redis expire time(set, hset, zadd) 에 관하여
(cli형식이 아니라, 프로그래밍 코드 형식을 예시로 설명하고자 합니다. 코드는 프레임워크마다 다를 것인데 참고 부탁드립니다.)
<set함수 에서 expiretime>
redis는 인메모리 db로서 빠른성능에 장점이 있는 엔진이기에, 데이터가 과도하게 쌓이면 성능상 효율상 문제가 발생하기 마련이다. 그래서 프로그램에서 아래와 같이 시간을 제한하는 "EXPIRE"의 약자인 "EX"를 사용하는 방식의 set이 흔하다.
redis객체.set(key, value, "EX", 초단위시간);
만약 24시간내 까지만 해당 데이터를 사용하고 삭제하고자 한다면, 아래와 같이 해주면 된다.
redis객체.set(key, value, "EX", 86400);
<hset와 set의 차이>
hset의 경우 이름에서 알 수 있듯 hash를 이용하는 것이고, 메모리 효율과 관리 이점이 있을수 있다. 그러나, 무엇보다 큰 차이는 아래와 같은 방법으로 하나의 key에 subkey1 : value1, subkey2 : value2, subkey3 : value3 ... 등의 형태로 데이터들을 쌓을 수 있다는 것이다.
redis객체.hset("key네임", "field1", "value1");
앞서 말한 subkey의 역할을 field가 하는 것이고, 하나의 키에 multi field를 구성하여 효율과 관리의 편의를 높인다.
<hset함수에서 expire time>
https://stackoverflow.com/questions/16545321/how-to-expire-the-hset-child-key-in-redis
(위 내용 참고)
stackoverflow에 참조되어 남겨진 redis의 창시자 Quoth Antirez 말에 따르면 hset에서는 expire 조건설정이 불가능하다. hset은 내부적으로 각각의 다른 sub key를 가지고 동작하기에 애플리케이션으로 하여금 각각의 key별 expired time을 판단하게 하는 것은 불가능하다고 말한다.(좀더 논리적인 이유는 찾아보시길 바랍니다.)
그래서 특정 field별로 데이터를 삭제하려면 hdel 함수를 직접 사용해야 한다.
예를 들어) rdb로 관리되는 특정 key값을 redis에도 field로 넣어놓고 사용한다고 가정하자. 이때 특정 key값의 상태값이 변경되었고, redis에서도 삭제해야 한다면, 필드명을 알고 있기에 바로 hdel을 이용하여 삭제가 가능할것.
<sorted set 또는 zset의 사용이유>
zadd는 zset의 함수이고, zset은 set자료형중에 정렬된 set자료형이다. set이나 map(딕셔너리)등의 자료형은 기본적으로 순서가 없는 자료형이다. 그러나, 내부적으로 또 다른 변수값을 두어 정렬이 가능하도록 할 수 있다.(이는 속도의 효율을 저하시키는 한다) java의 linkedhashmap 등을 생각해보면 될것이다. redis에서는 score라는 변수를 set내부에 둠으로서 score를 통해 자료들을 정렬시킨다.
redis객체.zadd("key네임", "score값", "value");
위와 같은 형식으로 zset에서는 zadd함수를 사용하여 데이터를 add하는데, 여기서 중요한것은 score값일 것이다. score값을 가지고 자료들을 정렬 시키므로, 정렬에 기준값이 되는 숫자값을 주는게 일반적이다. 실무에서는 특정 시간값을 number값으로 score에 넣곤 한다.
zset을 사용하는 이유는 여러가지가 있겠지만, zset의 특성은 score로 정렬된 set이라는 것이다. 그래서, 대표적으로 최신값을 가져오기 위해 특정 시간값을 score로 넣어 정렬시켜 최신의 set데이터를 가져오기 위한 목적이 있다. 또한, 어떤 값의 price나 수량 같은 것들 중 가장 큰 값을 가져오는 용도 등으로 사용할 수가 있다. 이는 score를 어떤 값으로 주느냐에 따라 달라질 것이다.
<zadd함수에서 expire time>
https://stackoverflow.com/questions/7577923/redis-possible-to-expire-an-element-in-an-array-or-sorted-set
(위 내용 참고)
zset구조에서도 키안에 멤버데이터인 score가 있기 때문에, expire time은 세팅하기 어려운것으로 보인다. 그러므로, zset구조에서 score별 데이터를 삭제하기 위해서 가장 일반적인 방법은 score 범위별로 데이터를 삭제하는 것이다.
예를 들어, 1시간에 한번씩 timestamp값으로 score와 value가 세팅된다고 가정해보자. 데이터가 끝없이 쌓이면 안되므로 30일이 지난 데이터는 삭제해야 한다고 가정하자. 스케쥴러를 주기적으로 돌려 score가 개수를 count하여 원하는 개수를 초과했을 경우 삭제시키도록 하면 될것이다. javascript 코드로 예를 들면
const count = await this.redis.zcard("key값");
if (count > 720) {
await redis객체.zpopmin("key값");
}
zcard는 해당 key안에 들어있는 멤버개수 count값을 리턴해주고, 그 count는 1시간에 1개 쌓이므로 1*24*30 = 720 을 하게 되면 30일에 쌓이는 count의 개수가 나오게 될 것이다.
해당 count값을 초과하는 데이터들은 pop을 시키되, score기준으로 min값을 pop을 시키면 가장 오래된(즉, 가장 낮은 score값)만이 삭제가 될 것이다.
<그외 - key namespaced data 형식>
redis의 키로 사용하는 데이터의 형식을 정할때, 아래와 같은 형식으로 사용하는 것은 흔한일이다. 아래에서 key로 사용된 user:bob:email 이게 무슨 형식인가 싶을 것이다. redis초창기부터 사용해오던 namespaced data 방식인데,
redis객체.set("user:bob:email", "bob@example.com");
여기서 user:bob:email은 그것 통째로 하나의 string형식의 하나의 key일 뿐이다. 만약에 user:james:email이라는 키가 하나 더 있다면 이 둘은 서로 관계 없는 독립적인 key이다. 다만, user라는 접두어(prefix)를 사용함으로서 해당 key들이 user에 대한 정보와 관계가 있는 데이터들이라는 것을 직관적으로 알게 해준다. 더불어 user로 grouping하거나, 정렬하기에도 좋은 형식이 된다.(medis로 위 데이터들을 set해보면, user라는 묶음으로 그룹핑 되어서 조회되는것을 알수있다.)