redis网络模型

    • 用户空间和内核空间
    • IO
      • 五种IO模型
        • 阻塞IO
        • 非阻塞IO
        • IO多路复用
          • select
          • poll
          • epoll
          • web服务流程
        • 信号驱动IO
        • 异步IO
      • IO模型比较
    • redis网络模型
      • redis为什么是单线程
      • redis单线程网络模型流程

用户空间和内核空间

为安全,将用户应用和系统应用分隔开,产生用户空间和内核空间
32位操作系统,内存大小为2^32(4G)
redis网络模型_第1张图片

IO

用户空间和内核空间各有一个缓冲区

  • 写数据:数据->用户缓冲区->内核缓冲区->写入设备
  • 读数据:设备->内核缓冲区->用户缓冲区->读出数据
    读数据时,首先要等待数据到达内核缓冲区,其次从内核缓冲区拷贝数据到用户缓冲区

五种IO模型

阻塞IO

进程阻塞,等待数据到达内核缓冲区(数据就绪)
redis网络模型_第2张图片

非阻塞IO

多次查询数据是否就绪,立即返回结果,不阻塞线程。
多次查询并未提高进程性能,反而使得cpu使用率增加
redis网络模型_第3张图片

IO多路复用

利用单个线程同时监听多个文件描述符FD,在某个文件就绪时得到通知,充分利用CPU,避免无效等待

select
  • 用户空间创建要监听的FD集合,将要监听的FD的对应bit位设为1。拷贝到内核空间。
  • 内核空间遍历FD集合,监听FD,阻塞等待,直到FD集合中有就绪数据,遍历FD集合,已就绪的不处理,未就绪的设为0,然后将FD集合拷贝到用户空间,覆盖原来的。此时FD集合中为1的是已就绪的,并告知共有几个问就绪。
  • 用户空间遍历集合,找到已就绪的数据
poll

redis网络模型_第4张图片

epoll
  • 用户空间epoll_create生成eventpoll,拷贝到内核空间
  • 用户空间epoll_ctl添加FD到内核空间的eventpoll的rbr中
  • FD就绪则触发callback函数,将FD添加到rdlist中
  • epoll_wait阻塞等待一段时间,检查rdlist是否有就绪数据,如果rdlist不为空,则返回rdlist的大小(就绪的文件数量)并将rdlist拷贝到用户空间,如果为空则再次epoll_wait

    redis网络模型_第5张图片
    事件通知机制:调用epoll_wait,当FD就绪,得到通知
  • LT,数据可读时,多次通知(每调用epoll_wait一次,得到一次通知)直到数据处理完成。epoll的默认模式。重复通知,效率↓。
  • ET,一次通知(第一次调用epoll_wait,得到一次通知,之后不再通知)
    eg:将rdlist拷贝到用户空间
    先将rdlist的链表指针断开,判断事件通知机制模式
    如果是ET,则开始拷贝,拷贝后删除内核空间数据,因指针断开之后rdlist为空,则下一次epoll_wait时不会通知
    如果是LT,则开始拷贝,当没有拷贝完时,恢复指针将数据连在rdlist中,下一次epoll_wait时,rdlist仍有数据,继续通知,继续读
    • ET可以手动添加回rdlist
    • LT 可以while循环,一次将数据拷贝完,无需再添加回rdlist。
      读取FD集合时,当读不到了进程会阻塞等待,直到有新的数据,所以while循环无法结束。应当采用非阻塞方式,每次读取立即返回无论是否有值
    • LT惊群现象: 数据一直存在rdlist中,每一次检查调用epoll_wait,都会显示有数据就绪,会唤醒等待的进程,多个进程都被唤醒,而然在最初的进程接收并处理完数据后,其他进程获取不到数据,所以根本无需唤醒。
web服务流程

redis网络模型_第6张图片

信号驱动IO

当内核有FD就绪时,发出SIGIO信号通知用户。无需阻塞等待也无需轮询
redis网络模型_第7张图片

  • 大量IO,SIGIO信号放在队列,可能导致队列溢出
  • 用户空间和内核空间频繁信号交互,效率低

异步IO

redis网络模型_第8张图片

  • 高并发时,内核空间需要处理的数据过多,内存占用过大,系统崩溃

IO模型比较

同步异步看内核和用户空间拷贝过程
redis网络模型_第9张图片

redis网络模型

redis为什么是单线程

核心业务部分(命令处理):单线程
核心网络模型:多线程,提高cpu利用率

  • redis,纯内存操作,快
  • 性能瓶颈为网络延迟,多线程没有帮助
  • 多线程上下文切换有开销
  • 多线程存在线程安全问题,需要引入锁,复杂度提高,性能降低

redis单线程网络模型流程

  • serverSocket注册到aeEventLoop中监听,通过aeApiPoll(epoll_wait)检查serverSocket是否可读
  • serverSocket可读,则由tcpAccpetHandler处理。得到clientSocket连接
  • clientSocket注册到eventLoop中监听,通过aeApiPoll(epoll_wait)检查clientSocket是否可读,由readQueryFromClient处理
  • 将clientSocket包装为一个client,读取数据放到client的buffer中,将buffer转为redis命令
  • 将redis命令执行结果存储在client中(需要写回client客户端),放在队列里
  • clientSocket可写时,将队列中的数据写入
    redis网络模型_第10张图片
  • aeEventLoop到aeApiPoll == IO多路复用+事件派发
  • 从clientSocket读写数据,受网络影响——>增加多线程

你可能感兴趣的:(redis,redis,网络,数据库)