[CoreOS 轉載] CoreOS實踐指南(五):分佈式數據存儲Etcd(上)

轉載:http://www.csdn.net/article/2015-01-22/2823659node

摘要:在「漫步雲端:CoreOS實踐指南」系列的前幾篇,分別介紹瞭如何架設CoreOS集羣,系統服務管家Systemd和集羣的指揮所Fleet,本篇將介紹CoreOS生態中鏈接各個節點通訊和支撐集羣服務協同運做的模塊Etcd。git

注:本文首發於CSDN,轉載請標明出處。github

【編者按】做爲一個操做系統,CoreOS 採用了高度精簡的系統內核及外圍定製,將許多本來須要複雜人工操做或者第三方軟件支持的功能在操做系統級別進行了實現,同時剔除了其餘對於服務器系統非核心的軟件,好比GUI和包管理器。CSDN特邀ThoughtWorks的軟件工程師林帆帶來了「漫步雲端:CoreOS實踐指南」系列文章,帶你們瞭解CoreOS的精華和推薦的實踐方法。本文爲基礎第五篇:分佈式數據存儲Etcd。Etcd是CoreOS生態系統中處於鏈接各個節點通訊和支撐集羣服務協同運做的核心地位的模塊,這篇文章將主要從系統運維工做者的角度介紹Etcd的操做和API的使用。算法


 

做者簡介:數據庫

林帆,生在80後尾巴的IT攻城獅,ThoughtWorks成都辦公室CloudOps小組成員,平時喜歡在業餘時間研究DevOps相關的應用,目前在備考AWS認證和推廣Docker相關技術。服務器

 


 

分佈式數據的存儲一直是解決集羣服務消息同步和協調操做的核心關注點。在這個系列的上一篇,介紹了用於集羣管理的Fleet服務,而Fleet的功能的實現除了依賴於Systemd服務的DBus擴展,其分佈式控制部分很大程度上得益於CoreOS提供的可靠且高效的分佈式數據服務Etcd。事實上,Etcd是CoreOS生態系統中處於鏈接各個節點通訊和支撐集羣服務協同運做的核心地位的模塊,這篇文章將主要從系統運維工做者的角度介紹Etcd的操做和API的使用。框架

什麼是分佈式數據存儲呢?從結果的角度上看,就是將數據分散存儲在多臺獨立的設備上,從而提升數據的可靠性或讀寫性能的方法。從實現的角度上看,目前主流的NoSQL數據庫,例如MongoDB、FoundationDB等都可以很方便地實現分佈式存儲。而Etcd本質上與一個NoSQL的數據庫系統也有幾分神似,但更準確的說法說是一個高可用的鍵值存儲系統。與通常的NoSQL數據庫不一樣,Etcd在設計的初衷主要用因而共享配置和服務發現,它的靈感來自於ZooKeeper和Doozer。關於這三者以及其餘同類的服務發現框架的比較能夠參看這篇文章,簡單來講,Etcd對TTL的支持和HTTP Restful API是其比較大的亮點。與語言和平臺無關的Restful API使得基於它的二次開發變得更加方便,而且可以對運行在應用容器中的程序提供(好比Docker)提供友好的支持。運維

在數據一致性方面,Etcd經過Raft一致性算法處理日誌複製以保證強一致性。這裏不打算對Raft算法進行深刻的探討,關於Raft算法的具體原理能夠參看桂陽的這篇文章curl

Etcd的發展

 

Etcd是CoreOS的核心服務模塊中起步最先的,它的第一行代碼提交於2013年6月,早於Fleet(2013年10月)以及其餘CoreOS模塊,它也是許多其餘服務模塊的根基。分佈式

值得一提的是,Etcd的最主要貢獻者是兩位華人開發者秦毅成和李響。最初的Etcd使用了一套獨立的GoRaft庫,在2014年中旬開始,Etcd作了一次大規模的代碼重構,撤去了對GoRaft庫的依賴,從新實現了一套更加精簡和穩定的Raft算法。Etcdctl命令的代碼也從單獨的項目合併到了Etcd版本庫中。從GitHub的代碼提交量來看,Etcd一直是CoreOS的幾個主要模塊中活躍度最高的模塊。

截止至這篇文章發佈時, CoreOS最新的博客已經宣佈了Etcd v2.0(即原來的v0.5版)的發佈候選版本(Release Candidate),這個版本的完成將是Etcd 走向Production Ready的一個重要里程碑。 須要注意的是,v2.0版本包含一個很是重要的更改,即將Etcd用於客戶端數據操做API的端口4001修改成2379,同時用於Etcd節點之間通訊的端口7001修改成2380。雖然新版本的API調用方式和接口依然和這一系列文章描述的內容保持兼容,而且4001/7001端口在能夠預見的一段時間內會繼續可以被使用,但請未來的你,在使用Etcd v2.0及其之後版本時務必注意到這個區別,將系列中的4001/7001端口替換爲2379/2380端口,以避免形成誤導。Etcd服務可挖掘的內容較多,有關Etcd的API部分會放在系列的下一篇具體詳述。

 

 

從集羣的節點自發現提及

 

 

從Etcd的發展過程來看,其設計初衷是一個與ZooKeeper類似的具備訂閱/通知(Subscript/Public)功能的配置共享服務。在集羣啓動的時候,咱們僅僅配置了一個集羣標識的URL地址就使得各個節點相互認識,並能夠經過Fleet得到其餘節點的信息,這當中就有Etcd的默默的功勞。

CoreOS官方提供的discovery集羣標識服務地址是https://discovery.etcd.io。在系列的第二篇構建CoreOS集羣的過程當中,經過訪問這個網站下的 /new 頁面得到了一個標識地址,若是已經忘記了這個地址,能夠在集羣中的任意一個節點查看 /run/systemd/system/etcd.service.d/20-cloudinit.conf 文件,這個文件記錄了節點啓動時的一些信息。

$ cat /run/systemd/system/etcd.service.d/20-cloudinit.conf [Service] Environment="ETCD_ADDR=172.17.8.101:4001" Environment="ETCD_DISCOVERY=https://discovery.etcd.io/09363c5fcdfcbd42ed60b8931263fda1" Environment="ETCD_PEER_ADDR=172.17.8.101:7001"

直接訪問這個標識地址就能獲得當前集羣的基本節點信息。

core@core-01 ~ $ curl https://discovery.etcd.io/09363c5fcdfcbd42ed60b8931263fda1 {"action":"get","node":{ ... }}

當新的CoreOS節點啓動時,首先會經過Cloud-init啓動Etcd服務(也是在此前經過user-data文件進行配置的),Etcd啓動的過程當中,會經過這個標識地址得到集羣中已有的節點的信息列表,而後將本身的信息也添加到這個列表中。提供這個節點信息的Discovery服務咱們會在另外的一篇文章裏單獨來講。

在Etcd得到到集羣的狀態後,它會進行一系列的初始化工做,其中有一項是更新Etcd數據中關於集羣成員的內容。所以之後的其餘服務就能夠經過Etcd的數據直接獲得實時更新的集羣成員信息了。

經過etcdctl命令能夠查看到Etcd服務存儲的這部分信息。例以下面這個命令可以列出Etcd存儲的全部節點。

core@core-01 ~ $ etcdctl ls /_etcd/machines --recursive /_etcd/machines/f260afd8224c4854bdf8427d8451da23 /_etcd/machines/0acdd9bf38194ea5ad1611ff9a4236f1 /_etcd/machines/f2558aaa231044f3abbe01510ac2b1d8

查看其中一個具體節點的信息。

core@core-01 ~ $ etcdctl get /_etcd/machines/f260afd8224c4854bdf8427d8451da23 etcd=http%3A%2F%2F172.17.8.102%3A4001&raft=http%3A%2F%2F172.17.8.102%3A7001
這裏用到的etcdctl命令是Etcd提供的用於查詢和操做其存儲內容的命令行工具,下面來看看它的其餘用法。

 

Etcdctl的基本使用

 

Etcd自己提供了基於HTTP的Restful API,可是爲了方便運維人員的平常使用,etcdctl實現了這套API中的許多功能,熟練的使用它可以簡化很多運維的工做量。

  • 查看目錄或鍵的內容

在上一節中已經用到了的etcdctl ls 和 etcdctl get 命令是最常用到的兩個基本命令。Etcd的鍵值能夠進行分層和嵌套,Etcd中的目錄能夠存放多個鍵以及其餘的目錄,同時每一個具體的目錄和鍵都有本身的「訪問路徑」,這種作法與文件管理中的普通文件和目錄頗爲類似。.而etcdctl ls 的做用是查看特定路徑下的鍵或目錄列表。例如列出根目錄下面的內容:

core@core-01 ~ $ etcdctl ls / /coreos.com

能夠經過 --recursive 參數一次性列出指定目錄及子目錄下全部的內容。

core@core-01 ~ $ etcdctl ls / --recursive /coreos.com /coreos.com/updateengine /coreos.com/updateengine/rebootlock /coreos.com/updateengine/rebootlock/semaphore

而 etcdctl get 命令用於得到指定的鍵所存儲的值,例如:

core@core-01 ~ $ etcdctl get /coreos.com/updateengine/rebootlock/semaphore {"semaphore":1,"max":1,"holders":[]}

對一個目錄使用 etcdctl get 命令會獲得一個提示信息,告訴使用者這是一個目錄。

core@core-01 ~ $ etcdctl get /coreos.com /coreos.com: is a directory

能夠經過etcdctl的 -o 參數指定輸出內容的格式,例如 -o extended 參數會打印這個鍵的更詳細信息。

core@core-01 ~ $ etcdctl -o extended get /coreos.com/updateengine/rebootlock/semaphore Key: /coreos.com/updateengine/rebootlock/semaphore Created-Index: 6 Modified-Index: 76156 TTL: 0 Etcd-Index: 104439 Raft-Index: 413950 Raft-Term: 12 {"semaphore":1,"max":1,"holders":[]}
  • 建立、修改目錄和鍵的內容

建立一個新的目錄和鍵分別使用 etcdctl mkdir 和 etcdctl mk 命令。

core@core-01 ~ $ etcdctl mkdir /demo core@core-02 ~ $ etcdctl get /demo /demo: is a directory core@core-01 ~ $ etcdctl mk /demo/hello "Hello Etcd"  # 實際狀況中這裏會回顯輸出「Hello Etcd」,省略 core@core-02 ~ $ etcdctl get /demo/hello Hello Etcd

實際狀況中每次使用 mk 之後,屏幕會回顯寫入值的內容。因爲以後咱們都會再次用 get 取出這個值,以驗證內容確實寫入了Etcd記錄中,因此統一省略回顯的輸出,後面的update和set的例子也是。注意在上面的例子中,咱們在core-01節點建立了新的鍵和目錄,而後在core-02節點檢查Etcd記錄的內容。這樣作是爲了說明在Etcd服務組成的集羣裏,每個節點上獲取的數據都是實時同步的。固然,要是在core-01上檢查記錄內容也會獲得相同的結果。

使用 etcdctl mk命令時,若是建立鍵的路徑不存在,會自動建立相應的目錄結構,例如:

core@core-01 ~ $ etcdctl mk /path/to/the/new/key "Text Message" core@core-02 ~ $ etcdctl get /path/to/the/new/key Text Message

嘗試重複建立一個已經存在的鍵會產生一個錯誤。

core@core-01 ~ $ etcdctl mk /demo/hello "Something Else" Error:  105: Key already exists (/demo/hello) [130187]

更新鍵的記錄內容能夠經過etcdctl update(或 etcdctl set)命令完成。

core@core-01 ~ $ etcdctl update /demo/hello "Hello CoreOS" core@core-02 ~ $ etcdctl get /demo/hello Hello CoreOS

使用etcdctl update與etcdctl set的區別在於嘗試update不存在的鍵時,會產生一個錯誤。

core@core-01 ~ $ etcdctl update /demo/xx "Message" Error:  100: Key not found (/demo/xx) [129853]
下面這個表格比較了etcdctl mk、etcdctl update和etcdctl set的異同。從結果能夠看出etcdctl set至關於前二者的功能的合併。在實際狀況中應該根據實際的應用場景選擇相應的命令。

 

 

 命令/操做

etcdctl mk

etcdctl update

etcdctl set

目標鍵不存在

建立此鍵並賦值

出錯:Key not found

建立此鍵並賦值

目標鍵已經存在

出錯:Key already exists

更新鍵的內容

更新鍵的內容

  • 刪除鍵和目錄

 

 

刪除鍵和目錄的命令分別爲etcdctl rm和etcdctl rmdir:

core@core-01 ~ $ etcdctl rm /demo/hello core@core-01 ~ $ etcdctl get /demo/hello Error:  100: Key not found (/demo/hello) [131166] core@core-01 ~ $ etcdctl rmdir /demo core@core-01 ~ $ etcdctl get /demo Error:  100: Key not found (/demo) [131189]

注意,etcdctl rmdir只能刪除空的目錄,這一點和Linux的rmdir命令很類似。試圖刪除還有其餘鍵或子目錄的目錄會產生一個錯誤。這種狀況可使用etcdctl rm配合--recursive參數遞歸刪除目錄下的全部子目錄和鍵。

core@core-01 ~ $ etcdctl rmdir /path Error:  108: Directory not empty (/path) [131209] core@core-01 ~ $ etcdctl rm /path --recursive
  • TTL:存活時間

Etcd的鍵值系統有一個對應用配置頗有幫助的特性,能夠給每個鍵或目錄指定一個存活時限(TTL,即Time To Life)。TTL的單位是秒,當指定的秒數過去之後,若是相應的鍵或目錄沒有獲得更新,就會被自動從Etcd記錄中移除。

用於給鍵或目錄添加TTL的參數是--ttl,這個命令對幾個建立和更新的命令都適用。

core@core-01 ~ $ etcdctl mkdir /path/to/demo --ttl 120  # 給目錄添加TTL時間 core@core-01 ~ $ etcdctl mk /path/to/demo/title 「Message Title」 --ttl 120  # 給鍵添加TTL時間

經過 update 和 updatedir 的 --ttl 參數可以將鍵和目錄的剩餘存活週期重置爲指定的新值。這個功能有點像用於確保儀器正確運行的「看門狗」程序,一旦發現程序必定時間內都沒有更新相應的Etcd記錄,這條記錄就會被認爲是過時的而直接被移除。在設定了TTL以後,可使用帶 -o extended 參數的ectdctl get命令來檢查數據鍵或目錄剩餘的存活時間。

core@core-01 ~ $ etcdctl updatedir /path/to/demo --ttl 500  # 更新目錄的TTL時間 core@core-01 ~ $ etcdctl update /path/to/demo/titl 「Message Title」 e--ttl 400  # 更新鍵的TTL時間

這個功能使得局部的系統出現節點或服務失效時,系統的其他部分可以及時發現這一狀況,並做出調整。具體的應用場景咱們在之後的進階篇內容中會舉例說明。

監控變化

若是Etcd的功能僅僅侷限於數據的存儲和分發,它與普通的NoSQL數據庫就沒有特別的差異了。事實上Etcd所作的遠不止這些,做爲一個用於集羣配置共享的服務,除了TTL這種典型特性外,另外一個重要的功能即是數據變動的訂閱/通知(Subscript/Public)。

集羣中的應用程序爲了保持正確的行爲,須要時刻依據所需的配置信息進行相應的調整,一般有兩種方式能夠實現。一種是按期去檢查集羣配置的內容,即定時輪詢(Polling)。另外一種是訂閱特定的事件,由集羣配置服務(Etcd)在相應事件發生的時候直接通知應用程序作出處理。顯然從響應的及時性和對應用程序效率的影響來講,後者要更加適用一些。

其實Etcd自己並無提供一套直接的訂閱/通知服務機制,但經過它提供的監控變化API以及HTTP long-polling的辦法,是能夠實現相同的功能的。與此相關的命令是etcdctl watch和etcdctl exec-watch,前者用於等待指定的鍵發生變化,後者在前者的基礎上提供了變化發生後,自動觸發另外一段用戶指定的命令的能力。

core@core-01 ~ $ etcdctl watch /path/to/demo core@core-02 ~ $ etcdctl update /path/to/demo 「new-value」

上面這段例子使用了在core-01節點監聽路徑/path/to/demo,當etcdctl watch執行後,程序就開始進入等待狀態。而後在core-02節點對這個路徑上的鍵進行了更新,此時等待在core-01節點上的etcdctl進程收到了這個變化隨即退出。

這個命令能夠接收一個參數 --recursive 用於遞歸監聽指定路徑下全部子路徑的變化。

core@core-01 ~ $ etcdctl watch --recursive /path

單獨使用etcdctl watch命令沒有太大的意義,由於它每次監聽到指定的變化就退出了,什麼也作不了。通常會將監聽到記錄變化之後須要執行的命令寫在這行命令的後面,這樣當事件發生之後,就會立刻執行特定的操做了。在一些後臺的腳本中,這種監聽功能十分有用。下面的這段腳本實現了自動監聽/path/to/demo路徑的變化,一旦有變化發生,就將這個鍵的值前面加上一個「Hello」。

KEY=/path/to/demo while true; do etcdctl watch ${KEY}   sleep 1s   etcdctl update ${KEY} 「Hello $(etcdctl get ${KEY})」 done

須要注意這段腳本中的「sleep 1s」這一行,若是去掉這一行,在後面當即使用etcdctl get獲得依然是變化發生以前這個鍵的內容。即etcdctl在接收到變化信號時候,若是想獲取變化後的內容,須要等待一點點時間。已經將這個問題提交到了GitHub,有興趣的同窗能夠跟一下後續的回覆。

除了將須要執行的命令放到etcdctl watch命令以後,etcdctl也提供了一條可以一步到位的命令:exec-watch。可是在實際使用中發現這個命令還存在不少問題,在監視同一個鍵時,修改了鍵的內容後,使用watch命令老是能當即返回,可是exec-watch命令常常平白無故的接收不到;此外exec-watch在執行了指定的命令後會存在命令沒法正確退出的問題。鑑於它所完成的工做使用etcdctl watch已經可以作到,這裏暫時略去對這個命令的介紹。

 

 

走進幕後

在這一篇中,咱們主要從Etcd服務的做用和它提供的數據操做工具etcdctl介紹了CoreOS的核心分佈式數據服務的概貌及用法。然而在這些工具表象的背後,是一套支撐着Etcd業務擴展的API系統。在系列的下一篇中,會繼續探討Etcd服務的Restful API使用、Etcd的配置參數以及其餘一些使用者須要知道的Etcd特性。敬請期待。(做者/林帆  責編/周小璐)

相關文章
相關標籤/搜索