Skip to content

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

ComponentLoạiInstancesImageNamespaceStorage
PostgreSQLStatefulSet (primary + replica)2 (1 primary + 1 replica)postgres:17-alpinenx-persistent20Gi mỗi pod
PgBouncerDeployment1ghcr.io/icoretech/pgbouncer-docker:1.24.1nx-persistent-
RedisStatefulSet (cluster mode)3 master, 0 replicaredis:7-alpinenx-broker5Gi mỗi pod
KafkaStatefulSet (KRaft + SASL)3 brokerapache/kafka:4.1.1nx-broker10Gi mỗi pod
TypesenseStatefulSet1typesense/typesense:27.1nx-search5Gi
DebeziumDeployment1debezium/connect:3.0.0.Finalnx-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_statementspgcrypto, và tạo repl_user cho streaming replication.

StatefulSet: nx-postgresql-primary
yaml
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: 20Gi

Replica 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
yaml
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: 20Gi

PgBouncer 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)
yaml
# 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 = 50

Init 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

ServiceDNSPortMục đích
nx-pgbouncernx-pgbouncer.nx-persistent.svc.cluster.local5432Kết nối pooled tới primary (dùng bởi tất cả backend service)
nx-postgresql-primarynx-postgresql-primary.nx-persistent.svc.cluster.local5432Primary trực tiếp (dùng bởi PgBouncer, port-forward)
nx-postgresql-replicanx-postgresql-replica.nx-persistent.svc.cluster.local5432Replica trực tiếp (chỉ đọc, dùng cho read splitting sau này)
nx-postgresql-primary-headless(pod DNS)5432DNS ổn định cho StatefulSet
nx-postgresql-replica-headless(pod DNS)5432DNS ổ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

UserMục đíchSecret
postgresSuperusernx-postgresql-superuser-secret
nx_seller_operatorApp user (CREATEDB)nx-postgresql-app-secret
repl_userStreaming replicationnx-postgresql-replication-secret

Database Schemas

BANA dùng 7 schema trong database nx_seller_core:

SchemaServices
publicidentity, commerce (bảng dùng chung)
pricingpricing
allocationcommerce (stock allocation)
inventoryinventory
financefinance, ledger
paymentpayment
salesale

Port-Forward cho Truy cập Local

bash
# 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_core

Redis

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
yaml
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: 5Gi

Khở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
yaml
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 0

PodSecurity 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

ServiceDNSPortMục đích
nx-redis-headlessnx-redis-headless.nx-broker.svc.cluster.local6379, 16379Headless — DNS cấp pod cho các node cluster
nx-redisnx-redis.nx-broker.svc.cluster.local6379, 16379ClusterIP — 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:6379

Cấu hình Kết nối Backend

Các backend service kết nối ở cluster mode qua shared-config.yaml:

Cache
yaml
# 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

ListenerPortProtocolMục đích
INTERNAL29092PLAINTEXTGiao tiếp inter-broker (bảo mật bằng NetworkPolicy)
CLIENT9092SASL_PLAINTEXT (SCRAM-SHA-512)Backend service kết nối vào đây
CONTROLLER9093PLAINTEXTĐồ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
yaml
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: 10Gi

Cấu hình Chính (từ server.properties được sinh ra)

properties
# 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=false

Khở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
yaml
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.staging

Cấ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

ServiceDNSPortsGhi chú
nx-kafka-headlessnx-kafka-headless.nx-broker.svc.cluster.local29092, 9092, 9093Headless, publishNotReadyAddresses: true (quan trọng cho KRaft bootstrap)
nx-kafkanx-kafka.nx-broker.svc.cluster.local29092, 9092ClusterIP — 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
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_PASSWORD

Typesense

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
yaml
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: 5Gi

Service

ServiceDNSPort
nx-typesensenx-typesense.nx-search.svc.cluster.local8108

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ínhGiá trị
Imagedebezium/connect:3.0.0.Final
Namespacenx-search
Replicas1
Port8083

Job nx-debezium-init đăng ký PostgreSQL source connector sau khi instance Debezium sẵn sàng.

Service

ServiceDNSPort
nx-debeziumnx-debezium.nx-search.svc.cluster.local8083

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
yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-all
spec:
  podSelector: {}
  policyTypes:
    - Ingress
    - Egress

Rule Allow

PolicyNamespaceHướngFrom/ToPorts
allow-dnsCả 6 namespaceEgresskube-system53 (UDP+TCP)
allow-egress-to-postgresqlnx-backendEgressnx-persistent5432
allow-egress-to-brokernx-backendEgressnx-broker6379, 16379, 9092, 29092
allow-egress-to-searchnx-backendEgressnx-search8108
allow-egress-to-backendnx-backendEgressnx-backend3000 (inter-service)
allow-egress-to-s3nx-backendEgressExternal (0.0.0.0/0 excl. private)443 (chỉ commerce, ledger)
allow-from-backendnx-brokerIngressnx-backend + nx-broker6379, 16379, 9092, 29092, 9093
allow-broker-internalnx-brokerEgressnx-broker6379, 16379, 9092, 29092, 9093
allow-pg-replicationnx-persistentCả haiPod PG trong nx-persistent5432
allow-pgbouncer-to-primarynx-persistentEgressPgBouncer → PG primary5432
allow-pgbouncer-from-backendnx-persistentIngressnx-backend → PgBouncer6432
allow-from-backendnx-persistentIngressnx-backend5432, 6432
allow-from-backendnx-searchIngressnx-backend8108
allow-search-internalnx-searchCả haiTrong nx-search8083, 8108
egress-nx-searchnx-searchEgressnx-persistent, nx-broker5432, 9092

Sao lưu & Khôi phục

ServicePhương phápTần suấtRetentionKhôi phục
PostgreSQLStreaming replication (replica)WAL liên tụcReplica onlinePromote replica
RedisAOF persistence (appendonly yes, appendfsync everysec)Liên tụcTrên đĩaKhởi động lại từ AOF
KafkaLog retentionTự động7 ngày / 1GB mỗi partitionReplay từ log được giữ lại
TypesenseRe-index từ PostgreSQLTheo yêu cầuN/ARe-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-vnpaycloudallowVolumeExpansion: true.

Cho StatefulSet (Redis, Kafka, Typesense, PostgreSQL)

bash
# 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)

WorkloadPodsCPU reqCPU limMem reqMem limStorage
PG Primary1500m21Gi4Gi20Gi
PG Replica1250m1512Mi2Gi20Gi
PgBouncer1100m500m256Mi512Mi-
Redis (x3)3300m31.125Gi1.5Gi15Gi
Kafka (x3)31.54.53.75Gi6Gi30Gi
Typesense1200m1512Mi2Gi5Gi
Debezium1250m1512Mi2Gi-
Tổng113.1137.67Gi18Gi90Gi

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.

ComponentSetup Production Dự kiến
PostgreSQLCloudNativePG operator (1 primary + 2 replica), PgBouncer sidecar, WAL archiving liên tục tới S3, retention 30 ngày, PITR
RedisRedis Sentinel hoặc Cluster với replica (1 master + 2 replica mỗi shard)
KafkaStrimzi operator (3 broker, rack-aware, CRD KafkaTopic/KafkaUser khai báo, Cruise Control)
TypesenseCluster Raft 3 node với bầu leader tự động
FailoverTự động: <30s cho PG (CNPG), <15s cho Redis (Sentinel), sẵn có cho Kafka (ISR)
BackupsWAL liên tục + base hàng ngày tới S3 (PG), AOF + RDB tới S3 (Redis), log retention + replication (Kafka)

Proprietary and Confidential. Unauthorized copying, distribution, or use of this software is strictly prohibited.