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

WebHdfs API创建文件成功但Append操作致Parquet文件损坏

问题描述

使用WebHDFS API可成功创建Parquet文件,但追加字节数组数据后出现异常:

  • 发送POST请求获取307重定向响应,携带数据向Location地址发起第二次POST请求返回200,文件大小增加
  • 打开Parquet文件时,阅读器显示行数与追加行数匹配,但无法查看数据,文件疑似损坏
  • 本地文件系统的追加操作正常,用待追加数据创建新Parquet文件也可正常读取,确认数据本身有效
  • 已确认请求URI包含&datanode=true参数

附相关C#代码:

uri = _strURI + (strFullFileName + "?op=APPEND&user.name=" + _webHdfsUserName);
method = "POST";

private async Task<bool> RunPutBinaryFileRequest(string strURI, string strMethod, byte[] data)
{
    bool blnResult = false;

    try
    {
        var handler = new HttpClientHandler
        {
            AllowAutoRedirect = false,
            PreAuthenticate = true,
        };
        var hClient = new HttpClient(handler);
        var request = new HttpRequestMessage
        {
            Method = new HttpMethod(strMethod), //PUT or POST: PUT = CREATE , POST REQUIRED FOR APPEND, determined by calling function.
            RequestUri = new Uri(strURI),
        };
        hClient.DefaultRequestHeaders.Referrer = new Uri(strURI);
        hClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(Encoding.ASCII.GetBytes(_webHdfsUserName + ":" + _webHdfsPassword)));

        var response = await hClient.SendAsync(request);
        //response.EnsureSuccessStatusCode();
        blnResult = await UseBinaryHTTP(data, response.Headers.Location, strMethod);
        hClient.Dispose();
    }
    catch (HttpRequestException ex)
    {
        _logger.LogError("[RunBinaryPutFileRequest]request}::WebException{ex}", ex.Message);
    }
    return blnResult;
}

private async Task<bool> UseBinaryHTTP(byte[] data, Uri url, string strMethod)
{
    var success = false;
    try
    {
        var hClient = new HttpClient();
        var sContent = new ByteArrayContent(data);
        var aValue = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(Encoding.ASCII.GetBytes(_webHdfsUserName + ":" + _webHdfsPassword)));
        hClient.DefaultRequestHeaders.Authorization = aValue;
        var request = new HttpRequestMessage
        {
            Method = new HttpMethod(strMethod),
            RequestUri = url,
            Content = sContent
        };
        request.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
        var response = await hClient.SendAsync(request);

        response.EnsureSuccessStatusCode();
        hClient.Dispose();
        success = true;
    }
    catch (HttpRequestException ex)
    {
        _logger.LogError("[UseBinaryHTTP]request}::WebException{ex}", ex.Message);
    }
    return success; 
}
排查思路与解决方案

核心原因分析

WebHDFS的APPEND接口是字节流级别的直接追加,而Parquet是具有严格格式规范的列式存储文件,包含文件头、元数据块、数据块、文件尾(Footer)等结构。直接将另一块Parquet的二进制数据追加到现有文件末尾,相当于把两个独立的Parquet文件拼接在一起,这不符合Parquet的格式要求——阅读器能识别总条数,但无法解析混乱的结构,导致无法查看数据。

而本地追加操作正常,是因为本地使用的Parquet库(如Parquet.Net)是记录级别的追加:它会读取原文件的元数据,将新数据合并到现有结构中,重新生成完整合法的Parquet文件结构,而非直接拼接二进制。

具体排查与修复步骤

  1. 放弃直接用WebHDFS APPEND接口追加二进制数据
    改用Parquet库的追加能力结合WebHDFS写入:

    • 先通过WebHDFS读取现有Parquet文件的内容
    • 使用Parquet库(如Parquet.Net)以Append模式打开该文件,写入新数据
    • 将生成的完整合法Parquet字节流,通过WebHDFS的CREATE接口覆盖写入原文件(如果HDFS版本支持,也可以先删除原文件再重新创建)
  2. 验证WebHDFS请求的正确性

    • 在RunPutBinaryFileRequest中,先判断第一次请求的响应状态码是否为307(HttpStatusCode.RedirectKeepVerb),只有在重定向时才调用UseBinaryHTTP,避免无效请求:
      if (response.StatusCode == HttpStatusCode.RedirectKeepVerb && response.Headers.Location != null)
      {
          blnResult = await UseBinaryHTTP(data, response.Headers.Location, strMethod);
      }
      else
      {
          _logger.LogError("First request did not return 307 redirect");
          blnResult = false;
      }
      
    • 抓包验证第二次请求的Content-Length是否与数据长度完全一致,确保ByteArrayContent没有截断或多传数据
  3. 检查WebHDFS URI拼接是否正确
    确认_strURI的格式是否符合WebHDFS规范,比如应为http://<host>:<port>/webhdfs/v1,拼接后完整URI类似:

    http://namenode:50070/webhdfs/v1/user/test/file.parquet?op=APPEND&user.name=hadoop&datanode=true
    

    避免因URI拼接错误导致写入位置异常

  4. 验证Parquet数据的完整性
    将待追加的字节流写入本地临时文件,用Parquet阅读器打开确认是否合法,排除数据本身的格式问题(虽然CREATE操作正常,但仍需确认追加的是完整的Parquet记录块,而非部分数据)

内容的提问来源于stack exchange,提问作者user23562292

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 12:33:33