怎么做期货网站,新闻发稿平台,工信部网站备案号,商城网站验收问题由来
数据redis和MySQL都要有一份#xff0c;如何保证两边的一致性。
如果redis中有数据#xff1a;需要和数据库中的值相同如果redis中没有数据#xff1a;数据库中的值是最新值#xff0c;且准备会写redis
缓存操作分类
自读缓存读写缓存#xff1a; #xff0…问题由来
数据redis和MySQL都要有一份如何保证两边的一致性。
如果redis中有数据需要和数据库中的值相同如果redis中没有数据数据库中的值是最新值且准备会写redis
缓存操作分类
自读缓存读写缓存 一同步直写策略 写数据后也同步写redis缓存缓存和数据库中的数据一致 对于读写缓存来说要想报增缓存和数据库中的数据一致就要采用同步直写策略。 二异步缓写策略 正常业务运行中mysql数据变动了但是可以在业务上容许出现一定时间后才作用于redis比如长裤、物流系统 异常情况出现了不得不将失败的动作重新修补有可能需要节奏Kafka或者RbbitMQ等消息中间件实现重试重写。
一致性问题 ckage com.atguigu.redis.service;import com.atguigu.redis.entities.User;
import com.atguigu.redis.mapper.UserMapper;
import io.swagger.models.auth.In;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.PathVariable;import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;/*** * 不能直接用哦理解高并发下“双检加锁”的思路。*/
Service
Slf4j
public class UserService {public static final String CACHE_KEY_USER user:;Resourceprivate UserMapper userMapper;Resourceprivate RedisTemplate redisTemplate;/*** 业务逻辑没有写错对于小厂中厂(QPS《1000)可以使用但是大厂不行* param id* return*/public User findUserById(Integer id){User user null;String key CACHE_KEY_USERid;//1 先从redis里面查询如果有直接返回结果如果没有再去查询mysqluser (User) redisTemplate.opsForValue().get(key);if(user null){//2 redis里面无继续查询mysqluser userMapper.selectByPrimaryKey(id);if(user null){//3.1 redismysql 都无数据//你具体细化防止多次穿透我们业务规定记录下导致穿透的这个key回写redisreturn user;}else{//3.2 mysql有需要将数据写回redis保证下一次的缓存命中率redisTemplate.opsForValue().set(key,user);}}return user;}/*** 加强补充避免突然key失效了打爆mysql做一下预防尽量不出现击穿的情况。* param id* return*/public User findUserById2(Integer id){User user null;String key CACHE_KEY_USERid;//1 先从redis里面查询如果有直接返回结果如果没有再去查询mysql// 第1次查询redis加锁前user (User) redisTemplate.opsForValue().get(key);if(user null) {//2 大厂用对于高QPS的优化进来就先加锁保证一个请求操作让外面的redis等待一下避免击穿mysqlsynchronized (UserService.class){//第2次查询redis加锁后user (User) redisTemplate.opsForValue().get(key);//3 二次查redis还是null可以去查mysql了(mysql默认有数据)if (user null) {//4 查询mysql拿数据(mysql默认有数据)user userMapper.selectByPrimaryKey(id);if (user null) {return null;}else{//5 mysql里面有数据的需要回写redis完成数据一致性的同步工作redisTemplate.opsForValue().setIfAbsent(key,user,7L,TimeUnit.DAYS);}}}}return user;}
}
数据库和缓存一致性的几种策略
目的:总之我们要到达最终的一致性。
一停机运维
挂牌报错凌晨升级温馨提示服务降级单线程这样重量级的数据操作最好不要用多线程
二不停机的四种策略
①先更新数据库再更新缓存
②先更新缓存再更新数据库
③先删除缓存再更新数据库延伸延迟双删
④先更新数据库再删除缓存
阿里巴巴的canal等中间件就是类似的思想通过binlog日志去更新消息、缓存这些中间件去订阅binlog的日志。 比如
总结如果我们想着A/B等多个线程去竞争无论如何都有可能导致不一致。但一般系统都已数据库为最终解释权这样3和4的方案会好许多最不推荐的是第二种。 1 先删除缓存值再更新数据库有可能导致请求因缓存缺失而访问数据库给数据库带来压力导致打满mysql。 2 如果业务应用中读取数据库和写缓存的时间不好估算那么延迟双删中的等待时间就不好设置。
如果业务叫非要一致性那就别用缓存了。加一个页面返回也是一个很好的解决方案不用太纠结这肉眼难见的事件。当然异常了还是得处理。