HttpClient use in C # Note: Warm-up and long connections

Source: Internet
Author: User
Tags http post

Original: C # httpclient Use note: Warm-up and long connections

Recently testing a third-party API to prepare for integration in our website application. The API call is using HttpClient in. NET, because this API will be used in the critical business, the call API overall response speed is strict, so the httpclient has a special concern.

At the beginning of the test, only the client sends an HTTP POST request with Postasync via HttpClient. Testing found that from the creation of httpclient instances, to the request, to read to the server response data is always time-consuming around 2s, and many tests are like this. The response speed of 2s is certainly unacceptable, and we want to be at least within 100ms. So began to trace the cause of the problem.

The return data for the API contains the time-consuming execution of the request on the server, which is within 20ms, regardless of the server-side API. Then put the suspicion on the network delay, but Ping server response time is around 10ms, network latency is not very likely.

When we were preparing for a change of network environment for testing, it occurred to us that there were some problems with our testing methods. We only sent a postasync request through httpclient, and if HttpClient had some kind of preheating mechanism at the first call (such as in EF), the total time spent on 2s now could be mostly consumed by httpclient preheating.

Then modify the test code, the call from 1 times to 100 times, and then suddenly realize-only the 1th time is 2s, the next 99 times are within 100ms. Sure enough, there is some kind of preheating mechanism in HttpClient!

Now that we know the reason for the httpclient preheating mechanism, we can help httpclient warm up and reduce the time required for the first request. We tried a warm-up method that sends an HTTP HEAD request before formally sending an HTTP POST request with the following code:

_httpclient.sendasync (new  httprequestmessage {                    new HttpMethod ("HEAD  (")                     ,new"/")})                . Result.ensuresuccessstatuscode ();

After testing, this warm-up method can reduce the time spent on the first request from about 2s to less than 1s (the test result is more than 700 ms).

After knowing the truth of the 1th time that the httpclient request took 2s, we turned to the remaining 99 time-consuming 100MS requests and found that most of the requests were above 50ms. Is it possible to reduce it to less than 50ms? And there's always been a tangle: is it always necessary to dispose of httpclient () for each invocation? Do you want to httpclient a single instance or static (declared as a static variable)? Take this opportunity to look into it together.

Behind the httpclient, there is an East--TCP connection that has no negligible impact on the response speed of the request. A httpclient instance is associated with a TCP connection, and the TCP connection is closed when you dispose of httpclient (we also verify this with the Wireshark network capture).

In the previous test, each time we use HttpClient to send a request, we are creating a new httpclient instance, and dispose of it after use, the code is as follows:

using (varnewnew  Uri (base_address)}) {    Httpclient.postasync ("/"new  formurlencodedcontent ( parameters));}

So every time you request to go through the new TCP connection, data-based closed connection (that is, usually referred to as short connection), and the worse is the request is HTTPS, the establishment of a TCP connection will also need a key exchange process on the basis of the public key and decryption: Client Hello, Server Hello, Certificate, Client Key Exchange, New Session Ticket.

If we want to reduce the request response time to less than 50ms, we have to start from this place-reusing a TCP connection (that is, the long connection that is commonly referred to). To implement a long connection, the first thing you need is to not close the TCP connection (without calling the Dispose method) after httpclient the 1th request, and to let the subsequent request continue to use the non-closed TCP connection, we must use the same HttpClient instance , and to use the same httpclient instance, you have to implement a singleton or static httpclient. The previous 3 issues, because to solve the 1th problem, the last 2 issues become a no choice.

To implement a long connection, we changed the httpclient calling code to look like this:

 Public classhttpclienttest{Private Static ReadOnlyHttpClient _httpclient; Statichttpclienttest () {_httpclient=NewHttpClient () {baseaddress =NewUri (base_address)}; //help httpclient warm up._httpclient.sendasync (NewHttprequestmessage {Method=NewHttpMethod ("HEAD"), RequestUri=NewUri (base_address +"/") })            .    Result.ensuresuccessstatuscode (); }     Public Asynctask<string>Postasync () {varResponse =await_httpclient.postasync ("/",Newformurlencodedcontent (parameters)); return awaitResponse.    Content.readasstringasync (); }}

Then test the request response time:

  elapsed:750ms  elapsed:31ms  elapsed:30ms  elapsed:43ms  elapsed:27ms  elapsed:29ms  Elapsed : 28ms  elapsed:35ms  elapsed:36ms  elapsed:31ms ...  .

In addition to the 1th request, the next 99 requests are mostly within 50ms. The effect of the TCP long connection must be!

The Wireshak clutch also verifies the effect of a long connection:

At this point, you may have a question: Is there a thread-safety issue in declaring httpclient as a static variable? We had this question at the time, and then we found the answer on the StackOverflow:

As per the comments below (thanks @ischell), the following instance methods is thread safe (all async): Cancelpendingreque Stsdeleteasyncgetasyncgetbytearrayasyncgetstreamasyncgetstringasyncpostasyncputasyncsendasync

All asynchronous methods of HttpClient are thread-safe and are used with ease.

Here, HttpClient's question is the perfect ending? Wait a minute, there's another problem.

While the client maintains a TCP connection, the TCP connection is a matter for the couple, the server side? You don't tell the server, how does the server know you want to keep the TCP connection? For the client, it is not very expensive to keep the TCP connection, but for the server it is completely different and if you keep the TCP connection by default, you have to keep thousands of clients connected. Therefore, the general Web server will be based on the client's request to determine whether to maintain a TCP connection, this is the reason for the existence of keep-alive.

So, we also want to add a connection:keep-alive request header to HttpClient, the code is as follows:

_httpclient.defaultrequestheaders.connection.add ("keep-alive");

Now it's time to end the finale. But certainly not perfect, sharing is only the process of solving the problem.

HttpClient use in C # Note: Warm-up and long connections

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.