聊天室项目开发——etcd的安装和使用
1.etcd的安装
这里也是比较简单我就直接放步骤了,一般是没有问题的,如果有问题欢迎在评论区指出
sudo apt-get install etcd //安装etcd
sudo systemctl start etcd //启动etcd服务
sudo systemctl enable etcd //设置etcd开机自启动
2.介绍etcd讲解一些有关etcd的概念
2.1 介绍etcd
Etcd 是一个 golang 编写的分布式、高可用的一致性键值存储系统,用于配置共享和服 务发现等。它使用 Raft 一致性算法来保持集群数据的一致性,且客户端通过长连接 watch 功能,能够及时收到数据变化通知,相较于 Zookeeper 框架更加轻量化。
扯了半天其实我们可以把etcd理解为一个 redis,置于为什么可以这么理解就要看我后面的讲解了。
2.2 etcd的一些概念
这里我先讲讲etcd是怎么进行使用的,首先我们得有一个能提供服务的服务端,然后在服务端向etcd server注册自己的信息,包括地址(ip和端口)和服务名称,在注册前我们需要先向etcd server申请一个租约(这个概念我后面讲)。
我们还要有一个需要访问我们服务端的客户端,在这个客户端一开始肯定是不知道我们服务的地址的,但是我们可以通过etcd的ls接口获取所有已经在etcd注册的服务,接着我们就可以通过服务的名称来获取我们需要服务的地址,进而进行访问。在客户端我们还可以通过定义监控对象,来感知服务的上下线。
上面提到的租约类似redis中数据的有效时间,一旦服务下线那么等待租约的时间一过,那么etcd就会通过回调函数通知监控对象有哪些服务下线,,但并不是说服务没有下线租约就没有作用,在服务正常的时候租约会每隔一段时间向etcd服务器发送信息,告诉etcd服务器我这个服务还在。
3.etcd的使用
服务发现测试程序
//discoverer.cc
#include <etcd/Client.hpp>
#include <etcd/Watcher.hpp>void watcherCallback(etcd::Response const &resp)
{if (resp.error_code()){std::cout << "Watcher Error:" << resp.error_code();std::cout << "-" << resp.error_message() << std::endl;}else{for(auto const &ev:resp.events())if (ev.event_type() == etcd::Event::EventType::PUT){// 如果是新增值,则通过当前值来查看新增的是什么值std::cout << "服务" << ev.kv().key() << "新增主机:";std::cout << ev.kv().as_string() << std::endl;}else if (ev.event_type() == etcd::Event::EventType::DELETE_){// 如果是值被删除,则需要通过发生事件之前的值来了解哪个值被删除了std::cout << "服务" << ev.kv().key() << "下线主机:";std::cout<< ev.prev_kv().as_string() << std::endl;}}
}int main()
{std::string registry_host = "http://127.0.0.1:2379";std::string service_key = "/service/user/";etcd::Client etcd(registry_host); // 初次先用 ls 获取所有能够提供指定服务的实例信息etcd::Response resp = etcd.ls(service_key).get();if (resp.is_ok()){for (int i = 0; i < resp.keys().size(); i++){std::cout << resp.key(i) << "=" << resp.value(i).as_string() << std::endl;}}else std::cout << "Get Service Error:" << resp.error_code();std::cout << "-" << resp.error_message() << std::endl;// 获取之后,然后定义监控对象,监控目录内容变化,通过目录变化来感知服务的上线与下线etcd::Watcher watcher(registry_host, service_key, watcherCallback, true);getchar();watcher.Cancel();return 0;
}
服务注册程序
//registry.cc
#include <etcd/Client.hpp>
#include <etcd/Response.hpp>
#include <etcd/KeepAlive.hpp>
#include <thread>int main()
{std::string registry_host = "http://127.0.0.1:2379";//为了防止多主机注册相同服务时,信息覆盖,因此每个主机在服务名后加入自己的实例名称,相当于各有各的服务-主机键值对std::string service_key = "/service/user/instance";std::string service_host = "112.23.23.120:9090";std::string service_key2 = "/service/user/test";std::string service_host2 = "112.23.23.120:9091";etcd::Client etcd(registry_host); //可以理解为连接服务器//对客户端创建一个指定时长的租约,若租约到期则创建的键值将被撤销//通过租约进行保活探测,若服务提供端掉线,则租约到期后etcd会给服务发现者发送服务下线通知// etcd::Response resp = etcd.leasegrant(3).get(); //设置一个3s的租约// auto lease_id = resp.value().lease(); //获取租约ID//创建客户端的同时,创建一个保活的3s租约 保活对象 -- 也就是一旦断开连接,3s租约失效std::shared_ptr<etcd::KeepAlive> keepalive = etcd.leasekeepalive(3).get();auto lease_id = keepalive->Lease();std::shared_ptr<etcd::KeepAlive> keepalive2 = etcd.leasekeepalive(10).get();auto lease_id2 = keepalive2->Lease();auto resp_task = etcd.put(service_key,service_host,lease_id); //注册服务auto resp_task2 = etcd.put(service_key2,service_host2,lease_id2); //注册服务auto resp = resp_task.get();if(resp.is_ok() == false){std::cout << resp.error_message() << std::endl;return -1;}std::cout << "添加数据成功!" << std::endl;getchar();//回车后撤销租约// //租约的撤销etcd.leaserevoke(lease_id);return 0;
}
make文件
all: registry discoverer
registry: registry.ccg++ -std=c++17 $^ -o $@ -letcd-cpp-api -lcpprest
discoverer: discoverer.ccg++ -std=c++17 $^ -o $@ -letcd-cpp-api -lcpprest
clean:rm -rf registry discoverer