background
I’ve been in the normal CRUD business all my life. Recently, our product manager came up with the idea of integrating a quiz versus mini-game into our current product. There are still some challenges for me who can only CRUD for years. Up to now, the project has been close to the completion of development. So far, some gains in the project are summarized.
This paper mainly summarizes my actual combat experience in doing this project, so each module starts from the business aspect, after all, the technical design without the business is nonsense. If you’re looking for code here that you can use, it’s obviously not there. And I assume that you already know the basics. But AT the end of the article, I added some good articles and blogs that I referred to during the project. Feel free to check them out.
Communication mode selection
The answer to the small game can be counted as an online game. In an online game, a very important point is to keep the synchronization between server and client, and between client and client. There are already two common synchronization models in the game industry: frame synchronization and state synchronization.
Frame synchronization
King of Glory, which we’re all familiar with, uses frame synchronization. In simple terms, the server specifies a sequence in which all clients must transmit their actions to the server. The server receives all the actions from the client and then forwards them to all the clients in the current battle. According to the received action signal, the client reproduces it locally.
As you can see, frame synchronization has a very complete timeline control, and in the case of a small number of clients, the amount of message data that needs to be sent to each other is very small (only the actions of each client in this time sequence need to be transmitted).
State synchronization
Status synchronization is when a client sends an operation to a server, which performs a calculation and passes the result to other clients. Since timing control is not strict, it is suitable for turn-based games.
conclusion
Frame synchronization and state synchronization are implemented differently, making them suitable for different types of games. We are going to do the answer to the small game, belongs to the turn-based game, so choose the state synchronization.
Implementation of communication mode
Regardless of the backend design, we need to consider how messages are sent from the server to the client. I was familiar with the HTTP interface, the request can only be initiated by the client, the server can only respond to the request of the client. So it’s time to introduce websockets.
In Java, the commonly used WebSocket framework has Spring and Netty, considering that I have a better understanding of Spring, so I use Spring.
Spring provides two different scenarios for using WebSockets. One is STOMP, a message-specific protocol that is very refreshing to use. The other is the native WebSocket, which is a bit more complicated to use but more flexible. I chose the latter because it was easier to dock with our small program front end.
Although WebSocket can be complicated to access, it actually provides only a few functions:
- Connection is established
- News listening
- Message is sent
That said, no matter what the business is, we need to boil it down to these three functions.
authentication
We need to authenticate any request on the network. WebSocket has an HTTP handshake request before establishing a connection. In Spring, we can by setting the org. Springframework. Web. Socket. Server HandshakeInterceptor to intercept a handshake request.
So we can set up a connection request with authentication parameters, such as the generated Token or the user’s account password. In addition, you can perform other tasks during authentication, such as checking the number of established connections and controlling the number of server connections to prevent public network bandwidth exhaustion.
Since this link is an HTTP request, it can respond with a specific HTTP status code to the front end.
Receives the message
Listening for the message is simple, org. Springframework. Web. Socket. WebSocketHandler# handleMessage provides news listening method. We can put the corresponding action action in the message and call different business methods based on the action.
Message is sent
In the Spring of the native WebSocket in use, if you want to send a message to the client, you must use the org. Springframework. Web. Socket. WebSocketSession. This is not a problem in itself, but it is in a distributed environment.
For example, I have two servers. Server 1 receives the message from client 1, and then responds to the message and needs to forward it to client 2, but client 2 is currently connected to server 2. How can server 1 keep the connection to which server client 2 is connected? How does server 1 forward the message to server 2 even if server 2 knows about it?
WebSocket cluster scheme in distributed environment
Nowadays, any business needs to consider its usage and implementation in a distributed environment, and a single point is never reliable. On the HTTP server, we can persist the HTTP Session into Redis to achieve distributed Session, or we can discard the Session completely and adopt the Token solution. However, WebSocket sessions cannot be saved to Redis. This is easy to understand, the WebSocket connection is actually stateful, the client and the server is established as a long connection, so even if I persist the session, it is impossible to obtain the session on another server to send messages to the corresponding client.
So how to solve it?
The simplest way is to use broadcast messages. When the server finds that it needs to send a message to the client, it sends a broadcast message directly, and all servers can receive the broadcast message. When the server receives this message, it checks whether the client to be pushed keeps the connection with itself. If not, it directly discards it. If it does, it pushes the message to the corresponding client. The implementation of broadcast message is also very simple, you can use MQ directly, currently the mainstream MQ provides broadcast message function, I used RocketMQ. You can also use Redis’s subscribe and publish feature, which works the same way.
Of course, broadcast messages are obviously wasteful of performance. A more advanced strategy is to use Hash routing to allow clients with certain characteristics to connect to a specified server. When the server needs to send messages, it only needs to find the server that keeps the connection with the client according to the routing table. However, such implementation needs the support and cooperation of operation and maintenance. If the request volume is not large or the server node itself is not much, the use of broadcast messages is enough.
Further reading
Learn WebSocket basics: WebSocket tutorial – Ruan Yifeng
If you add WebSocket implementation in Spring project: SpringMVC + WebSocket full implementation
Distributed WebSocket implementation: Distributed WebSocket cluster solution
Play Cards: Explore common game backends