Skip to content

English {#english}

Redis Server Separation Plan (Option A — Pulumi · Ansible)

Purpose: In Frappe/ERPNext multitenant setup, move Redis off App servers and run a single Redis instance with logical roles via DB numbers (1/2/3) to keep operations simple.
Pulumi provisions the Redis server, firewall, and network; Ansible installs/configures Redis and updates App Redis URLs.
No code generation — plan, phases, ownership, and deliverables only.

References: saas-expanded-multitenancy-redis-storage-plan §3 (Redis separate server); saas-db-separation-and-scaling-plan (DB separation Phase 1, same Pulumi/Ansible pattern); pulumi-ansible-step1-step2-plan (paths, execution order); resource-optimization-safe-adoption-plan (post-migration Redis tuning, Gunicorn, Docker limits).

Design principles: Align with Google SRE and cloud design patterns for scalable, reliable multitenant SaaS ERP on dedicated servers.


1. Objectives

  • Run Redis on a dedicated server (not on App hosts).
  • Use one Redis instance; roles by DB: 1 = cache, 2 = queue, 3 = socketio (0 optional).
  • Keep MariaDB on its own server (unchanged).
  • Minimize operational complexity (Option A recommended).

Goals: Tenant isolation (MariaDB per-tenant; Redis shared, tenant_id in message metadata). Centralized event broker (one Redis for cache, queue, socketio; competing consumers). Automation via Pulumi, Ansible, common_site_config.


2–7. Architecture, config, Pulumi, Ansible, phases

  • §2 Target architecture: One Redis VM (Hetzner), port 6379 allowed only from App (or private network). MariaDB separate. App nodes connect to remote Redis URLs.
  • §3 Redis roles: DB 1 cache, 2 queue, 3 socketio. URLs: redis://:PASSWORD@redis_host:6379/1 etc. MariaDB = physical/logical isolation; Redis = shared, tenant_id in metadata.
  • §4 Frappe: common_site_config.json (redis_cache, redis_queue, redis_socketio). Password via Ansible Vault. Optional: env vars or central config (NFS/Consul).
  • §5 Pulumi: Redis VM, firewall (22 + 6379 from App IPs only), optional private network/volume/DNS. Export redis_server_ip for Ansible. Spec: e.g. 4GB RAM, Ubuntu 24.04.
  • §6 Ansible: New group prego_redis_servers, role redis_server (Docker, redis.conf, requirepass, appendonly). App play: inject Redis URLs into common_site_config or env. Order: Pulumi → Ansible on redis_servers → Ansible on nodes (config).
  • §7 Phases: (1) Redis VM + role + verify. (2) Network/security (6379 only from App). (3) App config change, remove local Redis. (4) Rolling cutover (workers down, switch config, bench restart, workers up). Runbook and rollback.

Full tables (§1.2, §3, §4.1, §5.1–§5.3, §6.1–§6.4, §7.1–§7.4) and exact wording are in the Korean section below.


한국어 {#korean}

Redis 서버 분리 개발 기획서 (A안 — Pulumi·Ansible)

목적: Frappe/ERPNext 멀티테넌트 환경에서 Redis를 App 서버에서 분리하고, 단일 Redis 인스턴스에서 내부 DB 번호(1/2/3)로 역할을 나누어 운영 복잡도를 최소화한다.
Pulumi로 Redis 전용 서버·방화벽·네트워크를 프로비저닝하고, Ansible로 Redis 설치·설정 및 App 측 Redis URL 반영을 수행한다.
코드 생성 없음 — 기획·단계·책임·산출물만 정리.

참조:

설계 원칙: Google SRE 운영 원칙 및 클라우드 디자인 패턴을 참고하여, 독립 서버 환경에서 확장성(Scalability)·안정성(Reliability)을 보장하는 멀티테넌트 SaaS ERP 인프라에 맞춘다.


1. 목적 및 설계 목표 (Design Objectives)

1.1 목적

  • Redis를 App 서버에서 분리하여 전용 서버에서 운영
  • 단일 Redis 인스턴스 사용, 내부 DB 번호(0/1/2/3)로 역할 논리 분리
  • MariaDB는 이미 별도 서버(현행 유지)
  • 운영 복잡도 최소화(A안 권장/단순)

1.2 설계 목표 (Design Objectives)

목표내용
테넌트 격리 (Tenant Isolation)각 테넌트의 DB는 물리/논리적으로 분리하여 보안 및 장애 전파 방지. MariaDB는 별도 서버·스키마 분리; Redis는 공유하되 **테넌트 식별은 메시지 메타데이터(tenant_id)**로 수행.
중앙 집중형 이벤트 브로커 (Centralized Event Broker)시스템 전체의 비동기 작업·메시징·캐시·실시간 이벤트를 공유 Redis 한 곳에서 처리. 여러 App 노드의 Worker가 동일 큐를 분담 처리(Competing Consumers 패턴).
운영 자동화 (Operational Automation)Pulumi·Ansible 및 중앙 집중식 설정(common_site_config 등)을 통해 서버 증설·Redis 전환 시 수동 개입 최소화(KISS 원칙).

2. 목표 아키텍처

flowchart LR
  App1[App Node 1]
  App2[App Node 2]
  Redis[(Redis Server)]
  DB[(MariaDB Server)]

  App1 --> Redis
  App2 --> Redis
  App1 --> DB
  App2 --> DB
  • Redis 1대: 전용 VM(Hetzner). 6379 포트는 App 서버(또는 Private Network)만 허용. 중앙 집중형 이벤트 브로커 역할.
  • MariaDB: 기존 별도 서버 유지(테넌트 격리).
  • App 노드: Bench, Worker, Scheduler, SocketIO — 모두 원격 Redis URL로 연결. 독립 서버 환경에서 외부 DB/Redis 접근은 호스트 네트워크 또는 외부 네트워크 브릿지로 극대화할 수 있음.

3. Redis 역할 분리 전략 (단일 인스턴스, DB 번호 분리)

역할Redis DB 번호설명
redis_cache1캐시
redis_queue2RQ 작업 큐
redis_socketio3실시간 이벤트
(선택) default0예비/미사용

Redis URL 설계 (DB 번호 명시):

redis://:PASSWORD@redis_host:6379/1 # cache
redis://:PASSWORD@redis_host:6379/2 # queue
redis://:PASSWORD@redis_host:6379/3 # socketio
  • redis_host: Pulumi로 프로비저닝한 Redis 서버 IP 또는 Private Network 내부 호스트명(DNS).

3.1 데이터베이스 vs Redis 할당 전략 (아키텍처 정합성)

구분전략상세 내용
MariaDB물리/논리 격리테넌트별 독립 스키마 또는 인스턴스 할당. 데이터 주권·장애 전파 방지. 현행 DB 서버 분리와 동일.
Redis중앙 집중형 공유시스템 전체 이벤트·캐시·큐·실시간 메시지를 하나의 Redis에서 처리. **테넌트 식별은 메시지 메타데이터(tenant_id)**로 수행.

— 본 기획서의 “단일 Redis + DB 1/2/3 역할 분리”는 위 Redis 중앙 공유 전략에 부합한다.


4. Frappe 설정 반영

4.1 common_site_config.json

App 서버(또는 bench 볼륨)의 sites/common_site_config.json에 다음 키를 설정한다.

예시 값
redis_cacheredis://:password@redis.internal:6379/1
redis_queueredis://:password@redis.internal:6379/2
redis_socketioredis://:password@redis.internal:6379/3
  • 비밀번호는 Ansible Vault 또는 배포 시크릿으로 관리. 평문 저장 금지.

4.2 환경변수 vs common_site_config

  • 권장: common_site_config.json에 직접 설정 — Frappe 표준 방식.
  • Docker Compose 사용 시: 환경변수(REDIS_CACHE, REDIS_QUEUE, REDIS_SOCKETIO)로 주입할 수 있으나, Frappe가 config 파일을 우선할 수 있으므로 실제 스택( bench 컨테이너 vs frappe_docker )에 맞춰 주입 위치를 확정할 것. 기획 단계에서는 “redis” 문자열 검색으로 설정 주입 위치를 사전 조사하는 것을 권장.

4.3 중앙 집중식 설정 관리 (Runtime Reconfiguration 패턴)

  • 현행: Ansible이 각 App 노드에 배포 시 common_site_config.json에 Redis URL을 주입. 서버별 로컬 파일로 유지.
  • 확장 옵션: 여러 App 서버가 동일 Redis·DB 설정을 공유해야 할 때, 공유 파일 시스템(NFS) 또는 **설정 서버(Consul/Etcd)**에서 common_site_config.json을 동기화하여 로드하는 Runtime Reconfiguration 패턴 적용 검토. 서버 기동 시 중앙에서 최신 설정을 주입받아 수동 개입을 줄일 수 있음.

5. Pulumi 역할 (Redis 전용 서버·네트워크·보안)

5.1 범위

항목내용
Redis 전용 서버Hetzner VM 1대 (예: prego-redis-01). 동일 리전·동일 SSH 키·Placement Group(선택).
방화벽SSH(22) + 6379는 App 서버 IP(들)만 허용. Public에서 6379 차단. (DB 서버 방화벽 패턴과 동일: saas-db-separation-and-scaling-plan.md Phase 1.)
Private Network현재 Pulumi에 Private Network 사용 여부에 따라, Redis 서버를 동일 VPC에 넣고 App에서 redis.internal 등 내부 호스트명으로 접근하도록 할지 결정. 미사용 시 App 서버 공인 IP로 6379 허용.
볼륨선택. Redis 데이터 영속화를 서버 디스크가 아닌 Volume으로 둘 경우 Pulumi에서 Volume 생성·부착.
관리용 DNS선택. 예: redis-01.pregoi.com → Redis 서버 공인 IP (관리·헬스체크용).

5.2 출력(Export)

출력명설명Ansible에서의 사용
redis_server_ipRedis 서버의 IPv4 주소인벤토리 ansible_host (prego_redis_servers), App play의 redis_host 변수
  • 기존 app_server_ip, db_server_ip와 동일한 패턴으로 export.

5.3 사양 가이드

항목권장
Server type최소 4GB RAM (Cache 12GB, Queue 0.51GB, SocketIO ~200MB, 여유 1GB). 예: CPX21 또는 동급.
ImageUbuntu 24.04 (Ansible 호환).
Backups상용 환경 시 활성화 권장.

5.4 Base 경로

  • Pulumi: /Users/marco/prego-pulumi (pulumi-ansible-step1-step2-plan.md와 동일).

6. Ansible 역할 (Redis 설치·설정·App 연동)

6.1 범위

구분내용
Redis 서버 대상새 인벤토리 그룹 prego_redis_servers (호스트 예: redis_01). Redis 전용 서버에 Docker 설치·Redis 컨테이너 실행·설정 파일 배포.
Redis 서버 Roleredis_server (신규). tasks: OS 패키지, Docker 설치(선택), 디렉터리 생성, redis.conf 템플릿 배포, UFW(선택), Docker 컨테이너로 Redis 기동. handlers: Redis 재시작.
Redis 설정requirepass, appendonly yes, databases 16, maxmemory/maxmemory-policy(선택). bind는 0.0.0.0으로 두고 방화벽으로 접근 제한 권장.
App 서버 대상기존 prego_nodes play에서 redis_cache/redis_queue/redis_socketio URL을 변수로 받아 common_site_config.json에 반영. 또는 docker-compose/env 주입 방식이면 해당 경로에 변수 주입.

6.2 변수·시크릿

변수소스용도
redis_hostPulumi 출력 또는 인벤토리Redis 서버 IP 또는 호스트명
redis_passwordAnsible Vault / vault_redis_passwordRedis requirepass, URL에 포함
redis_maxmemory선택 (예: 4gb)Redis 서버 Role 기본값
redis_maxmemory_policynoeviction (권장)Queue 작업 유실 방지

6.3 인벤토리 예시(개념)

  • prego_redis_servers: redis_01 → ansible_host = Pulumi redis_server_ip.
  • prego_nodes 쪽 group_vars 또는 play vars: redis_cache, redis_queue, redis_socketio 전체 URL 또는 redis_host + redis_password로 조합.

6.4 실행 순서

  1. Pulumi: Redis 서버·방화벽 생성 → redis_server_ip 출력.
  2. Ansible: 먼저 prego_redis_servers 대상으로 redis_server Role 실행 (Redis 가동).
  3. Ansible: 이어서 prego_nodes 대상 play에서 common_site_config(또는 env)에 Redis URL 반영. (기존 docker/frappe_bench 등 기동 전 또는 설정만 배포.)

6.5 Base 경로

  • Ansible: /Users/marco/prego-ansible (인벤토리, roles, playbook).

7. 단계별 구현 계획 (기획 수준)

7.1 1단계 — Redis 전용 서버 준비

순서담당작업
1PulumiRedis 전용 VM 1대 프로비저닝. 방화벽: 22 + 6379(소스: App 서버 IP).
2Pulumiredis_server_ip export. (선택: 관리용 DNS, Volume.)
3Ansible인벤토리에 prego_redis_servers 추가, ansible_host = redis_server_ip.
4Ansibleredis_server Role: Docker(선택), 디렉터리, redis.conf, Redis 컨테이너(appendonly yes, requirepass, databases 16).
5검증Redis 서버에서 redis-cli ping 및 DB 1/2/3 분리 동작 확인.

7.2 2단계 — 네트워크·보안

항목내용
6379Public 차단, App 서버(및 필요 시 Private Network CIDR)만 허용.
UFWRedis 서버에서 UFW 사용 시 Ansible Role에서 6379 allow from App CIDR만 허용. (또는 Pulumi 방화벽만으로 충분할 수 있음.)

7.3 3단계 — App 설정 변경

순서담당작업
1Ansible/수동기존 App 서버의 로컬 Redis 컨테이너 또는 서비스 제거(또는 compose에서 redis 서비스 제거).
2AnsibleApp play에서 redis_host, redis_password(또는 vault)로 URL 3종 생성 후 common_site_config.json 또는 환경변수에 반영.
3문서실제 스택(서비스명: backend/worker/scheduler/socketio 등)에 맞춰 “설정 주입 위치” Runbook 정리.

7.4 4단계 — 롤링 적용 절차 (운영)

  1. Worker 중지 (큐 소비 중단)
  2. Scheduler 중지
  3. Backend(및 SocketIO) 설정 적용 후 재시작
  4. Worker 재시작
  5. Scheduler 재시작

— “소비자(Worker)”를 먼저 멈춘 뒤 연결 변경, 이후 재기동하여 큐 손실/중복 최소화.


8. 운영 전략

8.1 메모리

  • Redis 설정: maxmemory, maxmemory-policy noeviction (Queue 사용 시 작업 유실 방지).
  • Ansible redis_server Role 기본값 또는 변수로 지정.

8.2 모니터링 항목

지표의미
used_memory메모리 사용량
connected_clients연결 수
blocked_clients큐 문제
keyspace_hits/misses캐시 효율
instantaneous_ops_per_sec부하

8.3 장애 시 영향·대응

  • Redis 다운 시: 로그인 세션, background job, 실시간 알림 중단.
  • 대응: Redis 서버 재시작, Worker 재시작. 필요 시 로컬 Redis URL로 롤백.

8.4 운영·설계 인사이트 (Principal Engineer 관점)

항목내용
Competing Consumers 패턴중앙 Redis를 공유하므로, 여러 App 서버의 Worker 컨테이너가 동일 큐(redis_queue, DB 2)를 분담 처리할 수 있음. 특정 테넌트의 대량 비동기 작업을 전체 시스템 리소스로 빠르게 처리 가능.
Throttling 및 부하 제어공유 Redis 사용 시 특정 테넌트가 시스템 전체 리소스를 점유하지 않도록 테넌트별 API 호출 제한(Rate Limiting)·큐 사용량 제한을 반드시 설정할 것. (API Gateway·Zuplo 정책 또는 애플리케이션 레벨.)
Health Check 및 가시성각 App 서버의 App 컨테이너는 상태 체크 엔드포인트를 노출해야 함. 향후 L7 로드밸런서(Nginx/HAProxy) 도입 시 장애 서버를 라우팅에서 즉시 제외하여 가용성 확보.

9. 전환·롤백 전략

9.1 전환 전략 (운영 안전 절차)

  1. 신규 Redis 서버 기동 (Pulumi + Ansible redis_server).
  2. 스테이징에서 DB 1/2/3 연결 테스트.
  3. Production: Worker → Scheduler 중지 후 Backend/SocketIO 설정 변경 및 재시작, 이어서 Worker/Scheduler 재시작.
  4. 로컬 Redis는 1~2일 유지(롤백 대비).
  5. 문제 없으면 로컬 Redis 서비스 제거.

9.2 롤백

  • 설정을 기존(local redis) URL로 원복 후 서비스 재시작. 롤링 순서는 동일(Worker/Scheduler 중지 → Backend 원복 → Worker/Scheduler 재시작).
  • 롤백용 설정 원복 PR/commit을 미리 준비해 두는 것을 권장.

10. Production 전환 체크리스트 (기획 요약)

  • 전환 전: Redis 서버 생성·방화벽·6379는 App CIDR만 허용, requirepass·AOF·maxmemory 정책 결정.
  • 기능 점검: App 노드에서 redis-cli 접속 테스트, DB 1/2/3 분리 확인.
  • 스테이징: 스테이징에서 먼저 Redis URL 전환 후 로그인/세션, background job, socketio, 에러 로그 확인.
  • 프로덕션 롤링: Worker 중지 → Scheduler 중지 → Backend/SocketIO 재시작 → Worker/Scheduler 재시작.
  • 전환 후: connected_clients, redis connection error 0건, Job 실행·캐시 동작 확인.
  • 롤백 준비: 로컬 Redis 설정 원복용 설정/코드 준비, 동일 순서로 롤백 가능하도록 문서화.

11. 산출물 요약 (구현 시 생성할 것)

구분산출물
PulumiRedis 전용 서버 리소스, Redis 전용 방화벽(22 + 6379 from App), export redis_server_ip. (선택: Volume, 관리용 DNS.)
AnsibleRole redis_server: defaults, tasks, handlers, templates(redis.conf.j2). Playbook: prego_redis_servers 대상 redis_server 적용.
Ansible인벤토리 그룹 prego_redis_servers, App play에서 redis_cache/redis_queue/redis_socketio URL 반영(common_site_config 또는 env).
문서Runbook: Redis 전환 절차, 설정 주입 위치, 검증·롤백 절차. Production 전환 체크리스트 상세판.

12. 장점·리스크·향후 확장

12.1 장점

항목효과
단일 Redis관리 단순
DB 번호 분리역할 논리 분리 (cache/queue/socketio)
DB 분리 + Redis 분리장애 격리
방화벽·Private Network보안 강화
중앙 공유 RedisCompeting Consumers로 다수 Worker가 큐 분담 처리 가능

12.2 리스크

  • 단일 Redis는 SPOF. 초기 SaaS에는 허용 가능.
  • 고부하 시 DB 번호 분리보다 프로세스(인스턴스) 분리가 더 중요할 수 있음.
  • Redis 메모리 부족 시 전체 서비스 영향 → maxmemory·모니터링 필수.
  • 공유 Redis 사용 시: 특정 테넌트의 과도한 요청·큐 적체가 전체에 영향 → 테넌트별 Throttling·Rate Limiting 필수(§8.4).

12.3 향후 확장 로드맵

Phase내용
Phase 1 (현재)Docker Compose·단일/소수 서버, Pulumi·Ansible으로 Redis·DB·App 분리. 로컬 및 단일 서버 테스트 안정화.
Phase 2서비스 디스커버리·L7 라우팅: Nginx 또는 HAProxy 역방향 프록시 도입. tenant-a.your-erp.com 등 호스트 헤더 분석 후 해당 테넌트가 할당된 App 컨테이너로 트래픽 포워딩. Health Check로 장애 노드 라우팅 제외. 필요 시 Kubernetes(K8s) 도입으로 오케스트레이션·오토스케일링.
Phase 3Redis Sentinel(HA), Queue 전용 Redis 분리 또는 Redis Cluster. 전 세계 사용자 지연 최소화를 위한 멀티 데이터센터 배포·데이터 동기화 체계.

12.4 서비스 디스커버리·라우팅 (Phase 2 참고)

  • 구현 방법: Nginx 또는 HAProxy를 사용한 역방향 프록시(Reverse Proxy).
  • 동작 원리: 사용자가 tenant-a.your-erp.com으로 접속 시, L7이 호스트 헤더를 분석하여 해당 테넌트가 할당된 Docker App 컨테이너(또는 노드)로 트래픽 포워딩. 독립 서버 환경에서는 호스트 네트워크(Host Network) 또는 외부 네트워크 브릿지로 외부 DB/Redis 접근성 확보.

13. 최종 구조 한 줄 요약

Redis 1대 (전용 VM) · DB 1=cache, 2=queue, 3=socketio
Pulumi: Redis 서버·방화벽 · Ansible: redis_server Role + App 쪽 Redis URL 반영
Help