Jun Ouyang

By on November 14, 2022

How to Use Prometheus to Monitor Kong Gateway

Observability is a critical part of Kong’s API Gateway. In this post, we’ll describe two options to monitor Kong Gateway using Prometheus.

Prometheus is an open source system monitor toolkit built at SoundCloud that is now widely adopted. StatsD was originally a simple daemon developed by Etsy to aggregate and summarize application metrics. Prometheus provides a StatsD exporter to collect metrics that are sent in StatsD format.

Kong Gateway supports both of the above for integrating with Prometheus. This enables Prometheus to pull metrics directly from the gateway or using a StatsD exporter in between to offload some work from the gateway.

Kong Gateway is built on top of OpenResty/Nginx, which is a multi-process single-threaded architecture. To collect and aggregate metrics from different processes, we implement the Prometheus plugin with shared memory.

Nginx handles requests in a non-blocking way and is normally very efficient. However, every read and write operation to the shared memory requires a mutex lock to lock the critical section and will block all worker processes from processing requests. When the plugin is used to monitor metrics with high cardinality, it can affect Kong Gateway performance significantly, especially increasing the long tail latencies. We recommend using the StatsD plugin as an alternative for such use cases.

We’ll explain how to use these two plugins in the following sections.

Blog: How to use Prometheus monitor Kong Gateway diagram

Prometheus

In a previous version of Kong Gateway, we found some performance issues with the Prometheus plugin. For example, in the production environment of one of our enterprise customers, they found that the request from Prometheus to pull metrics caused sporadic spikes in latencies for other requests — sometimes as much as three seconds.

As the investigation progressed, we found that the Prometheus plugin collects metrics with some expensive function calls because it stores many high cardinality metrics in Nginx’s shared memory. Therefore when the Prometheus service performed its periodic pull for the metrics, it triggered high overhead in Nginx and affected the real request latency. (See the issues on GitHub to get more information).

So unlike the old release version, in Kong Gateway 3.0 the Prometheus plugin doesn’t export status codes, latencies, bandwidth, and upstream health check metrics by default to avoid the costly overhead of collecting metrics.

Because these metrics will need to be added up or reset during the life of each connection — and these metrics have some different labels — they take up a lot of memory space, which needs to be traversed when Prometheus polls for metrics leading to higher latencies. They can still be turned on manually by setting config status_code_metrics, lantency_metrics, bandwidth_metrics, and upstream_health_metrics respectively. Enabling those metrics will impact the performance if you have a lot of Kong entities, therefore we recommend using the StatsD plugin with the push model for those cases.

1. Bootstrap Kong config

# create upstream
curl -X POST http://127.0.0.1:8001/upstreams \
  --data name=example-upstream

# add target
curl -X POST http://127.0.0.1:8001/upstreams/example-upstream/targets \
  --data target='mockbin.org:80'

curl -X POST http://127.0.0.1:8001/upstreams/example-upstream/targets \
  --data target='httpbin.org:80'

# add service 
curl -i -X POST \
  --url http://localhost:8001/services/ \
  --data 'name=example-service' \
  --data 'host=example-upstream'

# add route
curl -i -X POST \
  --url http://localhost:8001/services/example-service/routes \
  --data 'name=example-route' \
  --data 'hosts[]=example.com'

# request api
curl -i -X GET \
  --url http://localhost:8000/ \
  --header 'Host: example.com'

2. Enable Prometheus plugin

# enable prometheus plugin (or you can use global plugin)
curl -X POST http://localhost:8001/services/example-service/plugins \
    --data "name=prometheus"

3. Config your Prometheus config

# add this line to your prometheus.yaml
- job_name: 'kong'
static_configs:
- targets: ['<kong-node-ip>:8001']

 4. Import dashboard

Import Kong statsd exporter dashboard to your grafana.

StatsD

In Kong Gateway 3.0, we moved all StatsD Advanced functions to StatsD plugin, so community users can use StatsD plugin to achieve more complex and functional things that are previously only available to Enterprise offerings. When using StatsD plugin to push metrics, Kong Gateway doesn’t need to store the content of the metrics in memory, and therefore this plugin has minimal impact on the proxy path. The only overhead is using OpenResty cosocket to asynchronously send data over the network,. However a middleware service (StatsD Exporter) needs to be deployed to collect and aggregate metrics sent by Kong.

1. Start statsd_exporter

While it is common to run centralized StatsD servers, the exporter works best as a sidecar. This allows you to scale the StatsD Exporter horizontally as you add more gateways where a single instance can become a bottleneck.

Here is an example of a mapping yaml file for statsd_exporter:

mappings:
# by Service
- match: kong.service.*.request.count
name: "kong_statsd_requests_proxy"
labels:
service: $1
job: "kong_metrics"


- match: kong.service.*.kong_latency
name: "kong_statsd_latency_ms"
timer_type: histogram
labels:
service: $1
job: "kong_metrics"


- match: kong.service.*.upstream_latency
name: "kong_statsd_upstream_latency_ms"
timer_type: histogram
labels:
service: $1
job: "kong_metrics"


- match: kong.service.*.latency
name: "kong_statsd_request_latency_ms"
timer_type: histogram
labels:
service: $2
job: "kong_metrics"


- match: kong.service.*.user.*.request.count
name: "kong_statsd_request_count_per_consumer"
labels:
service: $1
consumer: $2
job: "kong_metrics"

- match: kong.service.*.status.*
name: "kong_statsd_status_count"
labels:
service: $1
code: $2
job: "kong_metrics"

- match: kong.service.*.user.*.status.*
name: "kong_statsd_status_per_consumer"
labels:
service: $1
consumer: $2
code: $3
job: "kong_metrics"

- match: kong.service.*.workspace.*.status.*
name: "kong_statsd_status_per_workspace"
labels:
service: $1
workspace: $2
code: $3
job: "kong_metrics"

- match: kong.service.*.route.*.user.*.status.*
name: "kong_statsd_status_per_route_per_consumer"
labels:
service: $1
route: $2
consumer: $3
code: $4
job: "kong_metrics"

- match: kong.node.*.shdict.*.free_space
name: "kong_statsd_memory_lua_shared_dict_free_bytes"
labels:
kong_node: "$1"
shared_dict: "$2"
job: "kong_metrics"

- match: kong.node.*.shdict.*.capacity
name: "kong_statsd_memory_lua_shared_dict_total_bytes"
labels:
kong_node: "$1"
shared_dict: "$2"
job: "kong_metrics"


- match: kong.service.*.cache_datastore_hits_total
name: "kong_statsd_cache_datastore_hits_total"
labels:
kong_node: "$1"
service: "$2"
job: "kong_metrics"

- match: kong.node.*.service.*.cache_datastore_misses_total
name: "kong_statsd_cache_datastore_misses_total"
labels:
kong_node: "$1"
service: "$2"
job: "kong_metrics"

Using StatsD Plugin with the above provides slightly different metrics compared with Prometheus plugin.

Prometheus plugin metrics chart

Then start your statsd_exporter and config your Prometheus to collect metrics.

./statsd_exporter --statsd.mapping-config=./config.yaml

 

2. Bootstrap Kong config

Bootstrap kong gateway config

# create upstream
curl -X POST http://127.0.0.1:8001/upstreams \
  --data name='example-upstream'

# add target
curl -X POST http://127.0.0.1:8001/upstreams/example-upstream/targets \
  --data target='mockbin.org:80'

curl -X POST http://127.0.0.1:8001/upstreams/example-upstream/targets \
  --data target='httpbin.org:80'

# add service 
curl -i -X POST \
  --url http://localhost:8001/services/ \
  --data 'name=example-service' \
  --data 'host=example-upstream'


# add route
curl -i -X POST \
  --url http://localhost:8001/services/example-service/routes \
  --data 'name=example-route' \
  --data 'hosts[]=example.com'


# request api
curl -i -X GET \
  --url http://localhost:8000/ \
  --header 'Host: example.com'

3. Config statsd plugin

# enable statsd plugin (or you can use global plugin)

curl -X POST http://localhost:8001/services/example-service/plugins \

    --data "name=statsd"  \

    --data "config.host=<statsd_exporter_server_ip>" \

    --data "config.port=<statsd_exporter_server_port>"

4. Import dashboard

Import Kong statsd exporter dashboard to your grafana.

Share Post

Tags: