http://www.tuicool.com/articles/beYZfi7
引言
高可用(High Available)是線上生產環境所必不可少的重要條件,阿里云數據庫Redis版作為一款成熟穩定的數據庫產品,針對Redis的特性也支持高可用,本文將介紹云Redis是如何實現這一方案。
架構
目前云Redis有主從版和集群版兩種架構,本次主要針對主從版做HA的解析,集群版HA只在最后切換VIP指向時稍有不同,但均可保證高可用性。
下圖為主從版架構:

由圖可知,云Redis實例有主備兩個節點,平時只有Master提供服務,Slave只做熱備不提供訪問,Slave通過slaveof命令不斷從Master接收數據,保證Master宕機時云Redis仍可提供服務。
每一個云Redis實例都會分配一個VIP并與DNS綁定,VIP經過SLB后直接訪問Master不再有其他中間層,訪問Redis的鏈路為DNS-->VIP-->SLB-->REDIS(MASTER)。
HA模塊
HA作為一個獨立的系統模塊,遠程探測云Redis的健康狀況,當發生實例不可用時及時主備切換以保證服務質量。
健康檢查
健康檢查的邏輯很簡單,通過客戶端連接Redis并發送PING命令,如果返回PONG則說明Redis健康,其他情況則說明Redis異常,檢測邏輯用偽代碼來說明:
try: client = Redis(ip, port, connection_timeout, socket_timeout) //指定要連接Redis的ip:port(這里的ip:port即可以是VIP:VPORT也可以是Master或Slave的物理ip:port,HA會有多維度的探測),并設置超時時間 client.connect() //嘗試連接Redis,如果連接失敗或超時則會拋出異常 res = client.ping() //向Redis發送ping命令,結果為PONG說明Redis健康,返回OK;結果非PONG或超時則會拋出異常 if res == PONG: return OK except: //處理異常情況,若異常在預先定義的錯誤內,說明Redis真的異常,返回ERROR,HA會做下一步切換動作 if e.message in ERRORS: return ERROR else: return OK
需要HA真正做切換的異常情況有以下幾種:
/* 指定ip地址的機器不能找到(也就是說從當前機器不存在到指定ip路由),或者是該ip存在,但找不到指定的端口進行監聽,這時Redis所在主機可能宕機或是進程掛掉 */ "Connection refused" /* 服務器的并發連接數超過了其承載量,服務器會將其中一些連接主動Down掉 */ "Connection reset" /* 連接超時,目前設置為18秒 */ "connect timed out" /* 讀取數據超時,目前設置為2分鐘 */ "Read timed out" /* Redis正在加載數據 */ "LOADING Redis is loading the dataset in memory" /* 訪問的Redis是Slave */ "READONLY You can't write against a read only slave"
關于為何將讀超時設置為2分鐘這么久呢,這是我們在日常運維處理各種問題時,根據總結出來的經驗設置的一個相對合理的大小。
在一開始時讀超時的時間設置的和連接超時同樣為18秒,結果線上經常會有HA發生主備切換,這是因為Redis處理客戶端命令的線程只有一個,當在處理一些耗時操作比如FLUSHALL、KEYS等命令時,執行時間可達數十秒甚至幾分鐘,此時Redis處于"假死"狀態造成誤切換。經測試,清空64G的數據大約需要2分鐘的時間(目前主從版云Redis最大實例規格即為64G),故將讀超時設置為2分鐘。
單純調整超時時間并不是我們的最終方案,這里仍在改進,比如增加一個狀態監測端口,新開一個狀態線程來探測Redis活性等,歡迎大家集思廣益提供優質解決方案。
主備切換前準備工作
當健康檢查發現Redis出現不可用情況時就要準備進行主備切換,在主備切換真正執行前需要額外做一些工作:
通過VIP檢查Redis健康狀態 if VIP不健康: 檢查Slave狀態 if Slave健康: 再次檢查VIP狀態 if VIP健康: 無需主備切換 else: 執行主備切換 else: Slave不健康無法切換 else: 無需主備切換
在執行切換前要檢查Slave狀態以確保切換后實例是可服務的,否則即使切換也是無效的,比如兩臺主機都宕機這種極端情況。
同時對VPC類型的實例做了特殊處理,因為我們是沒有辦法訪問用戶自定義網絡的VIP的,這時需要把對VIP的健康檢查換成對Master的健康檢查。
執行主備切換
當Redis出現不可用且滿足切換條件時,真正開始執行主備切換動作。同時切換動作也支持主動的任務切換和被動的故障切換,兩者主要區別在是否需要Slave等待Master達到同步狀態,以下對主備切換做詳細說明:
1. 額外再次檢查一次Master狀態 if Master健康: if 故障切換: 無需切換,返回成功 else: a. 設置Master為readONLY只讀狀態 b. 通過info replication命令檢查主備同步狀態,也即master_repl_offset是否等于Slave的offset if 若超時仍未達到一致狀態: 重置Master為readwrite可讀寫狀態,并返回異常 else: 日志記錄此時Master無法連接 2. 切換VIP指向Slave if 切換失敗: 記錄日志并返回異常 3. 更新主備元信息 4. 向Slave發送slaveof no one命令,使其升級為新的Master 5. 嘗試向原Master發送slaveof命令,使其降級為新的Slave 此時原Master可能已經宕機,故不做失敗處理,僅記錄日志
通過以上方案,云數據庫Redis版SLA可以達到99.99%,僅在主從都發生宕機的極端情況無法服務。
結束
本文介紹了云數據Redis版HA方案,通過主從雙機熱備來保證服務高可用,健康檢查出現異常時及時進行主備切換,有效保障業務運行。