目前,几乎所有关于容器和微服务的谈论都跟“无状态”的应用挂钩。这完全可以理解,因为无状态应用程序更简单。而且容器和编排技术已经成熟到能够承工作负载的程度:即有状态的应用。
Kubernetes 是一个用于自动部署、扩展和管理容器化应用程序的开源系统,我之前做过两次关于 Kubernetes、数据库以及容器的演讲。
无状态服务,即 Web 服务器、代理和应用程序代码这样的应用程序,它们可以处理数据但不进行存储。编排过程中,开发者比较喜欢使用它们,因为它们易于部署且易于扩展。如果流量上升,则只需添加更多的负载平衡。更重要的是,它们是“不变动的”;上游容器镜像和基础架构中正在运行的容器其实几乎没有区别。这意味着它们可以随时被替代,而且容器实例切换过程中几乎不需要耗费“切换成本”。
有状态的服务,即路由器、CDN(内容传送网络)、streaming 服务器和认证服务器。从部署开始,这些容器就开始与上游镜像不同了,时间越长它们的差异越大。这种差异就被称为“state(状态)”。事实上,每个运行的应用程序都至少有一个小状态(差异),但对于“无状态”应用程序来说,状态(差异)很小,而且可以进行快速替换。
对于有状态的,那就不是这样的情况了。虽然状态可以通过状态节点进行同步或复制,但是这必须通过应用程序专用的一些方法在业务流程系统之外完成。总之很麻烦。
当然,鉴于我在 PostgreSQL 工作18年的历史,我真正关心的有状态应用程序是交易型数据库。数据库对于大多数应用程序堆栈而言至关重要,而且对于状态支持来说也是一个很好的测试用例,因为它们可以用有效方式进行状态化,包括:
Storage
Identity
Session
Cluster Role
例如,PostgreSQL 需要将数据和交易存储在每个 PostgreSQL 容器(存储)持久和特有的文件中。每个容器需要被识别为特定的数据库节点,我们需要能够通过名称或地址将流量路由到它。数据库客户端连接或会话也有一个状态,打破它们需要付出一定的代价,所以我们不想随意移动数据库节点。最后,每个数据库节点在其数据库集群中都有一个角色,集群角色例如 master、replica、shard 等。这些集群角色将持续存在,直到数据库特定 event 更改它们为止。
在流行的容器云堆栈上实现这些类型的状态一直是具有挑战性的。 Docker 和编排框架将大多数类型的状态视为发生在容器堆栈之外的状态,迫使数据库架构师管理存储、身份、路由以及很多其他的东西。你没有办法将数据库移动到帮助您的容器。因此,尽管很多网页应用程序已经容器化,但几乎没有数据库或其他有状态的应用程序能够容器化。那么,我们在哪里存储数据?一般来说,可以使用 Amazon RDS。
Kubernetes 项目一直致力于一个对象和一组功能,去年称为 StatefulSet 来处理数据库和其他状态服务。开发人员最初以“PetSet”的工作名称发布了此功能,但是他们进行了更改,然后发布到1.5版本中,并且有了一个更合适的名字:StatefulSet。此时,StatefulSet 实现 Storage 和 Identity 有状态质量。其他两个可以使用最小粘合代码使用 Kubernetes 作为资源实现。换句话说,你不必等待部署协调的容器化数据库。
现在,你可以在 Kubernetes 上的容器中运行数据库,但是为什么要这样做呢?答案与容器无关,但是都与编排的好处有关。
我们期望再现代数据库平台中高可用性(HA),希望它能够脱颖而出,但这光靠数据库软件是提供不了的。引入群集,替换故障机器上的数据库节点,重新路由应用程序流量到迁移的节点,以及其他 HA 注意事项需要大量的代码和许多数据库外部以及其内部的实用程序。
这样的代码很难写,因为它需要先实现分布式系统。
像其他业务流程系统一样,Kubernetes 提供了一个简单易用的分布式系统。数据库(如 PostgreSQL和MySQL)如果没有内置的 HA,很容易变成这样,已经是 HA 的数据库(如 Cassandra 和 RethinkDB),那就可以实现全自动。从经验来说,这是比自己从头开始做更容易。
我创建了一些例子,展示如何在我的 atomicdb 演示 repo 上使用 StatefulSet 来部署 PostgreSQL。以上这些是为了说明如何使用功能,并非完整的生产部署。 Zalando 是 Patroni 集群管理项目的领导者发布了 Helm Chart,它基于 Kubernetes 的群集 PostgreSQL。
免责申明:
本文系转载,版权归原作者所有,如若侵权请联系我们进行删除!