Mycat實現mysql主從複製(讀寫分離)

數據庫性能瓶頸主要緣由:
  1. 隨着用戶數的增多,帶來的是數據庫鏈接的大幅度增加
  2. 隨着業務體量的增加,表數據量(空間存儲的問題)的大幅增加,其中涉及到索引的優化,mysql默認的索引是硬盤級別的,BTREE(B樹)
  3. 硬件資源限制(QPS\TPS)
數據性能優化方案:
  1. sql優化
  2. 緩存
  3. 建好索引
  4. 讀寫分離
  5. 分庫分表

  在分佈式架構的數據庫優化方案中,最有效的則是讀寫分離與分庫分表了。java

大數據量數據庫性能解決方案:node

  一、讀寫分離區別讀、寫多數據源方式進行數據的存儲和加載。數據的存儲(增刪改)通常指定寫數據源,數據的讀取查詢指定讀數據源(讀寫分離會基於主從複製)mysql

  二、分庫分表對數據的庫表進行拆分,用分片的方式對數據進行管理。算法

Mycat:

  • 一個完全開源的,面向企業應用開發的大數據庫集羣
  • 支持事務、ACID、能夠替代MySQL的增強版數據庫
  • 一個能夠視爲MySQL集羣的企業級數據庫,用來替代昂貴的Oracle集羣
  • 一個融合內存緩存技術、NoSQL技術、HDFS大數據的新型SQL Server
  • 結合傳統數據庫和新型分佈式數據倉庫的新一代企業級數據庫產品
  • 一個新穎的數據庫中間件產品

  通俗點講,應用層能夠將它看做是一個數據庫的代理(或者直接當作增強版數據庫)。sql

邏輯庫(schema): 數據庫

  一般對實際應用來講,並不須要知道中間件的存在,業務開發人員只須要知道 數據庫的概念,因此數據庫中間件能夠被看作是一個或多個數據庫集羣構成的邏輯庫。 在雲計算時代,數據庫中間件能夠以多租戶的形式給一個或多個應用提供服務,每一個應用訪問的多是一個 獨立或者是共享的物理庫,常見的如阿里雲數據庫服務器 RDS。express

邏輯表(table):apache

  既然有邏輯庫,那麼就會有邏輯表,分佈式數據庫中,對應用來講,讀寫數據的表就是邏輯表。邏輯表,可 以是數據切分後,分佈在一個或多個分片庫中,也能夠不作數據切分,不分片,只有一個表構成。緩存

分片表 :安全

  是指那些原有的很大數據的表,須要切分到多個數據庫的表,這樣,每一個分片都有一部分數據,所 有分片構成了完整的數據。 例如在 mycat 配置中的 t_node 就屬於分片表,數據按照規則被分到 dn1,dn2 兩個分片節點(dataNode) 上。

非分片表

  一個數據庫中並非全部的表都很大,某些表是能夠不用進行切分的,非分片是相對分片表來講的,就是那 些不須要進行數據切分的表。只存在於分片節點(dataNode)dn1 上。

ER 表 :

  關係型數據庫是基於實體關係模型(Entity-Relationship Model)之上,經過其描述了真實世界中事物與關 系,Mycat 中的 ER 表便是來源於此。根據這一思路,提出了基於 E-R 關係的數據分片策略,子表的記錄與所關 聯的父表記錄存放在同一個數據分片上,即子表依賴於父表,經過表分組(Table Group)保證數據 Join 不會跨 庫操做。 表分組(Table Group)是解決跨分片數據 join 的一種很好的思路,也是數據切分規劃的重要一條規則。 如用戶的地址表,用戶表對應的用戶可能有多個地址,在進行分片後所對應的地址表也應該放入相同分區。

全局表 :

  一個真實的業務系統中,每每存在大量的相似字典表的表,這些表基本上不多變更,字典表具備如下幾個特 性: • 變更不頻繁; • 數據量整體變化不大; • 數據規模不大,不多有超過數十萬條記錄。 對於這類的表,在分片的狀況下,當業務表由於規模而進行分片之後,業務表與這些附屬的字典表之間的關 聯,就成了比較棘手的問題,因此 Mycat 中經過數據冗餘來解決這類表的 join,即全部的分片都有一份數據的拷 貝,全部將字典表或者符合字典表特性的一些表定義爲全局表。 數據冗餘是解決跨分片數據 join 的一種很好的思路,也是數據切分規劃的另一條重要規則。

主從複製:

  Mysql做爲目前世界上使用最普遍的免費數據庫,相信全部從事系統運維的工程師都必定接觸過。但在實際的生產環境中,由單臺Mysql做爲獨立的數據庫是徹底不能知足實際需求的,不管是在安全性,高可用性以及高併發等各個方面。

  所以,通常來講都是經過 主從複製(Master-Slave)的方式來同步數據,再經過讀寫分離(MySQL-Proxy)來提高數據庫的併發負載能力 這樣的方案來進行部署與實施的。

 主從複製的原理:

  1.  master將操做記錄到二進制日誌(binary log)中(這些記錄叫作二進制日誌事件,binary logevents)
  2. Slave經過I/O Thread異步將master的binary logevents拷貝到它的中繼日誌(relay log);
  3. Slave執行relay日誌中的事件,匹配本身的配置將須要執行的數據,在slave服務上執行一遍從而達到複製數據的目的。

   master 配置:

1.接入mysql並建立主從複製的用戶create user "username" identified by 'password';

2.給新建的用戶賦權GRANT REPLICATION SLAVE ON *.* TO 'username'@'%' IDENTIFIED BY ''password'';

3.指定服務ID,開啓binlog日誌記錄,在my.cn中加入

  server-id=137

  log-bin=dbstore_binlog

  binlog-do-db=db_store 

4.經過SHOW MASTER STATUS;查看Master db狀態

   master 其餘相關配置:

1 log-bin=mysql-bin 
       控制master的是否開啓binlog記錄功能;二進制文件最好放在單獨的目錄下,這不但方便優化、更方便維護。以下例子:要從新調整logbin的路徑爲「/home/mysql/binlog」
    log_bin=/home/mysql/binlog/binlog.log須要注意:指定目錄時候必定要以*.log結尾,即不能僅僅指定到文件夾的級別,不然在重啓mysql時會報錯。
2. server-id=1
     每一個server服務的標識,在master/slave環境中,此變量必定要不同
3. expire_logs_days=15
  經過此來實現master自動刪除binlog
4. innodb_flush_log_at_trx_commit=1 
  此參數表示在事務提交時,處理重作日誌的方式;此變量有三個可選值0,1,2:
  0:當事務提交時,並不將事務的重作日誌寫入日誌文件,而是等待每秒刷新一次
  1:當事務提交時,將重作日誌緩存的內容同步寫到磁盤日誌文件,爲了保證數據一致性,在replication環境中使用此值。
  2:當事務提交時,將重作日誌緩存的內容異步寫到磁盤日誌文件(寫到文件系統緩存中)
  建議必須設置innodb_flush_log_at_trx_commit=1 
5.sync_binlog=1 
  一、此參數表示每寫緩衝多少次就同步到磁盤;
  二、sync_binlog=1表示同步寫緩衝和磁盤二進制日誌文件,不使用文件系統緩存
  在使用innodb事務引擎時,在複製環境中,爲了保證最大的可用性,都設置爲「1」,但會對影響io的性能。
  三、即便設置爲「1」,也會有問題發生:
  假如當二進制日誌寫入磁盤,但事務尚未commit,這個時候宕機,當服務再次起來的恢復的時候,沒法回滾以及記錄到二進制日誌的未提交的內容;這個時候就會形成master和slave數據不一致
  解決方案:
  須要參數innodb_support_xa=1來保證。建議必須設置
6 .innodb_support_xa=1
  此參數與XA事務有關,它保證了二進制日誌和innodb數據文件的同步,保證複製環境中數據一致性。建議必須設置
7.binlog-do-db=skate_db
  只記錄指定數據庫的更新到二進制日誌中
8. binlog-do-table=skate_tab
  只記錄指定表的更新到二進制日誌中
9. binlog-ignore-db=skate_db
  忽略指定數據庫的更新到二進制日誌中
10.log_slave_updates=1
  此參數控制slave數據庫是否把從master接受到的log並在本slave執行的內容記錄到slave的二進制日誌中
  在級聯複製環境中(包括雙master環境),這個參數是必須的
11.binlog_format=statement|row|mixed
  控制以什麼格式記錄二進制日誌的內容,默認是mixed
12. max_binlog_size
  master的每一個二進制日誌文件的大小,默認1G
13.binlog_cache_size
  一、全部未提交的事務都會被記錄到一個緩存或臨時文件中,待提交時,統一同步到二進制日誌中,
  二、此變量是基於session的,每一個會話開啓一個binlog_cache_size大小的緩存。
  三、經過變量「Binlog_cache_disk_use」和「Binlog_cache_use」來設置binlog_cache_size的大小。
  說明:
  Binlog_cache_disk_use: 使用臨時文件寫二進制日誌的次數
  Binlog_cache_use: 使用緩衝記寫二進制的次數
14.auto_increment_increment=2 //增加的步長
  auto_increment_offset=1 //起始位置
  在雙master環境下能夠防止鍵值衝突 

  slave 配置:

1.指定服務器ID,指定同步的binlog存儲位置,在  my.cnf中加入

  server-id=101 

  relay-log=slave-relay-bin --中繼日誌
  relay-log-index=slave-relay-bin.indexread_
  only=1replicate_do_db=db_store

2.接入slave的mysql服務,並配置

  change master to master_host='192.168.254.138',master_port=3306,master_user='slave1',master_password='slave1',master_log_file='dbstore_binlog.000001',master_log_pos=120;

  其中 master_user 跟master_password 是由master配置的第一步所寫的 username跟password,而master_log_file跟master_log_pos 則是在master端用 show master status 查看狀態的時候所顯示的 ,也就是上文圖片中提到的 dbstore_binlog.000001 跟928,因爲我這邊是以前就作了主從以後有操做,因此從120變成了 928。
3.start slave; 若是要結束主從  執行 stop slave

4. show slave status\G ;查看slave服務器狀態 以下

 

   如圖,看到 Slave_IO_Running 跟 Slave_SQL_Running 都爲YES 說明主從關係創建完畢,能夠用客戶端工具連上測試。

  slave 其餘相關配置:

1.server-id=2
    和master的含義同樣,服務標識
2.log-bin=mysql-bin 
    和master的含義同樣,開啓二進制
3.relay-log=relay-bin 
    中繼日誌文件的路徑名稱
4. relay-log-index=relay-bin.index
    中繼日誌索引文件的路徑名稱
5. log_slave_updates=1 
    和master的含義同樣,如上
6.read_only=1
    一、使數據庫只讀,此參數在slave的複製環境和具備super權限的用戶不起做用,
    二、對於複製環境設置read_only=1很是有用,它能夠保證slave只接受master的更新,而不接受client的更新。
    三、客戶端設置:
    mysq> set global read_only=1
7. skip_slave_start
    使slave在mysql啓動時不啓動複製進程,mysql起來以後使用 start slave啓動,建議必須
8.replicate-do-db 
    只複製指定db
9.replicate-do-table
    只複製指定表
10. replicate-ingore-table
    忽略指定表
11. replicate_wild_do_table=skatedb.%
    模糊匹配複製指定db
12. auto_increment_increment=2
    auto_increment_offset=1
    和master含義同樣,參考如上 
13. log_slow_slave_statements 
    在slave上開啓慢查詢日誌,在query的時間大於long_query_time時,記錄在慢查詢日誌裏
14. max_relay_log_size
    slave上的relay log的大小,默認是1G
15.relay_log_info_file
    中繼日誌狀態信息文件的路徑名稱
16. relay_log_purge
    當relay log不被須要時就刪除,默認是on
    SET GLOBAL relay_log_purge=1
17.replicate-rewrite-db=from_name->to_name 
    數據庫的重定向,能夠把分庫彙總到主庫便於統計分析

Mycat 安裝:

  下載地址 : http://dl.mycat.io/1.6.6.1/ 

   下載完上傳至服務器 解壓後進入 mycat 主目錄:

  簡單說一下 bin與 conf 文件夾:

  bin 程序目錄:存放了可執行文件./mycat {start|restart|stop|status…}。

  conf 目錄下存放配置文件:

    server.xml 是 Mycat 服務器參數調整和用戶受權的配置文件。

    schema.xml 是邏輯庫定義和表。

    rule.xml 是分片規則的配置文件,分片規則的具體一些參數信息單獨存放爲文件,也在這個目錄下。

    log4j2.xml配置logs目錄日誌輸出規則.

    wrapper.conf JVM相關參數調整。

啓動 mycat ,進入 bin 目錄 ./mycat start : 默認端口 8066

  因爲mycat 能夠看做是一個數據庫的代理(或者直接當作增強版數據庫),mycat 能夠支持全部的基於JDBC這種鏈接的相關的東西。命令以下:

mysql -uroot -p -h192.168.254.138 -P8066
或者 mysql -uroot -p123456 -h192.168.254.138 -P8066 注意這裏的密碼是mycat的,不是mysql的

  輸入密碼之後查看當前數據庫會發現:

   這個 TESTDB 並不是 mysql 服務的,這是 mycat 的配置文件 schema.xml 中配置的邏輯庫:

<schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100">

  咱們本身來搭建一個mycat 的服務,因爲配置關係到數據庫的節點,咱們根據下圖的節點關係來配置:

   先來簡單的過一下配置文件,既然提到了schema.xml,就從他開始吧:

<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
    <!-- 邏輯庫配置-->
    <!--一個schema標籤就是一個邏輯庫, 邏輯庫名稱 -->
    <schema name="db_store" checkSQLschema="false" sqlMaxLimit="100">
        <!--非分片表的配置 名稱,從屬節點 主鍵-->
        <table name="store" dataNode="db_store_dataNode" primaryKey="storeID"/>
        <table name="employee" dataNode="db_store_dataNode" primaryKey="employeeID"/>
    </schema>
    
    <schema name="db_user" checkSQLschema="false" sqlMaxLimit="100">
        <!--全局表 指定 type ,指定所在分片 ,主鍵-->
        <table name="data_dictionary" type="global" dataNode="db_user_dataNode1,db_user_dataNode2" primaryKey="dataDictionaryID"/>
        <!--分片表的配置 ,配置分片節點 ,rule 配置分片規則,具體配置在rule.xml裏面,在rule.xml再細說-->
        <table name="users" dataNode="db_user_dataNode$1-2"  rule="mod-userID-long" primaryKey="userID">
            <!--ER表,經過parentKey去找 users表對應的分片,放到同一個分片下-->
            <childTable name="user_address"  joinKey="userID" parentKey="userID" primaryKey="addressID"/>
        </table>
    </schema>
    
    <!-- 節點配置
        爲何 db_store只有一個節點呢?由於這個節點理的兩個主機是主從複製實現了讀寫分離
        這裏即具有讀也具有了寫。在節點主機配置中有體現。
     -->
    <!-- db_store -->
    <dataNode name="db_store_dataNode" dataHost="db_storeHOST" database="db_store" />
    <!-- db_user -->
    <dataNode name="db_user_dataNode1" dataHost="db_userHOST1" database="db_user" />
    <dataNode name="db_user_dataNode2" dataHost="db_userHOST2" database="db_user" />
    
    <!-- 主從複製 節點主機配置 -->
    <!-- 配置db_store的節點主機 最大鏈接數100 最小10 -->
    <dataHost name="db_storeHOST" maxCon="1000" minCon="10" balance="1"
              writeType="0" dbType="mysql" dbDriver="native" switchType="1"  slaveThreshold="100">
        <!-- 心跳機制 -->
        <heartbeat>select user()</heartbeat>
        <!-- 讀寫分離 can have multi write hosts 寫節點(master)-->
        <writeHost host="hostM1" url="192.168.254.138:3306" user="root"  password="wuzhenzhao">
            <!-- can have multi read hosts 讀節點(slave)-->
            <readHost host="hostS1" url="192.168.254.136:3306" user="root" password="wuzhenzhao" />    
        </writeHost>
    </dataHost>

    <!-- 配置db_user的節點主機 -->
    <dataHost name="db_userHOST1" maxCon="1000" minCon="10" balance="0"
              writeType="0" dbType="mysql" dbDriver="native" switchType="1"  slaveThreshold="100">
        <heartbeat>select user()</heartbeat>
        <writeHost host="userHost1" url="192.168.254.138:3306" user="root"  password="wuzhenzhao">
        </writeHost>
    </dataHost>
    
    <dataHost name="db_userHOST2" maxCon="1000" minCon="10" balance="0"
              writeType="0" dbType="mysql" dbDriver="native" switchType="1"  slaveThreshold="100">
        <heartbeat>select user()</heartbeat>
        <writeHost host="userHost2" url="192.168.254.136:3306" user="root"  password="wuzhenzhao">
        </writeHost>
    </dataHost>
</mycat:schema>

  以上在配置分片的時候涉及到了規則的配置,來看看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="mod-long">
        <rule>
            <columns>id</columns>
            <algorithm>mod-long</algorithm>
        </rule>
    </tableRule>
    <!-- 分片規則定義-->
    <tableRule name="mod-userID-long">
        <rule>
            <!--根據哪一個列來分區-->
            <columns>userID</columns>
            <!--分區算法,指向下面的function 標籤-->
            <algorithm>mod-long</algorithm>
        </rule>
    </tableRule>
    
    <tableRule name="sharding-by-murmur">
        <rule>
            <columns>id</columns>
            <algorithm>murmur</algorithm>
        </rule>
    </tableRule>
    <tableRule name="crc32slot">
        <rule>
            <columns>id</columns>
            <algorithm>crc32slot</algorithm>
        </rule>
    </tableRule>
    <!--指定分片類。指定規則與2取模-->
    <function name="mod-long" class="io.mycat.route.function.PartitionByMod">
        <!-- how many data nodes -->
        <property name="count">2</property>
    </function>

    <function name="murmur"
        class="io.mycat.route.function.PartitionByMurmurHash">
        <property name="seed">0</property><!-- 默認是0 -->
        <property name="count">2</property><!-- 要分片的數據庫節點數量,必須指定,不然無法分片 -->
        <property name="virtualBucketTimes">160</property><!-- 一個實際的數據庫節點被映射爲這麼多虛擬節點,默認是160倍,也就是虛擬節點數是物理節點數的160倍 -->
        <!-- <property name="weightMapFile">weightMapFile</property> 節點的權重,沒有指定權重的節點默認是1。以properties文件的格式填寫,以從0開始到count-1的整數值也就是節點索引爲key,以節點權重值爲值。全部權重值必須是正整數,不然以1代替 -->
        <!-- <property name="bucketMapPath">/etc/mycat/bucketMapPath</property> 
            用於測試時觀察各物理節點與虛擬節點的分佈狀況,若是指定了這個屬性,會把虛擬節點的murmur hash值與物理節點的映射按行輸出到這個文件,沒有默認值,若是不指定,就不會輸出任何東西 -->
    </function>

    <function name="crc32slot"
              class="io.mycat.route.function.PartitionByCRC32PreSlot">
        <property name="count">2</property><!-- 要分片的數據庫節點數量,必須指定,不然無法分片 -->
    </function>
        ........
</mycat:rule>

  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>
    -->
    <!--把mycat當作一個超級數據庫,在這裏配置數據庫的用戶密碼及能夠訪問的數據庫-->
    <user name="root">
        <property name="password">wuzhenzhao</property>
        <property name="schemas">db_store,db_user</property>
        <!-- 表級 DML 權限設置 -->
        <!--         
        <privileges check="false">
            <schema name="db_user" dml="0110" >
                <table name="users" dml="1111"></table>  IUSD
                <table name="useraddres" dml="1110"></table>
            </schema>
        </privileges>-->
    </user>

</mycat:server>
    -->
</user>
</mycat:server>

   初略認識了這3個基本的配置文件後,咱們默認的配置文件修改爲本身修改過的來測試一下。重啓mycat,以下重啓成功

   而後用 Navicat 工具直連:這樣就完成了mycat 的搭建。

  能夠作個簡單的測試,如上圖鏈接到 mycat,在db_user裏面的user表插入5條數據:先來看看mycat上的存儲:

  再來看看兩個分片上面的數據:192.168.254.138

 

  192.168.254.139:

 

  能夠發現咱們的分片規則已經生效。其餘的表均可以分別的去測試一把。

  下面我會繼續學習 mycat 服務的相關配置。來深刻的學習一下。 

相關文章
相關標籤/搜索