Redis - the first sight
Introduction
Redis a.k.a Remote Dictionary Server
Open source , in-memory data structure store 資料儲存方式,用在 used as database, cache and message broker. 提供strings, hashes, lists, sets, sorted sets with range queries, bitmaps, geospatial indexes, and streams 等資料型態. Redis 內建 replica, Lua scripting, LRU eviction, transactions 以及不同level的on-disk persistence並且透過Redis Sentinel提供高可用性以及用Redis Cluster 達到automatic partitioning.
Redis 可以做 atomic operations 像是 append string to value, 對hash value增加(或減少),push elements to list, 取交集、聯集...等。Redis 可以藉由dump dataset to disk 或appended commands to a disk-based log來保存資料。若只為了做cached則不必則不必開啟persistence.
科普 What is "atomic operations"?
In concurrent programing - program runs completely independently of any other processes.
In operating system kernel - Most computer hardware, compilers, libraries are provide different levels of atomic operations. 處理器在同一個記憶體位置讀寫做data transmission,可用atomic operation 來確保資料的來確保資料的正確性。
AWS 的ElastiCache 提供Redis and Memcached可以選擇,根據不同需求來採用。Memcached 功能簡便,Redis提供很多feature and function來操作key-value pairs.
兩者皆有
1. sub-millisecond latency 亞毫秒等級的低延遲(sub-millisecond 指的是比milliseconds 更精確的值)
2. 易開發
3. 資料可切割, data可儲存在不同的node上易於scale out when handle more data
4. 支援多種程式語言
Redis 有
1. 更多進階的資料型態/結構
2. 儲存snapshot
3. 有Replication 讓 Scale read 同時能保有HA
4. Transactions -可將一群指令做atomic operation 的
5. Pub/Sub 發布與訂閱消息
6. 撰寫Lua script
7. Geospatial support - 支援地理位置e.g.: GEOADD
Memcached 支援 Multithreaded architecture,由於它是支援multithread,所以在scale up (vertical)很容易,但就是但就是要更多的CPU core與RAM
Redis 是key-value的資料結構儲存,常用的指令如
SET, GET - 設定與取得某個value by key
INCR, DECR - 對某個Key加一/減一
HSET, HGET - H代表的是hashmap, 表示Value中可以存在多個field與他的值,如 HSET User:001 name "John", HSET User:001 height "180"
SADD, SCARD - S代表Set, value不重複。前者家加item 到set裡面,後者算set size
LPUSH, RPUSH, LSET, LRANGE - 資料結構為List, L是從左邊塞value, R是右邊,SET是針對index update value, LRANGE是可以印出index範圍內的value。若index不在範圍內會出錯誤訊息
(error) ERR index out of range
Replication
最基本的replication就是主從式架構 replication, 允許 replica Redis instance 完整複製master instance,無論發生任何事。並在每次與master有斷線時自動重連。
主要是以下三個機制
- 主從instance 連線正常時,master 會送更新的command給replica
- 若因為網路因素或reconnect timeout 斷開連線,會嘗試保留在斷開期間的command stream
- 若無法進行部分重新同步,replica則會要求full resynchronization。此行為會相對耗費資源,需先把master 做snapshot 送到 replica, 再把後面update 的command stream 打進去
By default, Redis 用asynchronous replication 這種低延遲且高效的方式。Replicas 用 asynchronous 確認與master上一段期間的資料異動,因此master若有更新,則不會等replica處理完。若有需要,是可開啟synchronous replication.
Synchronous v.s Asynchronous 差異在於前者是master, replica同時更新,write會等replica確實copy完master的data後才done。後者則可以在master已經寫入資料後,再on schedule update 或用batch 方式同步到replica中,設計得好也能做的接近real time copy。
為何在synchronous下,WAIT 可以降低寫入失敗而造成data lose的問題?
However with WAIT the probability of losing a write after a failure event is greatly reduced to certain hard to trigger failure modes.
這個command blocks 當前client動作,直到所有先前的write commands都成功被執行,並且被至少指定數量的replicas確認。也就是說必須要有n個replicas確認之前該write commands都執行成功,才會解開block. 但如果timeout 則不會再經過n個replicas確認,直接放行。
- wait 保證return時,會將所有在connection中的write commands送到replicas
- 如果是在MULTI transaction中其中一個command包含 WAIT, 則直接做完
- Timeout 為0則block forever
- WAIT是返回失敗和成功狀況下replicas數量,使用者要自己判斷
所以WAIT並不會使Redis有高一致性,但在Sentinel (哨兵) or Redis Cluster 的failover, 能夠提高數據安全性。
Redis 架構上因應效能做的策略如下
- Replication
- Asynchronous copy data to slave node
- Master可掛多個slave, slave 也可以掛slave
- slave node主要用來做scale out, 讀寫分離, etc.
- slave 連接master發送SYNC,master收到後產生緩衝區裡面所以執行的commands文件,並將snapshot發送給slave。slaves載入snapshot並接受執行緩衝區的指令。
- Sentinel
- 解決主重架構中,msater掛掉後沒有寫入的節點,做法是將其中一個slave 變成master,原先master若回覆後就當slave加入。
- 因為sentinel也為單點node,理想的狀態下sentinel也是要是要有cluster
- Sentinel 監控master and slave status, 做master, slave node故障轉移,service monitoring and notification
- Redis Cluster
- 相較於前面兩個更能高效能,在client端連結Redis中間層做個proxy。
Redis replication如何運作?
每個Redis master 有replication ID (隨機字串)。為了update replicas上新的變動,每個master 會採用一個偏移資料(offset),偏移資料隨著replication stream 增加而增加。Replication offset 即便沒有被連結也會增加。
Replication ID, offset
當replicas 連結master, 利用PSYNC 指令去發送舊的 master replication ID 跟 offset,假設master只有小變動,就能只要傳需要變動的部分。假設master不夠buffer空間放backlog,或 replica reference到已不存在的歷史紀錄,則會觸發完全重新同步,從頭開始。
Redis Pub/Sub
Pub/Sub 是發布(Publish)/訂閱(Subscribe)的功能,可以當作輕量級的message queue使用。Publish 會post message 到channel, Subscribe 則是可以訂閱一個至多個channel, 並用listen()的get()方法去收data欄位的資料。除此之外用psubscribe的方法還能用*做regular expression的方式去掃符合該Channel name的頻道一起訂閱。
Redis Stream
Streams 是在Redis 5.0 後新的資料型態,以更抽象化的方式建立log data structure。以log為例,append的方式加到原有log file中來update內容。 因為 Redis stream 是in memory 抽象模型,實現更強大的功能如:克服log 本身檔案過大的限制。
在stream出來之前,有把redis藉由Pub/Sub, List, ZSET等指令當作message queue ,但因為會遇到會遇到資料持久化, message 順序, message 重複append等問題。 Stream 的設計機制由此而生。
這裡所提到的log file, 並不是backend engineer 常接觸的 "application logging file" 這類human readable 的"journal" or "data logs",而是指為了程式化而建構的訊息資料。
Customer groups 一詞是從Kafka來的,即便概念都是允許group of client 可以從同一個stream(Topic)中consume message,但Redis 的定義不同。
Kafka的consumer group是一個抽象化consumers的set 集合,從topic 去consume資料,每個consumer會被分配到不同的topic partition進行讀取。當有consumer 加入或離開都會重新rebalance partition讓每個成員都能公平獲得partition的資源。
Redis的consumer group 是所有processes set都讀相同stream (like only one partition). Redis 保證每個event 只會被其中一個consumer接收。
redis stream vs kafka
Kafka, 基本資料結構叫Topic,是個只能按照時間依序append資料的結構。Topic 架構上可有多個 partition 方便做水平擴充,並且可以分散到不同的Kafka instances中。每筆紀錄在partition中有各自的序號 sequential id, 也稱為offsets, 可在partition中用來區別每筆紀錄。Consumer 照序號順處理,多個consumer可以獨立對每筆記錄for different purpose 做處理。
Redis stream 有以下不同
- 可定義最大資料長度 (kafka保留一定時間內的資料)
- 可用 Redis Hash當方式儲存keys and values ( kafka只能一個key對單一value)
- customer group 平行處理單一stream ( kafka則是有多個partition分派給customer group
留言
張貼留言