Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
Tags
- bootcamp
- spring
- goorm
- s3
- DynamoDB
- 티스토리챌린지
- orm
- goorm x kakao
- rds
- Redis
- 자격증
- ec2
- codebuild
- Spring Boot
- CodeCommit
- CICD
- MSA
- jpa
- serverless
- codedeploy
- aws
- QueryDSL
- sqs
- backenddeveloper
- Docker
- 개발자
- 스터디
- mapping
- 오블완
- 백엔드
Archives
- Today
- Total
gony-dev 님의 블로그
[Redis] Connection Mode-1 본문
Redis는 통상적으로 4가지의 모드가 존재한다.
1. Redis Standalone(default)
2. Master/Slave
3. Redis Sentinel
4. Redis Cluster
각각의 모드는 뚜렷한 특징을 띄며, 모드를 조합하여 시스템의 요구사항을 만족시킬 수 있다.
1. Redis Standalone
- 우리가 흔히 프로젝트를 할 때 사용하는 모드로, 하나의 redis 서버만을 다룬다.
@Bean
public LettuceConnectionFactory redisConnectionFactory() {
RedisStandaloneConfiguration config = new RedisStandaloneConfiguration();
return new LettuceConnectionFactory(config);
}
2. Master/Slave
- 서버에 안전하게 데이터를 저장하게 하기 위한 모드이다.
- 읽기 성능을 향상시키며 redis 서버가 다운되더라도, 백업이 가능하다!
- Master
- 데이터를 읽고 쓰는 모든 요청을 처리하는 메인 서버이다.
- 데이터 쓰기 작업 발생 시 데이터를 자체 업데이트하고, 그와 동시에 하나 이상의 Slave 서버에게 복제한다.
- Slave
- 읽기 작업을 처리하는 서버이다.
- 복제 서버가 데이터를 제공하기에 Master에 가해지는 부하을 분산시킨다.
- Master가 제공하는 데이터를 주기적으로 반영한다.
- Replication
- Master와 Slave 간의 데이터 복제 과정을 의미하며 비동기적으로 실시된다.
- Master가 데이터를 쓰면 곧바로 Slave에 변경 사항이 전달된다.
application.yml
data:
redis:
master:
host: localhost
port: 6379
slaves:
- host: localhost
port: 7000
- host: localhost
port: 7001
RedisProperty.class
@Getter
@NoArgsConstructor
@ConfigurationProperties(prefix = "spring.redis")
@Configuration
public class RedisProperty {
private String host;
private Integer port;
private RedisProperty master;
private List<RedisProperty> slaves;
}
RedisConfig.class
@Bean
public LettuceConnectionFactory redisConnectionFactory() {
LettuceClientConfiguration clientConfig = LettuceClientConfiguration.builder()
.readFrom(ReadFrom.REPLICA_PREFERRED)
.build();
RedisStaticMasterReplicaConfiguration slaveConfig = new RedisStaticMasterReplicaConfiguration(
redisProperty.getMaster().getHost(), redisProperty.getMaster().getPort()
);
redisProperty.getSlaves().forEach(slave -> slaveConfig.addNode(slave.getHost(), slave.getPort()));
return new LettuceConnectionFactory(slaveConfig, clientConfig);
}
Test
- docker를 실행하여 master redis에서 key1에 대한 값을 써보고 읽어보았다.
정상적으로 처리되는 것을 확인할 수 있다! - 마찬가지로 slave redis에서도 동일한 명령어를 사용해 보자!
- 데이터를 넣을 수 없었다! 자연스러운 결과이다. slave redis는 오로지 데이터를 읽기 위함이므로 insert가 불가능하기 때문이다.
결론
- 실습을 통해 docker에서 master와 slave redis를 만들어 테스트해보았다.
- Redis Master-Slave 구조를 통해 Slave는 읽기 전용으로 Master의 부하를 줄이며,
비동기적 작동 방식으로 Slave redis에 데이터가 복제되는 것을 확인할 수 있었다! - 하지만 만일 Master가 죽으면 어떻게 될까? 이를 해결하기 위해서는 앞으로 나올 모드들을 파헤쳐 보는 것이 중요하다!
3. Redis Sentinel
- 고가용성 Redis를 처리하기 위한 모드이다.
- 자동 장애 복구를 수행하며 마스터-슬레이브 방식의 단점을 해결할 수 있다!
- 마스터-슬레이브 모드에서 마스터에 장애가 발생하면 슬레이브 중 하나를 승격하여 새로운 마스터로 지정한다.
- Sentinel 모드는 어플리케이션이 새로운 마스터를 자동으로 인식할 수 있게 돕는 역할을 한다.
- 이 부분은 도커를 이용하여 장애 조치가 원활히 이루어지는지 알아보겠다.
docker-compose.yml
version: '3.8'
services:
redis-master:
image: redis:latest
container_name: "redis-master"
ports:
- "6379:6379"
command: [ "redis-server" ]
volumes:
- master-data:/data
networks:
- redis-net
redis-slave1:
image: redis:latest
command: redis-server --slaveof redis-master 6379
links:
- redis-master
container_name: "redis-slave1"
networks:
- redis-net
redis-slave2:
image: redis:latest
command: redis-server --slaveof redis-master 6379
links:
- redis-master
container_name: "redis-slave2"
networks:
- redis-net
sentinel-1:
build: sentinel
ports:
- "5000:26379"
env_file:
- .env
depends_on:
- redis-master
- redis-slave1
- redis-slave2
container_name: "sentinel1"
networks:
- redis-net
sentinel-2:
build: sentinel
ports:
- "5001:26379"
env_file:
- .env
depends_on:
- redis-master
- redis-slave1
- redis-slave2
container_name: "sentinel2"
networks:
- redis-net
sentinel-3:
build: sentinel
ports:
- "5002:26379"
env_file:
- .env
depends_on:
- redis-master
- redis-slave1
- redis-slave2
container_name: "sentinel3"
networks:
- redis-net
volumes:
master-data:
slave1-data:
slave2-data:
networks:
redis-net:
driver: bridge
sentinel
- 올바른 환경 변수와 권한, 그리고 sentinel 명령을 달아주기 위해 sentinel이라는 폴더를 생성하여 빌드한다.
- 구조는 다음과 같다.
|
|_ _ _ Dockerfile
|_ _ _ sentinel.conf
|_ _ _ sentinel-entrypoint.sh
Dockerfile
- sentinel.conf 파일을 추가하고, 각 디렉터리에 권한을 부여한다.
- 최종적으로 sentinel-entirypoint.sh를 실행한다.
FROM redis:latest
EXPOSE 26379
ADD sentinel.conf /etc/redis/sentinel.conf
RUN mkdir -p /var/lib/redis /etc/redis && \
chmod 777 /var/lib/redis /etc/redis && \
chown redis:redis /etc/redis/sentinel.conf /var/lib/redis /etc/redis \
COPY sentinel-entrypoint.sh /usr/local/bin/
RUN chmod +x /usr/local/bin/sentinel-entrypoint.sh
ENTRYPOINT ["sentinel-entrypoint.sh"]
sentinel-entirypoint.sh
- 해당 파일 내에서는 기존에 저장해놓은 환경변수를 sentinel.conf에다가 집어넣는다.
- 그리고 /etc/redis에 대한 권한을 부여 후, 실행한다.
#!/bin/sh
# Replace environment variables in the configuration file
sed -i "s/\$SENTINEL_QUORUM/$SENTINEL_QUORUM/g" /etc/redis/sentinel.conf
sed -i "s/\$SENTINEL_DOWN_AFTER/$SENTINEL_DOWN_AFTER/g" /etc/redis/sentinel.conf
sed -i "s/\$SENTINEL_FAILOVER/$SENTINEL_FAILOVER/g" /etc/redis/sentinel.conf
chown -R redis:redis /etc/redis
# Run the Redis Sentinel with the updated configuration
exec docker-entrypoint.sh redis-server /etc/redis/sentinel.conf --sentinel
sentinel.conf
- log가 보이는 정도를 debug로 설정하고, 각 sentinel에 대한 명령을 수행한다.
- 가장 중요하다고 생각하는, 내가 그동안 되지 않았던 원인인.. 이 'sentinel resolve-hostnames yes'은 여러 서버가 도메인 이름을 통해 동적으로 IP를 할당받는 환경에서 유용하게 사용할 수 있다. 반드시 사용하기 바란다...
loglevel debug
port 26379
sentinel resolve-hostnames yes
sentinel monitor mymaster redis-master 6379 $SENTINEL_QUORUM
sentinel down-after-milliseconds mymaster $SENTINEL_DOWN_AFTER
sentinel parallel-syncs mymaster 1
sentinel failover-timeout mymaster $SENTINEL_FAILOVER
bind 0.0.0.0
그리고 docker-compose.yml를 실행하면 다음과 같이 컨테이너가 만들어진다.
redis-master의 정보를 보면, slave 노드가 2개 연결되어 있는 것을 확인할 수가 있다.
sentinel도 "info replication"을 사용하면 마스터 노드를 포함하여 다른 sentinel이 잘 등록되어 있는지 확인할 수 있다!
그렇게 만들어진 노드들로 장애 조치가 이루어지는지 확인하기 위해서는 redis-master의 연결을 끊어야 한다.
끊게 되면 sentinel들이 투표를 통해 다른 slave 노드를 마스터로 승격 시키게 된다.
결론
- sentinel 모드를 이용하여 master/slave 모드에 대해 master 노드에 장애가 생겼을 시 다른 slave 노드를 sentinel들의 투표를 통해 승격시키는 과정을 실습해보았다!
- 사실 실습하는 과정에서 환경변수에 대한 설정이 그닥 필요없었던 것 같았다.
그리고 왜인지 모르게 Dockerfile의 sentinel의 쓰기 권한이 제대로 설정되지 않아 disk에 변경 사항이 반영이 되지 않아 일일이 권한을 설정해주어야했던 번거로움이 있었다.(만일 제가 잘못짰다면 알려주세요..ㅜㅠㅜ) - 이렇게 sentinel은 장애 조치가 가능하여 redis 내의 데이터가 사라지는 것을 백업을 통해 해결할 수 있다!
- 하지만 sentinel + master/slave 간의 조합의 단점 또한 존재한다.
- Sentinel 자체가 다운되면 장애 복구가 이루어지지 않는다.
- 마스터와 슬레이브 간 동기화가 지연되면 읽기 작업 수행 시 최신 데이터 읽기를 수행할 수 없다.
- failover 발생 시 일시적 성능 저하가 일어날 수 있다.
- 모니터링 시스템이 없을 시 즉각적인 대처가 어렵다.
- 이 단점들을 한 번에 잡아주는 Cluster를 다음 포스트에 작성하면서 알아보자!
출처
'DBMS' 카테고리의 다른 글
[Redis] Connection Mode-2 (0) | 2024.12.08 |
---|---|
[Redis] Spring batch vs. Scheduler (0) | 2024.10.17 |
[Redis] Transaction (0) | 2024.10.15 |