Hello hello monkeys, I’m a turnip for coding bugs. Public account: Big Turnip Technology. Original is not easy, but welcome to reprint.

This article focuses on the cache consistency problem and its solution. The following is the main table of contents for you to browse.

directory
  1. What is cache consistency
  2. Why cache consistency
  3. How to ensure cache consistency
  4. How to achieve strong consistency
  5. conclusion

01 What is cache consistency

It is a problem caused by data inconsistency between the cache and the database. Cache consistency is classified into strong consistency and final consistency.

  • Strong consistency, this is lossy performance, it’s complicated, and when you add it, it’s probably slower than if you didn’t add the cache.

  • Final consistency is the ability to allow cache data and database data to be inconsistent for a period of time, but the data will eventually remain consistent. This has higher performance.

02 Why cache Consistency

Some write operations exist in the service. Do you need to write to the cache first or to the database first? The difference in the order of the two causes different problems.

Read operations alone do not cause cache consistency problems because reads are idempotent. There are no cache consistency problems caused by read operations because the read operation does not change for countless times.

So it is write operations that cause cache inconsistencies. Write operations are the cause of cache inconsistencies. However, this is not a reason to ensure cache consistency, it is ultimately a business need, if the business needs allow the cache and database to be inconsistent, then cache consistency is not necessary.

03 Ensuring Cache Consistency (Solution)

I believe many people know the classic scheme: cache aside pattern.

The first thing to make clear is that reads do not cause cache consistency problems. It is write operations that cause cache consistency problems.

First, invalidation: when a request comes in, it accesses the cache, which doesn’t exist, then it accesses the database and updates the cache.

Second, read: when the request comes in, there is data in the cache and the data is returned directly.

Third, write: update the database first, then delete the cache.

The key is the third point, the premise, the database must be updated. The remaining question is: do you want to update the cache? Or do you want to delete the cache? Do you operate on the database first? Or do you do caching first?

There are four possible combinations of two:

  • Update the cache first, then the database

  • Update the database first, then the cache

  • Delete the cache first and update the database later

  • Update the database first, then delete the cache

1. Update the cache first and then the database

The first thing to understand is that updating a database, or updating a cache, runs the risk of an update failure. But in the high-concurrency environment of the Internet and according to Murphy’s Law, it’s bound to happen.

  1. Update the cache first. It worked

  2. And then you update the database, and it fails, and of course you say try again, ok, so I’ll try again N times, but if the database is completely down, and you can’t recover, it doesn’t matter if you try again

Cause problems: data loss, data in the database is still old data

2. Update the database first and then the cache

Suppose you have two requests: request A is an update, request B is an update, and request A comes first, but only after request B

  1. Thread A updates the database

  2. Thread B updates the database

  3. Thread B updates the cache

  4. Thread A updates the cache

This leads to problems: old data in the cache, new data in the database, which is inconsistent. And will the updated cache really be read again? If the cache data is no longer read, a cache update operation is performed for nothing. It also takes up memory space.

As you can see from this example, updating the cache is not an option, so simply delete the cache. Then look at

3. Delete the cache and update the database

Suppose there are two requests, A for update and B for read, which may cause problems

  1. Thread A deletes the cache

  2. Thread B can not query the cache, directly to the database to look up the old value

  3. Thread A writes the new value to the database

  4. Thread B updates the cache

Cause problems: the old value in the cache is inconsistent with the new value in the database. Further, inconsistencies between cache and database data are exacerbated if there is read/write separation in the database.

  1. Thread A deletes the cache

  2. Thread A writes the new value to the master database, but does not synchronize data to the slave database

  3. Thread B, unable to query the cache, goes directly to the database and finds the old value

  4. Thread B updates the cache

  5. New data is synchronized to the slave database

Cause problems: cache is old value, database is new value, the two data inconsistency

4. Update the database and delete the cache

The problem may arise if there are two requests, A request for read and B request for update

  1. The cache just failed

  2. Thread A looks up the database and gets the old value

  3. Thread B updates the database

  4. Thread B deletes the cache

  5. Thread A updates the cache

Cause problems: cache is old value, database is new value, the two are inconsistent. However, this is relatively unlikely because you need the cache to be invalidated, and there is a thread to read, and there is a thread to write. And the writing thread is theoretically slower than the reading thread, because the writing thread needs to lock. Queries are unlocked and do not include complex queries.

This is even more pronounced in the case of database read-write separation:

  1. Thread B updates the main library

  2. Thread B deletes the cache

  3. Thread A queries the cache, does not hit, and the query gets the old value from the library

  4. Data is synchronized to the slave library

  5. Thread A updates the cache

Cause problems: Cache data and database data are inconsistent

If you think about updating the database or failing to update the cache, then if you fail to update the database, the database and the cache are actually old data, so there is no inconsistency.

If updating the cache fails, there is an expiration time to ensure final consistency. If you want to be serious, try a retry mechanism.

Retry mechanisms can be thread pools or MQ. MQ is more reliable. You can subscribe to MySQL binlog directly to trigger cache deletion. Of course, MQ will also hang. But the chances of both MQ and cache hanging together are slim.

To sum up the four cases mentioned above

While each scenario has its own problems, the less likely scenario is to update the database first and then delete the cache. Why update the database first? Because database persistence is better than caching. In the above four cases, cache concurrency, cache penetration, and cache avalanche may also occur. These questions will not be discussed here. If you are interested, read my related article for yourself.

04 How to Achieve Consistency

Scheme 1: distributed transaction

You can use distributed transaction, distributed transaction, the specific implementation of 2PC, 3PC, message queue, etc. If this solution is to be adopted, the architecture design should introduce a lot of fault tolerance, rollback, and bottom-saving measures. The business code adds complexity. Others say that using distributed consistency algorithms paxos and Raft makes it more complicated.

Scheme 2: Distributed read/write lock

First, let’s go back to updating the database first and then deleting the cache. When does dirty data occur?

Dirty data: after updating the database, before deleting the cache. At this point, the two data are inconsistent.

If the implementation updates the database, all read requests are blocked. This solves the problem of inconsistent data, which is serialization. But the consequence, of course, is performance degradation.

conclusion

Actually choose the strong consistency of the data and the final consistency of the data. Depends on the needs. I kind of just said a bunch of crap. However, giving up strong consistency means that the performance of our system has been improved to a certain extent. On the other hand, if we go for consistency, it will be extremely complex and may not be worth the cost, possibly with lower performance than without caching. Caching, if you want to use it well, you need to think about expiration time Settings, persistence, failover, balance of space and time, and consistent choices. There is no best solution, only the right solution.