背景
使用的特定的设备进行深度学习模型的推理,该机器仅仅提供了C++封装好的API进行模型的加载启动与推理,模型的训练依然是使用caffe,模型需要转化成该设备支持的格式,模型的转化这里就不在介绍。为了把模型的推理做成一种服务,只能上手C++,搭建HTTP服务,使得用户通过http服务post一张图片,服务器启动模型推理,实现模型的预测,并把结果返回给客户端。
整体框架
服务短的服务内容就是对接收的图片进行预处理,然后进行模型的推理,目前需要做的一点就是引入HTTP服务
前期调研
对于一个C++新手,前期调研当然是先进行搜索,http server c++搜处理的结果也是五花八门,有的是教你如何通过实现一个http服务器,有的是一个用第三方库,有的是直接怼一堆代码。。。知道在*上看到了:
why not try NGINX with fcgi-function mapping?
实现步骤
nginx这个是做代理的神器,做负载均衡的时候也经常用,只要我的客户端的内容发送的nginx上,然后nginx把数据转发给fcgi相关的应用就可以,我需要做的就是把fcgi和我的推理程序结合起来就可以。
nginx
简单说nginx就是中间商,客户端把请求发给中间商,中间商去货源地把货拿上,让后给客户回应:
客户告诉nginx 我要购买**商品,nginx就去对于的服务提供商取出对于服务并把它返回给客户。
目前需要的就是实现fcgi 部分,那么什么是fcgi?
cgi
通用网关接口(Common Gateway Interface/CGI)是一种重要的互联网技术,可以让一个客户端,从网页浏览器向执行在网络服务器上的程序请求数据。CGI描述了服务器和请求处理程序之间传输数据的一种标准。
这里的标准输入输出是对应的一些环境变量主要包含有与请求相关的环境变量,与服务器相关的环境变量,与客户端相关的环境变量三大类。
fastcgi
FastCGI 实际上是增加了一些扩展功能的 CGI 、是 CGI 的改进,同样也是描述客户端和Web服务器程序之间传输数据的一种标准。
FastCGI 致力于减少Web服务器与CGI程序之间进行互动的开销,从而使Web服务器可以同时处理更多的Web请求。与 CGI 为每个Web请求创建一个新的进程不同, FastCGI 使用持续的进程来处理一连串的Web请求,这些进程由FastCGI进程管理器管理,而不是Web服务器。
为什么说是减少了互动的开销呢?这就要看两种处理方式的区别!
cgi的工作流程:
每当客户端发出一个新的请求,首先要创建一个cgi子进程,然后cgi处理完请求,有多少个连接就会有多少个cgi子进程启动,当请求量大的时候会占用大量的系统资源。
fastcgi
fastcgi 是使用持续的进程处理一连串的请求,这些进程有fastcgi的进程管理器来进行管理具体流程如下所示:
也可以这样比喻:
cgi在卖鸡蛋灌饼,等到顾客要吃的时候,他开始点火,打鸡蛋,摊饼,然后熄火。然后等待下一个顾客
fastcgi就是早餐店老版,雇佣了一帮服务员,专门做需要现场做的饭,老板只需要把订单安排下去,服务员负责盛粥煎饼。
具体步骤
- 搭建c++的开发环境
- 搭建nginx
- 安装fastcgi
- 安装fastcgi的进程管理器spawn-cgi
- 编写运行程序
- 编译运行
工欲善其事,必先利其器,首先搭建环境把!
通过阅读不少的博客内容找到了最简单的安装步骤,好多都是通过下载源代码,然后通过make进行编译,不过对于这些比较常用的库,软件包中已经集成了。
C++开发环境安装
1
|
apt-get install build-essential
|
nginx
1
|
apt-get install nginx
|
fastcgi
1
|
sudo apt-get install libfcgi-dev
|
spawn-fcgi
1
|
apt-get install spawn-fcgi
|
编写运行程序
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
|
#include <iostream>
#include "fcgio.h"
using namespace std;
int main(void) {
// Backup the stdio streambufs
streambuf * cin_streambuf = cin.rdbuf();
streambuf * cout_streambuf = cout.rdbuf();
streambuf * cerr_streambuf = cerr.rdbuf();
FCGX_Request request;
FCGX_Init();
FCGX_InitRequest(&request, 0, 0);
while (FCGX_Accept_r(&request) == 0) {
fcgi_streambuf cin_fcgi_streambuf(request. in );
fcgi_streambuf cout_fcgi_streambuf(request.out);
fcgi_streambuf cerr_fcgi_streambuf(request.err);
cin.rdbuf(&cin_fcgi_streambuf);
cout.rdbuf(&cout_fcgi_streambuf);
cerr.rdbuf(&cerr_fcgi_streambuf);
cout << "Content-type: text/html\r\n"
<< "\r\n"
<< "<html>\n"
<< " <head>\n"
<< " <title>Hello, World!</title>\n"
<< " </head>\n"
<< " <body>\n"
<< " <h1>Hello, World!</h1>\n"
<< " </body>\n"
<< "</html>\n" ;
}
cin.rdbuf(cin_streambuf);
cout.rdbuf(cout_streambuf);
cerr.rdbuf(cerr_streambuf);
return 0;
|
编译程序
1
|
g++ cgi.cpp -o cgidemo -lfcgi
|
修改nginx 配置文件
1
|
vi /usr/local/nginx/conf/nginx .conf
|
启动nginx
1
|
nginx -c /usr/local/nginx/conf/nginx .conf
|
通过浏览器验证nginx是否正常启动http://*******:80
启动spwan-cgi进程
1
|
spawn-fcgi -a 127.0.0.1 -C 20 -p 7070 . /cgidemo
|
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对服务器之家的支持。
原文链接:https://www.jianshu.com/p/a8e611527277