Redis로 빠르고 가벼운 웹어플리케이션 만들기

이 글은 http://dev.kthcorp.com/2011/07/28/redis-buildingfast-lightweight-webapp/ 의 백업 이다
———————————————————-

by kth 기술전략팀 박민우

고가용성을 요구하는 시스템에서 수많은 request를 디스크 I/O 없이 빠르게 처리하기 위해서 in-memory key-value store (또는 in-memory key-value DB)가 각광받고 있습니다. 그 중 가장 널리 쓰이는 memcached 가 Twitter, Facebook, Wikipedia 등의 사이트에서 사용되며 유명해졌고 최근에는 Redis가 더 많은 기능과 다양한 data type 지원 등을 무기로 github, craigslist, blizzard, digg 등의 커다란 레퍼런스를 확보하며 좋은 평가를 받고 있습니다.

Redis 는 vmware 가 지원하고 있는 오픈소스(BSD 라이센스) 프로젝트로서 2009년도에 발표되었습니다. 메모리를 주 저장영역으로 사용하고 디스크는 보조적으로만 지원하며, key-value 형식의 데이터 저장을 지원합니다. 최근 각광받고있는 node.js에서도 사용할 수 있는 등 다양한 언어를 지원하며 ANSI C 로 되어있어 포팅이 용이하기 때문에 언어의 제약은 없다고 할 수 있습니다. 속도는 버전 2.0대로 진입하면서 많은 개선이 되어서 memcached 보다 조금 더 빠르거나 비슷한 정도라고 알려져 있습니다. Memcached 에서 replication 을 지원하기 위해서는 별도의 패치를 해야 하는 반면, Redis는 기본적으로 vertical, horizontal replication 을 지원하여 확장이 용이하다는 장점을 가지고 있습니다.

Redis를 사용하기 위해 기존DB를 Redis로 완전히 갈아 탈 수 있기때문에 특정한 기능을 위해서나 쓰기속도 등을 위해 실제로 많은 사람들이 Redis를 주 DB로 사용하고 있습니다. 하지만 Redis는 기본적으로는 메모리보다 더 많은 data set 을 저장할 수 없기 때문에 커다란 데이타를 저장해야 하는 경우에 적합하지 않습니다. Redis를 보조적으로 사용하면서 속도문제를 개선하고, 예전에는 불가능 했던 새로운 것을 하거나 오래된 문제들을 해결하는 데에 사용할 수 있습니다. Redis를 기존환경에 추가하여 Redis의 장점을 취한 사례를 몇 가지 소개해 드리도록 하겠습니다.

1. 홈페이지에서 최근 글 보여주기

SELECT * FROM foo WHERE … ORDER BY time DESC LIMIT 10
와 같은 쿼리 익숙하지 않나요?

“사용자에의해 추가된 최근 아이템” 등과 같은 최근 item을 보여주어야 하는 일은 웹 어플리케이션에서 매우 자주 발생합니다. 우리가 최근 20개의 댓글을 보여주고 싶은 웹 어플리케이션이 있다고 가정하겠습니다. 근처에는 20개 이상의 글을 보고싶은 사람들을 위한 “모두보기” 링크가 있고, “모두보기” 페이지에는 페이징을 보여주는 부분이 있어서 페이지를 이동하며 전체 댓글을 볼 수 있습니다.

아래와 같은 쿼리로 첫페이지와 “전체보기” 페이지를 만들 수 있습니다.

댓글이 입력될 때마다 id를 Redis list에 추가한다.
LPUSH latest.comments <ID>

Redis가 5000 개의 글만 가지도록 특정길이 이상은 잘라 없앤다.
LTRIM latest.comments 0 5000

글이 필요할 때마다 아래와 같이 가져올 수 있다. (pseudo 코드)

FUNCTION get_latest_comments(start,num_items):
id_list = redis.lrange("latest.comments",start,start+num_items-1)
IF id_list.length < num_items
id_list = SQL_DB("SELECT ... ORDER BY time LIMIT ...")
END
RETURN id_list
END

 

이렇게 Redis를 사용해 최신의 cache 를 유지할 수 있습니다. Start/count 파라메터가 Redis 가 저장하고있는 범위를 벗어날 떄에만 주DB에 직접 접근하기 때문에 메인페이지나 댓글 첫페이지에서는 절대 주DB에 접근할 일이 없습니다.
삭제가 필요할 시에는 LREM 명령으로 코멘트를 쉽게 삭제할 수 있습니다.

2. 최신 item의 랭킹 관리하기 (게임 / 뉴스 등)

  • 현재 게임의 랭킹 순위를 100등까지 보여주기
  • 현재 user 의 순위가 몇 등인지 보여주기
  • 인기뉴스 페이지 관리하기

와 같은 작업을 Redis를 이용하면 매우 쉽게 관리할 수 있습니다.

유저가 점수를 땄을 때에는

ZADD leaderboard <score> <username>
(leaderboard 가 key 입니다)

와 같이 데이터를 쌓은후,

100등까지의 순위를 보여주려면
ZREVRANGE leaderboard 0 99

특정 user 의 순위를 보여주려면
ZRANK leaderboard <username>

과 같이 쉽게 해결할 수 있습니다.

이 방법은 조금 응용하여 인기 뉴스기사를 보여주는데 등에도 응용될 수 있습니다. 최신 뉴스기사 1000개를 리스트에 유지하면서 (LPUSH + LTRIM 사용) 그 결과를 사용하여 ZADD를 하면서 인기뉴스의 목록을 관리하는데 응용할 수 있는 등 응용 방법은 무궁무진 합니다.

3. 기타 기능들

최신기사들만 뉴스 메인페이지에 보여주는 서비스 등을 위해서는 Redis 의 EXPIRE 기능을 사용해서 특정 시간이 지나면 item이 자동으로 지워지도록 할 수도있고 unix timestamp 를 value로 가지는 리스트에서 ZRANGE … WITHSCORES 로 최신글만 유지하고 나머지는 지우도록 할 수도 있습니다.

Redis는 유용한 counter 관련 함수들을 가지고 있습니다. 또한 Redis의 atomic 한(원자성을 보장하는) 카운터 함수들을 사용하여 카운터를 빠르게 관리하고, expire 를 이용하여 특정시간후에는 만료시키는 등의 작업을 할 수 있습니다.

이외에도 Stack 과 Queue 관리, 캐싱이나 자동완성(auto-complete) 기능구현, Pub/Sub 기능, 데이터베이스에 부하가 가기 때문에 하기 힘들었던 다양한 통계나 스팸관리 기능 등을 부하없이 빠르게 구현하는 데에 Redis를 사용하실 수 있습니다. 이외에도 Redis의 응용방법은 무궁무진 하다고 할 수 있습니다. 더 가볍고 빠른 서비스를 구현하는데 Redis의 다양한 기능과 data 형식을 응용해 보시기 바랍니다.

레퍼런스

  1. How to take advantage of Redis just adding it to your stack
    http://antirez.com/post/take-advantage-of-redis-adding-it-to-your-stack.html
  2. Redis 홈페이지
    http://redis.io/
  3. Browser 에서 직접 따라하는 Redis tutorial
    http://try.redis-db.com/
  4. Redis와 memcached 의 속도 벤치마크 (memcached 가 더 빠르다는 벤치마크에 대한 반박글)
    http://antirez.com/post/redis-memcached-benchmark.html
  5. In-memory database 소개
    http://www.mcobject.com/in_memory_database

  1. […] 인증이 구현되었다면 다음은 Redis를 설치해야 합니다. Redis에 대해서는 여기에 잘 설명되어 있습니다. config/cable.yml 파일에서 Redis가 아닌 MySQl이나 […]

Leave a Reply

Your email address will not be published. Required fields are marked *