地方エンジニアの学習日記

興味ある技術の雑なメモだったりを書いてくブログ。たまに日記とガジェット紹介。

【入門】etcd

event.cloudnativedays.jp

の発表を見てetcdの仕組みやRaftについて学んだのですがetcd単体で調べたのはエラーが出てた時とかそのレベルでまとも入門したことがなかったので学んでみました。

etcdとは

github.com

etcdは、分散システム用の軽量で高可用性のキーバリューストアです。一貫性と分断耐性を持ち、特にKubernetesなどのクラスタリングシステムの構成管理に使用されます。Raftアルゴリズムを用いて分散コンセンサスを実現し、データの安全性と信頼性を提供します。多くのクラウドネイティブアプリケーションで設定情報やサービスディスカバリに使われ、そのシンプルさと効率性で高い評価を受けています。実装言語はGoとなっています。

公式で挙げている特徴は以下となっていました。

  • Simple: well-defined, user-facing API (gRPC)
  • Secure: automatic TLS with optional client cert authentication
  • Fast: benchmarked 10,000 writes/sec
  • Reliable: properly distributed using Raft

触ってみる

docker-composeを使って触ってみます。etcdは、通信にポート2379番を使い、クラスタとしての通信にはポート2380番を使います。

version: "3"

services:
  etcdctl-client:
    image: quay.io/coreos/etcd:v3.5.0
    depends_on:
      - etcd0
      - etcd1
      - etcd2
    entrypoint: /bin/sh
    command: -c 'while true; do sleep 3600; done'
    environment:
      ETCDCTL_API: '3'
      ETCDCTL_ENDPOINTS: 'http://etcd0:2379,http://etcd1:2379,http://etcd2:2379'

  etcd0:
    image: quay.io/coreos/etcd:v3.5.0
    volumes:
      - etcd-data0:/etcd-data
    command: /usr/local/bin/etcd --name etcd0 --data-dir /etcd-data --listen-client-urls http://0.0.0.0:2379 --advertise-client-urls http://etcd0:2379 --listen-peer-urls http://0.0.0.0:2380 --initial-advertise-peer-urls http://etcd0:2380 --initial-cluster etcd0=http://etcd0:2380,etcd1=http://etcd1:2380,etcd2=http://etcd2:2380 --initial-cluster-token etcd-cluster-1 --initial-cluster-state new
    ports:
      - "2379:2379"
      - "2380:2380"

  etcd1:
    image: quay.io/coreos/etcd:v3.5.0
    volumes:
      - etcd-data1:/etcd-data
    command: /usr/local/bin/etcd --name etcd1 --data-dir /etcd-data --listen-client-urls http://0.0.0.0:2379 --advertise-client-urls http://etcd1:2379 --listen-peer-urls http://0.0.0.0:2380 --initial-advertise-peer-urls http://etcd1:2380 --initial-cluster etcd0=http://etcd0:2380,etcd1=http://etcd1:2380,etcd2=http://etcd2:2380 --initial-cluster-token etcd-cluster-1 --initial-cluster-state new
    ports:
      - "2379"
      - "2380"

  etcd2:
    image: quay.io/coreos/etcd:v3.5.0
    volumes:
      - etcd-data2:/etcd-data
    command: /usr/local/bin/etcd --name etcd2 --data-dir /etcd-data --listen-client-urls http://0.0.0.0:2379 --advertise-client-urls http://etcd2:2379 --listen-peer-urls http://0.0.0.0:2380 --initial-advertise-peer-urls http://etcd2:2380 --initial-cluster etcd0=http://etcd0:2380,etcd1=http://etcd1:2380,etcd2=http://etcd2:2380 --initial-cluster-token etcd-cluster-1 --initial-cluster-state new
    ports:
      - "2379"
      - "2380"

volumes:
  etcd-data0:
  etcd-data1:
  etcd-data2:

etcd自体はシングルバイナリでオプションで動作を変えています。いかに使っているオプションとその説明を記載します。

  • --endpoints (短縮形: -e): etcd クラスターのメンバーにアクセスするための URL を指定します。例: --endpoints=http://127.0.0.1:2379
  • --cert, --key, --cacert: TLS/SSL 認証を使用する場合に、クライアント証明書、クライアントキー、CA証明書のファイルパスをそれぞれ指定します。
  • --user (短縮形: -u): etcd クラスターへの認証にユーザー名とパスワードを使用します。例: --user=root:password
  • --write-out (短縮形: -w): 出力のフォーマットを指定します。JSONなどのフォーマットに設定可能です。例: --write-out=json
  • --prefix: キーの範囲操作(例えば範囲内のキーを取得する際)でプレフィックスを指定するために使用します。
  • --limit: 範囲クエリにおいて、返されるレコードの数を制限します。
  • --from-key: 指定したキーから始まる範囲のすべてのキーを取得するために使用します。
  • --sort-by: キーまたは値に基づいて結果をソートする際に使用します。
  • --consistency: クエリの一貫性レベルを指定します("s" は強い一貫性、"l" は軽い一貫性)

memcachedとの違いは?

分散KVSの部分だけ見るとmemcachedでも良いのでは?と思ってしまう面もあります。etcdの開発者は共有構成とサービス検出のための分散型の一貫したキーと値のストアと説明しています。一方でmemcachedは高性能な分散メモリキャッシュシステムとなります。そういった開発の思想が違うのかなと感じました。memcachedで耐久性を実現するにはmemcachedの機能だけで実現はできなくてクライアント側がダブルライトなどの仕組みを使ってあげる必要があったりします。

db-engines.com

また書き込み時にも複数サーバにログを送信した結果が戻るまで終了しないようになっておりノードの障害が起きてもデータが失われないようになっています。

書き込み時の処理

  1. リーダーの選出: etcd クラスターは Raft コンセンサスアルゴリズムを使用しています。このアルゴリズムにより、クラスター内のノード間でリーダーが選出されます。書き込みリクエストは、このリーダーノードに対してのみ行われます。

  2. ログエントリの追加: リーダーは書き込みリクエストを受け取ると、そのリクエストをログエントリとして記録します。このエントリはまだ永続化されていない「提案(proposal)」の状態です。

  3. ログのレプリケーション: リーダーはこのログエントリをクラスター内の他のフォロワーノードに複製します。フォロワーはこのエントリを自分のログに追加します。

  4. コミットと応答: クラスターの過半数のノードがログエントリを受け入れると、リーダーはそのエントリを「コミット(commit)」します。これにより、エントリはクラスター全体で合意された変更として確定します。リーダーはその後、クライアントに対して書き込み処理が成功したことを応答します。

  5. ステートマシンへの適用: コミットされた変更は各ノードの状態機械に適用され、キーバリューストアが更新されます。

www.docswell.com

終わり

今回の入門でmemcachedやRedis、zookeeperやconsulといったソリューションがあるなかで何故使われているのかがわかってよかったです。サンプルで使ったコードはこちらに置いておきます。

github.com