分布式數(shù)據(jù)庫架構(gòu)
1、MySQL常見架構(gòu)設(shè)計(jì)
對于mysql架構(gòu),一定會使用到讀寫分離,在此基礎(chǔ)上有五種常見架構(gòu)設(shè)計(jì):一主一從或多從、主主復(fù)制、級聯(lián)復(fù)制、主主與級聯(lián)復(fù)制結(jié)合。
1.1、主從復(fù)制
這種架構(gòu)設(shè)計(jì)是使用的最多的。在讀寫分離的基礎(chǔ)上,會存在一臺master作為寫機(jī),一個或多個slave作為讀機(jī)。因?yàn)樵趯?shí)際的情況下,讀的請求量一般是遠(yuǎn)遠(yuǎn)大于寫請求的。
采用這種架構(gòu)之后,當(dāng)應(yīng)用寫入輸入時,會把數(shù)據(jù)寫入到master節(jié)點(diǎn),然后由master節(jié)點(diǎn)將寫入數(shù)據(jù)復(fù)制到slave節(jié)點(diǎn)上。
缺點(diǎn):
- master單機(jī)故障
- 對master進(jìn)行維護(hù)時,無法接收寫請求
- master復(fù)制延遲,查詢數(shù)據(jù)延遲
- slave提升為master后,可能會發(fā)生數(shù)據(jù)丟失(數(shù)據(jù)不一致)
1.1.1、 主從復(fù)制搭建
1、首先需要在兩臺機(jī)器上安裝mysql鏡像以及創(chuàng)建mysql容器
docker pull mysql:5.7
docker run --name mysql3307 -p 3307:3306 --privileged=true -ti -e MYSQL_ROOT_PASSWORD=123456 -e MYSQL_USER=user -e MYSQL_PASSWORD=pass -v /home/mysql/docker-data/3307/conf:/etc/mysql/conf.d -v /home/mysql/docker-data/3307/data/:/var/lib/mysql -v /home/mysql/docker-data/3307/logs/:/var/log/mysql -d mysql:5.7
2、需要在兩臺機(jī)器上的/home/mysql/docker-data/3307/conf目錄下,需要創(chuàng)建mysql的配置文件my.cnf。
my.cnf配置文件內(nèi)容如下:
# For advice on how to change settings please see
# http://dev.mysql.com/doc/refman/5.7/en/server-configuration-defaults.html
[mysqld]
#
# Remove leading # and set to the amount of RAM for the most important data
# cache in MySQL. Start at 70% of total RAM for dedicated server, else 10%.
# innodb_buffer_pool_size = 128M
#
# Remove leading # to turn on a very important data integrity option: logging
# changes to the binary log between backups.
# log_bin
#
# Remove leading # to set options mainly useful for reporting servers.
# The server defaults are faster for transactions and fast SELECTs.
# Adjust sizes as needed, experiment to find the optimal values.
# join_buffer_size = 128M
# sort_buffer_size = 2M
# read_rnd_buffer_size = 2M
#datadir=/home/mysql/docker-data/3307/data
#socket=/home/mysql/docker-data/3307/mysql.sock
character_set_server=utf8
init_connect='SET NAMES utf8'
# Disabling symbolic-links is recommended to prevent assorted security risks
symbolic-links=0
#log-error=/home/mysql/docker-data/3307/logs/mysqld.log
#pid-file=/home/mysql/docker-data/3307/mysqld.pid
lower_case_table_names=1
#指定主機(jī)號,不允許出現(xiàn)重復(fù)
server-id=423307
#開啟binlog
log-bin=mysql-bin
auto_increment_increment=2
auto_increment_offset=1
#rpl_semi_sync_master_enabled=1
#rpl_semi_sync_master_timeout=10000
3、在master的docker容器中添加mysql權(quán)限,開啟備份機(jī)復(fù)制,并且設(shè)置備份用戶信息。
#添加權(quán)限
GRANT REPLICATION SLAVE,FILE,REPLICATION CLIENT ON *.* TO 'repluser'@'%' IDENTIFIED BY '123456';
#刷新權(quán)限
FLUSH PRIVILEGES;
4、設(shè)置并刷新權(quán)限后,重啟mysql服務(wù)器,可以查看master上的binlog信息。
show master status;
注意:至此上述步驟兩臺機(jī)器上都需要執(zhí)行,參數(shù)上的設(shè)置按實(shí)際情況來定。
5、接著在slave中進(jìn)入到mysql容器,設(shè)置master信息,用于標(biāo)注當(dāng)前slave的master是誰。
change master to master_host='localhost',master_port=3307,master_user='repluser',master_password='123456',master_log_file='mysql-bin.000002',master_log_pos=154;
參數(shù)解析
change master to master_host='master的ip',
master_port=master的端口號,
master_user='repluser',master_password='123456',
master_log_file='master中的binlob文件',
master_log_pos=master中的position位置信息;
6、設(shè)置完成后,還要開啟slave中的IO和SQL線程,這兩個線程主要用于slave中進(jìn)行數(shù)據(jù)備份,可以先查看slave中這兩個線程的狀態(tài)。
show slave status\G
開啟slave中的IO和SQL線程
start slave;
至此mysql主從復(fù)制搭建完成。
7、 相關(guān)狀態(tài)信息的查看
查看slave中的binlog是否已經(jīng)開啟
show global variables like "%log%";
接著還可以查看master、slave中的進(jìn)程信息
在master mysql中輸入:
show processlist;
從上圖中可以看出:master已經(jīng)把所有的binlog發(fā)送給slave,并且等待更多的更新操作。
在slave mysql中輸入:
show processlist;
從上圖可以看出:在slave它已經(jīng)連接到了master,正在等待master發(fā)送事件,并且slave已經(jīng)讀取了所有的relay log信息,并且正在等待更多的更新操作。
8、測試驗(yàn)證
連接主庫,并在主庫中創(chuàng)建數(shù)據(jù)庫,創(chuàng)建數(shù)據(jù)庫表以及添加行記錄。此時會發(fā)現(xiàn)從庫中也會創(chuàng)建相應(yīng)的數(shù)據(jù)庫和數(shù)據(jù)庫表和行記錄。
1.1.2、 MySQL復(fù)制原理
在mysql中,其有兩種復(fù)制機(jī)制,分別是:異步復(fù)制、半同步復(fù)制。默認(rèn)采用異步復(fù)制。(上述主從復(fù)制操作為異步復(fù)制)
異步復(fù)制執(zhí)行流程
- 1、應(yīng)用事務(wù)提交到master
- 2、master接收到應(yīng)用事務(wù)提交請求后,會更新內(nèi)部的binlog日志,接著讓mysql引擎執(zhí)行事務(wù)操作,并返回給客戶端執(zhí)行結(jié)果信息。同時在master中會存在一個事件監(jiān)聽,其會一直監(jiān)聽master中binlog日志文件的改變,一旦發(fā)現(xiàn)日志文件發(fā)生改變,則會觸發(fā)dump線程。
- 3、dump線程被觸發(fā)后,會通知slave中的IO線程現(xiàn)在有事務(wù)操作需要進(jìn)行同步。
- 4、slave中IO線程接收到通知后,會從slave中relay-log.info文件中獲取slave中的binlog日志文件和pos位置信息。接著會把這部分信息發(fā)送給master的dump線程。
- 5、master的dump線程接收到這些信息后,會根據(jù)slave發(fā)送的binlog日志文件和pos位置,將最新的binlog日志和pos位置后面的內(nèi)容同步給slave的IO線程。
- 6、slave的IO線程接收到這些信息后,會將這部分內(nèi)容同步到slave的relay-bin文件中。
- 7、當(dāng)relay-bin文件發(fā)生改變后,會觸發(fā)slave線程執(zhí)行sql操作。(異步操作)
- 8、當(dāng)slave向relay-bin寫入完成后,還會向master返回一個ACK消息,通知slave已經(jīng)執(zhí)行成功。
總結(jié):對于這一系列操作,可以發(fā)現(xiàn)master和slave在進(jìn)行同步時是以異步的方式完成的,master寫入完binlog后,會馬上通過引擎進(jìn)行事務(wù)提交并向客戶端返回響應(yīng),對于與slave同步的操作,則是異步完成的。
雖然這種方式的RT很快,但是很容易出現(xiàn)數(shù)據(jù)不一致的情況。
半同步復(fù)制執(zhí)行流程
- 半同步復(fù)制與異步復(fù)制的工作流程大體相似,但不同的是,當(dāng)master中的binlog日志寫入完成后,其不會馬上通過引擎進(jìn)行事務(wù)提交,而會處于等待,等到slave同步完成向master返回ACK通知后,才會喚醒等待,繼續(xù)向下執(zhí)行。
- 等待的時長,默認(rèn)為10秒,但該時間可以配置。
- 半同步復(fù)制盡量的避免的主從數(shù)據(jù)不一致的情況,但是會造成吞吐量的降低。
對于這個問題,mysql也進(jìn)行了解決,假設(shè)使用半同步復(fù)制進(jìn)行備份時,slave節(jié)點(diǎn)掛掉了,那么當(dāng)master等待10秒后,仍然會進(jìn)行引擎提交,同時會將半同步復(fù)制切換為異步復(fù)制。等到slave節(jié)點(diǎn)重啟后,又會自動的從異步復(fù)制切換到半同步復(fù)制。
主從異步復(fù)制日志效果
Mysql在進(jìn)行復(fù)制操作時,默認(rèn)是基于異步復(fù)制完成的。那為了更好的體會異步復(fù)制的效果,可以通過mysql日志來查看具體的復(fù)制過程效果。
啟動主從兩臺Mysql服務(wù)器。
查看master的Mysql日志信息
docker logs -f mysql3307 | grep binlog_dump
?根據(jù)當(dāng)前查看的日志信息,在master中已經(jīng)開啟了dump線程連接到了id為273307的slave節(jié)點(diǎn),并且該id就是在slave的mysql配置文件中設(shè)置的id。
同時pos內(nèi)容包括當(dāng)前的binlog日志和pos位置。
查看slave的mysql日志信息
根據(jù)slave中的日志信息,可以看到,當(dāng)前slave中已經(jīng)開啟了relay-log日志,其對應(yīng)文件信息就是xxxxx-relay-bin。其內(nèi)部保存的就是slave中的相關(guān)binlog信息和pos位置信息。
同時在slave中也已經(jīng)開啟了SQL Thread,并且根據(jù)信息可以,它會從xxxx-relay-bin.000001文件的4位置開始復(fù)制。
同時在slave中也開啟了IO Thread,其已經(jīng)連接到master,并且會從master的binlog日志的154的位置開啟復(fù)制。
查看master當(dāng)前的binlog日志信息
#確定當(dāng)前master正在使用的binlog日志文件
cat mysql-bin.index
#查看當(dāng)前binlog日志文件內(nèi)容
tail -f mysql-bin.000002
查看slave當(dāng)前的日志信息
cat relay-log.info
cat master.info
cat xxxxxxxxxx-relay-bin.index
監(jiān)控slave日志信息
tail -f 8122977f8b0a-relay-bin.000002
master中新增數(shù)據(jù),觸發(fā)主從同步
- 查看master修改前后的binlog日志
cat mysql-bin.000002
- 查看slave復(fù)制前后的relay-bin日志
tail -f 41dc8a520939-relay-bin.000002
1.1.3、 主從半同步復(fù)制搭建
1、配置
進(jìn)入mysql容器,加載lib,主從節(jié)點(diǎn)都要配置,因?yàn)橹鲝墓?jié)點(diǎn)間會存在切換。
install plugin rpl_semi_sync_master soname 'semisync_master.so';
install plugin rpl_semi_sync_slave soname 'semisync_slave.so';
查看插件信息
show plugins;
2、啟用半同步(務(wù)必先啟用從庫,再啟用主庫)
#先啟用從庫,再啟用主庫
#從庫:
set global rpl_semi_sync_slave_enabled= {0|1}; # 1:啟用,0:禁止
#主庫:
set global rpl_semi_sync_master_enabled= {0|1}; # 1:啟用,0:禁止
set global rpl_semi_sync_master_timeout=10000; # 單位為ms
3、重啟從庫IO Thread
stop slave io_thread;
start slave io_thread;
4、截止到此已經(jīng)完成半同步開啟配置,可以查看主庫狀態(tài)信息和參數(shù)信息
#查詢狀態(tài)信息
show global status like "%sync%";
#查詢參數(shù)信息
show global variables like '%sync%';
show global status like “%sync%”;
show global variables like ‘%sync%’;
根據(jù)上述的配置,當(dāng)前主從兩臺服務(wù)器的復(fù)制方式已經(jīng)改為半同步復(fù)制。接下來就可以來查看具體的效果。
- 正常的向master中添加數(shù)據(jù),slave可以進(jìn)行正常數(shù)據(jù)更新。
master打印日志信息如下: 開啟半同步復(fù)制,關(guān)閉異步復(fù)制
- 關(guān)閉slave的IO Thread或者停止salve服務(wù)
再次向master中添加數(shù)據(jù)。此時可以發(fā)現(xiàn),當(dāng)進(jìn)行數(shù)據(jù)提交時,會出現(xiàn)等待,過了十秒后,會對數(shù)據(jù)進(jìn)行保存。同時slave中不會同步的進(jìn)行數(shù)據(jù)更新。
如上圖所示,超過時間后,半同步復(fù)制會轉(zhuǎn)化為異步復(fù)制。此時復(fù)制機(jī)制就會由半同步復(fù)制轉(zhuǎn)換為異步復(fù)制,當(dāng)再次向master中添加數(shù)據(jù),不會再次出現(xiàn)等待。
- slave中重新開啟IO Thread。
異步復(fù)制會再次轉(zhuǎn)換為半同步復(fù)制,其次,在slave IO Tthread關(guān)閉這段時間內(nèi)的數(shù)據(jù),會同步到slave中,不會出現(xiàn)數(shù)據(jù)丟失。
1.2、主主復(fù)制
對于主從復(fù)制來說,其內(nèi)部會存在一臺master以及一臺或多臺slave。但有一個非常明顯的問題,master是單點(diǎn)存在。一旦master宕機(jī),則無法進(jìn)行數(shù)據(jù)的寫入。為了解決這個問題,可以使用主主復(fù)制架構(gòu)。
在主主復(fù)制架構(gòu)中,會存在兩臺master,沒有slave。并且會對這兩臺master進(jìn)行讀寫分離,兩臺master會進(jìn)行相互的復(fù)制。
主主復(fù)制架構(gòu)圖
在此架構(gòu)中,兩臺master會進(jìn)行雙向復(fù)制,為什么這么做呢? 因?yàn)榧僭O(shè)現(xiàn)在負(fù)責(zé)寫的master宕機(jī)了,那么寫的工作則會交給之前負(fù)責(zé)讀的服務(wù)器來完成,相當(dāng)于它即負(fù)責(zé)寫又負(fù)責(zé)讀。等到原先負(fù)責(zé)寫的master恢復(fù)了,其在繼續(xù)負(fù)責(zé)寫工作。 反之亦然。因此才需要兩者間進(jìn)行雙向復(fù)制。
此時缺點(diǎn)也非常明顯,雖然master不存在單點(diǎn)了,但是對于讀來說,如果并發(fā)量大的話,它肯定扛不住。對于主主復(fù)制架構(gòu)來說,應(yīng)用較少。
1.2.1、主主復(fù)制搭建
主主復(fù)制的搭建和主從非常類似,只不過主主復(fù)制會進(jìn)行互指。
1、參照主從完成搭建。(按照上述主從復(fù)制結(jié)構(gòu)搭建)
2、原slave端也要開啟權(quán)限
#添加權(quán)限
GRANT REPLICATION SLAVE,FILE,REPLICATION CLIENT ON *.* TO 'repluser'@'%' IDENTIFIED BY '123456';
#刷新權(quán)限
FLUSH PRIVILEGES;
#重啟mysql服務(wù)并查看binlog信息
show master status
3、在master這一端也要配置slave的相關(guān)配置
change master to master_host='localhost',master_port=3308,master_user='repluser',master_password='123456',master_log_file='mysql-bin.000002',master_log_pos=154;
start slave;
4、查看master和slave的進(jìn)程列表:show processlist??梢园l(fā)現(xiàn)他們現(xiàn)在互為主備。
master
slave
5、測試
當(dāng)在兩臺服務(wù)器中添加數(shù)據(jù),都可以完成雙向同步。
1.3、級聯(lián)復(fù)制架構(gòu)
當(dāng)讀壓力現(xiàn)在增大并且還想減小主從復(fù)制的性能消耗,可以采用級聯(lián)復(fù)制架構(gòu)。
寫請求的入口仍為一個,但當(dāng)master向slave進(jìn)行復(fù)制時,對于slave可以分為多層, master只要向其中兩臺slave復(fù)制即可,然后再由slave將其數(shù)據(jù)復(fù)制到后面更多的slave中。
通過這種方式可以減輕master向slave復(fù)制的IO壓力。
但是這種架構(gòu)也存在一個弊端:slave的延遲會加大。
1.4、雙主與級聯(lián)復(fù)制結(jié)合架構(gòu)
對于master在前面幾種架構(gòu)設(shè)計(jì)中,都存在單點(diǎn)問題, 對于master單點(diǎn)問題的解決,可以采用當(dāng)前的架構(gòu)。通過這種架構(gòu)不僅可以解決master單點(diǎn)的問題,也可以解決slave延遲的問題。
2、Mysql高可用實(shí)踐
以主主架構(gòu)為例,現(xiàn)在不管寫或者讀,只要其中一個宕機(jī),則會把它本身工作交給另外一臺服務(wù)器完成。此時就需要對IP進(jìn)行一個自動的指向。而且這種服務(wù)器IP切換,對于上層應(yīng)用來說,應(yīng)該是完全隱藏的,其無需知道當(dāng)前是由誰來完成具體工作,其只需要來連接一個IP就可以。
對于這種需求,就需要通過keepAlived來完成IP的自動切換。
對于keepalived會在多臺mysql服務(wù)器進(jìn)行安裝, 同時keepalived間也分為master和slave, 同時master會虛擬化一個VIP供應(yīng)用進(jìn)行連接。 如果一旦master掛掉后,會由slave節(jié)點(diǎn)繼續(xù)工作,同時slave節(jié)點(diǎn)也會虛擬出相同VIP,供應(yīng)用進(jìn)行連接。
2.1、keepAlived高可用配置
1、安裝keepalived
1. 下載keepalied安裝包 http://www.keepalived.org/download.html
2. yum -y install openssl-devel gcc gcc-c++
3. mkdir /etc/keepalived
4. 上傳安裝包并解壓 tar -zxvf keepalived-2.0.18.tar.gz
5. mv keepalived-2.0.18 /usr/local/keepalived
6. cd /usr/local/keepalived
7. ./configure && make && make install
8.創(chuàng)建啟動文件
cp -a /usr/local/etc/keepalived /etc/init.d/
cp -a /usr/local/etc/sysconfig/keepalived /etc/sysconfig/
cp -a /usr/local/sbin/keepalived /usr/sbin/
2、編寫執(zhí)行shell腳本
進(jìn)入/etc/keepalived。創(chuàng)建chk.sh,同時賦予執(zhí)行權(quán)限:chmod +x chk.sh
#! /bin/bash
mysql -h 127.0.0.1 -u root -p123456 -P 3312 -e "show status;" >/dev/null 2>&1
if [ $? == 0 ]
then
echo " $host mysql login successfully "
exit 0
else
echo " mysql login faild"
killall keepalived
exit 2
fi
3、編寫keepAlived配置文件
cd /etc/keepalived
vi keepalived.conf
! Configuration File for keepalived
#簡單的頭部,這里主要可以做郵件通知報警等的設(shè)置,此處就暫不配置了;
global_defs {
#notificationd LVS_DEVEL
router_id MYSQL_4 #唯一標(biāo)識不允許出現(xiàn)重復(fù)
script_user root
enable_script_security
}
#預(yù)先定義一個腳本,方便后面調(diào)用,也可以定義多個,方便選擇;
vrrp_script chk_haproxy {
script "/etc/keepalived/chk.sh"
interval 2 #腳本循環(huán)運(yùn)行間隔
}
#VRRP虛擬路由冗余協(xié)議配置
vrrp_instance VI_1 { #VI_1 是自定義的名稱;
state BACKUP #MASTER表示是一臺主設(shè)備,BACKUP表示為備用設(shè)備【我們這里因?yàn)樵O(shè)置為開啟不搶占,所以都設(shè)置為備用】
nopreempt #開啟不搶占
interface ens33 #指定VIP需要綁定的物理網(wǎng)卡
virtual_router_id 11 #VRID虛擬路由標(biāo)識,也叫做分組名稱,該組內(nèi)的設(shè)備需要相同
priority 130 #定義這臺設(shè)備的優(yōu)先級 1-254;開啟了不搶占,所以此處優(yōu)先級必須高于另一臺
advert_int 1 #生存檢測時的組播信息發(fā)送間隔,組內(nèi)一致
authentication { #設(shè)置驗(yàn)證信息,組內(nèi)一致
auth_type PASS #有PASS 和 AH 兩種,常用 PASS
auth_pass 111111 #密碼
}
virtual_ipaddress {
192.168.200.200 #指定VIP地址,組內(nèi)一致,可以設(shè)置多個IP
}
track_script { #使用在這個域中使用預(yù)先定義的腳本,上面定義的
chk_haproxy
}
}
4、啟動keepAlived
systemctl start keepalived
5、查看keepAlived執(zhí)行狀態(tài)
ps -ef|grep keepalived
6、可以通過tail -f /var/log/messages
7、查看ip信息,此時可以發(fā)現(xiàn)出現(xiàn)了配置的虛擬ip
ip a
8、測試
通過navicat使用虛擬IP連接mysql,當(dāng)前連接IP為VIP??梢赃B接成功。
3、數(shù)據(jù)切分核心思想
3.1、為什么要進(jìn)行數(shù)據(jù)切分?
當(dāng)前微服務(wù)架構(gòu)非常流行,很多都會采用微服務(wù)架構(gòu)對其系統(tǒng)進(jìn)行拆分。 而雖然產(chǎn)生了多個微服務(wù),但因?yàn)槠溆脩袅亢蛿?shù)據(jù)量的問題,很有可能仍然使用的是同一個數(shù)據(jù)庫。
但是隨著用戶量和數(shù)據(jù)量增加,就會出現(xiàn)很多影響數(shù)據(jù)庫性能的因素,如:數(shù)據(jù)存儲量、IO瓶頸、訪問量瓶頸等。此時就需要將數(shù)據(jù)進(jìn)行拆分,從一個庫拆分成多個庫。
3.2、數(shù)據(jù)拆分方式
垂直拆分
垂直拆分是按照業(yè)務(wù)將表進(jìn)行分類并分布到不同的數(shù)據(jù)節(jié)點(diǎn)上。在初始進(jìn)行數(shù)據(jù)拆分時,使用垂直拆分是非常直觀的一種方式。
垂直拆分的優(yōu)點(diǎn):
- 拆分規(guī)則明確,按照不同的功能模塊或服務(wù)分配不同的數(shù)據(jù)庫。
- 數(shù)據(jù)維護(hù)與定位簡單。
垂直拆分的缺點(diǎn):
- 對于讀寫極其頻繁且數(shù)據(jù)量超大的表,仍然存在存儲與性能瓶頸。簡單的索引此時已經(jīng)無法解決問題。
- 會出現(xiàn)跨庫join。
- 需要對代碼進(jìn)行重構(gòu),修改原有的事務(wù)操作。
- 某個表數(shù)據(jù)量達(dá)到一定程度后擴(kuò)展起來較為困難。
水平拆分
?為了解決垂直拆分出現(xiàn)的問題,可以使用水平拆分繼續(xù)橫向擴(kuò)展,首先,可以如果當(dāng)前數(shù)據(jù)庫的容量沒有問題的話,可以對讀寫極其頻繁且數(shù)據(jù)量超大的表進(jìn)行分表操作。由一張表拆分出多張表。
在一個庫中,拆分出多張表,每張表存儲不同的數(shù)據(jù),這樣對于其操作效率會有明顯的提升。而且因?yàn)樘幱谕粋€庫中,也不會出現(xiàn)分布式事務(wù)的問題。
而拆分出多張表后,如果當(dāng)前數(shù)據(jù)庫的容量已經(jīng)不夠了,但是還要繼續(xù)拆分的話,就可以進(jìn)行分庫操作,產(chǎn)生多個數(shù)據(jù)庫,然后在擴(kuò)展出的數(shù)據(jù)庫中繼續(xù)擴(kuò)展表。
水平拆分的優(yōu)點(diǎn):
- 盡量的避免了跨庫join操作。
- 不會存在超大型表的性能瓶頸問題。
- 事務(wù)處理相對簡單。
- 只要拆分規(guī)則定義好,很難出現(xiàn)擴(kuò)展性的限制。
水平拆分的缺點(diǎn):
- 拆分規(guī)則不好明確,規(guī)則一定會和業(yè)務(wù)掛鉤,如根據(jù)id、根據(jù)時間等。
- 不好明確數(shù)據(jù)位置,難以進(jìn)行維護(hù)。
- 多數(shù)據(jù)源管理難度加大,代碼復(fù)雜度增加。
- 也會存在分布式事務(wù)問題
- 數(shù)據(jù)庫維護(hù)成本增加
數(shù)據(jù)切分帶來的問題
- 按照用戶ID求模,將數(shù)據(jù)分散到不同的數(shù)據(jù)庫,具有相同數(shù)據(jù)用戶的數(shù)據(jù)都被分散到一個庫中。
- 按照日期,將不同月甚至日的數(shù)據(jù)分散到不同的庫中。
- 按照某個特定的字段求模,或者根據(jù)特定范圍段分散到不同的庫中。
數(shù)據(jù)切分帶來的核心問題
- 產(chǎn)生引入分布式事務(wù)的問題。
- 跨節(jié)點(diǎn) Join 的問題。
- 跨節(jié)點(diǎn)合并排序分頁問題。
3.3、Mycat中間件使用
當(dāng)對數(shù)據(jù)拆分后會產(chǎn)生諸多的問題,對于這些問題的解決,可以借助于數(shù)據(jù)庫中間件來進(jìn)行解決,現(xiàn)在時下比較流行的是使用Mycat。
Mycat是一款數(shù)據(jù)庫中間件,對于應(yīng)用程序來說是完全透明化的,不管底層的數(shù)據(jù)如何拆分,應(yīng)用只需要連接Mycat即可完成對數(shù)據(jù)的操作。同時它還支持MySQL、SQL Server、Oracle、DB2、PostgreSQL等主流數(shù)據(jù)庫。但是Mycat不會進(jìn)行數(shù)據(jù)存儲,它只是用于數(shù)據(jù)的路由。
其底層是基于攔截思想實(shí)現(xiàn),其會攔截用戶發(fā)送過來的SQL語句,首先對SQL語句做了一些特定的分析:如分片分析、路由分析、讀寫分離分析、緩存分析等,然后將此SQL發(fā)往后端的真實(shí)數(shù)據(jù)庫,并將返回的結(jié)果做適當(dāng)?shù)奶幚?,最終再返回給用戶。
Mycat特性
- 支持SQL92標(biāo)準(zhǔn)
- 遵守Mysql原生協(xié)議,跨語言,跨平臺,跨數(shù)據(jù)庫的通用中間件代理。
- 基于心跳的自動故障切換,支持讀寫分離,支持MySQL主從,以及galera cluster集群。
- 支持Galera for MySQL集群,Percona Cluster或者M(jìn)ariaDB cluster
- 基于Nio實(shí)現(xiàn),有效管理線程,高并發(fā)問題。
- 支持?jǐn)?shù)據(jù)的多片自動路由與聚合,支持sum,count,max等常用的聚合函數(shù)。
- 支持單庫內(nèi)部任意join,支持跨庫2表join。
- 支持通過全局表,ER關(guān)系的分片策略,實(shí)現(xiàn)了高效的多表join查詢。
- 支持多租戶方案。
- 支持分布式事務(wù)(弱xa)。
- 支持全局序列號,解決分布式下的主鍵生成問題。
- 分片規(guī)則豐富,插件化開發(fā),易于擴(kuò)展。
- 強(qiáng)大的web,命令行監(jiān)控。
- 支持前端作為mysq通用代理,后端JDBC方式支持Oracle、DB2、SQL Server 、 mongodb 。
- 支持密碼加密
- 支持服務(wù)降級
- 支持IP白名單
- 支持SQL黑名單、sql注入攻擊攔截
- 支持分表(1.6)
- 集群基于ZooKeeper管理,在線升級,擴(kuò)容,智能優(yōu)化,大數(shù)據(jù)處理(2.0開發(fā)版)。
Mycat源碼的本地部署運(yùn)行
**源碼下載:**https://codeload.github.com/MyCATApache/Mycat-Server/zip/Mycat-server-1675-release
默認(rèn)端口:8066
配置啟動參數(shù):
-DMYCAT_HOME=D:\workspace\Mycat-Server-Mycat-server-1675-release\src\main
#設(shè)置堆外內(nèi)存大小
-XX:MaxDirectMemorySize=512M
注意:為什么要設(shè)置堆外內(nèi)存:當(dāng)使用mycat對非分片查詢時,會把所有的數(shù)據(jù)查詢出來,然后把這部分?jǐn)?shù)據(jù)放在堆外內(nèi)存中
在Mycat有核心三個配置文件,分別為:sever.xml、schema.xml、rule.xml
- server.xml:是Mycat服務(wù)器參數(shù)調(diào)整和用戶授權(quán)的配置文件。
- schema.xml:是邏輯庫定義和表以及分片定義的配置文件
- rule.xml:是分片規(guī)則的配置文件,分片規(guī)則的具體一些參數(shù)信息單獨(dú)存放為文件,也在這個目錄下,配置文件修改需要重啟MyCAT。
MyCat核心概念
在學(xué)習(xí)Mycat首先需要先對其內(nèi)部一些核心概念有足夠的了解。
- 邏輯庫:Mycat中的虛擬數(shù)據(jù)庫。對應(yīng)實(shí)際數(shù)據(jù)庫的概念。在沒有使用mycat時,應(yīng)用需要確定當(dāng)前連接的數(shù)據(jù)庫等信息,那么當(dāng)使用mycat后,也需要先虛擬一個數(shù)據(jù)庫,用于應(yīng)用的連接。
- 邏輯表:mycat中的虛擬數(shù)據(jù)表。對應(yīng)時間數(shù)據(jù)庫中數(shù)據(jù)表的概念。
- 非分片表:沒有進(jìn)行數(shù)據(jù)切分的表。
- 分片表:已經(jīng)被數(shù)據(jù)拆分的表,每個分片表中都有原有數(shù)據(jù)表的一部分?jǐn)?shù)據(jù)。多張分片表可以構(gòu)成一個完整數(shù)據(jù)表。
- ER表:子表的記錄與所關(guān)聯(lián)的父表記錄存放在同一個數(shù)據(jù)分片上,即子表依賴于父表,通過表分組(Table Group)保證數(shù)據(jù)Join不會跨庫操作。表分組(Table Group)是解決跨分片數(shù)據(jù)join的一種很好的思路,也是數(shù)據(jù)切分規(guī)劃的重要一條規(guī)則
- 全局表:可以理解為是一張數(shù)據(jù)冗余表,如狀態(tài)表,每一個數(shù)據(jù)分片節(jié)點(diǎn)又保存了一份狀態(tài)表數(shù)據(jù)。數(shù)據(jù)冗余是解決跨分片數(shù)據(jù)join的一種很好的思路,也是數(shù)據(jù)切分規(guī)劃的另外一條重要規(guī)則。
- 分片節(jié)點(diǎn)(dataNode):數(shù)據(jù)切分后,每一個數(shù)據(jù)分片表所在的數(shù)據(jù)庫就是分片節(jié)點(diǎn)。
- 節(jié)點(diǎn)主機(jī)(dataHost):數(shù)據(jù)切分后,每個分片節(jié)點(diǎn)(dataNode)不一定都會獨(dú)占一臺機(jī)器,同一機(jī)器上面可以有多個分片數(shù)據(jù)庫,這樣一個或多個分片節(jié)點(diǎn)(dataNode)所在的機(jī)器就是節(jié)點(diǎn)主機(jī)(dataHost),為了規(guī)避單節(jié)點(diǎn)主機(jī)并發(fā)數(shù)限制,盡量將讀寫壓力高的分片節(jié)點(diǎn)(dataNode)均衡的放在不同的節(jié)點(diǎn)主機(jī)(dataHost)。
- 分片規(guī)則(rule):按照某種業(yè)務(wù)規(guī)則把數(shù)據(jù)分到某個分片的規(guī)則就是分片規(guī)則。
- 全局序列號(sequence):也可以理解為分布式id。數(shù)據(jù)切分后,原有的關(guān)系數(shù)據(jù)庫中的主鍵約束在分布式條件下將無法使用,因此需要引入外部機(jī)制保證數(shù)據(jù)唯一性標(biāo)識,這種保證全局性的數(shù)據(jù)唯一標(biāo)識的機(jī)制就是全局序列號(sequence),如UUID、雪花算法等。
4、Mycat企業(yè)級應(yīng)用實(shí)踐
4.1、環(huán)境參數(shù)配置
在server.xml 文件中的system標(biāo)簽下配置所有的參數(shù),全部為環(huán)境參數(shù),可以根據(jù)當(dāng)前需要進(jìn)行開啟和配置,如:設(shè)置mycat連接端口號
<property name="serverPort">8066</property>
4.2、數(shù)據(jù)非分片
4.2.1、配置初始化信息
應(yīng)用連接mycat的話,也需要設(shè)置用戶名、密碼、被連接數(shù)據(jù)庫信息,要配置這些信息的話,可以修改server.xml,在其內(nèi)部添加內(nèi)容如下:
<!--配置自定義用戶信息-->
<!--連接用戶名-->
<user name="mycat">
<!--連接密碼-->
<property name="password">mycat</property>
<!--創(chuàng)建虛擬數(shù)據(jù)庫-->
<property name="schemas">userdb</property>
<!--指定該庫是否只讀-->
<!--<property name="readOnly">true</property>-->
</user>
4.2.2、配置虛擬數(shù)據(jù)庫&表
<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
<!--配置虛擬數(shù)據(jù)庫-->
<!--name:虛擬邏輯數(shù)據(jù)庫名稱,對應(yīng)server.xml中的schemas屬性值-->
<!--dataNode:邏輯庫中邏輯表的默認(rèn)數(shù)據(jù)節(jié)點(diǎn)-->
<!--sqlMaxLimit:類似于SQL上添加limit,如schema為非分片庫,則該屬性無效-->
<schema name="userdb" checkSQLschema="true" dataNode="localdn" sqlMaxLimit="500">
<!--配置虛擬邏輯表-->
<!--name:邏輯表名稱,必須唯一-->
<!--dataNode:邏輯表所處的數(shù)據(jù)節(jié)點(diǎn),值必須與dataNode標(biāo)簽中的name屬性對應(yīng)。如果值過多可以用$連接,如:dn$1-99,dn$200-400-->
<!--primaryKey:邏輯表對應(yīng)的真實(shí)表的主鍵id的字段名-->
<table name="tb_user" dataNode="localdn" primaryKey="user_id"/>
</schema>
<!--配置dataNode信息-->
<!--name:當(dāng)前datanode名稱-->
<!--dataHost:分片節(jié)點(diǎn)所處的節(jié)點(diǎn)主機(jī),該值必須與dataHost標(biāo)簽中的name屬性對應(yīng)-->
<!--database:當(dāng)前數(shù)據(jù)節(jié)點(diǎn)所對應(yīng)的實(shí)際物理數(shù)據(jù)庫-->
<dataNode name="localdn" dataHost="localdh" database="user"/>
<!--配置節(jié)點(diǎn)主機(jī)-->
<!--balance:用于進(jìn)行讀操作指向,有三個值可選
0:所有讀操作都發(fā)送到當(dāng)前可用的writeHost上
1:所有讀操作都隨機(jī)的發(fā)送到readHost上
2:所有讀操作都隨機(jī)發(fā)送在writeHost與readHost上
-->
<!--maxCon:指定每個讀寫實(shí)例連接池的最大連接。也就是說,標(biāo)簽內(nèi)嵌套的writeHost、readHost標(biāo)簽都會使用這個屬性的值來實(shí)例化出連接池的最大連接數(shù)-->
<!--minCon:指定每個讀寫實(shí)例連接池的最小連接,初始化連接池的大小-->
<!--name:當(dāng)前節(jié)點(diǎn)主機(jī)名稱,不允許出現(xiàn)重復(fù)-->
<!--dbType:當(dāng)時使用的數(shù)據(jù)庫類型-->
<!--dbDriver:當(dāng)前使用的數(shù)據(jù)庫驅(qū)動-->
<!--writeType:用于寫操作指向,有三個值可選
0:所有寫操作都發(fā)送到可用的writeHost上
1:所有寫操作都隨機(jī)發(fā)送到readHost上
2:所有寫操作都隨機(jī)發(fā)送在writeHost與readHost上
-->
<!--readHost是從屬于writeHost的,即意味著它從那個writeHost獲取同步數(shù)據(jù)。
因此,當(dāng)它所屬的writeHost宕機(jī)了,則它也不會再參與到讀寫分離中來,即“不工作了”。這是因?yàn)榇藭r,它的數(shù)據(jù)已經(jīng)“不可靠”了。
基于這個考慮,目前mycat 1.3和1.4版本中,若想支持MySQL一主一從的標(biāo)準(zhǔn)配置,并且在主節(jié)點(diǎn)宕機(jī)的情況下,從節(jié)點(diǎn)還能讀取數(shù)據(jù)。
則需要在Mycat里配置為兩個writeHost并設(shè)置banlance=1。”-->
<!--switchType:設(shè)置節(jié)點(diǎn)切換操作,有三個值可選
-1:不自動切換
1:自動切換,默認(rèn)值
2:基于mysql主從同步的狀態(tài)決定是否切換
-->
<!--slaveThreshold:主從同步狀態(tài)決定是否切換,延遲超過該值就不切換-->
<dataHost balance="0" maxCon="100" minCon="10" name="localdh" dbType="mysql" dbDriver="jdbc" writeType="0" switchType="1" slaveThreshold="1000">
<!--查詢心跳-->
<heartbeat>select user()</heartbeat>
<!--配置寫節(jié)點(diǎn)實(shí)際物理數(shù)據(jù)庫信息-->
<writeHost url="jdbc:mysql://localhost:3306" host="host1" password="root" user="root"></writeHost>
</dataHost>
</mycat:schema>
4.2.3 測試
通過navicat創(chuàng)建本地?cái)?shù)據(jù)庫連接并創(chuàng)建對應(yīng)數(shù)據(jù)庫,同時創(chuàng)建mycat連接。 在mycat連接中操作表,添加數(shù)據(jù),可以發(fā)現(xiàn),本地?cái)?shù)據(jù)庫中同步的也新增了對應(yīng)的數(shù)據(jù)。
4.3、根據(jù)ID取模數(shù)據(jù)分片
當(dāng)一個數(shù)據(jù)表中的數(shù)據(jù)量非常大時,就需要考慮對表內(nèi)數(shù)據(jù)進(jìn)行分片,拆分的規(guī)則有很多種,比較簡單的一種就是,通過對id進(jìn)行取模,完成數(shù)據(jù)分片。
1)修改schema.xml
table標(biāo)簽新增屬性:subTables、rule
<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
<!--配置虛擬數(shù)據(jù)庫-->
<!--name:虛擬邏輯數(shù)據(jù)庫名稱,對應(yīng)server.xml中的schemas屬性值-->
<!--dataNode:邏輯庫中邏輯表的默認(rèn)數(shù)據(jù)節(jié)點(diǎn)-->
<!--sqlMaxLimit:類似于SQL上添加limit,如schema為非分片庫,則該屬性無效-->
<schema name="userdb" checkSQLschema="true" dataNode="localdn" sqlMaxLimit="500">
<!--配置虛擬邏輯表-->
<!--name:邏輯表名稱,必須唯一-->
<!--dataNode:邏輯表所處的數(shù)據(jù)節(jié)點(diǎn),值必須與dataNode標(biāo)簽中的name屬性對應(yīng)。如果值過多可以用$連接,如:dn$1-99,dn$200-400-->
<!--primaryKey:邏輯表對應(yīng)的真實(shí)表的主鍵id的字段名-->
<!--subTables:分表的名稱??梢源嬖诙鄠€,tb_user1,tb_user2,tb_user3.如果分表較多,可以通過$連接:tb_user$1-3-->
<!--rule:分片規(guī)則,對應(yīng)rule.xml中配置-->
<table name="tb_user" dataNode="localdn" primaryKey="user_id" subTables="tb_user$1-3" rule="mod-long"/>
</schema>
<!--配置dataNode信息-->
<!--name:當(dāng)前datanode名稱-->
<!--dataHost:分片節(jié)點(diǎn)所處的節(jié)點(diǎn)主機(jī),該值必須與dataHost標(biāo)簽中的name屬性對應(yīng)-->
<!--database:當(dāng)前數(shù)據(jù)節(jié)點(diǎn)所對應(yīng)的實(shí)際物理數(shù)據(jù)庫-->
<dataNode name="localdn" dataHost="localdh" database="user"/>
<!--配置節(jié)點(diǎn)主機(jī)-->
<!--balance:用于進(jìn)行讀操作指向,有三個值可選
0:所有讀操作都發(fā)送到當(dāng)前可用的writeHost上
1:所有讀操作都隨機(jī)的發(fā)送到readHost上
2:所有讀操作都隨機(jī)發(fā)送在writeHost與readHost上
-->
<!--maxCon:指定每個讀寫實(shí)例連接池的最大連接。也就是說,標(biāo)簽內(nèi)嵌套的writeHost、readHost標(biāo)簽都會使用這個屬性的值來實(shí)例化出連接池的最大連接數(shù)-->
<!--minCon:指定每個讀寫實(shí)例連接池的最小連接,初始化連接池的大小-->
<!--name:當(dāng)前節(jié)點(diǎn)主機(jī)名稱,不允許出現(xiàn)重復(fù)-->
<!--dbType:當(dāng)時使用的數(shù)據(jù)庫類型-->
<!--dbDriver:當(dāng)前使用的數(shù)據(jù)庫驅(qū)動-->
<!--writeType:用于寫操作指向,有三個值可選
0:所有寫操作都發(fā)送到可用的writeHost上
1:所有寫操作都隨機(jī)發(fā)送到readHost上
2:所有寫操作都隨機(jī)發(fā)送在writeHost與readHost上
-->
<!--readHost是從屬于writeHost的,即意味著它從那個writeHost獲取同步數(shù)據(jù)。
因此,當(dāng)它所屬的writeHost宕機(jī)了,則它也不會再參與到讀寫分離中來,即“不工作了”。這是因?yàn)榇藭r,它的數(shù)據(jù)已經(jīng)“不可靠”了。
基于這個考慮,目前mycat 1.3和1.4版本中,若想支持MySQL一主一從的標(biāo)準(zhǔn)配置,并且在主節(jié)點(diǎn)宕機(jī)的情況下,從節(jié)點(diǎn)還能讀取數(shù)據(jù)。
則需要在Mycat里配置為兩個writeHost并設(shè)置banlance=1?!?->
<!--switchType:設(shè)置節(jié)點(diǎn)切換操作,有三個值可選
-1:不自動切換
1:自動切換,默認(rèn)值
2:基于mysql主從同步的狀態(tài)決定是否切換
-->
<!--slaveThreshold:主從同步狀態(tài)決定是否切換,延遲超過該值就不切換-->
<dataHost balance="0" maxCon="100" minCon="10" name="localdh" dbType="mysql" dbDriver="jdbc" writeType="0" switchType="1" slaveThreshold="1000">
<!--查詢心跳-->
<heartbeat>select user()</heartbeat>
<!--配置寫節(jié)點(diǎn)實(shí)際物理數(shù)據(jù)庫信息-->
<writeHost url="jdbc:mysql://localhost:3306" host="host1" password="root" user="root"></writeHost>
</dataHost>
</mycat:schema>
2)修改rule.xml
在schema.xml中已經(jīng)指定規(guī)則為mod-long。因此需要到該文件中修改對應(yīng)信息。
<tableRule name="mod-long">
<rule>
<!--當(dāng)用用于id取模的字段-->
<columns>user_id</columns>
<algorithm>mod-long</algorithm>
</rule>
</tableRule>
<!--修改當(dāng)前的分片數(shù)量-->
<function name="mod-long" class="io.mycat.route.function.PartitionByMod">
<!-- how many data nodes -->
<!-- 根據(jù)datanode數(shù)量進(jìn)行取模分片,也就是要模幾。 -->
<property name="count">3</property>
</function>
3)測試
-
向數(shù)據(jù)庫中插入一千條數(shù)據(jù),可以發(fā)現(xiàn),其會根據(jù)id取模,放入不同的三張表中。
-
當(dāng)根據(jù)id查詢時,會通過對id的取模,確定當(dāng)前要查詢的分片。并且首先會先查詢mycat中的ehcache緩存,再來查詢數(shù)據(jù)分片。
-
當(dāng)查詢所有數(shù)據(jù)時,會查詢所有數(shù)據(jù)分片。
4)缺陷
通過id取模分片這種方式實(shí)際中應(yīng)用較少。主要因?yàn)閮牲c(diǎn)問題:
根據(jù)id取模,1)散列不均勻,出現(xiàn)數(shù)據(jù)傾斜。2)動態(tài)擴(kuò)容時,存在rehash,出現(xiàn)數(shù)據(jù)丟失。
1)數(shù)據(jù)散列不均勻,容易出現(xiàn)數(shù)據(jù)傾斜。每張表中的數(shù)據(jù)量差距較大。
2)動態(tài)擴(kuò)容后,當(dāng)需要新增表時,需要對模數(shù)修改,有可能就會造成當(dāng)查詢某個分片時,在該分片中找不到對應(yīng)數(shù)據(jù)。
3)動態(tài)擴(kuò)容后,要進(jìn)行rehash操作。
4.4、全局序列號
當(dāng)進(jìn)行數(shù)據(jù)切分后,數(shù)據(jù)會存放在多張表中,如果仍然通過數(shù)據(jù)庫自增id的方式,就會出現(xiàn)ID重復(fù)的問題,造成數(shù)據(jù)錯亂。所以當(dāng)拆分完數(shù)據(jù)后,需要讓每一條數(shù)據(jù)都有自己的ID,并且在多表中不能出現(xiàn)重復(fù)。比較常見的會使用雪花算法來生成分布式id。
在Mycat中也提供了四種方式來進(jìn)行分布式id生成:基于文件、基于數(shù)據(jù)庫、基于時間戳和基于ZK。
4.4.1、基于本地文件方式生成
優(yōu)點(diǎn):本地加載,讀取速度較快。
缺點(diǎn):當(dāng)MyCAT重新發(fā)布后,配置文件中的sequence會恢復(fù)到初始值。
?生成的id沒有含義,如時間。
?MyCat如果存在多個,會出現(xiàn)id重復(fù)問題。
1)修改sequence_conf.properties
USER.HISIDS= #使用過的歷史分段,可不配置
USER.MINID=1 #最小ID值
USER.MAXID=200000 #最大ID值
USER.CURID=1000 #當(dāng)前ID值
2)修改server.xml
<!--設(shè)置全局序號生成方式
0:文件
1:數(shù)據(jù)庫
2:時間戳
3:zookeeper
-->
<property name="sequnceHandlerType">0</property>
<!--進(jìn)入序列匹配流程, 必須帶有MYCATSEQ_或者 mycatseq_-->
<property name="sequnceHandlerPattern">(?:(\s*next\s+value\s+for\s*MYCATSEQ_(\w+))(,|\)|\s)*)+</property>
<property name="sequenceHanlderClass">io.mycat.route.sequence.handler.HttpIncrSequenceHandler</property>
3)測試
重啟mycat,并查詢是否修改成功
show @@sysparam
通過navicat插入數(shù)據(jù)
insert into tb_user(user_id,user_name) values('next value for MYCATSEQ_USER','wangwu')
通過程序插入數(shù)據(jù)
@Insert("insert into tb_user(user_id,user_name) values('next value for MYCATSEQ_USER',#{userName})")
void addUser(User user);
4.4.2、基于數(shù)據(jù)庫生成
優(yōu)點(diǎn):能夠進(jìn)行id批量生成,在分布式下,可以避免id重復(fù)問題。
缺點(diǎn):ID沒有意義,對數(shù)據(jù)庫有壓力。
1)在實(shí)際數(shù)據(jù)庫執(zhí)行dbseq.sql中的sql語句,執(zhí)行完畢后,會創(chuàng)建一張表。
2)修改sequence_db_conf.properties。
TB_USER=localdn
3)修改server.xml文件,修改全局序列號生成方式為數(shù)據(jù)庫方式
<property name="sequnceHandlerType">1</property>
4)修改schema.xml。在table中添加自增屬性
<table name="tb_user" dataNode="localdn" primaryKey="id" subTables="tb_user$1-3" rule="mod-long" autoIncrement="true"/>
5)測試
通過navicat新增記錄
insert into tb_user(user_id,user_name) values('next value for MYCATSEQ_TB_USER','wangwu')
4.4.3、基于zookeeper生成
1)修改server.xml,更改生成模式
<property name="sequenceHandlerType">3</property>
2)修改myid.properties,配置zk連接信息
loadZk=true
zkURL=192.168.200.131:2181
clusterId=01
myid=mycat_fz_01
clusterNodes=mycat_fz_01
#server booster ; booster install on db same server,will reset all minCon to 1
#type=server
#boosterDataHosts=localhost1
3)修改sequence_distributed_conf.properties
INSTANCEID=ZK #聲明使用zk生成
CLUSTERID=01
4)測試
啟動mycatServer后,通過zk客戶端查看節(jié)點(diǎn)信息。會發(fā)現(xiàn)新增了一個mycat節(jié)點(diǎn)
./zkCli.sh
ls /
插入數(shù)據(jù)
insert into tb_user(user_id,user_name) values('n
ext value for MYCATSEQ_TB_USER12','heima')
next value for MYCATSEQ_ 后的內(nèi)容可以隨意指定。
5)特性:
ID 結(jié)構(gòu):long 64 位,ID 最大可占 63 位
* |current time millis(微秒時間戳 38 位,可以使用 17 年)|clusterId(機(jī)房或者 ZKid,通過配置文件配置 5位)|instanceId(實(shí)例 ID,可以通過 ZK 或者配置文件獲取,5 位)|threadId(線程 ID,9 位)|increment(自增,6 位)
* 一共 63 位,可以承受單機(jī)房單機(jī)器單線程 1000*(2^6)=640000 的并發(fā)。
* 無悲觀鎖,無強(qiáng)競爭,吞吐量更高
7.4.4)基于時間戳生成
優(yōu)點(diǎn):不存在上面兩種方案因?yàn)閙ycat的重啟導(dǎo)致id重復(fù)的現(xiàn)象,ID= 64 位二進(jìn)制 (42(毫秒)+5(機(jī)器 ID)+5(業(yè)務(wù)編碼)+12(重復(fù)累加),每毫秒可以并發(fā) 12 位二進(jìn)制的累加。
缺點(diǎn):數(shù)據(jù)類型太長,建議采用bigint(最大取值18446744073709551615)
1)修改server.xml。更改生成方式
<property name="sequenceHandlerType">2</property>
2)修改sequence_time_conf.properties
#sequence depend on TIME
#WORKID與DATAACENTERID: 0-31 任意整數(shù)。多mycat節(jié)點(diǎn)下,每個節(jié)點(diǎn)的WORKID、DATAACENTERID不能重復(fù),組成唯一標(biāo)識,總共支持32*32=1024 種組合
WORKID=01
DATAACENTERID=01
3)測試
新增數(shù)據(jù)
insert into tb_user(user_id,user_name) values('next value for MYCATSEQ_TB_USER12','heima')
next value for MYCATSEQ_ 后的內(nèi)容可以隨意指定。
5、MyCat分庫&讀寫分離
之前已經(jīng)基于id取模完成了分表操作,但是一個數(shù)據(jù)庫的容量畢竟是有限制的,如果數(shù)據(jù)量非常大,分表已經(jīng)滿足不了的話,就會進(jìn)行分庫操作。
?當(dāng)前分庫架構(gòu)如下:
現(xiàn)在存在兩個主庫,并且各自都有從節(jié)點(diǎn)。 當(dāng)插入數(shù)據(jù)時,根據(jù)id取模放入不同的庫中。同時主從間在進(jìn)行寫時復(fù)制的同時,還要完成主從讀寫分離的配置。
1)修改schema.xml。配置多datenode與datahost。同時配置主從讀寫分離。
<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
<schema name="userdb" checkSQLschema="true" dataNode="dn09" sqlMaxLimit="500">
<table name="tb_user" dataNode="dn09,dn10" primaryKey="user_id" rule="mod-long"/>
</schema>
<dataNode name="dn09" dataHost="dh09" database="user"/>
<dataNode name="dn10" dataHost="dh10" database="user"/>
<dataHost name="dh09" balance="1" maxCon="100" minCon="10" dbType="mysql" dbDriver="jdbc" writeType="0" switchType="1" slaveThreshold="1000">
<!--查詢心跳-->
<heartbeat>select user()</heartbeat>
<!--配置寫節(jié)點(diǎn)實(shí)際物理數(shù)據(jù)庫信息-->
<writeHost url="jdbc:mysql://192.168.200.142:3309" host="host1" user="root" password="123456">
<!--配置讀節(jié)點(diǎn)實(shí)際物理數(shù)據(jù)庫信息-->
<readHost host="host2" url="jdbc:mysql://192.168.200.145:3309" user="root" password="123456" ></readHost>
</writeHost>
</dataHost>
<dataHost name="dh10" balance="1" maxCon="100" minCon="10" dbType="mysql" dbDriver="jdbc" writeType="0" switchType="1" slaveThreshold="1000">
<!--查詢心跳-->
<heartbeat>select user()</heartbeat>
<!--配置寫節(jié)點(diǎn)實(shí)際物理數(shù)據(jù)庫信息-->
<writeHost url="jdbc:mysql://192.168.200.142:3310" host="host1" user="root" password="123456">
<!--配置讀節(jié)點(diǎn)實(shí)際物理數(shù)據(jù)庫信息-->
<readHost host="host2" url="jdbc:mysql://192.168.200.145:3310" user="root" password="123456" ></readHost>
</writeHost>
</dataHost>
</mycat:schema>
2)修改rule.xml。配置取模時的模數(shù)
<function name="mod-long" class="io.mycat.route.function.PartitionByMod">
<!-- how many data nodes -->
<!-- 根據(jù)datanode數(shù)量進(jìn)行取模分片,也就是要模幾。 -->
<property name="count">2</property>
</function>
3)進(jìn)行批量數(shù)據(jù)添加,可以發(fā)現(xiàn)數(shù)據(jù)落在了不同的庫中。
4)讀寫分離驗(yàn)證
設(shè)置log4j2.xml的日志級別為DEBUG
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="DEBUG">
........
<asyncRoot level="DEBUG" includeLocation="true">
........
</asyncRoot>
</Loggers>
</Configuration>
基于mysql服務(wù)進(jìn)行數(shù)據(jù)查看,觀察控制臺信息,可以看到對于read請求的數(shù)據(jù)源,分別使用的是配置文件的配置。文章來源:http://www.zghlxwxcb.cn/news/detail-499699.html
文章來源地址http://www.zghlxwxcb.cn/news/detail-499699.html
到了這里,關(guān)于分布式數(shù)據(jù)庫架構(gòu)的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!