转:https://segmentfault.com/a/1190000005988895

# 1.服务雪崩介绍
## 1.1基本概念
分布式系统中经常会出现某个基础服务不可用造成整个系统不可用的情况, 这种现象被称为服务雪崩效应. 为了应对服务雪崩, 一种常见的做法是手动服务降级.

**服务雪崩效应**:是一种因“服务提供者的不可用”(原因)导致“服务调用者不可用”(结果),并将不可用逐渐放大的现象。如下图所示:
      

上图中, A为服务提供者, B为A的服务调用者, C和D是B的服务调用者. 当A的不可用,引起B的不可用,并将不可用逐渐放大C和D时, 服务雪崩就形成了。

## 1.2服务雪崩的过程可以分为三个阶段:
    1.服务提供者不可用;
    2.重试加大请求流量;
    3.服务调用者不可用;

## 1.3服务雪崩每个阶段的原因
###    1.3.1服务不可用的原因

    1.硬件故障
    2.程序Bug
    3.缓存击穿
    4.用户大量请求

**硬件故障**可能为硬件损坏造成的服务器主机宕机, 网络硬件故障造成的服务提供者的不可访问.
**缓存击穿**一般发生在缓存应用重启, 所有缓存被清空时,以及短时间内大量缓存失效时. 大量的缓存不命中, 使请求直击后端,造成服务提供者超负荷运行,引起服务不可用.
在秒杀和大促开始前,如果准备不充分,用户发起大量请求也会造成服务提供者的不可用.
**大量请求** :

    1.用户重试
    2.代码逻辑重试

###    1.3.2重试加大请求量
**用户重试**尝试在服务提供者不可用后, 用户由于忍受不了界面上长时间的等待,而不断刷新页面甚至提交表单.
**代码逻辑重试**:服务调用端会存在大量服务异常后的重试逻辑.
这些重试都会进一步加大请求流量.

###    1.3.3服务调用者不可用原因
当服务调用者使用 同步调用 时, 会产生大量的等待线程占用系统资源. 一旦线程资源被耗尽,服务调用者提供的服务也将处于不可用状态, 于是服务雪崩效应产生了.

## 1.4服务雪崩的应对策略

针对造成服务雪崩的不同原因, 可以使用不同的应对策略:

    1.流量控制
    2.改进缓存模式
    3.服务自动扩容
    4.服务调用者降级服务

### 1.4.1**流量控制** 的具体措施
    1.网关限流
    2.用户交互限流
    3.关闭重试

**网关限流**:因为Nginx的高性能, 目前一线互联网公司大量采用Nginx+Lua的网关进行流量控制, 由此而来的OpenResty也越来越热门.

**用户交互限流**:

    1. 采用加载动画,提高用户的忍耐等待时间.
    2. 提交按钮添加强制等待时间机制.

### 1.4.2改进缓存模式

    缓存预加载
    同步改为异步刷新

### 1.4.3服务自动扩容
    AWS的auto scaling

### 1.4.4服务调用者降级服务:
    资源隔离
    对依赖服务进行分类
    不可用服务的调用快速失败

**资源隔离**:主要是对调用服务的线程池进行隔离.
**分类**:我们根据具体业务,将依赖服务分为: 强依赖和若依赖. 强依赖服务不可用会导致当前业务中止,而弱依赖服务的不可用不会导致当前业务的中止.
**不可用服务的调用快速失败**:一般通过超时机制, 熔断器 和熔断后的 降级方法来实现.

# 2.Hystrix(已停更)
    github:https://github.com/Netflix/Hystrix
## 2.1基本概念
Hystrix [hɪst'rɪks]的中文含义是豪猪, 因其背上长满了刺,而拥有自我保护能力. Netflix的 Hystrix 是一个帮助解决分布式系统交互时超时处理和容错的类库, 它同样拥有保护系统的能力。
在某个服务单元发生故障之后,通过断路器的监控,向调用方返回一个可处理的响应,而不是长时间的等待或者抛出无法处理的异常。保证服务调用不会被长时间、不必要的占用,从而避免服务雪崩
## 2.2几个概念

**服务降级**: 当服务请求响应时间太长,或者响应出错的额时候,服务调用端不应该一直等在这里,需要直接返回相应的处理,释放资源。比如一些不重要的服务(如获取评价),可以设置返回时间不要超过1秒,超过了就直接返回一个预设的结果,使得这个接口的调用不用占用太多的额资源

**服务熔断**:类似保险丝。一个服务接口,在一段时间内,请求数达到一定的数量,且失败率达到阀值,此时服务被熔断:断路器打开-服务降级(断路器打开期间该接口所有请求都调用的是服务降级fallback方法)-等一段时间后,尝试才放一个请求进来正常执行-调用成功则断路器关闭,恢复正常,否则继续等待再次尝试

**服务限流**:限流的目的是为了保护系统不被大量请求冲垮,通过限制请求的速度来保护系统。秒杀高并发等操作,严禁一窝蜂的过来拥挤,大家排队,一秒钟N个,有序进行

## 2.3Hystrix的设计原则包括:
    1.资源隔离
    2.熔断器
    3.命令模式
### 2.3.1 资源隔离

货船为了进行防止漏水和火灾的扩散,会将货仓分隔为多个

这种资源隔离减少风险的方式被称为:Bulkheads(舱壁隔离模式).
Hystrix将同样的模式运用到了服务调用者上.
在一个高度服务化的系统中,我们实现的一个业务逻辑通常会依赖多个服务,比如:商品详情展示服务会依赖商品服务, 价格服务, 商品评论服务.

调用三个依赖服务会共享商品详情服务的线程池. 如果其中的商品评论服务不可用, 就会出现线程池里所有线程都因等待响应而被阻塞, 从而造成服务雪崩

Hystrix通过将每个依赖服务分配独立的线程池进行资源隔离, 从而避免服务雪崩.
如下图所示, 当商品评论服务不可用时, 即使商品评论服务独立分配的20个线程全部处于同步等待状态,也不会影响其他依赖服务的调用.

###   2.3.2 熔断器模式

熔断器模式定义了熔断器开关相互转换的逻辑

服务的健康状况 = 请求失败数 / 请求总数.
熔断器开关由关闭到打开的状态转换是通过当前服务健康状况和设定阈值比较决定的.
    当熔断器开关关闭时, 请求被允许通过熔断器. 如果当前健康状况高于设定阈值, 开关继续保持关闭. 如果当前健康状况低于设定阈值, 开关则切换为打开状态.
    当熔断器开关打开时, 请求被禁止通过.
    当熔断器开关处于打开状态, 经过一段时间后, 熔断器会自动进入半开状态, 这时熔断器只允许一个请求通过. 当该请求调用成功时, 熔断器恢复到关闭状态. 若该请求失败, 熔断器继续保持打开状态, 接下来的请求被禁止通过.
熔断器的开关能保证服务调用者在调用异常服务时, 快速返回结果, 避免大量的同步等待. 并且熔断器能在一段时间后继续侦测请求执行结果, 提供恢复服务调用的可能.

### 2.3.3命令模式

Hystrix使用命令模式(继承HystrixCommand类)来包裹具体的服务调用逻辑(run方法), 并在命令模式中添加了服务调用失败后的降级逻辑(getFallback).
同时我们在Command的构造方法中可以定义当前服务线程池和熔断器的相关参数

public class Service1HystrixCommand extends HystrixCommand<Response> {
private Service1 service;
private Request request; public Service1HystrixCommand(Service1 service, Request request){
supper(
Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("ServiceGroup"))
.andCommandKey(HystrixCommandKey.Factory.asKey("servcie1query"))
.andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey("service1ThreadPool"))
.andThreadPoolPropertiesDefaults(HystrixThreadPoolProperties.Setter()
.withCoreSize(20))//服务线程池数量
.andCommandPropertiesDefaults(HystrixCommandProperties.Setter()
.withCircuitBreakerErrorThresholdPercentage(60)//熔断器关闭到打开阈值
.withCircuitBreakerSleepWindowInMilliseconds(3000)//熔断器打开到关闭的时间窗长度
))
this.service = service;
this.request = request;
);
} @Override
protected Response run(){
return service1.call(request);
} @Override
protected Response getFallback(){
return Response.dummy();
}
}

在使用了Command模式构建了服务对象之后, 服务便拥有了熔断器和线程池的功能

Hystrix的内部处理逻辑

下图为Hystrix服务调用的内部逻辑:

1.构建Hystrix的Command对象, 调用执行方法.

2.Hystrix检查当前服务的熔断器开关是否开启, 若开启, 则执行降级服务getFallback方法.

3.若熔断器开关关闭, 则Hystrix检查当前服务的线程池是否能接收新的请求, 若超过线程池已满, 则执行降级服务getFallback方法.

4.若线程池接受请求, 则Hystrix开始执行服务调用具体逻辑run方法.

5.若服务执行失败, 则执行降级服务getFallback方法, 并将执行结果上报Metrics更新服务健康状况.

6.若服务执行超时, 则执行降级服务getFallback方法, 并将执行结果上报Metrics更新服务健康状况.

7.若服务执行成功, 返回正常结果.

8.若服务降级方法getFallback执行成功, 则返回降级结果.

9.若服务降级方法getFallback执行失败, 则抛出异常

### 2.3.4 Hystrix Metrics的实现

Hystrix的Metrics中保存了当前服务的健康状况, 包括服务调用总次数和服务调用失败次数等. 根据Metrics的计数, 熔断器从而能计算出当前服务的调用失败率, 用来和设定的阈值比较从而决定熔断器的状态切换逻辑. 因此Metrics的实现非常重要.
Hystrix1.4之前的滑动窗口实现
Hystrix在这些版本中的使用自己定义的滑动窗口数据结构来记录当前时间窗的各种事件(成功,失败,超时,线程池拒绝等)的计数.
事件产生时, 数据结构根据当前时间确定使用旧桶还是创建新桶来计数, 并在桶中对计数器进行修改.
这些修改是多线程并发执行的, 代码中有不少加锁操作,逻辑较为复杂.

1.5之后的滑动窗口实现

Hystrix在这些版本中开始使用RxJava的Observable.window()实现滑动窗口.
RxJava使用后台线程创建新桶, 避免了并发创建桶的问题.
同时RxJava的单线程无锁特性也保证了计数变更时的线程安全. 从而使代码更加简洁.
以下为我使用RxJava的window方法实现的一个简易滑动窗口Metrics, 短短几行代码便能完成统计功能,足以证明RxJava的强大:

@Test
public void timeWindowTest() throws Exception{
Observable<Integer> source = Observable.interval(50, TimeUnit.MILLISECONDS).map(i -> RandomUtils.nextInt(2));
source.window(1, TimeUnit.SECONDS).subscribe(window -> {
int[] metrics = new int[2];
window.subscribe(i -> metrics[i]++,
InternalObservableUtils.ERROR_NOT_IMPLEMENTED,
() -> System.out.println("窗口Metrics:" + JSON.toJSONString(metrics)));
});
TimeUnit.SECONDS.sleep(3);
}

spring-cloud06---Hystrix01简介的更多相关文章

  1. Spring Web Flow 简介

    Spring Web Flow 简介 博客分类: 转载 SSH 最近在TSS上看到了一片介绍Spring Web Flow的文章,顺便就翻译了下来,SWF的正式版估计要到6月份才能看到了,目前的例子都 ...

  2. Spring中AOP简介与切面编程的使用

    Spring中AOP简介与使用 什么是AOP? Aspect Oriented Programming(AOP),多译作 "面向切面编程",也就是说,对一段程序,从侧面插入,进行操 ...

  3. Unit03: Spring Web MVC简介 、 基于XML配置的MVC应用 、 基于注解配置的MVC应用

    Unit03: Spring Web MVC简介 . 基于XML配置的MVC应用 . 基于注解配置的MVC应用 springmvc (1)springmvc是什么? 是一个mvc框架,用来简化基于mv ...

  4. spring 拦截器简介

    spring 拦截器简介 常见应用场景 1.日志记录:记录请求信息的日志,以便进行信息监控.信息统计.计算PV(Page View)等.2.权限检查:如登录检测,进入处理器检测检测是否登录,如果没有直 ...

  5. Spring HTTP invoker简介

    Spring HTTP invoker简介 Spring HTTP invoker是spring框架中的一个远程调用模型,执行基于HTTP的远程调用(意味着可以通过防火墙),并使用java的序列化机制 ...

  6. Spring Boot 之Spring data JPA简介

    文章目录 添加依赖 添加entity bean 创建 Dao Spring Data Configuration 测试 Spring Boot 之Spring data JPA简介 JPA的全称是Ja ...

  7. Spring MVC+FreeMarker简介

    最近做项目,刚接触到SpringMVC与FreeMarker框架,就简单介绍一下自己的理解,不正确的地方请大家指教!! 1.Spring MVC工作原理: 用户发送请求--->前端服务器去找相对 ...

  8. Spring Data Redis简介以及项目Demo,RedisTemplate和 Serializer详解

    一.概念简介: Redis: Redis是一款开源的Key-Value数据库,运行在内存中,由ANSI C编写,详细的信息在Redis官网上面有,因为我自己通过google等各种渠道去学习Redis, ...

  9. Spring - Web MVC简介

    Web MVC简介 1.1.Web开发中的请求-响应模型: 在Web世界里,具体步骤如下: 1.  Web浏览器(如IE)发起请求,如访问http://www.cnblogs.com 2.  Web服 ...

  10. Spring.net(一)----Spring.NET框架简介及模块说明

    简介:    Spring.NET框架包括很多功能,Spring.NET 1.0包括完整的IoC容器和AOP类库.1.1版加入Web.ORM和数据模块.Spring.NET的下载包中并不包含与其它类库 ...

随机推荐

  1. EventBridge助力阿里云视觉智能开放平台AI智能存储实践

    本文作者:李建,阿里巴巴达摩院技术专家. 01 视觉智能开放平台(VIAPI)业务场景介绍 阿里云视觉智能开放平台(简称 VIAPI),是基于之前很多技术实践经验积累的 AI 能力的沉淀平台.目前整个 ...

  2. 浅谈HTTP缓存与CDN缓存的那点事

    HTTP缓存与CDN缓存一直是提升web性能的两大利器,合理的缓存配置可以降低带宽成本.减轻服务器压力.提升用户的体验.而不合理的缓存配置会导致资源界面无法及时更新,从而引发一系列的衍生问题.本文将分 ...

  3. Android开发之应用更新或软件下载

    Android开发之应用更新或软件下载 本文章学习前提:okHttp3或以上,EventBus或其它事件总线工具,四大组件的Activity和Service,安卓通知基础知识 新建项目文件 目录结构如 ...

  4. 【Java并发001】使用级别:线程相关知识

    一.前言 本文介绍Java线程相关知识(不包括线程同步+线程通信,这个内容在笔者的另一篇博客中介绍过了),包括:线程生命周期.线程优先级.线程礼让.后台线程.联合线程. 二.线程生命周期 2.1 引子 ...

  5. 图文详解在VMware Workstation 16 PRO虚拟机上安装Rocky 8.6 linux系统

    一.安装VMware Workstation虚拟机 下载VMware Workstation 16 PRO虚拟机 https://www.vmware.com/cn/products/workstat ...

  6. fbterm的配置,纯文本终端显示中文

    安装 fbterm sudo apt-get install fbterm 设置普通用户可以执行 fbterm 命令 sudo adduser username video #username为用户名 ...

  7. Zabbix技术分享——使用docker-compose快速部署zabbix监控系统

    前面文章有提到过使用docker来快速拉起一个zabbix监控系统(详见:如何使用docker快速部署一个zabbix监控系统),但是要一个个执行docker启动命令去将对应的容器启动.如果要配置参数 ...

  8. js day04 综合案例秒数计算

    <script>         //用户输入总秒数         let second = +prompt('请输入总秒数:')         //计算时分秒         fun ...

  9. 【每日一题】【排序sort重载】【工具类】2021年12月23日-31. 下一个排列

    实现获取 下一个排列 的函数,算法需要将给定数字序列重新排列成字典序中下一个更大的排列(即,组合出下一个更大的整数). 如果不存在下一个更大的排列,则将数字重新排列成最小的排列(即升序排列). 必须 ...

  10. Day34.2:Calendar详解

    Calendar 1.1 概述 Date类中很多方法被Calendar所取代,Calendar类提供了获取和设置各种日历的方法. 1.2 方法 构造方法:Calendar类的构造器被protected ...