Java面试突击(8):Hystrix

x33g5p2x  于2021-10-14 转载在 Java  
字(10.3k)|赞(0)|评价(0)|浏览(332)

写在前面

限流降级熔断。1、如何设计一个高可用系统。2、限流。2.1、如何限流?在工作中怎么做的?具体实现?3、降级。3.1、如何进行降级。4、熔断。4.1、如何进行熔断?熔断框架有哪些?实现原理?使用hystrix实现一套高可用保障机制,基于hystrix做降级限流熔断。

1、前半部分

专注在高并发这一块,缓存架构,承载高并发,在各种高并发导致的令人崩溃/异常的场景下,运行着。缓存架构,高可用性,在各种系统的各个地方有乱七八糟的异常和故障的情况下,整套缓存系统还能继续健康的run着。HA,HAProxy,主备服务间的切换,这就做到了高可用性,主备实例,多冗余实例,高可用最最基础的东西。什么样的情况下,可能会导致系统的崩溃,以及系统不可用,针对各种各样的一些情况,然后我们用什么技术,去保护整个系统处于高可用的一个情况下

2、hystrix是什么?

netflix(国外最大的类似于,爱奇艺,优酷)视频网站,五六年前,也是,感觉自己的系统,整个网站,经常出故障,可用性不太高。有时候一些vip会员不能支付,有时候看视频就卡顿,看不了视频。影响公司的收入。

五六年前,netflix,api team,提升高可用性,开发了一个框架,类似于spring,mybatis,hibernate,等等这种框架。高可用性的框架,hystrix。

hystrix,框架,提供了高可用相关的各种各样的功能,然后确保说在hystrix的保护下,整个系统可以长期处于高可用的状态,100%,99.99999%。最理想的状况下,软件的故障,就不应该说导致整个系统的崩溃,服务器硬件的一些故障,服务的冗余。唯一有可能导致系统彻底崩溃,就是类似于之前,支付宝的那个事故,工人施工,挖断了电缆,导致几个机房都停电。不可用,和产生一些故障或者bug的区别。

3、高可用系统架构

3.1、资源隔离、限流、熔断、降级、运维监控。

**资源隔离:**让你的系统里,某一块东西,在故障的情况下,不会耗尽系统所有的资源,比如线程资源。我实际的项目中的一个case,有一块东西,是要用多线程做一些事情,小伙伴做项目的时候,没有太留神,资源隔离,那块代码,在遇到一些故障的情况下,每个线程在跑的时候,因为那个bug,直接就死循环了,导致那块东西启动了大量的线程,每个线程都死循环。最终导致我的系统资源耗尽,崩溃,不工作,不可用,废掉了。

1、资源隔离:****那一块代码最多就是用掉10个线程,不能再多了就废掉了,限定好的一些资源

**2、限流:**高并发的流量涌入进来,比如说突然间一秒钟100万QPS,废掉了,10万QPS进入系统,其他90万QPS被拒绝了。

**3、熔断:**系统后端的一些依赖,出了一些故障,比如说mysql挂掉了,每次请求都是报错的,熔断了,后续的请求过来直接不接收了,拒绝访问,10分钟之后再尝试去看看mysql恢复没有。

**4、降级:**mysql挂了,系统发现了自动降级,从内存里存的少量数据中,去提取一些数据出来。

**5、运维监控:**监控+报警+优化,各种异常的情况,有问题就及时报警,优化一些系统的配置和参数,或者代码。

3.2、如何讲解这块内容?

(1)如何将eshop-cache,核心的缓存服务改造成高可用的架构。

(2)hystrix中的一部分内容,单拉出来,做成一个免费的小课程,作为福利发放出去。

(3)eshop-cache,写代码,eshop-cache-ha,业务场景,跟之前衔接起来,重新去写代码。

(4)hystrix做服务高可用这一块的内容,讲解成只有一个业务背景,重新写代码,独立。

eshop-cache,在各级缓存数据都失效的情况下,会重新从源系统中调用接口,依赖源系统去查询mysql数据库去重新获取数据。

如果你的各种依赖的服务有了故障,那么很可能会导致你的系统不可用。hystrix对系统进行各种高可用性的系统加固,来应对各种不可用的情况。缓存雪崩那一块去讲解,redis肯定挂,mysql有较大概率挂掉,在风雨飘摇中

我之前做的一个项目,我们多个项目都用了公司里公用的缓存的存储,缓存彻底挂了,雪崩了,导致各种业务系统全部崩溃,崩溃了好几个小时,导致公司损失了大量的资金的损失。其中导致公司损失最大的负责人,受到了很大的处分。

高可用性这个topic,然后咱们会用几讲的时间来讲解一下如何用hystrix,来构建高可用的服务的架构

咱们会用一个真实的项目背景,作为业务场景,来带出来在这个特定的业务场景下,可能会产生哪些各种各样的可用性的一些问题。针对这些问题,我们用hystrix的解决方案和原理是什么。带着大家,纯手工将所有的服务的高可用架构的代码,全部纯手工自己敲出来。形成高可用服务架构的项目实战的一个课程

4、Hystrix是什么?

4.1、高可用保障

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

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

4.2、Hystrix的历史

hystrix,就是一种高可用保障的一个框架,类似于spring(ioc,mvc),mybatis,activity,lucene,框架,预先封装好的为了解决某个特定领域的特定问题的一套代码库。框架,用了框架之后,来解决这个领域的特定的问题,就可以大大减少我们的工作量,提升我们的工作质量和工作效率,框架。hystrix,高可用性保障的一个框架。

Netflix(可以认为是国外的优酷或者爱奇艺之类的视频网站),API团队从2011年开始做一些提升系统可用性和稳定性的工作,Hystrix就是从那时候开始发展出来的。在2012年的时候,Hystrix就变得比较成熟和稳定了,Netflix中,除了API团队以外,很多其他的团队都开始使用Hystrix。时至今日,Netflix中每天都有数十亿次的服务间调用,通过Hystrix框架在进行,而Hystrix也帮助Netflix网站提升了整体的可用性和稳定性

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

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

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

(2)在复杂的分布式系统中,阻止某一个依赖服务的故障在整个系统中蔓延,服务A->服务B->服务C,服务C故障了,服务B也故障了,服务A故障了,整套分布式系统全部故障,整体宕机。

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

(4)提供fallback优雅降级的支持。

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

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

阻止故障蔓延

快速失败+快速恢复

降级

监控+报警+运维

完全描述了hystrix的功能,提供整个分布式系统的高可用的架构。

4.4、Hystrix要解决的问题是什么?

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

举例,某个服务有30个依赖服务,每个依赖服务的可用性非常高,达到了99.99%的高可用性。那么该服务的可用性就是99.99%的30次方,也就是99.7%的可用性。99.7%的可用性就意味着3%的请求可能会失败,因为3%的时间内系统可能出现了故障不可用了。对于1亿次访问来说,3%的请求失败,也就意味着300万次请求会失败,也意味着每个月有2个小时的时间系统是不可用的。在真实生产环境中,可能更加糟糕。

上面也就是说,即使你每个依赖服务都是99.99%高可用性,但是一旦你有几十个依赖服务,还是会导致你每个月都有几个小时是不可用的。

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

4.5、再看Hystrix的更加细节的设计原则是什么?

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

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

(3)提供fallback降级机制来应对故障。

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

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

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

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

调用这个依赖服务时,client调用包有bug,阻塞等,依赖服务的各种调用的故障都可处理,

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

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

(2)对于超出我们设定阈值的服务调用,直接进行超时,不允许其耗费过长时间阻塞住。这个超时时间默认是99.5%的访问时间,但是一般我们可以自己设置一下。

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

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

(5)如果对一个依赖服务的调用失败次数超过了一定的阈值,自动进行熔断,在一定时间内对该服务的调用直接降级,一段时间后再自动尝试恢复。

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

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

画图分析,对依赖进行资源隔离后,如何避免依赖服务调用延迟或失败导致当前服务的故障。


资源隔离是将所有资源100线程,分为40服务C,30个服务D,30个服务E。

5、基于hystrix,如何来构建高可用的分布式系统的架构

模拟真实业务的这么一个小型的项目,来全程贯穿,用这个项目中的业务场景去一个一个的讲解hystrix高可用的每个技术。

大背景:电商网站,首页,商品详情页,搜索结果页,广告页,促销活动,购物车,订单系统,库存系统,物流系统。

小背景:商品详情页,如何用最快的结果将商品数据填充到一个页面中,然后将页面显示出来。

分布式系统:商品详情页,缓存服务,+底层源数据服务,商品信息服务,店铺信息服务,广告信息服务,推荐信息服务,综合起来组成一个分布式的系统。

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

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

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

(3)页面模板

举个例子:将数据动态填充/渲染到一个html模板中,是什么意思呢?

<html>
    <title>#{name}的页面</title>
<body>
    商品的价格是:#{price}
    商品的介绍:#{description}
</body>
</html>

上面这个就可以认为是一个页面模板,里面的很多内容是不确定的,/#{name},/#{price},/#{description},这都是一些模板脚本,不确定里面的值是什么?

将数据填充/渲染到html模板中,是什么意思呢?

{
"name": "iphone7 plus(玫瑰金+32G)",
"price": 5599.50
"description": "这个手机特别好用。。。。。。"
}

<html>
    <title>iphone7 plus(玫瑰金+32G)的页面</title>
<body>
    商品的价格是:5599.50
    商品的介绍:这个手机特别好用。。。。。。
</body>
</html>

上面这个就是一份填充好数据的一个html页面。

2、缓存服务

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

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

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

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

在分布式系统中,对于这种大量的底层依赖服务的调用,就可能会出现各种可用性的问题,一旦没有处理好的话。

可能就会导致缓存服务自己本身会挂掉,或者故障掉,就会导致什么呢?不可以对外提供服务,严重情况下,甚至会导致说整个商品详情页显示不出来。

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

我们刚才讲解的整套大型电商网站的商品详情页的缓存架构,完整的那个流程,《亿级流量电商详情页系统的大型高并发与高可用缓存架构实战》

3、框架结构

围绕着缓存服务去拉取各种底层的源数据服务的数据,调用其接口时,可能出现的系统不可用的问题。spring boot,微服务的非常快速,非常好用的技术框架,脱胎于spring,具体的东西就不讲解,直接带着大家上手搭建一个spring boot的框架。2个服务,缓存服务,商品服务,缓存服务依赖于商品服务。模拟各种商品服务可能接口调用时出现的各种问题,导致系统不可用的场景,然后用hystrix完整的各种技术点全部贯穿在里面。解决了一大堆设计业务背景下的系统不可用问题,hystrix整个技术体系,知识体系,也就讲解完了。消息队列,redis,咱们都不搞了

分布式系统,微服务,dubbo,不用dubbo,目前比较明显的一个趋势是,行业里,未来主要还是spring boot,spring cloud,主流的开源技术,去构建微服务的分布式系统

基于dubbo,官方很久之前就停止更新了,支持也不是太好

spring boot + http client + hystrix

6、pom.xml

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.2.5.RELEASE</version>
</parent>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
</properties>

<dependencies>
<dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-thymeleaf</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-jdbc</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis-spring</artifactId>
        <version>1.2.2</version>
    </dependency>
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.2.8</version>
    </dependency>
    <dependency>
        <groupId>org.apache.tomcat</groupId>
        <artifactId>tomcat-jdbc</artifactId>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
    </dependency>
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>1.1.43</version>
    </dependency>
</dependencies>

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>

<repositories>
    <repository>
        <id>spring-milestone</id>
        <url>https://repo.spring.io/libs-release</url>
    </repository>
</repositories>

<pluginRepositories>
    <pluginRepository>
        <id>spring-milestone</id>
        <url>https://repo.spring.io/libs-release</url>
    </pluginRepository>
</pluginRepositories>

你实际在你本地去搭建这个工程的时候,你首先就会发现说,你一修改这个pom.xml,发现下载各种spring boot依赖包,下载巨慢巨慢。北京,宽带,100M,联通,还是下载的巨慢

手工下载依赖,并安装到本地maven仓库

(1)在maven中央仓库搜索jar包,如果没有找到,就得手动在百度里面找,下载jar下来

(2)根据jar对应的group id,artifact id,找到自己本地的maven仓库,对应的目录,将jar包拷贝到那个目录里面去

jmxtool,groupId=com.sun.jdmk,artifactId=jmxtools,version=1.2.1

com\sun\jdmk\jmxtools\1.2.1

(3)手工执行mvn install:install-file的命令,在本地仓库中安装这个依赖

mvn install:install-file -Dfile=E:\apache-maven-3.0.5\mvn_repo\com\sun\jdmk\jmxtools\1.2.1\jmxtools-1.2.1.jar -DgroupId=com.sun.jdmk -DartifactId=jmxtools -Dversion=1.2.1 -Dpackaging=jar

(4)强制kill掉你的eclipse

(5)重新再进入eclips,这个时候肯定是会报很多的错误的,

Application.properties
server.port=8081
spring.datasource.url=jdbc:mysql://192.168.31.85:3306/eshop
spring.datasource.username=eshop
spring.datasource.password=eshop
spring.datasource.driver-class-name=com.mysql.jdbc.Driver

重新加载maven依赖

(6)反复循环,手工下载了,十几个到二十个依赖,然后最终所有的依赖全部成功下载到了本地,工程部报错

2、配置文件(src/main/resources)

说明:我已经在一个虚拟机中,安装好了一个mysql数据库,大家需要自己在自己本地安装一个mysql,配置好对应的url连接串,还有对应的用户名和密码就可以了

怎么安装mysql,大家自己网上查一下吧,java工程师,大学的学生,自己在本地安装一个mysql还是可以搞定的吧

mybatis/UserMappper.xml

templates/hello.html

3、Application

@EnableAutoConfiguration
@SpringBootApplication
@ComponentScan
@MapperScan("com.roncoo.eshop.cache.mapper")
public class Application {

    @Bean
    @ConfigurationProperties(prefix="spring.datasource")
    public DataSource dataSource() {
        return new org.apache.tomcat.jdbc.pool.DataSource();
    }

    @Bean
    public SqlSessionFactory sqlSessionFactoryBean() throws Exception {
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(dataSource());
        PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        sqlSessionFactoryBean.setMapperLocations(resolver.getResources("classpath:/mybatis/*.xml"));
        return sqlSessionFactoryBean.getObject();
    }

    @Bean
    public PlatformTransactionManager transactionManager() {
        return new DataSourceTransactionManager(dataSource());
    }

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

4、HelloController。

5、完成两个服务的构建。

相关文章