How We Halved Go Monorepo CI Build Time

Tyler French, Mindaugas Rukas, Xiaoyang Tan
15 min readintermediate
--
View Original

Overview

This article discusses how Uber engineers successfully halved the CI build time for their Go Monorepo by implementing various optimizations. Key strategies included improving the SubmitQueue, optimizing the Changed Targets Calculation (CTC), and transitioning to a dynamic CI system using Buildkite.

What You'll Learn

1

How to optimize CI build times using parallelization techniques

2

Why managing large changes in a CI/CD pipeline is critical for efficiency

3

How to implement a remote cache to improve build performance

Prerequisites & Requirements

  • Understanding of CI/CD concepts and practices
  • Familiarity with Bazel and Buildkite(optional)

Key Questions Answered

How did Uber reduce Go Monorepo CI build time?
Uber reduced CI build time by optimizing the SubmitQueue, implementing a Changed Targets Calculation (CTC) that identifies only the necessary targets to rebuild, and transitioning to a dynamic CI system with Buildkite that allows for parallel processing of builds.
What is the impact of large changes on CI pipelines?
Large changes can significantly slow down CI pipelines as they require validation of many dependent packages, leading to bottlenecks. Uber's solution involved blocking large changes during peak hours to maintain throughput for smaller changes.
What role does remote caching play in CI performance?
Remote caching allows builds to reuse previously built artifacts, reducing the need for redundant builds. This optimization was crucial for improving performance, especially in a large repository with many dependencies.
How does Uber manage dependencies in their CI process?
Uber uses a Changed Targets Calculation (CTC) to identify which targets need to be rebuilt based on changes. This method minimizes unnecessary builds and speeds up the CI process.

Key Statistics & Figures

Reduction in push time
65%
Optimizations in the SubmitQueue reduced the time taken to push changes to the main branch.
CI build time for large changes
up to several hours
Large changes can take significantly longer to validate due to the number of dependent packages.
Current code changes per hour
50
Uber engineers introduce around 50 code changes per hour to the Go Monorepo during working hours.
Time to validate changes affecting the entire repository
under 15 minutes
With the new optimizations, engineers can land significant changes quickly.

Technologies & Tools

Some links below are affiliate links. We may earn a commission if you make a purchase.

Build System
Bazel
Used for building and testing Go packages in the CI process.
CI/CD
Buildkite
Used to implement a dynamic CI system that allows for parallel processing of builds.

Key Actionable Insights

1
Implement a remote cache to avoid redundant builds and significantly improve CI performance.
By storing build artifacts in a remote cache, subsequent builds can quickly access these artifacts, reducing setup time and improving overall efficiency.
2
Optimize your CI pipeline by parallelizing independent tasks to reduce build times.
Identifying tasks that can run concurrently, such as dependency checks, can lead to substantial time savings in the CI process.
3
Monitor and manage large changes in your CI pipeline to prevent bottlenecks.
Establishing rules to block large changes during peak hours can help maintain a steady flow of smaller changes, ensuring that the pipeline remains efficient.

Common Pitfalls

1
Failing to manage large changes effectively can lead to significant delays in the CI pipeline.
When large changes are not properly managed, they can block other changes from being validated, causing a backlog and reducing overall productivity.
2
Not utilizing caching mechanisms can result in redundant builds and longer CI times.
Without a remote cache, builds may repeatedly compile the same artifacts, wasting time and resources.

Related Concepts

Continuous Integration
Continuous Deployment
Build Optimization Techniques