Redis 为何支持高并发

基本原理

  • 采用多路 I/O 复用技术可以让单个线程高效的处理多个连接请求(尽量减少网络 IO 的时间消耗)
  1. 为什么不采用多进程或多线程处理?

    • 多线程处理可能涉及到锁
    • 多线程处理会涉及到线程切换而消耗 CPU
  2. 单线程处理的缺点?

    • 无法发挥多核 CPU 性能,不过可以通过在单机开多个 Redis 实例来完善
  • Redis 不存在线程安全问题?

    Redis 采用了线程封闭的方式,把任务封闭在一个线程,自然避免了线程安全问题,不过对于需要依赖多个 redis 操作的复合操作来说,依然需要锁,而且有可能是分布式锁

  • 什么是多路 I/O 复用(Epoll)

    1. 网络 IO 都是通过 Socket 实现,Server 在某一个端口持续监听,客户端通过 Socket(IP+Port)与服务器建立连接(ServerSocket.accept),成功建立连接之后,就可以使用 Socket 中封装的 InputStream 和 OutputStream 进行 IO 交互了。针对每个客户端,Server 都会创建一个新线程专门用于处理

    2. 默认情况下,网络 IO 是阻塞模式,即服务器线程在数据到来之前处于【阻塞】状态,等到数据到达,会自动唤醒服务器线程,着手进行处理。阻塞模式下,一个线程只能处理一个流的 IO 事件

    3. 为了提升服务器线程处理效率,有以下三种思路

      • 非阻塞【忙轮询】:采用死循环方式轮询每一个流,如果有 IO 事件就处理,这样可以使得一个线程可以处理多个流,但是效率不高,容易导致 CPU 空转
      • Select 代理(无差别轮询):可以观察多个流的 IO 事件,如果所有流都没有 IO 事件,则将线程进入阻塞状态,如果有一个或多个发生了 IO 事件,则唤醒线程去处理。但是还是得遍历所有的流,才能找出哪些流需要处理。如果流个数为 N,则时间复杂度为 O(N)
      • Epoll 代理:Select 代理有一个缺点,线程在被唤醒后轮询所有的 Stream,还是存在无效操作。 Epoll 会哪个流发生了怎样的 I/O 事件通知处理线程,因此对这些流的操作都是有意义的,复杂度降低到了 O(1)
  • 其它开源软件采用的模型

    • Nginx:多进程单线程模型
    • Memcached:单进程多线程模型

参考