Badoo 如何实现每秒渲染 200 万张照片的能力

Badoo 如何实现每秒渲染 200 万张照片的能力

如果没有媒体内容,现代网络几乎是不可想象的:几乎每个祖母都有智能手机,每个人都在社交网络上,服务停机对公司来说代价高昂。 为了您的注意,公司故事的文字记录 Badoo上 关于她是如何使用硬件方案来组织照片投递的,过程中遇到了哪些性能问题,是什么原因导致的,以及这些问题是如何使用基于Nginx的软件方案来解决的,同时保证各个层面的容错性(视频). 我们感谢故事奥列格的作者 桑尼斯 Efimova 和 Alexandra Dymova,他们在会议上分享了他们的经验 正常运行第 4 天.

让我们先简单介绍一下我们如何存储和缓存照片。 我们有一个存储它们的层,还有一个我们缓存照片的层。 同时,如果我们想实现一个大技巧并减少存储负载,对我们来说重要的是将单个用户的每张照片放在一个缓存服务器上。 否则,我们必须安装与服务器数量一样多的磁盘。 我们的命中率在 99% 左右,也就是说,我们将存储负载减少了 100 倍,为了做到这一点,10 年前,当所有这些都在构建时,我们有 50 台服务器。 因此,为了提供这些照片,我们实际上需要这些服务器服务的 50 个外部域。

自然而然地,问题立即出现了:如果我们的一台服务器出现故障并变得不可用,我们会损失哪一部分流量? 我们看了看市场上的东西,决定买一块铁来解决我们所有的问题。 选择落在了 F5 网络公司(顺便说一句,不久前收购了 NGINX, Inc)的解决方案上:BIG-IP Local Traffic Manager。

Badoo 如何实现每秒渲染 200 万张照片的能力

this piece of iron (LTM) 的作用:它是一个铁路由器,可以为其外部端口提供铁冗余,并允许您根据网络拓扑和某些设置路由流量,并进行健康检查。 这块铁可以编程,这对我们来说很重要。 因此,我们可以描述特定用户的照片如何从特定缓存返回的逻辑。 它是什么样子的? 有一个硬件,看互联网一个域,一个ip,做ssl offload,解析http请求,从IRule中选择一个缓存号,到哪里去,让流量到哪里去。 同时,它会进行健康检查,在机器不可用的情况下,我们做到这一点,以便当时流量转到一个备份服务器。 从配置的角度来看,当然有一些细微差别,但总的来说一切都很简单:我们规定了一个映射,某个数字对应于我们在网络上的 IP,我们说我们将在端口 80 上监听和443,我们说如果服务器不可用,那么你需要让流量去备份,在这种情况下,35号,我们描述了一堆逻辑应该如何拆解这个架构。 唯一的问题是,铁片的编程语言是 Tcl 语言。 如果有人完全记得这一点......这种语言比编程方便的语言更只写:

Badoo 如何实现每秒渲染 200 万张照片的能力

我们得到了什么? 我们得到了一个硬件来确保我们的基础设施的高可用性,路由我们所有的流量,提供健康检查并且正常工作。 而且,它已经工作了相当长的时间:在过去的10年里,没有人抱怨过它。 到 2018 年初,我们已经每秒渲染大约 80 万张照片。 这是来自我们两个数据中心的大约 80 吉比特的流量。

但是......

2018 年初,我们在图表上看到了一幅丑陋的画面:返回照片的时间明显增加了。 它不再适合我们。 问题是这种行为只在交通高峰期可见——对我们公司来说,这是周日到周一的晚上。 但其余时间系统表现如常,没有损坏的迹象。

Badoo 如何实现每秒渲染 200 万张照片的能力

然而,这个问题必须得到解决。 我们确定了可能的瓶颈并开始消除它们。 首先当然是我们扩展了外部上行链路,对内部上行链路进行了全面改造,把可能存在的瓶颈都找了出来。 但是这一切并没有给出明显的结果,问题并没有消失。

另一个可能的瓶颈是照片缓存本身的性能。 我们决定也许问题出在他们身上。 好吧,我们已经扩展了性能——基本上是照片缓存上的网络端口。 但同样,没有看到明显的改善。 最后,我们密切关注了 LTM 本身的性能,在这里我们在图表上看到了一个悲伤的画面:所有 CPU 的加载开始顺利,但随后急剧停滞。 与此同时,LTM 停止对健康检查和上行链路做出充分响应,并开始随机关闭它们,这会导致严重的性能下降。

也就是我们找到了问题的根源,找到了瓶颈。 我们将做什么仍有待决定。

Badoo 如何实现每秒渲染 200 万张照片的能力

我们可以做的第一件显而易见的事情就是以某种方式使 LTM 本身现代化。 但这里有一些细微差别,因为这款熨斗非常独特,您不会去最近的超市购买。 这是一份单独的合同,一份单独的许可合同,而且会花费很多时间。 第二种选择是开始自己思考,在自己的组件上提出自己的解决方案,最好使用开源程序。 剩下的只是决定我们将为此选择什么以及我们将花费多少时间来解决这个问题,因为用户没有收到照片。 因此,有必要非常、非常快地完成所有这些工作,有人可能会说——就在昨天。

由于任务听起来像是“尽快做某事并使用我们拥有的硬件”,我们想到的第一件事就是从前面移除一些不是最强大的机器,把 Nginx 放在那里,我们知道如何工作,并尝试实现所有与铁片过去相同的逻辑。 也就是说,事实上,我们离开了我们的硬件,安装了另外 4 台我们必须配置的服务器,通过类比 10 年前的方式为它们创建了外部域......如果这些机器出现故障,我们会失去一点可用性,但是,尽管如此,在本地解决了我们用户的问题。

因此,逻辑保持不变:我们安装 Nginx,它可以进行 SSL 卸载,我们可以以某种方式对路由逻辑进行编程,对配置进行健康检查,并简单地复制我们之前的逻辑。

我们坐下来写配置。 起初似乎一切都很简单,但不幸的是,很难找到每个任务的手册。 因此,我们不建议您简单地谷歌“如何为照片配置 Nginx”:最好参考官方文档,其中会显示应该触摸哪些设置。 但最好自己选择一个特定的参数。 好吧,那么一切都很简单:我们描述了我们拥有的服务器,我们描述了证书......但事实上,最有趣的是路由逻辑本身。

起初,在我们看来,我们只是简单地描述我们的位置,匹配其中的照片缓存编号,用我们的手或生成器描述我们需要多少个上游,在每个上游中我们指示流量应该去往的服务器,以及备份服务器 - 如果主服务器不可用:

Badoo 如何实现每秒渲染 200 万张照片的能力

但是,如果一切都这么简单,我们可能会回家,什么也不说。 不幸的是,使用 Nginx 的默认设置,一般来说,这些设置是经过多年的开发而做出的,并不完全适合这种情况......配置看起来像这样:如果某些上游服务器有请求错误或超时,Nginx 总是将流量切换到下一个。 同时,在第一次失败后,服务器也将在 10 秒内关闭,无论是错误还是超时 - 这甚至无法以任何方式配置。 也就是说,如果我们删除或重置 upstream 指令中的超时选项,那么,虽然 Nginx 不会处理此请求并响应一些不太好的错误,但服务器将关闭。

Badoo 如何实现每秒渲染 200 万张照片的能力

为了避免这种情况,我们做了两件事:

a) 他们禁止 Nginx 手动执行此操作 - 不幸的是,唯一的方法就是简单地设置最大失败设置。

b) 我们记得在其他项目中我们使用了一个允许您进行后台健康检查的模块 - 因此,我们进行了相当频繁的健康检查,以便在发生事故时将停机时间降至最低。

不幸的是,这还不是全部,因为从字面上看,这个方案运行的前两周表明 TCP 健康检查也是一个不可靠的东西:不是 Nginx,或者 D 状态的 Nginx 可以在上游服务器上启动,并且在这种情况下内核将接受连接,健康检查将通过,但它不会工作。 因此,我们立即将其替换为 http 的 health-check,做了一个特定的,如果它已经给出 200,那么在这个脚本中一切正常。 您可以执行其他逻辑 - 例如,在缓存服务器的情况下,检查文件系统是否已正确安装:

Badoo 如何实现每秒渲染 200 万张照片的能力

这对我们来说很合适,只是此刻电路完全重复了铁片所做的事情。 但我们想做得更好。 以前,我们有一台备份服务器,这可能不太好,因为如果你有一百台服务器,那么当几台同时倒下时,一台备份服务器不太可能应付负载。 因此,我们决定在所有服务器之间分配预留:我们简单地创建了另一个单独的上游,根据它们可以服务的负载使用特定参数记录所有服务器,添加与我们之前相同的健康检查:

Badoo 如何实现每秒渲染 200 万张照片的能力

由于您不能在一个上游中转到另一个上游,因此有必要确保如果主要上游(我们在其中简单地编写了正确的、必要的照片缓存)不可用,我们只需通过 error_page 进行回退,从那里我们去了备份上游:

Badoo 如何实现每秒渲染 200 万张照片的能力

从字面上看,增加了四台服务器,我们得到了:我们替换了部分负载——从 LTM 转移到这些服务器,使用标准硬件和软件在那里实现了相同的逻辑,立即获得了这些服务器可以扩展的好处,因为它们可以只需根据需要投入即可。 好吧,唯一的缺点是我们失去了对外部用户的高可用性。 但当时我不得不牺牲这个,因为必须立即解决问题。 所以,我们移除了部分负载,当时大约是 40%,LTM 变得更好了,实际上在问题开始两周后,我们开始提供每秒 45 个请求,而不是 55 个请求。 事实上,我们增长了 20%——这显然是我们没有给用户的流量。 而在这之后,他们又开始思考如何解决剩下的问题——保证外部高可用性。

Badoo 如何实现每秒渲染 200 万张照片的能力

我们有一些停顿,在此期间我们讨论了我们将为此使用什么解决方案。 有人提议使用 DNS 确保可靠性,借助一些自写脚本、动态路由协议……有很多选择,但很明显,为了真正可靠地返回照片,您需要引入另一层这将监控这一点。 我们称这些机器为照片导演。 我们依赖的软件是Keepalived:

Badoo 如何实现每秒渲染 200 万张照片的能力

首先,Keepalived 由什么组成。 第一个是 VRRP 协议,网络人员广为人知,它位于网络设备上,为客户端连接的外部 IP 地址提供容错功能。 第二部分是 IPVS,IP 虚拟服务器,在照片路由器之间进行平衡,并在该级别提供容错能力。 第三是健康检查。

让我们从第一部分开始:VRRP - 它是什么样子的? 有一个特定的虚拟 IP,它在 dns badoocdn.com 中有一个条目,客户端连接到那里。 在某个时间点,我们在一台服务器上有一个 IP 地址。 Keepalived 数据包在使用 VRRP 协议的服务器之间运行,如果主服务器从雷达上消失——服务器重启或其他原因,那么备份服务器会自动提升这个 IP 地址——不需要手动操作。 Master和Backup的区别,主要是优先级:越高的机器越有可能成为Master。 一个非常大的优势是你不需要在服务器本身配置IP地址,在配置中描述它们就足够了,如果IP地址需要一些自定义路由规则,这直接在配置中描述,用与 VRRP 包中描述的语法相同。 您不会遇到任何不熟悉的事物。

Badoo 如何实现每秒渲染 200 万张照片的能力

它在实践中是什么样子的? 如果其中一台服务器出现故障会怎样? 一旦 master 消失,我们的备份就停止接收提升并自动成为 master。 一段时间后,我们修复了 master,重新启动,启动了 Keepalived - 比备份更高优先级的广告到达,备份自动返回,从自身删除 IP 地址,无需手动操作。

Badoo 如何实现每秒渲染 200 万张照片的能力

这样,我们就保证了外部IP地址的容错性。 下一部分是以某种方式平衡从外部 IP 地址到已经终止它的照片路由器的流量。 有了平衡协议,一切就足够清楚了。 这要么是简单的循环,要么是稍微复杂一点的东西,wrr,list connection等等。 这个基本上在文档中都有描述,没有什么特别之处。 但是交付方式......在这里我们将详细介绍 - 为什么我们选择其中之一。 它们是 NAT、直接路由和 TUN。 事实上,我们立即准备好从网站返回 100 GB 的流量。 这是算出来的话,需要10个千兆卡吧? 一台服务器中有 10 个千兆卡 - 这至少已经超出了我们“标准设备”的概念。 然后我们想起我们不只是提供一些流量,我们还提供照片。

有什么特点? - 传入和传出流量之间的巨大差异。 传入流量很小,传出流量很大:

Badoo 如何实现每秒渲染 200 万张照片的能力

如果您查看这些图表,您会发现目前正在向主管发送大约每秒 200 Mb 的数据,这是最典型的一天。 我们每秒回馈 4,500 MB,比率约为 1/22。 已经很清楚,我们要完全向 22 个工作服务器提供传出流量,一个接受此连接就足够了。 这里直接路由算法,即路由算法,就派上用场了。

它是什么样子的? 根据他的表格,我们的照片导演将连接转移到照片路由器。 但是照片路由器将反向流量直接发送到 Internet,将其发送到客户端,它不会通过照片导向器返回,因此,我们使用最少数量的机器,提供所有流量的完全容错和泵送。 在配置中,它看起来像这样:我们指定算法,在我们的例子中它是一个简单的 rr,我们提供直接路由方法,然后我们开始列出所有真实服务器,我们有多少。 这将决定这个流量。 如果我们有一个或两个以上的服务器出现在那里,就会出现这种需要 - 我们只需将这部分添加到配置中,不要太担心。 从真正的服务器端,从照片路由器端,这种方法需要最少的配置,在文档中有完美的描述,没有任何陷阱。

特别令人高兴的是,这样的解决方案并不意味着要彻底改变本地网络,这对我们来说很重要,我们必须以最小的成本解决它。 如果你看 IPVS 管理命令输出然后我们将看到它的样子。 这里我们有一个特定的虚拟服务器,在端口 443 上侦听,接受连接,列出所有工作的服务器,很明显连接是正负相同的。 如果我们查看同一虚拟服务器上的统计信息,我们有传入数据包、传入连接,但绝对没有传出数据包。 传出连接直接转到客户端。 好吧,我们设法失去了平衡。 现在,如果我们的一个照片路由器发生故障会怎样? 毕竟铁就是铁。 它可能会进入内核恐慌,它可能会崩溃,电源可能会烧坏。 任何事物。 这就是健康检查的目的。 它们可以像检查端口的打开方式一样简单,也可以更复杂一些,甚至可以是一些甚至会检查业务逻辑的自写脚本。

我们在中间的某个地方停了下来:我们有一个针对特定位置的 https 请求,如果它以第 200 个响应进行响应,则会调用一个脚本,我们相信该服务器一切正常,它处于活动状态并且可以很容易地打开.

这在实践中又是如何看待的。 关闭服务器,允许进行维护 - 例如刷新 BIOS。 在日志中,我们立即有一个超时,我们看到第一行,然后在三次尝试后它被标记为“失败”,并且它被简单地从列表中删除。

Badoo 如何实现每秒渲染 200 万张照片的能力

第二种行为也是可能的,当 VS 简单地设置为零时,但在返回照片的情况下,这效果不佳。 服务器启动,Nginx 在那里启动,立即健康检查了解连接正在通过,一切正常,服务器出现在我们的列表中,负载立即开始自动应用到它。 值班管理员不需要手动操作。 晚上,服务器重新启动 - 监控部门不会在晚上打电话给我们。 他们让你知道发生了什么,一切都很好。

于是,我们用一种相当简单的方式,借助少量的服务器,解决了外部容错的问题。

当然,所有这些都需要监控。 另外,应该注意的是,Keepalivede 作为一个很久以前编写的软件,有很多方法来监控它,都使用通过 DBus、SMTP、SNMP 和标准 Zabbix 进行检查。 另外,他自己知道如何给几乎每个喷嚏写信,老实说,在某些时候我们甚至想关闭它,因为他为任何流量切换、包含、每个 IP-shnik 和等等。 当然,如果有很多服务器,那么你可以用这些字母淹没自己。 使用标准方法,我们在照片路由器上监控 nginx,硬件监控并没有消失。 当然,我们还会建议另外两件事:首先,外部健康检查和可访问性,因为即使一切正常,事实上,由于外部供应商的问题或更复杂的原因,用户也有可能收不到照片。 在另一个网络、亚马逊或其他地方的某个地方保留一台可以从外部 ping 你的服务器的单独机器总是值得的,而且对于那些擅长棘手的机器学习的人来说,使用异常检测也值得,或者简单监控,至少是为了跟踪请求是否急剧下降,反之亦然。 这也很有用。

总结一下:事实上,我们用一个相当简单的系统取代了在某些时候不再适合我们的铁解决方案,该系统的所有功能都相同,也就是说,它提供了 HTTPS 流量的终止和进一步的智能路由,具有必要的健康状况-检查。 我们增加了这个系统的稳定性,也就是说,我们仍然为每一层提供高可用性,而且我们得到的好处是在每一层上都可以很容易地扩展它,因为这是带有标准软件的标准硬件,也就是说,通过这样做,我们简化了自己对可能问题的诊断。

我们最终得到了什么? 我们在 2018 年 40 月假期遇到了问题。 前六个月,我们在实施这个方案的时候,把它扩展到所有的流量,为了把所有的流量都从LTM中去掉,我们只在一个数据中心的流量上从60G增长到2018G,同时整个 XNUMX 年的时间每秒能够提供近三倍的照片。

Badoo 如何实现每秒渲染 200 万张照片的能力

来源: habr.com

添加评论