目录
小白学习SpringCloud 远程通信【OpenFeign】
小白学习SpringCloud 配置中心【Nacos_Config】
2.4 RequestRateLimiterConfig 配置类
学习SpringCloud指南 ☆ ☆ ☆ ☆ ☆
小白学习SpringCloud 使用与Nacos
小白学习SpringCloud 远程通信【OpenFeign】
小白学习SpringCloud 配置中心【Nacos_Config】
小白学习SpringCloud 网关【Gateway】
问题分析
“一码通”一度瘫痪,西安电信遭质疑!崩溃原因到底是什么?_腾讯新闻
从技术角度分析一下,西安一码通为何反复崩溃? - 知乎
主要问题
- 限流问题:市民在长时间无法刷出健康码的情况下,多次退出刷新重试,新的流量到达服务 器,导 致服务器压力变大、承受负载增加,说明“西安一码通”系统没有做好限流措施。
- 服务器问题:无论是企业和个人在租用服务器的时候都会受到峰值承受限制的,一旦超过服 务器的 承受能力,就会导致服务器瘫痪,应用程序暂停,网站无法访问。服务器是有峰值限 制的,不可能 承受无上限的并发能力。而造成服务器瘫痪的原因就是在同一段时间内,访问 人数多,造成高流量 的突进,超出了服务器的承受范围。
- 架构问题:“西安一码通”功能影响“核酸检测”服务,说明模块间从界面到数据调用互相影响, 可能 不是微服务架构。
- 性能过载:典型的性能过载场景,不论内部根因是数据库瓶颈点,还是网络链接数瓶颈点等 等,外 因都是因为过载导致。
- 设计漏洞:没有考虑高流量高负载的情况,导致测试不充分;产品设计未考虑千万级的并发 访问, 交付前未进行同等级的压力测试。
- 压力测试:在市民长时间无法看到健康码的情况下,多次退出刷新重试,新的流量到达服务 器,导 致服务器压力变大、承受负载增加。说明压力测试不够。
1. 限流
限流的目的是通过对并发访问/请求进行限速或者对一个时间窗口内的请求进行限速来保护系统,一旦达 到限制速率则可由拒绝服务,就是定向到错误页或友好的展示页,排队或等待。
限流可以保障我们的 API 服务对所有用户的可用性,也可以防止网络攻击。在高并发的应用中,限流是 一个绕不开的话题。
令牌桶算法
令牌桶算法的原理是系统会以一个恒定的速度往桶里放入令牌,而如果请求需要被处理,则 需要先从桶 里获取一个令牌,当桶里没有令牌可取时,则拒绝服务。
- QPS 每秒请求数,就是说服务器在一秒的时间内处理了多少个请求。
提高带宽
2. Gateway限流的实现
2.1 导入pom依赖
-
<?xml version="1.0" encoding="UTF-8"?>
-
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-
xsi:schemaLocation=
"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
-
<modelVersion>4.0.0
</modelVersion>
-
<groupId>com.jmh
</groupId>
-
<artifactId>nacos_gateway
</artifactId>
-
<version>0.0.1-SNAPSHOT
</version>
-
<name>nacos_gateway
</name>
-
<description>Demo project for Spring Boot
</description>
-
-
<!--提供版本-->
-
<properties>
-
<project.build.sourceEncoding>UTF-8
</project.build.sourceEncoding>
-
<maven.compiler.source>1.8
</maven.compiler.source>
-
<maven.compiler.target>1.8
</maven.compiler.target>
-
<!--<spring-boot.version>2.4.1</spring-boot.version>
-
<spring-cloud.version>2020.0.0</spring-cloud.version>
-
<spring-cloud-alibaba.version>2021.1</spring-cloud-alibaba.version>-->
-
<spring-boot.version>2.3.7.RELEASE
</spring-boot.version>
-
<spring-cloud.version>Hoxton.SR5
</spring-cloud.version>
-
<spring-cloud-alibaba.version>2.1.1.RELEASE
</spring-cloud-alibaba.version>
-
</properties>
-
-
<!--提供依赖-->
-
<dependencies>
-
<dependency>
-
<groupId>org.springframework.boot
</groupId>
-
<artifactId>spring-boot-starter-test
</artifactId>
-
</dependency>
-
<!--注册与发现-->
-
<dependency>
-
<groupId>com.alibaba.cloud
</groupId>
-
<artifactId>spring-cloud-starter-alibaba-nacos-discovery
</artifactId>
-
</dependency>
-
<!--远程通信-->
-
<dependency>
-
<groupId>org.springframework.cloud
</groupId>
-
<artifactId>spring-cloud-starter-openfeign
</artifactId>
-
</dependency>
-
<!--负载均衡-->
-
<dependency>
-
<groupId>org.springframework.cloud
</groupId>
-
<artifactId>spring-cloud-loadbalancer
</artifactId>
-
</dependency>
-
<!--对象赋值依赖-->
-
<dependency>
-
<groupId>ma.glasnost.orika
</groupId>
-
<artifactId>orika-core
</artifactId>
-
<version>1.4.6
</version>
-
</dependency>
-
<dependency>
-
<groupId>org.projectlombok
</groupId>
-
<artifactId>lombok
</artifactId>
-
</dependency>
-
<!--配置中心-->
-
<!-- <dependency>
-
<groupId>com.alibaba.cloud</groupId>
-
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
-
</dependency>
-
<dependency>
-
<groupId>org.springframework.cloud</groupId>
-
<artifactId>spring-cloud-starter-bootstrap</artifactId>
-
</dependency>-->
-
<!--网关-->
-
<dependency>
-
<groupId>org.springframework.boot
</groupId>
-
<artifactId>spring-boot-starter-webflux
</artifactId>
-
</dependency>
-
<dependency>
-
<groupId>org.springframework.cloud
</groupId>
-
<artifactId>spring-cloud-starter-gateway
</artifactId>
-
</dependency>
-
<dependency>
-
<groupId>org.springframework.boot
</groupId>
-
<artifactId>spring-boot-starter-actuator
</artifactId>
-
</dependency>
-
<!--<dependency>
-
<groupId>org.springframework.cloud</groupId>
-
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
-
<version>2.2.9.RELEASE</version>
-
</dependency>-->
-
<dependency>
-
<groupId>io.projectreactor
</groupId>
-
<artifactId>reactor-test
</artifactId>
-
<scope>test
</scope>
-
</dependency>
-
<dependency>
-
<groupId>com.alibaba
</groupId>
-
<artifactId>fastjson
</artifactId>
-
<version>1.2.35
</version>
-
</dependency>
-
<!--限流-->
-
<dependency>
-
<groupId>org.springframework.boot
</groupId>
-
<artifactId>spring-boot-starter-data-redis-reactive
</artifactId>
-
</dependency>
-
<!--熔断-->
-
<dependency>
-
<groupId>org.springframework.cloud
</groupId>
-
<artifactId>spring-cloud-starter-netflix-hystrix
</artifactId>
-
</dependency>
-
</dependencies>
-
-
<!--提供依赖版本-->
-
<dependencyManagement>
-
<dependencies>
-
<dependency>
-
<groupId>org.springframework.boot
</groupId>
-
<artifactId>spring-boot-dependencies
</artifactId>
-
<version>${spring-boot.version}
</version>
-
<type>pom
</type>
-
<scope>import
</scope>
-
</dependency>
-
<dependency>
-
<groupId>org.springframework.cloud
</groupId>
-
<artifactId>spring-cloud-dependencies
</artifactId>
-
<version>${spring-cloud.version}
</version>
-
<type>pom
</type>
-
<scope>import
</scope>
-
</dependency>
-
<dependency>
-
<groupId>com.alibaba.cloud
</groupId>
-
<artifactId>spring-cloud-alibaba-dependencies
</artifactId>
-
<version>${spring-cloud-alibaba.version}
</version>
-
<type>pom
</type>
-
<scope>import
</scope>
-
</dependency>
-
</dependencies>
-
</dependencyManagement>
-
-
-
<build>
-
<plugins>
-
<plugin>
-
<groupId>org.springframework.boot
</groupId>
-
<artifactId>spring-boot-maven-plugin
</artifactId>
-
</plugin>
-
</plugins>
-
</build>
-
-
</project>
- Spring Cloud Gateway官方提供了RequestRateLimiterGatewayFilterFactory类,使用redis和lua脚本 来实现令牌桶的方式。
- Gateway通过内置的RequestRateLimiter过滤器实现限流,使用令牌桶算法,借助Redis保存中间数 据。用户可通过自定义KeyResolver设置限流维度。
- 对请求的目标URL进行限流
- 对来源IP进行限流
- 特定用户进行限流
2.2 添加redis配置
-
redis:
-
host: 127.0.0.1
-
port: 6379
-
# password: root123
-
database: 0
- 如果redis连接失败,限流功能将不能开启。因为没有redis作为容器来保存令牌,限流功能自 然就失效 了。
- 可以将redis的配置信息保存到nacos中,通过添加nacos配置中心客户端的方式进行读取
2.3 添加限流配置
-
filters:
-
- name: RequestRateLimiter
-
args:
-
#用于限流的键的解析器的 Bean 对象的名字,使用 SpEL表达式根据#{@beanName}获取Bean对象
-
key-resolver: '#{@ipAddrKeyResolver}'
-
#令牌桶填充速率,允许用户每秒处理多少个请求
-
redis-rate-limiter.replenishRate: 10
-
#令牌桶总容量,允许在一秒钟内完成的最大请求数
-
redis-rate-limiter.burstCapacity: 20
2.4 RequestRateLimiterConfig 配置类
-
package com.jmh.nacos_gateway;
-
-
import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver;
-
import org.springframework.context.annotation.Bean;
-
import org.springframework.context.annotation.Configuration;
-
import org.springframework.context.annotation.Primary;
-
import reactor.core.publisher.Mono;
-
-
/**
-
* 请求限流配置
-
*/
-
@SuppressWarnings("all")
-
@Configuration
-
public
class
RequestRateLimiterConfig {
-
-
/**
-
* 按IP来限流
-
*/
-
@Bean
-
@Primary
-
public KeyResolver
ipAddrKeyResolver
() {
-
return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getAddress().getHostAddress());
-
}
-
-
/**
-
* 按用户限流
-
*/
-
@Bean
-
KeyResolver
userKeyResolver
() {
-
return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst(
"user"));
-
}
-
-
/**
-
* 按URL限流,即以每秒内请求数按URL分组统计,超出限流的url请求都将返回429状态
-
*
-
* @return
-
*/
-
@Bean
-
KeyResolver
apiKeyResolver
() {
-
return exchange -> Mono.just(exchange.getRequest().getPath().toString());
-
}
-
-
}
2.5 整合yml文件参考
-
server:
-
port: 8084
-
spring:
-
application:
-
name: nacos-gateway
-
redis:
-
host: 127.0.0.1
-
port: 6379
-
password: 1234
-
database: 0
-
cloud:
-
nacos:
-
discovery:
-
server-addr: 127.0.0.1:8848
-
gateway:
-
discovery:
-
locator:
-
#是否与服务发现组件进行结合,通过service-id(必须设置成大写)转发到具体的服务实例。默认false
-
#为true代表开启基于服务发现的路由规则。
-
enabled: false
-
#配置之后访问时service-id无需大写
-
lower-case-service-id: true
-
routes:
-
# 路由标识(id:标识,具有唯一性)
-
- id: user-consumer-api
-
#目标服务地址(uri:地址,请求转发后的地址),会自动从注册中心获得服务的IP,不需要手动写死
-
uri: lb://nacos-consumer
-
#优先级,越小越优先
-
#order: 999
-
#路由条件(predicates:断言)
-
predicates:
-
# 路径匹配,
-
- Path=/aa/**
-
filters:
-
#路径前缀删除示例:请求/name/bar/foo,StripPrefix=2,去除掉前面两个前缀之后,最后转发到目标服务的路径为/foo
-
#前缀过滤,请求地址:http://localhost:8084/usr/hello
-
#此处配置去掉1个路径前缀,再配置上面的 Path=/usr/**,就将**转发到指定的微服务
-
#因为这个api相当于是服务名,只是为了方便以后nginx的代码加上去的,对于服务提供者service-client来说,不需要这段地址,所以需要去掉
-
- StripPrefix=1
-
#限流
-
- name: RequestRateLimiter
-
args:
-
#用于限流的键的解析器的 Bean 对象的名字,使用 SpEL表达式根据#{@beanName}获取Bean对象
-
key-resolver: '#{@ipAddrKeyResolver}'
-
#令牌桶填充速率,允许用户每秒处理多少个请求
-
redis-rate-limiter.replenishRate: 10
-
#令牌桶总容量,允许在一秒钟内完成的最大请求数
-
redis-rate-limiter.burstCapacity: 20
-
# # 路由标识(id:标识,具有唯一性)
-
# - id: user-provider-api
-
# #目标服务地址(uri:地址,请求转发后的地址),会自动从注册中心获得服务的IP,不需要手动写死
-
# uri: lb://nacos-provider
-
# #优先级,越小越优先
-
# #order: 999
-
# #路由条件(predicates:断言)
-
# predicates:
-
# # 路径匹配,
-
# - Path=/bb/**
-
# filters:
-
# #路径前缀删除示例:请求/name/bar/foo,StripPrefix=2,去除掉前面两个前缀之后,最后转发到目标服务的路径为/foo
-
# #前缀过滤,请求地址:http://localhost:8084/usr/hello
-
# #此处配置去掉1个路径前缀,再配置上面的 Path=/usr/**,就将**转发到指定的微服务
-
# #因为这个api相当于是服务名,只是为了方便以后nginx的代码加上去的,对于服务提供者service-client来说,不需要这段地址,所以需要去掉
-
# - StripPrefix=1
-
-
#自定义动态路由配置
-
gateway:
-
nacos:
-
server-addr: ${spring.cloud.nacos.discovery.server-addr}
-
# namespace: xxx-xx-xx-xx
-
data-id: gateway.json
-
group: DEFAULT_GROUP
-
-
3. JMeter压力测试
压力测试是每一个Web应用程序上线之前都需要做的一个测试,他可以帮助我们发现系统中 的瓶颈问 题,减少发布到生产环境后出问题的几率 预估系统的承载能力,使我们能根据其做出一些应对措施。所以压力测试是一个非常重要的步骤
4. 熔断
在分布式系统中,网关作为流量的入口,大量请求进入网关,向后端远程系统或服务发起调用, 后端服务不可避免的会产生调用失败(超时或者异常),失败时不能让请求堆积在网关上,需要快速失 败并返回回去, 这就需要在网关上做熔断、降级操作。
4.1 添加熔断配置
-
filters:
-
- name: Hystrix
-
args:
-
name: fallback
-
fallbackUri: forward:/fallback
-
hystrix:
-
command:
-
default:
-
execution:
-
isolation:
-
thread:
-
timeoutInMilliseconds: 300
4.2 整合yml文件参考
-
server:
-
port: 8084
-
spring:
-
application:
-
name: nacos-gateway
-
redis:
-
host: 127.0.0.1
-
port: 6379
-
password: 1234
-
database: 0
-
cloud:
-
nacos:
-
discovery:
-
server-addr: 127.0.0.1:8848
-
gateway:
-
discovery:
-
locator:
-
#是否与服务发现组件进行结合,通过service-id(必须设置成大写)转发到具体的服务实例。默认false
-
#为true代表开启基于服务发现的路由规则。
-
enabled: false
-
#配置之后访问时service-id无需大写
-
lower-case-service-id: true
-
routes:
-
# 路由标识(id:标识,具有唯一性)
-
- id: user-consumer-api
-
#目标服务地址(uri:地址,请求转发后的地址),会自动从注册中心获得服务的IP,不需要手动写死
-
uri: lb://nacos-consumer
-
#优先级,越小越优先
-
#order: 999
-
#路由条件(predicates:断言)
-
predicates:
-
# 路径匹配,
-
- Path=/aa/**
-
filters:
-
#路径前缀删除示例:请求/name/bar/foo,StripPrefix=2,去除掉前面两个前缀之后,最后转发到目标服务的路径为/foo
-
#前缀过滤,请求地址:http://localhost:8084/usr/hello
-
#此处配置去掉1个路径前缀,再配置上面的 Path=/usr/**,就将**转发到指定的微服务
-
#因为这个api相当于是服务名,只是为了方便以后nginx的代码加上去的,对于服务提供者service-client来说,不需要这段地址,所以需要去掉
-
- StripPrefix=1
-
#限流
-
- name: RequestRateLimiter
-
args:
-
#用于限流的键的解析器的 Bean 对象的名字,使用 SpEL表达式根据#{@beanName}获取Bean对象
-
key-resolver: '#{@ipAddrKeyResolver}'
-
#令牌桶填充速率,允许用户每秒处理多少个请求
-
redis-rate-limiter.replenishRate: 10
-
#令牌桶总容量,允许在一秒钟内完成的最大请求数
-
redis-rate-limiter.burstCapacity: 20
-
#熔断
-
- name: Hystrix
-
args:
-
name: fallback
-
#降级时返回的路径
-
fallbackUri: forward:/fallback
-
# # 路由标识(id:标识,具有唯一性)
-
# - id: user-provider-api
-
# #目标服务地址(uri:地址,请求转发后的地址),会自动从注册中心获得服务的IP,不需要手动写死
-
# uri: lb://nacos-provider
-
# #优先级,越小越优先
-
# #order: 999
-
# #路由条件(predicates:断言)
-
# predicates:
-
# # 路径匹配,
-
# - Path=/bb/**
-
# filters:
-
# #路径前缀删除示例:请求/name/bar/foo,StripPrefix=2,去除掉前面两个前缀之后,最后转发到目标服务的路径为/foo
-
# #前缀过滤,请求地址:http://localhost:8084/usr/hello
-
# #此处配置去掉1个路径前缀,再配置上面的 Path=/usr/**,就将**转发到指定的微服务
-
# #因为这个api相当于是服务名,只是为了方便以后nginx的代码加上去的,对于服务提供者service-client来说,不需要这段地址,所以需要去掉
-
# - StripPrefix=1
-
-
#自定义动态路由配置
-
gateway:
-
nacos:
-
server-addr: ${spring.cloud.nacos.discovery.server-addr}
-
# namespace: xxx-xx-xx-xx
-
data-id: gateway.json
-
group: DEFAULT_GROUP
-
-
4.3 服务器降级响应处理
-
package com.jmh.nacos_gateway.controller;
-
-
import org.springframework.web.bind.annotation.RequestMapping;
-
import org.springframework.web.bind.annotation.RestController;
-
-
import java.util.HashMap;
-
import java.util.Map;
-
-
/**
-
* @author 蒋明辉
-
* @data 2022/11/9 18:01
-
*/
-
@RestController
-
public
class
HystrixController {
-
-
@RequestMapping("/fallback")
-
public Object
fallback
(){
-
Map map=
new
HashMap();
-
map.put(
"code",
"204");
-
map.put(
"msg",
"服务降级了");
-
return map;
-
}
-
-
}
转载:https://blog.csdn.net/m0_63300795/article/details/127775243
查看评论