生产实践 | Flink + 直播(二)| 如何建设实时公共画像维表

技术架构

附上一篇。

生产实践 | 基于 Flink 的直播实时数据建设 (一)| 需求和架构篇

回顾上一节的 「技术架构」 图。

img

技术架构

从数据源到数据处理以及最后到数据汇部分,整个架构相对来说是比较好理解的。

img

但是大家的疑惑点可能就集中在三个维表的建设上,包含 「主播用户画像维表,观众用户画像维表,直播间画像维表」

img

技术架构

我们依然从以下几个角度的问题出发,通过分析场景,解答这几个问题来给大家介绍以上三个维表的建设过程。

Question

  • 「WHAT:直播实时公共画像维表是指什么?离线公共画像维表又指什么?区别?」
  • 「WHY:为什么架构图中的三类公共画像维表要按照实时和离线进行划分?为什么需要建设实时公共画像维表,离线公共画像维表不能满足需求?」
  • 「HOW:怎样才能建设满足直播实时数据的实时公共画像维表?」
  • 「WHO:需要使用什么样的组件建设直播实时公共画像维表?为什么选用这些组件进行建设?」

WHAT:实时 & 离线公共画像维表?

概念

首先简单介绍下, 「实时 & 离线公共画像维表」中存储的内容就是一个实体的其他固有属性(比如用户实体的年龄等),在我理解这两个概念本身是抽象的概念,本文中介绍的「主播用户画像维表,观众用户画像维表,直播间画像维表」 是其具体实现。

其他大佬的文章解释中会对 「实时公共画像维表」 & 「离线公共画像维表」 有更加深度的理解,这里我只说明我在直播实时数据建设过程中的理解~

img

区别

其实这两个词的区别从名字上就可以区分出来,实时公共画像维表和离线公共画像维表的最大区别就是数据建设和应用场景要求的 「时效性」 不同。

离线公共画像维表

特点:

  • 「场景」:适合离线场景,「时效性要求比较弱」 的场景,为指标提供画像维度填充或者打标服务
  • 「建设」:一般都是以离线 t + 1 的方式进行建设
  • 「应用」:使用的数据为离线 t + 1 的数据
  • 「举例」:数据仓库中的用户画像维表,为应用层数据提供画像服务;比如不但需要统计总 uv,还需要统计分年龄段的 uv。

实时公共画像维表

特点:

  • 「场景」:适合实时场景,「时效性要求比较强」 的场景,为指标提供画像维度填充或者打标服务
  • 「建设」:实时的进行建设,延迟一般在秒级别
  • 「应用」:使用的数据都是实时建设好的,必须可以实时获取(秒级别延迟后获取到)并使用

WHY:为什么建设实时公共画像维表?

为什么架构图中的三类公共画像维表要按照实时和离线进行划分?为什么需要建设实时公共画像维表,离线公共画像维表不能满足需求?

这几个问题其实围绕着我们的直播实时数据建设以及应用的场景就可以展开解答。

img

接上篇技术架构图,其中直播实时数据需要建设的公共维表分为以下三类:

  • 「直播间画像维表」:包含直播对应的直播类别、开播客户端、标题、开播地址等信息
  • 「主播画像维表」:主播对应的主播名、主播类别、性别、年龄段等
  • 「观众画像维表」:观众对应的观众性别、年龄段等

直播间画像维表

首先抛出结论: 「直播间画像都是直播间的固有属性画像,直播间画像维表的建设过程是实时的」

由于大多数直播的时长都在几小时不等,随着直播的开始,主播域观众的互动也随即产生,从而直播生产和消费的指标也开始产出,随着直播的结束,主播和观众的互动也就结束了,对应的直播生产和消费指标也就不存在了,因此直播间画像的所能提供给其他指标作为维表的价值也就快速消失了,所以直播间画像(标题,开播地址)的应用场景特点就是 「时效性很强」 。因此直播间画像维表对于直播生产消费指标的建设和应用来说,需要满足可实时建设、可实时查询获取的要求。

主播 & 观众用户画像维表

结论: 「这类画像都是用户的固有属性画像,而非直播间固有属性,和直播间是非强相关的。主播 & 观众用户画像维表的建设过程可以是离线的」

无论直播间的开播关播,直播过程中的生产消费,主播画像和观众画像基本上不会产生变动。(举例:大多数情况下,当已经判定一个用户的年龄段画像为 18 - 23 时,即使这个用户开了 10 场直播,或者这个用户观看了 10 场直播,其年龄段判定也基本不会有变化)。因此主播用户画像维表 & 观众用户画像维表对于直播生产消费指标的建设和应用来说,可以满足离线 t + 1 建设,提供数据服务进行实时获取的要求。

❝Notes: 主播 & 观众用户画像需要根据用户生产消费行为以及其他信息,使用到机器学习进行性别和年龄段等的用户画像信息判定产出。也有非常多的场景将这类画像进行实时建设,用于实时个性化推荐等。只不过本文的直播实时数据建设对于这两类画像的时效性要求较弱,所以采用了离线的方式进行建设。 ❞

HOW + WHO:怎样建设?用什么建设?

直播间生命周期 & 数据流转

直播间整个生命周期如图所示。

img

生命周期

  • 1.主播创建直播间,直播间进入开播的状态;
  • 2.观众进入直播间后,在直播间内与主播进行互动;
  • 3.最后就是主播对直播间进行关播,标识着直播间生命周期的结束状态。

直播间画像维表-实时

实时画像维表的建设。上图中 「红色」 的字体为实时画像维表的建设和应用过程。

直播间画像实时数据流转

  • 1.当主播开播,直播间进行直播后,直播间产生了直播间画像信息,这时可以将画像信息实时的建设到直播间画像实时维表中。并且可以同时建设生产侧的实时指标,利用建设好的 「直播间画像实时维表 + 主播 & 观众画像离线维表」 进行生产侧指标的维度填充;
  • 2.当观众进入直播间后,与主播进行互动,产生一系列的消费行为,随即可以建设消费侧的实时指标,利用建设的 「直播间画像实时维表 + 主播 & 观众画像离线维表」 进行消费侧指标的维度填充;
  • 3.当主播对直播间进行关播的时候,从直播间画像实时维表中就可以对该直播间的画像进行删除。

组件选型

通过上文的分析,可以了解到直播间画像实时维表建设的要求如下:

  • 实时画像:支持实时建设,实时访问;
  • 实时画像:建设的直播数据都为实时指标,即要求低延迟的访问响应时间(毫秒级别);
  • 公共画像:需要支撑多个大流量生产消费实时任务的访问请求,即提供高 QPS 画像数据服务;
  • 公共画像:高稳定性。

因此组件选型就自然落在了高速缓存的范畴中,我们最后经过方案对比之后,选择了 redis 作为我们的实时维表的存储引擎。

img

使用了 redis 中的 hash 作为维表存储结构,其中直播间画像维度存储设计如下图。

img

维度存储

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
public class LiveStreamRealtimeDimBuilderJob {

   public static void main(String[] args) throws Exception {
       final StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();

       DataStream<byte[]> source = SourceFactory.getSourceDataStream();
       source.process(new ProcessFunction<byte[], String>() {
           @Override
           public void processElement(byte[] bytes, Context context, Collector<String> collector) throws Exception {
               CommonModel c = CommonModel.parseFrom(bytes);
               // 开播
               if (c.isStartLiveStream()) {
                   RedisConfig
                          .get()
                          .hmset(c.getLiveStreamId()
                                  , ImmutableMap.<String, String>builder()
                                          .put("type", c.getType())
                                          .put("client", c.getClient())
                                          .put("title", c.getTitle())
                                          .put("address", c.getAddress())
                                          .build()
                          );
                   RedisConfig
                          .get()
                          .expire(c.getLiveStreamId(), 30 * 24 * 60 * 60);
              } else if (c.isEndLiveStream()) {
                   // 关播
                   RedisConfig
                          .get()
                          .expire(c.getLiveStreamId(), 2 * 24 * 60 * 60);
              }
          }
      });

       env.execute();
  }

   @Data
   public static class CommonModel {
       private String liveStreamId; // 直播间 id
       private String type; // 直播间类型
       private String client; // 开播客户端
       private String title; // 直播间标题
       private String address; // 直播间开播地址

       public static CommonModel parseFrom(byte[] bytes) {
           // 逻辑根据业务逻辑判定
           return null;
      }

       public boolean isStartLiveStream() {
           // 逻辑根据业务逻辑判定
           return false;
      }

       public boolean isEndLiveStream() {
           // 逻辑根据业务逻辑判定
           return false;
      }
  }
}

主播 & 观众用户画像维表-离线

离线画像维表的建设。主要包含主播和观众的用户画像,性别,年龄等信息。如下图 「蓝色」 的字体为离线画像维表的应用过程。

img

生命周期

主播 & 观众画像数据流转

在产出直播间生产侧、消费侧实时数据时,使用主播 & 观众画像进行了画像维度填充。

存储组件

其中离线画像维表的存储组件选型与实时相同,同为 redis,画像信息存储方式也是使用 redis hash 结构进行存储。

以 t + 1 离线的方式进行画像数据建设并进行数据同步,将建设好的全量主播和观众用户画像同步到 redis 高速缓存当中。

总结

本文衔接上文,介绍了实时 & 离线公共画像建设的整个过程。提出几个建设的问题,以这几个问题出发,主要引出了一下三小节。

第一节简单介绍了实时 & 离线公共画像维表的概念。

第二节从数据应用场景的角度出发,介绍了为什么需要建设实时的公共画像维表。

第三节主要介绍了实时画像维表的建设过程以及详细的技术方案。

最后一节对本文进行了总结。

如果你也建设过实时画像维表,或者有相同的需求,欢迎留言或者留下你的文章链接,相互交流~