当前位置: 首页 > news >正文

基于微服务的即时通讯系统 -- etcd实现服务注册与发现

前言

我们首先通过一个架构图来理解即时通讯系统:

即时通讯系统是高并发高可用的,倘若不加注册中心,网关需要轮询每个子服务,子服务需要主动通知网关自己准备好了,不说效率,只是注册发现都会存在海量网络传输,引入注册中心将发现和注册解耦,极大提高效率。

etcd实现注册中心

etcd是一个存储键值对的服务器(可以理解为数据库),该项目中引入了etcd实现注册中心,根本原因是其中的高级特性与机制能够解决多个子服务的数据一致性,换句话说,它可以监听一个服务的变化从而通知子服务,这在多个子服务的场景下十分重要,否则注册中心只有一个服务备份,谁更改了它,其他子服务都无从得知。

(1)主机与etcd

从主机与etcd的角度看,主机 a 向 etcd 中注册一个 (服务名,提供服务的主机地址)键值对,

主机 b 从etcd中申请到可用的服务。

(2)etcd - CP架构

那etcd底层如何实现最重要的数据一致性呢,注册流程保持一致,不过在注册接口 put 中我们注意到一个 lease_id ,它是租约ID,什么是租约?简单来说就是键值对数据能存储在 etcd 中的时间,通过创建一个租约对象就能让键值对数据在租约过后自动删除。

如果想续租呢?通常使用一个Keepalive(长连接对象)为租约续租,其实就是为 etcd 客户端和外部注册服务的主机建立一个长连接,一旦外部服务下线了,长连接自然也断开,从而通知 etcd 服务端删除该服务。

监听客户端如何知道这样的变化呢?它首先从 etcd 服务端拉取在 base_service 目录下的服务,之后交给 Watcher 对象监听,Watcher 对象监听到服务变化后,通过回调函数反馈给监听客户端。

注册服务客户端代码示例:

// 注册服务的客户端类 class Registery { public: // 创建一个智能指针便于外部访问 using ptr = std::shared_ptr<Registery>; Registery(const std::string& registery_host) :_registery_host(registery_host), _put_client(std::make_shared<etcd::Client>(registery_host)), _keepalive(_put_client->leasekeepalive(3).get()), _lease_id(_keepalive->Lease()) { // 先创建客户端 // 再创建长连接保活对象 // 最后得到租约id } bool registery(const std::string& key, const std::string &val) { auto resp = _put_client->put(key, val, _lease_id).get(); if(resp.is_ok() == false) { LOG_ERROR("{} 注册的 {}服务失败\n", val, key); return false; } LOG_DEBUG("{} 注册的 {}服务成功\n", val, key) return true; } ~Registery() { LOG_DEBUG("主机{}已下线\n", _registery_host); _keepalive->Cancel();} private: std::string _registery_host; // 主机名 std::shared_ptr<etcd::Client> _put_client; // 注册客户端 std::shared_ptr<etcd::KeepAlive> _keepalive; // 长连接租约保活对象 uint64_t _lease_id; // 租约id };

监听服务客户端代码示例:

// 监听(发现)服务的客户端类 // 提供两个put和get回调函数,以此让用户做出响应 using callback = std::function<void(etcd::Response)>; class Discovery { public: // 创建一个智能指针便于外部访问 using ptr = std::shared_ptr<Discovery>; using NotifyCallback = std::function<void(std::string, std::string)>; Discovery(const std::string& registery_host, const std::string& base_dir, const NotifyCallback& put_cb, const NotifyCallback& del_cb) :_registery_host(registery_host), _get_client(std::make_shared<etcd::Client>(_registery_host)), _base_dir(base_dir), _put_cb(put_cb), _del_cb(del_cb) { // 2、拉取所有注册过的服务 auto resp = _get_client->ls(_base_dir).get(); if(resp.is_ok()) { // 遍历所有注册的服务 for(int i = 0; i < resp.keys().size(); i++) { std::cout << resp.key(i) << "可以提供" << resp.value(i) << "服务" << std::endl; // 发现服务并触发回调 if(_put_cb) _put_cb(resp.key(i), resp.value(i).as_string()); } } else { LOG_ERROR("获取键值对数据失败-{}\n", resp.error_message()); } // 3、创建监听对象 _watcher = std::make_shared<etcd::Watcher>(*_get_client.get(), _base_dir, std::bind(&Discovery::WatcherCallback, this, std::placeholders::_1)); _watcher->Wait(); } private: void WatcherCallback(const etcd::Response& resp) { if (resp.is_ok() == false) { std::cout << "获取到一个错误的事件通知" << "-" << resp.error_message() << std::endl; return; } for(const auto& ev : resp.events()) { if(ev.event_type() == etcd::Event::EventType::PUT) { std::cout << "新增服务" << ev.kv().key() << "-" << ev.kv().as_string() << std::endl; if(_put_cb) _put_cb(ev.kv().key(), ev.kv().as_string()); } else if(ev.event_type() == etcd::Event::EventType::DELETE_) { std::cout << "删除服务" << ev.prev_kv().key() << "-" << ev.prev_kv().as_string() << std::endl; if(_del_cb) _del_cb(ev.prev_kv().key(), ev.prev_kv().as_string()); } } } private: NotifyCallback _put_cb; // 注册回调 NotifyCallback _del_cb; // 发现回调 std::string _registery_host; // 主机名 std::string _base_dir; // 监听目录 std::shared_ptr<etcd::Client> _get_client; // 监听客户端 std::shared_ptr<etcd::Watcher> _watcher; // 监听对象 };
http://www.jsqmd.com/news/1255789/

相关文章:

  • 重磅快讯!2026 济南黄金回收紧跟大盘,无任何套路扣费 - 资讯洞察员
  • Python计算机毕设之 基于 Python 的在线签到考勤管理系统员工考勤记录与薪资关联统计系统(完整前后端代码+说明文档+LW,调试定制等)
  • GTA5线上工具终极指南:免费开源辅助快速提升游戏体验
  • 如何选择正规靠谱、有口碑的装修公司?西安本地家装公司哪个好深度解析 - 子柔传媒
  • 041、YOLOv8改进实战:MobileNetv3轻量级骨干替换Backbone与代码实现
  • 如何用Driver Store Explorer一键清理Windows驱动垃圾,释放宝贵磁盘空间
  • 强力清理Windows驱动垃圾:Driver Store Explorer完全使用指南
  • XHS-Downloader小红书内容采集工具:高效批量下载小红书图文视频的终极指南
  • 聚焦Th1/Th17炎症分析,云克隆7因子Luminex多因子IL-1β、IL-2、IL-6、IL-10、IL-17、IL-22、TNFα检测方案填补感染免疫高通量分析空白
  • 深圳香薰机方案 诚信服务靠谱品牌评测 - 信息热点
  • bfs——带地板类题
  • 可观测性数据存储成本优化:采样、聚合与冷热分层
  • 百度网盘下载速度突然很慢怎么回事?2026还有解除限制的方法吗
  • 【化工仪表底层拆解】从 FMCW 雷达回波 FFT 算法到本安防爆,揭秘“化工防爆液位计原厂推荐”的 RD 实力审查红线
  • MAA明日方舟助手终极指南:从零开始掌握自动公招与基建管理
  • 2026Java后端面试题大全(附答案详解),最全面整理,金九银十冲刺专用
  • OneMore:解锁OneNote隐藏潜能的160+个实用功能
  • 基于SpringBoot3+Vue3的家政服务系统(源码)
  • 【AI API设计黄金法则】:20年架构师亲授7条避坑指南,90%团队正在踩的致命错误
  • 天津商业空间设计怎么避坑?从设计理念、施工工艺到环保标准的完整风险防控指南 - 中国品牌企业观察网
  • 2026 广州高端钻石闲置变现迈入专业鉴定时代,全城门店重构回收市场 - 商业每日快报
  • AI 音乐协作平台:多用户实时编辑与版本管理的架构设计
  • 如何3步免费获取Steam创意工坊动态壁纸:终极下载工具指南
  • 装闭 RenoPit 源码解析(05):FastAPI与Celery如何执行AI装修分析
  • C4996警告终极解决方案:从安全函数到跨平台实践
  • TDA3处理器PCB设计实战:电源与信号完整性及LPDDR2接口优化
  • GetQzonehistory终极指南:5分钟免费备份你的QQ空间所有历史记录
  • 在windows10里的apache2.4加php7.2的环境下上安装Laravel5.8框架
  • 2026年兴化黄金回收实测:紫金城黄金回收深度体验与里下河水乡变现避坑全指南(预约专线:18051266258) - 钦扬网络
  • 糖脂代谢紊乱的病理特征、临床风险与研究策略