天天看點

入門篇:從 etcd 名字的由來,到安裝部署和使用姿勢

大家好,我是

三十一

[0],本次分享分布式神器

etcd

[1]的 5 種部署方式和 10 種使用姿勢,閱讀全文預計花費 15 分鐘。

在學習 etcd 之前,我們先來聊一聊

etcd 名字的由來

[2]。etcd 中的 etc 取自 unix 系統的

/etc

目錄,再加上一個

d

代表

distributed system

就組成了 etcd。在 unix 系統中 /etc 目錄用于存儲系統的配置資料,單從名字看 etcd 可用于存儲分布式系統的配置資料,有時候也把 etcd 簡單了解為分布式 /etc 配置目錄。

etcd 簡介

etcd 是一個可靠的分布式 key-value 存儲系統,主要用于

配置共享

服務注冊和發現

,具有以下特性:

  • 簡單:基于 gRPC 定義了清晰、面向使用者的 API。
  • 安全:支援可選的用戶端 TLS 證書自動認證特性。
  • 快速:支援每秒 10000 次的寫入。
  • 可靠:基于 Raft 算法協定保證一緻性。

etcd 使用 Go 語言開發,底層基于 Raft 共識算法管理高可用的複制日志。目前已經被許多公司用于關鍵生産項目,比如:Kubernetes、locksmith、vulcand、Doorman 等。

當然,也有其他元件可以提供配置共享和服務注冊和發現的功能,比如最為廣泛和大家最為熟知的 Zookeeper,也被很多 Java 系的知名開源項目認可和使用,比如:Hadoop、HBase、Kafka 等。

但 etcd 是唯一一個可以媲美甚至超越 Zookeeper 的元件。

相較之下,Zookeeper 有如下缺點[3]:

  • 複雜:Zookeeper 基于 ZAB 協定,屬于類 Paxos 協定,而 Paxos 算法素以複雜難懂聞名;Zookeeper 的使用也比較複雜,需要安裝用戶端,而官方目前隻提供了 Java 和 C 兩種語言接口。
  • 發展慢:由于基金會龐大的結構以及松散的管理,導緻項目發展緩慢。

而 etcd 作為後起之秀,其優點也很明顯:

  • 簡單:使用 Go 語言編寫部署簡單;使用 gRPC 定義接口,支援跨語言、跨平台特性;使用了易于使用者了解的 Raft 算法保證一緻性,優于 Paxos 算法。
  • 發展快:etcd 正處于高速疊代開發中。
  • 性能優越:官方提供的基準測試資料中,etcd 叢集可以支援每秒 10000+ 次的寫入,性能優于 Zookeeper。
  • 安全性:etcd 支援 TLS 通路,而 ZooKeeper 在權限控制方面做得略顯粗糙。

環境搭建

一、本地安裝包部署

「下載下傳」:下載下傳最新的安裝包(目前最新:v3.5.4),下載下傳位址:https://github.com/etcd-io/etcd/releases/

入門篇:從 etcd 名字的由來,到安裝部署和使用姿勢

「安裝」:在解壓後的檔案目錄下

etcd

etcdctl

分别為安裝包和用戶端的編譯後的執行檔案,可使用三種方法進行運作配置。

  • 方法一:解壓目錄下直接運作
  • 方法二:把

    etcd

    etcdctl

    檔案複制到

    GOBIN

    目錄下。
  • 方法三:在環境變量裡添加

    etcd

    etcdctl

    檔案所在的目錄。

注:運作過程中,可能會涉及權限問題,授權即可。

「驗證」:

# 驗證 etcd 版本
$ etcd --version

etcd Version: 3.5.4
Git SHA: 08407ff76
Go Version: go1.16.15
Go OS/Arch: darwin/amd64

# 驗證 etcdctl 版本
$ etcdctl version

etcdctl version: 3.5.4
API version: 3.5
           

複制

二、本地編譯部署

「下載下傳」:使用以下指令克隆代碼

# 下載下傳最新版
$ git clone https://github.com/etcd-io/etcd.git
# 指定版本下載下傳
$ git clone -b v3.5.4 https://github.com/etcd-io/etcd.git
           

複制

「編譯安裝」:

# 編譯
$ cd etcd
$ make build

# 安裝
$ export PATH="$PATH:`pwd`/bin"
           

複制

「驗證」:

# 驗證 etcd 版本
$ etcd --version

# 驗證 etcdctl 版本
$ etcdctl version

# 驗證 etcdutl 版本
$ etcdutl version
           

複制

三、本地叢集部署

首先需要安裝

goreman

元件,它基于 Procfile 配置檔案管理 etcd 應用程序。

$ go install github.com/mattn/goreman@latest
           

複制

「啟動叢集」:源碼目錄下

Procfile

腳本已經建構好了本地示範叢集,直接運作啟動即可

$ goreman start
           

複制

「驗證」

$ etcdctl member list

8211f1d0f64f3269, started, infra1, http://127.0.0.1:12380, http://127.0.0.1:2379, false
91bc3c398fb3c146, started, infra2, http://127.0.0.1:22380, http://127.0.0.1:22379, false
fd422379fda50e48, started, infra3, http://127.0.0.1:32380, http://127.0.0.1:32379, false
           

複制

該腳本建立包含 3 個 etcd 成員節點的叢集,每個叢集成員都接收鍵值的讀取和寫入。也可以按照

Procfile.learner

腳本指導,學習叢集新增節點的操作。

四、Docker 單機部署

此處通過

docker-compose

進行實驗配置。

「鏡像拉取」

$ docker pull bitnami/etcd:3.5.2
           

複制

「編輯docker-compose.yml」

version: '3.5'

services:
  etcd:
    container_name: builder-etcd
    image: bitnami/etcd:3.5.2
    ports:
      - 2379:2379
    environment:
      - ALLOW_NONE_AUTHENTICATION=yes
      - ETCD_AUTO_COMPACTION_MODE=revision
      - ETCD_AUTO_COMPACTION_RETENTION=1002
      - ETCD_QUOTA_BACKEND_BYTES=4294967296
    volumes:
      - ${DOCKER_ROOT_DIR:-.}/volumes/etcd/data:/bitnami/etcd

networks:
  default:
    name: builder_dev
           

複制

「啟動服務」

$ docker-compose -f docker-compose.yml up
           

複制

「驗證」:驗證叢集節點的版本

$ docker exec -it builder-etcd /bin/bash -c "etcd --version"

etcd Version: 3.5.2
Git SHA: 99018a77b
Go Version: go1.16.3
Go OS/Arch: linux/amd64
           

複制

五、Docker 叢集部署

「編輯docker-compose.yml」

version: '3.5'

services:
  etcd1:
    container_name: builder-etcd1
    image: bitnami/etcd:3.5.2
    ports:
      - 12379:2379
    environment:
      - ALLOW_NONE_AUTHENTICATION=yes
      - ETCD_AUTO_COMPACTION_MODE=revision
      - ETCD_AUTO_COMPACTION_RETENTION=1002
      - ETCD_QUOTA_BACKEND_BYTES=4294967296
      - ETCD_NAME=etcd1
      - ETCD_INITIAL_ADVERTISE_PEER_URLS=http://etcd1:2380
      - ETCD_LISTEN_PEER_URLS=http://0.0.0.0:2380
      - ETCD_LISTEN_CLIENT_URLS=http://0.0.0.0:2379
      - ETCD_ADVERTISE_CLIENT_URLS=http://etcd1:2379
      - ETCD_INITIAL_CLUSTER_TOKEN=etcd-cluster
      - ETCD_INITIAL_CLUSTER=etcd1=http://etcd1:2380,etcd2=http://etcd2:2380,etcd3=http://etcd3:2380
      - ETCD_INITIAL_CLUSTER_STATE=new
    volumes:
      - ${DOCKER_ROOT_DIR:-.}/volumes/etcd/data1:/bitnami/etcd

  etcd2:
    container_name: builder-etcd2
    image: bitnami/etcd:3.5.2
    ports:
      - 22379:2379
    environment:
      - ALLOW_NONE_AUTHENTICATION=yes
      - ETCD_AUTO_COMPACTION_MODE=revision
      - ETCD_AUTO_COMPACTION_RETENTION=1002
      - ETCD_QUOTA_BACKEND_BYTES=4294967296
      - ETCD_NAME=etcd2
      - ETCD_INITIAL_ADVERTISE_PEER_URLS=http://etcd2:2380
      - ETCD_LISTEN_PEER_URLS=http://0.0.0.0:2380
      - ETCD_LISTEN_CLIENT_URLS=http://0.0.0.0:2379
      - ETCD_ADVERTISE_CLIENT_URLS=http://etcd2:2379
      - ETCD_INITIAL_CLUSTER_TOKEN=etcd-cluster
      - ETCD_INITIAL_CLUSTER=etcd1=http://etcd1:2380,etcd2=http://etcd2:2380,etcd3=http://etcd3:2380
      - ETCD_INITIAL_CLUSTER_STATE=new
    volumes:
      - ${DOCKER_ROOT_DIR:-.}/volumes/etcd/data2:/bitnami/etcd

  etcd3:
    container_name: builder-etcd3
    image: bitnami/etcd:3.5.2
    ports:
      - 32379:2379
    environment:
      - ALLOW_NONE_AUTHENTICATION=yes
      - ETCD_AUTO_COMPACTION_MODE=revision
      - ETCD_AUTO_COMPACTION_RETENTION=1002
      - ETCD_QUOTA_BACKEND_BYTES=4294967296
      - ETCD_NAME=etcd3
      - ETCD_INITIAL_ADVERTISE_PEER_URLS=http://etcd3:2380
      - ETCD_LISTEN_PEER_URLS=http://0.0.0.0:2380
      - ETCD_LISTEN_CLIENT_URLS=http://0.0.0.0:2379
      - ETCD_ADVERTISE_CLIENT_URLS=http://etcd3:2379
      - ETCD_INITIAL_CLUSTER_TOKEN=etcd-cluster
      - ETCD_INITIAL_CLUSTER=etcd1=http://etcd1:2380,etcd2=http://etcd2:2380,etcd3=http://etcd3:2380
      - ETCD_INITIAL_CLUSTER_STATE=new
    volumes:
      - ${DOCKER_ROOT_DIR:-.}/volumes/etcd/data3:/bitnami/etcd

networks:
  default:
    name: builder_dev
           

複制

部署配置檔案 docker-compose.yml 細節,詳見

etcd docker-compose yml

[4]

「啟動服務」

$ docker-compose -f docker-compose.yml up
           

複制

「驗證」:驗證叢集節點的版本

$ docker exec -it builder-etcd1 /bin/bash -c "etcd --version"
$ docker exec -it builder-etcd2 /bin/bash -c "etcd --version"
$ docker exec -it builder-etcd3 /bin/bash -c "etcd --version"

# 輸出
etcd Version: 3.5.2
Git SHA: 99018a77b
Go Version: go1.16.3
Go OS/Arch: linux/amd64
           

複制

API 學習

此處,通過使用

etcdctl

[5]進行 API 學習驗證,etcdctl 是一個用于與 etcd 伺服器互動的指令行工具。

「1.檢視版本」

$ etcdctl version

etcdctl version: 3.6.0-alpha.0
API version: 3.6
           

複制

「2.寫入 key」

$ etcdctl put foo bar
OK
           

複制

「3.讀取 key」

$ etcdctl get foo
foo
bar
# 隻是擷取值
$ etcdctl get foo --print-value-only
bar
           

複制

「4.批量取值」

$ etcdctl put foo1 bar1
$ etcdctl put foo3 bar2
$ etcdctl put foo3 bar3

# 擷取從 foo 到 foo3 的值,不包括 foo3
$ etcdctl get foo foo3 --print-value-only 
bar
bar1
bar2

# 擷取字首為 foo 的值
$ etcdctl get --prefix foo --print-value-only
bar
bar1
bar2
bar3

# 擷取符合字首的前兩個值
$ etcdctl get --prefix --limit=2 foo --print-value-only
bar
bar1
           

複制

「5.删除 key」

# 删除 foo 的值
$ etcdctl del foo
1

# 删除 foo 到 foo2 且不包括 foo2 的值
$ etcdctl del foo foo2
1
# 删除字首為 foo 的所有值
$ etcdctl del --prefix foo
2
           

複制

「6.監聽」

# 監聽 foo 單個 key
$ etcdctl watch foo
# 另一個控制台執行:etcdctl put foo bar
PUT
foo
bar

# 同時監視多個值
$ etcdctl watch -i
$ watch foo
$ watch zoo
# 另一個控制台執行: etcdctl put foo bar
PUT
foo
bar

# 另一個控制台執行: etcdctl put zoo val
PUT
zoo
val

# 監視 foo 字首命中的 key
$ etcdctl watch --prefix foo
# 另一個控制台執行:etcdctl put foo1 bar1
PUT
foo1
bar1
# 另一個控制台執行:etcdctl put fooz1 barz1
PUT
fooz1
barz1
           

複制

「7.設定租約」當一個 key 被綁定到一個租約上時,它的生命周期與租約的生命周期即綁定。

# 設定10秒後過期時間
$ etcdctl lease grant 10
lease 32698142c52a170a granted with TTL(10s)

# 把 foo 和租約綁定,設定成 10 秒後過期
$ etcdctl put --lease=32698142c52a170a foo bar
OK
$ etcdctl get foo
foo
bar

# 10 秒後,擷取不到 foo
$ etcdctl get foo
# 傳回空
           

複制

「8.撤銷租約」通過租約 ID 撤銷租約,撤銷租約将删除其所有綁定的 key。

$ etcdctl lease grant 10
lease 32698142c52a170c granted with TTL(10s)
$ etcdctl put --lease=32698142c52a170c foo bar
OK

# 撤銷租約
$ etcdctl lease revoke 32698142c52a170c
lease 32698142c52a170c revoked

$ etcdctl get foo
# 傳回空
           

複制

「9.續約」通過重新整理 TTL 值來保持租約的有效,使其不會過期。

# 設定 10 秒後過期租約
$ etcdctl lease grant 10
lease 32698142c52a170f granted with TTL(10s)

# 把 foo 和租約綁定,設定成 10 秒後過期
$ etcdctl put foo bar --lease=32698142c52a170f

# 自動定時執行續約,續約成功後每次租約為 10 秒
$ etcdctl lease keep-alive 32698142c52a170f
lease 32695410dcc0ca06 keepalived with TTL(10)
lease 32695410dcc0ca06 keepalived with TTL(10)
lease 32695410dcc0ca06 keepalived with TTL(10)
...
           

複制

「10.檢視租約」檢視租約資訊,以便續租或檢視租約是否仍然存在或已過期

# 設定 50 秒 TTL
$ etcdctl lease grant 50
lease 32698142c52a1711 granted with TTL(50s)

# zoo1 綁定 32698142c52a1711 租約
$ etcdctl put --lease=32698142c52a1711 zoo1 val1
OK

# 檢視租約,remaining(32s) 剩餘有效時間32秒;--keys 擷取租約綁定的 key
$ etcdctl lease timetolive --keys 32698142c52a1711
lease 32698142c52a1711 granted with TTL(50s), remaining(32s), attached keys([zoo1])
           

複制

注:一個租約支援綁定多個 key

$ etcdctl lease grant 50
lease 32698142c52a1713 granted with TTL(50s)

$ etcdctl put --lease=32698142c52a1713 zoo1 val1
OK

$ etcdctl put --lease=32698142c52a1713 zoo2 val2
OK

$ etcdctl put --lease=32698142c52a1713 zoo3 val3
OK
           

複制

租約過期後,所有 key 值都會被删除,是以:

  • 當租約隻綁定了一個 key 時,想删除這個 key,最好的辦法是撤銷它的租約,而不是直接删除這個 key。
  • 當租約沒有綁定key時,應主動把它撤銷掉,單純删除 key 後,續約操作持續進行,會造成記憶體洩露。
# 方法一:直接删除`key`
# 設定租約并綁定 zoo1
$ etcdctl lease grant 50
lease 32698142c52a1715 granted with TTL(50s)
$ etcdctl --lease=32698142c52a1715 put zoo1 val1
OK

# 續約
$ etcdctl lease keep-alive 32698142c52a1715
lease 32698142c52a1715 keepalived with TTL(50)

# 另一個控制台執行:etcdctl del zoo1
# 單純删除 key 後,續約操作持續進行,會造成記憶體洩露
lease 32698142c52a1715 keepalived with TTL(50)
lease 32698142c52a1715 keepalived with TTL(50)
lease 32698142c52a1715 keepalived with TTL(50)
...

# 方法二:撤銷`key`的租約
# 設定租約并綁定 zoo1
$ etcdctl lease grant 50
lease 32698142c52a1717 granted with TTL(50s)
$ etcdctl --lease=32698142c52a1717 put zoo1 val1
OK

# 續約
$ etcdctl lease keep-alive 32698142c52a1717
lease 32698142c52a1717 keepalived with TTL(50)
lease 32698142c52a1717 keepalived with TTL(50)

# 另一個控制台執行:etcdctl lease revoke 32698142c52a1717

# 續約撤銷并退出
lease 32698142c52a1717 expired or revoked.
$ etcdctl get zoo1
# 傳回空
           

複制

以上,就是今天的全部内容,幾乎包含了 etcd 安裝和使用的各種姿勢,歡迎各位号友敬請嘗試。

References

  • [0] 三十一: http://www.lee31.cn/assets/image/ThirtyOneLee.jpeg
  • [1] etcd: https://github.com/etcd-io/etcd
  • [2] etcd 名字的由來: https://etcd.io/docs/v3.5/faq/
  • [3] https://www.infoq.cn/article/etcd-interpretation-application-scenario-implement-principle/
  • [4] etcd docker-compose yml: https://github.com/liyaodev/docker-compose
  • [5] etcdctl: https://etcd.io/docs/v3.5/dev-guide/interacting_v3/