相比与单机程序设计,多机分布式程序面临着更多的挑战,比如网络通信,多机并发,临界区同步,事件的分离与处理,不同操作系统的移植性。要想开发出健壮的,性能优秀的,跨平台的服务器/中间件,需要十分有经验的架构师,开发能力十分强悍,对底层认识很深的程序员。而设计模式帮助缓解了很多内在的和偶然的软件复杂性。模式是在特定环境中针对一个标准问题的可重复解决方案。设计模式是大师用他们的经验来帮助我们解决各种通用问题。当然在涉足服务器架构/中间件开发之前,需要有读过诸如apue,unp这样的网络编程名著,gof这种的设计模式经典,了解操作系统的各种工作机制,以及掌握c++/java和阅读过他们的优秀开源网络库/中间件。
服务器架构设计主要面临的问题,主要有四点:
1.多机设备之间的通信:
在开发单机程序时,通过函数调用传递参数或者访问全局变量即可实现组件在单个地址空间的协作。然而,在开发多机程序时,我们可以选择使用以下方式:
1)进程间通信(IPC):进程间通信也是网络编程的一个很重要的主题,诸如共享内存,管道,信号,socket等等。选择合适的进程间通信方式以及多种通信方式的协作。
2)通信协议的选择:比如FTP, HTTP,SMTP等,很多类型的服务都使用通信协议向应用程序输出凝聚在一起的组件和功能
3)上层通信中间件的选择
对于基础架构网络,访问服务通常需要调用两种系统api:
1)并发服务访问api,比如unix进程,posix pthread, win32 线程,用于管理并发
2)IPC访问API
在学习系统级c api的编程中,会遇到很多偶然的复杂性,比如底层细节繁琐,缺乏移植性,出错概率高,需要对运行机制了如执掌不然程序执行难以掌控,学习难度相比与上层应用开发也要大上很多。有些坑只有自己亲历接触过才知道怎么解决。
另外一个设计挑战:
重新配置组件中某个特定的服务角色或重新分配负载时,需要确保整个系统不会因此关机,重新编译,重新启动。
解决方法是在运行时使用动态链接的方式,使程序按需配置成为可能。
unix中的dlopen(), dlsym(), dlclose(),win32中的LoadLibrary(),GetProcAddr(), CloseHandle()
java中的Java.Applet类定义了init(), start(), stop(), destroy()钩子方法,支持动态加载的程序.
用于解决联网通***问配置服务与组件的设计模式(以下模式来自POSA卷二):
Wrapper Facade, Componet Configurator, Interceptor以及Extension Interface
2.事件处理机制:
也就是事件驱动机制,相比与“自主控制”应用程序,事件驱动具有三大特点:
1)应用程序的行为由异步发生的内部或外部事件触发。常见的事件源包括设备驱动,I/O端口,传感器,键盘鼠标,信号等
2)大多数事件必须及时处理,避免CPU长时间等待。
3)由于事件驱动应用程序通常很少或者不能控制事件到达的顺序,所以可能需要有限状态机,用于控制事件的处理和检测非法的状态迁移。
因此,事件驱动应用程序通常采用分层架构,具有控制反转。
1)事件源位于最底层,负责检测和获取事件
2)事件分离程序,比如select,epoll负责等待来自各种事件源事件的到来,然后将其分派给相应的事件处理程序回调函数
3)事件处理程序与应用程序代码一起,用于相应回调函数,进行应用程序特定的处理---这就是“控制反转”
事件驱动的四种模式:
Reactor, Proactor, Asynchronous Comletion Token和Acceptor-Connector
根据我个人阅读过以及移植/重构的网络库来说,事件驱动模式是绝大多数网络库的核心,其中Reactor模式更是大名鼎鼎。