亚马逊AWS官方博客
Komodo Health 公司如何在 EKS 与 EMR 6 上使用多租户 Notebook 平台建立自助服务分析方案
Original URL: https://aws.amazon.com/cn/blogs/startups/how-komodo-health-enables-self-serve-analytics-with-eks-emr/
Komodo Health公司客座文章作者:Jigar Bhalodia,数据基础设施工程师;Hanyu Cui,数据基础设施高级软件工程师;Stephen Goeppele-Parrish,云基础设施工程师;Chris Han,高级工程经理。
我们还要特别感谢为本文审核以及平台开发做出贡献的工程师们:Scott Edenbaum、Jean Barmash、Andrea Ortuno以及Tomo Ishihara。
在Komodo Health公司,我们的使命一直在迅速演进,努力基于健康数据打造软件与数据产品、进而减轻全球疾病负担。我们的Healthcare MapTM记录超过3.2亿美国人(已进行数据脱敏)在整个医疗系统中的经历。我们还不断增加数据来源与临床绝对值,以确保我们的数据始终保持及时性、完整性与关联性。
过去几年当中,我们公司迎来了100%的同比增长(过去18个月中,我们工程技术团队中的工程师与数据科学家也由35位增加至90多位)。虽然这样的增长势头令人兴奋,但同时也带来一系列规模扩展挑战。其中最大的挑战之一,就是如何在内部运行Spark以进行即席分析与批量ETL作业。
挑战
我们在Kubernetes节点上运行独立Spark集群已经有四年时间,主要将其用于生产ETL管道与即席分析。在分析方面,我们的数据科学家与数据工程师首选的流行工具当数Jupyter notebooks,能够借此与Spark对接以实现分布式计算。在大规模自动化技术的帮助下,每位工程师或科学家都能获得属于自己的Spark集群,并在其中做出种种修改与调整以适应实际需求。另外,各个集群也都在AWS当中通过专用的ASG与EC2实例实现了自我管理。
对于最早接触基础设施的数据科学家与数据工程师们而言,Spark架构效果极佳,能够为他们提供与需求紧密关联的大量灵活性集群配置选项。但随着业务规模的增长,我们需要进一步改进基础设施以降低成本、扩展访问范围、提高工程效率并增强资源利用率。
愿景与目标
我们的愿景是通过AWS的Elastic Map Reduce (EMR) 6构建一套平台,借此:
- 通过快速帮助工程师及数据科学家访问Jupyter notebooks、JupyterLab与Spark计算资源,缩短入职时间。
- 消除基础设施中的复杂性,减少为数据科学家及工程师提供支持所带来的整体负担。
- 通过自动规模伸缩与资源优化(例如使用竞价实例)降低EC2运营成本。
- 通过容器化技术支持多租户机制,避免计算资源的过度配置。
- 提高集群的整体稳定性,并启用蓝/绿部署机制。
解决方案
我们以JupyterHub为前端,EMR 6为后端构建起一套Spark平台。其能够支持现有工作流,且不会令开发人员陷入Spark集群管理所带来的沉重负担当中。数据科学家与工程师们现在可以专注于完成自己最擅长的事务,其余工作则由基础设施团队接管负责。整体解决方案涵盖为notebooks提供服务的前端Kubernetes托管JupyterHub服务器、运行Spark的后端EMR 6集群,以及保证我们稳定如一提供高质量功能、且不会发生性能衰退的整体流程与CI/CD管道。
之所以能够成功打造出这样一套解决方案,关键在于我们立足架构与设计层面采取了一系列特殊实现方法。
使用EKS与EMR 6搭建平台架构
开源、分布式、多用户Jupyter notebook环境能够帮助用户组更加轻松高效地使用Jupyter notebooks。JupyterHub能够帮助我们构建起可供用户访问的网页,借此快速使用Jupyter notebooks服务器。用户不需要接触或者了解AWS及Kubernetes——相反,只需提供自己的单点登录凭证,即可快速完成身份验证。
Example of a Jupyter Notebook
我们将JupyterHub运行在一套部署有开源Helm charts(由Jupyter提供)的EKS集群之上。当用户访问我们的HupyterHub网页时,HupyterHub将通过Okta进行身份验证,并通过开箱即用的代理为该用户创建一个notebook服务器pod。JupyterHub notebook服务器的工作方式与常规notebook服务器相同,用户可以选择Python内核以支持纯Python代码,也可以选择PySPark内核与Sparkmagic以访问EMR 6集群。
运行不同内核
我们还支持JupyterLab——一套面向Jupyter notebooks的下一代用户界面。JupyterLab能够帮助用户在同一界面当中排布多个窗格,借此提高工作效率。各窗格可以容纳notebook、文本文件、终端或者控制台的一个或者多个实例。通过支持传统notebooks与JupyterLab notebooks,工程师与科学家们能够任意选择自己喜爱的界面布局。
JupyterLab示例
基础设施团队管理着JupyterHub及其辅助组件的方方面面,具体包括Sparkmagic、Livy以及多租户EMR Spark集群。作为唯一的例外,用户可以更改某些Sparkmagic配置选项。通过选项调节,我们的用户既能够指定出独一无二的Spark配置,又可以为运行在多租户EMR集群上的Spark应用程序定义出自己的Docker镜像。
JupyterHub、EKS与Spark架构
同时支持即席分析与批量ETL作业
我们的数据科学家与数据工程师们往往投入大量时间进行即席分析。这类工作主要为交互形式,需要快速轮转,而且用户通常无法预测总体资源需求量。在2分钟之内,我们的用户就能访问一个notebook并自动生成用于在EMR集群上运行代码的Spark会话。在登录之后,会话将在用户启动代码的当天之内保持活动状态。我们在Jupyter notebooks中还使用到Sparkmagic,用于实现notebook与PySpark的无缝集成。我们对开源项目Sparkmagic进行了定制化,借此满足我们业务体系中的独特安全性与部署需求。
在我们的Spark工作负载当中,ETL作业同样占据着相当高的比例。我们使用Airflow进行编排,而且各管道能够将Spark作业提交至EMR集群以进行分布式计算。我们还创建了一个内部小型Python软件包,用于将批处理作业直接提交至EMR集群中的Livy端点。即使不使用我们托管notebooks,Airflow作业仍然能够充分发挥托管EMR Spark集群的优势,借此减轻维护与运营负担。
通过实例组与YARN节点标签实现EMR自动规模伸缩
作为基础设施团队,我们主要为内部利益相关方提供服务,具体包括90多位全职工程师、数据科学家以及数据工程师。我们希望能打造出一套多租户平台,可支持各类用户与用例。凭借着灵活的用户数量与工作负载可变性,这套平台应该在保持成本效益的同时,根据需求可靠实现规模伸缩。最终,我们通过实例组与YARN节点标签成功实现了这一目标。
根据资源使用量快速实现节点的规模伸缩,将帮助我们在10到15分钟之内将资源调整到合适的水平。为了实现这种自动规模伸缩,最重要就是结合实际需求提供适当的YARN指标;此外规模伸缩的频率也要合理,避免出现“乒乓”状况,即先触发规模扩展并发现资源过多,再触发规模收缩并导致资源过少,而后反复循环。这只会引发作业失败并严重破坏集群的运行稳定性。
自动规模伸缩规则会直接影响到用户的体验,而在改善用户体验与管理基础设施成本之间寻求平衡点,则是我们不懈追求的终极目标。一方面,用户需要快速扩展资源并借此支持业务运行,另一方面,保留闲置资源以改善用户体验则非常昂贵。在自动规模伸缩方面不存在唯一正确的答案,我们需要遍历调整规则以在成本与用户体验之间找到微妙的最优比例。
自动规模伸缩功能
通过Spark动态分配实现高效资源利用
启用Spark动态分配,成为我们达成目标的关键所在,这也是我们选择EMR与YARN资源管理器的原因所在。默认情况下,EMR会启用动态分配,能够更高效地将资源分配给各Spark应用程序。使用临时作业,我们往往很难预测notebooks的资源利用率,也无法立足单元级别实现资源分配。而在静态资源分配的情况下,只要notebook仍在运行,就会有固定量的资源被分配给该notebook——无论其计算需求如何、繁忙抑或闲置。但在启用动态分配之后,Spark能够根据当前创建的任务数量确定分配给notebook中每个单元的适当资源量。如果notebook正在运行但却处闲置状态,则仅为驱动程序分配资源。当notebook闲置时,用户可以通过缓存数据框保留执行程序,并通过设定执行程序同样闲置后的数据块缓存时长,进一步节约系统资源。
使用容器实现多租户与依赖项管理
我们利用EMR 6中的Docker容器化支持功能作为多租户Spark集群的基础。如果没有容器化方案,依赖项管理将变得充满挑战,因为用户可能需要在单一集群上使用相互冲突的多个版本。用户需要使用各自不同的依赖项定义自己的Docker镜像,并为集群上运行的各个Spark应用程序指定驱动程序与执行程序镜像。我们将EMR引入多租户用例,自第一个beta版发布以来,我们已经与AWS EMR服务团队及支持工程师紧密合作,帮助他们发现问题并探索指导性的正确配置与变通方法。
日志传递架构
通过查看S3里面的EMR日志来调试Spark应用程序也是一项颇为复杂的难题。我们决定使用logstash从S3中的日志处提取并过滤字段,并将其进一步推送至AWS ElasticSearch当中。配合适当的索引管理与日志保留配置,AWS Elasticsearch极大降低了日志检索难度,也让应用程序调试变得更加轻松。
观察、洞见与经验教训
在平台构建的5个月中,我们吸取到很多教训,也观察到不少有趣的用例:
- 工程部门以外的其他职能用户也开始使用notebooks。即使对于内部使用者,用户体验同样非常重要。由于我们使用了新的用户友好型平台因此工程部门之外的其他职能用户也可以轻易通过notebooks高效完成自己的预期任务。
- 由于notebooks的上手难度有所降低,现在我们看到更多意料之外的精彩用例,例如使用notebooks进行工程师培训。
- 在架构阶段,我们预计需要对后端资源设置限制或配额,保证在一定程度上控制其容量过度扩展问题。但事实证明,虽然我们的用户数量众多,但这种风险从未真正出现。
- 预判主要目标之外的其他工具需求。我们还努力跟踪用户的使用情况,从多租户环境中明确划分不同部门的具体托管成本。我们可以在团队视图中汇总每位用户的行动以实现成本溯源。
- 为新的解决方案建立更准确的期望。在平台启动之后,我们知道其会涵盖大多数用例,但还达不到100%。但在人们开始使用平台并投入运营之后,我们预计人们会很快提出大量支持请求。为此,我们的团队在企业内部构建起多份演示与培训课程,帮助用户快速解决难题、学习相关方法。
- 内部工程团队的贡献有所增加,这提升了我们对用户需求的理解。自发布以来,我们已经在路线图中添加了Glue目录以及其他多项增强功能。
- EMR的实例组特定于当前可用区,这是为了尽可能降低延迟水平。我们依靠实例组与YARN节点标签在整个可用区内使用多种不同实例类型。
总结
在EMR上使用Spark,可以在基础设施抽象与管理之间达成适当的平衡,同时帮助我们实现粗粒度配置以保证数据科学家及工程师及时获得所需工具。在Route 53与ALB等多种AWS服务的帮助下,整个部署流程也变得更加轻松易行。
总体而言,我们的工程团队获得了高度评价。Jupyter notebooks与Spark得以顺畅配伍,EMR 6与其他AWS服务则成为这套平台全面成功的核心驱动力。
如果大家有意体验这套平台而且对基础设施技术抱有兴趣,我们正在招聘~