Game Development 18 min read

How to Build Scalable Multiplayer Game Server Architecture and Sync Strategies

This article explains the evolution of multiplayer game server architectures, compares client‑server and P2P models, details communication via long‑lived sockets, and explores frame‑sync, state‑sync, prediction, reconciliation and interpolation techniques with a complete React + Socket.io demo.

ELab Team
ELab Team
ELab Team
How to Build Scalable Multiplayer Game Server Architecture and Sync Strategies

Background

Multiplayer games involve multiple clients interacting together. Three common connection modes are:

Player‑host P2P mode (e.g., "Meteor Butterfly Sword" or cracked games).

Public server mode where player data is stored on a central server (e.g., StarCraft, Warcraft).

LAN mode that enables multiplayer within the same local network.

History of Server Architecture

Most multiplayer games use a client‑server (CS) architecture, with a dedicated server handling communication with players.

Client/Server architecture

First Generation Architecture (Single Server)

All player requests are processed on a single thread, which periodically updates all objects. Suitable for turn‑based or low‑compute games.

Second Generation Architecture (Sharding)

When player numbers grow, a single server becomes overloaded, so the system splits players across multiple servers, effectively creating parallel worlds.

Third Generation Architecture (World Server)

Even with sharding, players may want to cross servers, and a single server can become under‑populated. A world‑server model introduces a global layer that connects multiple game servers.

Basic Three‑Tier Architecture

The design separates the gateway from data storage; all game servers share a common data server, while the gateway handles data exchange between servers.

Advanced Three‑Tier Architecture

On top of the basic three‑tier design, functionalities are further decoupled into independent services to improve performance.

Seamless Map Architecture

To avoid loading screens when switching maps, a group of Node servers manages map regions. A NodeMaster oversees these nodes, and a larger WorldMaster can manage multiple NodeMasters.

Player movement across the map translates to moving between Node servers (e.g., from A → B, the NodeMaster copies data from NodeA to NodeB and removes NodeA’s data).

Communication

Multiplayer games require consistent data and visual states across all players. Before discussing synchronization, we first look at how two ends communicate.

Long‑Lived Connection (Socket.io)

Extremely simple chatroom demo (React + Node) [1] Implementation steps: Establish connection between front‑end and back‑end. Front‑end sends messages to the server. Server broadcasts received messages to all users. Front‑end receives broadcast and updates state.
// client
import React, { memo, useEffect, useState, useRef } from "react";
import { io } from "socket.io-client";
import { nanoid } from "nanoid";
import "./index.css";

const host = "192.168.0.108",
      port = 3101;

const ChatRoom = () => {
  const [socket, setSocket] = useState(io());
  const [message, setMessage] = useState("");
  const [content, setContent] = useState([]);
  const [userList, setUserList] = useState([]);
  const userInfo = useRef({ id: "", enterRoomTS: 0 });
  const roomState = useRef({ content: [] });

  useEffect(() => {
    initSocket();
    userInfo.current = { id: nanoid(), enterRoomTS: Date.now() };
  }, []);

  useEffect(() => { roomState.current.content = content; }, [content]);

  const initSocket = () => {
    const socket = io(`ws://${host}:${port}`);
    setSocket(socket);
    socket.on("connect", () => {
      console.log("连接成功");
      socket.emit("add user", userInfo.current);
    });
    socket.on("user joined", ({ id, userList }) => {
      const newContent = [...roomState.current.content];
      newContent.push({ id, message: `${id}加入`, type: "tip" });
      setContent(newContent);
      setUserList(userList);
    });
    socket.on("new message", ({ id, message }) => {
      const newContent = [...roomState.current.content];
      newContent.push({ id, message });
      setContent(newContent);
    });
    socket.on("user leave", function ({ id, userList }) {
      const newContent = [...roomState.current.content];
      newContent.push({ id, message: `${id}离开`, type: "tip" });
      setContent(newContent);
      setUserList(userList);
    });
  };

  const handleEnterSend = (e) => {
    if (e.key === "Enter") {
      socket.emit("new message", { id: userInfo.current.id, message });
      setMessage("");
      e.preventDefault();
    }
  };

  const handleButtonSend = () => {
    socket.emit("new message", { id: userInfo.current.id, message });
    setMessage("");
  };

  const handleChange = (e) => setMessage(e.target.value ?? "");

  const handleQuit = () => socket.disconnect();

  return (
    <div>
      {/* UI omitted for brevity */}
    </div>
  );
};

export default memo(ChatRoom);
// server
import { Server } from "socket.io";

const host = "192.168.0.108",
      port = 3101;

const io = new Server(port, { cors: true });
const sessionList = [];

io.on("connection", (socket) => {
  console.log("socket connected successful");
  socket.on("add user", ({ id }) => {
    socket.id = id;
    if (!sessionList.includes(id)) sessionList.push(id);
    console.log(`${id} 已加入房间, 房间人数: ${sessionList.length}`);
    io.emit("user joined", { id, userList: sessionList });
  });
  socket.on("new message", ({ id, message }) => {
    io.emit("new message", { id, message });
  });
  socket.on("disconnect", () => {
    sessionList.splice(sessionList.indexOf(socket.id), 1);
    socket.broadcast.emit("user leave", { id: socket.id, userList: sessionList });
  });
});

Synchronization Strategies

Modern games mainly use two synchronization approaches: frame sync and state sync .

Frame Sync

In frame sync, the server merely forwards player actions. Each client receives the actions and executes them locally.

State Sync

In state sync, the client sends actions to the server, the server computes the new state, and then broadcasts the result back to all clients for rendering.

Latency Compensation

Network latency is unavoidable, but three steps can hide it from players:

Prediction

The client does not wait for the server’s response; it immediately simulates the action locally and later reconciles with the authoritative state.

Because the server may return an older state, a rollback can occur.

Reconciliation

When the delayed server state arrives, the client re‑applies any actions that occurred after the received state, preventing rollback.

The server’s old state becomes the base; subsequent actions are re‑predicted to produce the correct current state.

Interpolation

Even with prediction and reconciliation, other players may still appear jittery. Adding smooth transition animations (interpolation) makes movement appear fluid.

Implementation of Synchronization Strategies

type Action = {
  actionId: string;
  actionType: -1 | 1;
  ts: number;
};

const GameDemo = () => {
  const [socket, setSocket] = useState(io());
  const [playerList, setPlayerList] = useState([]);
  const [serverPlayerList, setServerPlayerList] = useState([]);
  const curPlayer = useRef(new Player({ id: nanoid(), speed: 5 }));
  const actionList = useRef([]);
  const prePlayerList = useRef([]);
  // socket initialization and event handling omitted for brevity
  // player input handling (left/right) with prediction, reconciliation, and interpolation
  // UI rendering omitted for brevity
  return (<div>{/* UI omitted */}</div>);
};

export default memo(GameDemo);

Conclusion

Thanks to the help of senior developer King and the reference animations, I built a working demo. I discovered that my earlier attempts felt laggy because they differed from the pure front‑end demo. Networked multiplayer game development involves many more challenges beyond basic communication and synchronization.

References

How to design large‑scale game server architecture? – Toutiao

Two‑day multiplayer real‑time battle with 200 ms latency still feels smooth – Juejin

How to build a networked multiplayer game? – Zhihu

ReconciliationSynchronizationPredictionServer ArchitectureSocket.IOmultiplayerframe syncstate sync
ELab Team
Written by

ELab Team

Sharing fresh technical insights

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.