CPU throttling#
By default, the Go runtime sets GOMAXPROCS, which controls how many operating
system threads can concurrently execute Go code. The value is based on the
number of logical CPUs that are available on the physical node and does not account
for CPU limits that are defined for a container or Pod.
Whenever you configure CPU limits for MSR 4 containers or Pods, the Go scheduler is able to assume more CPU capacity than the container is permitted to use. As a result, the application might create more runnable threads than the assigned CPU quota can sustain. Thereafter, when these threads compete for CPU time, the container can repeatedly reach the Linux Completely Fair Scheduler (CFS) quota and become throttled.
For more information, refer to Go's official blog post on Container-aware GOMAXPROCS.
Symptoms#
CPU throttling can cause the following negative behaviors:
- Increased latency in API responses or UI interactions.
- Containers or Pods become slower or unresponsive despite low memory usage.
- CPU usage consistently reaches or slightly exceeds the configured limit.
For example, if the registry Pod is configured with a CPU limit of 1 core (1000m), resource metrics may show the Pod repeatedly reaching that limit:
$ kubectl top pods
NAME CPU(cores) MEMORY(bytes)
msr4-harbor-core-5f5859c7cb-dn8p8 300m 135Mi
msr4-harbor-database-0 7m 180Mi
msr4-harbor-jobservice-7dbcfc66f5-59fvp 2m 21Mi
msr4-harbor-nginx-67c568fdd4-sg9tb 1m 33Mi
msr4-harbor-portal-5469889b75-wkmmr 1m 12Mi
msr4-harbor-redis-0 4m 23Mi
msr4-harbor-registry-7558fbf44f-gprhf 1002m 141Mi <-- Reaching limit
msr4-harbor-trivy-0 1m 12Mi
Workaround#
Configure GOMAXPROCS to align with the container's CPU limit
instead of the total CPU count of the host.
This ensures that the Go scheduler does not oversubscribe CPU resources.
Set the GOMAXPROCS environment variable dynamically based on the
limits.cpu value allocated to the Pod.
The following examples both apply to a 1 CPU (1000m) limit.
Configure the value in the MSR 4 values.yaml file or by using the Helm CLI:
extraEnvVars:
- name: GOMAXPROCS
valueFrom:
resourceFieldRef:
resource: limits.cpu
divisor: "1"
Configure the value in the harbor.yml file:
version: '3.8'
services:
registry:
deploy:
resources:
limits:
cpus: '1.0'
environment:
- GOMAXPROCS=1