cortexproject / cortex

A horizontally scalable, highly available, multi-tenant, long term Prometheus.
https://cortexmetrics.io/
Apache License 2.0
5.47k stars 797 forks source link

MAXPROCS and CPU limits #902

Closed gouthamve closed 11 months ago

gouthamve commented 6 years ago

I've read somewhere that Go's GC that normally uses 25% of the GOMAXPROCS threads. Now which means if we run containers on a 32-core machine, and have CPULimit of 2cores, Go might use up all CPU for GC itself!

And in the case compute intensive workloads, it makes sense to explore setting the number of GOMAXPROCS to the cpu limits which can be done automatically using: https://github.com/uber-go/automaxprocs

bboreham commented 6 years ago

I'd like a citation for that GC claim. What I've read is that the GC continuously paces itself to aim for a certain budget.

~Note that cgroups CPU limits aren't hard limits, but adjust the priorities when multiple tasks are competing for all available CPU. If you have free CPU a process can go above its cgroup limit. Therefore GOMAXPROCS is a much harder limit than the cgroup limit.~ see later

I find automaxprocs interesting, but I think I would start by simply setting GOMAXPROCS.

cboggs commented 6 years ago

To use the Kubernetes parlance, I think what you say @bboreham is true for requests, but not for limits. Limits are indeed a hard cap on number of periods allowed to be used per second per core as enforced by the Linux CFS. So in the case of a proper limit, if the GC does indeed use the host's core count to determine its budget, it could definitely max out what CPU quota its been granted and not get any work done.

That said, I don't pretend at being a GC expert (or even a novice, yet), so I can't speak to the accuracy of that bit. :-)

bboreham commented 6 years ago

Limits are indeed a hard cap on number of periods allowed to be used per second per core as enforced by the Linux CFS.

I'm going to have to call "citation required" on that one.

I'm looking at, for instance: https://github.com/kubernetes/kubernetes/blob/master/pkg/kubelet/cm/node_container_manager.go#L159 , where CpuShares is set. To get closer to what you said, it should be setting CpuQuota.

There is also a beta feature which uses CPU sets, which would perhaps obviate this discussion: https://kubernetes.io/docs/tasks/administer-cluster/cpu-management-policies

bboreham commented 6 years ago

Update: following some Slack discussion, I was pointed at https://github.com/kubernetes/kubernetes/blob/master/pkg/kubelet/kuberuntime/kuberuntime_container_linux.go#L68 (the bool option cpuCFSQuota defaults on)

So you're right, it is a hard cap.

embano1 commented 5 years ago

Not sure if this is a stale discussion here (issue still open). Regarding GC and CPU quota (limits) in containerized deployments: Monzo hit that issue really hard (with Go GC in an older version, might still persist because it's not so much about the GC, rather the OS/kernel), which led them and other Kubernetes users to disable CPU quotas globally (per node/Kubelet). All details and references in this comment: https://github.com/uber-go/automaxprocs/issues/12

Hope it's still useful.

bboreham commented 5 years ago

Thanks for the pointer. I would say this issue is still open because we don't have a lot of evidence either way. For the Cortex installation I look after, we don't set any CPU limits and adjust requests so that machines are not avoid 90% CPU utilisation, so I don't expect we hit the issue.

bboreham commented 5 years ago

Well now. I tried setting GOMAXPROCS on our distributors, and saw a 15% reduction in CPU usage. We run on 16-core machines, and the distributors typically take 2-4 cores each with compression on which generates a lot of garbage. Same load same latency.

So colour me stunned.

stale[bot] commented 4 years ago

This issue has been automatically marked as stale because it has not had any activity in the past 30 days. It will be closed in 7 days if no further activity occurs. Thank you for your contributions.

friedrichg commented 1 year ago

Using GOMAXPROCS is the known method that still works till today in cortex. But it's certainly another hassle for operators to keep updating their GOMAXPROCS whenever cpu resources are changed, leave alone advanced automatic resource allocation...

Use automaxprocs as first suggested seems like the best way forward (Which falls back to GOMAXPROCS if configured).

stale[bot] commented 1 year ago

This issue has been automatically marked as stale because it has not had any activity in the past 60 days. It will be closed in 15 days if no further activity occurs. Thank you for your contributions.

friedrichg commented 11 months ago

Turns out it is possible today to configure GOMAXPROCS and GOMEMLIMITS appropiately in kubernetes downward API https://github.com/cortexproject/cortex-jsonnet/commit/524c3b3401fbe6efdb34339772cff63c05eeee03

This is no longer needed