dede网站怎么备份,网站策划选题,河南建筑工程网,哪家网站Redis 和 MySQL 数据一致性是分布式系统中的一个常见挑战。保证数据一致性通常涉及几种策略#xff0c;我会详细解释这些策略并提供相应的代码示例。
先更新数据库#xff0c;再更新缓存
这种方法先更新 MySQL#xff0c;然后更新或删除 Redis 缓存。
Transactional
publ…Redis 和 MySQL 数据一致性是分布式系统中的一个常见挑战。保证数据一致性通常涉及几种策略我会详细解释这些策略并提供相应的代码示例。
先更新数据库再更新缓存
这种方法先更新 MySQL然后更新或删除 Redis 缓存。
Transactional
public void updateUser(User user) {// 1. 更新MySQLuserMapper.updateUser(user);// 2. 更新Redis缓存// 方式1更新缓存redisTemplate.opsForValue().set(user: user.getId(), user);// 方式2删除缓存推荐redisTemplate.delete(user: user.getId());
}优点
简单直接保证数据库有最新数据
缺点
如果更新缓存失败会导致数据不一致
先删除缓存再更新数据库
这种方法先删除 Redis 缓存然后更新 MySQL。
Transactional
public void updateUser(User user) {// 1. 删除Redis缓存redisTemplate.delete(user: user.getId());// 2. 更新MySQLuserMapper.updateUser(user);
}优点
避免缓存更新失败导致的不一致
缺点
在高并发情况下可能出现数据不一致
延迟双删策略
这种方法在更新数据库前后都删除缓存并在第二次删除时增加短暂延迟。
Transactional
public void updateUser(User user) {// 1. 删除Redis缓存redisTemplate.delete(user: user.getId());// 2. 更新MySQLuserMapper.updateUser(user);// 3. 延迟一段时间后再次删除缓存CompletableFuture.runAsync(() - {try {Thread.sleep(500); // 延迟500毫秒redisTemplate.delete(user: user.getId());} catch (InterruptedException e) {// 处理异常}});
}优点
能够处理高并发场景下的数据一致性问题
缺点
实现较为复杂增加了系统延迟
使用消息队列
使用消息队列来保证数据一致性先更新数据库然后发送消息到队列由消费者来更新缓存。
Transactional
public void updateUser(User user) {// 1. 更新MySQLuserMapper.updateUser(user);// 2. 发送消息到消息队列kafkaTemplate.send(user-update-topic, JSON.toJSONString(user));
}// 在消费者服务中
KafkaListener(topics user-update-topic)
public void consumeUserUpdate(String message) {User user JSON.parseObject(message, User.class);// 更新Redis缓存redisTemplate.opsForValue().set(user: user.getId(), user);
}优点
解耦了数据库操作和缓存操作可以处理高并发场景
缺点
增加了系统复杂度可能引入短暂的数据不一致
使用 Canal 进行 MySQL binlog 同步
使用 Canal 监听 MySQL 的 binlog然后更新 Redis 缓存。
Component
public class CanalClient {Autowiredprivate RedisTemplateString, String redisTemplate;PostConstructpublic void init() {CanalConnector connector CanalConnectors.newSingleConnector(new InetSocketAddress(127.0.0.1, 11111), example, , );try {connector.connect();connector.subscribe(.*\\..*);while (true) {Message message connector.getWithoutAck(100);long batchId message.getId();ListCanalEntry.Entry entries message.getEntries();if (batchId ! -1 entries.size() 0) {for (CanalEntry.Entry entry : entries) {if (entry.getEntryType() CanalEntry.EntryType.ROWDATA) {CanalEntry.RowChange rowChange CanalEntry.RowChange.parseFrom(entry.getStoreValue());if (rowChange.getEventType() CanalEntry.EventType.UPDATE) {for (CanalEntry.RowData rowData : rowChange.getRowDatasList()) {// 处理更新操作更新Redis缓存updateRedisCache(rowData);}}}}}connector.ack(batchId);}} finally {connector.disconnect();}}private void updateRedisCache(CanalEntry.RowData rowData) {// 根据rowData更新Redis缓存// 这里需要根据具体的数据结构来实现}
}优点
实时性高对应用层代码无侵入
缺点
配置和维护相对复杂依赖 MySQL binlog 配置
总结
选择哪种方案取决于具体的业务需求、系统架构和性能要求。对于读多写少的场景可以考虑使用先更新数据库再删除缓存的策略。对于高并发场景可以考虑使用延迟双删或消息队列的方案。对于实时性要求高的场景可以考虑使用 Canal 进行 binlog 同步。无论选择哪种方案都需要考虑异常处理和重试机制以提高系统的可靠性。
在实际应用中可