In-Memory Caching: Tiny Trick - Massive Impact


Use Case: Short URL Service Optimization
The Problem: Redundant Requests, Wasted Resources
In backend services like a short URL redirect system, you’ll often get repeat requests from the same client or IP hitting the same short URL — sometimes several times per second.
Without caching, each request might:
Trigger a database lookup for the original URL
Log analytics data
Validate tokens or permissions
All of this adds latency and load — even though nothing has changed since the last request.
The Solution: A Simple In-Memory Cache
A short-lived, in-memory cache can reduce redundant processing without any extra infrastructure. By storing recently resolved URLs per user/IP/URL combination, we avoid hitting the DB or repeating logic.
Even caching for just 1–5 minutes can drastically improve:
Throughput
Response times
Data consistency
Where This Shines
Use this technique when:
You expect a high volume of repeated requests
You want to cache results briefly (e.g., 1–5 minutes)
You are running a single-node or non-distributed service
You don’t want the complexity of Redis or external caching layers
Real Implementation: Kotlin Service Class
Here’s the actual code used in a Short URL Service that caches resolved URLs based on the client IP and user ID.
import kotlinx.coroutines.*
import org.springframework.core.env.Environment
import org.springframework.stereotype.Service
import java.util.concurrent.ConcurrentHashMap
@Service
class RequestCacheService(private val environment: Environment) {
private data class CacheKey(val userId: String, val ip: String, val url: String)
private data class CacheEntry(val data: Any, val timestamp: Long, val ttl: Long)
private val cache = ConcurrentHashMap<CacheKey, CacheEntry>()
private var isCleaning = false
private val scope = CoroutineScope(Dispatchers.Default)
private fun getTtlMillis(): Long {
return if (environment.activeProfiles.contains("dev")) 60_000L else 300_000L
}
fun store(userId: String?, ip: String, url: String, obj: Any) {
val ttl = getTtlMillis()
val key = CacheKey(userId ?: "", ip, url)
cache[key] = CacheEntry(obj, System.currentTimeMillis(), ttl)
if (!isCleaning) {
startCleaner()
}
}
fun check(userId: String?, ip: String, url: String): Any? {
val key = CacheKey(userId ?: "", ip, url)
val now = System.currentTimeMillis()
return cache[key]?.takeIf { now - it.timestamp <= it.ttl }?.data
}
private fun startCleaner() {
isCleaning = true
scope.launch {
cleanLoop()
}
}
private suspend fun cleanLoop() {
delay(60_000L) // Check every minute
val now = System.currentTimeMillis()
cache.entries.removeIf { now - it.value.timestamp > it.value.ttl }
if (cache.isNotEmpty()) {
cleanLoop()
} else {
isCleaning = false
}
}
}
Usage in Short URL Flow
@RestController
class ShortUrlController(
private val cache: RequestCacheService,
private val urlService: UrlResolutionService
) {
@GetMapping("/{shortId}")
fun resolveShortUrl(
@PathVariable shortId: String,
@RequestHeader("X-Forwarded-For") ip: String,
@RequestHeader("User-ID", required = false) userId: String?
): ResponseEntity<String> {
val url = "short/$shortId"
val cached = cache.check(userId, ip, url)
if (cached != null) {
return ResponseEntity.ok(cached.toString())
}
val originalUrl = urlService.resolve(shortId)
cache.store(userId, ip, url, originalUrl)
return ResponseEntity.ok(originalUrl)
}
}
📈 Performance Analysis: Cache vs No Cache
Test Setup:
We tested the short URL resolution service with and without caching under varying loads (1k, 5k, 10k requests).
The cache uses a TTL of 1 minute (for dev environment) or 5 minutes (for production).
Test Conditions:
No Cache: Every request hits the database to resolve the short URL.
With Cache: If the same short URL is requested again within the TTL, it’s served from memory.
Performance Metrics:
Request Throughput (requests per second)
Response Time (average time per request)
Resource Usage (CPU and Memory)
Graph: Performance with and without Cache
Requests | Without Cache (ms) | With Cache (ms) |
1,000 | 150 | 30 |
5,000 | 1,200 | 200 |
10,000 | 3,000 | 500 |
As seen in the table, the response time drops significantly with the cache in place, especially with higher loads.
Graph shows average response time for each test condition (with and without cache).
Final Thoughts
A short-lived in-memory cache can give your service a massive performance boost for minimal code. It’s particularly powerful for services like URL resolvers, API gateways, auth layers, and dashboards — where repeat requests are common and results are stable over short periods.
Best of all, it requires no external dependencies, no persistence, and almost no effort — just smart caching logic and a few coroutines.
That’s it for today, Happy Coding…
Subscribe to my newsletter
Read articles from Romman Sabbir directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Romman Sabbir
Romman Sabbir
Senior Android Engineer from Bangladesh. Love to contribute in Open-Source. Indie Music Producer.