当前位置: 首页 > news >正文

Redis最佳实践

文章目录

  • Redis的键值设计
    • key的设计
    • BigKey
    • 选择最适合的数据结构
  • 2. 批处理优化
    • 2.1 Pipeline
    • 集群下的批处理
  • 持久化配置

Redis的键值设计

key的设计

Redis的key设置遵从的几个规则

  • 遵循基本格式:[业务名]:[数据名]:[数据id]
  • 长度不超过44字节
  • 不包含特殊字符

如:登录业务保存用户数据 key可以设置为 login:user:10
分层的key结构设计优点

  • 1.可读性强
  • 2.避免key冲突
  • 3.方便管理

为什么不超过44字节?
:key结构默认为string,但是其底层编码有三种,根据不同情况

  • 1.当全是数字的时候存储为int,消耗内存最低
  • 2.有字符,但是不超过44字节,按照embstr编码方式存储,该存储方式使用连续内存空间,内存占用更小
  • 3.有字符超过44字节,采用raw存储方式,采用指针指向真正存储字符串的地方,空间不连续,访问时性能会收到一定的影响,有可能产生内存碎片。注:key和value(string类型时)都遵循这种规则

BigKey

BigKey是什么?

BigKey通常以Key的大小和Key中成员的数量来综合判定(如果没有成员只看大小即可),例如:

  • Key本身的数据量过大:一个String类型的Key,它的值为5 MB
    String是单值的,最大存储为512M,达到5M就是一个非常大的k了。
  • Key中的成员数过多:一个ZSET类型的Key,它的成员数量为10,000个
    集合类型的key,比如list,set,成员数量达到1万个就会认为是BigKey。
  • Key中成员的数据量过大:一个Hash类型的Key,它的成员数量虽然只有1,000个但这些成员的Value(值)总大小为100 MB
  • 还有一些集合元素数量并不算多,但是每个成员都非常的大,最后合起来达到了100M,也会被称为BigKey。

在这里插入图片描述
推荐值:单个key的value值小于10KB,元素数量小于1000

BigKey的危害

在这里插入图片描述

如何发现BigKey

单个key分析

我们可以通过如下两个命令判断是否为bigkey

  • STRLEN key:查看String类型的value的字节长度/字符长度(一个字符占一个字节)
  • LLEN key:查看list集合的长度

全盘扫描

①redis-cli --bigkeys
利用redis-cli提供的–bigkeys参数,可以遍历分析所有key,并返回Key的整体统计信息与每个数据的Top1的big key

命令:redis-cli -a 密码 --bigkeys

注意:

  • 不要在redis的控制台运行,而是在黑窗口运行。

  • 得到的是每一种数据类型占用内存最多的那一个,排名第一的不一定是bigkey,即使第一个是bigkey那排名第二的也可能是bigkey,只显示排名第一可能就把排名第二的bigkey错过了。

  • 这种方式的统计不够完整只能看到第一名,因此只做一个参考。

这种方式只能看到每种元素对应最大,而且他list是以元素计的,不是字节数,所以可能第二个比第一个占用字节还要大
在这里插入图片描述

第三方工具
利用第三方工具,如 Redis-Rdb-Tools 分析RDB快照文件,全面分析内存使用情况
https://github.com/sripathikrishnan/redis-rdb-tools
好处:对redis无侵入

缺点:它是离线方式,所以时效性比较差。

②第三方工具

  • 利用第三方工具,如 Redis-Rdb-Tools 分析RDB快照文件,全面分析内存使用情况
  • https://github.com/sripathikrishnan/redis-rdb-tools

好处:对redis无侵入

缺点:它是离线方式,所以时效性比较差。

③网络监控

  • 自定义工具,监控进出Redis的网络数据,超出预警值时主动告警
  • 一般阿里云搭建的云服务器就有相关监控页面(阿里云上部署redis)
    在这里插入图片描述

如何删除BigKey?

找到BigKey后该怎么办呢?

首先:删除BigKey,但是不是说这部分数据不要了,而是把这份数据拆分后重新储存,这样就把BigKey打散了。
其次:选择合适的数据类型,分别存储,这样BigKey就变为小的key了。
BigKey内存占用较多,即便时删除这样的key也需要耗费很长时间,导致Redis主线程阻塞,引发一系列问题。

redis 3.0 及以下版本
如果是集合类型,则遍历BigKey的元素,先逐个删除子元素,最后删除BigKey
这里具体实现不说了,可以自己查一下

Redis 4.0以后
Redis在4.0后提供了异步删除的命令:unlink key(异步的删除key)
在这里插入图片描述

选择最适合的数据结构

例1:比如存储一个User对象,我们有三种存储方式
在这里插入图片描述
方式一:json字符串
挺平常的,如果是我的话我会用这种,来应对,读多写少的场景,因为json可以直接返回给前端不需要麻烦的处理

方式二:字段打散
原来一个key就能保存现在需要多个key,虽然从数据上看没有增多,但是每一次存储k-v结构在redis内部都是有很多原信息要保存的,key越多现在想要存储的元信息也越多。
现在想要获取user的所有信息,只能是一条条的获取。

方式三:hash(推荐)
v是一个hash结构

使用hash结构的时候,需要把user对象转化为hashmap的形式去存储,转化的时候考虑到对象的数据类型的转换,相较于json麻烦。

而json因为相对比较成熟,对象与json的序列化和反序列化都有非常成熟的解决方案了,不用考虑太多数据类型的问题。

不过市面上应该已经有成熟的工具类去帮我们做这个转换操作了,所以还是推荐这种方式

例2:假如有hash类型的key,其中有100万对field和value,field是自增id,这个key存在什么问题?如何优化?

keyfieldvalue
someKeyid:0value0
id:999999value999999

问题:
内存占用大

  • 上面学写过hash结构底层使用ziplist,空间占用小。但是当hash的entry数量超过500时,会使用哈希表而不是ZipList,内存占用较多
  • entry:一对k-v

解决方案

拆分为小的hash,将 id / 100 作为key, 将id % 100 作为field,这样每100个元素为一个Hash

解释:

  • 将 id / 100 作为key:id是0~999999的100万条数据,100万除以100为1万条数据,也就是说将来会有1万个key,把一个hash拆分成了一万个hash,100万条数据放到1万个hash里每个hash有100条数据,没有超过500,底层用的还是ziplist。
  • 将id % 100 作为field:
    0~99一共100条id,这些id除以100结果都是0作为key,这些id取模的结果恰好是0到99,刚好形成一个hash。
    100~199这些元素,除以100结果都是1作为key,取余是0到99。
    在这里插入图片描述
    这个方法需要自己编程实现

2. 批处理优化

2.1 Pipeline

2.1.1 单个命令的执行流程
一次命令的响应时间 = 1次往返的网络传输耗时 + 1次Redis执行命令耗时
在这里插入图片描述
2.1.2 N条命令依次执行
N次命令的响应时间 = N次往返的网络传输耗时 + N次Redis执行命令耗时

在这里插入图片描述
2.1.3 N条命令批量执行
N次命令的响应时间 = 1次往返的网络传输耗时 + N次Redis执行命令耗时

在这里插入图片描述
2.1.4 MSET和Pipeline
Redis提供了很多Mxxx这样的命令,可以实现批量插入数据,如:mset、hmset。

原生的批处理命令(相同结构的v可以一起批处理)

// 定义要设置的key-value对
Map<String, String> keyValueMap = new HashMap<>();
keyValueMap.put("key1", "value1");
keyValueMap.put("key2", "value2");// 使用mset方法设置key-value对
redisTemplate.opsForValue().multiSet(keyValueMap);

MSET虽然可以批处理,但是却只能操作部分数据类型,因此如果有对复杂数据类型的批处理需要,建议使用Pipeline功能:

pipeline 一次性可以插入不同的k-v(v结构不同也可以批处理)

List<Object> results = redisTemplate.executePipelined(new RedisCallback<Object>() {public Object doInRedis(RedisConnection connection) throws DataAccessException {connection.set("key1".getBytes(), "value1".getBytes());connection.get("key1".getBytes());connection.set("key2".getBytes(), "value2".getBytes());connection.get("key2".getBytes());return null;}
});for (Object result : results) {System.out.println(result);
}

注意:

批处理时不建议一次携带太多命令
Pipeline的多个命令之间不具备原子性

集群下的批处理

如MSET或Pipeline这样的批处理需要在一次请求中携带多条命令,而此时如果Redis是一个集群,那批处理命令的多个key必须落在一个插槽中,否则就会导致执行失败。

串行命令串行slot并行slothash_tag
实现思路for循环遍历,依次执行每个命令在客户端计算每个key的slot,将slot一致分为一组,每组都利用Pipeline批处理。串行执行各组命令 在客户端计算每个key的slot,将slot一致分为一组,每组都利用Pipeline批处理。将所有key设置相同的hash_tag,则所有key的slot一定相同
耗时N次网络耗时 + N次命令耗时m次网络耗时 + N次命令耗时 m = key的slot个数1次网络耗时 + N次命令耗时1次网络耗时 + N次命令耗时
优点实现简单耗时较短耗时非常短耗时非常短、实现简单
缺点耗时非常久实现稍复杂 slot越多,耗时越久实现复杂容易出现数据倾斜

注:spring环境下默认使用第三种并行slot(spring配置集群信息后使用mset会自动使用并行slot方式,不用我们自己实现)

持久化配置

3.1 持久化配置
Redis的持久化虽然可以保证数据安全,但也会带来很多额外的开销,因此持久化要遵循以下建议:

  • 用来做缓存的Redis实例尽量不要开启持久化功能
  • 建议关闭RDB持久化功能,使用AOF持久化
  • 利用脚本定期在slave节点做RDB,实现数据备份
  • 设置合理的rewrite阈值,避免频繁的bgrewrite
  • 配置no-appendfsync-on-rewrite = yes,禁止在rewrite期间做aof,避免因AOF引起的阻塞

部署有关建议:

  • Redis实例的物理机要预存足够内存,应对fork和rewrite
  • 单个Redis实例内存上限不要太大,例如4G或8G.可以加快fork的速度,减少主从同步、数据迁移压力
  • 不要和CPU密集型应用部署在一起(例如ES)
  • 不要与高硬盘负载应用一起部署(数据库,消息队列),单独部署得了。
http://www.xdnf.cn/news/192673.html

相关文章:

  • nginx代理websocket时ws遇到仅支持域名访问的处理
  • 23种设计模式 -- 工厂模式
  • 算力困局:AI 狂飙背后的能源枷锁与破局之道
  • 后端[特殊字符][特殊字符]看前端之Row与Col
  • 1.9多元函数积分学
  • Day15(贪心算法)——LeetCode121.买卖股票的最佳时机55.跳跃游戏
  • 【计网】计算机网络的类别与性能
  • Rust 学习笔记:修复所有权常见错误
  • cookie和session
  • Flink Checkpoint 与实时任务高可用保障机制实战
  • DBeaver详细安装步骤
  • 【AI】【MCP】搭建私人王炸MCP自动化工作流
  • 微信jdk 前端vue获取流程1、
  • 泰迪杯实战案例超深度解析:特殊医学用途配方食品数据分析与智能推荐系统设计
  • 《Linux篇》基础开发工具——vim详细介绍
  • 使用手机录制rosbag包
  • 21.气体放电管的特性与使用注意事项
  • uniapp+vue3+ts 使用canvas实现安卓端、ios端及微信小程序端二维码生成及下载
  • 十一、引用与拷贝函数(References the Copy-Constructor)
  • C++实时统计数据均值、方差和标准差
  • WGCAT工单系统发现错误 定时处理工单数据任务错误
  • MySQL笔记-mysql -hlocalhost和mysql -h127.0.0.1的不同
  • C语言教程(十八):C 语言共用体详解
  • 基于Python的携程国际机票价格抓取与分析
  • 【MCP教程系列】如何自己打包MCP服务并部署到阿里云百炼上【nodejs+TypeScript】搭建自己的MCP【Cline】
  • 排序算法详解笔记
  • Fiddler+Yakit实现手机流量抓包和小程序抓包
  • 【ESP32】st7735s + LVGL移植
  • 输出圆周率的前n位数字
  • 出口转内销如何破局?“金融+数智供应链”模式含金量还在上升