Skip to main content
ఆవిష్కరణ|ఆవిష్కరణ

Caching Strategies + Redis: మీ అప్లికేషన్‌ను మెరుపు వేగంతో చేయండి

Caching strategies మరియు Redis గురించి Java developers కోసం సంపూర్ణ గైడ్ — Spring Cache annotations, Redis data structures, multi-tier caching (Caffeine + Redis + Database), cache patterns (Cache-Aside, Write-Through, Write-Behind, Read-Through), TTL, eviction policies, మరియు production-ready Spring Boot configuration.

8 ఏప్రిల్, 202614 నిమిషాల చదువు

Caching ఎందుకు ముఖ్యం

మీరు పరీక్ష కోసం చదువుతున్నారని ఊహించుకోండి. ప్రతిసారి మీకు ఒక విషయం చూడాల్సి వస్తే, మీరు లైబ్రరీ వరకు నడిచి, సరైన షెల్ఫ్ కనుగొని, పుస్తకం తీసి, సరైన పేజీకి తిప్పి, సమాధానం చదివి, మళ్ళీ తిరిగి నడుస్తారు. మీ అప్లికేషన్ ప్రతి request కోసం database ని అడిగినప్పుడు అదే చేస్తుంది.

ఇప్పుడు మీ ఇష్టమైన పుస్తకాన్ని మీ డెస్క్ మీదే ఉంచుకున్నారని ఊహించుకోండి. సమాధానం కావాలా? కిందకు చూడండి. అదే caching. ఇది తరచుగా ఉపయోగించే data ను దగ్గరలో ఉంచుతుంది, కాబట్టి మీ అప్లికేషన్ మళ్ళీ మళ్ళీ fetch చేయడంలో సమయం వృధా చేయదు.

Cache అనేది పరీక్షలో ఒక cheat sheet లాంటిది — మొత్తం textbook చూడకుండా త్వరగా సమాధానాలు.

Caching లేకుండా, ఒక popular product page నిమిషానికి 10,000 సార్లు database ను query చేయవచ్చు. Caching తో, ఒకసారి query చేస్తుంది, result ను store చేస్తుంది, మరియు తదుపరి 9,999 requests ను memory నుండి serve చేస్తుంది. తేడా? Database query: ~5-50 milliseconds. Cache read: ~0.1-1 millisecond. అది 50x నుండి 500x వేగం.

Spring Cache Annotations

Spring Boot నాలుగు annotations తో caching ను సులభం చేస్తుంది. వాటిని మీ methods పై అతికించే సాధారణ labels గా భావించండి: "హే, ఈ result గుర్తుపెట్టుకో."

@Cacheable — "ఈ సమాధానం గుర్తుపెట్టుకో"

ఎవరైనా మొదటిసారి product అడిగినప్పుడు, Spring దాన్ని database నుండి fetch చేస్తుంది. ఆ తర్వాత ప్రతిసారి, Spring database ను తాకకుండా saved answer return చేస్తుంది. Sticky note పై సమాధానం రాయడం లాంటిది.

@Service
public class ProductService {

    @Cacheable(value = "products", key = "#productId")
    public Product getProductById(Long productId) {
        // ఇది ప్రతి productId కోసం మొదటిసారి మాత్రమే run అవుతుంది.
        // ఆ తర్వాత, Spring cached result return చేస్తుంది.
        log.info("Fetching product {} from database...", productId);
        return productRepository.findById(productId)
            .orElseThrow(() -> new ProductNotFoundException(productId));
    }

    // Conditional caching — price > 10 అయితే మాత్రమే cache చేయి
    @Cacheable(value = "products", key = "#productId",
               condition = "#productId > 0",
               unless = "#result.price < 10")
    public Product getExpensiveProduct(Long productId) {
        return productRepository.findById(productId).orElseThrow();
    }
}

@CachePut — "Sticky note update చేయి"

మీరు product update చేసినప్పుడు, cache లో latest version ఉండాలని కోరుకుంటారు. @CachePut ఎల్లప్పుడూ method run చేసి cache update చేస్తుంది. పాత sticky note చెరిపి కొత్తది రాయడం లాంటిది.

@CachePut(value = "products", key = "#product.id")
public Product updateProduct(Product product) {
    // ఇది ఎల్లప్పుడూ run అవుతుంది — result cache లో replace అవుతుంది.
    log.info("Updating product {} in database and cache", product.getId());
    return productRepository.save(product);
}

@CacheEvict — "Sticky note పారేయి"

Data delete అయినప్పుడు లేదా ఏమి మారిందో తెలియనప్పుడు, cache నుండి తీసేయండి. తదుపరిసారి ఎవరైనా అడిగినప్పుడు, Spring database నుండి fresh data fetch చేస్తుంది.

// ఒక product ను cache నుండి remove చేయి
@CacheEvict(value = "products", key = "#productId")
public void deleteProduct(Long productId) {
    productRepository.deleteById(productId);
}

// Nuclear option: మొత్తం cache clear చేయి
@CacheEvict(value = "products", allEntries = true)
public void refreshAllProducts() {
    log.info("Cleared entire products cache");
}

@Caching — "ఒకేసారి multiple cache operations చేయి"

కొన్నిసార్లు ఒక method multiple caches ను ప్రభావితం చేస్తుంది. @Caching multiple cache operations కలపడానికి అనుమతిస్తుంది.

@Caching(
    put = { @CachePut(value = "products", key = "#product.id") },
    evict = {
        @CacheEvict(value = "productList", allEntries = true),
        @CacheEvict(value = "productSearch", allEntries = true)
    }
)
public Product saveProduct(Product product) {
    return productRepository.save(product);
}

Redis Basics — మీ Super-Fast Notebook

Redis అంటే REmote DIctionary Server. ఇది hard drive పై కాకుండా మీ computer memory (RAM) లో ఉండే ఒక పెద్ద notebook లాంటిది. RAM నుండి చదవడం మీ ముందు ఉన్న sign చదవడం లాంటిది. Hard drive నుండి చదవడం అదే sign చదవడానికి మరొక city కి drive చేయడం లాంటిది.

Redis ఒక in-memory key-value store. మీరు దానికి ఒక name (key) మరియు value ఇస్తారు, అది గుర్తుపెట్టుకుంటుంది. Dictionary లా సులభం: word చూడండి, meaning పొందండి.

# Basic Redis commands — super-fast dictionary లాంటివి
SET product:101 "{\"name\": \"Wireless Mouse\", \"price\": 29.99}"
GET product:101
# Returns: {"name": "Wireless Mouse", "price": 29.99}

DEL product:101
# అయిపోయింది — notebook నుండి పోయింది

# Expiration (TTL) తో set చేయి — 300 seconds తర్వాత auto-delete
SET weather:nyc "72°F, Sunny" EX 300

# ఎంత సమయం మిగిలి ఉందో చూడండి
TTL weather:nyc
# Returns: 295 (seconds remaining)

Redis Data Structures — Key-Value కంటే ఎక్కువ

Redis కేవలం సాధారణ dictionary కాదు. దీనికి ఐదు శక్తివంతమైన data structures ఉన్నాయి, ప్రతి ఒక్కటి వేర్వేరు పనులకు సరిపోతుంది. వాటిని మీ kitchen లో ఐదు రకాల containers లా భావించండి.

1. String — సాధారణ Jar

ఒక single value store చేస్తుంది. Counters, simple values, లేదా serialized objects కోసం perfect.

# Simple value
SET user:profile:42 "{\"name\": \"Alice\", \"email\": \"alice@example.com\"}"

# Counter — tally counter లాంటిది
INCR page:views:homepage      # 1
INCR page:views:homepage      # 2
INCRBY page:views:homepage 10 # 12

2. Hash — Filing Cabinet

ఒక key లోపల mini-dictionary లాంటిది. JSON కి serialize చేయకుండా multiple fields ఉన్న objects store చేయడానికి perfect.

# User profile ను hash గా store చేయండి
HSET user:42 name "Alice" email "alice@example.com" age "30"

# ఒక field get చేయండి
HGET user:42 name          # "Alice"

# అన్ని fields get చేయండి
HGETALL user:42            # name, Alice, email, alice@example.com, age, 30

# ఒక field మాత్రమే update చేయండి — మొత్తం object rewrite అవసరం లేదు
HSET user:42 age "31"

3. List — Queue Line

Values యొక్క ordered list. Message queues, activity feeds, మరియు recent items కోసం perfect.

# Left కి add చేయండి (newest first) — line లో చేరే వ్యక్తులు లాంటిది
LPUSH recent:searches "wireless mouse"
LPUSH recent:searches "bluetooth keyboard"
LPUSH recent:searches "usb hub"

# 5 most recent searches get చేయండి
LRANGE recent:searches 0 4
# Returns: usb hub, bluetooth keyboard, wireless mouse

# Right నుండి remove చేయండి (oldest first) — queue process చేయండి
RPOP recent:searches       # "wireless mouse"

4. Set — Unique Stamp Collection

ప్రతి item unique గా ఉండే collection. Duplicates అనుమతించబడవు. Tags, unique visitors, మరియు "ఎవరు like చేశారు" కోసం perfect.

# Page కి unique visitors track చేయండి
SADD visitors:homepage "user:1" "user:2" "user:3"
SADD visitors:homepage "user:1"    # ignore చేయబడింది — ఇప్పటికే ఉంది!

# ఎంత మంది unique visitors?
SCARD visitors:homepage            # 3

# రెండు pages visit చేసిన users కనుగొనండి (intersection)
SADD visitors:about "user:2" "user:3" "user:4"
SINTER visitors:homepage visitors:about
# Returns: user:2, user:3

5. Sorted Set — Leaderboard

Set లాంటిది, కానీ ప్రతి item కి score ఉంటుంది. Items స్వయంచాలకంగా score ప్రకారం sort అవుతాయి. Leaderboards, ranking, మరియు top-N queries కోసం perfect.

# Movie ratings leaderboard
ZADD movie:ratings 9.3 "The Shawshank Redemption"
ZADD movie:ratings 9.2 "The Godfather"
ZADD movie:ratings 8.8 "The Dark Knight"
ZADD movie:ratings 9.0 "Pulp Fiction"

# Top 3 movies (highest score first)
ZREVRANGE movie:ratings 0 2 WITHSCORES
# 1) The Shawshank Redemption — 9.3
# 2) The Godfather — 9.2
# 3) Pulp Fiction — 9.0

# "The Dark Knight" rank ఏమిటి?
ZREVRANK movie:ratings "The Dark Knight"   # 3 (0-indexed)

Multi-Tier Caching — Three-Level రక్షణ

ఇలా ఆలోచించండి: L1 మీ నాలుక చివర ఉన్న సమాధానం (అత్యంత వేగం). L2 మీ జేబులో ఉన్న cheat sheet (వేగం). L3 మీ backpack లో ఉన్న textbook (నెమ్మది కానీ అన్నీ ఉన్నాయి).

LevelTechnologySpeedCapacityఎక్కడ
L1Caffeine (JVM Heap)~1 nsచిన్నది (100s of MBs)మీ app లోపల
L2Redis~0.5 msమధ్యస్థం (GBs)వేరే server
L3Database (PostgreSQL)~5-50 msపెద్దది (TBs)Disk storage

మీ app కి data అవసరమైనప్పుడు, మొదట L1 check చేస్తుంది. అక్కడ లేదా? L2 check చేయండి. ఇంకా లేదా? L3 (database) కి వెళ్ళండి, తర్వాత result ను L2 మరియు L1 లో store చేయండి.

@Service
public class MultiTierCacheService {

    private final Cache<String, Product> localCache; // L1: Caffeine
    private final RedisTemplate<String, Product> redisTemplate; // L2: Redis
    private final ProductRepository productRepository; // L3: Database

    public MultiTierCacheService(RedisTemplate<String, Product> redisTemplate,
                                  ProductRepository productRepository) {
        this.redisTemplate = redisTemplate;
        this.productRepository = productRepository;

        // L1: Caffeine — 1,000 items hold చేస్తుంది, 5 minutes తర్వాత expire
        this.localCache = Caffeine.newBuilder()
            .maximumSize(1_000)
            .expireAfterWrite(Duration.ofMinutes(5))
            .build();
    }

    public Product getProduct(String productId) {
        String cacheKey = "product:" + productId;

        // Step 1: L1 check చేయండి (Caffeine — JVM memory లో)
        Product product = localCache.getIfPresent(cacheKey);
        if (product != null) {
            log.debug("L1 HIT for {}", productId);
            return product;
        }

        // Step 2: L2 check చేయండి (Redis — separate server)
        product = redisTemplate.opsForValue().get(cacheKey);
        if (product != null) {
            log.debug("L2 HIT for {}", productId);
            localCache.put(cacheKey, product); // తదుపరిసారి కోసం L1 లో store చేయండి
            return product;
        }

        // Step 3: L3 నుండి fetch చేయండి (Database — source of truth)
        log.debug("L3 FETCH for {}", productId);
        product = productRepository.findById(productId).orElseThrow();

        // L2 మరియు L1 రెండింటిలో store చేయండి
        redisTemplate.opsForValue().set(cacheKey, product,
            Duration.ofMinutes(30));
        localCache.put(cacheKey, product);

        return product;
    }
}

Cache Patterns — మీ Cache ఉపయోగించడానికి నాలుగు మార్గాలు

మీ application cache మరియు database తో ఎలా మాట్లాడుతుందో నాలుగు ప్రధాన strategies ఉన్నాయి. ప్రతి దాని trade-offs ఉన్నాయి. మీ అవసరాల ఆధారంగా సరైనది ఎంచుకోండి.

1. Cache-Aside (Lazy Loading) — "వ్యక్తులు అడిగేది మాత్రమే cache చేయి"

Application స్వయంగా cache manage చేస్తుంది. Read లో, మొదట cache check చేయండి. Miss అయితే, database నుండి fetch చేసి cache లో store చేయండి. ఇది అత్యంత సాధారణ pattern.

Analogy: ఎవరైనా call చేసి మీరు number వెతకాల్సి వచ్చిన తర్వాత మాత్రమే sticky note పై phone number రాస్తారు. ఎవరూ Uncle Bob number అడగకపోతే, అది sticky note పై ఎప్పుడూ రాయబడదు.

@Service
public class UserProfileService {

    private final RedisTemplate<String, UserProfile> redis;
    private final UserRepository userRepository;

    // Cache-Aside: Read
    public UserProfile getUserProfile(Long userId) {
        String key = "user:profile:" + userId;

        // 1. Cache check చేయండి
        UserProfile cached = redis.opsForValue().get(key);
        if (cached != null) return cached;

        // 2. Cache miss — DB నుండి fetch చేయండి
        UserProfile profile = userRepository.findById(userId).orElseThrow();

        // 3. తదుపరిసారి కోసం cache లో store చేయండి (TTL: 1 hour)
        redis.opsForValue().set(key, profile, Duration.ofHours(1));
        return profile;
    }

    // Cache-Aside: Write (update కాదు, invalidate చేయండి)
    public UserProfile updateProfile(Long userId, UserProfile updated) {
        UserProfile saved = userRepository.save(updated);
        redis.delete("user:profile:" + userId); // Invalidate — next read re-cache చేస్తుంది
        return saved;
    }
}

ప్రయోజనాలు: నిజంగా request చేయబడిన data మాత్రమే cache చేస్తుంది. అర్థం చేసుకోవడం సులభం. Cache fail అయినా app break కాదు.

అప్రయోజనాలు: ప్రతి item కి మొదటి request ఎల్లప్పుడూ నెమ్మదిగా ఉంటుంది (cache miss). మీ app బయట database update అయితే stale data సాధ్యం.

2. Write-Through — "ఎల్లప్పుడూ cache మరియు database రెండింటినీ కలిసి update చేయి"

ప్రతి write cache మరియు database రెండింటికీ ఒకే సమయంలో వెళ్తుంది. Cache ఎల్లప్పుడూ database తో sync లో ఉంటుంది.

Analogy: మీరు address update చేసిన ప్రతిసారి, మీ phone contacts మరియు paper address book రెండింటినీ ఒకే సమయంలో update చేస్తారు.

@Service
public class WriteThroughProductService {

    public Product saveProduct(Product product) {
        // మొదట database కి write చేయండి
        Product saved = productRepository.save(product);

        // తర్వాత cache కి write చేయండి — cache ఎల్లప్పుడూ up to date
        String key = "product:" + saved.getId();
        redis.opsForValue().set(key, saved, Duration.ofHours(2));

        return saved;
    }

    public Product getProduct(String productId) {
        String key = "product:" + productId;
        // ప్రతి write update చేస్తుంది కాబట్టి cache ఎల్లప్పుడూ fresh
        Product cached = redis.opsForValue().get(key);
        if (cached != null) return cached;

        // DB కి fallback (first load లేదా cache eviction తర్వాత మాత్రమే అవసరం)
        Product product = productRepository.findById(productId).orElseThrow();
        redis.opsForValue().set(key, product, Duration.ofHours(2));
        return product;
    }
}

ప్రయోజనాలు: Cache ఎల్లప్పుడూ database తో consistent. Stale data లేదు.

అప్రయోజనాలు: Writes నెమ్మదిగా ఉంటాయి (ఒకటి బదులు రెండు writes). ఎప్పుడూ read కాని data కూడా cache చేస్తుంది.

3. Write-Behind (Write-Back) — "ఇప్పుడు cache update చేయి, database తర్వాత"

Writes వెంటనే cache కి వెళ్తాయి, మరియు cache background లో database కి write చేస్తుంది (batched). అత్యంత వేగమైన writes, కానీ complex.

Analogy: మీరు రోజంతా whiteboard పై notes రాస్తారు, తర్వాత రోజు చివరలో అన్నీ notebook కి copy చేస్తారు.

@Service
public class WriteBehindService {

    private final Queue<Product> writeQueue = new ConcurrentLinkedQueue<>();

    // Write వెంటనే cache కి వెళ్తుంది — అత్యంత వేగం
    public Product saveProduct(Product product) {
        String key = "product:" + product.getId();
        redis.opsForValue().set(key, product);

        // Database write ను తర్వాత కోసం queue చేయండి
        writeQueue.add(product);
        return product;
    }

    // Background job ప్రతి 5 seconds కి queue ను database కి flush చేస్తుంది
    @Scheduled(fixedRate = 5000)
    public void flushToDatabase() {
        List<Product> batch = new ArrayList<>();
        Product item;
        while ((item = writeQueue.poll()) != null) {
            batch.add(item);
        }
        if (!batch.isEmpty()) {
            productRepository.saveAll(batch);
            log.info("Flushed {} products to database", batch.size());
        }
    }
}

ప్రయోజనాలు: అత్యంత వేగమైన writes. Batching database load తగ్గిస్తుంది.

అప్రయోజనాలు: Flush చేయడానికి ముందు cache crash అయితే data loss risk. Implement చేయడం complex.

4. Read-Through — "Cache మీ కోసం database నుండి fetch చేస్తుంది"

Application cache తో మాత్రమే మాట్లాడుతుంది. Cache దగ్గర data లేకపోతే, cache స్వయంగా database కి వెళ్తుంది. Application database ను నేరుగా తాకదు.

Analogy: మీరు assistant ని file కోసం అడుగుతారు. Assistant దగ్గర లేకపోతే, filing cabinet కి వెళ్ళి, తీసుకొని, copy ఉంచుకొని, మీకు ఇస్తారు. మీరు filing cabinet కి ఎప్పుడూ వెళ్ళరు.

// Caffeine LoadingCache తో — miss పై automatically fetch చేస్తుంది
@Configuration
public class ReadThroughConfig {

    @Bean
    public LoadingCache<Long, Product> productCache(ProductRepository repo) {
        return Caffeine.newBuilder()
            .maximumSize(5_000)
            .expireAfterWrite(Duration.ofMinutes(15))
            .build(productId -> repo.findById(productId).orElse(null));
            // ^ ఈ loader cache miss పై automatically run అవుతుంది
    }
}

@Service
public class ReadThroughProductService {

    private final LoadingCache<Long, Product> productCache;

    public Product getProduct(Long productId) {
        // Cache ని అడగండి — అన్నీ handle చేస్తుంది
        return productCache.get(productId);
        // Cache HIT? Memory నుండి returns.
        // Cache MISS? Loader call చేస్తుంది, result store చేస్తుంది, return చేస్తుంది.
    }
}

ప్రయోజనాలు: Application code అత్యంత సాధారణం. Fetching logic అంతా cache handle చేస్తుంది.

అప్రయోజనాలు: Cache ను data source కి tightly couple చేస్తుంది. తప్పులు వచ్చినప్పుడు debug చేయడం కష్టం.

TTL మరియు Eviction Policies — పాత Data ఎప్పుడు పారేయాలి

Caches ఎప్పటికీ పెరగలేవు. పాత data ఎప్పుడు తీసేయాలో rules అవసరం. మీ desk గురించి ఆలోచించండి: మీరు ఎప్పటికీ papers పేర్చుకుంటూ పోతే, ఏమీ కనుగొనలేరు. ఏమి ఉంచాలి మరియు ఏమి పారేయాలి అనే rules అవసరం.

TTL (Time To Live) — "ఈ sticky note 10 minutes లో expire అవుతుంది"

Cache లో data ఎంత సమయం ఉంటుందో set చేయండి. Time అయిపోయాక, అది automatically disappear అవుతుంది.

# Redis: key 3600 seconds (1 hour) తర్వాత expire అవుతుంది
SET weather:london "15°C, Cloudy" EX 3600

# మిగిలిన సమయం check చేయండి
TTL weather:london    # 3542 (seconds left)
// Java: RedisTemplate తో TTL set చేయండి
redis.opsForValue().set("weather:london", weatherData,
    Duration.ofHours(1));

// Caffeine: write తర్వాత expire
Caffeine.newBuilder()
    .expireAfterWrite(Duration.ofMinutes(10))
    .build();

Eviction Policies — "Desk నిండిపోయింది. ఏమి remove చేద్దాం?"

Cache నిండినప్పుడు, Redis ఏమి remove చేయాలో decide చేయాలి. Redis ఈ eviction policies support చేస్తుంది:

Policyఏమి చేస్తుందిదేని కోసం Best
allkeys-lruఇటీవల తక్కువగా ఉపయోగించిన key remove చేయిGeneral purpose (recommend చేయబడింది)
allkeys-lfuతక్కువ frequency గా ఉపయోగించిన key remove చేయికొన్ని keys ఎల్లప్పుడూ popular అయినప్పుడు
volatile-lruLRU, కానీ TTL set చేసిన keys మాత్రమేPersistent మరియు cached data mix
volatile-ttlExpire కావడానికి దగ్గరగా ఉన్న keys remove చేయిTTL ప్రాముఖ్యతను reflect చేసినప్పుడు
noevictionMemory నిండినప్పుడు errors return చేయిData loss ఆమోదయోగ్యం కానప్పుడు
# redis.conf లో eviction policy set చేయండి
maxmemory 256mb
maxmemory-policy allkeys-lru

Cache Invalidation Strategies — Computer Science లో అత్యంత కష్టమైన సమస్య

Computer Science లో రెండు కష్టమైన విషయాలు మాత్రమే ఉన్నాయి: cache invalidation మరియు naming things. మొదటిదాన్ని ఎలా handle చేయాలో ఇక్కడ ఉంది.

1. Time-Based (TTL)

అత్యంత సాధారణ approach. Set చేసిన సమయం తర్వాత data expire అవుతుంది. కొద్దిగా stale data ఆమోదయోగ్యమైనప్పుడు బాగా పని చేస్తుంది (weather, product listings, blog posts).

@Cacheable(value = "weatherForecast", key = "#city")
public Weather getWeather(String city) {
    return weatherApi.fetchForecast(city);
}

// application.yml లో — cache కి TTL set చేయండి
spring:
  cache:
    redis:
      time-to-live: 600000   # 10 minutes in milliseconds

2. Event-Based (Publish/Subscribe)

Data మారినప్పుడు, event publish చేయండి. ఆసక్తి ఉన్న అన్ని services listen చేసి వాటి caches invalidate చేస్తాయి.

// Product update అయినప్పుడు, event publish చేయండి
@Service
public class ProductUpdatePublisher {

    private final RedisTemplate<String, String> redis;

    public void publishProductUpdate(Long productId) {
        redis.convertAndSend("product:updates",
            String.valueOf(productId));
    }
}

// మరొక service లో Listener — local cache clear చేస్తుంది
@Component
public class ProductCacheListener {

    private final Cache<Long, Product> localCache;

    @EventListener
    public void onProductUpdate(ProductUpdateEvent event) {
        localCache.invalidate(event.getProductId());
        log.info("Cache invalidated for product {}", event.getProductId());
    }
}

3. Version-Based

Cache key లో version number include చేయండి. Data మారినప్పుడు, version పెంచండి. పాత keys TTL ద్వారా naturally expire అవుతాయి.

@Service
public class VersionedCacheService {

    public Product getProduct(Long productId) {
        int version = getCurrentVersion(productId);
        String key = "product:" + productId + ":v" + version;

        Product cached = redis.opsForValue().get(key);
        if (cached != null) return cached;

        Product product = productRepository.findById(productId).orElseThrow();
        redis.opsForValue().set(key, product, Duration.ofHours(1));
        return product;
    }

    public void updateProduct(Long productId, Product updated) {
        productRepository.save(updated);
        incrementVersion(productId); // పాత cache key orphaned — TTL clean up చేస్తుంది
    }
}

Spring Boot + Redis Configuration

Spring Boot తో Redis caching కోసం complete, production-ready setup ఇక్కడ ఉంది.

Step 1: Dependencies Add చేయండి

<!-- pom.xml -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
    <groupId>com.github.ben-manes.caffeine</groupId>
    <artifactId>caffeine</artifactId>
</dependency>

Step 2: application.yml Configure చేయండి

spring:
  data:
    redis:
      host: localhost
      port: 6379
      password: ${REDIS_PASSWORD:}
      timeout: 2000ms
      lettuce:
        pool:
          max-active: 16
          max-idle: 8
          min-idle: 2
          max-wait: 500ms
        shutdown-timeout: 200ms

  cache:
    type: redis
    redis:
      time-to-live: 3600000        # 1 hour default TTL
      cache-null-values: false     # null results cache చేయవద్దు
      key-prefix: "myapp:"        # అన్ని keys కి prefix
      use-key-prefix: true

logging:
  level:
    org.springframework.cache: DEBUG   # Logs లో cache HIT/MISS చూడండి

Step 3: Redis Configuration Class

@Configuration
@EnableCaching
public class RedisConfig {

    @Bean
    public RedisCacheManager cacheManager(RedisConnectionFactory factory) {

        // Default config: 1 hour TTL, JSON serialization
        RedisCacheConfiguration defaultConfig = RedisCacheConfiguration
            .defaultCacheConfig()
            .entryTtl(Duration.ofHours(1))
            .serializeKeysWith(
                SerializationPair.fromSerializer(new StringRedisSerializer()))
            .serializeValuesWith(
                SerializationPair.fromSerializer(
                    new GenericJackson2JsonRedisSerializer()))
            .disableCachingNullValues();

        // ప్రతి cache name కి custom TTLs
        Map<String, RedisCacheConfiguration> perCacheConfig = Map.of(
            "products",        defaultConfig.entryTtl(Duration.ofMinutes(30)),
            "userProfiles",    defaultConfig.entryTtl(Duration.ofHours(2)),
            "weatherForecast", defaultConfig.entryTtl(Duration.ofMinutes(10)),
            "movieRatings",    defaultConfig.entryTtl(Duration.ofHours(6))
        );

        return RedisCacheManager.builder(factory)
            .cacheDefaults(defaultConfig)
            .withInitialCacheConfigurations(perCacheConfig)
            .transactionAware()
            .build();
    }

    @Bean
    public RedisTemplate<String, Object> redisTemplate(
            RedisConnectionFactory factory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(factory);
        template.setKeySerializer(new StringRedisSerializer());
        template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
        template.setHashKeySerializer(new StringRedisSerializer());
        template.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
        template.afterPropertiesSet();
        return template;
    }
}

Step 4: Complete Service Example

@Service
@CacheConfig(cacheNames = "products") // ఈ class కి default cache name
public class ProductCatalogService {

    private final ProductRepository productRepository;

    @Cacheable(key = "#productId")
    public Product findById(Long productId) {
        return productRepository.findById(productId)
            .orElseThrow(() -> new NotFoundException("Product not found"));
    }

    @Cacheable(key = "'all:' + #pageable.pageNumber")
    public Page<Product> findAll(Pageable pageable) {
        return productRepository.findAll(pageable);
    }

    @CachePut(key = "#result.id")
    public Product create(CreateProductRequest request) {
        Product product = new Product(request.name(), request.price());
        return productRepository.save(product);
    }

    @CachePut(key = "#productId")
    public Product update(Long productId, UpdateProductRequest request) {
        Product product = productRepository.findById(productId).orElseThrow();
        product.setName(request.name());
        product.setPrice(request.price());
        return productRepository.save(product);
    }

    @Caching(evict = {
        @CacheEvict(key = "#productId"),
        @CacheEvict(cacheNames = "products", key = "'all:*'",
                    allEntries = true)
    })
    public void delete(Long productId) {
        productRepository.deleteById(productId);
    }
}

ముఖ్యమైన అంశాలు

Caching అవసరం: Read-heavy workloads కోసం మీ application ను 50x-500x వేగంగా చేయగలదు. మీ అత్యధికంగా query చేయబడే methods పై @Cacheable తో ప్రారంభించండి.

Redis మీ best friend: Rich data structures (String, Hash, List, Set, Sorted Set) తో in-memory key-value store. ఇది fast, simple, మరియు battle-tested.

Multi-tier caching: Hottest data కోసం L1 (Caffeine), instances అంతటా shared data కోసం L2 (Redis), source of truth గా L3 (Database) ఉపయోగించండి.

సరైన pattern ఎంచుకోండి: Simplicity కోసం Cache-Aside, consistency కోసం Write-Through, speed కోసం Write-Behind, clean code కోసం Read-Through.

Invalidation ముఖ్యం: మీ baseline గా TTL, real-time accuracy కోసం event-based, complex scenarios కోసం version-based ఉపయోగించండి. Stale data ఎలా clean up అవుతుందో ఎల్లప్పుడూ plan చేయండి.

ఆలోచనతో configure చేయండి: ప్రతి cache కి different TTLs set చేయండి, debugging కోసం JSON serialization ఉపయోగించండి, HIT/MISS ratios చూడటానికి logging enable చేయండి, మరియు Redis లో maxmemory-policy set చేయండి.

Frequently Asked Questions

1. Caching ఎప్పుడు ఉపయోగించాలి మరియు ఎప్పుడు avoid చేయాలి?

మీ data write చేయడం కంటే చాలా ఎక్కువ read చేయబడినప్పుడు caching ఉపయోగించండి (product catalog లాగా — 10,000 సార్లు read, రోజుకు ఒకసారి update). నిరంతరం మారే data (live stock ticker లాగా) లేదా real-time లో 100% accurate గా ఉండాల్సిన data (transaction లో account balances లాగా) కోసం caching avoid చేయండి. మంచి rule of thumb: ఒకే query ఒకే result తో నిమిషానికి 10 కంటే ఎక్కువ సార్లు run అయితే, cache చేయండి.

2. Redis down అయితే ఏమి జరుగుతుంది? నా application crash అవుతుందా?

మీరు సరిగ్గా design చేస్తే కాదు. Cache ను ఎల్లప్పుడూ optional గా treat చేయండి. Redis down అయితే, మీ application database ను నేరుగా query చేయడానికి fall back అవ్వాలి — నెమ్మదిగా ఉంటుంది, కానీ పని చేస్తుంది. Spring Boot @Cacheable default గా దీన్ని gracefully handle చేస్తుంది. Production లో, high availability కోసం Redis Sentinel (automatic failover) లేదా Redis Cluster (multiple nodes అంతటా data) ఉపయోగించండి.

3. Cache కోసం సరైన TTL ఎలా decide చేయాలి?

మీ data ఎంత stale అవ్వవచ్చో దానిపై ఆధారపడి ఉంటుంది. Weather data? 10 minutes fine. User profile? 1-2 hours. Product listings? 30 minutes. Blog posts? 6-24 hours. Conservative (తక్కువ) TTL తో ప్రారంభించండి, మీ cache hit ratio monitor చేయండి, మరియు data అరుదుగా మారితే పెంచండి. మంచి target 90% లేదా అంతకంటే ఎక్కువ cache hit ratio.

4. Caffeine మరియు Redis caching మధ్య తేడా ఏమిటి?

Caffeine మీ application JVM memory లో run అవుతుంది — ఇది అద్భుతంగా fast (nanoseconds) కానీ ప్రతి server కి దాని స్వంత copy ఉంటుంది, మరియు app restart అయినప్పుడు data కోల్పోతుంది. Redis ఒక separate server గా run అవుతుంది — కొద్దిగా slow (sub-millisecond network call) కానీ మీ అన్ని app instances ఒకే cache share చేస్తాయి, మరియు data restarts survive చేస్తుంది. అరుదుగా మారే ultra-hot data కోసం Caffeine, instances అంతటా shared data కోసం Redis ఉపయోగించండి.

5. Microservices architecture తో caching ఉపయోగించవచ్చా?

ఖచ్చితంగా. Redis microservices కోసం perfect ఎందుకంటే అన్ని services access చేయగల shared cache గా పని చేస్తుంది. ప్రతి service దాని keys ను namespace చేయాలి (e.g., product-service:product:42, user-service:profile:99) collisions avoid చేయడానికి. Event-based invalidation (Redis Pub/Sub లేదా Kafka వంటి message broker) ఉపయోగించండి, ఒక service data update చేసినప్పుడు, cache చేసిన ఇతర services వాటి copies invalidate చేయగలవు.

ఆవిష్కరణ నుండి మరిన్ని

ఆవిష్కరణ

ఈ ఏడాది తెలివితేటలు చౌకయ్యాయి — విలువ మీరు దానితో నిర్మించేదానికి మారింది

ఒక మిలియన్ AI టోకెన్ల ఖర్చు ఒకే ఏడాదిలో దాదాపు నాలుగు రెట్లు తగ్గింది. ముడిసరుకు ఇంత వేగంగా చౌకైనప్పుడు, ప్రయోజనం మోడల్ ఎవరిది అనేది కాకుండా ఉపయోగకరమైనది ఎవరు నిర్మిస్తారు అనేదిగా మారుతుంది.

14, జూన్ 20263 నిమిషాల చదువు
ఆవిష్కరణ

రోబోట్లు ప్రదర్శన ఆపి పని మొదలుపెట్టిన సంవత్సరం

ఒక దశాబ్దం పాటు హ్యూమనాయిడ్ రోబోట్లు కేవలం డెమో వీడియోలే — ఎప్పుడూ ఆకట్టుకునేవి, ఎప్పుడూ ఐదేళ్ళ దూరంలో ఉండేవి. 2026లో కథ నిశ్శబ్దంగా వీడియోల నుండి ఉత్పత్తి సంఖ్యలకు మారింది.

14, జూన్ 20263 నిమిషాల చదువు
ఆవిష్కరణ

AI నెలనెలా చౌకవుతోంది. మరి అందరి AI బిల్లులు ఎందుకు పేలిపోతున్నాయి?

AI ధర ఏడాదిలో సుమారు 4 రెట్లు తగ్గింది — కానీ కంపెనీలు వార్షిక AI బడ్జెట్లను నెలల్లో ఖర్చు చేస్తున్నాయి. రెండూ నిజమే — కారణం అర్థం చేసుకోవడం ముఖ్యం.

12, జూన్ 20263 నిమిషాల చదువు