Hadoop Archive解决海量小文件存储

这段时间看了公司部门邮件中大家讨论较多的几个关于HDFS的问题,一个是关于Namenode可扩展性的讨论,目前单台服务器作为Namenode,当文件数量规模不断增大时,元数据的规模增长将是一个需要面对的问题,由于Namenode需要将所有元数据Load到内存中,单台Namenode可能会无法管理海量的元数据。另一个是HDFS中SequenceFile存储方式的讨论,利用Block压缩方式可以很好的解决空间压力。

今天刚好看到Yahoo! Hadoop Blog上的一篇文章Hadoop Archive: File Compaction for HDFS,和上面两个问题都有一点联系,文章主要提出了在HDFS中存在海量的小文件时,会给存储带来的一系列问题 。

HDFS中文件是按Block来存储的,默认一个Block的长度是128MB,当HDFS中存在大量小文件(长度小于128MB)时,不仅占用大量存储空间,而且也占用大量的namespace,给Namenode带来了内存压力,Yahoo内部有一个生产集群,统计下来有57,000,000个小于128MB的文件,这些小文件消耗了95%的namespace,占用了30%的存储空间。Namenode的压力一般也常常是因为有海量的小文件存在,如果没有这些小文件存在的话,Namenode内存还没撑爆,估计存储空间就先爆了。。

文中提到了解决方法,是利用Hadoop Archive(HAR),这个特性从Hadoop 0.18.0版本就已经引入了,他可以将众多小文件打包成一个大文件进行存储,并且打包后原来的文件仍然可以通过Map-reduce进行操作,打包后的文件由索引和存储两大部分组成,索引部分记录了原有的目录结构和文件状态。

Hadoop Archive

举个例子,原本获取一个文件通过命令

hadoop fs –get hdfs://namenode/foo/file-1 localdir

如果将foo目录打包成bar.har后,获取file-1的命令就变成

hadoop fs –get har://namenode/bar.har#foo/file-1 localdir

通过以下命令可以将文件打包成HAR。

hadoop archive -archiveName  *

但是,目前HAR文件中的源数据只能获取,不能修改,文章中提到实现可以修改将是下一步的工作。

参考文章:

  1. Hadoop Archive: File Compaction for HDFS
  2. The Small Files Problem
  3. Hadoop Archives

用Python监视进程是否结束

平时不打游戏在Linux下的时间比较长,用VirtualBox装了个XP可以上上QQ,用用其他一些只有Windows版的软件,这两天下BoA的演唱会又用到了网盘,而且网盘的客户端软件只支持Windows,这样就只能在VirtualBox里下载,可是下载结束自动关机的功能就失效了。。于是想到能不能VirtualBox自动关闭的同时,也能让Linux也一起关闭。

不知道有什么简便的方法可以实现,只想到了用Python写个小脚本(过去一直用Python来解决一些小问题),于是去网上搜了Python相关的类库,其中os.system函数可以调用Linux命令,初步想了下,准备用一个线程来不断执行ps命令,并检查VirtualBox的进程是否还存在,如果不存在了,就执行halt

不过尝试了一下用os.system调用ps后,输出的结果无法保存到变量中,看了一个帖子,发现os.popen可以解决,os.popen可以像打开文件一样执行一条Linux命令,命令返回的结果可以通过读取文件的方式获得。

通过ps ax|grep VirtualBox|grep xp的组合命令可以得到正在执行xp的虚拟机进程,其中xp是自己设定的虚拟机的标题,一般得到的结果会有2条,1条就是虚拟机进程,另1条是grep命令本身,所以当得到的结果只剩下grep命令本身时,说明虚拟机已经关闭。

由于我用的Linux发行版是Ubuntu,执行关机命令需要sudo并且输入密码,所以要让自动关机能够实现还有一步是,设定用户执行sudo不需要输入密码,这可以通过sudo visudosudoers文件进行修改,在文件最后加上chocobo ALL=(ALL) NOPASSWD: ALL其中chocobo是用户名。

好了,准备工作都做完,就可以执行脚本监视进程啦,具体代码如下:

#!/usr/bin/env python

import os
import time

def autohalt():
    while True:
        ps_string = os.popen('ps ax | grep VirtualBox | grep xp','r').read()
        ps_strings = ps_string.strip().split('\n')
        if len(ps_strings) < 2:
            os.system('sudo halt')
            return
        else:
            print 'Still',len(ps_strings),'Processes, waiting 10s...'
            time.sleep(10)

if __name__=='__main__':
    autohalt()

参考资料:

  1. http://docs.python.org/library/os.html#os.system
  2. http://docs.python.org/library/os.html#os.popen
  3. http://maestric.com/doc/unix/ubuntu_sudo_without_password

听豆瓣电台想到的推荐算法

无聊想听歌,尝试了下豆瓣电台,感觉“我喜欢”、“不再播放”、“跳过曲目”的设定很好,比虾米的评分、推荐、上标签更简洁,用户体验更好,通过这样3个用户行为就可以猜测用户的偏好。我不知道豆瓣后台具体的推荐算法是怎么样的,只能以自己的体验来猜测。

第一,我在“喜欢的歌手”里设置了一堆,不过开始听豆瓣电台连续放了n首都没有出现其中的歌手。难道是根据喜欢的歌手来猜测喜欢的曲风?但我设了很多日本歌手,开头几首没有一首是日语歌曲。。

第二,在我对一首歌点了“我喜欢”以后,后续会出现1到2首同一个歌手的歌曲。这个很符合常理,有时把我喜欢的几首歌连续放出了,不错。

第三,在我对东方神起的一首日语歌点了“跳过曲目”以后,后续出现了一首曲风差不多的其他日语歌。也许猜到了我只是不大喜欢听东方神起而已。。

虽然在听豆瓣电台时用户行为只有3种,但我觉得用户做出这3种行为的时间点也很重要,不知豆瓣电台的算法中是否有考虑。比如:

  1. 在歌曲一开始就点击了“我喜欢”,明显是用户耳熟能详的歌曲,对用户来说有一种怀旧的感觉,后续可以推荐“相关性”比较大的歌曲,如同一时期,或同一歌手,或其他有相关性的歌曲。
  2. 歌曲放了一段时间以后才点击“我喜欢”,可能是初次听了以后喜欢上的,后续可以继续推荐该歌手的歌曲,试探用户的喜好,若用户没有继续喜欢,或者直接跳过,那用户喜欢这个歌手的可能性就低了很多。
  3. 同时,“不再播放”的选择应该也是和“我喜欢”类似的。
  4. 至于“跳过曲目”,其实也是可以从时间点来反映一些问题的,有时候旋律的不断重复,会促使用户跳过,就像k歌时一样,但并不代表用户不喜欢这首歌,或这个歌手。

在写这篇blog的时候,因为对中岛美嘉的Orion(《流星之绊》主题曲)两个版本都评价了“我喜欢”,结果连续推荐了《求婚大作战》和《东京铁塔》的主题曲,不错。。另外提一点,虽然我知道这个是“电台”,但我还是想要个“暂停”功能。。。