在 MIMP 项目中,etcd 充当了微服务架构的**“神经中枢” 。它通过 服务注册 和 服务发现**机制,让各个独立的微服务(User, Message, Gateway 等)能够互相感知并协同工作。
下面我结合项目代码,从 服务注册 (我是谁)和 服务发现 (你在哪)两个维度详细说明。
1. 服务注册 (Service Registry) —— “我上线了,请联系我”
每个微服务(如 user_server )启动时,必须把自己登记到 etcd 上,这样其他服务才能找到它。
代码实现
在 etcd.hpp 中, Registry 类负责这个工作。
- 绑定租约 (Lease) :
为了防止服务挂了但 etcd 上还有残留数据,注册时会绑定一个 短期租约 (如 3 秒)。// 创建租约,并开启自动续租 (KeepAlive) _lease_id = _client->leasekeepalive(3).get().ID; - 写入数据 (Put) :
将服务名和地址写入 etcd。Key 通常是 /service/服务名/实例ID ,Value 是 IP:Port 。// 注册服务:Key=/service/user_service/instance_1, Value=127.0.0.1:10003 _client->put(key, value, _lease_id); ```项目应用
在 user_server 启动时,会调用 Registry 将自己注册上去。
参考 user_server.hpp :
// 构造注册对象,将本机地址注册到 etcd
_registry_client = std::make_shared<Registry>(reg_host);
_registry_client->registry(service_name, access_host);
2. 服务发现 (Service Discovery) —— “我想找人,他在哪?”
调用方(如 gateway_server )需要知道下游服务(如 user_server )的地址。它不直接读配置文件,而是问 etcd。
代码实现
在 etcd.hpp 中, Discovery 类负责这个工作。
- 初始获取 (List) :
刚启动时,先拉取目录下所有的服务节点。auto resp = _client->ls(basedir).get(); - 实时监听 (Watch) :
关键点!它会启动一个 Watcher 线程,死死盯着 etcd 的目录。一旦有服务上线(Put)或下线(Delete),立刻触发回调。_watcher = std::make_shared<etcd::Watcher>(*_client, basedir, [this](etcd::Response const &resp) { if (resp.action() == "put") _put_cb(resp.key(), resp.value()); if (resp.action() == "delete") _del_cb(resp.key ()); }, true); ```项目应用
在 gateway_server 中,它通过 ServiceManager 来管理这些发现的服务。
参考 gateway_server.hpp :
// 绑定回调函数:当 etcd 通知有服务上线/下线时,更新本地的连接池
auto put_cb = std::bind(&ServiceManager::onServiceOnline,
_mm_channels.get(), _1, _2);
auto del_cb = std::bind(&ServiceManager::onServiceOffline,
_mm_channels.get(), _1, _2);
// 启动服务发现,监听 /service 目录
_service_discoverer = std::make_shared<Discovery>
(reg_host, base_dir, put_cb, del_cb);
3. 实际运行流程 (举例:网关转发登录请求)
- UserServer 启动 :
- 向 etcd 写入 /service/user_service/node1 -> 192.168.1.10:10003 。
- 开始每秒发送心跳续租。
- Gateway 感知 :
- Discovery 类的 Watcher 收到 PUT 事件。
- 调用 ServiceManager::onServiceOnline ,建立到 192.168.1.10:10003 的 RPC 连接通道。
- UserServer 宕机 :
- 进程退出,心跳停止。
- 3秒后,etcd 租约过期,自动删除 /service/user_service/node1 。
- Gateway 摘除 :
- Discovery 收到 DELETE 事件。
- 调用 ServiceManager::onServiceOffline ,从连接池中移除该通道,后续请求不再发给它。
4. 为什么不用 Redis 做服务发现?
虽然 Redis 也能存 Key-Value,但 etcd 有两个 Redis 无法替代的优势:
- 强一致性 (CP) :etcd 基于 Raft 算法,保证集群中所有节点的数据完全一致。服务发现对数据准确性要求极高(不能把请求发给已经挂掉的节点),Redis 的主从复制是异步的,可能存在延迟。
- Watch 机制 :etcd 的 Watch 机制专为配置变更设计,能精确推送变更事件。Redis 的 Pub/Sub 是“发后即忘”,如果网络抖动,消费者可能会漏掉上下线通知。
总结
在 MIMP 项目中, etcd 是动态的、实时的服务通讯录 。
- 代码中 Registry 类利用 Lease 机制实现了 自动注销 。
- 代码中 Discovery 类利用 Watch 机制实现了 实时感知 。
这保证了 Gateway 永远只把请求发给活着的服务节点,实现了系统的高可用。
etcd 就是 MIMP 项目的**“活地图”**。它保证了 Gateway 能实时找到所有的后端服务,并且在某个服务宕机时,能立刻感知并停止向其转发请求,确保系统的高可用。
转载自CSDN-专业IT技术社区
原文链接:https://blog.csdn.net/fwfxhhx/article/details/158705207



