主要从三个方面进行分析:

1.事件处理模式

2.并发模式

一.事件处理模式

1.Reactoor模式

定义:

主线程只负责监听文件描述符上是否有事件发生,有的话立即将该事件通知工作线程,除此之外,主线程不做任何实质性的工作,读写数据,接受新的连接以及处理客户请求均在工作线程中完成

样例:

使用同步IO模型epoll_wait为例实现Reactor模式的工作流程:

1).主线程往epoll内核事件表中注册socket上的读就绪事件

2).主线程调用epoll_wait等待socket上有数据可读

3).当socket上有数据可读时,epoll_wait通知主线程,主线程则将socket可读事件放入请求队列

4).睡眠在请求队列上的某个工作线程被唤醒,它从socket读取数据,并处理客户请求,然后往epoll内核事件表中注册该socket上的写就绪事件

5).主线程调用epoll_wait等待socket可写

6).当socket可写时,epoll_wait通知主线程,主线程将socket可写事件放入请求队列

7).睡眠在请求队列上的某个工作线程被唤醒,它往socket上写入服务器处理客户请求的结果

2.Proactor模式

定义:

所有的IO操作都交给主线程和内核来处理,工作线程仅仅负责业务逻辑

样例:

使用异步IO模型(aio_read和aio_write)为例实现Proactor模式的工作流程

1).主线程调用aio_read函数向内核注册socket上的读完成事件,并告诉内核用户读缓冲区的位置,以及读操作完成时如何通知应用程序(信号)

2).主线程继续处理其他逻辑

3).当socket上的数据被读入用户缓冲区后,内核将向用户程序发送一个信号,以通知应用程序数据已经可用

4).应用程序预先定义好的信号处理函数选择一个工作线程来处理客户的请求,工作线程处理完客户的请求之后,调用aio_write函数向内核注册socket上的写完成事件,并告诉内核用户写缓冲区的位置,以及写操作完成时如何通知应用程序

5).主线程继续处理其他逻辑

6).当用户缓冲区的数据被写入socket之后,内核将向应用程序发送一个信号,已通知应用程序数据发送完毕

7).应用程序预先定义好的信号处理函数选择一个工作线程来做善后处理,比如决定是否关闭socket

3.使用同步IO的方式模拟Procator模式

定义:

主线程执行数据读写操作,读写完成后,主线程向工作线程通知这一完成事件,那么从工作线程的角度来看,他们就直接获得了数据的读写结果,接下来只需要对读写结果进行逻辑处理

样例:

使用同步模型(以epoll_wait为例)模拟出Proactor模式

1).主线程往内核事件表中注册socket上的读就绪事件

2).主线程调用epoll_wait等待socket上有可读数据

3).当socket上有可读数据时,epoll通知主线程,主线程从socket循环读取数据,直到没有更多的数据可读,然后将读取到的数据封装成一个请求对象并插入到请求队列

4).睡眠在请求队列上的某个工作线程被唤醒,它获得请求对象并处理客户请求,然后往epoll内核事件表中注册socket上的写就绪事件

5).主线程调用epoll_wait等待socket可写

6).当socket可写时,epoll_wait通知主线程,主线程往socket上写入服务器处理客户请求的结果

ps:Reactor模式注册的是文件描述符的就绪事件,而Procator模式注册的是完成事件

二.并发模式

1.并发编程存在的意义及背景介绍:

对计算密集型程序来说,并发编程并没有任何优势

IO密集型程序来说,并发编程具有非常大的优势,可用显著的提高性能,由于IO操作的速度远远没有CPU计算速度快,所以让程序阻塞于IO操作将浪费大量的CPU时间,如果采用多线程,那么在这个时间段,CPU就可用去做更加有意义的事情,而不是傻傻的等待IO操作的完成

在IO模型和并发模型中,同步和异步具有不同的意义

IO模型中:同步和异步区分的是内核向应用程序通知的是何种IO事件(就绪事件还是完成事件),以及由谁来完成IO读写(应用程序/内核)

并发模型中:同步和异步指的是程序的执行顺序(完全按照代码的顺序执行/执行顺序由系统事件来驱动)

按照同步方式运行的线程叫做同步线程,效率低,实时性差,但逻辑简单

按照异步方式运行的线程叫做异步线程,效率高,实时性强,但逻辑复杂

对于服务器这种既要求实时性又要求能同时处理多个客户请求的应用程序,可以同时采用同步线程和异步线程的方式实现,即半同步半异步模式

2.半同步半异步模式

概念:

该模式中,同步线程用来处理客户逻辑,异步线程用于处理IO事件

  异步线程监听到客户请求后,就将其封装成请求对象并插入请求队列中,请求队列将通知某个工作在同步模式的工作线程来读取并处理请求对象

在服务器程序中,如果考虑到事件处理模式和IO模型,那么半同步半异步模式存在好几种变种模式:半同步半异步的Reactor模式,半同步半异步的Procator模式

2.1 半同步半异步的Reactor模式(其实就是上面的Reactoor模式的样例)

概念:

异步线程只有一个,由主线程来充当

主线程负责监听所有socket上的事件

如果监听socket上有读事件发生,即有新的连接到来,主线程接受新连接的socket,然后往epoll内核事件注册表中注册该socket上的读写事件

如果连接socket上有读写事件发生,即有新的客户请求到来或者有数据要发送至客户端,主线程就将该就绪的连接socket插入到请求队列中

所有工作线程都睡眠在请求队列上,当有任务来到时,他们将通过竞争获得任务的接管权(空闲的工作线程来处理任务)

2.2 半同步半异步的Procator模式(其实就是上面的Procator模式的样例)

概念:

和半同步半异步的Reactor模式的不同之处在于半同步半异步的Reactor模式的主线程插入请求队列的是就绪的连接socket,而半同步半异步的Procator模式的主线程则会将应用程序数据,任务类型等信息封装成一个任务对象然后将其插入任务队列,两种模式的根本区别在于插入任务队列的东西不一样,一个是就绪的事件,一个是事件的结果

半同步半异步模式的缺陷:

1).请求队列需要加锁进行保护,无论是插入任务还是拉取任务都需要获得任务队列的锁,这将白白耗费CPU时间

2).工作线程数量少则无法满足需求,工作线程数量多则线程的切换将耗费大量CPU时间

2.3 高效的半同步半异步模式

概念:

  每个工作线程负责一个连接socket上的所有IO操作,这样每个工作线程都能同时处理多个客户连接(主线程对监听socket调用epoll_wait,工作线程对连接socket调用epoll_wait),无论是工作线程还是主线程都维持自己的事件循环,各自独立的监听不同的事件

不存在请求队列,主线程直接分发连接socket给工作线程

大大的减少了线程切换的次数

这种半同步半异步的模式其事件机制既可以采用Reactor也可以采用Proactor,可以主线程先直接读完socket上到来的数据,然后封装转递给工作线程,也可以由工作线程自己去读,建议采用读完封装传递的方式,这样响应更快,省去了线程切换的时间

3.领导者/追随者模式

概念:

多个工作线程轮流获得事件源集合,轮流监听,分发,并处理事件的一种模式

  在任意时间点,程序都仅有一个领导者线程,负责监听所有IO事件,而其他线程都是追随者,追随者休眠在线程池中等待成为领导者

  当前领导者如果检测到IO事件,则先从追随者中选出一位新的领导者,然后检测到IO事件的当前领导者处理IO事件,此时,新领导者等待新的IO事件,而原来的领导者处理IO事件,二者实现了并发

  这样以来,监听到IO事件的线程可以直接去处理IO事件,而不需要转交给其他线程从而浪费时间,也不需要将就绪IO事件直接放入请求队列或者读完封装放入请求队列中,不再需要请求队列,也不需要给请求队列加锁

  但是需要给线程集加锁,因为推选新的领导者和等待成为新的领导者都需要操作线程集,必须加锁避免竞态条件

  同样这种模式也仅仅支持一个事件源集合,无法像高效半同步半异步模式那样让每个工作线程独立管理多个客户连接 

  但总的来说还是非常高效的

 

-----------------------------------------------------------------------------------------------------------------

参考:《Linux高性能服务器编程》游双著

简述 高性能Linux服务器 模型架构 设计的更多相关文章

  1. 高性能Linux服务器 第10章 基于Linux服务器的性能分析与优化

    高性能Linux服务器 第10章    基于Linux服务器的性能分析与优化 作为一名Linux系统管理员,最主要的工作是优化系统配置,使应用在系统上以最优的状态运行.但硬件问题.软件问题.网络环境等 ...

  2. 高性能Linux服务器 第11章 构建高可用的LVS负载均衡集群

    高性能Linux服务器 第11章 构建高可用的LVS负载均衡集群 libnet软件包<-依赖-heartbeat(包含ldirectord插件(需要perl-MailTools的rpm包)) l ...

  3. 高性能Linux服务器

    TCP/IP协议族——高性能Linux服务器编程   现在 Internet 使用的主流协议族是 TCP/IP 协议族,它是一个分层.多协议的通信体系. TCP/IP 协议族体系结构以及主要协议 TC ...

  4. [转]【转】大型高性能ASP.NET系统架构设计

    大型高性能ASP.NET系统架构设计 大型动态应用系统平台主要是针对于大流量.高并发网站建立的底层系统架构.大型网站的运行需要一个可靠.安全.可扩展.易维护的应用系统平台做为支撑,以保证网站应用的平稳 ...

  5. 高性能Linux服务器 第6章 ext3文件系统反删除利器ext3grep extundelete工具恢复rm -rf 误删除的文件

    高性能Linux服务器 第6章  ext3文件系统反删除利器ext3grep  extundelete工具恢复rm -rf 误删除的文件 只能用于ext3文件系统!!!!!!!高俊峰(高性能Linux ...

  6. 优化系统资源ulimit《高性能Linux服务器构建实战:运维监控、性能调优与集群应用》

    优化系统资源ulimit<高性能Linux服务器构建实战:运维监控.性能调优与集群应用> 假设有这样一种情况,一台Linux 主机上同时登录了10个用户,在没有限制系统资源的情况下,这10 ...

  7. 优化Linux内核参数/etc/sysctl.conf sysctl 《高性能Linux服务器构建实战:运维监控、性能调优与集群应用》

    优化Linux内核参数/etc/sysctl.conf  sysctl  <高性能Linux服务器构建实战:运维监控.性能调优与集群应用> http://book.51cto.com/ar ...

  8. 高性能linux服务器内核调优

    高性能linux服务器内核调优 首先,介绍一下两个命令1.dmesg 打印系统信息.有很多同学们服务器出现问题,看了程序日志,发现没啥有用信息,还是毫无解决头绪,这时候,你就需要查看系统内核抛出的异常 ...

  9. 手机服务器微架构设计与实现 之 http server

    手机服务器微架构设计与实现 之 http server ·应用 ·传输协议和应用层协议概念 TCP  UDP  TCP和UDP选择 三次握手(客户端与服务器端建立连接)/四次挥手(断开连接)过程图 · ...

随机推荐

  1. LeetCode 1249. Minimum Remove to Make Valid Parentheses

    原题链接在这里:https://leetcode.com/problems/minimum-remove-to-make-valid-parentheses/ 题目: Given a string s ...

  2. Sequelize 数据类型

    Sequelize.STRING // VARCHAR(255)Sequelize.STRING(1234) // VARCHAR(1234)Sequelize.STRING.BINARY // VA ...

  3. OpenFOAM——前台阶

    本算例来自<ANSYS Fluid Dynamics Verification Manual>中的VMFL037:Turbulent Flow Over a Forward Facing ...

  4. [基础不过关填坑] 跨iframe触发事件

    子iframe $("#testId").on("change",function(){ alert("change") }) 父页面 $( ...

  5. pm2 启动模式 fork 和 cluster 的区别

    fork模式,单实例多进程,常用于多语言混编,比如php.python等,不支持端口复用,需要自己做应用的端口分配和负载均衡的子进程业务代码. 缺点就是单服务器实例容易由于异常会导致服务器实例崩溃. ...

  6. 经典算法(三) 单链表 反转 & 是否相交/成环 & 求交点 等

    参考文章: 判断链表是否相交:http://treemanfm.iteye.com/blog/2044196 一.单链表反转 链表节点 public class Node { private int ...

  7. Java API设计原则清单

    在设计Java API的时候总是有很多不同的规范和考量.与任何复杂的事物一样,这项工作往往就是在考验我们思考的缜密程度.就像飞行员起飞前的检查清单,这张清单将帮助软件设计者在设计Java API的过程 ...

  8. php 加载 zip 文件

    header('Content-type: application/zip');header('Content-Disposition: attachment; filename="Quer ...

  9. springboot响应消息(http)的编码设置

    一.方式一 在单个REST接口上设置 @ResponseBody @RequestMapping(value = "sys/getTree1",method = RequestMe ...

  10. php nl2br 将\n变成<br />

    <?php $str="h t m l"; //定义一个多处换行的字串 echo "未处理前的输出形式:<br />{$str}"; #nl2 ...