honor requests_max based on cgroup_limits if configured (#13673)

container limits would not be properly honored in
our current implementation, mem.VirtualMemory()
function only reads /proc/meminfo which points to
the host system information inside the container.
This commit is contained in:
Harshavardhana 2021-11-17 09:55:45 -08:00 committed by GitHub
parent 8378bc9958
commit 5b68f8ea6a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -18,7 +18,10 @@
package cmd package cmd
import ( import (
"io/ioutil"
"net/http" "net/http"
"runtime"
"strconv"
"sync" "sync"
"time" "time"
@ -48,6 +51,46 @@ type apiConfig struct {
deleteCleanupInterval time.Duration deleteCleanupInterval time.Duration
} }
const cgroupLimitFile = "/sys/fs/cgroup/memory/memory.limit_in_bytes"
func cgroupLimit(limitFile string) (limit uint64) {
buf, err := ioutil.ReadFile(limitFile)
if err != nil {
return 9223372036854771712
}
limit, err = strconv.ParseUint(string(buf), 10, 64)
if err != nil {
return 9223372036854771712
}
return limit
}
func availableMemory() (available uint64) {
available = 8 << 30 // Default to 8 GiB when we can't find the limits.
if runtime.GOOS == "linux" {
available = cgroupLimit(cgroupLimitFile)
// No limit set, It's the highest positive signed 64-bit
// integer (2^63-1), rounded down to multiples of 4096 (2^12),
// the most common page size on x86 systems - for cgroup_limits.
if available != 9223372036854771712 {
// This means cgroup memory limit is configured.
return
} // no-limit set proceed to set the limits based on virtual memory.
} // for all other platforms limits are based on virtual memory.
memStats, err := mem.VirtualMemory()
if err != nil {
return
}
available = memStats.Available / 2
return
}
func (t *apiConfig) init(cfg api.Config, setDriveCounts []int) { func (t *apiConfig) init(cfg api.Config, setDriveCounts []int) {
t.mu.Lock() t.mu.Lock()
defer t.mu.Unlock() defer t.mu.Unlock()
@ -64,14 +107,7 @@ func (t *apiConfig) init(cfg api.Config, setDriveCounts []int) {
var apiRequestsMaxPerNode int var apiRequestsMaxPerNode int
if cfg.RequestsMax <= 0 { if cfg.RequestsMax <= 0 {
var maxMem uint64 maxMem := availableMemory()
memStats, err := mem.VirtualMemory()
if err != nil {
// Default to 8 GiB, not critical.
maxMem = 8 << 30
} else {
maxMem = memStats.Available / 2
}
// max requests per node is calculated as // max requests per node is calculated as
// total_ram / ram_per_request // total_ram / ram_per_request