写点什么

《Spotify 的入云之旅》系列之一——事件传输系统

2016 年 5 月 02 日

写在之前

当 Spotify 的用户打开客户端听歌或者搜索音乐人,用户的任何一个触发的事件都会传送回 Spotify 的服务器。事件传输系统(也即,日志收集系统)是个有趣的项目,确保全球用户使用 Spotify 客户端所产生的事件都完全、安全的发送到数据中心。在本系列文章中,将讲述 Spotify 在这方面所做过的工作,而且会详细解说 Spotify 新的事件传输系统架构,并回答“为什么 Spotify 会基于 Google 云平台管理建立自己的新系统?”。

在本文章中,首先会阐述当前事件传输系统是如何工作,并分享一些在此架构下的实践经验;在下篇文章里,将描述新事件传输系统的架构设计,更进一步的,解释 Spotify 为什么会选择 Google 云平台的 Cloud Pub/Sub 服务作为所有事件的传输机制;在第三篇,将展示 Spotify 公司如何消费从 Google 的 DataFlow 订阅的事件数据,并分享 Spotify 技术团队采用这一方案的经验总结。

Spotify 的事件传输系统有很多用途,Spotify 大部分产品的设计策略是基于 A/B test 的结果,而这些 A/B test 得依赖于海量、精确的用户数据。Spotify 2015 年发布最受欢迎的特色功能之一是“Discover Weekly”播放列表,它是基于 Spotify 用户播放数据。“Year in music”、“Spotify Party”等其他特色的模块都是对用户播放数据进行数据分析的结果,同时 Soptify 的用户数据也是 Billboard 榜单的数据源。

事件传输系统是 Spotify 公司数据基础设施,它能保证数据以预期的延迟时间完整的传输,并且通过事先定义好的接口发送数据给开发者。用户数据是开发者事先埋点用户点击后产生的结构化数据。
Spotify 大部分事件都是响应用户在 Spotify 客户端的行为而触发的事件,事件在客户端发生后通过日志收集系统 syslog 发送到 Spotify 网关,这些数据通过事件传输系统时都会记录时间戳。为了能监测事件传输和事件传输的完整性,事件记录采用 syslog 时间戳而不是事件在客户端发生的时间戳,因为在事件传到 Spotify 服务器前是无法控制事件。

在 Spotify 公司,所有的用户数据需要发送到中心的 Hadoop 集群。Spotify 收集数据的服务器位于两个州的多个数据中心,但是数据中心之间的带宽是紧缺的资源,因此需要时刻监控带宽的占用情况。
数据接口是根据存储数据的 Hadoop 的位置和存储的格式来定义的,Soptify 所有通过事件传输服务传输的数据都是以 Avro 格式存储在 HDFS 上。传输的数据都是以小时来分桶,这么做的原因是系统遗留问题:Spotify 公司第一个事件传输系统是简单的用 scp 命令,然后按小时从所有的服务器上把 syslog 文件复制到 Hadoop 集群。现在 Spotify 公司所有的数据任务还是按小时分片的,这种接口形式预期将来一段时间还是不会变。

Spotify 的大部分数据读取任务是从小时桶里读取一次。一个 job 的输出会作为另外一个 job 的输入,这样形成一个长的转运 job 链。中间传输的 job 每小时传输一次,并且不做任何数据检查,即使在数据操作的过程中数据源发生了变化。一般出现小时桶里的数据发生变化需要手动去强制启动整个 job 链,相应的下游 job 就会按指定的时间运行。显然地,这是一个耗时耗力的处理过程,并且没有数据回滚的机制,因此需要一个事件传输服务来解决这个问题。数据完整性问题同时也带来的数据传输的延迟,你可以从 Google 的 Dataflow 论文里看到对数据完整性问题的有意思的看法。

当前使用的事件传输系统

系统设计

现在 Spotify 公司生产环境上使用的系统是基于 Kafka 0.7 版本。

(点击放大图像)

图1: 基于Kafka 0.7 点事件传输系统架构图

Spotify 线上运行的事件传输系统是按每小时文件抽象所设计的,它支持从服务器到 HDFS 的流式日志文件,包含事件数据。当所有的日志文件按小时传输到 HDFS 上的过程中会做一个日志格式转化,将原始的 Tab 键分隔的文本转化成 Avro 格式。

当线上正运行的事件传输系统上线时,Kafka 0.7 版本的 Kafka Broker 集群还未能实现稳定的持久化,这导致数据生产者、Kafka Syslog 生产者和 Hadoop 集群之间不能进行持久化。所以等到事件数据写入文件或者 HDFS 才能认为数据已经持久化了。

事件数据到达 Hadoop 集群并不能达到可靠的持久化,这里又面临一个问题:事件传输系统中 Hadoop 集群的单点问题,如果 Hadoop 集群宕机则事件传输系统即挂掉。为了解决这一问题,Spotify 公司确保所有收集事件数据的服务器上有足够多的磁盘空间,当 Hadoop 集群挂掉了,事件数据先缓存到服务器上,等 Hadoop 集群恢复后立即传输所有数据,这种传输策略到恢复时间主要受限于两个数据中心的带宽。

每个服务主机上都有一个 Producer 守护进程,它监控这日志文件并按行批量发送日志数据到 Kafka Syslog 消费者。Producer 并不会关注事件类型或者事件属性,它仅仅把区分日志文件的行数据,并且把所有数据发送到相同的 channel。这意味着所有的事件类型都包含在相同的日志文件里,并且发到同一个 channel 里。Producer 发送日志到 Consumer 后,需要等到 Consumer 成功的把日志持久化到 HDFS,并返回 ACK 给 Producer。当 Producer 收到成功的 ACK 后继续发送后面的日志。

Producer 上的事件数据传到 Consumer 需要经过 Kafka Brokers 和 Kafka Groupers。Kafka Brokers 是 Kafka 的标准组件,而 Kafka Groupers 是由 Spotify 工程师开发的,Grouper 消费本地数据中心的所有事件数据,并进行压缩、批量的发送到 Consumer 的单个 topic。

接下来是数据清洗(ETL)的过程,将 Tab 分隔的文本文件转化成 Avro 格式。这个 job 只是一个常规的 Hadoop MapReduce 任务,采用 Crunch 框架开发。
所有的 Producer 都会持续发送文件结束标记的检查点信息(checkpoint),当一个文件全部持久化到 Hadoop 集群后,Producer 会有且仅有发送一次文件结束标记。生命周期监控持续不断的去查询各数据中心的服务发现系统,探测在某个小时内服务器是否在线。为了确定某个小时的数据是否全部传送到数据中心,ETL 任务会去校验服务器文件的结束标记,如果 ETL 的 job 探测到数据未全部收到,它会延迟处理当前小时到数据。

为了最大化利用 mapper 和 reducer,ETL 的 job 需要知道如何共享输入数据,并且基于Consumer 传过来的事件数来优化共享。

总结

上述事件传输系统的设计主要缺点之一:本地Producer 需要确认发送的数据被持久化存储的数据中心位置。在美国西海岸的服务器,Producer 需要知道数据什么时间写入到London 数据中心。大部分情况下系统工作正常,一旦传输变慢将引起传输延迟并很难恢复。

对比这个问题,需要将转移点放在本地数据中心,这简化里Producer 的设计,只要数据中心的网络正常即可。

暂且放下这些问题,接下来计划构件一个事件传输系统能够可靠的每秒钟推送70 万个事件。重新设计这个事件传输系统同时给Spotify 团队一个机会提高软件的开发过程。

所有的事件一起发送到相同的channel,这会失去对不同QoS 的事件流的灵活管理。同时也会限制实时数据使用,因为任何实时的消费者需要过滤数据,仅仅获取有用的信息。

发送非结构化数据会带来不必要的延迟,因为清洗任务会带来额外的数据转移,当前运行的事件传输系统,清洗任务在处理非结构化数据会多好使大概30 分钟。如果发送的数据是结构化的Avro 格式,当被写入HDFS 会立即处理完。

跟踪处理的数据要按小时完整的数据会引起问题,例如,当机器挂掉,不能发送文件结束的标记。如果有一个缺失的文件结束标记,其他任务需要等到人为的处理才会继续工作。当机器的数量增长时,这个问题变得更明显。

下一步要做的

在Spotify 公司,传输的事件数据在不断的增长。同时系统的负载也在不断的增加,开始经历机器掉电,掉电掉数目开始警告大家,并且意识到系统在负载不断增加的情况下不能维持太久,见图2。

(点击放大图像)

图2

不幸的是,当前线上的事件传输系统已不能再通过迭代开发的方式得到提高了。留在前面唯一能解决问题的方法是重写事件传输系统。


感谢杜小芳对本文的策划和审校。

给InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家通过新浪微博( @InfoQ @丁晓昀),微信(微信号: InfoQChina )关注我们。

2016 年 5 月 02 日 17:451121
用户头像

发布了 43 篇内容, 共 24.3 次阅读, 收获喜欢 4 次。

关注

评论

发布
暂无评论
发现更多内容

开发更便捷 阿里云推出一站式应用研发平台EMAS 2.0

应用研发平台EMAS

阿里云 Serverless AI 低代码 移动研发平台

Java Optimizing 读书笔记(一)

绝影-大数据

量化策略交易软件开发|量化策略交易系统APP开发

开發I852946OIIO

系统开发

比特币矿机工作原理

v16629866266

比特币 比特币区块链

WiFi6 与 5G 的异同分析

石君

5G wifi 28天写作

红牛交易所app系统开发

威掂l8929545452

区块链 系统开发 APP开发 红牛交易所

组织部干部信息管理系统开发方案,智慧党建平台建设

WX13823153201

智慧党建平台建设

自动驾驶汽车的发展史

anyRTC开发者

人工智能 自动驾驶 AI

区块链轻节点:“身”轻,责任重

华为云开发者社区

区块链 数据 数据隐私 轻节点

TypeScript 渐进迁移指南

LeanCloud

JavaScript typescript nodejs

OpenYurt v0.3.0 重磅发布:全面提升边缘场景下应用部署效率

阿里巴巴云原生

阿里巴巴 容器 云原生 k8s 开源项目

百度研究院的追星逐浪,中国科技的奋发自强

脑极体

BI项目失败?看看是不是缺少了这几项闭环!

博文视点Broadview

在函数计算中到底该不该使用 VPC?

donghui

Serverless

量化交易系统开发

威掂l8929545452

区块链 系统开发 量化交易系统 交易所

Intel首次公布11代酷睿桌面处理器性能:8核i9斩落锐龙12核

科技新消息

为什么说“5G是第四次工业革命”,到底有哪些推动和影响?

一只数据鲸鱼

5G 物联网 数据可视化 工业物联网

避免短信接口被黑客刷取的方法

香芋味的猫丶

短信防刷 接口安全 短信验证码 短信防轰炸 短信防火墙

Redis 学习笔记 03:字典

架构精进之路

redis 七日更 28天写作

Serverless 架构到底要不要服务器?

Serverless Devs

Java 云计算 Serverless 运维 云原生

53w字!阿里首推系统性能优化指南太香了,堪称性能优化最优解

程序员小毕

Java 架构 性能优化 JVM 代码优化

数据库表数据量大读写缓慢如何优化(2)「查询分离」

我爱娃哈哈😍

数据库 大数据 架构 后端 优化

百度智能小程序打造购票观影一站式体验,影视宣发新玩法助力行业复苏

DT极客

干货来袭!拼多多首推全新微服务进阶指南(全彩版)简直不要太香

程序员小毕

Java 架构 微服务 springboot SpringCloud

如何利用策略模式避免冗长的if-else/switch分支判断代码?

码农架构

Java 学习 设计模式

高并发架构---TCP

赖猫

TCP 后端 高并发 TCP/IP 服务器开发

Linux网络之 从 C10K 到 DPDK

赖猫

c++ Linux linux编程 C10K DPDK

流行的后台管理系统模板总结

老魚

程序员 建站 web全栈

即构微信小程序直播组件是什么?有哪些功能?哪些小程序类目可以使用?

ZEGO即构

开发老人笔记:Git 常用命令清单

华为云开发者社区

git 代码 bug

解决Windows2012 R2下安装PostgreSQL报错的问题

PostgreSQLChina

数据库 postgresql 开源

大数据技术升级脉络及认知陷阱

大数据技术升级脉络及认知陷阱

《Spotify的入云之旅》系列之一——事件传输系统-InfoQ