[Grafana Loki] 블룸 필터 캐시를 맵으로 교체하여 운영 복잡도 제거
PR 링크: grafana/loki#20882 상태: Merged | 변경: +57 / -84
들어가며
Loki의 ingest-limits-frontend는 이미 수락된 스트림을 캐시하여 불필요한 제한 검사를 건너뛴다. 기존에는 이 캐시로 블룸 필터를 사용했는데, 블룸 필터는 크기를 미리 정해야 하고 false positive가 발생할 수 있으며 정확한 크기 추적이 어렵다는 운영상의 단점이 있었다. 현재 사용 규모에서는 단순한 Go map이 충분히 빠르고 메모리 효율적이라는 판단 하에 교체가 이루어졌다.
핵심 코드 분석
Before: 블룸 필터 기반 캐시
type acceptedStreamsCache struct {
mtx sync.RWMutex
bf *bloom.BloomFilter
// ...
}
func newAcceptedStreamsCache(ttl, maxJitter time.Duration, cacheSize int, r prometheus.Registerer) *acceptedStreamsCache {
c := &acceptedStreamsCache{
bf: bloom.NewWithEstimates(uint(cacheSize), 0.01),
}
// ...
}
func (c *acceptedStreamsCache) FilterInPlace(req *proto.ExceedsLimitsRequest) {
b := bytes.Buffer{}
for _, s := range req.Streams {
b.Reset()
encodeStreamToBuf(&b, req.Tenant, s)
if !c.bf.Test(b.Bytes()) {
filtered = append(filtered, s)
}
}
}
After: 테넌트별 맵 기반 캐시
type acceptedStreamsCache struct {
mtx sync.RWMutex
entries map[string]map[uint64]struct{} // tenant -> streamHash -> exists
entriesSize int
// ...
}
func newAcceptedStreamsCache(ttl, maxJitter time.Duration, r prometheus.Registerer) *acceptedStreamsCache {
c := &acceptedStreamsCache{
entries: make(map[string]map[uint64]struct{}, 4096),
}
}
func (c *acceptedStreamsCache) FilterInPlace(req *proto.ExceedsLimitsRequest) {
tenantEntries, ok := c.entries[req.Tenant]
if !ok {
return
}
for _, s := range req.Streams {
if _, found := tenantEntries[s.StreamHash]; !found {
filtered = append(filtered, s)
}
}
}
왜 이게 좋은가
- 사전 크기 설정 불필요: 블룸 필터는
cacheSize매개변수로 최대 스트림 수를 미리 지정해야 했다. 맵은 동적으로 크기가 조절되므로 설정 파라미터 하나가 사라졌다. - false positive 제거: 블룸 필터는 확률적 자료구조로 1%의 false positive를 허용했다. 즉, 수락된 적 없는 스트림을 수락된 것으로 잘못 판단할 수 있었다. 맵은 정확한 존재 확인을 제공한다.
- 인코딩 오버헤드 제거: 블룸 필터에 넣기 위해
tenant + streamHash를 바이트로 인코딩하는encodeStreamToBuf함수가 필요 없어졌다.map[uint64]struct{}로 해시값을 직접 키로 사용한다. - 정확한 메트릭:
ApproximatedSize()라는 추정치 대신entriesSize정수로 정확한 캐시 크기를 제공한다. - 테넌트 격리: 2단계 맵 구조(
tenant -> streamHash -> exists)로clear(c.entries)호출 시 모든 테넌트가 한 번에 초기화되면서도, 캐시 조회 시에는 해당 테넌트의 엔트리만 검색한다.
참고 자료
관련 포스트
PR Analysis 의 다른글
- 이전글 [Open WebUI] 메시지 전송마다 발생하는 불필요한 채팅 JSON 역직렬화 2회 제거
- 현재글 : [Grafana Loki] 블룸 필터 캐시를 맵으로 교체하여 운영 복잡도 제거
- 다음글 [triton] 캐시 테스트를 Device Agnostic하게 개선
댓글