The cache

Nuggets pheasant flow, may be wrong, see new knowledge points will be updated

Determine whether caching is required

The data are divided into three levels according to the difference in real time:

Level 1: high requirements for real-time and accuracy, without adding any cache, read and write operations directly operate the database.

Level 2: Read more and write less. Redis is used for caching.

Level 3: Small amount of data is read frequently and hardly modified. Local memory is used for caching.

Determine whether you need to use caching in two ways:

1. CPU usage: If the application consumes a lot of CPU to compute frequently (for example, regular expressions), use caching to cache the results of regular expressions.

2, database IO occupancy: if the database connection pool is busy, or even often reported insufficient connection alarm, you should consider using cache.

Classification of cache

Process the cache

Process caching is similar to the use of caching in a computer CPU to speed up access by reducing direct access to memory.

Why would you need a process cache like Guava and Caffeine when you already have Redis?

1, If Redis hangs or uses the old version of Redis, it will perform full synchronization, at this time Redis is not available, at this time we can only access the database, it is easy to cause an avalanche.

2, access to Redis will have a certain network I/O and serialization deserialization, although the performance is very high, but it is not as fast as the local method, you can store the hottest data locally, in order to speed up access.

ConcurrentHashMap: suitable for the relatively fixed and small number of caches, due to the JDK’s own class, there are a lot of use in various frameworks, such as we can use to cache our reflected Method, Field, etc. You can also cache some links to prevent them from being duplicated

LRUMap: You can use this if you don’t want to introduce third-party packages and you want to use an elimination algorithm to weed out data

Ehcache: Due to its large jar package, it is heavyweight. Ehcache is an option for persistence and clustering.

Guava Cache: The Guava JAR has been introduced in many Java applications, so it is easy to use, lightweight and feature-rich. If Caffeine is not required, you can choose the Guava Cache.

Caffeine: Hit ratio is high, read/write performance is much better than Guava Cache, and its API is almost the same as Guava Cache, if not more.

Summary: ConcurrentHashMap is recommended if you do not need to eliminate the algorithm, while Caffeine is recommended if you need to eliminate the algorithm and some rich apis

Distributed cache

MemCache: Large throughput, but supports fewer data structures, and does not support persistence

Redis: support rich data structure, high read and write performance, but data full memory, must consider resource cost, support persistence

Tair: Supports rich data structures with high read/write performance, but some types are slow. Theoretically, the capacity can be expanded indefinitely

Multistage cache

Generally, we choose a process cache and a distributed cache to make multi-level cache. For example, Caffeine is used for level 1 cache and Redis is used for level 2 cache

When an application process initiates a request:

1, check Caffeine first, if there is a direct return, if there is no, go to step 2.

2. Check again in Redis. If yes, return the data and fill in the data in Caffeine

3. Finally, query in MySQL, and some data will be returned and filled in successively in Redis and Caffeine

For Caffeine cache updates: if there is a data update, the cache can only be deleted on the machine that updated the data, other machines can only expire the cache deletion by timeout

For Redis cache updates, other machines will see them immediately, but you must also set a timeout, which should be longer than Caffeine

Redis pub/sub can be used to notify other process caches to remove caches. If Redis fails or the subscription mechanism is unreliable, it still expires with a timeout

Ensure cache and data consistency in dual-write mode

Update the cache, update the database

Generally not, the main reason is to update the cache, some cache is not directly taken out of the library to use, but after a series of calculations, the cost of updating the cache is very high. In addition, if there are a large number of write requests but few read requests, if the cache is updated for each write, the performance loss is very large

Deleting the cache instead of updating it is a lazy loading idea, recalculated only when it needs to be used

To verify that the cache is actually accessed frequently:

The cache is updated 100 times for a table whose fields have been changed 100 times in 1 minute. But the cache was only read once in a minute, and there was a lot of cold data.

If the cache is deleted, the cache is only recalculated once in a minute, and the overhead is significantly reduced. Cache is only counted when you want to use it

Delete the cache first, update the library later

Two concurrent read and write operations:

1, write operation first, delete cache

2, before the database is updated by the write operation, a read request comes in, and the cache is not hit

Write operations update the database

4. The read operation backfills old data back into the cache

The advantage of deleting the cache first is that if the operation on the database fails, it will only result in a cache miss because of the cache deleted first

Update the library first, delete the cache later

Two concurrent read and write operations without caching:

1. When the read operation came first, I found that there was no cache, so I went to the database to read the data. At this time, because of some reason, the data was not put into the cache in time

2, write operation in, modify database, delete cache

3, read operation recovery, write old data into the cache

If the cache fails to be deleted, new data is stored in the data store but old data is stored in the cache, causing inconsistency between the database and cache

The solution

Delay double delete

A delayed dual-deletion policy is adopted to ensure that the cache can be deleted after the transaction is committed

Deleting the cache for the first time is to check whether the cache service is available and whether the network is faulty. Deleting the cache for the second time is delayed to ensure that the read request is completed before the write request

However, if the MySQL read-write separation architecture is used, there will be a time difference between the master and slave synchronization after the object is submitted. The solution is to force Redis to point to the master library if it does a database lookup to populate the data

The message queue

Compensation for deletion using message queues:

1. Request A to update the database first

2. Failed to delete the cache

3. Send the key of Redis as the message body to the message queue

4. After receiving the message sent by the message queue, the system deletes Redis again

The disadvantage of this solution is that it causes A lot of intrusion into the business code, which is deeply coupled, and A has to do all kinds of work. If the write operation is very frequent, the data in the queue may be consumed slowly. As a result, the cache is deleted after a period of time after the database is modified

The final optimization is to take advantage of MySQL’s binlog and subscribe to the binlog service to operate on the cache and decouple the update operation

Cache pit three swordsmen

The cache to penetrate

Cache penetration refers to the query of a database and the cache do not have the data, will always query the database, database access pressure increases, there are two solutions: 1, cache empty object: simple code maintenance, poor effect 2, Bloom filter: complex code maintenance, good effect

Caching empty objects

Cache empty objects. When requesting data that does not exist in the cache or database, the first request will skip the cache and directly access the library, and the library returns an empty object, and the empty object will also be cached. When the empty object is accessed again, it hits the cache directly instead of falling into the library

Caching empty objects will cause many empty objects in the cache, wasting memory space. The solution is to set a short expiration time for empty objects

Bloom filter

A Bloom filter is a probabilistic data structure that can only tell you that an element is definitely not in a set or could be in a set, with the following characteristics:

1, a very large binary array (only 0 and 1), space efficiency and query efficiency, there are several hash functions

2, there is no missing report, but there may be false positive, do not provide deletion method

3, the bit array is initialized to 0, the element value is not stored, the element hash value corresponding to the array position value of 1

Misjudgment rate

The judgment accuracy of Bloom filter is related to two factors:

1, Bloom filter size: the larger the error rate is smaller, so the general length of bloom filter is very large.

2, the number of hash functions: the number of hash functions, the smaller the misjudgment rate

Do not delete

When the z element is deleted, the corresponding subscripts 10 and 13 will be set to 0, which will affect the subscripts of x and Y elements and lead to inaccurate data judgment. Therefore, the API for deleting elements is not provided directly

The disadvantage of a Bloom filter is that it maintains data in the container in real time. For frequently changing data, the Bloom filter needs to update the data in the container to the latest

Cache breakdown

Cache breakdown refers to that a key is very hot, and a large number of concurrent accesses are concentrated at this point. When the key fails at the moment, the continuous large concurrent accesses will Pierce the cache and directly request the database, which increases the pressure of accessing the database instantly. Cache breakdown emphasizes concurrency.

There are two reasons for cache breakdown:

1, the data has not been queried, the first time on a large concurrent access. (Unpopular data)

Reids also set the expiration time of the key. In case of a large number of concurrent accesses, the cache will be invalidated.

When a large number of concurrent accesses occur, the cache and database lookup processes are locked, and only the first incoming request can be executed. When the first request puts the data into the cache, subsequent accesses will hit the cache directly, preventing cache breakdown

To use a distributed Lock in a distributed environment, use a synchronized Lock on a standalone device.

Cache avalanche

Cache avalanche refers to the period in which the cache set expires and so many requests bypass the cache and go directly to the database. There are two reasons for cache avalanches:

1. Reids fail 2. A large number of keys fail at the same time

Solution:

1. Set up a high availability cluster to prevent the downtime of single Redis

2. Set different expiration times to prevent a large number of keys from becoming invalid at the same time