最近討論 Uber 的 MySQL 換 PostgreSQL 後又換回 MySQL 的文章...

先把兩份連結丟出來,一份是 PyPgDay 2013 時由 Uber 的 Evan Klitzke 給的「Migrating Uber from MySQL to PostgreSQL」,原 PDF 連結已經失效 (看起來已經被刪除),但這個網路年代什麼都可以找到備份... 可以在「Migrating Uber from MySQL to PostgreSQL」取得,但這個網站怪怪的,我另外丟了一份到 Google Docs 上

另外一份則是同一個人 Evan Klitzke 在 2016 年發表於公司的官方網站上:「Why Uber Engineering Switched from Postgres to MySQL」。

2013 年描述了從 MySQL 換到 PostgreSQL,2016 年同一個人出來則描述了從 PostgreSQL 換到 MySQL 的理由,有種臉腫腫的感覺。

先抓 2013 年的重點,當時分享的目標是要用 PostGIS

在 2016 年的文章絕口不提 PostGIS,而是提到各種效能問題:花了很長的篇幅講 Non-clustered Index 與 Clustered Index 的設計,以及 Replication 時的頻寬效能差異。

先不管 PostGIS,如果真的是 UPDATE 造成效能問題,那麼不是要朝 sharding 解決嗎,怎麼是換成 MySQL?換到 MySQL 後還是會遇到效能問題啊,你還是要在 application 層上面找出方案啊。

這篇文章看起來更像是內部技術與政治問題掛勾在一起談,因為政治原因而換 MySQL,然後找出技術原因說明換的理由 XDDD

DynamoDB Streams...

去年 (2014) 十一月時 AWS 推出了 DynamoDB Streams,像是 RDBMS 裡 trigger 的東西,不過當時還沒這麼方便,而且也是 preview 階段:「Sneak Preview – DynamoDB Streams」。

Once you enable it for a DynamoDB table, all changes (puts, updates, and deletes) made to the table are tracked on a rolling 24-hour basis.

而這個功能現在總算是開放讓一般人使用了,這次可以配合 AWS Lambda 一起使用,官方用了「DynamoDB Streams + Lambda = Database Triggers」的說明來解釋:「DynamoDB Update – Triggers (Streams + Lambda) + Cross-Region Replication App」。

另外這次也推出了 Cross-Region DynamoDB Replication,其實就是透過組合拳串起來:

This app runs on AWS Elastic Beanstalk and makes use of the EC2 Container Service, all launched via a AWS CloudFormation template.

Amazon S3 的 Cross-Region Replication

AWS 宣佈的新功能,自動 replicate 到其他區域的 Amazon S3 上:「New – Cross-Region Replication for Amazon S3」。

需要打開 Versioning 的功能,然後就可以設定了:

新上傳的 object 才會被 replicate,原先的 object 是不會有改變的。

Percona XtraDB Cluster 5.6 與 GTIDs 的結合

Percona 的 Fernando Laudares 在「How to setup a PXC cluster with GTIDs (and have async slaves replicating from it!)」這篇裡提到了 Percona XtraDB Cluster 5.6 與 GTIDs 的配合方式。

傳統的 replication 的 binlog 的表示方式是 filename + position,這個是大家已經很熟悉的方式。

digraph {
    M1 [label="Master 1"];
    M2 [label="Master 2"];

    S1 [label="Slave 1"];
    S2 [label="Slave 2"];
    S3 [label="Slave 3"];
    S4 [label="Slave 4"];

    { rank=same; M1; M2; };

    { rank=same; S1; S2; S3; S4; };
    S1 -> S2 -> S3-> S4 [style=invis];

    M1 -> M2;
    M2 -> M1;

    M1 -> {S1, S2, S3, S4};
    M2 -> {S1, S2, S3, S4} [color=gray];
}

優點是很簡單 (很好理解,也很容易設定管理),但缺點是 Slave 的 Master 跳動時 (從 Master 1 跳到 Master 2),Slave 可能會漏資料。

原因是出自於 MMM 之類的工具無法知道 Master 1 最後一筆寫入的資料對應到 Master 2 的哪個 binlog 位置。

MySQL 5.6 之後多了新的模式,叫做 GTIDs (Global Transaction IDs),把本來 binlog 的 filename + position 改良一下,變成 source_id + transaction_id 的形式。

source_id 是每台機器固定的值,目前是用 UUID 代表,而 transaction_id 則是遞增的流水號。所以也很好理解:「source_id 這台機器的第 n 個 transaction」。

這樣就可以多出很多偵測機制,降低問題發生的機率。

而 PXC 5.6 在這個領域則是因為已經有了自己的 cluster 機制,所以整個 cluster 會共用一組 UUID。這樣就可以避免混用機制而產生複雜的問題。

所以就變成三台 Master 互相切換 (通常 PXC 都是三台以上的奇數機器):

或是其中兩台互相切換 (第三台只跑 garbd 而沒有實際資料時):

我們家只剩下一組 cluster 是 PXC 5.5 (最大的一組),其他都是 PXC 5.6 了。應該要找人 deploy 這個機制降低 Master 跳機時的人力操作成本了...

MySQL 的 Parallel Replication

Multithreaded Replication to the Rescue」這篇提到了 Replication 的 Parallel Worker 機制。

作者給了平行的數量對 replication lag 的影響:

可以看得出來 Parallel Worker 機制對 Replication Lag 改善頗大,不過作者在 comment 提到中雷了:「MTS breaks in after restart」。

對於還在使用 traditional master-slave 架構的人可以參考看看。

利用 pt-online-schema-change 同步 master 與 slave 的資料

在「Syncing MySQL slave table with pt-online-schema-change」這篇看到 master 與 slave 的資料不同步時,強制性同步的方法:

pt-online-schema-change --alter 'ENGINE=INNODB' D=dbname,t=tblname

由於 pt-online-schema-change 的作法是建一個新的表格,然後把舊表格的資料寫過去,而這些行為會被 replicate 到新機器上,於是就同步了...

這招有趣 XDDD

AWS 提供跨區的 MySQL Read Replica...

Amazon RDS 將提供跨區的 MySQL read replication。看起來是針對 5.6+ 的版本提供這個功能...

有兩篇官方文章,一篇是 CTO 發了一篇「Expanding the Cloud: Enabling Globally Distributed Applications and Diaster Recovery」,另外一篇是官方網誌上的「Cross-Region Read Replicas for Amazon RDS for MySQL」。

用圖表示比較容易懂:

在 US-East 建立 MySQL master,另外在 EU 與 Tokyo 建立 slave replication。不知道中間的 traffic 有沒有過 IPSec 或是 SSL?

Amazon RDS 可以直接產生 Read Replica Replication 了...

以往要在 Amazon RDS 產生 Read Replica Replication 需要複雜的 snapshot 處理,但現在 AWS 直接提供這個功能了,而且可以同時生很多台:「New Read Replica Capabilities for Amazon RDS」。

這有多重要呢?以前因應流量瞬間爆增時的方式是增加 web server,並且利用 cache (可能是 memcached) 降低對後端的 query 數量。但因為引入 cache,平常就得處理 cache invalidate 的問題。

而這個方式平常只要處理讀寫分離就可以了。當量爆增時除了 web server 增加,直接增加後端的 RDS server (Read Replica Replication),甚至可以分層:

以目前的步調來看,之後有可能會推出 Master-Master 的 HA 架構?

Update:照 comment 提到的,Multi-AZ 本身就是 HA 架構了...

Percona 的 Crash-resistant replication

前幾天 Percona 寫了篇文章說明自家專有的 Crash-resistant replication (用在 Percona Server 5.1 與 5.5):「Crash-resistant replication: How to avoid MySQL replication errors」。

這是 async replication 用在 slave server crash 時的保護機制。

當 slave 更新資料後,會更新 relay log 寫下「目前 apply 到哪個位置」(預設值是 relay-log.info),也就可以依照這個資訊計算出 replication lag 的時間。在 mytop 裡看到的 Delay 欄位就是由此算出來的。

但當 MySQL 寫入後,但 relay-log.info 還沒更新時當掉,會造成下次啟動時重複 apply 同一筆資料。

而 Crash-resistant replication 就是把這個資訊寫到 transaction 內,避免這個問題。

也因此這個功能只有 InnoDB 類的 Engine 才有用,MyISAM 仍然是不受 Crash-resistant replication 保護的。

要打開這個功能也很簡單,只要 my.cnf 設起來就好了,設定說明可以參考原文。

在 Percona XtraDB Cluster 裡使用 async replication 時人工 failover 的方式...

在使用 Galera Cluster 時還是可以架設一般的 slave server (Percona XtraDB Cluster 則是 Percona 對 Galera Cluster 的封裝),像是這樣的架構:

其中 node{1,2} 為 cluster,node3 則是傳統的 async replication,來源的 master 為 node1。

當 node1 掛掉時,我們沒辦法自動將 node3 的 master 從 node1 改指到 node2,因為 binlog 的位置不一定正確。

在「Changing an async slave of a PXC cluster to a new Master」則是提供如何人工用最簡單的方式介入。

主要是靠 Galera Cluster 會在 binlog 內寫入 Xid 這個值,這個值可以在 global status 內的 wsrep_last_committed 看到。因為這個值在全 cluster 都是同步的,就可以拿來人工尋找 binlog 位置後手動下 CHANGE MASTER TO,而不用 pt-table-sync 同步修老半天...

而且邏輯被整理出來以後,就有機會寫成程式自動化... 這算是一個不錯的開頭 :p