当系统调用变为瓶颈
2024-05-14 本文已影响0人
谭英智
当程序在操作文件,网络传输时,都会发生系统调用
系统调用会让线程切换用户态和内核态,并且当系统调用长时间没返回,会导致线程阻塞,并无法处理其他事情
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,来做限流操作
-