Open cjuexuan opened 7 years ago
由于我司主要应用都是java,所以这一块的监控主要是对java程序的监控,我们设计的理念是对于用户metric的采集尽量的轻量级,这也是我们没有采用写固定目录,然后用flume传输的一个原因,我们的思路是将channel内嵌在代码里,因为如果依赖外部channel,那么部署上变得麻烦了很多,现有的所有接入监控系统的机器都需要安装agent,由于接入我们现在全部的大数据任务,整个流量还是比较大的,所以我们选择传输走一层mq,用mq还有一个好处是代码分离,模块划分更加清晰
最后的一个大概架构就是
app -> kafka -> spark streaming -> es (ttl 3day) -> play (analyze) | -> spark sql -> hdfs (parquet,partition by day)
这里的设计参考了下open-falcon
小米 open-falcon:
{ metric: net.port.listen, endpoint: open-falcon-host, tags: port=3306, value: 1, timestamp: `date +%s`, counterType: GAUGE, step: 60 }
footprint:
{ metric:jvm.gc.major.count labels :type=gc,idc=shanghai,endpoint=ctao-machine metricType: [Gauge/Delta/Cumnlative], valueType : [LongVal,DoubleVal,IntVal,StringVal] value : 1, timestamp: 'timestamp', domain: appName-appId }
其中metricType我们有三种,第一种就是瞬态值Gauge,第二种是差值Delta,第三种是计数器Cumulative,其中差值和计数器是可以相互转换的,因为有些监控场景中我们比较关心的是波动,有些监控场景中我们关心的是具体值对象,所以我们保留了这两种类型,可以根据业务部门的配置,在sparkStreaming中用mapWithState进行转换
Gauge
Delta
Cumulative
另外就是ValueType,我们增加了StringVal,这种数据类型主要是可以记录一些用户日志之类的,如果定成Number,其实在监控本身来说,会有很多的局限性,但我们要求的是StringVal,那么metricType一定要是Gauge
而domain这个字段,主要是区分一个监控的生命周期,比如对spark的离线任务来说,相同appName的任务太多了,但每个任务还会有一个appId,用这两个就可以唯一确定一个spark应用了,此时就有疑问了,那为啥不直接用appId呢,因为appId的可读性太差了,而且做同期任务对比的时候,我们可以模糊匹配,startWith appName就可以了
labels就是tags,比如你的应用也看full gc次数我的应用也看full gc次数,我们属于不同的service,也在不同的机器上,通过标签属性可以过滤到我们各自的监控域
endpoint,我们觉得这个字段其实是可以塞到labels上去,所以我们就没有额外加这个字段了
监控指标的特点就是量大,时效性高,而且有很多聚合统计,所以我们的思路是将最近三天的监控信息扔到es里面,ttl设置成3day,另外分析我们也不打算通过es做,我们可以用spark streaming在插入es之前去做聚合分析,然后es里面按照metric Type分开放,为啥要分开放呢,因为每种metric Type其实关心的点不一样,比如是一个Number 值类型的Gauge,我们需要关心的这段时间区间内的最大值,最小值和平均值,如果是String类型,那么对于时间区间而言,只能进行简单sample了,再比如对于Delta而言,我们需要在服务端维护上一个的状态,算一个差值,这样就需要分开设计最后的存储结构了
另外监控数据也蛮重要的,所以我们额外起一个离线任务对监控数据做一个backup,存成parquet格式,按天做分区
由于指标本身是无状态的,但分析的时候是有状态的,比如统计最近5分钟,xxx应用的full gc情况,统计最近一小时,xxx应用full gc情况,所以我们需要唯一的确定这个监控维度,那么唯一需要哪些东西呢,首先需要metric name,也就是metric,另外需要domain,最后我们需要labels,这三个才能唯一的确定一个监控维度,所以有了另外一个模型TSKey
现在我们支持的channel是kafka,kafka中有partition的概念,由于我们有key值,所以我们在发送的时候直接用TSKey的hashCode作为key,这样保证了相同Key的会落到同一个分区,也不需要自己去写partitioner,再绕一层了,而且由于模型固定,我们选择自己做序列化和反序列化,传输的时候是array byte,写入的时候对于int和long就用hadoop的Vint去写,整个实现还是比较高效的
监控系统可以方便业务开发很好的定位问题,所以这是我们这个系统的设计初衷,而spark,我们可以通过adapter,将spark的metric信息转换成我们的模型,进行统一的管理和处理
监控系统思路
由于我司主要应用都是java,所以这一块的监控主要是对java程序的监控,我们设计的理念是对于用户metric的采集尽量的轻量级,这也是我们没有采用写固定目录,然后用flume传输的一个原因,我们的思路是将channel内嵌在代码里,因为如果依赖外部channel,那么部署上变得麻烦了很多,现有的所有接入监控系统的机器都需要安装agent,由于接入我们现在全部的大数据任务,整个流量还是比较大的,所以我们选择传输走一层mq,用mq还有一个好处是代码分离,模块划分更加清晰
最后的一个大概架构就是
app -> kafka -> spark streaming -> es (ttl 3day) -> play (analyze) | -> spark sql -> hdfs (parquet,partition by day)
监控模型设计
这里的设计参考了下open-falcon
小米 open-falcon:
footprint:
其中metricType我们有三种,第一种就是瞬态值
Gauge
,第二种是差值Delta
,第三种是计数器Cumulative
,其中差值和计数器是可以相互转换的,因为有些监控场景中我们比较关心的是波动,有些监控场景中我们关心的是具体值对象,所以我们保留了这两种类型,可以根据业务部门的配置,在sparkStreaming中用mapWithState进行转换另外就是ValueType,我们增加了StringVal,这种数据类型主要是可以记录一些用户日志之类的,如果定成Number,其实在监控本身来说,会有很多的局限性,但我们要求的是StringVal,那么metricType一定要是
Gauge
而domain这个字段,主要是区分一个监控的生命周期,比如对spark的离线任务来说,相同appName的任务太多了,但每个任务还会有一个appId,用这两个就可以唯一确定一个spark应用了,此时就有疑问了,那为啥不直接用appId呢,因为appId的可读性太差了,而且做同期任务对比的时候,我们可以模糊匹配,startWith appName就可以了
labels就是tags,比如你的应用也看full gc次数我的应用也看full gc次数,我们属于不同的service,也在不同的机器上,通过标签属性可以过滤到我们各自的监控域
endpoint,我们觉得这个字段其实是可以塞到labels上去,所以我们就没有额外加这个字段了
存储设计
监控指标的特点就是量大,时效性高,而且有很多聚合统计,所以我们的思路是将最近三天的监控信息扔到es里面,ttl设置成3day,另外分析我们也不打算通过es做,我们可以用spark streaming在插入es之前去做聚合分析,然后es里面按照metric Type分开放,为啥要分开放呢,因为每种metric Type其实关心的点不一样,比如是一个Number 值类型的Gauge,我们需要关心的这段时间区间内的最大值,最小值和平均值,如果是String类型,那么对于时间区间而言,只能进行简单sample了,再比如对于Delta而言,我们需要在服务端维护上一个的状态,算一个差值,这样就需要分开设计最后的存储结构了
另外监控数据也蛮重要的,所以我们额外起一个离线任务对监控数据做一个backup,存成parquet格式,按天做分区
监控域的唯一性
由于指标本身是无状态的,但分析的时候是有状态的,比如统计最近5分钟,xxx应用的full gc情况,统计最近一小时,xxx应用full gc情况,所以我们需要唯一的确定这个监控维度,那么唯一需要哪些东西呢,首先需要metric name,也就是metric,另外需要domain,最后我们需要labels,这三个才能唯一的确定一个监控维度,所以有了另外一个模型TSKey
other
现在我们支持的channel是kafka,kafka中有partition的概念,由于我们有key值,所以我们在发送的时候直接用TSKey的hashCode作为key,这样保证了相同Key的会落到同一个分区,也不需要自己去写partitioner,再绕一层了,而且由于模型固定,我们选择自己做序列化和反序列化,传输的时候是array byte,写入的时候对于int和long就用hadoop的Vint去写,整个实现还是比较高效的
总结
监控系统可以方便业务开发很好的定位问题,所以这是我们这个系统的设计初衷,而spark,我们可以通过adapter,将spark的metric信息转换成我们的模型,进行统一的管理和处理