乐趣区

关于java:对高可用系统的一点理解

什么是高可用

简略来讲就是咱们零碎如何进步对外的服务工夫,想要零碎达到 100% 可用根本是不太可能的,也内有一个专门的衡量标准 SLA(全称:Service Level Agreement),也就是有几个 9 的高可用性:

  • 90% (1 个 9):零碎全年有 36.5 天不可用;
  • 99% (2 个 9):零碎全年有 3.65 天不可用;
  • 99.9% (3 个 9):零碎全年有 8.76 小时不可用;
  • 99.99% (4 个 9):零碎全年有 52.56 分不可用;
  • 99.999% (5 个 9):零碎全年有 5.26 分不可用;
    每家公司都在为进步 9 的个数而致力,当然这不能只靠研发部门就能做到的,须要所有部门的相互配合包含:测试,运维,数据中心,基础架构等等;本文仅从研发的角度来看看如何进步零碎的可用性。

如何进步

想要进步零碎的可用性,咱们须要整合多种手段来保障,当然在应用各种伎俩之前,作为研发人员咱们首先是要保障本人代码的高质量,这是所有的前提,如果不能保障代码的品质,再多高可用的伎俩都是徒劳;上面具体看看都有哪些罕用伎俩;

负载平衡

高可用很重要的一个伎俩就是防止单点,为啥要防止单点,因为每台机器都会有出问题的概率,当某一台机器呈现问题,其余机器节点同样能够提供雷同的服务,来保证系统的可用性;从整个零碎来看,每一层都须要防止单点,从零碎的接入层到服务层到最初的数据层都防止单点的状况下能力保障整个零碎的高可用;这时候负载均衡器就起了至关重要的性能,一个负载均衡器蕴含如下一些外围性能:

  • 操作单元配置;
  • 负载平衡算法;
  • 失败重试;
  • 健康检查;

负载均衡器一方面防止了单点的呈现,另一方面多个节点独特提供服务,提供整个零碎的能力;每一层都有各自的负载均衡器:

  • 接入层:最常见的就是 Nginx 了,通过配置文件简略配置一下即可,提供了多种负载平衡算法抉择,健康检查等性能;
  • 服务层:服务层次要的就是微服务框架比方 DubboSpring Cloud 等,外部都集成了负载平衡策略,应用起来也是十分不便;
  • 数据层:这一层相比其余层每个节点是有状态的,不能简略的横向扩大,个别的做法是为数据做分片解决,每个节点寄存局部数据,同时每个节点提供备节点,呈现问题能够实时切换。

隔离

隔离在为了零碎在产生异样时,能将此异样限定在肯定范畴之内,不会产生蝴蝶效应,导致整个零碎不可用;隔离的伎俩有很多比方线程隔离、过程隔离、集群隔离、机房隔离等等,这里重点看一下离开发人员更近的线程隔离;

看一个最常见的场景,在微服务架构下,某一条调用链中的某一个服务呈现问题,导致线程阻塞,而后阻塞越积越多,占满所有的 io 线程,最终以后服务无奈承受数据,直至奔溃;这时候线程隔离就起作用了,能够将 io 线程和业务线程离开,这样业务线程呈现问题不至于影响到 io 线程;

一些框架提供了本人的线程模型,比方 Dubbo 的 Dispatcher 调度器能够配置音讯的解决线程,蕴含了多种解决形式:

  • all 所有音讯都派发到线程池,包含申请,响应,连贯事件,断开事件,心跳等。
  • direct 所有音讯都不派发到线程池,全副在 IO 线程上间接执行。
  • message 只有申请响应音讯派发到线程池,其它连贯断开事件,心跳等音讯,间接在 IO 线程上执行。
  • execution 只有申请音讯派发到线程池,不含响应,响应和其它连贯断开事件,心跳等音讯,间接在 IO 线程上执行。
  • connection 在 IO 线程上,将连贯断开事件放入队列,有序一一执行,其它音讯派发到线程池。

当然能够应用第三方工具来实现隔离,比方SentinelHystrix;提供了线程池隔离、信号量隔离;

限流

咱们每个零碎其实都有一个解决峰值,当靠近峰值持续承受申请的时候,会导致整个零碎响应迟缓;为了爱护零碎,须要回绝解决过载的申请,这时候就须要用到限流;常见的限流算法:

  • 令牌桶限流
  • 漏桶限流
  • 计数器限流

个别咱们做限流能够在接入层限流,也能够在业务层做限流,上面简略看一下都有哪些限流工具:

  • 接入层限流:OpenRestynginx 的根底上做了功能扩充,其中有一项就是限流模块,应用 lua-resty-limit-traffic 模块进行限流;
  • 业务层限流:业务层能够做过程内的限流、也能够做分布式限流;过程内限流能够间接应用 guava 来实现,内置了很多限流算法的实现;分布式限流支流应用 Redis+luaOpenResty+lua来实现;

降级

当咱们的零碎呈现拜访量大增,比方遇到大促的状况,如果呈现系统资源不够用的状况下,能够优先把资源给外围性能,对非核心性能能够做降级解决,保障外围性能的可用性,这是一种有损的伎俩;常见的降级伎俩:

  • 自动开关降级:能够通过零碎主动做统计而后做降级解决,比方超时降级、统计失败次数降级等;Sentinel提供了多种主动降级策略,能够通过控制台间接配置;
  • 人工开关降级:给非核心功能模块配置降级开关,比方遇到大促期间,能够手动开启开关实现降级;
  • 读服务降级:对于一些一致性要求不高的场景,读服务可能在每一层都做缓存比方:接入层缓存、应用层本地缓存、分布式缓存、DB/RPC 服务,能够依据理论状况做读降级解决;
  • 写服务降级:写服务做降级解决个别都是做异步化解决,比方将数据写入 MQ,而后接管 MQ 数据再写入数据库;

超时重试

为什么要设置超时工夫,因为如果不设置超时工夫,可能因为某个申请无奈即时响应导致整个链路处于长时间期待状态,这种申请如果过多,间接导致整个零碎瘫痪,抛出超时异样其实也是及时止损;零碎的每一层简直都能够设置超时工夫比方:数据库超时、缓存超时、RPC 超时、网关超时、Web 超时、Httpclient 超时等;所以对于开发人员来说超时工夫的设置至关重要;

重试往往随同着超时一起呈现,因为超时可能是因为某些非凡起因导致暂时性的申请失败,也就是说重试是有可能呈现申请再次胜利的;限度肯定的重试次数(常见设置为 2 次),也是很有必要的;

其余

除了以上几种开发人员比拟关注的高可用伎俩,还有一些其余的伎俩:

  • 回滚机制:当上线新性能时,咱们须要提供部署版本的回滚机制,这样如果生产呈现问题,能够疾速回滚将影响降到最低;数据回滚机制,游戏行业遇到重大问题时,会应用回档解决;代码版本回滚,回滚到上一个稳固的版本;
  • 监控零碎:对系统做全链路监控,保障相干人员能够第一工夫发现零碎问题;
  • 压测预案:电商零碎个别在大促之前会对系统进行全链路压测,并对呈现的问题提供应急预案;
  • 灰度公布:当要上线新性能,首先只是更新大量的服务节点,通过路由权重,让少部分用户体验新版本,如果没有什么问题,再更新所有服务节点;这样能够在呈现问题把影响面降到最低,保障了零碎的可用性;
  • 攻防演练 …

总结

以上介绍了要想实现一个高可用零碎的各种伎俩,但不是说咱们实现一个高可用的零碎,就要把下面的伎俩一股脑的实现一遍;须要依据不同的零碎类型、处在何种阶段、以及不同的零碎模块等进行对应的取舍。

更多

限流浅析

灰度公布浅析

负载平衡浅析

超时与重试浅析

线程隔离浅析

感激关注

能够关注微信公众号「回滚吧代码」,第一工夫浏览,文章继续更新;专一 Java 源码、架构、算法和面试。

退出移动版