不积跬步,无以至千里;不积小流,无以成江海。

Mycat主从同步、读写分离、分库分表(3)- 简单配置Mycat,实现读写分离

数据库 康康 2496℃ 0评论

MyCat是基于阿里巴巴的开源产品CoBar演变而来,以代替昂贵的oracle的MySQL集群的中间件。关于MyCat的介绍在此不多赘述(详细介绍 : 查看Mycat的详细介绍)。

基于上篇的实验,我们当前的环境为:

角色      服务端口      用户        密码

master  3306       root    root@3306

slave     3307       root    root@3307

slave     3308       root    root@3308

已经实现master中发生写操作会自动同步到两个slave服务,下面将在此环境下配置mycat实现读写分离,将3306作为写库,3307、3308作为读操作用的库。

一、下载、配置MyCat

1.官方网站下载已编译好的安装包

cd /software/
wget http://dl.mycat.io/1.6-RELEASE/Mycat-server-1.6-RELEASE-20161028204710-linux.tar.gz
tar -zxvf  Mycat-server-1.6-RELEASE-20161028204710-linux.tar.gz

2.配置java环境

mycat基于jdk1.7,最低要用jdk1.7的版本,当前测试用的jdk1.8

[root@iZ2ze1np3s3kfsddhxqr0gZ software]# java -version 
java version "1.8.0_141"
Java(TM) SE Runtime Environment (build 1.8.0_141-b15)
Java HotSpot(TM) 64-Bit Server VM (build 25.141-b15, mixed mode)

省略配置过程...

3.配置mycat

mycat配置文件下都在conf目录下,本测试需要配置两个文件

server.xml  : 保存了所有mycat需要的系统配置信息。其在代码内直接的映射类为SystemConfig类。现在就对这个文件中的配置。

Schema.xml :作为MyCat中重要的配置文件之一,管理着MyCat的逻辑库、表、分片规则、DataNode以及DataSource等。

配置server.xml:

<user name="root">
<property name="password">123456</property>
<property name="schemas">test_db</property>

</user>

<user name="user">
<property name="password">user</property>
<property name="schemas">test_db</property>
<property name="readOnly">true</property>
</user>

配置两个用户 ,root 和user (只读权限),这里的用户与数据库无关,作为mycat登录时用,test_db为逻辑数据库,与schema.xml中对应

配置schema.xml:

<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">

<table name="goods" primaryKey="ID" type="global" dataNode="dn1" />

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

<!--只有一个dataNode-->

<dataNode name="dn1" dataHost="localhost1" database="test_db" />

<dataHost name="localhost1" maxCon="1000" minCon="10" balance="1"  writeType="0" dbType="mysql" dbDriver="native" switchType="1" slav       eThreshold="100">
<heartbeat>select user()</heartbeat>
<!--方案一 ,M1写 S1 S2读 -->
<writeHost host="hostM1" url="127.0.0.1:3306" user="root"  password="root@3306">
<readHost host="hostS1" url="127.0.0.1:3307" user="root" password="root@3307" />
<readHost host="hostS2" url="127.0.0.1:3308" user="root" password="root@3308" />
</writeHost>

</mycat:schema>

这里要配置 balance=“1” ,默认为0  

table标签属性说明:

Table 标签定义了MyCat中的逻辑表,所有需要拆分的表都需要在这个标签中定义。name定义逻辑表的表名,这个名字就如同我在数据库中执行create table命令指定的名字一样,同个schema标签中定义的名字必须唯一。我们定义一个 goods 表来测试读写分离。

dataHost标签属性说明:

  • name属性
    唯一标识dataHost标签,供上层的标签使用。
  • maxCon属性
    指定每个读写实例连接池的最大连接。也就是说,标签内嵌套的writeHost、readHost标签都会使用这个属性的值来实例化出连接池的最大连接数。
  • minCon属性
    指定每个读写实例连接池的最小连接,初始化连接池的大小。
  • balance属性
    负载均衡类型,目前的取值有3种:
    1. balance=“0”, 所有读操作都发送到当前可用的writeHost上。
    2. balance=“1”,所有读操作都随机的发送到readHost。
    3. balance=“2”,所有读操作都随机的在writeHost、readhost上分发。
  • writeType属性
    负载均衡类型,目前的取值有3种:
    1. writeType=“0”, 所有写操作都发送到可用的writeHost上。
    2. writeType=“1”,所有写操作都随机的发送到readHost。
    3. writeType=“2”,所有写操作都随机的在writeHost、readhost分上发。
  • dbType属性
    指定后端连接的数据库类型,目前支持二进制的mysql协议,还有其他使用JDBC连接的数据库。例如:mongodb、oracle、spark等。
  • dbDriver属性
    指定连接后端数据库使用的Driver,目前可选的值有native和JDBC。使用native的话,因为这个值执行的是二进制的mysql协议,所以可以使用mysql和marib。其他类型的数据库则需要使用JDBC驱动来支持。如果使用JDBC的话需要将符合JDBC 4标准的驱动JAR包放到MYCAT\lib目录下,并检查驱动JAR包中包括如下目录结构的文件:META-INF\services\java.sql.Driver。在这个文件内写上具体的Driver类名,例如:com.mysql.jdbc.Driver。

4.创建测试表goods

登录3306主库,在test_db中创建测试表goods:

mysql>use test_db; 
mysql>create table goods (id int primary key , gname varchar(50), gprice float , gdesc varchar(200) ) ;

二、启动MyCat,测试读写分离是否配置成功

操作命令:./bin/mycat start/stop/restart

日志:logs/mycat.log 和 logs/wrapper.log

1.启动mycat

./bin/mycat start

查看wrapper.log日志,如果出现
Error: Exception thrown by the agent : java.net.MalformedU
RLException: Local host name unknown: java.net.UnknownHostException: iZ2ze1np3s3kfsddhxqr0gZ: iZ2ze1
np3s3kfsddhxqr0gZ: Name or service not known 之类的错误
可能是由于hosts文件中 iZ2ze1np3s3kfsddhxqr0gZ 主机名没有映射到127.0.0.1, 加一条记录就好
vim /etc/hosts

127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
127.0.0.1   iZ2ze1np3s3kfsddhxqr0gZ

重新启动mycat并检查日志

查看服务成功启动:

ps -ef | grep mycat

查看服务端口,mycat默认监听8066和9066:

netstat -ant | grep 8066 / 9066

2.成功启动后,登录mycat,向goods表插入测试数据

当前操作登录到mycat(8066):

#这里的用户密码是在 mycat中 server.xml配置的 数据库 为逻辑数据库
 mysql -uroot -p123456 -h127.0.0.1 -P8066 test_db

#查看表,我们只配置了一个goods表,所以只能看到一个
mysql> show tables;
+-------------------+
| Tables in test_db |
+-------------------+
| goods             |
+-------------------+
1 row in set (0.00 sec)

#插入测试数据,为了区别我们的数据是从哪里来的,这里使用了@@PORT全局变量获取了mysql服务端端口,在select的时候发现端口为3307
insert into goods (id, gname , gprice , gdesc )  values ( 100,'果粒橙',3.5,@@PORT ); 
Query OK, 1 row affected, 1 warning (0.02 sec)

mysql> select * from goods;
+-----+-----------+--------+-------+
| id  | gname     | gprice | gdesc |
+-----+-----------+--------+-------+
| 100 | 果粒橙    |    3.5 | 3307  |
+-----+-----------+--------+-------+
1 row in set (0.00 sec)
mysql>

猜想:由于我们mysql已经做过主从同步,所以执行insert之后 3306和3307中会同步这条记录,但是由于端口不同所以gdesc中会有各自的端口

论证:

接下来登录到3306,看看goods表的内容

当前操作登录到3306:

Database changed
mysql> select * from goods;
+-----+-----------+--------+-------+
| id  | gname     | gprice | gdesc |
+-----+-----------+--------+-------+
| 100 | 果粒橙    |    3.5 | 3306  |
+-----+-----------+--------+-------+
1 row in set (0.00 sec)

再登录到3307查看goods表中的数据

当前操作登录到3307:

mysql> select * from goods;
+-----+-----------+--------+-------+
| id  | gname     | gprice | gdesc |
+-----+-----------+--------+-------+
| 100 | 果粒橙    |    3.5 | 3307  |
+-----+-----------+--------+-------+
1 row in set (0.00 sec)

再登录到3308查看goods表中的数据

当前操作登录到3308:

mysql> select * from goods;
+-----+-----------+--------+-------+
| id  | gname     | gprice | gdesc |
+-----+-----------+--------+-------+
| 100 | 果粒橙    |    3.5 | 3308  |
+-----+-----------+--------+-------+
1 row in set (0.00 sec)

毫无疑问,刚刚我们在mycat控制台查询到的数据,来源为3307中的数据!

接下来我们停掉3307服务,再查询goods表

[root@iZ2ze1np3s3kfsddhxqr0gZ software]# sh mysqlStop.sh 3307

回到mycat(8066)控制台,查询goods表:

mysql> select * from goods;
+-----+-----------+--------+-------+
| id  | gname     | gprice | gdesc |
+-----+-----------+--------+-------+
| 100 | 果粒橙    |    3.5 | 3308  |
+-----+-----------+--------+-------+
1 row in set (0.00 sec)

如图所示:

结论:由于我们在writeHost 配置了两个readHost ,mycat在查询的时候优先查询hostS1(3307),当hostS1不可用时,自动切换到hsotS2(3308)。该方案缺点,当写库hostM1挂掉,hostS1、hostS2均不能正常服务。

另一种配置方式--- 不使用mycay托管主从切换

<dataHost name="localhost1" maxCon="1000" minCon="10" balance="1"  writeType="0" dbType="mysql" dbDriver="native" switchType="1" slav       eThreshold="100">

<heartbeat>select user()</heartbeat>

<!-- 配置一个用于写的库 -->

<writeHost host="hostM1" url="127.0.0.1:3306" user="root" password="root@3306">

<!-- 可以配置多个用于读的库 -->

<writeHost host="hostS1" url="127.0.0.1:3307" user="root" password="root@3307" />

<writeHost host="hostS2" url="127.0.0.1:3308" user="root" password="root@3308" />
</writeHost>

这种方式也是优先将M1作为写,S1、S2作为随机读,当M1挂掉 S1、S2能继续使用,且S1变为写库,S2变为读库,当M1恢复后,M1变为读库,S1仍然为写库不变,由于此时并没有使用mycat托管主从切换,所以当M1挂掉,S1作为写库新增的数据不会同步到S2,导致读取S2库里的数据可能为旧数据!

切换主机的记录在 conf/dnindex.properties ,查看该文件:

#update
#Tue Aug 15 14:27:34 CST 2017
localhost1=1

此时应当重新配置主从同步服务,将S1变为主,M1变为从加入到从库后!或者将M1同步到最新,mycat中执行切换命令switch @@datasource localhost1:0

另一种配置方式--使用mycat托管主从切换

<dataHost name="localhost1" maxCon="1000" minCon="10" balance="2"  writeType="0" dbType="mysql" dbDriver="native" switchType="2" slav       eThreshold="100">

<heartbeat>show slave status</heartbeat>

<!-- 配置一个用于写的库 -->

<writeHost host="hostM1" url="127.0.0.1:3306" user="root" password="root@3306">

<!-- 可以配置多个用于读的库 -->

<writeHost host="hostS1" url="127.0.0.1:3307" user="root" password="root@3307" />

<writeHost host="hostS2" url="127.0.0.1:3308" user="root" password="root@3308" />
</writeHost>

当配置了Mycat托管主从,且 balance="2" 所有读操作在三个主机随机进行,写操作在M1进行。当M1挂掉,自动切换S1为主库

附录

其他实验

转载请注明:左手代码右手诗 » Mycat主从同步、读写分离、分库分表(3)- 简单配置Mycat,实现读写分离

喜欢 (2)or分享 (0)
发表我的评论
取消评论

 

表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址