4
头图

Friends who are familiar with me know that I have read the PDF of "HTTP Core Summary" before. This PDF is a summary of my HTTP series of articles. However, the HTTP-related content I wrote was all a year ago. I look back. I took a look at this PDF. Although there are a lot of contents, many of the contents lack systemicity and look uncomfortable. This is contrary to my original intention, so I plan to re-engage the HTTP protocol. The HTTP protocol is too great for our programmers. Importantly, no matter which language you are using, HTTP is the key point you need to know.

This is not an article that briefly introduces the basic concepts of HTTP. If you are not familiar with the basic concepts of HTTP, I recommend you to read the article about basic HTTP written by reading this HTTP, you will be

So we assume that everyone who is doing it has a certain understanding and knowledge of HTTP.

Let's start this article.

TCP with HTTP

We all know that HTTP, an application layer protocol, transmits data based on TCP. When you want to access a resource (a resource is a URL in the network), you need to parse the IP address and port number of the resource first to establish a TCP connection with the server where the IP and port number are located, and then the HTTP client initiates the service Request (GET) message. The server responds to the server's request message. When there is no need to exchange messages, the client will close the connection. Below I use a picture to illustrate this process.

image-20210724171103538

Good description of the HTTP connection is established from the beginning of the picture above -> initiate request packets -> close connection of the whole process, but the process above also overlooked a very important point, that is process established TCP connection .

TCP connection establishment requires a three-way handshake to exchange three messages. I believe everyone is well aware of this process. If you are still not sure about the process of TCP connection establishment, you can read this article by first 16109fbb8cb54c TCP connection management .

Since HTTP is located on the upper layer of TCP, the timeliness (performance) of the HTTP request -> response process largely depends on the performance of the underlying TCP. Only after understanding the performance of the TCP connection can you better understand the HTTP connection In order to achieve high-performance HTTP applications.

We usually call a complete request -> corresponding process an HTTP transaction.

So I will generally write it as HTTP transaction later, it is good if you understand what is going on.

Our next focus is to start with the performance of TCP.

HTTP latency loss

Let's review the above HTTP transaction process again. Which processes do you think will cause the HTTP transaction delay? As shown below

image-20210724224611391

As can be seen from the figure, there are mainly the following factors that affect the delay of HTTP transactions

  1. The client will determine the server's IP and port number according to the URL. This is mainly the delay of DNS converting the domain name into an IP address. DNS will initiate a DNS query to query the server's IP address.
  2. The second delay is when the TCP connection is established, the client sends a connection request message to the server and waits for the server to send back a response message. Each new TCP connection establishment will have an establishment delay.
  3. Once the connection is established, the client will request data from the server. This delay is mainly the delay for the server to read the request message from the TCP connection and process the request.
  4. The server will transmit the time delay of the response message to the client.
  5. The last delay is the delay for the TCP connection to close.

The last point of optimization is also a focus of this article.

HTTP connection management

Imagine a problem. Assuming that a page has five resources (elements), each resource requires the client to open a TCP connection, obtain resources, and disconnect, and each connection is opened serially, as shown in the following figure:

image-20210726231625034

Serial means that the five connections must be in order, and there will be no situation where more than two connections are opened at the same time.

The above five resources need to open five connections. Fortunately, if the resources are less, the CPU can handle it. What if the page resources reach hundreds or more? Do I need to open another connection separately for each resource? This will obviously increase the processing pressure of the CPU drastically and cause a lot of time delay, which is obviously unnecessary.

Another disadvantage of serial is that some browsers cannot know the size of the object before the object is loaded, and the browser needs object size information to place them in a reasonable position on the screen, so when loading Before there are enough objects, the screen will not display any content. This causes the object to be loaded all the time, but we think that the browser stuck with .

So, is there a way to optimize HTTP performance? This question is well asked, of course there is.

Parallel connection

This is the most common and easiest connection method to think of. HTTP allows the client to open multiple connections and execute multiple HTTP transactions in parallel. After adding parallel connections, the entire HTTP transaction request process is like this.

image-20210727234028172

Parallel connection will overcome the dead time and bandwidth limitations of a single connection, because each transaction has a connection, so the delay can overlap, which will increase the loading speed of the page.

But the parallel connection is not necessarily fast. If the bandwidth is not enough, even the page response speed is not as good as the serial connection, because in the parallel connection, each connection will compete for the effective bandwidth, and each object will be slower Speed is loaded, it is possible that connection 1 is loaded by 95%, connection 2 takes up 80% of the bandwidth, and connection 3 and connection 4. . . . . . Although every object is loading, there is no response on the page.

Moreover, opening a large number of connections will consume a lot of memory resources, resulting in performance problems. There are only five connections discussed above, which is relatively small. A complex web page may have dozens or even hundreds of embedded objects, which means , The client can open hundreds of connections, and there are many clients at the same time to send out applications, this will easily become a performance bottleneck.

In this way, the parallel connection is not necessarily "fast". In fact, the parallel connection does not speed up the transmission speed of the page. The parallel connection only creates the illusion of , which is a common problem with all parallelism.

Persistent connection

Web clients usually open a connection to the same site, and the application that initiates a request to a server is likely to initiate more requests to this server in the near future, such as getting more pictures. This feature is called site locality.

Therefore, HTTP 1.1 and HTTP1.0 allow HTTP to keep the open at 16109fbb8cb7ba after executing a transaction. This open state actually refers to the open state of TCP, so that the next HTTP transaction can reuse this connect.

A TCP connection that remains open after the end of an HTTP transaction is called persistent connection.

Non-persistent connections will be closed after the end of each transaction. In contrast, persistent connections will continue to remain open after the end of each transaction. A persistent connection will remain open between different transactions until the client or server decides to close it.

Long connections also have disadvantages. If the number of requests initiated by a single client is not very frequent, but there are many connected clients, the server will crash sooner or later.

There are generally two selection methods for persistent connections, one is HTTP 1.0 + keep-alive ; the other is HTTP 1.1 + persistent .

In versions prior to HTTP 1.1, the default connection is non-persistent connection . If you want to use a persistent connection on the old version of HTTP, you need to specify the value of Connection as Keep-Alive.

The HTTP 1.1 version is a persistent connection. If you want to disconnect, you need to specify the value of Connection as close. This is also the version factor of the two selection methods we mentioned above.

The following is a comparison diagram of HTTP transaction after using persistent connection and serial HTTP transaction connection

image-20210729224744113

This graph compares the time consumption graph of HTTP transaction on serial connection and persistent connection. It can be seen that HTTP persistent connection saves the time of connection opening-connection closing , so the time loss is reduced.

In the persistent connection, there is another very interesting place, that is the Connection option. Connection is a general option , which is a header that both the client and the server have. The following is a client with a persistent connection And server-side request-response diagram

image-20210729230851879

As can be seen from this picture, the connection header is mainly used for persistent connections, which means that Connection is the implementation of persistent connections. So below we mainly discuss the big guy Connection.

Connection header

The Connection header has two functions

  • Use with Upgrade for protocol upgrade
  • Manage persistent connections

and Upgrade are used together for protocol upgrade

HTTP provides a special mechanism, this mechanism allows an established connection to be upgraded to a new protocol, generally written as follows

GET /index.html HTTP/1.1
Host: www.example.com
Connection: upgrade
Upgrade: example/1, foo/2
HTTP/2 explicitly prohibits the use of this mechanism, this mechanism only belongs to HTTP/1.1

In other words, the client initiates Connection: upgrade to indicate that this is a connection upgrade request. If the server decides to upgrade this connection, it will return a 101 Switching Protocols response status code and a header field of the protocol to be switched to. Upgrade. If the server does not (or cannot) upgrade this connection, it ignores the Upgrade header field sent by the client and returns a regular response: for example, it returns 200.

Manage persistent connections

We said above that there are two ways of persistent connection, one is HTTP 1.0 + Keep-Alive ; the other is HTTP 1.1 + persistent .

Connection: Keep-Alive
Keep-Alive: timeout=10,max=500

In the HTTP 1.0 + Keep-Alive mode, the client can request to keep a connection open by including the Connection: Keep-Alive header.

One thing to note here: The Keep-Alive header just keeps the request in an active state. After the Keep-Alive request is issued, the client and server may not agree to the Keep-Alive session. They can close idle Keep-Alive connections at any time, and the client and server can limit the number of transactions handled by Keep-Alive connections.

The Keep-Alive header has the following options:

  • timeout : This parameter estimates the time the server wants to keep the connection active.
  • max : This parameter follows the timeout parameter. It indicates how many transactions the server can open persistent connections for.

The Keep-Alive header is optional, but it can only be used when Connection: Keep-Alive is provided.

There are certain restrictions on the use of Keep-Alive. Let's discuss the use restrictions of Keep-Alive.

Keep-Alive usage restrictions and rules

  • In HTTP/1.0, Keep-Alive is not used by default. The client must send a Connection: Keep-Alive request header to activate the Keep-Alive connection.
  • By detecting whether the response contains the Connection: Keep-Alive header field, the client can determine whether the server closes the connection after sending the response.
  • Agents and network management must be performed Connection header rules, they must forward the leopard out or before the cache, delete the Connection header header field and Connection header itself, because Connection is a Hop-by-Hop header, the header said only single This forwarding is valid and will be invalidated because of forwarding to the cache/proxy server .
  • Strictly speaking, a Keep-Alive connection should not be established with a proxy server that cannot be determined whether it supports the Connection header to prevent the dumb proxy problem. We will talk about the dumb proxy problem below.

Keep-Alive and dumb proxy issues

Here I first explain what a proxy server is, and then talk about the dumb proxy problem.

What is a proxy server?

The proxy server is a medium that replaces the client to obtain network information. Popularly, it is , the relay station for network information .

Why do we need a proxy server?

The most widespread use is that we need to use a proxy server to visit some websites that our clients cannot directly access for us. In addition, the proxy server has many functions, such as caching, which can reduce costs and save bandwidth; for real-time monitoring and filtering of information, the proxy server is also a client compared to the target server (the server that finally obtains the information). At the end, it can obtain the information provided by the server. Compared with the client, the proxy server is a server. It decides which information to provide to the client, so as to achieve the monitoring and filtering functions.

The dumb proxy problem appears on the proxy server. A more detailed point is that does not recognize the proxy server of the Connection header, and it does not know that the proxy server Connection header will be deleted after the request is sent.

Suppose a web client is talking to the web server through a dumb proxy server, as shown in the figure below

image-20210801143652945

To explain the picture above

  • First, the Web client sends a message to the agent, which contains the Connection: Keep-Alive header, hoping to continue to remain active after this HTTP transaction, and then the client waits for a response, and has determined whether the other party allows a persistent connection.
  • Dumb agent (it is not appropriate to define a dumb agent here. We often consider what we do first, and then characterize the matter. Now this server has not done any dumb proxy behavior, so we will give him the characterization) received this HTTP request, but it does not understand the Connection header, it does not know what Keep-Alive means, so it just sends the message to the server along the forwarding link, but the Connection header is a Hop-by-Hop header, which only applies to Single link transmission, so the proxy server should no longer send it to the server, but it still sends it, and some difficult things will happen later.
  • After the forwarded HTTP request arrives at the server, it will mistakenly think that the other party wants to keep the Keep-Alive persistent connection. After evaluation, the server responds and it agrees to the Keep-Alive conversation, so it sends back a Connection: Keep-Alive response and arrives A dumb proxy server.
  • The dumb proxy server sends the response directly to the client. After the client receives the response, it knows that the server can use the persistent connection. However, at this time, both the client and the server know to use Keep-Alive persistent connection, but the dumb proxy server knows nothing about Keep-Alive.
  • Since the proxy knows nothing about Keep-Alive, all the data it will receive will be sent to the client, and then wait for the server to close the connection, but the proxy server thinks it should be kept open, so it will not close the connection. In this way, the dumb proxy server has been hanging there waiting for the connection to be closed.
  • After the client sends the next HTTP transaction, the dumb proxy will directly ignore the new HTTP transaction, because it does not think that there will be other requests coming on a connection, so it will directly ignore the new request.

This is Keep-Alive's dumb proxy .

So how to solve this problem? Use Proxy-Connection

Proxy-Connection solves dumb proxy

Netscape has proposed a way to use the Proxy-Connection header. First, the browser will send the Proxy-Connection extension header to the proxy instead of the officially supported Connection header. If the proxy server is a dumb proxy, it will directly send the Proxy-Connection to the server, and if the server receives the Proxy-Connection, it will ignore this header, which will not cause any problems. If it is a smart proxy server, when it receives Proxy-Connection, it will directly replace Connection with Proxy-Connection and send it to the server.

HTTP/1.1 persistent connection

HTTP/1.1 gradually stopped supporting Keep-Alive connections and persistent connection . This improved design is also a persistent connection, but it has a better working mechanism than HTTP/1.0.

Unlike the Keep-Alive connection of HTTP/1.0, HTTP/1.1 uses a persistent connection by default. Unless otherwise specified, HTTP/1.1 assumes that all connections are persistent. If you want to close the connection after the transaction ends, you need to add a Connection: close header to the message. This is an important difference from the previous version of the HTTP protocol.

There are also some restrictions and rules for using persistent connection

  • First, after sending the Connection: close request, the client cannot send more requests on this connection. It can also be said that if the client does not want to send other requests, it can use Connection: close to close the connection.
  • The HTTP/1.1 proxy must be able to separately manage the persistent connections between the client and the server, and each persistent connection is only suitable for a single transmission.
  • It is best for the client to maintain only two persistent connections to any server or agent to prevent the server from being overloaded.
  • Only when the length of the physical part is Content-Length , or when the block transfer coding method is used, the connection can be maintained for a long time.

Piped connection

request pipeline to be used on persistent connections. This is another performance optimization relative to the Keep-Alive connection. A pipeline is a carrier that carries HTTP requests. We can put multiple HTTP requests into the pipeline, which can reduce the loopback time of the network and improve performance. The following figure is a schematic diagram of using serial connection, parallel connection, and pipeline connection:

image-20210801173109348

There are also several limitations to using pipelined connections:

  • If the HTTP client cannot confirm that the connection is persistent, pipes should not be used.
  • The HTTP response must be sent back in the same order as the request, because HTTP does not have the concept of sequence number, so once the response is out of order, there is no way to match it with the request.
  • The HTTP client must be prepared to close the connection at any time, and be prepared to resend all outstanding pipelined requests.

HTTP close connection

All HTTP clients, servers or proxies can close an HTTP transmission connection at any time. Under normal circumstances, the connection is closed after a response, but inaccuracy may also occur during the HTTP transaction.

However, the server cannot determine whether the client has any data to send at the moment of shutdown. If this happens, the client will have a write error during data transmission.

Even if there is no error, the connection can be closed at any time. If the connection is closed during transaction transmission, you need to reopen the connection and try again. If it is a single connection, it is better to say, if it is a pipelined connection, it is worse, because the pipelined connection will lose a large number of connections in the pipeline. At this time, if the server is shut down, a large number of connections will not respond and need to be rescheduled.

If an HTTP transaction is executed once or executed n times, the result is always the same, then we think that the transaction is idempotent, generally GET, HEAD, PUT, DELETE, TRACE and OPTIONS methods are considered Is idempotent. The client should not send any non-idempotent request in a pipelined manner, such as POST, otherwise it will cause uncertain consequences.

Since HTTP uses TCP as the transport layer protocol, HTTP closing the connection is actually the process of TCP closing the connection.

There are three situations for HTTP closed connection: completely closed, half closed and normal closed .

The application can close any one of the TCP input and output channels, or close both at the same time. Calling the socket close() method will close the input and output at the same time, which is called completely closed . You can also call the shutdown method of the socket to close the input or output channels individually. This is called half-closed . The HTTP specification suggests that when the client and server suddenly need to close the connection, should be normally closed , but it does not say how to do it.

For an in-depth study of some TCP closure issues, you can read another article by TCP basics

In addition, I own six PDFs, which have been disseminated over 10w+ throughout the Internet. After searching for "programmer cxuan" on WeChat and following the

Receive six PDFs for free


程序员cxuan
4.7k 声望17k 粉丝