顶级 fakapov 青色

顶级 fakapov 青色

一切都好! 

我叫Nikita,是Cian工程团队的组长。 我在公司的职责之一是将与生产基础设施相关的事故数量减少到零。
下面将要讨论的内容给我们带来了很大的痛苦,而本文的目的是防止其他人重复我们的错误或至少尽量减少其影响。 

前言

很久以前,当 Cian 由单体组成时,还没有微服务的迹象,我们通过检查 3-5 个页面来衡量资源的可用性。 

他们回答 - 一切都很好,如果他们很长时间不回答 - 警报。 他们需要下班多长时间才能被视为事件,这是由人们在会议上决定的。 工程师团队始终参与事件调查。 调查完成后,他们写了一份事后分析——一种通过电子邮件发送的报告,格式如下:发生了什么、持续了多长时间、我们当时做了什么、将来会做什么。 

网站的主要页面或我们如何理解我们已经触底

 
为了以某种方式了解错误的优先级,我们已经确定了业务功能最关键的网站页面。 使用它们,我们可以计算成功/不成功的请求和超时的数量。 这就是我们衡量正常运行时间的方式。 

假设我们发现该网站有许多非常重要的部分负责主要服务 - 搜索和提交广告。 如果失败的请求数量超过 1%,则属于严重事件。 如果在黄金时段15分钟内错误率超过0,1%,那么这也被视为严重事件。 这些标准涵盖了大多数事件;其余事件超出了本文的范围。

顶级 fakapov 青色

最佳最佳事件 青色

所以,我们肯定已经学会了确定事件发生的事实。 

现在,每个事件都被详细描述并反映在 Jira 史诗中。 顺便说一句:为此我们启动了一个单独的项目,称之为“失败”——只能在其中创建史诗。 

如果你收集过去几年的所有失败,领导者是: 

  • mssql相关事件;
  • 由外部因素引起的事件;
  • 管理错误。

让我们更详细地看看管理员的错误,以及其他一些有趣的失败。

第五名——“在 DNS 中把事情整理好”

那是一个风雨交加的星期二。 我们决定恢复 DNS 集群中的秩序。 

我想将内部 DNS 服务器从 bind 转移到 powerdns,为此分配完全独立的服务器,除了 DNS 之外什么都没有。 

我们在 DC 的每个位置放置了一台 DNS 服务器,现在是将区域从 Bind 移动到 powerdns 并将基础设施切换到新服务器的时刻到来了。 

在迁移过程中,在所有服务器上的本地缓存绑定中指定的所有服务器中,只剩下一台位于圣彼得堡的数据中心。 该 DC 最初被声明为对我们来说不重要,但突然变成了单点故障。
正是在搬迁期间,莫斯科和圣彼得堡之间的运河垮塌了。 实际上,我们有五分钟没有 DNS 服务,当托管服务商解决了问题后,我们又恢复了正常。 

结论:

如果说以前我们在准备工作时忽略了外部因素,那么现在它们也被纳入了我们正在准备的清单中。 现在我们努力确保所有组件都保留n-2,并且在工作过程中我们可以将这个级别降低到n-1。

  • 在制定行动计划时,标记出服务可能失败的点,并提前考虑一切“每况愈下”的场景。
  • 将内部 DNS 服务器分布在不同的地理位置/数据中心/机架/交换机/输入上。
  • 在每台服务器上,安装本地缓存 DNS 服务器,该服务器将请求重定向到主 DNS 服务器,如果不可用,则会从缓存中进行响应。 

第四名——“在 Nginx 中把事情整理好”

有一天,我们的团队决定“我们已经受够了”,重构 nginx 配置的过程开始了。 主要目标是将配置引入直观的结构。 以前一切都是“历史既定”,没有任何逻辑。 现在,每个 server_name 已移至同名文件,并且所有配置已分发到文件夹中。 顺便说一句,该配置包含 253949 行或 7836520 个字符,占用近 7 MB 的空间。 顶层结构: 

Nginx结构

├── access
│   ├── allow.list
...
│   └── whitelist.conf
├── geobase
│   ├── exclude.conf
...
│   └── geo_ip_to_region_id.conf
├── geodb
│   ├── GeoIP.dat
│   ├── GeoIP2-Country.mmdb
│   └── GeoLiteCity.dat
├── inc
│   ├── error.inc
...
│   └── proxy.inc
├── lists.d
│   ├── bot.conf
...
│   ├── dynamic
│   └── geo.conf
├── lua
│   ├── cookie.lua
│   ├── log
│   │   └── log.lua
│   ├── logics
│   │   ├── include.lua
│   │   ├── ...
│   │   └── utils.lua
│   └── prom
│       ├── stats.lua
│       └── stats_prometheus.lua
├── map.d
│   ├── access.conf
│   ├── .. 
│   └── zones.conf
├── nginx.conf
├── robots.txt
├── server.d
│   ├── cian.ru
│   │   ├── cian.ru.conf
│   │   ├── ...
│   │   └── my.cian.ru.conf
├── service.d
│   ├── ...
│   └── status.conf
└── upstream.d
    ├── cian-mcs.conf
    ├── ...
    └── wafserver.conf

它变得好多了,但在重命名和分发配置的过程中,其中一些配置的扩展名错误,并且没有包含在 include *.conf 指令中。 导致部分主机不可用,返回301返回主页。 由于响应代码不是 5xx/4xx,所以没有立即注意到这一点,而是在早上才注意到。 之后,我们开始编写测试来检查基础设施组件。

结论: 

  • 正确构建您的配置(不仅仅是 nginx)并在项目的早期阶段仔细考虑结构。 通过这种方式,您将使团队更容易理解它们,从而减少 TTM。
  • 为一些基础设施组件编写测试。 例如:检查所有关键服务器名称是否给出正确的状态+响应正文。 手头只要有几个脚本来检查组件的基本功能就足够了,这样就不用在凌晨 3 点疯狂地记住还需要检查什么。 

第三名——“卡桑德拉突然空间不足”

数据稳步增长,一切都很好,直到 Cassandra 集群中大型案例空间的修复开始失败的那一刻,因为压缩无法对它们起作用。 

在一个暴风雨天,该簇几乎变成了一个南瓜,即:

  • 集群中大约还剩下总空间的 20%;
  • 无法完全添加节点,因为添加节点后由于分区空间不足而无法进行清理;
  • 由于压实不起作用,生产率逐渐下降; 
  • 集群处于紧急模式。

顶级 fakapov 青色

退出 - 我们在没有清理的情况下又添加了 5 个节点,之后我们开始系统地从集群中删除它们并重新进入它们,就像空间不足的空节点一样。 花费的时间比我们想要的要多得多。 存在集群部分或完全不可用的风险。 

结论:

  • 在所有 cassandra 服务器上,每个分区上的空间占用不应超过 60%。 
  • 它们的负载不应超过 50% cpu。
  • 您不应忘记容量规划,并且需要根据每个组件的具体情况对其进行仔细考虑。
  • 集群中的节点越多越好。 包含少量数据的服务器过载速度更快,这样的集群更容易复活。 

第二名——“数据从consul键值存储中消失”

对于服务发现,我们像许多人一样使用 consul。 但我们也将其键值用于整体的蓝绿布局。 它存储有关活动和非活动上游的信息,这些信息在部署期间会改变位置。 为此,编写了与 KV 交互的部署服务。 某个时刻,KV 的数据消失了。 从记忆中恢复,但有一些错误。 因此,在上传过程中,上游的负载分布不均,并且由于后端 CPU 过载,我们收到了很多 502 错误。 因此,我们从 consul KV 迁移到 postgres,从那里删除它们不再那么容易。  

结论:

  • 未经任何授权的服务不应包含对网站运营至关重要的数据。 例如,如果您在 ES 中没有授权,那么最好在不需要的地方拒绝网络级别的访问,只保留必要的,并设置 action.delta_requires_name: true。
  • 提前练习您的备份和恢复机制。 比如提前制作一个可以备份和恢复的脚本(比如python)。

第一名——《不明显的船长》 

在某些时候,我们注意到在后端有 10 多台服务器的情况下,nginx 上游的负载分布不均匀。 由于轮询方式是按顺序从第一个上游发送请求到最后一个上游,并且每次 nginx 重新加载都会重新开始,所以第一个上游总是比其他上游收到更多的请求,导致它们的工作速度变慢,整个站点受到影响。 随着流量的增加,这一点变得越来越明显。 简单地更新 nginx 来启用随机是行不通的——我们需要重做一堆在 1 版本上没有成功的 lua 代码(当时)。 我们必须修补 nginx 1.15,引入随机支持。 这解决了问题。 该错误赢得了“非显而易见性队长”类别。

结论:

探索这个错误是非常有趣和令人兴奋的)。 

  • 组织您的监控,以便帮助您快速发现此类波动。 例如,您可以使用ELK来监控每个upstream的每个后端的rps,从nginx的角度监控它们的响应时间。 在本例中,这帮助我们识别了问题。 

因此,通过更加谨慎地对待所做的事情,大多数失败都是可以避免的。 我们必须永远记住墨菲定律: 任何可能出错的事情都会出错 并基于它构建组件。 

来源: habr.com

添加评论