Flink实战 - 利用SessionWindow处理直播间用户心跳数据
1.SessionWindow 介绍
先看看Flink提供的多种计算窗口
- countWindow:基于数据,根据数据的条数来划定一次聚合计算范围。
- timeWindow:根据时间划分聚合计算的范围。
timeWindow又分为三种:
- Tumbling window 滚动窗口
- Sliding Window 滑动窗口
- Session Window 会话窗口
其他窗口不再叙述,主要说说SessionWindow。
先说下session,web开发中,服务器会给每个用户浏览器创建一个session(会话对象),用户的状态都会在这个session中保存,这样我们不需要重复登录就可以做一些操作,当用户的操作停止了一定的时间后,该session会失效,表示一个session的结束。
流计算的是无界的,但是很多场景下,数据的计算周期还是有范围的。根据上述session的特性,flink提供了一个Session Window,每个窗口的划分范围为一簇数据从开始出现到最后一次出现之间的所有数据。
2.数据需求
- 用户在观看直播间时,进入直播间的这个事件可以在业务逻辑中进行判断,退出直播间在正常情况下,也可以在业务逻辑中判断。但是会出现非正常的情况,比如我每次停止使用一个APP时,最简单的方式就是杀死这个APP,而不是正常的退出操作,还有其他的情况,比如没话费断网了,家里停电WiFi断掉了,就没法正常统计用户观看时长。
- 实时观看直播间的uv,就是实时统计直播间有多少用户在观看。这时如果有1中所述的情况,就会出现无法正常的判断观众退出,uv的数据会不准确。
- 用户足迹,当我观看一个直播间的时长超过1分钟,那么表示我可能喜欢这个直播间,就会把这个APP记录到我的观看记录中,方便后续直接进入。
3.需求分析
- 用户的每个心跳数据进行累计,但用户退出直播间时,可以计算他的停留时长,这样也可以解决第三个问题。
- 第二个需求是需要实时统计有多少人在,这时就需要统计有多少人还在直播间观看,第一步就是要先记录在观看的人数,然后还需要统计退出直播间的人数。这里需要注意的是怎么去获取用户进入直播间和退出直播间的事件。
4.数据的处理
- 源数据:
心跳数据:每个用户在每个直播间,每10秒发送一次心跳数据,其中包含了用户、主播、直播间的信息,还有每次的心跳时间。
数据存储:心跳数据量很大,可以放在高吞吐的kafka中。
心跳数据格式:
{
"userId": 10000,
"liveRoomId": 123456,
"broadcasterId": 100002,
"scene": 2,
"heartTimestamp": 1592106002035,
"roomType": 2,
"userIp": "192.168.1.1",
"liveScene": 123
}
- 程序处理
源数据对应的Java类,用户每次心跳的数据信息,这里只列举本次能用到的字段
public class UserHeart implements Serializable {
/** 用户id */
private Long userId;
/** 直播间id */
private Long liveRoomId;
/** 直播间主播id */
private Long broadcasterId;
/** 心跳场景:1直播心跳、2观众心跳 */
private Integer scene;
/** 心跳时间:ms */
private Long heartTimestamp;
/** 直播间类型 */
private Integer roomType;
/** 客户ip */
private String userIp;
/** 直播间开播场次 */
private Integer liveScene;
}
需要计算用户心跳数据,就需要其他的一些属性,比如每次进入直播间后第一次心跳为首次心跳时间,最近的一次心跳为最近的心跳时间(退出直播间为退出直播间时间)。
消费kafka中的数据并将json转为对象
// kafka 数据读取,具体配置依照具体情况来定
Properties kafkaSourcePro = new Properties();
kafkaSourcePro.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, "192.168.1.100:9092,192.168.1.101:9092,192.168.1.102:9092");
kafkaSourcePro.put(ConsumerConfig.SESSION_TIMEOUT_MS_CONFIG, 30000);
kafkaSourcePro.put(ConsumerConfig.MAX_POLL_RECORDS_CONFIG, 100);
kafkaSourcePro.put(ConsumerConfig.GROUP_ID_CONFIG, "heart-kafka-group");
// 获取心跳源数据
SingleOutputStreamOperator<String> odsUserHeartStream = env.addSource(new FlinkKafkaConsumer011<String>("user-heart-topic", new SimpleStringSchema(), kafkaSourcePro));
// 心跳源数据转换成UserHeart对象
SingleOutputStreamOperator<UserHeart> userHeartStream = odsUserHeartStream
.filter(StringUtils::isBlank).name("filter-stringisnull")
.map(a -> JSONObject.parseObject(a, UserHeart.class)).name("userheart-map").uid("userheart-map");
过滤出观众的数据,并转成方便统计心跳的对象(此处的逻辑也可以在UserHeart对象中完成,但是为了将每个步骤都体现出来,因此创建了UserStayTime对象)转换为UserStayTime 对象,UserStayTime 类继承了UserHeart 类。
UserStayTime 类:
public class UserStayTime extends UserHeart {
/** 本次进入直播间的首次心跳时间 */
private Long startTime;
/** 本次进入直播间的最后一次心跳时间 */
private Long endTime;
/** 统计进入直播间后一共有多少次心跳 */
private Long heartCount;
/** 在直播间时长 */
private Long stayTime;
/** 用户进入直播间事件:1,用户退出直播间:2 */
private Integer eventType;
}
所有的心跳数据过滤出观众的心跳数据并转换。此处只是将心跳数据格式作了个转换,

最低0.47元/天 解锁文章
262

被折叠的 条评论
为什么被折叠?



