1 redo log(重做日志)
1)InnoDB首先將redo log放入到redo log buffer肤寝,然后按一定頻率將其刷新到redo log file刚梭。下列三種情況下會將redo log buffer刷新到redo log file:
- 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
MySQL里常說的WAL技術(shù)替劈,全稱是Write Ahead Log刮萌,即當(dāng)事務(wù)提交時,先寫redo log鬓催,再修改頁。也就是說恨锚,當(dāng)有一條記錄需要更新的時候宇驾,InnoDB會先把記錄寫到redo log里面,并更新Buffer Pool的page猴伶,這個時候更新操作就算完成了
2)Buffer Pool是物理頁的緩存课舍,對InnoDB的任何修改操作都會首先在Buffer Pool的page上進(jìn)行,然后這樣的頁將被標(biāo)記為臟頁并被放到專門的Flush List上他挎,后續(xù)將由專門的刷臟線程階段性的將這些頁面寫入磁盤
3)InnoDB的redo log是固定大小的筝尾,比如可以配置為一組4個文件,每個文件的大小是1GB办桨,循環(huán)使用筹淫,從頭開始寫,寫到末尾就又回到開頭循環(huán)寫(順序?qū)懩刈玻?jié)省了隨機寫磁盤的IO消耗)
4)Write Pos是當(dāng)前記錄的位置损姜,一邊寫一邊后移,寫到第3號文件末尾后就回到0號文件開頭殊霞。Check Point是當(dāng)前要擦除的位置摧阅,也是往后推移并且循環(huán)的,擦除記錄前要把記錄更新到數(shù)據(jù)文件
5)Write Pos和Check Point之間空著的部分绷蹲,可以用來記錄新的操作棒卷。如果Write Pos追上Check Point,這時候不能再執(zhí)行新的更新祝钢,需要停下來擦掉一些記錄比规,把Check Point推進(jìn)一下
6)當(dāng)數(shù)據(jù)庫發(fā)生宕機時,數(shù)據(jù)庫不需要重做所有的日志拦英,因為Check Point之前的頁都已經(jīng)刷新回磁盤苞俘,只需對Check Point后的redo log進(jìn)行恢復(fù),從而縮短了恢復(fù)的時間
7)當(dāng)緩沖池不夠用時龄章,根據(jù)LRU算法會溢出最近最少使用的頁吃谣,若此頁為臟頁,那么需要強制執(zhí)行Check Point做裙,將臟頁刷新回磁盤岗憋。
2 binlog(歸檔日志)
1)MySQL整體來看就有兩塊:一塊是Server層,主要做的是MySQL功能層面的事情锚贱;還有一塊是引擎層仔戈,負(fù)責(zé)存儲相關(guān)的具體事宜。redo log是InnoDB引擎特有的日志,而Server層也有自己的日志监徘,稱為binlog
2)binlog記錄了對MySQL數(shù)據(jù)庫執(zhí)行更改的所有操作晋修,不包括SELECT和SHOW這類操作,主要作用是用于數(shù)據(jù)庫的主從復(fù)制及數(shù)據(jù)的增量恢復(fù)
3)使用mysqldump備份時凰盔,只是對一段時間的數(shù)據(jù)進(jìn)行全備墓卦,但是如果備份后突然發(fā)現(xiàn)數(shù)據(jù)庫服務(wù)器故障,這個時候就要用到binlog的日志了
4)binlog格式有三種:STATEMENT户敬,ROW落剪,MIXED:
- STATEMENT模式:binlog里面記錄的就是SQL語句的原文。優(yōu)點是并不需要記錄每一行的數(shù)據(jù)變化尿庐,減少了binlog日志量忠怖,節(jié)約IO,提高性能抄瑟。缺點是在某些情況下會導(dǎo)致master-slave中的數(shù)據(jù)不一致
- ROW模式:不記錄每條SQL語句的上下文信息凡泣,僅需記錄哪條數(shù)據(jù)被修改了,修改成什么樣了皮假,解決了STATEMENT模式下出現(xiàn)master-slave中的數(shù)據(jù)不一致问麸。缺點是會產(chǎn)生大量的日志,尤其是alter table的時候會讓日志暴漲
- MIXED模式:以上兩種模式的混合使用钞翔,一般的復(fù)制使用STATEMENT模式保存binlog,對于STATEMENT模式無法復(fù)制的操作使用ROW模式保存binlog席舍,MySQL會根據(jù)執(zhí)行的SQL語句選擇日志保存方式
3 redo log和binlog日志的不同
- redo log是InnoDB引擎特有的布轿;binlog是MySQL的Server層實現(xiàn)的,所有引擎都可以使用
- redo log是物理日志来颤,記錄的是在某個數(shù)據(jù)也上做了什么修改汰扭;binlog是邏輯日志,記錄的是這個語句的原始邏輯福铅,比如給ID=2這一行的c字段加1
- redo log是循環(huán)寫的萝毛,空間固定會用完;binlog是可以追加寫入的滑黔,binlog文件寫到一定大小后會切換到下一個笆包,并不會覆蓋以前的日志
4 兩階段提交
create table T(ID int primary key, c int);
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),更新完成
- 將redo log的寫入拆成了兩個步驟:prepare和commit喉脖,這就是兩階段提交
5 分庫分表
水平拆分:同一個表的數(shù)據(jù)拆到不同的庫不同的表中椰苟。可以根據(jù)時間树叽、地區(qū)或某個業(yè)務(wù)鍵維度舆蝴,也可以通過hash進(jìn)行拆分,最后通過路由訪問到具體的數(shù)據(jù)题诵。拆分后的每個表結(jié)構(gòu)保持一致
-
垂直拆分:就是把一個有很多字段的表給拆分成多個表洁仗,或者是多個庫上去。每個庫表的結(jié)構(gòu)都不一樣性锭,每個庫表都包含部分字段赠潦。一般來說,可以根據(jù)業(yè)務(wù)維度進(jìn)行拆分草冈,如訂單表可以拆分為訂單她奥、訂單支持、訂單地址怎棱、訂單商品哩俭、訂單擴展等表;也可以拳恋,根據(jù)數(shù)據(jù)冷熱程度拆分凡资,20%的熱點字段拆到一個表,80%的冷字段拆到另外一個表谬运。
sharding jdbc
Sharding-JDBC分片策略:
standard:標(biāo)準(zhǔn)分片策略隙赁,對應(yīng)StandardShardingStrategy。提供對SQL語句中的=, IN和BETWEEN AND的分片操作支持梆暖。StandardShardingStrategy只支持單分片鍵鸳谜,提供PreciseShardingAlgorithm和RangeShardingAlgorithm兩個分片算法。PreciseShardingAlgorithm是必選的式廷,用于處理=和IN的分片咐扭。RangeShardingAlgorithm是可選的,用于處理BETWEEN AND分片,如果不配置RangeShardingAlgorithm蝗肪,SQL中的BETWEEN AND將按照全庫路由處理袜爪。
complex:符合分片策略,對應(yīng)ComplexShardingStrategy薛闪。復(fù)合分片策略辛馆。提供對SQL語句中
的=, IN和BETWEEN AND的分片操作支持。ComplexShardingStrategy支持多分片鍵豁延,由于多分片鍵之間的關(guān)系復(fù)雜昙篙,因此并未進(jìn)行過多的封裝,而是直接將分片鍵值組合以及分片操作符透傳至分片算法诱咏,完全由應(yīng)用開發(fā)者實現(xiàn)苔可,提供最大的靈活度。inline:行表達(dá)式分片策略袋狞,對應(yīng)InlineShardingStrategy焚辅。使用Groovy的表達(dá)式,提供對SQL
語句中的=和IN的分片操作支持苟鸯,只支持單分片鍵同蜻。對于簡單的分片算法,可以通過簡單的配置使用早处,從而避免繁瑣的Java代碼開發(fā)湾蔓,如: t_user_$->{u_id % 8} 表示t_user表根據(jù)u_id模8,而分成8張表砌梆,表名稱為t_user_0 到t_user_7 默责。hint:Hint分片策略,對應(yīng)HintShardingStrategy么库。通過Hint而非SQL解析的方式分片的策略。
對于分片字段非SQL決定甘有,而由其他外置條件決定的場景诉儒,可使用SQL Hint靈活的注入分片字段。例:內(nèi)部系統(tǒng)亏掀,按照員工登錄主鍵分庫忱反,而數(shù)據(jù)庫中并無此字段。SQL Hint支持通過Java API和SQL注釋(待實現(xiàn))兩種方式使用滤愕。none:不分片策略温算,對應(yīng) NoneShardingStrategy。不分片的策略间影。
水平分表
# shardingjdbc分片策略
# 配置數(shù)據(jù)源注竿,給數(shù)據(jù)源起名稱
spring.shardingsphere.datasource.names=m1
# 一個實體類對應(yīng)兩張表,覆蓋
spring.main.allow-bean-definition-overriding=true
#配置數(shù)據(jù)源具體內(nèi)容,包含連接池巩割,驅(qū)動裙顽,地址,用戶名和密碼
spring.shardingsphere.datasource.m1.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.m1.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.m1.url=jdbc:mysql://hadoop02:3306/course_db?serverTimezone=GMT%2B8
spring.shardingsphere.datasource.m1.username=root
spring.shardingsphere.datasource.m1.password=***
#指定course表分布情況宣谈,配置表在哪個數(shù)據(jù)庫里面愈犹,表名稱都是什么 m1.course_1 , m1.course_2
spring.shardingsphere.sharding.tables.course.actual-data-nodes=m1.course_$->{1..2}
spring.shardingsphere.sharding.default-data-source-name=m1
# 指定course表里面主鍵cid 生成策略 SNOWFLAKE
spring.shardingsphere.sharding.tables.course.key-generator.column=cid
spring.shardingsphere.sharding.tables.course.key-generator.type=SNOWFLAKE
# 指定分片策略 約定cid值偶數(shù)添加到course_1表,如果cid是奇數(shù)添加到course_2表
spring.shardingsphere.sharding.tables.course.table-strategy.inline.sharding-column=cid
spring.shardingsphere.sharding.tables.course.table-strategy.inline.algorithm-expression=course_$->{cid % 2 + 1}
# 打開sql輸出日志
spring.shardingsphere.props.sql.show=true
- 水平分庫
# shardingjdbc分片策略
# 配置數(shù)據(jù)源漩怎,給數(shù)據(jù)源起名稱,
# 水平分庫,配置兩個數(shù)據(jù)源
spring.shardingsphere.datasource.names=m1,m2
# 一個實體類對應(yīng)兩張表勋锤,覆蓋
spring.main.allow-bean-definition-overriding=true
#配置第一個數(shù)據(jù)源具體內(nèi)容,包含連接池怪得,驅(qū)動,地址卑硫,用戶名和密碼
spring.shardingsphere.datasource.m1.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.m1.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.m1.url=jdbc:mysql://hadoop02:3306/course_db?serverTimezone=GMT%2B8
spring.shardingsphere.datasource.m1.username=root
spring.shardingsphere.datasource.m1.password=***
#配置第二個數(shù)據(jù)源具體內(nèi)容徒恋,包含連接池欢伏,驅(qū)動,地址硝拧,用戶名和密碼
spring.shardingsphere.datasource.m2.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.m2.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.m2.url=jdbc:mysql://10.1.1.21:3306/course_db?characterEncoding=utf-8&useSSL=false&serverTimezone=GMT%2B8
spring.shardingsphere.datasource.m2.username=root
spring.shardingsphere.datasource.m2.password=***
#指定數(shù)據(jù)庫分布情況径筏,數(shù)據(jù)庫里面表分布情況
# m1 m2 course_1 course_2
spring.shardingsphere.sharding.tables.course.actual-data-nodes=m$->{1..2}.course_$->{1..2}
# 指定course表里面主鍵cid 生成策略 SNOWFLAKE
spring.shardingsphere.sharding.tables.course.key-generator.column=cid
spring.shardingsphere.sharding.tables.course.key-generator.type=SNOWFLAKE
# 指定表分片策略 約定cid值偶數(shù)添加到course_1表,如果cid是奇數(shù)添加到course_2表
spring.shardingsphere.sharding.tables.course.table-strategy.inline.sharding-column=cid
spring.shardingsphere.sharding.tables.course.table-strategy.inline.algorithm-expression=course_$->{cid % 2 + 1}
# 指定數(shù)據(jù)庫分片策略 約定user_id是偶數(shù)添加m1障陶,是奇數(shù)添加m2
#spring.shardingsphere.sharding.default-database-strategy.inline.sharding-column=user_id
#spring.shardingsphere.sharding.default-database-strategy.inline.algorithm-expression=m$->{user_id % 2 + 1}
spring.shardingsphere.sharding.tables.course.database-strategy.inline..sharding-column=user_id
spring.shardingsphere.sharding.tables.course.database-strategy.inline.algorithm-expression=m$->{user_id % 2 + 1}
# 打開sql輸出日志
spring.shardingsphere.props.sql.show=true
6 主從復(fù)制
1)Mysql主從復(fù)制原理
主從復(fù)制不是完全實時地進(jìn)行同步抱究,而是異步實時恢氯。這中間存在主從服務(wù)之間的執(zhí)行延時鼓寺,如果主服務(wù)器的壓力很大,則可能導(dǎo)致主從服務(wù)器延時較大敢靡。
2)主庫配置
vim /usr/local/mysqlData/master/cnf/mysql.cnf
[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)從庫配置
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錯誤是因為主從數(shù)據(jù)庫數(shù)據(jù)不一致
slave_skip_errors=1062
4)從服務(wù)器啟動I/O 線程和SQL線程
mysql> start slave;
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: 10.1.1.13
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即表示啟動成功
5) 主從復(fù)制延遲
- 延遲是sql thread與io thread之間差值,主機器負(fù)載過高造成更新推送延遲叭首,從機器負(fù)載過高造成拉取延遲
- 高并發(fā)分流:采用多主,誰寫誰讀图毕,業(yè)務(wù)層增加nosql 層-有更新讀緩存
- 從庫可以使用mysql5.7-支持多線程復(fù)制,rpl_semi_sync_master_enabled-完全同步機制
6)sharding jdbc實現(xiàn)讀寫分離
- Sharding-JDBC讀寫分離則是根據(jù)SQL語義的分析予颤,將讀操作和寫操作分別路由至主庫與從庫冬阳。
它提供透明化讀寫分離,讓使用方盡量像使用一個數(shù)據(jù)庫一樣使用主從數(shù)據(jù)庫集群肝陪。
spring.main.allow-bean-definition-overriding=true
#顯示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://hadoop02:3306/sharding-jdbc-db?useUnicode=true&useSSL=false&serverTimezone=Asia/Shanghai
spring.shardingsphere.datasource.ds1.username=root
spring.shardingsphere.datasource.ds1.password=***
spring.shardingsphere.datasource.ds1.maxPoolSize=100
spring.shardingsphere.datasource.ds1.minPoolSize=5
#slave-ds2數(shù)據(jù)庫連接信息
spring.shardingsphere.datasource.ds2.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.ds2.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.ds2.url=jdbc:mysql://hadoop03:3307/sharding-jdbc-db?useUnicode=true&useSSL=false&serverTimezone=Asia/Shanghai
spring.shardingsphere.datasource.ds2.username=root
spring.shardingsphere.datasource.ds2.password=***
spring.shardingsphere.datasource.ds2.maxPoolSize=100
spring.shardingsphere.datasource.ds2.minPoolSize=5
#slave-ds3數(shù)據(jù)庫連接信息
spring.shardingsphere.datasource.ds3.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.ds3.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.ds3.url=jdbc:mysql://hadoop01:3307/sharding-jdbc-db?useUnicode=true&useSSL=false&serverTimezone=Asia/Shanghai
spring.shardingsphere.datasource.ds3.username=root
spring.shardingsphere.datasource.ds3.password=***
spring.shardingsphere.datasource.ds.maxPoolSize=100
spring.shardingsphere.datasource.ds3.minPoolSize=5
#配置默認(rèn)數(shù)據(jù)源ds1 默認(rèn)數(shù)據(jù)源,主要用于寫
spring.shardingsphere.sharding.default-data-source-name=ds1
#配置主從名稱
spring.shardingsphere.masterslave.name=ms
#置主庫master,負(fù)責(zé)數(shù)據(jù)的寫入
spring.shardingsphere.masterslave.master-data-source-name=ds1
#配置從庫slave節(jié)點
spring.shardingsphere.masterslave.slave-data-source-names=ds2,ds3
#配置slave節(jié)點的負(fù)載均衡均衡策略,采用輪詢機制
spring.shardingsphere.masterslave.load-balance-algorithm-type=round_robin
#整合mybatis的配置
mybatis.type-aliases-package=com.ppdai.shardingjdbc.entity