MySQL 上 Replication 的方案

Percona 的人整理了一篇關於 Replication 的方案 (以及 NDB,不過這邊就先偷偷跳過去...),雖然標題寫的是 High Availability:「The MySQL High Availability Landscape in 2017 (The Elders)」。

先講他給的另外兩個方案,一個是 Shared Storage,另外一個是 NDB。

其中 Shared Storage 其實在儲存空間端還是有單點失效的問題,而 NDB 的特性跟 InnoDB 不同,有很多概念要重新學... 如果就這三個比較,常見的還是第一個提到的 Replication。

其實把 Replication 用熟的話已經可以解決不少問題了 (不論是早期的 MMM,或是 MHA)。而且因為技術已經發展很久了,大家幾乎都很熟特性 (以及 bug XD),網路上可以找到不少資料,甚至 Percona 也都能夠支援 (當你願意付錢的時候 XDDD)。

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 應該還可以撐不少量起來。

InnoDB redo log 大小對效能的影響

在「Benchmark(et)ing with InnoDB redo log size」這邊看到在討論 InnoDB redo log 的大小對效能的影響 (也就是 innodb_log_file_sizeinnodb_log_files_in_group)。

開頭就有先提到重點,在新版 MySQL 裡,幾乎所有的情況比較大的 redo log 有比較好的效能 (平均值):

tl;dr - conclusions specific to my test

  1. A larger redo log improves throughput
  2. A larger redo log helps more with slower storage than with faster storage because page writeback is more of a bottleneck with slower storage and a larger redo log reduces writeback.
  3. A larger redo log can help more when the working set is cached because there are no stalls from storage reads and storage writes are more likely to be a bottleneck.
  4. InnoDB in MySQL 5.7.17 is much faster than 5.6.35 in all cases except IO-bound + fast SSD

可以看出來平均效能的提昇很顯著,不管是增加 redo log 大小還是升級到 5.7:

但作者也遇到了奇怪的效能問題。雖然平均效能提昇得很顯著,但隨著加入資料的增加,效能的 degradation 其實很嚴重,在原來的網頁上可以看到這些資訊。

The results above show average throughput and that hides a lot of interesting behavior. We expect throughput over time to not suffer from variance -- for both InnoDB and for MyRocks. For many of the results below there is a lot of variance (jitter).

所以也許現階段先加大就好 (至少寫入的效能會提昇),不需要把這個特性當作升級 MySQL 的理由。

Oracle 官方的 InnoDB Cluster 出 GA 了...

Oracle 推出的 InnoDB Cluster 進入 GA 了,不過先觀望看看就好:「MySQL InnoDB Cluster GA is Available Now!」。

The GA release of InnoDB Cluster builds upon the great work that the MySQL Development Team has done on Group Replication, filling out the rest of the stack for setup, management, orchestration, and client routing.

算是 Galara Cluster 的競爭對手 (被 PerconaMariaDB 採用),產品成熟度還得再看如何...

在 MySQL InnoDB 下單表復原的方式

在「How to Restore a Single InnoDB Table from a Full Backup After Accidentally Dropping It」這篇提到了 MySQL InnoDB 單表復原的事情。

文章裡先提到了 2012 年的文章「How to recover a single InnoDB table from a Full Backup」,講更特定的情況。

這邊兩篇的大前提都是使用 innodb_file_per_table

2012 的文章裡講的是誤刪 (DELETE) 後的處理,如果是 DROP TABLETRUNCATE 或是因為 ALTER TABLE 而造成資料遺失的話,就不能用這篇文章的方式處理:

You must not drop, truncate or alter the schema of the table after the backup has been taken.

如果很幸運是因為 DELETE 而遺失的話,在文章裡有提到 innobackupex 這個工具,透過 innobackupex 備份的資料才有辦法依照文章裡的方法做到單表復原。

先 discard tablespace:

mysql> set FOREIGN_KEY_CHECKS=0;
mysql> ALTER TABLE salaries DISCARD TABLESPACE;

然後把檔案 cp 進去:

cp /tmp/2012-01-22_14-13-20/employees/salaries.ibd /var/lib/mysql/data/employees/

最後再 import tablespace 回去:

mysql> set FOREIGN_KEY_CHECKS=0;
mysql> ALTER TABLE salaries IMPORT TABLESPACE;
mysql> set FOREIGN_KEY_CHECKS=1;

而 2017 講的誤刪則是補充了 2012 文章裡另外的情況,用途也比較廣,但動作比較複雜。

本來的四個步驟:

  • Prepare the backup
  • Discard the tablespace of the original table
  • Copy .ibd from the backup to the original table path
  • Import the tablespace

變成了七個步驟:

  • Prepare the backup
  • Extract the original table structure from the backup (i.e., extract the create statement from the backup .frm file)
  • Create a new empty table
  • Apply some locks
  • Discard the newly created tablespace
  • Copy back .ibd from the backup
  • Import the tablespace

粗體的部份就是不一樣的部份,多出來的步驟產生出同樣的環境配合 .ibd,然後讓 .ibd 檔匯進 MySQL。

實際練過一次會比較有感覺 (應該可以在 Docker 裡測試),等不幸遇到的時候手腳比較不會慌亂...

Pinterest 對 InnoDB 壓縮的改善

三個月前 Pinterest 提到對 InnoDB 壓縮的改善,講到透過字典的改善方式:「Pinterest 在 InnoDB Compression 的努力」。

而在「Evolving MySQL Compression - Part 2」這邊繼續說明要怎麼生出對 Pinterest 比較有效的字典內容,作者把計算的工具放到 GitHub 上讓其他人可以用 (用 Python 寫的):「pinterest/mysql_utils/zdict_gen/」。

可以看出來又增加不少壓縮率,這算是針對資料庫壓縮從 A 到 A+ 的行為吧...

GitHub 重新定位 Redis 的功能...

GitHub Engineering 說明了他們為什麼改變 Redis 的使用情境:「Moving persistent data out of Redis」。

GitHub 裡面,Redis 有兩種不同的情境,一種叫做 transient Redis,只用做 cache:

We used it as an LRU cache to conveniently store the results of expensive computations over data originally persisted in Git repositories or MySQL. We call this transient Redis.

另外一種則是打開 persistence 功能,叫做 persistent Redis:

We also enabled persistence, which gave us durability guarantees over data that was not stored anywhere else. We used it to store a wide range of values: from sparse data with high read/write ratios, like configuration settings, counters, or quality metrics, to very dynamic information powering core features like spam analysis. We call this persistent Redis.

這邊講的是 persistent Redis 被換成用 MySQL (InnoDB) 儲存:

Recently we made the decision to disable persistence in Redis and stop using it as a source of truth for our data. The main motivations behind this choice were to:

  • Reduce the operational cost of our persistence infrastructure by removing some of its complexity.
  • Take advantage of our expertise operating MySQL.
  • Gain some extra performance, by eliminating the I/O latency during the process of writing big changes on the server state to disk.

For the majority of callsites, we replaced persistent Redis with GitHub::KV, a MySQL key/value store of our own built atop InnoDB, with features like key expiration. We were able to use GitHub::KV almost identically as we used Redis: from trending repositories and users for the explore page, to rate limiting to spammy user detection.

後面講了不少轉換的過程 (還包含了某些功能的改寫),但沒有講的太清楚為什麼不繼續使用 Redis。

目前只能就提到的三點問題來看,persistent 的 i/o 成本可能太高?而且難以再壓榨效能出來?而相反的,InnoDB 已經花了很多力氣在上面,直接拿來用反而可以解決問題?

不過看得出來這個轉換還是花了不少力氣,看得出來有些 application 使用 Redis 的模式不能直接搬到 InnoDB 上,花了時間改寫...

InnoDB 的 buffer pool preload 功能

Percona 的人討論了 InnoDB 提供的 buffer pool preload 功能:「Using the InnoDB Buffer Pool Pre-Load Feature in MySQL 5.7」。

就如同他所講的,因為硬體設備的進步 (主要是 SSD 的興起),而導致 preload 的需求已經沒以前重要了:

Frankly, time has reduced the need for this feature. Five years ago, we would typically store databases on spinning disks. These disks often took quite a long time to warm up with normal database workloads, which could lead to many hours of poor performance after a restart. With the rise of SSDs, warm up happens faster and reduces the penalty from not having data in the buffer pool.

由於 SSD 的 random read 很快,反而可以直接推上線讓他邊跑服務邊 warm up。不過相對的,傳統硬碟的 InnoDB database 還是可以規劃需求,畢竟 random read 還是痛點...

MyRocks 與 InnoDB 對於不同硬碟效能的差異

在「MyRocks: use less IO on writes to have more IO for reads」這邊有提到當使用 Disk Array、Slow SSD 與 Fast SSD 時效能 MyRocks 與 InnoDB 的效能差異。

可以看到當 I/O 層能提供的 IOPS capacity 愈高,MyRocks 與 InnoDB 之間的差異就愈低... 換句話說,RocksDB 對 IOPS 比較有效率的應用,這點在「Why is MyRocks more write-efficient than InnoDB?」這邊也可以看出一些說明 (不過這篇的 InnoDB 完全沒用 COMPRESSED)。

算是推銷... 不過可以持續關注看看 :o

InnoDB 的 Isolation Level 以及 Performance Schema 對效能的影響

雖然 Mark Callaghan 現在的主力都在 MyRocks 上,但他還是對 InnoDB 上的效能頗關注 (畢竟是個成熟而且競爭的產品)。而這篇「Sysbench, InnoDB, transaction isolation and the performance schema」講到 MySQL 5.6.26 裡的 InnoDB,了解 isolation level 與 performance schema 對效能的差異。結果可以在這邊翻到。

關掉 performance schema 會讓效能變好是預期的,不過看起來比預期小很多。另外某些情況下 RR (REPEATABLE-READ) 的效能會比 RC (READ-COMMITTED) 好倒是頗意外,這邊也有給出原因:

Using repeatable-read boosts performance because it reduces the mutex contention from getting a consistent read snapshot as that is done once per transaction rather than once per statement.

不過看了看數據,純粹讀取的部份 RC 會在某些地方快一些,不過整體來說在 MySQL 5.6.26 上的 RR 與 RC 差異真的不算太明顯了...