5 implementations of talking DB and cache consistency

Data is stored in the database. In order to speed up business access, we put some data in the database in the cache. Then the question is, how to ensure the consistency of the data in the db and the cache? We have listed 5 methods, everyone understands them, and then chooses them according to the business.

Plan 1

Get the cache logic

Use the timer to refresh the cache in redis regularly .

db update data logic

Update the data without considering the data in the cache, just update the data directly

Existing problems

The consistency of the data in the cache and the data in the db may not be so timely, but in the end, the data is consistent at a certain point in time.

Plan 2

Get the cache logic

c1: Get the corresponding in redis according to the key The value

c2: If the value exists, return the value directly; if the value does not exist, continue with the following steps

c3: Get the value from the database, assign it to the value, and then set the key-> Put value into redis and return value

update db logic

u1: start db transaction

u2: update data

u3: Submit db transaction

u4: Delete the cache of current data in redis

Existing problems

  1. The success of u3 above and failure of u4 will cause the cache deletion to fail, resulting in inconsistencies between the data in the cache and the db data.
  2. If many threads arrive at c2 at the same time and find that the cache does not exist, and request c3 to access db at the same time, it will put a lot of pressure on db

Solution 3

Get Cache Logic

c1: get the corresponding value in redis according to the key

c2: if the value If it exists, return the value directly; if the value does not exist, continue with the following steps

c3: Get the value from the database, assign it to the value, then put the key->value into redis, and return the value

update db logic

u1: delete the cache of current data in redis

u2: start db transaction

u3: Update data

u4: Submit db transaction

Existing problems

  1. The thread that updates the data executes u1 successfully After that, when u2 is not yet executed, the thread that gets the cache just executes the logic from c1 to c3. At this time, the old data will be put into redis, resulting in inconsistent redis and db data.
  2. There are also solutions The problem mentioned in 2: If many threads arrive at c2 at the same time and find that the cache does not exist, and request c3 to access db at the same time, it will cause a lot of pressure on db

Solution 4

Improve solution 2 to ensure that the delete cache operation will be executed after the db update is successful. We can achieve this through reliable messages. Reliable messages can ensure that the update db operation and the deletion of the cache in redis will eventually be either All success or failure depends on eventual consistency to achieve.

The process after improvement is as follows.

Get cache logic

c1: get the corresponding value in redis according to the key

c2: if the value exists, Return value directly; if value does not exist, continue with the following steps

c3: Get the value from the database, assign it to value, then put key->value into redis, and return value

Update db logic

u1: start db transaction

u2: update data

u3: post a message to delete redis cache< /p>

u4: Submit db transaction

Message consumer-consumer who clears redis cache

Accept After clearing the messages cached in redis, clear the corresponding cache in redis.

Existing problems

  1. There is a certain time delay between updating db and clearing the cache in redis. During this time, The data cached by redis is old, which means that the db and cached data are inconsistent during this period, but they will eventually be the same. The inconsistency time may be relatively small (this depends on the efficiency of message consumption)
  2. < li>There is also the same problem mentioned in Scheme 2: If many threads arrive at c2 at the same time and find that the cache does not exist, and request c3 to access db at the same time, it will cause great pressure on db

For reliable messages, you can see

  • Talk about mq usage scenarios
  • Talk about how to deliver messages to mq in the business system Ways
  • Talk about several ways of mq message consumption
  • How to ensure that messages are consumed at least once?

Method 5

Let’s first understand some knowledge.

Several methods in redis

get(key)

Get the key Value, if it exists, then return; if it does not exist, return nil

setnx(key,value)

The meaning of setnx It is SET if Not Exists. This method is atomic. If the key does not exist, the current key is set successfully and returns 1; if the current key already exists, the current key fails to be set and returns 0

del(key)

Delete the value corresponding to the key from redis

select v from t where t.key = #key# for update;

update t set v = #v# where t.key = #key#;

The above two sql will block each other, until one of them is submitted, the other can continue to execute.

Next, we will use the above knowledge to achieve strong consistency between DB and cache.

Update data logic

1. Open db transaction 2.update t set v = #v# where t.key = # key#;3. Delete the cache in redis according to the key: RedisUti.del(key); 4. Submit the db transaction

Get the cache logic

/*Public account: Passerby Java* The former Ali P7 who has worked for 10 years shares the technical dry goods of Java, algorithms, and databases! * Reliable technology changes fate and allows family members to live a more decent life. */public class CacheUtil {//Acquire the corresponding value in the cache according to the key public static String getCache(String key) throws InterruptedException {String value = RedisUtils.get(key); if (value != null) {return value;} / /Expiration time is the current time + 5 seconds String expireTimeKey = key + "ExpireTime"; long expireTimeValue = System.currentTimeMillis() + 5000; //setnx is an atomic operation, so only one will succeed int setnx = RedisUtils.setnx(expireTimeKey, expireTimeValue + ""); if (setnx == 0) {expireTimeValue = Long.valueOf(RedisUtils.get(expireTimeKey)); //If expireTimeValue is less than the current time, it means that the expireTimeKey has expired, delete it if (System.currentTimeMillis( )> expireTimeValue) {//Delete the expireTimeKey corresponding to RedisUtils.del(expireTimeKey);} else {//Sleep for 1 second to continue to get TimeUnit.SECONDS.sleep(1);} //Retry return getCache(key);} else {//1. Open db transaction start transaction; //2. Execute update t set v = #v# where t.key = #key# for update; Assign the value of v to value update t set v = #v# where t.key = #key# for update; RedisUtils.set(key, value); //3. Commit db transaction commit transaction;} return value;} //redis tool class, internal method is pseudo code public static class RedisUtils {//Get value according to key public static String get (String key) {return null;} //Set the value corresponding to the key public static void set(String key, String value) {} //Delete the value corresponding to a key in redis public static void del(String key) {} / The meaning of /setnx is SET if Not Exists. This method is atomic. If the key does not exist, //Set the current key successfully and return 1; if the current key already exists, set the current key failed and return 0 public static int setnx (String key, String value) {return 1;} }}

This method can ensure that the caches in db and redis are strongly consistent at the same time.

expireTimeKey in order to prevent some thread from executing RedisUtils.setnx(expireTimeKey, expireTimeValue + ""); returns 1, indicating that setnx succeeded, and the system executes the next line of code After hanging up, it will cause the db data to fail to load into redis. The code: if (System.currentTimeMillis()> expireTimeValue) is to give other threads the opportunity to get the expiration time, and directly after the expiration is found Delete, so that other threads have the opportunity to load db data into redis.

The former Ali P7 who has worked for 10 years shares the technical dry goods of Java, algorithms, and databases! Reliance on technology changes fate and allows family members to live a more decent life! If you like, please pay attention to the official account: Passerby Java
Share a picture

Leave a Comment

Your email address will not be published.