您觉得本文档还缺少什么内容?可以自己补充~

redis 配置

bc:
  cache:
    type: REDIS
  redis:
    ip: 10.10.20.233
    port: 6379
    # redis 的密码,没有配置密码的改成单引号的空字符串: ''
    password: ''
    database: 0

spring:
  cache:
    type: GENERIC
  redis:
    host: ${bc.redis.ip}
    password: ${bc.redis.password}
    port: ${bc.redis.port}
    database: ${bc.redis.database}

修改redis缓存的序列化类型

bc:
  cache: 
    serializerType: ProtoStuff  # 可选值: ProtoStuff   JDK    JACK_SON

redis 是否缓存null 值

bc:
  cache: 
    cacheNullVal: true

缓存的key不就是一个字符串吗,为啥要给每个key单独封装成一个类 (XxxCacheKeyBuilder)?

  • 问题1: 缓存key冲突,不能识别不同模块、不同业务的缓存(如相同的用户id和商品id不做任何修改,直接作为Redis的key,就可能会导致key冲突)
  • 问题2: 张三存储用户缓存时,使用了user:1 作为key存储, 李四操作用户缓存时,由于手误使用了usr:1 来操作同一个用户缓存。王五来接手项目时,以为没人用过缓存,又使用userinfo:1 来操作用户缓存。
  • 问题3: 不同的开发人员水平参差不齐,有些人甚至重来没用过缓存,不知道如何命名key。 张三的key以: 作为分割符、 李四用_ 、王五用驼峰。
  • 问题4:素质差的开发,直接就使用 魔法数,素质高的开发,会将key抽成 常量
  • 问题5: 张三用 user:1 来存储用户对象, 李四却用user:1 来存储用户的姓名。 (XxxCacheKeyBuilder 并没有解决此问题,欢迎留言讨论解决方案)
  • 问题6: 过期时间到底设置为多少?
  • 其他问题...

为了解决以上问题, 所以必须封装出一套缓存key的生成器,隐藏缓存key的生成细节,让开发者拿来即用,传入动态参数,即可返回全平台统一规则的 key。 所以,本系统封装的CacheKeyBuilder封装了以下功能:

  • 保证key的唯一性,体现了可靠性。
  • 统一的命名规则,体现了可读性。
  • 每个CacheKeyBuilder表示一种业务类型的缓存,体现了单一职责。
  • 隐藏key的字符串拼接细节, 减少出错概率。 体现了可靠性。
  • 统一设置过期时间

当然,本系统采取了一个key封装成一个对象的方式,来解决上述问题。 如果你觉得太重,可以使用一个方法来封装一个key也行。

  • key命名风格 【推荐】 Redis key命名需具有可读性以及可管理性,不该使用含义不清的key以及特别长的key名; 【强制】以英文字母开头,命名中只能出现小写字母、数字、英文点号(.)和英文半角冒号(:); 【强制】不要包含特殊字符,如下划线、空格、换行、单双引号以及其他转义字符;
  • 命名规范 【强制】命名规范:[租户编码:][服务模块名:]业务类型[:业务字段][:value类型][:业务值] 1)租户编码: 可选。 用来区分不同租户数据缓存。 如: 内置租户用0000。 2)服务模块名:可选。 用来区分不同服务或功能模块的缓存。 如: 仅在权限服务使用和仅在消息服务使用的缓存分别用authority和msg来区分,多个服务共用的缓存可以不设置该段,或者设置为common。 3) 业务类型: 必填。 用来区分不同业务类型的数据缓存。 通常设置为表名。 同一key有多个业务类型时, 使用英文半角点号 (.)分割,用来表示一个完整的语义。 如user.activity 表示存储用户和活动、 user表示存储用户如:用户表、应用表分别用 user、application来区分。 4) 业务字段: 可选。用来区分业务值是那个字段。 通常设置为字段名。 同一key有多个业务类型时,业务字段对应多个业务类型。使用英文半角点号 (.)分割,用来表示一个完整的语义。 如业务类型为 user.activity 表示存储用户和活动, 则应该用id.iduser.activity 对应,表示key中包user的id 和 activity的id 5) value类型: 可选。 用来区分value。 Redis key命名包含key所代表的value类型,以提高可读性。 如: obj 表示value是对象,number表示value是数字, string 表示value是字符串。 6) 业务值 :可选。 用来区分同一业务类型的不同行的数据缓存。如:用户表id为1的数据和id为2的,分别是指该值为1和2。

示例:

注意: => 左边表示缓存的完整key , => 右边表示缓存存储的值

  • tenant:Id:1:obj => {"id:":1, "name:"租户1"} 表示:租户表(tenant)的租户id(id)为 1 的数据,存储(obj)类型的值 ({"id:":1, "name:"租户1"})
  • 0000:authority:user:Id:1:obj => {"id:":1, "name:"张三"} 表示:租户(0000),权限服务(authority)中用户表(user)的用户id(id)为 1 的数据,存储(obj)类型的值 ({"id:":1, "name:"张三"})
  • 0000:authority:user:account:zhangsan:obj => {"id:":1, "name:"张三"} 表示:租户(0000),权限服务(authority)中用户表(user)的用户账号(account)为 zhangsan 的数据,存储(obj)类型的值 ({"id:":1, "name:"张三"})
  • key 设计 【强制】:拒绝bigkey(防止网卡流量、慢查询)。 String类型控制在10KB以内,Hash、List、Set、ZSet元素个数不要超过5000。 【强制】禁止大key。 大key数据存⼊Redis,除了带来极大的内存占用外,在并发高时,很容易就会将网卡流量占满,进而造成整个服务器上的所有服务不可用。虽然Redis支持512MB大小的string,但是假设1mb的string大key,每秒重复写入10次,就会导致写入网络IO达10MB; (1) 读写大key会导致超时严重,网卡流量占满,甚至阻塞服务,更甚者导致宕机风险。 (2) 如果删除大key,DEL命令可能阻塞Redis进程数十秒,使得其他请求阻塞,对应用程序和Redis集群可用性造成严重的影响。 (3) 每个key不要超过10Kb。

代码中如何直接使用缓存

  1. 继承带缓存的父类 SuperCacheServiceImpl 、SuperCacheService、SuperCacheController 后, 操作单体时,即可使用共用的缓存。 子类继承SuperCacheServiceImpl 后,需要实现 cacheKeyBuilder 方法,用于构造缓存的前缀。 如:
public class UserServiceImpl extends SuperCacheServiceImpl<UserMapper, User> implements UserService {
    @Override
    protected CacheKeyBuilder cacheKeyBuilder() {
        return new UserCacheKeyBuilder();
    }
}
public class UserCacheKeyBuilder implements CacheKeyBuilder {
    @Override
    public String getPrefix() {
        return "USER";
    }

    @Override
    public Duration getExpire() {
        return Duration.ofHours(24);
    }
}

实现 cacheKeyBuilder 方法后,调用UserService的getById、updateById、removeById等方法时,会自动存取或淘汰key-value类型的用户缓存, 缓存的key格式为: {TENANT}:USER:{id} , 储存的value为user对象。

如何设置缓存的有效期

  1. 永不过期
@Override
public Duration getExpire() {
    return null;
}
  1. 指定过期时间
@Override
public Duration getExpire() {
    return Duration.ofHours(24); // 24  小时候过期
}

如何自定义使用缓存?

  1. 注入CacheOps 或 CachePlusOps
@Resouce
private CacheOps cacheOps;  // 普通功能, key - value 存取
@Resouce
private CachePlusOps cachePlusOps;   // 增强功能,包含redis的高级api
@Resouce
RedisOps redisOps;   // 增强功能,包含redis的大部分 api ,若你的项目大量需要使用redis ,且不用考虑支持其他缓存,可以直接使用RedisOps
  1. 创建CacheKeyBuilder
public class UserCacheKeyBuilder implements CacheKeyBuilder {
    @Override
    public String getPrefix() {
        return "USER";    // 缓存的前缀,用以区分不同类型的缓存, 必须跟其他类型保持唯一!!!
    }

    @Override
    public Duration getExpire() {
        return Duration.ofHours(24);  // 缓存过期时间, 返回 null 则永不过期
    }
}
  1. 使用
User user  = userMapper.selectById(123);
CacheKey cacheKey = new UserCacheKeyBuilder ().key(user.getId());
cacheOps.set(cacheKey,  user);  // 设置

// 查询
User cacheUser = cacheOps.get(cacheKey);

//  淘汰
cacheOps.del(cacheKey);


cachePlusOps.keys('*user*');  // 模糊搜索key
cachePlusOps.scanUnlink('*user*');  // 模糊淘汰key    

// 参考源码, redisOps  支持 hash set list  zset 等api

内存建议

  1. 控制key的长度
  2. 避免存储bigkey
  3. 选择合适的数据类型
  4. key设置过期时间
  5. 实例设置maxmemory
  6. 数据插锁后写入Redis

性能建议

  1. 避免存储bigkey
  2. 4.0+ 版本开启lazy-free
  3. 不使用复杂度过高的命令
  4. O(N) 命令关注N的大小
  5. 关注DEL时间复杂度
  6. 批量命令代替单个命令
  7. 推荐使用Pipeline
  8. 避免集中过期key
  9. 使用长连接操作 Redis
  10. 只使用db0
  11. 读请求量大,使用读写分离
  12. 写请求量大,使用分片集群
  13. 不开AOF或AOF配置没秒刷盘
  14. 非虚拟机部署Redis
  15. 关闭操作系统内存大页

可靠性建议

  1. 按业务线部署实例
  2. 部署主从集群防止数据丢失
  3. 关注主从复制参数
  4. 部署哨兵实现故障自动切换

资源规划建议

  1. 保证机器有足够的CPU/内存/带宽/磁盘资源
  2. 主库机器预留一半的内存资源
  3. 实例内存控制在10G以下

监控建议

  1. CPU/内存/带宽/磁盘不足预警
  2. slowlog 过多监控工预警
  3. 避免频繁短链接采集INFO信息
  4. 重点关注expired_keys/evicted_keys/latest_fork_usec

Redis 安全建议

  1. 不要把 Redis 部署在公网可访问的服务器上
  2. 部署时不使用默认端口 6379
  3. 以普通用户启动 Redis 进程,禁止 root 用户启动
  4. 限制 Redis 配置文件的目录访问权限
  5. 推荐开启密码认证
  6. 禁用/重命名危险命令(KEYS/FLUSHALL/FLUSHDB/CONFIG/EVAL)

日常运维建议

  1. 禁用 (KEYS/FLUSHALL/FLUSHDB/CONFIG/EVAL)
  2. 扫描线上实例,设置休眠时间
  3. 慎用monitor命令
  4. 从库必须设置read-only
  5. 合理配置timeout 和 tcp-keepalive 参数

results matching ""

    No results matching ""