From 4e2db76ec9997559356371e54e849b0927aeafd7 Mon Sep 17 00:00:00 2001 From: gongjixiaobai Date: Thu, 16 Sep 2021 15:11:28 +0800 Subject: [PATCH 1/9] =?UTF-8?q?Update=20Java=E5=9F=BA=E7=A1=80=E7=9F=A5?= =?UTF-8?q?=E8=AF=86.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Java\345\237\272\347\241\200\347\237\245\350\257\206.md" | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git "a/docs/java/basis/Java\345\237\272\347\241\200\347\237\245\350\257\206.md" "b/docs/java/basis/Java\345\237\272\347\241\200\347\237\245\350\257\206.md" index 78e4e631e1a..6b04bbe5c4b 100644 --- "a/docs/java/basis/Java\345\237\272\347\241\200\347\237\245\350\257\206.md" +++ "b/docs/java/basis/Java\345\237\272\347\241\200\347\237\245\350\257\206.md" @@ -252,7 +252,7 @@ return 用于跳出所在方法,结束该方法的运行。return 一般有两 Java 泛型(generics)是 JDK 5 中引入的一个新特性, 泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型。泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。 -Java 的泛型是伪泛型,这是因为 Java 在编译期间,所有的泛型信息都会被擦掉,这也就是通常所说类型擦除 。 +Java 的泛型是伪泛型,这是因为 Java 在运行期间,所有的泛型信息都会被擦掉,这也就是通常所说类型擦除 。 ```java List list = new ArrayList<>(); From f6bbf59512f6ddec0aa9b68cf7ae718a06ed3210 Mon Sep 17 00:00:00 2001 From: anaer Date: Thu, 16 Sep 2021 15:19:47 +0800 Subject: [PATCH 2/9] =?UTF-8?q?Update=20=E6=9C=8D=E5=8A=A1=E4=B9=8B?= =?UTF-8?q?=E9=97=B4=E7=9A=84=E8=B0=83=E7=94=A8=E4=B8=BA=E5=95=A5=E4=B8=8D?= =?UTF-8?q?=E7=9B=B4=E6=8E=A5=E7=94=A8HTTP=E8=80=8C=E7=94=A8RPC.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit typo --- ...6\216\245\347\224\250HTTP\350\200\214\347\224\250RPC.md" | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git "a/docs/system-design/distributed-system/rpc/\346\234\215\345\212\241\344\271\213\351\227\264\347\232\204\350\260\203\347\224\250\344\270\272\345\225\245\344\270\215\347\233\264\346\216\245\347\224\250HTTP\350\200\214\347\224\250RPC.md" "b/docs/system-design/distributed-system/rpc/\346\234\215\345\212\241\344\271\213\351\227\264\347\232\204\350\260\203\347\224\250\344\270\272\345\225\245\344\270\215\347\233\264\346\216\245\347\224\250HTTP\350\200\214\347\224\250RPC.md" index 532e2cded3f..f3429d2398f 100644 --- "a/docs/system-design/distributed-system/rpc/\346\234\215\345\212\241\344\271\213\351\227\264\347\232\204\350\260\203\347\224\250\344\270\272\345\225\245\344\270\215\347\233\264\346\216\245\347\224\250HTTP\350\200\214\347\224\250RPC.md" +++ "b/docs/system-design/distributed-system/rpc/\346\234\215\345\212\241\344\271\213\351\227\264\347\232\204\350\260\203\347\224\250\344\270\272\345\225\245\344\270\215\347\233\264\346\216\245\347\224\250HTTP\350\200\214\347\224\250RPC.md" @@ -29,7 +29,7 @@ RPC(Remote Procedure Call)—远程过程调用,它是一种通过网络 - **RMI(JDK自带):** JDK自带的RPC,有很多局限性,不推荐使用。 - **Dubbo:** Dubbo是 阿里巴巴公司开源的一个高性能优秀的服务框架,使得应用可通过高性能的 RPC 实现服务的输出和输入功能,可以和 Spring框架无缝集成。目前 Dubbo 已经成为 Spring Cloud Alibaba 中的官方组件。 - **gRPC** :gRPC是可以在任何环境中运行的现代开源高性能RPC框架。它可以通过可插拔的支持来有效地连接数据中心内和跨数据中心的服务,以实现负载平衡,跟踪,运行状况检查和身份验证。它也适用于分布式计算的最后一英里,以将设备,移动应用程序和浏览器连接到后端服务。 -- **Hessian:** Hessian是一个轻量级的remotingonhttp工具,使用简单的方法提供了RMI的功能。 相比WebService,Hessian更简单、快捷。采用的是二进制RPC协议,因为采用的是二进制协议,所以它很适合于发送二进制数据。 +- **Hessian:** Hessian是一个轻量级的remoting on http工具,使用简单的方法提供了RMI的功能。 相比WebService,Hessian更简单、快捷。采用的是二进制RPC协议,因为采用的是二进制协议,所以它很适合于发送二进制数据。 - **Thrift:** Apache Thrift是Facebook开源的跨语言的RPC通信框架,目前已经捐献给Apache基金会管理,由于其跨语言特性和出色的性能,在很多互联网公司得到应用,有能力的公司甚至会基于thrift研发一套分布式服务框架,增加诸如服务注册、服务发现等功能。 ### RPC学习材料 @@ -50,7 +50,7 @@ RPC 只是一种概念、一种设计,就是为了解决 **不同服务之间 > 我们通常谈计算机网络的五层协议的体系结构是指:应用层、传输层、网络层、数据链路层、物理层。 > -> **应用层(application-layer)的任务是通过应用进程间的交互来完成特定网络应用。**HTTP 属于应用层协议,它会基于TCP/IP通信协议来传递数据(HTML 文件, 图片文件, 查询结果等)。HTTP协议工作于客户端-服务端架构为上。浏览器作为HTTP客户端通过 URL 向HTTP服务端即WEB服务器发送所有请求。Web服务器根据接收到的请求后,向客户端发送响应信息。HTTP协议建立在 TCP 协议之上。 +> **应用层(application-layer)的任务是通过应用进程间的交互来完成特定网络应用。** HTTP 属于应用层协议,它会基于TCP/IP通信协议来传递数据(HTML 文件, 图片文件, 查询结果等)。HTTP协议工作于客户端-服务端架构上。浏览器作为HTTP客户端通过 URL 向HTTP服务端即WEB服务器发送所有请求。Web服务器根据接收到的请求后,向客户端发送响应信息。HTTP协议建立在 TCP 协议之上。 > > **运输层(transport layer)的主要任务就是负责向两台主机进程之间的通信提供通用的数据传输服务**。TCP是传输层协议,主要解决数据如何在网络中传输。相比于UDP,**TCP** 提供的是**面向连接**的,**可靠的**数据传输服务。 @@ -65,7 +65,7 @@ RPC 进行服务注册和发现的一方面原因吧! ### 一个常见的错误观点 -很多文章中还会提到说 HTTP 协议相较于自定义 TCP 报文协议,增加的开销在于连接的建立与断开,但是这个观点已经被否认,下面截取自知乎中一个回答,原回答地址:https://www.zhihu.com/question/41609070/answer/191965937。 +很多文章中还会提到说 HTTP 协议相较于自定义 TCP 报文协议,增加的开销在于连接的建立与断开,但是这个观点已经被否认,下面截取自知乎中一个回答,原回答地址:https://www.zhihu.com/question/41609070/answer/191965937 。 >首先要否认一点 HTTP 协议相较于自定义 TCP 报文协议,增加的开销在于连接的建立与断开。HTTP 协议是支持连接池复用的,也就是建立一定数量的连接不断开,并不会频繁的创建和销毁连接。二一要说的是 HTTP 也可以使用 Protobuf 这种二进制编码协议对内容进行编码,因此二者最大的区别还是在传输协议上。 From 35a7876a2956596fa561a3f71b06c75c53bb4782 Mon Sep 17 00:00:00 2001 From: anaer Date: Thu, 16 Sep 2021 15:24:57 +0800 Subject: [PATCH 3/9] =?UTF-8?q?Update=20=E6=9C=8D=E5=8A=A1=E4=B9=8B?= =?UTF-8?q?=E9=97=B4=E7=9A=84=E8=B0=83=E7=94=A8=E4=B8=BA=E5=95=A5=E4=B8=8D?= =?UTF-8?q?=E7=9B=B4=E6=8E=A5=E7=94=A8HTTP=E8=80=8C=E7=94=A8RPC.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...4\346\216\245\347\224\250HTTP\350\200\214\347\224\250RPC.md" | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git "a/docs/system-design/distributed-system/rpc/\346\234\215\345\212\241\344\271\213\351\227\264\347\232\204\350\260\203\347\224\250\344\270\272\345\225\245\344\270\215\347\233\264\346\216\245\347\224\250HTTP\350\200\214\347\224\250RPC.md" "b/docs/system-design/distributed-system/rpc/\346\234\215\345\212\241\344\271\213\351\227\264\347\232\204\350\260\203\347\224\250\344\270\272\345\225\245\344\270\215\347\233\264\346\216\245\347\224\250HTTP\350\200\214\347\224\250RPC.md" index f3429d2398f..2b755e51d27 100644 --- "a/docs/system-design/distributed-system/rpc/\346\234\215\345\212\241\344\271\213\351\227\264\347\232\204\350\260\203\347\224\250\344\270\272\345\225\245\344\270\215\347\233\264\346\216\245\347\224\250HTTP\350\200\214\347\224\250RPC.md" +++ "b/docs/system-design/distributed-system/rpc/\346\234\215\345\212\241\344\271\213\351\227\264\347\232\204\350\260\203\347\224\250\344\270\272\345\225\245\344\270\215\347\233\264\346\216\245\347\224\250HTTP\350\200\214\347\224\250RPC.md" @@ -52,7 +52,7 @@ RPC 只是一种概念、一种设计,就是为了解决 **不同服务之间 > > **应用层(application-layer)的任务是通过应用进程间的交互来完成特定网络应用。** HTTP 属于应用层协议,它会基于TCP/IP通信协议来传递数据(HTML 文件, 图片文件, 查询结果等)。HTTP协议工作于客户端-服务端架构上。浏览器作为HTTP客户端通过 URL 向HTTP服务端即WEB服务器发送所有请求。Web服务器根据接收到的请求后,向客户端发送响应信息。HTTP协议建立在 TCP 协议之上。 > -> **运输层(transport layer)的主要任务就是负责向两台主机进程之间的通信提供通用的数据传输服务**。TCP是传输层协议,主要解决数据如何在网络中传输。相比于UDP,**TCP** 提供的是**面向连接**的,**可靠的**数据传输服务。 +> **传输层(transport layer)的主要任务就是负责向两台主机进程之间的通信提供通用的数据传输服务**。TCP是传输层协议,主要解决数据如何在网络中传输。相比于UDP,**TCP** 提供的是**面向连接**的,**可靠的**数据传输服务。 ### RPC框架功能更齐全 From b412617371f5823b1e0325ee4eeba44874d23ef4 Mon Sep 17 00:00:00 2001 From: anaer Date: Thu, 16 Sep 2021 16:08:13 +0800 Subject: [PATCH 4/9] Update Dubbo.md typo --- docs/system-design/distributed-system/rpc/Dubbo.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/system-design/distributed-system/rpc/Dubbo.md b/docs/system-design/distributed-system/rpc/Dubbo.md index 452c7f1b2f0..90f2fa4d2df 100644 --- a/docs/system-design/distributed-system/rpc/Dubbo.md +++ b/docs/system-design/distributed-system/rpc/Dubbo.md @@ -9,7 +9,7 @@ **为什么要 RPC ?** 因为,两个不同的服务器上的服务提供的方法不在一个内存空间,所以,需要通过网络编程才能传递方法调用所需要的参数。并且,方法调用的结果也需要通过网络编程来接收。但是,如果我们自己手动网络编程来实现这个调用过程的话工作量是非常大的,因为,我们需要考虑底层传输方式(TCP还是UDP)、序列化方式等等方面。 -**RPC 能帮助我们做什么呢? ** 简单来说,通过 RPC 可以帮助我们调用远程计算机上某个服务的方法,这个过程就像调用本地方法一样简单。并且!我们不需要了解底层网络编程的具体细节。 +**RPC 能帮助我们做什么呢?** 简单来说,通过 RPC 可以帮助我们调用远程计算机上某个服务的方法,这个过程就像调用本地方法一样简单。并且!我们不需要了解底层网络编程的具体细节。 举个例子:两个不同的服务 A、B 部署在两台不同的机器上,服务 A 如果想要调用服务 B 中的某个方法的话就可以通过 RPC 来做。 @@ -52,7 +52,7 @@ ![](https://my-blog-to-use.oss-cn-beijing.aliyuncs.com/2020-8/427f2168-1930-4c14-8760-415fac8db1d0-20200802184737978.png) -[Apache Dubbo](https://github.com/apache/incubator-dubbo) (incubating) |ˈdʌbəʊ| 是一款高性能、轻量级的开源 Java RPC 框架。 +[Apache Dubbo](https://github.com/apache/dubbo) |ˈdʌbəʊ| 是一款高性能、轻量级的开源 Java RPC 框架。 根据 [Dubbo 官方文档](https://dubbo.apache.org/zh/)的介绍,Dubbo 提供了六大核心能力 @@ -85,7 +85,7 @@ Dubbo 是由阿里开源,后来加入了 Apache 。正式由于 Dubbo 的出 不过,Dubbo 的出现让上述问题得到了解决。**Dubbo 帮助我们解决了什么问题呢?** -1. **负载均衡** : 同一个服务部署在不同的机器时该调用那一台机器上的服务。 +1. **负载均衡** : 同一个服务部署在不同的机器时该调用哪一台机器上的服务。 2. **服务调用链路生成** : 随着系统的发展,服务越来越多,服务间依赖关系变得错踪复杂,甚至分不清哪个应用要在哪个应用之前启动,架构师都不能完整的描述应用的架构关系。Dubbo 可以为我们解决服务之间互相是如何调用的。 3. **服务访问压力以及时长统计、资源调度和治理** :基于访问压力实时管理集群容量,提高集群利用率。 4. ...... @@ -186,7 +186,7 @@ public class XxxLoadBalance implements LoadBalance { } ``` -我们将这个是实现类的路径写入到`resources` 目录下的 `META-INF/dubbo/org.apache.dubbo.rpc.cluster.LoadBalance`文件中即可。 +我们将这个实现类的路径写入到`resources` 目录下的 `META-INF/dubbo/org.apache.dubbo.rpc.cluster.LoadBalance`文件中即可。 ```java src @@ -229,7 +229,7 @@ Dubbo 采用 微内核(Microkernel) + 插件(Plugin) 模式,简单来 正是因为Dubbo基于微内核架构,才使得我们可以随心所欲替换Dubbo的功能点。比如你觉得Dubbo 的序列化模块实现的不满足自己要求,没关系啊!你自己实现一个序列化模块就好了啊! -通常情况下,微核心都会采用 Factory、IoC、OSGi 等方式管理插件生命周期。Dubbo 不想依赖 Spring 等 IoC 容器,也不想自已造一个小的 IoC 容器(过度设计),因此采用了一种最简单的 Factory 方式管理插件 :**JDK 标准的 SPI 扩展机制** (`java.util.ServiceLoader`)。 +通常情况下,微核心都会采用 Factory、IoC、OSGi 等方式管理插件生命周期。Dubbo 不想依赖 Spring 等 IoC 容器,也不想自己造一个小的 IoC 容器(过度设计),因此采用了一种最简单的 Factory 方式管理插件 :**JDK 标准的 SPI 扩展机制** (`java.util.ServiceLoader`)。 ### 关于Dubbo架构的一些自测小问题 @@ -299,7 +299,7 @@ public abstract class AbstractLoadBalance implements LoadBalance { ` RandomLoadBalance` 具体的实现原理非常简单,假如有两个提供相同服务的服务器 S1,S2,S1的权重为7,S2的权重为3。 -我们把这些权重值分布在坐标区间会得到:S1->[0, 7) ,S2->(7, 10]。我们生成[0, 10) 之间的随机数,随机数落到对应的区间,我们就选择对应的服务器来处理请求。 +我们把这些权重值分布在坐标区间会得到:S1->[0, 7) ,S2->[7, 10)。我们生成[0, 10) 之间的随机数,随机数落到对应的区间,我们就选择对应的服务器来处理请求。 ![RandomLoadBalance](https://guide-blog-images.oss-cn-shenzhen.aliyuncs.com/java-guide-blog/%20RandomLoadBalance.png) From 8ac6241d6725df47eedcc05c03af8b4b89364e20 Mon Sep 17 00:00:00 2001 From: anaer Date: Thu, 16 Sep 2021 16:31:53 +0800 Subject: [PATCH 5/9] =?UTF-8?q?Update=20Kafka=E5=B8=B8=E8=A7=81=E9=9D=A2?= =?UTF-8?q?=E8=AF=95=E9=A2=98=E6=80=BB=E7=BB=93.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit typo PS: KafkaTopicPartitioning.png 配图中 Partition 错了 --- ...0\257\225\351\242\230\346\200\273\347\273\223.md" | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git "a/docs/system-design/distributed-system/message-queue/Kafka\345\270\270\350\247\201\351\235\242\350\257\225\351\242\230\346\200\273\347\273\223.md" "b/docs/system-design/distributed-system/message-queue/Kafka\345\270\270\350\247\201\351\235\242\350\257\225\351\242\230\346\200\273\347\273\223.md" index 8b4e6176757..8b595e1d8eb 100644 --- "a/docs/system-design/distributed-system/message-queue/Kafka\345\270\270\350\247\201\351\235\242\350\257\225\351\242\230\346\200\273\347\273\223.md" +++ "b/docs/system-design/distributed-system/message-queue/Kafka\345\270\270\350\247\201\351\235\242\350\257\225\351\242\230\346\200\273\347\273\223.md" @@ -11,7 +11,7 @@ Kafka 是一个分布式流式处理平台。这到底是什么意思呢? 流平台具有三个关键功能: 1. **消息队列**:发布和订阅消息流,这个功能类似于消息队列,这也是 Kafka 也被归类为消息队列的原因。 -2. **容错的持久方式存储记录消息流**: Kafka 会把消息持久化到磁盘,有效避免了消息丢失的风险·。 +2. **容错的持久方式存储记录消息流**: Kafka 会把消息持久化到磁盘,有效避免了消息丢失的风险。 3. **流式处理平台:** 在消息发布的时候进行处理,Kafka 提供了一个完整的流式处理类库。 Kafka 主要有两大应用场景: @@ -21,7 +21,7 @@ Kafka 主要有两大应用场景: ### 和其他消息队列相比,Kafka的优势在哪里? -我们现在经常提到 Kafka 的时候就已经默认它是一个非常优秀的消息队列了,我们也会经常拿它给 RocketMQ、RabbitMQ 对比。我觉得 Kafka 相比其他消息队列主要的优势如下: +我们现在经常提到 Kafka 的时候就已经默认它是一个非常优秀的消息队列了,我们也会经常拿它跟 RocketMQ、RabbitMQ 对比。我觉得 Kafka 相比其他消息队列主要的优势如下: 1. **极致的性能** :基于 Scala 和 Java 语言开发,设计中大量使用了批量处理和异步的思想,最高可以每秒处理千万级别的消息。 2. **生态系统兼容性无可匹敌** :Kafka 与周边生态系统的兼容性是最好的没有之一,尤其在大数据和流计算领域。 @@ -42,7 +42,7 @@ Kafka 主要有两大应用场景: **队列模型存在的问题:** -假如我们存在这样一种情况:我们需要将生产者产生的消息分发给多个消费者,并且每个消费者都能接收到完成的消息内容。 +假如我们存在这样一种情况:我们需要将生产者产生的消息分发给多个消费者,并且每个消费者都能接收到完整的消息内容。 这种情况,队列模型就不好解决了。很多比较杠精的人就说:我们可以为每个消费者创建一个单独的队列,让生产者发送多份。这是一种非常愚蠢的做法,浪费资源不说,还违背了使用消息队列的目的。 @@ -104,7 +104,7 @@ ZooKeeper 主要为 Kafka 提供元数据的管理的功能。 从图中我们可以看出,Zookeeper 主要为 Kafka 做了下面这些事情: -1. **Broker 注册** :在 Zookeeper 上会有一个专门**用来进行 Broker 服务器列表记录**的节点。每个 Broker 在启动时,都会到 Zookeeper 上进行注册,即到/brokers/ids 下创建属于自己的节点。每个 Broker 就会将自己的 IP 地址和端口等信息记录到该节点中去 +1. **Broker 注册** :在 Zookeeper 上会有一个专门**用来进行 Broker 服务器列表记录**的节点。每个 Broker 在启动时,都会到 Zookeeper 上进行注册,即到 `/brokers/ids` 下创建属于自己的节点。每个 Broker 就会将自己的 IP 地址和端口等信息记录到该节点中去 2. **Topic 注册** : 在 Kafka 中,同一个**Topic 的消息会被分成多个分区**并将其分布在多个 Broker 上,**这些分区信息及与 Broker 的对应关系**也都是由 Zookeeper 在维护。比如我创建了一个名字为 my-topic 的主题并且它有两个分区,对应到 zookeeper 中会创建这些文件夹:`/brokers/topics/my-topic/Partitions/0`、`/brokers/topics/my-topic/Partitions/1` 3. **负载均衡** :上面也说过了 Kafka 通过给特定 Topic 指定多个 Partition, 而各个 Partition 可以分布在不同的 Broker 上, 这样便能提供比较好的并发能力。 对于同一个 Topic 的不同 Partition,Kafka 会尽力将这些 Partition 分布到不同的 Broker 服务器上。当生产者产生消息后也会尽量投递到不同 Broker 的 Partition 里面。当 Consumer 消费的时候,Zookeeper 可以根据当前的 Partition 数量以及 Consumer 数量来实现动态负载均衡。 4. ...... @@ -138,7 +138,7 @@ Kafka 中发送 1 条消息的时候,可以指定 topic, partition, key,data 生产者(Producer) 调用`send`方法发送消息之后,消息可能因为网络问题并没有发送过去。 -所以,我们不能默认在调用`send`方法发送消息之后消息消息发送成功了。为了确定消息是发送成功,我们要判断消息发送的结果。但是要注意的是 Kafka 生产者(Producer) 使用 `send` 方法发送消息实际上是异步的操作,我们可以通过 `get()`方法获取调用结果,但是这样也让它变为了同步操作,示例代码如下: +所以,我们不能默认在调用`send`方法发送消息之后消息发送成功了。为了确定消息是发送成功,我们要判断消息发送的结果。但是要注意的是 Kafka 生产者(Producer) 使用 `send` 方法发送消息实际上是异步的操作,我们可以通过 `get()`方法获取调用结果,但是这样也让它变为了同步操作,示例代码如下: > **详细代码见我的这篇文章:[Kafka系列第三篇!10 分钟学会如何在 Spring Boot 程序中使用 Kafka 作为消息队列?](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247486269&idx=2&sn=ec00417ad641dd8c3d145d74cafa09ce&chksm=cea244f6f9d5cde0c8eb233fcc4cf82e11acd06446719a7af55230649863a3ddd95f78d111de&token=1633957262&lang=zh_CN#rd)** @@ -170,7 +170,7 @@ if (sendResult.getRecordMetadata() != null) { 当消费者拉取到了分区的某个消息之后,消费者会自动提交了 offset。自动提交的话会有一个问题,试想一下,当消费者刚拿到这个消息准备进行真正消费的时候,突然挂掉了,消息实际上并没有被消费,但是 offset 却被自动提交了。 -**解决办法也比较粗暴,我们手动关闭自动提交 offset,每次在真正消费完消息之后之后再自己手动提交 offset 。** 但是,细心的朋友一定会发现,这样会带来消息被重新消费的问题。比如你刚刚消费完消息之后,还没提交 offset,结果自己挂掉了,那么这个消息理论上就会被消费两次。 +**解决办法也比较粗暴,我们手动关闭自动提交 offset,每次在真正消费完消息之后再自己手动提交 offset 。** 但是,细心的朋友一定会发现,这样会带来消息被重新消费的问题。比如你刚刚消费完消息之后,还没提交 offset,结果自己挂掉了,那么这个消息理论上就会被消费两次。 #### Kafka 弄丢了消息 From b0014acf01181ec66ad815d9bddb74b09254981e Mon Sep 17 00:00:00 2001 From: anaer Date: Thu, 16 Sep 2021 17:39:58 +0800 Subject: [PATCH 6/9] Update RocketMQ-Questions.md --- .../distributed-system/message-queue/RocketMQ-Questions.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/system-design/distributed-system/message-queue/RocketMQ-Questions.md b/docs/system-design/distributed-system/message-queue/RocketMQ-Questions.md index 3e5dac43e91..2a4d89acd2c 100644 --- a/docs/system-design/distributed-system/message-queue/RocketMQ-Questions.md +++ b/docs/system-design/distributed-system/message-queue/RocketMQ-Questions.md @@ -190,7 +190,7 @@ class Broker { ### 2.1.10 RocketMQ 不使用 ZooKeeper 作为注册中心的原因,以及自制的 NameServer 优缺点? 1. ZooKeeper 作为支持顺序一致性的中间件,在某些情况下,它为了满足一致性,会丢失一定时间内的可用性,RocketMQ 需要注册中心只是为了发现组件地址,在某些情况下,RocketMQ 的注册中心可以出现数据不一致性,这同时也是 NameServer 的缺点,因为 NameServer 集群间互不通信,它们之间的注册信息可能会不一致 -2. 另外,当有新的服务器加入时,NameServer 并不会立马通知到 Produer,而是由 Produer 定时去请求 NameServer 获取最新的 Broker/Consumer 信息(这种情况是通过 Producer 发送消息时,负载均衡解决) +2. 另外,当有新的服务器加入时,NameServer 并不会立马通知到 Producer,而是由 Producer 定时去请求 NameServer 获取最新的 Broker/Consumer 信息(这种情况是通过 Producer 发送消息时,负载均衡解决) ### 2.1.11 其它 @@ -201,13 +201,13 @@ class Broker { 2. 消息重试负载均衡策略(具体参考 Dubbo 负载均衡策略) 3. 消息过滤器(Producer 发送消息到 Broker,Broker 存储消息信息,Consumer 消费时请求 Broker 端从磁盘文件查询消息文件时,在 Broker 端就使用过滤服务器进行过滤) 4. Broker 同步双写和异步双写中 Master 和 Slave 的交互 -5. Broker 在 4.5.0 版本更新中引入了基于 Raft 协议的多副本选举,之前这是商业版才有的特性 [ISSUE-1046][2] +5. Broker 在 4.5.0 版本更新中引入了基于 Raft 协议的多副本选举,之前这是商业版才有的特性 [ISSUE-1046][2] # 3 参考 1. 《RocketMQ技术内幕》:https://blog.csdn.net/prestigeding/article/details/85233529 2. 关于 RocketMQ 对 MappedByteBuffer 的一点优化:https://lishoubo.github.io/2017/09/27/MappedByteBuffer%E7%9A%84%E4%B8%80%E7%82%B9%E4%BC%98%E5%8C%96/ -3. 阿里中间件团队博客-十分钟入门RocketMQ:http://jm.taobao.org/2017/01/12/rocketmq-quick-start-in-10-minutes/ +3. 十分钟入门RocketMQ:https://developer.aliyun.com/article/66101 4. 分布式事务的种类以及 RocketMQ 支持的分布式消息:https://www.infoq.cn/article/2018/08/rocketmq-4.3-release 5. 滴滴出行基于RocketMQ构建企业级消息队列服务的实践:https://yq.aliyun.com/articles/664608 6. 基于《RocketMQ技术内幕》源码注释:https://github.com/LiWenGu/awesome-rocketmq From 90dd5e8888696814644f274473330cb5a7448870 Mon Sep 17 00:00:00 2001 From: anaer Date: Thu, 16 Sep 2021 19:19:30 +0800 Subject: [PATCH 7/9] Update RocketMQ.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit typo PS: https://my-blog-to-use.oss-cn-beijing.aliyuncs.com/2019-11/16ef381c4e1b1ac7.jpg 这个配图 有个result拼错了 --- .../distributed-system/message-queue/RocketMQ.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/system-design/distributed-system/message-queue/RocketMQ.md b/docs/system-design/distributed-system/message-queue/RocketMQ.md index 9391d522e13..31e36316769 100644 --- a/docs/system-design/distributed-system/message-queue/RocketMQ.md +++ b/docs/system-design/distributed-system/message-queue/RocketMQ.md @@ -4,7 +4,7 @@ ## 消息队列扫盲 -消息队列顾名思义就是存放消息的队列,队列我就不解释了,别告诉我你连队列都不知道似啥吧? +消息队列顾名思义就是存放消息的队列,队列我就不解释了,别告诉我你连队列都不知道是啥吧? 所以问题并不是消息队列是什么,而是 **消息队列为什么会出现?消息队列能用来干什么?用它来干这些事会带来什么好处?消息队列会带来副作用吗?** @@ -26,7 +26,7 @@ 我们省略中间的网络通信时间消耗,假如购票系统处理需要 150ms ,短信系统处理需要 200ms ,那么整个处理流程的时间消耗就是 150ms + 200ms = 350ms。 -当然,乍看没什么问题。可是仔细一想你就感觉有点问题,我用户购票在购票系统的时候其实就已经完成了购买,而我现在通过同步调用非要让整个请求拉长时间,而短息系统这玩意又不是很有必要,它仅仅是一个辅助功能增强用户体验感而已。我现在整个调用流程就有点 **头重脚轻** 的感觉了,购票是一个不太耗时的流程,而我现在因为同步调用,非要等待发送短信这个比较耗时的操作才返回结果。那我如果再加一个发送邮件呢? +当然,乍看没什么问题。可是仔细一想你就感觉有点问题,我用户购票在购票系统的时候其实就已经完成了购买,而我现在通过同步调用非要让整个请求拉长时间,而短信系统这玩意又不是很有必要,它仅仅是一个辅助功能增强用户体验感而已。我现在整个调用流程就有点 **头重脚轻** 的感觉了,购票是一个不太耗时的流程,而我现在因为同步调用,非要等待发送短信这个比较耗时的操作才返回结果。那我如果再加一个发送邮件呢? ![](https://my-blog-to-use.oss-cn-beijing.aliyuncs.com/2019-11/16ef380429cf373e.jpg) @@ -44,7 +44,7 @@ ![](https://my-blog-to-use.oss-cn-beijing.aliyuncs.com/2019-11/006APoFYly1fvd9cwjlfrj30as0b03ym.jpg) -那后来,我们工作赚钱了有钱去饭店吃饭了,我们告诉服务员来一碗牛肉面加个荷包蛋 **(传达一个消息)** ,然后我们就可以在饭桌上安心的玩手机了 **(干自己其他事情)** ,等到我们的牛肉面上了我们就可以吃了。这其中我们也就传达了一个消息,然后我们又转过头干其他事情了。这其中虽然做面的时间没有变短,但是我们只需要传达一个消息就可以看其他事情了,这是一个 **异步** 的概念。 +那后来,我们工作赚钱了有钱去饭店吃饭了,我们告诉服务员来一碗牛肉面加个荷包蛋 **(传达一个消息)** ,然后我们就可以在饭桌上安心的玩手机了 **(干自己其他事情)** ,等到我们的牛肉面上了我们就可以吃了。这其中我们也就传达了一个消息,然后我们又转过头干其他事情了。这其中虽然做面的时间没有变短,但是我们只需要传达一个消息就可以干其他事情了,这是一个 **异步** 的概念。 所以,为了解决这一个问题,聪明的程序员在中间也加了个类似于服务员的中间件——消息队列。这个时候我们就可以把模型给改造了。 @@ -174,7 +174,7 @@ ### RocketMQ中的消息模型 -`RockerMQ` 中的消息模型就是按照 **主题模型** 所实现的。你可能会好奇这个 **主题** 到底是怎么实现的呢?你上面也没有讲到呀! +`RocketMQ` 中的消息模型就是按照 **主题模型** 所实现的。你可能会好奇这个 **主题** 到底是怎么实现的呢?你上面也没有讲到呀! 其实对于主题模型的实现来说每个消息中间件的底层设计都是不一样的,就比如 `Kafka` 中的 **分区** ,`RocketMQ` 中的 **队列** ,`RabbitMQ` 中的 `Exchange` 。我们可以理解为 **主题模型/发布订阅模型** 就是一个标准,那些中间件只不过照着这个标准去实现而已。 @@ -190,7 +190,7 @@ 你可以看到图中生产者组中的生产者会向主题发送消息,而 **主题中存在多个队列**,生产者每次生产消息之后是指定主题中的某个队列发送消息的。 -每个主题中都有多个队列(分布在不同的 `Broker`中,如果是集群的话,`Broker`又分布在不同的服务器中),集群消费模式下,一个消费者集群多台机器共同消费一个 `topic` 的多个队列,**一个队列只会被一个消费者消费**。如果某个消费者挂掉,分组内其它消费者会接替挂掉的消费者继续消费。就像上图中 `Consumer1` 和 `Consumer2` 分别对应着两个队列,而 `Consuer3` 是没有队列对应的,所以一般来讲要控制 **消费者组中的消费者个数和主题中队列个数相同** 。 +每个主题中都有多个队列(分布在不同的 `Broker`中,如果是集群的话,`Broker`又分布在不同的服务器中),集群消费模式下,一个消费者集群多台机器共同消费一个 `topic` 的多个队列,**一个队列只会被一个消费者消费**。如果某个消费者挂掉,分组内其它消费者会接替挂掉的消费者继续消费。就像上图中 `Consumer1` 和 `Consumer2` 分别对应着两个队列,而 `Consumer3` 是没有队列对应的,所以一般来讲要控制 **消费者组中的消费者个数和主题中队列个数相同** 。 当然也可以消费者个数小于队列个数,只不过不太建议。如下图。 @@ -393,7 +393,7 @@ emmm,就两个字—— **幂等** 。在编程中一个*幂等* 操作的特 而在 `RocketMQ` 中采用了 `Dledger` 解决这个问题。他要求在写入消息的时候,要求**至少消息复制到半数以上的节点之后**,才给客⼾端返回写⼊成功,并且它是⽀持通过选举来动态切换主节点的。这里我就不展开说明了,读者可以自己去了解。 -> 也不是说 `Dledger` 是个完美的方案,至少在 `Dledger` 选举过程中是无法提供服务的,而且他必须要使用三个节点或以上,如果多数节点同时挂掉他也是无法保证可用性的,而且要求消息复制板书以上节点的效率和直接异步复制还是有一定的差距的。 +> 也不是说 `Dledger` 是个完美的方案,至少在 `Dledger` 选举过程中是无法提供服务的,而且他必须要使用三个节点或以上,如果多数节点同时挂掉他也是无法保证可用性的,而且要求消息复制半数以上节点的效率和直接异步复制还是有一定的差距的。 ### 存储机制 @@ -425,7 +425,7 @@ emmm,是不是有一点复杂🤣,看英文图片和英文文档的时候就 首先,在最上面的那一块就是我刚刚讲的你现在可以直接 **把 `ConsumerQueue` 理解为 `Queue`**。 -在图中最左边说明了 红色方块 代表被写入的消息,虚线方块代表等待被写入的。左边的生产者发送消息会指定 `Topic` 、`QueueId` 和具体消息内容,而在 `Broker` 中管你是哪门子消息,他直接 **全部顺序存储到了 CommitLog **。而根据生产者指定的 `Topic` 和 `QueueId` 将这条消息本身在 `CommitLog` 的偏移(offset),消息本身大小,和tag的hash值存入对应的 `ConsumeQueue` 索引文件中。而在每个队列中都保存了 `ConsumeOffset` 即每个消费者组的消费位置(我在架构那里提到了,忘了的同学可以回去看一下),而消费者拉取消息进行消费的时候只需要根据 `ConsumeOffset` 获取下一个未被消费的消息就行了。 +在图中最左边说明了 红色方块 代表被写入的消息,虚线方块代表等待被写入的。左边的生产者发送消息会指定 `Topic` 、`QueueId` 和具体消息内容,而在 `Broker` 中管你是哪门子消息,他直接 **全部顺序存储到了 CommitLog**。而根据生产者指定的 `Topic` 和 `QueueId` 将这条消息本身在 `CommitLog` 的偏移(offset),消息本身大小,和tag的hash值存入对应的 `ConsumeQueue` 索引文件中。而在每个队列中都保存了 `ConsumeOffset` 即每个消费者组的消费位置(我在架构那里提到了,忘了的同学可以回去看一下),而消费者拉取消息进行消费的时候只需要根据 `ConsumeOffset` 获取下一个未被消费的消息就行了。 上述就是我对于整个消息存储架构的大概理解(这里不涉及到一些细节讨论,比如稀疏索引等等问题),希望对你有帮助。 From d84f04332d3e9ec0bbe2b92dcbf15a3fbaffb7af Mon Sep 17 00:00:00 2001 From: guide Date: Thu, 16 Sep 2021 19:21:10 +0800 Subject: [PATCH 8/9] =?UTF-8?q?Update=20java=E6=96=B0=E7=89=B9=E6=80=A7?= =?UTF-8?q?=E6=80=BB=E7=BB=93.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...260\347\211\271\346\200\247\346\200\273\347\273\223.md" | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git "a/docs/java/new-features/java\346\226\260\347\211\271\346\200\247\346\200\273\347\273\223.md" "b/docs/java/new-features/java\346\226\260\347\211\271\346\200\247\346\200\273\347\273\223.md" index 11e75d96e5c..d27c7489745 100644 --- "a/docs/java/new-features/java\346\226\260\347\211\271\346\200\247\346\200\273\347\273\223.md" +++ "b/docs/java/new-features/java\346\226\260\347\211\271\346\200\247\346\200\273\347\273\223.md" @@ -864,7 +864,7 @@ System.out.println(encodedString); ### 预览新特性 -#### record 关键字 +#### 密封类 Java 15 对 Java 14 中引入的预览新特性进行了增强,主要是引入了一个新的概念 **密封类(Sealed Classes)。** @@ -892,11 +892,6 @@ public non-sealed class Manager extends Person { ![](https://guide-blog-images.oss-cn-shenzhen.aliyuncs.com/javaguide/image-20210820153955587.png) -在 `java.lang.Class` 增加了两个公共方法用于获取 `Record` 类信息: - -1. `RecordComponent[] getRecordComponents()` -2. `boolean isRecord()` - #### instanceof 模式匹配 Java 15 并没有对此特性进行调整,继续预览特性,主要用于接受更多的使用反馈。 From fecc2567ad8048fd12179c4d5b8bc676cb98f329 Mon Sep 17 00:00:00 2001 From: anaer Date: Thu, 16 Sep 2021 19:35:57 +0800 Subject: [PATCH 9/9] =?UTF-8?q?Update=20and=20rename=20=E4=B8=BA=E4=BB=80?= =?UTF-8?q?=E4=B9=88=E8=A6=81=E7=BD=91=E7=AB=99=E6=9C=89=E5=93=AA=E4=BA=9B?= =?UTF-8?q?=E5=B8=B8=E8=A7=81=E7=9A=84=E7=BD=91=E7=AB=99=E7=B3=BB=E7=BB=9F?= =?UTF-8?q?.md=20to=20=E4=B8=BA=E4=BB=80=E4=B9=88=E8=A6=81=E7=BD=91?= =?UTF-8?q?=E5=85=B3=E6=9C=89=E5=93=AA=E4=BA=9B=E5=B8=B8=E8=A7=81=E7=9A=84?= =?UTF-8?q?=E7=BD=91=E5=85=B3=E7=B3=BB=E7=BB=9F.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit typo --- ...32\204\347\275\221\345\205\263\347\263\273\347\273\237.md" | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename "docs/system-design/distributed-system/api-gateway/\344\270\272\344\273\200\344\271\210\350\246\201\347\275\221\347\253\231\346\234\211\345\223\252\344\272\233\345\270\270\350\247\201\347\232\204\347\275\221\347\253\231\347\263\273\347\273\237.md" => "docs/system-design/distributed-system/api-gateway/\344\270\272\344\273\200\344\271\210\350\246\201\347\275\221\345\205\263\346\234\211\345\223\252\344\272\233\345\270\270\350\247\201\347\232\204\347\275\221\345\205\263\347\263\273\347\273\237.md" (95%) diff --git "a/docs/system-design/distributed-system/api-gateway/\344\270\272\344\273\200\344\271\210\350\246\201\347\275\221\347\253\231\346\234\211\345\223\252\344\272\233\345\270\270\350\247\201\347\232\204\347\275\221\347\253\231\347\263\273\347\273\237.md" "b/docs/system-design/distributed-system/api-gateway/\344\270\272\344\273\200\344\271\210\350\246\201\347\275\221\345\205\263\346\234\211\345\223\252\344\272\233\345\270\270\350\247\201\347\232\204\347\275\221\345\205\263\347\263\273\347\273\237.md" similarity index 95% rename from "docs/system-design/distributed-system/api-gateway/\344\270\272\344\273\200\344\271\210\350\246\201\347\275\221\347\253\231\346\234\211\345\223\252\344\272\233\345\270\270\350\247\201\347\232\204\347\275\221\347\253\231\347\263\273\347\273\237.md" rename to "docs/system-design/distributed-system/api-gateway/\344\270\272\344\273\200\344\271\210\350\246\201\347\275\221\345\205\263\346\234\211\345\223\252\344\272\233\345\270\270\350\247\201\347\232\204\347\275\221\345\205\263\347\263\273\347\273\237.md" index 681f3dc81c8..c828cb3648f 100644 --- "a/docs/system-design/distributed-system/api-gateway/\344\270\272\344\273\200\344\271\210\350\246\201\347\275\221\347\253\231\346\234\211\345\223\252\344\272\233\345\270\270\350\247\201\347\232\204\347\275\221\347\253\231\347\263\273\347\273\237.md" +++ "b/docs/system-design/distributed-system/api-gateway/\344\270\272\344\273\200\344\271\210\350\246\201\347\275\221\345\205\263\346\234\211\345\223\252\344\272\233\345\270\270\350\247\201\347\232\204\347\275\221\345\205\263\347\263\273\347\273\237.md" @@ -4,7 +4,7 @@ 综上:**一般情况下,网关一般都会提供请求转发、安全认证(身份/权限认证)、流量控制、负载均衡、容灾、日志、监控这些功能。** -上面介绍了这么多功能实际上网关主要做了一件事情:**请求过滤** 。权限校验、流量控制这些都可以通过过滤器实现,请求转也是通过过滤器实现的。 +上面介绍了这么多功能实际上网关主要做了一件事情:**请求过滤** 。权限校验、流量控制这些都可以通过过滤器实现,请求转发也是通过过滤器实现的。 ### 你知道有哪些常见的网关系统? @@ -34,4 +34,4 @@ $ curl -X POST http://kong:8001/services/{service}/plugins \ --data "config.sample_ratio=0.001" ``` -ps:这里没有太深入去探讨,需要深入了解的话可以自行查阅相关资料。 \ No newline at end of file +ps:这里没有太深入去探讨,需要深入了解的话可以自行查阅相关资料。