From 590265b437002ae360b11eb89b08af72530a8557 Mon Sep 17 00:00:00 2001 From: Mike Lee Date: Tue, 21 Jul 2026 20:11:55 +0800 Subject: [PATCH 1/3] Update netutils and network modules for improved performance and stability - Bump server version from 2.2 to 2.3 in netutils.ecs. - Introduce new polling sleep durations for worker fibers to manage backpressure. - Replace bare fiber.yield() calls with fiber.sleep_for() for better control over idle states. - Enhance logging for slave worker availability and connection issues. - Implement graduated wait strategy in network.cpp to reduce busy-waiting and improve responsiveness. - Ensure compatibility with CovScript SDK version 260701 or higher. - Add functions for optimal scheduling and resource management in http_server class. - Refactor shutdown procedures to ensure graceful termination of async jobs. --- CMakeLists.txt | 6 ++ CNI_API.md | 4 +- NETUTILS.md | 22 ++--- README.md | 6 +- csbuild/netutils.json | 2 +- csbuild/network.json | 2 +- docs/async-architecture.md | 20 ++-- netutils.csp | 131 ++++++++++++++++++------- netutils.csym | 193 +++++++++++++++++++++++++++---------- netutils.ecs | 191 +++++++++++++++++++++++++++--------- network.cpp | 57 ++++++++--- 11 files changed, 467 insertions(+), 167 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 56f09c7..c5911f1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -28,6 +28,10 @@ set(NETWORK_TLS_SHUTDOWN_TIMEOUT_MS 5000 CACHE STRING "TCP safe_shutdown TLS close-notify timeout in milliseconds") set(NETWORK_THREAD_WORKER_POLL_MS 1 CACHE STRING "thread_executor run_one_for polling interval in milliseconds") +set(NETWORK_WAIT_SLEEP_MS 1 CACHE STRING + "Sleep duration in milliseconds for wait_impl / drain loops to avoid busy-waiting") +set(NETWORK_FAST_SPIN_COUNT 10 CACHE STRING + "Number of fast-spin (yield without sleep) iterations in wait_impl before escalating to sleep") find_package(OpenSSL REQUIRED) @@ -40,6 +44,8 @@ target_compile_definitions(network PRIVATE NETWORK_SAFE_SHUTDOWN_TIMEOUT_MS=${NETWORK_SAFE_SHUTDOWN_TIMEOUT_MS} NETWORK_TLS_SHUTDOWN_TIMEOUT_MS=${NETWORK_TLS_SHUTDOWN_TIMEOUT_MS} NETWORK_THREAD_WORKER_POLL_MS=${NETWORK_THREAD_WORKER_POLL_MS} + NETWORK_WAIT_SLEEP_MS=${NETWORK_WAIT_SLEEP_MS} + NETWORK_FAST_SPIN_COUNT=${NETWORK_FAST_SPIN_COUNT} ) target_link_libraries(network covscript OpenSSL::SSL OpenSSL::Crypto) diff --git a/CNI_API.md b/CNI_API.md index 315e634..809f3a9 100644 --- a/CNI_API.md +++ b/CNI_API.md @@ -111,7 +111,7 @@ sock.connect_ssl("localhost", {"trust_mode": "insecure"}.to_hash_map()) | `send` | `(data: string) → int` | 发送数据(单次部分写入,返回实际写入字节数)。需完整发送时使用 `write` | | `write` | `(data: string)` | 发送数据(保证全部写入,阻塞直到完成) | | `shutdown` | `()` | 关闭套接字通信通道。与 `close()` 的区别:`shutdown()` 仅关闭通信,socket 保持打开且资源不释放;`close()` 释放所有资源 | -| `safe_shutdown` | `() → boolean` | 安全关闭:协作式等待异步操作全部完成后关闭 TLS 和 TCP。成功返回 `true`;关闭过程中发生错误返回 `false`。在 fiber 环境中通过 `poll` + `yield` 协作等待,不阻塞 OS 线程 | +| `safe_shutdown` | `() → boolean` | 安全关闭:协作式等待异步操作全部完成后关闭 TLS 和 TCP。成功返回 `true`;关闭过程中发生错误返回 `false`。在 fiber 环境中通过 `poll` + 分级等待(`yield` × N,然后 `sleep_for`)协作等待,不阻塞 OS 线程 | | `local_endpoint` | `() → endpoint` | 获取本地端点地址 | | `remote_endpoint` | `() → endpoint` | 获取远程端点地址 | @@ -341,7 +341,7 @@ end 1. **异步操作生命周期**:异步操作期间 socket 必须保持存活。创建 `work_guard` 可防止事件循环在所有异步操作完成前停止。 2. **TLS 连接**:同步 `connect_ssl` 方法先建立 TCP 连接再执行 TLS 握手;异步 `async.connect_ssl` 仅执行 TLS 握手(socket 必须先建立 TCP 连接)。握手失败时 SSL 上下文会被自动清理。 3. **`send` vs `write`**:`send` 执行单次写入并返回实际写入字节数,类似 BSD `send()`;`write` 保证全部写入,类似 POSIX `write()`。需要可靠传输时使用 `write`。 -4. **`shutdown` vs `close` vs `safe_shutdown`**:`shutdown` 关闭通信通道但不释放资源(socket 保持 `is_open()` 为 true);`close` 立即关闭并释放 TLS 上下文(如有进行中的异步操作会抛出异常);`safe_shutdown` 协作式等待所有异步操作完成后关闭 TLS 和 TCP。异步任务等待无超时;TLS close-notify 超时默认 5000ms(`NETWORK_TLS_SHUTDOWN_TIMEOUT_MS`)。在 fiber 环境中通过 `poll` + `yield` 协作等待,不阻塞 OS 线程;非 fiber 环境调用线程一直阻塞到关闭完成。推荐在异步场景中使用 `safe_shutdown`。 +4. **`shutdown` vs `close` vs `safe_shutdown`**:`shutdown` 关闭通信通道但不释放资源(socket 保持 `is_open()` 为 true);`close` 立即关闭并释放 TLS 上下文(如有进行中的异步操作会抛出异常);`safe_shutdown` 协作式等待所有异步操作完成后关闭 TLS 和 TCP。异步任务等待无超时;TLS close-notify 超时默认 5000ms(`NETWORK_TLS_SHUTDOWN_TIMEOUT_MS`)。在 fiber 环境中通过 `poll` + 分级等待(`yield` × N,然后 `sleep_for`)协作等待,不阻塞 OS 线程;非 fiber 环境调用线程一直阻塞到关闭完成。推荐在异步场景中使用 `safe_shutdown`。 5. **信任报告**:建议使用 `sock.get_ssl_trust_report()`(每个 socket 独立),而非全局的 `get_last_global_ssl_trust_report()`(线程级别,可能被覆盖)。 6. **线程安全**:同一 socket 不应并发混合同步和异步操作。异步 API 最多允许一个 pending read/receive 和一个 pending write/send;同方向重叠操作会被拒绝,读写可全双工并行。TLS 异步 handler 绑定到每个 socket 的 strand,可由多个 `async.thread_worker` 安全驱动。 7. **netutils HTTP 客户端**:`netutils` 提供 `http_client` 类(`http_request` / `post` 方法)和 `openai_client` 子类。TLS 验证通过客户端实例的 `set_tls_options({"trust_mode": "auto"}.to_hash_map())` 控制,不再使用全局 `ssl_verify` 标志。详见 [NETUTILS.md](NETUTILS.md)。 diff --git a/NETUTILS.md b/NETUTILS.md index aab9c8c..5612f7e 100644 --- a/NETUTILS.md +++ b/NETUTILS.md @@ -1,6 +1,6 @@ # CovScript NetUtils 协议文档 -版本:2.2 +版本:2.3 作者:Covariant Script OSC @@ -27,7 +27,7 @@ ## 2. 基本常量与工具函数 * `server_name = "CovScript-NetUtils"` -* `server_version = "2.2"` +* `server_version = "2.3"` 与协议/实现相关的重要工具函数: @@ -168,7 +168,7 @@ Master 分配 `rank`:先尝试使用 `deprecated_rank`(回收的编号), | 配置项 | 含义 | 默认值 | | -------------------------- | -----------------------------------: | :----: | | `thread_count` | 底层 Asio I/O 线程数(不等于 handler 并发数) | `4` | -| `worker_count` | 单进程 HTTP 连接处理 fiber 数(控制可同时服务的活动/keep-alive 连接数) | `64` | +| `worker_count` | 单进程 HTTP 连接处理 fiber 数(控制可同时服务的活动/keep-alive 连接数) | `32` | | `max_keep_alive` | 每连接允许的最大请求数 | `100` | | `keep_alive_timeout` | 保持连接的最大空闲时间(ms) | `5000` | | `max_body_size` | 单个请求体的最大字节数 | `67108864` (64 MiB) | @@ -240,17 +240,17 @@ Master 分配 `rank`:先尝试使用 `deprecated_rank`(回收的编号), 转发时保留原始请求头,但会过滤 hop-by-hop 头(`Host`、`Connection`、`Content-Length`、`Transfer-Encoding`、`Keep-Alive`、`Proxy-*`、`TE`、`Trailer`、`Upgrade` 等由 `http_request` 内部管理,不透传);同时**注入 `X-Forwarded-For: <客户端真实 IP>`**(客户端伪造的同名头会被丢弃后重写),后端据此可获得真实来源地址而非代理自身 IP。 * `stop()` - 优雅关闭服务器:停止所有 worker、释放 async_guard、关闭 acceptor。 + 优雅关闭服务器:标记所有 worker 退出、关闭 acceptor 和 Socket,通知所有纤程检查退出标志。资源释放(thread_pool、async_guard)在 `run()` 的事件循环退出后统一执行,避免从 handler 内调用 `stop()` 时纤程在 foreach 迭代中访问已释放的 `worker_list` 导致崩溃。可重复调用(重入安全)。 -* `run()` - 启动事件循环(`listen` 或 `set_master` 后调用)。 + +* `set_optimal_scheduling(policy : string)` + 设置纤程调度策略,影响事件循环在恢复休眠 Worker 纤程时的反压行为。推荐在 `run()`/`poll()` 前调用,可选值:`"responsive"`(低延迟,适合轮询模式)、`"balanced"`(默认)、`"throughput"`、`"efficient"`。 * `poll()` - 启动服务(非阻塞),仅轮询一次。需循环调用才能使服务正常运行。 + 启动服务(非阻塞),仅轮询一次。需循环调用才能使服务正常运行。当所有 Worker 意外终止时会自动标记 `stopped` 并释放资源。 * `run()` - 启动服务(阻塞),适合守护进程模式。 - + 启动服务(阻塞),适合守护进程模式。事件循环退出后自动释放 thread_pool、async_guard、worker_list。当所有 Worker 意外终止时会记录日志并退出。 --- ## 9. 单进程(simple_worker)与多进程(master/slave)Worker 行为 @@ -263,7 +263,7 @@ Master 分配 `rank`:先尝试使用 `deprecated_rank`(回收的编号), * Accept Worker:接收新的客户端连接并把 `http_conn` 放入 `conn_list`。 * Request Worker:从 `conn_list` 中挑选一个处于 `state == 0` 的 `http_conn`,读取 header 并把 `session` push 到 `request_queue`。 - * Dispatch Worker:为空闲 Slave 分配 `conn->request_queue[conn->request_idx]` 并发送。 + * Dispatch Worker:为空闲 Slave 分配 `conn->request_queue[conn->request_idx]` 并发送。当无可用 Slave 时,以 10 ms 间隔轮询并每秒记录一次日志。有待处理工作时使用 `fiber.yield()` 快速重新调度,否则使用 `fiber.sleep_for(FAST_POLL_MS)`。 * Response Worker:负责把 Slave 返回的响应写回客户端 socket,并在必要时关闭连接与清理。 * **slave_worker**(Slave) @@ -375,7 +375,7 @@ slave.set_slave("127.0.0.1", 9000) * **POST Body 处理**:Master/Slave 之间传输 POST Body 时依赖 `content_length`,若客户端或中间链路错误导致长度不匹配,会引发阻塞或提前 EOF,要在应用层做好验证(如 Content-Length 校验)。 * **版本兼容**:Master 与 Slave 的 `server_version` 必须一致,握手会校验版本号;当升级版本时请同时升级 Master/Slave。 * **资源限制**:`max_connections` / `worker_count` / `master_worker_count` 应根据机器资源和负载曲线调整,避免出现大量 socket backlog 或内存耗尽。 -* **异常恢复**:Master 会在 Slave 出现错误或心跳失败时把该 Slave 标记为 `-1` 并尝试回收其 rank,以便后续新 Slave 使用;Slave 端在崩溃后会循环重连 Master(`slave_worker` 有短时 delay 重试)。 +* **异常恢复**:Master 会在 Slave 出现错误或心跳失败时把该 Slave 标记为 `-1` 并尝试回收其 rank,以便后续新 Slave 使用;Slave 端在崩溃后会循环重连 Master(`slave_worker` 使用 `fiber.sleep_for(ERROR_RECOVERY_MS)`(100 ms)重试)。 ## 14. 常见问题与调优建议 diff --git a/README.md b/README.md index 05e3592..93d227e 100644 --- a/README.md +++ b/README.md @@ -8,8 +8,8 @@ A high-performance network extension for the [Covariant Script](http://covscript | Package | Type | Version | Description | |---|---|---|---| -| `network` | C++ Extension | `1.38.0_v6.5` | TCP/UDP sockets, TLS/SSL, async I/O, event loop | -| `netutils` | CovScript | `2.2` | HTTP server/client framework with single-process, distributed master/slave, and OpenAI API modes | +| `network` | C++ Extension | `1.38.0_v6.6` | TCP/UDP sockets, TLS/SSL, async I/O, event loop | +| `netutils` | CovScript | `2.3` | HTTP server/client framework with single-process, distributed master/slave, and OpenAI API modes | | `argparse` | CovScript | `1.1` | Lightweight command-line argument parser | > **Note:** `netutils` and `argparse` are provided as both source (`.ecs`), compiled package (`.csp`), and bytecode module (`.csym`) — place them in your project's `imports/` directory. @@ -85,6 +85,8 @@ All options can be overridden with `-D