Problem
The KVCacheAware.Score plugin in the kthena-router introduces significant latency per request, typically ranging from 30ms to 100ms per scoring call. Under concurrent workloads (e.g., multi-turn conversations), this latency adds up and becomes a bottleneck for request routing.
Observed Latency (from production logs)
KVCacheAware.Score: completed in 57.139784ms
KVCacheAware.Score: completed in 31.290123ms
KVCacheAware.Score: completed in 85.288769ms
KVCacheAware.Score: completed in 100.34733ms
KVCacheAware.Score: completed in 76.064469ms
KVCacheAware.Score: completed in 72.113914ms
...
Average latency is approximately 50-60ms, with spikes exceeding 100ms. Under high concurrency scenarios, this significantly impacts overall request throughput and tail latency.
Test Script
The issue was reproduced using the following multi-turn conversation benchmark script:
https://github.com/YaoZengzeng/scripts/blob/master/aiperf/multi-turn-conversation.sh
Environment
- Model: Qwen (0.6B) with 3-4 replicas
- Backend: vLLM
- KV cache metadata stored in Redis
Root Cause Analysis
The Score function (pkg/kthena-router/scheduler/plugins/kvcache_aware.go) performs two expensive operations on every single request:
-
Tokenization (normalizeAndTokenizePrompt): Each incoming prompt must be tokenized to compute block hashes. This involves loading and invoking the tokenizer for the target model on every request, even for multi-turn conversations where prior turns have already been tokenized.
-
Redis Query (queryRedisForBlocks): After tokenization, the plugin queries Redis via a pipeline to check which pods have cached the corresponding KV blocks. Even though pipelining is used, the network round-trip and per-block hash lookup add consistent overhead.
Both operations are performed from scratch on every scoring call, with no reuse of previously computed results.
Problem
The
KVCacheAware.Scoreplugin in the kthena-router introduces significant latency per request, typically ranging from 30ms to 100ms per scoring call. Under concurrent workloads (e.g., multi-turn conversations), this latency adds up and becomes a bottleneck for request routing.Observed Latency (from production logs)
Average latency is approximately 50-60ms, with spikes exceeding 100ms. Under high concurrency scenarios, this significantly impacts overall request throughput and tail latency.
Test Script
The issue was reproduced using the following multi-turn conversation benchmark script:
https://github.com/YaoZengzeng/scripts/blob/master/aiperf/multi-turn-conversation.sh
Environment
Root Cause Analysis
The
Scorefunction (pkg/kthena-router/scheduler/plugins/kvcache_aware.go) performs two expensive operations on every single request:Tokenization (
normalizeAndTokenizePrompt): Each incoming prompt must be tokenized to compute block hashes. This involves loading and invoking the tokenizer for the target model on every request, even for multi-turn conversations where prior turns have already been tokenized.Redis Query (
queryRedisForBlocks): After tokenization, the plugin queries Redis via a pipeline to check which pods have cached the corresponding KV blocks. Even though pipelining is used, the network round-trip and per-block hash lookup add consistent overhead.Both operations are performed from scratch on every scoring call, with no reuse of previously computed results.