Yandex Cloud中如何安排托管数据库服务

当您信任某人拥有的最宝贵的东西时-您的应用程序或服务的数据-您想想像一下这个人将如何处理您的最大价值。

我叫Vladimir Borodin,我是Yandex.Cloud数据平台的负责人。 今天,我想告诉您,如何在Yandex托管数据库服务中安排和运行所有内容,为什么要那样做,以及从用户的角度来看,我们各种解决方案的优点是什么? 当然,您一定会发现我们计划在不久的将来完成哪些工作,以便为需要它的每个人提供更好,更方便的服务。

好吧,走吧!

图片

托管数据库(Yandex托管数据库)是最流行的Yandex.Cloud服务之一。 更确切地说,这是一整套服务,现在在流行度方面仅次于Yandex Compute Cloud虚拟机。

Yandex托管数据库使快速获取可用的数据库并执行以下任务成为可能:

  • 扩展-从添加计算资源或磁盘空间的基本功能到增加副本和分片的数量。
  • 安装次要和主要更新。
  • 备份和还原。
  • 提供容错能力。
  • 监控方式
  • 提供方便的配置和管理工具。

托管数据库服务的排列方式:顶视图


该服务包括两个主要部分:控制平面和数据平面。 简而言之,Control Plane是一个数据库管理API,可用于创建,修改或删除数据库。 数据平面是直接数据存储的级别。

图片

服务用户实际上有两个入口点:

  • 在控制平面中。 实际上,有很多输入-Web控制台,CLI实用程序以及提供公共API(gRPC和REST)的网关API。 但是所有这些最终都转到我们称为内部API的位置,因此,我们将把这一入口点视为控制平面。 实际上,这是托管数据库(MDB)服务职责范围的起点。
  • 在数据平面中。 这是通过对DBMS的访问协议与正在运行的数据库的直接连接。 例如,如果它是PostgreSQL,则它将是libpq接口

图片
下面,我们将更详细地描述数据平面中发生的所有事情,并且我们将分析控制平面的每个组件。

数据平面


在查看控制平面的组件之前,让我们看一下数据平面中发生的情况。

在虚拟机内部


MDB在Yandex Compute Cloud中提供的相同虚拟机中运行数据库。

图片

首先,在那里部署了数据库引擎,例如PostgreSQL。 同时,可以启动各种辅助程序。 对于PostgreSQL,这将是数据库连接工具Odyssey

同样在虚拟机内部,启动了一组特定的标准服务,每个DBMS都有自己的服务:

  • 用于创建备份的服务。 对于PostgreSQL,它是一个开源的WAL-G工具 它创建备份并将其存储在Yandex Object Storage中
  • Salt Minion是SaltStack系统中用于操作和配置管理的组件。 部署基础结构的说明中提供了有关它的更多信息。
  • MDB指标,负责将数据库指标传输到Yandex Monitoring和我们的微服务,以监控MDB Health群集和主机的状态。
  • 推送客户端将DBMS日志和计费日志发送到Logbroker服务,这是用于收集和传递数据的特殊解决方案。
  • MDB cron-我们的自行车,与通常的cron不同,它能够以每秒一秒的精度执行定期任务。

网络拓扑


图片

每个Data Plane主机都有两个网络接口:

  • 其中之一进入用户网络。 通常,需要服务产品负载。 通过它,复制正在追逐。
  • 第二个进入我们的托管网络之一,主机通过该网络进入控制平面。

是的,不同客户端的主机被卡在一个这样的受管网络中,但这并不可怕,因为在受管接口上(几乎)没有监听,控制平面中的传出网络连接只是从中打开。 几乎没有人,因为有开放的端口(例如SSH),但是它们被仅允许来自特定主机的连接的本地防火墙关闭。 因此,如果攻击者获得了具有数据库的虚拟机的访问权限,则他将无法访问其他人的数据库。

数据平面安全


既然我们在谈论安全性,那么必须说,我们最初是基于攻击者在群集虚拟机上获得根目录而设计的服务。

最后,我们在以下方面做了很多努力:

  • 本地和大型防火墙;
  • 加密所有连接和备份;
  • 全部带有身份验证和授权;
  • AppArmor
  • 自行编写的IDS。

现在考虑控制平面的组件。

控制平面


内部API


内部API是控制平面的第一个入口点。 让我们看看这里的一切。

图片

假设内部API收到创建数据库集群的请求。

首先,内部API访问云服务访问服务,该服务负责检查用户的身份验证和授权。 如果用户通过了验证,则内部API会检查请求本身的有效性。 例如,创建集群而不指定其名称或使用已经采用的名称的请求将使测试失败。
内部API可以将请求发送到其他服务的API。 如果要在特定网络A中创建集群,并在特定子网B中创建特定主机,则内部API必须确保您同时拥有网络A和指定子网B的权限。同时,它将检查子网B是否属于网络A。这需要访问基础结构API。

如果请求有效,则有关创建的群集的信息将保存在配置数据库中。 我们称其为MetaDB,它已部署在PostgreSQL上。 MetaDB有一个带有操作队列的表。 内部API保存有关操作的信息,并以事务方式设置任务。 之后,有关操作的信息将返回给用户。

通常,对于处理内部API的大多数请求,使用MetaDB和相关服务的API就足够了。 但是,内部API还可以用来回答一些查询的另外两个组件-LogsDB(用户群集日志所在的位置)和MDB运行状况。 关于它们中的每一个将在下面更详细地描述。

工人


工作程序只是一组查询MetaDB中的操作队列,获取它们并执行它们的过程。

图片

创建集群时,工作人员将做什么? 首先,他转向用于从我们的映像创建虚拟机的基础结构API(它们已经安装了所有必需的软件包,并且已配置了大多数东西,映像每天更新一次)。 创建虚拟机并在其中建立网络后,工作人员将转向Deploy基础架构(稍后将向您详细介绍)将用户所需的内容部署到虚拟机。

此外,工作人员访问其他云服务。 例如,要在Yandex Object Storage中创建一个存储桶,以在其中存储集群备份。 Yandex Monitoring服务,它将收集和可视化数据库指标。 工作人员必须在此处创建群集元信息。 如果用户要向群集主机分配公共IP地址,请使用DNS API。

通常,工人的工作非常简单。 它从配置数据库队列中接收任务,并访问所需的服务。 完成每个步骤后,工作人员将有关操作进度的信息存储在元数据库中。 如果发生故障,任务将重新启动并从中断处开始运行。 但是即使从一开始就重新启动也不是问题,因为几乎所有类型的工作任务都是幂等的。 这是因为工作人员可以执行该操作的一个或另一个步骤,但是MetaDB中没有与此有关的信息。

部署基础架构


最底层是SaltStack ,这是一个用Python编写的相当普遍的开源配置管理系统。 该系统非常可扩展 ,为此我们非常喜欢。

盐的主要成分是盐母版,它存储有关应应用的内容以及在何处的信息,以及安装在每个主机上的代理盐奴才与母版进行交互,并且可以将盐从盐母版直接应用于主机。 就本文而言,我们已经掌握了足够的知识,您可以在SaltStack文档中阅读更多内容

一个盐大师不是容错的,并且不能扩展到成千上万的奴才,所以需要几个盐大师。 直接与工作人员进行交互并不方便,我们在Salt上编写了绑定,我们将其称为Deploy框架。

图片

对于工作人员而言,唯一的入口点是Deploy API,它实现了诸如“将整个状态或其各个部分应用于这样的奴才”和“告诉这样的这样的状态”之类的方法。 Deploy API将有关所有首次发布及其特定步骤的信息存储在DeployDB中,在该数据库中我们也使用PostgreSQL。 有关所有奴才和主人的信息以及有关第一至第二者的财产的信息也存储在此处。

盐母版上安装了两个附加组件:

  • Salt REST API ,与Deploy API进行交互以启动部署。 REST API转到本地的盐管理器,他已经使用ZeroMQ与小兵通信。
  • 本质是,它转到Deploy API并接收必须连接到此Salt-master的所有奴才的公钥。 在主机上没有公钥的情况下,奴才根本无法连接到主机。

除了盐矿之外,数据平面中还安装了两个组件:

  • Returner-一个模块(盐中的可扩展部分之一),不仅将发布结果带给salt-master,而且还带给Deploy API。 部署API通过转到向导上的REST API来启动部署,并通过从奴才返回的结果接收结果。
  • Master Pinger,它定期轮询应将Master Minions连接到的Deploy API。 如果Deploy API返回一个新的向导地址(例如,由于旧的向导地址已失效或过载),则pinger将重新配置该奴才。

我们使用SaltStack可扩展性的另一个地方是ext_pillar-从外部某个地方获取支柱的能力(一些静态信息,例如PostgreSQL的配置,用户,数据库,扩展等)。 因为它们存储在MetaDB中,所以我们从模块转到Internal API以获取特定于群集的设置。

另外,我们注意到,该支柱还包含机密信息(用户密码,TLS证书,用于加密备份的GPG密钥),因此,首先,所有组件之间的所有交互均被加密(不在我们的任何数据库中)没有TLS,HTTPS的情况下,奴才和主人也会加密所有流量)。 其次,所有这些机密都在MetaDB中加密,并且我们使用机密分离-在内部API机器上,有一个公钥在将所有机密存储到MetaDB中之前对其进行加密,并且其私有部分位于Salt Master上,只有它们才能被获取。公开秘密,以作为奴隶的支柱(再次通过加密通道)转移。

MDB健康


使用数据库时,了解它们的状态很有用。 为此,我们拥有MDB Health微服务。 它从MDB虚拟机MDB的内部组件接收主机状态信息,并将其存储在其自己的数据库(在本例中为Redis)中。 当有关特定群集状态的请求到达内部API时,内部API使用来自MetaDB和MDB Health的数据。

图片

API中所有主机上的信息都以易于理解的形式进行处理和显示。 除了某些DBMS的主机和群集的状态外,MDB Health还返回特定主机是主主机还是副本主机。

MDB DNS


需要MDB DNS微服务来管理CNAME记录。 如果用于连接数据库的驱动程序不允许在连接字符串中传输多个主机,则可以连接到特殊的CNAME ,该CNAME始终指示集群中的当前主服务器。 如果主服务器切换,则CNAME会更改。

图片

怎么样了 如上所述,在虚拟机内部有一个MDB cron,它会定期向MDB DNS发送以下内容的心跳信号:“在此群集中,CNAME记录必须指向我。” MDB DNS接受来自所有虚拟机的此类消息,并决定是否更改CNAME记录。 如有必要,它将通过DNS API更改记录。

我们为什么为此单独提供服务? 因为DNS API仅在区域级别具有访问控制。 潜在的攻击者获得对单独虚拟机的访问权限,可以更改其他用户的CNAME记录。 MDB DNS排除了这种情况,因为它检查授权。

传送和显示数据库日志


当虚拟机上的数据库写入日志时,特殊的推式客户端组件将读取该记录,并将刚刚出现的行发送给Logbroker( 他们已经在Habré上写过了)。 推送客户端与LogBroker的交互是基于完全语义构建的:我们一定会发送它,并确保严格执行一次。

一个单独的计算机池-LogConsumers-从LogBroker队列中获取日志并将其存储在LogsDB数据库中。 ClickHouse DBMS用于日志数据库。

图片

当请求发送到内部API以显示特定集群在特定时间间隔内的日志时,内部API会检查授权并将请求发送到LogsDB。 因此,日志传送循环完全独立于日志显示循环。

开票


计费方案以类似的方式构建。 在虚拟机内部,有一个组件可以按一定的周期检查数据库是否一切正常。 如果一切顺利,则可以从上次启动之时起在该时间间隔进行结算。 在这种情况下,将在记帐日志中进行记录,然后推送客户端将记录发送到LogBroker。 来自Logbroker的数据被传输到计费系统,并在那里进行计算。 这是用于运行集群的计费方案。

如果关闭群集,则将停止对计算资源的使用收费,但是,对磁盘空间进行收费。 在这种情况下,无法从虚拟机进行计费,并且涉及第二个电路-离线计费电路。 有一个单独的计算机池,这些池从MetaDB中抽出关闭群集的列表,并在Logbroker中以相同的格式写入日志。

离线计费也可以用于计费和包含集群,但是我们将为主机计费,即使它们正在运行,但是它们不起作用。 例如,当您将主机添加到群集时,它会从备份中部署并进行复制。 为此,向用户收费是错误的,因为主机在这段时间内处于非活动状态。

图片

后备


对于不同的DBMS,备份方案可能略有不同,但是一般原理始终相同。

每个数据库引擎都使用自己的备份工具。 对于PostgreSQL和MySQL,这是WAL-G 。 它创建备份,对其进行压缩,对其进行加密,然后将其放入Yandex Object Storage中 。 同时,每个群集都放在一个单独的存储桶中(首先是隔离,其次是为了更容易节省备份空间),并使用自己的加密密钥对其进行加密。

图片

这就是控制平面和数据平面的工作方式。 由此,形成了Yandex.Cloud托管数据库服务。

为什么一切都这样安排


当然,在全球范围内,可以根据更简单的方案来实现某些目标。 但是我们有自己的理由不遵循阻力最小的道路。

首先,我们希望对所有类型的DBMS都有一个通用的控制平面。 选择哪一个都没有关系,最终您的请求将到达相同的内部API,并且其下的所有组件对于所有DBMS都是相同的。 就技术而言,这使我们的生活更加复杂。 另一方面,引入影响所有DBMS的新特性和功能要容易得多。 这只完成一次,而不是六个。

对我们来说第二个重要时刻-我们想确保数据平面与控制平面的独立性尽可能大。 今天,即使“控制平面”完全不可用,所有数据库也将继续工作。 该服务将确保其可靠性和可用性。

第三,几乎任何服务的开发总是一个折衷方案。 从广义上讲,从广义上讲,更重要的是发布的发布速度,以及更高的可靠性。 同时,现在没有人可以负担一年或两次的发行,这是显而易见的。 如果您查看Control Plane,这里我们关注的是开发速度,新功能的快速介绍,每周发布几次更新。 Data Plane负责数据库的安全性和容错能力,因此这是一个完全不同的发布周期,以周为单位。 在发展方面的这种灵活性也使我们相互独立。

另一个示例:通常,托管数据库服务仅向用户提供网络驱动器。 Yandex.Cloud还提供本地驱动器。 原因很简单:它们的速度要高得多。 例如,使用网络驱动器,可以更轻松地上下扩展虚拟机。 以网络存储快照的形式进行备份比较容易。 但是许多用户需要高速,因此我们将备份工具的等级提高了。

未来计划


关于中期改善计划的几句话。 这些计划会影响整个Yandex托管数据库,而不是单个DBMS。

首先,我们要在设置备份创建频率方面提供更大的灵活性。 在某些情况下,有必要每天在一天中每隔几小时进行一次备份,在一周中(一天一次,在一个月中一次),在一年中每周一次(在一年中)每月一次。 为此,我们正在内部API和Yandex Object Storage之间开发一个单独的组件。

对用户和我们而言都重要的另一个重要方面是操作的速度。 最近,我们对Deploy基础结构进行了重大更改,并将几乎所有操作的执行时间减少到几秒钟。 仅介绍了创建集群并将主机添加到集群的操作。 第二次操作的执行时间取决于数据量。 但是第一个我们会在不久的将来加快速度,因为用户经常希望在其CI / CD管道中创建和删除群集。

我们的重要案例列表包括添加了自动增加磁盘大小的功能。 现在,这是手动完成的,这不是很方便,也不是很好。

最后,我们为用户提供了大量图表,显示数据库中正在发生的事情。 我们授予对日志的访问权限。 同时,我们看到有时数据不足。 需要其他图形,其他切片。 在这里,我们还计划改进。

我们有关托管数据库服务的故事很长,可能很乏味。 比任何文字和描述都要好,只有真正的实践。 因此,如果需要,您可以独立评估我们的服务功能:

Source: https://habr.com/ru/post/zh-CN477860/


All Articles