首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >监控服务器线程性能

监控服务器线程性能
EN

Stack Overflow用户
提问于 2018-03-30 00:22:35
回答 1查看 33关注 0票数 1

我已经使用gcc和pthread开发了一个C服务器,它接收UDP数据包,并根据配置将它们丢弃或转发到特定的目标。在某些情况下,这些分组是原封不动的并且只是重定向,在某些情况下,分组中的报头被修改,在其他情况下,存在修改分组的每个字节的服务器的另一个模块。

为了配置这个服务器,有一个用Java编写的GUI,它使用TCP连接到C server (以交换配置命令)。可以同时有多个连接的GUI。

为了测量服务器的利用率,我编写了一个模块来启动两个独立的线程(#2和#3)。完成整个转发工作的主线程(#1)基本上是这样工作的:

代码语言:javascript
复制
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函数:

代码语言:javascript
复制
 //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。

提前感谢您的任何意见。

EN

回答 1

Stack Overflow用户

发布于 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万个分组。

当然,您可能没有那么强大的处理器和网卡,但是使用正确的技术可以很容易地达到每秒几百万个数据包。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/49560854

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档