Redis阻塞操作实现原理(转)

原文:https://www.jianshu.com/p/xsMzfn

作者:Haiger

最近一位朋友问到:既然Redis是单线程的工作模式,那像 _BLPOP_这样的阻塞操作又是然后实现的呢?

接下来分别从服务端和客户端来阐述这一逻辑的实现原理。

Redis Server:
redis实现了一套事件触发模型,主要处理两种事件:I/O事件(文件事件)和定时事件。而处理它们的就靠一个EventLoop线程。同时redis还提供了丰富的数据结构,今天我们要分析的主要是List数据结构中的阻塞命令。
先来看看BLPOP的源码(做了精简,只看主要的部分,详细的可以看文尾提供的参考链接):
t_list.c

Redis阻塞操作实现原理(转)

Redis阻塞操作实现原理(转)

上面代码表明:如果客户端发来一个blpop key命令,redis先找到对应的key的list,如果list不为空则pop一个数据返回给客户端;如果对应的list不存在或者里面没有数据,就将该key添加到一个blockling_keys的字典中,value就是想订阅该key的client链表。此时对应的client的为block状态,且i/o channel里面没有写入数据。

既然是list数据结构,当然有push数据的操作:
同样是 t_list.c

Redis阻塞操作实现原理(转)

Redis阻塞操作实现原理(转)

上面代码表明:如果客户端发来一个rpush key value命令,先从blocking_keys中查找是否存在对应的key,如果存在就往ready_keys这个链表中添加该key;同时将value插入到对应的list中,并响应客户端。

从上面的分析来看,主要是blocking_keys和ready_keys的作用,那何时才会处理它们呢? 我们知道redis全靠EventLoop来处理所以的I/O事件,我们来看看所以命令的处理入口:
redis.c

Redis阻塞操作实现原理(转)

Redis阻塞操作实现原理(转)

上面代码表明:每次处理完客户端命令后都会遍历ready_keys,并通过blocking_keys找到对应的client,依次将对应list的数据pop出来并响应对应的client;同时检查是否需要再次block。

这样一来整个流程就清晰了。redis就是通过blocking_keys和ready_keys两个数据结构来实现的阻塞操作。但整个阻塞并没有阻塞EventLoop本身,从而实现命令的快速响应。算是一个典型的空间换时间的设计思路。

接下来再看看客户端如何实现一个阻塞的I/O请求。
Client:
这里我们分两种I/O模型来阐述:阻塞I/O(BIO)和非阻塞I/O(NIO)。
BIO,以Jedis为例。
BinaryJedis.java

Redis阻塞操作实现原理(转)

可以看出一个blpop请求会向redis发起两次I/O请求,一次向redis发送BLPOP key命令,一次从对应的链接管道(channel)中读取数据。由于BIO的特性当channel中没有数据时会一直阻塞,直到有新数据为止。这样就实现了客户端的阻塞效果。

注意:

这里的链接是被独享的,不然会有数据干扰。

NIO的实现就稍微复杂一些,这里分两种情况(以netty为例):
不带RquestID的实现方式
伪代码如下:

Redis阻塞操作实现原理(转)

由于NIO的特性read和write是两个I/O事件,要分别等待selector来触发,所以不能像BIO那样连续发起两次I/O操作。再加上没有requesID,当read到数据时无法找到之前对应的发起者,所以这里的链接也必须是独享的,同时由一个只能包含一个元素的阻塞队列LinkedBlockingQueue来实现阻塞的效果。

带RequestID的实现方式
伪代码如下:

Redis阻塞操作实现原理(转)

这里因为reqeust和response数据结构里都有带上了requestId,并且在链接对象上缓存了requestId和响应future的对应关系,因此链接可以不用独享。

到处,整个阻塞的实现原理分析完毕。

参考链接:
带注解的redis源码:
https://github.com/huangz1990/annotated_redis_source/blob/unstable/src/t_list.c https://github.com/huangz1990/annotated_redis_source/blob/unstable/src/redis.c
IO – 同步,异步,阻塞,非阻塞 (亡羊补牢篇)
http://blog.csdn.net/historyasamirror/article/details/5778378

Original: https://www.cnblogs.com/ajianbeyourself/p/15650518.html
Author: 奋斗终生
Title: Redis阻塞操作实现原理(转)

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/528920/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • vim的使用

    1、概述: Vim 是从 vi 发展出来的一个文本编辑器。具有代码补全、编译及错误跳转等功能 2、vim编辑器的常用命令: 图源:https://vimsky.com/articl…

    Linux 2023年5月27日
    0153
  • 灵感来袭,基于Redis的分布式延迟队列(续)

    背景 上一篇(灵感来袭,基于Redis的分布式延迟队列)讲述了基于Java DelayQueue和Redis实现了分布式延迟队列,这种方案实现比较简单,应用于延迟小,消息量不大的场…

    Linux 2023年5月28日
    093
  • Windows针对子目录共享权限控制

    Windows的共享文件设置有两种,一种是共享这一个目录然后里面的子文件,文件夹权限则集成;一种是共享这个目录后,里面的子文件与文件夹权限可单独控制。 共享一 image-2021…

    Linux 2023年6月8日
    0115
  • fork创建进程的步骤___Spring-boot-Starter启动器和其加载的过程___redis怎么监视正在执行的命令

    fork创建进程的步骤 我们都知道,在Linux中调用fork()函数,会创建一个子进程,那么在创建这个子进程的过程中,发生了些什么事情? 首先,我们要知道,fork()函数其实是…

    Linux 2023年5月28日
    0130
  • 基于CentOS系统安装OceanBase数据库

    一、OceanBase介绍 OceanBase是由蚂蚁集团完全自主研发的金融级分布式关系数据库,始创于2010年。OceanBase具有数据强一致、高可用、高性能、在线扩展、高度兼…

    Linux 2023年5月27日
    0101
  • 对比nushell和powershell

    2021-07-17 第一版 有些对比领域缺失,这篇文章会持续更新。 这是一篇对比powershell和nushell的文章。我是powerhsell专家,又是nushell新手,…

    Linux 2023年6月14日
    0125
  • nacos集群部署

    使用外置数据源-mysql 如果是使用外部数据源,只能是mysql数据库。这样的话需要在mysql数据库里面创建一个数据库,初始化语句在conf目录下,再分配一个可以读写该库的账号…

    Linux 2023年6月8日
    0115
  • 监控平台SkyWalking9入门实践

    简便快速的完成对分布式系统的监控; 一、业务背景 微服务作为当前系统架构的主流选型,虽然可以应对复杂的业务场景,但是随着业务扩展,微服务架构本身的复杂度也会膨胀,对于一些核心的业务…

    Linux 2023年6月14日
    0107
  • cpu idle 状态查看【原创】

    查看cpu idle的类型 cat /sys/devices/system/cpu/cpu0/cpuidle/state0/desc ARM WFI 查看cpu idle进入的次数…

    Linux 2023年6月8日
    0141
  • Linux系统查看磁盘可用空间的5个命令

    大家好,我是良许。 工作中,经常会遇到磁盘爆满的情况,尤其是一台服务器运行了 N 年之后,里面会充满各种各样垃圾文件,比如:编译产生的中间文件、打包的镜像文件、日志文件,等等。 别…

    Linux 2023年6月14日
    0111
  • Windows10公钥远程连接Linux服务器

    前言 一、环境准备 二、使用步骤 – 1.服务器安装并配置OpenSSH 2. 本地生成密钥 3. 服务器ssh添加密钥 三 总结 前言 使用公钥远程登陆Linux十分…

    Linux 2023年6月7日
    0115
  • 网络设备配置–9、利用ppp协议实现点对点认证

    一、前言 同系列前几篇:网络设备配置–1、配置交换机enable、console、telnet密码网络设备配置–2、通过交换机划分vlan网络设备配置&#8…

    Linux 2023年6月8日
    0101
  • 一文搞懂docker容器基础:docker镜像管理,docker容器管理

    一.系统环境 二.docker 2.1 Docker 概述 2.2 Docker 平台 2.3 我可以使用 Docker 做什么? 2.3.1 快速、一致地交付您的应用程序 2.3…

    Linux 2023年6月7日
    0190
  • redis启动失败 提示Unregistered Authentication Agent for unix-process:6176

    使用宝塔软件安装的redis 一直没启动起来。 使用 journalctl -xe 命令查看原因,发现redis.pid已经存在。 进入该目录,删除redis.pid。 再使用sy…

    Linux 2023年5月28日
    0353
  • 关于程序员成长的一些思考

    任何一名技术大神都是从小菜鸟开始的,这应该无一例外。当然,有的人成长的快,有的人成长得慢,有的人坚持下来,有的人半途而废。如果我们在成长的过程中能掌握一些方法,也许能少走一些弯路。…

    Linux 2023年6月6日
    0113
  • alpinelinux镜像安装中文字体

    镜像下载、域名解析、时间同步请点击阿里云开源镜像站 编辑dockerfile,先切换国内镜像源,默认alpinelinux是国外源,下载包会很慢 vim Dockerfile FR…

    Linux 2023年6月7日
    0129
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球