好邻居:如何减少 Gradle 构建对 Maven Central 的流量
引言
Maven Central 是 Java、Kotlin 和其他 JVM 社区的重要资源。它提供了最流行的开源库、开发工具、文档和其他构件的仓库。该服务不仅被开发人员大量使用,也被 CI/CD 流水线和自动化工具大量使用。
虽然使用 Maven Central 的缓存代理是最佳实践,但并非所有人都这样做。这不仅会导致过高的流量成本和构建延迟,还会使您的构建和流水线由于保护 Maven Central 的限流机制而面临更多的减速和失败。
正如 Sonatype 首席技术官 Brian Fox 在 2024 年 6 月的这篇博客文章中写道:“Maven Central 总带宽的 83% 被仅占 1% 的 IP 地址消耗。此外,其中许多 IP 来自一些世界上最大的公司……我们将开始与我们的提供商合作,实施针对极端重度消费者的限流机制,这些消费者实际上正在滥用社区资源。”随着这项工作的进展,更多的组织将面临限流,包括那些使用 Gradle 的组织,特别是如果他们严重依赖 Maven Central 而没有启用缓存代理的话。
虽然 Gradle 目前没有内置 Maven 的 mirrorOf
功能来将所有依赖解析路由到缓存代理,但组织可以部署一个具有相同效果且与现有 Gradle 版本兼容的配置。这得益于 Gradle 的灵活性和丰富的编程模型。
ℹ️ Gradle 插件门户呢? |
---|
在这篇博文中,我们展示的配置更改也影响了 Gradle 插件门户在解析插件依赖方面的使用。这也是 Gradle Inc. 免费提供的社区资源,就像 Maven Central 一样,它需要管理其工作负载和带宽使用。请注意,插件门户还对构件解析使用速率限制,以应对日益增长的负载。 |
使用内部构件仓库 #
对于希望管理构件并降低网络流量成本的组织来说,拥有一个 Maven Central 的缓存 Maven 仓库代理是标准做法。不同的供应商或开源组织提供了此类仓库的多种实现,其中大多数都与 Maven Central 兼容。
配置 Gradle 项目以使用组织仓库而非 Maven Central #
在 Gradle 中,您必须显式定义一个或多个仓库来解析依赖。为此,请在您的 settings 脚本中声明适当的仓库
// in settings.gradle.kts
pluginManagement {
repositories {
// Replace Gradle's default for plugin resolution by internal repository
maven {
url = uri("https://company/com/proxy-repository")
}
}
}
plugins {
// Declare settings plugins here
}
dependencyResolutionManagement {
// Make sure projects do not add other repositories by accident
repositoriesMode = RepositoriesMode.FAIL_ON_PROJECT_REPOS
// Define the internal repository as the only repository to use
repositories {
maven {
url = uri("https://company/com/proxy-repository")
}
}
}
// Other settings content
在上面的示例中,将 URL 替换为您的组织的仓库位置。此片段是一种定义内部项目仓库的自定方式,它利用了集中式仓库声明功能。使用上述配置的项目将不会向 Maven Central 发送请求,尽管组织仓库本身可能需要这样做来缓存资源。
此声明与 Gradle 6.8 及更高版本兼容。有关仓库声明语法和要求的更多信息,请参阅 Gradle 文档。
覆盖 Maven Central 和插件门户仓库的 URL #
修改构建文件并非总是可行。例如,在您自己的基础设施中构建开源项目时,您可能希望全局覆盖构建中定义的仓库配置。
这是一个 init 脚本,它将替换所有使用 Maven Central 和 Gradle 插件门户的项目的 URL
// init.gradle.kts
apply<InternalRepositoryPlugin>()
class InternalRepositoryPlugin : Plugin<Gradle> {
override fun apply(gradle: Gradle) {
val canBeMirrored: Spec<MavenArtifactRepository> =
Spec { r -> r.getName().equals(ArtifactRepositoryContainer.DEFAULT_MAVEN_CENTRAL_REPO_NAME)
|| r.getName().equals("Gradle Central Plugin Repository") }
val useMirror: Action<MavenArtifactRepository> = Action {
val mirrorUrl: String = "https://company/com/proxy-repository"
setUrl(mirrorUrl)
}
val configureMirror: Action<RepositoryHandler> = Action {
withType(MavenArtifactRepository::class.java)
.matching(canBeMirrored)
.configureEach(useMirror)
}
gradle.beforeSettings(Action {
configureMirror.execute(getBuildscript().getRepositories())
configureMirror.execute(getPluginManagement().getRepositories())
})
// Remove the settingsEvaluated part if you are using Gradle <6.8
gradle.settingsEvaluated(Action {
configureMirror.execute(getDependencyResolutionManagement().getRepositories())
})
gradle.beforeProject(Action {
configureMirror.execute(getBuildscript().getRepositories())
})
gradle.afterProject(Action {
configureMirror.execute(getRepositories())
})
}
}
在上面的示例中,将 mirrorUrl
替换为您的内部仓库的 URL。部署此 init 脚本有多种选项;请参阅 Gradle 文档了解选项。
上述 init 脚本完全兼容 Gradle 6.8 及更高版本。对于 Gradle 6.0 到 6.7(包括),需要删除 gradle.settingsEvaluated
部分。不支持更低的版本。
支持更简单的镜像 #
上面的示例演示了 Gradle 的灵活性和编程模型如何解决构建挑战,即使没有开箱即用的功能。代码并不简单,因为 Gradle 区分了插件和项目仓库,并且有集中和本地的方式来声明这两种仓库。
诚然,解决镜像用例可以更容易。目前,Gradle 不支持定义仓库镜像,类似于 Apache Maven 对镜像的支持。我们正在关注 gradle/gradle #27808 中的一个开放功能请求。首先,我们计划改进关于如何从构建外部注入仓库配置的文档。我们还将根据社区对本文和即将到来的文档更新的反应,评估是否需要一个核心功能。
故障排除 #
要解决依赖解析和缓存问题,您可以使用我们免费的 Build Scan 服务。Build Scan 分析构建的有效依赖以及构件解析和下载的性能。
每个依赖项都指示它是从哪个 URL 解析的
您可以获取构建中所有网络流量的全局视图
要了解有关启用 Build Scan 的更多信息,请参阅 Gradle 文档。
总结 #
减少流向 Maven Central 的流量不仅仅是为了提高构建性能;它还关乎构建弹性、高效和可持续的开发流水线。无论您是从事开源项目还是管理企业级构建,使用构件仓库都可以显著减少冗余下载,最大限度地降低限流风险,并节省网络成本。
虽然并非每个项目都能采用所有解决方案,但即使是小的改进也能产生有意义的影响。随着公共基础设施(如 Maven Central)面临的压力越来越大,社区遵循最佳实践并减少不必要的负载变得越来越重要。
如果您尚未这样做,请考虑审查您组织的当前依赖解析设置,如果您受到 Gradle 中缺乏仓库镜像的影响,请在 Gradle issue #27808 中表达您的意见。
另请参阅 #
- 如有任何反馈,请访问 Gradle Community Slack 上的
#maven-central
频道。 - 如果您在排除下载故障方面需要帮助,我们有相同的 Community Slack 工作区中的
#community-support
频道 - 如果您是 Gradle, Inc. 客户,请使用官方支持渠道以获得更快的响应。
- Build Scan 文档
- Gradle Cookbook - 发布到 Maven Central
- Maven Central 与公地悲剧 - Brian Fox 于 2024 年发表在 Sonatype 博客上的文章
- 免费并非免费:开源基础设施中工具决策的隐藏成本 - Brian Fox 于 2025 年发表在 Sonatype 博客上的文章