分布式链路追踪专栏,Spring Cloud Sleuth:分布式链路追踪之通信模型设计

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

  • 通信渠道又会去一一映射各种配置,比如 ZipkinActiveMqSenderConfigurationZipkinRabbitSenderConfigurationZipkinKafkaSenderConfiguration 和 ZipkinRestTemplateSenderConfiguration

  • 通过 @Bean 来初始化 zipkinSpanHandlerSpan 是链路追踪中的核心用语,入参为 List<Reporter<Span>>,这个就是链路追踪从业务端采集的数据源,被封装为 Reporter 对象。在处理的过程,会按照策略来决定是否启用 CompositeSpanReporter,这个是一个批量处理数据的类,多个就循环调用并处理;

  • 通过 @Configuration 和 @ConditionalOnClass 初始化 MicrometerReporterMetrics 和 InMemoryReporterMetrics

示例应用如何接入Spring-Cloud-Sleuth并融合Zipkin

添加依赖 spring-cloud-starter-zipkin

<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

spring.zipkin.sender.type: kafka
<dependency> 
    <groupId>org.springframework.amqp</groupId>
    <artifactId>spring-rabbit</artifactId>
</dependency>

Spring Cloud Sleuth 2.1.0 版本支持发送跟踪到多个跟踪系统。为了使其工作,每个跟踪系统都需要有一个报告器 Span 和发送器。如果您想要覆盖所提供的 bean,则需要为它们指定一个特定的名称。为此,可以分别使用 ZipkinAutoConfigurationREPORTER_BEAN_NAME 和 ZipkinAutoConfiguration.SENDER_BEAN_NAME

笔者就是通过这样的方式来融合 SkyWalking 的链路追踪系统。
但是如果你只是想单独接入 Sleuth,那么应用的 pom 依赖就应该是如下配置:

<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 个方向:KafkaSenderRestTemplateSenderRabbitMQSender 和 ActiveMQSender

KafkaSender

整个类采用 Builder 设计模式,这里稍微带着源码解释下这个设计模式:

  • newBuilder 方法,从配置文件中读取属性文件,加载到 Properties 中;

  • Builder 类封装了 KafkaSender 的相关的一些属性的;

  • 通过 build() 方法来构建 KafkaSender 实例;

  • 通过 Builder 对象来动态的植入配置属性值;

KafkaSender 会封装 KafkaProducer 和 AdminClient,让 KafkaSender 具备 Kafka 的能力。

RabbitMQSender

  • Builder 模式,会去封装一些公共的信息,比如 ConnectionFactoryAddress、queue、Encoding 和 messageMaxBytes

  • 可以这么理解,凡是要做成公共模板的信息,都可以通过 Builder 来封装;

  • RabbitMQSender 在初始化的时候,就会通过 Builder 来动态的植入一些属性值;

  • 因为是公共的通信类,肯定是需要有发送方法的,统一封装了 sendSpans

  • 基础类 Sender 会封装 encoding()、 messageMaxBytes()、messageSizeInBytes() 和 sendSpans()

ActiveMQSender 

  • 同理,通过 Builder 模式,初始化 ActiveMQConnectionFactoryqueue、Encoding 和 messageMaxBytes

  • 只要有方法调用就会有回调,回调函数 ActiveMQCall 会继承Call.Base<Void>

  • 回调函数式异步模式,只管发送消息,不管发送的结果。

既然是通信,有发送端就会有接收端,Spring-Cloud-Sleuth 的性能指标的收集端也是封装得非常优秀。

 Reporter

从设计模式角度去看,这个是一个基类,一般基类是封装功能的共性。


/
   * 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 的子类中完成,比如 BoundedAsyncReporterreport 方法也一样,在子类 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、UberVerzon、网易、美团等互联网公司选择它作为基础大数据处理平台或消息中间件系统。

Kafka 特性如下。

解耦合

Kafka 可以作为多个交互系统之间的枢纽,负责任意系统之间的数据传递,Kafka 承担数据总线的功能。

数据持久化

分布式系统中各个组件是通过网络连接起来的,网路传输基本是不可靠的,那么就意味着我们的消息需要持久化,才能保证消息不丢失。但是数据持久化是很耗性能的,在磁盘操作中,耗时最长的是寻道时间,所以 Kafka 使用顺序读写来取代随机读写操作,实现高吞吐量。

扩展与容灾

Kafka 的每个 Topic(主题)都可以分为多个 Partition(分区),每个分区都有多个 Replica(副本),实现消息冗余备份。每个分区中的消息是不同的,通过水平切分的思想,提高了并发读写的能力。而同一分区的不同副本中保存的是相同的消息,副本之间是一主多从的关系,其中 Leader 副本负载处理读写请求,Follower 副本则只与 Leader 副本之间进行消息同步,当 Leader 副本出现故障时,则从 Follower 副本中重新选举 Leader 副本对外提供服务。

Kafka 的容灾能力体现在多个方面,在 Consumer 端,Consumer 采用 pull 方式从服务端拉取消息,并且在 Consumer 端保存消息的具体位置,当消费者宕机之后恢复上线,可以根据自己保存的消费位置重新拉取需要消费的消息进行消费。

顺序保证

Kafka 支持一定的顺序消息,这样业务可以利用这一特性完成特定的消息场景。

缓冲&峰值处理能力

因为 Kafka 的副本机制以及特有的异步模式,所以在缓冲和峰值消息的业务场景的处理能力上是非常优秀的。

异步通信

异步通信可以说是所有消息中间件的特性,Kafka 通过 topicqueue 和分区,让异步通信场景更加丰富。

高性能

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.x4.9.2版本)的核心原理分析和最佳实践,还包括RocketMQ5.x5.1. 0版本)的新特性分析和最佳实践。

【特色三】精心设计的主线:零基础入门,循序渐进,直至彻底掌握RocketMQ

本书精心研究了程序类、架构类知识的认知规律,全书共分为6篇:基础;进阶;高级;高并发、高可用和高性能;应用;新特性,是一条相对科学的主线,让读者快速从“菜鸟”向“RocketMQ分布式架构实战高手”迈进。

【特色四】绘制了大量的图,便于读者理解RocketMQ的原理、架构、流程 

一图胜于文,书中在涉及原理、架构、流程的地方配有插图,以便读者更加直观地理解。

【特色五】从架构师和技术专家的视角分析RocketMQ 

本书创造性地分析了RocketMQ具备高并发、高可用和高性能的功能及原理,并从架构的视角展开分析,这些也是程序员进阶为技术专家或架构师必备的技能。

以下为从架构师和技术专家的视角分析RocketMQ典型案例,读者阅读完本书之后,也能够达到这样的水准。

【特色六】不仅有原理分析,还有大量的实战案例 

本书介绍了大量的实战案例,能让读者“动起来”,在实践中体会功能,而不只是一种概念上的理解。

在讲解每一个知识模块时,我在思考:在这个知识模块中,哪些是读者必须实现的“标准动作”(实例);哪些“标准动作”是可以先完成的,以求读者能快速有一个感知;哪些“标准动作”具有一定难度, 需要放到后面完成。读者在实践完书中的案例之后,就能更容易理解那些抽象的概念和原理了。

本书的目标之一是,让读者在动手中学习,而不是“看书时好像全明白了,一动手却发现什么都不会”。通过体系化的理论和实战案例去培养读者的主动学习能力,这样本书的价值就会被最大化。 

本书相信“知行合一”的理念,而不是“只知,而不行”,避免开发人员出现眼高手低的现象。尤其是在技术面试过程中,面试官更加看重的是既懂原理,又能够主动是实践技术的技术人。

【特色七】深入剖析原理 

 本书以系统思维的方式,从业务功能视角剖析 RocketMQ 底层的技术原理,使读者具备快速阅读 RocketMQ 框架源码的能力。读者只有具备了这种能力,才能举一反三,实现更复杂的功能,应对更复杂的应用场景。

 【特色八】从运维的视角分析 RocketMQ 的最佳实践

【特色九】参与开源 

 本书向读者展示了如何修改 RocketMQ 源码,并快速验证案例分析。这样,读者可以从中学到参与开源的技能,并为后续自己能够参与开源做准备。

【特色十】双色印刷,读者体验会更好 

为了提高读者阅读本书的体验,在有上下两册的前提下(巨无霸,超过800页),出版社不吝啬印刷成本,依然采用双色印刷。

【推荐】本书的最佳学习路径 

 为了提高读者学习RocketMQ的效率,我这边结合我自身从RocketMQ小白到RocketMQ专家的经历,为读者汇总了一条最佳学习路径。

【寄语】作者寄语 

RocketMQ是我深度参与研究的一款开源消息中间件,无论是从源码,还是架构场景,我都提炼了很多最佳实践。

在开源领域,技术小伙伴可以使用的开源消息中间件非常的多,比如KafkaPulsar等,我之所以选择研究RocketMQ,除了工作内容和角色需要之外,更多的还是自己感兴趣,因此我建议技术小伙伴一定要先培养自己的兴趣,兴趣才是提升技术硬实力的第1要素。

当然我并不止研究了RocketMQ,还研究了PulsarKafka等(包括开源消息中间件生态中的主流框架),只是本书作为一本关于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最具价值技术专家的技术奖项。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/321001.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

肯·汤普逊 :我心目中的神,好像真正无敌之上的大佬都对C++提出了批判!大佬们的思想像红太阳太耀眼,常人不能直视

肯尼斯蓝汤普逊&#xff08;英语&#xff1a;Kenneth Lane Thompson&#xff0c;1943年2月4日—&#xff09;&#xff0c;小名肯汤普逊&#xff08;英语&#xff1a;Ken Thompson&#xff09;&#xff0c;美国计算机科学学者和工程师。黑客文化圈子通常称他为“ken”[1]。在贝尔…

为什么很多公司选择不升级JDK版本,仍然使用JDK8?

在讨论为什么许多公司选择不升级JDK版本&#xff0c;而继续使用JDK 8时&#xff0c;我们需要从多个角度来分析这个问题。以下是根据您提供的背景信息进行的一些分析和真实案例。 本文已收录于&#xff0c;我的技术网站 ddkk.com&#xff0c;有大厂完整面经&#xff0c;工作技术…

test Symbolic Execution-03-Soot - A Java optimization framework

拓展阅读 开源 Auto generate mock data for java test.(便于 Java 测试自动生成对象信息) 开源 Junit performance rely on junit5 and jdk8.(java 性能测试框架。性能测试。压测。测试报告生成。) test fuzz-01-模糊测试&#xff08;Fuzz Testing&#xff09; Soot 重要…

【linux】awk的基本使用

awk是shell中一个强大的文本处理工具&#xff0c;被用于处理文本和数据 当你心中默念想要使用类似于 处理某一行&#xff0c;处理某一列 的文本 的功能时&#xff0c;就是awk登场的时候了 举个简单的例子是&#xff0c;当我们想知道自己的所有网卡的名字时&#xff0c;可以用i…

繁花的范总-UMLChina建模知识竞赛第5赛季第3轮

DDD领域驱动设计批评文集 做强化自测题获得“软件方法建模师”称号 《软件方法》各章合集 参考潘加宇在《软件方法》和UMLChina公众号文章中发表的内容作答。在本文下留言回答。 只要最先答对前3题&#xff0c;即可获得本轮优胜。 如果有第4题&#xff0c;第4题为附加题&am…

OpenHarmony—Linux之系统调用

Linux之系统调用 这里我们只讨论&#xff1a; 硬件&#xff1a; Arm64系统&#xff1a; Linux系统 (Kernel-5.15-rc1)高级语言&#xff1a; C &#xff08;glibc-2.34&#xff09;模式&#xff1a; 64位 &#xff08;即未定义CONFIG_COMPAT&#xff09; 2、什么是系统调用 …

主键(设置/删除方法,复合主键),唯一键,主键和唯一键的应用差异,自增长字段(如何实现,查看上次的值),外键(引入,外键约束)

目录 主键(primary key) 介绍 作用 设置主键 建表前 建表后 复合主键 介绍 示例 删除主键 唯一键(unique) 介绍 意义 示例 建表 主键 唯一键 插入数据示例 主键和唯一键的应用差异 主键 唯一键 索引 auto_increment 介绍 示例 自动插入 手动插入 …

电子签章系统,怎么做到大量文件自动电子签章?

在当今信息爆炸的时代&#xff0c;海量文件的签署管理成为各行业面临的挑战之一。电子签章系统的出现&#xff0c;为解决这一问题提供了有效途径。本文将探讨电子签章系统如何实现海量文件自动签章&#xff0c;提高工作效率并确保安全性。 钉钉、企微、飞书、OA、CRM、ERP等&a…

K8S API访问控制之RBAC利用

前言 K8S对于API的访问安全提供了访问控制&#xff0c;主要为4个阶段&#xff0c;本文为第二个阶段——鉴权的RBAC。RBAC是基于角色的访问控制&#xff0c;使用kubeadm安装集群1.6版本以上的都默认开启了RBAC。本文主要研究集群可能存在的利用点及相对应的利用手法。 API访问…

图像的初识

一、图像的数组表示 RGB能够构成人眼所能识别的所有颜色。 二、图像的变换 Example&#xff1a; img.shape Out[329]: (512, 768, 3) img.dtype Out[330]: dtype(uint8) #补值变换 shift_temp_img [255,255,255] - img shift_img Image.fromarray(shift_temp_img.astype(ui…

机器学习~从入门到精通(二)线性回归算法和多元线性回归

为什么要做数据归一化 一、数据归一化&#xff1a; 1.最值归一化 2.均值方差归一化import numpy as npX np.random.randint(1,100,size100) X X.reshape(-1,2) X.shape X np.array(X,dtypefloat) X[:,0] (X[:,0]-np.min(X[:,0]))/(np.max(X[:,0])-np.min(X[:,0])) X[:,1]…

class_4:car类

#include <iostream> using namespace std; class Car{ public://成员数据string color; //颜色string brand; //品牌string type; //车型int year; //年限//其实也是成员数据&#xff0c;指针变量&#xff0c;指向函数的变量&#xff0c;并非真正的成员函数void (*…

强化学习应用(六):基于Q-learning的物流配送路径规划研究(提供Python代码)

一、Q-learning算法简介 Q-learning是一种强化学习算法&#xff0c;用于解决基于马尔可夫决策过程&#xff08;MDP&#xff09;的问题。它通过学习一个值函数来指导智能体在环境中做出决策&#xff0c;以最大化累积奖励。 Q-learning算法的核心思想是使用一个Q值函数来估计每…

C# .NET SQL sugar中 IsAny进行根据条件判断数据是否存在 IsAny的使用

SQL sugar 中控制器直接判断数据是否存在 首先确保你的Service层继承的表名 控制器中使用IsAny进行根据条件判断数据是否存在

Redis命令 - Sets命令组常用命令

Set集合&#xff0c;无序&#xff0c;一堆不重复值的组合。利用redis提供的set数据结构&#xff0c;可以存储一些集合性的数据。 使用场景&#xff1a;例如&#xff0c;实现如共同关注、共同喜好、二度好友等 1、SADD key member [member …] 向集合中添加一个或者多个成员 …

Windows Server调整策略实现999999个远程用户用时登录

正文共&#xff1a;1234 字 23 图&#xff0c;预估阅读时间&#xff1a;2 分钟 上篇文章中&#xff08;Windows Server 2019配置多用户远程桌面登录服务器&#xff09;&#xff0c;我们主要介绍了Windows Server 2019在配置远程桌面时&#xff0c;如何通过3种方式创建本地用户账…

Harbor安装

采用原生的方式安装Harbor 下载Harbor安装包&#xff1a;https://github.com/goharbor/harbor/releases/download/v2.3.4/harbor-offline-installer-v2.3.4.tgz 拖拽到Linux并解压&#xff1a; tar -zxvf harbor-offline-installer-v2.3.4.tgz -C /usr/local/修改Harbor配置文…

Python-AST语法树

一、抽象语法树 1、什么是抽象语法树 在计算机科学中&#xff0c;抽象语法树&#xff08;abstract syntax tree &#xff0c;AST&#xff09;&#xff0c;是源代码的抽象语法结构的树状表现形式&#xff0c;这里特指编程语言的源代码。AST是编译器或解释器在处理源代码时所使…

原子类-入门介绍和分类说明、基本类型原子类

Atomic翻译成中文是原子的意思。在化学上,我们知道原子是构成一般物质的最小单位,在化学 反应中是不可分割的。在我们这里Atomic是指一个操作是不可中断的。即使是在多个线程一起执 行的时候,一个操作一旦开始,就不会被其他线程干扰。 基本类型原子类 AtomicInteger:整…

QT上位机开发(权限管理)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 如果只是简单的工具软件&#xff0c;其实是没有权限管理这么一说的。比如说&#xff0c;串口工具、485工具之类的软件&#xff0c;其实根本不存在所…