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