Redis瘦身的示例分析

发布时间:2021-05-27 10:30:11 作者:小新
来源:亿速云 阅读:162

这篇文章主要介绍Redis瘦身的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!

Redis内存回收

Redis 服务器的最大占用内存量由配置项 maxmemory 决定,我们可以通过 config set maxmemory 2GB 的格式来配置。一旦 Redis 内存满,所有引起内存增加的操作都会被返回 error。作为专业 Redis 服务器我们通常将此项设置为0,以服务器系统内存来作为限制;

那么 Redis 使用内存达到了上限怎么办?Redis 为我们提供了几种选项以自动回收内存,可以通过配置项 maxmemory-policy 来配置;

最大内存回收策略需要根据业务来配置,如果纯粹做缓存,allkeys-lru无疑是最合适的。如果存储了稍微重要的数据,为了防止 Redis 误删一些重要键,则需要选用 noeviction;

allkeys-lru、allkeys-random 在内存满时都有键可删,可以腾出内存,但如果配置了其他的策略,数据库用久了(根据业务量),随着业务发展和数据积累,通常会累积到到服务器内存占用率高,利用率低的情况,则可能会遇到内存占用满的问题。

问题原由

产生问题的原因有:

持久键废弃

这是导致此问题的最常见情况。

有时候是开发人员的锅,开发不规范,未给有时效性的键设置过期时间,后续又不进行手动删除,键就成为无人管的孤儿键了。

还可能是整个业务慢慢被废弃,不知道哪一天起,业务整体已不再维护了,一批键自然也就没用了。比这更严重的是,如果使用 List 传递数据,消费进程已被停止,但生产进程未同步停止,还在往 Redis 里写数据。

过期键未回收

这个原因首先要谈到 Redis 的两种过期键删除策略:

如果我们产生过期键的速度很快,最多可导致 Redis 25% 的过期键没有被及时删除。

遍历清除垃圾键

由上,明白了问题产生的原因,解决 Redis 内存满的方法就明确了:清除这些垃圾键。 于是就面临着两个问题:

如何遍历键

对于查找键,我们首先想到的是 KEYS,但 KEYS 的时间复杂度是O(n),n 是 Redis 内键的总数,如果 Redis 内键很多还是会有性能问题,导致其他命令被阻塞的。

这里介绍一个键遍历命令: SCAN。

SCAN cursor:

0 => cursor, // cursor = 0 遍历结束
1 => array(key1, key2...)

需要注意的是 SCAN 命令是在版本2.8.0 加入的,如果是之前的版本,可以考虑解析 Redis 的 RDB 文件来获取所有的键。

如何判断键是否垃圾

我们有三种异常键需要处理:

这里介绍 Redis 的另一个命令 OBJECT,使用它可以从内部查看 key 对象的状态。使用 OBJECT IDLETIME key 来获取 key 的闲置时间,我们可以判断 key 闲置时间大于一个时间段(根据业务自定)的为已废弃。

此外还能使用 OBJECT REFCOUNT key获取 key 引用所储存的值的次数,OBJECT ENCODING key 获取 key 储存的值所使用的内部表示。

获取键大小

而获取 Redis 某键占用内存大小,则通过另一个命令 DEBUG OBJECT 来获取,此命令会返回比OBJECT命令更详细的内部数据。

DEBUG OBJECT test
Value at:0x7fb0ee16ebd0 refcount:1 encoding:embstr serializedlength:6 lru:12362780 lru_seconds_idle:4

结果包括内存地址、引用数、内部编码表示、序列化后的长度、最近最少使用标识值,闲置时间,我们可以解析此结果串来获取对应的数据。

需要注意,key 作为复合键拥有大量字段时使用 DEBUG 命令计算内存会使 Redis 阻塞较长时间,且 Redis 官方并不建议在客户端使用此命令。

我们也可以先使用 TYPE key 获取键的类型,再根据类型获取其键的大小,如对字符串使用LEN,对 哈希表使用HLEN。

要注意在删除特别大的复合键时,建议先逐步清空键内的字段,防止因字段过多,Redis 阻塞较长时间。

管道加速

Redis 支持 pipeline 管道技术,一次 请求/响应 服务器能实现处理并响应多个请求。这样就可以将多个命令同时发送到服务器,不等待回复,直接在最后获取多个结果。

PHP 中使用 MULTI(Redis::PIPELINE) 和 EXEC() 命令来实现管道;

脚本实现

下面是个简单的脚本:

$redis = new Redis();
$redis->connect('127.0.0.1');
do {
    $keys = $redis->scan($cursor);

    $pipeline = $redis->multi(Redis::PIPELINE);
    foreach ($keys as $key) {
        $idle_time = $redis->object('idletime', $key);
        if ($idle_time > 180 * 24 * 3600) {
            $pipeline->del($key);
        }
        // todo 判断类型进而判断占用内存大小,再删除
    }
    $pipeline->exec();
} while ($cursor != 0);

从根源避免问题

以上的脚本肯定也会在删除键时影响 Redis 的效率,最好的情况还是从根源就避免此类情况,以下是一些建议:

以上是“Redis瘦身的示例分析”这篇文章的所有内容,感谢各位的阅读!希望分享的内容对大家有帮助,更多相关知识,欢迎关注亿速云行业资讯频道!

推荐阅读:
  1. redis基础配置的示例分析
  2. Redis高级应用的示例分析

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

redis

上一篇:Spring Boot 中Profile配置体系的示例分析

下一篇:怎么用C写一个web服务器之I/O多路复用

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》