Memcached에 대한 캐싱 전략 - Amazon ElastiCache

기계 번역으로 제공되는 번역입니다. 제공된 번역과 원본 영어의 내용이 상충하는 경우에는 영어 버전이 우선합니다.

Memcached에 대한 캐싱 전략

다음 항목에서는 Memcached 캐시를 채우고 유지 관리하기 위한 전략을 확인할 수 있습니다.

캐시를 채우고 유지 관리하기 위해 구현하려는 전략은 캐싱되는 데이터의 유형과 해당 데이터에 대한 액세스 패턴에 따라 달라집니다. 예를 들어, 게임 사이트와 새 이야기 추세의 상위 10개 리더보드에 대해 동일한 전략을 사용하려고 하지 않을 수 있습니다. 이 섹션의 나머지 부분에서는 일반적인 캐시 유지 관리 전략, 이에 대한 장점 및 단점에 대해 살펴봅니다.

지연 로딩

이름에서 알 수 있듯이 지연 로딩은 필요할 때에만 데이터를 캐시에 로드하는 캐싱 전략입니다. 다음 설명과 같이 작동합니다.

Amazon ElastiCache는 액세스하는 애플리케이션과 데이터 스토어(데이터베이스) 사이에 위치하는 인 메모리 키/값 저장소입니다. 애플리케이션에서 데이터를 요청할 때마다 ElastiCache 캐시에 먼저 요청합니다. 데이터가 캐시에 있으며 최신 상태인 경우 ElastiCache가 데이터를 애플리케이션에 반환합니다. 데이터가 캐시에 없거나 만료된 경우 애플리케이션에서 데이터 스토어에 데이터를 요청합니다. 데이터 스토어에서 데이터를 애플리케이션에 반환합니다. 다음으로 애플리케이션은 스토어에서 수신한 데이터를 캐시에 씁니다. 이렇게 하면 다음에 요청이 있을 때 데이터를 더 빨리 검색할 수 있습니다.

캐시 적중률은 데이터가 캐시에 있고 만료되지 않은 경우에 발생합니다.

  1. 애플리케이션은 캐시에서 데이터를 요청합니다.

  2. 캐시는 애플리케이션으로 데이터를 반환합니다.

캐시 누락은 데이터가 캐시에 없거나 만료된 경우에 발생합니다.

  1. 애플리케이션은 캐시에서 데이터를 요청합니다.

  2. 캐시에 데이터가 요청되지 않으므로 null을 반환합니다.

  3. 애플리케이션은 데이터베이스에 데이터를 요청하고 수신합니다.

  4. 애플리케이션은 새 데이터로 캐시를 업데이트합니다.

지연 로딩의 장점 및 단점

지연 로딩의 장점은 다음과 같습니다.

  • 요청된 데이터만 캐싱됩니다.

    대부분의 데이터가 요청되지 않으므로 지연 로딩은 요청되지 않은 데이터가 있는 캐시를 채우지 않습니다.

  • 노드 장애가 애플리케이션에 치명적인 영향을 주지 않습니다.

    노드 장애가 발생하여 새로운 빈 노드로 대체될 경우 애플리케이션에서는 지연 시간 증가를 통해 계속 작동합니다. 새 노드에 대한 요청이 발생하면, 각 캐시가 누락될 때마다 데이터베이스 쿼리가 생성됩니다. 동시에 데이터 복사본이 캐시에 추가되어 이후의 요청이 캐시에서 검색됩니다.

지연 로딩의 단점은 다음과 같습니다.

  • 캐시 누락 패널티가 있습니다. 각 캐시 누락은 세 개의 이동으로 나타납니다.

    1. 캐시에서 데이터에 대한 초기 요청

    2. 데이터에 대한 데이터베이스의 쿼리

    3. 캐시에 데이터 작성

    이러한 누락으로 인해 애플리케이션으로 데이터를 가져오는 것이 눈에 띄게 지연될 수 있습니다.

  • 기한 경과된 데이터

    캐시 누락 시에만 데이터를 캐시에 쓰면, 캐시의 데이터가 기한이 경과할 수 있습니다. 이 결과는 데이터베이스에서 데이터가 변경될 때 캐시에 대한 업데이트가 없기 때문에 발생합니다. 이 문제를 해결하려면 라이트-스루TTL 추가 전략을 사용할 수 있습니다.

지연 로딩 유사 코드 예제

다음은 지연 로딩 로직의 의사(pseudo) 코드 예제입니다.

// ***************************************** // function that returns a customer's record. // Attempts to retrieve the record from the cache. // If it is retrieved, the record is returned to the application. // If the record is not retrieved from the cache, it is // retrieved from the database, // added to the cache, and // returned to the application // ***************************************** get_customer(customer_id) customer_record = cache.get(customer_id) if (customer_record == null) customer_record = db.query("SELECT * FROM Customers WHERE id = {0}", customer_id) cache.set(customer_id, customer_record) return customer_record

이 예제의 경우, 데이터를 갖는 애플리케이션 코드는 다음과 같습니다.

customer_record = get_customer(12345)

라이트-스루

라이트-스루 전략은 데이터베이스에 데이터를 작성할 때마다 데이터를 추가하거나 캐시의 데이터를 업데이트합니다.

라이트-스루의 장점 및 단점

라이트-스루의 장점은 다음과 같습니다.

  • 캐시의 데이터가 기한 경과되지 않습니다.

    캐시의 데이터는 데이터베이스에 쓰일 때마다 업데이트되므로 항상 최신 상태입니다.

  • 쓰기 패널티 vs. 읽기 패널티

    모든 쓰기에는 다음 2개의 이동이 수반됩니다.

    1. 캐시에 쓰기

    2. 데이터베이스에 쓰기

    이로 인해 프로세스에 지연 시간이 추가됩니다. 즉, 최종 사용자는 일반적으로 데이터를 검색할 때보다 데이터를 업데이트할 때 지연 시간에 더 관대합니다. 업데이트는 더 많이 작동하므로 오래 걸릴 수 있다는 고유한 생각이 있습니다.

라이트-스루의 단점은 다음과 같습니다.

  • 누락된 데이터

    노드 장애 또는 확장으로 인해 새 노드를 스핀업하면 데이터가 누락됩니다. 이 데이터는 데이터베이스에 추가되거나 업데이트될 때까지 계속 누락됩니다. 라이트-스루로 지연 로딩을 구현하여 이 문제를 최소화할 수 있습니다.

  • 캐시 이탈

    대부분의 데이터는 절대 읽히지 않으며 이는 리소스 낭비입니다. TTL(Time to Live) 값을 추가하면 낭비되는 공간을 최소화할 수 있습니다.

라이트-스루 의사 코드 예제

다음은 라이트-스루 로직의 의사(pseudo) 코드 예제입니다.

// ***************************************** // function that saves a customer's record. // ***************************************** save_customer(customer_id, values) customer_record = db.query("UPDATE Customers WHERE id = {0}", customer_id, values) cache.set(customer_id, customer_record) return success

이 예제의 경우, 데이터를 갖는 애플리케이션 코드는 다음과 같습니다.

save_customer(12345,{"address":"123 Main"})

TTL 추가

지연 로딩은 기한 경과 데이터에 대해 허용되지만 빈 노드로 인해 실패하지 않습니다. 라이트-스루는 데이터를 항상 최신 상태로 유지하지만, 빈 노드로 인해 실패할 수 있으며 불필요한 데이터로 캐시를 채울 수 있습니다. 각 쓰기에 TTL(Time to Live) 값을 추가하면 각 전략의 이점을 얻을 수 있습니다. 동시에 추가 데이터로 캐시를 복잡하게 만들지 않을 수 있습니다.

TTL(Time To Live)은 키가 만료될 때까지의 시간(초)을 지정하는 정수 값입니다. Valkey 또는 Redis OSS는 이 값에 대해 초 또는 밀리초를 지정할 수 있습니다. Memcached는 초 단위로 이 값을 지정합니다. 애플리케이션에서 만료된 키를 읽으려고 하면 키가 없는 것으로 처리됩니다. 데이터베이스가 키에 대해 쿼리되고 캐시가 업데이트됩니다. 이는 값이 기한 경과가 아님을 보장하지 않습니다. 그러나 데이터가 너무 기간 경과되지 않도록 방지하며, 경우에 따라 캐시의 값이 데이터베이스에서 새로 고침되어야 합니다.

자세한 내용은 Valkey 및 Redis OSS 명령 또는 Memcached set 명령을 참조하세요.

TTL 의사 코드 예제

다음 코드는 TTL을 통한 라이트-스루 로직의 의사(pseudo) 코드 예제입니다.

// ***************************************** // function that saves a customer's record. // The TTL value of 300 means that the record expires // 300 seconds (5 minutes) after the set command // and future reads will have to query the database. // ***************************************** save_customer(customer_id, values) customer_record = db.query("UPDATE Customers WHERE id = {0}", customer_id, values) cache.set(customer_id, customer_record, 300) return success

다음은 TTL을 통한 지연 로딩 로직의 의사(pseudo) 코드 예제입니다.

// ***************************************** // function that returns a customer's record. // Attempts to retrieve the record from the cache. // If it is retrieved, the record is returned to the application. // If the record is not retrieved from the cache, it is // retrieved from the database, // added to the cache, and // returned to the application. // The TTL value of 300 means that the record expires // 300 seconds (5 minutes) after the set command // and subsequent reads will have to query the database. // ***************************************** get_customer(customer_id) customer_record = cache.get(customer_id) if (customer_record != null) if (customer_record.TTL < 300) return customer_record // return the record and exit function // do this only if the record did not exist in the cache OR // the TTL was >= 300, i.e., the record in the cache had expired. customer_record = db.query("SELECT * FROM Customers WHERE id = {0}", customer_id) cache.set(customer_id, customer_record, 300) // update the cache return customer_record // return the newly retrieved record and exit function

이 예제의 경우, 데이터를 갖는 애플리케이션 코드는 다음과 같습니다.

save_customer(12345,{"address":"123 Main"})
customer_record = get_customer(12345)

관련 주제