我们对微服务了解多少

你好! 我叫 Vadim Madison,负责 Avito 系统平台的开发。 人们不止一次说过我们公司如何从单一架构转向微服务架构。 现在是时候分享我们如何改造我们的基础设施以充分利用微服务并防止我们迷失其中。 PaaS 如何在这方面为我们提供帮助,我们如何简化部署并将微服务的创建减少为一键式 - 请继续阅读。 并非我下面写的所有内容都在 Avito 中完全实现,其中一些是我们开发平台的方式。

(在本文的最后,我将谈论参加微服务架构专家 Chris Richardson 举办的为期三天的研讨会的机会)。

我们对微服务了解多少

我们如何走向微服务

Avito 是世界上最大的分类网站之一;每天发布超过 15 万条新广告。 我们的后端每秒接受超过 20 个请求。 我们目前有数百个微服务。

多年来我们一直在构建微服务架构。 究竟如何——我们的同事详细介绍 告诉 在 RIT++ 2017 的我们的部分。在 CodeFest 2017(参见。 视频),Sergey Orlov 和 Mikhail Prokopchuk 详细解释了为什么我们需要过渡到微服务以及 Kubernetes 在这里扮演了什么角色。 好吧,现在我们正在尽一切努力尽量减少这种架构固有的扩展成本。

最初,我们并没有创建一个能够全面帮助我们开发和推出微服务的生态系统。 他们只是收集了明智的开源解决方案,在家里推出它们并邀请开发人员来处理它们。 结果,他去了十几个地方(仪表板、内部服务),之后他更加强烈地渴望以旧的方式,在一个整体中削减代码。 下图中的绿色表示开发人员用自己的双手以某种方式完成的工作,黄色表示自动化。

我们对微服务了解多少

现在,在 PaaS CLI 实用程序中,使用一个命令创建一个新服务,并添加一个新数据库和另外两个命令并将其部署到 Stage。

我们对微服务了解多少

如何克服“微服务碎片化”时代

在单体架构中,为了产品变化的一致性,开发人员被迫弄清楚他们的邻居发生了什么。 在使用新架构时,服务上下文不再相互依赖。

此外,微服务架构要想发挥作用,还需要建立很多流程,即:

• 记录;
• 请求跟踪(Jaeger);
• 错误聚合(哨兵);
• 来自 Kubernetes(事件流处理)的状态、消息、事件;
• 竞赛限制/断路器(可以使用Hystrix);
• 服务连接控制(我们使用Netramesh);
• 监控(Grafana);
• 装配(TeamCity);
• 沟通和通知(Slack、电子邮件);
• 任务跟踪; (吉拉)
• 准备文件。

为了确保系统不会失去完整性并在扩展时保持有效,我们重新考虑了 Avito 中的微服务组织。

我们如何管理微服务

以下有助于在许多 Avito 微服务之间实施统一的“聚会策略”:

  • 将基础设施分层;
  • 平台即服务(PaaS)概念;
  • 监控微服务发生的一切。

基础设施抽象层包括三层。 让我们从上到下。

A. 顶部 - 服务网格。 起初我们尝试了 Istio,但结果发现它使用了太多资源,这对于我们的卷来说太昂贵了。 因此,架构团队的高级工程师Alexander Lukyanchenko开发了自己的解决方案—— 网网 (开源),我们目前在生产中使用它,消耗的资源比 Istio 少几倍(但并没有完成 Istio 可以夸耀的所有功能)。
B. 中型 - Kubernetes。 我们在其上部署和运行微服务。
C. 底部 - 裸露金属。 我们不使用云或 OpenStack 之类的东西,而是完全依赖裸机。

所有层均由 PaaS 组合。 而这个平台又由三部分组成。

一、发电机,通过 CLI 实用程序控制。 正是她帮助开发人员以正确的方式、以最小的努力创建微服务。

二. 联合收集器 通过通用仪表板控制所有工具。

三. 贮存。 与自动设置重要操作触发器的调度程序连接。 有了这样的系统,不会因为有人忘记在 Jira 中设置任务而错过任何一个任务。 为此,我们使用名为 Atlas 的内部工具。

我们对微服务了解多少

Avito 中微服务的实现也是按照单一方案进行的,这简化了在开发和发布的每个阶段对它们的控制。

标准微服务开发管道如何工作?

一般来说,微服务创建链是这样的:

CLI 推送 → 持续集成 → 烘焙 → 部署 → 人工测试 → 金丝雀测试 → 挤压测试 → 生产 → 维护。

让我们完全按照这个顺序来过一遍。

CLI 推送

• 创建微服务.
我们花了很长时间努力教每个开发人员如何做微服务。 这包括在 Confluence 中编写详细说明。 但计划发生了变化并得到了补充。 结果是,在旅程的开始就出现了瓶颈:启动微服务需要花费更多时间,并且在创建过程中仍然经常出现问题。

最后,我们构建了一个简单的 CLI 实用程序,可以自动执行创建微服务时的基本步骤。 事实上,它取代了第一个 git Push。 这就是她所做的。

— 根据模板以“向导”模式逐步创建服务。 我们在 Avito 后端提供了主要编程语言的模板:PHP、Golang 和 Python。

- 一次一个命令,在特定机器上部署本地开发环境 - Minikube 启动,Helm 图表自动生成并在本地 kubernetes 中启动。

— 连接所需的数据库。 开发人员不需要知道 IP、登录名和密码即可访问他所需的数据库 - 无论是本地、阶段还是生产中。 此外,数据库立即以容错配置和平衡方式部署。

— 它自行执行现场组装。 假设开发人员通过他的 IDE 更正了微服务中的某些内容。 该实用程序会看到文件系统中的更改,并根据这些更改重建应用程序(对于 Golang)并重新启动。 对于 PHP,我们只需转发多维数据集内的目录,然后“自动”获得实时重新加载。

— 生成自动测试。 虽然是空​​白形式,但非常适合使用。

• 微服务部署.

部署微服务对于我们来说曾经是一件苦差事。 需要以下内容:

一、Dockerfile。

二. 配置。
三. Helm 图表,它本身很麻烦,包括:

——图表本身;
— 模板;
——考虑到不同环境的具体值。

我们已经消除了重新设计 Kubernetes 清单的痛苦,因此它们现在可以自动生成。 但最重要的是,他们将部署简化到了极限。 从现在开始,我们有了一个 Dockerfile,开发人员将整个配置写入一个简短的 app.toml 文件中。

我们对微服务了解多少

是的,在 app.toml 本身中暂时没有什么可做的。 我们指定在哪里以及要启动多少个服务副本(在开发服务器上、在登台上、在生产中),并指示其依赖项。 请注意 [engine] 块中的行号 = "small"。 这是将通过 Kubernetes 分配给服务的限制。

然后,根据配置,自动生成所有必要的 Helm 图表并创建与数据库的连接。

• 基本验证。 此类检查也是自动化的。
需要追踪:
— 有 Dockerfile 吗?
— 有app.toml吗;
— 有可用的文档吗?
——依赖关系是否有序?
— 是否设置了警报规则。
最后一点:服务的所有者自己决定要监控哪些产品指标。

• 准备文件。
仍然是一个问题领域。 它似乎是最明显的,但同时它也是一个“经常被遗忘”的记录,因此也是链条中的一个脆弱环节。
每个微服务都有必要有文档。 它包括以下块。

一、服务简要说明。 从字面上讲几句话来说明它的作用以及为什么需要它。

二. 架构图链接。 重要的是,快速浏览一下就很容易理解,例如,您是否使用 Redis 进行缓存或作为持久模式的主要数据存储。 目前在 Avito 中,这是到 Confluence 的链接。

三. 运行手册。 关于启动服务以及处理该服务的复杂性的简短指南。

四。 常问问题,最好能够预测您的同事在使用该服务时可能遇到的问题。

五、API端点说明。 如果您突然没有指定目的地,那么与您的微服务相关的同事几乎肯定会为此付出代价。 现在我们使用 Swagger 和我们的解决方案来解决这个问题,称为brief。

六. 标签。 或者显示服务所属公司的产品、功能或结构部门的标记。 例如,它们可以帮助您快速了解您是否正在削减同事一周前为同一业务部门推出的功能。

七. 服务的所有者或所有者。 在大多数情况下,它(或它们)可以使用 PaaS 自动确定,但为了安全起见,我们要求开发人员手动指定它们。

最后,类似于代码审查,审查文档是一个很好的做法。

持续整合

  • 准备存储库。
  • 在 TeamCity 中创建管道。
  • 设置权限。
  • 搜索服务所有者。 这里有一个混合方案 - 手动标记和 PaaS 的最小自动化。 当服务被转移到另一个开发团队以获得支持时,或者例如,如果服务开发人员退出时,全自动方案就会失败。
  • 在 Atlas 中注册服务 (往上看)。 及其所有所有者和依赖项。
  • Проверка миграций. 我们检查其中是否有潜在危险。 例如,其中之一会弹出更改表或其他内容,这可能会破坏不同版本服务之间数据模式的兼容性。 然后,不会执行迁移,而是将其放入订阅中 - PaaS 必须在可以安全使用它时向服务所有者发出信号。

下一阶段是在部署之前打包服务。

  • 构建应用程序。 根据经典 - 在 Docker 镜像中。
  • 为服务本身和相关资源生成 Helm 图表。 包括数据库和缓存。 它们是根据 CLI 推送阶段生成的 app.toml 配置自动创建的。
  • 为管理员创建开放端口的票证 (在需要的时候)。
  • 运行单元测试并计算代码覆盖率。 如果代码覆盖率低于指定的阈值,那么该服务很可能不会进一步进行部署。 如果处于可接受的边缘,那么该服务将被分配一个“悲观”系数:然后,如果该指标随着时间的推移没有改善,开发人员将收到测试方面没有进展的通知(并且需要对此采取一些措施)。
  • 考虑内存和 CPU 限制。 我们主要用Golang编写微服务并在Kubernetes中运行它们。 因此,与 Golang 语言的特性相关的一个微妙之处是:默认情况下,启动时,会使用机器上的所有内核,如果您没有显式设置 GOMAXPROCS 变量,并且当在同一台机器上启动多个此类服务时,它们会开始运行。争夺资源,互相干扰。 下图显示了在无争用且处于资源竞争模式下运行应用程序时执行时间的变化情况。 (图表来源为 这里).

我们对微服务了解多少

执行时间越少越好。 最大值:643ms,最小值:42ms。 照片是可点击的。

我们对微服务了解多少

手术时间越少越好。 最大值:14091 ns,最小值:151 ns。 照片是可点击的。

在装配准备阶段,您可以显式设置此变量,也可以使用库 自动最大进程 来自 Uber 的人。

部署

• 检查约定。 在开始将服务程序集交付到预期环境之前,您需要检查以下内容:
- API 端点。
— API 端点响应与架构的合规性。
— 日志格式。
— 设置服务请求的标头(当前由 netramesh 完成)
— 在向事件总线发送消息时设置所有者令牌。 这是跟踪总线上服务的连接性所必需的。 您既可以将幂等数据发送到总线,这不会增加服务的连接性(这很好),也可以发送加强服务的连接性的业务数据(这非常糟糕!)。 当这种连接成为问题时,了解谁写入和读取总线有助于正确分离服务。

阿维托的会议还不是很多,但其数量正在扩大。 此类协议以团队能够理解和理解的形式提供的越多,就越容易维护微服务之间的一致性。

综合测试

• 闭环测试。 为此,我们现在使用开源 悬浮飞行。 首先,它记录服务上的真实负载,然后 - 只是在一个闭环中 - 它模拟它。

• 压力测试。 我们努力使所有服务达到最佳性能。 并且每个服务的所有版本都必须经过负载测试——这样我们就可以了解服务当前的性能以及与同一服务的先前版本的差异。 如果在服务更新后,其性能下降了一倍半,这对其所有者来说是一个明确的信号:您需要深入研究代码并纠正这种情况。
例如,我们使用收集到的数据来正确实现自动扩展,并最终大致了解服务的可扩展性。

在负载测试期间,我们检查资源消耗是否满足设定的限制。 我们主要关注极端情况。

a) 我们查看总负载。
- 太小 - 如果负载突然下降几次,很可能有些东西根本不起作用。
- 太大 - 需要优化。

b) 我们根据 RPS 查看截止值。
这里我们看一下当前版本与上一版本的差异以及总量。 例如,如果某个服务产生 100 个 rps,那么它要么写得不好,要么这就是它的特殊性,但无论如何,这都是仔细查看该服务的原因。
相反,如果 RPS 太多,则可能存在某种错误,某些端点已停止执行有效负载,而其他端点则被简单地触发 return true;

金丝雀测试

通过综合测试后,我们在少量用户上测试微服务。 我们从该服务的目标受众中的一小部分开始谨慎行事——不到 0,1%。 在这个阶段,将正确的技术和产品指标纳入监控中非常重要,以便它们尽快显示服务中的问题。 金丝雀测试的最短时间为 5 分钟,主要时间为 2 小时。 对于复杂的服务,我们手动设置时间。
我们分析:
— 特定于语言的指标,特别是 php-fpm 工作人员;
— Sentry 中的错误;
——响应状态;
——响应时间,准确的和平均的;
- 潜伏;
——已处理和未处理的异常;
——产品指标。

挤压测试

挤压测试也称为“挤压”测试。 该技术的名称被引入 Netflix。 其本质是,首先我们用真实流量填充一个实例直至故障点,从而设置其限制。 然后我们添加另一个实例并加载这一对 - 再次达到最大值; 我们在第一次“挤压”时看到了它们的上限和三角洲。 因此,我们一次连接一个实例并计算变化模式。
通过“挤压”的测试数据也会流入一个通用的指标数据库,我们可以用它们丰富人工负载结果,甚至用它们代替“合成”。

生产

• 缩放。 当我们将服务推出到生产环境时,我们会监控它的扩展情况。 根据我们的经验,仅监控CPU指标是无效的。 使用 RPS 基准测试的自动扩展以其纯粹的形式有效,但仅适用于某些服务,例如在线流媒体。 因此,我们首先关注特定于应用程序的产品指标。

因此,在缩放时我们分析:
- CPU和RAM指示器,
— 队列中的请求数量,
- 响应时间,
——基于累积历史数据的预测。

扩展服务时,监控其依赖关系也很重要,这样我们就不会扩展链中的第一个服务,并且它访问的服务会在负载下失败。 为了为整个服务池建立可接受的负载,我们查看“最近”依赖服务的历史数据(基于 CPU 和 RAM 指标的组合,加上特定于应用程序的指标)并将其与历史数据进行比较初始化服务的信息,等等,从上到下贯穿整个“依赖链”。

维修

微服务投入运行后,我们可以为其附加触发器。

以下是触发发生的典型情况。
— 检测到潜在危险的迁移。
— 安全更新已发布。
— 服务本身已经很久没有更新了。
— 服务负载明显下降或部分产品指标超出正常范围。
— 该服务不再满足新平台要求。

有些触发器负责运行的稳定性,有些则作为系统维护的功能,例如某些服务已经很长时间没有部署并且其基础镜像已不再通过安全检查。

仪表板

简而言之,仪表板就是我们整个PaaS的控制面板。

  • 有关服务的单点信息,包括有关其测试覆盖范围、图像数量、生产副本数量、版本等的数据。
  • 一种按服务和标签(属于业务部门、产品功能等的标记)过滤数据的工具
  • 与用于跟踪、记录和监控的基础设施工具集成的工具。
  • 单点服务文档。
  • 跨服务的所有事件的单一观点。

我们对微服务了解多少
我们对微服务了解多少
我们对微服务了解多少
我们对微服务了解多少

在总

在引入 PaaS 之前,新开发人员可能会花几周时间了解在生产中启动微服务所需的所有工具:Kubernetes、Helm、我们的内部 TeamCity 功能、以容错方式设置与数据库和缓存的连接等。需要几个小时来阅读快速入门并创建服务本身。

我在 HighLoad++ 2018 上做了一个关于这个主题的报告,你可以观看 视频 и 介绍.

读到最后的人的奖励曲目

我们 Avito 正在为来自以下国家的开发人员组织为期三天的内部培训: 克里斯·理查森,微服务架构专家。 我们想为本文的一位读者提供参与其中的机会。 这是 培训计划已发布。

训练将于5月7日至XNUMX日在莫斯科举行。 这些工作日将被占用。 午餐和培训将在我们的办公室进行,选定的参与者将自行支付交通费和住宿费。

您可以申请参与 在这个谷歌表格中。 来自您的 - 为什么您需要参加培训的问题的答案以及如何与您联系的信息。 用英语回答,因为克里斯将亲自选择参加培训的参与者。
我们将在这篇文章的更新中以及面向开发人员的社交网络 Avito 上公布培训参与者的姓名(AvitoTech Фейсбуке, VKONTAKTE, 叽叽喳喳)不迟于 19 月 XNUMX 日。

来源: habr.com

添加评论