日期 | 做者 | 版本 | 備註 |
---|---|---|---|
2020-12-7 | dingbin | v1.0 | |
Paeony是做者開源的用C++語言實現成熟的etcd v3版本客戶端API庫。Github地址是:https://github.com/apollo008/paeony 。它達到穩定可靠的企業級應用效果。它在原始單純etcdv3-cpp-api基礎上,封裝了不少面向負載均衡和鏈接重試的特性。它具備如下優點:c++
項目的src/paeony/paeony/core/examples目錄給出了經常使用的etcdv3 client使用示例。git
具體來講,demo使用入口見 src/paeony/paeony/core/examples/hello_paeony.cpp代碼示例:github
#include "paeony/core/examples/paeony_demo.h" PAEONY_USE_NAMESPACE; STD_USE_NAMESPACE; int main(int argc, char** argv) { TLOG_CONFIG("logger.conf"); TLOG_DECLARE_AND_SETUP_LOGGER(HELLOPAEONY, MAIN); EtcdDemoConnInfo info; PaeonyDemo demo(info); demo.DemoEtcdv3ClientGetPut(); demo.DemoEtcdv3Lease(); demo.DemoEtcdv3Watch(); demo.DemoEtcdv3Transaction(); TLOG_LOG_FLUSH(); TLOG_LOG_SHUTDOWN(); return 0; }
具體的4種主要的Etcdv3 client 接口Demo參考文件:src/paeony/paeony/core/examples/paeony_demo.cppvim
/** *@brief Method to demo etcdv3 client and Get/Put method *@author dingbinthu@163.com *@date 2020/12/7, 上午1:14 */ void PaeonyDemo::DemoEtcdv3ClientGetPut() { Etcdv3ClientPtr client = std::make_shared<Etcdv3Client>(m_info.m_certificateContents, m_info.m_user, m_info.m_passwd, m_info.m_allEndpoints, time(NULL), m_info.m_etctTestKey); try { while (true) { paeony::EtcdRangeResponse getResponse = client->Get(m_info.m_etctTestKey, true, false, false, 0, 3, 2, 50); if (getResponse.IsOk()) { TLOG_LOG(INFO,"Successfully get, value=[%s].", (getResponse.m_rpcResp.kvs_size()>0?getResponse.m_rpcResp.kvs(0).value().c_str(): "") ); } else { TLOG_LOG(ERROR,"Failed to get,error_code is:[%d],operation failed,detail message:[%s]", getResponse.GetErrorCode(), getResponse.GetErrorMsg().c_str() ); } EtcdPutResponse putResponse = client->Put(m_info.m_etctTestKey + "/123","hello,paeony!!!", 0, false, 5, 2, 50); if (putResponse.IsOk()) { TLOG_LOG(INFO,"Successfully put key:[%s]", m_info.m_etctTestKey.c_str()); } else { TLOG_LOG(ERROR,"Failed to put, error_code is:[%d],operation failed,detail message:[%s]", putResponse.GetErrorCode(),putResponse.GetErrorMsg().c_str() ); } sleep(3); } } catch (std::exception const & ex) { TLOG_LOG(ERROR,"Communication problem,details:[%s]", ex.what()); } }
/** *@brief Method used to demo Etcdv3 Watch interface *@author dingbinthu@163.com *@date 2020/12/7, 上午1:15 */ void PaeonyDemo::DemoEtcdv3Watch() { Etcdv3ClientPtr client = std::make_shared<Etcdv3Client>(m_info.m_certificateContents, m_info.m_user, m_info.m_passwd, m_info.m_allEndpoints, time(NULL), m_info.m_etctTestKey); string key = "/paeony/TestWatch"; client ->Put(key,"0"); function<void(EtcdWatchResponse)> watchCallback = [](EtcdWatchResponse response) { PaeonyDemo::_logger->Log(tulip::TLOG_LEVELNO_ERROR,__FILE__,__LINE__,__FUNCTION__, "got watch response, with response's events size:[%d] and if for the firstResponseCallback:[%s]", response.m_rpcResp.events_size(), (response.m_bFirstResponse ? "true":"false")); }; vector<WatchCreateRequest::FilterType> filtersVec; EtcdWatchWorkerPtr watchWorker = make_shared<EtcdWatchWorker>(client,key,true,true,true,filtersVec, watchCallback,100,30,4 * 1024 * 1024); watchWorker->Start(); while(!watchWorker->IsStarted()){ TLOG_LOG(INFO, "wait EtcdWatchWorker start..."); usleep(10); } TLOG_LOG(INFO,"EtcdWatchWorker started......"); sleep(180); TLOG_LOG(INFO, "=======================now terminate EtcdWatchWorker..."); watchWorker->Terminate(); TLOG_LOG(INFO,"EtcdWatchWorker terminate, wait done"); watchWorker->Join(); TLOG_LOG(INFO,"EtcdWatchWorker done."); int remainTimeSecond = 10; int t = 0; while (remainTimeSecond - t * 2 > 0) { TLOG_LOG(INFO,"Wait 10 seconds to exit Function:[%s], remain [%d] second..", __FUNCTION__ , remainTimeSecond - t * 2); ++t; sleep(2); } TLOG_LOG(INFO,"now exit function:[%s]", __FUNCTION__ ); }
/** *@brief Method used to demo Etcdv3 Lease interface *@author dingbinthu@163.com *@date 2020/12/7, 上午1:15 */ void PaeonyDemo::DemoEtcdv3Lease() { Etcdv3ClientPtr client = std::make_shared<Etcdv3Client>(m_info.m_certificateContents, m_info.m_user, m_info.m_passwd, m_info.m_allEndpoints, time(NULL), m_info.m_etctTestKey); int64_t ttl = 60; EtcdLeaseGrantResponse lgr; do { lgr = client ->LeaseGrant(ttl,0,3,2,50); if (lgr.IsOk()) { break; } else { TLOG_LOG(ERROR,"Lease grant errCode:[%d],errMsg:[%s]", lgr.GetErrorCode(),lgr.GetErrorMsg().c_str()); } sleep(1); } while(true); client ->Put("/paeony/TestLeaseKeepAlive","0",lgr.m_rpcResp.id()); function<void(LeaseGrantResponse)> reLeaseGrantCallback = [client](LeaseGrantResponse response) { time_t tm = time(NULL); ostringstream oss; oss <<tm; client ->Put("/paeony/TestLeaseKeepAlive",oss.str(),response.id()); PaeonyDemo::_logger->Log(tulip::TLOG_LEVELNO_INFO,__FILE__,__LINE__,__FUNCTION__, "got reLeaseGrant response, with id:[%ld] and ttl:[%ld]", response.id(),response.ttl()); }; EtcdLeaseKeepAliveWorkerPtr leaseKeepAliveWorker = make_shared<EtcdLeaseKeepAliveWorker> (client, lgr.m_rpcResp.id(),lgr.m_rpcResp.ttl(),reLeaseGrantCallback,100,ttl + 2,2 * 1024 * 1024); leaseKeepAliveWorker->Start(); while(!leaseKeepAliveWorker->IsStarted()){ TLOG_LOG(INFO,"wait LeaseKeepAliveWorker start"); usleep(10); } TLOG_LOG(INFO,"LeaseKeepAliveWorker started"); sleep(60 * 60); TLOG_LOG(INFO,"=======================now terminate LeaseKeepAliveWorker..."); leaseKeepAliveWorker->Terminate(); TLOG_LOG(INFO,"LeaseKeepAliveWorker terminate, wait done"); leaseKeepAliveWorker->Join(); TLOG_LOG(INFO,"LeaseKeepAliveWorker done."); int remainTimeSecond = 3 * 60; int t = 0; while (remainTimeSecond - t * 5 > 0) { TLOG_LOG(INFO,"Wait 3 minute to exit Function:[%s], remain [%d] second...", __FUNCTION__,remainTimeSecond - t * 5); ++t; sleep(5); } TLOG_LOG(INFO,"now exit function:[%s]",__FUNCTION__); }
/** *@brief Method used to demo Etcdv3 transaction interface *@author dingbinthu@163.com *@date 2020/12/7, 上午1:15 */ void PaeonyDemo::DemoEtcdv3Transaction() { string key = "/paeony/TestTxn"; Compare compare; compare.set_result(etcdserverpb::Compare::CompareResult::Compare_CompareResult_EQUAL); compare.set_target(etcdserverpb::Compare::CompareTarget::Compare_CompareTarget_VERSION); compare.set_key(key); compare.set_version(0); TransactionRequestPtrVec successTxnRequestsVec; TransactionRequestPtr put1 = make_shared<TransactionPutRequest>(Etcdv3Client::s_ConstructPutRequest(key,"1")); successTxnRequestsVec.push_back(put1); TransactionRequestPtr range1 = make_shared<TransactionRangeRequest>(Etcdv3Client::s_ConstructRangeRequest(key)); successTxnRequestsVec.push_back(range1); TransactionRequestPtr put2 = make_shared<TransactionPutRequest>(Etcdv3Client::s_ConstructPutRequest(key + "1","2")); successTxnRequestsVec.push_back(put2); TransactionRequestPtr range2 = make_shared<TransactionRangeRequest>(Etcdv3Client::s_ConstructRangeRequest(key + "1")); successTxnRequestsVec.push_back(range2); TransactionRequestPtrVec failureTxnRequestsVec; TransactionRequestPtr put1_ = make_shared<TransactionPutRequest>(Etcdv3Client::s_ConstructPutRequest(key,"1_")); failureTxnRequestsVec.push_back(put1_); TransactionRequestPtr range1_ = make_shared<TransactionRangeRequest>(Etcdv3Client::s_ConstructRangeRequest(key)); failureTxnRequestsVec.push_back(range1_); TransactionRequestPtr put2_ = make_shared<TransactionPutRequest>(Etcdv3Client::s_ConstructPutRequest(key+"2","2_")); failureTxnRequestsVec.push_back(put2_); TransactionRequestPtr range2_ = make_shared<TransactionRangeRequest>(Etcdv3Client::s_ConstructRangeRequest(key +"2")); failureTxnRequestsVec.push_back(range2_); Etcdv3ClientPtr client = std::make_shared<Etcdv3Client>(m_info.m_certificateContents, m_info.m_user, m_info.m_passwd, m_info.m_allEndpoints, time(NULL), m_info.m_etctTestKey); EtcdTxnResponse txnResponse = client->Transaction(compare,successTxnRequestsVec,failureTxnRequestsVec,8,3,50); if (txnResponse.IsOk()) { TLOG_LOG(INFO, "Succeed in executing transaction operation whose txnResponse's succeeded is:[%s]", (txnResponse.m_rpcResp.succeeded() ? "true":"false")); } else { TLOG_LOG(ERROR,"Failed to execute transaction operation with errorCode:[%d] and errorMsg:[%s]", txnResponse.GetErrorCode(), txnResponse.GetErrorMsg().c_str() ); } }
Tulip-log的配置文件示例參考:src/paeony/paeony/core/examples/logger.confapi
目前支持類Unix環境下編譯安裝,Paeony項目依賴的第三方庫有:網絡
編譯安裝paeony以前先要安裝以上4個依賴庫。多線程
具體編譯和安裝方法以下:負載均衡
git clone https://github.com/apollo008/paeony.git paeony.git cd paeony.git vim CMakeLists.txt 修改第8行: 原來是:set(PAEONY_DEPEND_PREFIX_DIR /path/to/install/share) 將/path/to/install/share 替換爲 安裝上面4個目標依賴庫的路徑,好比${HOME}/local,注意確保該路徑有寫權限。 修改以後後續不要再改變該路徑。 mkdir build-dir cd build-dir #安裝依賴 cmake -DENABLE_BUILD_SHARE=ON ../src 執行完以上這一步便可完成依賴庫。注意不須要再執行make 和make install了。 接下來安裝paeony #安裝paeony 首先保持根目錄下CMakeLists.txt第8行修改的內容再也不改變; cd build-dir rm -rf * cmake -DCMAKE_INSTALL_PREFIX=/path/to/install ../src make -j10 make install
執行完以上,便可在/path/to/install目錄下生成bin、lib、include3個目錄。其中lib目錄是libpaeony.so; bin目錄下是hello_paeony可執行程序; include目錄是paeony庫的頭文件。ui
注意:運行demo程序hello_paeony時,須要在當前目錄放置tulip-log的日誌配置文件logger.conf ,同時該目錄下要已經建立好logs 目錄供輸出文件名滾動的日誌文件。線程
相關細節或其它未盡事宜,可聯繫 dingbinthu@163.com 探討諮詢。