일상 코딩
[PostgreSQL] 백엔드 복잡성의 종말: PostgreSQL 하나로 구축하는 고효율·저비용 아키텍처 본문
[PostgreSQL] 백엔드 복잡성의 종말: PostgreSQL 하나로 구축하는 고효율·저비용 아키텍처
polarcompass 2026. 1. 1. 06:36[보고서] 백엔드 복잡성의 종말: PostgreSQL 하나로 구축하는 고효율·저비용 아키텍처
1. Executive Summary (핵심 요약)
본 영상은 현대 웹 개발 환경이 직면한 '과잉 도구화(Over-tooling)'와 그로 인한 비용/복잡성 문제를 날카롭게 지적합니다. 발표자는 레디스(Redis), 일라스틱 서치(Elasticsearch), 오스제로(Auth0) 등 각기 다른 외부 서비스를 연동하는 대신, PostgreSQL의 확장 기능과 내장 기능만으로 백엔드 인프라를 단일화할 수 있는 실무적 대안을 제시합니다.
단순히 DB의 역할을 넘어 캐싱, 예약 작업, AI 벡터 검색, 인증을 하나의 시스템(SQL 기반)으로 통합함으로써, 개발자는 API 요금과 인프라 설정에 드는 에너지를 줄이고 핵심 비즈니스 로직에 집중할 수 있습니다. 특히 리소스가 제한된 1인 개발자나 소규모 팀의 MVP(최소 기능 제품) 제작에 있어 PostgreSQL은 가장 강력하고 경제적인 '백엔드 플랫폼'으로서의 독창적 가치를 증명합니다.
2. 위계적 개요 (Hierarchical Outline)
- 도입: 현대 백엔드 개발의 복잡성과 비용 문제 [00:00]
- 항목 01: 데이터 캐싱과 임시 데이터 처리 (vs Redis) [00:54]
- 항목 02: 예약 작업 및 스케줄링 관리 (vs Cron/Lambda) [01:34]
- 항목 03: 고급 검색 및 AI 기능 구현 (vs Elasticsearch/Vector DB) [02:18]
- 항목 04: 사용자 인증 및 보안 로직 (vs Auth0/Firebase) [03:13]
- 결론: PostgreSQL 기반의 통합 백엔드 전략과 기대효과 [04:06]
3. 주요 내용 심층 분석
서론: 복잡성에 갇힌 현대 개발 환경 [00:00]
- 핵심 설명: 새로운 앱을 만들 때 인증, 로그, 결제, 캐싱, 배포 자동화 등을 위해 너무 많은 외부 서비스를 붙여야 하는 상황을 비판합니다.
- 발표자 비유: "출퇴근용 자전거를 조립하려는데 과대 스펙 부품만 잔뜩 있고 정작 꼭 맞는 건 하나도 없는 상황" [00:33]
- 문제점: 불안정한 스택, 과도한 설정, 너무 많은 API 요금과 AWS 비용 발생.
항목 01: 데이터 캐싱 - Unlogged Table [00:54]
- 핵심 설명: 기존에는 세션 토큰 등 임시 데이터를 위해 레디스를 별도로 써야 했으나, PostgreSQL의 '언로그드 테이블'로 이를 대체할 수 있습니다. [01:00]
- 기능적 특징:
- 쓰기 로깅(WAL)을 건너뛰고 메모리에 상주하여 레디스와 비슷한 속도를 냄. [01:11]
- 시스템 오류 시에도 데이터 복구 가능.
- 장점 및 변형 표현:
- "SQL만으로 충분합니다." [01:22]
- "로컬 개발 환경이 단순해지며 레디스 네트워킹 설정이나 도커 컨테이너를 관리할 필요가 없습니다." [01:34]
- 1문장 요약: 별도의 인프라 구축 없이 DB 내 Unlogged Table만으로 레디스 수준의 캐싱 성능을 구현합니다.
항목 02: 예약 작업 관리 - PG_CRON [01:34]
- 핵심 설명: 서버에 직접 접속해 크론탭(Crontab)을 수정하거나 외부 스케줄러를 쓰던 방식을 데이터베이스 내부로 통합합니다. [01:45]
- 주요 예시 및 샘플 대사:
- "이제는 pg_cron 확장 기능으로 충분합니다." [01:57]
- "데이터베이스 안에서 SQL 문장을 일정 간격으로 실행하도록 예약할 수 있습니다." [01:57]
- 상황별 적용 예시:
- 깃허브 액션(GitHub Actions)의 정리 작업 대체. [02:09]
- AWS 람다(Lambda)의 타이머 함수 대체. [02:09]
- 강조 포인트: 스케줄을 테이블 행처럼 다룰 수 있어 쿼리 한 번으로 수정/중지가 가능하다는 점이 매우 편리함. [02:18]
- 1문장 요약: DB 확장 기능을 통해 복잡한 외부 스케줄러 없이 SQL만으로 모든 예약 작업을 제어합니다.
항목 03: 검색 및 AI 기능 - TS_VECTOR & PG_VECTOR [02:18]
- 핵심 설명: 일라스틱 서치나 파인콘(Pinecone) 같은 무거운 검색 엔진 없이도 고급 검색과 AI 기능을 구현합니다. [02:31]
- 기술적 구현 예시:
- 전체 텍스트 검색: "TS Vector 기능으로 처리할 수 있습니다." [02:43]
- AI 벡터 검색: "PG Vector 확장 기능을 통해 벡터 데이터 타입을 추가하고 임베딩을 저장할 수 있습니다." [02:43]
- 장점 및 시너지:
- "시멘틱 검색과 일반 SQL 필터를 함께 쓸 수 있습니다." [03:04]
- "별도 벡터 데이터베이스 요금이 사라집니다." [03:04]
- 1문장 요약: 텍스트 검색부터 최신 RAG(검색 증강 생성) 시스템의 기반인 벡터 검색까지 DB 하나로 해결합니다.
항목 04: 인증 및 보안 - PG_CRYPTO & RLS [03:13]
- 핵심 설명: 유료 인증 서비스(Auth0, Firebase Auth)를 쓰지 않고도 안전한 프로덕션급 인증 시스템을 구축할 수 있습니다. [03:24]
- 보안 도구 발췌:
- pg_crypto: "비밀번호를 안전하게 해시합니다." [03:34]
- RLS (Row Level Security, 행 수준 보안): "사용자별로 데이터를 보호하며, 모든 쿼리는 자동으로 현재 사용자에 맞게 제한됩니다." [03:46]
- 실제 상황 예시: "고객마다 자기 데이터만 볼 수 있어야 하는 멀티테넌트(Multi-tenant) 앱에서 특히 유용합니다." [03:46]
- 1문장 요약: 행 수준 보안과 암호화 기능을 결합하여 외부 솔루션 없이 견고한 멀티테넌트 인증 체계를 만듭니다.
4. 핵심 질문 생성 및 답변
- Q: PostgreSQL이 어떻게 레디스만큼 빠를 수 있나요?
- A:
Unlogged Table설정을 통해 쓰기 로깅(WAL) 과정을 생략하고 데이터를 메모리 위주로 처리하기 때문에 레디스에 비견되는 속도를 낼 수 있습니다. [01:11]
- Q: pg_cron을 사용하면 어떤 관리적 이점이 있나요?
- A: 서버의 크론 설정 파일을 직접 수정할 필요 없이, SQL 쿼리만으로 예약 작업을 생성, 수정, 삭제할 수 있어 관리가 매우 직관적입니다. [02:18]
- Q: 대규모 AI 프로젝트에도 pg_vector가 적합한가요?
- A: 영상에서는 "몇 만 개 벡터를 다루는 앱이라면 pg_vector 하나로 충분하다"고 명시하며, 복잡한 인프라 대신 단순함을 선택할 것을 권장합니다. [03:13]
- Q: RLS(행 수준 보안)가 인증 개발 시간을 어떻게 단축하나요?
- A: 각 마이크로서비스나 API 레벨에서 일일이 권한 체크 코드를 짤 필요 없이, DB 레벨에서 사용자 세션에 맞춰 데이터 접근을 원천 차단하기 때문입니다. [03:59]
- Q: 이 아키텍처는 어떤 팀에게 가장 추천되나요?
- A: 최소 기능 제품(MVP)을 만드는 작은 팀이나, 사스(SaaS) 프로젝트를 운영하며 비용 효율성을 극대화하려는 개발팀에 적합합니다. [04:39]
5. 전략적 인사이트 및 실전 적용 팁
- 단일 소스 기반 진실(Single Source of Truth): 데이터와 로직(스케줄링, 검색, 보안)이 한곳에 모여 있어 데이터 동기화 문제에서 자유로워집니다.
- 비용 최적화 팁: 여러 개의 유료 사스(SaaS) 구독료를 지불하는 대신, 고성능 PostgreSQL 인스턴스 하나에 리소스를 집중 투자하는 것이 운영 효율 면에서 유리합니다.
- 적용 아이디어: PDF 영수증 발급과 같은 간단한 비즈니스 프로세스도 외부 API 연동 없이 pg_cron과 SQL 트리거만으로 내부 자동화가 가능합니다. [04:39]
6. 종합 결론 및 액션 플랜
최종 결론: PostgreSQL은 더 이상 단순한 저장소가 아니라 '완전에 가까운 백엔드 플랫폼'입니다. [04:08] 수많은 외부 도구를 엮는 데 시간을 낭비하기보다, 검증된 SQL 역량을 활용해 단순하고 강력한 아키텍처를 구축하는 것이 현대 개발자의 경쟁력입니다.
액션 플랜:
- 인프라 진단: 현재 사용 중인 외부 서비스(Redis, Cron, Auth 등) 중 PostgreSQL 기능으로 대체 가능한 항목을 리스트업 하세요.
- 확장 기능 설치: 프로젝트 초기 단계라면
pg_cron,pg_vector,pg_crypto를 활성화하여 구현 가능성을 테스트하세요. - 보안 강화: 멀티테넌트 구조가 필요한 경우 애플리케이션 코드가 아닌 DB의
RLS기능을 우선 적용하여 보안 로직을 단순화하세요. [03:46]
더보기Go gin과 postgresql로 백엔드를 구성하는 아키텍쳐 입장에서 앱/웹 통합으로 사용 가능한 백엔드 구상을 위의 기술 스택으로 구성한다고 했을때, 파일 서버는 minIO를 사용해서 컴터 한대를 할당한다도 치고, 메인 서버 go gin으로 작성한 도커 컨테이너 돌리는 컴퓨터 한대, postgresql 도커 컨테이너 돌리는 컴퓨터 한대 등등 남는 컴퓨터를 활용해서 백엔드를 구성한다고 치고, 쿠버네티스로 파드를 어떻게 구성해야 하는지, 쿠버네티스 관리는 어떻게 해야하는지, 파일을 저장하는 서버의 파일을 사용자가 보내면 제일 먼저 메인 go gin 서버 컴퓨터에 넣고 다시 파일 서버로 옮기는 게 정석인건 지 아니면 쿠버네티스 파드 관리로 정하는 건지 아니면 메인 서버 go gin 서버에서 설정하는 건지,
메인 서버, db, 파일 서버를 aws처럼 앞에 게이트웨이 서비스나, 루트53 서비스 같은 걸 둬야 하는지 등등 앱/웹에서 파일을 그냥 파일 서버로 바로 보내고, 파일 서버에서 minIO가 해당 파일의 주소만 DB 서버에 보내면 되는지 등등
갸능하면 성능 좋고, 저렴한 가격이 트래픽 처리도 빨리하는 그런 회사내 서버를 두는 그런 형태로 가서 스타트업시에 고정비 지출을 줄이고 싶어서 말이야. 백엔드에 대해서는 MVC 모델이나 NEST.JS, GO GIN 등을 통해서 DB에 연결하고 그런건 GO GIN을 AI한테ㅜ짜달라고하면 다 짜서 코드를 보여주긴 하는데, 이런 실무적인 응용이나 이런거라든지 컴퓨터를 나눠서 서로 연결해서 기능을 하드웨어적으로 분리하지만 서버로서의 역할은 제대로 하는 그런 부분에 대한 설계나 개발 환경 구축이나 세부 사항 설정 및 DOCKERFILE, dockercompose 작성 등은 잘 몰라서 말이야.
또한 postgresql로 다른 redis라든가, oauth, 등등 영상에서 설명한 많은 기능을 이용해서 비용을 줄이는 방법도 이렇게 하드웨어적으로 기능을 나눠 놨을때도 사용 가능한지 모르겠으니
아키텍쳐, 시니어 개발자 입장에서 자세히 알려줘.
스타트업 초기 단계에서 남는 하드웨어를 활용해 '비용은 최소화하면서 성능은 프로덕션급'인 인프라를 구축하려는 시도는 매우 전략적입니다. 시니어 개발자 입장에서 하드웨어 분리부터 쿠버네티스(K8s) 구성, 파일 업로드 흐름까지 실무적인 해결책을 정리해 드립니다.
1. 하드웨어 분리 아키텍처 및 쿠버네티스 구성
컴퓨터 3대(메인, DB, 파일서버)를 가지고 있다면, 쿠버네티스를 도입할 때 '역할 기반 노드'로 구성하는 것이 핵심입니다.
쿠버네티스 클러스터 구성 (K3s 추천)
리소스가 제한된 환경이므로 무거운 순정 K8s보다는 K3s(Lightweight Kubernetes)를 추천합니다.
- 컴퓨터 A (Control Plane + Worker): Go Gin 메인 서버 (Pod), Ingress Controller (Gateway 역할을 함).
- 컴퓨터 B (Worker): PostgreSQL (Pod).
- 주의: DB는 가급적 쿠버네티스 내부 Pod로 띄우되, 데이터는 로컬 디스크에 'HostPath'나 'Local Persistent Volume'으로 고정해야 성능이 나옵니다.
- 컴퓨터 C (External Storage): MinIO.
- MinIO는 스토리지 특화 서버이므로 K8s 클러스터 외부에 별도로 두거나, K8s 노드로 합류시키되 전용 디스크를 마운트합니다.
2. 효율적인 파일 업로드 흐름 (Presigned URL 전략)
질문하신 "메인 서버를 거쳐 파일 서버로 가는 방식"은 정석이 아닙니다. 이는 메인 서버의 메모리와 대역폭을 낭비하여 트래픽 처리 속도를 늦춥니다.
추천 방식: Presigned URL (직접 업로드)
- 클라이언트(앱/웹)가 Go Gin 서버에 "파일 업로드 할 건데 권한 줘"라고 요청합니다.
- Go Gin 서버는 MinIO와 통신하여 5~10분간 유효한 '임시 업로드 주소(Presigned URL)'를 발급받아 클라이언트에 전달합니다.
- 클라이언트는 해당 주소를 이용해 MinIO 서버로 직접 파일을 전송합니다.
- 업로드가 완료되면 클라이언트는 Go Gin 서버에 "업로드 끝났어, 파일 주소는 이거야"라고 알리고, Go Gin은 그 주소를 PostgreSQL에 저장합니다.
이점: 메인 서버(Go Gin)는 가벼운 JSON 데이터만 처리하므로 사양이 낮아도 수만 명의 요청을 처리할 수 있습니다.
3. 게이트웨이 및 네트워크 설정 (AWS Route53/ALB 대체)
집이나 사무실 컴퓨터를 사용하므로 고정 IP가 없다면 다음과 같이 구성합니다.
- DNS: Cloudflare(무료 플랜)를 사용하세요. Route53 역할을 하며 보안(DDoS 방지)도 제공합니다.
- Gateway: K8s 내부의 Nginx Ingress Controller가 AWS의 ALB 역할을 합니다.
- 외부 노출: 공유기에서 80, 443 포트를 '컴퓨터 A'로 포워딩합니다. 만약 유동 IP라면
ddclient같은 도구로 Cloudflare DNS를 자동 갱신합니다.
4. PostgreSQL 통합 전략 (비용 절감 핵심)
영상에서 언급된 PostgreSQL의 확장 기능(캐싱, 인증, 스케줄링)은 하드웨어가 분리되어 있어도 완벽하게 작동합니다. 오히려 분리된 환경에서 더 빛을 발합니다.
- Redis 대체: Go Gin에서 별도 레디스 연결 없이 PostgreSQL의
UNLOGGED테이블에 세션을 저장합니다. 네트워크 홉은 한 번 발생하지만, 관리 포인트가 1개로 줄어듭니다. - OAuth/인증:
pg_crypto를 사용하여 Go Gin에서 직접 해싱 로직을 처리하고, DB의RLS를 통해 데이터 접근 권한을 제어합니다.
5. 실전 설 설정 및 코드 가이드
Dockerfile (Go Gin용)
최대한 가볍게(Multi-stage build) 작성해야 성능이 좋습니다.
# 빌드 스테이지
FROM golang:1.21-alpine AS builder
WORKDIR /app
COPY . .
RUN go build -o main .
# 실행 스테이지
FROM alpine:latest
WORKDIR /root/
COPY --from=builder /app/main .
EXPOSE 8080
CMD ["./main"]
Docker Compose (K8s 도입 전 테스트용)
컴퓨터 한 대에서 먼저 돌려볼 때 사용합니다.
version: '3.8'
services:
db:
image: postgres:15
volumes:
- ./pgdata:/var/lib/postgresql/data
environment:
POSTGRES_PASSWORD: password123
minio:
image: minio/minio
command: server /data --console-address ":9001"
ports:
- "9000:9000"
- "9001:9001"
app:
build: .
depends_on:
- db
environment:
DB_URL: "postgres://user:password123@db:5432/dbname"
6. 시니어의 조언: 쿠버네티스 관리
스타트업 초기라면 쿠버네티스 관리에 너무 많은 시간을 쏟지 마세요.
- Lens(툴): K8s 클러스터를 GUI로 관리할 수 있는 가장 좋은 도구입니다. 반드시 설치하세요.
- Argocd: 나중에 여유가 되면 도입하세요. Git에 코드를 올리면 자동으로 서버에 배포해 줍니다.
- 모니터링:
Prometheus와Grafana를 K8s에 올려서 컴퓨터 3대의 CPU/메모리 상태를 체크하세요.
다음 단계로 무엇을 도와드릴까요?
- "Go Gin에서 MinIO Presigned URL을 발급하는 코드를 짜줘."
- "K3s를 컴퓨터 3대에 설치하는 명령어를 알려줘."
- "PostgreSQL의 RLS(행 수준 보안) 설정 예시를 보여줘."
어떤 것을 먼저 해볼까요?
아키텍트로서 시니어 개발자 및 리드 엔지니어가 실무에 바로 착수할 수 있도록 [고효율·저비용 온프레미스 통합 백엔드 구축 가이드]를 작성해 드립니다. 이 문서는 하드웨어 자원을 극대화하면서도 유지보수 효율을 높이는 데 초점을 맞췄습니다.
[설계서] 온프레미스 자원 활용형 통합 백엔드 아키텍처
1. 아키텍처 설계 원칙
- Single Source of Truth: 모든 상태 관리(Session, Job, Vector)를 PostgreSQL로 단일화하여 인프라 복잡도 최소화.
- Zero-Pass Upload: 대용량 파일은 API 서버를 거치지 않고 스토리지(MinIO)로 직접 업로드하여 네트워크 대역폭 및 메모리 보존.
- Infrastructure as Code (IaC): Docker 및 K3s Manifest를 통해 하드웨어 종속성 제거 및 재현성 확보.
2. 하드웨어 배분 및 인프라 구성 (K3s 기반)
물리적인 컴퓨터 3대를 활용한 분산 배치 계획입니다.
| 구분 | 역할 | 주요 스택 | 비고 |
|---|---|---|---|
| Node 1 (Master) | API 서버 및 게이트웨이 | Go Gin, Nginx Ingress, K3s Control Plane | 외부 트래픽 진입점 |
| Node 2 (Worker) | 메인 데이터베이스 | PostgreSQL 15+, PG_Cron, PG_Vector | 데이터 무결성 및 고성능 연산 |
| Node 3 (Storage) | 오브젝트 스토리지 | MinIO (Standalone/Docker) | 고용량 HDD/SSD 할당 |
3. 핵심 기술 구현 상세
3.1 파일 처리 워크플로우: Presigned URL
사용자가 파일을 업로드할 때 API 서버의 리소스를 점유하지 않도록 설계합니다.
- 권한 요청: Client Go Gin (
GET /upload/ticket) - 티켓 발급: Go Gin MinIO SDK (
PresignedPutObject) Client (유효기간 5분 주소 반환) - 직접 업로드: Client MinIO (
PUTBinary Data) - 완료 보고: Client Go Gin (
POST /upload/complete- File Path 저장)
3.2 PostgreSQL 기반 'All-in-One' 전략
영상에서 강조된 비용 절감 기술을 실제 인프라에 녹여냅니다.
- Caching: Redis 대신
UNLOGGED TABLE을 사용하여 세션 저장. (네트워크 지연시간은 K3s 내부망을 통해 1ms 미만으로 유지) - Job Scheduler:
pg_cron을 사용하여 정기적인 데이터 정산 및 로그 삭제 수행. - Security:
Row Level Security (RLS)를 활성화하여 다중 사용자 환경에서 앱 계층의 권한 체크 로직 최소화.
4. 실무 배포를 위한 IaC 가이드
4.1 Go Gin 애플리케이션 (Dockerfile)
성능을 위해 멀티 스테이지 빌드로 이미지 크기를 최소화(약 15MB)합니다.
# Stage 1: Build
FROM golang:1.21-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o /server main.go
# Stage 2: Final
FROM alpine:3.18
RUN apk add --no-cache ca-certificates
COPY --from=builder /server /server
EXPOSE 8080
ENTRYPOINT ["/server"]
4.2 인프라 오케스트레이션 (Docker Compose - 개발용)
로컬 테스트 환경과 프로덕션 환경의 일치를 위해 작성합니다.
services:
postgres:
image: postgres:15-alpine
command: ["postgres", "-c", "shared_preload_libraries=pg_cron"]
volumes:
- ./data/db:/var/lib/postgresql/data
environment:
POSTGRES_DB: app_db
minio:
image: minio/minio
volumes:
- ./data/minio:/data
command: server /data --console-address ":9001"
5. 운영 및 유지보수 전략
- External Access: Cloudflare Tunnel이나 Tailscale을 사용하여 포트 포워딩 없이 보안 연결 구성.
- Monitoring: Node 1에
Prometheus와Grafana를 배치하여 3대 컴퓨터의 자원 사용량(CPU/RAM/Disk)을 실시간 모니터링. - Backup: Node 2의 DB 데이터를 Node 3(MinIO)로 매일 새벽 자동 백업(pg_dump)하도록
pg_cron설정.
6. 액션 플랜 (Next Step)
이 문서를 바탕으로 시니어 개발자는 다음 작업을 우선 수행해 주세요.
- K3s 클러스터링: 3대 컴퓨터에 K3s 설치 및 노드 조인.
- PostgreSQL 환경 구축:
pg_cron,pg_vector가 포함된 커스텀 이미지 빌드 및 배포. - MinIO 연동 모듈 개발: Go Gin 내부에 MinIO SDK를 이용한
Presigned URL발급 유틸리티 작성.
이 설계안 중 특정 부분(예: PostgreSQL의 RLS 설정 구문이나 Go Gin의 MinIO 연동 코드)에 대해 상세 구현 예시가 필요하신가요?
아키텍트의 설계안을 바탕으로 시니어 개발자가 즉시 구현에 착수할 수 있도록, 가장 핵심이 되는 PostgreSQL의 RLS 보안 설정과 Go Gin의 MinIO Presigned URL 연동에 대한 실무 코드를 제공합니다.
1. PostgreSQL: Row Level Security (RLS) 및 인증 설계
애플리케이션(Go Gin)에서 복잡한 권한 체크를 하지 않아도, DB 레벨에서 세션별 데이터 접근을 차단하는 설정입니다.
[SQL] RLS 테이블 및 정책 설정
-- 1. 사용자별 데이터를 담는 테이블 생성
CREATE TABLE user_data (
id SERIAL PRIMARY KEY,
user_id VARCHAR(50) NOT NULL,
content TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 2. RLS 활성화
ALTER TABLE user_data ENABLE ROW LEVEL SECURITY;
-- 3. 보안 정책 생성: 세션 변수 'app.current_user_id'와 일치하는 행만 조회/수정 가능
CREATE POLICY user_data_isolation_policy ON user_data
USING (user_id = current_setting('app.current_user_id'));
-- [참고] Go Gin에서 쿼리 실행 전 세션 설정 방법
-- DB.Exec("SET LOCAL app.current_user_id = ?", authenticatedUserID)
2. Go Gin: MinIO Presigned URL 발급 구현
서버의 대역폭을 쓰지 않고 클라이언트가 직접 업로드하게 만드는 핵심 모듈입니다.
[Go] MinIO 연동 모듈 (pkg/storage/minio.go)
package storage
import (
"context"
"log"
"time"
"github.com/minio/minio-go/v7"
"github.com/minio/minio-go/v7/pkg/credentials"
)
type MinioClient struct {
Client *minio.Client
Bucket string
}
func NewMinioClient() *MinioClient {
endpoint := "node3-ip:9000" // Node 3의 MinIO 주소
accessKey := "minioadmin"
secretKey := "minioadmin"
client, err := minio.New(endpoint, &minio.Options{
Creds: credentials.NewStaticV4(accessKey, secretKey, ""),
Secure: false, // 온프레미스 내부망일 경우 false 가능
})
if err != nil {
log.Fatalln(err)
}
return &MinioClient{Client: client, Bucket: "uploads"}
}
// GenerateUploadURL: 클라이언트가 10분간 직접 업로드할 수 있는 URL 생성
func (m *MinioClient) GenerateUploadURL(ctx context.Context, objectName string) (string, error) {
expiry := time.Duration(10) * time.Minute
// PUT 메서드를 위한 Presigned URL 생성
presignedURL, err := m.Client.PresignedPutObject(ctx, m.Bucket, objectName, expiry)
if err != nil {
return "", err
}
return presignedURL.String(), nil
}
[Go] API 핸들러 (internal/handler/upload.go)
func GetUploadTicket(c *gin.Context) {
fileName := c.Query("filename") // 예: "profile_image.png"
objectName := fmt.Sprintf("%d_%s", time.Now().Unix(), fileName)
// MinIO로부터 임시 업로드 주소 발급
url, err := minioClient.GenerateUploadURL(c.Request.Context(), objectName)
if err != nil {
c.JSON(500, gin.H{"error": "주소 발급 실패"})
return
}
// 클라이언트에 주소 전달 (클라이언트는 이 주소로 직접 파일 전송)
c.JSON(200, gin.H{
"upload_url": url,
"file_path": objectName, // 나중에 DB에 저장할 경로
})
}
3. PostgreSQL 통합: pg_cron 예약 작업 예시
서버 비용 절감을 위해 별도의 람다(Lambda) 없이 DB 내부에서 정산 작업을 처리합니다.
[SQL] 매일 새벽 2시 만료된 세션 삭제 작업 등록
-- pg_cron 확장 활성화 (사전에 postgresql.conf 설정 필요)
CREATE EXTENSION pg_cron;
-- 6개월 지난 로그 데이터 자동 삭제 스케줄 등록
SELECT cron.schedule('delete-old-logs', '0 2 * * *', $$
DELETE FROM system_logs WHERE created_at < now() - interval '6 months';
$$);
4. 시니어 개발자를 위한 아키텍처 점검 포인트 (Review)
- 네트워크 성능: Node 1(Gin)과 Node 2(DB) 사이의 물리적 네트워크가 1Gbps 이상인지 확인하십시오. SQL 기반 캐싱을 사용할 때 네트워크 레이턴시가 성능을 좌우합니다.
- 데이터 보존: Node 2(DB)의
pgdata디렉토리는 반드시 호스트의 물리 디스크에 마운트하십시오. (K8s Pod가 재시작되어도 데이터가 유지되어야 함) - 보안: MinIO 콘솔(9001 포트)은 외부로 노출하지 말고 관리자 전용 VPN이나 SSH 터널링으로만 접속하도록 설정하십시오.
다음 단계로 "이 인프라를 한 번에 배포할 수 있는 Kubernetes Manifest(YAML)" 파일 작성을 도와드릴까요? 혹은 "Go Gin에서 RLS 세션을 주입하는 Middleware 코드"가 필요하신가요?