Mysql高階面試問題總結

一、Mysql版本問題

使用的是什麼版本?是否對MYSQL升級?最新的版本是什麼,什麼特性吸引你?
1、除了官方提供的社區版和企業版,還有一個版本使用的比較多:Perscona Mysql,該版本是原來的mysql開發者後續維護的改進版,對mysql的社區版進行了優化,性能要優於社區版的,落後於官方的一個版本。
下載地址:https://www.percona.com/downloads/Percona-Server-LATEST/

2、Mysql另一個常見發行版:MariaDB
該版本是mysql初創者在mysql被Oracle收購之後,另起爐竈重新成立的。(Mysql5.5之後發展起來的)增加了許多特有的功能。
下載地址:https://downloads.mariadb.org/
版本對比:
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
3、關於版本升級
在主從複製中,高版本的Mysql可以作爲低版本的從來使用的,反過來有時候就不行
(1)升級可以給業務帶來的益處

  • 是否可以解決業務上某一方面的痛點?比如使用5.6時,主從複製場景下的數據同步延遲太大,就可以考慮升級到5.7,因爲5.7版本新增了多線程複製功能,支持更高的併發,能夠解決延遲的問題;再比如,數據庫中大量使用了json類型,在Mysql8以前的版本中,進行二進制主從複製時,是全部複製的,而不是隻複製變化的一部分,但是Mysql8進行了修改,支持只複製json中修改的部分。
  • 是否可以解決運維上某一方面的痛點?比如,5.7就在原來的基礎上提供了更好的管理工具。

(2)升級可能對業務帶來的影響

  • 是否對原來業務程序的支持有影響?比如,jdbc與mysql的版本匹配問題。
  • 是否對原來業務的性能是否有影響?比如,在5.6中開啓performance_schema,則有些處理的性能還不如5.5,因爲performance_schema收集數據時會影響到性能。(一般會在5.6版本的mysql中關閉performance_schema,而5.6以上的版本對此進行了更多的優化,可以放心使用)

(3)數據庫升級方案的制定
必須要在測試環境中不斷的被驗證可行,才能實施。

  • 進行全備份
  • 升級slave服務器版本
  • 手動進行主從切換
  • 升級master服務器版本
  • 升級完成後進行業務檢查

(4)數據庫升級失敗的回滾方案

4、最新的Mysql版本及其新特性
Mysql8.0版本的主要新特性:(官方將版本號從5.7直接跳到了8.0,所以其更新的功能是很多的)
在這裏插入圖片描述
在這裏插入圖片描述
在安全性上滿足了許多大公司對審計的要求。
在這裏插入圖片描述

二、用戶賬號管理類

1、在給定場景下爲某個用戶授權
1.1 Mysql數據庫賬號
賬號由兩部分組成,形如:用戶名@可訪問控制列表
mysql5.7之前,用戶名的最大長度是16字節
mysql5.7之後,用戶名的最大長度是32字節
“可訪問控制列表”限制了用戶可以從哪些服務器上進行訪問。比如:

  • %:代表可以從所有外部主機訪問;(不加,則默認就使用這個)
  • 192.168.1.%:表示可以從192.168.1網段訪問
  • localhost:DB服務器本地訪問
    注意,如果一個用戶名配置了多個控制列表,mysql會使用最先匹配的情況。在mysql客戶端訪問時,會自動識別。

mysql5.7之前,使用create user命令建立用戶就指定權限,但是mysql5.7之後,是要先使用create user命令建立用戶,然後再指定權限。

常用的用戶權限:
在這裏插入圖片描述
在這裏插入圖片描述
通過命令:show privileges查看支持的權限。

給一個create的用戶設置權限

grant select,update,delete,insert on db.tb to user@ip;

收回某個用戶的權限:

revoke delete on db.tb from user@ip;

2、如何保證數據庫賬號的安全?
慕課網的《
高性能可擴展MySQL數據庫設計及架構優化——數據庫開發規範的制定》觀看筆記可參考:https://blog.csdn.net/weixin_38477351/article/details/90142597
基本上遵循以下幾個原則即可:最小權限原則、密碼強度策略、密碼過期原則、限制歷史密碼重用原則。當然要注意,如果程序支持從配置中心讀取最新密碼的話可以使用密碼過期,否則,會引起服務異常。
mysql8.0中設置密碼過期和限制歷史重用:

>\h create user
password_option: {
PASSWORD EXPIRE [DEFAULT | NEVER | INTERVAL N DAY]
| PASSWORD HISTORY {DEFAULT | N}
| PASSWORD REUSE INTERVAL {DEFAULT | N DAY}
| PASSWORD REQUIRE CURRENT [DEFAULT | OPTIONAL]
}

>create user test@‘localhost’ identified by ‘123456’ password history 1;
通過以下命令進行查看設置情況
>select * from mysql.user where user=‘test’\G

3、數據庫遷移賬號
首先要判斷數據庫版本是否一致,如果一致,備份後恢復即可。如果不一致,則需要先導出授權語句,在目的庫中再執行一遍即可。

導出用戶建立以及授權語句:
pt-show-grants u=root,p=123456, h=localhost

三、服務器配置類

1、Group By語句的異常原因
SQL MODE:配置Mysql處理SQL的方式
set [session/global/persist] sql_mode=‘xxxx’
8.0之後新增persist,對global範圍進行持久化(保存到生成新的文件mysqld-auto.cnf中),重啓mysql後還會存在,而如果是session和global則重啓失效。

當然,可以在mysql的配置文件中進行配置:
[msyqlid] sql_mode=xxxx
(以前的版本只需要修改.cfg文件,但是新版本中則是將某些配置保存到了mysql日期文件中)

常用的SQL MODE
ONLY_FULL_GROUP_BY: 對於group by聚合操作,如果出現在select中的列、having或者order by子句的非聚合列,沒有在group by中出現,那麼這個SQL語法檢查報錯。
ANSI_QUOTES:禁止用雙引號來引用字符串(數據庫遷移時不同的mysql版本對雙引號不一定支持)
設置後,如果還是用雙引號則會報錯:ERROR 1054 (42s22):Unknow column ‘xx’ in ‘field list’
REAL_AS_FLOAT: Real作爲float的同義詞(因爲Real默認是double類型的)
在這裏插入圖片描述
PIPES_AS_CONCAT:將||視爲字符串的連接操作符而非或運算符

其實,上面的這些配置很接近於ANSI的標準,所以,同時設置這些值時,簡單的設置爲:SQL_MODE='ANSI’即可。

以上又被稱爲寬鬆模式,下面開始是嚴格模式。

Strict_trans_tables / strict_all_tables: 在事務存儲引擎/所有存儲引擎上啓用嚴格模式出現,那麼這個SQL語法檢查報錯。

Error_for_division_by_zero: 不允許0做爲除數(該模式下,除0後會產生警告,而寬鬆模式下沒有任何提示)

NO_AUTO_CREATE_USER:在用戶不存在時不允許grant語句自動建立用戶。

NO_ZERO_IN_DATE / NO_ZERO_DATE: 日期數據內 / 日期數據不能含0

NO_ENGINE_SUBSTITUTION: 當指定的存儲引擎不可用時報錯。

2、如何比較系統運行配置和配置文件中的配置是否一致
爲什麼會出現不一致的情況:使用set命令可以配置動態參數
如果判斷是否一致呢:使用pt-confgi-diff工具比較配置文件
pt-confgi-diff該工具目前不支持8.0的mysql,具體使用方法如下:
pt-config-diff u=root,p=xxx,h=localhost /etc/my.cnf
在這裏插入圖片描述

3、MySQL中關鍵的性能參數

  • max_connections:最大連接數
  • interactive-timeout: 設置交互連接的timeout時間
  • wait_timeout: 設置非交互連接的timeout時間
  • max_allowed_packet: 控制mysql可以接收的數據包大小
  • sync_binlog: 爲了提高io性能而設置的參數,表示每寫多少次緩衝會向磁盤同步一次binlog。對於master,最好設置爲1,最大限度的同步,以免造成數據丟失。
  • sort_buffer_size: 設置每個會話使用的排序緩存區的大小。
  • join_buffer_size: 設置每個會話使用的連接緩衝的大小。
  • read_buffer_size: 指定了當對一個MYISAM(就是一個臨時表,8.0以前的查詢中會存在臨時表彙總最後結果的操作,排序)進行表掃描時所分配的讀緩存池的大小(一定是4k的倍數)
  • read_rnd_buffer_size: 設置控制索引緩衝區的大小

加粗的四個參數是針對每個線程分配的,所以,如果存在100個連接,就有可能出現內存溢出的風險。

  • binlog_cache_size:設置每個會話用於緩存未提交的事務緩存大小。

存儲引擎相關的參數:

  • innodb_flush_log_at_trx_commit :
    0:每秒進行一次重做日誌的磁盤刷新操作;
    1:每次事務提交都會刷新事務日誌到磁盤中;(默認,最好使用這個)
    2:每次事務提交寫入系統換存每秒向磁盤刷新一次(有可能丟失一秒的事務)。
  • innodb_buffer_pool_size: 設置Innodb緩衝池的大小,應爲系統可用內存的75%
  • innodb_buffer_pool_instances: Innodb緩衝池的實例個數,每個實例的大小爲總緩衝池大小 / 實例個數。
  • innodb_file_per_table:設置每個表獨立使用一個表空間文件。(5.7以及後續版本默認啓動該參數)

四、Mysql日誌

1、常用日誌(服務器的日誌,而不是存儲引擎的日誌)
錯誤日誌error_log:記錄啓動、運行、停止出現的問題。
分析排查mysql運行中的錯誤;記錄未經授權的訪問。

  • 指定錯誤日誌的路徑:log_error=$mysql/sql_log/mysql_error.log
  • 設置記錄錯誤日誌的級別:log_error_verbosity=[1,2,3]
    1—Error messages
    2—Error and warning messages
    3—Error,warning and note messages
  • 8.0中新增參數:log_error_services=[日誌服務組件1;日誌服務組件2]
    log_filter_internal—默認的日誌過濾組件,依賴log_error_verbosity(默認)
    log_sink_internal—默認的日誌輸出組件,依賴log_error(默認)
    log_sink_json—將錯誤日誌輸出到json文件(需要安裝組件)
    log_sink_syseventlog—將錯誤日誌輸出到系統日誌文件中
mysql> select @@log_error_services;
+----------------------------------------+
| @@log_error_services                   |
+----------------------------------------+
| log_filter_internal; log_sink_internal |
+----------------------------------------+
1 row in set (0.00 sec)
# 安裝json組件
mysql> install component 'file://component_log_sink_json';
Query OK, 0 rows affected (0.03 sec)

常規日誌general_log:記錄所有發向mysql的請求。
分析客戶端發送到mysql的實際請求時打開:
general_log=on / off
分析完後,一定要記得關閉,否則在幾分鐘內,就有可能佔滿空間。
general_log_file=$path
log_output=[file | table | none]

慢查詢日誌slow_query_log:記錄符合條件的查詢。
找需要優化的SQL:超過一定的閾值,沒有使用到索引。
slow_query_log = on / off
slow_query_log_file = $path
long_query_time=xxxx秒
log_queries_not_using_indexes=ON / OFF(默認off)
下面兩個不常用
log_slow_admin_statements=ON / OFF(記錄執行的管理類的命令,默認off)
log_slow_slave_statements=ON / OFF(默認off)

二進制日誌binary_log: 記錄全部有效的數據修改日誌。直接關係到對Mysql的高可用配置。(非常重要)

  • 記錄所有對數據庫中數據的修改
  • 基於時間點的備份和恢復(然後再增量的備份和恢復,另外還可以恢復誤操作的數據)
  • 主從複製(高可用架構都是通過二進制日誌實現的)

log-bin:靜態參數,只能在配置文件中配置,且只能是重啓生效。
可以配置存放的目錄和前綴名,默認存放在mysql的數據目錄中且以主機名作爲前綴。
binlog_format=[ROW | STATEMENT | MIXED],默認ROW,避免出現主從不一致的問題。statement是基於段的方式,比如一條SQL語句修改一萬行數據,row會記錄一萬次,而statement只是記錄SQL語句。所以,ROW方式會產生大量的記錄,如何減少ROW日誌呢?辦法就是下面的這個參數設置:binlog_row_image
binlog_row_image=[FULL | MINIMAL | NOBLOB],定義二進制日誌記錄的方式。FULL——默認使用該參數,會將修改前後的數據都記錄下來;MINIMAL——只記錄修改的數據,一般使用該參數;NOBLOB——記錄除blob以外的數據。

flush logs; // 刷新日誌文件,從而生成一個新的日誌文件。

上面有提到,在主從複製下,不建議使用statement,只能使用ROW,但是如果出現問題想看一下執行的SQL語句時,怎麼辦呢?這時就需要使用:binlog_rows_query_log_events參數來記錄執行SQL語句
binlog_rows_query_log_events=[ON | OFF]

log_slave_updates=[ ON | OFF ],開啓後,slave服務器也會記錄日誌到slave服務器上。默認爲off,就不會同步主上的日誌到slave上。
sync_binlog=[ 1 | 0 ];控制mysql如何刷新二進制日誌到磁盤,5.7後的版本默認爲1,也就是每寫一次二進制日誌,就會向磁盤刷新一次。即使是mysql崩潰,數據也不會丟失。如果是0,則由操作系統自己決定何時刷新數據到磁盤。

隨着操作的不斷增加,二進制日誌也會不斷的增大,最好是定期備份到其他地方。
expire_logs_days = days // 過期時間爲一天
purge binary logs to ‘mysql-bin.010’ // 將mysql-bin.0001到mysql-bin.009的文件全部刪除。
purge binary logs before ‘2019-12-01 22:00:00’ // 將這個時間點之前的二進制文件刪除

中繼日誌relay_log:用於主從複製,臨時存儲從主庫同步的二進制日誌。
主要作用是:臨時記錄從master服務器同步的二進制日誌。
重要的參數有兩個:
relay_log = filename // 指定位置和前綴
relay_log_purge = [ ON | OFF ] // 清理功能

2、通過日誌審計

https://www.jianshu.com/p/8339a4c86bd4
https://blog.csdn.net/qq_41930193/article/details/82776159

五 存儲引擎

Mysql數據庫也被稱爲插件式的數據庫,因爲可以更換不同的存儲引擎。
1、常見的存儲引擎以及適用場景:

  • MyIsam:不支持事務;5.6之前默認使用,最常用的非事務型存儲引擎。
    一般情況下的DB是服務層實現事務的,而mysql是通過存儲引擎實現的。
    MyISAM是以堆表的方式存儲,所以沒有特定順序的,沒有聚集索引的概念,所以索引的葉子節點存儲的就是指向數據的物理地址,而不是聚集索引的位置,因此避免了索引中的二次查找,對於大表的查詢性能會有一定的提高,單從大表的查詢性能上來看,MyISAM的性能一定是好於InnoDB的
    MyISAM使用的是表級鎖;在查詢時,加的是共享鎖,修改數據時加的是排他鎖。所以,讀寫時會阻塞,MyISAM天生不適合高併發場景下;
    MyISAM支持Btree索引,空間索引,全文索引;
    MyISAM的表索引和數據是分開存儲的,MYD、MYI,可以對這種表壓縮,損壞時可以修復。
    在這裏插入圖片描述
    使用場景:讀操作遠遠大於寫操作的場景;不需要事務支持的場景;

  • CSV:不支持事務;以CSV格式存儲的非事務型存儲引擎。
    CSV格式指的是:每一列數據用逗號分隔,字符串用雙引號括起來。(Comma-Separated Values的縮寫)
    CSV存儲引擎要求每一列都不能爲null;
    CSV存儲引擎不支持索引
    適用場景:做爲數據交換的中間表使用;

  • Archive:不支持事務;只允許查詢和新增數據而不允許修改的非事務型存儲引擎。(適用場景很顯然就是用在歸檔數據和日誌中)
    Archive存儲引擎的表數據會使用zlib壓縮;
    Archive存儲引擎只支持Insert和Select;
    Archive存儲引擎只允許在自增ID上建立索引;
    適用場景:日誌和數據採集類應用;數據歸檔存儲;

  • Memory:不支持事務;是一種易失性的非事務存儲引擎。(在內存中,重啓數據消失;在mysql中如何要臨時存儲中間的結果,並且這些臨時數據在符合一定條件的前提下,就會把中間結果數據存儲在Memory存儲引擎的表中)
    數據在內存中;
    所有字段長度固定;
    支持Btree和Hash索引;
    適用場景:用於緩存字典映射表;緩存週期性分析數據(類似於redis);

  • InnoDB:支持事務;最常用的事務型存儲引擎。(5.6以後默認)
    事務型存儲引擎支持ACID;
    數據按主鍵聚集存儲;每一個非主鍵索引的葉子節點所指向的都是數據行的主鍵,而不是數據存儲的物理位置,因此主鍵的大小直接影響查找的性能,另一方面,數據時按照主鍵的邏輯順序存儲的,如果主鍵的順序經常的無規則的變化,那麼一定會造成數據的不斷遷移,這樣會帶來IO性能的影響。(所以,分佈式中常用雪花算法生成ID)
    支持行級鎖以及MVCC;mvcc就是多版本併發控制,避免讀寫操作的相互阻塞。
    支持Btree和自適應Hash索引;自適應Hash索引指的是:InnoDB存儲引擎會根據數據統計信息,在內存中建立Hash索引,這種索引能用於等值查找,並且不需要DBA人爲的干預。
    支持全文索引和空間索引;5.6版本以及之後開始支持全文索引,5.7以及之後支持空間索引。
    適用場景:大多數OLTP場景。—— On-Line Transaction Processing聯機事務處理過程(OLTP),也稱爲面向交易的處理過程,其基本特徵是前臺接收的用戶數據可以立即傳送到計算中心進行處理,並在很短的時間內給出處理結果,是對用戶操作快速響應的方式之一。

補充:數據處理大致可以分成兩大類:聯機事務處理OLTP(on-line transaction processing)、聯機分析處理OLAP(On-Line Analytical Processing)。OLTP是傳統的關係型數據庫的主要應用,主要是基本的、日常的事務處理,例如銀行交易。OLAP是數據倉庫系統的主要應用,支持複雜的分析操作,側重決策支持,並且提供直觀易懂的查詢結果。
OLTP 系統強調數據庫內存效率,強調內存各種指標的命令率,強調綁定變量,強調併發操作;
OLAP 系統則強調數據分析,強調SQL執行市場,強調磁盤I/O,強調分區等。

在這裏插入圖片描述

  • NDB存儲引擎:用於集羣中,能夠保證一致性。但是並不常用,因爲不適合高併發,大數據量中應用。
    主要用於Mysql集羣中的存儲引擎;
    事務存儲引擎;
    數據存儲在內存中;
    支持行級鎖;
    支持高可用集羣;
    支持Ttree索引;
    適用場景:需要數據完全同步的高可用場景;

2、Innodb在什麼場景下無法在線修改表結構
5.5版本中如果要執行DDL操作時,會產生排它鎖,阻塞寫操作。5.6以及後續已經改善了。

(1)首次增加全文索引和空間索引的場景下
InnoDB在增加全文索引和空間索引的場景下,由於要增加一個隱藏列來記錄索引的信息,所以要重新建表,就不能在線修改表結構。也就是說,當第一次對錶進行建全文索引和空間索引時,不能在線進行

(2)刪除主鍵的場景下
InnoDB是按照主鍵的邏輯順序存儲的,當修改主鍵時,就需要重新排列,所以無法在線執行刪除主鍵的操作。

(3)增加自增列的場景下
自增列作爲主鍵的一部分,如果在線增加自增列時,就會影響到主鍵,就會影響到排列順序想,所以,不能在線執行該操作。

(4)修改列類型的場景下
因爲修改類型時,要對所有的數據進行校驗,所以,也不能在線完成。

(5)修改表的字符集場景下
因爲這種情況下,要對所有的數據進行校驗轉換,所以,也不能在線完成。
在這裏插入圖片描述
在線DDL存在的問題:

  • 部分語句不支持在線DDL;
  • 長時間的DDL操作會引起嚴重的主從延遲
  • 無法對DDL操作進行資源限制(尤其是操作大表時,有可能出現內存不足導致語句執行失敗)

3、如何更安全的執行DDL?如果在無法進行在線修改表結構的情況下,要如何操作?

解決方案:pt-online-schema-change [options] DSN
這是Perscona 的工具,pt-online-schema的原理是:先建立一個和所要修改的表相同的新表,結構是修改後的結構,然後把原表中的數據更新到這個新表中,數據導入完成後,新舊錶重命名即可,只有短暫的鎖定。

在這裏插入圖片描述
執行的過程和原理可以從輸出中看出:
在這裏插入圖片描述

4、InnoDB時如何實現事務的?
(1)什麼是事務?

  • 原子性A:全成功完成或者全失敗不操作;
  • 一致性C:事務開始前和事務結束以後,數據庫的完整性沒有被破壞;
  • 隔離性I:事務之間的可見性;
  • 持久性D:事務一旦提交,其結果就是永久的;

(2)事務的實現方式

  • 原子性A:回滾日誌Undo log,用於記錄數據修改前的狀態;
  • 一致性C:重作日誌Redo log,用於記錄數據修改後的狀態;
  • 隔離性I:鎖——用於資源隔離,分爲共享鎖和排它鎖;
  • 持久性D:重作日誌+回滾日誌共同實現;

以A賬戶向B賬戶匯款500元爲例:
在這裏插入圖片描述

5、InnoDB讀操作是否會阻塞寫操作?讀數據時加共享鎖,修改數據時加排它鎖,而共享鎖和排他鎖是不兼容的,爲什麼實際使用中沒有阻塞呢?
查詢需要對資源加共享鎖(S),防止其他事務修改數據
數據修改需要對資源加排他鎖(X),防止其他事務修改數據

Innodb中使用了**MVCC(多版本併發控制)**實現了讀寫不阻塞
簡單的說MVCC的過程如下:(還是以轉賬業務爲例)
在這裏插入圖片描述
也就是說,雖然加了排它鎖,其他事務是讀取的undo.log裏的值,與鎖無關。
MVCC只工作在REPEATABLE READ和READ COMMITED隔離級別下。

六 高可用架構

1、主從複製是如何工作的
(1)實現原理
在這裏插入圖片描述
主從複製——異步複製
一旦Master宕機會丟失數據
在這裏插入圖片描述

mysql從5.6開始引入了半同步複製機制
mysql>show plugins; // 查看已經安裝的插件
mysql>install plugin rpl_semi_sync_master SONAME ‘semisync_master.so’; // 在Master上安裝半同步複製-Linux環境
mysql>install plugin rpl_semi_sync_master SONAME ‘semisync_master.dll’; // 在Master上安裝半同步複製-Windows環境
mysql>install plugin rpl_semi_sync_slave SONAME ‘semisync_slave.so’; // 在Slave上安裝半同步複製-Linux環境
mysql>install plugin rpl_semi_sync_slave SONAME ‘semisync_slave.dll’; // 在Slave上安裝半同步複製-Windows環境
在這裏插入圖片描述

(2)異步方式主從複製的配置步驟(Master版本儘量不要高於Slave版本)
Master:

  • 開啓binlog(必須),開啓gtid(可選,大於5.6版本即可)
  • 建立同步所需要的賬號
  • 使用master_data參數備份數據庫
  • 把備份文件傳輸到Slave服務器
# 查看版本是否一致,如果是8.0版本要注意密碼的認證方式
>select @@version;
# 查看是否啓用了binary_log和gtid模式
>show variables like 'log_bin%';
>show variabels like 'gtid_mode';	// 要求要在配置文件中配置:enforce-gtid-consistency / log-slave-updates=on / master_info_repository=TABLE / relay_log_info_repository=TABLE
# 建立複製所用賬號並授權
>  create user repl@'192.168.1.%' identified by '123456';
>   grant replication slave on *.* to repl@'192.168.1.%';
# 導出現有的數據庫(single-transaction保證導出數據時事務的一致性,master-data記錄當前備份的日誌點)
>  mysqldump --single-transaction -uroot -p --routines --triggers --events --master-data=2 --all-databases > master.sql
// master-data有兩種取值:1和2,1代表只會生成change master command;2代表不僅僅生成change master command 而且會註釋掉這些命令。

將master.sql文件上傳到從服務器上

Slave:

  • 開啓binlog(可選),開啓gtid(可選,大於5.6版本即可)
  • 恢復Mster上的備份數據
  • 使用Change Master配置鏈路
  • 使用start slave啓動複製
# 導入備份文件
>msyql -uroot -p < maser.sql
# 完成主從複製鏈路,master_log_file和master_log_pos從備份文件中獲取
>change master to master_host='192.168.1.1', master_log_file='mysql-bin.0000001',master_log_pos=400;
# 查看複製鏈路具體信息
>show slave status \G;
# 啓動複製鏈路,需要指定複製賬號
>start slave user='repl' password='123456';
# 查看複製鏈路具體信息,可以看到Slave_IO_Running:Yes; Slave_SQL_Running: Yes
>show slave status \G;

(3)半同步方式的主從複製步驟
首先要保證安裝了半同步方式的插件(master和slave都需要)

# 查看半同步方式的變量
>show variables like 'rpl%';
# 設置半同步的超時時間500ms
>set persist rpl_semi_sync_master_timeout=500;
>set persist rpl_semi_sync_master_enabled=on;

Slave Mysql中只需要開啓即可。

以上配置是在Mysql正在運行的時候進行的,要想起作用,需要重啓複製鏈路,在Slave mysql中只需要重新啓動io線程即可。
mysql>stop slave io_thread;
mysql>start slave io-thread user=‘repl’ password=‘123456’;
mysql>show slave status \G // 查看啓動狀態

在master mysql上可以查看半同步複製的啓動狀態:
mysql>show global status like ‘rpl%’;
在這裏插入圖片描述
在slave mysql也執行該命令,會看到只有Rpl_semi_sync_slave_status ‘ON’

2、基於日誌點和GTID方式的複製
5.6版本之後引入的GTID方式(全局事務ID)
https://blog.51cto.com/13434336/2178937
https://blog.csdn.net/woailyoo0000/article/details/88981380

(1)對於基於日誌的複製方式,是slave請求master的增量日誌依賴於日誌偏移量的,所以在配置鏈路時需要指定master_log_file和master_log_pos參數。同一個事務在master和slave中的記錄都是不相同的,所以,一旦出現master宕機,需要做主從遷移的時候,很難在master中找到正確的二進制文件和偏移量。這也就是爲什麼在5.6中引入GTID方式的主要原因。

(2)GTID
所謂的全局僅僅指的是:在同一個集羣範圍之內,也就是說,如果有一個一主三從的主從複製架構的話,四臺服務器上的事務ID是唯一的。GTID的組成如下:
GTID=source_id:transaction_id
GTID的作用:source_id標識出事務從哪一臺服務器上最初提交的;另一個可以方便的對Mysql實例進行故障轉移。

slave 增量同步Master的數據依賴於其未同步的事務ID;
配置複製鏈路時,Slave可以根據已經同步的事務ID繼續自動同步。

兩種複製方式的比較:

基於日誌方式 基於GTID方式
兼容性好 同老版本的Mysql / MariaDB不兼容
支持MMM和MHA架構 僅支持MHA架構
主備切換後很難找到新的同步點 基於事務ID複製,可以很方便的找到未完成同步的事務ID
可以方便的跳過複製錯誤 只能通過設置入空事務的方式跳過錯誤

如何選擇複製方式:能用GTID就用GTID,優先選擇GTID。

3、MMM和MHA兩種高可用架構的優缺點
MMM和MHA是兩種對主從複製架構管理的系統。
https://www.jianshu.com/p/7331779dbae8

數據中間層的作用是:負責數據庫讀寫分離、負載均衡或分庫分表的。
MMM和MHA的作用是:保障數據庫服務的高可用。
這兩種架構的作用可以概括爲以下幾點:

  • 對主從複製集羣中的Master的健康進行監控
  • 當Master宕機後把寫VIP遷移到新的Master;(VIP是獨立於數據庫服務器物理IP的另外的虛擬IP,這個虛擬IP可以按需要任意綁定到具有Master角色的服務器上,當然,同一時間虛擬IP只能綁定一個IP上,上層只是訪問這個虛擬IP即可)
  • 重新配置集羣中的其他Slave對新的Master同步

3.1 MMM(Master-Master replication managerfor Mysql)
兩個master(一主一備,同一時間只有一個提供服務)
正常情況下的主從佈局:
在這裏插入圖片描述
當目前的主Mysql出現宕機後,從Mysql自動遷移到主備Mysql上,並且寫VIP也綁定到主備:
在這裏插入圖片描述
當某一個從Mysql出現問題後,MMM會自動將VIP綁定到其他從Mysql上:
在這裏插入圖片描述
當然,除了Mysql服務器之外,還需要有一個運行監控這些Mysql服務的服務:MMM_Monitor,上面圖中的每一個mysql服務器上都有一個mmm_agent組件。

優點:

  • 提供了讀寫VIP的配置,使讀寫請求都可以達到高可用;
  • 工具包相對完善,不需要額外開發腳本;
  • 完成故障轉移後,可以持續對Mysql集羣進行高可用監控;

缺點:

  • 故障切換簡單粗暴容易丟失事務;(解決方案:主備使用5.7以後的半同步複製)
  • 不支持GTID的複製方式;(解決方案:自行修改perl腳本實現)
  • 社區不活躍,很久不再更新版本

適用場景:

  • 使用基於日誌點的主從複製方式
  • 已經使用主主複製架構的
  • 需要考慮讀高可用的場景

3.2 MHA(Master High Availability)
正常情況下的佈局:
在這裏插入圖片描述
當主mysql出現問題後,在從mysql中選舉一個master
在這裏插入圖片描述
故障轉移步驟:

  1. 選舉具有最新更新的Slave
  2. 嘗試從宕機的master保存二進制日誌
  3. 應用差異的中繼日誌到其他slave
  4. 應用從Master保存的二進制日誌
  5. 提升選舉的slave爲新的master
  6. 配置其他slave向新的master同步

優點:

  • 支持GTID的複製方式和基於日誌點的複製方式;
  • 可從多個Slave中選舉最適合的新master;
  • 會嘗試從舊master中儘可能多的保存未同步的日誌;

缺點:

  • 未必能獲取到舊主未同步的日誌;(解決方案:主備使用5.7後的半同步複製)
  • 需要自行開發寫VIP轉移腳本;
  • 只監控master而沒有對slave實現高可用的辦法;

適用場景:

  • 使用基於GTID的複製方式;
  • 使用一主多從的複製架構;
  • 希望更少的數據丟失場景;

4、如何減小主從複製的延遲
產生原因:
在這裏插入圖片描述
幾種減小主從複製延遲的方法:
(1)大事務:數萬行的數據更新以及對大表的DDL操作

  • 化大事務爲小事務,分批進行更新
  • 使用pt-online-schema-change工具進行DDL操作
    先建立一個與原表結構相同但不包括任何數據的新表,對該表進行DDL操作後,再將數據逐步複製到該表中,然後同時修改原始表和新表的名字,最後將原始表刪除。

(2)網絡延遲

  • 減小單事務處理的數據量以減少產生的日誌文件的大小
  • 減少主上所同步的slave數量(最好不要超過5個)

(3)Master多線程寫入,Slave單線程恢復引起的延遲

  • 使用5.7之後的多線程複製(5.6不成熟)
  • 使用MGR複製架構(多寫複製的集羣)

5、MGR
5.7之後引入了全新的主從複製技術:MGR,這是將來的趨勢。
MGR(MySQL Group Replication)是一個MySQL Server插件,可用於創建彈性,高可用MySQL集羣方案。有一個內置的組成員服務,在任何給定的時間點,保持組的視圖一致並可供所有服務器使用。服務器可以離開並加入組,視圖也會相應更新。當成員離開組,故障檢測機制會檢測到此情況並通知組視圖已更改。

簡單的說:複製組就是一組彼此之間可以通過消息通訊來保持數據一致性的mysql服務器,而在複製組中每一臺服務器都可以獨立的完成數據的更新。也就是說,在MGR中,可以實現多個組同時對數據的修改。
MGR是在Mysql異步複製之上使用Paxos協議來實現的。 Paxos是分佈式一致性的算法,主要就是爲了解決多個節點併發操作數據時的讀寫數據一致性的問題。

MGR是一種不同於異步複製的多Master複製集羣。MGR和異步複製的主要區別還在於:MGR中已經不存在slave角色了,每個節點都需要安裝Group_replication插件
在這裏插入圖片描述

MGR的複製原理:
在這裏插入圖片描述
其中一個節點發送修改數據的請求(上圖中是master1發起),向其他節點廣播,只有當集羣中大多數節點都認可了這些數據修改後才能夠執行,MGR可以保證事務在各個集羣節點中進行的順序一致的,但是事務在各個節點中是分別提交的,所以,各個節點的數據還是會有不同步的情況,但是這個不同步的情況已經很小很小了,比異步複製的情況好很多。

MGR中支持多種模式,官方更推薦使用單主模式,因爲在多主模式下更容易出現死鎖和寫衝突,並且多主模式並不能減少寫負載。

單主模式下:只有一個節點可以處理寫和讀請求,其他節點負責讀請求(只讀),MGR集羣會自動選出主節點,宕機後重新選擇主節點。
設置group_replication_single_primary_mode=on; 該變量在運行狀態下是不能修改的,並且各個節點都需要設置該參數。
在這裏插入圖片描述
多主模式
每個節點都可以處理 / 同時處理寫和讀請求,多個事務時的順序和衝突就難免出問題,一旦出現問題後,MGR會自動選擇某個事務回滾。所以建議使用單主模式。
在這裏插入圖片描述
MGR所需要的資源
在這裏插入圖片描述
MGR複製架構的配置步驟:

  • 安裝group_replication插件
    mysql>install plugin group_replication soname ‘group_replication.so’; // 每個節點都需要安裝

  • 在第一個實例上新建複製用戶和權限

  • 配置第一個組實例
    mysql>show variables like ‘transaction_write_set_extraction’; // 事務的加密算法,設置成"XXHASH64",解決衝突的加密算法
    mysql>show variable like ‘binlog_checksum’; // 默認爲CRC32,設置該參數爲none
    mysql>set persist binlog_checksum=none;
    mysql>show variable like ‘group_replication_group_name’; // 查看默認組名稱
    mysql>select uuid(); // 一般使用UUID函數重新生成一個
    mysql>show variable like ‘group_replication_local_address’; // 設置本地服務IP/port,此時的端口是內部通信端口
    mysql>set global group_replication_bootstrap_group=on; // 初始化主複製集羣,在第一次啓動後可以設置爲off
    mysql>start group_replication; // 啓動主複製集羣
    mysql>set global group_replication_bootstrap_group=off; // 已經啓動過了,就可以關閉了
    mysql>use performance_schema; // 切換庫,找主從複製信息表replication_group_member_stats
    mysql>select * from replication_group_member_stats\G // 查看主從複製信息

  • 把其他實例加入組
    mysql>change master to master_user=‘repl’ password=‘123456’ for channel ‘group_replication_recovery’; // 同步數據
    mysql>show slave status for channel ‘group_replication_recovery’\G;
    mysql>start group_replication;

MGR複製架構的優點

  • Group Replication組內成員間基本無延遲;(事務的提交是在各個節點中,並不能保證絕對的同步)
  • 可以支持多寫操作,讀寫服務高可用;
  • 數據強一致,可以保證不丟失事務;

MGR複製架構的缺點

  • 只支持InnoDB存儲引擎的表,並且每個表上必須有一個主鍵
  • 在單主模式下很難確認下一個primary
  • 只能在grid模式的複製形式下,且日誌格式必須爲row

MGR複製架構的適用場景

  • 對主從延遲十分敏感的應用場景
  • 希望可以對讀寫提供高可用的場景
  • 希望可以保證數據強一致性的場景

介紹和使用比較全面的連接如下:
https://blog.csdn.net/L835311324/article/details/89345195

6、如何解決數據庫讀寫負載過大的問題

如何解決讀負載大的問題
讀寫分離,映入中間層MyCat、ProxySQL、Maxscale
在這裏插入圖片描述

  • 爲原DB增加Slave服務器
  • 進行讀寫分離,把讀分擔到Slave
  • 增加數據庫中間層,進行負載均衡

如何解決寫負載大的問題
在這裏插入圖片描述

七 備份恢復

1、如何對數據進行備份

邏輯備份:轉儲sql語句,速度較慢
物理備份:直接copy數據文件備份,速度很快

  • 全量備份
  • 增量備份
  • 差異備份

常用的備份工具:

  • mysqldump:最常用的邏輯備份工具,支持全量備份以及條件備份
    優點:備份結果爲可讀sql文件,可用於誇版本誇平臺的數據恢復;易於壓縮;自帶工具,無需安裝。
    缺點:只能單線程執行備份恢復任務,速度偏慢;爲完成一致性備份需要對備份表加鎖,容易造成阻塞;會對Innodb buffer pool造成污染。
    mysqldump --help查看如何使用
    可以使用–where進行有條件的備份

  • mysqlpump:多線程邏輯備份工具,mysqldump的增強版本(5.7引入)
    優點:mysqlpump語法同msyqldump高度相似;支持基於庫和表的並行備份,可以提高邏輯備份的性能;支持使用ZLIB和Lz4算法對備份進行壓縮;
    缺點:基於表進行並行備份,對於大表來說性能較差;5.7.11之前版本不支持一致性並行備份;會對Innodb buffer pool造成污染。
    mysqlpump --help | more // 查看幫助信息
    示例:https://www.cnblogs.com/zhoujinyi/p/5684903.html
    mysqlpump --compress-output=zlib --set-gtid-purged=off --databases 庫名 > xxx.zlib
    利用mysql自帶的解壓縮工具:zlib-decompress xxx.zlib 輸出的名稱.sql

  • xtrabackup:Innodb在線物理備份工具,支持多線程和增量備份。(Percona公司開發)
    優點:支持Innodb存儲引擎的在線熱備份,對Innodb緩衝沒有影響(啓動時記錄redolog的序列號,後臺新線程監視有沒有變化的redolog);支持並行對數據庫的全備份和增量備份;備份和恢復的效率比邏輯備份更高。
    缺點:做單表恢復時比較複雜;完整的數據文件copy,故備份文件較大;對跨平臺和數據庫的備份恢復支持度不如邏輯備份。(需要安裝)
    示例:https://www.cnblogs.com/linuxk/p/9372990.html

2、如何對Mysql進行增量備份和恢復

  • 邏輯備份+二進制日誌
  • xtrabackup

3、如何對binlog進行備份

  • 利用系統命令直接複製保存(非正在使用的)
  • 使用mysqlbinlog命令在線實時備份
    mysqlbinlog --raw --read-from-remote-server --stop-never --host 備份主機IP --port 3306 -u repl -p 123456 起始二進制日誌文件名
    repl用戶必須要具有replication slave權限

八 Mysql管理與監控

1、MySQL常見監控指標

性能指標:

  • QPS: 數據庫每秒處理的請求數量
  • TPS:數據庫每秒處理的事務數量,一般遠遠小於QPS
  • 併發數:數據庫實例當前並行處理的會話數量,反應當前Mysql處理是否繁忙的指標。每一個處理中的mysql線程都會佔用一個CPU的內核。
  • 連接數:連接到數據庫會話的數量。這個連接數不等於併發數。
  • 緩存命中率:Innodb的緩存命中率。決定了查詢是否可以快速的返回處理的結果給調用的程序。

功能性指標:

  • 可用性:數據庫是否可以正常對外提供服務
  • 阻塞:當前是否有阻塞的會話(一個事務鎖住了其他事務同樣需要的資源)
  • 死鎖:當前事務是否產生了死鎖(兩個不同的事務相互鎖住了對方需要的資源)。
  • 慢查詢:實時慢查詢監控
  • 主從延遲:數據庫主從延遲時間
  • 主從狀態:數據庫主從複製鏈路是否正常

死鎖的危害並沒有阻塞的危害大,因爲mysql會定期的檢查死鎖,一旦發現有死鎖,mysql會自行處理(選擇一個資源佔用較少的進行回滾,從而使得另一個事務繼續執行),但對業務會有一定的影響。

2、如何監控QPS

show global status like 'Com%';	//服務器啓動以來請求的數量
sum(Com_xxxx)		// 就是服務器啓動以來某個操作的數量
mysql已經提供了查詢這些指標的統計功能
show global status like 'Queries';	// 可以每隔多長時間採樣一次,再除時間,就能顯示出目前的QPS值

QPS=(Queries2 - Queries1) / 採樣間隔

例如:
show global status where variable_name in(‘Queries’, ‘uptime’) ;

3、如何監控TPS(每秒處理的事務量)和併發數
show global status where variable_name in(‘com_insert’, ‘com_delete’, ‘com_update’) ;
Tc≈com_insert + com_delete + com_update

TPS≈(Tc2 - Tc1)/ (time2 - time1)

併發數越大服務器的負載就越大,也就越慢。
show global status like ‘Threads_running’;

4、如何監控連接數和Innodb緩存命中率
連接數:
show global status like ‘Threads_connected’;

報警閾值:
Threads_connected / max_connections > 0.8

Innodb緩存命中率:
(Innodb_buffer_pool_read_requests - Innodb_buffer_pool_reads)/ Innodb_buffer_pool_read_requests * 100% > 95%

Innodb_buffer_pool_read_requests代表從緩衝池中讀取的次數
Innodb_buffer_pool_reads表示從物理磁盤讀取的次數

show global status like ‘Innodb_buffer_pool_read%’;

5、如何監控數據庫可用性
週期性的連接數據庫並執行:select @@version;
或者在操作系統中執行:mysqladmin -uxxxx -pxxxx -hxxxx ping; // 返回mysqld is alive

6、如何監控阻塞
5.7版本之前,使用下面的語句監控,查詢阻塞時間大於30秒的SQL:
select b.trx_mysql_thread_id AS ‘被阻塞的線程’
, b.trx_query AS ‘被阻塞SQL’
, c.trx_mysql_thread_id ‘阻塞線程’
, c.trx_query AS ‘阻塞SQL’
, (UNIX_TIMESTAMP()-UNIX_TIMESTAMP(c.trx_started)) AS ‘阻塞時間’
from information_schema.innodb_lock_waits a
JOIN information_schema.innodb_trx b ON a.requesting_trx_id=b.trx_id
JOIN information_schema.innodb_trx c ON a.blocking_trx_id=c.trx_id
WHERE (UNIX_TIMESTAMP()-UNIX_TIMESTAMP(c.trx_started)) > 30

5.7以及之後的版本,監控語句:
SELECT waiting_pid AS ‘被阻塞的線程’,
waiting_query AS ‘被阻塞的SQL’,
blocking_pid AS ‘阻塞線程’,
blocking_query AS ‘阻塞SQL’,
wait_age AS ‘阻塞時間’,
sql_skill_blocking_query AS ‘建議操作’
FROM sys.innodb_lock_waits
WHERE (UNIX_TIMESTAMP() - UNIX_TIMESTAMP(wait_started)) > 30;

sys.innodb_lock_waits其實就是上面5.7版本以前的視圖而已。
建議操作往往是建議殺死某個線程,執行kill 12;即可。

7、如何監控慢查詢

  • 通過慢查詢日誌,週期性的人爲查看
  • 通過information_schema.'PROCESSLIST’表實時監控
    例如:查看查詢時間大於60秒,並且處於sleep狀態的
    select * from information_schema.PROCESSLIST where time > 60 and COMMAND<> ‘sleep’;

如果查出來只有以下一條是很正常的,event_scheduler該進程是Mysql的後臺進程。

8、如何監控主從延遲
在slave上使用:
show slave status \G
看其中參數Seconds_Behind_Master的值

更加準確的方式是使用PT工具:
在master上:週期性的寫入數據
pt-heartbeat --user=xx --password=xx -h master --createtable --database xxx --update --daemonize --interval=1;

在slave上:週期性的讀取上面語句創建表中的數據
pt-heartbeat --user=xx --password=xx -h slave --database crn --monitor --daemonize --log /tmp/slave_lag.log;

9、如何監控主從狀態(鏈路)
在slave上使用:
show slave status \G
看其中參數Slave_IO_Running和Slave_SQL_Running的值,都爲Yes時代表時正常的,否則會在參數Last_Error中看到具體的故障信息。

10、如何監控死鎖
show engine innodb status; // 查看最近一次死鎖
但是通過這條語句查看到的結果太複雜,不容易看懂,所以有其他方法:

  • 使用PT工具
    pt-deadlock-logger u=dab, p=xxx, h=xxxx
    –create-dest-table
    –dest u=dba,p=xxxx,h=xxxx,D=crn,t=deadlock

    上面的語句最後將查詢的結果存儲到了deadlock表中,create-dest-table是自動建表;dest是要存儲到表的信息

  • 將死鎖記錄到錯誤日誌中
    set global innodb_print_all_deadlocks=on;

更好的方式還是使用PT工具。

九 Mysql優化和異常處理思路

1、數據庫負載過大
服務器磁盤IO超負荷
存在大量阻塞線程
存在大量併發慢查詢
其他原因

在這裏插入圖片描述

慢查詢造成磁盤IO爆表情況排查
在這裏插入圖片描述
可能的原因:

  • mysql正在輸出大量的日誌
  • mysql正在進行大批量的寫
  • 慢查詢產生了大量的磁盤臨時表

如果是慢查詢造成的IO爆表:
首先,利用lsof命令查看某個進程打開文件的情況,是否有大量的臨時表創建與寫入
然後,通過show global status like ‘%tmp%’;執行兩次,對created_tmp_disk_tables參數做差,得出是否建立臨時表的數量。
最後,優化慢查詢,減少磁盤臨時表;或者增加tmp_table_size和max_heap_table_size參數的大小,直接建立內存表,而不是臨時表。

2、主從數據庫無延遲情況下的數據不一致(IO_THREAD和SQL_THREAD狀態都爲Yes)
相同的查詢在主從服務器上查詢結果不一致的原因:

  • 對從庫中的數據進行了修改
  • 使用sql_slave_skip_counter或者注入空事務的方式修復錯誤
  • 使用了statement格式的複製(這種格式是分開執行事務的,默認取UUID或者當前時間的列就會出現不一致)

解決思路:

  • slave中設置read_only=on
  • 設置super_read_only=on
  • 使用row格式複製(記錄了master的修改,slave中直接應用)
  • 使用pt_table_sync這個工具修復數據
    pt_table_sync --execute --charset=utf8 --database=數據庫名 --table=表名 --sync-to-master h=從庫的地址, u=dba, p=123456;
    可以使用checksum table 庫名.表名,查看數據表的唯一值,可以對比主從上的表是否相同。

3、主服務器連接不上
在這裏插入圖片描述

  • 主從網絡是否暢通(ping IP, telnet ip port)
  • 是否存在防火牆,過濾了數據庫端口
  • 複製鏈路配置的用戶名和密碼是否正確、權限

4、主鍵衝突問題
在這裏插入圖片描述

  • 跳過故障數據
  • 檢查主從數據一致性
  • OR直接刪除從庫主鍵衝突數據(最好使用這個)

5、數據行不存在
在這裏插入圖片描述

  • 跳過故障數據
  • pt-table-sync工具(最好使用這個)

6、slave宕機引起的relay_log損壞
在這裏插入圖片描述

解決方法:

  1. 找到已經正確同步的日誌點
  2. 使用reset slave刪除relay_log
  3. 在正確同步日誌點後重新同步日誌

7、優化
在這裏插入圖片描述

發佈了55 篇原創文章 · 獲贊 28 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章