결론부터 말씀드리면 100% 구현 가능함. 다만, 앞서 언급하신 대로 하나의 버킷에 수억 건의 객체가 존재할 수 있는 고부하 환경이므로, 아무런 대책 없이 S3 ListObjects API를 순정 상태로 호출하면 API 서버와 MinIO 클러스터가 동시에 타임아웃으로 붕괴할 위험이 있음.
따라서 이 API는 1) 이전에 설계한 CNPG 메타 DB를 조회하는 방식(가장 추천) 또는 2) MinIO AIStor API를 극한으로 최적화하여 래핑하는 방식 중 하나를 선택하여 구현해야 함.
Kafka ➡️ Redis ➡️ CNPG 파이프라인을 통해 메타데이터를 이미 적재하고 있다면, S3를 찌를 필요가 전혀 없음. API 서버는 단순한 SQL 쿼리 실행기 역할만 수행하므로 리스크가 제로에 가까움.
/usage)COUNT와 SUM을 집계하여 리턴함.-- API 서버 내부에서 실행할 쿼리
SELECT COUNT(*) as total_objects, COALESCE(SUM(size), 0) as total_bytes
FROM storage_objects
WHERE prefix_id = (SELECT id FROM storage_prefixes WHERE full_path = :request_prefix);
/objects)GET /api/v1/storage/objects?prefix=dir1/&limit=1000&cursor_file=last_seen_file.txtSELECT name, size, created_at
FROM storage_objects
WHERE prefix_id = :prefix_id AND name > :cursor_file
ORDER BY name ASC
LIMIT :limit;
만약 실시간 정합성을 위해 메타 DB를 거치지 않고 MinIO 스토리지를 직접 찔러야 한다면, API 서버 내부에서 MinIO Go/Python SDK를 사용할 때 S3 호환 파라미터를 세밀하게 통제해야 함.
DataUsageInfo)을 제공함.# API 서버 내부 가상 코드
from minio import Minio
# Admin 클라이언트를 통해 S3 리스팅 없이 서버 측 집계 데이터 반환 요청
# (주의: 이 또한 수억 건인 경우 백엔드 가비지 컬렉션 주기에 따라 약간의 레이턴시가 있을 수 있음)
usage_info = minio_admin_client.get_bucket_usage(bucket_name, prefix=target_prefix)
return {
"size_bytes": usage_info.size,
"object_count": usage_info.object_count
}
Delimiter='/'): 수억 개의 하위 파일을 다 가져오지 않고, 파일 시스템 탐색기처럼 딱 현재 레벨의 하위 폴더(Prefix)와 파일 목록만 끊어서 가져오도록 래핑해야 함.NextContinuationToken)를 API 서버가 보관하지 말고, 최종 클라이언트(포털 또는 Workbench)에게 그대로 넘겨주어 무상태(Stateless)를 유지해야 함.GET /api/v1/storage/raw-list?prefix=dir1/&token=xyz...# API 서버가 MinIO SDK를 호출할 때 설정을 극단적으로 타이트하게 제한
objects = minio_client.list_objects(
bucket_name,
prefix=requested_prefix,
recursive=False, # ◀ 수억 건 폭주를 막기 위해 하위 폴더 재귀 탐색 절대 금지
delimiter='/', # ◀ 딱 한 단계 아래의 구조만 단건 분리
max_keys=100, # ◀ 한 번에 최대 100개씩만 페이징
start_after=requested_token
)
COUNT/SUM): MinIO Admin API를 래핑하거나, Prometheus 메트릭 엔드포인트를 API 서버가 파싱해서 던져주는 방식이 안전함.ListObjects): 6,000개 테넌트 규모에서는 결국 유저들이 각자 자기가 구축한 메타 DB(방안 1)를 조회하게 유도하고, 진짜 S3 스토리지 다이렉트 리스팅 API는 아주 특수한 관리자 UI나 Workbench 초기 로딩 시점에만 Strict 페이징(Recursive=False, MaxKeys=100)을 걸어 제한적으로 제공하는 것이 리스크를 관리하는 정석임.