实践_Redis开发规范

Redis开发规范

1. 背景与目的

为了让开发人员更合理的使用Redis,提升Redis服务的应用的可用性、可靠性和稳定性,缩短故障后服务恢复时间。

2. Redis规范

以下所有规范会按照【高危】、【强制】、【建议】三个级别进行标注,遵守优先级从高到低。

对于不满足【高危】和【强制】两个级别的设计,会强制打回要求修改。

2.1 key
  • 强制】key不要包含特殊字符。反例:包含空格、换行、单双引号以及其他转义字符。
  • 【建议】增强key的可读性和可维护性。说明:以特定业务含义字段为前缀(防止key冲突),用冒号分隔
  • 【建议】key应当尽量简洁。说明:保证语义的前提下,尽量控制key的长度,当key较多时,内存占用也不容忽视
2.2 value
  • 【建议】避免产生 bigkey。String类型,单个key的大小控制在10k以内。集合类型的key,容量一般不超过5000。
  • 【建议】选择适合的数据类型。说明:根据业务场景合理选择使用何种Redis数据类型,避免内存浪费。
2.3 过期时间
  • 强制】合理设置 Jedis 连接池配置,避免获取连接阻塞。说明:从 Jedis连接池获取连接时,如果连接池没有空闲连接,可能会导致应用的线程一直阻塞,进而无法继续处理任务。可以参考以下方法进行解决:
    (1) 设置 blockWhenExhausted 为 false,即获取不到空闲连接时,直接抛出异常,交给上层应用进行处理。
    (2) blockWhenExhausted 参数保持默认的 true,同时增加以下配置:maxWaitMillis: 不小于 0

  • 强制】Redis 客户端连接池 maxTotal 和 maxIdle 参数应在在同一数量级。建议maxTotal=maxIdle,或者 maxTotal 最大不能超过 maxIdle 的 120%。如果 maxTotal 与 maxIdle相差过大,可能会造成连接被频繁的创建和销毁,导致失去了连接池的意义。

    spring:
      jedis:
        pool:
          max-total: 20 #资源池中的最大连接数,默认值【8】
          max-idle: 20 #资源池允许的最大空闲连接数,默认值【8】
          min-idle: 2 #资源池确保的最少空闲连接数,默认值【0】 
          max-wait-millis: 3000 #当资源池连接用尽后,调用者的最大等待时间(单位为毫秒),默认值【-1】 
          test-on-borrow: true #向资源池借用连接时是否做连接有效性检测(ping)。检测到的无效连接将会被移除,默认值【false】 
          test-while-idle: true #向资源池归还连接时是否做连接有效性检测(ping)。检测到无效连接将会被移除,默认值【false】
          #以下配置不建议配置直接使用默认值
          block-when-exhausted: true #当资源池用尽后,调用者是否要等待。只有当值为true时,下面的maxWaitMillis才会生效,默认值【true】
          jmx-enabled: true #是否开启JMX监控,默认值【true】
          time-between-eviction-runs-millis: -1 #空闲资源的检测周期(单位为毫秒),默认值【-1】
          min-evictable-idle-time-millis: 1800000 #资源池中资源的最小空闲时间(单位为毫秒),达到此值后空闲资源将被移除,默认值【1800000】
          num-tests-per-eviction-run: 3 #做空闲资源检测时,每次检测资源的个数,默认值【3】
    
2.4 命令操作
  • 高危】禁止使用高危、阻塞式命令。例如:flush,flushall,keys,hgetall等。禁止遍历redis中的key。
  • 强制】禁止循环中操作redis。说明:循环中操作redis,容易将连接池中连接耗尽,导致服务不可用。
  • 【建议】非必要情况下不使用 monitor 命令,以防触发 OOM 异常。
  • 【建议】慎用复杂度过高的操作。例如sort,hgetall,smember,lrange等。

3. 注意事项

3.1 反序列化失败

描述:通常该问题表现为,对实体类进行修改以后,从redis取出旧数据时,无法反序列为新实体类。

解决方案:

  • 每个需要放入缓存的实体都应该实现Serializable接口,并指定serialVersionUID
  • 实体类添加注解@JsonIgnoreProperties(ignoreUnknown = true)
  • 开发时,尽量不对实体类原有字段做删减或修改
3.2 缓存一致性

描述:缓存数据库强一致性问题暂时没有绝对可靠的解决方案,我们只能尽可能的保证数据最终一致性。

解决方案:

  • 通用方案

    如果是读请求,先读缓存,后读数据库

    如果是写请求,先写数据库,在写缓存

    每次更新数据,都必须更新缓存或清除缓存

    设置合理的过期时间

  • 延时双删

    删除redis数据–>更新数据库数据–>延时等待500毫秒–>再次删除redis数据

3.3 缓存穿透

描述:当请求查询一定不存在的key时,会导致这个请求每次都会请求到数据库。

解决方案:

  • 在API入口对参数进行校验,过滤非法参数
  • 当首次查询数据库为空时,应将该空值缓存进redis
  • 使用布隆过滤器快速判断数据是否存在
3.4 缓存雪崩

描述:大量key的过期时间集中,导致该时间点,大量请求同时访问数据库

解决方案:

  • 差异化设置过期时间
  • 服务降级,核心业务访问达数据库,非核心业务返回预定义的信息
3.5 缓存击穿

描述:缓存击穿是指当缓存中某个热点数据过期了,在该热点数据重新载入缓存之前,有大量的查询请求穿过缓存,
直接查询数据库。这种情况会导致数据库压力瞬间骤增,造成大量请求阻塞,甚至直接挂掉。

解决方案:

  • 第一种是设置key永不过期。
  • 第二种是使用分布式锁, 保证同一时刻只能有一个查询请求重新加载热点数据到缓存中,这样,其他的线程只需等待该线程运行完毕,即可重新从Redis中获取数据。

你可能感兴趣的:(Java,项目实战,个人开发经验集,redis)