新聞中心
MySQL大型分布式集群具體怎么做
1、主要解決針對(duì)大型網(wǎng)站架構(gòu)中持久化部分中,大量數(shù)據(jù)存儲(chǔ)以及高并發(fā)訪問(wèn)所帶來(lái)是數(shù)據(jù)讀寫(xiě)問(wèn)題。分布式是將一個(gè)業(yè)務(wù)拆分為多個(gè)子業(yè)務(wù),部署在不同的服務(wù)器上。集群是同一個(gè)業(yè)務(wù),部署在多個(gè)服務(wù)器上。
喀喇沁網(wǎng)站建設(shè)公司成都創(chuàng)新互聯(lián)公司,喀喇沁網(wǎng)站設(shè)計(jì)制作,有大型網(wǎng)站制作公司豐富經(jīng)驗(yàn)。已為喀喇沁成百上千提供企業(yè)網(wǎng)站建設(shè)服務(wù)。企業(yè)網(wǎng)站搭建\成都外貿(mào)網(wǎng)站建設(shè)公司要多少錢(qián),請(qǐng)找那個(gè)售后服務(wù)好的喀喇沁做網(wǎng)站的公司定做!
2、著重對(duì)數(shù)據(jù)切分做了細(xì)致豐富的講解,從數(shù)據(jù)切分的原理出發(fā),一步一步深入理解數(shù)據(jù)的切分,通過(guò)深入理解各種切分策略來(lái)設(shè)計(jì)和優(yōu)化我們的系統(tǒng)。這部分中我們還用到了數(shù)據(jù)庫(kù)中間件和客戶(hù)端組件來(lái)進(jìn)行數(shù)據(jù)的切分,讓廣大網(wǎng)友能夠?qū)?shù)據(jù)的切分從理論到實(shí)戰(zhàn)都會(huì)有一個(gè)質(zhì)的飛躍。
通過(guò)分布式+集群的方式來(lái)提高io的吞吐量,以及數(shù)據(jù)庫(kù)的主從復(fù)制,主主復(fù)制,負(fù)載均衡,高可用,分庫(kù)分表以及數(shù)據(jù)庫(kù)中間件的使用。
教程樣例項(xiàng)目中用到的技術(shù)及相應(yīng)的環(huán)境:
MySQL5.7 CentOS6.9 Vmware Spring3.x以上 JDK8 Maven XShell Xftp
用 MySQL 實(shí)現(xiàn)分布式鎖,你聽(tīng)過(guò)嗎?
以前參加過(guò)一個(gè)庫(kù)存系統(tǒng),由于其業(yè)務(wù)復(fù)雜性,搞了很多個(gè)應(yīng)用來(lái)支撐。這樣的話(huà)一份庫(kù)存數(shù)據(jù)就有可能同時(shí)有多個(gè)應(yīng)用來(lái)修改庫(kù)存數(shù)據(jù)。
比如說(shuō),有定時(shí)任務(wù)域xx.cron,和SystemA域和SystemB域這幾個(gè)JAVA應(yīng)用,可能同時(shí)修改同一份庫(kù)存數(shù)據(jù)。如果不做協(xié)調(diào)的話(huà),就會(huì)有臟數(shù)據(jù)出現(xiàn)。
對(duì)于跨JAVA進(jìn)程的線(xiàn)程協(xié)調(diào),可以借助外部環(huán)境,例如DB或者Redis。下文介紹一下如何使用DB來(lái)實(shí)現(xiàn)分布式鎖。
本文設(shè)計(jì)的分布式鎖的交互方式如下:
在使用synchronized關(guān)鍵字的時(shí)候,必須指定一個(gè)鎖對(duì)象。
進(jìn)程內(nèi)的線(xiàn)程可以基于obj來(lái)實(shí)現(xiàn)同步。obj在這里可以理解為一個(gè)鎖對(duì)象。如果線(xiàn)程要進(jìn)入synchronized代碼塊里,必須先持有obj對(duì)象上的鎖。這種鎖是JAVA里面的內(nèi)置鎖,創(chuàng)建的過(guò)程是線(xiàn)程安全的。那么借助DB,如何保證創(chuàng)建鎖的過(guò)程是線(xiàn)程安全的呢?
可以利用DB中的UNIQUE KEY特性,一旦出現(xiàn)了重復(fù)的key,由于UNIQUE KEY的唯一性,會(huì)拋出異常的。在JAVA里面,是 SQLIntegrityConstraintViolationException 異常。
transaction_id是事務(wù)Id,比如說(shuō),可以用
來(lái)組裝一個(gè)transaction_id,表示某倉(cāng)庫(kù)某銷(xiāo)售模式下的某個(gè)條碼資源。不同條碼,當(dāng)然就有不同的transaction_id。如果有兩個(gè)應(yīng)用,拿著相同的transaction_id來(lái)創(chuàng)建鎖資源的時(shí)候,只能有一個(gè)應(yīng)用創(chuàng)建成功。
在寫(xiě)操作頻繁的業(yè)務(wù)系統(tǒng)中,通常會(huì)進(jìn)行分庫(kù),以降低單數(shù)據(jù)庫(kù)寫(xiě)入的壓力,并提高寫(xiě)操作的吞吐量。如果使用了分庫(kù),那么業(yè)務(wù)數(shù)據(jù)自然也都分配到各個(gè)數(shù)據(jù)庫(kù)上了。
在這種水平切分的多數(shù)據(jù)庫(kù)上使用DB分布式鎖,可以自定義一個(gè)DataSouce列表。并暴露一個(gè) getConnection(String transactionId) 方法,按照transactionId找到對(duì)應(yīng)的Connection。
實(shí)現(xiàn)代碼如下:
首先編寫(xiě)一個(gè)initDataSourceList方法,并利用Spring的PostConstruct注解初始化一個(gè)DataSource 列表。相關(guān)的DB配置從db.properties讀取。
DataSource使用阿里的DruidDataSource。
接著最重要的一個(gè)實(shí)現(xiàn)getConnection(String transactionId)方法。實(shí)現(xiàn)原理很簡(jiǎn)單,獲取transactionId的hashcode,并對(duì)DataSource的長(zhǎng)度取模即可。
連接池列表設(shè)計(jì)好后,就可以實(shí)現(xiàn)往distributed_lock表插入數(shù)據(jù)了。
接下來(lái)利用DB的 select for update 特性來(lái)鎖住線(xiàn)程。當(dāng)多個(gè)線(xiàn)程根據(jù)相同的transactionId并發(fā)同時(shí)操作 select for update 的時(shí)候,只有一個(gè)線(xiàn)程能成功,其他線(xiàn)程都block住,直到 select for update 成功的線(xiàn)程使用commit操作后,block住的所有線(xiàn)程的其中一個(gè)線(xiàn)程才能開(kāi)始干活。
我們?cè)谏厦娴腄istributedLock類(lèi)中創(chuàng)建一個(gè)lock方法。
當(dāng)線(xiàn)程執(zhí)行完任務(wù)后,必須手動(dòng)的執(zhí)行解鎖操作,之前被鎖住的線(xiàn)程才能繼續(xù)干活。在我們上面的實(shí)現(xiàn)中,其實(shí)就是獲取到當(dāng)時(shí) select for update 成功的線(xiàn)程對(duì)應(yīng)的Connection,并實(shí)行commit操作即可。
那么如何獲取到呢?我們可以利用ThreadLocal。首先在DistributedLock類(lèi)中定義
每次調(diào)用lock方法的時(shí)候,把Connection放置到ThreadLocal里面。我們修改lock方法。
這樣子,當(dāng)獲取到Connection后,將其設(shè)置到ThreadLocal中,如果lock方法出現(xiàn)異常,則將其從ThreadLocal中移除掉。
有了這幾步后,我們可以來(lái)實(shí)現(xiàn)解鎖操作了。我們?cè)贒istributedLock添加一個(gè)unlock方法。
畢竟是利用DB來(lái)實(shí)現(xiàn)分布式鎖,對(duì)DB還是造成一定的壓力。當(dāng)時(shí)考慮使用DB做分布式的一個(gè)重要原因是,我們的應(yīng)用是后端應(yīng)用,平時(shí)流量不大的,反而關(guān)鍵的是要保證庫(kù)存數(shù)據(jù)的正確性。對(duì)于像前端庫(kù)存系統(tǒng),比如添加購(gòu)物車(chē)占用庫(kù)存等操作,最好別使用DB來(lái)實(shí)現(xiàn)分布式鎖了。
如果想鎖住多份數(shù)據(jù)該怎么實(shí)現(xiàn)?比如說(shuō),某個(gè)庫(kù)存操作,既要修改物理庫(kù)存,又要修改虛擬庫(kù)存,想鎖住物理庫(kù)存的同時(shí),又鎖住虛擬庫(kù)存。其實(shí)也不是很難,參考lock方法,寫(xiě)一個(gè)multiLock方法,提供多個(gè)transactionId的入?yún)?,for循環(huán)處理就可以了。這個(gè)后續(xù)有時(shí)間再補(bǔ)上。
mysql如何實(shí)現(xiàn)分布式數(shù)據(jù)庫(kù)
應(yīng)該是通過(guò)ndb的cluster來(lái)實(shí)現(xiàn)啊,你只需在網(wǎng)上找mysql cluster的資料就可以知道了。在mysql官方網(wǎng)站上可以下載到,如《mysql cluster維護(hù)手冊(cè).docx》等
MySQL Mycat 分布式架構(gòu)
參考:
圖中是兩組分片,紅色我們稱(chēng)為shard1,藍(lán)色我們稱(chēng)為shard2
51 52是服務(wù)器
兩個(gè)3307互為主從(雙主),3309是本地3307的從庫(kù)
說(shuō)明:沒(méi)有明確說(shuō)明是只在某一個(gè)節(jié)點(diǎn)上做的,就是兩個(gè)節(jié)點(diǎn)都做
兩臺(tái)虛擬機(jī) db01 db02
每臺(tái)創(chuàng)建四個(gè)mysql實(shí)例:3307 3308 3309 3310
mysql軟件我們之前已完成二進(jìn)制安裝,直接初始化即可
我們server-id規(guī)劃為:db01上是7/8/9/10,db02上是17/18/19/20
"箭頭指向誰(shuí)是主庫(kù)"
10.0.0.51:3307 ----- 10.0.0.52:3307
10.0.0.51:3309 ------ 10.0.0.51:3307
10.0.0.52:3309 ------ 10.0.0.52:3307
兩個(gè)分片,每個(gè)分片四個(gè)mysql節(jié)點(diǎn)
shard1:
Master:10.0.0.51:3307
slave1:10.0.0.51:3309
Standby Master:10.0.0.52:3307
slave2:10.0.0.52:3309
shard2:
Master:10.0.0.52:3308
slave1:10.0.0.52:3310
Standby Master:10.0.0.51:3308
slave2:10.0.0.51:3310
shard1
10.0.0.51:3307 ----- 10.0.0.52:3307
db02
db01
db02
10.0.0.51:3309 ------ 10.0.0.51:3307
db01
10.0.0.52:3309 ------ 10.0.0.52:3307
db02
shard2
10.0.0.52:3308 ----- 10.0.0.51:3308
db01
db02
db01
10.0.0.52:3310 ----- 10.0.0.52:3308
db02
10.0.0.51:3310 ----- 10.0.0.51:3308
db01
這個(gè)復(fù)制用戶(hù)在誰(shuí)上建都行
注:如果中間出現(xiàn)錯(cuò)誤,在每個(gè)節(jié)點(diǎn)進(jìn)行執(zhí)行以下命令
常見(jiàn)方案:
360 Atlas-Sharding 360
Alibaba cobar 阿里
Mycat 開(kāi)源
TDDL 淘寶
Heisenberg 百度
Oceanus 58同城
Vitess 谷歌
OneProxy
DRDS 阿里云
我們裝的是openjdk,不是官方的那個(gè)
Mycat-server-xxxxx.linux.tar.gz
配置環(huán)境變量
我們mycat的命令也是在bin目錄下
啟動(dòng)
8066就是對(duì)外提供服務(wù)的端口,9066是管理端口
連接mycat:
默認(rèn)123456
db01:
我們一般先把原schema.xml備份,然后自己新寫(xiě)一個(gè):
xml和html看起來(lái)差不多,xml是從下往上調(diào)用的
前三行我們不用看,直接從第四行schema開(kāi)始看起:
定義了schema,然后以/schema結(jié)尾
為什么要用邏輯庫(kù)?
業(yè)務(wù)透明化
此配置文件就是實(shí)現(xiàn)讀寫(xiě)分離的配置
重啟mycat
讀寫(xiě)分離測(cè)試
總結(jié):
以上案例實(shí)現(xiàn)了1主1從的讀寫(xiě)分離功能,寫(xiě)操作落到主庫(kù),讀操作落到從庫(kù).如果主庫(kù)宕機(jī),從庫(kù)不能在繼續(xù)提供服務(wù)了。
我們推薦這種架構(gòu)
一寫(xiě)三讀,
不設(shè)置雙寫(xiě)的原因是:性能沒(méi)提升多少,反而引起主鍵沖突的情況
配置文件:
之后重啟:mycat restart
真正的 writehost:負(fù)責(zé)寫(xiě)操作的writehost
standby writeHost :和readhost一樣,只提供讀服務(wù)
我們此處寫(xiě)了兩個(gè)writehost,默認(rèn)使用第一個(gè)
當(dāng)寫(xiě)節(jié)點(diǎn)宕機(jī)后,后面跟的readhost也不提供服務(wù),這時(shí)候standby的writehost就提供寫(xiě)服務(wù),
后面跟的readhost提供讀服務(wù)
測(cè)試:
讀寫(xiě)分離測(cè)試
對(duì)db01 3307節(jié)點(diǎn)進(jìn)行關(guān)閉和啟動(dòng),測(cè)試讀寫(xiě)操作
結(jié)果應(yīng)為另一臺(tái)(52)的3307(17)是寫(xiě),3309(19)是讀
一旦7號(hào)節(jié)點(diǎn)恢復(fù),此時(shí)因?yàn)?落后了,寫(xiě)節(jié)點(diǎn)仍是17
balance屬性
負(fù)載均衡類(lèi)型,目前的取值有3種:
writeType屬性
負(fù)載均衡類(lèi)型,目前的取值有2種:
switchType屬性
-1 表示不自動(dòng)切換
1 默認(rèn)值,自動(dòng)切換
2 基于MySQL主從同步的狀態(tài)決定是否切換 ,心跳語(yǔ)句為 show slave status
datahost其他配置
dataHost name="localhost1" maxCon="1000" minCon="10" balance="1" writeType="0" dbType="mysql" dbDriver="native" switchType="1"
maxCon="1000":最大的并發(fā)連接數(shù)
minCon="10" :mycat在啟動(dòng)之后,會(huì)在后端節(jié)點(diǎn)上自動(dòng)開(kāi)啟的連接線(xiàn)程,長(zhǎng)連接,好處是連接速度快,弊端是占內(nèi)存
tempReadHostAvailable="1"
這個(gè)一主一從時(shí)(1個(gè)writehost,1個(gè)readhost時(shí)),可以開(kāi)啟這個(gè)參數(shù),如果2個(gè)writehost,2個(gè)readhost時(shí)
heartbeatselect user()/heartbeat 監(jiān)測(cè)心跳
其他參數(shù)sqlMaxLimit自動(dòng)分頁(yè),必須在啟用分表的情況下才生效
創(chuàng)建測(cè)試庫(kù)和表:
我們重啟mycat后連接到8066
發(fā)現(xiàn)跟一個(gè)庫(kù)一樣,實(shí)際上已經(jīng)分到不同的物理硬件上了
分片:對(duì)一個(gè)"bigtable",比如說(shuō)t3表
熱點(diǎn)數(shù)據(jù)表 核心表
(1)行數(shù)非常多,800w下坡
(2)訪問(wèn)非常頻繁
分片的目的:
(1)將大數(shù)據(jù)量進(jìn)行分布存儲(chǔ)
(2)提供均衡的訪問(wèn)路由
分片策略:
范圍 range 800w 1-400w 400w01-800w 不適用于業(yè)務(wù)訪問(wèn)不均勻的情況
取模 mod (取余數(shù)) 和節(jié)點(diǎn)的數(shù)量進(jìn)行取模
枚舉 按枚舉的種類(lèi)分,如移動(dòng)項(xiàng)目按省份分
哈希 hash
時(shí)間 流水
優(yōu)化關(guān)聯(lián)查詢(xún)(否則join的表在不同分片上,效率會(huì)比單庫(kù)還要低)
全局表
ER分片
案例:移動(dòng)統(tǒng)一:先拆出邊緣業(yè)務(wù),再按地域分片,但對(duì)應(yīng)用來(lái)說(shuō)是統(tǒng)一的
vim rule.xml
tableRule name="auto-sharding-long"
rule
columnsid/columns
algorithmrang-long/algorithm
/rule
function name="rang-long"
class="io.mycat.route.function.AutoPartitionByLong"
property name="mapFile"autopartition-long.txt/property
/function
===================================
vim autopartition-long.txt
0-10=0
11-20=1
創(chuàng)建測(cè)試表:
mysql -S /data/3307/mysql.sock -e "use taobao;create table t3 (id int not null primary key auto_increment,name varchar(20) not null);"
mysql -S /data/3308/mysql.sock -e "use taobao;create table t3 (id int not null primary key auto_increment,name varchar(20) not null);"
測(cè)試:
重啟mycat
mycat restart
mysql -uroot -p123456 -h 127.0.0.1 -P 8066
insert into t3(id,name) values(1,'a');
insert into t3(id,name) values(2,'b');
insert into t3(id,name) values(3,'c');
insert into t3(id,name) values(4,'d');
insert into t3(id,name) values(11,'aa');
insert into t3(id,name) values(12,'bb');
insert into t3(id,name) values(13,'cc');
insert into t3(id,name) values(14,'dd');
取余分片方式:分片鍵(一個(gè)列)與節(jié)點(diǎn)數(shù)量進(jìn)行取余,得到余數(shù),將數(shù)據(jù)寫(xiě)入對(duì)應(yīng)節(jié)點(diǎn)
vim schema.xml
table name="t4" dataNode="sh1,sh2" rule="mod-long" /
vim rule.xml
property name="count"2/property
準(zhǔn)備測(cè)試環(huán)境
創(chuàng)建測(cè)試表:
mysql -S /data/3307/mysql.sock -e "use taobao;create table t4 (id int not null primary key auto_increment,name varchar(20) not null);"
mysql -S /data/3308/mysql.sock -e "use taobao;create table t4 (id int not null primary key auto_increment,name varchar(20) not null);"
重啟mycat
mycat restart
測(cè)試:
mysql -uroot -p123456 -h10.0.0.52 -P8066
use TESTDB
insert into t4(id,name) values(1,'a');
insert into t4(id,name) values(2,'b');
insert into t4(id,name) values(3,'c');
insert into t4(id,name) values(4,'d');
分別登錄后端節(jié)點(diǎn)查詢(xún)數(shù)據(jù)
mysql -S /data/3307/mysql.sock
use taobao
select * from t4;
mysql -S /data/3308/mysql.sock
use taobao
select * from t4;
t5 表
id name telnum
1 bj 1212
2 sh 22222
3 bj 3333
4 sh 44444
5 bj 5555
sharding-by-intfile
vim schema.xml
table name="t5" dataNode="sh1,sh2" rule="sharding-by-intfile" /
vim rule.xml
tableRule name="sharding-by-intfile"
rule columnsname/columns
algorithmhash-int/algorithm
/rule
/tableRule
function name="hash-int" class="org.opencloudb.route.function.PartitionByFileMap"
property name="mapFile"partition-hash-int.txt/property
property name="type"1/property
property name="defaultNode"0/property
/function
partition-hash-int.txt 配置:
bj=0
sh=1
DEFAULT_NODE=1
columns 標(biāo)識(shí)將要分片的表字段,algorithm 分片函數(shù), 其中分片函數(shù)配置中,mapFile標(biāo)識(shí)配置文件名稱(chēng)
準(zhǔn)備測(cè)試環(huán)境
mysql -S /data/3307/mysql.sock -e "use taobao;create table t5 (id int not null primary key auto_increment,name varchar(20) not null);"
mysql -S /data/3308/mysql.sock -e "use taobao;create table t5 (id int not null primary key auto_increment,name varchar(20) not null);"
重啟mycat
mycat restart
mysql -uroot -p123456 -h10.0.0.51 -P8066
use TESTDB
insert into t5(id,name) values(1,'bj');
insert into t5(id,name) values(2,'sh');
insert into t5(id,name) values(3,'bj');
insert into t5(id,name) values(4,'sh');
insert into t5(id,name) values(5,'tj');
a b c d
join
t
select t1.name ,t.x from t1
join t
select t2.name ,t.x from t2
join t
select t3.name ,t.x from t3
join t
使用場(chǎng)景:
如果你的業(yè)務(wù)中有些數(shù)據(jù)類(lèi)似于數(shù)據(jù)字典,比如配置文件的配置,
常用業(yè)務(wù)的配置或者數(shù)據(jù)量不大很少變動(dòng)的表,這些表往往不是特別大,
而且大部分的業(yè)務(wù)場(chǎng)景都會(huì)用到,那么這種表適合于Mycat全局表,無(wú)須對(duì)數(shù)據(jù)進(jìn)行切分,
要在所有的分片上保存一份數(shù)據(jù)即可,Mycat 在Join操作中,業(yè)務(wù)表與全局表進(jìn)行Join聚合會(huì)優(yōu)先選擇相同分片內(nèi)的全局表join,
避免跨庫(kù)Join,在進(jìn)行數(shù)據(jù)插入操作時(shí),mycat將把數(shù)據(jù)分發(fā)到全局表對(duì)應(yīng)的所有分片執(zhí)行,在進(jìn)行數(shù)據(jù)讀取時(shí)候?qū)?huì)隨機(jī)獲取一個(gè)節(jié)點(diǎn)讀取數(shù)據(jù)。
vim schema.xml
table name="t_area" primaryKey="id" type="global" dataNode="sh1,sh2" /
后端數(shù)據(jù)準(zhǔn)備
mysql -S /data/3307/mysql.sock
use taobao
create table t_area (id int not null primary key auto_increment,name varchar(20) not null);
mysql -S /data/3308/mysql.sock
use taobao
create table t_area (id int not null primary key auto_increment,name varchar(20) not null);
重啟mycat
mycat restart
測(cè)試:
mysql -uroot -p123456 -h10.0.0.52 -P8066
use TESTDB
insert into t_area(id,name) values(1,'a');
insert into t_area(id,name) values(2,'b');
insert into t_area(id,name) values(3,'c');
insert into t_area(id,name) values(4,'d');
A
join
B
為了防止跨分片join,可以使用E-R模式
A join B
on a.xx=b.yy
join C
on A.id=C.id
table name="A" dataNode="sh1,sh2" rule="mod-long"
childTable name="B" joinKey="yy" parentKey="xx" /
/table
mysql如何做成分布式?
MySQL做分布式需要通過(guò)ndb的Cluster來(lái)實(shí)現(xiàn)。MySQLCluster是MySQL適合于分布式計(jì)算環(huán)境的高實(shí)用、高冗余版本。 實(shí)現(xiàn)的步驟比較復(fù)雜,百度云案例:《MySQLCluster(MySQL集群)分布式》 下載地址:
網(wǎng)站題目:mysql怎么制作分布式 mysql數(shù)據(jù)庫(kù)是分布式的嗎
路徑分享:http://fisionsoft.com.cn/article/hgeeog.html