Chukwa在百度的应用实践

从上一篇 chukwa 的简介中,我们知道 chukwa 为日志分析系统提供了一整套的解决方案,其中包含了数据的生成、收集、排序、去重、分析和展示所需要的几乎所有事情,要扩展 chukwa 以实现自己特殊的需求,是很方便的.本文以 chukwa-0.3.0 为例,阐述在 分布式小组内如何以 chukwa 为基础实现"资源状态图"。

概述需求
"资源状态图"的需求是很明确的,具体分析如下:

约束
原始数据采集自多个不同的 hadoop 集群
我们所使用的 hadoop 是基于官方版本修改过的,细节上与官方版本可能不同
功能需求
1. 保存和展示用户资源在各集群上的预算、当前使用情况和历史使用情况
2. 其中的“资源”包括存储空间、map槽位数和reduce槽位数
3. 资源的粒度为: 用户, 用户组,单个集群,所有集群
4. 保存和展示集群整个的存储、槽位、机器数、内存、文件数等等信息
5. 数据保存要完整,便于分析和统计
6. 数据展示要直观,方便看出变化趋势
用户需求
1. 集群使用者不能修改系统的数据和展示
2. 集群使用者可以单独关注自己的所有资源,需要它们都放在一起
3. 集群维护者可以修改系统的展示布局和增加数据项
4. 集群维护者关注单个集群的整体信息和所有集群的统计数据
从上述约束和需求来看:
1. 这是一个典型的数据分析和展示系统
2. 数据来自于 hadoop 集群
3. 可能需要存储海量的数据
4. 这些数据需要长久保存以供分析
5. 分析的结果需要多方面多维度展示
6. 需要动态地增加对新数据项的支持
基于以上分析, 确定此项目可以基于 chukwa 来实现.

设计与实现
既然 chukwa 本身已经全面支持 hadoop 的日志分析了,为什么还要作设计和实现呢?主要是两方面的原因:一方面,因为我们的修改后的 hadoop 版本在代码层面与 chukwa 不兼容,用直接修改 chukwa 配置的方法, chukwa 不能正常提供服务;另一方面,, 像用户和总有集群总和这类特殊的需求,是 chukwa 本身所没有的,需要对 chukwa 进行扩展.
下面就按照 chukwa 的架构图,从数据生命周期的各阶段来介绍所需要的工作.
 



数据生成
chukwa 提供了多种数据生成的接口,包括日志文件、命令执行结果、Socket等等,对于我们而言,最方便的接口当然是脚本的执行结果了, 所以在这里统一采用了 execAdaptor,直接读取脚本的执行结果. 在 initial_adaptors 文件中每行代表一个 adaptor, execAdaptor 的配置格式是这样的(单引号内的):'add org.apache.hadoop.chukwa.datacollection.adaptor.ExecAdaptor KK 60000 /home/chukwa/tailbin/hdfs_new.sh 0'
其中, 'add org.apache.hadoop.chukwa.datacollection.adaptor.ExecAdaptor' 是 execAdaptor 的固定格式, KK 是自定义的数据格式(由于我们的数据不是 chukwa 的默认支持数据,所以数据类型需要自定义,在简单数据一节,我们会介绍自定义数据类型的处理), 60000 代表这个脚本每多长时间执行一次,单位是毫秒(在 chukwa-0.4.0 里,这个单位好像又改成秒了,请特别注意), /home/chukwa/tailbin/hdfs_new.sh 是脚本的全路径, 这里也请注意
脚本要用全路径
脚本要有可执行权限
如果不是 shell 脚本,而是其它语言的脚本或C语言类的需要编译执行的程序,请用 shell 包装一层,否则可能出现脚本执行正常,但是 agent 收集不到数据的情况
最后的 0 代表数据偏移, 一般写 0 既可,除非是一个特殊大的文件需要续传时,才会用到.
另外,在这里需要提一下, chukwa-0.3.0 的 agent 有一个 bug, 就是在修改 initial_adaptors 的配置后,重启 agent, 新的配置不会生效.这是因为 agent 错误地读取了所配置的 log 目录里的 chukwa_agent_checkpointXX 文件(XX 是一个数字),这个文件里记录了当前的 adaptor 配置情况. 所以改配置的话,需要在重启 agent 时把这个文件删掉.

数据收集
chukwa 本身对于数据的收集工作已经作得足够好了,无论是在容错方面,还是在数据的"化零为整"方面,所以我们的工作就是部署 collectors 环境,并且把所有的 adaptor 和对应的端口放到所有 agents 的 conf/collectors 文件中.
这里需要注意的两点是:
在 collector 的 chukwa-collector-conf.xml 中需要配置下面两项:
<property>
<name>writer.hdfs.filesystem</name>
<value>hdfs://localhost:9000/</value>
<description>HDFS to dump to</description>
</property>
<property>
<name>chukwaCollector.http.port</name>
<value>9090</value>
<description>The HTTP port number the collector will listen on</description>
</property>
writer.hdfs.filesystem 请修改为要写入的集群的 hdfs 配置, chukwaCollector.http.port 强烈建议不要使用默认的 8080 端口,这个端口很可能已经被占用了.可以看到,我这边都是用的 9090.
在 agents 的 conf/collector 中需要写上所有 collectors 的机器名(或ip)和端口号,每行一个,例如(单引号内的): 'jx-hadoop-a000.jx.xxx.com:9090'

简单数据处理
对于 collectors 收集并推送到 hdfs 的数据,chukwa 通过周期性的 map/reduce 作业来进行处理,对于自定义的数据,需要自己来实现相应的 demux 接口,来作这一工作.具体而言
在 chukwa-demux-conf.xml 文件中,增加如下的数据类型和数据解析类的对应关系
<property>
<name>KK</name>
<value>org.apache.hadoop.chukwa.extraction.demux.processor.mapper.XgllCommon</value>
<description>Parser class for </description>
</property>
实现 org.apache.hadoop.chukwa.extraction.demux.processor.mapper.XgllCommon 这个 java 类, 具体地:
) 这个类需要 extends AbstractProcessor?
) 这个类的构造函数如下:
public XgllCommon() {
sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");
}
) 这个类需要实现 protected void parse(String recordEntry, OutputCollector?<ChukwaRecordKey, ChukwaRecord?> output, Reporter reporter) throws Throwable 这个方法. 具体细节可以参考org.apache.hadoop.chukwa.extraction.demux.processor.mapper.Df 这个类.
这样,我们自定义的数据就可以和 chukwa 默认的数据一样,分类进入合适的目录了,并且会有 archive 作业定期来合并相关记录,防止文件数变得太多.
在“资源状态图”的设计中,实现了一个通用的 (key/value) 集合数据类型,以方便加入新的数据

后期数据处理
数据进入到集群后,从使用上来讲,已经可以通过 mapre/reduce 作业或 pig 语言来处理这些数据了.为了让这些数据可以更方便地展示和查看, chukwa 还提供了数据的后期处理和展示功能,其中后期处理过程包含数据的析取和稀释,统一由 dbAdmin.sh 这个脚本来启动, 展示功能统一由 hicc 来实现.

数据的析取
chukwa 通过 mdl 语言来实现数据从集群到 mysql 数据库的析取,方便查询和展示. mysql 的数据库是通过 conf/database_create_tables.sql 这个脚本来建立 template_table 的,然后通过 template_table 来生成各时间段的表.所以需要在 database_create_tables.sql 这个文件里增加对自定义数据类型的表的 template 的定义. 然后在 dbAdmin.sh 启动之前, 在mysql 里 source database_create_tables.sql 就可以了.
对于自定义的数据类型,有了 demux 的处理后,还需要修改相应的 mdl 配置,让数据分类进到数据库中.还以上面提到的 KK 数据类型为例,需要在启动 dbAdmin.sh 的服务器上修改 conf/mdl.xml 中如下 4 类配置, 分别对应于"数据库表名""主键""数据库列和数据数据类型项的对应关系""数据析取周期(单位为分钟)":
<property>
<name>report.db.name.xgllcommon</name>
<value>xgllcommon</value>
<description></description>
</property>

<property>
<name>report.db.primary.key.xgllcommon</name>
<value>timestamp,item_key</value>
<description></description>
</property>

<property>
<name>metric.xgllcommon.item</name>
<value>item_key</value>
<description></description>
</property>

<property>
<name>metric.xgllcommon.value</name>
<value>item_value</value>
<description></description>
</property>

<property>
<name>consolidator.table.xgllcommon</name>
<value>5,30,180,720</value>
</property>

数据的稀释
显然,如果所有的数据都放在数据库中,数据量是巨大的,所以,chukwa 只在集群上保存了所有最原始的数据,而数据库中的数据是按时间稀释的,即时间越久,数据的精度越低,而对于最近一周的数据,则完全保留。这里的数据稀释方 式是通过启动 dbAdmin.sh 的服务器上的 conf/aggregator.sql 来配置的, 可以参照其中的配置改一下自定义数据类型的稀释方式,例如上面提到的 KK 数据类型的稀释方式如下:
replace into [xgllcommon_month] (select FROM_UNIXTIME(floor(avg(UNIX_TIMESTAMP(timestamp))/900) * 900), item_key, a
vg(item_value) from [xgllcommon_week] where timestamp between '[past_15_minutes]' and '[now]' group by item_key, fl
oor((UNIX_TIMESTAMP(timestamp))/900));
replace into [xgllcommon_quarter] (select FROM_UNIXTIME(floor(avg(UNIX_TIMESTAMP(timestamp))/5400) * 5400), item_ke
y, avg(item_value) from [xgllcommon_week] where timestamp between '[past_90_minutes]' and '[now]' group by item_ke
y, floor((UNIX_TIMESTAMP(timestamp))/5400));
replace into [xgllcommon_year] (select FROM_UNIXTIME(floor(avg(UNIX_TIMESTAMP(timestamp))/32400) * 32400), item_key
, avg(item_value) from [xgllcommon_week] where timestamp between '[past_540_minutes]' and '[now]' group by item_ke
y, floor((UNIX_TIMESTAMP(timestamp))/32400));
replace into [xgllcommon_decade] (select FROM_UNIXTIME(floor(avg(UNIX_TIMESTAMP(timestamp))/129600) * 129600), item
_key, avg(item_value) from [xgllcommon_week] where timestamp between '[past_2160_minutes]' and '[now]' group by ite
m_key, floor((UNIX_TIMESTAMP(timestamp))/129600));
这里需要注意的一点是, 如果需要对时间有精确的控制,可以考虑上面的 floor 的作法,把时间点精确"对齐", 否则在使用 a = b 这样的 sql 查询时,会出现找不到数据的情况.

数据的展示
chukwa 提供了多种数据展示方式,但是仍不足以满足“资源状态图”的需求,于是我们又开发实现了“单个数据类型的多曲线图”“让时间段对比的多曲线图”“按用户分 类的数据展示”等等展示方式,并实现了简单的用户权限划分, 这里主要是 jsp 和 javascript 相关的技术应用,具体细节不再详述.

效果和收益
资源状态图的最终效果如下图
 



此项目在完成预期完成功能之外,还实现了如下收益:
1. 组内集群状态总结,只需要看一下页面就所有数据都有了,时间大大减少
2. 历史数据可以用于新一轮的集群预算
3. 集群的新项目可以依托 chukwa 框架,直接省去数据采集存储相关的考虑
4. 用户和集群维护者都对集群的运行情况一目了然

tips
在设计和开发中发现,chukwa 本身其实文档很不全面,有很多地方需要注意,以下 tips 可以让刚刚开始使用 chukwa 的开发者少走很多弯路。
1. adaptor 的采集时间间隔,文档中说单位是秒,实际单位是毫秒
2. mysql 的配置中,建议使用 large.my 的配置,或者是 huge.my 的配置
3. mysql 的配置中,socket 的位置和数据的存放位置,建议不要放在 /tmp 目录下,因为的 /tmp 目录可能会定期清空,危险
4. 当 hadoop 版本和 chukwa 版本不是相匹配时, 需要在 chukwa-env.sh 中明确指定 export HADOOP_JAR=${CHUKWA_HOME}/hadoopjars/hadoop-0.20.0-core.jar, 否则 agent 不能启动
5. adaptor 重启时,需要删除 /tmp/chukwa 下的 checkpoint 文件,否则相关配置不会重新读取
6. demux 中分析用的是硬编码的偏移量,需要多次测试,或者可以有更好的解析办法
7. 当数据类型中有多个项作主键时,chukwa 本身的 postProcess 存在 bug, 需要修正
最后,祝各位使用愉快.

 

【本文首发于: 百度运维空间http://hi.baidu.com/ops_bd/blog/item/7dd0d6374675e08aa8018e31.html
关注百度技术沙龙

你可能感兴趣的:(百度,应用,实践,休闲,chukwa)