Spring Cloud Gateway
Spring Cloud Gateway#
学习了 Eureka 之后我们知道了 服务提供者 是 消费者 通过 [Eureka] Server 进行访问的,即[Eureka] Server 是 服务提供者的统一入口。那么整个应用中存在那么多 消费者 需要用户进行调用,这个时候用户该怎样访问这些 消费者工程 呢?当然可以像之前那样直接访问这些工程。但这种方式没有统一的消费者工程调用入口,不便于访问与管理.
1.什么是网关#
网关是微服务最边缘的服务,直接暴露给用户,用来做用户和微服务的桥梁
- 没有网关:客户端直接访问我们的微服务,会需要在客户端配置很多的 ip:port,如果
user-service 并发比较大,则无法完成负载均衡
- 有网关:客户端访问网关,网关来访问微服务,(网关可以和注册中心整合,通过服务名
称找到目标的 ip:prot)这样只需要使用服务名称即可访问微服务,可以实现负载均衡,可
以实现 token 拦截,权限验证,限流等操作
2.Spring Cloud Gateway 简介#
你们项目里面 用的什么网关? gateway zuul
它是 Spring Cloud 官方提供的用来取代 zuul(
netflix****)的新一代网关组件
(
zuul:1.0 , 2.0 ,zuul 的本质,一组过滤器,根据自定义的过滤器顺序来执行,本质就是
web 组件 web 三大组件(监听器 过滤器 servlet****)
拦截 springmvc)
Zuul1.0 使用的是 BIO(
Blocking IO) tomcat7.0 以前都是 BIO 性能一般
Zuul2.0 性能好 NIO
AIO 异步非阻塞 io
a+nio = aio = async + no blocking io
它基于 spring5.x,springboot2.x 和 ProjectReactor 等技术。
它的目地是让路由更加简单,灵活,还提供了一些强大的过滤器功能,例如:熔断、限流、重
试,自义定过滤器等 token 校验 ip 黑名单等
SpringCloud Gateway作为Spring Cloud生态的网关,目标是替代Zuul,在SpringCloud2.0
以上的版本中,没有对新版本的 zuul2.0 以上的最新高性能版本进行集成,仍然还是使用的
zuul1.x[可以看项目依赖找到]非 Reactor 模式的老版本。而为了提升网关的性能,
SpringCloud Gateway 是基于 webFlux 框架实现的,而 webFlux 框架底层则使用了高性能
的 Reactor 模式通信框架的 Netty
NIO(非阻塞式 io) BIO 你只需要了解网关能做什么? 网关里面写什么代码 就可以了
3.Spring Cloud Gateway 工作流程#
客户端向 springcloud Gateway 发出请求,然后在 Gateway Handler Mapping 中找到与
请求相匹配的路由,将其发送到 Gateway Web Handler。
Handler 再通过指定的过滤器来将请求发送到我们实际的服务的业务逻辑,然后返回。 过滤器之间用虚线分开是因为过滤器可能会在发送爱丽请求之前【pre】或之后【post】执行业务
逻辑,对其进行加强或处理。
Filter 在 【pre】 类型的过滤器可以做参数校验、权限校验、流量监控、日志输出、协议转
换等
在【post】 类型的过滤器中可以做响应内容、响应头的修改、日志的输出,流量监控等有着
非常重要的作用。
总结:Gateway 的核心逻辑也就是 路由转发 + 执行过滤器链
4.Spring Cloud Gateway 三大核心概念#
4.1 Route(路由)(重点 和 eureka 结合做动态路由)#
路由信息的组成:
由一个 ID、一个目的 URL、一组断言工厂、一组 Filter 组成。
如果路由断言为真,说明请求 URL 和配置路由匹配。
4.2 Predicate(断言)(就是一个返回 bool 的表达式)#
Java 8 中的断言函数。 lambda 四大接口 供给形,消费性,函数型,断言型
Spring Cloud Gateway 中 的 断 言 函 数 输 入 类 型 是 Spring 5.0 框 架 中 的
ServerWebExchange。Spring Cloud Gateway 的断言函数允许开发者去定义匹配来自于
Http Request 中的任何信息比如请求头和参数
4.3 Filter(过滤) (重点)#
一个标准的 Spring WebFilter。
Web 三大组件****(servlet listener filter) mvc
interceptor
Spring Cloud Gateway 中的 Filter 分为两种类型的 Filter,分别是 Gateway Filter 和
Global Filter。过滤器 Filter 将会对请求和响应进行修改处理。
一个是针对某一个路由(路径)的 filter 对某一个接口做限流
一个是针对全局的 filter token ip 黑名单
5.Nginx 和 Gateway 的区别#
Nginx 在做路由,负载均衡,限流之前,都有修改 nginx.conf 的配置文件,把需要负载均衡,
路由,限流的规则加在里面。Eg:使用 nginx 做 tomcat 的负载均衡
但是 gateway 不同,gateway 自动的负载均衡和路由,gateway 和 eureka 高度集成,实现
自动的路由,和 Ribbon 结合,实现了负载均衡(
lb),gateway 也能轻易的实现限流和权限验证。
Nginx(c)比 gateway(java)的性能高一点。
本质的区别呢?
Nginx
(更大 服务器级别的)
Gateway
(项目级别的)
6. Gatewa的两种路由配置方式#
8.1 代码路由方式(掌握)#
package com.example.getawayserver.config;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class RouteConfig {
/**
* 代码的路由 和yml不冲突 都可以用
* 如果你的uri后面给了一个访问地址 和匹配地址相同 那么就不会再凭借
* @param builder
* @return
*/
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder){
return builder.routes()
.route("path_route", r -> r.path("/get").uri("http://httpbin.org"))
.build();
}
}
8.2 使用 yml 方式(重点)#
server:
port: 80 # 网关一般是80
spring:
application:
name: gateway-server
cloud:
gateway:
enabled: true
routes:
- id: login-service-route # 这个是路由的id 保持唯一即可
# uri: http://localhost:8081 # uri统一资源定位符 url 统一资源标识符
uri: http://127.0.0.1:8081
predicates:
- Path=/doLogin/** # 匹配规则 只要你Path匹配上了/doLogin 就往 uri 转发 并且将路径带上
9.Gateway 微服务名动态路由,负载均衡#
9.1 概述#
从之前的配置里面我们可以看到我们的 URL 都是写死的,这不符合我们微服务的要求,我们
微服务是只要知道服务的名字,根据名字去找,而直接写死就没有负载均衡的效果了
默认情况下 Gateway 会根据注册中心的服务列表,以注册中心上微服务名为路径创建动态路
由进行转发,从而实现动态路由的功能
需要注意的是 uri 的协议为 lb(
load Balance****),表示启用 Gateway 的负载均衡功能。
lb://serviceName 是 spring cloud gateway 在微服务中自动为我们创建的负载均衡 uri
协议:就是双方约定的一个接头暗号
http://
9.2 配置文件#
server:
port: 80 # 网关一般是80
spring:
application:
name: gateway-server
cloud:
gateway:
enabled: true # =只要加了依赖 默认开启
routes: # 如果一个服务里面有100个路径 如果我想做负载均衡 ?? 动态路由
- id: login-service-route # 这个是路由的id 保持唯一即可
#uri: http://localhost:8081 # uri统一资源定位符 url 统一资源标识符
uri: lb://login-service # uri统一资源定位符 url 统一资源标识符
predicates: # 断言是给某一个路由来设定的一种匹配规则 默认不能作用在动态路由上
- Path=/doLogin # 匹配规则 只要你Path匹配上了/doLogin 就往 uri 转发 并且将路径带上
- After=2022-03-22T08:42:59.521+08:00[Asia/Shanghai]
- Method=GET,POST
discovery:
locator:
enabled: true # 开启动态路由 开启通用应用名称 找到服务的功能
lower-case-service-id: true # 开启服务名称小写
# 向eureka组成,得到负载均衡功能
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka
registry-fetch-interval-seconds: 3 # 网关拉去服务列表的时间缩短
instance:
hostname: localhost
instance-id: ${eureka.instance.hostname}:${spring.application.name}:${server.port}
9.3 两种访问方式#
http://localhost/login-service/doLogin login-service(服务名称)
10. Predicate 断言工厂的使用【了解】#
在 gateway 启动时会去加载一些路由断言工厂(判断一句话是否正确 一个 boolean 表达式 )
10.1 什么是断言,Gateway 里面有哪些断言#
断言就是路由添加一些条件(丰富路由功能的)
通俗的说,断言就是一些布尔表达式,满足条件的返回 true,不满足的返回 false。
Spring Cloud Gateway 将路由作为 Spring WebFlux HandlerMapping 基础架构的一部分
进行匹配。Spring Cloud Gateway 包括许多内置的路由断言工厂。所有这些断言都与 HTTP
请求的不同属性匹配。您可以将多个路由断言可以组合使用
Spring Cloud Gateway 创建对象时,使用 RoutePredicateFactory 创建 Predicate 对象,
Predicate 对象可以赋值给 Route
10.2如何使用这些断言#
我们常用yml配置文件的方式进行配置
cloud:
gateway:
enabled: true # =只要加了依赖 默认开启
routes: # 如果一个服务里面有100个路径 如果我想做负载均衡 ?? 动态路由
- id: login-service-route # 这个是路由的id 保持唯一即可
#uri: http://localhost:8081 # uri统一资源定位符 url 统一资源标识符
uri: lb://login-service # uri统一资源定位符 url 统一资源标识符
predicates: # 断言是给某一个路由来设定的一种匹配规则 默认不能作用在动态路由上
- Path=/doLogin # 匹配规则 只要你Path匹配上了/doLogin 就往 uri 转发 并且将路径带上
- After=2022-03-22T08:42:59.521+08:00[Asia/Shanghai]
- Method=GET,POST
- Query=name,admin. #正则表达式的值
predicates: #断言匹配
- Path=/info/** #和服务中的路径匹配,是正则匹配的模式
- After=2020-01-20T17:42:47.789-07:00[Asia/Shanghai] #此断言匹配发生在指定
日期时间之后的请求,ZonedDateTime dateTime=ZonedDateTime.now()获得
- Before=2020-06-18T21:26:26.711+08:00[Asia/Shanghai] #此断言匹配发生在指定
日期时间之前的请求
-
Between=2020-06-18T21:26:26.711+08:00[Asia/Shanghai],2020-06-18T21:32:26.711+08:00[Asia/Shanghai]
#此断言匹配发生在指定日期时间之间的请求
- Cookie=name,xiaobai #Cookie 路由断言工厂接受两个参数,Cookie 名称和 regexp(一
个 Java 正则表达式)。此断言匹配具有给定名称且其值与正则表达式匹配的 cookie
- Header=token,123456 #头路由断言工厂接受两个参数,头名称和 regexp(一个 Java 正
则表达式)。此断言与具有给定名称的头匹配,该头的值与正则表达式匹配。
- Host=**.bai*.com:* #主机路由断言工厂接受一个参数:主机名模式列表。该模式是一
个 ant 样式的模式。作为分隔符。此断言匹配与模式匹配的主机头
- Method=GET,POST #方法路由断言工厂接受一个方法参数,该参数是一个或多个参数:
要匹配的 HTTP 方法
- Query=username,cxs #查询路由断言工厂接受两个参数:一个必需的 param 和一个
可选的 regexp(一个 Java 正则表达式)。
- RemoteAddr=192.168.1.1/24 #RemoteAddr 路由断言工厂接受一个源列表(最小大小 1),
这些源是 cidr 符号(IPv4 或 IPv6)字符串,比如 192.168.1.1/24(其中 192.168.1.1 是 IP 地址,24 是子网掩码)
还有一个访问权重的设置,意思是说:
80%的请求,由 https://weighthigh.org 这个 url 去处理
20%的请求由 https://weightlow.org 去处理
routes:
- id: weight_high
uri: https://weighthigh.org
predicates:
- Weight=group1, 8
- id: weight_low
uri: https://weightlow.org
predicates:
- Weight=group1, 2
11. Filter 过滤器工厂(重点)#
11.1 概述#
gateway 里面的过滤器和 Servlet 里面的过滤器,功能差不多,路由过滤器可以用于修改进入
Http 请求和返回 Http 响应
11.2 分类#
11.2.1 按生命周期分两种#
pre 在业务逻辑之前
post 在业务逻辑之后
11.2.2 按种类分也是两种#
GatewayFilter 需要配置某个路由,才能过滤。如果需要使用全局路由,需要配置 Default
Filters。
GlobalFilter
全局过滤器,不需要配置路由,系统初始化作用到所有路由上
全局过滤器 统计请求次数 限流 token 的校验 ip 黑名单拦截 跨域本质(filter)
144 开头的电话 限制一些 ip 的访问
11.3 官方文档查看过滤器#
11.3.1 单一过滤器(31个)
11.3.2 全局过滤器(9 个
11.4 自定义网关过滤器(重点)#
11.4.1 自定义全局过滤器#
全局过滤器的优点的初始化时默认挂到所有路由上,我们可以使用它来完成 IP 过滤,限流等
功能
11.4.2 创建配置类#
/**
* 定义了一个过滤器
* 十个过滤器
*/
@Component
public class MyGlobalFilter implements GlobalFilter, Ordered {
/**
* 这个就是过滤的方法
* 过滤器链模式
* 责任链模式
* 网关里面有使用 mybatis的 二级缓存有变种责任链模式
*
* @param exchange
* @param chain
* @return
*/
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 针对请求的过滤 拿到请求 header url 参数 ....
ServerHttpRequest request = exchange.getRequest();
// HttpServletRequest 这个是web里面的
// ServerHttpRequest webFlux里面 响应式里面的
String path = request.getURI().getPath();
System.out.println(path);
HttpHeaders headers = request.getHeaders();
System.out.println(headers);
String methodName = request.getMethod().name();
System.out.println(methodName);
String ip = request.getHeaders().getHost().getHostString();
System.out.println(ip);
// 响应相关的数据
ServerHttpResponse response = exchange.getResponse();
// 用了微服务 肯定是前后端分离的 前后端分离 一般前后通过 json
// {"code":200,"msg":"ok"}
// 设置编码 响应头里面置
response.getHeaders().set("content-type","application/json;charset=utf-8");
// 组装业务返回值
HashMap<String, Object> map = new HashMap<>(4);
map.put("code", HttpStatus.UNAUTHORIZED.value());
map.put("msg","你未授权");
ObjectMapper objectMapper = new ObjectMapper();
// 把一个map转成一个字节
byte[] bytes = new byte[0];
try {
bytes = objectMapper.writeValueAsBytes(map);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
// 通过buffer工厂将字节数组包装成 一个数据包
DataBuffer wrap = response.bufferFactory().wrap(bytes);
return response.writeWith(Mono.just(wrap));
// 放行 到下一个过滤器了
// return chain.filter(exchange);
}
/**
* 指定顺序的方法
* 越小越先执行
* @return
*/
@Override
public int getOrder() {
return 0;
}
}
12. IP 认证拦截实战#
12.1 创建 IPGlobalFilter#
/**
* 网关里面 过滤器
* ip拦截
* 请求都有一个源头
* 电话 144 027 010
* 请求------->gateway------->service
* 黑名单 black_list
* 白名单 white_list
* 根据数量
* 像具体的业务服务 一般黑名单
* 一般像数据库 用白名单
*/
@Component
public class IPCheckFilter implements GlobalFilter, Ordered {
/**
* 网关的并发比较高 不要再网关里面直接操作mysql
* 后台系统可以查询数据库 用户量 并发量不大
* 如果并发量大 可以查redis 或者 在内存中写好
*/
public static final List<String> BLACK_LIST = Arrays.asList("127.0.0.1", "144.128.232.147");
/**
* 1.拿到ip
* 2.校验ip是否符合规范
* 3.放行/拦截
*
* @param exchange
* @param chain
* @return
*/
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
String ip = request.getHeaders().getHost().getHostString();
// 查询数据库 看这个ip是否存在黑名单里面 mysql数据库的并发
// 只要是能存储数据地方都叫数据库 redis mysql
if (!BLACK_LIST.contains(ip)) {
return chain.filter(exchange);
}
// 拦截
ServerHttpResponse response = exchange.getResponse();
response.getHeaders().set("content-type","application/json;charset=utf-8");
HashMap<String, Object> map = new HashMap<>(4);
map.put("code", 438);
map.put("msg","你是黑名单");
ObjectMapper objectMapper = new ObjectMapper();
byte[] bytes = new byte[0];
try {
bytes = objectMapper.writeValueAsBytes(map);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
DataBuffer wrap = response.bufferFactory().wrap(bytes);
return response.writeWith(Mono.just(wrap));
}
@Override
public int getOrder() {
return -5;
}
}
13. 限流实战(会问)#
13.1 什么是限流#
通俗的说,限流就是限制一段时间内,用户访问资源的次数,减轻服务器压力,限流大致分为
两种:
1. IP 限流(5s 内同一个 ip 访问超过 3 次,则限制不让访问,过一段时间才可继续访问)
2. 请求量限流(只要在一段时间内(窗口期),请求次数达到阀值,就直接拒绝后面来的访问了,
过一段时间才可以继续访问)(粒度可以细化到一个 api(url),一个服务)
13.2 本次限流模型#
限流模型:漏斗算法 ,令牌桶算法,窗口滑动算法 计数器算法
入不敷出
1)、所有的请求在处理之前都需要拿到一个可用的令牌才会被处理;
2)、根据限流大小,设置按照一定的速率往桶里添加令牌;
3)、桶设置最大的放置令牌限制,当桶满时、新添加的令牌就被丢弃或者拒绝;
4)、请求达到后首先要获取令牌桶中的令牌,拿着令牌才可以进行其他的业务逻辑,处理完
业务逻辑之后,将令牌直接删除;
5)、令牌桶有最低限额,当桶中的令牌达到最低限额的时候,请求处理完之后将不会删除令
牌,以此保证足够的限流;
13.3 Gateway 结合 redis 实现请求量限流#
Spring Cloud Gateway 已经内置了一个 RequestRateLimiterGatewayFilterFactory,我们
可以直接使用。
目前 RequestRateLimiterGatewayFilterFactory 的实现依赖于 Redis,所以我们还要引入
spring-boot-starter-data-redis-reactive。
13.3.1 添加依赖#
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>
13.3.2 修改配置文件#
spring:
application:
name: gateway-server
cloud:
gateway:
enabled: true # =只要加了依赖 默认开启
routes: # 如果一个服务里面有100个路径 如果我想做负载均衡 ?? 动态路由
- id: login-service-route # 这个是路由的id 保持唯一即可
#uri: http://localhost:8081 # uri统一资源定位符 url 统一资源标识符
uri: lb://login-service # uri统一资源定位符 url 统一资源标识符
predicates: # 断言是给某一个路由来设定的一种匹配规则 默认不能作用在动态路由上
- Path=/doLogin # 匹配规则 只要你Path匹配上了/doLogin 就往 uri 转发 并且将路径带上
- After=2022-03-22T08:42:59.521+08:00[Asia/Shanghai]
- Method=GET,POST
- Query=name, admin. #正则表达式的值
filters:
- name: RequestRateLimiter # 这个是过滤器的名称
args: # 这个过滤器的参数
key-resolver: '#{@ipKeyResolver}' # 通过spel表达式取 ioc容器中bean的值
redis-rate-limiter.replenishRate: 1 # 生成令牌的速度
redis-rate-limiter.burstCapacity: 3 # 桶容量
13.3.3 配置文件说明#
在上面的配置文件,配置了 redis 的信息,并配置了 RequestRateLimiter 的限流过滤器,
该过滤器需要配置三个参数:
burstCapacity:令牌桶总容量。
replenishRate:令牌桶每秒填充平均速率。
key-resolver:用于限流的键的解析器的 Bean 对象的名字。它使用 SpEL 表达式根据 #{@beanName}从 Spring 容器中获取 Bean 对象
13.3.4 创建配置类 RequestRateLimiterConfig#
/**
* 自定义请求限制的
*/
@Configuration
public class RequestLimitConfig {
// 针对某一个接口 ip来限流 /doLogin 每一个ip 10s只能访问3次
@Bean
@Primary // 主候选的
public KeyResolver ipKeyResolver() {
return exchange -> Mono.just(exchange.getRequest().getHeaders().getHost().getHostString());
}
// 针对这个路径来限制 /doLogin
// api 就是 接口 外面一般把gateway api网关 新一代网关
@Bean
public KeyResolver apiKeyResolver() {
return exchange -> Mono.just(exchange.getRequest().getPath().value());
}
}
14. 跨域配置#
跨域? ajax 同源策略
8080
8081
因为网关是微服务的边缘 所有的请求都要走网关 跨域的配置只需要写在网关即可
第一种 java配置
@Configuration
public class CorsConfig {
@Bean
public CorsWebFilter corsFilter() {
CorsConfiguration config = new CorsConfiguration();
config.addAllowedMethod("*");
config.addAllowedOrigin("*");
config.addAllowedHeader("*");
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(new PathPatternParser());
source.registerCorsConfiguration("/**", config);
return new CorsWebFilter(source);
}
}
第二种 yml配置
spring:
cloud:
gateway:
globalcors:
cors-configurations:
# 仅在开发环境设置为*
'[/**]':
allowedOrigins: "*"
allowedHeaders: "*"
allowedMethods: "*"
15. 总结和面试#
-
你们网关用的什么 ? Gateway zuul
-
你们网关里面写什么代码?
跨域,路由(动态路由,负载均衡)****ip 黑名单拦截,****Token 的校验,对请求进行过滤(请求
参数校验) 对响应做处理(状态码,响应头) 熔断 限流
微服务的网关,可以很好地将具体的服务和浏览器隔离开,只暴露网关的地址给到浏览器
在微服务网关中,可以很好的实现校验认证,负载均衡(
lb****),黑名单拦截,限流等。
15.1 Gateway 和 zuul 的区别 ZuulFilter#
Zuul 也是 web 网关,本质上就是一组过滤器,按照定义的顺序,来执行过滤操作
二者的区别:
1. 两者均是 web 网关,处理的是 http 请求
2. Gateway 是 springcloud 官方的组件,zuul 则是 netflix 的产品
springcloud,netflix ,alibaba(
nacos,sentinel,dubbo zk,seata,rocketmq****)
3. gateway 在 spring 的支持下,内部实现了限流、负载均衡等,扩展性也更强,但同时也
限制了仅适合于 Spring Cloud 套件。而 zuul 则可以扩展至其他微服务框架中,其内部没有
实现限流、负载均衡等
4. Gateway(Netty NIO)很好的支持异步(spring5.x ,webFlux 响应式编程默认是异步的),
而 zuul****1.0 仅支持同步 BIO zuul2.0 以后也支持异步了
15.2 Nginx 在微服务中的地位#
最后简单聊一下 nginx,在过去几年微服务架构还没有流行的日子里,nginx 已经得到了广大
开发者的认可,其性能高、扩展性强、可以灵活利用 lua 脚本构建插件的特点让人没有抵抗力。
(
nginx 的请求转发 最大并发是多个次,每秒 5w-10w 左右) 3w 左右
有一个能满足我所有需求还很方便我扩展的东西,还免费,凭啥不用??
但是,如今很多微服务架构的项目中不会选择 nginx,我认为原因有以下几点:
微服务框架一般来说是配套的,集成起来更容易
如今微服务架构中,仅有很少的公司会面对无法解决的性能瓶颈,而他们也不会因此使用
nginx,而是选择开发一套适合自己的微服务框架(很多公司会对现有框架进行修改)
spring boot 对于一些模板引擎如 FreeMarker、themleaf 的支持是非常好的,很多应用还没
有达到动、静态文件分离的地步,对 nginx 的需求程度并不大。
动静分离: css js
可以放在 nginx
单体项目需要部署 对 nginx 的使用的需求还是比较大的
斗鱼 不是使用后端技术 如何实现大规模缓存
使用 Nginx 做大规模的静态资源缓存
不是为了用技术而用技术 按照实际业务来 目的是盈利
无论如何,nginx 作为一个好用的组件,最终使不使用它都是由业务来驱动的,只要它能为我
们方便的解决问题,那用它又有何不可呢?
找工作思想: 不要为了用技术而去用技术
ssm 吃一辈子 稳定 挣钱
你想技术提升 跳大厂
先入行 一年就跳槽
15.3 关于限流,面试不会直接问,而是间接来问 问 不卖超#
比如:如果在抢购过程中,用户量请求非常大,怎么确保商品不会卖超
Redis 单线程 (
IO 为什么快,因为我们现在的处理器是多核心数的,redis 底层使用的是
IO 的多路复用)
一般人只会在意商品卖超,而忘记了限流的重要性
Mq(限流 削峰,异步,解耦合)
作者:Esofar
出处:https://www.cnblogs.com/firsthelloworld/p/17439932.html
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)