kingshard(https://github.com/flike/king...開源有一段時間了,有些熱心的用戶發郵件來諮詢kingshard的設計和實現問題。因而週末抽空寫了一篇介紹kingshard架構和功能實現的文章,但願經過本文可以讓用戶對kingshard有更深的瞭解。下面分模塊來介紹kingshard的核心組件的設計和實現。node
kingshard採用Go開發,充分地利用了Go語言的併發特性。Go語言在併發方面,作了很好的封裝,這大大簡化了kingshard的開發工做。kingshard的總體工做流程入下所述:git
kingshard工做總體流程可參考下面這幅圖。github
kingshard總體架構圖以下所示web
要將kingshard的功能作的足夠強大,就不得不進行SQL的詞法和語義分析。SQL語句的詞法分析指的是將SQL語句切分紅一個一個的關鍵字。例如對SQL語句:select name from stu where id < 13
進行詞法分析,獲得的結果是:{"select","name","from","stu","where","id","<","13"}
。
這樣作的目的主要爲了生成一棵抽象語法樹,也就是你們常說的AST(abstract syntax tree),語義分析就是基於這棵語法樹來操做的。語義分析的目的主要有如下幾個方面:算法
kingshard並無考慮徹底兼容MySQL全部語法,由於徹底兼容MySQL語法會使得詞法和語義分析模塊變得異常複雜,並且低效。對於DDL語句其實不必解析,只要能正確轉發到後端相應的DB上就能夠。sql
kingshard只對部分DML語句(select,update,insert,delete,replace)
進行了解析,這樣能夠知足絕大部分的分表操做。對於其餘語句,kingshard會將其發送到一個默認的DB,或者經過kingshard特有的方式將其發送到指定的DB上,例如:/*node2*/insert into stu(id,name) values(12,'xiaoming')
,對於這種帶有註釋的的sql語句,kingshard可以識別出,而後將這條sql語句發送到node2節點的Master DB上。數據庫
用戶使用Mysql Proxy目的很大一部分就是爲了下降單臺DB的負載,將讀壓力分擔到多臺DB上。kingshard支持多個slave,不一樣的slave能夠配置不一樣的讀權重,權重越大分擔的讀請求越多。kingshard讀請求負載均衡採用的是權重輪詢調度算法。後端
大部分系統採用該算法時,都是轉發SQL語句時,動態地計算出本次選取DB的序號。而後將讀請求的SQL語句發送到該DB。仔細分析一下,這樣作實際上是沒有必要的。由於DB的權重是相對固定的,不會常常變更,因此徹底能夠計算出一個固定的輪詢序列,而後將這個序列保存在一個數組中。這樣不須要動態計算,每次讀取數組就能夠。舉個例子來講,在kingshard的node配置項中配置slave選項:slave:192.168.0.12@2,192.168.0.13@3
kingshard在讀取配置信息初始化系統的時候,就生成了一個輪詢數組:[0,0,1,1,1]。在kingshard中會將這個數組打亂順序,變成:[0,1,1,0,1]。這樣就避免了動態計算DB下標的問題,對性能提高有必定幫助。數組
首選須要介紹兩個概念:安全
發送SQL語句時,kingshard會識別出須要分表的SQL語句,並改寫該SQL。例如,客戶端發送過來的SQL語句是:select name from stu where id =10;
kingshard收到該SQL語句後,從配置信息中識別出該表是一個Hash類型的分表。根據分表規則,將該SQL改寫成:select name from stu_2 where id =10;
而後發送給對應的DB。
kingshard的sharding採用了兩級映射的思想,首選根據SQL語句的分表條件計算出這條SQL語句落在哪一個子表上,而後再根據配置信息找到該子表
落在哪一個node上。採用兩級映射的思想,對於MySQL的擴容和縮容都能很方便地支持。目前kingshard sharding支持insert, delete, select, update和replace語句, 全部這五類操做都支持跨子表。但寫操做僅支持單node上的跨子表,select操做則能夠跨node,跨子表。
對於有些表沒有分表,操做該表的SQL語句會發往default node。或者用戶能夠選擇在SQL語句前面加上註釋,指定該SQL要發往的node,kingshard接收到語句後,識別出注釋中指定的node,而後將該SQL發往對應node中合適的DB。例如用戶發送/*node1*/select * from member where id=100
,kingshard接收到該SQL後會將其發送到node1的salve上。這樣kingshard就能很好地兼容分表和不分表的各類應用場景了。
全部proxy支持shard後都會面臨一個問題:支不支持分佈式事務?出於性能和可用性考慮,
kingshard只支持單臺DB上的事務,不容許跨DB的事務。kingshard處理單DB上的事務流程以下:
kingshard每一個node啓動了一個goroutine用於檢測後端master和slave的狀態。當goroutine持續一段時間(由配置文件中down_after_noalive參數設置)ping不通後端的DB後,會將該DB的狀態設置爲down,後續kingshard就不會將sql語句發往該DB了。
有時候用戶爲了安全考慮,但願只能某幾臺server可以鏈接kingshard。在kingshard的配置文件中有一個參數:allow_ips,用於實現客戶端白名單機制。當管理員設置了該參數,則意味着只有allow_ips指定的IP可以鏈接kingshard,其餘IP都會被kingshard拒絕鏈接。若是不設置該參數,則鏈接kingshard的客戶端不受限制。
kingshard的管理端口複用了工做端口,經過特定的關鍵字(admin)來標示。kingshard是經過對管理端特定的SQL進行詞法和語義分析,將SQL語句解析爲一條kingshard能夠識別的命令。目前支持平滑上下線master和slave,和查看kingshard配置和後端DB狀態。後續打算將web頁面集成到管理端,這樣用戶就能夠不用輸入命令行操做,而是在網頁上操做。大大下降用戶使用kingshard的門檻。
上述各個模塊都是kingshard中比較核心的模塊,經過這篇文章的介紹,我想讀者應該對kingshard的架構和實現有了初步的瞭解。不少功能的設計和實現,都是做者慢慢地摸索和實踐。若是有讀者對kingshard的設計或實現感興趣或者對上述設計有不一樣的想法,歡迎發郵件(flikecn#126.com)給我。
歡迎關注後端技術快訊公衆號,有關kingshard的最新消息與後端架構設計類的文章,都會在這個公衆號分享。