ClickHouse는 전역 메모리 할당자로 jemalloc을 사용합니다. jemalloc에는 할당 샘플링과 프로파일링을 위한 도구가 포함되어 있습니다.
ClickHouse와 Keeper에서는 구성 파일, 쿼리 설정, SYSTEM 명령, 그리고 Keeper의 4문자 명령(4LW)을 사용해 샘플링을 제어할 수 있습니다. 결과를 확인하는 방법은 여러 가지가 있습니다.
- 쿼리별 분석을 위해
JemallocSample유형으로 샘플을system.trace_log에 수집합니다. - 내장된 jemalloc web UI에서 실시간 메모리 통계를 확인하고 힙 프로파일을 가져옵니다(26.2+).
system.jemalloc_profile_text를 사용해 현재 힙 프로파일을 SQL에서 직접 쿼리합니다(26.2+).- 힙 프로파일을 디스크에 플러시한 뒤
jeprof로 분석합니다.
메모리 할당 샘플링
메모리 할당을 샘플링하고 프로파일링하려면 jemalloc_enable_global_profiler 설정을 활성화한 상태로 ClickHouse/Keeper를 시작합니다:
<clickhouse>
<jemalloc_enable_global_profiler>1</jemalloc_enable_global_profiler>
</clickhouse>jemalloc은 메모리 할당을 샘플링하고 해당 정보를 내부적으로 저장합니다.
jemalloc_enable_profiler 설정을 사용하면 쿼리별 샘플링도 활성화할 수 있습니다.
system.trace_log에 jemalloc 샘플 저장
JemallocSample 유형으로 jemalloc 샘플을 system.trace_log에 저장할 수 있습니다.
전체적으로 활성화하려면 jemalloc_collect_global_profile_samples_in_trace_log 설정을 사용하세요:
<clickhouse>
<jemalloc_collect_global_profile_samples_in_trace_log>1</jemalloc_collect_global_profile_samples_in_trace_log>
</clickhouse>jemalloc_collect_profile_samples_in_trace_log 설정을 사용하면 쿼리별로도 이를 활성화할 수 있습니다.
예시: 쿼리의 메모리 사용량 분석
먼저 jemalloc 프로파일러를 활성화한 상태에서 쿼리를 실행하고, 샘플을 system.trace_log에 수집합니다:
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.system.trace_log를 플러시합니다:
SYSTEM FLUSH LOGS trace_log그런 다음 시간에 따른 누적 메모리 사용량을 확인하기 위해 쿼리합니다:
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메모리 사용량이 가장 높았던 시점을 찾으십시오:
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
)해당 결과를 바탕으로 피크 시점에 어떤 할당 스택이 가장 활발했는지 확인합니다:
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 ASCJemalloc 웹 UI
ClickHouse는 /jemalloc HTTP 엔드포인트에서 jemalloc 메모리 통계를 확인할 수 있는 내장 웹 UI를 제공합니다.
이 UI는 allocated, active, resident, mapped 메모리를 비롯한 실시간 메모리 메트릭을 차트로 표시하며, arena별 및 빈(bin)별 통계도 제공합니다.
또한 UI에서 전역 및 쿼리별 힙 프로파일을 직접 가져올 수 있습니다.
http://localhost:8123/jemalloc서버 UI에는 Summary, Allocations, Arenas, Operations, Global Profiler, Query Profiler, Raw Output 등 모든 탭이 포함되어 있습니다.
http://localhost:9182/jemallocKeeper UI는 HTTP control 포트에서 사용할 수 있습니다. 이 포트는 기본적으로 비활성화되어 있으므로, Keeper 구성에서 keeper_server.http_control.port를 설정해 명시적으로 활성화해야 합니다:
<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 등 서버와 동일한 시각화를 제공합니다.
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를 반환합니다
SQL에서 힙 프로파일 가져오기
system.jemalloc_profile_text 시스템 테이블을 사용하면 외부 도구 없이, 먼저 디스크에 플러시하지 않고도 현재 jemalloc 힙 프로파일을 SQL에서 직접 가져와 볼 수 있습니다.
이 테이블에는 단일 컬럼이 있습니다:
| Column | Type | Description |
|---|---|---|
line |
String | 심볼화된 jemalloc 힙 프로파일의 한 줄 |
이 테이블은 직접 쿼리할 수 있으므로, 미리 힙 프로파일을 플러시할 필요가 없습니다:
SELECT * FROM system.jemalloc_profile_text출력 형식
출력 형식은 jemalloc_profile_text_output_format 설정으로 제어되며, 이 설정은 다음 3가지 값을 지원합니다.
raw— jemalloc이 생성한 원시 힙 프로파일입니다.symbolized— 함수 심볼이 내장된 jeprof 호환 형식입니다. 심볼이 이미 내장되어 있으므로jeprof는 ClickHouse 바이너리 없이도 출력을 분석할 수 있습니다.collapsed(기본값) — 바이트 수와 함께 한 줄에 하나의 스택이 기록되는 플레임 그래프 호환 collapsed stacks 형식입니다.
예를 들어, 원시 프로필을 가져오려면 다음과 같이 하십시오:
SELECT * FROM system.jemalloc_profile_text
SETTINGS jemalloc_profile_text_output_format = 'raw'심볼이 해석된 결과를 얻으려면:
SELECT * FROM system.jemalloc_profile_text
SETTINGS jemalloc_profile_text_output_format = 'symbolized'추가 설정
jemalloc_profile_text_symbolize_with_inline(Bool, 기본값:true) — 심볼화 시 인라인 프레임을 포함할지 여부를 지정합니다. 이 옵션을 비활성화하면 심볼화 속도가 크게 빨라지지만, 인라인된 함수 호출이 스택에 표시되지 않아 정밀도가 떨어집니다.symbolized및collapsed포맷에만 영향을 줍니다.jemalloc_profile_text_collapsed_use_count(Bool, 기본값:false) —collapsed포맷을 사용할 때 바이트 대신 할당 횟수 기준으로 집계합니다.
예시: SQL로 플레임 그래프 생성
기본 출력 형식이 collapsed이므로 출력을 FlameGraph로 직접 파이프할 수 있습니다:
clickhouse-client -q "SELECT * FROM system.jemalloc_profile_text" | flamegraph.pl --color=mem --title="Allocation Flame Graph" --width 2400 > result.svg바이트가 아니라 할당 횟수를 기준으로 flame graph를 생성하려면:
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힙 프로파일을 디스크에 플러시하기
jeprof로 오프라인 분석을 하기 위해 힙 프로파일을 파일로 저장해야 하는 경우, 이를 디스크에 플러시할 수 있습니다.
기본적으로 힙 프로파일 파일은 /tmp/jemalloc_clickhouse._pid_._seqnum_.heap에 생성됩니다. 여기서 _pid_는 ClickHouse의 PID이고 _seqnum_은 현재 힙 프로파일의 전역 시퀀스 번호입니다.
Keeper의 경우 기본 파일은 /tmp/jemalloc_keeper._pid_._seqnum_.heap이며, 동일한 규칙을 따릅니다.
현재 프로파일을 플러시하려면 다음을 실행하십시오.
SYSTEM JEMALLOC FLUSH PROFILE플러시된 프로파일의 위치가 반환됩니다.
echo jmfp | nc localhost 9181MALLOC_CONF 환경 변수에 prof_prefix 옵션을 추가해 다른 위치를 지정할 수 있습니다.
예를 들어, 파일 이름 접두사를 my_current_profile로 하여 /data 폴더에 프로파일을 생성하려면 다음 환경 변수와 함께 ClickHouse/Keeper를 실행하면 됩니다.
MALLOC_CONF=prof_prefix:/data/my_current_profile생성된 파일 이름에는 prefix, PID, 시퀀스 번호가 덧붙습니다.
jeprof를 사용한 힙 프로파일 파일 분석
힙 프로파일을 디스크에 플러시한 후에는 jeprof라는 jemalloc 도구를 사용해 분석할 수 있습니다. jeprof는 여러 가지 방법으로 설치할 수 있습니다:
- 시스템 패키지 관리자를 사용합니다
- jemalloc 저장소를 클론한 다음 루트 디렉터리에서
autogen.sh를 실행합니다. 그러면bin폴더에 있는jeprof스크립트를 사용할 수 있습니다
사용할 수 있는 출력 형식은 다양합니다. 전체 옵션 목록은 jeprof --help를 실행해 확인하십시오.
심볼화된 힙 프로파일
버전 26.1+부터 ClickHouse는 SYSTEM JEMALLOC FLUSH PROFILE로 플러시할 때 심볼화된 힙 프로파일을 자동으로 생성합니다.
심볼화된 프로파일(.symbolized 확장자)에는 함수 심볼이 내장되어 있으므로 ClickHouse 바이너리 없이도 jeprof로 분석할 수 있습니다.
예를 들어, 다음을 실행하면:
SYSTEM JEMALLOC FLUSH PROFILEClickHouse는 심볼화된 프로파일의 경로(예: /tmp/jemalloc_clickhouse.12345.0.heap.symbolized)를 반환합니다.
그런 다음 jeprof를 사용해 이를 직접 분석할 수 있습니다:
jeprof /tmp/jemalloc_clickhouse.12345.0.heap.symbolized --output_format [ > output_file]이전의 심볼화되지 않은 힙 프로파일이 있고 ClickHouse 바이너리에 계속 접근할 수 있다면, 기존 방식을 사용할 수 있습니다:
jeprof path/to/clickhouse path/to/heap/profile --output_format [ > output_file]두 프로필을 비교할 때는 --base 인수를 사용할 수 있습니다:
jeprof --base /path/to/first.heap.symbolized /path/to/second.heap.symbolized --output_format [ > output_file]예시
심볼이 포함된 프로파일 사용(권장):
- 각 프로시저를 줄별로 기록한 텍스트 파일을 생성합니다:
jeprof /tmp/jemalloc_clickhouse.12345.0.heap.symbolized --text > result.txt- 콜 그래프가 포함된 PDF 파일을 생성합니다:
jeprof /tmp/jemalloc_clickhouse.12345.0.heap.symbolized --pdf > result.pdf심볼화되지 않은 프로파일 사용(바이너리 필요):
- 각 프로시저를 한 줄에 하나씩 적은 텍스트 파일을 생성합니다:
jeprof /path/to/clickhouse /tmp/jemalloc_clickhouse.12345.0.heap --text > result.txt- 호출 그래프가 포함된 PDF 파일을 생성합니다:
jeprof /path/to/clickhouse /tmp/jemalloc_clickhouse.12345.0.heap --pdf > result.pdf플레임 그래프 생성하기
jeprof를 사용하면 플레임 그래프를 생성하는 데 필요한 collapsed stacks를 만들 수 있습니다.
--collapsed 인수를 사용해야 합니다:
jeprof /tmp/jemalloc_clickhouse.12345.0.heap.symbolized --collapsed > result.collapsed또는 심볼화되지 않은 프로파일 사용 시:
jeprof /path/to/clickhouse /tmp/jemalloc_clickhouse.12345.0.heap --collapsed > result.collapsed그다음에는 collapsed stacks를 시각화하는 데 여러 도구를 사용할 수 있습니다.
가장 널리 쓰이는 도구는 FlameGraph로, flamegraph.pl이라는 스크립트가 포함되어 있습니다:
cat result.collapsed | /path/to/FlameGraph/flamegraph.pl --color=mem --title="Allocation Flame Graph" --width 2400 > result.svg또 다른 흥미로운 도구로 speedscope가 있으며, 이를 사용하면 수집된 스택을 더 인터랙티브하게 분석할 수 있습니다.
프로파일러 추가 옵션
jemalloc에는 프로파일러와 관련된 다양한 옵션이 있으며, MALLOC_CONF 환경 변수를 수정해 제어할 수 있습니다.
예를 들어, 할당 샘플 간 인터벌은 lg_prof_sample로 제어할 수 있습니다.
N바이트마다 힙 프로파일을 dump하려면 lg_prof_interval을 활성화하면 됩니다.
전체 옵션 목록은 jemalloc의 참고 페이지에서 확인하는 것이 좋습니다.
기타 리소스
ClickHouse/Keeper는 jemalloc 관련 메트릭을 여러 방식으로 노출합니다.
시스템 테이블 asynchronous_metrics
SELECT *
FROM system.asynchronous_metrics
WHERE metric LIKE '%jemalloc%'
FORMAT Vertical시스템 테이블 jemalloc_bins
모든 arena에서 집계한 jemalloc 메모리 할당자의 각 크기 클래스(bin)별 메모리 할당 정보를 포함합니다.
시스템 테이블 jemalloc_stats (26.2+)
malloc_stats_print()의 전체 출력 결과를 하나의 문자열로 반환합니다. SYSTEM JEMALLOC STATS 명령과 동일합니다.
SELECT * FROM system.jemalloc_statsPrometheus
asynchronous_metrics의 모든 jemalloc 관련 메트릭은 ClickHouse와 Keeper 모두에서 Prometheus 엔드포인트를 통해서도 제공됩니다.
Keeper의 jmst 4LW 명령
Keeper는 기본 메모리 할당자 통계를 반환하는 jmst 4LW 명령을 지원합니다:
echo jmst | nc localhost 9181