> ## Documentation Index
> Fetch the complete documentation index at: https://clickhouse.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# 스케일링

> 확장성을 위해 설계된 예시 아키텍처를 설명하는 페이지

export const Image = ({img, alt, size = "lg"}) => {
  const normalizedSize = ["sm", "md", "lg"].includes(size) ? size : "lg";
  return <div className={`ch-image-${normalizedSize}`}>
      <Frame>
        <img src={img} alt={alt} />
      </Frame>
    </div>;
};

> 이 예시에서는
> 확장 가능한 간단한 ClickHouse 클러스터를 설정하는 방법을 알아봅니다. 5대의 서버가 구성됩니다. 이 중 2대는 데이터를 세그먼트로 분산하는 데 사용됩니다.
> 나머지 3대의 서버는 클러스터 조정을 위해 사용됩니다.

설정할 클러스터의 아키텍처는 아래와 같습니다:

<Image img="https://mintcdn.com/private-7c7dfe99/NvnCM4vX9aZ07JxK/images/deployment-guides/replication-sharding-examples/sharding.webp?fit=max&auto=format&n=NvnCM4vX9aZ07JxK&q=85&s=bb9b9d42024b0aed234f3cc36f854628" size="md" alt="2개의 세그먼트와 1개의 레플리카를 위한 아키텍처 다이어그램" width="1200" height="800" data-path="images/deployment-guides/replication-sharding-examples/sharding.webp" />

<Note>
  ClickHouse 서버와 ClickHouse Keeper를 동일한 서버에서 함께 실행할 수는 있지만,
  프로덕션 환경에서는 ClickHouse Keeper용 *전용* 호스트를 사용하는 것을 강력히 권장합니다.
  이 예시에서도 이 방식을 보여드립니다.

  Keeper 서버는 더 작은 사양으로도 충분하며, 일반적으로 각 Keeper 서버에는 4GB RAM이면 충분합니다.
  ClickHouse 서버 규모가 커지기 전까지는 그렇습니다.
</Note>

<div id="pre-requisites">
  ## 사전 요구 사항
</div>

* 이전에 [로컬 ClickHouse 서버](/docs/ko/get-started/setup/install)를 설정한 적이 있습니다
* [설정 파일](/docs/ko/concepts/features/configuration/server-config/configuration-files) 등 ClickHouse의 기본 구성 개념을 이해하고 있습니다
* 사용 중인 환경에 Docker가 설치되어 있습니다

<Steps>
  <Step title="디렉터리 구조 및 테스트 환경 설정" id="set-up">
    <Tip>
      **예시 파일**

      다음 단계에서는 클러스터를 처음부터 설정하는 방법을 안내합니다. 이 단계를 건너뛰고 바로
      클러스터를 실행하려면, examples 리포지토리의 ['docker-compose-recipes' 디렉터리](https://github.com/ClickHouse/examples/tree/main/docker-compose-recipes/recipes)에서 예시
      파일을 가져올 수 있습니다.
    </Tip>

    이 튜토리얼에서는 [Docker compose](https://docs.docker.com/compose/)를 사용하여 ClickHouse 클러스터를 구성합니다. 이 설정은 별도의 로컬 머신, 가상 머신 또는 클라우드 인스턴스 환경에서도 동작하도록 수정할 수 있습니다.

    다음 명령어를 실행하여 이 예시에 필요한 디렉터리 구조를 설정하십시오.

    ```bash theme={null}
    mkdir cluster_2S_1R
    cd cluster_2S_1R

    # Create clickhouse-keeper directories
    for i in {01..03}; do
      mkdir -p fs/volumes/clickhouse-keeper-${i}/etc/clickhouse-keeper
    done

    # Create clickhouse-server directories
    for i in {01..02}; do
      mkdir -p fs/volumes/clickhouse-${i}/etc/clickhouse-server
    done
    ```

    다음 `docker-compose.yml` 파일을 `cluster_2S_1R` 디렉터리에 추가하십시오:

    ```yaml title="docker-compose.yml" theme={null}
    version: '3.8'
    services:
      clickhouse-01:
        image: "clickhouse/clickhouse-server:latest"
        user: "101:101"
        container_name: clickhouse-01
        hostname: clickhouse-01
        networks:
          cluster_2S_1R:
            ipv4_address: 192.168.7.1
        volumes:
          - ${PWD}/fs/volumes/clickhouse-01/etc/clickhouse-server/config.d/config.xml:/etc/clickhouse-server/config.d/config.xml
          - ${PWD}/fs/volumes/clickhouse-01/etc/clickhouse-server/users.d/users.xml:/etc/clickhouse-server/users.d/users.xml
        ports:
          - "127.0.0.1:8123:8123"
          - "127.0.0.1:9000:9000"
        depends_on:
          - clickhouse-keeper-01
          - clickhouse-keeper-02
          - clickhouse-keeper-03
      clickhouse-02:
        image: "clickhouse/clickhouse-server:latest"
        user: "101:101"
        container_name: clickhouse-02
        hostname: clickhouse-02
        networks:
          cluster_2S_1R:
            ipv4_address: 192.168.7.2
        volumes:
          - ${PWD}/fs/volumes/clickhouse-02/etc/clickhouse-server/config.d/config.xml:/etc/clickhouse-server/config.d/config.xml
          - ${PWD}/fs/volumes/clickhouse-02/etc/clickhouse-server/users.d/users.xml:/etc/clickhouse-server/users.d/users.xml
        ports:
          - "127.0.0.1:8124:8123"
          - "127.0.0.1:9001:9000"
        depends_on:
          - clickhouse-keeper-01
          - clickhouse-keeper-02
          - clickhouse-keeper-03
      clickhouse-keeper-01:
        image: "clickhouse/clickhouse-keeper:latest-alpine"
        user: "101:101"
        container_name: clickhouse-keeper-01
        hostname: clickhouse-keeper-01
        networks:
          cluster_2S_1R:
            ipv4_address: 192.168.7.5
        volumes:
         - ${PWD}/fs/volumes/clickhouse-keeper-01/etc/clickhouse-keeper/keeper_config.xml:/etc/clickhouse-keeper/keeper_config.xml
        ports:
            - "127.0.0.1:9181:9181"
      clickhouse-keeper-02:
        image: "clickhouse/clickhouse-keeper:latest-alpine"
        user: "101:101"
        container_name: clickhouse-keeper-02
        hostname: clickhouse-keeper-02
        networks:
          cluster_2S_1R:
            ipv4_address: 192.168.7.6
        volumes:
         - ${PWD}/fs/volumes/clickhouse-keeper-02/etc/clickhouse-keeper/keeper_config.xml:/etc/clickhouse-keeper/keeper_config.xml
        ports:
            - "127.0.0.1:9182:9181"
      clickhouse-keeper-03:
        image: "clickhouse/clickhouse-keeper:latest-alpine"
        user: "101:101"
        container_name: clickhouse-keeper-03
        hostname: clickhouse-keeper-03
        networks:
          cluster_2S_1R:
            ipv4_address: 192.168.7.7
        volumes:
         - ${PWD}/fs/volumes/clickhouse-keeper-03/etc/clickhouse-keeper/keeper_config.xml:/etc/clickhouse-keeper/keeper_config.xml
        ports:
            - "127.0.0.1:9183:9181"
    networks:
      cluster_2S_1R:
        driver: bridge
        ipam:
          config:
            - subnet: 192.168.7.0/24
              gateway: 192.168.7.254
    ```

    다음 하위 디렉터리와 파일을 생성하십시오.

    ```bash theme={null}
    for i in {01..02}; do
      mkdir -p fs/volumes/clickhouse-${i}/etc/clickhouse-server/config.d
      mkdir -p fs/volumes/clickhouse-${i}/etc/clickhouse-server/users.d
      touch fs/volumes/clickhouse-${i}/etc/clickhouse-server/config.d/config.xml
      touch fs/volumes/clickhouse-${i}/etc/clickhouse-server/users.d/users.xml
    done
    ```

    * `config.d` 디렉터리에는 ClickHouse 서버 설정 파일 `config.xml`이 있으며,
      여기에서 각 ClickHouse 노드의 사용자 지정 구성을 정의합니다. 이
      구성은 모든 ClickHouse 설치에 함께 제공되는 기본 `config.xml` ClickHouse 설정
      파일과 결합됩니다.
    * `users.d` 디렉터리에는 사용자 설정 파일 `users.xml`이 있으며,
      여기에서 사용자별 사용자 지정 구성을 정의합니다. 이 구성은 모든
      ClickHouse 설치에 함께 제공되는 기본 ClickHouse `users.xml` 설정 파일과 결합됩니다.

    <Tip>
      **사용자 지정 구성 디렉터리**

      자체 구성을 작성할 때는 `/etc/clickhouse-server/config.xml` 및 `etc/clickhouse-server/users.xml`의
      기본 구성을 직접 수정하기보다 `config.d` 및 `users.d` 디렉터리를
      사용하는 것을 권장합니다.

      다음 줄은

      ```xml theme={null}
      <clickhouse replace="true">
      ```

      `config.d` 및 `users.d` 디렉터리에 정의된 구성 섹션이
      기본 `config.xml` 및 `users.xml` 파일에 정의된 기본 구성 섹션을
      재정의하도록 합니다.
    </Tip>
  </Step>

  <Step title="ClickHouse 노드 구성" id="configure-clickhouse-servers">
    ### 서버 설정

    이제 `fs/volumes/clickhouse-{}/etc/clickhouse-server/config.d`에 있는 각 빈 설정 파일 `config.xml`을 수정하십시오. 아래에 강조된 줄은 각 노드에 맞게 변경해야 합니다:

    ```xml highlight={9,54-57} theme={null}
    <clickhouse replace="true">
        <logger>
            <level>debug</level>
            <log>/var/log/clickhouse-server/clickhouse-server.log</log>
            <errorlog>/var/log/clickhouse-server/clickhouse-server.err.log</errorlog>
            <size>1000M</size>
            <count>3</count>
        </logger>
        <display_name>cluster_2S_1R node 1</display_name>
        <listen_host>0.0.0.0</listen_host>
        <http_port>8123</http_port>
        <tcp_port>9000</tcp_port>
        <user_directories>
            <users_xml>
                <path>users.xml</path>
            </users_xml>
            <local_directory>
                <path>/var/lib/clickhouse/access/</path>
            </local_directory>
        </user_directories>
        <distributed_ddl>
            <path>/clickhouse/task_queue/ddl</path>
        </distributed_ddl>
        <remote_servers>
            <cluster_2S_1R>
                <shard>
                    <replica>
                        <host>clickhouse-01</host>
                        <port>9000</port>
                    </replica>
                </shard>
                <shard>
                    <replica>
                        <host>clickhouse-02</host>
                        <port>9000</port>
                    </replica>
                </shard>
            </cluster_2S_1R>
        </remote_servers>
        <zookeeper>
            <node>
                <host>clickhouse-keeper-01</host>
                <port>9181</port>
            </node>
            <node>
                <host>clickhouse-keeper-02</host>
                <port>9181</port>
            </node>
            <node>
                <host>clickhouse-keeper-03</host>
                <port>9181</port>
            </node>
        </zookeeper>
        <macros>
            <shard>01</shard>
            <replica>01</replica>
        </macros>
    </clickhouse>
    ```

    | 디렉터리                                                      | File                                                                                                                                                                             |
    | --------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
    | `fs/volumes/clickhouse-01/etc/clickhouse-server/config.d` | [`config.xml`](https://github.com/ClickHouse/examples/blob/main/docker-compose-recipes/recipes/cluster_2S_1R/fs/volumes/clickhouse-01/etc/clickhouse-server/config.d/config.xml) |
    | `fs/volumes/clickhouse-02/etc/clickhouse-server/config.d` | [`config.xml`](https://github.com/ClickHouse/examples/blob/main/docker-compose-recipes/recipes/cluster_2S_1R/fs/volumes/clickhouse-02/etc/clickhouse-server/config.d/config.xml) |

    위 설정 파일의 각 섹션에 대해서는 아래에서 자세히 설명합니다.

    #### 네트워킹 및 로깅

    listen
    host 설정을 활성화하면 네트워크 인터페이스에 대한 외부 통신이 허용됩니다. 이렇게 하면 다른
    호스트에서 ClickHouse 서버 호스트에 접근할 수 있습니다:

    ```xml theme={null}
    <listen_host>0.0.0.0</listen_host>
    ```

    HTTP API 포트는 `8123`으로 설정됩니다:

    ```xml theme={null}
    <http_port>8123</http_port>
    ```

    clickhouse-client
    및 기타 네이티브 ClickHouse 도구와 clickhouse-server 및 기타 clickhouse-servers 간에 ClickHouse 네이티브 프로토콜로 통신하는 데 사용하는 TCP 포트는 `9000`으로 설정됩니다:

    ```xml theme={null}
    <tcp_port>9000</tcp_port>
    ```

    로깅은 `<logger>` 블록에서 정의됩니다. 다음 예시 구성은 1000M 크기에서 최대 3회 롤오버되는 디버그 로그를 설정합니다:

    ```xml theme={null}
    <logger>
        <level>debug</level>
        <log>/var/log/clickhouse-server/clickhouse-server.log</log>
        <errorlog>/var/log/clickhouse-server/clickhouse-server.err.log</errorlog>
        <size>1000M</size>
        <count>3</count>
    </logger>
    ```

    로깅 구성에 대한 자세한 내용은 기본 ClickHouse [설정 파일](https://github.com/ClickHouse/ClickHouse/blob/master/programs/server/config.xml)에 포함된 주석을 참조하십시오.

    #### 클러스터 구성

    클러스터 구성은 `<remote_servers>` 블록에서 설정합니다.
    여기서 클러스터 이름 `cluster_2S_1R`을 정의합니다.

    `<cluster_2S_1R></cluster_2S_1R>` 블록은 `<shard></shard>` 및 `<replica></replica>` 설정을 사용하여 클러스터의 레이아웃을 정의하며, `ON CLUSTER` 절을 통해 클러스터 전체에서 실행되는 분산 DDL 쿼리의 템플릿 역할을 합니다. 기본적으로 분산 DDL 쿼리는 허용되지만, `allow_distributed_ddl_queries` 설정으로 비활성화할 수도 있습니다.

    세그먼트당 레플리카가 하나뿐이므로 `internal_replication`은 기본값 false로 유지됩니다.

    ```xml theme={null}
    <remote_servers>
        <cluster_2S_1R>
            <shard>
                <replica>
                    <host>clickhouse-01</host>
                    <port>9000</port>
                </replica>
            </shard>
            <shard>
                <replica>
                    <host>clickhouse-02</host>
                    <port>9000</port>
                </replica>
            </shard>
        </cluster_2S_1R>
    </remote_servers>
    ```

    각 서버에는 다음 매개변수를 지정합니다:

    | 매개변수   | 설명                                                                                                                                                                   | 기본값 |
    | ------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --- |
    | `host` | 원격 서버의 주소입니다. 도메인 또는 IPv4/IPv6 주소를 사용할 수 있습니다. 도메인을 지정하면 서버 시작 시 DNS 조회를 수행하며, 그 결과는 서버가 실행되는 동안 유지됩니다. DNS 조회에 실패하면 서버가 시작되지 않습니다. DNS 레코드를 변경한 경우 서버를 다시 시작해야 합니다. | -   |
    | `port` | 메시지 교환에 사용하는 TCP 포트입니다(설정의 `tcp_port`이며, 일반적으로 9000으로 설정됩니다). `http_port`와 혼동하지 마십시오.                                                                                | -   |

    #### Keeper 구성

    `<ZooKeeper>` 섹션은 ClickHouse Keeper(또는 ZooKeeper)가 실행 중인 위치를 ClickHouse에 알려줍니다.
    ClickHouse Keeper 클러스터를 사용하는 경우, 클러스터의 각 `<node>`에 대해 `<host>` 및 `<port>` 태그를 사용하여 호스트명과 포트 번호를 지정해야 합니다.

    ClickHouse Keeper 설정은 튜토리얼의 다음 단계에서 설명합니다.

    ```xml theme={null}
    <zookeeper>
        <node>
            <host>clickhouse-keeper-01</host>
            <port>9181</port>
        </node>
        <node>
            <host>clickhouse-keeper-02</host>
            <port>9181</port>
        </node>
        <node>
            <host>clickhouse-keeper-03</host>
            <port>9181</port>
        </node>
    </zookeeper>
    ```

    <Note>
      ClickHouse Keeper를 ClickHouse 서버와 동일한 서버에서 실행할 수는 있지만,
      프로덕션 환경에서는 ClickHouse Keeper를 전용 호스트에서 실행하는 것을 강력히 권장합니다.
    </Note>

    #### 매크로 구성

    또한 `<macros>` 섹션은 복제된 테이블에 대한 매개변수 치환을 정의하는 데 사용됩니다. 이 값들은 `system.macros`에 나열되며, 쿼리에서 `{shard}` 및 `{replica}` 같은 치환 값을 사용할 수 있습니다.

    ```xml theme={null}
    <macros>
        <shard>01</shard>
        <replica>01</replica>
    </macros>
    ```

    <Note>
      이는 클러스터 구성에 따라 각기 다르게 정의됩니다.
    </Note>

    ### 사용자 구성

    이제 `fs/volumes/clickhouse-{}/etc/clickhouse-server/users.d`에 위치한 빈 설정 파일 `users.xml`을 각각 아래 내용으로 수정하십시오.

    ```xml title="/users.d/users.xml" theme={null}
    <?xml version="1.0"?>
    <clickhouse replace="true">
        <profiles>
            <default>
                <max_memory_usage>10000000000</max_memory_usage>
                <use_uncompressed_cache>0</use_uncompressed_cache>
                <load_balancing>in_order</load_balancing>
                <log_queries>1</log_queries>
            </default>
        </profiles>
        <users>
            <default>
                <access_management>1</access_management>
                <profile>default</profile>
                <networks>
                    <ip>::/0</ip>
                </networks>
                <quota>default</quota>
                <access_management>1</access_management>
                <named_collection_control>1</named_collection_control>
                <show_named_collections>1</show_named_collections>
                <show_named_collections_secrets>1</show_named_collections_secrets>
            </default>
        </users>
        <quotas>
            <default>
                <interval>
                    <duration>3600</duration>
                    <queries>0</queries>
                    <errors>0</errors>
                    <result_rows>0</result_rows>
                    <read_rows>0</read_rows>
                    <execution_time>0</execution_time>
                </interval>
            </default>
        </quotas>
    </clickhouse>
    ```

    | 디렉터리                                                     | File                                                                                                                                                                          |
    | -------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
    | `fs/volumes/clickhouse-01/etc/clickhouse-server/users.d` | [`users.xml`](https://github.com/ClickHouse/examples/blob/main/docker-compose-recipes/recipes/cluster_2S_1R/fs/volumes/clickhouse-01/etc/clickhouse-server/users.d/users.xml) |
    | `fs/volumes/clickhouse-02/etc/clickhouse-server/users.d` | [`users.xml`](https://github.com/ClickHouse/examples/blob/main/docker-compose-recipes/recipes/cluster_2S_1R/fs/volumes/clickhouse-02/etc/clickhouse-server/users.d/users.xml) |

    이 예시에서는 편의상 기본 사용자를 비밀번호 없이 구성합니다.
    실제 운영 환경에서는 권장하지 않는 방식입니다.

    <Note>
      이 예시에서는 클러스터의 모든 노드에서 `users.xml` 파일이 동일합니다.
    </Note>
  </Step>

  <Step title="ClickHouse Keeper 구성" id="configure-clickhouse-keeper-nodes">
    ### Keeper 설정

    복제가 작동하려면 ClickHouse Keeper 클러스터를 설정하고
    구성해야 합니다. ClickHouse Keeper는 데이터 복제를 위한 조정 시스템을 제공하며,
    대체 구성 요소로 Zookeeper를 사용할 수도 있습니다.
    하지만 ClickHouse Keeper는 ZooKeeper보다 더 나은 보장과
    신뢰성을 제공하고 리소스도 더 적게 사용하므로 권장됩니다. 고가용성을 확보하고
    쿼럼을 유지하려면 최소 3개의 ClickHouse Keeper 노드를 실행하는 것이 좋습니다.

    <Note>
      ClickHouse Keeper는 클러스터의 어느 노드에서든 ClickHouse와 함께 실행할 수 있지만,
      ClickHouse Keeper 클러스터를 데이터베이스 클러스터와 독립적으로 스케일링하고
      관리할 수 있도록 전용 노드에서 실행하는 것이 좋습니다.
    </Note>

    다음 명령을 사용하여 예시 폴더의 루트에서
    각 ClickHouse Keeper 노드용 `keeper_config.xml` 파일을 생성하세요:

    ```bash theme={null}
    for i in {01..03}; do
      touch fs/volumes/clickhouse-keeper-${i}/etc/clickhouse-keeper/keeper_config.xml
    done
    ```

    각 노드의
    디렉터리 `fs/volumes/clickhouse-keeper-{}/etc/clickhouse-keeper`에 생성된 빈 설정 파일을 수정합니다. 아래에서
    강조 표시된 줄은 각 노드별로 맞게 변경해야 합니다:

    ```xml title="/clickhouse-keeper/keeper_config.xml" highlight={12} theme={null}
    <clickhouse replace="true">
        <logger>
            <level>information</level>
            <log>/var/log/clickhouse-keeper/clickhouse-keeper.log</log>
            <errorlog>/var/log/clickhouse-keeper/clickhouse-keeper.err.log</errorlog>
            <size>1000M</size>
            <count>3</count>
        </logger>
        <listen_host>0.0.0.0</listen_host>
        <keeper_server>
            <tcp_port>9181</tcp_port>
            <server_id>1</server_id>
            <log_storage_path>/var/lib/clickhouse/coordination/log</log_storage_path>
            <snapshot_storage_path>/var/lib/clickhouse/coordination/snapshots</snapshot_storage_path>
            <coordination_settings>
                <operation_timeout_ms>10000</operation_timeout_ms>
                <session_timeout_ms>30000</session_timeout_ms>
                <raft_logs_level>information</raft_logs_level>
            </coordination_settings>
            <raft_configuration>
                <server>
                    <id>1</id>
                    <hostname>clickhouse-keeper-01</hostname>
                    <port>9234</port>
                </server>
                <server>
                    <id>2</id>
                    <hostname>clickhouse-keeper-02</hostname>
                    <port>9234</port>
                </server>
                <server>
                    <id>3</id>
                    <hostname>clickhouse-keeper-03</hostname>
                    <port>9234</port>
                </server>
            </raft_configuration>
        </keeper_server>
    </clickhouse>
    ```

    | 디렉터리                                                    | 파일                                                                                                                                                                                           |
    | ------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
    | `fs/volumes/clickhouse-keeper-01/etc/clickhouse-keeper` | [`keeper_config.xml`](https://github.com/ClickHouse/examples/blob/main/docker-compose-recipes/recipes/cluster_2S_1R/fs/volumes/clickhouse-keeper-01/etc/clickhouse-keeper/keeper_config.xml) |
    | `fs/volumes/clickhouse-keeper-02/etc/clickhouse-keeper` | [`keeper_config.xml`](https://github.com/ClickHouse/examples/blob/main/docker-compose-recipes/recipes/cluster_2S_1R/fs/volumes/clickhouse-keeper-02/etc/clickhouse-keeper/keeper_config.xml) |
    | `fs/volumes/clickhouse-keeper-03/etc/clickhouse-keeper` | [`keeper_config.xml`](https://github.com/ClickHouse/examples/blob/main/docker-compose-recipes/recipes/cluster_2S_1R/fs/volumes/clickhouse-keeper-03/etc/clickhouse-keeper/keeper_config.xml) |

    각 설정 파일에는 다음과 같은 고유한 구성이 포함되어야 합니다(아래 참조).
    사용할 `server_id`는 cluster 내 해당 ClickHouse Keeper 노드에서 고유해야 하며,
    `<raft_configuration>` 섹션에 정의된 서버 `<id>`와 일치해야 합니다.
    `tcp_port`는 ClickHouse Keeper의 *클라이언트*가 사용하는 포트입니다.

    ```xml theme={null}
    <tcp_port>9181</tcp_port>
    <server_id>{id}</server_id>
    ```

    다음 섹션은 [Raft 합의 알고리즘](https://en.wikipedia.org/wiki/Raft_\(algorithm\))의
    쿼럼에 참여하는 서버를 구성하는 데 사용됩니다:

    ```xml highlight={6} theme={null}
    <raft_configuration>
        <server>
            <id>1</id>
            <hostname>clickhouse-keeper-01</hostname>
            <!-- ClickHouse Keeper 노드 간 통신에 사용되는 TCP 포트 -->
            <port>9234</port>
        </server>
        <server>
            <id>2</id>
            <hostname>clickhouse-keeper-02</hostname>
            <port>9234</port>
        </server>
        <server>
            <id>3</id>
            <hostname>clickhouse-keeper-03</hostname>
            <port>9234</port>
        </server>
    </raft_configuration>
    ```

    <Tip>
      **ClickHouse Cloud로 관리가 간소화됩니다**

      [ClickHouse Cloud](/docs/ko/products/cloud/getting-started/intro)
      에서는 세그먼트와 레플리카 관리에 따른 운영 부담이 사라집니다. 이
      플랫폼은 고가용성, 복제, 스케일링을 자동으로 처리합니다.
      컴퓨트와 스토리지는 분리되어 있으며, 수요에 따라 수동
      구성이나 지속적인 유지 관리 없이 확장됩니다.

      [자세히 보기](/docs/ko/products/cloud/features/autoscaling/overview)
    </Tip>
  </Step>

  <Step title="설정 확인" id="test-the-setup">
    로컬 머신에서 Docker가 실행 중인지 확인하십시오.
    `cluster_2S_1R` 디렉터리의 루트에서 `docker-compose up` 명령으로 클러스터를 시작하십시오:

    ```bash theme={null}
    docker-compose up -d
    ```

    docker가 ClickHouse 및 Keeper 이미지를 가져오기 시작하고,
    이어서 컨테이너를 시작하는 것을 볼 수 있습니다:

    ```bash theme={null}
    [+] Running 6/6
     ✔ Network cluster_2s_1r_default   Created
     ✔ Container clickhouse-keeper-03  Started
     ✔ Container clickhouse-keeper-02  Started
     ✔ Container clickhouse-keeper-01  Started
     ✔ Container clickhouse-01         Started
     ✔ Container clickhouse-02         Started
    ```

    클러스터가 실행 중인지 확인하려면 `clickhouse-01` 또는 `clickhouse-02` 중 하나에 연결한 다음 아래
    쿼리를 실행하십시오. 첫 번째 노드에 연결하는 명령은 다음과 같습니다:

    ```bash theme={null}
    # Connect to any node
    docker exec -it clickhouse-01 clickhouse-client
    ```

    성공하면 ClickHouse client 프롬프트가 표시됩니다:

    ```response theme={null}
    cluster_2S_1R node 1 :)
    ```

    다음 쿼리를 실행하여 각 호스트에 어떤 클러스터 토폴로지가 정의되어 있는지 확인하십시오:

    ```sql title="Query" theme={null}
    SELECT 
        cluster,
        shard_num,
        replica_num,
        host_name,
        port
    FROM system.clusters;
    ```

    ```response title="Response" theme={null}
       ┌─cluster───────┬─shard_num─┬─replica_num─┬─host_name─────┬─port─┐
    1. │ cluster_2S_1R │         1 │           1 │ clickhouse-01 │ 9000 │
    2. │ cluster_2S_1R │         2 │           1 │ clickhouse-02 │ 9000 │
    3. │ default       │         1 │           1 │ localhost     │ 9000 │
       └───────────────┴───────────┴─────────────┴───────────────┴──────┘
    ```

    다음 쿼리를 실행하여 ClickHouse Keeper 클러스터의 상태를 확인하세요:

    ```sql title="Query" theme={null}
    SELECT *
    FROM system.zookeeper
    WHERE path IN ('/', '/clickhouse')
    ```

    ```response title="Response" theme={null}
       ┌─name───────┬─value─┬─path────────┐
    1. │ task_queue │       │ /clickhouse │
    2. │ sessions   │       │ /clickhouse │
    3. │ clickhouse │       │ /           │
    4. │ keeper     │       │ /           │
       └────────────┴───────┴─────────────┘
    ```

    `mntr` 명령은 ClickHouse Keeper가
    실행 중인지 확인하고, 3개의 Keeper 노드가 서로 어떤 상태인지에 대한 정보를 확인하는 데에도 일반적으로 사용됩니다.
    이 예시에서 사용된 구성에서는 3개의 노드가 함께 동작합니다.
    노드들은 리더를 선출하고, 나머지 노드들은 팔로워가 됩니다.

    `mntr` 명령은 성능 관련 정보와 함께 특정
    노드가 팔로워인지 리더인지에 대한 정보도 제공합니다.

    <Tip>
      `mntr` 명령을 Keeper로 보내려면 `netcat`를 설치해야 할 수 있습니다.
      다운로드 정보는 [nmap.org](https://nmap.org/ncat/) 페이지를 참조하십시오.
    </Tip>

    각 Keeper 노드의 상태를 확인하려면 `clickhouse-keeper-01`, `clickhouse-keeper-02`,
    `clickhouse-keeper-03`의 셸에서 아래 명령을 실행하십시오. `clickhouse-keeper-01`용 명령은
    아래와 같습니다:

    ```bash theme={null}
    docker exec -it clickhouse-keeper-01  /bin/sh -c 'echo mntr | nc 127.0.0.1 9181'
    ```

    아래는 팔로워 노드에서 반환된 응답의 예시입니다:

    ```response title="Response" highlight={9} theme={null}
    zk_version      v23.3.1.2823-testing-46e85357ce2da2a99f56ee83a079e892d7ec3726
    zk_avg_latency  0
    zk_max_latency  0
    zk_min_latency  0
    zk_packets_received     0
    zk_packets_sent 0
    zk_num_alive_connections        0
    zk_outstanding_requests 0
    zk_server_state follower
    zk_znode_count  6
    zk_watch_count  0
    zk_ephemerals_count     0
    zk_approximate_data_size        1271
    zk_key_arena_size       4096
    zk_latest_snapshot_size 0
    zk_open_file_descriptor_count   46
    zk_max_file_descriptor_count    18446744073709551615
    ```

    아래는 leader 노드의 응답 예시입니다:

    ```response title="Response" highlight={9,18-19} theme={null}
    zk_version      v23.3.1.2823-testing-46e85357ce2da2a99f56ee83a079e892d7ec3726
    zk_avg_latency  0
    zk_max_latency  0
    zk_min_latency  0
    zk_packets_received     0
    zk_packets_sent 0
    zk_num_alive_connections        0
    zk_outstanding_requests 0
    zk_server_state leader
    zk_znode_count  6
    zk_watch_count  0
    zk_ephemerals_count     0
    zk_approximate_data_size        1271
    zk_key_arena_size       4096
    zk_latest_snapshot_size 0
    zk_open_file_descriptor_count   48
    zk_max_file_descriptor_count    18446744073709551615
    zk_followers    2
    zk_synced_followers     2
    ```

    이로써 2개의 세그먼트와 각 세그먼트당 1개의 레플리카로 구성된 ClickHouse 클러스터를 성공적으로 설정했습니다.
    다음 단계에서는 클러스터에 테이블을 생성합니다.
  </Step>

  <Step title="데이터베이스 생성" id="creating-a-database">
    이제 클러스터가 올바르게 설정되어 실행 중임을 확인했으므로,
    [영국 부동산 가격](/docs/ko/get-started/sample-datasets/uk-price-paid)
    예시 데이터셋 튜토리얼에서 사용한 것과 동일한 테이블을 다시 생성합니다. 이 데이터셋은
    1995년 이후 잉글랜드와 웨일스의 부동산 거래 가격 데이터 약 3천만 행으로 구성됩니다.

    각 호스트의 클라이언트에 연결하려면, 별도의 터미널
    탭 또는 창에서 다음 각 명령을 실행하십시오:

    ```bash theme={null}
    docker exec -it clickhouse-01 clickhouse-client
    docker exec -it clickhouse-02 clickhouse-client
    ```

    각 호스트의 clickhouse-client에서 아래 쿼리를 실행하여
    기본 데이터베이스 외에는 아직 생성된 데이터베이스가 없는지 확인할 수 있습니다:

    ```sql title="Query" theme={null}
    SHOW DATABASES;
    ```

    ```response title="Response" theme={null}
       ┌─name───────────────┐
    1. │ INFORMATION_SCHEMA │
    2. │ default            │
    3. │ information_schema │
    4. │ system             │
       └────────────────────┘
    ```

    `clickhouse-01` 클라이언트에서 `ON CLUSTER` 절을 사용해 `uk`라는 새 데이터베이스를 생성하는 다음 **분산** DDL 쿼리를 실행하십시오:

    ```sql highlight={2} theme={null}
    CREATE DATABASE IF NOT EXISTS uk 
    ON CLUSTER cluster_2S_1R;
    ```

    각 호스트의 클라이언트에서 이전과 동일한 쿼리를 다시 실행하여,
    쿼리를 `clickhouse-01`에서만 실행했더라도 데이터베이스가 클러스터 전체에 생성되었는지
    확인할 수 있습니다:

    ```sql theme={null}
    SHOW DATABASES;
    ```

    ```response highlight={6} theme={null}
       ┌─name───────────────┐
    1. │ INFORMATION_SCHEMA │
    2. │ default            │
    3. │ information_schema │
    4. │ system             │
    5. │ uk                 │
       └────────────────────┘
    ```
  </Step>

  <Step title="클러스터에 테이블 생성" id="creating-a-table">
    이제 데이터베이스가 생성되었으므로 테이블(table)을 생성합니다.
    호스트 클라이언트 어느 곳에서든 다음 쿼리를 실행하세요:

    ```sql highlight={2} theme={null}
    CREATE TABLE IF NOT EXISTS uk.uk_price_paid_local
    ON CLUSTER cluster_2S_1R
    (
        price UInt32,
        date Date,
        postcode1 LowCardinality(String),
        postcode2 LowCardinality(String),
        type Enum8('terraced' = 1, 'semi-detached' = 2, 'detached' = 3, 'flat' = 4, 'other' = 0),
        is_new UInt8,
        duration Enum8('freehold' = 1, 'leasehold' = 2, 'unknown' = 0),
        addr1 String,
        addr2 String,
        street LowCardinality(String),
        locality LowCardinality(String),
        town LowCardinality(String),
        district LowCardinality(String),
        county LowCardinality(String)
    )
    ENGINE = MergeTree
    ORDER BY (postcode1, postcode2, addr1, addr2);
    ```

    원래 `CREATE` statement에서 사용된 쿼리와
    [UK property prices](/docs/ko/get-started/sample-datasets/uk-price-paid) 예시 데이터셋 튜토리얼의 쿼리는 동일하며,
    차이점은 `ON CLUSTER` 절뿐입니다.

    `ON CLUSTER` 절은 `CREATE`, `DROP`, `ALTER`, `RENAME`과 같은 DDL (Data Definition Language)
    쿼리를 분산 실행하도록 설계되었으며, 이러한
    스키마 변경이 cluster의 모든 노드에 적용되도록 보장합니다.

    아래 쿼리를 각 호스트의 클라이언트에서 실행하여 테이블이 cluster 전체에 생성되었는지 확인할 수 있습니다:

    ```sql title="Query" theme={null}
    SHOW TABLES IN uk;
    ```

    ```response title="Response" theme={null}
       ┌─name────────────────┐
    1. │ uk_price_paid_local │
       └─────────────────────┘
    ```

    영국 부동산 실거래가 데이터를 삽입하기 전에, 어느 호스트에서 일반 테이블에 데이터를 삽입하면
    어떤 일이 일어나는지 간단한 실험으로 확인해 보겠습니다.

    어느 호스트에서든 다음 쿼리를 실행하여 테스트 데이터베이스와 테이블을 생성하십시오:

    ```sql theme={null}
    CREATE DATABASE IF NOT EXISTS test ON CLUSTER cluster_2S_1R;
    CREATE TABLE test.test_table ON CLUSTER cluster_2S_1R
    (
        `id` UInt64,
        `name` String
    )
    ENGINE = MergeTree()
    ORDER BY id;
    ```

    이제 `clickhouse-01`에서 다음 `INSERT` 쿼리를 실행하세요:

    ```sql theme={null}
    INSERT INTO test.test_table (id, name) VALUES (1, 'Clicky McClickface');
    ```

    `clickhouse-02`로 전환한 후 다음 `INSERT` 쿼리를 실행하세요:

    ```sql title="Query" theme={null}
    INSERT INTO test.test_table (id, name) VALUES (1, 'Alexey Milovidov');
    ```

    이제 `clickhouse-01` 또는 `clickhouse-02`에서 다음 쿼리를 실행하십시오:

    ```sql theme={null}
    -- from clickhouse-01
    SELECT * FROM test.test_table;
    --   ┌─id─┬─name───────────────┐
    -- 1.│  1 │ Clicky McClickface │
    --   └────┴────────────────────┘

    --from clickhouse-02
    SELECT * FROM test.test_table;
    --   ┌─id─┬─name───────────────┐
    -- 1.│  1 │ Alexey Milovidov   │
    --   └────┴────────────────────┘
    ```

    `ReplicatedMergeTree` 테이블과 달리, 해당 호스트의 테이블에 삽입된 행만 반환되며 두 행이 모두 반환되지는 않는다는 점을 확인할 수 있습니다.

    두 세그먼트 전반의 데이터를 읽으려면, 모든 세그먼트에 걸친 쿼리를 처리하고,
    여기에서 select 쿼리를 실행할 때는 두 세그먼트의 데이터를 결합하며
    insert 쿼리를 실행할 때는 두 세그먼트 모두에 데이터를 삽입할 수 있는 인터페이스가 필요합니다.

    ClickHouse에서는 이 인터페이스를 **분산 테이블**이라고 하며,
    [`Distributed`](/docs/ko/reference/engines/table-engines/special/distributed) 테이블 엔진을 사용해 생성합니다. 어떻게 작동하는지 살펴보겠습니다.
  </Step>

  <Step title="분산 테이블 생성" id="create-distributed-table">
    다음 쿼리를 사용하여 분산 테이블을 생성하세요:

    ```sql theme={null}
    CREATE TABLE test.test_table_dist ON CLUSTER cluster_2S_1R AS test.test_table
    ENGINE = Distributed('cluster_2S_1R', 'test', 'test_table', rand())
    ```

    이 예시에서는 `rand()` 함수를 세그먼트 분할 키로 선택하여
    삽입되는 데이터가 세그먼트 전반에 무작위로 분산되도록 합니다.

    이제 어느 호스트에서든 분산 테이블을 쿼리하면
    이전 예시와는 달리 두 호스트에 삽입된 두 행이 모두 반환됩니다:

    ```sql theme={null}
    SELECT * FROM test.test_table_dist;
    ```

    ```response theme={null}
       ┌─id─┬─name───────────────┐
    1. │  1 │ Alexey Milovidov   │
    2. │  1 │ Clicky McClickface │
       └────┴────────────────────┘
    ```

    영국 부동산 가격 데이터에도 동일하게 적용하겠습니다. 어느 호스트 클라이언트에서든
    다음 쿼리를 실행하여, 앞서 `ON CLUSTER`로 생성한 기존 테이블을 사용해
    분산 테이블을 생성하십시오:

    ```sql theme={null}
    CREATE TABLE IF NOT EXISTS uk.uk_price_paid_distributed
    ON CLUSTER cluster_2S_1R
    ENGINE = Distributed('cluster_2S_1R', 'uk', 'uk_price_paid_local', rand());
    ```
  </Step>

  <Step title="분산 테이블에 데이터 삽입" id="inserting-data-into-distributed-table">
    이제 호스트 중 하나에 연결하여 데이터를 삽입하십시오:

    ```sql theme={null}
    INSERT INTO uk.uk_price_paid_distributed
    SELECT
        toUInt32(price_string) AS price,
        parseDateTimeBestEffortUS(time) AS date,
        splitByChar(' ', postcode)[1] AS postcode1,
        splitByChar(' ', postcode)[2] AS postcode2,
        transform(a, ['T', 'S', 'D', 'F', 'O'], ['terraced', 'semi-detached', 'detached', 'flat', 'other']) AS type,
        b = 'Y' AS is_new,
        transform(c, ['F', 'L', 'U'], ['freehold', 'leasehold', 'unknown']) AS duration,
        addr1,
        addr2,
        street,
        locality,
        town,
        district,
        county
    FROM url(
        'http://prod1.publicdata.landregistry.gov.uk.s3-website-eu-west-1.amazonaws.com/pp-complete.csv',
        'CSV',
        'uuid_string String,
        price_string String,
        time String,
        postcode String,
        a String,
        b String,
        c String,
        addr1 String,
        addr2 String,
        street String,
        locality String,
        town String,
        district String,
        county String,
        d String,
        e String'
    ) SETTINGS max_http_get_redirects=10;
    ```

    데이터가 삽입되면 분산 테이블을 사용하여 행 수를 확인할 수 있습니다:

    ```sql title="Query" theme={null}
    SELECT count(*)
    FROM uk.uk_price_paid_distributed
    ```

    ```response title="Response" theme={null}
       ┌──count()─┐
    1. │ 30212555 │ -- 30.21 million
       └──────────┘
    ```

    두 호스트 중 어느 쪽에서든 다음 쿼리를 실행하면 데이터가 세그먼트 전반에 걸쳐 거의 균등하게 분산되어 있음을 확인할 수 있습니다(어느 세그먼트에 삽입할지는 `rand()`로 결정되므로 실행 결과는 다를 수 있습니다):

    ```sql theme={null}
    -- from clickhouse-01
    SELECT count(*)
    FROM uk.uk_price_paid_local
    --    ┌──count()─┐
    -- 1. │ 15107353 │ -- 15.11 million
    --    └──────────┘

    --from clickhouse-02
    SELECT count(*)
    FROM uk.uk_price_paid_local
    --    ┌──count()─┐
    -- 1. │ 15105202 │ -- 15.11 million
    --    └──────────┘
    ```

    호스트 중 하나에 장애가 발생하면 어떻게 될까요? `clickhouse-01`을 종료하여 이 상황을 시뮬레이션해 보겠습니다:

    ```bash theme={null}
    docker stop clickhouse-01
    ```

    다음 명령을 실행하여 호스트가 중단되었는지 확인하십시오:

    ```bash theme={null}
    docker-compose ps
    ```

    ```response title="Response" theme={null}
    NAME                   IMAGE                                        COMMAND            SERVICE                CREATED          STATUS          PORTS
    clickhouse-02          clickhouse/clickhouse-server:latest          "/entrypoint.sh"   clickhouse-02          X minutes ago    Up X minutes    127.0.0.1:8124->8123/tcp, 127.0.0.1:9001->9000/tcp
    clickhouse-keeper-01   clickhouse/clickhouse-keeper:latest-alpine   "/entrypoint.sh"   clickhouse-keeper-01   X minutes ago    Up X minutes    127.0.0.1:9181->9181/tcp
    clickhouse-keeper-02   clickhouse/clickhouse-keeper:latest-alpine   "/entrypoint.sh"   clickhouse-keeper-02   X minutes ago    Up X minutes    127.0.0.1:9182->9181/tcp
    clickhouse-keeper-03   clickhouse/clickhouse-keeper:latest-alpine   "/entrypoint.sh"   clickhouse-keeper-03   X minutes ago    Up X minutes    127.0.0.1:9183->9181/tcp
    ```

    이제 `clickhouse-02`에서 앞서 분산 테이블에 실행했던 동일한 select 쿼리를 실행하십시오:

    ```sql theme={null}
    SELECT count(*)
    FROM uk.uk_price_paid_distributed
    ```

    ```response title="Response" highlight={6} theme={null}
    Received exception from server (version 25.5.2):
    Code: 279. DB::Exception: Received from localhost:9000. DB::Exception: All connection tries failed. Log:

    Code: 32. DB::Exception: Attempt to read after eof. (ATTEMPT_TO_READ_AFTER_EOF) (version 25.5.2.47 (official build))
    Code: 209. DB::NetException: Timeout: connect timed out: 192.168.7.1:9000 (clickhouse-01:9000, 192.168.7.1, local address: 192.168.7.2:37484, connection timeout 1000 ms). (SOCKET_TIMEOUT) (version 25.5.2.47 (official build))
    Code: 198. DB::NetException: Not found address of host: clickhouse-01: (clickhouse-01:9000, 192.168.7.1, local address: 192.168.7.2:37484). (DNS_ERROR) (version 25.5.2.47 (official build))

    : While executing Remote. (ALL_CONNECTION_TRIES_FAILED)
    ```

    안타깝게도 현재 클러스터는 내결함성(fault-tolerant)을 갖추고 있지 않습니다. 호스트 중 하나에 장애가 발생하면 클러스터가 비정상 상태로 간주되어 쿼리가 실패합니다. [이전 예시](/docs/ko/guides/oss/deployment-and-scaling/examples/1-shard-2-replicas)에서 살펴본 복제된 테이블(Replicated Table)은 호스트 중 하나에 장애가 발생하더라도 데이터를 삽입할 수 있었던 것과는 대조적입니다.
  </Step>
</Steps>

<div id="conclusion">
  ## 결론
</div>

이 클러스터 토폴로지의 장점은 데이터가 서로 다른 호스트에 분산되어
노드당 스토리지를 절반만 사용한다는 점입니다. 더 중요한 점은 쿼리가
두 세그먼트에 걸쳐 처리되므로 메모리 활용 측면에서 더 효율적이고
호스트별 I/O도 줄어든다는 것입니다.

물론 이 클러스터 토폴로지의 가장 큰 단점은
호스트 중 하나를 잃으면 쿼리를 처리할 수 없게 된다는 점입니다.

[다음 예시](/docs/ko/guides/oss/deployment-and-scaling/examples/2-shards-2-replicas)에서는
확장성과 장애 허용을 모두 제공하는 두 개의 세그먼트와 두 개의 레플리카로 구성된 클러스터를
설정하는 방법을 살펴보겠습니다.
