基於Redis的低成本高可用排行榜服務構建

IT技術精選文摘發表於2018-07-12

640?wx_fmt=gif

引言

業務運營活動中排行榜的使用很廣泛,因此在三年前組內已經將排行榜服務元件化。整個服務是基於Redis的zset資料結構實現的。

限於當時Redis的發展,這套服務在高可用性方面有所欠缺。近年來,公司內外團隊在實現高可用Redis方面做了很多工作,也有很多部門提供現成的接入方案。但由於我們的Redis是定製過的(修改過原始碼),一方面是現有方案不支援接入,開源專案往往也需要修改原始碼進行適配,即便如此也不完全如意;另一方面我們自己也希望在升級迭代上能靈活掌控,所以權衡後還是決定自行部署和運維。

架構方案

早期的架構

在此之前,排行榜服務部署情況如下圖所示。此時,無狀態的接入層通過內部協議對外提供服務,各業務無需關注Redis的連線和呼叫方式。但是當redis master停止服務時,需要人工將slave提升為master,併發布配置將接入層的指向切換到slave。此方案雖然能在大多數情況下做到資料安全,但是在出現故障後人工介入之前,服務處於不可用狀態。

640?wx_fmt=png

早期的架構

高可用架構

關於Redis的高可用部署方案,常見的有twemproxy、codis等,這些第三方方案往往需要引入額外元件,增加了運維成本。Redis本身提供了哨兵做HA,官方文件就哨兵的不同部署方案做了詳細介紹。本著低成本的原則,本文亦採用哨兵作高可用保障。改進的排行榜服務架構如下圖所示。

640?wx_fmt=png

高可用架構

整個服務由以下部分組成:

  • 排行榜CGI及業務模組:即服務使用方。排行榜CGI是一個通用化的供H5前端拉取排行榜資料的元件,業務無關。當業務有特殊邏輯時,亦可直接呼叫接入層介面。

  • 服務接入層: 1. 對業務提供慣用的內部協議介面,供業務呼叫 2. 對單個原生命令無法完成的操作,如插入元素並返回排名操作,使用pipelining或lua優化查詢,細節對業務透明 3. 對業務隱藏從哨兵處獲取redis例項地址、master例項切換後地址更新等複雜邏輯 4. 當讀併發量較大時,可通過增加redis slave實現讀操作水平擴容,增加的slave可通過哨兵自動發現,對業務透明 5. 提供黑名單、週期榜單等業務通用能力支援

  • Redis例項:即Redis主從例項對。可以有多個slave以實現讀操作水平擴容。

  • 哨兵叢集:提供高可用保證以及名服務。由3個哨兵組成,不與任何Redis例項混布。

  • 監控與告警:藉助公司內部指標監控平臺實現指標監控以及異常告警。下一節詳述。

監控告警與自動運維

Redis存活監控與master自動切換。由哨兵負責。當例項程式終止或不可達時,哨兵會檢測到該例項的sdownodown狀態(主觀下線與客觀下線),並在客觀下線後自動切換主例項。通過配置哨兵的notification-script指令碼,在狀態變化時哨兵可以呼叫運維介面傳送簡訊和郵件通知。而配置reconfig-script,能在新的master切換成功後觸發通知。

同時,接入層需要根據哨兵sentinel slaves命令返回的資料自動發現slave,並根據狀態識別slave是否可用。幾種情況下的master和slave可用性如下表所示。

情形

master狀態

slave狀態

master與slave正常

正常

正常。flagsslavemaster-link-statusok

master不可達

不可讀寫,等待恢復或切換

正常。flagsslavemaster-link-statusok

master切換後slave同步中

新master正常。

暫不可用。與新master成功建立連線前flags包含disconnected;與新master連線後完成同步前master-link-status不為ok

新slave上線同步中

正常

暫不可用。與新master成功建立連線前flags包含disconnected;與新master連線後完成同步前master-link-status不為ok

slave不可達

正常

不可讀。flags包含sdownodown

Redis指標監控。在Redis例項機器上部署監控指令碼,通過crontab定時取樣,資料上報到監控平臺,方便檢視實時和歷史資料。監控的指標項可包含CPU使用率、記憶體使用率、key數量等,根據業務需要確定。

哨兵間相互監控。同樣由哨兵負責。但需要注意的是,當某個哨兵不可達時,其他哨兵只會觸發sdown狀態變化,併傳送通知告警。

擴充套件能力

功能可擴充套件性。除了現有的黑名單、週期榜的能力,接入層還可以擴充套件豐富的業務功能,對業務遮蔽複雜的redis呼叫邏輯。比如,藉助LUA實現一個定時訊息佇列(參考此文)、介面流控等。

標準元件相容。接入層同時支援切換到其他符合Redis協議的元件,比如360 pika等。對於上層業務來說,不管是呼叫標準redis例項,還是其他元件,都沒有差別。

安裝包與配置管理

Redis安裝包與配置管理

業務的線上Redis使用相同的配置,統一使用內部服務包釋出系統管理Redis的安裝包和配置,以後臺server方式打包和部署。好處是:

  • 便於版本管理,能跟蹤每一次變更情況。

  • 跟蹤現網部署情況,可以看到部署了哪些例項,分別是哪個版本。當發現問題時可以方便評估受影響的範圍。

  • 能將部署工作流程化。安裝包內包含了監控指令碼和工具,並且會自動新增指標監控的crontab。

哨兵安裝包與配置管理

業務同樣使用內部包釋出系統管理哨兵安裝包。但在配置管理方面與redis包有些不同,因為哨兵的配置檔案,同時也是哨兵的狀態儲存,故每個哨兵的線上配置是有差異的。我們將哨兵配置項區分為以下幾類:

分類

內容

特徵

每例項獨有

哨兵ID

配置變更後要保持不變,否則其他哨兵會認為有新哨兵加入且原哨兵不可用,將影響到故障恢復時多數派選舉leader過程。哨兵之所以不清除不可用的哨兵狀態,是為了防止當網路故障導致腦裂時錯誤的選舉區域性leader。

公共靜態配置

埠、工作目錄、日誌檔案等

每個例項一樣,且日常運維中無需變更。

公共動態配置

監控的Redis例項及紀元資訊。

這部分配置隨著監控例項的增刪會變化。值得注意的是,如果某個哨兵的紀元資訊被重置,其可以從別的哨兵處恢復。

故可以採用如下策略管理哨兵配置:

  1. 靜態配置放在sentinel-base.conf檔案中,隨哨兵安裝包釋出。

  2. 指定配置檔案sentinel.conf啟動哨兵,首次部署啟動後會在配置sentinel.conf中生成哨兵唯一idsentinel myid,利用包部署服務等啟動後指令碼將其備份到myid.conf中。指令碼如下:cd $install_path/conf grep -E '^sentinel myid' sentinel.conf > myid.conf

  3. 最後利用配置系統下發例項監控配置檔案sentinel.conf,在配置檔案開頭用include方式包含sentinel-base.confmyid.conf,且例項監控配置不需要包括epoch資訊。這樣,就能在每次下發新的配置後,保留哨兵ID和每個被監控例項的epoch資訊了。_不過需要注意的是,相比起使用配置中心動態儲存配置的方式,當線上故障導致master變更後,需要手動修改配置。_include "/usr/local/services/redis_sentinel_qzmall-1.0/conf/sentinel-base.conf" include "/usr/local/services/redis_sentinel_qzmall-1.0/conf/myid.conf"

# 例項1
sentinel monitor my_redis 100.66.82.X 6479 2
sentinel down-after-milliseconds my_redis 10000
sentinel auth-pass my_redis mypasswd
sentinel parallel-syncs my_redis 1
sentinel notification-script my_redis /usr/local/services/redis_sentinel_qzmall-1.0/bin/notification-script.sh
sentinel client-reconfig-script my_redis /usr/local/services/redis_sentinel_qzmall-1.0/bin/reconfig-script.sh

結語

與大多數公共組建一樣,本文的Redis部署方案也由接入層、哨兵(名服務)、Redis例項(核心服務)、監控服務等部分組成。除哨兵與Redis是官方開源元件外,其他部分均選擇公司已有技術和運維平臺完成。方案整體既能滿足日常業務需求,也能滿足日常運維與監控要求,在可用性與維護成本上取得了一個平衡。

相關文章