热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Redis高性能之IO多路复用

Redis之所以这么流行,就是因为它的性能贼高,之所以性能高一是因为它是内存数据库,数据

Redis之所以这么流行,就是因为它的性能贼高,之所以性能高一是因为它是内存数据库,数据的存取都是内存操作,速度很快,另一方面就是它的IO模型,下面讲讲它 的多路复用机制。

BIO

传统的IO模型是阻塞式的,服务端在接收一个连接请求和读取数据都会被阻塞,因此一个服务只能同时建立一个连接,只有本次服务完成,才能重新和别的客户端建立连接就像这样。


    //伪代码
    socket = new ServerSocket(port); 开辟一个socket
    socket.accept(); 建立连接 阻塞
    socket.read(); 读取数据 阻塞


    为了解决这个问题,可以引入多线程机制,即为每一个连接,创建一个线程,这样新连接需要建立时,就重新new一个线程,这样同时就可以建立多个连接,就像这样。


      //伪代码
      while (true) {
      new Thread(() -> {
      socket = new ServerSocket(port); 开辟一个socket
      socket.accept(); 建立连接
      socket.read(); 读取数据
      }).start();


      }


      但是因为线程的开辟是比较耗费资源,因此这个线程的数量也很有限,并且线程切换的开销对于性能要求比较高的场景,也是一个比较大的代价。


      随着内核的发展,可以使用accept和read都是非阻塞的,只需要设置非阻塞模式即可,如果没有连接或数据返回,可以很快返回-1,而不是阻塞等待。因此,我们可以将连接放进一个数组fdList,专门用一个线程不停遍历这个fd列表,这样就可以将原来一个线程监听一个fd,转换为一个线程监听一个fd列表,如下图。


      select和poll

      内核很快又有了一个系统调用select。


        int select(
        int nfds,
        fd_set *readfds, // 读数据到达fd
        fd_set *writefds, // 写数据到达fd
        fd_set *exceptfds, //异常fd
        struct timeval *timeout);
        // 返回就绪fd个数



        select系统调用入参是fd列表,我们不再需要一个额外的线程遍历这个fd列表,而是将这个遍历过程转给内核,由内核遍历fd列表,随后将就绪的fd做上标记,返回就绪的文件描述符个数,然后由用户寻找标记就绪的fd即可,这个过程的优化主要在于,将用户的遍历转为内核的遍历,省去了用户态多次无效系统调用带来的用户态和内核态的之间的多次切换。poll和select基本相同,只不过优化了select文件描述符1024的限制。

        epoll


        epoll系统调用实际上可以分为三个函数,epoll_create创建一个epoll句柄,epoll_ctl添加修改或删除监听的fd,为了使平均复杂度均衡,fds在内核中采用的红黑树结构,epoll_wait等待就绪的fd列表。epoll在select的基础上,主要优化了以下几个方面

        1.select如果一个fd迟迟没有就绪,那么将会被拷贝入内核多次,epoll只需增量添加一次

        2.select内核需要主动遍历fd是否就绪,epoll采用异步通知机制

        3.select返回就绪fd个数,用户自己遍历获取就绪标记的fd,而epoll直接返回就绪fd列表

        Redis单机能够承受住单机十万的并发量,IO的多路复用功不可没。随着Redis6.0的发布,Redis的性能又得到进一步的提升。6.0最值得注意的新特性我觉得主要有两点

        1.多IO线程

        2.客户端缓存

        因为随着Redis读写线程的性能改进,高并发情况下,网络IO也有可能成为Redis的性能瓶颈,因此IO线程引入了多线程来读取和解析网络请求,但是读写命令仍然是在主线程中执行的,因此数据的安全性依然可以得到保证。


        客户端缓存就是客户端将数据缓存在客户端,当需要读取时如果缓存没有改变,可以直接本地读取,而不需要请求服务端,缓存最大的问题就是失效如何通知的问题。6.0实现了两种模式第一种是服务端记录客户端读取过的key,如果缓存失效,服务端会给客户端发送一个失效通知,但是普通模式只会通知一次,如果key又被修改失效,则不会发起通知。只有客户端再次读取服务端,服务端才会再次发起通知。另外一种是广播模式,广播模式服务端会将客户端所有失效的key广播给客户端,这种模式下,客户端会接收到大量的失效通知,因此需要客户端按需注册,只需要注册自己关注的key即可。

        总结

        IO模型进化历程

        1.一个线程监听一个fd事件。

        2.一个线程监听一个fd列表,遍历列表查找就绪的fd(多次系统调用)。

        3.一个线程一次系统调用传入多个fd,遍历过程由内核完成。

        4.一个线程不断修改监听的fd列表,和监听已就绪的fd列表,采用异步通知机制。

                                                       





        推荐阅读
        • 思科IOS XE与ISE集成实现TACACS认证配置
          本文详细介绍了如何在思科IOS XE设备上配置TACACS认证,并通过ISE(Identity Services Engine)进行用户管理和授权。配置包括网络拓扑、设备设置和ISE端的具体步骤。 ... [详细]
        • 本文详细介绍了 InfluxDB、collectd 和 Grafana 的安装与配置流程。首先,按照启动顺序依次安装并配置 InfluxDB、collectd 和 Grafana。InfluxDB 作为时序数据库,用于存储时间序列数据;collectd 负责数据的采集与传输;Grafana 则用于数据的可视化展示。文中提供了 collectd 的官方文档链接,便于用户参考和进一步了解其配置选项。通过本指南,读者可以轻松搭建一个高效的数据监控系统。 ... [详细]
        • PTArchiver工作原理详解与应用分析
          PTArchiver工作原理及其应用分析本文详细解析了PTArchiver的工作机制,探讨了其在数据归档和管理中的应用。PTArchiver通过高效的压缩算法和灵活的存储策略,实现了对大规模数据的高效管理和长期保存。文章还介绍了其在企业级数据备份、历史数据迁移等场景中的实际应用案例,为用户提供了实用的操作建议和技术支持。 ... [详细]
        • 服务器部署中的安全策略实践与优化
          服务器部署中的安全策略实践与优化 ... [详细]
        • 在使用 SQL Server 时,连接故障是用户最常见的问题之一。通常,连接 SQL Server 的方法有两种:一种是通过 SQL Server 自带的客户端工具,例如 SQL Server Management Studio;另一种是通过第三方应用程序或开发工具进行连接。本文将详细分析导致连接故障的常见原因,并提供相应的解决策略,帮助用户有效排除连接问题。 ... [详细]
        • 如何在Java中使用DButils类
          这期内容当中小编将会给大家带来有关如何在Java中使用DButils类,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。D ... [详细]
        • 本文总结了在SQL Server数据库中编写和优化存储过程的经验和技巧,旨在帮助数据库开发人员提升存储过程的性能和可维护性。 ... [详细]
        • 在什么情况下MySQL的可重复读隔离级别会导致幻读现象? ... [详细]
        • 在CentOS 7环境中安装配置Redis及使用Redis Desktop Manager连接时的注意事项与技巧
          在 CentOS 7 环境中安装和配置 Redis 时,需要注意一些关键步骤和最佳实践。本文详细介绍了从安装 Redis 到配置其基本参数的全过程,并提供了使用 Redis Desktop Manager 连接 Redis 服务器的技巧和注意事项。此外,还探讨了如何优化性能和确保数据安全,帮助用户在生产环境中高效地管理和使用 Redis。 ... [详细]
        • 在Linux系统中避免安装MySQL的简易指南
          在Linux系统中避免安装MySQL的简易指南 ... [详细]
        • Unity与MySQL连接过程中出现的新挑战及解决方案探析 ... [详细]
        • Java Socket 关键参数详解与优化建议
          Java Socket 的 API 虽然被广泛使用,但其关键参数的用途却鲜为人知。本文详细解析了 Java Socket 中的重要参数,如 backlog 参数,它用于控制服务器等待连接请求的队列长度。此外,还探讨了其他参数如 SO_TIMEOUT、SO_REUSEADDR 等的配置方法及其对性能的影响,并提供了优化建议,帮助开发者提升网络通信的稳定性和效率。 ... [详细]
        • Keepalived 提供了多种强大且灵活的后端健康检查机制,包括 HTTP_GET、SSL_GET、TCP_CHECK、SMTP_CHECK 和 MISC_CHECK 等多种检测方法。这些健康检查功能确保了高可用性环境中的服务稳定性和可靠性。通过合理配置这些检查方式,可以有效监测后端服务器的状态,及时发现并处理故障,从而提高系统的整体性能和可用性。 ... [详细]
        • 资源管理器的基础架构包括三个核心组件:1)资源池,用于将CPU和内存等资源分配给不同的容器;2)负载组,负责承载任务并将其分配到相应的资源池;3)分类函数,用于将不同的会话映射到合适的负载组。该系统提供了两种主要的资源管理策略。 ... [详细]
        • 在深入掌握Spring框架的事务管理之前,了解其背后的数据库事务基础至关重要。Spring的事务管理功能虽然强大且灵活,但其核心依赖于数据库自身的事务处理机制。因此,熟悉数据库事务的基本概念和特性是必不可少的。这包括事务的ACID属性、隔离级别以及常见的事务管理策略等。通过这些基础知识的学习,可以更好地理解和应用Spring中的事务管理配置。 ... [详细]
        author-avatar
        廖赞胜
        这个家伙很懒,什么也没留下!
        PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
        Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有