HDFS全称是Hadoop Distributed File System,简称HDFS。这是一个分布式文件系统,当数据规模大小超过一台物理计算机的存储能力时,就有必要进行分区并存储到若干台物理计算机上。管理网络中跨多台计算机的文件系统称为分布式文件系统。
Hadoop的文件系统是一个抽象的概念,java的抽象类是org.apache.hadoop.fs.FileSystem,在创建一个FileSystem的时候,FileSystem使用文件系统URI的Schema作为查询配置或者SPI寻找实现类(类似JDBC)。FileSystem有很多实现,HDFS只是其中的一个实现,它的实现类是org.apache.hadoop.hdfs.DistributedFileSystem,它的URI schema为hdfs。Hadoop默认配置的文件系统实现是org.apache.hadoop.fs.LocalFileSystem,URI schema为file,用于管理本地文件。
块设备(例如硬盘)一般会有一个默认块大小,这是设备读写的最小单位,这类设备的块大小一般为几千字节。HDFS同样有块的概念,默认情况下HDFS的块大小为128MB。但是与硬盘的文件系统不一样,当文件小于HDFS的块大小时,不会占用整个块的空间,例如一个1MB大小的文件只占用了1MB的空间,而不是128MB。HDFS的块比硬盘的大是为了最小化寻址开销,如果块足够大,从磁盘传输数据的时间会明显大于定位这个块位置需要的时间,所以传输一个大文件的时间取决于磁盘传输速率。
使用块来管理分布式文件系统有很多好处,例如一个文件可以大于某个物理设备的容量,文件并不需要存储在一个物理设备上。另一个好处是块可以存储在多个节点上,防止某个设备因为故障而丢失数据。
HDFS集群有两种节点,分别是namenode和datanode。以管理节点——工作节点方式对外提供服务,即client连接namenode,一个namenode节点负责管理多个datanode。
namenode负责管理文件系统的命名空间,它维护文件系统元数据信息,例如目录和文件名称。这些信息以文件的形式永久保存在硬盘上:分别是命令空间镜像文件和编辑日志文件。namenode也记录每个文件的块所在的数据节点信息,但它并不永久保存块的位置,这些信息会在启动的时候根据数据节点的数据重建。
datanode就是文件系统的工作节点。它们根据需要存储数据块信息,并且定期向namenode发送所存储的块列表。HDFS通过把数据块冗余到多个datanode实现数据的安全性,默认副本数量为3。
namenode对外提供服务的时候需要把所有的文件元数据加载到内存,重启的时候会利用镜像文件和编辑日志重建数据,镜像文件类似于Redis的rdb文件。namenode会周期性归档编辑日志来生成一个更加新的镜像文件,由于归档编辑日志的时候namenode也会对外提供服务,这段时间的操作会写入到编辑日志中,所以namenode需要镜像文件和编辑日志一起重建文件元数据。一个大规模的HDFS的恢复是非常消耗时间的(取决于所管理的数据规模),由于namenode是管理节点,没有namenode整个文件系统将无法使用,所以相对datanode,namenode的高可用非常重要。本节主要为对HDFS简单介绍,故先不讨论HDFS的高可用方案。
由于namenode在内存中维护系统内文件和数据块的关系,很明显namenode运行机器的内存会限制整个集群能存储的文件数量。Hadoop在2.x版本引入的联邦namenode,在联邦环境下,每个namenode管理一个命名空间的一部分。例如一个namenode管理/a目录下的所有文件,另一个namenode管理/b目录下的所有文件。在联邦环境下,每个namenode是独立的,其中一个namenode失效了也不会影响其他namenode。
Hadoop命令行的fs参数提供了一些方便访问文件系统的操作,所有的参数和格式可以在官网文档FileSystemShell中查询到,这里简单列举一些常用的操作。
格式:hadoop fs -cat [-ignoreCrc] URI [URI ...]
参数说明:
例如:
打印本地文件系统下的text.txt内容
hadoop fs -cat file:///D:/test.txt
打印hdfs上根目录下的a.txt内容
hadoop fs -cat hdfs://192.168.73.130:8082/a.txt
格式:hadoop fs -ls URI
参数说明:
例如:
列出hdfs上根目录的文件内容
hadoop fs -ls hdfs://192.168.73.130:8082/
输出每一列含义为:权限,副本数,所属用户,所属用户组,文件大小,修改时间,文件名。权限字段由有7个标识位,第一个标识位含义是文件类型,如果是目录则为d,然后紧跟的6个标识位表示所属用户、所属用户组、其他用户的是否可读、可写、可执行,可执行权限可以忽略,因为不能在HDFS中执行。第二列为副本数,目录的元数据保存在namenode上,所以没有副本数。
示例输入如下:
hadoop fs -ls hdfs://192.168.73.130:8082/
Found 2 items
-rw-r--r-- 3 debian supergroup 19481 2023-01-25 15:30 hdfs://192.168.73.130:8082/a.txt
drwxr-xr-x - debian supergroup 0 2023-01-28 09:08 hdfs://192.168.73.130:8082/test
格式:hadoop fs -copyFromLocal localsrc URI
参数说明:
例如:
把本地的文件a.txt复制到HDFS的/testDir/a.txt上
hadoop fs -copyFromLocal a.txt hdfs://192.168.73.130:8082/testDir/a.txt
格式:hadoop fs -copyToLocal URI localsrc
参数说明:
例如:
把HDFS的/testDir/a.txt复制到本地
hadoop fs -copyToLocal hdfs://localhost:8082/testDir/a.txt a.txt
格式:hadoop fs [-f] [-r |-R] [-skipTrash] [-safely] URI [URI ...]
参数说明:
例如:
删除根目录的output文件
hadoop fs -rm hdfs://localhost:8082/output
使用方法FileSystem#open()可以打开一个FSDataInputStream输入流,然后可以像读取本地文件一样文件中的数据。但是与一般的输入流不一样,FSDataInputStream实现了Seekable和接口PositionedReadable,它们分别支持随机读取和指定位置读取。
Seekable的声明如下:
public interface Seekable {
/**
* 设置下一次读取的时,使用的偏移量
*/
void seek(long pos) throws IOException;
/**
* 返回当前读取偏移量
*/
long getPos() throws IOException;
}
getPos返回当前读取偏移量,seek设置下一次read的偏移量,偏移量是当前距离文件起始位置的字节数。例如可以用如下代码重复读取文件开头的2048个字节;
FSDataInputStream in = .....;
byte[] buff = new buff[2048];
in.read(buff);
in.seek(0);
in.read(buff);
seek使用起来很方便,但是是一个相对高开销的操作,需要慎重使用。
PositionedReadable的声明如下:
public interface PositionedReadable {
/**
* 从position指定的位置开始读取length个长度的数据,复制到buffer的offset处,返回实际读取到的字节数
*/
int read(long position, byte[] buffer, int offset, int length)
throws IOException;
/**
* 从position指定的位置开始读取length个长度的数据,复制到buffer的offset处
* 如果到达文件结尾抛出EOFException
*/
void readFully(long position, byte[] buffer, int offset, int length) throws IOException;
/**
* 从position指定的位置开始读取buffer.length个长度的数据,复制到buffer的offset处
* 如果到达文件结尾抛出EOFException
*/
void readFully(long position, byte[] buffer) throws IOException;
}
read函数把指定偏移量数据读取到buffer中,但是实际读取的字节数需要调用者接受返回值进行判断。readFully效果也类似,但是如果到达文件结尾会抛出EOFException。PositionedReadable所有的方法都不会改变当前流读取文件的位置,同时它的方法也都是线程安全的。
传入一个Path对象,然后使用FileSystem#create可以创建一个新文件,并且返回一个FSDataOutputStream对象。与java其他的api不一样,调用create方法会自动创建父级目录。
使用FileSystem#append()可以向一个已存在的文件尾追加内容,需要说明的是这个方法是一个可选的实现,并不是每一个文件系统都正常此方法。
调用FileSystem#mkdirs()方法可以新建一个目录,通常创建文件不需要显示调用此方法,因为创建文件会自动创建对应的父级目录。
调用FileSystem#delete()可以删除一个文件或者目录。
使用FileSystem#getFileStatus方法可以返回一个FileStatus对象来获取文件或者目录的的状态信息,例如是否为目录、权限、文件长度等数据。
FileSystem#listStatus可以列出目录下所有的文件信息。listStatus有多个重载方法,可以额外传入一个org.apache.hadoop.fs.PathFilter用来过滤目录的文件。
对于创建一个目录,HDFS可以保证操作是立即可见的。但是对于写入数据并不能保证其可见性。例如对于以下一段Java程序代码:
OutputStream out = ...;
out.write(buff);
out.flush();
如果是操作本地文件,调用flush方法,会把缓冲区数据刷新到硬盘上,保证其可见性。然而对于HDFS,即使调用了flush方法也不能保证可见性,需要等到数据超过一个块之后才能对其他读取进程可见。但是HDFS的实现提供了两个方法用于保证可见性,分别是FSDataOutputStream#hflush和FSDataOutputStream#hsync,hsync和操作系统的sync方法类似,保证数据已经存储在datanode的硬盘上,而hflush仅仅保证数据写入到datanode的内存。调用close关闭流会自动调用一次hflush。
我使用FileSystem常用api实现了一个客户端demo,代码地址在github 的hdfsApiExample模块,打包此模块可以得到一个hdfs-api-example-1.0-SNAPSHOT.jar的文件,它的使用方法如下:
参数:
示例:
列出hdfs上,根目录的文件
hadoop jar hdfs-api-example-1.0-SNAPSHOT.jar -fs hdfs://192.168.73.130:8082 -u debian -o ls /
删除hdfs上,/cnblog目录。使用额外的r参数递归删除非空目录
hadoop jar hdfs-api-example-1.0-SNAPSHOT.jar -fs hdfs://192.168.73.130:8082 -u debian -o rm r /cnblog
在根目录下创建一个cnblog目录
hadoop jar hdfs-api-example-1.0-SNAPSHOT.jar -fs hdfs://192.168.73.130:8082 -u debian -o mkdir /cnblog
复制本地文件test.txt到hdfs的根目录上
hadoop jar hdfs-api-example-1.0-SNAPSHOT.jar -fs hdfs://192.168.73.130:8082 -u debian -o cp text.txt hdfs:/test.text
复制hdfs的根目录文件text.txt到本地目录上
hadoop jar hdfs-api-example-1.0-SNAPSHOT.jar -fs hdfs://192.168.73.130:8082 -u debian -o cp hdfs:/test.text text.txt
需求:要创建虚拟机,就需要给他提供一个虚拟的磁盘,我们就在/opt目录下创建一个10G大小的raw格式的虚拟磁盘CentOS-7-x86_64.raw命令格式:qemu-imgcreate-f磁盘格式磁盘名称磁盘大小qemu-imgcreate-f磁盘格式-o?1.创建磁盘qemu-imgcreate-fraw/opt/CentOS-7-x86_64.raw10G执行效果#ls/opt/CentOS-7-x86_64.raw2.安装虚拟机使用virt-install命令,基于我们提供的系统镜像和虚拟磁盘来创建一个虚拟机,另外在创建虚拟机之前,提前打开vnc客户端,在创建虚拟机的时候,通过vnc
Region是HBase数据管理的基本单位,region有一点像关系型数据的分区。region中存储这用户的真实数据,而为了管理这些数据,HBase使用了RegionSever来管理region。Region的结构hbaseregion的大小设置默认情况下,每个Table起初只有一个Region,随着数据的不断写入,Region会自动进行拆分。刚拆分时,两个子Region都位于当前的RegionServer,但处于负载均衡的考虑,HMaster有可能会将某个Region转移给其他的RegionServer。RegionSplit时机:当1个region中的某个Store下所有StoreFile
我试图在Ubuntu14.04中使用Curl安装RVM。我运行了以下命令:\curl-sSLhttps://get.rvm.io|bash-sstable出现如下错误:curl:(7)Failedtoconnecttoget.rvm.ioport80:Networkisunreachable非常感谢解决此问题的任何帮助。谢谢 最佳答案 在执行curl之前尝试这个:echoipv4>>~/.curlrc 关于ruby-在Ubuntu14.04中使用Curl安装RVM时出错,我们在Stack
安装Rails时,一切都很好,但后来,我写道:rails-v和输出:/home/toshiba/.rvm/rubies/ruby-2.2.1/lib/ruby/site_ruby/2.2.0/rubygems/core_ext/kernel_require.rb:54:in`require':cannotloadsuchfile--rails/cli(LoadError)from/home/toshiba/.rvm/rubies/ruby-2.2.1/lib/ruby/site_ruby/2.2.0/rubygems/core_ext/kernel_require.rb:54:in`r
提供3种Ubuntu系统安装微信的方法,在Ubuntu20.04上验证都ok。1.WineHQ7.0安装微信:ubuntu20.04安装最新版微信--可以支持微信最新版,但是适配的不是特别好;比如WeChartOCR.exe报错。2.原生微信安装:linux系统下的微信安装(ubuntu20.04)--微信适配的最好,反应最快,但是微信版本只到2.1.1,版本太老,很多功能都没有。3.深度deepin-wine6安装微信:ubuntu20.04+系统deepin-wine6安装新版微信--综合比较好,当前个人使用此种方法1个月,微信版本3.4;没什么大问题,尚可。一、WineHQ7.0安装微信
这个问题在这里已经有了答案:Unabletoinstallgem-Failedtobuildgemnativeextension-cannotloadsuchfile--mkmf(LoadError)(17个答案)关闭9年前。嘿,我正在尝试在一台新的ubuntu机器上安装rails。我安装了ruby和rvm,但出现“无法构建gemnative扩展”错误。这是什么意思?$sudogeminstallrails-v3.2.9(没有sudo表示我没有权限)然后它会输出很多“获取”命令,最终会出现这个错误:Buildingnativeextensions.Thiscouldtakeawhi
这是什么。我首先做了:rvmgetstablervminstallruby-2.2.2没有交易。它向我展示了以下内容:$rvminstallruby-2.2.2Searchingforbinaryrubies,thismighttakesometime.Nobinaryrubiesavailablefor:ubuntu/14.04/i386/ruby-2.2.2.Continuingwithcompilation.Pleaseread'rvmhelpmount'togetmoreinformationonbinaryrubies.Checkingrequirementsforubunt
昨晚看到IDEA官推宣布IntelliJIDEA2023.1正式发布了。简单看了一下,发现这次的新版本包含了许多改进,进一步优化了用户体验,提高了便捷性。至于是否升级最新版本完全是个人意愿,如果觉得新版本没有让自己感兴趣的改进,完全就不用升级,影响不大。软件的版本迭代非常正常,正确看待即可,不持续改进就会慢慢被淘汰!根据官方介绍:IntelliJIDEA2023.1针对新的用户界面进行了大量重构,这些改进都是基于收到的宝贵反馈而实现的。官方还实施了性能增强措施,使得Maven导入更快,并且在打开项目时IDE功能更早地可用。由于后台提交检查,新版本提供了简化的提交流程。IntelliJIDEA
我正在ubuntu14.04和ruby2.2.4上安装passenger+nginx。passenger-install-nginx-module有bundler错误$passenger-install-nginx-module/home/ubuntu/.rvm/gems/ruby-2.2.4/gems/bundler-1.13.1/lib/bundler/rubygems_ext.rb:45:in`full_gem_path':uninitializedconstantBundler::Plugin::API::Source(NameError)from/home/ubuntu/.r
介绍pytest是一个非常成熟的全功能的Python测试框架,主要有以下几个特点:简单灵活,容易上手支持参数化能够支持简单的单元测试和复杂的功能测试,还可以用来做selenium/appnium等自动化测试、接口自动化测试(pytest+requests)pytest具有很多第三方插件,并且可以自定义扩展,比较好用的如pytest-selenium(集成selenium)、pytest-html(完美html测试报告生成)、pytest-rerunfailures(失败case重复执行)、pytest-xdist(多CPU分发)等测试用例的skip和xfail处理可以很好的和jenkins集成