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

Linux系统C++开发环境搭建工具(二)—— etcd 使用指南

文章目录

  • etcd简介
  • etcd安装与使用
  • API接口的使用
  • 以服务发现场景为例进行二次封装

etcd简介

  etcd 是一个分布式、高可用的键值存储系统(以key: val的形式做数据存储),主要用于在分布式系统中安全地存储和管理关键数据。 它最著名的角色是 Kubernetes 的“大脑”,负责存储整个集群的状态和配置信息。
  etcd 服务器类似于一个数据库,存储键值对数据。所有客户端都可以通过长连接共享这些数据。一个客户端修改了键值对,etcd 服务器会通知所有正在监听该键值对的客户端。

常用场景:服务发现(Service Discovery)

  • 场景:在微服务架构中,服务实例的 IP 和端口是动态变化的。服务启动时可以将自己的地址注册到 etcd,消费者则从 etcd 查询可用的服务地址。
  • 类比:就像电话簿,服务在这里“登记”和“查找”。

图示:
在这里插入图片描述

etcd安装与使用

安装:

sudo apt-get install etcd

配置文件:

vim /etc/default/etcd

更改绑定监听地址,使用外部网络能访问:
ETCD_LISTEN_CLIENT_URLS="http://0.0.0.0"
更改外部访问的地址:
ETCD_ADVERTISE_CLIENT_URLS="http://公网ip:端口"

重新启动:

sudo systemctl restart etcd

配置指定API版本:

vim /etc/profile

在末尾加:
export ETCDCTL_API=3
重新加载配置文件:

source /etc/profile

验证:
在这里插入图片描述

搭建c++客户端,使用第三方库API接口
下载库:

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

下载etcd-cpp-apiv3库源码(可选):

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

API接口的使用

  • Client对象:客户端操作句柄对象
    在构建该对象时需要传入参数:url_or_endpoints,即字符串或字符串向量,指定 etcd 服务地址。键值数据的推送和拉取,租约的设置等都是通过该对象提供的接口完成。
  • KeepAlive保活对象:针对一个租约可以不断进行续租,从而维持租约数据的有效性。
    该对象通过Client对象提供的leasekeepalive()租约接口返回值再进行get()而得到。
  • Response对象:针对请求进行响应。
    该对象通常由Client对象提供的接口put()/ls()返回而得到。
  • Value对象:存放键值对数据。
  • Watcher对象:进行数据变化通知。
    构建该对象需要参数:
    • client对象
    • 要监听的键名
    • 变化回调函数
    • 是否递归监听前缀匹配的所有键,通常填true

图示:
在这里插入图片描述

示例:
put.cc

#include <etcd/Client.hpp>
#include <etcd/KeepAlive.hpp>
#include <etcd/Response.hpp>
#include <etcd/Watcher.hpp>
#include <thread>
int main(int argc,char* argv[])
{//创建客户端etcd::Client client("http://127.0.0.1:2379");//指定租约并获取租约保活对象auto keep_alive = client.leasekeepalive(3).get();//获取租约idauto lease_id = keep_alive->Lease();//向etcd新增数据auto rsp = client.put("/source/user","127.0.0.1:6000",lease_id).get();if(rsp.is_ok()==false)std::cout<<"新增数据失败"<<std::endl;rsp = client.put("/source/file","127.0.0.1:6001",lease_id).get();if(rsp.is_ok()==false)std::cout<<"新增数据失败"<<std::endl;std::this_thread::sleep_for(std::chrono::seconds(10));return 0;
}

get.cc

#include <etcd/Client.hpp>
#include <etcd/KeepAlive.hpp>
#include <etcd/Response.hpp>
#include <etcd/Watcher.hpp>
#include <etcd/Value.hpp>
#include <etcd/SyncClient.hpp>void callback(const etcd::Response& rsp)
{if(rsp.is_ok()==false){std::cout<<"错误事件通知"<<rsp.error_message()<<std::endl;return;}for(auto const& ev: rsp.events()){if (ev.event_type() == etcd::Event::EventType::PUT) {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;}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[])
{//创建客户端etcd::Client client("http://127.0.0.1:2379");//获取数据auto rsp = client.ls("/source").get();if(rsp.is_ok()==false){std::cout<<"数据获取失败"<<std::endl;return -1;}int n = rsp.keys().size();for(int i = 0;i<n;i++){std::cout<<rsp.value(i).as_string()<<":"<<rsp.key(i)<<std::endl;}auto watcher = etcd::Watcher(client,"/source",callback,true);watcher.Wait();return 0;
}

Makefile:

all:put get
put:put.ccg++ -o $@ $^ -letcd-cpp-api -lcpprest
get:get.ccg++ -o $@ $^ -letcd-cpp-api -lcpprest
.PHONY:clean
clean:rm -rf put get

在这里插入图片描述

以服务发现场景为例进行二次封装

使用原生 API 接口较为复杂繁琐,接下来我们针对服务发现场景进行二次封装

两个客户端:

  • 服务注册客户端:向服务器新增服务信息数据,并进行保活
  • 服务发现客户端:从服务器查找服务信息数据,并进行改变事件监控

思想:

  1. 封装服务注册客户端类:
    提供一个接口:向服务器新增数据并保活
    参数:注册中心地址、新增的服务信息
  2. 封装服务发现客户端类:
    提供两个设置回调函数的接口:提供服务上线和下线的事件处理接口
    提供一个设置根目录的接口:用于获取指定目录下的数据以及监控目录下的数据的改变

示例:

#include <etcd/Client.hpp>
#include <etcd/KeepAlive.hpp>
#include <etcd/Response.hpp>
#include <etcd/Watcher.hpp>
#include <etcd/Value.hpp>
#include <etcd/SyncClient.hpp>
#include <memory>
#include <functional>
class Registry
{
public:Registry(const std::string& host):_client(std::make_shared<etcd::Client>(host)),_keep_alive(_client->leasekeepalive(3).get()),_lease_id(_keep_alive->Lease()){}bool registry(const std::string& key,const std::string& val){auto rsp = _client->put(key,val,_lease_id,true).get();if(rsp.is_ok()==false){//建议替换为日志输出std::cout<<key<<": "<<val<<"注册失败"<<std::endl;return false;}else return true;}~Registry(){_client->Cancel();}
private:std::shared_ptr<etcd::Client> _client;std::shared_ptr<etcd::KeepAlive> _keep_alive;uint64_t _lease_id;
};
class Discovery
{
public: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 rsp = _client->ls(basedir).get();if(rsp.is_ok()==false){std::cout<<"获取数据失败 "<<rsp.error_message()<<std::endl;}int sz = rsp.keys().size();for(int i=0;i<sz;i++){if(_del_cb)_put_cb(rsp.key(i),rsp.value(i).as_string());}_watcher = std::make_shared<etcd::Watcher>(*_client,basedir,std::bind(&Discovery::callback,this, std::placeholders::_1),true);}void callback(const etcd::Response& rsp){if(rsp.is_ok()==false){std::cout<<"错误事件通知"<<rsp.error_message()<<std::endl;return;}for(auto const& ev: rsp.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_) {std::cout << "下线服务:" << ev.kv().key() << "-" << ev.kv().as_string() << std::endl;}}}~Discovery(){_watcher->Cancel();}
private:NotifyCallback _put_cb;NotifyCallback _del_cb;std::shared_ptr<etcd::Client> _client;std::shared_ptr<etcd::Watcher> _watcher;
};

非常感谢您能耐心读完这篇文章。倘若您从中有所收获,还望多多支持呀!在这里插入图片描述

http://www.dtcms.com/a/485751.html

相关文章:

  • AI+大数据时代:如何从架构到生态重构时序数据库的价值?
  • 小小 Postgres,何以替代 Redis、MongoDB 甚至 ES?
  • Win10正式谢幕!附最后更新版本
  • 前端自动翻译插件webpack-auto-i18n-plugin的使用
  • 山东官方网站建设沧州网络推广渠成网络
  • 贺州网站建设公司家装设计需要学什么软件
  • 网站在百度上搜索不到丽水山耕品牌建设网站
  • 漂亮的门户网站dedecms游戏门户网站源码
  • thinkphp2.1网站挂文件国有企业投资建设项目
  • 网站首页的动态视频怎么做的建网站的流程和费用
  • 一些可以做翻译的网站微信小程序制作文档
  • 东莞公司网站开发首页制作教程
  • 河北大名网站建设招聘深圳网站设计首选柚米
  • 网站友链中英文外贸网站模版
  • html5企业网站模版经营一个网站要怎么做
  • 专业点网站制作公司龙泉市建设局网站
  • 网站设计资源seo优化网站的注意事项
  • 深圳网站运营托管163邮箱怎么申请企业邮箱
  • 孝感市门户网站传媒wordpress博客
  • 做网站推广的销售电话开场白wordpress注册邮箱怎么修改
  • 在哪公司建设网站东莞seo关键词搜索关键词
  • 万网虚拟服务器怎么做网站内容模板网站如何做优化
  • 网站底部关键词内链个人微信公众平台注册流程
  • 兰州seo网站排名高新西区网站建设
  • 山东济南网站开发移动商务网站开发课程
  • 哪家网站好中国企业500强最新排名2021
  • 好的网站推广什么网站可以做试卷
  • 网页设计与制作参考文献聊城关键词优化推广
  • 网站配色设计wordpress写作工具
  • 做网站价格表贵州贵州省住房和城乡建设厅网站