๐ค ๊ฐ์
์ด์ ๊ธ์ ๋ณด๋ฉด, ๋ ๋์ค์ ๋ฐฑ์ ๊ณผ ๊ณ ๊ฐ์ฉ์ฑ์ ๋ํ ์์ธํ ์ด์ผ๊ธฐ๊ฐ ๋ด๊ฒจ์์ต๋๋ค.
Redis์ ๊ณ ๊ฐ์ฉ์ฑ์ ์ํด์ Cluster๋ฅผ ๊ตฌ์ฑํ ์ ์์ต๋๋ค. ๊ทธ ์ค์์๋ Docker Desktop for Mac์ ์ฌ์ฉํ๋ฉด์ Redis-Cluster๋ฅผ ๊ตฌ์ถํ ์ ์๋๋ก Docker-Compose ํ์ผ ๊ตฌ์ฑ๊ณผ SpringBoot Application ์ค์ ์ ๋ํด ์์๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค.
ํด๋ฌ์คํฐ์ ๋ํ ์์ธํ ๋ด์ฉ์ด ๊ถ๊ธํ๋ค๋ฉด, ์์ ์ด์ ๊ธ์ ์ฐธ์กฐํด์ฃผ์ธ์.
๐ Docker Compose ์ธํ
Docker์ ์ด๋ค ์ด๋ฏธ์ง๋ฅผ ์ฌ์ฉํ๋๋๊ฐ ๊ต์ฅํ ์ค์ํฉ๋๋ค.
์ผ๋ฐ์ ์ธ Redis ์ด๋ฏธ์ง๋ฅผ ์ฌ์ฉํ ์๋ ์๊ณ , bitnami์ Redis-Cluster ์ด๋ฏธ์ง๋ฅผ ์ฌ์ฉํ์ ๋ ์ข์ต๋๋ค.
ํ์ง๋ง ์ฌ๊ธฐ์์๋ Docker Desktop for Mac์ ์ฌ์ฉํ๋ฉฐ(M1 MacOS) Docker ํ๊ฒฝ์ ๊ตฌ์ฑํ๋ ค ํ๊ธฐ ๋๋ฌธ์ arm64v8/redis ์ด๋ฏธ์ง๋ฅผ ์ฌ์ฉํ์๋ ๊ฒ์ด ์ข์ต๋๋ค.
Linux ์๋ฒ ๋ฑ์์ Cluster๋ฅผ ๊ตฌ์ถ์ ์๋ํ๋ค๋ฉด, bitnami/redis-cluster๋ฅผ ๊ฒ์ํด ๊ตฌํํ๋ฉด ํธํ๊ฒ ๊ตฌ์ถํ ์ ์์๊ฒ๋๋ค.
โ 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
depends_on:
- redis-master-1
- redis-master-2
- redis-master-3
- redis-replica-1
- redis-replica-2
- redis-replica-3
๋ ๋์ค ํด๋ฌ์คํฐ์ ๊ตฌ์ฑ์ Master : Replica = 3 : 3์ ๋น์จ๋ก ๊ตฌ์ฑ๋์ด ์์ต๋๋ค.
์ด๋ฏธ์ง๋ ์ค๋ฆฌ์ฝ ๋งฅ ํ๋ซํผ์ ์ง์ํ๋ arm64v8/redis์ latest ๋ฒ์ ์ ์ฌ์ฉํ์ต๋๋ค.
network_mode๋ ๋ชจ๋ ๋ ธ๋๊ฐ redis-master-1์ผ๋ก ์ค์ ํจ์ผ๋ก์จ ๊ฐ์ ๋คํธ์ํฌ๋ฅผ ๊ณต์ ํ๋๋ก ๊ตฌ์ฑํ์ต๋๋ค.
๊ฐ ํด๋ฌ์คํฐ์ ๋ ธ๋๋ ๋ณผ๋ฅจ ๋ง์ดํธ๋ฅผ ํ๊ณ ์์ผ๋ฏ๋ก, docker-compose.yml๊ณผ ๊ฐ์ ๋๋ ํ ๋ฆฌ ์์น์
- redis-master-1.conf ~ redis-master-3.conf
- redis-replica-1.conf ~ redis-replica-3.conf
์ ์ค์ ํ์ผ์ด ์กด์ฌํด์ผ ํฉ๋๋ค. ํด๋น ์ค์ ํ์ผ ๋ด์์ ํฌํธ ๋ฒํธ์, ๋น๋ฐ๋ฒํธ, AOF ๋ฐฑ์ ๋ฐฉ์, enable cluster ์ค์ ์ ๋ง์น๊ณ ์ ์ฅํฉ๋๋ค.
defaultํ config ํ์ผ์ ์๋์ ๋งํฌ์์ Redis์ ๋ฒ์ ์ ๋ง๊ฒ ๋ค์ด๋ก๋ ๋ฐ์ ์ ์์ผ๋ฉฐ, ํด๋น ํ์ผ์์ ๊ฐ์ ์์ ํด ์ ์ฅํ๋ฉด ๋ฉ๋๋ค.
Redis์ ๋ฒ์ ์ด ๋ค๋ฅธ config ํ์ผ์ ๋ฐ์ ์ค์ ํ๋ฉด ์คํ ์ค ์ค๋ฅ๊ฐ ์๊ธธ ์ฌ์ง๊ฐ ์์ผ๋ฏ๋ก ๋ฐ๋์ ๋ง์ถฐ์ฃผ์๊ธฐ ๋ฐ๋๋๋ค.
์๋๋ ํด๋ฌ์คํฐ ๋ ธ๋๋ก ๋ง๋ค๊ธฐ ์ํด config ํ์ผ์ ๋ํ์ ์ผ๋ก ์์ ํ ๋ถ๋ถ์ ๋๋ค.
# ํธ์คํธ ๋จธ์ ์์ ๋ ๋์ค๊ฐ ์ปค๋ฅ์
์ ๋ฐ์๋ค์ผ IP ์ค์
# bind 192.168.1.100 10.0.0.1 # listens on two specific IPv4 addresses
# bind 127.0.0.1 ::1 # listens on loopback IPv4 and IPv6
# bind * -::* # like the default, all available interfaces
# ์๋๋ ์์์
๋๋ค.
bind 127.0.0.1
# ๋ ๋์ค์ ํฌํธ ๋๋ฒ ์ค์
port 6379
# ๋ฐฑ์
๋ฐฉ์ AOF ๋ฐฉ์ ์ค์
appendonly yes
# 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
์์ ๊ฐ์ ์์ ์ ๊ฐ ๋ ธ๋ ๋ง๋ค ๋ ธ๋์ ๋ง๋ ๊ฐ์ผ๋ก (๋ง์คํฐ 3, ๋ ํ๋ฆฌ์นด 3 ๊ฐ ๋ ธ๋์ ๋ง๋ ํฌํธ ๋ฒํธ) conf ํ์ผ์ ๊ตฌ์ฑํ๋ฉด ๋ฉ๋๋ค.
์ต์ข ์ ์ผ๋ก redis-cluster-entry์์ ์๋์ ๊ฐ์ ๋ช ๋ น์ด๋ฅผ ํตํด ํด๋ฌ์คํฐ ๊ตฌ์ถ์ ์๋ฃํฉ๋๋ค.
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
๊ตฌ์ถ์ด ์๋ฃ๋ ํ, ์๋์ ๊ฐ์ด ๋์ปค ํ๋ก์ธ์ค๊ฐ ๊ตฌ๋๋๋ ๊ฒ์ ํ์ธํ ์ ์์ต๋๋ค.
์๋๋, ๋ฐ์ดํฐ๊ฐ ์ ์ฝ์ ๋๋์ง ํ ์คํธ์ฉ์ผ๋ก, ๊ฐ๋จํ๊ฒ Medis GUI๋ฅผ ํตํด Connection์ ๋งบ์ต๋๋ค. ํ๋จ์ Cluster ๋ชจ๋๋ฅผ ์ค์ ํด์ MOVED ์๋ฌ๋ฅผ ํ์ฒ๋ฆฌ ํ ํ ๊ฒฐ๊ณผ ๊ฐ์ ๋ณด์ฌ์ฃผ๋๋ก ์ธํ ํฉ๋๋ค.
๊ฐ์ด ์ ๋์ค๋ ๊ฒ์ ํ์ธํ์ต๋๋ค.
๐ SpringBoot Application
์์ ๊ฐ์ด ๊ตฌ์ฑํ ๋ ๋์ค ํด๋ฌ์คํฐ์ ์คํ๋ง ๋ถํธ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ฐ๊ฒฐํด๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค.
โ build.gradle
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
โ application.yml
spring:
data:
redis:
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
โ RedisConfig.java
@Configuration
public class NEORedisConfig {
private final String clusterNodes;
public NEORedisConfig(@Value("${spring.data.redis.cluster.nodes}") final String clusterNodes) {
this.clusterNodes = clusterNodes;
}
@Bean
public RedisTemplate<?, ?> redisTemplate() {
RedisTemplate<byte[], byte[]> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory());
return redisTemplate;
}
@Bean
public RedisConnectionFactory redisConnectionFactory() {
RedisClusterConfiguration clusterConfig = new RedisClusterConfiguration(Arrays.asList(clusterNodes.split(",")));
return new LettuceConnectionFactory(clusterConfig);
}
}
application.yml์์ ์ค์ ํ cluster์ ๋ ธ๋๋ค์ @Value ์ ๋ ธํ ์ด์ ์ ํตํด cluterNodes ํ๋์ ์ฝ์ ํฉ๋๋ค.
๊ทธ ํ, ๊ฐ ๋ ธ๋๋ค์ RedisClusterConfiguration ๊ฐ์ฒด๋ฅผ ์์ฑํด LettuceConnectionFactory์ ๋ฑ๋กํฉ๋๋ค.
์ด๊ฒ์ผ๋ก ๊ฐ๋จํ ์ฐ๊ฒฐ ์ค์ ์ ๋ง์น ์ ์์ต๋๋ค.