高可用架构

简介

​ Heartbeat、Corosync、Keepalived这三个集群组件我们到底选哪个好,首先我想说明的是,Heartbeat、Corosync是属于同一类型,Keepalived与Heartbeat、Corosync,根本不是同一类型的。Keepalived使用的vrrp协议方式,虚拟路由冗余协议 (Virtual Router Redundancy Protocol,简称VRRP);Heartbeat或Corosync是基于主机或网络服务的高可用方式;简单的说就是,Keepalived的目的是模拟路由器的高可用,Heartbeat或Corosync的目的是实现Service的高可用。

​ 所以一般Keepalived是实现前端高可用,常用的前端高可用的组合有,就是我们常见的LVS+Keepalived、Nginx+Keepalived、HAproxy+Keepalived。而Heartbeat或Corosync是实现服务的高可用,常见的组合有Heartbeat v3(Corosync)+Pacemaker+NFS+Httpd 实现Web服务器的高可用、Heartbeat v3(Corosync)+Pacemaker+NFS+MySQL 实现MySQL服务器的高可用。总结一下,Keepalived中实现轻量级的高可用,一般用于前端高可用,且不需要共享存储,一般常用于两个节点的高可用。而Heartbeat(或Corosync)一般用于服务的高可用,且需要共享存储,一般用于多节点的高可用。这个问题我们说明白了。

说明

高可用HA(High Availability)是分布式系统架构设计中必须考虑的因素之一, 它通常是指,通过设计减少系统不能提供服务的时间。

单点往往是系统高可用最大的风险和敌人,应该尽量在系统设计的过程中避免单点。 高可用保证的原则是“集群化”,或者叫“冗余”:只有一个单点,挂了服务会受影响。
如果有冗余备份,挂了还有其他backup能够顶上。

有了冗余之后,还不够,每次出现故障需要人工介入恢复势必会增加系统的不可服务实践。
所以,又往往是通过“自动故障转移”来实现系统的高可用。

  • 客户端层:典型调用方是浏览器browser或者手机应用APP
  • 反向代理层:系统入口,反向代理
  • 站点应用层:实现核心应用逻辑,返回html或者json
  • 服务层:如果实现了服务化,就有这一层
  • 数据-缓存层:缓存加速访问存储
  • 数据-数据库层:数据库固化数据存储

客户端到方向代理

【客户端层】到【反向代理层】的高可用,是通过反向代理层的冗余来实现的。以nginx为例:有两台nginx, 一台对线上提供服务,另一台冗余以保证高可用,常见的实践是keepalived存活探测,相同virtual IP提供服务。

自动故障转移:当nginx挂了的时候,keepalived能够探测到心跳,会自动的进行故障转移, 将流量自动迁移到备份nginx,由于使用的是相同的virtual IP,这个切换过程对调用方是透明的

反向代理层到站点层

【反向代理层】到【站点层】的高可用,是通过站点层的冗余来实现的。 假设反向代理层是nginx,nginx.conf里能够配置多个web后端,并且nginx能够探测到多个后端的存活性。

自动故障转移:当web-server挂了的时候,nginx能够探测到,会自动的进行故障转移, 将流量自动迁移到其他的web-server,整个过程由nginx自动完成,对调用方是透明的。

站点层到服务层

【站点层】到【服务层】的高可用,是通过服务层的冗余来实现的。“服务连接池”会建立与下游服务多个连接,每次请求会“随机”选取连接来访问下游服务。

自动故障转移:当service挂了的时候,service-connection-pool能够探测到,会自动的进行故障转移,将流量自动迁移到其他的service, 整个过程由连接池自动完成,对调用方是透明的(所以说RPC-client中的服务连接池是很重要的基础组件)。

一般这个会使用到分布式服务框架

数据库层的高可用

大部分互联网技术,数据库层都用了“主从同步,读写分离”架构,所以数据库层的高可用,又分为“读库高可用”与“写库高可用”两类。

总结

  • 【客户端层】到【反向代理层】的高可用,是通过反向代理层的冗余实现的,常见实践是keepalived + virtual IP自动故障转移
  • 【反向代理层】到【站点层】的高可用,是通过站点层的冗余实现的,常见实践是nginx与web-server之间的存活性探测与自动故障转移
  • 【站点层】到【服务层】的高可用,是通过服务层的冗余实现的,常见实践是通过service-connection-pool来保证自动故障转移
  • 【服务层】到【缓存层】的高可用,是通过缓存数据的冗余实现的,常见实践是缓存客户端双读双写,或者利用缓存集群的主从数据同步与sentinel保活与自动故障转移;更多的业务场景,对缓存没有高可用要求,可以使用缓存服务化来对调用方屏蔽底层复杂性
  • 【服务层】到【数据库“读”】的高可用,是通过读库的冗余实现的,常见实践是通过db-connection-pool来保证自动故障转移
  • 【服务层】到【数据库“写”】的高可用,是通过写库的冗余实现的,常见实践是keepalived + virtual IP自动故障转移

MySQL读写分离

MySQLProxy实际上是在客户端请求与MySQLServer之间建立了一个连接池。所有客户端请求都是发向MySQLProxy,然后经由MySQLProxy进行相应的分析,判断出是读操作还是写操作,分发至对应的MySQLServer上。对于多节点Slave集群,也可以起做到负载均衡的效果。

HAProxy在使用方式上和MySQL-Proxy略有区别,它要求在应用层做读写分离,并需要给HAProxy分别配置读/写端口,一个用来做写操作,一个用来做读操作。然后在应用层还需要做一点修改,这又回到了最开始的的应用层做读写分离的情况,唯一的区别是这里把情况由原来的一写多读变成了一写一读。

  • 程序修改mysql操作类

可以参考PHP实现的Mysql读写分离,阿权开始的本项目,以php程序解决此需求。
优点:直接和数据库通信,简单快捷的读写分离和随机的方式实现的负载均衡,权限独立分配
缺点:自己维护更新,增减服务器在代码处理

  • amoeba

参考官网:http://amoeba.meidusa.com/
优点:直接实现读写分离和负载均衡,不用修改代码,有很灵活的数据解决方案
缺点:自己分配账户,和后端数据库权限管理独立,权限处理不够灵活

  • mysql-proxy

参考 mysql-proxy。
优点:直接实现读写分离和负载均衡,不用修改代码,master和slave用一样的帐号
缺点:字符集问题,lua语言编程,还只是alpha版本,时间消耗有点高

  • MySQL 采用HAproxy或amoeba进行高可用

通过前面的keepalived故障模拟可以看出,当keepalived挂掉之后,或者当主机宕机时,VIP是可以切换到备机工作。
但是如果keepalived没有挂,并且主机也没有宕机,而是haproxy自身挂掉了呢?
这个时候不会有任何切换动作,下面我们要做的就是为keepalived提供一个脚本用来检测haproxy是否正常工作,
如果没有正常工作可以再次启动haproxy,或者关闭keepalived自身。
这样一来,keepalived自身挂掉了,那么VIP就可以切换到备机上工作了。

谢谢您请我喝咖啡!