阅读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的时候就从里面取,不用的时候就放回去,而这个不用的时机很重要,也就是管道里的数据全部复制过去之后,这样管道只会在异步等待写出的短时间里被使用,同时的使用量就没有那么大,系统消耗就大大减小。
    以上就是一点点个人心得,希望对底层开发的程序员们有所帮助。

“阅读HAProxy代码学习linux下的splice函数用法” 有4条评论

  1. 我找到了,
    1>.cd src
    2>. grep “splice(” ./*.c

    最近在研究splice,感觉使用splice的人好少,尤其是在服务器上.
    你的这篇文章指给我一条路.谢谢!

  2. 我在用到这个系统调用的时候提示
    SPLICE_F_MOVE 未定义。也就是splice()的最后一个flags标志参数。这是什么情况?
    另外,按照splice()的描述,两个文件描述符之间必须有一个是管道。
    如果我想时间这样一个功能,直接在文件之间进行数据复制,而不经过缓冲区。
    splice可以实现吗?或者有其他相似的系统调用?

    1. 按理说#include <fcntl.h>就可以了,如果还是不行的话可能是linux内核版本太低

发表评论

您的电子邮箱地址不会被公开。

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据