ElastiCache Redis — Why items inconsistent between nodes?

Jerry’s Notes
What’s next?
Published in
8 min readAug 20, 2022

最近處理到一個相當有趣的案例,客戶在更新 Redis Engine 版本後,發現更新後,Redis 節點上數據筆數變少的問題,同時也觀察到內存使用量也是同時下降的狀況。

Q: Why item number CurrItems got decreased and memory utilization BytesUsedForCache also got decreased when updating Redis Engine version on ElastiCache Redis Cluster?

A: Redis replication will using full-sync with RDB which didn’t include EXPIRED keys. Thus, BytesUsedForCache/CurrItems decreased are normal situation.

這個一個原生 Redis cluster/replication group,在執行同步 Replication 所產生的正常行為及現象,以下是客戶常常會提及的問題場景。

Q: 為什麼更新 Redis Engine 版本後,新節點的數據筆數、及內存使用量下降了 xx%?

Q: 我新增加一個只讀副本從節點 (replica node),為什麼新的節點上的內存使用量比舊的主節點少了 xx%?

Q: 為什麼我換機型大小後,為什麼節點上的數據筆數、及內存使用量比之前少?

Q: 我備份 ElastiCache Redis、匯入 RDB 檔,然後在自建的 Redis 上載入後,為什麼數據筆數,跟我備份時 ElastiCache Redis 上的不同,少了很多?

Q: 我備份 ElastiCache Redis、匯入 RDB 檔,為什麼這個 RDB 檔這麼小,比我備份時 ElastiCache Redis 時,上面顯示的內存使用量很多很多?

使用者在 ElastiCache Redis 集群上,執行 ElastiCache Upgrade Engine for Redis (更新Engine版本的動作),並發現以下異常的行為,並懷疑有部份的數據沒有全部同步,而造成數據丟失的狀況

首先客戶觀察到 BytesUsedForCache內存使用量下降的現象,而第一個時間點是在 replica 節點先發生內存使用下降的狀況,然後在主從切換後(failover)後,舊的主節點(old primary)也隨之內存使用量有有5~10%的下降。

同時,也可以從 CurrItems 數據比數觀察到一樣的狀況。

從下面可以確認,該分片組是持續有 Reclaimed 的值,代表該節點上 Redis 內的數據是有配置過期時間(TTL),也有固定在清除過期鍵值,但被 Reclaimed 筆數,跟下降的 CurrItems 差距很大,再加上此次動作有觸發全同步作,所以確認並不是因為在短時間內,有大量鍵值被清除,而導致數據筆數 CurrItems 下降。

!!! 注意,因使用者在配置鍵值時,若有大量鍵值、配置在很短的時間區間時,若又在同一秒鐘內,去讀取大量已過期鍵值時,有機會造成大量 Reclaimed 的增加,此時有機會造成短時間操作延遲(operation latency increased)的增加,所以避免將大量的鍵值,配置相同的過期時間,也可以定期去主動刪除鍵值,來減少這類似操作的風險。

首先要先說明,ElastiCache Upgrade Engine for Redis (更新Engine版本) 這個動作,ElatiCache Redis 會先從只讀副本(replica nodes),來更新 Engine 版本,在更新 Engine 版本後,該節點會跟主節點求要數據同步(全同步 fullsync),當數據同步(replication)完成後,才會去接著執行主從切換(failover)的狀況,最後才會去更新舊的主節點上的Engine 版本。

而在 ElastiCache Redis 叢集模式(Cluster mode enable)下,多個分片組(shards)會同時執行。

詳細請參考 :

!!! 在以上動作,造成內存使用量下降的主要原因,是因為原生 Redis 在執行全同步數據時,只會同步 “非過期” 的鍵值,所以節點在升級 Engine 版本後,內存使用量及鍵值數量下降,是預期中的行為。

而 Redis 同步作業如何執行,請參考以下資訊:

Full Synchronization

A fork or forkless snapshot (RDB file) is taken on the master node. The snapshot is then sent to the read replica node.

A fork or forkless snapshot is taken, but data is not written to the RDB file on the file system, data is send to the socket file descriptor which connects to the read replica node.

The full synchronization process is essentially the same as the snapshot process.

!!! 所以當您更新 ElastiCache Redis 節點類型時,也會觀察到類型的狀況,另外若是加新的只讀副本從節點(New replica nodes),也的有類似的狀況發生。

另外,您可以也會好奇,為什麼 Redis 有過期的鍵值,去佔用內存,而沒有自動去清除呢? 這必須談到 Redis 過期鍵值的處理方式。

Redis 刪除過期的鍵值,有兩種方式:

1. Passive(被動被動刪除) : 當該鍵值被存取到時,若該鍵值已過期,則會先刪除該鍵值,而後回覆空值給前端應用。
2. Active(主動刪除) : 每隔 100 milliseconds 隨機挑選 20 個鍵值,然後刪除過期鍵值,若這20個鍵值中,有超過25%是過期的鍵值,則會重復這個動作,直到過期比率低於25%。 (每秒做10次,每次挑20個鍵值)

所以 Redis 內存中,會有一定比例的過期鍵值存在,詳細請參考以下文檔。

最後談到下面兩個問題。

Q: 我備份 ElastiCache Redis、匯入 RDB 檔,然後在自建的 Redis 上載入後,為什麼數據筆數,跟我備份時 ElastiCache Redis 上的不同,少了很多?

Q: 我備份 ElastiCache Redis、匯入 RDB 檔,為什麼這個 RDB 檔這麼小,比我備份時 ElastiCache Redis 時,上面顯示的內存使用量很多很多?

簡單來說,原生 Redis 在執行備份作業時,會從內存中將數據存至 RDB 檔中,而這個動作,也只有儲存 “非過期” 的鍵值,另外預設也會做壓縮(compressed)的動作,所以還原後,也的有類似的狀況。

詳細請參考以下文檔。

RDB (Redis Database)

■ The RDB persistence performs point-in-time snapshots of your dataset at specified intervals.
■ Dump all data in Redis to a file which is called RDB file.
■ ElastiCache sends the file to the S3. Later can restore a Redis cluster or Replication Group from the snapshot.
■ Snapshot does not include expired items.

--

--

Jerry’s Notes
What’s next?

An cloud support engineer focus on troubleshooting with customer reported issue ,and cloud solution architecture.