大家好,我是V哥,国足0-7不敌日本,创下12年来最大惨败,真的好久不看球赛了,我关心的是,作为国内唯一一家转播平台爱奇艺体育昨天崩了,官方道歉文中解释由于瞬时流量过大导致,这让我想起服务熔断、降级和限流是微服务架构中用于提高系统稳定性和可用性的三种关键策略。

介绍

服务熔断(Circuit Breaker)

服务熔断是一种防止服务故障蔓延的机制。它的概念来源于电力系统中的熔断器,当电流超过电路的承载能力时,熔断器会自动断开电路,以防止火灾等严重事故的发生。

在软件架构中,熔断器模式通常用于处理服务调用链中的远程服务调用。当某个服务调用失败的次数超过预设阈值时,熔断器会“断开”,暂时停止对该服务的调用。这样,系统可以快速失败,避免长时间的等待或大量的错误,从而保持系统的稳定性。在熔断期间,通常会提供一个备用的行为或返回一个友好的错误信息。

服务降级(Service Degradation)

服务降级是一种在系统负载过高或某些服务不可用时,临时关闭一些功能或降低服务标准的策略,以保证核心业务的正常运行。

在一个电商平台中,当遇到流量高峰时,可能会暂时关闭一些非核心功能,如商品推荐、优惠券发放等,以减轻服务器压力。或者,当支付服务不可用时,系统可能会允许用户将商品加入购物车,但暂时无法完成购买。

服务降级的目的是牺牲一部分用户体验,以确保系统不会因为过载而完全崩溃。

服务限流(Rate Limiting)

服务限流是一种控制服务调用频率的策略,以保护系统不被过量的请求压垮。

限流可以通过各种方式实现,例如:

  • 令牌桶:按照固定速率向桶中添加令牌,每次请求需要消耗一个令牌。
  • 漏桶:请求以固定速率从桶中流出,如果流出速度跟不上请求速度,多余的请求会被拒绝。
  • 固定窗口计数器:在固定时间窗口内计数请求次数,超过限制则拒绝服务。

限流可以应用于API网关,以控制对下游服务的访问频率,也可以应用于服务内部,以控制处理请求的速度。

高并发的电商购物车服务案例

假设在一个高并发的电商购物车服务案例,实现服务熔断、降级和限流。我们将使用Spring Boot和Spring Cloud Alibaba Sentinel来实现这些功能。

1. 项目结构

假设我们的项目结构如下:

shopping-cart-service
├── pom.xml
├── src
│   ├── main
│   │   ├── java
│   │   │   └── com
│   │   │       └── example
│   │   │           └── shoppingcart
│   │   │               ├── ShoppingCartApplication.java
│   │   │               ├── controller
│   │   │               │   └── ShoppingCartController.java
│   │   │               ├── service
│   │   │               │   └── ShoppingCartService.java
│   │   │               └── config
│   │   │                   └── SentinelConfig.java
│   │   └── resources
│   │       ├── application.yml
│   │       └── flow-rules.json
└── .gitignore

2. 添加依赖

pom.xml中添加Spring Boot和Spring Cloud Alibaba Sentinel依赖:

<dependencies>
    <!-- Spring Boot Starter Web -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!-- Spring Cloud Alibaba Sentinel -->
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
    </dependency>
    <!-- Spring Boot Starter Actuator -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
</dependencies>

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>Hoxton.SR9</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-alibaba-dependencies</artifactId>
            <version>2.2.5.RELEASE</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>

3. 应用主类

ShoppingCartApplication.java中创建Spring Boot应用:

package com.example.shoppingcart;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

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

4. 配置文件

application.yml中配置Sentinel Dashboard地址:

server:
  port: 8080

spring:
  application:
    name: shopping-cart-service

spring:
  cloud:
    sentinel:
      transport:
        dashboard: localhost:8080
      datasource:
        ds1:
          type: file
          data-id: ${spring.application.name}-flow-rules
          rule-type: flow
          url: file:///path/to/your/flow-rules.json

5. 熔断、降级和限流规则

flow-rules.json中配置熔断、降级和限流规则:

[
  {
    "resource": "addCart",
    "limitApp": "default",
    "grade": 1,
    "strategy": 0,
    "controlBehavior": 0,
    "threshold": 10,
    "action": 1
  },
  {
    "resource": "addCart",
    "limitApp": "default",
    "grade": 0,
    "strategy": 0,
    "controlBehavior": 1,
    "threshold": 5,
    "action": 1
  },
  {
    "resource": "addCart",
    "limitApp": "default",
    "grade": 0,
    "strategy": 0,
    "controlBehavior": 0,
    "threshold": 20,
    "action": 2
  }
]

6. 控制器

ShoppingCartController.java中创建REST API:

package com.example.shoppingcart.controller;

import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.SphU;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.example.shoppingcart.service.ShoppingCartService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ShoppingCartController {

    @Autowired
    private ShoppingCartService shoppingCartService;

    @GetMapping("/addCart")
    public String addCart(@RequestParam String productId, @RequestParam int quantity) {
        try (Entry entry = SphU.entry("addCart")) {
            return shoppingCartService.addCart(productId, quantity);
        } catch (BlockException ex) {
            return shoppingCartService.fallback();
        }
    }
}

7. 服务

ShoppingCartService.java中实现业务逻辑:

package com.example.shoppingcart.service;

public class ShoppingCartService {

    public String addCart(String productId, int quantity) {
        // 模拟业务逻辑
        if (quantity > 10) {
            throw new RuntimeException("Quantity too large");
        }
        return "Added " + quantity + " of " + productId + " to cart";
    }

    public String fallback() {
        return "Cart service is temporarily unavailable";
    }
}

8. 配置类

SentinelConfig.java中配置Sentinel规则:

package com.example.shoppingcart.config;

import com.alibaba.csp.sentinel.init.InitConfig;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.ArrayList;
import java.util.List;

@Configuration
public class SentinelConfig {

    @Bean
    public InitConfig initConfig() {
        InitConfig initConfig = new InitConfig();
        initConfig.setDataSource("file", "classpath:flow-rules.json");
        return initConfig;
    }

    @Bean
    public List<FlowRule> flowRules() {
        List<FlowRule> rules = new ArrayList<>();
        FlowRule rule = new FlowRule("addCart");
        rule.setCount(10); // 限流阈值
        rule.setGrade(RuleConstant.FLOW_GRADE_QPS); // QPS模式
        rule.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_DEFAULT); // 直接拒绝
        rules.add(rule);
        return rules;
    }

    @Bean
    public List<DegradeRule> degradeRules() {
        List<DegradeRule> rules = new ArrayList<>();
        DegradeRule rule = new DegradeRule("addCart");
        rule.setGrade(RuleConstant.DEGRADE_GRADE_RT); // 响应时间模式
        rule.setCount(500); // 响应时间阈值
        rule.setTimeWindow(10); // 时间窗口
        rule.setMinRequestAmount(5); // 最小请求量
        rules.add(rule);
        return rules;
    }
}

9. 启动Sentinel Dashboard

确保你已经启动了Sentinel Dashboard,可以通过以下命令启动:

java -jar sentinel-dashboard.jar

10. 运行应用

运行ShoppingCartApplication,然后通过浏览器或Postman测试API:

http://localhost:8080/addCart?productId=123&quantity=5

解释一下

  1. 熔断:当addCart方法的调用次数超过10次时,Sentinel会触发熔断,直接返回降级逻辑。
  2. 降级:当addCart方法的响应时间超过500ms,或者调用次数超过5次时,Sentinel会触发降级,返回降级逻辑。
  3. 限流:当addCart方法的调用次数超过10次时,Sentinel会触发限流,直接拒绝请求。

通过这些配置,我们可以在高并发场景下保护我们的服务,避免系统过载。

最后

  • 熔断:当服务不可用时,快速失败,避免系统过载。
  • 降级:在系统压力较大时,暂时关闭或降低非核心服务的质量,保证核心服务的可用性。
  • 限流:控制请求的速率,防止系统因请求过多而崩溃。

这三种策略通常结合使用,以提高大型分布式系统的稳定性和可用性。


威哥爱编程
178 声望15 粉丝

华为开发者专家(HDE)、TiDB开发者官方认证讲师、Java畅销书作者、HarmonyOS应用开发高级讲师