Add performance testing in Monasca persister
Leverages the JMeter and KafkaMeter to inject into persister metric messages with permutation of random metric names and dimensions. Monitors the metrics flushed to the database in all persister instances and calculates the throughput. The number of metrics and the number of unique metic definitions are configurable in the test plan. The script currently supports only the Java implementation of the Monasca persister. Monasca python does not provide the same internal metric api as the Dropwizard in the Java implemation. Future work is required for the Python implemation. Change-Id: Id8e6a5b62aa434d9943c7eee4be8991536b1c45f Depends-On: https://review.openstack.org/543399 story: 2001292 task: 5841
This commit is contained in:
parent
97e26fa554
commit
169f2c3ca3
4
.gitignore
vendored
4
.gitignore
vendored
@ -13,4 +13,6 @@ cover/
|
|||||||
*egg-info/
|
*egg-info/
|
||||||
.testrepository/
|
.testrepository/
|
||||||
.stestr/
|
.stestr/
|
||||||
*.sample
|
*.sample
|
||||||
|
perf/persister_perf_*/*.*
|
||||||
|
perf/jmeter.log
|
||||||
|
56
perf/README.md
Normal file
56
perf/README.md
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
<!-- Change things from this point on -->
|
||||||
|
|
||||||
|
monasca-persister performance benchmarking
|
||||||
|
=============
|
||||||
|
|
||||||
|
This tool benchmarkes the Monasca Persister performance and throughput.
|
||||||
|
It uses JMeter and Kafka plugin to initiate Kafka metric messages and
|
||||||
|
query the Dropwizard rest api to retrieve perister processing metrics.
|
||||||
|
Becasue the Monasca persister python implementation does not have
|
||||||
|
similar internal processing metric rest api availalbe, the support
|
||||||
|
for python implementation performance benchmark will be added in a
|
||||||
|
future release.
|
||||||
|
|
||||||
|
# Install
|
||||||
|
|
||||||
|
1. Download and install the latest Apache JMeter from
|
||||||
|
http://jmeter.apache.org/download_jmeter.cgi.
|
||||||
|
2. Add JMeter bin directory to the path, for example,
|
||||||
|
PATH=$PATH:/opt/apache-jmeter/bin.
|
||||||
|
3. Clone KafkaMeter repository: https://github.com/BrightTag/kafkameter.
|
||||||
|
4. Run Maven package and install Kafkameter jar to $JMETER_HOME/lib/ext
|
||||||
|
folder under the Apache JMeter installation home.
|
||||||
|
|
||||||
|
# Configure
|
||||||
|
|
||||||
|
1. Make a copy of the jmeter_test_plan.jmx file and modify the test plan
|
||||||
|
to fit your goal. The available options are:
|
||||||
|
- The number of threads(users)
|
||||||
|
- The number of loops, i.e., the number of metric messages each thread/user
|
||||||
|
will create)
|
||||||
|
- The range of the random values in the metric name and dimension values.
|
||||||
|
This controls the number of unique metric definitions the test plan will
|
||||||
|
create.
|
||||||
|
|
||||||
|
The total number of metrics = the number of threads(users) * loop count.
|
||||||
|
|
||||||
|
# Run test
|
||||||
|
|
||||||
|
1. Execute persister_perf.sh, for example,
|
||||||
|
```
|
||||||
|
./persister_perf.sh -t jmeter_test_plan.jmx -n 1000000 -s 192.168.1.5,192.168.1.6 -p 8091 -w 10
|
||||||
|
|
||||||
|
-n the expected number of metric messages (equals to the number of threads(users) * loop count.
|
||||||
|
-s a comma separated list of the Monasca Persister server hosts in the cluster
|
||||||
|
-p Monasca Persister server port number
|
||||||
|
-w the time to wait for before checking the processing status from the Monasca persister next time
|
||||||
|
```
|
||||||
|
|
||||||
|
2. For each test run, an output folder (postfixed by the timestamp) is
|
||||||
|
created. You can monitor the log file to watch the progress of jmeter
|
||||||
|
sending messages, Monasca persister reading messages as well as
|
||||||
|
Persister flushing the metrics into the time series database. It
|
||||||
|
includes the accumulated number of metrics created, read and flushed
|
||||||
|
and snapshots of throughput in each check interval.
|
||||||
|
|
||||||
|
3. The output file contains the summary of the performance testing result.
|
170
perf/jmeter_test_plan.jmx
Normal file
170
perf/jmeter_test_plan.jmx
Normal file
@ -0,0 +1,170 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<jmeterTestPlan version="1.2" properties="3.2" jmeter="3.3 r1808647">
|
||||||
|
<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.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="tenant" elementType="Argument">
|
||||||
|
<stringProp name="Argument.name">tenant</stringProp>
|
||||||
|
<stringProp name="Argument.value">t1</stringProp>
|
||||||
|
<stringProp name="Argument.metadata">=</stringProp>
|
||||||
|
</elementProp>
|
||||||
|
</collectionProp>
|
||||||
|
</elementProp>
|
||||||
|
<stringProp name="TestPlan.user_define_classpath"></stringProp>
|
||||||
|
</TestPlan>
|
||||||
|
<hashTree>
|
||||||
|
<ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="Thread Group" enabled="true">
|
||||||
|
<stringProp name="ThreadGroup.on_sample_error">stoptest</stringProp>
|
||||||
|
<elementProp name="ThreadGroup.main_controller" elementType="LoopController" guiclass="LoopControlPanel" testclass="LoopController" testname="Loop Controller" enabled="true">
|
||||||
|
<boolProp name="LoopController.continue_forever">false</boolProp>
|
||||||
|
<stringProp name="LoopController.loops">80000000</stringProp>
|
||||||
|
</elementProp>
|
||||||
|
<stringProp name="ThreadGroup.num_threads">2</stringProp>
|
||||||
|
<stringProp name="ThreadGroup.ramp_time">1</stringProp>
|
||||||
|
<longProp name="ThreadGroup.start_time">1507913213000</longProp>
|
||||||
|
<longProp name="ThreadGroup.end_time">1507913213000</longProp>
|
||||||
|
<boolProp name="ThreadGroup.scheduler">false</boolProp>
|
||||||
|
<stringProp name="ThreadGroup.duration"></stringProp>
|
||||||
|
<stringProp name="ThreadGroup.delay"></stringProp>
|
||||||
|
</ThreadGroup>
|
||||||
|
<hashTree>
|
||||||
|
<CounterConfig guiclass="CounterConfigGui" testclass="CounterConfig" testname="metric_Counter" enabled="true">
|
||||||
|
<stringProp name="CounterConfig.start">1</stringProp>
|
||||||
|
<stringProp name="CounterConfig.end">1000000</stringProp>
|
||||||
|
<stringProp name="CounterConfig.incr">1</stringProp>
|
||||||
|
<stringProp name="CounterConfig.name">metric_counter</stringProp>
|
||||||
|
<stringProp name="CounterConfig.format"></stringProp>
|
||||||
|
<boolProp name="CounterConfig.per_user">false</boolProp>
|
||||||
|
</CounterConfig>
|
||||||
|
<hashTree/>
|
||||||
|
<RandomVariableConfig guiclass="TestBeanGUI" testclass="RandomVariableConfig" testname="Random Tenant ID" enabled="true">
|
||||||
|
<stringProp name="maximumValue">10</stringProp>
|
||||||
|
<stringProp name="minimumValue">1</stringProp>
|
||||||
|
<stringProp name="outputFormat">tenant_00</stringProp>
|
||||||
|
<boolProp name="perThread">true</boolProp>
|
||||||
|
<stringProp name="randomSeed">${__Random(1, 1000000)}</stringProp>
|
||||||
|
<stringProp name="variableName">tenant_id</stringProp>
|
||||||
|
</RandomVariableConfig>
|
||||||
|
<hashTree/>
|
||||||
|
<RandomVariableConfig guiclass="TestBeanGUI" testclass="RandomVariableConfig" testname="Random Metric Name" enabled="true">
|
||||||
|
<stringProp name="maximumValue">600</stringProp>
|
||||||
|
<stringProp name="minimumValue">1</stringProp>
|
||||||
|
<stringProp name="outputFormat">metric_000</stringProp>
|
||||||
|
<boolProp name="perThread">true</boolProp>
|
||||||
|
<stringProp name="randomSeed">${__Random(1000001, 2000000)}</stringProp>
|
||||||
|
<stringProp name="variableName">metric_name</stringProp>
|
||||||
|
</RandomVariableConfig>
|
||||||
|
<hashTree/>
|
||||||
|
<RandomVariableConfig guiclass="TestBeanGUI" testclass="RandomVariableConfig" testname="Random Host Dimension" enabled="true">
|
||||||
|
<stringProp name="maximumValue">1500</stringProp>
|
||||||
|
<stringProp name="minimumValue">1</stringProp>
|
||||||
|
<stringProp name="outputFormat">host_0000</stringProp>
|
||||||
|
<boolProp name="perThread">true</boolProp>
|
||||||
|
<stringProp name="randomSeed">${__Random(3000001, 4000000)}</stringProp>
|
||||||
|
<stringProp name="variableName">host_dim_value</stringProp>
|
||||||
|
</RandomVariableConfig>
|
||||||
|
<hashTree/>
|
||||||
|
<RandomVariableConfig guiclass="TestBeanGUI" testclass="RandomVariableConfig" testname="Random Process Dimension" enabled="true">
|
||||||
|
<stringProp name="maximumValue">20</stringProp>
|
||||||
|
<stringProp name="minimumValue">1</stringProp>
|
||||||
|
<stringProp name="outputFormat">process_000</stringProp>
|
||||||
|
<boolProp name="perThread">true</boolProp>
|
||||||
|
<stringProp name="randomSeed">${__Random(5000000, 10000000)}</stringProp>
|
||||||
|
<stringProp name="variableName">process_dim_value</stringProp>
|
||||||
|
</RandomVariableConfig>
|
||||||
|
<hashTree/>
|
||||||
|
<JavaSampler guiclass="JavaTestSamplerGui" testclass="JavaSampler" testname="kafka Request" enabled="true">
|
||||||
|
<elementProp name="arguments" elementType="Arguments" guiclass="ArgumentsPanel" testclass="Arguments" enabled="true">
|
||||||
|
<collectionProp name="Arguments.arguments">
|
||||||
|
<elementProp name="kafka_brokers" elementType="Argument">
|
||||||
|
<stringProp name="Argument.name">kafka_brokers</stringProp>
|
||||||
|
<stringProp name="Argument.value">192.168.1.2:9092,192.168.1.16:9092</stringProp>
|
||||||
|
<stringProp name="Argument.metadata">=</stringProp>
|
||||||
|
</elementProp>
|
||||||
|
<elementProp name="kafka_topic" elementType="Argument">
|
||||||
|
<stringProp name="Argument.name">kafka_topic</stringProp>
|
||||||
|
<stringProp name="Argument.value">metrics</stringProp>
|
||||||
|
<stringProp name="Argument.metadata">=</stringProp>
|
||||||
|
</elementProp>
|
||||||
|
<elementProp name="kafka_key" elementType="Argument">
|
||||||
|
<stringProp name="Argument.name">kafka_key</stringProp>
|
||||||
|
<stringProp name="Argument.value">${__time()}</stringProp>
|
||||||
|
<stringProp name="Argument.metadata">=</stringProp>
|
||||||
|
</elementProp>
|
||||||
|
<elementProp name="kafka_message" elementType="Argument">
|
||||||
|
<stringProp name="Argument.name">kafka_message</stringProp>
|
||||||
|
<stringProp name="Argument.value">{"metric":{"timestamp":${__time()},"name":"${metric_name}","dimensions":{"hostname":"${host_dim_value}","service":"monitoring", "process":"${__Random(1,22)}"},"value":${metric_counter},"value_meta":null},"meta":{"region":"RegionX","tenantId":"${tenant_id}"},"creation_time":${__time(/1000,)}}</stringProp>
|
||||||
|
<stringProp name="Argument.metadata">=</stringProp>
|
||||||
|
</elementProp>
|
||||||
|
<elementProp name="kafka_message_serializer" elementType="Argument">
|
||||||
|
<stringProp name="Argument.name">kafka_message_serializer</stringProp>
|
||||||
|
<stringProp name="Argument.value">org.apache.kafka.common.serialization.StringSerializer</stringProp>
|
||||||
|
<stringProp name="Argument.metadata">=</stringProp>
|
||||||
|
</elementProp>
|
||||||
|
<elementProp name="kafka_key_serializer" elementType="Argument">
|
||||||
|
<stringProp name="Argument.name">kafka_key_serializer</stringProp>
|
||||||
|
<stringProp name="Argument.value">org.apache.kafka.common.serialization.StringSerializer</stringProp>
|
||||||
|
<stringProp name="Argument.metadata">=</stringProp>
|
||||||
|
</elementProp>
|
||||||
|
<elementProp name="kafka_ssl_keystore" elementType="Argument">
|
||||||
|
<stringProp name="Argument.name">kafka_ssl_keystore</stringProp>
|
||||||
|
<stringProp name="Argument.value">${PARAMETER_KAFKA_SSL_KEYSTORE}</stringProp>
|
||||||
|
<stringProp name="Argument.metadata">=</stringProp>
|
||||||
|
</elementProp>
|
||||||
|
<elementProp name="kafka_ssl_keystore_password" elementType="Argument">
|
||||||
|
<stringProp name="Argument.name">kafka_ssl_keystore_password</stringProp>
|
||||||
|
<stringProp name="Argument.value">${PARAMETER_KAFKA_SSL_KEYSTORE_PASSWORD}</stringProp>
|
||||||
|
<stringProp name="Argument.metadata">=</stringProp>
|
||||||
|
</elementProp>
|
||||||
|
<elementProp name="kafka_ssl_truststore" elementType="Argument">
|
||||||
|
<stringProp name="Argument.name">kafka_ssl_truststore</stringProp>
|
||||||
|
<stringProp name="Argument.value">${PARAMETER_KAFKA_SSL_TRUSTSTORE}</stringProp>
|
||||||
|
<stringProp name="Argument.metadata">=</stringProp>
|
||||||
|
</elementProp>
|
||||||
|
<elementProp name="kafka_ssl_truststore_password" elementType="Argument">
|
||||||
|
<stringProp name="Argument.name">kafka_ssl_truststore_password</stringProp>
|
||||||
|
<stringProp name="Argument.value">${PARAMETER_KAFKA_SSL_TRUSTSTORE_PASSWORD}</stringProp>
|
||||||
|
<stringProp name="Argument.metadata">=</stringProp>
|
||||||
|
</elementProp>
|
||||||
|
<elementProp name="kafka_use_ssl" elementType="Argument">
|
||||||
|
<stringProp name="Argument.name">kafka_use_ssl</stringProp>
|
||||||
|
<stringProp name="Argument.value">false</stringProp>
|
||||||
|
<stringProp name="Argument.metadata">=</stringProp>
|
||||||
|
</elementProp>
|
||||||
|
<elementProp name="kafka_compression_type" elementType="Argument">
|
||||||
|
<stringProp name="Argument.name">kafka_compression_type</stringProp>
|
||||||
|
<stringProp name="Argument.value"></stringProp>
|
||||||
|
<stringProp name="Argument.metadata">=</stringProp>
|
||||||
|
</elementProp>
|
||||||
|
<elementProp name="kafka_partition" elementType="Argument">
|
||||||
|
<stringProp name="Argument.name">kafka_partition</stringProp>
|
||||||
|
<stringProp name="Argument.value"></stringProp>
|
||||||
|
<stringProp name="Argument.metadata">=</stringProp>
|
||||||
|
</elementProp>
|
||||||
|
</collectionProp>
|
||||||
|
</elementProp>
|
||||||
|
<stringProp name="classname">co.signal.kafkameter.KafkaProducerSampler</stringProp>
|
||||||
|
</JavaSampler>
|
||||||
|
<hashTree/>
|
||||||
|
<Arguments guiclass="ArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="false">
|
||||||
|
<collectionProp name="Arguments.arguments">
|
||||||
|
<elementProp name="process_dim_value" elementType="Argument">
|
||||||
|
<stringProp name="Argument.name">process_dim_value</stringProp>
|
||||||
|
<stringProp name="Argument.value">${__javaScript(Math.floor(Math.random()*22),MYRESULT)}</stringProp>
|
||||||
|
<stringProp name="Argument.metadata">=</stringProp>
|
||||||
|
</elementProp>
|
||||||
|
</collectionProp>
|
||||||
|
</Arguments>
|
||||||
|
<hashTree/>
|
||||||
|
</hashTree>
|
||||||
|
</hashTree>
|
||||||
|
<WorkBench guiclass="WorkBenchGui" testclass="WorkBench" testname="WorkBench" enabled="true">
|
||||||
|
<boolProp name="WorkBench.save">true</boolProp>
|
||||||
|
</WorkBench>
|
||||||
|
<hashTree/>
|
||||||
|
</hashTree>
|
||||||
|
</jmeterTestPlan>
|
238
perf/jmeter_test_plan_mix.jmx
Normal file
238
perf/jmeter_test_plan_mix.jmx
Normal file
@ -0,0 +1,238 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<jmeterTestPlan version="1.2" properties="3.2" jmeter="3.3 r1808647">
|
||||||
|
<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.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="tenant" elementType="Argument">
|
||||||
|
<stringProp name="Argument.name">tenant</stringProp>
|
||||||
|
<stringProp name="Argument.value">t1</stringProp>
|
||||||
|
<stringProp name="Argument.metadata">=</stringProp>
|
||||||
|
</elementProp>
|
||||||
|
</collectionProp>
|
||||||
|
</elementProp>
|
||||||
|
<stringProp name="TestPlan.user_define_classpath"></stringProp>
|
||||||
|
</TestPlan>
|
||||||
|
<hashTree>
|
||||||
|
<ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="Monasca Tenant Thread Group" enabled="true">
|
||||||
|
<stringProp name="ThreadGroup.on_sample_error">stoptest</stringProp>
|
||||||
|
<elementProp name="ThreadGroup.main_controller" elementType="LoopController" guiclass="LoopControlPanel" testclass="LoopController" testname="Loop Controller" enabled="true">
|
||||||
|
<boolProp name="LoopController.continue_forever">false</boolProp>
|
||||||
|
<stringProp name="LoopController.loops">1080</stringProp>
|
||||||
|
</elementProp>
|
||||||
|
<stringProp name="ThreadGroup.num_threads">4</stringProp>
|
||||||
|
<stringProp name="ThreadGroup.ramp_time">1</stringProp>
|
||||||
|
<longProp name="ThreadGroup.start_time">1510384829000</longProp>
|
||||||
|
<longProp name="ThreadGroup.end_time">1510384829000</longProp>
|
||||||
|
<boolProp name="ThreadGroup.scheduler">false</boolProp>
|
||||||
|
<stringProp name="ThreadGroup.duration"></stringProp>
|
||||||
|
<stringProp name="ThreadGroup.delay"></stringProp>
|
||||||
|
</ThreadGroup>
|
||||||
|
<hashTree>
|
||||||
|
<CounterConfig guiclass="CounterConfigGui" testclass="CounterConfig" testname="metric_Counter" enabled="true">
|
||||||
|
<stringProp name="CounterConfig.start">1</stringProp>
|
||||||
|
<stringProp name="CounterConfig.end">1000000</stringProp>
|
||||||
|
<stringProp name="CounterConfig.incr">1</stringProp>
|
||||||
|
<stringProp name="CounterConfig.name">metric_counter</stringProp>
|
||||||
|
<stringProp name="CounterConfig.format"></stringProp>
|
||||||
|
<boolProp name="CounterConfig.per_user">false</boolProp>
|
||||||
|
</CounterConfig>
|
||||||
|
<hashTree/>
|
||||||
|
<CounterConfig guiclass="CounterConfigGui" testclass="CounterConfig" testname="GuestHostCounter" enabled="true">
|
||||||
|
<stringProp name="CounterConfig.start">1</stringProp>
|
||||||
|
<stringProp name="CounterConfig.end"></stringProp>
|
||||||
|
<stringProp name="CounterConfig.incr">50</stringProp>
|
||||||
|
<stringProp name="CounterConfig.name">guestHostStartNum</stringProp>
|
||||||
|
<stringProp name="CounterConfig.format"></stringProp>
|
||||||
|
<boolProp name="CounterConfig.per_user">true</boolProp>
|
||||||
|
</CounterConfig>
|
||||||
|
<hashTree/>
|
||||||
|
<LoopController guiclass="LoopControlPanel" testclass="LoopController" testname="Loop Controller" enabled="true">
|
||||||
|
<boolProp name="LoopController.continue_forever">true</boolProp>
|
||||||
|
<stringProp name="LoopController.loops">10400000</stringProp>
|
||||||
|
</LoopController>
|
||||||
|
<hashTree>
|
||||||
|
<ThroughputController guiclass="ThroughputControllerGui" testclass="ThroughputController" testname="Admin Throughput Controller" enabled="true">
|
||||||
|
<intProp name="ThroughputController.style">1</intProp>
|
||||||
|
<boolProp name="ThroughputController.perThread">false</boolProp>
|
||||||
|
<intProp name="ThroughputController.maxThroughput">1</intProp>
|
||||||
|
<FloatProperty>
|
||||||
|
<name>ThroughputController.percentThroughput</name>
|
||||||
|
<value>40.0</value>
|
||||||
|
<savedValue>0.0</savedValue>
|
||||||
|
</FloatProperty>
|
||||||
|
<stringProp name="TestPlan.comments"> 1 mil unique metrics for admin tenants</stringProp>
|
||||||
|
</ThroughputController>
|
||||||
|
<hashTree>
|
||||||
|
<JavaSampler guiclass="JavaTestSamplerGui" testclass="JavaSampler" testname="Admin kafka Request" enabled="true">
|
||||||
|
<elementProp name="arguments" elementType="Arguments" guiclass="ArgumentsPanel" testclass="Arguments" enabled="true">
|
||||||
|
<collectionProp name="Arguments.arguments">
|
||||||
|
<elementProp name="kafka_brokers" elementType="Argument">
|
||||||
|
<stringProp name="Argument.name">kafka_brokers</stringProp>
|
||||||
|
<stringProp name="Argument.value">192.168.1.2:9092,192.168.1.16:9092</stringProp>
|
||||||
|
<stringProp name="Argument.metadata">=</stringProp>
|
||||||
|
</elementProp>
|
||||||
|
<elementProp name="kafka_topic" elementType="Argument">
|
||||||
|
<stringProp name="Argument.name">kafka_topic</stringProp>
|
||||||
|
<stringProp name="Argument.value">metrics</stringProp>
|
||||||
|
<stringProp name="Argument.metadata">=</stringProp>
|
||||||
|
</elementProp>
|
||||||
|
<elementProp name="kafka_key" elementType="Argument">
|
||||||
|
<stringProp name="Argument.name">kafka_key</stringProp>
|
||||||
|
<stringProp name="Argument.value">${__time()}</stringProp>
|
||||||
|
<stringProp name="Argument.metadata">=</stringProp>
|
||||||
|
</elementProp>
|
||||||
|
<elementProp name="kafka_message" elementType="Argument">
|
||||||
|
<stringProp name="Argument.name">kafka_message</stringProp>
|
||||||
|
<stringProp name="Argument.value">{"metric":{"timestamp":${__time()},"name":"metric_${__Random(1,500)}","dimensions":{"hostname":"controller_${__Random(1,3)}","service":"service_${__Random(1,20)}", "process":"process_${__Random(1,33)}"},"value":${metric_counter},"value_meta":null},"meta":{"region":"RegionX","tenantId":"admin"},"creation_time":${__time(/1000,)}}</stringProp>
|
||||||
|
<stringProp name="Argument.metadata">=</stringProp>
|
||||||
|
</elementProp>
|
||||||
|
<elementProp name="kafka_message_serializer" elementType="Argument">
|
||||||
|
<stringProp name="Argument.name">kafka_message_serializer</stringProp>
|
||||||
|
<stringProp name="Argument.value">org.apache.kafka.common.serialization.StringSerializer</stringProp>
|
||||||
|
<stringProp name="Argument.metadata">=</stringProp>
|
||||||
|
</elementProp>
|
||||||
|
<elementProp name="kafka_key_serializer" elementType="Argument">
|
||||||
|
<stringProp name="Argument.name">kafka_key_serializer</stringProp>
|
||||||
|
<stringProp name="Argument.value">org.apache.kafka.common.serialization.StringSerializer</stringProp>
|
||||||
|
<stringProp name="Argument.metadata">=</stringProp>
|
||||||
|
</elementProp>
|
||||||
|
<elementProp name="kafka_ssl_keystore" elementType="Argument">
|
||||||
|
<stringProp name="Argument.name">kafka_ssl_keystore</stringProp>
|
||||||
|
<stringProp name="Argument.value">${PARAMETER_KAFKA_SSL_KEYSTORE}</stringProp>
|
||||||
|
<stringProp name="Argument.metadata">=</stringProp>
|
||||||
|
</elementProp>
|
||||||
|
<elementProp name="kafka_ssl_keystore_password" elementType="Argument">
|
||||||
|
<stringProp name="Argument.name">kafka_ssl_keystore_password</stringProp>
|
||||||
|
<stringProp name="Argument.value">${PARAMETER_KAFKA_SSL_KEYSTORE_PASSWORD}</stringProp>
|
||||||
|
<stringProp name="Argument.metadata">=</stringProp>
|
||||||
|
</elementProp>
|
||||||
|
<elementProp name="kafka_ssl_truststore" elementType="Argument">
|
||||||
|
<stringProp name="Argument.name">kafka_ssl_truststore</stringProp>
|
||||||
|
<stringProp name="Argument.value">${PARAMETER_KAFKA_SSL_TRUSTSTORE}</stringProp>
|
||||||
|
<stringProp name="Argument.metadata">=</stringProp>
|
||||||
|
</elementProp>
|
||||||
|
<elementProp name="kafka_ssl_truststore_password" elementType="Argument">
|
||||||
|
<stringProp name="Argument.name">kafka_ssl_truststore_password</stringProp>
|
||||||
|
<stringProp name="Argument.value">${PARAMETER_KAFKA_SSL_TRUSTSTORE_PASSWORD}</stringProp>
|
||||||
|
<stringProp name="Argument.metadata">=</stringProp>
|
||||||
|
</elementProp>
|
||||||
|
<elementProp name="kafka_use_ssl" elementType="Argument">
|
||||||
|
<stringProp name="Argument.name">kafka_use_ssl</stringProp>
|
||||||
|
<stringProp name="Argument.value">false</stringProp>
|
||||||
|
<stringProp name="Argument.metadata">=</stringProp>
|
||||||
|
</elementProp>
|
||||||
|
<elementProp name="kafka_compression_type" elementType="Argument">
|
||||||
|
<stringProp name="Argument.name">kafka_compression_type</stringProp>
|
||||||
|
<stringProp name="Argument.value"></stringProp>
|
||||||
|
<stringProp name="Argument.metadata">=</stringProp>
|
||||||
|
</elementProp>
|
||||||
|
<elementProp name="kafka_partition" elementType="Argument">
|
||||||
|
<stringProp name="Argument.name">kafka_partition</stringProp>
|
||||||
|
<stringProp name="Argument.value"></stringProp>
|
||||||
|
<stringProp name="Argument.metadata">=</stringProp>
|
||||||
|
</elementProp>
|
||||||
|
</collectionProp>
|
||||||
|
</elementProp>
|
||||||
|
<stringProp name="classname">co.signal.kafkameter.KafkaProducerSampler</stringProp>
|
||||||
|
</JavaSampler>
|
||||||
|
<hashTree/>
|
||||||
|
</hashTree>
|
||||||
|
<ThroughputController guiclass="ThroughputControllerGui" testclass="ThroughputController" testname="Guest Throughput Controller" enabled="true">
|
||||||
|
<intProp name="ThroughputController.style">1</intProp>
|
||||||
|
<boolProp name="ThroughputController.perThread">true</boolProp>
|
||||||
|
<intProp name="ThroughputController.maxThroughput">1</intProp>
|
||||||
|
<FloatProperty>
|
||||||
|
<name>ThroughputController.percentThroughput</name>
|
||||||
|
<value>60.0</value>
|
||||||
|
<savedValue>0.0</savedValue>
|
||||||
|
</FloatProperty>
|
||||||
|
<stringProp name="TestPlan.comments">3 mil unique metric definitions</stringProp>
|
||||||
|
</ThroughputController>
|
||||||
|
<hashTree>
|
||||||
|
<JavaSampler guiclass="JavaTestSamplerGui" testclass="JavaSampler" testname="Guest kafka Request" enabled="true">
|
||||||
|
<elementProp name="arguments" elementType="Arguments" guiclass="ArgumentsPanel" testclass="Arguments" enabled="true">
|
||||||
|
<collectionProp name="Arguments.arguments">
|
||||||
|
<elementProp name="kafka_brokers" elementType="Argument">
|
||||||
|
<stringProp name="Argument.name">kafka_brokers</stringProp>
|
||||||
|
<stringProp name="Argument.value">192.168.1.2:9092,192.168.1.16:9092</stringProp>
|
||||||
|
<stringProp name="Argument.metadata">=</stringProp>
|
||||||
|
</elementProp>
|
||||||
|
<elementProp name="kafka_topic" elementType="Argument">
|
||||||
|
<stringProp name="Argument.name">kafka_topic</stringProp>
|
||||||
|
<stringProp name="Argument.value">metrics</stringProp>
|
||||||
|
<stringProp name="Argument.metadata">=</stringProp>
|
||||||
|
</elementProp>
|
||||||
|
<elementProp name="kafka_key" elementType="Argument">
|
||||||
|
<stringProp name="Argument.name">kafka_key</stringProp>
|
||||||
|
<stringProp name="Argument.value">${__time()}</stringProp>
|
||||||
|
<stringProp name="Argument.metadata">=</stringProp>
|
||||||
|
</elementProp>
|
||||||
|
<elementProp name="kafka_message" elementType="Argument">
|
||||||
|
<stringProp name="Argument.name">kafka_message</stringProp>
|
||||||
|
<stringProp name="Argument.value">{"metric":{"timestamp":${__time()},"name":"metric_${__Random(501,600)}","dimensions":{"hostname":"host_${__intSum(${guestHostStartNum},${__Random(0,499)})}","service":"service_${__Random(1,2)}", "process":"process_${__Random(1,3)}"},"value":${metric_counter},"value_meta":null},"meta":{"region":"RegionX","tenantId":"tenant_${__Random(0,10)}"},"creation_time":${__time(/1000,)}}</stringProp>
|
||||||
|
<stringProp name="Argument.metadata">=</stringProp>
|
||||||
|
</elementProp>
|
||||||
|
<elementProp name="kafka_message_serializer" elementType="Argument">
|
||||||
|
<stringProp name="Argument.name">kafka_message_serializer</stringProp>
|
||||||
|
<stringProp name="Argument.value">org.apache.kafka.common.serialization.StringSerializer</stringProp>
|
||||||
|
<stringProp name="Argument.metadata">=</stringProp>
|
||||||
|
</elementProp>
|
||||||
|
<elementProp name="kafka_key_serializer" elementType="Argument">
|
||||||
|
<stringProp name="Argument.name">kafka_key_serializer</stringProp>
|
||||||
|
<stringProp name="Argument.value">org.apache.kafka.common.serialization.StringSerializer</stringProp>
|
||||||
|
<stringProp name="Argument.metadata">=</stringProp>
|
||||||
|
</elementProp>
|
||||||
|
<elementProp name="kafka_ssl_keystore" elementType="Argument">
|
||||||
|
<stringProp name="Argument.name">kafka_ssl_keystore</stringProp>
|
||||||
|
<stringProp name="Argument.value">${PARAMETER_KAFKA_SSL_KEYSTORE}</stringProp>
|
||||||
|
<stringProp name="Argument.metadata">=</stringProp>
|
||||||
|
</elementProp>
|
||||||
|
<elementProp name="kafka_ssl_keystore_password" elementType="Argument">
|
||||||
|
<stringProp name="Argument.name">kafka_ssl_keystore_password</stringProp>
|
||||||
|
<stringProp name="Argument.value">${PARAMETER_KAFKA_SSL_KEYSTORE_PASSWORD}</stringProp>
|
||||||
|
<stringProp name="Argument.metadata">=</stringProp>
|
||||||
|
</elementProp>
|
||||||
|
<elementProp name="kafka_ssl_truststore" elementType="Argument">
|
||||||
|
<stringProp name="Argument.name">kafka_ssl_truststore</stringProp>
|
||||||
|
<stringProp name="Argument.value">${PARAMETER_KAFKA_SSL_TRUSTSTORE}</stringProp>
|
||||||
|
<stringProp name="Argument.metadata">=</stringProp>
|
||||||
|
</elementProp>
|
||||||
|
<elementProp name="kafka_ssl_truststore_password" elementType="Argument">
|
||||||
|
<stringProp name="Argument.name">kafka_ssl_truststore_password</stringProp>
|
||||||
|
<stringProp name="Argument.value">${PARAMETER_KAFKA_SSL_TRUSTSTORE_PASSWORD}</stringProp>
|
||||||
|
<stringProp name="Argument.metadata">=</stringProp>
|
||||||
|
</elementProp>
|
||||||
|
<elementProp name="kafka_use_ssl" elementType="Argument">
|
||||||
|
<stringProp name="Argument.name">kafka_use_ssl</stringProp>
|
||||||
|
<stringProp name="Argument.value">false</stringProp>
|
||||||
|
<stringProp name="Argument.metadata">=</stringProp>
|
||||||
|
</elementProp>
|
||||||
|
<elementProp name="kafka_compression_type" elementType="Argument">
|
||||||
|
<stringProp name="Argument.name">kafka_compression_type</stringProp>
|
||||||
|
<stringProp name="Argument.value"></stringProp>
|
||||||
|
<stringProp name="Argument.metadata">=</stringProp>
|
||||||
|
</elementProp>
|
||||||
|
<elementProp name="kafka_partition" elementType="Argument">
|
||||||
|
<stringProp name="Argument.name">kafka_partition</stringProp>
|
||||||
|
<stringProp name="Argument.value"></stringProp>
|
||||||
|
<stringProp name="Argument.metadata">=</stringProp>
|
||||||
|
</elementProp>
|
||||||
|
</collectionProp>
|
||||||
|
</elementProp>
|
||||||
|
<stringProp name="classname">co.signal.kafkameter.KafkaProducerSampler</stringProp>
|
||||||
|
</JavaSampler>
|
||||||
|
<hashTree/>
|
||||||
|
</hashTree>
|
||||||
|
</hashTree>
|
||||||
|
</hashTree>
|
||||||
|
</hashTree>
|
||||||
|
<WorkBench guiclass="WorkBenchGui" testclass="WorkBench" testname="WorkBench" enabled="true">
|
||||||
|
<boolProp name="WorkBench.save">true</boolProp>
|
||||||
|
</WorkBench>
|
||||||
|
<hashTree/>
|
||||||
|
</hashTree>
|
||||||
|
</jmeterTestPlan>
|
164
perf/persister_perf.sh
Executable file
164
perf/persister_perf.sh
Executable file
@ -0,0 +1,164 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Copyright 2017 SUSE LLC.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
PORT=8091
|
||||||
|
CHECK_INTERVAL=30
|
||||||
|
TIME_STAMP=$(date +%s)
|
||||||
|
|
||||||
|
mkdir persister_perf_${TIME_STAMP}
|
||||||
|
|
||||||
|
usage()
|
||||||
|
{
|
||||||
|
echo "usage: persister_perf.sh [[-s servers (required)] [-p port] \
|
||||||
|
[-t JMeter test plan file] [-n number of metrics to insert (required)] \
|
||||||
|
[-w wait time (seconds) betweenchecking persister status] | [-h help ]]"
|
||||||
|
exit
|
||||||
|
}
|
||||||
|
|
||||||
|
log()
|
||||||
|
{
|
||||||
|
# echo "$1"
|
||||||
|
echo "$1" >> persister_perf_${TIME_STAMP}/persister_perf.log
|
||||||
|
}
|
||||||
|
|
||||||
|
output()
|
||||||
|
{
|
||||||
|
# echo "$1"
|
||||||
|
echo "$1" >> persister_perf_${TIME_STAMP}/persister_perf_output.txt
|
||||||
|
}
|
||||||
|
|
||||||
|
get_received_metric_count_per_host()
|
||||||
|
{
|
||||||
|
local msg_count=$(curl -m 60 -s http://$1:$PORT/metrics?pretty=true | \
|
||||||
|
jq '[.meters | with_entries(select(.key|match("monasca.persister.pipeline.event.MetricHandler\\[metric-[0-9]*\\].events-processed-meter";"i")))[] | .count] | add')
|
||||||
|
echo "$msg_count"
|
||||||
|
}
|
||||||
|
|
||||||
|
get_total_received_metric_count()
|
||||||
|
{
|
||||||
|
local count=0
|
||||||
|
for server in $SERVERS; do
|
||||||
|
local count_per_host=$(get_received_metric_count_per_host $server)
|
||||||
|
log "$(date) Persister host: $server; Received metrics: $count_per_host"
|
||||||
|
count=$((count + count_per_host))
|
||||||
|
done
|
||||||
|
log "$(date) Total received metrics: $count"
|
||||||
|
echo "$count"
|
||||||
|
}
|
||||||
|
|
||||||
|
get_flushed_metric_count_per_host()
|
||||||
|
{
|
||||||
|
local msg_count=$(curl -m 60 -s http://$1:$PORT/metrics?pretty=true \
|
||||||
|
| jq '[.meters | with_entries(select(.key|match("monasca.persister.pipeline.event.MetricHandler\\[metric-[0-9]*\\].flush-meter";"i")))[] | .count] | add')
|
||||||
|
echo "$msg_count"
|
||||||
|
}
|
||||||
|
|
||||||
|
get_total_flushed_metric_count()
|
||||||
|
{
|
||||||
|
local count=0
|
||||||
|
for server in $SERVERS; do
|
||||||
|
local count_per_host=$(get_flushed_metric_count_per_host $server)
|
||||||
|
log "$(date) Persister host: $server; Flushed metrics: $count_per_host"
|
||||||
|
count=$((count + count_per_host))
|
||||||
|
done
|
||||||
|
log "$(date) Total flushed metrics: $count"
|
||||||
|
echo "$count"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
while getopts "hs:p:t:n:w:" option; do
|
||||||
|
case "${option}" in
|
||||||
|
h) usage;;
|
||||||
|
s) declare -a SERVERS=$(echo "${OPTARG}" | sed "s/,/\n/g");;
|
||||||
|
p) PORT=${OPTARG};;
|
||||||
|
t) TEST_PLAN=${OPTARG};;
|
||||||
|
n) NUM_METRICS=${OPTARG};;
|
||||||
|
w) CHECK_INTERVAL=${OPTARG};;
|
||||||
|
*) exit 1;;
|
||||||
|
:) echo "Missing option argument for -$OPTARG" >&2; exit 1;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ ! "$SERVERS" ] || [ ! "$NUM_METRICS" ]; then
|
||||||
|
usage
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
log "starting JMeter run $TEST_PLAN"
|
||||||
|
|
||||||
|
jmeter -n -t $TEST_PLAN -l persister_perf_${TIME_STAMP}/jmeter.jnl -e \
|
||||||
|
-o persister_perf_${TIME_STAMP}/jmeter \
|
||||||
|
>> persister_perf_${TIME_STAMP}/persister_perf.log 2>&1 &
|
||||||
|
|
||||||
|
START_TIME=$(date +%s)
|
||||||
|
|
||||||
|
received_metric_count_start=$(get_total_received_metric_count)
|
||||||
|
output "Total received metric count at start: $received_metric_count_start"
|
||||||
|
|
||||||
|
flushed_metric_count_start=$(get_total_flushed_metric_count)
|
||||||
|
output "Total flushed metric count at start: $flushed_metric_count_start"
|
||||||
|
|
||||||
|
received_metric_count_orig=$((received_metric_count_start))
|
||||||
|
|
||||||
|
flushed_metric_count_orig=$((flushed_metric_count_start))
|
||||||
|
|
||||||
|
target_received_metric_count=$((received_metric_count_start + NUM_METRICS))
|
||||||
|
|
||||||
|
target_flushed_metric_count=$((flushed_metric_count_start + NUM_METRICS))
|
||||||
|
|
||||||
|
sleep $CHECK_INTERVAL
|
||||||
|
|
||||||
|
INTERVAL_END_TIME=$(date +%s)
|
||||||
|
received_metric_count=$(get_total_received_metric_count)
|
||||||
|
flushed_metric_count=$(get_total_flushed_metric_count)
|
||||||
|
|
||||||
|
while [ "$received_metric_count" -lt "$target_received_metric_count" \
|
||||||
|
-o "$flushed_metric_count" -lt "$target_flushed_metric_count" ]
|
||||||
|
do
|
||||||
|
INTERVAL_START_TIME=$((INTERVAL_END_TIME))
|
||||||
|
received_metric_count_start=$((received_metric_count))
|
||||||
|
flushed_metric_count_start=$((flushed_metric_count))
|
||||||
|
|
||||||
|
sleep $CHECK_INTERVAL
|
||||||
|
INTERVAL_END_TIME=$(date +%s)
|
||||||
|
received_metric_count=$(get_total_received_metric_count)
|
||||||
|
flushed_metric_count=$(get_total_flushed_metric_count)
|
||||||
|
|
||||||
|
log "Current received metric throughput: \
|
||||||
|
$((($received_metric_count - $received_metric_count_start) \
|
||||||
|
/ $(($INTERVAL_END_TIME - $INTERVAL_START_TIME))))"
|
||||||
|
log "Current flushed metric throughput: \
|
||||||
|
$((($flushed_metric_count - $flushed_metric_count_start) \
|
||||||
|
/ $(($INTERVAL_END_TIME - $INTERVAL_START_TIME))))"
|
||||||
|
log "Average received metric throughput: \
|
||||||
|
$((($received_metric_count - $received_metric_count_orig) \
|
||||||
|
/ $(($INTERVAL_END_TIME - $START_TIME))))"
|
||||||
|
log "Average flushed metric throughput: \
|
||||||
|
$((($flushed_metric_count - $flushed_metric_count_orig) \
|
||||||
|
/ $(($INTERVAL_END_TIME - $START_TIME))))"
|
||||||
|
log "Expect $((target_flushed_metric_count - flushed_metric_count)) \
|
||||||
|
more metrics to be flushed"
|
||||||
|
done
|
||||||
|
|
||||||
|
END_TIME=$(date +%s)
|
||||||
|
ELAPSED=$(($END_TIME - $START_TIME))
|
||||||
|
output "Total received metric count at end: $received_metric_count"
|
||||||
|
output "Total flushed metric count at end: $flushed_metric_count"
|
||||||
|
output "Total elapsed time: $ELAPSED"
|
||||||
|
output "Average received metrics/second: \
|
||||||
|
$((($received_metric_count - $received_metric_count_orig) / $ELAPSED))"
|
||||||
|
output "Average persisted metrics/second: \
|
||||||
|
$((($flushed_metric_count - $flushed_metric_count_orig) / $ELAPSED))"
|
Loading…
Reference in New Issue
Block a user