1. 程式人生 > >mycat讀寫分離介紹

mycat讀寫分離介紹

時延 技術 show monitor classpath cep str arc sql查詢

安裝mycat實現mysql負載均衡

事先準備好兩臺及以上數據庫服務器
mycat支持特性如(官網mycat.io,以下是官網介紹的支持特性):
SQL92標準,支持MySQL、Oracle、DB2、SQL Server、PostgreSQL等DB的常見SQL語法
遵守Mysql原生協議,跨語言,跨平臺,跨數據庫的通用中間件代理。
基於心跳的自動故障切換,支持讀寫分離,支持MySQL主從,以及galera cluster集群。
支持Galera for MySQL集群,Percona Cluster或者MariaDB cluster
基於Nio實現,有效管理線程,解決高並發問題。
數據的多片自動路由與聚合,sum,count,max等常用的聚合函數,支持跨庫分頁。

單庫內部任意join,跨庫2表join,甚至基於caltlet的多表join。
通過全局表,ER關系的分片策略,實現了高效的多表join查詢。
多租戶方案。分布式事務(弱xa)。XA分布式事務(1.6.5)。
全局序列號,解決分布式下的主鍵生成問題。分片規則豐富,插件化開發,易於擴展。
強大的web,命令行監控。前端作為MySQL通用代理,後端JDBC方式支持Oracle、DB2、SQL Server 、 mongodb 、巨杉。
密碼加密,服務降級,IP白名單,SQL黑名單、sql註入×××攔截
prepare預編譯指令(1.6),非堆內存(Direct Memory)聚合計算(1.6)
PostgreSQL的native協議(1.6)。mysql和oracle存儲過程,out參數、多結果集返回(1.6)。zookeeper協調主從切換、zk序列、配置zk化(1.6)。庫內分表(1.6),集群基於ZooKeeper管理,在線升級,擴容,智能優化,大數據處理(2.0)

事先準備兩臺數據庫

安裝好jdk的環境,mycat啟動需要依賴jdk運行,jdk下載後解壓到相應目錄下
jdk變量如下示例,可根據jdk版本修改變量路徑,將PATH變量路徑寫入/etc/profile文件中

JAVA_HOME=/usr/local/jdk1.8
JAVA_BIN=/usr/local/jdk1.8/bin
JRE_HOME=/usr/local/jdk1.8/jre
PATH=$PATH:/usr/local/jdk1.8/bin:/usr/local/jdk1.8/jre/bin
CLASSPATH=/usr/local/jdk1.8/jre/lib:/usr/local/jdk1.8/lib:/usr/local/jdk1.8/jre/lib/charsets.jar

下載mycat安裝包,解壓後直接移動到/usr/local/目錄下

[root@www src]# tar zxf Mycat-server-1.6.6.1-test-20180709095126-linux.tar.gz -C .
[root@www src]# mv mycat/ /usr/local/

創建mycat運行的用戶和組,並把mycat的目錄給予mycat用戶所屬主所屬組權限

[root@www src]# groupadd mycat
[root@www src]# useradd -r -g mycat mycat
[root@www src]# chown -R mycat:mycat /usr/local/mycat/

mycat作為中間件並不存儲任何數據,後端鏈接mysql物理服務器,schem.xml用來鏈接後端的mysql服務器的(文件可配置分庫分表策略,分片節點也在其中)

修改mycat配置文件/usr/local/mycat/conf/schema.xml
在配置文件的vriteHost標簽中配置mysql的地址、用戶名和密碼
<readHost host=>中配置的是從節點的數據庫連接用戶和密碼,我們現在先只在writeHost中配置(這臺服務器安裝了mysql)
所有讀操作分配到readhost上、負載均衡發送到第一個writehost,第一個無法提供服務後會分發到第二個writehost上、

[root@www mycat]# vim conf/schema.xml
 <dataHost name="localhost1" maxCon="1000" minCon="10" balance="3"
 ? ? ? ? writeType="0" dbType="mysql" dbDriver="native" switchType="-1" ?slaveThreshold="100" ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? maxRetryCount="4">
 ? ? <heartbeat>select user()</heartbeat>

<writeHost host="hostM1" url="localhost:3306" user="root"
 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? password="pwd@123">
 ? ? ? ? ? ? ? ? ? <!-- can have multi read hosts -->
 ? ? ? ? ? ? ? ? ? ? ? <readHost host="hostS2" url="192.168.1.223:3306" user="root" password="pwd@123" />
 ? ? ? ? ? ? ? ? ? ? ? <readHost host="hostS3" url="192.168.1.220:3306" user="slave" password="pwd@123" />
 ? ? ? ? ? ? ?
 ?  </writeHost>
</dataHost>

schema.xml中配置負載均衡需要註意的地方
此處有三點需要註意:?

balance=”1”,writeType=”0”?,switchType=”1”?
balance?屬性負載均衡類型,目前的取值有?4?種
balance="0", 不開啟讀寫分離機制,所有讀操作都發送到當前可用的writeHost 上。
balance="1",全部的 readHost 與 stand by writeHost 參與 select 語句的負載均衡,簡單的說,當雙主雙從模式(M1 ->S1 , M2->S2,並且 M1 與 M2 互為主備),正常情況下, M2,S1,S2 都參與 select 語句的負載均衡。
balance="2",所有讀操作都隨機的在 writeHost、 readhost 上分發。
balance="3", 所有讀請求隨機的分發到 wiriterHost 對應的 readhost 執行,writerHost 不負擔讀壓力,註意 balance=3 只在 1.4 及其以後版本有, 1.3 沒有。

writeType屬性,負載均衡類型,配置項有3類

writeType="0", 所有寫操作發送到配置的第一個 writeHost,第一個掛了切到還生存的第二個writeHost,重新啟動後已切換後的為準,切換記錄在配置文件中:dnindex.properties .
writeType="1",所有寫操作都隨機的發送到配置的 writeHost。
writeType="2",沒實現

switchType屬性

-1表示不切換
1默認值,自動切換
2基於mysql,主從同步狀態決定是否切換
3基於MySQL galary cluster的切換機制(適合集群)(1.4.1),心跳語句為 show status like ‘wsrep%‘

mycat支持雙主多從,可以配置兩個writeHost節點,多個readHost節點

配置mycat的用戶密碼,在文件中找到user name標簽中配置mycat的用戶名和密碼,保存
server.xml跟讀寫分離策略關系不大,但是需要使用此文件來配置連接mycat用戶的權限,這裏簡單配置用戶和密碼
第一個user是指定主數據庫的登錄寫入用戶名和密碼
第二個user指定從數據庫的讀取用戶名和密碼(可能不需要指定)

  <user name="repl" defaultAccount="true">
 ? ? ? ? ? ? ?  <property name="password">pwd@123</property>
 ? ? ? ? ? ? ?  <property name="schemas">TESTDB</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="slave">
 ? ? ? ? ? ? ?  <property name="password">pwd@123</property>
 ? ? ? ? ? ? ?  <property name="schemas">TESTDB</property>
 ? ? ? ? ? ? ?  <property name="readOnly">true</property>
 ? ? ?  </user>

啟動mycat服務 /usr/locar/mycat/bin/mycat start
查看mycat啟動監聽的端口,如果監聽到8066端口,說明mycat啟動成功 ? ? ? ? ? ? ??

[root@www local]# /usr/local/mycat/bin/mycat start
Starting Mycat-server...
[root@www local]# netstat -ntlp |grep 8066
tcp6 0 0 :::8066 :::* LISTEN 25766/java 
連接mycat,驗證是否能夠通過mycat去訪問mysql數據庫
[root@www mycat]# mysql -uroot -ppwd@123 -h127.0.0.1 -P8066 -DTESTDB
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 1
Server version: 5.6.29-mycat-1.6.6.1-test-20180709095126 MyCat Server (OpenCloundDB)
?
Copyright (c) 2000, 2018, 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 |
+----------+
| TESTDB |
+----------+
1 row in set (0.00 sec)
?
mysql> 

mycat服務驗證

mycat的主從延時切換技術?
Mycat1.4開始支持?MySQL主從復制狀態綁定的讀寫分離機制,讓讀更加安全可靠,配置如下:?MyCAT心跳檢查語句配置為?show?slave?status?,dataHost?上定義兩個新屬性:?switchType=”2”?與slaveThreshold=”100”,此時意味著開啟MySQL主從復制狀態綁定的讀寫分離與切換機制,Mycat心跳機制通過檢測?show?slave?status?中的?“Seconds_Behind_Master”,?“Slave_IO_Running”,?“Slave_SQL_Running”?三個字段來確定當前主從同步的狀態以及Seconds_Behind_Master?主從復制時延,?當Seconds_Behind_Master>slaveThreshold?時,讀寫分離篩選器會過濾掉此Slave機器,防止讀到很久之前的舊數據,而當主節點宕機後,切換邏輯會檢查Slave上的Seconds_Behind_Master是否為0,為0時則表示主從同步,可以安全切換,否則不會切換。

登入mycat的操作端 mysql -uroot -ppwd@123 -h127.0.0.1 -P8066 -DTESTDB
創建測試用的表
這裏報錯Invalid DataSource:1。修改server.xml文件,指定主數據庫寫入的用戶名和密碼

mysql -uroot -ppwd@123 -h127.0.0.1 -P8066 -DTESTDB
mysql> create table travelrecord (id bigint not null primary key,user_id varchar(100),traveldate DATE, fee decimal,days int);
ERROR 3009 (HY000): java.lang.IllegalArgumentException: Invalid DataSource:1

報錯 Invalid DataSource:0?
需要創建schema.xml中的一個配置裏的三個數據庫,是沒有這三個庫造成的,退出mycat在mysql終端裏進行新建庫操作

mysql> create table travelrecord (id bigint not null primary key,user_id varchar(100),traveldate DATE, fee decimal,days int);
ERROR 3009 (HY000): java.lang.IllegalArgumentException: Invalid DataSource:0

創建mycat所需的三個庫(schema.xml配置文件中指定的庫)

mysql> create database db1;
Query OK, 1 row affected (0.01 sec)
?
mysql> create database db2;
Query OK, 1 row affected (0.01 sec)
?
mysql> create database db3;
Query OK, 1 row affected (0.01 sec)
?
mysql> exit
Bye

在mysql主庫裏創建好三個庫後,登入mycat,執行新建表操作,可見成功創建一個新表

Your MySQL connection id is 2
Server version: 5.6.29-mycat-1.6.6.1-test-20180709095126 MyCat Server (OpenCloundDB)
?
Copyright (c) 2000, 2018, 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> create table travelrecord (id bigint not null primary key,user_id varchar(100),traveldate DATE, fee decimal,days int);
Query OK, 0 rows affected (0.12 sec)

mycat讀寫分離驗證

mycat無法與mysql讀寫問題解決完成後
上述創建好了一個表後,進行sql查詢,中間件服務mycat建議不要和master數據庫再一個服務器上,驗證master停止mysql服務後,mycat無法提供正常的sql讀取操作
在所有從服務器上創建master授權訪問的用戶,用於master上的mycat查詢數據使用,授權對象是192.168.1.234,有多個從的話都需要授權192.168.1.234訪問

mysql> grant all on *.* to ‘slave‘@192.168.1.234 identified by ‘pwd@123‘ ;
Query OK, 0 rows affected, 1 warning (0.01 sec)
?
mysql> exit
Bye

修改mycat的schema.xml配置文件,在readhost中指定從的授權用戶

<writeHost host="hostM1" url="localhost:3306" user="root"
 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? password="pwd@123">
 ? ? ? ? ? ? ? ? ? ? <!-- can have multi read hosts -->
 ? ? ? ? ? ? ? ? ? ? ? ? <readHost host="hostS2" url="192.168.1.223:3306" user="root" password="pwd@123" />
 ? ? ? ? ? ? ? ? ? ? ? ? <readHost host="hostS3" url="192.168.1.220:3306" user="slave" password="pwd@123" />
 ? ? ? ? ? ? ?  </writeHost>

在其中一個slave從上創建一個master主上沒有的數據,真實環境部署不建議這麽操作
首先查看master主上的travelrecord的表內容,確認和slave從上數據不一致

mysql> use db2;

Database changed
mysql> select * from travelrecord;
+---------+---------+------------+------+------+
| id ? ?  | user_id | traveldate | fee  | days |
+---------+---------+------------+------+------+
| 5000001 | aaa.com | 2016-01-02 | 100  | 10 ? |
+---------+---------+------------+------+------+
row in set (0.00 sec)
?
mysql> use db1;
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 travelrecord;
+------+---------+------------+------+------+
| id ? | user_id | traveldate | fee  | days |
+------+---------+------------+------+------+
| 1 ?  | aaa.com | 2016-01-01 | 100  | 10 ? |
| 2233 | aaa.com | 2016-01-02 | 100  | 10 ? |
+------+---------+------------+------+------+
rows in set (0.00 sec)

在slave中插入一條master上沒有的數據,查看slave從上的表內容

mysql> insert into travelrecord(id,user_id,traveldate,fee,days) values(23333,@@hostname,20160102,100,10);
Query OK, 1 row affected (0.02 sec)
?
mysql> use db1;
Database changed
mysql> select * from travelrecord;
+-------+--------------+------------+------+------+
| id ?  | user_id ? ?  | traveldate | fee  | days |
+-------+--------------+------------+------+------+
| 1 ? ? | aaa.com ? ?  | 2016-01-01 | 100  | 10 ? |
| 2233  | aaa.com ? ?  | 2016-01-02 | 100  | 10 ? |
| 23333 | www.abcd.com | 2016-01-02 | 100  | 10 ? |
+-------+--------------+------------+------+------+
3 rows in set (0.00 sec)
?
mysql> use db2;
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 travelrecord;
+---------+---------+------------+------+------+
| id ? ?  | user_id | traveldate | fee  | days |
+---------+---------+------------+------+------+
| 5000001 | aaa.com | 2016-01-02 | 100  | 10 ? |
+---------+---------+------------+------+------+
1 row in set (0.00 sec)

這裏註意master中沒有www.abcd.com這條數據,如果執行查詢操作,master不會給出這個查詢的結果
在master上登入mycat,多次查詢數據

mysql> select * from travelrecord;
+---------+--------------+------------+------+------+
| id ? ?  | user_id ? ?  | traveldate | fee  | days |
+---------+--------------+------------+------+------+
| 5000001 | aaa.com ? ?  | 2016-01-02 | 100  | 10 ? |
| 1 ? ? ? | aaa.com ? ?  | 2016-01-01 | 100  | 10 ? |
| 2233 ?  | aaa.com ? ?  | 2016-01-02 | 100  | 10 ? |
| 23333 ? | www.abcd.com | 2016-01-02 | 100  | 10 ? |
+---------+--------------+------------+------+------+
4 rows in set (0.00 sec)
?
mysql> select * from travelrecord;
+---------+--------------+------------+------+------+
| id ? ?  | user_id ? ?  | traveldate | fee  | days |
+---------+--------------+------------+------+------+
| 5000001 | aaa.com ? ?  | 2016-01-02 | 100  | 10 ? |
| 1 ? ? ? | aaa.com ? ?  | 2016-01-01 | 100  | 10 ? |
| 2233 ?  | aaa.com ? ?  | 2016-01-02 | 100  | 10 ? |
| 23333 ? | www.abcd.com | 2016-01-02 | 100  | 10 ? |
+---------+--------------+------------+------+------+
4 rows in set (0.00 sec)
?
mysql> select * from travelrecord;
+---------+--------------+------------+------+------+
| id ? ?  | user_id ? ?  | traveldate | fee  | days |
+---------+--------------+------------+------+------+
| 1 ? ? ? | aaa.com ? ?  | 2016-01-01 | 100  | 10 ? |
| 2233 ?  | aaa.com ? ?  | 2016-01-02 | 100  | 10 ? |
| 23333 ? | www.abcd.com | 2016-01-02 | 100  | 10 ? |
| 5000001 | aaa.com ? ?  | 2016-01-02 | 100  | 10 ? |
+---------+--------------+------------+------+------+
4 rows in set (0.00 sec)

可以從mycat的查詢結果中得到顯而易見的結果,讀數據會從slave上讀取

mycat讀寫分離介紹