rpc注册中心优化

心跳检测

给注册的结点信息一个倒计时,让结点定期的续期,重置倒计时,如果节点宕机了,一直不续期,etcd就会进行key的过期删除

  1. 服务者想etcd注册自己的服务信息,在注册时设置过期时间
  2. etcd收到服务方的信息后一直维持这个过期时间,并在过期后删除key
  3. 服务方定期向etcd发起请求续签自己的注册信息(续期时间小于过期时间)
java 复制代码
// 创建一个 30 秒的租约
        long leaseId = leaseClient.grant(30).get().getID();

        // 设置要存储的键值对
        String registerKey = ETCD_ROOT_PATH + serviceMetaInfo.getServiceNodeKey();
        ByteSequence key = ByteSequence.from(registerKey, StandardCharsets.UTF_8);
        ByteSequence value = ByteSequence.from(JSONUtil.toJsonStr(serviceMetaInfo), StandardCharsets.UTF_8);

        // 将键值对与租约关联起来,并设置过期时间
        PutOption putOption = PutOption.builder().withLeaseId(leaseId).build();
        kvClient.put(key, value, putOption).get();

实现心跳检测

java 复制代码
 for(String key : loaclRegistryNodeKeySet) {
                    try{
                        List<KeyValue> keyValues = kvClient.get(ByteSequence.from(key, StandardCharsets.UTF_8))
                                .get().getKvs();
                        // 如果节点过期,需要重启节点才能注册
                        if(CollUtil.isEmpty(keyValues)){
                            continue;
                        }
                        // 节点为过期,重新注册
                        KeyValue keyValue = keyValues.get(0);
                        String value = keyValue.getValue().toString(StandardCharsets.UTF_8);
                        ServiceMetaInfo serviceMetaInfo = JSONUtil.toBean(value, ServiceMetaInfo.class);
                        register(serviceMetaInfo);
                    }catch (Exception e){
                        throw new RuntimeException(key+"续签失败",e);
                    }
                }

服务节点下线机制

  • 主动下线:关闭了provider的链接
  • 被动下线:服务者出现异常后,将该节点剔除

我们需要完善的是主动下线机制,利用jvm中的shutdownHook实现,允许开发者在jvm关闭前完成一些必要操作,例如数据库的关闭,释放资源等

java 复制代码
@Override
    public void destroy() {
        System.out.println("当前节点下线");
        // 下线节点,遍历所有的key
        for(String key: loaclRegistryNodeKeySet) {
            try{
                kvClient.delete(ByteSequence.from(key, StandardCharsets.UTF_8));
            }catch (Exception e){
                throw new RuntimeException(key+"下线失败");
            }

        }
        // 释放资源
        if (kvClient != null) {
            kvClient.close();
        }
        if (client != null) {
            client.close();
        }
    }

消费者服务缓存

由于服务节点的更新频率不是很高,所以在注册后完完全可以缓存在本地,下次就不需要在注册中心获取了,此时我们通过本地缓存实现

java 复制代码
public class RegistryServiceCache {

    /**
     * 服务缓存
     */
    List<ServiceMetaInfo> serviceCache;

    /**
     * 写缓存
     *
     * @param newServiceCache
     * @return
     */
    void writeCache(List<ServiceMetaInfo> newServiceCache) {
        this.serviceCache = newServiceCache;
    }

    /**
     * 读缓存
     *
     * @return
     */
    List<ServiceMetaInfo> readCache() {
        return this.serviceCache;
    }

    /**
     * 清空缓存
     */
    void clearCache() {
        this.serviceCache = null;
    }
}

修改我们EtcdRegistry的判断逻辑

java 复制代码
// 优先从缓存获取服务
    List<ServiceMetaInfo> cachedServiceMetaInfoList = registryServiceCache.readCache();
    if (cachedServiceMetaInfoList != null) {
        return cachedServiceMetaInfoList;
    }
......
    
    
     // 写入服务缓存
        registryServiceCache.writeCache(serviceMetaInfoList);

服务端缓存更新机制

当注册信息发生改变后(例如节点下线),需要及时更新消费缓存,此时采用etcd的watch机制,当监听到某个key发生变化后,触发事件

java 复制代码
/**
     * 只监听首次加入到监听集合中的key,防止重复
     * @param serviceNodeKey
     */
    @Override
    public void watch(String serviceNodeKey) {
        Watch watchClient = client.getWatchClient();
        // 开启监听
        boolean newWatch = watchKeySet.add(serviceNodeKey);
        if (newWatch) {
            watchClient.watch(ByteSequence.from(serviceNodeKey,StandardCharsets.UTF_8),response->{
                for(WatchEvent event : response.getEvents()){
                    switch (event.getEventType()){
                        // key 删除时触发
                        case DELETE:
                            // 清除缓存
                            registryServiceCache.clearCache();
                            break;
                        case PUT:
                        default:
                            break;
                    }
                }
            });
        }
    }

tip:ETCD集群的高可用保障

  1. 多节点部署,确保集群中有足够的健康节点
  2. raft一致性算法:通过选举和复制机制,确保集群中节点状态保持一致
  3. 自动选举和复制
  4. 负载均衡:分发请求到每个节点中,确保了高可用
  5. 监控和告警
  6. 通过WAL机制进行日志记录,即使在系统崩溃后也能进行数据恢复
相关推荐
草莓熊Lotso12 小时前
【Redis 初阶】Set 类型深度解析:去重集合的运算能力与实战场景
linux·网络·数据库·windows·redis·tcp/ip·缓存
XR12345678813 小时前
汽车制造园区网络怎么建?柔性产线与 AGV 的选型逻辑
网络·汽车·制造
IT大白鼠1 天前
MSF二次开发与自定义模块编写
网络·安全·web安全·msf
Julien20041 天前
调查和解决 SELinux 问题
linux·运维·服务器·网络·学习方法
kekekzt1 天前
TCP协议的粘包问题介绍,IP分片,MTU,MSS,滑动窗口的概念及之间的关系
网络·网络协议·tcp/ip
mooooooooooye1 天前
2026 年跨平台 SSH 客户端怎么选?Xterminal、Termius、MobaXterm 谁更合适
服务器·网络·ssh
Blockchina1 天前
Codex 实战:从一句需求到可验收的 Linux 主机巡检脚本
运维·服务器·网络
江安下小雨1 天前
muduo网络库(十六):新增连接池模块
网络·c++
aiot189189352181 天前
机场候机大厅高空场景技术红线!蓝牙AOA不能做手机导航??!!
大数据·网络·人工智能·蓝牙aoa
从入门到退休1 天前
企业远程控制选型:向日葵SDK vs RustDesk自建,谁是更务实的选择?
运维·服务器·网络·远程工作·远程控制