深入浅出Hadoop之HDFS
Hadoop生态系统一直是大数据领域的热点,其中包括今天要聊的HDFS,和计划以后想聊的yarn, mapreduce, spark, hive, hbase, 已经聊过的zookeeper,等等。
今天主聊HDFS,hadoop distributed file system, 起源于Google 的 GFS,只不过GFS是用c++写的,Hadoop是Doug Cutting在yahoo用Java写的。2008 年 Hadoop成为Apache top-level project。
应用
HDFS适用于什么场景呢? 非常大的文件存储,比如以G或T为单位,因为HDFS内部的block的基本单位已经是128MB。注意这里有一个小文件问题,误区是说怕1K的小文件也能占用128MB的硬盘,其实不是的,它还是占用1K硬盘,但是小文件问题的bottle neck是在name node里,因为name node要存储文件和block的相关信息在内存里,文件数量一多,name node的内存就不够了(比如,百万小文件要占用300MB 内存),当然hdfs federation能够通过sharding的方式解决name node内存不够用的问题,接下来会细说。HDFS还适用于“write once,read-many”的场景,而且它的写是append only,所以想改也没法改。如果是多次写的话,应该考虑一下cassandra(参见我的上一篇文章)。同时HDFS的文件通常只能允许single writer写入(是通过lease的方式来保证只有一个writer能够当前写某个文件)。HDFS因为只需要普通的commodity hardware而不需要昂贵的高可用硬件而被企业欢迎。HDFS不适用于需要low latency的数据访问方式,因为HDFS是拿延迟交换高throughput。
概念
Blocks
HDFS里,文件是被分割成block大小的chunk,每个block是128MB,有人会问了,为什么非要搞这么大,主要是要缩短寻道时间在总硬盘读写时间中的比例,比如寻道时间需要5 ms,而寻到时间只能占总时间0.5%的比例,那么硬盘读写时间差不多在1s左右,1s中能穿多少文件呢,如果硬盘的读写为128MB/s,那么就能传128MB,所以block大小就定义为128MB,这样可以保证硬盘操作的时间有效的应用在读写上而不是花费在寻道上。当然太大了也不行,mapreduce的map通常是以block为单位,如果block太少,mapreduce的效率会比较低。
hdfs fsck $path -files -blocks -locations
上面的命令可以用来提供文件的block信息,比如block在哪台机器,名字是什么,方便你进一步查询block的具体信息。
Namenodes and datanodes
namenode管理namespace, 管理文件系统树状结构和文件/目录的metadata,这些信息以如下方式持久化在硬盘里:namespace image 和 edit log。同时block的metadata也存放在namd node,存放于内存中。前面提到过百万小文件,会占用300MB内存的例子。block信息为什么不持久化呢,因为它会变动,系统重启的时候会从datanode那里重新构建。
name node的备份有几种方式,一种是把持久化存放于硬盘的信息既写到本地硬盘也同时写到远程NFS mount。另一种方式是运行secondary namenode,它其实并没有扮演namenode的角色,而是周期性的merge namesapce image以及edit log来防止edit log过大。它会保存一份merged namespace image,一旦primary fail了,就把NFS上的metadata copy到secondary namenode上,这样secondary就成为了新的primary。
具体过程如下图所示,edit log和fsimage都是在硬盘中,edit log就是WAL(cassandra写操作也用到了WAL的手段,WAL很流行,可以单拉出来讲一次),fsimage是check point of the filesystem metadata。写的时候先写edit log,然后update in-memory representation of filesystem metadata(用来serve读请求),图中没有画出这部分操作。
有没有更好的方法呢?上述方法没能提供HA, namenode仍然是single point of failure。新的primary需要(1)load namespace image into memory (2)replay edit log (3)从datanode那边接收足够的block reports(前文提到block信息是在内存中的)。这个过程有可能会话费30分钟或更久。client等不了啊~~
Hadoop 2提供了HA的support。namenode采用active-standby的配置方式:
- namenodes使用高可用共享存储来存edit log。active每次写入都会被standby读出并synchronize到自己的内存中。
- datanodes在发送block reports时会同时发给所有的name nodes,记住block mapping是在内存中。
- 客户端需要配置来handle namenode failover,其实就是watch zookeeper的leader election(参见我之前讲的zookeeper)
- 这样就不需要secondary namenode啦,standby取代了它的作用会周期性的产生check points
上面提到的共享存储主要指的是QJM(quorum journal manager),通常配置3个(当然我也见过50个node配5个journal nodes),写的时候需要满足quorum。
这样当active namenode fail时,standby可以马上扛住,因为latest edit log和 up-to-date block mapping都在内存中。
HDFS write
HDFS read
CLI Example
touch test.txt hdfs dfs -mkdir /user/qingge/testdir hdfs dfs -copyFromLocal ./test.txt /user/qingge/testdir/ hdfs dfs -ls /user/qingge/testdir/test.txt hdfs dfs -chmod o-r /user/qingge/testdir/test.txt hdfs dfs -cat /user/qingge/testdir/test.txt | head -10 hdfs dfs -mv /user/qingge/testdir/test.txt /user/qingge/testdir/test2.txt hdfs fsck /data/lalala -files -blocks -locations hdfs fsck -blockId blk_10101010
HTTP 访问
(1) direct access: HDFS daemons server HTTP requests, embedded web servers in the name node and datanodes act as WebHDFS endpoionts.
(2) proxy access: 中间有多个HDFS proxy,for strictr firewall and bandwidth-limiting policies, proxy和node之间使用RPC request和block request。
HDFS Federation
相当于namenode sharding了,如果不想用HA,然后namenode内存又要爆了怎么办,答分区呀,每个namenode从根目录下划走几个子目录,无线分区无线扩充,每个namenode之间井水不犯河水,一个爆了或废了丝毫不影响另一个。
思考题:
如果HDFS有1PB容量,每个block大小是64MB,平均的metadata大小是每个block300B,replication factor是3, 那么namenode最小的内存是多少呢?
答:差不多需要1.56G, 1024*1024*1024 MB/(64MB*3)*300B/(1024 * 1024 * 1024) = 1.56 GB
好,今天差不多就到这了~~ happy HDFS!