← 返回首页
💼

游戏服务器架构:帧同步、状态同步与房间系统

📂 architecture ⏱ 3 min 509 words

游戏服务器架构:帧同步、状态同步与房间系统

游戏服务器架构概览

游戏服务器需要处理实时交互,对延迟和一致性要求极高。主要模块包括:网关服务、匹配服务、房间服务、游戏逻辑服务、数据存储。

游戏服务器架构:

客户端: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压力
  - 数据压缩存储

监控优化:
  - 实时性能监控
  - 帧率统计
  - 网络延迟监控
  - 异常行为检测