Akamas Docs
3.6
3.6
  • Home
  • Getting started
    • Introduction
    • Insights for Kubernetes
    • Free Trial
    • Licensing
    • Deployment
      • Cloud Hosting
    • Security
    • Maintenance & Support (M&S) Services
      • Customer Support Services
      • Support levels for Customer Support Services
      • Support levels for software versions
      • Support levels with Akamas
  • Installing
    • Architecture
    • Docker compose installation
      • Prerequisites
        • Hardware Requirements
        • Software Requirements
        • Network requirements
      • Install Akamas dependencies
      • Install the Akamas Server
        • Online installation mode
          • Online installation behind a Proxy server
        • Offline installation mode
        • Changing UI Ports
        • Setup HTTPS configuration
      • Troubleshoot Docker installation issues
    • Kubernetes installation
      • Prerequisites
        • Cluster Requirements
        • Software Requirements
      • Install Akamas
        • Online Installation
        • Offline Installation - Private registry
      • Installing on OpenShift
      • Accessing Akamas
      • Useful commands
      • Selecting Cluster Nodes
    • Install the CLI
      • Setup the CLI
      • Initialize the CLI
      • Change CLI configuration
      • Use a proxy server
    • Verify the installation
    • Installing the toolbox
    • Install the license
    • Manage anonymous data collection
  • Managing Akamas
    • Akamas logs
    • Audit logs
    • Upgrade Akamas
      • Docker compose
      • Kubernetes
    • Monitor Akamas status
    • Backup & Recover of the Akamas Server
    • Users management
      • Accessing Keycloak admin console
      • Configure an external identity provider
        • Azure Active Directory
        • Google
      • Limit users sessions
        • Local users
        • Identity provider users
    • Collecting support information
  • Using
    • System
    • Telemetry
    • Workflow
    • Study
      • Offline Study
      • Live Study
        • Analyzing results of live optimization studies
      • Windowing
      • Parameters and constraints
  • Optimization Guides
    • Optimize application costs and resource efficiency
      • Kubernetes microservices
        • Optimize cost of a Kubernetes deployment subject to Horizontal Pod Autoscaler
        • Optimize cost of a Kubernetes microservice while preserving SLOs in production
        • Optimize cost of a Java microservice on Kubernetes while preserving SLOs in production
      • Application runtime
        • Optimizing a sample Java OpenJDK application
        • Optimizing cost of a Node.js application with performance tests
        • Optimizing cost of a Golang application with performance tests
        • Optimizing cost of a .NET application with performance tests
      • Applications running on cloud instances
        • Optimizing a sample application running on AWS
      • Spark applications
        • Optimizing a Spark application
    • Optimize application performance and reliability
      • Kubernetes microservices
        • Optimizing cost of a Kubernetes microservice while preserving SLOs in production
        • Optimizing cost of a Java microservice on Kubernetes while preserving SLOs in production
  • Integrating
    • Integrating Telemetry Providers
      • CSV provider
        • Install CSV provider
        • Create CSV telemetry instances
      • Dynatrace provider
        • Install Dynatrace provider
        • Create Dynatrace telemetry instances
          • Import Key Requests
      • Prometheus provider
        • Install Prometheus provider
        • Create Prometheus telemetry instances
        • CloudWatch Exporter
        • OracleDB Exporter
      • Spark History Server provider
        • Install Spark History Server provider
        • Create Spark History Server telemetry instances
      • NeoLoadWeb provider
        • Install NeoLoadWeb telemetry provider
        • Create NeoLoadWeb telemetry instances
      • LoadRunner Professional provider
        • Install LoadRunner Professional provider
        • Create LoadRunner Professional telemetry instances
      • LoadRunner Enterprise provider
        • Install LoadRunner Enterprise provider
        • Create LoadRunner Enterprise telemetry instances
      • AWS provider
        • Install AWS provider
        • Create AWS telemetry instances
    • Integrating Configuration Management
    • Integrating with pipelines
    • Integrating Load Testing
      • Integrating NeoLoad
      • Integrating LoadRunner Professional
      • Integrating LoadRunner Enterprise
  • Reference
    • Glossary
      • System
      • Component
      • Metric
      • Parameter
      • Component Type
      • Workflow
      • Telemetry Provider
      • Telemetry Instance
      • Optimization Pack
      • Goals & Constraints
      • KPI
      • Optimization Study
      • Workspace
      • Safety Policies
    • Construct templates
      • System template
      • Component template
      • Parameter template
      • Metric template
      • Component Types template
      • Telemetry Provider template
      • Telemetry Instance template
      • Workflows template
      • Study template
        • Goal & Constraints
        • Windowing policy
          • Trim windowing
          • Stability windowing
        • Parameter selection
        • Metric selection
        • Workload selection
        • KPIs
        • Steps
          • Baseline step
          • Bootstrap step
          • Preset step
          • Optimize step
        • Parameter rendering
        • Optimizer Options
    • Workflow Operators
      • General operator arguments
      • Executor Operator
      • FileConfigurator Operator
      • LinuxConfigurator Operator
      • WindowsExecutor Operator
      • WindowsFileConfigurator Operator
      • Sleep Operator
      • OracleExecutor Operator
      • OracleConfigurator Operator
      • SparkSSHSubmit Operator
      • SparkSubmit Operator
      • SparkLivy Operator
      • NeoLoadWeb Operator
      • LoadRunner Operator
      • LoadRunnerEnteprise Operator
    • Telemetry metric mapping
      • Dynatrace metrics mapping
      • Prometheus metrics mapping
      • NeoLoadWeb metrics mapping
      • Spark History Server metrics mapping
      • LoadRunner metrics mapping
    • Optimization Packs
      • Linux optimization pack
        • Amazon Linux
        • Amazon Linux 2
        • Amazon Linux 2022
        • CentOS 7
        • CentOS 8
        • RHEL 7
        • RHEL 8
        • Ubuntu 16.04
        • Ubuntu 18.04
        • Ubuntu 20.04
      • DotNet optimization pack
        • DotNet Core 3.1
      • Java OpenJDK optimization pack
        • Java OpenJDK 8
        • Java OpenJDK 11
        • Java OpenJDK 17
      • OpenJ9 optimization pack
        • IBM J9 VM 6
        • IBM J9 VM 8
        • Eclipse Open J9 11
      • Node JS optimization pack
        • Node JS 18
      • GO optimization pack
        • GO 1
      • Web Application optimization pack
        • Web Application
      • Docker optimization pack
        • Container
      • Kubernetes optimization pack
        • Horizontal Pod Autoscaler v1
        • Horizontal Pod Autoscaler v2
        • Kubernetes Pod
        • Kubernetes Container
        • Kubernetes Workload
        • Kubernetes Namespace
        • Kubernetes Cluster
      • WebSphere optimization pack
        • WebSphere 8.5
        • WebSphere Liberty ND
      • AWS optimization pack
        • EC2
        • Lambda
      • PostgreSQL optimization pack
        • PostgreSQL 11
        • PostgreSQL 12
      • Cassandra optimization pack
        • Cassandra
      • MySQL Database optimization pack
        • MySQL 8.0
      • Oracle Database optimization pack
        • Oracle Database 12c
        • Oracle Database 18c
        • Oracle Database 19c
        • RDS Oracle Database 11g
        • RDS Oracle Database 12c
      • MongoDB optimization pack
        • MongoDB 4
        • MongoDB 5
      • Elasticsearch optimization pack
        • Elasticsearch 6
      • Spark optimization pack
        • Spark Application 2.2.0
        • Spark Application 2.3.0
        • Spark Application 2.4.0
    • Command Line commands
      • Administration commands
      • User and Workspace management commands
      • Authentication commands
      • Resource management commands
      • Optimizer options commands
    • Release Notes
  • Knowledge Base
    • Performing load testing to support optimization activities
    • Creating custom optimization packs
    • Setting up a Konakart environment for testing Akamas
    • Modeling a sample Java-based e-commerce application (Konakart)
    • Optimizing a web application
    • Optimizing a sample Java OpenJ9 application
    • Optimizing a sample Linux system
    • Optimizing a MongoDB server instance
    • Optimizing a Kubernetes application
    • Leveraging Ansible to automate AWS instance management
    • Guidelines for optimizing AWS EC2 instances
    • Optimizing an Oracle Database server instance
    • Optimizing an Oracle Database for an e-commerce service
    • Guidelines for optimizing Oracle RDS
    • Optimizing a MySQL server database running Sysbench
    • Optimizing a MySQL server database running OLTPBench
    • Optimizing a live full-stack deployment (K8s + JVM)
    • Setup Instana integration
    • Setup Locust telemetry via CSV
    • Setup AppDynamics integration
Powered by GitBook
On this page
  • Environment Setup
  • Environment
  • Prometheus and exporters
  • Optimization Setup
  • System
  • Telemetry
  • Workflow
  • Study

Was this helpful?

Export as PDF
  1. Knowledge Base

Optimizing an Oracle Database for an e-commerce service

Last updated 1 year ago

Was this helpful?

In this example study, we will tune the initialization parameters of an Oracle Database server instance to minimize the memory required for running , a popular Java e-commerce service, without significantly impacting the responsiveness of the whole system.

We’ll use to stress the system for the test, while we will leverage the to extract the metrics.

Environment Setup

Environment

For this study, we will use three dedicated machines:

  • oradb.mycompany.com, hosting an Oracle Database 19c instance

  • konakart.mycompany.com, running the KonaKart Community Edition service

  • akamas.mycompany.com, which generates the workload using JMeter and will host the instance

Refer to the following links to install and configure KonaKart Community Edition:

  • : install and configure the service

  • : install the demo dataset

For this use case, we provisioned the database on a VM on , which allows us to easily provision licensed instances on demand.

Prometheus and exporters

Install the OracleDB Prometheus exporter

Through the OracleDB Prometheus exporter, we can publish as metrics the results of the arbitrary queries defined in the configuration file. In our case, we’ll use it to extract valuable performance metrics from Oracle’s Dynamic Performance (V$) Views.

docker run -d --name orabench_exporter --restart always \
  -p 9161:9161 \
  -v ~/oracledb_exporter/cust-metrics.toml:/cust-metrics.toml \
  -e CUSTOM_METRICS=/cust-metrics.toml \
  -e DATA_SOURCE_NAME='user/passwd@//oradb.mycompany.com:1521/konakart' \
  iamseth/oracledb_exporter

The exporter will publish the metrics on the specified port 9161.

Here’s the metrics file used to run the exporter:

[[metric]]
context= "memory"
labels= [ "component" ]
metricsdesc= { size="Component memory extracted from v$memory_dynamic_components in Oracle." }
request = '''
SELECT component, current_size as "size"
FROM V$MEMORY_DYNAMIC_COMPONENTS
UNION
SELECT name, bytes as "size"
FROM V$SGAINFO
WHERE name in ('Free SGA Memory Available', 'Redo Buffers', 'Maximum SGA Size')
'''

[[metric]]
context = "activity"
metricsdesc = { value="Generic counter metric from v$sysstat view in Oracle." }
fieldtoappend = "name"
request = '''
SELECT name, value
FROM V$SYSSTAT WHERE name IN (
  'execute count',
  'user commits', 'user rollbacks',
  'db block gets from cache', 'consistent gets from cache', 'physical reads cache', /* CACHE */
  'redo log space requests'
 )
 '''

[[metric]]
context = "system_event"
labels = [ "event", "wait_class" ]
request = '''
SELECT
  event, wait_class,
  total_waits, time_waited
FROM V$SYSTEM_EVENT
'''
[metric.metricsdesc]
  total_waits= "Total number of waits for the event as per V$SYSTEM_EVENT in Oracle."
  time_waited= "Total time waited for the event (in hundredths of seconds) as per V$SYSTEM_EVENT in Oracle."

Install and configure Prometheus

Using the following snippet we configure Prometheus to fetch metrics from:

  • the JMeter exporter exposing the load-generator stats

  • the OracleDB exporter monitoring the database

scrape_configs:
  - job_name: jmeter
    static_configs:
      - targets: ['akamas.mycompany.com:9270']
    relabel_configs:
      - source_labels: [__address__]
        action: replace
        regex: "(.*):.*"
        target_label: instance

  - job_name: oracle-exp
    static_configs:
      - targets: ['akamas.mycompany.com:9161']
        labels:
          instance: oradb

Setup the load-generator

The load generator runs containerized on the akamas.mycomopany.com instance using the attached Konakart_optimizePerf.jmx configuration file.

<?xml version="1.0" encoding="UTF-8"?>
<jmeterTestPlan version="1.2" properties="5.0" jmeter="5.3">
  <hashTree>
    <TestPlan guiclass="TestPlanGui" testclass="TestPlan" testname="Test Plan" enabled="true">
      <stringProp name="TestPlan.comments"></stringProp>
      <boolProp name="TestPlan.functional_mode">false</boolProp>
      <boolProp name="TestPlan.tearDown_on_shutdown">true</boolProp>
      <boolProp name="TestPlan.serialize_threadgroups">false</boolProp>
      <elementProp name="TestPlan.user_defined_variables" elementType="Arguments" guiclass="ArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
        <collectionProp name="Arguments.arguments">
          <elementProp name="HOST" elementType="Argument">
            <stringProp name="Argument.name">HOST</stringProp>
            <stringProp name="Argument.value">${__P(HOST,konakartoraclecloud.lab.akamas.io)}</stringProp>
            <stringProp name="Argument.metadata">=</stringProp>
          </elementProp>
          <elementProp name="VUSER" elementType="Argument">
            <stringProp name="Argument.name">VUSER</stringProp>
            <stringProp name="Argument.value">${__P(VUSER,60)}</stringProp>
            <stringProp name="Argument.metadata">=</stringProp>
          </elementProp>
        </collectionProp>
      </elementProp>
      <stringProp name="TestPlan.user_define_classpath"></stringProp>
    </TestPlan>
    <hashTree>
      <kg.apc.jmeter.threads.UltimateThreadGroup guiclass="kg.apc.jmeter.threads.UltimateThreadGroupGui" testclass="kg.apc.jmeter.threads.UltimateThreadGroup" testname=" Thread Group" enabled="true">
        <collectionProp name="ultimatethreadgroupdata">
          <collectionProp name="682260423">
            <stringProp name="-1375672883">${__P(VUSER,10)}</stringProp>
            <stringProp name="0">0</stringProp>
            <stringProp name="49586">200</stringProp>
            <stringProp name="53430">600</stringProp>
            <stringProp name="48">0</stringProp>
          </collectionProp>
        </collectionProp>
        <elementProp name="ThreadGroup.main_controller" elementType="LoopController" guiclass="LoopControlPanel" testclass="LoopController" testname="Loop Controller" enabled="true">
          <boolProp name="LoopController.continue_forever">false</boolProp>
          <intProp name="LoopController.loops">-1</intProp>
        </elementProp>
        <stringProp name="ThreadGroup.on_sample_error">startnextloop</stringProp>
      </kg.apc.jmeter.threads.UltimateThreadGroup>
      <hashTree>
        <RandomVariableConfig guiclass="TestBeanGUI" testclass="RandomVariableConfig" testname="Random catId" enabled="true">
          <stringProp name="maximumValue">30</stringProp>
          <stringProp name="minimumValue">1</stringProp>
          <stringProp name="outputFormat"></stringProp>
          <boolProp name="perThread">true</boolProp>
          <stringProp name="randomSeed">666</stringProp>
          <stringProp name="variableName">catId</stringProp>
        </RandomVariableConfig>
        <hashTree/>
        <HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="Welcome" enabled="true">
          <elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
            <collectionProp name="Arguments.arguments"/>
          </elementProp>
          <stringProp name="HTTPSampler.domain">${HOST}</stringProp>
          <stringProp name="HTTPSampler.port">8780</stringProp>
          <stringProp name="HTTPSampler.protocol">http</stringProp>
          <stringProp name="HTTPSampler.contentEncoding"></stringProp>
          <stringProp name="HTTPSampler.path">konakart/Welcome.action</stringProp>
          <stringProp name="HTTPSampler.method">GET</stringProp>
          <boolProp name="HTTPSampler.follow_redirects">false</boolProp>
          <boolProp name="HTTPSampler.auto_redirects">true</boolProp>
          <boolProp name="HTTPSampler.use_keepalive">true</boolProp>
          <boolProp name="HTTPSampler.DO_MULTIPART_POST">false</boolProp>
          <boolProp name="HTTPSampler.BROWSER_COMPATIBLE_MULTIPART">true</boolProp>
          <boolProp name="HTTPSampler.image_parser">true</boolProp>
          <boolProp name="HTTPSampler.concurrentDwn">true</boolProp>
          <stringProp name="HTTPSampler.embedded_url_re"></stringProp>
          <stringProp name="HTTPSampler.connect_timeout"></stringProp>
          <stringProp name="HTTPSampler.response_timeout"></stringProp>
        </HTTPSamplerProxy>
        <hashTree/>
        <HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="SelectCat" enabled="true">
          <elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
            <collectionProp name="Arguments.arguments"/>
          </elementProp>
          <stringProp name="HTTPSampler.domain">${HOST}</stringProp>
          <stringProp name="HTTPSampler.port">8780</stringProp>
          <stringProp name="HTTPSampler.protocol">http</stringProp>
          <stringProp name="HTTPSampler.contentEncoding"></stringProp>
          <stringProp name="HTTPSampler.path">konakart/SelectCat.action?catId=${catId}</stringProp>
          <stringProp name="HTTPSampler.method">GET</stringProp>
          <boolProp name="HTTPSampler.follow_redirects">false</boolProp>
          <boolProp name="HTTPSampler.auto_redirects">true</boolProp>
          <boolProp name="HTTPSampler.use_keepalive">true</boolProp>
          <boolProp name="HTTPSampler.DO_MULTIPART_POST">false</boolProp>
          <boolProp name="HTTPSampler.BROWSER_COMPATIBLE_MULTIPART">true</boolProp>
          <boolProp name="HTTPSampler.image_parser">true</boolProp>
          <boolProp name="HTTPSampler.concurrentDwn">true</boolProp>
          <stringProp name="HTTPSampler.embedded_url_re"></stringProp>
          <stringProp name="HTTPSampler.connect_timeout"></stringProp>
          <stringProp name="HTTPSampler.response_timeout"></stringProp>
        </HTTPSamplerProxy>
        <hashTree/>
        <com.github.johrstrom.listener.PrometheusListener guiclass="com.github.johrstrom.listener.gui.PrometheusListenerGui" testclass="com.github.johrstrom.listener.PrometheusListener" testname="Prometheus Listener" enabled="true">
          <collectionProp name="prometheus.collector_definitions">
            <elementProp name="" elementType="com.github.johrstrom.listener.ListenerCollectorConfig">
              <stringProp name="collector.help">Sampler Response Time</stringProp>
              <stringProp name="collector.metric_name">ResponseTime</stringProp>
              <stringProp name="collector.type">SUMMARY</stringProp>
              <collectionProp name="collector.labels">
                <stringProp name="102727412">label</stringProp>
                <stringProp name="3059181">code</stringProp>
              </collectionProp>
              <stringProp name="collector.quantiles_or_buckets">0.5,0.01|0.85,0.01|0.9,0.01|0.99,0.01;60</stringProp>
              <stringProp name="listener.collector.listen_to">samples</stringProp>
              <stringProp name="listener.collector.measuring">ResponseTime</stringProp>
            </elementProp>
            <elementProp name="" elementType="com.github.johrstrom.listener.ListenerCollectorConfig">
              <stringProp name="collector.help">Success and failure ratio</stringProp>
              <stringProp name="collector.metric_name">Ratio</stringProp>
              <stringProp name="collector.type">SUCCESS_RATIO</stringProp>
              <collectionProp name="collector.labels">
                <stringProp name="102727412">label</stringProp>
                <stringProp name="3059181">code</stringProp>
              </collectionProp>
              <stringProp name="collector.quantiles_or_buckets"></stringProp>
              <stringProp name="listener.collector.listen_to">samples</stringProp>
              <stringProp name="listener.collector.measuring">SuccessRatio</stringProp>
            </elementProp>
          </collectionProp>
        </com.github.johrstrom.listener.PrometheusListener>
        <hashTree/>
        <ResultCollector guiclass="ViewResultsFullVisualizer" testclass="ResultCollector" testname="View Results Tree" enabled="false">
          <boolProp name="ResultCollector.error_logging">false</boolProp>
          <objProp>
            <name>saveConfig</name>
            <value class="SampleSaveConfiguration">
              <time>true</time>
              <latency>true</latency>
              <timestamp>true</timestamp>
              <success>true</success>
              <label>true</label>
              <code>true</code>
              <message>true</message>
              <threadName>true</threadName>
              <dataType>true</dataType>
              <encoding>false</encoding>
              <assertions>true</assertions>
              <subresults>true</subresults>
              <responseData>false</responseData>
              <samplerData>false</samplerData>
              <xml>false</xml>
              <fieldNames>true</fieldNames>
              <responseHeaders>false</responseHeaders>
              <requestHeaders>false</requestHeaders>
              <responseDataOnError>false</responseDataOnError>
              <saveAssertionResultsFailureMessage>true</saveAssertionResultsFailureMessage>
              <assertionsResultsToSave>0</assertionsResultsToSave>
              <bytes>true</bytes>
              <sentBytes>true</sentBytes>
              <url>true</url>
              <threadCounts>true</threadCounts>
              <idleTime>true</idleTime>
              <connectTime>true</connectTime>
            </value>
          </objProp>
          <stringProp name="filename"></stringProp>
        </ResultCollector>
        <hashTree/>
        <ResultCollector guiclass="SummaryReport" testclass="ResultCollector" testname="Summary Report" enabled="false">
          <boolProp name="ResultCollector.error_logging">false</boolProp>
          <objProp>
            <name>saveConfig</name>
            <value class="SampleSaveConfiguration">
              <time>true</time>
              <latency>true</latency>
              <timestamp>true</timestamp>
              <success>true</success>
              <label>true</label>
              <code>true</code>
              <message>true</message>
              <threadName>true</threadName>
              <dataType>true</dataType>
              <encoding>false</encoding>
              <assertions>true</assertions>
              <subresults>true</subresults>
              <responseData>false</responseData>
              <samplerData>false</samplerData>
              <xml>false</xml>
              <fieldNames>true</fieldNames>
              <responseHeaders>false</responseHeaders>
              <requestHeaders>false</requestHeaders>
              <responseDataOnError>false</responseDataOnError>
              <saveAssertionResultsFailureMessage>true</saveAssertionResultsFailureMessage>
              <assertionsResultsToSave>0</assertionsResultsToSave>
              <bytes>true</bytes>
              <sentBytes>true</sentBytes>
              <url>true</url>
              <threadCounts>true</threadCounts>
              <idleTime>true</idleTime>
              <connectTime>true</connectTime>
            </value>
          </objProp>
          <stringProp name="filename"></stringProp>
        </ResultCollector>
        <hashTree/>
      </hashTree>
      <kg.apc.jmeter.threads.UltimateThreadGroup guiclass="kg.apc.jmeter.threads.UltimateThreadGroupGui" testclass="kg.apc.jmeter.threads.UltimateThreadGroup" testname="jp@gc - Ultimate Thread Group - slow slope" enabled="false">
        <collectionProp name="ultimatethreadgroupdata">
          <collectionProp name="-811668396">
            <stringProp name="50">2</stringProp>
            <stringProp name="48">0</stringProp>
            <stringProp name="1722">60</stringProp>
            <stringProp name="1508508">1140</stringProp>
            <stringProp name="0"></stringProp>
          </collectionProp>
          <collectionProp name="1110318546">
            <stringProp name="50">2</stringProp>
            <stringProp name="50547">300</stringProp>
            <stringProp name="1722">60</stringProp>
            <stringProp name="55476">840</stringProp>
            <stringProp name="0"></stringProp>
          </collectionProp>
          <collectionProp name="-277728215">
            <stringProp name="50">2</stringProp>
            <stringProp name="53430">600</stringProp>
            <stringProp name="1722">60</stringProp>
            <stringProp name="52593">540</stringProp>
            <stringProp name="0"></stringProp>
          </collectionProp>
          <collectionProp name="1889215593">
            <stringProp name="50">2</stringProp>
            <stringProp name="56313">900</stringProp>
            <stringProp name="1722">60</stringProp>
            <stringProp name="49710">240</stringProp>
            <stringProp name="0"></stringProp>
          </collectionProp>
        </collectionProp>
        <elementProp name="ThreadGroup.main_controller" elementType="LoopController" guiclass="LoopControlPanel" testclass="LoopController" testname="Loop Controller" enabled="true">
          <boolProp name="LoopController.continue_forever">false</boolProp>
          <intProp name="LoopController.loops">-1</intProp>
        </elementProp>
        <stringProp name="ThreadGroup.on_sample_error">continue</stringProp>
      </kg.apc.jmeter.threads.UltimateThreadGroup>
      <hashTree>
        <RandomVariableConfig guiclass="TestBeanGUI" testclass="RandomVariableConfig" testname="Random catId" enabled="true">
          <stringProp name="maximumValue">30</stringProp>
          <stringProp name="minimumValue">1</stringProp>
          <stringProp name="outputFormat"></stringProp>
          <boolProp name="perThread">true</boolProp>
          <stringProp name="randomSeed">666</stringProp>
          <stringProp name="variableName">catId</stringProp>
        </RandomVariableConfig>
        <hashTree/>
        <HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="Welcome" enabled="true">
          <elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
            <collectionProp name="Arguments.arguments"/>
          </elementProp>
          <stringProp name="HTTPSampler.domain">${__P(HOST,konakartoraclecloud.lab.akamas.io)}</stringProp>
          <stringProp name="HTTPSampler.port">8780</stringProp>
          <stringProp name="HTTPSampler.protocol">http</stringProp>
          <stringProp name="HTTPSampler.contentEncoding"></stringProp>
          <stringProp name="HTTPSampler.path">konakart/Welcome.action</stringProp>
          <stringProp name="HTTPSampler.method">GET</stringProp>
          <boolProp name="HTTPSampler.follow_redirects">false</boolProp>
          <boolProp name="HTTPSampler.auto_redirects">true</boolProp>
          <boolProp name="HTTPSampler.use_keepalive">true</boolProp>
          <boolProp name="HTTPSampler.DO_MULTIPART_POST">false</boolProp>
          <boolProp name="HTTPSampler.BROWSER_COMPATIBLE_MULTIPART">true</boolProp>
          <boolProp name="HTTPSampler.image_parser">true</boolProp>
          <boolProp name="HTTPSampler.concurrentDwn">true</boolProp>
          <stringProp name="HTTPSampler.embedded_url_re"></stringProp>
          <stringProp name="HTTPSampler.connect_timeout"></stringProp>
          <stringProp name="HTTPSampler.response_timeout"></stringProp>
        </HTTPSamplerProxy>
        <hashTree/>
        <TestAction guiclass="TestActionGui" testclass="TestAction" testname="think time" enabled="true">
          <intProp name="ActionProcessor.action">1</intProp>
          <intProp name="ActionProcessor.target">0</intProp>
          <stringProp name="ActionProcessor.duration">100</stringProp>
        </TestAction>
        <hashTree/>
        <HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="SelectCat" enabled="true">
          <elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
            <collectionProp name="Arguments.arguments"/>
          </elementProp>
          <stringProp name="HTTPSampler.domain">${__P(HOST,konakartoraclecloud.lab.akamas.io)}</stringProp>
          <stringProp name="HTTPSampler.port">8780</stringProp>
          <stringProp name="HTTPSampler.protocol">http</stringProp>
          <stringProp name="HTTPSampler.contentEncoding"></stringProp>
          <stringProp name="HTTPSampler.path">konakart/SelectCat.action?catId=${catId}</stringProp>
          <stringProp name="HTTPSampler.method">GET</stringProp>
          <boolProp name="HTTPSampler.follow_redirects">false</boolProp>
          <boolProp name="HTTPSampler.auto_redirects">true</boolProp>
          <boolProp name="HTTPSampler.use_keepalive">true</boolProp>
          <boolProp name="HTTPSampler.DO_MULTIPART_POST">false</boolProp>
          <boolProp name="HTTPSampler.BROWSER_COMPATIBLE_MULTIPART">true</boolProp>
          <boolProp name="HTTPSampler.image_parser">true</boolProp>
          <boolProp name="HTTPSampler.concurrentDwn">true</boolProp>
          <stringProp name="HTTPSampler.embedded_url_re"></stringProp>
          <stringProp name="HTTPSampler.connect_timeout"></stringProp>
          <stringProp name="HTTPSampler.response_timeout"></stringProp>
        </HTTPSamplerProxy>
        <hashTree/>
        <TestAction guiclass="TestActionGui" testclass="TestAction" testname="think time" enabled="true">
          <intProp name="ActionProcessor.action">1</intProp>
          <intProp name="ActionProcessor.target">0</intProp>
          <stringProp name="ActionProcessor.duration">100</stringProp>
        </TestAction>
        <hashTree/>
        <com.github.johrstrom.listener.PrometheusListener guiclass="com.github.johrstrom.listener.gui.PrometheusListenerGui" testclass="com.github.johrstrom.listener.PrometheusListener" testname="Prometheus Listener" enabled="true">
          <collectionProp name="prometheus.collector_definitions">
            <elementProp name="" elementType="com.github.johrstrom.listener.ListenerCollectorConfig">
              <stringProp name="collector.help">Sampler Response Time</stringProp>
              <stringProp name="collector.metric_name">ResponseTime</stringProp>
              <stringProp name="collector.type">SUMMARY</stringProp>
              <collectionProp name="collector.labels">
                <stringProp name="102727412">label</stringProp>
                <stringProp name="3059181">code</stringProp>
              </collectionProp>
              <stringProp name="collector.quantiles_or_buckets">0.5,0.01|0.85,0.01|0.9,0.01|0.99,0.01;60</stringProp>
              <stringProp name="listener.collector.listen_to">samples</stringProp>
              <stringProp name="listener.collector.measuring">ResponseTime</stringProp>
            </elementProp>
            <elementProp name="" elementType="com.github.johrstrom.listener.ListenerCollectorConfig">
              <stringProp name="collector.help">Success and failure ratio</stringProp>
              <stringProp name="collector.metric_name">Ratio</stringProp>
              <stringProp name="collector.type">SUCCESS_RATIO</stringProp>
              <collectionProp name="collector.labels">
                <stringProp name="102727412">label</stringProp>
                <stringProp name="3059181">code</stringProp>
              </collectionProp>
              <stringProp name="collector.quantiles_or_buckets"></stringProp>
              <stringProp name="listener.collector.listen_to">samples</stringProp>
              <stringProp name="listener.collector.measuring">SuccessRatio</stringProp>
            </elementProp>
          </collectionProp>
        </com.github.johrstrom.listener.PrometheusListener>
        <hashTree/>
        <ResultCollector guiclass="ViewResultsFullVisualizer" testclass="ResultCollector" testname="View Results Tree" enabled="false">
          <boolProp name="ResultCollector.error_logging">false</boolProp>
          <objProp>
            <name>saveConfig</name>
            <value class="SampleSaveConfiguration">
              <time>true</time>
              <latency>true</latency>
              <timestamp>true</timestamp>
              <success>true</success>
              <label>true</label>
              <code>true</code>
              <message>true</message>
              <threadName>true</threadName>
              <dataType>true</dataType>
              <encoding>false</encoding>
              <assertions>true</assertions>
              <subresults>true</subresults>
              <responseData>false</responseData>
              <samplerData>false</samplerData>
              <xml>false</xml>
              <fieldNames>true</fieldNames>
              <responseHeaders>false</responseHeaders>
              <requestHeaders>false</requestHeaders>
              <responseDataOnError>false</responseDataOnError>
              <saveAssertionResultsFailureMessage>true</saveAssertionResultsFailureMessage>
              <assertionsResultsToSave>0</assertionsResultsToSave>
              <bytes>true</bytes>
              <sentBytes>true</sentBytes>
              <url>true</url>
              <threadCounts>true</threadCounts>
              <idleTime>true</idleTime>
              <connectTime>true</connectTime>
            </value>
          </objProp>
          <stringProp name="filename"></stringProp>
        </ResultCollector>
        <hashTree/>
        <ResultCollector guiclass="SummaryReport" testclass="ResultCollector" testname="Summary Report" enabled="false">
          <boolProp name="ResultCollector.error_logging">false</boolProp>
          <objProp>
            <name>saveConfig</name>
            <value class="SampleSaveConfiguration">
              <time>true</time>
              <latency>true</latency>
              <timestamp>true</timestamp>
              <success>true</success>
              <label>true</label>
              <code>true</code>
              <message>true</message>
              <threadName>true</threadName>
              <dataType>true</dataType>
              <encoding>false</encoding>
              <assertions>true</assertions>
              <subresults>true</subresults>
              <responseData>false</responseData>
              <samplerData>false</samplerData>
              <xml>false</xml>
              <fieldNames>true</fieldNames>
              <responseHeaders>false</responseHeaders>
              <requestHeaders>false</requestHeaders>
              <responseDataOnError>false</responseDataOnError>
              <saveAssertionResultsFailureMessage>true</saveAssertionResultsFailureMessage>
              <assertionsResultsToSave>0</assertionsResultsToSave>
              <bytes>true</bytes>
              <sentBytes>true</sentBytes>
              <url>true</url>
              <threadCounts>true</threadCounts>
              <idleTime>true</idleTime>
              <connectTime>true</connectTime>
            </value>
          </objProp>
          <stringProp name="filename"></stringProp>
        </ResultCollector>
        <hashTree/>
      </hashTree>
      <kg.apc.jmeter.threads.UltimateThreadGroup guiclass="kg.apc.jmeter.threads.UltimateThreadGroupGui" testclass="kg.apc.jmeter.threads.UltimateThreadGroup" testname="jp@gc - Ultimate Thread Group  - steep slope" enabled="false">
        <collectionProp name="ultimatethreadgroupdata">
          <collectionProp name="-1293805452">
            <stringProp name="1696">55</stringProp>
            <stringProp name="48">0</stringProp>
            <stringProp name="50547">300</stringProp>
            <stringProp name="1507521">1035</stringProp>
            <stringProp name="0"></stringProp>
          </collectionProp>
          <collectionProp name="-1729043283">
            <stringProp name="52">4</stringProp>
            <stringProp name="52593">540</stringProp>
            <stringProp name="1598">20</stringProp>
            <stringProp name="54613">775</stringProp>
            <stringProp name="0"></stringProp>
          </collectionProp>
          <collectionProp name="110060986">
            <stringProp name="53">5</stringProp>
            <stringProp name="55352">800</stringProp>
            <stringProp name="1603">25</stringProp>
            <stringProp name="52500">510</stringProp>
            <stringProp name="0"></stringProp>
          </collectionProp>
          <collectionProp name="-1520762789">
            <stringProp name="54">6</stringProp>
            <stringProp name="1507614">1065</stringProp>
            <stringProp name="1629">30</stringProp>
            <stringProp name="49710">240</stringProp>
            <stringProp name="0"></stringProp>
          </collectionProp>
        </collectionProp>
        <elementProp name="ThreadGroup.main_controller" elementType="LoopController" guiclass="LoopControlPanel" testclass="LoopController" testname="Loop Controller" enabled="true">
          <boolProp name="LoopController.continue_forever">false</boolProp>
          <intProp name="LoopController.loops">-1</intProp>
        </elementProp>
        <stringProp name="ThreadGroup.on_sample_error">continue</stringProp>
      </kg.apc.jmeter.threads.UltimateThreadGroup>
      <hashTree>
        <RandomVariableConfig guiclass="TestBeanGUI" testclass="RandomVariableConfig" testname="Random catId" enabled="true">
          <stringProp name="maximumValue">30</stringProp>
          <stringProp name="minimumValue">1</stringProp>
          <stringProp name="outputFormat"></stringProp>
          <boolProp name="perThread">true</boolProp>
          <stringProp name="randomSeed">666</stringProp>
          <stringProp name="variableName">catId</stringProp>
        </RandomVariableConfig>
        <hashTree/>
        <HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="Welcome" enabled="true">
          <elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
            <collectionProp name="Arguments.arguments"/>
          </elementProp>
          <stringProp name="HTTPSampler.domain">${__P(HOST,konakartoraclecloud.lab.akamas.io)}</stringProp>
          <stringProp name="HTTPSampler.port">8780</stringProp>
          <stringProp name="HTTPSampler.protocol">http</stringProp>
          <stringProp name="HTTPSampler.contentEncoding"></stringProp>
          <stringProp name="HTTPSampler.path">konakart/Welcome.action</stringProp>
          <stringProp name="HTTPSampler.method">GET</stringProp>
          <boolProp name="HTTPSampler.follow_redirects">false</boolProp>
          <boolProp name="HTTPSampler.auto_redirects">true</boolProp>
          <boolProp name="HTTPSampler.use_keepalive">true</boolProp>
          <boolProp name="HTTPSampler.DO_MULTIPART_POST">false</boolProp>
          <boolProp name="HTTPSampler.BROWSER_COMPATIBLE_MULTIPART">true</boolProp>
          <boolProp name="HTTPSampler.image_parser">true</boolProp>
          <boolProp name="HTTPSampler.concurrentDwn">true</boolProp>
          <stringProp name="HTTPSampler.embedded_url_re"></stringProp>
          <stringProp name="HTTPSampler.connect_timeout"></stringProp>
          <stringProp name="HTTPSampler.response_timeout"></stringProp>
        </HTTPSamplerProxy>
        <hashTree/>
        <HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="SelectCat" enabled="true">
          <elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
            <collectionProp name="Arguments.arguments"/>
          </elementProp>
          <stringProp name="HTTPSampler.domain">${__P(HOST,konakartoraclecloud.lab.akamas.io)}</stringProp>
          <stringProp name="HTTPSampler.port">8780</stringProp>
          <stringProp name="HTTPSampler.protocol">http</stringProp>
          <stringProp name="HTTPSampler.contentEncoding"></stringProp>
          <stringProp name="HTTPSampler.path">konakart/SelectCat.action?catId=${catId}</stringProp>
          <stringProp name="HTTPSampler.method">GET</stringProp>
          <boolProp name="HTTPSampler.follow_redirects">false</boolProp>
          <boolProp name="HTTPSampler.auto_redirects">true</boolProp>
          <boolProp name="HTTPSampler.use_keepalive">true</boolProp>
          <boolProp name="HTTPSampler.DO_MULTIPART_POST">false</boolProp>
          <boolProp name="HTTPSampler.BROWSER_COMPATIBLE_MULTIPART">true</boolProp>
          <boolProp name="HTTPSampler.image_parser">true</boolProp>
          <boolProp name="HTTPSampler.concurrentDwn">true</boolProp>
          <stringProp name="HTTPSampler.embedded_url_re"></stringProp>
          <stringProp name="HTTPSampler.connect_timeout"></stringProp>
          <stringProp name="HTTPSampler.response_timeout"></stringProp>
        </HTTPSamplerProxy>
        <hashTree/>
        <com.github.johrstrom.listener.PrometheusListener guiclass="com.github.johrstrom.listener.gui.PrometheusListenerGui" testclass="com.github.johrstrom.listener.PrometheusListener" testname="Prometheus Listener" enabled="true">
          <collectionProp name="prometheus.collector_definitions">
            <elementProp name="" elementType="com.github.johrstrom.listener.ListenerCollectorConfig">
              <stringProp name="collector.help">Sampler Response Time</stringProp>
              <stringProp name="collector.metric_name">ResponseTime</stringProp>
              <stringProp name="collector.type">SUMMARY</stringProp>
              <collectionProp name="collector.labels">
                <stringProp name="102727412">label</stringProp>
                <stringProp name="3059181">code</stringProp>
              </collectionProp>
              <stringProp name="collector.quantiles_or_buckets">0.5,0.01|0.85,0.01|0.9,0.01|0.99,0.01;60</stringProp>
              <stringProp name="listener.collector.listen_to">samples</stringProp>
              <stringProp name="listener.collector.measuring">ResponseTime</stringProp>
            </elementProp>
            <elementProp name="" elementType="com.github.johrstrom.listener.ListenerCollectorConfig">
              <stringProp name="collector.help">Success and failure ratio</stringProp>
              <stringProp name="collector.metric_name">Ratio</stringProp>
              <stringProp name="collector.type">SUCCESS_RATIO</stringProp>
              <collectionProp name="collector.labels">
                <stringProp name="102727412">label</stringProp>
                <stringProp name="3059181">code</stringProp>
              </collectionProp>
              <stringProp name="collector.quantiles_or_buckets"></stringProp>
              <stringProp name="listener.collector.listen_to">samples</stringProp>
              <stringProp name="listener.collector.measuring">SuccessRatio</stringProp>
            </elementProp>
          </collectionProp>
        </com.github.johrstrom.listener.PrometheusListener>
        <hashTree/>
        <ResultCollector guiclass="ViewResultsFullVisualizer" testclass="ResultCollector" testname="View Results Tree" enabled="false">
          <boolProp name="ResultCollector.error_logging">false</boolProp>
          <objProp>
            <name>saveConfig</name>
            <value class="SampleSaveConfiguration">
              <time>true</time>
              <latency>true</latency>
              <timestamp>true</timestamp>
              <success>true</success>
              <label>true</label>
              <code>true</code>
              <message>true</message>
              <threadName>true</threadName>
              <dataType>true</dataType>
              <encoding>false</encoding>
              <assertions>true</assertions>
              <subresults>true</subresults>
              <responseData>false</responseData>
              <samplerData>false</samplerData>
              <xml>false</xml>
              <fieldNames>true</fieldNames>
              <responseHeaders>false</responseHeaders>
              <requestHeaders>false</requestHeaders>
              <responseDataOnError>false</responseDataOnError>
              <saveAssertionResultsFailureMessage>true</saveAssertionResultsFailureMessage>
              <assertionsResultsToSave>0</assertionsResultsToSave>
              <bytes>true</bytes>
              <sentBytes>true</sentBytes>
              <url>true</url>
              <threadCounts>true</threadCounts>
              <idleTime>true</idleTime>
              <connectTime>true</connectTime>
            </value>
          </objProp>
          <stringProp name="filename"></stringProp>
        </ResultCollector>
        <hashTree/>
        <ResultCollector guiclass="SummaryReport" testclass="ResultCollector" testname="Summary Report" enabled="false">
          <boolProp name="ResultCollector.error_logging">false</boolProp>
          <objProp>
            <name>saveConfig</name>
            <value class="SampleSaveConfiguration">
              <time>true</time>
              <latency>true</latency>
              <timestamp>true</timestamp>
              <success>true</success>
              <label>true</label>
              <code>true</code>
              <message>true</message>
              <threadName>true</threadName>
              <dataType>true</dataType>
              <encoding>false</encoding>
              <assertions>true</assertions>
              <subresults>true</subresults>
              <responseData>false</responseData>
              <samplerData>false</samplerData>
              <xml>false</xml>
              <fieldNames>true</fieldNames>
              <responseHeaders>false</responseHeaders>
              <requestHeaders>false</requestHeaders>
              <responseDataOnError>false</responseDataOnError>
              <saveAssertionResultsFailureMessage>true</saveAssertionResultsFailureMessage>
              <assertionsResultsToSave>0</assertionsResultsToSave>
              <bytes>true</bytes>
              <sentBytes>true</sentBytes>
              <url>true</url>
              <threadCounts>true</threadCounts>
              <idleTime>true</idleTime>
              <connectTime>true</connectTime>
            </value>
          </objProp>
          <stringProp name="filename"></stringProp>
        </ResultCollector>
        <hashTree/>
      </hashTree>
      <kg.apc.jmeter.threads.UltimateThreadGroup guiclass="kg.apc.jmeter.threads.UltimateThreadGroupGui" testclass="kg.apc.jmeter.threads.UltimateThreadGroup" testname="jp@gc - Ultimate Thread Group - Infinite slope" enabled="false">
        <collectionProp name="ultimatethreadgroupdata">
          <collectionProp name="-477682307">
            <stringProp name="1722">60</stringProp>
            <stringProp name="0">0</stringProp>
            <stringProp name="1572771">3600</stringProp>
            <stringProp name="0"></stringProp>
            <stringProp name="0"></stringProp>
          </collectionProp>
        </collectionProp>
        <elementProp name="ThreadGroup.main_controller" elementType="LoopController" guiclass="LoopControlPanel" testclass="LoopController" testname="Loop Controller" enabled="true">
          <boolProp name="LoopController.continue_forever">false</boolProp>
          <intProp name="LoopController.loops">-1</intProp>
        </elementProp>
        <stringProp name="ThreadGroup.on_sample_error">continue</stringProp>
      </kg.apc.jmeter.threads.UltimateThreadGroup>
      <hashTree>
        <RandomVariableConfig guiclass="TestBeanGUI" testclass="RandomVariableConfig" testname="Random catId" enabled="true">
          <stringProp name="maximumValue">30</stringProp>
          <stringProp name="minimumValue">1</stringProp>
          <stringProp name="outputFormat"></stringProp>
          <boolProp name="perThread">true</boolProp>
          <stringProp name="randomSeed">666</stringProp>
          <stringProp name="variableName">catId</stringProp>
        </RandomVariableConfig>
        <hashTree/>
        <HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="Welcome" enabled="true">
          <elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
            <collectionProp name="Arguments.arguments"/>
          </elementProp>
          <stringProp name="HTTPSampler.domain">${__P(HOST,konakartoraclecloud.lab.akamas.io)}</stringProp>
          <stringProp name="HTTPSampler.port">8780</stringProp>
          <stringProp name="HTTPSampler.protocol">http</stringProp>
          <stringProp name="HTTPSampler.contentEncoding"></stringProp>
          <stringProp name="HTTPSampler.path">konakart/Welcome.action</stringProp>
          <stringProp name="HTTPSampler.method">GET</stringProp>
          <boolProp name="HTTPSampler.follow_redirects">false</boolProp>
          <boolProp name="HTTPSampler.auto_redirects">true</boolProp>
          <boolProp name="HTTPSampler.use_keepalive">true</boolProp>
          <boolProp name="HTTPSampler.DO_MULTIPART_POST">false</boolProp>
          <boolProp name="HTTPSampler.BROWSER_COMPATIBLE_MULTIPART">true</boolProp>
          <boolProp name="HTTPSampler.image_parser">true</boolProp>
          <boolProp name="HTTPSampler.concurrentDwn">true</boolProp>
          <stringProp name="HTTPSampler.embedded_url_re"></stringProp>
          <stringProp name="HTTPSampler.connect_timeout"></stringProp>
          <stringProp name="HTTPSampler.response_timeout"></stringProp>
        </HTTPSamplerProxy>
        <hashTree/>
        <HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="SelectCat" enabled="true">
          <elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
            <collectionProp name="Arguments.arguments"/>
          </elementProp>
          <stringProp name="HTTPSampler.domain">${__P(HOST,konakartoraclecloud.lab.akamas.io)}</stringProp>
          <stringProp name="HTTPSampler.port">8780</stringProp>
          <stringProp name="HTTPSampler.protocol">http</stringProp>
          <stringProp name="HTTPSampler.contentEncoding"></stringProp>
          <stringProp name="HTTPSampler.path">konakart/SelectCat.action?catId=${catId}</stringProp>
          <stringProp name="HTTPSampler.method">GET</stringProp>
          <boolProp name="HTTPSampler.follow_redirects">false</boolProp>
          <boolProp name="HTTPSampler.auto_redirects">true</boolProp>
          <boolProp name="HTTPSampler.use_keepalive">true</boolProp>
          <boolProp name="HTTPSampler.DO_MULTIPART_POST">false</boolProp>
          <boolProp name="HTTPSampler.BROWSER_COMPATIBLE_MULTIPART">true</boolProp>
          <boolProp name="HTTPSampler.image_parser">true</boolProp>
          <boolProp name="HTTPSampler.concurrentDwn">true</boolProp>
          <stringProp name="HTTPSampler.embedded_url_re"></stringProp>
          <stringProp name="HTTPSampler.connect_timeout"></stringProp>
          <stringProp name="HTTPSampler.response_timeout"></stringProp>
        </HTTPSamplerProxy>
        <hashTree/>
        <com.github.johrstrom.listener.PrometheusListener guiclass="com.github.johrstrom.listener.gui.PrometheusListenerGui" testclass="com.github.johrstrom.listener.PrometheusListener" testname="Prometheus Listener" enabled="true">
          <collectionProp name="prometheus.collector_definitions">
            <elementProp name="" elementType="com.github.johrstrom.listener.ListenerCollectorConfig">
              <stringProp name="collector.help">Sampler Response Time</stringProp>
              <stringProp name="collector.metric_name">ResponseTime</stringProp>
              <stringProp name="collector.type">SUMMARY</stringProp>
              <collectionProp name="collector.labels">
                <stringProp name="102727412">label</stringProp>
                <stringProp name="3059181">code</stringProp>
              </collectionProp>
              <stringProp name="collector.quantiles_or_buckets">0.5,0.01|0.85,0.01|0.9,0.01|0.99,0.01;60</stringProp>
              <stringProp name="listener.collector.listen_to">samples</stringProp>
              <stringProp name="listener.collector.measuring">ResponseTime</stringProp>
            </elementProp>
            <elementProp name="" elementType="com.github.johrstrom.listener.ListenerCollectorConfig">
              <stringProp name="collector.help">Success and failure ratio</stringProp>
              <stringProp name="collector.metric_name">Ratio</stringProp>
              <stringProp name="collector.type">SUCCESS_RATIO</stringProp>
              <collectionProp name="collector.labels">
                <stringProp name="102727412">label</stringProp>
                <stringProp name="3059181">code</stringProp>
              </collectionProp>
              <stringProp name="collector.quantiles_or_buckets"></stringProp>
              <stringProp name="listener.collector.listen_to">samples</stringProp>
              <stringProp name="listener.collector.measuring">SuccessRatio</stringProp>
            </elementProp>
          </collectionProp>
        </com.github.johrstrom.listener.PrometheusListener>
        <hashTree/>
        <ResultCollector guiclass="ViewResultsFullVisualizer" testclass="ResultCollector" testname="View Results Tree" enabled="false">
          <boolProp name="ResultCollector.error_logging">false</boolProp>
          <objProp>
            <name>saveConfig</name>
            <value class="SampleSaveConfiguration">
              <time>true</time>
              <latency>true</latency>
              <timestamp>true</timestamp>
              <success>true</success>
              <label>true</label>
              <code>true</code>
              <message>true</message>
              <threadName>true</threadName>
              <dataType>true</dataType>
              <encoding>false</encoding>
              <assertions>true</assertions>
              <subresults>true</subresults>
              <responseData>false</responseData>
              <samplerData>false</samplerData>
              <xml>false</xml>
              <fieldNames>true</fieldNames>
              <responseHeaders>false</responseHeaders>
              <requestHeaders>false</requestHeaders>
              <responseDataOnError>false</responseDataOnError>
              <saveAssertionResultsFailureMessage>true</saveAssertionResultsFailureMessage>
              <assertionsResultsToSave>0</assertionsResultsToSave>
              <bytes>true</bytes>
              <sentBytes>true</sentBytes>
              <url>true</url>
              <threadCounts>true</threadCounts>
              <idleTime>true</idleTime>
              <connectTime>true</connectTime>
            </value>
          </objProp>
          <stringProp name="filename"></stringProp>
        </ResultCollector>
        <hashTree/>
        <ResultCollector guiclass="SummaryReport" testclass="ResultCollector" testname="Summary Report" enabled="false">
          <boolProp name="ResultCollector.error_logging">false</boolProp>
          <objProp>
            <name>saveConfig</name>
            <value class="SampleSaveConfiguration">
              <time>true</time>
              <latency>true</latency>
              <timestamp>true</timestamp>
              <success>true</success>
              <label>true</label>
              <code>true</code>
              <message>true</message>
              <threadName>true</threadName>
              <dataType>true</dataType>
              <encoding>false</encoding>
              <assertions>true</assertions>
              <subresults>true</subresults>
              <responseData>false</responseData>
              <samplerData>false</samplerData>
              <xml>false</xml>
              <fieldNames>true</fieldNames>
              <responseHeaders>false</responseHeaders>
              <requestHeaders>false</requestHeaders>
              <responseDataOnError>false</responseDataOnError>
              <saveAssertionResultsFailureMessage>true</saveAssertionResultsFailureMessage>
              <assertionsResultsToSave>0</assertionsResultsToSave>
              <bytes>true</bytes>
              <sentBytes>true</sentBytes>
              <url>true</url>
              <threadCounts>true</threadCounts>
              <idleTime>true</idleTime>
              <connectTime>true</connectTime>
            </value>
          </objProp>
          <stringProp name="filename"></stringProp>
        </ResultCollector>
        <hashTree/>
      </hashTree>
      <kg.apc.jmeter.threads.UltimateThreadGroup guiclass="kg.apc.jmeter.threads.UltimateThreadGroupGui" testclass="kg.apc.jmeter.threads.UltimateThreadGroup" testname="jp@gc - Ultimate Thread Group - gibbo slope" enabled="false">
        <collectionProp name="ultimatethreadgroupdata">
          <collectionProp name="-80734132">
            <stringProp name="1572">15</stringProp>
            <stringProp name="48">0</stringProp>
            <stringProp name="56313">900</stringProp>
            <stringProp name="1509345">1200</stringProp>
            <stringProp name="0"></stringProp>
          </collectionProp>
          <collectionProp name="-1213623823">
            <stringProp name="50">2</stringProp>
            <stringProp name="1509345">1200</stringProp>
            <stringProp name="48687">120</stringProp>
            <stringProp name="54639">780</stringProp>
            <stringProp name="0"></stringProp>
          </collectionProp>
          <collectionProp name="-1560134527">
            <stringProp name="51">3</stringProp>
            <stringProp name="1513251">1620</stringProp>
            <stringProp name="48873">180</stringProp>
            <stringProp name="50547">300</stringProp>
            <stringProp name="0"></stringProp>
          </collectionProp>
        </collectionProp>
        <elementProp name="ThreadGroup.main_controller" elementType="LoopController" guiclass="LoopControlPanel" testclass="LoopController" testname="Loop Controller" enabled="true">
          <boolProp name="LoopController.continue_forever">false</boolProp>
          <intProp name="LoopController.loops">-1</intProp>
        </elementProp>
        <stringProp name="ThreadGroup.on_sample_error">continue</stringProp>
      </kg.apc.jmeter.threads.UltimateThreadGroup>
      <hashTree>
        <RandomVariableConfig guiclass="TestBeanGUI" testclass="RandomVariableConfig" testname="Random catId" enabled="true">
          <stringProp name="maximumValue">30</stringProp>
          <stringProp name="minimumValue">1</stringProp>
          <stringProp name="outputFormat"></stringProp>
          <boolProp name="perThread">true</boolProp>
          <stringProp name="randomSeed">666</stringProp>
          <stringProp name="variableName">catId</stringProp>
        </RandomVariableConfig>
        <hashTree/>
        <HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="Welcome" enabled="true">
          <elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
            <collectionProp name="Arguments.arguments"/>
          </elementProp>
          <stringProp name="HTTPSampler.domain">${__P(HOST,konakartoraclecloud.lab.akamas.io)}</stringProp>
          <stringProp name="HTTPSampler.port">8780</stringProp>
          <stringProp name="HTTPSampler.protocol">http</stringProp>
          <stringProp name="HTTPSampler.contentEncoding"></stringProp>
          <stringProp name="HTTPSampler.path">konakart/Welcome.action</stringProp>
          <stringProp name="HTTPSampler.method">GET</stringProp>
          <boolProp name="HTTPSampler.follow_redirects">false</boolProp>
          <boolProp name="HTTPSampler.auto_redirects">true</boolProp>
          <boolProp name="HTTPSampler.use_keepalive">true</boolProp>
          <boolProp name="HTTPSampler.DO_MULTIPART_POST">false</boolProp>
          <boolProp name="HTTPSampler.BROWSER_COMPATIBLE_MULTIPART">true</boolProp>
          <boolProp name="HTTPSampler.image_parser">true</boolProp>
          <boolProp name="HTTPSampler.concurrentDwn">true</boolProp>
          <stringProp name="HTTPSampler.embedded_url_re"></stringProp>
          <stringProp name="HTTPSampler.connect_timeout"></stringProp>
          <stringProp name="HTTPSampler.response_timeout"></stringProp>
        </HTTPSamplerProxy>
        <hashTree/>
        <TestAction guiclass="TestActionGui" testclass="TestAction" testname="think time" enabled="true">
          <intProp name="ActionProcessor.action">1</intProp>
          <intProp name="ActionProcessor.target">0</intProp>
          <stringProp name="ActionProcessor.duration">100</stringProp>
        </TestAction>
        <hashTree/>
        <HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="SelectCat" enabled="true">
          <elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
            <collectionProp name="Arguments.arguments"/>
          </elementProp>
          <stringProp name="HTTPSampler.domain">${__P(HOST,konakartoraclecloud.lab.akamas.io)}</stringProp>
          <stringProp name="HTTPSampler.port">8780</stringProp>
          <stringProp name="HTTPSampler.protocol">http</stringProp>
          <stringProp name="HTTPSampler.contentEncoding"></stringProp>
          <stringProp name="HTTPSampler.path">konakart/SelectCat.action?catId=${catId}</stringProp>
          <stringProp name="HTTPSampler.method">GET</stringProp>
          <boolProp name="HTTPSampler.follow_redirects">false</boolProp>
          <boolProp name="HTTPSampler.auto_redirects">true</boolProp>
          <boolProp name="HTTPSampler.use_keepalive">true</boolProp>
          <boolProp name="HTTPSampler.DO_MULTIPART_POST">false</boolProp>
          <boolProp name="HTTPSampler.BROWSER_COMPATIBLE_MULTIPART">true</boolProp>
          <boolProp name="HTTPSampler.image_parser">true</boolProp>
          <boolProp name="HTTPSampler.concurrentDwn">true</boolProp>
          <stringProp name="HTTPSampler.embedded_url_re"></stringProp>
          <stringProp name="HTTPSampler.connect_timeout"></stringProp>
          <stringProp name="HTTPSampler.response_timeout"></stringProp>
        </HTTPSamplerProxy>
        <hashTree/>
        <TestAction guiclass="TestActionGui" testclass="TestAction" testname="think time" enabled="true">
          <intProp name="ActionProcessor.action">1</intProp>
          <intProp name="ActionProcessor.target">0</intProp>
          <stringProp name="ActionProcessor.duration">100</stringProp>
        </TestAction>
        <hashTree/>
        <com.github.johrstrom.listener.PrometheusListener guiclass="com.github.johrstrom.listener.gui.PrometheusListenerGui" testclass="com.github.johrstrom.listener.PrometheusListener" testname="Prometheus Listener" enabled="true">
          <collectionProp name="prometheus.collector_definitions">
            <elementProp name="" elementType="com.github.johrstrom.listener.ListenerCollectorConfig">
              <stringProp name="collector.help">Sampler Response Time</stringProp>
              <stringProp name="collector.metric_name">ResponseTime</stringProp>
              <stringProp name="collector.type">SUMMARY</stringProp>
              <collectionProp name="collector.labels">
                <stringProp name="102727412">label</stringProp>
                <stringProp name="3059181">code</stringProp>
              </collectionProp>
              <stringProp name="collector.quantiles_or_buckets">0.5,0.01|0.85,0.01|0.9,0.01|0.99,0.01;60</stringProp>
              <stringProp name="listener.collector.listen_to">samples</stringProp>
              <stringProp name="listener.collector.measuring">ResponseTime</stringProp>
            </elementProp>
            <elementProp name="" elementType="com.github.johrstrom.listener.ListenerCollectorConfig">
              <stringProp name="collector.help">Success and failure ratio</stringProp>
              <stringProp name="collector.metric_name">Ratio</stringProp>
              <stringProp name="collector.type">SUCCESS_RATIO</stringProp>
              <collectionProp name="collector.labels">
                <stringProp name="102727412">label</stringProp>
                <stringProp name="3059181">code</stringProp>
              </collectionProp>
              <stringProp name="collector.quantiles_or_buckets"></stringProp>
              <stringProp name="listener.collector.listen_to">samples</stringProp>
              <stringProp name="listener.collector.measuring">SuccessRatio</stringProp>
            </elementProp>
          </collectionProp>
        </com.github.johrstrom.listener.PrometheusListener>
        <hashTree/>
        <ResultCollector guiclass="ViewResultsFullVisualizer" testclass="ResultCollector" testname="View Results Tree" enabled="false">
          <boolProp name="ResultCollector.error_logging">false</boolProp>
          <objProp>
            <name>saveConfig</name>
            <value class="SampleSaveConfiguration">
              <time>true</time>
              <latency>true</latency>
              <timestamp>true</timestamp>
              <success>true</success>
              <label>true</label>
              <code>true</code>
              <message>true</message>
              <threadName>true</threadName>
              <dataType>true</dataType>
              <encoding>false</encoding>
              <assertions>true</assertions>
              <subresults>true</subresults>
              <responseData>false</responseData>
              <samplerData>false</samplerData>
              <xml>false</xml>
              <fieldNames>true</fieldNames>
              <responseHeaders>false</responseHeaders>
              <requestHeaders>false</requestHeaders>
              <responseDataOnError>false</responseDataOnError>
              <saveAssertionResultsFailureMessage>true</saveAssertionResultsFailureMessage>
              <assertionsResultsToSave>0</assertionsResultsToSave>
              <bytes>true</bytes>
              <sentBytes>true</sentBytes>
              <url>true</url>
              <threadCounts>true</threadCounts>
              <idleTime>true</idleTime>
              <connectTime>true</connectTime>
            </value>
          </objProp>
          <stringProp name="filename"></stringProp>
        </ResultCollector>
        <hashTree/>
        <ResultCollector guiclass="SummaryReport" testclass="ResultCollector" testname="Summary Report" enabled="false">
          <boolProp name="ResultCollector.error_logging">false</boolProp>
          <objProp>
            <name>saveConfig</name>
            <value class="SampleSaveConfiguration">
              <time>true</time>
              <latency>true</latency>
              <timestamp>true</timestamp>
              <success>true</success>
              <label>true</label>
              <code>true</code>
              <message>true</message>
              <threadName>true</threadName>
              <dataType>true</dataType>
              <encoding>false</encoding>
              <assertions>true</assertions>
              <subresults>true</subresults>
              <responseData>false</responseData>
              <samplerData>false</samplerData>
              <xml>false</xml>
              <fieldNames>true</fieldNames>
              <responseHeaders>false</responseHeaders>
              <requestHeaders>false</requestHeaders>
              <responseDataOnError>false</responseDataOnError>
              <saveAssertionResultsFailureMessage>true</saveAssertionResultsFailureMessage>
              <assertionsResultsToSave>0</assertionsResultsToSave>
              <bytes>true</bytes>
              <sentBytes>true</sentBytes>
              <url>true</url>
              <threadCounts>true</threadCounts>
              <idleTime>true</idleTime>
              <connectTime>true</connectTime>
            </value>
          </objProp>
          <stringProp name="filename"></stringProp>
        </ResultCollector>
        <hashTree/>
      </hashTree>
    </hashTree>
  </hashTree>
</jmeterTestPlan>

The provided run_test.sh wraps the command to execute the test, and requires as an argument the URL of the target KonaKart instance.

#!/bin/bash

set -e

TARGET="${1:-konakartoracle.lab.akamas.io}"
IMAGE=chiabre/jmeter_plugins

THIS_DIR=`dirname "${BASH_SOURCE[0]}"`
NOW=`date +'%Y%m%d%H%M%S'`

docker run --rm --name jmeter -i \
  --network akamas \
  -v /home/ubuntu/konakart-oracle/jmeter:/tmp \
  -w /tmp \
  -p 9270:9270 \
  $IMAGE \
  -t Konakart_optimizePerf.jmx -JTARGET_HOST=$TARGET

cp "${THIS_DIR}/jmeter.log" "${THIS_DIR}/jmeter.log.$NOW"

Optimization Setup

System

Our modeled system includes the following components:

  • The oracle component that models the Oracle Database instance on oradb.mycompany.com, whose parameters are the targets of our optimization

  • The webapp component that models the KonaKart service running on konakart.mycompany.com, providing the performance metrics used to validate the system’s SLOs

The first step is defining the system (system.yaml):

name: oracle system
description: Multi-tier application model featuring Java technology and Oracle Database on cloud

Here’s the definition of our oracle component (oracle.yaml), including the parameters needed to connect to the database instances and the filters to fetch metrics from Prometheus.

name: oracle
description: Oracle DB for konakart
componentType: Oracle Database 19c
properties:
  connection:
    user: user
    password: password
    host: oradb.mycompany.com
    service: konakart
    port: 1521

  prometheus:
    instance: oradb

Notice: to update the init parameter the user requires the ALTER SYSTEM privilege.

Here’s the definition of the konakart component (konakart.yaml), containing the filters to fetch the metrics from Prometheus:

name: konakart
description: Web application component for e2e metrics
componentType: Web Application
properties:
  prometheus:
    instance: jmeter
    job: jmeter

We can create the system by running the following command:

akamas create system system.yaml

We can then create the components by running the following commands:

akamas create component oracle.yaml 'oracle system'
akamas create component konakart.yaml 'oracle system'

Telemetry

provider: Prometheus
config:
  address: akamas.mycompany.com
  port: 9090

  logLevel: DETAILED

We can now create the telemetry instance and attach it to our system by running:

akamas create telemetry-instance prom.yaml 'oracle system'

Workflow

This section outlines the steps performed during the execution of the experiments.

Stop KonaKart

- name: stop konakart
  operator: Executor
  arguments:
    retries: 0
    command: bash /opt/konakart/bin/stopkonakart.sh
    host:
      hostname: konakart.mycompany.com
      username: ubuntu
      key: keyfile

- name: check konakart stop
  operator: Executor
  arguments:
    retries: 0
    command: bash /opt/scripts/check_konakart_stop.sh
    host:
      hostname: konakart.mycompany.com
      username: ubuntu
      key: keyfile

Attached you can find the referenced script check_konakart_stop.sh:

#! /bin/bash
numOfKonakartRunning=$(ps aux | grep "/opt/konakart/bin" | grep -v "grep" | wc -l)

if  [ $numOfKonakartRunning -eq 0 ] ;
then
    echo "konakart not running"
    exit 0
else
    echo "konakart is still running"
    exit 1
fi

Configure the Oracle instance

- name: update oracle parameters
  operator: OracleConfigurator
  arguments:
    retries: 0
    component: oracle

- name: restart oracle
  operator: Executor
  arguments:
    retries: 0
    command: sudo su -c 'bash /opt/scripts/restart_db.sh' - oracle
    host:
      hostname: oradb.mycompany.com
      username: opc
      key: oraclekey

- name: check oracle status
  operator: Executor
  arguments:
    retries: 0
    command: sudo su -c 'bash /opt/scripts/check_db.sh' - oracle
    host:
      hostname: oradb.mycompany.com
      username: opc
      key: oraclekey

Attached you can find the referenced script check_db.sh:

#!/bin/bash

ORA_OWNER=oracle

DB_NAME=kona_kart
BAK_FILE=~/akamas/spfilekona.ora

# [o] to avoid self-grep
PMON=[o]ra_pmon_kona

if ps -ef | grep -q $PMON ; then
  echo "[INFO] - Database running"

else
  if sudo test -f "$BAK_FILE"; then
    echo "[INFO] - Trying to restore Oracle database using file $BAK_FILE"
    echo "[INFO] - ORACLE_HOME value is: $ORACLE_HOME"

    cp "$BAK_FILE" "$ORACLE_HOME/dbs/"

    echo "[INFO] - Trying to restart oracle"

    echo "[INFO] - Stopping the database"
    $ORACLE_HOME/bin/dbshut $ORACLE_HOME
    # $ORACLE_HOME/bin/srvctl stop database -d $DB_NAME
    cat $ORACLE_HOME/rdbms/log/shutdown.log

    echo "[INFO] - Starting the database"
    $ORACLE_HOME/bin/dbstart $ORACLE_HOME
    # $ORACLE_HOME/bin/srvctl start database -d $DB_NAME
    cat $ORACLE_HOME/rdbms/log/startup.log

    ps -ef | grep $PMON

  else
    echo "[ERROR] - The spfile does not exist in current folder!"
  fi

  exit 255
fi

exit 0

and restart_db.sh:

#!/bin/bash

ORA_OWNER=oracle

DB_NAME=kona_kart

# [o] to avoid self-grep
PMON=[o]ra_pmon_kona

echo "[INFO] - Stopping the database"
$ORACLE_HOME/bin/dbshut $ORACLE_HOME
# $ORACLE_HOME/bin/srvctl stop database -d $DB_NAME
cat $ORACLE_HOME/rdbms/log/shutdown.log
echo "[INFO] - Starting the database"
$ORACLE_HOME/bin/dbstart $ORACLE_HOME
# $ORACLE_HOME/bin/srvctl start database -d $DB_NAME
cat $ORACLE_HOME/rdbms/log/startup.log

ps -ef | grep $PMON

exit 0

Restart the KonaKart instance

- name: start konakart
  operator: Executor
  arguments:
    retries: 0
    command: /opt/konakart/bin/startkonakart.sh
    host:
      hostname: konakart.mycompany.com
      username: ubuntu
      key: keyfile

- name: wait for konakart
  operator: Sleep
  arguments:
    retries: 0
    seconds: 30

- name: check konakart service status
  operator: Executor
  arguments:
    retries: 0
    command: bash /opt/scripts/check_konakart_start.sh
    host:
      hostname: konakart.mycompany.com
      username: ubuntu
      key: keyfile

Attached you can find the referenced script:

#! /bin/bash
numOfKonakartRunning=$(ps aux | grep "/opt/konakart/bin" | grep -v "grep" | wc -l)

if  [ $numOfKonakartRunning -eq 1 ] ;
then
    echo "konakart running"
    exit 0
else
    echo "konakart not running"
    exit 1
fi

Run the workload

- name: test
  operator: Executor
  arguments:
    retries: 0
    command: bash /opt/scripts/run_test.sh konakart.mycompany.com
    host:
      hostname: akamas.mycompany.com
      username: ubuntu
      key: keyfile

Complete workflow

By putting together all the tasks defined above we come up with the following workflow definition (workflow.yaml):

name: konakart_workfl
tasks:

- name: stop konakart
  operator: Executor
  arguments:
    retries: 0
    command: bash /opt/konakart/bin/stopkonakart.sh
    host:
      hostname: konakart.mycompany.com
      username: ubuntu
      key: keyfile

- name: check konakart stop
  operator: Executor
  arguments:
    retries: 0
    command: bash /opt/scripts/check_konakart_stop.sh
    host:
      hostname: konakart.mycompany.com
      username: ubuntu
      key: keyfile

- name: update oracle parameters
  operator: OracleConfigurator
  arguments:
    retries: 0
    component: oracle

- name: restart oracle
  operator: Executor
  arguments:
    retries: 0
    command: sudo su -c 'bash /opt/scripts/restart_db.sh' - oracle
    host:
      hostname: oradb.mycompany.com
      username: opc
      key: oraclekey

- name: wait for oracle
  operator: Sleep
  arguments:
    retries: 0
    seconds: 60

- name: check oracle status
  operator: Executor
  arguments:
    retries: 0
    command: sudo su -c 'bash /opt/scripts/check_db.sh' - oracle
    host:
      hostname: oradb.mycompany.com
      username: opc
      key: oraclekey

- name: start konakart
  operator: Executor
  arguments:
    retries: 0
    command: /opt/konakart/bin/startkonakart.sh
    host:
      hostname: konakart.mycompany.com
      username: ubuntu
      key: keyfile

- name: wait for konakart
  operator: Sleep
  arguments:
    retries: 0
    seconds: 30

- name: check konakart service status
  operator: Executor
  arguments:
    retries: 0
    command: bash /opt/scripts/check_konakart_start.sh
    host:
      hostname: konakart.mycompany.com
      username: ubuntu
      key: keyfile

- name: test
  operator: Executor
  arguments:
    retries: 0
    command: bash /opt/scripts/run_test.sh konakart.mycompany.com
    host:
      hostname: akamas.mycompany.com
      username: ubuntu
      key: keyfile

We can create the workflow by running:

akamas create workflow workflow.yaml

Study

This study aims to minimize the memory allocated for the Oracle database while under a simulated load of the typical traffic, without impacting the SLOs.

This section provides a step-by-step description of the study definition.

Goal

Here’s the definition of the goal for our study, which is to minimize the memory allocated by Oracle to the SGA and PGA memory areas. The constraints ensure that any tested configuration that does not operate within the defined SLOs is flagged as not valid. In particular, the following are required:

  • the peak error rate must not exceed 5 errors per second

  • the transaction throughput must not decrease more than 10% with respect to the baseline

  • the response time must not increase more than 20% with respect to the baseline

goal:
  objective: minimize
  function:
    formula: oracle.oracle_sga_total_size + oracle.oracle_pga_target_size
  constraints:
    absolute:
    - konakart.transactions_error_rate <= 5.0
    relativeToBaseline:
    - konakart.transactions_throughput >= -10%
    - konakart.transactions_response_time <= +20%

Windowing

We define a window to consider only the data points after the ramp-up time of the load test:

windowing:
  type: trim
  trim: [200s, 30s]
  task: testde

Parameters to optimize

For this study, we are trying to optimize the size of the two main memory areas, meaning the Program Global Area and the Shared Global Area.

Given our goal, we set the domains of the parameters to explore only sizes smaller than the baseline.

parametersSelection:
- name: oracle.sga_target
  domain: [256, 1536]
- name: oracle.sga_max_size
  domain: [256, 1536]
- name: oracle.pga_aggregate_target
  domain: [256, 512]

The following constraint prevents Akamas from exploring configurations that we already know Oracle won’t validate:

parameterConstraints:
- name:  SGA
  formula: oracle.sga_target <= oracle.sga_max_size

Steps

We are going to add to our study two steps:

  • A baseline step, in which we configure the default values for the memory parameters as discovered from previous manual executions.

  • An optimization step, where we perform 200 experiments to search the set of parameters that best satisfies our goal.

Here’s what these steps look like:

steps:
- name: Baseline step
  type: baseline
  values:
    oracle.sga_target: 1536
    oracle.pga_aggregate_target: 512
    oracle.sga_max_size: 1536
    oracle.pga_aggregate_limit: 2048

- name: Optimization step
  type: optimize
  numberOfExperiments: 200
  maxFailedExperiments: 200

Complete study

Here’s the study definition (study.yaml) for optimizing the Oracle instance:

name: Minimize Oracle memory for KonaKart
system: oracle system
workflow: konakart_workfl
goal:
  objective: minimize
  function:
    formula: oracle.oracle_sga_total_size + oracle.oracle_pga_target_size
  constraints:
    absolute:
    - konakart.transactions_error_rate <= 5.0
    relativeToBaseline:
    - konakart.transactions_throughput >= -10%
    - konakart.transactions_response_time <= +20%

windowing:
  type: trim
  trim: [200s, 30s]
  task: test

parametersSelection:
- name: oracle.sga_target
  domain: [256, 1536]
- name: oracle.sga_max_size
  domain: [256, 1536]
- name: oracle.pga_aggregate_target
  domain: [256, 512]

parameterConstraints:
- name:  SGA
  formula: oracle.sga_target <= oracle.sga_max_size

trialAggregation: AVG
numberOfTrials: 1

steps:
- name: Baseline step
  type: baseline
  values:
    oracle.sga_target: 1536
    oracle.pga_aggregate_target: 512
    oracle.sga_max_size: 1536
    oracle.pga_aggregate_limit: 2048

- name: Optimization step
  type: optimize
  numberOfExperiments: 200
  maxFailedExperiments: 200

You can create the study by running:

akamas create study study.yaml

You can then start it by running:

akamas start study 'Minimize Oracle memory for KonaKart'

We can spin up the exporter using the using the following command, where cust-metrics.toml is our custom metrics file:

For a complete guide on how to configure and manage Prometheus refer to the .

Since we are using Prometheus to extract the database metrics we can leverage the which already includes the queries needed for the Oracle and JMetric queries for the metrics we need. To use the Prometheus provider we need to define a telemetry instance (prom.yaml):

Using an we run a command to stop the KonaKart instance using the script provided with the installation, then check the service is not running anymore with a custom script:

Using the to update the Oracle initialization parameters with the new configuration. Then with the , we run some custom scripts to restart the database instance to apply the new parameters and check for a successful startup. Additionally, in case of a failed startup, the script of the last task restores a backup of the default configuration file (spfile), restarts the database, and returns an error code to notify Akamas that the tested configuration is invalid:

We then define the tasks that restart the KonaKart service and check it is running correctly:

Finally, we define a task that uses the to run the JMeter load test against the KonaKart instance:

KonaKart
Apache JMeter
Oracle Prometheus exporter
OracleDB Prometheus exporter
Install KonaKart
Manual Installation
Oracle Cloud
official Docker image
official documentation
Prometheus provider,
Executor operator
OracleConfigurator operator
Executor operator
Executor operator
Executor operator