`
star65225692
  • 浏览: 268240 次
  • 性别: Icon_minigender_1
  • 来自: 上海
文章分类
社区版块
存档分类

web半同步半异步模式的服务器模型

阅读更多

半年前偶然看到一叫spserver的服务器框架,它将windows下ICOP移植到到libevent,并且以HSHA,LF两种模式实现了服务器框架.我做了点功课,写点心得.

一般来说在设计一个服务器网络框架的时候,需要用到线程池,里面的线程负责执行服务端所有代码.这些代码总的来说可以分为两类:

    一类负责网络IO部分,也就是从网络读取和发送数据
    另一类负责处理各种业务逻辑.

通常情况下他们是分离的,网络IO部分不需要管理业务逻辑具体做什么工作,而后者也不关心数据怎么得来,怎么送到网络上.两者就是一个生产者消费者关系.用JMeter进行性能测试

这里讨论的HSHA就是网络IO部分为异步模式,而业务逻辑部分为同步模式.即:

    网络IO请求为非阻塞的异步操作,只要调用了,就立即返回,操作结果不用调用方不断的去问:”发送/接收成功了吗?”.网上有一个比较形象的比喻,叫经典的好莱坞法则:你不用给我们打电话,我们会通知你的(you dont call me,i will call you).
    业务逻辑部分是同步的,虽然不确定服务端线程池中,到底是哪一个线程在执行,但同一时刻只会有一个线程在执行这个网络会话上的业务逻辑.

同步和异步两部分采用一个作业队列(jobQueue)来实现结合,一些细节:

    服务端定义一组回调函数,用于将网络连接上的OnAccept,OnRecv,OnSend,OnClose等事件通知业务逻辑层,而业务逻辑层的实现代码正是在这些回调函数中实现.
    网络连接建立时,服务端会创建一个网络会话对象,并保存有相关回调函数的指针.将回调函数OnAccept和相关上下文打包成一个任务push到作业队列.
    网络连接收到数据后,服务端将回调函数OnRecv和相关上下文打包成一个任务push到作业队列.
    网络连接发送数据后,服务端将回调函数OnSend和相关上下文打包成一个任务push到作业队列.
    网络连接关闭后,服务端将回调函数OnClose和相关上下文打包成一个任务push到作业队列.
    负责执行作业的某个线程被唤醒,取出这些作业,并执行.

以下代码说明大概的处理流程:

   1: class job_queue;

   2: class msg_free_queue;

   3: class thread_pool;

   4: int main()

   5: {

   6:     job_queue jobs;

   7:     msg_free_queue msg_to_free;

   8:     thread_pool        job_thread;

   9:     thread_pool        clean_thread;

  10:     server_init_and_listen();

  11:     run_accept_thread();

  12:     while(!exit_falg){

  13:         run_iocp_event_loop(&jobs,&msg_to_free);

  14:         while(job_queue.size() > 0){

  15:             job_thread.push(job_queue.pop_front());

  16:         }

  17:         while(msg_to_free.size() > 0){

  18:             clean_thread.push(msg_to_free.pop_front());

  19:         }

  20:     };

  21: }

 
 
主线程负责完成端口事件的处理,并完成作业任务的打包,保存在一个容器中.
以上代码只说明了服务端如何把IO层收到的数据交给逻辑层,并没有解释逻辑层怎么样把数据交给IO层发送,实际上这个工作是在负责调用回调函数的那个线程完成,当回调函数返回后,作业线程直接将需要发送的数据打包成一个完成事件,post到完成端口句柄上,这样就建立起关系了.
由于是异步的,逻辑层发送的数据不能确定什么时候发送出去,因此需要保存起来,当完成事件到达后,会把已经发送的数据指针放到一个容器中,然后由主线程负责处理善后问题.

下面是一些题外话:

你也看到了,只有一个线程负责处理IO部分,那么性能如何呢?

这个吧,其实大多数时候,你的服务器性能瓶颈不再网络IO部分,而在业务逻辑处理部分,在那里可能产生磁盘IO,数据库操作等.我个人觉得但线程 IO已经足够了.采用IOCP这样高效的IO模型是为业务逻辑处理腾出资源,因为一个高效的服务端不是看你每秒能收发多少数据,而是看业务处理能力.另外单线程的IOCP也有很多好处,首先就是锁的问题解决了,其次就是资源的管理简单了,这两个问题都是比较棘手的东西.

我编译了spserver的代码,用asio的乒乓测试客户端程序做了一下压力测试,结果你可能也猜到了,IO吞吐量并不算很高,而且多核CPU 上,只有一个CPU达到了100%利用率,而另外几个CPU则利用率不足50%.如果你跟我一样,是一个完美主义者,我们可以这样改进它:

将上面的代码中,监听工作和Accept线程分离出来,主循环那的部分(while那一块和相关的上下文环境)封装成一个模块,每一个模块都有自己完成端口句柄,当连接建立时,做一个简单的负载均衡,为新建立的连接的套接字句柄选择一个完成端口句柄并绑定.于是就变成了下面的样子:

   1: class job_queue;

   2: class msg_free_queue;

   3: class thread_pool;

   4: int nod();

   5: int main()

   6: {

   7:     thread_pool io_thread_nods;

   8:     io_thread_nods.set_thread_count(4);

   9:     server_init_and_listen();

  10:     run_accept_thread();

  11:     while(true){

  12:         io_thread_nods.run(nod);

  13:     }

  14: }

  15: int nod()

  16: {

  17:     job_queue jobs;

  18:     msg_free_queue msg_to_free;

  19:     thread_pool        job_thread;

  20:     thread_pool        clean_thread;

  21:     while(!exit_falg){

  22:         run_iocp_event_loop(&jobs,&msg_to_free);

  23:         while(job_queue.size() > 0){

  24:             job_thread.push(job_queue.pop_front());

  25:         }

  26:         while(msg_to_free.size() > 0){

  27:             clean_thread.push(msg_to_free.pop_front());

  28:         }

  29:     };

  30: }

分享到:
评论

相关推荐

    C++从零开始搭建一个web服务器

    Linux下基于C++的轻量级Web服务器; (1)使用 线程池 + 非阻塞socket + epoll(ET和LT均实现) + 事件处理(Reactor、Proactor) 的并发模型; ... (3)访问服务器数据库...(4)实现同步/异步日志系统,记录服务器运行状态

    异步请求和同步请求1

    在同步请求/响应通信模型中,总是浏览器(与 web 服务器、应用服务器或 web 应用程序相对)发起请求(通过 web 用户)。在异步请求/响应通信模型中,浏览

    Java异步请求

    传统web交互模型,浏览器直接将请求发送给服务器,服务器回送响应,直接发给浏览器, Ajax交互模型,浏览器首先将请求 发送 Ajax引擎(以XMLHttpRequest为核心),AJax引擎再将请求发送给 服务器,服务器回送响应先...

    TinyWebServer.zip

    Linux下C++轻量级Web服务器,助力初学者快速实践网络编程,搭建属于自己的服务器. 使用 线程池 + 非阻塞socket + ...实现同步/异步日志系统,记录服务器运行状态 经Webbench压力测试可以实现上万的并发连接数据交换

    Linux高性能服务器编程

    第8章 高性能服务器程序框架 8.1 服务器模型 8.1.1 CS模型 8.1.2 P2P模型 8.2 服务器编程框架 8.3 IO模型 8.4 两种高效的事件处理模式 8.4.1 Reactor模式 8.4.2 Proactor模式 8.4.3 模拟Proactor模式 8.5...

    ajax长连接式的浏览器、服务器的全双工通信框架.rar

    ajax 的全称是Asynchronous JavaScript and XML(异步的JavaScript 和 XML),其中,Asynchronous 是 异步 的意思,它有别于传统web开发中采用的同步的方式。 ajax所包含的技术 1.使用CSS和XHTML来表示。 2. 使用...

    构建高性能Web站点_PDF_45.5M

    1.9 更换Web服务器软件 1.10 页面组件分离 1.11 合理部署服务器 1.12 使用负载均衡 1.13 优化数据库 1.14 考虑可扩展性 1.15 减少视觉等待 第2章 数据的网络传输 2.1 分层网络模型 2.2 带宽 2.3 响应时间 ...

    构建高性能Web站点(PDF)

    1.9 更换Web服务器软件 1.1 页面组件分离 1.11 合理部署服务器 1.12 使用负载均衡 1.13 优化数据库 1.14 考虑可扩展性 1.15 减少视觉等待 第2章 数据的网络传输 2.1 分层网络模型 2.2 带宽 2.3 响应时间 ...

    基于C++实现的轻量级Web服务器源码+项目说明.zip

    基于C++实现的轻量级Web服务器源码+项目说明.zip 开发部署环境 操作系统: Ubuntu 16.04 编译器: g++ 5.4 版本控制: git 自动化构建: cmake 集成开发工具: CLion 编辑器: Vim 压测工具:WebBench 核心功能及...

    TinyWebserver

    实现同步/异步日志系统,记录服务器运行状态 经Webbench压力测试可以实现上万的并发连接数据交换 基础测试 服务器测试环境 Ubuntu版本16.04 MySQL版本5.7.29 浏览器测试环境 Windows,Linux操作系统 Chrome合金 ...

    构建高性能Web站点(PDF)-第2部分

    1.9 更换Web服务器软件 1.1 页面组件分离 1.11 合理部署服务器 1.12 使用负载均衡 1.13 优化数据库 1.14 考虑可扩展性 1.15 减少视觉等待 第2章 数据的网络传输 2.1 分层网络模型 2.2 带宽 2.3 响应时间 ...

    WebServer:C ++ Linux Web服务器服务器

    利用单例模式与双向同步实现异步的日志系统,记录服务器运行状态;利用RAII机制实现了数据库连接池,减少了数据库连接建立与关闭的开销,同时实现了用户注册登录功能。增加logsys,threadpool测试单元(待办事项:...

    spserver:SPServer是一个用C++编写的高并发服务器框架库

    SPServer 是一个用 C++ 编写的服务器框架库,它实现了半同步/半异步和领导者/跟随者模式。 它基于 libevent,以便在任何平台上利用最佳 I/O 循环。 SPServer 可以简化 TCP 服务器的构建。 它是线程和事件驱动之间的...

    shelf:Dart 的 Web 服务器中间件

    简单地混合和匹配同步和异步处理。 使用相同模型返回简单字符串或字节流的灵活性。 有关更多信息,请参阅。 您可能还想查看和作为构建和扩展package:shelf的包的示例。 例子 参见example/example.dart import '...

    基于python3.7利用Motor来异步读写Mongodb提高效率(推荐)

    如果使用Python做大型海量数据批量任务时,并且backend用mongodb做数据储存时,常常面临大量读写...它通常用在基于Tornado的异步web服务器中。 Motor同时支持使用asyncio(Python3.4以上标准库)作为异步模型,使用起

    COM与COM+从入门到精通(pdf版本,含源码)

    关于异步服务器与客户机 让服务器进行异步处理 调用序列化与自动完成 COM管道 COM管道接口 异步管道与提前读取 调用对象与调用取消 调用取消请求 调用取消处理 轻量级处理器 标准LWH 自定义LWH 小结 第...

    MULE IN ACTION

    3.支持任何传输之上的异步,同步和请求响应事件处理机制. 4.支持Axis或者Glue的Web Service. 5.灵活的部署结构[Topologies]包括Client/Server, P2P, ESB 和Enterprise Service Network. 6.与Spring 框架集成:可...

    Ajax课件学习(免费)

    因为在web2.0的应用中,客户端的界面没有刷新,这样你就必须得告诉用户服务器端的各种状态,但是这种情况再web1中不存在,因为在web1中如果能返回页面那就是执行成功了,如果不能返回页面那执行失败。而web2.0的这种...

    CLR.via.C#.(中文第3版)(自制详细书签)

    27.6 异步实现服务器 27.7 APM和计算限制操作 27.8 APM的注意事项 27.8.1 在没有线程池的前提下使用APM 27.8.2 总是调用EndXxx方法,而且只调用一次 27.8.3 调用EndXxx方法时总是使用相同的对象 27.8.4 为...

Global site tag (gtag.js) - Google Analytics