MySQL讀寫分離神器:MyCat淺析
云和安全管理服務(wù)專家新鈦云服 王永偉原創(chuàng)
前言:
在如今的互聯(lián)?時代,?數(shù)據(jù)已成為?業(yè)發(fā)展的?個重要?向標,?對于海量數(shù)據(jù)的處理?成為?論是技術(shù)還是業(yè)務(wù)發(fā)展中都不可回避的重要問題。數(shù)據(jù)量越來越?,對性能要求越來越?;對于?量數(shù)據(jù)的存儲的現(xiàn)在主要分為兩種數(shù)據(jù)庫:關(guān)系型數(shù)據(jù)庫和 NoSQL 數(shù)據(jù)庫。
傳統(tǒng)數(shù)據(jù)庫天然存在著單機單庫瓶頸、難于擴展;? NoSQL 產(chǎn)品的出現(xiàn)雖然彌補了傳統(tǒng)數(shù)據(jù)庫的性能問題 ,但是不能完全替代傳統(tǒng)數(shù)據(jù)庫。
隨著業(yè)務(wù)量的擴張和數(shù)據(jù)量的激增,系統(tǒng)負載很?的情況下,就必須對數(shù)據(jù)進?分割。數(shù)據(jù)被分到多個分?數(shù)據(jù)庫后,應(yīng)?如果需要讀取數(shù)據(jù),就要需要處理多個數(shù)據(jù)源的數(shù)據(jù)。
如果沒有數(shù)據(jù)庫中間件(eg:MyCat) ,那么應(yīng)?將直接?對分?集群,數(shù)據(jù)源切換、事務(wù)處理、數(shù)據(jù)聚合都需要應(yīng)?直接處理,原本該是專注于業(yè)務(wù)的應(yīng)?,將會花?量的?作來處理分?后的問題。
MyCat 是什么?
對于 DBA 來說:
MyCat 就是 MySql Server 增強版的存儲引擎。
對于軟件工程師來說:
MyCat 就是數(shù)據(jù)庫服務(wù)器,可以像操作數(shù)據(jù)庫那樣操作MyCat。
對于架構(gòu)師來說:
MyCat 是?個強?的數(shù)據(jù)庫中間件,不僅可以?作讀寫分離以及分庫分表,甚?可?于多租戶應(yīng)?開發(fā)、云平臺基礎(chǔ)設(shè)施,讓架構(gòu)具備很強的靈活性和適應(yīng)性。
MyCat的應(yīng)用場景:
1、?持讀寫分離、主從切換;
2、垂直分庫、?平分表;
3、多租戶應(yīng)?,如果每個應(yīng)??個庫,所有的應(yīng)該只需連接 Mycat,實現(xiàn)多租戶;
4、報表系統(tǒng),處理?規(guī)模報表的統(tǒng)計。數(shù)據(jù)被切分到不同的分?數(shù)據(jù)庫上,當應(yīng)?需要讀取數(shù)據(jù)時,中間件 mycat 就可以幫助開發(fā)?員進?數(shù)據(jù)聚合、事務(wù)、數(shù)據(jù)源切換等處理,讓開發(fā)?員更加專注于業(yè)務(wù)開發(fā)。
MyCat 基本概念介紹:
邏輯庫(schema):
對實際應(yīng)???,業(yè)務(wù)開發(fā)?員并不需要知道中間件的存在,所以 mycat 中間件?個或多個數(shù)據(jù)庫集群構(gòu)成的邏輯庫。
邏輯表(table):
對應(yīng)?來說,讀寫數(shù)據(jù)的表就是邏輯表。邏輯表是對應(yīng)邏輯庫存在的。
分片表:
指原有很?的數(shù)據(jù)表需要切分到不同數(shù)據(jù)庫上的表。
非分片表 :
針對分?表來說,原則上是不需要切分的表。
E-R 表:
基于關(guān)系型數(shù)據(jù)庫中實體關(guān)系模型,?表和?表記錄存放在同?個分?上,通過表分組保證數(shù)據(jù) join 不會出現(xiàn)跨庫操作。
全局表:
類似字典的表;變動不頻繁、數(shù)據(jù)量總體變化不是很?、規(guī)模不超過10w 的表。
分片節(jié)點(dataNode):
?個?表被分到不同的分?數(shù)據(jù)庫上?,每個表分?所在的數(shù)據(jù)庫就是分?節(jié)點
節(jié)點主機(dataHost):
?個或多個分?節(jié)點(dataNode)所在的機器就是節(jié)點主機
分片規(guī)則(rule):
?個?表被分成若?個分?表,就需要?定的規(guī)則,這樣按照某種業(yè)務(wù)規(guī)則把數(shù)據(jù)分到某個分?的規(guī)則就是分?規(guī)則。
MyCat連接池解讀:
MyCat通過共享?個MySQL上的所有物理連接,并結(jié)合連接狀態(tài)同步的特性,MyCat的連接池做到了最佳的吞吐量,也在?定程度上提升了整個系統(tǒng)的并發(fā)?撐能?。
其中ConMap 是存放連接池對象重要的數(shù)據(jù)結(jié)構(gòu),ConMap部分源碼如下:
private final ConcurrentHashMap<string,< span=""> ConQueue> items = new ConcurrentHashMap();
public ConQueue getSchemaConQueue(String schema)
{
// 根據(jù)schema 獲取當前切?的連接
ConQueue queue = items.get(schema);
if (queue == null) { // 如果沒有可?連接,則新建
ConQueue newQueue = new ConQueue();
queue = items.putIfAbsent(schema,newQueue);
return (queue == null) ? newQueue: queue;
}
return queue;
}
public BackendConnection tryTakeCon(final String schema,
boolean autoCommit)
{
final ConQueue queue = items.get(schema);
// 嘗試獲取?個可?連接
BackendConnection con = tryTakeCon(queue,autoCommit);
if (con != null) {
return con;
}
如果沒有可?連接或者不是?動模式,為了?效且充分利?數(shù)據(jù)庫連接,當某個?戶會話需要?個?動提交到分? dn1(對應(yīng)db1)的 SQL 連接的時候,連接池?先找是否有 db1 上的可?連接。
如果有,看是否有?動提交模式的連接,找到就返回,否則返回 db1 上的?動提交模式的連接,若沒有db1 的可?連接,則隨機返回?個其他 db 對應(yīng)的可?連接,若沒有可?連接,并且連接池還沒達到上限,則創(chuàng)建?個新連接并返回。
MyCat網(wǎng)絡(luò)模型NIO/AIO:
· SocketConnector 發(fā)起連接請求類,如 MyCAT 與 MySQL 數(shù)據(jù)庫的連接,都是由 MyCAT 主動發(fā)起連接請求。
· SocketAcceptor 接收連接請求類,如 MyCAT 啟動 9066 和 8066 分別偵聽管理員和應(yīng)?程序的連接請求。
· SocketWR 讀寫操作類,SocketConnector 和 SocketAcceptor 只負責 socket 建?,當 socket 連接建?后進?字節(jié)的讀寫操作則由SocketWR 來完成。在 MyCAT 中,NIO 采?多 Reactor 模式,內(nèi)部維護?個 Selector 選擇器分別處理不同是事件。例如 NIOConnector 類- selector 事件選擇器。
· connectQueue 需要建?連接的對象,臨時放在這個隊列?
· reactorPool 當連接建?后,從 reactorPool 中分配?個 NIOReactor,處理 Read和 Write 事件
connect 源碼解讀:
private void connect(Selector selector) {
AbstractConnection c = null;
while ((c = connectQueue.poll()) != null) {
try {
SocketChannel channel = (SocketChannel) c.getChannel();
channel.register(selector, SelectionKey.OP_CONNECT, c);
channel.connect(new InetSocketAddress(c.host, c.port));
} catch (Exception e) {
LOGGER.error("error:",e);
c.close(e.toString());
}
}
// 處理connect事件,交給reactor處理
private void finishConnect(SelectionKey key, Object att) {
BackendAIOConnection c = (BackendAIOConnection) att;
try {
if (finishConnect(c, (SocketChannel) c.channel)) {
clearSelectionKey(key);
c.setId(ID_GENERATOR.getId());
NIOProcessor processor =
MycatServer.getInstance().nextProcessor();
c.setProcessor(processor);
NIOReactor reactor = reactorPool.getNextReactor();
reactor.postRegister(c);
c.onConnectfinish();
}
} catch (Exception e) {
clearSelectionKey(key);
LOGGER.error("error:",e);
c.close(e.toString());
c.onConnectFailed(e);
}
}
1、判斷 connectQueue 中是否新的連接請求。
2、建??個 SocketChannel。
3、在 selector 中進行注冊 OP_CONNECT。
4、發(fā)起 SocketChannel.connect()操作。
MyCat讀寫分離實戰(zhàn):
在?些?型?站業(yè)務(wù)場景中,單臺數(shù)據(jù)庫提供的并發(fā)量已經(jīng)?法滿?業(yè)務(wù)需求;為了提供數(shù)據(jù)庫的并發(fā)能?和負載能?,?般通過讀寫分離來實現(xiàn)。
當我們的數(shù)據(jù)庫實現(xiàn)讀寫分離的時候,在應(yīng)?中需要對數(shù)據(jù)源進?切換, MyCat能夠幫我們更好的實現(xiàn)數(shù)據(jù)源的動態(tài)切換,也就是應(yīng)?程序只需要連接MyCat中間件,?動幫我們讀取讀寫的數(shù)據(jù)庫。
未采用MyCat中間件項目架構(gòu):
采用MyCat中間件架構(gòu):
兩者對比差異:
圖?需要在應(yīng)?程序中配置多個數(shù)據(jù)源,通過不同的業(yè)務(wù)需求動態(tài)切換多個數(shù)據(jù)源。?通過MyCat以后,應(yīng)?程序只需要連接MyCat作為數(shù)據(jù)源,?便拓展,對現(xiàn)有的程序不影響。
搭建主從:
1、jdk 準備:jdk1.7 往上版本
2、mysql 準備,兩臺mysql服務(wù),?臺作為主庫負責寫?數(shù)據(jù),?臺是從庫負責讀數(shù)據(jù)
3、MyCat 安裝:MyCAT 有提供編譯好的安裝包,Mycat-server-xxxxx.linux.tar.gz 解壓
4、MyCat 相關(guān)?錄說明:
bin 程序目錄,進入到 bin目錄:
Linux 下運?:./mycat console,?先要 chmod x *
conf ?錄下存放配置?件,server.xml 是 Mycat 服務(wù)器參數(shù)調(diào)整和?戶授權(quán)的配置?件,schema.xml 是邏輯庫定義和表以及分?定義的配置?件,
rule.xml
是分?規(guī)則的配置?件,分?規(guī)則的具體?些參數(shù)信息單獨存放為?件,
version.txtlib ?錄下主要存放 mycat 依賴的?些 jar ?件.
?志存放在 logs/mycat.log 中,每天?個?件,?志的配置是在
conf/log4j.xml 中,根據(jù)??的需要,可以調(diào)整輸出級別為 debug,debug 級別下,會輸出更多的信息,?便排查問題。
配置schemal.xml邏輯庫、邏輯表、分片:
<!-– 配置邏輯庫 –>
<schema name="TESTDB_YONG" checkSQLschema="true" sqlMaxLimit="100" randomDataNode="dn1">
</schema>
<datanode name="dn1" dataHost="localhost1" database="yong_test" />
<!-– 配置讀寫分離 –>
"localhost1" maxCon="1000" minCon="10" balance="0"
writeType="0" dbType="mysql" dbDriver="jdbc" switchType="1" slaveThreshold="100">
<!– ?跳配置,檢測所屬的數(shù)據(jù)庫是否存活 –>
<heartbe< span="">at>select user()
<!– 寫主庫 –>
<writehost host="hostM1" url="jdbc:mysql://192.168.235.136:3306?useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true" user="root" password="12345678">
writeHost>
<!– 讀從庫 –>
<readhost host="hostS1" url="jdbc:mysql://192.168.235.133:3306?useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true" user="root" password="12345678">
readHost>
dataHost>
配置server.xml,主要配置連接MyCat的邏輯庫、邏輯表訪問權(quán)限的配置:
<!– 邏輯庫、邏輯表訪問權(quán)限配置 ?戶名 name=root 密碼passwors=123456 –>
<user name="root" defaultAccount="true">
<property name="password">123456</property>
<property name="schemas">TESTDB_YONG</property>
<property name="defaultSchema">TESTDB_YONG</property>
<!– 表級 DML 權(quán)限設(shè)置 –>
<!–
<privileges check="false">
<schema name="TESTDB" dml="0110" >
<table name="tb01" dml="0000"></table>
<table name="tb02" dml="1111"></table>
</schema>
</privileges>
–>
</user>
讀寫分離測試:
1、準備兩臺mysql服務(wù)器,?臺配置為主數(shù)據(jù)庫,負責數(shù)據(jù)的寫?,?臺配置為從數(shù)據(jù)庫,負責數(shù)據(jù)的讀取。
2、數(shù)據(jù)庫中間件MyCat通過shcemal.xml和server.xml配置兩臺數(shù)據(jù)庫的讀寫。
3、啟動MyaCat服務(wù),連接mycat實現(xiàn)讀寫分離數(shù)據(jù)源的切換:
mysql -h127.0.0.1 -P8066 -uroot -p
4、連接成功后,然后業(yè)務(wù)開發(fā)?員就可以像操作數(shù)據(jù)庫那樣使? mycat,mycat 會根據(jù)配置的相關(guān)路由規(guī)則對數(shù)據(jù)進?分?存儲和匯總。
通過MyCat插?數(shù)據(jù):
insert into test(id, name) value (1,'wyw');
Query OK, 1 row affected (0.05 sec)
查看主從數(shù)據(jù)庫是否有數(shù)據(jù),
訪問數(shù)據(jù):
select * from test where id = 1;
±—–
| id |
±—–
| 1 |
±—–
1 rows in set (0.00 sec)
5、根據(jù)MyCat的運??志查看讀寫分離的的實質(zhì):mycat/logs/mycat.log
查詢指令在從服務(wù)器上:
版權(quán)聲明:本文內(nèi)容由互聯(lián)網(wǎng)用戶自發(fā)貢獻,該文觀點僅代表作者本人。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔相關(guān)法律責任。如發(fā)現(xiàn)本站有涉嫌抄襲侵權(quán)/違法違規(guī)的內(nèi)容, 請發(fā)送郵件至 舉報,一經(jīng)查實,本站將立刻刪除。