阅读HAProxy代码学习linux下的splice函数用法
自从linux 2.6.9后linux提供了驱动级的系统函数splice。它的作用是在文件描述符直接转发数据,直接对内核内存块做引用标记而不需要借用用户内存复制数据。这样就大大节省了分配内存,再read和write的性能消耗。
自己用了一下这个函数发现总是返回EINVAL,于是去阅读HAProxy的源代码,总算弄明白了一些使用条件,理解了这个函数的设计思路。
可以说splice本来就是用于select/poll/epoll等异步机制或者跨进程的通信,所以要求输入和输出必须至少有一个描述符是管道。于是我们可以看到以下清晰的流程:有数据读取时将来源fd的数据splice到pipe_in,然后异步请求写事件;写事件到来时从pipe_out再splice到目标fd。
这样的流程处理常见的fd数据复制是够了,但是问题又来了,当处理网络socket描述符的时候,如果并发量很大,难道我们要为每个fd创建一对管道,那对系统是一个巨大的消耗。
让我们看看HAProxy是怎么处理这个问题的:它用了一个pipe池,每当要做splice的时候就从里面取,不用的时候就放回去,而这个不用的时机很重要,也就是管道里的数据全部复制过去之后,这样管道只会在异步等待写出的短时间里被使用,同时的使用量就没有那么大,系统消耗就大大减小。