Scala在Databricks的大规模应用


Databricks 拥有数百名开发人员和数百万行代码,是最大的 Scala 应用之一。这篇文章将在 Databricks 对 Scala 进行一次广泛的介绍,从开始到使用、风格、工具和挑战,从这篇文章中,您将了解在 Databricks 中使 Scala 工作的所有大大小小的信息,对于支持在成长中的组织中使用 Scala 的任何人来说,这是一个有用的案例研究。
Databricks 由 Apache Spark 的原始创建者构建,最初是分布式 Scala 集合。选择 Scala 是因为它是少数具有可序列化 lambda 函数的语言之一,而且它的 JVM 运行时允许与基于 Hadoop 的大数据生态系统轻松互操作。从那时起,Spark 和 Databricks 的发展都远远超出了任何人最初的想象。
Scala 今天是Databricks 中的一种通用语言。
查看我们的代码库,最流行的语言是 Scala,有数百万行,其次是 Jsonnet(用于配置管理)、Python(脚本、ML、PySpark)和 Typescript(Web)。
Databricks 并不反对编写非 Scala 代码。我们还有高性能的 C++ 代码、一些 Jenkins Groovy、在 Nginx 中运行的 Lua、一些 Go 和其他东西。但大部分代码仍使用Scala。
Databricks 的几乎每个人都编写了一些 Scala,但很少有人是狂热者。我们没有进行正式的 Scala 培训。人们带着各种各样的背景来到这里,第一天就开始编写 Scala,然后随着时间的推移慢慢掌握更多的功能特性。由此产生的 Java-Python-ish 风格是自然的结果。
尽管几乎每个人都编写了一些 Scala,但 Databricks 的大多数人并没有深入研究该语言。人们首先是基础设施工程师、数据工程师、ML 工程师、产品工程师等等。有时,我们必须深入处理一些棘手的问题(例如,着色、反射、宏等),但这远远超出了大多数 Databricks 工程师需要处理的标准。
总的来说,大多数 Databricks 代码都存在于单一存储库中。Databricks 对 mono-repo 中的所有内容都使用 Bazel 构建工具:Scala、Python、C++、Groovy、Jsonnet 配置文件、Docker 容器、Protobuf 代码生成器等。鉴于我们从 Scala 开始,这曾经都是 SBT,但是我们主要迁移到 Bazel 是为了更好地支持大型代码库。我们仍然在 SBT 或 Mill 上维护一些较小的开源存储库,并且在我们尝试完成迁移时,一些代码具有并行的 Bazel/SBT 构建,但我们的大部分代码和基础设施都是围绕 Bazel 构建的。
 
Scala 编译速度是一个普遍关注的问题,我们付出了巨大的努力来缓解这个问题:

  • 设置 Bazel 以使用长期存在的后台编译工作者来编译 Scala,以保持编译器 JVM 的热和快速。
  • 在选择加入的基础上为想要使用它的人设置增量编译(通过 Zinc)和并行编译(通过 Hydra)。
  • 升级到更新版本的 Scala 2.12,比以前的版本快得多。

 
Scala 在主要版本之间是二进制不兼容的,这意味着需要为两个版本分别编译旨在支持多个版本的代码。即使忽略 Scala,支持多个 Spark 版本也有类似的要求。Databricks 的 Bazel-Scala 集成内置了交叉构建,每个构建目标(相当于“模块”或“子项目”)都可以指定它支持的 Scala 版本列表:
cross_scala_lib ( 
    base_name = "my_lib"
    cross_scala_versions = [
"2.11" , "2.12" ], 
    cross_deps = [
"other_lib" ], 
    srcs = [
"Test.scala" ], )     

通过上述输入,我们的cross_scala_lib函数生成构建目标的my_lib_2.11和my_lib_2.12版本,并依赖于相应的other_lib_2.11和other_lib_2.12目标。
。。。。。
  
Scala 非常适合做脚本/胶水类应用!
人们通常认为 Scala 是一种用于编译器或 Serious Business后端服务的语言。但是,我们发现 Scala 对于类似脚本的胶水代码来说也是一种出色的语言!我的意思是代码杂耍子进程、与 HTTP API 通信、处理 JSON 等。虽然 Scala 的 JVM 运行时的高性能对于脚本编写无关紧要,但许多其他平台优势仍然适用:
  • Scala是简洁的。根据您使用的库,它可以与 Python 或 Ruby 等“传统”脚本语言一样简洁,甚至更简洁,并且具有同样的可读性。
  • 脚本/粘合代码通常是最难进行单元测试的。集成测试虽然可能,但通常是缓慢而痛苦的;我们不止一次让第三方服务因为运行过多的集成测试而限制我们!在这种环境中,具有基本的编译时检查水平是天赐之物。
  • 部署很好:程序集 jar 比 Python PEX 好得多,例如,因为它们更标准、更简单、更封闭、更高效等。尝试在不同环境中部署 Python 代码一直是一个令人头疼的问题,总是有人brew install或apt-get install会导致我们部署和测试的 Python 可执行文件崩溃。Scala 程序集 jar 不会发生这种情况。

Scala/JVM 并编写脚本并不完美:任何非平凡程序都有 0.5-1 秒的 JVM 启动开销,内存使用率很高,编辑/编译/运行 Scala 程序的迭代循环相对较慢。尽管如此,我们发现使用 Scala 与 Python 等传统脚本语言相比有很多好处,并且我们已经在许多人们自然希望使用脚本语言的场景中引入了 Scala。甚至 Scala 的 REPL 也被证明是一种有价值的工具,可以方便灵活地与内部和第三方服务进行交互。
点击标题