当前位置:首页 > 问答 > 正文

Redis那些事儿,文档里说不完的参考和技巧分享

说到Redis,很多人觉得就是个缓存,set和get就完事儿了,但真用起来,尤其是线上环境,总会碰到一些文档里不会细说,但又很关键的地方,我结合一些实践和网上的讨论,比如像阿里云开发者社区里一些工程师的分享,还有像“Redis实战”这类书里的案例,聊聊那些值得注意的参考和技巧。

别把Redis当黑盒子:INFO命令是你的透视眼

很多人部署完Redis,业务跑起来就不管了,等出问题了才手忙脚乱,其实Redis自带一个强大的诊断工具,就是INFO命令,你直接敲INFO,会出来一大堆信息,看着头疼,关键在于按模块查看。

INFO stats命令,这里面有个关键的keyspace_hitskeyspace_misses,你可以算一下缓存命中率:命中率 = hits / (hits + misses),如果命中率低得可怜,比如低于90%,甚至更低,那你就得想想了:是不是缓存key的设计有问题?或者内存太小,数据被频繁淘汰了?《Redis设计与实现》这本书里强调,监控命中率是评估缓存有效性的第一步。

再比如INFO memory,要看used_memoryused_memory_rss,前者是Redis实际存储数据占的内存,后者是操作系统分配给Redis进程的总内存,如果RSS远大于used_memory,比如大出很多,可能意味着内存碎片化比较严重了,这时候可能需要关注mem_fragmentation_ratio这个比值,如果长时间超过1.5,可能就得考虑重启实例或者检查是否有大key导致的不连续分配了,这些细节,文档只会告诉你命令,但不会告诉你什么时候该警惕。

键值对不是随便设的:小心“大Key”和“热Key”

这是生产环境最常踩的坑,所谓“大Key”,比如一个String类型的value有好几MB,或者一个Hash、List、Set里面积累了成千上万个元素,问题在哪呢?比如你要删除一个几MB的key,这个操作可能会阻塞Redis几毫秒甚至更久,Redis是单线程的,这段时间所有其他请求都得等着,延迟就上去了,阿里云的专家在分享里经常提到,他们遇到很多性能毛刺都是大Key删除导致的,解决方法是拆分:大的Hash可以按字段前缀拆成多个小Key;大的List可以拆成多个短的List。

Redis那些事儿,文档里说不完的参考和技巧分享

更隐蔽的是“热Key”,就是这个Key的访问频率特别高,比如某个明星出轨的消息缓存Key,瞬间所有请求都来读它,这个Key所在的Redis实例的CPU负载会很高,网卡流量也集中在这里,可能成为瓶颈,解决方法除了业务上做本地缓存(比如在应用层用Guava Cache再缓一层),还可以在架构上做文章,比如把这个热Key复制多份,叫key_copy1, key_copy2,然后让客户端随机读,分散压力,这个技巧在一些大型互联网公司的技术博客里能看到。

管道(Pipeline)和事务(Transaction)不是一回事

很多人容易把这俩混淆,管道(Pipeline)是为了解决网络开销的,比如你要执行100次set命令,如果一次一次发,100次网络往返时间(RTT)很长,管道就是把多个命令打包,一次发过去,Redis一次执行完,再把结果打包返回给你,大大减少网络开销,但它不保证原子性,中间可能被其他命令插入。

事务(Transaction)是用MULTIEXEC包起来的一组命令,它保证原子性,就是要么都执行,要么都不执行,但它并不是在所有命令执行完才返回结果,而是每个命令入队时就先返回QUEUED,最后EXEC才拿到所有结果,Redis的事务没有回滚功能,如果中间一个命令出错,后面的命令还会继续执行,这点和数据库事务很不一样,需要特别注意,管道是为了快,事务是为了保证一批命令的原子执行,目的不同。

Redis那些事儿,文档里说不完的参考和技巧分享

持久化策略:RDB和AOF怎么选?这是个权衡

RDB像是拍快照,定时把整个内存数据保存到磁盘,优点是恢复快,文件紧凑,缺点是可能会丢失最后一次快照之后的数据。 AOF是记录所有写操作命令,像写日志,优点是最多丢失一秒的数据(如果配置为每秒同步),数据更安全,缺点是文件会越来越大,恢复起来比RDB慢。

生产环境通常不会二选一,而是两者结合使用,用AOF来保证数据安全性,同时定期用RDB做一次快照,用于快速恢复和备份,AOF文件大了之后,Redis会启动重写机制,压缩指令,这里有个技巧是,在《Redis开发与运维》书中提到,如果机器磁盘压力大,可以把AOF重写的触发条件调得宽松一些,比如把auto-aof-rewrite-percentage调大,避免在业务高峰时因为重写导致磁盘IO瓶颈。

一些零散但实用的小技巧

  1. Key的命名规范:别用乱七八糟的命名,建议用冒号分隔,形成一种层次结构,比如user:1000:profileorder:20231001:status,这样看起来清晰,也方便用keys(生产环境慎用)或scan命令模式匹配。
  2. 慎用KEYS命令KEYS *这个命令会遍历所有key,在生产环境key多的时候,会直接让Redis卡住,应该用SCAN命令来迭代式地遍历,它是非阻塞的。
  3. 设置合适的过期时间:尽量不要让大量key在同一时间点过期,这可能会引起瞬间的延迟小波动,可以给过期时间加个随机数,让过期时间分散开。
  4. 连接池:不要每次操作都新建连接,一定要用连接池,并且要合理设置连接池的大小,太小了会阻塞等待,太大了浪费资源。

Redis上手容易,但要真正用好,尤其是在要求高性能、高可用的生产环境,就得关注这些文档之外的经验和细节,多看看监控,多了解底层原理,才能让它成为你得心应手的利器,而不是一个随时会炸的雷。