業務高峯性能時的緊急處理
-
問題一:短鏈接風暴。mysql
-
數據庫處理得慢一些,鏈接數就會暴漲。max_connections參數,用來控制一個MySQL實例同時存在的鏈接數的上限,超過這個值,系統就會拒絕接下來的鏈接請求,並報錯提示「Too many connections」。對於被拒絕鏈接的請求來講,從業務角度看就是數據庫不可用。sql
-
方法一:先處理掉佔着鏈接卻不工做的線程。數據庫
- max_connections的計算,不是看誰在running,是隻要連着就佔用一個計數位置。對於那些不須要保持的鏈接,咱們能夠經過kill connection主動踢掉。這個行爲跟事先設置wait_timeout的效果是同樣的。設置wait_timeout參數表示的是,一個線程空閒wait_timeout這麼多秒以後,就會被MySQL直接斷開鏈接。
- 注意:應該先斷開那些非提交事物的鏈接,由於若是事物還未提交,斷開會執行回滾。所以,若是是鏈接數過多,你能夠優先斷開事務外空閒過久的鏈接;若是這樣還不夠,再考慮斷開事務內空閒過久的鏈接。
-
方法二:減小鏈接過程的消耗。併發
- 有的業務代碼會在短期內先大量申請數據庫鏈接作備用,若是如今數據庫確認是被鏈接行爲打掛了,那麼一種可能的作法,是讓數據庫跳過權限驗證階段。跳過權限驗證的方法是:重啓數據庫,並使用–skip-grant-tables參數啓動。這樣,整個MySQL會跳過全部的權限驗證階段,包括鏈接過程和語句執行過程在內。(風險極高)
-
-
問題二:慢查詢性能問題函數
-
索引沒有設計好:性能
- Online DDL,對於那種高峯期數據庫已經被這個語句打掛了的狀況,最高效的作法就是直接執行alter table 語句。
- 比較理想的是可以在備庫先執行。假設你如今的服務是一主一備,主庫A、備庫B,這個方案的大體流程是這樣的:
- 在備庫B上執行 set sql_log_bin=off,也就是不寫binlog,而後執行alter table 語句加上索引;
- 執行主備切換;
- 這時候主庫是B,備庫是A。在A上執行 set sql_log_bin=off,而後執行alter table 語句加上索引。
-
sql語句沒寫好:spa
- 檢查sql語句,字符集是否同樣,查詢字段的數據類型和數據庫存儲的數據類型是否同樣,有沒有隱式使用了函數致使沒有走索引。
-
mysql選錯了索引:線程
- 這時候,應急方案就是給這個語句加上force index。
-
mysql是怎麼保證事物不丟的
- binlog的寫入機制:事物執行過程當中,先把日誌寫到binlog cache,事務提交的時候,再把binlog cache寫道binlog文件中。
- 一個事物的binlog是不能被拆開的,所以不管這個事物多大,也要確保一次性寫入,系統給binlog cache分配了一片內存,每一個線程一個,參數binlog_cache_size用於控制單個線程內binlog cache所佔內存的大小,若是超過了,就要暫存到磁盤。
- 事物提交的時候,執行器把binlog cache裏的完整事物寫入到binlog中,並清空binlog cache。
每一個線程有本身的binlog cache,可是共用一份binlog。設計
- 圖中的write,指的就是指把日誌寫入到文件系統的page cache,並無把數據持久化到磁盤,因此速度比較快。
- 圖中的fsync,纔是將數據持久化到磁盤的操做。通常狀況下,咱們認爲fsync才佔磁盤的IOPS。
write 和fsync的時機,是由參數sync_binlog控制的:日誌
-
sync_binlog=0的時候,表示每次提交事務都只write,不fsync;
-
sync_binlog=1的時候,表示每次提交事務都會執行fsync;
-
sync_binlog=N(N>1)的時候,表示每次提交事務都write,但累積N個事務後才fsync。
所以,在出現IO瓶頸的場景里,將sync_binlog設置成一個比較大的值,能夠提高性能。在實際的業務場景中,考慮到丟失日誌量的可控性,通常不建議將這個參數設成0,比較常見的是將其設置爲100~1000中的某個數值。
可是,將sync_binlog設置爲N,對應的風險是:若是主機發生異常重啓,會丟失最近N個事務的binlog日誌。
redo log的寫入機制
-
事務還沒提交的時候,redo log buffer中的部分日誌有沒有可能被持久化到磁盤呢?
-
確實會有,redo log可能存在在的三種狀態。
-
存在redo log buffer中,物理上是在MySQL進程內存中,就是圖中的紅色部分;
-
寫到磁盤(write),可是沒有持久化(fsync),物理上是在文件系統的page cache里面,也就是圖中的黃色部分;
-
持久化到磁盤,對應的是hard disk,也就是圖中的綠色部分。
-
-
日誌寫到redo log buffer是很快的,wirte到page cache也差不多,可是持久化到磁盤的速度就慢多了。爲了控制redo log的寫入策略,InnoDB提供了innodb_flush_log_at_trx_commit參數,它有三種可能取值:
- 設置爲0的時候,表示每次事務提交時都只是把redo log留在redo log buffer中;
- 設置爲1的時候,表示每次事務提交時都將redo log直接持久化到磁盤;
- 設置爲2的時候,表示每次事務提交時都只是把redo log寫到page cache。
- InnoDB有一個後臺線程,每隔1秒,就會把redo log buffer中的日誌,調用write寫到文件系統的page cache,而後調用fsync持久化到磁盤。
- 注意,事務執行中間過程的redo log也是直接寫在redo log buffer中的,這些redo log也會被後臺線程一塊兒持久化到磁盤。也就是說,一個沒有提交的事務的redo log,也是可能已經持久化到磁盤的。
組提交機制
- 日誌邏輯序列號(log sequence number)LSN,LSN是單調遞增的,用來對用redo log的一個個寫入點,每次寫入長度爲length的redo log,LSN的值就會加上length。
- 例子:如圖,三個併發事物(trx1,trx2,trx3)在prepare階段,都寫完redo log buffer,持久化到磁盤的過程,對應的LSN是50,120,160
如圖:
1. trx1是第一個到達的,會被選爲這組的 leader; 2. 等trx1要開始寫盤的時候,這個組里面已經有了三個事務,這時候LSN也變成了160; 3. trx1去寫盤的時候,帶的就是LSN=160,所以等trx1返回時,全部LSN小於等於160的redolog,都已經被持久化到磁盤; 4. 這時候trx2和trx3就能夠直接返回了。
- 因此,一次組提交里面,組員越多,節約磁盤IOPS的效果越好。
兩階段提交回顧
- 寫binlog,先把binlog從binlog cache中寫道磁盤上的binlog文件中
- 調用fsync持久化 MySQL爲了讓組提交的效果更好,把redo log作fsync的時間拖到了步驟1以後。也就是說,上面的圖變成了這樣:
- 這麼一來,binlog也能夠組提交了。在執行圖中第4步把binlog fsync到磁盤時,若是有多個事務的binlog已經寫完了,也是一塊兒持久化的,這樣也能夠減小IOPS的消耗。
- WAL機制是減小磁盤寫,但是每次提交事務都要寫redo log和binlog,這磁盤讀寫次數也沒變少呀?
- redo log 和 binlog都是順序寫,磁盤的順序寫比隨機寫速度要快;
- 組提交機制,能夠大幅度下降磁盤的IOPS消耗。
若是你的MySQL如今出現了性能瓶頸,並且瓶頸在IO上,能夠經過哪些方法來提高性能呢?
- 設置 binlog_group_commit_sync_delay 和 binlog_group_commit_sync_no_delay_count參數,減小binlog的寫盤次數。這個方法是基於「額外的故意等待」來實現的,所以可能會增長語句的響應時間,但沒有丟失數據的風險。
- 將sync_binlog 設置爲大於1的值(比較常見是100~1000)。這樣作的風險是,主機掉電時會丟binlog日誌。