This is a creation in Article, where the information may have evolved or changed.
Previously, because of the work required, wrote 2 Golang HTTP protocol services, and did not find any noticeable performance problems.
Http/1
This is mainly because the Golang HTTP client supports keepalived long connection multiplexing by default and supports maintaining connection pooling (multiple connections) for the same host, so it is not affected by the performance of short connection problems. Of course, you should also pay attention to configure some of the HTTP client parameters to optimize the behavior of keepalived, for reference: "Go HTTP client large number of long connection hold."
Now that the HTTP client is so good, do you need to study anything else? Obviously, there are some problems with http:
- Server-side serial response: Successive requests on a connection must return an answer in the order in which the request arrives.
- This causes the previous request processing slow to directly affect the subsequent response time of all requests to become longer, obviously is a problem that can not be ignored.
- HTTP protocol Parsing performance: parsing HTTP header is a text protocol, not as fast as binary protocol.
- Payload parsing trouble: In general, we use json/xml and other formats in the business protocol, Golang directly in the sequence/deserialization is troublesome, or when the protocol upgrade may appear compatibility problems, can only be used in the Google Protobuf library to solve, It's either a lengthy code 1.1-point deserialization, a headache.
HTTP/2 very good!
In fact, a good optimization scheme is the HTTP2 protocol, which is the upgraded version of HTTP1, which solves 2 problems:
- Reply Disorderly Order: Not only the request and the reply through the ID association satisfies the disorderly order reply, moreover the reply can also divide the frame transmission, solves the large file transfer to bring the connection occupation problem.
- binary protocol: Resolves the performance problem of protocol resolution and reduces the amount of transmission.
Golang Standard library Current support for HTTP/2 is more mature https/2, that is, encrypted version, need to generate a public private key to use.
It has the advantage of Golang HTTP/1 client (connection pool, idle automatic disconnection, long connection), is a very good RPC scheme. Even Google's Grpc is based on the HTTP/2 protocol, so it's recommended to take precedence.
The background of HTTP/1 and HTTP/2 can be added here to learn the connection building of HTTP/2 notes.
How's JSONRPC?
JSONRPC is a standard RPC protocol, simply said the request is a number of JSON string sent out continuously, the answer is the continuous JSON string returned back, because it is RPC reason request and answer by ID Association, thus implementing concurrent chaos, the relevant instructions can be understood in the Wikipedia.
Golang's support for JSONRPC is limited, and there are several issues:
- Automatic re-connection is not supported
- A client is not supported to access multiple downstream
- Single downstream multiple connections not supported
- Exposes transport (underlying TCP connections) to user management, adding complexity.
Do not underestimate these missing features, it has undoubtedly brought us to use that caused a great obstacle, and did not reflect the Golang to simplify the advantages of network development.
But I just took a learning attitude to experience a bit of JSONRPC, it is part of the Golang standard library, although it is not the value of the use of a high, the relevant code see GITHUB:HTTPS://GITHUB.COM/OWENLIANG/GO-JSONRPC.
The biggest advantage of JSONRPC as an RPC library is that it automatically transforms JSON requests and responses through reflection technology, transforming JSON fields into well-defined struct structure fields, avoiding the complexity of manually parsing requests.
JSON requests are sent in the TCP data stream, the server uses streaming JSON parsing, thus stripping out a separate JSON string from the TCP data stream, which is the basic principle of its communication.
Jsonrpc is very similar to protobuf, because it is a sequence/deserialization between a struct and a JSON, adding a field or reducing a field in a protocol upgrade does not cause an exception, and when deserializing the corresponding field is the default value if no value is passed.
The most troublesome thing is how to further encapsulate the various features mentioned above, and I only implemented a rudimentary reconnection mechanism that detects the connection state and initiates reconnection through a separate coprocessor timing, which causes the request to fail during the loss of the connection.
Learn HTTP Libraries
I deliberately looked at the HTTP library during the connection request processing, the idea is that if the connection pool has a normal connection then re-use it to send the request (in fact, queued on the connection request), if the connection pool is not properly connected then asynchronous to establish a connection.
The problem is that multiple concurrent requests will find the fact that there is no normal connection, and each initiate their own connection setup so that a connection cannot be reused.
Golang The idea of solving this problem is that first there is no connection so let them build their own connections concurrently. Second, as long as the requested connection succeeds in receiving a reply, the connection is dropped to a public size=1 channel to notify the other requests that are waiting for their connection to complete, and the new connection is added to the connection pool array, and subsequent requests can be reused directly.
Then other requests that are waiting for their connection may receive priority notification of the channel rather than the notification of their own connection completion, which, once this happens, is reused directly using the channel-transmitted connection. While your connection starts a goroutine wait for the connection to complete and then shut it down or put it in the connection pool (assuming the connection pool is not full).
Of course, there may be several concurrent requests that have a number of new connections that have been made by themselves, and that doesn't matter. These connections can also be added to the connection pool array for the first time after the request is completed, but the subsequent requests to reuse the connection always take precedence over the most recently used connections, so the redundant connections will gradually not queue more requests and slowly be shut down.
This is the idea of the HTTP library, you can see that it is a very trickery solution:
- Determine if the connection pool has an available connection, and if it is reused directly, be aware that multiplexing is not exclusive, but instead queues the request directly to the connection.
- If the connection pool is empty, start a new connection immediately, while waiting for other requests to create connections with their own connections, and who to complete first. The extra connections are either placed in the connection pool or closed directly as redundant connections.