Intel 與 AMD 在 RSQRTSS 的不同

看到「rr Trace Portability: Diverging Behavior of RSQRTSS in AMD vs Intel」這個,作者因為在 rr 上發現 replay 不正確,發現是 SSE 裡面的 RSQRTSS 這個指令在 IntelAMD 平台上會有不同的值出現導致的。

RSQRTSS 是計算平方根倒數,也就是計算 1 / \sqrt{x},另外比較特別的是,這個指令不保證正確性,是允許有誤差產生的。

提到平方根倒數,這個演算法更有名的應該是「反平方根快速演算法」這個用到 0x5f3759df 這個魔術數字的奇技淫巧,不過這不是這次的重點...

作者發現 RSQRTSS 在 Intel 與 AMD 平台的值不一定一樣,像是 256 的平方根導數是 1/16 (0.0625),但兩個平台跑出來不同:

On Intel Skylake I get
out = 3d7ff000, float = 0.062485

On AMD Rome I get
out = 3d7ff800, float = 0.062492

在這邊的 case 可以看出來 AMD 算的比較正確 (誤差值比較低),但都還是在 spec 允許的誤差範圍。

後來作者還發現有其他不同的指令也有類似的問題,為了解決在 rr 上可以正確 replay 的問題,他生了對應的 mapping table 來解:「Emulating AMD Approximate Arithmetic Instructions On Intel」。

苦啊... 不過這個主題還蠻有趣的。

MySQL InnoDB 的 OPTIMIZE TABLE 的 Lock

Backend Twhttps://www.facebook.com/groups/616369245163622/posts/2467225396744655/ 這邊看到:

先大概回答一下假設,DELETE 後的空間是可以被同一個表格重複使用的,所以應該是還好,不過離峰時間跑一下 OPTIMIZE TABLE 也沒什麼關係就是了。

裡面提到的「13.7.2.4 OPTIMIZE TABLE Statement」(MySQL 5.7 文件) 以及「13.7.2.4 OPTIMIZE TABLE Statement」(MySQL 5.6 文件) 都有講到目前比較新的版本都已經是 Online DDL 了:(這邊抓 5.6 的文件,有支援的版本資訊)

Prior to Mysql 5.6.17, OPTIMIZE TABLE does not use online DDL. Consequently, concurrent DML (INSERT, UPDATE, DELETE) is not permitted on a table while OPTIMIZE TABLE is running, and secondary indexes are not created as efficiently.

As of MySQL 5.6.17, OPTIMIZE TABLE uses online DDL for regular and partitioned InnoDB tables, which reduces downtime for concurrent DML operations. The table rebuild triggered by OPTIMIZE TABLE is completed in place. An exclusive table lock is only taken briefly during the prepare phase and the commit phase of the operation. During the prepare phase, metadata is updated and an intermediate table is created. During the commit phase, table metadata changes are committed.

文件上有提到會有一小段 lock 的時間,不過一般來說應該不會造成太大問題。

這邊要講的是早期的經典工具 pt-online-schema-change (pt-osc),這是使用 TRIGGER-based 的方式在跑,他的範例就直接提供了一個不需要 Online DDL 支援的版本:

Change sakila.actor to InnoDB, effectively performing OPTIMIZE TABLE in a non-blocking fashion because it is already an InnoDB table:

pt-online-schema-change --alter "ENGINE=InnoDB" D=sakila,t=actor

這在早期的時候還蠻常被拿出來用的,如果還在維護一些舊系統的話還蠻推薦的...

弄個 whoogle.hasname.com 給大家玩

先前提到的 Whoogle:「自架的 Google Search Proxy 伺服器專案:Whoogle Search」與「改寫「Press "g" to Google (DuckDuckGo)」讓他支援 Whoogle」,後來想一想還是讓沒打算自己架的人可以用好了,指到國外的 latency 還是比較高...

如果你是 Chromium 類的瀏覽器,可以把搜尋引擎改成:

https://whoogle.hasname.com/search?q=%s

如果是我寫的 userscript (「Press "g" to Google (DuckDuckGo)」這個),可以改成:

https://whoogle.hasname.com/search?q=

然後 nginx 這邊先 access_log off; 了,理論上這樣應該是差不多了?

目前機器是放在客廳 (加 UPS),之後可能會丟到台灣的 VPS 上?

Firefox 支援 HTTPS RR

在「Firefox 92.0, See All New Features, Updates and Fixes」這邊看到支援 HTTPS RR:

More secure connections: Firefox can now automatically upgrade to HTTPS using HTTPS RR as Alt-Svc headers.

在「Enabling HTTPS RR on release」這邊決定啟用的,使用的標準是「Service binding and parameter specification via the DNS (DNS SVCB and HTTPS RRs)」這個,可以看到目前還是 draft (draft-ietf-dnsop-svcb-https-07)。

HSTS 是 Trust on first use,也就是在第一次連線時 server side 會送出 HSTS header,之後瀏覽器遇到同一個網站時就會都強制使用 HTTPS。

如果要確保第一次也是強制使用 HTTPS,在這之前必須靠瀏覽器內建的清單 HSTS Preload List 才能確保安全性,這次的 HTTPS RR 算是補上這個缺口。

在使用者環境有 DNS over HTTPS (DoH) 或是 DNS over TLS (DoT),再加上 DNS resolver 會檢查 DNSSEC 的前提下,整條環境就接起來了。

不過實際讀了 spec 會發現 SVCB RR 與 HTTPS RR 想做的事情太多了,話說愈複雜的東西愈容易出包,先放著觀望看看好了...

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 都應該可以拉上來...

OpenSSH 的 scp 改用 SFTP 協定

在「By default, scp(1) now uses SFTP protocol」這邊看到的,OpenSSH 的 scp 改用 SFTP 協定了,原因也有附在文章裡:

SFTP offers more predictable filename handling and does not require expansion of glob(3) patterns via the shell on the remote side.

要注意這是 BC-break change,有些之前會動的 case 在改用 SFTP 後會爛掉,但這算是前進了一大步,scp 因為 spec 的關係很難維護安全性。

在「Deprecating scp」這邊也有提到相關的問題,另外也給出了一些範例。

OpenSSL 3.0 釋出,使用 Apache License 2.0

OpenSSL 3.0 推出了,這是轉換到 Apache License 2.0 後的第一個正式版本:「OpenSSL 3.0 Has Been Released!」。

中間跳過 2.0 的原因在維基百科上也有提到,因為之前被 OpenSSL FIPS module 用掉了:

The major version 2.0.0 was skipped due to its previous use in the OpenSSL FIPS module.

雖然 3.0.0 看起來是大版本,不過主要的功能都在 OpenSSL 1.1.1 先加進去了,沒有什麼特別的理由現在就要升級到 3.0.0...

改寫「Press "g" to Google (DuckDuckGo)」讓他支援 Whoogle

前幾天提到了 Whoogle 這個專案 (參考「自架的 Google Search Proxy 伺服器專案:Whoogle Search」),用 Docker 跑起來後就改寫「Press "g" to Google (DuckDuckGo)」這個專案,讓他可以支援設定 Whoogle,大概像是這樣:

使用者可以自己設定對應的 Whoogle 伺服器,這樣應該會方便一些...

用 Podman 替代 Docker?

也是因為最近 Docker Desktop 改變授權的關係 (參考先前寫的「Docker Desktop 要開始對商用收費了,以及 Open Source 版本的設法」這篇),有不少人在講怎麼用 Podman 替代 Docker,不過要注意這邊的替代不是 drop-in replacement,而是功能上的替代。轉移的過程還是得花一些時間處理...

在 Mac 上面的範例大多都是用 Homebrew,我在 MacPorts 上也有看到套件:「podman」,看起來好像得多裝 qemu,但即使把 qemu 裝起來,也還是不會動... 後續因為沒有需求,加上先前已經把 Docker CLI 的版本弄好了,暫時就沒再多研究要怎麼跑起來。

另外有人寫了「Migrating from Docker to Podman」這篇,在「GUI Replacement」的部份還介紹了對應的 GUI 方案,也可以參考看看。

跟以前的養套殺類似,都會推動一些 open source 替代方案的成熟度,以這次的情況看起來這些能量有很大一部份都會進到 Podman 裡面,對於個人用戶也可以再放幾個月看看是不是要跳槽過去。

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 語法... (應該是還好)