為什么需要讀寫分離
至于為什么需要讀寫分離,在我之前的文章有介紹過(guò)了,相信看到這篇文章的人也知道為什么需要讀寫分離了,當(dāng)然如果你也需要了解一下,那么歡迎查看我之前的文章SpringBoot Mybatis 讀寫分離配置,順便也可以了解一下怎么通過(guò)代碼進(jìn)行讀寫分離的
MySQL主從復(fù)制
主從復(fù)制是讀寫分離的關(guān)鍵,不管通過(guò)什么方式進(jìn)行讀寫分離,前提就是MySQL有主從復(fù)制,當(dāng)前雙機(jī)主從也行,但是關(guān)鍵的關(guān)鍵,是要能保證2個(gè)庫(kù)的數(shù)據(jù)能一致(出掉剛寫入主庫(kù)從庫(kù)還未能及時(shí)反應(yīng)過(guò)來(lái)的情況),如果2個(gè)庫(kù)的數(shù)據(jù)不一致,那么讀寫分離也有沒(méi)有任何意義了,具體MySQL怎么做主從復(fù)制可以查看我之前的文章MySQL主從復(fù)制搭建,基于日志(binlog)
Mycat是什么
一個(gè)徹底開源的,面向企業(yè)應(yīng)用開發(fā)的大數(shù)據(jù)庫(kù)集群
支持事務(wù)、ACID、可以替代MySQL的加強(qiáng)版數(shù)據(jù)庫(kù)
一個(gè)可以視為MySQL集群的企業(yè)級(jí)數(shù)據(jù)庫(kù),用來(lái)替代昂貴的Oracle集群
一個(gè)融合內(nèi)存緩存技術(shù)、NoSQL技術(shù)、HDFS大數(shù)據(jù)的新型SQL Server
結(jié)合傳統(tǒng)數(shù)據(jù)庫(kù)和新型分布式數(shù)據(jù)倉(cāng)庫(kù)的新一代企業(yè)級(jí)數(shù)據(jù)庫(kù)產(chǎn)品
一個(gè)新穎的數(shù)據(jù)庫(kù)中間件產(chǎn)品
以上內(nèi)容來(lái)自Mycat官網(wǎng),簡(jiǎn)單來(lái)說(shuō),Mycat就是一個(gè)數(shù)據(jù)庫(kù)中間件,對(duì)于我們開發(fā)來(lái)說(shuō),就像是一個(gè)代理,當(dāng)我們需要使用到多個(gè)數(shù)據(jù)庫(kù)和需要進(jìn)行分庫(kù)分表的時(shí)候,我們只需要在mycat里面配置好相關(guān)規(guī)則,程序無(wú)需做任何修改,只是需要將原本的數(shù)據(jù)源鏈接到mycat而已,當(dāng)然如果以前有多個(gè)數(shù)據(jù)源,需要將數(shù)據(jù)源切換為單個(gè)數(shù)據(jù)源,這樣有個(gè)好處就是當(dāng)我們的數(shù)據(jù)量已經(jīng)很大的時(shí)候,需要開始分庫(kù)分表或者做讀寫分離的時(shí)候,不用修改代碼(只需要改一下數(shù)據(jù)源的鏈接地址)
Mycat讀寫分離設(shè)置
配置Mycat用戶
Mycat的用戶就跟MySQL用戶是同一個(gè)意思,主要配置鏈接到Mycat的用戶名以及密碼,以及能使用的邏輯庫(kù),用戶信息主要在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="defaultSqlParser">druidparser</property>
<!-- <property name="useCompression">1</property>--> <!--1為開啟mysql壓縮協(xié)議-->
<!-- <property name="processorBufferChunk">40960</property> -->
<!--
<property name="processors">1</property>
<property name="processorExecutor">32</property>
-->
<!--默認(rèn)是65535 64K 用于sql解析時(shí)最大文本長(zhǎng)度 -->
<!--<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="mutiNodeLimitType">1</property> 0:開啟小數(shù)量級(jí)(默認(rèn)) ;1:開啟億級(jí)數(shù)據(jù)排序
<property name="mutiNodePatchSize">100</property> 億級(jí)數(shù)量排序批量
<property name="processors">32</property> <property name="processorExecutor">32</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> -->
</system>
<user name="raye">
<property name="password">rayewang</property>
<property name="schemas">separate</property>
</user>
</host>
</mycat:server>
其中<user name="raye">定義了一個(gè)名為raye的用戶,標(biāo)簽user中的<property name="password">rayewang</property>定義了用戶的密碼,<property name="schemas">separate</property>定義了用戶可以使用的邏輯庫(kù)
配置Mycat邏輯庫(kù)
Mycat的配置有很多,不過(guò)因?yàn)槲覀冎皇鞘褂肕ycat的讀寫分類的功能,所以用到的配置并不多,只需要配置一些基本的,當(dāng)然本文也只是會(huì)介紹到讀寫分離相關(guān)的配置,其他配置建議讀者自己查看一下文檔,或者通過(guò)其他方式了解,邏輯庫(kù)是在schema.xml中配置的
首先介紹Mycat邏輯庫(kù)中的一些配置標(biāo)簽
schema
schema 標(biāo)簽是用來(lái)定義邏輯庫(kù)的,schema有四個(gè)屬性dataNode,checkSQLschema,sqlMaxLimit,name
dataNode 標(biāo)簽屬性用于綁定邏輯庫(kù)到某個(gè)具體的 database 上,1.3 版本如果配置了 dataNode,則不可以配置分片表,1.4 可以配置默認(rèn)分片,只需要配置需要分片的表即可
name是定義當(dāng)前邏輯庫(kù)的名字的,方便server.xml中定義用戶時(shí)的引用
checkSQLschema當(dāng)該值設(shè)置為 true 時(shí),如果我們執(zhí)行語(yǔ)句select * from separate.users;則 MyCat 會(huì)把語(yǔ)句修改
為select * from users;。即把表示 schema 的字符去掉,避免發(fā)送到后端數(shù)據(jù)庫(kù)執(zhí)行時(shí)報(bào)(ERROR 1146 (42S02): Table ‘separate.users’ doesn’t exist)。
不過(guò),即使設(shè)置該值為 true ,如果語(yǔ)句所帶的是并非是 schema 指定的名字,例如:select * from db1.users; 那么 MyCat 并不會(huì)刪除 db1 這個(gè)字段,如果沒(méi)有定義該庫(kù)的話則會(huì)報(bào)錯(cuò),所以在提供 SQL語(yǔ)句的最好是不帶這個(gè)字段。
sqlMaxLimit當(dāng)該值設(shè)置為某個(gè)數(shù)值時(shí)。每條執(zhí)行的 SQL 語(yǔ)句,如果沒(méi)有加上 limit 語(yǔ)句,MyCat 也會(huì)自動(dòng)的加上所對(duì)應(yīng)的值。例如設(shè)置值為 100,執(zhí)行select * from users;的效果為和執(zhí)行select * from users limit 100;相同。設(shè)置該值的話,MyCat 默認(rèn)會(huì)把查詢到的信息全部都展示出來(lái),造成過(guò)多的輸出。所以,在正常使用中,還是建議加上一個(gè)值,用于減少過(guò)多的數(shù)據(jù)返回。當(dāng)然 SQL 語(yǔ)句中也顯式的指定 limit 的大小,不受該屬性的約束。需要注意的是,如果運(yùn)行的 schema 為非拆分庫(kù)的,那么該屬性不會(huì)生效。需要手動(dòng)添加 limit 語(yǔ)句。
schema標(biāo)簽中有標(biāo)簽table用于定義不同的表分片信息,不過(guò)我們只是做讀寫分離,并不會(huì)用到,所以這里就不多介紹了
dataNode
dataNodedataNode 標(biāo)簽定義了 MyCat 中的數(shù)據(jù)節(jié)點(diǎn),也就是我們通常說(shuō)所的數(shù)據(jù)分片。一個(gè) dataNode 標(biāo)簽就是一個(gè)獨(dú)立的數(shù)據(jù)分片,dataNode有3個(gè)屬性:name,dataHost,database。
name定義數(shù)據(jù)節(jié)點(diǎn)的名字,這個(gè)名字需要是唯一的,此名字是用于table標(biāo)簽和schema標(biāo)簽中引用的
dataHost該屬性用于定義該分片屬于哪個(gè)數(shù)據(jù)庫(kù)實(shí)例的,屬性值是引用 dataHost 標(biāo)簽上定義的 name 屬性
database該屬性用于定義該分片屬性哪個(gè)具體數(shù)據(jù)庫(kù)實(shí)例上的具體庫(kù),因?yàn)檫@里使用兩個(gè)緯度來(lái)定義分片,就是:實(shí)例+具體的庫(kù)。因?yàn)槊總€(gè)庫(kù)上建立的表和表結(jié)構(gòu)是一樣的。所以這樣做就可以輕松的對(duì)表進(jìn)行水平拆分
dataHost
dataHost是定義真實(shí)的數(shù)據(jù)庫(kù)連接的標(biāo)簽,該標(biāo)簽在 mycat 邏輯庫(kù)中也是作為最底層的標(biāo)簽存在,直接定義了具體的數(shù)據(jù)庫(kù)實(shí)例、讀寫分離配置和心跳語(yǔ)句,dataHost有7個(gè)屬性:name,maxCon,minCon,balance,writeType,dbType,dbDriver,有2個(gè)標(biāo)簽heartbeat,writeHost,其中writeHost標(biāo)簽中又包含一個(gè)readHost標(biāo)簽
name唯一標(biāo)識(shí) dataHost 標(biāo)簽,供dataNode標(biāo)簽使用
maxCon指定每個(gè)讀寫實(shí)例連接池的最大連接。也就是說(shuō),標(biāo)簽內(nèi)嵌套的 writeHost、readHost 標(biāo)簽都會(huì)使用這個(gè)屬性的值來(lái)實(shí)例化出連接池的最大連接數(shù)
minCon指定每個(gè)讀寫實(shí)例連接池的最小連接,初始化連接池的大小
balance
讀取負(fù)載均衡類型
balance="0", 不開啟讀寫分離機(jī)制,所有讀操作都發(fā)送到當(dāng)前可用的 writeHost 上。
balance="1",全部的 readHost 與 stand by writeHost 參與 select 語(yǔ)句的負(fù)載均衡,簡(jiǎn)單的說(shuō),當(dāng)雙主雙從模式(M1->S1,M2->S2,并且 M1 與 M2 互為主備),正常情況下,M2,S1,S2 都參與 select 語(yǔ)句的負(fù)載均衡。
balance="2",所有讀操作都隨機(jī)的在 writeHost、readhost 上分發(fā)。
balance="3",所有讀請(qǐng)求隨機(jī)的分發(fā)到 wiriterHost 對(duì)應(yīng)的 readhost 執(zhí)行,writerHost 不負(fù)擔(dān)讀壓力
writeType寫入負(fù)載均衡類型,目前的取值有 3 種:
writeType="0", 所有寫操作發(fā)送到配置的第一個(gè) writeHost,第一個(gè)掛了切到還生存的第二個(gè)writeHost,重新啟動(dòng)后已切換后的為準(zhǔn),切換記錄在配置文件中:dnindex.properties .
writeType="1",所有寫操作都隨機(jī)的發(fā)送到配置的 writeHost
dbType 指定后端連接的數(shù)據(jù)庫(kù)類型,目前支持二進(jìn)制的 mysql 協(xié)議,還有其他使用 JDBC 連接的數(shù)據(jù)庫(kù)。例如:mongodb、oracle、spark 等
dbDriver指定連接后端數(shù)據(jù)庫(kù)使用的 Driver,目前可選的值有 native 和 JDBC。使用 native 的話,因?yàn)檫@個(gè)值執(zhí)行的
是二進(jìn)制的 mysql 協(xié)議,所以可以使用 mysql 和 maridb。其他類型的數(shù)據(jù)庫(kù)則需要使用 JDBC 驅(qū)動(dòng)來(lái)支持。從 1.6 版本開始支持 postgresql 的 native 原始協(xié)議。
如果使用 JDBC 的話需要將符合 JDBC 4 標(biāo)準(zhǔn)的驅(qū)動(dòng) JAR 包放到 MYCAT\lib 目錄下,并檢查驅(qū)動(dòng) JAR 包中包括如下目錄結(jié)構(gòu)的文件:META-INF\services\java.sql.Driver。在這個(gè)文件內(nèi)寫上具體的 Driver 類名,例如:
com.mysql.jdbc.Driver。
heartbeat這個(gè)標(biāo)簽內(nèi)指明用于和后端數(shù)據(jù)庫(kù)進(jìn)行心跳檢查的語(yǔ)句。例如,MYSQL 可以使用 select user(),Oracle 可以使用 select 1 from dual 等。
這個(gè)標(biāo)簽還有一個(gè) connectionInitSql 屬性,主要是當(dāng)使用 Oracla 數(shù)據(jù)庫(kù)時(shí),需要執(zhí)行的初始化 SQL 語(yǔ)句就這個(gè)放到這里面來(lái)。例如:alter session set nls_date_format='yyyy-mm-dd hh24:mi:ss'
writeHost,readHost這兩個(gè)標(biāo)簽都指定后端數(shù)據(jù)庫(kù)的相關(guān)配置給 mycat,用于實(shí)例化后端連接池。唯一不同的是,writeHost 指定寫實(shí)例、readHost 指定讀實(shí)例,組著這些讀寫實(shí)例來(lái)滿足系統(tǒng)的要求。
在一個(gè) dataHost 內(nèi)可以定義多個(gè) writeHost 和 readHost。但是,如果 writeHost 指定的后端數(shù)據(jù)庫(kù)宕機(jī),那么這個(gè) writeHost 綁定的所有 readHost 都將不可用。另一方面,由于這個(gè) writeHost 宕機(jī)系統(tǒng)會(huì)自動(dòng)的檢測(cè)到,并切換到備用的 writeHost 上去,這2個(gè)標(biāo)簽屬性都一致,擁有host,url,password,user,weight,usingDecrypt等屬性
host用于標(biāo)識(shí)不同實(shí)例,一般 writeHost 我們使用M1,readHost 我們用S1
url真實(shí)數(shù)據(jù)庫(kù)的實(shí)例的鏈接地址,如果是使用 native 的 dbDriver,則一般為 address:port 這種形式。用 JDBC 或其他的dbDriver,則需要特殊指定。當(dāng)使用 JDBC 時(shí)則可以這么寫:jdbc:mysql://localhost:3306/
user真實(shí)數(shù)據(jù)庫(kù)實(shí)例的鏈接用戶名
password真實(shí)數(shù)據(jù)庫(kù)實(shí)例的鏈接密碼
weight權(quán)重 配置在 readhost 中作為讀節(jié)點(diǎn)的權(quán)重,主要用于多臺(tái)讀取的數(shù)據(jù)庫(kù)實(shí)例機(jī)器配置不同的情況,可以根據(jù)權(quán)重調(diào)整訪問(wèn)量
usingDecrypt是否對(duì)密碼加密默認(rèn) 0 否 如需要開啟配置 1,同時(shí)使用加密程序?qū)γ艽a加密
==注意,readHost是在writeHost標(biāo)簽內(nèi)的,不是單獨(dú)的==
以下是我的讀寫分離配置文件
<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
<schema name="separate" checkSQLschema="false" sqlMaxLimit="100" dataNode="dn1"/>
<dataNode name="dn1" dataHost="localhost1" database="test" />
<dataHost name="localhost1" 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.126:3307" user="root"
password="123456">
<!-- can have multi read hosts -->
<readHost host="hostS2" url="192.168.1.126:3308" user="root" password="123456" />
</writeHost>
</dataHost>
</mycat:schema>
前面已經(jīng)差不多都解釋清楚了,因?yàn)槲抑皇怯玫幕镜闹鲝膹?fù)制,所以我的將dataHost的balance設(shè)置成了3
啟動(dòng)mycat,然后用數(shù)據(jù)庫(kù)連接工具連接到mycat,可以測(cè)試是否配置成功,最簡(jiǎn)單的就是通過(guò)修改從庫(kù)的數(shù)據(jù),這樣方便查看到底是運(yùn)行到哪個(gè)庫(kù)上面了,另外由于我是基于docker啟動(dòng)的mycat,所以如果是直接在系統(tǒng)中運(yùn)行的mycat的,可以去看官方文檔,看看到底怎么啟動(dòng)mycat