顶级法卡波夫·青色



对所有人都好! 

我叫Nikita,我是Cyan工程师的团队负责人。我在公司的职责之一是将与产品上的基础结构相关的事件数量减少到零。
稍后将讨论的内容给我们带来了很多痛苦,本文的目的是防止其他人重复我们的错误或至少将其影响最小化。 

前言


曾几何时,当Cyan由单块组成,并且还没有微服务的提示时,我们通过检查3-5页来测量资源的可用性。 

答案-一切正常,不要长时间响应-警报。人们在会议上决定,他们应该花多少时间才能将其视为事件。工程师团队一直参与事件调查。调查完成后,他们写了一份验尸报告-一种格式的报告给邮局:当时是什么,持续了多长时间,他们现在做什么,将来我们会做什么。 

网站的首页,或者据我们所知,已经跌破了谷底

 
为了以某种方式理解错误的优先级,我们突出显示了该网站针对业务功能最关键的页面。根据他们的意见,我们考虑成功/失败请求和超时的数量。因此,我们测量正常运行时间。 

假设我们发现站点中有许多超重要部分负责主要服务-搜索和提交公告。如果失败的请求数大于1%,则这是严重事件。如果在黄金时间的15分钟内错误百分比超过0.1%,则这也被视为严重事件。这些标准涵盖了大多数事件,其余事件超出了本文的范围。



最佳的青色事故


因此,我们精确地学会了确定事件发生的事实。 

现在,对我们国家的每起事件都进行了详细描述,并反映在吉拉史诗中。顺便说一句:为此,我们启动了一个单独的项目,称为FAIL-只能在其中创建史诗。 

如果您收集过去几年中所有的失败,那么领导者是: 

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

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

第五名-“将域名放入DNS”


星期二下雨天。我们决定清理DNS群集。 

我想将内部dns服务器从绑定转移到powerdns,从而突出显示完全独立的服务器,除了dns外没有其他东西。 

我们在DC的每个位置上都放置了一台dns服务器,此刻该将区域从绑定移动到powerdns,并将基础结构切换到新服务器。 

在移动高峰时,在本地缓存中指示的所有服务器都绑定在所有服务器上,圣彼得堡的数据中心中只有一个。最初,这个DC对我们来说并不重要,但突然变成了单点故障。
就在这样的搬迁时期,莫斯科和圣彼得堡之间的通道下降了。实际上,我们在没有DNS的情况下保持了五分钟,并在托管人解决问题后起床。 

结论:

如果以前我们在准备工作时忽略了外部因素,那么现在这些因素也包括在我们正在准备的工作清单中。现在,我们努力确保所有组件都保留为n-2,并且在工作期间我们可以将该级别降低为n-1。

  • 在制定行动计划时,请先标记出服务可能下降的要点,并事先考虑一切都变得“比没有地方糟”的情况。
  • 通过不同的地理位置/数据中心/机架/交换机/输入来分配内部DNS服务器。
  • 在每台服务器上,放置一个本地缓存dns服务器,该服务器将请求重定向到主dns服务器,如果该请求不可用,它将从缓存中响应。 

第四名-“清理Nginx”


一天,我们的团队决定“足够忍受”,重构nginx配置的过程开始了。主要目标是使配置具有直观的结构。以前,一切都是“历史悠久的”,其本身没有逻辑。现在,每个server_name都被取出到同名文件中,并将所有配置分发到文件夹中。顺便说一下,配置包含253949行或7836520个字符,占用了将近7兆字节。顶层结构: 

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。
  • 对于某些基础架构组件,编写测试。例如:检查所有关键的server_names返回正确的状态+响应主体。只需要几个脚本来检查组件的基本功能就足够了,这样您就不必在凌晨3点疯狂地记住其他需要检查的内容。 

第三名-“卡桑德拉(Cassandra)突然结束”


数据一直在稳定增长,直到Cassandra群集中的大型案例的修复工作开始下降之前,一切都很好,因为无法对其进行压缩。 

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

  • 名额仍占集群总数的20%;
  • 您无法完全添加节点,因为添加分区后由于分区空间不足而无法进行清理;
  • 由于压缩不起作用,性能会略有下降; 
  • 群集处于紧急模式。



退出-添加了另外5个无需清理的节点,之后它们开始系统地从群集中删除,然后将它们重新输入为结束该节点的空节点。时间花费比我们想要的多得多。存在集群部分或完全无法访问的风险。 

发现:

  • 所有cassandra服务器应占用每个分区上不超过60%的空间。 
  • 它们应加载不超过50%的CPU。
  • 不要阻塞容量规划,而要根据其具体情况为每个组件仔细考虑。
  • 集群中的节点越多越好。包含少量数据的服务器迁移速度更快,并且这样的集群更易于恢复。 

第二名-“领事键值存储中的数据已消失”


对于服务发现,我们和许多人一样使用领事。但是这里,它的键值也用于蓝绿色整块计算。它存储有关活动上游和非活动上游的信息,这些信息在部署期间会更改位置。为此,编写了与KV交互的部署服务。在某些时候,来自KV的数据消失了。从内存中恢复,但有许多错误。结果,在计算过程中,上游的负载分布不均,并且由于CPU后端过载而导致很多502错误。结果,我们从领事KV转移到postgres,从那里移除它们并不容易。  

发现:

  • - . , ES — , , , action.destructive_requires_name: true.
  • . , ( ,  python), .

— « » 


在某些时候,如果后端有10台以上的服务器,我们会注意到nginx上游的负载分布不均。由于轮循机制将请求从1顺序发送到最后一个上游,并且每次nginx重新加载都是从头开始的,因此第一个上游总是比其余上游有更多请求,结果,它们的工作速度较慢,整个站点遭受了损失。随着流量的增加,这一点变得更加明显。仅仅更新nginx以启用随机功能是行不通的-您需要重做一堆在版本1.15上还没有启动的lua代码(当时)。我必须修补我们的nginx 1.14.2,在其中引入随机支持。这样就解决了问题。该错误赢得了“队长非显而易见性”提名。

结论:

研究此bug非常有趣,令人兴奋。 

  • 设置监视,以帮助快速发现此类波动。例如,您可以使用ELK监视每个上游的每个后端上的rp,并从nginx的角度监视它们的响应时间。在这种情况下,它有助于我们识别问题。 

因此,可以采用更加谨慎的方法来避免大多数失败。您必须始终牢记墨菲定律:  任何可能出错的地方都会出错,并基于该错误构建组件。 

All Articles