为什么SSHJ最大写入大小为32KB?如何突破限制并提升SFTP传输效率?
SSHJ SFTP 32KB块大小限制解决与吞吐量优化方案
问题解决方法
1. 修正窗口/数据包参数配置时机
你当前的配置顺序错误,Connection.setWindowSize()、setMaxPacketSize() 必须在 sshClient.connect() 执行前调用,连接建立后再修改参数无法生效,服务端SSH协商阶段拿到的仍是SSHJ默认的32KB窗口阈值,才会触发net.schmizz.sshj.connection.ConnectionException: Timeout when trying to expand the window size报错。
修正后的配置示例:
SSHClient sshClient = new SSHClient(); Connection conn = sshClient.getConnection(); // 连接前配置窗口与单包最大值,无需直接设置为4GB,8~32MB即可满足绝大多数场景 conn.setWindowSize(16 * 1024 * 1024); conn.setMaxPacketSize(1 * 1024 * 1024); sshClient.addHostKeyVerifier(new PromiscuousVerifier()); sshClient.connect(destCredUri[0], Integer.parseInt(destCredUri[1])); Socket socket = sshClient.getSocket(); socket.setKeepAlive(true); // 批量传输场景关闭TcpNoDelay,启用Nagle算法合并小包,可提升吞吐量20%以上 socket.setTcpNoDelay(false); socket.setSendBufferSize(8 * 1024 * 1024); socket.setReceiveBufferSize(8 * 1024 * 1024);
2. 同步调整服务端SSH配置
32KB的默认阈值是绝大多数SSH服务端的内置限制,仅调整客户端参数无法突破,需同步修改服务端配置:
- 若使用OpenSSH服务端,编辑
/etc/ssh/sshd_config新增如下配置:
配置完成后执行TCPRcvBufSize 16777216 TCPSndBufSize 16777216systemctl restart sshd生效即可。
如果服务端SSH版本过旧不支持自定义缓冲区,无法突破32KB单包限制,可以将客户端单块大小控制在32KB以内,通过并发提交多块的方式提升总吞吐量。
吞吐量优化建议
- 窗口大小无需设置为4GB最大值,绝大多数网络设备和服务端不支持超大滑动窗口,设置在8MB~32MB区间即可,再高不会带来明显的性能提升
- 初始化
SFTPClient时,将SFTPEngine的内部缓冲区设置为单块大小的2倍,减少用户态与内核态的切换次数 - Spring Batch写入时采用异步批量提交模式,不要单块同步等待返回,并行提交多个块充分利用带宽
- 大文件传输可先拆分为多个独立分片并行传输,所有分片传输完成后在服务端执行合并操作,相比单流串行传输吞吐量可提升数倍
- 网络条件较差的场景下,可开启SSH的压缩传输选项,降低传输数据体积,进一步提升传输效率
内容的提问来源于stack exchange,提问作者Jacob Goldverg
相关产品推荐
相关产品推荐

