即时通讯项目--(3)etcd二次封装

二次封装:封装etcd-client-api,实现两种类型的客户端

1.服务注册客户端:向服务器新增服务信息数据,并进行保活

2.服务发现客户端:从服务器查找服务信息数据,并进行改变事件监控

封装的时候,我们尽量减少模块之间的耦合度,本质上etcd是一个键值存储系统,并不是专门用于作为注册中心进行服务注册和发现的。

封装思想:

1.封装服务注册客户端类

提供一个接口:向服务器新增数据并进行保活

参数:注册中心地址(etcd服务器地址),

新增的服务信息(服务名-主机地址键值对)

2.封装服务发现客户端类

提供两个设置回调函数的接口:服务上线事件接口(数据新增),服务下线事件接口(数据删除)

提供一个设置根目录的接口:用于获取指定目录下的数据以及监控目录下数据的改变

复制代码
#pragma once
#include <etcd/Client.hpp>
#include <etcd/KeepAlive.hpp>
#include <etcd/Response.hpp>
#include <etcd/Watcher.hpp>
#include <etcd/Value.hpp>
#include <functional>
#include "logger.hpp"

namespace im{

//服务注册客户端类
class Registry{
public:
    using ptr = std::shared_ptr<Registry>;

    Registry(const std::string& host): 
        _client(std::make_shared<etcd::Client>(host)),  // 1. 创建etcd客户端
        _keep_alive(_client->leasekeepalive(3).get()),  // 2. 创建3秒租约并启动保活
        _lease_id(_keep_alive->Lease()) {}              // 3. 获取租约ID

    ~Registry() { _keep_alive->Cancel(); }  // 停止租约保活

    bool registry(const std::string& key,const std::string& val){
        // 向etcd写入键值对,绑定租约ID(成为临时节点),同步等待结果
        auto resp = _client->put(key,val,_lease_id).get();
        if(resp.is_ok() == false){  // 判断etcd操作是否成功
            LOG_ERROR("注册数据失败:{}",resp.error_message());
            return false;
        }
        return true;
    }

private:
    std::shared_ptr<etcd::Client> _client;  // etcd客户端智能指针
    std::shared_ptr<etcd::KeepAlive> _keep_alive;   // 租约保活智能指针,后台自动发心跳
    uint64_t _lease_id; // etcd租约ID,用于绑定键值对为「临时节点」

};


//服务发现客户端类
class Discovery{
public:
    using ptr = std::shared_ptr<Discovery>;
    // 服务变化的回调函数类型:参数为(服务key,服务val)
    using NotifyCallback = std::function<void(std::string,std::string)>;

    Discovery(const std::string& host,
        const std::string& basedir,
        const NotifyCallback& put_cb,
        const NotifyCallback& del_cb):
        _client(std::make_shared<etcd::Client>(host)),
        _put_cb(put_cb),_del_cb(del_cb){
            // 全量拉取:获取指定目录下的所有已有服务
            auto resp = _client->ls(basedir).get();
            if(resp.is_ok() == false){
                LOG_ERROR("获取服务信息数据失败:{}",resp.error_message());
            }
            int sz = resp.keys().size();
            for(int i=0;i<sz;++i){
                if(_put_cb){    // 回调非空则执行,初始化本地服务列表
                    _put_cb(resp.key(i),resp.value(i).as_string());
                }
            }
            // 增量监听:启动Watch,感知目录下的节点变化
            _watcher = std::make_shared<etcd::Watcher>(*_client.get(),basedir,
                        std::bind(&Discovery::callback,this,std::placeholders::_1),true);
        }
        
        ~Discovery(){ _watcher->Cancel(); } // 停止后台监听线程

private:
    void callback(const etcd::Response& resp){
        if(resp.is_ok() == false){
            LOG_ERROR("收到一个错误的事件通知:{}",resp.error_message());
            return;
        }
        for (auto const& ev : resp.events()) {
            if (ev.event_type() == etcd::Event::EventType::PUT) {
                if (_put_cb) _put_cb(ev.kv().key(), ev.kv().as_string());
                LOG_DEBUG("新增服务:{}-{}", ev.kv().key(), ev.kv().as_string());
            }else if (ev.event_type() == etcd::Event::EventType::DELETE_) {
                if (_del_cb) _del_cb(ev.prev_kv().key(), ev.prev_kv().as_string());
                LOG_DEBUG("下线服务:{}-{}", ev.prev_kv().key(), ev.prev_kv().as_string());
            }
        }
    }

private:
    NotifyCallback _put_cb; // 服务新增/更新的回调
    NotifyCallback _del_cb; // 服务下线的回调
    std::shared_ptr<etcd::Client> _client;  // etcd客户端
    std::shared_ptr<etcd::Watcher> _watcher;// 监听对象,后台运行


};



}
相关推荐
ghxufMuht2 天前
从台达三相PFC到艾默生15kW充电桩模块:一场电力电子的探索之旅
etcd
羑悻的小杀马特13 天前
etcd实战指南:从安装集群到C++封装,解锁分布式服务治理的“钥匙”
c++·分布式·etcd·集群
sim202017 天前
把etcd分区挂到SSD盘
linux·etcd
方璧18 天前
ETCD注册中心
数据库·学习·etcd
2501_9418072620 天前
从单机限流到分布式动态流控体系落地的互联网系统工程实践随笔与多语言语法思考
eureka·etcd
咩咩大主教23 天前
在Linux bashrc配置全局代理导致etcd连接失败
linux·vscode·ubuntu·ssh·etcd·远程连接
2401_832298101 个月前
云服务器与物联网:万物互联的算力网络
etcd
jiajia_lisa1 个月前
防燃油车占位方案助力充电桩行业提高用户体验
etcd
Msshu1231 个月前
多协议PD快充诱骗取电芯片XSP26支持快充取电和识别电脑传输数据
zookeeper·hbase·etcd·memcached·memcache