royguo opened a new issue, #3307:
URL: https://github.com/apache/brpc/issues/3307

   ## 问题摘要                                                                      
            
                                                                                
                
   当 brpc 作为 HTTPS client 使用,并且 `connection_type=pooled` 时,在高并发                 
  
   PUT 请求场景下,进程可能在 brpc 内部直接 abort:                                             
                                                                                
                
   ```text                                                                      
                
   controller.cpp:462] Check failed: false error_code is 0                      
                
   ```                                                                          
                
                                                                                
                
   从日志看,问题发生在远端 HTTPS peer 关闭 pooled TLS 连接时。brpc 已经观察到了                
   SSL EOF,但后续 socket failure 路径把错误传播成了 `error_code=0`,也就是                     
   `Success`。随后 `Controller::SetFailed(0)` 触发 brpc 内部硬 CHECK,导致整个进程             
 
   崩溃。
   
   ## 环境信息                                                                      
            
                                                                                
                
   - brpc: 1.16.0                                                               
                
   - OpenSSL: 3.3.1                                                             
                
   - OS: Linux x86_64                                                           
                
   - Compiler: GCC 12                                                           
                
   - 场景:高并发 HTTPS S3-compatible PUT 请求                                          
        
   - brpc channel 配置大致如下:                                                       
         
                                                                                
                
   ```cpp                                                                       
                
   brpc::ChannelOptions options;                                                
                
   options.protocol = "http";                                                   
                
   options.connection_type = "pooled";                                          
                
   options.timeout_ms = 3000;                                                   
                
   options.max_retry = 0;                                                       
                
                                                                                
                
   auto* ssl_options = options.mutable_ssl_options();
   ssl_options->sni_name = "";
   
   channel.Init("https://<bucket>.<endpoint>", "", &options);
   ```
   
   ## 复现方式
   
   我们系统中的复现链路是:
   
   ```text
   test client -> local frontend -> local dataserver -> brpc HTTPS S3 client -> 
OSS/S3 endpoint
   ```
   
   其中 local frontend 和 local dataserver 由进程内 MiniCluster 启动。dataserver
   会把对象 PUT 请求代理到真实 HTTPS S3-compatible endpoint,并使用 brpc
   `connection_type=pooled`。
   
   本次复现参数:
   
   - 128 并发
   - 每个 PUT 对象 128 KiB
   - 真实 HTTPS OSS/S3 endpoint
   - `connection_type=pooled`
   
   最近一次复现中,测试开始约 7 秒后进程 abort。
   
   等价的最小复现形态是:
   
   1. 创建 brpc HTTPS channel,并设置 `connection_type=pooled`。
   2. 向真实 HTTPS 服务端持续发送并发 HTTP PUT 请求。
   3. 当远端关闭某个 pooled TLS 连接,而 brpc 仍尝试从该连接读取时,可能触发该问题。
   
   ## 关键日志
   
   ```text
   W socket.cpp:2169] Fail to read from ssl_fd=646: error:0A000126:SSL 
routines::unexpected eof 
   while reading
   W socket.cpp:2178] Fail to read from ssl_fd=646: Success [0]
   W input_messenger.cpp:406] Fail to read from Socket{id=11824 fd=646 
addr=<remote-ip>:443:3504
   4}: Success [0]
   F controller.cpp:462] Check failed: false error_code is 0
   Aborted (core dumped)
   ```
   
   ## 预期行为                                                                      
            
                                                                                
                
   远端关闭 HTTPS 连接时,请求应该以一个非零的网络错误或 SSL 错误失败,或者 brpc                
   应该关闭这个异常 pooled connection,并让调用方感知为普通请求失败。                           
                                                                                
                
   无论如何,brpc 不应该因为一次远端连接关闭导致整个进程 abort。                                
   
   ## 实际行为
   
   brpc 把 socket failure 继续传播成 `error_code=0`,随后
   `Controller::SetFailed(0)` 触发硬 CHECK:
   
   ```text
   Check failed: false error_code is 0
   ```
   
   最终导致整个进程崩溃。
   
   ## 初步分析
   
   从日志看,错误链路大致如下:
   
   1. SSL read 返回 `unexpected eof while reading`。
   2. 后续错误处理路径将该失败格式化为 `Success [0]`。
   3. `Socket::SetFailed(0, ...)` 继续向上传播 `error_code=0`。
   4. `Controller::HandleSocketFailed(0, ...)` 调用 `Controller::SetFailed(0)`。
   5. `Controller::SetFailed()` 检查到 `error_code == 0`,触发 CHECK 并 abort。
   
   因此,一个普通的远端 TLS 连接关闭,被放大成了进程级 crash。
   
   ## 当前 workaround
   
   我们验证过下面两种方式可以规避该崩溃:
   
   - 使用 HTTP + pooled connection。
   - 使用 HTTPS + short connection。
   
   目前观察到存在风险的组合是:
   
   ```text
   HTTPS + connection_type=pooled + 高并发
   ```
   
   ## 期望修复
   
   希望 brpc 的 HTTPS socket failure 路径不要以 `error_code=0` 调用
   `Controller::SetFailed()`。
   
   当 SSL EOF、远端关闭连接或类似网络错误发生时,brpc 应该映射成一个非零错误码,并作为
   普通请求失败返回给调用方,而不是触发进程 abort。


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to