MariaDB 的 S3 Engine 效能測試

PerconaMariaDB 在 10.5 (目前的最新穩定版) 裡出的 S3 Engine 給出了簡單的測試報告:「MariaDB S3 Engine: Implementation and Benchmarking」。

這個 engine 顧名思義就是把資料丟到 Amazon S3 上,目前是 alpha 版本,預設是不會載入的,需要開 alpha flag 才能用:

The S3 engine is READ_ONLY so you can’t perform any write operations ( INSERT/UPDATE/DELETE ), but you can change the table structure.

另外這是從 Aria 改出來的 read-only engine,而 Aria 是從 MyISAM 改出來的:

The S3 storage engine is based on the Aria code and the main feature is that you can directly move your table from a local device to S3 using ALTER.

測出來發現在 read-only 的情境下,COUNT(*) 超快,看起來就是跟 MyISAM 體系有關,直接撈 MyISAM 內的資料,所以本地要 18 秒,但放到 S3 反而秒殺 XDDD

整體看起來還不錯?算是一種 Data warehouse 的方案,主要是要用到 row-based format 儲存的優點,遇到一些冷資料可以這樣玩。

從「Using the S3 Storage Engine」這邊的設定方式看到 s3_host_name,看起來有機會接其他家的 S3 API,或是本地的 Storage。

話說 Aria 這個引擎當初最主要的重點就在 crash-safe,在有了 crash-safe 之後,DRBD 這種 block-level replication 機制就可以硬幹上去,後來主力就在擴充其他型態了,像是 GIS 與 virtual column 的功能,不過這些功能本家在 InnoDB 上好像也都陸陸續續跟上來了,單純的 Aria engine 好像還好...

PostgreSQL 的 SERIALIZABLE 的 bug

這是 Jespen 第一次測試 PostgreSQL,就順利找出可重製的 bug 了:「PostgreSQL 12.3」。

第一個 bug 是 REPEATABLE READ 下的問題,不過因為 SQL-92 定義不夠嚴謹的關係,其實算不算是 bug 有討論的空間,這點作者 Kyle Kingsbury 在文章裡也有提出來:

Whether PostgreSQL’s repeatable-read behavior is correct therefore depends on one’s interpretation of the standard. It is surprising that a database based on snapshot isolation would reject the strict interpretation chosen by the seminal paper on SI, but on reflection, the behavior is defensible.

另外一個就比較沒問題了,是 SERIALIZABLE 下的 bug,在 SQL-92 下對 SERIALIZABLE 的定義是這樣:

The execution of concurrent SQL-transactions at isolation level SERIALIZABLE is guaranteed to be serializable. A serializable execution is defined to be an execution of the operations of concurrently executing SQL-transactions that produces the same effect as some serial execution of those same SQL-transactions. A serial execution is one in which each SQL-transaction executes to completion before the next SQL-transaction begins.

也就是說,在 SERIALIZABLE 下一堆 transaction 的執行結果,你至少可以找到一組排序,使得這些 transaction 的結果是等價的。

而 Jespen 順利找出了一組 transaction (兩個 transaction),在 SERIALIZABLE 下都成功 (但不應該成功):

對於這兩個 transaction,不論是上面這條先執行,還是下面這條先執行,都不存在等價的結果,所以不符合 SERIALIZABLE 的要求。

另外也找到一個包括三個 transaction 的情況:

把 transaction 依照執行的結果把 dependency 拉出來,就可以看出來裡面產生了 loop,代表不可能在 SERIALIZABLE 下三個都成功。

在 Jespen 找到這些 bug 後,PostgreSQL 方面也找到軟體內產生 bug 的部份,並且修正了:「Avoid update conflict out serialization anomalies.」,看起來是在 PostgreSQL 引入 Serializable Snapshot Isolation (SSI) 的時候就有這個 bug,所以 9.1 以後的版本都有這個問題...

這次順利打下來,測得很漂亮啊... 翻了一下 Jespen 上的記錄,發現好像還沒測過 MySQL,應該會是後續的目標?

在 Bash 的迴圈裡面跑 FFmpeg

Bash 的迴圈裡面跑 FFmpeg 有時候會遇到奇怪的靈異現象,發現是這個問題:「execute ffmpeg command in a loop」。

原因是當你用 while + read 產生迴圈時會有對 stdin 的操作行為,而 FFmpeg 預設也會去讀 stdin (WTF),於是兩邊就打架了。

解法是用 -nostdin 叫 FFmpeg 不要手賤去讀 stdin,這樣就可以解決這個問題。

Amazon Aurora MySQL 5.7 也可以上 Global Database 了

AWSAmazon Aurora MySQL 5.7 版本推出了 Amazon Aurora Global Database:「Aurora Global Database is Now Supported on Amazon Aurora MySQL 5.7」。

看起來 MySQL 系的 Global Database 就是跨區的 master-slave 架構 (所以標榜降低了 read latency,但沒有提到 write latency):

An Amazon Aurora Global Database is a single database that spans multiple AWS regions, enabling low latency global reads and disaster recovery from region-wide outages.

另外可以看到是 1 秒,所以應該是 async replication:

Aurora Global Database replicates writes in the primary region with typical latency of <1 second to secondary regions, for low latency global reads.

然後可以跨區切換:

In disaster recovery situations, you can promote the secondary region to take full read-write responsibilities in under a minute.

看了一下好像不用多付服務費用,就是各區自己的費用,加上傳輸的費用而已,看起來是個還不錯的服務?

在 MySQL 上遇到 Replication Lag 的解法

看到 Percona 的 blog 上寫了一篇 MySQL 遇到 replication lag 時要怎麼解決:「MySQL High Availability: Stale Reads and How to Fix Them」,另外在留言也有人提到 Booking.com 的解法:「How Booking.com avoids and deals with replication lag」。

在業務成長到單台 MySQL server 不夠用的情況下,最簡單的擴充方式是架設 slave server,然後把應用程式裡讀取的部份導到 slave 上 (也就是 R/W split),但因為 MySQL 的 replication 是非同步的,所以有可能會發生在 master 寫入資料後 slave 還讀不到剛剛寫的資料,也就是 replication lag。

這就大概有幾種作法,一種是當發現 lag 時就回 master 讀,但通常這都會造成 master 過載... 所以另外一種改善的作法是發現 lag 時就換其他 slave 看看,但這個方法就不保證讀的到東西,因為有可能所有的 slave 都 lag。

以前遇到的時候是拆情境,預設還是 R/W split,但敏感性的資料處理以及金流相關的資料就全部都走 master。

不過文章裡的解法更一般性,在寫入時多寫一份資料,然後在 slave 等這組資料出現。唯一的缺點就是要 GC 把多寫的資料清掉...

同樣的想法,其實可以讓 MySQL 在 commit 時直接提供給 binlog 或 GTID 的資訊,然後在 slave 等待這組 binlog 或 GTID 被執行。

看起來算是很不錯的解法,不知道各家 framework 對這些方式的支援度如何...

Cloudflare 的 Workers KV

Cloudflare 推出了 Workers KV 服務:「Building With Workers KV, a Fast Distributed Key-Value Store」。

是個 key-value 結構服務 (全球性,eventually consistent,約 10 秒的同步時間),key 的限制是 2KB,value 是 64KB,一個 namespace 最多 10 億筆資料。

讀取可以到 100k+ read/s,但寫入是 1 write/s/key,可以看出來主要是為了讀取資料而設計的。

現有的 worker ($5/month) 會送一些量,包括 1GB 的空間與一千萬次的讀取:

Your $5 monthly Workers compute minimum includes 1 GB of KV storage and up to 10 million KV reads. If you use less than the 10 million included Worker requests now, you can use KV without paying a single cent more.

超過的部份另外再收:

Beyond the minimums, Workers KV is billed at $0.50 per GB-month of additional storage and $0.50 per million additional KV reads.

這樣好像整個 blog 的基本功能都可以直接在上面跑了... 而搜尋靠外部服務,圖片與影音也可以靠外部空間協助?

Amazon S3 提供更高的存取量...

AWS 宣佈提高了 Amazon S3 的效能:「Amazon S3 Announces Increased Request Rate Performance」。

每個 S3 prefix 都可以到 5500 RPS read 與 3500 RPS write:

Amazon S3 now provides increased performance to support up to 3,500 requests per second to add data and 5,500 requests per second to retrieve data, which can save significant processing time for no additional charge. Each S3 prefix can support these request rates, making it simple to increase performance exponentially.

舊的資料可以看「Request Rate and Performance Considerations」這邊,裡面沒有明講速度,但有提到如果超過 800 RPS read 與 300 RPS write 的門檻,建議開 case:

However, if you expect a rapid increase in the request rate for a bucket to more than 300 PUT/LIST/DELETE requests per second or more than 800 GET requests per second, we recommend that you open a support case to prepare for the workload and avoid any temporary limits on your request rate.

不過如果有量的話,還是建議照著原來的 prefix 建議,打散處理會比較好,通常在前面的 CDN 通常可以跑簡單的 url rewrite 處理掉 (像是 CloudFront 自家或是 Cloudflare),像是把使用 unix timestamp (ms) 的 https://www.example.com/1531843366123.jpg 變成 https://www.example.com/6123/1531843366123.jpg,這樣可以讓 Amazon S3 的後端依照 prefix 打散 loading,避免當站愈來愈大的時候很難處理。

在 Amazon Aurora 利用 ProxySQL 的讀寫分離提昇效能

Percona 的「Leveraging ProxySQL with AWS Aurora to Improve Performance, Or How ProxySQL Out-performs Native Aurora Cluster Endpoints」這篇有夠長的,其實就是發現 AWSAmazon Aurora 只使用 Cluster Endpoint 無法壓榨出所有效能,只有當你讀寫分離拆開 Cluster endpoint 與 Reader endpoint 時才能提昇效能。主要是在推銷 ProxySQL 啦,其他的軟體應該也能達到類似的效果...

然後這張怪怪的,應該是 copy & paste 上去的關係?

因為事後再疊 ProxySQL 進去不會太困難,一般還是建議先直接用服務本身提供的 endpoint (少了一層要維護的設備),等到有遇到效能問題時再來看是卡在哪邊,如果是 R/W split 可以解決的,才用 ProxySQL 或是其他軟體來解...

Instagram 解決 Cassandra 效能問題的方法

在解決 Cassandra 效能問題中大概就 ScyllaDB 特別有名,用 C++ 重寫一次使得效能大幅改善。而 Instagram 的人則是把底層的資料結構換掉,改用 RocksDB (這公司真的很愛自家的 RocksDB...):「Open-sourcing a 10x reduction in Apache Cassandra tail latency」。

主要原因是他們發現 Cassandra 在處理資料的部份會有 JVM 的 GC 問題,而且是導致 Cassandra 效能差的主要原因:

Apache Cassandra is a distributed database with it’s own LSM tree-based storage engine written in Java. We found that the components in the storage engine, like memtable, compaction, read/write path, etc., created a lot of objects in the Java heap and generated a lot of overhead to JVM.

然後在換完後測試可以看到效能大幅提昇,也可以看到 GC 的延遲大幅降低:

In one of our production clusters, the P99 read latency dropped from 60ms to 20ms. We also observed that the GC stalls on that cluster dropped from 2.5% to 0.3%, which was a 10X reduction!

比較一下這兩者的差異:在 ScyllaDB 是全部都用 C++ 改寫 (資料結構不換),這樣就直接解決掉 JVM 的 GC 問題。在 Rocksandra 則是在 profiling 後挑重點換掉 (這邊看起來是處理資料的 code,直接換成 RocksDB),另外順便把一些界面抽象化... 兩個不一樣的解法,都解決了 JVM 的 GC 問題。

Amazon Aurora (PostgreSQL) 也支援 Read Replica 了

Amazon Aurora (PostgreSQL) 支援 Read Replica 了:「Announcing Amazon Aurora PostgreSQL Read Replica for Amazon RDS for PostgreSQL」。

馬上想到的用途是量爆增時,如果當初有作 R/W split (讀寫分離) 就可以直接用錢撐住,不過官方給的範例是降低 RDS 轉移到 Aurora 的 downtime,這點就有點微妙...:

You can now create an Amazon Aurora PostgreSQL read replica for an Amazon RDS for PostgreSQL instance, allowing you to continuously replicate to Amazon Aurora PostgreSQL. This helps you minimize downtime when migrating a live workload from Amazon RDS for PostgreSQL to Amazon Aurora PostgreSQL, by keeping the instances in sync until you're ready to move your applications and users to Amazon Aurora PostgreSQL.

所以這次算是陸陸續續把功能補上來,在 Amazon Aurora (MySQL) 有的一般性功能,這邊就跟著先實作...