雲栖号資訊:【 點選檢視更多行業資訊】
在這裡您可以找到不同行業的第一手的上雲資訊,還在等什麼,快來!
一、背景
攜程自 2013 年開始使用 Redis,舊時期為 Memcached 和 Redis 混用狀态。由于 Redis 在處理性能,可儲存 key 的多樣化上有着顯著的優勢,2017 年開始,Memcached 全部下線,全公司開始大規模使用 Redis。Redis 執行個體數量也由剛開始的幾十個增長到幾萬個,資料量達到百 TB 規模。作為 Redis 的運維方,為保證 Redis 的高可用性,DBA 的壓力也随 Redis 使用規模的增大而增大,叢集的擴容,上下線,執行個體擴容都面臨着不小的挑戰。
攜程 Redis 并非采用原生的 cluster 或者第三方開源的 proxy,而是使用自主研發的 CRedis Client 元件,部署在所有的應用端。該方案的好處是,Redis 的使用者隻需要知道自己的 Redis 名稱,就可以通路自己的 Redis,而不需要關心 Redis 的實際部署情況。
這也意味着全部的運維操作都需要在 CRedis 中注冊并推送到所有的用戶端,為保障 Redis 的持續可用性,DBA 的所有運維操作都是以資料的安全性為第一準則,盡可能做到擴容遷移等操作透明化,保證使用者至上。

二、單機多執行個體時期
Redis 使用早期(2016 年以前),Redis 伺服器上線後,由 DBA 在實體伺服器上部署多個執行個體,然後這些執行個體在 CRedis 中注冊,提供給應用通路。資源優化和性能的平衡由 DBA 管理,主要是基于伺服器的記憶體、CPU、網絡帶寬等名額來手動調節,和 MySQL 的單機多執行個體類似。DBA 在叢集上下線和部署時需要自行在 pool 中尋找合适的機器,當然我們也總結出了一套比較合理的優化算法和方式來管理 Redis 的部署。
在 Redis 的使用爆發增長時期(2016-2018),我們上線了一套 Redis 自動化治理系統 RAT(Redis Administration tools)。Redis 的上下線和擴容從手工時代來到了自動化部署和自動擴容時期,Redis 運維管理難度,随着執行個體大規模增加而增加。
由于前期對 Redis 的申請和擴容沒有做太多限制,實體伺服器的使用率一直不太理想,維持在 40%+ 左右。加上頻繁擴容導緻的超大執行個體(20GB+),稍不注意在全量同步時就容易引起執行個體 OOM,影響業務。為了提高記憶體效率和降低手動操作風險,DBA 迫切需要一種更先進的部署治理系統來管理 Redis。
三、容器化時期
2018 年開始,随着容器化的流行以及 Kubernetes 成為容器編排的事實标準,我們也開始逐漸探索有狀态應用容器化。
Redis 的部署由 Kubernetes 根據設定的規則自動化排程部署,DBA 再也不需要操心資源的問題,操作效率提高了幾十倍。Redis 的上線和無狀态的應用一樣接入到了 PaaS 系統中,Redis 的配置設定也劃分了多個可用域(Region),每個 Region 劃分多個可用 Pool 滿足相關性強的 Redis 集中部署。
Redis 作為一種典型的有狀态應用,很多的落地經驗可以參考前面的文章《攜程 Redis 容器化實踐》。但在當時容器化的規模隻有幾千個,而目前已經增加了十倍多,還在不斷增長,對于如此大規模的執行個體數,治理政策的調整勢在必行。
3.1 二次排程
很多情況下,業務方在申請 Redis 時,并不特别清楚該 Redis 會用到多大,随着業務量的增長或調整,Redis 的使用量可能會遠超或遠小于原始的配置設定額度。對于遠超額度的,為避免 Key 剔除,以及由此帶來的主從切換,影響業務的持續可用性等問題,我們會在 Redis 的使用率(UsedMemory/MaxMemory)達到 90% 的時候進行自動擴容處理(修改 Redis 的 MaxMemory),也就是記憶體超分,但支援記憶體超分帶來的負面效果也很明顯:
1)Kubernetes 的 Request 會失去它原先占位作用,因為真實的用量無法感覺。
2)因為 Request 無法感覺,是以為了防止實際的主控端記憶體被打爆,我們必須限制主控端執行個體的個數。
3)限制執行個體個數是根據每個執行個體配置設定的平均期望記憶體來估算,實際配置設定中會導緻資源的使用率并不平衡。
而對于遠小于原始配置設定額度的,缺點也很明顯:
1)執行個體占用了大量的 Request 配額,而實際用的很小。
2)大量的配額無法釋放,導緻新的執行個體無法部署到某些很空的主控端上。
3)某些很空的主控端無法部署新執行個體,使用率低下。
由于 Kubernetes 對于這種有狀态應用支援的不夠完善,而我們的 Redis 叢集又有幾千台的規模,在處理這些問題時必須分而治之,各個擊破。
因為遷移執行個體需要遷移一組,一組一般是 2 個或更多執行個體,對于運維來說是個非常重的操作,但遷移執行個體可以修正 Request 配額,讓其适配 UsedMemory。而漂移隻需要遷移一個執行個體,是個相對輕量級的操作。對于 Request 和 UsedMemory 嚴重不比對的(一般是 2 倍以上或 1/3 以下的關系),我們通過遷移來修正。而對于 Request 和 UsedMemory 相差不是很大的,我們必須在外圍進行二次排程。
二次排程可以認為是主控端資源 Rebalance 的過程,而在二次排程之前,我們必須要厘清二次排程的目标:
1)對于一個标準的主控端,為了支援自動擴容,我們認為 Request 100%,記憶體使用率為 60%-65% 為最優狀态。
2)每個主控端上記憶體使用率盡可能地平均,也就說方差盡可能地小。
3)Node 可用記憶體小于 35%,禁止排程,大于 45%,開放排程。
對于第三點,在外圍有專門的 Job 來檢測 Node 的可用記憶體,來 cordon/uncordon 符合條件的 Node。
對于上面第一第二點的兩個目标,我們設計了支援 2 種模式的局部最優平衡算法:
1)預留制
由于 Redis 執行個體在使用過程中記憶體使用量不斷增長,且增長趨勢無序無規律,使得某些主控端上的記憶體可用率很低(如圖 2 所示主控端可用率約為 24%-26%)。是以,可以通過将記憶體不足的主控端上的執行個體漂移到閑置或記憶體充足的主控端上來緩解源主控端的記憶體壓力。
首先,通過選擇需要被二次排程的源主控端以及指定目标記憶體可用率(如圖 2 為 50%),預留制算法可将源主控端上需要被排程的執行個體漂移到閑置主控端上,或是調用已經實作的 bestnode 接口,自動為源主控端上需要被排程的執行個體選擇符合排程條件的目标主控端,且二次排程後目标主控端以及閑置主控端的記憶體可用率不低于指定的目标記憶體可用率。
bestnode 是已經實作的一種二次排程的政策,可為執行個體選擇相同 label、相同 zone 且可用記憶體、可配置設定記憶體及主控端可容納執行個體個數充足的最優目标主控端,進而保證執行個體可以成功地漂移到目标主控端上。
2)完全平衡制
由于叢集中主控端記憶體使用率的差距非常大(如圖 3 所示),為了使每個主控端上記憶體使用率盡可能平均,即方差盡可能小,可以通過将記憶體緊張的主控端上的執行個體漂移到記憶體充足的主控端上,進而縮小主控端記憶體使用率的差距。
如圖 3 所示,通過手動選擇需要平衡的主控端執行個體,完全平衡制算法将計算主控端群記憶體使用率的最小方差(圖 3 中主控端群記憶體使用率達到最小方差約為 61%),并在主控端群間做執行個體的排程。
在執行個體漂移前 Redis 叢集中還存在如圖 4 所示的情況。由于某些主控端上執行個體的 UsedMemory 很小,導緻主控端的記憶體可用率很高卻由于執行個體個數已滿無法再将執行個體漂移到主控端上,使得主控端的記憶體使用率不高。相反,也存在執行個體的 UsedMemory 很大導緻的主控端記憶體可用率低但還可将執行個體漂移到主控端上的情況。
對于這種情況,我們首先将記憶體可用率高的主控端上 UsedMemory 最小的幾個執行個體漂移到記憶體使用率低的主控端上,進而為主控端騰出執行個體個數配額,接着将記憶體可用率低的主控端上 UsedMemory 較大的幾個執行個體漂移過來,進而平均主控端的記憶體使用率。
使用者可配置二次排程的參數,如指定可漂移執行個體的 Max/Min UsedMemory,Rebalance 次數,最後生成一個 config 檔案。
預留制算法與完全平衡制算法在選擇源主控端上需要被排程的執行個體時都使用的是 First Fit Decreasing(FFD)算法,即首先計算達到目标記憶體可用率需從源主控端上釋放記憶體(ReleaseMemory)的大小,接着周遊由大到小排序後源主控端上執行個體的 RequestMemory 以及 UsedMemory,将符合條件(RequestMemory在先對主控端進行預處理後(如上圖 4),根據二次排程 config 檔案,綜合考慮黑白名單、執行個體優先級,并且排除不能被排程的執行個體類型(如 XPipe 以及多 slave 執行個體)後,即可确定最終需要被二次排程的執行個體名單。最後即可生成如圖 5 所示的二次排程方案。
Redis 主要瓶頸在記憶體,是以我們暫時也隻考慮記憶體。但這種二次排程的模式同樣可以應用于其他有狀态應用的場景,如 Mysql/Mongodb/Es 等,隻是考慮的次元更全面(Cpu/ 記憶體 / 磁盤)。
3.2 自動化漂移
有了上面的二次排程,我們可以手工或者自動生成二次排程的計劃或任務,在指定時間觸發,此外我們上線了容器自動化漂移系統,漂移操作支援下面幾種類型:
1)指定執行個體漂移到指定主控端。
2)主控端完全 down 掉,無法恢複,一鍵漂移。
3)主控端有故障需要維修,一鍵漂移。
4)二次排程計劃自動或手動漂移。
根據之前的描述,我們所有的運維操作需要在 CRedis 中注冊,我們也針對 Redis 執行個體在 CRedis 中的不同角色,在邏輯和實體層面進行了無縫銜接,在漂移過程中自動修改 CRedis 的通路政策,資料同步,Xpipe DR 系統自動化注冊(Xpipe 是攜程 Redis 跨 IDC 容災的方案),自動添加删除哨兵等。
3.3 Cilium
由于我們漂移過程中,整個 IP 是不變的,IP 不變的邏輯由 OVS 來保證,這樣好處是對用戶端和中間件透明。但随着攜程單個 IDC 内容器部署密度的越來越大,大二層網絡的交換機表項無法承受這麼多 IP 在整個 IDC 内可漂移。
Cilium 是下一代雲原生的網絡解決方案,之前有其他同僚的文章有所描述,這裡不再展開。我們将 Redis 容器跑在了 Cilium 上,漂移過程中 Redis 換主控端後 IP 會變,這樣會涉及多個系統的資料變更,如哨兵記錄了老 IP,目前執行個體卻變成新 IP,這時候正好配置設定一個老的 IP 給了新的執行個體,導緻複制關系錯亂,稍有不慎便會導緻生産事故。也對漂移流程的可靠性提出了更高的要求,我們細化每一步漂移流程,設計合适的狀态機,保證每一步的可重試和幂等性。
3.4 傲騰落地
大規模的 Redis 用量以及增長速度迫切需要我們調研成本效益更高的解決方案,這時候 Intel 傲騰技術進入了我們的視線。目前為止,傲騰主控端大約為整個 Redis 主控端的 10% 左右。
傲騰 SSD
率先被我們引入的是傲騰 SSD, 通過 2 塊 SSD 組合,可以提供作業系統約 700 多 G 的記憶體。
從實際效果上看(圖 7)傲騰 SSD 的平均延遲相比記憶體還是相對明顯,從 0.3ms 上升到了 0.9ms,與測試的結果吻合,但某些業務能接受這種延遲的上升,并且能節約 60% 成本,是以我們首先在攜程内部小範圍的部署了傲騰 SSD。
傲騰 AEP
盡管傲騰 SSD 可以符合我們的部分要求,但缺點還是比較多。
1)驅動支援不完善,基本所有的廠商需要對應的 RAID 卡驅動,并且每家還不太一樣,現實狀況是需要編譯多個核心版本來适配不同廠商的驅動。
2)裝機繁瑣,需要注冊碼,還要開關機多次,并且還有失敗的機率,是否能最終進入系統有點憑運氣。
3)700G+ 作為 Redis 主控端來說相對太大了,因為我們需要考慮 Redis 主控端萬一挂了恢複的時間。
從線上結果來看,傲騰 AEP 和純記憶體的耗時比較接近,業務的監控狀态如上圖。傲騰與普通實體記憶體實際運作差別已經非常小,可以滿足絕大部分業務場景。并且相對于傲騰 SSD,傲騰 AEP 還有以下的優點:
1)裝機友善,不需要注冊碼,也無需額外的驅動程式
2)可以選擇的規格比較多,可以友善組合 CPU/ 記憶體 / 傲騰 AEP 的配比
我們經過數量和大小的權衡,選擇的規格是 32C CPU+4 個 128G 的傲騰 AEP,傲騰 AEP 與記憶體配比是 1:4。單 GB 成本約為純記憶體的 50%。
四、混合雲時期
2019 年開始,随着集團業務的全球化,業務海外通路量的增加,Redis 出海的需求也不斷上升,由于 Redis 的快速響應要求,我們也需要在公有雲上部署 Redis 群集,以提供給當地的應用通路,減少延遲。
然而公有雲上無法提供裸金屬伺服器,實際提供的主控端都是虛拟機,出于容災方面的考慮,我們将 Redis 的主控端嚴格按 zone 打散,讓 master/slave 部署在不同的 zone,這樣即使一個 zone 全部 down 掉也完全不影響 Redis 的業務。此外對申請部署透明,對于使用者來說,隻需要選擇想要部署的 Region 即可将 Redis 部署到海外,與私有雲完全一緻的體驗,至此攜程的 Redis 走到了混合雲時期。
Redis On SSD
公有雲上的 Redis 價格非常昂貴,約為私有雲的 10 倍左右,并且私有雲還有類似傲騰這種方案來進一步降低成本,但 Redis 需要出海的規模巨大,而攜程大部分 Redis 需要通過内部的 Xpipe 系統同步到海外,是以迫切需要我們尋找一種廉價的方案來代替 Redis 跑在公有雲上。
我們調研一段時間,最終選擇開源的 kvrocks 作為二次開發的方案,自己開發實作支援 Redis 的 SYNC 和 PSYNC 協定,無縫對接公司的 Xpipe,來作為出海 Redis 的替代方案,實作方案和詳細的資料後續會有專門文章介紹。
這裡簡單說下結論:下圖為線上生産環境同一 Group 的 2 個 Redis/2 個 kvrocks 的通路平均延遲,表現較好的那兩條線是 kvrocks 執行個體,從線上結果來看,與 Redis 表現沒有什麼差距。而這種替代方案可以節約 60%-80% 的成本。
五、總結
Redis 作為有狀态應用,容器化和治理都需要很大的精力投入,而攜程 Redis 治理既不盲從社群,為了支援記憶體超分,也難以照搬公有雲廠商的相應的 Redis PaaS 服務,從實際業務需求出發,走出了一條既可行又現實的路。
作者介紹:
向晨,攜程資深資料庫工程師;布萊德,攜程技術專家;皓月,攜程技術教育訓練生。
【雲栖号線上課堂】每天都有産品技術專家分享!
課程位址:
https://yqh.aliyun.com/zhibo立即加入社群,與專家面對面,及時了解課程最新動态!
【雲栖号線上課堂 社群】
https://c.tb.cn/F3.Z8gvnK
原文釋出時間:2020-05-14
本文作者:向晨
本文來自:“
InfoQ”,了解相關資訊可以關注“
”