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"
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIiclRnblN0LclHdpZXYyd2LcBzNvwVZ2x2bzNXak9CX90TQNNkRrFlQKBTSvwFbslmZvwFMwQzLcVmepNHdu9mZvwFVywUNMZTY18CX052bm9CX90TUOdXWE5UeRRUT4FEVkZXUYpVd1kmYr50MZV3YyI2cKJDT29GRjBjUIF2LcRHelR3LcJzLctmch1mclRXY39jM3AjNwAjM2EDNyMDM1EDMy8CX0Vmbu4GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.jpg)
*擷取一個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 <curl/curl.h>
#include <jsoncpp/json/json.h>
#include <iostream>
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 <curl/curl.h>
#include <stdio.h>
#include <string.h>
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 <curl/curl.h>
#include <jsoncpp/json/json.h>
#include <iostream>
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、總結
因為工作需要研究了一段時間,特記錄在此,希望對大家有所幫助。