6.Flink实时项目之业务数据分流
在上一篇文章中,我们已经获取到了业务数据的输出流,分别是dim层维度数据的输出流,及dwd层事实数据的输出流,接下来我们要做的就是把这些输出流分别再流向对应的数据介质中,dim层流向hbase中,dwd层依旧回写到kafka中。
1.分流维度表sink到hbase
上一篇的结果是维度数据在侧输出流hbaseDs,事实数据在主流filterDs中,如下:
//5.动态分流,事实表写会kafka,维度表写入hbase
OutputTag<JSONObject> hbaseTag = new OutputTag<JSONObject>(TableProcess.SINK_TYPE_HBASE){};
//创建自定义mapFunction函数
SingleOutputStreamOperator<JSONObject> kafkaTag = filterDs.process(new TableProcessFunction(hbaseTag));
DataStream<JSONObject> hbaseDs = kafkaTag.getSideOutput(hbaseTag);
filterDs.print("json str --->>");
处理流程如下:

自定义RickSinkFunction类:DimSink.java
初始化phoenix连接
保存数据
1.1 配置
在BaseDbTask任务中,我们已经获取到hbase的输出流,然后就可以开始hbase的一系列操作了。
添加phoenix依赖包
<!-- phoenix -->
<dependency>
<groupId>org.apache.phoenix</groupId>
<artifactId>phoenix-spark</artifactId>
<version>5.0.0-HBase-2.0</version>
<exclusions>
<exclusion>
<groupId>org.glassfish</groupId>
<artifactId>javax.el</artifactId>
</exclusion>
</exclusions>
</dependency>
修改hbase-site.xml,因为要用单独的 schema,所以在 Idea 程序中也要加入 hbase-site.xml
为了开启 hbase 的 namespace 和 phoenix 的 schema 的映射,在程序中需要加这个配置文件,另外在 linux 服务上,也需要在 hbase 以及 phoenix 的 hbase-site.xml 配置文件中,加上以上两个配置,并使用 xsync 进行同步。
<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
<configuration>
<property>
<name>hbase.rootdir</name>
<value>hdfs://hadoop101:9000/hbase</value>
</property>
<property>
<name>hbase.cluster.distributed</name>
<value>true</value>
</property>
<property>
<name>hbase.zookeeper.quorum</name>
<value>hadoop101,hadoop102,hadoop103</value>
</property>
<property>
<name>hbase.table.sanity.checks</name>
<value>false</value>
</property>
<property>
<name>phoenix.schema.isNamespaceMappingEnabled</name>
<value>true</value>
</property>
<property>
<name>phoenix.schema.mapSystemTablesToNamespace</name>
<value>true</value>
</property>
</configuration>
1.2 创建命名空间
在phoenix中执行
create schema GMALL_REALTIME;
1.3 DimSink.java
自定义addSink类
package com.zhangbao.gmall.realtime.app.func;
import com.alibaba.fastjson.JSONObject;
import com.google.common.base.Strings;
import com.zhangbao.gmall.realtime.common.GmallConfig;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.StringUtils;
import org.apache.flink.configuration.Configuration;
import org.apache.flink.streaming.api.functions.sink.RichSinkFunction;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
/**
* @author: zhangbao
* @date: 2021/9/4 12:23
* @desc: 将维度表写入hbase中
**/
@Log4j2
public class DimSink extends RichSinkFunction<JSONObject> {
private Connection conn = null;
@Override
public void open(Configuration parameters) throws Exception {
log.info("建立 phoenix 连接...");
Class.forName("org.apache.phoenix.jdbc.PhoenixDriver");
conn = DriverManager.getConnection(GmallConfig.PHOENIX_SERVER);
log.info("phoenix 连接成功!");
}
@Override
public void invoke(JSONObject jsonObject, Context context) throws Exception {
String sinkTable = jsonObject.getString("sink_table");
JSONObject data = jsonObject.getJSONObject("data");
PreparedStatement ps = null;
if(data!=null && data.size()>0){
try {
//生成phoenix的upsert语句,这个包含insert和update操作
String sql = generateUpsert(data,sinkTable.toUpperCase());
log.info("开始执行 phoenix sql -->{}",sql);
ps = conn.prepareStatement(sql);
ps.executeUpdate();
conn.commit();
log.info("执行 phoenix sql 成功");
} catch (SQLException throwables) {
throwables.printStackTrace();
throw new RuntimeException("执行 phoenix sql 失败!");
}finally {
if(ps!=null){
ps.close();
}
}
}
}
//生成 upsert sql
private String generateUpsert(JSONObject data, String sinkTable) {
StringBuilder sql = new StringBuilder();
//upsert into scheme.table(id,name) values('11','22')
sql.append("upsert into "+GmallConfig.HBASE_SCHEMA+"."+sinkTable+"(");
//拼接列名
sql.append(StringUtils.join(data.keySet(),",")).append(")");
//填充值
sql.append("values('"+ StringUtils.join(data.values(),"','")+"')");
return sql.toString();
}
}
然后在主程序中加入
//6. 将维度表写入hbase中
hbaseDs.addSink(new DimSink());
1.4 测试
需要启动的服务
hdfs、zk、kafka、Maxwell、hbase,BaseDbTask.java
修改配置数据:gmall2021_realtime.table_process
INSERT INTO `gmall2021_realtime`.`table_process` (`source_table`, `operate_type`, `sink_type`, `sink_table`, `sink_columns`, `sink_pk`, `sink_extend`) VALUES ('base_trademark', 'insert', 'hbase', 'dim_base_trademark', 'id,tm_name', 'id', NULL);此条配置数据代表,如果表base_trademark有插入数据,就把数据同步到hbase中,自动建表,作为维度数据。
修改业务库中表数据:gmall2021.base_trademark
INSERT INTO `gmall2021`.`base_trademark` (`id`, `tm_name`, `logo_url`) VALUES ('15', '55', '55');查看phoenix数据:
select * from GMALL_REALTIME.BASE_TRADEMARK;
数据已经实时同步到hbase中。
2.分流事实表sink到kafka
2.1 MyKafkaUtil定义新方法
在MyKafkaUtil中定义新的生产者方法,可动态指定topic,如果不指定则生产到默认topic:default_data
/**
* 动态生产到不同的topic,如果不传topic,则自动生产到默认的topic
* @param T 序列化后的数据,可指定topic
*/
public static <T> FlinkKafkaProducer<T> getKafkaBySchema(KafkaSerializationSchema<T> T){
Properties pros = new Properties();
pros.setProperty(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG,KAFKA_HOST);
return new FlinkKafkaProducer<T>(DEFAULT_TOPIC,T,pros,FlinkKafkaProducer.Semantic.EXACTLY_ONCE);
}
在主任务BaseDbTask中使用
//7. 将事实数据写回到kafka
FlinkKafkaProducer<JSONObject> kafkaBySchema = MyKafkaUtil.getKafkaBySchema(new KafkaSerializationSchema<JSONObject>() {
@Override
public void open(SerializationSchema.InitializationContext context) throws Exception {
System.out.println("kafka serialize open");
}
@Override
public ProducerRecord<byte[], byte[]> serialize(JSONObject jsonObject, @Nullable Long aLong) {
String sinkTopic = jsonObject.getString("sink_table");
return new ProducerRecord<>(sinkTopic, jsonObject.getJSONObject("data").toString().getBytes());
}
});
kafkaTag.addSink(kafkaBySchema);
2.2 测试
需要启动的服务
hdfs、zk、kafka、Maxwell、hbase,BaseDbTask.java
修改配置信息:gmall2021_realtime.table_process
INSERT INTO `gmall2021_realtime`.`table_process` (`source_table`, `operate_type`, `sink_type`, `sink_table`, `sink_columns`, `sink_pk`, `sink_extend`) VALUES ('order_info', 'insert', 'kafka', 'dwd_order_info', 'id,consignee,consignee_tel,total_amount,order_status,user_id,payment_way,delivery_address,order_comment,out_trade_no,trade_body,create_time,operate_time,expire_time,process_status,tracking_no,parent_order_id,img_url,province_id,activity_reduce_amount,coupon_reduce_amount,original_total_amount,feight_fee,feight_fee_reduce,refundable_time', 'id', NULL);表示表order_info有插入数据,就会同步到kafka中,topic为dwd_order_info。
启动kafka消费者,查看是否有数据进来
[zhangbao@hadoop101 root]$ cd /opt/module/kafka/bin/[zhangbao@hadoop101 bin]$ ./kafka-console-consumer.sh --bootstrap-server hadoop101:9092,hadoop102:9092,hadoop103:9092 --topic dwd_order_info最后启动业务数据生成服务:mock-db-0.0.1-SNAPSHOT.jar
记得先修改配置文件的生成日期:2021-09-12
最后查看kafka消费者可以看到有数据产生,说明流程已经走通。
3.算子选择简介
| function | 可转换结构 | 可过滤数据 | 侧输出 | open | 可以使用状态 | 输出至 |
|---|---|---|---|---|---|---|
| MapFunction | Yes | 下游算子 | ||||
| FilterFunction | Yes | 下游算子 | ||||
| RichMapFunction | Yes | Yes | Yes | 下游算子 | ||
| RichFilterFunction | Yes | Yes | Yes | 下游算子 | ||
| ProcessFunction | Yes | Yes | Yes | Yes | Yes | 下游算子 |
| SinkFunction | Yes | Yes | 外部 | |||
| RichSinkFunction | Yes | Yes | Yes | Yes | 外部 |
6.Flink实时项目之业务数据分流的更多相关文章
- 5.Flink实时项目之业务数据准备
1. 流程介绍 在上一篇文章中,我们已经把客户端的页面日志,启动日志,曝光日志分别发送到kafka对应的主题中.在本文中,我们将把业务数据也发送到对应的kafka主题中. 通过maxwell采集业务数 ...
- 3.Flink实时项目之流程分析及环境搭建
1. 流程分析 前面已经将日志数据(ods_base_log)及业务数据(ods_base_db_m)发送到kafka,作为ods层,接下来要做的就是通过flink消费kafka 的ods数据,进行简 ...
- 7.Flink实时项目之独立访客开发
1.架构说明 在上6节当中,我们已经完成了从ods层到dwd层的转换,包括日志数据和业务数据,下面我们开始做dwm层的任务. DWM 层主要服务 DWS,因为部分需求直接从 DWD 层到DWS 层中间 ...
- 10.Flink实时项目之订单维度表关联
1. 维度查询 在上一篇中,我们已经把订单和订单明细表join完,本文将关联订单的其他维度数据,维度关联实际上就是在流中查询存储在 hbase 中的数据表.但是即使通过主键的方式查询,hbase 速度 ...
- 4.Flink实时项目之数据拆分
1. 摘要 我们前面采集的日志数据已经保存到 Kafka 中,作为日志数据的 ODS 层,从 kafka 的ODS 层读取的日志数据分为 3 类, 页面日志.启动日志和曝光日志.这三类数据虽然都是用户 ...
- 9.Flink实时项目之订单宽表
1.需求分析 订单是统计分析的重要的对象,围绕订单有很多的维度统计需求,比如用户.地区.商品.品类.品牌等等.为了之后统计计算更加方便,减少大表之间的关联,所以在实时计算过程中将围绕订单的相关数据整合 ...
- 1.Flink实时项目前期准备
1.日志生成项目 日志生成机器:hadoop101 jar包:mock-log-0.0.1-SNAPSHOT.jar gmall_mock |----mock_common |----mock ...
- 11.Flink实时项目之支付宽表
支付宽表 支付宽表的目的,最主要的原因是支付表没有到订单明细,支付金额没有细分到商品上, 没有办法统计商品级的支付状况. 所以本次宽表的核心就是要把支付表的信息与订单明细关联上. 解决方案有两个 一个 ...
- 8.Flink实时项目之CEP计算访客跳出
1.访客跳出明细介绍 首先要识别哪些是跳出行为,要把这些跳出的访客最后一个访问的页面识别出来.那么就要抓住几个特征: 该页面是用户近期访问的第一个页面,这个可以通过该页面是否有上一个页面(last_p ...
随机推荐
- IE播放音频踩坑之路---待修改
在其他浏览器都是兼容的!在IE9就是显示一个黑色的框上面有个X 音乐无法播放 要显示播放界面的话,要添加 controls 属性(控件属性)例子:<audio src="xxx.m ...
- vue实现PC端分辨率适配
lib-flexible + px2rem Loader lib-flexible 阿里伸缩布局方案 px2rem-loader:px转rem: 依赖 首先需要安装 vue-cli 脚手架,这里我安装 ...
- hadoop入门到实战(6)hive常用优化方法总结
问题导读:1.如何理解列裁剪和分区裁剪?2.sort by代替order by优势在哪里?3.如何调整group by配置?4.如何优化SQL处理join数据倾斜?Hive作为大数据领域常用的数据仓库 ...
- Selenium_python自动化跨浏览器执行测试
Selenium_python自动化跨浏览器执行测试(简单多线程案例) 转:https://www.cnblogs.com/dong-c/p/8976746.html 跨浏览器测试是功能测试的一个分 ...
- Web开发之response
Web服务器收到客户端的http请求,会针对每一次请求,分别创建一个用于代表请求的request对象.和代表响应的response对象. 我们要获取客户机提交过来的数据,只需要找request对象就行 ...
- Linux命令(2)--cp拷贝、mv剪切、head、tail追踪、tar归档
文章目录 一.知识回顾 ls cd 二.Linux基本操作(二) 1.cp 拷贝 2.mv 移动(剪切) 3.head 头部 4.tail 追踪(尾部) 5.tar 归档 查看 压缩 解压 总结 一. ...
- 微信小程序云开发指南
一.初识云开发 官方文档 小程序·云开发是微信团队联合腾讯云推出的专业的小程序开发服务. 开发者可以使用云开发快速开发小程序.小游戏.公众号网页等,并且原生打通微信开放能力. 开发者无需搭建服务器,可 ...
- linux不使用useradd添加新用户
不使用useradd创建新的用户 1.进入用户特征信息:/etc/passwd 编辑: vim /etc/passwd 命令模式 :G 进入末行 进入编辑模式 :在最后添加新用户信息: 例:new_u ...
- 学习Java第4天
今天所作的工作: 1.类 2.类的构造方法 3.静态变量 4.类的主方法 5.对象 今天没有完成昨天的工作安排,因为发现进入类之后的编程思想发生的变化,相对与c++的逻辑既有较大的相似性又有不同的性质 ...
- js文件中三斜杠注释///reference path的用途
编辑某个js文件时,要想这个js文件出现其他js成员的ide提示,可以在js文件开头使用3个斜杠注释和reference指令的path指向此js文件路径,这样在编写这个js文件时,ide就会自动出现p ...