keystone系列三:閘道器協議

linhaifeng發表於2017-01-10

一 靜態頁面和動態頁面

在瞭解了http協議後,我們知曉,一個web server的本質就是

  1. 瀏覽器傳送一個HTTP請求;

  2. 伺服器收到請求,生成一個HTML文件;

  3. 伺服器把HTML文件作為HTTP響應的Body傳送給瀏覽器;

  4. 瀏覽器收到HTTP響應,從HTTP Body取出HTML文件並顯示。

而使用者的請求的結果分靜態頁面和動態頁面兩種

靜態頁面:是一對寫死了的html程式碼,所有的訪問者看到的內容都一樣,如你訪問京東的主頁,所有人看到的都一樣

動態頁面:動態的概念意味著變,程式中體現'變'的概念就是變數,因而在html程式碼中需要嵌入變數,變數的值的來源需要用一段程式碼動態生成,這樣不同的使用者會提交不同的資料給服務端,服務端分析使用者提交過來的資料然後執行這段程式碼,動態生成值後賦值html中變數,然後返回html給使用者,這樣對每個使用者來說收到的頁面都是不一樣的。比如你登入京東,登入後返回的頁面每個人都不一樣。

二 什麼是web server

使用者上網的本質就是在自己這端啟動socket client(瀏覽器),服務的啟動socket server(web server)。

基於http協議的學習我們知道,web server主要是用來響應使用者的http請求然後返回html頁面給使用者。

從使用者上網的角度來說,早期的網際網路只有倆個角色:瀏覽器<->web server,此時所有的使用者訪問的都是靜態頁面

現在主流的web server有apache,nginx,lighttpd等,須知,它們只能接收使用者的請求然後生成靜態頁面

三 什麼是閘道器協議

3.1 引子

隨著網際網路的發展,網站為每個使用者單獨定製個人的東西呈現給使用者成為了主流,這時候就產生了動態頁面的需求。

因web server比如apache只能處理靜態請求,所以對於動態請求,你需要編寫專門的程式來處理

隨著網際網路的發展,越來越多的使用者資料需要永久儲存下來,檔案是可以永久儲存,但是檔案的資料處理效能太低,於是資料庫慢慢成為了網站大後端的主流

 

apache無法處理動態請求,所以我們需要自己編寫一個個的功能來處理這些動態請求(注意:這些動態請求有的需要查詢資料庫有的則不需要)

我們按照一個需要運算元據的動態請求舉例,來分析下問題

1 #處理動態請求的虛擬碼,可以稱之為web application,或者簡web app
2 
3 一:接收apache提交過來的使用者請求,觸發函式執行
4 二:連線資料庫
5 三:運算元據庫(增刪改查)
6 四:根據獲取的資料進行其他邏輯處理
7 五:返回給apache資料
8 六:關閉資料庫

問題一:

你在編寫web app時,需要深入研究apache工作的協議HTTP,等你研究明白了,過去了一百年。這嚴重影響了開發效率。

問題二:

這只是你針對apache這款web server定製的程式碼,換成了另外的web server你的程式無法重用

問題三:

這只是針對一種動態請求的程式碼實現,對於其他的動態請求呢,你仍然需要寫重複的程式碼去處理。

3.2 閘道器協議

 

如何解決問題一:

我們迫切需要在web server與web app之間定義一種標準,用來明細分工,web server對外提供一種標準,web app開發者只要遵循這個標準,那麼後者就無需考慮web server到底是如何實現的了而可以專注web app的開發,這個標準就是閘道器協議

如何解決問題二:

在web server與web app之間定義了標準,那麼只要我的web app是遵循這個標準的,換另外一個也遵循該標準的web server,同樣可以執行

如何解決問題三:

這裡需要引入一個概念叫:web app開發框架(也稱web 框架)

web app開發框架用來為web app開發者提供一套現成的開發工具與開發模式,web app開發者不再需要寫重複程式碼了,只需要使用某種現成的web開發框架,一些重複的功能就不用再去重複造輪子了,這極大的提高了開發效率

比如web app開發框架一般本事都是基於閘道器協議標準實現的,因為你用web app開發框架去開發web app,自然就是遵循某種閘道器協議標準的,你甚至連這個協議具體是什麼都無需知道。

四 閘道器協議CGI、FastCGI、WSGI、UWSGI

閘道器協議CGI

什麼是CGI?

CGI即通用閘道器介面(Common Gateway Interface),是web app應用程式(CGI程式)與Web伺服器之間的介面標準。。

CGI 的跨平臺效能極佳,幾乎可以在任何作業系統上實現。

fork-and-execute模式:apache接收使用者動態請求,先要建立cgi的子程式,然後處理請求,處理完後結束這個子程式。

fork-and-execute模式的弊端:用cgi方式的伺服器有多少連線請求就會有多少cgi子程式,子程式反覆載入是cgi效能低下的主要原因。當使用者請求數量非常多時,會大量擠佔系統的資源如記憶體,CPU時間等,造成效能低下。

CGI指令碼的工作流程:

  1. 瀏覽器傳送動態請求(通過HTML表單或者超連結)
  2. 服務端接收該請求,呼叫CGI指令碼,產生一個CGI程式來處理該動態請求,結果返回給伺服器
  3. 伺服器將html返回給瀏覽器

閘道器協議FASTCGI

什麼是FASTCGI?

FastCGI是從CGI發展改進而來的

傳統CGI介面方式的主要缺點是效能很差,因為每次HTTP伺服器遇到動態請求時都需要重新啟動指令碼解析器來處理,然後返回結果給HTTP伺服器。無法應對高並非場景。

FastCGI像是一個常駐(long-live)型的CGI,它可以一直執行著,只要啟用後,不會每次都要花費時間去fork一次(這是CGI最為人詬病的fork-and-execute 模式)。

CGI 就是所謂的短生存期應用程式,FastCGI 就是所謂的長生存期應用程式。

由於 FastCGI 程式並不需要不斷的產生新程式,可以大大降低伺服器的壓力並且產生較高的應用效率。它的速度效率最少要比CGI 技術提高 5 倍以上。它還支援分散式的運算, 即 FastCGI 程式可以在網站伺服器以外的主機上執行並且接受來自其它網站伺服器來的請求。

 

FastCGI是語言無關的、可伸縮架構的CGI開放擴充套件,其主要行為是將CGI直譯器程式保持在記憶體中並因此獲得較高的效能。眾所周知,CGI直譯器的反覆載入是CGI效能低下的主要原因,如果CGI直譯器保持在記憶體中並接受FastCGI程式管理器排程,則可以提供良好的效能、伸縮性、Fail-Over特性等等。FastCGI介面方式採用C/S結構,可以將HTTP伺服器和指令碼解析伺服器分開,同時在指令碼解析伺服器上啟動一個或者多個指令碼解析守護程式。當HTTP伺服器每次遇到動態程式時,可以將其直接交付給FastCGI程式來執行,然後將得到的結果返回給瀏覽器。這種方式可以讓HTTP伺服器專一地處理靜態請求或者將動態指令碼伺服器的結果返回給客戶端,這在很大程度上提高了整個應用系統的效能。

FastCGI的工作流程:

  1. Web Server啟動時載入FastCGI程式管理器(PHP-CGI或者PHP-FPM或者spawn-cgi)
  2. FastCGI程式管理器自身初始化,啟動多個CGI直譯器程式(可見多個php-cgi)並等待來自Web Server的連線。
  3. 當客戶端請求到達Web Server時,FastCGI程式管理器選擇並連線到一個CGI直譯器。Web server將CGI環境變數和標準輸入傳送到FastCGI子程式php-cgi。
  4. FastCGI子程式完成處理後將標準輸出和錯誤資訊從同一連線返回Web Server。當FastCGI子程式關閉連線時,請求便告處理完成。FastCGI子程式接著等待並處理來自FastCGI程式管理器(執行在Web Server中)的下一個連線。 在CGI模式中,php-cgi在此便退出。

FastCGI 的特點

  1. 打破傳統頁面處理技術。傳統的頁面處理技術,程式必須與 Web 伺服器或 Application 伺服器處於同一臺伺服器中。這種歷史已經早N年被FastCGI技術所打破,FastCGI技術的應用程式可以被安裝在伺服器群中的任何一臺伺服器,而通過 TCP/IP 協議與 Web 伺服器通訊,這樣做既適合開發大型分散式 Web 群,也適合高效資料庫控制。
  2. 明確的請求模式。CGI 技術沒有一個明確的角色,在 FastCGI 程式中,程式被賦予明確的角色(響應器角色、認證器角色、過濾器角色)。
PHP-CGI是PHP自帶的FastCGI管理器。PHP-CGI的不足:

php-cgi變更php.ini配置後需重啟php-cgi才能讓新的php-ini生效,不可以平滑重啟
直接殺死php-cgi程式php就不能執行了。(PHP-FPM和Spawn-FCGI就沒有這個問題,守護程式會平滑從新生成新的子程式。)
PHP-CGI
Spawn-FCGI是一個通用的FastCGI管理伺服器,它是lighttpd中的一部份,很多人都用Lighttpd的Spawn-FCGI進行FastCGI模式下的管理工作,不過有不少缺點。而PHP-FPM的出現多少緩解了一些問題,但PHP-FPM有個缺點就是要重新編譯,這對於一些已經執行的環境可能有不小的風險),在php 5.3.3中可以直接使用PHP-FPM了。Spawn-FCGI的程式碼很少,全部才630行,用c語言編寫,最近一次提交是5年前。程式碼主頁:https://github.com/lighttpd/spawn-fcgi

Spawn-FCGI程式碼分析如下:

spawn-fcgi 首先create socket,bind,listen 3步建立伺服器socket,(把這個socket叫做 fcgi_fd)
用dup2,把fcgi_fd 交換給 FCGI_LISTENSOCK_FILENO (FCGI_LISTENSOCK_FILENO數值上等於0,這是fastcgi協議當中指定用來listen的socket id)
執行execl ,replaces the current process image with a new process image. process image 程式在執行空間的程式碼段
很顯然,Spawn-FCGI也是 pre-fork 模型,只是用了上古C語言編寫,充滿了N多 unix下暗黑程式設計技巧。

Spawn-FCGI功能很單一:

只管fork程式,子程式掛了,主程式僅僅log記錄一次,根本不會重新fork。在2009年一段時間內,我曾經用spawn-fcgi部署php-cgi,當跑一段時間就會全掛掉,只能用crontab定時重啟spawn-fcgi
不負責子程式中的網路IO,把socket放到指定位置就完了,接下來的事情由被spawn的程式處理
Spawn-FCGI是一個很早期的程式,瞻仰一下即可。另外有:1996年的一段程式碼:http://www.fastcgi.com/om_archive/kit/cgi-fcgi/cgi-fcgi.c,和spawn-fcgi一個風格
Spawn-FCGI
PHP-FPM是一個PHP FastCGI管理器,是隻用於PHP的,可以在 http://php-fpm.org/download下載得到。PHP-FPM其實是PHP原始碼的一個補丁,旨在將FastCGI程式管理整合進PHP包中。必須將它patch到你的PHP原始碼中,在編譯安裝PHP後才可以使用。FPM(FastCGI 程式管理器)用於替換 PHP-CGI 的大部分附加功能,對於高負載網站是非常有用的。它的功能包括:

支援平滑停止/啟動的高階程式管理功能;
可以工作於不同的 uid/gid/chroot 環境下,並監聽不同的埠和使用不同的 php.ini 配置檔案(可取代 safe_mode 的設定);
stdout 和 stderr 日誌記錄;
在發生意外情況的時候能夠重新啟動並快取被破壞的 opcode;
檔案上傳優化支援;
“慢日誌” – 記錄指令碼(不僅記錄檔名,還記錄 PHP backtrace 資訊,可以使用 ptrace或者類似工具讀取和分析遠端程式的執行資料)執行所導致的異常緩慢;
fastcgi_finish_request() – 特殊功能:用於在請求完成和重新整理資料後,繼續在後臺執行耗時的工作(錄入視訊轉換、統計處理等);
動態/靜態子程式產生;
基本 SAPI 執行狀態資訊(類似Apache的 mod_status);
基於 php.ini 的配置檔案。
PHP-FPM

閘道器協議WSGI

什麼是WSGI?

Web伺服器閘道器介面(Python Web Server Gateway Interface,縮寫為WSGI)是為Python語言定義的Web伺服器和Web應用程式或框架之間的一種簡單而通用的介面。它只是一個介面定義:它不負責伺服器的實現,也不負責網頁應用的實現,它只是一個兩邊介面方式的約定。

自從WSGI被開發出來以後,許多其它語言中也出現了類似介面。WSGI是作為Web伺服器與Web應用程式或應用框架之間的一種低階別的介面,以提升可移植Web應用開發的共同點。WSGI是基於現存的CGI標準而設計的。WSGI就是Python的CGI包裝,相對於Fastcgi是PHP的CGI包裝

有了WSGI,你就不用去考慮,伺服器程式的具體實現,應用程式獲得了很好的適用性。比如一個雲平臺提供了對 WSGI 介面的支援,那麼,只要應用是基於 WSGI 的,就可以直接跑起來。其實keystone就是一款python開發的基於WSGI標準的app。

什麼是WSGI中介軟體?

基於WSGI 的設計哲學,我們可以寫一些對 server 和 application 都相容的模組,即WSGI中介軟體(middleware)。所謂的 WSGI 中介軟體同時實現了API的兩方,因此可以在WSGI服務和WSGI應用之間起調解作用:從WSGI伺服器的角度來說,中介軟體扮演應用程式,而從應用程式的角度來說,中介軟體扮演伺服器。

WSGI中介軟體的功能與好處?

WSGI中介軟體可以完成比如快取、字元編碼轉換、根據 url 做應用 routing 等功能。

這種設計模式,是 WSGI 降低了 server 和 application 耦合度之後的產物,同時,它從另一個角度大大提升了設計的靈活性。

WSGI的處理模式

WSGI將 web 元件分為三類: web伺服器,web中介軟體,web應用程式

wsgi基本處理模式為 : WSGI Server -> (WSGI Middleware)* -> WSGI Application 。

在處理一個WSGI請求時,伺服器會為應用程式提供環境資訊及一個回呼函式(Callback Function)。當應用程式完成處理請求後,透過前述的回呼函式,將結果回傳給伺服器。

 

1.WSGI Server/gateway

wsgi server可以理解為一個符合wsgi規範的web server,接收request請求,封裝一系列環境變數,按照wsgi規範呼叫註冊的wsgi app,最後將response返回給客戶端。文字很難解釋清楚wsgi server到底是什麼東西,以及做些什麼事情,最直觀的方式還是看wsgi server的實現程式碼。以python自帶的wsgiref為例,wsgiref是按照wsgi規範實現的一個簡單wsgi server。

  1. 伺服器建立socket,監聽埠,等待客戶端連線。
  2. 當有請求來時,伺服器解析客戶端資訊放到環境變數environ中,並呼叫繫結的handler來處理請求。
  3. handler解析這個http請求,將請求資訊例如method,path等放到environ中。
  4. wsgi handler再將一些伺服器端資訊也放到environ中,最後伺服器資訊,客戶端資訊,本次請求資訊全部都儲存到了環境變數environ中。
  5. wsgi handler 呼叫註冊的wsgi app,並將environ和回撥函式傳給wsgi app
  6. wsgi app 將reponse header/status/body 回傳給wsgi handler
  7. 最終handler還是通過socket將response資訊塞回給客戶端。

2、WSGI Application

wsgi application就是一個普通的callable物件,當有請求到來時,wsgi server會呼叫這個wsgi app。這個物件接收兩個引數,通常為environ,start_response。environ就像前面介紹的,可以理解為環境變數,跟一次請求相關的所有資訊都儲存在了這個環境變數中,包括伺服器資訊,客戶端資訊,請求資訊。start_response是一個callback函式,wsgi application通過呼叫start_response,將response headers/status 返回給wsgi server。此外這個wsgi app會return 一個iterator物件 ,這個iterator就是response body。

基於python wsgiref製作wsgi server(web server)

#_*_coding:utf-8_*_
#!/usr/bin/env python

from wsgiref.simple_server import make_server
# 定義application函式:
def application(environ, start_response):
    print(environ)
    start_response('200 OK', [('Content-Type', 'text/html')])

    f=open('test.html','rb')
    return [f.read()]

# 建立一個伺服器,IP地址為空,埠是8000,處理函式是application:
httpd = make_server('', 8000, application)
print('Serving HTTP on port 8000...')
# 開始監聽HTTP請求:
httpd.serve_forever()
wsgi server

 

<!DOCTYPE html>
<html>
<body>

<form>
使用者名稱:<br>
<input type="text" name="username">
<br>
密碼:<br>
<input type="text" name="password">
<input type="submit" value="登入">
</form>

</body>
</html>
test.html

3、WSGI MiddleWare

有些功能可能介於伺服器程式和應用程式之間,例如,伺服器拿到了客戶端請求的URL, 不同的URL需要交由不同的函式處理,這個功能叫做 URL Routing,這個功能就可以放在二者中間實現,這個中間層就是 middleware。middleware對伺服器程式和應用是透明的,也就是說,伺服器程式以為它就是應用程式,而應用程式以為它就是伺服器。這就告訴我們,middleware需要把自己偽裝成一個伺服器,接受應用程式,呼叫它,同時middleware還需要把自己偽裝成一個應用程式,傳給伺服器程式。

 

閘道器協議uWSGI

uWSGI is gaining steam as a highly-performant WSGI server implementation.

參考:

http://www.fullstackpython.com/wsgi-servers.html

https://www.biaodianfu.com/cgi-fastcgi-wsgi.html

http://www.cnblogs.com/pied/p/4597740.html

五 閘道器協議與keystone

keystone本質就是python開發的一款基於wsgi的app,社群提倡的部署方法:

apache(wsgi)+keystone

nginx(uwsgi)+keystone

六 概念梳理

客戶端

常用瀏覽器:chrome

web服務

常用web server:apache,nginx,lighttpd

web app

常用web app開發語言:python,php,java

python常用web app開發框架(Web框架):

除了Flask,常見的Python 還有:

  • Flask:輕量級Web app開發框架;

  • Django:全能型Web app開發框架;
  • web.py:一個小巧的Web app開發框架;

  • Bottle:和Flask類似的Web app開發框架;

  • Tornado:Facebook的開源非同步Web app開發框架。

資料庫

常用資料庫:mysql,db2,oracle,sqlserver

相關文章