6.0 KiB
6.0 KiB
⚠️ 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
- 没有配置主从复制
- 直接扩展会导致数据问题
✅ 推荐的优化方案
-
保持单实例运行
replicas: 1 # 固定不变 -
优化资源配置
resources: requests: cpu: 500m memory: 1Gi limits: cpu: 2000m memory: 4Gi -
配置连接池
- 使用 PgBouncer 作为连接池
- PgBouncer 可以使用 KEDA 扩展
-
定期备份
- 使用 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 扩展。
如果需要扩展能力,优先考虑:
- 部署 PgBouncer 连接池 + KEDA
- 或者迁移到 PostgreSQL Operator
重要提醒:有状态服务的扩展需要特殊处理,不能简单地增加副本数! ⚠️