MySQL (InnoDB) 的內部狀態

Percona 老大 Peter Zaitsev 在「MySQL – A Series of Bad Design Decisions」這篇裡提到了他認為 MySQL 設計上的問題,不過裡面也提到了不少有用的指令,平常可以先熟悉一下輸出,等真的有狀況的時候才會想起來可以用這些指令。

首先是最經典的 SHOW ENGINE INNODB STATUS,算是很多文件上面都會提到的指令。可以看 InnoDB 當下的情況,藉以猜測內部現在是怎麼卡住...

另外一個是 SHOW ENGINE INNODB MUTEX,就如同 Peter Zaitsev 所提到的,這個指令想辦法抓出最重要的資訊,但不要像 SHOW ENGINE INNODB STATUS 給了那麼多。

另外當然就是 INFORMATION_SCHEMA,他甚至希望 SHOW ENGINE INNODB 系列的指令應該要被整合進去,這樣才能用 SELECT 相關的指令整理... (因為 ORDER BY 以及蠻多的指令沒辦法在 SHOW ... 上面用)

MySQL 總算要拔掉 mysql_query_cache 了

半官方的 MySQL blog 上宣佈了拔掉 mysql_query_cache 的計畫:「MySQL 8.0: Retiring Support for the Query Cache」。

作者開頭引用了 ProxySQL 的人對 MySQL Query Cache 的說明:

Although MySQL Query Cache was meant to improve performance, it has serious scalability issues and it can easily become a severe bottleneck.

主要問題在於 MySQL Query Cache 在多 CPU 環境下很難 scale,很容易造成一堆 thread 在搶 lock。而且作者也同意 ProxySQL 的說法,將 cache 放到 client 的效能比較好:

We also agree with Rene’s conclusion, that caching provides the greatest benefit when it is moved closer to the client:

可以看到 Query Cache 在複雜的環境下對效能極傷。而之前也提到過類似的事情了:「Percona 對 mysql_query_cache 的測試 (以 Magento 為例)」、「關閉 MySQL 的 Query Cache」。

一般如果要 cache 的話,透過 InnoDB 裡良好的 index 應該還可以撐不少量起來。

關閉 MySQL 的 Query Cache

MySQL 的 Query Cache 是目前已知效能不好的主要因素之一 (global mutex lock 的緣故),在正式環境裡的 best practice 一般都是關閉,之前測過也是一開下去效能就會狂掉...

Percona 的人在討論要怎麼樣才能完全關閉 MySQL 的 Query Cache:「Is Your Query Cache Really Disabled?」,而他們發現只有在 query_cache_typequery_cache_size 都設為 0,而且重開 MySQL 才能完全避免 global mutex lock:

[W]e can see it is not possible to fully disable the query cache on the fly by changing query_cache_type or/and query_cache_size to 0. Based on the code and the tests, if you want to make sure the query cache is fully disabled, change query_cache_size and query_cache_type to 0 and restart MySQL.

應該是要再修正 my.cnf 的 template 了...

Auto Scaling 的 Instance Protection,有點像是 mutex...

前幾天 AWS 放出來的新功能,可以針對 Auto Scaling 裡的機器設定保護 (避免關機):「New – Instance Protection for Auto Scaling」。

看提供的 pseudocode 可以了解想法,ProcessWorkUnit(Work) 是個需要跑比較長時間的 process,中斷掉的話會浪費掉 resource:

while (true)
{
  SetInstanceProtection(False);
  Work = GetNextWorkUnit();
  SetInstanceProtection(True);
  ProcessWorkUnit(Work);
  SetInstanceProtection(False);
}

也就是這些機器還是會被 Auto Scaling 計算在內,但關機不會動這些機器。這段範例有種以前上課學 mutexcritical section 的感覺...

Percona 對 mysql_query_cache 的測試 (以 Magento 為例)

Percona 的人以現在的觀點來看 mysql_query_cache:「The MySQL query cache: Worst enemy or best friend?」。

起因主要也是懷疑 query cache 是 global mutex 在現在的硬體架構 (主要是 CPU 數量成長) 應該是個負面的影響,但不確定影響多少:

The query cache is well known for its contentions: a global mutex has to be acquired for any read or write operation, which means that any access is serialized. This was not an issue 15 years ago, but with today’s multi-core servers, such serialization is the best way to kill performance.

這邊就有點怪了,PK search 應該是個位數 ms 等級才對 (一般 EC 網站的資料量都應該可以 memory fit),不知道他是怎麼測的:

However from a performance point of view, any query cache hit is served in a few tens of microseconds while the fastest access with InnoDB (primary lookup) still requires several hundreds of microseconds. Yes, the query cache is at least an order of magnitude faster than any query that goes to InnoDB.

anyway,他實際測試兩個不同的 configuration,首先是打開 query cache 的:

再來是關閉 query cache 的:

測試的方式在原文有提到,這邊就不抄過來了。測試的結果可以看到關閉 query cache 得到比較好的 thoughput:

Throughput scales well up to somewhere between 10 and 20 threads (for the record the server I was using had 16 cores). But more importantly, even at the higher concurrencies, the overall throughput continued to increase: at 20 concurrent threads, MySQL was able to serve nearly 3x more queries without the query cache.

跟預期的差不多,硬體的改變使得演算法也必須跟著改,不然就會遇到問題...