[Grafana Loki] 파서의 문자열 인턴 셋에서 키 충돌 결과 캐싱 버그 수정
PR 링크: grafana/loki#19984 상태: Merged | 변경: +70 / -50
들어가며
Grafana Loki의 로그 파서(JSON, Logfmt, Regexp, Unpack)에서는 문자열 인턴 최적화(internedStringSet)를 사용하여 동일한 키 문자열의 반복 할당을 방지합니다. 그런데 createNew 콜백 함수 안에서 기존 라벨과의 충돌 감지(duplicate suffix 추가)와 파서 힌트 체크를 함께 수행하고 그 결과를 캐싱했습니다. 이로 인해 첫 번째 스트림에서의 충돌 결과가 다른 스트림에도 그대로 적용되는 미묘한 버그가 발생했습니다.
핵심 코드 분석
Before: 충돌 감지를 캐시 내부에서 수행
// JSONParser
sanitizedKey, ok := j.keys.Get(key, func() (string, bool) {
field := sanitizeLabelKey(string(key), true)
if j.lbs.BaseHas(field) {
field = field + duplicateSuffix // 충돌 시 "_extracted" 추가
}
if !j.lbs.ParserLabelHints().ShouldExtract(field) {
return "", false
}
return field, true // 이 결과가 캐싱됨! 다른 스트림에도 동일 적용
})
After: 캐시에는 정제된 키만, 충돌 감지는 밖에서
// JSONParser
sanitizedKey, ok := j.keys.Get(key, func() (string, bool) {
field := sanitizeLabelKey(string(key), true)
if len(field) == 0 {
return "", false
}
return field, true // 순수하게 정제된 키만 캐싱
})
if !ok {
return nil
}
// 충돌 감지는 캐시 밖에서 스트림별로 수행
if j.lbs.BaseHas(sanitizedKey) {
sanitizedKey = sanitizedKey + duplicateSuffix
}
if !j.lbs.ParserLabelHints().ShouldExtract(sanitizedKey) ||
j.lbs.ParserLabelHints().Extracted(sanitizedKey) {
return nil
}
왜 이게 좋은가
- 스트림별 정확한 충돌 감지: 라벨 충돌은 각 스트림의 기존 라벨셋에 따라 달라지므로, 캐시 밖에서 매번 확인해야 정확하다.
- 인턴 캐시의 순수성 보장:
internedStringSet은 바이트 슬라이스를 문자열로 변환하는 순수 매핑만 캐싱하고, 부수 효과가 있는 로직은 분리했다. - 4개 파서 동시 수정: JSON, Logfmt, Regexp, Unpack 파서 모두에 동일한 패턴을 적용하여 일관성을 확보했다.
참고 자료
관련 포스트
PR Analysis 의 다른글
- 이전글 [triton] Triton Kernel의 Matrix Multiplication 리팩토링: 코드 가독성과 유지보수성 향상
- 현재글 : [Grafana Loki] 파서의 문자열 인턴 셋에서 키 충돌 결과 캐싱 버그 수정
- 다음글 [Loki] 테넌트 rate limit 기반 셔플 샤딩으로 쿼리 성능 향상
댓글