preface

It’s great to use caching to improve application performance, but what are the problems associated with using caching?

Let’s talk about what’s wrong with caching and how to deal with it

  • Understand the problems that arise when systems use caching
  • Understand solutions to common cache consistency problems
  • Deal with cache penetration, cache breakdown, cache avalanche

Common problems with caching

Let’s review the process of using caching

The use of caching greatly improves the performance and efficiency of applications, especially data queries. But at the same time it also brings some problems, the most crucial of which is the data consistency problem

In a strict sense, there is no solution to this problem. Business scenarios with high requirements on real-time performance should not use caching, whereas to use caching should accept its inconsistencies

In addition to cache consistency issues, there are several typical problems encountered: cache penetration, cache breakdown, and cache avalanche

There are also popular solutions to common problems with caching

We’re not trying to perfect these problems, nor are we trying to subvert popular industry solutions

We want to understand some problems and solutions encountered in the use of cache

Cache consistency

Real-time data synchronization

This data synchronization is incremental, proactive, and highly consistent

  • When database data is updated (add, modify, delete), the cache is eliminated

  • Update the cache as data is read. Synchronization is needed to avoid an avalanche of cache breakdowns

    Control a key and only one thread reads the data and then updates the cache, while the other threads block and wait

  • Set cache expiration time. This is a bottom-of-the-line operation. If the cache update fails, the cache will be invalidated as soon as the cache expiration time expires

The flow chart is as follows

Of course, this is only to ensure that the thread execution order is not out of order

If Clinet2 is executed too quickly and Clinet1 is not finished, the cached data is still inconsistent with the database

On-time data synchronization

This data synchronization is incremental, passive, and quasi-consistent

  • Send an UPDATED CACHED MQ message after the data update operation (if you want to ensure that data is not lost, create a message table locally and retry after sending MQ failed)
  • The cache update service consumes THE MQ update data message and reads the database data for relevant business processing
  • The cache update service updates the business processing results to the cache

The flow chart is as follows

The core idea is to send a message to update the data over MQ to the cache update service, which reads the database data to update the cache

Task scheduling update

In this way, the cache is updated periodically by scheduling tasks, and the application scenario is as follows: report statistics data, reconciliation data is periodically updated to the cache and other scenarios where real-time performance is not high

The implementation is relatively simple

  • The Timer or ScheduledExecutorService
  • Spring Task Indicates a scheduled Task
  • Periodic task framework Quartz or XXL-Job

The flow chart is as follows

The core idea is to update the cache by reading database data in a timed way, which will have a certain delay and can be considered in scenarios requiring less real-time performance

Binlog Log subscription

Update the cache by subscribing to binlog. The consumption service we build is a slave of mysql. Subscribe to binlog to parse the update content and then update it to the cache

The flow chart is as follows

Its process is very similar to task scheduling update, scheduled task is scheduled active update and log subscription is passive update

In this way, the performance is better and the consistency of cached data is better guaranteed

When mysql is under low pressure, its latency is relatively low, and it is completely decoupled from services, which also solves the real-time problem

Of course, the disadvantages are also obvious, the need to build a separate binlog client synchronization service, and the introduction of binlog synchronization mechanism, so that the cost will increase invisibly

The cache to penetrate

Cache penetration is a query for data that must not exist because the cache is not hit when the query is from the database

If the data is not found, it will not be written to the cache, which will result in the non-existent data being queried in the database on every request

In case of heavy traffic, DB may hang. If someone attacks our application frequently with non-existent key, it is a system vulnerability

The solution

  • Verify the validity of request parameters based on service scenarios to prevent illegal requests from crushing the DB. Direct interception such as user ID <=0
  • If db cannot query the data, save the empty object to the cache layer and set a short expiration time
  • Bloom filters are used to store cached keys and filter out non-existent keys when access requests arrive, preventing these requests from reaching the DB level

Cache breakdown

Cache breakdown refers to data that is not in the cache but is present in the database.

At this time, due to a large number of concurrent requests, the cache does not read data at the same time

At the same time to the database query data, causing the database pressure increased instantly, resulting in excessive pressure

The solution

  • If the cache data is not set to expire, there will be no hot key expiration resulting in a large number of requests to the database
  • Add a mutex lock to ensure that only one request can access the database when the cache data fails, update the cache, and the other threads wait and retry

Cache avalanche

Cache avalanche refers to the fact that a large amount of data in the cache reaches the expiration time and a large amount of query data causes the database to become overburdened or even down

Unlike a cache breakdown, which refers to a concurrent query for the same data, a cache avalanche is when different data are out of date and a lot of data is not found and therefore the database is queried

The solution

  • 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 among different cache databases
  • Set the hotspot data to never expire