前几天和同事讨论起CGI的性能、CGI为什么是一项落后的技术的时候,发现其实很多人对CGI等的网关技术并不熟悉。这里相信很多同学也都听过CGI、fastCGI、WSGI等的词语,但是应该很多同学都分辨不清它们的区别和联系,本篇文章,就和大家一起探讨这些技术的发展简史。而本篇文章标题的GI,指的就是Gateway Interface(网关接口)的缩写。
了解网关接口之前,我们需要先弄清楚两个东西,Web服务器和Web应用程序。什么是Web服务器?什么是Web应用程序?虽然在我的Django小程序课程里面,有对这两者的区别展开来介绍,但是这里考虑到很多同学并没有学习这门课,所以我们先把这两个概念弄清楚,否则在后面讨论起网关接口,也只会一知半解。
首先,什么是Web服务器。Web服务器是服务于网站后台的一个软件,是常驻于物理服务器的一个计算机程序。Web服务器可以向浏览器等Web客户端提供文档,也可以放置网站文件,让全世界浏览;可以放置数据文件,让全世界下载。目前最主流的三个Web服务器是Apache、 Nginx 、IIS。
Apache是世界使用排名第一的Web服务器软件。它可以运行在几乎所有广泛使用的计算机平台上,由于其跨平台和安全性被广泛使用,是最流行的Web服务器端软件之一。它快速、可靠并且可通过简单的API扩充,将Perl/Python等解释器编译到服务器中。
Nginx是一款轻量级的Web服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器,在BSD-like 协议下发行。其特点是占有内存少,并发能力强,事实上Nginx的并发能力在同类型的网页服务器中表现较好,中国大陆使用Nginx网站用户有:百度、京东、新浪、网易、腾讯、淘宝等。
这里先简单讨论一下Nginx和Apache的区别,在资源上,Nginx占用的内存更少;在性能上,Nginx的并发能力更强;在社区方面,Nginx和Apache都拥有广泛的使用者,Apache的插件会比Nginx丰富一些。另外Nginx的功能比Apache要丰富一些,Nginx除了作为Web服务器以外,也经常作为反向代理服务器等使用,而Apache则主要作为Web服务器去使用。
还有IIS,IIS是微软公司在Windows Server提供的一个Web服务器,一般部署在Windows系统上,也有一定的使用者。
了解了Web服务器,我们接着了解一下Web应用程序。
Web应用程序一般指的是完成业务逻辑的程序,比如熟悉Python语言的,经常会用Django、Flask、Tornado等框架来完成业务逻辑的处理,接受请求,返回结果;熟悉Java语言的,则经常会使用Spring、Spring Boot来完成业务逻辑处理;熟悉PHP语言的,则常用ThinkPHP、Laravel、CI等等框架来完成Web后台的开发;还有Golang、Node.js等等,都会有相应的框架来完成Web请求的处理。
这些就是定义为Web应用程序的东西,也就是我们常说的Web框架,比如一个Pythoner问另外一个Pythoner,你一般使用什么Web框架呀?这个就是Web应用程序。
那么Web服务器和Web应用程序有啥区别?其实在前面的描述里面,我已经说的比较清楚了,Web应用程序主要是完成业务逻辑的处理,Web服务器则主要是进行外部请求的接收和转发。这里需要注意的是,我们一般不应该把业务逻辑放在Web服务器上去处理,虽然说Web服务器支持广泛的脚本来进行拓展,但是我们一般情况下还是不应该把业务逻辑放在Web服务器去处理,比如拦截请求、鉴权处理等等的操作。
看到这里可能有些人又会有疑问了,在开发Web应用的时候,我们直接就可以把应用跑起来接受请求了呀,为啥还需要Web服务器的存在。比如说使用Django的时候,直接输入命令python manage.py runserver,就可以接收请求了,为啥还需要Web服务器呢。
这主要是从性能上去考虑的,Web应用虽然在开发阶段就可以通过一些命令来启动服务,但是这些功能主要是提供调试所使用的,真正部署上线的时候,如果流量较大,性能是不行的,所以需要有Web服务器的存在。Web服务器是专门用于接收外部请求并处理的软件,所以Web服务器在性能上会比Web应用更佳,毕竟术业有专攻。Web服务器处理静态资源请求(CSS、JS、HTML、图片)等,性能会比Web应用更好。另外对于一些非静态资源的请求,则需要转发到后台Web应用。
到这里,我们基本分清楚Web服务器和Web应用的区别了,这里面我们注意一个关键词“转发”,当Web服务器接受请求的时候,会把请求转发到后台Web应用去处理,我们本篇文章的主角,GI就工作在这个转发的过程中。
终于轮到主角“网关接口”。前面介绍了GI工作的地方,接下来我们就来一起探讨一下现在有哪些GI,他们有哪些特点和区别。
首先是CGI,CGI是Common Gateway Interface (通用网关接口)的缩写。CGI是一项古老的技术。最初是在1993年由美国国家超级电脑应用中心(NCSA)为NCSA HTTPd Web服务器开发的。CGI的原理非常简单粗暴,在支持CGI的Web服务器下,只需要写一个简单的脚本,然后在脚本中输出内容,这些内容就会返回给前台。举个简单的例子,使用Python实现一个hello.py:
#!/usr/bin/env python
print 'Hello, World! Hello CGI.'
然后把他改名为hello.cgi,部署到Web服务器下,当请求到达的时候,打印的字符串就会通过Web服务器返回到页面。我们常常称这种应用为console application (也可以称作command-line interface programs) 的程序,这样的脚本称为CGI脚本。
CGI工作完整的原理是这样的:
- 当用户访问我们的 Web 应用时,会发起一个 HTTP 请求。最终 Web 服务器接收到这个请求。
- Web 服务器创建一个新的 CGI 进程。在这个进程中,将 HTTP 请求数据已一定格式解析出来,并通过标准输入和环境变量传入到 URL 指定的 CGI 程序。
- Web 应用程序处理完成后将返回数据写入到标准输出中,Web 服务器进程则从标准输出流中读取到响应,并采用 HTTP 协议返回给用户响应。
一句话就是 Web 服务器中的 CGI 进程将接收到的 HTTP 请求数据读取到环境变量中,通过标准输入转发给CGI程序;当CGI程序处理完成后,Web 服务器中的CGI进程从标准输出中读取返回数据,并转换回 HTTP 响应消息格式,最终将页面呈现给用户。然后 Web 服务器关闭掉这个 CGI 进程。
可以说 CGI 协议特别擅长处理 Web 服务器和 Web 应用的通信问题。然而,它有一个严重缺陷,对于每个请求都需要重新 fork 出一个 CGI 进程,处理完成后立即关闭。当请求量比较大时,会有严重的性能问题,因为频繁的创建进程和回收进程,会占用非常多的服务器资源。因为CGI的性能问题,于是新一代的CGI技术,FastCGI应运而生。
快速通用网关接口(Fast Common Gateway Interface/FastCGI)是一种让交互程序与Web服务器通信的协议。FastCGI是早期通用网关接口(CGI)的增强版本。
FastCGI致力于减少网页服务器与CGI程序之间交互的开销,从而使服务器可以同时处理更多的网页请求。
而FastCGI的工作原理是这样的:
- FastCGI 进程管理器启动时会创建一个 主(Master) 进程和多个 CGI 解释器进程(Worker 进程),然后等待 Web 服务器的连接。
- Web 服务器接收 HTTP 请求后,将 CGI 报文通过 套接字(UNIX 或 TCP Socket)进行通信,将环境变量和请求数据写入标准输入,转发到 CGI 解释器进程。
- CGI 解释器进程完成处理后将标准输出和错误信息从同一连接返回给 Web 服务器。
- CGI 解释器进程等待下一个 HTTP 请求的到来。
所以FastCGI可以看作是解决原始CGI性能问题的一个升级版本。
WSGI:全称是Web Server Gateway Interface,Web服务器网关接口,WSGI不是服务器,Python模块,框架,API或者任何软件,只是一种规范,描述前面Web服务器如何与Web应用通信的规范。
前面介绍网关接口的时候介绍了CGI、FastCGI等,那这里的WSGI主要是Python为Web服务器和Web应用程序之间通信而设计的。在Python中,常见的Web框架Tornado、Django、Flask都支持使用WSGI和Web服务器进行通信,而在采用WSGI协议的时候,则常常安装uWSGI模块来完成通信。
与WSGI类似的还有一个ASGI,ASGI也是由Python实现的一类网关接口,这里的A指的是Async,异步的意思。ASGI是WSGI的扩展,支持除了原来的HTTP以外的WebSocket等的网络协议。
终于来到Java阵营了,在前面的CGI、FastCGI、WSGI等等,主要都是PHP、C++、Python等语言实现Web应用程序和Web服务器通信的网关接口,尤其是CGI、FastCGI,在以前C++、PHP大行其道的时候,它们拥有广泛的用户基础,像腾讯等大企业,由于历史的关系,内部系统中还有很多保留着CGI、FastCGI等技术。那么在Java的阵营下,一般使用什么技术作为Web服务器和Web应用框架之间的通信呢?
Servlet,谈到Java不得不谈的一项技术,全称Server Applet,是用Java编写的服务器端程序,可以看做是前面我们介绍的Web应用程序。其主要功能在于交互式地浏览和修改数据,生成动态Web内容。Servlet最初诞生在1997年,最新的一个版本Servlet4.0于2017年9月份推出,Servlet拥有广泛的用户群体。
如果说Servlet是应用程序,那Servlet容器就是包含应用程序的Web服务器,常见的Servlet容器就有我们熟知的汤姆猫(Tomcat)、Jetty等,Servlet容器管理着Servlet应用,我们的Servlet程序一般通过Servlet容器对外进行服务。
随着Docker容器技术和K8S容器编排技术的成熟,今天微服务技术也是非常热门,而微服务离不开的Spring Boot、Spring Cloud的其中,就有Servlet、Servlet容器的身影。
我们说说Spring Boot,对于Spring Boot,大家都被他快捷的开发和部署方式所吸引,Spring Boot是由早期的Spring框架发展而来的,其设计目的是用来简化新Spring应用的初始搭建以及开发过程。在我们开发使用Spring Boot开发Web后台的时候,我们在写完逻辑代码的时候,在本地只需要点击运行,就能通过浏览器进行调试,颇为方便;这和前面我们使用PHP、Python开发Web程序非常类似,我们在使用Flask、Tornado等框架开发Web程序的时候,也可以通过简单的启动,就可以在本地通过浏览器去调试。但是这里是有一些区别的,我们说Flask、Tornado等框架是Web应用框架,没有说他们是Web服务器,他们通过前面介绍的网关接口(GI)通信,但是在使用Spring Boot的时候,却很少说需要把它部署在Web服务器Apache、Nginx之下,一般部署Spring Boot应用的时候,我们直接把它打包成jar包,就可以在服务器跑起来对外服务了。这是为什么呢?
其实Spring Boot内嵌了Servlet容器Tomcat,也就是Spring Boot既充当了Web应用程序的角色,也充当了Web服务器的角色,在开发Spring Boot应用程序的过程中,我们是先通过代码实现了Web应用程序的逻辑,处理请求和应答,而Servlet容器的部分,完全不需要我们去配置,这就是Spring Boot简单、便捷,高效的开发效率的原因,所以现在很多同学都喜欢使用Spring Boot去开发Web的后台。Spring Boot提供了简单的开发模式,但是也带来一些问题,比如说很多同学根本无法分清楚Web应用程序和Web服务器的区别等等。
最后简单的回顾一下今天这篇文章,我们主要是介绍了现在Web后端各种网关接口,包括CGI、FastCGI、WSGI等,在理解这些之前,我们需要弄懂Web服务器和Web应用程序,而网关接口,就是主要工作在Web服务器和Web应用程序之间的。最后我们还介绍了Java阵营的技术,在Java现在大行其道的Spring Boot框架里面,我们不再特意强调Web服务器和Web应用程序,Spring Boot框架是把两个融合在一起的一个框架,Spring Boot可以便捷的开发和部署Web程序,就是因为内部包含了一个叫Tomcat的Servlet容器,也就是Web服务器。
最后希望这篇文章对大家捋清楚Web后台技术和网关接口,都能有一定的帮助。
···················
欢迎关注课程:
《计算机基础——更适合程序员的编程必备基础知识》
《Django2.0+小程序技术打造微信小程序助手》
热门评论
亲 你那编程必备计算机基础知识 有地方说错了,tcp 建立三次握手的最主要原因是确认通讯双方的收发信息能力是否正常!不是别的。
第一次握手:客户端: 你好服务器,我是客户端,能听到我说话吗 收到请回复 111?(客户端不知道自己的发送信息能力是否正常)
第二次握手:服务端: 你好客户端,我听到你说话啦 111;你能听到我说话吗 收到请回复 222?(该步证明客户端发送信息能力正常;服务器端接收信息能力也正常。但服务器不知道自己的发送信息能力是否正常)
第三次握手:客户端: 服务器我收到你的信息了 222 (该步证明服务器端发送信息能力正常,客户端接收信息能力也正常)经过第三次握手证明双方收发信息能力都没问题,能正常开始通信了。
写的非常好,点赞了。
谢谢大佬的文章,学到了很多。