💻🚀 目标人群:跨国团队里维护共用 Gradle 仓库、同时要扛 iOS / Android / 后端流水线的 CI 维护者。远程 Mac 节点上 Kotlin DSL 已普及,真正的抖动往往来自跨境解析慢、并行过高撑爆守护进程、远程缓存键设计粗糙。本文给出对照矩阵、可复制的 properties 与 settings 片段、超时重试阈值与lockfile 验收。延伸阅读 Homebrew/npm/CocoaPods 镜像、Git 与 CocoaPods 加速、Xcode 与 SPM 周边缓存;入口 首页、博客列表、定价、帮助中心均免登录。
跨境拉取瓶颈画像
1)解析风暴:dependencyResolutionManagement 未聚合时,子项目各自的 repositories 会把同一坐标打出多条 TLS 握手链。
2)内存剪刀差:org.gradle.workers.max 与 Kotlin 编译叠加,守护进程堆在十六吉字节 Runner上仍可能频繁 full GC。
3)缓存错觉:流水线命中了制品缓存目录却未命中远程构建缓存,通常是缓存键漏了 JDK 次版本或 Kotlin 插件次版本。
| 决策维度 | 保守落地 | 激进试探 |
|---|---|---|
| 仓库顺序 | 企业聚合源→地域镜像→官方源兜底 | 仅直连境外 central |
| 并行 | --parallel + workers 四至六 |
默认知核拉满且无异步磁盘 |
| 缓存策略 | wrapper 与 lock 入键,分区 osx-aarch64 | 全局单一键跨 JDK 混用 |
settings.gradle.kts 仓库镜像模板
使用 PREFER_SETTINGS 或 FAIL_ON_PROJECT_REPOS 强制单一解析入口;私服凭证走 CI 密钥,不写明文。
// settings.gradle.kts(示例:镜像链 + 模式)
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
maven { url = uri("https://nexus.corp.example/repository/maven-public/") }
maven { url = uri("https://maven.aliyun.com/repository/public") }
mavenCentral()
google()
}
}
若需插件管理,在同文件 pluginManagement.repositories 镜像我块保持同源顺序,避免插件与市场坐标分叉解析。
并行 worker 与守护进程内存峰值阈值
| gradle.properties 键 | 远程 Mac 起步建议 | 说明 |
|---|---|---|
| org.gradle.parallel | true | 配合 CLI --parallel;单模块收益有限属预期 |
| org.gradle.workers.max | 4(共享 Runner 2~3) | 先稳后升;观察守护进程 RSS 是否触顶 |
| org.gradle.jvmargs | -Xmx4g -XX:MaxMetaspaceSize=512m | Kotlin 与大模块并行时可酌增至六至八吉字节 |
| org.gradle.daemon | CI false(可选) | 短时 Job 关守护更易回收峰值内存 |
org.gradle.parallel=true
org.gradle.workers.max=4
org.gradle.jvmargs=-Xmx4g -XX:MaxMetaspaceSize=512m -Dfile.encoding=UTF-8
org.gradle.caching=true
远程缓存键命名与失效策略
可引用清单(写入 Runbook)
- 流水线缓存键片段:
gradle-wrapper.properties校验和 +libs.versions.toml或dependencies.lock校验和 + JDK 主版本 + osx-aarch64。 - 目录隔离:
export GRADLE_USER_HOME="$PWD/.gradle-job-$CI_JOB_ID",结束归档或删除,避免多 Job 污染 metadata。 - 失效触发:升级 Android Gradle Plugin 或 Kotlin 插件次版本后硬失效一层远程缓存分区。
- 磁盘水位:
caches/与build-cache-*合计超阈值先 prune 再构建。
Push/Pull 远程构建缓存时,确保令牌轮换与TLS 域名一致,避免误降级为纯本地缓存。
失败重试与 lockfile 一致性验收
把网络超时写进属性,把抖动留在壳层:systemProp.http.socketTimeout 与 systemProp.http.connectionTimeout 常用一百二十秒跨境起步。
systemProp.http.socketTimeout=120000
systemProp.http.connectionTimeout=120000
# 外层示例:二四八秒最多三轮
for i in 1 2 3; do
./gradlew assembleDebug --parallel --build-cache --no-daemon && break
sleep $((i==1?2:i==2?4:8))
done
lockfile 门禁(≥5 步)
- ① 提交版本目录或依赖锁;禁止在共享 Runner 上即兴 bump。
- ② 流水线打印
./gradlew --version与 AGP、Kotlin 插件坐标。 - ③ 对可疑坐标跑
dependencyInsight对照锁期望。 - ④ 变更依赖后首轮强制冷缓存并记录耗时基线。
- ⑤ 401 或 PKIX 类失败单独打点,不与普通超时混统计。
FAQ:401、证书钉扎、私服混用
仓库返回 401 但本地 IDE 正常?
CI 密钥往往缺读仓库范围或主机头与 settings URL 不一致;检查镜像是否在转发时剥离 Authorization。
证书钉扎或企业 CA 报错?
把根证书导入 Runner JDK trustStore 或使用 JAVA_TOOL_OPTIONS 追加 -Djavax.net.ssl.trustStore;禁用校验仅可作短时排障。
私服与 mavenCentral 混用坐标漂移?
开启 FAIL_ON_PROJECT_REPOS;镜像命中顺序写死;发现同 GAV 不同哈希立即冻结镜像快照并比对上游。