Redis有哪些潜在的慢操作?

本文涉及的产品
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
简介: Redis作为内存数据库,访问速度快是最大的特点,那么,什么情况下,Redis也会变慢呢?

Redis作为内存数据库,访问速度快是最大的特点,那么,什么情况下,Redis也会变慢呢?

Redis底层数据结构

Redis有5种基本数据类型:String,List,Hash,Set,ZSet

有6种底层数据结构:

  • 简单动态字符串SDS
  • 压缩列表 ZipList
  • 快表 QuickList
  • 字典/哈希表 Dict
  • 整数集 IntSet
  • 跳表 ZSkipList

1.png

键值访问

Redis用了一个全局的哈希表保存所有的键值对,一个哈希表,其实是一个数组,数组里的每一个元素对应为一个哈希桶。每个哈希桶保存键值对数据。

哈希桶中元素保存的是指向值的地址指针,这样即使值是一个集合,也能通过指针找到。

如图是全局哈希表的键值访问过程:

3.png

哈希表的查找依赖哈希计算,O(1)的时间复杂度找到键值对。

为什么哈希表操作变慢了?

既然是哈希表,可能存在哈希冲突。redis解决哈希冲突的方法是链地址法,即同一个哈希桶中的多个元素用一个链表来保存,它们之间用指针相连。

4.png

看到这,肯定有个疑问,如果冲突的元素越来越多,就会导致在这个链上查找的耗时变长,对于追求快的Redis来说,这是不能接受的。

所以,Redis会对哈希表做rehash操作。可以理解为和Java里的HashMap扩容一样。增加现有哈希桶数量,让增多的元素在更多的桶之间分散保存。

redis中rehash的方法是:

1. redis默认使用了2个全局哈希表
2. 当插入数据时,默认使用哈希表1
3. 随着数据增多,redis进行rehash操作,为哈希表2分配更大的内存空间,如是哈希表1的两倍;
4. 把哈希表1中的数据重新映射到哈希表2中
5. 释放哈希表1的内存

其中 数据重新映射 这一步涉及大量数据拷贝,如果让主线程一次全部迁移完,会造成redis线程阻塞

为了避免这一问题,redis使用了渐进式rehash

简单地说,就是在拷贝数据过程中,不是一次拷贝完。而是每处理一个请求时,从哈希表1的第一个索引位置开始,将这个位置上所有元素拷贝到哈希表2中,等处理下一请求时,再拷贝下一索引位置的数据,整个过程如下:

5.png

集合数据结构的操作

集合类型的底层结构是:整数数组,双向链表,哈希表,压缩列表,跳表

哈希表、整数列表、双向链表的操作特征都是顺序读写,操作复杂度是O(N),效率比较低。

压缩列表

  • 类似数组,表头有3个字段zlbytes、zltail、zllen,分别表示列表长度、列表尾的偏移量、列表中entry个数。
  • 表尾还有一个zlend,表示列表结束

6.png

查找定位列表的第一个元素和最后一个元素,可以通过表头3个字段的长度直接定位,复杂度O(1),查找其他元素时,只能逐个查找了,复杂度O(N)。

跳表

  • 跳表是在链表的基础上,增加了多级索引,通过索引位置的几个跳转,实现数据的快速定位

7.png

如图所示,

  • 单链表查找元素33,需要找6次;
  • 增加一级索引(每两个元素选一个出来作为索引,索引再通过指针指向原始链表),只需要找4次;
  • 增加二级索引(从一级索引中再抽取部分元素作为二级索引),只需要找3次;

当数据量很大时,跳表查找的复杂度是O(logN)

redis底层数据结构查找的时间复杂度如下表:

名称 时间复杂度
哈希表 O(1)
跳表 O(logN)
双向链表 O(N)
压缩列表 O(N)
整数数组 O(N)

思考:压缩列表和整数数组的查找时间复杂度比较高,为什么redis还要用它们呢?

  • 内存利用率

    数组和压缩列表都是非常紧凑的数据结构,比起链表,占用的内存更少,而redis是内存数据库,需要尽可能的优化,提高内存利用率;

  • 数组对CPU高速缓存支持更友好

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore     ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库 ECS 实例和一台目标数据库 RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
4月前
|
NoSQL Java Redis
SpringBoot 配置Redis操作
SpringBoot 配置Redis操作
50 0
|
4月前
|
存储 NoSQL 关系型数据库
使用lua脚本操作redis
使用lua脚本操作redis
51 0
|
11天前
|
存储 缓存 NoSQL
【Go语言专栏】Go语言中的Redis操作与缓存应用
【4月更文挑战第30天】本文探讨了在Go语言中使用Redis进行操作和缓存应用的方法。文章介绍了Redis作为高性能键值存储系统,用于提升应用性能。推荐使用`go-redis/redis`库,示例代码展示了连接、设置、获取和删除键值对的基本操作。文章还详细阐述了缓存应用的步骤及常见缓存策略,包括缓存穿透、缓存击穿和缓存雪崩的解决方案。利用Redis和合适策略可有效优化应用性能。
|
4月前
|
缓存 NoSQL Java
RedisTemplate操作Redis,这一篇文章就够了
redis是一款开源的Key-Value数据库,运行在内存中,由C语言编写。企业开发通常采用Redis来实现缓存。同类的产品还有memcache 、memcached 等。
261 1
|
1天前
|
NoSQL Java Redis
在Java中操作Redis
在Java中操作Redis
5 0
|
11天前
|
存储 NoSQL 安全
java 中通过 Lettuce 来操作 Redis
java 中通过 Lettuce 来操作 Redis
java 中通过 Lettuce 来操作 Redis
|
12天前
|
NoSQL 关系型数据库 Redis
数据管理DMS产品使用合集之要通过 DMS 登录到 RDS、DRDS 或 Redis,我该怎么操作
阿里云数据管理DMS提供了全面的数据管理、数据库运维、数据安全、数据迁移与同步等功能,助力企业高效、安全地进行数据库管理和运维工作。以下是DMS产品使用合集的详细介绍。
|
17天前
|
JSON NoSQL Java
SpringDataRedis 操作 Redis,并指定数据序列化器
SpringDataRedis 操作 Redis,并指定数据序列化器
17 1
|
1月前
|
编解码 监控 NoSQL
告别复杂操作:体验Tiny RDM,下一代Redis GUI神器登场!
告别复杂操作:体验Tiny RDM,下一代Redis GUI神器登场!
114 0
|
1月前
|
NoSQL Java Redis
SpringBoot中操作RedisTemplate获取redis中以某些字符串为前缀的KEY列表
SpringBoot中操作RedisTemplate获取redis中以某些字符串为前缀的KEY列表
32 0