我已经使用gcc和pthread开发了一个C服务器,它接收UDP数据包,并根据配置将它们丢弃或转发到特定的目标。在某些情况下,这些分组是原封不动的并且只是重定向,在某些情况下,分组中的报头被修改,在其他情况下,存在修改分组的每个字节的服务器的另一个模块。
为了配置这个服务器,有一个用Java编写的GUI,它使用TCP连接到C server (以交换配置命令)。可以同时有多个连接的GUI。
为了测量服务器的利用率,我编写了一个模块来启动两个独立的线程(#2和#3)。完成整个转发工作的主线程(#1)基本上是这样工作的:
struct monitoring_struct data; //contains 2 * uint64_t for start and end time among other fields
for(;;){
recvfrom();
data.start = current_time();
modifyPacket();
sendPacket(); //sometimes to multiple destinations
data.end = current_time();
writeDataToPipe();
}current_time函数:
//give a timestamp in microsecond precision
uint64_t current_time(void){
struct timespec spec;
clock_gettime(CLOCK_REALTIME, &spec);
uint64_t ts = (uint64_t) ((((double) spec.tv_sec) * 1.0e6) +
(((double) spec.tv_nsec) / 1.0e3));
return ts;
}如主线程中所示,数据结构被写入管道中,线程#2等待从中读取。每次从管道中读取数据时,线程#2都会使用一个给定的聚合函数,该函数将数据存储在内存中的另一个位置。线程#3是一个循环,它总是休眠大约1秒,然后发出聚合值(中位数、平均值、最小值、最大值、下四分位数、上四分位数...)然后重置聚集的数据。线程#2和#3由互斥锁同步。
GUI监听这些数据(如果监控窗口打开),这些数据通过UDP发送给监听器(可能还有更多),然后GUI将这些数字转换为图表、图形和“压力”指示器。
我想出了这个解决方案,因为在我看来,这是对线程#1干扰最小的解决方案(假设它运行在一个多核系统上,它总是运行在一个多核系统上,并且只在OS和SSH之外运行)。
由于性能对我的服务器至关重要(配置更简单的"1.0“版本能够管理使用千兆以太网可能的最大数量的流),我想问一下,如果我的解决方案可能没有我认为的那么好,以确保线程#1的性能影响最小,如果你认为有更好的设计?至少我想不出另一种解决方案,不使用数据本身的锁(避免管道,但有可能锁定线程#1)或使用rwlock的共享列表实现,可能会导致读取器匮乏。
存在数据包更大的情况,但我们目前使用1 Streams每秒恰好发送1000个数据包的模式进行性能测量。我们目前希望确保版本2.0至少可以处理12个流(即每秒12000个数据包),而之前服务器只能管理84个流。
在未来,我想在线程#1中添加其他里程碑时间戳,例如在modifyPacket()内部(有多个步骤)和sendPacket()之前。
我尝试过修改current_time()函数,主要是通过存储clock_gettime()的值来删除它以节省时间,但在我的简单测试程序中,current_time()函数总是胜过clock_gettime。
提前感谢您的任何意见。
发布于 2018-03-31 05:08:22
如果你认为有更好的设计呢?
简短的答案是将Data Plane Development Kit (DPDK)与其设计模式和库一起使用。这可能是一个相当长的学习曲线,但就性能而言,它是目前最好的解决方案。它是免费和开源的(BSD许可证)。
更详细的回答:
将数据结构写入管道
因为线程#1和#2是同一进程的线程,所以使用共享内存而不是管道来传递数据会快得多。就像你在线程#2和#3之间使用的一样。
线程#2使用一个给定的聚合函数将数据存储在内存中的另一个位置
这两个线程似乎是不必要的。线程#2可以读取线程#1传递的数据,聚合并发送吗?
我想不出另一个不对数据本身使用锁的解决方案
让我们看一下称为"rings" in DPDK的无锁队列。这个想法是在线程之间有一个公共的circular buffer,并使用无锁算法将缓冲区入队/出队。
我们目前希望确保版本2.0至少可以处理12个流(即每秒12000个数据包),而之前服务器只能管理84个流。
测量性能并找到瓶颈(似乎您仍然不能100%确定代码中的瓶颈是什么)。
仅供参考,英特尔发布了performance reports for DPDK。这些用于L3转发(即路由)的参考数字高达每秒3000万个分组。
当然,您可能没有那么强大的处理器和网卡,但是使用正确的技术可以很容易地达到每秒几百万个数据包。
https://stackoverflow.com/questions/49560854
复制相似问题