本题考察生产事故处理能力:
┌─────────────────────────────────────────────────────────────┐
│ 生产事故分类 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 数据事故: │
│ ├── 数据丢失 │
│ ├── 数据错乱 │
│ ├── 回滚失败 │
│ └── 影响: 玩家损失巨大 │
│ │
│ 服务事故: │
│ ├── 服务宕机 │
│ ├── 响应超时 │
│ ├── 连接断开 │
│ └── 影响: 无法登录/游戏 │
│ │
│ 安全事故: │
│ ├── 刷物品 │
│ ├── 外挂泛滥 │
│ ├── 数据泄露 │
│ └── 影响: 经济系统崩溃 │
│ │
│ 性能事故: │
│ ├── 负载过高 │
│ ├── 内存溢出 │
│ ├── 数据库锁 │
│ └── 影响: 服务不可用 │
│ │
└─────────────────────────────────────────────────────────────┘
| 级别 | 描述 | 响应时间 | 示例 |
|---|
| P0 | 核心功能完全不可用 | 5分钟 | 所有玩家无法登录 |
| P1 | 严重影响部分玩家 | 15分钟 | 某个服掉线 |
| P2 | 轻微影响 | 1小时 | 个别功能异常 |
| P3 | 观察性问题 | 4小时 | 偶发卡顿 |
"""
事故描述:
时间: 周六晚 20:00 (高峰期)
影响: 全服玩家数据丢失
持续时间: 2 小时
事故经过:
1. 执行数据库清理脚本
2. 误将 WHERE 条件写错
3. 清空了玩家数据表
4. 发现后立即停止服务
"""
def cleanup_old_players():
"""
错误: 注释掉的条件导致全表删除
"""
sql = "DELETE FROM players"
db.execute(sql)
def cleanup_old_players_safe():
"""安全的清理脚本"""
check_sql = """
SELECT COUNT(*)
FROM players
WHERE last_login < DATE_SUB(NOW(), INTERVAL 180 DAY)
"""
count = db.query_one(check_sql)
print(f"Will delete {count} old players")
if count > 10000:
raise Exception(f"Too many rows to delete: {count}")
batch_size = 1000
offset = 0
while True:
delete_sql = """
DELETE FROM players
WHERE last_login < DATE_SUB(NOW(), INTERVAL 180 DAY)
LIMIT %s
"""
affected = db.execute(delete_sql, (batch_size,))
if affected == 0:
break
offset += affected
print(f"Deleted {offset} rows")
class IncidentHandler:
"""事故处理器"""
def handle_data_loss(self):
"""处理数据丢失"""
self.stop_all_services()
loss_assessment = self.assess_data_loss()
INFO_MSG(f"Data loss assessment: {loss_assessment}")
recovery_result = self.recover_data()
validation_result = self.validate_recovery()
if validation_result['success']:
self.restore_services()
else:
CRITICAL_MSG("Recovery validation failed!")
self.fallback_recovery()
def assess_data_loss(self):
"""评估数据损失"""
assessment = {
'affected_tables': [],
'affected_players': 0,
'data_range': None,
'recovery_options': []
}
for table in ['players', 'inventory', 'guilds']:
count = self.query(f"SELECT COUNT(*) FROM {table}")
assessment['affected_tables'].append({
'table': table,
'count': count
})
return assessment
def recover_data(self):
"""恢复数据"""
backup_time = self.get_latest_backup_time()
INFO_MSG(f"Latest backup from: {backup_time}")
binlog_position = self.get_binlog_position()
INFO_MSG(f"Binlog position: {binlog_position}")
try:
self.stop_applications()
self.restore_from_backup(backup_time)
self.apply_binlog(binlog_position)
return {'success': True, 'method': 'backup+binlog'}
except Exception as e:
ERROR_MSG(f"Recovery failed: {e}")
return {'success': False, 'error': str(e)}
def validate_recovery(self):
"""验证恢复结果"""
checks = [
self.check_player_count(),
self.check_data_consistency(),
self.check_critical_accounts()
]
all_passed = all(check['passed'] for check in checks)
return {
'success': all_passed,
'checks': checks
}
事故描述:
时间: 活动上线后 10 分钟
影响: 游戏经济崩溃
损失: 数百亿游戏币
事故经过:
1. 新增交易功能
2. 未校验余额
3. 玩家发现可无限刷钱
4. 短时间内大量传播
class TradingSystem:
"""交易系统 (修复版)"""
def trade_item(self, player_id, item_id, count, price):
"""交易物品"""
with self.db.transaction():
player = self.db.query_for_update(
"SELECT * FROM players WHERE id = ? FOR UPDATE",
(player_id,)
)
if not player:
raise Exception("Player not found")
inventory = self.get_inventory(player_id, item_id)
if inventory['count'] < count:
raise Exception("Insufficient items")
if price < 0:
if player['gold'] < abs(price):
raise Exception("Insufficient gold")
self.remove_item(player_id, item_id, count)
self.update_gold(player_id, player['gold'] + price)
self.log_transaction({
'player_id': player_id,
'item_id': item_id,
'count': count,
'price': price,
'timestamp': time.time()
})
self.notify_client(player_id, {
'action': 'trade_complete',
'item_id': item_id,
'count': count,
'new_gold': player['gold'] + price
})
class AntiAbuse:
"""防刷系统"""
def __init__(self):
self.player_limits = {}
self.global_limits = {
'transactions_per_minute': 1000,
'gold_change_per_minute': 1000000
}
def check_transaction_limit(self, player_id, action, amount):
"""检查交易限制"""
current_time = time.time()
key = (player_id, action)
if key not in self.player_limits:
self.player_limits[key] = []
history = self.player_limits[key]
history[:] = [t for t in history if current_time - t < 60]
if len(history) > 100:
WARNING_MSG(f"Player {player_id} exceeded transaction limit")
return False
if action == 'gold_change':
total = sum(h['amount'] for h in history)
if total + amount > 100000:
WARNING_MSG(f"Player {player_id} exceeded gold limit")
return False
history.append({'time': current_time, 'amount': amount})
return True
class DataRollback:
"""数据回滚"""
def rollback_economy(self):
"""回滚经济数据"""
exploit_detected_time = self.get_exploit_detected_time()
rollback_time = exploit_detected_time - 300
INFO_MSG(f"Rolling back to {rollback_time}")
self.backup_current_state("before_rollback")
self.rollback_player_gold(rollback_time)
self.rollback_item_transactions(rollback_time)
self.confiscate_illegal_assets()
self.compensate_players()
def confiscate_illegal_assets(self):
"""追缴非法所得"""
suspicious_players = self.find_suspicious_players()
for player_id in suspicious_players:
illegal_amount = self.calculate_illegal_amount(player_id)
self.deduct_gold(player_id, illegal_amount)
INFO_MSG(f"Confiscated {illegal_amount} gold from player {player_id}")
if illegal_amount > 100000:
self.ban_player(player_id, reason="exploit_abuse")
"""
事故: 数据库误删玩家数据
Why 1: 为什么数据被删除?
答: 清理脚本误删
Why 2: 为什么清理脚本会误删?
答: WHERE 条件被注释掉
Why 3: 为什么 WHERE 条件被注释?
答: 测试时临时注释,忘记恢复
Why 4: 为什么没有测试就上线?
答: 缺少代码审查流程
Why 5: 为什么缺少流程?
答: 没有建立完善的上线规范
根本原因: 缺少完善的代码审查和上线流程
"""
| 措施 | 说明 |
|---|
| 代码审查 | 所有数据库操作必须审查 |
| 脚本验证 | 脚本执行前预览 |
| 备份测试 | 定期测试备份恢复 |
| 权限控制 | 限制生产环境操作 |
| 监控告警 | 异常操作立即告警 |
| 实践 | 说明 |
|---|
| 快速止损 | 优先恢复服务 |
| 保持冷静 | 按流程处理 |
| 记录详细 | 保留所有日志 |
| 及时沟通 | 通知相关人员 |
| 事后总结 | 输出事故报告 |
| 预防为主 | 建立防护机制 |
事故处理 = 快速响应 + 止损恢复 + 根因分析 + 改进预防
- 分级响应
- 优先恢复服务
- 详细记录过程
- 建立改进机制