6.9 KiB
背景
目前灾备方案使用客户端User唯一标识做灾备切换,能有效保障整个客户端元数据统一切换。目前用户存量场景存在Kafka User共享使用情况,但是各个客户端对Topic的访问是互相独立的,为了兼容这种场景实现客户端能独立进行灾备切换,而不影响其他客户端连带切换。
方案
Client端兼容方案二
client.id 格式: HA#AppId#TopicName InstanceID
一个InstanceID可以对应多个Topic
约束: AppID下每个客户端实例使用相同的InstanceID,并且不同客户端实例的InstanceID不能重复
客户端实例定义:最好是每个生产者、消费者实例使用一套InstanceID,次之是应用粒度,一个应用使用一套InstanceID但是存在访问多个Topic会存在一些关联切换情况
注意:客户端每次启动都使用相同的InstanceID,不能每次启动都生成新的InstanceID
InstanceID生成方式:
- 由平台申请生成InstanceID,可以在Topic申请时为每一个Topic产生一个InstanceID,或者多个Topic申请一个InstanceID
- 由用户自己控制,直接在客户端设置一个ID
InstanceID和Topic对应关系:
- 声明式:由平台申请InstanceID与Topic绑定关系
- 自动化:从引擎侧上报的连接信息中自动获取(客户端未启动过这种场景获取不到)
引擎侧上报用户访问信息(已有):TopicName、AppID、访问类型(生产、消费)、ClientID
平台切换:
用户选择切换方式:用户维度、用户+InstanceID维度
用户维度:跟现有逻辑保持一致,用户下所有Topic同时切换
用户+InstanceID维度:切换Topic时,如果用户下InstanceID绑定了Topic则只切换这个InstanceID,否则整个用户进行切换
Gateway、引擎处理:
如果AppID+InstanceID绑定了集群则按这个集群进行转发,否则按AppID粒度进行转发
Server端兼容方案
现状
灾备Gateway、Broker会根据客户端标识转发以下请求
- API_VERSIONS
- METADATA(null、empty、some topics)
- FIND_COORDINATOR
- INIT_PRODUCER_ID // 无事务、幂等场景可忽略
Broker会根据客户端标识阻断以下请求
- PRODUCE
- FETCH
- OFFSET_COMMIT
- OFFSET_FETCH
- JOIN_GROUP
- HEARTBEAT
- OFFSET_FOR_LEADER_EPOCH
流程
每个节点建立连接后会发送API_VERSIONS请求获取节点协议版本信息
生产者:
-
生产者启动后会先向引导地址发送METADATA(topics=empty)请求,只请求集群地址的元数据,并更新缓存中metadata的nodes信息
-
当发送一条消息后,生产者刷新元数据发送METADATA(topics=some topics)请求
消费者:
-
消费者启动后会向引导地址发送METADATA(topics=empty)请求,只请求集群地址的元数据,并更新缓存中metadata的nodes信息
-
消费者启动后会向引导地址发送FIND_COORDINATOR请求,获取Coordinator地址
-
客户端向Coordinator发起连接,后续发送JOIN_GROUP、SYNC_GROUP
-
随后会更新客户端元数据,发送元数据请求
如果订阅类型为AUTO_TOPICS会向引导地址发送METADATA(topics=some topics)请求
如果订阅类型为AUTO_PATTERN,则会向引导地址发送**METADATA(topics=null)**请求(null为all topics元数据请求)
请求归类:
- 无信息
- API_VERSIONS
- METADATA(null、empty)
- 含Topic信息(多个)
- METADATA(some topics)
- PRODUCE
- FETCH
- OFFSET_FOR_LEADER_EPOCH
- 含Group信息
- FIND_COORDINATOR
- OFFSET_COMMIT
- OFFSET_FETCH
- JOIN_GROUP
- HEARTBEAT
改造
根据更细粒度客户端标识进行转发和阻断,对于生产者使用AppID#TopicName,消费者使用AppID#TopicName或AppID##GroupName作为客户端标识
限制1:要求AppID#TopicName或AppID##GroupName全局唯一
限制2:要求客户端只访问一个Topic(待定)
-
客户端标识获取
通过解析请求协议内容获取对应的标识符
Topic: AppID#TopicName
Group:AppID##GroupName
-
请求协议处理
根据优先级:AppID##GroupName、AppID#TopicName、AppID获取客户端标识是否绑定集群如果绑定集群进行响应转发或者阻断
-
无标识请求处理
-
API_VERSIONS
客户端发送API_VERSIONS到Gateway,由Gateway直接响应给客户端GW的APIs信息,不进行转发(由于GW是基于2.5版本的,灾备也是基于2.5版本),这里需要判断是不是灾备场景,非灾备场景继续按原有逻辑进行处理
-
METADATA
empty情况:这种情况是客户端第一次启动时发出的请求nodes信息,由Gateway直接响应给客户端GW地址,不进行转发
null情况:这种情况时消费者采用正则的方式进行订阅,需要返回用户有权限的所有Topic列表,Gateway无法处理这种场景
-
-
多Topic处理
方案1:只处理单一Topic情况,如果出现多个Topic按AppID粒度进行转发或阻断
方案2:平台维护AppID#TopicList与集群绑定关系,当请求的Topic集合为维护的子集时按照细粒度转发否则使用AppID粒度进行转发或阻断
-
平台改造
维护:平台增加AppID#TopicName和AppID##GroupName与集群绑定关系
切换:如果AppID下Topic维护了细粒度绑定关系切换时则不关联其他Topic,未维护细粒度绑定关系的Topic切换时不关联出其他已经维护了细粒度绑定关系的Topic
总结
前提假设: 1. Gateway版本与Broker版本一致 2. 明确了解用户客户端访问Topic范围
局限性: 不支持消费者采用正则模式的订阅方式
只有在平台管理员能够明确了解共享用户的使用情况下才可以使用这种兼容方案,否则可能会导致客户端访问集群元数据混乱部分Topic访问失败的情况。平台做大之后平台管理员很难了解每一个用户的使用情况,也许当下是规范的后续可能会产生使用交叉情况,所以这个兼容方案制作临时使用,长期优先在平台侧进行细粒度管控。
Client端兼容方案一
通过在客户端增加client.id配置生成更细粒度的标识,由服务器端进行识别转发
client.id 格式: HA#AppId#TopicName
-
在Gateway和Broker的ZK中维护AppId#TopicName与集群的绑定关系
-
Gateway和Broker识别客户端ClientID以HA开头,则此ClientID是一个细粒度灾备标识,根据AppId#TopicName获取集群绑定关系,将请求转发到实际集群
0.10.0.0 Protocol version
METADATA V1满足正常使用
GROUP_COORDINATOR_REQUEST V0 (10 FindCoordinatorRequest) V1+增加key_type,默认为0:group
API_VERSIONS V0
Gateway为2.5版本,如果客户端是2.5,服务端是0.10,客户端将以2.5版本协议进行发送