데이터를 저장하고 검색하는 두 가지 방법을 알아봅니다. 애플리케이션에서 사용할 방법을 선택할 때는 데이터 액세스 패턴을 기준으로 아키텍처를 간소화할 수 있는 방법을 선택합니다.

먼저 Redis에 연결할 수 있는지 확인합니다.

모듈 완료 시간: 60분



4.1단계

(확대하려면 클릭)

4.1단계
4.2단계

(확대하려면 클릭)

4.2단계

예제에서 엔드포인트가 언급될 때마다 구성 엔드포인트의 호스트 이름을 사용해야 합니다.

4.3단계

(확대하려면 클릭)

4.3단계

구문: 셸

$ python

명령이 응답하지 않으면 다음 예제의 참고를 참조하십시오. 

구문: python

syntax: python
>>> import redis
>>> client = redis.Redis.from_url('redis://endpoint:6379')
>>> client.ping()

True

참고: 응답하지 않는 경우 보안 그룹 설정으로 인해 차단된 것입니다. EC2 인스턴스가 ElastiCache 인스턴스에 할당된 보안 그룹에 액세스할 수 있는지 확인합니다. 예를 들어 EC2 인스턴스가 기본 보안 그룹에 할당되어 있다고 가정해보겠습니다. 이제 Amazon ElastiCache 인스턴스의 보안 그룹을 수정하고 포트 6379에서 기본 보안 그룹의 모든 인스턴스로부터의 연결을 허용하는 맞춤형 TCP 규칙을 추가할 수 있습니다.

[소스]에 보안 그룹의 이름을 입력하기 시작하면 보안 그룹 ID를 클릭할 수 있습니다. 보안 그룹에 대해 자세히 알아보아야 하는 경우 설명서 또는 보안 그룹 규칙 참조를 참조하면 됩니다.

4.5단계

(확대하려면 클릭)

4.5단계

리포지토리에는 EC2 인스턴스에서 실행할 수 있는 Python 코드가 있습니다. 하지만 먼저 환경 변수를 몇 가지 구성해야 합니다.

구문: 셸

$ export REDIS_URL=redis://your_redis_endpoint:6379/
$ export DB_HOST=your_mysql_endpoint
$ export DB_USER=admin
$ export DB_PASS=your_admin_password
$ export DB_NAME=tutorial

mysql_endpoint, redis_endpoint의 값과 암호는 이전 단계에서 저장한 것들입니다.


코드 샘플에 구현된 처음 두 가지 메서드는 SQL 쿼리 결과의 직렬화된 표현을 캐싱하는 방식으로 작동합니다. 다음 Python 조각은 이 로직을 보여 줍니다.

구문: python

def fetch(sql):

  result = cache.get(sql)
  if result:
    return deserialize(result)
  else:
    result = db.query(sql)
    cache.setex(sql, ttl, serialize(result))
    return result

먼저 이 SQL 문이 Redis의 키로 사용되며 값이 있는지 확인하기 위해 캐시가 조사됩니다. 값이 있는 경우 이 SQL 문이 데이터베이스를 쿼리하는 데 사용됩니다. 데이터베이스 쿼리의 결과가 Redis에 저장됩니다. 애플리케이션의 성격에 따라 ttl 변수를 적절한 값으로 설정해야 합니다. ttl이 만료되면 Redis가 키를 제거하고 관련 메모리를 확보합니다. 이 코드는 자습서 리포지토리에 있고 그대로 실행할 수 있지만, 특정 시점의 변수 값을 확인하려는 경우 원하는 위치에 print 문을 자유롭게 추가할 수 있습니다.

전략의 관점에서 보면, 이 방식은 이전 결과가 캐싱되고 ttl이 아직 경과하지 않은 경우에 데이터베이스의 데이터가 수정될 때 변경 내용이 사용자에게 자동으로 반영되지 않는다는 단점이 있습니다.

다음은 fetch 함수를 사용하는 방법을 보여 주는 예입니다.

구문: python

print(fetch("SELECT * FROM planet"))

결과는 다음과 같습니다.

구문: python

[{'id': 10, 'name': 'Mercury'},
 {'id': 11, 'name': 'Venus'},
 {'id': 12, 'name': 'Earth'},
 {'id': 13, 'name': 'Mars'},
 {'id': 14, 'name': 'Jupiter'},
 {'id': 15, 'name': 'Saturn'},
 {'id': 16, 'name': 'Uranus'},
 {'id': 17, 'name': 'Neptune'}]

물론 이는 매우 기본적인 예지만, 캐시에서 가져오는 결과와 데이터베이스에서 직접 가져오는 결과가 서로 차이가 없는 경우 이 캐싱 패턴을 구현하면 애플리케이션에 큰 이점이 있습니다.


구현할 두 번째 예는 데이터베이스 레코드를 Redis 해시에 매핑합니다.

구문: python

def planet(id):

  key = "planet:" + str(id)
  result = cache.hgetall(key)

  if result:
      return result

  else:
      sql = "SELECT `id`, `name` FROM `planet` WHERE `id`=%s"
      result = db_record(sql, (id,))

      if result:
          cache.hmset(key, result)
          cache.expire(key, ttl)
      return result

Redis의 키 공간은 한정적이지만 콜론으로 구분된 문자열로 구조를 시뮬레이션하는 규칙이 있습니다. 이 예에서 ID가 1인 레코드의 키는 “planet:1”이 됩니다. 이 조각은 일반적인 패턴을 잘 보여주지만 더 추상화할 수도 있습니다. 즉, 모듈 중 하나에서 키를 생성하고 다른 모듈에서 SQL 문자열 작성을 처리하는 등의 방식으로 구현할 수 있습니다. 또한 사용하는 프로그래밍 언어에 이 용도로 툴이 구축되어 있는 경우가 많습니다.
이 예제는 캐시 또는 데이터베이스에서 레코드를 검색하며, 마찬가지로 객체를 데이터베이스에 유지하는 함수가 있을 수도 있습니다.


이 2개의 예제에서는 TTL(Time To Live)을 사용했는데, 이 시간이 경과하고 나면 키가 제거됩니다. 대부분의 경우 이 방법으로 충분하지만 오래된 데이터를 최대한 빨리 제거해야 하는 경우도 있습니다. 이 같은 사용 사례에서는 라이트 스루 캐싱 전략과 같은 다른 옵션을 고려해야 합니다. 이 자습서의 마지막에 있는 링크에서 자세한 내용을 참조할 수 있습니다. 궁금하신 분들을 위해 설명하자면, 이 예제들은 EXPIRE 명령을 사용하지만 Redis는 키를 제거해야 하는 정확한 날짜와 시간을 지정할 수 있는 EXPIREAT 명령도 제공합니다. 이 명령은 절대 Unix 타임스탬프(1970년 1월 1일부터의 경과 시간(초))를 파라미터로 받습니다.


데이터의 양이 구성된 maxmemory 설정을 초과하는 경우 Redis는 선택한 제거 정책에 따라 다른 방식으로 대응합니다. 기본적으로 ElastiCache for Redis는 설정된 ttl을 기준으로 사용된 지 가장 오래된 키를 메모리에서 제거하도록 구성됩니다. 이 제거 정책 파라미터를 maxmemory-policy라고 하며 ElastiCache의 기본값은 volatile-lru입니다. 이 사용 사례에 적용되는 다른 흥미로운 옵션으로 ttl이 가장 짧은 키를 제거하여 메모리를 재확하도록 Redis에 지시하는 volatile-ttl이 있습니다.


이 전략을 구현한 후에는 애플리케이션을 테스트하여 최적의 ttl 값과 최적의 제거 전략을 찾아야 합니다. 빈 캐시와 전체 캐시를 사용하여 애플리케이션의 성능을 확인합니다.