Files
k3s/009-基础设施/007-keda/scalers/postgresql-说明.md
2026-02-05 00:11:05 +08:00

6.0 KiB
Raw Blame History

⚠️ PostgreSQL 不适合使用 KEDA 自动扩缩容

问题说明

对于传统的 PostgreSQL 架构,直接通过 KEDA 增加副本数会导致:

1. 存储冲突

  • 多个 Pod 尝试挂载同一个 PVC
  • ReadWriteOnce 存储只能被一个 Pod 使用
  • 会导致 Pod 启动失败

2. 数据损坏风险

  • 如果使用 ReadWriteMany 存储,多个实例同时写入会导致数据损坏
  • PostgreSQL 不支持多主写入
  • 没有锁机制保护数据一致性

3. 缺少主从复制

  • 需要配置 PostgreSQL 流复制Streaming Replication
  • 需要配置主从切换机制
  • 需要使用专门的 PostgreSQL Operator

正确的 PostgreSQL 扩展方案

方案 1: 使用 PostgreSQL Operator

推荐使用专业的 PostgreSQL Operator

Zalando PostgreSQL Operator

# 添加 Helm 仓库
helm repo add postgres-operator-charts https://opensource.zalando.com/postgres-operator/charts/postgres-operator

# 安装 Operator
helm install postgres-operator postgres-operator-charts/postgres-operator

# 创建 PostgreSQL 集群
apiVersion: "acid.zalan.do/v1"
kind: postgresql
metadata:
  name: acid-minimal-cluster
spec:
  teamId: "acid"
  volume:
    size: 10Gi
    storageClass: longhorn
  numberOfInstances: 3  # 1 主 + 2 从
  users:
    zalando:
    - superuser
    - createdb
  databases:
    foo: zalando
  postgresql:
    version: "16"

CloudNativePG Operator

# 安装 CloudNativePG
kubectl apply -f https://raw.githubusercontent.com/cloudnative-pg/cloudnative-pg/release-1.22/releases/cnpg-1.22.0.yaml

# 创建集群
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
  name: cluster-example
spec:
  instances: 3
  storage:
    storageClass: longhorn
    size: 10Gi

方案 2: 读写分离 + KEDA

如果需要使用 KEDA正确的架构是

┌─────────────────┐
│  主库 (Master)  │ ← 固定 1 个副本,处理写入
│  StatefulSet    │
└─────────────────┘
        │
        │ 流复制
        ↓
┌─────────────────┐
│  从库 (Replica) │ ← KEDA 管理,处理只读查询
│  Deployment     │    可以 0-N 个副本
└─────────────────┘

配置示例:

# 主库 - 固定副本
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: postgresql-master
spec:
  replicas: 1  # 固定 1 个
  # ... 配置主库

---
# 从库 - KEDA 管理
apiVersion: apps/v1
kind: Deployment
metadata:
  name: postgresql-replica
spec:
  # replicas 由 KEDA 管理
  # ... 配置从库(只读)

---
# KEDA ScaledObject - 只扩展从库
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
  name: postgresql-replica-scaler
spec:
  scaleTargetRef:
    name: postgresql-replica  # 只针对从库
  minReplicaCount: 0
  maxReplicaCount: 5
  triggers:
  - type: postgresql
    metadata:
      connectionString: postgresql://user:pass@postgresql-master:5432/db
      query: "SELECT COUNT(*) FROM pg_stat_activity WHERE state = 'active' AND query NOT LIKE '%pg_stat_activity%'"
      targetQueryValue: "10"

方案 3: 垂直扩展(推荐用于单实例)

对于单实例 PostgreSQL使用 VPA (Vertical Pod Autoscaler) 更合适:

apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
  name: postgresql-vpa
spec:
  targetRef:
    apiVersion: "apps/v1"
    kind: StatefulSet
    name: postgresql
  updatePolicy:
    updateMode: "Auto"
  resourcePolicy:
    containerPolicies:
    - containerName: postgresql
      minAllowed:
        cpu: 250m
        memory: 512Mi
      maxAllowed:
        cpu: 2000m
        memory: 4Gi

当前部署建议

对于您当前的 PostgreSQL 部署(/home/fei/k3s/010-中间件/002-postgresql/

不要使用 KEDA 水平扩展

  • 当前是单实例 StatefulSet
  • 没有配置主从复制
  • 直接扩展会导致数据问题

推荐的优化方案

  1. 保持单实例运行

    replicas: 1  # 固定不变
    
  2. 优化资源配置

    resources:
      requests:
        cpu: 500m
        memory: 1Gi
      limits:
        cpu: 2000m
        memory: 4Gi
    
  3. 配置连接池

    • 使用 PgBouncer 作为连接池
    • PgBouncer 可以使用 KEDA 扩展
  4. 定期备份

    • 使用 Longhorn 快照
    • 备份到 S3

PgBouncer + KEDA 方案

这是最实用的方案PostgreSQL 保持单实例PgBouncer 使用 KEDA 扩展。

# PostgreSQL - 固定单实例
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: postgresql
spec:
  replicas: 1  # 固定
  # ...

---
# PgBouncer - 连接池
apiVersion: apps/v1
kind: Deployment
metadata:
  name: pgbouncer
spec:
  # replicas 由 KEDA 管理
  template:
    spec:
      containers:
      - name: pgbouncer
        image: pgbouncer/pgbouncer:latest
        # ...

---
# KEDA ScaledObject - 扩展 PgBouncer
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
  name: pgbouncer-scaler
spec:
  scaleTargetRef:
    name: pgbouncer
  minReplicaCount: 1
  maxReplicaCount: 10
  triggers:
  - type: postgresql
    metadata:
      connectionString: postgresql://postgres:postgres123@postgresql:5432/postgres
      query: "SELECT COUNT(*) FROM pg_stat_activity WHERE state = 'active'"
      targetQueryValue: "20"

总结

方案 适用场景 复杂度 推荐度
PostgreSQL Operator 生产环境,需要高可用
读写分离 + KEDA 读多写少场景
PgBouncer + KEDA 连接数波动大
VPA 垂直扩展 单实例,资源需求变化
直接 KEDA 扩展 不适用 -

对于当前部署,建议保持 PostgreSQL 单实例运行,不使用 KEDA 扩展。

如果需要扩展能力,优先考虑:

  1. 部署 PgBouncer 连接池 + KEDA
  2. 或者迁移到 PostgreSQL Operator

重要提醒:有状态服务的扩展需要特殊处理,不能简单地增加副本数! ⚠️