摘要:目前市面上已經(jīng)有OneProxy、TDSQL、MyCat、360Atlas等出色的數(shù)據(jù)庫(kù)中間件,對(duì)于如何選型,不同公司會(huì)有不同的考慮,當(dāng)然也有公司會(huì)選擇自研,網(wǎng)易電商樂(lè)得在實(shí)際生產(chǎn)中就根據(jù)需要研發(fā)了自己的中間件Cetus,并于不久前開(kāi)源。...
電商系統(tǒng)中,隨著業(yè)務(wù)量的增大,讀寫(xiě) QPS 越來(lái)越高,單節(jié)點(diǎn) MySQL 實(shí)例壓力越來(lái)越大,單純的對(duì)服務(wù)器硬件升級(jí)已經(jīng)無(wú)法滿(mǎn)足生產(chǎn)環(huán)境的需要,對(duì)數(shù)據(jù)分片增加多個(gè)節(jié)點(diǎn),降低單節(jié)點(diǎn) MySQL 實(shí)例的壓力成了必然選擇。傳統(tǒng)的分片是通過(guò) DAO 層進(jìn)行的,但是 DAO 層對(duì)數(shù)據(jù)分片存在諸多問(wèn)題:
從業(yè)務(wù)角度看,配置修改需要重啟服務(wù),代價(jià)巨大;需要對(duì)分片結(jié)果集進(jìn)行處理,業(yè)務(wù)邏輯愈加復(fù)雜;功能相對(duì)簡(jiǎn)單。
從數(shù)據(jù)庫(kù)運(yùn)維角度看,配置管理的統(tǒng)一化難度較大;DB的升級(jí)、遷移等操作復(fù)雜。
因此 MySQL 數(shù)據(jù)庫(kù)中間件應(yīng)運(yùn)而生,解決了上述 DAO 層的諸多問(wèn)題。MySQL 數(shù)據(jù)庫(kù)中間件為業(yè)務(wù)提供了統(tǒng)一的入口、對(duì)業(yè)務(wù)透明,提供了讀寫(xiě)分離、分片、豐富的路由策略,以及其它較為實(shí)用的統(tǒng)計(jì)、管理、鑒權(quán)等功能。
目前市面上已經(jīng)有 OneProxy、TDSQL、MyCat、360 Atlas 等出色的數(shù)據(jù)庫(kù)中間件,對(duì)于如何選型,不同公司會(huì)有不同的考慮,當(dāng)然也有公司會(huì)選擇自研,網(wǎng)易電商樂(lè)得在實(shí)際生產(chǎn)中就根據(jù)需要研發(fā)了自己的中間件 Cetus,并于不久前開(kāi)源。
項(xiàng)目地址:
GitHub
碼云
Cetus 主打穩(wěn)定、高性能和對(duì)開(kāi)發(fā)友好,并以 OneProxy 等出色中間件為追趕目標(biāo),那它的具體設(shè)計(jì)思路與能力如何?開(kāi)源中國(guó)采訪了 Cetus 負(fù)責(zé)人@王斌,請(qǐng)他從項(xiàng)目背景、設(shè)計(jì)思路、研發(fā)經(jīng)驗(yàn)與未來(lái)計(jì)劃等幾個(gè)方面為讀者全面解讀 Cetus。本文由采訪整理而成。
嘉賓介紹
王斌,網(wǎng)易高級(jí)技術(shù)專(zhuān)家,愛(ài)好開(kāi)源,tcpcopy 和 Cetus 主要開(kāi)發(fā)人員之一,希望為中國(guó)開(kāi)源做點(diǎn)貢獻(xiàn),目前主要負(fù)責(zé) Cetus 項(xiàng)目,關(guān)注領(lǐng)域包括分布式數(shù)據(jù)庫(kù)、網(wǎng)絡(luò)與機(jī)器學(xué)習(xí)。

項(xiàng)目背景
樂(lè)得作為網(wǎng)易的電商系統(tǒng),近年來(lái)業(yè)務(wù)不斷發(fā)展,隨之而來(lái)的是數(shù)據(jù)庫(kù)數(shù)據(jù)量和訪問(wèn)量的不斷變大。當(dāng)數(shù)據(jù)量達(dá)到一定量級(jí),尤其是寫(xiě)請(qǐng)求過(guò)于頻繁時(shí),傳統(tǒng) MySQL 架構(gòu)很難支持樂(lè)得的大業(yè)務(wù),因此我們考慮用水平切分的方式進(jìn)行優(yōu)化,以降低單個(gè)庫(kù)、單個(gè)表的壓力。
已有的開(kāi)源分布式 MySQL 中間件具有不穩(wěn)定、對(duì)開(kāi)發(fā)不友好等問(wèn)題,很難直接采用,于是我們決定自主開(kāi)發(fā)一款分布式事務(wù)功能的 MySQL 中間件,我們有幾個(gè)目標(biāo)想要達(dá)到,包括高可用、高性能、讀寫(xiě)分離、分庫(kù)等。自己開(kāi)發(fā)有個(gè)好處就是自研可控,可以按照實(shí)際需求添加新功能,并且可以及時(shí)修復(fù) bug。
這一次將 Cetus 開(kāi)源也是想跟同行一起將它打造成一款出色的 MySQL 中間件,把 MySQL 后端集群整合成一個(gè)強(qiáng)有力的分布式數(shù)據(jù)庫(kù)。
讓 MySQL 更加強(qiáng)大
先介紹一下 Cetus 這個(gè)名字的意思,Cetus 這個(gè)英文翻譯成中文是“鯨魚(yú)座”,大家知道 MySQL 官方 logo 是海豚,鯨魚(yú)和海豚同屬于一個(gè)類(lèi)別,而鯨魚(yú)體型更大點(diǎn),把這個(gè)項(xiàng)目命名為 Cetus,一方面是想讓 MySQL 更加強(qiáng)大的意思,另一方面鯨魚(yú)座代表了我們有著胸懷宇宙的情懷,想把 Cetus 做得更好、更長(zhǎng)久。
Cetus 專(zhuān)注于性能、穩(wěn)定和分布式事務(wù),目標(biāo)是做一款可以媲美 OneProxy 和 TDSQL 等商業(yè)軟件的中間件。
下邊拿 Cetus 和一些知名的數(shù)據(jù)庫(kù)中間件或者NewSQL一起做個(gè)小分析:
OneProxy 是商業(yè)軟件,在穩(wěn)定性和性能方面遠(yuǎn)勝其它開(kāi)源中間件,它一直是我們追趕的對(duì)象。
TiDB 代表了 NewSQL,是為大數(shù)據(jù)設(shè)計(jì)的,但由于成本較高,在可以使用 MySQL 的地方不建議使用 TiDB。
TDSQL 是騰訊開(kāi)發(fā)的數(shù)據(jù)庫(kù)中間件,為騰訊云服務(wù),它在 MySQL XA 分布式事務(wù)方面進(jìn)行了很多探索,為我們的分布式事務(wù)處理提供了很多思路。
MyCat 功能較為復(fù)雜,細(xì)節(jié)方面還待改善(如算法沒(méi)有優(yōu)化、存在很多使用上的坑),用戶(hù)的抱怨比較多,與優(yōu)秀的數(shù)據(jù)庫(kù)中間件差距較大。
至于360 Atlas,它是一個(gè)長(zhǎng)期沒(méi)有更新的中間件,設(shè)計(jì)、穩(wěn)定和性能不佳,導(dǎo)致了很多用戶(hù)放棄使用。
……
了解到其它開(kāi)源和商業(yè)數(shù)據(jù)庫(kù)中間件的設(shè)計(jì)思路和存在的問(wèn)題,我們?cè)?Cetus 中大量借鑒和改進(jìn),這成了 Cetus 的優(yōu)勢(shì)。相比其它開(kāi)源數(shù)據(jù)庫(kù)中間件,Cetus 會(huì)更加貼近用戶(hù),兼顧開(kāi)發(fā)和整體效率,同時(shí)規(guī)避了影響數(shù)據(jù)庫(kù)中間件穩(wěn)定和性能的坑。主要特點(diǎn)有:
自主開(kāi)發(fā)的解析器,無(wú)需依賴(lài)第三方解析器,更新可控
異步處理,無(wú)任何阻塞,類(lèi)似 Nginx
并行處理,對(duì)多個(gè)后端并行訪問(wèn),減少延遲
tcp stream 處理,tcp stream 可以分解大響應(yīng)處理過(guò)程,從而可以公平處理各個(gè)外部事件,同時(shí)也解決了內(nèi)存炸裂問(wèn)題
分布式事務(wù)支持
對(duì)開(kāi)發(fā)無(wú)感知,開(kāi)發(fā)無(wú)需去了解這個(gè)事務(wù)是不是分布式事務(wù),像MyCat、DRDS 等中間件需要用戶(hù)顯式去指定這個(gè)事務(wù)是不是分布式事務(wù),這對(duì)開(kāi)發(fā)人員不是很友好
分布式事務(wù)深度優(yōu)化,繼承了騰訊 TDSQL 的不少優(yōu)良特點(diǎn)
緊跟 MySQL 趨勢(shì)
在重置 MySQL 連接方面,MySQL 5.7 開(kāi)始支持 reset conn,而 Cetus 已經(jīng)采用了 reset conn 代替 change user,以降低 MySQL 的 CPU 開(kāi)銷(xiāo)
支持 MySQL Group Replication,集群產(chǎn)生新的寫(xiě)節(jié)點(diǎn),Cetus 會(huì)及時(shí)更新寫(xiě)節(jié)點(diǎn)信息,實(shí)現(xiàn)服務(wù)高可用
利用GTID tracking,自動(dòng)實(shí)現(xiàn)一致性讀(正在開(kāi)發(fā)中)
設(shè)計(jì)思路與技術(shù)細(xì)節(jié)
Cetus 位于應(yīng)用程序與 MySQL 數(shù)據(jù)庫(kù)之間,作為前端應(yīng)用與數(shù)據(jù)庫(kù)的通訊。其中,前端應(yīng)用連接 LVS 節(jié)點(diǎn),LVS 節(jié)點(diǎn)映射端口到多個(gè) Cetus 服務(wù),后者通過(guò)自身的連接池連接到后端的數(shù)據(jù)庫(kù)。
整體網(wǎng)絡(luò)架構(gòu)如下圖所示:

Cetus 主要的功能模塊包括以下五個(gè)部分:
讀寫(xiě)分離
分庫(kù)
SQL 解析
連接池
管理功能
各個(gè)功能模塊間的交互關(guān)系如下:

其中,SQL 解析模塊為后續(xù)讀寫(xiě)分離和數(shù)據(jù)分片等功能解析出 SQL 類(lèi)型、表名和查詢(xún)條件等關(guān)鍵信息;連接池模塊是自維護(hù)連接池,支持 Cetus 根據(jù)需求查詢(xún)和檢測(cè)后端,維護(hù)連接數(shù),具有高效連接共享性、事務(wù)與 Prepare 的前后端綁定功能和熱點(diǎn)連接重用與連接等待機(jī)制;管理功能模塊通過(guò)用戶(hù)在管理界面輸入,獨(dú)立認(rèn)證并轉(zhuǎn)到下一狀態(tài),給用戶(hù)回復(fù)狀態(tài)查詢(xún)結(jié)果或調(diào)整參數(shù)。
Cetus 的整體工作流程:
Cetus 讀取啟動(dòng)配置文件和其他配置并啟動(dòng),監(jiān)聽(tīng)客戶(hù)端請(qǐng)求;
收到客戶(hù)端新建連接請(qǐng)求后,Cetus 經(jīng)過(guò)用戶(hù)鑒權(quán)和連接池判斷連接數(shù)是否達(dá)到上限,確定是否新建連接;
連接建立和認(rèn)證通過(guò)后,Cetus 接收客戶(hù)端發(fā)送來(lái)的 SQL 語(yǔ)句,并進(jìn)行詞法和語(yǔ)義分析,對(duì) SQL 語(yǔ)句進(jìn)行解析,分析 SQL 的請(qǐng)求類(lèi)型,必要時(shí)改寫(xiě) SQL,然后選取相應(yīng)的 DB 并轉(zhuǎn)發(fā);
等待后端處理查詢(xún),接收處理查詢(xún)結(jié)果集,進(jìn)行合并和修改,然后轉(zhuǎn)發(fā)給客戶(hù)端;
如收到客戶(hù)端關(guān)閉連接的請(qǐng)求,Cetus 判斷是否需要關(guān)閉后端連接,關(guān)閉連接。
如下圖所示:

Cetus 目前分為兩個(gè)版本,分別是讀寫(xiě)分離和分庫(kù)版本,這主要有兩個(gè)考慮:
分庫(kù)解析器和讀寫(xiě)分離解析器很不一樣
Cetus 是基于 MySQL proxy 基礎(chǔ)上做的,由于原先代碼架構(gòu)不是很好,不易統(tǒng)一,隨著以后代碼架構(gòu)的不斷完善,兩個(gè)版本統(tǒng)一問(wèn)題會(huì)最終得到解決
在讀寫(xiě)分離版本中,通過(guò)對(duì) SQL 進(jìn)行解析,根據(jù) SQL 特點(diǎn)和 GTID tracking 智能選擇路由主庫(kù)或從庫(kù),從而實(shí)現(xiàn)讀寫(xiě)分離,減少主庫(kù)的壓力,同時(shí)通過(guò)相關(guān)策略,保證從庫(kù)上進(jìn)行負(fù)載均衡。
而分庫(kù)的思想是參考了 Fabric 和 OneProxy,采用了 vdb 的思想,一個(gè) vdb 代表一個(gè)具體的分片規(guī)則,Cetus 確保同一個(gè) vdb 內(nèi)可以 join,不同 vdb 相互隔離,兼顧垂直拆分和開(kāi)發(fā)對(duì) join 的需求,不同 vdb 之間可以走分布式事務(wù)。
但 Cetus 基于以下考慮,不支持分表:
MySQL 分區(qū)性能會(huì)越來(lái)越好
Oracle 分區(qū)功能強(qiáng)大,而 MySQL 是 Oracle 公司的,并且 MySQL 5.7 以后的分區(qū)性能越來(lái)越好。
我們電商系統(tǒng)沒(méi)有用到分表功能
我們預(yù)測(cè),未來(lái) MySQL 分區(qū)會(huì)逐漸取代分表,類(lèi)似 Oracle 原先走的路線,鑒于這個(gè)判斷和緊跟 MySQL 趨勢(shì),樂(lè)得電商放棄了分表功能開(kāi)發(fā)。
研發(fā)過(guò)程中暴露的問(wèn)題
在項(xiàng)目開(kāi)發(fā)過(guò)程中,我們遇到了一些難點(diǎn)與坑,并且有相應(yīng)的解決思路,這里與大家分享一下。
構(gòu)造分庫(kù)測(cè)試環(huán)境
我們改造了 tpcc、Zabbix 等軟件,以支持分布式數(shù)據(jù)庫(kù)使用場(chǎng)景。改造 tpcc 是為了測(cè)試分庫(kù)性能和分布式事務(wù)性能;改造 Zabbix,是為了讓分庫(kù)版本盡快用起來(lái),盡早去發(fā)現(xiàn)問(wèn)題。
線上規(guī)避問(wèn)題
線上如果出大的問(wèn)題,開(kāi)發(fā)是很難接受的,因此確保線上盡量不出大問(wèn)題,是遇到的最大挑戰(zhàn)。為了更好地解決此問(wèn)題,我們專(zhuān)門(mén)優(yōu)化了 tcpcopy,使其更加適合流量測(cè)試。
目前80%以上的線上潛在問(wèn)題都被流量測(cè)試所發(fā)現(xiàn)。
分布式事務(wù)
MySQL 在這方面是不太完美的,一旦 MySQL 在分布式事務(wù)支持方面出問(wèn)題,是需要去補(bǔ)救的。
在測(cè)試過(guò)程中,我們發(fā)現(xiàn) MySQL 在分布式事務(wù)處理方面有如下兩大問(wèn)題:
1、只有主庫(kù)存在懸掛事務(wù)
MySQL 主庫(kù)已接受到 xa commit 通知,xa commit 未完成前,kill -9 殺掉 MySQL 主庫(kù),再啟動(dòng) MySQL 主庫(kù),主庫(kù)出現(xiàn)懸掛事務(wù),而從庫(kù)該分布式事務(wù)已提交。主庫(kù)此時(shí)需要執(zhí)行 xa commit 語(yǔ)句,提交分布式事務(wù),這個(gè)操作同步到從庫(kù)后,會(huì)導(dǎo)致從庫(kù) SQL 應(yīng)用進(jìn)程報(bào)錯(cuò),提示找不到該分布式事務(wù)。
2、只有從庫(kù)出現(xiàn)懸掛事務(wù)
Cetus 向后端分片發(fā)送 xa prepare,分片 MySQL 主庫(kù)接收到 xa prepare,xa prepare 未完成前,kill -9 殺掉 MySQL 主庫(kù),再啟動(dòng) MySQL 主庫(kù),xa 事務(wù)已回滾,主庫(kù)未出現(xiàn)懸掛事務(wù);從庫(kù)出現(xiàn)懸掛事務(wù)。這種情況下,從庫(kù)需要回滾 xa 事務(wù),才能保證數(shù)據(jù)的一致性。
以上兩種情況,主庫(kù)的 xa 事務(wù)狀態(tài),跟 binlog 記錄的事務(wù)狀態(tài)不一致。在 MySQL 官方文檔找到解釋?zhuān)琈ySQL 異常關(guān)閉,有可能導(dǎo)致數(shù)據(jù)庫(kù)狀態(tài)和 binlog 不一致。這些 bug,在非正常關(guān)閉 MySQL 時(shí)才出現(xiàn),正常關(guān)閉 MySQL 不會(huì)出現(xiàn)這個(gè)問(wèn)題。如果出現(xiàn) xa 事務(wù)懸掛,可以用 Cetus xa 懸掛處理工具自動(dòng)處理。
tcp stream 改造
由于 MySQL 協(xié)議是有狀態(tài)的協(xié)議,Cetus 是純異步的,再加上 tcp stream,處理過(guò)程就變得異常復(fù)雜。我們采用的策略是讓線上運(yùn)行禁止 tcp stream 功能的 Cetus,而流量測(cè)試環(huán)境使用 tcp stream 的 Cetus,這樣就很容易去發(fā)現(xiàn) tcp stream 的很多問(wèn)題。
網(wǎng)易樂(lè)得目前使用 Cetus 已經(jīng)一年多了,線上沒(méi)有遇到大的問(wèn)題,而在測(cè)試的時(shí)候遇到了原先 MySQL proxy 帶過(guò)來(lái)的一個(gè)問(wèn)題,因?yàn)樵O(shè)置 max-open-files 過(guò)小導(dǎo)致 CPU 100%,也正因?yàn)檫@個(gè)問(wèn)題,使我們堅(jiān)決部署了 tcpcopy 流量測(cè)試環(huán)境。
展望
我們對(duì) Cetus 的短期計(jì)劃是讓用戶(hù)大量用起來(lái),并完成基于GTID tracking一致性讀的功能, 對(duì)MGR 的完善支持和擴(kuò)容工具的完善。
長(zhǎng)期計(jì)劃是在不斷成長(zhǎng)中,將 Cetus 打造成類(lèi)似 OneProxy 的高性能數(shù)據(jù)庫(kù)中間件,支持多進(jìn)程、query cache、ssl與更好的安全過(guò)濾等,為MySQL保駕護(hù)航。


