没有媒体内容,现代网络几乎是不可想象的:我们几乎每个祖母都拥有智能手机,每个人都坐在社交网络上,服务中断对于公司而言代价高昂。 请注意, Badoo讲述了它如何使用硬件解决方案组织照片的交付,过程中遇到的性能问题,导致问题的原因以及如何使用基于Nginx的软件解决方案解决这些问题的故事的笔录,同时确保各个级别的容错能力( 视频 )。 我们感谢故事Oleg Sannis Efimov和Alexander Dymov的作者,他们在Uptime Day 4会议上分享了他们的经验。-让我们从简短的介绍开始,介绍如何存储和缓存照片。 我们有一层存储它们的层,还有一层存储照片的层。 同时,如果我们想获得巨大成功并减少数百人的负担,则对我们而言重要的是,单个用户的每张照片都位于一台缓存服务器上。 否则,我们将不得不放置多少磁盘,多少磁盘。 我们的命中率大约为99%,也就是说,我们将存储负载减少了100倍,为此,在10年前,当所有这些构建完毕时,我们有50台服务器。 因此,为了提供这些照片,我们基本上需要这些服务器提供服务的50个外部域。
自然地,问题立即出现:如果一台服务器崩溃,它将不可用,我们损失了那部分流量? 我们查看了市场上的东西,并决定购买一块铁,以解决所有问题。 选择取决于F5网络公司(该公司最近刚收购了NGINX,Inc)的决定:BIG-IP本地流量管理器。

这件硬件(LTM)的作用:它是一个铁路由器,可以对其外部端口进行铁冗余,并允许您根据网络拓扑,某些设置来路由流量并进行运行状况检查。 对我们来说重要的是,可以对这块铁进行编程。 因此,我们可以描述如何从特定缓存中获得特定用户的照片的逻辑。 看起来像什么? 有一块铁可以在一个域,一个ip上查看Internet,可以进行ssl卸载,解析http请求,从IRule中选择要去往的缓存号,并在那发送流量。 同时,它会进行运行状况检查,并且如果某台计算机不可用,我们会在此时进行检查,以使流量流向一台备用服务器。 从配置的角度来看,当然会有一些细微差别,但总的来说,一切都很简单:我们开一张卡,将一些号码与网络上的IP匹配,我们说我们将在第80和443端口监听,我们说,如果服务器不可用,则需要在备份上启动流量(在本例中为第35个),并且我们描述了如何分解此体系结构的大量逻辑。 唯一的问题是对硬件进行编程的语言是Tcl。 如果有人甚至还记得这一点……这种语言比只适合编程的语言更只写:

我们得到了什么? 我们有一块硬件,可以提供高可用性的基础架构,路由所有流量,提供医疗保健并且可以正常工作。 此外,它已经运行了相当长的一段时间:在过去的10年中,没有关于它的投诉。 到2018年初,我们已经每秒发出约8万张照片。 我们两个数据中心的流量约为80吉比特。
但是...
在2018年初,我们在图表上看到了一张丑陋的图片:照片的响应时间明显增加了。 而且它不再适合我们。 问题在于,这种行为仅在流量高峰时才可见-对于我们公司而言,这是星期日至星期一的夜晚。 但是在其余时间中,系统仍照常运行,没有损坏的迹象。

但是,这个问题必须解决。 我们确定了可能的瓶颈,并开始消除它们。 当然,首先,我们扩展了外部上行链路,对内部上行链路进行了全面审核,发现了所有可能的瓶颈。 但是所有这些都没有给出明显的结果,问题并没有消失。
另一个可能的瓶颈是照片缓存本身的性能。 我们认为问题可能出在他们身上。 好吧,我们扩展了性能-主要是照片缓存中的网络端口。 但同样,没有看到明显的改善。 最后,我们密切关注了LTM本身的性能,在这里我们在图表上看到了一个悲惨的画面:所有CPU的负载开始平稳运行,但随后突然搁在架子上。 同时,LTM停止对运行状况检查和上行链路做出充分响应,并开始随机关闭它们,这会导致严重的性能下降。
也就是说,我们确定了问题的根源,确定了瓶颈。 有待决定我们将做什么。

建议我们采取的第一件事是以某种方式升级LTM本身。 但是有些细微差别,因为这种熨斗非常独特,您不会去最近的超市,也不会购买。 这是一个单独的合同,一个单独的许可合同,将花费大量时间。 第二种选择是开始思考,在组件上提出自己的解决方案,最好使用开放访问程序。 由于用户尚未收到照片,因此剩下的唯一决定就是我们将为此选择确切的内容以及将花费多少时间来解决此问题。 因此,所有这些都必须非常非常快地完成,一个人可能会说-昨天。
由于任务听起来像“尽快完成任务并使用我们拥有的硬件”,所以我们想到的第一件事就是简单地从前端移除一些不是最强大的计算机,然后将Nginx与我们一起使用。我们知道如何工作,并尝试实现铁块过去经常执行的所有逻辑。 也就是说,实际上,我们离开了硬件,设置了另外4台应该配置的服务器,为它们创建了外部域,这与10年前的情况类似。如果这些计算机崩溃,我们将失去可用性,但是,较少解决了我们本地用户的问题。
因此,逻辑保持不变:我们将Nginx放到了它,可以进行SSL卸载,可以以某种方式对路由逻辑进行编程,对配置进行运行状况检查,并仅复制以前的逻辑。
我们坐下来编写配置文件。 最初,一切似乎都很简单,但不幸的是,很难找到每个任务的手册。 因此,我们不建议您仅使用Google“如何为照片配置Nginx”:最好参考官方文档,该文档将显示值得修改的设置。 但是最好自己选择一个特定的参数。 好了,那么一切都很简单:我们描述了我们拥有的服务器,我们描述了证书……但实际上,最有趣的是路由本身的逻辑。
最初,在我们看来,我们只是简单地描述了我们的位置,匹配其中的照片缓存的数量,用手或生成器描述了我们需要多少个上游设备,在每个上游设备中,我们指示流量应该到达的服务器,以及在主服务器情况下的备用服务器不可用:

但是,也许,如果一切都变得如此简单,我们就回家,什么也不说。 不幸的是,使用Nginx的默认设置(通常是经过多年的开发),并且在这种情况下并不完全适用...配置看起来像这样:如果某些上游服务器出现请求错误或超时,则Nginx总是将流量切换到下一个。 同时,在第一个文件之后,服务器也会由于错误和超时而关闭10秒钟-甚至无法配置。 也就是说,如果我们删除或重置上游指令中的timeout选项,则尽管Nginx不会处理此请求并会以一些不太好的错误响应,但服务器将关闭。

为了避免这种情况,我们做了两件事:
a)他们禁止Nginx手动执行此操作-不幸的是,执行此操作的唯一方法是简单地设置最大失败设置。
b)记得在其他项目中,我们使用了一个允许您进行背景健康检查的模块-相应地,我们进行了相当频繁的健康检查,因此在发生事故的情况下可以进行最少的检查。
不幸的是,这还不是全部,因为从字面上看,该方案的前两周表明TCP运行状况检查也是不可靠的事情:在这种情况下,不能在上游服务器上引发Nginx或处于D状态的Nginx内核将接受连接,运行状况检查将通过,但将不起作用。 因此,我们立即用运行状况检查http'shny替换了它,并进行了专门的设置,如果返回200,则该脚本中的所有内容都可以正常运行。 您可以执行其他逻辑-例如,在缓存服务器的情况下,请验证文件系统是否正确安装:

它会适合我们,但此刻电路完全重复了一块铁。 但是我们想做得更好。 以前,我们只有一台备份服务器,这可能不是很好,因为如果您有一百台服务器,那么当一次崩溃时,一台备份服务器不太可能应付负载。 因此,我们决定在所有服务器之间分配预留空间:我们只是在上游创建了另一个单独的服务器,根据它们可以处理的负载在其中记录了具有某些参数的所有服务器,并添加了之前的运行状况检查:

由于不可能转到上游中的另一个上游,因此有必要确保在主上游不可用的情况下(简单地写入正确的照片缓存),我们只是通过error_page进行了后备,从那里我们备份了4月:

从字面上添加了四个服务器,我们得到了:我们替换了部分负载-从LTM中删除了这些服务器,在那里使用标准的硬件和软件实施了相同的逻辑,并且立即获得了可以扩展这些服务器的好处,因为它们可以简单地进行扩展根据需要放置。 好吧,唯一的不利因素是我们已经失去了外部用户的高可用性。 但是那一刻我不得不牺牲这一点,因为我不得不立即解决问题。 因此,我们删除了一部分负载,当时约为40%,LTM感觉很好,从字面上讲,问题开始两周后,我们开始每秒发送的请求不是45k,而是55k。 实际上,我们增长了20%-显然这是我们没有给用户的流量。 之后,他们开始思考如何解决剩余的问题-提供较高的外部可访问性。

我们暂停了一下,在此期间我们讨论了将为此使用的解决方案。 有建议使用DNS,使用一些自写脚本,动态路由协议来确保可靠性...有很多选择,但是很明显,对于真正可靠的照片输出,您需要引入另一层对此进行监视。 我们称这些机器为照片导演。 作为我们所依赖的软件,我选择了Keepalived:

首先-Keepalived的组成。 第一个是VRRP协议,对于网络人员来说是众所周知的,它位于网络设备上,它为客户端连接到的外部IP地址提供容错功能。 第二部分是IPVS,即IP虚拟服务器,用于在照片路由器之间保持平衡并确保此级别的容错能力。 第三是健康检查。
让我们从第一部分开始:VRRP-它看起来像什么? 在客户端连接的dns badoocdn.com中有一个特定的虚拟IP。 在某个时间点,我们在一台服务器上有一个IP地址。 Keepalived数据包使用VRRP协议在服务器之间运行,并且如果向导从雷达中消失了-服务器重新启动或发生其他情况,备份服务器会自动从其自身提升IP地址-无需手动操作。 主服务器和备份服务器之间存在差异,主要是优先级:优先级越高,计算机将成为主服务器的可能性就越大。 一个非常大的优点是,无需在服务器本身上配置IP地址,只需在config中描述它们就足够了;如果同时IP地址需要一些自定义路由规则,则可以直接在config中进行描述,语法与上述相同在VRRP软件包中。 您不会遇到任何不熟悉的事情。

在实践中看起来像什么? 如果其中一台服务器出现故障怎么办? 一旦母版消失,我们的备份就停止接收广告,并自动成为母版。 一段时间后,我们修复了主服务器,重新启动,解除了Keepalived-出现的优先级比备份高,并且备份自动返回,删除IP地址,无需手动操作。

因此,我们确保了外部IP地址的容错能力。 下一部分将以某种方式平衡流量到已经通过外部IP地址终止它的照片路由器。 使用平衡协议,一切都非常清楚。 这要么是简单的循环,要么是稍微复杂一些的东西,例如wrr,列表连接等等。 原则上在文档中对此进行了描述,没有什么特别的。 但是交付方式……这里我们将详细介绍-为什么他们选择其中一种。 这些是NAT,直接路由和TUN。 事实是,我们立即放弃了来自站点的100吉比特流量的回报。 如果这样估计,您需要10个千兆卡,对吗? 一台服务器中包含10 GB的卡-至少已经超出了我们“标准设备”概念的范围。 然后我们想起了我们不仅仅是在浪费交通,而是在拍照。
有什么功能? -入站流量和出站流量之间的巨大差异。 传入流量很小,传出流量很大:

如果查看这些图,您会发现当前大约每秒200 MB的速度到达导演,这是最普通的一天。 我们每秒回馈4,500 MB,比率约为1/22。 已经很清楚,对于我们来说,要完全确保到22个工作服务器的传出流量,一个接受此连接的服务器就足够了。 在这里,直接路由算法,即路由算法,对我们有帮助。
看起来像什么? 根据我们的表格,照片导演将连接转移到照片路由器。 但是照片路由器会将返回的流量直接发送到Internet,再将其发送到客户端,它不会通过照片导演返回,因此,在使用最少数量的计算机的情况下,我们提供了完全的容错能力,并可以抽出所有流量。 在配置中,它看起来像这样:我们指定了算法,在我们的情况下,它是一个简单的rr,我们提供了一种直接路由方法,然后我们开始列出所有真实服务器,包括多少个。 哪个将决定此流量。 万一我们那里又有一台或两台服务器,就会产生这种需求-我们只需在配置中添加此部分,我们就不用担心。 在真实服务器方面,在照片路由器方面,此方法仅需极少的配置,在文档中已对此进行了完美描述,并且没有任何陷阱。
尤其好-这种解决方案并不意味着对本地网络进行彻底的更改,这对我们很重要,我们必须用最少的费用解决它。 如果您查看
IPVS admin命令的
输出 ,我们将看到它的外观。 在这里,我们有一个虚拟服务器,在端口443上,它侦听,接受连接,列出了所有正常工作的服务器,很显然,连接是相同的(加或减)。 如果我们查看同一虚拟服务器上的统计信息,则我们有传入数据包,传入连接,但绝对没有传出数据包。 传出连接直接进入客户端。 好吧,我们能够不平衡。 现在,如果其中一个光电路由器发生故障怎么办? 毕竟,铁就是铁。 可能会导致内核崩溃,破裂或损坏电源。 没事 为此,需要进行健康检查。 它们可以是最简单的-检查端口如何与我们一起打开-或更复杂的命令,甚至可以是一些甚至可以检查业务逻辑的自写脚本。
我们在中间的某个地方停了下来:我们有一个https要求提供一个特定的位置,如果脚本响应第200个答案,就会调用一个脚本,我们相信此服务器一切正常,该服务器是活动的,并且您可以从容地打开它。
再次,它看起来如何在实践中。 关闭服务器,例如要进行服务-例如BIOS刷新。 在日志中,我们立即有一个超时,我们看到第一行,然后在尝试了三行之后将其标记为“翻转”,并从列表中将其删除。

当仅将VS设置为零时,还有第二种可能的行为,但是如果返回照片,则效果不佳。 服务器上升,Nginx从此处启动,运行状况检查就可以知道连接已通过,一切都很好,并且该服务器出现在我们的列表中,并且负载自动开始立即应用于它。 同时,值班管理员无需手动操作。 晚上,服务器重新启动-监控部门在晚上不给我们打电话。 他们告知,当时一切正常。
, , .
, , , . , Keepalivede, , , DBus, SMTP, SNMP, Zabbix'. , , , - , , , IP- . , , . nginx -, . , , : -, health-check' , , , , - - . - , amazon -, , , anomaly detection, , machine learning, , , , , , . .
: , , , - , , , HTTPS health-check'. , , , , , .
? 2018-. , , LTM, - 40 60 , 2018- .
