上一回介紹了 GitLab 的基礎功能和架構,但還沒具體講解用戶的請求是怎麼被處理的,只是將各個組件的功能職責介紹了一遍,本節將簡單介紹 gitlab-workhorse 的功能css
首先回顧一下:GitLab 利用 Nginx 將前端的 http/https 請求代理至 gitlab-workhorse,gitlab-workhorse 再將請求轉發至 Unicorn Web 服務器。默認狀況下 gitlab-workhorse 與前端之間的通訊是使用 unix domain socket 進行的,但也支持 TCP 轉發請求;GitLab 使用 Unicorn Web 服務器提供動態網頁和 API 接口html
從架構圖能夠看出,HTTP/HTTPS 請求進入 GitLab 的第一站是 nginx前端
下載 GitLab-ce 官方源碼後,進入 ${gitlab-ce根目錄}/lib/support/nginx
,打開 gitlab-ssl
能夠看到 nginx 的配置nginx
GitLab 默認將 http 請求重定向至 https 請求git
## Redirects all HTTP traffic to the HTTPS host
server {
listen 0.0.0.0:80;
listen [::]:80 ipv6only=on default_server;
server_name YOUR_SERVER_FQDN;
server_tokens off;
return 301 https://$http_host$request_uri;
access_log /var/log/nginx/gitlab_access.log gitlab_ssl_access;
error_log /var/log/nginx/gitlab_error.log;
}
複製代碼
https 的設置相對比較複雜,這裏僅提一個亮點:location: /
下面的 proxy_pass http://gitlab-workhorse;
,說明了 除了某些靜態頁面,nginx 幾乎將全部的 http/https 請求傳遞給了 gitlab-workhorse 組件處理(使用 unix socket 通訊)web
Unix Socket 是一種 socket 方式實現的進程間通訊功能,它不須要進行復雜的數據打包拆包、校驗和計算驗證,不須要走網絡協議棧,安全可靠。Unix Socket 實際上是 socket 的其中一種 AF_UNIX 或 AF_LOCAL 的類型,成爲 unix domain socket,是爲了進行本地通訊,也就是爲了實現 IPC,因此構造函數不須要IP和端口,取而代之的是文件路徑數據庫
upstream gitlab-workhorse {
# GitLab socket file,
# for Omnibus this would be: unix:/var/opt/gitlab/gitlab-workhorse/socket
server unix:/home/git/gitlab/tmp/sockets/gitlab-workhorse.socket fail_timeout=0;
}
...
## HTTPS host
server {
listen 0.0.0.0:443 ssl;
listen [::]:443 ipv6only=on ssl default_server;
server_name YOUR_SERVER_FQDN;
server_tokens off;
ssl on;
ssl_certificate /etc/nginx/ssl/gitlab.crt;
ssl_certificate_key /etc/nginx/ssl/gitlab.key;
ssl_ciphers "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4";
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 5m;
real_ip_recursive off; ## If you enable 'on'
access_log /var/log/nginx/gitlab_access.log gitlab_ssl_access;
error_log /var/log/nginx/gitlab_error.log;
location / {
client_max_body_size 0;
gzip off;
proxy_read_timeout 300;
proxy_connect_timeout 300;
proxy_redirect off;
proxy_http_version 1.1;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Ssl on;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade_gitlab_ssl;
proxy_pass http://gitlab-workhorse;
}
error_page 404 /404.html;
error_page 422 /422.html;
error_page 500 /500.html;
error_page 502 /502.html;
error_page 503 /503.html;
location ~ ^/(404|422|500|502|503)\.html$ {
root /home/git/gitlab/public;
internal;
}
}
複製代碼
那麼 GitLab-workhorse 是什麼呢?官方解釋稱它是 GitLab 的智能反向代理服務器,用於處理負載量較大的 HTTP 請求,諸如文件上傳/下載、Git push/pull 以及 Git 歸檔下載等。而實際上可能比較複雜瀏覽器
+-------+ +------------------+ +---------+
| | | | | |
| NGINX +->| gitlab-workhorse +->| Unicorn |
| | | | | |
+-------+ +------------------+ +---------+
複製代碼
下述的 Rails 組件是運行在 Unicorn Web 服務器的:安全
send_file
,那麼 gitlab-workhorse 將會打開磁盤中的文件而後把文件內容做爲響應體返回給客戶端git clone
以前得確認當前客戶的權限,在向 Rails 組件詢問確認後 workhorse 將繼續接管 git clone
的請求
好比 Unicorn 處理靜態資源文件效率相對較低,那就交給 workhorse 處理。因爲文章篇幅的緣由,這裏僅挑一個例子進行講解:gzip 資源文件bash
在 ${gitlab-workhorse根目錄}/internal/staticpages/servefile.go
的函數 func (s *Static) ServeExisting
內,定義了 workhorse 對靜態資源文件的處理方式
假設咱們得請求相對 URL 爲 /assets/locale/zh_CN/app-3396bd500e53f89d971d8c31ba7275f1c9ae2899062d4a7aeef14339084f44bd.js
,由於帶有 assets
前綴,因此 workhorse 將採用處理靜態資源文件的方式處理請求,如代碼所示
// ${gitlab-workhorse根目錄}/internal/upstream/routes.go
// Serve assets
route(
"", `^/assets/`,
static.ServeExisting(
u.URLPrefix,
staticpages.CacheExpireMax,
NotFoundUnless(u.DevelopmentMode, proxy),
),
withoutTracing(), // Tracing on assets is very noisy
),
複製代碼
下圖對 js 靜態資源文件的請求 /assets/locale/zh_CN/app-3396bd500e53f89d971d8c31ba7275f1c9ae2899062d4a7aeef14339084f44bd.js
,就是使用 gzip 的方式
若是用戶請求頭帶 Accept-Encoding: gzip
的話,workhorse 將讀取相應請求靜態資源的 gzip 文件(服務器預壓縮的靜態資源文件),並向瀏覽器傳送(並不是直接傳送,還得通過 nginx 服務器)壓縮過的內容,瀏覽器接收到服務器響應以後判斷內容是否被壓縮,若是被壓縮則進行解壓縮;固然若是用戶請求頭不指示使用 gzip ,那 workhorse 就會讀取源文件
// ${gitlab-workhorse根目錄}/internal/staticpages/servefile.go
// ...省略部分代碼
file := filepath.Join(s.DocumentRoot, prefix.Strip(r.URL.Path))
// ...省略部分代碼
// Serve pre-gzipped assets
if acceptEncoding := r.Header.Get("Accept-Encoding"); strings.Contains(acceptEncoding, "gzip") {
content, fi, err = helper.OpenFile(file + ".gz")
if err == nil {
w.Header().Set("Content-Encoding", "gzip")
}
}
複製代碼
從下圖感覺一下,壓縮後的 gz 文件比源文件的 1/3 還小,能夠說是大大節省服務器的網絡帶寬了
同時咱們也該注意到,當訪問靜態資源文件的時候,請求並無轉發到 Unicorn Web 服務器,而是 workhorse 親自處理了,這就是 workhorse 組件存在的最大意義,就是彌補 Unicorn Web 服務器存在的缺陷。這就得聯想一個名言了:
Any problem in computer science can be solved by another layer of indirection
計算機科學領域的任何問題均可以以增長一箇中間層來搞定,原來都是滿滿的套路啊
最後作個總結吧:workhorse 組件最初是爲了解決 git-over-http/https 超時的問題,或者換句話說,workhorse 組件解決的是 unicorn 服務器不擅長處理的請求,而諸如動態頁面渲染等請求將由 workhorse 幫忙代理至 unicorn 服務器處理,由於 unicorn 服務器擅長處理這類請求。至於最前端的 nginx 服務器則主要用於 https 配置等目的
參考連接