博文

目前显示的是 三月, 2012的博文

不用root安装rpm包

Update: 此路已经不通。在CentOS6及以上版本已经不能用了。最近上线了一个hadoop集群,但是苦于线上网络和办公网络不通,需要走跳板机中转,于是我就准备拿跳板机当编译、打包的平台。可惜跳板机上很多命令都没有,比如svn。跳板机是一个公用的机器,我并没有root权限。(准确来说,我不想通过不正当途径手段拥有)首先从collabnet下载编译好的rpm包:http://www.open.collab.net/downloads/subversion/然后登陆跳板机:$ mkdir -p $HOME/local/lib/rpm$ rpm --initdb --root $HOME/local --dbpath $HOME/local/lib/rpm$ rpm --root $HOME/local --dbpath $HOME/local/lib/rpm --relocate /opt=$HOME/local --nodeps -ivh CollabNetSubversion-client-1.7.4-1.x86_64.rpm最后打开.bash_profile修改环境变量:PATH=$PATH:$HOME/local/CollabNet_Subversion/binexport PATH
export LD_LIBRARY_PATH=$HOME/local/CollabNet_Subversion/lib:$LD_LIBRARY_PATH爽啊!!!

Hadoop Authentication

我被被派去做别的事情了,所以与hadoop相关的工作就只能搁下。写篇总结,把最近遇到的和kerberos相关的东西列一下。JAAS是Java 认证和授权服务(Java Authentication and Authorization Service)的缩写,是PAM框架的Java实现。
javax.sercurity.auth.Subject是一个不可继承的实体类,它表示单个实体的一组相关信息,与请求的来源相关。
javax.security.auth.Principal是一个接口,表示带有不同类型凭证的标识,基本上来说,Principal可以是任意对象。
JAAS的授权机制主要就是围绕着Subject和Principal。关于JAAS比较详细的参考是这里:http://docs.oracle.com/javase/6/docs/technotes/guides/security/jaas/JAASRefGuide.html
几个比较重要的java属性:
java.security.krb5.realm
java.security.krb5.kdc
java.security.krb5.confhadoop的身份认证和授权都是建立在JAAS之上。
hadoop.security.authentication属性有2种值:
simple: Security is disabled。
kerberos: Security is enabled。
org.apache.hadoop.security.UserGroupInformation有一个静态方法:getCurrentUser()。它会返回一个UserGroupInformation类的实例(以下简称UGI)。如果subject为空,或者这个subject中与org.apache.hadoop.security.User对应的Principal为空,那么说明尚未登录过,调用getLoginUser()创建UserGroupInformation的实例。
getLoginUser()的流程:
1.创建LoginContext:
LoginContext是由UserGroupInformation.newLoginContext(String, Subject)方法创建的。LoginContext的name有三种取值:hadoop-user-k…

sawzall中,"unknown type kind in type description string"的原因

最近遇到了一个奇怪的问题,在创建emitter的时候遇到“unknown type kind in type description string: sum”错误。这个问题是这样:emitters/szlbootstrapsumresults.cc这个文件编译后的代码在libszlemitters.so中,szlbootstrapsumresults.cc这个文件的末尾有一个宏REGISTER_SZL_RESULTS(bootstrapsum, SzlBootstrapsumResults);它展开后是一个类型为SzlResultsRegisterer的静态变量。这个类的构造函数的实现在szlresult.cc中。szlresult.cc中定义了这样一个静态变量:static SzlResultsCreators* creators;它在SzlResultsRegisterer的构造函数中会按需初始化,即,第一次调用SzlResultsRegisterer的时候,初始化creators这个静态变量。在creators未被初始化(即creators==NULL)的情况下,SzlResults::Properties函数无法工作,所以会直接返回false。这就导致SzlType::InitFromSzlProto无法工作,也就是说,无法从二进制数据反序列化得到SzlType对象。这个问题在于,链接器发现我要用到SzlResults这个类,所以把emitvalues/szlresults.cc所在的so(libszl.so)包含了进来。但是它没有发现emitvalues/szlresults.cc中的静态变量creators需要被libszlemitters.so中的代码初始化。当然,这不能怪gnu ld,这得怪库的作者没有考虑到这种情况?解决办法:这个问题不需要特别解决。因为我平时写代码喜欢边写边测试。所以只需要继续往下写,把剩下的代码写完即可。

hadoop yarn是如何控制内存使用量的?

最近在写一个统计程序,因为需要在两个表之间做join操作。于是我的想法就是,把较小的那个表,序列化成一个hadoop的SequenceFile,然后在Map/Reduce的阶段载入。这个SequenceFile其实也不大,就48MB,但是载入内存的时候至少需要1G内存,这让我很奇怪。hadoop默认情况下,每个child jvm只有200MB内存,于是我的这个jar在交给hadoop执行的时候,总是报告out of memory error。还好,这个默认值可以通过mapred.child.java.opts参数修改。我把它改成了1G。然后用ps命令看,确实在执行org.apache.hadoop.mapred.YarnChild这个类的时候,jvm的参数中有“ -Xmx1G”。但是悲剧的是,这个参数似乎没有被resource manager理解。它以为每个jvm只需要200MB的内存,于是就启动了很多个jvm。然后我的机器就因为物理内存不足,而频繁的在做swap in/swap out。接着,我把mapreduce.map.memory.mb和mapreduce.reduce.memory.mb这两个参数设置成2048,无任何好转。

以local方式运行hadoop pipes程序时遇到的问题

hadoop对map-reduce运行框架一共提供了3种实现,在mapred-site.xml中通过"mapreduce.framework.name”这个属性来设置为“classic”、“yarn”或者“local”。在classic模式中,任务是提交给jobtracker,它的地址通过“mapreduce.jobtracker.address”设置。而在yarn中,任务是提交给resource manager中的applications manager,它的地址是通过“yarn.resourcemanager.address”设置(在yarn-site.xml中)。所以如果想在本地使用mapreduce,那么把mapreduce.framework.name和mapreduce.jobtracker.address都设置成local就行了。如果连hdfs也不想启动,那么就fs.defaultFS也设置成"file:///”。但是hadoop pipes框架似乎没有在这种情况下做充分的测试,我遇到的问题如下:一. hadoop pipes在启动C++子进程之前,要写入一个jobTokenPassword文件。从tokencache中读入一个名为"ShuffleAndJobToken”的token,然后写入该文件中。但是问题是,在local模式下,tokencache中根本就木有这个token嘛。于是在这一步,就会抛异常,导致Application初始化失败。我的做法就是把byte[] password = jobToken==jobToken.getPassword(); 改成byte[] password = jobToken==null?"dummy".getBytes():jobToken.getPassword(); 绕过去。二. 紧接着一个问题是,这个文件是被创建在当前目录的,并且权限是0400。String localPasswordFile = new File(".") + Path.SEPARATOR + "jobTokenPassword"; 于是第二次启动Application的时候,它会尝试重写这个文件,但是因为没有写入权限,所以写不了。于是…

向hadoop提交C++程序

假如你有一个上千台的hadoop集群,那你肯定无法保证所有的机器都具有完全一样的操作系统版本。前文已经讲了如何让C/C++程序一次编译,在不同的Linux版本下运行。这里具体讲讲hadoop下的情况。要想在hadoop上运行C++程序,有两个接口,一个是老的hadoop streaming,不推荐使用。另外一个就是比较新的,hadoop pipes。一、分发动态链接库文件Hadoop提供了一个叫DistributedCache的东西,用来给map/reduce任务分发jar和动态链接库(以及其它的只读文件)。launch_container.sh在启动container的时候,一定会把当前工作目录加入到java.library.path和LD_LIBRARY_PATH中。那么怎么把文件扔到DistributedCache中呢?有两种办法。1.提交任务的时候,加上-files参数,然后填以逗号分割的本机的Unix路径。2.手动把文件复制到hdfs中,然后在任务的配置中加上mapred.cache.files属性,里面填以逗号分割的hdfs URL。这两个方法可以混用。但是此时有个问题,如果机器的数量特别多,任务启动的时候大家一起来找同一个机器要某个文件,那么就会堵住。好在hadoop一般会把一个文件存3份,如果机器数量特别多,那么就需要对这些so文件增大存的份数。二、设置ELF解释器但是就算把所有的第三方库的so都提交上去了,某些so必须要求特定版本的glibc才能工作。而libc.so的版本又必须和ld.so的版本匹配。所以,有两个办法在链接的时候加上–dynamic-linker ./ld-linux-x86-64.so.2在任务的配置中把mapreduce.pipes.executable.interpretor设置成”./ld-linux-x86-64.so.2 ”三、分发数据文件然后呢,你会发现光有so文件还不够,有些so文件还需要依赖于很多数据文件,而这些数据文件在目标机器上未必有。例如,ubuntu的glibc,在执行iconv_open函数的时候,需要去/usr/lib/x86_64-linux-gnu/gconv目录下读gconv的数据文件,而对于CentOS,则是在/usr/lib64/gconv目录下。还好有一个很重要的环境变量:GCONV_P…