系統開發中,數據庫是非常重要的一個點。除了程序的本身的優化,如:SQL語句優化、代碼優化,數據庫的處理本身優化也是非常重要的。主從、熱備、分表分庫等都是系統發展遲早會遇到的技術問題問題。Mycat是一個廣受好評的數據庫中間件,已經在很多產品上進行使用了。下面就針對Mycat的基礎知識和應用做一總結性梳理,這些內容有的是從網上收集的,有的是自己做的測試驗證信息,如有錯誤,煩請諒解和指出!
一、MyCat簡單介紹
MyCat是一個開源的分布式數據庫系統,是一個實現了MySQL協議的服務器,前端用戶可以把它看作是一個數據庫代理(類似於Mysql Proxy),用MySQL客戶端工具和命令行訪問,而其后端可以用MySQL原生協議與多個MySQL服務器通信,也可以用JDBC協議與大多數主流數據庫服務器通信,其核心功能是分表分庫,即將一個大表水平分割為N個小表,存儲在后端MySQL服務器里或者其他數據庫里。
MyCat發展到目前的版本,已經不是一個單純的MySQL代理了,它的后端可以支持MySQL、SQL Server、Oracle、DB2、PostgreSQL等主流數據庫,也支持MongoDB這種新型NoSQL方式的存儲,未來還會支持更多類型的存儲。而在最終用戶看來,無論是那種存儲方式,在MyCat里,都是一個傳統的數據庫表,支持標准的SQL語句進行數據的操作,這樣一來,對前端業務系統來說,可以大幅降低開發難度,提升開發速度。
Mycat可以簡單概括為
- 一個徹底開源的,面向企業應用開發的大數據庫集群
- 支持事務、ACID、可以替代MySQL的加強版數據庫
- 一個可以視為MySQL集群的企業級數據庫,用來替代昂貴的Oracle集群
- 一個融合內存緩存技術、NoSQL技術、HDFS大數據的新型SQL Server
- 結合傳統數據庫和新型分布式數據倉庫的新一代企業級數據庫產品
- 一個新穎的數據庫中間件產品
Mycat關鍵特性
- 支持SQL92標准
- 遵守Mysql原生協議,跨語言,跨平台,跨數據庫的通用中間件代理
- 基於心跳的自動故障切換,支持讀寫分離,支持MySQL主從,以及galera cluster集群
- 支持Galera for MySQL集群,Percona Cluster或者MariaDB cluster
- 基於Nio實現,有效管理線程,高並發問題
- 支持數據的多片自動路由與聚合,支持sum,count,max等常用的聚合函數,支持跨庫分頁
- 支持單庫內部任意join,支持跨庫2表join,甚至基於caltlet的多表join
- 支持通過全局表,ER關系的分片策略,實現了高效的多表join查詢
- 支持多租戶方案
- 支持分布式事務(弱xa)
- 支持全局序列號,解決分布式下的主鍵生成問題
- 分片規則豐富,插件化開發,易於擴展
- 強大的web,命令行監控
- 支持前端作為mysq通用代理,后端JDBC方式支持Oracle、DB2、SQL Server 、 mongodb 、巨杉
- 支持密碼加密
- 支持服務降級
- 支持IP白名單
- 支持SQL黑名單、sql注入攻擊攔截
- 支持分表(1.6)
- 集群基於ZooKeeper管理,在線升級,擴容,智能優化,大數據處理(2.0開發版)
二、為什么要用MyCat
這里要先搞清楚Mycat和MySQL的區別(Mycat的核心作用)。我們可以把上層看作是對下層的抽象,例如操作系統是對各類計算機硬件的抽象。那么我們什么時候需要抽象?假如只有一種硬件的時候,我們需要開發一個操作系統嗎?再比如一個項目只需要一個人完成的時候不需要leader,但是當需要幾十人完成時,就應該有一個管理者,發揮溝通協調等作用,而這個管理者對於他的上層來說就是對項目組的抽象。
同樣的,當我們的應用只需要一台數據庫服務器的時候我們並不需要Mycat,而如果你需要分庫甚至分表,這時候應用要面對很多個數據庫的時候,這個時候就需要對數據庫層做一個抽象,來管理這些數據庫,而最上面的應用只需要面對一個數據庫層的抽象或者說數據庫中間件就好了,這就是Mycat的核心作用。所以可以這樣理解:數據庫是對底層存儲文件的抽象,而Mycat是對數據庫的抽象。
三、Mycat工作原理
Mycat的原理並不復雜,復雜的是代碼。Mycat的原理中最重要的一個動詞是“攔截”,它攔截了用戶發送過來的SQL語句,首先對SQL語句做了一些特定的分析:如分
片分析、路由分析、讀寫分離分析、緩存分析等,然后將此SQL發往后端的真實數據庫,並將返回的結果做適當的處理,最終再返回給用戶。
上述圖片里,Orders表被分為三個分片datanode(簡稱dn),這三個分片是分布在兩台MySQL Server上(DataHost),即datanode=database@datahost方式,因此你可以用一台到N台服務器來分片,分片規則為(sharding rule)典型的字符串枚舉分片規則,一個規則的定義是分片字段(sharding column)+分片函數(rule function),這里的分片字段為prov而分片函數為字符串枚舉方式。
當Mycat收到一個SQL時,會先解析這個SQL,查找涉及到的表,然后看此表的定義,如果有分片規則,則獲取到SQL里分片字段的值,並匹配分片函數,得到該SQL對應的分片列表,然后將SQL發往這些分片去執行,最后收集和處理所有分片返回的結果數據,並輸出到客戶端。以select * from Orders where prov=?語句為例,查到prov=wuhan,按照分片函數,wuhan返回dn1,於是SQL就發給了MySQL1,去取DB1上的查詢結果,並返回給用戶。
如果上述SQL改為select * from Orders where prov in (‘wuhan’,‘beijing’),那么,SQL就會發給MySQL1與MySQL2去執行,然后結果集合並后輸出給用戶。但通常業務中我們的SQL會有Order By 以及Limit翻頁語法,此時就涉及到結果集在Mycat端的二次處理,這部分的代碼也比較復雜,而最復雜的則屬兩個表的Jion問題,為此,Mycat提出了創新性的ER分片、全局表、HBT(Human Brain Tech)人工智能的Catlet、以及結合Storm/Spark引擎等十八般武藝的解決辦法,從而成為目前業界最強大的方案,這就是開源的力量!
四、Mycat應用場景
Mycat發展到現在,適用的場景已經很豐富,而且不斷有新用戶給出新的創新性的方案,以下是幾個典型的應用場景:
- 單純的讀寫分離,此時配置最為簡單,支持讀寫分離,主從切換;
- 分表分庫,對於超過1000萬的表進行分片,最大支持1000億的單表分片;
- 多租戶應用,每個應用一個庫,但應用程序只連接Mycat,從而不改造程序本身,實現多租戶化;
- 報表系統,借助於Mycat的分表能力,處理大規模報表的統計;
- 替代Hbase,分析大數據;
- 作為海量數據實時查詢的一種簡單有效方案,比如100億條頻繁查詢的記錄需要在3秒內查詢出來結果,除了基於主鍵的查詢,還可能存在范圍查詢或其他屬性查詢,此時Mycat可能是最簡單有效的選擇;
- Mycat長期路線圖;
- 強化分布式數據庫中間件的方面的功能,使之具備豐富的插件、強大的數據庫智能優化功能、全面的系統監控能力、以及方便的數據運維工具,實現在線數據擴容、遷移等高級功能;
- 進一步挺進大數據計算領域,深度結合Spark Stream和Storm等分布式實時流引擎,能夠完成快速的巨表關聯、排序、分組聚合等 OLAP方向的能力,並集成一些熱門常用的實時分析算法,讓工程師以及DBA們更容易用Mycat實現一些高級數據分析處理功能。
- 不斷強化Mycat開源社區的技術水平,吸引更多的IT技術專家,使得Mycat社區成為中國的Apache,並將Mycat推到Apache
基金會,成為國內頂尖開源項目,最終能夠讓一部分志願者成為專職的Mycat開發者,榮耀跟實力一起提升。
五、Mycat不適合的應用場景
- 設計使用Mycat時有非分片字段查詢,請慎重使用Mycat,可以考慮放棄!
- 設計使用Mycat時有分頁排序,請慎重使用Mycat,可以考慮放棄!
- 設計使用Mycat時如果要進行表JOIN操作,要確保兩個表的關聯字段具有相同的數據分布,否則請慎重使用Mycat,可以考慮放棄!
- 設計使用Mycat時如果有分布式事務,得先看是否得保證事務得強一致性,否則請慎重使用Mycat,可以考慮放棄!
需要注意: 在生產環境中, Mycat節點最好使用雙節點, 即雙機熱備環境, 防止Mycat這一層出現單點故障. 可以使用的高可用集群方式有: Keepalived+Mycat+Mysql, Keepalived+LVS+Mycat+Mysql, Keepalived+Haproxy+Mycat+Mysql
六、利用MyCAT實現MySQL的讀寫分離、主從切換、分庫分表的操作記錄
Mycat實現Mysql主從復制,其中寫操作在master主節點上執行,包括insert,delete,update 語句操作;讀操作在slave節點上執行,只有select語句操作,其他操作均由主master的二進制文件決定;MyCat支持雙主多從,多主多從情況需要配置多個writeHost兄弟節點,多個readHost節點即可!
Mycat的架構其實很好理解,Mycat是數據庫代理中間件,Mycat后面就是物理數據庫。和Web服務器的Nginx類似。對於使用者來說,訪問的都是Mycat,不會接觸到后端的數據庫。如下案例是做一個主從、讀寫分離,簡單分庫分表的示例。結構如下圖:
服務器信息如下(實驗環境,關閉機器的iptables防火牆和selinux):
1
2
3
4
5
6
7
8
9
10
11
12
|
服務器主機名 ip 說明
Mycat-node 192.168.10.210 mycat服務器,連接數據庫時,連接此服務器
Mysql-node1 192.168.10.205 物理數據庫1,真正存儲數據的數據庫,這里為Master主數據庫
Mysql-node2 192.168.10.206 物理數據庫2,真正存儲數據的數據庫,這里為Slave主數據庫
三台機器分布修改主機名,並做hosts綁定
# vim /etc/hosts
192.168.10.205 Mysql-node1
192.168.10.206 Mysql-node1
192.168.10.210 Mycat-node
為方便做實驗,關閉三台機器的iptables防火牆和selinux
|
Mycat作為主數據庫中間件,肯定是與代碼弱關聯的,所以代碼是不用修改的,使用Mycat后,連接數據庫是不變的,默認端口是8066。連接方式和普通數據庫一樣,比如:jdbc:mysql://192.168.10.210:8066/
1)Mysql安裝及主從復制部署(Mysql-node1和Mysql-node2兩台機器上操作)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
|
a)安裝Mysql,安裝過程要在兩個Mysql節點機器上都要操作。
安裝過程參考:http:
//www
.cnblogs.com
/kevingrace/p/6109679
.html
這里省去安裝過程~~
b)Mysql主從復制(兩個節點的mysql登錄用戶名和密碼都是root
/123456
)
參考:http:
//www
.cnblogs.com
/kevingrace/p/6256603
.html
====================================================
首先是Mysql-node1主節點配置操作
[root@Mysql-node1 ~]
# cp /usr/local/mysql/my.cnf /usr/local/mysql/my.cnf.bak
[root@Mysql-node1 ~]
# vim /usr/local/mysql/my.cnf #在[mysqld]區域添加下面內容
......
[mysqld]
server-
id
=1
log-bin=mysql-bin
#binlog-do-db=kevin #需要同步的數據庫。如果是多個同步庫,就以此格式另寫幾行即可。如果不指明對某個具體庫同步,就去掉此行,表示同步所有庫(除了ignore忽略的庫)
binlog-ignore-db = mysql,information_schema
sync_binlog = 1
binlog_checksum = none
binlog_format = mixed
重啟mysql服務
[root@Mysql-node1 ~]
# /etc/init.d/mysql restart
登錄mysql,授予slave從機復制權限
mysql> grant replication slave,replication client on *.* to slave@
'192.168.10.206'
identified by
"slave@123"
;
Query OK, 0 rows affected (0.05 sec)
mysql> flush privileges;
Query OK, 0 rows affected (0.06 sec)
授權之后,要保證192.168.10.206這台slave節點機器能使用上面的權限信息登錄到本機的mysql
將數據庫鎖住,僅僅允許讀,以保證數據一致性;
mysql> FLUSH TABLES WITH READ LOCK;
#注意,鎖定后,如果自己同步對方數據,同步前一定要記得先解鎖!
Query OK, 0 rows affected (0.00 sec)
mysql> flush privileges;
Query OK, 0 rows affected (0.05 sec)
查看主節點的master復制信息
mysql> show master status;
+------------------+----------+--------------+--------------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+--------------------------+-------------------+
| mysql-bin.000003 | 1349 | | mysql,information_schema | |
+------------------+----------+--------------+--------------------------+-------------------+
1 row
in
set
(0.00 sec)
====================================================
接着是slave從節點操作
[root@Mysql-node2 ~]
# cp /usr/local/mysql/my.cnf /usr/local/mysql/my.cnf.bak
[root@Mysql-node2 ~]
# vim /usr/local/mysql/my.cnf
.......
[mysqld]
.......
server-
id
=2
log-bin=mysql-bin
#replicate-do-db=kevin #需要同步的數據庫名。如果不指明同步哪些庫,就去掉這行,表示所有庫的同步(除了ignore忽略的庫)。
replicate-ignore-db=mysql
slave-skip-errors = all
重啟mysql服務
[root@Mysql-node2 ~]
# /etc/init.d/mysql restart
登錄slave節點的mysql,進行主從同步設置
mysql> stop slave;
Query OK, 0 rows affected (0.09 sec)
mysql> change master to master_host=
'192.168.10.205'
,master_user=
'slave'
,master_password=
'slave@123'
,master_log_file=
'mysql-bin.000003'
,master_log_pos=1349;
Query OK, 0 rows affected, 2 warnings (0.21 sec)
mysql> start slave;
Query OK, 0 rows affected (0.02 sec)
mysql> show slave status \G;
*************************** 1. row ***************************
Slave_IO_State: Waiting
for
master to send event
Master_Host: 192.168.10.205
Master_User: slave
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin.000003
Read_Master_Log_Pos: 1349
Relay_Log_File: mysql-relay-bin.000002
Relay_Log_Pos: 283
Relay_Master_Log_File: mysql-bin.000003
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Replicate_Do_DB:
Replicate_Ignore_DB: mysql
Replicate_Do_Table:
Replicate_Ignore_Table:
Replicate_Wild_Do_Table:
Replicate_Wild_Ignore_Table:
Last_Errno: 0
Last_Error:
Skip_Counter: 0
Exec_Master_Log_Pos: 1349
Relay_Log_Space: 456
Until_Condition: None
Until_Log_File:
Until_Log_Pos: 0
Master_SSL_Allowed: No
Master_SSL_CA_File:
Master_SSL_CA_Path:
Master_SSL_Cert:
Master_SSL_Cipher:
Master_SSL_Key:
Seconds_Behind_Master: 0
Master_SSL_Verify_Server_Cert: No
Last_IO_Errno: 0
Last_IO_Error:
Last_SQL_Errno: 0
Last_SQL_Error:
Replicate_Ignore_Server_Ids:
Master_Server_Id: 1
Master_UUID: 747977ea-8fba-11e8-86c0-525400b19c93
Master_Info_File:
/data/mysql/data/master
.info
SQL_Delay: 0
SQL_Remaining_Delay: NULL
Slave_SQL_Running_State: Slave has
read
all relay log; waiting
for
the slave I
/O
thread to update it
Master_Retry_Count: 86400
Master_Bind:
Last_IO_Error_Timestamp:
Last_SQL_Error_Timestamp:
Master_SSL_Crl:
Master_SSL_Crlpath:
Retrieved_Gtid_Set:
Executed_Gtid_Set:
Auto_Position: 0
1 row
in
set
(0.00 sec)
ERROR:
No query specified
mysql>
=========================================================
通過上面的信息,可知主從復制環境已經OK(Slave_IO_Running和Slave_SQL_Running狀態均為YES),下面驗證下主從復制是否正常?
在Mysql-node1主節點上操作
mysql> unlock tables;
Query OK, 0 rows affected (0.00 sec)
mysql> CREATE DATABASE kevin CHARACTER SET utf8 COLLATE utf8_general_ci;
Query OK, 1 row affected (0.06 sec)
mysql> use kevin;
Database changed
mysql> create table
if
not exists haha (
id
int(10) PRIMARY KEY AUTO_INCREMENT,name varchar(50) NOT NULL);
Query OK, 0 rows affected (0.34 sec)
在Mysql-node2從節點上查看(保證從節點上查看slave狀態時,Slave_IO_Running和Slave_SQL_Running狀態均為YES,這樣就能保證主從復制在進行中)
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| kevin |
| mysql |
| performance_schema |
|
test
|
+--------------------+
5 rows
in
set
(0.00 sec)
mysql> use kevin;
Reading table information
for
completion of table and column names
You can turn off this feature to get a quicker startup with -A
Database changed
mysql> show tables;
+-----------------+
| Tables_in_kevin |
+-----------------+
| haha |
+-----------------+
1 row
in
set
(0.00 sec)
接着在Mysql-node1主節點插入數據
mysql> insert into kevin.haha values(1,
"wangshibo"
),(2,
"linan"
),(3,
"zhangminmin"
);
Query OK, 3 rows affected (0.04 sec)
Records: 3 Duplicates: 0 Warnings: 0
然后再在MYsql-node2從節點查看,如下發現已經同步過來了!
mysql> use kevin;
Database changed
mysql> show tables;
+-----------------+
| Tables_in_kevin |
+-----------------+
| haha |
+-----------------+
1 row
in
set
(0.00 sec)
mysql>
select
* from haha;
+----+-------------+
|
id
| name |
+----+-------------+
| 1 | wangshibo |
| 2 | linan |
| 3 | zhangminmin |
+----+-------------+
3 rows
in
set
(0.00 sec)
由此可見,Mysql的主從復制已經實現!
|
2)Mycat中間件安裝、配置和測試(Mycat-node節點機器上操作)
2.1)Mycat安裝
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
建議下載1.6-RELEASE 版本,畢竟是比較穩定的版本。
下載官網地址:http:
//dl
.mycat.io/
[root@Mycat-node ~]
# cd /usr/local/src/
[root@Mycat-node src]
# wget http://dl.mycat.io/1.6-RELEASE/Mycat-server-1.6-RELEASE-20161028204710-linux.tar.gz
[root@Mycat-node src]
# tar -zvxf Mycat-server-1.6-RELEASE-20161028204710-linux.tar.gz
[root@Mycat-node src]
# mv mycat /data/
[root@Mycat-node src]
# ls /data/mycat/
bin catlet conf lib logs version.txt
mycat安裝完成后,目錄如下:
bin mycat命令,啟動、重啟、停止等
catlet catlet為Mycat的一個擴展功能
conf Mycat 配置信息,重點關注
lib Mycat引用的jar包,Mycat是java開發的
logs 日志文件,包括Mycat啟動的日志和運行的日志。
Mycat的配置文件都在conf目錄里面,這里介紹幾個常用的文件:
server.xml Mycat的配置文件,設置賬號、參數等
schema.xml Mycat對應的物理數據庫和數據庫表的配置
rule.xml Mycat分片(分庫分表)規則
[root@Mycat-node src]
# cd /data/mycat/conf
[root@Mycat-node conf]
# ll server.xml
-rwxrwxrwx. 1 root root 3740 Jul 25 12:19 server.xml
[root@Mycat-node conf]
# ll schema.xml
-rwxrwxrwx. 1 root root 4667 Jul 31 02:54 schema.xml
|
2.2)Mycat相關配置
server.xml文件其實跟讀寫分離策略關系不大,但是需要用此文件來配置連接MyCat的用戶及權限等,因此在這里簡單說明。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
|
[root@Mycat-node conf]
# cp server.xml server.xml.bak
[root@Mycat-node conf]
# vim server.xml
.......
<user name=
"bobo"
>
<property name=
"password"
>bo@123<
/property
>
<property name=
"schemas"
>mycat
/property
>
<!-- 表級 DML 權限設置 -->
<!--
<privileges check=
"false"
>
<schema name=
"TESTDB"
dml=
"0110"
>
<table name=
"tb01"
dml=
"0000"
><
/table
>
<table name=
"tb02"
dml=
"1111"
><
/table
>
<
/schema
>
<
/privileges
>
-->
<
/user
>
<!--
#注意,由於這里只定義了一個標簽,所以把多余的都注釋了。如果這個打開,也需要將TESTDB庫改為和上面一樣的mycat庫名。
<user name=
"user"
>
<property name=
"password"
>user<
/property
>
<property name=
"schemas"
>TESTDB<
/property
>
<property name=
"readOnly"
>
true
<
/property
>
<
/user
>
-->
<
/mycat
:server>
.......
重點關注上面這段配置,其他默認即可。
=======================================
參數 說明
user 用戶配置節點
name 登錄的用戶名,也就是連接Mycat的用戶名。
password 登錄的密碼,也就是連接Mycat的密碼
schemas 數據庫名,這里會和schema.xml中的配置關聯,多個用逗號分開,例如需要這個用戶需要管理兩個數據庫db1,db2,則配置db1,dbs
privileges 配置用戶針對表的增刪改查的權限
readOnly mycat邏輯庫所具有的權限。
true
為只讀,
false
為讀寫都有,默認為
false
。
=======================================
我這里配置了一個賬號boo,密碼為bo@123,邏輯數據庫為mycat,這些信息都可以自己隨意定義,讀寫權限都有,沒有針對表做任何特殊的權限。
注意:
- server.xml文件里登錄mycat的用戶名和密碼可以任意定義,這個賬號和密碼是為客戶機登錄mycat時使用的賬號信息。
- 邏輯庫名(如上面的mycat,也就是登錄mycat后顯示的庫名,切換這個庫之后,顯示的就是代理的真實mysql數據庫的表)要在schema.xml里面也定義,否則會導致mycat服務啟動失敗!
- 這里只定義了一個標簽,所以把多余的都注釋了。如果定義多個標簽,即設置多個連接mycat的用戶名和密碼,那么就需要在schema.xml文件中定義多個對應的庫!
|
schema.xml是最主要的配置項,此文件關聯mysql讀寫分離策略!讀寫分離、分庫分表策略、分片節點都是在此文件中配置的!
MyCat作為中間件,它只是一個代理,本身並不進行數據存儲,需要連接后端的MySQL物理服務器,此文件就是用來連接MySQL服務器的!
schemaxml文件中配置的參數解釋
1
2
3
4
|
參數 說明
schema 數據庫設置,此數據庫為邏輯數據庫,name與server.xml中schema對應
dataNode 分片信息,也就是分庫相關配置
dataHost 物理數據庫,真正存儲數據的數據庫
|
配置說明
1
2
3
4
|
name屬性唯一標識dataHost標簽,供上層的標簽使用。
maxCon屬性指定每個讀寫實例連接池的最大連接。也就是說,標簽內嵌套的
writeHost、readHost標簽都會使用這個屬性的值來實例化出連接池的最大連接數。
minCon屬性指定每個讀寫實例連接池的最小連接,初始化連接池的大小。
|
每個節點的屬性逐一說明
1
2
3
4
5
|
schema:
屬性 說明
name 邏輯數據庫名,與server.xml中的schema對應
checkSQLschema 數據庫前綴相關設置,建議看文檔,這里暫時設為folse
sqlMaxLimit
select
時默認的limit,避免查詢全表
|
table
1
2
3
4
5
6
|
屬性 說明
name 表名,物理數據庫中表名
dataNode 表存儲到哪些節點,多個節點用逗號分隔。節點為下文dataNode設置的name
primaryKey 主鍵字段名,自動生成主鍵時需要設置
autoIncrement 是否自增
rule 分片規則名,具體規則下文rule詳細介紹
|
dataNode
1
2
3
4
|
屬性 說明
name 節點名,與table中dataNode對應
datahost 物理數據庫名,與datahost中name對應
database 物理數據庫中數據庫名
|
dataHost
1
2
3
4
5
6
|
屬性 說明
name 物理數據庫名,與dataNode中dataHost對應
balance 均衡負載的方式
writeType 寫入方式
dbType 數據庫類型
heartbeat 心跳檢測語句,注意語句結尾的分號要加
|
schema.xml文件中有三點需要注意:balance="1",writeType="0" ,switchType="1"
schema.xml中的balance的取值決定了負載均衡對非事務內的讀操作的處理。balance 屬性負載均衡類型,目前的取值有 4 種:
1
2
3
4
5
6
7
8
9
10
|
balance=
"0"
: 不開啟讀寫分離機制,所有讀操作都發送到當前可用的writeHost 上,即讀請求僅發送到writeHost上。
balance=
"1"
: 讀請求隨機分發到當前writeHost對應的readHost和standby的writeHost上。即全部的readHost與stand by writeHost 參與
select
語句的負載均衡,簡單的說,當雙主雙從模式(M1 ->S1 , M2->S2,並且 M1 與 M2 互為主備),正常情況下, M2,S1,
S2 都參與
select
語句的負載均衡
balance=
"2"
: 讀請求隨機分發到當前dataHost內所有的writeHost和readHost上。即所有讀操作都隨機的在writeHost、 readhost 上分發。
balance=
"3"
: 讀請求隨機分發到當前writeHost對應的readHost上。即所有讀請求隨機的分發到 wiriterHost 對應的 readhost 執行,
writerHost 不負擔讀壓力,注意 balance=3 只在 1.4 及其以后版本有,1.3 沒有。
|
writeType 屬性,負載均衡類型,目前的取值有 3 種
1
2
3
|
writeType=
"0"
所有寫操作發送到配置的第一個 writeHost,第一個掛了切到還生存的第二個writeHost,重新啟動后已切換后的為准,切換記錄在配置文件中:dnindex.properties .
writeType=
"1"
所有寫操作都隨機的發送到配置的 writeHost。
writeType=
"2"
沒實現。
|
對於事務內的SQL默認走寫節點
1
2
3
4
5
|
以 /*balance*/ 開頭,可以指定SQL使用特定負載均衡方案。例如在大環境開啟讀寫分離的情況下,特定強一致性的SQL查詢需求;
slaveThreshold:近似的主從延遲時間(秒)Seconds_Behind_Master < slaveThreshold ,讀請求才會分發到該Slave,確保讀到的數據相對較新。
schema.xml中的writeType的取值決定了負載均衡對寫操作的處理:
writeType=
"0"
:所有的寫操作都發送到配置文件中的第一個write host。(第一個write host故障切換到第二個后,即使之后修復了仍然維持第二個為寫庫)。推薦取0值,不建議修改.
|
主從切換(雙主failover):switchType 屬性
1
2
3
4
5
6
7
8
|
如果細心觀察schem.xml文件的話,會發現有一個參數:switchType,如下配置:
<dataHost name=
"237_15"
maxCon=
"1000"
minCon=
"10"
balance=
"1"
writeType=
"0"
dbType=
"mysql"
dbDriver=
"native"
switchType=
"1"
slaveThreshold=
"100"
>
參數解讀
switchType=
"-1"
: 不自動切換
switchType=
"1"
: 默認值,自動切換
switchType=
"2"
: 基於MySQL主從同步的狀態來決定是否切換。需修改heartbeat語句(即心跳語句):show slave status
switchType=
"3"
: 基於Mysql Galera Cluster(集群多節點復制)的切換機制。需修改heartbeat語句(即心跳語句):show status like
'wsrep%'
|
dbType屬性
1
|
指定后端連接的數據庫類型,目前支持二進制的mysql協議,還有其他使用JDBC連接的數據庫。例如:mongodb、oracle、spark等。
|
dbDriver屬性指定連接后端數據庫使用的
1
2
3
4
5
6
7
|
Driver,目前可選的值有native和JDBC。
使用native的話,因為這個值執行的是二進制的mysql協議,所以可以使用mysql和maridb。
其他類型的數據庫則需要使用JDBC驅動來支持。從1.6版本開始支持postgresql的native原始協議。
如果使用JDBC的話需要將符合JDBC 4標准的驅動JAR包放到MYCAT\lib目錄下,並檢查驅動JAR包中包括如下目錄結構的文件:
META-INF\services\java.sql.Driver。在這個文件內寫上具體的Driver類名,例如:com.mysql.jdbc.Driver。
|
heartbeat標簽
1
2
3
4
5
6
|
這個標簽內指明用於和后端數據庫進行心跳檢查的語句。例如,MYSQL可以使用
select
user(),Oracle可以使用
select
1 from dual等。
這個標簽還有一個connectionInitSql屬性,主要是當使用Oracla數據庫時,需要執行的初始化SQL
語句就這個放到這里面來。例如:altersession
set
nls_date_format=
'yyyy-mm-dd hh24:mi:ss'
1.4主從切換的語句必須是:showslave status
|
writeHost標簽、readHost標簽
1
2
3
4
5
6
|
這兩個標簽都指定后端數據庫的相關配置給mycat,用於實例化后端連接池。
唯一不同的是:writeHost指定寫實例、readHost指定讀實例,組着這些讀寫實例來滿足系統的要求。
在一個dataHost內可以定義多個writeHost和readHost。但是,如果writeHost指定的后端數據庫宕機,那么這個writeHost綁定的所有readHost都將不可用。
另一方面,由於這個writeHost宕機系統會自動的檢測到,並切換到備用的writeHost上去。
|
應用場景1--->Mycat讀寫分離(負載均衡)、主從自動切換
目前有大量Mycat的生產實踐案例是屬於簡單的讀寫分離類型的,此案例主要用到Mycat的以下特性:
- 讀寫分離支持
- 高可用
大多數讀寫分離的案例是同時支持高可用性的,即Mycat+MySQL主從復制的集群,並開啟Mycat的讀寫分離功能,這種場景需求下,Mycat是最為簡單並且功能最為
豐富的一類Proxy,正常情況下,配置文件也最為簡單,不用每個表配置,只需要在schema.xml中的元素上增加dataNode=“defaultDN”屬性,並配置此dataNode
對應的真實物理數據庫的database,然后dataHost開啟讀寫分離功能即可。
修改mycat的schema.xml:
balance為1:讓全部的readHost及備用的writeHost參與select的負載均衡。
switchType為2:基於MySQL主從同步的狀態決定是否切換。
heartbeat:主從切換的心跳語句必須為show slave status。
僅僅進行讀寫分離的schema.xml配置(備份原來的schema.xml文件,清空,直接復制下面內容):不想要自動切換功能,即MySQL寫節點宕機后不自動切換到備用節點:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
[root@Mycat-node conf]
# vim schema.xml
<?xml version=
"1.0"
?>
<!DOCTYPE mycat:schema SYSTEM
"schema.dtd"
>
<mycat:schema xmlns:mycat=
"http://io.mycat/"
>
<schema name=
"mycat"
checkSQLschema=
"false"
sqlMaxLimit=
"100"
dataNode=
"haha"
>
<
/schema
>
<dataNode name=
"haha"
dataHost=
"Mycat-node"
database=
"kevin"
/>
<dataHost name=
"Mycat-node"
maxCon=
"1000"
minCon=
"10"
balance=
"1"
writeType=
"0"
dbType=
"mysql"
dbDriver=
"native"
switchType=
"1"
slaveThreshold=
"100"
>
<heartbeat>show slave status<
/heartbeat
>
<writeHost host=
"Mysql-node1"
url=
"192.168.10.205:3306"
user=
"root"
password=
"123456"
>
<readHost host=
"Mysql-node2"
url=
"192.168.10.206:3306"
user=
"root"
password=
"123456"
>
<
/readHost
>
<
/writeHost
>
<
/dataHost
>
<
/mycat
:schema>
|
實現主從自動切換的schema.xml配置:即MySQL寫節點宕機后自動切換到備用節點(也就是把從機也配置成writeHosts):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
[root@Mycat-node conf]
# vim schema.xml
<?xml version=
"1.0"
?>
<!DOCTYPE mycat:schema SYSTEM
"schema.dtd"
>
<mycat:schema xmlns:mycat=
"http://io.mycat/"
>
<schema name=
"mycat"
checkSQLschema=
"false"
sqlMaxLimit=
"100"
dataNode=
"haha"
>
<
/schema
>
<dataNode name=
"haha"
dataHost=
"Mycat-node"
database=
"kevin"
/>
<dataHost name=
"Mycat-node"
maxCon=
"1000"
minCon=
"10"
balance=
"1"
writeType=
"0"
dbType=
"mysql"
dbDriver=
"native"
switchType=
"1"
slaveThreshold=
"100"
>
<heartbeat>show slave status<
/heartbeat
>
<writeHost host=
"Mysql-node1"
url=
"192.168.10.205:3306"
user=
"root"
password=
"123456"
>
<readHost host=
"Mysql-node2"
url=
"192.168.10.206:3306"
user=
"root"
password=
"123456"
>
<
/readHost
>
<
/writeHost
>
<writeHost host=
"Mysql-node2"
url=
"192.168.10.206:3306"
user=
"root"
password=
"123456"
>
<
/writeHost
>
<
/dataHost
>
<
/mycat
:schema>
|
上面配置中,balance改為1,表示讀寫分離。
以上配置達到的效果就是192.168.10.205為主庫,192.168.10.206為從庫。
注意:要保證192.168.10.205和192.168.10.206機器能使用root/123456權限成功登錄mysql數據庫。同時,也一定要授權mycat機器能使用root/123456權限成功登錄這兩台機器的mysql數據庫!!這很重要,否則會導致登錄mycat后,對庫和表操作失敗!
一主一從結構是最簡單的配置。
MyCat支持雙主多從,如果有N個主,那么就配置N個writeHost兄弟節點;如果有M個從節點,那么就配置M個readHost節點即可。
也可以有多台MySQL服務器,或者SQL Server、Oracle等,配置多個dataHost節點就可以。
需要注意的是:
Mycat主從分離只是在讀的時候做了處理,寫入數據的時候,只會寫入到writehost,需要通過mycat的主從復制將數據復制到readhost!這個問題需要弄明白!!
如果沒有提前做mysql主從復制,會發現Mycat讀寫分離配置后,數據寫入writehost后,readhost一直沒有數據!因為Mycat就沒有實現主從復制的功能,畢竟數據庫本身自帶的這個功能才是最高效穩定的。
特別注意:
1
2
3
4
5
6
7
8
9
10
11
|
1)本案例采用的一主一從模式的兩個mysql實例,並且針對單一的數據庫名進行測試;大多數mycat使用場景都是在多主多從模式並針對多個庫進行的。
2)要想登錄Mycat后看到mysql的真實數據庫的表內容,需要在schema.xml文件中指明database,其中dataNote和dataHost名稱可以自定義,database名稱要是mysql上的庫名。
3)如果針對的是mysql的多個庫,比如mysql的真實庫名是kevin、grace、shanshan,那么schema.xml文件里應該指明多個庫名,如:
<schema name=
"mycat"
checkSQLschema=
"false"
sqlMaxLimit=
"100"
dataNode=
"haha,heihei,hengheng"
>
<
/schema
>
<dataNode name=
"haha"
dataHost=
"Mycat-node"
database=
"kevin"
/>
<dataNode name=
"heihei"
dataHost=
"Mycat-node"
database=
"grace"
/>
<dataNode name=
"hengheng"
dataHost=
"Mycat-node"
database=
"shanshan"
/>
........
4)主從自動切換配置后,第一個writeHost故障后,會自動切換到第二個,第二個故障后自動切換到第三個;
如果當是1主3從模式,可以把第1個從節點配置為writeHost 2,第2個和第3個從節點則配置為writeHost 1的readHost;
|
Mycat服務啟動
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
[root@Mycat-node ~]
# cd /data/mycat/bin/
[root@Mycat-node bin]
#
[root@Mycat-node bin]
# ./mycat start #開啟
[root@Mycat-node bin]
# ./mycat stop #關閉
[root@Mycat-node bin]
# ./mycat restart #重啟
[root@Mycat-node bin]
# ./mycat status #查看啟動狀態
[root@Mycat-node bin]
# ./mycat console #前台運行
[root@Mycat-node bin]
# ./mycat pause #暫停
mycat啟動后,執行命令不成功,可能實際上配置有錯誤,導致后面的命令沒有很好的執行。
如果在啟動時發現異常,在logs目錄中查看日志。
[root@Mycat-node ~]
# cd /data/mycat/logs/
[root@Mycat-node logs]
# ls
2018-07 mycat.log mycat.pid wrapper.log
- wrapper.log 為程序啟動的日志,啟動時的問題看這個
- mycat.log 為腳本執行時的日志,SQL腳本執行報錯后的具體錯誤內容,查看這個文件。mycat.log是最新的錯誤日志,歷史日志會根據時間生成目錄保存。
[root@Mycat-node conf]
# cd /data/mycat/bin/
[root@Mycat-node bin]
# ./mycat start
Starting Mycat-server...
[root@Mycat-node bin]
# ps -ef|grep cat
root 5693 1 0 11:28 ? 00:00:00
/data/mycat/bin/
.
/wrapper-linux-x86-64
/data/mycat/conf/wrapper
.conf wrapper.syslog.ident=mycat wrapper.pidfile=
/data/mycat/logs/mycat
.pid wrapper.daemonize=TRUE wrapper.lockfile=
/var/lock/subsys/mycat
root 5695 5693 58 11:28 ? 00:00:01 java -DMYCAT_HOME=. -server -XX:MaxPermSize=64M -XX:+AggressiveOpts -XX:MaxDirectMemorySize=2G -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=1984 -Dcom.sun.management.jmxremote.authenticate=
false
-Dcom.sun.management.jmxremote.ssl=
false
-Xmx4G -Xms1G -Djava.library.path=lib -classpath lib
/wrapper
.jar:conf:lib
/zookeeper-3
.4.6.jar:lib
/velocity-1
.7.jar:lib
/disruptor-3
.3.4.jar:lib
/hamcrest-library-1
.3.jar:lib
/curator-client-2
.11.0.jar:lib
/mysql-binlog-connector-java-0
.4.1.jar:lib
/curator-framework-2
.11.0.jar:lib
/wrapper
.jar:lib
/log4j-1
.2.17.jar:lib
/kryo-2
.10.jar:lib
/objenesis-1
.2.jar:lib
/log4j-core-2
.5.jar:lib
/log4j-1
.2-api-2.5.jar:lib
/log4j-slf4j-impl-2
.5.jar:lib
/leveldb-api-0
.7.jar:lib
/minlog-1
.2.jar:lib
/mongo-java-driver-2
.11.4.jar:lib
/netty-3
.7.0.Final.jar:lib
/sequoiadb-driver-1
.12.jar:lib
/libwrapper-linux-x86-64
.so:lib
/curator-recipes-2
.11.0.jar:lib
/dom4j-1
.6.1.jar:lib
/commons-lang-2
.6.jar:lib
/guava-19
.0.jar:lib
/commons-collections-3
.2.1.jar:lib
/reflectasm-1
.03.jar:lib
/slf4j-api-1
.6.1.jar:lib
/joda-time-2
.9.3.jar:lib
/jline-0
.9.94.jar:lib
/libwrapper-linux-x86-32
.so:lib
/leveldb-0
.7.jar:lib
/Mycat-server-1
.6-RELEASE.jar:lib
/jsr305-2
.0.3.jar:lib
/libwrapper-linux-ppc-64
.so:lib
/univocity-parsers-2
.2.1.jar:lib
/hamcrest-core-1
.3.jar:lib
/log4j-api-2
.5.jar:lib
/asm-4
.0.jar:lib
/mapdb-1
.0.7.jar:lib
/fastjson-1
.2.12.jar:lib
/druid-1
.0.26.jar:lib
/ehcache-core-2
.6.11.jar -Dwrapper.key=ZcN0KgylpD8RMkUx -Dwrapper.port=32000 -Dwrapper.jvm.port.min=31000 -Dwrapper.jvm.port.max=31999 -Dwrapper.pid=5693 -Dwrapper.version=3.2.3 -Dwrapper.native_library=wrapper -Dwrapper.service=TRUE -Dwrapper.cpu.timeout=10 -Dwrapper.jvmid=1 org.tanukisoftware.wrapper.WrapperSimpleApp io.mycat.MycatStartup start
root 5729 24581 0 11:29 pts
/0
00:00:00
grep
cat
Mycat服務端口默認是8066
[root@Mycat-node bin]
# lsof -i:8066
COMMAND PID USER FD TYPE DEVICE SIZE
/OFF
NODE NAME
java 5695 root 79u IPv6 37036522 0t0 TCP *:8066 (LISTEN)[root@Mycat-node conf]
# lsof -i:9066
Mycat還有一個管理端口,默認是9066
[root@Mycat-node conf]
# lsof -i:9066
COMMAND PID USER FD TYPE DEVICE SIZE
/OFF
NODE NAME
java 5695 root 75u IPv6 37036520 0t0 TCP *:9066 (LISTEN)
|
在客戶機遠程登錄Mycat登錄mysql(將mycat啟動起來后,遠程連接,默認端口是8066,邏輯庫名和賬號密碼就是在schema.xml里配置的信息。代碼里用jdbc方式連接)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
|
Mycat帶來的最大好處就是:
使用是完全不用修改原有代碼的,在mycat通過命令啟動后,你只需要將數據庫連接切換到Mycat的地址就可以了。
如下面就可以進行連接了(注意使用server.xml文件中定義的用戶名和密碼連接mycat)
登錄mycat的前提是:兩台mysql機器要授權mycat服務器使用root
/123456
成功登錄這兩個mysql。
[root@client-server ~]
# mysql -h192.168.10.210 -P8066 -ubobo -pbo@123
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection
id
is 1
Server version: 5.6.29-mycat-1.6-RELEASE-20161028204710 MyCat Server (OpenCloundDB)
Copyright (c) 2000, 2013, Oracle and
/or
its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and
/or
its
affiliates. Other names may be trademarks of their respective
owners.
Type
'help;'
or
'\h'
for
help. Type
'\c'
to
clear
the current input statement.
mysql> show databases;
+----------+
| DATABASE |
+----------+
| mycat |
+----------+
1 row
in
set
(0.01 sec)
mysql> use mycat;
Reading table information
for
completion of table and column names
You can turn off this feature to get a quicker startup with -A
Database changed
mysql> show tables;
+-----------------+
| Tables_in_kevin |
+-----------------+
| haha |
+-----------------+
1 row
in
set
(0.00 sec)
mysql>
select
* from haha;
+----+-------------+
|
id
| name |
+----+-------------+
| 1 | wangshibo |
| 2 | linan |
| 3 | zhangminmin |
+----+-------------+
3 rows
in
set
(0.00 sec)
mysql>
|
Mycat讀寫分離測試
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
|
將mycat的日志輸出級別改完debug(默認是info級別),在conf
/log4j2
.xml里配置,然后去查詢去添加數據在
/logs/mycat
.log日志文件里查看sql被路由到了
哪個服務器上
特別注意:查詢語句不要加事務,否則讀操作會被分發到寫服務器上。
[root@Mycat-node ~]
# vim /data/mycat/conf/log4j2.xml
......
把
<asyncRoot level=
"info"
includeLocation=
"true"
>
改成
<asyncRoot level=
"debug"
includeLocation=
"true"
>
重啟mycat服務
[root@Mycat-node ~]
# /data/mycat/bin/mycat restart
Stopping Mycat-server...
Stopped Mycat-server.
Starting Mycat-server...
[root@Mycat-node ~]
# lsof -i:8066
COMMAND PID USER FD TYPE DEVICE SIZE
/OFF
NODE NAME
java 18955 root 79u IPv6 3812293 0t0 TCP *:8066 (LISTEN)
登錄mycat
[root@client-server ~]
# mysql -h192.168.10.210 -P8066 -ubobo -pbo@123
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection
id
is 2
Server version: 5.6.29-mycat-1.6-RELEASE-20161028204710 MyCat Server (OpenCloundDB)
Copyright (c) 2000, 2013, Oracle and
/or
its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and
/or
its
affiliates. Other names may be trademarks of their respective
owners.
Type
'help;'
or
'\h'
for
help. Type
'\c'
to
clear
the current input statement.
mysql> show databases;
+----------+
| DATABASE |
+----------+
| mycat |
+----------+
1 row
in
set
(0.00 sec)
mysql> use mycat;
Reading table information
for
completion of table and column names
You can turn off this feature to get a quicker startup with -A
Database changed
mysql> show tables;
+-----------------+
| Tables_in_kevin |
+-----------------+
| haha |
+-----------------+
1 row
in
set
(0.00 sec)
mysql>
select
* from haha;
+----+-------------+
|
id
| name |
+----+-------------+
| 1 | wangshibo |
| 2 | linan |
| 3 | zhangminmin |
+----+-------------+
3 rows
in
set
(0.00 sec)
mysql>
通過mycat寫入一條數據或讀數據,查看sql被路由到了代理的哪個mysql服務器上了:
mysql> insert into kevin.haha values(4,
"lihuan"
);
Query OK, 1 row affected (0.31 sec)
mysql>
select
* from haha;
+----+-------------+
|
id
| name |
+----+-------------+
| 1 | wangshibo |
| 2 | linan |
| 3 | zhangminmin |
| 4 | lihuan |
+----+-------------+
4 rows
in
set
(0.01 sec)
mysql>
然后查看mycat.log的debug日志,觀察mysql的sql被路由到了哪個服務器上了(下面日志中的192.168.10.203是遠程客戶機的ip地址)。
[root@Mycat-node ~]
# tail -f /data/mycat/logs/mycat.log
.......
2018-07-31 08:50:12.616 DEBUG [$_NIOREACTOR-1-RW] (io.mycat.server.NonBlockingSession.execute(NonBlockingSession.java:110)) - ServerConnection
[
id
=2, schema=mycat, host=192.168.10.203, user=bobo,txIsolation=3, autocommit=
true
, schema=mycat]insert into kevin.haha values(4,
"lihuan"
),
route={
1 -> haha{insert into kevin.haha values(4,
"lihuan"
)}
.......
.......
2018-07-31 08:50:12.617 DEBUG [$_NIOREACTOR-1-RW] (io.mycat.backend.mysql.nio.MySQLConnection.synAndDoExecute(MySQLConnection.java:448)) -
con need syn ,total syn cmd 1 commands SET names latin1;schema change:
false
con:MySQLConnection [
id
=6, lastTime=1532998212617, user=root,
schema=kevin, old shema=kevin, borrowed=
true
, fromSlaveDB=
false
, threadId=55, charset=latin1, txIsolation=3, autocommit=
true
, attachment=
haha{insert into kevin.haha values(4,
"lihuan"
)}, respHandler=SingleNodeHandler [node=haha{insert into kevin.haha values(4,
"lihuan"
)}, packetId=0],
host=192.168.10.205, port=3306, statusSync=null, writeQueue=0, modifiedSQLExecuted=
true
]
.......
.......
2018-07-31 08:50:14.358 DEBUG [$_NIOREACTOR-0-RW] (io.mycat.server.NonBlockingSession.releaseConnection(NonBlockingSession.java:341)) -
release connection MySQLConnection [
id
=12, lastTime=1532998214353, user=root, schema=kevin, old shema=kevin, borrowed=
true
, fromSlaveDB=
true
,
threadId=29, charset=latin1, txIsolation=3, autocommit=
true
, attachment=haha{
select
* from haha}, respHandler=SingleNodeHandler [node=haha
{
select
* from haha}, packetId=8], host=192.168.10.206, port=3306, statusSync=null, writeQueue=0, modifiedSQLExecuted=
false
]
從日志中可以看出,
"insert into ...."
插入語句路由到了192.168.10.205的主機上了,
"select * ..."
的查詢語句路由到了192.168.10.206的從機上了。
這就實現了mysql的讀寫分離!!
|
Mycat主從自動切換測試(采用上面自動切換的schema.xml配置)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
|
首先關閉主機192.168.10.205的mysql服務,此時從機192.168.10.206的mysql已經失去了和主機192.168.10.205的mysql主從關系。
[root@Mysql-node1 ~]
# /etc/init.d/mysql stop
Shutting down MySQL............ SUCCESS!
[root@Mysql-node1 ~]
# lsof -i:3306
[root@Mysql-node1 ~]
#
[root@Mysql-node2 ~]
# mysql -p123456
........
mysql> show slave status \G;
*************************** 1. row ***************************
.......
Slave_IO_Running: Connecting
Slave_SQL_Running: Yes
.......
Last_IO_Error: error reconnecting to master
'slave@192.168.10.205:3306'
- retry-
time
: 60 retries: 1
然后客戶機登錄mycat進行讀寫操作
[root@client-server ~]
# mysql -h192.168.10.210 -P8066 -ubobo -pbo@123
......
mysql> use mycat;
Reading table information
for
completion of table and column names
You can turn off this feature to get a quicker startup with -A
Database changed
mysql> show tables;
+-----------------+
| Tables_in_kevin |
+-----------------+
| haha |
+-----------------+
1 row
in
set
(0.00 sec)
mysql>
select
* from haha;
+----+-------------+
|
id
| name |
+----+-------------+
| 1 | wangshibo |
| 2 | linan |
| 3 | zhangminmin |
| 4 | lihuan |
+----+-------------+
4 rows
in
set
(0.00 sec)
mysql> insert into kevin.haha values(5,
"gengmei"
);
Query OK, 1 row affected (0.00 sec)
mysql>
select
* from haha;
+----+-------------+
|
id
| name |
+----+-------------+
| 1 | wangshibo |
| 2 | linan |
| 3 | zhangminmin |
| 4 | lihuan |
| 5 | gengmei |
+----+-------------+
5 rows
in
set
(0.00 sec)
同時查看mycat.log的debug日志,觀察讀寫操作都被路由到哪里了:
[root@Mycat-node ~]
# tail -f /data/mycat/logs/mycat.log
.......
2018-07-31 09:10:19.261 INFO [$_NIOConnector] (io.mycat.net.AbstractConnection.close(AbstractConnection.java:508)) - close connection,reason:java.net.
ConnectException: Connection refused ,MySQLConnection [
id
=0, lastTime=1532999419254, user=root, schema=kevin, old shema=kevin, borrowed=
false
, fromSlaveDB=
false
,
threadId=0, charset=utf8, txIsolation=3, autocommit=
true
, attachment=null, respHandler=null, host=192.168.10.205, port=3306, statusSync=null, writeQueue=0,
modifiedSQLExecuted=
false
]
2018-07-31 09:10:19.261 INFO [$_NIOConnector] (io.mycat.sqlengine.SQLJob.connectionError(SQLJob.java:114)) - can't get connection
for
sql :show slave status
.......
2018-07-31 09:06:20.139 DEBUG [$_NIOREACTOR-1-RW] (io.mycat.server.NonBlockingSession.releaseConnection(NonBlockingSession.java:341)) -
release connection MySQLConnection [
id
=17, lastTime=1532999180134, user=root, schema=kevin, old shema=kevin, borrowed=
true
, fromSlaveDB=
false
,
threadId=46, charset=latin1, txIsolation=3, autocommit=
true
, attachment=haha{insert into kevin.haha values(5,
"gengmei"
)}, respHandler=SingleNodeHandler
[node=haha{insert into kevin.haha values(5,
"gengmei"
)}, packetId=1], host=192.168.10.206, port=3306, statusSync=null, writeQueue=0, modifiedSQLExecuted=
true
]
......
2018-07-31 09:06:21.727 DEBUG [$_NIOREACTOR-0-RW] (io.mycat.backend.mysql.nio.MySQLConnection.synAndDoExecute(MySQLConnection.java:448)) - con need syn ,total
syn cmd 1 commands SET names latin1;schema change:
false
con:MySQLConnection [
id
=16, lastTime=1532999181727, user=root, schema=kevin, old shema=kevin, borrowed
=
true
, fromSlaveDB=
false
, threadId=48, charset=latin1, txIsolation=3, autocommit=
true
, attachment=haha{
select
* from haha}, respHandler=SingleNodeHandler [node=
haha{
select
* from haha}, packetId=0], host=192.168.10.206, port=3306, statusSync=null, writeQueue=0, modifiedSQLExecuted=
false
]
從上面的日志中可以看出,主機192.168.10.205已經斷開從mycat連接,insert寫語句和
select
讀語句都被路由分配到了從機192.168.10.206的mysql上了,
這就看出來已經實現了mysql主從啟動切換了!!!
登錄從機192.168.10.206的mysql,發現新插入的數據已經寫進去了
[root@Mysql-node2 ~]
# mysql -p123456
.......
mysql> use kevin;
Reading table information
for
completion of table and column names
You can turn off this feature to get a quicker startup with -A
Database changed
mysql>
select
* from kevin.haha;
+----+-------------+
|
id
| name |
+----+-------------+
| 1 | wangshibo |
| 2 | linan |
| 3 | zhangminmin |
| 4 | lihuan |
| 5 | gengmei |
+----+-------------+
5 rows
in
set
(0.00 sec)
mysql>
|
Mycat分表分庫的原理
mycat里面通過定義路由規則來實現分片表(路由規則里面會定義分片字段,以及分片算法)。分片算法有多種,你所說的hash是其中一種,還有取模、按范圍分片等等。在mycat里面,會對所有傳遞的sql語句做路由處理(路由處理的依據就是表是否分片,如果分片,那么需要依據分片字段和對應的分片算法來判斷sql應該傳遞到哪一個、或者哪幾個、又或者全部節點去執行)
Mycat適用於哪些場景?
數據量大到單機hold不住,而又不希望調整架構切換為NoSQL數據庫,這個場景下可以考慮適用mycat。當然,使用前也應該做規划,哪些表需要分片等等。另外mycat對跨庫join的支持不是很好,在使用mycat的時候要注意規避這種場景。
應用場景2--->MYcat分庫分表配置及測試:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
|
接着上面的操作繼續:
啟動主機192.168.10.205的mysql
[root@Mysql-node1 ~]
# /etc/init.d/mysql start
Starting MySQL... SUCCESS!
[root@Mysql-node1 ~]
# lsof -i:3306
COMMAND PID USER FD TYPE DEVICE SIZE
/OFF
NODE NAME
mysqld 11645 mysql 17u IPv4 10457025 0t0 TCP *:mysql (LISTEN)
mysqld 11645 mysql 39u IPv4 10457749 0t0 TCP Mysql-node1:mysql->Mycat-node:39252 (ESTABLISHED)
mysqld 11645 mysql 40u IPv4 10458099 0t0 TCP Mysql-node1:mysql->Mysql-node1:57270 (ESTABLISHED)
登錄從機192.168.10.206的mysql,重啟slave的主從同步關系
[root@Mysql-node2 ~]
# mysql -p123456
......
mysql> show slave status \G;
......
Slave_IO_Running: Connecting
Slave_SQL_Running: Yes
......
Last_IO_Error: error reconnecting to master
'slave@192.168.10.205:3306'
- retry-
time
: 60 retries: 81
......
mysql> stop slave;
Query OK, 0 rows affected (0.08 sec)
mysql> start slave;
Query OK, 0 rows affected (0.04 sec)
mysql> show slave status \G;
......
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
.....
在主機192.168.10.205的mysql上再創建一個數據庫grace
現在需要將haha表放在kevin庫里,將heihei表拆分放到kevin和grace庫了。
操作如下(在主機mysql里操作,從機mysql自動會同步過來):
登錄grace庫里創建heihei表,同時在kevin庫里也創建heihei表。
特別需要注意的是:
- 分表的表在創建時一定要創建主鍵,否則在mycat端寫入數據時會報錯主鍵沖突!!
- 分表的表要在兩個庫上都要創建。
mysql> CREATE DATABASE grace CHARACTER SET utf8 COLLATE utf8_general_ci;
Query OK, 1 row affected (0.00 sec)
mysql> use grace;
Database changed
mysql> CREATE TABLE heihei (
->
id
INT NOT NULL AUTO_INCREMENT,
-> city varchar(50) NOT NULL,
-> PRIMARY KEY (
id
)
-> )AUTO_INCREMENT= 1 ENGINE=InnoDB DEFAULT CHARSET=utf8;
Query OK, 0 rows affected (0.23 sec)
mysql> insert into grace.heihei values(1,
"beijing"
);
Query OK, 1 row affected (0.03 sec)
mysql> show tables;
+-----------------+
| Tables_in_grace |
+-----------------+
| heihei |
+-----------------+
1 row
in
set
(0.00 sec)
mysql>
select
* from grace.heihei;
+----+---------+
|
id
| name |
+----+---------+
| 1 | beijing |
+----+---------+
1 row
in
set
(0.00 sec)
mysql> use kevin;
Reading table information
for
completion of table and column names
You can turn off this feature to get a quicker startup with -A
Database changed
mysql> show tables;
+-----------------+
| Tables_in_kevin |
+-----------------+
| haha |
+-----------------+
1 row
in
set
(0.00 sec)
mysql> CREATE TABLE heihei (
->
id
INT NOT NULL AUTO_INCREMENT,
-> city varchar(50) NOT NULL,
-> PRIMARY KEY (
id
)
-> )AUTO_INCREMENT= 1 ENGINE=InnoDB DEFAULT CHARSET=utf8;
Query OK, 0 rows affected (0.23 sec)
mysql> show tables;
+-----------------+
| Tables_in_kevin |
+-----------------+
| haha |
| heihei |
+-----------------+
2 rows
in
set
(0.00 sec)
mysql> insert into kevin.heihei values(1,
"shanghai"
);
Query OK, 1 row affected (0.13 sec)
mysql>
select
* from kevin.heihei;
+----+----------+
|
id
| name |
+----+----------+
| 1 | shanghai |
+----+----------+
1 row
in
set
(0.00 sec)
上面在從機的mysql里操作后,從機的mysql會自動把數據同步過來!
登錄mycat機器192.168.10.210機器,分別設置server.xml文件、rule.xml文件、schema.xml文件
server.xml文件在上面已經設置過了,這里就不用修改了:
[root@Mycat-node ~]
# vim /data/mycat/conf/server.xml
......
<!-- mycat的服務端口默認為8066,管理端口默認為9066 -->
<property name=
"serverPort"
>8066<
/property
> <property name=
"managerPort"
>9066<
/property
>
.....
<!-- 任意設置登陸 mycat 的用戶名,密碼,數據庫 -->
<user name=
"bobo"
>
<property name=
"password"
>bo@123<
/property
>
<property name=
"schemas"
>mycat<
/property
>
<!-- 表級 DML 權限設置 -->
<!--
<privileges check=
"false"
>
<schema name=
"TESTDB"
dml=
"0110"
>
<table name=
"tb01"
dml=
"0000"
><
/table
>
<table name=
"tb02"
dml=
"1111"
><
/table
>
<
/schema
>
<
/privileges
>
-->
<
/user
>
<!--
<user name=
"user"
>
<property name=
"password"
>user<
/property
>
<property name=
"schemas"
>TESTDB<
/property
>
<property name=
"readOnly"
>
true
<
/property
>
<
/user
>
-->
<
/mycat
:server>
分庫分表配置還涉及到rule.xml文件,配置如下(備份文件,清空,直接復制下面內容):
[root@Mycat-node conf]
# cp rule.xml rule.xml.bak
[root@Mycat-node conf]
# vim rule.xml
<?xml version=
"1.0"
encoding=
"UTF-8"
?>
<!-- - - Licensed under the Apache License, Version 2.0 (the
"License"
);
- you may not use this
file
except
in
compliance with the License. - You
may obtain a copy of the License at - - http:
//www
.apache.org
/licenses/LICENSE-2
.0
- - Unless required by applicable law or agreed to
in
writing, software -
distributed under the License is distributed on an
"AS IS"
BASIS, - WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the
License
for
the specific language governing permissions and - limitations
under the License. -->
<!DOCTYPE mycat:rule SYSTEM
"rule.dtd"
>
<mycat:rule xmlns:mycat=
"http://io.mycat/"
>
<tableRule name=
"mycat-rule"
> <!-- heihei表分片的規則名,這里定義為mycat-rule,這個需要在schema.xml文件中引用 -->
<rule>
<columns>
id
<
/columns
> <!--heihei表的分片列 -->
<algorithm>mod-long<
/algorithm
>
<
/rule
>
<
/tableRule
>
<
function
name=
"mod-long"
class=
"io.mycat.route.function.PartitionByMod"
>
<!-- how many data nodes -->
<property name=
"count"
>2<
/property
> <!-- count值與分片個數相同,這里heihei表分片到kevin庫和grace庫里,共2份。 -->
<
/function
>
<
/mycat
:rule>
接着配置schema.xml文件(server.xml文件配置在已經已經完成),分庫分表配置如下
(要將rule.xml里定義的分片模型寫進去,由於這里的heihei表配置了主鍵,所以primaryKey=
"id"
這個也寫進去,其他情況看表結構,也可以不寫):
[root@Mycat-node conf]
# cp schema.xml schema.xml.old
[root@Mycat-node conf]
# vim schema.xml
<?xml version=
"1.0"
?>
<!DOCTYPE mycat:schema SYSTEM
"schema.dtd"
>
<mycat:schema xmlns:mycat=
"http://io.mycat/"
>
<schema name=
"mycat"
checkSQLschema=
"false"
sqlMaxLimit=
"100"
>
<table name=
"haha"
primaryKey=
"id"
dataNode=
"kevin_db"
/>
<table name=
"heihei"
primaryKey=
"id"
dataNode=
"kevin_db,grace_db"
rule=
"mycat-rule"
/>
<
/schema
>
<dataNode name=
"kevin_db"
dataHost=
"Mycat-node"
database=
"kevin"
/>
<dataNode name=
"grace_db"
dataHost=
"Mycat-node"
database=
"grace"
/>
<dataHost name=
"Mycat-node"
maxCon=
"1000"
minCon=
"10"
balance=
"1"
writeType=
"0"
dbType=
"mysql"
dbDriver=
"native"
switchType=
"1"
slaveThreshold=
"100"
>
<heartbeat>show slave status<
/heartbeat
>
<writeHost host=
"Mysql-node1"
url=
"192.168.10.205:3306"
user=
"root"
password=
"123456"
>
<readHost host=
"Mysql-node2"
url=
"192.168.10.206:3306"
user=
"root"
password=
"123456"
>
<
/readHost
>
<
/writeHost
>
<writeHost host=
"Mysql-node1"
url=
"192.168.10.206:3306"
user=
"root"
password=
"123456"
>
<
/writeHost
>
<
/dataHost
>
<
/mycat
:schema>
重啟mycat服務
[root@Mycat-node conf]
# /data/mycat/bin/mycat restart
Stopping Mycat-server...
Stopped Mycat-server.
Starting Mycat-server...
[root@Mycat-node conf]
# lsof -i:8066
COMMAND PID USER FD TYPE DEVICE SIZE
/OFF
NODE NAME
java 971 root 79u IPv6 4024290 0t0 TCP *:8066 (LISTEN)
[root@Mycat-node conf]
# lsof -i:9066
COMMAND PID USER FD TYPE DEVICE SIZE
/OFF
NODE NAME
java 971 root 75u IPv6 4024288 0t0 TCP *:9066 (LISTEN)
在客戶機遠程登錄Mycat
[root@client-server ~]
# mysql -h192.168.10.210 -P8066 -ubobo -pbo@123
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection
id
is 1
Server version: 5.6.29-mycat-1.6-RELEASE-20161028204710 MyCat Server (OpenCloundDB)
Copyright (c) 2000, 2013, Oracle and
/or
its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and
/or
its
affiliates. Other names may be trademarks of their respective
owners.
Type
'help;'
or
'\h'
for
help. Type
'\c'
to
clear
the current input statement.
mysql> show databases;
+----------+
| DATABASE |
+----------+
| mycat |
+----------+
1 row
in
set
(0.01 sec)
mysql> use mycat;
Reading table information
for
completion of table and column names
You can turn off this feature to get a quicker startup with -A
Database changed
mysql> show tables;
+-----------------+
| Tables
in
mycat |
+-----------------+
| haha |
| heihei |
+-----------------+
2 rows
in
set
(0.01 sec)
mysql>
select
* from haha;
+----+-------------+
|
id
| name |
+----+-------------+
| 1 | wangshibo |
| 2 | linan |
| 3 | zhangminmin |
| 4 | lihuan |
+----+-------------+
4 rows
in
set
(0.12 sec)
mysql>
select
* from heihei;
+----+----------+
|
id
| city |
+----+----------+
| 1 | beijing |
| 1 | shanghai |
+----+----------+
2 rows
in
set
(0.04 sec)
mysql>
分別在mycat里往heihei和grace.heihei表里插入一些數據
mysql> insert into haha values(10,
"wangbiao"
);
insert into haha values(11,
"zhangcaiyi"
);Query OK, 1 row affected (0.06 sec)
mysql> insert into haha values(11,
"zhangcaiyi"
);
Query OK, 1 row affected (0.06 sec)
mysql> insert into heihei(
id
,city) values(20,
"chognqing"
);
Query OK, 1 row affected (0.09 sec)
mysql> insert into heihei(
id
,city) values(22,
"xianggang"
);
insert into heihei(
id
,city) values(28,
"chengdu"
);Query OK, 1 row affected (0.02 sec)
mysql> insert into heihei(
id
,city) values(23,
"huoqiu"
);
Query OK, 1 row affected (0.02 sec)
mysql> insert into heihei(
id
,city) values(24,
"haikou"
);
Query OK, 1 row affected (0.03 sec)
mysql> insert into heihei(
id
,city) values(25,
"anqing"
);
Query OK, 1 row affected (0.03 sec)
mysql> insert into heihei(
id
,city) values(26,
"tianqing"
);
Query OK, 1 row affected (0.02 sec)
mysql> insert into heihei(
id
,city) values(27,
"hangzhou"
);
Query OK, 1 row affected (0.04 sec)
mysql> insert into heihei(
id
,city) values(28,
"chengdu"
);
Query OK, 1 row affected (0.26 sec)
特別注意:
1)在配置了sharding分片策略之后(如heihei表),mycat里分片的表做插入數據時,即使插入所有字段的數據,也一定要在表名后面寫明插入數據的字段名稱,
否則插入數據會報錯:ERROR 1064 (HY000): partition table, insert must provide ColumnList
2)沒有配置sharding分片策略的表(如haha表),插入所有字段的數據時,表名后面不需要寫明字段名稱,默認就是所有字段插入數據,如上面的haha表。
登錄主機和從機,查看從mycat端寫入的數據
mysql>
select
* from kevin.haha;
+----+-------------+
|
id
| name |
+----+-------------+
| 1 | wangshibo |
| 2 | linan |
| 3 | zhangminmin |
| 4 | lihuan |
| 10 | wangbiao |
| 11 | zhangcaiyi |
+----+-------------+
6 rows
in
set
(0.00 sec)
mysql>
select
* from grace.heihei;
+----+-----------+
|
id
| city |
+----+-----------+
| 1 | beijing |
| 21 | guangzhou |
| 23 | huoqiu |
| 25 | anqing |
| 27 | hangzhou |
+----+-----------+
5 rows
in
set
(0.00 sec)
mysql>
select
* from kevin.heihei;
+----+-----------+
|
id
| city |
+----+-----------+
| 1 | shanghai |
| 20 | chognqing |
| 22 | xianggang |
| 24 | haikou |
| 26 | tianqing |
| 28 | chengdu |
+----+-----------+
6 rows
in
set
(0.00 sec)
mysql>
從上面可以看出:
在mycat里往做了sharding分片策略的heihei表里寫入的數據,已經分片到kevin和grace兩個庫里了,即成功實現了分庫分表功能!
查看mycat的debug日志,可以觀察到mysql讀寫分離和分庫分表情況
[root@Mycat-node logs]
# tail -f mycat.log
|
這里需要注意:
- 查詢語句不要加事務,否則讀操作會被分發到寫服務器上。
- 主從復制是mysql自己實現的,mycat只是代理插件,它本身不能實現主從復制,只能實現了讀寫分離、主從切換、分庫分表功能。
為了提升查詢的性能,有人創新的設計了一種MySQL主從復制的模式,主節點為InnoDB引擎,讀節點為MyISAM引擎,經過實踐,發現查詢性能提升不少。
此外,為了減少主從復制的時延,也建議采用MySQL 5.6+的版本,用GTID同步復制方式減少復制的時延,可以將一個Database中的表,根據寫頻率的不同,
分割成幾個Database,用Mycat虛擬為一個Database,這樣就滿足了多庫並發復制的優勢,需要注意的是,要將有Join關系的表放在同一個庫中。
對於某些表,要求不能有復制時延,則可以考慮這些表放到Gluster集群里,消除同步復制的時延問題,前提是這些表的修改操作並不很頻繁,需要做性能測試,
以確保能滿足業務高峰。
總結一下,Mycat做讀寫分離和高可用,可能的方案很靈活,只有你沒想到的,沒有做不到的。
=================Mycat常見問題及注意點==================
1)Mycat自動切換需要人工處理么?
Mycat通過心跳檢測,自主切換數據庫,保證高可用性,無須手動切換。
2)Mycat支持集群么?
目前Mycat沒有實現對多Mycat集群的支持,可以暫時使用haproxy來做負載,或者統計硬件負載。
3)Mycat目前有生產案例了么?
目前Mycat初步統計大概600家公司使用。
4)Mycat穩定性與Cobar如何?
目前Mycat穩定性優於Cobar,而且一直在更新,Cobar已經停止維護,可以放心使用。
5)Mycat除了Mysql還支持哪些數據庫?
mongodb、oracle、sqlserver 、hive 、db2 、 postgresql。
6)Mycat如何配置字符集?
在配置文件server.xml配置,默認配置為utf8。
7)Mycat后台管理監控如何使用?
9066端口可以用JDBC方式執行命令,在界面上進行管理維護,也可以通過命令行查看命令行操作。
命令行操作是:mysql -h127.0.0.1 -utest -ptest -P9066 登陸,然后執行相應命令。
8)Mycat主鍵插入后應用如何獲取?
獲得自增主鍵,插入記錄后執行select last_insert_id()獲取。
9)Mycat運行sql時經常阻塞或卡死是什么原因?
如果出現執行sql語句長時間未返回,或卡死,請檢查是否是虛機下運行或cpu為單核。如果仍舊無法解決,可以暫時跳過,目前有些環境阻塞卡死原因未知。
10)Mycat中,舊系統數據如何遷移到Mycat中?
舊數據遷移目前可以手工導入,在mycat中提取配置好分配規則及后端分片數據庫,然后通過dump或loaddata方式導入,后續Mycat就做舊數據自動數據遷移工具。
11)Mycat如何對舊分片數據遷移或擴容,支持自動擴容么?
目前除了一致性hash規則分片外其他數據遷移比較困難,目前暫時可以手工遷移,未提供自動遷移方案,具體遷移方案情況Mycat權威指南對應章節。
12)Mycat支持批量插入嗎?
目前Mycat1.3.0.3以后支持多values的批量插入,如insert into(xxx) values(xxx),(xxx) 。
13)Mycat支持多表Join嗎?
Mycat目前支持2個表Join,后續會支持多表Join,具體Join請看Mycat權威指南對應章節。
14)Mycat 啟動報主機不存在的問題?
需要添加ip跟主機的映射。
15)Mycat連接會報無效數據源(Invalid datasource)?
例如報錯:mysql> select * from company;
ERROR 3009 (HY000): java.lang.IllegalArgumentException: Invalid DataSource:0
這類錯誤最常見是一些配置問題例如schema.xml中的dataNode的配置和實際不符合,請先仔細檢查配置項,確保配置沒有問題。
如果不是配置問題,分析具體日志看出錯原因,常見的有:
- 如果是應用連:在某些版本的Mysql驅動下連接Mycat會報錯,可升級最新的驅動包試下。
- 如果是服務端控制台連,確認mysql是否開啟遠程連接權限,或防火牆是否設置正確,或者數據庫database是否配置,或用戶名密碼是否正確。
16)Mycat支持的或者不支持的語句有哪些?
insert into,復雜子查詢,3表及其以上跨庫join等不支持。
17)MycatJDBC連接報 PacketTooBigException異常
檢查mysqljdbc驅動的版本,在使用mycat1.3和mycat1.4版本情況下,不要使用jdbc5.1.37和38版本的驅動,會出現如下異常報錯:
com.mysql.jdbc.PacketTooBigException: Packet for query is too large (60 > -1). You can change this value on the server by setting the max_allowed_packet’ variable。
建議使用jdbc5.1.35或者36的版本。
18)Mycat中文亂碼的問題
答:如果在使用mycat出現中文插入或者查詢出現亂碼,請檢查三個環節的字符集設置:
a)客戶端環節(應用程序、mysql命令或圖形終端工具)連接mycat字符集
b)mycat連接數據庫的字符集
c)數據庫(mysql,oracle)字符集。這三個環節的字符集如果配置一致,則不會出現中文亂碼,其中尤其需要注意的是客戶端連接mycat時使用的連接字符集,
通常的中文亂碼問題一般都由此處設置不當引出。其中mycat內部默認使用utf8字符集,在最初啟動連接數據庫時,mycat會默認使用utf8去連接數據庫,當客戶
端真正連接mycat訪問數據庫時,mycat會使用客戶端連接使用的字符集修改它連接數據庫的字符集,在mycat環境的管理9066端口,可以通過"show @@backend"命令
查看后端數據庫的連接字符集,通過show @@connection命令查看前端客戶端的連接字符集。客戶端的連接可以通過指定字符集編碼或者發送SET命令指定連接mycat
時connection使用的字符集,常見客戶端連接指定字符集寫法如下:
- jdbcUrl=jdbc:mysql://localhost:8066/databaseName? characterEncoding=iso_1
- SET character_set_client = utf8;用來指定解析客戶端傳遞數據的編碼
SET character_set_results = utf8;用來指定數據庫內部處理時使用的編碼
SET character_set_connection = utf8;用來指定數據返回給客戶端的編碼方式
- mysql –utest –ptest –P8066 –default-character-set=gbk
19)Mycat無法登陸Access denied
Mycat正常安裝配置完成,登陸mycat出現以下錯誤:
[mysql@master ~]$ mysql -utest -ptest -P8066
ERROR 1045 (28000): Access denied for user 'test’@’localhost’ (using password: YES)
請檢查在schema.xml中的相關dataHost的mysql主機的登陸權限,一般都是因為配置的mysql的用戶登陸權限不符合,mysql用戶權限管理不熟悉的請自己度娘。
只有一種情況例外,mycat和mysql主機都部署在同一台設備,其中主機localhost的權限配置正確,使用-hlocalhost能正確登陸mysql但是無法登陸mycat的情況,
請使用-h127.0.0.1登陸,或者本地網絡實際地址,不要使用-hlocalhost,很多使用者反饋此問題,原因未明。
20)Mycat的分片數據插入報異常IndexOutofBoundException
在一些配置了分片策略的表進行數據插入時報錯,常見的報錯信息如下:java.lang.IndexOutOfBoundsException:Index:4,size:3
這類報錯通常由於分片策略配置不對引起,請仔細檢查並理解分片策略的配置,例如:使用固定分片hash算法,PartitionByLong策略,如果schema.xml里面設置
的分片數量dataNode和rule.xml配置的partitionCount 分片個數不一致,尤其是出現分片數量dataNode小於partitionCount數量的情況,插入數據就可能會報錯。
很多使用者都沒有仔細理解文檔中對分片策略的說明,用默認rule.xml配置的值,沒有和自己實際使用環境進行參數核實就進行分片策略使用造成這類問題居多。
21)Mycat ER分片子表數據插入報錯
一般都是插入子表時出現不能找到父節點的報錯。報錯信息如: [Err] 1064 - can’t find (root) parent sharding node for sql:。
此類ER表的插入操作不能做為一個事務進行數據提交,如果父子表在一個事務中進行提交,顯然在事務沒有提交前子表是無法查到父表的數據的,因此就無法確定
sharding node。如果是ER關系的表在插入數據時不能在同一個事務中提交數據,只能分開提交。
22)Mycat最大內存無法調整至4G以上
mycat1.4的JVM使用最大內存調整如果超過4G大小,不能使用wrapper.java.maxmemory參數,需要使用wrapper.java.additional的寫法,注意將
wrapper.java.maxmemory參數注釋,例如增加最大內存至8G:wrapper.java.additional.10=-Xmx8G。
23)Mycat使用過程中報錯怎么辦
記住無論什么時候遇到報錯,如果不能第一時間理解報錯的原因,首先就去看日志,無論是啟動(wrapper.log)還是運行過程中(mycat.log),請相信良好的
日志是編程查錯的終極必殺技。日志如果記錄信息不夠,可以調整conf/log4j.xml中的level級別至debug,所有的詳細信息均會記錄。另外如果在群里面提問,
盡量將環境配置信息和報錯日志提供清楚,這樣別人才能快速幫你定位問題。