You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by as...@apache.org on 2020/01/24 17:09:08 UTC

[camel-k] 07/07: feat(JVM): Max heap size heuristic based on container memory limit

This is an automated email from the ASF dual-hosted git repository.

astefanutti pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/camel-k.git

commit 22fe7285a8adb24159a970a9e0d57da78bb84813
Author: Antonin Stefanutti <an...@stefanutti.fr>
AuthorDate: Fri Jan 24 16:31:16 2020 +0100

    feat(JVM): Max heap size heuristic based on container memory limit
---
 go.mod           |  1 +
 pkg/trait/jvm.go | 26 ++++++++++++++++++++++++++
 2 files changed, 27 insertions(+)

diff --git a/go.mod b/go.mod
index ac7aa1e..07f35d9 100644
--- a/go.mod
+++ b/go.mod
@@ -32,6 +32,7 @@ require (
 	github.com/stoewer/go-strcase v1.0.2
 	github.com/stretchr/testify v1.4.0
 	go.uber.org/multierr v1.1.0
+	gopkg.in/inf.v0 v0.9.1
 	gopkg.in/yaml.v2 v2.2.4
 	k8s.io/api v0.0.0
 	k8s.io/apimachinery v0.0.0
diff --git a/pkg/trait/jvm.go b/pkg/trait/jvm.go
index b1a783b..89f3710 100644
--- a/pkg/trait/jvm.go
+++ b/pkg/trait/jvm.go
@@ -22,9 +22,14 @@ import (
 	"sort"
 	"strings"
 
+	"gopkg.in/inf.v0"
+
 	"github.com/pkg/errors"
 	"github.com/scylladb/go-set/strset"
 
+	corev1 "k8s.io/api/core/v1"
+	"k8s.io/apimachinery/pkg/api/resource"
+
 	k8sclient "sigs.k8s.io/controller-runtime/pkg/client"
 
 	v1 "github.com/apache/camel-k/pkg/apis/camel/v1"
@@ -125,11 +130,32 @@ func (t *jvmTrait) Apply(e *Environment) error {
 					suspend, t.DebugAddress))
 		}
 
+		hasHeapSizeOption := false
 		// Add JVM options
 		if t.Options != nil {
+			hasHeapSizeOption = strings.Contains(*t.Options, "-Xmx") ||
+				strings.Contains(*t.Options, "-XX:MaxHeapSize") ||
+				strings.Contains(*t.Options, "-XX:MinRAMPercentage") ||
+				strings.Contains(*t.Options, "-XX:MaxRAMPercentage")
+
 			container.Args = append(container.Args, strings.Split(*t.Options, ",")...)
 		}
 
+		// Tune JVM maximum heap size based on the container memory limit, if any.
+		// This is configured off-container, thus is limited to explicit user configuration.
+		// We may want to inject a wrapper script into the container image, so that it can
+		// be performed in-container, based on CGroups memory resource control files.
+		if memory, hasLimit := container.Resources.Limits[corev1.ResourceMemory]; !hasHeapSizeOption && hasLimit {
+			// Simple heuristic that caps the maximum heap size to 50% of the memory limit
+			percentage := int64(50)
+			// Unless the memory limit is lower than 300M, in which case we leave more room for the non-heap memory
+			if resource.NewScaledQuantity(300, 6).Cmp(memory) > 0 {
+				percentage = 25
+			}
+			memory.AsDec().Mul(memory.AsDec(), inf.NewDec(percentage, 2))
+			container.Args = append(container.Args, fmt.Sprintf("-Xmx%dM", memory.ScaledValue(resource.Mega)))
+		}
+
 		// Add mounted resources to the class path
 		for _, m := range container.VolumeMounts {
 			classpath.Add(m.MountPath)