version: '3.8'
networks:
app-tier:
driver: bridge
services:
redis-master:
image: "bitnami/redis:7.2.4"
hostname: redis-master
container_name: eighteen-be-redis-master
environment:
- ALLOW_EMPTY_PASSWORD=yes
- REDIS_REPLICATION_MODE=master
ports:
- "6379:6379"
networks:
- app-tier
redis-slave-1:
image: "bitnami/redis:7.2.4"
hostname: redis-slave-1
container_name: eighteen-be-redis-slave-1
environment:
- ALLOW_EMPTY_PASSWORD=yes
- REDIS_MASTER_HOST=redis-master
- REDIS_REPLICATION_MODE=slave
ports:
- "6479:6379"
depends_on:
- redis-master
networks:
- app-tier
redis-slave-2:
image: "bitnami/redis:7.2.4"
hostname: redis-slave-2
container_name: eighteen-be-redis-slave-2
environment:
- ALLOW_EMPTY_PASSWORD=yes
- REDIS_MASTER_HOST=redis-master
- REDIS_REPLICATION_MODE=slave
ports:
- "6579:6379"
depends_on:
- redis-master
- redis-slave-1
networks:
- app-tier
redis-sentinel-1:
image: 'bitnami/redis-sentinel:7.2.4'
hostname: redis-sentinel-1
container_name: eighteen-be-redis-sentinel-1
environment:
- REDIS_SENTINEL_DOWN_AFTER_MILLISECONDS=3000
- REDIS_MASTER_HOST=redis-master
- REDIS_MASTER_PORT_NUMBER=6379
- REDIS_MASTER_SET=mymaster
- REDIS_SENTINEL_QUORUM=2
depends_on:
- redis-master
- redis-slave-1
- redis-slave-2
ports:
- '26379:26379'
networks:
- app-tier
redis-sentinel-2:
image: 'bitnami/redis-sentinel:7.2.4'
hostname: redis-sentinel-2
container_name: eighteen-be-redis-sentinel-2
environment:
- REDIS_SENTINEL_DOWN_AFTER_MILLISECONDS=3000
- REDIS_MASTER_HOST=redis-master
- REDIS_MASTER_PORT_NUMBER=6379
- REDIS_MASTER_SET=mymaster
- REDIS_SENTINEL_QUORUM=2
depends_on:
- redis-master
- redis-slave-1
- redis-slave-2
ports:
- '26380:26379'
networks:
- app-tier
redis-sentinel-3:
image: 'bitnami/redis-sentinel:7.2.4'
hostname: redis-sentinel-3
container_name: eighteen-be-redis-sentinel-3
environment:
- REDIS_SENTINEL_DOWN_AFTER_MILLISECONDS=3000
- REDIS_MASTER_HOST=redis-master
- REDIS_MASTER_PORT_NUMBER=6379
- REDIS_MASTER_SET=mymaster
- REDIS_SENTINEL_QUORUM=2
depends_on:
- redis-master
- redis-slave-1
- redis-slave-2
ports:
- '26381:26379'
networks:
- app-tier
volumes:
mysql-data:
Docker Compose 를 사용해 Redis 마스터- 슬레이브 복제 구성을 설정하는 예시 설정 (위)
왜 프로젝트에서 Master & Slave 구조를 채택했는가?
[NHN FORWARD 2021] Redis 야무지게 사용하기 (youtube.com)
NHN Forward 발표 자료에서 아키텍처 선택 기준을 참고하였다.
HA 기능?
- High Availability ⇒ 고 가용성
- 시스템이나 서비스에 장애가 발생하더라도 지속적으로 운영될 수 있도록 설계된 기능이다.
- 시스템의 신뢰성을 높일 수 있다.
HA 기능의 경우
1. 단일 레디스로 구성할 것인가
2. 다중 레디스로 구성할 것인가
2가지 분기로 나눠서 생각해야한다.
- 단일 레디스 == 오직 하나의 Master 레디스만 존재
- 만약 오류가 발생하여 Master 레디스(인스턴스)가 종료되는 경우, 수동으로 Master 재시작을 해줘야한다.
- 다중 레디스
- Master 에 장애가 발생하는 경우 Slave 레디스를 생성해놓고 대안으로 사용하는 구조가 가능함.
- 해당 과정에서 Replication 이라는 DB 복제가 필연적임
또한 다중 레디스를 구성하는 경우
복제
를 슬레이브에 해줘야한다.
소스상에선
redis-slave-1:
image: "bitnami/redis:7.2.4"
hostname: redis-slave-1
container_name: eighteen-be-redis-slave-1
environment:
- ALLOW_EMPTY_PASSWORD=yes
- REDIS_MASTER_HOST=redis-master
- REDIS_REPLICATION_MODE=slave
ports:
- "6479:6379"
depends_on:
- redis-master
networks:
- app-tier
redis-slave-2:
image: "bitnami/redis:7.2.4"
hostname: redis-slave-2
container_name: eighteen-be-redis-slave-2
environment:
- ALLOW_EMPTY_PASSWORD=yes
- REDIS_MASTER_HOST=redis-master
- REDIS_REPLICATION_MODE=slave
ports:
- "6579:6379"
depends_on:
- redis-master
- redis-slave-1
networks:
- app-tier
요 부분이 되는데
하나의 마스터 Redis 인스턴스와 두 개의 슬레이브 Redis 인스턴스 ( redis-slave-1 , redis-slave-2 ) 가 포함되어 있다.
이미지
모든 인스턴스를 최신 버전인 bitnami/redis:7.2.4 버전을 채택하였다.
hostname
, container_name
hostname
의 경우 네트워크 내에서 컨테이너를 식별할 수 있는 고유한 이름이 되기에 중요하다.ports
“외부:내부” 구조로 구성되어 있다.
외부 요청을 컨테이너의 6379 로 전달한다
마스터 - 슬레이브 간의 예시
- redis-master 인스턴스는
- “6379:6379”
- 6379 포트로 들어와서 6379포트로 전달
- redis-slave-1 인스턴스는
- “6380:6379”
- 6380 포트로 들어와서 6379포트로 전달
- 결국 6379 포트인 master 에서 작업을 수행함을 알 수 있음.
network
컨테이너가 연결될 네트워크를 지정한다.
초기에 docker-compose
에서 설정해놓았던
networks:
app-tier:
driver: bridge
와 관계있다.
이게 무엇이냐..
일단 DOCKER 가 등장한 이유중에 하나가 될 수 있다.
격리
통신
app-tier ( 그냥 내가 정한 네트워크 이름 ) 네트워크를 사용함으로서
마스터와 슬레이브 간의 통신 경로를 지정한다.
컨테이너 간의 통신을 위하여 bridge
모드로 네트워크를 설정한 것이다.
레디스 친구들은 레디스 끼리 통신하고 연관되어 있어야하니 너네 끼리는 서로에 대해 인지하렴~ 인 것이다.
또한
bridge
모드는
- 통신의 유연성을 제공한다고 한다.
- SOLID 원칙중에 개방 폐쇄 원칙이 존재한다.
- 개방 폐쇄 원칙은 새로운 서비스를 추가하거나 변경하는 경우 기존 네트워크 구성을 수정하지 않고 확장하는 것을 말하는데
bridge
모드는 마스터 슬레이브외에 센티넬.. 등의 다른 추가적인 서비스를 동일한 네트워크에 묶을 수 있다.
REDIS_REPLICATION_MODE = master
- 레디스 서버의 복제 모드를 마스터로 설정하는 것이다.
- 마스터는 데이터의 원본을 가지며, 슬레이브에 데이터를 복제한다.
REDIS_MASTER_HOST= redis-master
데이터를 복제할 마스터 서버의 호스트 이름
을 지정한다.REDIS_REPLICATION_MODE = slave
- 레디스 서버의 복제 모드는 슬레이브로 설정한다.
- 마스터로부터 데이터를 복제하여 , 읽기 요청을 처리하거나, 마스터에 장애가 발생한 경우 대체 역할을 수행
ALLOW_EMPTY_PASSWORD = yes
- 비밀번호없이 레디스 서버에 접근함
### 해당 설정은 운영될 환경에서는 절대로 설정하면 안된다.
depends_on
redis-slave-1
혹은 redis-slave-2
의 경우redis-master
가 먼저 시작해야 작동해야함docker-compose 파일 services 실행
docker compose up -d
를 수행하면된다.서비스에서 이미지들을 pulling 하는 모습
정상적으로 수행됨을 알 수 있다.
docker-compose down
docker-desktop 에서 redis-master 인스턴스의 로그만 체크해봐도 replication 이 수행됨을 알 수 있다.
redis-sentinel-1:
image: 'bitnami/redis-sentinel:7.2.4'
hostname: redis-sentinel-1
container_name: eighteen-be-redis-sentinel-1
environment:
- REDIS_SENTINEL_DOWN_AFTER_MILLISECONDS=3000
- REDIS_MASTER_HOST=redis-master
- REDIS_MASTER_PORT_NUMBER=6379
- REDIS_MASTER_SET=mymaster
- REDIS_SENTINEL_QUORUM=2
depends_on:
- redis-master
- redis-slave-1
- redis-slave-2
ports:
- '26379:26379'
networks:
- app-tier
redis-sentinel-2:
image: 'bitnami/redis-sentinel:7.2.4'
hostname: redis-sentinel-2
container_name: eighteen-be-redis-sentinel-2
environment:
- REDIS_SENTINEL_DOWN_AFTER_MILLISECONDS=3000
- REDIS_MASTER_HOST=redis-master
- REDIS_MASTER_PORT_NUMBER=6379
- REDIS_MASTER_SET=mymaster
- REDIS_SENTINEL_QUORUM=2
depends_on:
- redis-master
- redis-slave-1
- redis-slave-2
ports:
- '26380:26379'
networks:
- app-tier
redis-sentinel-3:
image: 'bitnami/redis-sentinel:7.2.4'
hostname: redis-sentinel-3
container_name: eighteen-be-redis-sentinel-3
environment:
- REDIS_SENTINEL_DOWN_AFTER_MILLISECONDS=3000
- REDIS_MASTER_HOST=redis-master
- REDIS_MASTER_PORT_NUMBER=6379
- REDIS_MASTER_SET=mymaster
- REDIS_SENTINEL_QUORUM=2
depends_on:
- redis-master
- redis-slave-1
- redis-slave-2
ports:
- '26381:26379'
networks:
- app-tier
환경 설정부분만 보면 될 듯하다.
REDIS_SENTINEL_DOWN_AFTER_MILLISECONDS
3000
밀리세컨드 만큼 가동되지 않는 경우, failover(장애 조치)
를 시도한다.장애 조치
- 밑의 그림같은 과정을 말함.
REDIS_SENTINEL_QUORUM
Sentinel 시스템이 마스터 서버에 장애가 발생했다고 판단하고 장애 조치를 시작하기 위해 필요한 최소한의 Sentinel 인스턴스의 수를 정의
2
로 설정된 경우
- 3개의 센티넬의 경우 2개 이상의 투표를 받은 slave 가 master 노드가 된다.
센티넬은 무조건 3개 이상의 홀수로 설정해야한다
- 투표가 동률이 되는 경우 선택이 불가능
failover
가 동작하지 않게 된다.
새로운 마스터를 선출하는 과정을 거친다.
1:X 19 Mar 2024 17:01:18.523 # +monitor master mymaster 192.168.32.2 6379 quorum 2
- mymaster 라는 이름의 마스터를 192.168.32.2 주소와 6379 포트에서 모니터링하기 시작한다.
- 쿼럼은 2
로 설정
1:X 19 Mar 2024 17:01:18.524 * +slave slave 192.168.32.4:6379 192.168.32.4 6379 @ mymaster 192.168.32.2 6379
1:X 19 Mar 2024 17:01:18.527 * +slave slave 192.168.32.3:6379 192.168.32.3 6379 @ mymaster 192.168.32.2 6379
slave 2개를 감지합니다
- 2개의 슬레이브를 감지하고, mymaster 에 연결되어 있음을 확인한다.
1:X 19 Mar 2024 17:01:20.182 * +sentinel sentinel 403c57ff71396630f2f894b49ba3662ddb151a48 192.168.32.5 26379 @ mymaster 192.168.32.2 6379
1:X 19 Mar 2024 17:01:20.423 * +sentinel sentinel 85fb9fd730d7fc5995bd4cd04f4af770dc7b2d3e 192.168.32.6 26379 @ mymaster 192.168.32.2 6379
센티넬 2개를 감지
- 2개의 센티넬을 감지하고, 이들도 mymaster를 모니터링한다.
1:X 19 Mar 2024 17:01:59.913 # +sdown master mymaster 192.168.32.2 6379
1:X 19 Mar 2024 17:01:59.976 # +odown master mymaster 192.168.32.2 6379 #quorum 3/2
주관적 (sdown) 및 객관적 다운 (odown) 상태 감지
> 주관적 다운
>
> - 특정 Sentinel 인스턴스가 마스터 - 슬레이브 와의 연결이 끊어졌다고 `개인적으로` 판단하는 상태
> - 지금 판단하는 센티넬의 `개인적` 생각
> 객관적 다운
>
> - 여러 Sentinel 인스턴스들이 공통적으로 노드 ( 주로 마스터임 ) 가 다운되었다고 판단하는 상태를 말한다.
> - Quorom (쿼럼) 이라는 다수결 원칙에 의해 결정된다.
>
> ### 실질적으로 시스템전체에서 해당 마스터 인스턴스가 실패했음을 인정한 상태 ⇒ 마스터가 죽었다!
>
1:X 19 Mar 2024 17:02:00.955 # +switch-master mymaster 192.168.32.2 6379 192.168.32.4 6379
마스터와 slave 를 교체한다.
192.168.32.4 6379
는 이전에는 slave 였지만, 새 마스터로 선출하고,redis-cli -p <sentinel 의 내부포트>
info sentinel
명령어를 수행하면```
redis-master:
image: "bitnami/redis:7.2.4"
hostname: redis-master
container_name: eighteen-be-redis-master
environment:
- ALLOW_EMPTY_PASSWORD=yes
- REDIS_REPLICATION_MODE=master
volumes:
- redis-master-data:/bitnami/redis/data:rw
command: redis-server --enable-debug-command yes --protected-mode no
ports:
- "6379:6379"
networks:
- app-tier
redis-slave-1:
image: "bitnami/redis:7.2.4"
hostname: redis-slave-1
container_name: eighteen-be-redis-slave-1
environment:
- ALLOW_EMPTY_PASSWORD=yes
- REDIS_MASTER_HOST=redis-master
- REDIS_REPLICATION_MODE=slave
ports:
- "6479:6379"
volumes:
- redis-slave-1-data:/bitnami/redis/data:rw
depends_on:
- redis-master
networks:
- app-tier
redis-slave-2:
image: "bitnami/redis:7.2.4"
hostname: redis-slave-2
container_name: eighteen-be-redis-slave-2
environment:
- ALLOW_EMPTY_PASSWORD=yes
- REDIS_MASTER_HOST=redis-master
- REDIS_REPLICATION_MODE=slave
ports:
- "6579:6379"
volumes:
- redis-slave-2-data:/bitnami/redis/data:rw
depends_on:
- redis-master
- redis-slave-1
networks:
- app-tier
redis-sentinel-1:
image: 'bitnami/redis-sentinel:7.2.4'
hostname: redis-sentinel-1
container_name: eighteen-be-redis-sentinel-1
environment:
- REDIS_SENTINEL_DOWN_AFTER_MILLISECONDS=3000
- REDIS_MASTER_HOST=redis-master
- REDIS_MASTER_PORT_NUMBER=6379
- REDIS_MASTER_SET=mymaster
- REDIS_SENTINEL_QUORUM=2
depends_on:
- redis-master
- redis-slave-1
- redis-slave-2
ports:
- '26379:26379'
networks:
- app-tier
redis-sentinel-2:
image: 'bitnami/redis-sentinel:7.2.4'
hostname: redis-sentinel-2
container_name: eighteen-be-redis-sentinel-2
environment:
- REDIS_SENTINEL_DOWN_AFTER_MILLISECONDS=3000
- REDIS_MASTER_HOST=redis-master
- REDIS_MASTER_PORT_NUMBER=6379
- REDIS_MASTER_SET=mymaster
- REDIS_SENTINEL_QUORUM=2
depends_on:
- redis-master
- redis-slave-1
- redis-slave-2
ports:
- '26380:26379'
networks:
- app-tier
redis-sentinel-3:
image: 'bitnami/redis-sentinel:7.2.4'
hostname: redis-sentinel-3
container_name: eighteen-be-redis-sentinel-3
environment:
- REDIS_SENTINEL_DOWN_AFTER_MILLISECONDS=3000
- REDIS_MASTER_HOST=redis-master
- REDIS_MASTER_PORT_NUMBER=6379
- REDIS_MASTER_SET=mymaster
- REDIS_SENTINEL_QUORUM=2
depends_on:
- redis-master
- redis-slave-1
- redis-slave-2
ports:
- '26381:26379'
networks:
- app-tier
volumes:
mysql-data:
redis-master-data:
redis-slave-1-data:
redis-slave-2-data:
- 볼륨 관련해서 문제가 있어서 이런식으로 수정 각각의 노드들이 독립적인 볼륨을 가지도록 설정
- 또한 permission 에러가 발생해서.. 수정했다 이유를 도저히 모르겠다.