Skip to main content

Architecture Overview

Introduction

Lock-free asynchronous and event-driven architecture; truly lightweight. You can build a distributed network communication server without any third-party middleware.

Built-in load balancing, distributed support, and dynamic machine scale-out/scale-in.

NameScaling ModeResponsibility
ExternalServerDistributedResponsible for user connections and interaction
LogicServerDistributedResponsible for specific business logic processing

ionet


From this architecture overview, we know the overall architecture consists of external services and logic services. They can run independently or be integrated together.

  • External server and logic server in one process. (Monolithic app; easier debugging during distributed development)
  • External server and logic server in multiple processes. (Distributed deployment)
  • You can even run only logic servers without an external server for internal communication in other systems.

Because ionet follows object-oriented design principles (Single Responsibility, Open-Closed, Liskov Substitution, Dependency Inversion, Interface Segregation, and the Law of Demeter), the architecture has clear responsibilities and can be combined flexibly.

Most developers have seen this situation: in the early stage, projects are usually developed as a monolith, but as requirements keep growing and iterating, the project becomes bloated. At that point, splitting the whole system is difficult and expensive, sometimes practically impossible, and eventually leads to a full rewrite.

ionet provides deployment flexibility through structural combinations, so these split issues can be avoided from the beginning. During development, we can use monolithic-development thinking to reduce development cost. With a monolithic development style, debugging distributed projects becomes much easier. This balances distributed development and module splitting while reducing team cost.

Architectural Advantages

The architecture is highly abstracted, allowing designers to focus more on business logic without worrying about low-level implementation details or communication parameters.

We use a modular and abstract architecture that significantly reduces coupling between servers. Logic servers can be dynamically added, removed, or modified, which greatly improves scalability and maintainability and makes dynamic expansion simple and efficient. In addition, lower coupling between logic servers also makes debugging and testing easier to manage.

The architecture is very clear: the external server is responsible for client access maintenance (user/player connections), while logic servers focus on business logic. Because this split is reasonable, it is especially convenient to scale freely with Kubernetes: scale out the busy service, then scale back in when traffic drops.

Same-Process Affinity

Same-process affinity is one of the framework features. It gives servers in the same process priority access to each other. When a request needs to be handled, it is prioritized to a logic server in the same process.

  • For example, process P-1 starts External-A-1 and LogicServer-B-1.
  • For example, process P-2 starts External-A-2 and LogicServer-B-2.

When External-A-1 needs to request LogicServer-B, the request is prioritized to LogicServer-B-1 instead of LogicServer-B-2.


Deployment Sketch

  • pid: indicates services running in the same process.
  • External: external server.
  • LogicServer: logic server.
  • CommonGameLogic: shared/common logic servers. An

In the diagram, we start 3 processes.

  • pid:1111 runs an external server and logic servers [A-1, B-1].
  • pid:2222 runs an external server and logic servers [A-2, B-2].
  • pid:3333 runs multiple common logic servers.

Because services are in the same process, when pid:1111 has an action request to process, it is prioritized to A-1. Cross-server shared business requests are handled by pid:3333.

tip

Using same-process affinity properly enables process-level micro-isolation between services.


Use Cases

By leveraging same-process affinity and the deployment shown above, developers can achieve process-level micro-isolation between services. At the same time, some logic servers can be provided for shared business handling, such as cross-server activities, cross-server battles, and other cross-server business.

For the following game types, you can consider this deployment model:

  • Multi-shard games.
  • RTS (Real Time Strategy), such as StarCraft and Red Alert.
  • MOBA (Multiplayer Online Battle Arena), such as League of Legends and DOTA2.
  • ARPG (Action Role-playing Game), such as Diablo and Infinity Blade.
  • FPS (First-person Shooter), such as Call of Duty and PUBG.
  • TPS (Third-person Shooter), such as Vanquish and Battlefield.
  • ...

Flexible Architecture Deployment

From Why Fast, we know the framework provides an IPC mechanism that enables nanosecond-level communication between processes on the same machine. This means by adjusting different combinations, we can adapt to almost any game and scenario. For example:

  1. On the same machine, communication between different processes uses IPC.
  2. In the same process, communication between different logic server instances uses IPC.
  3. In the same LAN, communication between different machines uses UDP.
  4. Across different LANs, communication uses UDP.

ionet supports all the scenarios above, effectively covering all communication-related scenarios.


Network Communication Across Different LANs

In production, cross-LAN communication is rarely used, but it is useful in some special cases. For example, during a pandemic or fully remote work, backend and frontend teams can collaborate well in this mode.

Deploy the external server to the cloud, while running logic servers locally. Note that you do not need to deploy your logic server to the cloud before frontend teammates can access it. You can run logic servers locally and connect them to the cloud, so frontend teammates can access the business you implemented.

During joint debugging, code changes and server restarts are usually frequent. In this process, you only need local modifications and restarts, and frontend connections stay intact while logic servers restart. So frontend teammates do not need to repeatedly log in, avoiding tedious actions (such as re-entering account/password). For frontend teammates, this process is almost transparent, which is an excellent development experience.

ionet starts quickly, typically in about 0.x seconds. By the time we finish changes and restart, frontend teammates may not even notice before everything is ready.


Summary

From these examples, we can see ionet's architecture is diverse and adaptable. To support different game types, you can adjust deployment patterns, and the adaptation is straightforward.

When developing with the framework, you do not need to worry whether it can support a certain game type, because deployment patterns can solve that and adapt to any game type.


How to Choose

From the discussion above, there is no fixed universal best solution, only the best fit for your project needs.

If some logic server businesses change quickly and require frequent restarts, then a single-process deployment may not suit your current business; separated deployment is usually better.

After choosing separated deployment, logic server restarts do not affect online players, because online players remain connected to external servers, so this process is transparent. That transparency provides a great player experience. You probably would not want to play a game that disconnects frequently.

So the conclusion is to adjust based on the current stage and needs of your project.