点击标题下「蓝色微信名」可快速关注
Lead
上篇文章我们聊到了《用户行为数据收集系统之客户端SDK设计》,详细介绍了客户端SDK的设计要点和运行过程。客户端的功能设计,主要是为了服务端可以更加方便地进行数据处理和分析。今天我们将来探讨下,数据接收端该如何设计。
数据接收端的核心功能是高效稳定地接收网络请求发送来的用户数据,并顺利传递给下一阶段服务。下面我们将从其核心功能、困难、挑战三个维度来讲解其设计,并以笔者所在公司的实现方案为例讲解实现细节。
1高性能
数据接收端面临的问题是需要同时接收成千上万,甚至几十上百万设备源源不断地上传过来的数据,并且需要快速响应,完成数据的接收并返回状态信息给客户端。否则的话,会引起日志堆积,不断积累压力,最终导致服务崩溃。因此,高性能是其最基础的考虑要素。基于上述要求,单机的设计方案显然是容易出现瓶颈的,因此通常采用分布式架构的方式,这样既易于通过水平扩展的方式来提升性能,同时也可以降低对单台服务性能的要求。
2稳定性
采用分布式架构设计,服务稳定性问题就会显得尤为重要。因为数据接收服务,面临的是大量设备以及源源不断的流量,因此如果个别节点出现宕机,就意味着其他节点需要扛住原本宕机节点承担的流量,如果继续再有节点宕机,而其他节点处理能力饱和,则极有可能出现雪崩问题。笔者公司就遇到过这个问题,后文中会详细介绍其发生原因及过程。在处理这个问题上,笔者公司采取的策略是一方面精简服务,尽量不做复杂的处理,把一些不必要的处理工作交给下游服务去做,另一方面实现动态扩容,当监测到集群压力过大时,自动增加节点来分担压力,从而尽可能提升稳定性,避免雪崩发生。
3数据校验
在上篇文章中,我们提到脏数据的混入容易造成数据污染,导致数据质量下降,从而影响数据分析,可能引发决策偏差。因此,服务端需要对数据做基础的校验。具体的校验策略,需要根据数据的保密程度和重要程度来定。在笔者公司,使用了加盐MD5的方式,客户端和服务端维护相同秘钥,客户端使用秘钥利用MD5算法生成校验码,在服务端使用相同秘钥相同方法也生成一个校验码,比较两个校验码,如果一致则通过,如果不一致则剔除。如果数据的安全程度较高,可以采用一些不是很耗性能的加密算法,如DESRT4等。
4扛高并发&可扩展性
大部分的应用都会存在使用高峰的情况,这时使用人数达到最高,操作频率也会很高。这时产生大量数据流量的同时,并发数也会大幅提高,这对服务端是个巨大考验。高并发场景发生时,数据接收服务端,必须要保证服务响应及时,可建立连接数充裕,否则也是容易引发雪崩的。扛高并发的手段,除了提升单台服务的连接处理效率,还可以通过横向扩展分布式服务集群的方式提升并发能力,因此架构设计时,要兼顾可扩展性,实现短时间内简单方便得扩展集群能力。
5分流&分级
分流主要包含两个方面,一是总体流量的分流,大量设备的海量数据,需要经由不同的接入IP到达服务端;二是服务端流量分流,确保每个接收服务处理大致相同的流量,避免数据倾斜的发生。总体流量分流,可以采用多域名策略、DNS服务多个A记录(IP地址)轮询策略等来实现,从而突破单个IP的网络资源限制。服务端流量分流,通常的策略是使用负载均衡服务,来实现流量的均衡分发。
与此同时,服务端接收到数据后,针对不同的日志,需要进行分级操作,这样才能区分对待处理。对于重要程度高、时效性强的数据,可以获得更多资源,尽快处理,提升数据的价值。
6数据的下一步流向
数据流向和具体业务有很大关系,常见的方式有直接落地存储(文件)、进入消息队列(如kafka)、进入数据库(如时序数据库)等。笔者公司采用的是直接落地存储为文件,这和具体的业务场景及对数据如何使用关系密切,后文中会详细解释。
由于数据接收端与具体的业务要求关系密切,不同的业务对数据的实时性、存储和结构要求差异很大,因此实现方案也会相差较大。以下,笔者以自己公司的业务场景为例,简单介绍下我们的实现方案。
首先,我们使用到了上篇文章中讲解的客户端SDK,在其进行日志上传时,先会经过域名解析过程,每个产品都对应一组域名,每个域名都对应30个服务端IP,以此实现流量的分流。当流量到达服务端时,首先是被负载均衡服务集群接收到,然后转发给具体的接收服务,这里采用的是轮询转发的策略,以保证流量到达服务时是均衡,不会出现数据倾斜,所有服务承担近似的压力。接收服务是通过nginx+lua实现的,非常轻便高效,实现简单且非常高效,并且nginx扛并发的能力也是非常给力的。nginx在接收到数据后,会调用Lua代码块进行数据合法性校验、分级等处理,之后通过access_log模块写入文件,这样设计的原因是保证数据及时保存,即使下游出现严重故障,至少数据不会丢失。日志文件会有两个去处,一是定时上传到HDFS供离线分析使用,另一个是由文件流化组件filebeat写入消息队列kafka,供实时分析使用。
1流量雪崩
在方案实行之初,由于对特殊情况发生的考虑和准备不足,在一次晚高峰期间,由于机房内部网络不稳定和网络拥堵,导致服务端响应变慢,客户端未能在超时时间内收到响应,触发了失败重传机制,又重新上传一次,结果可想而知,服务端相继宕机,出现雪崩,服务陷入瘫痪。最后的解决方案是,待机房网络恢复后,加大网络带宽,增多接收服务节点,重启服务,由于客户端有失败重传机制,所以数据只有极少量丢失,重复上传的数据采用客户端预先设计的去重字段在后续的数据处理过程中完成去重。
2转义字符
由于使用nginxaccess_log模块来将数据写入文件,在低版本nginx中,对引号、反斜杠等都会转义,以十六进制的形式写入日志文件,导致日志文件增大很多,磁盘IO变大,服务性能一直提升不上去。针对这个问题,我们采用的方案是,升级了nginx的版本,使用escape特性,并修改了nginx中关于json转义的源代码,实现了将转义字符还原为真实字符,日志文件的大小减少了约30%,上传到HDFS的时间,比原来缩短了约50%,性能提升明显,延时大大缩短。
结语
本文介绍了数据接收端设计的一些核心功能点和注意事项,并以笔者公司为例,介绍了其中一种实现方案,希望对大家有所启发。下一篇我们将一同探讨下,高可用性及监控的具体设计。
推荐阅读
互联网从业人必须知道的「用户行为数据收集系统」
用户行为数据收集系统--(2)客户端SDK设计
推荐系统评估
更多精彩内容
长按扫码可关注
继续阅读
阅读原文