第3章 远程缓存搭建:HTTP 缓存服务器选型与 Docker 部署

3.1 为什么需要远程缓存?

在大型多模块 Gradle 项目中,本地缓存只能加速单机构建。团队协作或 CI/CD 流水线中,每次构建都需要重新下载外部依赖,重复缓存本地构建产物。远程缓存(Remote Build Cache)允许所有开发者及 CI 节点共享编译产物,显著缩短构建时间。核心原理是:Gradle 构建结束后将模块的输出(如 class 文件、jar 包)上传到 HTTP 缓存服务器,其他节点构建时先根据缓存 key 远程拉取,命中则跳过本地编译和测试。

选择适当的 HTTP 缓存服务器是搭建远程缓存的第一步。本章对比三种主流方案,并给出 Docker 部署与 HTTPS 配置的完整实现。

3.2 缓存服务器选型对比

特性Nginx + 文件系统JFrog ArtifactoryGradle Enterprise
成本开源免费企业版收费(有社区版但限制多)商业许可,价格较高
缓存协议支持纯 HTTP PUT/GET,需手动配置原生支持 Gradle Build Cache(REST API)深度集成 Gradle,内建缓存监控
存储后端本地磁盘 / NFS / S3(需额外配置)本地磁盘、S3、GCS 等本地磁盘 + 集群存储
HTTPS 配置快速,Nginx 原生支持需反向代理或自带 HTTPS(企业版)内置 HTTPS,支持 mTLS
管理与监控无自带 UI,依赖日志Web 平台,缓存分析、清理策略构建扫描、缓存命中率、加速效果展示
适用场景小团队、偏技术型、预算有限中型/大型团队,需要制品管理大型企业,端到端构建优化
选型建议:若团队人数少于 20 且希望零成本快速验证远程缓存效果,优先选择 Nginx。若已有 Artifactory 用于依赖管理,可直接复用其 Gradle 缓存支持。Gradle Enterprise 适合追求极致构建效率和可观测性的组织,但需要商业授权。

3.3 远程缓存架构总览

下图清晰展示了远程缓存系统的基本数据流。Gradle 客户端(本地或 CI)向缓存服务器发送 PUT(缓存存储)和 GET(缓存读取)请求,服务器根据缓存 key 返回文件或 404。缓存 key 由构建输入(源文件哈希、任务类型、JDK 版本等)计算得出。

远程缓存架构与数据传输流程 Gradle 客户端 (本地 / CI) HTTP 缓存服务器 (Nginx / Artifactory) 存储后端 磁盘 / S3 / NFS 缓存索引 (LRU / 过期策略) 关键操作说明 • PUT /cache/{key} – 上传构建缓存文件(HTTP body 二进制) • GET /cache/{key} – 下载缓存文件,响应 200 或 404

3.4 Docker 部署(以 Nginx 为例)

Nginx 作为缓存服务器最简单可靠,只需配置 HTTP PUT 和 GET 访问的静态目录作为缓存存储。以下提供完整的 Docker Compose 部署文件。

3.4.1 创建项目目录结构

mkdir -p ~/gradle-cache-nginx/{conf,cache,ssl}
cd ~/gradle-cache-nginx

3.4.2 编写 Nginx 配置文件

文件:conf/nginx.conf

worker_processes auto;
events { worker_connections 1024; }

http {
    access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log;

    server {
        listen 80;
        server_name cache.example.com;

        # 缓存根目录
        root /var/cache/nginx;

        # 允许 HTTP PUT 上传
        location ~ ^/cache/(.+)$ {
            # 缓存 key 校验:只允许特定哈希格式
            if ($request_method = PUT) {
                client_body_in_file_only clean;
                client_body_buffer_size 16k;
                client_max_body_size 1000m;
                dav_methods PUT;
                create_full_put_path on;
                dav_access user:rw group:rw all:r;
                break;
            }
            if ($request_method = GET) {
                try_files /var/cache/nginx/$1 =404;
                break;
            }
        }

        # 健康检查
        location /health {
            return 200 "OK\n";
        }
    }
}

3.4.3 生成 docker-compose.yml

version: '3.8'
services:
  cache:
    image: nginx:1.26-alpine
    container_name: gradle-cache
    volumes:
      - ./conf/nginx.conf:/etc/nginx/nginx.conf:ro
      - ./cache:/var/cache/nginx
      - ./ssl:/etc/nginx/ssl:ro
    ports:
      - "80:80"
      - "443:443"
    restart: unless-stopped

3.4.4 启动容器

docker compose up -d
验证部署:执行 curl -X PUT --data-binary @test.jar http://localhost:80/cache/mykey,然后 curl -O http://localhost:80/cache/mykey 应能成功下载相同的文件。

3.5 HTTPS 配置

生产环境必须启用 HTTPS 以保证传输安全。Gradle 默认对远程缓存服务器进行 TLS 校验。下面以自签名证书为例演示,生产环境应使用受信任 CA。

3.5.1 生成自签名证书(仅用于演示)

cd ~/gradle-cache-nginx/ssl
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout cache.key -out cache.crt \
  -subj "/CN=cache.example.com"

3.5.2 修改 Nginx 配置,启用 HTTPS

在 conf/nginx.conf 中添加 server 块:

server {
    listen 443 ssl http2;
    server_name cache.example.com;

    ssl_certificate /etc/nginx/ssl/cache.crt;
    ssl_certificate_key /etc/nginx/ssl/cache.key;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;

    # 复用之前的缓存 location 配置
    location ~ ^/cache/(.+)$ {
        if ($request_method = PUT) {
            client_body_in_file_only clean;
            client_body_buffer_size 16k;
            client_max_body_size 1000m;
            dav_methods PUT;
            create_full_put_path on;
            dav_access user:rw group:rw all:r;
            break;
        }
        if ($request_method = GET) {
            try_files /var/cache/nginx/$1 =404;
            break;
        }
    }
    location /health { return 200 "OK\n"; }
}

3.5.3 重启 Nginx 容器

docker compose restart

3.5.4 客户端 Gradle 端配置

在 gradle.properties 或 build.gradle 中启用远程缓存:

# gradle.properties
org.gradle.caching=true
org.gradle.caching.http.url=https://cache.example.com/cache/

如果使用自签名证书,还需要将证书导入 Gradle 的信任库:

keytool -import -trustcacerts -keystore $JAVA_HOME/lib/security/cacerts \
  -storepass changeit -alias gradle-cache -file ssl/cache.crt

3.6 调试与常见错误

3.6.1 调试命令

  • 查看缓存服务器日志:docker compose logs -f cache
  • 测试 PUT:curl -k -X PUT --data-binary @dummy.jar https://localhost:443/cache/abc123
  • 测试 GET:curl -k -o /dev/null https://localhost:443/cache/abc123 -w "%{http_code}"
  • 检查 Nginx 访问日志:docker exec -it gradle-cache cat /var/log/nginx/access.log

3.6.2 常见错误及解决方案

错误现象可能原因解决方法
Gradle 报 Cannot resolve cache key: 403 ForbiddenNginx 的 dav_methods 未正确启用确认 location 块中写入了 dav_methods PUT,且目录权限可写
HTTPS 连接被拒绝证书 / 端口映射未生效检查 docker-compose.yml 的 ports 是否包含 443:443;证书路径是否正确
缓存文件上传后下载为 404文件存储路径与 try_files 路径不一致确保 client_body_in_file_only 写入的路径与 try_files 路径一致
Gradle 构建速度没有提升缓存未命中或 key 不匹配确认构建输入一致(JDK 版本、任务配置、源文件哈希)

3.7 性能优化与运维建议

  • 缓存清理策略:Nginx 自带 proxy_cache_path 但没有原生的 LRU 清理。建议编写 cron 脚本定期删除超过 N 天的文件:find /var/cache/nginx -type f -mtime +30 -delete。
  • 高并发:调整 worker_processes auto 和 worker_connections 2048,启用 sendfile 和 tcp_nopush。
  • 后端存储:若缓存量大,将 /var/cache/nginx 挂载到 SSD 或 NFS;切勿使用跨地域的远程文件系统。
  • 监控:通过 /health 端点配合 Prometheus + Grafana 监控。
  • 测试环境:先用 curl -s -w "@%{http_code}" -o /dev/null 测试每秒请求量,确保满足团队 CI 峰值。

3.8 小结