Redis最佳实践

Redis最佳实践

Redis键值设计

优雅的key结构
  • 遵循基本格式:[业务名称]:[数据名]:[id] eg:login:user:10
  • 长度不超过44字节:key为string类型,底层编码为int,embstr和raw(>44)三种。embstr在小于44字节使用,采用连续内存空间,占用小。
  • 不包含特殊字符
拒绝BigKey

BigKey通常以key的大小和key中成员的数量来综合判断,例如:

  • key本身的数据量过大:一个string类型的key,它的值为5MB
  • key中的成员数过多:一个ZSET类型的key,他的成员数量为10000个
  • ke0y中成员的数据量过大:一个Hash类型的key,它的成员数量虽然只有1000个,但value总大小为100MB

扩展:查看key大小:MEMORY USAGE key/value 简单:STRLEN key/LLEN key
推荐:1.单个key的value小于10KB 2.对于集合类型的key,建议元素数量小于1000

BigKey危害
  • 网络阻塞:对BigKey执行读,少量QPS就可能导致贷款使用率被占满,导致Redis变慢
  • 数据倾斜:BigKey所在的内存使用率远超其他实例,无法使数据分片的内存资源达到平衡
  • Redis阻塞:对元素较多的hash,list,zset等做运算会耗时较久,使主线程阻塞
  • CPU压力:对BigKey的数据序列化和反序列化会导致CPU飙升,影响Redis实例和本机其他应用。

如何发现BigKey:

  • redis-cli --bigkeys:可遍历所有key,返回key整体统计信息与每个数据的Top1的bigkey
  • scan扫描:自己编程,利用strlen,hlen等命令判断key长度(不建议用MEMORY USAGE)
  • 第三方工具:Reids-Rdb-Tools分析RDB快照文件
  • 网络监控:自定义工具,监控进出Reids的网络数据,超出预警值主动警告

如何删除BigKey:

  • 小于redis3:集合类型遍历所有key,先逐个删除子元素,最后删除BigKey
  • 大于redis4:异步删除命令:unlink
恰当的数据结构

推荐hash按照key打散,底层使用zipList,空间占用小,可灵活访问对象的任意字段,不推荐直接存jsonstring,hash和单个key数据
注意:hash的Entry数量超过500,会使用hash表而不是ZipList,可以调整hash-max-ziplist-entries配置entry上限,设置太大也会BigKey。

总结

key:固定格式,简短,不包含特殊字符
value:合理拆分,不BigKey。合适的数据结构。hash结构entry数量不超过1000。设置合理的超时时间。

批处理优化(如何优雅的处理海量数据)

Pipeline-大数据导入方式

MSET,HSET方式:
N条命令的批处理行:1次网络传输时间+N次Redis执行耗时
注意:不要在一次批处理中传输太多命令,否则单次命令占用带宽过多,会导致网路阻塞。

//按照奇偶数批量插入数据
void test{
    String[] arr = new String[2000];
    int j;
    for(int i = 0; i <= 10000; i++){
        j = (i%1000) << 1;
        arr[j] = "test:key_" + i;
        arr[j + 1] = "value_" + i;
        if(j == 0){  //当j=0时表示一组数据(1000)满了
            jedis.mset(arr);
        }
    }
}

缺点:格式固定只能操作基础数据类型,不能扩展复杂数据,建议使用Pipeline
Pipeline:

void testPipeline(){
    //创建管道
    Pipeline pipeline = jedis.pipelined();
    for(int i = 1; i<= 100000; i++){
        //放入命令到管道
        pipeline.set("test:key_" + i, "value_" + i);
        //pipeline.hset("test:key_" + i, "value_" + i);
        if(i % 1000 = 0){
            //每放入1000条命令,批量执行
            pipeline.sync();
        }
    }
}
总结:

批处理方案:原生M操作。Pipeline批处理
注意事项:批处理时不建议一次携带太多命令。Pipeline的多个命令之间不具备原子性

集群下的批处理

如MSET或Pipeline这样的操作需在一次请求中携带多条命令,而redis是集群那么批处理命令的多个key必须落在一个插槽内,否则就会执行失败。
spring底层采用并行slot,lettuce。springRedisTemplate.opsForValue().multiSet(map);:底层实现异步分区asynslot根据key计算插槽,把插槽一样的放在一个集合。
《图:批处理解决方案》

服务端优化

持久化配置

Redis持久化虽然可以保证数据安全,但会带来额外开销,需遵循以下建议:

  1. 用来做缓存的Redis实例尽量不要开启持久化
  2. 建议关闭RDB,使用AOF
  3. 利用脚本定期在salve节点做RDB,实现数据备份
  4. 设置合理的rewrite阈值,避免频繁bgrewrite
  5. 配置no-appendfsync-no-rewrite=yes(追求安全性配置no,性能yes),禁止在rewrite期间做aof,避免AOF引起的阻塞。

部署建议:

  1. Redis实例的物理机要预留足够内存,应对fork和rewrite
  2. 单个Redis实例内存上限不要太大,eg:4/8G,可以加快fork的速度,减少主从同步,数据迁移的压力。
  3. 不要与CPU密集型应用部署在一起。
  4. 不要与高硬盘负载应用一起部署。eg:数据库,消息队列。
慢查询

在Redis执行时耗时超过某个阈值的命令,成为慢查询。由于Redis单线程,客户端发送指令后会在服务端入队等待执行,超过阈值则报错。
慢查询的阈值配置:slowlog-log-slower-than:慢查询阈值,微秒。默认10000,建议1000
慢查询会被存入日志,日志长度配置:slowlog-max-len:默认128,建议1000
查询慢查询:slowlog get[n]
清空慢查询列表:slowlog reset

命令及安全配置

Redis会绑定在0.0.0.0:6379,这样将会将Redis服务暴露在公网,而redis没做身份认证,会出现严重的安全漏洞。
Redis未授权访问配合SSH key:https://cloud.tencent.com/developer/article/1039000
漏洞原因:

  • Redis暴露到公网,且没有密码
  • 利用了Redis的config set命令动态修改Redis配置
  • 使用了Root账号权限启动Redis

建议:

  1. 一定要设置密码,开启防火墙,不使用默认端口,不使用root账户启动redis
  2. 禁止线上使用:keys,flushall,flushdb,config set等命令。可利用rename-command禁用。
  3. bind:限制网卡,禁止外网网卡访问。
内存配置

当redis内存不足,会导致key频繁被删除,响应时间变长,QPS不稳定。内存占用超过90%就需要注意。
《图:内存配置》

  • 数据内存:BigKey,内存碎片 主要
  • 进程内存:redis进程占用内存(代码,常量池) 可忽略
  • 缓冲区内存:客户端缓冲区(输入,输出),AOF缓冲区,复制缓冲区。 波动大

Redis查看内存分配命令:info memory;memory xxx
内存缓冲区配置:

  • 复制缓冲区:主从复制的repl_backlog_buf,如果太小可能导致频繁的全量复制,影响性能。通过repl-backlog-size来设置。默认1mb
  • AOF缓冲区:AOF刷盘之前的缓存区域,AOF执行rewrite的缓冲区,无法设置容量上限。
  • 客户端缓冲区:分为输入输出缓冲区,输入缓冲区最大1G且不能设置。输出可以。

集群最佳实践

集群还是主从?集群存在一些问题:

  1. 集群完整性问题-reids默认配置中,如果发现一个插槽不可用,整个集群都会停止。建议设置为false
  2. 集群带宽问题-集群节点之间会不断的ping来确定集群中其他节点的状态,每次ping都会包含插槽信息集群状态信息

集群节点越多,集群状态信息数据量也越大,10个节点的相关信息可能达到1kb,此时每次集群互通需要的带宽非常高。
解决:
① 避免大集群,最好小于1000
② 避免在单个物理机中运行太多的Redis实例
③ 配置合适的cluster-node-timeout值

  1. 数据倾斜问题-bigkey或者批处理时使用相同的hashkey从而导致部分节点负担较重
  2. 客户端性能问题-节点的选择,读写分离的判断,插槽的判断
  3. 命令的集群兼容性问题-批处理问题方案
  4. lua和事务问题-集群下不好保证
    注意:单体Redis(主从)已经能达到万级别的QPS,并且也具备很强的高可用特性。如果主从能满足业务需要的情况下,尽量不要搭建Reids集群。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值