26F12H

Young-Kyoo Kim·2026년 2월 11일

감사 로그 최적화 회의록


1. 회의 배경

1.1 현재 상황

감사 로그 규모

고객사 설명:

"Logging like daily? Approximately [one] 150 gigabyte to... 
a maximum 250 gigabytes... for the audit logging."

현재 상태:

  • 일일 로그: 150~250 GB
  • 로그 수: 100~200 million 로그/일
  • 대상: OpenSearch

로그 타입

벤더 확인:

"event log and Audit Log... they're monitoring is bucket level 
[operations]"

로그 종류:
1. Audit Log: 모든 API 호출 (GET, PUT, DELETE)
2. Event Log: Bucket 이벤트 (특정 작업)

1.2 문제점

과도한 트래픽

고객사 우려:

"They found it too much... it's too chatty."

문제:

  • Chatty: 너무 많은 로그
  • OpenSearch 부하: Receiver 과부하
  • 네트워크: 대역폭 소모

2. 현재 아키텍처

2.1 로그 파이프라인

구조:

MinIO Cluster (54 nodes)
  ↓ (Audit Log)
Fluentd (Log aggregator)
  ↓ (Webhook/HTTP)
OpenSearch (Log storage)
  ↓
Kibana (Visualization)

2.2 Fluentd 설정

현재 설정:

# fluentd.conf (추정)
<source>
  @type http
  port 8888
  bind 0.0.0.0
</source>

<match minio.audit.**>
  @type opensearch
  host opensearch.example.com
  port 9200
  index_name minio-audit-%Y%m%d
  
  # 문제: Batch size 미설정 또는 작음
  # flush_interval 1s
  # chunk_limit_size 1M
</match>

문제:

  • 개별 전송: 로그마다 HTTP 요청
  • Chatty: 초당 수천 건 요청
  • Overhead: Network/CPU

3. 최적화 방안

3.1 Batch Size 증가

권장 설정

벤더 제안:

"So if you do batch size 100 fluent[d]"

Fluentd 최적화:

<match minio.audit.**>
  @type opensearch
  host opensearch.example.com
  port 9200
  index_name minio-audit-%Y%m%d
  
  # 배치 설정
  <buffer>
    @type file
    path /var/log/fluentd/buffer/opensearch
    
    # 핵심: Batch size
    chunk_limit_size 10M
    flush_interval 10s
    flush_at_shutdown true
    
    # 재시도
    retry_type exponential_backoff
    retry_wait 1s
    retry_max_interval 60s
    retry_timeout 1h
  </buffer>
  
  # Bulk insert
  bulk_message_request_threshold 100
  
  # 압축
  compression gzip
</match>

효과

벤더 설명:

"it will just make [OpenSearch] less chatty, because right now, 
less traffic"

Before (개별 전송):

100M logs/day ÷ 86400 seconds ≈ 1,157 requests/second

After (Batch 100):

100M logs/day ÷ 100 per batch ÷ 86400 seconds ≈ 12 requests/second

개선:

  • Request 수: 99% 감소
  • Network overhead: 대폭 감소
  • OpenSearch 부하: 최소화

3.2 로그 크기 vs 트래픽

벤더 확인:

"less traffic, but... the size of logs will be the same."

주의:

  • 로그 크기: 변화 없음 (150~250 GB/일)
  • 트래픽 패턴: 개선 (Chatty → Batch)
  • 저장 공간: 동일

비유:

Before: 100만 개 소포 (개별 배송)
After: 1만 개 컨테이너 (100개씩 묶음)
총 화물 무게: 동일
배송 횟수: 99% 감소

3.3 OpenSearch 최적화

Bulk API 사용

설정:

POST /_bulk
{ "index": { "_index": "minio-audit-20260202" } }
{ "timestamp": "2026-02-02T10:00:00Z", "user": "admin", "action": "GET" }
{ "index": { "_index": "minio-audit-20260202" } }
{ "timestamp": "2026-02-02T10:00:01Z", "user": "user1", "action": "PUT" }
...
(100개 batch)

장점:

  • 단일 HTTP 요청: 100개 로그
  • Parsing 효율: 한 번에 처리
  • Indexing: 최적화

Index 설정

PUT /minio-audit-template
{
  "index_patterns": ["minio-audit-*"],
  "settings": {
    "number_of_shards": 3,
    "number_of_replicas": 1,
    "refresh_interval": "30s",
    "codec": "best_compression"
  }
}

최적화:

  • Refresh interval: 30초 (즉시성 < 성능)
  • Compression: 저장 공간 절약
  • Shards: 적절한 분산

4. 로그 보관 전략

4.1 Hot-Warm-Cold Architecture

벤더 제안:

"You could just keep a day of how it looks in [OpenSearch], or 
a month, and then everything else, take it out and put it into 
[like] a compressed [file]."

계층:

Hot (OpenSearch):

  • 기간: 최근 1일~1개월
  • 용도: 실시간 검색/분석
  • 성능: 빠름
  • 비용: 높음

Warm (S3/MinIO):

  • 기간: 1~12개월
  • 형식: Parquet/JSON (압축)
  • 용도: 주기적 분석
  • 성능: 중간
  • 비용: 중간

Cold (S3/MinIO):

  • 기간: 12개월+
  • 형식: 고압축 (Snappy/Gzip)
  • 용도: 컴플라이언스/아카이브
  • 성능: 느림
  • 비용: 낮음

4.2 자동 Tiering

Curator 설정:

# curator_actions.yml
actions:
  1:
    action: delete_indices
    description: Delete indices older than 30 days
    options:
      ignore_empty_list: True
    filters:
    - filtertype: pattern
      kind: prefix
      value: minio-audit-
    - filtertype: age
      source: name
      direction: older
      timestring: '%Y%m%d'
      unit: days
      unit_count: 30

또는 ILM (Index Lifecycle Management):

PUT /_ilm/policy/minio-audit-policy
{
  "policy": {
    "phases": {
      "hot": {
        "actions": {}
      },
      "warm": {
        "min_age": "7d",
        "actions": {
          "forcemerge": { "max_num_segments": 1 },
          "shrink": { "number_of_shards": 1 }
        }
      },
      "delete": {
        "min_age": "30d",
        "actions": {
          "delete": {}
        }
      }
    }
  }
}

4.3 S3/MinIO로 Export

Lambda/Cron 작업:

#!/usr/bin/env python3
import boto3
from datetime import datetime, timedelta
from elasticsearch import Elasticsearch

es = Elasticsearch(['http://opensearch:9200'])
s3 = boto3.client('s3', endpoint_url='http://minio:9000')

# 7일 이상 지난 로그
cutoff = datetime.now() - timedelta(days=7)
index = f"minio-audit-{cutoff.strftime('%Y%m%d')}"

# OpenSearch에서 추출
query = {"query": {"match_all": {}}}
result = es.search(index=index, body=query, scroll='5m', size=10000)

# S3에 저장 (Parquet)
logs = [hit['_source'] for hit in result['hits']['hits']]
df = pd.DataFrame(logs)
df.to_parquet(f's3://audit-archive/{index}.parquet', compression='snappy')

# OpenSearch에서 삭제
es.indices.delete(index=index)

5. Audit Log vs Event Log

5.1 차이점

벤더 설명:

"Audit log has the same data. It has more data... As long as 
you have access to audit log, you can basically do everything"

비교:

항목Audit LogEvent Log
범위모든 API 호출특정 Bucket 이벤트
상세도매우 상세선택적
용도컴플라이언스, 추적알림, 워크플로우
크기매우 큼작음

5.2 Audit Log 내용

포함 정보:

  • Timestamp: 정확한 시간
  • User: LDAP/IAM 사용자
  • Action: GET, PUT, DELETE, LIST
  • Bucket/Object: 리소스 경로
  • IP Address: 클라이언트 IP
  • User Agent: 애플리케이션
  • Response: 성공/실패
  • Bytes: 전송 크기

예시:

{
  "timestamp": "2026-02-02T10:15:30Z",
  "user": "ldap:john.doe@company.com",
  "action": "s3:GetObject",
  "bucket": "data-warehouse",
  "object": "2026/02/sales.parquet",
  "ip": "10.0.1.100",
  "user_agent": "Spark/3.5.0",
  "status": 200,
  "bytes_sent": 134217728
}

5.3 Event Log (Bucket Events)

벤더 설명:

"Bucket events... you need to send them on a bucket level."

설정:

# Bucket event 설정
mc event add minio/data-warehouse \
  arn:minio:sqs::primary:webhook:audit \
  --event put,delete

# Webhook endpoint
# POST http://event-processor:8080/webhook

사용 사례:

  • Lambda 트리거: 새 파일 → 처리
  • 알림: 삭제 이벤트 → Slack
  • 워크플로우: PUT → Data pipeline

6. 사용자별 추적

6.1 요구사항

벤더 설명:

"if I do every time somebody does a put, and I can track that 
based on their LDAP name... Do you want to track it to one bucket 
or lots of buckets?"

시나리오:

  • 사용자: LDAP 기반
  • 작업: GET, PUT, DELETE
  • 범위: 특정 Bucket 또는 전체

6.2 Audit Log 쿼리

OpenSearch Query:

GET /minio-audit-*/_search
{
  "query": {
    "bool": {
      "must": [
        { "match": { "user": "ldap:john.doe@company.com" } },
        { "match": { "action": "s3:PutObject" } },
        { "match": { "bucket": "shared-data" } }
      ],
      "range": {
        "timestamp": {
          "gte": "2026-02-01",
          "lte": "2026-02-28"
        }
      }
    }
  },
  "aggs": {
    "total_bytes": {
      "sum": { "field": "bytes_sent" }
    },
    "count": {
      "value_count": { "field": "action" }
    }
  }
}

결과:

{
  "hits": { "total": 15234 },
  "aggregations": {
    "total_bytes": { "value": 524288000000 },
    "count": { "value": 15234 }
  }
}

해석:

  • John Doe가 2월에 shared-data에
  • 15,234번 PUT
  • 524 GB 업로드

6.3 비용 청구

벤더 설명:

"you have to track their gets. You have to track their puts and 
their deletes. Gets usually don't [matter] unless you're tracking 
API costs"

추적 항목:

Storage Cost:

  • PUT (업로드)
  • DELETE (삭제 - 용량 회수)

API Cost:

  • GET (다운로드 - 대역폭)
  • LIST (메타데이터)
  • HEAD (존재 확인)

SQL 예시:

-- 사용자별 월별 사용량
SELECT 
  user,
  action,
  COUNT(*) as request_count,
  SUM(bytes_sent) / 1024 / 1024 / 1024 as total_gb,
  DATE_FORMAT(timestamp, '%Y-%m') as month
FROM minio_audit_logs
WHERE timestamp >= '2026-02-01'
  AND timestamp < '2026-03-01'
GROUP BY user, action, month
ORDER BY total_gb DESC;

7. 모니터링 및 Alert

7.1 Kibana Dashboard

주요 지표:

Overview:

  • Total Requests/sec
  • Error Rate (%)
  • Top Users
  • Top Buckets

Performance:

  • Request Latency (p50, p95, p99)
  • Bytes Transferred
  • Slow Queries (> 1s)

Security:

  • Failed Authentication
  • Unauthorized Access
  • Unusual Activity

예시 Query:

// Failed requests
GET /minio-audit-*/_search
{
  "query": {
    "bool": {
      "must": [
        { "range": { "status": { "gte": 400 } } },
        { "range": { "timestamp": { "gte": "now-1h" } } }
      ]
    }
  },
  "aggs": {
    "by_user": {
      "terms": { "field": "user.keyword", "size": 10 }
    }
  }
}

7.2 Alert 규칙

OpenSearch Alerting:

{
  "name": "High Error Rate",
  "type": "monitor",
  "schedule": {
    "period": {
      "interval": 5,
      "unit": "MINUTES"
    }
  },
  "inputs": [{
    "search": {
      "indices": ["minio-audit-*"],
      "query": {
        "bool": {
          "filter": [
            { "range": { "timestamp": { "gte": "now-5m" } } },
            { "range": { "status": { "gte": 400 } } }
          ]
        }
      }
    }
  }],
  "triggers": [{
    "name": "Error rate > 5%",
    "severity": "1",
    "condition": {
      "script": {
        "source": "ctx.results[0].hits.total.value > 100"
      }
    },
    "actions": [{
      "name": "Slack notification",
      "destination_id": "slack-webhook",
      "message_template": {
        "source": "High error rate detected: {{ctx.results[0].hits.total.value}} errors in last 5 minutes"
      }
    }]
  }]
}

8. 액션 아이템

8.1 벤더 측 (MinIO/AIStore)

즉시 실행 (1주일 내)

  1. Fluentd 최적화 가이드

    • Batch size 설정 예시
    • Buffer 설정
    • Compression 활성화
  2. OpenSearch 통합 문서

    • Bulk API 사용
    • Index template
    • ILM 정책
  3. 보관 전략 문서

    • Hot-Warm-Cold
    • S3 export 스크립트
    • Parquet 변환

단기 (2주일 내)

  1. 사용자 추적 가이드
    • Audit log 쿼리 예시
    • 비용 청구 리포트
    • Kibana Dashboard 템플릿

8.2 고객사 측 (SK Hynix)

즉시 실행

  1. Fluentd 설정 최적화

    • Batch size 100 적용
    • Buffer 설정 조정
    • 압축 활성화
  2. 모니터링

    • Request rate 측정 (Before/After)
    • OpenSearch 부하 확인
    • 네트워크 트래픽 분석
  3. OpenSearch 최적화

    • Index template 적용
    • ILM 정책 설정
    • Refresh interval 조정

단기 (Q2 2026)

  1. 보관 정책 구현

    • 30일 이상 로그 삭제
    • S3/MinIO export 자동화
    • Parquet 변환
  2. Dashboard 구축

    • Kibana 대시보드
    • Alert 설정
    • 사용자별 리포트

9. 예상 효과

9.1 성능 개선

Request 수:

  • Before: 1,157 req/sec
  • After: 12 req/sec
  • 개선: 99% 감소

OpenSearch 부하:

  • CPU: 80% → 20%
  • Network: 대폭 감소
  • Indexing: 안정화

9.2 비용 절감

네트워크:

  • HTTP overhead 99% 감소
  • 압축으로 전송량 감소

저장 공간:

  • Hot: 1일 (최소화)
  • Warm/Cold: 압축 (50% 절감)

운영:

  • OpenSearch 리소스 최적화
  • Alert 노이즈 감소

10. 위험 요소 및 완화

10.1 로그 지연

위험

  • Batch 처리로 지연 발생
  • 실시간성 저하

완화

  • ✅ Flush interval 조정 (10s)
  • ✅ 중요 이벤트는 별도 처리
  • ✅ Alert는 즉시 전송

10.2 Buffer 오버플로우

위험

  • 대량 로그 발생 시 Buffer 부족
  • 로그 손실

완화

  • ✅ 충분한 Buffer 크기 (10M)
  • ✅ Disk buffer 사용
  • ✅ 모니터링 및 Alert

10.3 OpenSearch 용량

위험

  • 150~250 GB/일 누적
  • 저장 공간 부족

완화

  • ✅ ILM 정책 (30일 삭제)
  • ✅ S3 export (자동화)
  • ✅ 용량 모니터링

11. 참고 자료

11.1 MinIO 문서

  • Audit Logging
  • Webhook Target
  • Bucket Events

11.2 Fluentd 문서

  • Buffer Plugin
  • OpenSearch Output
  • Performance Tuning

11.3 OpenSearch 문서

  • Bulk API
  • Index Lifecycle Management
  • Alerting

12. 결론 및 다음 단계

12.1 핵심 합의사항

  1. Batch size 100 (Fluentd)
  2. ILM 30일 (OpenSearch)
  3. S3 export (자동화)
  4. 압축 활성화 (Gzip)
  5. Dashboard 구축 (Kibana)

12.2 즉시 실행 항목

  • Fluentd 설정 최적화
  • Request rate 모니터링
  • ILM 정책 적용

12.3 성공 기준

  • ✅ Request rate 99% 감소
  • ✅ OpenSearch CPU < 30%
  • ✅ 로그 지연 < 30초
  • ✅ 저장 공간 최적화

문서 버전: 1.0
최종 수정일: 2026년 2월 2일
다음 리뷰: 최적화 적용 후 (2026년 2월 중순)


부록: 주요 인용문

로그 규모

"Logging like daily? Approximately [one] 150 gigabyte to... 
a maximum 250 gigabytes... for the audit logging."

Chatty 문제

"They found it too much... it's too chatty."

Batch 해결책

"So if you do batch size 100 fluent[d]... it will just make 
[OpenSearch] less chatty"

로그 크기 불변

"less traffic, but... the size of logs will be the same."

보관 전략

"You could just keep a day... in [OpenSearch], or a month, and 
then everything else, take it out and put it into [like] a 
compressed [file]."

Audit Log 포괄성

"Audit log has the same data. It has more data... As long as 
you have access to audit log, you can basically do everything"

0개의 댓글