【声明】本博客所有内容均为个人业余时间创作,所述技术案例均来自公开开源项目(如Github,Apache基金会),不涉及任何企业机密或未公开技术,如有侵权请联系删除
背景
上篇 blog
【Ubuntu】【Gitlab】拉出内网 Web 服务:Gitlab 配置审视(一)
分析了自定义的 Nginx 配置项,会绕过 GitLab 默认的架构:Workhorse + Puma ,下面继续
Nginx 配置审视
关于 WorkHorse ,可参考官方描述 GitLab Architecture Overview -- Workhorse

OK,下面来看下 WorkHorse 和 Puma 配合的例子

比如用户上传一个 1GB 的大文件
- 首先是流量路径:用户 → Nginx → Gitlab-Workhorse
- Workhorse 接收整个文件,保存到磁盘
- Workhorse 调用 Puma API,通知 Puma 文件已存好,路径是
/tmp/xxx,可以创建数据库记录 - Puma 只需要执行轻量级数据库操作,不用处理大文件
- 响应返回用户
从流程上可以看到,这样 Puma 的线程不会被大文件上传给卡住(由 Workhorse 进行处理),系统更稳定,并发能力更高
Nginx,Workhorse,Puma 具体的协作流程图如下

- 首先,客户端通过 HTTP(S) 访问 Web 服务器,比如
http://192.168.1.100(以局域网 ip 为例) - Nginx 监听
80/443端口(后面分析),端口配置由 Gitlab 管理,可以通过gitlab.rb文件配置 - Nginx 通过 Socket 协议(套接字在
/var/opt/gitlab/gitlab-workhorse/sockets/socket)将访问信息传递给 Gitlab-Workhorse(Go 服务),终端输入
bash
sudo lsof /var/opt/gitlab/gitlab-workhorse/sockets/socket
可查看打开该套接字的进程(Linux 中一切皆文件,套接字在操作系统眼里也是一个文件)

- 如果是
/assets,/uploads,git 操作,或者大文件等,Gitlab-Workhorse 自己就能处理,等处理好了再通知 Puma - 如果是普通页面,或者 Api,比如
/dashboard,/api/v4/projects等,则 Gitlab-Workhorse 再通过 Socket 套接字(位置在/var/opt/gitlab/gitlab-rails/sockets/gitlab.socket)通知 Puma 进行处理,终端输入
bash
sudo lsof /var/opt/gitlab/gitlab-rails/sockets/gitlab.socket
可以查看监听 Gitlab-WorkHorse 套接字的 Puma 进程如下

可以看到,监听 Gitlab-Workhorse 套接字的 Puma 进程,足足有 14 个(CPU 核心为 16),Puma 需要多个进程是因为 Ruby 应用本身是 CPU/IO 密集型任务 ,会默认将进程数量开到接近 CPU 核心数量 ,这里少了两个,是预留系统资源,留给系统或其他服务,不占满所有核心,避免系统卡顿

另外,上面可以看到,GitLab-Workhorse 只有一个进程监听 Nginx 的套接字,这里首先 Gitlab-Workhorse 使用 Go 语言写的,设计目标就是轻量,高效,并利用 Go 协程实现高并发 ,通过 goroutine(协程),Gitlab-workhorse 一个进程就能处理成千上万的并发连接 ,而不需要 fork 多个进程来提升并发能力(不像 Ruby/Python 等传统模型)

OK,从这里可以看出,Workhorse 是 Puma 的守门人和助手,只把真正需要业务逻辑的请求交给 Puma
OK,本篇先到这里,如有疑问,欢迎评论区留言讨论,祝各位功力大涨,技术更上一层楼!!!更多内容见下篇 blog
【Ubuntu】【Gitlab】拉出内网 Web 服务:Gitlab 配置审视(三)