myrpc 学习笔记-005 注册中心
项目地址 欢迎访问
笔记总览 myrpc 学习笔记-001 实现简易版 rpc myrpc 学习笔记-002 配置加载 myrpc 学习笔记-003 Mock 服务代理 myrpc 学习笔记-004 序列化实现和 SPI 机制 myrpc 学习笔记-005 注册中心 myrpc 学习笔记-006 自定义协议 myrpc 学习笔记-007 负载均衡 myrpc 学习笔记-008 重试机制 myrpc 学习笔记-009 容错机制 myrpc 学习笔记-0010 启动机制和注解驱动
架构图v5.0.0
- 实现注册中心(etcd zookeeper)
- 支持自定义注册中心实现类

一、注册中心是什么?
注册中心是RPC框架的“通讯录”:
- 服务端(提供者):启动时把自己的地址、接口信息注册进去
- 客户端(消费者):调用时从注册中心发现可用服务节点
- 心跳/监听:保证节点健康,自动剔除故障节点
二、核心功能
- 服务注册:服务启动时把节点信息存入注册中心
- 服务发现:客户端获取可用服务节点列表
- 心跳续约:防止节点因故障假死
- 服务下线:服务停机主动/自动删除节点
- 监听机制:节点变化实时通知客户端
- 本地缓存:提升性能,减轻注册中心压力
- 多注册中心支持:Etcd / ZooKeeper 可插拔
三、整体结构设计
1. 统一接口(规范)
▼java复制代码public interface Registry { void init(RegistryConfig config); // 初始化 void register(ServiceMetaInfo info); // 注册 void unRegister(ServiceMetaInfo info); // 注销 List<ServiceMetaInfo> serviceDiscovery(String serviceKey); // 发现 void destroy(); // 销毁 void heartBeat(); // 心跳 void watch(String key); // 监听 }
2. 工厂 + SPI 可扩展
▼java复制代码public class RegistryFactory { static { SpiLoader.load(Registry.class); } public static Registry getRegistry(String key) { return SpiLoader.getInstance(Registry.class, key); } }
支持 Etcd、ZooKeeper、Nacos 无缝切换。
3. 本地注册(内存存储)
▼java复制代码public class LocalRegistry { private static final Map<String, Class<?>> SERVICE_MAP = new ConcurrentHashMap<>(); }
作用:服务端反射调用时快速找到实现类。
四、Etcd 注册中心实现
1. 核心机制
- Key-Value 存储
- 租约(Lease):节点30秒过期
- 心跳续约:每10秒续期一次
- Watch 监听:节点删除自动清空缓存
2. 存储结构
▼text复制代码/rpc/服务名:版本号/地址:端口 -> {服务元信息}
示例:
▼text复制代码/rpc/com.xxx.UserService:1.0/127.0.0.1:8080
3. 服务注册流程
- 申请 30s租约
- 拼接 key、存储 value
- 绑定租约存入 Etcd
- 加入本地缓存
- 启动心跳定时任务
4. 心跳实现(最关键)
▼java复制代码// 每10秒执行一次 CronUtil.schedule("*/10 * * * * *", task -> { for (String key : localRegisterNodeKeySet) { // 获取租约ID long leaseId = kvs.get(0).getLease(); // 手动续约 leaseClient.keepAliveOnce(leaseId); } });
5. 服务发现流程
- 先查本地缓存
- 缓存不存在 → Etcd前缀查询
- 解析结果 → 写入本地缓存
- 对每个节点 开启监听
6. 监听机制
监听节点删除事件:
▼java复制代码watchClient.watch(key, response -> { for (WatchEvent event : response.getEvents()) { if (event.getEventType() == DELETE) { // 清空缓存,下次强制拉新 registryServiceCache.clearCache(); } } });
五、ZooKeeper 注册中心实现
1. 核心机制
- 临时节点:会话断开自动删除
- 天然心跳:无需手动续约
- Cache 监听:节点变化自动感知
2. 为什么不用心跳?
因为 ZooKeeper 临时节点特性:
- 客户端断开 → 节点自动删除
- 无需代码实现心跳
3. 服务注册
▼java复制代码serviceDiscovery.registerService(instance);
4. 服务监听
▼java复制代码CuratorCache cache = CuratorCache.build(client, key); cache.listenable().addListener( CuratorCacheListener.builder() .forDeletes(child -> clearCache()) .build() );
六、服务本地缓存(RegistryServiceCache)
▼java复制代码public class RegistryServiceCache { List<ServiceMetaInfo> serviceCache; void writeCache(); List<ServiceMetaInfo> readCache(); void clearCache(); }
作用:
- 避免频繁请求注册中心
- 提高调用速度
- 注册中心宕机仍可使用缓存调用
七、服务启动初始化(ProviderBootstrap)
▼java复制代码public class ProviderBootstrap { public static void init(List<ServiceRegisterInfo<?>> list) { // 1. RPC 初始化 RpcApplication.init(); // 2. 本地注册 LocalRegistry.register(serviceName, implClass); // 3. 注册中心注册 Registry registry = RegistryFactory.getRegistry(type); registry.register(serviceMetaInfo); // 4. 启动 TCP 服务 VertxTcpServer server = new VertxTcpServer(); server.doStart(port); } }
八、客户端调用流程(ServiceProxy)
▼java复制代码// 1. 从注册中心发现服务 List<ServiceMetaInfo> list = registry.serviceDiscovery(serviceKey); // 2. 负载均衡选择一个节点 ServiceMetaInfo selected = loadBalancer.select(params, list); // 3. 发送 TCP 请求 RpcResponse response = VertxTcpClient.doRequest(request, info);
九、总结
- 接口化设计:可随意切换注册中心实现
- SPI 加载:高度可扩展
- Etcd 租约+心跳:保证节点健康
- ZooKeeper 临时节点:天然健康检查
- 本地缓存:高性能
- Watch 监听:实时感知节点上下线
- 优雅停机:服务下线主动删除节点
- 统一存储结构:服务名+版本+地址
十、不同注册中心对比
| 特性 | Etcd | ZooKeeper |
|---|---|---|
| 存储类型 | KV | 树结构 |
| 节点类型 | 带租约 | 临时/持久 |
| 心跳 | 代码实现 | 无需实现 |
| 监听 | Watch | Cache |
| 一致性 | Raft | ZAB |
| 易用性 | 高 | 中 |
评论
问答助学
相关内容
0个评论
全部评论
点击登录,快来和大家讨论吧~
表情
图片
暂无评论
内容推荐
Day 12✅ 今天做了:vue前端, 了解vue - Nginx - springboot关系⏰ 明天计划:继续搞前端的功能实现
4
🚩JavaD121、某个接口有10个抽象方法和100个具体的实现类,考虑到接口后期可能需要增加方法,设计接口时,通过中间的一个抽象类(适配器抽象类)默认实现或空实现接口(都是使用普通方法),然后具体的100个子类覆写自己想要的方法。后期接口增加方法时,给适配器抽象类增加一个普通方法,第101个具体子类再覆写适配器抽象类的第101个方法。2、抽象方法可以声明为static,错,因为static方法
2
🚩JavaD131、抽象类、继承、多态、接口、内部类,单独每一章节能懂,综合后就似懂非懂2、每一章节重复看视频,还是懂,做综合题,这一遍刷题是对的,再接着刷题是错的。3、死板的知识适合我,灵活的不适合。4、五大山头压着都懵圈了,看来还要多花时间在这五大山头
3
Day 13✅ 今天做了:Vue表单搜索, 搜索栏布局⏰ 明天计划:继续学前端
2
今天学了Python基础之:①数据类型和变量:五大数据类型以及变量常量②字符串与编码:字符编码以及Python中的字符串、编解码、格式化
1
