[root@10-10-66-229 binlog]# mysqlbinlog -vv mysql-bin.000175|grep -E 'insert sbtest|insert into sbtest|last_committed|update xx_heartbeat|GTID_NEXT' > a.sql [root@10-10-66-229 binlog]# cat a.sql ...... #171011 15:01:42 server id 3306103 end_log_pos 29975 CRC32 0x85a80516 GTID last_committed=76 sequence_number=77 SET @@SESSION.GTID_NEXT= '6d362bfe-ae21-11e7-a22f-fabb9a69be00:90292'/*!*/; # update xx_heartbeat set hb_time=now() where server_id=@@server_id #171011 15:01:43 server id 3306103 end_log_pos 30366 CRC32 0x14c9d915 GTID last_committed=77 sequence_number=78 SET @@SESSION.GTID_NEXT= '6d362bfe-ae21-11e7-a22f-fabb9a69be00:90293'/*!*/; # update xx_heartbeat set hb_time=now() where server_id=@@server_id # 以下就是我們要找的關鍵信息,留意記錄group 信息的event的時間,從這里可以看到insert...select語句發生的時間順序按照表名排序/ # 依次sbtest1、sbtest3、sbtest2、sbtest4,xx_heartbeat表(與在客戶端敲下SQL的時間順序相同),從信息"last_committed=78"我們可以知道這些SQL都被放進了/ # 同一個隊列里進行binlog提交,從信息"sequence_number=79"我們可以得知,操作表sbtest4的線程在binlog提交隊列中的順序最靠前,也就是說它是leader,其他的為follower #171011 14:39:56 server id 3306103 end_log_pos 30757 CRC32 0xb2c44222 GTID last_committed=78 sequence_number=79 SET @@SESSION.GTID_NEXT= '6d362bfe-ae21-11e7-a22f-fabb9a69be00:90294'/*!*/; # insert sbtest4(k,c,pad) select k,c,pad from sbtest4 # 業務SQL #171011 14:39:55 server id 3306103 end_log_pos 1429482395 CRC32 0x00c7685d GTID last_committed=78 sequence_number=80 SET @@SESSION.GTID_NEXT= '6d362bfe-ae21-11e7-a22f-fabb9a69be00:90295'/*!*/; # insert sbtest3(k,c,pad) select k,c,pad from sbtest3 # 業務SQL #171011 14:39:55 server id 3306103 end_log_pos 2858934033 CRC32 0xb0e9f488 GTID last_committed=78 sequence_number=81 SET @@SESSION.GTID_NEXT= '6d362bfe-ae21-11e7-a22f-fabb9a69be00:90296'/*!*/; # insert sbtest2(k,c,pad) select k,c,pad from sbtest2 # 業務SQL #171011 14:39:54 server id 3306103 end_log_pos 4288385671 CRC32 0x52cf3dfa GTID last_committed=78 sequence_number=82 SET @@SESSION.GTID_NEXT= '6d362bfe-ae21-11e7-a22f-fabb9a69be00:90297'/*!*/; # insert sbtest1(k,c,pad) select k,c,pad from sbtest1 # 業務SQL #171011 16:21:45 server id 3306103 end_log_pos 1422870013 CRC32 0xd3caff89 GTID last_committed=78 sequence_number=83 SET @@SESSION.GTID_NEXT= '6d362bfe-ae21-11e7-a22f-fabb9a69be00:90298'/*!*/; # 下面一句SQL即為被阻塞的心跳SQL,可以看到排在了前面幾個業務SQL的后面,而前面幾個業務SQL產生了大量的binlog數據,這些數據寫到binlog文件中消耗了大量的時間/ # 而因為這句心跳SQL與前面幾個業務SQL在同一個group中,必須等待前面幾個業務SQL的binlog數據寫完之后才能寫binlog,所以,從這里就可以知道,/ # 心跳SQL就是因為在提交binlog階段被業務SQL阻塞了,所以最終導致心跳SQL的事務無法提交 # update xx_heartbeat set hb_time=now() where server_id=@@server_id SET @@SESSION.GTID_NEXT= 'AUTOMATIC' /* added by mysqlbinlog */ /*!*/ PS:到這里,我們已經知道了心跳SQL被阻塞的原因,但是在2.9步驟中,session視圖輸出行的last_wait列顯示的事件代表什么含義呢?感興趣的同學可以根據2.9步驟中信息行的source列值翻看源碼 3、解決方法 關于碰到類似的因為寫binlog時互斥的原因導致毫不相干的表語句相互阻塞的問題的解決方法,需要自行根據業務需求進行分析,這里由于阻塞的是心跳SQL,而HA高可用程序依賴于心跳SQL的檢測結果,對這個心跳SQL具有響應時間要求,必須按時返回結果,對于我們演示的這個場景而言,心跳SQL的作用就是檢測MySQL實例是否存活、是否可寫。so,對于心跳SQL的DML,記錄binlog不是必須的,所以我們臨時的解決辦法就是:動態關閉心跳語句記錄BINLOG的功能,就不會因為寫binlog的原因被阻塞了,如下: 點擊(此處)折疊或打開
set sql_log_bin=0;update xx_heartbeat set hb_time=now() where server_id=@@server_id 4、總結 對于大事務的DML操作,從數據庫的兩大關鍵性能指標(并發數和響應時間)上考慮,強烈建議拆分數據量(例如使用limit按id進行拆分或者程序拆分),雖然我們的開發規范上一再強調,但對于某些人來講,他就認為慢點無所謂嘛,所以,在HA高可用的心跳檢測場景這里,就掉坑里了。