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

Redis底层数据结构

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

有6种底层数据结构:

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

键值访问

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

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

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

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

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

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

看到这,肯定有个疑问,如果冲突的元素越来越多,就会导致在这个链上查找的耗时变长,对于追求快的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中,等处理下一请求时,再拷贝下一索引位置的数据,整个过程如下:

集合数据结构的操作

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

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

压缩列表

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

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

跳表

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

如图所示,

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

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

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

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

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

  • 内存利用率

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

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

Redis有哪些潜在的慢操作?的更多相关文章

  1. Redis:安装、配置、操作和简单代码实例(C语言Client端)

    Redis:安装.配置.操作和简单代码实例(C语言Client端) - hj19870806的专栏 - 博客频道 - CSDN.NET Redis:安装.配置.操作和简单代码实例(C语言Client端 ...

  2. redis对sorted_set进行的相关操作

    redis对sorted_set(有序集合)类型操作的相关命令以及如何在python使用这些命令 redis对sorted_set(有序集合)类型操作的命令: 命令 语法 概述 返回值 Redis Z ...

  3. Redis 安装,配置以及数据操作

    Nosql介绍 Nosql:一类新出现的数据库(not only sql)的特点 不支持SQL语法 存储结构跟传统关系型数据库中那种关系表完全不同,nosql中存储的数据都是k-v形式 Nosql的世 ...

  4. redis基础之基本键值操作和使用(三)

    前言 redis安装完毕后开始使用redis,先熟悉命令行操作. redis数据的类型 键:redis的所有的键都是string类型: 值:五种类型 string:字符串类型:一个string最大可以 ...

  5. redis的String类型以及其操作

    Redis的数据类型 String类型以及操作 String是最简单的数据类型,一个key对应一个Value,String类型是二进制安全的.Redis的String可以包含任何数据,比如jpg图片或 ...

  6. 在centos7中安装redis,并通过node.js操作redis

    引言 最近在学习node.js 连接redis的模块,所以尝试了一下在虚拟机中安装cent OS7,并安装redis,并使用node.js 操作redis.所以顺便做个笔记. 如有不对的地方,欢迎大家 ...

  7. Redis数据类型Strings、Lists常用操作指令

    Redis数据类型Strings.Lists常用操作指令 Strings常用操作指令 GET.SET相关操作 # GET 获取键值对 127.0.0.1:6379> get name (nil) ...

  8. Redis数据类型:Hashes、Geo操作指令

    Redis数据类型:Hashes.Geo操作指令 Hashes常用操作指令 Redis Hashes是一个键值对的映射表,最对能存储2^32-1(约40亿)个键值对. HSET HGET HSET:将 ...

  9. Redis的C++与JavaScript访问操作

    上篇简单介绍了Redis及其安装部署,这篇记录一下如何用C++语言和JavaScript语言访问操作Redis 1. Redis的接口访问方式(通用接口或者语言接口) 很多语言都包含Redis支持,R ...

  10. redis常用的命令行以及操作

    redis常用的命令行以及操作 转载酱紫人的理直气壮 最后发布于2018-07-30 17:00:41 阅读数 805  收藏 转载地址:https://blog.csdn.net/li_lening ...

随机推荐

  1. Flask的简单学习

    简介 Flask是一个非常小的PythonWeb框架,被称为微型框架:只提供了一个稳健的核心,其他功能全部是通过扩展实现的:意思就是我们可以根据项目的需要量身定制,也意味着我们需要学习各种扩展库的使用 ...

  2. 极速生成缩略图,Serverless 支撑赛事转播锁定冬奥亮点

    作者 | 西流.筱姜 ​ "北京冬奥会在开赛的第四天便成为了历史上收视最高的一届冬奥会,其转播内容总生产量将达 6000 小时,超过平昌冬奥会的 5400 小时.关注北京冬奥会的人群比往届都 ...

  3. python连接liunx主机:paramiko类基本操作

    一.下载paramiko类 pip install paramiko 二.实现过程 # coding utf-8# author:Mr.white import paramiko # 创建SSHCli ...

  4. 机器学习-无监督机器学习-LDA线性判别分析-25

    目录 1. Linear Discriminant Analysis 线性判别分析 1. Linear Discriminant Analysis 线性判别分析 经常被用于分类问题的降维技术,相比于P ...

  5. 机器学习-无监督机器学习-SVD奇异值分解-24

    [POC] 1. 奇异值分解的本质 特征值分解只能够对于方阵提取重要特征, Ax=λx λ为特征值 x为对应的特征向量 奇异值分解可以对于任意矩阵: 注意看中间的矩阵是一个对角矩阵,颜色越深越起作用- ...

  6. 例2.9 建立一个带头结点的线性链表,用以存放输人的二进制数,链表中每个结点的data域存放一个二进制位。并在此链表上实现对二进制数加1的运算。

    1.题目 例2.9建立一个带头结点的线性链表,用以存放输人的二进制数,链表中每个结点的data域存放一个二进制位.并在此链表上实现对二进制数加1的运算. 2.算法分析 3.代码 /* 二进制加1 */ ...

  7. Java-Enum常量特定方法

    OnJava8-Enum-常量特定方法 用枚举实现责任链模式 责任链(Chain Of Responsibility)设计模式先创建了一批用于解决目标问题的不同方法,然后将它们连成一条"链& ...

  8. Qt5.9 UI设计(一)——在win10系统上安装Qt5.9

    安装环境 win10 系统 Qt5.9.0 版本 官方下载地址 可以从官方网站获取:https://www.qt.io/zh-cn/ 现在的安装包跟以前的有些区别,加上网络比较慢,我这里演示的是Qt5 ...

  9. [转帖]配置ftp连接对象存储bucket子目录的方法

    https://developer.jdcloud.com/article/1838 配置ftp连接对象存储bucket子目录的方法  京东云技术交付部  2021-01-27 IP归属:未知 441 ...

  10. awk的简单样例

    shell awk求和 当第一列相同时,对应的第二列相加 awk'{sum[$1]+=$2}END{for(c in sum){print c,sum[c]}}'输入文件名 在Shell中,我们可以用 ...