作者:丁顺杰 RisingWave Labs 开发工程师
背景和动机
“云原生”俨然是时下的热词。本质上,它是指在云上运行的具有弹性、可管理性和可观察性的系统。RisingWave就是一个云原生的流式数据库,它的设计宗旨是充分利用云计算带来的弹性。但是,在云上部署和维护RisingWave仍然是一个具有挑战性的“技术活”。特别是考虑到以下问题:
如何在云服务供应商(如AWS、Azure和GCP)上部署流式数据库?
当负载过大时如何扩展数据库?能否自动进行扩展?
当一些组件出现故障时如何进行快速恢复?
还好,有Kubernetes。Kubernetes是一个开源系统,可在计算机集群上自动化部署、扩展和管理容器化应用程序。它提供了大量的API用于抽象所需资源。有了Kubernetes,人们在部署应用程序时不必担心被云服务供应商深度绑定。所以,将RisingWave带到Kubernetes上顺理成章。
我们开发了Kubernetes Operator for RisingWave(下文简写为“Operator”),一个能在Kubernetes上管理RisingWave的扩展插件。编写Operator颇具挑战。这篇博文将概述Operator的功能特性、实现过程中的挑战以及我们的解决方案。
Kubernetes operator基础知识
在讲到operator之前,先简要介绍一下Kubernetes中的一些核心概念。
Pod是Kubernetes中可被调度的最小单元。每个Pod可包含多个容器(Containers),Pod之间通常共享相同的命名空间隔离(namespace isolation)。Pod是Kubernetes提供的抽象计算资源的基本组件。不夸张地说,整个世界都是建立在它的基础上的。
Service是一种抽象,用于将一组Pod上运行的应用程序公开为网络服务。
Deployment和StatefulSet都是工作负载资源(workload resources)。工作负载资源能帮助你在Kubernetes上运行应用程序,并能提供高级功能。例如,使用Deployment,你可以简单地通过设置所需的副本来扩容或缩容应用。Deployment和StatefulSet的主要区别在于,Deployment仅适用于无状态应用(stateless applications),而StatefulSet则尽可能保持状态活跃,例如挂载的持久卷。
除了内置资源之外,Kubernetes还引入了自定义资源(即CustomResourceDefinition,CRD),以扩展其API。CRD API允许用户自定义自己的资源。通常,每种资源类型都有一个控制器(controller)。但是Kubernetes核心组件中没有针对自定义资源的控制器。开发者通常会提供与自定义资源相配对的控制器。
那么,Kubernetes operator到底是什么?广义上,Kubernetes operator是一组CRD和相应的控制器。控制器通过遵循operator模式确保扩展的API最终按预期运作。
在介绍了Kubernetes operator的一些基础知识后,接下来的部分将详细说明Kubernetes Operator for RisingWave是如何建立在这些抽象之上的。
实现Kubernetes Operator for RisingWave
Operator能管理RisingWave集群。它使得部署、升级、监控和扩展RisingWave集群的操作变得简单、高效、自动化。要实现Operator,技术上主要有两方面挑战:
如何在Kubernetes中体现RisingWave?
如何在控制器中建立管理不同组件的工作流程?
在Operator中抽象RisingWave
要在Kubernetes中抽象RisingWave,需要解决三个主要问题。
使用工作负载资源抽象组件
RisingWave有四个主要组件:元数据服务器、前端、计算节点和compactor节点。有关详细信息,可参考设计文档。我们可以将所有组件节点都看作是无状态的,因为RisingWave是建立在云原生共享存储上的。因此,将Deployment用于每个组件再直截了当不过。但是,考虑到计算节点中的本地缓存,我们使用了StatefulSet而不是Deployment来管理它们。StatefulSet在状态方面有许多保证,例如,它会在升级副本时保持顺序,但我们所需的是它的存储守护。
用于通信的稳定网络标识符
在Kubernetes中,每个Pod在创建时都会分配一个内部IP。除非存在进一步的限制,这个IP在Kubernetes内部是可访问的。但是,这些内部IP不能直接用于进程之间的通信。例如,当发生故障或升级时,Pod常常会被销毁并重建。在这些情况下,同一组件的IP也会在RisingWave实例的生命周期中发生变化。因此,我们为每个组件启用了一个单独的Service。这些Service会保留不可变的内部IP作为稳定的标识符。我们利用Service的发现机制让节点之间“认识”彼此。
连接不同的资源
那这些资源能够为RisingWave实例提供所需的功能吗?不幸的是,对于实现一个可用于生产环境的operator来说,答案是否定的。为了在部署和管理上有更多灵活性,我们还开发和使用了:
ConfigMap——用于存储配置。它将挂载到运行的Pod上。
工作负载资源组——同一组件的工作负载资源可以分成多个组并单独管理。例如,我们允许计算节点在两个可用区(availability zones)运行。
ServiceMonitor——用于声明Prometheus的抓取任务。这是个可选的子资源。它只会在安装Prometheus operator时同步。
这是RisingWave不同子资源之间关系的概览。

RisingWave不同子资源之间的关系
实现控制器
在Kubernetes中,这些管理不同资源的工作流是在控制器中定义的。在下文中,我们将讨论在Operator中实现控制器的细节。
反应作为基本单元
实现控制器非常复杂。每个不同的子资源都有自己的状态和逻辑。我们将复杂的过程分成小的片段:每个片段只关注一些子资源,并尽力做到最好。例如,前端Deployment只应在有相关规格更改时更新,例如修改副本、资源或节点选择器时。在这种情况下,我们只需进行以下其中一种操作:
在找不到此类资源时创建一个。
根据RisingWave的规格进行更新。
如果已过时且不再需要,则删除。
这些操作构成了对RisingWave规格和实际状态的反应(reaction)。每个子资源都有自己的反应。无论发生什么,反应都会找到一种方法来确保Deployment最终在线并与规格保持一致。
反应式工作流
我们设计了一个反应式工作流,并提供两个原语来有序地组织反应。
Join反应允许反应运行,但将结果合并。本质上,Join是用于同时运行多个独立反应的。
Sequential反应允许反应按顺序运行。它能确保依赖的反应在条件满足之前不会运行。
除了用于将反应组织到工作流中的原语之外,我们还设计了几个装饰器来增强反应,但不改变它们的意图:
Timeout可装饰反应,并尽可能在给定时间过后使程序超时。
Retry在遇到意外错误时会重试反应,直到达到限制次数。
Parallel可并行运行基础反应。
Shared可标记反应为共享反应,让不同的工作流分支可以共享该反应,但只运行一次。
此外,工作流原语还支持构建结构化并发工作流,这可能是并行编程的最佳模式。你可以参考代码库中的ctrlkit包了解有关设计的更多细节。下图展示了当前运行的工作流:

在上方图表中,Sync Components and Sub-resources是一个共享的子工作流,如下所示:

有了反应和工作流,开发者能从这几方面受益:
专注于一个小单元(通常只考虑单个方面的子资源)使得代码更具鲁棒性、更易于维护。
用原语来组织工作流能最大限度给予调整行为的灵活性,并将常用的装饰器与反应解耦。在Operator的工作流中,我们追求极致的效率,几乎并行化了每个独立的反应。
碎碎念
我们还遇到了很多其他的技术难题,例如使用客户端缓存所带来的问题,客户端缓存对象并提供Get操作(那么数据的新鲜度始终不够好)。这些我们会留到以后的文章中再探讨。
改进计划
在经过上文讲述的所有努力之后,Operator已经整合了在云上管理RisingWave集群的基本功能。但是,我们还有很多工作要做。在我们发布这篇文章的时候,许多令人兴奋的功能的设计和开发正如火如荼地进行着:
kubectl插件——可帮助用户在Kubernetes上更自然地操作RisingWave。
Helm图表——可用于部署Operator、RisingWave和依赖项。
与Grafana和Prometheus的即插即用集成。Operator将来还会附带可用于生产环境的仪表板。
Serverless RisingWave
云原生带来了从本地部署到无服务器部署的系统设计上的范式转变。无服务器数据库必须通过自动调整部署甚至根据工作负载的波动自动扩展,以对工作负载做出反应。我们正在设计无服务器RisingWave的解决方案。该解决方案包括一个自动伸缩器(autoscaler),用于在Operator之上对RisingWave集群进行扩缩容。该伸缩器应了解集群的运行状态,并根据运行的工作负载自动调用不同节点的扩容、缩容操作。RisingWave作为一个从零构建的云原生流式数据库,它的自动伸缩器很可能可以访问数据流的底层指标,并直接在流处理引擎中调度参与者。这为我们提供了设计空间,以探索细粒度的扩展政策,实现更好的成本效益比。
总结
本文概述了Kubernetes Operator for RisingWave、其实现过程中的主要技术挑战以及我们的解决方案。Operator能帮助用户在Kubernetes中运行RisingWave。它支持即开即用式的对RisingWave集群的重启、扩展和升级操作。此外,它还将为无服务器版RisingWave提供技术支撑。Operator是RisingWave迈向云端的坚实一步。是即将推出的云服务的基础。
流处理的未来,即将到来!如果你想提前试用由Operator提供技术支持的RisingWave Cloud,请访问我们的网站获取早期试用权限。你还可以尝试使用Operator部署RisingWave集群。Operator完全开源,我们欢迎并期待你的贡献!最后,请关注我们的Twitter和LinkedIn、加入我们的Slack社区,并随时关注RisingWave!
RisingWave是一个云原生SQL流式数据库。其旨在降低构建实时应用的门槛以及成本。
✨ GitHub: https://github.com/risingwavelabs/risingwave
💻 官网: https://www.risingwave.com/
👨💻 Slack: https://join.slack.com/t/risingwave-community/shared_invite/zt-120rft0mr-d8uGk3d~NZiZAQWPnElOfw
文档: https://www.risingwave.dev




