【AICon】 如何构建高效的 RAG 系统?RAG 技术在实际应用中遇到的挑战及应对策略?>>> 了解详情
写点什么

在大规模系统中使用 Scala

  • 2015-06-15
  • 本文字数:3834 字

    阅读完需:约 13 分钟

本文是关于在大规模数据储存及分析系统中使用 Sacla__ 系列文章中的第一篇。

在过去几年间,已经有多个项目使用了 Scala 进行大规模数据储存及分析平台的设计。

BBC 在设计公司内部的 RDF 数据储存系统时就使用了 Scala 以及 Scalatra HTTP 框架,这套内部系统可用于查询 BBC 新闻与体育所有文章中的链接数据。

在整个 2014 年间,业界对于 Apache Spark 的兴趣达到了一个高峰,这是一套使用 Scala 编写的数据分析工具。Spark 中包含了一套由 Spray 编写的 HTTP 接口,它的后端使用了 Akka 用于并行处理。

迈凯伦应用技术(MAT)在他们的数据分析平台中也使用了Scala、Scalatra 和Akka,作为整个平台的构建基础。

为什么这些项目会选择Scala 呢?

为了找到这一问题背后的原因,我们与来自MAT 的高级软件工程师Andrew Jayne 进行了一次对话,了解了后者使用Scala 创建一个自定义的高性能数据储存系统的经验。

迈凯伦应用技术位于伦敦附近,它源自于母公司迈凯伦几十年以来在F1 赛车方面的经验。从母公司分离之后,MAT 也将F1 的相关经验应用在其它产业上。

由于MAT 深厚的F1 背景,因此它们在根据数据进行分析以及进行快速决策方面具备很强的技术实力,例如它们的时间序列数据存储系统能够分析一场F1 赛事中车辆的数据流。不过,他们也发现这套序列分析技术在与传感器设备相结合的情况下,往往能够应用在赛车之外的其它许多场景中:他们已经对制造业、传输业、能源业以及医疗保健行业的部门提出了这项建议。

为了支持MAT 的这项咨询工作,他们的工程师创建了一个序列数据平台,运行于 AWS 之上。

InfoQ:你是否能为我们概述一下 MAT序列数据储存系统的作用是什么,以及如何使用它?

Jayne:这是一个大容量、高性能的排序式键 - 值存储系统,它能够保存读 - 写的一致性,并且具有一个专门为实时及历史序列数据(根据时间、距离、深度等进行索引)设计的特性集。它允许我们以一种版本控制的方式进行微批量及批量处理,并且可以通过某个 REST API 对我们的数据分析平台的输入与输出的所有序列进行持久化。这方面有一个例子,我们正在为葛兰素史克(GSK)设计对渐冻症(ALS)患者进行监控与分析的系统,这是基于传感器设备的,通过临床实验,让我们能够得到在实验中患者的病症得到改善,或产生恶化的反馈信息。

InfoQ**: MAT序列数据存储系统是否是用于分析 F1相关的时间序列数据的目的,还是更为一般性的目的而存在的?**

Jayne:设计这套系统的目的是作为一种一般性的解决方案,对序列数据进行保存与查询,它基于我们在赛车运动、竞技体育、医疗以及能源行业的经验。我们在这些项目中都面临着类似的问题,因此急需一种存储方案,它能够保持数据完整性,同时又能帮助我们解决这些问题。比方说,如果你的数据来自于某个产生了时钟漂移的设备,你该怎么做?如果出于带宽的限制,使得上传的数据只具有较低的分辨率,那么我们又该如何确保数据的高精度?如果在一段长时间的网络断线之后,某个数据源又开始发送数据,那么又会发生什么情况?

InfoQ:这套系统主要针对怎样的数据集,目标的数据量是什么?

Jayne:它可以用于 n 维的数值数据,其中包含一个数值型的、严格增长的键。目前我们的用例除了我们的数据分析结果之外,还包含病患监控设备的传感器数据、钻井作业以及数据中心。

InfoQ:为什么选择 Scala?你的技术背景是从 Java转移而来的吗?这门语言有什么地方吸引了你?

Jayne:整个团队具有多种语言的背景。在 2012 之前,我们使用了 Java、C#和 MATLAB。随着 Typesafe Stack 2.0 发布之后,我们就开始采用 Scala 作为我们的服务以及 web 应用程序的后端语言。

当时 Scala 最吸引我们的地方在于它的可伸缩性,例如可以通过使用 Actor、不可变对象以及函数式编程简化并发处理。此外还有一些原因,比如能够以更加算术式的语法表达程序、模式匹配,并且能够减少样板代码。不过,如果要牺牲 Java 的互操作性,那我们也不可能会选择 Scala。函数式编程的方式非常新颖、痛快,也为我们展现了更多创新的机会。这个选项很符合团队的文化与心态。

InfoQ:为什么这套系统没有选择 Java

Jayne:我们已经有了一个用 Java 编写并基于 Hadoop 的组件。虽然我们也可以在这个组件的基础上打造新系统,但其它所有后台组件都是用 Scala 编写的。我们将此看做一次开展研究工作的好机会,很快我们就明白,要支持我们所设计的架构,可以选择的类库与技术有哪些了。基于这些研究的经验,我们意识到可以用函数式编程简化我们的现有功能。虽然 Java 很易于使用,但它的语法过于啰嗦,会妨碍我们保持代码清晰度的意图。我们已经在商业项目中使用 Scala 有很多年了,我们发现能够与创建这门语言以及核心类库的人们进行交流是很有价值的。

InfoQ:其它的一些时间序列数据库(TSDB)缺少了什么功能?为什么没有选择 KairosDb Druid InfluxDb OpenTSDB ,或其它任何一种现有的 TSDB

Jayne:对于我们的业务来说,数据完整性与数据管理是至关重要的,并且我们需要对这些数据进行某些程度的保证,以符合代码端的期望。仅仅实现备份与记录日志是不够的。受到了 Git 的影响,我们最终设计了一套数据储存系统,它具有基于提交的版本控制能力,以及基于树状的组织结构。

我们的验收场景也提出了额外的挑战,例如:

  • 原子性 —— 不允许在查询系统时返回不一致的状态。
  • 一致性与正确性 —— 查询应当是可重复的,并且始终返回一致的、正确的数据。
  • 接近实时的写操作 —— 支持每秒几百万次写入操作(数据来自于高频率及可变频率的传感器),并且在数据写入后的几秒钟之内就可用于查询。
  • 查询性能 —— 通过在整个频道中提供可预测且快速的查询,支持能够感知延迟的数据分析能力,包括:
    • 数据准备(即插值),
    • 子集(即窗口、范围、偏移、限制),
    • 聚合(即平均值、最小值、最大值等等),
    • 预测(即推断、回归、关联)
  • 语言无关性 —— 使用 REST API 与 ETag 缓存。
  • 通用的数据格式 —— 数据应当与现有的工具兼容,例如 CSV、JSON 等等。
  • 部署复杂性 —— 系统应当使用现有的云端基础设施(AWS),并且能够以最小的代价创建新的数据存储。

这些需求中有很大一部分已经在现有的 TSDB 中已经得到解决,其中某些 TSDB 对这些问题的解决方案更为出色。但是,我们所需的某些查询是其它数据库所不支持的,也很难对其进行改进。主流的 TSDB 都是在其它数据库系统的基础上创建的(例如 HBase),它们的复杂性已经超出了我们的用例的需求。通过使用一种更简化的、量身订做的存储机制,并利用分布式特性,我们就能够对数据的组织进行优化,更适用于我们所执行的查询。这种方式也让系统管理员的工作量以及运行时的成本减至最小。最重要的是,其它数据库都无法提供这种对数据的版本控制机制,而我们在开发与生产环境中都需要这种机制。

InfoQ:说到 REST API**,你在项目中使用了 Scalatra作为 REST HTTP接口,原因是什么?**

Jayne:Scalatra 的维护工作做得很好,它的发布策略也很明智,我们之前在使用其它框架时曾在这一点上吃过亏。这个框架有一套十分简单的领域特定语言(DSL),我们只需要进行很少的工作,即请求处理与测试。并且它还能够使用我们选择的其它类库,进行诸如序列化等工作。Scalatra 能够简单地部署到某个 servlet 容器中是它的一大优点,并且它的性能也十分出色。

InfoQ:你提到了 Actor**。那么 Akka这个选择在实际运行中效果如何?我听说某些人对它爱不释手,而另一些人则表示自从他们远离了 Akka之后,代码就变得简单了许多倍。那么使用它的挑战又来自于哪里呢?**

Jayne:我们在数据储存系统中使用 Akka 管理异步的请求,因为一个请求的生命周期中的大部分都是进行 I/O 操作。它目前还不是一种基于事件的 I/O 技术,但我们认为 Akka 的优点在于它的调度器以及对栈溢出的处理。

我们使用了 actor 模型将某一问题分解为多个子系统集,每个子系统维护自己的状态,负责自己的可伸缩性。由于在设计时就考虑到了默认的分布式架构,因此你可以利用它的位置透明性特征实现纵向与横向的扩展。不过,由于失去了正式的接口,这一点也让我们产生了动摇,因为这意味着我们将失去编译器检查的优势。一种妥协方案是使用正规的协议,让 actor 保持简洁,并让这些协议在我们的设计与测试中明确地表现出来。编写清晰的、简明的测试不是一件简单的事,而在任何并发系统中进行调试都是一个很大的挑战。

InfoQ:这套数据库能够在多个节点间进行集群化吗?它的横向扩展能力如何?这一点与你们选择了 Scala的决定是否有关,还是说无论使用哪一种语言结果都一样呢?

Jayne:目前来说,它仅在数据处理量以及故障转移方面做到了可伸缩性,因为 API 终结点与数据的位置是在一起的。接下来在改善可伸缩性方面的工作是移除这一限制,这样我们就可以在 REST API 端使用一种灵活的负载均衡器,并将其从数据储存层中分解出去。

使用 Scala 进行开发的速度是非常之快的,并且使用函数式编程能够让许多最复杂的处理过程也变得十分清晰。默认的不可变性也鼓励更清晰的编程模式,并且更容易实现对系统的原子性与一致性的强制实施。不过,在 Java 中也没有什么不能做到的,只是我们觉得 Scala 是最适合我们团队的工具。

关于作者

Dave Hrycyszyn Head London 的技术总监,这是一家位于英国的数字产品与服务代理商。Dave 是 《Scalatra in Action》一书的作者之一,也是创建 Scalatra 这个微框架的团队的成员之一。他在自己的博客 constructiveproof.com 上撰写了大量有关于 Scala、API 和与数据相关的主题文章。

查看英文原文: Scala in Large Scale Systems

2015-06-15 03:536655
用户头像

发布了 428 篇内容, 共 170.9 次阅读, 收获喜欢 36 次。

关注

评论

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

第一周:学习总结

王建军

第1周 作业

Pyr0man1ac

Java新特性:数据类型可以扔掉了?

王磊

Java 新特性 Java新特性 var 局部类型推导

程序员为什么热衷于造轮子,升职加薪吗?

小傅哥

Java 小傅哥 代码质量 编程开发 编程经验

java安全编码指南之:输入校验

程序那些事

java安全编码 安全编码规范 java安全编码指南

智能商业时代的思考(三)数据驱动

刘旭东

大数据 数据驱动 智能商业

架构师训练营第一周总结

知鱼君

极客大学架构师训练营

第1周 作业

wgl

UML

信任环:口碑传播的关键环节

boshi

用户增长 运营创新

腾讯PCG数据中台专场介绍&招聘报名

Geek_c46970

数据中台 腾讯 招聘

科大讯飞再握一国产核心技术,可高精细拾取30分贝超小音量

Talk A.I.

早知道这 8 个锦囊,我的程序人生一定更精彩

沉默王二

程序员

高效程序员的45个习惯:敏捷开发修炼之道(8)

石云升

敏捷开发 技术分享 轮换制

Java ConcurrentHashMap 高并发安全实现原理解析

vivo互联网技术

Java hashmap 多线程 高并发

架构师训练营第一周课程笔记及心得

Airs

# 架构师训练营Week1总结

lggl

极客大学架构师训练营 UML

【架构师训练营1期】第一周作业

诺乐

架构师训练营第 1 期第一周总结

Geek_a01290

极客大学架构师训练营

第二周 - 框架设计

Arthur云剑

oeasy 教您玩转linux 010303文件管理器 nautilus

o

超全面分布式缓存高可用方案:哨兵机制

架构精进之路

redis哨兵模式

RDS、DDS和GaussDB理不清?看这一篇足够了!

华为云开发者联盟

数据库 华为云 RDS

week-1-part2 学习总结

陈龙

架构师第一周笔记

Geek_Gu

课程大作业

小胖子

git 常用操作及 git 工作流介绍

hepingfly

git git分支操作 git工作流

从linux源码看socket的阻塞和非阻塞

无毁的湖光

Linux TCP socket Linux Kenel

SpringBoot系列(1)-初识SpringBoot

引花眠

学习 springboot

ARTS打卡 第17周

引花眠

微服务 ARTS 打卡计划

架构师训练营第 1 期第一次作业

Geek_a01290

极客大学架构师训练营

深入理解JVM垃圾回收算法 - 标记清理算法

SkyeDance

GC算法 标记清理 位图标记 懒惰标记

在大规模系统中使用Scala_Java_Dave Hrycyszyn_InfoQ精选文章