引言
在人工智能 (AI) 和机器学习 (ML) 领域,最需要的就是可扩展的高效 AI 推理解决方案。随着企业部署日益复杂的 AI 模型来解决实际问题,确保这些模型能够处理海量的推理请求变得非常关键。
NGINX Plus 能够高效管理传入流量。作为高性能 Web 服务器和反向代理服务器,NGINX Plus 可跨 AI 模型服务环境的多个实例对传入的 HTTP 和 TCP 流量实施负载均衡和路由。
采用英特尔 OpenVINO 工具套件的 OpenVINO Model Server 是一款多功能推理服务器,支持多种深度学习框架和硬件加速技术,便于开发人员高效部署和支持 AI 模型,以优化性能和资源利用率。
通过结合使用 NGINX Plus 功能,开发人员能够创建可扩展的弹性 AI 推理解决方案,从而处理高负载并确保高可用性。健康检查允许 NGINX Plus 持续监控上游 OVMS 实例的健康状况。如果某个 OVMS 实例运行异常或无响应,NGINX Plus 会自动将流量从该实例路由出去,以确保推理请求只由健康的 OVMS 实例进行处理。通过健康检查,管理员可以实时了解 OVMS 实例的健康状况,监控响应时间、错误率及可用性等关键指标,从而及时主动地发现和解决问题,避免服务性能受到影响。
本文深入探究了 OpenVINO Model Server 和 NGINX Plus 如何共同构建一个可扩展的强大 AI 推理解决方案;并探讨了如何设置环境、配置模型服务器、利用 NGINX Plus 实施负载均衡并执行测试。最后,您将了解如何利用 Docker、OpenVINO Model Server 和 NGINX Plus 来根据具体需求构建可扩展的 AI 推理系统。
流程说明:
- 下面我们来看看典型的推理请求流程。当用户提交一张斑马图像进行推理时,请求首先会进入 NGINX 负载均衡器。
- 然后,负载均衡器将请求转发给一个可用的 OpenVINO Model Server 容器,从而将工作负载均匀分配给多个容器。
- 所选容器使用优化的深度学习模型处理图像,并将推理结果返回给用户。在本例中,对象被命名为“斑马”。
OpenVINO™ Model Server 是一款可扩展的高性能解决方案,用于支持针对英特尔® 架构优化的机器学习模型。该服务器通过 gRPC、REST API 或 C API 提供推理服务,便于轻松部署新算法和进行 AI 实验。
更多详情请访问 https://hub.docker.com/u/openvino。
设置:
首先,我们将在容器中部署模型服务器。在本用例中,需要将模型服务器部署至虚拟机 (VM)。以下是详细步骤:
- 获取 OpenVINO ONNX 运行时的 docker 镜像
docker pull openvino/onnxruntime_ep_ubuntu20
- 您还可以访问 https://docs.openvino.ai/nightly/ovms_docs_deploying_server.html,了解如何在容器环境中部署 OpenVINO Model Server。
- 首先,按照下面的结构创建一个 docker-compose 文件:
https://raw.githubusercontent.com/f5businessdevelopment/F5openVino/main/docker-compose.yml
version: '3'
services:
resnet1:
image: openvino/model_server:latest
command: >
--model_name=resnet
--model_path=/models/resnet50
--layout=NHWC:NCHW
--port=9001
volumes:
- ./models:/models
ports:
- "9001:9001"
resnet2:
image: openvino/model_server:latest
command: >
--model_name=resnet
--model_path=/models/resnet50
--layout=NHWC:NCHW
--port=9002
volumes:
- ./models:/models
ports:
- "9002:9002"
# 添加更多服务以创建更多容器
resnet3:
image: openvino/model_server:latest
command: >
--model_name=resnet
--model_path=/models/resnet50
--layout=NHWC:NCHW
--port=9003
volumes:
- ./models:/models
ports:
- "9003:9003"
resnet4:
image: openvino/model_server:latest
command: >
--model_name=resnet
--model_path=/models/resnet50
--layout=NHWC:NCHW
--port=9004
volumes:
- ./models:/models
ports:
- "9004:9004"
resnet5:
image: openvino/model_server:latest
command: >
--model_name=resnet
--model_path=/models/resnet50
--layout=NHWC:NCHW
--port=9005
volumes:
- ./models:/models
ports:
- "9005:9005"
resnet6:
image: openvino/model_server:latest
command: >
--model_name=resnet
--model_path=/models/resnet50
--layout=NHWC:NCHW
--port=9006
volumes:
- ./models:/models
ports:
- "9006:9006"
resnet7:
image: openvino/model_server:latest
command: >
--model_name=resnet
--model_path=/models/resnet50
--layout=NHWC:NCHW
--port=9007
volumes:
- ./models:/models
ports:
- "9007:9007"
resnet8:
image: openvino/model_server:latest
command: >
--model_name=resnet
--model_path=/models/resnet50
--layout=NHWC:NCHW
--port=9008
volumes:
- ./models:/models
ports:
- "9008:9008"
- 确保您的系统已安装 Docker 和 Docker Compose。
- 将模型文件放在本地计算机的 `./models/resnet50` 目录中。
- 将提供的 Docker Compose 配置保存到名为 `docker-compose.yml` 的文件中。
- 在包含 `docker-compose.yml` 文件的目录中运行以下命令,以启动服务:
docker-compose up -d
- 现在,您可以使用指定的端口访问 OpenVINO Model Server 实例(例如,使用 `http://localhost:9001` 访问 `resnet1`,使用 `http://localhost:9002` 访问 `resnet2`)。
—— 在启动服务之前,确保将模型文件正确放置在 `./models/resnet50` 目录中。
-
设置 NGINX Plus 代理服务器。
有关 NGINX Plus 的安装,您还可以参考 https://docs.nginx.com/nginx/admin-guide/installing-nginx/installing-nginx-plus/
您可选择通过以下任一方式在 AWS 上使用 NGINX Plus 配置虚拟机:
- 按照下列链接中的指南,通过 AWS Marketplace 在 AWS 上设置 NGINX Plus:
AWS Marketplace 上的 NGINX Plus
或者
- 按照 GitHub 上提供的仓库链接中的说明进行操作。该仓库可用于在 AWS 上使用 Terraform 创建多台虚拟机,并在 GitHub 仓库 —— F5 OpenVINO下利用 NGINX Plus 部署虚拟机
NGINX Plus 代理服务器的功能是代理上游 (upstream) 模型服务器。在 upstream 代码块中,定义了后端服务器 (model_servers) 及其各自的 IP 地址和端口。在服务器块中,NGINX 会监听 80 端口,以处理指向特定服务器名称或 IP 地址的 HTTP/2 传入请求。定向到根位置 (/) 的请求将通过 gRPC 协议转发到上游模型服务器。使用 proxy_set_header 指令是为了在向后端服务器传递请求时保持客户端信息的完整性。确保根据具体设置调整 IP 地址、端口及服务器名称。
下面是一个配置示例 —— 也可在 GitHub 中找到: https://github.com/f5businessdevelopment/F5openVino
upstream model_servers { server 172.17.0.1:9001; server 172.17.0.1:9002; server 172.17.0.1:9003; server 172.17.0.1:9004; server 172.17.0.1:9005; server 172.17.0.1:9006; server 172.17.0.1:9007; server 172.17.0.1:9008; zone model_servers 64k; } server { listen 80 http2; server_name 10.0.0.19; # 替换为您的域名或公共 IP 位置 / { grpc_pass grpc://model_servers; health_check type=grpc grpc_status=12; # 12=unimplemented proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } }
如果您使用的是开启 SSL 的 gRPC,请参考 NGINX Plus SSL 配置中的详细配置
示例如下:
upstream model_servers { server 172.17.0.1:9001; # Docker bridge network IP and port for your container server 172.17.0.1:9002; # Docker bridge network IP and port for your container .... .... }
本节定义了一个名为 model_servers 的 upstream 代码块,它表示一组后端服务器。在本例中,定义了两个后端服务器,每个服务器都有自己的 IP 地址和端口。这些服务器通常是 NGINX 将代理请求的目标端点。
server { listen 80 http2; server_name 10.1.1.7; # 替换为您的域名或公共 IP
这一部分以主服务器块开始。它指定 NGINX 应监听 80 端口上采用 HTTP/2 协议 (http2) 的传入连接,并将服务器绑定到 IP 地址 10.1.1.7。将此 IP 地址替换为您的域名或公共 IP 地址。
location / { grpc_pass grpc://model_servers; health_check type=grpc grpc_status=12; # 12=unimplemented proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; }
在 location/ 代码块中,NGINX 定义了如何处理对根位置的请求。在本例中,它使用 gRPC (grpc_pass grpc://model_servers;) 将请求传递给在 model_servers 代码块中定义的上游服务器。proxy_set_header 指令用于设置请求头,以便在向后端服务器传递请求时保留客户端信息。这些请求头包括 Host、X-Real-IP 及 X-Forwarded-For。使用 type=grpc 执行健康检查便于对单个 gRPC 服务和端点进行细粒度监控。您可以验证特定 gRPC 方法或功能的健康状况,确保每个服务组件都正常运行。
总之,该 NGINX 配置设置了一个反向代理服务器。该服务器在 80 端口监听 HTTP/2 请求,并使用 gRPC 协议将这些请求转发到后端服务器 (model_servers)。它通常用于实施负载均衡或将请求路由到多台后端服务器。
推理测试:
下面是进行测试的方法。在客户端,我们使用一个名为 predict.py 的脚本。脚本如下
# 导入必要的库 import numpy as np from classes import imagenet_classes from ovmsclient import make_grpc_client # 创建一个 gRPC 客户端来与服务器进行通信 # 将“10.1.1.7:80”替换为您服务器的 IP 地址和端口 client = make_grpc_client("10.1.1.7:80") # 以二进制读取模式打开图像文件“zebra.jpeg” with open("zebra.jpeg", "rb") as f: img = f.read() # 使用“resnet”模型将图像数据发送至服务器进行预测 output = client.predict({"0": img}, "resnet") # 提取概率最高的已预测类索引 result_index = np.argmax(output[0]) # 使用 imagenet_classes 字典打印预测的类标签 print(imagenet_classes[result_index])
该脚本会导入必要的库,在指定的 IP 地址和端口上与服务器建立连接,读取名为“zebra.jpeg”的图像文件,使用“resnet”模型将图像数据发送到服务器进行预测,检索概率最高的已预测类索引,并打印相应的类标签。
结果:
在客户端机器上执行以下命令。此处,我们将“斑马”的图像传输到模型服务器。
python3 predict.py zebra.jpg # 运行推理流量 zebra。预测输出为“斑马”。
下面我们来看看 NGINX Plus 日志
cat /var/log/nginx/access.log 10.1.1.7 - - [13/Apr/2024:00:18:52 +0000] "POST /tensorflow.serving.PredictionService/Predict HTTP/2.0" 200 4033 "-" "grpc-python/1.62.1 grpc-c/39.0.0 (linux; chttp2)"
此日志条目显示,在指定的时间戳向 NGINX 服务器发出了 POST 请求,服务器返回了成功状态代码 (200)。如用户代理字符串所示,请求是通过 gRPC 发出的。
结语 :
有了 NGINX Plus,企业可以实现可扩展的高效 AI 推理解决方案。NGINX Plus 能够解决因连接超时/错误、请求率骤增或网络拓扑变更所致的中断问题。OpenVINO Model Server 优化了模型性能和推理速度,利用英特尔硬件加速技术提高了效率。NGINX Plus 可充当高性能负载均衡器,将传入请求分配给多个模型服务器实例,有助于提高可扩展性和可靠性。它们共同实现了 AI 推理工作负载的无缝扩展,可确保最佳性能和资源利用率。
请参考此视频:https://youtu.be/Sd99woO9FmQ
参考资料:
https://hub.docker.com/u/openvino
https://docs.nginx.com/nginx/deployment-guides/amazon-web-services/high-availability-keepalived/
https://www.nginx-cn.net/blog/nginx-1-13-10-grpc/
https://github.com/f5businessdevelopment/F5openVino.git
https://docs.openvino.ai/nightly/ovms_docs_deploying_server.html