Why cache

It is applicable to high concurrency and high performance scenarios on the Internet, providing the fastest response speed to users and reducing the cost of back-end servers

Caches are sorted by request path

The front-end cache

  • Negotiation cache (304)

Implementation is based on the if-Modified-since field in the request header and the Last Modified field in the return header, or on the if-none-match field in the request header and the ETag field in the return header. The implementation principle of the two methods is the same. The former is implemented based on time, while the latter is implemented based on a unique identifier. Comparatively, the latter can judge whether the file content is modified more accurately, avoiding the unreliable problem caused by time tampering.

Implementation process: When the browser requests to access the server resource for the first time, the server will return the resource and add the ETag unique identifier in the Response header. The value of this unique identifier is generated according to the resource currently requested. When the browser requests to access the resource in the server again, the if-none-match field is added to the Request header. The value of this field is the unique identifier of the ETag tag in the Response header. After receiving the request again, the server will compare the if-none-match value in the request with the only identifier generated by the current requested resource. If the value is equal, 304 Not Modified will be returned. If Not, a new ETag unique identifier will be added to the Response header. And returns resources; If the browser receives 304’s request response status code, it loads the resource from the local cache, otherwise it updates the resource

  • Strong cache (200 size: Memory cache)

This is implemented using Expires or cache-control, two HTTP Response headers, both of which are used to indicate the expiration date of a resource in the client Cache. Expires is an absolute time, whereas cache-control is a relative time. Cache-control is recommended for strong caching

Implementation process: When the browser requests to access the server resource for the first time, the server will return the resource at the same time, in Response header plus cache-control, cache-control set expiration time size; When the browser requests to access the resource in the server again, the browser calculates whether the resource is expired based on the request time and the expiration time set in cache-Control. If no, the browser uses the Cache. Otherwise, the browser requests the server. When the server receives the request again, it updates the cache-Control of the Response header again.

  • CDN

After the side cache

  • Nginx cache (LUA) or gateway cache
  • Process the cache

Guava Cache, Caffeine, Ehcache, JVM collection, etc

  • Distributed cache

Redis

How is the cache used in a project

  • Springboot @ CacheConfig

Query: first check cache, return, no check database, set to cache return. Modify: delete db first, then delete redis

  • Individual business use

Db, cache consistency issues, cache contention solutions discussed later

What are the ways in which caching can be used to achieve this effect

  • Paging cache (query condition when key, time control business can accept orientation)
  • Database row data cache (cache only useful columns that cannot be changed easily)
  • Business cache (special Settings for specific business, special elimination)

Most queries in the system are cached. Cold and hot data dynamic setting, obsolete. The cache hit ratio is high.

What are the consequences of improper cache use

Cache avalanche

A large amount of data in the cache reaches the expiration date, but a large amount of data is queried. As a result, the database is overloaded or even breaks down

Solution:

  • Cold and hot data are separated, and different validity periods are adopted. The expiration time of cache data is set randomly to prevent a large number of data from expiring at the same time.
  • If the cache database is deployed in a distributed manner, distribute the hotspot data evenly.
  • Set hotspot data to never expire.

The cache to penetrate

This refers to data that is not in the cache or database, and the cache does not act as a stress buffer because the user is constantly making requests

Solution:

  • Add verification at the interface layer, such as user authentication verification, id basic verification, ID <=0 direct interception;
  • If the data cannot be cached or retrieved from the database, you can write the key-value pair to key-null. The cache validity period can be shorter, for example, 30 seconds. (If the value is too long, the cache cannot be used in normal cases.) This prevents the attacker from using the same ID over and over again
  • Create a Bloom filter for the key. If there is a deletion, create a new Bloom filter
  • In the grayscale publishing mode, a small number of requests are first connected, and then the number of requests is gradually increased until all the requests are switched
  • Preheat the cache in advance or periodically

Cache breakdown

It refers to the data that is not in the cache but exists in the database (generally, the cache time expires). At this time, because there are many concurrent users, they do not read the data from the cache at the same time, and they go to the database to fetch data at the same time (SQL is slow), causing the database pressure to increase suddenly, causing excessive pressure. Instantaneous concurrent calls to the database when the cache fails

Solution:

  • Set hotspot data to never expire
  • Double -check (distributed locking can limit concurrency, so use single JVM level limit, except special scenarios)

Full amount of the cache

When dealing with very large concurrency scenarios, the number of concurrent requests is so large that even a small cache penetration can kill the database and cause an avalanche effect.

Solution:

  • In this case, we can cache the full amount of data to completely avoid cache penetration problems

Canal subscribes to the binlog asynchronous update cache

Cache concurrency contention

If multiple clients concurrently write a key, the data that should have arrived first may arrive later, resulting in incorrect data version. Or if multiple clients get a key at the same time, change the value and write it back, as long as the order is wrong, the data is wrong

  • If you operate on this key, no order is required

In this case, prepare a distributed lock, everyone to grab the lock, grab the lock to do the set operation, relatively simple.

  • If you operate on this key, order is required

Suppose there is A key1. System A needs to set key1 to valueA, system B needs to set Key1 to valueB, and system C needs to set key1 to valueC. Expected key1 values in the order of valueA–>valueB–>valueC. In this case, we need to save a timestamp when the data is written to the database. Suppose the timestamp is as follows

System A Key 1 {valueA 3:00} System B Key 1 {valueB 3:05} System C Key 1 {valueC 3:10}Copy the code

So, assuming that system B grabs the lock first, set key1 to {valueB 3:05}. Then system A grabs the lock and finds that its valueA timestamp is older than the timestamp in the cache, so the set operation is not performed. And so on.

  • Using queues, it is also possible to make the set method serial access

The cache and database double-write are inconsistent, causing data consistency problems

Cache Aside Pattern Indicates the bypass Cache

  • Read request: the cache is read first. If no match is hit, the database is read and set back to the cache
  • Write request: delete the cache first, then delete the database,

Why is it recommended to deprecate the cache and not modify it

When two concurrent writes (1 and 2) occur, because the timing cannot be guaranteed, either the cache or the database may be operated first:

  • Request 1 operates on the database and request 2 operates on the database
  • Request 2 sets the cache first, request 1 sets the cache after

As a result, data is inconsistent between the database and the cache.

Cache Aside Pattern problem

Cache Aside can also cause data inconsistencies in high concurrency scenarios. Read operation A, not hit the cache, will fetch data v1 from the database. A write operation B writes v2 to the database, invalidating the cache; Read operation A is putting V1 into the cache, which results in dirty data. Because it’s v1 in the cache, v2 in the database

Solution:

  • Thread B: read cache -> missed -> write lock > read data from DB to cache -> release lock; Thread A: write lock -> write DB -> delete cache/change cache -> release lock;
  • See how long the business can accept dirty data, and then the cache sets the expiration time.
  • Or when the database update is successful, use MQ to notify the cache refresh

  • Canal subscribes to binlog, the ultimate solution – it also solves master/slave library synchronization problems

  • Demotion or compensation schemes or bottom-of-the-line schemes

Redis basis

5.0.7 Memory, single thread, C language, IO multiplexing

Persistent mode:

RDB, AOF, mixed mode 1W times within 1 minute 10 times within 5 minutes 1 time within 15 minutesCopy the code

Elimination mechanism:

Volatile - lRU: Selects the most recent unused data from a data set with expiration time. Allkeys-lru: Select the latest and longest unused data from the dataset (including the dataset with expiration time set and the dataset without expiration time set) to release; Volatile -random: Randomly selects a data set from which the expiration time is set to release the data. Allkeys-random: Randomly select a data from the data set (including set expiration time and not set expiration time) for import and release; Volatile - TTL: To release data from a set whose expiration time is set. Noeviction: Arbitrary data will not be deleted (redis will release it based on reference counters), errors will be returned if memory is out of order. Allkeys-lru, for allkeys, delete the least recently used Key first; Volatile -lru: For keys with expiration time, the least recently used Key is deleted first. Volatile - TTL: For keys with an expiration time, delete the keys that are about to expire (based on the TTL value). Allkeys-lfu (Redis 4.0 or above), for allkeys, delete the least used Key first; Volatile - LFU (Redis 4.0 or higher) : For keys with expiration time, delete the least used keys. The value can be allkeys and volatile, and the algorithm can be LRU, TTL, and LFU. Volatile - LFU is recommendedCopy the code

What are the data types of Redis and where are they used in the project?

String counter, Token Hash circle ID uid: lastUpdateTime (last publish time) userId: name: name; Age: 13 -- User information storage, modify list user fan list, user like list, user favorite list, user concern list lrange command, Concurrent big latest 200 review paging message queue set the only permanent memory of the concern of disordered book | attention | fans are close to each other each other is to make use of the intersection, and set, difference set operations, such as common preferences can be calculated, the be fond of of all, his own preferences, and other functions zset score only, Group list | | book top ranking promotion administrator - n principle jump table stream instead of before release subscription based on the listCopy the code

Redis cluster solution

One active/standby mode, one active/multiple slave mode, sentinel mode, coDIS, Redis cluster, bypass exploration and concurrent massive Bypass exploration cluster mode is recommended

A distributed lock

Single JVM level

Compared with synchronized keyword, Lock is used more flexibly, and can add Lock timeout time, fairness and other advantages

Single redis distributed lock

Set key value EX 60 NX timeout based on service design setnx set if Not eXists 1: Obtains a lock 0: Request A, REQUEST B, and Request C compete for the lock at the same time. Request A obtains the lock first, and other requests can only try to obtain the lock continuously. The processing time of request A has timed out due to complex services. So request B is able to obtain the lock. Request A finally completes its business, and then executes DEL user_id, but his own lock is invalid. The request B is not finished yet, so there is a problem! SET user_id 10086 EX 30 NX // The service is being processed. // The service is completed. If ((GET user_id) == "XXX"){DEL user_id} if((GET User_id) == "XXX"){// After the lock is obtained, the value is determined and the value is true. At this point, the lock just failed. The other request happens to get the lock with the key of user_id. DEL user_id} to ensure atomicity of the query and delete. Lua script supports eval() to ensure atomicity of the query. Because Redis is a single thread, when an eval command executes Lua code, the Lua code is treated as a command to lock with a different key and a different value. When releasing the lock, value determines whether it is my lock or not. Release the lock in time instead of using automatic timeout. The timeout period must be weighed based on service conditions. Program exceptions should be caught and unlocked. If you need to roll back, take the initiative to roll back and compensate. Ensure overall robustness and consistency key timeout resolution: get a daemon thread to listen for the key expiration time, and then renew its life when it is about to expireCopy the code

Cluster Redis distributed lock

The command first fell to the main library. If the primary database is down and the data is not synchronized to the secondary database, sentinel will elect one of the secondary databases as the primary database. If setnx mykey hisValue is executed by another client, it will also succeed, that is, it will also get the lock. This means that at this point, there are two clients that have acquired the lock. In order to solve the defect in the failover case, Antirez invented the Redlock algorithm. To use the Redlock algorithm, multiple instances of Redis are required. It will send the setex mykey myValue command to the majority of the nodes, and if the majority of the nodes succeed, then the lock is successful. To release the lock, issue the del command to all nodes. This is a mechanism based on which [most agree]Copy the code

Multi-level cache implementation

  • Nginx + Lua (two layers: distribution layer, application layer)
  • Process cache (ZooKeeper listens for changes)
  • Redis cluster

Conclusion:

  • The granularity of the lock, the scope should be as small as possible
  • Cache data should be allowed to be lost, and try not to set the cache to never expire
  • Consider some of the problems associated with improper use of caching, and think ahead about solutions
  • Massive concurrency can consider n-level caching, full caching, and a bottom-of-the-line solution to create consistency problems
  • Data is frequently updated and requires data consistency. Therefore, cache is not recommended

Reference:

  • www.cnblogs.com/rjzheng/p/9…
  • Blog.csdn.net/z50L2O08e2u…
  • www.pianshen.com/article/170…
  • www.jianshu.com/p/d00348a9e…
  • www.cnblogs.com/qdhxhz/p/11…
  • www.cnblogs.com/rgcLOVEyaya…
  • Github.com/liyue2008/c…