mysql多实例访问代理_MySql-Proxy之多路结果集归并
MySql-Proxy之多路結果集歸并
筆者覺得Cobar之類的分庫分表最神奇的部分就是靠一條sql查詢不同schema下(甚至不同實例下)的不同的表。例如
select * from t_test; // 映射為
|------select * from schema1.t_test
|------select * from schema2.t_test
ResultSet // 返回結果集為兩者的歸并
|--schema1.t_test.ResultSet
|--schema2.t_test.ResultSet
以筆者這種刨根到底的性格當然要把這個過程DIY出來。
由于Cobar對MySql的連接是BIO的。而筆者喜歡NIO,于是用NIO將Corbar的多節點查詢全部重寫(基于Netty)。NIO的難度更大,性能也更好,這個重寫的過程就記錄成博客,以饗讀者。
多路歸并原理
多節點發送select語句
當客戶端發送給select * from test后,Lancelot會根據配置將語句將當前語句路由到多個不同的DB實例上,如上圖所示。
FrontEnd:用來和client交互,一個FrontEnd可以對應多個Backend
BackEnd:用來和DB交互
多節點歸并結果集
每條語句在一個DB實例上面執行后,都會返回一個ResultSet結果集,在此需要將多個結果集歸并成一個統一的結果集,然后返回給client,這樣client就感覺像查詢一個DB實例一樣。
如上圖所示,歸并過程在下面講解。
歸并ResultSet結果集
在講如何歸并前,我們需要重溫一下MySql返回結果集的結構, 其詳細描述見筆者博客:
https://my.oschina.net/alchemystar/blog/834150
其協議格式如下所示:
由上圖可見,
其中的Row才是真正的數據內容。而其余的例如,field_count、fields 、eof以及last_eof則僅僅是攜帶數據格式的信息。
如果要多路歸并成一路的話,field_count、fields、eof以及last_eof這些只需要返回給client一份即可。
去掉多余的結構描述信息
現在根據協議結構將Frontend歸并結果集的代碼階段分為三個:
(1)fieldList階段: 由于field_count、fields、eof這三個階段是連續的,于是將其合并成一個狀態。
(2)Row階段:顧名思義,接收DB返回的數據階段。
(3)LastEof階段:最后的收尾階段,每個結果集的last_eof表示此結果集的結束,只有所有的last_eof都收到之后才能表示結果的結束。
fieldList階段的處理:
首先每個Backend都接收field_count,fields,eof。當其接收到eof之后,收到row之前,向Frontend提交這些信息。如下圖所示:
當Frontend獲取到Backend1的feilds信息之后,就開始接收Row,并丟棄其余Backend的fields信息。代碼如下:
public void fieldListResponse(List fieldList) {
lock.lock();
try {
if(!isFailed.get()) {
// 如果還沒有傳過fieldList的話,則傳遞
if (!fieldEofReturned) {
writeFiledList(fieldList);
fieldEofReturned = true;
}
}
} finally {
lock.unlock();
}
}
Row階段的處理
當Frontend進入Row階段之后,處理比較簡單,Backend發送的任何Row都向前段傳輸,如果是Backend的fields信息則丟棄。如下圖所示:
LastEof階段
每當一個Backend收到last_eof之后,表明當前Backend的結果集已經結束。Frontend需要等所有的Backend結果集結束之后,再發送一個last_eof告訴client,所有的結果已經完了,如下圖所示:
代碼如下所示:
// last eof response
public void lastEofResponse(BinaryPacket bin) {
lock.lock();
try {
logger.info("last eof ");
if (decrementCountBy()) {
if (!isFailed.get()) {
bin.packetId = ++packetId;
logger.info("write eof okay");
bin.write(session.getCtx());
// 如果是自動提交,則釋放session
if(session.getSource().isAutocommit()){
session.release();
}
}else{
notifyFailure();
}
}
} finally {
lock.unlock();
}
}
例子
運行lancelot中的LanceLotServer的main命令,其就自動連接了我本機的MySql。 配置之類的在SystemConfig中進行修改(現在還沒有做到配置文件化)。
我用mysqlclient連接到lancetlot,然后運行select * from test命令。結果如下圖所示:
公眾號
關注筆者公眾號,獲取更多干貨文章:
GitHub鏈接
碼云鏈接
原文鏈接
總結
以上是生活随笔為你收集整理的mysql多实例访问代理_MySql-Proxy之多路结果集归并的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 吕布开1200斤弓相当于多大力?
- 下一篇: 后勤力量配置应尽量靠近战斗部队对吗