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

Etcd使用

介绍

本文将从 Etcd 命令行基础操作入手,解决 API 版本兼容问题,再深入讲解 C++ 客户端库的安装与使用,最终通过封装 Registry(服务注册)和 Discovery(服务发现)类,提供可直接复用的分布式服务管理方案。

一、Etcd 命令行基础操作与 API 版本适配

在使用 etcdctl(Etcd 官方命令行工具)时,最常见的问题是 API 版本不兼容 ——Etcd 默认可能启用 V2 版本 API,而 V3 版本才支持更丰富的分布式特性(如租约、Watcher 等)。以下是完整的键值对操作流程及问题解决方案。

1.1 基础键值对操作(V3 版本)

首先尝试创建一个键 mykey 并设置值为 this is awesome,命令如下:

bash

etcdctl put mykey "this is awesome"
常见报错与原因

若执行后出现类似以下报错,说明当前使用的是 V2 版本 API,而 put 是 V3 版本的命令:

bash

Error: unknown command "put" for "etcdctl"

1.2 永久配置 Etcd V3 API

为了让 etcdctl 默认使用 V3 版本 API,需将 API 版本配置到系统环境变量中,步骤如下:

  1. 编辑系统环境变量配置文件打开 /etc/profile(该文件对所有用户生效,若仅需当前用户生效,可编辑 ~/.bashrc):

    bash

    sudo vim /etc/profile
    
  2. 添加 API 版本配置在文件末尾添加以下内容,指定 Etcd 客户端 API 版本为 3:

    bash

    export ETCDCTL_API=3
    
  3. 加载配置使其生效执行以下命令,无需重启系统即可让配置生效:

    bash

    source /etc/profile
    
  4. 验证配置重新执行 put 命令,若成功输出以下内容,说明配置生效:

    bash

    etcdctl put mykey "this is awesome"
    # 成功输出:OK
    

    可进一步通过 get 命令验证键值对是否存在:

    bash

    etcdctl get mykey
    # 输出:
    # mykey
    # this is awesome
    

二、Etcd C++ 客户端库安装

要在 C++ 项目中使用 Etcd,需安装官方推荐的 etcd-cpp-apiv3 客户端库。该库依赖 Boost、Protobuf、gRPC 等基础组件,需先安装依赖再编译库文件。

2.1 安装依赖库(Ubuntu 系统)

按顺序执行以下命令,安装所有依赖组件:

# 1. 安装 Boost 全量库(Etcd 依赖 Boost 进行网络和异步操作)
sudo apt-get install libboost-all-dev libssl-dev # 2. 安装 Protobuf 和 gRPC(Etcd 底层使用 gRPC 协议通信)
sudo apt-get install libprotobuf-dev protobuf-compiler-grpc 
sudo apt-get install libgrpc-dev libgrpc++-dev  # 3. 安装 cpprestsdk(用于 HTTP 异步请求处理)
sudo apt-get install libcpprest-dev 

2.2 编译并安装 etcd-cpp-apiv3

从 GitHub 克隆源码并编译安装,指定安装路径为 /usr(系统默认库路径,方便项目引用):

# 1. 克隆源码
git clone https://github.com/etcd-cpp-apiv3/etcd-cpp-apiv3.git# 2. 创建编译目录并进入
cd etcd-cpp-apiv3 
mkdir build && cd build # 3. CMake 配置(指定安装路径为 /usr)
cmake .. -DCMAKE_INSTALL_PREFIX=/usr # 4. 编译(-j$(nproc) 表示使用所有 CPU 核心加速编译)
make -j$(nproc) # 5. 安装到系统路径
sudo make install

三、Etcd 核心概念与 C++ 客户端类解析

在进行代码实现前,需先理解 Etcd 用于服务注册与发现的核心概念,以及 etcd-cpp-apiv3 库中的关键类 —— 这些类是实现功能的基础。

3.1 核心概念

  • 服务注册:服务启动时,向 Etcd 写入自身的「服务标识 - 地址 / 端口」键值对,并通过「租约」确保服务下线后键值对自动删除(避免无效服务地址残留)。
  • 服务发现:客户端通过 Etcd 读取指定「服务目录」下的所有键值对,获取可用服务地址;同时通过「Watcher」监听目录变化,实时感知服务上线 / 下线。
  • 租约(Lease):Etcd 中的临时键机制,租约到期前需「续租」,否则键值对自动删除(用于服务健康检测)。
  • Watcher:Etcd 的事件监听机制,可监听指定键 / 目录的新增、删除、修改事件,实时同步数据变化。

3.2 关键 C++ 类解析

etcd-cpp-apiv3 库封装了 Etcd 的核心功能,以下是实现服务注册与发现必须掌握的类:

类名核心作用关键方法
Event封装 Etcd 事件信息(如键值对新增 / 删除)event_type():获取事件类型(PUT/DELETE_/INVALID);kv():获取当前键值对;prev_kv():获取事件前的键值对
Response封装 Etcd 操作的响应结果(成功 / 失败信息、返回数据)is_ok():判断操作是否成功;error_message():获取错误信息;events():获取事件列表(Watcher 场景)
KeepAlive封装租约的「续租」逻辑,确保租约不失效Lease():获取租约 ID;Cancel():停止续租(服务下线时调用)
ClientEtcd 客户端核心类,提供键值对操作、租约管理的接口put():写入键值对(支持绑定租约);ls():读取目录下所有键值对;leasegrant():创建租约;leasekeepalive():创建续租对象
Watcher封装 Etcd 监听逻辑,实时感知键 / 目录变化构造函数:指定监听的客户端、键 / 目录、回调函数;Wait():阻塞等待监听事件;Cancel():停止监听

四、C++ 实战:服务注册与发现基础实现

本节通过两个基础示例,分别演示「服务注册」和「服务发现 + Watcher 监听」的核心逻辑,帮助理解底层调用流程。

4.1 示例 1:服务注册(带租约)

服务启动时,向 Etcd 的 /service 目录下注册自身地址,并通过租约确保服务下线后键值对自动删除。

#include <etcd/Client.hpp>
#include <etcd/KeepAlive.hpp>
#include <etcd/Response.hpp>
#include <thread>
#include <chrono>
#include <iostream>int main()
{// 1. Etcd 服务地址(默认端口 2379)const std::string etcd_host = "http://127.0.0.1:2379";// 2. 创建 Etcd 客户端实例etcd::Client client(etcd_host);// 3. 创建租约并启动续租(租约有效期 10 秒,需定期续租)// leasekeepalive() 返回 pplx::task(异步任务),get() 阻塞获取结果auto keep_alive = client.leasekeepalive(10).get();// 获取租约 ID(后续绑定到键值对)int64_t lease_id = keep_alive->Lease();std::cout << "创建租约成功,租约 ID:" << lease_id << std::endl;// 4. 注册服务auto resp = client.put("/service/user", "127.0.0.1:15535", lease_id).get();if (!resp.is_ok()){std::cerr << "服务注册失败:" << resp.error_message() << std::endl;return -1;}std::cout << "user 服务注册成功:/service/user -> 127.0.0.1:15535" << std::endl;// 5. 注册第二个服务(无租约,永久存在)auto resp2 = client.put("/service/friend", "127.0.0.1:9090").get();if (resp2.is_ok()){std::cout << "friend 服务注册成功:/service/friend -> 127.0.0.1:9090" << std::endl;}// 6. 模拟服务运行(10 秒后退出,租约停止续租,user 服务键值对自动删除)std::this_thread::sleep_for(std::chrono::seconds(10));// 主动停止续租(可选,程序退出时会自动释放)keep_alive->Cancel();std::cout << "服务停止,租约已取消" << std::endl;return 0;
}

4.2 示例 2:服务发现与 Watcher 监听

客户端读取 Etcd 中 /service 目录下的所有服务,并监听目录变化,实时打印服务上线 / 下线信息。

cpp

#include <etcd/Client.hpp>
#include <etcd/Watcher.hpp>
#include <etcd/Response.hpp>
#include <etcd/Value.hpp>
#include <iostream>// 7. 事件回调函数:监听到服务变化时触发
void on_service_change(const etcd::Response &resp)
{// 检查响应是否正常if (!resp.is_ok()){std::cerr << "Watcher 错误:" << 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;}else if (ev.event_type() == etcd::Event::EventType::DELETE_){// 服务下线事件(通过 prev_kv() 获取下线前的服务信息)std::cout << "[服务下线] " << ev.prev_kv().key() << " -> " << ev.prev_kv().as_string() << std::endl;}}
}int main()
{const std::string etcd_host = "http://127.0.0.1:2379";etcd::Client client(etcd_host);// 8. 初始获取 /service 目录下的所有服务(服务发现)auto resp = client.ls("/service").get();if (!resp.is_ok()){std::cerr << "获取服务列表失败:" << resp.error_message() << std::endl;return -1;}// 打印初始服务列表std::cout << "初始服务列表:" << std::endl;int service_count = resp.keys().size();for (int i = 0; i < service_count; ++i){std::cout << "- " << resp.key(i) << " -> " << resp.value(i).as_string() << std::endl;}// 9. 创建 Watcher 监听 /service 目录(递归监听子键变化)// 构造函数参数:客户端、监听目录、回调函数、是否递归监听etcd::Watcher watcher(client, "/service", on_service_change, true);// 10. 阻塞等待监听事件(程序持续运行,直到手动终止)std::cout << "\n开始监听服务变化(Ctrl+C 退出)..." << std::endl;watcher.Wait();return 0;
}

五、工程化封装:Registry 与 Discovery 类

基础示例仅演示核心逻辑,实际项目中需将代码封装为可复用的类,降低耦合度。以下是 Registry(服务注册)和 Discovery(服务发现)的工程化封装实现,包含日志打印(需自行实现 logger.hpp)和智能指针管理。

5.1 服务注册类:Registry

封装租约创建、服务注册、自动续租逻辑,服务销毁时自动停止续租。

#pragma once#include <etcd/Client.hpp>
#include <etcd/KeepAlive.hpp>
#include <etcd/Response.hpp>
#include <memory>  // 用于智能指针
#include <string>
#include "logger.hpp"  // 自定义日志库class Registry
{
public:// 智能指针类型定义(方便外部管理对象生命周期)using ptr = std::shared_ptr<Registry>;Registry(const std::string &host, int lease_ttl = 10): _lease_ttl(lease_ttl){// 创建 Etcd 客户端_client = std::make_shared<etcd::Client>(host);if (!_client){LOG_FATAL("创建 Etcd 客户端失败");throw std::runtime_error("Failed to create Etcd client");}// 创建租约并启动续租try{_keepalive = _client->leasekeepalive(_lease_ttl).get();_lease_id = _keepalive->Lease();LOG_INFO("Etcd 租约创建成功,租约 ID:{},有效期:{} 秒", _lease_id, _lease_ttl);}catch (const std::exception &e){LOG_FATAL("创建 Etcd 租约失败:{}", e.what());throw;  // 向上抛出异常,让调用者处理}}~Registry(){if (_keepalive){_keepalive->Cancel();LOG_INFO("Etcd 租约已取消,租约 ID:{}", _lease_id);}}bool register_service(const std::string &service_key, const std::string &service_value){if (service_key.empty() || service_value.empty()){LOG_ERROR("服务键或值不能为空");return false;}try{// 绑定租约写入键值对auto resp = _client->put(service_key, service_value, _lease_id).get();if (resp.is_ok()){LOG_INFO("服务注册成功:{} -> {}", service_key, service_value);return true;}else{LOG_ERROR("服务注册失败:{},错误信息:{}", service_key, resp.error_message());return false;}}catch (const std::exception &e){LOG_ERROR("服务注册异常:{} -> {},异常信息:{}", service_key, service_value, e.what());return false;}}private:std::shared_ptr<etcd::Client> _client;       // Etcd 客户端(智能指针管理
http://www.dtcms.com/a/473546.html

相关文章:

  • etcd实战课-实战篇(上)
  • Kubernetes 运维指南:kubectl 命令全解析
  • 网站logo关键字参数
  • ubuntu下桌面应用启动图标的内容文件
  • Leetcode 25
  • 西安博达网站建设自己制作wordpress plugin
  • OpenCV的数据类型二
  • Serdes专题(3)Lattice Serdes架构
  • 人形机器人项目中使用Ubuntu-Server安装桌面系统进行远程xrdp远程连接操作
  • 京东开源了一款大模型安全框架:JoySafety,说是京东内部已应用,实现95%+攻击拦截率
  • 【传奇开心果系列】基于Flet框架实现的关于页面创建和提供文件下载集成了网络请求、文件下载、剪贴板操作功能自定义模板特色和实现原理深度解析
  • ​为什么我们需要将Flow转换为StateFlow?​​
  • vscode远程连接云服务器的初次尝试
  • 甘肃网站开发公司用手机怎么做免费网站
  • 网站是由多个网页组成的吗济南网约车平台
  • Linux系统下的终端,会话,shell,bash,进程组这几个概念的关系。
  • 微信小程序入门学习教程,从入门到精通,自定义组件与第三方 UI 组件库(以 Vant Weapp 为例) (16)
  • 银河麒麟V10高级服务器版Bash快捷键经常失效
  • 建设网站平台需要什么硬件配置电脑上买wordpress
  • Jessibuca 播放器
  • minio之docker的单机版安装
  • 主流 AI IDE 之一的 Qoder 和 Lingma IDE 介绍
  • 搜索不到网站的关键词国家企业信用公示系统官网查询
  • PostgreSQL在Linux中的部署和安装教程
  • AI大事记12:Transformer 架构——重塑 NLP 的革命性技术(上)
  • PostgreSQL JDBC 连接参数大全
  • 【SpringBoot从初学者到专家的成长11】Spring Boot中的application.properties与application.yml详解
  • 简述你对于网站建设的认识h5微网站开发
  • OpenHarmony IMF输入法框架全解析:从原理到自定义输入法开发实战指南
  • LabVIEW的PID控制器带报警仿真系统