>hdfs 动态扩容:
HDFS 中存储的文本副本大小:默认是128M
参数:dfs.blocksize 默认128M 每一个副本大小,这是客户端的行为,传一个副本或者获取一个副本,值获取配置大小的副本,也就是存储的大小都是由客户端决定的。
def.replication 默认副本数量3个,也是由客户端决定,
元数据存储目录:
dfs.namenode.name.dir | file://${hadoop.tmp.dir}/dfs/name |
默认的存储方式是,在配置的hadoop.tmp.dir配置目录下面的name,
正确的做法是,配置多个目录
<name>dfs.namenode.name.dir</name>
<value>/mnt/disk1, /mnt/disk2,nfs://xxx/xxxx</value>
dataNode的文件块目录也应该是配置到专门存储数据的磁盘
dfs.datanode.data.dir 默认的也是在 file://${hadoop.tmp.dir}/dfs/data 目录中
<name>dfs.datanode.dir</name>
<value>/mnt/disk1, /mnt/disk2,nfs://xxx/xxxx</value>
这里的写法核上面的写法是不一样的,上面的namenode 的写法是没一个数据在每一个目录都写一遍,而datanode 的写法是,讲所有的挂载目录都当成是一个,这次给这个目录写,下一次给下一个目录写。
第一个api操作程序:
// 1 获取入口FileSystem
Configuration conf = new Configuration();
// set 客户端使用的参数
conf.set("dfs.replication","2");
FileSystem dfsClient = FileSystem.get(new URI("hdfs://172.16.214.128:9000"), conf,"root");
// 上传一个文件
Path fromLocalPath = new Path("/Users/xuxliu/Downloads/hadoopConfigcopy.docx");
Path targetHdfsPath = new Path("/test/test.doc");
dfsClient.copyFromLocalFile(fromLocalPath, targetHdfsPath);
dfsClient.close();
遇到问题:Caused by: org.apache.hadoop.ipc.RemoteException(org.apache.hadoop.security.AccessControlException): Permission denied: user=xuxliu, access=WRITE, inode="/":root:supergroup:drwxr-xr-x
权限问题,默认是需要开启权限的,而我们在命令行里面没有遇到这个问题是因为命令行里是root执行的,解决方法,关闭权限
<property>
<name>dfs.permissions.enabled</name>
<value>false</value>
</property>
需要重启
API 测试代码
private FileSystem dfsClient;
@Before
public void init() throws Exception {
Configuration conf = new Configuration();
conf.set("dfs.replication","2");
dfsClient = FileSystem.get(new URI("hdfs://172.16.214.128:9000"), conf,"root");
}
/**
* 测试hdfs 上取文件到本地
*/
@Test
public void testGetFile() throws IOException {
Path targetLocalPath = new Path("/Users/xuxliu/Downloads/");
Path sorHdfsPath = new Path("/test/test.doc");
dfsClient.copyToLocalFile(sorHdfsPath, targetLocalPath);
dfsClient.close();
}
@Test
public void testMkdir() throws IOException {
boolean mkdirs = dfsClient.mkdirs(new Path("/xxx/yyyy"));
dfsClient.close();
}
@Test
public void testDelete() throws IOException {
// delete(Path f, boolean recursive)
boolean delete = dfsClient.delete(new Path("/xxx"), true);
dfsClient.close();
}
@Test
public void testRenameDir() throws IOException {
dfsClient.rename(new Path("/xxx"), new Path("/xxxuuu"));
dfsClient.close();
}
@Test
public void testlistDir() throws IOException {
// final Path f, final boolean recursive) 递归显示全部
RemoteIterator<LocatedFileStatus> iterator = dfsClient.listFiles(new Path("/"), true);
while (iterator.hasNext()){
LocatedFileStatus next = iterator.next();
System.out.println(next.getBlockLocations());
System.out.println(next.getBlockSize());
System.out.println(next.getOwner());
}
dfsClient.close();
}
@Test
public void testDirInfo() throws IOException {
// List the statuses of the files/directories in the given path if the path is
// * a directory. 不会递归
FileStatus[] fileStatuses = dfsClient.listStatus(new Path("/"));
for (FileStatus fs: fileStatuses
) {
System.out.println(fs);
// FileStatus{path=hdfs://172.16.214.128:9000/a.txt; isDirectory=false;
// length=15; replication=2; blocksize=134217728; modification_time=1550903769312;
// access_time=1550903768982; owner=root; group=supergroup; permission=rw-r--r--;
// isSymlink=false}
}
dfsClient.close();
}
@Test
public void testGetPartOfFile() throws IOException {
FSDataInputStream inputStream = dfsClient.open(new Path("/qingshu.txt"));
FileOutputStream outputStream = new FileOutputStream("/Users/xuxliu/Downloads/qingshu.txt");
// offset from start index 指定读取的起始位置
inputStream.seek(20);
byte[] bytes = new byte[10];
int len = 0;
long count = 0;
while (inputStream.read(bytes)!=-1){// 不等于-1 就是读取了一个缓存
outputStream.write(bytes);
count += 1;
if (count == 20){
break;
}
}
inputStream.close();
outputStream.close();
dfsClient.close();
}
@Test
// 输出流的方式网 hdfs 写数据
public void testWriteDataToHdfs() throws IOException {
// 打开 hdfs 文件
FSDataOutputStream hdfsOut = dfsClient.create(new Path("/qingshu2.txt"));
hdfsOut.write("77777777777777777".getBytes());
hdfsOut.write("88888888888888888".getBytes());
hdfsOut.flush();
hdfsOut.close();
dfsClient.close();
}
HDFS 读写机制:
写:
- 客户端请求写数据(带着路径)nameNode,namenode会返回这个路径是否能写
- 客户端继续请求namenode,写入一个block,
- namenode 会返回来可用的datanode blockId 可用的datanode等
- 客户端和datanode握手,请求传输文件块,只会传递给一个datanode,这个datanode会和其他的datanode发请求,谁准备接受数据。返回接听的端口,告诉客户端准备好了
- 客户端本地读书局,然后网络流给第一台机器收数据,这台机器的这些数据,还会给其他datanode传输数据
- 接着客户端传递这个文件的第二块,重复上面的步骤
下载数据:
- 客户端读取数据请求。
- namenode 会根据请求参数,查看这些数据是否存在,如果存在则返回请求文件的元数据
- 客户端拿着这些元数据取datanode 取数据
NameNode 如何管理元数据的:
元数据是什么:HDFS 中的文件的描述信息,路径/BLK信息/位置/长度/副本数量,这些数据是放在内存中的
所以宕机那么就会很危险了。
元数据的的任何东西都是因为客户端的操作而引起的。nameNode 的信息会根据客户端的操作而跟新,也会将这些操作写到磁盘里面去,防止宕机,隔一段时间就会将操作的东西写到磁盘(fsimage), 而这个存放是有secondaryNamenode做的,到达一个触发点就会将这段时间的操作,写到 fsimage,然后nameNode重新记录新的操作,万一宕机,那么可以根据执行这些记录而重新操作一遍讲数据恢复。
secondaryNamenode 执行checkpoint操作