【纯干货】Amoeba实现MySQL主从同步与读写分离

一、简介

  1. amoeba简介

Amoeba(变形虫)项目,该开源框架于2008年开始发布一款 Amoeba for Mysql软件。这个软件致力于MySQL的分布式数据库前端代理层,它主要在应用层访问MySQL的 时候充当SQL路由功能,专注于分布式数据库代理层(Database Proxy)开发。座落与 Client、DB Server(s)之间,对客户端透明。具有负载均衡、高可用性、SQL 过滤、读写分离、可路由相关的到目标数据库、可并发请求多台数据库合并结果。 通过Amoeba你能够完成多数据源的高可用、负载均衡、数据切片的功能,目前Amoeba已在很多企业的生产线上面使用

  1. Amoeba的优缺点

优点:

(1)降低费用,简单易用

(2)提高系统整体可用性

(3)易于扩展处理能力与系统规模

(4)可以直接实现读写分离及负载均衡效果,而不用修改代码

缺点:

(1)不支持事务与存储过程

(2)暂不支持分库分表,amoeba目前只做到分数据库实例

(3)不适合从amoeba导数据的场景或者对大数据量查询的query并不合适(比如一次请求返回10w以上甚至更多数据的场合)

3.什么是读写分离

读写分离(Read/Write Splitting),基本的原理是让主数据库处理事务性增、改、删操作(INSERT、UPDATE、DELETE),而从数据库处理SELECT查询操作。

数据库复制被用来把事务性操作导致的变更同步到集群中的从数据库。

二、实验拓扑构架

client linux6-1 IP:192.168.234.186

主MySQL centos7-1 IP:192.168.234.174

从MySQL01 centos7-2 IP:192.168.234.177

从MySQL02 centos7-5 IP:192.168.234.184

amoeba服务器 centos7-3 IP:192.168.234.181

【纯干货】Amoeba实现MySQL主从同步与读写分离_第1张图片

读写分离实验配置

源码编译安装MySQL5.5

  1. 编译MySQL5.5的依赖环境包

yum install gcc 、 gcc-c++ 、make、cmake
ncurses-devel、bison、libaio-devel -y

  1. 创建MySQL用户

groupadd -r mysql
useradd -g mysql -r -d /mydata/data mysql

  1. 源码编译MySQL

tar zxvf mysql-5.5.24.tar.gz -C /opt
cd /opt/mysql-5.5.24.tar.gz
cmake -DCMAKE_INSTALL_PREFIX=/usr/local/mysql
-DMYSQL_UNIX_ADDR=/home/mysql/mysql.sock
-DDEFAULT_CHARSET=utf8
-DDEFAULT_COLLATION=utf8_general_ci
-DWITH_EXTRA_CHARSETS=all
-DWITH_MYISAM_STORAGE_ENGINE=1
-DWITH_INNOBASE_STORAGE_ENGINE=1
-DWITH_MEMORY_STORAGE_ENGINE=1
-DWITH_READLINE=1
-DENABLED_LOCAL_INFILE=1
-DMYSQL_DATADIR=/home/mysql
-DMYSQL_USER=mysql
-DMYSQL_TCP_PORT=3306
make && make install

4.更改mysql的主目录为mysql组

chown -R mysql.mysql /usr/local/mysql

5.配置mysql环境变量

echo "export PATH=\$PATH:/usr/local/mysql/bin" > /etc/profile.d/mysql.sh

source /etc/profile.d/mysql.sh

6.复制MySQL启动脚本和服务配置文件分别到/etc/my.cnf和/etc/init.d/mysqld

cp support-files/my-medium.cnf /etc/my.cnf

cp support-files/mysql.server /etc/init.d/mysqld

7.给予相应的权限并且加入开机自启动项

chmod 755 /etc/init.d/mysqld
chkconfig --add /etc/init.d/mysqld
chkconfig mysqld --level 35 on

8.初始化数据库

/usr/local/mysql/scripts/mysql_install_db \
--user=mysql \
--ldata=/var/lib/mysql \
--basedir=/usr/local/mysql \
--datadir=/home/mysql

9.建立软链接

ln -s /var/lib/mysql/mysql.sock /home/mysql/mysql.sock

10.配置启动脚本

vim /etc/init.d/mysqld
basedir=/usr/local/mysql
datadir=/home/mysql

11.启动MySQL服务

systemctl start mysqld.service

12.设置MySQL用户的密码

mysqladmin -u root password 'abc123'

MySQL主服务器(master CentOS7-1)配置

[root@localhost ~]# vim /etc/my.cnf
...省略
log-bin=master-bin          //这里原来的mysql修改为master
log-slave-updates=true      //添加,表示从服务器更新二进制日志
...省略
server-id       = 11   

重新启动mysql服务,并且给予从服务器访问权限

[root@localhost ~]# systemctl restart mysqld.service    //重启MySQL服务
[root@localhost ~]# mysql -u root -p
Enter password:
mysql> GRANT REPLICATION SLAVE ON *.* TO 'myslave'@'192.168.234.%' IDENTIFIED BY '123456';        //给予从服务器访问权限
Query OK, 0 rows affected (0.00 sec)

mysql> flush privileges;    //刷新生成二进制文件
Query OK, 0 rows affected (0.00 sec)

mysql> show master status;     //查看pos偏移量  
+-------------------+----------+--------------+------------------+
| File              | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+-------------------+----------+--------------+------------------+
| master-bin.000001 |      477 |              |                  |
+-------------------+----------+--------------+------------------+
1 row in set (0.01 sec)

从服务器(slave CentOS7-2)配置

[root@localhost ~]# systemctl stop firewalld.service 

localhost ~]# setenforce 0
[root@localhost ~]# yum install ntpdate -y
[root@localhost ~]# systemctl start ntpd.service 
[root@localhost ~]# vim /etc/my.cnf
...省略
server-id       = 22   
relay-log=relay-log-bin    //从主服务器上同步日志文件记录到本地
relay-log-index=slave-relay-bin.index   //定义relay-log的位置和名称

重启MySQL服务,并且指定从服务器同步的对象服务器

[root@localhost ~]# mysql -u root -p
Enter password:
mysql> change master to master_host='192.168.234.174',master_user='myslave',master_password='123456',master_log_file='master-bin.000001',master_log_pos=477;    //设置同步的对象服务器及用户密码
Query OK, 0 rows affected (0.01 sec) 

mysql> start slave;    //开启主从同步
Query OK, 0 rows affected (0.01 sec)

mysql> show slave status\G;     //查看slave状态
*************************** 1. row ***************************
               Slave_IO_State: Reconnecting after a failed master event read
                  Master_Host: 192.168.234.174
                  Master_User: myslave
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: master-bin.000001
          Read_Master_Log_Pos: 564
               Relay_Log_File: localhost-relay-bin.001259
                Relay_Log_Pos: 254
        Relay_Master_Log_File: master-bin.000001
             Slave_IO_Running: Yes      //这里必须是yes
            Slave_SQL_Running: Yes     //这里必须是yes
              Replicate_Do_DB: 
          Replicate_Ignore_DB: 
           Replicate_Do_Table: 
       Replicate_Ignore_Table: 
      Replicate_Wild_Do_Table: 
  Replicate_Wild_Ignore_Table: 
                   Last_Errno: 0
                   Last_Error: 
                 Skip_Counter: 0
          Exec_Master_Log_Pos: 564
              Relay_Log_Space: 561
              Until_Condition: None
               Until_Log_File: 
                Until_Log_Pos: 0
           Master_SSL_Allowed: No
           Master_SSL_CA_File: 
           Master_SSL_CA_Path: 
              Master_SSL_Cert: 
            Master_SSL_Cipher: 
               Master_SSL_Key: 
        Seconds_Behind_Master: 1360
Master_SSL_Verify_Server_Cert: No
                Last_IO_Errno: 0
                Last_IO_Error: 
               Last_SQL_Errno: 0
               Last_SQL_Error: 
  Replicate_Ignore_Server_Ids: 
             Master_Server_Id: 11
1 row in set (0.00 sec)

从服务器2(slave2 CentOS7-5)和上面一样的配置

验证主从同步

在主服务器上添加一个数据库school,查看两个从服务器是否能够同步获取到school数据库

主服务器添加数据库school

mysql> show databases;  
+--------------------+
| Database           |
+--------------------+
| information_schema |
| #mysql50#.mozilla  |
| mysql              |
| performance_schema |
| test               |
+--------------------+
5 rows in set (0.01 sec)

mysql> create database school;     //添加school数据库
Query OK, 1 row affected (0.00 sec)

在两台从服务器上查看是否同步获取到school数据库

slave1 CentOS7-2

mysql> show databases;    //查看有哪些数据库
+--------------------+
| Database           |
+--------------------+
| information_schema |
| #mysql50#.mozilla  |
| mysql              |
| performance_schema |
| school             |      //这里就同步获取到school数据库
| test               |
+--------------------+
6 rows in set (0.01 sec)

slave2 CentOS7-5

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| #mysql50#.mozilla  |
| mysql              |
| performance_schema |
| school             |     //这里slave2也同步获取到一个school的数据库
| test               |
+--------------------+
6 rows in set (0.00 sec)

到这里如果两台从服务器都能获取到school数据库,就说明主从同步已经没问题了,那么接下来就是在amoeba服务器(CentOS7-3)上部署读写分离了

amoeba服务器(CentOS7-3)的部署设置

因为Amoeba是java程序开发的,所以Amoeba服务器上要先安装jdk环境

[root@localhost ~]# systemctl stop firewalld.service 
[root@localhost ~]# setenforce 0
[root@localhost mysql]# cp jdk-6u14-linux-x64.bin /usr/local/
[root@localhost mysql]# ./jdk-6u14-linux-x64.bin 
。。。省略
Do you agree to the above license terms? [yes or no]   
y    //前面一直按Enter直到这里输入y(yes),然后就等jdk环境安装完成

然后安装Amoeba服务

[root@localhost local]# mv jdk1.6.0_14/ jdk1.6
[root@localhost local]# vim /etc/profile    //添加amoeba的环境变量
   //G到行尾添加
export JAVA_HOME=/usr/local/jdk1.6
export CLASSPATH=$CLASSPATH:$JAVA_HOME/lib:$JAVA_HOME/jre/lib
export PATH=$JAVA_HOME/lib:$JAVA_HOME/jre/bin/:$PATH:$HOME/bin
export AMOEBA_HOME=/usr/local/amoeba
export PATH=$PATH:$AMOEBA_HOME/bin

[root@localhost local]# source /etc/profile    //刷星使环境变量立即生效
[root@localhost local]# mkdir /usr/local/amoeba    //创建一个amoeba的工作目录
[root@localhost local]# tar zxvf /abc/mysql/amoeba-mysql-binary-2.2.0.tar.gz -C /usr/local/amoeba/     //解压安装amoeba至工作目录

[root@localhost local]# chmod -R 755 amoeba/     //递归给予amoeba及子文件执行权限
[root@localhost local]# /usr/local/amoeba/bin/amoeba   //检查amoeba是否安装成功
amoeba start|stop     //看到这样的提示就说明amoeba服务安装完成

然后在三台MySQL服务器上添加权限开放给amoeba访问,用户使用test,密码是123123

grant all on . to test@'192.168.234.%' identified by '123123';

修改amoeba服务器的配置文件

[root@localhost amoeba]# vim conf/amoeba.xml 
。。。省略
                               //删除这里,表示开启
30                amoeba      //这里修改用户为之前设置的amoeba
 31                            //删除这里,表示开启
 32               123456  //添加密码为之前设置的密码123456
 33 
。。。省略
115                 master       //这里修改为默认使用master主服务器
116 
117 
118                 master           //允许主服务器写入
119                 slaves           //允许从服务器读取

[root@localhost amoeba]# vim conf/dbServers.xml       //修改数据库的配置文件
                           
 26                         test     //这里修改为test,即使用test用户去读取MySQL的数据
 27                               //删除

          //修改原来的server1为master
 45                 
 46                         
 47                         192.168.234.174       //这里改为主服务器的IP地址
 48                 
 49         
 50 
 51               //server2改为slave1
 52                 
 53                         
 54                         192.168.234.177      //slave1(即CentOS7-2)IP地址
 55                 
 56         
 57 #添加
 58             
 59                 
 60                         
 61                         192.168.234.184   //slave2(即CentOS7-5)IP地址
 62                 

 64               //服务器池名为slaves
 65                 
 66                         
 67                         1
 68 
 69                         
 70                         slave1,slave2     //服务器池内的两台服务器的名称
 71                 
 72         

开启amoeba服务,并且检查端口是否开启

[root@localhost amoeba]# /usr/local/amoeba/bin/amoeba start &   //开启amoeba服务器,并且放入后台执行
[2] 3996
[root@localhost amoeba]# log4j:WARN log4j config load completed from file:/usr/local/amoeba/conf/log4j.xml
2018-07-08 15:02:45,493 INFO  context.MysqlRuntimeContext - Amoeba for Mysql current versoin=5.1.45-mysql-amoeba-proxy-2.2.0
log4j:WARN ip access config load completed from file:/usr/local/amoeba/conf/access_list.conf
2018-07-08 15:02:46,450 INFO  net.ServerableConnectionManager - Amoeba for Mysql listening on 0.0.0.0/0.0.0.0:8066.     //这里可以看到开始监听端口8066
2018-07-08 15:02:46,476 INFO  net.ServerableConnectionManager - Amoeba Monitor Server listening on /127.0.0.1:38438.
^C
[root@localhost amoeba]# netstat -ntap | grep java      //查看java的程序
tcp6       0      0 :::8066                 :::*                    LISTEN      3996/java             //然后就可以看到有一个8066的端口已经开启了
tcp6       0      0 127.0.0.1:38438         :::*                    LISTEN      3996/java           
tcp6       0      0 192.168.234.181:37510   192.168.234.174:3306    ESTABLISHED 3996/java           
tcp6       0      0 192.168.234.181:38208   192.168.234.177:3306    ESTABLISHED 3996/java           
tcp6       0      0 192.168.234.181:47642   192.168.234.184:3306    ESTABLISHED 3996/java 

然后这里该部署的部署完成了,剩下的就是验证是否能够实现读写分离了

验证

这里先简单说明下验证过程:先在主服务器的school库中创建一个表zyc,然后两台从服务器关闭slave,在主服务器的zyc表中插入数据1,从服务器1的zyc表(注:创建表时同步并未关闭,所以从服务器会同步生成一个zyc表)中插入数据2,从服务器2的zyc表中插入数据3,然后使用客户机Linux6-1访问amoeba服务器,会看到显示的数据会在两个从服务器的2、3数据间切换,并不会显示主服务器写入的数据1;在客户机Linux6-1上写入数据,然后只有在主MySQL服务器能查询到,两个从服务器却查看不到;最后开启两个从服务器的同步,在客户机查看数据,就会看到数据显示为214、314间切换。

//主服务器添加表
mysql> create table zyc (id int(5),name varchar(10));
Query OK, 0 rows affected (0.03 sec)

mysql> show tables;
+------------------+
| Tables_in_school |
+------------------+
| zyc              |
+------------------+
1 row in set (0.00 sec)

//两个从服务器即会同步获取表信息
#从服务器1    CentOS7-2
mysql> use school;
Database changed
mysql> show tables;
+------------------+
| Tables_in_school |
+------------------+
| zyc              |
+------------------+
1 row in set (0.00 sec)

mysql> stop slave;
Query OK, 0 rows affected (0.00 sec)

#从服务器2    CentOS7-5
mysql> use school;
Database changed
mysql> show tables;
+------------------+
| Tables_in_school |
+------------------+
| zyc              |
+------------------+
1 row in set (0.01 sec)

mysql> stop slave;
Query OK, 0 rows affected (0.01 sec)

#主服务器插入数据1
mysql> insert into zyc values (1,'zhangsan');
Query OK, 1 row affected (0.01 sec)

mysql> select * from zyc;
+------+----------+
| id   | name     |
+------+----------+
|    1 | zhangsan |
+------+----------+
1 row in set (0.00 sec)

#从服务器1插入数据2
mysql> insert into zyc values (2,'lisi');
Query OK, 1 row affected (0.01 sec)

mysql> select * from zyc;
+------+------+
| id   | name |
+------+------+
|    2 | lisi |
+------+------+
1 row in set (0.01 sec)

#从服务器2插入数据3
mysql> insert into zyc values (3,'wangwu');
Query OK, 1 row affected (0.01 sec)

mysql> select * from zyc;
+------+--------+
| id   | name   |
+------+--------+
|    3 | wangwu |
+------+--------+
1 row in set (0.00 sec)

#此时使用客户机去访问amoeba服务器会看到数据只显示两个从服务器的
mysql> select * from zyc;
+------+--------+
| id   | name   |
+------+--------+
|    2 | lisi   |
+------+--------+
1 row in set (0.00 sec)

mysql> select * from zyc;
+------+--------+
| id   | name   |
+------+--------+
|    3 | wangwu |
+------+--------+
1 row in set (0.00 sec)

#然后打开两个从服务器的同步,在客户机插入数据4
mysql> insert into zyc values (4,'zhaoliu');
Query OK, 1 row affected (0.01 sec)

select * from zyc;
+------+----------+
| id   | name     |
+------+----------+
|    2 | lisi     |
+------+----------+
|    1 | zhangsan |
+------+----------+
|    4 | zhaoliu  |
+------+----------+

select * from zyc;
+------+----------+
| id   | name     |
+------+----------+
|    3 | wangwu   |
+------+----------+
|    1 | zhangsan |
+------+----------+
|    4 | zhaoliu  |
+------+----------+

最后的实验结论为:主服务器负责写入数据;从服务器负责读取数据;且两个从服务器会与主服务器进行同步,而两个从服务器间则不会同步

如果您实验到最后得到的也是这样的结果,那么恭喜您读写分离的实验您成功了!

这样就实现了MySQL的读写分离及主从同步