Architecture
Architecture에서는 아래의 핵심 개념에 대하여 자세히 설명합니다.
핵심 개념
- Read Path와 Write Path: Loki는 로그 데이터 처리를 위한 읽기 경로(Read Path)와 쓰기 경로(Write Path)를 구분합니다. 이러한 분리는 데이터 처리의 효율성을 극대화하며, 각 경로는 특정 작업에 최적화된 컴포넌트로 구성됩니다.
- Consistent Hash Rings: 클러스터 내에서 데이터를 균등하게 분배하고 고가용성을 보장하는 메커니즘입니다. 이는 클러스터의 스케일링을 용이하게 하며, 데이터 샤딩과 복제를 통한 안정성을 제공합니다.
- Multi-tenancy: Loki는 다중 테넌시를 지원하여, 하나의 Loki 인스턴스를 여러 사용자나 팀이 공유할 수 있게 합니다. 이는 리소스의 효율적인 사용과 데이터 분리를 가능하게 합니다.
Write Path: Distributor, Ingester
아래는 로그 스트림이 장기 저장소에 저장되는 과정을 Component와 함께 나타냅니다.
Distributor
Distributor는 클라이언트로부터 받은 스트림을 처리하여 Ingester로 전달하는 중요한 역할을 합니다. 이 과정은 몇 가지 핵심 단계와 특징을 포함하고 있습니다:
Distributor의 주요 기능 및 특징:
- 유효성 검사(Validation): Distributor는 수신된 스트림이 Grafana LGTM 사양에 부합하는지 첫 번째로 확인합니다. 이는 데이터가 올바르게 처리될 수 있는지를 보장하기 위한 필수적인 과정입니다.
- 전처리(Preprocessing): 스트림의 레이블을 정렬하는 과정으로, 이를 통해 Loki는 데이터를 효율적으로 캐시하고 해시할 수 있습니다.
- 속도 제한(Rate limiting): 테넌트별 최대 전송률을 설정하여, 들어오는 로그의 전송률을 제어할 수 있습니다. 이는 시스템의 안정성을 유지하는 데 중요한 역할을 합니다.
- 전달(Forwarding): 모든 유효성 검사와 전처리 작업을 마친 후, 데이터는 Ingester로 전달됩니다. Ingester는 최종적으로 데이터의 쓰기를 승인하며, 이 과정에서 replication_factor를 참고하여 데이터 손실 위험을 최소화하기 위한 복제본을 생성합니다.
- replication_factor가 3이라면 Ingester 내에 3개의 복제본을 생성하도록 3개의 스트림을 전달합니다.
- 해싱(Hashing): Distributor는 일관된 해싱을 사용해 특정 스트림이 전달될 Ingester 인스턴스를 결정합니다. 이는 데이터가 올바른 대상에게 전달되도록 합니다.
- 쿼럼 일관성(Quorum consistency): Distributor는 최소 절반 이상의 Ingester로부터 응답을 받기 전까지는 클라이언트에게 응답을 보류합니다. 이는 Dynamo 스타일의 쿼럼 일관성을 통해 데이터의 신뢰성을 높입니다.
이러한 과정과 특징들은 Distributor가 Grafana Loki에서 매우 중요한 역할을 수행하게 합니다.
특히, stateless한 성격 덕분에, 작업을 Ingester로 쉽게 확장하고 오프로드할 수 있으며, DDos 공격으로부터 시스템을 보호할 수 있습니다.
또한 distributor는 내부에서 링 component를 사용하여 peers 사이에서 자신을 등록하고 총 active distributors를 얻습니다. 이는 ingesters가 링에서 사용하는 것과는 다른 "키"이며 distributor의 자체 링 구성에서 비롯됩니다. 이는 Distributor의 효율성과 안정성을 더욱 높입니다.
Ingester
Ingester는 로그 데이터를 장기 저장소 백엔드(예: DynamoDB, S3, Cassandra 등)에 저장하고, 필요 시 인메모리 쿼리를 통해 이 데이터를 빠르게 검색하는 역할을 합니다.
Ingester의 주요 기능 및 특징:
- 수명 주기 관리: Ingester 내에는 lifecycler라고 불리는 컴포넌트가 포함되어 있어, 해시 링을 통해 각 Ingester의 생명 주기를 관리합니다. Ingester의 상태는 PENDING, JOINING, ACTIVE, LEAVING, 또는 UNHEALTHY 중 하나입니다.
- 청크 처리: 로그 스트림은 메모리 내에서 여러 '청크' 집합으로 관리되며, 설정 가능한 주기에 따라 장기 저장소 백엔드로 플러시됩니다. 청크는 용량에 도달하거나, 업데이트 없이 일정 시간이 지나거나, 플러시가 발생할 때 압축되고 읽기 전용으로 전환됩니다.
- 데이터 복제: 갑작스러운 프로세스 종료나 충돌로 인해 아직 플러시되지 않은 데이터 손실을 방지하기 위해, Loki는 로그 데이터를 여러 Ingester에 복제합니다(일반적으로 3개,replication_factor). 이는 데이터의 안정성과 가용성을 높입니다.
- Timestamp Ordering: Loki는 설정을 통해 시간 순서가 뒤섞인 데이터 쓰기를 허용할 수 있습니다. 이러한 설정 없이는 Ingester가 순서대로 입력되는 로그 라인을 확인하고, 순서가 맞지 않는 경우 오류를 반환합니다.
- 파일 시스템 지원: Ingester는 BoltDB를 통해 파일 시스템에 쓰기를 지원하지만, queriers가 동일한 백엔드 저장소에 액세스해야 하고 BoltDB는 주어진 시간에 하나의 프로세스만 DB에 대한 잠금을 가질 수 있도록 허용하기 때문에 단일 프로세스 모드에서만 작동합니다.
작동 방식:
- 플러시: 장기 저장소로의 플러시 과정에서, 청크는 테넌트, 레이블, 콘텐츠를 기반으로 해시되어 중복된 데이터의 백업 저장소 쓰기를 방지합니다. 그러나 복제본 중 하나에 쓰기가 실패하면 여러 개의 서로 다른 청크 객체가 생성될 수 있습니다.
이러한 기능과 특징들은 Ingester가 Grafana LGTM 아키텍처에서 중요한 역할을 수행하게 합니다. 데이터의 안정적인 저장과 효율적인 검색을 보장하는 동시에, 시스템의 전반적인 신뢰성과 성능을 높이는 데 기여합니다.
로그 스트림이 청크에 저장되는 과정:
- distributor는 스트림(로그)에 대한 데이터를 저장하기 위한 HTTP/1 요청을 받습니다.
- 각 스트림은 해시 링을 사용하여 해시됩니다.
- distributor는 각 스트림을 적절한 ingesters에 해당 복제본으로 보냅니다.
- 각 ingesters는 스트림 데이터에 대해 청크를 생성하거나 기존 청크에 추가합니다. 청크는 테넌트 및 레이블 세트별로 고유합니다.
- distributor는 HTTP/1 연결을 통해 성공 코드로 응답합니다.
Read Path: Query frontend, Querier
아래는 로그 스트림이 장기 저장소에 읽어지는 과정을 Component와 함께 나타냅니다.
Query Frontend와 Querier의 조합은 Grafana Loki에서 데이터 검색과 분석을 위한 효율적이고 강력한 읽기 경로를 제공합니다. 이러한 구조는 대규모 데이터 세트에 대한 쿼리 처리 시간을 줄이고, 시스템의 전반적인 성능과 확장성을 향상시키는 데 중요한 역할을 합니다. 특히, 캐싱과 쿼리 분할 같은 기능은 쿼리 응답 시간을 단축시키고 사용자 경험을 개선하는 데 크게 기여합니다.
Query frontend(optional service)
Query Frontend는 실제 쿼리를 실행하는 Querier를 보조하여 읽기 경로의 성능을 향상시키는 서비스입니다. 이 서비스는 쿼리 실행을 더 효율적으로 만들기 위해 다음과 같은 주요 기능을 수행합니다:
- 큐잉(Queueing): 큰 쿼리로 인한 메모리 부족 문제를 방지하고, 공정한 스케줄링을 가능하게 합니다. 이는 더 작은 쿼리의 병렬 실행을 통해 전체 소유 비용(TCO)을 줄이는 데 기여합니다.
- 분할(Splitting): 큰 쿼리를 여러 작은 쿼리로 분할하여 Querier의 메모리 부족 문제를 예방하고, 쿼리 결과를 더 빠르게 도출할 수 있도록 합니다.
- 캐싱(Caching): 쿼리 결과를 캐시하여 후속 쿼리에서 재사용합니다. 이는 쿼리 수행 시간을 단축시키고 전반적인 시스템 성능을 향상시키는 데 도움이 됩니다.
Query Frontend는 상태를 유지하지 않는 서비스로, 일반적으로 두 개의 복제본으로 운영되며, 이는 가용성을 높이면서도 리소스 사용을 최적화합니다.
Querier
Querier는 LogQL 쿼리 언어를 사용하여 로그 데이터에 대한 쿼리를 처리합니다. Querier의 주요 작업은 다음과 같습니다:
- 인메모리 데이터 및 장기 저장소 쿼리: 모든 Ingester에서 현재 메모리에 있는 데이터를 쿼리한 다음, 같은 쿼리를 장기 저장소에 대해서도 실행합니다. 이는 실시간 데이터와 과거 데이터 모두에 대한 쿼리를 가능하게 합니다.
- 중복 제거: 복제로 인해 중복된 데이터를 수신할 수 있는데, Querier는 동일한 나노초 타임스탬프, 레이블 세트 및 로그 메시지를 가진 데이터를 중복 제거하여 최종 쿼리 결과의 정확성을 보장합니다.
Read Path에서 로그 스트림이 읽어지는 과정:
- querier는 데이터에 대한 HTTP/1 요청을 받습니다.
- querier는 인메모리 데이터에 대한 쿼리를 모든 ingesters에 전달합니다.
- ingesters는 읽기 요청을 수신하고 쿼리와 일치하는 데이터가 있는 경우 반환합니다.
- querier는 데이터를 반환한 ingesters가 없는 경우 백업 저장소에서 데이터를 느리게 로드하고 이에 대해 쿼리를 실행합니다.
- querier는 수신된 모든 데이터를 반복하고 중복을 제거하여 HTTP/1 연결을 통해 최종 데이터 세트를 반환합니다.
Consistent Hash Rings
이 기술은 로그 라인의 샤딩, 고가용성 구현, 그리고 클러스터의 수평적 확장성(scaling)을 용이하게 하는 데 사용됩니다. 해시 링은 Loki의 다양한 컴포넌트 간의 효율적인 데이터 분배와 관리를 가능하게 합니다. 각각의 노드는 Loki 시스템 내의 특정 컴포넌트 인스턴스를 대표하며, 키-값 저장소에는 해당 인스턴스의 통신 정보가 저장됩니다.
일관된 해시 링의 주요 특징 및 용도
- Distributor Ring: Distributor의 수를 계산하는 데 사용됩니다. 이는 로그 데이터가 어떻게 분산되어야 할지 결정하는 데 중요한 역할을 합니다.
- Ingester Ring: 로그 라인을 어느 Ingester에 전달할지 결정하는 데 사용됩니다. 이는 데이터의 안정적인 저장과 검색을 위한 효율적인 데이터 분배 메커니즘을 제공합니다.
- Query Scheduler Ring: 서비스 탐색에 사용됩니다. 쿼리 요청을 효율적으로 처리할 Querier를 결정하는 데 도움을 줍니다.
- Compactor Ring: 로그 데이터의 압축을 담당할 인스턴스를 식별하는 데 사용됩니다. 이는 저장 공간의 효율적 사용과 데이터 처리 성능 향상에 기여합니다.
- Ruler Ring: 어떤 규칙 그룹을 평가할지 결정하는 데 사용됩니다. 이는 경고 및 메트릭 규칙을 효율적으로 관리하고 실행하는 데 중요합니다.
- Index Gateway Ring(선택적): 어떤 게이트웨이가 특정 테넌트의 인덱스를 담당할지 결정하는 데 사용됩니다. 이는 인덱스 데이터의 관리와 접근성을 향상시킵니다.
중요성 및 이점
일관된 해시 링은 Grafana Loki의 분산 시스템에서 데이터를 균등하게 분배하고, 컴포넌트 간의 효율적인 통신을 가능하게 하는 핵심 메커니즘입니다. 이는 시스템의 확장성, 고가용성, 그리고 관리 용이성을 보장합니다. 또한, 클러스터의 동적인 스케일 업과 스케일 다운을 지원하여, 변화하는 워크로드에 빠르게 대응할 수 있게 합니다. 일관된 해시 링을 통한 데이터의 효율적인 분배는 리소스 사용 최적화와 시스템의 전반적인 성능 향상을 이끌어내며, Grafana Loki를 대규모 로그 데이터를 처리하는 강력한 도구로 만듭니다.
Multi-tenancy
Grafana Loki는 멀티테넌트 모드를 지원하여, 여러 사용자 또는 팀이 동일한 Loki 인스턴스를 공유할 수 있도록 합니다. 이 모드에서는 메모리와 장기 저장소에 있는 모든 데이터가 HTTP 요청의 X-Scope-OrgID 헤더에서 가져온 테넌트 ID에 따라 파티셔닝됩니다. 멀티테넌트 모드가 아닐 경우, 테넌트 ID는 "fake"로 설정되며, 이는 모든 사용자의 데이터가 동일한 인덱스와 저장된 청크에 표시됨을 의미합니다. 이 기능은 데이터의 격리와 보안을 강화하며, 리소스 사용의 효율성을 높입니다.
Storage
TSDB
Loki 버전 2.8부터는 TSDB(Time Series Database)를 사용하여 인덱스 저장소로서 NoSQL 저장소에 의존하지 않고도 Loki를 실행할 수 있게 되었습니다. 이전 버전까지는 **Single Store(boltdb-shipper)**가 이 역할을 담당했습니다. TSDB를 사용하면 모든 데이터(청크와 인덱스)를 단일 오브젝트 스토리지 백엔드에 저장할 수 있으며, 이는 운영의 단순화, 비용 절감, 그리고 성능 향상을 가능하게 합니다. TSDB 어댑터를 통한 인덱스 저장은 청크 저장 방식과 유사하게 진행되어, Loki의 데이터 관리 방식을 더욱 통합하고 효율적으로 만듭니다.
이러한 요소들은 Grafana Loki를 효과적으로 운영하기 위한 핵심적인 부분이며, 대규모 로그 데이터 관리 시스템의 설계와 구현에 중요한 기여를 합니다. Loki의 멀티테넌시 지원과 TSDB를 활용한 스토리지 관리는 사용자가 대규모 로그 데이터를 보다 유연하고 효율적으로 처리할 수 있게 돕습니다.
Deployment modes
Monolithic mode
하루에 최대 약 100GB의 읽기/쓰기 볼륨에 유용합니다.
Shared object store를 사용하여 라운드 로빈 방식 라우팅의 수평적 확장 구성 가능합니다.
Simple scalable deployment mode
하루에 수백 GB를 초과하거나 읽기 및 쓰기 문제를 분리하려는 경우에 유용합니다.
이 배포 모드는 하루에 몇 TB 이상의 로그로 확장할 수 있습니다.
Microservices mode
components를 개별 마이크로서비스로 실행하면 마이크로서비스의 양을 늘려 확장할 수 있습니다.
마이크로서비스 모드는 규모가 매우 큰 Loki 클러스터 또는 확장 및 클러스터 작업을 더 많이 제어해야 하는 클러스터에 권장됩니다.
'Observability > Loki' 카테고리의 다른 글
[Promtail]Install promtail with helm chart (0) | 2024.03.03 |
---|---|
[Loki]Install Grafana loki-distributed with helm chart (6) | 2023.06.03 |
[Loki]What is Grafana Loki? (0) | 2023.06.01 |