黑马程序员Redis教程学习笔记(第4部分):缓存同步与最佳实践

2026-04-02
1
-
- 分钟
|

黑马程序员Redis教程学习笔记(第4部分):缓存同步与最佳实践

课程概述

本篇笔记涵盖黑马程序员Redis教程中关于缓存同步策略与Redis最佳实践的重要内容,主要包括Canal缓存同步、多级缓存架构总结以及Redis键值设计最佳实践。

1. Canal缓存同步实现

Canal简介

Canal是阿里巴巴开源的MySQL数据库增量日志解析中间件,它伪装成MySQL的Slave节点,监听MySQL的binlog变化,实现数据的实时同步。

Canal工作原理

  • MySQL主从同步:MySQL主节点记录binlog文件,从节点读取并重放操作
  • Canal伪装:Canal伪装成MySQL从节点,监听binlog变化
  • 数据同步:当数据库发生变更时,Canal立即感知并通知缓存服务更新

Canal安装配置

1. 开启MySQL主从同步

修改MySQL配置文件my.cnf

# binlog文件位置和名称
log-bin=mysql-bin
# 监控的数据库
binlog-do-db=hmdp

2. 创建Canal用户并授权

-- 创建Canal用户
CREATE USER 'canal'@'%' IDENTIFIED BY 'canal';
-- 授权
GRANT SELECT, REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'canal'@'%';
-- 刷新权限
FLUSH PRIVILEGES;

3. Docker网络配置

# 创建网络
docker network create hmdp

# 将MySQL容器加入网络
docker network connect hmdp mysql

4. 运行Canal容器

docker run -p 11111:11111 --name canal \
  -e canal.destinations=hmdp \
  -e canal.instance.master.address=mysql:3306 \
  -e canal.instance.dbUsername=canal \
  -e canal.instance.dbPassword=canal \
  -e canal.instance.connectionCharset=UTF-8 \
  -e canal.instance.tsdb.enable=true \
  -e canal.instance.gtidon=false \
  --network=hmdp \
  -d canal/canal-server:v1.1.5

Canal客户端集成

1. 引入依赖

<dependency>
    <groupId>top.javatool</groupId>
    <artifactId>canal-spring-boot-starter</artifactId>
    <version>1.2.1-RELEASE</version>
</dependency>

2. 配置文件

canal:
  destination: hmdp  # 与Canal服务器配置保持一致
  server: 192.168.150.101:11111  # Canal服务器地址

3. 实体类注解

@Data
@NoArgsConstructor
@AllArgsConstructor
@TableName("tb_item")
public class Item {
    @TableId(type = IdType.ASSIGN_ID)
    private Long id;  // 主键映射
    
    private String name;
    private String title;
    private Long price;
    private String image;
    private String category;
    private String brand;
    
    @TableField(exist = false)  // 非表字段
    private Integer stock;
    
    @TableField(exist = false)  // 非表字段
    private Integer sold;
}

4. Canal处理器实现

@CanalTable("tb_item")
@Component
public class ItemHandler implements EntryHandler<Item> {

    @Autowired
    private RedisHandler redisHandler;

    @Override
    public void insert(Item item) {
        // 新增数据到缓存
        redisHandler.saveItem(item);
    }

    @Override
    public void update(Item before, Item after) {
        // 更新缓存数据
        redisHandler.saveItem(after);
    }

    @Override
    public void delete(Item item) {
        // 删除缓存数据
        redisHandler.deleteItemById(item.getId());
    }
}

5. Redis缓存操作封装

@Component
public class RedisHandler {
    
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    
    @Autowired
    private ObjectMapper objectMapper;
    
    public void saveItem(Item item) {
        try {
            String json = objectMapper.writeValueAsString(item);
            redisTemplate.opsForValue().set("item:" + item.getId(), json);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    
    public void deleteItemById(Long id) {
        redisTemplate.delete("item:" + id);
    }
}

2. 多级缓存架构总结

整体架构流程

浏览器/客户端 -> Nginx静态资源服务器 -> OpenResty负载均衡 -> Tomcat集群
                                    -> OpenResty本地缓存
                                    -> Redis缓存
                                    -> Tomcat进程缓存
                                    -> MySQL数据库

各层缓存策略

  1. 浏览器客户端缓存:静态资源缓存,通过304状态码优化
  2. Nginx本地缓存:基于URL哈希的负载均衡,确保相同商品请求路由到同一服务器
  3. OpenResty本地缓存:使用shared_dict实现进程间共享缓存
  4. Redis缓存:分布式缓存,支持集群部署
  5. Tomcat进程缓存:JVM进程内缓存,使用Caffeine实现

缓存同步策略

  • OpenResty本地缓存:使用过期时间策略,适合更新频率较低的数据
  • Redis缓存:通过Canal监听MySQL binlog实现数据同步
  • Tomcat进程缓存:同样通过Canal实现同步

3. Redis键值设计最佳实践

Key设计规范

  • 格式:使用冒号分隔的多段格式,如业务名:数据名:ID
  • 示例login:user:1001表示登录业务的用户ID为1001的用户信息
  • 长度:不超过150字节,避免使用特殊字符
  • 优势
    • 可读性强,便于理解
    • 避免key冲突
    • 便于管理,支持层级结构

Value设计考虑

1. BigKey问题识别

  • 字符串类型:大小不超过10KB
  • 集合类型:元素数量不超过1000个
  • 检测命令
    • MEMORY USAGE key:查看key占用内存
    • STRLEN key:查看字符串长度
    • LLEN key:查看列表长度
    • HLEN key:查看哈希长度
    • SCARD key:查看集合大小

2. BigKey问题危害

  • 网络阻塞:大key占用带宽,影响其他请求
  • 数据倾斜:导致Redis节点内存使用不均
  • Redis阻塞:单线程处理大key操作时阻塞其他请求
  • CPU占用:序列化/反序列化消耗大量CPU

3. BigKey检测方案

方案一:使用redis-cli –bigkeys
redis-cli -a 密码 --bigkeys
方案二:使用SCAN命令遍历
@Test
void testScan(){
    // 定义BigKey的阈值
    int strMaxLen = 10 * 1024; // 10KB
    int hashMaxLen = 500;       // 500个field
    
    long cursor = 0; // 游标
    do {
        // 扫描一批数据
        ScanResult<String> result = stringRedisTemplate.execute(RedisServerCommands::scan,
                new ScanOptions.ScanOptionsBuilder()
                        .match("*")
                        .count(100)
                        .build());
        cursor = Long.parseLong(result.getCursor());

        // 判断是否为BigKey
        List<String> keys = result.getResult();
        for (String key : keys) {
            // 获取数据类型
            DataType type = stringRedisTemplate.type(key);
            switch (type) {
                case STRING:
                    String value = stringRedisTemplate.opsForValue().get(key);
                    if (value != null && value.length() > strMaxLen) {
                        System.out.printf("发现BigKey: %s, 类型: %s, 长度: %d%n", key, type, value.length());
                    }
                    break;
                case HASH:
                    Long hashLen = stringRedisTemplate.opsForHash().size(key);
                    if (hashLen > hashMaxLen) {
                        System.out.printf("发现BigKey: %s, 类型: %s, 长度: %d%n", key, type, hashLen);
                    }
                    break;
                // 其他类型类似处理
            }
        }
    } while (cursor > 0);
}

4. BigKey解决方案

  • 删除策略
    • Redis 4.0+:使用UNLINK命令异步删除
    • Redis 4.0以下:使用SCAN遍历逐个删除集合元素,最后删除key
  • 拆分策略
    • 将大集合拆分为多个小集合
    • 使用合适的分片策略,如按ID范围或哈希分片

4. 缓存同步策略总结

常见同步策略对比

策略 优点 缺点 适用场景
有效期控制 简单方便,无代码入侵 实时性差,存在数据不一致期 更新频率低、实时性要求低的业务
同步双写 实时性强,数据一致性高 代码侵入度高,耦合度高 对一致性要求极高的业务
异步通知 低耦合,代码侵入少 实时性相对较差 对实时性要求不高、多服务同步场景

Canal同步优势

  • 零代码入侵:无需修改业务代码
  • 高实时性:基于binlog监听,延迟极低
  • 低耦合:业务与缓存同步完全分离
  • 高效能:避免了消息队列的额外开销

总结

本篇笔记详细介绍了多级缓存架构中的缓存同步机制和Redis最佳实践:

  1. Canal缓存同步:通过监听MySQL binlog实现数据的实时同步,具有零代码入侵、高实时性等优势
  2. 多级缓存架构:从浏览器到数据库的多层缓存体系,极大提升了系统性能
  3. 键值设计规范:合理的Key命名规范和BigKey问题处理,确保Redis的高性能运行
  4. 缓存同步策略:不同场景下选择合适的同步策略,平衡性能与一致性

这些最佳实践对于构建高性能、高可用的Redis缓存系统具有重要意义,有助于在实际项目中避免常见问题并优化系统性能。

评论交流

文章目录