Database/Redis

[Redis] Jedis 에서 Redis Sentinel 을 통한 마스터 정보 얻는 방법

꽁담 2020. 12. 23. 01:04

개요


Redis 에서는 Sentinel 기능이라는 마스터/슬레이브를 모니터링 하는 기능을 제공합니다.

 

Sentinel 은 일명 모니터를 하는 기능으로 마스터/슬레이브를 정해주며

마스터 노드가 Failover 되었을 때 슬레이브 노드를 마스터로 구동 후, 마스터로 접속할 수 있도록 해주는 기능입니다.

 

Jedis 라이브러리에서는 이렇게 Failover 되었을 때 센티넬로부터 새로운 마스터 정보를 얻어와서

변경된 마스터로 접속할 수 있도록 제공하고 있습니다.

 

 

테스트 환경


테스트를 하기 위한 환경은 아래와 같고

모든 테스트는 리눅스 환경에서 이루어졌습니다.

 

Jedis 를 사용한 자바 코드도 리눅스 환경에서 동작합니다.

OS Ubuntu 18.04
Redis Master 127.0.0.1 6161
Redis Slave 127.0.0.1 6162
Redis Sentinel 127.0.0.1 26937
Jedis 2.9.0
JDK openjdk 1.8.0

 

 

예제 코드


라인 23 : 센티넬의 정보를 센티넬 스트링 변수에 추가합니다.

라인 25 : 센티넬 풀에 센티넬 정보와 모니터링 하는 마스터 이름을 등록합니다.

라인 26 : 센티넬 풀에 있는 마스터 정보로 커넥션을 생성합니다.

라인 51 : 쓰레드로 돌면서 마스터의 정보를 출력합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
import java.text.SimpleDateFormat;
import redis.clients.jedis.*;
 
import java.util.Set;
import java.util.HashSet;
 
public class test {
        public static void main(String[] args) {
                Runnable r = new classRun();
                Thread[] t = new Thread[1];
 
                t[0= new Thread(r);
                t[0].start();
        }
}
 
 
class classRun implements Runnable {
        public void run()
        {
                SimpleDateFormat format1 = new SimpleDateFormat ( "yyyy-MM-dd HH:mm:ss" );
                Set<String> sentinels = new HashSet<>();
                sentinels.add("localhost:26937");
 
                JedisSentinelPool pool = new JedisSentinelPool("TEST", sentinels, "P@ssword");
                Jedis jedis = pool.getResource();
                //System.out.println("Current jedis : " + pool.getCurrentHostMaster().toString());
 
                while(!Thread.currentThread().isInterrupted())
                {
                        try {
                                Thread.sleep(1000);
 
                                System.out.println("Ping 체크시작");
                                for(int j = 0 ; j < 10 ; j ++)
                                {
                                        try {
                                                jedis.ping();
                                                break;
                                        }catch(Exception e) {
                                                continue;
                                        }
                                }
                                System.out.println("Ping 체크종료");
                                jedis.psubscribe ( new JedisPubSub() {
                                        public void onMessage(String channel, String message){}
                                        public void onSubscribe(String channel, int num){}
                                        public void onUnsubscribe(String channel, int num){}
                                        public void onPSubscribe(String channel, int num){}
                                        public void onPUnsubscribe(String channel, int num){}
                                        public void onPMessage(String pattern, String event, String message) {
                                                String format_time = format1.format(System.currentTimeMillis());
                                                String[] msg = message.split(" ");
                                                System.out.println("[" + format_time + "]" + msg[0]);
                                }, "*");
                        }catch (Exception e){
                                System.out.println("[ERROR] Exception : " + e.getMessage());
                                continue;
                        }
                }
                try {
                        Thread.sleep(1000);
                }
                catch (InterruptedException e) {
                        System.out.println("[ERROR] InterruptedException : " + e.getMessage());
                }
                pool.close();
                pool.destroy();
        }
}
cs

 

자바 로그

Java 의 로그를 보면 192.168.56.101, 26937 센티넬 서버에서 마스터 정보를 새로 얻어오는 걸 볼 수 있습니다.

또한 1:02:24 초에 Failover 되면서 마스터 풀 정보를 새로 구성하는 것을 확인할 수 있습니다.

1
2
3
4
5
6
7
8
9
10
[2020-12-23 01:02:20]192.168.56.101,26937,d4714e799fc45f5d9c305cd54d519430ff9b5167,33,TEST,192.168.56.101,6162,33
 
[2020-12-23 01:02:22]192.168.56.101,26937,d4714e799fc45f5d9c305cd54d519430ff9b5167,33,TEST,192.168.56.101,6162,33
 
12월 232020 1:02:24 오전 redis.clients.jedis.JedisSentinelPool initPool
정보: Created JedisPool to master at 192.168.56.101:6161
 
[2020-12-23 01:02:26]192.168.56.101,26937,d4714e799fc45f5d9c305cd54d519430ff9b5167,34,TEST,192.168.56.101,6161,34
 
[2020-12-23 01:02:28]192.168.56.101,26937,d4714e799fc45f5d9c305cd54d519430ff9b5167,34,TEST,192.168.56.101,6161,34
cs

 

센티넬 로그

1:02:24 초에 센티넬 TEST 인스턴스가 Failover 된 것을 확인할 수 있습니다.

1
2
3
[20610] 23 Dec 01:02:24.455 # +failover-end master TEST 192.168.56.101 6162
[20610] 23 Dec 01:02:24.455 # +switch-master TEST 192.168.56.101 6162 192.168.56.101 6161
[20610] 23 Dec 01:02:24.455 * +slave slave 192.168.56.101:6162 192.168.56.101 6162 @ TEST 192.168.56.101 6161
cs

 

 

참고사항


Jedis 의 Pub/Sub 기능은 완벽하지 않다고 나와있고

Pub/Sub 기능을 사용할거면 Lettuce 를 사용하기를 권고한다고 나와있습니다.

 

redisgate.kr/redis/clients/jedis_pubsub.php

 

Jedis Pub/Sub

jedis_pubsub Jedis Pub/Sub Pub/Sub Sentinel 메시지를 받는데는 실패했다. Async가 안되는 것도 좀 문제다. Pub/Sub을 사용할 계획이면 Lettuce를 사용하기를 권합니다. public class Pubsub { JedisPubSub jedisPubSub = null; Bi

redisgate.kr