3:高性能IO模型:为什么单线程Redis能那么快?

1:Redis单线程的概念?
Redis 是单线程,主要是指 Redis 的网络 IO 和键值对读写是由一个线程来完成的,这也是 Redis 对外提供键值存储服务的主要流程。
但 Redis 的其他功能,比如持久化、异步删除、集群数据同步等,其实是由额外的线程执行的。
2:Redis使用单线程和多线程对比?
先看一下多线程的作用:
在有合理的资源分配的情况下, 可以增加系统中处理同时多个请求操作的资源实体,
进而提升系统能够同时处理的请求数,即吞吐率。

但如果没有一个良好的设计,实际上会导致进一步新增线程时,系统吞吐率就增长缓慢了。
原因主要归结于:多线性对共同资源执行操作时,需要解决并发的问题, 
比如说加锁,这也就导致了实际上多线程也会变成串行执行。
3:Redis使用单线程为什么这么快?
第一:Redis 的大部分操作在内存上完成,再加上它采用了高效的数据结构,例如哈希表和跳表,这是它实现高性能的一个重要原因。
第二:就是 Redis 采用了多路复用机制,使其在网络 IO 操作中能并发处理大量的客户端请求,实现高吞吐率。

以一个SimpleKV(简陋版本的Redis)为例子:

以 Get 请求为例,SimpleKV 为了处理一个 Get 请求,
    1:需要监听客户端请求(bind/listen),
    2:客户端建立连接(accept),
    3:从 socket 中读取请求(recv),
    4:解析客户端发送请求(parse),
    5:根据请求类型读取键值数据(get),
    6:最后给客户端返回结果,即向 socket 中写回数据(send)。
 由于在这里的网络 IO 操作中,有潜在的阻塞点,分别是 accept() 和 recv()。
 
 1:当 Redis 监听到一个客户端有连接请求,但一直未能成功建立起连接时,
      会阻塞在 accept() 函数这里,导致其他客户端无法和 Redis 建立连接。
 
 2:当 Redis 通过 recv() 从一个客户端读取数据时,如果数据一直没有到达,
     Redis 也会一直阻塞在 recv()。
4:网络IO操作的解决方案(Socket的NIO)
Socket 网络模型的非阻塞模式设置,主要体现在三个关键的函数调用上。

三个函数的调用返回类型和设置模式概念

在 socket 模型中,不同操作调用后会返回不同的套接字类型。

1:socket() 方法会返回主动套接字(生成主动套字节)
2:然调用 listen() 方法,将主动套接字转化为监听套接字,
    此时,可以监听来自客户端的连接请求。
3:调用 accept() 方法接收到达的客户端连接,并返回已连接套接字。

理解:
        一个线程可以生成多个套接字   下面实际上只有套接字A 与套接字B
        一个线程生成的套接字会经过 请求事件的转换  分别经历下面的阶段
        主动套接字(A)  监听套接字(A)  已连接套接字(A)
        主动套接字(B)  监听套接字(B)  已连接套接字(B)
针对监听套接字,我们可以设置非阻塞模式:
当 Redis 调用 accept() 但一直未有连接请求到达时,
Redis 线程可以返回处理其他操作,而不用一直等待。

特别注意:
    调用 accept() 时,已经存在监听套接字了。    
    因为虽然 Redis 线程可以不用继续等待,
    但是总得有机制继续在监听  监听套接字  等待后续连接请求并在有请求时通知 Redis。
    
    调用 recv() 后,如果已连接套接字上一直没有数据到达,
    Redis 线程同样可以返回处理其他操作。
    我们也需要有机制继续监听该  已连接套接字 并在有数据达到时通知 Redis。
         
 这样才能保证 Redis 线程,既不会像基本 IO 模型中一直在阻塞点等待,
 也不会导致 Redis 无法处理实际到达的连接请求或数据。   
5:基于多路复用的高性能 I/O 模型
Linux 中的 IO 多路复用机制是指一个线程处理多个 IO 流,就是我们经常听到的 select/epoll 机制。
简单来说,在 Redis 只运行单线程的情况下,该机制允许内核中,同时存在多个监听套接字和已连接套接字。

内核会一直监听这些套接字上的连接请求或数据请求。
一旦有请求到达,就会交给 Redis 线程处理,这就实现了一个 Redis 线程处理多个 IO 流的效果。
    
图中的多个 FD 就是刚才所说的多个套接字。
Redis 网络框架调用 epoll 机制,让内核监听这些套接字。(由于sokcet产生的套接字)
总点:
        当这些套接字发生事件之后存入队列中 同时有可能该套接字的本身会变化类型

Redis 线程不会阻塞在某一个特定的监听或已连接套接字上,
正因为此,可以同时和多个客户端连接并处理请求,从而提升并发性。
为了在请求到达时能通知到 Redis 线程(通过回调机制重新通知Redis)
select/epoll 提供了基于事件的回调机制,即针对不同事件的发生,调用相应的处理函数。

那么,回调机制是怎么工作的呢?
当select/epoll 监听到事件之后 这些事件会被放进一个事件队列;

Redis单线程 无需一直轮询是否有请求实际发生,只需要对该事件队列不断进行处理。
这就可以避免造成 CPU 资源浪费。

然后Redis 在对事件队列中的事件进行处理时,会调用相应的处理函数,
这就实现了基于事件的回调,能及时响应客户端请求,提升 Redis 的响应性能。
6:基于多路复用的高性能 I/O 模型 小总结
关键点在于accpet和recv时可能会阻塞线程

1:使用IO多路复用技术可以让线程先处理其他事情,等需要accpet资源或者recv资源到位
2:Redis运行在其内核中的epoll会去监听多个套接字
2:epoll会调用回调函数通知线程,然后线程再去处理存/取数据;

redis的单线程既生成socket(主动套接字) 又处理 事件处理队列
redis的内核使用 epoll_wait 来进行套接字的监听 当事件发生时把事件存入 事件处理队列
6: 简单介绍下select poll epoll的区别
select和poll本质上没啥区别,就是文件描述符数量的限制,select根据不同的系统,文件描述符限制为1024或者2048,poll没有数量限制。
他两都是把文件描述符集合保存在用户态,每次把集合传入内核态,内核态返回ready的文件描述符。

epoll是通过epoll_create和epoll_ctl和epoll_await三个系统调用完成的,
每当接入一个文件描述符,通过ctl添加到内核维护的红黑树中,通过事件机制,
当数据ready后,从红黑树移动到链表,通过await获取链表中准备好数据的fd,程序去处理。
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,504评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,434评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,089评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,378评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,472评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,506评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,519评论 3 413
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,292评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,738评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,022评论 2 329
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,194评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,873评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,536评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,162评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,413评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,075评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,080评论 2 352

推荐阅读更多精彩内容

  • 1. Redis单线程 通常说Redis单线程是指Redis的网络IO和键值对读写是由一个线程完成的 2. 为什么...
    one_8274阅读 252评论 0 0
  • 众所周知,Redis 在内存数据库领域内,可谓是独领风骚,应用非常广泛。这主要得益于其丰富的数据类型和极高的性能。...
    瞎胡扯1阅读 144评论 0 1
  • 我是黑夜里大雨纷飞的人啊 1 “又到一年六月,有人笑有人哭,有人欢乐有人忧愁,有人惊喜有人失落,有的觉得收获满满有...
    陌忘宇阅读 8,532评论 28 53
  • 信任包括信任自己和信任他人 很多时候,很多事情,失败、遗憾、错过,源于不自信,不信任他人 觉得自己做不成,别人做不...
    吴氵晃阅读 6,187评论 4 8
  • 怎么对待生活,它也会怎么对你 人都是哭着来到这个美丽的人间。每个人从来到尘寰到升入天堂,整个生命的历程都是一本书,...
    静静在等你阅读 4,972评论 1 6