MyCat的說明文檔請參見官網
主要使用到得幾個配置文件有schema.xml、rule.xml、server.xml
MYCAT_HOME/conf/schema.xml 中定義邏輯庫,表、分片節點等內容.
MYCAT_HOME/conf/rule.xml 中定義分片規則.
MYCAT_HOME/conf/server.xml 中定義用戶以及系統相關變量,如端口等.
假設有如下幾個數據庫,arp庫是a庫的復制庫,brp庫是b庫的復制庫,需要搭建成mycat模式,配置成單個實例模式,同時配置成讀寫分離模式
mysqldatabasetable
a.mysql.com.cnt_database1-4t_table
arp.mysql.com.cnt_database1-4t_table
b.mysql.com.cnt_database5-8t_table
brp.mysql.com.cnt_database5-8t_table
mycatdatabasetable
mycat.mysql.com.cnt_databaset_table
schema.xml配置讀寫分離數據庫,并定義讀寫分離的模式
[envuser@node1 conf]$ more schema.xmlselect user()select user()
rule.xml定義讀寫規則
site_idpartStr8site_idpartStr81664:2568128:256
server.xml配置,定義mycat的數據庫名稱、用戶名、密碼等參數
passwordt_database
默認分配的賬戶是具備讀寫權限的賬戶
開啟MyCat
[envuser@localhost conf]$ cd ~/mycat/bin/
[envuser@localhost bin]$ ./mycat start
關閉MyCat
[envuser@localhost conf]$ cd ~/mycat/bin/
[envuser@localhost bin]$ ./mycat stop
查看MyCat狀態
[envuser@localhost conf]$ cd ~/mycat/bin/
[envuser@localhost bin]$ ./mycat status
Mycat-server is running (8320).
如果只想給MyCat分配一個只讀賬戶,可以通過配置server.xml來實現,重啟MyCat,使配置生效
passwordt_databasetrue
MyCat的log都存放在logs目錄下,可以通過查找logs目錄找到對應的log,默認的log級別是info,可以通過調整~/mycat/conf/log4j2.xml調整日志的級別和日志的格式,如果MyCat無法正常開啟,可以通過查找該日志來定位原因,修改日志的配置文件,重啟MyCat使配置生效
[envuser@ip-10-21-8-46 conf]$ more log4j2.xml%d{yyyy-MM-dd HH:mm:ss.SSS} %5p [%t] (%l) - %m%n-->-->-->-->
大體數據庫架構如上面所示,由于以a.mysql.com.cn和arp.mysql.com.cn,這兩個數據庫通過mycat配置成讀寫分離,但是發現復制庫的cpu長時間處于100%狀態,且該數據庫的Read的QPS明顯要高于Write的QPS,而主數據庫的CPU長期處于空閑狀態,針對該現象做原因分析
該數據庫由4個分庫,每個分庫中只有1張表,但是表最高的數據行數達到了1800W行((⊙﹏⊙)b),通過修改代碼將每一條SQL的耗時打印到日志中觀察發現,用戶的使用行為中針對該數據庫的Wirie操作較少,且寫的數據庫操作耗時較短,屬于正常現象,但是Read操作較為頻繁,通過分析日志發現,Read的操作最長耗時竟然達到了20s,這也是為什么用戶使用起來覺得查詢慢的原因,由于查詢不斷堆積,導致cpu長時間100%
通過日志分析定位出查詢時間較長的SQL,發現有幾個SQL的查詢非常慢,需要20s以上。將該SQL通過MyCat執行,確實需要花費20s以上的時間,驗證日志無異常;
由于擔心MyCat的查詢規則導致查詢慢,通過在MyCat explain該語句,定位到需要執行該語句的數據庫,直接在該數據庫上執行該語句,發現依然需要20s以上,也就是說該查詢的慢跟MyCat沒有關系
mysql>SELECTglobal_idFROMt_tableWHEREwarn_type='102'ANDchild_warn_type='102003'ANDsite_id='xxxxxxx'ANDdevice_id='xxxxxx'ANDpoint_id='INV.State'ANDcategory='22'ANDOCCUR_TIME_UTC<'2017-09-25 00:05:55.079'ANDOCCUR_TIME<'2017-09-25 08:05:55.079'ANDOCCUR_TIME>'2017-07-01 00:00:00'ORDERBYOCCUR_TIMEDESCLIMIT1;+----------------------------------+|global_id|+----------------------------------+|xxxxxxxx|+----------------------------------+1rowinset(25.80sec)
通過在數據庫上單獨explain該查詢用戶,獲取執行過程中hit到的索引,發現該查詢查找了數百萬行的數據,同時explain的結果顯示,并沒有hit到以前的索引,所以導致查詢慢,并通過分析所有慢的查詢,通過綜合分析索引和查詢的條件,發現以前的索引已經不符合現有的使用情況;
mysql>explainSELECTglobal_idFROMt_tableWHEREwarn_type='102'ANDchild_warn_type='102003'ANDsite_id='xxxxxxxx'ANDdevice_id='xxxxxxx'ANDpoint_id='INV.State'ANDcategory='22'ANDOCCUR_TIME_UTC<'2017-09-25 00:05:55.079'ANDOCCUR_TIME<'2017-09-25 08:05:55.079'ANDOCCUR_TIME>'2017-07-01 00:00:00'ORDERBYOCCUR_TIMEDESCLIMIT1;mysql>showindexfromt_table;+------------------+------------+----------------------------+--------------+-----------------+-----------+-------------+----------+--------+------+------------+---------+---------------+|Table|Non_unique|Key_name|Seq_in_index|Column_name|Collation|Cardinality|Sub_part|Packed|Null|Index_type|Comment|Index_comment|+------------------+------------+----------------------------+--------------+-----------------+-----------+-------------+----------+--------+------+------------+---------+---------------+|t_table|0|PRIMARY|1|id|A|8669108|NULL|NULL||BTREE||||t_table|0|PRIMARY|2|occur_time|A|8669108|NULL|NULL||BTREE||||t_table|1|t_table_global_id_index|1|global_id|A|8669108|NULL|NULL||BTREE||||t_table|1|t_table_index|1|site_id|A|7833|NULL|NULL|YES|BTREE||||t_table|1|t_table_index|2|occur_time_utc|A|6831715|NULL|NULL|YES|BTREE||||t_table|1|t_table_index|3|device_id|A|8669108|NULL|NULL||BTREE||||t_table|1|t_table_index|4|point_id|A|8669108|NULL|NULL|YES|BTREE||||t_table|1|t_table_index|5|warn_type|A|8669108|NULL|NULL|YES|BTREE||||t_table|1|t_table_index|6|child_warn_type|A|8669108|NULL|NULL|YES|BTREE|||+------------------+------------+----------------------------+--------------+-----------------+-----------+-------------+----------+--------+------+------------+---------+---------------+9rowsinset(0.00sec)mysql>
決定重構索引,將查詢的字段根據查詢的內容重構索引,并將老的索引刪除,重啟MyCat后,該查詢正常,經過沖過股索引后,已經可以解決大部分查詢慢的問題,但是還有若干查詢很奇怪,每次查詢的耗時很長20s以上,但是查詢的頻率非常高,基本上市1s一次,這樣的查詢在某個時間段內一直出現,且該查詢可以hit到正常的索引,也就是說他是可以正常的查詢,但是這樣的查詢行為是很怪異的
經過定位查詢語句和查詢邏輯找到了查詢的調用方,經過檢查發現,由于調用方的配置錯誤,導致了這樣的異常查詢調用,要求調用方整改后,基本上已經沒有了長時間的CPU非常高的情況,說明用戶的調用都已經開始恢復正常
但是每天都會有一段時間復制庫的cpu達到100%,持續時間在1h左右,經過定位分析這是用戶的正常使用邏輯,之所以CPU 100%,是由于業務方每天定時調用,每次調用的數據量較大,完成這樣的大量查詢需要1h才能把所有的查詢執行完成,在這段時間內復制庫的cpu是100%的,但是Master數據庫的cpu卻一直長期處于低領用率狀態
既然不能要求業務方該,那就只能從數據庫這方面修改了,由于索引的利用價值已經不高,在不增加成本的情況下,相當一個方案是,將讀寫分離的架構調整成為,主庫寫/讀,復制庫讀的模式,將復制庫的讀壓力部分的轉移到主庫上來,可以分擔一部分的壓力
通過查詢MyCat的schema.xml配置,發現dataHost的blance配置可以滿足我們這樣的需求,balance的具體配置如下:
balance 屬性
負載均衡類型,目前的取值有 3 種:
1. balance="0", 不開啟讀寫分離機制,所有讀操作都發送到當前可用的 writeHost 上。
2. balance="1",全部的 readHost 與 stand by writeHost 參與 select 語句的負載均衡,簡單的說,當雙
主雙從模式(M1->S1,M2->S2,并且 M1 與 M2 互為主備),正常情況下,M2,S1,S2 都參與 select 語句的負載
均衡。
3. balance="2",所有讀操作都隨機的在 writeHost、readhost 上分發。
4. balance="3",所有讀請求隨機的分發到 wiriterHost 對應的 readhost 執行,writerHost 不負擔讀壓
力,注意 balance=3 只在 1.4 及其以后版本有,1.3 沒有。
通過修改balance的值=2,重啟MyCat使配置生效,后面觀察發現主數據庫的Read的IOPS明顯上升,同時副本數據庫的IOPS明顯下降,說明該配置已經生效,復制數據庫的CPU明顯下降,再也沒有打到100%的情況
雖然我也不推薦使用balance=2的模式,但是在成本控制的時候,可以使用,當然了有更好的方案,比如再增加一個副本數據庫,如arp2.mysql.com.cn,同時按照如下配置,將從數據庫的讀寫分擔,也是可以實現這樣的壓力分擔的,但是MySQL數據庫的瓶頸上限是1000W行,當數據量超過1000W行時,查詢等操作會明顯有瓶頸,應當考慮其他的存儲方式,如HBase等
[envuser@node1 conf]$ more schema.xmlselect user()select user()