Sharding-Jdbc?實(shí)現(xiàn)讀寫分離? ?分庫分表,寫得太好了!
| 概覽
ShardingSphere-Jdbc定位為輕量級Java框架,在Java的Jdbc層提供的額外服務(wù)。它使用客戶端直連數(shù)據(jù)庫,以jar包形式提供服務(wù),可理解為增強(qiáng)版的Jdbc驅(qū)動,完全兼容Jdbc和各種ORM框架。
| MySQL主從復(fù)制
1)docker配置mysql主從復(fù)制
1)創(chuàng)建主服務(wù)器所需目錄mkdir -p /usr/local/mysqlData/master/cnfmkdir -p /usr/local/mysqlData/master/data
2)定義主服務(wù)器配置文件
[mysqld]
## 設(shè)置server_id,注意要唯一
server-id=1
## 開啟binlog
log-bin=mysql-bin
## binlog緩存
binlog_cache_size=1M
## binlog格式(mixed、statement、row,默認(rèn)格式是statement)
binlog_format=mixed
3)創(chuàng)建并啟動mysql主服務(wù)
4)添加復(fù)制master數(shù)據(jù)的用戶reader,供從服務(wù)器使用
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
6af1df686fff mysql:5.7 "docker-entrypoint..." 5 seconds ago Up 4 seconds 0.0.0.0:3306->3306/tcp, 33060/tcp master
[root@aliyun /]# docker exec -it master /bin/bash
root@41d795785db1:/# mysql -u root -p123456
mysql> GRANT REPLICATION SLAVE ON *.* to 'reader'@'%' identified by 'reader';
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> FLUSH PRIVILEGES;
Query OK, 0 rows affected (0.00 sec)
5)創(chuàng)建從服務(wù)器所需目錄,編輯配置文件
mkdir /usr/local/mysqlData/slave/cnf -p
vim /usr/local/mysqlData/slave/cnf/mysql.cnf
[mysqld]
## 設(shè)置server_id,注意要唯一
server-id=2
## 開啟binlog,以備Slave作為其它Slave的Master時使用
log-bin=mysql-slave-bin
## relay_log配置中繼日志
relay_log=edu-mysql-relay-bin
## 如果需要同步函數(shù)或者存儲過程
log_bin_trust_function_creators=true
## binlog緩存
binlog_cache_size=1M
## binlog格式(mixed、statement、row,默認(rèn)格式是statement)
binlog_format=mixed
## 跳過主從復(fù)制中遇到的所有錯誤或指定類型的錯誤,避免slave端復(fù)制中斷
## 如:1062錯誤是指一些主鍵重復(fù),1032錯誤是因?yàn)橹鲝臄?shù)據(jù)庫數(shù)據(jù)不一致
slave_skip_errors=1062
6)創(chuàng)建并運(yùn)行mysql從服務(wù)器
7)在從服務(wù)器上配置連接主服務(wù)器的信息首先主服務(wù)器上查看master_log_file、master_log_pos兩個參數(shù),然后切換到從服務(wù)器上進(jìn)行主服務(wù)器的連接信息的設(shè)置。
mysql> show master status;
------------------ ---------- -------------- ------------------ -------------------
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
------------------ ---------- -------------- ------------------ -------------------
| mysql-bin.000003 | 591 | | | |
------------------ ---------- -------------- ------------------ -------------------
1 row in set (0.00 sec)
docker查看主服務(wù)器容器的ip地址:
172.17.0.2
從服務(wù)器上執(zhí)行:
root@fe8b6fc2f1ca:/# mysql -u root -p123456
mysql> change master to master_host='172.17.0.2',master_user='reader',master_password='reader',master_log_file='mysql-bin.000003',master_log_pos=591;
8)從服務(wù)器啟動I/O 線程和SQL線程
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> show slave status\G
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 172.17.0.2
Master_User: reader
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin.000003
Read_Master_Log_Pos: 591
Relay_Log_File: edu-mysql-relay-bin.000002
Relay_Log_Pos: 320
Relay_Master_Log_File: mysql-bin.000003
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Slave_IO_Running: Yes,Slave_SQL_Running: Yes即表示啟動成功。
2)binlog和redo log回顧
1)redo log(重做日志)
- Master Thread每一秒將redo log buffer刷新到redo log file。
- 每個事務(wù)提交時會將redo log buffer刷新到redo log file。
- 當(dāng)redo log緩沖池剩余空間小于1/2時,會將redo log buffer刷新到redo log file。
Write Pos和Check Point之間空著的部分,可以用來記錄新的操作。如果Write Pos追上Check Point,這時候不能再執(zhí)行新的更新,需要停下來擦掉一些記錄,把Check Point推進(jìn)一下。當(dāng)數(shù)據(jù)庫發(fā)生宕機(jī)時,數(shù)據(jù)庫不需要重做所有的日志,因?yàn)镃heck Point之前的頁都已經(jīng)刷新回磁盤,只需對Check Point后的redo log進(jìn)行恢復(fù),從而縮短了恢復(fù)的時間。當(dāng)緩沖池不夠用時,根據(jù)LRU算法會溢出最近最少使用的頁,若此頁為臟頁,那么需要強(qiáng)制執(zhí)行Check Point,將臟頁刷新回磁盤。2)binlog(歸檔日志)
- STATEMENT模式:binlog里面記錄的就是SQL語句的原文。優(yōu)點(diǎn)是并不需要記錄每一行的數(shù)據(jù)變化,減少了binlog日志量,節(jié)約IO,提高性能。缺點(diǎn)是在某些情況下會導(dǎo)致master-slave中的數(shù)據(jù)不一致。
- ROW模式:不記錄每條SQL語句的上下文信息,僅需記錄哪條數(shù)據(jù)被修改了,修改成什么樣了,解決了STATEMENT模式下出現(xiàn)master-slave中的數(shù)據(jù)不一致。缺點(diǎn)是會產(chǎn)生大量的日志,尤其是alter table的時候會讓日志暴漲。
- MIXED模式:以上兩種模式的混合使用,一般的復(fù)制使用STATEMENT模式保存binlog,對于STATEMENT模式無法復(fù)制的操作使用ROW模式保存binlog,MySQL會根據(jù)執(zhí)行的SQL語句選擇日志保存方式。
-
redo log是InnoDB引擎特有的;binlog是MySQL的Server層實(shí)現(xiàn)的,所有引擎都可以使用。
-
redo log是物理日志,記錄的是在某個數(shù)據(jù)也上做了什么修改;binlog是邏輯日志,記錄的是這個語句的原始邏輯,比如給ID=2這一行的c字段加1。
-
redo log是循環(huán)寫的,空間固定會用完;binlog是可以追加寫入的,binlog文件寫到一定大小后會切換到下一個,并不會覆蓋以前的日志。
update T set c=c 1 where ID=2;
執(zhí)行器和InnoDB引擎在執(zhí)行這個update語句時的內(nèi)部流程:
- 執(zhí)行器先找到引擎取ID=2這一行。ID是主鍵,引擎直接用樹搜索找到這一行。如果ID=2這一行所在的數(shù)據(jù)也本來就在內(nèi)存中,就直接返回給執(zhí)行器;否則,需要先從磁盤讀入內(nèi)存,然后再返回。
- 執(zhí)行器拿到引擎給的行數(shù)據(jù),把這個值加上1,得到新的一行數(shù)據(jù),再調(diào)用引擎接口寫入這行新數(shù)據(jù)。
- 引擎將這行新數(shù)據(jù)更新到內(nèi)存中,同時將這個更新操作記錄到redo log里面,此時redo log處于prepare狀態(tài)。然后告知執(zhí)行器執(zhí)行完成了,隨時可以提交事務(wù)。
- 執(zhí)行器生成這個操作的binlog,并把binlog寫入磁盤
- 執(zhí)行器調(diào)用引擎的提交事務(wù)接口,引擎把剛剛寫入的redo log改成提交狀態(tài),更新完成。
3)MySQL主從復(fù)制原理
- 在從庫B上通過change master命令,設(shè)置主庫A的IP、端口、用戶名、密碼,以及要從哪個位置開始請求binlog,這個位置包含文件名和日志偏移量。
- 在從庫B上執(zhí)行start slave命令,這時從庫會啟動兩個線程,就是圖中的I/O線程和SQL線程。其中I/O線程負(fù)責(zé)與主庫建立連接。
- 主庫A校驗(yàn)完用戶名、密碼后,開始按照從庫B傳過來的位置,從本地讀取binlog,發(fā)給B。
- 從庫B拿到binlog后,寫到本地文件,稱為中繼日志。
- SQL線程讀取中繼日志,解析出日志里的命令,并執(zhí)行。
| Sharding-Jdbc實(shí)現(xiàn)讀寫分離
1)新建Springboot工程,引入相關(guān)依賴
org.springframework.boot
spring-boot-starter-web
org.mybatis.spring.boot
mybatis-spring-boot-starter
2.1.4
mysql
mysql-connector-java
runtime
com.alibaba
druid-spring-boot-starter
1.1.21
org.apache.shardingsphere
sharding-jdbc-spring-boot-starter
4.0.0-RC1
org.projectlombok
lombok
true
org.springframework.boot
spring-boot-starter-test
test
2)application.properties配置文件
#顯示sql
spring.shardingsphere.props.sql.show=true
#配置數(shù)據(jù)源
spring.shardingsphere.datasource.names=ds1,ds2,ds3
#master-ds1數(shù)據(jù)庫連接信息
spring.shardingsphere.datasource.ds1.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.ds1.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.ds1.url=jdbc:mysql://47.101.58.187:3306/sharding-jdbc-db?useUnicode=true