从spserver看HS-HA模式

原创 2010年05月29日 21:02:00

在互联网企业里,*nux下的C/C++编程主要的焦点还是server开发,关于不同的server模型,在UNP30章里有过简单的讨论,这里得出的结论就是多线程和多进程的server模型效率较高。但书中缺乏对多路复用机制的讨论,而当前主流的server模型则是epoll+multi-threads/multi-processeslighttpd就属于这种模型。本文将探讨一个更加高效的server模型,half-synchorize/half-asynchorize模式。

half-sync/half-async模型

此模式最早是由著名的C++网络编程框架ACE的作者的一篇文章,其主要思想就是用异步的方式来处理IO事件,而用同步的方式来处理业务逻辑,同步和异步之间使用一个队列作为缓冲,如下图:

此模型详细介绍可参考原文

spserver简介

引用作者对spserver的介绍:spserver 是一个实现了半同步/半异步(Half-Sync/Half-Async)和领导者/追随者(Leader/Follower) 模式的服务器框架,能够简化 TCP server 的开发工作。并且spserve使用了libevent作为底层的异步响应机制的实现。

我抱着一种学习的态度,阅读了其half-sync/half-async模式的实现代码,本文也可以看做是一篇spserver的源码分析。

代码结构

1)  spserver:主文件,程序从start方法里启动。

2)  speventcb:主要的回调函数实现逻辑。

3)  spsession:代表一个会话。

4)  sprequest:封装了客户端ipmessageDecoder,个人认为封装的不好。

5)  spresponse:封装了响应的内容。

6)  spiochannel:封装底层IO

7)  spmsgdecoder:消息解析器,判断消息是否完整。

8)  spbuffer:对libevent里的buffer的简单封装。

9)  spthreadspthreadpoolspexecutor:线程池的封装。

代码分析

spsession代表一个连接的会话,它属于half-sync/half-async模型的3层结构中的queue,业务逻辑和网络IO通过session中的input bufferoutput list来通信。

先来看一下SP_Session类的成员:

SP_Sid_t mSid; //session id,详见下一节

 

     struct event * mReadEvent; //session关联的读写事件

     struct event * mWriteEvent;

 

     SP_Handler * mHandler; //用户实现业务逻辑的handler

     void * mArg; //event args

 

     SP_Buffer * mInBuffer; //输入缓冲队列

     SP_Request * mRequest; //对请求的封装

 

     int mOutOffset; //输出偏移量,以字节为单位,表明out list中已输出的字节数

     SP_ArrayList * mOutList; // list of msg,输出的缓冲队列

 

     char mStatus; //当前session的状态,可为eNormal, eWouldExit, eExit

     char mRunning; //是否在运行

     char mWriting; //是否在写

     char mReading; //是否在读

 

     unsigned int mTotalRead, mTotalWrite; //session已读写的字节数

 

     SP_IOChannel * mIOChannel; //关联的IOChannel

session是通过SP_SessionManager来进行管理的,它实际上是一个64*1024的二维数组,entry的类型定义如下:

typedef struct tagSP_SessionEntry {

     uint16_t mSeq;

     uint16_t mNext;

 

     SP_Session * mSession;

} SP_SessionEntry;

其中每个entry都是通过一个key来标识其在matrix中的坐标,key=1024*row+col,而seq标识这个entry被使用过多少次,通过keyseq就可以形成一个ssion id了。entry中的mNext成员指向list中下一个成员的key,这样就可以快速的定位和分配listtailor

程序从SP_Server中的start方法开始,绑定server的地址和端口后,注册signal handler,然后注册listenfdonAccept异步回调函数。这里值得一提的是libevent对所有的异步调用做了抽象,甚至包括signal handler

程序的流程是通过libevent对不同的事件来回调不同的函数推进的,主要的回调函数有onAcceptonReadonWriteonResponse,下面将逐一讨论它们的流程。

onAccept

下面结合流程图对代码分析:

 

onAccept中完成了连接的初始化,主要包括:

1)  accept并为返回的clientfd注册读写事件。

2)  session manager中为连接分配一个session

3)  调用SP_EventHelper::doStart方法。

以上这些过程虽然都是通过事件触发的,但都是在主线程的main loop里的event_base_loop中调用的。而HS-HA模式主要是通过doStart方法来体现的。

doStart实际上是把一个task放到一个task queue里,而后task由一个线程完成。其主要逻辑在SP_EventHelper :: start中实现。

start中的执行步骤如下:

1)  初始化IOChannel

2)  分配response对象。

3)  调用业务逻辑实现SP_Handler中的start方法。SP_Handler中的start方法可以调用block函数,这也是为何此函数会由一个线程来调用。其实凡是用户实现的业务逻辑都是通过线程来异步调用的。

4)  调用msgqueue_push,将经过start中用户返回的response对象放入msgqueue中。msgqueue是一个带异步通知机制的队列,当response对象放入队列后,msgqueue_pop方法将被调用,它实际将response对象作为参数,调用onResponse方法。

onResponse

onResponse函数并不是通过libevent的回调机制触发的,实际上它是SP_EventArg中的response queue(实际为event_msgqueue类型)的回调函数,当队列中有response对象时,对每个response对象均调用onResponse函数。onResponse函数的主要作用就是将response对象中包含的msg对象加入到sessionoutList中。这里值得一提的是,SP_MessageSP_Session式多对多的关系,这样可以节省重复的SP_Message占用的内存。

onRead

onRead函数在fd可读和超时的情况下被调用,其主要流程为:

1)判断触发事件是否为可读,若为超时,则调用SP_EventHelper::doTimeout,它将用户实现的timeout函数封装为tasktaskpusheventArg中的InputResultQueue中,而后由executor来执行。

2)若为可读,则读入数据并解码,解码成功则调用SP_EventHelper::doWork,它将用户实现的handle函数封装为tasktaskpusheventArg中的InputResultQueue中,而后由executor来执行。

onWrite

onRead函数在fd可写和超时的情况下被调用,其主要流程为:

1)判断触发事件是否为可写,若为超时,则调用SP_EventHelper::doTimeout,它将用户实现的timeout函数封装为task,由线程调用。taskpusheventArg中的InputResultQueue中,而后由executor来执行。

2)若为可写,则将session中的outList中的msg发往client,值得注意的是,这里是通过writev来一次尽可能的多的写出数据。

总结

由上可知,一般来说Server是通过session来管理不同的连接,且在session中保留输入缓冲和输出缓冲,而后通过异步事件机制来向网络中读写数据,这便形成了half-async端。而用户实现自身的业务逻辑,且这些业务逻辑中可调用阻塞式的函数,这便形成了half-sync端,而为了提高效率,在half-sync端可使用多线程机制。

Javascript 设计模式之修饰模式【专家辅导】

-
  • 1970年01月01日 08:00

SPServer : 一个基于线程池(包括HAHS和LF)的高并发

http://www.rosoo.net/a/201001/8341.html
  • GZFStudy
  • GZFStudy
  • 2015-11-19 15:35:43
  • 629

spserver

为了搭一个spserver服务器,花了半天的时间,终于搞好了.....其实也怪我自己,因为粗心大意没看清楚编译spserver源代码工程的先后顺序,一直搞不定,果断google百度了半下午+一晚上,不...
  • zp373860147
  • zp373860147
  • 2011-09-16 21:29:11
  • 6312

网络服务器开发框架spserver源码分析 (一)

    最近工作比较轻松,有时间学习一些开源代码, 本系列文章主要分析网络服务器框架spserver, 采用的版本是最新的0.9.5(http://code.google.com/p/spserver...
  • guoxin_min
  • guoxin_min
  • 2010-11-15 17:07:00
  • 6523

SPServer中线程池实现部分分析

原文链接:http://blog.sina.com.cn/s/blog_67b570090100jsda.html 一次偶遇,看到了Half-Sync/Half-async相关论文,提到SPServe...
  • yangfm315
  • yangfm315
  • 2015-01-05 13:50:21
  • 356

SPServer

在互联网企业里,*nux下的C/C++编程主要的焦点还是server开发,关于不同的server模型,在UNP第30章里有过简单的讨论,这里得出的结论就是多线程和多进程的server模型效率较高。但书...
  • markman101
  • markman101
  • 2011-03-09 23:26:00
  • 1427

SPServer源码分析(四): 核心服务器类SP_Server分析

1。进入SP_Server的runForever函数,该函数最终转入start()函数执行2。start函数是主要执行函数函数内部使用了libevent.有关libevent编程参考官方主页。函数内部...
  • chenyinggang
  • chenyinggang
  • 2010-09-26 12:09:00
  • 5874

优秀的轻量级网络开发框架spserver源码分析(一)

1。框架介绍http://iunknown.javaeye.com/blog/59804 2。源码分析下文源码分析基于最新源码0.9.5,下载地址http://code.google.com/p/sp...
  • chenyinggang
  • chenyinggang
  • 2010-06-02 18:05:00
  • 3177

spserver 开源服务器框架研究与分析

网上开源的C/C++服务器框架 还是比较少的。 最近研究了 spserver , 里面用了较多的设计模式,使用设计模式的目的是把不变的东西和可变的东西分离并且封装起来,避免以后修改代码, 应用设计模式...
  • langeldep
  • langeldep
  • 2010-05-19 11:47:00
  • 5117

基于SPserver的大型通信服务器开发

服务方向 软件开发技术服务软件开发办公财务MIS股票设备监控网页信息采集及控制多媒体软件开发培训Java 安卓移动开发Java Web开发网站前端开发VC++C++游戏开发培训C#软件C语言(Lin...
  • zgx123666
  • zgx123666
  • 2016-02-29 17:23:51
  • 1109
收藏助手
不良信息举报
您举报文章:从spserver看HS-HA模式
举报原因:
原因补充:

(最多只允许输入30个字)