• Mycat搭建负载均衡,读写分离的Mysql集群


    Mycat搭建负载均衡,读写分离的Mysql集群

    准备环境

    1、mysql-5.7.24-linux-glibc2.12-x86_64.tar.gz

    2、Mycat-server-1.6.7.4-test-20191113141017-linux.tar.gz

    3、Centos7

    运行环境

    1个mycat,四个mysql实例(两个一主一从)。

    下载安装配置运行

    1、mysql安装配置运行

    参考我的另一篇随笔:从零开始:mysql基于Amoeba的集群搭建

    mysql需要创建3307,3308,3309,3310端口,其中,3307(主)和3308(从),3310(主)和3309(从)。

    [root@iz2zeaf5jdjve80rjlsjgnz support-files]# ps -aux | grep mysql
    root      5708  0.0  0.0 112712   964 pts/0    R+   23:25   0:00 grep --color=auto mysql
    root      6218  0.0  0.0 113320  1608 pts/0    S    22:43   0:00 /bin/sh /software/mysql/mysql3310/bin/mysqld_safe --datadir=/software/mysql/mysql3310/data --pid-file=/software/mysql/mysql3310/mysqld.pid
    mysql     7008  0.0 14.5 1796424 273876 pts/0  Sl   22:43   0:02 /software/mysql/mysql3310/bin/mysqld --basedir=/software/mysql/mysql3310 --datadir=/software/mysql/mysql3310/data --plugin-dir=/software/mysql/mysql3310/lib/plugin --user=mysql --log-error=iz2zeaf5jdjve80rjlsjgnz.err --open-files-limit=4161 --pid-file=/software/mysql/mysql3310/mysqld.pid --port=3310
    root      7434  0.0  0.0 113320  1624 pts/0    S    23:15   0:00 /bin/sh /software/mysql/mysql3307/bin/mysqld_safe --datadir=/software/mysql/mysql3307/data --pid-file=/software/mysql/mysql3307/mysqld.pid
    mysql     8214  0.1 15.3 1777900 288340 pts/0  Sl   23:15   0:00 /software/mysql/mysql3307/bin/mysqld --basedir=/software/mysql/mysql3307 --datadir=/software/mysql/mysql3307/data --plugin-dir=/software/mysql/mysql3307/lib/plugin --user=mysql --log-error=iz2zeaf5jdjve80rjlsjgnz.err --open-files-limit=4161 --pid-file=/software/mysql/mysql3307/mysqld.pid --port=3307
    root     27817  0.0  0.0 113324  1300 pts/3    S    22:06   0:00 /bin/sh /software/mysql/mysql3308/bin/mysqld_safe --datadir=/software/mysql/mysql3308/data --pid-file=/software/mysql/mysql3308/mysqld.pid
    mysql    28625  0.0  3.6 1795656 69588 pts/3   Sl   22:06   0:03 /software/mysql/mysql3308/bin/mysqld --basedir=/software/mysql/mysql3308 --datadir=/software/mysql/mysql3308/data --plugin-dir=/software/mysql/mysql3308/lib/plugin --user=mysql --log-error=iz2zeaf5jdjve80rjlsjgnz.err --open-files-limit=4161 --pid-file=/software/mysql/mysql3308/mysqld.pid --port=3308
    root     29106  0.0  0.0 113324  1640 pts/3    S    22:07   0:00 /bin/sh /software/mysql/mysql3309/bin/mysqld_safe --datadir=/software/mysql/mysql3309/data --pid-file=/software/mysql/mysql3309/mysqld.pid
    mysql    29916  0.0 15.1 1795660 284968 pts/3  Sl   22:07   0:03 /software/mysql/mysql3309/bin/mysqld --basedir=/software/mysql/mysql3309 --datadir=/software/mysql/mysql3309/data --plugin-dir=/software/mysql/mysql3309/lib/plugin --user=mysql --log-error=iz2zeaf5jdjve80rjlsjgnz.err --open-files-limit=4161 --pid-file=/software/mysql/mysql3309/mysqld.pid --port=3309
    

    2、mycat安装

    使用wget命令下载Mycat-server-1.6.7.4-test-20191113141017-linux.tar.gz

    mkdir /software/mycat
    cd /software/mycat
    wget http://dl.mycat.io/1.6.7.4/Mycat-server-1.6.7.4-test-20191113141017-linux.tar.gz
    

    使用tar解压

    tar zxvf Mycat-server-1.6.7.4-test-20191113141017-linux.tar.gz
    

    3、mycat配置

    mycat配置文件主要有schema.xml和server.xml。

    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="nonePasswordLogin">0</property> <!-- 0为需要密码登陆、1为不需要密码登陆 ,默认为0,设置为1则需要指定默认账户-->
    	<property name="useHandshakeV10">1</property>
    	<property name="useSqlStat">0</property>  <!-- 1为开启实时统计、0为关闭 -->
    	<property name="useGlobleTableCheck">0</property>  <!-- 1为开启全加班一致性检测、0为关闭 -->
    		<property name="sqlExecuteTimeout">300</property>  <!-- SQL 执行超时 单位:秒-->
    		<property name="sequnceHandlerType">5</property>
    		<!--<property name="sequnceHandlerPattern">(?:(s*nexts+values+fors*MYCATSEQ_(w+))(,|)|s)*)+</property>-->
    		<!--必须带有MYCATSEQ_或者 mycatseq_进入序列匹配流程 注意MYCATSEQ_有空格的情况-->
    		<property name="sequnceHandlerPattern">(?:(s*nexts+values+fors*MYCATSEQ_(w+))(,|)|s)*)+</property>
    	<property name="subqueryRelationshipCheck">false</property> <!-- 子查询中存在关联查询的情况下,检查关联字段中是否有分片字段 .默认 false -->
    	<property name="sequenceHanlderClass">io.mycat.route.sequence.handler.HttpIncrSequenceHandler</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 | type 2 NettyBufferPool -->
    		<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="dataNodeIdleCheckPeriod">300000</property> 5 * 60 * 1000L; //连接空闲检查
    			<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">0</property>
    
    		<!--
    			单位为m
    		-->
            <property name="memoryPageSize">64k</property>
    
    		<!--
    			单位为k
    		-->
    		<property name="spillsFileBufferSize">1k</property>
    
    		<property name="useStreamOutput">0</property>
    
    		<!--
    			单位为m
    		-->
    		<property name="systemReserveMemorySize">384m</property>
    
    
    		<!--是否采用zookeeper协调切换  -->
    		<property name="useZKSwitch">false</property>
    
    		<!-- XA Recovery Log日志路径 -->
    		<!--<property name="XARecoveryLogBaseDir">./</property>-->
    
    		<!-- XA Recovery Log日志名称 -->
    		<!--<property name="XARecoveryLogBaseName">tmlog</property>-->
    		<!--如果为 true的话 严格遵守隔离级别,不会在仅仅只有select语句的时候在事务中切换连接-->
    		<property name="strictTxIsolation">false</property>
    		
    		<property name="useZKSwitch">true</property>
    		
    	</system>
    	
    	<!-- 全局SQL防火墙设置 -->
    	<!--白名单可以使用通配符%或着*-->
    	<!--例如<host host="127.0.0.*" user="root"/>-->
    	<!--例如<host host="127.0.*" user="root"/>-->
    	<!--例如<host host="127.*" user="root"/>-->
    	<!--例如<host host="1*7.*" user="root"/>-->
    	<!--这些配置情况下对于127.0.0.1都能以root账户登录-->
    	<!--
    	<firewall>
    	   <whitehost>
    	      <host host="1*7.0.0.*" user="root"/>
    	   </whitehost>
           <blacklist check="false">
           </blacklist>
    	</firewall>
    	-->
    
        <!--使用navicat等软件登录mycat的账户和密码-->
    	<user name="mycat" defaultAccount="true">
    		<property name="password">mycat</property>
        <!--类似于mysql的数据库名-->
    		<property name="schemas">DB1</property>
    		<property name="defaultSchema">DB1</property>
    		<!--No MyCAT Database selected 错误前会尝试使用该schema作为schema,不设置则为null,报错 -->
    		
    		<!-- 表级 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="user">
    		<property name="password">user</property>
    		<property name="schemas">DB1</property>
    		<property name="readOnly">true</property>
    		<property name="defaultSchema">DB1</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="DB1" checkSQLschema="false" sqlMaxLimit="100">
    		<table name="ADMIN" dataNode="dn1,dn2,dn3" rule="auto-sharding-long" />
    	</schema>
    	<!-- <dataNode name="dn1$0-743" dataHost="localhost1" database="db$0-743"
    		/> -->
    	<dataNode name="dn1" dataHost="localhost1" database="DB1" />
    	<dataNode name="dn2" dataHost="localhost1" database="DB2" />
    	<dataNode name="dn3" dataHost="localhost1" database="DB3" />
    
    	<!--<dataNode name="dn4" dataHost="sequoiadb1" database="SAMPLE" />
    	 <dataNode name="jdbc_dn1" dataHost="jdbchost" database="db1" />
    	<dataNode	name="jdbc_dn2" dataHost="jdbchost" database="db2" />
    	<dataNode name="jdbc_dn3" 	dataHost="jdbchost" database="db3" /> -->
    	<dataHost name="localhost1" maxCon="1000" minCon="10" balance="3"
    			  writeType="0" dbType="mysql" dbDriver="native" switchType="1"  slaveThreshold="100">
    		<heartbeat>show slave status</heartbeat>
    		<!-- can have multi write hosts -->
    		<writeHost host="hostM1" url="localhost:3307" user="root"
    				   password="root">
    			<readHost host="hosts1" url="localhost:3308" user="root"
    					   password="root">
    			</readHost>
    		</writeHost>
    		<writeHost host="hostM2" url="localhost:3310" user="root" 
    					password="root">
    			<readHost host="hosts2" url="localhost:3309" user="root"
    					   password="root">
    			</readHost>
    		</writeHost>
    	</dataHost>
    
    	<!--
    		<dataHost name="sequoiadb1" maxCon="1000" minCon="1" balance="0" dbType="sequoiadb" dbDriver="jdbc">
    		<heartbeat> 		</heartbeat>
    		 <writeHost host="hostM1" url="sequoiadb://1426587161.dbaas.sequoialab.net:11920/SAMPLE" user="jifeng" 	password="jifeng"></writeHost>
    		 </dataHost>
    
    	  <dataHost name="oracle1" maxCon="1000" minCon="1" balance="0" writeType="0" 	dbType="oracle" dbDriver="jdbc"> <heartbeat>select 1 from dual</heartbeat>
    		<connectionInitSql>alter session set nls_date_format='yyyy-mm-dd hh24:mi:ss'</connectionInitSql>
    		<writeHost host="hostM1" url="jdbc:oracle:thin:@127.0.0.1:1521:nange" user="base" 	password="123456" > </writeHost> </dataHost>
    
    		<dataHost name="jdbchost" maxCon="1000" 	minCon="1" balance="0" writeType="0" dbType="mongodb" dbDriver="jdbc">
    		<heartbeat>select 	user()</heartbeat>
    		<writeHost host="hostM" url="mongodb://192.168.0.99/test" user="admin" password="123456" ></writeHost> </dataHost>
    
    		<dataHost name="sparksql" maxCon="1000" minCon="1" balance="0" dbType="spark" dbDriver="jdbc">
    		<heartbeat> </heartbeat>
    		 <writeHost host="hostM1" url="jdbc:hive2://feng01:10000" user="jifeng" 	password="jifeng"></writeHost> </dataHost> -->
    
    	<!-- <dataHost name="jdbchost" maxCon="1000" minCon="10" balance="0" dbType="mysql"
    		dbDriver="jdbc"> <heartbeat>select user()</heartbeat> <writeHost host="hostM1"
    		url="jdbc:mysql://localhost:3306" user="root" password="123456"> </writeHost>
    		</dataHost> -->
    </mycat:schema>
    

    首先schema标签中,设置的名字和server.xml设置的必须一致,它的子节点table表示设置哪个表,dataNode设置的是下面dataNode标签的name,表示将这个表分片到哪些database,dataHost属性设置的是下面dataHost的name。dataHost中writeHost设置的是3307(主服务器),readHost设置的是3308(从服务器)。第二个writeHost设置的和上面的相同,将writeHost设置的是3310(主服务器),readHost设置的是3308(从服务器)。

    其中dataHost的balance、writeType、switchType属性。

    balance, switchType, writeType
    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",所有读请求随机的分发到writeHost下的readhost执行,writeHost不负担读压力
    writeType表示写模式
    writeType="0",所有的操作发送到配置的第一个writehost
    writeType="1",随机发送到配置的所有writehost
    writeType="2",不执行写操作
    switchType指的是切换的模式,目前的取值也有4种:
    switchType=‘-1‘ 表示不自动切换
    switchType=‘1‘ 默认值,表示自动切换
    switchType=‘2‘ 基于MySQL主从同步的状态决定是否切换,心跳语句为show slave status,dnindex.properties里面的localhost1的值会发生改变。
    switchType=‘3‘基于MySQL galary cluster的切换机制(适合集群)(1.4.1),心跳语句为show status like ‘wsrep%‘。
    

    由于switchType设置的2,所以heartbeat的值是show slave status。

    4、mycat运行

    cd /software/mycat/mycat/bin
    ./mycat start
    

    使用navicat连接(默认是8066端口)

    QQ截图20191124235323

    5、测试心跳

    [root@iz2zeaf5jdjve80rjlsjgnz bin]# ./mysql -h127.0.0.1 -umycat -P9066 -pmycat
    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 98
    Server version: 5.7.24-log MySQL Community Server (GPL)
    
    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命令

    mysql> show @@heartbeat;
    +--------+-------+-----------+------+---------+-------+--------+---------+--------------+---------------------+-------+
    | NAME   | TYPE  | HOST      | PORT | RS_CODE | RETRY | STATUS | TIMEOUT | EXECUTE_TIME | LAST_ACTIVE_TIME    | STOP  |
    +--------+-------+-----------+------+---------+-------+--------+---------+--------------+---------------------+-------+
    | hostM1 | mysql | localhost | 3307 |       1 |     0 | idle   |   30000 | 65,22,22     | 2019-11-24 23:57:12 | false |
    | hostM2 | mysql | localhost | 3310 |       1 |     0 | idle   |   30000 | 99,33,33     | 2019-11-24 23:57:12 | false |
    | hosts1 | mysql | localhost | 3308 |       1 |     0 | idle   |   30000 | 81,33,33     | 2019-11-24 23:57:12 | false |
    | hosts2 | mysql | localhost | 3309 |       1 |     0 | idle   |   30000 | 82,30,30     | 2019-11-24 23:57:12 | false |
    +--------+-------+-----------+------+---------+-------+--------+---------+--------------+---------------------+-------+
    4 rows in set (0.00 sec)
    
    mysql> 
    

    rs_code:表示心跳状态

    • 0:INIT_STATUS 表示初始化状态
    • 1:OK_STATUS 表示正常状态
    • -1:ERROR_STATUS 表示连接出错
    • -2:TIMEOUT_STATUS 表示连接超时

    若节点发生故障,会连续进行默认5个周期的检测,心跳连续失败后会变成 -1 。


    其中RS_CODE都是1,表示所有mysql实例状态正常。

    6、测试分片

    mysql> create table admin (id bigint not null primary key,user_id varchar(100),traveldate DATE, fee decimal,days int);
    Query OK, 0 rows affected (0.22 sec)
    mysql> insert into ADMIN(id,user_id,traveldate,fee,days)  values(1,@@hostname,20160101,100,10);
    Query OK, 1 row affected (0.28 sec)
    mysql> insert into ADMIN(id,user_id,traveldate,fee,days)  values(5000001,@@hostname,20160101,100,10);
    Query OK, 1 row affected (0.18 sec)
    mysql> insert into ADMIN(id,user_id,traveldate,fee,days)  values(10000001,@@hostname,20160101,100,10);
    Query OK, 1 row affected (0.19 sec)
    

    因为在schema.xml中配置了table的rule属性为auto-sharding-long。

    这个属性值在rule.xml的内容为

    <tableRule name="auto-sharding-long">
    		<rule>
    			<columns>id</columns>
    			<algorithm>rang-long</algorithm>
    		</rule>
    	</tableRule>
    <function name="rang-long"
    			  class="io.mycat.route.function.AutoPartitionByLong">
    		<property name="mapFile">autopartition-long.txt</property>
    	</function>
    
    

    对应的文件是autopartition-long.txt,打开这个文件

    # range start-end ,data node index
    # K=1000,M=10000.
    0-500M=0
    500M-1000M=1
    1000M-1500M=2
    

    表示id在0-500M范围内,500M-1000M范围内,1000M-1500M范围内,分别在不同的数据库。

    QQ截图20191125001252

    7、测试读写分离

    查询ADMIN表。

    mysql> select * from ADMIN;
    +----------+-------------------------+------------+-----+------+
    | ID       | USER_ID                 | TRAVELDATE | FEE | DAYS |
    +----------+-------------------------+------------+-----+------+
    |        1 | iz2zeaf5jdjve80rjlsjgnz | 2016-01-01 | 100 |   10 |
    |  5000001 | iz2zeaf5jdjve80rjlsjgnz | 2016-01-01 | 100 |   10 |
    | 10000001 | iz2zeaf5jdjve80rjlsjgnz | 2016-01-01 | 100 |   10 |
    +----------+-------------------------+------------+-----+------+
    3 rows in set (0.48 sec)
    

    关闭3310主服务器。

    kill -9 6218 7008
    

    此时心跳测试出现-1。

    dnindex.properties的localhost1发生改变,说明已经切换到另一个主服务器(关闭之前是0)。

    #update
    #Mon Nov 25 23:58:11 CST 2019
    localhost1=1
    
    
    mysql> show @@heartbeat;
    +--------+-------+-----------+------+---------+-------+--------+---------+--------------+---------------------+-------+
    | NAME   | TYPE  | HOST      | PORT | RS_CODE | RETRY | STATUS | TIMEOUT | EXECUTE_TIME | LAST_ACTIVE_TIME    | STOP  |
    +--------+-------+-----------+------+---------+-------+--------+---------+--------------+---------------------+-------+
    | hostM1 | mysql | localhost | 3307 |       1 |     0 | idle   |   30000 | 2,2,3        | 2019-11-25 00:23:16 | false |
    | hostM2 | mysql | localhost | 3310 |      -1 |     2 | idle   |   30000 | 17,3,3       | 2019-11-25 00:23:16 | false |
    | hosts1 | mysql | localhost | 3308 |       1 |     0 | idle   |   30000 | 2,2,2        | 2019-11-25 00:23:16 | false |
    | hosts2 | mysql | localhost | 3309 |       1 |     0 | idle   |   30000 | 2,3,3        | 2019-11-25 00:23:16 | false |
    +--------+-------+-----------+------+---------+-------+--------+---------+--------------+---------------------+-------+
    4 rows in set (0.16 sec)
    

    再次查询ADMIN表。

    mysql> select * from ADMIN;
    1105 - Table 'DB1.ADMIN' doesn't exist
    

    结论:

    1、设置了两个及以上的writeHost后,如果默认的writeHost出现宕机,那么会切换到第二个writeHost,相应的,dnindex.properties的localhost1值会改变,show @@heartbeat;命令查询到的HOST对应的RS_CODE会变成-1。

    2、自动切换writeHost之后,第一个writeHost的值不会同步过去,所以再次查询ADMIN表会出现Table 'DB1.ADMIN' doesn't exist。

    解决办法:

    有四个mysql实例

    mysql3307
    mysql3308
    mysql3309
    mysql3310
    

    在schema.xml中配置:

    <writeHost Host="mysql3307">
        <readHost Host="mysql3308"></readHost>
    </writeHost>
    <writeHost Host="mysql3308">
        <readHost Host="mysql3309"></readHost>
    </writeHost>
    <writeHost Host="mysql3309">
        <readHost Host="mysql3310"></readHost>
    </writeHost>
    

    在3307宕机后,3308复制的3307,所以3308的数据和3307是一样的,切换到3308后,3309和3308的数据是同步的,以此类推,可以解决主宕机后数据不同步的问题。

  • 相关阅读:
    k8s-pv
    k8s ---kubectl 部署时,pull image 报错,拉取不到镜像
    【knowledgebase】不要在一个很大的RDD上调用collect
    【knowledgebase】如何知道partition数
    Spark SQL External Data Sources JDBC官方实现写测试
    Spark SQL External Data Sources JDBC官方实现读测试
    Sqoop2入门之导入关系型数据库数据到HDFS上(sqoop2-1.99.4版本)
    Spark Streaming、Kafka结合Spark JDBC External DataSouces处理案例
    Spark Streaming、HDFS结合Spark JDBC External DataSouces处理案例
    Spark SQL External Data Sources JDBC简易实现
  • 原文地址:https://www.cnblogs.com/lxxxxxxy/p/11932868.html
Copyright © 2020-2023  润新知