分布式微服务学习总结——Hystrix

本文涉及的产品
注册配置 MSE Nacos/ZooKeeper,118元/月
云原生网关 MSE Higress,422元/月
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
简介: 分布式微服务学习总结——Hystrix

一、前言

最近刚看完springcloud、dubbo的学习视频,但感觉不是那么扎实,所以打算写一个系列的博客来巩固自身所学。

当然有些内容是参考了别的博客,毕竟我也是初探分布式微服务的,并不是所谓的大神,只是一个新手在初探分布式微服务后写下的一些自己的理解和总结。


注:以下简述部分来自官方文档翻译(官方文档写的已经很好了,所以直接搬运)


官方文档地址:https://github.com/Netflix/hystrix/wiki


二、简述

什么是 Hystrix?

在分布式环境中,不可避免地会遇到所依赖的服务挂掉的情况,Hystrix 可以通过增加 延迟容忍度 与 错误容忍度,来控制这些分布式系统的交互。Hystrix 在服务与服务之间建立了一个中间层,防止服务之间出现故障,并提供了失败时的 fallback 策略,来增加你系统的整体可靠性和弹性。


Hystrix 做了那些事情?

Hystrix 提供了以下服务


引入第三方的 client 类库,通过延迟与失败的检测,来保护服务与服务之间的调用(网络间调用最为典型)

阻止复杂的分布式系统中出现级联故障

快速失败与快速恢复机制

提供兜底方案(fallback)并在适当的时机优雅降级

提供实时监控、报警与操作控制


Hystrix 解决了什么问题?

在复杂的分布式架构中,服务之间都是相互依赖的,任何一个节点都不可避免会宕机。如果主节点不能从这些宕机节点中独立出来,那主节点将会面临被这些宕机的节点拖垮的风险。举个例子,如果一个应用依赖了 30 个服务,每个服务保证 99.99% 的时间是正常的,那可以计算出


99.9930 = 99.7% uptime
0.3% of 1 billion requests = 3,000,000 failures
2+ hours downtime/month even if all dependencies have excellent uptime.


实际情况往往更糟糕


完好情况下,请求流如下:

q1.png


当一个依赖的节点坏掉时,将阻塞整个的用户请求:


q3.png

流量高峰时,一个单节点的宕机或延迟,会迅速导致所有服务负载达到饱和。应用中任何一个可能通过网络访问其他服务的节点,都有可能成为造成潜在故障的来源。更严重的是,还可能导致服务之间的延迟增加,占用队列、线程等系统资源,从而导致多系统之间的级联故障。

q2.png


更严重的是,当网络请求是通过第三方的一个黑盒客户端来发起时,实现细节都被隐藏起来了,而且还可能频繁变动,这样发生问题时就很难监控和改动。如果这个第三方还是通过传递依赖的,主应用程序中根本没有显示地写出调用的代码,那就更难了。


网络连接失败或者有延迟,服务将会产生故障或者响应变慢,最终反应成为一个 bug。


所有上述表现出来的故障或延迟,都需要一套管理机制,将节点变得相对独立,这样任何一个单节点故障,都至少不会拖垮整个系统的可用性。


Hystrix 的设计原则是什么?

Hystrix 通过以下设计原则来运作:


防止任何一个单节点将容器中的所有线程都占满

通过快速失败,取代放在队列中等待

提供在故障时的应急方法(fallback)

使用隔离技术 (如 bulkhead, swimlane, 和 circuit breaker patterns) 来限制任何一个依赖项的影响面

提供实时监控、报警等手段

提供低延迟的配置变更

防止客户端执行失败,不仅仅是执行网络请求的客户端


Hystrix 如何时间它的目标?

如下:


将远程请求或简单的方法调用包装成 HystrixCommand 或者 HystrixObservableCommand 对象,启动一个单独的线程来运行。

你可以为服务调用定义一个超时时间,可以为默认值,或者你自定义设置该属性,使得99.5%的请求时间都在该时间以下。

为每一个依赖的服务都分配一个线程池,当该线程池满了之后,直接拒绝,这样就防止某一个依赖的服务出问题阻塞了整个系统的其他服务

记录成功数、失败数、超时数以及拒绝数等指标

设置一个熔断器,将所有请求在一段时间内打到这个熔断器提供的方法上,触发条件可以是手动的,也可以根据失败率自动调整。

实时监控配置与属性的变更


当你启用 Hystrix 封装了原有的远程调用请求后,整个流程图变为下图所示。

q1.png


接下来让我们学习如何使用它吧


三、快速入门

注解方式

此种方式最为简便,适用于大部分情况,但无法进行动态配置


1.导入依赖(服务提供者端)

<!--熔断机制-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
        </dependency>
        <!--完善监控信息-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>


2.在需要添加熔断机制的类上加上fallback方法并进行注解(服务提供者端)

如下:

package com.dreamchaser.springcloud.controller;
import com.dreamchaser.pojo.Tag;
import com.dreamchaser.springcloud.service.TagService;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@Controller
public class TagController {
    @Autowired
    TagService tagService;
    @GetMapping(value = "/tag",produces = "application/json;charset=UTF-8")
    //添加熔断注解
    @HystrixCommand(fallbackMethod = "hystrixGet")
    public @ResponseBody List<Tag> findTags(){
        List<Tag> list=tagService.findTagAll();
        if (list==null){
            throw new RuntimeException("不存在该标签,id未找到!");
        }
        list.get(0).setId(8005);
        return list;
    }
    @PostMapping("/tag")
    @HystrixCommand(fallbackMethod = "hystrixGet")
    public @ResponseBody String insertTag(Tag tag){
        if (tagService.insertTag(tag)==1){
            return "添加新标签成功!";
        }else {
            return "添加新标签失败!";
        }
    }
    //备选方案
    public @ResponseBody List<Tag> hystrixGet(){
        Tag tag=new Tag();
        tag.setId(1).setName("没有对应的信息!").setDate(new Date()).setNumber(0);
        List<Tag> list=new ArrayList<>();
        list.add(tag);
        return list;
    }
}


需要自己写个fallback方法,并且在需要加熔断机制的方法上加上@HystrixCommand(fallbackMethod = “hystrixGet”)注解,fallbackmethod表示回调的方法。


即当服务发生超时、异常或者线程已满等服务不可用的情况时,hystrix会记录,并直接执行fallback方法。当服务健康状况达到一定程度,会触发服务降级。


服务的健康状况=请求失败数/请求总数


3.开启熔断支持(服务提供者端)

在启动类上加上@EnableCircuitBreaker注解来开启熔断支持。


至此我们便已经开启了熔断机制,如果还想进行流量监控则还需以下几步。


4.注册一个servlet来作为检测地址(服务提供者端)

可以在启动类中加入一个方法


//增加一个servlet
    @Bean
    public ServletRegistrationBean hystrixMetricsStreamServlet(){
        ServletRegistrationBean registrationBean=new ServletRegistrationBean(new HystrixMetricsStreamServlet());
        registrationBean.addUrlMappings("/actuator/hystrix.stream");
        registrationBean.setLoadOnStartup(1);
        registrationBean.setName("HystrixMetricsStreamServlet");
        return registrationBean;
    }


这表示在项目中加上一个servlet,这样访问该地址时会返回一个stream流,用来hystrix对服务进行流监控。


5.加入依赖并开启流监控(服务消费者端)

添加依赖


<!--dashboard流监控-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
        </dependency>

开启流监控


@EnableHystrixDashboard


6.测试运行

启动完进程,打开http://localhost:81/hystrix(就是消费端地址后加上hystrix)



q4.png

我们看到了一只豪猪。。。


访问一下业务


正常!

q3.png


访问我们刚设置的servlet地址



q2.png

可以看到它每隔一秒发送一段字符串


把这个地址输入hystrix页面


输入地址后点击右下角的按钮,我们可以看到这样一个画面


q1.png


绿色表示服务访问成功的次数,每次刷新业务的接口地址,上面的数字就会+1。


这样就相当于与仪表盘一样来监测服务的实时状态,达到实时监控的效果。


如果想要更加详细的配置,具体可以参考这篇文章Hystrix在项目中的使用(一)-注解方式


命令式编程方式

这种方式就比较麻烦了,对代码的修改程度就比较大,一般不建议采用,不过它可以实现动态配置,如果实在要用可采用aop切面来减少对代码的影响。


具体可以参考这篇Hystrix在项目中的使用(二)-基于AOP实现命令式编程(动态配置)


四、总结

hystrix是一款功能强大的中间件,用来解决某个服务节点宕机导致服务雪崩的问题。


同时还可以用来实时监控服务的流量情况。


相关文章
|
1月前
|
存储 消息中间件 Apache
比较微服务中的分布式事务模式
比较微服务中的分布式事务模式
48 2
|
4天前
|
存储 NoSQL 调度
|
23天前
|
数据库 C++ Ruby
为什么你应该选择分布式平台与微服务?
为什么你应该选择分布式平台与微服务?
|
22天前
|
监控 Go API
带你十天轻松搞定 Go 微服务之大结局(分布式事务)
带你十天轻松搞定 Go 微服务之大结局(分布式事务)
|
30天前
|
监控 Java 开发者
随着软件开发的发展,传统单体应用已难以适应现代业务需求,微服务架构因此兴起,成为构建可伸缩、分布式系统的主流
随着软件开发的发展,传统单体应用已难以适应现代业务需求,微服务架构因此兴起,成为构建可伸缩、分布式系统的主流。本文探讨Java微服务架构的设计原则与实践。核心思想是将应用拆分为独立服务单元,增强模块化与扩展性。Java开发者可利用Spring Boot等框架简化开发流程。设计时需遵循单一职责、自治性和面向接口编程的原则。以电商系统为例,将订单处理、商品管理和用户认证等拆分为独立服务,提高可维护性和容错能力。还需考虑服务间通信、数据一致性及监控等高级话题。掌握这些原则和工具,开发者能构建高效、可维护的微服务应用,更好地应对未来挑战。
66 1
|
30天前
|
Java 微服务 Spring
SpringBoot+Vue+Spring Cloud Alibaba 实现大型电商系统【分布式微服务实现】
文章介绍了如何利用Spring Cloud Alibaba快速构建大型电商系统的分布式微服务,包括服务限流降级等主要功能的实现,并通过注解和配置简化了Spring Cloud应用的接入和搭建过程。
SpringBoot+Vue+Spring Cloud Alibaba 实现大型电商系统【分布式微服务实现】
|
1月前
|
Cloud Native 云计算 微服务
云原生时代:企业分布式应用架构的惊人蜕变,从SOA到微服务的大逃亡!
【8月更文挑战第8天】在云计算与容器技术推动下,企业分布式应用架构正经历从SOA到微服务再到云原生的深刻变革。SOA强调服务重用与组合,通过标准化接口实现服务解耦;微服务以细粒度划分服务,增强系统灵活性;云原生架构借助容器化与自动化技术简化部署与管理。每一步演进都为企业带来新的技术挑战与机遇。
82 6
|
17天前
|
Java 数据库连接 微服务
揭秘微服务架构下的数据魔方:Hibernate如何玩转分布式持久化,实现秒级响应的秘密武器?
【8月更文挑战第31天】微服务架构通过将系统拆分成独立服务,提升了可维护性和扩展性,但也带来了数据一致性和事务管理等挑战。Hibernate 作为强大的 ORM 工具,在微服务中发挥关键作用,通过二级缓存和分布式事务支持,简化了对象关系映射,并提供了有效的持久化策略。其二级缓存机制减少数据库访问,提升性能;支持 JTA 保证跨服务事务一致性;乐观锁机制解决并发数据冲突。合理配置 Hibernate 可助力构建高效稳定的分布式系统。
31 0
|
22天前
|
消息中间件 SQL 关系型数据库
go-zero微服务实战系列(十、分布式事务如何实现)
go-zero微服务实战系列(十、分布式事务如何实现)
|
22天前
|
消息中间件 存储 Kafka
微服务实践之分布式定时任务
微服务实践之分布式定时任务