范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

最近沉迷Redis网络模型,无法自拔!终于知道Redis为啥这么快了

  1. 用户空间和内核态空间1.1 为什么要区分用户和内核
  服务器大多都采用 Linux 系统,这里我们以 Linux 为例来讲解:
  ubuntu 和 Centos 都是 Linux 的发行版,发行版可以看成对 linux 包了一层壳,任何 Linux 发行版,其系统内核都是 Linux 。我们的应用都需要通过 Linux 内核与硬件交互
  用户的应用,比如 redis ,mysql 等其实是没有办法去执行访问我们操作系统的硬件的,所以我们可以通过发行版的这个壳子去访问内核,再通过内核去访问计算机硬件
  计算机硬件包括,如 cpu,内存,网卡等等,内核(通过寻址空间)可以操作硬件的,但是内核需要不同设备的驱动,有了这些驱动之后,内核就可以去对计算机硬件去进行 内存管理,文件系统的管理,进程的管理等等
  我们想要用户的应用来访问,计算机就必须要通过对外暴露的一些接口,才能访问到,从而简介的实现对内核的操控,但是内核本身上来说也是一个应用,所以他本身也需要一些内存,cpu 等设备资源,用户应用本身也在消耗这些资源,如果不加任何限制,用户去操作随意的去操作我们的资源,就有可能导致一些冲突,甚至有可能导致我们的系统出现无法运行的问题,因此我们需要把用户和 内核隔离开 1.2 进程寻址空间
  进程的寻址空间划分成两部分:内核空间、用户空间
  什么是寻址空间呢?我们的应用程序也好,还是内核空间也好,都是没有办法直接去物理内存的,而是通过分配一些虚拟内存映射到物理内存中,我们的内核和应用程序去访问虚拟内存的时候,就需要一个虚拟地址,这个地址是一个无符号的整数。
  比如一个 32 位的操作系统,他的带宽就是 32,他的虚拟地址就是 2 的 32 次方,也就是说他寻址的范围就是 0~2 的 32 次方, 这片寻址空间对应的就是 2 的 32 个字节,就是 4GB,这个 4GB,会有 3 个 GB 分给用户空间,会有 1GB 给内核系统
  在 linux 中,他们权限分成两个等级,0 和 3,用户空间只能执行受限的命令(Ring3),而且不能直接调用系统资源,必须通过内核提供的接口来访问内核空间可以执行特权命令(Ring0),调用一切系统资源,所以一般情况下,用户的操作是运行在用户空间,而内核运行的数据是在内核空间的,而有的情况下,一个应用程序需要去调用一些特权资源,去调用一些内核空间的操作,所以此时他俩需要在用户态和内核态之间进行切换。
  比如:
  Linux 系统为了提高 IO 效率,会在用户空间和内核空间都加入缓冲区: 写数据时,要把用户缓冲数据拷贝到内核缓冲区,然后写入设备 读数据时,要从设备读取数据到内核缓冲区,然后拷贝到用户缓冲区
  针对这个操作:我们的用户在写读数据时,会去向内核态申请,想要读取内核的数据,而内核数据要去等待驱动程序从硬件上读取数据,当从磁盘上加载到数据之后,内核会将数据写入到内核的缓冲区中,然后再将数据拷贝到用户态的 buffer 中,然后再返回给应用程序,整体而言,速度慢,就是这个原因,为了加速,我们希望 read 也好,还是 wait for data 也最好都不要等待,或者时间尽量的短。
  2. 网络模型2.1 阻塞IO过程 1:应用程序想要去读取数据,他是无法直接去读取磁盘数据的,他需要先到内核里边去等待内核操作硬件拿到数据,这个过程是需要等待的,等到内核从磁盘上把数据加载出来之后,再把这个数据写给用户的缓存区。 过程 2:如果是阻塞 IO,那么整个过程中,用户从发起读请求开始,一直到读取到数据,都是一个阻塞状态。
  用户去读取数据时,会去先发起 recvform 一个命令,去尝试从内核上加载数据,如果内核没有数据,那么用户就会等待,此时内核会去从硬件上读取数据,内核读取数据之后,会把数据拷贝到用户态,并且返回 ok,整个过程,都是阻塞等待的,这就是阻塞 IO
  总结如下:
  顾名思义,阻塞 IO 就是两个阶段都必须阻塞等待:
  阶段一: 用户进程尝试读取数据(比如网卡数据) 此时数据尚未到达,内核需要等待数据 此时用户进程也处于阻塞状态
  阶段二: 数据到达并拷贝到内核缓冲区,代表已就绪 将内核数据拷贝到用户缓冲区 拷贝过程中,用户进程依然阻塞等待 拷贝完成,用户进程解除阻塞,处理数据
  可以看到,阻塞 IO 模型中,用户进程在两个阶段都是阻塞状态。
  2.2 非阻塞 IO
  顾名思义,非阻塞 IO 的 recvfrom 操作会立即返回结果而不是阻塞用户进程
  阶段一: 用户进程尝试读取数据(比如网卡数据) 此时数据尚未到达,内核需要等待数据 返回异常给用户进程 用户进程拿到 error 后,再次尝试读取 循环往复,直到数据就绪
  阶段二: 将内核数据拷贝到用户缓冲区 拷贝过程中,用户进程依然阻塞等待 拷贝完成,用户进程解除阻塞,处理数据 可以看到,非阻塞 IO 模型中,用户进程在第一个阶段是非阻塞,第二个阶段是阻塞状态。虽然是非阻塞,但性能并没有得到提高。而且忙等机制会导致 CPU 空转,CPU 使用率暴增。
  2.3 信号驱动
  信号驱动 IO 是与内核建立 SIGIO 的信号关联并设置回调,当内核有 FD 就绪时,会发出 SIGIO 信号通知用户,期间用户应用可以执行其它业务,无需阻塞等待。
  阶段一: 用户进程调用 sigaction ,注册信号处理函数 内核返回成功,开始监听 FD 用户进程不阻塞等待,可以执行其它业务 当内核数据就绪后,回调用户进程的 SIGIO 处理函数
  阶段二: 收到 SIGIO 回调信号 调用 recvfrom ,读取 内核将数据拷贝到用户空间 用户进程处理数据
  当有大量 IO 操作时,信号较多,SIGIO 处理函数不能及时处理可能导致信号队列溢出,而且内核空间与用户空间的频繁信号交互性能也较低。 2.4 异步 IO
  这种方式,不仅仅是用户态在试图读取数据后,不阻塞,而且当内核的数据准备完成后,也不会阻塞
  他会由内核将所有数据处理完成后,由内核将数据写入到用户态中,然后才算完成,所以性能极高,不会有任何阻塞,全部都由内核完成,可以看到,异步 IO 模型中,用户进程在两个阶段都是非阻塞状态。
  2.5 IO 多路复用场景引入
  为了更好的理解 IO ,现在假设这样一种场景:一家餐厅 A 情况:这家餐厅中现在只有一位服务员,并且采用客户排队点餐的方式,就像这样:
  每排到一位客户要吃到饭,都要经过两个步骤:
  思考要吃什么
  顾客开始点餐,厨师开始炒菜
  由于餐厅只有一位服务员,因此一次只能服务一位客户,并且还需要等待当前客户思考出结果,这浪费了后续排队的人非常多的时间,效率极低。这就是阻塞 IO。
  当然,为了缓解这种情况,老板完全可以多雇几个人,但这也会增加成本,而在极大客流量的情况下,仍然不会有很高的效率提升 B 情况: 这家餐厅中现在只有一位服务员,并且采用客户排队点餐的方式。
  每排到一位客户要吃到饭,都要经过两个步骤: 思考要吃什么 顾客开始点餐,厨师开始炒菜
  与 A 情况不同的是,此时服务员会不断询问顾客:"你想吃番茄鸡蛋盖浇饭吗?那滑蛋牛肉呢?那肉末茄子呢?……"
  虽然服务员在不停的问,但是在网络中,这并不会增加数据的就绪速度,主要还是等顾客自己确定。所以,这并不会提高餐厅的效率,说不定还会招来更多差评。这就是非阻塞 IO。 C 情况: 这家餐厅中现在只有一位服务员,但是不再采用客户排队的方式,而是顾客自己获取菜单并点餐,点完后通知服务员,就像这样:
  每排到一位客户要吃到饭,还是都要经过两个步骤: 看着菜单,思考要吃什么 通知服务员,我点好了
  与 A B 不同的是,这种情况服务员不必再等待顾客思考吃什么,只需要在收到顾客通知后,去接收菜单就好。这样相当于餐厅在只有一个服务员的情况下,同时服务了多个人,而不像 A B,同一时刻只能服务一个人。此时餐厅的效率自然就提高了很多。
  映射到我们的网络服务中,就是这样: 客人:客户端请求 点餐内容:客户端发送的实际数据 老板:操作系统 人力成本:系统资源 菜单:文件状态描述符。操作系统对于一个进程能够同时持有的文件状态描述符的个数是有限制的,在 linux 系统中 $ulimit -n 查看这个限制值,当然也是可以 (并且应该) 进行内核参数调整的。 服务员:操作系统内核用于 IO 操作的线程 (内核线程) 厨师:应用程序线程 (当然厨房就是应用程序进程咯) 餐单传递方式:包括了阻塞式和非阻塞式两种。方法 A: 阻塞 IO方法 B: 非阻塞 IO方法 C: 多路复用 IO 2.6 多路复用 IO 的实现
  目前流程的多路复用 IO 实现主要包括四种: select、poll、epoll、kqueue。下表是他们的一些重要特性的比较:
  IO 模型
  相对性能
  关键思路
  操作系统
  JAVA 支持情况
  select
  较高
  Reactor
  windows/Linux
  支持,Reactor 模式 (反应器设计模式)。Linux 操作系统的 kernels 2.4 内核版本之前,默认使用 select;而目前 windows 下对同步 IO 的支持,都是 select 模型
  poll
  较高
  Reactor
  Linux
  Linux 下的 JAVA NIO 框架,Linux kernels 2.6 内核版本之前使用 poll 进行支持。也是使用的 Reactor 模式
  epoll
  高
  Reactor/Proactor
  Linux
  Linux kernels 2.6 内核版本及以后使用 epoll 进行支持;Linux kernels 2.6 内核版本之前使用 poll 进行支持;另外一定注意,由于 Linux 下没有 Windows 下的 IOCP 技术提供真正的 异步 IO 支持,所以 Linux 下使用 epoll 模拟异步 IO
  kqueue
  高
  Proactor
  Linux
  目前 JAVA 的版本不支持
  多路复用 IO 技术最适用的是 "高并发" 场景,所谓高并发是指 1 毫秒内至少同时有上千个连接请求准备好。其他情况下多路复用 IO 技术发挥不出来它的优势。另一方面,使用 JAVA NIO 进行功能实现,相对于传统的 Socket 套接字实现要复杂一些,所以实际应用中,需要根据自己的业务需求进行技术选择。 2.6.1 select
  select 是 Linux 最早是由的 I/O 多路复用技术:
  linux 中,一切皆文件,socket 也不例外,我们把需要处理的数据封装成 FD,然后在用户态时创建一个 fd_set 的集合(这个集合的大小是要监听的那个 FD 的最大值 + 1,但是大小整体是有限制的 ),这个集合的长度大小是有限制的,同时在这个集合中,标明出来我们要控制哪些数据。
  其内部流程:
  用户态下: 创建 fd_set 集合,包括要监听的 读事件、写事件、异常事件 的集合 确定要监听的 fd_set 集合 将要监听的集合作为参数传入 select () 函数中,select 中会将 集合复制到内核 buffer 中
  内核态: 内核线程在得到 集合后,遍历该集合 没数据就绪,就休眠 当数据来时,线程被唤醒,然后再次遍历集合,标记就绪的 fd 然后将整个集合,复制回用户 buffer 中 用户线程遍历 集合,找到就绪的 fd ,再发起读请求。
  不足之处: 集合大小固定为 1024 ,也就是说最多维持 1024 个 socket,在海量数据下,不够用 集合需要在 用户 buffer 和内核 buffer 中反复复制,涉及到 用户态和内核态的切换,非常影响性能 2.6.2 poll
  poll 模式对 select 模式做了简单改进,但性能提升不明显。
  IO 流程: 创建 pollfd 数组,向其中添加关注的 fd 信息,数组大小自定义 调用 poll 函数,将 pollfd 数组拷贝到内核空间,转链表存储,无上限 内核遍历 fd ,判断是否就绪 数据就绪或超时后,拷贝 pollfd 数组到用户空间,返回就绪 fd 数量 n 用户进程判断 n 是否大于 0, 大于 0 则遍历 pollfd 数组,找到就绪的 fd
  与 select 对比: select 模式中的 fd_set 大小固定为 1024,而 pollfd 在内核中采用链表,理论上无上限,但实际上不能这么做,因为的监听 FD 越多,每次遍历消耗时间也越久,性能反而会下降
  2.6.3 epoll
  epoll 模式是对 select 和 poll 的改进,它提供了三个函数:eventpoll 、epoll_ctl 、epoll_wait eventpoll 函数内部包含了两个东西 :红黑树 :用来记录所有的 fd链表 : 记录已就绪的 fd epoll_ctl 函数 ,将要监听的 fd 添加到 红黑树 上去,并且给每个 fd 绑定一个监听函数,当 fd 就绪时就会被触发,这个监听函数的操作就是 将这个 fd 添加到 链表中去。 epoll_wait 函数,就绪等待。一开始,用户态 buffer 中创建一个空的 events 数组,当就绪之后,我们的回调函数会把 fd 添加到链表中去,当函数被调用的时候,会去检查链表(当然这个过程需要参考配置的等待时间,可以等一定时间,也可以一直等),如果链表中没有有 fd 则 fd 会从红黑树被添加到链表中,此时再将链表中的的 fd 复制到 用户态的空 events 中,并且返回对应的操作数量,用户态此时收到响应后,会从 events 中拿到已经准备好的数据,在调用 读方法 去拿数据。 2.6.4 总结:
  select 模式存在的三个问题: 能监听的 FD 最大不超过 1024 每次 select 都需要把所有要监听的 FD 都拷贝到内核空间 每次都要遍历所有 FD 来判断就绪状态
  poll 模式的问题: poll 利用链表解决了 select 中监听 FD 上限的问题,但依然要遍历所有 FD,如果监听较多,性能会下降
  epoll 模式中如何解决这些问题的? 基于 epoll 实例中的红黑树保存要监听的 FD,理论上无上限,而且增删改查效率都非常高 每个 FD 只需要执行一次 epoll_ctl 添加到红黑树,以后每次 epol_wait 无需传递任何参数,无需重复拷贝 FD 到内核空间 利用 ep_poll_callback 机制来监听 FD 状态,无需遍历所有 FD,因此性能不会随监听的 FD 数量增多而下降 2.7 基于 epoll 的服务器端流程
  一张图搞定:
  我们来梳理一下这张图 服务器启动以后,服务端会去调用 epoll_create,创建一个 epoll 实例,epoll 实例中包含两个数据 红黑树(为空):rb_root 用来去记录需要被监听的 FD 链表(为空):list_head,用来存放已经就绪的 FD 创建好了之后,会去调用 epoll_ctl 函数,此函数会会将需要监听的 fd 添加到 rb_root 中去,并且对当前这些存在于红黑树的节点设置回调函数。 当这些被监听的 fd 一旦准备就绪,与之相关联的回调函数就会被调用,而调用的结果就是将红黑树的 fd 添加到 list_head 中去 (但是此时并没有完成) fd 添加完成后,就会调用 epoll_wait 函数,这个函数会去校验是否有 fd 准备就绪(因为 fd 一旦准备就绪,就会被回调函数添加到 list_head 中),在等待了一段时间 (可以进行配置)。 如果等够了超时时间,则返回没有数据,如果有,则进一步判断当前是什么事件,如果是建立连接事件,则调用 accept () 接受客户端 socket ,拿到建立连接的 socket ,然后建立起来连接,如果是其他事件,则把数据进行写出。 2.8 五种网络模型对比:
  最后用一幅图,来说明他们之间的区别
  3. redis 通信协议3.1 RESP 协议
  Redis 是一个 CS 架构的软件,通信一般分两步(不包括 pipeline 和 PubSub): 客户端(client)向服务端(server)发送一条命令,服务端解析并执行命令 返回响应结果给客户端,因此客户端发送命令的格式、服务端响应结果的格式必须有一个规范,这个规范就是通信协议。
  而在 Redis 中采用的是 RESP(Redis Serialization Protocol)协议: Redis 1.2 版本引入了 RESP 协议 Redis 2.0 版本中成为与 Redis 服务端通信的标准,称为 RESP2 Redis 6.0 版本中,从 RESP2 升级到了 RESP3 协议,增加了更多数据类型并且支持 6.0 的新特性–客户端缓存
  但目前,默认使用的依然是 RESP2 协议。在 RESP 中,通过首字节的字符来区分不同数据类型,常用的数据类型包括 5 种: 单行字符串:首字节是 ‘+’ ,后面跟上单行字符串,以 CRLF( "r " )结尾。例如返回"OK": "+OKr " 错误(Errors):首字节是 ‘-’ ,与单行字符串格式一样,只是字符串是异常信息,例如:"-Error messager " 数值:首字节是 ‘:’ ,后面跟上数字格式的字符串,以 CRLF 结尾。例如:":10r " 多行字符串:首字节是 ‘$’ ,表示二进制安全的字符串,最大支持 512MB:如果大小为 0,则代表空字符串:"$0r r "如果大小为 - 1,则代表不存在:"$-1r " 数组:首字节是 ‘*’,后面跟上数组元素个数,再跟上元素,元素数据类型不限 :

人民币只在国内才叫人民币,出国后称呼就换了?是啥呢?据报道,近年来,我国的综合实力逐年攀升,国际影响力和地位逐渐提高。我国与其他国家和地区越来越密切的经贸往来,一带一路帮助周边临近友好国家等等一切造福自己和其他国家,因此人民币在各个两国联手,锂价飙升至78000美元吨,中国主导地位持续增强近日,珠穆朗玛峰附近发现新锂矿床,这让中国的锂储量大幅增加。与此同时,阿根廷总统签署一带一路倡议,同样是锂储量巨大的国家,中阿的联手让中国和阿根廷在全球绿色能源转型中的影响力大大增听到过最有安全感的句子1。你可以无数次向我确认我对你的爱意,但你一定要知道,在有你的选择里,我都选择你。2。见面少没关系啊,反正呢我也不会喜欢上别人,属于你的爱我一分也不会少给你。3。你在的时候,你是一浅谈高情商之冲动控制学习做个高情商的人成就精彩人生我们往往说智商决定一个人的下限,情商决定一个人的上限。那么,怎样拥有高情商呢?今天谈谈冲动控制和实际验证。冲动控制要注意以下几方面1,做决定之前先思考一下。免得自己总是为冲动的决定经常用电热水壶烧水喝,会伤害神经,还致癌?可信吗对于成年人来说,水分占到了身体的70以上,少年儿童特别是婴儿体内,水分占比要高于成年人。随着年龄的增加,体内水分流失过快,所以那些上了岁数的中老年人,身体当中的水分含量可能是相对较佟丽娅自称全班最丑,晒同学合照后,网友这都啥班级啊简易的内容带来您幸福的情绪,期待您看了最终忘掉一天的苦恼!佟丽娅是很多人内心的美女妹妹,出世新疆的佟丽娅的五官比一般女人平台式精致,而佟丽娅又比一般的新疆女人多了一份温婉。假如说佟演女主不出彩,演女二却惊艳抢镜,角色合适最重要影视剧里有些女配太惊艳,常常会艳压女主。但是当她们自己担任女主的时候却不算出彩,不过每每一演到女配,那就太轻松抢镜,哪怕有着主角光环的女主都不及。蒋欣说到演女二最惊艳的,还当属蒋欣太敷衍了!影视剧中那些无语的穿帮镜头,简直让人哭笑不得最近,热播剧人世间大火,好几次都霸占了热搜榜。实话说,这是一部良心好剧,情感刻画得非常细腻,但也有一些不得不提的小瑕疵。比如说周蓉新家里出现了电动沙发,极其富有现代化气息。在那个年谭世瑛的儿子被枪决,进京向老同学伟人告状,伟人如何处理?每个人都有自己的伙伴,都有一生难忘的挚友。生活是残酷的,出门在外没有父母亲戚的照拂只能靠朋友,所以朋友在人的一生中扮演的角色是十分重要的。有时候一个忠诚的朋友能给自己带来极大的幸运30年了,今新白娘子传奇演员现状,宝山和法海去世,碧莲优雅新白娘子传奇新白娘子传奇是许多90后心目中的童年回忆,伴随着90后一代的成长。这部剧自1992年播出,时至今日,已经过去了30年了,岁月不待人,当初年轻漂亮的演员在脸上早已经有了岁制片人裘千尺太丑女演员不肯演!张纪中没女人?那男演员呢?举起手来李明文17编辑嘈坊2005年,神雕侠侣开拍在即,导演却始终愁眉不展,因为剧中的裘千尺一角迟迟未能找到演员。裘千尺是著名的女性丑角,容貌丑陋不堪,还是个极为恶毒的反派。演员罗
砸钱砸到停服,腾讯这次认输了不知道为什么,说到财大气粗,机哥的脑子里总是会蹦出两个字腾讯。但现实是,大和粗(指财气)往往并不能解决问题,腾讯就再次给我们上了一课。腾讯忽然宣布将在11月11日的时候,停止腾讯地在鼓励生育奖励1万元的情况下,你会选择生第三胎么?10月12号湖南省长沙市卫健委,将相关文件关于对合法生育三孩子及以上的家庭,给与一次性的生育儿的补偿1万元已经下发到各县的卫健委。当然也有明确的要求,夫妻双方均为长沙市的户籍或者一侦选好基童兰谢治宇董理共管兴全趋势投资,业绩一塌糊涂百亿基金分享179兴全趋势投资(163402)各位侦探哥的粉丝们大家好,一年前,我们每天都分享一只基金,现在这个栏目又重新开始了,我们继续按照最新季度的规模排名从大到小来分析主动权能源成国际博弈重要筹码,默克尔再度发声,沙特打算和美硬刚到底能源向来都是国际社会竞争与博弈的重要筹码,俄乌冲突之后,俄罗斯与欧盟之间的能源战更是向我们生动地展现了这一真理。最近一段时间,国际社会上关于能源的战役再度打响,各种人员纷纷下场,又写给想躺平的你活着,贵在优秀从出生,到现在,这是一段人生之路。只要还活着,脚下的路,依旧在。不是躺平了,也不是闭起眼睛,这条通往未来的路就不存在的。不管我们如何回避,生老病死是无法回避的。毋庸置疑,躺平是一种诗歌丨其实我很爱你其实我很爱你文张振波其实我很爱你像秋后的山在你身后永远站立其实我很爱你像路边的那棵树作你前行的标记其实我很爱你像夏日的风暴增添你成长的阅历其实我很爱你像涓涓细流默默流向你心里即使我第十节当思考走进你的生活时,你想到了什么?小狗钱钱旁注原文摘要(概要)1在此之前(写出十个愿望之前),我不会再和你谈话了。2那天我剩下的时间里,我绞尽脑汁的想啊想啊,我要思考的东西太多了。3想到我绝对(保护好我的钱钱,对搞涉及近40家保险公司!三季度17位董事长,24位总经理变动2022年第三季度39家险企一把手发生调整任职已批复10位董事长,15位总经理官网已公告7位董事长,9位总经理9月140名保险高管新履职有高管任职获批后,被监管撤销人事密集调整期新睡眠是门好生意?有哄睡师1小时收费450,还有上市公司斥巨资设基金投资日前,麒盛科技股份有限公司(以下简称麒盛科技603610。SH)发布公告称,将出资近6亿元参与设立睡眠数字疗法基金,主要投资于睡眠数字疗法的新兴技术产业公司及生态相关的其他优质公司上半年只赚了83万元,鹿晗王一博撑不起上市公司资本市场只相信实力,不相信顶流。文中国企业家记者邓双琳编辑李薇头图来源视觉中国IPO失败四次后,风华秋实再一次向港交所发起冲击。10月12日,风华秋实集团控股有限公司第五次向港交所此前套现66亿,现又转让两公司45股权,刘强东要继续退?卸任后,他不断减持,刘强东似乎发生了一些变化。9月19日,刘强东转让系关联公司股份的消息,将刘强东再次推上热搜。这是刘强东自六月以来的又一大动作。根据京东发布的公告,刘强东同意将其