此项目还未写完
基于新闻咨询行业的头条数据进行的准实时处理的数据仓库建设。 新闻咨询行业的app,软件有 今日头条,腾讯新闻,百度浏览器,360浏览器。 这些app产生的数据流,我们使用structuredstreaming框架来处理,进而将处理后的数据保存到hive中,建模,做一些数据分析,展示,监控等。
要处理的数据,有三种
用户行为数据
业务数据
内容数据
目的:
构建数仓模型,分析这些数据的价值
两种分析模型:
用户行为分析模型: 事件分析,留存分析,漏斗分析
DAU预测模型: 日活用户数据的预测,预测未来的数据情况。
1. 事件是用来记录或者追踪用户行为的,如`用户登录`,`浏览新闻`,`点击新闻进入详情页`,`点击新闻列表中的广告`,`发布评论`
-- 事件一般都会有一个字段event来记录
-- 事件还有其他状态数据,也会有相关属性记录
2.所谓事件分析,就是基于事件的指标统计,属性分组,条件筛选等功能的查询分析
-- 例子1:最近10天那个渠道的新增用户最多,及变化趋势。
-- 例子2:每天每个地域的活跃用户数,新增用户数是多少
1. 留存这个指标是衡量产品对用户价值高低的重要指标。
2. 留存分析是一种用来分析用户活跃程度/参与情况的分析模型
-- 留存分析中,定义了两个行为,分别是初始行为,和后续行为
-- 对于如何选择初始行为和后续行为,有两种策略:
(1)一种是初始行为和后续行为相同,用于分析用户忠实度, 本项目选择的是该策略
(2)一种是初始行为和后续行为不同,用来衡量评估产品迭代或运营策略调整的得失与好坏
(3)选择的初始行为和后续行为在业务上要有意义
-- 留存表示的是在选定时间范围内进行了初始行为的用户有多少人在随后的第 N 天/周/月进行了后续行为
-- 举例说明:
例子1:初始行为是APP启动,后续行为同样是APP启动,那么就是计算APP活跃用户留存。
例子2:初始行为是APP注册,后续行为是APP启动,那么就是计算注册(新增)用户留存
漏斗模型指的是多个自定义事件序列按照指定顺序依次触发的流程中的量化转化模型。通俗点说,就是从起点到终点有多个环节,每个环节都会产生用户流失,依次递减,每一步都会有一个转化率。另外衍生出“路径分析方法”,包括:关键路径、扩散路径、收敛路径、端点路径,每一条路径,都是一个漏斗。
1. 漏斗模型主要分析多步骤过程中每一个步骤的转换与流失用户情况
2. 漏斗模型中的三个概念:
-- 漏斗步骤 : 漏斗的每一步,其实就是一个行为事件或者带条件的行为事件
-- 漏斗时间范围 : 指的是漏斗发生的时间范围
-- 漏斗窗口期:指的是用户完成漏斗的时间限制,只有在这个窗口期的时间范围内,用户从第一步进行到最后一步,才能算作一
次完整的漏斗转化
举例说明:
从用户发表评论的完成流程可以包含以下步骤:
1. 用户登录
2. 浏览新闻
3. 点击新闻进入详情页
4. 发布评论
可以将上述流程设置为一个漏斗,分析整体的转化情况及每一步的转化率
DAU(Daily Active User),日活跃用户数量。一般用于反应网站、互联网应用等运营情况。结合MAU(月活跃用户数量)一起使用,用来衡量服务的用户粘性以及服务的衰退周期。日均活跃用户数量(Daily Active User,DAU)是用于反映网站、互联网应用或网络游戏的运营情况的统计指标。日活跃用户数量通常统计一日(统计日)之内,登录或使用了某个产品的用户数(去除重复登录的用户)。受统计方式限制,互联网行业使用的日均活跃用户数指在统计周期(周/月)内,该App的每日活跃用户数的平均值。
我们通过DAU预测模型的讲解,来进一步设计我们的数仓层次,让我们可以从需求的角度来审视数仓的建设。在这里我们先把DAU预测模型的基本算法做一个简单说明,后面实现时再做详解。
$ DAU_N = A_N + \sum_{i=1}^{N}A_{N-i}*R_i $
$ DAU_N$ 表示第`N`日的日活用户
$A_N$ 表示第`N`日新增
$R_i$ 表示第`i`日留存率
$\sum_{i=1}^{N}A_{N-i}*R_i$ 表示第`N-i`日的新增和第`i`日留存率乘积之和
整个公式含义: `当天日活等于当日新增和此前每一天新增用户留存到当日的用户之和`
数据采集方案变更
回顾采集项目:
行为数据,先落地到nginx的目录下,然后使用flume监听目录,采集到hdfs上,然后映射到hive表中,最后又做了parquet映射
内容数据,直接使用flume的http采集到hdfs上,然后映射到hive表中
业务数据,使用sqoop,定期同步到hdfs上,然后映射到hive表中
方案变更
由于学习了kafka和structuredStreaming(简称SS)这些框架,所以可以更改如下
行为数据,先到nginx的内存中,然后通过脚本充当生产者,将数据发送到kafka上,然后SS作为消费者,消费Kafka的数据进行处理,再存储到数仓中
内容数据,也可以通过kafka,然后使用SS处理,也可以不更改,还是直接使用flume的http采集到hdfs上。
业务数据,使用canal框架来监听数据库中的表的实时变化,然后采集到Kafka上,使用springboot框架进行处理,然后再存储到数仓中。
1. 实现`事件分析`,`留存分析`,`漏斗分析`三个模型,同时要支持自定义多维分析。
2. 优化模型的实现方式,加速多维查询速度
3. 通过自建的用户行为分析平台,可视化理解三个分析模型,及其他用户行为模型。
1. 构建数仓层次支持DAU预测模型快速查询数据
2. 设计实现DAU预测中留存率预测的算法
3. Spring Boot 编写提供DAU预测查询的API
下方架构依然展现了数据采集与监控的架构,只是数据采集的方式和监控的组件有所变化(可以和之前数据采集与监控项目的[架构一]做比较)。
Lua
+lua-resty-kafka
+Kafka+Flume+Canal+DataXStructured Streaming
[Spark]+Hudi
+Presto
+Hue
+Superset
Prometheus
+ Grafana
+ IM
leastsq[最小二乘法]
, $ y=a*x^b$ [幂函数拟合]
nginx-lua-prometheus
+ Burrow
+burrow-exporter
+Prometheus
+ Grafana
+Supervisor
+ IM
在之前的采集监控项目中,行为数据是先落地到nginx的目录下,然后由flume采集方案采集到hdfs上,而该项目是使用lua脚本直接将nginx刚刚接受到的数据从内存中发送到kafka中,不需要落盘,因此要修改一下。
步骤1)创建主题
start-all.sh
zkServer.sh start
kafka-server-start.sh -daemon /usr/local/kafka/config/server.properties
[root@qianfeng01 ~]# ${KAFKA_HOME}/bin/kafka-topics.sh \
--zookeeper qianfeng01:2181/kafka \
--replication-factor 1 \
--partitions 1 \
--topic news \
--create
验证是否创建成功
[root@qianfeng01 ~]# ${KAFKA_HOME}/bin/kafka-topics.sh \
--zookeeper qianfeng01:2181/kafka \
--list
步骤2)下载和安装lua-resty-kafka库
[root@qianfeng01 ~]# wget -P /usr/local/openresty/ http://doc.qfbigdata.com/qf/project/soft/lua/lua-resty-kafka_0.0.9.tgz
[root@qianfeng01 ~]# cd /usr/local/
[root@qianfeng01 ~]# cd openresty/
[root@qianfeng01 openresty]# tar -xzvf lua-resty-kafka_0.0.9.tgz
[root@qianfeng01 openresty]# rm -rf lua-resty-kafka_0.0.9.tgz
[root@qianfeng01 openresty]# ll lua-resty-kafka
步骤3)编写kafka的lua脚本
[root@qianfeng01 ~]# mkdir /opt/apps/realtime/lua
[root@qianfeng01 ~]# vim /opt/apps/realtime/lua/collect-app.lua
local cjson = require "cjson"
local client = require "resty.kafka.client"
local producer = require "resty.kafka.producer"
local broker_list = {
{ host = "192.168.10.101", port = 9092 }
}
local error_handle = function (topic, partition_id, queue, index, err, retryable)
ngx.log(ngx.ERR, "failed to send to kafka: " .. err)
end
local producer_config = {
request_timeout = 60000,
socket_timeout = 60000,
producer_type = "async",
flush_time = 1000,
batch_num = 500,
max_buffering = 100000,
error_handle = error_handle
}息
ngx.req.read_body()
local body_data = ngx.req.get_body_data()
if body_data == nil then
ngx.say('{"code":500,"data":"req body nil"}')
return
end
local current_time = ngx.now()*1000
local project = ngx.var.arg_project
local data={}
data["project"] = project
data["ctime"] = current_time
if ngx.var.http_x_forwarded_for == nil then
data["ip"] = ngx.var.remote_addr;
else
data["ip"] = ngx.var.http_x_forwarded_for
end
local meta = cjson.encode(data)
local res = ngx.encode_base64(meta) .. "-" .. ngx.unescape_uri(body_data)
local bp = producer:new(broker_list,producer_config)
local offset, err = bp:send(project, tostring(current_time),res)
if not offset then
ngx.say('{"code":500,"data":"send kafka failed"}')
return
end
ngx.say('{"code":200,"data":true}')
步骤4)更改nginx的主配置文件
1. 注释掉 log_format collect-app '$cad'; # 这是我们之前自定义掉log_fromat,现在不需要了
2. 修改 lua_package_path "/usr/local/openresty/nginx-lua-prometheus/?.lua;;"; 为
lua_package_path "/usr/local/openresty/nginx-lua-prometheus/?.lua;/usr/local/openresty/lua-resty-kafka/lib/?.lua;;";
实操如下:
[root@qianfeng01 realtime]# vim /opt/apps/realtime/conf/core.conf
# work进程数,
worker_processes 4;
# 错误日志路径,和日志级别
error_log logs/nginx_error.log error;
# nginx pid文件
pid logs/nginx.pid;
# 单个worker最大打开的文件描述符个数
worker_rlimit_nofile 65535;
events
{
#使用epoll模型
use epoll;
# 单个worker进程允许的最多连接数
worker_connections 65535;
}
http
{
include mime.types;
default_type application/octet-stream;
gzip on;
gzip_min_length 1k;
gzip_buffers 4 16k;
gzip_http_version 1.0;
gzip_comp_level 2;
gzip_types text/plain application/x-javascript text/css application/xml;
gzip_vary on;
underscores_in_headers on;
log_format main
'$remote_addr - $remote_user [$time_local] '
'$request_length '
'"$request" $status $bytes_sent $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'"$gzip_ratio" "$request_time" '
'"$upstream_addr" "$upstream_status" "$upstream_response_time"';
# 定义我们数据采集的 access 日志格式
#log_format collect-app '$cad';
open_log_file_cache max=1000 inactive=60s;
keepalive_timeout 0;
client_max_body_size 20m;
include /opt/apps/realtime/conf/vhost/*.conf;
lua_package_path "/usr/local/openresty/nginx-lua-prometheus/?.lua;;/usr/local/openresty/lua-resty-kafka/lib/?.lua;;";
}
步骤5)修改nginx的副配置文件
[root@qianfeng01 realtime]# vim /opt/apps/realtime/conf/vhost/minor1.conf
# 修改为如下内容:
server {
listen 8802 default_server;
lua_need_request_body on;
client_max_body_size 5M;
client_body_buffer_size 5M;
location /data/v1 {
content_by_lua_file /opt/apps/realtime/lua/collect-app.lua;
access_log logs/realtime-access.log main;
}
}
批注基于项目的常用指令
start-all.sh
zkServer.sh start
hive --service metastore &
hive
start-hbase.sh
kafka-server-start.sh -daemon /usr/local/kafka/config/server.properties
openresty -p /opt/apps/realtime -c conf/core.conf -t
openresty -p /opt/apps/realtime -c conf/core.conf -s stop
openresty -p /opt/apps/realtime -c conf/core.conf
ps -ef | grep nginx
curl qianfeng01:8802/data/v1?project=news -d test_data
/usr/local/canal.deployer/bin/startup.sh
/usr/local/canal.deployer/bin/stop.sh
service clickhouse-server restart
/usr/local/chproxy/chproxy -config config.yml
kafka-topics.sh \
--zookeeper qianfeng01:2181/kafka \
--create \
--topic news \
--partitions 1 \
--replication-factor 1
kafka-topics.sh \
--zookeeper qianfeng01:2181/kafka \
--list
kafka-console-producer.sh \
--broker-list qianfeng01:9092 \
--topic news
kafka-console-consumer.sh \
--bootstrap-server qianfeng01:9092 \
--topic news
--from-beginning
kafka-topics.sh \
--zookeeper qianfeng01/kafka \
--delete \
--topic news
kafka-console-consumer.sh \
--bootstrap-server 192.168.10.101:9092 \
--topic news
launcher start
presto-cli --server qianfeng01:8090 --catalog hive
/usr/local/frpc/frpc http --sd tom -l 9666 -s frp.qfbigdata.com:7001 -u tom
/usr/local/frpc/frpc http --sd xixi -l 8802 -s frp.qfbigdata.com:7001 -u xixi