生产端:生产者客户端的SDK有哪些设计要点

101 阅读4分钟

image.png

基础功能,包括请求连接管理、心跳检测、内容构建、序列化、重试、容错处理等等。生产功能,包括客户端寻址、分区选择、批量发送,生产错误处理、SSL、压缩、事务、幂等等等。

客户端基础功能

连接管理

一般有初始化创建连接和使用时创建链接两种方式。

因为客户端会有空闲连接回收机制,创建连接的耗时一般较短,所以在实际的架构实现中,两种方式都会用,优劣区别并不明显。不过,从资源利用率的角度考虑,我建议你使用晚建立连接的方式。

心跳检测

心跳检测是客户端和服务端之间保活的一种机制,检测服务端或者客户端的一方不可用时,另一方可以及时回收资源,避免资源浪费。一般通过 ping-pong 的方式来发起探测。

一般有基于 TCP 的 KeepAlive 保活机制和应用层主动探测两种形式。

基于 TCP 的 KeepAlive 保活机制是 TCP/IP 协议层内置的功能,需要手动打开 TCP 的 KeepAlive 功能。通过这种方案实现心跳探测,优点是简单,缺点是 KeepAlive 实现是在服务器侧,这种连接会占用服务器内存资源,导致服务端的性能下降。

应用层主动探测一般是 Client 向 Server 发起的,主要解决灵活性和 TCP KeepAlive 的缺陷。探测流程一般是客户端定时发送保活心跳,当服务端连续几次没收到请求,就断开连接。

错误处理

在客户端的处理中也会将错误分为可重试错误和不可重试错误两类。

image.png

可重试错误就是这类通过一次或多次重试可能恢复的异常;不可重试的错误就是不管如何重试都无法恢复的异常。

重试机制

重试策略一般会支持重试次数和退避时间的概念。当消息失败,超过设置的退避时间后,会继续重试,当超过重试次数后,就会抛弃消息或者将消息投递到配置好的重试队列中。

生产相关功能

客户端寻址机制

主要有Metadata(元数据)寻址机制和服务端内部转发两个思路。

  1. Metadata(元数据)寻址机制 服务端会提供一个获取全量的 Metadata 的接口,客户端在启动时,首先通过接口拿到集群所有的元数据信息,本地缓存这部分数据信息。然后,客户端发送数据的时候,会根据元数据信息的内容,得到服务端的地址是什么,要发送的分区在哪台节点上。最后根据这两部分信息,将数据发送到服务端。

元数据信息主要包括 Topic 及其对应的分区信息和 Node 信息两部分。客户端一般通过定期全量更新 Metadata 信息和请求报错时更新元数据信息两种方式,来保证客户端的元数据信息是最新的。目前 Kafka、RocketMQ、Pulsar 用的都是这个方案。

2.服务端内部转发机制

服务端的每一台 Broker 会缓存所有节点的元数据信息,生产者将数据发送给 Broker 后,Broker 如果判断分区不在当前节点上,会找到这个分区在哪个节点上,然后把数据转发到目标节点。

这个方案的好处是分区寻址在服务端完成,客户端的实现成本比较低。但是生产流程多了一跳,耗时增加了。另外服务端因为转发多了一跳,会导致服务端的资源损耗多一倍。

这种方案不适合大流量、高吞吐的消息队列。目前业界只有 RabbitMQ 使用这个方案。

生产分区分配策略

消息队列默认支持轮询、按 Key Hash、手动指定、自定义分区分配策略四种分区分配策略。

批量语义

批量发送的实现思路一般是在客户端内存中维护一个队列,数据写入的时候,先将其写到这个内存队列,然后通过某个策略从内存队列读取数据,发送到服务端。

数据发送方式

消息队列一般也会提供同步发送、异步发送、发送即忘三种形式。

发送即忘指消息发送后不关心请求返回的结果,立即发送下一条。

集群管控操作

集群管控操作一般是用来完成资源的创建、查询、修改、删除等集群管理动作。资源包括主题、分区、配置、消费分组等等。

程序编码上一般由命令行、参数包装、底层 SDK 调用三部分组成。主要流程是接收参数、处理参数、调用 SDK 等相关操作。


此文章为11月Day7学习笔记,内容来源于极客时间《深入拆解消息队列 47 讲》