首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 訪問 Hadoop HDFS 完整配置與 API 實戰指南

     編輯:Java 相關知識

Java 客戶端操作 HDFS 完全指南:核心配置、API 詳解與避坑實錄

Hadoop 分布式文件系統(HDFS)是大數據生態存儲基石。本文詳細講解 Java API 訪問 HDFS 的核心配置文件解析、完整 CRUD 操作代碼、Kerberos 認證、高可用(HA)配置及生產環境調優參數。

一、核心配置文件深度解析

1. core-site.xml — 文件系統入口



    
    
        hadoop.tmp.dir
        /home/hadoop/hdfs/tmp
    
    
    
    
        fs.defaultFS  
        hdfs://namenode-host:9000
    
    
    
    
        io.file.buffer.size
        131072  
    

關鍵點:fs.defaultFS 必須指向 NameNode RPC 地址(端口 8020/9000),而非 HTTP WebUI 端口(50070/9870)。

2. hdfs-site.xml — HDFS 專項配置



    
    
        dfs.namenode.name.dir
        file:///mnt/disk1/dfs/nn,file:///mnt/disk2/dfs/nn
    
    
    
    
        dfs.datanode.data.dir
        file:///mnt/disk1/dfs/dn,file:///mnt/disk2/dfs/dn
    
    
    
    
        dfs.replication
        3
    
    
    
    
        dfs.blocksize
        134217728
    
    
    
    
        dfs.client.read.shortcircuit
        true
    
    
        dfs.domain.socket.path
        /var/run/hdfs-sockets/dn
    
    
    
    
        dfs.nameservices
        mycluster
    
    
        dfs.ha.namenodes.mycluster
        nn1,nn2
    
    
        dfs.namenode.rpc-address.mycluster.nn1
        nn1-host:8020
    
    
        dfs.namenode.rpc-address.mycluster.nn2
        nn2-host:8020
    
    
        dfs.client.failover.proxy.provider.mycluster
        org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider
    

3. mapred-site.xml / yarn-site.xml — 計算引擎配置(客戶端通常無需)

純 HDFS 客戶端操作不需要這兩個文件。僅提交 MapReduce/YARN 作業時需配置。

二、Java API 完整操作代碼

Maven 依賴(Hadoop 3.x 為例)



    org.apache.hadoop
    hadoop-client
    3.3.4


    org.apache.hadoop
    hadoop-hdfs
    3.3.4



    org.apache.hadoop
    hadoop-common
    3.3.4

HDFS 操作工具類


package com.demo.hdfs;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.*;
import org.apache.hadoop.io.IOUtils;
import org.apache.hadoop.util.Progressable;

import java.io.*;
import java.net.URI;

public class HdfsClient {
    private FileSystem fs;
    private Configuration conf;

    public HdfsClient(String namenodeUri, String user) throws IOException {
        conf = new Configuration();
        // 加載 classpath 下的 core-site.xml, hdfs-site.xml
        // conf.addResource("core-site.xml"); // 可選,默認自動加載
        fs = FileSystem.get(URI.create(namenodeUri), conf, user);
    }

    // 簡單構造:使用默認配置與當前用戶
    public HdfsClient() throws IOException {
        this("hdfs://namenode-host:9000", System.getProperty("user.name"));
    }

    /** 上傳文件 */
    public void upload(String localPath, String hdfsPath, boolean overwrite) throws IOException {
        Path src = new Path(localPath);
        Path dst = new Path(hdfsPath);
        fs.copyFromLocalFile(overwrite, src, dst);
        // 或手動流式上傳(大文件、進度監聽)
        // try (InputStream in = new BufferedInputStream(new FileInputStream(localPath));
        //      OutputStream out = fs.create(dst, new Progressable() {
        //          public void progress() { System.out.print("."); }
        //      })) {
        //     IOUtils.copyBytes(in, out, 4096, true);
        // }
    }

    /** 下載文件 */
    public void download(String hdfsPath, String localPath) throws IOException {
        Path src = new Path(hdfsPath);
        Path dst = new Path(localPath);
        fs.copyToLocalFile(src, dst);
    }

    /** 追加寫入(需 HDFS 支援且配置 dfs.append.support=true) */
    public void append(String hdfsPath, String content) throws IOException {
        Path path = new Path(hdfsPath);
        try (FSDataOutputStream out = fs.append(path)) {
            out.write(content.getBytes("UTF-8"));
        }
    }

    /** 讀取文件內容 */
    public String readAsString(String hdfsPath) throws IOException {
        Path path = new Path(hdfsPath);
        try (FSDataInputStream in = fs.open(path);
             ByteArrayOutputStream out = new ByteArrayOutputStream()) {
            IOUtils.copyBytes(in, out, 4096, false);
            return out.toString("UTF-8");
        }
    }

    /** 刪除文件/目錄 */
    public boolean delete(String hdfsPath, boolean recursive) throws IOException {
        return fs.delete(new Path(hdfsPath), recursive);
    }

    /** 列出目錄 */
    public FileStatus[] list(String hdfsPath) throws IOException {
        return fs.listStatus(new Path(hdfsPath));
    }

    /** 創建目錄 */
    public boolean mkdirs(String hdfsPath) throws IOException {
        return fs.mkdirs(new Path(hdfsPath));
    }

    /** 文件/目錄是否存在 */
    public boolean exists(String hdfsPath) throws IOException {
        return fs.exists(new Path(hdfsPath));
    }

    /** 獲取文件元信息 */
    public FileStatus getFileStatus(String hdfsPath) throws IOException {
        return fs.getFileStatus(new Path(hdfsPath));
    }

    /** 關閉連接 */
    public void close() throws IOException {
        if (fs != null) fs.close();
    }

    // 使用示例
    public static void main(String[] args) throws Exception {
        try (HdfsClient client = new HdfsClient()) {
            client.mkdirs("/user/test");
            client.upload("local.txt", "/user/test/remote.txt", true);
            System.out.println("文件內容: " + client.readAsString("/user/test/remote.txt"));
            client.append("/user/test/remote.txt", "\n追加行");
            for (FileStatus status : client.list("/user/test")) {
                System.out.printf("名稱: %s, 大小: %d, 類型: %s%n", 
                    status.getPath().getName(), status.getLen(), 
                    status.isDirectory() ? "目錄" : "文件");
            }
        }
    }
}

三、Kerberos 安全認證配置

1. 核心站點配置




    hadoop.security.authentication
    kerberos


    hadoop.security.authorization
    true

2. Java 代碼認證


import org.apache.hadoop.security.UserGroupInformation;
import javax.security.auth.login.LoginContext;

// 方式一:Keytab 免密登錄(推薦生產)
UserGroupInformation.setConfiguration(conf);
UserGroupInformation.loginUserFromKeytab("hdfs/host@REALM", "/path/to/hdfs.keytab");
FileSystem fs = FileSystem.get(conf);

// 方式二:票據緩存(開發測試)
// kinit hdfs@REALM 後
UserGroupInformation.setConfiguration(conf);
UserGroupInformation.loginUserFromSubject(null); // 使用默認 Subject

四、高可用(HA)客戶端配置

核心在於 fs.defaultFS 使用邏輯 nameservice:


Configuration conf = new Configuration();
conf.set("fs.defaultFS", "hdfs://mycluster");  // 對應 dfs.nameservices
conf.set("dfs.nameservices", "mycluster");
conf.set("dfs.ha.namenodes.mycluster", "nn1,nn2");
conf.set("dfs.namenode.rpc-address.mycluster.nn1", "nn1-host:8020");
conf.set("dfs.namenode.rpc-address.mycluster.nn2", "nn2-host:8020");
conf.set("dfs.client.failover.proxy.provider.mycluster", 
         "org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider");

FileSystem fs = FileSystem.get(conf);
// 自動故障轉移,無感知切換

五、生產環境調優參數

參數建議值說明
dfs.client.buffer.size131072 (128KB)讀寫緩衝區,大文件可調大
dfs.client.read.shortcircuittrue同機短路讀,繞過 DataNode 進程
dfs.client.read.shortcircuit.skip.checksumfalse生產保持校驗,測試可關閉提速
dfs.datanode.socket.write.timeout0 (無限)寫超時,防網絡抖動斷連
ipc.client.connect.max.retries10RPC 重試次數
ipc.client.connect.retry.interval3000重試間隔 ms
hadoop.rpc.timeout60000RPC 超時 ms

六、常見坑點與解決

現象原因解決
連接超時 / Connection refusedfs.defaultFS 錯誤、防火牆、NameNode 未啟動檢查端口 8020/9000、core-site.xml、telnet 測試
No FileSystem for scheme: hdfs缺少 hadoop-hdfs 依賴、類加載衝突引入 hadoop-hdfs、排除傳遞依賴衝突
Permission denied用戶無權限、Kerberos 未認證、ACL 限制檢查用戶組、kinit/keytab、HDFS 權限命令
File could only be replicated to 0 nodesDataNode 未啟動、磁盤滿、網絡不通檢查 DataNode 日誌、磁盤空間、網絡連通性
Lease recovery 卡住客戶端異常退出未關閉流、NameNode 切換try-with-resources 確保關閉、配置租約恢復參數
短路讀不生效libhadoop.so 缺失、socket 路徑錯誤、用戶不一致安裝 native lib、檢查 dfs.domain.socket.path、同用戶運行

七、進階主題

  1. Erasure Coding (EC):Hadoop 3.x 替代副本的節省空間編碼,冷數據適用
  2. Storage Types / Policies:SSD/HDD/ARCHIVE/MEMORY 分層存儲策略
  3. Snapshot:目錄級快照,備份/防誤刪
  4. DistCp:集群間/集群內大規模數據複製工具(MapReduce 基礎)
  5. HttpFS / WebHDFS:REST API 訪問 HDFS,跨語言、穿透防火牆

掌握 HDFS Java API 的核心配置、流式操作模式、安全認證與 HA 故障轉移,是大數據開發者的必備技能。建議在測試環境完整跑通上傳、下載、追加、列表、刪除、權限、Kerberos、HA 切換全鏈路,再投入生產使用。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved