장애 감지를 구현해야 할 일이 있었다.
아래와 같은 고민들이 있었다.
분산 환경에서 장애 감지를 어떻게 할까??
exception이 일정 시간 동안 일정 횟수 이상 발생하면 모니터링 알림을 줘야 한다.
각각의 exception count의 총합을 어떻게 관리하지..?
일정 시간은 어떻게 체크하지..?
정답은 바로 "레디스"
레디스로 어떻게..?
레디스의 특징 중에서 여러 프로세스에서 동시에 같은 key에 대해서 갱신을 요청하는 경우 Atomic 하게 처리해주기 때문에 Exception 발생 시 키 값에 대해 카운트를 증가시켜 줄 수 있다.
오 그럼 일정 시간은 어떻게..?
레디스는 TTL 제공을 제공해준다. 그렇기 때문에 일정 시간을 TTL로 잡고 해당 시간 동안 count 수가 내가 설정해놓은 수치를 넘을 때만, 장애 알림을 보내주면 된다.
구현
처음에는 레디스를 설치해서 명령어를 찾아보며 간단하게 테스트를 해봤다.
nil 은 null과 같은 의미이다.
get key를 했을 때 null 이면 초기값을 set 해준다.
세팅한 count를 확인한다.
key가 존재하면 ++해준다.
키에 "일정 시간"에 해당하는 ttl을 부여한다.
ttl이 줄어드는 모습이 보이고 마침내 ttl을 종료한다.
ttl이 종료하면 해당 key 값은 삭제된다.
이를 바탕으로 아래와 같은 방법으로 구현했다. (의사 코드)
key 값 조회
if (key 존재)
count++
else
set key, countValue, ttl
if (count > 목표 카운트 수)
slackSend("장애 확인");
음 하지만, 이 방법보다 더 효율적인 방법이 있었다.
나는 key값을 일일이 세팅해줬지만, incr 기능 자체가 map의 getOrDefault 메서드처럼 key가 존재하면 값을 증가시켜주고, 키가 존재하지 않는다면 키를 생성 후 값을 증가시켜준다.
- key값을 조회할 필요가 없었다. -> 그래서 소스코드가 훨씬 줄어들었다.
의사 코드
private void checkExceptionCount() {
int count = redis.getKey();
if(count > 목표 카운트 수)
slackSend("장애 확인");
redis.increaseKey(); && redis.setTTL();
}
간단 명령어 정리
기본
모든키 조회 keys * -> 상용에서는 절대 쓰면 안됨
100개 제한 읽어오기 - scan 0 count 100 match *
String 관련
저장 - set [key] (key에 value를 저장)
검색 - get [key]
삭제 - del [key]
값의 길이 - strlen
존재여부 - exists (존재하면1, 없으면 0)
모든 key 삭제 - flushall
List 관련
lpush - list의 index0 쪽으로 데이터를 넣는다.
rpush - list의 index last 쪽으로 데이터를 넣는다.
lpop - list의 index 0 데이터를 뺀다.
rpop - list의 index last 데이터를 뺀다.
lrange - lrange key start end (start부터 end까지 element 반환)
llen - key길이 확인
Set관련 - 중복되지 않는 값을 가짐
sadd key member - set에 value 하나 추가
srem key - set에서 key 삭제
smembers key - set에 속해있는 모든 member 조회
scard key - set에 속해있는 member 갯수 구함
spop - set 에서 무작위로 member 가져옴
Sorted Set (중복되지 않는 값을 데이터로 가지는 Collection)
가중치(Score)를 가지고 있고 가중치에 따른 정렬된 순서를 가지고 있는다.
Score가 같으면 value로 sort됨. value는 중복되지 않고 score는 중복될 수 있음.
zadd key score member - 집합에 score value를 추가한다.
zcard key - 집합에 member 갯수 조회
zrange key start stop - 인덱스 범위로 조회
zrangebyscore key min max - score 범위로 조회
해시값 관련 - key 하나에 field와 value 쌍을 40억개(4,294,967,295)까지 저장 가능
hgetall [key] - key에 대한 전체 field와 value 출력
hvals [key] - key에 대한 전체 values
hkeys [key] - key에 대한 전체 field
hset key field value - key에 field와 value를 쌍으로 저장
hget key field - key에서 field로 valuef를 가져온다.
hdel key field - key에서 field를 삭제
hlen key - field 갯수반환
지정시간 이후 key 자동 삭제
expire key member second : key에 ttl 설정
ttl key : 남은 ttl을 초단위로 확인
SLOWLOG GET
# get 으로 시작하는 카운트 중 시간이 오개걸리는 값을 반환한다
# 일반적으로 겟 명령어에서 슬로우 로그가 발생하는 경우 해당 키값의 데이터가 용량이 가장 큰 (메모리를 많이 잡아먹는) 키 값이다
# 레디스 운영 시 OOM redis Out Of Memory 같은 경우, 해당 키 또는 리스트의 값이 너무 큰 (보통 팝 과정 없이 잘못 쌓이는 push LIST에서 발생한다. )
# GET , RESET, LEN 등을 확인 할 수 있다.
SETEX 키 시간 키밸류
# expire time을 걸어 아이템을 set 한다.
# setex hong 60 sungho 라고 입력하면, 60초간 hong이라는 키가 저장된다.
SETNX
기존에 데이터가 없을 경우에만 저장된다.
사용법은 setnx key value
결론
항상 분산 환경임을 전제하에 코딩을 해야 하기 때문에, 생각 없이 했다간 큰일 날 수 있을 것 같다.
레디스를 처음 사용해봤지만, 생각보다 간단하게 사용해볼 수 있었다.
하지만, 정밀하게 사용하기에는 까다로울 것 같다는 생각이 들었고 앞으로도 레디스를 사용해 개발할 일이 많아지기를 바랄 뿐이다.
재밌었다.
댓글