Citymobil-在初创企业业务增长中提高可用性的手册。 第三部分



这是该系列的下一篇文章,描述了我们如何提高Citymobil的服务可用性(您可以在此处此处阅读之前的部分)。 在其他部分,我将详细讨论事故和停机。 但是首先让我强调一下我应该在第一篇文章中谈到但没有的事情。 我从读者的反馈中发现了这一点。 本文使我有机会解决这一烦人的缺点。

1.序言


一位读者问我一个非常公平的问题:“打车服务的后端到底有什么复杂?” 这是一个好问题。 去年夏天,在开始在Citymobil工作之前,我问了我一个问题。 我当时在想:“这只是带有三按钮应用程序的出租车服务。” 那有多难? 它变成了高科技产品。 为了澄清我在说什么,这是什么重大的技术,我将向您介绍Citymobil的一些产品方向:

  • 定价。 我们的定价团队会随时随地解决最佳乘车价格问题。 价格由基于统计数据和其他一些数据的供需平衡预测确定。 所有这些都是通过基于机器学习的复杂且不断开发的服务来完成的。 定价团队还负责各种付款方式的实施,旅行结束后的额外费用,退款,计费,与合作伙伴和驾驶员的互动。
  • 订单分派。 哪辆车完成了客户的订单? 例如,就行程次数的最大化而言,选择最接近的车辆并不是最好的选择。 更好的选择是匹配汽车和客户,以便考虑到特定客户在这种特定情况下(因为等待时间太长)取消订单的可能性以及该特定驾驶员取消或破坏订单的可能性,从而最大化出行次数(例如,因为距离太大或价格太小)。
  • 地理位置 有关地址搜索和建议,接送点,预计到达时间的调整(我们的地图供应合作伙伴并不总是向我们提供允许交通的准确ETA信息),直接和反向地理编码精度提高,汽车到达点精度提高。 有很多数据,很多分析,很多基于机器学习的服务。
  • 反欺诈 乘客和驾驶员旅行成本的差异(例如,短途旅行)为试图窃取我们钱财的入侵者创造了经济诱因。 处理欺诈与处理垃圾邮件有点类似-准确性和召回率都非常重要。 我们需要阻止最大数量的欺诈(召回),但同时我们也无法将好的用户吸引到欺诈(精确)上。
  • 驾驶员激励团队负责监督一切开发活动,这些活动可以通过各种奖励措施来增加驾驶员对我们平台的使用以及驾驶员的忠诚度。 例如,完成X次旅行并获得额外的Y钱。 或购买Z的档次,然后无佣金地开车。
  • 驱动程序应用程序后端。 订单清单,需求图(显示驾驶员要最大化利润的去向),状态更改,与驾驶员的通信系统以及许多其他内容。
  • 客户端应用后端(这可能是最明显的部分,这就是人们通常所说的“出租车后端”):订单放置,订单状态信息,在地图上提供小汽车的移动,后端提示等。

这只是冰山一角。 还有更多功能。 似乎很简单的界面后面是冰山的巨大水下部分。

现在让我们回到事故中。 六个月的事故历史记录记录得出以下分类:

  • 错误版本:500个内部服务器错误;
  • 不良发布:数据库过载;
  • 不幸的是手动系统操作交互;
  • 复活节彩蛋;
  • 外部原因;
  • 发行不良:功能损坏。

下面,我将详细介绍我们针对最常见的事故类型得出的结论。

2.发行错误:500个内部服务器错误


我们的后端主要是用PHP(一种弱类型的解释语言)编写的。 我们将发布由于类或函数名称错误而崩溃的代码。 这只是发生500个错误时的一个示例。 它也可能是由代码中的逻辑错误引起的。 错误的分支被释放; 包含代码的文件夹被误删除; 测试所需的临时工件保留在代码中; 表格结构未根据代码进行更改; 必要的cron脚本未重新启动或停止。

我们正在逐步解决此问题。 由于发行不当而造成的旅行损失显然与其生产时间成正比。 因此,我们应该尽力而为,并确保最大程度地减少不良发布的生产时间。 开发过程中的任何更改,即使将错误发布操作时间的平均时间减少甚至1秒也对业务有利,因此必须予以实施。

发行不畅以及实际上生产中的任何事故都有两个状态,我们将其称为“被动阶段”和“主动阶段”。 在被动阶段,我们还没有发现事故。 活动阶段意味着我们已经知道。 事故始于被动阶段。 随着时间的流逝,它进入了活跃的阶段-那就是我们找到它并开始解决它的时候:首先我们诊断它,然后-对其进行修复。

为了减少任何中断的持续时间,我们需要减少主动和被动阶段的持续时间。 糟糕的发行版也是如此,因为它被视为一种中断。

我们开始分析故障排除的历史记录。 我们刚开始分析事故时所经历的不良发行平均导致20到25分钟的停机时间(全部或部分停机)。 被动阶段通常需要15分钟,主动阶段通常需要10分钟。 在被动阶段,我们将收到由我们的呼叫中心处理的用户投诉; 在达到特定的阈值后,呼叫中心会在闲聊中抱怨。 有时,我们的一位同事会抱怨无法打车。 同事的抱怨将预示着一个严重的问题。 在不良版本进入活动阶段之后,我们开始了问题诊断,分析了最新版本,各种图表和日志,以找出事故原因。 确定原因后,我们将回退错误版本是否为最新版本,或者使用还原的提交执行新的部署。

这是我们准备改进的不良发行处理流程。

被动阶段:20分钟。
活动阶段:10分钟。

3.被动阶段减少


首先,我们注意到,如果一个错误的发布伴随着500个错误,我们可以说即使没有用户的抱怨也发生了问题。 幸运的是,所有500个错误都记录在New Relic(这是我们使用的监视系统之一)中,我们要做的就是添加有关超过500个特定数量错误的SMS和IVR通知。 随着时间的流逝,阈值将不断降低。

发生事故时的过程如下所示:

  1. 工程师部署发布。
  2. 释放导致事故(大量500s)。
  3. 收到短信。
  4. 工程师和开发人员开始对其进行研究。 有时不是马上,而是在2-3分钟内:短信可能会延迟,手机声音可能会关闭; 当然,接收到此文本后立即做出反应的习惯不可能一overnight而就。
  5. 事故激活阶段开始并持续与之前相同的10分钟。

如此一来,“不良释放:500个内部服务器错误”类型的事故的活动阶段将在释放后3分钟开始。 因此,被动阶段从15分钟减少到3分钟。

结果:

被动阶段:3分钟。
活动阶段:10分钟。

4.进一步减少被动阶段


即使从被动阶段减少到3分钟,它仍然比主动阶段困扰我们更多,因为在主动阶段我们正在尝试解决问题,并且在被动阶段服务已全部或部分关闭,我们绝对毫无头绪

为了进一步减少被动阶段,我们决定在每次发布后牺牲3分钟的工程师时间。 这个想法很简单:我们将部署代码,三分钟后,我们在New Relic,Sentry和Kibana中查找500个错误。 一旦发现问题,我们就假定它与代码相关,并开始进行故障排除。

我们根据统计数据选择了这三分钟的时间段:有时问题会在1-2分钟内出现在图表中,但不会迟于3分钟。

此规则已添加到“执行和不执行”中。 起初并不总是遵循此规则,但是随着时间的流逝,我们的工程师已经习惯了这一规则,就像他们习惯了基本的卫生习惯一样:早上刷牙也需要一些时间,但是仍然有必要。

结果,被动阶段减少到了1分钟(图表有时仍然很晚)。 这也减少了活跃阶段的奖金。 因为现在工程师将面对准备好的问题,并准备立即将其代码回滚。 即使问题并非总是有帮助,因为问题可能是由其他人同时部署的发行版引起的。 也就是说,活跃阶段平均减少到五分钟。

结果:

被动阶段:1分钟。
活动阶段:5分钟。

5.进一步减少活跃阶段


我们对1分钟的被动阶段或多或少感到满意,并开始考虑如何进一步减少主动阶段。 首先,我们将注意力集中在中断的历史上(这恰恰是建立可用性的基石!),并且发现在大多数情况下,我们不立即回滚发行版,因为我们不知道我们应该使用哪个版本:有许多并行发行版。 为了解决这个问题,我们引入了以下规则(并将其写下来做为“做”和“不做”):在发布之前,应该在Slack聊天中通知所有人您将要部署的内容以及原因; 万一发生意外,应该写:“意外,不要部署!” 我们还开始通过SMS通知那些没有阅读聊天记录的人。

这个简单的规则大大降低了持续发生的事故期间的释放数量,减少了故障排除的时间,并将活动阶段从5分钟减少到3分钟。

结果:

被动阶段:1分钟。
活动阶段:3分钟。

6.更大程度地减少活跃阶段


尽管我们在聊天室中发布了有关所有发布和事故的警告,但有时仍会发生比赛情况-有人发布了发布信息,而此时正由另一名工程师进行部署。 或发生事故时,我们在聊天室中对此进行了描述,但有人刚刚部署了她的代码。 这种情况会延长故障排除时间。 为了解决此问题,我们对并行发布实施了自动禁止。 这是一个非常简单的想法:每次发行后的5分钟内,CI / CD系统都禁止对除最新发行版作者以外的任何人进行其他部署(以便她可以回滚或部署必要的修补程序)和一些经验丰富的开发人员(紧急情况下)。 不仅如此,CI / CD系统还可以防止在事故发生时进行部署(也就是说,从有关事故开始的通知到达的那一刻起,直到有关事故结束的通知到达为止)。

因此,我们的过程开始像这样:工程师部署一个发行版,监视图形三分钟,然后在两分钟内没有人可以部署任何东西。 万一发生问题,工程师会回滚发行版。 该规则极大地简化了故障排除,主动和被动阶段的总持续时间从3 +1 = 4分钟减少到1 +1 = 2分钟。

但是即使是两分钟的事故也太多了。 这就是为什么我们继续进行流程优化的原因。

结果:

被动阶段:1分钟。
活动阶段:1分钟。

7.自动事故确定和回滚


我们已经思考了一段时间,以减少因不良发布而导致的事故持续时间。 我们甚至尝试强迫自己查看tail -f error_log | grep 500 tail -f error_log | grep 500 。 但是最后,我们选择了一种激进的自动解决方案。

简而言之,这是自动回滚。 我们有一个单独的Web服务器,并通过均衡器加载了它,比其他Web服务器少了10倍。 CI / CD系统将在每个单独的服务器上自动部署每个发行版(我们称其为preprod,但尽管其名称为真但它会从真实用户那里收到实际负载)。 然后脚本将执行tail -f error_log | grep 500 tail -f error_log | grep 500 。 如果在一分钟内没有500错误,CI / CD会将生产中的新版本部署到其他Web服务器上。 万一有错误,系统会回滚。 在平衡器级别,所有导致preprod错误500的请求将在生产Web服务器之一上重新发送。

此措施将500个错误的发布影响降至零。 就是说,为了防止自动控制中的错误,我们没有取消三分钟的图表监视规则。 这些都是关于不良版本和500个错误的。 让我们进入下一类事故。

结果:

被动阶段:0分钟。
活动阶段:0分钟。



在其他部分,我将讨论Citymobil体验中的其他类型的中断,并详细介绍每种中断类型; 我还将告诉您有关断电的结论,如何修改开发流程以及引入了哪些自动化。 敬请期待!

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


All Articles