游戏服务器架构:帧同步、状态同步与房间系统
游戏服务器架构:帧同步、状态同步与房间系统
游戏服务器架构概览
游戏服务器需要处理实时交互,对延迟和一致性要求极高。主要模块包括:网关服务、匹配服务、房间服务、游戏逻辑服务、数据存储。
游戏服务器架构:
客户端:Unity/Unreal Engine、Web Client
网关层:连接管理、协议解析、负载均衡
业务层:
- 匹配服务:玩家匹配、段位系统、匹配队列
- 房间服务:房间创建、加入、退出、状态管理
- 游戏逻辑:游戏规则、战斗计算、结算
- 好友系统:好友列表、组队、聊天
- 排行榜:积分排行、赛季排名
数据层:Redis(热数据)、MySQL(持久化)、MongoDB(日志)
帧同步架构
帧同步(Lockstep)是实时对战游戏的主流同步方案,所有客户端执行相同的操作序列,保证游戏状态一致。
# 帧同步服务
class FrameSyncService:
def __init__(self):
self.frame_interval = 66 # 每帧66ms,约15fps
self.current_frame = 0
self.input_buffer = {} # frame -> [inputs]
self.players = []
def start_game(self, players):
"""开始游戏"""
self.players = players
self.current_frame = 0
self.input_buffer = {}
# 通知客户端游戏开始
for player in players:
player.send(GameStartEvent(
frame_interval=self.frame_interval,
players=[p.id for p in players]
))
def receive_input(self, player_id, frame, input_data):
"""接收玩家输入"""
if frame not in self.input_buffer:
self.input_buffer[frame] = []
self.input_buffer[frame].append({
'player_id': player_id,
'input': input_data
})
def tick(self):
"""帧循环"""
# 收集当前帧的所有输入
inputs = self.input_buffer.get(self.current_frame, [])
# 检查是否所有玩家都发送了输入
if len(inputs) < len(self.players):
# 等待或使用空输入
missing_players = [p.id for p in self.players
if p.id not in [i['player_id'] for i in inputs]]
for player_id in missing_players:
inputs.append({
'player_id': player_id,
'input': {'type': 'empty'}
})
# 广播当前帧的输入给所有客户端
frame_event = FrameEvent(
frame=self.current_frame,
inputs=inputs
)
for player in self.players:
player.send(frame_event)
# 推进到下一帧
self.current_frame += 1
状态同步架构
状态同步(State Sync)适用于非实时或弱实时游戏,服务器是权威状态源,定期同步游戏状态给客户端。
// 状态同步服务
@Service
public class StateSyncService {
@Autowired
private RoomRepository roomRepo;
// 游戏状态快照
public GameStateSnapshot getGameState(Long roomId) {
Room room = roomRepo.getRoom(roomId);
return GameStateSnapshot.builder()
.roomId(roomId)
.tick(room.getCurrentTick())
.players(room.getPlayers().stream()
.map(this::convertToPlayerState)
.collect(Collectors.toList()))
.entities(room.getEntities())
.build();
}
// 处理客户端输入
public void processInput(Long roomId, PlayerInput input) {
Room room = roomRepo.getRoom(roomId);
// 1. 验证输入合法性
if (!validateInput(room, input)) {
return;
}
// 2. 应用输入到游戏状态
applyInput(room, input);
// 3. 推进游戏逻辑
updateGameLogic(room);
// 4. 广播状态更新
broadcastStateUpdate(room);
}
private void broadcastStateUpdate(Room room) {
// 计算状态差异(delta)
GameStateDelta delta = calculateDelta(room);
// 只发送变化的部分
for (Player player : room.getPlayers()) {
player.send(StateUpdateEvent.builder()
.delta(delta)
.tick(room.getCurrentTick())
.build());
}
}
}
房间系统设计
房间系统是多人游戏的基础,需要处理房间创建、加入、退出、状态管理等。
# 房间管理系统
class RoomManager:
def __init__(self):
self.rooms = {} # room_id -> Room
self.redis = RedisClient()
def create_room(self, creator_id, room_config):
"""创建房间"""
# 生成房间ID
room_id = self.generate_room_id()
# 创建房间
room = Room(
id=room_id,
creator_id=creator_id,
config=room_config,
status='WAITING',
create_time=time.time()
)
# 保存房间
self.rooms[room_id] = room
self.redis.set(f"room:{room_id}", room.to_dict(), ex=7200)
return room
def join_room(self, room_id, player_id):
"""加入房间"""
room = self.get_room(room_id)
if not room:
raise RoomNotFoundError()
if room.status != 'WAITING':
raise RoomNotAvailableError()
if len(room.players) >= room.config.max_players:
raise RoomFullError()
# 添加玩家
player = Player(id=player_id)
room.players.append(player)
# 更新房间状态
self.save_room(room)
# 通知房间内所有玩家
for p in room.players:
p.send(PlayerJoinEvent(player_id=player_id))
return room
def start_game(self, room_id):
"""开始游戏"""
room = self.get_room(room_id)
if not room:
raise RoomNotFoundError()
if len(room.players) < room.config.min_players:
raise NotEnoughPlayersError()
# 更新房间状态
room.status = 'PLAYING'
room.start_time = time.time()
self.save_room(room)
# 创建游戏实例
game = GameFactory.create_game(room.config.game_type, room)
# 启动游戏循环
self.start_game_loop(room_id, game)
# 通知所有玩家
for player in room.players:
player.send(GameStartEvent(room_id=room_id))
游戏数据存储
游戏数据需要支持实时读写和历史查询,通常采用Redis+MySQL的组合存储。
// 游戏数据服务
@Service
public class GameDataService {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
@Autowired
private GameRecordMapper gameRecordMapper;
// 保存游戏记录
public void saveGameRecord(GameRecord record) {
// 1. 保存到MySQL(持久化)
gameRecordMapper.insert(record);
// 2. 更新Redis排行榜
updateLeaderboard(record);
// 3. 更新玩家统计
updatePlayerStats(record);
}
// 更新排行榜
private void updateLeaderboard(GameRecord record) {
String leaderboardKey = "leaderboard:" + record.getGameType();
// 更新每个玩家的分数
for (PlayerScore score : record.getPlayerScores()) {
redisTemplate.opsForZSet().add(
leaderboardKey,
score.getPlayerId(),
score.getScore()
);
}
}
// 获取排行榜
public List<LeaderboardEntry> getLeaderboard(String gameType, int page, int size) {
String leaderboardKey = "leaderboard:" + gameType;
// 获取排行数据
Set<ZSetOperations.TypedTuple<Object>> entries = redisTemplate.opsForZSet()
.reverseRangeWithScores(leaderboardKey,
(page - 1) * size, page * size - 1);
List<LeaderboardEntry> result = new ArrayList<>();
int rank = (page - 1) * size + 1;
for (ZSetOperations.TypedTuple<Object> entry : entries) {
result.add(LeaderboardEntry.builder()
.rank(rank++)
.playerId((String) entry.getValue())
.score(entry.getScore().longValue())
.build());
}
return result;
}
}
游戏服务器性能优化
游戏服务器对延迟敏感,需要进行专门的性能优化。
性能优化策略:
网络优化:
- 使用UDP协议(帧同步)
- 压缩网络包
- 预测和插值
- 丢包重传优化
计算优化:
- 多线程并行计算
- 空间分区(四叉树/八叉树)
- 物理引擎优化
- AI计算分帧处理
内存优化:
- 对象池复用
- 内存对齐
- 减少GC压力
- 数据压缩存储
监控优化:
- 实时性能监控
- 帧率统计
- 网络延迟监控
- 异常行为检测