數據庫讀寫分離對於大型系統或者訪問量很高的互聯網應用來說,是必不可少的一個重要功能。
從數據庫的角度來說,對於大多數應用來說,從集中到分布,最基本的一個需求不是數據存儲的瓶頸,而是在於計算的瓶頸,即SQL查詢的瓶頸,我們知道,正常情況下,Insert SQL就是幾十個毫秒的時間內寫入完成,而系統中的大多數Select SQL則要幾秒到幾分鍾才能有結果,很多復雜的SQL,其消耗服務器CPU的能力超強,不亞於死循環的威力。在沒有讀寫分離的系統上,很可能高峰時段的一些復雜SQL查詢就導致數據庫服務器CPU爆表,系統陷入癱瘓,嚴重情況下可能導致數據庫崩潰。因此,從保護數據庫的角度來說,我們應該盡量避免沒有主從復制機制的單節點數據庫。
環境
最低環境需求
MySQL | 5.5及以上 |
Java JDK | 7及以上 |
主服務器環境
CentOS | 7.4.1708 |
MySQL | 5.6.40 |
Java JDK | 10.0.1 |
Mycat | 1.6 |
從服務器環境
CentOs | 7.2.1511 |
MySQL | 5.6.35 |
安裝
主服務器安裝
安裝MySQL
本人使用的環境為自動部署上去的,其中已包含Mysql,所以關於MySQL 的單獨安裝請大家參考網上的教程。
安裝Java JDK
下載地址:http://www.oracle.com/technetwork/java/javase/downloads/index.html
點擊 DOWNLOAD
同意協議,點擊下載。
登錄服務器,創建 Java JDK 安裝目錄
mkdir /usr/local/java
上傳 JDK 至目錄
解壓 JDK 至當前目錄
tar -zxvf jdk-10.0.1_linux-x64_bin.tar.gz
編輯配置文件,配置環境變量
vim /etc/profile
添加如下內容:JAVA_HOME根據實際目錄來
JAVA_HOME=/usr/local/java/jdk-10.0.1
CLASSPATH=$JAVA_HOME/lib/
PATH=$PATH:$JAVA_HOME/bin
export PATH JAVA_HOME CLASSPATH
重啟機器
sudo shutdown -r now
查看安裝情況
java -version
安裝Mycat
MyCAT有提供編譯好的安裝包,支持windows、Linux、Mac、Solaris等系統上安裝與運行。
下載地址:http://dl.mycat.io/
這里我選擇下載1.6版本:Mycat-server-1.6-RELEASE-20161028204710-linux.tar.gz
上傳 Mycat 至服務器 /usr/local
解壓 Mycat 至當前目錄
tar -zxvf Mycat-server-1.6-RELEASE-20161028204710-linux.tar.gz
移動安裝包至 mycat 文件夾
mv Mycat-server-1.6-RELEASE-20161028204710-linux.tar.gz /usr/local/mycat/
創建用戶並設置
useradd Mycat
chown -R Mycat.Mycat /usr/local/mycat/
passwd Mycat
mycat 文件夾目錄說明
/usr/local/mycat
├── bin
├── catlet
├── conf
├── lib
├── logs
└── version.txt
目錄解釋如下:
bin 程序目錄,存放了window版本和linux版本,除了提供封裝成服務的版本之外,也提供了nowrap的shell腳本命令,方便大家選擇和修改,進入到bin目錄:
Linux下運行:./mycat console,首先要chmod +x *
注:mycat支持的命令{ console | start | stop | restart | status | dump }
conf目錄下存放配置文件,server.xml是Mycat服務器參數調整和用戶授權的配置文件,schema.xml是邏輯庫定義和表以及分片定義的配置文件,rule.xml是分片規則的配置文件,分片規則的具體一些參數信息單獨存放為文件,也在這個目錄下,配置文件修改,需要重啟Mycat或者通過9066端口reload.
lib目錄下主要存放mycat依賴的一些jar文件.
日志存放在logs/mycat.log中,每天一個文件,日志的配置是在conf/log4j.xml中,根據自己的需要,可以調整輸出級別為debug,debug級別下,會輸出更多的信息,方便排查問題.
注意:Linux下部署安裝MySQL,默認不忽略表名大小寫,需要手動到/etc/my.cnf 下配置 lower_case_table_names=1 使Linux環境下MySQL忽略表名大小寫,否則使用MyCAT的時候會提示找不到表的錯誤!
增加環境變量
MyCAT在Linux中部署啟動時,首先需要在Linux系統的環境變量中配置MYCAT_HOME,操作方式如下:
vi /etc/profile
在文件中增加
export MYCAT_HOME=/usr/local/mycat
刷新環境變量
source /etc/profile
Mycat 集群配置
如果是在多台Linux系統中組建的MyCAT集群,那需要在MyCAT Server所在的服務器上配置對其他ip和主機名的映射,配置方式如下:
vi /etc/hosts
例如:我有4台機器,配置如下:
IP 主機名:
192.168.100.2 sam_server_1
192.168.100.3 sam_server_2
192.168.100.4 sam_server_3
192.168.100.5 sam_server_4
編輯完后,保存文件。
啟動 Mycat
經過以上兩個步驟的配置,就可以到 /usr/local/Mycat/bin 目錄下執行:(先不要動配置文件)
./mycat start
即可啟動mycat服務!
注:mycat支持的命令{ console | start | stop | restart | status | dump }
初次執行可以使用 ./mycat console 命令執行,這樣有失敗信息直接就能顯示出來。
檢驗執行是否成功可以使用 ./mycat status
開放端口
如果開啟防火牆需要開放8066/9066端口,9066和8066分別偵聽管理員和應用程序的連接請求。
vim /etc/sysconfig/iptables
添加:
-A INPUT -p tcp -m state --state NEW -m tcp --dport 8066 -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 9066 -j ACCEPT
重啟 iptables
systemctl restart iptables.service
從服務器安裝
從服務器主要用到的是 MySQL,環境為自動部署上去的,其中已包含Mysql,所以關於MySQL 的單獨安裝請大家參考網上的教程。
配置MySQL主從復制
配置mysql端主從的數據自動同步,mycat不負責任何的數據同步問題。
關於 MySQL 主從復制的介紹我不多贅述,其中優缺點有興趣的可以查閱相關資料。主要復制方式:
- 基於SQL語句的復制(statement-based replication, SBR),
- 基於行的復制(row-based replication, RBR),
- 混合模式復制(mixed-based replication, MBR)。
基於SQL語句的方式最古老的方式,也是目前默認的復制方式,后來的兩種是MySQL 5以后才出現的復制方式。
主服務器配置
登錄MySQL,創建一個同步賬號,並分配用戶權限
CREATE USER 'AiMasterSlave'@'%' IDENTIFIED BY '123456';
GRANT REPLICATION SLAVE ON *.* TO 'AiMasterSlave'@'%';
修改/etc/my.cnf
server-id = 2 # 每台服務器標識要唯一,不要設置為0,為0會拒絕所有鏈接
log_bin = mysql-bin
重啟Mysql
service mysqld restart
登錄MySQL,查看二進制日志
show master status;
記錄下來,一會要用到。
檢查3306端口是否開放,如果沒開放,開放端口,參考上面打開8066端口方法
從服務器配置
先別着急配置,嘗試遠程鏈接主服務器,檢驗一下
mysql -h192.168.1.45 -uAiMasterSlave -p123456
如果不能鏈接,請檢驗主服務器用戶配置
修改/etc/my.cnf
server-id = 1
replicate_wild_do_table=master_slave_test.% # 同步庫
replicate_wild_ignore_table=mysql.% # 排除庫
重啟Mysql
service mysqld restart
登錄MySQL
stop slave;
CHANGE MASTER TO
MASTER_HOST='192.168.1.45',
MASTER_USER='AiMasterSlave',
MASTER_PASSWORD='123456',
MASTER_LOG_FILE='mysql-bin.000013',
MASTER_LOG_POS=680;
start slave;
查看狀態
show slave status \G;
如果上面兩處都為 Yes 說明配置就沒問題。為 NO 或者 connecting 請檢查配置和防火牆設置是否准確。
測試主從復制
我在主服務器寫的數據,從服務器會自動同步,說明配置生效。
配置Mycat讀寫分離
關於 Mycat 的詳細配置說明,請到官網去查閱文檔,太多了我就不搬過來了。資料下載:百度雲
server.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:server SYSTEM "server.dtd"> <mycat:server xmlns:mycat="http://io.mycat/"> <system> <property name="useSqlStat">0</property> <!-- 1為開啟實時統計、0為關閉 --> <property name="useGlobleTableCheck">0</property> <!-- 1為開啟全加班一致性檢測、0為關閉 --> <property name="sequnceHandlerType">2</property> <!-- <property name="useCompression">1</property>--> <!--1為開啟mysql壓縮協議--> <!-- <property name="fakeMySQLVersion">5.6.20</property>--> <!--設置模擬的MySQL版本號--> <!-- <property name="processorBufferChunk">40960</property> --> <!-- <property name="processors">1</property> <property name="processorExecutor">32</property> --> <!--默認為type 0: DirectByteBufferPool | type 1 ByteBufferArena--> <property name="processorBufferPoolType">0</property> <!--默認是65535 64K 用於sql解析時最大文本長度 --> <!--<property name="maxStringLiteralLength">65535</property>--> <!--<property name="sequnceHandlerType">0</property>--> <!--<property name="backSocketNoDelay">1</property>--> <!--<property name="frontSocketNoDelay">1</property>--> <!--<property name="processorExecutor">16</property>--> <!-- <property name="serverPort">8066</property> <property name="managerPort">9066</property> <property name="idleTimeout">300000</property> <property name="bindIp">0.0.0.0</property> <property name="frontWriteQueueSize">4096</property> <property name="processors">32</property> --> <!--分布式事務開關,0為不過濾分布式事務,1為過濾分布式事務(如果分布式事務內只涉及全局表,則不過濾),2為不過濾分布式事務,但是記錄分布式事務日志--> <property name="handleDistributedTransactions">0</property> <!-- off heap for merge/order/group/limit 1開啟 0關閉 --> <property name="useOffHeapForMerge">1</property> <!-- 單位為m --> <property name="memoryPageSize">1m</property> <!-- 單位為k --> <property name="spillsFileBufferSize">1k</property> <property name="useStreamOutput">0</property> <!-- 單位為m --> <property name="systemReserveMemorySize">384m</property> <!--是否采用zookeeper協調切換 --> <property name="useZKSwitch">true</property> </system> <!-- 全局SQL防火牆設置 --> <!-- <firewall> <whitehost> <host host="127.0.0.1" user="mycat"/> <host host="127.0.0.2" user="mycat"/> </whitehost> <blacklist check="false"> </blacklist> </firewall> --> <user name="mycat"> <property name="password">123456</property> <property name="schemas">TESTDB</property> <property name="readOnly">false</property> </user> </mycat:server>
schema.xml
<?xml version="1.0"?> <!DOCTYPE mycat:schema SYSTEM "schema.dtd"> <mycat:schema xmlns:mycat="http://io.mycat/"> <schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100" dataNode="dn1"></schema> <dataNode name="dn1" dataHost="aiMasterSlave" database="master_slave_test" /> <dataHost name="aiMasterSlave" maxCon="1000" minCon="10" balance="3" writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100"> <heartbeat>select user()</heartbeat> <!-- can have multi write hosts --> <writeHost host="hostM1" url="192.168.1.45:3306" user="AiMasterSlave" password="123456"> <!-- can have multi read hosts --> <readHost host="hostS2" url="192.168.1.239:3306" user="aliyun" password="123456" /> </writeHost> </dataHost> </mycat:schema>
測試讀寫分離
開啟debug級別日志(生產環境不要一直設置日志級別為debug)
vi /usr/local/mycat/conf/log4j2.xml
重啟Mycat
使用本地 Shell 測試
檢驗物理數據庫
數據已同步,說明沒問題!
查看Mycat日志
可以看到讀和寫分別走兩個服務器。至此,讀寫分離和主從配置完畢!
Mycat高可用方案
Mycat作為一個代理層中間件,Mycat系統的高可用涉及到Mycat本身的高可用以及后端MySQL的高可用。在大多數情況下,建議采用標准的MySQL主從復制高可用性配置並交付給Mycat來完成后端MySQL節點的主從自動切換。
應用強制走寫/從
一個查詢SQL語句以/*balance*/注解來確定其是走讀節點還是寫節點。 1.6以后添加了強制走讀走寫處理:
強制走從:
/*!mycat:db_type=slave*/ select * from travelrecord
/*#mycat:db_type=slave*/ select * from travelrecord
強制走寫:
/*#mycat:db_type=master*/ select * from travelrecord
/*!mycat:db_type=master*/ select * from travelrecord
根據主從延時切換
1.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時則表示主從同步,可以安全切換,否則不會切換。
<dataHost name="localhost1" maxCon="1000" minCon="10" balance="0" writeType="0" dbType="mysql" dbDriver="native" switchType="2" slaveThreshold="100"> <heartbeat>show slave status</heartbeat> <!-- can have multi write hosts --> <writeHost host="hostM1" url="localhost:3306" user="root" password="123456"></writeHost> <writeHost host="hostS1" url="localhost:3316" user="root" password="123456"/> </dataHost> 1.4.1 開始支持MySQL 集群模式,讓讀更加安全可靠,配置如下: MyCAT心跳檢查語句配置為 show status like ‘wsrep%’ , dataHost 上定義兩個新屬性: switchType="3" 此時意味着開啟MySQL集群復制狀態狀態綁定的讀寫分離與切換機制,Mycat心跳機制通過檢測集群復制時延時,如果延時過大或者集群出現節點問題不會負載改節點。 <dataHost name="localhost1" maxCon="1000" minCon="10" balance="0" writeType="0" dbType="mysql" dbDriver="native" switchType="3" > <heartbeat> show status like ‘wsrep%’</heartbeat> <writeHost host="hostM1" url="localhost:3306" user="root" password="123456"></writeHost> <writeHost host="hostS1" url="localhost:3316" user="root" password="123456"></writeHost> </dataHost>
主從數據監控
關於主從監控(數據一致性,延遲監測),我使用的是 percona-toolkit
關於 percona-toolkit 的配置與使用,可以參考:http://www.cnblogs.com/kevingrace/p/6261091.html