Caching issues

The cache to penetrate

Cache penetration: Access to a key that does not exist but is still accessed by a large number of users

It refers to a large number of requests to access values that do not exist in the cache. As a result, a large number of requests are sent to the DB, causing DB faults.

Cache breakdown

Cache breakdown: A cache key fails but is still accessed by a large number of users

When the cache of hotspot data expires, a large number of requests are sent to the DB, causing a DB fault.

Cache avalanche

Cache avalanche: Multiple cache keys fail and are still accessed by a large number of users

A failure caused by a large cache failure that causes users to send requests to the database.

The solution

  • Add verification at the interface layer, such as user authentication verification (parameter verification)
  • The value can be set to NULL for data not available from the cache and not available from the database
  • The timeouts are set at random to avoid avalanches
  • Bloom filter, hash all possible data into a large enough bitmap, and a certain non-existent data will be intercepted by the bitmap, thus avoiding the query pressure on the underlying storage system
  • Cache warmingCommit to store the hot key in the cache

Bloom filter

The cached values are computed by multiple hash functions to hash out the hash code and then stored in an array that only holds zeros and ones, so we can quickly tell if a cache is in Redis by using bits.

The bloom filter can be used to filter out cache keys that do not exist in Redis, but it is not certain whether a value is definitely in redis.

Conclusion: The value that does not exist in bloom filter does not exist in reality, and may not exist in reality

Bloom filters can be used in more scenarios, such as:

  • There were a billion numbers, now there are 100,000 numbers, and you have to quickly and accurately determine whether those 100,000 numbers are in the billion number pool
  • Spam filtering
  • Crawler URL Filtering

And so on this kind of large data set, quickly and accurately determine whether a certain data is in the set, and does not occupy memory, this is the application scenario of Bloom filter

Cache warming

Stuff hot data into Redis in advance

Because we don’t know, we’re going to use the lock protection plan

Development logic should also avoid differential sets, which can cause breakdowns, penetrations, avalanches

Specific operation:

  • Routine data access records: Collects statistics on frequently accessed hotspot data
  • The data retention queue is constructed by LRU data deletion strategy

Redis implements distributed locking

The client request first goes to Redis to request the lock. Only one thread can acquire the lock while the other thread does a spin of CAS. The thread that holds the lock can then go to mysql and bring the data back to Redis and release the lock. The other client brothers can find the data in Redis. when

Double write inconsistent

When we update the database, we also want to update the order in the cache. These are two actions, not atomic, so who came first and who came last? So we have the following four options

  • Update database first, before write cache (not desirable)
  • Write to the cache before updating the database (not recommended)
  • Delete the cache before updating the database (not desirable)
  • Update the database first, then delete the cache (desirable, but flawed)

Update database first, before write cache

Thread A is going to the database to perform an inventory deletion, but the cache has not been updated yet. But now thread B checks the cache, finds that there is still a cache, places an order, but actually the database has no cache, so it doesn’t work

Write to the cache before updating the database

There’s no data in the cache at the beginning, so thread A goes to the database and writes data, but it hasn’t written it yet. In this case, thread B will check the data in the cache. The data in the cache is new, but the database has not been updated, and the data in the database is old, so thread B will use the old data in the database to operate.

Delete the cache first, then update the database

Thread A deletes the cache and then updates the database. Thread B arrives, finds that there is nothing in the cache, runs to the database, and gets the data faster than thread A, but the data is still old because thread A hasn’t done A write yet.

Update the database first, then delete the cache

Thread A updates the database and deletes the cache. So thread B is going to take the old data that it found and store it in the cache, the old data that’s stored in the cache,

Solutions:

Delayed double deletion: Thread A performs A sleep after the first deletion, and then deletes again. You can avoid the above problems. But that also introduces another problem, and it’s not easy to know what the value of sleep should be. From this background, Canal was born!

Canal

The main purpose is to provide incremental data subscription and consumption based on MySQL database incremental log resolution

In the early stage, Because of the deployment of double machine rooms in Hangzhou and the United States, Alibaba had the business requirement of cross-machine room synchronization, and the realization method was mainly based on business trigger to obtain incremental changes. Since 2010, businesses have gradually tried database log parsing to obtain incremental changes for synchronization, resulting in a large number of database incremental subscription and consumption services.

Canal disguised himself as a mysql slave and then sent a dump request to the mysql master to get a binlog. After the master returns the binlog, the data in the binlog will be parsed into memory and provided to the customer for query without persistence.