当系统调用变为瓶颈

当程序在操作文件,网络传输时,都会发生系统调用

系统调用会让线程切换用户态和内核态,并且当系统调用长时间没返回,会导致线程阻塞,并无法处理其他事情

system call latency

下图是getpid在发生系统调用时和不使用系统调用时的latency对比。

syscall.PNG

可以看到带system call 的 getpid latency是200ns

不带system call 的 getpid latency是8.7ns

相差20倍

write system call latency

通过下面的benchmark数据可以看到

latency在3us左右

writev_t1k reported mean: 6.17776
 500: mean 6.018us median 6us
1000: mean 5.172us median 5us
1500: mean 5.048us median 5us
2000: mean 3.918us median 4us

writev_t1k reported mean: 5.64197
 500: mean 6.254us median 6us
1000: mean 5.038us median 6us
1500: mean 3.526us median 4us
2000: mean 3.608us median 4us

writev_t1k reported mean: 4.33704
 500: mean 3.528us median 3us
1000: mean 3.486us median 3us
1500: mean 3.518us median 3us
2000: mean 3.492us median 3us

换句话说,当程序在调用系统调用write时,程序会停顿3us,并无法处理其实事情

一个可能的解决方案 io_uring?

io_uring是内核5.9以上才会有

一般来说,目前广泛使用的linux版本一般比这低

而且 io_uring在处理stream mode时,性能不如epoll

为了解决这些问题,提出以下解决方案:

  • 编写自定义内核模块

    • 在内核建立epoll对fd的监控

    • 在内核启动线程,做fd polling和polling来自用户态的数据

    • 建立一片共享内存,与用户态公用,并在共享内存上,建立单读单写无锁队列

    • 对fd的读写消息,通过共享内存返回ack给用户态

  • 用户态程序

    • 获取共享内存,并处理共享内存上队列的请求

    • 单线程polling无锁队列,实现与内核线程的交互

    • 获取共享内存中的ack,来做限流操作

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。
禁止转载,如需转载请通过简信或评论联系作者。

推荐阅读更多精彩内容