本文将介绍整年4个9(99.99%)的系统可用性方案nginx
在系统的高可靠性里有个衡量其可靠性的标准——X个9,这个X是表明数字3~5。X个9表示在系统1年时间的使用过程当中,系统能够正常使用时间与总时间(1年)之比git
系统可用性的计算公式:A=MTBF/(MTBF+MTTR)github
拿365天(1年)作计算吧,看看几个9要停机多久时间作能才能达到!web
1年 = 365天 = 8760小时
99.9 = 8760 * 0.1% = 8760 * 0.001 = 8.76小时
99.99 = 8760 * 0.0001 = 0.876小时 = 0.876 * 60 = 52.6分钟
99.999 = 8760 * 0.00001 = 0.0876小时 = 0.0876 * 60 = 5.26分钟算法
本文设计技术点:spring
LVS 是 Linux Virtual Server
(Linux 虚拟服务器) 的简称,目前 LVS 已是 Linux 内核标准的一部分,LVS 工做在网络 4 层之上仅做分发之用,因此抗负载能力比较强。LVS 有完整的双机热备方案,几乎支持对全部应用作负载均衡。LVS 在互联网应用中的位置是在 Nginx 之上后端
LVS 自己只是一个叫 IP_VS
的内核模块,这个模块能够作负载均衡,可是只用这个模块来作应用负载是远远不够的,好比 LVS 自己宕机后如何处理?实际生产环境中,通常配合 Keepalived
来使用 LVS,keepalived
支持 VRRP
心跳协议,能够实现 LVS 主备冗余,以解决 LVS 自己单点故障。另外,Keepalived 支持健康检测,网络 4 层和 7 层健康检测,防止服务器宕机。 浏览器
Keepalived做为一个高性能集群软件,它还能实现对集群中服务器运行状态的监控以及故障隔离,下面咱们介绍一下Keepalived对服务器运行状态和故障隔离的工做原理。tomcat
Keepalived工做在TCP/IP 模型的 三层(网络层)、四层(传输层)、七层(应用层),根据TCP、IP 模型各层所能实现的功能,Keepalived运行机制以下:服务器
在网络层(3):咱们知道运行中有4个重要的协议。互联网络IP协议、互联网络可控制报文协议ICMP、地址转换协议ARP、反向地址转换协议RARP,Keepalived在网络层采用最多见的工做方式是经过ICMP协议向服务器集群中的每个节点发送一个ICMP数据包(有点相似与Ping的功能),若是某个节点没有返回响应数据包,那么认为该节点发生了故障,Keepalived将报告这个节点失效,并从服务器集群中剔除故障节点。
在传输层(4):提供了两个主要的协议:传输控制协议TCP和用户数据协议UDP,传输控制协议TCP能够提供可靠的数据输出服务、IP地址和端口,表明TCP的一个链接端,要得到TCP服务,须要在发送机的一个端口和接收机的一个端口上创建链接,而Keepalived在传输层里利用了TCP协议的端口链接和扫描技术来判断集群节点的端口是否正常,好比对于常见的WEB服务器80端口。或者SSH服务22端口,Keepalived一旦在传输层探测到这些端口号没有数据响应和数据返回,就认为这些端口发生异常,而后强制将这些端口所对应的节点从服务器集群中剔除掉。
在应用层(7):能够运行FTP,TELNET,SMTP,DNS等各类不一样类型的高层协议,Keepalived的运行方式也更加全面化和复杂化,用户能够经过自定义Keepalived工做方式,例如:能够经过编写程序或者脚原本运行Keepalived,而Keepalived将根据用户的设定参数检测各类程序或者服务是否容许正常,若是Keepalived的检测结果和用户设定的不一致时,Keepalived将把对应的服务器从服务器集群中剔除
VRRP
能够将两台或者多台物理路由器设备虚拟成一个虚拟路由
,这个虚拟路由器经过虚拟IP(一个或者多个)对外提供服务,而在虚拟路由器内部十多个物理路由器协同工做,同一时间只有一台物理路由器对外提供服务,这台物理路由设备被成为:主路由器(Master角色),通常状况下Master是由选举算法产生,它拥有对外服务的虚拟IP,提供各类网络功能,如:ARP请求,ICMP 数据转发等,并且其它的物理路由器不拥有对外的虚拟IP,也不提供对外网络功能,仅仅接收MASTER的VRRP状态心跳信息,这些路由器被统称为BACKUP
的角色”,当主路由器失败时,处于BACKUP
角色的备份路由器将从新进行选举,产生一个新的主路由器进入MASTER
角色,继续提供对外服务,整个切换对用户来讲是彻底透明的。
缺点:
- 非高可用,web-server挂了整个系统就挂了
- 扩展性差,当吞吐量达到web-server上限时,没法扩容
注:单机不涉及负载均衡的问题
假设tomcat的吞吐量是1w次每秒,当系统总吞吐量达到3w时,如何扩容是首先要解决的问题,DNS轮询是一个很容易想到的方案:
优势:
- 零成本:在DNS-server上多配几个ip便可,功能也不收费
- 部署简单:多部署几个web-server便可,原系统架构不须要作任何改造
- 负载均衡:变成了多机,但负载基本是均衡的
缺点:
- 非高可用:DNS-server只负责域名解析ip,这个ip对应的服务是否可用,DNS-server是不保证的,假设有一个web-server挂了,部分服务会受到影响
- 扩容非实时:DNS解析有一个生效周期
- 暴露了太多的外网ip
tomcat的性能较差,但nginx做为反向代理的性能就强多了,假设线上跑到1w,就比tomcat高了10倍,能够利用这个特性来作扩容:
优势:
- DNS-server不须要动
- 负载均衡:经过nginx来保证
- 只暴露一个外网ip,nginx->tomcat之间使用内网访问
- 扩容实时:nginx内部可控,随时增长web-server随时实时扩容
- 可以保证站点层的可用性:任何一台tomcat挂了,nginx能够将流量迁移到其余tomcat
缺点:
- 时延增长+架构更复杂了:中间多加了一个反向代理层
- 反向代理层成了单点,非高可用:tomcat挂了不影响服务,nginx挂了怎么办?
为了解决高可用的问题,keepalived出场了
优势:
- 解决了高可用的问题
缺点:
- 资源利用率只有50%
- nginx仍然是接入单点,若是接入吞吐量超过的nginx的性能上限怎么办,例如qps达到了50000咧?
nginx毕竟是软件,性能比tomcat好,但总有个上限,超出了上限,仍是扛不住。lvs就不同了,它实施在操做系统层面, 性能比nginx好不少,例如每秒能够抗10w,这样能够利用他们来扩容,常见的架构图以下:
缺点 不论是使用lvs仍是f5,这些都是scale up的方案,根本上,lvs/f5仍是会有性能上限,假设每秒能处理10w的请求,一天也只能处理80亿的请求(10w秒吞吐量*8w秒),那万一系统的日PV超过80亿怎么办呢?(好吧,没几个公司要考虑这个问题)
水平扩展,是解决性能问题的根本方案,经过加机器扩充性能的方案才具有最好的扩展性。 facebook,google,baidu的PV是否是超过80亿呢,它们的域名只对应一个ip么,终点又是起点,仍是得经过DNS轮询来进行扩容: 此时:
这一部分跳过了,微服务集群化部署的相关的文章不少,本文篇幅有限,想了解的朋友请自行查找阅读。
微服务架构中的应用优雅停机主要是指应用实例有计划而平滑(即不产生须要处理的事故)的退出。应用服务器的停机主要分为两类:主动停机和被动停机,而其中主动停机和大部分的被动停机都是能够实现优雅停机。若是应用不作优雅停机,则会带来如下状况:
微服务的优雅升级的目标就是避免以上几种状况,从而避免人工干预的工做量和提高微服务架构的服务高可靠。
优雅停机能够解决如下场景:
优雅停机解决不了如下场景:
Java的优雅停机一般经过注册JDK的ShutdownHook(钩子)来实现,当系统接收到退出指令后,首先标记系统处于退出状态,再也不接收新的消息,而后将积压的消息处理完,最后调用资源回收接口将资源销毁,最后各线程退出执行。简单的使用demo案例以下(简单版):
/**
* 优雅停机处理方式
*
* @author lry
**/
public class Main{
/**
* 启动应用
**/
public void start(){
// 第一步:启动应用服务……
// 第二步:注册JDK钩子
Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
@Override
public void run() {
System.out.println("The hook running...");
//第三步:调用停机处理
stop();
}
}));
}
/**
* 中止应用
**/
public void stop(){
// 中止应用前停机处理(如:注销服务、标记不接受请求等)
}
}
复制代码
注:一般优雅退出须要有超时控制机制,若是到达超时时间仍然没有完成退出前的资源回收等操做,则由停机脚本直接调用KILL -9 PID的方式进行强制退出,否则可能会等待很长时间。
能够遵照如下建议规则来设计微服务的优雅停机机制
微服务应用的优雅停机根据其使用者角色的不一样,而主要分为两种类型
上图1-6步操做在大多数微服务框架中都已经集成了,无需开发人员自主开发,若是某些采用自研微服务框架的公司没有这方面功能,开发人员能够先行在本身负责的业务系统中编写ShutdownHook来完成相同操做。
若是不支持Nginx动态发现网关,则停机升级切换的过程须要人工接入,稍微费力点,但一样对用用户来讲是没法感知到的。
结合接入层的负载均衡高可用与微服务架构的高可用涉及,能够作到任意时间升级而不影响用户体验,不形成生产事故。但仍是没实现全自动的流程,由于Nginx不支持动态发现网关并修改配置生效。
社区经常使用的 upstream 动态更新方案有 4 个
这些插件有一个共同点,那就是在不须要重启nginx的基础上, 动态修改nginx的配置。
基于以上插件呢,能够略作修改,使其支持nacos/zookeeper/consol/erueka等注册中心的服务发现,定制须要的nginx reload upstream 动态更新模块便可。