一、概述
MyCat的读写分离是基于后端MySQL集群的主从同步来实现的,而MyCat提供语句的分发功能。MyCat1.4开始支持MySQL主从复制状态绑定的读写分离机制,让读更加安全可靠。
原理
上述图片里,Orders表被分为三个分片datanode(简称dn),这三个分片是分布在两台MySQL Server上(DataHost),即datanode=database@datahost方式,因此你可以用一台到N台服务器来分片,分片规则为(sharding rule)典型的字符串枚举分片规则,一个规则的定义是分片字段(sharding column)+分片函数(rule function),这里的分片字段为prov而分片函数为字符串枚举方式。
当Mycat收到一个SQL时,会先解析这个SQL,查找涉及到的表,然后看此表的定义,如果有分片规则,则获取到SQL里分片字段的值,并匹配分片函数,得到该SQL对应的分片列表,然后将SQL发往这些分片去执行,最后收集和处理所有分片返回的结果数据,并输出到客户端。以select * from Orders where prov=?语句为例,查到prov=wuhan,按照分片函数,wuhan返回dn1,于是SQL就发给了MySQL1,去取DB1上的查询结果,并返回给用户。如果上述SQL改为select * from Orders where prov in (‘wuhan’,‘beijing’),那么,SQL就会发给MySQL1与MySQL2去执行,然后结果集合并后输出给用户。但通常业务中我们的SQL会有Order By 以及Limit翻页语法,此时就涉及到结果集在Mycat端的二次处理,这部分的代码也比较复杂,而最复杂的则属两个表的Jion问题,为此,Mycat提出了创新性的ER分片、全局表、HBT(Human Brain Tech)人工智能的Catlet、以及结合Storm/Spark引擎等十八般武艺的解决办法。
二、MyCat环境部署
MyCat的读写分离是基于后端MySQL集群的主从同步来实现的,而MyCat提供语句的分发功能。MyCat1.4开始支持MySQL主从复制状态绑定的读写分离机制,让读更加安全可靠。
环境介绍
主机名 |
IP地址 |
系统 |
服务名 |
Mycat-A |
192.168.200.103 |
CentOS 6.5 |
Mycat |
Mysql-A |
192.168.200.104 |
CentOS 6.5 |
Mysql |
Mysql-B |
192.168.200.105 |
CentOS 6.5 |
Mysql |
1. 服务器基本配置
配置本地解析文件:
vim /etc/hosts 192.168.200.103 MyCat-A 192.168.200.104 Mysql-A 192.168.200.105 Mysql-B
配置主机名:
hostname MyCat-A/Mysql-A/Mysql-B
Mysql主从复制部署
Mysql-A安装配置:
[root@Mysql-A ~]# yum -y install mysql-server [root@Mysql-A ~]# vim /etc/my.cnf log-bin=mysql-bin server-id=1 log_bin_trust_function_creators=true lower_case_table_names=1 [root@Mysql-A ~]# service mysql start
Mysql-B安装配置:
[root@Mysql-B ~]# yum -y install mysql-server [root@Mysql-B ~]# vim /etc/my.cnf server-id=2 relay-log=relay-log log-bin=mysql-bin log_bin_trust_function_creators=true lower_case_table_names=1 [root@Mysql-B ~]# service mysql start
Mysql-A:
[root@Mysql-A ~]# mysqladmin -uroot password "123456" [root@Mysql-A ~]# mysql -uroot -p123456 mysql> grant replication slave on *.* to 'repu'@'192.168.200.%' identified by '123456'; Query OK, 0 rows affected (0.01 sec) mysql> show master status; +------------------+----------+--------------+------------------+ | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | +------------------+----------+--------------+------------------+ | mysql-bin.000004 | 461 | | | +------------------+----------+--------------+------------------+ 1 row in set (0.00 sec)
Mysql-B:
[root@Mysql-B ~]# mysqladmin -uroot password "123456" [root@Mysql-B ~]# mysql -uroot -p123456 mysql> change master to -> master_host='192.168.200.104', -> master_user='repu', -> master_password='123456', -> master_log_file='mysql-bin.000004', -> master_log_pos='461'; 1 row in set (0.00 sec) mysq>slave start; 1 row in set (0.00 sec) mysql>show slave status\G Slave_IO_Running: Yes Slave_SQL_Running: Yes 1 row in set (0.00 sec)
MyCat安装
下载地址:http://dl.mycat.io/
[root@MyCat-A ~]# tar xf Mycat-server-1.6-RELEASE-20161028204710-linux.tar.gz -C /usr/local/
配置MyCat
1. server.xml
[root@MyCat-A ~]# cp /usr/local/mycat/conf/server.xml{,.bak} [root@MyCat-A ~]# vim /usr/local/mycat/conf/server.xml//修改文件末端user项 <user name="readuser">//用户名 <property name="password">readuser</property>//密码 <property name="schemas">mytest</property>//虚拟数据库名 <property name="readOnly">true</property>//只读 </user> <user name="writeuser"> <property name="password">writeuser</property> <property name="schemas">mytest</property> </user>
1. schema.xml
[root@MyCat-A ~]# cp /usr/local/mycat/conf/schema.xml{,.bak} [root@MyCat-A ~]# vim /usr/local/mycat/conf/schema.xml <?xml version="1.0"?>//该行前面不能有任何内容否则服务启动会报错 <!DOCTYPE mycat:schema SYSTEM "schema.dtd"> <mycat:schema xmlns:mycat="http://io.mycat/"> <schema name="mytest" checkSQLschema="false" sqlMaxLimit="100" dataNode="my1" />//定义虚拟数据库名 <dataNode name="my1" dataHost="test1" database="test" />//真实数据库名 <dataHost name="test1" maxCon="1000" minCon="10" balance="1" writeType="0" dbType="mysql" dbDriver="native" > <heartbeat>select user()</heartbeat> <writeHost host="hostM1" url="192.168.200.104:3306" user="tank" password="123456" >//真是数据库连接方式 <readHost host="hostS1" url="192.168.200.105:3306" user="tank" password="123456" /> //同上 </writeHost> </dataHost> </mycat:schema>
mycat的配置参数,相当的多。重点说一下 balance="1"与writeType="0"
- balance 属性负载均衡类型,目前的取值有 4 种:
- 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", 所有读请求随机的分发到 wiriterHost 对应的 readhost 执行,writerHost 不负担读压力,注意 balance=3 只在 1.4 及其以后版本有, 1.3 没有。
- writeType 属性
负载均衡类型,目前的取值有 3 种:
- writeType="0", 所有写操作发送到配置的第一个 writeHost,第一个挂了切到还生存的第二个
- writeHost,重新启动后已切换后的为准,切换记录在配置文件中:dnindex.properties .
- writeType="1",所有写操作都随机的发送到配置的 writeHost。
- writeType="2",没实现。
具体参数:http://mycat.io/document/Mycat_V1.6.0.pdf
2. log4j2.xml(可选)
[root@MyCat-A ~]# vim /usr/local/mycat/conf/log4j2.xml value=”info” 修改为”debug”
验证
[root@MyCat-A ~]# netstat -antup | egrep ":(8066|9066)" tcp 0 0 0.0.0.0:8066 0.0.0.0:* LISTEN 2077/java tcp 0 0 0.0.0.0:9066 0.0.0.0:* LISTEN 2077/java
[root@MyCat-A ~]# mysql -uwriteuser -pwriteuser -P 8066 -h 192.168.200.103 mysql> show databases; +----------+ | DATABASE | +----------+ | mytest | +----------+ 1 row in set (0.06 sec) mysql> use mytest Reading table information for completion of table and column names You can turn off this feature to get a quicker startup with -A Database changed
#创建一个表测试 mysql>CREATE TABLE IF NOT EXISTS `user` ( -> `id` int(11) unsigned NOT NULL DEFAULT '0' COMMENT 'ID', -> `name` varchar(20) NOT NULL DEFAULT '' COMMENT '姓名', -> `create_time` int(10) NOT NULL DEFAULT '0' COMMENT '创建时间', -> PRIMARY KEY (`id`) -> ) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ; 1 row in set (0.06 sec)
# 插入数据 mysql> INSERT INTO `user` (`id` ,`name`)VALUES ('1', 'msl23'); 1 row in set (0.06 sec) mysql> select * from user; +----+-------+-------------+ | id | name | create_time | +----+-------+-------------+ | 1 |msl23 | 0 | +----+-------+-------------+ 2 rows in set (0.14 sec)
三、使用HAproxy部署MyCat高可用
MyCat-B和Mycat-A配置相同:
- 主机名
- hosts文件更新为:
[root@MyCat-B ~]# vim /etc/hosts 192.168.200.103 MyCat-A 192.168.200.104 Mysql-A 192.168.200.105 Mysql-B 192.168.200.102 MyCat-B 192.168.200.101 HAproxy
简介
HAProxy官网:http://www.haproxy.org/ (可能需要FQ)
HAProxy各版本的官方文档:http://cbonte.github.io/haproxy-dconv/index.html
HAProxy 是一款提供高可用性、负载均衡以及基于TCP(第四层)和HTTP(第七层)应用的代理软件,支持虚拟主机,它是免费、快速并且可靠的一种解决方案。
HAProxy目前主要有三个版本:1.4、1.5、1.6,CentOS6.6自带的RPM包为1.5的。
HAProxy1.5版开始,支持SSL、DDoS防护等功能,可看官网说明:
version 1.5 : the most featureful version, supports SSL, IPv6, keep-alive, DDoS protection, etc...
MyCat官方推荐使用HAProxy做MyCat的高可用负载均衡代理。
HAProxy支持TCP(第四层)和HTTP(第七层)应用的代理,本节课程我们使用HAProxy来做MyCat的负载均衡代理使用的是TCP模式。在4层模式下HAProxy仅在客户端和服务器之间转发双向流量。HAProxy配置简单,拥有非常不错的服务器健康检查功能,当其代理的后端服务器出现故障,HAProxy会自动将该服务器摘除,故障恢复后会自动将该服务器加入进来。
架构图
配置MyCatAB(A/B配置相同)
配置服务检查状态:
MyCat服务主机(MyCat-A,MyCat-B)上需要增加mycat服务的状态检测脚本,并开放相应的检测端口,以提供给HAProxy对MyCat的服务状态进行检测判断。可以使用xinetd来实现,通过xinetd,HAProxy可以用httpchk来检测MyCat的存活状态。(xinetd即extended internet daemon,xinetd是新一代的网络守护进程服务程序,又叫超级Internet服务器。经常用来管理多种轻量级Internet服务。xinetd提供类似于inetd+tcp_wrapper的功能,但是更加强大和安全。xinetd为linux系统的基础服务)
1. 配置
[root@MyCat-A ~]# yum install xinetd [root@MyCat-A ~]# vim /etc/xinetd.d/mycat_status service mycat_status { flags = REUSE ## 使用该标记的socket_type为stream,需要设置wait为no socket_type = stream ## 封包处理方式,Stream为TCP数据包 port = 48700 ## 服务监听端口 wait = no ## 表示不需等待,即服务将以多线程的方式运行 user = root ## 执行此服务进程的用户 server =/usr/local/bin/mycat_status ## 需要启动的服务脚本 log_on_failure += USERID ## 登录失败记录的内容 disable = no ## 要启动服务,将此参数设置为no } [root@MyCat-A ~]# vim /usr/local/bin/mycat_status mycat=`/usr/local/mycat/bin/mycat status | grep 'not running' | wc -l` if [ "$mycat" = "0" ]; then /bin/echo -e "HTTP/1.1 200 OK\r\n" else /bin/echo -e "HTTP/1.1 503 Service Unavailable\r\n" fi [root@MyCat-A ~]# chmod a+x /usr/local/bin/mycat_status [root@MyCat-A ~]# vim /etc/services//添加 mycat_status 48700/tcp # mycat_status [root@MyCat-A ~]# service xinetd restart
2. 验证
[root@MyCat-A ~]# netstat -antup|grep 48700 tcp 0 0 0.0.0.0:48700 0.0.0.0:* LISTEN 2193/xinetd
配置HAproxy
1. 安装
[root@HAproxy ~]# yum install gcc gcc-c++ pcre pcre-devel zlib zlib-devel openssl openssl-devel [root@HAproxy ~]# tar xf haproxy-1.5.19.tar.gz [root@HAproxy ~]# cd haproxy-1.5.19 [root@HAproxy haproxy-1.5.19]# make TARGET=linux2628 ARCH=x86_64 USE_PCRE=1 USE_OPENSSL=1 USE_ZLIB=1 PREFIX=/usr/local/haproxy [root@HAproxy haproxy-1.5.19]# mkdir /usr/local/haproxy [root@HAproxy haproxy-1.5.19]# make install PREFIX=/usr/local/haproxy
准备配置文件
[root@HAproxy haproxy-1.5.19]# cp examples/haproxy.cfg /usr/local/haproxy/conf/
准备错误文件
[root@HAproxy haproxy-1.5.19]# cp -r examples/errorfiles/ /usr/local/haproxy/
准备开机启动文件
[root@HAproxy haproxy-1.5.19]# cp examples/haproxy.init /etc/init.d/ [root@HAproxy haproxy-1.5.19]# chmod a+x /etc/init.d/haproxy [root@HAproxy haproxy-1.5.19]# chkconfig --add haproxy [root@HAproxy haproxy-1.5.19]# chkconfig haproxy on
2. 配置HAproxy
修改haproxy.cfg文件
[root@HAproxy ~]# vim /usr/local/haproxy/conf/haproxy.cfg #--------------------------------------------------------------------- # Global settings #--------------------------------------------------------------------- global log 127.0.0.1 local0 ##记日志的功能 maxconn 4096 ##最大连接数,默认4000 #chroot /usr/local/haproxy user root #所属用户 group root #所属组 daemon ###创建1个进程进入deamon模式运行。此参数要求将运行模式设置为"daemon" defaults log global ###采用全局定义的日志 option dontlognull ###不记录健康检查的日志信息 retries 3 ###3次连接失败就认为服务不可用,也可以通过后面设置 option redispatch ###serverId对应的服务器挂掉后,强制定向到其他健康的服务器 maxconn 2000 ###最大连接数 timeout connect 5000ms ##contimeout 5000 连接超时 timeout client 50000ms ##clitimeout 50000 客户端连接超时 timeout server 50000ms ##srvtimeout 50000 服务器连接超时 ##listen admin_status 192.168.200.101:48800 ##VIP ##stats uri/admin-status #统计页面 ##stats auth admin:admin mode http ###默认的模式,tcp是4层,http是7层,health只会返回OK 若是混合模式则 mode 不需要设置 option httplog ###日志类别http日志格式 混合模式 此处还需要加上 tcplog ## HAProxy的状态信息统计页面 listen admin_stats bind :48800 ## 绑定端口 stats uri /admin-status ##统计页面 stats auth admin:admin ## 设置统计页面认证的用户和密码,如果要设置多个,另起一行写入即可 mode http option httplog ## 启用日志记录HTTP请求 listen allmycat_service ##192.168.200.101:8096 ##转发到mycat的8066端口,即mycat的服务端口 bind 192.168.200.101:8096 mode tcp option tcplog option httpchk OPTIONS * HTTP/1.1\r\nHost:\ www balance roundrobin server mycat_161 192.168.200.102:8066 check port 48700 inter 5s rise 2 fall 3 server mycat_165 192.168.200.103:8066 check port 48700 inter 5s rise 2 fall 3 #srvtimeout 20000 timeout server 20000 listen allmycat_admin ##192.168.200.101:8097 ##转发到mycat的9066端口,及mycat的管理控制台端口 bind 192.168.200.101:8097 mode tcp option tcplog option httpchk OPTIONS * HTTP/1.1\r\nHost:\ www balance roundrobin server mycat_161 192.168.200.102:9066 check port 48700 inter 5s rise 2 fall 3 server mycat_165 192.168.200.103:9066 check port 48700 inter 5s rise 2 fall 3 #srvtimeout 20000 timeout server 20000
3. 配置rsyslog
默认haproxy是不记录日志的,为了记录日志还需要配置syslog模块,在Linux下是rsyslogd服务
[root@HAproxy ~]# yum -y install rsyslog [root@HAproxy ~]# vim /etc/rsyslog.d/haproxy.conf $ModLoad imudp $UDPServerRun 514 local0.* /var/log/haproxy.log [root@HAproxy ~]# vim /etc/rsyslog.conf # Save boot messages also to boot.log local7.* /var/log/boot.log local0.* /var/log/haproxy.log [root@HAproxy ~]# service rsyslog restart
启动HAproxy
检查HAproxy配置文件是否正确
[root@HAproxy ~]# /usr/local/haproxy/sbin/haproxy -f /usr/local/haproxy/conf/haproxy.cfg -c
启动HAproxy
[root@HAproxy ~]# /usr/local/haproxy/sbin/haproxy -f /usr/local/haproxy/conf/haproxy.cfg
验证
通过HAproxy登陆MyCat:
[root@HAproxy ~]# mysql -uwriteuser -pwriteuser -h192.168.200.101 -P8096 Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql> show databases; +----------+ | DATABASE | +----------+ | mytest | +----------+ 1 row in set (0.00 sec)
查看状态访问http://192.168.200.101:48800/admin-status
账号密码为:
listen admin_stats bind :48800 # 绑定端口 stats uri /admin-status #统计页面 stats auth admin:admin # 设置统计页面认证的用户和密码,如果要设置多个,另起一行写入即可 mode http option httplog #启用日志记录HTTP请求