본문 바로가기
DBMS

Redis Cluster 예제 app (ruby, python)

by developer's warehouse 2024. 5. 30.

Redis 클러스터를 설치한 후 몇 가지 예제 애플리케이션을 만들거나 최소한 간단한 Redis 클러스터 클라이언트와 어떻게 동작하는지 이해해야 어떤 작업이든 진행할 수 있습니다.

이 글에서는 Redis Cluster 애플리케이션 예제를 간단하게 알아보고 동작시켜보도록 하겠습니다.

나중에 노드 장애를 일으키거나 데이터를 재배치하는 리샤딩을 시작하여 실제 조건에서 Redis Cluster가 어떻게 작동하는지 확인할 수 있습니다. 클러스터에 아무 작업이 없는 상태에서 어떤 일이 일어나는지 확인하는 것은 별로 도움이 되지 않습니다.

 연관 글 보기
 Redis Cluster 쓰려면 어떤걸 설치 해야하지? - Redis OSS와 Stack의 차이 및 라이선스 그리고 Cluster는?
Redis Cluster 리눅스에 설치하고 테스트 하기
Redis Cluster 예제 app (ruby, python)
Redis Cluster 리샤딩으로 데이터 조정하기 - Resharding

 

예제를 통해 redis-rb-cluster app의 기본적인 사용법을 설명합니다. 오늘은 단순 예제인 example.rp와 이를 python으로 바꾼 example.py만 확인해 보도록 하겠습니다.

Redis Cluster 예제 app (ruby, python) 썸네일

Ruby 단순 예제 ( example.rb )

첫 번째 예제는 다음과 같으며, github에 있는 redis-rb-cluster 내에 있는 example.rb 파일입니다.

먼저 아래와 같이 git clone을 통해서 예제 프로그램을 레디스 클러스터가 설치된 혹은 로컬 장비에 다운받습니다.

% git clone https://github.com/antirez/redis-rb-cluster
'redis-rb-cluster'에 복제합니다...
remote: Enumerating objects: 153, done.
remote: Total 153 (delta 0), reused 0 (delta 0), pack-reused 153
오브젝트를 받는 중: 100% (153/153), 27.65 KiB | 5.53 MiB/s, 완료.
델타를 알아내는 중: 100% (73/73), 완료.
% ls
README.md cluster.rb consistency-test.rb crc16.rb example.rb

 

파일 중 example.rb를 Ruby로 작성한 redis cluster에 접속해서 간단한 데이터를 set/get 하는 예제입니다.

   1  require './cluster'
   2
   3  if ARGV.length != 2
   4      startup_nodes = [
   5          {:host => "127.0.0.1", :port => 7000},
   6          {:host => "127.0.0.1", :port => 7001}
   7      ]
   8  else
   9      startup_nodes = [
  10          {:host => ARGV[0], :port => ARGV[1].to_i}
  11      ]
  12  end
  13
  14  rc = RedisCluster.new(startup_nodes,32,:timeout => 0.1)
  15
  16  last = false
  17
  18  while not last
  19      begin
  20          last = rc.get("__last__")
  21          last = 0 if !last
  22      rescue => e
  23          puts "error #{e.to_s}"
  24          sleep 1
  25      end
  26  end
  27
  28  ((last.to_i+1)..1000000000).each{|x|
  29      begin
  30          rc.set("foo#{x}",x)
  31          puts rc.get("foo#{x}")
  32          rc.set("__last__",x)
  33      rescue => e
  34          puts "error #{e.to_s}"
  35      end
  36      sleep 0.1
  37  }

 

위의 코드를 실행하기 위해서는 ruby의 redis 라이브러리를 설치해야하는데 다음 명령로 설치하실 수 있습니다.

gem install redis

위의 코드는 매우 간단한 작업을 수행합니다. foo<number> 형식의 키를 차례로 숫자로 설정합니다. 따라서 프로그램을 실행하면 다음과 같은 명령 스트림이 생성됩니다:

SET foo0 0

SET foo1 1

SET foo2 2

....

 

이 프로그램은 예외로 종료하는 대신 화면에 오류를 표시하도록 설계되었기 때문에 클러스터로 수행되는 모든 작업이 begin rescue 블록으로 래핑되므로 더 복잡해 보입니다.

14 라인에서는 시작 노드 목록, 이 객체가 다른 노드에 대해 허용되는 최대 연결 수, 마지막으로 주어진 작업이 실패한 것으로 간주되는 시간(timeout)을 인수로 사용하여 Redis 클러스터 개체를 생성합니다.

시작 노드가 클러스터의 모든 노드일 필요는 없습니다. 중요한 것은 적어도 하나의 노드에 연결할 수 있어야 한다는 것입니다. 또한 redis-rb-cluster는 첫 번째 노드에 연결할 수 있는 즉시 이 시작 노드 목록을 업데이트합니다. 다른 클라이언트에서도 이러한 동작을 예상해야 합니다.

이제 rc 변수에 Redis 클러스터 객체 인스턴스가 저장되었으므로, 일반 Redis 객체 인스턴스처럼 사용할 준비가 되었습니다.

 

18~26 라인

예제를 다시 시작할 때 foo0으로 다시 시작하고 싶지 않기 때문에 카운터를 Redis 자체에 저장합니다. 위의 코드는 이 카운터를 읽거나, 카운터가 존재하지 않는 경우 0 값을 할당하도록 설계되었습니다.

 

그러나 클러스터가 다운되어 오류를 반환하는 경우에도 계속 반복해서 시도해야 하므로 루프로 동작합니다. 일반 애플리케이션은 이렇게 작성할 필요가 없습니다.

 

28~37라인

키가 설정되거나 오류가 표시되는 메인 루프가 시작되는 곳입니다.
루프가 끝날 때 sleep 으로 잠시 쉽니다. 테스트에서 클러스터에 최대한 빨리 쓰고 싶다면 sleep을 제거할 수 있습니다.

 

이 예제를 실행하면 다음과 같습니다.

ruby ./example.rb
1
2
3
4
5
6
7
8
9
^C

 

이 예제를 통해서 간단하게 예제 Redis Cluster app을 만들어 보았습니다.

다음에 이 예제를 돌리면서 데이터를 재분배하는 reshard 명령을 실행해 보도록 하겠습니다.

 

Python 단순 예제 ( example.py )

위의 코드는 레디스 공식 홈페이지에 나와있는 예시입니다. 하지만, 저는 파이썬으로 레디스 클러스터 사용 코드를 만들어 보고 싶습니다.

 

다음과 같이 동일한 파이썬 코드를 작성할 수 있습니다.

% cat example.py
import time

from rediscluster import RedisCluster

# Redis cluster conf
startup_nodes = [
    {"host": "127.0.0.1", "port": "30001"},
    {"host": "127.0.0.1", "port": "30002"},
    {"host": "127.0.0.1", "port": "30003"}
]

# Redis Cluster Connect
rc = RedisCluster(startup_nodes=startup_nodes, decode_responses=True)

last = False

while not last:
    try:
        last = rc.get("__last__")
        if not last:
            last = 0
    except Exception as e:
        print(f"error {str(e)}")
        time.sleep(1)

for x in range(int(last)+1, 1000000001):
    try:
        rc.set(f"foo{x}", x)
        print(rc.get(f"foo{x}"))
        rc.set("__last__", x)
    except Exception as e:
        print(f"error {str(e)}")
    time.sleep(0.1)

 

이를 위해서 pip로 redis-py-cluster 모듈을 설치해야합니다.

% pip install redis-py-cluster
Defaulting to user installation because normal site-packages is not writeable
Collecting redis-py-cluster
  Downloading redis_py_cluster-2.1.3-py2.py3-none-any.whl (42 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 42.6/42.6 KB 2.0 MB/s eta 0:00:00
Collecting redis<4.0.0,>=3.0.0
  Downloading redis-3.5.3-py2.py3-none-any.whl (72 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 72.1/72.1 KB 12.7 MB/s eta 0:00:00
Installing collected packages: redis, redis-py-cluster
  Attempting uninstall: redis
    Found existing installation: redis 5.0.3
    Uninstalling redis-5.0.3:
      Successfully uninstalled redis-5.0.3
Successfully installed redis-3.5.3 redis-py-cluster-2.1.3

 

위의 코드를 실행하면 ruby와 동일하게 동작합니다.

 

facebook twitter kakaoTalk kakaostory naver band shareLink