-
MacOS 로컬 환경에서 Docker Redis Cluster 설정 및 Springboot와 연동하기Redis 2024. 8. 9. 12:22
Docker Compose
Docker Desktop for Mac을 사용하며(M3 MacOS)
Docker 환경을 구성하려 하기 때문에 arm64v8/redis 이미지를 사용하였습니다.
docker-compose.yml
version: '3' services: redis-master-1: container_name: redis-master-1 image: arm64v8/redis:latest restart: always volumes: - ./redis-master-1.conf:/etc/redis-master-1.conf command: redis-server /etc/redis-master-1.conf ports: - "7001:7001" - "7002:7002" - "7003:7003" - "7004:7004" - "7005:7005" - "7006:7006" redis-master-2: container_name: redis-master-2 image: arm64v8/redis:latest network_mode: "service:redis-master-1" restart: always volumes: - ./redis-master-2.conf:/etc/redis-master-2.conf command: redis-server /etc/redis-master-2.conf redis-master-3: container_name: redis-master-3 image: arm64v8/redis:latest network_mode: "service:redis-master-1" restart: always volumes: - ./redis-master-3.conf:/etc/redis-master-3.conf command: redis-server /etc/redis-master-3.conf redis-replica-1: container_name: redis-replica-1 image: arm64v8/redis:latest network_mode: "service:redis-master-1" restart: always volumes: - ./redis-replica-1.conf:/etc/redis-replica-1.conf command: redis-server /etc/redis-replica-1.conf redis-replica-2: container_name: redis-replica-2 image: arm64v8/redis:latest network_mode: "service:redis-master-1" restart: always volumes: - ./redis-replica-2.conf:/etc/redis-replica-2.conf command: redis-server /etc/redis-replica-2.conf redis-replica-3: container_name: redis-replica-3 image: arm64v8/redis:latest network_mode: "service:redis-master-1" restart: always volumes: - ./redis-replica-3.conf:/etc/redis-replica-3.conf command: redis-server /etc/redis-replica-3.conf redis_cluster_entry: image: arm64v8/redis:latest network_mode: "service:redis-master-1" container_name: redis_cluster_entry command: redis-cli --cluster create 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005 127.0.0.1:7006 --cluster-yes -a {설정한 비밀번호} depends_on: - redis-master-1 - redis-master-2 - redis-master-3 - redis-replica-1 - redis-replica-2 - redis-replica-3
위 docker-compose.yml의 내용을 요약해보자면 아래와 같습니다.
- Redis 클러스터는 Master와 Replica의 비율이 3:3으로 구성되어 있습니다.
- 이미지는 실리콘 맥 플랫폼을 지원하는 arm64v8/redis의 최신 버전을 사용하고 있습니다.
- 모든 노드가 같은 네트워크를 공유하도록 network_mode를 redis-master-1로 설정했습니다.
Redis Cluster Mode를 위한 config 파일 작성
아래 링크에서 Redis 버전에 맞춰 기본 양식의 config 파일을 다운로드할 수 있습니다.
해당 파일에서 필요한 값들을 수정해서 저장하면 됩니다.
아래는 클러스터 모드를 구축하기 위해 추가한 config 파일 내용입니다.
port 부분은 master와 replica 각 노드에 맞는 port 번호로 conf 파일을 구성하면 됩니다.
비밀번호를 설정하려면 requirepass {비밀번호}를 추가해줍니다.
# IF YOU ARE SURE YOU WANT YOUR INSTANCE TO LISTEN TO ALL THE INTERFACES # COMMENT OUT THE FOLLOWING LINE. # # You will also need to set a password unless you explicitly disable protected # mode. # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ bind 0.0.0.0 # Accept connections on the specified port, default is 6379 (IANA #815344). # If port 0 is specified Redis will not listen on a TCP socket. port 7001 # AOF and RDB persistence can be enabled at the same time without problems. # If the AOF is enabled on startup Redis will load the AOF, that is the file # with the better durability guarantees. # # Note that changing this value in a config file of an existing database and # restarting the server can lead to data loss. A conversion needs to be done # by setting it via CONFIG command on a live server first. # # Please check https://redis.io/topics/persistence for more information. appendonly yes ################################ REDIS CLUSTER ############################### # Normal Redis instances can't be part of a Redis Cluster; only nodes that are # started as cluster nodes can. In order to start a Redis instance as a # cluster node enable the cluster support uncommenting the following: # cluster-enabled yes # Every cluster node has a cluster configuration file. This file is not # intended to be edited by hand. It is created and updated by Redis nodes. # Every Redis Cluster node requires a different cluster configuration file. # Make sure that instances running in the same system do not have # overlapping cluster configuration file names. # cluster-config-file nodes.conf # Cluster node timeout is the amount of milliseconds a node must be unreachable # for it to be considered in failure state. # Most other internal time limits are a multiple of the node timeout. # cluster-node-timeout 3000
이제 앞서 작성한 docker-compose를 실행하게 되면
redis-cluster-entry에서 docker-compose.yml에 포함 되어 있는 아래와 같은 명령어를 통해 클러스터 구축하게 됩니다.
redis-cli --cluster create 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005 127.0.0.1:7006 --cluster-yes
혹시 앞의 redis-master-1.conf ~ redis-replica-3.conf 설정 단계에서
requirepass {비밀번호}와 같이 별도의 비밀번호를 설정하지 않았다면
위 docker-compose.yml에서 -a 옵션은 제거하면 됩니다.
docker-compose up -d 명령어로 컨테이너를 실행하면 아래와 같이 잘 작동하는 것을 확인할 수 있습니다.
테스트
이제 실제로 데이터가 잘 삽입되는지 테스트를 해보도록 하겠습니다.
보편적인 터미널로 직접 명령어를 작성해서 테스트 하는 방법과
Medis를 통해서 좀 더 편하게 테스트 하는 방법이 있는데,
레디스 클러스터 모드가 처음이라 터미널에서 직접 해보니깐 좀 흥미로운 점이 있었어서 둘다 기록하려합니다.
터미널
흥미로웠던 부분은 큰 네모 박스 부분이였습니다.
"Redirected to slot [12539] located at 127.0.0.1:7005"가 눈에 띄는데,
Redis 클러스터는 16,384개의 해시 슬롯으로 데이터를 분할합니다.
키가 특정 슬롯에 매핑되며 이 슬롯이 위치한 노드에서 명령어가 실행됩니다.
만약 클라이언트가 다른 노드에 연결되어 있다면(7001)
클러스터는 자동으로 올바른 노드로 리다이렉트하여 작업을 처리하게 되고,
해당 리다이렉션 과정이 "Redirected to slot [12539] located at 127.0.0.1:7005" 메시지로 나타나게 된 것입니다.
Medis
Medis GUI는 사용이 비교적 간단하고 직관적이라서 Redis를 관리하는 데 유용한 도구로,
위와 같이 터미널에서 복잡한 과정을 보다 쉽게 테스트 할 수 있습니다.
앱스토어에서 다운이 가능합니다.
우선 위와 같이 host와 port를 설정해주시고, Mode는 Cluster로 설정하고 저장해줍니다.
그리고 Connect를 클릭해줍니다.
Command Query를 클릭해서 레디스 명령어를 입력하여 데이터가 잘 삽입되고 가져와지는지 테스트해줍니다.
잘 가져오는 것을 확인할 수 있었습니다.
Spring Boot와 연동하기
이제 위에서 구성한 레디스 클러스터를 스프링부트와 연결해보도록 하겠습니다.
build.gradle
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
application.yml
spring: data: redis: password: {설정한 비밀번호} cluster: nodes: 127.0.0.1:7001, 127.0.0.1:7002, 127.0.0.1:7003, 127.0.0.1:7004, 127.0.0.1:7005, 127.0.0.1:7006
RedisClusterConfig.java
@Configuration @EnableCaching public class RedisClusterConfig { @Value("${spring.data.redis.cluster.nodes}") private List<String> clusterNodes; @Value("${spring.data.redis.password}") private String password; @Bean public RedisConnectionFactory redisConnectionFactory() { List<RedisNode> redisNodes = clusterNodes.stream() .map(clusterNode -> new RedisNode(clusterNode.split(":")[0], Integer.parseInt(clusterNode.split(":")[1]))) .toList(); RedisClusterConfiguration clusterConfiguration = new RedisClusterConfiguration(); clusterConfiguration.setClusterNodes(redisNodes); clusterConfiguration.setPassword(password); // Socket 옵션 SocketOptions socketOptions = SocketOptions.builder() .connectTimeout(Duration.ofMillis(100L)) .keepAlive(true) .build(); // Cluster topology refresh 옵션 ClusterTopologyRefreshOptions clusterTopologyRefreshOptions = ClusterTopologyRefreshOptions.builder() .dynamicRefreshSources(true) .enableAllAdaptiveRefreshTriggers() .enablePeriodicRefresh(Duration.ofMinutes(30L)) .build(); // Cluster Client 옵션 ClientOptions clientOptions = ClusterClientOptions.builder() .topologyRefreshOptions(clusterTopologyRefreshOptions) .socketOptions(socketOptions) .build(); // Lettuce Client 옵션 LettuceClientConfiguration clientConfiguration = LettuceClientConfiguration.builder() .clientOptions(clientOptions) .commandTimeout(Duration.ofMillis(3000L)) .build(); return new LettuceConnectionFactory(clusterConfiguration, clientConfiguration); } @Bean public RedisTemplate<?, ?> redisTemplate() { RedisTemplate<byte[], byte[]> redisTemplate = new RedisTemplate<>(); redisTemplate.setKeySerializer(new StringRedisSerializer()); redisTemplate.setValueSerializer(new StringRedisSerializer()); redisTemplate.setHashKeySerializer(new StringRedisSerializer()); redisTemplate.setHashValueSerializer(new StringRedisSerializer()); redisTemplate.setConnectionFactory(redisConnectionFactory()); return redisTemplate; } }
위에 작성한 코드는 Spring Boot 애플리케이션이 Redis 클러스터와 통신하기 위해 필요한 설정을 정의한 코드입니다.
클러스터 노드 정보, 소켓 및 클라이언트 옵션, 클러스터 토폴로지 갱신 방법 등을 포함하였습니다.
또한, 애플리케이션이 Redis와 데이터를 주고받을 때 사용할 RedisTemplate 빈도 정의하였습니다.
보다 자세한 내용은 아래 블로그를 참고해주세요!
다음에는 AWS Elasticache를 통해 클러스터 모드 적용을 했던 내용을 기록하고자합니다.
'Redis' 카테고리의 다른 글
Redis 데이터 구조 (0) 2024.02.20 [Redis] backup1, backup2... 그리고 Failed opening the RDB file crontab (in server root dir /etc) for saving: Read-only file system (0) 2023.11.22