From 3da8dc8e2b7cd38de81c5aaeb80967776728e955 Mon Sep 17 00:00:00 2001 From: "stu126940@mail.uni-kiel.de" <stu126940@mail.uni-kiel.de> Date: Mon, 4 Oct 2021 15:01:38 +0200 Subject: [PATCH] Allow arbitrary prometheus range query for the evaluation of benchmarks - Allow arbitrary prometheus range queres (update prometheusResponse) - Allow usage of more than one slo checker - Update the json which send to the python slo checker - refactoring - Update CRDs in order to set the query string as an dedicated parameter for a slo checker - Update exisiting python slo checker in order to use the new JSON format --- helm/jmx-custom-map.yaml | 11 ++++ helm/templates/theodolite/crd-execution.yaml | 3 + slope-evaluator/app/main.py | 6 +- .../resources/test-1-rep-success.json | 8 ++- .../resources/test-3-rep-success.json | 8 ++- theodolite/crd/crd-execution.yaml | 5 +- .../examples/operator/example-execution.yaml | 1 + .../standalone/example-execution.yaml | 1 + .../benchmark/BenchmarkExecution.kt | 1 + .../theodolite/evaluation/AnalysisExecutor.kt | 5 +- .../evaluation/ExternalSloChecker.kt | 13 ++-- .../kotlin/theodolite/evaluation/SloJson.kt | 63 +++++++++++++++++++ .../theodolite/execution/BenchmarkExecutor.kt | 2 +- .../execution/BenchmarkExecutorImpl.kt | 22 ++++--- .../execution/TheodoliteExecutor.kt | 2 +- .../theodolite/util/PrometheusResponse.kt | 15 +---- .../theodolite/CompositeStrategyTest.kt | 7 ++- .../theodolite/TestBenchmarkExecutorImpl.kt | 4 +- .../test-execution-update.yaml | 1 + .../k8s-resource-files/test-execution.yaml | 1 + 20 files changed, 133 insertions(+), 46 deletions(-) create mode 100644 helm/jmx-custom-map.yaml create mode 100644 theodolite/src/main/kotlin/theodolite/evaluation/SloJson.kt diff --git a/helm/jmx-custom-map.yaml b/helm/jmx-custom-map.yaml new file mode 100644 index 000000000..5abe283ce --- /dev/null +++ b/helm/jmx-custom-map.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +data: + jmx-kafka-prometheus.yml: | + jmxUrl: service:jmx:rmi:///jndi/rmi://localhost:5555/jmxrmi + lowercaseOutputName: true + lowercaseOutputLabelNames: true + ssl: false +kind: ConfigMap +metadata: + name: theodolite-cp-kafka-jmx-configmap + namespace: default diff --git a/helm/templates/theodolite/crd-execution.yaml b/helm/templates/theodolite/crd-execution.yaml index 163835e9b..f6305ad3e 100644 --- a/helm/templates/theodolite/crd-execution.yaml +++ b/helm/templates/theodolite/crd-execution.yaml @@ -60,6 +60,9 @@ spec: prometheusUrl: description: Connection string for Promehteus. type: string + query: + description: The prometheus query string + type: string offset: description: Hours by which the start and end timestamp will be shifted (for different timezones). type: integer diff --git a/slope-evaluator/app/main.py b/slope-evaluator/app/main.py index 6f6788f0c..621fa0cfc 100644 --- a/slope-evaluator/app/main.py +++ b/slope-evaluator/app/main.py @@ -38,7 +38,7 @@ def calculate_slope_trend(results, warmup): err_msg = 'Computing trend slope failed.' logger.exception(err_msg) logger.error('Mark this subexperiment as not successful and continue benchmark.') - return False + return float('inf') logger.info("Computed lag trend slope is '%s'", trend_slope) return trend_slope @@ -49,7 +49,7 @@ def check_service_level_objective(results, threshold): @app.post("/evaluate-slope",response_model=bool) async def evaluate_slope(request: Request): data = json.loads(await request.body()) - results = [calculate_slope_trend(total_lag, data['warmup']) for total_lag in data['total_lags']] - return check_service_level_objective(results=results, threshold=data["threshold"]) + results = [calculate_slope_trend(total_lag, data['metadata']['warmup']) for total_lag in data['results']] + return check_service_level_objective(results=results, threshold=data['metadata']["threshold"]) logger.info("SLO evaluator is online") \ No newline at end of file diff --git a/slope-evaluator/resources/test-1-rep-success.json b/slope-evaluator/resources/test-1-rep-success.json index 9e315c707..dfe112827 100644 --- a/slope-evaluator/resources/test-1-rep-success.json +++ b/slope-evaluator/resources/test-1-rep-success.json @@ -1,5 +1,5 @@ { - "total_lags": [ + "results": [ [ { "metric": { @@ -134,6 +134,8 @@ } ] ], - "threshold": 2000, - "warmup": 0 + "metadata": { + "threshold": 2000, + "warmup": 0 + } } \ No newline at end of file diff --git a/slope-evaluator/resources/test-3-rep-success.json b/slope-evaluator/resources/test-3-rep-success.json index 485966cba..cf483f42f 100644 --- a/slope-evaluator/resources/test-3-rep-success.json +++ b/slope-evaluator/resources/test-3-rep-success.json @@ -1,5 +1,5 @@ { - "total_lags": [ + "results": [ [ { "metric": { @@ -284,6 +284,8 @@ } ] ], - "threshold": 2000, - "warmup": 0 + "metadata": { + "threshold": 2000, + "warmup": 0 + } } \ No newline at end of file diff --git a/theodolite/crd/crd-execution.yaml b/theodolite/crd/crd-execution.yaml index 47d0306f5..0debaa46d 100644 --- a/theodolite/crd/crd-execution.yaml +++ b/theodolite/crd/crd-execution.yaml @@ -51,7 +51,7 @@ spec: description: The type of the resource. It must match one of the resource types specified in the referenced benchmark. type: string resourceValues: - descriptoin: List of resource values for the specified resource type. + description: List of resource values for the specified resource type. type: array items: type: integer @@ -68,6 +68,9 @@ spec: prometheusUrl: description: Connection string for Promehteus. type: string + query: + description: The prometheus query string + type: string offset: description: Hours by which the start and end timestamp will be shifted (for different timezones). type: integer diff --git a/theodolite/examples/operator/example-execution.yaml b/theodolite/examples/operator/example-execution.yaml index e2efb6e9a..52bd499e5 100644 --- a/theodolite/examples/operator/example-execution.yaml +++ b/theodolite/examples/operator/example-execution.yaml @@ -14,6 +14,7 @@ spec: - sloType: "lag trend" prometheusUrl: "http://prometheus-operated:9090" offset: 0 + query: "sum by(group)(kafka_consumergroup_group_lag >= 0)" properties: threshold: 2000 externalSloUrl: "http://localhost:80/evaluate-slope" diff --git a/theodolite/examples/standalone/example-execution.yaml b/theodolite/examples/standalone/example-execution.yaml index 6e649df95..d25aa3866 100644 --- a/theodolite/examples/standalone/example-execution.yaml +++ b/theodolite/examples/standalone/example-execution.yaml @@ -10,6 +10,7 @@ slos: - sloType: "lag trend" prometheusUrl: "http://prometheus-operated:9090" offset: 0 + query: "sum by(group)(kafka_consumergroup_group_lag >= 0)" properties: threshold: 2000 externalSloUrl: "http://localhost:80/evaluate-slope" diff --git a/theodolite/src/main/kotlin/theodolite/benchmark/BenchmarkExecution.kt b/theodolite/src/main/kotlin/theodolite/benchmark/BenchmarkExecution.kt index f2dda487d..6aeeb2c54 100644 --- a/theodolite/src/main/kotlin/theodolite/benchmark/BenchmarkExecution.kt +++ b/theodolite/src/main/kotlin/theodolite/benchmark/BenchmarkExecution.kt @@ -63,6 +63,7 @@ class BenchmarkExecution : KubernetesResource { class Slo : KubernetesResource { lateinit var sloType: String lateinit var prometheusUrl: String + lateinit var query: String var offset by Delegates.notNull<Int>() lateinit var properties: MutableMap<String, String> } diff --git a/theodolite/src/main/kotlin/theodolite/evaluation/AnalysisExecutor.kt b/theodolite/src/main/kotlin/theodolite/evaluation/AnalysisExecutor.kt index 777ea1c0e..8e363a18e 100644 --- a/theodolite/src/main/kotlin/theodolite/evaluation/AnalysisExecutor.kt +++ b/theodolite/src/main/kotlin/theodolite/evaluation/AnalysisExecutor.kt @@ -37,6 +37,7 @@ class AnalysisExecutor( * @return true if the experiment succeeded. */ fun analyze(load: LoadDimension, res: Resource, executionIntervals: List<Pair<Instant, Instant>>): Boolean { + var result = false var repetitionCounter = 1 @@ -50,7 +51,7 @@ class AnalysisExecutor( fetcher.fetchMetric( start = interval.first, end = interval.second, - query = RECORD_LAG_QUERY + query = slo.query ) } @@ -58,7 +59,7 @@ class AnalysisExecutor( ioHandler.writeToCSVFile( fileURL = "${fileURL}_${repetitionCounter++}", data = data.getResultAsList(), - columns = listOf("group", "timestamp", "value") + columns = listOf("labels", "timestamp", "value") ) } diff --git a/theodolite/src/main/kotlin/theodolite/evaluation/ExternalSloChecker.kt b/theodolite/src/main/kotlin/theodolite/evaluation/ExternalSloChecker.kt index 448a2a05f..d646286b7 100644 --- a/theodolite/src/main/kotlin/theodolite/evaluation/ExternalSloChecker.kt +++ b/theodolite/src/main/kotlin/theodolite/evaluation/ExternalSloChecker.kt @@ -36,13 +36,12 @@ class ExternalSloChecker( */ override fun evaluate(fetchedData: List<PrometheusResponse>): Boolean { var counter = 0 - val data = Gson().toJson( - mapOf( - "total_lags" to fetchedData.map { it.data?.result }, - "threshold" to threshold, - "warmup" to warmup - ) - ) + val data = SloJson.Builder() + .results(fetchedData.map { it.data?.result }) + .addMetadata("threshold", threshold) + .addMetadata( "warmup", warmup) + .build() + .toJson() while (counter < RETRIES) { val result = post(externalSlopeURL, data = data, timeout = TIMEOUT) diff --git a/theodolite/src/main/kotlin/theodolite/evaluation/SloJson.kt b/theodolite/src/main/kotlin/theodolite/evaluation/SloJson.kt new file mode 100644 index 000000000..fc9fe17b2 --- /dev/null +++ b/theodolite/src/main/kotlin/theodolite/evaluation/SloJson.kt @@ -0,0 +1,63 @@ +package theodolite.evaluation + +import com.google.gson.Gson +import theodolite.util.PromResult + +class SloJson private constructor( + val results: List<List<PromResult>?>? = null, + var metadata: MutableMap<String, Any>? = null +) { + + data class Builder( + var results:List<List<PromResult>?>? = null, + var metadata: MutableMap<String, Any>? = null + ) { + + /** + * Set the results + * + * @param results list of prometheus results + */ + fun results(results: List<List<PromResult>?>) = apply { this.results = results } + + /** + * Add metadata as key value pairs + * + * @param key key of the metadata to be added + * @param value value of the metadata to be added + */ + fun addMetadata(key: String, value: String) = apply { + if (this.metadata.isNullOrEmpty()) { + this.metadata = mutableMapOf(key to value) + } else { + this.metadata!![key] = value + } + } + + /** + * Add metadata as key value pairs + * + * @param key key of the metadata to be added + * @param value value of the metadata to be added + */ + fun addMetadata(key: String, value: Int) = apply { + if (this.metadata.isNullOrEmpty()) { + this.metadata = mutableMapOf(key to value) + } else { + this.metadata!![key] = value + } + } + + fun build() = SloJson( + results = results, + metadata = metadata + ) + } + + fun toJson(): String { + return Gson().toJson(mapOf( + "results" to this.results, + "metadata" to this.metadata + )) + } +} \ No newline at end of file diff --git a/theodolite/src/main/kotlin/theodolite/execution/BenchmarkExecutor.kt b/theodolite/src/main/kotlin/theodolite/execution/BenchmarkExecutor.kt index e7b511d8c..e699a6f8e 100644 --- a/theodolite/src/main/kotlin/theodolite/execution/BenchmarkExecutor.kt +++ b/theodolite/src/main/kotlin/theodolite/execution/BenchmarkExecutor.kt @@ -25,7 +25,7 @@ abstract class BenchmarkExecutor( val results: Results, val executionDuration: Duration, val configurationOverrides: List<ConfigurationOverride?>, - val slo: BenchmarkExecution.Slo, + val slos: List<BenchmarkExecution.Slo>, val repetitions: Int, val executionId: Int, val loadGenerationDelay: Long, diff --git a/theodolite/src/main/kotlin/theodolite/execution/BenchmarkExecutorImpl.kt b/theodolite/src/main/kotlin/theodolite/execution/BenchmarkExecutorImpl.kt index c54d1878d..e6f55d982 100644 --- a/theodolite/src/main/kotlin/theodolite/execution/BenchmarkExecutorImpl.kt +++ b/theodolite/src/main/kotlin/theodolite/execution/BenchmarkExecutorImpl.kt @@ -20,7 +20,7 @@ class BenchmarkExecutorImpl( results: Results, executionDuration: Duration, configurationOverrides: List<ConfigurationOverride?>, - slo: BenchmarkExecution.Slo, + slos: List<BenchmarkExecution.Slo>, repetitions: Int, executionId: Int, loadGenerationDelay: Long, @@ -30,7 +30,7 @@ class BenchmarkExecutorImpl( results, executionDuration, configurationOverrides, - slo, + slos, repetitions, executionId, loadGenerationDelay, @@ -53,13 +53,19 @@ class BenchmarkExecutorImpl( * Analyse the experiment, if [run] is true, otherwise the experiment was canceled by the user. */ if (this.run.get()) { - result = AnalysisExecutor(slo = slo, executionId = executionId) - .analyze( - load = load, - res = res, - executionIntervals = executionIntervals - ) + + val experimentResults = slos.map { + AnalysisExecutor(slo = it, executionId = executionId) + .analyze( + load = load, + res = res, + executionIntervals = executionIntervals + ) + } + + result = (false !in experimentResults) this.results.setResult(Pair(load, res), result) + } return result } diff --git a/theodolite/src/main/kotlin/theodolite/execution/TheodoliteExecutor.kt b/theodolite/src/main/kotlin/theodolite/execution/TheodoliteExecutor.kt index bc9371763..0368435fa 100644 --- a/theodolite/src/main/kotlin/theodolite/execution/TheodoliteExecutor.kt +++ b/theodolite/src/main/kotlin/theodolite/execution/TheodoliteExecutor.kt @@ -64,7 +64,7 @@ class TheodoliteExecutor( results = results, executionDuration = executionDuration, configurationOverrides = config.configOverrides, - slo = config.slos[0], + slos = config.slos, repetitions = config.execution.repetitions, executionId = config.executionId, loadGenerationDelay = config.execution.loadGenerationDelay, diff --git a/theodolite/src/main/kotlin/theodolite/util/PrometheusResponse.kt b/theodolite/src/main/kotlin/theodolite/util/PrometheusResponse.kt index bf33fcf61..72fa6779c 100644 --- a/theodolite/src/main/kotlin/theodolite/util/PrometheusResponse.kt +++ b/theodolite/src/main/kotlin/theodolite/util/PrometheusResponse.kt @@ -23,7 +23,7 @@ data class PrometheusResponse( * The format of the returned list is: `[[ group, timestamp, value ], [ group, timestamp, value ], ... ]` */ fun getResultAsList(): List<List<String>> { - val group = data?.result?.get(0)?.metric?.group.toString() + val group = data?.result?.get(0)?.metric?.toString()!! val values = data?.result?.get(0)?.values val result = mutableListOf<List<String>>() @@ -64,18 +64,9 @@ data class PromResult( /** * Label of the metric */ - var metric: PromMetric? = null, + var metric: Map<String,String>? = null, /** * Values of the metric (e.g. [ [ <unix_time>, "<sample_value>" ], ... ]) */ var values: List<Any>? = null -) - -/** - * Corresponds to the metric field in the range-vector result format of a Prometheus range-query response. - */ -@RegisterForReflection -data class PromMetric( - var group: String? = null -) - +) \ No newline at end of file diff --git a/theodolite/src/test/kotlin/theodolite/CompositeStrategyTest.kt b/theodolite/src/test/kotlin/theodolite/CompositeStrategyTest.kt index 49131352c..675ba9e35 100644 --- a/theodolite/src/test/kotlin/theodolite/CompositeStrategyTest.kt +++ b/theodolite/src/test/kotlin/theodolite/CompositeStrategyTest.kt @@ -31,7 +31,7 @@ class CompositeStrategyTest { val results = Results() val benchmark = TestBenchmark() val sloChecker: BenchmarkExecution.Slo = BenchmarkExecution.Slo() - val benchmarkExecutor = TestBenchmarkExecutorImpl(mockResults, benchmark, results, sloChecker, 0, 0, 5) + val benchmarkExecutor = TestBenchmarkExecutorImpl(mockResults, benchmark, results, listOf(sloChecker), 0, 0, 5) val linearSearch = LinearSearch(benchmarkExecutor) val lowerBoundRestriction = LowerBoundRestriction(results) val strategy = @@ -65,7 +65,7 @@ class CompositeStrategyTest { val benchmark = TestBenchmark() val sloChecker: BenchmarkExecution.Slo = BenchmarkExecution.Slo() val benchmarkExecutorImpl = - TestBenchmarkExecutorImpl(mockResults, benchmark, results, sloChecker, 0, 0, 0) + TestBenchmarkExecutorImpl(mockResults, benchmark, results, listOf(sloChecker), 0, 0, 0) val binarySearch = BinarySearch(benchmarkExecutorImpl) val lowerBoundRestriction = LowerBoundRestriction(results) val strategy = @@ -98,7 +98,7 @@ class CompositeStrategyTest { val results = Results() val benchmark = TestBenchmark() val sloChecker: BenchmarkExecution.Slo = BenchmarkExecution.Slo() - val benchmarkExecutor = TestBenchmarkExecutorImpl(mockResults, benchmark, results, sloChecker, 0, 0, 0) + val benchmarkExecutor = TestBenchmarkExecutorImpl(mockResults, benchmark, results, listOf(sloChecker), 0, 0, 0) val binarySearch = BinarySearch(benchmarkExecutor) val lowerBoundRestriction = LowerBoundRestriction(results) val strategy = @@ -114,4 +114,5 @@ class CompositeStrategyTest { assertEquals(actual, expected) } + } diff --git a/theodolite/src/test/kotlin/theodolite/TestBenchmarkExecutorImpl.kt b/theodolite/src/test/kotlin/theodolite/TestBenchmarkExecutorImpl.kt index cbd2d5926..ac7c7883f 100644 --- a/theodolite/src/test/kotlin/theodolite/TestBenchmarkExecutorImpl.kt +++ b/theodolite/src/test/kotlin/theodolite/TestBenchmarkExecutorImpl.kt @@ -12,7 +12,7 @@ class TestBenchmarkExecutorImpl( private val mockResults: Array<Array<Boolean>>, benchmark: Benchmark, results: Results, - slo: BenchmarkExecution.Slo, + slo: List<BenchmarkExecution.Slo>, executionId: Int, loadGenerationDelay: Long, afterTeardownDelay: Long @@ -22,7 +22,7 @@ class TestBenchmarkExecutorImpl( results, executionDuration = Duration.ofSeconds(1), configurationOverrides = emptyList(), - slo = slo, + slos = slo, repetitions = 1, executionId = executionId, loadGenerationDelay = loadGenerationDelay, diff --git a/theodolite/src/test/resources/k8s-resource-files/test-execution-update.yaml b/theodolite/src/test/resources/k8s-resource-files/test-execution-update.yaml index c075702da..4689e468d 100644 --- a/theodolite/src/test/resources/k8s-resource-files/test-execution-update.yaml +++ b/theodolite/src/test/resources/k8s-resource-files/test-execution-update.yaml @@ -15,6 +15,7 @@ spec: - sloType: "lag trend" prometheusUrl: "http://prometheus-operated:9090" offset: 0 + query: "sum by(group)(kafka_consumergroup_group_lag >= 0)" properties: threshold: 2000 externalSloUrl: "http://localhost:80/evaluate-slope" diff --git a/theodolite/src/test/resources/k8s-resource-files/test-execution.yaml b/theodolite/src/test/resources/k8s-resource-files/test-execution.yaml index e12c851da..816915ad8 100644 --- a/theodolite/src/test/resources/k8s-resource-files/test-execution.yaml +++ b/theodolite/src/test/resources/k8s-resource-files/test-execution.yaml @@ -15,6 +15,7 @@ spec: - sloType: "lag trend" prometheusUrl: "http://prometheus-operated:9090" offset: 0 + query: "sum by(group)(kafka_consumergroup_group_lag >= 0)" properties: threshold: 2000 externalSloUrl: "http://localhost:80/evaluate-slope" -- GitLab