Hadoop Distributed File System, HDFS
简介
在 Hadoop 生态下的分布式文件系统,有如下的特点:
- 大数据文件,适合 TB 级大文件存储。
- 分块多副本,将完整大文件分块多副本均匀存储到不同服务器上,可以提高并发以及防止数据丢失。
- 流式数据写入,无法动态修改文件内容,文件写入后不再变化,即使变化也只能在文件末尾添加内容。
当单个文件比较大时,单块磁盘无法保存,那么可以将其切分成很多小块,然后分散存储在不同的服务器上,各个服务器通过网络连接,组成一个整体。在 3.x
以上的版本中每个块是 128M
,会自动切割并分散存储在 DataNode
节点上,用户可以在 hdfs-site.xml
配置文件中通过 dfs.replication
参数配置副本数。
采用的是主从结构,主节点为 NameNode
从节点为 DataNode
。
NameNode
文件被分成了多份 Block 数据,在访问某个文件时需要确定由哪些文件组成,具体在哪些机器上,这也就是所谓的元数据。文件、Block、目录等大概会占用 150 字节,所以比较适合大文件存储,而小文件的存储效率过低。
所有的读写操作都与元数据相关,当文件很多之后,对应的元数据必然很大,那么就可能会引入并发性能问题,所以,性能、高可用是元数据操作的关键特性。
安装部署
可以从 Hadoop Release 下载相应的二进制版本,一些默认配置可以参考 share/doc/hadoop/hadoop-project-dist
目录。
----- 解压保存在/opt/module/hadoop目录下
# mkdir -p /opt/module/hadoop/data/{data,name}
----- 添加环境变量,并验证安装正常
# vim /etc/profile
export HDFS_NAMENODE_USER=root
export HDFS_DATANODE_USER=root
export HDFS_SECONDARYNAMENODE_USER=root
export HADOOP_HOME=/opt/module/hadoop
export PATH=${HADOOP_HOME}/bin:${HADOOP_HOME}/sbin:${PATH}
# source /etc/profile
# hadoop version
----- 配置免密登录,注意,对本机也需要进行配置,或者直接添加到
# ssh-keygen -t rsa -f ~/.ssh/id_rsa -N "" -C "hadoop related"
# ssh-copy-id -i ~/.ssh/id_rsa.pub root@localhost
直接在单节点上部署。
----- 修改全局参数,例如HDFS的URL、Hadoop临时目录等
# vim ${HADOOP_HOME}/etc/hadoop/core-site.xml
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
<configuration>
<property>
<name>fs.defaultFS</name>
<value>hdfs://package:8020/</value>
</property>
</configuration>
----- HDFS相关的参数,例如名称和数据节点的保存位置,文件副本数,文件读取权限
# vim ${HADOOP_HOME}/etc/hadoop/hdfs-site.xml
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
<configuration>
<property>
<name>dfs.namenode.http-address</name>
<value>0.0.0.0:9870</value>
</property>
<property>
<name>dfs.replication</name>
<value>1</value>
</property>
<property>
<name>dfs.namenode.name.dir</name>
<value>/opt/module/hadoop/data/name</value>
</property>
<property>
<name>dfs.datanode.name.dir</name>
<value>/opt/module/hadoop/data/data</value>
</property>
</configuration>
----- 格式化NameNode的命令,详见如下的介绍
# hdfs namenode -format
----- 如果通过start-dfs.sh启动会同时开启SecondaryNamenode,这里直接简单启动
# hadoop-daemon.sh start namenode
# hadoop-daemon.sh start datanode
----- 上述命令适合比较老的集群
# hdfs --daemon stop namenode
# hdfs --daemon start namenode
# hdfs --daemon stop datanode
# hdfs --daemon start datanode
Hadoop 集群中的 NameNode 节点用来管理文件系统的命令空间以及文件块的元数据信息,通常在部署、重建、修复集群时使用,会清理 NameNode 上的所有元数据,包括文件、目录、权限、命名空间等信息,将 NameNode 格式化为一个新的状态,所以执行前需要先备份数据。
启动之后就可以通过上述的 dfs.namenode.http-address
配置项访问 Hadoop 界面。
SSL 配置
Java 中包含了 KeyStore 和 TrustStore 两种,本质上都是 KeyStore 只是存放密钥的所有者不同而已,只不过通过文件名区分类型以及用途,其中 KeyStore 存放自己的私钥和公钥,而 TrustStore 则存放自己信任对象的公钥。
----- 创建CA证书,密码为 YourPass ,正常需要发送到各个 Client 节点,单机就不需要发送了
openssl req -new -x509 -keyout /opt/module/keys/ssl/hadoop_ca_key -out /opt/module/keys/ssl/hadoop_ca_cert -days 9999 -subj '/C=CN/ST=ZheJiang/L=HangZhou/O=FooBar/OU=Security/CN=example.com'
----- 生成 KeyStore 文件,并导出证书文件,需要输入 KeyStore 的密码,可以通过 -storetype PKCS12 配置不同格式,不过建议使用默认
keytool -genkey -keystore hadoop.keystore -alias localhost -validity 9999 -keyalg RSA -keysize 2048 -dname "C=CN, ST=ZheJIang, L=HangZhou, O=Foobar, OU=Security, CN=example.com"
keytool -certreq -alias localhost -keystore hadoop.keystore -file hadoop_cert
----- 导入并生成 truststore 文件
keytool -keystore hadoop.truststore -alias CARoot -import -file hadoop_ca_cert
----- 用CA对导出证书进行签名
openssl x509 -req -CA hadoop_ca_cert -CAkey hadoop_ca_key -in hadoop_cert -out hadoop_cert_signed -days 9999 -CAcreateserial
----- 将CA和已经签名的证书导入 keystore 中
keytool -keystore hadoop.keystore -alias CARoot -import -file hadoop_ca_cert
keytool -keystore hadoop.keystore -alias localhost -import -file hadoop_cert_signed
然后修改如下配置。
----- 修改 hdfs 相关配置文件,设置为支持 HTTPS
# vim /opt/module/hadoop/etc/hadoop/hdfs-site.xml
<property>
<name>dfs.http.policy</name>
<value>HTTPS_ONLY</value>
</property>
----- 修改客户端配置文件,直接从模板复制即可
# vim /opt/module/hadoop/etc/hadoop/ssl-client.xml
<property>
<name>ssl.client.truststore.location</name>
<value>/opt/module/keys/ssl/hadoop.truststore</value>
</property>
<property>
<name>ssl.client.truststore.password</name>
<value>YourPass</value>
</property>
<property>
<name>ssl.client.truststore.type</name>
<value>jks</value>
</property>
<property>
<name>ssl.client.keystore.location</name>
<value>/opt/module/keys/ssl/hadoop.keystore</value>
</property>
<property>
<name>ssl.client.keystore.password</name>
<value>YourPass</value>
</property>
<property>
<name>ssl.client.keystore.keypassword</name>
<value>YourPass</value>
</property>
<property>
<name>ssl.client.keystore.type</name>
<value>PCKS12</value>
</property>
----- 修改服务端配置文件,同样从模板复制即可
# vim /opt/module/hadoop/etc/hadoop/ssl-server.xml
<property>
<name>ssl.server.truststore.location</name>
<value>/opt/module/keys/ssl/hadoop.truststore</value>
</property>
<property>
<name>ssl.server.truststore.password</name>
<value>YourPass</value>
</property>
<property>
<name>ssl.server.truststore.type</name>
<value>jks</value>
</property>
<property>
<name>ssl.server.keystore.location</name>
<value>/opt/module/keys/ssl/hadoop.keystore</value>
</property>
<property>
<name>ssl.server.keystore.password</name>
<value>YourPass</value>
</property>
<property>
<name>ssl.server.keystore.keypassword</name>
<value>YourPass</value>
</property>
<property>
<name>ssl.server.keystore.type</name>
<value>PKCS12</value>
</property>
<property>
<name>ssl.server.exclude.cipher.list</name>
<value>TLS_ECDHE_RSA_WITH_RC4_128_SHA,SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA,
SSL_RSA_WITH_DES_CBC_SHA,SSL_DHE_RSA_WITH_DES_CBC_SHA,
SSL_RSA_EXPORT_WITH_RC4_40_MD5,SSL_RSA_EXPORT_WITH_DES40_CBC_SHA,
SSL_RSA_WITH_RC4_128_MD5</value>
</property>
注意,此时需要通过默认的 9871
端口访问 NameNode 的 Web 页面,也可以在 hdfs-site.xml
文件中通过 dfs.namenode.https-address
配置项修改。
安全集群
通过 Kerberos 配置,其中的 DataNode 启动时会对安全性进行检查,除了要配置 Kerberos 相关的内容外,还需要配置 SSL 才行。另外,因为进行鉴权时经常会验证域名,所以建议要先配置好,这里本地使用 package 作为主机名。
----- 创建一个Principal
# kadmin -proot/admin -w'Mrs@2022' -q"addprinc -randkey hadoop/package"
----- 生成所需的Keytab文件
# kadmin -proot/admin -w'Mrs@2022' -q"ktadd -k /opt/module/keys/hadoop.keytab hadoop/package"
----- 可以加载到缓存
# kinit -kt /opt/module/keys/hadoop.keytab hadoop/package
----- 注意这里有个大坑,详见 Tips#1
# klist
Ticket cache: FILE:/tmp/krb5cc_0
Default principal: hadoop/package@EXAMPLE.COM
Valid starting Expires Service principal
08/24/2023 11:12:55 08/25/2023 11:12:55 krbtgt/EXAMPLE.COM@EXAMPLE.COM
renew until 08/24/2023 11:12:55
查看时必须要保证 Ticket Cache
信息是以 FILE
的格式保存,在 CentOS 中还可能存在 KEYRING
和 KCM
等其它格式,需要将 default_ccache_name
配置项删除或者修改为 FILE:/tmp/krb5cc_%{uid}
这种方式。
注意,修改包括 /etc/krb5.conf
和 /etc/krb5.conf.d/
中的相关配置。
然后增加如下配置项,并重启 NameNode 和 DataNode 即可,另外,调试可以通过如下环境变量开启。
export HADOOP_ROOT_LOGGER=DEBUG,console
export HADOOP_OPTS="-Dsun.security.krb5.debug=true -Djavax.net.debug=ssl"
然后修改配置文件。
----- Hadoop开启安全认证
# vim /opt/module/hadoop/etc/hadoop/core-site.xml
<property>
<name>hadoop.security.authorization</name>
<value>true</value>
</property>
<property>
<name>hadoop.security.authentication</name>
<value>kerberos</value>
</property>
<property>
<name>hadoop.rpc.protection</name>
<value>authentication</value>
</property>
----- HDFS配置安全规则
# vim /opt/module/hadoop/etc/hadoop/hdfs-site.xml
<property> <!-- HDFS开启安全配置 -->
<name>dfs.block.access.token.enable</name>
<value>true</value>
</property>
<property> <!-- NameNode开启安全配置 -->
<name>dfs.namenode.kerberos.principal</name>
<value>hadoop/_HOST@EXAMPLE.COM</value>
</property>
<property>
<name>dfs.namenode.keytab.file</name>
<value>/opt/module/keys/hadoop.keytab</value>
</property>
<property>
<name>dfs.namenode.kerberos.internal.spnego.principal</name>
<value>hadoop/_HOST@EXAMPLE.COM</value>
</property>
<property> <!-- DataNode开启安全配置 -->
<name>dfs.datanode.kerberos.principal</name>
<value>hadoop/_HOST@ESRICHINA.COM</value>
</property>
<property>
<name>dfs.datanode.keytab.file</name>
<value>/opt/module/keys/hadoop.keytab</value>
</property>
<property>
<name>dfs.datanode.kerberos.https.principal</name>
<value>hadoop/_HOST@EXAMPLE.COM</value>
</property>
<property>
<name>dfs.datanode.address</name>
<value>0.0.0.0:61004</value>
</property>
<property>
<name>dfs.datanode.http.address</name>
<value>0.0.0.0:61006</value>
</property>
<property>
<name>dfs.data.transfer.protection</name>
<value>integrity</value>
</property>
默认 Hadoop 会使用 Kerberos Principal 中的第一部分作为用户名,如果之前使用的是 root
创建的资源,那么当切换为类似 hadoop/package@EXAMPLE.com
这种的默认对应的用户为 hadoop
,那么就会出现权限问题,最简单的方式是将其统一进行映射。
<property>
<name>hadoop.security.auth_to_local</name>
<value>
RULE:[2:$1@$0](.*@EXAMPLE.COM)s/.*/root/
DEFAULT
</value>
</property>
常用命令
----- 查看集群用户信息
hadoop fs -ls /user
----- 检查集群状态,包括NS、机器数等
hdfs fsck /
----- 设置副本数
hadoop fs -setrep -R 4 FilePath
----- 查看根目录,通过-R参数递归查看
hadoop fs -ls /
----- 统计信息,包括了目录个数、文件个数、文件总大小等信息
hadoop fs -count <hdfs path>
----- 文件大小,可以使用参数-h方便可读、-s总大小
hadoop fs -du <hdfs path>
----- 查看状态信息,格式有%b(文件大小)、%o(Block大小)、%n(文件名)、%r(副本个数)、%y(最后一次修改日期)
hadoop fs -stat [format] <hdfs path>
----- 上传文件,目的地可以是文件名或者目录,注意路径必须存在
hadoop fs -put <local file path> <hdfs file/dir path>
----- 下载文件,如果本地文件存在则不会下载
hadoop fs -get <hdfs file/dir path> <local file/dir path>
----- 删除文件,如果是目录需要使用-r参数,默认会放到回收站
hadoop fs -rm <hdfs file/dir path>
hadoop fs -rm -r -skipTrash <hdfs file/dir path>
----- 创建目录,多个层级需要使用-p参数
hadoop fs -mkdir <hdfs dir path>
----- 删除目录,需要先确保目录为空
hadoop fs -rmdir <hdfs dir path>
其它,常用命令包括了复制 -cp
、移动 -mv
等。
----- 清空回收站,数据会在一分钟后清除
hdfs dfs -expunge
----- 日志分区占用空间大小
hdfs dfs -du -s -h /tmp/logs/dc_admin/logs
----- 检查健康的节点
hadoop dfsadmin -report
用户
HDFS 提供了一套兼容 POSIX 的文件权限模型,包括粗粒度的 POSIX UGO 模型和细粒度的 POSIX ACL 协议。在使用时会从用户身份认证、用户组映射、数据访问鉴权三个环节进行验证,如果其中某个失败,那么就会返回报错。
使用客户端的常见操作,例如上传、下载等,都会通过一个用户来进行操作,当开启 ACL 之后还会通过用户信息来进行权限校验,默认会按照如下规则按照优先级获取:
export HADOOP_USER_NAME=root
通过环境变量配置,相比来说优先级更高。export HADOOP_CLIENT_OPTS=-DHADOOP_USER_NAME=root
执行 hdfs 脚本时会作为参数传入。- 使用当前用户。
如果是启用了 Kerberos 认证时,包含了:A) 从系统缓存票据 (Ticket) 内获取用户信息;B) 指定 Principal 以及 Keytab 文件调用 Hadoop 接口完成 Kerberos 认证并从中获取用户信息。
----- 通过缓存票据完成鉴权
# kinit root
# klist
# hdfs dfs -mkdir /user