Redis Clients PHPREDIS

Redis Developer Course Redis Technical Support Redis Enterprise Server

Redis Clients PHPREDIS

Phpredis는 PHP 레디스 클라이언트입니다.   이 글은 주로 phpredis와 레디스 클러스터 테스트를 다룹니다.

이 문서는 버전 3.2.0을 기준으로 만들었습니다.

목차


테스트 준비: 레디스 클러스터 설치, PHP 소스

레디스 클러스터 설치

  • 마스터: 7000, 7001, 7002
  • 슬레이브: 7003, 7004, 7005
  • 서버 설치 디렉토리: /root/redis-3.2.0/ 아래에 7000 ~ 7005
  • redis.conf에서 수정한 내용: port와 dir은 7000 ~ 7005에 맞게 수정하세요.
    각 디렉토리 아래에 redis.conf만 남기고 다른 파일은 지워주세요.
  • port   7000
    dir   "/root/redis-3.2.0/7000"
    cluster-enabled   yes
    cluster-config-file   nodes.conf
    cluster-node-timeout   3000
  • 레디스 서버 시작 쉘 스크립트
  • 레디스 클러스터 시작 쉘 스크립트
  • 레디스 서버 종료 쉘 스크립트
  • 레디스 클러스터를 설치하는 자세한 방법은 레디스 클러스터 소개를 참고하세요.

PHP 소스 설명

PHP에서 레디스 클러스터에 접속해서 SET 명령으로 key1 ~ key6까지 입력하고, get 명령으로 값을 가져온다.

  • 클러스터 접속: $cluster = new RedisCluster(IP:Port, ...)
  • 입력 SET: $cluster->set("key1","value1")
  • 조회 GET: $cluster->get("key1")

PHP 소스





Phpredis 클러스터 테스트

테스트 케이스


Case1) 정상 상태인 경우

서버 시작 쉘 스크립트로 6개 서버를 시작하고, 클러스터 시작 쉘 스크립트로 클러스터를 구성한다.
웹 브라우저에서 테스트 페이지를 실행했다.   아래는 실행 결과 화면을 캡처한 것이다.

phpredis cluster test
    그림 1-1   PhpRedis Redis Cluster 테스트 결과 화면

RedisCluster()를 실행하면 Phpredis에서 IP와 Port를 이용해서 클러스터 정보 읽어와서 phpredis에 저장한다.   클러스터 정보는 서버가 마스터인지 슬레이브인지, 각 마스터에 할당된 슬롯 정보 등이다.
Phpredis는 레디스 서버와 동일한 해시 함수를 가지고 있어서 입력받은 키(key)를 슬롯 번호로 변환한다.   그리고 가지고 있는 글러스터 정보와 비교해서 어느 서버에 저장할지 정한다.   그래서 $cluster->set() 명령을 실행하면 어느 서버로 저장할지 개발자가 지정하지 않아도 phpredis가 알아서 저장한다.

키 할당 내역

7000번 서버 : key2, key3, key6
7001번 서버 : key1, key5
7002번 서버 : key4


Case2) 마스터 서버 하나가 다운될 경우

  • 3번 서버 7002을 redis-cli로 shutdown 시킨다.
  • [redis-3.2.0]# src/redis-cli -p 7002 shutdown
  • 다운 직후 테스트 페이지를 실행하면 key1,2,3번은 입력되고 key4에서 에러가 난다.
  • phpredis cluster test error
        그림 1-2   PhpRedis Redis Cluster 마스터 서버 다운 직후 테스트 결과 화면
  • 잠시 후에 다시 시도하면 key1 부터 key6까지 에러없이 입력된다.
  • 레디스 클러스터에서 7002번이 다운되었다는 것을 인지하고, 슬레이브인 7005번 서버가 마스터로 승격되는 시간은 cluster-node-timeout 파라미터 설정에 따라 다르다.   디폴트는 15초이고, 본 테스트에서는 3초로 설정했다.
  • 이렇게 변경된 레디스 클러스터 정보를 phpredis가 읽어와서 적용하는 시간이 소요되고, 적용 후에는 에러 없이 정상적으로 처리된다.
  • 정리하면, 마스터 다운 시 정상적으로 복구되었다면 phpredis도 해당 정보를 읽어와서 정상적인 처리를 한다.

Case3) 마스터 서버 하나의 모든 슬롯을 다른 서버로 재 할당(resharding)한 경우

현재 레디스 클러스터 상태

마스터 3대: 7000, 7001, 7005
슬레이브 2대: 7003, 7004
다운 1대: 7002

  • 7005번에 할당된 슬롯 5461개 모두 7001번 서버로 옮긴다.
    재 할당 과정은 아래에 있다.   일부분은 생략하고 표시했다.
  • [redis-3.2.0]# src/redis-trib.rb reshard 127.0.0.1:7000
    >>> Performing Cluster Check (using node 127.0.0.1:7000)
    [OK] All nodes agree about slots configuration.
    >>> Check for open slots...
    >>> Check slots coverage...
    [OK] All 16384 slots covered.
    How many slots do you want to move (from 1 to 16384)? 5461
    What is the receiving node ID? 0329febf0f3bd63d0705acd5a11ecfd24f64f5d6
    Please enter all the source node IDs.
    Type 'all' to use all the nodes as source nodes for the hash slots.
    Type 'done' once you entered all the source nodes IDs.
    Source node #1:9de12c4b911a634946be8c7b171fd56c94b66066
    Source node #2:done
    Do you want to proceed with the proposed reshard plan (yes/no)? yes
  • 7005번에 있는 'key4'도 7001번 서버로 옮겨갔다.
  • 테스트 페이지를 실행하면 레디스 클러스터에 접속할 때 에러가 난다.
  • phpredis cluster test error
        그림 1-3   PhpRedis Redis Cluster 슬롯 이동 후 테스트 결과 화면
  • 테스트 결과로 보면, 슬롯을 하나도 가지고 있지 않은 서버가 있으면 phpredis에서 레디스 클러스터에 접속 시 에러가 난다.   [하지만 이것은 사실이 아닙니다. 조금 더 읽어 보세요.]
  • 다음은 cluster nodes 명령으로 본 클러스터 정보이다.   일부 데이터는 생략하고 간추려 표시했다.
    7000과 7001 서버에만 슬롯이 할당되어 있다.
    * 7002는 shutdown된 상태지만 아직 클러스터 정보에는 남아 있다.
  • 127.0.0.1:7000> cluster nodes
    127.0.0.1:7000 myself,master - 0-5460
    127.0.0.1:7001 master - 5461-16383
    127.0.0.1:7002 master,fail
    127.0.0.1:7003 slave
    127.0.0.1:7004 slave
    127.0.0.1:7005 master
  • cluster info 명령으로 보면 상태도 OK이지만,   cluster_size가 2이다.   cluster_size는 마스터 서버의 개수가 아니고 슬롯이 할당된 마스터 서버의 개수이다.
  • 127.0.0.1:7000> cluster info
    cluster_state:ok
    cluster_slots_assigned:16384
    cluster_slots_ok:16384
    cluster_slots_pfail:0
    cluster_slots_fail:0
    cluster_known_nodes:6
    cluster_size:2
  • 사실은 슬롯을 가지고 있는 마스터 서버가 2대 이하면 phpredis는 접속 시 에러를 낸다.
    즉, cluster_size가 3 이상이어야 정상적으로 처리된다.
  • 7005번 서버에 슬롯 하나만 재 할당하면 어떻게 될까?   당연히 슬롯을 가지고 있는 마스터 서버가 3대이므로 에러 없이 처리된다.

Case4) 마스터 서버 한 대를 추가하고 슬롯을 재 할당(resharding)한 경우

이전에 shutdown 시켰던 7002 서버를 클러스터에서 제거한 후 다시 새 마스터로 추가한다.

  • 클러스터에서 제거: cluster forget node-id 명령으로 제거한다.   이 명령은 한 노드에서만 실행하면 안 되고, 마스터, 슬레이브 관계없이 클러스터 모든 노드에서 해야 한다.
    이때는 redis-trib del-node를 사용할 수 없다.   왜냐하면 del-node는 서버가 살아있을 때만 가능하다.
  • [redis-3.2.0]# src/redis-cli -p 7000 cluster forget 7d04151b254222...14e2fecd
    [redis-3.2.0]# src/redis-cli -p 7001 cluster forget 7d04151b254222...14e2fecd
    [redis-3.2.0]# src/redis-cli -p 7003 cluster forget 7d04151b254222...14e2fecd
    [redis-3.2.0]# src/redis-cli -p 7004 cluster forget 7d04151b254222...14e2fecd
    [redis-3.2.0]# src/redis-cli -p 7005 cluster forget 7d04151b254222...14e2fecd
  • 7000번 서버를 재 시작하기 전에 7000 디렉터리 아래에 redis.conf 만 남기고 nodes.conf, appendonly.aof 같은 다른 파일은 모두 삭제한다.
  • 서버를 재 시작한다.
  • [redis-3.2.0]# src/redis-server 7002/redis.conf
  • 클러스터에 서버를 추가한다.
  • [redis-3.2.0]# src/redis-trib.rb add-node 127.0.0.1:7002 127.0.0.1:7000
  • 7001번 서버에서 7002번 서버로 슬롯 500개를 할당한다.
  • [redis-3.2.0]# src/redis-trib.rb reshard 127.0.0.1:7000
  • 테스트 페이지를 실행하면 정상적으로 수행된다.   슬롯이 할당된 마스터가 3대이므로 문제가 없다.
  • 정리하면 노드 추가 시 phpredis에서 정상적으로 처리한다.   하지만, 노드 추가, 슬롯 할당 작업과 phpredis에서 변경된 클러스터 정보 업데이트 시간이 필요하므로 정비 시간을 가지고 처리할 것을 권고합니다.

Case5) 마스터 서버 한 대를 제거한 경우

이번에는 7000 서버를 클러스터에서 제거한다.   클러스터에서 제거할 노드가 슬롯을 가지고 있으면 제거되지 않으므로, 7000번 서버가 가지고 있는 슬롯을 7005번 노드에 재 할당한다.

  • 슬롯 재 할당
  • [redis-3.2.0]# src/redis-trib.rb reshard 127.0.0.1:7000
  • 노드 제거
  • [redis-3.2.0]# src/redis-trib.rb del-node 127.0.0.1:7001 ba84a1d44...7f2971
  • 테스트 페이지를 실행하면 정상적으로 처리된다.

테스트 정리

슬롯이 할당된 마스터 서버가 2대 이하인 경우를 제외하고는 모든 테스트 케이스에서 개발자가 특별히 해 주어야 할 것 없이 정상적으로 처리되었다.

  • 현재 레디스 클러스터 상태
  • 127.0.0.1:7001   myself,master - 5961-16383
    127.0.0.1:7002   master - 5461-5960
    127.0.0.1:7003   slave of 7005
    127.0.0.1:7004   slave of 7001
    127.0.0.1:7005   master - 0-5460

접속 테스트

RedisCluster()로 접속할 때 위 테스트 소스처럼 클러스터의 모든 IP:Port를 지정하지 않아도 된다.
마스터, 슬레이브 관계없이 하나만 지정해도 된다.   여러개를 지정해도 첫 번째 지정한 노드에서 클러스터 정보를 얻어오는 것으로 보인다.   그런데 이렇게 하나만 지정하면 그 서버가 다운되었을 경우에는 접속할 수 없게 되므로 가능한 모든 노드를 지정하는 것이 좋다.
현재 없는 노드를 지정해도 된다.

  • 마스터 하나만 저장한 경우:
  • $cluster = new RedisCluster(NULL, Array('127.0.0.1:7000'));
  • 슬레이브 하나만 저장한 경우:
  • $cluster = new RedisCluster(NULL, Array('127.0.0.1:7004'));
  • 현재 없는 노드를 저장한 경우: 이 경우, 첫 번째 지정한 노드에서 클러스터 정보를 읽어오므로 두 번째 지정한 노드는 접속에 영향을 미치지 않는다.
  • $cluster = new RedisCluster(NULL, Array('127.0.0.1:7000', '155.55.55.55:8000'));
  • 현재 없는 노드를 첫 번째로 지정한 경우: 이 경우는 첫 번째 노드가 접속이 안된다는 것을 알고, 두 번째 노드에 접속해서 정보를 얻어오기까지 시간이 걸린다.
  • $cluster = new RedisCluster(NULL, Array('155.55.55.55:8000', '127.0.0.1:7000'));
  • 접속 시간 timeout, 읽기 timeout 설정: IP:Port 다음에 첫 번째 파라미터 2가 접속 시간 timeout이고 두 번째 파라미터 2가 읽기 timeout이다.
  • $cluster = new RedisCluster(NULL, Array('127.0.0.1:7000', '127.0.0.1:7001'), 2, 2);


조회 명령은 슬레이브 노드에서 처리하는 방법

PhpRedis는 옵션으로 조회 명령을 어느 노드에서 처리할지 선택할 수 있습니다.

  • 디폴트는 모든 명령을 마스터 노드에서만 처리하는 것입니다.
    The default option, only send commands to master nodes
  • $cluster->setOption(RedisCluster::OPT_SLAVE_FAILOVER, RedisCluster::FAILOVER_NONE);
  • 마스터에 접속할 수 없지만 슬레이브가 있다면 조회 명령은 슬레이브에서 처리합니다.
    In the event we can't reach a master, and it has slaves, failover for read commands
    하지만 이 명령은 마스터가 살아있으면 조회 명령도 마스터에서 처리하고, 마스터가 다운되었고 아직 Failover가 되지 않은 상태라면 GET 명령도 에러가 납니다.   이후 Failover 되어서 슬레이브가 마스터가 되면 정상 처리됩니다.   처리 결과를 보면 설명과 다르게 동작합니다.
    $obj_cluster->setOption(RedisCluster::OPT_SLAVE_FAILOVER, RedisCluster::FAILOVER_ERROR);
  • 조회 명령을 랜덤하게 마스터와 슬레이브에서 처리합니다.
    Always distribute readonly commands between masters and slaves, at random
    $obj_cluster->setOption(RedisCluster::OPT_SLAVE_FAILOVER, RedsiCluster::FAILOVER_DISTRIBUTE);

PhpRedis 공식 홈페이지 설명에는 첫 번째 옵션이 OPT_FAILOVER으로 되어 있는데,   실제는 OPT_SLAVE_FAILOVER 입니다.  


PhpRedis 테스트

여기서는 레디스 서버에 IP와 Port를 직접 지정해서 접속하는 방법을 설명한다.
이것은 클러스터를 사용하지 않고 단독 서버를 사용할 경우와 클러스터를 사용해도 INFO 같은 서버 명령은 특정 서버에 접속해서만 실행할 수 있기 때문이다.

  • 직접 접속 방법과 명령 실행
  • $redis = new Redis();
    $redis->connect('127.0.0.1',7001,2);
    $redis->ping();
  • PHP 소스

PhpRedis 설치

php-devel 설치

사전에 php-devel이 설되어 있어야 한다.
설치 확인: rpm -qa | grep php-devel
설치: yum install php-devel

PhpRedis 설치

설치 명령 요약

phpize
./configure [--enable-redis-igbinary]
make && make install

진행과정

  • 여기서 phpredis-develop.zip을 다운받는다. https://github.com/phpredis/phpredis
  • 디렉토리 확인과 압축해제

  • 디렉토리 이동과 파일 확인
  • phpize
  • configure
  • make & make install


  • PhpRedis에 대한 더 자세한 내용은 PhpRedis 공식 홈 페이지를 참고하세요.


  • << StackExchange.Redis Cluster PHPREDIS Enterprise >>

    Email 답글이 올라오면 이메일로 알려드리겠습니다.