【作者】
許金柱,攜程資深DBA,專注於分散式資料庫研究及運維。
臺楓,攜程高階DBA,主要負責MySQL和OceanBase的運維。
【前言】
讀寫分離,是一種將資料庫的查詢操作和寫入操作分離的方案,目的是為了降低讀寫操作的相互影響並提升資源利用率。在攜程,讀寫分離的應用場景非常普及,只讀的業務場景主要包括線上業務的讀請求、快取的拉取,大資料ETL取數等。
OceanBase 資料庫天然支援讀寫分離的功能,即通過 OBProxy 代理服務和OBServer的配置修改即可實現業務的讀寫分離策略;然而OceanBase 讀寫分離方案存在與業務耦合度過高、匹配不夠靈活等問題。因此,我們在 OceanBase已有的讀寫分離方案下繼續探索並優化更符合當前業務場景的解決方案。
一、OceanBase原生的讀寫分離策略
OceanBase資料庫在讀取資料時,提供了兩種一致性級別:強一致性和弱一致性。
強一致性指的是讀取最新資料,請求路由給主副本;
弱一致性不要求讀取最新資料,請求優先路由給備副本。
基於此,通過應用側為執行的sql新增sql hint來顯性開啟弱一致性讀就可以實現基於註釋的讀寫分離,同時也衍生出瞭如下三種常用的讀寫分離策略:
策略一、備優先讀
通過修改obproxy的路由策略為follower_first,並將業務讀流量指定到該obproxy從而保證讀請求優先訪問follower副本。
優點: 配置相對簡單,只修改obproxy的配置,無需修改observer的配置;讀流量均攤到全部follower副本上。
缺點: 讀請求可能存在跨zone訪問;在不調整副本leader的情況下,同zone或同server下不同副本的leader和follower可能共存,不能完全實現zone級別或者server級別的讀寫隔離。
高可用: 當兩個follower副本中的一個當機時,配置讀寫分離的obproxy將優先路由到另一個follower副本。
策略二、LDC(Logical Data Center)只讀型副本
新增一個只讀副本,為其新增idc標籤,並將obproxy的引數proxy_idc_name指向該idc。指定讀流量訪問該obproxy,通過LDC配置僅訪問只讀副本。
優點: 讀寫完全隔離,讀擴充套件性好。
缺點: 只讀型副本只同步資料,不參與分散式選舉,需要額外增加一個副本。對讀請求不大的場景存在資源浪費。
高可用: 當只讀副本當機時,配置讀寫分離的obproxy將自動把流量切到其他follower副本上。
適用場景: 業務的讀請求遠大於寫請求,且大部分讀請求對實時性要求不高或者有大量的AP分析場景。
策略三、LDC(Logical Data Center)全功能型副本
將一個全功能型副本新增idc標籤,驅逐該副本上的leader,並將obproxy的引數proxy_idc_name指向該idc。指定讀流量訪問該obproxy,通過LDC配置僅訪問該副本,完全分離讀寫流量
優點: 讀寫完全隔離,且相對於策略二不需要額外資源
缺點: leader分佈集中在兩個zone中,有可能會降低寫入效能
高可用性: 當指定idc側的follower副本當機時,配置讀寫分離的obproxy將自動路由到其他follower副本上。
適用場景: 讀寫比較均衡,存在少量AP場景
在滿足讀寫分離需求的同時,我們也關心在使用這些策略時的高可用性:
當只讀節點當機時,配置讀寫分離的OBproxy將自動修改路由,優先將讀流量路由到其他follower副本上。在使用策略二或者策略三時,每一個partition只有單個的readonly或者follower副本承擔讀壓力,因此切換到新的follower副本上的壓力是可以負擔的。
當配置讀寫分離的OBproxy出現問題時,由於obproxy是一組無狀態的服務,因此只需要依賴資料庫訪問中介軟體的判活來修改應用訪問obproxy的入口即可實現高可用。
二、攜程針對OceanBase在讀寫分離場景的探索
上面三種策略,在不同場景下各有優劣,也都能達成讀寫分離的效果,但相較於前兩種策略,我們更傾向於使用策略三。攜程的業務場景中,大部分資料庫的讀寫相對均衡,同時包含少量的etl取數、BI查詢等場景,與策略三的適用場景更貼合,且成本相對較低。
同時,我們也關注到oceanbase現有的讀寫分離策略中存在一個共性問題:應用側必須為sql新增弱一致性讀的sql hint,否則即使在obproxy做了相應配置,仍然不能達到讀寫分離的效果,所有讀寫壓力將集中在leader副本上。這涉及到使用者的程式碼改造且使讀寫分離策略與應用的耦合度高。因此,我們需要在已有方案的基礎上,根據當前業務場景探索並實踐出一個靈活的、與應用耦合度低的讀寫分離策略。
攜程目前已接入OceanBase近百套叢集,租戶約140個,同時越來越多基於MySQL資料庫的業務計劃遷移至OceanBase 資料庫。對於讀寫分離場景,遷移OceanBase成本較大。
針對需要保證OceanBase資料庫適配當前讀寫分離場景的需求,我們首先梳理了攜程業務目前讀寫分離的主要適用場景:
- ETL取數:Zeus定時作業,需要將線上訂單相關資料同步至Hive或ES
- BI查詢 Offline報表,為業務部門提供分析資料
- MySQL業務中已存在的讀寫分離場景(如快取拉取): 讀請求遠大於寫請求的產品庫場景,要求在延遲閾值內,將讀請求路由到只讀節點
我們看到攜程現有的讀寫分離場景包含OLTP和OLAP,並且db涉及的業務線可能比較複雜很難簡單分辨。
同時,讀寫分離改造涉及到增加sql hint /*+READ_CONSISTENCY(WEAK) */ 的問題 。sql hint在傳統的關係型資料庫中是一種通過註釋的方式改寫sql執行計劃的設計,而在OceanBase中它同樣有類似功能,並且提供了sql選擇副本訪問策略的能力。為了使弱一致性讀生效,需要對有讀寫分離需求應用中的sql做如下改造:
- Mysql原版sql
SELECT * FROM test
- Oceanbase改造讀寫分離的sql
SELECT /*+READ_CONSISTENCY(WEAK) */ * FROM test
綜上,在攜程的業務上線或業務遷移過程中,容易遇到以下問題:
- 現有業務遷移過程不透明,涉及業務層面的程式碼改造。
- 程式碼和讀寫分離策略耦合,造成技術債。
- DBA需要大量重新稽核查詢語句和業務行為,給出改造評估建議。
針對這些痛點,我們希望可以不使用sql hint,直接指定這些sql進行弱一致性讀來達到讀寫分離的目的。我們開始調研能否在OceanBase程式碼層尋求解決方案。通過對原始碼研究,我們嘗試在OBProxy元件上進行改造,最終實現不涉及使用者程式碼改造前提下的自動開啟弱一致性讀功能。程式碼的改造包含以下兩個方面:
- 功能1、自動為訪問本OBProxy的所有連線開啟弱一致性讀策略
- 功能2、自動為訪問本OBProxy的指定帳號(只讀賬號)開啟弱一致性讀策略
我們通過新增兩個引數enable_weak_read和weak_read_user_list在建連時進行判斷來分別實現上述兩個功能。enable_weak_read引數開啟時,將為訪問該OBProxy的所有連線開啟弱一致性讀;weak_read_user_list引數則針對賬號維度來指定部分賬號進行弱一致性讀。
以上弱一致性讀策略均基於會話級別開啟,通過配置LDC和read(slave)域名,進行讀、寫隔離,分擔主庫壓力,自動實現讀寫分離策略,不需要人工干預。
三、攜程針對 OceanBase 讀寫分離場景的實踐和測試
對於obproxy進行改造後,為了驗證其功能性,我們將其與LDC(Logical Data Center)全功能型副本讀寫分離策略相結合,進行了如下實驗。
場景一:
leader副本集中在zone1,obproxy指定賬號開啟弱一致性讀並且繫結idc2(zone2+zone3)
實驗結果:zone1的流量消失,流量被zone2和zone3分攤
場景二:
Leader副本集中在zone1和zone3,obproxy開啟對所有連線開啟弱一致性讀,並繫結idc2(zone2)
實驗結果:zone1和zone3的流量消失,流量全部由zone2承擔
四、攜程選擇的 OceanBase 讀寫分離場景
在攜程現有的業務讀寫分離場景中,我們往往通過區分業務的賬號來識別業務的行為,因此我們將obproxy上設定針對部分賬號開啟弱一致性讀並將其中一個zone和proxy繫結來將這部分請求路由到指定zone上實現讀寫分離。
優點:
1、同一個叢集的obproxy配置統一(不開啟弱一致性讀時LDC路由不生效),便於obproxy的橫向擴充套件和快速切換應用流量的指向。
2、按照賬號維度配置靈活度高,在部分極端場景方便人工介入。
五、總結
我們根據現有oceanbase的讀寫分離方案通過優化obproxy原始碼,新增enable_weak_read和weak_read_user_list兩個功能,在obproxy上直接實現讀寫流量的分離,解決了mysql遷移oceanbase過程不透明、使用者程式碼與原讀寫分離方案耦合度高等痛點。為推動分散式資料庫oceanbase適配攜程當前業務場景,更好地在攜程落地,走出紮實的一步。