写点什么

用 AWS、Scala、Akka、Play、MongoDB 和 Elasticsearch 构建社交音乐服务

  • 2014-03-13
  • 本文字数:3301 字

    阅读完需:约 11 分钟

Serendip.me 的前首席架构师 Rotem Hermon 撰文介绍了初创音乐服务Serendip.me 在架构及扩展方面所考虑的内容。

Serendip.me 为人们提供社交音乐服务,帮助人们发现朋友们分享的优秀音乐,并为他们介绍“知音” - 那些靠近他们的社交圈子,有相似音乐品味的陌生人。

Serendip 运行在 AWS 之上,采用了如下这些技术: scala (还有一些 Java), akka (用来处理并发), Play 框架 (Web 和 API 前端), MongoDB Elasticsearch

技术栈的选择

Serendip 的主要功能是从公共音乐服务中收集 Twitter 上分享的所有音乐,所以它需要处理大量的数据,所以 Serendip 在选择语言和技术时,首先要考虑它们的扩展能力。

因为 JVM 久经考验的性能和工具,并且还有很多采用这门语言开发的开源系统(比如 Elasticsearch),所以他们选择 JVM 作为系统的基石。

而在 JVM 的体系中,scala 又脱颖而出,成为了一个有趣的选择。Scala 可以用现代的方式写代码,又可以跟 Java 全面互通。此外还有一个很重要的原因,akka actor 框架是非常合适的流处理基础设施(绝对是!)。刚刚开始流行起来的 Play 框架看起来也很不错。Serendip 开始于 2011 年初,当时这些都是非常前沿的技术。到了 2011 年末,scala 和 akka 合并成 Typesafe ,Play 也在不久之后加入。

选择 MongoDB 是因为它对开发者友好,易用,功能集和可能的扩展能力(采用了自动分片技术)。但因为 Serendip 使用和查询数据的方式需要在 MongoDB 上创建很多大索引,而这样会很快引发性能和内存方面的问题。所以他们主要是用 MongoDB 存储键 - 值文档,还有几个需要计数器的功能依赖于它的原子增长。

事实证明,这样使用时 MongoDB 非常牢靠。还容易操作,但主要是因为尽量避免使用分片,并且只有一个复制集(MongoDB 的分片架构相当复杂)。

查询数据需要一个完全成熟的搜索系统。在开源的搜索解决方案中,Elasticsearch 是扩展性最强,并且面向云端的系统。它有动态索引机制,还提供了很多搜索和切面的可能性,可以在其上构建很多功能。因此,Elasticsearch 成为了 serendip 架构中的一个中心组件。

Serendip 决定自己管理 MongoDB 和 Elasticsearch,主要有两个原因。第一,Serendip 要完全控制两个系统。不想在软件的升级 / 降级上依赖于其它元素。第二,因为 serendip 要处理大量数据,采用托管方案要比他们直接在 EC2 上自己管理昂贵得多。

一些数字

Serendip 的“抽水泵” (处理 Twitter 公众流和 Facebook 用户订阅源的那部分) 每天要消化大概 5,000,000 条信息项。这些信息项要经过一系列的“过滤器”,对它们进行检测,并解析出受支持服务(YouTube、Soundcloud、Bandcamp 等)上的音乐链接,还要添加一些元数据上去。抽水泵和过滤器是 akka 的 actor,并且整个过程是用单个 m1.large EC2 管理的。如果需要,可以用 akka 的远程 actor 将任务分发到集群中,轻松实现系统扩展。

从这些信息项中,Serendip 每天大概能得到 850,000 条有效的信息项 (也就是真的包含相关音乐链接的信息项)。这些信息项在 Elasticsearch 中索引 (还要在 MongoDB 中备份并持续计数)。因为每条有效的信息项都要更新几个对象,所以在 Elasticsearch 中的索引率大约为 40 条 / 秒。

Serendip 在 Elasticsearch 中保留一个月的信息项索引 (微博和帖子)。每个月的索引大概包含 25M 信息项,有 3 个分片。集群运行着 4 个节点,每个都在 m2.2xlarge 实例上。这个配置有足够的内存运行 Serendip 所需的数据搜索。

Serendip 的 MongoDB 集群的操作频率大概是 100 次写 / 秒和 300 次读 / 秒,因为它处理更多的数据类型、技术和统计数据更新。复制集的主节点跑在一个 m2.2xlarge 实例上,副节点在一个 m1.xlarge 实例上。

构建订阅源

在设计 Serendip 主音乐订阅源的架构时,想让订阅源是动态的,并且可以根据用户的动作和输入作出反应。比如说,如果某位用户将一首歌标为“摇滚”,或将某位艺术家标为“趾高气昂”,那么这些动作应该马上反应到订阅源上。如果用户“不喜欢”一位艺术家,那以后就不应该再播放那些音乐。

并且这个订阅源应该是几个源头的组合,比如朋友分享的音乐,喜爱的艺术家的音乐,以及有相同音乐品味的“建议”用户分享的音乐。

这些需求意味着那种“fan-out-on-write”式的订阅源创建方式可能并不合适。应该实时构建订阅源,把跟用户相关的所有信号都用上。Elasticsearch 的功能可以构建出这种实时的订阅源生成器。

订阅源算法有几种选择信息项的“策略”,在每次订阅源的获取上都根据不同的比率动态组合。每个策略都会考虑到用户最近的动作和信号。策略的组合被转换成几种对鲜活数据的搜索,这些数据是不断地由Elasticsearch 索引的。因为这些数据是基于时间的,并且索引每月创建一次,所以只需要查询全部数据中的一小部分子集。

Elasticsearch 非常擅于处理这些搜索。它还提供了一种扩展这种架构的著名路径 - 通过增加分片数量扩展写操作。通过增加更多的复制和物理节点扩展搜索。

寻找“知音”的过程(根据用户的音乐品味进行匹配)充分利用了 Elasticsearch 的切面(聚合)能力。作为持续不断的社交流处理的一部分,系统通过计算顶级分享的艺术家来为它遇到的社交网络用户准备数据(在他们分享的音乐上使用切面搜索)。

当 Serendip 用户给出一个信号(播放音乐或跟订阅源交互)时,它能为那位用户重新触发一次知音计算过程。这个算法按照喜爱艺术家(这个是不断在更新的)列表来寻找匹配程度最高的其他用户,并用一些额外的参数作为权重,比如流行程度、分享次数等。然后再用另一组算法过滤掉垃圾邮件发送者(是的,有音乐垃圾邮件发送者)和异常值。

实践证明,这种处理能得出很好的结果,并不需要再用一套系统来运行更加复杂的聚类或推荐算法。

监测与部署

Serendip 用 ServerDensity 做系统监测和报警。对于初创公司而言,它是一种易于使用的托管方案,有像样的功能集和合理的价格。ServerDensity 原生提供了服务器和 MongoDB 的监测。Serendi 还大量使用了它报告定制指标的能力来报告内部系统统计数据。

内部统计数据采集机制负责采集系统内发生的所有动作,并把它们保留在一个 MongoDB 集合内。一个定期任务每隔一分钟从 MongoDB 中读取一次这些统计数据,并报告给 ServerDensity。这样就可以用 ServerDensity 对 Elasticsearch 及运营数据进行监测和报警。

服务器的管理和部署是用亚马逊 Elastic Beanstalk 完成的。Elastic Beanstalk 是 AWS 的受限 PaaS 解决方案。很容易上手,但它不是功能完整的 PaaS,对于大部分常见用例而言,它的基本功能已经足够了。它提供了易用的自动扩展配置,还可以通过 EC2 完整访问。

应用程序的构建是由 EC2 上的 Jenkins 实例执行的。Play 程序被打包成 WAR。一个构建后置脚本将这个 WAR 作为新版本推送到 Elastic Beanstalk 上。这个新版本不会自动部署到服务器上 - 它的部署是手动完成的。通常是先部署到临时环境中进行测试,然后经过证实后再部署到生产环境中。

外卖

作为结论,这里有一些在构建 Serendip 的过程中得到的最重要的经验教训,重要程度跟顺序没什么关系。

  1. 知道如何扩展。一开始你可能并不需要扩展,但你得知道系统的每一部分能够如何扩展,以及能扩展到什么程度。如果扩展需要时间,要预先给你自己留出充足的时间。
  2. 为峰值做好准备。特别是在创业阶段,如果你总是接近满负荷运行,一个 lifehacker 或 reddit 帖子就能把你的系统宕掉。保留充足的边界空间,这样才能应对突发负载,或时刻准备好真正快速地扩展。
  3. 选择一门不会拖你后腿的语言。确保你所采用的技术在你的语言中有原生客户端,或者至少有维护得很活跃的一些。不要被等着类库更新给拖住。
  4. 相信炒作。你想要技术跟你的产品共同成长,不会过早死掉。一个充满活力的活跃社区,以及跟该项技术有关的一些噪音,是这种技术存活的良好迹象。
  5. 不要相信炒作。看看那些批判你正在评估的技术的帖子。它们可以告诉你它的弱点。但也不要太认真,当事情不能按照期望工作时,人们通常会变得情绪化。
  6. 玩得开心点。选择会让你兴奋的技术。要能让你觉得“哦,我能用它做的事情太酷啦”。毕竟那(也)是我们来这里的目的。

查看英文原文: Building a social music service - the technology behind serendip.me

2014-03-13 07:195585
用户头像

发布了 45 篇内容, 共 26.0 次阅读, 收获喜欢 11 次。

关注

评论

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

2020大厂web前端面试常见问题总结

华为云开发者联盟

CSS 面试 响应式 大前端 浏览器

第二次推荐笔记:wolai

申屠鹏会

对待一件事,从不喜欢再到喜欢,转变需要多大

良知犹存

程序人生

gRPC在Spring Cloud中的应用

xcbeyond

Java gRPC SpringCloud

字节跳动想招什么样的技术人?

池建强

HTTP协议-进阶

Jaykey

大前端 HTTP

误执行 rm -fr /*,我删删删删库了,要跑路吗?

小林coding

Linux 程序人生 Shell linux命令

Spring Boot Actuator微服务服务监控

xcbeyond

Java 微服务 springboot actuator 服务监控

从根上学习Git

书旅

git 工具 版本控制 版本管理工具

HTTP协议-基础

Jaykey

大前端 HTTP

C++ 深入浅出工厂模式(进阶篇)

小林coding

c++ 设计模式 工厂模式

让类/进程/脚本「单身」的方法

小林coding

c c++ Shell 设计模式 单例模式

超超超全递归技巧讲解,这次带你拿下递归

多选参数

数据结构 算法 递归 数据结构与算法

深挖502和504

书旅

nginx 服务器 HTTP 状态码

C++ 深入浅出工厂模式(初识篇)

小林coding

c++ 设计模式 工厂模式

SpringCloud(Netflix)-技术专题-微服务入门介绍

码界西柚

大数据技术发展(一):大数据技术的起源

cristal

Java 大数据 hadoop

为什么使用Portainer,而不是Docker CLI来管理Docker环境

xcbeyond

Docker 运维 Portainer

Web 全栈开发利器: 强大的在线 Cloud IDE

华为云开发者联盟

Web python3.x 全栈 编码 CloudIDE

精美前端UI(VUE)界面,ASP.NET通用工作流开发分享

雯雯写代码

工作流 可视化

国内首家 ABM 营销技术服务商火眼云完成5000万元A轮融资

人称T客

为什么你做的 Excel 表不好用?

Tony Wu

效率工具 产品设计 Excel ER图

为什么直播系统不用RTP协议

soolaugust

WebRTC 直播 RTMP rtp

优化教育体验 智微智能高品质录播系统

InfoQ_967a83c6d0d7

Newbe.Claptrap 框架如何实现在多种框架之上运行?

newbe36524

Docker 云计算 微服务 .net core ASP.NET Core

老张「原创小说」

瓜藤老祖

个人成长

「C++ 篇」答应我,别再 if else 走天下了可以吗

小林coding

c++ 编程 设计模式 编程习惯 编程风格

修改系统时间,导致 sem_timedwait 一直阻塞的问题解决和分析

小林coding

Linux 编程 问题处理

全球移动服务生态的暗涌与新机

脑极体

音画同步体验有多好,来看看即构的自研互动白板就知道啦

ZEGO即构

在线教育 SVG canvas

直播技术的背后--RTMP协议

soolaugust

直播 RTMP

用AWS、Scala、Akka、Play、MongoDB和Elasticsearch构建社交音乐服务_Scala_吴海星_InfoQ精选文章