티스토리 뷰
Redis Sentinel 기반 고가용성 캐시 시스템 구축기
최근 시스템의 성능 향상 및 장애 대응력을 높이기 위해 Redis를 도입하였다. 단일 인스턴스 구조의 한계를 극복하고자, Redis Sentinel을 기반으로 한 고가용성(HA) 구조를 구성하였다.
1. Redis Sentinel 3대 구성: Master - Slave - Slave
Redis는 기본적으로 싱글 스레드 구조이며, 단일 장애 지점(SPOF: Single Point of Failure)을 갖는다는 단점이 있다. 이를 해결하기 위해 Sentinel을 활용하여 총 3대의 Redis 노드를 구성하였다. 구조는 다음과 같다.
- 1대의 Master 노드
- 2대의 Slave 노드
- 모든 노드에서 Sentinel 프로세스를 별도로 실행하여 장애 감지 및 자동 페일오버를 지원
Sentinel은 Master 노드의 상태를 지속적으로 모니터링하며, 장애 발생 시 자동으로 새로운 Master를 선출하고 클라이언트 설정을 갱신할 수 있도록 구성하였다.
/configs
├── redis-1
│ ├── redis.conf
│ └── sentinel.conf
├── redis-2
│ ├── redis.conf
│ └── sentinel.conf
├── redis-3
│ ├── redis.conf
│ └── sentinel.conf
redis.conf
port 6379
dir /data
appendonly yes
slave 노드 설정 (redis-2, redis-3)
replicaof <MASTER_IP> 6379
sentinel.conf
port 26379
dir /tmp
sentinel monitor mymaster <MASTER_IP> 6379 2
sentinel down-after-milliseconds mymaster 5000
sentinel parallel-syncs mymaster 1
sentinel failover-timeout mymaster 10000
- mymaster는 Master 인스턴스 이름
- 2는 quorum 수로, 최소 2대가 다운을 인지해야 failover 수행
2. Grafana 기반 모니터링 환경 구축
Redis의 상태 및 Sentinel의 동작을 실시간으로 확인할 수 있도록 Prometheus Exporter를 활용하여 메트릭을 수집하고, 이를 Grafana 대시보드에 연동하였다.
모니터링 항목은 다음과 같다:
- 각 노드의 메모리 사용량 및 연결 수
- keyspace 정보
- Master-Slave 동기화 지연 시간
- Sentinel의 현재 Master 인식 정보 및 failover 이력
이로 인해 장애 발생 시 원인 파악 및 대응이 훨씬 수월해졌다.
Redis Exporter 설치
docker run -d \
--name redis_exporter \
-p 9121:9121 \
oliver006/redis_exporter \
--redis.addr=redis://<REDIS_HOST>:6379
Prometheus prometheus.yml
scrape_configs:
- job_name: 'redis'
static_configs:
- targets: ['redis-1:9121', 'redis-2:9121', 'redis-3:9121']
3. 내부용 Key-Value 조회 API 구현
Redis 운영 편의성을 높이기 위해 내부 개발자들이 손쉽게 캐시 데이터를 확인할 수 있도록 조회 전용 API를 구현하였다. 주요 기능은 다음과 같다:
- 지정한 Key에 대한 Value 조회
- Key 패턴 검색 (Wildcard 지원)
- TTL 정보 확인
application.yml
spring:
redis:
sentinel:
master: mymaster
nodes:
- redis-1:26379
- redis-2:26379
- redis-3:26379
password: your_password # 없다면 생략
RedisConfig.java
@Configuration
public class RedisConfig {
@Bean
public RedisConnectionFactory redisConnectionFactory(RedisProperties properties) {
RedisSentinelConfiguration sentinelConfig = new RedisSentinelConfiguration()
.master(properties.getSentinel().getMaster());
properties.getSentinel().getNodes().forEach(node -> {
String[] parts = node.split(":");
sentinelConfig.sentinel(parts[0], Integer.parseInt(parts[1]));
});
return new LettuceConnectionFactory(sentinelConfig);
}
@Bean
public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory connectionFactory) {
RedisTemplate<String, String> template = new RedisTemplate<>();
template.setConnectionFactory(connectionFactory);
template.setKeySerializer(new StringRedisSerializer());
template.setValueSerializer(new StringRedisSerializer());
return template;
}
}
RedisService.java
@Service
@RequiredArgsConstructor
public class RedisService {
private final RedisTemplate<String, String> redisTemplate;
public String getValue(String key) {
return redisTemplate.opsForValue().get(key);
}
public Long getTTL(String key) {
return redisTemplate.getExpire(key);
}
public Set<String> scanKeys(String pattern) {
return redisTemplate.keys(pattern);
}
}
RedisController.java
@RestController
@RequestMapping("/redis")
@RequiredArgsConstructor
public class RedisController {
private final RedisService redisService;
@GetMapping("/value/{key}")
public ResponseEntity<String> getValue(@PathVariable String key) {
String value = redisService.getValue(key);
return ResponseEntity.ok(value);
}
@GetMapping("/ttl/{key}")
public ResponseEntity<Long> getTTL(@PathVariable String key) {
return ResponseEntity.ok(redisService.getTTL(key));
}
@GetMapping("/keys")
public ResponseEntity<Set<String>> getKeys(@RequestParam String pattern) {
return ResponseEntity.ok(redisService.scanKeys(pattern));
}
}
'실무 개발' 카테고리의 다른 글
분산 트랜잭션 처리하기 (0) | 2025.02.22 |
---|---|
2PC (2-Phase-Commit)은 무엇인가? (2) | 2024.09.26 |
커스텀 어노테이션으로 중복 코드 제거하기 (0) | 2023.10.31 |
NGINX는 왜 Apache보다 좋은가? (0) | 2022.06.17 |
- Total
- Today
- Yesterday
- 프로그래밍 모델
- jvm
- 스프링
- 2021
- 모던 자바 인 액션
- zipkin
- 2019 Kakao Blind
- 디자인패턴
- spring cloud sleuth
- 카카오
- 카카오 코테
- KAKAO 2021
- okhttp3
- Java #GC #가비지콜렉터 #Garbage Collector
- 2020 KAKAO
- JobInstance
- Java #JIT #JVM
- runidincrementer
- springboot
- Kakao Blind
- 카카오코테
- 코테
- behavior parameterization
- PatternSyntaxException
- Java
- decorator
- nginx 내부
- Spring
- IOC
- WORE
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |