半夜ATM机前看书的那位

导航

hadoop状态分析系统chukwa和在百度的应用实践(转)

Apache 的开源项目 hadoop, 作为一个分布式存储和计算系统,已经被业界广泛应用。很多大型企业都有了各自基于 hadoop 的应用和相关扩展。当 1000+ 以上个节点的 hadoop 集群变得常见时,集群自身的相关信息如何收集和分析呢?针对这个问题, Apache 同样提出了相应的解决方案,那就是 chukwa。

概述 
chukwa 的官方网站是这样描述自己的: chukwa 是一个开源的用于监控大型分布式系统的数据收集系统。这是构建在 hadoop 的 hdfs 和 map/reduce 框架之上的,继承了 hadoop 的可伸缩性和鲁棒性。Chukwa 还包含了一个强大和灵活的工具集,可用于展示、监控和分析已收集的数据。
在一些网站上,甚至声称 chukwa 是一个“日志处理/分析的full stack solution”。

说了这么多,你心动了吗?
我们先来看看 chukwa 是什么样子的: 

 

chukwa 不是什么
1. chukwa 不是一个单机系统. 在单个节点部署一个 chukwa 系统,基本没有什么用处. chukwa 是一个构建在 hadoop 基础上的分布式日志处理系统.换言之,在搭建 chukwa 环境之前,你需要先构建一个 hadoop 环境,然后在 hadoop 的基础上构建 chukwa 环境,这个关系也可以从稍后的 chukwa 架构图上看出来.这也是因为 chukwa 的假设是要处理的数据量是在 T 级别的.
2. chukwa 不是一个实时错误监控系统.在解决这个问题方面, ganglia,nagios 等等系统已经做得很好了,这些系统对数据的敏感性都可以达到秒级. chukwa 分析的是数据是分钟级别的,它认为像集群的整体 cpu 使用率这样的数据,延迟几分钟拿到,不是什么问题.
3. chukwa 不是一个封闭的系统.虽然 chukwa 自带了许多针对 hadoop 集群的分析项,但是这并不是说它只能监控和分析 hadoop.chukwa 提供了一个对大数据量日志类数据采集、存储、分析和展示的全套解决方案和框架,在这类数据生命周期的各个阶段, chukwa 都提供了近乎完美的解决方案,这一点也可以从它的架构中看出来.

chukwa 是什么
上一节说了很多 chukwa 不是什么,下面来看下 chukwa 具体是干什么的一个系统呢?
具体而言, chukwa 致力于以下几个方面的工作:
1. 总体而言, chukwa 可以用于监控大规模(2000+ 以上的节点, 每天产生数据量在T级别) hadoop 集群的整体运行情况并对它们的日志进行分析
2. 对于集群的用户而言: chukwa 展示他们的作业已经运行了多久,占用了多少资源,还有多少资源可用,一个作业是为什么失败了,一个读写操作在哪个节点出了问题.
3. 对于集群的运维工程师而言: chukwa 展示了集群中的硬件错误,集群的性能变化,集群的资源瓶颈在哪里.
4. 对于集群的管理者而言: chukwa 展示了集群的资源消耗情况,集群的整体作业执行情况,可以用以辅助预算和集群资源协调.
5. 对于集群的开发者而言: chukwa 展示了集群中主要的性能瓶颈,经常出现的错误,从而可以着力重点解决重要问题.

基本架构
有了一个感性的认识后,我们来看下它的构架, chukwa 的整体结构图是下面这个样子的:
 

其中主要的部件为:
1. agents : 负责采集最原始的数据,并发送给 collectors
2. adaptor : 直接采集数据的接口和工具,一个 agent 可以管理多个 adaptor 的数据采集
3. collectors 负责收集 agents 收送来的数据,并定时写入集群中
4. map/reduce jobs 定时启动,负责把集群中的数据分类、排序、去重和合并
5. HICC 负责数据的展示

相关设计
adaptors 和 agents
在每个数据的产生端(基本上是集群中每一个节点上), chukwa 使用一个 agent 来采集它感兴趣的数据,每一类数据通过一个 adaptor 来实现, 数据的类型(DataType?)在相应的配置中指定. 默认地, chukwa 对以下常见的数据来源已经提供了相应的 adaptor : 命令行输出、log 文件和 httpSender等等. 这些 adaptor 会定期运行(比如每分钟读一次 df 的结果)或事件驱动地执行(比如 kernel 打了一条错误日志). 如果这些 adaptor 还不够用,用户也可以方便地自己实现一个 adaptor 来满足需求。

为防止数据采集端的 agent 出现故障,chukwa 的 agent 采用了所谓的 ‘watchdog’ 机制,会自动重启终止的数据采集进程,防止原始数据的丢失。
另一方面, 对于重复采集的数据, 在 chukwa 的数据处理过程中,会自动对它们进行去重. 这样,就可以对于关键的数据在多台机器上部署相同的 agent,从而实现容错的功能.
collectors
agents 采集到的数据,是存储到 hadoop 集群上的. hadoop 集群擅长于处理少量大文件,而对于大量小文件的处理则不是它的强项,针对这一点,chukwa 设计了 collector 这个角色,用于把数据先进行部分合并,再写入集群,防止大量小文件的写入。
另一方面,为防止 collector 成为性能瓶颈或成为单点,产生故障, chukwa 允许和鼓励设置多个 collector, agents 随机地从 collectors 列表中选择一个 collector 传输数据,如果一个 collector 失败或繁忙,就换下一个 collector. 从而可以实现负载的均衡,实践证明,多个 collector 的负载几乎是平均的.
demux 和 archive
放在集群上的数据,是通过 map/reduce 作业来实现数据分析的. 在 map/reduce 阶段, chukwa 提供了 demux 和 archive 任务两种内置的作业类型.
demux 作业负责对数据的分类、排序和去重. 在 agent 一节中,我们提到了数据类型(DataType?)的概念.由 collector 写入集群中的数据,都有自己的类型. demux 作业在执行过程中,通过数据类型和配置文件中指定的数据处理类,执行相应的数据分析工作,一般是把非结构化的数据结构化,抽取中其中的数据属性.由于 demux 的本质是一个 map/reduce 作业,所以我们可以根据自己的需求制定自己的 demux 作业,进行各种复杂的逻辑分析. chukwa 提供的 demux interface 可以用 java 语言来方便地扩展.
而 archive 作业则负责把同类型的数据文件合并,一方面保证了同一类的数据都在一起,便于进一步分析, 另一方面减少文件数量, 减轻 hadoop 集群的存储压力。
dbadmin
放在集群上的数据,虽然可以满足数据的长期存储和大数据量计算需求,但是不便于展示.为此, chukwa 做了两方面的努力:
1. 使用 mdl 语言,把集群上的数据抽取到 mysql 数据库中,对近一周的数据,完整保存,超过一周的数据,按数据离现在的时间长短作稀释,离现在越久的数据,所保存的数据时间间隔越长.通过 mysql 来作数据源,展示数据.
2. 使用 hbase 或类似的技术,直接把索引化的数据在存储在集群上
到 chukwa 0.4.0 版本为止, chukwa 都是用的第一种方法,但是第二种方法更优雅也更方便一些.
hicc
hicc 是 chukwa 的数据展示端的名字.在展示端, chukwa 提供了一些默认的数据展示 widget,可以使用“列表”、“曲线图”、“多曲线图”、“柱状图”、“面积图式展示一类或多类数据,给用户直观的数据趋势展示。而且,在 hicc 展示端,对不断生成的新数据和历史数据,采用 robin 策略,防止数据的不断增长增大服务器压力,并对数据在时间轴上“稀释”,可以提供长时间段的数据展示
从本质上, hicc 是用 jetty 来实现的一个 web 服务端,内部用的是 jsp 技术和 javascript 技术.各种需要展示的数据类型和页面的局都可以通过简直地拖拽方式来实现,更复杂的数据展示方式,可以使用 sql 语言组合出各种需要的数据.如果这样还不能满足需求,不用怕,动手修改它的 jsp 代码就可以了.
其它数据接口
如果对原始数据还有新的需要,用户还可以通过 map/reduce 作业或 pig 语言直接访问集群上的原始数据,以生成所需要的结果。chukwa 还提供了命令行的接口,可以直接访问到集群上数据。
默认数据支持
对于集群各节点的cpu使用率、内存使用率、硬盘使用率、集群整体的 cpu 平均使用率、集群整体的内存使用率、集群整体的存储使用率、集群文件数变化、作业数变化等等 hadoop 相关数据,从采集到展示的一整套流程, chukwa 都提供了内建的支持,只需要配置一下就可以使用.可以说是相当方便的.
可以看出,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, 需要修正
最后,祝各位使用愉快。

 

posted on 2011-08-18 13:25  zhizhesky  阅读(1168)  评论(0编辑  收藏  举报