PyPy JIT 的改善

PyPy 這邊看到 JIT 的重大進展:「Better JIT Support for Auto-Generated Python Code」。

他們在 Tornado 上重製出來效能問題,後面也都是用這個例子在測試:

If you render a big HTML template (example) using the Tornado templating engine, the template rendering is really not any faster than CPython.

看起來上的 workaround 是在撞到 trace limit 時標記起來,之後再遇到時就可以跳進 special mode,接著處理下去避免浪費掉之前處理過的 trace:

After we have hit the trace limit and no inlining has happened so far, we mark the outermost function as a source of huge traces. The next time we trace such a function, we do so in a special mode. In that mode, hitting the trace limit behaves differently: Instead of stopping the tracer and throwing away the trace produced so far, we will use the unfinished trace to produce machine code.

效能可以看到改善很多:

看起來這個概念有打算在 3.8 的時候放進去:

The work described in this post tiny bit experimental still, but we will release it as part of the upcoming 3.8 beta release, to get some more experience with it. Please grab a 3.8 release candidate, try it out and let us know your observations, good and bad!

Django 的 template engine 不怎麼快,用 Jinja2 可能是一個方法,但既有的 project 如果有遇到 template engine 的效能問題,也許也可以翻看看 PyPy 解得如何...

用顏色區分程式碼裡面的括弧

Hacker News Daily 上看到 VSCode 改善了 bracket pair colorization 效率的文章,才想到我的 Vim 好像沒裝這個功能:「Bracket pair colorization 10,000x faster」。

VSCode 這邊主要是引入了新的資料結構改善了計算量,有興趣的可以看一下:

Efficient bracket pair colorization was a fun challenge. With the new data structures, we can also solve other problems related to bracket pairs more efficiently, such as general bracket matching or showing colored line scopes.

我這邊則是去找 Vim 上的套件,目前看到是「Rainbow Parentheses Improved」這個,裝起來拿 PHP 程式碼看了一下還行,這樣就不用在那邊算哪個左括弧對應到右括弧...

Netflix 在單機服務 400Gbps 的影音流量

Hacker News 首頁上看到 NetflixEuroBSDCon 2021 上發表的投影片:「Serving Netflix Video at 400Gb/s on FreeBSD」,對應的討論則是在「Serving Netflix Video at 400Gb/s [pdf] (freebsd.org)」這邊可以翻到,投影片的作者有在上面回答一些問題。

投影片在講的應該就是 Netflix 的 Open Connect

主要是因為 Open Connect 的伺服器是放到各家 ISP 機房,在單一 IP 且單一伺服器的限制下,要想辦法壓榨出最高的效能。

硬體是 AMDEPYC,在先前的版本可以達到 240Gbps,經過分析與嘗試解決了一堆問題後,最後是在原來的 AMD 機器上跑到了 380Gbps (另外有測 ARM 以及 Intel 的數字),然後之後機房有可能會有 800Gbps 的標準,他們又要繼續煩惱...

有看到 Mellanox ConnectX-6 Dx (CX6-DX) 這個東西,看起來很有趣啊,有 200Gbps 的能力,而且可以把 TLS 的事情推到卡上面處理... 然後這家公司被 Nvidia 買走了。

另外當然也會有人問為什麼不用 Linux,作者在討論串裡面也有回答一些,有興趣的可以自己去搜一下。

Brendan Gregg 的工具與 profiling 技巧

這篇放在 browser tab 上一陣子了,今天找機會玩一下... 這是 Brendan Gregg 的工具,以及他說明怎麼用他來 profiling:「Analyzing a High Rate of Paging」。

裡面提到的 iostatfree 算是基本盤了,但裡面提到了很多看起來很神奇的東西,像是 biolatency、bitesize、cachestat,可以裝 bpfcc-tools 來用,檔名會加上 -bpfcc 的 suffix (像是 biolatency-bpfcc 這樣)。

三隻程式都需要 root 才能跑,對我來說,在 database 上面分析效能應該是很好用... 好像可以考慮直接當作預設安裝裝到每台機器上?

用 Ephemeral Storage 加速 MySQL over ZFS 的效能

Percona 的「MySQL/ZFS in the Cloud, Leveraging Ephemeral Storage」這篇裡面在探討是不是可以看看 ZFS 在 Ephemeral Storage (機器附的本地硬碟) 上的效能。

一開始測試是直接當主力硬碟來測,可以看到跑 ZFS 的情況下,本地的 storage 還是會比 SSD Premium (這是 Azure 的產品線) 還快不少:

但把資料放在本地的 storage 上其實有點刺激,至少在 production 應該不太會這樣搞,所以後面用 L2ARC 的方式來測,可以看到效率提昇相當明顯,甚至接近本來直接把資料放在本地的 storage:

另外測了 ext4/bcache,看起來效率就沒那麼好:

這樣看起來是個不錯的選擇...

Amazon EC2 上的一些小常識

Twitter 上看到 Laravel News 轉發了「Mistakes I've Made in AWS」這篇,講 Amazon EC2 上面的一些小常識。

在 EC2 中,T 系列的機器 (目前主要是 t2/t3/t3a/t4g) 對於開發很好用,甚至對於量還不大的 production system 也很好用,加上 Unlimited 模式可以讓你在 CPU credit 用完時付錢繼續 burst。

文章裡面有討論到,使用 T 系列機器時,常常是不怎麼需要大量 CPU 資源的情境,這時候 AMD-based 的 t3a 通常都是個還不錯的選擇,大概會比 Intel-based 的 t3 省 10% 的費用。另外如果可以接受 ARM-based 的話,t4g 也是個選項,價錢會更便宜而且在很多應用下速度會更快。不過同事有遇到 Python 上面跑起來的行為跟 x86-64-based 的不同,這點就得自己琢磨了...

另外就是目前的 EBS 預設還是會使用 gp2,而在 gp3 出來後其實大多數的情況下應該可以換過去,主要就是便宜了 20%,加上固定的 3000 IOPS。

不過也是有些情境下是不應該換的,主要是 gp2 可以 burst 到 250MB/sec,但 gp3 只給了 125MB/sec。雖然 gp3 可以加價買 throughput,但加價的費用不低,這種需求改用 gp2 應該會比較划算。

不過這邊推薦比較技術的作法,可以掛兩個 gp3 (也可以更多) 跑 RAID0 (像是在 Linux 上可以透過 mdadm 操作),這樣 IOPS 與 throughput 都應該可以拉上來...

Percona 連載到 PostgreSQL 存 JSON object 以及增加 Index 的方式了...

先前 Percona 的人在講 MySQL 存 JSON object 的方式,現在開始講在 PostgreSQL 裡存 JSON object,並且增加 index 的方式了:「Storing and Using JSON Within PostgreSQL Part One」。

這基本上就是不想用 MongoDB,但還是有需要極為彈性而選擇用 JSON object 的需求。

首先先先建立一個表格,這邊直接用 JSONB:

alice=# CREATE TABLE table1 (id SERIAL PRIMARY KEY, jb JSONB);

接著拿「A dataset of English plaintext jokes」這邊的 reddit_jokes.json 來玩,我先把 JSON 裡面的內容變成 JSON Lines 格式:

cat reddit_jokes.json | jq -c '.[]' > reddit_jokes.jsonl

然後 COPY 了十次,多一點資料,後面可以看效能:

alice=# COPY table1 (jb) FROM '/tmp/reddit_jokes.jsonl' CSV QUOTE e'\x01' DELIMITER e'\x02';
-- (repeat this command 10 times)

接著跑個 SELECT 看看速度,我跑了幾次大約都在 260ms 上下:

alice=# SELECT COUNT(*) FROM table1 WHERE (jb->>'score')::int = 10;
 count 
-------
 25510
(1 row)

Time: 264.023 ms

然後針對 score 生個數字的 index:

alice=# CREATE INDEX ON table1 (((jb->>'score')::int));
CREATE INDEX
Time: 1218.503 ms (00:01.219)

接著再跑 SELECT 下去,可以看到速度快超多:

alice=# SELECT COUNT(*) FROM table1 WHERE (jb->>'score')::int = 10;
 count 
-------
 25510
(1 row)

Time: 12.735 ms

另外也可以加 column:

alice=# ALTER TABLE table1 ADD COLUMN score INT GENERATED ALWAYS AS ((jb->>'score')::int) STORED;

然後可以看到速度也不快:

alice=# SELECT COUNT(*) FROM table1 WHERE score = 10;
 count 
-------
 25510
(1 row)

Time: 222.163 ms

幫他補 index:

alice=# CREATE INDEX ON table1 (score);

速度有變快,但不知道為什麼沒有 JSONB 的版本快:

alice=# SELECT COUNT(*) FROM table1 WHERE score = 10;
 count 
-------
 25510
(1 row)

Time: 81.346 ms

算是還蠻好用的,不過得學 JSON query 語法... (應該是還好)

2019 年 Percona 對 UUID 當作 Primary Key 的看法

前陣子的「為資料庫提案新的 UUID 格式」這邊提到了有人提案要增加新的 UUID 格式,Percona 的老大 Peter ZaitsevTwitter 上貼了「UUIDs are Popular, but Bad for Performance — Let’s Discuss」這篇在 2019 年時他們家的文章,題到了 MySQL 使用 UUID 當作 Primary Key 的事情:

要注意的是這篇文章沒有要從頭解釋 UUID 對於 Primary Key 的壞處,如果你想要先了解的話,在這篇文章的開頭給了一堆其他文章的連結,裡面就有討論過了。

這篇主要是在討論,如果硬要用 UUID 當 Primary Key 時,可以有什麼方法降低對 InnoDB 的衝擊,剛好回應最近的提案。

開頭還是先花了一些篇幅大概講一下 UUID 的種類,然後在「What is so Wrong with UUID Values?」這邊提到了字串比較的差異,如果 UUID 是到最後一碼才不同的話 (這邊是跑 df878007-80da-11e9-93dd-00163e000002 與 df878007-80da-11e9-93dd-00163e000003 與比較一億次):

1 row in set (27.67 sec)

但如果是一開始就不同的話 (這邊是選擇 df878007-80da-11e9-93dd-00163e000002ef878007-80da-11e9-93dd-00163e000003) 會快很多:

1 row in set (2.45 sec)

但如果與數字相比的話 (這邊是 2=3 這樣的條件去比):

1 row in set (0.96 sec)

可以看數字在這邊的優勢,另外也是在說明,如果你用的是 time-based ordering 的 UUID,要考慮會遇到這個可能會發生的效能問題。

再來是玩 UUID 的三種不同的儲存方式對於寫入效能的差異,分別是 CHAR(36) (32 bytes 的 hex 加上四個 -)、base64 (用 CHAR(22) 存) 與 BINARY(16),可以看出來 BINARY(16) 因為佔用空間比較小的關係,是可以高速寫入持續最久的,再來是 base64,最差的是 CHAR(36)

後面給了兩個 workaround,第一個算是定義了另外一種產生 128 bits 的方式,第二個則是想辦法把 UUID 對應到數字。

這在 MySQL 的環境裡面算是被討論的很久的主題了。(我猜在 PostgreSQL 應該也是,不過 PostgreSQL 的社群沒跟那麼久...)

MySQL 在不同種類 EBS 上的效能

Percona 的人寫了一篇關於 MySQL 跑在 AWS 上不同種類 EBS 的效能差異:「Performance of Various EBS Storage Types in AWS」,不過這篇的描述部份不是很專業,重點是直接看測試資料建立自己的理解。

他的方法是在 AWS 上建立了相同參數的 gp2gp3io1io2 空間,都是 1TB 與 3000 IOPS,但他提到這應該會一樣:

So, all the volumes are 1TB with 3000 iops, so in theory, they are the same.

但這在「Amazon EBS volume types」文件上其實都有提過了,先不管 durability 的部份,光是與效能有關的規格就不一樣了。

在 gp2 的部份直接有提到只有保證 99% 的時間可以達到宣稱的效能:

AWS designs gp2 volumes to deliver their provisioned performance 99% of the time.

而 gp3 則是只用行銷宣稱「consistent baseline rate」,連 99% 都不保證:

These volumes deliver a consistent baseline rate of 3,000 IOPS and 125 MiB/s, included with the price of storage.

io* 的部份則是保證 99.9%:

Provisioned IOPS SSD volumes use a consistent IOPS rate, which you specify when you create the volume, and Amazon EBS delivers the provisioned performance 99.9 percent of the time.

另外在測試中 gp2gp3 的 throughput 看起來也沒調整成一樣的數字。在 1TB 的 gp2 中會給 250MB/sec 的速度,1TB 的 gp3 則是給 125MB/sec,除非你有加買 throughput。

另外從這句也可以看出來他對 AWS 不熟:

The tests were only run in a single availability zone (eu-west-1a).

在「AZ IDs for your AWS resources」這邊有提過不同帳號之間,同樣代碼的 AZ 不一定是一樣的區域,需要看 AZ ID:

For example, the Availability Zone us-east-1a for your AWS account might not have the same location as us-east-1a for another AWS account.

To identify the location of your resources relative to your accounts, you must use the AZ ID, which is a unique and consistent identifier for an Availability Zone. For example, use1-az1 is an AZ ID for the us-east-1 Region and it is the same location in every AWS account.

在考慮到只有設定大小與 IOPS 的情況下,剩下的測試結果其實跟預期的差不多:io2 貴但是可以得到最好的效能,io1 的品質會差一些,gp3 在大多數的情況下其實很夠用,但要注意預設的 throughput 沒有 gp2 高。

Amazon EC2 推出 m6i 的機器

AWS 給了公告,在 Amazon EC2 上面推出了 m6iIntel-based 新機種:「New – Amazon EC2 M6i Instances Powered by the Latest-Generation Intel Xeon Scalable Processors」。

這好像是第一次看到 Intel-based 機種加上了 i 的 suffix...

這次比較大的兩個差異,與 m5 相比,多出了 m6i.32xlarge

A larger instance size (m6i.32xlarge) with 128 vCPUs and 512 GiB of memory that makes it easier and more cost-efficient to consolidate workloads and scale up applications.

另外看了一下 us-east-1 上的單價,看起來與 m5 系列的機器價錢一樣,但是效能提昇了 15% (然後很假掰的寫了 price/performance?):

Up to 15% improvement in compute price/performance.

單以數字看起來的話還是 m6g 系列會比較香?當然如果只有 x86-64 binary 的話看起來還是可以考慮換到 m6i 上跑...