代码编织梦想

        redis作为一种常见的kv数据库,在实际中使用非常广泛,其最大的特点就是"快",在系统中常被用来当做缓存快速获取想要数据。我们也会经常被问到,redis为什么这么快呢?兄弟们常常都是以下的回答:

  • redis基于内存
  • redis是单线程
  • redis采用阻塞式io和多路io复用
  • 优化了数据结构

        相信许多的兄弟在刚刚毕业的时候都是这个回答,我当初也是如此。随着我们年龄的增长,以及对技术的不断了解。我们不能只局限于此,我将把这几点具体展开。

redis基于内存

        这一点想必是大家最耳熟能详的一句话了。redis为什么快?因为基于内存!

        不过也确实如此,MySQL的数据和索引都是持久化保存在磁盘上的,因此当我们使用SQL语句执行一条查询命令时,如果目标数据库的索引还没被加载到内存中,那么首先要先把索引加载到内存,再通过若干寻址定位和磁盘I/O,把数据对应的磁盘块加载到内存中,最后再读取数据。Redis把数据存在内存中,读写都直接对数据库进行操作,天然地就比硬盘数据库少了到磁盘读取数据的这一步。

        不过redis快,基于内存是一个很重要的因素。不过不是全部的因素。

redis是单线程

        在很久以前,当时秋招的我在背到这一条的时候其实是纳闷的。

        redis单线程所以快?不应该是多线程来的快些吗?

        多线程有时候确实比单线程快,但也有很多时候没有单线程那么快。比如并发时,并发是指多个进程指令在一个cpu中运行在宏观上具有多个进程同时执行的效果,但在微观上并不是同时执行的,只是把时间分成若干段,使多个进程快速交替的执行。

        在这种并发的情况下,就涉及到上下文切换的问题了。在切换前会保存上一个任务的状态,以便下次切换回这个任务时,可以再加载这个任务的状态。redis的单线程模式就不需要上下文切换,提升了速度。避免了不必要的上下文切换和竞争条件,也不存在多进程或者多线程导致的切换而消耗 CPU,不用去考虑各种锁的问题,不存在加锁释放锁操作,没有因为可能出现死锁而导致的性能消耗。

redis采用非阻塞式io和多路io复用

        非阻塞式io当用户进程发出 read 操作时,如果内核中的数据还没有准备好,那么它不会阻塞用户进程,而是立刻返回一个错误。从用户进程角度讲,它发起一个read操作后,并不需要等待,而是马上就得到了一个结果。当用户进程判断结果是一个错误时,它就知道数据还没有准备好,于是它可以再次发送read操作。

        多路IO复用,有时也称为事件驱动IO。它的基本原理就是有个函数会不断地轮询所负责的所有socket,当某个socket有数据到达了,就通知用户进程。

优化了数据结构

        redis实现的数据结构,使得我们对数据进行增删查改操作时,Redis 能更加高效的处理。具体的数据结构主要有以下这些:



SDS

        Redis 是用 C 语言实现的,但是它没有直接使用 C 语言的 char* 字符数组来实现字符串,而是自己封装了一个名为简单动态字符串(simple dynamic string,SDS) 的数据结构来表示字符串,也就是 Redis 的 String 数据类型的底层数据结构是 SDS。

        为啥要封装这样应该数据结构呢?

        首先,之前c语音的char的数据结构有缺陷!char类型的数据结构在读取到\0的时候就看做字符串结束,这样会有两个问题:

  1. 要是字符串中含有\0时会提前结束。
  2. 每次查询char类型的长度时,时间复杂度位0(n)
  3. C 语言的字符串是不会记录自身的缓冲区大小的,字符串操作函数不高效且不安全,比如可能会发生缓冲区溢出,从而造成程序运行终止。

        Redis封装的SDS数据结构如下:

 

  •  len记录所保存字符串的长度
  • alloc,分配给字符数组的空间长度
  • flags,SDS 类型,用来表示不同类型的 SDS
  • buf[],字节数组,用来保存实际数据

        因为 SDS 不需要用 “\0” 字符来标识字符串结尾了,而且 SDS 的 API 都是以处理二进制的方式来处理 SDS 存放在 buf[] 里的数据,程序不会对其中的数据做任何限制,数据写入的时候时什么样的,它被读取时就是什么样的。

        不会发生缓冲区溢出,Redis 的 SDS 结构里引入了 alloc 和 leb 成员变量,这样 SDS API 通过 alloc - len 计算,可以算出剩余可用的空间大小,这样在对字符串做修改操作的时候,就可以由程序内部判断缓冲区大小是否足够用 。不够用时自动扩大空间大小。

        节省内存空间,通过不同类型的sds可以节省内存空间。

双向链表

         listnode节点是每一个双向链表节点的结构:

typedef struct listNode {
    //前置节点
    struct listNode *prev;
    //后置节点
    struct listNode *next;
    //节点的值
    void *value;
} listNode;

        Redis 在 listNode 结构体基础上又封装了 list 这个数据结构,这样操作起来会更方便,链表结构如下:

  • listNode 链表节点带有 prev 和 next 指针,获取某个节点的前置节点或后置节点的时间复杂度只需O(1),而且这两个指针都可以指向 NULL,所以链表是无环链表;

  • list 结构因为提供了表头指针 head 和表尾节点 tail,所以获取链表的表头节点和表尾节点的时间复杂度只需O(1);

  • list 结构因为提供了链表节点数量 len,所以获取链表中的节点数量的时间复杂度只需O(1);

  • listNode 链表节使用 void* 指针保存节点值,并且可以通过 list 结构的 dup、free、match 函数指针为节点设置该节点类型特定的函数,因此链表节点可以保存各种不同类型的值;

         链表的缺陷也是有的,链表每个节点之间的内存都是不连续的,意味着无法很好利用 CPU 缓存。

        这时便设计出来了压缩链表来更好的利用CPU 缓存来加速访问。

压缩列表

压缩列表是 Redis 数据类型为 list 和 hash 的底层实现之一。

  • 当一个列表键(list)只包含少量的列表项,并且每个列表项都是小整数值,或者长度比较短的字符串,那么 Redis 就会使用压缩列表作为列表键(list)的底层实现。

  • 当一个哈希键(hash)只包含少量键值对,并且每个键值对的键和值都是小整数值,或者长度比较短的字符串,那么 Redis 就会使用压缩列表作为哈希键(hash)的底层实现。 

 压缩列表在表头有三个字段:

  • zlbytes,记录整个压缩列表占用对内存字节数;

  • zltail,记录压缩列表「尾部」节点距离起始地址由多少字节,也就是列表尾的偏移量;

  • zllen,记录压缩列表包含的节点数量;

  • zlend,标记压缩列表的结束点,特殊值 OxFF(十进制255)。

哈希表 

         哈希表是一种保存键值对(key-value)的数据结构。

        哈希表中的每一个 key 都是独一无二的,程序可以根据 key 查找到与之关联的 value,或者通过 key 来更新 value,又或者根据 key 来删除整个 key-value等等。

        Hash 表优点在于,它能以 O(1) 的复杂度快速查询数据。主要是通过 Hash 函数的计算,就能定位数据在表中的位置,紧接着可以对数据进行操作,这就使得数据操作非常快。

        但是存在的风险也是有,在哈希表大小固定的情况下,随着数据不断增多,那么哈希冲突的可能性也会越高。

        解决哈希冲突的方式,有很多种。Redis 采用了链式哈希,在不扩容哈希表的前提下,将具有相同哈希值的数据链接起来,以便这些数据在表中仍然可以被查询到。

 

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/m0_58366209/article/details/127994149

分布式缓存redis知识点总结_圣小童的博客-爱代码爱编程

Redis是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。 Redis V3.2 数据结构及操作 数据类型 主要操作 底层实现

我想说,什么时候都不晚。-爱代码爱编程

作者:阿秀阿秀的求职笔记:https://interviewguide.cn 你好,我是阿秀,今天想跟大家分享点不一样的。 有位小学弟,认识我一年多了,从去年年末就关注我了,可以说是我最开始的一批粉丝啦。 前段时间也是跟我私聊后进了我的学习小圈子,这是他发表在学习圈子里的一篇新人报道,我觉得他写的情真意切,在取得他的同意后想给大家分享一下他

狂神说 redis 笔记-爱代码爱编程

狂神说 redis 笔记 Nosql概述 为什么要学Nosql 我们先在处于大数据时代,大数据一般的数据库无法进行分析处理了!2006 Hadoop 压力一定会越来越大,适者生存!一定要逼着自己学习,这是在这个社会生存的唯一法则! 1、单机MySQL的时代 90年代,一个基本的网站访问量一般不会太大,单个数据库完全足够! 那个时候,更多的去

来自未来,2022 年的前端人都在做什么?-爱代码爱编程

来自上帝视角的总览 这是一份来自未来的文档,感谢你对前端技术领域持续关注。 编程语言趋势大观:Python 反超 JavaScript 数据来源 Github 根据 Github 的相关数据我们可以发现 JavaScript 常年保持榜首位置,但是在 2021 年 Q4 被 Python 反超(很可能是因为分流了一部分人去使用 Typ

金三银四,作为java程序员的你为什么面试总拿不到高薪?_周坤java的博客-爱代码爱编程

金三银四指的是每年的三四月份都是人才招聘的高峰期,因为跟春节和春运紧接,到人才市场,人都是满的,所以称为金三,伴随的四月则称为银四,每一年职场迎来“金三银四”。 总结做完了,得失看清了,奖金拿到了,“算账”过后的职场人可谓一身轻松。有什么计划,可以放心做起来,一场接一场的招聘会更是把职场人的心撩拨得蠢蠢欲动。迂回作战、直奔目标、潇洒“裸辞”。 如果有了

springboot2.7.4整合redis_这人很懒没留下什么的博客-爱代码爱编程

目录 一、添加maven依赖 二、添加配置项 三、新增配置类 四、编辑实体类 五、编写接口 六、编写业务层 1.编写service层 2.编写service实现层  七、测试接口 一、添加maven依赖 <dependency> <groupId>org.springframework.boot&l

刨根问底 redis, 面试过程真好使_娜布其 20224016017的博客-爱代码爱编程

充满寒气的互联网如何在面试中脱颖而出,平时积累很重要,八股文更不能少!下面带来的这篇 Redis 问答希望能够在你的 offer 上增添一把🔥。 在 Web 应用发展的初期阶段,一个网站的访问量本身就不是很高,直接使用关系型数据库就可以应付绝大部分场景。但是随着互联网时代的崛起,人们对于网站访问速度有着越来越高的要求,直接使用关系型数据库的方案

redis缓存何以一枝独秀?以及热门面试题中redis的核心特性_程序员阿金的博客-爱代码爱编程

​Redis的各种数据类型 作为缓存组件,Redis的数据结构整体而言就是key-value类型的键值对,但是Redis对于value类型的支持还是比较丰富的,提供了5种不同的数据结构,可以满足大部分场景的使用诉求。 ​对几种类型的结构特点与使用注意点梳理汇总如下: 类型 说明 支持功能 string 普通字符串 字符

使用redis查询数据库数据增加访问速度小案例_msss-的博客-爱代码爱编程

黑马B栈网课案例 文章目录 案例需求:SQL建表所需jar包项目结构代码展示index.html首页面domainProcince.java daoProvinceDaoProvinceDaoImp

linux docker 安装 redis_kingcruel的博客-爱代码爱编程

1、Redis 搜索,下载,查看 # 搜索 redis 镜像 docker search redis # 下载 redis 镜像 docker pull redis:bullseye # 查看所有镜像 docker images 2、创建 Redis 配置文件 # 创建文件夹目录 mkdir -p /home/20221125/myredis/c

如何看待2023年秋招技术岗哀鸿遍野?-爱代码爱编程

昨天在知乎上看到个提问"如何看待2023年秋招技术岗哀鸿遍野?"。 最近有很多读者都找我咨询秋招问题,发现同学们的秋招之路都不是很顺,不是个人的问题,而是大环境的问题,今年秋招形势的确是很严峻! 以下是我在知乎的回答 字节2022秋招有8000hc,今年2023届秋招只有3000hc,减少了60% 阿里秋招8.18才开始,

2023年秋招技术岗-爱代码爱编程

昨天在知乎上看到个提问"如何看待2023年秋招技术岗哀鸿遍野?"。 最近有很多读者都找我咨询秋招问题,发现同学们的秋招之路都不是很顺,不是个人的问题,而是大环境的问题,今年秋招形势的确是很严峻! 以下是我在知乎的回答 字节2022秋招有8000hc,今年2023届秋招只有3000hc,减少了60% 阿里秋招8.18才

redis实战篇(三)秒杀_redis lua 自增id-爱代码爱编程

一、全局唯一ID (1)定义 全局ID生成器,是一种在分布式系统下用来生成全局唯一ID的工具,一半满足下列特性: 唯一性高可用高性能递增性安全性 为了增加ID的安全性,我们不直接使用Redis自增的数值,而是拼接一些

redis持久化策略aof、rdb详解及源码分析_rdb-爱代码爱编程

写在前面 以下内容是基于Redis 6.2.6 版本整理总结 一、Redis为什么要持久化 Redis 是一个内存数据库,就是将数据库中的内容保存在内存中,这与传统的MySQL,Oracle等关系型数据库直接将内容保存

springboot 小巧简便的限流器使用 ratelimiter_springboot ratelimiter-爱代码爱编程

前言 之前,写过一篇基于redis限流,能应用到分布式相关场景:(Redis使用系列) Springboot 使用redis实现接口Api限流 十_小目标青年的博客-CSDN博客 也在很久之前,写过一个使用也非常便捷的,整合current-limiting的:Springboot 整合 Current-Limiting 实现接口限流_小目标青年的博