大規模排行榜系統實踐及挑戰

版權聲明:本文由唐聰原創文章,轉載請註明出處: 
文章原文連接:https://www.qcloud.com/community/article/154linux

來源:騰雲閣 https://www.qcloud.com/communitygit

 

排行榜知足了人的攀比、炫耀心理,幾乎每一個產品都會涉及。SNG增值產品部的QQ會員、QQ動漫、企鵝電競、遊戲賽事等大量業務都對排行榜有強烈需求,特別是企鵝電競等業務的發展壯大對咱們排行榜系統提出了更多要求和挑戰。在過去的一年中,排行榜系統從無到有,接入的業務從單一的QQ會員到企鵝電競動漫等20幾個各種業務,接入的排行榜數實現了從幾個到數萬的突破,單個排行榜用戶數最大9000萬, 排行榜存儲集羣活躍用戶量數億,而在這過程當中,排行榜系統也遇到了如下挑戰:github

  • 如何支持業務就近接入?低延時?web

  • 如何支撐數萬乃至幾十萬級排行榜自動化申請調度?redis

  • 如何下降機器成本?選擇合適存儲引擎?算法

  • 如何避免各業務資源搶佔,相互影響?sql

接下來的各小節會詳細討論目前咱們在實踐中是如何解決這些挑戰的。docker

一.排行榜系統基本架構

在討論咱們如何解決面對的挑戰以前,先簡單瞭解下排行榜系統基本架構、以及業務是如何接入、使用排行榜系統的。排行榜系統基本架構如圖三所示,當前的排行榜系統架構不是設計出來的,而是根據咱們業務場景、需求、發展等不斷演化,不斷優化而造成,其主要由如下幾個服務組成:api

  • 接入服務(無狀態,提供訪問修改排行榜數據的全部RPC接口給業務使用,如查詢名次、topN等)服務器

  • 存儲服務(有狀態,主備部署,排行榜數據存儲)

  • APIServer服務(提供申請排行榜、業務接入、排行榜配置信息、存儲機容量等接口)

  • 調度服務(從存儲機中篩選知足業務申請條件的存儲機,並擇優分配)

  • Agent(上報存儲機容量信息、存儲服務監控數據等)

  • ZooKeeper(排行榜路由數據存儲、存儲機容量數據存儲等,爲何咱們選擇zookeeper將在第三部分說明)

  • Mysql(業務接入信息、各排行榜配置、用戶量、存儲服務核心參數監控等存儲)

業務接入排行榜系統時,首先會爲每一個業務分配一個ID,其次須要申請排行榜ID,業務排行榜server經過l5調用排行榜系統的接入服務,接入服務每一個接口都包含業務ID、排行榜ID,接入服務經過業務ID、排行榜ID查詢zookeeper獲取該業務排行榜ID的存儲服務實例,最終經過存儲服務API操做排行榜數據,返回結果給業務Server。

上面提到的L5是什麼呢? L5(Load Balancer,5代指Level5,即99.999%的可用性)是一套兼具負載均衡和過載保護的容錯系統, 業務服務接入L5時,會分配一個標識(modid、cmdid),此標識映射若干業務服務器IP:PORT,業務機器須要部署L5 agent, l5最大的缺點是業務服務若要經過L5調用被調, 就必須修改代碼,每次網絡調用以前都須要經過L5 agent api獲取被調IP:PORT,調用結束以後上報調用延時、返回碼等。

二.如何支持業務就近接入?低延時?

因部門產品業務較多,服務部署區域也各異,有的業務部署在深圳地區、有的業務部署在上海地區。深圳、上海內網機房ping延時約30ms, 這麼高的延時是部分業務沒法容忍的,做爲平臺支撐方,咱們也但願提供的各接口平均延時應在5ms內,因此要儘可能避免跨城訪問。如何避免跨城訪問呢? 固然是各區域自治,早期因接入業務、排行榜數都較少,只有接入服務、存儲服務機器是按地區部署的,排行榜路由數據存儲只部署在深圳,排行榜路由也只會在沒命中localcache的狀況下才會跨城查詢深圳的路由數據存儲集羣,當時延時也能知足業務需求, 所以咱們並未徹底支持業務就近接入。可是後面隨着各種業務快速接入、排行榜的快速增長,特別是當localcache失效時,上海地區服務質量、延時波動較大,頻繁告警,因而咱們不得不推動各區域全面自治方案。

業務場景決定着咱們選擇什麼存儲方案來解決跨城訪問致使的高延時問題。

簡單分析下咱們的業務場景(業務核心鏈路請求):

  • 存儲的是什麼數據? 數據量多大? 路由、存儲節點容量數據,預計幾十萬條,key、value長度較小((固然也能夠採用表結構存儲)

  • 讀寫比例? 讀爲主,極少許寫(每分鐘幾個,申請排行榜時纔會添加路由配置)

  • CAP如何取捨? 儘可能保證各區域數據一致性,不丟失數據,高可用性(如其中一節點宕機不影響服務讀),在出現網絡分區時(如深圳、上海網絡中斷),集羣少數成員一方(上海地區),可以降級提供只讀模式。

經常使用的開源解決方案,以及各方案的優點、不足以下:

存儲 原理 優點 不足
Mysql Mysql binlog 穩定性、友好的sql接口、可根據業務場景須要配置複製模式 系統可用性不如etcd、zookeeper
etcd Raft 強一致性、高可用、 較成熟,kubernetes等大型項目應用普遍,可是目前還處在快速發展中,團隊內暫未在生產環境應用
zookeeper Zab 高可用、高性能讀、團隊已在生產環境應用多年、有配套的web配置系統 部署維護、C API使用等相比etcd不夠友好

結合以上各解決方案優缺點,再根據咱們的業務場景需求,咱們選擇了zookeeper做爲核心的路由、存儲節點容量數據存儲,而後咱們還面臨着深圳、上海各部署一套仍是隻部署一套的選擇。若深圳、上海各部署一套,咱們的方案是深圳集羣爲主寫,主寫成功後,write opration log(create/set)能夠寫入MQ,MQ需支持 at-least-once語義, 由消費者異步寫入上海集羣,由於create/set/del都是冪等性接口,對於網絡波動、中斷等消費者寫入上海集羣失敗的狀況下,能夠無限重試,確保兩集羣數據最終一致性。可是鑑於咱們業務場景極低的寫請求,以及當出現網絡分區時,zookeeper上海地區集羣能夠開啓read only mode, 同時咱們還有zk proxy cache,local cache等,咱們最終選擇了部署一套, 在生產環境中咱們部署了7臺zookeeper節點(分佈在深圳、上海4個IDC),經過zookeeper自己的zab算法實現深圳、上海地區數據同步,各區域實現徹底自治,總體部署方案見圖四,部署以後業務調用延時見圖五(低於2ms)。


三.如何支撐數萬乃至百萬級排行榜申請?

和區域自治的低延時部署方案相似, 當前的調度系統也是排行榜的申請流程的不斷優化衍變而來,排行榜的申請可分爲如下三個時期:

  • 石器時代: 系統剛上線時,幾個排行榜,手動配置。

  • 青銅時代: 幾十個排行榜,經過Web界面人工審批排行榜。

  • 鐵器時代: 數萬個排行榜,經過調度服務篩選、打分選擇最優的存儲機,自動化容量規劃,無需人工干預

如上所述,排行榜系統提供了兩種申請排行榜方法,一種是在web管理平臺提交申請單,一種是經過API Server提供的API實時申請排行榜,前者試用於排行榜數申請不頻繁的業務場景,後者適用於須要大量排行榜的業務場景。

那麼咱們又是如何設計實現調度服務的呢? 經過分析咱們的業務場景,業務在申請排行榜時通常須要填寫部署地區(深圳、上海)、預計用戶量、請求量、排行榜類型、是否容器部署、存儲引擎類型等條件參數,所以排行榜調度服務的核心職責就是從有效的存儲節點中篩選出知足業務申請條件的候選節點,並按某種策略對候選節點進行評分,選擇最優分數節點分配。

基於以上業務場景,咱們設計實現了調度服務,調度服務流程如圖六所示,由兩部分組成,篩選和打分,篩選模塊會根據配置運行一系列模塊,好比健康檢查模塊、標籤匹配模塊、容量檢查匹配模塊。健康檢查模塊會檢查全部候選節點的存活性,存活性經過zookeeper的臨時節點來判斷,當一臺機器掛掉時,臨時節點會自動刪除。標籤匹配模塊很是靈活,提供了強大的篩選能力,好比篩選部署地區、實體機部署仍是容器部署、存儲引擎類型等等。容量匹配模塊檢查候選節點是否容量滿、剩餘容量是否能支撐當前排行榜等,那麼一個若干G內存的容器能支撐多少排行榜呢?首先一個容器總容量能支撐多少用戶量,咱們能夠根據線上數據,計算出一個經驗值做爲上限,其次,容量規劃目前咱們採用兩種策略,一種是hard limit, 適合業務能較精準預測排行榜的用戶量,若業務指定這種資源分配,就會實際預分配指定的用戶量, 另一種是soft limit,業務沒法預測排行榜用戶量,調度服務會根據此業務歷史排行榜用戶量計算一個平均值,若平均值低於該業務配置的最低用戶量閥值,就預分配閥值,默認咱們採用這種策略。經過以上過濾模塊篩選後的候選節點就會進入下一輪的評分模塊,評分模塊支持多種調度算法,如最小資源調度(選擇內存資源剩餘最多的節點)、多權重混合調度(根據用戶申請參數,cpu、memory賦予不一樣的權重),排行榜最終被調度到節點將是評分最高的節點。調度數據存儲保存在zookeeper,各個存儲機都部署了agent, 定時上報存儲機容量信息到zookeeper集羣。

四.如何下降機器成本?選擇合適存儲引擎?

選擇什麼樣的存儲引擎來存儲排行榜數據? 咱們分析下排行榜的基本操做,查詢用戶名次/分數,更新用戶名次,查詢前若干名,刪除用戶等,有些業務須要用到所有這些接口,有些業務只須要用到其中部分接口(好比更新用戶分數、獲取前若干名)。咱們可選的存儲引擎有內存型存儲redis,磁盤型存儲leveldb,rocksdb等,redis提供了多種豐富的數據結構,其中的sorted sets(zset)能徹底知足咱們各接口需求, zset的核心數據結構是哈希表+跳躍表,其中哈希表保存各個用戶的分數,跳躍表維護各個分數對應的排名,增長用戶分數和查詢用戶排名的時間複雜度都是LOG(N),所以適合對性能要求較高的業務使用。而leveldb、rocksdb只提供了key、value型接口,爲何也能夠在部分業務場景(無需查詢用戶名次)也可使用呢? 圖八是leveldb架構,從圖中可知, leveldb是key都是有序存儲的,ssdb就是經過將分數經過必定規則編碼也做爲一個key寫入leveldb以支持redis zset數據結構,不過ssdb的查詢排名時間複雜度是O(N),在生產環境中僅適合不查詢用戶排名的業務使用,但能夠支持查詢整個排行榜前N名(N通常小於等於200)。

所以下降成本第一個方法就是根據各業務特色、類型按需選擇合適的存儲引擎! 不須要查詢名次的業務可使用ssdb(leveldb)磁盤性存儲引擎!

再看下降成本第二個方法,隨着排行榜數愈來愈多,redis排行榜存儲機也逐漸增多,存儲機器資源緊張,申請週期長,成本也較高,經過分析線上存量排行榜,發現部分業務具備明顯的週期性,如各種業務的活動、賽事排行榜等上線推廣時流量較大,活動結束時幾乎無流量訪問可是又不能清空整個排行榜,對於這類業務,排行榜系統提供了冷熱分離機制,將冷數據從redis內存中遷移到ssdb(leveldb)的硬盤中,從而釋放寶貴的內存資源,提升機器資源使用率,節省成本。

數據冷熱分離方案如圖九所示,經過agent採集現網全部排行榜流量,每日定時分析是否有排行榜知足遷移策略(如排行榜用戶數大於1萬,近兩週流量小於某閥值等),若知足策略,就生成遷移任務,記錄遷移的排行榜一系列元數據信息,寫入MQ。遷移服務輪詢MQ,若發現有遷移任務,就開始遷移工做,將全量排行榜數據備份到SSDB(leveldb)存儲節點,縮容或清空現網redis排行榜數據,釋放內存資源,圖十是冷數據、熱數據佔比分析,冷數據佔比高達17%。

五.如何避免各業務資源搶佔,相互影響?

愈來愈多的業務接入同時,各業務排行榜以前資源爭奪、相互影響成了一個不可忽視的問題,好比上海地區某業務排行榜申請了大量排行榜,觸發上海地區存儲機資源容量限制,全部業務申請上海地區的排行榜都失敗。爲了解決各業務之間相互影響,排行榜系統實現了業務資源配額、資源隔離方案。排行榜資源隔離容器方案如圖十一所示,容器daemon引擎使用了docker, 網絡模式使用了host模式,沒有性能損失,簡單可控,數據卷使用主機映射,容器重啓、宕機數據都不丟失,後續也將測試使用分佈式文件系統ceph. 鏡像存儲驅動選擇公司tlinux2操做系統自帶的aufs, aufs不適合對容器內的文件進行頻繁寫操做,首次寫須要copy up和多層branch檢索開銷, 而咱們的業務場景對容器鏡像文件讀寫操做都極少,也將最大程度避免存儲鏡像的潛在的內核BUG,各類鏡像存儲驅動優缺點對比見圖十二。registry使用公司內部的通用倉庫,docker daemon使用內部gaia團隊維護的docker 1.9.1,使用內部維護版本的好處是通過了公司大量其餘業務的應用,相比docker最新版本而言比較穩定,同時對於咱們遇到的一些BUG、需求功能,反饋給gaia團隊以後,他們也會較快修復、合併新版本中咱們須要的功能。好比咱們以前遇到的兩個docker daemon bug,在內部版本中都較快解決或避免了。
https://github.com/docker/docker/pull/22932
https://github.com/docker/containerd/pull/265


圖十二 存儲鏡像驅動優缺點(引用docker官方)

相比以前的混合部署,容器方案推出後,各業務接入時須要簡單估算此業務將來排行榜總用戶量數,預計須要的資源量,調度服務經過必定的策略從容器存儲節點中,篩選一個最優的節點,動態建立一個若干G的容器分配給此業務使用,後續此業務下全部排行榜將調度到該容器,若容器資源不夠,一方面能夠在線提升容器資源大小,另外一方面能夠新增容器,一業務對應多容器。

最後總結下Docker container資源隔離方案的優缺點。

優勢:

  • 各業務資源隔離,經過cgroup限制各業務使用的內存、CPU等資源,同時能夠根據業務最終數據量、請求量在線動態調整資源大小。

  • 簡化部署,一個image鏡像,任意一臺存儲機器,簡單快速起多個redis容器,充分利用多核機器的資源,各業務相互隔離。

  • 提升機器資源利用率。以前實體機一主一備模式,備機負載很低,容器化部署後,各容器主備可混合部署在一臺機器上,調度時只需保證主備容器不在同一臺機器。

缺點:

  • 全部容器進程共享同一個內核空間,若某容器觸發內核BUG,將致使內核崩潰,影響機器上全部容器進程,所以在生產環境實踐上應吸取業界的最佳實踐經驗,主備容器數據熱同步,定時備份數據,增強監控、容災能力。

  • 低版本的docker daemon 退出後將致使全部容器進程死亡,docke1.12版本增長了--live-restore參數,若指定此參數,docker daemon關閉後容器進程將繼續運行,https://github.com/docker/docker/pull/23213.

六.總結

在解決以上問題的過程當中,排行榜系統逐步實現了一套較高可用性、低延遲、低成本的排行榜解決方案(涵蓋自動接入、調度、容災、資源隔離、監控、擴縮容、數據冷熱分離等),後續將增強系統自愈能力的建設,好比對於寫流量不大的主備實例的全自動切換(對於寫流量較大的實例因redis是異步複製,master_repl_offset與slave offset存在幾十萬的差別),還有數據卷使用ceph-rbd, 即使出現主備容器都掛,經過系統監控探測到後,能夠動態建立新容器、掛載ceph-rbd數據卷,重建redis實例等,更重要的是要支持實現排行榜級別的在線遷移。

相關文章
相關標籤/搜索