PlanetScale 生产实践 #
本章将介绍 PlanetScale 在生产环境中的最佳实践,帮助你构建稳定、高效、安全的数据库服务。
生产环境检查清单 #
部署前检查 #
text
┌─────────────────────────────────────────────────────────────┐
│ 部署前检查清单 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 数据库配置: │
│ □ 选择正确的区域 │
│ □ 确认计划满足需求 │
│ □ 配置多区域(如需要) │
│ │
│ 安全配置: │
│ □ 创建生产环境专用密码 │
│ □ 使用最小权限原则 │
│ □ 配置 IP 白名单(如需要) │
│ □ 审查团队成员权限 │
│ │
│ 连接配置: │
│ □ 配置合理的连接池大小 │
│ □ 启用 SSL/TLS │
│ □ 设置连接超时 │
│ │
│ 监控配置: │
│ □ 设置告警阈值 │
│ □ 配置通知渠道 │
│ □ 准备监控面板 │
│ │
└─────────────────────────────────────────────────────────────┘
监控配置 #
关键指标监控 #
text
┌─────────────────────────────────────────────────────────────┐
│ 监控指标 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 资源使用: │
│ ├── 存储使用量 │
│ ├── 行读取量 │
│ ├── 行写入量 │
│ └── 连接数 │
│ │
│ 性能指标: │
│ ├── 查询延迟 │
│ ├── 慢查询数量 │
│ ├── 错误率 │
│ └── 可用性 │
│ │
│ 告警阈值建议: │
│ ├── 存储使用 > 80% │
│ ├── 行读取 > 90% 配额 │
│ ├── 慢查询 > 100/小时 │
│ └── 错误率 > 1% │
│ │
└─────────────────────────────────────────────────────────────┘
自定义监控脚本 #
javascript
import { connect } from '@planetscale/database';
const conn = connect({ url: process.env.DATABASE_URL });
async function checkHealth() {
const startTime = Date.now();
try {
await conn.execute('SELECT 1');
const latency = Date.now() - startTime;
return {
status: 'healthy',
latency,
timestamp: new Date().toISOString()
};
} catch (error) {
return {
status: 'unhealthy',
error: error.message,
timestamp: new Date().toISOString()
};
}
}
setInterval(async () => {
const health = await checkHealth();
console.log(JSON.stringify(health));
}, 60000);
性能优化 #
查询优化 #
sql
-- 使用 EXPLAIN 分析查询
EXPLAIN SELECT * FROM users WHERE email = 'test@example.com';
-- 确保使用索引
-- type: ref, range, const 是好的
-- type: ALL 需要优化
-- 优化前
SELECT * FROM users WHERE YEAR(created_at) = 2024;
-- 优化后
SELECT * FROM users WHERE created_at >= '2024-01-01' AND created_at < '2025-01-01';
连接池优化 #
javascript
import mysql from 'mysql2/promise';
const pool = mysql.createPool({
uri: process.env.DATABASE_URL,
connectionLimit: 10,
waitForConnections: true,
queueLimit: 0,
connectTimeout: 10000,
acquireTimeout: 30000
});
setInterval(() => {
console.log('Pool stats:', {
total: pool.pool._allConnections.length,
free: pool.pool._freeConnections.length,
waiting: pool.pool._connectionQueue.length
});
}, 60000);
故障排查 #
常见问题诊断 #
text
┌─────────────────────────────────────────────────────────────┐
│ 故障排查指南 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 问题 1:连接超时 │
│ 症状:Connection timeout │
│ 诊断: │
│ 1. 检查网络连通性 │
│ 2. 检查区域是否正确 │
│ 3. 检查防火墙规则 │
│ 解决: │
│ - 增加连接超时时间 │
│ - 使用 CLI 代理测试 │
│ - 联系支持 │
│ │
│ 问题 2:查询慢 │
│ 症状:查询响应时间长 │
│ 诊断: │
│ 1. 使用 EXPLAIN 分析 │
│ 2. 检查索引使用情况 │
│ 3. 检查查询复杂度 │
│ 解决: │
│ - 添加合适的索引 │
│ - 优化查询语句 │
│ - 减少返回数据量 │
│ │
│ 问题 3:配额超限 │
│ 症状:Row read/write limit exceeded │
│ 诊断: │
│ 1. 检查使用统计 │
│ 2. 分析查询模式 │
│ 解决: │
│ - 优化查询减少读取 │
│ - 添加缓存 │
│ - 升级计划 │
│ │
└─────────────────────────────────────────────────────────────┘
诊断脚本 #
javascript
import { connect } from '@planetscale/database';
const conn = connect({ url: process.env.DATABASE_URL });
async function diagnose() {
console.log('=== Database Diagnostics ===\n');
const tables = await conn.execute(`
SELECT
table_name,
table_rows,
ROUND(data_length / 1024 / 1024, 2) as data_mb,
ROUND(index_length / 1024 / 1024, 2) as index_mb
FROM information_schema.tables
WHERE table_schema = DATABASE()
`);
console.log('Tables:');
console.table(tables.rows);
const indexes = await conn.execute(`
SELECT
table_name,
index_name,
GROUP_CONCAT(column_name ORDER BY seq_in_index) as columns
FROM information_schema.statistics
WHERE table_schema = DATABASE()
GROUP BY table_name, index_name
`);
console.log('\nIndexes:');
console.table(indexes.rows);
}
diagnose();
备份与恢复 #
备份策略 #
text
┌─────────────────────────────────────────────────────────────┐
│ 备份策略 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 自动备份: │
│ ├── PlanetScale 每日自动备份 │
│ ├── 保留 7 天 │
│ └── 支持时间点恢复 │
│ │
│ 手动备份: │
│ ├── 定期导出关键数据 │
│ ├── 重要变更前备份 │
│ └── 存储到安全位置 │
│ │
│ 备份命令: │
│ pscale database dump my-db main --output ./backup │
│ │
│ 恢复: │
│ - 联系 PlanetScale 支持 │
│ - 或从导出文件恢复 │
│ │
└─────────────────────────────────────────────────────────────┘
自动备份脚本 #
bash
#!/bin/bash
DATE=$(date +%Y%m%d)
BACKUP_DIR="./backups/$DATE"
mkdir -p $BACKUP_DIR
pscale database dump my-database main --output $BACKUP_DIR
echo "Backup completed: $BACKUP_DIR"
# 上传到云存储
# aws s3 sync $BACKUP_DIR s3://my-bucket/backups/$DATE/
安全最佳实践 #
生产安全清单 #
text
┌─────────────────────────────────────────────────────────────┐
│ 安全检查清单 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 访问控制: │
│ □ 审查所有成员权限 │
│ □ 使用最小权限原则 │
│ □ 定期轮换密码 │
│ □ 删除未使用的密码 │
│ │
│ 连接安全: │
│ □ 强制使用 SSL/TLS │
│ □ 验证服务器证书 │
│ □ 使用环境变量存储密码 │
│ │
│ 数据安全: │
│ □ 敏感数据加密存储 │
│ □ 不在日志中记录敏感信息 │
│ □ 定期审计数据访问 │
│ │
└─────────────────────────────────────────────────────────────┘
灾难恢复 #
恢复计划 #
text
┌─────────────────────────────────────────────────────────────┐
│ 灾难恢复计划 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 场景 1:数据误删 │
│ 步骤: │
│ 1. 立即停止写入操作 │
│ 2. 联系 PlanetScale 支持 │
│ 3. 提供时间点恢复请求 │
│ 4. 验证恢复数据 │
│ │
│ 场景 2:Schema 变更错误 │
│ 步骤: │
│ 1. 评估影响范围 │
│ 2. 创建回滚分支 │
│ 3. 执行反向变更 │
│ 4. 部署回滚 │
│ │
│ 场景 3:服务不可用 │
│ 步骤: │
│ 1. 检查 PlanetScale 状态页 │
│ 2. 检查应用日志 │
│ 3. 联系支持 │
│ 4. 准备备用方案 │
│ │
└─────────────────────────────────────────────────────────────┘
运维自动化 #
CI/CD 集成 #
yaml
name: Production Deployment
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install PlanetScale CLI
run: curl -fsSL https://raw.githubusercontent.com/planetscale/cli/main/install.sh | bash
- name: Check for pending deploy requests
env:
PLANETSCALE_SERVICE_TOKEN: ${{ secrets.PLANETSCALE_SERVICE_TOKEN }}
run: |
pscale auth login --service-token $PLANETSCALE_SERVICE_TOKEN
DR_COUNT=$(pscale deploy-request list my-app --format json | jq 'length')
if [ "$DR_COUNT" -gt 0 ]; then
echo "Pending deploy requests found"
pscale deploy-request deploy my-app 1
fi
- name: Deploy to Vercel
run: vercel --prod
健康检查端点 #
typescript
import { getConnection } from '@/lib/db';
import { NextResponse } from 'next/server';
export async function GET() {
const checks = {
database: false,
timestamp: new Date().toISOString()
};
try {
const conn = getConnection();
await conn.execute('SELECT 1');
checks.database = true;
} catch (error) {
console.error('Database health check failed:', error);
}
const allHealthy = checks.database;
const status = allHealthy ? 200 : 503;
return NextResponse.json(checks, { status });
}
总结 #
PlanetScale 提供了强大的无服务器 MySQL 平台,通过遵循本章的最佳实践,你可以构建稳定、高效、安全的生产环境应用。关键要点:
- 监控先行:配置完善的监控和告警
- 安全第一:遵循最小权限原则
- 性能优化:合理使用索引和连接池
- 故障准备:制定灾难恢复计划
- 持续改进:定期审查和优化
祝你的 PlanetScale 生产之旅顺利!
最后更新:2026-03-29