很難大規模操作有狀態的分布式系統,redis 也不例外。托管數據庫通過承擔大部分繁重工作使生活變得更輕松。但是您仍然需要一個健全的架構并在服務器(Redis)和客戶端(應用程序)上應用最佳實踐。
本博客涵蓋了一系列與 Redis 相關的最佳實踐、提示和技巧,包括集群可擴展性、客戶端配置、集成、指標等。雖然我會不時引用Amazon MemoryDB和ElastiCache for Redis,但大多數(如果不是全部) ) 一般適用于 Redis 集群。
無論如何,這并不意味著是一個詳盡的清單。我只是選擇了十,因為它是一個不錯的、有益健康的數字!
讓我們深入了解一下您在擴展 Redis 集群方面有哪些選擇。
1. 可擴展性選項
您可以放大或縮小:
擴展(垂直)- 您可以增加單個節點/實例的容量,例如從Amazon EC2db.r6g.xlarge類型升級到db.r6g.2xlarge
Scaling Out (Horizontal) - 您可以向集群添加更多節點
向外擴展的需求可能是由幾個原因驅動的。
如果您需要處理讀取繁重的工作負載,您可以選擇添加更多副本節點。這適用于 Redis 集群設置(如MemoryDB)或非集群主副本模式,例如ElastiCache with cluster mode disabled的情況。
如果您想增加寫入容量,您會發現自己受到主副本模式的限制,應該選擇基于 Redis 集群的設置。您可以增加集群中的分片數量 - 這是因為只有主節點可以接受寫入,并且每個分片只能有一個主節點。
這還具有增加整體高可用性的額外好處。
圖 1:Redis(已禁用集群模式)和 Redis(已啟用集群模式)集群 – ElastiCache for Redis 文檔
2. 擴展集群后,最好使用這些副本!
大多數 Redis 集群客戶端(包括 )的默認行為redis-cli是將所有讀取重定向到主節點。如果您添加了只讀副本來擴展讀取流量,它們將處于空閑狀態!
您需要切換到READONLY模式以確保副本處理所有讀取請求,而不僅僅是被動參與者。確保正確配置您的 Redis 客戶端 - 這將因客戶端和編程語言而異。
例如,在Go Redis 客戶端中,您可以設置ReadOnly為true:
client := redis.NewClusterClient(
&redis.ClusterOptions{
Addrs: []string{clusterEndpoint},
ReadOnly: true,
//..other options
})
為了進一步優化,您還可以使用RouteByLatency或RouteRandomly,這兩個都自動開啟ReadOnly模式。
您可以參考JAVA 客戶端(例如 Lettuce)的工作原理
3. 使用只讀副本時要注意一致性特征
您的應用程序有可能從副本中讀取過時的數據——這就是最終一致性。由于主副本節點復制是異步的,因此您發送到主節點的寫入器可能尚未反映在只讀副本中。當您擁有大量只讀副本(尤其是跨多個可用區)時,可能會出現這種情況。如果這對您的用例來說是不可接受的,那么您也必須求助于使用主節點進行讀取。
MemoryDB 或 ElastiCache for Redis 中的ReplicationLag 指標可用于檢查副本在應用來自主節點的更改方面落后多長時間(以秒為單位)。
那么強一致性呢?
在這種情況下MemoryDB,來自主節點的讀取是強一致的。這是因為客戶端應用程序僅在寫入(到主節點)寫入持久多可用區事務日志后才會收到成功的寫入確認。
4. 請記住,您可以影響密鑰在 Redis 集群中的分布方式
Redis 沒有使用一致性哈希(像許多其他分布式數據庫一樣),而是使用哈希槽的概念。總共有16384槽,為集群中的每個主節點分配一定范圍的哈希槽,每個鍵屬于特定的哈希槽(從而分配給特定節點)。如果鍵屬于不同的哈希槽,則在 Redis 集群上執行的多鍵操作將無法進行。
但是,您并非完全受集群的支配!可以通過使用hashtags來影響鍵的位置。因此,您可以確保特定鍵具有相同的哈希槽。例如,如果您將客戶 ID 的訂單存儲42在HASHnamedcustomer:42:orders中,并將客戶資料信息存儲在 中customer:42:profile,您可以使用花括號{}來定義將被散列的特定子字符串。在這種情況下,我們的鍵是{customer:42}:orders和{customer:42}:profile-{customer:42}現在驅動哈希槽的放置。現在我們可以確信這兩個鍵都在同一個哈希槽中(因此是同一個節點)。
5. 您是否考慮過縮小(后退)?
您的應用程序很成功,它有很多用戶和流量。你擴展了集群,事情仍然很順利。驚人的!
但是,如果您需要縮減規模怎么辦?
在執行此操作之前,您需要注意一些事項:
每個節點上是否有足夠的可用內存?
這可以在非高峰時段進行嗎?
它將如何影響您的客戶端應用程序?
在此階段您可以監控哪些指標?(例如CPUUtilization,CurrConnections等等)
請參閱MemoryDb for Redis 文檔中的一些最佳實踐,以更好地規劃擴展。
6. 當事情出錯時......
面對現實吧,失敗是令人羨慕的。重要的是你是否為他們做好了準備。對于您的 Redis 集群,需要考慮以下幾點:
您是否測試過您的應用程序/服務在遇到故障時的行為?如果沒有,請做!借助 MemoryDB 和 ElastiCache for Redis,您可以利用故障轉移 API模擬主節點故障并觸發故障轉移。
你有副本節點嗎?如果您只有一個帶有單個主節點的分片,那么如果該節點發生故障,您肯定會停機。
你有多個分片嗎?如果您只有一個分片(主分片和副本分片),則在該分片的主節點故障的情況下,集群將無法接受任何寫入。
您的分片是否跨越多個可用區?如果您有跨多個 AZ 的分片,您將更好地準備應對 AZ 故障。
在所有情況下,MemoryDB確保在節點更換或故障轉移期間不會丟失數據
7. 無法連接Redis,求助!
Tl;DR:可能是網絡/安全配置
這是一直困擾人們的事情!使用MemoryDB和ElastiCache,您的Redis 節點位于 VPC 中。如果您將客戶端應用程序部署到AWS Lambda、EKS、ECS、App Runner等計算服務,則需要確保您擁有正確的配置 - 特別是在 VPC 和安全組方面。
這可能因您使用的計算平臺而異。例如,您如何配置 Lambda 函數以訪問 VPC 中的資源與 App Runner 的操作方式(通過VPC 連接器)甚至 EKS(盡管從概念上講,它們是相同的)略有不同。
8. Redis 6 自帶訪問控制列表 - 使用它們!
沒有理由不對 Redis 集群應用身份驗證(用戶名/密碼)和授權(基于 ACL 的權限)。MemoryDB符合 Redis 6 并支持 ACL。但是,為了符合較舊的 Redis 版本,它為每個帳戶配置一個默認用戶(使用用戶名default)和一個名為 的不可變 ACL open-access。如果您創建MemoryDB集群并將其與此 ACL 關聯:
客戶端無需身份驗證即可連接
客戶端可以在任何鍵上執行任何命令(也沒有權限或授權)
作為最佳實踐:
定義顯式 ACL
添加用戶(連同密碼),以及
根據您的安全要求配置訪問字符串。
您應該監控身份驗證失敗。例如,MemoryDB 中的AuthenticationFailures指標為您提供失敗的身份驗證嘗試總數 - 對此設置警報以檢測未經授權的訪問嘗試。
不要忘記周邊安全
如果您已經TLS在服務器上進行了配置,請不要忘記在您的客戶端中也使用它!例如,使用 Go Redis:
client := redis.NewClusterClient(
&redis.ClusterOptions{
Addrs: []string{clusterEndpoint},
TLSConfig: &tls.Config{MaxVersion: tls.VersionTLS12},
//..other options
})
不使用它可能會給你的錯誤不夠明顯(例如泛型i/o timeout)并使事情難以調試 - 這是你需要小心的事情。
9.有些事情你不能做
作為托管數據庫服務,MemoryDB或ElastiCache 限制對某些 Redis 命令的訪問。例如,您不能使用與CLUSTER相關的命令的子集,因為集群管理(規模、分片等)由服務本身承擔。
但是,在某些情況下,您可能會找到替代方案。以監控運行緩慢的查詢為例。雖然您無法latency-monitor-threshold使用CONFIG SET進行配置,但您可以slowlog-log-slower-than在參數組中設置設置,然后使用slowlog get它進行比較。
10.使用連接池
您的 Redis 服務器節點(即使是功能強大的節點)資源有限。其中之一是能夠支持一定數量的并發連接。大多數 Redis 客戶端都提供連接池作為有效管理與 Redis 服務器的連接的一種方式。重用連接不僅有利于您的 Redis 服務器,而且由于開銷減少,客戶端性能也得到了提高——這在大容量場景中至關重要。
ElastiCache 提供了一些您可以跟蹤的指標:
CurrConnections:客戶端連接數(不包括只讀副本)
NewConnections:特定時間段內服務器接受的連接總數。
11.(獎勵)使用適當的連接模式
這一點很明顯,但我還是要說出來,因為這是我目睹人們犯的最常見的“入門”錯誤之一。
您在客戶端應用程序中使用的連接模式取決于您是使用獨立的 Redis 設置還是 Redis 集群(很可能)。大多數 Redis 客戶端對它們進行了明確的區分。例如,如果您使用啟用了集群模式的Go Redis 客戶端MemoryDB),則Elasticache需要使用NewClusterClient(而不是NewClient):
redis.NewClusterClient(&redis.ClusterOptions{//....})
有趣的是,有一個更加靈活的 UniversalClient 選項(在撰寫本文時,這是在 Go Redis v9 中)
如果你沒有使用正確的連接模式,你會得到一個錯誤。但有時,根本原因會隱藏在一般錯誤消息的后面——因此您需要保持警惕。
結論
您所做的架構選擇最終將取決于您的特定需求。我鼓勵您瀏覽以下博客文章,以更深入地了解 MemoryDB 和 ElastiCache for Redis 的性能特征,以及它們如何影響設計解決方案的方式:
優化 Amazon ElastiCache 和 MemoryDB 的 Redis 客戶端性能
最佳實踐:Redis 客戶端和適用于 Redis 的 Amazon ElastiCache
測量 Amazon MemoryDB for Redis 的數據庫性能
隨意分享您的 Redis 提示、技巧和建議。在那之前,快樂的建筑!