You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

CentOS6.9下C++ epoll服务器SSL_accept/SSL_do_handshake性能缓慢求助

针对高并发SSL握手场景的性能优化方案

我之前在CentOS 6.9 + OpenSSL 1.0.2的环境下做过高并发SSL服务器的优化,碰到过几乎一模一样的50k连接场景下的握手性能瓶颈,给你整理几个实际落地有效的优化方向:

1. 优化OpenSSL会话缓存与复用策略

SSL握手的最大开销之一就是会话密钥协商,复用已有的会话能直接跳过大部分握手步骤:

  • 启用会话复用:在初始化SSL_CTX时设置缓存模式,避免自动清理会话:
    SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_SERVER | SSL_SESS_CACHE_NO_AUTO_CLEAR);
    
  • 调整缓存容量:根据你的50k连接规模,把缓存调大到足够容纳活跃会话:
    SSL_CTX_sess_set_cache_size(ctx, 100000); // 可以根据实际连接数调整
    
  • 若内存紧张,可尝试自定义会话缓存回调(SSL_CTX_sess_set_get_cb/SSL_CTX_sess_set_new_cb),把会话存到共享内存里,不过优先先试内置缓存优化,成本更低。

2. 改用非阻塞式SSL握手流程

你现在可能是在EPOLL_CTL_ADD后直接阻塞调用SSL_accept/SSL_do_handshake,这会导致事件循环被卡住,无法同时处理其他连接。改成非阻塞模式:

  • 先将socket设置为非阻塞:
    int flags = fcntl(sockfd, F_GETFL, 0);
    fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);
    
  • 调用SSL_accept时,若返回SSL_ERROR_WANT_READSSL_ERROR_WANT_WRITE,就把对应的读写事件注册到epoll,等事件触发后再继续握手。这样整个事件循环不会被单个握手操作阻塞,能同时处理大量连接。
  • 可以给新连接的epoll事件加上EPOLLONESHOT,避免重复触发事件,减少不必要的上下文切换。

3. 调整系统内核参数,释放并发能力

CentOS 6.9的默认参数不足以支撑50k级别的并发连接,先把系统层面的限制解开:

  • 提升文件描述符限制:
    # 临时生效
    ulimit -n 100000
    # 永久生效,修改/etc/security/limits.conf,添加两行:
    # * soft nofile 100000
    # * hard nofile 100000
    
  • 调整TCP内核参数(修改/etc/sysctl.conf后执行sysctl -p生效):
    net.core.somaxconn = 65535
    net.ipv4.tcp_max_syn_backlog = 65535
    net.ipv4.tcp_syncookies = 1
    net.core.netdev_max_backlog = 65535
    

这些参数能让系统同时处理更多的连接请求,避免因为队列满导致的握手延迟。

4. 启用OpenSSL硬件加速与编译优化

OpenSSL 1.0.2支持CPU的AES-NI指令集,能大幅降低加密解密的CPU开销:

  • 先检查CPU是否支持AES-NI:
    cat /proc/cpuinfo | grep aes
    
    有输出说明支持。
  • 重新编译OpenSSL,启用硬件加速和最高级别编译优化:
    ./config --prefix=/usr/local/openssl enable-ec_nistp_64_gcc_128 enable-aesni enable-asm -O3
    make && make install
    

CentOS 6.9自带的OpenSSL通常没有启用这些优化,自定义编译后握手速度能提升30%-50%。

5. 拆分SSL握手与业务处理的负载

SSL握手是CPU密集型操作,单进程处理50k握手容易把CPU打满:

  • 可以采用主进程+多子进程架构:主进程负责监听并接受连接,把socket传递给子进程处理SSL握手,子进程完成握手后再把连接交给业务线程。这样能把握手负载分散到多个CPU核心上。
  • 进程间传递socket用sendmsg,这是最高效的方式,避免拷贝数据。

6. 选择更高效的SSL协议与加密套件

过时的协议和重加密套件会拖慢握手速度:

  • 只启用TLSv1.2(OpenSSL 1.0.2支持),禁用旧协议:
    SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1);
    
  • 选择轻量级的加密套件,比如ECDHE密钥交换的GCM套件,比传统RSA套件握手快很多:
    SSL_CTX_set_cipher_list(ctx, "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256");
    

最后建议用perf工具分析CPU热点,确认瓶颈是否真的在SSL操作上,比如:

perf top -p <你的服务器进程PID>

如果看到SSL_acceptSSL_do_handshake占比很高,就针对性优化上面的方向;如果是系统调用或epoll本身的问题,再调整事件循环逻辑。

内容的提问来源于stack exchange,提问作者M. Mike

火山引擎 最新活动