当时我正在读博客帖子,注意到下面这句话:
然后,他说了一些非常令人惊讶的话:在Seastar HTTP框架中,他们编写了自己的TCP堆栈,这使每件事的速度都快了好几倍。什么?!
出于性能原因,我试图理解为什么内核功能会在用户空间中重新实现。我假设内核中存在的特性正是因为它们执行(许多)特权指令而存在的,因为否则该特性可以简单地作为用户空间程序来实现。因此,如果要在用户空间中重新实现内核特性或功能,比如网络堆栈(例如,gVisor对其网栈所做的),那么您最终会不会不得不在内核中执行许多系统调用,从而造成大量开销?
这样的用户空间重新实现的特性,传统上是内核的一部分,以某种方式可以避免进行许多系统调用?如果是这样的话,这对于例如网络堆栈是如何工作的,因为您可能不得不经常使用send()或recv(),我可以想象。
我理解在用户空间中重新实现特性的两个潜在优势是:
但我更感兴趣的是这个问题的表现方面。
发布于 2020-10-03 22:25:00
其中一些方法是避免跨越系统调用边界的一些旅行。
确实如此,但另一个方面是,Linux系统调用接口同时非常通用(即必须处理许多不同类型的应用程序和系统),而且非常狭窄(系统调用参数只处理当前请求)。内核通常不知道您的代码下一步将做什么。
让我们以find为例。它在系统调用(如getdents和opendir )上花费了大量时间。您可以使用find做很多事情,但是下面是一个典型的命令行:
find . -name 'report_201[89].txt' -print -quitfind程序将打开大量目录并读取大量文件名。它将把这些文件名提供给用户空间函数fnmatch,以确定它们是report_2018.txt还是report_2019.txt。
但是,让我们假设.在一些现代文件系统中。这些目录实际上是B树或哈希表。如果内核知道我们要找的是哪个文件名,我们就可以节省很多处理。
假设我们转而看git status。如果跟踪它的系统调用,它会发出大量的lstat调用。但它真正想弄清楚的是,用户是否改变了文件系统?内核基本上知道答案,但是git无法告诉内核这是它想知道的。因此,它必须检查每件事本身(尽管它以一种相当聪明的方式这样做)。
这里的主题是,如果内核API是特定于应用程序的,那么事情可能会更有效率。但从设计上讲,这太疯狂了,因为有很多不同的应用程序。维护更宽的内核接口可能具有超线性的复杂性。但这就是为什么在用户空间中解决更多的问题(对于某些问题)可以获得更多的效率。
发布于 2020-10-03 21:23:15
简而言之,内核必须处理许多不同的情况/应用程序/硬件。当您知道您的硬件和/或应用程序通信需求时,堆栈的重新实现就会完成。然后你就可以为那个宇宙编码了。
假设您有一个通过UDP定期发送数据的小型感测设备。您可以创建具有大多数固定值的UDP/IP数据包,以便它到达服务器(您知道您的IP、端口、目标端口和地址、消息的长度、标志.你只需要改变读数)。
只为这个目的运行一个完整的IP内核堆栈将是过分的,速度更慢,甚至是不可行的(例如,在赤裸的骨头里奔跑,阿迪诺)。
但更广泛的答案更复杂,所以我建议这篇文章:为什么我们使用Linux内核的内核的堆栈链接在你引用的文章底部。
https://unix.stackexchange.com/questions/612785
复制相似问题