KeyDB:使用 Multithreading 改善 Redis 的效能

Hacker News 上看到有支援 Multithreading 的 Redis fork:「KeyDB – A Multithreaded Fork of Redis (keydb.dev)」,官網在「KeyDB - The Faster Redis Alternative」這邊。

不過這篇是要記錄從 Hacker News 看到的雷點,這樣以後自己再找資料的時候會比較容找到。

36022425 這篇是跳下去用發現不太行,最後在 application 端實作需要的 feature,後端還是用原廠的 Redis:

To counter what the other active business said, we tried using KeyDB for about 6 months and every fear you concern you stated came true. Numerous outages, obscure bugs, etc. Its not that the devs aren’t good, its just a complex problem and they went wide with a variety of enhancements. We changed client architecture to work better with tradition Redis. Combined with with recent Redis updates, its rock solid and back to being an after-thought rather than a pain point. Its only worth the high price if it solves problems without creating worse ones. I wish those guys luck but I wont try it again anytime soon.

* its been around 2 years since our last use as a paying customer. YMMV.

另外是在專案裡搜尋「is:open is:issue label:"Priority 1"」的結果可以看到不太妙,在 36021108 這邊有提到的問題:

Filed July, eventually marked priority 1 in early December, not a single comment or signs of fix on it since. That doesn't look good at all.

然後 36020184 有提到 Snap 買進去後沒有什麼在管 open source project 的部分了:

I think I'll stay far away from this thing anyway. Numerous show-stopper bug reports open and there hasn't been a substantial commit on the main branch in at least a few weeks, and possibly months. I'll be surprised if Snap is actually paying anybody to work on this.

npm 裡的 redis 與 ioredis

前幾天在噗浪的偷偷說上看到有人提到 npmtrends 上的 redis (官方的) 與 ioredis:「https://www.plurk.com/p/p6wdc9」。

意外發現以下載量來看,ioredis 已經超越官方的 redis 了:

找了一下差異,看起來的確有些團隊在 loading 很高的情況下會考慮用 ioredis 取代 redis:「Migrating from Node Redis to Ioredis: a slightly bumpy but faster road」。

但沒有特別需求的話應該還是會用官方版本?

在 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 為主,穩定度以及功能還是重點...

Linode 過了三年,終於想起來要推出 Managed Databases 服務了

看到 Linode 宣佈 Managed Databases 服務:「Linode Managed Databases in Open Beta」。

測試期間不用錢,但目前只有支援 MySQL,其他幾個像是 PostgreSQLRedisMongoDB 都還沒推出 (在 roadmap 上):

Our new managed database service is now in open beta for new and existing customers! We currently support MySQL during this beta—with a near-term roadmap to add PostgreSQL, Redis, MongoDB—and plan to include additional features.

搜了一下隔壁 DigitalOcean 的資料,Manage Databases 這條產品線在 2019 年二月推出 PostgreSQL 的版本:「Our Valentine’s Gift to You: Managed Databases for PostgreSQL」,在 2019 年八月推出了 MySQL 與 Redis 的版本:「Take the worry out of managing your MySQL & Redis databases」,然後在 2021 年六月推出了 MongoDB 的版本:「Introducing DigitalOcean Managed MongoDB – a fully managed, database as a service for modern apps」。

不過 Vultr 看起來是還是完全沒有樣子,相比起來 Linode 好像不算慢?

另外看起來 DigitalOcean 是跟 MongoDB 合作,不像 AWS 自己另外用 PostgreSQL 搞了一套 XDDD

限制流量的方式 (rate limit)

Lobsters Daily 上看到這篇 2017 年的文章,Figma 的工程師講怎麼做 rate limit:「An alternative approach to rate limiting」,只要大一點的站台就會遇到 spammer 之類的攻擊,就會希望實做自動化的機制擋住 spammer。

文章裡面提到了三種方式,第一種 (類) 提到了經典的 Token bucketLeaky bucket,這邊文章提供的演算法是讓每個使用者都會有一筆資料紀錄在 Redis 裡面 (這邊的用法可以抽換換成 Memcached),裡面記錄了最後一次的 access time 以及還剩下多少 token 可以用,接下來就可以照時間計算 token 的補充與消耗:

但這個演算法的缺點是 race condition,需要另外設計一些機制確保操作的 atomic:

不過大多數的實做就算不管 atomic 也還行 OK,只是會比較不精確一點。

第二個方法他叫做 Fixed window counters,這個方法把時間切齊為單位 (像是 60 秒為一個 window),所以可以把起點的時間也放到 key 裡面,然後 value 就是數量:

這個作法的好處就是簡單,而且 Redis 與 Memcached 都有提供 atomic 的 +1 操作。但缺點是可能會發生兩倍以上的 request,像是 5 reqs/min 的限制有可能會有連續的一分鐘內達到 10 reqs/min:

不過我覺得就 antispam 來說算是夠用了,當年 (大概是 2007 或是 2008 年?) 在 PIXNET 時用 C 寫 Apache module 就是把資料丟到 Memcached 裡面就是這樣實做的,然後每次學術網路的實驗室跑來掃站的就會自動被擋 XDDD

第三種方式他們稱作 Sliding window log,就是把每個 request 的 timestamp 都存起來,這個部份用 Redis 的資料結構會比用 Memcached 方便一些:

這個方式在控制上更精確,不過空間成本上就高很多... 這樣算是把常見的實做方式都提到了。

Memcached 與 Redis 的比較

在「Memcached vs Redis - More Different Than You Would Expect」這邊看到對 MemcachedRedis 的分析。

這兩套軟體都很常被拿來用作 cache 機制,所以一般來說比較時就是比兩邊都有的東西 (如果你要 pub-sub 之類的東西,在這兩套裡面只有 Redis 有)。

最前面還是先講了對使用者 (開發者) 的差異,很明顯的是 Redis 對各種不同的資聊結構都有支援,這點可以從 Redis 被官方被稱作 Data Structures Server 就可以知道 (在「An introduction to Redis data types and abstractions」這篇可以看到),而 Memcached 只支援了 key-value 架構。

不過如果是以 cache 來說,的確 key-value 架構就還蠻好用的。

後面就開始比較硬的主題了,提到了 Memcached 與 Redis 內部是怎麼使用記憶體的。

Memcached 的部份先提了 page/slab/chunk 的架構以及產生的效能限制與浪費,接著有提到 2020 年 refactor 的部份 (太久沒有看 Memcached 的消息,去年沒跟到這個部份),讓多 CPU 的支援度更好。

Redis 則是靠 jemalloc 來處理這個部份,另外加上 background thread 的機制降低 fragment。

然後是比較 cache expiration 的部份,可以看到兩者用的演算法在現實世界中都夠用 (尤其是當作 cache 來用),這部份跟印象中的架構差不多,應該是沒有太大變化。

最後是比較 cluster 的部份,Memcached 是 share nothing,所以沒什麼好說的,主要是靠 client library 實做 consistent hash 之類的架構打散;而 Redis 的話看起來有實做新的機制出來 (也沒跟到),之後有機會再看看可以做到什麼程度。

不過好像沒提到 proxy 之類的架構,基本上各大公司都有自己幹:

少了這塊對於 cluster 架構的完整性差蠻多的。

文章最後沒有下定論一定要用哪個比較好,兩者都有強項與弱項,還是得看情況來處理。不過我自己還是很喜歡用 Memcached 就是了...

PostgreSQL 的 Job Queue、Application Lock 以及 Pub/Sub

Hacker News Daily 上看到一篇講 PostgreSQL 做 Job Queue、Application Lock 以及 Pub/Sub 的方法:「Do You Really Need Redis? How to Get Away with Just PostgreSQL」,對應的討論在「Do you really need Redis? How to get away with just PostgreSQL (atomicobject.com)」這邊可以翻到。

拿 PostgreSQL 跑這些東西的確有點浪費,不過如果是自己的專案,不想要把 infrastructure 搞的太複雜的話,倒是還不錯。

首先是 Job Queue 的部份,從他的範例看起來他是在做 async job queue (不用等回傳值的),這讓我想到很久前寫的 queue service (應該是 2007 年與 2012 年都寫過一次),不過我是用 MySQL 當作後端,要想辦法降低 InnoDB 的 lock 特性。

async job queue 設計起來其實很多奇怪的眉角,主要就是在怎麼處理失敗的狀態。大多數的需求可以放到兩個種類,最常見用的是 at-least-once,保證最少跑一次,大多數從設計上有設計成 idempotence 的都可以往這類丟,像是報表類的 (重複再跑一次昨天的報表是 OK 的),另外每天更新會員狀態也可以放在這邊。

另外少見一點的是 at-most-once 與 exactly-once,最多只跑一次與只跑一次,通常用在不是 idempotence 的操作上,像是扣款之類的,這邊的機制通常都會跟商業邏輯有關,反正不太好處理...

第二個是 Application Lock,跨機器時的 lock 機制,量沒有很大時拿 PostgreSQL 跑還行,再大就要另外想辦法了,馬上想到的是 ZooKeeper,但近年設計的系統應該更偏向用 etcdConsul 了...

最後提到的 Pub/Sub,一樣是在量大的時候拿 PostgreSQL 跑還行,更大的時候就要拿 Kafka 這種專門為了效能而設計出來的軟體出來用...

ALB 支援 Sticky Session

又是一個以為很久前就已經支援,但實際上沒支援的功能...

ALB 支援使用 cookie 實現 sticky session 功能:「Application Load Balancer now supports Application Cookie Stickiness」。

使用者的 session 通常會使用 cookie 記錄,而如果有多台 server 提供服務時,session 裡的資訊就需要找一個 shared session storage 放,以確保使用者在連到不同的 server 時都還是可以讀到對應的 session,比較傳統的方案就是直接把 session 塞進資料庫,後來發展出 memcached 或是 Redis 可以用。

但有些買來的軟體並沒有考慮到這點 (常常都是內部系統),導致前面放 load balancer 時,必須想個辦法記錄使用者使用後端的哪台機器,這樣就可以在後端不支援 shared session storage 的情況下,還是可以讓應用正常運作。

透過 cookie 實做的 sticky session 算是蠻常見的作法,只是以為早就有了...

AWS 上的 Redis 服務支援 Global Replication

AWS 上的 Redis 服務 (Amazon ElastiCache) 推出了 Global Datastore,也就是跨區同步的功能:「Now Available: Amazon ElastiCache Global Datastore for Redis」。

技術上會分成 read endpoint 與 write endpoint (在最後面的操作可以看到 $US_WEST_1_CLUSTER_READWRITE$US_WEST_2_CLUSTER_READONLY),所以算是蠻常見的 primary-secondary 架構。

不過我基本上不太愛 Redis,能用 Memcached 解決的偏好用 Memcached 解。不過如果把 Redis 當作是一種雲端服務的話,倒是還可以接受...

Stripe 將 Redis 單機版轉到 Cluster 版本上降低了錯誤率

在「Scaling a High-traffic Rate Limiting Stack With Redis Cluster」這邊提到了 StripeRedis 單機版轉移到 10 個節點的 cluster 版本,然後錯誤率大幅下降:

Stripe’s rate limiters are built on top of Redis, and until recently, they ran on a single very hot instance of Redis. The server had followers in place for failover, but at any given time, one node was handling every operation.

We eventually solved it by migrating to a 10-node Redis Cluster.

另外也可以看出來,在轉移到 cluster 版本後有不少要注意的,像是因為 sharding 而需要調整平衡性。另外是 cluster 模式下寫入的 confirmation 跟一般預期的不太一樣,不過這對於 rate limit 的應用還好,可以接受某種程度的掉資料...