写文章之前,我们通常会想要采用何种方式,是“开门见山”,还是”疑问式开头“。写代码也有些类似,在编码之前我们需要考虑系统整体方案,这也就是各种设计文档的作用。在设计新系统之初,我主要的目的是:保证高效率;保证高扩展性。
效率评价以”任务数/秒“做单位。由于我的系统只是客户端,不应该占用太多内存以及CPU,所以内存占用率,CPU使用率也被作为一个硬性指标。那么这里就存在疑问的地方:客户端有必要采用Boost Asio来做吗?我个人觉得这取决于客户端的规模,如果客户端需要做到高并发,那么应该采用异步IO方式来做;反之则不必。
进一步,我们是如何做到高效率?我们的设计大体流程如下:
注意:这里的任务都是同一份实例。
stream_server:负责接收任务。它实际上包括两部分:stream_server和stream_client。stream_server负责accept新连接,当连接到来时,它创建出stream_client。这个被创建出的stream_client负责具体的任务解析,任务接收。stream_client并不保存任务信息,它直接将正确的任务交由task_manager去进一步处理。stream_server内部保存着各个client实例,这是为了方便以后对并发数的限制。
task_manager实际上包括分发和检测任务超时两个功能。无论是何种功能,task_manager都不保存任务信息。分发时,task_manager将任务分配到对应的runner中去运行;检测超时,则调用各个runner提供的检测超时接口。
runner是唯一真正持有任务实例的地方。从上面我们对stream_server和task_manager的描述,这二者都不持有任务。我们希望通过这样的设计,最大限度地实现0拷贝。runner的划分根据业务而来,比如:下载某个文件之后解压,那么我们可分创先出download_runner和decompress_runner:download_runner进行下载,decompress_runner进行解压。这样细分的好处是:如果decompress_runner失败了,那么可以再交由task_manager分发到download_runner进行重试。换言之,runner可以得到重用。
client是实际执行任务的模块,任务可能是完成一次HTTP请求(长连接或是短连接由client根据任务来决定),也可能是调用一次shell脚本。为了保证任务的成功率以及原子性,client具有超时控制,以及自动重试的功能(重试次数由runner指定)。
写到这里已经很明显了,如果要做到多任务并发,或者采用多个client同时并发,或者采用多个runner同时执行任务。这里需要注意的是:runner是同步且被动的。也就是:runner同一时刻只能运行一个任务,且需要由task_manager主动给予任务。
原文地址:http://blog.csdn.net/cool_way/article/details/41039053