【沙龙干货】主题二:一个用户行为分析产品的设计与实现

分享内容


今天想跟大家分享一下我们目前推出的一个海量用户行为分析产品---“神策分析”的设计与实现。由于脱离需求和产品谈技术是不合时宜的,所以我首先会先讲一下我们产品所面临的用户需求,我们是如何根据这些用户需求来确定我们的产品设计,以及这些产品设计对于技术选型的一些要求,后面再详细讲一下我们产品整体架构和技术实现。

简单来看我们的产品面临的第一个需求,我们的客户普遍需要一个可以私有化部署的用户行为分析产品,这个需求是可以理解的,也是有很多实际的原因:首先是出于对数据安全和隐私的考虑;其次则是希望能够完成数据资产的积累;第三个则是希望可以对数据做深度的应用与二次开发,满足数据的更高阶的应用需求,而这些都是只有私有化部署才能够满足的。因此,私有化部署是客户对产品的一个非常实际的需求,也我们产品和技术上带来一些挑战。

首先我们做设计和开发的时候,需要考虑因为私有部署所带来的对运维、部署和设计的技术挑战,我们整个开发过程中,有至少三分之一的精力花在解决私有化部署带来的这些技术挑战上;另外一个方面,做整个产品架构设计的时候,就要考虑数据、API、计算和存储资源的开放,要让每个环节都能开放出去给用户使用;第三点,则是让我们决定整个架构以开源技术为主,如果选择一些非常冷门的技术,可能别人在这个基础上做二次开发是一个很难的事情;第四点则是为了满足客户的积累数据资产的需求,我们需要能够向用户提供明细数据,提供最细力度数据,这也是最终决定我们存储选型的一个关键性因素。

到了现在这个年代,特别是移动互联网、O2O已经蓬勃发展了这么多年,每一个产品的业务都越来越复杂,线下成分越来越重,因此全端的数据采集会是一个非常常见的需求。所谓的全端数据采集,就是要打通一个真实用户在不同端的行为,可能是iOS、安卓、Web、微信,也可能是业务数据库、第三方服务,需要能够把同一个用户在这些不同端的行为都贯通起来,一起进行分析和处理。为了满足的这一个需求,我们提供了各种不同的埋点和数据采集的手段,并且需要有一个技术手段来管理这些埋点。与此同时,我们也为客户提供了 ID-MAPPING 功能。在这里,我们对需求做了一个折中,为了保证我们的秒级导入时效性,ID-MAPPING不能向前回溯数据,因此我们选择了牺牲ID-MAPPING的部分功能而保留数据的导入时效性,这是一个客户需求与最终技术实现相互折中的一个最终例子。

我们目前有了如下的一些核心的技术决策,首先我们的产品要能私有化部署,并且花了很大的代价来解决运维的问题;其次,我们要做一个全开放的PaaS 平台,以开源技术为主,便于用户做二次开发;第三,我们要能够保证在十亿数据量下秒级导入、秒级查询的时效性。因此,我们最终没有选择预先聚合数据,而是存储明细数据,也就是说存储一条条最明细的数据,在 MOLAP 与 ROLAP 的抉择之间,我们选择了ROLAP的方案。

前边是对我们产品跟设计的一个简单的回顾,后面主要讲产品的具体技术实现。

我们在做客户端数据采集的时候,对于数据发送策略要做很多很多优化。我这里边详细列了一下我们目前所做的优化的策略,首先是我们整个数据采集策略的核心,以保证用户体验为核心,在用户体验和数据采集的时效性两方面的抉择上,宁愿牺牲部分数据采集的时效性,以保证不影响用户正常使用APP的体验。首先我们数据并不会逐条的实时的向后台发送,先在本地做缓存,网络情况比较好的时候才会往后面发送数据,发送数据的时候也会做一些打包压缩的情况。

后端日志也是比较常用的一种需要采集的数据。采集方案有两种,一种是在模块里面用代码的方式直接调用数据采用的API。之前我们提供了一整套日志打印的库,可以让这个日志直接打印到后台数据仓库里面,并且是以格式化的方式打印,从而保证一条日志在打印之后几分钟就已经能够被查询到。另外一种方案则是为了减少我们业务模块跟后面数据仓库的耦合性,会选择先在业务模块打印文本或者格式化的日志,然后用LogAgent 的方式将这些日志向数据仓库发送。

除了后端日志跟前端操作,业务数据也是一种比较常见的需要采集的数据源,主要通过工具采数据。

我们的数据接入层,因为我们要支持前端采集并通过公网传输数据,所我们的API采用了 HTTP 协议,所以这是一个很好的选择。

这里我们选择了Nginx做数据接入服务,在只需要接收 HTTP 请求并且打印日志的情况下,Nginx 可以保证很好的可靠性、很高的性能。能够很轻松满足单台接收十几万条用户行为的需求,能够满足绝大多数产品的需要。同时Nginx也能很容易做到负载均衡和服务冗余,这方面有很多成熟的方案。

然后我们有一个模块叫做 Extractor,它会实时读取和处理Nginx日志,然后把处理结果发送到kafka。

我们所有的数据都是要发到KAFKA,是一个高可用的数据分布式队列,用它是作为数据接入与数据处理之间的缓冲,也是数据的一个暂存,并且可以对外提供访问。

怎么样把KAFKA里面的数据实时写到我们的存储系统里面?

在存储上,我们选择了 Kudu 和 Parquet 两个存储方案。其中,Kudu 被我们用作 WOS,响应实时的写入。Parquet 被我们用作 ROS,保证良好的查询性能。下面是我们的整个存储写入的流程图。简单的来说我们有一个模块叫 KafkaConsumer,是一个常驻内存的 MapReduce程序,会实时地从kafka订阅数据,并将数据实时写入到Kudu中。在Kudu中有两类表,一类是正在被写入,另一类则是不再被写入。当一张表的写入数据量达到阈值时,它就不再会被写入,而是会写入新的表中。每一个不再被写入的 Kudu 表,都会被一个后台程序转换成Parquet文件,并且移动到相应的一系列Partition中。由于这种操作过程,每一个Partition下都可能会有一系列碎文件,则我们后台会有一个定时的 MapReduce程序,用来将碎文件合并成理想大小的文件,目前我们在多次尝试后,选择了 512MB 作为一个比较理想的文件大小,从而提高查询和扫描的速度。

我们跟用户打交道的一个模块是WebServer,它是用来转发前端查询请求的,会接收客户通过我们前端发送过来的查询请求。当然,前端也提供了相应的 API,以满足客户的二次开发需求。WebServer会把这个查询请求转发给QueryEngine,后者会将查询请求翻译成SQL提交给Impala。Impala是一个目前很流行的 MPP 架构的分布式计算系统。前面我们提到,数据是存储在Kudu和Parquet两个存储体系里面,所以在这里我们将他们构建了一个视图,让Impala直接在这个视图上面进行查询,然后把查询的结果返回给前端。

原文发布于微信公众号 - 美团点评技术团队(meituantech)

原文发表时间:2016-08-05

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏跟着阿笨一起玩NET

C#巧用Excel模版变成把Table打印出来

转载:http://blog.csdn.net/gwblue/article/details/38865525

1152
来自专栏积累沉淀

Hive2.0.0操作HBase 1.2.1报错解决

首先看错  org.apache.hive.service.cli.HiveSQLException: Failed to open new session: ...

2329
来自专栏跟着阿笨一起玩NET

[C#]工具类—FTP上传下载

  不错的文章:http://www.cnblogs.com/greatverve/archive/2012/03/03/csharp-ftp.html

1151
来自专栏跟着阿笨一起玩NET

C# 通过HttpWebRequest在后台对WebService进行调用

http://www.cnblogs.com/macroxu-1982/archive/2009/12/23/1630415.html

2742
来自专栏阿炬.NET

c# datetime 格式化

2836
来自专栏码匠的流水账

聊聊spring cloud的AbstractLoadBalancingClient

本文主要研究一下spring cloud的AbstractLoadBalancingClient

832
来自专栏成长道路

JDBC动态SQL语句连接orcale数据库的工具类

import java.sql.Connection; import java.sql.DriverManager; import java.sql.P...

2450
来自专栏海说

Java应用中常见的JDBC连接字符串(SQLite、MySQL、Oracle、Sybase、SQLServer、DB2)

Java应用中常见的JDBC连接字符串 Java应用中连接数据库是不可或缺的,于是便整理一些可能用到的JDBC的jar包及其相匹配的URL,以备日后查阅。 1)...

2710
来自专栏谈补锅

记录C#常用的代码片段

using Newtonsoft.Json; using Newtonsoft.Json.Linq;

912
来自专栏闻道于事

商城项目整理(三)JDBC增删改查

商品表的增加,修改,删除,订单表的增加,确认,用户表的查看,日志表的增加,查看 商品表建表语句: 1 create table TEST.GOODS_TABL...

5435

扫码关注云+社区