离线日志采集统计分析

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_28844767/article/details/84313879

项目中数据采集:
flume
ELK(ElasticSearch logstash kibana)
搜索引擎 日志采集 数据分析可视化平台

在使用flume时,最注重的是数据的安全性,所以一般情况下channle=file
flume集群中汇总多个flume的日志信息,前一个flume的sink是avro序列化数据下沉。
问题:
agent1和agent2要解决一个问题:采集的数据有多种类型,如何区分?
因为在给下游传递的过程中是混在一起的,所以为了分类进行存储,需要为数据做标记,使用拦截器interceptor为每一条flume的记录(一个flume event【header, body】)在header中添加一个自定义的属性(key-value键值对)

#通过flume采集access、ugchead、ugctail日志


a1.sources = access ugchead ugctail
a1.sinks = k1 k2
a1.channels = c1

# 配置source 
a1.sources.access.type = exec
a1.sources.access.command = tail -F /home/hadoop/logs/data-clean/data-access.log
a1.sources.access.interceptors = i1 i2
a1.sources.access.interceptors.i1.type = static
# 静态的在header中添加一个key value
a1.sources.access.interceptors.i1.key = type
a1.sources.access.interceptors.i1.value = access
# 对于hdfs-sink,对于所有与时间相关的转义序列,
# 事件标题中必须存在带有“timestamp”键的标头
#(除非hdfs.useLocalTimeStamp设置为true)。
# 自动添加此方法的一种方法是使用TimestampInterceptor。
# 所以我们这边设置一个TimestampInterceptor
a1.sources.access.interceptors.i2.type = timestamp


a1.sources.ugchead.type = exec
a1.sources.ugchead.command = tail -F /home/hadoop/logs/data-clean/data-ugchead.log
a1.sources.ugchead.interceptors = i1 i2
a1.sources.ugchead.interceptors.i1.type = static
# 静态的在header中添加一个key value
a1.sources.ugchead.interceptors.i1.key = type
a1.sources.ugchead.interceptors.i1.value = ugchead
a1.sources.ugchead.interceptors.i2.type = timestamp

a1.sources.ugctail.type = exec
a1.sources.ugctail.command = tail -F /home/hadoop/logs/data-clean/data-ugctail.log
a1.sources.ugctail.interceptors = i1 i2
a1.sources.ugctail.interceptors.i1.type = static
# 静态的在header中添加一个key value
a1.sources.ugctail.interceptors.i1.key = type
a1.sources.ugctail.interceptors.i1.value = ugctail
a1.sources.ugctail.interceptors.i2.type = timestamp



# 对于sink的配置描述 使用avro日志做数据的消费
# a1.sinks.k1.type = logger
# a1.sinks.k1.type = avro
# a1.sinks.k1.hostname = hadoop03
# a1.sinks.k1.port = 44444

#define sinkgroups  此处配置k1、k2的组策略,类型为均衡负载方式  
# a1.sinkgroups=g1  
# a1.sinkgroups.g1.sinks=k1 k2  
# a1.sinkgroups.g1.processor.type=load_balance  
# a1.sinkgroups.g1.processor.backoff=true  
# a1.sinkgroups.g1.processor.selector=round_robin

#define sinkgroups  此处配置k1、k2的组策略,类型为Failover
a1.sinkgroups = g1
a1.sinkgroups.g1.sinks = k1 k2
a1.sinkgroups.g1.processor.type = failover
a1.sinkgroups.g1.processor.priority.k1 = 5
a1.sinkgroups.g1.processor.priority.k2 = 10
a1.sinkgroups.g1.processor.maxpenalty = 10000

a1.sinks.k1.type = avro
a1.sinks.k1.hostname = hadoop02
a1.sinks.k1.port = 44444

a1.sinks.k2.type = avro
a1.sinks.k2.hostname = hadoop03
a1.sinks.k2.port = 44444


# 对于channel的配置描述 使用文件做数据的临时缓存 这种的安全性要高
a1.channels.c1.type = file
a1.channels.c1.checkpointDir = /home/hadoop/data/flume/data-clean/checkpoint
a1.channels.c1.dataDirs = /home/hadoop/data/flume/data-clean/data


# 通过channel c1将source r1 r2 r3 和sink k1 关联起来
a1.sources.access.channels = c1
a1.sources.ugchead.channels = c1
a1.sources.ugctail.channels = c1
a1.sinks.k1.channel = c1
a1.sinks.k2.channel = c1

问题:
1、Flume source has been removed due to an error in configuration
中文含义: Flume的source部分因为配置异常被移除。
表象: Flume中source没有启动。
解决办法:查看上下文,查看诸如java.lang.IllegalStateException: The parameter command must be specified类似的具体异常,具体定位问题。(一般是配置文件或者自定义source未写正确导致,可以try-catch捕获处理某些异常。)

2、拦截器
timestamp问题:
对于hdfs-sink,对于所有与时间相关的转义序列,事件标题中必须存在带有“timestamp”键的标头(除非hdfs.useLocalTimeStamp设置为true)。自动添加此方法的一种方法是使用TimestampInterceptor。
所以我们这边设置一个TimestampInterceptor。
详细参考:flume官网中hdfs-sink
3、执行监听日志文件中的新增记录,操作异常:
java.lang.OutOfMemoryError: GC overhead limit exceeded,简称OOM/OOME
两种方案解决:
第一种方案: 给该flume程序加大内存存储容量
默认值为 -Xmx20m(最大堆内存大小) --> -Xmx2000m
-Xms10(初始堆内存大小)
第二种方案:第一种搞不定的时候,比如机器可用内存不够的时候,使用其它channel解决
比如:磁盘文件,jdbc等
详细参考:flume官网中的flume-channels

在实现flume的HA的过程中,使用failover sink时,发现在设置多个sink的优先级的时候,没有效果,理论上是只要有优先级高的sink去下沉到HDFS,优先级低的不启用,但是,在实际测试中发现,两个sink里面都有写入数据。。。
理论上应该是只有一个临时文件

ETL(extract transform loading)
数据仓库:设计

清楚最终的效果
数据的清洗
框架:
数据清洗使用的框架:
MR、Hive、Sparkcore
原始数据 --------》标准化的数据 :
判断数据字段:是否需要脱敏(映射),是否需要删除,可不可以衍生
如:ip可以转换—》省市,基于地域维度进行数据的统计(问题在于如何通过ip得到省市)
request(请求方法,请求地址,请求协议)
status,appid,userid,mid,login_type,http_referer,user_agent,time

数据分析模块:
次日留存率:
如何计算?
要计算出今日和昨天的用户的交集,这个交集就是留存的用户,留存率就是这个交集/昨日用户数
MR:如何使用MR对两天的数据求交集?
进行交集的关联的字段:userid
很多数据可能是游客的身份进行访问,所以不能将这部分非常大的数据进行舍弃,所以这个关联字段,就不仅仅是 userid,还需要我们唯一的用户表示字段mid。
mid+userid
mid+null 如果mid相同?
BIDUPSID=26B8D7FB2C1DE6F17DD917F85E31BF84 登陆状态下
BIDUPSID=26B8D7FB2C1DE6F17DD917F85E31BF84 注销状态下
BIDUPSID=26B8D7FB2C1DE6F17DD917F85E31BF84;清理cookie之后
BAIDUID EED2B4AC7B051972D61990DEF0120F8D 不同浏览器
键 值
BAIDUID=EED2B4AC7B051972D61990DEF0120F8D

 		用户登陆了?
	现在的问题,是用单一的mid或者userid都能准确的判断出用户的唯一性,所以我们需要两步来完成用户唯一的判断。
	第一步使用mid+userid这样,这样我们就能够统计出所有的用户信息。
		去掉mid留下userid(去重)就是唯一的用户,
	第二步如果userid为null,这个时候使用mid作为唯一标识即可,也就是说吧userid去掉。

如何使用MR完成表的(前天的表)join(昨天的表)
mr的join操作:
map join
考虑将其中一张表在一个task任务中复制一份,加载内存,和另外一张表进行关联操作,
在编码中就是map做映射。
前提是加载到内存中的表是一张小表,不建议这张表超过100M。
reduce join
将数据使用关联的字段发送到reduce端进行join操作,所以我们就需要在reduce端知道那一条记录来自于左表,那一条记录来自于右表。
为每条记录添加一个标签。
原始数据: 598d5d7d-e1c4-46a0-92c5-d91366050f12 20202 。。。
Mapper1: 按照 mid+userid为key,时间为value为map的结果输出
Reducer1: <mid+userid, [2018-11-22, 2018-11-23,2018-11-22, 2018-11-23] 去重
数据结果集: mid + uid + 用户日志操作日期集合
Mapper2: 2018-11-22_2018-11-23---->1
Reducer2: 2018-11-22_2018-11-23---->sum

外链TopN:
以外链为key,求wordcount
Mapper1和Reducer1: referer,sum
求topN:
Mapper2: setup TreeSet //设置一个有序集合,按照字符串中的第二列进行降序排序
map ts.size() > topn ==> ts.pollLast()
cleanup 遍历写入
Reducer2: 同Mapper2逻辑相同
注意:
mr中的参数TopN的传递,不能使用全局的静态变量!
mr中传递参数只能通过configuration来进行!

将mysql中的用户数据上传到hdfs,方便和统计后的标准数据进行关联,在此基础上进行性别,年龄指标的统计,地域统计。
判断:上传一次还是每天增量上传
mysql中保存的用户的数据,要增量的上传到hdfs
1. 写mysql脚本,再将数据查询到本地,然后再通过hdfs dfs -put 上传到每天的目录
2. mapreduce, 有DBInputFormat,将db中的数据,上传到hdfs中
3. sqoop,将数据直接从db --> hdfs

yesterday=`date -d"1 day ago" +"%Y-%m-%d"`	
yesterdayDir=`date -d"1 day ago" +"%Y/%m/%d"`		
SQOOP_HOME=xxxx
$SQOOP_HOME/bin/sqoop import \
--connect xxxx \
--username xxxx \
--username xxxx \
--password xxxx \
--query "select * from t_user where DATE(regster_date) between ${yesterday} and ${yesterday} and \$conditions" \
--target-dir hdfs://hadoop/xxxx/${yesterdayDir}
-m 4

注意:通过sqoop导入数据的时候,某一天的数据录入失败?
通知 发邮件等
补救方法: 手动提交脚本 循环

UGC(用户生成的内容)
只能在代码中加入埋点,当触发该埋点之后,触发一条信息记录。
ugchead (appid ip mid seid userid param time)
head
ugctail (appid ip mid seid userid param time)
tail
为了保障数据的不丢失,计算的时候,去ugchead和ugctail的并集(交集|差集|余弦定理|距离公式|矩阵)
为了日志信息,可扩展,xml—>可以,但是不建议 ==》json
注意:
MapReduce常见问题

猜你喜欢

转载自blog.csdn.net/qq_28844767/article/details/84313879