关于高性能网络编程的一些总结与思考

从IO说起

一直以来我很欣赏Google I/O大会,一方面是由于一些新技术与新产品的介绍让人兴奋,更重要的是我太爱这个名字了^_^,我觉得正好符合了我对整个互联网技术的浅薄思考与认识。I/O系统就是整个互联网的关键接口,整个互联网的底层就是I/O系统织成的抽象意义上的net,建立在物理线路之上。而网络编程显然是合理创造与利用I/O的重要工具。而以太网的TCP/UDP则在通常的网络编程中占据了核心的地位。本文主要基于Linux平台,其他如Windows NT以及一些Unix衍生版都提供了对应的解决方案。

网络编程是一个很大也很有趣的话题,要写好一个高性能并且bug少的服务端或者客户端程序还是挺不容易的,而且往往涉及到进程线程管理/内存管理/NFS/协议栈等许多相关的知识,所以不仅仅只是会使用socket那么简单。

网络编程模型

首先简单解释几个相关概念:

阻塞/非阻塞 阻塞和非阻塞通常是指文件描述符本身的属性,拿socket来说,,当socket读缓冲区中没有数据时或者写缓冲区满时,都会造成我们read/recv或者write/send系统调用阻塞。而非阻塞socket在这种情况下会产生EWOULDBLOCK或者EAGAIN等错误并立即返回,不会等待socket变得可读或者可写。当然这只是理解阻塞和非阻塞的一个简单例子,并不全面。在Linux下我们可以通过accept4/fcntl等函数设置socket为非阻塞。

同步/异步 同步和异步更多地是我们怎么处理读写问题的一种手段,这里仅仅限制在IO读写上,真正的这两个概念个人觉得可以推得更广。通常这也对应着两种高性能网络编程模式reactor和proactor,同步通常是我们主动读写数据,而异步通常是我们交给操作系统帮我们读写,只需要注册读写完成后的回调函数。

IO复用 IO复用通常是用select/poll/epoll等来统一代理多个socket的事件的发生,select是一种比较通用的多路复用技术,很多平台都支持,poll是Linux平台下对select做的改进,而epoll可以说是目前Linux平台下性能最高的一种multiplexing技术,当然你得用好,尤其是LT和ET两种触发方式的使用。

下面简单总结了常见的服务器端使用的网络编程模型(包含线程模型)

先看看常见组件采用的模型(只看epoll):

nginx:master进程+多个worker进程,每个进程一个epoll eventloop memcached: 主线程+多个worker线程,每个线程一个epoll eventloop tornado:单线程,一个epoll eventloop libevent:对于Linux平台封装了epoll libev:对于Linux平台封装了epoll boost.asio:对于Linux平台封装了epoll muduo:对于Linux平台封装了epoll swoole:对于Linux平台封装了epoll nodejs的libuv:基于libev对epoll的封装 …

所以排除掉传统的单线程,多进程,多线程等模型,常见的高性能网络编程模型通常是one eventloop per thread与多线程的组合,或者为了处理耗时的任务再加上threadpool。通常为了更好地性能与并发,以master/worker的形式来配置进程线程模型。其实说到底各种高性能网络库或者框架还是在玩epoll+非阻塞。

值得注意的问题选择线程模型 单线程下不用考虑同步等问题,one eventloop,相对容易很多 多线程下要考虑多线程编程可能产生的各种竞争同步问题,协调各个thread里面的eventloop。 多进程下要考虑各个eventloop thread的通信等问题socket的读写 这也是一大难点,尤其是epoll LT和ET方式下的读写,还有怎么优雅地处理各种错误。应用层之外

前面都是基于应用层对于C10K这类问题的解决方案,在更高并发要求的环境下就得在内核态下做手脚了,如零拷贝等技术,直接越过内核协议栈,实现高速数据包的传递。相应的内核模块也早有实现。

相关资源书籍: 《UNIX环境高级编程》 《UNIX网络编程》两卷 《TCP/IP协议》三卷 《Linux内核设计与实现》 《深入理解Linux内核》 《Linux多线程服务端编程》各种开源组件: nginx memcached beanstalkd libevent libev muduo boost.asio ace tornado swoole

人之相识,贵在相知;人之相知,贵在知心。

关于高性能网络编程的一些总结与思考

相关文章:

你感兴趣的文章:

标签云: