微信搜索lxw1234bigdata | 邀请体验:数阅–数据管理、OLAP分析与可视化平台 | 赞助作者:赞助作者

记录一下互联网日志实时收集和实时计算的简单方案

大数据平台 lxw1234@qq.com 55027℃ 10评论

关键字:日志、实时收集、实时计算

作为互联网公司,网站监测日志当然是数据的最大来源。我们目前的规模也不大,每天的日志量大约1TB。后续90%以上的业务都是需要基于日志来完成,之前,业务中对实时的要求并不高,最多也就是准实时(延迟半小时以上),因此,我们使用Flume将数据收集到HDFS,然后进行清洗和分析。

后来,根据业务需要,我们有了两个Hadoop集群,并且部署在不同的地方(北京和西安),而所有的日志收集服务器在北京,因此需要将日志数据通过外网传输到西安,于是有了这样的部署:

日志收集

很快,通过Flume流到西安Hadoop集群的数据就遇到了问题,比原始数据多或者少一些,造成这个问题的主要原因是在网络不稳定的情况下,北京Flume Agent发送到西安Flume Collector的过程中,会发送失败,或者响应失败。另外,之前的数据准实时也不能满足业务的需求。

为了解决数据实时跨外网传输以及实时业务的问题,于是有了现在的架构:

实时计算

  1. 引入Kafka,并且和日志收集服务器部署在北京同机房;
  2. 每台日志收集服务器上的Flume Agent,通过内网将数据发送至Kafka;
  3. Kafka的第一个消费者,北京网关机上的Flume,负责从Kafka中消费数据,然后流到北京Hadoop集群;
  4. Kafka的第二个消费者,西安网关机上的Flume,负责从Kafka中消费数据,然后流到西安Hadoop集群;这里是西安的Flume通过外网连接北京Kafka,主动拉取数据,如果网络不稳定,那么当前批次拉取失败,最多重新拉一次,数据不会进Flume channel,更不会流到HDFS上,因此,这种方式在网络不稳定的情况下,不会造成数据缺失或重复;
  5. Kafka的第三个消费者,北京网关机上的实时计算模块,后面再说;
  6. Kafka的第N个消费者,其他;

Kafka中的数据分区及副本

这种架构下,Kafka成为了统一的日志数据提供者,至关重要。我们目前有4台Broker节点,每个Topic在创建时候都指定了4个分区,副本数为2;

数据在进入Kafka分区的时候,使用了Flume的拦截器,从日志中提取用户ID,然后通过HASH取模,将数据流到Kafka相应的分区中。这种方式,一方面,完成了简单的负载均衡,另一方面,确保相同的用户数据都处于同一个分区中,为后面实时计算模块的统计提供了极大的便利。

Flume拦截器的使用

在整个流程中,有两个地方用到了同一个Flume拦截器(Regex Extractor Interceptor),就是在Flume Source中从消息中提取数据,并加入到Header,供Sink使用;

  • 一处是在LogServer上部署的Flume Source,它从原始日志中提取出用户ID,然后加入到Header中,Flume Sink(Kafka Sink)再入Kafka之前,从Header中拿出该用户ID,然后通过应用分区规则,将该条消息写入Kafka对应的分区中;
  • 另外一处是部署在西安的Flume Source,它从Kafka中读取消息之后,从消息中抽取出时间字段,并加入到Header中,后面的Flume Sink(HDFS Sink)通过读取Header中时间,根据消息中的时间,将数据写入HDFS相应的目录和文件中。如果在HDFS Sink中仅仅使用当前时间来确定HDFS目录和文件名称,这样会造成一小部分数据没有写入到正确的目录和文件中,比如:日志中8点59分59秒的数据可能会被写进HDFS上9点的目录和文件中,因为原始数据经过Kafka,通过外网传输到西安的Flume,有个几秒的延时,那是很正常的。

Flume消费者的负载均衡和容错

在北京部署的Flume,使用Kafka Source从Kafka中读取数据流向北京Hadoop集群,西安的也一样,在消费同一Topic的消息时候,我们都是在两台机器上启动了两个Flume Agent,并且设置的统一消费组(group.id),根据Kafka相同的Topic,一条消息只能被同一消费组内的一个消费者消费,因此,Kafka中的一条消息,只会被这两个Flume Agent其中的一个消费掉,如果一个Flume Agent挂掉,那么另外一个将会消费所有消息;

这种方式,也是在流向HDFS的消费者端做了负载均衡和容错。

实时计算模块

目前我们实时计算的业务比较简单,就是类似于根据不同维度统计PV和UV。比如:实时统计一个网站当天累计PV、UV、IP数等,目前我们直接开发的JAVA程序,使用streamlib统计这些指标,UV和IP数这种需要去重的指标有2%以内的误差,业务可以接受。

实时计算

实时计算模块使用Kafka low-level API,针对每一个Topic,都使用和分区数相等的线程去处理,每个线程消费一个分区的数据,由于数据在进入Kafka分区的时候,都是经过相应规则的分区,因此相同用户的数据会在同一个分区中;

另外,每个线程会在Redis中维护自己当前的Offsets,比如:在实时计算当天累计指标的业务场景中,每天0天在Redis中记录当前的Offsets,这样,如果实时计算程序挂掉,下次启动时候,从Redis中读取当天的Offsets,重新读取和计算当天的所有消息。

由于我们的需求是实时统计当天累计的指标,而且能接受一定的误差,因此采用这种方式。如果需要精确统计累计去重指标,那么可能需要采用其它方式,比如:精确统计当天实时累计用户数,一种简单的办法是在HBase中使用计数器来配合完成。

其它实时数据消费者

如果需要实时统计一小段时间(比如十分钟、一小时)之内的PV、UV等指标,那么可以使用SparkStreaming来完成,比较简单。如果单独使用Spark Streaming来完成一天内海量数据的累计去重统计,我还不太清楚有什么好的解决办法。

另外,实时OLAP也可能作为Kafka的实时消费者应用,比如:Druid。

相关阅读

Kafka分区机制介绍与示例
Kafka架构和原理深度剖析
利用Flume拦截器(interceptors)实现Kafka Sink的自定义规则多分区写入
Java使用极小的内存完成对超大数据的去重计数,用于实时计算中统计UV
Druid.io实时OLAP数据分析存储系统介绍

就这么多吧,很多东西都是初次尝试,肯定有很多不足之处,慢慢探索吧。

您可以关注 lxw的大数据田地 ,或者 加入邮件列表 ,随时接收博客更新的通知邮件。

 

如果觉得本博客对您有帮助,请 赞助作者

转载请注明:lxw的大数据田地 » 记录一下互联网日志实时收集和实时计算的简单方案

喜欢 (49)
分享 (0)
发表我的评论
取消评论
表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
(10)个小伙伴在吐槽
  1. 第一时间阅读,顺便占个沙发。 请问楼主大牛,单独使用kafka+spark可以实现日志实时分析吗?
    郭国钊2015-11-27 15:48 回复
    • 当然可以,只要有生产者实时将日志发送到Kafka,SparkStreaming就可以实时消费并分析。
      lxw1234@qq.com2015-11-27 16:11 回复
      • 我们这边主要是java程序及spark程序,采用log4j写日志,目前日志都是各应用写各自的。 咨询下专家:log4j是否可以直接将日志推送到kafka呢?
        过过招2015-11-27 16:29 回复
        • Kafka 自带了 Log4j appender,配置一下,将日志发送至Kafka,完全可行。
          lxw1234@qq.com2015-11-27 16:56 回复
  2. 受益匪浅!博主,请问flume日志采集您使用tail命令,还是其他方法?我用tail经常会丢包等问题,非常感谢!
    zjj072015-12-03 11:19 回复
  3. 已经看到您前面的tailDirSource,问题解决了,看看源码先,谢谢!
    zjj072015-12-03 11:24 回复
  4. 如果有跨机房通过公网访问 kafka 的情况时,需要指定 advertised.host.name ,不然好像访问不通。
    罗最帅2016-01-04 11:29 回复
  5. spark统计一天的去重数据用spark+redis做缓存去重效率不知道咋样。只简单搭过环境,没到生产环境实战过
    泰格2016-01-26 15:33 回复
  6. 如果单独使用Spark Streaming来完成一天内海量数据的累计去重统计,我还不太清楚有什么好的解决办法 请问现在有什么好方法吗
    欲风2017-08-22 22:10 回复
  7. 您好,请问flume collector是什么呢,使用flume为什么会有数据丢失的问题呢,数据重复是因为网络环境不稳导致响应失败,flume重新发送导致的吗,您能详细说下吗,谢谢 :roll:
    hgdhot2018-06-12 17:32 回复