title | subtitle | description |
---|---|---|
Distributed Caching for the GraphOS Router |
Configure Redis-backed caching for query plans and APQ |
Distributed caching for GraphOS Router with GraphOS Enterprise. Configure a Redis-backed cache for query plans and automatic persisted queries (APQ). |
<PlanRequired plans={["Free", "Developer", "Standard", "Enterprise"]}>
Rate limits apply on the Free plan. Performance pricing applies on Developer and Standard plans. Developer and Standard plans require Router v2.6.0 or later.
If you have multiple GraphOS Router instances, those instances can share a Redis-backed cache for their query plans and automatic persisted queries (APQ). This means that if any of your router instances caches a particular value, all of your instances can look up that value to significantly improve responsiveness. For more details on query plans and APQ, see the article on in-memory caching.
To use this feature:
- You must have a Redis cluster (or single instance) that your router instances can communicate with.
- You must have a GraphOS Enterprise plan and connect your router to GraphOS.
Whenever a router instance requires a query plan or APQ query string to resolve a client operation:
- The router instance checks its own in-memory cache for the required value and uses it if found.
- If not found, the router instance then checks the distributed Redis cache for the required value and uses it if found. It also then replicates the found value in its own in-memory cache.
- If not found, the router instance generates the required query plan or requests the full operation string from the client for APQ.
- The router instance stores the obtained value in both the distributed cache and its in-memory cache.
The distributed caching configuration must contain one or more URLs using different schemes depending on the expected deployment:
redis
- TCP connected to a centralized server.rediss
- TLS connected to a centralized server.redis-cluster
- TCP connected to a cluster.rediss-cluster
- TLS connected to a cluster.redis-sentinel
- TCP connected to a centralized server behind a sentinel layer.rediss-sentinel
- TLS connected to a centralized server behind a sentinel layer.
The URLs must have the following format:
redis|rediss :// [[username:]password@] host [:port][/database]
Example: redis://localhost:6379
redis|rediss[-cluster] :// [[username:]password@] host [:port][?[node=host1:port1][&node=host2:port2][&node=hostN:portN]]
or, if configured with multiple URLs:
[
"redis|rediss[-cluster] :// [[username:]password@] host [:port]",
"redis|rediss[-cluster] :// [[username:]password@] host1 [:port1]",
"redis|rediss[-cluster] :// [[username:]password@] host2 [:port2]"
]
redis|rediss[-sentinel] :// [[username1:]password1@] host [:port][/database][?[node=host1:port1][&node=host2:port2][&node=hostN:portN]
[&sentinelServiceName=myservice][&sentinelUsername=username2][&sentinelPassword=password2]]
or, if configured with multiple URLs:
[
"redis|rediss[-sentinel] :// [[username:]password@] host [:port][/database][?[&sentinelServiceName=myservice][&sentinelUsername=username2][&sentinelPassword=password2]]",
"redis|rediss[-sentinel] :// [[username1:]password1@] host [:port][/database][?[&sentinelServiceName=myservice][&sentinelUsername=username2][&sentinelPassword=password2]]"
]
In your router's YAML config file, you should specify your Redis URLs via environment variables and variable expansion. This prevents your Redis URLs from being committed to version control, which is especially dangerous if they include authentication information like a username and/or password.
Cached query plans are not evicted on schema refresh, which can quickly lead to distributed cache overflow when combined with cache-warm up and frequent schema publishes. Test your cache configuration with expected queries and consider decreasing the TTL to prevent cache overflow.
To enable distributed caching of query plans, add the following to your router's YAML config file:
supergraph:
query_planning:
cache:
redis: #highlight-line
urls: ["redis://..."] #highlight-line
The value of urls
is a list of URLs for all Redis instances in your cluster.
All query plan cache entries will be prefixed with plan.
within the distributed cache.
To enable distributed caching of automatic persisted queries (APQ), add the following to your router's YAML config file:
apq:
router:
cache:
redis: #highlight-line
urls: ["redis://..."] #highlight-line
The value of urls
is a list of URLs for all Redis instances in your cluster.
All APQ cache entries will be prefixed with apq
followed by a null byte character (referenced by the escape sequence \0
in most programming languages) within the distributed cache.
Redis configuration is done in the same way for APQ caching, query plan caching and entity caching.
supergraph:
query_planning:
cache:
redis: #highlight-line
urls: ["redis://..."] #highlight-line
username: admin/123 # Optional, can be part of the urls directly, mainly useful if you have special character like '/' in your password that doesn't work in url. This field takes precedence over the username in the URL
password: admin # Optional, can be part of the urls directly, mainly useful if you have special character like '/' in your password that doesn't work in url. This field takes precedence over the password in the URL
timeout: 2s # Optional, by default: 500ms
ttl: 24h # Optional
namespace: "prefix" # Optional
#tls:
required_to_start: false # Optional, defaults to false
reset_ttl: true # Optional, defaults to true
pool_size: 4 # Optional, defaults to 1
Connecting and sending commands to Redis are subject to a timeout, set by default to 500ms, that can be overriden.
The ttl
option defines the default global expiration for Redis entries. For APQ caching, the default is no expiration, while for query plan caching, the default expiration is set to 30 days.
When enabling distributed caching, consider how frequently you publish new schemas and configure the TTL accordingly. When new schemas are published, the router pre-warms the in-memory and distributed caches but doesn't invalidate existing cached query plans in the distributed cache, creating an additive effect on cache utilization.
To prevent cache overflow, consider decreasing the TTL to 24 hours or twice the median publish interval (whichever's lesser), and monitor cache utilization in your environment, especially during schema publish events.
Also note that when cache warm-up is enabled, each router instance will warm the distributed cache with query plans from its own in-memory cache. In the worst case, a schema publish will increase the number of query plans in the distributed cache by the number of router instances multiplied by the number of warmed-up queries per instance, which may noticeably increase the total cache utilization.
Be sure to test your configuration with expected queries and during schema publish events to understand the impact of distributed caching on cache utilization.When using the same Redis instance for multiple purposes, the namespace
option defines a prefix for all the keys defined by the router.
For Redis TLS connections, you can set up a client certificate or override the root certificate authority by configuring tls
in your router's YAML config file. For example:
apq:
router:
cache:
redis:
urls: [ "rediss://redis.example.com:6379" ]
#highlight-start
tls:
certificate_authorities: ${file./path/to/ca.crt}
client_authentication:
certificate_chain: ${file./path/to/certificate_chain.pem}
key: ${file./path/to/key.pem}
#highlight-end
When active, the required_to_start
option will prevent the router from starting if it cannot connect to Redis. By default, the router will still start without a connection to Redis, which would result in only using the in-memory cache for APQ and query planning, and entity caching sending the requests to subgraphs undisturbed.
When this option is active, accessing a cache entry in Redis will reset its expiration.
The pool_size
option defines the number of connections to Redis that the router will open. By default, the router will open a single connection to Redis. If there is a lot of traffic between router and Redis and/or there is some latency in those requests, it is recommended to increase the pool size to reduce that latency.