1. 概述
1.1. 數據分佈式切分方式
分佈式架構中最難解決的是數據分佈式問題,大部分數據庫中間件都以分庫分表作為切分方式,好處是通用,但也存在以下問題:
- 擴容過程需要以切片為單位在庫間移動數據。擴容規模受到切片數量限制,如果業務發展增長規模大大超出初期預估會導致切片數量不夠用,陷入數據硬遷移的困境。
- 同一業務對象的數據分散在不同庫中,無法做聚合、連接等複雜處理。
- 跨庫意味著分佈式事務,雖然現在有兩階段提交等解決方案,但理論上並不總是那麼可靠,尤其是在金融行業苛求數據強一致性時。
以核心業務對象切分方式則以產品線入口業務對象作為切分目標(比如互聯網業務系統中的客戶對象),開戶交易途徑數據庫中間件,以手機號或其它入口字段作為核心字段做附帶權重的客群切分,歸屬到數據庫集群中的某個庫中,並保存分配結果,以後該客戶的所有交易都會被髮往其歸屬庫處理。當需要庫存儲擴容時,只需簡單的增加MySQL歸屬庫到數據庫集群中,在數據庫中間件系統中增加新歸屬庫配置信息,並調大新庫被分配權重,新客戶分配歸屬到新庫的概率變大,當新庫存儲增長到一定程度時調平分配權重,新客戶分配歸屬到所有庫的概率均等,直到下一次擴容。
以核心業務對象切分方式的好處是:
- 無需預估切片,其擴容過程無需移動任何數據。
- 由於同一業務對象的數據集中在其歸屬庫中,所以可以進行任意聚合、連接等複雜處理。
- 每個庫都是全業務庫,同一業務對象的所有模塊處理都在一個庫中完成,不存在跨庫分佈式事務,數據強一致性丟還給數據庫單庫來保證。
但也存在以下硬傷:
- 產品線設計初期慎重挑選核心業務對象作為切分依據,後期很難變更。
- 有些業務系統存在多個核心業務對象,不適合使用這種切分方式,如銀行線上線下整合核心。
以分庫分表切分和以核心業務對象切分是兩種主流的數據分佈式設計範式,各有優缺點,應在不同場景挑選合適的方式。
1.2. mysqlda
mysqlda是一款基於核心業務對象切分的Proxy模式的分佈式MySQL數據庫中間件。
mysqlda優勢:
- 以核心業務對象切分方式的所有好處。
- 支持以核心業務對象定位MySQL歸屬庫(如開戶用手機號或郵箱),也支持核心業務對象的關聯對象(如開戶後的用戶ID、用戶名、賬號)定位MySQL歸屬庫。
- 歸屬庫分配權重自動調整,擴容後新庫與老庫的分配權重也自動調整,無需人工介入,使得所有歸屬庫的數據量儘量自動均衡增長。
- 已包含數據庫網關高可用功能,當一個歸屬庫當前MySQL主服務器不可用時自動切換到備服務器,支持多個備服務器。
- 與MySQL服務器之間的連接池機制,實現了連接複用和閒置清理,提高連接和切換性能。
- 通過在線重載配置文件,擴容新增MySQL歸屬庫、調整MySQL服務器優先列表等完全無感。
- 單體系統的數據分佈式改造過程儘量無感。
2. 架構與原理
2.1. 體系架構
mysqlda數據庫中間件完全遵循MySQL通訊協議橋接應用服務器集群和MySQL數據庫集群。
mysqlda內部進程結構為“父-單子進程”。
2.2. 工作原理
全量數據以核心業務對象切分到多個歸屬庫中,每個歸屬庫包含全業務表。一個歸屬庫由一個MySQL服務器列表(需部署為向下遊同步數據)組成,噹噹前MySQL服務器不可用時自動切換到下一個。
MySQL數據庫集群預創建相同的連接用戶名、密碼,相同的數據庫名和應用表結構,mysqlda預創建相同的連接用戶名、密碼。
啟動mysqlda,從配置文件(etc/mysqlda.conf)中裝載連接用戶名、密碼,從保存文件(etc/mysqlda.save、etc/mysqlda.關聯對象類.save)中裝載已存在的核心業務對象、關聯對象 與 MySQL數據庫集群庫 歸屬庫關係信息。
應用服務器調用標準MySQL連接函數/方法連接mysqlda,mysqlda會遵循MySQL通訊協議處理MySQL用戶登錄和密碼校驗。
登錄成功後,所有DSL、DML操作前,應用服務器發送mysqlda擴展SQL選擇核心業務對象("select library (核心業務對象)")或
關聯對象類、關聯對象("select library_by_correl_object (關聯對象類) (關聯對象)")以連接MySQL歸屬庫,mysqlda會查詢其已分配的MySQL庫核心業務對象或關聯對象類、關聯對象(如果沒有分配過則根據加權一致性哈希算法分配一個歸屬庫並持久化到保存文件中),從該MySQL歸屬庫對應數據庫服務器有序列表中選擇第一個有效MySQL服務器及其連接池中選取空閒連接(如沒有緩存連接則新建一條連接),然後橋接對外和對內連接結對,開始處理後續所有DSL、DML操作。後續操作中可以也發送mysqlda擴展SQL再選擇核心業務對象或關聯對象類、關聯對象以調整MySQL歸屬庫服務器連接。
MySQL歸屬庫對應一個數據庫服務器列表,如由MySQL數據庫1A(MASTER)、1B(SLAVE)、1C(SLAVE)、1D(SLAVE)組成,1A同步複製數據給1B、1C和1D,如果1A出現故障不能被mysqlda連接,mysqlda會依次嘗試連接1B、1C和1D,實現系統可用性。
應用服務器發送mysqlda擴展SQL綁定關聯對象類 和關聯對象和核心業務對象("set correl_object 關聯對象類 關聯對象 核心業務對象"),mysqlda會保存該關係並持久化到保存文件中,供以後直接用關聯對象類、關聯對象定位MySQL歸屬庫。
2.3. 簡易案例
部署了三個MySQL歸屬庫,每個庫有主備兩臺MySQL服務器組成。
A用戶用手機號(核心業務對象)開戶,應用服務器發送手機號13812345678給mysqlda請求定位歸屬庫("select library 13812341234"),mysqlda通過加權一致性哈希算法計算出該手機號(分配客戶)歸屬庫N並持久化到保存文件中,從歸屬庫N連接池中取出一個連接,把該連接與應用服務器連接橋接,交換後面的所有SQL和處理結果。
開戶業務邏輯中創建了賬戶331234567890,,應用服務器發送mysqlda擴展SQL給mysqla("set correl_object account_no 331234567890 13812345678"),mysqlda綁定兩者關係並持久化到保存文件中。
A用戶後續處理請求,可以送手機號("select library 13812341234")或賬號("select library_by_correl_object account_no 331234567890")給mysqlda定位、連接用戶歸屬庫,該用戶的所有業務數據和業務處理都在該歸屬庫中完成。
2.4. 內部數據實體和關係
一個MySQL歸屬庫(forward_instance)對應一個MySQL數據庫服務器有序列表(forward_servers list)。
一個MySQL數據庫服務器有序列表(forward_servers list)下轄一個空閒連接池(unused_forward_session list)和一個工作連接池(forward_session list)。
一個核心業務對象可以綁定一個或多個關聯對象類(forward_correl_object_class)、關聯對象(forward_correl_object)。
一個核心業務對象或一個關聯對象類、關聯對象 與 MySQL歸屬庫 建立一個歸屬關係(forward_library)。
accepted_session是應用服務器與mysqlda之間的通訊會話 ,forward_session是mysqlda與MySQL數據庫服務器之間的通訊會話,一旦一條連接上的MySQL歸屬庫被選定或切換,這兩個會話會被橋接起來。
閱讀更多 儒雅程序員 的文章