組件日志——etcd

目錄

?一、簡介

二、安裝【Ubuntu】

安裝etcd

安裝C++API

三、寫一個示例

3.0寫一個示例代碼

3.1獲取一個etcd服務

3.2獲取租約(寫端操作)

3.3使用租約(寫端操作)

3.4銷毀租約(寫端操作)

3.5獲取etcd服務中的服務列表(讀端操作)

3.6監聽狀態變化(讀端操作)


?一、簡介

? ? ? ? Etcd是一個golang編寫的分布式、高可用的一致性鍵值存儲系統,用于配置共享和服務發現等。它使用Raft一致性算法來保持集群數據的一致性,且客戶端通過長連接watch功能,能夠及時收到數據變化通知。

? ? ? ? 這樣的簡介比較干澀也不太好理解,我們換個說法,如果你開發過集群式的網絡服務,你應該知道,通常情況下,你需要指定一臺網關主機轉發來自用戶的請求,這些請求將被轉發到對應的應用服務器上,然后進行業務處理。但是這里就有一個問題,當我們上線一個主機、或者下線一個主機的時候網關機器是很難進行感知的(下線相對來說好感知,可以發送網絡包進行探測),但是一個新的服務主機上線就是個麻煩事,我們怎么才能通知這個服務上線了?簡單點來說,這個時候就需要我們有一臺管理主機,用來管理服務的上下線通知,當有新服務上下線時,就立即通知網關主機。

? ? ? ? 其實你也可以將etcd看作是一個鍵值存儲的數據庫,服務主機上線時,就將我們主機的信息放入到數據庫中,當網關主機需要獲取服務信息時,就需要對這個數據進行讀操作,這個時候不就可以讓網關機感知服務的上下線了嗎?當然etcd也會主動的將變化信息發送給所有監聽變化的主機上。

圖1? ? ? ? 關于etcd的作用解釋

二、安裝【Ubuntu】

安裝etcd

安裝etcd

sudo apt-get install etcd

啟動etcd

sudo systemctl start etcd

設置開機自啟

sudo systemctl enable etcd

添加使用的etcd版本到環境變量

export ETCDCTL_API=3

重新加載環境變量

source /etc/profile

測試向etcd中寫入一個鍵值對

etcdctl put mykey "test"

獲取一下

etcdctl get mykey
圖2? ? ? ? 測試etcd的存入/取出功能

安裝C++API

安裝依賴

sudo apt-get install libboost-all-dev 
libssl-dev sudo apt-get install libprotobuf-dev protobuf-compiler-grpc 
sudo apt-get install libgrpc-dev libgrpc++-dev 
sudo apt-get install libcpprest-dev

獲取框架

git clone https://github.com/etcd-cpp-apiv3/etcd-cpp-apiv3.git 

進入拉取后的目錄

cd etcd-cpp-apiv3

創建并進入構建目錄

mkdir build && cd build

?cmake

cmake .. -DCMAKE_INSTALL_PREFIX=/usr

構建并安裝

make -j$(nproc) && sudo make install

三、寫一個示例

3.0寫一個示例代碼

//write.cpp
#include <etcd/Client.hpp>
#include <etcd/Response.hpp>
#include <etcd/KeepAlive.hpp>
#include <thread>
#include <chrono>
#include <string>void RegistryService(etcd::Client& etcd,const std::string& serviceKey,const std::string& serviceValue,size_t liveTime)
{//獲取resphone對象auto res_lease =  etcd.leasekeepalive(liveTime).get();//獲取租約IDint64_t leaseid =  res_lease->Lease();//將鍵值與租約綁定etcd.put(serviceKey,serviceValue,leaseid);//休眠該執行流20sstd::this_thread::sleep_for(std::chrono::seconds(20));std::cout<<"程序已退出"<<std::endl;
}int main()
{try{    etcd::Client etcd("http://127.0.0.1:2379");size_t time=20; //單位:秒RegistryService(etcd,"/test/test1","127.0.0.1:8888",time);RegistryService(etcd,"/test/test2","127.0.0.1:8889",time);RegistryService(etcd,"/test/test3","127.0.0.1:8890",time);}catch(const std::exception& e){std::cerr << e.what() << '\n';}return 0;
}
//reader.cpp#include <etcd/Client.hpp>
#include <etcd/Watcher.hpp>
#include <etcd/Value.hpp>
void WatchListen(etcd::Response res)
{for(auto e:res.events()){if(e.event_type()==etcd::Event::EventType::PUT){std::cout<<"鍵值發生修改"<<std::endl;std::cout<<"before: "<<e.prev_kv().key()<<":"<<e.prev_kv().as_string()<<std::endl;std::cout<<"now: "<<e.kv().key()<<":"<<e.kv().as_string()<<std::endl;}else if(e.event_type()==etcd::Event::EventType::DELETE_){std::cout<<"數據發生刪除"<<std::endl;std::cout<<"now: "<<e.kv().key()<<":"<<e.kv().as_string()<<std::endl;}}
}int main()
{etcd::Client etcd("http://127.0.0.1:2379");etcd::Response res = etcd.ls("/test").get();for(auto e:res.events()){std::cout<<"當前值"<<e.kv().key()<<e.kv().as_string()<<std::endl;}etcd::Watcher watcher(etcd,"/test",WatchListen,true);watcher.Wait();return 0;
}
//makefile
all:reader writer
reader:reader.cppg++ -o $@ $^ -letcd-cpp-api -lcpprest -std=c++17
writer:writer.cppg++ -o $@ $^ -letcd-cpp-api -lcpprest -std=c++17

3.1獲取一個etcd服務

? ? ? ? 無論是想要注冊的服務主機,還是想要獲取服務的網關機,都需要創建一個etcd客戶端類,這一點應該不難理解,因為注冊的服務器需要將服務主機的信息交給etcd服務器,讓其進行通知其它網關機;同理,網關機如果想要獲取etcd中存儲的信息,也就必須要連接上etcd才可以獲取。

? ? ? ? 在3.0的示例代碼中,獲取etcd服務的語句是:

 etcd::Client etcd("http://127.0.0.1:2379");

3.2獲取租約(寫端操作)

? ? ? ? 為了方便介紹,我們暫且把服務提供主機叫做“寫端”,需要獲取服務主機信息的網關機叫做“讀端”,在獲取王etcd服務之后,讀寫端的操作就出現了差異,寫端肯定是要向etcd服務器中寫入數據,而讀端肯定是要從etcd服務中讀取數據。

? ? ? ? 如果我們向向etcd服務中寫入數據,我們必須要申請一個租約,租約其實就是一個過期時間,即你寫入的這個數據,etcd服務需要給你保留多久,那么現在我們先來看看如何獲取一個租約,根據官方文檔中所提到的有兩個方法可以獲取租約一個是KeepAlive類中的Lease方法,一個是通過leasegrant方法獲取;前者獲取后其會定期自動重置租約時長,后者則不會,所以如果你問我推薦使用哪種方式來獲取租約,我個人就更傾向于前者。

auto res_lease =  etcd.leasekeepalive(liveTime).get();
//獲取租約ID
int64_t leaseid =  res_lease->Lease();

? ? ? ? 需要說明的是,為什么etcd要先get獲取一個對象而后在使用這個對象獲取租約ID?

????????這是因為etcd中的大部分操作都是支持異步的,租約的獲取也不例外,而是用get方法則是在阻塞在原地等待資源就緒,也就是我們常說的同步獲取資源,而如果想在這期間去完成其它的工作,你可以不立即使用get方法,而是將get返回的結果進行托管(設置一個回調函數),當資源就緒的時候就會執行你設置好的回調函數,那借此機會,我們看看如何異步獲取一個租約ID。

int64_t lease_id1=-1;
pplx::task<std::shared_ptr<etcd::KeepAlive>> res = etcd.leasekeepalive(liveTime);
//這里的回調函數,是一個lamada表達式
res.then([&lease_id1](std::shared_ptr<etcd::KeepAlive> res){ lease_id1 = res->Lease();}
).wait();
//模擬去做其它的事情  
std::this_thread::sleep_for(std::chrono::seconds(2));
std::cout<<lease_id1<<std::endl;

? ? ? ? 在這個代碼中我們使用執行流休眠來模擬申請資源期間完成其它工作,此外需要注意的是,如果你將資源設置為異步獲取,你必須要保證主執行流不會執行的很快以至于資源還沒申請成功需要被使用,所以建議在使用異步獲取的資源之前最好先做一個資源獲取成功的校驗。

3.3使用租約(寫端操作)

? ? ? ? 使用租約就比較簡單了,我們只需要指定我們需要存入的服務名稱、主機信息和我們的租約ID就可以了,其中serviceKey指的時我們服務名稱,serviceValue指的是我們的主機信息。leaseid就是之前申請的租約ID,這個ID對應著一個租約,如果租約過期了,etcd就會幫我們自動刪除保存在etcd服務器上的服務信息。

etcd.put(serviceKey,serviceValue,leaseid);

? ? ? ? 需要說明的是serviceKey的最好是像文件目錄格式一樣的結構,這一點一會我們讀取etcd服務器內容時,我們在說明。?

圖3? ? ? ? etcd服務管理規范

3.4銷毀租約(寫端操作)

? ? ? ? 其實我寫的代碼,是錯的,錯就錯在沒有銷毀租約,如果不銷毀租約就會發生這樣一種情況,就是當你程序退出了,但是etcd服務器中的租約沒過期,也就繼續保存著你的服務信息,這個時候etcd默認你的主機還在,但是如果此時有其它用戶請求到來且網關主機還把這個請求交給了這臺已經退出的主機那就會導致請求丟失。

圖4? ? ? ? 租約未即時釋放

? ? ? ? 在你明確某個租約退出時,你可以使用leaserevoke來釋放租約,來避免租約未被即時釋放放的問題。

etcd.leaserevoke(leaseid);

3.5獲取etcd服務中的服務列表(讀端操作)

? ? ? ? 讀端操作相對簡單的多,因為即便不是我們的簡單示例,在實際生產中,請求的處理通常都是交給應用服務主機來進行處理的,而讀端更像是一個“傳話人”,我們使用Client類中的ls方法就可以獲取服務的整個列表,還記得我畫的圖3嗎,這里獲取的不是目錄而是所有的節點,即圖3中的主機A、主機B、……,目錄的作用起到的是一個指示服務類型的作用。當然,我這里只畫了兩層結構,實際上可能比兩層結構更多。

etcd::Response res = etcd.ls("/test").get();for(auto e:res.events())
{std::cout<<"當前值"<<e.kv().key()<<e.kv().as_string()<<std::endl;
}

3.6監聽狀態變化(讀端操作)

? ? ? ? 這個功能就是,在最開始提到的,etcd的一個重要功能,它可以通知其它主機,某一個服務主機的上線,要使用這個功能需要我們使用Watcher類,在這個類中,我們填入etcd主機信息、監聽目錄、狀態變化時需要執行的回調函數、最后一個參數要設置為true表示監聽整個目錄還是監聽單個主機,監聽整個目錄則將此值置為true,否則置為false。

圖5? ? ? ? 監聽狀態變化(部分)

? ? ? ? 需要一提的是,使用watcher監聽狀態變化是需要阻塞的,這是因為watcher是一個異步操作,也就是說如果你不阻塞住主執行流而且還讓其退出,那么就會造成watcher執行流一并退出而導致無法監聽變化。

四、結語? ? ? ??

????????本片文章只講解了一些基本操作,其實還有一些問題尚且沒有明晰:

  • etcd是一個集群服務,當有多個etcd服務器是如何保證一致性。
  • etcd是如何保證并發安全的。
  • etcd容災都做了哪些工作。

? ? ? ? 這些問題就不在本文中闡述了,也許過幾天我會在出一個補檔內容了,來介紹一下這部分內容,說句心里話,博主在寫這篇文章的時候也是在學習etcd,初學者學習內容難免紕漏,如果屏幕前的你發現了問題,還請多多指教。對于哪些沒看懂或者想要了解更多的小伙伴可以去看看源碼或者官方的示例代碼,這會對你理解etcd有很大的幫助。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/73232.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/73232.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/73232.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

python網絡爬蟲開發實戰之網頁數據的解析提取

目錄 1 XPath的使用 1.1 XPath概覽 1.2 XPath常用規則 1.3 準備工作 1.4 實例引入 1.5 所有節點 1.6 節點 1.7 父節點 1.8 屬性匹配 1.9 文本獲取 1.10 屬性獲取 1.11 屬性多值匹配 1.12 多屬性匹配 1.13 按序選擇 1.14 節點軸選擇 2 Beautiful Soup 2.1 簡介…

理解操作系統(一)馮諾依曼結構和什么是操作系統

認識馮諾依曼系統 操作系統概念與定位 深?理解進程概念&#xff0c;了解PCB 學習進程狀態&#xff0c;學會創建進程&#xff0c;掌握僵?進程和孤?進程&#xff0c;及其形成原因和危害 1. 馮諾依曼體系結構 我們常?的計算機&#xff0c;如筆記本。我們不常?的計算機&am…

Tomcat常見漏洞攻略

一、CVE-2017-12615 漏洞原理&#xff1a;當在Tomcat的conf&#xff08;配置?錄下&#xff09;/web.xml配置?件中添加readonly設置為false時&#xff0c;將導致該漏洞產 生&#xff0c;&#xff08;需要允許put請求&#xff09; , 攻擊者可以利?PUT方法通過精心構造的數據包…

快速求出質數

要快速判斷一個數是否為質數&#xff0c;可以采用以下優化后的試除法&#xff0c;結合數學規律大幅減少計算量&#xff1a; 步驟說明 處理特殊情況&#xff1a; 若 ( n \leq 1 )&#xff0c;不是質數。若 ( n 2 ) 或 ( n 3 )&#xff0c;是質數。若 ( n ) 能被 2 或 3 整除&…

Linux上位機開發實戰(camera視頻讀取)

【 聲明&#xff1a;版權所有&#xff0c;歡迎轉載&#xff0c;請勿用于商業用途。 聯系信箱&#xff1a;feixiaoxing 163.com】 關于linux camera&#xff0c;一般都是認為是mipi camera&#xff0c;或者是usb camera。當然不管是哪一種&#xff0c;底層的邏輯都是v4l2&#x…

高性能緩存:使用 Redis 和本地內存緩存實戰示例

在現代高并發系統中&#xff0c;緩存技術是提升性能和降低數據庫壓力的關鍵手段。無論是分布式系統中的Redis緩存&#xff0c;還是本地高效的本地內存緩存&#xff0c;合理使用都能讓你的應用如虎添翼。今天&#xff0c;我們將基于go-dev-frame/sponge/pkg/cache庫的代碼示例&a…

Python實現deepseek接口的調用

簡介&#xff1a;DeepSeek 是一個強大的大語言模型&#xff0c;提供 API 接口供開發者調用。在 Python 中&#xff0c;可以使用 requests 或 httpx 庫向 DeepSeek API 發送請求&#xff0c;實現文本生成、代碼補全&#xff0c;知識問答等功能。本文將介紹如何在 Python 中調用 …

山東大學數據結構課程設計

題目&#xff1a;全國交通咨詢模擬系統 問題描述 處于不同目的的旅客對交通工具有不同的要求。例如&#xff0c;因公出差的旅客希望在旅途中的時間盡可能地短&#xff0c;出門旅游的旅客則期望旅費盡可能省&#xff0c;而老年旅客則要求中轉次數最少。編織一個全國城市間的交…

深入理解倒排索引原理:從 BitSet 到實際應用

倒排索引是一種極為重要的數據結構&#xff0c;它能夠高效地支持大規模數據的快速查詢&#xff0c;本文將深入探討倒排索引的原理&#xff0c;借助 BitSet 這種數據結構來理解其實現機制&#xff0c;并通過具體的JSF請求條件示例來展示其在實際應用中的運算過程。 BitSet&#…

Unity網絡開發快速回顧

知識點來源&#xff1a;總結人間自有韜哥在&#xff0c; 唐老獅&#xff0c;豆包 目錄 1.網絡通信-通信必備知識-IP地址和端口類2.網絡通信中序列化和反序列化2進制數據3.Socket類4.TCP同步服務端和客戶端基礎實現4.1.服務端基本實現4.2.客戶端實現&#xff1a; 5.區分消息類型…

內網滲透技術 Docker逃逸技術(提權)研究 CSMSF

目錄 如何通過上傳的webshell判斷當前環境是否是物理環境還是Docker環境 方法一&#xff1a;檢查文件系統 方法二&#xff1a;查看進程 方法三&#xff1a;檢查網絡配置 方法四&#xff1a;檢查環境變量 方法五&#xff1a;檢查掛載點 總結 2. 如果是Docker環境&#x…

動態規劃:從暴力遞歸到多維優化的算法進化論(C++實現)

動態規劃&#xff1a;從暴力遞歸到多維優化的算法進化論 一、動態規劃的本質突破 動態規劃&#xff08;Dynamic Programming&#xff09;不是簡單的遞歸優化&#xff0c;而是計算思維范式的革命性轉變。其核心價值在于通過狀態定義和決策過程形式化&#xff0c;將指數復雜度問…

數據結構與算法-數據結構-樹狀數組

概念 樹狀數組&#xff0c;也叫二叉索引樹&#xff08;Binary Indexed Tree&#xff0c;BIT&#xff09;&#xff0c;它是用數組來模擬樹形結構。樹狀數組的每個節點存儲的是數組中某一段的和&#xff08;或其他可合并的信息&#xff09;&#xff0c;通過巧妙的索引方式和樹形…

AI比人腦更強,因為被植入思維模型【19】三腦理論思維模型

定義 三腦理論思維模型是由美國神經科學家保羅麥克萊恩&#xff08;Paul MacLean&#xff09;提出的&#xff0c;該理論認為人類的大腦由三個不同但又相互關聯的部分組成&#xff0c;分別是爬蟲腦&#xff08;Reptilian Brain&#xff09;、邊緣腦&#xff08;Limbic Brain&am…

使用 patch-package 優雅地修改第三方依賴庫

在前端開發中&#xff0c;有時我們需要對第三方依賴庫進行修改以滿足項目需求。然而&#xff0c;直接修改 node_modules 中的文件并不是一個好方法&#xff0c;因為每次重新安裝依賴時這些修改都會丟失。patch-package 是一個優秀的工具&#xff0c;可以幫助我們優雅地管理這些…

馬科維茨均值—方差理論推導過程

下面給出一個詳細的、符號嚴謹、公式連貫的馬科維茨均值—方差理論推導過程&#xff0c;假設你輸入了 nnn 列股票的歷史收盤價數據。我們從數據符號的定義開始&#xff0c;逐步構建所有公式&#xff0c;并詳細解釋每個符號的意義。

僅靠prompt,Agent難以自救

Alexander的觀點很明確&#xff1a;未來 AI 智能體的發展方向還得是模型本身&#xff0c;而不是工作流&#xff08;Work Flow&#xff09;。還拿目前很火的 Manus 作為案例&#xff1a;他認為像 Manus 這樣基于「預先編排好的提示詞與工具路徑」構成的工作流智能體&#xff0c;…

【css酷炫效果】純CSS實現懸浮彈性按鈕

【css酷炫效果】純CSS實現懸浮彈性按鈕 緣創作背景html結構css樣式完整代碼效果圖 想直接拿走的老板&#xff0c;鏈接放在這里&#xff1a;https://download.csdn.net/download/u011561335/90492020 緣 創作隨緣&#xff0c;不定時更新。 創作背景 剛看到csdn出活動了&…

決策樹基礎

決策樹 定義 從根節點開始&#xff0c;也就是擁有全部的數據&#xff0c;找一個維度對根節點開始劃分&#xff0c; 劃分后希望數據整體的信息熵是最小的&#xff0c; 針對劃分出來的兩個節點&#xff0c;我們繼續重復剛才的劃分方式尋找信息熵最小的維度和閾值。 遞歸這個…

動態查找表

1.問題分析&#xff1a; 動態查找表是一種可以動態地插入、刪除和查找元素的數據結構。它是基于二叉搜索樹實現的&#xff0c;具有快速的查找和插入操作。 以下是一些關于動態查找表的問題分析&#xff1a; 1. 插入操作&#xff1a;在動態查找表中插入一個元素時&#xff0c…