为了解决负载分布不均匀导致的高延迟问题,SaaS Web 搜索产品 Algolia 将其基础设施的 DNS 轮询负载均衡模型换掉了。他们引入了NGINX和 OpenResty 作为软件负载均衡器,Redis 使用自定义的 Go 程序来管理后端服务器列表。这个解决方案在 Algolia 的基础设施之上提供了一个新的抽象层。InfoQ 联系了 Algolia 站点可靠性工程师Paul Berthaux,了解更多关于这个做法的信息。
Algolia“应用”有 3 个服务器集群和分布式搜索网络(DSN)服务器,后者提供搜索查询服务。DSN 在功能上类似于内容交付网络接入点(POP),因为它们从离用户最近的地方提供数据。每个应用都有一个 DNS 记录。Algolia 的 DNS 配置使用了多个顶级域名(TLD),并且为了获得弹性使用了两个 DNS 提供商。此外,每个应用的 DNS 记录都被配置为以轮询方式返回 3 个集群服务器的 IP 地址。这是试图将负载分布到集群中的所有服务器上。搜索集群的常见用例是通过前端应用程序或移动应用程序。然而,一些客户也有访问搜索 API 的后端应用程序。后一种情况会造成负载不均,因为所有请求都将到达同一服务器,直到特定服务器的 DNS 生存时间(TTL)到期为止。
Algolia 的一个应用在黑色星期五(Black Friday)搜索量很大时,搜索速度变得很慢。这导致了查询的不均匀分布。团队瞄准了 NGINX 作为客户端应用程序和应用服务器之间的软件负载均衡器。虽然这确实解决了负载分配的一般问题,但是仍然存在使该设置具有通用性和自动化操作的问题。团队选择了OpenResty,它为 NGINX 中的请求-响应生命周期提供Lua脚本支持。使用这个模型,NGINX 可以根据客户“了解到”将请求发送到哪个后端服务器。此信息缓存在 Redis 中。一个名为 lb-helper 的自定义 Go 守护进程从内部 API 获取服务器列表。
在回答是否可以使 Redis 缓存失效的问题时,Berthaux 解释说,他们这样做是“使用了内部公开的用于维护目的的 lib -helper 中的 API 端点”。如果团队必须删除大量的后端服务器,并且不希望 LB 客户端在响应时间上有任何差异,那么就可能需要这样做。
图片来自:https://blog.algolia.com/one-year-load-balancing/,已获授权。
通过此更改,负载均衡器可能成为单点故障。Berthaux 解释了为什么现在还不用担心:
为了获得弹性,我们运行着多个LB——LB的选择是通过轮询DNS。目前,这没有问题,因为与我们的搜索API服务器相比,LB执行非常简单的任务,所以我们不需要在它们之间进行均匀的负载均衡。也就是说,我们有一些非常长期的计划,从轮询DNS转移到基于Anycast路由的东西。
lb-helper 还负责从列表中删除不健康的服务器。按照 Berthaux 的说法:
NGINX/OpenResty中嵌入了对上游故障的检测以及针对不同上游流的重试功能。我使用OpenResty中的log_by_lua指令和一些自定义的Lua代码进行失败计数,从活动Redis条目中删除失败的上游,并在连续10次失败后向lib -helper发出警告。我设置了这个故障阈值,以避免短时自解“事件(incident)”(如准时丢包)中很多不必要的事件(event)。这样,lb-helper将探测失败的上游FQDN,并在它恢复后将其放回Redis中。
通过此更改,Algolia 的搜索负载趋于平稳。他们目前正在进一步改进负载均衡算法。
查看英文原文:Load Balancing Search Traffic at Algolia With NGINX and OpenResty
评论