[Clickhouse] S3 비용 튜닝: 통계 갱신 누수
Clickhouse를 쓸 경우에는 S3 등을 백업 스토리지로서 활용하는 복합적인 전략을 많이 사용하게 된다.
근데 당연히 외부 서비스를 쓰는만큼, 부가적인 비용 발생 가능성도 생긴다. 로컬 스토리지와는 다르게 비용이 쓰는만큼 더 청구되는데, Clickhouse 자체의 백그라운드 처리로 인해서 비용이 튈 가능성은 항상 실재하는 것이다.
그래서 그냥 넣었다가는 이런 식으로 비용이 의도치 않게 튈 수 있다.
보면 GetObject 비용이 $10나 튄 것을 볼 수 있다.
실제로 많이 읽어서 그렇다면 이해할 수 있는데, 문제는 1개월 이전 범위를 조회한 적도 거의 없고, 저장공간 자체도 매우 작았다는 것이다.
500MB밖에 안됐다. 명백히 비정상적인 현상이다.
요주의 범인: 통계 캐시
Clickhouse는 통계 캐시라는 것을 관리한다.
이게 뭐냐면, 스캔 효율성을 높이기 위해 part 단위에서 키값의 분포나 비율 등을 미리 적재해놓고 그걸 통해 쿼리를 최적화하는 것이다.
쿼리 성능에 꽤 유의미한 영향을 미치는 것이라서 쿼리 시점에 갱신을 하기도 하고, 아무것도 안해도 백그라운드로 갱신을 하기도 한다.
그리고 이 중 후자, 백그라운드 갱신은 테이블의 refresh_statistics_interval라는 옵션을 통해 관리되며, 기본값이 300초다.
문제는 이게 로컬 디스크에서는 주기적으로 발생해도 딱히 비용 부담이 없지만, 외부 스토리지는 그렇지 않다는 것이다. 스토리지 사용량이 늘어날수록 Idle 비용이 선형적으로 증가하게 된다.
가장 좋은 방법은 백그라운드 통계 갱신을 아예 끄는 것이다.
ALTER TABLE default.otel_logs MODIFY SETTING refresh_statistics_interval = 0;
ALTER TABLE default.otel_traces MODIFY SETTING refresh_statistics_interval = 0;
ALTER TABLE default.otel_metrics_sum MODIFY SETTING refresh_statistics_interval = 0;
ALTER TABLE default.otel_metrics_gauge MODIFY SETTING refresh_statistics_interval = 0;
ALTER TABLE default.otel_metrics_histogram MODIFY SETTING refresh_statistics_interval = 0;
ALTER TABLE default.otel_logs_kv_rollup_15m MODIFY SETTING refresh_statistics_interval = 0;
ALTER TABLE default.otel_traces_kv_rollup_15m MODIFY SETTING refresh_statistics_interval = 0;
이렇게 하면 멋대로 디스크를 읽는 것을 최대한 줄일 수 있다.
그리고 이렇게 한다고 해서 통계 갱신이 사라지는 것은 아니다. 단지 쿼리를 날리는 시점에서 "없다면 갱신하는" 조건으로 처리가 되는 것이다. cold start가 조금 더 생길 수는 있지만, 대체로는 감수할만한 정도일 것이다.
그리고 실제로 적용했을때, 의도한대로 비용이 안정화되는 것을 확인했다.
체감 성능에도 큰 차이는 없었다.
참조
https://clickhouse.com/docs/ko/reference/settings/merge-tree-settings/refresh