使用 acl 服务器框架编写负载均衡的应用服务
acl 服务器框架的几种服务器模型(进程模型,多线程模型,非阻塞模型,协程模型,触发器模型,UDP通信模型)中,使用比较多的是多线程模型、协程模块及非阻塞模型,这三种模型可以配置成启动多个进程实例(即成为:多进程多线程、多进程多协程及多进程非阻塞),但在实际应用中因为系统 TCP 连接分配的不均匀性,会导致每个进程实例的 TCP 连接数极不均匀甚至相差很大的问题(便出现了有的进程“撑死”,有的进程“饿死“的现象),acl 服务器框架提供了一个 TCP 连接分配器,该分配器负责接收外来 TCP 连接,然后将该 TCP 连接的文件句柄通过 UNIX 域套接字”平均传递给“后端的每一个子进程,从而保证了应用服务器进程池中的每个进程实例都能获得相等数量的 TCP 连接,从而达到负载均衡的目的。
如上图所示,整个网络连接处理过程如下:
在 acl_master 服务器框架下启动两个服务:TCP连接分配器和应用服务进程
TCP 连接分配器监听两个地址:一个是网络地址(如:192.168.188.1:80)和一个本机的 UNIX 域套接字(如:/opt/acl/var/private/dispatch.sock)
注:acl 服务器框架支持同时监听多个网络地址或 UNIX 域套口地址,参见:使用 acl 服务器框架编写监听多个地址的服务器程序
应用服务的每个进程通过该 UNIX 域套接口连接 TCP 连接分配器:
- 通过该连接向TCP连接分配器报告自己当前的 TCP 连接数
- 在该UNIX套接口接收TCP连接分配器发送的客户端TCP连接的套接字句柄
客户端通过网络连接 TCP 连接分配器监听的网络地址
TCP 连接分配器从后端进程池中选取一个连接数最少的进程,并通过与该进程的 UNIX 套接字将客户端的 TCP 连接句柄传递给该进程
后端获得 TCP 连接分配器传递来的 TCP 连接句柄,从而与前端客户端建立联系,开始处理客户端的请求。
通过以上处理流程,就可以保证客户端连接可以均匀地分配给后端服务进程池中的每一个进程实例,这样,每个进程实例占用的系统资源(如:CPU、内存、IO 等)就相对比较均匀。
在 UNIX/LINUX 平台下,通过 UNIX 域套接字传递描述字过程是由内核完成的,应用层只需负责相关的系统 API 调用即可,如何使用系统 API 传递描述字可以参考 acl 库中的 lib_acl/src/stdlib/sys/unix/acl_transfer_fd.c 源文件。
另外,上面所提的 TCP 连接分配器是使用 acl 服务器框架中的非阻塞服务模型编写的一个服务器程序,具体实现在 app/master_dispatch/server 目录下;应用服务器程序可以使用 acl 服务器框架中的线程池模型或非阻塞模型编写。
在部署时,需要将 TCP 连接分配器(app/master_dispatch/server/master_dispatch) 及用户自己写的服务器程序拷贝到执行目录下,在应用自己的服务器程序中需要将配置文件中的域接口连接地址打开(对于线程池模型需要打开 ioctl_dispatch_addr 配置项,对于非阻塞模型需要打开 aio_dispatch_addr 配置项)