Summary of cache processing ideas in high concurrency scenarios

application background

In actual development, we often need to read and search disk data, so there are often scenarios where data is read from the database. However, when the number of data accesses increases, too many disk reads may eventually become a performance bottleneck of the entire system, or even overwhelm the entire database, causing serious problems such as system freezing.

In a conventional application system, we usually search the database when needed, so the general structure of the system is as follows:

 

When the amount of data is high, it is necessary to reduce the disk read and write operations in the database, so it is usually chosen to add a layer of cache between the business system and the MySQL database to reduce the access pressure on the database.

 

But in many cases, the application of caching in actual projects is not so simple. Let's list some problems through several classic cache application scenarios:

1. Data consistency problem between cache and database

The mechanisms commonly used for cache processing are summarized as follows:

Cache Aside, Read Through, Write Through, Write Behind Caching

Cache Aside mode

This mode handles the cache usually first from the database cache query, if the cache does not hit, then look it up from the database. There are three situations that can happen here:

cache hit

When the query finds that the cache exists, it is directly extracted from the cache.

cache invalidation

When there is no data in the cache, the source data is read from the database and added to the cache.

 

cache update

When there is a new write operation to modify the data in the database, it is necessary to invalidate the corresponding data in the cache after the write operation is completed.

 

This Cache aside mode is usually the most commonly used mode in practical application development. However, it does not mean that the cache processing in this mode will be perfect, and there will still be defects in this mode. For example, one is a read operation, but it does not hit the cache, and then fetches data from the database. At this time, a write operation occurs. After the database is written, the cache is invalidated. Then, the previous read operation puts the old data Going in, so, will cause dirty data. Facebook's big cows have also published related papers on the issue of cache processing, the link is as follows: www.usenix.org/system/file ... It is extremely difficult to completely ensure data consistency in a distributed environment , we can only reduce the occurrence of this data inconsistency problem as much as possible.

Read Through mode

Read Through mode means that the application always requests data from the cache. If the cache has no data, it is responsible for retrieving the data from the database using the underlying provider plugin. After the data is retrieved, the cache updates itself and returns the data to the calling application. There is a benefit to using Read Through. We always use the key to retrieve data from the cache, the calling application does not know the database, and the storage side is responsible for its own cache processing, which makes the code more readable and clearer. But this also has corresponding defects. Developers need to write related program plug-ins, which increases the difficulty of development.

Write Through mode

The Write Through mode is similar to the Read Through mode. When the data is updated, it is first updated in the Cache. If it is hit, the cache is updated first, and then the Cache side updates the database. If there is no hit, the data in the Database is directly updated.

 

Write Behind Caching mode

Write Behind Caching This mode usually writes data into the cache first, and then asynchronously writes it into the database for data synchronization. This design can directly reduce our direct access to the data in the database and reduce the pressure. , At the same time, multiple modifications of the database can be merged, which greatly improves the carrying capacity of the system. However, this mode of processing cached data has certain risks. For example, when the cache machine is down, data may be lost.

 

2. Cache penetration problem

In high-concurrency scenarios, cache penetration is a problem that is often encountered.

What is cache penetration

A large number of requests do not find the specified data in the cache, so they need to be queried from the database, resulting in cache penetration.

what will happen

The influx of a large number of requests into the database for query in a short period of time will increase the pressure on the database, which will eventually cause the database to be unable to bear the pressure of the customer's single request, causing downtime and freezing.

Commonly used solutions

1. Null cache

In some specific business scenarios, the query for data may be empty and has no actual existence, and such data information will not change after repeated queries in a short period of time, so in the whole process, how many Requesting database operations once would be a bit redundant. It may be possible to store the keys corresponding to these null values ​​(data without query results) in the cache, so that the second lookup does not require the trouble of requesting the database again, and only needs to query through memory. This approach can greatly reduce the access pressure on the database.

 

2. Bloom filter

Usually, the key value of the data in the database can be pre-stored in the Bloom filter, and then filtered in the Bloom filter first. If it is found that there is no Bloom filter, then go to redis to query, if If there is no data in redis, then go to the database to query. This can prevent non-existing data information from also going to the repository for query.

 

For learning about Bloom filters, please refer to my notes: blog.csdn.net/Danny_idea/…

3. Cache the avalanche scene

What is Cache Avalanche

When the cache server restarts or a large number of caches fail in a certain period of time, it will also put a lot of pressure on the back-end system (such as DB) when it fails.

How to Avoid the Cache Avalanche Problem

1. Use a lock queue to deal with this kind of problem. When there are multiple requests influx, when the cache becomes invalid, a distributed lock is added to allow only successful lock grabbing requests to read data from the library and then store it in the cache, and then release the lock to allow subsequent Read requests fetch data from the cache. However, this approach has certain disadvantages. Too many read request threads are blocked and the machine memory is full, which still cannot fundamentally solve the problem.

2. Before the concurrent scenario occurs, manually trigger the request and store the cache to reduce the pressure on the first query of the database by the later request. The data expiration time settings should be scattered as far as possible, and the data should not be cached and expired in the same time period.

3. From the perspective of cache availability, to avoid the problem of a single point of failure in the cache, you can use the master-slave + sentinel mode to build a cache architecture. However, the cache architecture built in this mode has a drawback, that is, it cannot be cached. slices, the amount of data stored and cached is limited, so it can be upgraded to the Redis Cluster architecture for optimized processing. (It needs to be combined with the actual economic strength of the enterprise, after all, the construction of Redis Cluster requires more machines)

4. Ehcache local cache + Hystrix current limit & downgrade to avoid MySQL being killed. The purpose of using Ehcache local cache is also to consider that when Redis Cluster is completely unavailable, Ehcache local cache can still support it for a while. Use Hystrix for current limiting & downgrading. For example, if 5000 requests come in one second, we can set the assumption that only 2000 requests can pass through this component in one second, and then the remaining 3000 requests will go through the current limiting logic. Then call the downgrade component (downgrade) we developed ourselves, such as setting some default values ​​and the like. In this way, the last MySQL will not be killed by a large number of requests.

Guess you like

Origin blog.csdn.net/BASK2312/article/details/131090317