尚硅谷大数据项目之Flink实时数仓一
思考:
Flink1.13版本能用 CDC2.0版本
代码敲三遍:
- 先自己整理思路–》对着代码敲
- 保留注释 --》 对着注释敲
- 什么都不要,自己敲
学完每一块之后,去画架构图
1. 为什么会有DWM(中间层)层
正常情况下DWD层(明细层)直接到DWS层,
DWS是一个宽表,说明会需要DWD层的多张表进行构建,多个宽表可能会公用DWD层的一些明细表。可能会存在对明细表进行加工,可能会有重复加工的操作。
所以避免重复加工操作。
比如说 在不同维度下,如地区维度,访客维度,他们的UV指标都需要对page_log中的mid要进行去重操作,这样就重复计算了
所以可以将mid去重操作后的page_log存放在DWM层中,可以直接拿取地区维度,访客维度,的UV指标
视频P073
3. 实时数仓为什么要分层?
分层, 提高数数据复用性,会牺牲一定的时效性。
2. 实时数仓的数据是存在哪里的呢?
kafka?
4. 为什么DIM层的数据放在了Hbase中,不放在kafka中
维度数据最重要的是查询,事实表根据ID去查维度表来补充事实数据。
Kafka默认保存数据为7天,维度数据不能删除,需要永久保存。
Kafka查询数据不方便。
5. Flume中的TailDirSource当文件更名之后会重新读取该文件造成重复
解放方法: 1. 更改源码,不使用文件名进行判断,只看iNode值; 2. 要使用不更名的打印日志框架(logback)
6. Flume中的TailDirSource中的监控的文件名直接写死,对每天重新生成一个hive.log进行监控,是否可行?
不可以,因为存在零点飘逸,22.30挂了,还持续给log中写数据,然后过了零点后文件更名就监控不到,然后数据丢失了
7. 框架复习逻辑线,flume,kafka
数据流,监控,优化,配置。
知识点相关的东西一定要记牢
Kafka:
Producer:ACK 0 1 -1;拦截器,序列化器,分区器;发送流程;幂等性,事务;分区规则–》有分区则发往指定分区,没有指定分区,则根据Kay值hash,没有指定分区也没有Key的时候,轮询(粘性)
如何保证生产者不丢数据? 问的是ACK
Broker:
Topic:副本(高可靠,ISR:LEO、HW),分区(高并发,负载均衡防止热点)
Comsumer:
分区分配规则: range,roundRobin,Sticky
offset保存:默认保存在__consumer_offsets主题,其他:手动维护Offset《Mysql》 ,保存数据&保存Offset写到一个事务,支持事务可以做到精准一次消费
先保证数据后保存Offset 重复数据+幂等性(精准一次性消费)
先保存Offset后保存数据 丢失数据
8. HQL的书写
优化,ist
解析器,编译器,优化器,执行器
9. FlinkCDC和MaxWell和Canal的区别
数据存储地方不一样
FlinkCDC放在CheckPoint里
MaxWell放在MySQL里
Canal放在本地磁盘里
都支持断点续传
新增数据时, 涉及到多行语句的更新,Canal默认只有一个更新语句,所有的数据都在一起,不方便操作。
项目 | Value | 地方 | 地方 |
---|---|---|---|
sql与数据的关系 | 无 | 无 | 一对一(炸开) |
初始化功能 | 有(多库多表) | 有(单表) | 无(单独查询) |
断点续传 | CK | MySQL | 本地磁盘 |
封装格式 | 自定义 | json | json(c/s自定义) |
高可用 | 运行集群高可用 | 无 | 集群(ZK) |
介绍
1. 课程重点
1. 行为采集
行为采集框架: FlinkCDC, Maxwell, Canal
2. 动态分流
业务数据采集:
业务数据库有非常多的表,如何进行拆分呢?
以及当业务数据增加了一张表之后,我们如何在不停止计算任务的情况下,能够动态的将新增加的表数据采集到呢?–动态分流
3. 多流join, 多流union
事实表的关联
4. 关联维表
旁路缓存—异步IO
2. 课程特色
新,Flink 1.12.0
全
细
3. 技术要求
语言:Java
框架:Hadoop Kafka Hbase Zookeeper Redis
1. 电商实时数层分层介绍(ODS)
为什么要分层?
分为几层?这几层分别存到哪?为什么要这样做?
离线数仓为什么要分层?复杂问题简单化;较少重复计算,提高复用性;解耦,隔离原始数据
1.1 普通实时计算与实时数仓比较
普通的实时计算优先考虑时效性,所以从数据源采集经过实时计算直接得到结果。如此做时效性更好,但是弊端是由于计算过程中的中间结果没有沉淀下来,所以当面对大量实时需求的时候,计算的复用性较差,开发成本随着需求增加直线上升。
实时数仓基于一定的数据仓库理念,对数据处理流程进行规划、分层,目的是提高数据的复用性。
最重要的区别是分层, 提高数数据复用性,会牺牲一定的时效性。
1.2 实时电商数仓,项目分为以下几层
分了五层,
ODS:原始数据,日志和业务数据,放在Kafka中,因为要进行实时计算
DWD:根据数据对象为单位进行分流,比如订单、页面访问等等,可以通过测输出流来达到分流效果
DIM:维度数据,放在了Hbase
DWM:对于部分数据对象进行进一步加工,比如独立访问、跳出行为,也可以和维度进行关联,形成宽表,依旧是明细数据。公用的部分抽取出来了,放在了Kafka
DWS:根据某个主题将多个事实数据轻度聚合,形成主题宽表。放在了clickHouse中
ADS:把ClickHouse中的数据根据可视化需进行筛选聚合。不落盘,数据接口
2. 实时需求概览
听个热闹
2.1 离线计算与实时计算的比较
离线计算:就是在计算开始前已知所有输入数据,输入数据不会产生变化,一般计算量级较大,计算时间也较长。例如今天早上一点,把昨天累积的日志,计算出所需结果。最经典的就是 Hadoop 的 MapReduce 方式;
一般是根据前一日的数据生成报表,虽然统计指标、报表繁多,但是对时效性不敏感。从技术操作的角度,这部分属于批处理的操作。即根据确定范围的数据一次性计算。
实时计算:输入数据是可以以序列化的方式一个个输入并进行处理的,也就是说在开始的时候并不需要知道所有的输入数据。与离线计算相比,运行时间短,计算量级相对较小。
强调计算过程的时间要短,即所查当下给出结果。主要侧重于对当日数据的实时监控,通常业务逻辑相对离线需求简单一下,统计指标也少一些,但是更注重数据的时效性,以及用户的交互性。从技术操作的角度,这部分属于流处理的操作。根据数据源源不断地到达进行实时的运算。
即席查询:需求的临时性
离线计算和实时计算: 需求的固定性
Presto: 当场计算(基于内存速度快)
Kylin:预计算(提前算好),多维分析(Hive With Cube)
2.2 实时需求种类
- 日常统计报表或分析图中需要包含当日部分
- 实时数据大屏监控
- 数据预警或提示(只做实时不做离线,讲究时效性,不需要保存)
- 实时推荐系统
3. 统计架构分析*
自己能说出来,
对比两种架构
3.1 离线架构
架构分析:
Sqoop导入数据的方式:全量,增量,新增及变化,特殊
Flume:
- TailDirSource:
优点:断点续传,监控多目录多文件,实时监控
缺点:当文件更名之后会重新读取该文件造成重复
解决方法: 1. 更改源码,不使用文件名进行判断,只看iNode值; 2. 要使用不更名的打印日志框架(logback) - KafkaChannel:
优点:将数据写入Kafak中,省了一层Sink
Kafka中属于生产者,也可以作为消费者
三种用法:
Source-KafkaChannel-Sink
Source-KafkaChannel
KafkaChannel-Sink
3.2 实时架构
不能用Sqoop进行导入了,原理是MR,太慢了。
可以采用Canal/Maxwell/FlickCDC都是监控binlog的方式(行级别)。
区别1:行为数据由日志服务器直接发送到了Kafka,没有经过落盘处理。(好处:快,减少磁盘IO;缺点:耦合性高,)
ODS只有俩个主题:行为数据和业务数据
DWD要用Flink将ODS层的数据消费,使用测输出流分流分到不同的主题里面。
Flink会再次使用消费DWD的数据,并且可能关联维度表Hbase,形成DWM的数据
然后Flink会消费DWD和DWM的数据再写到Click House
3.3 对比
理线架构:
优点:耦合性低,稳定性高。
缺点:时效性差一点
读取数据先落盘,再从磁盘中读取出来,为什么不直接拿过来用呢?因为
1.项目经理是大公司出来的,追求系统的稳定性。
2.耦合性低,稳定性高。
3.考虑到工作未来的发展,数据量一定会变得很大。
4.早期的时候实时业务使用的是SparkStreaming(微批次)
实时架构:
优点:时效性好
缺点:耦合性低,稳定性低。
说明:1.时效性好
2.Kakfa集群高可用,挂一台两台没有问题
3.数据量小,所有机器存在于同一个机房,传输没有问题
4.架构是公司项目经理架构师定的
4. 日志数据采集
mock代替web/app,
先写SpringBoot代码,先用直连的方式做测试(单机部署)
然后搭建Nginx做负载均衡,再连接102,103,104进行集群测试。
4.1 模拟日志生成器的使用
这里提供了一个模拟生成数据的 jar 包,可以将日志发送给某一个指定的端口,需要大数据程序员了解如何从指定端口接收数据并数据进行处理的流程。
4.2 日志采集模块-本地测试
Lombok: 添加依赖
4.2.1 SpringBoot 简介
SpringBoot: Controller,Service,DAO(Mapper),DAO再对持久化层进行操作
- Controller:拦截用户请求,调用Service,响应请求
- Service:调用DAO层,加工数据
- DAO: 获取数据
- 持久化层: 存储数据
1) 有了 springboot 我们就可以…
不再需要那些千篇一律,繁琐的 xml 文件。
➢ 内嵌 Tomcat,不再需要外部的 Tomcat
➢ 更方便的和各个第三方工具(mysql,redis,elasticsearch,dubbo,kafka 等等整合),而只要维护一个配置文件即可。
2) springboot 和 ssm 的关系
springboot 整合了 springmvc,spring 等核心功能。也就是说本质上实现功能的还是原有的 spring ,springmvc 的包,但是 springboot 单独包装了一层,这样用户就不必直接对 springmvc,spring 等,在 xml 中配置。
3) 没有 xml,我们要去哪配置
springboot 实际上就是把以前需要用户手工配置的部分,全部作为默认项。除非用户需要额外更改不然不用配置。这就是所谓的:“约定大于配置”
如果需要特别配置的时候,去修改application.properties(application.yml)
4.2.2 快速搭建 SpringBoot 程序 gmall-logger,采集模拟生成的日志数据
- 在 IDEA 中安装 lombok 插件、
- 创建空的父工程 gmall2021,用于管理后续所有的模块 module
- 新建 SpringBoot 模块,作为采集日志服务器
A. 在父 project 下增加一个 Module,选择 Spring Initializr
B. 配置项目名称为 gmall2021-logger 及 JDK 版本
C. 选择版本以及通过勾选自动添加 lombok、SpringWeb、Kafka 相关依赖
D. 完成之后开始下载依赖,完整的 pom.xml 文件如下
E. 创建 LoggerController 输出 SpringBoot 处理流程
F. 运行 Gmall2021LoggerApplication,启动内嵌 Tomcat
G. 用浏览器测试并查看控制台输出
package www.atguigu.gmalllogger.controller;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
//@Controller
@RestController // @Controller + @ResponseBody
@Slf4j
public class LoggerController {
@Autowired
private KafkaTemplate<String, String> kafkaTemplate;
@RequestMapping("test")
//@ResponseBody // 表示不返回页面,返回普通的java对象
public String test1(){
System.out.println("success");
return "success.html";
}
@RequestMapping("test2")
public String test2(@RequestParam("name") String nn,
@RequestParam(value="age", defaultValue = "13") int age){
System.out.println(nn + ": " + age);
return "success";
}
@RequestMapping("applog")
public String getLog(@RequestParam("param") String jsonStr){
// 打印数据
//System.out.println(jsonStr);
// 将数据落盘
log.info(jsonStr);
// log.warn();
// log.error();
// log.trace();
// log.debug();
// 将数据写入Kafka
kafkaTemplate.send("ods_base_log", jsonStr);
return "success";
}
}
4.2.3 SpringBoot 整合 Kafka
- 修改 SpringBoot 核心配置文件 application.propeties
# 应用名称
spring.application.name=gmall-logger
# 应用服务 WEB 访问端口
server.port=8081
#============== kafka ===================
# 指定 kafka 代理地址,可以多个
spring.kafka.bootstrap-servers=hadoop102:9092
# 指定消息 key 和消息体的编解码方式
spring.kafka.producer.key-serializer=org.apache.kafka.common.serialization.StringSerializer
spring.kafka.producer.value-serializer=org.apache.kafka.common.serialization.StringSerializer
- 在 LoggerController 中添加方法,将日志落盘并发送到 Kafka 主题中
- 在 Resources 中添加 logback.xml 配置文件
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<property name="LOG_HOME" value="f:/logs" />
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%msg%n</pattern>
</encoder>
</appender>
<appender name="rollingFile" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${
LOG_HOME}/app.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${
LOG_HOME}/app.%d{
yyyy-MM-dd}.log</fileNamePattern>
</rollingPolicy>
<encoder>
<pattern>%msg%n</pattern>
</encoder>
</appender>
<!-- 将某一个包下日志单独打印日志 -->
<logger name="www.atguigu.gmalllogger.controller.LoggerController"
level="INFO" additivity="false">
<appender-ref ref="rollingFile" />
<appender-ref ref="console" />
</logger>
<root level="error" additivity="false">
<appender-ref ref="console" />
</root>
</configuration>
- 修改 hadoop102 上的 rt_applog 目录下的 application.yml 配置文件
- 测试
➢ 运行 Windows 上的 Idea 程序 LoggerApplication
➢ 运行 rt_applog 下的 jar 包
➢ 启动kafka 消费者进行测试
zk.sh start
kf.sh start
bin/kafka-console-consumer.sh --bootstrap-server hadoop102:9092 --topic ods_base_log
4.3 日志采集模块-打包单机部署
4.3.1 修改 gmall2021-logger 中的 logback.xml 配置文件
<property name="LOG_HOME" value="/opt/module/gmall-flink/rt_applog/logs" />
注意:路径和上面创建的路径保持一致,根据自己的实际情况进行修改
4.3.2 打包
4.3.3 将打好的 jar 包 上 传 到 hadoop102 的
/opt/module/gmall-flink/rt_applog 目录下
[atguigu@hadoop102 rt_applog]$ ll
总用量 29984
-rw-rw-r--. 1 atguigu atguigu 30700347 8 月 10 11:35 gmall2021-logger-0.0.1-SNAPSHOT.jar
4.3.4 修改/opt/module/gmall-flink/rt_applog/application.yml
#http 模式下,发送的地址
mock.url=http://hadoop102:8081/applog
4.3.5 测试
➢ 运行 hadoop102 上的 rt_gmall 下的日志处理 jar 包
➢ 运行 rt_applog 下的 jar 包
➢ 启动 kafka 消费者进行测试
bin/kafka-console-consumer.sh --bootstrap-server hadoop102:9092 --topic ods_base_log
4.4 日志采集模块-打包集群部署,并用 Nginx 进行反向代理
4.4.1 根据附录内容搭建好 Nginx 环境
4.4.2 将日志采集的 jar 包同步到 hadoop103 和 hadoop104
[atguigu@hadoop102 module]$ xsync gmall-flink
4.4.3 修改模拟日志生成的配置
发送到的服务器路径修改为 nginx 的
[atguigu@hadoop102 rt_applog]$ vim application.yml
# 外部配置打开
#logging.config=./logback.xml
#业务日期
mock.date=2020-07-13
#模拟数据发送模式
mock.type=http
#http 模式下,发送的地址
mock.url=http://hadoop102/applog
4.4.4 测试
➢ 运行 kafka 消费者,准备消费数据
bin/kafka-console-consumer.sh --bootstrap-server hadoop102:9092 --topic ods_base_log
➢ 启动 nginx 服务
/opt/module/nginx/sbin/nginx
➢ 运行采集数据的 jar
[atguigu@hadoop102 rt_applog]$ java -jar gmall2021-logger-0.0.1-SNAPSHOT.jar
[atguigu@hadoop103 rt_applog]$ java -jar gmall2021-logger-0.0.1-SNAPSHOT.jar
[atguigu@hadoop104 rt_applog]$ java -jar gmall2021-logger-0.0.1-SNAPSHOT.jar
➢ 运行模拟生成数据的 jar