Spring Cloud Sleuth 赋予分布式跟踪的Spring Boot 自动配置的一键解决方案。Spring Cloud Sleuth 是基于Brave的封装,也是很多公司采用开源加自研的最佳解决方案。
那么从作为架构师或者技术专家如何去借鉴优秀框架的设计理念和思想,本次 Chat 将开启作者既分布式链路追踪生态的兄弟篇:Skywalking (全链路监控)之后的 Spring-Cloud-Sleuth 系列,欢迎大家拍砖。
也欢迎大家参与Skywalking 的 Chat系列:
-
SkyWalking 分布式链路追踪:最新 Kafka通信模型设计;
-
分布式链路追踪 Skywalking:插件化和模块化架构设计;
-
分布式链路追踪 Skywalking:告警和度量架构设计;
-
分布式链路追踪Skywalking:底层通信设计;
-
分布式链路追踪 SkyWalking:配置管理设计;
-
分布式链路追踪:集群管理设计;
-
分布式链路追踪:Skywalking 探针模型设计;
-
分布式链路追踪:Skywalking 的链路模型设计;
-
分布式链路追踪:Skywalking 底层存储模型设计;
- 分布式链路追踪:Spring-Cloud-Sleuth 探针模型设计。
Spring Cloud Sleuth如何和Zipkin融合
首先 Spring-Cloud-Sleuth 是一套分布式链路追踪的解决方案,也是已经落地的比较优秀的开源解决方案,当然对于很多公司来说,可以是拿来主义直接用,也可以自己改造。
在 Spring-Cloud-Sleuth 中有一个项目叫做 spring-cloud-sleuth-zipkin ,这个项目就会去融合 Zipkin,依赖如下:
-
zipkin;
-
zipkin-reporter;
-
zipkin-reporter-brave;
-
zipkin-sender-kafka;
-
zipkin-sender-activemq-client;
逐步分析可以从 ZipkinAutoConfiguration 开始,那么熟悉Spring Boot 框架的人都知道,自动配置是框架初始化的源头。
-
开关 spring.sleuth.enabled 和 spring.zipkin.enabled ,默认都是 true;
-
通过注解 @AutoConfigureBefore 确保在TraceAutoConfiguration 之前初始化,通过注解 @AutoConfigureAfter 确保在 RefreshAutoConfiguration 之后初始化;
-
通过注解 @Import 引入ZipkinSenderConfigurationImportSelector;
-
ZipkinSenderConfigurationImportSelector 会封装各种通信渠道 ActiveMQ、Rabbit、Kafka 和 Web;
-
通信渠道又会去一一映射各种配置,比如 ZipkinActiveMqSenderConfiguration 、ZipkinRabbitSenderConfiguration 、ZipkinKafkaSenderConfiguration 和 ZipkinRestTemplateSenderConfiguration;
-
通过 @Bean 来初始化 zipkinSpanHandler ,Span 是链路追踪中的核心用语,入参为 List<Reporter<Span>> ,这个就是链路追踪从业务端采集的数据源,被封装为 Reporter 对象。在处理的过程,会按照策略来决定是否启用CompositeSpanReporter,这个是一个批量处理数据的类,多个就循环调用并处理;
-
通过 @Configuration 和 @ConditionalOnClass 初始化 MicrometerReporterMetrics 和 InMemoryReporterMetrics。
示例应用如何接入Spring-Cloud-Sleuth并融合Zipkin
添加依赖 spring-cloud-starter-zipkin:
XML
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${release.train.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zipkin</artifactId>
</dependency>
配置通信渠道
如果你想使用RabbitMQ 或 Kafka 代替 HTTP ,添加 spring-rabbit 或 spring-kafka 依赖。默认的目标名称是 Zipkin 。如果使用 Kafka ,则必须设置属性 spring.zipkin.sender。
XML
spring.zipkin.sender.type: kafka
XML
<dependency>
<groupId>org.springframework.amqp</groupId>
<artifactId>spring-rabbit</artifactId>
</dependency>
Spring Cloud Sleuth 2.1.0 版本支持发送跟踪到多个跟踪系统。为了使其工作,每个跟踪系统都需要有一个报告器 Span 和发送器。如果您想要覆盖所提供的 bean ,则需要为它们指定一个特定的名称。为此,可以分别使用 ZipkinAutoConfiguration 。REPORTER_BEAN_NAME 和 ZipkinAutoConfiguration.SENDER_BEAN_NAME。
笔者就是通过这样的方式来融合 SkyWalking 的链路追踪系统。
但是如果你只是想单独接入 Sleuth ,那么应用的 pom 依赖就应该是如下配置:
XML
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${release.train.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
Spring-Cloud-Sleuth通信模型设计
Spring-Cloud-Sleuth 的通信模型主要分为 4 个方向:KafkaSender 、RestTemplateSender 、RabbitMQSender 和 ActiveMQSender。
KafkaSender
整个类采用 Builder设计模式,这里稍微带着源码解释下这个设计模式:
-
new Builder 方法,从配置文件中读取属性文件,加载到 Properties 中;
-
Builder 类封装了 KafkaSender的相关的一些属性的;
-
通过 build() 方法来构建 KafkaSender 实例;
-
通过 Builder 对象来动态的植入配置属性值;
KafkaSender 会封装KafkaProducer 和AdminClient ,让KafkaSender 具备 Kafka 的能力。
RabbitMQSender
-
Builder 模式,会去封装一些公共的信息,比如 ConnectionFactory 、Address、queue、Encoding 和 messageMaxBytes;
-
可以这么理解,凡是要做成公共模板的信息,都可以通过 Builder 来封装;
-
RabbitMQSender 在初始化的时候,就会通过 Builder 来动态的植入一些属性值;
-
因为是公共的通信类,肯定是需要有发送方法的,统一封装了 sendSpans;
-
基础类 Sender 会封装 encoding()、 messageMaxBytes()、messageSizeInBytes() 和 sendSpans()。
ActiveMQSender
-
同理,通过 Builder 模式,初始化 ActiveMQConnectionFactory 、queue、Encoding 和 messageMaxBytes;
-
只要有方法调用就会有回调,回调函数ActiveMQCall 会继承Call.Base<Void>;
-
回调函数式异步模式,只管发送消息,不管发送的结果。
既然是通信,有发送端就会有接收端,Spring-Cloud-Sleuth的性能指标的收集端也是封装得非常优秀。
Reporter
从设计模式角度去看,这个是一个基类,一般基类是封装功能的共性。
java
/
* Schedules the span to be sent onto the transport.
*
* @param span Span, should not be <code>null</code>.
*/
void report(S span);
report 这个方法,是整个通信模型的核心,但是单单是通信,数据是肯定不能落地的,所以需要持久化,持久化就是接口 Flushable ,这个接口封装了公共的方法 flush(),从方法的名称就可以看到,这个是持久化操作。
AsyncReporter 抽象类,继承Component ,实现 Reporter 和 Flushable ,那么从这里就可以看出,不变的 report 和flush() 定义分别是封装在接口中,然而变化的部分是封装在抽象类 AsyncReporter 中。那么什么是变化的,在AsyncReporter 中封装抽象方法 flush() ,实现是在 AsyncReporter 的子类中完成,比如 BoundedAsyncReporter ,report 方法也一样,在子类 BoundedAsyncReporter 完成。既然是要持久化,那么在 flush 的时候就自然要调用 Sender 实例完成通信。report 是 sender.messageSizeInBytes ,持久化就是 sender.sendSpans。
Spring-Cloud-Sleuth通信模型和Skywalking的横向对比
我们判断一款 APM系统,不能笼统的从某些局部的一些功能特性来判断它的价值,要从全局,甚至是整个领域来判断,因为能力的大小是要靠业务场景来决定的。
Spring-Cloud-Sleuth 的通信模型,从通信渠道能力的角度出发,要丰富很多,既支持同步调用的 HTTP ,又支持异步消息能力,比如 Kafka 和 RabbitMQ 等消息中间件等。那么 SkyWalking 呢,到目前为止只支持 GRPC ,当然在8.1.0 之后,新的框架也已经支持Kafka,业务也可以异步完成数据的发送,这样也能完全解耦链路平台。
单从支持异步场景能力 Spring-Cloud-Sleuth 支持的更多,但是我们都知道,在日志消息处理能力上,我们基本都会是直接选型 Kafka ,所以为了保证能力的完整性**,SkyWalking** 在通信能力的选择上更加倾向于简单实用。
为什么要选择 Kafka?
Kafka 最开始由 LinkedIn 设计开发,并于 2011 年开源,2012 年成为 Apache 的顶级项目。目前Kafka 为越来越多的分布式大数据处理系统提供支持,其中包括著名的 Apache Spark、LinkenId、Netflix、Uber 、Verzon、网易、美团等互联网公司选择它作为基础大数据处理平台或消息中间件系统。
Kafka 特性如下。
解耦合
Kafka 可以作为多个交互系统之间的枢纽,负责任意系统之间的数据传递,Kafka承担数据总线的功能。
数据持久化
分布式系统中各个组件是通过网络连接起来的,网路传输基本是不可靠的,那么就意味着我们的消息需要持久化,才能保证消息不丢失。但是数据持久化是很耗性能的,在磁盘操作中,耗时最长的是寻道时间,所以 Kafka 使用顺序读写来取代随机读写操作,实现高吞吐量。
扩展与容灾
Kafka 的每个 Topic (主题)都可以分为多个 Partition (分区),每个分区都有多个 Replica (副本),实现消息冗余备份。每个分区中的消息是不同的,通过水平切分的思想,提高了并发读写的能力。而同一分区的不同副本中保存的是相同的消息,副本之间是一主多从的关系,其中 Leader 副本负载处理读写请求,Follower 副本则只与 Leader 副本之间进行消息同步,当 Leader 副本出现故障时,则从 Follower 副本中重新选举 Leader 副本对外提供服务。
Kafka 的容灾能力体现在多个方面,在Consumer 端,Consumer 采用 pull 方式从服务端拉取消息,并且在 Consumer端保存消息的具体位置,当消费者宕机之后恢复上线,可以根据自己保存的消费位置重新拉取需要消费的消息进行消费。
顺序保证
Kafka支持一定的顺序消息,这样业务可以利用这一特性完成特定的消息场景。
缓冲&峰值处理能力
因为 Kafka 的副本机制以及特有的异步模式,所以在缓冲和峰值消息的业务场景的处理能力上是非常优秀的。
异步通信
异步通信可以说是所有消息中间件的特性,Kafka 通过 topic 、queue 和分区,让异步通信场景更加丰富。
高性能
Kafka 提高效率方面付出了巨大努力。它的主要用例之一是处理 Web 活动数据,它的容量非常大:每个页面视图可能生成几十次写操作。此外,假设发布的每个消息至少有一个使用者(通常是很多)读取,因此尽量降低使用成本。
从构建和运行大量类似系统的经验中,Kafka还发现,效率是有效的多租户操作的关键。如果下游基础设施服务由于应用程序使用的一个小波动而很容易成为瓶颈,那么这样的小变化通常会产生问题。通过非常快的速度,我们有助于确保应用程序在加载基础设施之前就会在负载下崩溃。当试图在一个集中式集群上运行支持数十或数百个应用程序的集中式服务时,这一点尤其重要,因为几乎每天都要更改使用模式。
针对磁盘效率,一旦消除了不良的磁盘访问模式,在这种类型的系统中存在两个导致效率低下的常见原因:太多的小I/O 操作和过多的字节复制。
小的 I/O问题既发生在客户机和服务器之间,也发生在服务器自己的持久操作中。
为了避免这种情况,我们的协议是围绕"消息集"抽象构建的,该抽象自然地将消息分组在一起。这允许网络请求将消息分组在一起,分摊网络往返的开销,而不是一次发送一条消息。服务器依次将消息块追加到它的日志中,而使用者一次获取大的线性消息块。
这个简单的优化产生了数量级的速度。批处理会导致更大的网络包、更大的顺序磁盘操作、连续的内存块等等,所有这些都允许 Kafka将突发的随机消息写入流转换为线性写入流,然后发送给消费者。
另一个低效率是字节复制。在低消息率下,这不是一个问题,但在负载下,影响是显著的。为了避免这种情况,我们采用了由生产者、代理和使用者共享的标准化二进制消息格式(这样数据块就可以在它们之间传输而无需修改)。
由代理维护的消息日志本身就是一个文件目录,每个文件都由以生产者和消费者使用的相同格式写入磁盘的消息集序列填充。维护这种通用格式允许优化最重要的操作------持久日志块的网络传输。现代 Unix 操作系统提供了一个高度优化的代码路径,用于将数据从 PageCache 传输到套接字;在 Linux 中,这是通过 sendfile 系统调用完成的。
要理解 sendfile的影响,重要的是要理解从文件到套接字传输数据的通用数据路径:
-
操作系统将数据从磁盘读取到内核空间中的 PageCache;
-
应用程序将数据从内核空间读入用户空间缓冲区;
-
应用程序将数据写回内核空间到套接字缓冲区中;
操作系统将数据从套接字缓冲区复制到 NIC 缓冲区,在那里通过网络发送数据
这显然是低效的,有四个副本和两个系统调用。通过使用 sendfile ,允许操作系统将数据从PageCache 直接发送到网络,从而避免了这种重复复制。所以在这个优化的路径中,只需要最终的副本到 NIC缓冲区。
我们期望一个通用用例是一个主题的多个使用者。使用上面的零拷贝优化,数据被精确地复制到 PageCache 中一次,并在每次使用时重用,而不是在每次读取时存储在内存中并复制到用户空间。这允许以接近网络连接限制的速度使用消息。
PageCache 和 sendfile 的组合意味着在 Kafka集群中,消费者大部分都被捕获了,你将看不到磁盘上的读取活动,因为它们将完全从缓存中提供数据。
生产者负载均衡
生产者直接将数据发送到作为分区领导者的代理,而没有任何中间路由层。为了帮助生成器完成这一任务,所有Kafka节点都可以回答关于哪些服务器是活的以及某个主题分区的领导者在任何给定时间的元数据请求,从而允许生成器适当地指导其请求。
客户端控制它将消息发布到哪个分区。这可以随机完成,实现一种随机的负载平衡,也可以通过一些语义分区函数来完成。我们通过允许用户为分区指定一个键,并使用这个键散列到一个分区来公开语义分区的接口(如果需要,还可以选择覆盖分区函数)。例如,如果选择的键是一个用户id,那么给定用户的所有数据将被发送到相同的分区。这反过来又允许消费者对他们的消费做出本地假设。这种分区样式被显式设计为允许在使用者中进行对位置敏感的处理。
消费者 pull 和 push 模式
我们首先考虑的一个问题是,消费者是应该从代理拉取数据,还是代理应该将数据推给消费者。在这方面,Kafka 遵循了大多数消息传递系统所共享的更传统的设计,其中数据从生产者推到代理,由消费者从代理提取。
一些以日志为中心的系统,如Scribe 和 Apache Flume,遵循完全不同的基于推的路径,其中数据被推到下游。这两种方法各有利弊。但是,基于推的系统在处理不同的使用者时存在困难,因为代理控制数据传输的速率。其目标通常是让使用者能够以最大的可能速度消耗;不幸的是,在推式系统中,这意味着当消费者的消费率低于生产率时(本质上是拒绝服务攻击),消费者往往会不知所措。以拉力为基础的系统有一个更好的特性,那就是消费者只是落在后面,然后在可能的时候赶上来。这可以通过某种退出协议来缓解,通过这种协议,使用者可以表明它已经超负荷了,但是要让传输速率充分利用(而不是过度利用)使用者要比看起来更加棘手。以前以这种方式构建系统的尝试导致我们采用更传统的拉式模型。
基于拉取的系统的另一个优点是,它便于对发送给消费者的数据进行积极的批处理。基于推的系统必须选择要么立即发送请求,要么积累更多数据,然后在不知道下游客户是否能够立即处理它的情况下再发送。如果调优为低延迟,这将导致一次只发送一条消息,传输最终将被缓冲,这是一种浪费。基于拉的设计解决了这个问题,因为使用者总是在消息在日志中的当前位置之后拉出所有可用消息(或者直到某个可配置的最大大小)。这样就可以在不引入不必要延迟的情况下获得最佳批处理。
幼稚的基于拉取的系统的不足之处在于,如果代理没有数据,使用者可能最终会在一个紧密的循环中轮询,有效地忙碌地等待数据的到达。为了避免这种情况,我们在 pull 请求中使用了一些参数,这些参数允许用户请求以"长轮询"的方式阻塞,直到数据到达(也可以选择等待,直到给定的字节数可用,以确保较大的传输规模)。
你可以想象其他可能的设计,只需要端到端拉。生产者将从本地写入到本地日志,代理将从该日志中提取,而消费者从它们中提取。经常会提出类似的"存储并转发"生成器。这很有趣,但我们觉得不太适合我们有数千生产者的目标用例。大规模运行持久数据系统的经验让我们感到,跨许多应用程序在系统中涉及数千个磁盘实际上不会使事情更可靠,而且操作起来会是一场噩梦。在实践中,我们发现我们可以在不需要生产者持久性的情况下大规模运行具有强 SLA的管道。
我可以这样理解 Spring-Cloud-Sleuth 和 SkyWalking的通信模型上,对于我们使用者来说的场景:
-
如果希望自研链路追踪,那么 Spring-Cloud-Sleuth 的通信模型比较简单并且实用,并且底层是基于 Zinpkin,所以更加通用;
-
如果是希望稳定,并且满足后期的扩展性,可以选择 SkyWalking;
-
如果是社区活跃度,那么也是首选 SkyWalking,因为它是 Apapche 项目,项目会持续发展,所以会有更多的贡献者会参与新的功能的研发和维护,并且场景也非常的丰富。
总结
Spring Cloud Sleuth,也是一款人气非常高的分布式链路追踪组件,活跃度还行,但是通过笔者对这款组件的研究发现,大部分公司还是会采用它的开源方案,并结合业务场景去自研落地。
那么为什么会这样,那是因为 Spring Cloud Sleuth 是采用SDK 模式,需要业务去 pom 依赖,所以耦合度是非常高的,如果直接使用开源,不考虑后期的扩展性和可维护性,后面这个套开源代码会直接成为团队的噩梦,所以既然要选择 Spring Cloud Sleuth ,就必然要重写,重写就意味着要通过 Spring Boot 或者 Spring Cloud 的基础 starter 完成扩展。
另外我的新书RocketMQ消息中间件实战派上下册,在京东已经上架啦,目前都是5折,非常的实惠。
https://item.jd.com/14337086.html编辑https://item.jd.com/14337086.html
"RocketMQ 消息中间件实战派上下册"是我既"Spring Cloud Alibaba 微服务架构实战派上下册"之后,又一本历时超过1年半的巨无霸技术实战类型的书籍。
为了提高读者阅读本书的体验性,本书总共设计了十个特色,下面我一一的给技术小伙伴阐述一下。
【特色一】由浅到深
本书将RocketMQ 的技术原理和最佳实践体系化,按照由浅到深的顺序呈现给读者,使读者可以按照章节顺序按部就班地学习。当学习完全书内容之后,读者不仅能熟悉RocketMQ 的核心原理,还能充分理解RocketMQ的"根"。
【特色二】技术新
本书不仅包括RocketMQ4.x (4.9.2 版本)的核心原理分析和最佳实践,还包括RocketMQ5.x (5.1. 0版本)的新特性分析和最佳实践。
【特色三】精心设计的主线:零基础入门,循序渐进,直至彻底掌握RocketMQ
本书精心研究了程序类、架构类知识的认知规律,全书共分为6 篇:① 基础;② 进阶;③ 高级;④ 高并发、高可用和高性能;⑤ 应用;⑥ 新特性,是一条相对科学的主线,让读者快速从"菜鸟"向"RocketMQ分布式架构实战高手"迈进。
【特色四】绘制了大量的图,便于读者理解RocketMQ的原理、架构、流程
一图胜于文,书中在涉及原理、架构、流程的地方配有插图,以便读者更加直观地理解。
【特色五】从架构师和技术专家的视角分析RocketMQ
本书创造性地分析了RocketMQ具备高并发、高可用和高性能的功能及原理,并从架构的视角展开分析,这些也是程序员进阶为技术专家或架构师必备的技能。
以下为从架构师和技术专家的视角分析RocketMQ典型案例,读者阅读完本书之后,也能够达到这样的水准。
【特色六】不仅有原理分析,还有大量的实战案例
本书介绍了大量的实战案例,能让读者"动起来",在实践中体会功能,而不只是一种概念上的理解。
在讲解每一个知识模块时,我在思考:在这个知识模块中,哪些是读者必须实现的"标准动作"(实例);哪些"标准动作"是可以先完成的,以求读者能快速有一个感知;哪些"标准动作"具有一定难度, 需要放到后面完成。读者在实践完书中的案例之后,就能更容易理解那些抽象的概念和原理了。
本书的目标之一是,让读者在动手中学习,而不是"看书时好像全明白了,一动手却发现什么都不会"。通过体系化的理论和实战案例去培养读者的主动学习能力,这样本书的价值就会被最大化。
本书相信"知行合一"的理念,而不是"只知,而不行",避免开发人员出现眼高手低的现象。尤其是在技术面试过程中,面试官更加看重的是既懂原理,又能够主动是实践技术的技术人。
【特色七】深入剖析原理
本书以系统思维的方式,从业务功能视角剖析 RocketMQ 底层的技术原理,使读者具备快速阅读 RocketMQ 框架源码的能力。读者只有具备了这种能力,才能举一反三,实现更复杂的功能,应对更复杂的应用场景。
【特色八】从运维的视角分析 RocketMQ 的最佳实践
【特色九】参与开源
本书向读者展示了如何修改 RocketMQ 源码,并快速验证案例分析。这样,读者可以从中学到参与开源的技能,并为后续自己能够参与开源做准备。
【特色十】双色印刷,读者体验会更好
为了提高读者阅读本书的体验,在有上下两册的前提下(巨无霸,超过800页),出版社不吝啬印刷成本,依然采用双色印刷。
【推荐】本书的最佳学习路径
为了提高读者学习RocketMQ 的效率,我这边结合我自身从RocketMQ 小白到RocketMQ专家的经历,为读者汇总了一条最佳学习路径。
【寄语】作者寄语
RocketMQ是我深度参与研究的一款开源消息中间件,无论是从源码,还是架构场景,我都提炼了很多最佳实践。
在开源领域,技术小伙伴可以使用的开源消息中间件非常的多,比如Kafka 、Pulsar 等,我之所以选择研究RocketMQ,除了工作内容和角色需要之外,更多的还是自己感兴趣,因此我建议技术小伙伴一定要先培养自己的兴趣,兴趣才是提升技术硬实力的第1要素。
当然我并不止研究了RocketMQ ,还研究了Pulsar 和Kafka 等(包括开源消息中间件生态中的主流框架),只是本书作为一本关于RocketMQ 实战派的书籍,我必须要以RocketMQ为主。
假如技术小伙伴想成为Java领域的架构师或者技术专家,我强烈建议你去研究RocketMQ,它会给你带来很多意想不到的技术和架构方法论的收获,这个也是我写本书的主要目的之一。
建议技术小伙伴按照本书设计的学习路线,逐章的去阅读和实战,这样学习效果会更好。
如果技术小伙伴有技术交流的,可以通过博文视点官方的读者群找到我的联系方式,并与我沟通,我会实时的解答读者的疑问。
本文公众号"架构随笔录"
本人视频号"架构随笔录"
【博文视点】2021年度优秀作者
2021 年我和博文视点合作了一本技术类型的书籍"Spring Cloud Alibaba微服务架构实战派上下册",它是我涉足知识输出领域以来的第一本书,同时它也是我自己积累的技术池中部分技术的产出。
为了写好那本书,我几乎花费了所有的休息时间,并主动的承担了书的售后技术辅导和咨询的职责(几乎是有问必答,坚持了整整两年)。
所谓有付出总会有回报,Alibaba 这本书的销量还不错,我也因此获得了博文视点颁发的2021年度优秀作者。
我很清楚,这个是博文视点为了鼓励我继续去用心写书,因此我又花了接近1年半的时间去写了RocketMQ消息中间件实战派上下册这本书。
所谓一分耕耘一份收获,我将我对RocketMQ的理解体系化的输出给喜欢技术的技术人,希望真的对大家有帮助。
【博文视点】2023技术成长领路人
2022 年,我开始涉足技术直播和技术讲师领域,并和博文视点合作几次技术直播,直播效果还不错,再加上我孜孜不倦的布道"Spring Cloud Alibaba 微服务架构实战派上下册"这本书相关的技术,并且这些技术都是有助于"技术人"快速成长的,因此也获得了博文视点颁发的"2023技术成长领路人"这个技术奖项,这个奖项也是为了鼓励我继续通过技术直播的方式给技术人去布道技术,因此只要我有时间,我就会孜孜不倦的去讲和聊技术。
【四维口袋】2022 KVP最具价值技术专家
2022 年,我开始涉足企业培训和相关技术直播,并和"四维口袋"合作了几次技术直播,并荣获了2022 KVP最具价值技术专家的技术奖项。