目錄
- select1判斷
- 查表判斷
- 更新判斷
- 外部檢測弊端
- 內部統計
一主一備的雙M架構里,主備切換只需要把客戶端流量切換到備庫。
在一主多從的架構里,主備切換要把客戶端流量切換到備庫,也需要把從庫接到新主庫上。
切換有兩種場景:1、主動切換 2、被動切換。
被動切換是由于主庫出問題了,下面是幾種判斷主庫出問題的方法:
select1判斷
select 1 成功返回,說明這個庫的進程孩子啊,但是不能說明主庫沒問題。
如果在執行語句超過了設置的innodb_thread_concurrency
,此時select 1語句是成功的,但是CPU不能滿足線程查詢要求了,新的查詢要求進來只會阻塞。
查表判斷
在系統庫(mysql庫)里創建一個表,命名為health_check,里面只放一行數據,然后定期執行語句:
select * from mysql.headlth_check;
使用這個方法,可以檢測出由于并發線程過多導致的數據庫不可用的情況。
但是這個方法也會有一個問題:空間滿了,失效
更新事務要寫binlog,一旦binlog所在的磁盤空間占用率達到100%,那么所有的更新語句和事務提交commit語句就會堵住。但是系統此時是可以正常讀數據的。
更新判斷
放一個timestamp字段,用來表示最后一次執行檢測的時間:
update mysql.health_check set t_modified = now();
這種節點可用性檢測應該包含主庫和備庫。
備庫檢測也要寫binlog, 一般只能主庫寫,備庫不能寫。這里是為了檢測備庫,所以才能寫,但是binlog是雙M結構,所以會互相同步這一個檢測sql,那么有可能會造成主從數據不一致(t_modified內容不同)
如果主庫A和備庫B都用相同的更新命令,就可能出現行沖突,從而導致主備同步停止。
我們可以在表上存入多行數據,用A,B的server_id做主鍵:
create table 'health_check' ('id' int(11) not null,'t_modified' timestamp not null default current_timestamp,PRIMARY KEY ('id')
) engine = InnoDB;
檢測命令如下:
insert into mysql.health_check(id,t_modified) values(@@server_id, now()) on duplicate key update t_modified=now();
MySQL規定了主庫和備庫的server_id必須不同,就可以保證主、備庫各自的檢測命令不會發生沖突
這種方法仍然存在問題:判定慢
所有的檢測邏輯都需要一個超時時間N。即執行一條update語句,超過N秒后還不返回就認為系統不可用。
如果一個日志盤的IO利用率已經是100%的場景,此時系統響應非常慢,已經需要做主備切換了。
我們檢測使用的update命令由于需要的資源比較少,很可能在拿到IO資源的時候就可以提交成功,并且在超時時間N秒未到達之前就返回給檢測系統。所以update命令沒有超時,然后得到系統正常的錯誤結論。
外部檢測弊端
上面的三種方法都是基于外部檢測的。外部檢測天然有個問題,就是隨機性。
外部檢測都需要定時輪詢,所以系統可能已經出現問題了,但是卻要等到下一個檢測語句執行的時候才能發現問題。運氣不好,第一次輪詢還不能發現。
內部統計
MySQL5.6版本后提供了performance_schema
庫,在file_summary_by_event_name
表里統計每次IO請求的時間。
該行數據統計的是redo log的寫入時間。
COUNT_STAR是所有IO總次數。
前綴SUM、MIN、AVG、MAX,指統計項的總和、最小值、平均值、最大值。
SUM_NUMBER_OF_BYTES_READ 統計總共從redo log里讀了多少字節
需要注意的是,每進行一次統計,是由性能損耗的,所以建議只打開自己需要的項進行統計。
如打開 redo log 的時間監控:
mysql> update setup_instruments set ENABLED='YES', Timed='YES' where name like '%wait/io/file/innodb/innodb_log_file%';
然后通過MAX_TIMER值來判斷數據庫是否出現問題。可以設定閾值,單次IO請求時間超過200ms屬于異常,然后使用類似于下面的語句檢測:
mysql> select event_name,MAX_TIMER_WAIT FROM performance_schema.file_summary_by_event_name where event_name in ('wait/io/file/innodb/innodb_log_file','wait/io/file/sql/binlog') and MAX_TIMER_WAIT>200*1000000000;
發生異常后,取得需要數據后再:
mysql> truncate table performance_schema.file_summary_by_event_name;
把之前的統計信息清空。