天天看點

RDS MySQL Adaptive Hash Index (AHI)最佳實踐背景AHI的關鍵節點适合的場景不适合的場景關閉AHI總結參考

背景

很多客戶在使用MySQL時大部分隻要文法執行沒問題,一般來講是不太會關注更多細節的。像MySQL的AHI就是其中一個細節。記憶體的延時是120ns,通路記憶體裡的資料是比較快的。InnoDB監視對每個索引的使用情況,如果它注意到某些索引頁經常被通路,并可以從建立AHI中受益,那它會自動為該索引在Buffer Pool裡建構hash table。基于InnoDB觀察到的搜尋模式,它使用索引鍵的字首來建構AHI。鍵的字首可以是任何長度,而且可能隻有B樹中的一些值出現在AHI中。

是否使用AHI可以通過innodb_adaptive_hash_index控制。盡管InnoDB可以監控索引的通路,但直到現在也沒有對AHI自己的穩定性監控,以至于在生産上遇到某些不适合的場景,需要人為判斷要不要禁用AHI。從資料結構上來說,AHI并不适用于所有通路場景,本篇文章就來聊聊它的使用場景。

AHI的關鍵節點

  • MySQL從5.5版本AHI誕生

但隻有一個hash table,隻有一把鎖,有時保護對AHI的讀/寫鎖可能會在高負載(如多個并發連接配接)下成為瓶頸。

通過show engine innodb status看到的資訊是:

-------------------------------------
INSERT BUFFER AND ADAPTIVE HASH INDEX
-------------------------------------
Ibuf: size 1, free list len 0, seg size 2, 0 merges
merged operations:
 insert 0, delete mark 0, delete 0
discarded operations:
 insert 0, delete mark 0, delete 0
Hash table size 50999503, node heap has 1 buffer(s)
300220.95 hash searches/s, 364993.48 non-hash searches/s      
  • MySQL5.7裡增加了innodb_adaptive_hash_index_parts

為了解決上述瓶頸問題,從5.7開始(RDS MySQL從5.6支援)對AHI特征進行了分區,分區由innodb_adaptive_hash_index_parts變量控制。MySQL通過取模将AHI鎖打散到多個hash table上,也就意味着打散後的hash table越多,AHI鎖就打得更散,鎖的粒度就更細,并發查詢時建構AHI的性能就更好。

-------------------------------------
INSERT BUFFER AND ADAPTIVE HASH INDEX
-------------------------------------
Ibuf: size 1, free list len 0, seg size 2, 19164 merges
merged operations:
 insert 135, delete mark 19087, delete 33
discarded operations:
 insert 0, delete mark 0, delete 0
Hash table size 6375037, node heap has 1432 buffer(s)
Hash table size 6375037, node heap has 2884 buffer(s)
Hash table size 6375037, node heap has 1 buffer(s)
Hash table size 6375037, node heap has 1 buffer(s)
Hash table size 6375037, node heap has 1443 buffer(s)
Hash table size 6375037, node heap has 1440 buffer(s)
Hash table size 6375037, node heap has 1 buffer(s)
Hash table size 6375037, node heap has 18606 buffer(s)
1085.85 hash searches/s, 0.24 non-hash searches/s      

從上面的資訊可以看到如果node heap has * buffer(s)不均衡的話,說明AHI有資料傾斜。hash searches/s 命中hash索引的次數,non-hash searches未命中hash索引的次數。 

适合的場景

  • 隻支援=和in

不适合的場景

AHI的工作流程參考MySQL核心月報的“

AHI介紹

”。在下面的通路不能使用AHI:

  • drop table、truncate table、alter table 、drop index分區等
  • like、regexp、<=>等
  • 任何範圍查詢
  • 有spatial索引
  • 排序

在DDL時打開AHI容易引起資料庫卡頓的原因如下:

  • 在删除表時,需要先通過掃描LRU連結清單找到該表在AHI使用的資料頁,将這些資料從AHI中删除。如果為MySQL執行個體配置較多的實體記憶體,掃描LRU連結清單可能會導緻資料庫性能異常甚至資料庫Crash。
  • 删除AHI的操作正在執行,而InnoDB資料字典緩存dict_sys被獨占鎖定,進而影響正常業務擷取MDL鎖,阻塞正常業務。

關閉AHI

在實際的生産環境場景比較複雜,又很難事先預測AHI是否适合實際生産需要,對于不能從AHI受益的場景,通過SHOW ENGINE INNODB STATUS中SEMAPHORES可以部分監控AHI的使用情況,當看到許多線程在等待btr0sea.c中建立的RW-latch,可以考慮關閉AHI。

鑒于阿裡雲使用者回報的SQL執行慢或卡頓問題有很多跟打開AHI有關,是以阿裡雲RDS MySQL 5.6 & 5.7執行個體從2020-12-02 20:00之後 / 8.0版本從2021-05-22 17:05之後的新購執行個體預設關閉AHI。對于舊有版本還需要使用者自行關閉。

具體操作可以參考下圖:

RDS MySQL Adaptive Hash Index (AHI)最佳實踐背景AHI的關鍵節點适合的場景不适合的場景關閉AHI總結參考

總結

雖然在MySQL官方版本中每個版本都是把AHI預設打開,但根據實際生産中的表現來看卻差強人意,InnoDB AHI隻能在特定的、幾乎是隻讀的場景中才能提高性能;而對于諸如:drop table、truncate table、alter table或drop index等場景表現不佳,甚至導緻MySQL hung或極端場景下的資料損壞。此外,AHI會消耗Buffer Pool的空間,這可能會影響性能。當有上述語句執行時可以在執行之前把AHI關掉,執行完後再打開。但這一系列操作比較麻煩,稍有疏忽可能會影響業務,考慮打開AHI弊大于利,最好禁用AHI。

參考

https://bugs.mysql.com/bug.php?id=100512 https://bugs.mysql.com/bug.php?id=101667 https://bugs.mysql.com/bug.php?id=62018 https://dev.mysql.com/doc/refman/5.6/en/innodb-parameters.html#sysvar_innodb_adaptive_hash_index https://jira.mariadb.org/browse/MDEV-20487