
Loki는 Grafana 플랫폼의 일부이며, 메트릭 데이터와 로그 데이터를 인덱싱하고 관리하는 시스템입니다. 다른 로깅 제품들과 달리 Loki의 인덱스는 레이블로부터 작성되고, 원본 데이터는 변경없이 보존합니다. 에이전트(혹은 클라이언트)는 로그를 수집하여 스트림으로 변환하고, 이를 HTTP API를 통해 Loki에 푸시합니다.레이블을 인덱싱함으로써, 로그의 인덱스가 다른 로깅 제품들보다 상당히 작습니다. 이는 곧 적은 리소스 비용으로 로그를 처리할 수 있다는 장점입니다.
Loki의 여러 테넌트가 하나의 Loki 인스턴스를 활용할 수 있습니다. 별개의 테넌트의 데이터는 다른 테넌트로부터 완전히 격리됩니다. 멀티 테넌시는 에이전트에서 테넌트 ID를 할당하여 구성됩니다.Loki 인스턴스(쉽게 말해 서비스)를 공유하되, 각각의 로그 데이터는 테넌트 ID를 기준으로 서로 분리되어 있음을 나타냅니다. 이를 통해 각 사용자 혹은 팀이 자신들의 데이터를 안전하게 관리하고 검색할 수 있는 이점을 제공합니다.<aside>
💡 테넌트(Tenant)는 "다중 사용자" 또는 “다중 렌트" 환경에서 사용되는 용어입니다. 소프트웨어 아키텍처 측면에서 테넌트는 독립적인 인스턴스를 참조합니다. 각각의 테넌느는 별도로 격리되어 있어, 자신들의 데이터와 프로세스가 다른 테넌트와 상호 작용하지 않습니다.
</aside>
loki는 확장성을 고려하여 설계되어 싱글 바이너리(하나의 파일에 모든 컴포넌트가 포함된 파일)외에도 마이크로 서비스 형태로 배포할 수 있습니다. loki를 마이크로 서비스로 배포할 경우 설정을 통해 각 컴포넌트들을 개별적으로 확장할 수 있어 유연하게 대규모 배포가 가능합니다.테넌트 ID(Tenant ID)
X-Scope-OrgID’을 통해 얻을 수 있습니다. 단, Loki가 멀티 테넌트 모드(multi-tenant mode)일 때만 동작하며 만약 멀티 테넌트 모드가 아닌 경우 헤더값(X-Scope-OrgID)이 무시되고, 테넌트 ID는 ‘fake’가 됩니다. 테넌트 ID는 인덱스와 저장된 청크에서 확인 가능합니다.청크 포맷(Chunk Format)
Loki는 로그 데이터를 청크로 분할하여 저장하고, 각 청크는 레이블 세트와 일련의 로그 라인(시간+로그 라인)으로 구성됩니다. 이러한 청크는 시간 범위별로 분리되어 저장됩니다. Loki는 로그 라인을 압축하고 이들을 청크에 저장하여 공간을 절약합니다. 이는 저장 공간을 절약하고 로그 데이터의 쿼리 속도를 높이는 데 도움이 됩니다.v1이 아닌 v2를 기본으로 사용하고 있습니다. 새로운 청크 포맷 v2는 훨씬 더 효율적인 압축 방식을 사용하며, 이로 인해 저장 공간이 더욱 절약되고 쿼리 시간이 더욱 단축되었습니다. -------------------------------------------------------------------
| | |
| MagicNumber(4b) | version(1b) |
| | |
-------------------------------------------------------------------
| block-1 bytes | checksum (4b) |
-------------------------------------------------------------------
| block-2 bytes | checksum (4b) |
-------------------------------------------------------------------
| block-n bytes | checksum (4b) |
-------------------------------------------------------------------
| #blocks (uvarint) |
-------------------------------------------------------------------
| #entries(uvarint) | mint, maxt (varint) | offset, len (uvarint) |
-------------------------------------------------------------------
| #entries(uvarint) | mint, maxt (varint) | offset, len (uvarint) |
-------------------------------------------------------------------
| #entries(uvarint) | mint, maxt (varint) | offset, len (uvarint) |
-------------------------------------------------------------------
| #entries(uvarint) | mint, maxt (varint) | offset, len (uvarint) |
-------------------------------------------------------------------
| checksum(from #blocks) |
-------------------------------------------------------------------
| #blocks section byte offset |
-------------------------------------------------------------------
MagicNumber는 청크 파일이 Loki에서 사용하는 특정 포맷인지 확인하는 데 사용되며, version은 청크 포맷의 버전을 나타냅니다.#entries는 해당 청크에 저장된 로그 라인의 수를 나타냅니다. mint와 maxt는 청크의 최소 시간과 최대 시간을 나타내며, offset과 len은 해당 로그 라인의 바이트 오프셋과 길이를 나타냅니다.#blocks 필드의 체크섬을 나타냅니다.#blocks 섹션이 시작하는 위치를 나타냅니다.블록 포맷(Block Format)
-------------------------------------------------------------------
| ts (varint) | len (uvarint) | log-1 bytes |
-------------------------------------------------------------------
| ts (varint) | len (uvarint) | log-2 bytes |
-------------------------------------------------------------------
| ts (varint) | len (uvarint) | log-3 bytes |
-------------------------------------------------------------------
| ts (varint) | len (uvarint) | log-n bytes |
-------------------------------------------------------------------
Block Format)은 로그 데이터를 저장하는 데 사용되는 데이터 구조를 의미합니다. Loki에서, 로그 데이터는 블록(block)이라는 단위로 구분되어 저장됩니다. 각 블록은 하나 이상의 로그 라인을 포함하고 있으며, 이러한 로그 라인들은 블록 내에서 시간 순서대로 정렬되어 있습니다.Loki는 각 블록을 개별적으로 압축하고, 이들을 청크(chunk)에 묶어 저장합니다. 이는 데이터의 중복을 줄이고, 공간을 절약하는 데 도움이 됩니다.Loki는 데이터의 검색 속도를 높일 수 있습니다. 예를 들어, 특정 시간 범위의 로그를 검색할 때 Loki는 해당 시간 범위에 해당하는 블록만을 압축 해제하고 읽을 수 있습니다.