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机制进行日志记录,即使在系统崩溃后也能进行数据恢复
相关推荐
嗝屁小孩纸2 分钟前
免费测评RPC分布式博客平台(仅用云服务器支持高性能)
服务器·分布式·rpc
emiya_saber27 分钟前
Linux 硬盘分区管理
java·linux·网络
apple-mapping27 分钟前
电脑有连接网络,但浏览器网页无法打开
网络
小草cys1 小时前
【解决】华为欧拉系统上遇到能 ping 通 IP 地址(如 8.8.8.8)但无法 ping 通域名(如 www.baidu.com)的情况
网络·网络协议·tcp/ip
jenchoi4131 小时前
【2025-11-11】软件供应链安全日报:最新漏洞预警与投毒预警情报汇总
网络·安全·web安全·网络安全·npm
重启编程之路1 小时前
python 基础学习socket -UDP编程
python·网络协议·学习·udp
站长朋友1 小时前
解决SSL证书安装后网站仍显示“不安全”的问题
网络协议·安全·ssl·ssl证书安装不安全·锐安信ssltrus·ocsp响应速度·根证书链完整
踏浪无痕2 小时前
记一次被 K8s 网络 SNAT 坑惨的经历
网络协议·kubernetes
百***65952 小时前
PON架构(全光网络)
网络·数据库·架构
WDLOVELONGLONG2 小时前
与实验室服务器互相ping
linux·服务器·网络