上一回介绍了 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 配置等目的
参考连接