前段时间看了《大型网站系统与Java中间件实践》这本书,了解到大型网站构架的演进,大致上来说也是单机走向分布式集群来分摊访问压力。书中提到了很多常见的场景,比如数据库方面,当压力变大时可以实现读写分离、分库分表等,总体上是给出了通用解决方案和思路。
分享下《大型网站系统与Java中间件实践》PDF,网上找不到带目录的,简单的用Adobe自己添加了目录(百度云地址)
网上搜mysql集群高可用方案结果是一大堆,也没有说哪个方案是相对比较好。看了很多文章介绍初步了解到下面的几种情况:
数据库一主多从实现读写分离
mysql-proxy:原理上应该是通过lua脚本解析sql,写主库读从库,还能配置负载均衡
mycat:也是统一拦截sql,还支持分表分库、读写分离,负载均衡等,好像比较强大。
负载均衡,把请求分发以分摊服务器压力
LVS:LVS(Linux Virtual Server)是一个虚拟的服务器集群系统,可以在UNIX/LINUX平台下实现负载均衡集群功能, LVS内核模块IPVS从2.4.24以后已经成为Linux官方标准内核的一部分。LVS相关参考这篇文章高并发场景 LVS 安装及高可用实现
haproxy、nginx:也是可以用来做负载均衡
高可用则需要定时检测节点,出现故障时自动转移
keepalived:具体参考这篇写的比较好的文章keepalived实现服务高可用,keepalived一开始就为LVS设计的,和LVS搭配比较简单。keepalived使用VRRP协议,限制的地方是使用arp的广播模式,只有同一网段才能使用,也就是局域网环境,然后还有脑裂的问题
《从Paxos到Zookeeper 分布式一致性原理与实践》中对脑裂的描述
MHA:比较成熟的高可用集群方案
看了一下好像都有点复杂,决定先简单的实践下使用keepalived+LVS实现mysql高可用。
draw.io
上图是我们需要实现的流程构架,只使用两台机器,将LVS与RealServer合并在同一台机器上。而且我们还是使用LVS的DR模式。先介绍下LVS的DR模式:
假设我们客户端(client:192.168.1.101)请求我们负载均衡服务器上的VIP地址(192.168.1.200),则发送的请求中源IP为(192.168.1.101),目标IP为(192.168.1.200)
路由器通过arp解析到负载均衡服务器mac地址,则转发请求到负载均衡服务器上。
DR模式下负载均衡服务器不修改该请求的目标IP,即目标IP还是(192.168.1.200),而是修改请求的mac地址再转发到RealServer(真正调用的服务器),RealServer不经过负载均衡服务器而直接返回响应信息给client。
DR模式参考网上的图
LVSDR模式需要注意的点:
默认情况下RealServer接收到目标IP是192.168.1.200的请求跟自己的IP地址不一致,则会直接抛弃这个请求导致无法访问。需要在RealServer的网卡lo接口上添加我们的VIP(192.168.1.200)来接收请求。lo是本地回环接口,当RealServer接收到目标IP是192.168.1.200的请求时,被当成本地程序服务处理,而不是直接丢弃。
这个就是我们构建LVSDR模式时最普遍使用到的realserver脚本的其中一个作用
按照网上很多的教程都是至少需要4台机器,其中keepalived+LVS部署到两台机作为单纯的负载均衡服务器,而keepalived则保证LVS负载均衡服务器的高可用,同时还支持realserver的健康检测,当其中一个realserver节点服务挂了,就将其排除出去。
个人觉得两台机作为单纯负载均衡机会有点浪费,想直接将LVS和RealServer部署在同一台机器上,但是实际测试过程中确实是出现了请求的死循环,最后通过iptables的MARK标记请求的方式不触发LVS的slave机的负载均衡解决这个问题。
一:首先本地使用虚拟机搭建实验环境
因为keepalived使用要求是同一网段(局域网),这里使用了VirtualBox搭建CentOS-7环境。
主要遇到下面几点问题:
1. 网卡设置选择桥接模式
目标是实现主机与虚拟机相互能ping通,虚拟机能上网,这里连接方式选择桥接模式并且网卡选择当前主机正在使用的网卡。
桥接模式:像是局域网中的一台独立的主机,可以访问与局域网内任何一台机器相互访问
NAT模式:可以通过主机实现上网,但不能访问主机。也可以添加多一个网卡2选择Host-only来实现虚拟机访问主机。
桥接模式
2. 虚拟机固定IP
修改虚拟机为固定IP,目的是实验时IP地址不会变化而且容易记。
主机本地cmd->ipconfig得到ipv4地址以及子网掩码和网关配置:
获取主机ip
ifconfig -a查看除了lo回环接口的外的接口名称,并执行ifup 网卡接口名称启用网卡,可以看到这里名称不是一般默认的eth0
查看网卡接口名称
修改为固定ip:vi /etc/systemconfig/network-scripts/ifcfg-enp0s3
BOOTPROTO=static
IPADDR=192.168.1.110
NETMASK=255.255.255.0
GATEWAY=192.168.1.1
DNS1=192.168.1.1
DNS2=8.8.8.8
ONBOOT=yes
3. 关闭防火墙和SELinux,减少复杂