Seata 注册中心

注册中心

注册中心的实现有很多种方式, 如下图所示。
注册中心实现图
这是注册中心定义的接口, 分别给不同的角色使用。 例如协调者: 注册,取消注册,关闭。 事务管理器和资源管理器: 订阅,取消订阅,查找

public interface RegistryService<T> {
	// 注册
	void register(InetSocketAddress address) throws Exception;

   	//  取消注册
   	void unregister(InetSocketAddress address) throws Exception;

   	// 订阅
   	void subscribe(String cluster, T listener) throws Exception;

    // 取消订阅
    void unsubscribe(String cluster, T listener) throws Exception;

    // 查找
    List<InetSocketAddress> lookup(String key) throws Exception;

    // 关闭
    void close() throws Exception;

    // 获得服务组名称
    default String getServiceGroup(String key) {
        key = PREFIX_SERVICE_ROOT + CONFIG_SPLIT_CHAR + PREFIX_SERVICE_MAPPING + key;
        if (!SERVICE_GROUP_NAME.contains(key)) {
            ConfigurationCache.addConfigListener(key);
            SERVICE_GROUP_NAME.add(key);
        }
        return ConfigurationFactory.getInstance().getConfig(key);
    }
     Set<String> SERVICE_GROUP_NAME = new HashSet<>();
}

注册中心有什么意义呢?

注册中心主要就是为了让TM,RM动态感知协调者的变更。 在向协调者发送请求的时候,会从注册中心里的协调者列表用负载均衡算法选择一个协调者,然后发送请求。 从这里可以看出协调者必须是对等的, 每个请求发给哪一台协调者都是一样的。

例如seata中的各个角色和注册中心的交互图:

事物管理器 资源管理器 协调者 注册中心 注册 订阅 通过事件更新协调者列表 订阅 通过事件更新协调者列表 通过注册中心工厂获取协调者列表 通过协调者列表用负载均衡组件选择一个协调者 发送请求 通过注册中心工厂获取协调者列表 通过协调者列表用负载均衡组件选择一个协调者 发送请求 事物管理器 资源管理器 协调者 注册中心

zookeeper注册中心加载流程

在创建 GlobalTransactionScanner 时,会确认事物分组名称,例如: my_test_tx_group

注册中心的加载

Caller RegistryFactory EnhancedServiceLoader getInstance load RegistryProvider SPI 方式加载 RegistryProvider RegistryProvider RegistryService = RegistryProvider.provide Caller RegistryFactory EnhancedServiceLoader

接下来看获取注册中心的协调者(TC)列表

  1. 首先从本地缓存中获取, 不存在从注册中心获取
  2. 通过配置中心获取集群名称: service.vgroupMapping.my_test_tx_group = default
  3. 获取协调者列表, zk的节点数据: /registry/zk/default = [192.168.1.103:8091]
  4. 将协调者列表加入本地缓存
RegistryService Configuration Zookeeper lookUp 获取集群名称 default 获取协调者列表 [192.168.1.103:8091] 将ip放入本地集群名称缓存,订阅zk节点 RegistryService Configuration Zookeeper

负载均衡

负载均衡算法在1.3.0 还没有最少使用算法和一致性hash算法, 这里是1.4.0 的负载均衡图
负载均衡实现图
负载均衡算法,用来在多台协调者中选择一台机器,将消息发送给协调者。 例如TC1,TC2,TC3 通过负载均衡算法选择了TC2, 将全局事物开启请求发送给TC2。

当只有一台机器的时候,是不会采用任何负载均衡算法的

随机

从当前机器总数5, 通过 ThreadLocalRandom 随机一个下标, 例如 随机到 3, 选择3的下标,就是第四台机器

最少使用

1.4.0 的负载均衡算法

最少使用的算法由RpcStatus实现,RemotingClient 内部有通过SPI机制加载的列表: List<RpcHook>,
发消息前对RpcStatus计数+1, 收到响应后对计数-1
RemotingClient

发消息变更 RpcStatus 的流程

ResourceManager RemotingClient StatusRpcHook RpcStatus TC sendSyncRequest doBeforeRpcHooks doBeforeRequest beginCount request response doAfterRpcHooks doAfterRequest endCount ResourceManager RemotingClient StatusRpcHook RpcStatus TC

首先遍历Invoker, 然后通过RpcStatus拿到对应的调用次数。
首先过滤到一组最少的调用次数,如果只有一个,就只用这一个, 如果有多个最少的,就随机一个。

例如有五台机器的调用次数如下: (4,8,9,29,4), 筛选到新数组(0,5) , 新数组的内容是老数组的下标, 然后新数组随机一个值: 下标1, 取得里面的值:5. 那么就取原数组的第5个下标。 最终调用第五台机器。

例如有五台机器调用次数如下: (5,8,19,6,2), 只有2是最少的, 所以调用第五台机器

一致性哈希

1.4.0 的负载均衡算法
在 [0,Integer,MAX_VALUE) 范围看成一个环, 如果环上用实际节点,很容易会不均匀。 例如 0,MAX_VALUE-100 属于节点A, 其他的属于节点B。 那么这种负载均衡算法就没有意义了, 99.99%都是选择节点A。

在这里插入图片描述

为了解决节点分布不均匀的问题, 引入了虚拟节点。 例如原先的节点A的hash是MAX_VALUE-1000, 虚拟节点就是计算 节点A+1,节点A+2,节点A+n 重新计算的hash值, 会有更大概率分布在整个环上。 根据调用的全局事物ID 计算一个hash值, 找到环上的下一个虚拟几点, 最后找到实际节点进行调用。

在这里插入图片描述

一致性hash听起来还是很高大上的,实现方式一个是虚拟节点的hash计算, 另一个是用 SortedMap.tailMap 找到下一个hash值

轮询

先从 [0,Integer.MAX_VALUE) 取值, 然后用当前值 % 机器总数

例如轮询到 18, 总共 5 太机器 , 18%5 = 3, 选择3的下标,就是第四台机器

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值