yivgame
Yivgame is a microservice architecture game server solution written in the go language based on go-kit. It is not a framework, but a complete set of game server instances. Each module only retains a sample code implementation. In addition to the game server (long connection), it also includes an API interface server for front-end and back-end operations. The interface of the operation back-end will be implemented using Angular. In addition to the server itself, detailed configuration of docker deployment will also be involved.
characteristic
- Microservice architecture
- The client and the game server realize transmissibility through grpc bidirectional streaming
- Client-server-side websocket communication
- Implement http endpoints and websocket endpoints weights and logs
Design Practice
Microservice architecture
- Through the microservice architecture, traditional game servers are split into different microservices
- Different micro servers can communicate synchronously through grpc and asynchronously through kafka
Domain-driven model
- In order to achieve decoupling of different levels of software, each service is designed in accordance with the domain-driven model.
- Divide the software structure of microservices from the inside to the outside into the game business layer, use case layer, interface layer and facility dependency layer
- Strictly abide by one-way dependence from the outside to the inside between the various levels
The business layer mainly implements the core logic of the game or server, does not care about external implementations, and depends on file systems, databases, etc. The business layer uses interface to define interfaces, implements interface methods by the dependency layer, and passes them in main through dependency injection. Called to the business layer. Therefore, except for citing some basic standard libraries, the business layer hardly refers to third-party packages.
Event-driven model with Kafka
- The core communication method between the entire microservice system is grpc synchronous call and asynchronous event communication using kafka as the streaming platform.
- All activities that are being followed in microservices will be published to kafka in the form of events generated. Consumers with different concerns will subscribe to the events of their interest. kafka pushes the events to consumers, and consumers will handle the event accordingly. and response
Event-driven model and data analysis
- In the past, when doing game data analysis, they were searched through joint tables.
- After using the event-driven model, all the player behaviors we pay attention to can be recorded as events, design different attributes for different events, and achieve extremely scalable data analysis


Project directory structure
- Since the microservice architecture implemented by go-kit, try to keep it consistent with the official example of go-kit in the directory structure as much as possible.
- Since the domain-driven model is layered, it is natural to include the inner package directory in the outer layer when designing the project directory structure. Since I prefer the flat directory structure of most Go projects, I do not strictly follow it. Designing the directory structure at the domain level, instead, the directory of packages of different levels is placed under the directory of the same level. For me, this seems more intuitive and simple.
No global variables
- In order to make the software clearer in code logic, strictly avoid global variables
Data cache, data storage and Kafka
- Therefore, player data is directly stored in service memory, which facilitates direct data processing
- The modification of player data is written to kafka through WAL, and then the storage service is asynchronously written to the database.
- Since the WAL method is used, redo and undo of player data are easy to implement
NewSQL CockroachDB
- Data persistence uses CockroachDB, a relational database that supports distributed transactions
- Using CockroachDB can easily achieve horizontal scaling, fault tolerance, automatic recovery, and load balancing
I started using CockroachDB from v1.0, from v1.0 to v1.0.6, CockroachDB has always had a crash problem under specific situations and pressures. Since the release of v1.1, the crash problem has not appeared again, but the performance has not been large. improve. Because almost all the data of yivgame is in memory, and only db needs to be written when saving, so for the entire yivgame system, there is no db performance bottleneck.
Model
Communication diagram

- Communication method
- HTTP: http is a short connection, mainly used for communication in the background operation system. In addition, the data communication part involving strong interaction in the game can also be used to communicate with http.
- WebSocket: The client is developed using cocos creator, and long-connect communication supports WebSocket. WebSocket is mainly used for difficult communication with real-time and strong interactions in games.
- GRPC: Based on HTTP/2 protocol GRPC, it can realize multi-stream communication on a socket connection. It is a relatively common communication method in the go microservice ecosystem.
- Data format
- JSON: Due to the self-interpretation of the json format, it is mainly used for data exchange between short connections and backend operation system interfaces in the game.
- Protobuf: mainly used for data exchange between client and server websocket and micro-service
Service component diagram

- Agent: It is mainly used for client access. It directly transmits data packets and forwards them to the backend microservice. It is a stupid gateway and thin gateway that hardly participates in business logic and codec business data, so its code logic is relatively Simple, and easy to expand horizontally
- UserCenter: All player data is managed in the user center, and the user center is responsible for reading, writing, deleting, modifying and checking game data. It provides grpc interface for APIGate, game server and other microservices that require player data to be used.
- Game Server: Mainly responsible for processing game business logic
Identity authentication and authentication

- Use jwt to authenticate between services
- Single sign-in through API gateway
- Do authentication globally, and authorization in every microservice
Facilities dependency
- docker: All dependency facilities and game instances are deployed through the docker community version
- rockcoach: as a persistent database
- kafka: as message queue and stream platform
- etcd: for service discovery
- gogs: Use gogs for version management
- bind9: Domain name server, seamless switching of development and testing networks through switching domain name resolution
go-kit generator
- yiv/gk: go-kit code generator is a hand-electric drill. The only upset that go-kit has found at present is that writing a service is too long-winded. It designs a very elegant service output method, but in order to write a service interface, each Everyone has to write a complete set of endpoint, set and transport. The code patterns are the same. The codes of this big bunch are basically similar. If you write too much, you will be very irritated. You feel that you are doing repetitive work and are very prone to errors. , after searching for several times, I didn't find a generator that fully matches the official example of go-kit. Finally, I selected kujtimiihoxha/gk, but it was not perfect yet, and it was not completely applicable to me, so I fork it down and changed it myself and passed it Automatically generate code, which can reduce duplicate code by 60% when writing service interfaces. More importantly, it greatly reduces the probability of errors.
System environment
refer to
- gonet/2: yivgame has absorbed a lot of designs from gonet, such as using stream for transparent transmission, introducing kafka, etc.
- go-kit: yivgame is developed based on go-kit
- goddd: A sample APP based on domain model written in go
- Practical Persistence in Go: Organising Database Access
- The Clean Architecture
- Applying The Clean Architecture to Go applications
- A post to understand the hierarchical structure
Some thoughts on design
- The complexity of the system will only shift and will not disappear. Behind the straightforward simplicity, there are dirty and tiring work behind it. Simplicity has costs. Either reduce performance, avoid some features such as expansion, or do it by others, use it. The advantage of go-kit is that it doesn't look that simple, and directly reflects the design goals in the code. Learning to use go-kit helps improve software design capabilities.
- go-kit is not suitable for pursuing easy-to-use, short, flat and fast goals. It uses layering to separate attention, which will inevitably introduce complexity. The code may seem to be interspersed with wordy words, but focusing on separation design helps logical decoupling.
- go-kit starts with service interface, starts with focusing on business areas, http or grpc is just a way to publish it to the outside world, and it is placed in the end.
- Don't pursue freedom of writing, but pursue freedom of software adaptability. Freedom does not mean that I can write as much as I want. The code must be standardized, and the team must unify the programming style to facilitate communication. Go-kit is not free because it defines The result is that the services written using it all look similar. It is so awesome that the code is written like a painting, and can be compiled and run. It is only suitable for playing, but not for engineering.
- The codec and communication of microservice calls introduced is about 2 milliseconds, and the domestic mutual ping delay is usually 40ms.
- Whether it is a framework or a language, they are just tools. Choose an excellent, handy, and suitable one in the industry. Use it well and skillfully. There is no need to spend time arguing and entangling which one is the best. Even if the tools are the best, they will be bad if they are not used well. The key is to learn and master the essence of their design so that they can never leave their essence.