持续高负载下服务的常见背压策略

持续高负载下服务的常见背压策略

我想知道人们为其网络服务使用哪些常见的背压策略?

假设您的服务在高负载下运行,并且某个时候负载达到容量的 120%。您该如何处理这种情况?

我能想到的最合理的策略是开始拒绝连接。因此,如果一台主机达到其峰值容量(例如所有 Apache 工作进程都忙),我将开始拒绝 TCP 连接,直到其中一个工作进程空闲。这样,所有被接受的连接都会立即处理,而无需排队(因此延迟最小),并且拒绝超过 20% 的连接,从而允许负载平衡器将它们重新调度到另一台主机或执行任何其他负载削减策略(例如重定向到静态/缓存内容)。

我认为这种快速失败方法比任何类型的排队都要好得多。小队列有利于吸收短时间的流量突发,但如果排队过多,您的系统在重负载下可能会出现严重故障。例如,使用没有任何 AQM 的 FIFO 队列处理时,它会进入客户端所有已处理的请求都已超时的状态,因此系统不会向前推进。

令我惊讶的是,这个策略并不像听起来那么容易实现。我的方法是在 Web 服务器上设置一个小的监听积压,期望所有不适合的连接都被拒绝。但由于 Linux 内核 2.2 的变化,这个策略失败了(参见http://veithen.github.io/2014/01/01/how-tcp-backlog-works-in-linux.html)。

较新的 Linux 内核会无条件地接受您的连接。SYN-ACK 响应会发送到客户端,完全不考虑监听积压大小。启用tcp_abort_on_overflow选项也没有多大帮助。当连接不适合接受队列时,此选项会使内核发送 RST,但此时客户端已经认为连接已建立并可能已开始发送数据。

这对于 HAProxy 来说尤其成问题。如果连接成功建立,它不会将请求重新发送到另一台服务器,因为该请求可能对服务器产生了一些副作用。

所以我想我的问题是:

  • 我是不是很奇怪,为什么我要尝试实现这样的事情?
  • 您能推荐其他应对持续高负荷的策略吗?
  • Linux 内核的 tcp_abort_on_overflow 是否损坏了并且应该应用于半开队列?

提前致谢!

答案1

回答你的第一个问题:是的。好吧,无论如何,就我个人而言,不要太在意。问题是,你试图在你的 TCP 堆栈上设置限制,而你在它前面有一个带有许多计数器和选项的负载均衡器。如果你将自己限制在 TCP 堆栈中,那么当你达到这些限制时,你会遇到更多的问题。我会检查并保留负载均衡器本身的限制。设置会话计数器,或制作一些可以验证服务器健康状况的健康脚本。达到限制后,你可以拒绝新的传入请求,或者在将后端设置为满时将它们重定向到另一台服务器。你受 Apache 的限制约束,而不是操作系统或 haproxy,因此请尝试通过在达到系统限制之前控制 apache 的负载来远离系统限制。

我想这也已经回答了你的第二个问题。

第三个问题的答案更为复杂,我认为您不会想深入了解。在我看来,达到 TCP 溢出状态对于调整服务器以维持高负载和流量来说已经是过分了。

这是我的观点,希望有所帮助。

相关内容