The Ultra Performant API Gateway
Abdullah Fathi
Introduction
In today’s digital landscape, managing microservices highlights the need for efficient API Gateways. They facilitate communication between client applications and backend services, enhancing performance, security, and microservice orchestration.
What is ?
-
Extensible, declarative, high performance open-source API Gateway
-
Written in Go
-
Stateless Architecture
-
Needs no programming as it offers a declarative way to create the endpoints
-
KrakenD core engine has joined The Linux Foundation on 2021 with a codename Lura Project
Effortlessly adopt microservices
1.
Move from dealing with every particular microservice to talking to a single entry point that handles the interaction with all your microservices
2.
Secure by Default
Authorization, protection against scrapping, security best practices and abuse prevention implementation out of the box
3.
Scale Out Without Single Points of Failure
Stateless design provides true linear scalability. KrakenD does not require node coordinator or data centralization
KrakenD is more than a typical proxy that forwards clients to backend services, but a powerful engine that can transform, aggregate or remove data from your own or third party services
Performance
KrakenD supports more than 70K req/s on commodity software. They're the fastest and more performant solution in the market.
Low Operational Cost
Higher performance results in lower requirements in terms of resources, allowing you to save costs in your infrastructure
Stateless Design
The stateless design is a competitive advantage over other solutions. It provides a true linear scalability and no need of node coordination
True Linear Scalability
Every KrakenD node can operate independently without any coordination or centralized persistence of configuration needed
What makes KrakenD different from others?
Simple to Operate
and Run
Support from Creators
Rich Open-Source
Ecosystem
No Lock-In
Only need KrakenD binary and a JSON config file to get KrakenD up & running
Rather than "trained" or "sales engineers. you'll receive support and advice from the engineers that coded the software
Able to integrate with standard and proved open-source solutions for every specific task
Integrate with existing solutions in the technical stack, and easily replace them when needed. Compatible to both Community or Enterprise Edition
What makes KrakenD different from others?
What else?
- A Feature-Rich Gateway: Supports various protocols and APIs with access controls, data transformation, integrations, and caching.
- Customizable to Your Needs: Add features via plugin system, tailoring KrakenD to your requirements.
- Innovative Content Aggregation: A pioneer in the Backend For Frontend pattern, KrakenD aggregates multiple APIs in one call, handling different encodings.
- Uncompromised Security: Compliant with OWASP best practices, KrakenD offers top security without storing data, ensuring regulatory compliance.
- Transparent, Predictable Pricing: The pricing model includes unlimited requests and services, with a free open-source version and an Enterprise Edition for premium features and support.
KrakenD Features
1) Installation
Running KrakenD (Dev)
Docker
docker run -p "8080:8080" -v $PWD:/etc/krakend/ devopsfaith/krakend:2.7.0 run -c krakend.json
# Healthcheck
http://localhost:8080/__health
{
"$schema": "https://www.krakend.io/schema/krakend.json",
"version": 3
}
krakend.json
CLI
Running KrakenD (Dev)
Docker Compose
version: "3"
services:
krakend:
image: devopsfaith/krakend:watch
volumes:
- ".:/etc/krakend"
ports:
- "8080:8080"
command: [ "run", "-dc", "krakend.json" ]
{
"$schema": "https://www.krakend.io/schema/krakend.json",
"version": 3
}
krakend.json
docker-compose.yaml
Running KrakenD (Prod)
Docker Artifact
FROM devopsfaith/krakend:2.7 as builder
ARG ENV=prod
COPY krakend.tmpl .
COPY config .
## Save temporary file to /tmp to avoid permission errors
RUN FC_ENABLE=1 \
FC_OUT=/tmp/krakend.json \
FC_PARTIALS="/etc/krakend/partials" \
FC_SETTINGS="/etc/krakend/settings/$ENV" \
FC_TEMPLATES="/etc/krakend/templates" \
krakend check -d -t -c krakend.tmpl --lint
FROM devopsfaith/krakend:2.7
# Keep operating system updated with security fixes between releases
RUN apk upgrade --no-cache --no-interactive
COPY --from=builder --chown=krakend:nogroup /tmp/krakend.json .
# Uncomment with Enterprise image:
# COPY LICENSE /etc/krakend/LICENSE
Dockerfile
docker build --build-arg ENV=prod -t mykrakend .
CLI
Running KrakenD (Prod)
Kubernetes
apiVersion: apps/v1
kind: Deployment
metadata:
name: krakend-deployment
spec:
selector:
matchLabels:
app: krakend
replicas: 2
template:
metadata:
labels:
app: krakend
spec:
containers:
- name: krakend
image: YOUR-KRAKEND-IMAGE:1.0.0
ports:
- containerPort: 8080
imagePullPolicy: Never
command: [ "/usr/bin/krakend" ]
args: [ "run", "-d", "-c", "/etc/krakend/krakend.json", "-p", "8080" ]
securityContext:
allowPrivilegeEscalation: false
runAsNonRoot: true
runAsUser: 1000
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
add:
- NET_BIND_SERVICE
env:
- name: KRAKEND_PORT
value: "8080"
deployment.yaml
Running KrakenD (Prod)
Kubernetes
apiVersion: v1
kind: Service
metadata:
name: krakend-service
spec:
type: NodePort
ports:
- name: http
port: 8000
targetPort: 8080
protocol: TCP
selector:
app: krakend
service.yaml
2) Configuration
Config File Structure
Flexible Configuration (Intro)
Benefit of Flexible Configuration
Flexible Configuration
Flexible Configuration
Flexible Configuration (File Structure)
.
├── krakend.tmpl
└── config
├── partials
│ └── file.txt
├── templates
│ ├── telemetry.tmpl
│ └── endpoints.tmpl
└── settings
├── prod
| └── urls.json
└── dev
└── urls.json
Template Introduction
- Delimited by {{ }}
- Multiple functions and options
{{/*
This
is
multiline
comment
*/}}
I had {{ .num_coffees}} coffees today.
{{ if gt .num_coffees 3 }}
This was too much
{{end}}
{{ if and (gt .num_coffees 3) (lt .num_coffees 10) }}
This was too much
{{end}}
Template Overview
KrakenD will set variable for your template automatically depending on where the template is used
Debug and print context as JSON structure using toJson
Create variable (using $)
Template Overview
Conditionals
Loops Array
Template Overview
-
Enable it
-
Define the location of input files
Working with Flexible Configuration
FC_ENABLE: Switch on the flexible configuration
FC_OUT: Writed the result
FC_TEMPLATES: Directory with the sub templates you will call from the master template
FC_SETTINGS: Directory where you store environment configuration and other settings
FC_PARTIALS: Directory where you store snippets of text that you can inject into templates without being evaluated
Flexible Configuration (Env Var)
{
"$schema":"https://www.krakend.io/schema/krakend.json",
"version": 3,
"name": "A simple config"
}
Run Flexible Configuration (docker)
docker run --rm -it -v "$PWD:/etc/krakend" -p "8080:8080" -e "FC_ENABLE=1" -e "FC_OUT=out.json" devopsfaith/krakend:watch run -c krakend.tmpl
# Give a write permission to output file
sudo chown $USER out.json
krakend.json
cli
{
"$schema":"https://www.krakend.io/schema/krakend.json",
"version": 3,
"name": "A simple config"
}
Run Flexible Configuration (docker compose)
version: "3"
services:
krakend:
image: devopsfaith/krakend
volumes:
- .:/etc/krakend
ports:
- "8080:8080"
environment:
- FC_ENABLE=1
- FC_SETTINGS=config/settings/prod
- FC_PARTIALS=config/partials
- FC_TEMPLATES=config/templates
- FC_OUT=out.json
- SERVICE_NAME=KrakenD API Gateway
command: [ "run", "-dc", "krakend.tmpl", "" ]
krakend.json
docker-compose.yaml
3) Routing and Forwarding
Declare endpoints and backends
{
"$schema":"https://www.krakend.io/schema/v3.json",
"version": 3,
"host": ["http://api.github.com"],
"endpoints": [
{
"endpoint": "/users/{id}",
"backend": [
{
"url_pattern": "/users/{id}",
"group": "fathi"
},
{
"url_pattern": "/users/hafizan",
"group": "hafizan"
}
]
}
]
}
Proxy-like features (no-op)
KrakenD is NOT Reverse Proxy
KrakenD is not designed as a reverse proxy but as an API Gateway that acts as a decoupling layer between the client and microservices
Proxy-like features (no-op)
No-op Encoding
Allows response from the backend to be returned directly to the client without any modification or parsing by the gateway. It behaves like a regular proxy, preserving the original status codes and headers
Proxy-like features (no-op)
No-op Limitation
- Limited to single backend per endpoint
- Does not support merging responses from multiple backends
- Couples the client directly to the backend and max expose more information than necessary
Usage Scenarios
Useful in cases where direct interaction between the client and backend is required, such as setting cookies or performing write operations like file uploads
Proxy-like features (no-op)
{
"$schema": "https://www.krakend.io/schema/krakend.json",
"version": 3,
"host": [ "https://api.github.com" ],
"endpoints":[
{
"endpoint": "/default",
"@comment": "The body is parsed by KrakenD and headers are the ones from KrakenD",
"backend": [{
"url_pattern": "/status"
}]
},
{
"endpoint": "/no-op",
"output_encoding": "no-op",
"@comment": "Content and headers are the ones provided by the backend directly",
"backend": [{
"encoding": "no-op",
"url_pattern": "/status"
}]
}
]
}
Sequential Proxy (chain reqs.)
Sequential Proxy (chain reqs.)
{
"$schema": "https://www.krakend.io/schema/krakend.json",
"version": 3,
"port": 8080,
"host": ["http://backend:8080"],
"endpoints": [{
"endpoint": "/hotel/{id}",
"extra_config": {
"proxy": {
"sequential": true
}
},
"backend": [{
"@comment": "The first call fields have its response under resp0_xxx",
"url_pattern": "/hotels/{id}.json"
},
{
"@comment": "Second call fields have its response under resp1_xxx, we could add more chained backends",
"url_pattern": "/calendar/{resp0_calendar_id}.json"
}
]
},
{
"endpoint": "/hotel/failing/{id}",
"extra_config": {
"proxy": {
"sequential": true
}
},
"backend": [{
"@comment": "The first call fields have its response under resp0_xxx",
"url_pattern": "/hotels/{id}.json"
},
{
"@comment": "The requested attribute does not exist, so we can't fetch the data",
"url_pattern": "/calendar/{resp0_unexisting_field}.json"
}
]
}
]
}
Sequential Proxy
4) Request and Response Manipulation
1) Encoding
Encoding is referring to data format you will find in your upstream responses and the format you want to deliver to API consumers
1) Encoding
{
"$schema": "https://www.krakend.io/schema/krakend.json",
"version": 3,
"host": [
"http://107.155.65.148:5000"
],
"endpoints": [
{
"endpoint": "/xml",
"output_encoding": "xml",
"@comment": "Backend is json but client receives XML",
"backend": [
{
"url_pattern": "/index.php",
"encoding": "json"
}
]
},
{
"endpoint": "/collection",
"output_encoding": "json",
"@comment": "The backend is a JSON collection [], not an object {}, and by default encapsulated in a 'collection' object",
"backend": [
{
"is_collection": true,
"url_pattern": "/index.php?collection=true",
"encoding": "json"
}
]
},
{
"endpoint": "/safe-collection",
"output_encoding": "json",
"@comment": "KrakenD looks if the 'is_collection' is needed or not.",
"backend": [
{
"url_pattern": "/index.php?collection=true",
"encoding": "safejson",
"mapping": {
"collection": "SOMETHING_ELSE"
}
}
]
},
{
"endpoint": "/collection-as-it-was",
"output_encoding": "json-collection",
"@comment": "The backend is a JSON collection [], not an object {}, and is returned as such",
"backend": [
{
"is_collection": true,
"url_pattern": "/index.php?collection=true",
"encoding": "json"
}
]
},
{
"endpoint": "/negotiate",
"output_encoding": "negotiate",
"backend": [
{
"url_pattern": "/index.php",
"encoding": "json"
}
]
},
{
"endpoint": "/string",
"output_encoding": "string",
"backend": [
{
"encoding": "string",
"host": [
"https://www.google.com"
],
"url_pattern": "/"
}
]
},
{
"endpoint": "/string-in-object",
"output_encoding": "json",
"backend": [
{
"encoding": "string",
"host": [
"https://www.google.com"
],
"url_pattern": "/"
}
]
}
]
}
2) Status Codes, Headers and Errors
The client get all the status code, the headers and the error body
KrakenD return a 500 status code, no body and none of the response header
2) Status Codes, Headers and Errors
KrakenD do this by default because client must completely decoupled from their underlying services. When API is protected by API Gateway, we should not return back an implementation detail. In the same way we wouldn't return an implementation detail to the client from the application.
2) Status Codes, Headers and Errors
Status codes returned before contacting backends
404
Requested endpoint does not exist
400
Bad Request. i.e: failed JSON schema validation of the body
401
Unauthorized: Invalid JWT Token
403
Forbidden access
429
Too many requests. Reach the rate limit for the endpoint
503
Service Unavailable. Reached global rate limit for the endpoint
2) Status Codes, Headers and Errors
Status codes returned to clients after reaching the backends
2) Status Codes, Headers and Errors
What happen with redirect status code such as 301 and 302?
2) Status Codes, Headers and Errors
Strategies
2) Status Codes, Headers and Errors
{
"version": 3,
"$schema": "https://www.krakend.io/schema/krakend.json",
"debug_endpoint": true,
"endpoints": [
{
"endpoint": "/ok",
"backend": [
{
"host": ["https://api.github.com"],
"url_pattern": "/status"
}
]
},
{
"endpoint": "/epic-fail",
"backend": [
{
"@comment": "Request to a URL that will produce a 404",
"host": ["http://google.com"],
"url_pattern": "/this-url-likely-does-not-exist"
}
]
},
{
"endpoint": "/mixed",
"backend": [
{
"host": ["https://api.github.com"],
"url_pattern": "/status"
},
{
"@comment": "Request to a URL that will produce a 404",
"host": ["http://google.com"],
"url_pattern": "/this-url-likely-does-not-exist"
}
]
}
]
}
2) Status Codes, Headers and Errors
Interpretation of error
{
"version": 3,
"$schema": "https://www.krakend.io/schema/krakend.json",
"@comment": "Preserve the status code of a single backend",
"extra_config": {
"router": {
"return_error_msg": true
}
},
"endpoints": [
{
"endpoint": "/interpretation-bad-status",
"backend": [
{
"@comment": "Request to a URL that will produce a 404, which is not a returnable status code",
"host": ["http://google.com"],
"url_pattern": "/this-url-likely-does-not-exist"
}
]
},
{
"endpoint": "/interpretation-bad-encoding",
"backend": [
{
"@comment": "Request a valid URL, but with the wrong encoding parsing",
"host": ["http://google.com"],
"url_pattern": "/"
}
]
}
]
}
Show the interpretation of the error but not the error of the backend
2) Status Codes, Headers and Errors
{
"version": 3,
"$schema": "https://www.krakend.io/schema/krakend.json",
"@comment": "Preserve the status code of a single backend",
"endpoints": [
{
"endpoint": "/details",
"backend": [
{
"extra_config": {
"backend/http": {
"return_error_details": "error_from_google"
}
},
"@comment": "Request to a URL that will produce a 404",
"host": ["http://google.com"],
"url_pattern": "/this-url-likely-does-not-exist"
}
]
}
]
}
Return the error in a key
Revealing error details to the client. Using return_error_details, all status codes returned to the client are 200. The client must parse the response for the presence of the error_backend_alias or any other key we have set to determine if there’s a problem
2) Status Codes, Headers and Errors
{
"version": 3,
"$schema": "https://www.krakend.io/schema/krakend.json",
"@comment": "Preserve the status code of a single backend",
"endpoints": [
{
"endpoint": "/preserve-404",
"backend": [
{
"extra_config": {
"backend/http": {
"return_error_code": true
}
},
"@comment": "Request to a URL that will produce a 404",
"host": ["http://google.com"],
"url_pattern": "/this-url-likely-does-not-exist"
}
]
}
]
}
Preserve the status code of a single backend
When we have one backend only and use an encoding different than no-op
3) Parameter Forwarding
Deny by default
Zero-trust security
KrakenD is an API Gateway with a zero-trust security policy, and when it comes to forward query strings, cookies, and headers, we need to define what is allowed.
Part of the zero-trust policy implies that KrakenD does not forward any unexpected query string, headers, or cookies
3) Parameter Forwarding
Fine tuned parameter forwarding
input_query_strings
Query strings reaching backends
input_headers
Headers reaching backends
case-sensitive
case-insensitive
3) Parameter Forwarding
The received headers are always normalized. The normalization consist of converting any header to its canonical MIME format
3) Parameter Forwarding
3) Parameter Forwarding
{
"$schema": "https://www.krakend.io/schema/krakend.json",
"version": 3,
"echo_endpoint": true,
"@comment": "All examples use as backend KrakenD itself",
"host": [ "http://localhost:8080" ],
"endpoints":[
{
"endpoint": "/default",
"@comment": "The backend does not receive any header, query string or cookie from the client",
"backend": [{
"url_pattern": "/__echo/"
}]
},
{
"endpoint": "/known-params",
"input_headers": ["Accept"],
"input_query_strings": ["q","a[]" ],
"@comment": "The backend receives a controlled set of parameters, but discards unknown sets",
"backend": [{
"url_pattern": "/__echo/"
}]
},
{
"endpoint": "/all",
"input_headers": ["*"],
"input_query_strings": ["*" ],
"@comment": "The backend receives all parameters from client. NOT RECOMMENDED.",
"backend": [{
"url_pattern": "/__echo/"
}]
},
{
"endpoint": "/mandatory/{id}",
"input_query_strings": ["optional" ],
"@comment": "The backend receives always the mandatory {id} and the optional one only when sent.",
"backend": [{
"url_pattern": "/__echo/?id={id}"
}]
}
]
}
4) Basic Manipulation
Automatically merges all responses from all backends in a final response
Aggregation
Wrap response of a backend inside a new object
Grouping
Remove hierarchy by extracting subpath
Targetting
Rename attribute in JSON response
Mapping
4) Basic Manipulation
Rename attribute in JSON response
Mapping
Filter response data in JSON response.
Filtering
Rename attribute in JSON response
Mapping
Allows us to extract, move, append and delete properties
Flatmap
4) Basic Manipulation
{
"$schema": "https://www.krakend.io/schema/krakend.json",
"version": 3,
"echo_endpoint": true,
"debug_endpoint": true,
"@comment": "All examples use as backend KrakenD itself",
"host": [
"http://107.155.65.148:5002"
],
"endpoints": [
{
"endpoint": "/aggregation",
"backend": [
{
"url_pattern": "/users/alice.json"
},
{
"url_pattern": "/users/bob.json"
}
]
},
{
"endpoint": "/group",
"backend": [
{
"url_pattern": "/users/alice.json",
"group": "alice"
},
{
"url_pattern": "/users/bob.json",
"group": "bob"
}
]
},
{
"endpoint": "/target",
"backend": [
{
"url_pattern": "/users/alice.json",
"target": "data.user"
}
]
},
{
"endpoint": "/mapping",
"backend": [
{
"url_pattern": "/users/bob.json",
"mapping": {
"data": "my_response",
"status": "result"
}
}
]
},
{
"endpoint": "/deny",
"backend": [
{
"url_pattern": "/users/bob.json",
"deny": [
"data"
]
}
]
},
{
"endpoint": "/allow",
"backend": [
{
"url_pattern": "/users/bob.json",
"allow": [
"data.user.name",
"data.user.city"
]
}
]
},
{
"endpoint": "/flatmap/object",
"backend": [
{
"url_pattern": "/users/alice.json",
"extra_config": {
"proxy": {
"flatmap_filter": [
{ "type": "move", "args": ["data.user","details"] },
{ "type": "move", "args": ["details.name","name"] },
{ "type": "del","args": ["status", "data"] }
]
}
}
}
]
},
{
"endpoint": "/flatmap/collection",
"backend": [
{
"url_pattern": "/numbers.json",
"extra_config": {
"proxy": {
"flatmap_filter": [
{
"type": "del",
"args": ["numerals.0"]
},
{
"type": "move",
"args": ["numerals.*.numeral", "numerals.*.number"]
},
{
"type": "move",
"args": ["numerals.*.english", "numerals.*.name"]
},
{
"type": "del",
"args": ["numerals.*.spanish"]
},
{
"type": "move",
"args": ["numerals", "numbers"]
}
]
}
}
}
]
}
]
}
5) Martian: Static request & response manipulation
Inject static content in the request & responses of a backend through a simple DSL definition in config file
5) Martian: Static request & response manipulation
We can inject data in requests and responses using the Martian component as long as it’s static data, hardcoded in the configuration. It does not allow us to place {variables} inside the modifiers
When to use Martian?
Use Martian whenever we need to alter the request or response based on criteria with static values.
- Set a new cookie during gateway processing
- Flag requests with query strings or headers when specific criteria is met
- Add, remove, or change specific headers
- Do basic authentication between KrakenD and the backend
- Add query strings before making the backend request (e.g., set an API key)
5) Martian: Static request & response manipulation
Change the state of a request or a response. For instance, you want to add a custom header or a query string in the request before sending it to a backend
Modifiers
Check for specific conditions and execute one modifier or another
Filters
Execute more than one modifier in single request or response
Groups
5) Martian: Static request & response manipulation
{
"$schema": "https://www.krakend.io/schema/krakend.json",
"version": 3,
"echo_endpoint": true,
"debug_endpoint": true,
"@comment": "All examples use as backend KrakenD itself",
"host": [
"http://localhost:8080"
],
"endpoints": [
{
"endpoint": "/header.Modifier",
"output_encoding": "no-op",
"backend": [
{
"host": ["http://localhost:8080"],
"url_pattern": "/__echo/header.Modifier",
"extra_config": {
"modifier/martian": {
"header.Modifier": {
"scope": ["request","response"],
"name": "User-Agent",
"value": "Late-Night-Commander v2.3"
}
}
}
}
]
},
{
"endpoint": "/body.Modifier",
"backend": [
{
"url_pattern": "/__debug/body.Modifier",
"extra_config": {
"modifier/martian": {
"body.Modifier": {
"scope": [
"request",
"response"
],
"@comment": "Send a {\"msg\":\"you rock!\"}",
"body": "eyJtc2ciOiJ5b3Ugcm9jayEifQ=="
}
}
}
}
]
},
{
"endpoint": "/header.RegexFilter",
"input_headers": [
"X-App-Version"
],
"backend": [
{
"url_pattern": "/__echo/header.RegexFilter",
"allow": ["req_uri"],
"extra_config": {
"modifier/martian": {
"header.RegexFilter": {
"scope": [
"request"
],
"header": "X-App-Version",
"regex": ".*-(alpha|beta|preview)$",
"modifier": {
"querystring.Modifier": {
"scope": [
"request"
],
"name": "testing",
"value": "1"
}
}
}
}
}
}
]
},
{
"endpoint": "/fifo.Group",
"output_encoding": "no-op",
"backend": [
{
"url_pattern": "/__echo/fifo.Group",
"extra_config": {
"modifier/martian": {
"fifo.Group": {
"scope": [
"request",
"response"
],
"aggregateErrors": true,
"modifiers": [
{
"body.Modifier": {
"scope": [
"request"
],
"body": "eyJtc2ciOiJ5b3Ugcm9jayEifQ=="
}
},
{
"header.Modifier": {
"scope": [
"request",
"response"
],
"name": "X-Additional-Header",
"value": "true"
}
}
]
}
}
}
}
]
}
]
}
6) Request Validation: JSON Schema
JSON Schema is a declarative language that allows us to validation JSON documents
6) Request Validation: JSON Schema
6) Request Validation: JSON Schema
{
"$schema": "https://www.krakend.io/schema/krakend.json",
"version": 3,
"port": 8080,
"host": ["http://127.0.0.1:8080"],
"echo_endpoint": true,
"extra_config": {
"router": {
"return_error_msg": true
}
},
"endpoints": [
{
"endpoint": "/user",
"method": "POST",
"extra_config": {
"validation/json-schema": {
"$schema": "http://json-schema.org/draft-07/schema",
"required": ["name", "age"],
"properties": {
"age": {
"type": "number"
},
"name": {
"type": "string"
},
"pronoun": {
"type": "string",
"enum": [
"she/her/hers",
"he/him/his",
"they/them/theirs",
"ze/hir/hirs",
"no pronoun",
"no preference",
"other"
]
}
}
}
},
"backend": [
{
"url_pattern": "/__echo/",
"allow": ["req_body"]
}
]
}
]
}
5) Security
JWT: Token Validation
Json Web Token
An industry standard to represent claims securely between two parties
JWT: Token Validation
JWT: Token Validation
JWT: Token Validation
JWT: Token Validation
6) Traffic Management
1) Caching
Caching allows us to store backend responses in memory to reduce the number of calls a user sends to the origin, reducing the network traffic and alleviating the pressure on your services.
1) Caching
{
"$schema": "https://www.krakend.io/schema/krakend.json",
"version": 3,
"host": [ "http://localhost:8080" ],
"debug_endpoint": true,
"cache_ttl": "1h",
"endpoints": [
{
"endpoint": "/one",
"cache_ttl": "1s",
"backend": [
{
"url_pattern": "/__debug/one"
}
]
},
{
"endpoint": "/two",
"backend": [
{
"host": ["https://api.github.com"],
"url_pattern": "/orgs/krakendio",
"extra_config": {
"qos/http-cache": {
"shared": true
},
"modifier/martian": {
"header.Modifier": {
"scope": ["response"],
"name": "Cache-Control",
"value": "max-age=3600, public",
"@comment": "Change the max-age policy before KrakenD checks it for caching."
}
}
}
}
]
}
]
}
2) Timeout
Controlling waiting times is crucial because KrakenD connect with many services
2) Timeout
The user will receive an HTTP status code 500 Internal Server Error when there is no content to return
What happens when the timeout is reached?
2) Timeout
{
"$schema": "https://www.krakend.io/schema/krakend.json",
"version": 3,
"port": 8080,
"timeout": "1s",
"host": [
"http://107.155.65.148:5003"
],
"endpoints": [
{
"endpoint": "/fast",
"backend": [
{
"url_pattern": "/speedy/"
}
]
},
{
"endpoint": "/semi-slow",
"timeout": "100ms",
"backend": [
{
"@comment": "This one takes over 100ms",
"url_pattern": "/delayed/"
},
{
"url_pattern": "/speedy/"
}
]
},
{
"endpoint": "/slow",
"timeout": "100ms",
"backend": [
{
"@comment": "This one takes over 100ms",
"url_pattern": "/delayed/"
}
]
}
]
}
3) Concurrent Calls
While we increase the load the backends, we will improve our client's response time and error rate
3) Concurrent Calls
3) Concurrent Calls
{
"$schema": "https://www.krakend.io/schema/krakend.json",
"version": 3,
"port": 8080,
"timeout": "1s",
"host": [
"http://107.155.65.148:5004"
],
"endpoints": [
{
"endpoint": "/error-10",
"concurrent_calls": 3,
"backend": [
{
"url_pattern": "/error-10"
}
]
},
{
"endpoint": "/error-50",
"concurrent_calls": 3,
"backend": [
{
"url_pattern": "/error-50"
}
]
},
{
"endpoint": "/flaky",
"concurrent_calls": 3,
"backend": [
{
"url_pattern": "/flaky"
}
]
}
]
}
4) Rate Limiting
Protect infrastructure from abusive actions, mitigate cascade failures, and control the overall API usage
4) Rate Limiting
Rate limiting is also compliment other traffic management technique such as Circuit-breaker, bot detector and service discovery
Purpose
4) Rate Limiting
- Service Rate Limiting**: set the maximum throughput users can do to KrakenD without distinguishing what endpoint the user is requesting
- Endpoint Rate Limiting: Set the maximum throughout users can do to specific endpoint.
- Proxy Rate Limiting: Set the maximum throughput between KrakenD and its backend
4) Rate Limiting
max_rate: Applies simultaneously to all clients using the endpoint, sharing a unique counter
client_max_rate: Sets a counter to each individual user
Both types can coexist and they complement each other, and store the counters in-memory
4) Rate Limiting
Bucket Token Algorithm
When do bucket is empty, they have to wait until the bucket is refilled again with the tokens.
The max_rate and client_max_rate define how many tokens it will refill every second
4) Rate Limiting
{
"version": 3,
"$schema": "https://www.krakend.io/schema/krakend.json",
"host": ["http://localhost:8080"],
"debug_endpoint": true,
"endpoints": [
{
"endpoint": "/r1",
"extra_config": {
"qos/ratelimit/router": {
"client_max_rate": 1,
"client_capacity": 5,
"strategy": "header",
"key": "Authorization",
"max_rate": 100
}
},
"backend": [
{
"url_pattern": "/__debug/ep",
"extra_config": {
"qos/ratelimit/proxy": {
"capacity": 3,
"max_rate": 3
}
}
}
]
}
]
}
5) Circuit Breaker
Error must be consecutive or the counter will be reset
Text
The Circuit Breaker is a straightforward state machine in the middle of the request and response that monitors all your backend failures. When they reach a configured threshold, the circuit breaker will prevent sending more traffic to a failing backend alleviating its pressure under challenging conditions
5) Circuit Breaker
Text
The backend wont be contacted again until it passes the timeout that we set
When the timeout window passes, it will allow one single request to pass to test it
5) Circuit Breaker
Text
If it fails, it will retry again after another timeout window
If the request passes, all traffic resumes normally
5) Circuit Breaker
Text
{
"$schema": "https://www.krakend.io/schema/krakend.json",
"version": 3,
"host": [ "http://107.155.65.148:5005" ],
"endpoints": [
{
"endpoint": "/cb",
"backend": [
{
"url_pattern": "/fail-fifty-percent",
"extra_config": {
"qos/circuit-breaker": {
"log_status_change": true,
"name": "the fifty percent trouble maker",
"interval": 60,
"max_errors": 2,
"timeout": 5
}
}
}
]
}
]
}
- interval: Time window where the errors count, in seconds
- max_errors: The CONSECUTIVE (not total) number of errors within the interval window to consider the backend unhealthy
- timeout: For how many seconds the circuit breaker will wait before testing again if the backend is healthy
5) Circuit Breaker
Text
7) Monitoring & Analytics
1) Health Endpoint
Is KrakenD up?
http://localhost:8080/__health
1) Health Endpoint
{
"version": 3,
"$schema": "https://www.krakend.io/schema/krakend.json",
"extra_config": {
"router": {
"logger_skip_paths": ["/health"],
"health_path": "/health",
"disable_health": false
}
}
}
2) Logging
{
"version": 3,
"$schema": "https://www.krakend.io/schema/krakend.json",
"extra_config": {
"telemetry/logging": {
"level": "DEBUG",
"stdout": true,
"syslog": false,
"prefix": "[KRAKEND]"
},
"router": {
"disable_access_log": false,
"logger_skip_paths":["/__health"]
}
}
}
3) Monitoring
Logging
Metrics
Tracing
Push log to log monitoring tools
Monitor request and response time, memory consumption and other vital information to understand the performance of the gateway
Gain insight into the flow of requests as they propagate through different services in a distributed system, from the user request to the gateway response
3) Monitoring
Logging
Metrics
Tracing
3) Monitoring
Logging
Metrics
Tracing
3) Monitoring
Logging
Metrics
Tracing
3) Monitoring
grafana:
image: grafana/grafana:9.1.2
ports:
- "4000:3000"
volumes:
- "./config/grafana/datasources/all.yml:/etc/grafana/provisioning/datasources/all.yml"
- "./config/grafana/dashboards/all.yml:/etc/grafana/provisioning/dashboards/all.yml"
- "./config/grafana/krakend:/var/lib/grafana/dashboards/krakend"
influxdb:
image: influxdb:1.8.10
environment:
- "INFLUXDB_DB=krakend"
- "INFLUXDB_USER=krakend-dev"
- "INFLUXDB_USER_PASSWORD=pas5w0rd"
- "INFLUXDB_ADMIN_USER=admin"
- "INFLUXDB_ADMIN_PASSWORD=supersecretpassword"
ports:
- "8086:8086"
jaeger:
image: jaegertracing/all-in-one:1
ports:
- "16686:16686"
- "14268:14268"
elasticsearch:
image: elasticsearch:8.4.1
environment:
- "discovery.type=single-node"
- "xpack.security.enabled=false"
- "xpack.security.transport.ssl.enabled=false"
- "xpack.security.http.ssl.enabled=false"
- "ES_JAVA_OPTS=-Xms1024m -Xmx1024m"
ports:
- "19200:9200"
- "9300:9300"
kibana:
image: kibana:8.4.1
ports:
- "5601:5601"
logstash:
image: logstash:8.4.1
ports:
- "12201:12201/udp"
- "5044:5044"
environment:
- "xpack.monitoring.elasticsearch.url=http://elasticsearch:9200"
volumes:
- ./config/logstash/logstash.conf:/usr/share/logstash/pipeline/logstash.conf
command: ["-f", "/usr/share/logstash/pipeline/logstash.conf"]
docker-compose.yaml
3) Monitoring
"sequential_start": true,
"extra_config": {
"telemetry/metrics": {
"collection_time": "30s",
"listen_address": ":8090"
},
"telemetry/influx": {
"address": "http://influxdb:8086",
"ttl": "25s",
"buffer_size": 100,
"username": "krakend-dev",
"password": "pas5w0rd"
},
"telemetry/logging": {
"level": "DEBUG",
"prefix": "[KRAKEND]",
"syslog": false,
"stdout": true
},
"telemetry/gelf": {
"address": "logstash:12201",
"enable_tcp": false
},
"telemetry/opencensus": {
"sample_rate": 100,
"reporting_period": 1,
"enabled_layers": {
"backend": true,
"router": true
},
"exporters": {
"jaeger": {
"endpoint": "http://jaeger:14268/api/traces",
"service_name": "krakend"
}
}
},
"security/cors": {
"allow_origins": ["*"],
"allow_methods": ["POST", "GET"],
"allow_headers": ["Origin", "Authorization", "Content-Type"],
"expose_headers": ["Content-Length"],
"max_age": "12h"
}
}
krakend.json
3) Monitoring
Your feedback matters
There are no secrets to success. It is the result of preparation, hard work, and learning from failure. - Colin Powell
THANK YOU
KrakenD Training
By Abdullah Fathi
KrakenD Training
- 82