一般的数据库环境多为一主多从的多实例集群环境,与此同时应用层基于这个结构改造与数据库连接的部分,将操作频率低的写操作放在master节点上执行,操作频率高的查询类请求放在slave节点执行。具备初级的读写分离并具备一定的负载均衡能力。
这种读写分离架构,同时要考虑到性能和扩展方面的因素,负责查询服务的slave节点会有多个,此时应该连接哪个mysql实例,就成了问题,一是连接的每个slave都是单点,一旦连接的那台节点遇到故障,就需要应用层修改连接配置,使之指向另一台正常工作的节点,其次不具备负载均衡能力,如果被连接的节点负载已经较高,很难通过增加节点的方式弹性的为期增强承载能力。如果能够像oracle rac那样提供虚拟ip(vip)地址供应用层选用就可以解决这个问题。Mysql通常使用开源的LVS(linux virtual server)
一. 配置LVS
Linux2.6.x以上内核版本都已自带对LVS的支持,可以通过“modprobe-l |grep ipvs”查看当前操作系统是否存在LVS相关模块。自带模块说明可以使用LVS这项服务。不过还需要一个管理工具来执行常规的管理操作,这就需要用到ipvsadm软件包,这个软件包相当于是LVS的命令行管理接口。
1. 安装ipvsadm
下载地址:http://www.linuxvirtualserver.org/software/ipvs.html
--检查依赖包
# rpm -q gcc
# rpm -q openssl
# rpm -q openssl-devel
# rpm -q popt
# rpm -q kernel-devel
--安装静态资源包
[root@mysql_slave ~]# rpm -ivh popt-static-1.13-7.el6.x86_64.rpm
Preparing... ########################################### [100%]
1:popt-static ########################################### [100%]
--建立安装需要的软链,内核版本和软件目录需要一致。
[root@mysql_slave ipvsadm-1.26]# rpm -q kernel-devel
kernel-devel-2.6.32-431.el6.x86_64
[root@mysql_slave ipvsadm-1.26]# ln -s /usr/src/kernel-devel-2.6.32-431.el6.x86_64 /usr/src/linux
--解压,编译
[root@mysql_slave ~]# tar zxvf ipvsadm-1.26.tar.gz
[root@mysql_slave ipvsadm-1.26]# make
make -C libipvs
make[1]: Entering directory `/root/ipvsadm-1.26/libipvs'
gcc -Wall -Wunused -Wstrict-prototypes -g -fPIC -DLIBIPVS_USE_NL -DHAVE_NET_IP_VS_H -c -o libipvs.o libipvs.c
gcc -Wall -Wunused -Wstrict-prototypes -g -fPIC -DLIBIPVS_USE_NL -DHAVE_NET_IP_VS_H -c -o ip_vs_nl_policy.o ip_vs_nl_policy.c
ar rv libipvs.a libipvs.o ip_vs_nl_policy.o
ar: creating libipvs.a
a - libipvs.o
a - ip_vs_nl_policy.o
gcc -shared -Wl,-soname,libipvs.so -o libipvs.so libipvs.o ip_vs_nl_policy.o
make[1]: Leaving directory `/root/ipvsadm-1.26/libipvs'
gcc -Wall -Wunused -Wstrict-prototypes -g -DVERSION=\"1.26\" -DSCHEDULERS=\""rr|wrr|lc|wlc|lblc|lblcr|dh|sh|sed|nq"\" -DPE_LIST=\""sip"\" -DHAVE_POPT -DHAVE_NET_IP_VS_H -c -o ipvsadm.o ipvsadm.c
ipvsadm.c: In function ‘print_largenum’:
ipvsadm.c:1383: warning: field width should have type ‘int’, but argument 2 has type ‘size_t’
gcc -Wall -Wunused -Wstrict-prototypes -g -DVERSION=\"1.26\" -DSCHEDULERS=\""rr|wrr|lc|wlc|lblc|lblcr|dh|sh|sed|nq"\" -DPE_LIST=\""sip"\" -DHAVE_POPT -DHAVE_NET_IP_VS_H -c -o config_stream.o config_stream.c
gcc -Wall -Wunused -Wstrict-prototypes -g -DVERSION=\"1.26\" -DSCHEDULERS=\""rr|wrr|lc|wlc|lblc|lblcr|dh|sh|sed|nq"\" -DPE_LIST=\""sip"\" -DHAVE_POPT -DHAVE_NET_IP_VS_H -c -o dynamic_array.o dynamic_array.c
gcc -Wall -Wunused -Wstrict-prototypes -g -o ipvsadm ipvsadm.o config_stream.o dynamic_array.o libipvs/libipvs.a -lpopt -lnl
[root@mysql_slave ipvsadm-1.26]# make install
make -C libipvs
make[1]: Entering directory `/root/ipvsadm-1.26/libipvs'
make[1]: Nothing to be done for `all'.
make[1]: Leaving directory `/root/ipvsadm-1.26/libipvs'
if [ ! -d /sbin ]; then mkdir -p /sbin; fi
install -m 0755 ipvsadm /sbin
install -m 0755 ipvsadm-save /sbin
install -m 0755 ipvsadm-restore /sbin
[ -d /usr/man/man8 ] || mkdir -p /usr/man/man8
install -m 0644 ipvsadm.8 /usr/man/man8
install -m 0644 ipvsadm-save.8 /usr/man/man8
install -m 0644 ipvsadm-restore.8 /usr/man/man8
[ -d /etc/rc.d/init.d ] || mkdir -p /etc/rc.d/init.d
install -m 0755 ipvsadm.sh /etc/rc.d/init.d/ipvsadm
[root@mysql_slave ipvsadm-1.26]# ipvsadm
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
--验证是否安装成功
[root@mysql_slave ~]# ipvsadm
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
2. 配置LVS
[root@mysql ~]# ipvsadm -A -t 192.168.48.52:3306 -s rr
[root@mysql ~]# ipvsadm -a -t 192.168.48.52:3306 -r 192.168.48.50:3306 -g
[root@mysql ~]# ipvsadm -a -t 192.168.48.52:3306 -r 192.168.48.51:3306 -g
-A:指的是当前的操作要增加一个新的虚拟服务器,即VIP(虚拟IP地址)
-t:为新增加的服务器指定IP地址,就是指定的CIP
-s:指定轮循方式,共有八种。Rr为使用最传统的轮循算法,他会将接收到的请求按顺序轮流分配到集群中的RealServer上(即后面通过-r参数指定的地址),均等地对待每一台RealServer,不管服务器当前实际的连接数或系统负载如何,甚至不管当前该节点是否可以正常连接。
-a:指定当前的操作是要增加一个新的RealServer节点,RealServer也就是实际的服务器。
-r:指定指定RealServer服务所在的地址,以及端口
-g:选择路由方式,-g代表的是直接路由(DR)模式,对于数据库来说,DR模式为首选,也就是-g参数
综上,以上三条命令的功能就是:创建一个新的虚拟服务器:192.168.48.52:3306,所有连接到该IP:3306的访问请求,都会以轮循的方式转发到192.168.48.50或192.168.48.51的3306端口进行响应。
VS接收到的请求会转发给后端的RealServer,即能够处理请求的服务器,关于转发后的请求处理后的数据返回给请求方的方法,LVS提供了两套相应方案,一套是由各slave节点相应请求,并直接将数据返回给请求发起方,LVS相当于纯工作转派,这种就是DR模式,第二套方案也是slave节点响应请求,不过在返回数据时,slave不会讲数据直接返回给请求的发起方,而是反馈给LVS,由LVS统一返回请求到发起方,即是NAT模式,相当LVS为统一入口。实际情况多采用DR模式,LVS只负责转发请求而无需处理,由实际的RealServer负责实际响应请求。
这种模式也就是传说中的反向代理,对于前端请求发起方来说,他不知道也不需要知道后端是谁相应它的请求,它只需要发请求等待接收数据就好了,对于后端服务器来说,它自身也不需要暴露给前端,一方面增强了安全性,另一方面也起到一定的负载均衡效果。
--指定ipvsadm –L –n,查看当前LVS虚拟配置[root@mysql ~]# ipvsadm -L -n
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
TCP 192.168.48.52:3306 rr
-> 192.168.48.50:3306 Local 1 0 0
-> 192.168.48.51:3306 Route 1 0 0
要想让应用层改为连接192.168.48.52,还需要为网卡绑定192.168.48.52这个地址,因为前面的ipvsadm命令只是定义了服务,此时应用端连接这个地址是得不到相应的。不管是对于windos,linux/unix,每个网卡都可以绑定多个ip地址,我们只需要将刚刚创建的服务IP绑定到LVS所在服务器的网卡上。
--直接在eth0网卡中绑定一个别名即可
[root@mysql ~]# ifconfig eth0:0 192.168.48.52
[root@mysql ~]# ifconfig
eth0 Link encap:Ethernet HWaddr 00:0C:29:38:88:35
inet addr:192.168.48.50 Bcast:192.168.48.255 Mask:255.255.255.0
inet6 addr: fe80::20c:29ff:fe38:8835/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:8204 errors:0 dropped:0 overruns:0 frame:0
TX packets:1557 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:1889213 (1.8 MiB) TX bytes:271800 (265.4 KiB)
eth0:0 Link encap:Ethernet HWaddr 00:0C:29:38:88:35
inet addr:192.168.48.52 Bcast:192.168.48.255 Mask:255.255.255.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:16436 Metric:1
RX packets:16 errors:0 dropped:0 overruns:0 frame:0
TX packets:16 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:1272 (1.2 KiB) TX bytes:1272 (1.2 KiB)
3. 配置real server
配置好LVS之后,还需要为RealServer们绑定前设置的虚拟服务器192.168.48.52,但不是将其绑定在标准网卡设置,而是将之绑定到lo(local)换回接口上面。
[root@mysql ~]# ifconfig lo:242 192.168.48.52 broadcast 192.168.48.52 netmask 255.255.255.255
[root@mysql ~]# ifconfig
eth0 Link encap:Ethernet HWaddr 00:0C:29:38:88:35
inet addr:192.168.48.50 Bcast:192.168.48.255 Mask:255.255.255.0
inet6 addr: fe80::20c:29ff:fe38:8835/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:9169 errors:0 dropped:0 overruns:0 frame:0
TX packets:1693 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:2123354 (2.0 MiB) TX bytes:290620 (283.8 KiB)
eth0:0 Link encap:Ethernet HWaddr 00:0C:29:38:88:35
inet addr:192.168.48.52 Bcast:192.168.48.255 Mask:255.255.255.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:16436 Metric:1
RX packets:16 errors:0 dropped:0 overruns:0 frame:0
TX packets:16 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:1272 (1.2 KiB) TX bytes:1272 (1.2 KiB)
lo:242 Link encap:Local Loopback
inet addr:192.168.48.52 Mask:255.255.255.255
UP LOOPBACK RUNNING MTU:16436 Metric:1
--禁用lo环回接口的APR广播,执行操作如下:
在每个realserver执行
[root@mysql ~]# echo "1" >/proc/sys/net/ipv4/conf/lo/arp_ignore
[root@mysql ~]# echo "2" >/proc/sys/net/ipv4/conf/lo/arp_announce
[root@mysql ~]# echo "3" >/proc/sys/net/ipv4/conf/all/arp_ignore
[root@mysql ~]# echo "4" >/proc/sys/net/ipv4/conf/all/arp_announce
--lvs搭建完成后可以通过应用层通过192.168.48.52来访问slave节点
二. 使用keepalived增强LVS高可用能力
对于应用端,不管后端有多少slave节点,它只需连接调度服务器中分配的VIP,即192.168.48.52,具体连接到哪台slave节点,由调度服务器来决定。
如果此时手工停止某个slave节点,连接就会时好时坏。要实现故障的自动切换,就需要另外一款开源软件,keepalived,其设计之初也就是为LVS提供高可用集群功能。
Keepalived主要实现三个功能:
a. 实现Ip地址的漂移。比如有A,B两个节点,A节点出现故障,则将A节点的IP地址漂移到B节点,前端应用的请求就会有B节点来响应,这样对于前端的应用来说,故障就是透明的。
b. 生成ipvs规则,即直接在keepalived中配置我们前面通过ipvsadm创建的一系列规则。
c. 执行健康检查,即时检测到节点故障,并定义检测到故障后的处理思路
1. 安装keepalived步骤
[root@mysql ~]# tar xvfz keepalived-1.2.19.tar.gz
[root@mysql ~]# cd keepalived-1.2.19
[root@mysql keepalived-1.2.19]# ./configure --prefix=/usr/local/keepalived --with-kernel-dir=/usr/src/kernels/2.6.32-431.el6.x86_64
[root@mysql keepalived-1.2.19]# make && make install
--复制文件到相关路径,以方便调用
[root@mysql ~]# cp /usr/local/keepalived/sbin/keepalived /usr/sbin/
[root@mysql ~]# cp /usr/local/keepalived/etc/rc.d/init.d/keepalived /etc/init.d/
[root@mysql ~]# cp /usr/local/keepalived/etc/sysconfig/keepalived /etc/sysconfig/
2. 配置keepalived
默认情况下,keepalived会在下列路径下查找配置文件,即/etc/keepalived/keepalived.conf文件,我们直接在该路径下创建配置文件:
[root@mysql ~]# mkdir /etc/keepalived
[root@mysql ~]# cd /etc/keepalived/
[root@mysql keepalived]# vi keepalived.conf
global_defs {
notification_email {
username@domainname.com
}
notification_email_from username@domainname.com
smtp_server smtp.domain.com
smtp_connect_timeout 30
router_id MySQL-HA
}
vrrp_instance VI_1 {
state MASTER
interface eth0
virtual_router_id 1
priority 100
advert_int 1
authentication {
auth_type PASS
auth_pass 3306
}
virtual_ipaddress {
192.168.48.55
}
track_script {
check_run
}
"keepalived.conf" 52L, 1282C
auth_type PASS
auth_pass 3306
}
virtual_ipaddress {
192.168.48.55
}
track_script {
check_run
}
}
virtual_server 192.168.48.55 3306 {
delay_loop 6
lb_algo rr
lb_kind DR
#nat_mask 255.255.255.0
persistence_timeout 50
protocol TCP
real_server 192.168.48.51 3306 {
weight 1
TCP_CHECK {
connect_timeout 5
nb_get_retry 3
delay_before_retry 3
connect_port 3306
}
}
real_server 192.168.48.53 3306 {
weight 1
TCP_CHECK {
connect_timeout 5
nb_get_retry 3
delay_before_retry 3
connect_port 3306
}
}
}
--清除之前配置的ipvs配置
[root@mysql ~]# ipvsadm -C
--启动keepalived服务
[root@mysql ~]# service keepalived start
Starting keepalived: [ OK ]
--keepalived服务启动之后,这部分已完全由keepalived接管,相应的规则也就生效了。
[root@mysql ~]# ipvsadm -L -n
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
TCP 192.168.48.55:3306 rr persistent 50
-> 192.168.48.51:3306 Route 1 0 0
-> 192.168.48.53:3306 Route 1 0 0
Keepalived具备高可用方面的功效,依赖于其对realserver的检测功能,当前的配置是基于自带的top_check,也可以自定义脚本进行检测。
停掉realserver中的一个后,keepalived会将其从lvs的配置中移除。应用也就不会再去连接死掉的节点了