[C++][第三方库][etcd]详细讲解

目录

  • 1.介绍
  • 2.安装
    • 1.安装etcd
    • 2.节点配置
    • 3.运行验证
  • 3.搭建服务注册发现中心
    • 0.前言
    • 1.etcd-cpp-apiv3
    • 2.客户端
      • 1.类与接口介绍
      • 2.使用示例


1.介绍

  • Etcd是一个golang编写的分布式、高可用的一致性键值存储系统,用于配置共享和服务发现
  • 它使用Raft一致性算法来保持集群数据的一致性,且客户端通过长连接watch功能,能够及时收到数据变化通知,相较于Zookeeper框架更加轻量化

2.安装

1.安装etcd

  • 安装sudo apt install etcd
  • 启动服务sudo systemctl start etcd
  • 设置开机自启sudo systemctl enable etcd

2.节点配置

  • 如果是单节点集群其实就可以不用进行配置,默认etcd的集群节点通信端口为2380, 客户端访问端口为2379
  • 若需要修改,则可以配置:/etc/default/etcd
#节点名称,默认为 "default" 
ETCD_NAME="etcd1" 
#数据目录,默认为 "${name}.etcd" 
ETCD_DATA_DIR="/var/lib/etcd/default.etcd" 
#用于客户端连接的 URL。 
ETCD_LISTEN_CLIENT_URLS="http://192.168.65.132:2379,http://127.0.0.1:2379" 
#用于客户端访问的公开,也就是提供服务的 URL 
ETCD_ADVERTISE_CLIENT_URLS="http://192.168.65.132:2379,http://127.0.0.1:2379" 
#用于集群节点间通信的 URL。 
ETCD_LISTEN_PEER_URLS="http://192.168.65.132:2380" 
ETCD_INITIAL_ADVERTISE_PEER_URLS="http://192.168.65.132:2380" 
#心跳间隔时间-毫秒 
ETCD_HEARTBEAT_INTERVAL=100 
#选举超时时间-毫秒 
ETCD_ELECTION_TIMEOUT=1000 
 
#以下为集群配置,若无集群则需要注销 
#初始集群状态和配置--集群中所有节点 
#ETCD_INITIAL_CLUSTER="etcd1=http://192.168.65.132:2380,etcd2=http
 ://192.168.65.132:2381,etcd3=http://192.168.65.132:2382" 
#初始集群令牌-集群的ID 
#ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster" 
#ETCD_INITIAL_CLUSTER_STATE="new" 
 
 
#以下为安全配置,如果要求SSL连接etcd的话,把下面的配置启用,并修改文件
路径 
#ETCD_CERT_FILE="/etc/ssl/client.pem" 
#ETCD_KEY_FILE="/etc/ssl/client-key.pem" 
#ETCD_CLIENT_CERT_AUTH="true" 
#ETCD_TRUSTED_CA_FILE="/etc/ssl/ca.pem" 
#ETCD_AUTO_TLS="true" 
#ETCD_PEER_CERT_FILE="/etc/ssl/member.pem" 
#ETCD_PEER_KEY_FILE="/etc/ssl/member-key.pem" 
#ETCD_PEER_CLIENT_CERT_AUTH="false" 
#ETCD_PEER_TRUSTED_CA_FILE="/etc/ssl/ca.pem" 
#ETCD_PEER_AUTO_TLS="true" 

3.运行验证

  • 命令行输入etcdctl put key "SnowK"
  • 如果以下出现报错,在/etc/profile默认声明环境变量ETCDCTL_API=3以确定etcd版本
    $ etcdctl put key "SnowK"
    No help topic for 'put'
    
  • 完成后,加载配置文件,并重新执行测试命令
    $ source /etc/profile 
    $ etcdctl put key "SnowK"
    OK 
    $ etcdctl get key 
    key 
    SnowK
    $ etcdctl del mykey 
    

3.搭建服务注册发现中心

0.前言

  • 使用etcd作为服务注册发现中心,需要定义服务的注册和发现逻辑
  • 通常涉及到以下几个操作
    • 服务注册:服务启动时,向etcd注册自己的地址和端口
    • 服务发现:客户端通过etcd获取服务的地址和端口,用于远程调用
    • 健康检查:服务定期向Etcd发送心跳,以维持其注册信息的有效性
  • 官方只维护了golangclient库,因此需要找到C/C++ 非官方的client 开发库

1.etcd-cpp-apiv3

  • etcd-cpp-apiv3是一个etcd的C++版本客户端API,它依赖于mipsasm, boost, protobuf, gRPC, cpprestsdk等库
  • Github
  • 依赖安装
    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 
    
  • API框架安装
    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
    

2.客户端

1.类与接口介绍

  • Client对象:客户端操作句柄对象
    • 提供了新增,获取数据的接口
    • 提供了获取保活对象的接口,以及租约的接口
  • KeepAlive保活对象:一旦被析构,则无法保活,则租约数据失效被删除
    • 本身提供一个获取租约ID的接口
    • 作用:针对一个可以不断进行续租 --> 一直维持租约数据的有效性
  • Response对象:针对请求进行的响应
  • Value对象:存放键值对数据的对象
  • Watcher对象:进行数据变化通知的类
    //pplx::task 并行库异步结果对象 
    //阻塞方式   get(): 阻塞直到任务执行完成,并获取任务结果 
    //非阻塞方式 wait(): 等待任务到达终止状态,然后返回任务状态 
     
    namespace etcd 
    { 
    	class Value 
    	{ 
    	    bool is_dir()//判断是否是一个目录 
    	    std::string const& key() //键值对的key值 
    	    std::string const& as_string()//键值对的val值 
    	     
    	    int64_t lease() //用于创建租约的响应中,返回租约ID 
    	} 
    	
    	//etcd会监控所管理的数据的变化,一旦数据产生变化会通知客户端 
    	//在通知客户端的时候,会返回改变前的数据和改变后的数据 
    	class Event 
    	{ 
    	    enum class EventType 
    	    { 
    	        PUT, //键值对新增或数据发生改变 
    	        DELETE_,//键值对被删除 
    	        INVALID, 
    	    }; 
    	    enum EventType event_type()  
    	    const Value& kv() 
    	    const Value& prev_kv() 
    	} 
    	
    	class Response 
    	{ 
    	    bool is_ok() 
    	    std::string const& error_message() 
    	    Value const& value()//当前的数值 或者 一个请求的处理结果 
    	    Value const& prev_value()//之前的数值 
    	    Value const& value(int index)// 
    	    std::vector<Event> const& events();//触发的事件 
    	} 
    	 
    	class KeepAlive 
    	{ 
    	    KeepAlive(Client const& client, int ttl, int64_t lease_id = 0); 
    	    //返回租约ID 
    	    int64_t Lease(); 
    	    //停止保活动作 
    	    void Cancel(); 
    	} 
    	 
    	class Client 
    	{ 
    	    // etcd_url: "http://127.0.0.1:2379" 
    	    Client(std::string const& etcd_url, 
    	        std::string const& load_balancer = "round_robin"); 
    	        
    	    //新增一个键值对 
    	    pplx::task<Response> put(std::string const& key,  
    						         std::string const& value); 
    	        
    	    //新增带有租约的键值对 (一定时间后,如果没有续租,数据自动删除) 
    	    pplx::task<Response> put(std::string const& key,  
    						         std::string const& value, 
    						         const int64_t leaseId); 
    	        
    	    //获取一个指定key目录下的数据列表 
    	    pplx::task<Response> ls(std::string const& key); 
    	    
    	    //创建并获取一个存活ttl时间的租约 
    	    pplx::task<Response> leasegrant(int ttl); 
    	    
    	    //获取一个租约保活对象,其参数ttl表示租约有效时间 
    	    pplx::task<std::shared_ptr<KeepAlive>> leasekeepalive(int ttl); 
    	    
    	    //撤销一个指定的租约 
    	    pplx::task<Response> leaserevoke(int64_t lease_id); 
    	    
    	    //数据锁 
    	    pplx::task<Response> lock(std::string const& key); 
    	} 
    	 
    	class Watcher 
    	{ 
    	    Watcher(Client const& client,  
    	        std::string const& key, //要监控的键值对key 
    	        std::function<void(Response)> callback, //发生改变后的回调 
    	        bool recursive = false); //是否递归监控目录下的所有数据改变 
    	        
    	    Watcher(std::string const& address,  
    	        std::string const& key, 
    	        std::function<void(Response)> callback,  
    	        bool recursive = false); 
    	        
    	    //阻塞等待,直到监控任务被停止 
    	    bool Wait(); 
    	    bool Cancel(); 
    	}
    }
    

2.使用示例

  • makefile
    all: get put
    
    get: get.cc
    	g++ -o $@ $^ -std=c++17 -letcd-cpp-api -lcpprest
    
    put: put.cc
    	g++ -o $@ $^ -std=c++17 -letcd-cpp-api -lcpprest
    
    .PHONY:clean
    clean:
    	rm get put
    
  • get.cc
    #include <iostream>
    #include <thread>
    #include <etcd/Client.hpp>
    #include <etcd/KeepAlive.hpp>
    #include <etcd/Response.hpp>
    #include <etcd/Watcher.hpp>
    #include <etcd/Value.hpp>
    
    void CallBack(const etcd::Response& resp)
    {
        if(resp.is_ok() == false)
        {
            std::cout << "收到一个错误的事件通知:" << resp.error_message() 
    			      << std::endl;
            return;
        }
        else
        {
            for(const auto& ev : resp.events())
            {
                if(ev.event_type() == etcd::Event::EventType::PUT)
                {
                    std::cout << "服务信息发生了改变:" << std::endl;
                    std::cout << "当前的值:" << ev.kv().key() << "-" 
                              << ev.kv().as_string() << std::endl;
                    std::cout << "原来的值:" << ev.prev_kv().key() << "-" 
                              << ev.prev_kv().as_string() << std::endl;
                }
                else if(ev.event_type() == etcd::Event::EventType::DELETE_)
                {
                    std::cout << "服务信息下线被删除:\n";
                    std::cout << "当前的值:" << ev.kv().key() << "-" 
                              << ev.kv().as_string() << std::endl;
                    std::cout << "原来的值:" << ev.prev_kv().key() << "-" 
                              << ev.prev_kv().as_string() << std::endl;
                }
            }
        }
    }
    
    int main(int argc, char* argv[])
    {
        std::string etcd_host = "http://127.0.0.1:2379";
    
        // 实例化客户端对象
        etcd::Client client(etcd_host);
    
        // 获取指定的键值对信息
        // ls() -> 获取一个指定key目录下的数据列表
        auto resp = client.ls("/service").get();
        if(resp.is_ok() == false)
        {
            std::cout << "获取键值对数据失败: " << resp.error_message() 
                      << std::endl;
            return -1;
        }
    
        int sz = resp.keys().size();
        for (int i = 0; i < sz; i++)
        {
            std::cout << resp.value(i).as_string() << "可以提供" << resp.key(i) 
                      << "服务" << std::endl;
        }
    
        // 实例化一个键值对事件监控对象
        // true: 是否递归监控该目录
        auto watcher = etcd::Watcher(client, "/service", CallBack, true);
        watcher.Wait();
        
        return 0;
    }
    
  • put.cc
    #include <iostream>
    #include <thread>
    #include <etcd/Client.hpp>
    #include <etcd/KeepAlive.hpp>
    #include <etcd/Response.hpp>
    
    int main(int argc, char* argv[])
    {
        std::string etcd_host = "http://127.0.0.1:2379";
    
        // 实例化客户端对象
        etcd::Client client(etcd_host);
    
        // 获取租约保活对象 --> 伴随着创建一个指定有效时长的租约
        auto keep_alive = client.leasekeepalive(3).get();
    
        // 获取租约ID
        auto lease_id = keep_alive->Lease();
    
        // 向etcd新增数据
        auto resp1 = client.put("/service/user", 
    						    "127.0.0.1:3366", lease_id).get();
        if(resp1.is_ok() == false)
        {
            std::cout << "新增数据失败: " << resp1.error_message() << std::endl;
            return -1;
        }
    
        auto resp2 = client.put("/service/friend", "127.0.0.1:6633").get();
        if (resp2.is_ok() == false)
        {
            std::cout << "新增数据失败: " << resp2.error_message() << std::endl;
            return -1;
        }
    
        std::this_thread::sleep_for(std::chrono::seconds(10));
    
        return 0;
    }
    
  • 运行结果
    127.0.0.1:6633可以提供/service/friend服务
    127.0.0.1:3366可以提供/service/user服务
    服务信息下线被删除:
    当前的值:/service/user-
    原来的值:/service/user-127.0.0.1:3366
    

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

硬件-开关电源-结构组成及元件作用

文章目录 一&#xff1a;开关电源组成1.1 开关电源是什么&#xff1f;1.2 开关电源六个组成部分 二&#xff1a;六个组成部分的作用2.1 EMC区域2.2 输入整流滤波区域2.3 控制区域2.4 变压器2.5 输出整流滤波区域2.6 反馈电路区域道友:勿以小恶弃人大美&#xff0c;勿以小怨忘人…

【C++】——list的介绍和模拟实现

P. S.&#xff1a;以下代码均在VS2019环境下测试&#xff0c;不代表所有编译器均可通过。 P. S.&#xff1a;测试代码均未展示头文件stdio.h的声明&#xff0c;使用时请自行添加。 博主主页&#xff1a;Yan. yan.                        …

ARM 架构、cpu

一、ARM的架构 ARM是一种基于精简指令集&#xff08;RISC&#xff09;的处理器架构. 1、ARM芯片特点 ARM芯片的主要特点有以下几点&#xff1a; 精简指令集&#xff1a;ARM芯片使用精简指令集&#xff0c;即每条指令只完成一项简单的操作&#xff0c;从而提高指令的执行效率…

EasyCVR视频汇聚平台:解锁视频监控核心功能,打造高效安全监管体系

随着科技的飞速发展&#xff0c;视频监控技术已成为现代社会安全、企业管理、智慧城市构建等领域不可或缺的一部分。EasyCVR视频汇聚平台作为一款高性能的视频综合管理平台&#xff0c;凭借其强大的视频处理、汇聚与融合能力&#xff0c;在构建智慧安防/视频监控系统中展现出了…

Qt Quick 3D 入门:QML 3D场景详解

随着 Qt 6 的发布&#xff0c;QtQuick3D 模块带来了新的 3D 渲染和交互能力&#xff0c;使得在 Qt 中创建 3D 场景变得更加简单和直观。本文将带您从一个简单的 QML 3D 应用开始&#xff0c;详细讲解各个相关领域的概念、代码实现以及功能特点。 什么是 Qt Quick 3D&#xff1…

关于 JVM 个人 NOTE

目录 1、JVM 的体系结构 2、双亲委派机制 3、堆内存调优 4、关于GC垃圾回收机制 4.1 GC中的复制算法 4.2 GC中的标记清除算法 1、JVM 的体系结构 "堆"中存在垃圾而"栈"中不存在垃圾的原因: 堆(Heap) 用途:堆主要用于存储对象实例和数组。在Java中…

Linux --入门学习笔记

文章目录 Linux概述基础篇Linux 的安装教程 ⇒ 太简单了&#xff0c;百度一搜一大堆。此处略……Linux 的目录结构常用的连接 linux 的开源软件vi 和 vim 编辑器Linux 的关机、开机、重启用户登录和注销用户管理添加用户 ⇒ ( useradd 用户名 ) &#xff08; useradd -d 制定目…

【Unity踩坑】Unity更新Google Play结算库

一、问题描述&#xff1a; 在Google Play上提交了app bundle后&#xff0c;提示如下错误。 我使用的是Unity 2022.01.20f1&#xff0c;看来用的Play结算库版本是4.0 查了一下文档&#xff0c;Google Play结算库的维护周期是两年。现在需要更新到至少6.0。 二、更新过程 1. 下…

Python | Leetcode Python题解之第454题四数相加II

题目&#xff1a; 题解&#xff1a; class Solution:def fourSumCount(self, A: List[int], B: List[int], C: List[int], D: List[int]) -> int:countAB collections.Counter(u v for u in A for v in B)ans 0for u in C:for v in D:if -u - v in countAB:ans countAB…

C++ | Leetcode C++题解之第454题四数相加II

题目&#xff1a; 题解&#xff1a; class Solution { public:int fourSumCount(vector<int>& A, vector<int>& B, vector<int>& C, vector<int>& D) {unordered_map<int, int> countAB;for (int u: A) {for (int v: B) {count…

Python并发编程(1)——Python并发编程的几种实现方式

更多精彩内容&#xff0c;请关注同名公众&#xff1a;一点sir&#xff08;alittle-sir&#xff09; Python 并发编程是指在 Python 中编写能够同时执行多个任务的程序。并发编程在任何一门语言当中都是比较难的&#xff0c;因为会涉及各种各样的问题&#xff0c;在Python当中也…

C0010.Qt5.15.2下载及安装方法

1. 下载及安装 Qt 添加链接描述下载地址&#xff1a;http://download.qt.io/ 选择 archive 目录 安装Qt **注意&#xff1a;**本人使用的是Qt5.15.2版本&#xff0c;可以按如下方法找到该版本&#xff1b;

Android Studio 新版本 Logcat 的使用详解

点击进入官方Logcat介绍 一个好的Android程序员要会使用AndroidStudio自带的Logcat查看日志&#xff0c;会Log定位也是查找程序bug的第一关键。同时Logcat是一个查看和处理日志消息的工具&#xff0c;它可以更快的帮助开发者调试应用程序。 步入正题&#xff0c;看图说话。 点…

msys2+gdb-multiarch+jlinkGDBServer的nrf52调试环境搭建

前言 刚拿到一块nrf52840的板子&#xff0c;为了方便以后的开发&#xff0c;先搭建一个调试环境&#xff0c;为方便以后回忆记录一下过程。 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参考 1.msys2命令行调用jlink工具 将jlink工具路径加入msys2的PAT…

华为云LTS日志上报至观测云最佳实践

华为云LTS简介 华为云云日志服务&#xff08;Log Tank Service&#xff0c;简称 LTS&#xff09;&#xff0c;用于收集来自主机和云服务的日志数据&#xff0c;通过海量日志数据的分析与处理&#xff0c;可以将云服务和应用程序的可用性和性能最大化&#xff0c;为您提供实时、…

【51单片机】点亮LED之经典流水灯

开发环境 开发板&#xff1a;普中51-单核-A2单片机&#xff1a;STC89C52RC&#xff08;双列直插40引脚 DIP40&#xff09;Keil uVision5 v9.61 最新版破解方法自行百度&#xff0c;相关文档和视频资料很多&#xff0c;我自己将这一操作记录下来当做博客发布&#xff0c;CSDN以…

【数据结构强化】应用题打卡

应用题打卡 数组的应用 对称矩阵的压缩存储 注意&#xff1a; 1. 2.上三角的行优先存储及下三角的列优先存储与数组的下表对应 上/下三角矩阵的压缩存储 注意&#xff1a; 上/下三角压缩存储是将0元素统一压缩存储&#xff0c;而不是将对角线元素统一压缩存储 三对角矩阵的…

King3399 SDK(ubuntu文件系统)编译简明教程

该文章仅供参考&#xff0c;编写人不对任务实验设备、人员及测量结果负责&#xff01;&#xff01;&#xff01; 0 引言 文章主要介绍King3399&#xff08;瑞芯微rk3399开发板&#xff0c;荣品&#xff09;官方SDK&#xff08;Ubuntu文件系统&#xff09;编译过程&#xff0c…

GaussDB关键技术原理:高弹性(六)

书接上文GaussDB关键技术原理&#xff1a;高弹性&#xff08;五&#xff09;从日志多流和事务相关方面对hashbucket扩容技术进行了解读&#xff0c;本篇将从扩容实践方面继续介绍GaussDB高弹性技术。 5 扩容实践 5.1 工具介绍 5.1.1 TPC-C TPC-C(全称Transaction Proces…

Leetcode 540. 有序数组中的单一元素

1.题目基本信息 1.1.题目描述 给你一个仅由整数组成的有序数组&#xff0c;其中每个元素都会出现两次&#xff0c;唯有一个数只会出现一次。 请你找出并返回只出现一次的那个数。 你设计的解决方案必须满足 O(log n) 时间复杂度和 O(1) 空间复杂度。 1.2.题目地址 https:…