自 sgcWebSockets 2022.9.0 起,Indy 服务器 IOCP IOHandler 已从头重写,性能得到提升。IOCP IOHandler 仅在 sgcWebSockets Enterprise 包中提供。
使用 IOCP 可以避免"每客户端一线程"问题——随着服务器处理的连接数增加,性能会大幅下降。IOCP 使用少量线程处理多个客户端,这些线程在没有内容需要处理时会挂起,不消耗 CPU 周期。
配置
要为 Indy 服务器启用 IOCP,请前往 IOHandlerOptions 属性,将 IOHandler 类型选择为 iohIOCP。
Server.IOHandlerOptions.IOHandlerType := iohIOCP; Server.IOHandlerOptions.IOCP.IOCPThreads := 0; // the number of IOCP threads will be calculated automatically using the number of processors. Server.IOHandlerOptions.IOCP.WorkOpThreads := 0;
1. IOCPThreads:用于 IOCP 异步请求(重叠操作)的线程数,默认值为零,表示线程数量将根据处理器数量自动计算(Delphi 7 和 2007 除外,这两个版本固定为 32 个线程,因为不支持 cpucount 函数)。
2. WorkOpThreads:仅当您希望连接始终在同一线程中处理时才需要启用。使用 IOCP 时,请求由线程池处理,同一连接的每个请求可能由不同线程处理。如果您希望每个连接始终由同一线程处理,请在 WorkOpThreads 中设置用于处理这些请求的线程数量。这会影响服务器性能,仅建议在确实需要此功能时将该值设置为大于零。
当需要处理数千个连接时,建议为 Windows 服务器启用 IOCP;若服务器最多仅处理 100 个并发连接,则可以保持默认的 Indy 线程模型。
性能测试
以下简单测试展示了 Indy 线程模型与 IOCP 之间的差异。测试通过 WebSocket 协议连接到服务器,下表展示了 CPU 使用率和内存消耗情况。CPU 使用率百分比为服务器处于空闲状态时的数据。
| 连接数 | Indy 默认 IOHandler | Indy IOCP IOHandler |
| 100 | 0% (4.1MB) | 0% (3.9MB) |
| 500 | 0% (17.1MB) | 0% (7.7MB) |
| 1000 | 0% (32.2MB) | 0% (12.4MB) |
| 1500 | 7.3% (46.8MB) | 0% (17.1MB) |
| 2000 | 15.4% (61.6MB) | 0% (21.9MB) |
| 2500 | 51.9% (76.5MB) | 0% (26.5MB) |
| 3000 | 68.8% (91.7MB) | 0% (31.2MB) |
| 3500 | 72.3% (106MB) | 0% (35.9MB) |
当并发连接数超过 3000 时,Indy 服务器开始出现速度下降,这很可能是由于线程上下文切换导致的,服务器空闲时 CPU 使用率也非常高。
IOCP 服务器在空闲状态下 CPU 使用率为零,内存消耗也更低。
下一个测试衡量连接 3000 个客户端所需的时间,每个客户端连接服务器后发送一条消息,服务器将该消息回显。
| Indy 默认 IOHandler | Indy IOCP IOHandler | |
| 连接 3000 个客户端并回显消息 | 15.32 seconds | 6.89 seconds |
性能测试在搭载 16 核处理器和 32GB 内存的 Windows Server 2022 上进行。
