主備切換的兩種場景
- 主動切換
- 被動切換:主庫出現問題,HA系統發起
如何判斷一個主庫是否有問題?
- select 1判斷
- 查表判斷
- 更新判斷
- 內部統計
select 1判斷
select 1成功返回,只能說明庫的進程還存在,不能說明主庫沒有問題。
-- 在主庫上執行以下命令
set global innodb_thread_concurrency = 2;
innodb_thread_concurrency參數的目的是控制InnoDB并發線程的上限,一旦并發線程數達到此值,InnoDB在收到新請求后,就會進入等待狀態,直到有線程退出。
innodb_thread_concurrency限制的是并發查詢(當前正在執行的語句),如果一條語句在進入鎖等待以后,并發線程數也會減1。
Session C的select 1是可以執行成功,但是select表t會被阻塞,因此用select 1檢測實例是否正常是檢測不出問題的。
查表判斷
為了解決select 1的問題,我們可以在系統庫(MySQL庫)里面創建1個表,比如命名為health_check,里面只放一行數據,如下:
create table health_check (
t_modified timestamp NOT NULL default CURRENT_TIMESTAMP
) engine=InnoDB;
使用上述方法可以檢測到由于并發線程數過多導致的數據庫不可用的情況。
但是假設磁盤空間使用率達100%,由于我們更新需要些日志,因此所有的更新語句都會被阻塞,但是查表還是可以的(正常讀數據)。
更新判斷
update mysql.health_check set t_modified = now();
對于主備庫我們都需要使用上述語句進行檢測,但是如果主備關系為雙M結構,說明兩個節點會同步彼此的binlog,如果使用上述語句就可能出現行沖突,導致主備停止。為了讓主備之間的更新不產生沖突,可以在mysql.health_check放入多行數據,并將兩個節點的server_id放入表中,如下:
create table health_check (
id bigint not null primary key ,
t_modified timestamp NOT NULL default CURRENT_TIMESTAMP
) engine=InnoDB;
/* 檢測命令 */
insert into mysql.health_check(id, t_modified) values (@@server_id, now()) on duplicate key update t_modified=now();
由于主備庫建立關系需要保證server_id不同,因此可以保證主備庫各自檢測命令不會發生沖突。
但是上述語句無法判斷慢(比如磁盤使用率100%)的問題,但是由于上述檢測語句只需要很少的資源,因此有可能在超時前執行成功,無法真正得出系統異常。
內部統計
我們可以根據mysql的performance_schema庫里的一些統計信息,從內部檢測數據庫異常。
比如針對上述的磁盤使用率,在performance_schema庫的file_summary_by_event_name表里會有統計信息,比如:
- event_name如果為wait/io/file/innodb/innodb_log_file,記錄redo log的一些信息
- event_name如果為wait/io/file/sql/binlog,記錄了binlog的一些信息
file_summary_by_event_name表結構如下:
- COUNT_STAR表示所有IO的總次數
- SUM、MIN、AVG、MAX_TIMER_WAIT:單位皮秒,所有IO的耗時求和、最小值、平均值、最大值
- COUNT_READ:讀操作的次數
- SUM_NUMBER_OF_BYTES_READ:總共從日志里讀取了多少個字節
- COUNT_WRITE:寫操作的次數
- SUM_NUMBER_OF_BYTES_WRITE:寫日志的字節數
- COUNT_MISC:其他類型的次數,比如對于redo log,可以認為是fsync的次數
關于內部統計信息的開啟可以通過setup_instruments表控制。