安装与配置consul服务端
安装
在这里我直接使用docker
安装了,简单许多
docker pull consul
docker配置启动consul
#1.启动consul服务器
docker run --hostname consulsvul --name consul_node_1 -d -p 8500:8500 -p 8301:8301 -p 8302:8302 -p 8600:8600 consul agent -server -bootstrap-expect 2 -ui -bind=0.0.0.0 -client=0.0.0.0
#2.查看分配的ip地址
docker inspect --format '{{.NetworkSettings.IPAddress}}' consul_node_1
#3.启动另外两个节点,加入集群
docker run --hostname consulsvu2 --name consul_node_2 -d -p 8501:8500 consul agent -server -ui -bind=0.0.0.0 -client=0.0.0.0 -join 填写第二步显示分配的ip地址
docker run --hostname consulsvu3 --name consul_node_3 -d -p 8502:8500 consul agent -server -ui -bind=0.0.0.0 -client=0.0.0.0 -join 填写第二步显示分配的ip地址
#查看集群状态
docker exec -t consul_node_1 consul members
网页后台
浏览器打开即可
127.0.0.1:8500
这就是后台界面了,可以看见我们配置的集群的三个节点.由于我之前在主节点中注册了两个服务,但是没有做健康处理,所以这里主节点是红色的,你们应该都是绿色的.
进入services
服务界面,consul
是自带的,显示的是集群中三个节点的健康状态,
signupService1
是我测试代码产生的,等后续执行了我写的代码也会这样,由于consul
有健康检测,需要定时给服务端发送健康心跳,所以超时后就会如图显示变成红色,表示不健康
使用c++ ppconsul库实现Consul集成
简介
Consul是一个用于服务发现、健康检查和动态配置的工具,使得分布式系统中的服务能够轻松地相互发现和通信。ppconsul是一个用于C++的库,为开发者提供了与Consul进行交互的简单而强大的接口。
安装
首先,你需要获取ppconsul库的源代码,并将其集成到你的C++项目中。你可以通过以下步骤来完成:
git clone https://github.com/oliora/ppconsul.git
cd ppconsul
mkdir build && cd build
cmake ..
make
sudo make install
确保你的系统上已经安装了CMake
和libcurl
,json11
头文件header-only
#include <ppconsul/consul.h>
链接
g++ ppconsul_test.cpp -o ppconsul -lppconsul -lcurl -ljson11#添加这个参数链接ppconsul
服务注册
让我们通过一个简单的示例来展示如何使用ppconsul进行服务注册和发现。
由于这里的定时提交健康服务的代码,我使用了workflow
框架的定时器来编写的代码,读者可以将这部分的代码删除后学习,或者替换成其他的库
#include <ppconsul/consul.h>
#include "workflow/WFTaskFactory.h"
//维持节点健康
void timerCallback(WFTimertask* timerTask){
ppconsul::agent::Agent *pagent = static_cast<ppconsul::agent::Agent*>(timerTask->user_data);
pagent->servicePass("SignupServicel");
auto nextTask = WFTaskFactory::create_timer_task(5000000,timerCallback);
nextTask->user = pagent;
service_of(timerTask)->push_back(nextTask);
}
int main()
{
//将本服务注册到consul之中
//找到dc1注册中心
ppconsul::Consul consul("127.0.0.1:8500",ppconsul::kw::dc = "dc1");
//创建一个用来访问注册中心的agent
ppconsul::agent::Agent agent(consul);
agent.reisterService(
ppconsul::agent::kw::name = "SignupServicel",
ppconsul::agent::kw::address = "127.0.0.1",
ppconsul::agent::kw::id = "SignupServicel",
ppconsul::agent::kw::port = 1412,
ppconsul::agent::kw::check = ppconsul::agent::Ttlcheck{std::chrono::seconds(10)}
);
agent.servicePass("SignupServicel");//设置健康服务(心跳)
auto timerTask = WFTaskFactory::create_timer_task(5,timerCallback);
timerTask->user_data = &agent;
timerTask->start();
}
服务发现
服务发现作为客户端,我们可以直接使用http访问,在解析返回的json
我在consul中注册了一个名为SignupServicel的服务,其下有SignupServicel和SignupService2(在之前的代码执行后再将ppconsul::agent::kw::id =xxx这一行改为SignupService2即可和我一致)
查看所有的服务
http://127.0.0.1:8500/v1/agent/services
{
"signupService1": {
"ID": "signupService1",
"Service": "signupService1",
"Tags": [],
"Meta": {},
"Port": 1412,
"Address": "127.0.0.1",
"TaggedAddresses": {
"lan_ipv4": {
"Address": "127.0.0.1",
"Port": 1412
},
"wan_ipv4": {
"Address": "127.0.0.1",
"Port": 1412
}
},
"Weights": {
"Passing": 1,
"Warning": 1
},
"EnableTagOverride": false,
"Datacenter": "dc1"
},
"signupService2": {
"ID": "signupService2",
"Service": "signupService1",
"Tags": [],
"Meta": {},
"Port": 1412,
"Address": "127.0.0.1",
"TaggedAddresses": {
"lan_ipv4": {
"Address": "127.0.0.1",
"Port": 1412
},
"wan_ipv4": {
"Address": "127.0.0.1",
"Port": 1412
}
},
"Weights": {
"Passing": 1,
"Warning": 1
},
"EnableTagOverride": false,
"Datacenter": "dc1"
}
}
查看指定的服务
http://127.0.0.1::8500/v1/agent/service/signupService1
{
"ID": "signupService1",
"Service": "signupService1",
"Tags": [],
"Meta": {},
"Port": 1412,
"Address": "127.0.0.1",
"TaggedAddresses": {
"lan_ipv4": {
"Address": "127.0.0.1",
"Port": 1412
},
"wan_ipv4": {
"Address": "127.0.0.1",
"Port": 1412
}
},
"Weights": {
"Passing": 1,
"Warning": 1
},
"EnableTagOverride": false,
"ContentHash": "1ff72835f53fe7d",
"Datacenter": "dc1"
}
查看健康服务
http://127.0.0.1:8500/v1/health/service/signupService1
此时先执行代码使SignupService2处于健康状态,对比SignupServicel和SignupService2
可以看出json[0]是SignupServicel的信息,json[1]是SignupServicel的信息
由于我们事先让SignupService2处于健康状态,SignupServicel处于不健康状态
可以看见json[0][“Checks”][1]==critical,json[1][“Checks”][1]==passing
也就是说passing是健康的,critical是不健康的
[
{
"Node": {
"ID": "41557981-708b-5e95-a80d-4a0ae866346b",
"Node": "consulsvul",
"Address": "172.17.0.2",
"Datacenter": "dc1",
"TaggedAddresses": {
"lan": "172.17.0.2",
"lan_ipv4": "172.17.0.2",
"wan": "172.17.0.2",
"wan_ipv4": "172.17.0.2"
},
"Meta": {
"consul-network-segment": ""
},
"CreateIndex": 5,
"ModifyIndex": 9
},
"Service": {
"ID": "signupService1",
"Service": "signupService1",
"Tags": [],
"Address": "127.0.0.1",
"TaggedAddresses": {
"lan_ipv4": {
"Address": "127.0.0.1",
"Port": 1412
},
"wan_ipv4": {
"Address": "127.0.0.1",
"Port": 1412
}
},
"Meta": {},
"Port": 1412,
"Weights": {
"Passing": 1,
"Warning": 1
},
"EnableTagOverride": false,
"Proxy": {
"Mode": "",
"MeshGateway": {},
"Expose": {}
},
"Connect": {},
"CreateIndex": 928,
"ModifyIndex": 928
},
"Checks": [
{
"Node": "consulsvul",
"CheckID": "serfHealth",
"Name": "Serf Health Status",
"Status": "passing",
"Notes": "",
"Output": "Agent alive and reachable",
"ServiceID": "",
"ServiceName": "",
"ServiceTags": [],
"Type": "",
"Interval": "",
"Timeout": "",
"ExposedPort": 0,
"Definition": {},
"CreateIndex": 5,
"ModifyIndex": 5
},
{
"Node": "consulsvul",
"CheckID": "service:signupService1",
"Name": "Service 'signupService1' check",
"Status": "critical",
"Notes": "",
"Output": "TTL expired",
"ServiceID": "signupService1",
"ServiceName": "signupService1",
"ServiceTags": [],
"Type": "ttl",
"Interval": "",
"Timeout": "",
"ExposedPort": 0,
"Definition": {},
"CreateIndex": 928,
"ModifyIndex": 1172
}
]
},
{
"Node": {
"ID": "41557981-708b-5e95-a80d-4a0ae866346b",
"Node": "consulsvul",
"Address": "172.17.0.2",
"Datacenter": "dc1",
"TaggedAddresses": {
"lan": "172.17.0.2",
"lan_ipv4": "172.17.0.2",
"wan": "172.17.0.2",
"wan_ipv4": "172.17.0.2"
},
"Meta": {
"consul-network-segment": ""
},
"CreateIndex": 5,
"ModifyIndex": 9
},
"Service": {
"ID": "signupService2",
"Service": "signupService1",
"Tags": [],
"Address": "127.0.0.1",
"TaggedAddresses": {
"lan_ipv4": {
"Address": "127.0.0.1",
"Port": 1412
},
"wan_ipv4": {
"Address": "127.0.0.1",
"Port": 1412
}
},
"Meta": {},
"Port": 1412,
"Weights": {
"Passing": 1,
"Warning": 1
},
"EnableTagOverride": false,
"Proxy": {
"Mode": "",
"MeshGateway": {},
"Expose": {}
},
"Connect": {},
"CreateIndex": 1167,
"ModifyIndex": 1167
},
"Checks": [
{
"Node": "consulsvul",
"CheckID": "serfHealth",
"Name": "Serf Health Status",
"Status": "passing",
"Notes": "",
"Output": "Agent alive and reachable",
"ServiceID": "",
"ServiceName": "",
"ServiceTags": [],
"Type": "",
"Interval": "",
"Timeout": "",
"ExposedPort": 0,
"Definition": {},
"CreateIndex": 5,
"ModifyIndex": 5
},
{
"Node": "consulsvul",
"CheckID": "service:signupService2",
"Name": "Service 'signupService1' check",
"Status": "passing",
"Notes": "",
"Output": "",
"ServiceID": "signupService2",
"ServiceName": "signupService1",
"ServiceTags": [],
"Type": "ttl",
"Interval": "",
"Timeout": "",
"ExposedPort": 0,
"Definition": {},
"CreateIndex": 1167,
"ModifyIndex": 9231
}
]
}
]
使用consul kv存储
consul的kv存储可以用来编写配置文件,程序启动后从kv存储中读取配置信息在进行配置,可以进行集中配置管理,一般使用json格式
#include "ppconsul/kv.h"
using ppconsul::Consul;
using ppconsul::Consistency;
using namespace ppconsul::kv;
int main(){
Consul consul("127.0.0.1:8500",ppconsul::kw::dc="dc1");
Kv kv(consul);
// 设置一个key-value
kv.set("settings.something", "new-value");
// 从存储器中读取键的值
std::string something = kv.get("settings.something", "default-value");
std::cout << something << std::endl;
// 从consul kv存储中通过key删除
kv.erase("settings.something");
return 0;
}
root@VM-16-3-ubuntu:~/projects/test# g++ consul.cpp -o consul -lppconsul -lcurl -ljson11
root@VM-16-3-ubuntu:~/projects/test# ./consul
new-value
也可以在后台管理界面直接编写,点击右边的create按钮即可
高级功能
ppconsul库不仅仅局限于服务注册和发现,它还提供了许多其他功能,如健康检查、KV存储等。你可以根据自己的需求深入了解和使用这些高级功能。
结论
ppconsul是一个强大而灵活的C++库,用于简化与Consul的集成。通过它,你可以轻松地在你的应用程序中实现服务发现、健康检查等功能,使得你的分布式系统更加强大和可靠。