【网络进阶】redis、memcached、nginx网络组件(二)

1. reactor

1.1 io多路复用

IO多路复用是一种可以同时监听多个网络连接IO事件的技术,使用一个线程就可以管理多个socket。它的主要方法有select,poll,epoll。

  • select:select函数监视的文件描述符分3类,分别是writefds、readfds、和exceptfds。调用后select函数会阻塞,直到有描述符就绪(有数据可读、可写、或者有exception),或者超时。

  • poll:poll本质上和select没有区别,它将用户传入的数组拷贝到内核空间,然后查询每个fd对应的设备状态,如果设备就绪则在设备等待队列中加入一项并继续遍历,如果遍历完所有fd后没有发现就绪设备则挂起在设备等待队列中。

  • epoll:相比于select和poll,epoll更加灵活而且没有最大并发连接的限制。epoll使用一个文件描述符管理多个描述符,将用户关心的事件存放到内核的一个事件表中,这样在用户空间和内核空间的copy只需一次。

1.2 非阻塞io

非阻塞IO是指在对IO操作进行请求时,如果不能立即完成该操作,系统不会阻塞该进程,而只是立即返回一个错误信息,避免了阻塞IO需要等待的问题。

1.3 one eventloop per thread

每个线程一个事件循环(EventLoop),该设计可以避免线程之间的竞争,同时又可以充分利用多核CPU的优势,提高系统的吞吐量。

1.4 reactor为什么搭配非阻塞io

使用Reactor模型配合非阻塞IO可以更好地处理高并发场景。主要有以下几点理由:

  • 多线程环境:可以将一个listenfd放到多个epoll去处理,利用多核CPU,提高并发处理能力。

  • 边缘触发:在读事件触发时,read在一次事件循环中把read buffer读空,减少了多次触发IO事件,提高了效率。

  • 解决select bug:select在某种情况下存在问题。当某个socket接收缓冲区有新数据分节到达,然后select报告这个socket描述符可读,但随后,协议栈检查到这个新分节检验和错误,然后丢弃这个分节,这时候调用read则无数据可读,如果socket没有被设置nonblocking,此read将阻塞当前线程。

1.5 是不是io多路复用一定要搭配非阻塞io

IO多路复用并不一定要搭配非阻塞IO,但是非阻塞IO可以更好地提高系统的响应能力和处理能力。一些系统或者库在特定的场景下可能选择不使用非阻塞IO。

  • MySQL:MySQL使用select接受链接,每条链接一个线程处理,不需要使用非阻塞IO。

  • libevent:libevent库可以通过加一个系统调用来获取读缓冲区字节数,不需要使用非阻塞IO,但是这种方式效率相对较低。

    int n = EVBUFFER_MAX_READ_DEFAULT;
    if (ioctl(fd, FIONREAD, &n) < 0)
        return -1;
    return n;
    

2. redis

2.1 环境

Redis是一个开源的,基于内存的Key-Value数据库,同时也支持持久化。Redis不仅支持基本的Key-Value类型,还提供了丰富的数据类型,如Lists, Sets, Sorted Sets, HyperLogLogs等。

  • Key-Value数据库:Redis是Key-Value存储系统,也即一种内存数据库系统,同时也被认为是一种NoSQL系统。例如存取字符串:
# 存储key-value
127.0.0.1:6379> set mykey somevalue
OK
# 获取value
127.0.0.1:6379> get mykey
"somevalue"
  • 单线程命令处理:Redis采用了一种类似于Node.js的事件驱动模型,这意味着它会处理尽可能多的命令,然后返回结果,而不是为每一个连接启动一个线程。

2.2 Redis为什么要使用单Reactor

Redis使用单Reactor主要因为以下两个原因:

  • 单线程业务逻辑:Redis本身就是单线程的,在一个时间点只执行一个命令,因此在设计上使用单reactor更符合其内部的运行机制,更为简洁高效。

  • 操作具体命令时间复杂度比较低:Redis的大多数命令的时间复杂度都是O(1),即使是最复杂的操作,时间复杂度也是O(logN),这样的设计保证了即使在高并发的环境下,Redis也能保持高性能和快速的响应。

2.3 Redis怎么处理Reactor

Redis使用了一种称为“事件循环”的机制来处理客户端的请求,具体流程如下:

  1. client -> reactor:客户端向Redis服务器发送命令请求。
  2. reactor -> acceptor:Redis服务器接收到请求后,将请求转交给适当的处理程序。
  3. acceptor -> reactor:处理程序处理完请求后,将结果返回给Redis服务器。
  4. reactor -> read -> decode compute encode:Redis服务器读取请求,对请求解码,执行命令,然后将结果编码。
  5. reactor -> write:最后,Redis服务器将结果写回给客户端。

2.4 Redis针对Reactor做了哪些优化

Redis针对Reactor模型进行了一系列的优化,以提高处理效率:

  • read, decode:记录日志:在读取和解码请求时,Redis会记录详细的日志,以便在出现问题时进行调试。

  • encode, write:获取排行榜记录:在执行完命令并将结果编码后,Redis不会立即将结果返回给客户端,而是将结果暂存起来,等待其他命令一起处理,这样可以减少系统的IO操作,提高处理效率。例如,使用Redis实现一个排行榜功能:

    # 添加排行数据
    127.0.0.1:6379> zadd ranking 90 user1
    (integer) 1
    127.0.0.1:6379> zadd ranking 80 user2
    (integer) 1
    127.0.0.1:6379> zadd ranking 70 user3
    (integer) 1
    
    # 获取排行榜
    127.0.0.1:6379> zrevrange ranking 0 -1 withscores
    1) "user1"
    2) "90"
    3) "user2"
    4) "80"
    5) "user3"
    6) "70"
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Ricky_0528

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值