GitLab系列2 GitLab Workhorse

GitLab Workhorse

上一回介紹了 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

1. Nginx 入口

從架構圖能夠看出,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;
  }
}
複製代碼

2. GitLab-workhorse

那麼 GitLab-workhorse 是什麼呢?官方解釋稱它是 GitLab 的智能反向代理服務器,用於處理負載量較大的 HTTP 請求,諸如文件上傳/下載、Git push/pull 以及 Git 歸檔下載等。而實際上可能比較複雜瀏覽器

+-------+  +------------------+  +---------+
|       |  |                  |  |         |
| NGINX +->| gitlab-workhorse +->| Unicorn |
|       |  |                  |  |         |
+-------+  +------------------+  +---------+
複製代碼

下述的 Rails 組件是運行在 Unicorn Web 服務器的:安全

  1. workhorse 能處理一些無需調用 Rails 組件的請求,例如靜態的 js/css 資源文件


  2. workhorse 能修改 Rails 組件發來的響應。例如:假設你的 Rails 組件使用 send_file ,那麼 gitlab-workhorse 將會打開磁盤中的文件而後把文件內容做爲響應體返回給客戶端
  3. workhorse 能接管向 Rails 組件詢問操做權限後的請求,例如 處理 git clone 以前得確認當前客戶的權限,在向 Rails 組件詢問確認後 workhorse 將繼續接管 git clone 的請求


  4. workhorse 能修改發送給 Rails 組件以前的請求信息。例如:當處理 Git LFS 上傳時,workhorse 首先向 Rails 組件詢問當前用戶是否有執行權限,而後它將請求體儲存在一個臨時文件裏,接着它將修改事後的包含此臨時文件路徑的請求體發送給 Rails 組件
  5. workhorse 能管理與 Rails 組件通訊的長時間存活的 websocket 鏈接


  6. workhorse 沒法直接鏈接數據庫,只能與 Rails 組件和 Redis 組件(可選)通訊
  7. 全部到達 workhorse 的請求都是由上游代理服務器(nginx)轉發而來
  8. workhorse 不接受 https 鏈接
  9. workhorse 不會清除空閒客戶端鏈接
  10. 全部對 Rails 組件的請求都得通過 workhorse

好比 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 配置等目的

附錄

參考連接

GitLab Workhorse 官方倉庫

相關文章
相關標籤/搜索