mirror of
https://github.com/Snailclimb/JavaGuide
synced 2025-06-16 18:10:13 +08:00
[docs add&update]规范目录+新增Spring Cloud Gateway常见问题总结
This commit is contained in:
parent
ccf963b5eb
commit
0e662ff9be
38
README.md
38
README.md
@ -324,14 +324,27 @@ JVM 这部分内容主要参考 [JVM 虚拟机规范-Java8 ](https://docs.oracle
|
|||||||
|
|
||||||
### 理论&算法&协议
|
### 理论&算法&协议
|
||||||
|
|
||||||
- [CAP 理论和 BASE 理论详解](./docs/distributed-system/protocol/cap-and-base-theorem.md)
|
- [CAP 理论和 BASE 理论解读](./docs/distributed-system/protocol/cap-and-base-theorem.md)
|
||||||
- [Paxos 算法详解](./docs/distributed-system/protocol/paxos-algorithm.md)
|
- [Paxos 算法解读](./docs/distributed-system/protocol/paxos-algorithm.md)
|
||||||
- [Raft 算法详解](./docs/distributed-system/protocol/raft-algorithm.md)
|
- [Raft 算法解读](./docs/distributed-system/protocol/raft-algorithm.md)
|
||||||
- [Gossip 协议详解](./docs/distributed-system/protocol/gossip-protocl.md)
|
- [Gossip 协议详解](./docs/distributed-system/protocol/gossip-protocl.md)
|
||||||
|
|
||||||
|
### RPC
|
||||||
|
|
||||||
|
- [RPC 基础知识总结](./docs/distributed-system/rpc/rpc-intro.md)
|
||||||
|
- [Dubbo 常见知识点&面试题总结](./docs/distributed-system/rpc/dubbo.md)
|
||||||
|
|
||||||
|
### ZooKeeper
|
||||||
|
|
||||||
|
> 这两篇文章可能有内容重合部分,推荐都看一遍。
|
||||||
|
|
||||||
|
- [ZooKeeper 相关概念总结(入门)](./docs/distributed-system/distributed-process-coordination/zookeeper/zookeeper-intro.md)
|
||||||
|
- [ZooKeeper 相关概念总结(进阶)](./docs/distributed-system/distributed-process-coordination/zookeeper/zookeeper-plus.md)
|
||||||
|
|
||||||
### API 网关
|
### API 网关
|
||||||
|
|
||||||
[API 网关详解](./docs/distributed-system/api-gateway.md)
|
- [API 网关基础知识总结](./docs/distributed-system/api-gateway.md)
|
||||||
|
- [Spring Cloud Gateway 常见知识点&面试题总结](./docs/distributed-system/spring-cloud-gateway-questions.md)
|
||||||
|
|
||||||
### 分布式 ID
|
### 分布式 ID
|
||||||
|
|
||||||
@ -349,19 +362,6 @@ JVM 这部分内容主要参考 [JVM 虚拟机规范-Java8 ](https://docs.oracle
|
|||||||
|
|
||||||
[分布式配置中心详解](./docs/distributed-system/distributed-configuration-center.md)
|
[分布式配置中心详解](./docs/distributed-system/distributed-configuration-center.md)
|
||||||
|
|
||||||
### RPC
|
|
||||||
|
|
||||||
- [RPC 基础常见知识点&面试题总结](./docs/distributed-system/rpc/rpc-intro.md)
|
|
||||||
- [Dubbo 常见知识点&面试题总结](./docs/distributed-system/rpc/dubbo.md)
|
|
||||||
|
|
||||||
### ZooKeeper
|
|
||||||
|
|
||||||
> 前两篇文章可能有内容重合部分,推荐都看一遍。
|
|
||||||
|
|
||||||
- [ZooKeeper 相关概念总结(入门)](./docs/distributed-system/distributed-process-coordination/zookeeper/zookeeper-intro.md)
|
|
||||||
- [ZooKeeper 相关概念总结(进阶)](./docs/distributed-system/distributed-process-coordination/zookeeper/zookeeper-plus.md)
|
|
||||||
- [ZooKeeper 实战](./docs/distributed-system/distributed-process-coordination/zookeeper/zookeeper-in-action.md)
|
|
||||||
|
|
||||||
## 高性能
|
## 高性能
|
||||||
|
|
||||||
### 数据库读写分离&分库分表
|
### 数据库读写分离&分库分表
|
||||||
@ -382,8 +382,8 @@ JVM 这部分内容主要参考 [JVM 虚拟机规范-Java8 ](https://docs.oracle
|
|||||||
|
|
||||||
### 消息队列
|
### 消息队列
|
||||||
|
|
||||||
消息队列在分布式系统中主要是为了解耦和削峰。相关阅读: [消息队列常见问题总结](./docs/high-performance/message-queue/message-queue.md)。
|
- [消息队列基础知识总结](./docs/high-performance/message-queue/message-queue.md)
|
||||||
|
- [Disruptor 常见面试题](./docs/high-performance/message-queue/disruptor-questions.md)
|
||||||
- [RabbitMQ 常见面试题](./docs/high-performance/message-queue/rabbitmq-questions.md)
|
- [RabbitMQ 常见面试题](./docs/high-performance/message-queue/rabbitmq-questions.md)
|
||||||
- [RocketMQ 常见面试题总结](./docs/high-performance/message-queue/rocketmq-questions.md)
|
- [RocketMQ 常见面试题总结](./docs/high-performance/message-queue/rocketmq-questions.md)
|
||||||
- [Kafka 常见问题总结](./docs/high-performance/message-queue/kafka-questions-01.md)
|
- [Kafka 常见问题总结](./docs/high-performance/message-queue/kafka-questions-01.md)
|
||||||
|
@ -23,11 +23,7 @@ export default sidebar({
|
|||||||
icon: "star",
|
icon: "star",
|
||||||
collapsible: true,
|
collapsible: true,
|
||||||
prefix: "javaguide/",
|
prefix: "javaguide/",
|
||||||
children: [
|
children: ["intro", "contribution-guideline", "faq"],
|
||||||
"intro",
|
|
||||||
"contribution-guideline",
|
|
||||||
"faq",
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: "面试准备",
|
text: "面试准备",
|
||||||
@ -462,28 +458,45 @@ export default sidebar({
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: "RPC详解",
|
text: "RPC",
|
||||||
prefix: "rpc/",
|
prefix: "rpc/",
|
||||||
icon: "network",
|
icon: "network",
|
||||||
collapsible: true,
|
|
||||||
children: ["rpc-intro", "dubbo"],
|
children: ["rpc-intro", "dubbo"],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: "ZooKeeper 详解",
|
text: "ZooKeeper",
|
||||||
icon: "framework",
|
icon: "framework",
|
||||||
prefix: "distributed-process-coordination/",
|
prefix: "distributed-process-coordination/zookeeper/",
|
||||||
collapsible: true,
|
|
||||||
children: [
|
children: [
|
||||||
"zookeeper/zookeeper-intro",
|
"zookeeper-intro",
|
||||||
"zookeeper/zookeeper-plus",
|
"zookeeper-plus",
|
||||||
"zookeeper/zookeeper-in-action",
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
"api-gateway",
|
{
|
||||||
"distributed-id",
|
text: "API网关",
|
||||||
"distributed-lock",
|
icon: "gateway",
|
||||||
"distributed-transaction",
|
children: ["api-gateway","spring-cloud-gateway-questions"],
|
||||||
"distributed-configuration-center",
|
},
|
||||||
|
{
|
||||||
|
text: "分布式ID",
|
||||||
|
icon: "id",
|
||||||
|
children: ["distributed-id"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: "分布式锁",
|
||||||
|
icon: "lock",
|
||||||
|
children: ["distributed-lock"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: "分布式事务",
|
||||||
|
icon: "transanction",
|
||||||
|
children: ["distributed-transaction"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: "分布式配置中心",
|
||||||
|
icon: "configuration",
|
||||||
|
children: ["distributed-configuration-center"],
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -491,11 +504,25 @@ export default sidebar({
|
|||||||
icon: "et-performance",
|
icon: "et-performance",
|
||||||
prefix: "high-performance/",
|
prefix: "high-performance/",
|
||||||
collapsible: true,
|
collapsible: true,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
text: "CDN",
|
||||||
|
icon: "cdn",
|
||||||
|
children: ["cdn"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: "负载均衡",
|
||||||
|
icon: "fuzaijunheng",
|
||||||
|
children: ["load-balancing"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: "数据库优化",
|
||||||
|
icon: "mysql",
|
||||||
children: [
|
children: [
|
||||||
"read-and-write-separation-and-library-subtable",
|
"read-and-write-separation-and-library-subtable",
|
||||||
"load-balancing",
|
|
||||||
"cdn",
|
|
||||||
"sql-optimization",
|
"sql-optimization",
|
||||||
|
],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
text: "消息队列",
|
text: "消息队列",
|
||||||
prefix: "message-queue/",
|
prefix: "message-queue/",
|
||||||
@ -503,6 +530,7 @@ export default sidebar({
|
|||||||
collapsible: true,
|
collapsible: true,
|
||||||
children: [
|
children: [
|
||||||
"message-queue",
|
"message-queue",
|
||||||
|
"disruptor-questions",
|
||||||
"kafka-questions-01",
|
"kafka-questions-01",
|
||||||
"rocketmq-questions",
|
"rocketmq-questions",
|
||||||
"rabbitmq-questions",
|
"rabbitmq-questions",
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
---
|
---
|
||||||
title: API网关详解
|
title: API网关基础知识总结
|
||||||
category: 分布式
|
category: 分布式
|
||||||
icon: "gateway"
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 什么是网关?
|
## 什么是网关?
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
---
|
---
|
||||||
title: 分布式配置中心详解(付费)
|
title: 分布式配置中心常见问题总结(付费)
|
||||||
category: 分布式
|
category: 分布式
|
||||||
icon: "configuration"
|
|
||||||
---
|
---
|
||||||
|
|
||||||
**分布式配置中心** 相关的面试题为我的[知识星球](https://javaguide.cn/about-the-author/zhishixingqiu-two-years.html)(点击链接即可查看详细介绍以及加入方法)专属内容,已经整理到了《Java 面试指北》中。
|
**分布式配置中心** 相关的面试题为我的[知识星球](https://javaguide.cn/about-the-author/zhishixingqiu-two-years.html)(点击链接即可查看详细介绍以及加入方法)专属内容,已经整理到了《Java 面试指北》中。
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
---
|
---
|
||||||
title: 分布式ID详解
|
title: 分布式ID常见问题总结
|
||||||
category: 分布式
|
category: 分布式
|
||||||
icon: "id"
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 分布式 ID 介绍
|
## 分布式 ID 介绍
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
---
|
---
|
||||||
title: 分布式锁详解
|
title: 分布式锁常见问题总结
|
||||||
category: 分布式
|
category: 分布式
|
||||||
icon: "lock"
|
|
||||||
---
|
---
|
||||||
|
|
||||||
网上有很多分布式锁相关的文章,写了一个相对简洁易懂的版本,针对面试和工作应该够用了。
|
网上有很多分布式锁相关的文章,写了一个相对简洁易懂的版本,针对面试和工作应该够用了。
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
title: ZooKeeper 相关概念总结(入门)
|
title: ZooKeeper相关概念总结(入门)
|
||||||
category: 分布式
|
category: 分布式
|
||||||
tag:
|
tag:
|
||||||
- ZooKeeper
|
- ZooKeeper
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
title: ZooKeeper 相关概念总结(进阶)
|
title: ZooKeeper相关概念总结(进阶)
|
||||||
category: 分布式
|
category: 分布式
|
||||||
tag:
|
tag:
|
||||||
- ZooKeeper
|
- ZooKeeper
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
---
|
---
|
||||||
title: 分布式事务详解(付费)
|
title: 分布式事务常见问题总结(付费)
|
||||||
category: 分布式
|
category: 分布式
|
||||||
icon: "transanction"
|
|
||||||
---
|
---
|
||||||
|
|
||||||
**分布式事务** 相关的面试题为我的[知识星球](https://javaguide.cn/about-the-author/zhishixingqiu-two-years.html)(点击链接即可查看详细介绍以及加入方法)专属内容,已经整理到了《Java 面试指北》中。
|
**分布式事务** 相关的面试题为我的[知识星球](https://javaguide.cn/about-the-author/zhishixingqiu-two-years.html)(点击链接即可查看详细介绍以及加入方法)专属内容,已经整理到了《Java 面试指北》中。
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
title: Dubbo 常见面试题总结
|
title: Dubbo常见问题总结
|
||||||
category: 分布式
|
category: 分布式
|
||||||
tag:
|
tag:
|
||||||
- rpc
|
- rpc
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
title: RPC 基础常见面试题总结
|
title: RPC基础知识总结
|
||||||
category: 分布式
|
category: 分布式
|
||||||
tag:
|
tag:
|
||||||
- rpc
|
- rpc
|
||||||
|
155
docs/distributed-system/spring-cloud-gateway-questions.md
Normal file
155
docs/distributed-system/spring-cloud-gateway-questions.md
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
---
|
||||||
|
title: Spring Cloud Gateway常见问题总结
|
||||||
|
category: 分布式
|
||||||
|
---
|
||||||
|
|
||||||
|
> 本文重构完善自[6000 字 | 16 图 | 深入理解 Spring Cloud Gateway 的原理 - 悟空聊架构](https://mp.weixin.qq.com/s/XjFYsP1IUqNzWqXZdJn-Aw)这篇文章。
|
||||||
|
|
||||||
|
## 什么是 Spring Cloud Gateway?
|
||||||
|
|
||||||
|
Spring Cloud Gateway 属于 Spring Cloud 生态系统中的网关,其诞生的目标是为了替代老牌网关 **Zuul**。准确点来说,应该是 Zuul 1.x。Spring Cloud Gateway 起步要比 Zuul 2.x 更早。
|
||||||
|
|
||||||
|
为了提升网关的性能,Spring Cloud Gateway 基于 Spring WebFlux 。Spring WebFlux 使用 Reactor 库来实现响应式编程模型,底层基于 Netty 实现同步非阻塞的 I/O。
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
Spring Cloud Gateway 不仅提供统一的路由方式,并且基于 Filter 链的方式提供了网关基本的功能,例如:安全,监控/指标,限流。
|
||||||
|
|
||||||
|
Spring Cloud Gateway 和 Zuul 2.x 的差别不大,也是通过过滤器来处理请求。不过,目前更加推荐使用 Spring Cloud Gateway 而非 Zuul,Spring Cloud 生态对其支持更加友好。
|
||||||
|
|
||||||
|
- Github 地址 : <https://github.com/spring-cloud/spring-cloud-gateway>
|
||||||
|
- 官网 : <https://spring.io/projects/spring-cloud-gateway>
|
||||||
|
|
||||||
|
## Spring Cloud Gateway 的工作流程?
|
||||||
|
|
||||||
|
Spring Cloud Gateway 的工作流程如下图所示:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
这是 Spring 官方博客中的一张图,原文地址:<https://spring.io/blog/2022/08/26/creating-a-custom-spring-cloud-gateway-filter>。
|
||||||
|
|
||||||
|
具体的流程分析:
|
||||||
|
|
||||||
|
1. **路由判断** :客户端的请求到达网关后,先经过 Gateway Handler Mapping 处理,这里面会做断言(Predicate)判断,看下符合哪个路由规则,这个路由映射后端的某个服务。
|
||||||
|
2. **请求过滤**:然后请求到达 Gateway Web Handler,这里面有很多过滤器,组成过滤器链(Filter Chain),这些过滤器可以对请求进行拦截和修改,比如添加请求头、参数校验等等,有点像净化污水。然后将请求转发到实际的后端服务。这些过滤器逻辑上可以称作 Pre-Filters,Pre 可以理解为“在...之前”。
|
||||||
|
3. **服务处理**:后端服务会对请求进行处理。
|
||||||
|
4. **响应过滤**:后端处理完结果后,返回给 Gateway 的过滤器再次做处理,逻辑上可以称作 Post-Filters,Post 可以理解为“在...之后”。
|
||||||
|
5. **响应返回**:响应经过过滤处理后,返回给客户端。
|
||||||
|
|
||||||
|
总结:客户端的请求先通过匹配规则找到合适的路由,就能映射到具体的服务。然后请求经过过滤器处理后转发给具体的服务,服务处理后,再次经过过滤器处理,最后返回给客户端。
|
||||||
|
|
||||||
|
## Spring Cloud Gateway 的断言是什么?
|
||||||
|
|
||||||
|
断言(Predicate)这个词听起来极其深奥,它是一种编程术语,我们生活中根本就不会用它。说白了它就是对一个表达式进行 if 判断,结果为真或假,如果为真则做这件事,否则做那件事。
|
||||||
|
|
||||||
|
在 Gateway 中,如果客户端发送的请求满足了断言的条件,则映射到指定的路由器,就能转发到指定的服务上进行处理。
|
||||||
|
|
||||||
|
断言配置的示例如下,配置了两个路由规则,有一个 predicates 断言配置,当请求 url 中包含 `api/thirdparty`,就匹配到了第一个路由 `route_thirdparty`。
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
常见的路由断言规则如下图所示:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## Spring Cloud Gateway 的路由和断言是什么关系?
|
||||||
|
|
||||||
|
Route 路由和 Predicate 断言的对应关系如下::
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
- **一对多**:一个路由规则可以包含多个断言。如上图中路由 Route1 配置了三个断言 Predicate。
|
||||||
|
- **同时满足**:如果一个路由规则中有多个断言,则需要同时满足才能匹配。如上图中路由 Route2 配置了两个断言,客户端发送的请求必须同时满足这两个断言,才能匹配路由 Route2。
|
||||||
|
- **第一个匹配成功**:如果一个请求可以匹配多个路由,则映射第一个匹配成功的路由。如上图所示,客户端发送的请求满足 Route3 和 Route4 的断言,但是 Route3 的配置在配置文件中靠前,所以只会匹配 Route3。
|
||||||
|
|
||||||
|
## Spring Cloud Gateway 如何实现动态路由?
|
||||||
|
|
||||||
|
在使用 Spring Cloud Gateway 的时候,官方文档提供的方案总是基于配置文件或代码配置的方式。
|
||||||
|
|
||||||
|
Spring Cloud Gateway 作为微服务的入口,需要尽量避免重启,而现在配置更改需要重启服务不能满足实际生产过程中的动态刷新、实时变更的业务需求,所以我们需要在 Spring Cloud Gateway 运行时动态配置网关。
|
||||||
|
|
||||||
|
实现动态路由的方式有很多种,其中一种推荐的方式是基于 Nacos 配置中心来做。简单来说,我们将将路由配置放在 Nacos 中存储,然后写个监听器监听 Nacos 上配置的变化,将变化后的配置更新到 GateWay 应用的进程内。
|
||||||
|
|
||||||
|
其实这些复杂的步骤并不需要我们手动实现,通过 Nacos Server 和 Spring Cloud Alibaba Nacos Config 即可实现配置的动态变更,官方文档地址:<https://github.com/alibaba/spring-cloud-alibaba/wiki/Nacos-config> 。
|
||||||
|
|
||||||
|
## Spring Cloud Gateway 的过滤器有哪些?
|
||||||
|
|
||||||
|
过滤器 Filter 按照请求和响应可以分为两种:
|
||||||
|
|
||||||
|
- **Pre 类型**:在请求被转发到微服务之前,对请求进行拦截和修改,例如参数校验、权限校验、流量监控、日志输出以及协议转换等操作。
|
||||||
|
- **Post 类型**:微服务处理完请求后,返回响应给网关,网关可以再次进行处理,例如修改响应内容或响应头、日志输出、流量监控等。
|
||||||
|
|
||||||
|
另外一种分类是按照过滤器 Filter 作用的范围进行划分:
|
||||||
|
|
||||||
|
- **GatewayFilter**:局部过滤器,应用在单个路由或一组路由上的过滤器。标红色表示比较常用的过滤器。
|
||||||
|
- **GlobalFilter**:全局过滤器,应用在所有路由上的过滤器。
|
||||||
|
|
||||||
|
### 局部过滤器
|
||||||
|
|
||||||
|
常见的局部过滤器如下图所示:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
具体怎么用呢?这里有个示例,如果 URL 匹配成功,则去掉 URL 中的 “api”。
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
filters: #过滤器
|
||||||
|
- RewritePath=/api/(?<segment>.*),/$\{segment} # 将跳转路径中包含的 “api” 替换成空
|
||||||
|
```
|
||||||
|
|
||||||
|
当然我们也可以自定义过滤器,本篇不做展开。
|
||||||
|
|
||||||
|
### 全局过滤器
|
||||||
|
|
||||||
|
常见的全局过滤器如下图所示:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
全局过滤器最常见的用法是进行负载均衡。配置如下所示:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
spring:
|
||||||
|
cloud:
|
||||||
|
gateway:
|
||||||
|
routes:
|
||||||
|
- id: route_member # 第三方微服务路由规则
|
||||||
|
uri: lb://passjava-member # 负载均衡,将请求转发到注册中心注册的 passjava-member 服务
|
||||||
|
predicates: # 断言
|
||||||
|
- Path=/api/member/** # 如果前端请求路径包含 api/member,则应用这条路由规则
|
||||||
|
filters: #过滤器
|
||||||
|
- RewritePath=/api/(?<segment>.*),/$\{segment} # 将跳转路径中包含的api替换成空
|
||||||
|
```
|
||||||
|
|
||||||
|
这里有个关键字 `lb`,用到了全局过滤器 `LoadBalancerClientFilter`,当匹配到这个路由后,会将请求转发到 passjava-member 服务,且支持负载均衡转发,也就是先将 passjava-member 解析成实际的微服务的 host 和 port,然后再转发给实际的微服务。
|
||||||
|
|
||||||
|
## Spring Cloud Gateway 支持限流吗?
|
||||||
|
|
||||||
|
Spring Cloud Gateway 自带了限流过滤器,对应的接口是 `RateLimiter`,`RateLimiter` 接口只有一个实现类 `RedisRateLimiter` (基于 Redis + Lua 实现的限流),提供的限流功能比较简易且不易使用。
|
||||||
|
|
||||||
|
从 Sentinel 1.6.0 版本开始,Sentinel 引入了 Spring Cloud Gateway 的适配模块,可以提供两种资源维度的限流:route 维度和自定义 API 维度。也就是说,Spring Cloud Gateway 可以结合 Sentinel 实现更强大的网关流量控制。
|
||||||
|
|
||||||
|
## Spring Cloud Gateway 如何自定义全局异常处理?
|
||||||
|
|
||||||
|
在 SpringBoot 项目中,我们捕获全局异常只需要在项目中配置 `@RestControllerAdvice`和 `@ExceptionHandler`就可以了。不过,这种方式在 Spring Cloud Gateway 下不适用。
|
||||||
|
|
||||||
|
Spring Cloud Gateway 提供了多种全局处理的方式,比较常用的一种是实现`ErrorWebExceptionHandler`并重写其中的`handle`方法。
|
||||||
|
|
||||||
|
```java
|
||||||
|
@Order(-1)
|
||||||
|
@Component
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class GlobalErrorWebExceptionHandler implements ErrorWebExceptionHandler {
|
||||||
|
private final ObjectMapper objectMapper;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 参考
|
||||||
|
|
||||||
|
- Spring Cloud Gateway 官方文档:<https://cloud.spring.io/spring-cloud-gateway/reference/html/>
|
||||||
|
- Creating a custom Spring Cloud Gateway Filter:<https://spring.io/blog/2022/08/26/creating-a-custom-spring-cloud-gateway-filter>
|
||||||
|
- 全局异常处理: <https://zhuanlan.zhihu.com/p/347028665>
|
@ -1,7 +1,6 @@
|
|||||||
---
|
---
|
||||||
title: CDN(内容分发网络)详解
|
title: CDN(内容分发网络)详解
|
||||||
category: 高性能
|
category: 高性能
|
||||||
icon: cdn
|
|
||||||
head:
|
head:
|
||||||
- - meta
|
- - meta
|
||||||
- name: keywords
|
- name: keywords
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
---
|
---
|
||||||
title: 负载均衡详解
|
title: 负载均衡详解
|
||||||
category: 高性能
|
category: 高性能
|
||||||
icon: fuzaijunheng
|
|
||||||
head:
|
head:
|
||||||
- - meta
|
- - meta
|
||||||
- name: keywords
|
- name: keywords
|
||||||
|
138
docs/high-performance/message-queue/disruptor-questions.md
Normal file
138
docs/high-performance/message-queue/disruptor-questions.md
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
---
|
||||||
|
title: Disruptor常见面试题总结
|
||||||
|
category: 高性能
|
||||||
|
tag:
|
||||||
|
- 消息队列
|
||||||
|
---
|
||||||
|
|
||||||
|
Disruptor 是一个相对冷门一些的知识点,不过,如果你的项目经历中用到了 Disruptor 的话,那面试中就很可能会被问到。
|
||||||
|
|
||||||
|
一位球友之前投稿的面经(社招)中就涉及一些 Disruptor 的问题,文章传送门:[圆梦!顺利拿到字节、淘宝、拼多多等大厂 offer!](https://mp.weixin.qq.com/s/C5QMjwEb6pzXACqZsyqC4A) 。
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
这篇文章可以看作是对 Disruptor 做的一个简单总结,每个问题都不会扯太深入,主要针对面试或者速览 Disruptor。
|
||||||
|
|
||||||
|
## Disruptor 是什么?
|
||||||
|
|
||||||
|
Disruptor 是一个开源的高性能内存队列,诞生初衷是为了解决内存队列的性能和内存安全问题,由英国外汇交易公司 LMAX 开发。
|
||||||
|
|
||||||
|
根据 Disruptor 官方介绍,基于 Disruptor 开发的系统 LMAX(新的零售金融交易平台),单线程就能支撑每秒 600 万订单。Martin Fowler 在 2011年写的一篇文章 [The LMAX Architecture](https://martinfowler.com/articles/lmax.html) 中专门介绍过这个 LMAX 系统的架构,感兴趣的可以看看这篇文章。。
|
||||||
|
|
||||||
|
LMAX 公司 2010 年在 QCon 演讲后,Disruptor 获得了业界关注,并获得了 2011 年的 Oracle 官方的 Duke's Choice Awards(Duke 选择大奖)。
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
> “Duke 选择大奖”旨在表彰过去一年里全球个人或公司开发的、最具影响力的 Java 技术应用,由甲骨文公司主办。含金量非常高!
|
||||||
|
|
||||||
|
我专门找到了 Oracle 官方当年颁布获得 Duke's Choice Awards 项目的那篇文章(文章地址:https://blogs.oracle.com/java/post/and-the-winners-arethe-dukes-choice-award) 。从文中可以看出,同年获得此大奖荣誉的还有大名鼎鼎的 Netty 、JRebel 等项目。
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
Disruptor 提供的功能优点类似于 Kafka、RocketMQ 这类分布式队列,不过,其作为范围是 JVM(内存)。
|
||||||
|
|
||||||
|
- Github 地址:<https://github.com/LMAX-Exchange/disruptor>
|
||||||
|
- 官方教程: <https://lmax-exchange.github.io/disruptor/user-guide/index.html>
|
||||||
|
|
||||||
|
关于如何在 Spring Boot 项目中使用 Disruptor,可以看这篇文章:[Spring Boot + Disruptor 实战入门](https://mp.weixin.qq.com/s/0iG5brK3bYF0BgSjX4jRiA) 。
|
||||||
|
|
||||||
|
## 为什么要用 Disruptor?
|
||||||
|
|
||||||
|
Disruptor 主要解决了 JDK 内置线程安全队列的性能和内存安全问题。
|
||||||
|
|
||||||
|
**JDK 中常见的线程安全的队列如下** :
|
||||||
|
|
||||||
|
| 队列名字 | 锁 | 是否有界 |
|
||||||
|
| ----------------------- | ----------------------- | -------- |
|
||||||
|
| `ArrayBlockingQueue` | 加锁(`ReentrantLock`) | 有界 |
|
||||||
|
| `LinkedBlockingQueue` | 加锁(`ReentrantLock`) | 有界 |
|
||||||
|
| `LinkedTransferQueue` | 无锁(`CAS`) | 无界 |
|
||||||
|
| `ConcurrentLinkedQueue` | 无锁(`CAS`) | 无界 |
|
||||||
|
|
||||||
|
从上表中可以看出:这些队列要不就是加锁有界,要不就是无锁无界。而加锁的的队列势必会影响性能,无界的队列又存在内存溢出的风险。
|
||||||
|
|
||||||
|
因此,一般情况下,我们都是不建议使用 JDK 内置线程安全队列。
|
||||||
|
|
||||||
|
**Disruptor 就不一样了!它在无锁的情况下还能保证队列有界,并且还是线程安全的。**
|
||||||
|
|
||||||
|
下面这张图是 Disruptor 官网提供的 Disruptor 和 ArrayBlockingQueue 的延迟直方图对比。
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
Disruptor 真的很快,关于它为什么这么快这个问题,会在后文介绍到。
|
||||||
|
|
||||||
|
此外,Disruptor 还提供了丰富的扩展功能比如支持批量操作、支持多种等待策略。
|
||||||
|
|
||||||
|
## Kafka 和 Disruptor 什么区别?
|
||||||
|
|
||||||
|
- **Kafka** :分布式消息队列,一般用在系统或者服务之间的消息传递,还可以被用作流式处理平台。
|
||||||
|
- **Disruptor** :内存级别的消息队列,一般用在系统内部中线程间的消息传递。
|
||||||
|
|
||||||
|
## 哪些组件用到了 Disruptor?
|
||||||
|
|
||||||
|
用到 Disruptor 的开源项目还是挺多的,这里简单举几个例子:
|
||||||
|
|
||||||
|
- **Log4j2** :Log4j2 是一款常用的日志框架,它基于 Disruptor 来实现异步日志。
|
||||||
|
- **SOFATracer** :SOFATracer 是蚂蚁金服开源的分布式应用链路追踪工具,它基于 Disruptor 来实现异步日志。
|
||||||
|
- **Storm** : Storm 是一个开源的分布式实时计算系统,它基于 Disruptor 来实现工作进程内发生的消息传递(同一 Storm 节点上的线程间,无需网络通信)。
|
||||||
|
- **HBase** :HBase 是一个分布式列存储数据库系统,它基于 Disruptor 来提高写并发性能。
|
||||||
|
- ......
|
||||||
|
|
||||||
|
## Disruptor 核心概念有哪些?
|
||||||
|
|
||||||
|
- **Event** :你可以把 Event 理解为存放在队列中等待消费的消息对象。
|
||||||
|
- **EventFactory** :事件工厂用于生产事件,我们在初始化 `Disruptor` 类的时候需要用到。
|
||||||
|
- **EventHandler** :Event 在对应的 Handler 中被处理,你可以将其理解为生产消费者模型中的消费者。
|
||||||
|
- **EventProcessor** :EventProcessor 持有特定消费者(Consumer)的 Sequence,并提供用于调用事件处理实现的事件循环(Event Loop)。
|
||||||
|
- **Disruptor** :事件的生产和消费需要用到 `Disruptor` 对象。
|
||||||
|
- **RingBuffer** :RingBuffer(环形数组)用于保存事件。
|
||||||
|
- **WaitStrategy** :等待策略。决定了没有事件可以消费的时候,事件消费者如何等待新事件的到来。
|
||||||
|
- **Producer** :生产者,只是泛指调用 `Disruptor` 对象发布事件的用户代码,Disruptor 没有定义特定接口或类型。
|
||||||
|
- **ProducerType** :指定是单个事件发布者模式还是多个事件发布者模式(发布者和生产者的意思类似,我个人比较喜欢用发布者)。
|
||||||
|
- **Sequencer** :Sequencer 是 Disruptor 的真正核心。此接口有两个实现类 `SingleProducerSequencer`、`MultiProducerSequencer` ,它们定义在生产者和消费者之间快速、正确地传递数据的并发算法。
|
||||||
|
|
||||||
|
下面这张图摘自Disruptor 官网,展示了 LMAX 系统使用 Disruptor 的示例。
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## Disruptor 等待策略有哪些?
|
||||||
|
|
||||||
|
**等待策略(WaitStrategy)** 决定了没有事件可以消费的时候,事件消费者如何等待新事件的到来。
|
||||||
|
|
||||||
|
常见的等待策略有下面这些:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
- `BlockingWaitStrategy`:基于 `ReentrantLock`+`Condition` 来实现等待和唤醒操作,实现代码非常简单,是 Disruptor 默认的等待策略。虽然最慢,但也是 CPU 使用率最低和最稳定的选项生产环境推荐使用;
|
||||||
|
- `BusySpinWaitStrategy`:性能很好,存在持续自旋的风险,使用不当会造成 CPU 负载 100%,慎用;
|
||||||
|
- `LiteBlockingWaitStrategy`:基于 `BlockingWaitStrategy` 的轻量级等待策略,在没有锁竞争的时候会省去唤醒操作,但是作者说测试不充分,因此不建议使用;
|
||||||
|
- `TimeoutBlockingWaitStrategy`:带超时的等待策略,超时后会执行业务指定的处理逻辑;
|
||||||
|
- `LiteTimeoutBlockingWaitStrategy`:基于`TimeoutBlockingWaitStrategy`的策略,当没有锁竞争的时候会省去唤醒操作;
|
||||||
|
- `SleepingWaitStrategy`:三段式策略,第一阶段自旋,第二阶段执行 Thread.yield 让出 CPU,第三阶段睡眠执行时间,反复的睡眠;
|
||||||
|
- `YieldingWaitStrategy`:二段式策略,第一阶段自旋,第二阶段执行 Thread.yield 交出 CPU;
|
||||||
|
- `PhasedBackoffWaitStrategy`:四段式策略,第一阶段自旋指定次数,第二阶段自旋指定时间,第三阶段执行 `Thread.yield` 交出 CPU,第四阶段调用成员变量的`waitFor`方法,该成员变量可以被设置为`BlockingWaitStrategy`、`LiteBlockingWaitStrategy`、`SleepingWaitStrategy`三个中的一个。
|
||||||
|
|
||||||
|
## Disruptor 为什么这么快?
|
||||||
|
|
||||||
|
- **RingBuffer(环形数组)** : Disruptor 内部的 RingBuffer 是通过数组实现的。由于这个数组中的所有元素在初始化时一次性全部创建,因此这些元素的内存地址一般来说是连续的。这样做的好处是,当生产者不断往 RingBuffer 中插入新的事件对象时,这些事件对象的内存地址就能够保持连续,从而利用 CPU 缓存的局部性原理,将相邻的事件对象一起加载到缓存中,提高程序的性能。这类似于 MySQL 的预读机制,将连续的几个页预读到内存里。除此之外,RingBuffer 基于数组还支持批量操作(一次处理多个元素)、还可以避免频繁的内存分配和垃圾回收(RingBuffer 是一个固定大小的数组,当向数组中添加新元素时,如果数组已满,则新元素将覆盖掉最旧的元素)。
|
||||||
|
- **避免了伪共享问题** :CPU 缓存内部是按照 Cache Line(缓存行)管理的,一般的 Cache Line 大小在 64 字节左右。Disruptor 为了确保目标字段独占一个 Cache Line,会在目标字段前后增加了 64 个字节的填充(前 56 个字节和后 8 个字节),这样可以避免 Cache Line 的伪共享(False Sharing)问题。
|
||||||
|
- **无锁设计** :Disruptor 采用无锁设计,避免了传统锁机制带来的竞争和延迟。Disruptor 的无锁实现起来比较复杂,主要是基于 CAS 、内存屏障(Memory Barrier)、RingBuffer 等技术实现的。
|
||||||
|
|
||||||
|
综上所述,Disruptor 之所以能够如此快,是基于一系列优化策略的综合作用,既充分利用了现代 CPU 缓存结构的特点,又避免了常见的并发问题和性能瓶颈。
|
||||||
|
|
||||||
|
关于 Disruptor 高性能队列原理的详细介绍,可以查看这篇文章:[Disruptor 高性能队列原理浅析](https://qin.news/disruptor/) (参考了美团技术团队的[高性能队列——Disruptor](https://tech.meituan.com/2016/11/18/disruptor.html)这篇文章)。
|
||||||
|
|
||||||
|
🌈 这里额外补充一点 : **数组中对象元素地址连续为什么可以提高性能?**
|
||||||
|
|
||||||
|
CPU 缓存是通过将最近使用的数据存储在高速缓存中来实现更快的读取速度,并使用预取机制提前加载相邻内存的数据以利用局部性原理。
|
||||||
|
|
||||||
|
在计算机系统中,CPU 主要访问高速缓存和内存。高速缓存是一种速度非常快、容量相对较小的内存,通常被分为多级缓存,其中L1、L2、L3 分别表示一级缓存、二级缓存、三级缓存。越靠近 CPU 的缓存,速度越快,容量也越小。相比之下,内存容量相对较大,但速度较慢。
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
为了加速数据的读取过程,CPU 会先将数据从内存中加载到高速缓存中,如果下一次需要访问相同的数据,就可以直接从高速缓存中读取,而不需要再次访问内存。这就是所谓的 **缓存命中** 。另外,为了利用 **局部性原理** ,CPU 还会根据之前访问的内存地址预取相邻的内存数据,因为在程序中,连续的内存地址通常会被频繁访问到,这样做可以提高数据的缓存命中率,进而提高程序的性能。
|
||||||
|
|
||||||
|
## 参考
|
||||||
|
|
||||||
|
- Disruptor 高性能之道-等待策略:<http://wuwenliang.net/2022/02/28/Disruptor高性能之道-等待策略/>
|
||||||
|
- 《Java 并发编程实战》- 40 | 案例分析(三):高性能队列Disruptor:https://time.geekbang.org/column/article/98134
|
@ -5,6 +5,12 @@ tag:
|
|||||||
- 消息队列
|
- 消息队列
|
||||||
---
|
---
|
||||||
|
|
||||||
|
::: tip
|
||||||
|
|
||||||
|
这篇文章中的消息队列主要指的是分布式消息队列。
|
||||||
|
|
||||||
|
:::
|
||||||
|
|
||||||
“RabbitMQ?”“Kafka?”“RocketMQ?”...在日常学习与开发过程中,我们常常听到消息队列这个关键词。我也在我的多篇文章中提到了这个概念。可能你是熟练使用消息队列的老手,又或者你是不懂消息队列的新手,不论你了不了解消息队列,本文都将带你搞懂消息队列的一些基本理论。
|
“RabbitMQ?”“Kafka?”“RocketMQ?”...在日常学习与开发过程中,我们常常听到消息队列这个关键词。我也在我的多篇文章中提到了这个概念。可能你是熟练使用消息队列的老手,又或者你是不懂消息队列的新手,不论你了不了解消息队列,本文都将带你搞懂消息队列的一些基本理论。
|
||||||
|
|
||||||
如果你是老手,你可能从本文学到你之前不曾注意的一些关于消息队列的重要概念,如果你是新手,相信本文将是你打开消息队列大门的一板砖。
|
如果你是老手,你可能从本文学到你之前不曾注意的一些关于消息队列的重要概念,如果你是新手,相信本文将是你打开消息队列大门的一板砖。
|
||||||
@ -154,7 +160,7 @@ RPC 和消息队列都是分布式微服务系统中重要的组件之一,下
|
|||||||
|
|
||||||
RPC 和消息队列本质上是网络通讯的两种不同的实现机制,两者的用途不同,万不可将两者混为一谈。
|
RPC 和消息队列本质上是网络通讯的两种不同的实现机制,两者的用途不同,万不可将两者混为一谈。
|
||||||
|
|
||||||
## 消息队列技术选型
|
## 分布式消息队列技术选型
|
||||||
|
|
||||||
### 常见的消息队列有哪些?
|
### 常见的消息队列有哪些?
|
||||||
|
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
---
|
---
|
||||||
title: 读写分离和分库分表详解
|
title: 读写分离和分库分表详解
|
||||||
category: 高性能
|
category: 高性能
|
||||||
icon: mysql
|
|
||||||
head:
|
head:
|
||||||
- - meta
|
- - meta
|
||||||
- name: keywords
|
- name: keywords
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
---
|
---
|
||||||
title: 常见SQL优化手段总结(付费)
|
title: 常见SQL优化手段总结(付费)
|
||||||
category: 高性能
|
category: 高性能
|
||||||
icon: SQL
|
|
||||||
head:
|
head:
|
||||||
- - meta
|
- - meta
|
||||||
- name: keywords
|
- name: keywords
|
||||||
|
32
docs/home.md
32
docs/home.md
@ -320,9 +320,22 @@ JVM 这部分内容主要参考 [JVM 虚拟机规范-Java8](https://docs.oracle.
|
|||||||
- [Raft 算法解读](./distributed-system/protocol/raft-algorithm.md)
|
- [Raft 算法解读](./distributed-system/protocol/raft-algorithm.md)
|
||||||
- [Gossip 协议详解](./distributed-system/protocol/gossip-protocl.md)
|
- [Gossip 协议详解](./distributed-system/protocol/gossip-protocl.md)
|
||||||
|
|
||||||
|
### RPC
|
||||||
|
|
||||||
|
- [RPC 基础知识总结](./distributed-system/rpc/rpc-intro.md)
|
||||||
|
- [Dubbo 常见知识点&面试题总结](./distributed-system/rpc/dubbo.md)
|
||||||
|
|
||||||
|
### ZooKeeper
|
||||||
|
|
||||||
|
> 这两篇文章可能有内容重合部分,推荐都看一遍。
|
||||||
|
|
||||||
|
- [ZooKeeper 相关概念总结(入门)](./distributed-system/distributed-process-coordination/zookeeper/zookeeper-intro.md)
|
||||||
|
- [ZooKeeper 相关概念总结(进阶)](./distributed-system/distributed-process-coordination/zookeeper/zookeeper-plus.md)
|
||||||
|
|
||||||
### API 网关
|
### API 网关
|
||||||
|
|
||||||
[API 网关详解](./distributed-system/api-gateway.md)
|
- [API 网关基础知识总结](./distributed-system/api-gateway.md)
|
||||||
|
- [Spring Cloud Gateway 常见知识点&面试题总结](./distributed-system/spring-cloud-gateway-questions.md)
|
||||||
|
|
||||||
### 分布式 ID
|
### 分布式 ID
|
||||||
|
|
||||||
@ -340,19 +353,6 @@ JVM 这部分内容主要参考 [JVM 虚拟机规范-Java8](https://docs.oracle.
|
|||||||
|
|
||||||
[分布式配置中心详解](./distributed-system/distributed-configuration-center.md)
|
[分布式配置中心详解](./distributed-system/distributed-configuration-center.md)
|
||||||
|
|
||||||
### RPC
|
|
||||||
|
|
||||||
- [RPC 基础常见知识点&面试题总结](./distributed-system/rpc/rpc-intro.md)
|
|
||||||
- [Dubbo 常见知识点&面试题总结](./distributed-system/rpc/dubbo.md)
|
|
||||||
|
|
||||||
### ZooKeeper
|
|
||||||
|
|
||||||
> 前两篇文章可能有内容重合部分,推荐都看一遍。
|
|
||||||
|
|
||||||
- [ZooKeeper 相关概念总结(入门)](./distributed-system/distributed-process-coordination/zookeeper/zookeeper-intro.md)
|
|
||||||
- [ZooKeeper 相关概念总结(进阶)](./distributed-system/distributed-process-coordination/zookeeper/zookeeper-plus.md)
|
|
||||||
- [ZooKeeper 实战](./distributed-system/distributed-process-coordination/zookeeper/zookeeper-in-action.md)
|
|
||||||
|
|
||||||
## 高性能
|
## 高性能
|
||||||
|
|
||||||
### 数据库读写分离&分库分表
|
### 数据库读写分离&分库分表
|
||||||
@ -373,8 +373,8 @@ JVM 这部分内容主要参考 [JVM 虚拟机规范-Java8](https://docs.oracle.
|
|||||||
|
|
||||||
### 消息队列
|
### 消息队列
|
||||||
|
|
||||||
消息队列在分布式系统中主要是为了解耦和削峰。相关阅读: [消息队列常见问题总结](./high-performance/message-queue/message-queue.md)。
|
- [消息队列基础知识总结](./high-performance/message-queue/message-queue.md)
|
||||||
|
- [Disruptor 常见面试题](./high-performance/message-queue/disruptor-questions.md)
|
||||||
- [RabbitMQ 常见面试题](./high-performance/message-queue/rabbitmq-questions.md)
|
- [RabbitMQ 常见面试题](./high-performance/message-queue/rabbitmq-questions.md)
|
||||||
- [RocketMQ 常见面试题总结](./high-performance/message-queue/rocketmq-questions.md)
|
- [RocketMQ 常见面试题总结](./high-performance/message-queue/rocketmq-questions.md)
|
||||||
- [Kafka 常见问题总结](./high-performance/message-queue/kafka-questions-01.md)
|
- [Kafka 常见问题总结](./high-performance/message-queue/kafka-questions-01.md)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user