From 8d090a20cef92dbf8389e63807c7e5b8e663b256 Mon Sep 17 00:00:00 2001 From: Harshavardhana Date: Sat, 30 Jul 2016 08:50:49 -0700 Subject: [PATCH] server: set globalCacheSize honoring system limits for max memory. (#2332) On unix systems it is possible to set max memory used by running processes using 'ulimit -m' or 'syscall.RLIMIT_AS'. A process whence exceeds this limit, kernel would pro-actively kill such a server with OOM. To avoid this problem of defaulting our cache size to 8GB we should look for if the current system limits are lower and set the cache size appropriately. --- server-main.go | 5 +++++ server-rlimit-nix.go | 33 ++++++++++++++++++++++++++++++++- server-rlimit-win.go | 5 +++++ 3 files changed, 42 insertions(+), 1 deletion(-) diff --git a/server-main.go b/server-main.go index 1321088fa..60c6028d3 100644 --- a/server-main.go +++ b/server-main.go @@ -203,6 +203,11 @@ func initServerConfig(c *cli.Context) { // Set maxOpenFiles, This is necessary since default operating // system limits of 1024, 2048 are not enough for Minio server. setMaxOpenFiles() + // Set maxMemory, This is necessary since default operating + // system limits might be changed and we need to make sure we + // do not crash the server so the set the maxCacheSize appropriately. + setMaxMemory() + // Do not fail if this is not allowed, lower limits are fine as well. } diff --git a/server-rlimit-nix.go b/server-rlimit-nix.go index a70ad7074..549e39b12 100644 --- a/server-rlimit-nix.go +++ b/server-rlimit-nix.go @@ -30,7 +30,7 @@ func setMaxOpenFiles() error { return err } // Set the current limit to Max, it is usually around 4096. - // TO increate this limit further user has to manually edit + // TO increase this limit further user has to manually edit // `/etc/security/limits.conf` rLimit.Cur = rLimit.Max err = syscall.Setrlimit(syscall.RLIMIT_NOFILE, &rLimit) @@ -43,3 +43,34 @@ func setMaxOpenFiles() error { } return nil } + +// Set max memory used by minio as a process, this value is usually +// set to 'unlimited' but we need to validate additionally to verify +// if any hard limit is set by the user, in such a scenario would need +// to reset the global max cache size to be 80% of the hardlimit set +// by the user. This is done to honor the system limits and not crash. +func setMaxMemory() error { + var rLimit syscall.Rlimit + err := syscall.Getrlimit(syscall.RLIMIT_AS, &rLimit) + if err != nil { + return err + } + // Set the current limit to Max, it is default 'unlimited'. + // TO decrease this limit further user has to manually edit + // `/etc/security/limits.conf` + rLimit.Cur = rLimit.Max + err = syscall.Setrlimit(syscall.RLIMIT_AS, &rLimit) + if err != nil { + return err + } + err = syscall.Getrlimit(syscall.RLIMIT_AS, &rLimit) + if err != nil { + return err + } + // Validate if rlimit memory is set to lower + // than max cache size. Then we should use such value. + if rLimit.Cur < globalMaxCacheSize { + globalMaxCacheSize = (80 / 100) * rLimit.Cur + } + return nil +} diff --git a/server-rlimit-win.go b/server-rlimit-win.go index 39398be62..9cc676709 100644 --- a/server-rlimit-win.go +++ b/server-rlimit-win.go @@ -24,3 +24,8 @@ func setMaxOpenFiles() error { // (well, you do but it is based on your resources like memory). return nil } + +func setMaxMemory() error { + // TODO: explore if Win32 API's provide anything special here. + return nil +}