OxideDB:另外一套用 PostgreSQL 為底的 MongoDB 相容層

看到 OxideDB 這個專案:

OxideDB is a translation layer that works as a MongoDB database server while using PostgreSQL's JSON capabilities as the underlying data store.

跟之前提到的 MangoDB 有些淵源 (參考「MangoDB:拿 PostgreSQL 當作後端的 MongoDB 相容層」),順便提一下 MangoDB 然後後來被要求改名為 FerretDB:「MangoDB 改名為 FerretDB (雪貂)」。

主要的差異在於 OxideDB 只以 PostgreSQL 為底層,另外是用 Rust 寫的:

The project was heavily inspired by FerretDB and is on its early days. The main difference is that there is no intention to support any database other than PostgreSQL (FerretDB is also supporting Tigris) and it's written in Rust, as opposed to Go.

看起來大家都拿 PostgreSQL 在搞事,但這個專案裡面好像沒搜到 GIN 這個關鍵字,不知道是不是連 index 都沒下...

SQLite 的 zstd extension

看到「sqlite-zstd」這個實驗性質的專案,可以針對 SQLite 的 row-level 層壓縮:

Extension for sqlite that provides transparent dictionary-based row-level compression for sqlite. This basically allows you to compress entries in a sqlite database almost as well as if you were compressing the whole DB file, but while retaining random access.

看起來在空間上有很不錯的成果:

作者在他自己的 blog 上面有給了一篇比較完整的說明,除了空間上的優勢以外,還包含了效能上的分析:「sqlite-zstd: Transparent dictionary-based row-level compression for SQLite」。

在文章裡面測出來的數據看起來在效能上就不一定有比較好的結果,本來的 SQLite 就已經處理的還不錯了。

但看起來是個還蠻有趣的東西,舉例來說,如果可以透過 WebAssembly 編譯,再配合之前的「把 SQLite 的 VFS 掛上 WebTorrent 的 PoC Demo」,可以省下不少傳輸的量...

可以看看後續會不會真的有人這樣幹 XD

ClickHouse 自家做的 benchmark 比較

在「Show HN: A benchmark for analytical databases (Snowflake, Druid, Redshift) (clickhouse.com)」這邊看到 ClickHouse 自家做的 benchmark 比較,網站在「ClickBench — a Benchmark For Analytical DBMS」這邊。

這種 benchmark 基本上是拿來當作清單來看,另外 Hacker News 上的討論一定得看,尤其是沒被列上 benchmark 的...

講到 ClickHouse,先前是有朋友跑來說他有個需求是需要跑分析,但遇到用 PostgreSQL 時發現寫入速度不夠快的問題,看看有沒有什麼方法可以解。問了多一點以後發現他的需求是 OLAP 類而不是 OLTP 類,就先跟他講要去找 OLAP engine 來解決。

然後就聊到維基百科上「Comparison of OLAP servers」這個條目,裡面列出來的 open source 軟體是不少,但 Apache 家基本上大家都知道是回收場,裡面就剩下 ClickHouse 比較常在 Hacker News 以及其他地方被提到,但我有跟他講我連玩都沒玩過,我們家自己反而是用 CassandraTrino 搭出來的,當時沒有花太多時間研究市場上的方案,就挑了一個自己熟悉的方案趕快先解決。

但過了兩天後他就說用 ClickHouse 解決了,反而讓我對 ClickHouse 有興趣起來,反正記憶體當時裝了一堆沒用到。

拉了一下「Summary of the 1.1 Billion Taxi Rides Benchmarks」這邊的資料看,這個作者常常會測各種資料庫,算是一個可以參考的資料來源,可以看到 2019 年測的「1.1 Billion Taxi Rides: 108-core ClickHouse Cluster」其實就相當不錯了?

基本上先照「Usage Recommendations」這邊看一輪,基本的要求不低,但剛好機器是 32GB RAM:

If your system has less than 16 GB of RAM, you may experience various memory exceptions because default settings do not match this amount of memory. The recommended amount of RAM is 32 GB or more. You can use ClickHouse in a system with a small amount of RAM, even with 2 GB of RAM, but it requires additional tuning and can ingest at a low rate.

如果要跑 cluster 模式的話會需要 ZooKeeper 或是替代品 ClickHouse Keeper

然後除了使用官方的 clickhouse-client 連線以外,也可以用 MySQL 或是 PostgreSQL 的 client 連,裡面操作其實蠻簡單的,好像值得投資看看?

又一份講基本 RDBMS 的文件

前幾天在 Hacker News Daily 看到「Things You Should Know About Databases」這篇文章,裡面講了很多基本的 RDBMS 的概念,另外 Hacker News 上對應的討論在「Things to know about databases (architecturenotes.co)」這邊。

裡面講了 B-treeB+tree 的差異:

不過這點在維基百科上也蠻清楚的文字說明:

A B+ tree can be viewed as a B-tree in which each node contains only keys (not key–value pairs), and to which an additional level is added at the bottom with linked leaves.

另外裡面的 sorted 的那張圖:

這邊的說明不完全正確,在維基百科上的「Database index」這個條目裡面有提到 Non-clustered、Clustered 與 Cluster 三種架構,這邊圖片所表示的是 Non-clustered。在 InnoDB 裡面 data 是照 primary key 順序存放的 (沒有指定時會有一套邏輯選出哪個欄位當 PK,最後的情況是有 hidden key)。

再來就是提到 isolation,這邊也講的比較淺,只提到 ANSI 標準裡面的 SERIALIZABLEREPEATABLE READ (RR)、READ COMMITTED (RC) 與 READ UNCOMMITTED (RU) 四個,但沒提到像是 SNAPSHOT ISOLATION (SI) 這類的也很常見的標準。

說到 SI,在查 Snapshot isolation 的資料時整理了一下 PostgreSQL 的混亂情況。

在 PostgreSQL 9.0 以及更早前的版本,你指定 SERIALIZABLE 其實只有做到 Snapshot isolation 的等級,到了 9.1+ 後,SERIALIZABLE 才是真正做到 ANSI 定義的強度:

Snapshot isolation is called "serializable" mode in Oracle and PostgreSQL versions prior to 9.1, which may cause confusion with the "real serializability" mode.

另外 ANSI 定義的 isolation level 很難「用」 (但還是值得學起來,算是基本的東西),實際上的使用都是看各家資料庫對 isolation level 的保證程度來設計。

PostgreSQL 上對應 pt-online-schema-change 的工具 pg-osc

翻資料的時候翻到「pg-osc: Zero downtime schema changes in PostgreSQL」這篇文章,可以在 PostgreSQL 上做到類似 pt-online-schema-change 的事情,這邊先提一下 pt-online-schema-change 的說明:

ALTER tables without locking them.

不管是 MySQL 還是 PostgreSQL,都會遇到 ALTER TABLE 常常會 lock 的問題,這點主要的影響就是 db migration。

在 dev 環境的機器應該沒什麼問題,資料量都不大,應該是很快就可以跑完;但在 stage 環境時就會開始有狀況了 (假設是從 production 複製過來的資料,表格的大小可能偏大),但應該還是可以用 downtime 換,慢慢跑,花幾個小時把 db migration 跑完。

可是到了 production 環境時就不太能這樣搞了,這也是一般不太建議在 production 環境裡用現成的 db migration 工具,尤其當資料量偏大的時候。

解這個問題的方法就是透過繞路的方式,不要直接動原來的 table:基本的想法是開一個新的 table,然後一直從舊的 table 搬資料到新的 table 上 (包括應用程式下指令寫到舊的 table 上的資料),直到最後用一個短暫的 lock 機制來切換 table。

在 MySQL 的世界裡比較有名的是 Percona 的 pt-online-schema-change (trigger-based) 以及 GitHubgh-ost (replication-based),另外找資料的時候有發現 Facebook 也有丟 OnlineSchemaChange (trigger-based) 出來。

在 PostgreSQL 的世界裡似乎是 pg_repack 這個方案,用了 trigger-based 的方式處理,但之前沒有注意到,是翻 pg-osc 的時候被提到才知道有這個工具。

而這次提到的 pg-osc 則是 2022 年才出的軟體,也是 trigger-based 的方式:

pg-osc uses the concept of shadow tables to perform schema changes. At a high level, it creates a shadow table that looks structurally the same as the primary table, performs the schema change on the shadow table (avoiding any locks since nothing is using this table), copies contents from the primary table to the shadow table and swaps the table names in the end while preserving all changes to the primary table using triggers (via audit table).

另外從 PostgreSQL 的 wiki 上看到「Change management tools and techniques」這頁,裡面看到「Metagration: Logical PostgreSQL Migration」這個工具,看起來好像是 replication-based 的方案,不過還是有用到一些 trigger 做事。

這些方案都先記錄起來好了...

比對兩個表格 (可以是不同的資料庫) 的內容,指出差異處

前幾天看到的東西,不確定是不是在 Hacker News 上,反正在 tab 上幾天了... 但還是附上 Hacker News 的連結:「Show HN: Data Diff – compare tables of any size across databases」,專案的位置在 GitHub 上的 datafold/data-diff

這是用 Python 寫的工具,安裝可以透過 pip 直接裝,所以也可以用 pipx 之類的工具獨立起來跑。

data-diff 會先拆成多個區塊,然後透過 checksum 的機制判斷兩邊的資料是否相同,不同的部份再取 bisection 分開下去找 (或是更多份,在 Technical Explanation 這個段落有寫到)。

在「Common use-cases」這段有提到幾個常見的使用情境,像是在自動化的環境下可以當作異常監控的工具:

Alerting and maintaining data integrity SLOs. You can create and monitor your SLO of e.g. 99.999% data integrity, and alert your team when data is missing.

另外在 troubleshooting 的情境下當然也很有幫助,可以先確認資料是否有問題,以及資料的哪邊出問題:

Debugging complex data pipelines. When data gets lost in pipelines that may span a half-dozen systems, without verifying each intermediate datastore it's extremely difficult to track down where a row got lost.

這個工具讓我想到 Percona Toolkit 裡面的 pt-table-checksum,不過 pt-table-checksum 只能處理 MySQL replication 的情境,data-diff 看起來通用多了:

目前完整測試過的是 MySQLPostgreSQLSnowflake,其他的有實做但還沒完整測試過。

看起來還在開發 (後面是商業公司 Datafold),但先寫下來,之後如果有用到的時候可以回頭看看進展...

直接用 SQLite 查詢 Excel 檔案的 XLite (還有 dsq)

Hacker News 上看到「Xlite: Query Excel and Open Document spreadsheets as SQLite virtual tables (github.com/x2bool)」這個專案,就如同說明,是一個支援讀取 Excel 檔案的 SQLite extension,原網站在 x2bool/xlite 這邊。

依照說明支援舊的 .xls 與新的 .xlsx 的格式,但不知道公式運算支援到什麼程度...

先 load extension:

sqlite3 # will open SQLite CLI
> .load libxlite

接著是建立 virtual table:

CREATE VIRTUAL TABLE class_data USING xlite(
    FILENAME './path/to/example.xlsx',
    WORKSHEET 'Class Data',
    RANGE 'A2:F'
);

接下來就可以搞事了:

SELECT COUNT(*), D FROM class_data GROUP BY D ORDER BY COUNT(*);

看起來是用 Rust + C 寫的,然後作者有提醒這是寫興趣的專案:

This project is experimental, use at your own risk. The project is developed in my free time as a way to learn Rust and database systems.

反倒是 Hacker News 討論串裡面提到了 multiprocessio/dsq 這個專案,看起來發展的比較久,支援度也比較完整了:

Commandline tool for running SQL queries against JSON, CSV, Excel, Parquet, and more

不過就不是綁 SQLite 了 (雖然還是有關),從範例可以看到他是獨立的程式:

$ dsq testdata.json "SELECT * FROM {} WHERE x > 10"

Under the hood dsq uses DataStation as a library and under that hood DataStation uses SQLite to power these kinds of SQL queries on arbitrary (structured) data.

如果是真的要用的話,這套看起來應該會好一些...

翻一下 Linux container 的各種 overhead

想要查一下 Linux 下跑 container 的 overhead,發現大多都是 2014~2016 左右的文章,而且基本上都是 Docker,好像沒什麼新資料,但還是整理整理...

首先是「What is the runtime performance cost of a Docker container?」這篇,裡面的答案有提到 CPU、Memory 以及 I/O 看起來 overhead 都不高,主要是網路的 latency 增加不少:

看起來大約是 40µs 的增加 (0.04ms),這個量級雖然看起來很小,但對於本來就是透過 Ethernet 溝通的的應用來說,平常可能都是 <1ms 了,0.04ms 的增加可能還是有影響 (像是 TCP 的 3-way handshake)。

另外一篇是 Percona 的「Measuring Percona Server Docker CPU/network overhead」,不過這邊是測 CPU bound 的方式,沒有碰到 heavy I/O:

可以看到網路層的變化造成 tps 的變化,也符合在 Stack Overflow 上面找到的文章。

Oracle 官方的「MySQL with Docker - Performance characteristics」這篇則是測到 I/O bound 的應用,畢竟資料庫軟體會用到很多一般 I/O 測試不會用到的 flag,像是 InnoDB 大家通常都會啟用 O_DIRECT

For these tests, we used a custom configuration file. We first deliberately set the buffer pool size to around 10% of the total database size in order to increase I/O-bound load. The database size was 2358MB, so we set our buffer pool size to 256MB. We then increased the buffer size to 16384MB to see what happens when Docker isn’t bound by I/O load.

文章後面有列出數字,可以看到 I/O bound 的應用似乎沒有什麼影響,而 network bound 的時候可以看到效能的下降。

不過得注意這些資料都是六年前的資料了,沒有什麼新資料可以看做應該是沒什麼改變,但畢竟不是 100% 確定的事情...

在 Shell 下一行用 SQLite 查詢 CSV 內的資料

Simon Willison 這邊看到 command line 下用 SQLite 的技巧:「One-liner for running queries against CSV files with SQLite」。

範例指令是這樣 (整理了一下排版):

sqlite3 :memory: \
    -cmd '.import -csv taxi.csv taxi' \
    'SELECT passenger_count, COUNT(*), AVG(total_amount) FROM taxi GROUP BY passenger_count'

可以看出來這個方式是將 csv 檔先讀到 in-memory database (:memory:),再用 SQLite 下指令處理,另外也可以自己變化,應該可以透過 /dev/stdin 這樣的方式讀 pipe 的東西。

拿來簡單跑一些東西應該還不賴?

在 Hacker News 上看到幾個 Key-Value Store 軟體

Hacker News 上看到「Redis vs. KeyDB vs. Dragonfly vs. Skytable」這篇,裡面介紹了四套 key-value store 軟體:

  • Redis:這個應該不太需要介紹...
  • KeyDBSnapchat 搞出來的 Redis clone,主要的賣點是 multi-threading。
  • Dragonfly:宣稱地球上最快,但作者跑不出來,下面的討論有人提到 Dragonfly 在更多的 CPU 資源效能就會更好。
  • Skytable:作者測出來最快的。

裡面看起來都蠻有趣的,可以追起來看看發展的情況,但如果真的要的用的話,應該還是先以 Redis 為主,穩定度以及功能還是重點...