欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

项目开发中如何定义Redis 使用规范

程序员文章站 2022-06-27 21:08:25
一. SDK选择目前Java平台Redis的使用一般为以下三种客户端 Jedis使用Redis原生数据结构,比较全面的提供了Redis的操作特性数据结构过于简单,需根据实际情况自行设计所需数据结构轻量,简洁,便于集成和改造非线程安全,需要使用连接池支持pipelining、事务、LUA Scripting、Redis Sentinel、Redis Cluster使用RedisCluster时不支持pipelining不支持读写分离,不支持异步,需要自己实现...

从个人实践经验,从SDK选择,键值设计,命令使用方面总结以下几点

一. SDK选择

目前Java平台Redis的使用一般为以下三种客户端

  1.    Jedis

    1. 使用Redis原生数据结构,比较全面的提供了Redis的操作特性
    2. 数据结构过于简单,需根据实际情况自行设计所需数据结构
    3. 轻量,简洁,便于集成和改造
    4. 非线程安全,需要使用连接池
    5. 支持pipelining、事务、LUA Scripting、Redis Sentinel、Redis Cluster
    6. 使用RedisCluster时不支持pipelining
    7. 不支持读写分离,不支持异步,需要自己实现
    8. 缺乏完善的文档
    9. Springboot2之前作为spring-data-redis组件的底层连接组件,之后被Lettuce取代
  2. Redisson
    1. 基于Netty实现,采用非阻塞IO,系统资源利用率高
    2. 对Redis原生数据结构进行了封装,实现了java中的Set,List,Map,Multimap,Queue,BlockingQueue等数据结构
    3. 实现了各类分布式锁,实现了基于Redis的简易MQ队列
    4. 提供了底层Redis客户端用以实现目前未封装的原生命令
    5. 支持Redis异步操作
    6. RedissonClient单例模式下线程安全,支持连接池
    7. 支持pipelining、LUA Scripting、Redis Sentinel、Redis Cluster
    8. 支持在Redis Cluster架构下使用pipelining
    9. 支持读写分离,支持读负载均衡,在主从复制和Redis Cluster架构下都可以使用
    10. 支持API级别的事务操作
    11. 支持与Springboot的集成,提供了spring-session-redisson等组件
    12. 文档较丰富,有官方中文文档
  3. Lettuce
    1. 基于Netty实现,采用非阻塞IO,系统资源利用率高
    2. 高级Redis客户端,用于线程安全同步,异步和响应使用,支持集群,Sentinel,pipelining和编码器。
    3. springboot2集成spring-data-redis的官方首选客户端
    4. 文档资料较少

二 . 键值设计

  1. Key名设计
    1. 可读性和可管理性【强制】
      1. 以系统名:业务名(或数据库名)为前缀(防止key冲突),用冒号分隔,比如业务名:表名:id
      2. 例: LSXD:CUSTOMER:000001
    2. 简洁性
      1. 保证语义的前提下,控制key的长度,当key较多时,内存占用也不容忽视
      2. 例: user:{uid}:friends:messages:{mid}简化为u:{uid}:fr:m:{mid}。
    3. 不要包含除了 下划线_ 中划线- 之外的特殊字符【强制】
      1. 例: LSXD:CUS_INFO:000001
      2. 反例:包含空格、换行、单双引号以及其他转义字符
    4. 合适的key,便于查看,统计,排错。【强制】
      1. ":"-作为key分隔符,方便客户端工具作为目录分级
  2. Value设计
    1. 拒绝bigkey(即一个key下的value过大,防止网卡流量、慢查询)【强制】
      1. 对于访问量较大的数据,Value长度控制在2KB以内,其他数据大小尽量控制在10KB以内,hash、list、set、zset元素个数不要超过5000,对于过大的数据集合,按实际情况考虑分割等方式存储
      2. 反例:一个包含200万个元素的list。
      3. 非字符串的bigkey,不要使用del删除,使用hscan、sscan、zscan方式渐进式删除,同时要注意防止bigkey过期时间自动删除问题(例如一个200万的zset设置1小时过期,会触发del操作,造成阻塞,而且该操作不会不出现在慢查询中(latency可查)),查找方法和删除方法【非强制】
    2. 选择适合的数据类型
      1. 应根据所需数据结构选择合适的数据类型如List,Map,Bucket等数据结构
      2. 注意在数据结构与该数据占用内存之间取得平衡
      3. 对于java实体类型,注意缩小数据字段,减小内存消耗,提高性能【建议】
  3. 控制Key的生命周期
    1. 建议使用expire设置过期时间(条件允许可以打散过期时间,防止集中过期),不过期的数据重点关注数据刷新时间
  4. 数据压缩
    1. 对于必须要存储的大文本数据(超过10KB)建议压缩后存储

三 . 命令使用

  1. O(N)命令关注N的数量
     
    1. 例如hgetalllrangesmemberszrangesinter等并非不能使用,但是需要明确N的值。有遍历的需求可以使用hscansscanzscan代替
       
  2. 禁止使用Keys正则(模糊)匹配操作【强制】
     
    1. Redis是单线程处理,在线上Keys数量较多时,操作效率极低【时间复杂度为O(N)】,该命令一旦执行会严重阻塞线上其它命令的正常请求,而且在高QPS情况下会直接造成Redis服务崩溃!如果有类似需求,请使用scan命令代替
       
  3. 禁用命令
    1. 禁止线上使用keys、flushall、flushdb等,通过redis的rename机制禁掉命令,或者使用scan的方式渐进式处理
  4. 合理使用select
    1. redis的多数据库较弱,使用数字进行区分,很多客户端支持较差,同时多业务用多数据库实际还是单线程处理,会有干扰
  5. 使用批量操作提高效率
    1. 批处理方式
      1. 原生命令:例如mget、mset
      2. 非原生命令:可以使用pipeline提高效率,但要注意控制一次批量操作的元素个数(例如500以内,可根据每个元素占用的内存调节批量操作允许的最大元素数)
    2. 注意原生命令和非原生命令的不同
      1. 原生命令是指原子操作,pipeline是非原子操作
      2. pipeline可以打包不同的命令,原生做不到
      3. pipeline需要客户端和服务端同时支持
    3. 灵活使用各客户端提供的批处理操作(如Redisson基于pipelining的RBatch接口)
  6. Redis事务功能较弱,不建议过多使用
    1. Redis原生的事务功能较弱(不支持回滚),而且集群版本(自研和官方)要求一次事务操作的key必须在一个slot上(可以使用hashtag功能解决)
    2. Redisson完整实现了事务的提交与回滚,但仍然无法应用于Redis集群,只能支持单节点与哨兵模式
    3. 大部分Redis的事务都只能应用于Redis操作本身,无法与其他(如数据库事务)作用于同一个事务域
      1. 注:Redisson的收费(Pro)版提供了XA事务接口,可与其他支持的数据库(如Oracle)同时开启JTA事务,但仍然不建议使用

参考资料:

书籍:Redis开发与运维(付磊)

本文地址:https://blog.csdn.net/Ronin_88/article/details/107490993

相关标签: Redis