├── README.md ├── dist ├── README.txt └── app.jar ├── images └── elastic-duke-70x70.png ├── kubernetes ├── README.md ├── dashboards │ ├── java-dashboard-cpu.json │ └── java-dashboard-mem.json ├── deployments │ ├── adoptopenjdk.yaml │ ├── deployment.yaml │ ├── dragonwell.yaml │ ├── libericajdk12.yaml │ ├── openj9.yaml │ ├── openjdk13.yaml │ └── zing.yaml ├── images │ └── kube.png ├── java-dashboard-cpu.json ├── java-dashboard-mem.json ├── manifests │ ├── actions.jps │ ├── manifest-k8s-dragonwell-g1.yaml │ ├── manifest-k8s-openj9.yaml │ ├── manifest-k8s-zgc.yaml │ └── manifest-k8s-zing.yaml └── scripts │ ├── grafana.sh │ ├── label-nodes.sh │ └── labelnodes.sh ├── manifest-k8s.yaml ├── manifest.yml └── src └── com └── jelastic └── verticalscaling ├── Load.java ├── MemoryUsage.java └── Test.java /README.md: -------------------------------------------------------------------------------- 1 | # Java Vertical Scaling Load Test 2 | A simple app for testing JVM vertical scaling 3 | 4 | 5 | ``` java [$JAVA_OPTS] -jar app.jar [sleep] ``` 6 | 7 | * $JAVA_OPTS - JVM start options, for example -Xmx2g -Xms32m -XX:+UseG1GC 8 | * sleep - interval between memory load cycles in milliseconds, default is 10ms 9 | 10 | 11 | Press \ to start the load test! 12 | -------------------------------------------------------------------------------- /dist/README.txt: -------------------------------------------------------------------------------- 1 | ======================== 2 | BUILD OUTPUT DESCRIPTION 3 | ======================== 4 | 5 | When you build an Java application project that has a main class, the IDE 6 | automatically copies all of the JAR 7 | files on the projects classpath to your projects dist/lib folder. The IDE 8 | also adds each of the JAR files to the Class-Path element in the application 9 | JAR files manifest file (MANIFEST.MF). 10 | 11 | To run the project from the command line, go to the dist folder and 12 | type the following: 13 | 14 | java -jar "app.jar" 15 | 16 | To distribute this project, zip up the dist folder (including the lib folder) 17 | and distribute the ZIP file. 18 | 19 | Notes: 20 | 21 | * If two JAR files on the project classpath have the same name, only the first 22 | JAR file is copied to the lib folder. 23 | * Only JAR files are copied to the lib folder. 24 | If the classpath contains other types of files or folders, these files (folders) 25 | are not copied. 26 | * If a library on the projects classpath also has a Class-Path element 27 | specified in the manifest,the content of the Class-Path element has to be on 28 | the projects runtime path. 29 | * To set a main class in a standard Java project, right-click the project node 30 | in the Projects window and choose Properties. Then click Run and enter the 31 | class name in the Main Class field. Alternatively, you can manually type the 32 | class name in the manifest Main-Class element. 33 | -------------------------------------------------------------------------------- /dist/app.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jelastic/java-vertical-scaling-test/6cfdd3c9f4561c00f7b1bd8f03228d3be64145c6/dist/app.jar -------------------------------------------------------------------------------- /images/elastic-duke-70x70.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jelastic/java-vertical-scaling-test/6cfdd3c9f4561c00f7b1bd8f03228d3be64145c6/images/elastic-duke-70x70.png -------------------------------------------------------------------------------- /kubernetes/README.md: -------------------------------------------------------------------------------- 1 | # Java vertical scaling test 2 | 3 | ## Nodes 4 | 5 | This addon assumes that there are 6 nodes in the cluster. Nodes are [labeled](https://github.com/bianchi2/kube-deployer/blob/master/scripts/labelnodes.sh) in a special way so that Kubernetes schedules 1 Java pod per node. 6 | Currently, the addon does not check if there are enough nodes, so if nodes count is under 6, one of the pods won't be scheduled. 7 | 8 | Also, Jelastic nodes displayNames are modified to make statistics analysis simpler. 9 | 10 | 11 | ## Deployments 12 | 13 | This addon creates 6 K8s deployments in `java` namespace. Deployments are defined in .yaml files and can be edited if necessary. 14 | 15 | The addon processes retrieved yamls and replaces placeholders with desired values (at this moment only memory limits and JAVA_OPTS). 16 | You can make more things configurable is necessary. 17 | 18 | ``` 19 | curl ${baseUrl}/deployments/adoptopenjdk.yaml | sed "s/%JAVA_OPTS%/${globals.common} ${globals.adoptopenjdk}/g" | sed "s/%MEM_LIMIT%/${settings.adoptopenjdkLimit}/g" | kubectl apply -f - 20 | ``` 21 | 22 | ## Memory Limits 23 | 24 | The default memory limit is `3Gi`. You can change it for each pod in `${settings.jdkFlavor}`: 25 | 26 | ``` 27 | - type: string 28 | name: zulujdkLimit 29 | caption: Zulu Pod Mem Limit 30 | default: 3Gi 31 | inputType: hidden 32 | ``` 33 | Remove `inputType: hidden` if you want to be able to define memory requests for containers on UI. 34 | 35 | ## JAVA_OPTS 36 | 37 | There are common `JAVA_OPTS` defined in `{globals.common}` and `JAVA_OPTS` defined for each individual pod - `$globals.jdkFlavor` 38 | 39 | ``` 40 | globals: 41 | common: -Xmx3g -Xms32m -XX:+UseCompressedOops 42 | zing: -XX:-AutoTuneResourceDefaultsBasedOnXmx 43 | openjdk: -XX:+UnlockExperimentalVMOptions -XX:+UseZGC -XX:ZUncommitDelay=1 -XX:ZCollectionInterval=30 44 | openj9: -XX:+IdleTuningCompactOnIdle -XX:+IdleTuningGcOnIdle -XX:IdleTuningMinIdleWaitTime=1 -Xjit:waitTimeToEnterDeepIdleMode=1000 45 | adoptopenjdk: -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -XX:ShenandoahGCHeuristics=compact 46 | liberica: -XX:+UseG1GC -XX:G1PeriodicGCInterval=10k 47 | zulujdk: -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC 48 | ``` 49 | 50 | ## Redeploy 51 | 52 | When this addon is repeatedly applied to a Kubernetes cluster, all existing deployments in `java` namespace are forcefully deleted, 53 | thus, there is no need to manually clean up resources before a repeated deployment. 54 | 55 | ## Monitoring 56 | 57 | The addon assumes that Grafana is installed in a cluster and is available at `${env.url}/grafana`. 58 | Several dashboards are imported to track Java pods memory utilization. 59 | 60 | Once installed, the addon will print URL and names of dashboards to check out. 61 | -------------------------------------------------------------------------------- /kubernetes/dashboards/java-dashboard-cpu.json: -------------------------------------------------------------------------------- 1 | { 2 | "dashboard": { 3 | "annotations": { 4 | "list": [ 5 | { 6 | "builtIn": 1, 7 | "datasource": "-- Grafana --", 8 | "enable": true, 9 | "hide": true, 10 | "iconColor": "rgba(0, 211, 255, 1)", 11 | "name": "Annotations & Alerts", 12 | "type": "dashboard" 13 | } 14 | ] 15 | }, 16 | "editable": true, 17 | "gnetId": null, 18 | "graphTooltip": 0, 19 | "links": [], 20 | "panels": [ 21 | { 22 | "aliasColors": {}, 23 | "bars": false, 24 | "dashLength": 10, 25 | "dashes": false, 26 | "fill": 1, 27 | "fillGradient": 0, 28 | "gridPos": { 29 | "h": 21, 30 | "w": 17, 31 | "x": 6, 32 | "y": 0 33 | }, 34 | "id": 2, 35 | "legend": { 36 | "avg": false, 37 | "current": false, 38 | "max": false, 39 | "min": false, 40 | "show": true, 41 | "total": false, 42 | "values": false 43 | }, 44 | "lines": true, 45 | "linewidth": 1, 46 | "nullPointMode": "null", 47 | "options": { 48 | "dataLinks": [] 49 | }, 50 | "percentage": false, 51 | "pointradius": 2, 52 | "points": false, 53 | "renderer": "flot", 54 | "seriesOverrides": [], 55 | "spaceLength": 10, 56 | "stack": false, 57 | "steppedLine": false, 58 | "targets": [ 59 | { 60 | "expr": "rate(container_cpu_usage_seconds_total{container_name=\"%CONTAINER1%\"}[5m])", 61 | "legendFormat": "%CONTAINER1%", 62 | "refId": "A" 63 | }, 64 | { 65 | "expr": "rate(container_cpu_usage_seconds_total{container_name=\"%CONTAINER2%\"}[5m])", 66 | "legendFormat": "%CONTAINER2%", 67 | "refId": "B" 68 | }, 69 | { 70 | "expr": "rate(container_cpu_usage_seconds_total{container_name=\"%CONTAINER3%\"}[5m])", 71 | "legendFormat": "%CONTAINER3%", 72 | "refId": "C" 73 | }, 74 | { 75 | "expr": "rate(container_cpu_usage_seconds_total{container_name=\"%CONTAINER4%\"}[5m])", 76 | "legendFormat": "%CONTAINER4%", 77 | "refId": "D" 78 | } 79 | ], 80 | "thresholds": [], 81 | "timeFrom": null, 82 | "timeRegions": [], 83 | "timeShift": null, 84 | "title": "Panel Title", 85 | "tooltip": { 86 | "shared": true, 87 | "sort": 0, 88 | "value_type": "individual" 89 | }, 90 | "type": "graph", 91 | "xaxis": { 92 | "buckets": null, 93 | "mode": "time", 94 | "name": null, 95 | "show": true, 96 | "values": [] 97 | }, 98 | "yaxes": [ 99 | { 100 | "format": "short", 101 | "label": null, 102 | "logBase": 1, 103 | "max": null, 104 | "min": null, 105 | "show": true 106 | }, 107 | { 108 | "format": "short", 109 | "label": null, 110 | "logBase": 1, 111 | "max": null, 112 | "min": null, 113 | "show": true 114 | } 115 | ], 116 | "yaxis": { 117 | "align": false, 118 | "alignLevel": null 119 | } 120 | } 121 | ], 122 | "schemaVersion": 19, 123 | "style": "dark", 124 | "tags": [], 125 | "templating": { 126 | "list": [] 127 | }, 128 | "time": { 129 | "from": "now-5m", 130 | "to": "now" 131 | }, 132 | "timepicker": { 133 | "refresh_intervals": [ 134 | "5s", 135 | "10s", 136 | "30s", 137 | "1m", 138 | "5m", 139 | "15m", 140 | "30m", 141 | "1h", 142 | "2h", 143 | "1d" 144 | ] 145 | }, 146 | "timezone": "", 147 | "title": "Java CPU %NAME%", 148 | "uid": "java-cpu-%NAME%", 149 | "version": 2 150 | }, 151 | "folderId": 0, 152 | "overwrite": false 153 | } 154 | -------------------------------------------------------------------------------- /kubernetes/dashboards/java-dashboard-mem.json: -------------------------------------------------------------------------------- 1 | { 2 | "dashboard": { 3 | "annotations": { 4 | "list": [ 5 | { 6 | "builtIn": 1, 7 | "datasource": "-- Grafana --", 8 | "enable": true, 9 | "hide": true, 10 | "iconColor": "rgba(0, 211, 255, 1)", 11 | "name": "Annotations & Alerts", 12 | "type": "dashboard" 13 | } 14 | ] 15 | }, 16 | "editable": true, 17 | "gnetId": null, 18 | "graphTooltip": 0, 19 | "links": [], 20 | "panels": [ 21 | { 22 | "aliasColors": {}, 23 | "bars": false, 24 | "dashLength": 10, 25 | "dashes": false, 26 | "fill": 1, 27 | "fillGradient": 0, 28 | "gridPos": { 29 | "h": 21, 30 | "w": 17, 31 | "x": 6, 32 | "y": 0 33 | }, 34 | "id": 2, 35 | "legend": { 36 | "avg": false, 37 | "current": false, 38 | "max": false, 39 | "min": false, 40 | "show": true, 41 | "total": false, 42 | "values": false 43 | }, 44 | "lines": true, 45 | "linewidth": 1, 46 | "nullPointMode": "null", 47 | "options": { 48 | "dataLinks": [] 49 | }, 50 | "percentage": false, 51 | "pointradius": 2, 52 | "points": false, 53 | "renderer": "flot", 54 | "seriesOverrides": [], 55 | "spaceLength": 10, 56 | "stack": false, 57 | "steppedLine": false, 58 | "targets": [ 59 | { 60 | "expr": "sum(container_memory_usage_bytes{container_name=\"%CONTAINER1%\"})/1024/1024/1024", 61 | "legendFormat": "%CONTAINER1%", 62 | "refId": "A" 63 | }, 64 | { 65 | "expr": "sum(container_memory_usage_bytes{container_name=\"%CONTAINER2%\"})/1024/1024/1024", 66 | "legendFormat": "%CONTAINER2%", 67 | "refId": "B" 68 | }, 69 | { 70 | "expr": "sum(container_memory_usage_bytes{container_name=\"%CONTAINER3%\"})/1024/1024/1024", 71 | "legendFormat": "%CONTAINER3%", 72 | "refId": "C" 73 | }, 74 | { 75 | "expr": "sum(container_memory_usage_bytes{container_name=\"%CONTAINER4%\"})/1024/1024/1024", 76 | "legendFormat": "%CONTAINER4%", 77 | "refId": "D" 78 | } 79 | ], 80 | "thresholds": [], 81 | "timeFrom": null, 82 | "timeRegions": [], 83 | "timeShift": null, 84 | "title": "Panel Title", 85 | "tooltip": { 86 | "shared": true, 87 | "sort": 0, 88 | "value_type": "individual" 89 | }, 90 | "type": "graph", 91 | "xaxis": { 92 | "buckets": null, 93 | "mode": "time", 94 | "name": null, 95 | "show": true, 96 | "values": [] 97 | }, 98 | "yaxes": [ 99 | { 100 | "format": "short", 101 | "label": null, 102 | "logBase": 1, 103 | "max": null, 104 | "min": null, 105 | "show": true 106 | }, 107 | { 108 | "format": "short", 109 | "label": null, 110 | "logBase": 1, 111 | "max": null, 112 | "min": null, 113 | "show": true 114 | } 115 | ], 116 | "yaxis": { 117 | "align": false, 118 | "alignLevel": null 119 | } 120 | } 121 | ], 122 | "schemaVersion": 19, 123 | "style": "dark", 124 | "tags": [], 125 | "templating": { 126 | "list": [] 127 | }, 128 | "time": { 129 | "from": "now-15m", 130 | "to": "now" 131 | }, 132 | "timepicker": { 133 | "refresh_intervals": [ 134 | "5s", 135 | "10s", 136 | "30s", 137 | "1m", 138 | "5m", 139 | "15m", 140 | "30m", 141 | "1h", 142 | "2h", 143 | "1d" 144 | ] 145 | }, 146 | "timezone": "", 147 | "title": "Java Memory %NAME%", 148 | "uid": "java-mem-%NAME%", 149 | "version": 2 150 | }, 151 | "folderId": 0, 152 | "overwrite": false 153 | } 154 | -------------------------------------------------------------------------------- /kubernetes/deployments/adoptopenjdk.yaml: -------------------------------------------------------------------------------- 1 | kind: Deployment 2 | apiVersion: apps/v1 3 | metadata: 4 | labels: 5 | k8s-app: java-shenandoah 6 | app: java 7 | name: java-shenandoah 8 | namespace: java 9 | spec: 10 | replicas: 1 11 | revisionHistoryLimit: 10 12 | selector: 13 | matchLabels: 14 | k8s-app: java-shenandoah 15 | template: 16 | metadata: 17 | labels: 18 | k8s-app: java-shenandoah 19 | app: java 20 | spec: 21 | containers: 22 | - name: java-shenandoah 23 | resources: 24 | limits: 25 | memory: %MEM_LIMIT% 26 | image: jelastic/javaengine:adoptopenjdk-12.0.2 27 | imagePullPolicy: Always 28 | env: 29 | - name: _JAVA_OPTIONS 30 | value: %JAVA_OPTS% 31 | command: ["/bin/bash", "-c", "curl -L https://github.com/jelastic/java-vertical-scaling-test/raw/master/dist/app.jar --output app.jar && sleep 3 && %CMD%"] 32 | nodeSelector: 33 | gc: Shenandoah 34 | -------------------------------------------------------------------------------- /kubernetes/deployments/deployment.yaml: -------------------------------------------------------------------------------- 1 | kind: Deployment 2 | apiVersion: apps/v1 3 | metadata: 4 | labels: 5 | k8s-app: %NAME% 6 | app: java 7 | name: %NAME% 8 | namespace: java 9 | spec: 10 | replicas: 1 11 | revisionHistoryLimit: 10 12 | selector: 13 | matchLabels: 14 | k8s-app: %NAME% 15 | template: 16 | metadata: 17 | labels: 18 | k8s-app: %NAME% 19 | app: java 20 | spec: 21 | volumes: 22 | - name: zingmm0 23 | hostPath: 24 | path: /dev/zing_mm0 25 | containers: 26 | - name: %NAME% 27 | resources: 28 | limits: 29 | memory: %MEM_LIMIT% 30 | image: %IMAGE% 31 | imagePullPolicy: Always 32 | securityContext: 33 | privileged: true 34 | capabilities: 35 | add: ["NET_ADMIN", "SYS_TIME", "SYS_RAWIO", "SYS_ADMIN", "ALL"] 36 | env: 37 | - name: _JAVA_OPTIONS 38 | value: %JAVA_OPTS% 39 | command: ["/bin/bash", "-c", "curl -L https://github.com/jelastic/java-vertical-scaling-test/raw/master/dist/app.jar --output app.jar && sleep 3 && %CMD%"] 40 | nodeSelector: 41 | opts: %NODE% 42 | -------------------------------------------------------------------------------- /kubernetes/deployments/dragonwell.yaml: -------------------------------------------------------------------------------- 1 | kind: Deployment 2 | apiVersion: apps/v1 3 | metadata: 4 | labels: 5 | k8s-app: java-g1-dragonwell 6 | app: java 7 | name: java-g1-dragonwell 8 | namespace: java 9 | spec: 10 | replicas: 1 11 | revisionHistoryLimit: 10 12 | selector: 13 | matchLabels: 14 | k8s-app: java-g1-dragonwell 15 | template: 16 | metadata: 17 | labels: 18 | k8s-app: java-g1-dragonwell 19 | app: java 20 | spec: 21 | containers: 22 | - name: java-g1-dragonwell 23 | image: devbeta/javaengine:dragonwell-8.1.1 24 | imagePullPolicy: Always 25 | resources: 26 | limits: 27 | memory: %MEM_LIMIT% 28 | env: 29 | - name: _JAVA_OPTIONS 30 | value: %JAVA_OPTS% 31 | command: ["/bin/bash", "-c", "curl -L https://github.com/jelastic/java-vertical-scaling-test/raw/master/dist/app.jar --output app.jar && sleep 3 && %CMD%"] 32 | nodeSelector: 33 | gc: G1-dragon 34 | -------------------------------------------------------------------------------- /kubernetes/deployments/libericajdk12.yaml: -------------------------------------------------------------------------------- 1 | kind: Deployment 2 | apiVersion: apps/v1 3 | metadata: 4 | labels: 5 | k8s-app: java-g1 6 | app: java 7 | name: java-g1 8 | namespace: java 9 | spec: 10 | replicas: 1 11 | revisionHistoryLimit: 10 12 | selector: 13 | matchLabels: 14 | k8s-app: java-g1 15 | template: 16 | metadata: 17 | labels: 18 | k8s-app: java-g1 19 | app: java 20 | spec: 21 | containers: 22 | - name: java-g1 23 | resources: 24 | limits: 25 | memory: %MEM_LIMIT% 26 | image: jelastic/javaengine:libericajdk-12.0.2 27 | imagePullPolicy: Always 28 | env: 29 | - name: _JAVA_OPTIONS 30 | value: %JAVA_OPTS% 31 | command: ["/bin/bash", "-c", "curl -L https://github.com/jelastic/java-vertical-scaling-test/raw/master/dist/app.jar --output app.jar && sleep 3 && %CMD%"] 32 | nodeSelector: 33 | gc: G1 34 | -------------------------------------------------------------------------------- /kubernetes/deployments/openj9.yaml: -------------------------------------------------------------------------------- 1 | kind: Deployment 2 | apiVersion: apps/v1 3 | metadata: 4 | labels: 5 | k8s-app: java-openj9 6 | app: java 7 | name: java-openj9 8 | namespace: java 9 | spec: 10 | replicas: 1 11 | revisionHistoryLimit: 10 12 | selector: 13 | matchLabels: 14 | k8s-app: java-openj9 15 | template: 16 | metadata: 17 | labels: 18 | k8s-app: java-openj9 19 | app: java 20 | spec: 21 | containers: 22 | - name: java-openj9 23 | resources: 24 | limits: 25 | memory: %MEM_LIMIT% 26 | image: jelastic/javaengine:openj9-0.15.1-12.0.2 27 | imagePullPolicy: Always 28 | env: 29 | - name: OPENJ9_JAVA_OPTIONS 30 | value: %JAVA_OPTS% 31 | command: ["/bin/bash", "-c", "curl -L https://github.com/jelastic/java-vertical-scaling-test/raw/master/dist/app.jar --output app.jar && sleep 3 && %CMD%"] 32 | nodeSelector: 33 | gc: OpenJ9 34 | -------------------------------------------------------------------------------- /kubernetes/deployments/openjdk13.yaml: -------------------------------------------------------------------------------- 1 | kind: Deployment 2 | apiVersion: apps/v1 3 | metadata: 4 | labels: 5 | k8s-app: java-zgc 6 | app: java 7 | name: java-zgc 8 | namespace: java 9 | spec: 10 | replicas: 1 11 | revisionHistoryLimit: 10 12 | selector: 13 | matchLabels: 14 | k8s-app: java-zgc 15 | template: 16 | metadata: 17 | labels: 18 | k8s-app: java-zgc 19 | app: java 20 | spec: 21 | containers: 22 | - name: java-zgc 23 | resources: 24 | limits: 25 | memory: %MEM_LIMIT% 26 | image: jelastic/javaengine:openjdk-13.ea-b31 27 | imagePullPolicy: Always 28 | env: 29 | - name: _JAVA_OPTIONS 30 | value: %JAVA_OPTS% 31 | command: ["/bin/bash", "-c", "curl -L https://github.com/jelastic/java-vertical-scaling-test/raw/master/dist/app.jar --output app.jar && sleep 3 && %CMD%"] 32 | nodeSelector: 33 | gc: ZGC 34 | -------------------------------------------------------------------------------- /kubernetes/deployments/zing.yaml: -------------------------------------------------------------------------------- 1 | kind: Deployment 2 | apiVersion: apps/v1 3 | metadata: 4 | labels: 5 | k8s-app: java-c4 6 | app: java 7 | name: java-c4 8 | namespace: java 9 | spec: 10 | replicas: 1 11 | revisionHistoryLimit: 10 12 | selector: 13 | matchLabels: 14 | k8s-app: java-c4 15 | template: 16 | metadata: 17 | labels: 18 | k8s-app: java-c4 19 | app: java 20 | spec: 21 | volumes: 22 | - name: zingmm0 23 | hostPath: 24 | path: /dev/zing_mm0 25 | containers: 26 | - name: java-c4 27 | image: devbeta/javaengine:zing-11.0.0 28 | imagePullPolicy: Always 29 | securityContext: 30 | privileged: true 31 | capabilities: 32 | add: ["NET_ADMIN", "SYS_TIME", "SYS_RAWIO", "SYS_ADMIN", "ALL"] 33 | resources: 34 | limits: 35 | memory: %MEM_LIMIT% 36 | env: 37 | - name: _JAVA_OPTIONS 38 | value: %JAVA_OPTS% 39 | command: ["/bin/bash", "-c", "curl -L https://github.com/jelastic/java-vertical-scaling-test/raw/master/dist/app.jar --output app.jar && sleep 3 && %CMD%"] 40 | nodeSelector: 41 | gc: C4 42 | -------------------------------------------------------------------------------- /kubernetes/images/kube.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jelastic/java-vertical-scaling-test/6cfdd3c9f4561c00f7b1bd8f03228d3be64145c6/kubernetes/images/kube.png -------------------------------------------------------------------------------- /kubernetes/java-dashboard-cpu.json: -------------------------------------------------------------------------------- 1 | { 2 | "dashboard": { 3 | "annotations": { 4 | "list": [ 5 | { 6 | "builtIn": 1, 7 | "datasource": "-- Grafana --", 8 | "enable": true, 9 | "hide": true, 10 | "iconColor": "rgba(0, 211, 255, 1)", 11 | "name": "Annotations & Alerts", 12 | "type": "dashboard" 13 | } 14 | ] 15 | }, 16 | "editable": true, 17 | "gnetId": null, 18 | "graphTooltip": 0, 19 | "links": [], 20 | "panels": [ 21 | { 22 | "aliasColors": {}, 23 | "bars": false, 24 | "dashLength": 10, 25 | "dashes": false, 26 | "fill": 1, 27 | "fillGradient": 0, 28 | "gridPos": { 29 | "h": 21, 30 | "w": 17, 31 | "x": 6, 32 | "y": 0 33 | }, 34 | "id": 2, 35 | "legend": { 36 | "avg": false, 37 | "current": false, 38 | "max": false, 39 | "min": false, 40 | "show": true, 41 | "total": false, 42 | "values": false 43 | }, 44 | "lines": true, 45 | "linewidth": 1, 46 | "nullPointMode": "null", 47 | "options": { 48 | "dataLinks": [] 49 | }, 50 | "percentage": false, 51 | "pointradius": 2, 52 | "points": false, 53 | "renderer": "flot", 54 | "seriesOverrides": [], 55 | "spaceLength": 10, 56 | "stack": false, 57 | "steppedLine": false, 58 | "targets": [ 59 | { 60 | "expr": "rate(container_cpu_usage_seconds_total{container_name=\"java-c4\"}[5m])", 61 | "legendFormat": "C4", 62 | "refId": "A" 63 | }, 64 | { 65 | "expr": "rate(container_cpu_usage_seconds_total{container_name=\"java-zgc\"}[5m])", 66 | "legendFormat": "ZGC", 67 | "refId": "B" 68 | }, 69 | { 70 | "expr": "rate(container_cpu_usage_seconds_total{container_name=\"java-openj9\"}[5m])", 71 | "legendFormat": "OpenJ9", 72 | "refId": "C" 73 | }, 74 | { 75 | "expr": "rate(container_cpu_usage_seconds_total{container_name=\"java-g1\"}[5m])", 76 | "legendFormat": "G1", 77 | "refId": "D" 78 | }, 79 | { 80 | "expr": "rate(container_cpu_usage_seconds_total{container_name=\"java-shenandoah\"}[5m])", 81 | "legendFormat": "Shenandoah", 82 | "refId": "E" 83 | }, 84 | { 85 | "expr": "rate(container_cpu_usage_seconds_total{container_name=\"java-g1-dragonwell\"}[5m])", 86 | "legendFormat": "Dragonwell", 87 | "refId": "F" 88 | } 89 | ], 90 | "thresholds": [], 91 | "timeFrom": null, 92 | "timeRegions": [], 93 | "timeShift": null, 94 | "title": "Panel Title", 95 | "tooltip": { 96 | "shared": true, 97 | "sort": 0, 98 | "value_type": "individual" 99 | }, 100 | "type": "graph", 101 | "xaxis": { 102 | "buckets": null, 103 | "mode": "time", 104 | "name": null, 105 | "show": true, 106 | "values": [] 107 | }, 108 | "yaxes": [ 109 | { 110 | "format": "short", 111 | "label": null, 112 | "logBase": 1, 113 | "max": null, 114 | "min": null, 115 | "show": true 116 | }, 117 | { 118 | "format": "short", 119 | "label": null, 120 | "logBase": 1, 121 | "max": null, 122 | "min": null, 123 | "show": true 124 | } 125 | ], 126 | "yaxis": { 127 | "align": false, 128 | "alignLevel": null 129 | } 130 | } 131 | ], 132 | "schemaVersion": 19, 133 | "style": "dark", 134 | "tags": [], 135 | "templating": { 136 | "list": [] 137 | }, 138 | "time": { 139 | "from": "now-5m", 140 | "to": "now" 141 | }, 142 | "timepicker": { 143 | "refresh_intervals": [ 144 | "5s", 145 | "10s", 146 | "30s", 147 | "1m", 148 | "5m", 149 | "15m", 150 | "30m", 151 | "1h", 152 | "2h", 153 | "1d" 154 | ] 155 | }, 156 | "timezone": "", 157 | "title": "Java CPU", 158 | "uid": "java-cpu", 159 | "version": 2 160 | }, 161 | "folderId": 0, 162 | "overwrite": false 163 | } 164 | -------------------------------------------------------------------------------- /kubernetes/java-dashboard-mem.json: -------------------------------------------------------------------------------- 1 | { 2 | "dashboard": { 3 | "annotations": { 4 | "list": [ 5 | { 6 | "builtIn": 1, 7 | "datasource": "-- Grafana --", 8 | "enable": true, 9 | "hide": true, 10 | "iconColor": "rgba(0, 211, 255, 1)", 11 | "name": "Annotations & Alerts", 12 | "type": "dashboard" 13 | } 14 | ] 15 | }, 16 | "editable": true, 17 | "gnetId": null, 18 | "graphTooltip": 0, 19 | "links": [], 20 | "panels": [ 21 | { 22 | "aliasColors": {}, 23 | "bars": false, 24 | "dashLength": 10, 25 | "dashes": false, 26 | "fill": 1, 27 | "fillGradient": 0, 28 | "gridPos": { 29 | "h": 21, 30 | "w": 17, 31 | "x": 6, 32 | "y": 0 33 | }, 34 | "id": 2, 35 | "legend": { 36 | "avg": false, 37 | "current": false, 38 | "max": false, 39 | "min": false, 40 | "show": true, 41 | "total": false, 42 | "values": false 43 | }, 44 | "lines": true, 45 | "linewidth": 1, 46 | "nullPointMode": "null", 47 | "options": { 48 | "dataLinks": [] 49 | }, 50 | "percentage": false, 51 | "pointradius": 2, 52 | "points": false, 53 | "renderer": "flot", 54 | "seriesOverrides": [], 55 | "spaceLength": 10, 56 | "stack": false, 57 | "steppedLine": false, 58 | "targets": [ 59 | { 60 | "expr": "sum(container_memory_usage_bytes{container_name=\"java-c4\"})/1024/1024/1024", 61 | "legendFormat": "C4", 62 | "refId": "A" 63 | }, 64 | { 65 | "expr": "sum(container_memory_usage_bytes{container_name=\"java-zgc\"})/1024/1024/1024", 66 | "legendFormat": "ZGC", 67 | "refId": "B" 68 | }, 69 | { 70 | "expr": "sum(container_memory_usage_bytes{container_name=\"java-openj9\"})/1024/1024/1024", 71 | "legendFormat": "OpenJ9", 72 | "refId": "C" 73 | }, 74 | { 75 | "expr": "sum(container_memory_usage_bytes{container_name=\"java-g1\"})/1024/1024/1024", 76 | "legendFormat": "G1", 77 | "refId": "D" 78 | }, 79 | { 80 | "expr": "sum(container_memory_usage_bytes{container_name=\"java-shenandoah\"})/1024/1024/1024", 81 | "legendFormat": "Shenandoah", 82 | "refId": "E" 83 | }, 84 | { 85 | "expr": "sum(container_memory_usage_bytes{container_name=\"java-g1-dragonwell\"})/1024/1024/1024", 86 | "legendFormat": "Dragonwell", 87 | "refId": "F" 88 | } 89 | ], 90 | "thresholds": [], 91 | "timeFrom": null, 92 | "timeRegions": [], 93 | "timeShift": null, 94 | "title": "Panel Title", 95 | "tooltip": { 96 | "shared": true, 97 | "sort": 0, 98 | "value_type": "individual" 99 | }, 100 | "type": "graph", 101 | "xaxis": { 102 | "buckets": null, 103 | "mode": "time", 104 | "name": null, 105 | "show": true, 106 | "values": [] 107 | }, 108 | "yaxes": [ 109 | { 110 | "format": "short", 111 | "label": null, 112 | "logBase": 1, 113 | "max": null, 114 | "min": null, 115 | "show": true 116 | }, 117 | { 118 | "format": "short", 119 | "label": null, 120 | "logBase": 1, 121 | "max": null, 122 | "min": null, 123 | "show": true 124 | } 125 | ], 126 | "yaxis": { 127 | "align": false, 128 | "alignLevel": null 129 | } 130 | } 131 | ], 132 | "schemaVersion": 19, 133 | "style": "dark", 134 | "tags": [], 135 | "templating": { 136 | "list": [] 137 | }, 138 | "time": { 139 | "from": "now-15m", 140 | "to": "now" 141 | }, 142 | "timepicker": { 143 | "refresh_intervals": [ 144 | "5s", 145 | "10s", 146 | "30s", 147 | "1m", 148 | "5m", 149 | "15m", 150 | "30m", 151 | "1h", 152 | "2h", 153 | "1d" 154 | ] 155 | }, 156 | "timezone": "", 157 | "title": "Java Memory", 158 | "uid": "java-mem", 159 | "version": 2 160 | }, 161 | "folderId": 0, 162 | "overwrite": false 163 | } 164 | -------------------------------------------------------------------------------- /kubernetes/manifests/actions.jps: -------------------------------------------------------------------------------- 1 | type: update 2 | name: Label Nodes and Create Deployments 3 | onInstall: 4 | - labelNodes 5 | - renameNodes 6 | - setCloudlets 7 | - deploy 8 | - monit 9 | actions: 10 | labelNodes: 11 | - cmd [${nodes.k8sm.master.id}]: curl ${baseUrl}/scripts/label-nodes.sh | bash -s -- opts=${globals.container1} opts=${globals.container2} opts=${globals.container3} opts=${globals.container4} 12 | - cmd[${nodes.k8sm.master.id}]: kubectl get node -l=opts=${globals.container1} --template '{{range .items}}{{.metadata.name}}{{"\n"}}{{end}}' | awk '{print $1}' | awk -F"-" '{print $1}' | cut -c5- 13 | - setGlobals: 14 | node1: ${response.out} 15 | - cmd[${nodes.k8sm.master.id}]: kubectl get node -l=opts=${globals.container2} --template '{{range .items}}{{.metadata.name}}{{"\n"}}{{end}}' | awk '{print $1}' | awk -F"-" '{print $1}' | cut -c5- 16 | - setGlobals: 17 | node2: ${response.out} 18 | - cmd[${nodes.k8sm.master.id}]: kubectl get node -l=opts=${globals.container3} --template '{{range .items}}{{.metadata.name}}{{"\n"}}{{end}}' | awk '{print $1}' | awk -F"-" '{print $1}' | cut -c5- 19 | - setGlobals: 20 | node3: ${response.out} 21 | - cmd[${nodes.k8sm.master.id}]: kubectl get node -l=opts=${globals.container4} --template '{{range .items}}{{.metadata.name}}{{"\n"}}{{end}}' | awk '{print $1}' | awk -F"-" '{print $1}' | cut -c5- 22 | - setGlobals: 23 | node4: ${response.out} 24 | renameNodes: 25 | - jelastic.environment.control.SetNodeDisplayName: 26 | envName: ${env.name} 27 | nodeId: ${globals.node1} 28 | displayName: ${globals.container1} 29 | - jelastic.environment.control.SetNodeDisplayName: 30 | envName: ${env.name} 31 | nodeId: ${globals.node2} 32 | displayName: ${globals.container2} 33 | - jelastic.environment.control.SetNodeDisplayName: 34 | envName: ${env.name} 35 | nodeId: ${globals.node3} 36 | displayName: ${globals.container3} 37 | - jelastic.environment.control.SetNodeDisplayName: 38 | envName: ${env.name} 39 | nodeId: ${globals.node4} 40 | displayName: ${globals.container4} 41 | 42 | setCloudlets: 43 | env.control.SetCloudletsCountByGroup: 44 | nodeGroup: cp 45 | fixedCloudlets: 1 46 | flexibleCloudlets: ${globals.cloudlets} 47 | 48 | deploy: 49 | - cmd [${nodes.k8sm.master.id}]: |- 50 | kubectl create namespace java || true 51 | kubectl delete deployment --force --grace-period=0 -l=app=java -n java || true 52 | kubectl delete pods -n java $(kubectl get pods -l=app=java -n java --template '{{range .items}}{{.metadata.name}}{{"\n"}}{{end}}' | awk '{print $1}') --force --grace-period=0 || true 53 | wget ${baseUrl}/dashboards/java-dashboard-mem.json -O java-dashboard-mem.json 54 | wget ${baseUrl}/dashboards/java-dashboard-cpu.json -O java-dashboard-cpu.json 55 | 56 | cat java-dashboard-mem.json | sed "s/%CONTAINER1%/${globals.container1}/g" | sed "s/%CONTAINER2%/${globals.container2}/g" | sed "s/%CONTAINER3%/${globals.container3}/g" | sed "s/%CONTAINER4%/${globals.container4}/g" | sed "s/%NAME%/${globals.name}/g" > java-dashboard-memory.json 57 | 58 | cat java-dashboard-cpu.json | sed "s/%CONTAINER1%/${globals.container1}/g" | sed "s/%CONTAINER2%/${globals.container2}/g" | sed "s/%CONTAINER3%/${globals.container3}/g" | sed "s/%CONTAINER4%/${globals.container4}/g" | sed "s/%NAME%/${globals.name}/g" > java-dashboard-cpu1.json 59 | 60 | export grafana_secret=$(kubectl get secret --namespace kubernetes-monitoring monitoring-grafana -o jsonpath='{.data.admin-password}' | base64 --decode ; echo) 61 | curl -s -k -u "admin:${grafana_secret}" -X POST -H "Accept: application/json" -H "Content-Type: application/json" -d @java-dashboard-memory.json http://${env.domain}/grafana/api/dashboards/db/ 62 | curl -s -k -u "admin:${grafana_secret}" -X POST -H "Accept: application/json" -H "Content-Type: application/json" -d @java-dashboard-cpu1.json http://${env.domain}/grafana/api/dashboards/db/ 63 | rm java-dashboard-cpu.json java-dashboard-mem.json || true 64 | yaml=${baseUrl}/deployments/deployment.yaml?_r=${fn.random} 65 | curl $yaml | sed "s/%JAVA_OPTS%/${globals.common} ${globals.opts-container1}/g" | sed "s/%MEM_LIMIT%/${globals.limit}/g" | sed "s/%CMD%/${globals.cmd}/g" | sed "s/%NAME%/${globals.container1}/g" | sed "s/%NODE%/${globals.container1}/g" | sed "s@%IMAGE%@${globals.image}@g" | kubectl apply -f - 66 | curl $yaml | sed "s/%JAVA_OPTS%/${globals.common} ${globals.opts-container2}/g" | sed "s/%MEM_LIMIT%/${globals.limit}/g" | sed "s/%CMD%/${globals.cmd}/g" | sed "s/%NAME%/${globals.container2}/g" | sed "s/%NODE%/${globals.container2}/g" | sed "s@%IMAGE%@${globals.image}@g" | kubectl apply -f - 67 | curl $yaml | sed "s/%JAVA_OPTS%/${globals.common} ${globals.opts-container3}/g" | sed "s/%MEM_LIMIT%/${globals.limit}/g" | sed "s/%CMD%/${globals.cmd}/g" | sed "s/%NAME%/${globals.container3}/g" | sed "s/%NODE%/${globals.container3}/g" |sed "s@%IMAGE%@${globals.image}@g" | kubectl apply -f - 68 | curl $yaml | sed "s/%JAVA_OPTS%/${globals.common} ${globals.opts-container4}/g" | sed "s/%MEM_LIMIT%/${globals.limit}/g" | sed "s/%CMD%/${globals.cmd}/g" | sed "s/%NAME%/${globals.container4}/g" | sed "s/%NODE%/${globals.container4}/g" | sed "s@%IMAGE%@${globals.image}@g" | kubectl apply -f - 69 | 70 | 71 | monit: 72 | - cmd[${nodes.k8sm.master.id}]: kubectl get secret --namespace kubernetes-monitoring monitoring-grafana -o jsonpath='{.data.admin-password}' | base64 --decode 73 | - setGlobals: 74 | monit_token: ${response.out} 75 | - setGlobals: 76 | success: | 77 | Pods have been deployed to namespace java. 78 | 79 | Get pods: `kubectl get pods -n java` 80 | 81 | Get deployments: `kubectl get deployments -n java` 82 | 83 | Get logs: `kubectl logs -f $deploymentName -n java` 84 | 85 | [Memory Utilization Dashboard](${env.url}grafana/d/java-mem-${globals.name}/java-memory-${globals.name}?orgId=1&refresh=5s&from=now-5m&to=now) 86 | 87 | [CPU Utilization Dashboard](${env.url}grafana/d/java-cpu-${globals.name}/java-cpu-${globals.name}?orgId=1&refresh=5s&from=now-5m&to=now) 88 | 89 | Login: admin : ${globals.monit_token} 90 | 91 | success: ${globals.success} 92 | -------------------------------------------------------------------------------- /kubernetes/manifests/manifest-k8s-dragonwell-g1.yaml: -------------------------------------------------------------------------------- 1 | type: update 2 | description: | 3 | Java vertical scaling test on Kubernetes: G1 @ Dragonwell 8.1.1 4 | 5 | **Important!** Apply this Add-On to a Kubernetes Cluster with **4** worker nodes. 6 | Each pod is deployed to its dedicated labeled node to easily track memory utilization. 7 | 8 | 9 | name: Java Vertical Scaling on Kubernetes 10 | logo: https://github.com/jelastic/java-vertical-scaling-test/raw/master/kubernetes/images/kube.png 11 | baseUrl: https://raw.githubusercontent.com/jelastic/java-vertical-scaling-test/master/kubernetes 12 | 13 | globals: 14 | # keep \\\\n for sed replacement!!! 15 | name: dragonwell 16 | image: devbeta/javaengine:dragonwell-8.1.1 17 | cmd: java --uninstall; echo -ne '\\\\n' | java -jar app.jar 100 2 18 | limit: 3Gi 19 | cloudlets: 40 20 | common: -Xmx3g -Xms3g -XX:+UseCompressedOops -XX:+UseG1GC 21 | container1: custom1 22 | container2: custom2 23 | container3: custom3 24 | container4: default 25 | opts-container1: -XX:+G1ElasticHeap -XX:+ElasticHeapPeriodicUncommit -XX:ElasticHeapPeriodicYGCIntervalMillis=10000 -XX:ElasticHeapYGCIntervalMinMillis=1000 -XX:ElasticHeapInitialMarkIntervalMinMillis=1000 -XX:ElasticHeapPeriodicInitialMarkIntervalMillis=600000 -XX:ElasticHeapPeriodicUncommitStartupDelay=1 -XX:ElasticHeapPeriodicMinYoungCommitPercent=10 -XX:ElasticHeapPeriodicUncommitStartupDelay=10 -XX:ElasticHeapPeriodicMinYoungCommitPercent=10 -XX:ElasticHeapMinYoungCommitPercent=5 26 | opts-container2: -XX:+G1ElasticHeap -XX:+ElasticHeapPeriodicUncommit -XX:ElasticHeapPeriodicYGCIntervalMillis=30000 -XX:ElasticHeapYGCIntervalMinMillis=1000 -XX:ElasticHeapInitialMarkIntervalMinMillis=1000 -XX:ElasticHeapPeriodicInitialMarkIntervalMillis=300000 -XX:ElasticHeapPeriodicUncommitStartupDelay=1 -XX:ElasticHeapPeriodicMinYoungCommitPercent=10 -XX:ElasticHeapPeriodicUncommitStartupDelay=10 -XX:ElasticHeapPeriodicMinYoungCommitPercent=30 -XX:ElasticHeapMinYoungCommitPercent=10 27 | opts-container3: -XX:+G1ElasticHeap -XX:+ElasticHeapPeriodicUncommit -XX:ElasticHeapPeriodicYGCIntervalMillis=10000 -XX:ElasticHeapYGCIntervalMinMillis=1000 -XX:ElasticHeapInitialMarkIntervalMinMillis=1000 -XX:ElasticHeapPeriodicInitialMarkIntervalMillis=60000 -XX:ElasticHeapPeriodicUncommitStartupDelay=1 -XX:ElasticHeapPeriodicMinYoungCommitPercent=10 -XX:ElasticHeapPeriodicUncommitStartupDelay=10 -XX:ElasticHeapPeriodicMinYoungCommitPercent=10 -XX:ElasticHeapMinYoungCommitPercent=5 28 | opts-container4: -XX:+G1ElasticHeap -XX:+ElasticHeapPeriodicUncommit 29 | 30 | mixins: 31 | - manifests/actions.jps 32 | 33 | onInstall: 34 | - labelNodes 35 | - renameNodes 36 | - setCloudlets 37 | - deploy 38 | - monit 39 | success: ${globals.success} 40 | -------------------------------------------------------------------------------- /kubernetes/manifests/manifest-k8s-openj9.yaml: -------------------------------------------------------------------------------- 1 | type: update 2 | description: | 3 | Java vertical scaling test on Kubernetes: OpenJ9 4 | 5 | **Important!** Apply this Add-On to a Kubernetes Cluster with **4** worker nodes. 6 | Each pod is deployed to its dedicated labeled node to easily track memory utilization. 7 | 8 | 9 | name: Java Vertical Scaling on Kubernetes 10 | logo: https://github.com/jelastic/java-vertical-scaling-test/raw/master/kubernetes/images/kube.png 11 | baseUrl: https://raw.githubusercontent.com/jelastic/java-vertical-scaling-test/master/kubernetes 12 | 13 | globals: 14 | # keep \\\\n for sed replacement!!! 15 | name: openj9 16 | image: jelastic/javaengine:openj9-0.15.1-12.0.2 17 | cmd: java --uninstall; echo -ne '\\\\n' | java -jar app.jar 100 2 18 | limit: 3Gi 19 | cloudlets: 40 20 | common: -Xmx3g -Xms32m -XX:+UseCompressedOops 21 | container1: option1 22 | container2: option2 23 | container3: option3 24 | container4: option4 25 | 26 | 27 | opts-container1: -XX:+IdleTuningCompactOnIdle -XX:+IdleTuningGcOnIdle -XX:IdleTuningMinIdleWaitTime=1 -Xjit:waitTimeToEnterDeepIdleMode=1000 28 | opts-container2: -XX:+IdleTuningCompactOnIdle -XX:+IdleTuningGcOnIdle -XX:IdleTuningMinIdleWaitTime=10 -Xjit:waitTimeToEnterDeepIdleMode=1000 29 | opts-container3: -XX:+IdleTuningCompactOnIdle -XX:+IdleTuningGcOnIdle -XX:IdleTuningMinIdleWaitTime=10 -Xjit:waitTimeToEnterDeepIdleMode=10000 30 | opts-container4: -XX:+IdleTuningCompactOnIdle -XX:+IdleTuningGcOnIdle -XX:IdleTuningMinIdleWaitTime=10 -Xjit:waitTimeToEnterDeepIdleMode=10000 -Xgc:noConcurrentMark 31 | 32 | mixins: 33 | - manifests/actions.jps 34 | 35 | onInstall: 36 | - labelNodes 37 | - renameNodes 38 | - setCloudlets 39 | - deploy 40 | - monit 41 | success: ${globals.success} 42 | -------------------------------------------------------------------------------- /kubernetes/manifests/manifest-k8s-zgc.yaml: -------------------------------------------------------------------------------- 1 | type: update 2 | description: | 3 | Java vertical scaling test on Kubernetes: ZGC @ Oracle OpenJDK 4 | 5 | **Important!** Apply this Add-On to a Kubernetes Cluster with **4** worker nodes. 6 | Each pod is deployed to its dedicated labeled node to easily track memory utilization. 7 | 8 | 9 | name: Java Vertical Scaling on Kubernetes 10 | logo: https://github.com/jelastic/java-vertical-scaling-test/raw/master/kubernetes/images/kube.png 11 | baseUrl: https://raw.githubusercontent.com/jelastic/java-vertical-scaling-test/master/kubernetes 12 | 13 | globals: 14 | # keep \\\\n for sed replacement!!! 15 | name: zgc 16 | image: jelastic/javaengine:openjdk-13.ea-b31 17 | cmd: java --uninstall; echo -ne '\\\\n' | java -jar app.jar 100 2 18 | limit: 3Gi 19 | cloudlets: 40 20 | common: -Xmx3g -Xms32m -XX:+UseCompressedOops -XX:+UnlockExperimentalVMOptions -XX:+UseZGC 21 | container1: delay1-int30 22 | container2: delay30-int60 23 | container3: delay60-int30 24 | container4: delay30-int1 25 | opts-container1: -XX:ZUncommitDelay=1 -XX:ZCollectionInterval=30 26 | opts-container2: -XX:ZUncommitDelay=30 -XX:ZCollectionInterval=60 27 | opts-container3: -XX:ZUncommitDelay=60 -XX:ZCollectionInterval=30 28 | opts-container4: -XX:ZUncommitDelay=30 -XX:ZCollectionInterval=1 29 | 30 | mixins: 31 | - manifests/actions.jps 32 | 33 | onInstall: 34 | - labelNodes 35 | - renameNodes 36 | - setCloudlets 37 | - deploy 38 | - monit 39 | success: ${globals.success} 40 | -------------------------------------------------------------------------------- /kubernetes/manifests/manifest-k8s-zing.yaml: -------------------------------------------------------------------------------- 1 | type: update 2 | description: | 3 | Java vertical scaling test on Kubernetes: C4 @ Zing Azul Systems 4 | 5 | **Important!** Apply this Add-On to a Kubernetes Cluster with **4** worker nodes. 6 | Each pod is deployed to its dedicated labeled node to easily track memory utilization. 7 | 8 | 9 | name: Java Vertical Scaling on Kubernetes 10 | logo: https://github.com/jelastic/java-vertical-scaling-test/raw/master/kubernetes/images/kube.png 11 | baseUrl: https://raw.githubusercontent.com/jelastic/java-vertical-scaling-test/master/kubernetes 12 | 13 | globals: 14 | # keep \\\\n for sed replacement!!! 15 | name: zing 16 | image: devbeta/javaengine:zing-11.0.0 17 | cmd: java --uninstall; echo -ne '\\\\n' | java -jar app.jar 100 2 18 | limit: 3Gi 19 | cloudlets: 40 20 | common: -XX:+UseCompressedOops -XX:+UseZST -XX:-AutoTuneResourceDefaultsBasedOnXmx 21 | container1: xmx256m 22 | container2: xmx512m 23 | container3: xmx1024m 24 | container4: xmx2024m 25 | opts-container1: -Xmx256m 26 | opts-container2: -Xmx512m 27 | opts-container3: -Xmx1024m 28 | opts-container4: -Xmx2024m 29 | 30 | mixins: 31 | - manifests/actions.jps?_r=${fn.random} 32 | 33 | onInstall: 34 | - labelNodes 35 | - renameNodes 36 | - setCloudlets 37 | - deploy 38 | - monit 39 | success: ${globals.success} 40 | -------------------------------------------------------------------------------- /kubernetes/scripts/grafana.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | grafana_host=$1 3 | grafana_secret=$(kubectl get secret --namespace kubernetes-monitoring monitoring-grafana -o jsonpath='{.data.admin-password}' | base64 --decode ; echo) 4 | grafana_cred="admin:${grafana_secret}" 5 | grafana_datasource="Prometheus" 6 | ds=(1471 10000 5228 7249); 7 | echo -n "Processing dashboard: " 8 | for d in "${ds[@]}"; do 9 | echo -n "Processing $d: " 10 | j=$(curl -s -k -u "$grafana_cred" $grafana_host/api/gnet/dashboards/$d | jq .json) 11 | curl -s -k -u "$grafana_cred" -XPOST -H "Accept: application/json" \ 12 | -H "Content-Type: application/json" \ 13 | -d "{\"dashboard\":$j,\"overwrite\":true, \ 14 | \"inputs\":[{\"name\":\"DS_PROMETHEUS\",\"type\":\"datasource\", \ 15 | \"pluginId\":\"Jelastic\",\"value\":\"$grafana_datasource\"}]}" \ 16 | $grafana_host/api/dashboards/import; echo "" 17 | done -------------------------------------------------------------------------------- /kubernetes/scripts/label-nodes.sh: -------------------------------------------------------------------------------- 1 | NODES=$(kubectl get nodes | grep \ | awk '{print $1}') 2 | NODES=(${NODES// / }) 3 | LABELS=($1 $2 $3 $4) 4 | for i in ${!NODES[*]}; do 5 | kubectl label nodes ${NODES[$i]} ${LABELS[$i]} --overwrite 6 | done 7 | -------------------------------------------------------------------------------- /kubernetes/scripts/labelnodes.sh: -------------------------------------------------------------------------------- 1 | NODES=$(kubectl get nodes | grep \ | awk '{print $1}') 2 | NODES=(${NODES// / }) 3 | LABELS=(gc=ZGC gc=Shenandoah gc=C4 gc=OpenJ9 gc=G1 gc=G1-dragon) 4 | for i in ${!NODES[*]}; do 5 | kubectl label nodes ${NODES[$i]} ${LABELS[$i]} --overwrite 6 | done 7 | -------------------------------------------------------------------------------- /manifest-k8s.yaml: -------------------------------------------------------------------------------- 1 | type: update 2 | description: | 3 | Java vertical scaling test on Kubernetes: 4 | * G1 5 | * Shenandoah 6 | * G1 @ Dragonwell 8.1.1 7 | * ZGC @ Oracle OpenJDK 8 | * C4 @ Zing 9 | * OpenJ9 10 | 11 | **Important!** Apply this Add-On to a Kubernetes Cluster with **6** worker nodes. 12 | Each pod is deployed to its dedicated labeled node to easily track memory utilization. 13 | 14 | 15 | name: Java Vertical Scaling on Kubernetes 16 | logo: https://github.com/jelastic/java-vertical-scaling-test/raw/master/kubernetes/images/kube.png 17 | baseUrl: https://raw.githubusercontent.com/jelastic/java-vertical-scaling-test/master/kubernetes 18 | 19 | globals: 20 | # keep \\\\n for sed replacement!!! 21 | cmd: java --uninstall; echo -ne '\\\\n' | java -jar app.jar 100 2 22 | limit: 3Gi 23 | cloudlets: 40 24 | common: -Xmx3g -Xms32m -XX:+UseCompressedOops 25 | zing: -Xmx500m -Xms32m -XX:+UseCompressedOops -XX:+UseZST 26 | openjdk: -XX:+UnlockExperimentalVMOptions -XX:+UseZGC -XX:ZUncommitDelay=30 -XX:ZCollectionInterval=60 27 | openj9: -XX:+IdleTuningCompactOnIdle -XX:+IdleTuningGcOnIdle -XX:IdleTuningMinIdleWaitTime=10 -Xjit:waitTimeToEnterDeepIdleMode=10000 -Xgc:noConcurrentMark 28 | adoptopenjdk: -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -XX:ShenandoahGCHeuristics=compact 29 | liberica: -XX:+UseG1GC -XX:G1PeriodicGCInterval=10k 30 | dragonwell: -Xmx3g -Xms3g -XX:+UseCompressedOops -XX:+UseG1GC -XX:+G1ElasticHeap -XX:+ElasticHeapPeriodicUncommit -XX:ElasticHeapPeriodicYGCIntervalMillis=10000 -XX:ElasticHeapYGCIntervalMinMillis=1000 -XX:ElasticHeapInitialMarkIntervalMinMillis=1000 -XX:ElasticHeapPeriodicInitialMarkIntervalMillis=60000 -XX:ElasticHeapPeriodicUncommitStartupDelay=1 -XX:ElasticHeapPeriodicMinYoungCommitPercent=10 -XX:ElasticHeapPeriodicUncommitStartupDelay=10 -XX:ElasticHeapPeriodicMinYoungCommitPercent=10 -XX:ElasticHeapMinYoungCommitPercent=5 31 | 32 | onInstall: 33 | - labelNodes 34 | - renameNodes 35 | - setCloudlets 36 | - deploy 37 | - monit 38 | - getPods 39 | actions: 40 | labelNodes: 41 | - cmd [${nodes.k8sm.master.id}]: curl ${baseUrl}/scripts/labelnodes.sh | bash 42 | - cmd[${nodes.k8sm.master.id}]: kubectl get node -l=gc=ZGC --template '{{range .items}}{{.metadata.name}}{{"\n"}}{{end}}' | awk '{print $1}' | awk -F"-" '{print $1}' | cut -c5- 43 | - setGlobals: 44 | zgcNode: ${response.out} 45 | - cmd[${nodes.k8sm.master.id}]: kubectl get node -l=gc=Shenandoah --template '{{range .items}}{{.metadata.name}}{{"\n"}}{{end}}' | awk '{print $1}' | awk -F"-" '{print $1}' | cut -c5- 46 | - setGlobals: 47 | shenandoahNode: ${response.out} 48 | - cmd[${nodes.k8sm.master.id}]: kubectl get node -l=gc=OpenJ9 --template '{{range .items}}{{.metadata.name}}{{"\n"}}{{end}}' | awk '{print $1}' | awk -F"-" '{print $1}' | cut -c5- 49 | - setGlobals: 50 | openj9Node: ${response.out} 51 | - cmd[${nodes.k8sm.master.id}]: kubectl get node -l=gc=G1 --template '{{range .items}}{{.metadata.name}}{{"\n"}}{{end}}' | awk '{print $1}' | awk -F"-" '{print $1}' | cut -c5- 52 | - setGlobals: 53 | g1Node: ${response.out} 54 | - cmd[${nodes.k8sm.master.id}]: kubectl get node -l=gc=C4 --template '{{range .items}}{{.metadata.name}}{{"\n"}}{{end}}' | awk '{print $1}' | awk -F"-" '{print $1}' | cut -c5- 55 | - setGlobals: 56 | c4Node: ${response.out} 57 | - cmd[${nodes.k8sm.master.id}]: kubectl get node -l=gc=G1-dragon --template '{{range .items}}{{.metadata.name}}{{"\n"}}{{end}}' | awk '{print $1}' | awk -F"-" '{print $1}' | cut -c5- 58 | - setGlobals: 59 | dragonNode: ${response.out} 60 | renameNodes: 61 | - jelastic.environment.control.SetNodeDisplayName: 62 | envName: ${env.name} 63 | nodeId: ${globals.zgcNode} 64 | displayName: ZGC 65 | - jelastic.environment.control.SetNodeDisplayName: 66 | envName: ${env.name} 67 | nodeId: ${globals.shenandoahNode} 68 | displayName: Shenandoah 69 | - jelastic.environment.control.SetNodeDisplayName: 70 | envName: ${env.name} 71 | nodeId: ${globals.openj9Node} 72 | displayName: Openj9 73 | - jelastic.environment.control.SetNodeDisplayName: 74 | envName: ${env.name} 75 | nodeId: ${globals.g1Node} 76 | displayName: G1 77 | - jelastic.environment.control.SetNodeDisplayName: 78 | envName: ${env.name} 79 | nodeId: ${globals.c4Node} 80 | displayName: C4 81 | - jelastic.environment.control.SetNodeDisplayName: 82 | envName: ${env.name} 83 | nodeId: ${globals.dragonNode} 84 | displayName: G1-Dragonwell 85 | setCloudlets: 86 | env.control.SetCloudletsCountByGroup: 87 | nodeGroup: cp 88 | fixedCloudlets: 1 89 | flexibleCloudlets: ${globals.cloudlets} 90 | 91 | deploy: 92 | - cmd [${nodes.k8sm.master.id}]: |- 93 | kubectl create namespace java || true 94 | kubectl delete deployment --force --grace-period=0 -l=app=java -n java || true 95 | kubectl delete pods -n java $(kubectl get pods -l=app=java -n java --template '{{range .items}}{{.metadata.name}}{{"\n"}}{{end}}' | awk '{print $1}') --force --grace-period=0 || true 96 | wget ${baseUrl}/java-dashboard-mem.json -O java-dashboard-mem.json 97 | wget ${baseUrl}/java-dashboard-cpu.json -O java-dashboard-cpu.json 98 | export grafana_secret=$(kubectl get secret --namespace kubernetes-monitoring monitoring-grafana -o jsonpath='{.data.admin-password}' | base64 --decode ; echo) 99 | curl -s -k -u "admin:${grafana_secret}" -X POST -H "Accept: application/json" -H "Content-Type: application/json" -d @java-dashboard-mem.json http://${env.domain}/grafana/api/dashboards/db/ 100 | curl -s -k -u "admin:${grafana_secret}" -X POST -H "Accept: application/json" -H "Content-Type: application/json" -d @java-dashboard-cpu.json http://${env.domain}/grafana/api/dashboards/db/ 101 | curl ${baseUrl}/deployments/adoptopenjdk.yaml | sed "s/%JAVA_OPTS%/${globals.common} ${globals.adoptopenjdk}/g" | sed "s/%MEM_LIMIT%/${globals.limit}/g" | sed "s/%CMD%/${globals.cmd}/g" | kubectl apply -f - 102 | curl ${baseUrl}/deployments/libericajdk12.yaml | sed "s/%JAVA_OPTS%/${globals.common} ${globals.liberica}/g" | sed "s/%MEM_LIMIT%/${globals.limit}/g" | sed "s/%CMD%/${globals.cmd}/g" | kubectl apply -f - 103 | curl ${baseUrl}/deployments/openj9.yaml | sed "s/%JAVA_OPTS%/${globals.common} ${globals.openj9}/g" | sed "s/%MEM_LIMIT%/${globals.limit}/g" | sed "s/%CMD%/${globals.cmd}/g" | kubectl apply -f - 104 | curl ${baseUrl}/deployments/openjdk13.yaml | sed "s/%JAVA_OPTS%/${globals.common} ${globals.openjdk}/g" | sed "s/%MEM_LIMIT%/${globals.limit}/g" | sed "s/%CMD%/${globals.cmd}/g" | kubectl apply -f - 105 | curl ${baseUrl}/deployments/zulujdk.yaml | sed "s/%JAVA_OPTS%/${globals.common} ${globals.zulujdk}/g" | sed "s/%MEM_LIMIT%/${globals.limit}/g" | sed "s/%CMD%/${globals.cmd}/g" | kubectl apply -f - 106 | curl ${baseUrl}/deployments/zing.yaml | sed "s/%JAVA_OPTS%/${globals.zing}/g" | sed "s/%MEM_LIMIT%/${globals.limit}/g" | sed "s/%CMD%/${globals.cmd}/g" | kubectl apply -f - 107 | curl ${baseUrl}/deployments/dragonwell.yaml | sed "s/%JAVA_OPTS%/${globals.dragonwell}/g" | sed "s/%MEM_LIMIT%/${globals.limit}/g" | sed "s/%CMD%/${globals.cmd}/g" | kubectl apply -f - 108 | monit: 109 | - cmd[${nodes.k8sm.master.id}]: kubectl get secret --namespace kubernetes-monitoring monitoring-grafana -o jsonpath='{.data.admin-password}' | base64 --decode 110 | - setGlobals: 111 | monit_token: ${response.out} 112 | getPods: 113 | - cmd[${nodes.k8sm.master.id}]: kubectl get pods -l=k8s-app=java-shenandoah -n java --template '{{range .items}}{{.metadata.name}}{{"\n"}}{{end}}' | awk '{print $1}' 114 | - setGlobals: 115 | adoptOpenJDKPod: ${response.out} 116 | - cmd[${nodes.k8sm.master.id}]: kubectl get pods -l=k8s-app=java-g1 -n java --template '{{range .items}}{{.metadata.name}}{{"\n"}}{{end}}' | awk '{print $1}' 117 | - setGlobals: 118 | libericajdkPod: ${response.out} 119 | - cmd[${nodes.k8sm.master.id}]: kubectl get pods -l=k8s-app=java-openj9 -n java --template '{{range .items}}{{.metadata.name}}{{"\n"}}{{end}}' | awk '{print $1}' 120 | - setGlobals: 121 | openj9Pod: ${response.out} 122 | - cmd[${nodes.k8sm.master.id}]: kubectl get pods -l=k8s-app=java-zgc -n java --template '{{range .items}}{{.metadata.name}}{{"\n"}}{{end}}' | awk '{print $1}' 123 | - setGlobals: 124 | openjdkPod: ${response.out} 125 | - cmd[${nodes.k8sm.master.id}]: kubectl get pods -l=k8s-app=java-c4 -n java --template '{{range .items}}{{.metadata.name}}{{"\n"}}{{end}}' | awk '{print $1}' 126 | - setGlobals: 127 | zingPod: ${response.out} 128 | - cmd[${nodes.k8sm.master.id}]: kubectl get pods -l=k8s-app=java-g1-dragonwell -n java --template '{{range .items}}{{.metadata.name}}{{"\n"}}{{end}}' | awk '{print $1}' 129 | - setGlobals: 130 | dragonwell: ${response.out} 131 | - setGlobals: 132 | success: | 133 | Pods have been deployed to namespace java. 134 | 135 | Get pods: `kubectl get pods -n java` 136 | 137 | Get deployments: `kubectl get deployments -n java` 138 | 139 | Get logs: `kubectl logs -f $deploymentName -n java` 140 | 141 | [Memory Utilization Dashboard](${env.url}grafana/d/java-mem/java-memory?orgId=1&refresh=5s&from=now-5m&to=now) 142 | 143 | [CPU Utilization Dashboard](${env.url}grafana/d/java-cpu/java-cpu?orgId=1&refresh=5s&from=now-5m&to=now) 144 | 145 | Login: admin : ${globals.monit_token} 146 | 147 | success: ${globals.success} 148 | -------------------------------------------------------------------------------- /manifest.yml: -------------------------------------------------------------------------------- 1 | type: install 2 | id: java-memory-usage-demo 3 | name: Java Vertical Scaling 4 | baseUrl: https://raw.githubusercontent.com/jelastic/java-vertical-scaling-test/master 5 | homepage: https://github.com/jelastic/java-vertical-scaling-test 6 | logo: /images/elastic-duke-70x70.png 7 | description: | 8 | Java vertical scaling test: 9 | * G1 @ Zulu 12.0.2 10 | * G1 @ Dragonwell 8.1.1 11 | * Shenandoah 12 | * ZGC @ Oracle OpenJDK 13 | * C4 @ Zing 14 | * OpenJ9 15 | * Serial 16 | * CMS 17 | * Epsilon 18 | * Parallel 19 | 20 | globals: 21 | cloudlets: 26 22 | common: -Xmx3g -Xms32m -XX:+UseCompressedOops 23 | nodes: 24 | - nodeType: javaengine 25 | tag: zulujdk-12.0.2 26 | nodeGroup: g1 27 | cloudlets: ${globals.cloudlets} 28 | displayName: G1 @ Zulu 12 29 | startService: false 30 | env: 31 | _JAVA_OPTIONS: ${globals.common} -XX:+UseG1GC -XX:G1PeriodicGCInterval=1k 32 | 33 | - image: devbeta/javaengine:dragonwell-8.1.1 34 | nodeGroup: dw 35 | cloudlets: ${globals.cloudlets} 36 | displayName: G1 @ Dragonwell 8 37 | startService: false 38 | env: 39 | _JAVA_OPTIONS: -Xmx3g -Xms3g -XX:+UseCompressedOops -XX:+UseG1GC -XX:+G1ElasticHeap -XX:+ElasticHeapPeriodicUncommit -XX:ElasticHeapPeriodicYGCIntervalMillis=10000 -XX:ElasticHeapYGCIntervalMinMillis=1000 -XX:ElasticHeapInitialMarkIntervalMinMillis=1000 -XX:ElasticHeapPeriodicInitialMarkIntervalMillis=300000 -XX:ElasticHeapPeriodicUncommitStartupDelay=1 -XX:ElasticHeapPeriodicMinYoungCommitPercent=10 40 | 41 | - nodeType: javaengine 42 | tag: zulujdk-12.0.2 43 | nodeGroup: shenan 44 | cloudlets: ${globals.cloudlets} 45 | displayName: Shenandoah 46 | startService: false 47 | #-XX:ShenandoahGCHeuristics=compact is very agressive mode 48 | env: 49 | _JAVA_OPTIONS: ${globals.common} -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -XX:ShenandoahGCHeuristics=compact 50 | - nodeType: javaengine 51 | tag: openjdk-13.ea-b31 52 | nodeGroup: zgc 53 | cloudlets: ${globals.cloudlets} 54 | displayName: ZGC @ Oracle OpenJDK 55 | startService: false 56 | #-XX:ZUncommitDelay=1 -XX:ZCollectionInterval=30 is very agressive mode as well, similar to Shenandoah 57 | env: 58 | _JAVA_OPTIONS: ${globals.common} -XX:+UnlockExperimentalVMOptions -XX:+UseZGC -XX:ZUncommitDelay=30 -XX:ZCollectionInterval=60 59 | 60 | - nodeType: javaengine 61 | tag: zulujdk-12.0.2 62 | nodeGroup: epsilon 63 | cloudlets: ${globals.cloudlets} 64 | displayName: Epsilon 65 | startService: false 66 | env: 67 | _JAVA_OPTIONS: ${globals.common} -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC 68 | 69 | - nodeType: javaengine 70 | tag: openj9-0.15.1-12.0.2 71 | nodeGroup: openj9 72 | cloudlets: ${globals.cloudlets} 73 | displayName: OpenJ9 74 | startService: false 75 | env: 76 | OPENJ9_JAVA_OPTIONS: ${globals.common} -XX:+IdleTuningCompactOnIdle -XX:+IdleTuningGcOnIdle -XX:IdleTuningMinIdleWaitTime=1 -Xjit:waitTimeToEnterDeepIdleMode=1000 77 | 78 | - image: devbeta/javaengine:zing-11.0.0 79 | nodeGroup: zing 80 | cloudlets: ${globals.cloudlets} 81 | displayName: C4 @ Zing 82 | startService: false 83 | env: 84 | _JAVA_OPTIONS: -Xmx500m -XX:+UseCompressedOops -XX:+UseZST 85 | 86 | - nodeType: javaengine 87 | tag: zulujdk-12.0.2 88 | nodeGroup: cms 89 | cloudlets: ${globals.cloudlets} 90 | displayName: ConcMarkSweep 91 | startService: false 92 | env: 93 | _JAVA_OPTIONS: ${globals.common} -XX:+UseConcMarkSweepGC 94 | 95 | - nodeType: javaengine 96 | tag: zulujdk-12.0.2 97 | nodeGroup: parallel 98 | cloudlets: ${globals.cloudlets} 99 | displayName: Parallel 100 | startService: false 101 | env: 102 | _JAVA_OPTIONS: ${globals.common} -XX:+UseParallelGC 103 | 104 | - nodeType: javaengine 105 | tag: zulujdk-12.0.2 106 | nodeGroup: serial 107 | cloudlets: ${globals.cloudlets} 108 | displayName: Serial 109 | startService: false 110 | env: 111 | _JAVA_OPTIONS: ${globals.common} -XX:+UseSerialGC 112 | 113 | 114 | onInstall: 115 | - cmd[*]: |- 116 | chmod 775 /var/run/screen 117 | chmod 777 /var/log/run.log 118 | java --uninstall 119 | user: root 120 | - cmd[*]: |- 121 | wget https://github.com/jelastic/java-vertical-scaling-test/raw/master/dist/app.jar 122 | screen -dm bash -c "echo -ne '\n' | java -jar app.jar 100 2 &>> /var/log/run.log" 123 | - cmd[serial, cms, parallel, epsilon]: |- 124 | screen -dm bash -c 'sleep 300; while true; do a="app"; j=".jar"; /usr/java/latest/bin/jcmd $(pgrep -f $a$j | tail -n1) GC.run &>> /var/log/run.log; sleep 20; done;' 125 | 126 | # OpenJ9 memory usage should be tracked in a tricky way 127 | # while true; do used=$(ps -orss --no-headers --pid $(pgrep -f java | tail -n1)); echo "scale=2 ; $used / 1024*1024" | bc; sleep 1; done 128 | -------------------------------------------------------------------------------- /src/com/jelastic/verticalscaling/Load.java: -------------------------------------------------------------------------------- 1 | package com.jelastic.verticalscaling; 2 | 3 | import java.io.IOException; 4 | import java.util.LinkedList; 5 | import java.util.List; 6 | 7 | /** 8 | * 9 | * @author ruslan 10 | */ 11 | public class Load { 12 | 13 | private int sleep = 0; 14 | private int longSleep = 60000; 15 | private int numCycles = 3; 16 | private int mode = 1; 17 | 18 | public Load(int sleep) { 19 | this.sleep = sleep; 20 | } 21 | 22 | public Load(int sleep, int mode) { 23 | this(sleep); 24 | this.mode = mode; 25 | } 26 | 27 | public void run() throws IOException, InterruptedException { 28 | long start = System.currentTimeMillis(); 29 | try { 30 | switch (mode) { 31 | case 1: 32 | simple(); 33 | break; 34 | case 2: 35 | gil(); 36 | break; 37 | default: 38 | System.out.println("Unknown load mode: " + mode); 39 | } 40 | 41 | } catch (OutOfMemoryError e) { 42 | e.printStackTrace(); 43 | } 44 | System.out.println("total time = " + (System.currentTimeMillis() - start) + ", ms"); 45 | System.out.println("done"); 46 | 47 | } 48 | 49 | private void simple() throws InterruptedException, OutOfMemoryError { 50 | int n = 1 * 1024 * 512 / 2; 51 | List list = new LinkedList(); 52 | for (int i = 0; i < n; i++) { 53 | String[] str = new String[1024]; 54 | list.add(str); 55 | if (i % 100 == 0) { 56 | //System.out.println("i=" + i); 57 | Thread.sleep(sleep); 58 | } 59 | } 60 | } 61 | 62 | private static volatile Object foo[] = new Object[20]; 63 | 64 | private void gil() throws InterruptedException, OutOfMemoryError { 65 | int ratio = 20; 66 | for (int k = 0; k < numCycles; k++) { 67 | int n = 1 * 1024 * 512 / 3 ; 68 | List list = new LinkedList(); 69 | for (int i = 0; i < n; i++) { 70 | String[] str = new String[1024]; 71 | list.add(str); 72 | for (int r = 0; r < ratio; r++) { 73 | foo[r] = new String[1024]; 74 | } 75 | if (i % 100 == 0) { 76 | Thread.sleep(sleep); 77 | } 78 | } 79 | System.out.println("Load is finished. Sleeping..."); 80 | Thread.sleep(longSleep); 81 | list.clear(); 82 | System.out.println("Calling list.clear(). Sleeping..."); 83 | Thread.sleep(longSleep); 84 | System.gc(); 85 | System.out.println("Calling System.gc(). Sleeping..."); 86 | Thread.sleep(longSleep); 87 | } 88 | } 89 | 90 | } 91 | -------------------------------------------------------------------------------- /src/com/jelastic/verticalscaling/MemoryUsage.java: -------------------------------------------------------------------------------- 1 | package com.jelastic.verticalscaling; 2 | 3 | import java.lang.management.ManagementFactory; 4 | import java.lang.management.MemoryMXBean; 5 | import java.text.SimpleDateFormat; 6 | import java.util.Date; 7 | import java.util.logging.Level; 8 | import java.util.logging.Logger; 9 | 10 | /** 11 | * 12 | * @author ruslan 13 | */ 14 | public class MemoryUsage implements Runnable { 15 | 16 | @Override 17 | public void run() { 18 | 19 | while (true) { 20 | try { 21 | Thread.sleep(3000); 22 | } catch (InterruptedException ex) { 23 | Logger.getLogger(MemoryUsage.class.getName()).log(Level.SEVERE, null, ex); 24 | } 25 | java.lang.management.MemoryUsage mu = ManagementFactory.getMemoryMXBean().getHeapMemoryUsage(); 26 | 27 | Date dNow = new Date( ); 28 | SimpleDateFormat ft = new SimpleDateFormat ("hh:mm:ss"); 29 | 30 | print(ft.format(dNow) + " -> Init", mu.getInit()); 31 | print("Used", mu.getUsed()); 32 | print("Committed", mu.getCommitted()); 33 | print("Max", mu.getMax()); 34 | 35 | System.out.println(); 36 | } 37 | 38 | } 39 | 40 | private void print(String name, double value) { 41 | System.out.print(name + ": " + Math.round(value / 1024 / 1024) + "M "); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/com/jelastic/verticalscaling/Test.java: -------------------------------------------------------------------------------- 1 | package com.jelastic.verticalscaling; 2 | 3 | import java.io.IOException; 4 | 5 | /** 6 | * 7 | * @author ruslan 8 | */ 9 | public class Test { 10 | 11 | /** 12 | * @param args the command line arguments 13 | */ 14 | public static void main(String[] args) throws InterruptedException, IOException { 15 | System.out.println("Press to start the load test"); 16 | int sleep = 10; 17 | if (args.length > 0) { 18 | sleep = Integer.parseInt(args[0]); 19 | } 20 | int mode = 1; 21 | if (args.length > 1) { 22 | mode = Integer.parseInt(args[1]); 23 | } 24 | boolean gc = false; 25 | if (args.length > 2) { 26 | gc = Boolean.parseBoolean(args[2]); 27 | } 28 | int nGc = 1; 29 | if (args.length > 3) { 30 | nGc = Integer.parseInt(args[3]); 31 | } 32 | new Thread(new MemoryUsage()).start(); 33 | while (true) { 34 | int n = System.in.read(); 35 | if (n > -1) { 36 | Load test = new Load(sleep, mode); 37 | test.run(); 38 | test = null; 39 | } 40 | 41 | Thread.sleep(10000); 42 | if (gc) { 43 | for (int i = 0; i < nGc; i++) { 44 | System.out.println("Calling GC..."); 45 | System.gc(); 46 | } 47 | } 48 | } 49 | } 50 | 51 | } 52 | --------------------------------------------------------------------------------