You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Bash网络重定向上传HDFS请求体不完整的原因及解决方法

问题描述

我用Bash网络重定向通过WebHDFS API向HDFS上传文件。当文件内容接近1MB时,不加sleep操作的话,文件内容没法完整上传到HDFS;加120秒sleep后,文件就能完整上传。

代码示例

content_length=$(wc -c $local_dump_file)
content_length=${content_length% *}

exec 3<> $socket_file
content="PUT $path HTTP/1.1\n"
content="${content}Host: $url:$port\nAccept: */*\nContent-Length: $content_length\nContent-Type: application/x-www-form-urlencoded; charset=utf-8\n\n$(cat $local_dump_file)"
echo -e "$content" >&3
sleep 120
exec 3<&-

注:所有变量均正确,小文件(1字节至1000字节)上传无截断问题。不添加sleep时,HDFS上的文件内容每次上传截断长度不同(如500KB、615KB等),仿佛echo -e "$content" >&3命令无提示终止。

疑问

  1. 为何出现此现象?
  2. 如何无需添加任意sleep即可强制发送全部数据?

解答

1. 问题原因分析

这是因为Bash通过重定向向套接字写入数据时,采用异步I/O机制:echo命令只是把数据写入系统的套接字发送缓冲区,缓冲区满了就会返回,但此时数据可能还没完全发送到HDFS服务器。如果紧接着关闭套接字(exec 3<&-),缓冲区中未发送的数据会被直接丢弃,导致文件上传截断。

小文件体积小,能一次性填满缓冲区并快速发送完成,所以不会出现问题;而接近1MB的大文件,缓冲区无法容纳全部数据,echo返回后还有大量数据留在缓冲区等待发送,此时关闭套接字就会丢失剩余数据。添加sleep 120相当于给了系统足够时间把缓冲区数据全部发送到服务器,因此文件能完整上传。

另外,WebHDFS基于HTTP协议,要求客户端发送完请求后等待服务器响应,但你的代码没有读取服务器响应就直接关闭套接字,这会导致服务器可能还没接收完数据就中断连接,进一步加剧截断问题。

2. 无需sleep的解决方案

方案一:读取服务器响应后再关闭套接字

HTTP是请求-响应协议,客户端发送完请求后等待服务器响应的过程,会自动确保所有数据发送完成。修改代码如下:

content_length=$(wc -c "$local_dump_file")
content_length=${content_length% *}

exec 3<> "$socket_file"
# 用printf替代echo,避免不同系统转义字符处理不一致的问题
printf "PUT $path HTTP/1.1\nHost: $url:$port\nAccept: */*\nContent-Length: $content_length\nContent-Type: application/x-www-form-urlencoded; charset=utf-8\n\n" >&3
cat "$local_dump_file" >&3
# 读取服务器响应,确保数据全部发送完成
cat <&3
exec 3<&-

同时分开发送请求头和文件内容,避免把大文件全部加载到内存中(文件更大时会引发问题)。

方案二:用dd强制刷写缓冲区

dd的conv=fsync参数可以强制等待数据完全发送到服务器后再返回:

content_length=$(wc -c "$local_dump_file")
content_length=${content_length% *}

# 构造请求头到临时文件
printf "PUT $path HTTP/1.1\nHost: $url:$port\nAccept: */*\nContent-Length: $content_length\nContent-Type: application/x-www-form-urlencoded; charset=utf-8\n\n" > /tmp/request_header.tmp
# 合并请求头和文件内容,用dd发送并强制刷写
cat /tmp/request_header.tmp "$local_dump_file" | dd of="$socket_file" conv=fsync
rm /tmp/request_header.tmp

方案三:改用curl工具(最推荐)

curl是专门的HTTP客户端,会自动处理HTTP协议的所有细节(数据发送、响应读取、缓冲区管理等),比手动套接字重定向稳定得多:

curl -X PUT -T "$local_dump_file" "http://$url:$port$path" \
  -H "Content-Type: application/x-www-form-urlencoded; charset=utf-8"

内容的提问来源于stack exchange,提问作者Itération 122442

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 19:45:09