Building a specification REST API with ASP. NET Core 2.1--Caching and concurrency

Source: Internet
Author: User
Tags rfc browser cache
https://www.cnblogs.com/cgzl/p/9165388.html

 

Some preliminary knowledge required for this article can be found here: http://www.cnblogs.com/cgzl/p/9010978.html and http://www.cnblogs.com/cgzl/p/9019314.html

Establish Richardson's RESTful API for POST, GET, PUT, PATCH, and DELETE at level 2 /cgzl/p/9080960.html and https://www.cnblogs.com/cgzl/p/9117448.html

HATEOAS: https://www.cnblogs.com/cgzl/p/9153749.html.

This article introduces caching and concurrency, you can understand without reading the previous article.

The practice code required for this article (right-click and save it, the suffix is changed to zip): https://images2018.cnblogs.com/blog/986268/201806/986268-20180611132306164-388387828.jpg

Caching
According to REST constraints: "Each response should define whether it can be cached by itself." This article will introduce how to ensure that the HTTP response can be cached. The knowledge of HTTP caching is used here. HTTP caching is part of the HTTP standard (RFC 2616, RFC 7234).

"Unless performance can be greatly improved, caching is useless. The goal of caching in HTTP / 1.1 is to avoid sending requests in many scenarios and to avoid returning complete responses in other cases."

To avoid sending requests, the cache uses an expiration mechanism.

To avoid the need to return a complete response, the cache uses a verification mechanism.

 

What is caching?

The cache is a separate component that exists between the API and the API consumer.

The cache receives requests from API consumers and sends the requests to the API;

The cache also receives the response from the API and saves the response if it is cacheable, and returns the response to the API consumer. If the same request is sent again, the cache may return the saved response to the API consumer.

The cache can be seen as a middleman of the request-response communication mechanism.

There are three kinds of caches in HTTP:

Client-side cache / browser cache, which exists on the client and is private (because it is not shared with other clients).
Gateway cache, which is a shared cache, is located on the server side, and all API consumer clients will share this cache. It also has aliases for reverse proxy server caching, HTTP accelerators, etc.
Proxy cache, which is located on the network and shared, it is neither located on the API consumer client nor on the API server, it is located elsewhere on the network. This cache is often used by large enterprises or ISPs to serve large-scale users. (This is not introduced, I will not)
 

Expired model
The expiration model allows the server to declare the requested resource, that is, how long the response information can be kept "fresh". The cache can store this response, so subsequent requests can be responded by the cache, as long as the cache is "fresh". For this purpose, two Response Headers are used:

Expires Header, which contains an HTTP date that describes when the response will expire, for example: Expires: Mon, 11 Jun 2018 13:55:41 GMT. However, it may have some synchronization problems, so the cache and server time are required to be consistent. It has limited control over the type, time, and place of the response, because these things are controlled and limited by the cache-control header.

Cache-Control Header, such as Cache-Control: public, max-age = 60, this header contains two instructions public and max-age. max-age indicates that the response can be cached for 60 seconds, so clock synchronization is not a problem; public means that it can be cached by shared and private caches. So the server can decide whether the response is allowed to be cached by the gateway cache or proxy cache. For expired models, the cache-control header is preferred. There are many other instructions of Cache-Control. Common ones can be viewed on the ASP.NET Core official website: https://docs.microsoft.com/en-us/aspnet/core/performance/caching/response?view= aspnetcore-2.1 # http-based-response-caching

 

The expiration model works, see the following example:

The cache here can be private or shared.

The client program sends a request for GET countries. At this time, there is no cached version of the response, so the cache will continue to send the request to the API server. Then the API returns a response to the cache. The response contains the Cache-Control header. The response will stay "fresh" (or called valid) for half an hour. Finally, the cache returns the response to the client, but at the same time the cache copies a response and saves it.

Then, for example, after 10 minutes, the client sends the same request:

At this time, the response in the cache is still within the validity period. The cache will directly return this response. The response contains an age header. For this example (10 minutes), the value of age is 600 (seconds).

In this case, the request to the API server is avoided, and the cache will only access the back-end API server if the cache expires (or is called stale).

 

If the cache is private, such as in the localstorage of a web application, or on a mobile device, the request stops here.

This is not the case if the cache is shared, such as on the server.

For example, after 10 minutes, another client sends the same request. This request must come to the cache first. If the cache has not expired, the cache will directly return the response to the client. This time, the value of the age header is 1200 ( Seconds), 20 minutes:

In general, private caches will reduce the need for network bandwidth, and will also reduce requests from the cache to the API.

The shared cache does not save the network bandwidth of the cache to the API, but it greatly reduces the requests to the API. For example, at the same time 10,000 clients sent the same request to the API, the first request that came will come to the API program, and other same requests would only come to the cache, which also means that the amount of code execution will be greatly reduced, access The number of databases will also be greatly reduced, and so on.

So a combination of private and shared caches (client-side cache and public / gateway cache) is good. However, this cache is more suitable for relatively static resources, such as samples and content webpages; and it is not suitable for APIs whose data changes frequently. If the API adds a piece of data, the cached data is incorrect for these 10,000 clients. For this example, incorrect data may be returned for half an hour. At this time, a verification model is needed.

 

Validation model
The validation model is used to verify that the cached response data is up to date.

In this case, when the cached data is going to be a response to a client request, it first checks the source server or an intermediate cache with the latest data to see if the data it caches is still up to date. The validator is used here.

Validator
There are two types of validators: strong validators and weak validators.

Strong Validator: If the body or header of the response changes, the strong validator will change. A typical example is the ETag (Entity Tag) response header, for example: ETag: "12345678". ETag is an opaque identifier issued by a web server or API. It represents a specific version of a resource. Strong validators can be used in any context with a cache, and they can be used to check concurrency when updating resources.

Weak Validator: When the response changes, the weak validator usually does not necessarily change. It is up to the server to determine when to change. The usual practice is to "change only when important changes occur." A typical example is the Last-Modified header. For example: Mon, 11 Jun 2018 13:55:41 GMT, which contains the last modified time of the resource. This is a bit weak, because it is accurate to the second. , Because it is possible to update resources more than twice in a second. But even for weak validators, the clock must be synchronized, so it has the same problem as the expires header, so ETag is a better choice.

There is also a weak ETag, which starts with w /. For example, ETag: "w / 123456789", it is treated as a weak validator, but its degree is still determined by the server. When ETag is in this format, if the response changes, it does not necessarily change.

Weak validators can only be used if they are allowed to be equivalent (roughly equal), but they cannot be used if they require exact equality.

The HTTP standard suggests that it is best to send both ETag and Last-Modified headers if possible.

 

Let's see how it works. When the client made the first request, when the request reached the cache, it found that there was no cache, and the cache sent the request to the API. The API returned a response. This response contained two headers, ETag and Last-Modified. The cache sends it to the client, while the cache holds a copy of the response.

After 10 minutes, the client sends the same request again, and the request comes to the cache, but the cached response cannot be guaranteed to be "fresh". In this example, the Cache-Control Header is not used, so the cache must go to the server API Check it out. At this time, it will add two headers: If-None-Match, which is set to the ETag value of the cached response data; If-Modified-Since, which is set to the Last-Modified value of the cached response data. Now the request is based on the situation. The server receives the request and compares these headers or generates a response based on the witness.

If the check is successful, the server does not need to generate a response, it will return 304 Not Modified, and the cache will return the cached response. This response also contains a latest Last-Modified Header (if Last-Modifed is supported);

If the resource of the response changes, the API will generate a new response.

If it is a private cache, the request will stop here.

But if it is a shared cache, if another client sends a request after 10 minutes, this request will also reach the cache, and then follow the same process as above:

 

In general, the same response is only generated once.

Compare:

Private cache: subsequent requests will save network bandwidth, we need to communicate with the API, but the API does not need to return the complete response, if the resource has not changed, only 304 can be returned.

Shared cache: It will save the bandwidth between the cache and the API. If the verification is passed, the API does not need to regenerate the response and then resend it.

 

Out-of-date and validation models are often used in combination.

Combining outdated and validated models
This can be done:

If a private cache is used, as long as the response does not expire, the response will be returned directly from the private cache. The advantage of this is that it reduces the communication with the API, it also reduces the work of the API to generate the response, and reduces the bandwidth requirements. And if the private cache expires, it will still access the API. If there is only expiration (model) checking, this means that if the API expires, the response must be regenerated. But we might avoid this if we use validation (model) checks. Because the cached response expires, it does not mean that the cached response is not valid. The API will check the validator, and if the response is still valid, it will return 304. In this way, the network bandwidth and response generation actions may be greatly reduced.

If it is a shared cache, the cached response will always be returned as long as it has not expired. This will not save the network bandwidth between the client and the cache, but will save the network bandwidth between the cache and the API, and also greatly reduce it. The number of requests to the API is larger than the private cache, because the shared cache is shared with all clients. If the cached response expires, the cache must communicate with the API, but this does not necessarily mean that the response must be regenerated. If the verification is successful, it will return 304 with no response body. This may reduce the network bandwidth requirements between the cache and the API. The response is still returned from the cache to the client.

So in summary, it is best practice to have a private cache on the client side and a shared cache on the server level.

 

Cache-Control directive
First look at the common Cache-Control directives:

Freshness: 
max-age defines the lifetime of the response, beyond this value, the cached response expires, and its unit is seconds.
s-maxage will override the max-age value for the shared cache. So the expiration time of the response may be different between the private cache and the shared cache.
Storage locationhttps://www.cnblogs.com/cgzl/p/9165388.html

 

Some preliminary knowledge required for this article can be found here: http://www.cnblogs.com/cgzl/p/9010978.html and http://www.cnblogs.com/cgzl/p/9019314.html

Establish Richardson's RESTful API for POST, GET, PUT, PATCH, and DELETE at level 2 /cgzl/p/9080960.html and https://www.cnblogs.com/cgzl/p/9117448.html

HATEOAS: https://www.cnblogs.com/cgzl/p/9153749.html.

This article introduces caching and concurrency, you can understand without reading the previous article.

The practice code required for this article (right-click and save it, the suffix is changed to zip): https://images2018.cnblogs.com/blog/986268/201806/986268-20180611132306164-388387828.jpg

Caching
According to REST constraints: "Each response should define whether it can be cached by itself." This article will introduce how to ensure that the HTTP response can be cached. The knowledge of HTTP caching is used here. HTTP caching is part of the HTTP standard (RFC 2616, RFC 7234).

"Unless performance can be greatly improved, caching is useless. The goal of caching in HTTP / 1.1 is to avoid sending requests in many scenarios and to avoid returning complete responses in other cases."

To avoid sending requests, the cache uses an expiration mechanism.

To avoid the need to return a complete response, the cache uses a verification mechanism.

 

What is caching?

The cache is a separate component that exists between the API and the API consumer.

The cache receives requests from API consumers and sends the requests to the API;

The cache also receives the response from the API and saves the response if it is cacheable, and returns the response to the API consumer. If the same request is sent again, the cache may return the saved response to the API consumer.

The cache can be seen as a middleman of the request-response communication mechanism.

There are three kinds of caches in HTTP:

Client-side cache / browser cache, which exists on the client and is private (because it is not shared with other clients).
Gateway cache, which is a shared cache, is located on the server side, and all API consumer clients will share this cache. It also has aliases for reverse proxy server caching, HTTP accelerators, etc.
Proxy cache, which is located on the network and shared, it is neither located on the API consumer client nor on the API server, it is located elsewhere on the network. This cache is often used by large enterprises or ISPs to serve large-scale users. (This is not introduced, I will not)
 

Expired model
The expiration model allows the server to declare the requested resource, that is, how long the response information can be kept "fresh". The cache can store this response, so subsequent requests can be responded by the cache, as long as the cache is "fresh". For this purpose, two Response Headers are used:

Expires Header, which contains an HTTP date that describes when the response will expire, for example: Expires: Mon, 11 Jun 2018 13:55:41 GMT. However, it may have some synchronization problems, so the cache and server time are required to be consistent. It has limited control over the type, time, and place of the response, because these things are controlled and limited by the cache-control header.

Cache-Control Header, such as Cache-Control: public, max-age = 60, this header contains two instructions public and max-age. max-age indicates that the response can be cached for 60 seconds, so clock synchronization is not a problem; public means that it can be cached by shared and private caches. So the server can decide whether the response is allowed to be cached by the gateway cache or proxy cache. For expired models, the cache-control header is preferred. There are many other instructions of Cache-Control. Common ones can be viewed on the ASP.NET Core official website: https://docs.microsoft.com/en-us/aspnet/core/performance/caching/response?view= aspnetcore-2.1 # http-based-response-caching

 

The expiration model works, see the following example:

The cache here can be private or shared.

The client program sends a request for GET countries. At this time, there is no cached version of the response, so the cache will continue to send the request to the API server. Then the API returns a response to the cache. The response contains the Cache-Control header. The response will stay "fresh" (or called valid) for half an hour. Finally, the cache returns the response to the client, but at the same time the cache copies a response and saves it.

Then, for example, after 10 minutes, the client sends the same request:

At this time, the response in the cache is still within the validity period. The cache will directly return this response. The response contains an age header. For this example (10 minutes), the value of age is 600 (seconds).

In this case, the request to the API server is avoided, and the cache will only access the back-end API server if the cache expires (or is called stale).

 

If the cache is private, such as in the localstorage of a web application, or on a mobile device, the request stops here.

This is not the case if the cache is shared, such as on the server.

For example, after 10 minutes, another client sends the same request. This request must come to the cache first. If the cache has not expired, the cache will directly return the response to the client. This time, the value of the age header is 1200 ( Seconds), 20 minutes:

In general, private caches will reduce the need for network bandwidth, and will also reduce requests from the cache to the API.

The shared cache does not save the network bandwidth of the cache to the API, but it greatly reduces the requests to the API. For example, at the same time 10,000 clients sent the same request to the API, the first request that came will come to the API program, and other same requests would only come to the cache, which also means that the amount of code execution will be greatly reduced, access The number of databases will also be greatly reduced, and so on.

So a combination of private and shared caches (client-side cache and public / gateway cache) is good. However, this cache is more suitable for relatively static resources, such as samples and content webpages; and it is not suitable for APIs whose data changes frequently. If the API adds a piece of data, the cached data is incorrect for these 10,000 clients. For this example, incorrect data may be returned for half an hour. At this time, a verification model is needed.

 

Validation model
The validation model is used to verify that the cached response data is up to date.

In this case, when the cached data is going to be a response to a client request, it first checks the source server or an intermediate cache with the latest data to see if the data it caches is still up to date. The validator is used here.

Validator
There are two types of validators: strong validators and weak validators.

Strong Validator: If the body or header of the response changes, the strong validator will change. A typical example is the ETag (Entity Tag) response header, for example: ETag: "12345678". ETag is an opaque identifier issued by a web server or API. It represents a specific version of a resource. Strong validators can be used in any context with a cache, and they can be used to check concurrency when updating resources.

Weak Validator: When the response changes, the weak validator usually does not necessarily change. It is up to the server to determine when to change. The usual practice is to "change only when important changes occur." A typical example is the Last-Modified header. For example: Mon, 11 Jun 2018 13:55:41 GMT, which contains the last modified time of the resource. This is a bit weak, because it is accurate to the second. , Because it is possible to update resources more than twice in a second. But even for weak validators, the clock must be synchronized, so it has the same problem as the expires header, so ETag is a better choice.

There is also a weak ETag, which starts with w /. For example, ETag: "w / 123456789", it is treated as a weak validator, but its degree is still determined by the server. When ETag is in this format, if the response changes, it does not necessarily change.

Weak validators can only be used if they are allowed to be equivalent (roughly equal), but they cannot be used if they require exact equality.

The HTTP standard suggests that it is best to send both ETag and Last-Modified headers if possible.

 

Let's see how it works. When the client made the first request, when the request reached the cache, it found that there was no cache, and the cache sent the request to the API. The API returned a response. This response contained two headers, ETag and Last-Modified. The cache sends it to the client, while the cache holds a copy of the response.

After 10 minutes, the client sends the same request again, and the request comes to the cache, but the cached response cannot be guaranteed to be "fresh". In this example, the Cache-Control Header is not used, so the cache must go to the server API Check it out. At this time, it will add two headers: If-None-Match, which is set to the ETag value of the cached response data; If-Modified-Since, which is set to the Last-Modified value of the cached response data. Now the request is based on the situation. The server receives the request and compares these headers or generates a response based on the witness.

If the check is successful, the server does not need to generate a response, it will return 304 Not Modified, and the cache will return the cached response. This response also contains a latest Last-Modified Header (if Last-Modifed is supported);

If the resource of the response changes, the API will generate a new response.

If it is a private cache, the request will stop here.

But if it is a shared cache, if another client sends a request after 10 minutes, this request will also reach the cache, and then follow the same process as above:

 

In general, the same response is only generated once.

Compare:

Private cache: subsequent requests will save network bandwidth, we need to communicate with the API, but the API does not need to return the complete response, if the resource has not changed, only 304 can be returned.

Shared cache: It will save the bandwidth between the cache and the API. If the verification is passed, the API does not need to regenerate the response and then resend it.

 

Out-of-date and validation models are often used in combination.

Combining outdated and validated models
This can be done:

If a private cache is used, as long as the response does not expire, the response will be returned directly from the private cache. The advantage of this is that it reduces the communication with the API, it also reduces the work of the API to generate the response, and reduces the bandwidth requirements. And if the private cache expires, it will still access the API. If there is only expiration (model) checking, this means that if the API expires, the response must be regenerated. But we might avoid this if we use validation (model) checks. Because the cached response expires, it does not mean that the cached response is not valid. The API will check the validator, and if the response is still valid, it will return 304. In this way, the network bandwidth and response generation actions may be greatly reduced.

If it is a shared cache, the cached response will always be returned as long as it has not expired. This will not save the network bandwidth between the client and the cache, but will save the network bandwidth between the cache and the API, and also greatly reduce it. The number of requests to the API is larger than the private cache, because the shared cache is shared with all clients. If the cached response expires, the cache must communicate with the API, but this does not necessarily mean that the response must be regenerated. If the verification is successful, it will return 304 with no response body. This may reduce the network bandwidth requirements between the cache and the API. The response is still returned from the cache to the client.

So in summary, it is best practice to have a private cache on the client side and a shared cache on the server level.

 

Cache-Control directive
First look at the common Cache-Control directives:

Freshness: 
max-age defines the lifetime of the response, beyond this value, the cached response expires, and its unit is seconds.
s-maxage will override the max-age value for the shared cache. So the expiration time of the response may be different between the private cache and the shared cache.
Storage location


Related Article

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.