共计 5551 个字符,预计需要花费 14 分钟才能阅读完成。
这篇文章主要讲解了“Redis 使用规范和监控方法是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着丸趣 TV 小编的思路慢慢深入,一起来研究和学习“Redis 使用规范和监控方法是什么”吧!
一、前言
在互联网应用中,缓存成为高并发架构的关键组件。本文主要介绍缓存使用的典型场景、实操案例分析、Redis 使用规范及常规 Redis 监控。
二、常见缓存对比
常见的缓存方案:本地缓存包括 HashMap/ConcurrentHashMap、Ehcache、Memcache、Guava Cache 等,缓存中间件包括 Redis、Tair 等。
三、Redis 使用场景
1、计数
Redis 实现快速计数及缓存功能。
例如:视频或直播在线观看人数,用户每播放一次,就会自增 1。
2、Session 集中管理
Session 可以存储在应用服务是 JVM 中,但这一种方案会有一致性的问题,还有高并发下,会引发 JVM 内存溢出。Redis 将用户的 Session 集中管理,这种情况下只要保证 Redis 的高可用和扩展性,每次用户更新或查询登录都直接从 Redis 中信息获取。
3、限速
例如:高并发的秒杀活动,使用 incrby 命令实现原子性递增。
例如:业务要求用户一分钟内,只能获取 5 次验证码。
4、排行榜
关系型数据库在排行榜方面查询速度普遍偏慢,所以可以借助 redis 的 SortedSet 进行热点数据的排序。
比如在项目中,如果需要统计主播的吸金排行榜,可以以主播的 id 作为 member, 当天打赏的活动礼物对应的热度值作为 score, 通过 zrangebyscore 就可以获取主播活动日榜。
5、分布式锁
在实际的多进程并发场景下,使用分布式锁来限制程序的并发执行。多用于防止高并发场景下,缓存被击穿的可能。
分布式锁的实际就是 占坑,当另一个进程来执行 setnx 时,发现标识位已经为 1,只好放弃或者等待。
四、案例解析
1、过期设置 - set 命令会去掉过期时间
Redis 所有的数据结构,都可以设置过期时间。如果一个字符串已经设置了过期时间,然后重新设置它,会导致过期时间消失。所以在项目中需要合理评估 Redis 容量,避免因为频繁 set 导致没有过期策略,间接导致内存被占满。
如下是 Redis 源码截图:
2、Jedis 2.9.0 及以下版本过期设置 BUG
发现 Jedis 在进行 expiredAt 命令调用时有 bug,最终调用的是 pexpire 命令,这个 bug 会导致 key 过期时间很长,导致 Redis 内存溢出等问题。建议升级到 Jedis 2.9.1 及以上版本。
BinaryJedisCluster.java 源码如下:
@Override public Long pexpireAt(final byte[] key, final long millisecondsTimestamp) { return new JedisClusterCommand Long (connectionHandler, maxAttempts) { @Override public Long execute(Jedis connection) { return connection.pexpire(key, millisecondsTimestamp); // 此处 pexpire 应该是 pexpireAt } }.runBinary(key); }
对比 pexpire 和 pexpireAt:
比如我们当前使用的时间是 2018-06-14 17:00:00,它的 unix 时间戳为 1528966800000 毫秒,当我们使用 PEXPIREAT 命令时,由于是过去的时间,相应的 key 会立即过期。
而我们误用了 PEXPIRE 命令时,key 不会立即过期,而是等到 1528966800000 毫秒后才过期,key 过期时间会相当长,约几 W 天后,从而可能导致 Redis 内存溢出、服务器崩溃等问题。
3、缓存被击穿
缓存的 key 有过期策略,如果恰好在这个时间点对这个 Key 有大量的并发请求,这些请求发现缓存过期一般都会从后端 DB 回源数据并回设到缓存,这个时候大并发的请求可能会瞬间把后端 DB 压挂。
业界常用优化方案有两种:
第一种:使用分布式锁,保证高并发下,仅有一个线程能回源后端 DB;
第二种:保证高并发的请求到的 Redis key 始终是有效的,使用非用户请求回源后端,改成主动回源。一般可以使用异步任务进行缓存的主动刷新。
4、Redis-standalone 架构禁止使用非 0 库
Redis 执行命令 select 0 和 select 1 切换,造成性能损耗。
RedisTemplate 在执行 execute 方法的时候会先获取链接。
执行到 RedisConnectionUtils.java,会有一段获取链接的方法。
JedisConnectionFactory.java 会调用
JedisConnection 构造器,注意这边的 dbIndex 就是数据库编号,如:1
继续跟进 JedisConnection 代码,当选择库大于 1 时,会有 select db 操作。如果一直使用 0 库是不需要额外执行切库命令的。知道了第一个切库 select 1 的地方,那么 select 0 是哪来的呢?
其实客户端使用 Redis 也会是要释放链接的,只不过 RedisTemplate 已经帮我们自动释放了,让我们再回到一开始 RedisTemplate 执行 execute(…) 方法的地方。
下面还是 RedisConnectionUtils.java,执行链接关闭的代码。
按代码注释的意思,如果选择库编号不为 0,spring-data-redis 框架每次都会执行重置 select 0!
笔者在 vivo 商城业务中,商品详情页接口经过上面的调优,性能提高了 3 倍多。
进一步验证数据库切换至少影响性能 3 倍左右(视具体业务而定)。
Rediscluster 集群数据库,默认 0 库,无法选择其他数据库,也就避免了这个问题。
5、当心时间复杂度 o(n)Redis 命令
Redis 是单线程的,所以线程安全的。
Redis 使用非阻塞 IO,并且大部分命令的时间复杂度 O(1)。
使用高耗时的命令是非常危险的,会占用唯一的一个线程的大量处理时间,导致所有的请求都被拖慢。
例如:获取所有 set 集合中的元素 smembers myset,返回指定 Hash 中所有的 member,时间复杂度 O(N)。
缓存的 Value 集合变大,当高并接口请求时,会从 Redis 读取相关数据,每个请求读取的时间变长,不断的叠加,导致出现热点 KEY 情况,Redis 某个分片处于阻塞,CPU 使用率达到 100%。
6、缓存热 key
在 Redis 中,访问频率高的 key 称为热点 key,当某一热点 key 的请求到 Server 主机时,由于请求量特别大,导致主机资源不足,甚至宕机,影响正常的服务。
热 key 问题的产生,有如下两种原因:
用户消费的数据远大于生产的数据,比如热卖商品或秒杀商品、热点新闻、热点评论等,这些典型的读多写少的场景会产生热点问题;
请求分片集中,超过单 Server 的性能极限,比如 固定名称 key,哈希落入一台 Server,访问量极大的情况,超过 Server 极限时,就会导致热点 Key 问题的产生。
那么在实际业务中,如何识别到热点 key 呢?
凭借业务经验,进行预估哪些是热 key;
客户端统计收集,本地统计或者上报;
如果服务端有代理层,可以在代理层进行收集上报。
当我们识别到热 key,如何解决热 key 问题?
Redis 集群扩容:增加分片副本,均衡读流量;
进一步对热 key 进行散列,比如将一个 key 备份为 key1,key2 hellip; hellip;keyN,同样的数据 N 个备份,N 个备份分布到不同分片,访问时可随机访问 N 个备份中的一个,进一步分担读流量;
使用二级缓存,即本地缓存。
当发现热 key 后,将热 key 对应数据首先加载到应用服务器本地缓存中,减少对 Redis 的读请求。
五、Redis 规范
1、禁止使用非 database 0
说明:
Redis-standalone 架构,禁止使用 Redis 中的其他 database。
原由:
为以后业务迁移 Redis Cluster 保持兼容性;
多个 database 用 select 切换时,更消耗 CPU 资源;
更易自动化运维管理,如 scan/dbsize 命令只用于当 database;
部分 Redis Clients 因线程安全问题,不支持单实例多 database。
2、Key 设计规范
按业务功能命名 key 前缀,防止 key 冲突覆盖,推荐 用冒号分隔,例如,业务名: 表名:id:,如 live:rank:user:weekly:1:202003。
Key 的长度小于 30 个字符,Key 名字本身是 String 对象,Redis 硬编码限制最大长度 512MB。
在 Redis 缓存场景,推荐 Key 都设置 TTL 值,保证不使用的 Key 能被及时清理或淘汰。
Key 设计时禁止包含特殊字符,如空格、换行、单双引号以及其他转义字符。
3、Value 设计规范
单个 Value 大小必须控制 10KB 以内,单实例键个数过大,可能导致过期键的回收不及时。
set、hash、list 等复杂数据类型,要尽量降低数据结构中的元素个数,建议个数不要超过 1000。
4、关注命令时间复杂度
推荐使用 O(1) 命令,如 get scard 等。
O(N) 命令关注 N 的数量,如下命令需要对 N 值在业务层面做控制。
hgetall
lrange
smembers
zrange
例如:smember 命令时间复杂度为 O(n),当 n 持续增加时,会导致 Redis CPU 持续飙高,阻塞其他命令的执行。
5、Pipeline 使用
说明:Pipeline 是 Redis 批量提交的一种方式, 也就是把多个命令操作建立一次连接发给 Redis 去执行, 会比循环的单次提交性能更优。
Redis 客户端执行一条命令分 4 个过程:发送命令 – 命令排队 – 命令执行 – 返回结果。
常用的 mget、mset 命令,有效节约 RTT(命令执行往返时间),但 hgetall 并没有 mhgetall,是不支持批量操作的。此时,需要使用 Pipeline 命令
例如:直播中台项目中,需要同时查询主播日、周、月排行榜,使用 PIPELINE 一次提交多个命令,同时返回三个榜单数据。
6、线上禁用命令
禁止使用 Monitor
禁止生产环境使用 monitor 命令,monitor 命令在高并发条件下,会存在内存暴增和影响 Redis 性能的隐患
禁止使用 Keys
keys 操作是遍历所有的 key,如果 key 非常多的情况下导致慢查询,会阻塞其他命令。所以禁止使用 keys 及 keys pattern 命令。
建议线上使用 scan 命令代替 keys 命令。
禁止使用 Flushall、Flushdb
删除 Redis 中所有数据库中的所有记录,并且该命令是原子性的,不会终止执行,一旦执行,将不会执行失败。
禁止使用 Save
阻塞当前 redis 服务器,直到持久化操作完成为止,对于内存较大的实例会造成长时间的阻塞
BGREWRITEAOF
手动 AOF,手动持久化对于内存较大的实例会造成长时间的阻塞
Config
Config 是客户端配置方式,不利于 Redis 运维。建议在 Redis 配置文件中设置。
六、Redis 监控
1、慢查询
方法一:slowlog 获取慢查询日志
127.0.0.1:{port} slowlog get 5 1) 1) (integer) 47 2) (integer) 1533810300 3) (integer) 175833 4) 1) DEL 2) spring:session:expirations:1533810300000 2) 1) (integer) 46 2) (integer) 1533810300 3) (integer) 117400 4) 1) SMEMBERS
方法二:更全面的慢查询可以通过 CacheCloud 工具监控。
路径:应用列表 - 点击相关应用名 - 点击 慢查询 Tab 页。
点击 慢查询,重点关注慢查询个数及相关命令。
2、监控 Redis 实例绑定的 CPU 核心使用率
由于 Redis 是单线程,重点监控 Redis 实例绑定的 CPU 核心使用率。
一般 CPU 资源使用率为 10% 左右,如果使用率高于 20% 时,考虑是否使用了 RDB 持久化。
3、Redis 分片负载均衡
当前 redis-cluster 架构模式,3 个 master 和 3 个 Slave 组成的集群,关注 Redis-cluster 每个分片 requests 流量均衡情况;
通过命令获取:
redis-cli -p{port} -h{host} --stat
一般情况,超过 12W 需要告警。
4、关注大 key BigKey
通过 Redis 提供的工具,redis-cli 定时扫描相应 Redis 大 Key,进行优化。
具体命令如下:
redis-cli -h 127.0.0.1 -p {port} --bigkeys
或
redis-memory-for-key -s {IP} -p {port} XXX_KEY
一般超过 10K 为大 key,需要重点关注,建议从业务层面优化。
5、监控 Redis 占用内存大小
Info memory 命令查看,避免在高并发场景下,由于分配的 MaxMemory 被耗尽,带来的性能问题。
重点关注 used_memory_human 配置项对应的 value 值,增量过高时,需要重点评估。
感谢各位的阅读,以上就是“Redis 使用规范和监控方法是什么”的内容了,经过本文的学习后,相信大家对 Redis 使用规范和监控方法是什么这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是丸趣 TV,丸趣 TV 小编将为大家推送更多相关知识点的文章,欢迎关注!