2013年10 月月 发布的文章

mapreduce程序shell脚本运行跑多天数据

vprun.sh

sh vprun.sh 20130101 20130102

说明:参数为开始日期和结束日期,如果开始日期和结束日期是一样的话,那就是跑一天的数据

#!/bin/bash
#Filename: vprun.sh
ct=0
date=`date -d "${1} ${ct} days" +%Y%m%d`
while [[ ${2} > ${date} ]] || [[ ${2} == ${date} ]]
	do
		hadoop jar /home/yda/tianhailong/vp-0.0.1-SNAPSHOT.jar com.youku.vp.userindex.day.calculators.TDVUserVideoJoin -libjars /home/yda/tianhailong/json-lib-2.3-jdk15.jar,/home/yda/tianhailong/ezmorph-1.0.6.jar,/home/yda/tianhailong/kfs-0.3.jar,/home/yda/tianhailong/redis-0.0.1.jar,/home/yda/tianhailong/jedis-2.0.0.jar,/work/yda/video_profile/dataUtil.jar /commons/common_data/user/hive/tudou:/commons/common_data/t_dlord_info/hive:/commons/common_data/t_vuser/hive:/commons/common_data/video/hive/tudou /commons/web/vuser-video/$date/tudou $date
	let "ct += 1"
	date=`date -d "${1} ${ct} days" +%Y%m%d`
	done

Jackson和json-lib效率比较

Jackson 和 json-lib
这两个json工具转换json的效率差的不是一点半点的,Jackson转换9万条json的字符串基本上在毫秒级完成,而同样的字符串解析json-lib则需要400多秒;
所以Jackson适合解析大量数据;json-lib并不是一点优点都没有,在web系统中传递的数据都是“小数据”,使用json-lib方便在字符串和json之间转换;

利用redis的Sorted Set实现分页

redis命令:

ZADD key score member [[score member] [score member] ...]
ZRANGE key start stop [WITHSCORES]

练习下redis ZADD ZRANGE命令:

redis> ZADD myzset 1 "one"
(integer) 1redis> ZADD myzset 2 "two"
(integer) 1redis> ZADD myzset 3 "three"
(integer) 1redis> ZRANGE myzset 0 -1
1) "one"
2) "two"
3) "three"redis> ZRANGE myzset 2 3
1) "three"redis> ZRANGE myzset -2 -1
1) "two"
2) "three"redis>

如果明白了 这两个命令的含义,实际上分页的原理就已经弄明白了。
现在的场景是:
要进行分页的数据是以json的格式写在hdfs上的,每条记录中有createtime这个字段(2013-02-19 01:23:50),将其变成10位的时间戳,把时间戳作为score,就可以按照时间从早到晚来排列,start stop参数决定着分页的大小!
java客户端jedis对应的方法:
读取:

Set set = jedis.zrange("tv-videos_102599699", 0, 9);
for (Object str : set) {
     System.out.println(str);
}

返回的是有序的LinkedHashSet,而不是hashset
批量写入,而不是单条写入:

Pipeline pipeline = RedisCon.getJeidsConForPipLine();//getJeidsConForPipLine自定义函数
pipeline.zadd("tv-videos_"+key.toString(), Long.parseLong(str), jsonArray.getString(i));
pipeline.sync();

其他命令参考:http://www.redis.cn/commands/zrange.html

Flume日志系统

           Flume是Cloudera提供的一个高可用的,高可靠的,分布式的海量日志采集、聚合和传输的系统,Flume支持在日志系统中定制各类数据发送方,用于收集数据;同时,Flume提供对数据进行简单处理,并写到各种数据接受方(可定制)的能力。
          Flume最早是Cloudera提供的日志收集系统,目前是Apache下的一个孵化项目,Flume支持在日志系统中定制各类数据发送方,用于收集数据;同时,Flume提供对数据进行简单处理,并写到各种数据接受方(可定制)的能力 Flume提供了从console(控制台)、RPC(Thrift-RPC)、text(文件)、tail(UNIX tail)、syslog(syslog日志系统,支持TCP和UDP等2种模式),exec(命令执行)等数据源上收集数据的能力。
Flume采用了多Master的方式。为了保证配置数据的一致性,Flume[1]引入了ZooKeeper,用于保存配置数据,ZooKeeper本身可保证配置数据的一致性和高可用,另外,在配置数据发生变化时,ZooKeeper可以通知Flume Master节点。Flume Master间使用gossip协议同步数据。
这个和hadoop配合起来应该不错,后续研究下……

Java Thread State 相关术语

线程,有时被称为轻量级进程(Lightweight Process,LWP),是程序执行流的最小单元。
一个标准的线程由线程ID,当前指令指针(PC),寄存器集合和堆栈组成。另外,线程是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点在运行中必不可少的资源,但它可与同属一个进程的其它线程共享进程所拥有的全部资源。一个线程可以创建和撤消另一个线程,同一进程中的多个线程之间可以并发执行。由于线程之间的相互制约,致使线程在运行中呈现出间断性。线程也有就绪、阻塞和运行三种基本状态。每一个程序都至少有一个线程,若程序只有一个线程,那就是程序本身。
线程状态有:
1.死锁,Deadlock(重点关注)
2.执行中,Runnable
3.等待资源,Waiting on condition(重点关注)
4.等待获取监视器,Waiting on monitor entry(重点关注)
5.暂停,Suspended
6.对象等待中,Object.wait() 或 TIMED_WAITING
7.阻塞,Blocked(重点关注)
8.停止,Parked
Deadlock:死锁线程,一般指多个线程调用间,进入相互资源占用,导致一直等待无法释放的情况。
Runnable:一般指该线程正在执行状态中,该线程占用了资源,正在处理某个请求,有可能正在传递SQL到数据库执行,有可能在对某个文件操作,有可能进行数据类型等转换
Waiting on condition:等待资源,或等待某个条件的发生。具体原因需结合 stacktrace来分析。
如果堆栈信息明确是应用代码,则证明该线程正在等待资源。一般是大量读取某资源,且该资源采用了资源锁的情况下,线程进入等待状态,等待资源的读取。
又或者,正在等待其他线程的执行等。
如果发现有大量的线程都在处在 Wait on condition,从线程 stack看,正等待网络读写,这可能是一个网络瓶颈的征兆。因为网络阻塞导致线程无法执行。
一种情况是网络非常忙,几乎消耗了所有的带宽,仍然有大量数据等待网络读写;
另一种情况也可能是网络空闲,但由于路由等问题,导致包无法正常的到达。
另外一种出现 Wait on condition的常见情况是该线程在 sleep,等待 sleep的时间到了时候,将被唤醒。
 
Blocked:线程阻塞,是指当前线程执行过程中,所需要的资源长时间等待却一直未能获取到,被容器的线程管理器标识为阻塞状态,可以理解为等待资源超时的线程。
Waiting for monitor entry 和 in Object.wait():Monitor是 Java中用以实现线程之间的互斥与协作的主要手段,它可以看成是对象或者 Class的锁。每一个对象都有,也仅有一个 monitor。从下图1中可以看出,每个 Monitor在某个时刻,只能被一个线程拥有,该线程就是 “Active Thread”,而其它线程都是 “Waiting Thread”,分别在两个队列 “ Entry Set”和 “Wait Set”里面等候。在 “Entry Set”中等待的线程状态是 “Waiting for monitor entry”,而在 “Wait Set”中等待的线程状态是 “in Object.wait()”。
 

“选择”是一种病

发现自己什么都不懂,什么都想学,又什么都学不精,是不是一种病态?
这种面对无穷选择的无力感,我觉得是因为欲望,因为想学会一切的欲望。社会中学习和学校中学习是完全不一样的。没有人帮你选课程,也没有人帮你打分。同样也不要妄想拿到100分。有舍才有得!
《海上钢琴师》有一段经典台词:
”一部钢琴,从琴键开始,结束。你知道钢琴只有88个键。它们不是无限的。你才是无限的,在琴键上制作出的音乐是无限的。我喜欢这样,我活的惯。 你把我推到舷梯上然后扔给我一架有百万琴键的钢琴,百万千万的没有尽头的琴键,那是事实,max,它们没有尽头。那键盘是无限延伸的。然而如果琴键是无限的,那么在那架琴上就没有你能弹奏的音乐,你坐错了地方,那是上帝的钢琴。“
大千世界,知识无止境。面对无尽的知识不知从何学起,这种状态,与1900面对陆地生活的恐惧,是何其相似。因为生于陆地,才觉得陆地生活是何其正常又轻松;因为长于陆地,才学会如何摒弃、选择、归纳、遗忘。1900对陆地生活的恐惧感,是因为他终身生活在同一艘船上。
当你发现什么都不懂,什么都想学的时候,最先做的应该不是迷惘,而是庆幸。因为你的目光终于不再局限于船上,因为你发现了一片新大陆。
学校的教育,就像一艘封闭的大船。再大也是有限的,用不了多久就能看清。这种桎梏可能会深深的影响一生。大船停航,学习也就终结了。从船到陆地,从有限到无限,选择和遗忘是很珍贵的技能。有舍才有得!
“所罗门•舍雷舍夫斯基出生于1886年,俄国记者,记得发生过的所有事情。” 在一个实验中,研究人员给舍雷舍夫斯基出示了一张纸,上面写着一个拥有三十个字母和数字组成的复杂公式。然后他们把纸放在盒子里,将它封存十五年。当他们取出之后,舍雷舍夫斯基能够精确地回忆起来…舍雷舍夫斯基能够记起来,但他不能提取精髓。他记住了大量随机事实,但他不能将它们组织成重复性样式。最终他不能搞清隐喻、明喻、诗歌,甚至于复杂的句子。【1】
不能遗忘,是一件可怕的事。不会选择,是一件失败的事。因为1900不会选择,所以惧怕,所以止步。他已经习惯了88个钢琴键的有限世界,可以完全的掌握,然后在任意组合。然而面对陆地生活,他仍然沿用了有限世界的学习方法:全部掌握、任意组合。结果必然是不可能。
因此面对海量的知识,首先应当意识到学是学不完的,学了也会忘的。不知道如何选择的时候,付诸行动比选择更重要。不能一直犹豫,一直不迈出第一步,最终困死在船上。
总结一下:
1.有取舍之心,不能什么都学会,也就没必要什么都想学。这是一种心态,可以让你面对无穷选择的时候不会有犹豫、迷惘、恐惧这些负面情绪。
2.有时候付诸行动比选择更重要。学习尤为如此,作为新的开端,学习的状态比学什么更重要。很多知识要学一段时间才能发现兴趣,才知道是否有用。
什么都不懂,很正常,因为这是新的开始;什么都想学,是缺少取舍的心态,先开始学一个再说;什么都不精,学过几年才见分晓,一万小时才算精通。
有人会因为无法作出决定就推迟决定,然而实际上推迟决定是最差的决定 ,在推迟决定期间,时间悄悄流逝,你却没有任何一条路上的积累,白白浪费了时间。
如果你有一些钱不知道花在 A 还是 B 上,你先不作决定,没问题,因为钱还是你的,但如果你有一些时间,不知道花在 A 上还是 B 上,不行,因为过了这段时间,这段时间就不是你的了。【2】
最后推荐一文《学习的艺术》【3】,不要让学习停滞,坚持下去,这些焦虑将不复存在。
【1】 摘自《中国的创造力是如何被扼杀的》:译言网 | 中国的创造力是如何被扼杀的?
【2】 摘自刘未鹏的博客《不是书评 :「我是一只IT小小鸟」》:不是书评 :《我是一只IT小小鸟》
【3】 《学习的艺术》:学习的艺术 – 左岸读书_blog
http://www.zhihu.com/question/19778858/answer/12943046?utm_source=weibo&utm_medium=weibo_share&utm_content=share_answer&utm_campaign=share_button

数据库sharding(scale up to scale out)

sharding是将一个大数据库按照一定规则拆分成多个小数据库的一门技术.
当我们的应用数据量越来越多,访问量越来越大的时候,我们会作何选择?继续提升数据库服务器的性能还是采用一项技术让数据库平滑扩展?虽然伴随着服务器的更新换代,性能越来越好,更换更加豪华的服务器能暂时解决这个问题,但是无论是从花费和可控都无法让人满意。这时数据库sharding是一个更加可行的方案。
常用的sharding方案有以下几种,
1。按功能划分(垂直切分)
将不同功能相关的表放到不同的数据库中,譬如将用户管理相关表放到shard 1上,将blog相关表放到shard 2上。。。这样做的好处是非常直观,当需要用户列表时,我就到shard 1上获取。。。。这样也有一个问题,当某一部分的功能其数据量或性能要求超出了可控的范围,我们就需要继续对其进行深入的sharding。
2。按表中某一字段值的范围划分(水平切分)
当伴随着某一个表的数据量越来越大,以至于不能承受的时候,就需要对她进行进一步的切分。一种选择是根据key的范围来做切分,譬如userID为1-10000的放到shard 10上,userID为10000到20000的放到shanrd 11上。。。这样的扩展就是可预见的。另一种是根据某一字段值得来划分,譬如根据用户名的首字母,如果是a-d,就属于shard 20,e-h就属于shard 21。。。这样做也存在不均衡性,当某个范围超出了shard所能承受的范围就需要继续切分。还有按日期切分等等,
3。基于hash的切分
类似于memcached的key hash算法,一开始确定切分数据库的个数,通过hash取模来决定使用哪台shard。这种方法能够平均的来分配数据,但是伴随着数据量的增大,需要进行扩展的时候,这种方式无法做到在线扩容。每增加节点的时候,就需要对hash算法重新运算,数据需要重新割接。
4。基于路由表的切分
前面的几种方式都是跟据应用的数据来决定操作的shard,基于路由表的切分是一种更加松散的方法。它单独维护一张路由表,根据用户的某一属性来查找路由表决定使用哪个shard,这种方式是一种更加通用的方案。譬如我们在系统中维护一张表-(用户所属省-〉shard),这样每个用户我们知道是哪个省的,去路由表查找,就知道它所在的shard。因为每次数据操作的时候都需要进行路由的查找,所以将这些内容存储到一台独立cache上是一个非常好的方式,譬如memcached。这种切分的方式同时也带来了另一个好处,当需要增加shard的时候,可以在不影响在线应用的情况下来执行,当然这也跟应用程序的架构设计相关,你的设计必须适用这种增加。
虽然应用sharding会带来显而易见的好处,但是它也有一些固有的问题需要我们了解,这些问题大致分成以下几类,
1。shard的扩容
当当前的shard已经不能适用当前的应用需求时,就需要对shard数据库进行扩容,增加shard意味着需要对原有的shard数据进行迁移,这个过程是非常复杂,而且可能会导致数据的不一致(一边写、一边迁移)或者其他应用问题,因此扩容一般选择在凌晨等时间进行。
2。联合多个shard的表数据查询
这个是shard固有的问题,当遇到这样的问题时,你需要获取各个shard的数据,然后对这些数据进行汇总,很多时候因为现在的网络速度比较发达这个问题可以几乎被忽略掉。但是如果要进行数据的分析或挖掘,shard就会存在问题,通常面对这种对于数据要求不是那么实时的情况下,可以采用将shard数据同步到汇总数据库的方案,olap可以在这台汇总数据库上进行,这就需要在每台shard上进行数据的定时同步,这增加了程序的复杂性;如果要求实时的情况下,采用sharding方案会是一个毁灭性打击。
3。其他
我们现在做的系统就是采用的按照路由表切分的sharding方案,而且我们需要要求不是那么实时的汇总数据以提供数据的分析和挖掘,同时我们的基础数据都是在汇总数据库中进行管理,通过oracle的高级复制到shard节点上。在shard数据库向汇总数据库同步数据的时候,我们是通过oracle数据库的存储过程实现的,这种架构方式导致了数据库非常的复杂,同时还存在了一些其他问题,譬如同步会无缘无故的断掉。。。这就需要采用一些其他手段来维持数据的延迟一致性。
我们的sharding还在改进,我们的shard还在增加,我们还需要不断努力使我们的应用更加高效。
有时候觉得我们的社会就像一个巨大的多层sharding方案,中央、省(自治区)、市。。。
————————————————————-
还有一种数据库方案是master-slave,一台master主要负责数据的更新,然后通过高级复制等手段将数据复制到各个slave节点,slave节点负责查询。这种结构是不管master和slave都拥有全部的数据,master到slave的数据存在一定的延迟。可以跟sharding方案结合使用。
http://eddysheng.iteye.com/blog/461393

hadoop Task process exit with nonzero status of 126

通过分析hadoop 1.0.1代码,发现map/reduce task在执行的时候,hadoop系统会先把要执行的java 命令已经一些环境变量写到一个本地的sh文件taskjvm.sh中,然后使用bash -c file的方式执行这个sh脚本,如果出错当然后抛出异常,进而导致看到
Caused by: java.io.IOException: Task process exit with nonzero status of 126.
at org.apache.hadoop.mapred.TaskRunner.run(TaskRunner.java:258)
这样的错误
所以,这个exitcode实际就是bash执行时的推出代码,bash的exitcode是有特殊含义的,通过google可以知道126表明是permission的问题,具体为啥是这样的,不是很清楚了~~
上面的那个文件在创建的是权限是700(rwx——), 而这个文件在执行的过程中又被以setsid的方式exec,会不会这中间有些permission上的问题那~~~ 源码里说了,这样做是为了防止special character attacks
好吧水平有限,看不出来这里有什么竞争条件导致出现那样的错误
bash的退出码含义可以在下面的地方查到 http://tldp.org/LDP/abs/html/exitcodes.html
这个问题可以修改hadoop源码DefaultTaskControl加入重试机制,或者对task启用reuse=-1得到缓解(reuse和非reuse执行逻辑不一样),因为涉及到文件系统,不太容易根治。