Tầng Dữ liệu
Tầng dữ liệu chạy trên node pool stateful trong cụm Kubernetes VNPAY Cloud. Tất cả workload đều dùng StorageClass csi-sc-vnpaycloud (Cinder CSI trên OpenStack) với allowVolumeExpansion: true, nghĩa là PVC có thể được mở rộng online mà không downtime.
Tổng quan Kiến trúc
Tóm tắt Component
| Component | Loại | Instances | Image | Namespace | Storage |
|---|---|---|---|---|---|
| PostgreSQL | StatefulSet (primary + replica) | 2 (1 primary + 1 replica) | postgres:17-alpine | nx-persistent | 20Gi mỗi pod |
| PgBouncer | Deployment | 1 | ghcr.io/icoretech/pgbouncer-docker:1.24.1 | nx-persistent | - |
| Redis | StatefulSet (cluster mode) | 3 master, 0 replica | redis:7-alpine | nx-broker | 5Gi mỗi pod |
| Kafka | StatefulSet (KRaft + SASL) | 3 broker | apache/kafka:4.1.1 | nx-broker | 10Gi mỗi pod |
| Typesense | StatefulSet | 1 | typesense/typesense:27.1 | nx-search | 5Gi |
| Debezium | Deployment | 1 | debezium/connect:3.0.0.Final | nx-search | - |
PostgreSQL
Kiến trúc: Primary + Replica với PgBouncer
PostgreSQL chạy dưới dạng hai StatefulSet tách biệt — một primary (đọc-ghi) và một replica (chỉ đọc, hot standby) — với một Deployment PgBouncer đứng trước để connection pooling. Replica stream WAL từ primary bằng streaming replication native của PostgreSQL.
Primary StatefulSet
Init container xử lý khởi tạo database lần đầu: tạo app user nx_seller_operator, database nx_seller_core, kích hoạt extension pg_stat_statements và pgcrypto, và tạo repl_user cho streaming replication.
StatefulSet: nx-postgresql-primary
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: nx-postgresql-primary
namespace: nx-persistent
spec:
serviceName: nx-postgresql-primary-headless
replicas: 1
template:
spec:
nodeSelector:
node.kubernetes.io/pool: stateful
securityContext:
runAsNonRoot: true
runAsUser: 70
runAsGroup: 70
fsGroup: 70
seccompProfile:
type: RuntimeDefault
initContainers:
- name: init-primary
image: postgres:17-alpine
# Creates: nx_seller_operator user, nx_seller_core DB,
# pg_stat_statements + pgcrypto extensions, repl_user for replication,
# pg_hba.conf entries for replication + SCRAM auth
containers:
- name: postgresql
image: postgres:17-alpine
ports:
- containerPort: 5432
args:
- -c
- wal_level=logical
- -c
- max_wal_senders=10
- -c
- max_replication_slots=10
- -c
- hot_standby=on
- -c
- shared_buffers=512MB
- -c
- effective_cache_size=1536MB
- -c
- work_mem=8MB
- -c
- maintenance_work_mem=128MB
- -c
- max_connections=100
- -c
- random_page_cost=1.1
- -c
- effective_io_concurrency=200
- -c
- log_statement=ddl
- -c
- log_min_duration_statement=1000
- -c
- password_encryption=scram-sha-256
- -c
- timezone=Asia/Ho_Chi_Minh
resources:
requests:
cpu: 500m
memory: 1Gi
limits:
cpu: "2"
memory: 4Gi
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: [ReadWriteOnce]
storageClassName: csi-sc-vnpaycloud
resources:
requests:
storage: 20GiReplica StatefulSet
Init container của replica dùng pg_basebackup từ primary lần đầu, sau đó vào chế độ hot standby. Nó stream WAL liên tục từ primary để độ trễ replication gần như bằng 0.
StatefulSet: nx-postgresql-replica
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: nx-postgresql-replica
namespace: nx-persistent
spec:
serviceName: nx-postgresql-replica-headless
replicas: 1
template:
spec:
initContainers:
- name: init-replica
image: postgres:17-alpine
# pg_basebackup from primary on first run, standby.signal on restart
containers:
- name: postgresql
image: postgres:17-alpine
args:
- -c
- hot_standby=on
- -c
- hot_standby_feedback=on
- -c
- shared_buffers=512MB
- -c
- max_connections=100
resources:
requests:
cpu: 250m
memory: 512Mi
limits:
cpu: "1"
memory: 2Gi
volumeClaimTemplates:
- metadata:
name: data
spec:
storageClassName: csi-sc-vnpaycloud
resources:
requests:
storage: 20GiPgBouncer Connection Pooling
PgBouncer chạy dưới dạng Deployment đứng trước primary. Các backend service kết nối tới nx-pgbouncer:5432 (ánh xạ tới port 6432 nội bộ của PgBouncer). Nó chạy ở chế độ transaction pooling với max_client_conn là 200 và default_pool_size là 20.
Cấu hình PgBouncer (từ ConfigMap)
# PgBouncer configuration (from ConfigMap)
[databases]
nx_seller_core = host=nx-postgresql-primary.nx-persistent.svc.cluster.local port=5432 dbname=nx_seller_core
[pgbouncer]
listen_addr = 0.0.0.0
listen_port = 6432
auth_type = scram-sha-256
pool_mode = transaction
max_client_conn = 200
default_pool_size = 20
min_pool_size = 5
reserve_pool_size = 5
max_db_connections = 50Init container sinh file userlist.txt từ các Kubernetes Secret (app user + superuser). Service expose port 5432 ra bên ngoài, ánh xạ tới 6432 nội bộ — nên các backend service dùng cùng port như khi kết nối trực tiếp PostgreSQL.
Services
| Service | DNS | Port | Mục đích |
|---|---|---|---|
nx-pgbouncer | nx-pgbouncer.nx-persistent.svc.cluster.local | 5432 | Kết nối pooled tới primary (dùng bởi tất cả backend service) |
nx-postgresql-primary | nx-postgresql-primary.nx-persistent.svc.cluster.local | 5432 | Primary trực tiếp (dùng bởi PgBouncer, port-forward) |
nx-postgresql-replica | nx-postgresql-replica.nx-persistent.svc.cluster.local | 5432 | Replica trực tiếp (chỉ đọc, dùng cho read splitting sau này) |
nx-postgresql-primary-headless | (pod DNS) | 5432 | DNS ổn định cho StatefulSet |
nx-postgresql-replica-headless | (pod DNS) | 5432 | DNS ổn định cho StatefulSet |
Đường dẫn Kết nối Mặc định
Các backend service kết nối tới nx-pgbouncer.nx-persistent.svc.cluster.local:5432 (pooled). Điều này được cấu hình trong shared-config.yaml dưới dạng APP_ENV_POSTGRES_HOST. Các service primary/replica trực tiếp tồn tại cho truy cập admin và read/write splitting trong tương lai.
Users & Secrets
| User | Mục đích | Secret |
|---|---|---|
postgres | Superuser | nx-postgresql-superuser-secret |
nx_seller_operator | App user (CREATEDB) | nx-postgresql-app-secret |
repl_user | Streaming replication | nx-postgresql-replication-secret |
Database Schemas
BANA dùng 7 schema trong database nx_seller_core:
| Schema | Services |
|---|---|
public | identity, commerce (bảng dùng chung) |
pricing | pricing |
allocation | commerce (stock allocation) |
inventory | inventory |
finance | finance, ledger |
payment | payment |
sale | sale |
Port-Forward cho Truy cập Local
# From infrastructure/deployments/staging/ directory:
./kc port-forward svc/nx-postgresql-primary 5432:5432 -n nx-persistent
# From project root:
infrastructure/deployments/staging/kc port-forward svc/nx-postgresql-primary 5432:5432 -n nx-persistent
# Then connect locally:
psql -h localhost -U nx_seller_operator -d nx_seller_coreRedis
Cluster Mode (3 Master, 0 Replica)
Redis chạy dưới dạng cluster 3 node với 16384 hash slot phân phối qua 3 master. Không có replica được cấu hình (staging không cần dự phòng cho từng master). Cluster cung cấp sharding dữ liệu qua các node.
StatefulSet
StatefulSet: nx-redis
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: nx-redis
namespace: nx-broker
spec:
serviceName: nx-redis-headless
replicas: 3
template:
spec:
nodeSelector:
node.kubernetes.io/pool: stateful
securityContext:
runAsNonRoot: true
runAsUser: 999
runAsGroup: 999
fsGroup: 999
seccompProfile:
type: RuntimeDefault
containers:
- name: redis
image: redis:7-alpine
command:
- redis-server
- --requirepass
- $(REDIS_PASSWORD)
- --masterauth
- $(REDIS_PASSWORD)
- --cluster-enabled
- "yes"
- --cluster-config-file
- /data/nodes.conf
- --cluster-node-timeout
- "5000"
- --appendonly
- "yes"
- --appendfsync
- everysec
- --maxmemory
- 256mb
- --maxmemory-policy
- noeviction
ports:
- containerPort: 6379
name: redis
- containerPort: 16379
name: cluster-bus
env:
- name: REDIS_PASSWORD
valueFrom:
secretKeyRef:
name: nx-redis-secret
key: REDIS_PASSWORD
resources:
requests:
cpu: 100m
memory: 384Mi
limits:
cpu: "1"
memory: 512Mi
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: [ReadWriteOnce]
storageClassName: csi-sc-vnpaycloud
resources:
requests:
storage: 5GiKhởi tạo Cluster
Sau khi cả 3 pod đang chạy, một Job một lần tạo cluster:
Job: nx-redis-cluster-init
apiVersion: batch/v1
kind: Job
metadata:
name: nx-redis-cluster-init
namespace: nx-broker
spec:
ttlSecondsAfterFinished: 600
backoffLimit: 3
template:
spec:
restartPolicy: OnFailure
nodeSelector:
node.kubernetes.io/pool: default
securityContext:
runAsNonRoot: true
runAsUser: 999
runAsGroup: 999
seccompProfile:
type: RuntimeDefault
containers:
- name: cluster-init
image: redis:7-alpine
command:
- sh
- -c
- |
set -e
export REDISCLI_AUTH="$REDIS_PASSWORD"
HEADLESS="nx-redis-headless.nx-broker.svc.cluster.local"
NODES=""
for i in 0 1 2; do
HOST="nx-redis-${i}.${HEADLESS}"
until [ "$(redis-cli -h "$HOST" ping 2>/dev/null)" = "PONG" ]; do sleep 2; done
NODES="${NODES} ${HOST}:6379"
done
echo "yes" | redis-cli --cluster create ${NODES} --cluster-replicas 0PodSecurity Restricted
Init job phải có runAsNonRoot: true, seccompProfile: RuntimeDefault, và capabilities.drop: [ALL] để thỏa mãn PodSecurity Standard restricted được enforce trên tất cả namespace.
Services
| Service | DNS | Port | Mục đích |
|---|---|---|---|
nx-redis-headless | nx-redis-headless.nx-broker.svc.cluster.local | 6379, 16379 | Headless — DNS cấp pod cho các node cluster |
nx-redis | nx-redis.nx-broker.svc.cluster.local | 6379, 16379 | ClusterIP — load-balanced (discovery ban đầu) |
Địa chỉ pod riêng lẻ được các backend service dùng:
nx-redis-0.nx-redis-headless.nx-broker.svc.cluster.local:6379
nx-redis-1.nx-redis-headless.nx-broker.svc.cluster.local:6379
nx-redis-2.nx-redis-headless.nx-broker.svc.cluster.local:6379Cấu hình Kết nối Backend
Các backend service kết nối ở cluster mode qua shared-config.yaml:
Cache
# Cache
APP_ENV_CACHE_REDIS_MODE: cluster
APP_ENV_CACHE_REDIS_CLUSTER_NODES: "nx-redis-0.nx-redis-headless.nx-broker.svc.cluster.local:6379,nx-redis-1.nx-redis-headless.nx-broker.svc.cluster.local:6379,nx-redis-2.nx-redis-headless.nx-broker.svc.cluster.local:6379"
# BullMQ
APP_ENV_BULLMQ_REDIS_MODE: cluster
APP_ENV_BULLMQ_REDIS_CLUSTER_NODES: "nx-redis-0....:6379,nx-redis-1....:6379,nx-redis-2....:6379"
# WebSocket
APP_ENV_WEBSOCKET_REDIS_MODE: cluster
APP_ENV_WEBSOCKET_REDIS_CLUSTER_NODES: "nx-redis-0....:6379,nx-redis-1....:6379,nx-redis-2....:6379"Redis Cluster vs. Logical Databases
Chế độ Redis Cluster không hỗ trợ SELECT \<db\> (logical database). Tất cả dữ liệu nằm ở DB 0, được phân vùng theo hash slot qua 3 master. Tiền tố key (ví dụ: cache:, bullmq:, ws:) được dùng thay cho các database riêng biệt.
Kafka
KRaft StatefulSet với SASL/SCRAM-SHA-512
Apache Kafka 4.1.1 chạy ở chế độ KRaft (không ZooKeeper) với 3 node kết hợp broker+controller. Backend service xác thực qua SASL/SCRAM-SHA-512 trên listener CLIENT.
Listeners
| Listener | Port | Protocol | Mục đích |
|---|---|---|---|
INTERNAL | 29092 | PLAINTEXT | Giao tiếp inter-broker (bảo mật bằng NetworkPolicy) |
CLIENT | 9092 | SASL_PLAINTEXT (SCRAM-SHA-512) | Backend service kết nối vào đây |
CONTROLLER | 9093 | PLAINTEXT | Đồng thuận quorum KRaft |
StatefulSet
Init container sinh server.properties động (đặt node.id từ ordinal của pod), xóa lost+found khỏi PVC ext4 (Kafka không chấp nhận), và chạy kafka-storage.sh format lần đầu khởi động.
StatefulSet: nx-kafka
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: nx-kafka
namespace: nx-broker
spec:
serviceName: nx-kafka-headless
replicas: 3
podManagementPolicy: Parallel
template:
spec:
nodeSelector:
node.kubernetes.io/pool: stateful
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 1000
fsGroup: 1000
seccompProfile:
type: RuntimeDefault
initContainers:
- name: kafka-init-config
image: apache/kafka:4.1.1
# Generates server.properties, removes lost+found,
# runs kafka-storage.sh format on first run
containers:
- name: kafka
image: apache/kafka:4.1.1
command:
- /opt/kafka/bin/kafka-server-start.sh
- /config/server.properties
env:
- name: KAFKA_OPTS
value: "-Djava.security.auth.login.config=/etc/kafka-jaas/kafka_server_jaas.conf"
ports:
- containerPort: 29092
name: internal
- containerPort: 9092
name: client
- containerPort: 9093
name: controller
resources:
requests:
cpu: 500m
memory: 1280Mi
limits:
cpu: "1.5"
memory: 2Gi
volumeMounts:
- name: data
mountPath: /var/lib/kafka/data
- name: config
mountPath: /config
- name: jaas
mountPath: /etc/kafka-jaas
readOnly: true
volumes:
- name: config
emptyDir: { sizeLimit: 8Mi }
- name: jaas
secret:
secretName: nx-kafka-jaas
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: [ReadWriteOnce]
storageClassName: csi-sc-vnpaycloud
resources:
requests:
storage: 10GiCấu hình Chính (từ server.properties được sinh ra)
# Replication
offsets.topic.replication.factor=3
transaction.state.log.replication.factor=3
transaction.state.log.min.isr=2
default.replication.factor=3
min.insync.replicas=2
num.partitions=3
# Retention
log.retention.hours=168 # 7 days
log.retention.bytes=1073741824 # 1 GB per partition
log.segment.bytes=1073741824
# Auto-create topics
auto.create.topics.enable=falseKhởi tạo User SASL/SCRAM
Một Job một lần tạo user SCRAM-SHA-512 nx.staging trên listener INTERNAL (vốn là PLAINTEXT và không yêu cầu SASL):
Job: nx-kafka-scram-init
apiVersion: batch/v1
kind: Job
metadata:
name: nx-kafka-scram-init
namespace: nx-broker
spec:
template:
spec:
containers:
- name: scram-init
image: apache/kafka:4.1.1
command:
- sh
- -c
- |
BOOTSTRAP="nx-kafka-0.nx-kafka-headless.nx-broker.svc.cluster.local:29092"
# Wait for Kafka, then:
/opt/kafka/bin/kafka-configs.sh \
--bootstrap-server "$BOOTSTRAP" \
--alter \
--add-config "SCRAM-SHA-512=[iterations=8192,password=${KAFKA_SASL_PASSWORD}]" \
--entity-type users \
--entity-name nx.stagingCấu hình JAAS được lưu trong Secret nx-kafka-jaas và mount tại /etc/kafka-jaas/kafka_server_jaas.conf. Nó được load qua JVM argument KAFKA_OPTS.
Services
| Service | DNS | Ports | Ghi chú |
|---|---|---|---|
nx-kafka-headless | nx-kafka-headless.nx-broker.svc.cluster.local | 29092, 9092, 9093 | Headless, publishNotReadyAddresses: true (quan trọng cho KRaft bootstrap) |
nx-kafka | nx-kafka.nx-broker.svc.cluster.local | 29092, 9092 | ClusterIP — load-balanced |
publishNotReadyAddresses
Headless service phải có publishNotReadyAddresses: true. Không có nó, các pod không thể discover nhau trong giai đoạn bootstrap KRaft ban đầu vì chúng chưa "ready".
Cấu hình Kết nối Backend
From shared-config.yaml
# From shared-config.yaml
APP_ENV_KAFKA_BROKERS: nx-kafka-0.nx-kafka-headless.nx-broker.svc.cluster.local:9092,nx-kafka-1.nx-kafka-headless.nx-broker.svc.cluster.local:9092,nx-kafka-2.nx-kafka-headless.nx-broker.svc.cluster.local:9092
APP_ENV_KAFKA_SASL_ENABLE: "true"
APP_ENV_KAFKA_SASL_MECHANISM: SCRAM-SHA-512
APP_ENV_KAFKA_SASL_USERNAME: nx.staging
# Password in nx-shared-secret: APP_ENV_KAFKA_SASL_PASSWORDTypesense
Single Instance
Typesense chạy dưới dạng StatefulSet single-pod. Với staging điều này là đủ — dữ liệu Typesense có thể được re-index từ PostgreSQL nếu bị mất.
StatefulSet: nx-typesense
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: nx-typesense
namespace: nx-search
spec:
serviceName: nx-typesense
replicas: 1
template:
spec:
nodeSelector:
node.kubernetes.io/pool: stateful
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 1000
fsGroup: 1000
seccompProfile:
type: RuntimeDefault
containers:
- name: typesense
image: typesense/typesense:27.1
args:
- --data-dir=/data
- --api-port=8108
- --api-key=$(TYPESENSE_API_KEY)
- --enable-cors
ports:
- containerPort: 8108
name: http
env:
- name: TYPESENSE_API_KEY
valueFrom:
secretKeyRef:
name: nx-typesense-secret
key: TYPESENSE_API_KEY
resources:
requests:
cpu: 200m
memory: 512Mi
limits:
cpu: "1"
memory: 2Gi
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: [ReadWriteOnce]
storageClassName: csi-sc-vnpaycloud
resources:
requests:
storage: 5GiService
| Service | DNS | Port |
|---|---|---|
nx-typesense | nx-typesense.nx-search.svc.cluster.local | 8108 |
Debezium
CDC Connector
Debezium chạy dưới dạng instance Kafka Connect trong nx-search, stream sự kiện change data capture (CDC) từ PostgreSQL đến các Kafka topic. Điều này cho phép cập nhật search index tới Typesense theo thời gian thực.
Deployment
| Thuộc tính | Giá trị |
|---|---|
| Image | debezium/connect:3.0.0.Final |
| Namespace | nx-search |
| Replicas | 1 |
| Port | 8083 |
Job nx-debezium-init đăng ký PostgreSQL source connector sau khi instance Debezium sẵn sàng.
Service
| Service | DNS | Port |
|---|---|---|
nx-debezium | nx-debezium.nx-search.svc.cluster.local | 8083 |
Network Policies
Tất cả namespace đều có default-deny-all (cả ingress và egress) với các rule allow rõ ràng.
Mặc định Deny
Áp dụng cho: nx-backend, nx-app, nx-persistent, nx-broker, nx-search, nx-internal.
NetworkPolicy: default-deny-all
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
spec:
podSelector: {}
policyTypes:
- Ingress
- EgressRule Allow
| Policy | Namespace | Hướng | From/To | Ports |
|---|---|---|---|---|
allow-dns | Cả 6 namespace | Egress | kube-system | 53 (UDP+TCP) |
allow-egress-to-postgresql | nx-backend | Egress | nx-persistent | 5432 |
allow-egress-to-broker | nx-backend | Egress | nx-broker | 6379, 16379, 9092, 29092 |
allow-egress-to-search | nx-backend | Egress | nx-search | 8108 |
allow-egress-to-backend | nx-backend | Egress | nx-backend | 3000 (inter-service) |
allow-egress-to-s3 | nx-backend | Egress | External (0.0.0.0/0 excl. private) | 443 (chỉ commerce, ledger) |
allow-from-backend | nx-broker | Ingress | nx-backend + nx-broker | 6379, 16379, 9092, 29092, 9093 |
allow-broker-internal | nx-broker | Egress | nx-broker | 6379, 16379, 9092, 29092, 9093 |
allow-pg-replication | nx-persistent | Cả hai | Pod PG trong nx-persistent | 5432 |
allow-pgbouncer-to-primary | nx-persistent | Egress | PgBouncer → PG primary | 5432 |
allow-pgbouncer-from-backend | nx-persistent | Ingress | nx-backend → PgBouncer | 6432 |
allow-from-backend | nx-persistent | Ingress | nx-backend | 5432, 6432 |
allow-from-backend | nx-search | Ingress | nx-backend | 8108 |
allow-search-internal | nx-search | Cả hai | Trong nx-search | 8083, 8108 |
egress-nx-search | nx-search | Egress | nx-persistent, nx-broker | 5432, 9092 |
Sao lưu & Khôi phục
| Service | Phương pháp | Tần suất | Retention | Khôi phục |
|---|---|---|---|---|
| PostgreSQL | Streaming replication (replica) | WAL liên tục | Replica online | Promote replica |
| Redis | AOF persistence (appendonly yes, appendfsync everysec) | Liên tục | Trên đĩa | Khởi động lại từ AOF |
| Kafka | Log retention | Tự động | 7 ngày / 1GB mỗi partition | Replay từ log được giữ lại |
| Typesense | Re-index từ PostgreSQL | Theo yêu cầu | N/A | Re-index |
Chiến lược Dữ liệu Staging
Dữ liệu staging có thể được tạo lại từ migration seed. Bộ đôi primary+replica cung cấp sẵn sàng đọc và warm standby, nhưng không có backup off-cluster lên S3 ở mức staging. Đối với backup cấp production (CNPG với barman, WAL archiving tới S3, PITR), xem mục Production bên dưới.
Mở rộng Volume
Tất cả PVC dùng StorageClass csi-sc-vnpaycloud có allowVolumeExpansion: true.
Cho StatefulSet (Redis, Kafka, Typesense, PostgreSQL)
# Example: expand Redis PVC from 5Gi to 10Gi
# From infrastructure/deployments/staging/ directory:
./kc patch pvc data-nx-redis-0 -n nx-broker -p '{"spec":{"resources":{"requests":{"storage":"10Gi"}}}}'
./kc patch pvc data-nx-redis-1 -n nx-broker -p '{"spec":{"resources":{"requests":{"storage":"10Gi"}}}}'
./kc patch pvc data-nx-redis-2 -n nx-broker -p '{"spec":{"resources":{"requests":{"storage":"10Gi"}}}}'
# From project root:
infrastructure/deployments/staging/kc patch pvc data-nx-redis-0 -n nx-broker -p '{"spec":{"resources":{"requests":{"storage":"10Gi"}}}}'Driver Cinder CSI hỗ trợ mở rộng online — không cần restart pod.
Tóm tắt Tài nguyên
Staging (stateful node pool)
| Workload | Pods | CPU req | CPU lim | Mem req | Mem lim | Storage |
|---|---|---|---|---|---|---|
| PG Primary | 1 | 500m | 2 | 1Gi | 4Gi | 20Gi |
| PG Replica | 1 | 250m | 1 | 512Mi | 2Gi | 20Gi |
| PgBouncer | 1 | 100m | 500m | 256Mi | 512Mi | - |
| Redis (x3) | 3 | 300m | 3 | 1.125Gi | 1.5Gi | 15Gi |
| Kafka (x3) | 3 | 1.5 | 4.5 | 3.75Gi | 6Gi | 30Gi |
| Typesense | 1 | 200m | 1 | 512Mi | 2Gi | 5Gi |
| Debezium | 1 | 250m | 1 | 512Mi | 2Gi | - |
| Tổng | 11 | 3.1 | 13 | 7.67Gi | 18Gi | 90Gi |
Production (Dự kiến)
Chưa triển khai
Tầng dữ liệu production đã được lên kế hoạch nhưng chưa triển khai. Mục sau mô tả kiến trúc mục tiêu. Manifest thực tế sẽ được tạo khi hạ tầng production được provisioned.
| Component | Setup Production Dự kiến |
|---|---|
| PostgreSQL | CloudNativePG operator (1 primary + 2 replica), PgBouncer sidecar, WAL archiving liên tục tới S3, retention 30 ngày, PITR |
| Redis | Redis Sentinel hoặc Cluster với replica (1 master + 2 replica mỗi shard) |
| Kafka | Strimzi operator (3 broker, rack-aware, CRD KafkaTopic/KafkaUser khai báo, Cruise Control) |
| Typesense | Cluster Raft 3 node với bầu leader tự động |
| Failover | Tự động: <30s cho PG (CNPG), <15s cho Redis (Sentinel), sẵn có cho Kafka (ISR) |
| Backups | WAL liên tục + base hàng ngày tới S3 (PG), AOF + RDB tới S3 (Redis), log retention + replication (Kafka) |