12

我正在实现需要维护大量(100K 或更多)长期连接的自定义服务器。服务器只是在套接字之间传递消息,它不做任何严肃的数据处理。消息很小,但其中许多消息每秒都会接收/发送。减少延迟是目标之一。我意识到使用多个内核不会提高性能,因此我决定通过调用run_one或对象poll方法在单个线程中运行服务器io_service。无论如何,多线程服务器将更难实现。

可能的瓶颈是什么?系统调用、带宽、完成队列/事件多路分解?我怀疑调度处理程序可能需要锁定(由 asio 库在内部完成)。是否可以在 boost.asio 中禁用队列锁定(或任何其他锁定)?

编辑:相关问题。多线程时系统调用性能会提高吗?我的感觉是,因为系统调用是由内核原子/同步的,所以添加更多线程不会提高速度。

4

2 回答 2

17

你可能想读几年前的问题,我在为Blue Gene/Q 超级计算机开发系统软件时第一次调查 Boost.Asio 的可扩展性时问过这个问题。

扩展到 100k 或更多连接应该不是问题,但您需要注意明显的资源限制,例如打开文件描述符的最大数量。如果您还没有阅读开创性的C10K 论文,我建议您阅读它。

在使用单线程和单线程实现应用程序后io_service,我建议调查调用线程池io_service::run(),然后才调查将 an 固定io_service到特定线程和/或 cpu。Asio 文档中包含所有这三种设计的多个示例,以及一些关于 SO 的问题以及更多信息。请注意,当您引入多个线程调用io_service::run()时,您可能需要实现strands 以确保处理程序具有对共享数据结构的独占访问权限。

于 2013-02-26T17:52:13.283 回答
10

使用 boost::asio,您可以以大致相同的开发成本编写单线程或多线程服务器。您可以将单线程版本编写为第一个版本,然后在需要时将其转换为多线程。

通常, boost::asio 的唯一瓶颈是epoll/kqueue反应器在互斥体中工作。因此,只有一个线程同时进行 epoll。如果您有多线程服务器,这可能会降低性能,该服务器提供大量非常小的数据包。但是,无论如何,它应该比普通的单线程服务器更快。

现在关于你的任务。如果您只想在连接之间传递消息-我认为它必须是多线程服务器。问题是系统调用(接收/发送等)。一条指令很容易为 CPU 执行,但任何系统调用都不是非常“轻量级”的操作(一切都是相对的,但相对于您任务中的其他工作)。所以,单线程你会得到很大的系统调用开销,这就是我推荐使用多线程方案的原因。

此外,您可以分离io_service并使其作为“每个线程的 io_service”习语工作。我认为这必须提供最佳性能,但它有缺点:如果 io_service 之一将获得太大的队列 - 其他线程将无济于事,因此某些连接可能会变慢。另一方面,使用单个 io_service - 队列溢出会导致较大的锁定开销。你所能做的——做这两种变体并测量带宽/延迟。实现这两种变体应该不会太难。

于 2013-02-26T08:24:01.407 回答