有两种方法可以让HAProxy在多个CPU核心上运行:
传统的多进程方法目前实现了更好的性能,但新的多线程模型解决了通常与多进程配置相关的所有限制,对于喜欢易于管理而不是最大性能的早期采用者来说肯定会很有趣。
方法的选择在某种程度上还取决于特定的用户需求和配置。我们知道SSL卸载和HTTP压缩在多线程模型中很好地扩展,至少在相对少量的线程(2到4)上。对于其他用途或更多线程,我们仍在收集明确的基准和经验。
在这篇博文中,我们将带你了解HAProxy 1.8中的多线程功能。我们将为你提供背景信息,配置说明,更详细的技术概述以及一些调试技巧。
让我们开始吧!
从多进程到多线程
从2002年发布的HAProxy 1.1.7版开始,可以自动启动多个HAProxy进程。这是使用配置指令nbproc 完成的,后来各个进程也使用 cpu-map映射到各个CPU核心。
这些多进程配置是扩展用户工作负载的标准方法,并且通过正确的设置,每个单独的进程都能够充分利用高性能,事件驱动的HAProxy引擎。
此外,多进程配置还有其他专用用途 - 例如,它们是大规模SSL卸载解决方案的首选配置。SSL卸载的一般方法是:
但是,多进程配置具有某些限制:
因此,虽然多进程配置在许多情况下都很有用,但性能优势与管理复杂性的增加相结合。
在多线程模型中,HAProxy在单个进程中启动多个线程,而不是启动多个单独的进程,因此,它避免了所有上述问题。
从HAProxy 1.8开始,已实现多线程支持并包含在HAProxy中。
我们的第一个多线程版本的目标是通过创新和可扩展的设计生成稳定,线程安全的实现。最初的工作花了我们8个月才完成,我们相信我们已经完成了任务,但多线程支持将继续标记为实验,直到我们改进其整体性能并确认最大安装的稳定性。
多线程支持
在激活多线程之前,必须使用多线程支持编译HAProxy。默认情况下,这在Linux 2.6.28及更高版本,FreeBSD,OpenBSD和Solaris上完成。对于其他目标平台,必须使用标志“USE_THREAD = 1”显式启用它。与启用它类似,在默认启用多线程的上述平台上,可以使用“USE_THREAD =”禁用它。
要检查HAProxy中的多线程支持,请运行“haproxy -vv”。如果启用了多线程,你将在输出中看到“使用多线程支持构建”文本:
[root@Node-www.linuxea.com ~]# haproxy -vv
HA-Proxy version 1.9.0 2018/12/19 - https://haproxy.org/
Build options :
TARGET = linux2628
CPU = generic
CC = gcc
CFLAGS = -m64 -march=x86-64 -O2 -g -fno-strict-aliasing -Wdeclaration-after-statement -fwrapv -Wno-unused-label -Wno-sign-compare -Wno-unused-parameter -Wno-old-style-declaration -Wno-ignored-qualifiers -Wno-clobbered -Wno-missing-field-initializers -Wtype-limits
OPTIONS =
Default settings :
maxconn = 2000, bufsize = 16384, maxrewrite = 1024, maxpollevents = 200
Built with transparent proxy support using: IP_TRANSPARENT IPV6_TRANSPARENT IP_FREEBIND
Built without compression support (neither USE_ZLIB nor USE_SLZ are set).
Compression algorithms supported : identity("identity")
Built without PCRE or PCRE2 support (using libc's regex instead)
Encrypted password support via crypt(3): yes
Built with multi-threading support.
Available polling systems :
epoll : pref=300, test result OK
poll : pref=200, test result OK
select : pref=150, test result OK
Total: 3 (3 usable), will use epoll.
Available multiplexer protocols :
(protocols marked as <default> cannot be specified using 'proto' keyword)
h2 : mode=HTX side=FE|BE
h2 : mode=HTTP side=FE
<default> : mode=HTX side=FE|BE
<default> : mode=TCP|HTTP side=FE|BE
Available filters :
[SPOE] spoe
[COMP] compression
[CACHE] cache
[TRACE] trace
多线程配置
默认情况下,HAProxy将启动一个进程和一个线程。要启动更多线程,应在全局配置部分中设置选项“ nbthread ”。
请注意,选项“ nbthread ”与“ nbproc ” 兼容,这意味着甚至可以启动多个HAProxy进程,每个进程中有多个线程。
然后,还应使用配置指令“ cpu-map ” 将进程和线程映射到CPU核心。
运行单个HAProxy进程(1)以及映射到前四个CPU核心(0-3)的4个线程(1-4)所需的完整配置如下所示:
nbproc 1 #设置启动进程数,默认是1
nbthread 4 #4个线程
cpu-map auto:1/1-4 0-3 # 绑定cpu
这基本上就是一个简单,功能齐全的用例!
请参阅HAProxy的配置指南,章节#3.1 nbproc,#3.1 nbthread和3.1 CPU的地图为所有可用选项的完整描述。
顺便看看CPU-MAP的例子:
cpu-map 1-4 0-3 # bind processes 1 to 4 on the first 4 CPUs
cpu-map 1/all 0-3 # bind all threads of the first process on the
# first 4 CPUs
cpu-map 1- 0- # will be replaced by "cpu-map 1-64 0-63"
# or "cpu-map 1-32 0-31" depending on the machine's
# word size.
# all these lines bind the process 1 to the cpu 0, the process 2 to cpu 1
# and so on.
cpu-map auto:1-4 0-3
cpu-map auto:1-4 0-1 2-3
cpu-map auto:1-4 3 2 1 0
# all these lines bind the thread 1 to the cpu 0, the thread 2 to cpu 1
# and so on.
cpu-map auto:1/1-4 0-3
cpu-map auto:1/1-4 0-1 2-3
cpu-map auto:1/1-4 3 2 1 0
# bind each process to exactly one CPU using all/odd/even keyword
cpu-map auto:all 0-63
cpu-map auto:even 0-31
cpu-map auto:odd 32-63
# invalid cpu-map because process and CPU sets have different sizes.
cpu-map auto:1-4 0 # invalid
cpu-map auto:1 0-3 # invalid
# invalid cpu-map because automatic binding is used with a process range
# and a thread range.
cpu-map auto:all/all 0 # invalid
cpu-map auto:all/1-4 0 # invalid
cpu-map auto:1-4/all 0 # invalid
当配置完成,可以通过show info查看
[root@www.linuxea.com ~]# echo "@1;show info" | socat stdio /var/run/haproxy.sock
Name: HAProxy
Version: 1.9.0
Release_date: 2018/12/19
Nbthread: 4
Nbproc: 1
Process_num: 1
Pid: 28687
Uptime: 0d 0h23m58s
....
你也可以通过web查看
高级:多线程架构
本节为希望更好地了解和理解HAProxy中多线程功能的人员提供了更深入的技术概述。
从架构的角度来看,HAProxy的许多部分都得到了改进,作为添加多线程支持的一部分。
但是,我们决定在每个线程中运行一个调度程序,而不是为调度程序提供一个线程,为工作程序提供多个线程。这使得HAProxy经过验证的高性能事件驱动引擎组件能够按线程运行并保持基本不变。另外,就这种方式而言,就这种方式而言,多线程行为与多进程行为非常相似,但它没有多进程限制!
在多线程模型中,每个实体(任务,fd或applet)一次只由一个线程处理,并且连接到同一会话的所有实体都由同一个线程处理。这意味着与特定会话相关的所有处理都被序列化,从而避免了否则将出现的大多数锁定问题。
还在每个实体上设置线程亲和性。与会话相关的实体坚持接受传入连接的线程。全局实体(侦听器,对等体,检查器,DNS解析器等)没有亲和力,并且所有线程都可能处理它们,但是根据前一段中给出的描述,总是一次一个。
与多线程相关的另一个重要主题是后端服务器状态的变化及其传播。服务器状态的更改现在在同一个位置同步完成,无需在通常需要的地方使用锁。
任何剩余的多线程主题大多归结为锁和原子操作。在HAProxy 1.8.0的初始版本中,一些部分被保守地锁定以使它们成为线程安全的,并且我们肯定会通过改进或删除其中一些锁来提高性能。
例如,未来将获得改进的领域之一是Lua多线程性能。Lua设计迫使我们使用全局锁,这意味着使用具有多个线程的Lua脚本将具有明显的成本,因为脚本基本上将运行单线程。
代码中的其他一些地方已经成为线程本地的,以避免需要锁定,但因此,它们可能会略微改变预期的行为。例如,后端的可重用连接仅适用于粘贴在同一线程上的会话。
调试
“DEBUG=-DDEBUG_THREAD”编译时候添加可以打开调试模式
延伸阅读
linuxea:haproxy1.9 了解四个基础部分https://www.haproxy.com/blog/multithreading-in-haproxy/