mysql主从同步+mycat读写分离+.NET程序连接mycat代理

背景

最近新项目需要用到mysql数据库,并且由于数据量大的原因,故打算采用1主1从(主数据库负责增、删、改操作;从数据库负责查操作)的数据库架构,在实现主从之后还要实现读写分离的代理,在网上搜寻了很久,自己也了解了一些资料,目前有三种代理组件:1、mysql_proxy   2、amoeba   3、mycat   我采用了第3种,选择mycat的原因下面会提到。

部署环境

我在我虚拟机下面装了三台Centos7_x64系统:

1、192.168.8.47 主mysql服务器

2、192.168.8.45 从mysql服务器

3、192.168.8.52 mycat读写分离代理服务器

实现步骤

1、主mysql服务器上安装mysql数据库(从mysql服务器安装一样,为了兼容主从同步故从mysql版本和主保持一致)

1、下载mysql源安装包,地址:wget http://dev.mysql.com/get/mysql57-community-release-el7-8.noarch.rpm

2、安装mysql源 :yum localinstall mysql57-community-release-el7-8.noarch.rpm

3、检查mysql源是否安装成功:yum repolist enabled | grep "mysql.*-community.*"

mysql主从同步+mycat读写分离+.NET程序连接mycat代理

看到这个,就说明安装成功了。

4、安装mysql:yum install mysql-community-server

5、启动mysql服务:systemctl start mysqld

6、设置开启mysql自启动:systemctl enable mysqld 和systemctl daemon-reload都执行

7、安装完mysql之后在/var/log/mysqld.log文件中给root生成一个默认密码,通过下面的方式可以找到root默认密码,然后登录mysql进行修改

   grep 'temporary password' /var/log/mysqld.log

mysql主从同步+mycat读写分离+.NET程序连接mycat代理

其中,y.0w(csyT,Sx就是默认密码。

8、登录mysql以及修改默认密码

mysql -uroot -p

    ALTER USER 'root'@'localhost' IDENTIFIED BY 'newpwd';
注意:mysql5.7默认安装了密码安全检查插件(validate_password),默认密码检查策略要求密码必须包含:大小写字母、数字和特殊符号,并且长度不能少于8位。否则会提示ERROR 1819 (HY000): Your password does not satisfy the current policy requirements错误 2、配置主从同步
在此之前,先啰嗦说下主从同步的原因,在脑海中形成个初步的印象

master服务器将数据的改变记录二进制binlog日志,当master上的数据发生改变时,则将其改变写入二进制日志中;salve服务器会在一定时间间隔内对master二进制日志进行探测其是否发生改变,如果发生改变,则开始一个I/OThread请求master二进制事件,同时主节点为每个I/O线程启动一个dump线程,用于向其发送二进制事件,并保存至从节点本地的中继日志中,从节点将启动SQL线程从中继日志中读取二进制日志,在本地重放,使得其数据和主节点的保持一致,最后I/OThread和SQLThread将进入睡眠状态,等待下一次被唤醒。
注意几点:
     1--master将操作语句记录到binlog日志中,然后授予slave远程连接的权限(master一定要开启binlog二进制日志功能;通常为了数据安全考虑,slave也开启binlog功能)。
     2--slave开启两个线程:IO线程和SQL线程。其中:IO线程负责读取master的binlog内容到中继日志relay log里;SQL线程负责从relay log日志里读出binlog内容,并更新到slave的数据库里,这样就能保证slave数据和master数据保持一致了。
     3--Mysql复制至少需要两个Mysql的服务,当然Mysql服务可以分布在不同的服务器上,也可以在一台服务器上启动多个服务。
     4--Mysql复制最好确保master和slave服务器上的Mysql版本相同(如果不能满足版本一致,那么要保证master主节点的版本低于slave从节点的版本)
     5--master和slave两节点间时间需同步

Mysql复制的流程图如下:

mysql主从同步+mycat读写分离+.NET程序连接mycat代理

如上图所示:
     Mysql复制过程的第一部分就是master记录二进制日志。在每个事务更新数据完成之前,master在二日志记录这些改变。MySQL将事务串行的写入二进制日志,即使事务中的语句都是交叉执行的。在事件写入二进制日志完成后,master通知存储引擎提交事务。
    第二部分就是slave将master的binary log拷贝到它自己的中继日志。首先,slave开始一个工作线程——I/O线程。I/O线程在master上打开一个普通的连接,然后开始binlog dump process。Binlog dump process从master的二进制日志中读取事件,如果已经跟上master,它会睡眠并等待master产生新的事件。I/O线程将这些事件写入中继日志。
    SQL slave thread(SQL从线程)处理该过程的最后一步。SQL线程从中继日志读取事件,并重放其中的事件而更新slave的数据,使其与master中的数据一致。只要该线程与I/O线程保持一致,中继日志通常会位于OS的缓存中,所以中继日志的开销很小。
   此外,在master中也有一个工作线程:和其它MySQL的连接一样,slave在master中打开一个连接也会使得master开始一个线程。复制过程有一个很重要的限制——复制在slave上是串行化的,也就是说master上的并行更新操作不能在slave上并行操作。

4)Mysql复制的模式
    1--主从复制:主库授权从库远程连接,读取binlog日志并更新到本地数据库的过程;主库写数据后,从库会自动同步过来(从库跟着主库变);
    2--主主复制:主从相互授权连接,读取对方binlog日志并更新到本地数据库的过程;只要对方数据改变,自己就跟着改变;

5)Mysql主从复制的优点
    1--在从服务器可以执行查询工作(即我们常说的读功能),降低主服务器压力;(主库写,从库读,降压)
    2--在从主服务器进行备份,避免备份期间影响主服务器服务;(确保数据安全)
    3--当主服务器出现问题时,可以切换到从服务器。(提升性能)

6)Mysql主从复制工作流程细节
    1)MySQL支持单向、异步复制,复制过程中一个服务器充当主服务器,而一个或多个其它服务器充当从服务器。MySQL复制基于主服务器在二进制日志中跟踪所有对数据库的更改(更新、删除等等)。因此,要进行复制,必须在主服务器上启用二进制日志。每个从服务器从主服务器接收主服务器上已经记录到其二进制日志的保存的更新。当一个从服务器连接主服务器时,它通知主服务器定位到从服务器在日志中读取的最后一次成功更新的位置。从服务器接收从那时起发生的任何更新,并在本机上执行相同的更新。然后*并等待主服务器通知新的更新。从服务器执行备份不会干扰主服务器,在备份过程中主服务器可以继续处理更新。
    2)MySQL使用3个线程来执行复制功能,其中两个线程(Sql线程和IO线程)在从服务器,另外一个线程(IO线程)在主服务器。
当发出START SLAVE时,从服务器创建一个I/O线程,以连接主服务器并让它发送记录在其二进制日志中的语句。主服务器创建一个线程将二进制日志中的内容发送到从服务器。该线程可以即为主服务器上SHOW PROCESSLIST的输出中的Binlog Dump线程。从服务器I/O线程读取主服务器Binlog Dump线程发送的内容并将该数据拷贝到从服务器数据目录中的本地文件中,即中继日志。第3个线程是SQL线程,由从服务器创建,用于读取中继日志并执行日志中包含的更新。在从服务器上,读取和执行更新语句被分成两个独立的任务。当从服务器启动时,其I/O线程可以很快地从主服务器索取所有二进制日志内容,即使SQL线程执行更新的远远滞后。

1、配置主mysql数据库配置文件:vim /usr/local/mysql/my.cnf

..............

  server-id=1          #数据库唯一ID,主从的标识号绝对不能重复。
  log-bin=mysql-bin      #开启bin-log,并指定文件目录和文件名前缀
  binlog-do-db=test_z   #需要同步的数据库。如果是多个同步库,就以此格式另写几行即可。如果不指明对某个具体库同步,就去掉此行,表示同步所有库(除了ignore忽略的库)。
  #binlog-ignore-db=mysql  #不同步mysql系统数据库。如果是多个不同步库,就以此格式另写几行;也可以在一行,中间逗号隔开。
  sync_binlog = 1        #确保binlog日志写入后与硬盘同步
  binlog_checksum = none  #跳过现有的采用checksum的事件,mysql5.6.5以后的版本中binlog_checksum=crc32,而低版本都是binlog_checksum=none
  binlog_format = mixed   #bin-log日志文件格式,设置为MIXED可以防止主键重复。
     温馨提示:在主服务器上最重要的二进制日志设置是sync_binlog,这使得mysql在每次提交事务的时候把二进制日志的内容同步到磁盘上,即使服务器崩溃也会把事件写入日志中。
sync_binlog这个参数是对于MySQL系统来说是至关重要的,他不仅影响到Binlog对MySQL所带来的性能损耗,而且还影响到MySQL中数据的完整性。对于"sync_binlog"参数的各种设置的说明如下:
sync_binlog=0,当事务提交之后,MySQL不做fsync之类的磁盘同步指令刷新binlog_cache中的信息到磁盘,而让Filesystem自行决定什么时候来做同步,或者cache满了之后才同步到磁盘。
sync_binlog=n,当每进行n次事务提交之后,MySQL将进行一次fsync之类的磁盘同步指令来将binlog_cache中的数据强制写入磁盘。
     
在MySQL中系统默认的设置是sync_binlog=0,也就是不做任何强制性的磁盘刷新指令,这时候的性能是最好的,但是风险也是最大的。因为一旦系统Crash,在binlog_cache中的所有binlog信息都会被丢失。而当设置为“1”的时候,是最安全但是性能损耗最大的设置。因为当设置为1的时候,即使系统Crash,也最多丢失binlog_cache中未完成的一个事务,对实际数据没有任何实质性影响。
     
从以往经验和相关测试来看,对于高并发事务的系统来说,“sync_binlog”设置为0和设置为1的系统写入性能差距可能高达5倍甚至更多。
    2、配置文件配置完之后,登录mysql数据库设置数据同步权限
        mysql> grant replication slave,replication client on *.* to root@'192.168.8.45' identified by "Zxq311915~..";
        mysql>flush privileges; 
    3、查看master服务器状态
        mysql> show master status;(注意File与Position项,从服务器需要这两项参数)

   +------------------+----------+--------------+------------------+-------------------+

   | File         | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
   +------------------+----------+--------------+------------------+-------------------+
   | mysql-bin.000007 |    120 | test_z     |            |
   +------------------+----------+--------------+------------------+-------------------+
   1 row in set (0.00 sec)
 
2、从mysql数据库配置
     1、配置从mysql配置文件
     # vim /usr/local/mysql/my.cnf
     ...........
  server-id=2   #设置从服务器id,必须与主服务器不同
  log-bin=mysql-bin   #启动MySQ二进制日志系统
  replicate-do-db=test_z  #需要同步的数据库名。如果不指明同步哪些库,就去掉这行,表示所有库的同步(除了ignore忽略的库)。
  #replicate-ignore-db=mysql  #不同步mysql系统数据库
  slave-skip-errors = all   #跳过所有的错误错误,继续执行复制操作

  2、配置主从同步指令

  mysql>stop slave;   #执行同步前,要先关闭slave

  mysql>change  master to master_host='192.168.8.47',master_user='root',master_password='Zxq311915~..',master_log_file='mysql-bin.000007',master_log_pos=120;

mysql>start slave;          #开启同步

mysql>show slave status \G

  *************************** 1. row ***************************
      Slave_IO_State: Waiting for master to send event
         Master_Host: 192.168.8.47
         Master_User: slave
         Master_Port: 3306
         Connect_Retry: 60
       Master_Log_File: mysql-bin.000007
       Read_Master_Log_Pos: 120
       Relay_Log_File: mysql-relay-bin.000002
       Relay_Log_Pos: 279
       Relay_Master_Log_File: mysql-bin.000007
       Slave_IO_Running: Yes
       Slave_SQL_Running: Yes
       Replicate_Do_DB: test_z
       Replicate_Ignore_DB:
       .............
       Seconds_Behind_Master: 0
    
  如上,当IO和SQL线程的状态均为Yes,则表示主从已实现同步了!
     注意:此处默认主从mysql都已经存在test_z数据库,主从同步是基于主从配置完之后开始,并且mysql主从部署之后可能会出现主从同步延迟的问题,在此文中不作讲解,可自行搜索资料。
2、mycat读写分离组件安装、配置
      上文提到,目前有mysql-proxy、amoeba、mycat三种读写分离的组件,为什么选择mycat,因为mysql-proxy需要lua脚本支持,对于不知道lua为何物的我来说编写难道大,而amoeba项目我从网上了解到大概从13年后就没有更新了,而mycat现在有大量开发人员在维护完善这个项目,而且是国产的,必须支持下!!!
       1、下载mycat
       wget https://github.com/MyCATApache/Mycat-download/raw/master/1.4-RELEASE/Mycat-server-1.4-release-20151019230038-linux.tar.gz
       2、解压
       tar -xvf  Mycat-server-1.4-release-20151019230038-linux.tar.gz
       3、配置java环境变量(m'y'cat是java项目,所有你懂的。。。)
       4、配置mycat的server.xml文件
       找到这段

<user name="web">

<property name="password">Zxq123456~..</property>

<property name="schemas">test_z</property>

</user>

<user name="web_r">

<property name="password">Zxq123456~..</property>

<property name="schemas">test_z</property>

<property name="readOnly">true</property>

</user>

这里配置了两个用户可以用来连接mycat,【用户1:账号,web;密码,Zxq123456~.. ;数据库,test_z,权限,所有 】【 用户2:账号,web_r;密码,Zxq123456~..;数据库,test_z;权限,只读】

5、配置schema.xml文件(由于我只需要读写分离的配置,只进行了按需的配置,还可以添加很多其他的功能配置,可以网上自行搜索)

mysql主从同步+mycat读写分离+.NET程序连接mycat代理

这里着重解释几个配置参数:

1、 name="test_z"这里就是对外的数据库名称,必须和server.xml中配置的一样。

2、database="test_z"指真是数据库名称

3、balance参数可选0、1、2、3(这个选项只有mycat1.3以及之后版本才有)

0---不开启读写分离机制,所有读操作都发送到当前可用的 writeHost 上

1---全部的 readHost 与 stand by writeHost 参与 select 语句的负载均衡,简单的说,当双主双从模式(M1 ->S1 , M2->S2,并且 M1 与 M2 互为主备),正常情况下, M2,S1,S2 都参与 select 语句的负载均衡

2---所有读操作都随机的在 writeHost、 readhost 上分发

3---所有读请求随机的分发到 wiriterHost 对应的 readhost 执行,writerHost 不负担读压力

4、writeType参数可选0、1、2

0--所有写操作发送到配置的第一个 writeHost,第一个挂了切到还生存的第二个

1--所有写操作都随机的发送到配置的 writeHost

2--没有实现

5、switchType参数可选-1、1、2

-1--不自动切换

1--自动切换,默认值

2--根据mysql主从同步的状态决定是否切换

6、启动mycat

./mycat start

mysql主从同步+mycat读写分离+.NET程序连接mycat代理

7、用户授权

mysql> grant select,update,delete,insert on test_z.* to web@'192.168.8.52' identified

by'Zxq311915~..';
        mysql> flush privileges; 

7、测试读写分离

.NET控制台代码测试;

1、由于MyCAT与MySQL协议有些许差异,开发者可能不能够直接使用Oracle官方提供的Mysql.Data(ADO层)来与MyCAT直接连接,因此我们专门为.NET开发者设计了针对MyCAT优化过的ADO层驱动,即Pomelo.Data.MyCat,开发者通过使用MyCatConnection、MyCatCommand类可以实现对MyCAT的连接与查询。

2、导入Pomelo.Data.Mycat

mysql主从同步+mycat读写分离+.NET程序连接mycat代理

3、代码测试

mysql主从同步+mycat读写分离+.NET程序连接mycat代理

大伙还记得之前配置的参数吧,这里连接字符串要用到,mycat默认监听端口是8066,至于怎么测试读写分离,我想大家都会,自行在数据库里通过添加删除数据来控制。

--------------------------------------------------------------------

后记

今天写这篇文章作为个备忘录,写的比较简单,算是一个大概的过程,后面会根据实际使用中按需扩展或者修改,大家如果阅读过程中发现有不对的地方,欢迎指正。



上一篇:监控mysql主从同步状态脚本


下一篇:Cause:java.sql.SQLException: null, message from server: "Host '192.168.222.1' is not allowed to connect to this MySQL server"