[TOC]
# 簡介
必須開啟二進制日志,有些并沒有開啟,如果沒有開啟以后需要開啟就需要重啟服務器
**分擔讀負載**
利用二進制日志增量進行的,不需要太多的帶寬
但是在更新大批量的更改時會對帶寬造成一定的壓力
mysql的復制是基于二進制日志復制的
**從庫用二進制日志重放來完成的**
**最主要的就是從庫重放主服務的效率**
mysql的主從是異步的,所以無法保證主庫和從庫是一致的,無法保證主庫和從庫的延遲
非共享架構,同樣的數據分布在多臺服務器上,增加數據庫安全
可以實現數據庫在線升級
# 日志

二進制日志屬于服務層日志,記錄了所有對mysql數據庫的修改事件包括增刪改查事件和對表結構的修改事件
在binglog中記錄的是已經成功執行的,一些執行沒有成功事務回滾是不會記錄在這個日志中的
## 二進制日志格式
### 基于段的格式(SBR)
邏輯復制
binlog_format=STATEMENT
這是在mysql5.7之前默認的使用的格式,記錄更改的sql語句
**優點**
* 日志記錄量相對較小,節約磁盤及網絡I/O,因為是sql,不用去記錄每行的變化,如果只是對一條記錄修改或插入,row格式所產生的日志量還小于段產生的日志量
* 減少數據庫鎖的使用
**缺點**
* 必須要記錄上下文信息,保證語句在從服務器上執行結果和在主服務器上相同
* 對于一些特定的函數,比如UUID(),user()這樣非確定函數還是無法復制,如果使用這些函數可能造成主從服務器數據不一致
* 對于存儲過程,觸發器,自定義函數進行修改也可能造成數據不一致
* 相比基于行的復制在執行上時需要更多的鎖
* 要求主從數據庫的表結構必須一致,否則可能中斷復制
* 無法在從上單獨執行觸發器
---
在mysql中運行
~~~
show variables like 'binlog_format';
~~~
看他默認是基于什么的格式
~~~
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| binlog_format | ROW |
+---------------+-------+
~~~
我這邊mysql5.7的是基于行的
我們改為基于段格式
~~~
set session binlog_format=statement;
~~~
我們看下原來的binlog日志
~~~
show binary logs;
~~~
刷新下binlog
~~~
flush logs;
~~~
然后我們在命令行用mysqlbinlog對binglog日志進行查看
每個人目錄可能不一樣,log文件是用 `show binary logs;` 這個查看,然后在磁盤上找這個文件
~~~
/usr/local/mysql/bin/mysqlbinlog mysql-bin.000025
~~~
在這里面可以看到我們剛才執行的sql
### 基于行的日志格式(RBR)
binlog_format=ROW
這種格式可以避免mysql復制中出現的主從不一致問題
同一個sql語句修改1000條記錄情況下,基于段的日志格式只會記錄這個sql語句
基于行的日志會有1000條記錄分別記錄每一行的數據修改
**優點**
* 使mysql主從復制更安全,無論使用確定還是非確定性函數對于主從都是一樣的
* 對每一行數據的修改比基于段的復制高效,這樣就可以更快的在從庫上完成數據的重放,降低主從的延遲
* 誤操作而修改了數據庫中的數據,同時又沒有備份可以恢復的時候,我們可以通過分析二進制日志對日志中記錄的數據修改操作做反向處理的方式來達到恢復數據的目的
**缺點**
* 記錄日志量較大,每行都要記錄,消耗更多的磁盤IO和網絡帶寬,但是日志都是順序寫入的,所以順序寫入,IO消耗并不是太多
mysql官方考慮到了這一點
binlog_row_image=[FULL|MINIMAL|NOBLOB]
通過設置這個full表示主要一行中有一列修改就把這行的所有列都記錄下來
MINIMAL表示只記錄修改的列
NOBLOB和full很像就是對blob和text沒有修改的時候就不記錄這個列
---
把格式改為行
在mysql中運行
~~~
mysql> show variables like 'binlog_row_image';
+------------------+-------+
| Variable_name | Value |
+------------------+-------+
| binlog_row_image | FULL |
+------------------+-------+
~~~
然后我們在命令行用mysqlbinlog對binglog日志進行查看
每個人目錄可能不一樣,log文件是用 `show binary logs;` 這個查看,然后在磁盤上找這個文件
~~~
/usr/local/mysql/bin/mysqlbinlog mysql-bin.000027
~~~
這里的數據根本看不懂
~~~
/usr/local/mysql/bin/mysqlbinlog -vv mysql-bin.000027
~~~
加上 -vv 就可以看到一些對應的sql和后面跟的那行變化的所有值
我們要測試其他binlog_row_image
運行
~~~
set session binlog_row_image=minimal;
~~~
就可以了
### 混合日志格式
binlog_format=MIXED
他是混合了段的格式和行的格式的一些特點
* 根據SQL語句由系統決定在基于段和基于行的日志格式中作出選擇,大部分是基于段的,有些使用不確定函數的一些是使用行的
* 數據量大小由所執行的SQL語句決定
根據實際內容在以上兩者中切換
# mysql復制的工作方式

1. 主將變更寫入二進制日志
2. 從讀取主的二進制日志變更并寫入到relay_log中,這個讀取,從庫上開啟一個線程稱為IO線程和主庫建立個普通的客戶端連接,在主庫上建立個特殊二進制轉儲線程稱為binlog down,從庫上線程通過這個線程來讀取主庫上的二進制日志事件,他不會對事件進行輪詢,如果從庫上的線程追趕上主庫,他會進入到sleep狀態,直到主庫上有數據變更通知從庫的線程,才會被喚醒.relay_log格式和二進制日志格式是相同的,可以用binlog工具進行查看
根據從什么位置開始讀取主庫上二進制日志的方法不同又分為
基于日志點的復制
基于GTID的復制
3. 在從上重放relay_log中的日志,這一步用從的sql線程來執行,對于這一步可以配置是否記錄到從服務器的二進制日志文件中,日志格式不同重放的行為也不同
# 復制拓撲

## 主主復制

不會造成死循環
### 主備模式的主主復制
當一個主出現問題的時候,另一個主才會提供服務
注意
只有一臺服務器處于只讀狀態并且只作為熱備使用
在對外提供服務的主庫出現故障或是計劃性的維護時才會進行轉換
使原來的備庫成為主庫,而原來的主庫會成為新的備庫并處理只讀或是下線狀態,待維護完成后重新上線
* 確保兩臺服務器上的初始數據相同
在2個服務器上使用同一個備份文件,進行數據恢復方式來完成
或者 一臺已經運行一段時間的mysql來增加另外一臺主庫,這需要特殊的處理,在已有的數據庫上進行備份記錄下日志點等相關信息,這個信息作為老的庫和新的主庫連接時作為日志的binlog日志點來使用,然后在新的主庫上進行日志恢復時用這個binlog日志點
* 確保兩臺服務器上已經啟用binlog并且有不同的server_id
* 在兩臺服務器上啟用log_slave_updates參數
* 在初始的備庫上啟用read_only
---
我們也可以用下面這種方式

每個主下面都有只讀從,但是要注意的是如果一個主DB出現問題,這個主下面的從也要在從的負載中去掉以免讀到出問題主的從,數據會不一致
從庫數量太多,會消耗很多主庫的網絡流量,而且每個從庫復制主庫,都要主庫開啟一個binlog down線程
---
級聯復制

這樣就避免了主庫的分發負載,如果從庫很多,可以建立多個分發主庫
在分發主庫上要開啟slave_log_updates
### 主主模式的主主復制
2個主同時對外提供服務,這種無法分擔主的寫的負擔,因為寫無論發生在那個主庫上都會被附加到另外一個主上
注意
容易產生數據沖突而造成復制鏈路的中斷,如果造成沖突需要人為解決,耗費大量的時間
而且會造成數據丟失
* 兩個主中所操作的表最好能夠分開,避免數據的沖突
* 使用下面2個參數控制自增id的生成,避免自增id沖突
auto_increment_increment=2
auto_increment_offset=1 | 2 #自增id從1或是從2開始,一臺奇數一臺偶數
# 影響主從延遲的因素
復制主要是主庫執行完sql后,把相應的記錄放到binlog日志中,然后從庫再把這個binlog日志復制到自己的中繼日志中,然后從庫的sql線程從中繼日志中讀取數據來恢復自己的數據,這些是異步的,延遲是不可避免的
* 主庫上寫入二進制日志時間和主庫上執行大事務的消耗的時間,解決辦法是控制大事務變為小事務
* 二進制日志的傳輸時間和傳輸的日志的大小
* 默認情況下從庫只有一個sql線程,主庫上并發處理的到從庫上就變成串行.解決辦法最好使用mysql5.6中配置的多線程復制,來增加從上的sql線程的數量
* 多線程復制,mysql5.6中的多線程復制是從庫上每個線程處理一個數據庫上的數據回放,如果是一主多從,那么這邊的多線程復制還不如單線程復制,顯得有些雞肋,解決辦法mysql5.7中的可以按照邏輯時鐘的方式來分配sql線程
# 如何配置多線程復制
show slave status;
stop slave 在從上停止鏈路復制
set global slave_parallel_type = 'logical_clock'; 開啟邏輯時鐘
set global slave_parallel_workers=4; 設置復制的線程數量,也覺得并發處理的數量
start slave;
# 復制常見問題處理
由于數據損壞或丟失所引起的主從復制錯誤
* 主庫或從庫意外宕機引起的錯誤,沒有將最后事件刷到binlog日志中,從庫再次請求這個時間,主庫告訴從庫二進制日志文件中沒有這個事件.解決辦法:使用跳過二進制日志事件,注入空事務的方式先恢復中斷的復制鏈路,再使用其他方法來對比主從服務器上的數據
從庫宕機會導致master info文件沒有及時同步到磁盤上,master info文件中記錄了從庫已經同步了主庫的二進制日志文件的信息,會導致從庫重新執行了一些二進制日志.解決辦法:使用跳過二進制日志事件,用其他方法來對比主從服務器上的數據
* 主庫上的二進制日志損壞,意外的關閉通過change master命令來重新指定,但是這會丟失一些主庫上的更新,造成數據差異,解決辦法:用其他方法來對比主從服務器上的數據
* 備庫上的中繼日志損壞,只要主庫上沒事就好處理,通過change master命令指定IO線程重新從損壞的位置再次同步主庫的二進制日志
* 在從庫上進行數據修改造成的主從復制錯誤,從庫應該設置為只讀,但是在mysql5.7之前擁有slave權限的用戶還是能對從庫進行修改,主從復制依賴數據的一致性,如果數據一致性被破壞,復制鏈路會輕易的中斷.要人為的決定是保留主庫上的數據還是從庫上的數據
* 主從包括從從之間不唯一的server_id或server_uuid,server_uuid是記錄在數據目錄中的auto.cnf文件中,一旦這個文件存在,mysql是不會重新生成server_uuid的,這個問題非常隱蔽.2個相同的server_uuid一旦重復會導致重復執行二進制日志事件也有可能丟失二進制日志事件. 也會造成選擇相同的server_uuid,主從切換失敗
* max_allow_packet最大允許的包設置不一致,引起主從復制錯誤,主庫會記錄從庫接收多大的包,這個不正確會導致一些無限報錯,中繼日志損壞
# 復制無法解決的問題
* 分擔主數據庫的寫負載,在主庫上寫的事件,在從庫上都會重放,解決寫負載只能分庫分表來解決
* 自動進行故障轉移及主從切換
* 提供讀寫分離功能
# 高可用
## 單點故障
**共享存儲**

2個服務器共享一個磁盤,一個服務器宕機,另一個服務器接管磁盤
缺點這也是單點故障
---
**DRDB磁盤復制**

通過網卡把主服務器上的塊提交給備用服務器的塊,DRDB是鏡像不是共享存儲,缺點主DB被污染,備也被污染.
發生故障轉移時間長,故障恢復不能提供服務
---
**利用多寫集群**
percona公司提供的->pxc集群

一個事務被集群中所有事務提交后才可提交
缺點:整個集群中性能取決于性能最差的那臺集群,只支持innodb
---
**NDB集群**
所有節點都進行主主復制,所有節點都可寫入,所有節點都有相同的讀寫能力,并且每行數據都是冗余存儲的
缺點:要求所有數據存放在內存中,如果放在磁盤中性能會非常差,還有其他限制,一般不會使用
---
**mysql本身復制**
常見問題
主服務器切換后 如何通知應用新的主服務器的IP地址
如何檢查Mysql主服務器是否可用
如何處理從服務器和新主服務器之間那種復制關系
解決可以自己寫代碼解決也可以用第三方復制組件
組件常用有MMM還有MHA
# MMM的主要作用
監控和管理mysql的主主復制拓撲,并在當前的主服務器失效時,進行主和主備服務器之間的主從切換和故障轉移等工作
MMM監控Mysql主從復制健康情況
1. 主動主動模式的主主復制,2個主同時對外提供服務
2. 主動被動模式的主主復制,同時只有一個主提供服務,另一個主是備份
MMM是工作在第二種的復制模式,意思就是MMM同一時間只能有一個主對外提供服務
在主庫出現宕機時進行故障轉移并自動配置其他從對新主的復制
提供了主,寫虛擬ip,在主從服務器出現問題時可以自動遷移虛擬ip
**那么問題來了**
如何找到從庫對應的新的主庫日志點的日志同步點
如果存在多個從庫出現數據不一致的情況如何處理
MMM只是簡單把從做為主,在一個繁忙的系統中肯定會造成數據丟失
- SQL
- 名詞
- mysql
- 初識mysql
- 備份和恢復
- 存儲引擎
- 數據表損壞和修復
- mysql工具
- 數據庫操作
- 增
- 刪
- 改
- 查
- 數據類型
- 整數類型
- 小數類型
- 日期時間類型
- 字符和文本型
- enum類型
- set類型
- 時間類型
- null與not null和null與空值''的區別
- 數據表操作
- 創建
- 索引
- 約束
- 表選項列表
- 表的其他語句
- 視圖
- sql增刪改查
- sql增
- sql刪
- sql改
- sql查
- sql語句練習
- 連接查詢和更新
- 常用sql語句集錦
- 函數
- 字符函數
- 數值運算符
- 比較運算符與函數
- 日期時間函數
- 信息函數
- 聚合函數
- 加密函數
- null函數
- 用戶權限管理
- 用戶管理
- 權限管理
- pdo
- 與pdo相關的幾個類
- 連接數據庫
- 使用
- pdo的錯誤處理
- pdo結果集對象
- pdo結果集對象常用方法
- pdo預處理
- 常用屬性
- mysql編程
- 事務
- 語句塊
- mysql中的變量
- 存儲函數
- 存儲過程
- 觸發器
- mysql優化
- 存儲引擎
- 字段類型
- 三范式和逆范式
- 索引
- 查詢緩存
- limit分頁優化
- 分區
- 介紹
- 分區算法
- list分區
- range范圍
- Hash哈希
- key鍵值
- 分區管理
- 特別注意
- 分表
- 數據碎片與維護
- innodb表壓縮
- 慢查詢
- explain執行計劃
- count和max,groupby優化
- 子查詢優化
- mysql鎖機制
- 介紹
- 演示
- 總結
- 樂觀鎖和悲觀鎖
- 扛得住的mysql
- 實例和故事
- 系統參數優化
- mysql體系結構
- mysql基準測試
- 索引
- mysql的復制
- win配置MySQL主從
- mysql5.7新特性
- 常見問題
- general log
- 忘記密碼
- uodo log與redo log
- 事務隔離級別
- mysql8密碼登錄
- explain
- 高效的Tree表
- on delete cascade 總結
- mongod
- 簡介
- 集合文檔操作語句
- 增刪改查
- 索引
- 數據導入和導出
- 主從復制
- php7操作mongod
- 權限管理
- redis
- redis簡介
- 3.2版本配置文件
- 3.0版本配置文件
- 2.8版本配置文件
- 配置文件總結
- 外網連接
- 持久化
- RDB備份方式保存數據
- AOF備份方式保存數據
- 總結
- win安裝redis和sentinel部署
- 事務
- Sentinel模式配置
- 分布式鎖
- 管道
- php中redis代碼
- 發布訂閱
- slowlog
- Redis4.0
- scan和keys
- elasticsearch
- 配置說明
- 啟動
- kibana
- kibana下載
- kibana配置文件
- kibana常用功能
- 常用術語
- Beats
- Beats簡介
- Filebeat
- Packetbeat
- Logstash
- 配置
- elasticsearch架構
- es1.7
- head和bigdesk插件
- 插件大全
- 倒排索引
- 單模式下API增刪改查
- mget獲取多個文檔
- 批量操作bulk
- 版本控制
- Mapping映射
- 基本查詢
- Filter過濾
- 組合查詢
- es配置文件
- es集群優化和管理
- logstash
- kibana
- es5.2
- 安裝
- 沖突處理
- 數據備份
- 缺陷不足
- 集群管理api
- 分布式事務
- CAP理論
- BASE模型
- 兩階段提交(2PC)
- TCC (Try-Confirm-Cancle)
- 異步確保型
- 最大努力通知型
- 總結