Mycat使用

Mycat使用

主從複製

複製的基本原理

slave 會從master 讀取 binlog 來進行數據同步

mysql主從複製

  1. master將改變記錄到二進制日誌(binary log)。這些記錄過程叫做二進制日誌事件,binary log events
  2. slave 將 master 的 binary log events 拷貝到它的中繼日誌(relay log)
  3. slave 重做中繼日誌中的事件,將改變應用到自己的數據庫中。 MySQL 複製是異步的且串行化的

複製的基本原則

  • 每個 master 可以有多個 salve
  • 每個 slave 只有一個 master
  • 每個 slave 只能有一個唯一的服務器 ID

配置思路

在這裏插入圖片描述

  • 配置主機,win的 my.ini,注意是:[mysqld]
[mysqld]
# The TCP/IP Port the MySQL Server will listen on
port=3306
server-id=1
log-bin=自己本地的路徑/data/mysqlbin #自定義的路徑
binlog-ignore-db=mysql
binlog-do-db=需要複製的主數據庫名字
binlog_format=STATEMENT

binlog_format 有三種:STATEMENT(默認,記錄寫操作sql,函數調用會出錯)、ROW(記錄每行變化,效率問題)、MIXED(有函數切換到R,無函數切換到S,有系統變量會出錯)

  • 從機,修改 Linux 中的 my.cnf(/etc 目錄)
[mysqld]
#加入這些
server-id = 2
relay-log=mysql-relay
  • 重啓,模擬時關閉防火牆
  • 在 Windows 主機上建立帳戶並授權 slave,查看

執行完此步驟後不要再操作主服務器MYSQL,防止主服務器狀態值變化

GRANT REPLICATION SLAVE ON *.* TO 'zhangsan'@'從機器數據庫IP' IDENTIFIED BY '123456';
show master status;
  • 在Linux 從機上配置需要複製的主機
CHANGE MASTER TO MASTER_HOST='主機IP',
MASTER_USER='zhangsan',
MASTER_PASSWORD='123456',
MASTER_LOG_FILE='File名字',
MASTER_LOG_POS=Position數字;
start slave;
show slave status\G;# 查看是否配置成功

主機新建庫、新建表、insert記錄,從機複製

進入正題

概述

是什麼?

Mycat 是數據庫中間件,前身是阿里的 cobar,屬於 proxy 層方案。

拓展:sharding-jdbc:噹噹開源的,屬於 client 層方案。

能夠幹什麼?

  • 讀寫分離
  • 數據分片
    • 垂直拆分
    • 水平拆分
    • 垂直+水平拆分
  • 多數據源整合

原理

Mycat 的原理中最重要的一個動詞是“攔截”,它攔截了用戶發送過來的 SQL 語句,

  1. 首先對 SQL 語句做了一些特定的分析:如分片分析、路由分析、讀寫分離分析、緩存分析等,
  2. 然後將此 SQL 發往後端的真實數據庫,並將返回的結果做適當的處理,
  3. 最終再返回給用戶

所以,我們只要配置 mycat,它會攔截,自動發給對應服務器處理

在這裏插入圖片描述

安裝使用

下載地址:http://www.mycat.org.cn/

修改配置文件

  • schema.xml:定義邏輯庫,表、分片節點等內容
  • rule.xml:定義分片規則
  • server.xml:定義用戶以及系統相關變量,如端口等.

啓動前先修改 schema.xml

<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
           <!--邏輯庫 name名稱,   checkSQLschema  sqlMaxLimit 末尾是否要加 limit xxx-->
        <schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100" dataNode="dn1"> </schema>
            <!--邏輯庫 name名稱, dataHost 引用的哪個dataHost  database:對應mysql的database-->
        <dataNode name="dn1" dataHost="localhost1" database="db1" />
        <dataHost name="localhost1" maxCon="1000" minCon="10" balance="0"
                          writeType="0" dbType="mysql" dbDriver="native" switchType="1"  slaveThreshold="100">
                <heartbeat>select user()</heartbeat>
                <!-- can have multi write hosts -->
                <writeHost host="hostM1" url="localhost:3306" user="root"
                                   password="123456">
                </writeHost>
        </dataHost>
</mycat:schema>

再修改 server.xml

<user name="root">
                <property name="password">654321</property>
                <property name="schemas">TESTDB</property>
</user>

驗證數據庫訪問情況

mysql -uroot -p123123 -h 192.168.154.1 -P 3306
mysql -uroot -p123123 -h 192.168.154.154 -P 3306
# 如本機遠程訪問報錯,請建對應用戶
grant all privileges on *.* to root@'缺少的host'  identified by '123123';

啓動程序

  • 控制檯啓動 :去mycat/bin 目錄下 mycat console
  • 後臺啓動 :去mycat/bin 目錄下 mycat start

啓動時可能出現報錯:域名解析失敗

  1. 用 vim 修改 /etc/hosts 文件 (在 127.0.0.1 後面增加你的機器名)
  2. 修改後重新啓動網絡服務 service network restart

登錄

  • 後臺管理窗口
    • mysql -uroot -p654321 -P9066 -h192.168.67.131
    • show database
    • show @@help
  • 數據窗口
    • mysql -uroot -p654321 -P8066 -h192.168.67.131

讀寫分離

注意:必須完成主從複製的搭建,才能實現讀寫分離

在這裏插入圖片描述

配置 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="host1" database="atguigu_mc" />
        <dataHost name="host1" maxCon="1000" minCon="10" balance="3"
                          writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
                <heartbeat>select user()</heartbeat>
                <writeHost host="hostm1" url="192.168.67.1:3306" user="root"
                                   password="123123">
<!--讀庫(從庫)的配置 -->
                       <readHost host="hosts1" url="192.168.67.131:3306" user="root"
                                   password="123123">
                       </readHost>
                </writeHost>
        </dataHost>
</mycat:schema>

負載均衡類型,目前的取值有4 種

  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",所有讀請求隨機的分發到 readhost 執行,writerHost 不負擔讀壓力

讀寫分離

  1. 創建表 t_replica
  2. 分別在兩個庫下插入:insert into t_replica(name) values (@@hostname)
  3. 然後再 mycat下執行 select * from t_replica 查詢實驗

垂直分庫

一個庫的瓶頸約爲 5kw,一個表的瓶頸約爲 500w

水平與垂直拆分

  • 水平拆分的意思,就是把一個表的數據給弄到多個庫的多個表裏去,但是每個庫的表結構都一樣,只不過每個庫表放的數據是不同的,所有庫表的數據加起來就是全部數據。用多個庫來抗更高的併發,還有就是用多個庫的存儲容量來進行擴容。
  • 垂直拆分的意思,就是把一個有很多字段的表給拆分成多個表,或者是多個庫上去。一般來說,會將較少的訪問頻率很高的字段放到一個表裏去,然後將較多的訪問頻率很低的字段放到另外一個表裏去。

場景

有一個庫,

  • #客戶表 rows:20萬
  • #訂單表 rows:600萬
  • #訂單詳細表 rows:600萬
  • #訂單狀態字典表 rows:20萬

垂直分庫操作

  • 搭建兩個乾淨的庫,通過 mycat 做分庫操作
  • 拆分時需注意 join 關聯情況要避免

在這裏插入圖片描述

配置 schema.xml

<mycat:schema xmlns:mycat="http://io.mycat/">
 
        <schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100" dataNode="dn1">
                <table name="customer" dataNode="dn2" ></table>
        </schema>
        <dataNode name="dn1" dataHost="host1" database="atguigu_mc" />
    <!--配置 dn2-->
        <dataNode name="dn2" dataHost="host2" database="atguigu_sm" />
        <dataHost name="host1" maxCon="1000" minCon="10" balance="3"
                          writeType="0" dbType="mysql" dbDriver="native" switchType="1"  slaveThreshold="100">
                <heartbeat>select user()</heartbeat>
                <writeHost host="hostm1" url="192.168.67.1:3306" user="root"
                                   password="123123">
                       <readHost host="hosts1" url="192.168.67.131:3306" user="root"
                                   password="123123">
                       </readHost>
                </writeHost>
        </dataHost>
    <!--配置 host2,balance改爲0,不做讀寫分離 -->
        <dataHost name="host2" maxCon="1000" minCon="10" balance="0"
                          writeType="0" dbType="mysql" dbDriver="native" switchType="1"  slaveThreshold="100">
                <heartbeat>select user()</heartbeat>
                <writeHost host="hostm2" url="192.168.67.1:3306" user="root"
                                   password="123123">
                </writeHost>
        </dataHost>
 
</mycat:schema>
 

若未建立新分庫,則會報錯哦

水平分表

水平分表

在這裏插入圖片描述

  • 我們拆分 order 表

修改 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">
                <table name="customer" dataNode="dn2" ></table>
            <!--配置要分的 order 表,指定rule 算法-->
                <table name="orders" dataNode="dn1,dn2"  rule="mod_rule" ></table>
        </schema>
        <dataNode name="dn1" dataHost="host1" database="atguigu_mc" />
        <dataNode name="dn2" dataHost="host2" database="atguigu_sm" />
        <dataHost name="host1" maxCon="1000" minCon="10" balance="2"
                          writeType="0" dbType="mysql" dbDriver="native" switchType="1"  slaveThreshold="100">
                <heartbeat>select user()</heartbeat>
                <writeHost host="hostm1" url="192.168.67.1:3306" user="root"
                                   password="123123">
                <!--       <readHost host="hosts1" url="192.168.67.131:3306" user="root"
                                   password="123123">
                       </readHost>-->
                </writeHost>
        </dataHost>
        <dataHost name="host2" maxCon="1000" minCon="10" balance="0"
                          writeType="0" dbType="mysql" dbDriver="native" switchType="1"  slaveThreshold="100">
                <heartbeat>select user()</heartbeat>
                <writeHost host="hostm2" url="192.168.67.1:3306" user="root"
                                   password="123123">
                </writeHost>
        </dataHost>

修改 rule.xml

<tableRule name="mod_rule">
    <!--配置分片規則,注意字段名啊,要和表中一致 -->
             <rule>
                        <columns>customer_id</columns>
                        <algorithm>mod-long</algorithm>
               </rule>
       </tableRule>
 
<function name="mod-long" class="io.mycat.route.function.PartitionByMod">
                <!-- 節點數記得改啊 -->
                <property name="count">2</property>
        </function>
 

關聯表

跨庫無法 join 查詢,那關聯表(訂單詳情表)怎麼拆呢?

配置 ER 表:爲了相關聯的表的行儘量分在一個庫下,這裏就是訂單詳情表的配置

配置 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">
                <table name="customer" dataNode="dn2" ></table>
                <table name="orders" dataNode="dn1,dn2"  rule="mod_rule" >
                    <!--在這裏指定關聯表 -->
                    <childTable name="orders_detail" primaryKey="id" joinKey="order_id" parentKey="id" />
                </table>
            <!--在這裏指定全局表 -->
                <table name="dict_status" dataNode="dn1,dn2" type="global" ></table>
        </schema>
        <dataNode name="dn1" dataHost="host1" database="atguigu_mc" />
        <dataNode name="dn2" dataHost="host2" database="atguigu_sm" />
        <dataHost name="host1" maxCon="1000" minCon="10" balance="2"
                          writeType="0" dbType="mysql" dbDriver="native" switchType="1"  slaveThreshold="100">
                <heartbeat>select user()</heartbeat>
                <writeHost host="hostm1" url="192.168.67.1:3306" user="root"
                                   password="123123">
                <!--       <readHost host="hosts1" url="192.168.67.131:3306" user="root"
                                   password="123123">
                       </readHost>-->
                </writeHost>
        </dataHost>
        <dataHost name="host2" maxCon="1000" minCon="10" balance="0"
                          writeType="0" dbType="mysql" dbDriver="native" switchType="1"  slaveThreshold="100">
                <heartbeat>select user()</heartbeat>
                <writeHost host="hostm2" url="192.168.67.1:3306" user="root"
                                   password="123123">
                </writeHost>
        </dataHost>
 
</mycat:schema>
 

全局表:每個庫都會使用的表,一般數據量不會過大,這裏就是訂單狀態字典表的配置

  • 設定爲全局的表,會直接複製給每個數據庫一份,所有寫操作也會同步給多個庫。
  • 所以全局表一般不能是大數據表或者更新頻繁的表
  • 一般是字典表或者系統表爲宜。
<?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">
                <table name="customer" dataNode="dn2" ></table>
                <table name="orders" dataNode="dn1,dn2"  rule="mod_rule" ></table>
                 <table name="dict_order_type" dataNode="dn1,dn2" type="global" ></table>
        </schema>
        <dataNode name="dn1" dataHost="host1" database="atguigu_mc" />
        <dataNode name="dn2" dataHost="host2" database="atguigu_sm" />
        <dataHost name="host1" maxCon="1000" minCon="10" balance="2"
                          writeType="0" dbType="mysql" dbDriver="native" switchType="1"  slaveThreshold="100">
                <heartbeat>select user()</heartbeat>
                <writeHost host="hostm1" url="192.168.67.1:3306" user="root"
                                   password="123123">
                <!--       <readHost host="hosts1" url="192.168.67.131:3306" user="root"
                                   password="123123">
                       </readHost>-->
                </writeHost>
        </dataHost>
        <dataHost name="host2" maxCon="1000" minCon="10" balance="0"
                          writeType="0" dbType="mysql" dbDriver="native" switchType="1"  slaveThreshold="100">
                <heartbeat>select user()</heartbeat>
                <writeHost host="hostm2" url="192.168.67.1:3306" user="root"
                                   password="123123">
                </writeHost>
        </dataHost>
 

分表小結

  • 直接根據 rule 算法分表:如訂單表
  • ER 表(childTable):如訂單詳情表 隨着訂單表連帶
  • 全局表:每個庫都會複製的表,如字典表、系統表

全局序列

用於:保證配置多個節點時,如訂單 id 不會重複

幾種方式

  • 本地文件:不推薦,抗風險能力太差
  • 時間戳方式:不推薦,太長了
  • 數據庫方式

數據庫方式

原理

  • 利用數據庫一個表 來進行計數累加。
  • 但是並不是每次生成序列都讀寫數據庫,這樣效率太低
  • mycat 會預加載一部分號段到 mycat 的內存中,這樣大部分讀寫序列都是在內存中完成的。
  • 如果內存中的號段用完了 mycat會再向數據庫要一次。

那如果mycat崩潰了 ,那內存中的序列豈不是都沒了?

是的。如果是這樣,那麼 mycat 啓動後會向數據庫申請新的號段,原有號段會棄用。

也就是說如果mycat重啓,那麼損失是當前的號段沒用完的號碼,但是不會因此出現主鍵重複

建庫序列腳本

腳本

win10
DELIMITER $$
 
CREATE FUNCTION mycat_seq_currval(seq_name VARCHAR(50)) RETURNS VARCHAR(64)
DETERMINISTIC  
BEGIN
DECLARE retval VARCHAR(64);
SET retval="-999999999,null";
SELECT CONCAT(CAST(current_value AS CHAR),",",CAST(increment AS CHAR)) INTO retval FROM
MYCAT_SEQUENCE WHERE NAME = seq_name;
RETURN retval;
END $$
DELIMITER;
 
DELIMITER $$
CREATE FUNCTION mycat_seq_setval(seq_name VARCHAR(50),VALUE INTEGER) RETURNS VARCHAR(64)
DETERMINISTIC
BEGIN
UPDATE MYCAT_SEQUENCE
SET current_value = VALUE
WHERE NAME = seq_name;
RETURN mycat_seq_currval(seq_name);
END $$
DELIMITER ;
 
DELIMITER $$
CREATE FUNCTION mycat_seq_nextval(seq_name VARCHAR(50)) RETURNS VARCHAR(64) 
DETERMINISTIC
BEGIN
UPDATE MYCAT_SEQUENCE
SET current_value = current_value + increment WHERE NAME = seq_name;
RETURN mycat_seq_currval(seq_name);
END $$
DELIMITER;

測試

CREATE TABLE MYCAT_SEQUENCE (NAME VARCHAR(50) NOT NULL,current_value INT NOT
NULL,increment INT NOT NULL DEFAULT 100, PRIMARY KEY(NAME)) ENGINE=INNODB;

SELECT * FROM MYCAT_SEQUENCE
 
TRUNCATE TABLE MYCAT_SEQUENCE

##增加要用的序列
INSERT INTO MYCAT_SEQUENCE(NAME,current_value,increment) VALUES ('ORDERS', 400000,
100);

修改 mycat 配置

  • vim sequence_db_conf.properties ,修改序列對應的節點,參考schema.xml
  • vim server.xml,改成1,使用數據庫方式
<property name="sequnceHandlerType">1<property>

自主生成

  • 根據業務邏輯組合
  • 可以利用 redis 的單線程原子性 incr來生成序列
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章