etcd键值存储系统的介绍和使用

1、etcd的介绍

etcd是一个高可用的键值存储,用来共享配置和服务发现。etcd是一个分布式减值存储,提供了一种可靠的方式来将数据存储在一个机器集群中,它是开源的,并且在GitHub上面可以下载源码。etcd优雅的处理了在网络分区之间的master选举,并且有很好的容错性,包括master丢失。您的应用可以向etcd写入数据或读取数据。一个简单的使用示例,实现了将存储数据库链接信息和特征存作为键-值存储在etcd中。这个值可以被监控,当这些值发生变化的时候,并且允许您的应用重新配置自己。

2、为什么介绍etcd

目前在网上能查到关于etcd的介绍只有几篇,而且转载来转载去的,主要针对其raft选举算法进行图解,这里就不作介绍了。而本文主要对其的使用方法来讲解,这方面相关的介绍甚少,官网https://coreos.com/把etcd的项目迁移到了GitHub,建议读者先到这里etcd软件包下载自己需要的etcd安装包(可解压直接使用),里面有丰富的document文档说明教你如何使用HTTP RESTful API来访问和请求etcd,您也可以到官网查看etcdctl工具的使用,您还可以选择在本博客了解etcd怎么使用。

3、etcd能用来做什么

etcd是一个应用在分布式环境下的 key/value 存储服务。利用 etcd 的特性,应用程序可以在集群中共享信息、配置或作服务发现,etcd 会在集群的各个节点中复制这些数据并保证这些数据始终正确。我们知道,etcd是CoreOs轻量级linux操作系统中最重要的组成部分,CoreOS是一个基于Docker的轻量级容器化Linux发行版,专为大型数据中心而设计,旨在通过轻量的系统架构和灵活的应用程序部署能力简化数据中心的维护成本和复杂度。CoreOS作为Docker生态圈中的重要一员,日益得到各大云服务商的重视。另外etcd的开源性质使得它可以很容易被我们的项目所引进,利用它我们可以实现服务共享,可以很轻松的实现客户端和服务器进行通信,在此基础上我们可以定制各种各样的服务。下面让我们赶紧看看如何使用etcd吧。

4、etcd提供的HTTP RESTful API

etcd支持http RESTful API,支持get查询,post,delete,put等操作。为了便于理解,可将它存储数据的框架看做一个文件系统,可以创建目录和“文件”,每个“文件”名就是一个key,每个“文件”的内容就是它的value,目录没有value只能包含子目录或者“文件”,可以通过RESTful API来获取这些key的值或者设置这些key的值。

5、etcd命令行接口使用

*运行一个单一的机器集群即启动本地etcd服务

解压上面下载的etcd软件包,执行etcd文件./etcd

*获取etcd的版本号

curl -L http://127.0.0.1:2379/version

*设置一个key的value

curl http://127.0.0.1:2379/v2/keys/message -XPUT -d value="Hello world"


*获取一个key的value

curl http://127.0.0.1:2379/v2/keys/message


*改变一个key的value

curl http://127.0.0.1:2379/v2/keys/message -XPUT -d value="Hello etcd"


*删除一个key节点

curl http://127.0.0.1:2379/v2/keys/message -XDELETE


*使用ttl(即设置一个key的值并给这个key加一个生命周期,当超过这个时间该值没有被访问则自动被删除)

curl http://127.0.0.1:2379/v2/keys/foo -XPUT -d value=bar -d ttl=5

*等待一个值的变化

curl http://127.0.0.1:2379/v2/keys/foo?wait=true

该命令调用之后会阻塞进程,直到这个值发生变化才能返回,当改变一个key的值,或者删除等操作发生时,该等待就会返回

特别注意,在变化发生度较高的情况下,最好把这种变化结果交给另外一个线程来处理,监控线程立即返回继续监控变化情况,当然etcd也提供了获取历史变化的命令,这个命令仅为丢失监听事件的情况下的补救方案。

*创建一个目录

curl http://127.0.0.1:2379/v2/keys/dir -XPUT -d dir=true

*列举一个目录

curl http://127.0.0.1:2379/v2/keys/dir

*递归列举一个目录

curl http://127.0.0.1:2379/v2/keys/dir?recursive=true

到这里我们可以组合以上的诸多用法实现自己想要的功能。例如监控一个目录下的所有key的变化,包括子目录的。可以使用命令:

curl http://127.0.0.1:2379/v2/keys/dir?recursive=true&wait=true

*删除一个目录

curl 'http://127.0.0.1:2379/v2/keys/dir?dir=true' -XDELETE

命令行接口就介绍这么多,详细可以参考下载的安装包里文档里面的api.md文件有更加详细的介绍。

6、c++封装libcurl实现etcd数据操作

libcurl为c语言提供了一套HTTP RESTful API例如要实现上面的获取一个值的方法:

#include 
#include 
#include 

using namespace std;
using namespace Json;

size_t process_data(void *buffer, size_t size, size_t nmemb, void *user_p)
{
	/* 获取json的value */
	Value root;
	Value node;
	Reader reader;
	FastWriter writer;
	string json = (char*)buffer;

	if(!reader.parse(json, root))
	{
		cout << "parse json error" << endl;	
		return 0;
	}
	string nodeString = writer.write(root["node"]);
	if(!reader.parse(nodeString, node))
	{
		cout << "parse json error" << endl;	
		return 0;
	}

	cout << node["value"] << endl;

	return 0;
}

int main(int argc, char **argv)
{
	//初始化libcurl
	CURLcode return_code;
	return_code = curl_global_init(CURL_GLOBAL_SSL);
	if (CURLE_OK != return_code)
	{
		cerr << "init libcurl failed." << endl;
		return -1;
	}

	// 获取easy handle
	CURL *easy_handle = curl_easy_init();
	if (NULL == easy_handle)
	{
		cerr << "get a easy handle failed." << endl;
		curl_global_cleanup(); 

		return -1;
	}

	char * buff_p = NULL;

	// 设置easy handle属性
	curl_easy_setopt(easy_handle, CURLOPT_URL, "http://127.0.0.1/v2/keys/message1");
	curl_easy_setopt(easy_handle, CURLOPT_PORT, 2379);
	curl_easy_setopt(easy_handle, CURLOPT_WRITEFUNCTION, &process_data);
	curl_easy_setopt(easy_handle, CURLOPT_WRITEDATA, buff_p);

	// 执行数据请求
	curl_easy_perform(easy_handle);	

	// 释放资源

	curl_easy_cleanup(easy_handle);
	curl_global_cleanup();

	return 0;
}
由于etcd返回的数据都是以json的形式,所以代码中还增加了一段对json的处理。

实现设置一个key的功能:

#include 
#include 
#include 

int etcd_set(char *key, char *value, char *token)
{
#define URL_MAX_LEN 50
#define VALUE_LEN 1024

         //初始化libcurl
	CURLcode return_code;
	char etcd_url[URL_MAX_LEN];
        char etcd_value[VALUE_LEN]; 
	
        return_code = curl_global_init(CURL_GLOBAL_SSL);
	if (CURLE_OK != return_code)
	{
		//cerr << "init libcurl failed." << endl;
		printf("init libcurl failed\n");
		return -1;
	}

	sprintf(etcd_url, "http://127.0.0.1:2379/v2/keys%s", key);
	sprintf(etcd_value, "value=%s", value);

	// 获取easy handle
	CURL *easy_handle = curl_easy_init();
	if (NULL == easy_handle)
	{
		//cerr << "get a easy handle failed." << endl;
		printf("get a easy handle failed.\n");
		curl_global_cleanup(); 
		return -1;
	}

	// 设置easy handle属性
	curl_easy_setopt(easy_handle, CURLOPT_URL, etcd_url); 
	curl_easy_setopt(easy_handle, CURLOPT_POST, 1);
	curl_easy_setopt(easy_handle, CURLOPT_POSTFIELDS, etcd_value);
	curl_easy_setopt(easy_handle, CURLOPT_CUSTOMREQUEST, "PUT");

	// 执行数据请求
	curl_easy_perform(easy_handle); 

	// 释放资源
	curl_easy_cleanup(easy_handle);
	curl_global_cleanup();
	return 0;
}

int main(void)
{
	etcd_set("/put", "2l", NULL);
	return 0;
}
监控一个值的变化。这个在上面获取一个key的值的基础上来实现,只需要改变其url,其它不做改动即可。

#include 
#include 
#include 

using namespace std;
using namespace Json;

size_t process_data(void *buffer, size_t size, size_t nmemb, void *user_p)
{
	/* 获取json的value */
	Value root;
	Value node;
	Reader reader;
	FastWriter writer;
	string json = (char*)buffer;

	if(!reader.parse(json, root))
	{
		cout << "parse json error" << endl;	
		return 0;
	}
	string nodeString = writer.write(root["node"]);
	if(!reader.parse(nodeString, node))
	{
		cout << "parse json error" << endl;	
		return 0;
	}

	cout << node["value"] << endl;

	return 0;
}

int main(int argc, char **argv)
{
	//初始化libcurl
	CURLcode return_code;
	return_code = curl_global_init(CURL_GLOBAL_SSL);
	if (CURLE_OK != return_code)
	{
		cerr << "init libcurl failed." << endl;
		return -1;
	}

	// 获取easy handle
	CURL *easy_handle = curl_easy_init();
	if (NULL == easy_handle)
	{
		cerr << "get a easy handle failed." << endl;
		curl_global_cleanup(); 

		return -1;
	}

	char * buff_p = NULL;

	// 设置easy handle属性
	curl_easy_setopt(easy_handle, CURLOPT_URL, "http://127.0.0.1/v2/keys/message1?wait=true");
	curl_easy_setopt(easy_handle, CURLOPT_PORT, 2379);
	curl_easy_setopt(easy_handle, CURLOPT_WRITEFUNCTION, &process_data);
	curl_easy_setopt(easy_handle, CURLOPT_WRITEDATA, buff_p);

	// 执行数据请求
	curl_easy_perform(easy_handle);	

	// 释放资源

	curl_easy_cleanup(easy_handle);
	curl_global_cleanup();

	return 0;
}
以上是我实现的简单的etcd接口,读者可以通过本博客或者根据libcurl提供的http RESTful API来实现etcd支持的更多的接口。

另外,基于etcd的高级语言接口在GitHub上已有相当多的开源工程,读者感兴趣可以到这里去下载查看——>高级语言封装的etcd接口。

7、总结

因为工作需要研究了一段时间,特记录在此,希望对大家有所帮助。


你可能感兴趣的:(分布式,coreOs,Restful,API,数据库,etcd)