Redis命令使用实例分析


问题原因

小编负责的应用是一个管理后台应用,权限管理使用 shiro 框架,由于存在多个节点,需要使用分布式 session,于是这里使用 redis 存储 session 信息。

由于 Shiro 并没有直接提供 Redis 存储 Session 组件,阿粉不得不使用 Github 一个开源组件 shiro-redis。

由于 Shiro 框架需要定期验证 Session 是否有效,于是 Shiro 底层将会调用  SessionDAO#getActiveSessions 获取所有的 Session 信息。

shiro-redis 正好继承 SessionDAO 这个接口,底层使用用keys 命令查找 Redis 所有存储的 Session key。

public Set<byte[]> keys(byte[] pattern){
    checkAndInit();
    Set<byte[]> keys = null;
    Jedis jedis = jedisPool.getResource();
    try{
        keys = jedis.keys(pattern);
    }finally{
        jedis.close();
    }
    return keys;
}

找到问题原因,解决办法就比较简单了,github 上查找到解决方案,升级一下 shiro-redis 到最新版本。

在这个版本,shiro-redis 采用 scan命令代替 keys,从而修复这个问题。

public Set<byte[]> keys(byte[] pattern) {
    Set<byte[]> keys = null;
    Jedis jedis = jedisPool.getResource();


    try{
        keys = new HashSet<byte[]>();
        ScanParams params = new ScanParams();
        params.count(count);
        params.match(pattern);
        byte[] cursor = ScanParams.SCAN_POINTER_START_BINARY;
        ScanResult<byte[]> scanResult;
        do{
            scanResult = jedis.scan(cursor,params);
            keys.addAll(scanResult.getResult());
            cursor = scanResult.getCursorAsBytes();
        }while(scanResult.getStringCursor().compareTo(ScanParams.SCAN_POINTER_START) > 0);
    }finally{
        jedis.close();
    }
    return keys;


}

虽然问题成功解决了,但是阿粉心里还是有点不解。

为什么keys 指令会导致其他命令执行变慢?

为什么Keys 指令查询会这么慢?

为什么Scan 指令就没有问题?

Redis 执行命令的原理

首先我们来看第一个问题,为什么keys 指令会导致其他命令执行变慢?

站在客户端的视角,执行一条命令分为三步:

  1. 发送命令

  2. 执行命令

  3. 返回结果

但是这仅仅客户端自己以为的过程,但是实际上同一时刻,可能存在很多客户端发送命令给 Redis ,而 Redis 我们都知道它采用的是单线程模型。

为了处理同一时刻所有的客户端的请求命令,Redis 内部采用了队列的方式,排队执行。

于是客户端执行一条命令实际需要四步:

  1. 发送命令

  2. 命令排队

  3. 执行命令

  4. 返回结果

由于 Redis 单线程执行命令,只能顺序从队列取出任务开始执行。

只要 3 这个过程执行命令速度过慢,队列其他任务不得不进行等待,这对外部客户端看来,Redis 好像就被阻塞一样,一直得不到响应。

《PHP技术内幕》中文版 《PHP技术内幕》中文版

本书详细说明了PHP的使用方法,内容涉及PHP应用的各个方面,并提供了大量的代码实例,使读者能够快速而容易地学会PHP。每一章都分为两部分,前一部分“深入分析”详细说明相关的技术信息,

《PHP技术内幕》中文版 385 查看详情 《PHP技术内幕》中文版

所以使用 Redis 过程切勿执行需要长时间运行的指令,这样可能导致 Redis 阻塞,影响执行其他指令。

KEYS 原理

接下来开始回答第二个问题,为什么Keys 指令查询会这么慢?

回答这个问题之前,请大家回想一下 Redis 底层存储结构。

不太清楚朋友的也没关系,大家可以回看一下之前的文章「阿里面试官:HashMap 熟悉吧?好的,那就来聊聊 Redis 字典吧!」。

keys命令需要返回所有的符合给定模式 pattern 的  Redis 中键,为了实现这个目的,Redis 不得不遍历字典中 ht[0]哈希表底层数组,这个时间复杂度为 「O(N)」(N 为 Redis 中 key 所有的数量)。

即使 Redis 中的键数量很少,它仍然会有很快的执行速度。当Redis键的数量逐渐增多,达到百万、千万,甚至上亿级别时,它的执行速度会变得非常缓慢。

下面是阿粉本地做的一次实验,使用 lua 脚本往 Redis 中增加 10W 个 key,然后使用 keys 查询所有键,这个查询大概会阻塞十几秒的时间。

eval "for i=1,100000  do redis.call('set',i,i+1) end" 0
这里阿粉使用 Docker 部署 Redis,性能可能会稍差。

SCAN 原理

最后我们来看下第三个问题,为什么scan 指令就没有问题?

这是因为 scan命令采用一种黑科技-「基于游标的迭代器」

每次调用 scan 命令,Redis 都会向用户返回一个新的游标以及一定数量的 key。下次再想继续获取剩余的 key,需要将这个游标传入 scan 命令, 以此来延续之前的迭代过程。

简单来讲,scan 命令使用分页查询 redis 。

下面是一个 scan 命令的迭代过程示例:

scan 命令使用游标这种方式,巧妙将一次全量查询拆分成多次,降低查询复杂度。

虽然  scan 命令时间复杂度与 keys一样,都是 「O(N)」,但是由于 scan 命令只需要返回少量的 key,所以执行速度会很快。

最后,虽然scan 命令解决 keys不足,但是同时也引入其他一些缺陷:

  • 同一个元素可能会被返回多次,这就需要我们应用程序增加处理重复元素功能。

  • 在迭代过程中,有可能会返回正在增加到 Redis 的元素,或者正在被删除的元素,也有可能不会。

以上这些缺陷,在我们开发中需要考虑这种情况。

除了 scan以外,redis 还有其他几个用于增量迭代命令:

  • sscan:用于迭代当前数据库中的数据库键,用于解决 smembers可能产生阻塞问题

  • hscan命令用于迭代哈希键中的键值对,用于解决 hgetall 可能产生阻塞问题。

  • zscan:命令用于迭代有序集合中的元素(包括元素成员和元素分值),用于产生 zrange 可能产生阻塞问题。

以上就是Redis命令使用实例分析的详细内容,更多请关注其它相关文章!


# 迭代  # googleads and seo  # seo适合创业吗  # 无锡网站seo优化公司价格  # 通州外贸网站推广招聘  # 电子商场网站维护与推广  # 湛江营销推广厂商排名  # 都是  # 的是  # 变慢  # 单线程  # 如何实现  # 网络带宽  # 这个问题  # 是一个  # 客户端  # redis  # 网站图片优化的方法技巧  # 广州市关键词排名渠道  # 谷歌国外推广推荐网站有哪些  # 平度网络营销运营推广 


相关栏目: 【 Google疑问12 】 【 Facebook疑问10 】 【 优化推广96088 】 【 技术知识133117 】 【 IDC资讯59369 】 【 网络运营7196 】 【 IT资讯61894


相关推荐: 邮编号码查询app有哪些_邮编号码查询推荐app及使用体验  steam缓存文件在哪儿_steam缓存文件的路径查找方法与结构说明  作业帮网页版不用下载入口 在线问老师快速答疑  《暗黑破坏神4》国服回归送狂欢礼包 价值6916元  《下一站江湖2》大雪山加入方法  mysql通配符能用于日志查询吗_mysql通配符在系统日志查询中的实际使用方法  Excel如何快速找到并断开外部数据源链接_Excel外部数据源断开方法  word文档中的分隔符有哪些不同类型和用途_Word分隔符类型与用途方法  C++中的explicit关键字有什么作用_C++类型转换控制与explicit使用  小米civi如何设置锁屏时间  mysql中如何分析索引使用情况_mysql索引使用分析方法  J*aScript深度克隆:实现高效、健壮与安全的复杂对象复制  《盗墓笔记手游》技能介绍  《密马》发布账号方法  mysql归档数据怎么导出为csv_mysql归档数据导出为csv文件的方法  LINUX怎么查看显卡信息_LINUX查看GPU状态  SQLAlchemy 2.0 与 Pydantic 模型类型安全集成指南  AO3中文入口稳定分享_AO3官网HTTPS看文详解  抖音火山版注销账号抖音会注销吗 抖音火山版与抖音账号注销关系  告别繁琐SEO!如何使用SyliusSitemap插件自动化生成网站地图,提升搜索引擎排名  Composer如何使用composer-plugin-api开发自定义插件  包子漫画官网链接官方地址 包子漫画在线观看官网首页入口  Firefox OS应用开发:解决XMLHttpRequest跨域请求阻塞问题  解决jQuery多计算器输入字段冲突的教程  苹果电脑如何快速截图并编辑 苹果电脑截屏标注快捷操作  掌握产品代码正则表达式:避免常见陷阱与精确匹配  无人机考证官网 中国民航无人机考证官网登录入口  Python实时数据流中高效查找最大最小值  管理打开的编辑器:固定、分组和关闭技巧  高德地图怎么查看未来行程规划_高德地图未来行程规划查看方法  《气泡星球》兑换码礼包大全  Selenium自动化:利用键盘模拟解决复杂日期输入框输入问题  汽水音乐官方网站登录入口_汽水音乐网页版进入链接  背部总是隐隐作痛怎么回事 背痛如何改善  抖音评论无法发送如何修复 抖音评论功能操作指南  《tt语音》超级玩家开通方法  《漫蛙manwa2》防走失网页版链接2025  解决Flex容器横向滚动内容截断与偏移问题  使用jQuery精确检测除指定元素外任意位置的点击事件  rabbitmq 持久化有什么缺点?  电脑没有声音了怎么办 电脑声音问题的全面排查与修复指南【详解】  拷贝漫画2025网页版入口 拷贝漫画官网免费看全集  《海豚家》注销账号方法  三星A55应用闪退排查步骤_Samsung A55稳定性优化技巧  React应用中Commerce.js数据加载与状态管理最佳实践  Cassandra中复合主键、二级索引与ORDER BY排序的限制与解决方案  海外搜索引擎推广效果怎么样,怎么分析效果!  猫眼app抢票快还是小程序快  J*aScript字符串_Unicode处理  铁拳8在线玩 铁拳8在线秒玩入口 

 2023-05-30

了解您产品搜索量及市场趋势,制定营销计划

同行竞争及网站分析保障您的广告效果

点击免费数据支持

提交您的需求,1小时内享受我们的专业解答。

运城市盐湖区信雨科技有限公司


运城市盐湖区信雨科技有限公司

运城市盐湖区信雨科技有限公司是一家深耕海外推广领域十年的专业服务商,作为谷歌推广与Facebook广告全球合作伙伴,聚焦外贸企业出海痛点,以数字化营销为核心,提供一站式海外营销解决方案。公司凭借十年行业沉淀与平台官方资源加持,打破传统外贸获客壁垒,助力企业高效开拓全球市场,成为中小企业出海的可靠合作伙伴。

 8156699

 13765294890

 8156699@qq.com

Notice

We and selected third parties use cookies or similar technologies for technical purposes and, with your consent, for other purposes as specified in the cookie policy.
You can consent to the use of such technologies by closing this notice, by interacting with any link or button outside of this notice or by continuing to browse otherwise.