• SpringCloud 服务限流与熔断


    目录

    学习SpringCloud指南 ☆ ☆ ☆ ☆ ☆

      小白学习SpringCloud 使用与Nacos

      小白学习SpringCloud 远程通信【OpenFeign】

      小白学习SpringCloud 配置中心【Nacos_Config】

      小白学习SpringCloud 网关【Gateway】

    1. 限流

    2. Gateway限流的实现

    2.1 导入pom依赖

    2.2 添加redis配置

    2.3 添加限流配置

    2.4 RequestRateLimiterConfig 配置类

    2.5 整合yml文件参考

    3. JMeter压力测试

    4. 熔断

    4.1 添加熔断配置 

    4.2 整合yml文件参考

    4.3 服务器降级响应处理


    学习SpringCloud指南 ☆ ☆ ☆ ☆ ☆

      小白学习SpringCloud 使用与Nacos

      小白学习SpringCloud 远程通信【OpenFeign】

      小白学习SpringCloud 配置中心【Nacos_Config】

      小白学习SpringCloud 网关【Gateway】


    问题分析 

         “一码通”一度瘫痪,西安电信遭质疑!崩溃原因到底是什么?_腾讯新闻 

          从技术角度分析一下,西安一码通为何反复崩溃? - 知乎  

     主要问题

    •  限流问题:市民在长时间无法刷出健康码的情况下,多次退出刷新重试,新的流量到达服务   器,导 致服务器压力变大、承受负载增加,说明“西安一码通”系统没有做好限流措施。 

    •  服务器问题:无论是企业和个人在租用服务器的时候都会受到峰值承受限制的,一旦超过服   务器的 承受能力,就会导致服务器瘫痪,应用程序暂停,网站无法访问。服务器是有峰值限   制的,不可能 承受无上限的并发能力。而造成服务器瘫痪的原因就是在同一段时间内,访问   人数多,造成高流量 的突进,超出了服务器的承受范围。

    •  架构问题:“西安一码通”功能影响“核酸检测”服务,说明模块间从界面到数据调用互相影响,   可能 不是微服务架构。 

    •  性能过载:典型的性能过载场景,不论内部根因是数据库瓶颈点,还是网络链接数瓶颈点等   等,外 因都是因为过载导致。 

    •  设计漏洞:没有考虑高流量高负载的情况,导致测试不充分;产品设计未考虑千万级的并发   访问, 交付前未进行同等级的压力测试。 

    •  压力测试:在市民长时间无法看到健康码的情况下,多次退出刷新重试,新的流量到达服务   器,导 致服务器压力变大、承受负载增加。说明压力测试不够。 

    1. 限流

    限流的目的是通过对并发访问/请求进行限速或者对一个时间窗口内的请求进行限速来保护系统,一旦达 到限制速率则可由拒绝服务,就是定向到错误页或友好的展示页,排队或等待。

    限流可以保障我们的 API 服务对所有用户的可用性,也可以防止网络攻击。在高并发的应用中,限流是 一个绕不开的话题。

     

    令牌桶算法

     令牌桶算法的原理是系统会以一个恒定的速度往桶里放入令牌,而如果请求需要被处理,则   需要先从桶 里获取一个令牌,当桶里没有令牌可取时,则拒绝服务。

    •  QPS 每秒请求数,就是说服务器在一秒的时间内处理了多少个请求。

    提高带宽

     

    2. Gateway限流的实现

        2.1 导入pom依赖

    1. "1.0" encoding="UTF-8"?>
    2. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    3. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    4. <modelVersion>4.0.0modelVersion>
    5. <groupId>com.jmhgroupId>
    6. <artifactId>nacos_gatewayartifactId>
    7. <version>0.0.1-SNAPSHOTversion>
    8. <name>nacos_gatewayname>
    9. <description>Demo project for Spring Bootdescription>
    10. <properties>
    11. <project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
    12. <maven.compiler.source>1.8maven.compiler.source>
    13. <maven.compiler.target>1.8maven.compiler.target>
    14. <spring-boot.version>2.3.7.RELEASEspring-boot.version>
    15. <spring-cloud.version>Hoxton.SR5spring-cloud.version>
    16. <spring-cloud-alibaba.version>2.1.1.RELEASEspring-cloud-alibaba.version>
    17. properties>
    18. <dependencies>
    19. <dependency>
    20. <groupId>org.springframework.bootgroupId>
    21. <artifactId>spring-boot-starter-testartifactId>
    22. dependency>
    23. <dependency>
    24. <groupId>com.alibaba.cloudgroupId>
    25. <artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
    26. dependency>
    27. <dependency>
    28. <groupId>org.springframework.cloudgroupId>
    29. <artifactId>spring-cloud-starter-openfeignartifactId>
    30. dependency>
    31. <dependency>
    32. <groupId>org.springframework.cloudgroupId>
    33. <artifactId>spring-cloud-loadbalancerartifactId>
    34. dependency>
    35. <dependency>
    36. <groupId>ma.glasnost.orikagroupId>
    37. <artifactId>orika-coreartifactId>
    38. <version>1.4.6version>
    39. dependency>
    40. <dependency>
    41. <groupId>org.projectlombokgroupId>
    42. <artifactId>lombokartifactId>
    43. dependency>
    44. <dependency>
    45. <groupId>org.springframework.bootgroupId>
    46. <artifactId>spring-boot-starter-webfluxartifactId>
    47. dependency>
    48. <dependency>
    49. <groupId>org.springframework.cloudgroupId>
    50. <artifactId>spring-cloud-starter-gatewayartifactId>
    51. dependency>
    52. <dependency>
    53. <groupId>org.springframework.bootgroupId>
    54. <artifactId>spring-boot-starter-actuatorartifactId>
    55. dependency>
    56. <dependency>
    57. <groupId>io.projectreactorgroupId>
    58. <artifactId>reactor-testartifactId>
    59. <scope>testscope>
    60. dependency>
    61. <dependency>
    62. <groupId>com.alibabagroupId>
    63. <artifactId>fastjsonartifactId>
    64. <version>1.2.35version>
    65. dependency>
    66. <dependency>
    67. <groupId>org.springframework.bootgroupId>
    68. <artifactId>spring-boot-starter-data-redis-reactiveartifactId>
    69. dependency>
    70. <dependency>
    71. <groupId>org.springframework.cloudgroupId>
    72. <artifactId>spring-cloud-starter-netflix-hystrixartifactId>
    73. dependency>
    74. dependencies>
    75. <dependencyManagement>
    76. <dependencies>
    77. <dependency>
    78. <groupId>org.springframework.bootgroupId>
    79. <artifactId>spring-boot-dependenciesartifactId>
    80. <version>${spring-boot.version}version>
    81. <type>pomtype>
    82. <scope>importscope>
    83. dependency>
    84. <dependency>
    85. <groupId>org.springframework.cloudgroupId>
    86. <artifactId>spring-cloud-dependenciesartifactId>
    87. <version>${spring-cloud.version}version>
    88. <type>pomtype>
    89. <scope>importscope>
    90. dependency>
    91. <dependency>
    92. <groupId>com.alibaba.cloudgroupId>
    93. <artifactId>spring-cloud-alibaba-dependenciesartifactId>
    94. <version>${spring-cloud-alibaba.version}version>
    95. <type>pomtype>
    96. <scope>importscope>
    97. dependency>
    98. dependencies>
    99. dependencyManagement>
    100. <build>
    101. <plugins>
    102. <plugin>
    103. <groupId>org.springframework.bootgroupId>
    104. <artifactId>spring-boot-maven-pluginartifactId>
    105. plugin>
    106. plugins>
    107. build>
    108. project>
    • Spring Cloud Gateway官方提供了RequestRateLimiterGatewayFilterFactory类,使用redis和lua脚本 来实现令牌桶的方式。
    • Gateway通过内置的RequestRateLimiter过滤器实现限流,使用令牌桶算法,借助Redis保存中间数 据。用户可通过自定义KeyResolver设置限流维度。
    • 对请求的目标URL进行限流
    • 对来源IP进行限流
    • 特定用户进行限流

       2.2 添加redis配置

    1. redis:
    2. host: 127.0.0.1
    3. port: 6379
    4. # password: root123
    5. database: 0
    • 如果redis连接失败,限流功能将不能开启。因为没有redis作为容器来保存令牌,限流功能自  然就失效 了。
    • 可以将redis的配置信息保存到nacos中,通过添加nacos配置中心客户端的方式进行读取

       2.3 添加限流配置

    1. filters:
    2. - name: RequestRateLimiter
    3. args:
    4. #用于限流的键的解析器的 Bean 对象的名字,使用 SpEL表达式根据#{@beanName}获取Bean对象
    5. key-resolver: '#{@ipAddrKeyResolver}'
    6. #令牌桶填充速率,允许用户每秒处理多少个请求
    7. redis-rate-limiter.replenishRate: 10
    8. #令牌桶总容量,允许在一秒钟内完成的最大请求数
    9. redis-rate-limiter.burstCapacity: 20

      2.4 RequestRateLimiterConfig 配置类

    1. package com.jmh.nacos_gateway;
    2. import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver;
    3. import org.springframework.context.annotation.Bean;
    4. import org.springframework.context.annotation.Configuration;
    5. import org.springframework.context.annotation.Primary;
    6. import reactor.core.publisher.Mono;
    7. /**
    8. * 请求限流配置
    9. */
    10. @SuppressWarnings("all")
    11. @Configuration
    12. public class RequestRateLimiterConfig {
    13. /**
    14. * 按IP来限流
    15. */
    16. @Bean
    17. @Primary
    18. public KeyResolver ipAddrKeyResolver() {
    19. return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getAddress().getHostAddress());
    20. }
    21. /**
    22. * 按用户限流
    23. */
    24. @Bean
    25. KeyResolver userKeyResolver() {
    26. return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("user"));
    27. }
    28. /**
    29. * 按URL限流,即以每秒内请求数按URL分组统计,超出限流的url请求都将返回429状态
    30. *
    31. * @return
    32. */
    33. @Bean
    34. KeyResolver apiKeyResolver() {
    35. return exchange -> Mono.just(exchange.getRequest().getPath().toString());
    36. }
    37. }

      2.5 整合yml文件参考

    1. server:
    2. port: 8084
    3. spring:
    4. application:
    5. name: nacos-gateway
    6. redis:
    7. host: 127.0.0.1
    8. port: 6379
    9. password: 1234
    10. database: 0
    11. cloud:
    12. nacos:
    13. discovery:
    14. server-addr: 127.0.0.1:8848
    15. gateway:
    16. discovery:
    17. locator:
    18. #是否与服务发现组件进行结合,通过service-id(必须设置成大写)转发到具体的服务实例。默认false
    19. #为true代表开启基于服务发现的路由规则。
    20. enabled: false
    21. #配置之后访问时service-id无需大写
    22. lower-case-service-id: true
    23. routes:
    24. # 路由标识(id:标识,具有唯一性)
    25. - id: user-consumer-api
    26. #目标服务地址(uri:地址,请求转发后的地址),会自动从注册中心获得服务的IP,不需要手动写死
    27. uri: lb://nacos-consumer
    28. #优先级,越小越优先
    29. #order: 999
    30. #路由条件(predicates:断言)
    31. predicates:
    32. # 路径匹配,
    33. - Path=/aa/**
    34. filters:
    35. #路径前缀删除示例:请求/name/bar/foo,StripPrefix=2,去除掉前面两个前缀之后,最后转发到目标服务的路径为/foo
    36. #前缀过滤,请求地址:http://localhost:8084/usr/hello
    37. #此处配置去掉1个路径前缀,再配置上面的 Path=/usr/**,就将**转发到指定的微服务
    38. #因为这个api相当于是服务名,只是为了方便以后nginx的代码加上去的,对于服务提供者service-client来说,不需要这段地址,所以需要去掉
    39. - StripPrefix=1
    40. #限流
    41. - name: RequestRateLimiter
    42. args:
    43. #用于限流的键的解析器的 Bean 对象的名字,使用 SpEL表达式根据#{@beanName}获取Bean对象
    44. key-resolver: '#{@ipAddrKeyResolver}'
    45. #令牌桶填充速率,允许用户每秒处理多少个请求
    46. redis-rate-limiter.replenishRate: 10
    47. #令牌桶总容量,允许在一秒钟内完成的最大请求数
    48. redis-rate-limiter.burstCapacity: 20
    49. # # 路由标识(id:标识,具有唯一性)
    50. # - id: user-provider-api
    51. # #目标服务地址(uri:地址,请求转发后的地址),会自动从注册中心获得服务的IP,不需要手动写死
    52. # uri: lb://nacos-provider
    53. # #优先级,越小越优先
    54. # #order: 999
    55. # #路由条件(predicates:断言)
    56. # predicates:
    57. # # 路径匹配,
    58. # - Path=/bb/**
    59. # filters:
    60. # #路径前缀删除示例:请求/name/bar/foo,StripPrefix=2,去除掉前面两个前缀之后,最后转发到目标服务的路径为/foo
    61. # #前缀过滤,请求地址:http://localhost:8084/usr/hello
    62. # #此处配置去掉1个路径前缀,再配置上面的 Path=/usr/**,就将**转发到指定的微服务
    63. # #因为这个api相当于是服务名,只是为了方便以后nginx的代码加上去的,对于服务提供者service-client来说,不需要这段地址,所以需要去掉
    64. # - StripPrefix=1
    65. #自定义动态路由配置
    66. gateway:
    67. nacos:
    68. server-addr: ${spring.cloud.nacos.discovery.server-addr}
    69. # namespace: xxx-xx-xx-xx
    70. data-id: gateway.json
    71. group: DEFAULT_GROUP

    3. JMeter压力测试

    压力测试是每一个Web应用程序上线之前都需要做的一个测试,他可以帮助我们发现系统中 的瓶颈问 题,减少发布到生产环境后出问题的几率 预估系统的承载能力,使我们能根据其做出一些应对措施。所以压力测试是一个非常重要的步骤

    4. 熔断

    在分布式系统中,网关作为流量的入口,大量请求进入网关,向后端远程系统或服务发起调用, 后端服务不可避免的会产生调用失败(超时或者异常),失败时不能让请求堆积在网关上,需要快速失 败并返回回去, 这就需要在网关上做熔断、降级操作。 

       4.1 添加熔断配置 

    1. filters:
    2. - name: Hystrix
    3. args:
    4. name: fallback
    5. fallbackUri: forward:/fallback
    1. hystrix:
    2. command:
    3. default:
    4. execution:
    5. isolation:
    6. thread:
    7. timeoutInMilliseconds: 300

       4.2 整合yml文件参考

    1. server:
    2. port: 8084
    3. spring:
    4. application:
    5. name: nacos-gateway
    6. redis:
    7. host: 127.0.0.1
    8. port: 6379
    9. password: 1234
    10. database: 0
    11. cloud:
    12. nacos:
    13. discovery:
    14. server-addr: 127.0.0.1:8848
    15. gateway:
    16. discovery:
    17. locator:
    18. #是否与服务发现组件进行结合,通过service-id(必须设置成大写)转发到具体的服务实例。默认false
    19. #为true代表开启基于服务发现的路由规则。
    20. enabled: false
    21. #配置之后访问时service-id无需大写
    22. lower-case-service-id: true
    23. routes:
    24. # 路由标识(id:标识,具有唯一性)
    25. - id: user-consumer-api
    26. #目标服务地址(uri:地址,请求转发后的地址),会自动从注册中心获得服务的IP,不需要手动写死
    27. uri: lb://nacos-consumer
    28. #优先级,越小越优先
    29. #order: 999
    30. #路由条件(predicates:断言)
    31. predicates:
    32. # 路径匹配,
    33. - Path=/aa/**
    34. filters:
    35. #路径前缀删除示例:请求/name/bar/foo,StripPrefix=2,去除掉前面两个前缀之后,最后转发到目标服务的路径为/foo
    36. #前缀过滤,请求地址:http://localhost:8084/usr/hello
    37. #此处配置去掉1个路径前缀,再配置上面的 Path=/usr/**,就将**转发到指定的微服务
    38. #因为这个api相当于是服务名,只是为了方便以后nginx的代码加上去的,对于服务提供者service-client来说,不需要这段地址,所以需要去掉
    39. - StripPrefix=1
    40. #限流
    41. - name: RequestRateLimiter
    42. args:
    43. #用于限流的键的解析器的 Bean 对象的名字,使用 SpEL表达式根据#{@beanName}获取Bean对象
    44. key-resolver: '#{@ipAddrKeyResolver}'
    45. #令牌桶填充速率,允许用户每秒处理多少个请求
    46. redis-rate-limiter.replenishRate: 10
    47. #令牌桶总容量,允许在一秒钟内完成的最大请求数
    48. redis-rate-limiter.burstCapacity: 20
    49. #熔断
    50. - name: Hystrix
    51. args:
    52. name: fallback
    53. #降级时返回的路径
    54. fallbackUri: forward:/fallback
    55. # # 路由标识(id:标识,具有唯一性)
    56. # - id: user-provider-api
    57. # #目标服务地址(uri:地址,请求转发后的地址),会自动从注册中心获得服务的IP,不需要手动写死
    58. # uri: lb://nacos-provider
    59. # #优先级,越小越优先
    60. # #order: 999
    61. # #路由条件(predicates:断言)
    62. # predicates:
    63. # # 路径匹配,
    64. # - Path=/bb/**
    65. # filters:
    66. # #路径前缀删除示例:请求/name/bar/foo,StripPrefix=2,去除掉前面两个前缀之后,最后转发到目标服务的路径为/foo
    67. # #前缀过滤,请求地址:http://localhost:8084/usr/hello
    68. # #此处配置去掉1个路径前缀,再配置上面的 Path=/usr/**,就将**转发到指定的微服务
    69. # #因为这个api相当于是服务名,只是为了方便以后nginx的代码加上去的,对于服务提供者service-client来说,不需要这段地址,所以需要去掉
    70. # - StripPrefix=1
    71. #自定义动态路由配置
    72. gateway:
    73. nacos:
    74. server-addr: ${spring.cloud.nacos.discovery.server-addr}
    75. # namespace: xxx-xx-xx-xx
    76. data-id: gateway.json
    77. group: DEFAULT_GROUP

        4.3 服务器降级响应处理

    1. package com.jmh.nacos_gateway.controller;
    2. import org.springframework.web.bind.annotation.RequestMapping;
    3. import org.springframework.web.bind.annotation.RestController;
    4. import java.util.HashMap;
    5. import java.util.Map;
    6. /**
    7. * @author 蒋明辉
    8. * @data 2022/11/9 18:01
    9. */
    10. @RestController
    11. public class HystrixController {
    12. @RequestMapping("/fallback")
    13. public Object fallback(){
    14. Map map=new HashMap();
    15. map.put("code","204");
    16. map.put("msg","服务降级了");
    17. return map;
    18. }
    19. }
  • 相关阅读:
    HDF5文件数据读取
    Linux命令(115)之journalctl
    Python视频剪辑AutoCut在文档中合成制作口播视频
    hadoop的日志知识点
    51.Sentinel微服务保护
    java计算机毕业设计三门峡市旅游景点一站式服务规划系统演示录像源码+数据库+系统+lw文档+mybatis+运行部署
    有想法就去设计吧!——《好玩的好设计》读书笔记
    CMS知识小结及wordpress的安装与漏洞复现
    GemBox.Bundle 47.0.1315 最新Crack
    竞赛 深度学习 机器视觉 人脸识别系统 - opencv python
  • 原文地址:https://blog.csdn.net/m0_63300795/article/details/127775243