上亿高并发,如何保证缓存与数据库的双写一致性
文字出处:五九盾网络 | 责任编辑:五九盾网络 | 发布时间:2022-10-19 09:35:52
高防CDN套餐
高防IP
香港服务器租用
阿里云低折扣
动态BGP高防服务器
在业务中使用缓存现在非常普遍,甚至可能与数据库一样频繁。如果你的用户量增加,直接背一个裸MySQL来承受所有压力显然是不合理的。这里的缓存,目前业界主流是Redis,如何保证缓存和数据库的双写一致性
只要使用缓存,就可能涉及缓存和数据库的双重存储和双重写入。只要你是双写,就会出现数据一致性问题,那么如何解决一致性问题
亿级高并发,如何保证缓存和数据库的双写一致性
一、初始缓存不一致问题及解决方案
问题:先修改数据库,再删除缓存。如果缓存删除失败,会导致数据库中有新数据,缓存中有旧数据,导致数据不一致。
解决方案:
先删除缓存,再修改数据库。如果删除缓存成功,修改数据库失败,那么数据库是旧数据,缓存是空的,所以数据不会不一致,因为读取的时候没有缓存,那么读取旧数据在数据库,然后更新缓存。
2.并发下数据缓存不一致的分析
问题:
当第一次请求数据发生变化时,先删除缓存,再修改数据库。此时,没有时间修改它;
第二个请求来读缓存,发现缓存为空,去查询数据库,找到修改前的旧数据,放入缓存;
第三个请求读取缓存中的数据(此时第一个请求已经完成了数据库修改操作)。
完了,数据库和缓存中的数据不一样了。 . . .
问题分析:
仅在同时读取和写入相同数据时可能会出现此问题。问题。事实上,如果你的并发很低,尤其是读并发很低,每天的访问量是10000次,那么在极少数情况下,会出现刚才描述的不一致的场景; 1亿流量,每秒几万次并发读取,只要每秒有数据更新请求,就可能出现上述数据库+缓存不一致的情况。
解决方案:
数据库的缓存更新和读取操作是序列化的。一个队列对应一个工作线程。每个工作线程依次获取相应的操作,并一一执行。
1.首先,我们在项目中维护了一组线程池和内存队列。
2、更新数据时,根据数据的唯一标识将请求路由到一个jvm队列更新数据库,然后请求结束。
3、读取数据时,先检查缓存。如果发现数据不在缓存中,会根据唯一标识进行路由,然后发送到同一个jvm内部的队列中,重新读取数据库后会更新缓存。最后,请求结束。
这里有一点需要优化。比如在一个队列中,多个更新缓存请求串在一起是没有意义的,所以重复查询数据库和更新缓存的操作应该优化:如果发现队列中已经有更新缓存如果接收到请求,那么就不需要放入更新请求操作,直接阻塞后续的读取请求200ms左右(这里只是举例,实际值可以根据服务的响应时间和机器的处理能力),然后再次查询缓存。如果缓存中没有值,请检查数据库。得到结果后,不需要更新缓存,直接返回到页面即可。
高并发解决方案:/dedicated/hkcdn.html
在业务中使用缓存现在非常普遍,甚至可能与数据库一样频繁。如果你的用户量增加,直接背一个裸MySQL来承受所有压力显然是不合理的。这里的缓存,目前业界主流是Redis,如何保证缓存和数据库的双写一致性
只要使用缓存,就可能涉及缓存和数据库的双重存储和双重写入。只要你是双写,就会出现数据一致性问题,那么如何解决一致性问题
亿级高并发,如何保证缓存和数据库的双写一致性
一、初始缓存不一致问题及解决方案
问题:先修改数据库,再删除缓存。如果缓存删除失败,会导致数据库中有新数据,缓存中有旧数据,导致数据不一致。
解决方案:
先删除缓存,再修改数据库。如果删除缓存成功,修改数据库失败,那么数据库是旧数据,缓存是空的,所以数据不会不一致,因为读取的时候没有缓存,那么读取旧数据在数据库,然后更新缓存。
2.并发下数据缓存不一致的分析
问题:
当第一次请求数据发生变化时,先删除缓存,再修改数据库。此时,没有时间修改它;
第二个请求来读缓存,发现缓存为空,去查询数据库,找到修改前的旧数据,放入缓存;
第三个请求读取缓存中的数据(此时第一个请求已经完成了数据库修改操作)。
完了,数据库和缓存中的数据不一样了。 . . .
问题分析:
仅在同时读取和写入相同数据时可能会出现此问题。问题。事实上,如果你的并发很低,尤其是读并发很低,每天的访问量是10000次,那么在极少数情况下,会出现刚才描述的不一致的场景; 1亿流量,每秒几万次并发读取,只要每秒有数据更新请求,就可能出现上述数据库+缓存不一致的情况。
解决方案:
数据库的缓存更新和读取操作是序列化的。一个队列对应一个工作线程。每个工作线程依次获取相应的操作,并一一执行。
1.首先,我们在项目中维护了一组线程池和内存队列。
2、更新数据时,根据数据的唯一标识将请求路由到一个jvm队列更新数据库,然后请求结束。
3、读取数据时,先检查缓存。如果发现数据不在缓存中,会根据唯一标识进行路由,然后发送到同一个jvm内部的队列中,重新读取数据库后会更新缓存。最后,请求结束。
这里有一点需要优化。比如在一个队列中,多个更新缓存请求串在一起是没有意义的,所以重复查询数据库和更新缓存的操作应该优化:如果发现队列中已经有更新缓存如果接收到请求,那么就不需要放入更新请求操作,直接阻塞后续的读取请求200ms左右(这里只是举例,实际值可以根据服务的响应时间和机器的处理能力),然后再次查询缓存。如果缓存中没有值,请检查数据库。得到结果后,不需要更新缓存,直接返回到页面即可。
高并发解决方案:/dedicated/hkcdn.html