用户行为日志分析是实时数据处理很常见的一个应用场景,比如常见的PV、UV统计。本文将基于Flink从0到1构建一个用户行为日志分析系统,包括架构设计与代码实现。本文分享将完整呈现日志分析系统的数据处理链路,通过本文,你可以了解到:
- 基于discuz搭建一个论坛平台
- Flume日志收集系统使用方式
- Apache日志格式分析
- Flume与Kafka集成
- 日志分析处理流程
- 架构设计与完整的代码实现
项目简介
本文分享会从0到1基于Flink实现一个实时的用户行为日志分析系统,基本架构图如下:
首先会先搭建一个论坛平台,对论坛平台产生的用户点击日志进行分析。然后使用Flume日志收集系统对产生的Apache日志进行收集,并将其推送到Kafka。接着我们使用Flink对日志进行实时分析处理,将处理之后的结果写入MySQL供前端应用可视化展示。本文主要实现以下三个指标计算:
- 统计热门板块,即访问量最高的板块
- 统计热门文章,即访问量最高的帖子文章
- 统计不同客户端对版块和文章的总访问量
基于discuz搭建一个论坛平台
安装XAMPP
- 下载
wget https://www.apachefriends.org/xampp-files/5.6.33/xampp-linux-x64-5.6.33-0-installer.run
- 安装
# 赋予文件执行权限
chmod u+x xampp-linux-x64-5.6.33-0-installer.run
# 运行安装文件
./xampp-linux-x64-5.6.33-0-installer.run
-
配置环境变量
将以下内容加入到 ~/.bash_profile
export XAMPP=/opt/lampp/
export PATH=$PATH:$XAMPP:$XAMPP/bin
- 刷新环境变量
source ~/.bash_profile
- 启动XAMPP
xampp restart
- MySQL的root用户密码和权限修改
#修改root用户密码为123qwe
update mysql.user set password=PASSWORD('123qwe') where user='root';
flush privileges;
#赋予root用户远程登录权限
grant all privileges on *.* to 'root'@'%' identified by '123qwe' with grant option;
flush privileges;
安装Discuz
- 下载discuz
wget http://download.comsenz.com/DiscuzX/3.2/Discuz_X3.2_SC_UTF8.zip
- 安装
#删除原有的web应用
rm -rf /opt/lampp/htdocs/*
unzip Discuz_X3.2_SC_UTF8.zip –d /opt/lampp/htdocs/
cd /opt/lampp/htdocs/
mv upload/*
#修改目录权限
chmod 777 -R /opt/lampp/htdocs/config/
chmod 777 -R /opt/lampp/htdocs/data/
chmod 777 -R /opt/lampp/htdocs/uc_client/
chmod 777 -R /opt/lampp/htdocs/uc_server/
Discuz基本操作
- 自定义版块
- 进入discuz后台:http://kms-4/admin.php
- 点击顶部的论坛菜单
- 按照页面提示创建所需版本,可以创建父子版块
Discuz帖子/版块存储数据库表介
-- 登录ultrax数据库
mysql -uroot -p123 ultrax
-- 查看包含帖子id及标题对应关系的表
-- tid, subject(文章id、标题)
select tid, subject from pre_forum_post limit 10;
-- fid, name(版块id、标题)
select fid, name from pre_forum_forum limit 40;
当我们在各个板块添加帖子之后,如下所示:
修改日志格式
- 查看访问日志
# 日志默认地址
/opt/lampp/logs/access_log
# 实时查看日志命令
tail –f /opt/lampp/logs/access_log
- 修改日志格式
Apache配置文件名称为httpd.conf,完整路径为/opt/lampp/etc/httpd.conf
。由于默认的日志类型为common类型,总共有7个字段。为了获取更多的日志信息,我们需要将其格式修改为combined格式,该日志格式共有9个字段。修改方式如下:
# 启用组合日志文件
CustomLog "logs/access_log" combined
- 重新加载配置文件
xampp reload
Apache日志格式介绍
192.168.10.1 - - [30/Aug/2020:15:53:15 +0800] "GET /forum.php?mod=forumdisplay&fid=43 HTTP/1.1" 200 30647 "http://kms-4/forum.php" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.135 Safari/537.36"
上面的日志格式共有9个字段,分别用空格隔开。每个字段的具体含义如下:
192.168.10.1 ##(1)客户端的IP地址
- ## (2)客户端identity标识,该字段为"-"
- ## (3)客户端userid标识,该字段为"-"
[30/Aug/2020:15:53:15 +0800] ## (4)服务器完成请求处理时的时间
"GET /forum.php?mod=forumdisplay&fid=43 HTTP/1.1" ## (5)请求类型 请求的资源 使用的协议
200 ## (6)服务器返回给客户端的状态码,200表示成功
30647 ## (7)返回给客户端不包括响应头的字节数,如果没有信息返回,则此项应该是"-"
"http://kms-4/forum.php" ## (8)Referer请求头
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.135 Safari/537.36" ## (9)客户端的浏览器信息
关于上面的日志格式,可以使用正则表达式进行匹配:
(\d{
1,3}\.\d{
1,3}\.\d{
1,3}\.\d{
1,3}) (\S+) (\S+) (\[.+?\]) (\"(.*?)\") (\d{
3}) (\S+) (\"(.*?)\") (\"(.*?)\")
Flume与Kafka集成
本文使用Flume对产生的Apache日志进行收集,然后推送至Kafka。需要启动Flume agent对日志进行收集,对应的配置文件如下:
# agent的名称为a1
a1.sources = source1
a1.channels = channel1
a1.sinks = sink1
# set source
a1.sources.source1.type = TAILDIR
a1.sources.source1.filegroups = f1
a1.sources.source1.filegroups.f1 = /opt/lampp/logs/access_log
a1sources.source1.fileHeader = flase
# 配置sink
a1.sinks.sink1.type = org.apache.flume.sink.kafka.KafkaSink
a1.sinks.sink1.brokerList=kms-2:9092,kms-3:9092,kms-4:9092
a1.sinks.sink1.topic= user_access_logs
a1.sinks.sink1.kafka.flumeBatchSize = 20
a1.sinks.sink1.kafka.producer.acks = 1
a1.sinks.sink1.kafka.producer.linger.ms = 1
a1.sinks.sink1.kafka.producer.compression.type = snappy
# 配置channel
a1.channels.channel1.type = file
a1.channels.channel1.checkpointDir = /home/kms/data/flume_data/checkpoint
a1.channels.channel1.dataDirs= /home/kms/data/flume_data/data
# 配置bind
a1.sources.source1.channels = channel1
a1.sinks.sink1.channel = channel1
知识点:
Taildir Source相比Exec Source、Spooling Directory Source的优势是什么?
TailDir Source:断点续传、多目录。Flume1.6以前需要自己自定义Source记录每次读取文件位置,实现断点续传
Exec Source:可以实时收集数据,但是在Flume不运行或者Shell命令出错的情况下,数据将会丢失
Spooling Directory Source:监控目录,不支持断点续传
值得注意的是,上面的配置是直接将原始日志push到Kafka。除此之外,我们还可以自定义Flume的拦截器对原始日志先进行过滤处理,同时也可以实现将不同的日志push到Kafka的不同Topic中。
启动Flume Agent
将启动Agent的命令封装成shell脚本:**start-log-collection.sh **,脚本内容如下:
#!/bin/bash
echo "start log agent !!!"
/opt/modules/apache-flume-1.9.0-bin/bin/flume-ng agent --conf-file /opt/modules/apache-flume-1.9.0-bin/conf/log_collection.conf --name a1 -Dflume.root.logger=INFO,console
查看push到Kafka的日志数据
将控制台消费者命令封装成shell脚本:kafka-consumer.sh,脚本内容如下:
#!/bin/bash
echo "kafka consumer "
bin/kafka-console-consumer.sh --bootstrap-server kms-2.apache.com:9092,kms-3.apache.com:9092,kms-4.apache.com:9092 --topic $1 --from-beginning
使用下面命令消费Kafka中的数据:
[kms@kms-2 kafka_2.11-2.1.0]$ ./kafka-consumer.sh user_access_logs
日志分析处理流程
为了方便解释,下面会对重要代码进行讲解,完整代码移步github:https://github.com/jiamx/flink-log-analysis
创建MySQL数据库和目标表
-- 客户端访问量统计
CREATE TABLE `client_ip_access` (
`client_ip` char(50) NOT NULL COMMENT '客户端ip',
`client_access_cnt` bigint(20) NOT NULL COMMENT '访问次数',
`statistic_time` text NOT NULL COMMENT '统计时间',
PRIMARY KEY (`client_ip`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- 热门文章统计
CREATE TABLE `hot_article` (
`article_id` int(10) NOT NULL COMMENT '文章id',
`subject` varchar(80) NOT NULL COMMENT '文章标题',
`article_pv` bigint(20) NOT NULL COMMENT '访问次数',
`statistic_time` text NOT NULL COMMENT '统计时间',
PRIMARY KEY