其实很多人都知道hadoop自带一个hadoop balancer的功能,作用于让各个datanode之间的数据平衡.
比如说node-A有100GB数据,占用磁盘99%空间;
而node-B只有10GB数据占用磁盘10%空间~
那么当我们以hdfs身份运行hadoop balance的时候,hadoop将会平衡这两个node之间的数据.
至于多少叫做平衡,hadoop的default是10%的threshold, 但是我们可以在命令里面指定一个门限~比如:
sh $HADOOP_HOME/bin/start-balancer.sh –t 15%
具体的用法可以参照: http://www.cnblogs.com/gpcuster/archive/2011/02/16/1956555.html
但是这里我们要讨论的是一个datanode内部的数据平衡,简单来说就是一个node如果我们有多个数据分区被hadoop使用,那么这些数据分区之间是不是也将被balancer自动平衡呢?
答案是否定的!
hadoop balancer不会自动平衡node内部的数据,也就是说,如果遇到我们上述的情况,hadoop根本不会管理,而是只是考虑数据的总量!
于是现在问题就来了,hadoop在写入数据的时候采用的平衡写入的方式,也就是说如果我们有两个partition被hadoop使用存储数据:
/data1 100% total 100GB
/data2 10% total 100GB
|
那么结果将是hadoop还是将数据尝试平分到两个分区,但是由于第一个分区已经用完,这时候hadoop则会放弃在这个node存储更多的数据!!
这个绝对是我们不想要的结果,但是有什么办法可以解决这个问题呢?
搜索了一下官方的文档以后我发现了答案:
其实hadoop node内部的数据存放是非常简单的,每一个数据块都是有一个meta data的文件维持.*(什么是数据块请参考hadoop dfs相关文献)
所以举例:
数据块 A 一定有一个叫 A.meta的文件维持其在hadoop dfs中的存放.
简单的来说就是,hadoop将大数据文件split成小文件块,default size是64MB~ (这里有一个hadoop小文件problem,请参考相关资料)
每一个数据块都需要有一个meta文件以便让hadoop dfs方便的知道这个数据块的内容,这样hadoop dfs就不需要完全的读出整个数据块的内容就可以轻易的在我们需要找到他的时候快速的找出(里面用到了Hash以及Indexing的有关算法,有兴趣可以查看相关的文档)
那么现在的问题就是,我们怎样自己把文件转移到另一个分区.
根据官方的说法:
Hadoop currently does not have a method by which to do this automatically. To do this manually:
- Take down the HDFS
- Use the UNIX mv command to move the individual blocks and meta pairs from one directory to another on each host
- Restart the HDFS
也就是,我们service down datanode,然后使用类似mv的命令将数据块和相关的meta文件同时复制到另一个分区即可!
操作是非常简单的,但是一定要记住,在转移的过程中一定要关闭datanode service, 尽量也关闭tasktracker service.
因为如果在datanode service还在运行的时候我们就转移文件的话,hadoop dfs非常可能崩溃~而且有可能是不可恢复的!
另外一个小提醒:
如果在转移文件的时候我们还有其他的hadoop job在运行,我们还是可以直接关闭某一个node的datanode service, 因为hadoop default的data replica = 2
也就是说我们shutdown这个node以后,其他的node还是有这个node上所有的数据备份.
但是我们最好不要同时shutdown多个node,因为这样或许会影响hadoop job的正常运行~