Performance optimization (1) - request response optimization

1. Request and response optimization

Purpose: Faster content arrival time.

1. Reduce DNS lookup: Each host name resolution requires a network round trip, which increases the delay time of the request and blocks subsequent requests.

  • Reuse TCP connections: Use persistent connections whenever possible to eliminate delays caused by TCP handshakes and slow starts.
    3. Reduce HTTP redirection: HTTP redirection requires additional DNS queries, TCP handshakes, etc., which are very time-consuming, and the optimal number of redirections is 0.
  • Compressed resources for transmission: such as Gzip, image compression.
  • Use cache: such as HTTP cache, CDN cache, Service Worker cache.
  • Use CDN (Content Distribution Network): Putting data closer to the user's geographical location can significantly reduce the network delay of each TCP connection and increase throughput.
  • Delete unnecessary requested resources.
    8. Cache resources on the client side: cache necessary application resources to avoid repeated requests for the same content every time. For example, multiple image downloads can consider using cache. 9.
    Compress content before transmission: compress application resources before transmitting data. Minimize the bytes to be transferred, and make sure to use the best compression method for each different resource when compressing.
    10. Eliminate unnecessary request overhead: reduce the HTTP header data of the request (such as HTTP COookie)
    11. Process requests and responses in parallel: queuing requests and responses will cause delays, and you can try to process requests and responses in parallel (using multiple HTTP1 .1 Connections for parallel downloads, using HTTP pipe counting where possible)
    12. Take optimization measures for protocol versions. Upgrade to HTTP2.0.
  • Use server-side rendering as needed. This method can solve the problem of slow rendering of the first screen of the SPA application.
    14. Use pre-rendering to quickly load static pages. The extreme performance of page rendering is more suitable for static pages.

2. DNS resolution

When a browser requests a resource from a (third-party) server, that cross-origin domain name must be resolved to an IP address before the browser can make the request. This process is called DNS resolution . DNS is the basic protocol of the Internet, and its resolution speed seems to be easily overlooked by website optimizers. Most new browsers are now optimized for DNS resolution, such as DNS caching. A typical DNS resolution takes 20-120 milliseconds, and the time spent is almost negligible, but when the resources used in the website depend on multiple different domains, the time will increase exponentially, thus increasing the time spent on the website load time. For example, in some pages with many pictures, pre-resolving the domain name before initiating a picture loading request will increase the picture loading speed by at least 5%.

Generally speaking, there are two points related to DNS in front-end optimization:

  • Reduce the number of DNS requests
  • Perform DNS prefetch: DNS Prefetch

Reduce DNS lookups

The Domain Name System (DNS) maps hostnames to IP addresses, much like a phone book maps people's names to their phone numbers. When entering www.taobao.com in the browser, the DNS resolver contacted by the browser will return the IP address of the server. DNS has a cost. DNS typically takes 20-120 milliseconds to look up the IP address for a given hostname. 1 The browser cannot download anything from that hostname until the DNS lookup is complete.

Caches DNS lookups to improve performance. This caching can take place on special caching servers maintained by the user's ISP or local area network, but caching can also occur on individual users' computers.

DNS information is kept in the operating system's DNS cache ("DNS Client Service" on Microsoft Windows). Most browsers have their own cache, separate from the operating system's cache. As long as the browser keeps the DNS records in its own cache, it doesn't bother with the operating system making requests for the records.
By default, Internet Explorer caches DNS lookups for 30 minutes, as specified by the DnsCacheTimeout registry setting. Firefox caches DNS lookups for 1 minute under the control of the network.dnsCalcheExpiration configuration setting. Chrome is also 1 minute.

When the client's DNS cache is empty (for browsers and operating systems), the number of DNS lookups is equal to the number of unique hostnames in the web page. This includes hostnames used in page URLs, images, script files, style sheets, Flash objects, etc. Reducing the number of unique hostnames will reduce the number of DNS lookups.

Reducing the number of domains has the potential to reduce the number of parallel downloads in a page. Avoiding DNS lookups reduces response time, but reducing parallel downloads may increase response time. My guideline is to divide these resources into at least two but no more than four domain names. This will be a good compromise between reducing DNS lookups and allowing highly parallel downloads.

dns-prefetch

DNS-prefetch (DNS prefetch) is an attempt to resolve a domain name before requesting a resource. This could be a file to be loaded later, or it could be the target of a link the user is trying to open. Domain name resolution and content loading are serial network operations, so this method can reduce user waiting time and improve user experience.
dns-prefetch helps developers mask DNS resolution delays. The HTML element provides this functionality through the value of the rel attribute of dns-prefetch. Then refer to the domain name to be cross-domain in the hrlef attribute:

<link rel="dns-prefetch" href="https://fonts.googleapis.com/">

For example, this is Taobao's use of dns-prefetch:
insert image description here

dns-prefetch (and other resource hints) can also be specified as HTTP headers by using the HTTP Link field:

Link: <https://fonts.gstatic.com/>; rel=dns-prefetch

Whenever a site refers to a resource on a cross-origin domain, you should place the dns-prefetch hint in the element, but there are a few caveats to keep in mind.
(1) dns-prefetch is only effective for DNS lookups on cross-origin domains, so avoid using it to point to your site or domain. This is because, by the time the browser sees the prompt, the IP behind your site domain has already been resolved.
(2) dns-prefetch should be used with caution. Repeated DNS pre-analysis on multiple pages will increase the number of repeated DNS queries.
(3) By default, the browser will prefetch the domain name on the page that is not in the same domain as the current domain name (the domain name that is browsing the webpage), and cache the result, which is the implicit DNSPrefetch. If you want to prefetch domains that do not appear on the page, you must use Display DNS Prefetch.
(4) Although the use of DNS Prefetch can speed up the parsing speed of the page, it cannot be abused, because some developers pointed out that disabling DNS prefetch can save 10 billion DNS queries per month.


<meta http-equiv="x-dns-prefetch-control" content="off">

More DNS resolution optimization

  1. Extend DNS cache time
  2. Use A or AAAA records instead of CNAMEs whenever possible
  3. Use CDN to accelerate domain names
  4. Build your own DNS service

Attachment: clear DNS cache

1. Clear browser DNS cache
Clear DNS cache: chrome://net-internals/#dns
Sometimes you also need to clear socket cache pool at the same time: chrome://net-internals/#sockets
2. Clear system DNS cache

#在Windows中查看DNS缓存记录
ipconfig /displaydns

#在Windows中清除DNS缓存记录
ipconfig /flushdns

#在macOS中清除DNS缓存记录
sudo killall -HUP mDNSResponder

3. HTTP long connection

short connection

In the initial version of the HTTP protocol, a TCP connection was disconnected for every HTTP communication.
insert image description here
In the case of early communication, because they were all text transmissions with small capacity, even this was not a big problem. However, with the widespread popularity of HTTP, there are more cases where documents contain a large amount of rich text (pictures, videos and other resources).

For example, when using a browser to browse an HTML page containing multiple pictures, while sending a request to access the HTML page resource, it will also request other resources contained in the HTML page. Therefore, each request will cause unnecessary TCP connection establishment and disconnection, increasing the overhead of the address book.
insert image description here
To solve this problem, some browsers use a non-standard Connection field when requesting.

Connection: keep-alive

This field requires the server not to close the TCP connection so that other requests can be reused. The server also responds to this field.

Connection: keep-alive

A reusable TCP connection is established until the client or server actively closes the connection. However, this is not a standard field, and different implementations may behave inconsistently, so it is not a fundamental solution.

Long connection

In January 1997, the HTTP/1.1 version was released, only half a year later than the 1.0 version. It further improved the HTTP protocol and is still the most popular version until now.

The biggest change in HTTP version 1.1 is the introduction of persistent connections (HTTP Persistent Connections), that is, TCP connections are not closed by default and can be reused by multiple requests without declaring Connection: keep-alive.

insert image description here
The advantage of persistent connection is that it reduces the overhead caused by repeated establishment and disconnection of TCP connections, and reduces the load on the server side. In addition, reducing the time spent on overhead enables HTTP requests and responses to end earlier, so that the display speed of Web pages is correspondingly improved.

When the client and server find that the other party has not been active for a period of time, they can actively close the connection. Connection: closeHowever, the normative approach is that the client explicitly asks the server to close the TCP connection when it sends the last request .

Currently, for the same domain name, most browsers allow 6 persistent connections to be established at the same time.

pipeline mechanism

HTTP version 1.1 also introduces the pipeline mechanism (pipelining), that is, in the same TCP connection, the client can send multiple requests at the same time. This further improves the efficiency of the HTTP protocol.

In the past, after sending a request, it was necessary to wait and receive a response before sending the next request. With the emergence of pipeline technology, the next request can be sent directly without waiting for a response. In this way, multiple requests can be sent in parallel at the same time without waiting for a response one by one. Compared with connecting one by one, using a persistent connection can make the request end faster. Pipelining, on the other hand, is faster than persistent connections. The more requests, the more obvious the time difference.

insert image description here
For example, a client needs to request two resources. The previous practice was to send A request first in the same TCP connection, then wait for the server to respond, and then send B request after receiving it. The pipeline mechanism allows the browser to send A request and B request at the same time, but the server still responds to the A request in order, and then responds to the B request after completion.

Content-Length field

A TCP connection can now transmit multiple responses, and there must be a mechanism to distinguish which response the data packet belongs to. This is the role of Content-lengththe field , which declares the data length of this response.

Content-Length: 3495

The above code tells the browser that the length of this response is 3495 bytes, and the following bytes belong to the next response.

In version 1.0, the Content-Length field is not required, because the browser finds that the server has closed the TCP connection, which means that the received data packet is complete.

chunked transfer encoding

The prerequisite for using the Content-Length field is that the server must know the data length of the response before sending the response.

For some time-consuming dynamic operations, this means that the server cannot send data until all operations are completed, which is obviously not efficient. A better processing method is to send a piece of data when a piece of data is generated, and use the "stream mode" (stream) instead of the "buffer mode".
Therefore, version 1.1 stipulates that the Content-Length field may not be used, but "chunked transfer encoding" (chunked transfer encoding). Whenever a request or response header has a Transfer-Encoding field, it indicates that the response will consist of an unspecified number of chunks.

Transfer-Encoding: chunked

Before each non-empty data block, there will be a hexadecimal value indicating the length of this block. Finally, there is a block with a size of 0, which means that the data of this response has been sent. Below is an example.
insert image description here

Disadvantages of long connection

Although HTTP version 1.1 allows multiplexing of TCP connections, within the same TCP connection, all data communications are performed sequentially. The server will not proceed to the next response until it has processed one response. If the previous response is particularly slow, there will be many requests waiting in line later. This is called "head-of-line blocking".

To avoid this problem, there are only two ways:

  • One is to reduce the number of requests
  • The second is to open multiple persistent connections at the same time

This has led to a lot of web optimization tricks like merging scripts and stylesheets, embedding images in CSS code, domain sharding, and more. This extra work could have been avoided if the HTTP protocol had been better designed.

4. HTTP2

In 2009, Google released its self-developed SPDY protocol, mainly to solve the problem of low efficiency of HTTP/1.1.
After this protocol proved feasible on the Chrome browser, it was regarded as the basis of HTTP/2, and the main features were inherited in HTTP/2.
In
2015, HTTP/2 was released. It is not called HTTP/2.0 because the standard committee does not plan to release sub-versions anymore, and the next new version will be HTTP/3

binary protocol

The header information of HTTP/1.1 version must be text (ASCI encoding), and the data body can be text or binary. HTTP/2 is a complete binary protocol, header information and data body are binary, and collectively referred to as "frame" (frame): header information frame and data frame.
One benefit of the binary protocol is that additional frames can be defined. HTTP/2 defines nearly ten kinds of frames, laying the foundation for future advanced applications. If you use text to implement this function, parsing data will become very troublesome, and binary parsing is much more convenient.

multitasking

HTTP/2 multiplexes TCP connections. In one connection, both the client and the browser can send multiple requests or responses at the same time, and there is no need for one-to-one correspondence in order, thus avoiding "queue blockage".
For example, in a TCP connection, the server receives the A request and the B request at the same time, so it responds to the A request first, and finds that the processing process is very time-consuming, so it sends the processed part of the A request, and then responds to the B request, When complete, send A to request the rest.
Such two-way, real-time communication is called multiplexing.
Here's an online example comparing HTTP1 and HTTP2 resource loading: https://http2.akamai.com/demo .

data flow

Because HTTP/2 data packets are sent out of order, consecutive data packets in the same connection may belong to different responses. Therefore, the packet must be marked to indicate which response it belongs to.
HTTP/2 refers to all data packets of each request or response as a data stream (stream). Each data stream has a unique number. When a data packet is sent, the data flow ID must be marked to distinguish which data flow it belongs to. In addition, it is also stipulated that the ID of the data stream sent by the client is all odd, and the ID sent by the server is even.
When the data stream is sent halfway, both the client and the server can send a signal (RST_STREAM frame) to cancel the data stream. The only way to cancel the data flow in version 1.1 is to close the TCP connection. That is to say, HTTP/2 can cancel a certain request, while ensuring that the TCP connection is still open and can be used by other requests.
Clients can also specify the priority of data streams. The higher the priority, the sooner the server will respond.

header compression

The HTTP protocol has no state, and all information must be attached to each request. Therefore, many fields of the request are repeated, such as Cookie and User Agent, the exact same content must be attached to each request, which will waste a lot of bandwidth and affect the speed.
HTTP/2 optimizes this and introduces a header compression mechanism (header compression). On the one hand, the header information is compressed with gzip or compress before sending; on the other hand, the client and the server maintain a header information table at the same time, and all fields will be stored in this table to generate an index number, and the same fields will not be sent in the future , only the index number is sent, which improves the speed.

server push

HTTP/2 allows the server to actively send resources to the client without request, which is called server push.
A common scenario is that the client requests a web page, which contains many static resources. Under normal circumstances, the client must parse the HTML source code after receiving the webpage, find static resources, and then send a static resource request. In fact, the server can expect that after the client requests a webpage, it is likely to request static resources again, so it actively sends these static resources to the client along with the webpage.
Reference link:
https://developers.google.com/web/fundamentals/performance/http2?hl=zh-cn

5. Data resources for compressed transmission

Data compression is an important means to improve the performance of Web sites. For some files, compression ratios as high as 70% can greatly reduce bandwidth requirements. Over time, compression algorithms have become more efficient, and new compression algorithms have been invented and applied on both client and server sides.

HTTP response data compression

Compress JS, Css
The compression mentioned here refers to the compression such as removing newline spaces, and the file content remains unchanged.

Compress text with Gzip

An active negotiation mechanism is used between the browser and the server. The browser sends the Accept-Encoding header, which contains the compression algorithms it supports and their respective priorities, and the server chooses one of them, uses this algorithm to compress the response message body, and sends the Content-Encoding header to notify Which algorithm the browser chooses. Since the content negotiation process selects the presentation form of the resource based on the encoding type, in the response, the Vary header must include at least Accept-Encoding; in this way, the cache server can cache different presentation forms of the resource.
The following is an example of an HTTP message for a request response:
insert image description here

header data compression

The HTTP protocol has no state, and all information must be attached to each request. Therefore, many fields of the request are repeated, such as Cookie and User Agent, the exact same content must be attached to each request, which will waste a lot of bandwidth and affect the speed.
HTTP/2 optimizes this and introduces a header compression mechanism (header compression). On the one hand, the header information is compressed with gzip or compress before sending; on the other hand, the client and server maintain a header information table at the same time, and all fields will be stored in this table to generate an index number, and the same fields will not be sent in the future , only the index number is sent, which improves the speed.

Request Body Data Compression

Earlier we introduced the Accept-Encoding/Content-Encoding mechanism in the HTTP protocol. This mechanism can be well used for the compression of the text response body, which can greatly reduce network transmission, so it has been widely used. However, the initiator of the HTTP request (such as a browser) cannot know in advance whether the server to be accessed supports decompression, so browsers at this stage do not compress the request body.
Some communication protocols have been extended based on HTTP. Their clients and servers are dedicated, and they can compress the request body safely and boldly. This is the case with WebDAV clients, for example.
In actual web projects, there will be scenarios where the request body is very large, such as publishing a long blog, reporting network data for debugging, and so on. If these data can be compressed locally and then submitted,
it can save network traffic and reduce transmission time. This article describes how to compress the HTTP request body, including how to decompress it on the server side and how to compress it on the client side.
Before we start, let's introduce the three data compression formats covered in this article:
DEFLATE, which is a compression format that uses the Lempel-Ziv compression algorithm (LZ77) and Huffman coding. See RFC 1951 for details;
ZLIB, a compression format using DEFLATE, corresponds to Content-Encoding: deflate in HTTP. See RFC 1950 for details;
GZIP is also a compression format using DEFLATE, corresponding to Content-Encoding in HTTP: gzip. See RFC 1952 for details;

The deflate in Content-Encoding is actually ZLIB. For clarity, this article refers to DEFLATE as RAW DEFLATE, and ZLIB and GZIP are different Wrappers of RAW DEFLATE.

Below is a simple example.
(1) Compress request body data

insert image description here
(2) Decompress the data in the request body in Node.
insert image description here
The actual use also needs to match the specific server, such as nginx, Apache, etc.

6. Mandatory caching

For mandatory caching, if the browser judges that the requested target resource is effectively hit, it can directly return the request response from the mandatory cache without any communication with the server.

Before introducing the mandatory cache hit judgment, let’s first look at part of the response header information:
insert image description here
the two fields related to mandatory caching are expires and cache-control, and expires is declared in the HTTP 1.0 protocol to control the cache expiration date The timestamp field is specified by the server and notified to the browser through the response header, and the browser caches it after receiving the response body with this field.
If the browser initiates the same resource request again later, it will compare expires with the current local timestamp. If the local timestamp of the current request is less than the value of expires, it means that the response cached by the browser has not expired and can be used directly without Send the request to the server again. Only when the cache expires when the local timestamp is greater than the expires value, the request is allowed to be re-initiated to the server.
It is not difficult to see from the above judging mechanism of whether the mandatory cache expires, there is a big loophole in this method, that is, it relies too much on the local timestamp. If the local time of the client is not synchronized with the time of the server, or the client time is updated Active modification, then the judgment of cache expiration may not be in line with expectations.
In order to solve the limitation of expires judgment, a new cache-control field has been added from the HTTP 1.1 protocol to extend and improve the function of expires. It can be seen from the above code that cache-control sets the attribute value of maxage=31536000 to control the validity period of the response resource. It is a time length in seconds, indicating that the resource is valid within 31536000 seconds after being requested, so that It can avoid problems caused by out-of-sync timestamps on the server side and client side. In addition, cache-control can also configure some other attribute values ​​to more accurately control the cache, as described below.

no-cache and no-store

Setting no-cache does not mean not to use the cache literally, but to force a negotiated cache (which will be discussed later), that is, for each request initiated, it will not judge whether the mandatory cache expires, but directly communicate with the server Negotiate to verify the validity of the cache. If the cache has not expired, the local cache will be used. Setting no-store means that any caching strategy is prohibited, and each request from the client requires a new response from the server. no-cache and no-store are two mutually exclusive attribute values ​​and cannot be set at the same time.
Send the following response headers to disable caching.

Cache-Control: no-store

Specifying no-cache or max-age=0 means that the client can cache resources, and must re-verify the validity of the cached resources before each use. This means that an HTTP request will be made every time, but the download of the HTTP response body can be skipped when the cached content is still valid.

Cache-Control: max-age=0
Cache-Control: no-store

ETag-based negotiation cache

In order to make up for the lack of judging by timestamp, a new ETag header has been added from the HTTP 1.1 specification, that is, the entity tag (Entity Tag)
whose content is mainly a string generated by the server for different resources. Strings are similar to file fingerprints. As long as there are differences in file content encoding, the corresponding ETag tag values ​​will be different. Therefore, ETag can be used for more accurate change perception of file resources. Let's take a look at an example of using ETag to negotiate and cache image resources. The key information of some response headers after the first request is as follows:

code example

const http = require('http')
const fs = require('fs')
const url = require('url')
const etag = require('etag')

http.createServer((req, res) => {
    
    
  console.log(req.method, req.url)

  const {
    
     pathname } = url.parse(req.url)
  if (pathname === '/') {
    
    
    const data = fs.readFileSync('./index.html')
    res.end(data)
  } else if (pathname === '/img/01.jpg') {
    
    
    const data = fs.readFileSync('./img/01.jpg')
    res.writeHead(200, {
    
    
      Expires: new Date('2021-4-30 12:19:57').toUTCString()
    })
    res.end(data)
  } else if (pathname === '/img/02.jpg') {
    
    
    const data = fs.readFileSync('./img/02.jpg')
    res.writeHead(200, {
    
    
      'Cache-Control': 'max-age=5' // 滑动时间,单位是秒
    })
    res.end(data)
  } else if (pathname === '/img/03.jpg') {
    
     // 协商缓存
    const {
    
     mtime } = fs.statSync('./img/03.jpg')

    const ifModifiedSince = req.headers['if-modified-since']

    if (ifModifiedSince === mtime.toUTCString()) {
    
    
      // 缓存生效
      res.statusCode = 304
      res.end()
      return
    }

    const data = fs.readFileSync('./img/03.jpg')

    res.setHeader('last-modified', mtime.toUTCString())
    res.setHeader('Cache-Control', 'no-cache')
    res.end(data)
  } else if (pathname === '/img/04.jpg') {
    
     // 基于 ETag 的协商缓存
    const data = fs.readFileSync('./img/04.jpg')
    const etagContent = etag(data)

    const ifNoneMatch = req.headers['if-none-match']

    if (ifNoneMatch === etagContent) {
    
    
      res.statusCode = 304
      res.end()
      return
    }

    res.setHeader('etag', etagContent)
    res.setHeader('Cache-Control', 'no-cache')
    res.end(data)
  } else {
    
    
    res.statusCode = 404
    res.end()
  }
}).listen(3000, () => {
    
    
  console.log('http://localhost:3000')
})

Cache Decision Example

The HTML file contains a JavaScript file script.js, a style sheet file style.css, and a picture file photo.jpg. To display the content in the HTML, it is necessary to load all the external link files it contains. Accordingly, we can make the following settings for them.
First of all, HTML here belongs to the main file that contains other files. In order to ensure that its content can be updated in time when its content is modified, it should be set as a negotiation cache, that is, add no-cache attribute value to the cache-control field; secondly, image files, Because the modification of pictures on the website is basically replacement and modification, and considering that the number and size of picture files may cause a lot of overhead on the client's cache space, forced caching can be used and the expiration time should not be too long, so you can set cache- The value of the control field is max-age=86400.
The next thing to consider is the style sheet file style.css. Since it is a text file, there may be occasional modification of the content, and you want to use mandatory caching to improve reuse efficiency, so you can consider adding file fingerprints to the naming of the style sheet file or the version number (for example, the file name of the style sheet after adding the file fingerprint becomes style.51ad84f7.css ), so that when the file is modified, different files will have different file fingerprints, that is, the URL of the file to be requested is different. So re-requests for resources are bound to occur. At the same time, considering the caching of intermediate agents such as browsers and CDNs in the network, the expiration time can be appropriately extended to one year, that is, cache-control: max-age=31536000.
The last is the JavaScript script file, which can be similar to the setting of the style sheet file, taking the file fingerprint and a long expiration time. If the JavaScript contains the user's private information and does not want the intermediate proxy to cache it, you can add private to the cache-control attribute value.
From the example of this caching strategy, we can see that combining mandatory caching, negotiating caching, and file fingerprints or version numbers for different resources can achieve multiple goals: timely modification and update, longer cache expiration time, and control capabilities Where to cache.

Seven, CDN cache

The full name of CDN is Content Delivery Network, that is, content distribution network. It is a virtual intelligent network built on the basis of existing networks. It relies on edge servers deployed in various places, and through functional modules such as load balancing, scheduling, and content distribution of the central platform, it enables users to When you request the content you need to access, you can get it nearby, so as to reduce network congestion and improve the response speed of resources to users.

Recall that when I first learned about computer networks, the common B/S model is that the browser directly requests the required resources from the server, but the actual networking situation is not so simple. Because usually for popular sites, the number of users who initiate resource requests at the same time is often very large, and if these requests are all sent to the same server, it is very likely to cause access congestion. Therefore, it is more reasonable to cache some data on the edge server closer to the user. This will not only increase the speed of requesting resources, but also effectively reduce the egress bandwidth pressure of the root node of the website. This is the core of CDN technology. The basic idea.

insert image description here
insert image description here
insert image description here
From the requested domain names of the above resource files, we can find that these files are all obtained from the CDN network. Text files such as JavaScript and style sheets and image files use different CDN domain names, and the CDN domain name and the main website domain name are also different. Completely different, this design is also out of performance considerations.

Guess you like

Origin blog.csdn.net/woyebuzhidao321/article/details/129326871