> ## Documentation Index
> Fetch the complete documentation index at: https://private-7c7dfe99-mintlify-8a08bda2.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

> ClickHouse의 할당 프로파일링을 자세히 설명하는 페이지

# 할당 프로파일링

ClickHouse는 전역 메모리 할당자로 [jemalloc](https://github.com/jemalloc/jemalloc)을 사용합니다. jemalloc에는 할당 샘플링과 프로파일링을 위한 도구가 포함되어 있습니다.

ClickHouse와 Keeper에서는 구성 파일, 쿼리 설정, `SYSTEM` 명령, 그리고 Keeper의 4문자 명령(4LW)을 사용해 샘플링을 제어할 수 있습니다. 결과를 확인하는 방법은 여러 가지가 있습니다.

* 쿼리별 분석을 위해 `JemallocSample` 유형으로 샘플을 `system.trace_log`에 수집합니다.
* 내장된 [jemalloc web UI](#jemalloc-web-ui)에서 실시간 메모리 통계를 확인하고 힙 프로파일을 가져옵니다(26.2+).
* [`system.jemalloc_profile_text`](#fetching-heap-profiles-from-sql)를 사용해 현재 힙 프로파일을 SQL에서 직접 쿼리합니다(26.2+).
* 힙 프로파일을 디스크에 플러시한 뒤 [`jeprof`](#analyzing-heap-profile-files-with-jeprof)로 분석합니다.

<Note>
  이 가이드는 25.9+ 버전에 적용됩니다.
  이전 버전은 [25.9 이전 버전용 할당 프로파일링](/ko/concepts/features/performance/allocation-profiling-old)을 확인하십시오.
</Note>

<div id="sampling-allocations">
  ## 메모리 할당 샘플링
</div>

메모리 할당을 샘플링하고 프로파일링하려면 `jemalloc_enable_global_profiler` 설정을 활성화한 상태로 ClickHouse/Keeper를 시작합니다:

```xml theme={null}
<clickhouse>
    <jemalloc_enable_global_profiler>1</jemalloc_enable_global_profiler>
</clickhouse>
```

`jemalloc`은 메모리 할당을 샘플링하고 해당 정보를 내부적으로 저장합니다.

`jemalloc_enable_profiler` 설정을 사용하면 쿼리별 샘플링도 활성화할 수 있습니다.

<Warning>
  **경고**

  ClickHouse는 메모리 할당이 많은 애플리케이션이므로 jemalloc 샘플링 시 성능 오버헤드가 발생할 수 있습니다.
</Warning>

<div id="storing-jemalloc-samples-in-system-trace-log">
  ## `system.trace_log`에 jemalloc 샘플 저장
</div>

`JemallocSample` 유형으로 jemalloc 샘플을 `system.trace_log`에 저장할 수 있습니다.
전체적으로 활성화하려면 `jemalloc_collect_global_profile_samples_in_trace_log` 설정을 사용하세요:

```xml theme={null}
<clickhouse>
    <jemalloc_collect_global_profile_samples_in_trace_log>1</jemalloc_collect_global_profile_samples_in_trace_log>
</clickhouse>
```

<Warning>
  **경고**

  ClickHouse는 메모리 할당이 많이 발생하는 애플리케이션이므로 system.trace\_log에서 모든 샘플을 수집하면 부하가 크게 증가할 수 있습니다.
</Warning>

`jemalloc_collect_profile_samples_in_trace_log` 설정을 사용하면 쿼리별로도 이를 활성화할 수 있습니다.

<div id="example-analyzing-memory-usage-trace-log">
  ### 예시: 쿼리의 메모리 사용량 분석
</div>

먼저 jemalloc 프로파일러를 활성화한 상태에서 쿼리를 실행하고, 샘플을 `system.trace_log`에 수집합니다:

```sql theme={null}
SELECT *
FROM numbers(1000000)
ORDER BY number DESC
SETTINGS max_bytes_ratio_before_external_sort = 0
FORMAT `Null`
SETTINGS jemalloc_enable_profiler = 1, jemalloc_collect_profile_samples_in_trace_log = 1

Query id: 8678d8fe-62c5-48b8-b0cd-26851c62dd75

Ok.

0 rows in set. Elapsed: 0.009 sec. Processed 1.00 million rows, 8.00 MB (108.58 million rows/s., 868.61 MB/s.)
Peak memory usage: 12.65 MiB.
```

<Note>
  ClickHouse를 `jemalloc_enable_global_profiler`와 함께 시작한 경우 `jemalloc_enable_profiler`를 활성화할 필요가 없습니다.
  `jemalloc_collect_global_profile_samples_in_trace_log`와 `jemalloc_collect_profile_samples_in_trace_log`도 동일합니다.
</Note>

`system.trace_log`를 플러시합니다:

```sql theme={null}
SYSTEM FLUSH LOGS trace_log
```

그런 다음 시간에 따른 누적 메모리 사용량을 확인하기 위해 쿼리합니다:

```sql theme={null}
WITH per_bucket AS
(
    SELECT
        event_time_microseconds AS bucket_time,
        sum(size) AS bucket_sum
    FROM system.trace_log
    WHERE trace_type = 'JemallocSample'
      AND query_id = '8678d8fe-62c5-48b8-b0cd-26851c62dd75'
    GROUP BY bucket_time
)
SELECT
    bucket_time,
    sum(bucket_sum) OVER (
        ORDER BY bucket_time ASC
        ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
    ) AS cumulative_size,
    formatReadableSize(cumulative_size) AS cumulative_size_readable
FROM per_bucket
ORDER BY bucket_time
```

메모리 사용량이 가장 높았던 시점을 찾으십시오:

```sql theme={null}
SELECT
    argMax(bucket_time, cumulative_size),
    max(cumulative_size)
FROM
(
    WITH per_bucket AS
    (
        SELECT
            event_time_microseconds AS bucket_time,
            sum(size) AS bucket_sum
        FROM system.trace_log
        WHERE trace_type = 'JemallocSample'
          AND query_id = '8678d8fe-62c5-48b8-b0cd-26851c62dd75'
        GROUP BY bucket_time
    )
    SELECT
        bucket_time,
        sum(bucket_sum) OVER (
            ORDER BY bucket_time ASC
            ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
        ) AS cumulative_size,
        formatReadableSize(cumulative_size) AS cumulative_size_readable
    FROM per_bucket
    ORDER BY bucket_time
)
```

해당 결과를 바탕으로 피크 시점에 어떤 할당 스택이 가장 활발했는지 확인합니다:

```sql theme={null}
SELECT
    concat(
        '\n',
        arrayStringConcat(
            arrayMap(
                (x, y) -> concat(x, ': ', y),
                arrayMap(x -> addressToLine(x), allocation_trace),
                arrayMap(x -> demangle(addressToSymbol(x)), allocation_trace)
            ),
            '\n'
        )
    ) AS symbolized_trace,
    sum(s) AS per_trace_sum
FROM
(
    SELECT
        ptr,
        sum(size) AS s,
        argMax(trace, event_time_microseconds) AS allocation_trace
    FROM system.trace_log
    WHERE trace_type = 'JemallocSample'
      AND query_id = '8678d8fe-62c5-48b8-b0cd-26851c62dd75'
      AND event_time_microseconds <= '2025-09-04 11:56:21.737139'
    GROUP BY ptr
    HAVING s > 0
)
GROUP BY ALL
ORDER BY per_trace_sum ASC
```

<div id="jemalloc-web-ui">
  ## Jemalloc 웹 UI
</div>

<Note>
  이 섹션은 버전 26.2 이상에 적용됩니다.
</Note>

ClickHouse는 `/jemalloc` HTTP 엔드포인트에서 jemalloc 메모리 통계를 확인할 수 있는 내장 웹 UI를 제공합니다.
이 UI는 allocated, active, resident, mapped 메모리를 비롯한 실시간 메모리 메트릭을 차트로 표시하며, arena별 및 빈(bin)별 통계도 제공합니다.
또한 UI에서 전역 및 쿼리별 힙 프로파일을 직접 가져올 수 있습니다.

<Tabs>
  <Tab title="ClickHouse">
    ```text theme={null}
    http://localhost:8123/jemalloc
    ```

    서버 UI에는 Summary, Allocations, Arenas, Operations, Global Profiler, Query Profiler, Raw Output 등 모든 탭이 포함되어 있습니다.
  </Tab>

  <Tab title="Keeper">
    ```text theme={null}
    http://localhost:9182/jemalloc
    ```

    Keeper UI는 HTTP control 포트에서 사용할 수 있습니다. 이 포트는 **기본적으로 비활성화되어 있으므로**, Keeper 구성에서 `keeper_server.http_control.port`를 설정해 명시적으로 활성화해야 합니다:

    ```xml theme={null}
    <clickhouse>
        <keeper_server>
            <http_control>
                <port>9182</port>
            </http_control>
        </keeper_server>
    </clickhouse>
    ```

    활성화되면 UI는 SQL과 `system.trace_log`가 필요한 Query Profiler 탭을 제외하고, Summary, Allocations, Arenas, Operations, Global Profiler, Raw Output 등 서버와 동일한 시각화를 제공합니다.

    <Warning>
      **보안**

      Keeper HTTP control 포트에는 애플리케이션 수준의 authentication이 없습니다. 모든 데이터 쿼리가 SQL HTTP handler를 통해 처리되고 사용자 이름/비밀번호 자격 증명이 필요한 ClickHouse 서버 jemalloc UI와 달리, Keeper REST API 엔드포인트에는 authentication이 적용되지 않습니다. 이는 다른 Keeper HTTP control 엔드포인트(명령, 스토리지, dashboard)와도 일관됩니다.

      네트워크 수준 제어를 사용해 이 포트에 대한 접근을 제한하십시오. 예를 들어 Keeper를 localhost에 bind하거나, firewall 규칙을 사용하거나, authentication이 적용된 reverse 프록시 뒤에 배치할 수 있습니다. `listen_host`가 구성되지 않은 경우 Keeper는 기본적으로 localhost에서만 수신합니다.
    </Warning>

    Keeper는 프로그래밍 방식으로 접근할 수 있도록 REST API 엔드포인트도 제공합니다:

    * `GET /jemalloc/stats` — 원시 `malloc_stats_print` 출력
    * `GET /jemalloc/status` — JSON 형식의 profiling 상태 (`prof_enabled`, `prof_active`, `thread_active_init`, `lg_sample`)
    * `GET /jemalloc/profile?format={collapsed|raw}` — 힙 프로파일을 플러시하고 서버 측 심볼화를 수행하며, flame graph 렌더링에 적합한 collapsed stacks(기본값) 또는 원시 jemalloc dump를 반환합니다
  </Tab>
</Tabs>

<div id="fetching-heap-profiles-from-sql">
  ## SQL에서 힙 프로파일 가져오기
</div>

<Note>
  이 섹션은 버전 26.2 이상에 적용됩니다.
</Note>

`system.jemalloc_profile_text` 시스템 테이블을 사용하면 외부 도구 없이, 먼저 디스크에 플러시하지 않고도 현재 jemalloc 힙 프로파일을 SQL에서 직접 가져와 볼 수 있습니다.

이 테이블에는 단일 컬럼이 있습니다:

| Column | Type   | Description               |
| ------ | ------ | ------------------------- |
| `line` | String | 심볼화된 jemalloc 힙 프로파일의 한 줄 |

이 테이블은 직접 쿼리할 수 있으므로, 미리 힙 프로파일을 플러시할 필요가 없습니다:

```sql theme={null}
SELECT * FROM system.jemalloc_profile_text
```

<div id="output-format">
  ### 출력 형식
</div>

출력 형식은 `jemalloc_profile_text_output_format` 설정으로 제어되며, 이 설정은 다음 3가지 값을 지원합니다.

* `raw` — jemalloc이 생성한 원시 힙 프로파일입니다.
* `symbolized` — 함수 심볼이 내장된 jeprof 호환 형식입니다. 심볼이 이미 내장되어 있으므로 `jeprof`는 ClickHouse 바이너리 없이도 출력을 분석할 수 있습니다.
* `collapsed` (기본값) — 바이트 수와 함께 한 줄에 하나의 스택이 기록되는 플레임 그래프 호환 collapsed stacks 형식입니다.

예를 들어, 원시 프로필을 가져오려면 다음과 같이 하십시오:

```sql theme={null}
SELECT * FROM system.jemalloc_profile_text
SETTINGS jemalloc_profile_text_output_format = 'raw'
```

심볼이 해석된 결과를 얻으려면:

```sql theme={null}
SELECT * FROM system.jemalloc_profile_text
SETTINGS jemalloc_profile_text_output_format = 'symbolized'
```

<div id="fetching-heap-profiles-settings">
  ### 추가 설정
</div>

* `jemalloc_profile_text_symbolize_with_inline` (Bool, 기본값: `true`) — 심볼화 시 인라인 프레임을 포함할지 여부를 지정합니다. 이 옵션을 비활성화하면 심볼화 속도가 크게 빨라지지만, 인라인된 함수 호출이 스택에 표시되지 않아 정밀도가 떨어집니다. `symbolized` 및 `collapsed` 포맷에만 영향을 줍니다.
* `jemalloc_profile_text_collapsed_use_count` (Bool, 기본값: `false`) — `collapsed` 포맷을 사용할 때 바이트 대신 할당 횟수 기준으로 집계합니다.

<div id="example-flamegraph-from-sql">
  ### 예시: SQL로 플레임 그래프 생성
</div>

기본 출력 형식이 `collapsed`이므로 출력을 FlameGraph로 직접 파이프할 수 있습니다:

```sh theme={null}
clickhouse-client -q "SELECT * FROM system.jemalloc_profile_text" | flamegraph.pl --color=mem --title="Allocation Flame Graph" --width 2400 > result.svg
```

바이트가 아니라 할당 횟수를 기준으로 flame graph를 생성하려면:

```sh theme={null}
clickhouse-client -q "SELECT * FROM system.jemalloc_profile_text SETTINGS jemalloc_profile_text_collapsed_use_count = 1" | flamegraph.pl --color=mem --title="Allocation Count Flame Graph" --width 2400 > result.svg
```

<div id="flushing-heap-profiles">
  ## 힙 프로파일을 디스크에 플러시하기
</div>

`jeprof`로 오프라인 분석을 하기 위해 힙 프로파일을 파일로 저장해야 하는 경우, 이를 디스크에 플러시할 수 있습니다.

기본적으로 힙 프로파일 파일은 `/tmp/jemalloc_clickhouse._pid_._seqnum_.heap`에 생성됩니다. 여기서 `_pid_`는 ClickHouse의 PID이고 `_seqnum_`은 현재 힙 프로파일의 전역 시퀀스 번호입니다.
Keeper의 경우 기본 파일은 `/tmp/jemalloc_keeper._pid_._seqnum_.heap`이며, 동일한 규칙을 따릅니다.

현재 프로파일을 플러시하려면 다음을 실행하십시오.

<Tabs>
  <Tab title="ClickHouse">
    ```sql theme={null}
    SYSTEM JEMALLOC FLUSH PROFILE
    ```

    플러시된 프로파일의 위치가 반환됩니다.
  </Tab>

  <Tab title="Keeper">
    ```sh theme={null}
    echo jmfp | nc localhost 9181
    ```
  </Tab>
</Tabs>

`MALLOC_CONF` 환경 변수에 `prof_prefix` 옵션을 추가해 다른 위치를 지정할 수 있습니다.
예를 들어, 파일 이름 접두사를 `my_current_profile`로 하여 `/data` 폴더에 프로파일을 생성하려면 다음 환경 변수와 함께 ClickHouse/Keeper를 실행하면 됩니다.

```sh theme={null}
MALLOC_CONF=prof_prefix:/data/my_current_profile
```

생성된 파일 이름에는 prefix, PID, 시퀀스 번호가 덧붙습니다.

<div id="analyzing-heap-profile-files-with-jeprof">
  ## `jeprof`를 사용한 힙 프로파일 파일 분석
</div>

힙 프로파일을 디스크에 플러시한 후에는 [jeprof](https://github.com/jemalloc/jemalloc/blob/dev/bin/jeprof.in)라는 `jemalloc` 도구를 사용해 분석할 수 있습니다. `jeprof`는 여러 가지 방법으로 설치할 수 있습니다:

* 시스템 패키지 관리자를 사용합니다
* [jemalloc 저장소](https://github.com/jemalloc/jemalloc)를 클론한 다음 루트 디렉터리에서 `autogen.sh`를 실행합니다. 그러면 `bin` 폴더에 있는 `jeprof` 스크립트를 사용할 수 있습니다

사용할 수 있는 출력 형식은 다양합니다. 전체 옵션 목록은 `jeprof --help`를 실행해 확인하십시오.

<div id="symbolized-heap-profiles">
  ### 심볼화된 힙 프로파일
</div>

버전 26.1+부터 ClickHouse는 `SYSTEM JEMALLOC FLUSH PROFILE`로 플러시할 때 심볼화된 힙 프로파일을 자동으로 생성합니다.
심볼화된 프로파일(`.symbolized` 확장자)에는 함수 심볼이 내장되어 있으므로 ClickHouse 바이너리 없이도 `jeprof`로 분석할 수 있습니다.

예를 들어, 다음을 실행하면:

```sql theme={null}
SYSTEM JEMALLOC FLUSH PROFILE
```

ClickHouse는 심볼화된 프로파일의 경로(예: `/tmp/jemalloc_clickhouse.12345.0.heap.symbolized`)를 반환합니다.

그런 다음 `jeprof`를 사용해 이를 직접 분석할 수 있습니다:

```sh theme={null}
jeprof /tmp/jemalloc_clickhouse.12345.0.heap.symbolized --output_format [ > output_file]
```

<Note>
  **바이너리가 필요하지 않습니다**: 심볼화된 프로파일(`.symbolized` 파일)을 사용하는 경우 `jeprof`에 ClickHouse 바이너리 경로를 지정할 필요가 없습니다. 따라서 다른 머신에서 프로파일을 분석하거나 바이너리가 업데이트된 후에 분석할 때도 훨씬 수월합니다.
</Note>

이전의 심볼화되지 않은 힙 프로파일이 있고 ClickHouse 바이너리에 계속 접근할 수 있다면, 기존 방식을 사용할 수 있습니다:

```sh theme={null}
jeprof path/to/clickhouse path/to/heap/profile --output_format [ > output_file]
```

<Note>
  심볼 정보가 없는 프로필의 경우 `jeprof`는 스택트레이스를 생성하기 위해 `addr2line`을 사용하므로 매우 느릴 수 있습니다.
  이런 경우에는 이 도구의 [대체 구현](https://github.com/gimli-rs/addr2line)을 설치하는 것이 좋습니다.

  ```bash theme={null}
  git clone https://github.com/gimli-rs/addr2line.git --depth=1 --branch=0.23.0
  cd addr2line
  cargo build --features bin --release
  cp ./target/release/addr2line path/to/current/addr2line
  ```

  또는 `llvm-addr2line`도 동일하게 잘 작동합니다(단, `llvm-objdump`는 `jeprof`와 호환되지 않으므로 유의하십시오)

  이후에는 다음과 같이 사용할 수 있습니다. `jeprof --tools addr2line:/usr/bin/llvm-addr2line,nm:/usr/bin/llvm-nm,objdump:/usr/bin/objdump,c++filt:/usr/bin/llvm-cxxfilt`
</Note>

두 프로필을 비교할 때는 `--base` 인수를 사용할 수 있습니다:

```sh theme={null}
jeprof --base /path/to/first.heap.symbolized /path/to/second.heap.symbolized --output_format [ > output_file]
```

<div id="examples">
  ### 예시
</div>

심볼이 포함된 프로파일 사용(권장):

* 각 프로시저를 줄별로 기록한 텍스트 파일을 생성합니다:

```sh theme={null}
jeprof /tmp/jemalloc_clickhouse.12345.0.heap.symbolized --text > result.txt
```

* 콜 그래프가 포함된 PDF 파일을 생성합니다:

```sh theme={null}
jeprof /tmp/jemalloc_clickhouse.12345.0.heap.symbolized --pdf > result.pdf
```

심볼화되지 않은 프로파일 사용(바이너리 필요):

* 각 프로시저를 한 줄에 하나씩 적은 텍스트 파일을 생성합니다:

```sh theme={null}
jeprof /path/to/clickhouse /tmp/jemalloc_clickhouse.12345.0.heap --text > result.txt
```

* 호출 그래프가 포함된 PDF 파일을 생성합니다:

```sh theme={null}
jeprof /path/to/clickhouse /tmp/jemalloc_clickhouse.12345.0.heap --pdf > result.pdf
```

<div id="generating-flame-graph">
  ### 플레임 그래프 생성하기
</div>

`jeprof`를 사용하면 플레임 그래프를 생성하는 데 필요한 collapsed stacks를 만들 수 있습니다.

`--collapsed` 인수를 사용해야 합니다:

```sh theme={null}
jeprof /tmp/jemalloc_clickhouse.12345.0.heap.symbolized --collapsed > result.collapsed
```

또는 심볼화되지 않은 프로파일 사용 시:

```sh theme={null}
jeprof /path/to/clickhouse /tmp/jemalloc_clickhouse.12345.0.heap --collapsed > result.collapsed
```

그다음에는 collapsed stacks를 시각화하는 데 여러 도구를 사용할 수 있습니다.

가장 널리 쓰이는 도구는 [FlameGraph](https://github.com/brendangregg/FlameGraph)로, `flamegraph.pl`이라는 스크립트가 포함되어 있습니다:

```sh theme={null}
cat result.collapsed | /path/to/FlameGraph/flamegraph.pl --color=mem --title="Allocation Flame Graph" --width 2400 > result.svg
```

또 다른 흥미로운 도구로 [speedscope](https://www.speedscope.app/)가 있으며, 이를 사용하면 수집된 스택을 더 인터랙티브하게 분석할 수 있습니다.

<div id="additional-options-for-profiler">
  ## 프로파일러 추가 옵션
</div>

`jemalloc`에는 프로파일러와 관련된 다양한 옵션이 있으며, `MALLOC_CONF` 환경 변수를 수정해 제어할 수 있습니다.
예를 들어, 할당 샘플 간 인터벌은 `lg_prof_sample`로 제어할 수 있습니다.
N바이트마다 힙 프로파일을 dump하려면 `lg_prof_interval`을 활성화하면 됩니다.

전체 옵션 목록은 `jemalloc`의 [참고 페이지](https://jemalloc.net/jemalloc.3.html)에서 확인하는 것이 좋습니다.

<div id="other-resources">
  ## 기타 리소스
</div>

ClickHouse/Keeper는 `jemalloc` 관련 메트릭을 여러 방식으로 노출합니다.

<Warning>
  **경고**

  이 메트릭들은 서로 동기화되지 않으므로 값이 서로 어긋날 수 있다는 점에 유의해야 합니다.
</Warning>

<div id="system-table-asynchronous_metrics">
  ### 시스템 테이블 `asynchronous_metrics`
</div>

```sql theme={null}
SELECT *
FROM system.asynchronous_metrics
WHERE metric LIKE '%jemalloc%'
FORMAT Vertical
```

[참고](/ko/reference/system-tables/asynchronous_metrics)

<div id="system-table-jemalloc_bins">
  ### 시스템 테이블 `jemalloc_bins`
</div>

모든 arena에서 집계한 jemalloc 메모리 할당자의 각 크기 클래스(bin)별 메모리 할당 정보를 포함합니다.

[참고](/ko/reference/system-tables/jemalloc_bins)

<div id="system-table-jemalloc_stats">
  ### 시스템 테이블 `jemalloc_stats` (26.2+)
</div>

`malloc_stats_print()`의 전체 출력 결과를 하나의 문자열로 반환합니다. `SYSTEM JEMALLOC STATS` 명령과 동일합니다.

```sql theme={null}
SELECT * FROM system.jemalloc_stats
```

<div id="prometheus">
  ### Prometheus
</div>

`asynchronous_metrics`의 모든 `jemalloc` 관련 메트릭은 ClickHouse와 Keeper 모두에서 Prometheus 엔드포인트를 통해서도 제공됩니다.

[참고](/ko/reference/settings/server-settings/settings#prometheus)

<div id="jmst-4lw-command-in-keeper">
  ### Keeper의 `jmst` 4LW 명령
</div>

Keeper는 [기본 메모리 할당자 통계](https://github.com/jemalloc/jemalloc/wiki/Use-Case%3A-Basic-Allocator-Statistics)를 반환하는 `jmst` 4LW 명령을 지원합니다:

```sh theme={null}
echo jmst | nc localhost 9181
```
