hystrix 与高可用系统架构深入分析(一)

一,在框架的使用上,个人觉得应该是在场景上才能理解的,比如为什么手游「赤潮」中进入游戏时加载界面, 显示的头像偶尔是不正确的,这种是不是就是使用了降级机制呢? :::

在各种高并发导致的令人崩溃的异常场景下,还能运行

接下来会花大部分章节讲解怎么保证高可用性:在各种系统的各个地方有乱七八糟的异常和故障的情况下,整套缓存系统还能继续健康的 运行 着

网上会有一些将高可用的知识:HA、HAProxy 组件,主备服务间的切换,这就做到了高可用性, 主备实例,多冗余实例只是高可用最最基础的东西

接下来会讲解在什么样的情况下,可能会导致系统的崩溃?以及系统不可用,针对各种各样的一些情况, 然后我们用什么技术,去保护整个系统处于高可用的一个情况下

 

hystrix 是什么?

hystrix 提供了高可用相关的各种各样的功能,确保在 hystrix 的保护下,整个系统可以长期处于 高可用的状态,如 99.99%;

最理想的状态下,软件故障不应该导致整个系统的崩溃,服务器硬件故障可用通过服务的冗余来保证, 唯一有可能导致系统彻底崩溃,就是类似于机房停电,自然灾害等状况。

在分布式系统中,每个服务都可能会调用很多其他服务,被调用的那些服务就是依赖服务,有的时候某些依赖服务出现故障也是很正常的。

Hystrix 可以让我们在分布式系统中对服务间的调用进行控制,加入一些调用延迟或者依赖故障的容错机制。 Hystrix 通过将依赖服务进行资源隔离,进而阻止某个依赖服务出现故障的时候,这种故障在整个系统所有的依赖服务调用中进行蔓延, 同时 Hystrix 还提供故障时的 fallback 降级机制

总而言之,Hystrix 通过这些方法帮助我们提升分布式系统的可用性和稳定性

不可用和产生的一些故障或者 bug 的区别:

  • 不可用:

    是完全不可用,整个系统完全崩溃

  • 部分故障或 bug:

    只是一小部分服务出问题

初步看一看 Hystrix 的设计原则是什么?

hystrix 为了实现高可用性的架构,设计 hystrix 的时候,一些设计原则是什么?

  1. 对依赖服务调用时出现的调用延迟和调用失败进行控制和容错保护

  2. 在复杂的分布式系统中,阻止某一个依赖服务的故障在整个系统中蔓延

    服务 A - 服务 B -> 服务 C,服务 C 故障了,服务 B 也故障了,服务 A 故障了,整套分布式系统全部故障,整体宕机

  3. 提供 fail-fast(快速失败)和快速恢复的支持

  4. 提供 fallback 优雅降级的支持

  5. 支持近实时的监控、报警以及运维操作

关键词总结:

  • 调用延迟 + 失败,提供容错

  • 阻止故障蔓延

  • 快速失败 + 快速恢复

  • 降级

  • 监控 + 报警 + 运维

这里不是完全描述了 hystrix 的功能,简单来说是按照这些原则来设计 hystrix ,提供整个分布式系统的高可用的架构

 

Hystrix 要解决的问题是什么?

在复杂的分布式系统架构中,每个服务都有很多的依赖服务,而每个依赖服务都可能会故障, 如果服务没有和自己的依赖服务进行隔离,那么可能某一个依赖服务的故障就会拖垮当前这个服务

举例来说:某个服务有 30 个依赖服务,每个依赖服务的可用性非常高,已经达到了 99.99% 的高可用性

那么该服务的可用性就是 99.99% - (100% - 99.99% * 30 = 0.3%)= 99.69%, 意味着 3% 的请求可能会失败,因为 3% 的时间内系统可能出现了故障不可用了

对于 1 亿次访问来说,3% 的请求失败也就意味着 300万 次请求会失败,也意味着每个月有 2个 小时的时间系统是不可用的, 在真实生产环境中,可能更加糟糕

上面的描述想表达的意思是:即使你每个依赖服务都是 99.99% 高可用性,但是一旦你有几十个依赖服务, 还是会导致你每个月都有几个小时是不可用的

下面画图分析说,当某一个依赖服务出现了调用延迟或者调用失败时,为什么会拖垮当前这个服务? 以及在分布式系统中,故障是如何快速蔓延的?

简而言之:

  1. 假设只有系统承受并发能力是 100 个线程,

  2. C 出问题的时候,耗时增加,将导致当前进入的 40 个线程得不到释放

  3. 后续大量的请求涌进来,也是先调用 c,然后又在这里了

  4. 最后 100 个线程都被卡在 c 了,资源耗尽,导致整个服务不能提供服务

  5. 那么其他依赖的服务也会出现上述问题,导致整个系统全盘崩溃

当时这个只能是在 高并发高流量的场景下会出现这种情况,其实我工作中也遇到过一次真实的案例, quartz 默认线程只有 25 个,当时定时任务接近 150 个左右,平时每个定时任务触发时间基本上上分散的, 而且基本上在 10 分钟左右会结束任务,当我们调用其他第三方服务时,没有加超时功能, 第三方服务可能出问题了,导致我们的请求被卡主,进而导致任务线程不能结束,最后整个任务调度系统完全崩溃, 完全不能提供服务。

这个场景在我所工作生涯中可能是记忆最深的一次了,因为当时在线上,根据日志打印完全看不出来问题, 就像系统假死一样,后来通过 jconsole 查看线程挂起情况,发现所有线程调用第三方服务后都被卡主了。 才顺藤摸瓜找到 quartz 的默认线程只有 25 个。最后加大了线程,也只是治标不治本,长时间运行还是会出问题

再看 hystrix 的更加细节的设计原则是什么?

  1. 阻止任何一个依赖服务耗尽所有的资源,比如 tomcat 中的所有线程资源

  2. 避免请求排队和积压,采用限流和 fail fast 来控制故障

  3. 提供 fallback 降级机制来应对故障

  4. 使用资源隔离技术

    隔离技术是为了实现第一条的功能

    比如 bulkhead(舱壁隔离技术),swimlane(泳道技术),circuit breaker(短路技术), 来限制任何一个依赖服务的故障的影响

  5. 通过近实时的统计/监控/报警功能,来提高故障发现的速度

  6. 通过近实时的属性和配置热修改功能,来提高故障处理和恢复的速度

  7. 保护依赖服务调用的所有故障情况,而不仅仅只是网络故障情况

    调用这个依赖服务的时候,client 调用包有 bug、阻塞,等等

    依赖服务的各种各样的 调用的故障,都可以处理

Hystrix 是如何实现它的目标的?

  1. 通过 HystrixCommand 或者 HystrixObservableCommand 来封装对外部依赖的访问请求 d 这个访问请求一般会运行在独立的线程中,资源隔离

  2. 对于超出我们设定阈值的服务调用,直接进行超时,不允许其耗费过长时间阻塞住。

    这个超时时间默认是 99.5% 的访问时间,但是一般我们可以自己设置一下

  3. 为每一个依赖服务维护一个独立的线程池,或者是 semaphore(信号量),当线程池已满时,直接拒绝对这个服务的调用

  4. 对依赖服务的调用的成功次数、失败次数、拒绝次数、超时次数,进行统计

  5. 如果对一个依赖服务的调用失败次数超过了一定的阈值,自动进行熔断

    在一定时间内对该服务的调用直接降级,一段时间后再自动尝试恢复

  6. 当一个服务调用出现失败、被拒绝、超时、短路(熔断)等异常情况时,自动调用 fallback 降级机制

  7. 对属性和配置的修改提供近实时的支持

 

疑问:上图只是站在全局角度来看的?并非自己所想,当一个依赖故障的时候,怎么搞也拿不到正确数据了?关注点关注错了?意思是说,及时这个一个小功能点不能用了,但是该系统其它的功能点能正常使用。并且不会因为这个故障导致整个系统崩溃?

 

 

 

高可用系统架构

资源隔离、限流、熔断、降级、运维监控 而这些也是 hystrix 提供的功能

  • 资源隔离:让某一刻东西在故障的情况下,不会耗尽系统所有资源,如线程资源

    一个真实的遭遇,线上某块代码 bug,导致大量线程死循环,又创建大量线程, 最后系统资源被耗尽。崩溃

    资源隔离的话,比如限制只能使用 10 个线程,那么这一块出问题,也不会影响整个系统

  • 限流

    高并发流量涌入,比如突然间一秒钟 100 完 QPS,系统完全承受不住,直接崩溃。 限流可以只对 10 万 QPS 进行服务,其他的都拒绝。这种情况下就是在你双 11 抢东西付款 的时候,老是告诉你系统繁忙的情况,但是偶尔又可以刷出来

  • 熔断:连续故障,则在一段时间内直接拒绝服务

    我自己最近遇到的就是 zuul 中的路由转发,当某一个服务连续转发失败(如那个服务根本没有启动), 则在一分钟内直接返回异常信息,而不是继续转发,继续等待异常

  • 降级:

    如 mysql 挂了,系统发现了,自动降级,从内存里存的少量数据中,去提取一些数据出来。 疑问:这样的数据在什么场景下使用使用呢?

  • 运维监控:

    监控 + 报警 + 优化,各种异常的情况,有问题就及时报警,然后对症下药

如何深入理解并运用这块内容?

比如首页面数据缓存,在各级缓存数据都失效的情况下,会重新从源系统中调用接口,依赖源系统去查询 mysql 数据库去重新获取数据, 如果你的各种依赖的服务有了故障,那么很可能会导致你的系统不可用

怎么使用 hystrix 对系统进行各种高可用性的系统加固,来应对各种不可用的情况;

所以会写代码,hystrix 做服务高可用这一块的内容, 比如基于商品详情页缓存架构这个业务背景,重新写代码,这样的话相对来说就比较独立,这章节就是高可用架构

简而言之,系统在 hystrix 的保护下,不会完全崩溃,就算所有依赖都失效了,那么也还能提供一些最最基础的简单服务;

上面的介绍很多地方现在以我本人的知识储备是完全想不到在什么场景下还能提供简单服务?是什么效果?这吸引力还是很大的

redis 挂掉,放在缓存雪崩那一章节讲解,雪崩,redis 必然挂,mysql 有较大概率挂掉

之前一个真实的项目,我们多个项目都用了公司里公用的缓存的存储,缓存彻底挂了、雪崩了, 导致各种业务系统全部崩溃,崩溃了好几个小时。

  1. 亿级流量的电商网站的商品详情页系统架构

  2. 大型的缓存架构,支撑高并发与高可用

  3. 几十万 QPS 的高并发 + 99.99% 高可用 + 1T 以上的海量数据 + 绝对数据安全的 redis 集群架构

  4. 高并发场景下的数据库 + 缓存双写一致性保障方案

  5. 大缓存的维度化拆分方案

  6. 基于双层 nginx 部署架构的缓存命中率提升方案

  7. 基于 kafka + spring boot + ehcache + redis + nginx + lua 的多级缓存架构

  8. 基于 zookeeper 的缓存并发更新安全保障方案

  9. 基于 storm + zookeeper 的大规模缓存预热解决方案

  10. 基于 storm + zookeeper + nginx + lua 的热点缓存自动降级与恢复解决方案

  11. 基于 hystrix 的高可用缓存服务架构

  12. hystrix 的进阶高可用架构方案、架构性能优化以及监控运维

  13. 基于 hystrix 的大规模缓存雪崩解决方案

  14. 高并发场景下的缓存穿透解决方案

  15. 高并发场景下的缓存失效解决方案

电商网站的商品详情页系统架构

 

 

小型电商网站的商品详情页系统架构(不是我们要讲解的)

大型电商网站的商品详情页系统架构

 

缓存服务

缓存服务,订阅一个 MQ (后转为rabbitMQ)的消息变更,如果有消息变更的话,那么就会发送一个网络请求,调用一个底层的对应的源数据服务的接口,去获取变更后的数据

将获取到的变更后的数据填充到分布式的 redis 缓存中去

高可用这一块儿,最可能出现说可用性不高的情况,是什么呢?就是说,在接收到消息之后,可能在调用各种底层依赖服务的接口时,会遇到各种不稳定的情况

比如底层服务的接口调用超时,预计 200ms 内返回,但是 2s 都没有返回; 底层服务的接口调用失败,比如说卡了 500ms 之后,返回一个报错

在分布式系统中,对于这种大量的底层依赖服务的调用,就可能会出现各种可用性的问题,一旦没有处理好的话,可能就会导致缓存服务自己本身会挂掉,或者故障掉,就会导致什么呢?不可以对外提供服务,严重情况下,甚至会导致说整个商品详情页显示不出来

hystrix 的主题是:缓存服务接收到变更消息后,去调用各个底层依赖服务时的高可用架构的实现

框架结构

围绕着缓存服务去拉取各种底层的源数据服务的数据,调用其接口时,可能出现的系统不可用的问题

在框架上一切从简:动手搭建 2 个 spring boot 服务,缓存服务和商品服务,缓存服务依赖于商品服务

模拟各种商品服务可能接口调用时出现的各种问题,导致系统不可用的场景,然后用 hystrix 完整的各种技术点全部贯穿在里面,解决了一大堆设计业务背景下的系统不可用问题,hystrix 整个技术体系,知识体系,也就讲解完了

消息队列、redis 咱们都不搞了,只关注这个 hystrix 的场景

简化的分布式系统的架构:spring boot + http client + hystrix

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值