问题原因
小编负责的应用是一个管理后台应用,权限管理使用 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
指令会导致其他命令执行变慢?
站在客户端的视角,执行一条命令分为三步:
发送命令
执行命令
返回结果
但是这仅仅客户端自己以为的过程,但是实际上同一时刻,可能存在很多客户端发送命令给 Redis ,而 Redis 我们都知道它采用的是单线程模型。
为了处理同一时刻所有的客户端的请求命令,Redis 内部采用了队列的方式,排队执行。
于是客户端执行一条命令实际需要四步:
发送命令
命令排队
执行命令
返回结果
由于 Redis 单线程执行命令,只能顺序从队列取出任务开始执行。
只要 3 这个过程执行命令速度过慢,队列其他任务不得不进行等待,这对外部客户端看来,Redis 好像就被阻塞一样,一直得不到响应。
所以使用 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命令使用实例分析的详细内容。更多信息请关注PHP中文网其他相关文章!

Redis和SQL数据库的主要区别在于:Redis是内存数据库,适用于高性能和灵活性需求;SQL数据库是关系型数据库,适用于复杂查询和数据一致性需求。具体来说,1)Redis提供高速数据访问和缓存服务,支持多种数据类型,适用于缓存和实时数据处理;2)SQL数据库通过表格结构管理数据,支持复杂查询和事务处理,适用于电商和金融系统等需要数据一致性的场景。

REDISACTSASBOTHADATASTOREANDASERVICE.1)ASADATASTORE,ITUSESIN-MEMORYSTOOGATOFORFOFFASTESITION,支持VariousDatharptructuresLikeKey-valuepairsandsortedsetsetsetsetsetsetsets.2)asaservice,ItprovidespunctionslikeItionitionslikepunikeLikePublikePublikePlikePlikePlikeAndluikeAndluAascriptingiationsmpleplepleclexplectiations

Redis与其他数据库相比,具有以下独特优势:1)速度极快,读写操作通常在微秒级别;2)支持丰富的数据结构和操作;3)灵活的使用场景,如缓存、计数器和发布订阅。选择Redis还是其他数据库需根据具体需求和场景,Redis在高性能、低延迟应用中表现出色。

Redis在数据存储和管理中扮演着关键角色,通过其多种数据结构和持久化机制成为现代应用的核心。1)Redis支持字符串、列表、集合、有序集合和哈希表等数据结构,适用于缓存和复杂业务逻辑。2)通过RDB和AOF两种持久化方式,Redis确保数据的可靠存储和快速恢复。

Redis是一种NoSQL数据库,适用于大规模数据的高效存储和访问。1.Redis是开源的内存数据结构存储系统,支持多种数据结构。2.它提供极快的读写速度,适合缓存、会话管理等。3.Redis支持持久化,通过RDB和AOF方式确保数据安全。4.使用示例包括基本的键值对操作和高级的集合去重功能。5.常见错误包括连接问题、数据类型不匹配和内存溢出,需注意调试。6.性能优化建议包括选择合适的数据结构和设置内存淘汰策略。

Redis在现实世界中的应用包括:1.作为缓存系统加速数据库查询,2.存储Web应用的会话数据,3.实现实时排行榜,4.作为消息队列简化消息传递。Redis的多功能性和高性能使其在这些场景中大放异彩。

Redis脱颖而出是因为其高速、多功能性和丰富的数据结构。1)Redis支持字符串、列表、集合、散列和有序集合等数据结构。2)它通过内存存储数据,支持RDB和AOF持久化。3)从Redis6.0开始引入多线程处理I/O操作,提升了高并发场景下的性能。

RedisisclassifiedasaNoSQLdatabasebecauseitusesakey-valuedatamodelinsteadofthetraditionalrelationaldatabasemodel.Itoffersspeedandflexibility,makingitidealforreal-timeapplicationsandcaching,butitmaynotbesuitableforscenariosrequiringstrictdataintegrityo


热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

Video Face Swap
使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热门文章

热工具

SublimeText3汉化版
中文版,非常好用

适用于 Eclipse 的 SAP NetWeaver 服务器适配器
将Eclipse与SAP NetWeaver应用服务器集成。

WebStorm Mac版
好用的JavaScript开发工具

SublimeText3 Linux新版
SublimeText3 Linux最新版

MinGW - 适用于 Windows 的极简 GNU
这个项目正在迁移到osdn.net/projects/mingw的过程中,你可以继续在那里关注我们。MinGW:GNU编译器集合(GCC)的本地Windows移植版本,可自由分发的导入库和用于构建本地Windows应用程序的头文件;包括对MSVC运行时的扩展,以支持C99功能。MinGW的所有软件都可以在64位Windows平台上运行。