项目组件框架介绍[etcd]

news2024/12/13 21:23:06

文章目录

  • 前言
  • etcd安装
    • Ubuntu 上通过包管理器安装
    • 通过源码安装
    • 配置
  • 客户端开发包
    • 开发包的安装
    • 接口介绍
      • 添加一个键值对
      • 获取一个键值对
      • 租约保活机制
      • 监听
  • 封装服务注册与发现
    • 服务注册
    • 服务发现


前言

    Etcd 是一个 golang 编写的分布式、高可用的一致性键值存储系统,用于配置共享和服务发现等

etcd安装

Ubuntu 上通过包管理器安装

# 直接安装
sudo apt-get install etcd
# 启动
sudo systemctl start etcd
# 设置开机自启
sudo systemctl enable etcd

验证安装

$ etcd --version
etcd Version: 3.2.26
Git SHA: Not provided (use ./build instead of go build)
Go Version: go1.13.8
Go OS/Arch: linux/amd64

可见已经安装成功

通过源码安装

    etcd是使用Go语言编写的, 根据官网描述的教程, 需要Go1.2+的版本

# 克隆仓库
$ git clone -b v3.5.16 https://github.com/etcd-io/etcd.git
$ cd etcd
# 运行构建脚本:
$ ./build.sh
# 二进制文件位于 directory/bin
# 设置环境变量, 假如你的二进制文件位于/bin
$ export PATH="$PATH:`pwd`/bin"
# 验证安装
$ etcd --version

配置

    默认 etcd 的集群节点通信端口为 2380, 客户端访问端口为 2379, 如果需要更改可以修改/etc/default/etcd文件
修改配置

客户端开发包

开发包的安装

    官方只维护了 go 语言版本的 client 库, 因此需要使用 C/C++ 非官方的 client 开发库, etcd-cpp-apiv3是一个不错的选择, etcd-cpp-apiv3 是一个 etcd 的 C++版本客户端 API。它依赖于 mipsasm, boost, protobuf, gRPC, cpprestsdk 等库
所有首先需要安装依赖

# 建议先看看是否已经用其他方式安装这些, 否则出现版本冲突问题很难受
# 比如up就在项目中途把protobuf版本更新了, 就导致所有依赖protobuf编译安装的第三方库都用不了
# 比如这个, brpc等等都用不了,最后重新编译安装了它们才解决, 还出现了莫名其妙的库找不到的问题
sudo apt-get install libboost-all-dev libssl-dev
sudo apt-get install libprotobuf-dev protobuf-compiler-grpc
sudo apt-get install libgrpc-dev libgrpc++-dev 
sudo apt-get install libcpprest-dev

使用源码安装即可

git clone https://github.com/etcd-cpp-apiv3/etcd-cpp-apiv3.git
cd etcd-cpp-apiv3
mkdir build && cd build
cmake .. -DCMAKE_INSTALL_PREFIX=/usr
make -j$(nproc) && sudo make install

接口介绍

    项目中主要使用etcd进行服务注册和发现, 我们重点介绍这些接口, 其他介绍可参考官方介绍

添加一个键值对

#include<etcd/Client.hpp>

//构造一个etcd::Client 对象, 用etcd服务端的url构造
etcd::Client etcd("http://127.0.0.1:2379");
//使用put方法添加一个键值对, etcd.put() 方法是非阻塞的,返回一个异步任务pplx::task
pplx::task<etcd::Response> response_task = etcd.put("/test/1", "111");
// 等待异步任务完成并获取结果
try 
{
    etcd::Response response = response_task.get();
    if (response.is_ok()) 
    {
        std::cout << "Put: " << response.key() << " : " << response.value() << std::endl;
    } 
    else 
    {
        std::cerr << "Error: " << response.error_message() << std::endl;
    }
} 
catch (const std::exception &e) 
{
    std::cerr << e.what() << std::endl;
}

获取一个键值对

etcd::Client etcd("http://127.0.0.1:2379");
//使用get方法获取一个键值对, 这个也是非阻塞的, 返回一个异步任务
pplx::task<etcd::Response> response_task = etcd.get("/test/1");
try
{
    etcd::Response response = response_task.get();
    if (response.is_ok())
    {
        std::cout << "获取成功" << response.value().as_string();
    }
    else
    {
        std::cout << "获取失败: " << response.error_message();
    }
}
catch (std::exception const & ex)
{
    std::cerr << ex.what() <<std::endl;
}

租约保活机制

    在项目中我们需要监控一个服务的在线情况, 如果异常退出, 有时候就不能很好的检测到, etcd提供了租约保活机制, 服务如果没有续约, 就可以认为该服务已下线

    etcd::Client etcd("http://127.0.0.1:2379");
    //获取一个三秒的租约保活对象 
    std::shared_ptr<etcd::KeepAlive> keep(etcd.leasekeepalive(3).get());
    //获取租约ID
    int64 lease_id=keep->Lease();
    etcd.put("/test/2", "222",lease_id);

监听

    项目中需要对服务的上线与下线进行监控, 再结合其他组件, 比如bprc, 就可通过这个服务获取相对应的通信对象

    //构造一个监控对象, 第二个参数可以是一个目录, 比如/test, 那么就会监控/test下比如/test/1 /test/2, 第三个是一个回调函数, 当被监控的对象发送改变时就会触发回调
    etcd::Watcher watcher("http://127.0.0.1:2379", "/test", CallBack);
    //etcd::Response是一个容器, 可以通过遍历的方式获取, 比如
    void CallBack(const etcd::Response& re)
    {
        if(!re.is_ok())
        {
            LOG_ROOT_ERROR<<re.error_message();
            return;
        }
        for(const auto& ev: re.events())
        {
            //通过etcd::EVent::EventType 可得知具体情况
            if(ev.event_type()==etcd::Event::EventType::PUT)
            {
                LOG_ROOT_INFO<<"新增服务: "<<ev.kv().key()<<" : "<<ev.kv().as_string();
            }
            if(ev.event_type()==etcd::Event::EventType::DELETE_)
            {
                LOG_ROOT_INFO<<"服务下线: "<<ev.prev_kv().key()<<" : "<<ev.prev_kv().as_string();
            }
        }
    }

封装服务注册与发现

    有了上面了了解, 我们就能完成一个简单的服务注册与发现模块

服务注册

#include<etcd/Client.hpp>
#include<etcd/KeepAlive.hpp>
#include<etcd/Response.hpp>
#include<etcd/Value.hpp>
#include<etcd/Watcher.hpp>
#include"log.hpp"
namespace MindbniM
{
    class Registry
    {
    public:
        using ptr=std::shared_ptr<Registry>;
        //这里默认使用3秒保活了, 也可以手动传入
        Registry(const std::string& host):_client(std::make_unique<etcd::Client>(host)),_ka(_client->leasekeepalive(3).get()),_lease_id(_ka->Lease())
        {}
        bool registry(const std::string& key,const std::string& value)
        {
            etcd::Response re=_client->put(key,value,_lease_id).get();
            if(!re.is_ok())
            {
                LOG_ROOT_ERROR<<"服务注册失败"<<":"<<re.error_message();
                return false;
            }
            LOG_ROOT_DEBUG<<"服务注册:"<<key<<" : "<<value;
            return true;
        }
    private:
        std::unique_ptr<etcd::Client> _client;
        std::shared_ptr<etcd::KeepAlive> _ka;
        int64_t _lease_id;
    };
}

服务发现

    为了和其他组件相互结合, 我们设置两个回调, 分别对应服务上线与下线的操作

#include<etcd/Client.hpp>
#include<etcd/Response.hpp>
#include<etcd/Value.hpp>
#include<etcd/Watcher.hpp>
#include"log.hpp"
namespace MindbniM
{
    class Discovery
    {
    public:
        using ptr=std::shared_ptr<Discovery>;
        //对应key和value
        using CallBack=std::function<void(const std::string&,const std::string&)>;
        Discovery(const std::string& host,const CallBack& put=nullptr,const CallBack& del=nullptr):_client(std::make_unique<etcd::Client>(host)),_put(put),_del(del)
        {}
        bool discover(const std::string& dir)
        {
            etcd::Response re=_client->ls(dir).get();
            if(!re.is_ok())
            {
                LOG_ROOT_ERROR<<"服务发现错误"<<re.error_message();
                return false;
            }
            int n=re.keys().size();
            if(_put!=nullptr)
            {
                for(int i=0;i<n;i++)
                {
                    _put(re.key(i),re.value(i).as_string());
                }
            }
            //开始监听
            _watch=std::make_unique<etcd::Watcher>(*_client,dir,std::bind(&Discovery::_CallBack,this,std::placeholders::_1),true);
            return true;
        }
        bool wait()
        {
            return _watch->Wait();
        }
    private:
        void _CallBack(const etcd::Response& re)
        {
            if(!re.is_ok())
            {
                LOG_ROOT_ERROR<<re.error_message();
                return;
            }
            for(const auto& ev: re.events())
            {
                if(ev.event_type()==etcd::Event::EventType::PUT)
                {
                    if(_put) _put(ev.kv().key(),ev.kv().as_string());
                    LOG_ROOT_INFO<<"新增服务: "<<ev.kv().key()<<" : "<<ev.kv().as_string();
                }
                if(ev.event_type()==etcd::Event::EventType::DELETE_)
                {
                    if(_del) _del(ev.prev_kv().key(),ev.prev_ky().as_string());
                    LOG_ROOT_INFO<<"服务下线: "<<ev.prev_kv().key()<<" : "<<ev.prev_kv().as_string();
                }
            }
        }
        CallBack _put;
        CallBack _del;
        std::unique_ptr<etcd::Client> _client;
        std::unique_ptr<etcd::Watcher> _watch;
    };
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2258958.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

网页爬虫技术全解析:从基础到实战

引言 在当今信息爆炸的时代&#xff0c;互联网上的数据量每天都在以惊人的速度增长。网页爬虫&#xff08;Web Scraping&#xff09;&#xff0c;作为数据采集的重要手段之一&#xff0c;已经成为数据科学家、研究人员和开发者不可或缺的工具。本文将全面解析网页爬虫技术&…

Jmeter如何对UDP协议进行测试?

Jmeter如何对UDP协议进行测试&#xff1f; 1 jmeter-plugins安装2 UDP-Protocol Support安装3 UDP协议测试 1 jmeter-plugins安装 jmeter-plugins是Jmeter的插件管理器&#xff1b;可以组织和管理Jmeter的所有插件&#xff1b;直接进入到如下页面&#xff0c;选择如图的选项进…

计算机网络之网络层超详细讲解

个人主页&#xff1a;C忠实粉丝 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 C忠实粉丝 原创 计算机网络之网络层超详细讲解 收录于专栏【计算机网络】 本专栏旨在分享学习计算机网络的一点学习笔记&#xff0c;欢迎大家在评论区交流讨论&#x1f48c; …

微信小程序:实现节点进度条的效果;正在完成的节点有动态循环效果;横向,纵向排列

参考说明 微信小程序实现流程进度功能 - 知乎 上面的为一个节点进度条的例子&#xff0c;但并不完整&#xff0c;根据上述代码&#xff0c;进行修改完善&#xff0c;实现其效果 横向效果 代码 wxml <view classorder_process><view classprocess_wrap wx:for&quo…

如何不重启修改K8S containerd容器的内存限制(Cgroup方法)

1. 使用crictl 查看容器ID crictl ps2. 查看Cgroup位置 crictl inspect 容器ID3. 到容器Cgroup的目录下 使用上个命令就能找到CgroupPath 4 . 到cgroup目录下 正确目录是 : /sys/fs/cgroup/memory/kubepods.slice/kubepods-burstable.slice/kubepods-burstable-podf68e18…

海康威视摄像头RTSP使用nginx推流到服务器直播教程

思路&#xff1a; 之前2020年在本科的时候&#xff0c;由于项目的需求需要将海康威视的摄像头使用推流服务器到网页进行直播。这里将自己半个月琢磨出来的步骤给大家发一些。切勿转载&#xff01;&#xff01;&#xff01;&#xff01; 使用网络摄像头中的rtsp协议---------通…

智简模型,边缘智能:AI 轻量化与边缘计算的最佳实践

文章目录 摘要引言模型轻量化与优化方法模型量化模型剪枝知识蒸馏合理使用边缘计算硬件 轻量化图像分类实战1. 模型量化2. 知识蒸馏3. 学生模型的创建与训练 QA环节总结参考资料 摘要 边缘计算与 AI 模型的结合&#xff0c;能够在资源受限的环境中提供实时智能服务。通过模型轻…

flink sink kafka的事务提交现象猜想

现象 查看flink源码时 sink kafka有事务提交机制&#xff0c;查看源码发现是使用两阶段提交策略&#xff0c;而事务提交是checkpoint完成后才执行&#xff0c;那么如果checkpoint设置间隔时间比较长时&#xff0c;事务未提交之前&#xff0c;后端应该消费不到数据&#xff0c…

推送(push)项目到gitlab

文章目录 1、git init1.1、在当前目录中显示隐藏文件&#xff1a;1.2、查看已有的远程仓库1.3、确保你的本地机器已经生成了 SSH 密钥&#xff1a;1.4、将生成的公钥文件&#xff08;通常位于 ~/.ssh/id_rsa.pub&#xff09;复制到 GitLab 的 SSH 设置中&#xff1a;1.5、测试 …

7.Vue------$refs与$el详解 ------vue知识积累

$refs 与 $el是什么&#xff1f; 作用是什么? ref&#xff0c;$refs&#xff0c;$el &#xff0c;三者之间的关系是什么&#xff1f; ref (给元素或者子组件注册引用信息) 就像你要给元素设置样式&#xff0c;就需要先给元素设定一个 class 一样&#xff0c;同理&#xff0c;…

通俗易懂的 Nginx 反向代理 配置

通俗易懂的 Nginx 反向代理 配置 首先 root 与 alias 的区别 root 是直接拼接 root location location /i/ {root /data/w3; }当请求 /i/top.gif &#xff0c;/data/w3/i/top.gif 会被返回。 alias 是用 alias 替换 location location /i/ {alias /data/w3/images/; }当请…

git 导出某段时间修改的文件 windows

第一步&#xff1a;列出两次commitID之间的文件变动 git diff oldid newid --name-only// 例如 git diff 4a886c57a8b5611a2abcfcd120461c2e92f7029a HEAD --name-only 4a886c57a8b5611a2abcfcd120461c2e92f7029a 代表之前 HEAD 代表最新或者换成某次commitID 例如&#xf…

若依集成Uflo2工作流引擎

文章目录 1. 创建子模块并添加依赖1.1 新建子模块 ruoyi-uflo1.2 引入 Uflo2 相关依赖 2. 配置相关 config2.1 配置 ServletConfig2.2 配置 UfloConfig2.3 配置 TestEnvironmentProvider 3. 引入Uflo配置文件4. 启动并访问 Uflo2 是由 BSTEK 自主研发的一款基于 Java 的轻量级工…

BERT:用于语言理解的深度双向 Transformer 的预训练。

文章目录 0. 摘要1. 介绍2. 相关工作2.1 无监督的基于特征的方法2.3 无监督微调方法2.3 从受监督数据中迁移学习 3. BERT3.1 预训练 BERT3.2 微调 BERT 4. 实验4.1 GLUE4.2 SQuAD v1.14.3 SQuAD v2.04.4 SWAG 5. 消融研究5.1 预训练任务的影响5.2 模型大小的影响5.3 使用 BERT …

如何快速批量把 PDF 转为 JPG 或其它常见图像格式?

在某些特定场景下&#xff0c;将 PDF 转换为 JPG 图片格式却具有不可忽视的优势。例如&#xff0c;当我们需要在不支持 PDF 查看的设备或软件中展示文档内容时&#xff0c;JPG 图片能够轻松被识别和打开&#xff1b;此外&#xff0c;对于一些网络分享或社交媒体发布的需求&…

如何在项目中使用人大金仓替换mysql

文章目录 数据库连接配置调整驱动和连接字符串修改&#xff1a;用户名和密码&#xff1a; SQL 语法兼容性检查数据类型差异处理&#xff1a;函数差异&#xff1a;SQL语句客户端 SQL 交互工具 数据迁移数据库、用户移植数据迁移工具使用&#xff1a;迁移过程中的问题及解决方案 …

【DVWA】XSS(Stored)

倘若人生一马平川&#xff0c;活着还有什么意思呢。 1.XSS(Stored)(Low) 相关代码分析 trim(string,charlist) 函数移除字符串两侧的空白字符或其他预定义字符&#xff0c;预定义字符包括、\t、\n、\x0B、\r以及空格&#xff0c;可选参数charlist支持添加额外需要删除的字符…

数据分析python小工具录入产品信息到Excel

在没有后台管理系统的时候&#xff0c;有时候为了方便起见&#xff0c;想提供一个输入框让运营人员直接输入&#xff0c;然后数据就会以数据库的形式存进数据库 效果图&#xff1a; 输入用户名 输入数据 输入信息后点击添加到表格&#xff0c;检查后方便批量保存到excel …

HTML和JavaScript实现商品购物系统

下面是一个更全面的商品购物系统示例&#xff0c;包含新增商品、商品的增加删除以及结算找零的功能。这个系统使用HTML和JavaScript实现。 1.功能说明&#xff1a; 这个应用程序使用纯HTML和JavaScript实现。 包含一个商品列表和一个购物车区域。商品列表中有几个示例商品&a…

C# 探险之旅:第三节 - 有趣的变量命名

欢迎再次回到我们的C#魔法森林。今天&#xff0c;我们要一起探索一个既有趣又实用的技能——变量命名。想象一下&#xff0c;你正在为你的小精灵们&#xff08;变量&#xff09;起名字&#xff0c;好的名字不仅能让它们更容易被识别&#xff0c;还能让你的魔法书&#xff08;代…