간단한 "캐시 무효화"전략, 2부

"There are only two hard problems in Computer Science: cache invalidation, and naming things."
— Phil Karlton





이것은 우리가 간단한 캐시 미들웨어 구현에 대해 이야기했던 지난 게시물에 이어지며 위의 흐름도에 요약될 수 있습니다. 해당 게시물을 읽지 않은 경우 계속하기 전에 읽어 보십시오. 그 게시물은 "캐시 무효화를 어떻게 할 수 있습니까?"라는 질문으로 끝났습니다. 이제 이 질문을 살펴보겠습니다.

좋아, 이것을 한 번 더 해보자.



질문 캐싱이 필요한 이유는 무엇입니까?
답. 사용자가 데이터를 더 빨리 얻을 수 있도록.
질문 캐시 무효화가 필요한 이유는 무엇입니까?
답. 사용자가 최근 실시간 데이터를 얻을 수 있도록.

캐시 무효화란 무엇입니까?



캐시 무효화는 computer system의 프로세스로서 cache의 항목을 교체하거나 제거합니다.
  • "교체됨": 캐시가 최근 업데이트된 데이터로 교체됨
  • "제거됨": 전체 캐시가 제거되었습니다.

  • 이 두 가지 방법 중 "제거"가 구현하기 가장 쉽고 캐시가 지워지고 새 데이터로 다시 작성됩니다.

    캐시 무효화 전략



    여기에는 두 단계만 있지만 구현은 아키텍처마다 크게 다를 수 있습니다.
  • 데이터 변경이 트리거될 수 있는 모든 소스 찾기: 데이터는 API 끝점, 주기적 작업 또는 코드베이스 깊숙이 숨겨진 트리거를 통해 변경될 수 있습니다. 당신의 임무는 그것들을 모두 찾는 것입니다.
  • 데이터가 변경된 후 캐시를 지우거나 업데이트하는 방법을 추가합니다. 그렇게 간단합니다. 😅

  • 다시 말하지만 이에 대한 정확한 구현은 다를 수 있습니다.
  • 데이터베이스 모델의 $afterUpdate와 같은 낮은 수준에서 캐시 지우기 방법을 추가합니다.
  • 데이터를 변경하는 모든 메소드에 추가하십시오. 그것은 모두 응용 프로그램의 복잡성에 달려 있습니다.

  • 이 게시물에서는 캐시 미들웨어를 확장하여 무효화도 처리할 것입니다. 어떻게 작동하는지 살펴보겠습니다. 이 예에서는 리소스의 데이터를 변경하는 유일한 방법은 POST 요청을 수행하는 것이라고 가정합니다. 미들웨어에 clear라는 새 메서드를 추가합니다.

    // middlewares/cache.js
    
    const NodeCache = require('node-cache')
    const cache = new NodeCache({ stdTTL: 5 * 60 })
    
    function getUrlFromRequest(req) {
        ...
    }
    
    function set(req, res, next) {
        ...  
    }
    
    function get(req, res, next) {
        ...
    }
    
    + function clear(req, res, next) {
    +   cache.keys(function(err, keys) {
    +       if (!err) {
    +           let resourceUrl = req.baseUrl;
    +           const resourceKeys = keys.filter(k => k.includes(resourceUrl));
    +           cache.del(resourceKeys);
    +       }
    +   });
    +   return next();
    + }
    
    module.exports = { get, set, clear }
    

    그리고 우리 경로에서 사용

    // products/routes.js
    
    router.get(
        ...
    )
    
    router.post(
        '/',
        productsController.create,
        cache.clear, // 👈
        responseHandler
    )
    

    그리고 완료!
    POST 요청이 있을 때마다 데이터가 변경되었으므로 다음 GET 요청이 들어올 때 캐시를 다시 작성할 수 있도록 캐시 지우기를 트리거합니다.
    cache.clear에서 정확히 무슨 일이 일어나고 있습니까?

    // middlewares/cache.js
    
    ...
    ...
    
    function clear(req, res, next) {
        cache.keys(function(err, keys) {
            if (!err) {
                // again, it depends on your application architecture,
                // how you would retrive and clear the cache that needs to be cleared.
                // You may use query path, query params or anything. 
                let resourceUrl = req.baseUrl;
                const resourceKeys = keys.filter(k => k.includes(resourceUrl));
    
                cache.del(resourceKeys);
            }
        });
        return next();
    }
    

  • cache.keys 저장된 모든 캐시 키를 반환합니다.
  • req.baseUrl에는 요청의 기본 경로가 있습니다. 'products'
  • resourceKeys는 하위 문자열로 기본 경로가 있는 모든 키를 가져옵니다. (기억하세요? 키는 단순히 GET 리소스를 가리키는 URL이었습니다.)
  • cache.del 키가 가리키는 캐시를 지웁니다.

  • 예를 들어 캐시에 다음과 같은 키가 있는 값이 있는 경우
  • https://api.com/products?sort=date&include=sellers&top=25
  • https://api.com/products?sort=cost&include=[sellers,sales]
  • POST에 대한 /products/ 요청은 이러한 모든 👆 캐시를 지우고 새 GET 요청이 들어올 때 다시 작성됩니다.

    내 예에서는 POST 요청의 기본 경로 범위 내에 있는 키가 있는 모든 캐시를 지우기만 하면 됩니다.

    이 설정을 사용하면 이론적으로 캐시 TTL을 무한대로 설정할 수 있습니다. 데이터를 변경할 때마다 캐시가 지워지고 캐시에 항상 최신 데이터가 있기 때문입니다. 하지만 건강을 위해 TTL을 15분으로 유지했습니다. 이제 사용자는 항상 최신 데이터를 더 빠르게 보유하게 되었습니다.

    오늘은 그게 다야. 행복한 코딩!

    나를 따르라 | Github , 멋진 물건을 만들고 게시합니다. 👨‍💻

    좋은 웹페이지 즐겨찾기