将所有 Redis 的 oom_adj 设置为最低值或者稍小的值
,降低被 OOM killer 杀掉的概率。保证不同机器时钟一致性
的服务。一般公司里都会有 NTP 服务用来提供标准时间服务,从而达到纠正时钟的效果。appendonly no
:对 AOF 持久化没有任何影响,因为根本不存在 AOF 文件。appendonly yes
:只不过在 AOF 文件中追加了一条 flushall 记录。AOF 文件还保存着 flush 操作之前完整的数据
,这对恢复数据是很有帮助的。Redis 执行了 flushall 操作后,RDB持久化文件会受到什么影响呢?
1)如果没有开启 RDB 的自动策略
,也就是配置文件中没有类似如下配置
save 900 1 save 300 10 save 60 10000
那么除非手动执行过 save、bgsave 或者发生了主从的全量复制,否则 RDB 文件也会保存 flush 操作之前的数据,可以作为恢复数据的数据源。注意问题如下:
2)如果开启了 RDB 的自动策略
,由于 flush 涉及键值数量较多,RDB 文件会被清除意味着使用 RDB 恢复基本无望。
redis-cli -h {ip} -p {port}
来执行命令。keys
:如果键值较多,存在阻塞 Redis 的可能性flushall/flushdb
:数据全部被清除save
:如果键值较多,存在阻塞 Redis 的可能性debug
:个例如 debug reload 会重启 Redisconfig
:config 应该交给管理员使用shutdown
:停止 Redisrename-command
配置解决了这个问题,例如添加如下配置:rename-command flushall abcabcabc
bigkey 是指 key 对应的 value 所占的内存空间比较大
,例如一个字符串类型的 value 可以最大存到 512MB,一个列表类型的 value 最多可以存储 2^32 - 1 个元素。如果按照数据结构来细分的话,一般分为两种:
单个 value 值很大
,一般认为超过 10 KB 就是 bigkey,但这个值和具体的 OPS 相关。元素个数过多
。redis-cli --bigkeys
可以命令统计 bigkey 的分布。但是生产环境中,开发和运维人员更希望自己可以定义 bigkey 的大小而且更希望找到真正的 bigkey 都有哪些
,这样才可以去定位、解决、优化问题。执行 debug object key 查看 serializedlength 属性
即可,它表示 key 对应的 value 序列化之后的字节数。通过对异常的分析通常能找到异常原因可能是 bigkey
,这种方式并不推荐,但是在实际生产环境中却大量存在,建议修改 Redis 客户端,当抛出异常时打印出所操作的 key,方便排查 bigkey 问题。scan + debug object
,如果怀疑存在bigkey,可以使用scan命令渐进的扫描出所有的key,分别计算每个 key 的 serializedlength,找到对应 bigkey 进行相应的处理和报警,这种方式是比较推荐的方式。删除 bigkey 通常来说会阻塞 Redis 服务
。sscan、hscan、zscan
。public void delBigHash(String bigKey) { // 游标 Jedis jedis = new Jedis("127.0.0.1", 6379); String cursor = "0"; while (true) { ScanResult<Map.Entry<String, String>> scanResult = jedis.hscan(bigKey, cursor, new ScanParams().count(100)); // 每次扫描后获取新的游标 cursor = scanResult.getStringCursor(); // 获取扫描结果 List<Map.Entry<String, String>> list = scanResult.getResult(); if (list == null || list.size() == 0) { continue; } String[] fields = getFieldsFrom(list); // 删除多个field jedis.hdel(bigkey, fields); // 游标为0时停止 if (cursor.equals("0")) { break; } } //最终删除key jedis.del(bigKey); } /** * 获取 field 数组 * @param list * @return */ private String[] getFieldsFrom(List<Map.Entry<String, String>> list) { List<String> fields = new ArrayList<>(); for (Map.Entry<String, String> entry : list) { fields.add(entry.getKey()); } return fields.toArray(new String[fields.size()]); }
惰性删除 lazy free 特性
,从根本上解决了 bigkey(主要指定元素较多集合类型key)删除的风险热门新闻事件或商品通常会给系统带来巨大的流量,对存储这类信息的 Redis 来说却是一个巨大的挑战。以 Redis Cluster 为例,它会造成整体流量的不均衡,个别节点出现 OPS 过大的情况,极端情况下热点 key 甚至会超过 Redis 本身能够承受的 OPS,因此寻找热点 key 对于开发和运维人员非常重要。下面从以下几个方面分析热点 key。
在客户端设置全局字典(key 和调用次数)
,每次调用 Redis 命令时,使用这个字典进行记录。代理是所有 Redis 客户端和服务端的桥梁
。但并不是所有Redis都是采用此种架构。monitor 命令可以监控到 Redis 执行的所有命令
。内存暴增和影响 Redis 性能
的隐患,所以此种方法适合在短时间内使用。只能统计一个 Redis 节点的热点 key
,对于 Redis 集群需要进行汇总统计。对机器上所有 Redis 端口的 TCP 数据包进行抓取完成热点 key 的统计
。拆分复杂数据结构
:如果当前 key 的类型是一个二级数据结构,例如哈希类型。如果该哈希元素个数较多,可以考虑将当前 hash 进行拆分,这样该热点 key 可以拆分为若干个新的 key 分布到不同 Redis 节点上,从而减轻压力。迁移热点key
:以 Redis Cluster 为例,可以将热点 key 所在的 slot 单独迁移到一个新的 Redis 节点上,但此操作会增加运维成本。本地缓存加通知机制
:可以将热点 key 放在业务端的本地缓存中,因为是在业务端的本地内存中,处理能力要高出 Redis 数十倍,但当数据更新时,此种模式会造成各个业务端和 Redis 数据不一致,通常会使用发布订阅机制来解决类似问题。来源:《Redis 开发与运维》第 12 章 开发运维的“陷阱”