微服务-服务容错

1.高并发带来的问题

微服务架构 中,我们将业务拆分成⼀个个的服务 ,服务与服务之间可以相互调⽤,但是由于**⽹络原因或者⾃身的原因**,服务并不能保证服务的100%可⽤,如果单个服务出现问题,调⽤这个服务就会出现**⽹络延迟** ,此时若有大量的网络涌入 ,会形成任务堆积 ,最终导致服务瘫痪。

2.模拟场景

接下来,我们来模拟⼀个⾼并发的场景。
创建⼀个服务提供者项目,在 controller 书写两个⽅法供消费者调⽤,⼀个⽅法被延迟,另⼀个方法正常。

2.1 新建一个cloud.sentinel.provider项目

java 复制代码
package com.jiazhong.mingxing.project.cloud.sentinel.provider.controller;

import com.jiazhong.mingxing.cloud.commons.util.JsonResult;
import com.jiazhong.mingxing.cloud.commons.util.ResultTool;
import lombok.SneakyThrows;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/sentinel_provider")
public class SentinelProviderController {
    @SneakyThrows
    @GetMapping("/a")
    public JsonResult a() {
        Thread.sleep(3000);
        return ResultTool.success("This is SentinelProviderController`a method");
    }
    @GetMapping("/b")
    public JsonResult b() {
        return ResultTool.success("This is SentinelProviderController`b method");
    }
}

启动项目

2.2新建cloud.sentinel.consumer项目

写一个SentinelProviderFeign接口

java 复制代码
package com.jiazhong.mingxing.project.cloud.sentinel.provider.feign;

import com.jiazhong.mingxing.cloud.commons.util.JsonResult;
import com.jiazhong.mingxing.project.cloud.sentinel.provider.feign.impl.SentinelProviderFeignImpl;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;

@FeignClient(value = "cloud-sentinel-provider", path = "sentinel_provider", fallback = SentinelProviderFeignImpl.class)
public interface SentinelProviderFeign {

    @GetMapping("/a")
    JsonResult a();

    @GetMapping("/b")
    JsonResult b();
}

写service以及实现类

java 复制代码
package com.jiazhong.mingxing.project.cloud.sentinel.provider.service;

import com.jiazhong.mingxing.cloud.commons.util.JsonResult;
import org.springframework.stereotype.Service;

@Service
public interface SentinelConsumerService {
    JsonResult a();
    JsonResult b();

}
java 复制代码
package com.jiazhong.mingxing.project.cloud.sentinel.provider.feign.impl;

import com.jiazhong.mingxing.cloud.commons.util.JsonResult;
import com.jiazhong.mingxing.cloud.commons.util.ResultTool;
import com.jiazhong.mingxing.project.cloud.sentinel.provider.feign.SentinelProviderFeign;
import org.springframework.stereotype.Component;

@Component
public class SentinelProviderFeignImpl implements SentinelProviderFeign {
    @Override
    public JsonResult a() {
        return sentinelProviderFeign.a();
    }

    @Override
    public JsonResult b() {
        return sentinelProviderFeign.b();
    }
}

新建controller类

java 复制代码
package com.jiazhong.mingxing.project.cloud.sentinel.provider.controller;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.jiazhong.mingxing.cloud.commons.util.JsonResult;
import com.jiazhong.mingxing.cloud.commons.util.ResultTool;
import com.jiazhong.mingxing.project.cloud.sentinel.provider.service.SentinelConsumerService;
import lombok.SneakyThrows;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/sentinel_consumer")
public class CloudSentinelConsumerController {
    private SentinelConsumerService sentinelConsumerService;
    public CloudSentinelConsumerController(SentinelConsumerService sentinelConsumerService) {
        this.sentinelConsumerService = sentinelConsumerService;
    }
    @GetMapping("/a")
    public JsonResult a() {
        return sentinelConsumerService.a();
    }
    @GetMapping("/b")
    public JsonResult b() {
        return sentinelConsumerService.b();
    }
}

修改yml文件

java 复制代码
server:
  port: 8022
  jetty:
    threads:
      max: 10
spring:
  application:
    name: cloud-sentinel-consumer
  #这里是微服务的内容
  #注册
  cloud:
    nacos:
      discovery:
        namespace: 5dde225c-61e0-4015-8a2f-5eabe8407195 # 你的命名空间
        server-addr: 192.168.xx.xx:8848 # 自己的地址
        #ephemeral: false
    sentinel:
      transport:
        port: 8719 #跟控制台交流的端⼝,随意指定⼀个未使⽤的端⼝即可
        dashboard: localhost:8888 # 指定控制台服务的地址
      web-context-unify: false
feign:
  sentinel:
    enabled: true

启动该项目

2.3.下载压测工具JMeter

下载地址:https://jmeter.apache.org/

解压,启动jmeter.sh

2000个请求,访问a,a占用资源,来一个正常的b,没有资源处理,响应时间会增加。


最后,观察运行结果。
此时会发现 , 由于 a ⽅法囤积了⼤量请求,导致 b ⽅法的访问出现了问题,这就是服务雪崩的雏形。

3.服务雪崩效应

在分布式系统中,由于⽹络原因或⾃身的原因,服务⼀般⽆法保证100% 可⽤。如果⼀个服务出现了问题,调⽤这 个服务就会出现线程阻塞的情况,此时若有⼤量的请求涌⼊,就会出现多条线程阻塞等待,进⽽导致服务瘫痪。 由 于服务于服务之间的依赖性,故障会传播,会对整个微服务系统造成灾难性的严重后果,这就是服务故障的" 雪崩 " 效应。
雪崩发生过的原因多种多样,有不合理的容量设计,或者是⾼并发下某⼀个⽅法响应变慢,亦或是某台机器的资源耗 尽。我们⽆法完全杜绝雪崩源头的发⽣, 只有做好⾜够的容错,保证在⼀个服务发⽣问题,不会影响到其他服务的 正常运⾏。也就是 " 雪落⽽不雪崩 " 。

4.常见容错方案

要防⽌雪崩的扩散,我们就要做好服务的容错,容错说⽩了就是保护⾃⼰不被猪队友拖垮的⼀些措施,下⾯介绍常见的服务容错思路和组件。 常⻅的容错思路有隔离、超时、限流、熔断、降级这几种,下⾯分别介绍⼀下。

4.1隔离

它是指将系统按照⼀定的原则划分为若⼲服务模块,各个模块之间相对独⽴,⽆强影响。当有故障发⽣时,能将问 题和影响隔离在某个模块内部, ⽽不扩散⻛险,不波及其他模块,不影响整体的系统服务。

常⻅的隔离⽅式有:

  • 线程池隔离。
  • 信号量隔离。

4.2超时

在上游( A 服务)服务调⽤下游( B 服务)服务的时候,设置⼀个最⼤响应时间,如果超过这个时间,下游未作出反 应,就断开请求,释放掉线程

4.3限流

限流就是限制系统的输入和输出流量已达到保护系统 的目的,为了保护系统的稳固巡行,一旦达到的需要限制的阈值,就需要限制流量并采取少量措施以完成限制流量的目的。

4.4熔断

在互联⽹系统中,当下游( B 服务)服务因访问压⼒过⼤⽽响应变慢或失败,上游( A 服务)服务为了保护系统整体的可⽤性,可以暂时切断对下游服务的调⽤。这种牺牲局部,保全整体的措施就叫做熔断。

服务熔断⼀般有三种状态:

  • 熔断关闭状态(Closed) B服务没有故障时,熔断器所处的状态,对调⽤⽅(A服务)的调⽤不做任何限制。
  • 熔断开启状态(Open) B服务有故障时,后续对该服务接⼝的调⽤不再经过⽹络(不在对B 服务进行访问),直接执⾏本地的fallback的⽅法。
  • 半熔断状态(Half-Open) 尝试恢复服务调⽤,允许有限的流量调⽤该服务,并监控调⽤成功率。如果成功率达到预期,则说明服务已恢复,进⼊熔断关闭状态; 如果成功率仍旧很低,则重新进⼊熔断开启状态。

4.5降级

降级其实就是为服务提供⼀个托底(备选)⽅案,⼀旦服务⽆法正常调⽤,就使⽤托底(备选)方案。

我们使用容错组件Sentinel

5.Sentinel入门

5.1什么是Sentinel

Sentinel 是 Alibaba 开源的分布式系统流量控制、熔断降级、系统负载保护工具 ,核心目标是 保障微服务架构的稳定性,避免因流量突增、服务故障、资源耗尽等问题导致整体系统雪崩。

它与 Spring Cloud 生态深度集成(如 Spring Cloud Alibaba Sentinel),可无缝对接 Nacos、Gateway、Feign 等组件,是微服务架构中 "稳定性防护" 的核心组件之一。
基本概念

  • 资源:是 Sentinel 的关键概念。它可以是 Java 应⽤程序中的任何内容,可以是⼀个服务,也可以是⼀个⽅法,甚⾄可以是⼀段代码。就是 Sentinel 需要保护的东⻄。 我们⼊⻔案例中的 customer/b ⽅法就可以认为是⼀个资源。
  • 规则:作⽤在资源之上,定义以什么样的⽅式保护资源,主要包括流量控制规则、熔断降级规则以及系统保护规则。规则就是⽤来定义如何进⾏保护资源的。 我们⼊⻔案例就是为 customer/b 资源设置了⼀种流控规则,限制了进⼊ customer/b 的流量。

5.2Sentinel的组成部分

  • 核心库( Java 客户端)不依赖任何框架|库,能够运⾏于所有 Java 运⾏环境,同时对 Dubbo/Spring Cloud 等框架也有较好的⽀持。
  • 控制台( Dashboard )基于 Spring Boot 开发,打包后可以直接运⾏,不需要额外的 Tomcat 等应⽤容器。

5.3微服务集成Sentinel

微服务集成 Sentinel ⾮常简单 , 只需要加⼊ Sentinel 的依赖即可。

5.3.1导入依赖

XML 复制代码
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency

5.3.2安装控制台

Sentinel 提供⼀个轻量级的控制台,它提供机器发现、单机资源实时监控以及规则管理等功能。 下载 jar 包,存放到任意⽂件夹。 https://github.com/alibaba/Sentinel/releases(下载1.8.9)

5.3.3启动控制台

通过 cmd 命令可以启动控制台。

XML 复制代码
## 其中8888是端⼝号,1.8.5是下载的版本号。都是可以修改的。
java -Dserver.port=8888 -Dcsp.sentinel.dashboard.server=localhost:8888 -
Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.8.9.jar

在浏览器中输入地址:localhost:8888 即可出现下图画面

用户以及密码都是sentinel

5.3.4 修改"消费者项目",在⾥边加⼊有关控制台的配置

XML 复制代码
spring:
   cloud:
     sentinel:
       transport:
          port: 8719 #跟控制台交流的端⼝,随意指定⼀个未使⽤的端⼝即可 
             dashboard: localhost:8888 # 指定控制台服务的地址 

启动生产者和消费者项目,多访问几次,就会在Sentinel中看到

设置每秒最多访问2

若1秒内多于2次,出现下图

6.案例

在controller类中写下述方法

java 复制代码
@GetMapping("/c")
    public JsonResult c() {
        return ResultTool.success("This is SentinelConsumerController`c method!");
    }

这样可以只启动消费者

6.1流控(线程数)

启动Jmeter

3/7的几率失败

6.2让步

在controller类下写入d方法

java 复制代码
 @GetMapping("/d")
    public JsonResult d() {
        return ResultTool.success("This is SentinelConsumerController`d method!");
    }

如果d的资源每秒访问数超过4次就会限流访问c

c不可以访问,d可以访问

6.3链路

链路:只记录指定链路上的流量(指定资源从⼊⼝资源进来的流量,如果达到阈值,就进⾏限流 ) , 可看作 api 级别的针对来源,链路的粒度更细,需要如下步骤才能实现

6.3.1修改yml文件

添加下述代码

java 复制代码
web-context-unify: false

6.3.2在service中写方法

java 复制代码
@SentinelResource("messageE")
    public JsonResult e() {
        return ResultTool.success("This is SentinelConsumerServiceImpl`e method!");
    }

6.3.3写两个controller方法e1 e2

java 复制代码
@GetMapping("/e1")
    public JsonResult e1() {
        return sentinelConsumerService.e();
    }

    @GetMapping("/e2")
    public JsonResult e2() {
        return sentinelConsumerService.e();
    }

对e1限流,e2不限流

相关推荐
Xの哲學1 小时前
Linux TTY子系统深度剖析
linux·服务器·算法·架构·边缘计算
拾忆,想起1 小时前
Dubbo灰度发布完全指南:从精准引流到全链路灰度
前端·微服务·架构·dubbo·safari
星哥说事1 小时前
容器编排:K8s 集群部署(kubeadm / kops)、节点管理全解读
云原生·容器·kubernetes
摇滚侠1 小时前
2025最新 SpringCloud 教程,Seata-基础-架构原理-整合 Seata 完成,笔记68,笔记69
笔记·spring cloud·架构
weixin_307779133 小时前
Jenkins GitHub插件1.45.0:深度集成与实践指南
运维·云原生·云计算·jenkins
如果未来,10 小时前
k8s介绍,及其主要组件作用
云原生·容器·kubernetes
刘一说10 小时前
Nacos 权限控制详解:从开源版 v2.2+ 到企业级安全实践
spring boot·安全·spring cloud·微服务·nacos·架构·开源
TG:@yunlaoda360 云老大12 小时前
谷歌云AI 时代的算力革命:CPU、GPU 到 TPU 的架构与定位解析
人工智能·架构·googlecloud
阿拉斯攀登12 小时前
Kubernetes(K8s)全面解析:核心概念、架构与实践
docker·云原生·容器·kubernetes·k8s