ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Etcd] Watch 기능 알아보기 ( HTTP2, WatchCreateRequest )
    Etcd 2024. 6. 17. 05:59
    728x90
    반응형

    - 목차

     

    들어가며.

    EtcdDistributed Application 의 상태를 저장하는 저장소로써 동작합니다.

    일반적인 분산 시스템은 네트워크적으로 떨어져 존재하는데요.

    하지만 이들은 마치 한 몸처럼 동작해야만 합니다.

    대표적인 분산 시스템의 예시로써 Kafka 가 존재합니다.

    보통 3개 이상의 Kafka 서버는 네트워크적으로 떨어져있지만 Kafka ClientKafka Broker 들이 마치 하나의 시스템인 것처럼 보여집니다.

    즉, 분산 시스템은 멀리 떨어져 있지만 한 몸처럼 동작해야한 하는 것이죠.

     

    Kafka 는 Etcd 가 아닌 Zookeeper 를 사용하긴 하지만 Etcd, Zookeepr, Consul 등 이들은 분산 시스템의 상태를 저장하기 위한 저장소로써 동일한 목적을 가집니다.

    그리고 이러한 기능의 핵심이 Watch Mechanism 입니다.

     

    Watch Mechanism 은 특정 데이터의 상태가 변화하게 되면, 클라이언트인 Watcher 에게 이 변화를 보고합니다.

    예를 들어, 여러 개의 Kafka Broker 들은 서로의 상태 변화에 민감하게 대응해야합니다.

    왜냐하면 Leader Broker 가 Down 되면, 다른 Follower Broker 가 새로운 Leader 가 되어야하기 때문이죠.

    그래서 각 node 의 상태를 저장하는 Key-Value 데이터를 Zookeeper 에 등록하고, Broker 들을 서로가 서로의 상태를 체크합니다.

    만약 한 Broker-1 가 Down 되게되면 Zookeeper 의 Broker-1 데이터의 값이 unhealthy 상태로 변경되며,

    Zookeeper 는 모든 Watcher 들에게 이 변화를 보고하게 됩니다.

     

    Etcd 의 Watch Mechanism 도 이와 동일하게 동작합니다.

    Application-A 는 자신의 상태를 Etcd 에 저장합니다.

    "etcdctl put Application-A Healthy" 와 같은 형식으로 데이터를 생성할 수 있습니다.

    그리고 Application-B 는 "Application-A" Key-Value 데이터를 모니터링하는 Watcher 입니다.

    만약 Application-A 가 비정상 종료가 되고, "Application-A" 의 Value 가 Unhealthy 로 변경된다면,

    Watcher 인 Application-B 는 이에 대한 보고를 Etcd 로부터 받게 됩니다.

    그리고 사전에 정의된 Failure Handling 프로세스가 진행될 겁니다.

     

    이번 글에서는 Watch Mechanism 이 실제로 어떻게 동작하는지에 대해서 깊이있게 다루어보도록 하겠습니다.

     

    etcdctl watch.

    etcdctl watch 명령어를 통해서 특정 Key 의 데이터를 모니터링할 수 있습니다.

    먼저 아래의 명령어를 통해서 1개의 Etcd Docker Container 를 실행합니다.

     

    docker network create etcd
    
    docker run --platform linux/amd64 -d --network etcd \
    --name etcd1 --hostname etcd1 \
    -p 12380:2380 \
    -p 12379:2379 \
    quay.io/coreos/etcd:v3.5.17 \
    /usr/local/bin/etcd \
        --data-dir=/var/etcd \
        --listen-client-urls=http://0.0.0.0:2379 \
        --advertise-client-urls="http://host.docker.internal:12379" \
        --listen-peer-urls=http://0.0.0.0:2380 \
        --initial-advertise-peer-urls=http://etcd1:2380 \
        --initial-cluster="node1=http://etcd1:2380" \
        --initial-cluster-state=new \
        --initial-cluster-token=etcd \
        --name=node1

     

     

    그리고 아래와 같은 etcdctl watch 명령어를 통해서 특정 Key 에 해당하는 데이터의 변경을 감지할 수 있습니다.

     

    docker run --platform linux/amd64 --network etcd --rm quay.io/coreos/etcd:v3.5.17 \
    etcdctl --endpoints=http://etcd1:2379 watch key1

     

    아래의 명령어는 etcdctl put 명령어의 예시입니다.

     

    docker run --platform linux/amd64 --network etcd --rm quay.io/coreos/etcd:v3.5.17 \
    etcdctl --endpoints=http://etcd1:2379 put key1 value1

     

    블로그의 특정상 생동감있게 Watcher Process 의 데이터 변경 감지를 보여드리지는 못하지만,

    아래의 캡쳐 이미지와 같이 key1 에 해당하는 데이터가 변경된다면 Put KEY VALUE 의 결과를 모니터링할 수 있습니다.

     

     

     

    Watch Mechanism 과 HTTP2.

    이번에는 Etcd Watch 기능를 네트워크 관점에서 이야기해보려고 합니다.

    Etcd 는 통신을 위해서 일반적으로 gRPC 를 사용합니다.

    그리고 AppendEntries, RequestVote, WatchCreateRequest 등의 대표적인 RPC 함수들이 존재합니다.

    gRPC 의 중요한 두가지 특징이 있는데요.

    하나는 HTTP2 프로토콜을 사용한다는 점, 그리고 다른 하나는 ProtoBuf 직렬화 방식을 사용하는 점입니다.

    특히 Watch Mechanism 과 HTTP2 프로토콜을 Persistent Connection 이라는 관점에서 중요한 역할을 수행하는데요.

    이 부분에 대해서 이야기해보도록 하겠습니다.

     

    Etcd 의 클라이언트가 Watcher 로써 동작하기 위해서는 Etcd 와 Watcher 가 지속적인 네트워크 연결이 되어야만 합니다.

    왜냐하면 클라이언트는 일반적인 서버처럼 네트워크 소켓을 만들어 특정 Port 를 리스닝하는 구조가 아니기 때문입니다.

    그래서 Etcd 에게 어떠한 데이터의 변화가 감지되면 Watcher 인 클라이언트에게 이를 보고해야하는데,

    네트워크 트래픽을 리스닝하고 있지 않는 Etcd 클라이언트에게 이를 보고하기 위해서 지속적인 네트워크 연결이 되어 있어야만 합니다.

     

    HTTP 1.1 의 구조는 근본적으로 일회성 연결을 지원합니다.

    Keep-Alive 설정이 있긴 하지만 이는 지속적인 네트워크 연결과 맞지 않습니다.

    하지만 Etcd 는 gRPC 를 사용하고, gRPC 가 HTTP2 프로토콜을 사용하기 때문에 HTTP2 의 지속적인 네트워크 연결 구조의 힘입어

    Watcher 인 클라이언트와 Etcd 는 지속적인 네트워크 연결이 가능합니다.

    ( 추후에 HTTP2 에 대한 새로운 주제로 글을 하나 작성해보도록 하겠습니다. )

     

     

    Watcher 와 TCP 커넥션 관계 살펴보기.

    일반적으로 HTTP 연결은 TCP 레이어 위에서 동작하게 됩니다.

    etcdctl watch 명령어를 통해서 Etcd 의 특정 Key 를 모니터링하게 될 때에 내부적으로 어떻게 동작하게 되는지 살펴보겠습니다.

    먼저 저는 2개의 etcdctl watch 명령를 실행하여 2개의 Watcher 프로세스를 실행합니다.

     

    그리고 아래의 이미지는 netstat 를 통해서 확인되는 2개의 TCP 연결의 상태입니다.

    각 TCP 커넥션은 etcd1:2379 주소와 연결되며, 이는 Etcd Docker Container 에 해당합니다.

    그리고 각각의 Watcher Process 는 46828 과 38054 port 를 사용하고 있습니다.

    즉, Watcher Process 는 TCP Client 에 해당하게 됩니다.

     

     

    아래의 결과는 ps 명령어로 확인되는 실행 중인 Process 목록입니다.

    저의 개발 환경에 ARM 기반의 컴퓨터라서 Process Command 에 rosetta 가 보이긴하지만, etcdctl watch 로 실행된 Process 2개가 구동되고 있습니다.

     

    # ps auxww
    USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
    1001         1  0.0  0.1 1967348 34576 ?       Ssl  05:14   0:00 /run/rosetta/rosetta /opt/bitnami/etcd/bin/etcdctl etcdctl --endpoints=http://etcd1:2379 watch key1
    1001        23  0.0  0.0 726004  6744 pts/0    Ss   05:14   0:00 /run/rosetta/rosetta /usr/bin/bash bash
    1001        29  0.0  0.1 1967360 35944 pts/0   Sl+  05:15   0:00 /run/rosetta/rosetta /opt/bitnami/etcd/bin/etcdctl etcdctl --endpoints=http://etcd1:2379 watch key1
    root       517  0.0  0.0 726040  6752 pts/1    Ss   05:24   0:00 /run/rosetta/rosetta /usr/bin/bash bash

     

     

    반응형
Designed by Tistory.