Hadoop JAVA API

目录

 引言 

权限管理

shell命令        

hdfs API

线程池管理

文件系统管理

集群管理

 引言 

        目前项目中部分数据接入了Hadoop中的hdfs文件系统。对hdfs提出了以下几个需求,首先用户需要能够正常地访问hdfs文件系统,这便需要对hdfs文件系统中关于用户权限进行处理。其次是由于可能存在并发地提交任务,所以需要在客户端设置一个线程池应对高并发的情况。数据文件提交后,当然需要能够查看文件的结构以及各个节点的状态。

权限管理

        hdfs文件系统采用与linux相似的文件系统权限模型,也就是UGO模型。当接收一个用户时,会通过namenode调用shell命令,查看namenode服务器用户组系统。根据组列表判断该用户所拥有的权限。

        上图中我们新创建一个testLimit目录, 默认情况下,新创建目录会赋权为755,对于新创建的文件则会赋权为644,可以看到该目录的所有者是master用户,并且属于supergroup。

shell命令        

        新创建一个用户dell,尝试对hdfs文件系统进行创建目录操作,可以看到我们被拒绝了,为了解决这个问题,考虑将dell用户加入到supergroup组中。

# 在linux本机创建supergroup用户组,在root用户下执行

usermod -a -G supergroup dell

# 同步本机用户组信息到hdfs

 hdfs dfsadmin -refreshUserToGroupsMappings

# 切换到dell用户

su - dell

# 尝试在hdfs中创建目录
hdfs dfs -mkdir /testLimist2
# 查看hdfs
hdfs dfs -ls /

        上面的操作我们也可以使用java api来实现,使用jSch连接到linux服务器,然后通过channel来执行shell命令。

/*
    连接linux服务器
     */
    public Session getConnect () {
        // 初始化jsch
        JSch jSch = new JSch();
        // 初始化session
        Session session = null;
        try {
            // 建立连接
            session = jSch.getSession("root", "192.168.139.100", 22);
            session.setPassword("123456");
            session.setConfig("StrictHostKeyChecking", "no");
            // 启用连接
            session.connect();
            System.out.println("服务器连接成功");
        } catch (JSchException e) {
            System.out.println("服务器连接失败");
            throw new RuntimeException(e);
        }
        return session;
    }
/*
    关闭连接
     */
    public void closeConnection(Session session) {
        try {
            session.disconnect();
            System.out.println("关闭连接成功");
        }catch (Exception e){
            e.printStackTrace();
            System.out.println("关闭连接失败");
        }
    }
    /*
/*
    使用脚本语言将用户添加到superGroup
     */
    public List<String> setGroup(Session session, List<String > stringList) {
        // 存放命令返回值
        List<String> outputList = new ArrayList<>();
        for (String command: stringList) {
            // 创建通道
            Channel channel = null;
            try {
                // 创建执行通道
                channel = session.openChannel("exec");
                // 设置命令
                ((ChannelExec) channel).setCommand(command);
                // 连接通道
                channel.connect();
                // 获取输出
                InputStream in = channel.getInputStream();
                BufferedReader reader = new BufferedReader(new InputStreamReader(in));
                // 存放命令的结果
                String line;
                // 用lines拼接line结果
                StringBuffer lines = new StringBuffer();
                while((line = reader.readLine()) != null) {
                    line.trim();
                    lines = lines.append(lines);
                }
                // 如果没有返回值,则输出没有返回值
                if (String.valueOf(lines).equals("")){
                    outputList.add("命令["+command+"]执行成功,但没有返回值");
                }else {
                    outputList.add(String.valueOf(lines));
                }
                reader.close();
                channel.disconnect();
            } catch (JSchException e) {
                throw new RuntimeException(e);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
        return outputList;
    }
hdfs API

         使用hadoop java api对待操作目录的权限进行修改,该操作需要在管理员用户情况下才能使用。

/*
    修改目录权限
     */
    public void modifyDir(String aimDir) {

        // 配置类
        Configuration conf = new Configuration();
        // 设master用户的ugi
        conf.set("hadoop.job.ugi", "dell");
        // 设置远程连接的用户
        UserGroupInformation ugi = UserGroupInformation.createRemoteUser("dell");
        try {
            // 使用doAs执行操作
            ugi.doAs((PrivilegedExceptionAction<Void>)() ->{
                // 创建文件对象
                FileSystem fs = FileSystem.get(conf);
                // 对testLimit目录更新权限
                fs.setPermission(new Path(aimDir), new FsPermission(FsAction.ALL, FsAction.ALL, FsAction.ALL));
                System.out.printf("%s 权限修改成功\n", aimDir);
                return null;
            });
        } catch (IOException e) {
            throw new RuntimeException(e);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }

线程池管理

        在实际应用中,常常会存在大量客户端访问服务端的情况,如果每有一个客户端请求就创建一个线程,不仅会造成系统资源的消耗,还极易造成系统的不稳定。而线程池能够重复利用已创建线程,并且在任务达到时不需要等待线程创建便能够执行,因此考虑使用线程池解决多个客户端并发访问Hadoop集群。

public void ThreadPool() {
        // 初始线程池 设置线程数
        ExecutorService executorService = Executors.newFixedThreadPool(20);
        long begin = System.currentTimeMillis();
        // 将线程池中提交100次查看文件的任务
        for (int i = 1; i <= 100; i++) {
            executorService.submit(new Request("/test/input/a.txt"));

        }
        long end = System.currentTimeMillis();
        executorService.shutdown();
        System.out.printf("花费时间为 %d", end - begin);
    }

         创建一个用于操作hdfs的Request类

public class Request implements Runnable{
    private String filepath;

    public Request(String filepath) {
        this.filepath = filepath;
    }

    public void readFile(String filePath){
        // 实例化HdfsFs
        HdfsFS hdfsFS = new HdfsFS();
        // 调用方法连接到hdfs文件系统
        FileSystem fs = hdfsFS.getFileSystem();
        // 初始化FsDataInputStream
        FSDataInputStream in = null;
        try {
            // 打开a.txt文件按
            in = fs.open(new Path(filePath));
            // 输出文件中的内容
            IOUtils.copyBytes(in, System.out, 2048, false);
            // 关闭文件FsDataInputStream
            IOUtils.closeStream(in);
            // 关闭文件系统
            fs.close();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
    @Override
    public void run() {
        this.readFile(this.filepath);
    }

    public String getFilepath() {
        return filepath;
    }

    public void setFilepath(String filepath) {
        this.filepath = filepath;
    }
}

 文件系统管理

        在linux系统中,我们可以通过hdfs提供一些命令来查看文件系统,如`-ls`、`-cat`等。但是我们想要通过前端界面中一个交互式按钮来实现该功能,那么就需要使用到Hadoop提供的Java API。主要使用到FileSystem中的listStatus函数。

package testJavaAPI;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileStatus;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;

import java.io.IOException;

public class FSOperation {
    // 查看指定文件目录下的文件结构
    public FileStatus[] getFileStructure() {
        // 待查看的路径
        String pathName = "hdfs://192.168.139.100:9000/";
        // 配置类
        Configuration conf = new Configuration();
        // 初始化文件系统
        FileSystem fs = null;
        // 初始化路径系统
        Path path = new Path(pathName);
        // 通过文件系统查看路径下的内容
        try {
            // 为文件系统传入conf
            fs = FileSystem.get(conf);
            // 调用status查看目标路径下的文件系统情况
            FileStatus[] fileStatuses = fs.listStatus(path);
            // 遍历查看目录下文件的组织情况
            for (FileStatus fileStatus: fileStatuses) {
                // 取出path属性
                String[] filePathList = fileStatus.getPath().toString().split("/");
                String filePath = "/" + filePathList[filePathList.length - 1];
                // 设置path需要改为的值
                Path pathTemp = new Path(filePath);
                // 修改path的内容 path=hdfs://192.168.139.100:9000/home => path=/home;
                fileStatus.setPath(pathTemp);
                // 查看输出 FileStatus{path=/home; isDirectory=true; modification_time=1698108051829; access_time=0; owner=master; group=supergroup; permission=rwxr-xr-x; isSymlink=false}
                //System.out.println(fileStatus);
            }
            return fileStatuses;
        } catch (IOException e) {
            System.out.println(e);
            throw new RuntimeException(e);
        }
    }

    public static void main(String[] args) {
        FSOperation fsOperation = new FSOperation();
        fsOperation.getFileStructure();
    }
    
}

集群管理

        虽然hdfs为我们提供了web可以查看各个节点的状态,但是项目需要装这些状态展示到前端,能够实时显示各个节点的健康状态、使用容量、剩余容量等。所以使用到FileSystem与DistributedFileSystem来获取到各个节点的详细状态,但是要注意的是想要使用该功能需要使用管理员用户登录到hdfs。

public void getDataNodeInformation(){
        // 配置类
        Configuration conf = new Configuration();
        //
        try {
            // 初始化文件系统
            FileSystem fs = null;
            try {
                fs = FileSystem.get(new URI("hdfs://192.168.139.100:9000"), conf, "master");
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            } catch (URISyntaxException e) {
                throw new RuntimeException(e);
            }
            // 初始化分布式文件系统
            DistributedFileSystem hdfs = (DistributedFileSystem)fs;
            // 查看datanode情况
            DatanodeInfo[] datanodeInfos = hdfs.getDataNodeStats();
            for (DatanodeInfo datanodeInfo: datanodeInfos) {
                // 获取节点名称
                System.out.println("Name:" + datanodeInfo.getHostName());
                System.out.println("IP:" + datanodeInfo.getIpAddr());
                System.out.println("Status:" + datanodeInfo.getAdminState());
                System.out.println("Capacity:" + datanodeInfo.getDfsUsed());
                System.out.println("Used:" + datanodeInfo.getDfsUsed());
                System.out.println("Remaining:" + datanodeInfo.getRemaining());
            }

        } catch (IOException e) {
            throw new RuntimeException(e);
        }

    }

猜你喜欢

转载自blog.csdn.net/2201_75875170/article/details/133913482