Go language writing game server also has more than a month, can also feel the difference between the two. The purpose of this article is to talk about the differences in detail. Of course, before understanding the differences, let’s take a brief look at the Go language itself. *
PS: Just take SLG mobile games as an example
1. Go language features
Go is a relatively young language compared to other languages such as Java. The Go language was developed by Robert Griesemer, Rob Pike, and Ken Thompson at Google in 2007. It was officially released in 2009.
Go is designed around the idea that less is more. If you are familiar with Java, you can easily see this feeling when you use Java syntax naming to compare to Go.
The characteristics of Go can be summarized as follows.
1.1 Static and compiled types
First, Go is statically typed. Static typing means that you know the type of every variable at compile time. Thanks to this, problems can be found at compile time. In a dynamic language, such as JavaScript, some problems are not discovered until runtime.
Go is a compiled language, and when you see compiled you probably have another word that comes to mind: interpreted. The difference between the two can be seen literally, but let me use a simple analogy.
- When you go to a restaurant and order food, the restaurant waits for everything to be ready before serving it
- The interpretive type goes to a restaurant for dinner, orders the food, and slowly eats while eating
1.2 cross-platform
As the name implies, your Go source code runs on all systems.
This is easy to understand. For example, the slogan of Java is “Write once, run Anywhere “. We all know that Java is a compiled language, but Java generates bytecode when compiled, which is independent of the current operating system and CPU.
This bytecode must rely on the Java virtual machine to run, and the virtual machine hides differences between the operating system and CPU from the user. The process is virtually insensate to the programmer. For Java, the fact that the language itself is cross-platform does not mean that the code is cross-platform.
In some ways, as opposed to Java types, we need to install the version of Go that corresponds to the current operating system. The compiled executable will vary from operating system to operating system.
1.3 Automatic garbage collection
As with the JVM, Go’s memory management (GC) at runtime is managed by the Go language itself without programmer involvement, although we can intervene.
1.4 Native concurrent programming
What is native? As we all know, to achieve concurrency in Java, we need external library support (Thread), and Go does not need to import any external dependencies. The keyword go is supported. And Java communicates through shared memory, so anyone familiar with Go has seen the phrase “Don’t communicate through shared memory, communicate through shared memory.”
1.5 Perfect build tools
A range of processes from get, compile, test, install, run, and analyze have their own built-in tools. For example, you can use go get command to download and update the specified code package, and compile and install them. You can use Go Build to compile the source code, use go run command to run the go program, use Go FMT to quickly format the code and unify the code style.
1.6 Multi-paradigm programming
At present, the mainstream programming paradigms include imperative programming, functional programming and the most familiar object-oriented programming. When writing Go code, we can choose to use the object-oriented approach, or we can use the idea of functional programming, combined with each other, complement each other.
For example, in Go, you can also use interfaces to describe behavior, or you can use pure functions to avoid side effects. Therefore, multi-paradigm programming means that the language supports multiple programming paradigms.
1.7 Strong unified code style
Use Go’s built-in tool Go FMT to quickly format the code into the official unified standard, so as to achieve the purpose of uniform code style. You can even use Golangci-Lint to check if your syntax conflicts with the built-in standard syntax. You can also use golangci-Lint on a Git hook to enforce uniform code styles.
1.8 Active community
Another important feature is that the Go community in China is very active, which plays a great role in the popularity of Go in China.
2. Take advantage of Go
Let me start with my view on Go. I think Go is very advantageous in the server space. In the future, if there are high concurrency application scenarios, there is a high probability that the service will be written in Go. I don’t know if you’ve noticed, but Moore’s Law is failing. The raw processing power of hardware hasn’t improved much in the last decade. Obviously, simply increasing the number of transistors is no longer the best solution.
A recent NASA article posted to its website and then quickly deleted revealed that Google may have achieved quantum hegemony, which in layman’s terms means that it has more computing power than any conventional computer. It’s getting more expensive to put more transistors in, so now manufacturers are adding more cores to processors to boost performance.
As you are familiar with Java, using multithreaded programming code on Java can be expensive, even though Java itself supports multithreading. Creating a new thread in Java consumes approximately 1 MB of memory. If you really need to support running thousands of threads, then the service is probably running OOM. In addition to memory consumption, there are issues such as concurrency and deadlocks due to support for multithreading.
In Go, coroutines are used instead of threads. And a coroutine consumes many times less memory than a thread. With the same physical device limitations, you may only be able to start a few thousand threads at most, whereas coroutines can start millions. And different Goroutines can communicate securely through a channel.
3. Differences between game servers and Web servers
Some descriptions of game servers might say that a game server is a long-running application and then something. I personally think that Web servers are just as persistent and need to respond to random requests from users. There is no essential difference between them from a macro point of view. At the same time, the Web server will also have requirements for stability and performance, game service is generally divided into large and small service, we are here according to the small service examples.
3.1 state
The first thing to mention is states. You’ve probably heard of the concept that a game server is stateful, whereas a Web server is stateless. What does that mean? Most of the data flow from the Web server goes directly to the database. The game server streams data into memory and then periodically writes it to the database (landing).
In other words, there is a window of inconsistencies between the game server’s own data and the data in the database at runtime. If the game server goes down at this point, there will be a mismatch between the memory data that the data arrives in first and the data store data.
A Web server doesn’t have this problem; all data states on the Web land, and transactions can be added for operations without worrying about dirty data being introduced if operations fail. Because of the state constraint, the game server will be very careful to use memory and CPU. In order to maximize the capacity under the circumstances of limited resources, and reduce service delays. Of course, the Web server will make optimizations to reduce the response time of an interface.
3.2 capacity
In the Web server, if you can’t evaluate a service pressure, do not want to because of instantaneous hot access service directly, not with words, completely can be set to automatic expansion, simply because each service receives the request, and then process the request and returns the result, not the data stored in the server’s memory. To have data stored in memory, that is also in Redis. Redis data loss basically has no impact on data consistency.
But on the game server side it’s hard to be as flexible as on the Web. First, the data flows not to the database, but to memory.
Take a very simple example, a player’s main city is attacked and set on fire. If there is automatic expansion, it is very likely that in the landing window, the player will request again and request another instance. The main city is not on fire again. Because the data is going to be in memory first.
Another example is when a player buys a gift pack. Then quit the game, the landing window is no more online. It’s not just a data problem, it’s an item that the player bought for real money, and suddenly it’s gone. One or two can handle it, but if multiple players have this problem, it’s a serious online incident. The workload of data repair is very large.
Therefore, for a game server, the available memory and CPU resources are very limited, unlike a Web server that can scale horizontally without much expense. This is why game servers are very focused on code performance and stability.
3.3 stable
As in the example above, if the game server runs with a BUG that causes the service to be directly unavailable, or a large number of items are brushed through this BUG, it would be a very serious online incident.
For Web servers, if it is a management system and so on, there may be dirty data. It is worth mentioning that dirty data is also a headache for the Web to troubleshoot. If there is no dirty data, the service is temporarily unavailable, and if the microservice architecture is used, the cost of restarting the service is relatively small. Only the services that are being restarted are unavailable, and the rest of the services can be accessed normally.
For game servers, server restarts affect all players. Players can’t even enter the game during downtime, which is particularly bad for the player experience. In addition, if the server fails to land data before the service stops, data will be loaded from the database to memory after the service restarts, which will also cause data inconsistency problems.
3.4 performance
In my experience, when working on a Web server, there is not a lot of optimization to reduce GC stress, to reduce memory footprint. Of course this is due to the small size of the project itself, and if the QPS is high, the Web server also needs to be very performance-oriented, but the game server needs to be very focused on this aspect all the time.
On the Web, however, if the volume of traffic causes a single service to fail, the first solution most people think of is multiple instances, which can easily scale horizontally.
In the game server, will see the server’s resources are quite precious. For example, fields that cannot be landed should never be landed, and the value of a field that can be calculated using known conditions should not be defined in the code. But it depends on the tradeoff between the amount of computation and the frequency of the calls. Because once you go live, if you encounter data inconsistencies, the less data you maintain, the easier it is to fix.
3.5 strict
This is, I think, a key focus of both. However, in some cases on the game server, if the server throws an exception or panic. The consequences are magnified by the particular context of the game.
For example, if you fail to recall your troops from the field, they will remain out and unavailable. This is relatively minor compared to clicking a button in the middle of a browser and not responding. And with a microservice architecture, after fixing the problem, the corresponding service can be restarted at a very low cost, with the game server having to repair the data once.
To take another extreme example, click on the store and the player will be prepared to pay. But you find that you can’t get into the store and may not be able to get a list of items. These can have a direct impact on the experience of the game and even the revenue.
For the Web, server stability is also important. Otherwise, the severity of the consequences may vary according to the business. Affect the user experience, will directly affect the product reputation.
3.6 Data transmission format
As anyone familiar with the Web knows, the data transfer format is JSON. On the game server is Protobuf, a data transfer format developed by Google that is similar to JSON. Protobuf is binary, and binary data is a little bit smaller than JSON. Also, if the transmitted field is null, it will not be transmitted. If JSON is null, the same will be transmitted.
Protobuf performs better than JSON in any environment, for example, node.js and Java. In Java, Protobuf is even nearly 80% faster than JSON. If Java is experiencing performance bottlenecks in communication between services, consider using RPC to communicate between services.
But every coin has two sides. The disadvantages of Protobuf still exist:
- The document is less
- Community versus JSON
- Not as readable as JSON
4 summarizes
So that’s the difference over the last two months. Just from the general do a contrast, and did not go into detail. Details may be introduced separately in the future.