尚硅谷大数据项目之Flink实时数仓-踩坑记录和笔记记录

这里写自定义目录标题

    • 1. 关于Slf4j注解配置文件logback.xml不生效问题
    • 2. 判断新老用户的时候,什么时候会出问题:
    • 3. 为什么维度数据选择存储在Hbase中,而不是Redis,Mysql中
    • 4. 启动phoenix卡住不动了
    • 6. java找不到符号
    • 7. 为什么实时数仓中没有DWT层?
    • 8. 为什么实时数仓中有dwm层?
    • 9. 如何给普通的泛型对象赋值?
    • 10. 一秒钟来了1000个数据,只能处理800个数据就会产生反压,如何优化?
    • 11. redis的安装
    • 12. 在做redis旁路缓存的过程中,BaseDBAPP中,如果当前数据为更新操作,则先删除Redis中的数据,然后再执行插入操作,但是如果这两个操作中间,OrderWideAPP进行了一个查询该数据的操作,redis又有该数据了如何解决?
    • 13.在使用异步查询优化的测试的时候,老是报Timeout错误,
    • 14. DWS层的访客主题宽表中的聚合需要用什么函数?既需要增量也需要窗口信息
    • 15. DWS中访客主题宽表,visitorStatsAPP输出的uj_ct始终为0,但是UserJumpDetail会有用户跳出的数据输出,为什么数据没进来?
    • 16. 列式存储数据库的优点
    • 17. OLAP和OLTP特点
    • 18.clickhouse使用什么引擎?在DWS层中按什么分区?按什么排序?
    • 19. HBASE随机写操作为什么这么快?
    • 20 clickhouse 和hbase区别
    • 21. hive中增加字段怎么操作?
    • 22. 往Phoenix中写数据的用的是JdbcUtil为什么没有用JdbcSink?ClickHouse用哪个?
    • 23. DWS层商品主题宽表计算的思路是什么?
    • 24. 编写代码的问题
      • 爆出类型错误
      • 保持ts属性空指针异常
    • 25. hadoop102挂掉了。
    • 26. 恢复hadoop之后发现,clickhouse无法启动,
    • 27. 断电后Kafka的Hadoop104始终启动不起来。
    • 28. 如何做压测
    • 29. 状态后端有什么存储位置?
    • 30. 什么是FlinkCDC?
  • 数据流和程序
    • mocklog
    • Nginx
    • Logger.sh:
    • BaseLogApp:Flink程序
    • Phoenix
    • BaseDBApp
    • UniqueVisitApp
    • UserJumpDetailApp
    • OrderWideApp
    • PaymentWideApp
    • ClickHouse
    • ODS:
    • DWD-DIM:
    • DWM
    • DWS
      • 商品主题宽表
      • 地区主题表
      • 关键词主题表
  • Sugar的使用
    • 写接口
    • 品牌GMV接口
  • 优化:
    • 状态后端
    • 反压
    • 数据倾斜
    • kafkaSource如何调优

bin/kafka-console-consumer.sh --bootstrap-server hadoop102:9092 --topic dwd_order_refund_info
bin/kafka-console-producer.sh --broker-list hadoop102:9092 --topic

Linux非root用户是没有权限访问1024以下的端口的。
nginx的默认端口号是80
http的默认端口号是80,http://hadoop102:80可以不写80

用process可以把数据保留下来, 把脏数据 输出到测输出流中,用到测输出流只能用到process

动态分流来解决增加表的问题,通过外部文件来感知通知到程序,然后根据外部文件的配置变化来增加

跳出率和留存率都可以反映出用户粘性

CEP可以使用事件时间,而且如果加了within就可以处理乱序数据,

env.setParallelism(1); // 生产环境,与Kafka分区数保持一致

1. 关于Slf4j注解配置文件logback.xml不生效问题

logback.xml的命名多打了一个空格,真的栓q

2. 判断新老用户的时候,什么时候会出问题:

卸载重装app的时候可能会将老用户标记为新用户。is_new为1时,老用户需要将1改为0,需要用到flink的状态编程(值状态)和相关知识点

3. 为什么维度数据选择存储在Hbase中,而不是Redis,Mysql中

因为维度数据中有个是用户维度信息,数据量非常的大,Hbase能够存储海量数据并且能够做到毫秒级查询
为什么不放在Mysql中,并发压力大,会加大业务数据库的压力。

4. 启动phoenix卡住不动了

[wanghaha@hadoop102 module]$ /opt/module/phoenix/bin/sqlline.py hadoop102,hadoop103,hadoop104:2181
Setting property: [incremental, false]
Setting property: [isolation, TRANSACTION_READ_COMMITTED]
issuing: !connect -p driver org.apache.phoenix.jdbc.PhoenixDriver -p user "none" -p password "none" "jdbc:phoenix:hadoop102,hadoop103,hadoop104:2181"
SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/opt/module/phoenix/phoenix-client-hbase-2.4-5.1.2.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/opt/module/hadoop-3.1.3/share/hadoop/common/lib/slf4j-log4j12-1.7.25.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
SLF4J: Actual binding is of type [org.slf4j.impl.Log4jLoggerFactory]
Connecting to jdbc:phoenix:hadoop102,hadoop103,hadoop104:2181
22/07/13 17:02:18 WARN util.NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable

原因:是hbase的meta信息不一致
将zk中hbase删除,然后重新启动hbase搞定

成功解决
尚硅谷大数据项目之Flink实时数仓-踩坑记录和笔记记录_第1张图片

6. java找不到符号

尚硅谷大数据项目之Flink实时数仓-踩坑记录和笔记记录_第2张图片
尚硅谷大数据项目之Flink实时数仓-踩坑记录和笔记记录_第3张图片
尚硅谷大数据项目之Flink实时数仓-踩坑记录和笔记记录_第4张图片
解决方法:我们用到了lombok的Data注解,而我们误引入了多个lombok依赖,删除版本低的,成功解决

7. 为什么实时数仓中没有DWT层?

DWT 数据主题层, 是历史数据的累计结果,实时数仓中不需要。

8. 为什么实时数仓中有dwm层?

9. 如何给普通的泛型对象赋值?

使用工具类,来实现。

 
        <dependency>
            <groupId>commons-beanutilsgroupId>
            <artifactId>commons-beanutilsartifactId>
            <version>1.9.3version>
        dependency>
        
        <dependency>
            <groupId>com.google.guavagroupId>
            <artifactId>guavaartifactId>
            <version>29.0-jreversion>
        dependency>
// 给泛型对象赋值
            for (int i = 1; i < columnCount+1; i++) {
                // 获取列名
                String columnName = metaData.getColumnName(i);
                // 判断是否需要转换为 驼峰命名
                if(underScoreToCamel){
                    columnName = CaseFormat.LOWER_UNDERSCORE
                            .to(CaseFormat.LOWER_CAMEL,columnName.toLowerCase(Locale.ROOT));
                }
                // 获取列值
                Object value = resultSet.getObject(i);
                // 给泛型对象 赋值
                BeanUtils.setProperty(t, columnName, value);

            }

10. 一秒钟来了1000个数据,只能处理800个数据就会产生反压,如何优化?

优化:

加入旁路缓存,缓存选型? 会有什么问题?要实现三个功能:读写和删。
尚硅谷大数据项目之Flink实时数仓-踩坑记录和笔记记录_第5张图片
Redis:

  1. 存什么数据? jsonStr
  2. 使用什么类型?String Set Hash
  3. ReidsKey?
    String: tableName + id
    Set:
    hash: tableName id

不选Hash的原因:

  • 用户维度数据量大,因为生产环境是集群, 会造成热点数据
  • 设置过期时间,我们需要每一条数据的过期时间都不一样

不选Set的原因:

  • 查询不方便
  • 设置过期时间

异步查询
原来 当一条数据过来之后,将所有维度信息关联上之后在进行返回,然后在下一条。
现在 可以多条数据过来之后, 依次对所有维度信息进行关联。共同等待。

11. redis的安装

安装在了/user/local/bin目录下

make
make test
sudo make install

redis启动

[wanghaha@hadoop102 src]$ redis-server
16652:C 21 Jul 16:00:33.822 # Warning: no config file specified, using the default config. In order to specify a config file use redis-server /path/to/redis.conf
16652:M 21 Jul 16:00:33.822 # You requested maxclients of 10000 requiring at least 10032 max file descriptors.
16652:M 21 Jul 16:00:33.822 # Redis can't set maximum open files to 10032 because of OS error: Operation not permitted.
16652:M 21 Jul 16:00:33.822 # Current maximum open files is 4096. maxclients has been reduced to 4064 to compensate for low ulimit. If you need higher maxclients increase 'ulimit -n'.
                _._                                                  
           _.-``__ ''-._                                             
      _.-``    `.  `_.  ''-._           Redis 3.0.4 (00000000/0) 64 bit
  .-`` .-```.  ```\/    _.,_ ''-._                                   
 (    '      ,       .-`  | `,    )     Running in standalone mode
 |`-._`-...-` __...-.``-._|'` _.-'|     Port: 6379
 |    `-._   `._    /     _.-'    |     PID: 16652
  `-._    `-._  `-./  _.-'    _.-'                                   
 |`-._`-._    `-.__.-'    _.-'_.-'|                                  
 |    `-._`-._        _.-'_.-'    |           http://redis.io        
  `-._    `-._`-.__.-'_.-'    _.-'                                   
 |`-._`-._    `-.__.-'    _.-'_.-'|                                  
 |    `-._`-._        _.-'_.-'    |                                  
  `-._    `-._`-.__.-'_.-'    _.-'                                   
      `-._    `-.__.-'    _.-'                                       
          `-._        _.-'                                           
              `-.__.-'                                               



     
[wanghaha@hadoop102 redis-3.0.4]$ src/redis-cli -h hadoop102
hadoop102:6379> ping
PONG
hadoop102:6379> keys *
(empty list or set)
hadoop102:6379> 

12. 在做redis旁路缓存的过程中,BaseDBAPP中,如果当前数据为更新操作,则先删除Redis中的数据,然后再执行插入操作,但是如果这两个操作中间,OrderWideAPP进行了一个查询该数据的操作,redis又有该数据了如何解决?

首先维度数据是缓慢变化的,更新的数据并不多,将redis的数据不删,直接写一份更新的数据。

其他解决方法: 事务,删改删

13.在使用异步查询优化的测试的时候,老是报Timeout错误,

在 Flink 流处理过程中,经常需要和外部系统进行交互,用维度表补全事实表中的字段。默认情况下,在 Flink 的 MapFunction 中,单个并行只能用同步方式去交互: 将请求发送到外部存储,IO 阻塞,等待请求返回,然后继续发送下一个请求。这种同步交互的方式往往在网络等待上就耗费了大量时间。为了提高处理效率,可以增加 MapFunction 的并行度,但增加并行度就意味着更多的资源,并不是一种非常好的解决方式。Flink 在 1.2 中引入了 Async I/O,在异步模式下,将 IO 操作异步化,单个并行可以连续发送多个请求,哪个请求先返回就先处理,从而在连续的请求间不需要阻塞式等待,大大提高了流处理效率。

在实现的过程中,使用异步查询优化的测试的时候,老是报Timeout错误。

解决方法:DimUtil工具类中实现的getDimInfo方法中,先查询的Redis然后查询的是Phoenix,如果在Redis查询到了数据,原本写的是先归还连接,然后重置时间,最后在返回结果。但是先归还连接再重置时间的这个操作,在多线程中是有问题的(同一个executor的slot公用一个jedispool),a线程归还连接到池子之后,还能够用这个连接,B线程也能够用这个连接。所以会导致超时。
但是还是没有效果,然后查看的超时的数据,其中user_age为null,user_gender有数据,说明在解析对user_age赋值的时候产生了问题。然后发现Diminfo.getString(‘birthday’)没有大写,在Phoenix中表名都是大写的。

14. DWS层的访客主题宽表中的聚合需要用什么函数?既需要增量也需要窗口信息

全窗口函数需要先收集窗口中的数据,并在内部缓存起来,等到窗口要输出结果的时候再取出数据进行计算。
apply方法里面的windowFunction里面 有时间窗口信息

reduceFunction和aggregateFunction适合增量聚合的,来一条聚合一条节省空间,效率高
windowFunction和ProcesswindowFunction,全量聚合,先收集起来,然后统一计算。

答案: 可以一起用, reduceFunction + WindowFunction
在这里插入图片描述

15. DWS中访客主题宽表,visitorStatsAPP输出的uj_ct始终为0,但是UserJumpDetail会有用户跳出的数据输出,为什么数据没进来?

因为UserJumpDetail等待10秒计算完后,visitorStatsAPP所开的窗口就关闭了。
尚硅谷大数据项目之Flink实时数仓-踩坑记录和笔记记录_第6张图片
解决方法:  
方法一:将事件事件 换成处理时间(不建议这么做)
方法二:将visitorStatsAPP的延迟时间增长

16. 列式存储数据库的优点

更擅长聚合操作,sum,count
压缩效率高

17. OLAP和OLTP特点

OLAP:擅长一次写入,多次读取,在于查

OLTP:可以增删改查,支持事务。

18.clickhouse使用什么引擎?在DWS层中按什么分区?按什么排序?

使用的是replacingMergeTree,当机器挂掉后,可以避免重复消费。

按 天进行分区
按 四个维度+时间信息 进行排序。
如果只有四个维度的话,旧的窗口就会被新的窗口的数据覆盖掉。

尚硅谷大数据项目之Flink实时数仓-踩坑记录和笔记记录_第7张图片

19. HBASE随机写操作为什么这么快?

因为

采用了版本,牺牲了读的速度,
当读一条数据的时候,把所有的版本都拿到进行比较,然后返回最新的版本数据。如果标记了删除,就不会返回该数据

20 clickhouse 和hbase区别

hbase写操作非常快,比

hbase适合查询明细
clihoust OLAP 适合分析

所以我们把维度信息放在hbase,而最终的WDS层放在了clickhouse

21. hive中增加字段怎么操作?

可以往后面追加字段,但是不能在原有字段中间追加字段。

22. 往Phoenix中写数据的用的是JdbcUtil为什么没有用JdbcSink?ClickHouse用哪个?

因为要往Phoenix中多个表进行数据的写入,字段都是不确定的,因此只能用JdbcUtil
ADS直往ClickHouse一张表中写数据,因此可以使用JdbcSink,但是为了更加通用一点,同时满足四个维度主题宽表写入数据,可以定义工具类实现。

23. DWS层商品主题宽表计算的思路是什么?

思路一:我们可以用sku_id去关联hbase里面的数据,但是每个都查的话不方便。我们可以先union然后再查,这样就少写了很多代码,但是从查询数据库的角度来说,查询次数并没有减少。
思路二:我们可以根据sku_id去分组,按八个字段(sku,spu,tm,category的id和name)去分组,其中这八个的sku_id都是一样的,我们可以按照sku_id先聚合,聚合好以后,再查。代码量少了,访问数据库的次数也减少了

那DWS层商品主题宽表中,我们最后还有要访问hbase和phenoix或者redis,我们前面的事情就白做了么?前面只需要写订单和订单明细的关联,在取订单数据的时候我也可以只取sku_id,包括取支付数据也可以取sku_id,我没必要把那八种都取出来,最后还是要按照sku_id进行分组,那我可以不做dwm层的维度关联呢
是给ads层其他的需求准备的。

之前在做离线数仓的时候,ads的指标都是从dwt或者dws层出的,也有从dwd层出的。dwt和dws层可以满足生产环境中绝大部分需求,但也有部分需求需要用到dwd层

24. 编写代码的问题

爆出类型错误

getLong(‘item’),item结果出现了电视字段,

在检查了BaseLogApp打印的数据类型,打印的 曝光输出流 中的item并没有中文类型,但是 页面日志输出流 中的item是有中文字段的。
所以可能代码写错了, 获取display的item字段,写成了获取page的item字段。

保持ts属性空指针异常

在七个数据流(页面,订单,支付,加购,评论,收藏,退款,)union后,生成时间戳的过程中,爆出了 空指针异常,
所以检查了每个流的ts字段是否正确赋值,结果发现评论数据流未能正确赋值,本来是由string转换为Json数据类型,然后获取到string类型的create_time,再转换为时间戳类型。结果 直接写成了获取里面的ts字段。

25. hadoop102挂掉了。

hadoop没有配置高可用,

解决方法
链接1
链接2

26. 恢复hadoop之后发现,clickhouse无法启动,

通过查看/var/log/clickhouse-server/clickhouse-server.log文件,发现是在加载元数据时抓到了异常,无法打开trace_log中的一个数据文件,

2022.07.27 18:41:38.882741 [ 2781 ] {} <Error> Application: Cannot open file: not a directory: /var/lib/clickhouse/data/system/trace_log/202207_13878_13878_0/

cd到该目录发现,正常的数据文件的用户组是clickhouse,文件大小为165,而这个文件的用户组是root,文件大小为0,于是更改了用户组,重新启动了但还是失败了。

备份方法

[root@hadoop102 home]# mkdir backup
[root@hadoop102 data]# mv /var/lib/clickhouse/data/default /home/backup/

[root@hadoop102 backup]# mkdir metadata
[root@hadoop102 metadata]# mv /var/lib/clickhouse/metadata/default /home/backup/metadata/
[root@hadoop102 metadata]# mv /var/lib/clickhouse/metadata/default.sql /home/backup/metadata/

卸载clickhouse

[root@hadoop102 metadata]# yum list installed | grep clickhouse
clickhouse-client.noarch                20.4.5.36-2                    installed
clickhouse-common-static.x86_64         20.4.5.36-2                    installed
clickhouse-common-static-dbg.x86_64     20.4.5.36-2                    installed
clickhouse-server.noarch                20.4.5.36-2                    installed
[root@hadoop102 metadata]# yum remove -y clickhouse-common-static*
[root@hadoop102 metadata]# yum remove -y clickhouse-server-common
已加载插件:fastestmirror, langpacks
参数 clickhouse-server-common 没有匹配
不删除任何软件包
[root@hadoop102 metadata]# rm -rf /var/lib/clickhouse
[root@hadoop102 metadata]# rm -rf /etc/clickhouse-*
[root@hadoop102 metadata]# rm -rf /var/log/clickhouse-server
[root@hadoop102 metadata]# yum list installed | grep clickhouse

恢复数据


[root@hadoop102 data]# mv /home/backup/default /var/lib/clickhouse/data/

[root@hadoop102 metadata]# mv /home/backup/metadata/default /var/lib/clickhouse/metadata/ 
[root@hadoop102 metadata]# mv /home/backup/metadata/default.sql  /var/lib/clickhouse/metadata/

然后就可以正常使用了。

27. 断电后Kafka的Hadoop104始终启动不起来。

问题描述:

在测试可视化大屏的关于商品交易额方面的数据接口时,发现orderWideApp无法输出数据,通过查看集群发现Hadoop104上的kafka没有用启动起来。
然后尝试单点启动,但是没过几秒钟就自动关闭了

原因:查看kafka目录下logs/server.log,
断点后导致停止kafka时某些步骤没有处理,比如replication-offset-checkpoint文件没有处理好。

解决方法:备份/export/servers/kafka_2.11-1.0.0/logs/replication-offset-checkpoint文件,删掉该文件,然后重启kafka,就好了。

参考1

28. 如何做压测

积压kafka的数据,来做flink的压测。

29. 状态后端有什么存储位置?

memory
本地:TM内存tesk
远程:JM内存job

fs
本地:TM内存tesk
远程:文件系统(HDFS)

recksDB
本地:当前机器的内存 + 磁盘
远程:文件系统(HDFS)

30. 什么是FlinkCDC?

ChangeDataCapture 变更数据获取,
监测并捕获数据库的变动,将这些变更按发生的顺序完整记录下来,写入到消息中间件中以供其他服务进行订阅及消费。
基于binlog的cdc

数据流和程序

数据流:web/app --> Nginx --> SpringBoot --> Kafka(ods) -> FlinkApp -> Kafka(dwd)

程 序: mocklog -> Nginx --> Logger.sh --> Kafka(ZK) --> BaseLogApp -> Kafka

mocklog

使用模拟日志生成器
发送的地址为http://hadoop102:80/applog

启动命令,一般最后启动

java -jar gmall2020-mock-log-2020-12-18.jar

Nginx

主要用于负载均衡
模拟数据以后应该发给 nginx, 然后 nginx 再转发给我们的日志服务器.
日志服务器我们会分别配置在 hadoop102,hadoop103,hadoop104 三台设备上.

默认端口为80端口
转发地址为:

server hadoop102:8081 weight=1;
 server hadoop103:8081 weight=1;
 server hadoop104:8081 weight=1;

启动命令为:

sudo /opt/module/nginx/sbin/nginx
ps -ef | grep nginx

Logger.sh:

采集日志服务(nginx 和采集日志数据的 jar 启动服务)
将各节点的gmall-logger.jar启动

gmall-logger.jar包含一个LoggerController类,实现两个功能:将数据落盘,将数据写入Kafka的ods_base_log主题中

BaseLogApp:Flink程序

TODO 1. 获取执行环境
TODO 2. 消费 ods_base_log 主题数据创建流
TODO 3. 将每行数据转换为JSON对象
TODO 4. 新老用户校验 状态编程
TODO 5. 分流 测输出流 页面: 主流 启动: 测输出流 曝光:测输出流
TODO 6. 提取测输出流
TODO 7. 将三个流进行打印并输出到对应的Kafka主题中

Phoenix

[wanghaha@hadoop102 redis-3.0.4]$ cd ../phoenix/
[wanghaha@hadoop102 phoenix]$ bin/sqlline.py 

BaseDBApp

在测试环境中,要先起BaseDBApp,然后在启FlinkCDC。
因为先启动FlinkCDC,数据就写到了Kafka的 ods层了,然后再启动BaseDBApp,有可能只读到了Kafka的 ods层的数据,还没有读到TableProcess中的数据,会造成数据的丢失。

如何避免这个问题?

TODO 1. 获取执行环境
TODO 2. 消费Kafka ods_base_db 主题数据创建流
TODO 3. 将每行数据转换为JSON对象并过滤(delete) 主流
TODO 4. 使用FlinkCDC消费配置表并处理成 广播流
TODO 5. 连接主流和广播流
TODO 6. 分流 处理数据 广播流数据,主流数据(根据广播流数据进行处理)
广播流

  1. 解析数据 String =》 TableProcess
  2. 检查Hbase表是否存在并建表
  3. 写入状态

主流

  1. 读取状态
  2. 过滤数据
  3. 分流
    TODO 7. 提取Kafka流数据和Hbase数据
    TODO 8. 将Kafka数据写入Kafka主题, 将Hbase数据写入Phoenix表中
    DimSinkFunction
    TODO 9. 启动任务

测试:开哪些东西,zk,kafka,hdfs,hbase

UniqueVisitApp

filter方法中的逻辑
尚硅谷大数据项目之Flink实时数仓-踩坑记录和笔记记录_第8张图片
使用定时器,上process,去清空长时间不用的状态。
也可以设置TTL,超时时间,最多保留24小时。

uv测试数据

{"common":{"ar":"110000","ba":"Xiaomi","ch":"huawei","is_new":"1","md":"Xiaomi 10 Pro ","mid":"mid_9","os":"Android 11.0","uid":"41","vc":"v2.1.132"},"page":{"during_time":9223,"item":"4","item_type":"sku_ids","last_page_id":"trade","page_id":"payment"},"ts":1608281608000}

{"common":{"ar":"110000","ba":"Xiaomi","ch":"huawei","is_new":"1","md":"Xiaomi 10 Pro ","mid":"mid_9","os":"Android 11.0","uid":"41","vc":"v2.1.132"},"page":{"during_time":9223,"item":"4","item_type":"sku_ids","page_id":"payment"},"ts":2608281608000}

uj测试数据

{"common":{"ar":"110000","ba":"Xiaomi","ch":"huawei","is_new":"1","md":"Xiaomi 10 Pro ","mid":"mid_9","os":"Android 11.0","uid":"41","vc":"v2.1.132"},"page":{"during_time":9223,"item":"4","item_type":"sku_ids","last_page_id":"trade","page_id":"payment"},"ts":1608281608000}

{"common":{"ar":"110000","ba":"Xiaomi","ch":"huawei","is_new":"1","md":"Xiaomi 10 Pro ","mid":"mid_9","os":"Android 11.0","uid":"41","vc":"v2.1.132"},"page":{"during_time":9223,"item":"4","item_type":"sku_ids","page_id":"payment"},"ts":1608281613000}

UserJumpDetailApp

DWM层,用户跳出行为计算。

利用 CEP 可以针对一组数据进行筛选判断。

TODO 1. 获取执行环境
TODO 2. 读取kafka主题的的数据创建流
TODO 3. 将每行的数据转换为JSON对象并提取时间戳生成watermark
TODO 4. 定义模式序列
TODO 5. 将模式序列 作用到流上
TODO 6. 提取匹配上的超时序列事件
TODO 7. union两种事件
TODO 8. 将数据写入Kafka
TODO 9. 启动任务

OrderWideApp

DWM层,订单宽表

事实数据和事实数据关联,其实就是流与流之间的关联。
事实数据与维度数据关联,其实就是流计算中查询外部数据源

TODO 1.获取执行环境
TODO 2. 读取kafka主题数据 并转换为JavaBean对象 & 提取时间戳生产watermark
TODO 3. 双流join
TODO 4. 关联维度信息,用户维度,地区维度,SKU维度,SPU维度,TM维度,Category维度
DimAsyncFuncion类
TODO 5.将数据写入kafka
TODO 6. 启动任务

PaymentWideApp

支付宽表

支付宽表的目的,最主要的原因是支付表没有到订单明细,支付金额没有细分到商品上,没有办法统计商品级的支付状况。
所以本次宽表的核心就是要把支付表的信息与订单宽表关联上。

用流的方式接收订单宽表,然后用双流 join 方式进行合并。因为订单与支付产生有一定的时差。所以必须用 intervalJoin 来管理流的状态时间,保证当支付到达时订单宽表还保存在状态中。

TODO 1. 获取执行环境
TODO 2. 读取kafka主题数据, 创建数据流 并转化为javaBean对象,并提取时间戳生成WaterMark
TODO 3. 双流join
TODO 4. 写入kafka
TODO 5. 启动任务

ClickHouse

启动sudo systemctl start clickhouse-server

查看状态sudo systemctl status clickhouse-server

停止: sudo systemctl stop clickhouse-server

使用client链接server: clickhouse-client -m

ODS:

数据源: 行为数据,业务数据
架构分析: 40分钟
FlickCDC:DataStream/FlinkSQL,FLinkCDC/Maxwell/Canal
作用: 保持数据原貌,不做任何修改
ods_base_log, ods_base_log

DWD-DIM:

行为数据:DWD(Kafka)
1. 过滤脏数据 --> 测输出流 脏数据率
2. 新老用户校验 —》 前台校验不准
3. 分流 --》 测输出流 页面、启动、曝光
4. 写入Kafka

业务数据:DWD(Kafka)-DIM(Phoenix)

  1. 过滤数据 --》 删除数据

  2. 读取配置表创建广播流

  3. 连接主流和广播流并处理

    • ① 广播流数据
      • a.解析数据
      • b.Phoenix建表
      • c.写入状态广播
    • ② 主流数据
      • a.读取状态
      • b.过滤字段
      • c.分流(添加SinkTable字段)
  4. 提取kafka和Hbase流分别对应的位置

  5. Hbase流: 自定义Sink

  6. Kafka流: 自定义序列化方式

DWM

横向看是 DWS
纵向看是 ADS
尚硅谷大数据项目之Flink实时数仓-踩坑记录和笔记记录_第9张图片
简单的说就是UV是指每一个独立的访客,PV指的就是刷新的次数,
uv:按天对mid去重

DWM层-跳出明细计算

思路一: 可以使用会话窗口,因为没有会话id,我们只能根据时间来判断是否是一次会话。
思路二: CEP,第一条数据last_page_id == null ,第二条数据也为null, within(10s),主流数据和测输出流union

next 严格近邻,
分别输入了时间戳为70000,75000,79000的数据,因为延迟设置了两秒,79000的数据到来时,77000以前的数据全部到齐,就是两条数据,并且都符合start和next,所有输出了一条数据

DWM 层-订单宽表

双流join
两张事实表join好之后,去phonenix中根据id查询相关的维度信息。查好之后join进来。
尚硅谷大数据项目之Flink实时数仓-踩坑记录和笔记记录_第10张图片
DWM 层-支付宽表

测试数据是否丢失:
尚硅谷大数据项目之Flink实时数仓-踩坑记录和笔记记录_第11张图片
尚硅谷大数据项目之Flink实时数仓-踩坑记录和笔记记录_第12张图片

DWS

商品主题宽表

第一事情:因为需要的字段太多, 我们需要用到构造者设计模式
第二个事情:我们可以根据sku_id去分组,按八个字段(sku,spu,tm,category的id和name)去分组,其中这八个的sku_id都是一样的,我们可以按照sku_id先聚合,聚合好以后,再查。代码量少了,访问数据库的次数也减少了

第三个事情:同一个订单,有相同的商品sku_id相同。(一个订单拆出来两个明细,两个明细当中的sku_id相同)所以我们要做去重。商品主题宽表中有一个度量叫下单的次数,具有相同的skuid的两个明细属于同一个订单,如果按照skuid计算指标的话,这个订单只能累加一次。如果不做任何处理,这个订单对于当前商品而言就计算了两次。所以我们要做去重。怎么做去重?状态,按照sku_id分组,保存order_id。保存多久?不好说。使用Set javabean三个set,下单,支付,退款

// TODO 1. 获取执行化境
// TODO 2. 读取kafka 7个主题的 数据创建流
// TODO 3. 将 7个流统一数据格式
// TODO 4. Union 7个流
// TODO 5. 提取时间戳生成 WaterMark
// TODO 6. 分组,开窗,聚合 按照sku_id分组,10秒的滚动窗口,结合增量聚合(累加值) 和 全量聚合(提取窗口信息)
// TODO 7. 关联维度信息
// 7.1 关联 sku维度

// 7.2 关联spu维度

// 7.3 关联TM维度
// 7.4 关联Category维度
// TODO 8. 将数据写入 clickHouse
// TODO 9. 启动任务

地区主题表

FlinkSQL实现

在这里插入图片描述
第一个难点:根据我们的数据来提取事件时间生成watermark
第二个难点:开窗

TODO 1. 获取执行环境
TODO 2. 只用DDL创建表 提取时间戳生成waterMark
TODO 3. 查询数据 分组,开窗,聚合
TODO 4. 将动态表转换为流
TODO 5. 打印数据并写入ClickHouse
TODO 6. 启动任务

关键词主题表

分词,要炸裂函数,自定义UDTF,
KeywordStatsApp

    // TODO 1. 获取执行环境
    // TODO 2. 使用DDL方式读取Kafka数据创建表
    // TODO 3. 过滤数据  上一跳页面为search and 搜索词is not null
    // TODO 4. 注册UDTF,  进行分词处理
    // TODO 5. 分组, 开窗, 聚合
    // TODO 6. 将动态表 转化为 流
    // TODO 7. 将数据打印并写入CLickHouse
    // TODO 8. 启动任务

Sugar的使用

  1. 选择所需要的数据展示格式

  2. 数据的JSON格式
    尚硅谷大数据项目之Flink实时数仓-踩坑记录和笔记记录_第13张图片

  3. 写数据接口
    localhost:8070/api/sugar/gmv ==>当天
    localhost:8070/api/sugar/gmv?date=20210901

  4. 测试

写接口

169: 三重绑定

第一重绑定:让web项目能够读取,我们所写的接口以及xml文件
在主类上面添加MapperScan,把接口扫面进来
xml文件:在application.properties文件中加mybatis.mapper-locations=classpath:mappers/*xml

第二重绑定:
在xml中,写namespace标签

第三重绑定:
Mapper里有很多方法,要对应到xml相应的sql语句上
xml中的id等于方法名

一张表一个mapper

品牌GMV接口

mapper: 查询数据,Map[(“tm_name”-> “苹果”),("order_amount->279501)]
service层及其实现: 将数据格式加工为: [(“苹果” -> 276501),… ]
Controller: 处理请求,

优化:

做过什么优化?解决过什么问题?遇到哪些问题?都是问的是优化

  1. 说明业务场景
  2. 遇到了什么问题-- 往往是通过监控工具结合报警系统得知的;
  3. 排查问题;
  4. 解决手段;
  5. 问题被解决!

状态后端

memory
本地:TM内存tesk
远程:JM内存job

fs
本地:TM内存tesk
远程:文件系统(HDFS)

recksDB
本地:当前机器的内存 + 磁盘
远程:文件系统(HDFS)

反压

尚硅谷大数据项目之Flink实时数仓-踩坑记录和笔记记录_第14张图片
不拉取数据,kafka数据挤压,延迟会越来越高

spark:

数据倾斜

数据倾斜:相同Task的多个SubTask中,个别Subtask接收到的数据量明显大于其他Subtask接收到的数据量。

keyBy之前: rebalance

不开窗keyBy之后:MR,spark中可以使用双重聚合,(某一个key的数据量很多的话,可以先将key打散,按key1,key2…分组聚合,最后再统一聚合)但是这个在flink中用不了,因为流是一条一条写出去的,不同算子中,双重聚合后和原始数据比并没有减少,下一个算子中还是会产生数据倾斜。而且有数据重复问题导致结果不对
可以使用:LocalKeyBy的思想, 定义状态,mapStatus,再加定时器,数据不打散,在map端直接输出一批,相当于在map端欲聚合

开窗keyBy之后:可以使用两阶段聚合,DataStream->keyedStream->WindowedStream->DataStream

kafkaSource如何调优

动态发现分区
从kafka数据源生成watermark
设置空闲等待
如果数据源中的某一个分区/分片在一段时间内未发送事件数据,则意味着
WatermarkGenerator 也不会获得任何新数据去生成 watermark。我们称这类数据源为空闲输入或空闲源。在这种情况下,当某些其他分区仍然发送事件数据的时候就会出现问题。比如 Kafka 的 Topic 中,由于某些原因,造成个别 Partition 一直没有新的数据。
由于下游算子 watermark 的计算方式是取所有不同的上游并行数据源 watermark 的最小值,则其 watermark 将不会发生变化,导致窗口、定时器等不会被触发
为了解决这个问题,你可以使用 WatermarkStrategy 来检测空闲输入并将其标记为空闲状态。
Kafka 的 offset 消费策略

你可能感兴趣的:(大数据项目,大数据,flink,java)