SQL 解析
分庫分表后在應(yīng)用層面執(zhí)行一條 SQL 語句時,通常需要經(jīng)過以下六個步驟:SQL 解析
-> 執(zhí)?器優(yōu)化
-> SQL 路由
-> SQL 改寫
-> SQL 執(zhí)?
-> 結(jié)果歸并
。
在這里插入圖片描述
SQL解析過程分為詞法解析
和語法解析
兩步,比如下邊查詢用戶訂單的SQL,先用詞法解析將這條SQL拆解成不可再分的原子單元。在根據(jù)不同數(shù)據(jù)庫方言所提供的字典,將這些單元歸類為關(guān)鍵字,表達式,變量或者操作符等類型。
SELECT order_no FROM t_order where order_status > 0 and user_id = 10086
接著語法解析會將拆分后的SQL關(guān)鍵字轉(zhuǎn)換為抽象語法樹,通過對抽象語法樹遍歷,提煉出分片所需的上下文,上下文包含查詢字段信息(Field
)、表信息(Table
)、查詢條件(Condition
)、排序信息(Order By
)、分組信息(Group By
)以及分頁信息(Limit
)等,并標記出 SQL中有可能需要改寫的位置。
抽象語法樹
執(zhí)?器優(yōu)化
執(zhí)?器優(yōu)化是根據(jù)SQL查詢特點和執(zhí)行統(tǒng)計信息,選擇最優(yōu)的查詢計劃并執(zhí)行,比如user_id
字段有索引,那么會調(diào)整兩個查詢條件的位置,主要是提高SQL的執(zhí)行效率。
SELECT order_no FROM t_order where user_id = 10086 and order_status > 0
SQL 路由
通過上邊的SQL解析得到了分片上下文數(shù)據(jù),在匹配用戶配置的分片策略和算法,就可以運算生成路由路徑,將 SQL 語句路由到相應(yīng)的數(shù)據(jù)節(jié)點上。
簡單點理解就是拿到分片策略中配置的分片鍵等信息,在從SQL解析結(jié)果中找到對應(yīng)分片鍵字段的值,計算出 SQL該在哪個庫的哪個表中執(zhí)行,SQL路由又根據(jù)有無分片健分為 分片路由
和 廣播路由
。
有分?鍵的路由叫分片路由,細分為直接路由、標準路由和笛卡爾積路由這3種類型。
標準路由
標準路由是最推薦也是最為常?的分??式,它的適?范圍是不包含關(guān)聯(lián)查詢或僅包含綁定表之間關(guān)聯(lián)查詢的SQL。
當 SQL分片健的運算符為 =
時,路由結(jié)果將落?單庫(表),當分?運算符是BETWEEN
或IN
等范圍時,路由結(jié)果則不?定落?唯?的庫(表),因此?條邏輯SQL最終可能被拆分為多條?于執(zhí)?的真實SQL。
SELECT * FROM t_order where t_order_id in (1,2)
SQL路由處理后
SELECT * FROM t_order_0 where t_order_id in (1,2)
SELECT * FROM t_order_1 where t_order_id in (1,2)
直接路由
直接路由是直接將SQL路由到指定?庫、表的一種分?方式,而且直接路由可以?于分?鍵不在SQL中的場景,還可以執(zhí)?包括?查詢、?定義函數(shù)等復(fù)雜情況的任意SQL。
笛卡爾積路由
笛卡爾路由是由?綁定表之間的關(guān)聯(lián)查詢產(chǎn)生的,比如訂單表t_order
分片鍵是t_order_id
和用戶表t_user
分片鍵是t_order_id
,兩個表的分片鍵不同,要做聯(lián)表查詢,會執(zhí)行笛卡爾積路由,查詢性能較低盡量避免走此路由模式。
SELECT * FROM t_order_0 t LEFT JOIN t_user_0 u ON u.user_id = t.user_id WHERE t.user_id = 1
SELECT * FROM t_order_0 t LEFT JOIN t_user_1 u ON u.user_id = t.user_id WHERE t.user_id = 1
SELECT * FROM t_order_1 t LEFT JOIN t_user_0 u ON u.user_id = t.user_id WHERE t.user_id = 1
SELECT * FROM t_order_1 t LEFT JOIN t_user_1 u ON u.user_id = t.user_id WHERE t.user_id = 1
無分?鍵的路由又叫做廣播路由,可以劃分為全庫表路由、全庫路由、 全實例路由、單播路由和阻斷路由這 5種類型。
全庫表路由
全庫表路由針對的是數(shù)據(jù)庫 DQL
和 DML
,以及 DDL
等操作,當我們執(zhí)行一條邏輯表 t_order
SQL時,在所有分片庫中對應(yīng)的真實表 t_order_0
··· t_order_n
內(nèi)逐一執(zhí)行。
全庫路由
全庫路由主要是對數(shù)據(jù)庫層面的操作,比如數(shù)據(jù)庫 SET
類型的數(shù)據(jù)庫管理命令,以及 TCL 這樣的事務(wù)控制語句。
對邏輯庫設(shè)置 autocommit
屬性后,所有對應(yīng)的真實庫中都執(zhí)行該命令。
SET autocommit=0;
全實例路由
全實例路由是針對數(shù)據(jù)庫實例的 DCL 操作(設(shè)置或更改數(shù)據(jù)庫用戶或角色權(quán)限),比如:創(chuàng)建一個用戶 order ,這個命令將在所有的真實庫實例中執(zhí)行,以此確保 order 用戶可以正常訪問每一個數(shù)據(jù)庫實例。
CREATE USER order@127.0.0.1 identified BY '程序員小富';
單播路由
單播路由用來獲取某一真實表信息,比如獲得表的描述信息:
DESCRIBE t_order;
t_order
的真實表是 t_order_0
···· t_order_n
,他們的描述結(jié)構(gòu)相完全同,我們只需在任意的真實表執(zhí)行一次就可以。
阻斷路由
?來屏蔽SQL對數(shù)據(jù)庫的操作,例如:
USE order_db;
這個命令不會在真實數(shù)據(jù)庫中執(zhí)?,因為 ShardingSphere
采?的是邏輯 Schema(數(shù)據(jù)庫的組織和結(jié)構(gòu)) ?式,所以無需將切換數(shù)據(jù)庫的命令發(fā)送?真實數(shù)據(jù)庫中。
SQL 改寫
SQL經(jīng)過解析、優(yōu)化、路由后已經(jīng)明確分片具體的落地執(zhí)行的位置,接著就要將基于邏輯表開發(fā)的SQL改寫成可以在真實數(shù)據(jù)庫中可以正確執(zhí)行的語句。比如查詢 t_order
訂單表,我們實際開發(fā)中 SQL是按邏輯表 t_order
寫的。
SELECT * FROM t_order
這時需要將分表配置中的邏輯表名稱改寫為路由之后所獲取的真實表名稱。
SELECT * FROM t_order_n
SQL執(zhí)?
將路由和改寫后的真實 SQL 安全且高效發(fā)送到底層數(shù)據(jù)源執(zhí)行。但這個過程并不能將 SQL 一股腦的通過 JDBC 直接發(fā)送至數(shù)據(jù)源執(zhí)行,需平衡數(shù)據(jù)源連接創(chuàng)建以及內(nèi)存占用所產(chǎn)生的消耗,它會自動化的平衡資源控制與執(zhí)行效率。
結(jié)果歸并
將從各個數(shù)據(jù)節(jié)點獲取的多數(shù)據(jù)結(jié)果集,合并成一個大的結(jié)果集并正確的返回至請求客戶端,稱為結(jié)果歸并。而我們SQL中的排序、分組、分頁和聚合等語法,均是在歸并后的結(jié)果集上進行操作的。
分布式主鍵
數(shù)據(jù)分?后,一個邏輯表(t_order
)對應(yīng)諸多的真實表(t_order_n
),它們之間由于?法互相感知,主鍵ID都從初始值累加,所以必然會產(chǎn)?重復(fù)主鍵ID,此時主鍵不再唯一那么對于業(yè)務(wù)來說也就沒意義了。
盡管可通過設(shè)置表?增主鍵 初始值
和 步?
的?式避免ID碰撞,但這樣會使維護成本加大,可擴展性差。
這個時候就需要我們手動為一條數(shù)據(jù)記錄,分配一個全局唯一的ID,這個ID被叫做分布式ID,而生產(chǎn)這個ID的系統(tǒng)通常被叫做發(fā)號器。
大家可以參考我之前發(fā)布的這篇文章 9種分布式ID生成方案
數(shù)據(jù)脫敏
分庫分表數(shù)據(jù)脫敏是一種有效的數(shù)據(jù)保護措施,可以確保敏感數(shù)據(jù)的機密性和安全性,減少數(shù)據(jù)泄露的風險。
比如,我們在分庫分表時可以指定表的哪些字段為脫敏列,并設(shè)置對應(yīng)的脫敏算法,在數(shù)據(jù)分片時解析到執(zhí)行SQL中有待脫敏字段,會直接將字段值脫敏后的寫入庫表內(nèi)。
對于用戶的個人信息,如姓名、地址和電話號碼等,可以通過加密、隨機化或替換成偽隨機數(shù)據(jù)的方式進行脫敏,以確保用戶的隱私得到保護。
大家可以參考我之前發(fā)布的這篇文章 大廠也在用的 6種 數(shù)據(jù)脫敏方案
分布式事務(wù)
分布式事務(wù)的核心問題是如何實現(xiàn)跨多個數(shù)據(jù)源的原子性操作。
由于不同的服務(wù)通常會使用不同的數(shù)據(jù)源來存儲和管理數(shù)據(jù),因此,跨數(shù)據(jù)源的操作可能會導(dǎo)致數(shù)據(jù)不一致性或丟失的風險。因此,保證分布式事務(wù)的一致性是非常重要的。
以訂單系統(tǒng)為例,它需要調(diào)用支付系統(tǒng)、庫存系統(tǒng)、積分系統(tǒng)等多個系統(tǒng),而每個系統(tǒng)都維護自己的數(shù)據(jù)庫實例,系統(tǒng)間通過API接口交換數(shù)據(jù)。
為了保證下單后多個系統(tǒng)同時調(diào)用成功,可以使用強一致性事務(wù)
的XA協(xié)議,或者柔性事務(wù)
的代表工具Seata,來實現(xiàn)分布式事務(wù)的一致性。這些工具可以幫助開發(fā)人員簡化分布式事務(wù)的實現(xiàn),減少錯誤和漏洞的出現(xiàn),提高系統(tǒng)的穩(wěn)定性和可靠性。
經(jīng)過分庫分表之后,問題的難度進一步提升。自身訂單服務(wù),也需要處理跨數(shù)據(jù)源的操作。這樣一來,系統(tǒng)的復(fù)雜度顯著增加。因此,不到萬不得已的情況下,最好避免采用分庫分表的解決方案。
關(guān)于分布式事務(wù)詳細的介紹,大家可以參考我之前發(fā)布的這篇文章 對比 5 種分布式事務(wù)方案,還是寵幸了阿里的 Seata(原理 + 實戰(zhàn))
數(shù)據(jù)遷移
分庫分表后還有個讓人頭疼的問題,那就是數(shù)據(jù)遷移,為了不影響現(xiàn)有的業(yè)務(wù)系統(tǒng),通常會新建數(shù)據(jù)庫集群遷移數(shù)據(jù)。將數(shù)據(jù)從舊集群的數(shù)據(jù)庫、表遷移到新集群的分庫、分表中。這是一個比較復(fù)雜的過程,在遷移過程中需要考慮數(shù)據(jù)量
、數(shù)據(jù)一致性
、遷移速度
等諸多因素。
遷移主要針對 存量數(shù)據(jù)
和 增量數(shù)據(jù)
的處理,存量數(shù)據(jù)指舊數(shù)據(jù)源中已經(jīng)存在且有價值的歷史數(shù)據(jù),增量數(shù)據(jù)指當下持續(xù)增長以及未來產(chǎn)生的業(yè)務(wù)數(shù)據(jù)。
存量數(shù)據(jù)可以采用定時、分批次的遷移,遷移過程可能會持續(xù)幾天。
增量數(shù)據(jù)可以采用新、舊數(shù)據(jù)庫集群雙寫模式。待數(shù)據(jù)遷移完畢,業(yè)務(wù)驗證了數(shù)據(jù)一致性,應(yīng)用直接切換數(shù)據(jù)源即可。
后續(xù)我們會結(jié)合三方工具,來演示遷移的過程。
影子庫
什么是影子庫(Shadow Table
)?
影子庫是一個與生產(chǎn)環(huán)境數(shù)據(jù)庫結(jié)構(gòu)完全相同的實例,它存在的意義是為了在不影響線上系統(tǒng)的情況下,驗證數(shù)據(jù)庫遷移或者其他數(shù)據(jù)庫變更操作的正確性,以及全鏈路壓測。影子庫中存儲的數(shù)據(jù)是從生產(chǎn)環(huán)境中定期復(fù)制過來的,但是它不對線上業(yè)務(wù)產(chǎn)生任何影響,僅用于測試,驗證和調(diào)試。
在進行數(shù)據(jù)庫升級、版本變更、參數(shù)調(diào)優(yōu)等操作前,通過在影子庫上模擬這些操作,可以發(fā)現(xiàn)潛在的問題,因為測試環(huán)境的數(shù)據(jù)是不可靠的。
在使用影子庫時,需要遵循以下幾個原則:
- 與生產(chǎn)環(huán)境數(shù)據(jù)庫的結(jié)構(gòu)應(yīng)該完全一致,包括表結(jié)構(gòu)、索引、約束等;
- 數(shù)據(jù)要與生產(chǎn)環(huán)境保持一致,可以通過定期同步方式實現(xiàn);
- 讀寫操作不會影響生產(chǎn)環(huán)境,一般情況下應(yīng)該禁止在影子庫上執(zhí)行更新、刪除等操作;
- 由于影子庫的數(shù)據(jù)特點,訪問權(quán)限應(yīng)該嚴格控制,只允許授權(quán)人員進行訪問和操作;
總結(jié)
本文介紹了關(guān)于分庫分表架構(gòu)的21個通用概念,有一定的了解之后,接下來我們將進入更深度的內(nèi)容,包括讀寫分離
、數(shù)據(jù)脫敏
、分布式主鍵
、分布式事務(wù)
、配置中心
、注冊中心
、Proxy服務(wù)
等實戰(zhàn)案例的講解和源碼分析。
-
SQL
+關(guān)注
關(guān)注
1文章
766瀏覽量
44159 -
路由
+關(guān)注
關(guān)注
0文章
278瀏覽量
41857
發(fā)布評論請先 登錄
相關(guān)推薦
評論