From 66a1d670610c1d147692c1afeb126fb18ae33e73 Mon Sep 17 00:00:00 2001 From: Andrey Novikov Date: Thu, 19 Aug 2021 01:03:23 +0900 Subject: [PATCH 1/3] Instrumentation and monitoring Co-authored-by: palkan --- .dockerdev/compose.yml | 41 + Gemfile | 6 + Gemfile.lock | 37 +- README.md | 16 + config/initializers/metrics.rb | 8 + config/puma.rb | 4 + etc/grafana/dashboards/anycable_combined.json | 1076 +++++++++++++++++ etc/grafana/dashboards/anycable_go.json | 729 +++++++++++ etc/grafana/dashboards/anycable_rpc.json | 284 +++++ .../docker_resource_consumption.json | 462 +++++++ etc/grafana/dashboards/rails_puma.json | 739 +++++++++++ etc/grafana/provisioning/dashboards/all.yml | 9 + etc/grafana/provisioning/datasources/all.yml | 15 + etc/prometheus/prometheus.yml | 29 + 14 files changed, 3454 insertions(+), 1 deletion(-) create mode 100644 config/initializers/metrics.rb create mode 100644 etc/grafana/dashboards/anycable_combined.json create mode 100644 etc/grafana/dashboards/anycable_go.json create mode 100644 etc/grafana/dashboards/anycable_rpc.json create mode 100644 etc/grafana/dashboards/docker_resource_consumption.json create mode 100644 etc/grafana/dashboards/rails_puma.json create mode 100644 etc/grafana/provisioning/dashboards/all.yml create mode 100644 etc/grafana/provisioning/datasources/all.yml create mode 100644 etc/prometheus/prometheus.yml diff --git a/.dockerdev/compose.yml b/.dockerdev/compose.yml index b29f4bbd..02cd8427 100644 --- a/.dockerdev/compose.yml +++ b/.dockerdev/compose.yml @@ -40,6 +40,7 @@ x-backend: &backend ACTION_CABLE_ADAPTER: ${ACTION_CABLE_ADAPTER:-anycable} ANYCABLE_RPC_HOST: 0.0.0.0:50051 ANYCABLE_BROADCAST_ADAPTER: redis + PROMETHEUS_EXPORTER_PORT: 5100 CHROME_URL: http://chrome:3333 EDITOR: vi LOG: ${LOG:-0} @@ -102,6 +103,9 @@ services: ANYCABLE_REDIS_URL: redis://redis:6379/0 ANYCABLE_RPC_HOST: anycable:50051 ANYCABLE_DEBUG: ${ANYCABLE_DEBUG:-1} + ANYCABLE_METRICS_HOST: "0.0.0.0" + ANYCABLE_METRICS_PORT: 5100 + ANYCABLE_METRICS_HTTP: /metrics depends_on: redis: condition: service_healthy @@ -179,6 +183,42 @@ services: # https://docs.browserless.io/docs/docker.html#connection-timeout CONNECTION_TIMEOUT: 600000 + prometheus: + image: prom/prometheus:v2.29.1 + volumes: + - ./etc/prometheus/prometheus.yml:/etc/prometheus/prometheus.yml + ports: + - "9090:9090" + command: + - --config.file=/etc/prometheus/prometheus.yml + + grafana: + image: grafana/grafana:8.1.1 + ports: + - "5000:3000" + volumes: + - ./etc/grafana/provisioning:/etc/grafana/provisioning + - ./etc/grafana/dashboards:/var/lib/grafana/dashboards + - grafana:/var/lib/grafana + user: "472" + depends_on: + prometheus: + condition: service_started + cadvisor: + condition: service_started + + # Collects runtime metrics from Docker containers (CPU, RAM, etc) + cadvisor: + image: gcr.io/cadvisor/cadvisor:latest + ports: + - 8082:8080 + volumes: + - /:/rootfs:ro + - /var/run:/var/run:ro + - /sys:/sys:ro + - /var/lib/docker/:/var/lib/docker:ro + - /var/run/docker.sock:/var/run/docker.sock:ro + volumes: postgres: redis: @@ -188,3 +228,4 @@ volumes: history: assets: assets_builds: + grafana: diff --git a/Gemfile b/Gemfile index a25c5d49..7051f9b6 100644 --- a/Gemfile +++ b/Gemfile @@ -20,6 +20,12 @@ gem 'cssbundling-rails' gem 'jsbundling-rails' gem 'propshaft' +gem "yabeda-anycable" +gem "yabeda-rails" +gem "yabeda-puma-plugin" +gem "yabeda-prometheus" +gem "webrick" # For exporting metrics from AnyCable RPC + group :development, :test do gem 'debug' gem 'rspec-rails', '~> 4.0.0' diff --git a/Gemfile.lock b/Gemfile.lock index f9baf60e..25c42b25 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -106,6 +106,8 @@ GEM reline (>= 0.2.7) diff-lcs (1.5.0) digest (3.1.0) + dry-initializer (3.0.4) + equalizer (0.0.11) erubi (1.10.0) ferrum (0.11) addressable (~> 2.5) @@ -126,9 +128,14 @@ GEM io-wait (0.2.1) irb (1.4.1) reline (>= 0.3.0) + ice_nine (0.11.2) jsbundling-rails (1.0.2) railties (>= 6.0.0) - loofah (2.15.0) + json (2.5.1) + listen (3.4.1) + rb-fsevent (~> 0.10, >= 0.10.3) + rb-inotify (~> 0.9, >= 0.9.10) + loofah (2.9.0) crass (~> 1.0.2) nokogiri (>= 1.5.9) mail (2.7.1) @@ -161,6 +168,8 @@ GEM parser (3.1.1.0) ast (~> 2.4.1) pg (1.3.4) + procto (0.0.3) + prometheus-client (2.1.0) propshaft (0.6.4) actionpack (>= 7.0.0) activesupport (>= 7.0.0) @@ -241,11 +250,32 @@ GEM diff-lcs (~> 1.3) parser (>= 3.1.0) websocket-driver (0.7.5) + webrick (1.7.0) + websocket-driver (0.7.3) websocket-extensions (>= 0.1.0) websocket-extensions (0.1.5) xpath (3.2.0) nokogiri (~> 1.8) zeitwerk (2.5.4) + yabeda (0.10.0) + anyway_config (>= 1.3, < 3) + concurrent-ruby + dry-initializer + yabeda-anycable (0.1.0) + anycable-core (~> 1.1) + yabeda (~> 0.10) + yabeda-prometheus (0.7.0) + prometheus-client (>= 0.10, < 3.0) + rack + yabeda (~> 0.10) + yabeda-puma-plugin (0.6.0) + json + puma + yabeda (~> 0.5) + yabeda-rails (0.7.2) + rails + yabeda (~> 0.8) + zeitwerk (2.4.2) PLATFORMS aarch64-linux @@ -271,6 +301,11 @@ DEPENDENCIES ruby-next (>= 0.15.0) test-prof turbo-rails + webrick + yabeda-anycable + yabeda-prometheus + yabeda-puma-plugin + yabeda-rails RUBY VERSION ruby 3.1.1p18 diff --git a/README.md b/README.md index db726a00..3f78428d 100644 --- a/README.md +++ b/README.md @@ -59,6 +59,22 @@ dip rspec dip rspec system ``` +## Instrumentation + +You can also collect and visualize instrumentation metrics via Prometheus and Grafana: + +```sh +# Start Prometheus, Grafana and Cadvisor +dip up -d grafana +``` + +Open Grafana at [localhost:5000](http://localhost:5000/) (login `admin`, password `admin`) and navigate to Dashboards → Manage. + +Or just open dashboards using the direct links: + +- [AnyCable](http://localhost:5000/d/anycable-combined/anycable-combined) +- [Docker containers CPU and RAM usage](http://localhost:5000/d/docker-containers/resource-consumption) + ## Resources - [Ruby on Whales](https://evilmartians.com/chronicles/ruby-on-whales-docker-for-ruby-rails-development)—learn about the Docker development setup used for this application. diff --git a/config/initializers/metrics.rb b/config/initializers/metrics.rb new file mode 100644 index 00000000..9b954bb9 --- /dev/null +++ b/config/initializers/metrics.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +# To collect metrics from all processes +Prometheus::Client.config.data_store = Prometheus::Client::DataStores::DirectFileStore.new(dir: "/tmp/prometheus_direct_file_store") + +AnyCable.configure_server do + Yabeda::Prometheus::Exporter.start_metrics_server! +end diff --git a/config/puma.rb b/config/puma.rb index 761e78f4..f22839b7 100644 --- a/config/puma.rb +++ b/config/puma.rb @@ -40,3 +40,7 @@ # Allow puma to be restarted by `rails restart` command. plugin :tmp_restart + +activate_control_app +plugin :yabeda +plugin :yabeda_prometheus diff --git a/etc/grafana/dashboards/anycable_combined.json b/etc/grafana/dashboards/anycable_combined.json new file mode 100644 index 00000000..ce47b11d --- /dev/null +++ b/etc/grafana/dashboards/anycable_combined.json @@ -0,0 +1,1076 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "id": null, + "links": [], + "panels": [ + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": null, + "decimals": null, + "fieldConfig": { + "defaults": { + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 5, + "w": 12, + "x": 0, + "y": 0 + }, + "hiddenSeries": false, + "id": 4, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "sideWidth": 250, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "8.1.1", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "anycable_go_clients_num", + "interval": "", + "legendFormat": "total", + "refId": "A" + }, + { + "expr": "anycable_go_clients_uniq_num", + "interval": "", + "legendFormat": "uniq", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Number of clients", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": null, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 5, + "w": 12, + "x": 12, + "y": 0 + }, + "hiddenSeries": false, + "id": 11, + "legend": { + "alignAsTable": true, + "avg": true, + "current": false, + "max": true, + "min": false, + "rightSide": true, + "show": true, + "sideWidth": 300, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "8.1.1", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "rate(anycable_go_rpc_call_total[$__rate_interval])", + "interval": "", + "legendFormat": "total", + "refId": "A" + }, + { + "expr": "rate(anycable_go_rpc_error_total[$__rate_interval])", + "interval": "", + "legendFormat": "errors", + "refId": "B" + }, + { + "expr": "rate(anycable_go_rpc_retries_total[$__rate_interval])", + "interval": "", + "legendFormat": "retries", + "refId": "C" + }, + { + "expr": "rate(anycable_go_rpc_pending_num[$__rate_interval])", + "interval": "", + "legendFormat": "pending", + "refId": "D" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "RPC calls", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": null, + "fieldConfig": { + "defaults": { + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 5, + "w": 12, + "x": 0, + "y": 5 + }, + "hiddenSeries": false, + "id": 2, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": false, + "rightSide": true, + "show": true, + "sideWidth": 250, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "8.1.1", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "errors", + "bars": true, + "color": "#C4162A", + "fillGradient": 1, + "lines": false + } + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "increase(anycable_go_broadcast_msg_total[$__rate_interval])", + "interval": "10s", + "legendFormat": "msgs", + "refId": "A" + }, + { + "expr": "increase(anycable_go_failed_broadcast_msg_total[$__rate_interval])", + "interval": "10s", + "legendFormat": "errors", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Total anycable messages broadcasted", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "cps", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": null, + "decimals": null, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 5, + "w": 12, + "x": 12, + "y": 5 + }, + "hiddenSeries": false, + "id": 23, + "legend": { + "alignAsTable": true, + "avg": true, + "current": false, + "hideEmpty": true, + "max": true, + "min": false, + "rightSide": true, + "show": true, + "sideWidth": 300, + "sort": "max", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "8.1.1", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "exemplar": true, + "expr": "histogram_quantile(0.95, sum(rate(anycable_rpc_call_runtime_seconds_bucket[1m])) by (method,command,le))", + "interval": "", + "legendFormat": "{{method}}: {{command}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "RPC call runtime (95th percentile)", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": null, + "fieldConfig": { + "defaults": { + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 5, + "w": 12, + "x": 0, + "y": 10 + }, + "hiddenSeries": false, + "id": 5, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": false, + "rightSide": true, + "show": true, + "sideWidth": 250, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "8.1.1", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "errors", + "bars": true, + "color": "#C4162A", + "fillGradient": 1, + "lines": false + } + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "rate(anycable_go_client_msg_total[$__rate_interval])", + "interval": "", + "legendFormat": "msgs", + "refId": "A" + }, + { + "expr": "rate(anycable_go_failed_client_msg_total[$__rate_interval])", + "interval": "", + "legendFormat": "errors", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Client anycable messages", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "cps", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": null, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 5, + "w": 12, + "x": 12, + "y": 10 + }, + "hiddenSeries": false, + "id": 25, + "legend": { + "alignAsTable": true, + "avg": true, + "current": false, + "hideEmpty": true, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "sideWidth": 300, + "sort": "max", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "8.1.1", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "exemplar": true, + "expr": "sum(rate(anycable_rpc_call_count[1m])) by (method, command, status)", + "interval": "", + "legendFormat": "{{method}}: {{command}} ({{status}})", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "RPC call throughput", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 0, + "format": "reqps", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "datasource": null, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 6, + "x": 0, + "y": 15 + }, + "id": 17, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.1.1", + "targets": [ + { + "exemplar": true, + "expr": "anycable_go_failed_auths_total", + "interval": "", + "legendFormat": "", + "refId": "A" + } + ], + "title": "Failed authentication attempts", + "type": "stat" + }, + { + "datasource": null, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 6, + "x": 6, + "y": 15 + }, + "id": 19, + "options": { + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true, + "text": {} + }, + "pluginVersion": "8.1.1", + "targets": [ + { + "exemplar": true, + "expr": "anycable_go_disconnect_queue_size", + "interval": "", + "legendFormat": "", + "refId": "A" + } + ], + "title": "Disconnect queue size", + "type": "gauge" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": null, + "description": "This is memory usage reported by anycable-go itself", + "fieldConfig": { + "defaults": { + "unit": "decbytes" + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 5, + "w": 12, + "x": 12, + "y": 15 + }, + "hiddenSeries": false, + "id": 15, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "max": true, + "min": false, + "rightSide": true, + "show": true, + "sideWidth": 250, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "8.1.1", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "anycable_go_mem_sys_bytes", + "interval": "", + "legendFormat": "mem", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "AnyCable Go Memory", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "decbytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "datasource": null, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "decbytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 12, + "x": 0, + "y": 20 + }, + "id": 21, + "options": { + "legend": { + "calcs": [ + "sum" + ], + "displayMode": "table", + "placement": "right" + }, + "tooltip": { + "mode": "single" + } + }, + "targets": [ + { + "exemplar": true, + "expr": "anycable_go_data_rcvd_total", + "instant": false, + "interval": "", + "legendFormat": "In (bytes)", + "refId": "A" + }, + { + "exemplar": true, + "expr": "anycable_go_data_sent_total", + "hide": false, + "interval": "", + "legendFormat": "Out (bytes)", + "refId": "B" + } + ], + "title": "In/out data", + "type": "timeseries" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": null, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 5, + "w": 12, + "x": 12, + "y": 20 + }, + "hiddenSeries": false, + "id": 9, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "max": true, + "min": false, + "rightSide": true, + "show": true, + "sideWidth": 250, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "8.1.1", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "anycable_go_goroutines_num", + "interval": "", + "legendFormat": "goroutines", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Go routines number", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": "5s", + "schemaVersion": 30, + "style": "dark", + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "AnyCable (combined)", + "uid": "anycable-combined", + "version": 2 +} \ No newline at end of file diff --git a/etc/grafana/dashboards/anycable_go.json b/etc/grafana/dashboards/anycable_go.json new file mode 100644 index 00000000..ae0540fc --- /dev/null +++ b/etc/grafana/dashboards/anycable_go.json @@ -0,0 +1,729 @@ +{ + "__inputs": [ + { + "name": "DS_PROMETHEUS", + "label": "Prometheus", + "description": "", + "type": "datasource", + "pluginId": "prometheus", + "pluginName": "Prometheus" + } + ], + "__requires": [ + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "6.6.0" + }, + { + "type": "panel", + "id": "graph", + "name": "Graph", + "version": "" + }, + { + "type": "datasource", + "id": "prometheus", + "name": "Prometheus", + "version": "1.0.0" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "id": null, + "iteration": 1629304815665, + "links": [], + "panels": [ + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": null, + "decimals": null, + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 5, + "w": 24, + "x": 0, + "y": 0 + }, + "hiddenSeries": false, + "id": 4, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "sideWidth": 250, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "7.3.1", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "anycable_go_clients_num", + "interval": "", + "legendFormat": "total", + "refId": "A" + }, + { + "expr": "anycable_go_clients_uniq_num", + "interval": "", + "legendFormat": "uniq", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Number of clients", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": null, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 5, + "w": 24, + "x": 0, + "y": 5 + }, + "hiddenSeries": false, + "id": 9, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "sideWidth": 250, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "7.3.1", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "anycable_go_goroutines_num", + "interval": "", + "legendFormat": "goroutines", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Go routines number", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": null, + "description": "This is memory usage reported by anycable-go itself", + "fieldConfig": { + "defaults": { + "custom": {}, + "unit": "decbytes" + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 5, + "w": 24, + "x": 0, + "y": 10 + }, + "hiddenSeries": false, + "id": 15, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "sideWidth": 250, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "7.3.1", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "anycable_go_mem_sys_bytes", + "interval": "", + "legendFormat": "mem", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "AnyCable Go Memory", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "decbytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": null, + "fieldConfig": { + "defaults": { + "custom": {}, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 6, + "w": 24, + "x": 0, + "y": 21 + }, + "hiddenSeries": false, + "id": 11, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": false, + "rightSide": true, + "show": true, + "sideWidth": 250, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "7.3.1", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "rate(anycable_go_rpc_call_total[$__rate_interval])", + "interval": "", + "legendFormat": "total", + "refId": "A" + }, + { + "expr": "rate(anycable_go_rpc_error_total[$__rate_interval])", + "interval": "", + "legendFormat": "errors", + "refId": "B" + }, + { + "expr": "rate(anycable_go_rpc_retries_total[$__rate_interval])", + "interval": "", + "legendFormat": "retries", + "refId": "C" + }, + { + "expr": "rate(anycable_go_rpc_pending_num[$__rate_interval])", + "interval": "", + "legendFormat": "pending", + "refId": "D" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "RPC calls", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": null, + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 6, + "w": 24, + "x": 0, + "y": 27 + }, + "hiddenSeries": false, + "id": 2, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": false, + "rightSide": true, + "show": true, + "sideWidth": 250, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "7.3.1", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "errors", + "bars": true, + "color": "#C4162A", + "fillGradient": 1, + "lines": false + } + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "increase(anycable_go_broadcast_msg_total[$__rate_interval])", + "interval": "10s", + "legendFormat": "msgs", + "refId": "A" + }, + { + "expr": "increase(anycable_go_failed_broadcast_msg_total[$__rate_interval])", + "interval": "10s", + "legendFormat": "errors", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Total anycable messages broadcasted", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "cps", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": null, + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 6, + "w": 24, + "x": 0, + "y": 33 + }, + "hiddenSeries": false, + "id": 5, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": false, + "rightSide": true, + "show": true, + "sideWidth": 250, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "7.3.1", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "errors", + "bars": true, + "color": "#C4162A", + "fillGradient": 1, + "lines": false + } + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "rate(anycable_go_client_msg_total[$__rate_interval])", + "interval": "", + "legendFormat": "msgs", + "refId": "A" + }, + { + "expr": "rate(anycable_go_failed_client_msg_total[$__rate_interval])", + "interval": "", + "legendFormat": "errors", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Client anycable messages", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "cps", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": "5s", + "schemaVersion": 27, + "style": "dark", + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "AnyCable Go", + "uid": "anycable-go", + "version": 1 +} \ No newline at end of file diff --git a/etc/grafana/dashboards/anycable_rpc.json b/etc/grafana/dashboards/anycable_rpc.json new file mode 100644 index 00000000..0b246555 --- /dev/null +++ b/etc/grafana/dashboards/anycable_rpc.json @@ -0,0 +1,284 @@ +{ + "__inputs": [ + { + "name": "DS_PROMETHEUS", + "label": "Prometheus", + "description": "", + "type": "datasource", + "pluginId": "prometheus", + "pluginName": "Prometheus" + } + ], + "__requires": [ + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "6.6.0" + }, + { + "type": "panel", + "id": "graph", + "name": "Graph", + "version": "" + }, + { + "type": "datasource", + "id": "prometheus", + "name": "Prometheus", + "version": "1.0.0" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "description": "", + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "id": null, + "links": [ + { + "asDropdown": false, + "icon": "doc", + "includeVars": false, + "keepTime": false, + "tags": [], + "targetBlank": true, + "title": "yabeda-anycable", + "tooltip": "Open anycable-yabeda homepage and docs", + "type": "link", + "url": "https://github.com/yabeda-rb/yabeda-anycable" + } + ], + "panels": [ + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": null, + "decimals": null, + "fieldConfig": { + "defaults": {}, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 9, + "w": 23, + "x": 0, + "y": 0 + }, + "hiddenSeries": false, + "id": 4, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "hideEmpty": true, + "max": true, + "min": false, + "rightSide": true, + "show": true, + "sideWidth": 350, + "sort": "max", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "7.5.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "exemplar": true, + "expr": "histogram_quantile(0.95, sum(rate(anycable_rpc_call_runtime_seconds_bucket[1m])) by (method,command,le))", + "interval": "", + "legendFormat": "{{method}}: {{command}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "RPC call runtime (95th percentile)", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": null, + "fieldConfig": { + "defaults": {}, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 9, + "w": 23, + "x": 0, + "y": 9 + }, + "hiddenSeries": false, + "id": 2, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "hideEmpty": true, + "max": true, + "min": false, + "rightSide": true, + "show": true, + "sideWidth": 350, + "sort": "max", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "7.5.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "exemplar": true, + "expr": "sum(rate(anycable_rpc_call_count[1m])) by (method, command, status)", + "interval": "", + "legendFormat": "{{method}}: {{command}} ({{status}})", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "RPC call throughput", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 0, + "format": "reqps", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": "5s", + "schemaVersion": 27, + "style": "dark", + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "AnyCable RPC", + "uid": "yabeda-anycable", + "version": 1 +} \ No newline at end of file diff --git a/etc/grafana/dashboards/docker_resource_consumption.json b/etc/grafana/dashboards/docker_resource_consumption.json new file mode 100644 index 00000000..5b530272 --- /dev/null +++ b/etc/grafana/dashboards/docker_resource_consumption.json @@ -0,0 +1,462 @@ +{ + "__inputs": [ + { + "name": "DS_PROMETHEUS", + "label": "Prometheus", + "description": "", + "type": "datasource", + "pluginId": "prometheus", + "pluginName": "Prometheus" + } + ], + "__requires": [ + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "7.2.0" + }, + { + "type": "panel", + "id": "timeseries", + "name": "Time series", + "version": "" + }, + { + "type": "datasource", + "id": "prometheus", + "name": "Prometheus", + "version": "1.0.0" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "id": null, + "iteration": 1629345603122, + "links": [], + "panels": [ + { + "collapsed": false, + "datasource": null, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 6, + "panels": [], + "repeat": "component", + "title": "Resource consumption for $component", + "type": "row" + }, + { + "datasource": null, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "smooth", + "lineWidth": 1, + "pointSize": 1, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 1 + }, + "id": 2, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi" + } + }, + "repeat": null, + "targets": [ + { + "exemplar": true, + "expr": "sum(rate(container_cpu_usage_seconds_total{container_label_com_docker_compose_service=\"$component\"}[$__rate_interval])) by (name)", + "interval": "", + "legendFormat": "{{name}}", + "refId": "A" + } + ], + "title": "CPU usage", + "type": "timeseries" + }, + { + "datasource": null, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 1 + }, + "id": 12, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "single" + } + }, + "targets": [ + { + "exemplar": true, + "expr": "container_memory_working_set_bytes{container_label_com_docker_compose_service=\"$component\"}", + "interval": "", + "legendFormat": "{{name}}", + "refId": "A" + } + ], + "title": "Total memory usage", + "type": "timeseries" + }, + { + "datasource": null, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "binBps" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 12, + "x": 0, + "y": 9 + }, + "id": 20, + "options": { + "legend": { + "calcs": [], + "displayMode": "hidden", + "placement": "bottom" + }, + "tooltip": { + "mode": "single" + } + }, + "targets": [ + { + "exemplar": true, + "expr": "sum(rate(container_network_transmit_bytes_total{container_label_com_docker_compose_service=\"$component\"}[$__rate_interval])) by (name)", + "interval": "", + "legendFormat": "{{name}}", + "refId": "A" + } + ], + "title": "Network transmit", + "type": "timeseries" + }, + { + "datasource": null, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "binBps" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 12, + "x": 12, + "y": 9 + }, + "id": 29, + "options": { + "legend": { + "calcs": [], + "displayMode": "hidden", + "placement": "bottom" + }, + "tooltip": { + "mode": "single" + } + }, + "targets": [ + { + "exemplar": true, + "expr": "sum(rate(container_network_receive_bytes_total{container_label_com_docker_compose_service=\"$component\"}[$__rate_interval])) by (name)", + "interval": "", + "legendFormat": "{{name}}", + "refId": "A" + } + ], + "title": "Network receive", + "type": "timeseries" + } + ], + "refresh": "5s", + "schemaVersion": 30, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "allValue": null, + "current": { + "selected": true, + "text": [ + "All" + ], + "value": [ + "$__all" + ] + }, + "description": null, + "error": null, + "hide": 0, + "includeAll": true, + "label": null, + "multi": true, + "name": "component", + "options": [ + { + "selected": true, + "text": "All", + "value": "$__all" + }, + { + "selected": false, + "text": "rails", + "value": "rails" + }, + { + "selected": false, + "text": "anycable", + "value": "anycable" + }, + { + "selected": false, + "text": "ws", + "value": "ws" + } + ], + "query": "rails,anycable,ws", + "queryValue": "", + "skipUrlSync": false, + "type": "custom" + } + ] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "Resource consumption", + "uid": "docker-containers", + "version": 2 +} \ No newline at end of file diff --git a/etc/grafana/dashboards/rails_puma.json b/etc/grafana/dashboards/rails_puma.json new file mode 100644 index 00000000..d7ae2692 --- /dev/null +++ b/etc/grafana/dashboards/rails_puma.json @@ -0,0 +1,739 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "description": "Basic Rails and Puma metrics", + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "id": 5, + "links": [], + "panels": [ + { + "datasource": null, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 0 + }, + "id": 10, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "single" + } + }, + "pluginVersion": "8.1.1", + "targets": [ + { + "exemplar": true, + "expr": "(sum(increase(rails_requests_total[1m])) by (status))", + "format": "time_series", + "interval": "", + "legendFormat": "total ({{status}})", + "refId": "A" + } + ], + "title": "Throughput", + "type": "timeseries" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": null, + "fieldConfig": { + "defaults": { + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 0 + }, + "hiddenSeries": false, + "id": 14, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "hideEmpty": true, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "paceLength": 10, + "percentage": false, + "pluginVersion": "8.1.1", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "exemplar": true, + "expr": "sum(rate(rails_request_duration_seconds_sum[1m]))\n/\nsum(rate(rails_request_duration_seconds_count[1m]))", + "format": "time_series", + "interval": "", + "intervalFactor": 2, + "legendFormat": "total", + "refId": "B" + }, + { + "exemplar": true, + "expr": "sum(rate(rails_db_runtime_seconds_sum[1m]))\n/\nsum(rate(rails_db_runtime_seconds_count[1m]))", + "format": "time_series", + "interval": "", + "intervalFactor": 2, + "legendFormat": "db", + "refId": "A" + }, + { + "exemplar": true, + "expr": "sum(rate(rails_view_runtime_seconds_sum[1m]))\n/\nsum(rate(rails_view_runtime_seconds_count[1m]))", + "format": "time_series", + "interval": "", + "intervalFactor": 2, + "legendFormat": "view", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Rails average response time", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "dtdurations", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "datasource": null, + "description": "The number of connections waiting for a worker thread", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 6 + }, + "id": 6, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "single" + } + }, + "targets": [ + { + "exemplar": true, + "expr": "sum(puma_backlog)", + "interval": "", + "legendFormat": "backlog", + "refId": "A" + } + ], + "title": "Puma backlog", + "type": "timeseries" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": null, + "fieldConfig": { + "defaults": { + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 6 + }, + "hiddenSeries": false, + "id": 18, + "legend": { + "alignAsTable": true, + "avg": true, + "current": false, + "hideEmpty": true, + "hideZero": true, + "max": true, + "min": false, + "rightSide": true, + "show": true, + "sort": "total", + "sortDesc": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "paceLength": 10, + "percentage": false, + "pluginVersion": "8.1.1", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "exemplar": true, + "expr": "sum(increase(rails_requests_total[1m])) by (controller, action)", + "format": "time_series", + "interval": "", + "intervalFactor": 2, + "legendFormat": "{{controller}}#{{action}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Throughput / Endpoint", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "rpm", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "datasource": null, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "percentunit" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 12 + }, + "id": 4, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "single" + } + }, + "targets": [ + { + "exemplar": true, + "expr": "(puma_max_threads - puma_pool_capacity) / puma_running", + "interval": "", + "legendFormat": "utilization (worker {{ index }})", + "refId": "A" + } + ], + "title": "Puma threads utilization", + "type": "timeseries" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": null, + "fieldConfig": { + "defaults": { + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 12 + }, + "hiddenSeries": false, + "id": 16, + "legend": { + "alignAsTable": true, + "avg": true, + "current": false, + "hideEmpty": true, + "hideZero": true, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "sort": "avg", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "paceLength": 10, + "percentage": false, + "pluginVersion": "8.1.1", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "exemplar": true, + "expr": "histogram_quantile(0.95, sum(rate(rails_request_duration_seconds_bucket[1m])) by (le,controller,action))", + "format": "time_series", + "interval": "", + "intervalFactor": 2, + "legendFormat": "{{controller}}#{{action}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Rails 95% response time by endpoint", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 10, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "datasource": null, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 6, + "x": 0, + "y": 18 + }, + "id": 8, + "options": { + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true, + "text": {} + }, + "pluginVersion": "8.1.1", + "targets": [ + { + "exemplar": true, + "expr": "sum(puma_max_threads)", + "interval": "", + "legendFormat": "", + "refId": "A" + } + ], + "title": "Puma max threads", + "type": "gauge" + }, + { + "datasource": null, + "description": "The total number of Puma workers currently running", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 6, + "x": 6, + "y": 18 + }, + "id": 2, + "options": { + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true, + "text": {} + }, + "pluginVersion": "8.1.1", + "targets": [ + { + "exemplar": true, + "expr": "sum(puma_workers)", + "interval": "", + "legendFormat": "Total", + "refId": "A" + } + ], + "title": "Puma workers", + "type": "gauge" + } + ], + "refresh": false, + "schemaVersion": 30, + "style": "dark", + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "Rails / Puma", + "uid": "rails-puma", + "version": 7 +} diff --git a/etc/grafana/provisioning/dashboards/all.yml b/etc/grafana/provisioning/dashboards/all.yml new file mode 100644 index 00000000..584689a8 --- /dev/null +++ b/etc/grafana/provisioning/dashboards/all.yml @@ -0,0 +1,9 @@ +apiVersion: 1 + +providers: +- name: 'default' # name of this dashboard configuration (not dashboard itself) + orgId: 1 # id of the org to hold the dashboard + folder: '' # name of the folder to put the dashboard (http://docs.grafana.org/v5.0/reference/dashboard_folders/) + type: 'file' # type of dashboard description (json files) + options: + path: '/var/lib/grafana/dashboards' # where dashboards are diff --git a/etc/grafana/provisioning/datasources/all.yml b/etc/grafana/provisioning/datasources/all.yml new file mode 100644 index 00000000..0be3d1d4 --- /dev/null +++ b/etc/grafana/provisioning/datasources/all.yml @@ -0,0 +1,15 @@ +# https://github.com/cirocosta/sample-grafana/blob/master/grafana/provisioning/datasources/all.yml + +apiVersion: 1 + +datasources: + - access: 'proxy' # make grafana perform the requests + editable: true # whether it should be editable + isDefault: true # whether this should be the default DS + name: 'prometheus' # name of the datasource + orgId: 1 # id of the organization to tie this datasource to + type: 'prometheus' # type of the data source + url: 'http://prometheus:9090' # url of the prom instance + version: 1 # well, versioning + jsonData: + timeInterval: '5s' diff --git a/etc/prometheus/prometheus.yml b/etc/prometheus/prometheus.yml new file mode 100644 index 00000000..cb1597cf --- /dev/null +++ b/etc/prometheus/prometheus.yml @@ -0,0 +1,29 @@ +global: + scrape_interval: 5s + evaluation_interval: 5s + +scrape_configs: + - job_name: 'rails' + scheme: http + metrics_path: '/metrics' + static_configs: + - targets: + - 'rails:5100' + - job_name: 'anycable-rpc' + scheme: http + metrics_path: '/metrics' + static_configs: + - targets: + - 'anycable:5100' + - job_name: 'anycable-go' + scheme: http + metrics_path: '/metrics' + static_configs: + - targets: + - 'ws:5100' + - job_name: 'cadvisor' + scheme: http + metrics_path: '/metrics' + static_configs: + - targets: + - cadvisor:8080 From dcfebfb53fbc9a1465772dea33ae60d333f02b92 Mon Sep 17 00:00:00 2001 From: Vladimir Dementyev Date: Wed, 18 Aug 2021 00:01:08 +0300 Subject: [PATCH 2/3] Add k6 example script (cherry picked from commit d42383356ee6922d6f8e0c7cca4dfc48a1eb4ef3) --- .dockerdev/compose.yml | 10 ++-- .gitignore | 1 + config/environments/development.rb | 6 +++ config/puma.rb | 2 +- etc/k6/README.md | 29 +++++++++++ etc/k6/chat.js | 84 ++++++++++++++++++++++++++++++ 6 files changed, 127 insertions(+), 5 deletions(-) create mode 100644 etc/k6/README.md create mode 100644 etc/k6/chat.js diff --git a/.dockerdev/compose.yml b/.dockerdev/compose.yml index 02cd8427..61126a31 100644 --- a/.dockerdev/compose.yml +++ b/.dockerdev/compose.yml @@ -33,10 +33,12 @@ x-backend: &backend DATABASE_URL: postgres://postgres:postgres@postgres:5432 BOOTSNAP_CACHE_DIR: /usr/local/bundle/_bootsnap WEBPACKER_DEV_SERVER_HOST: webpacker - WEB_CONCURRENCY: 1 - HISTFILE: /usr/local/hist/.bash_history - PSQL_HISTFILE: /usr/local/hist/.psql_history - IRB_HISTFILE: /usr/local/hist/.irb_history + WEB_CONCURRENCY: ${WEB_CONCURRENCY:-1} + HISTFILE: /app/log/.bash_history + PSQL_HISTFILE: /app/log/.psql_history + EDITOR: vi + LOG: ${LOG:-0} + ANYCABLE_DEBUG: ${ANYCABLE_DEBUG:-1} ACTION_CABLE_ADAPTER: ${ACTION_CABLE_ADAPTER:-anycable} ANYCABLE_RPC_HOST: 0.0.0.0:50051 ANYCABLE_BROADCAST_ADAPTER: redis diff --git a/.gitignore b/.gitignore index 5c514e8d..ffde378b 100644 --- a/.gitignore +++ b/.gitignore @@ -34,3 +34,4 @@ yarn-debug.log* /app/assets/builds/* !/app/assets/builds/.keep +etc/k6/k6 diff --git a/config/environments/development.rb b/config/environments/development.rb index fb9d9df2..d94b3aaf 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -45,4 +45,10 @@ # Raises error for missing translations. # config.action_view.raise_on_missing_translations = true + + # Use an evented file watcher to asynchronously detect changes in source code, + # routes, locales, etc. This feature depends on the listen gem. + config.file_watcher = ActiveSupport::EventedFileUpdateChecker + + config.log_level = :warn if ENV["ANYCABLE_DEBUG"] == "0" end diff --git a/config/puma.rb b/config/puma.rb index f22839b7..668bc016 100644 --- a/config/puma.rb +++ b/config/puma.rb @@ -29,7 +29,7 @@ # Workers do not work on JRuby or Windows (both of which do not support # processes). # -# workers ENV.fetch("WEB_CONCURRENCY") { 2 } +workers ENV.fetch("WEB_CONCURRENCY", 2) # Use the `preload_app!` method when specifying a `workers` number. # This directive tells Puma to first boot the application and load code diff --git a/etc/k6/README.md b/etc/k6/README.md new file mode 100644 index 00000000..212b27dc --- /dev/null +++ b/etc/k6/README.md @@ -0,0 +1,29 @@ +# Benchmarking with k6 + +This folder contains benchmark/stress test scenarios to be used with [k6][]. + +We rely on the [xk6-cable][] extension, so you must first build a custom k6 executable (following the instructions described in the xk6-cable repo) and keep it in the `etc/k6/` folder: + +```sh +/etc/k6> xk6 build v0.32.0 --with github.com/anycable/xk6-cable +``` + +## Scenarios + +All scenarios support the following env vars: + +- `CABLE_URL`: WebSocket connection url (defaults to `ws://localhost:8080/cable`). +- `WORKSPACE`: Workspace ID. + +### `chat.js` + +Connect to a chat room, send N (env `NUM` or 5) messages and expect to receive own messages back: + +```sh +./k6 run --vus 20 --duration 10s chat.js +``` + +This scenario uses ramping VUs executor, you can control the max number of VUs and the total duration via the `MAX` and `TIME` env vars (default to 20 and 120 respectively). + +[k6]: https://k6.io +[xk6-cable]: https://github.com/anycable/xk6-cable diff --git a/etc/k6/chat.js b/etc/k6/chat.js new file mode 100644 index 00000000..90d950ee --- /dev/null +++ b/etc/k6/chat.js @@ -0,0 +1,84 @@ +import { check, sleep, fail } from "k6"; +import cable from "k6/x/cable"; +import { randomIntBetween } from "https://jslib.k6.io/k6-utils/1.1.0/index.js"; + +import { Trend } from "k6/metrics"; + +let rttTrend = new Trend("rtt", true); + +let userId = `100${__VU}`; +let userName = `Kay${userId}`; + +const URL = __ENV.CABLE_URL || "ws://localhost:8080/cable"; +const WORKSPACE = __ENV.WORKSPACE || "demo"; + +// The number of messages each VU sends during an iteration +const MESSAGES_NUM = parseInt(__ENV.NUM || "5"); +// Max VUs during the peak +const MAX = parseInt(__ENV.MAX || "20"); +// Total test duration +const TIME = parseInt(__ENV.TIME || "120"); + +export let options = { + thresholds: { + checks: ["rate>0.9"], + }, + scenarios: { + chat: { + executor: "ramping-vus", + startVUs: (MAX / 10 || 1) | 0, + stages: [ + { duration: `${TIME / 3}s`, target: (MAX / 4) | 0 }, + { duration: `${(7 * TIME) / 12}s`, target: MAX }, + { duration: `${TIME / 12}s`, target: 0 }, + ], + }, + }, +}; + +export default function () { + let client = cable.connect(URL, { + cookies: `uid=${userName}/${userId}`, + receiveTimeoutMS: 30000, + }); + + if ( + !check(client, { + "successful connection": (obj) => obj, + }) + ) { + fail("connection failed"); + } + + let channel = client.subscribe("ChatChannel", { id: WORKSPACE }); + + if ( + !check(channel, { + "successful subscription": (obj) => obj, + }) + ) { + fail("failed to subscribe"); + } + + for (let i = 0; i < MESSAGES_NUM; i++) { + let startMessage = Date.now(); + channel.perform("speak", { message: `hello from ${userName}` }); + + let message = channel.receive({ author_id: userId }); + + if ( + !check(message, { + "received its own message": (obj) => obj, + }) + ) { + fail("expected message hasn't been received"); + } + + let endMessage = Date.now(); + rttTrend.add(endMessage - startMessage); + + sleep(randomIntBetween(5, 10) / 10); + } + + client.disconnect(); +} From 2e31e9a6b7f2a1a5b9fc9033ebcb53537c0dc8cf Mon Sep 17 00:00:00 2001 From: Vladimir Dementyev Date: Mon, 29 Aug 2022 17:46:04 -0400 Subject: [PATCH 3/3] fixup! Instrumentation and monitoring --- .dockerdev/compose.yml | 2 -- Gemfile.lock | 18 +++++++----------- config/environments/development.rb | 4 ---- 3 files changed, 7 insertions(+), 17 deletions(-) diff --git a/.dockerdev/compose.yml b/.dockerdev/compose.yml index 61126a31..ec98f1a0 100644 --- a/.dockerdev/compose.yml +++ b/.dockerdev/compose.yml @@ -44,8 +44,6 @@ x-backend: &backend ANYCABLE_BROADCAST_ADAPTER: redis PROMETHEUS_EXPORTER_PORT: 5100 CHROME_URL: http://chrome:3333 - EDITOR: vi - LOG: ${LOG:-0} depends_on: &backend_depends_on postgres: condition: service_healthy diff --git a/Gemfile.lock b/Gemfile.lock index 25c42b25..fdca2930 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -107,7 +107,6 @@ GEM diff-lcs (1.5.0) digest (3.1.0) dry-initializer (3.0.4) - equalizer (0.0.11) erubi (1.10.0) ferrum (0.11) addressable (~> 2.5) @@ -128,13 +127,9 @@ GEM io-wait (0.2.1) irb (1.4.1) reline (>= 0.3.0) - ice_nine (0.11.2) jsbundling-rails (1.0.2) railties (>= 6.0.0) - json (2.5.1) - listen (3.4.1) - rb-fsevent (~> 0.10, >= 0.10.3) - rb-inotify (~> 0.9, >= 0.9.10) + json (2.6.2) loofah (2.9.0) crass (~> 1.0.2) nokogiri (>= 1.5.9) @@ -163,12 +158,15 @@ GEM net-protocol timeout nio4r (2.5.8) + nokogiri (1.13.3-aarch64-linux) + racc (~> 1.4) + nokogiri (1.13.3-arm64-darwin) + racc (~> 1.4) nokogiri (1.13.3-x86_64-linux) racc (~> 1.4) parser (3.1.1.0) ast (~> 2.4.1) pg (1.3.4) - procto (0.0.3) prometheus-client (2.1.0) propshaft (0.6.4) actionpack (>= 7.0.0) @@ -249,14 +247,12 @@ GEM unparser (0.6.4) diff-lcs (~> 1.3) parser (>= 3.1.0) - websocket-driver (0.7.5) webrick (1.7.0) - websocket-driver (0.7.3) + websocket-driver (0.7.5) websocket-extensions (>= 0.1.0) websocket-extensions (0.1.5) xpath (3.2.0) nokogiri (~> 1.8) - zeitwerk (2.5.4) yabeda (0.10.0) anyway_config (>= 1.3, < 3) concurrent-ruby @@ -275,7 +271,7 @@ GEM yabeda-rails (0.7.2) rails yabeda (~> 0.8) - zeitwerk (2.4.2) + zeitwerk (2.5.4) PLATFORMS aarch64-linux diff --git a/config/environments/development.rb b/config/environments/development.rb index d94b3aaf..7fba211f 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -46,9 +46,5 @@ # Raises error for missing translations. # config.action_view.raise_on_missing_translations = true - # Use an evented file watcher to asynchronously detect changes in source code, - # routes, locales, etc. This feature depends on the listen gem. - config.file_watcher = ActiveSupport::EventedFileUpdateChecker - config.log_level = :warn if ENV["ANYCABLE_DEBUG"] == "0" end