이후에 쓴 관련 포스트
Memcached에서 사용하는 시간
Memcached flush_all 두번째
2일전에 강대명님과 twitter @zerocool_kor님의 캐쉬에대한 트윗을 뒤늦게 보고 뒷북 트윗 날리면서 훼방 놓았었는데 최근에 바로 블로그 포스트까지 나와 포스트 주소도 함께 올립니다. 좋은 정보는 다음은 블로그를 통해 확인해주세요. :-) 링크와 훼방 트윗.
[분산캐시] Redis 와 memcache의 flush는 왜 다를까?
훼방 트윗 1
훼방 트윗 2
위의 블로그 포스트에서도 잘 설명해주셨지만 memcached와 redis는 flush에대한 처리가 완전히 다르므로 memcached 기준으로 side-effects를 설명하고자 합니다. (참고로 memcached, redis 둘 다 잘 몰라요. 틀리더라도 너그럽게 이해해주세요.)
안성화팀장님과 캐쉬팀에 있으면서 많은 부분 배운 것을 토대로 합니다. (제게 많은 insight를 주시는 분) – 팀장님이 블로깅은 안하신다고 하여 제가 적습니다. 저는 주워 먹는 사람. 이것 때문에 flush by prefix 기능이 탄생된 배경입니다.
주의깊게 사용하신다면 문제되지 않을 수도 있는데 듣고 보면 생각이 달라질 수도 있으실겁니다.
생각해보니 memcached에대한 첫 글!
문제에 앞서 되짚어 볼 사항은
- memcached 의 flush는 지우는 것이 아닌 marking
- GET operation이 발생할 때 expire check 후 제거 (정확히는 link만 끊고 재활용)
redis와 다르게 flush시에 제거하지 않았을 경우 생길 수 있는 문제가 될 수 있는 시나리오를 생각해보면
Normal Flow
# 참고로 아래 예는 ASCII 프로토콜과는 다르며 이해를 위해 옵션은 제거한 것 입니다.
> set acts:row:123
{"actor": {"id": 1}}
> get acts:row:123
{"actor": {"id": 1}}
> flush_all
OK
> get acts:row:123
END
Alternative Flow
# 참고로 아래 예는 ASCII 프로토콜과는 다르며 이해를 위해 옵션은 제거한 것 입니다.
> set acts:row:123
{"actor": {"id": 1}}
> get acts:row:123
{"actor": {"id": 1}}
> flush_all
OK
> flush_all 1000
OK
> get acts:row:123
{"actor": {"id": 1}}
위의 경우를 보면 알 수 있듯이 flush_all은 추가 옵션이 있는데 이를 생략하면 즉시 flush를 시키는 것(물론 지우지 않습니다.) 생략하지 않으면 입력한 초만큼 지연시킨 후 flush 합니다. (이 해석은 정확하지 않아서 보다 정확하게 바꿉니다.) 생략하지 않으면 입력한 시간(memcached 에서는 두가지 형태의 시간)을 기준으로 flush 시킵니다 (지연되는 효과가 있습니다. 근데 생각해보니 효과가 어짜피 지연인 것 같네요. ㅡㅁㅡ;). 물론 의도한 상황이 아니라면 stale data가 나옵니다. (의도한 것은 flush 시켜서 나오지 않게 하는 것 이니) 물론!! 이렇게 사용하는 경우가 있을지는 모르겠습니다만 ㅋㅋ
if (exptime > 0)
settings.oldest_live = realtime(exptime) - 1;
else /* exptime == 0 */
settings.oldest_live = current_time - 1;
정리하면 첫 번째 flush_all 후, 추가 exptime(0보다 큰 상황일 때)과 함께 flush_all를 하면 oldest_live는 커지며 GET operation이 발생해도 지워지지 않습니다.
또한 flush_all을 해도 지워지지 않는 경우가 한가지 더 있습니다.
* 다들 예상하시겠지만 flush_all 후 server 시간을 뒤로 돌리고 조회하면 제거되지 않습니다. (flush_all exptime 과 같은 효과죠)
flush_all 는 항상 주의해야할 것 중 하나는 cache를 비웠다는 것이죠. 모두 DB 등과 같은 외부시스템에 부하가 발생합니다. ㅋㅋ
일단 이번 포스트는 여기까지 쓰는 것으로 마무리하겠습니다. 즐거운 주말되세요. :-)
실제 ASCII 프로토콜 시연예제는 다음과 같습니다.
$ telnet localhost 11211 Trying ::1... Connected to localhost. Escape character is '^]'. set row:1 0 0 5 HELLO STORED get row:1 VALUE row:1 0 5 HELLO END flush_all OK flush_all 100 OK get row:1 VALUE row:1 0 5 HELLO END
생큐 베리 감사합니다 저희는 따로 옵션을 안주고 그대로 날리니 이런 문제가 없었군요
그리고 정확히는 flush_all 의 뒤에 delay 시켜서 지우라는 뜻이 아니고, 해당 시간 이전의 데이터들을 전부 expire 시키라는 뜻입니다. ^^ 30일 이전 시간은 memcached에서 쭈욱 바꿔 생각하는 거 아시잖아요 ㅋㅋㅋ, 그래서 30일 이전의 시간은 delay와 같은 효과가 나는거죠 ㅎㅎㅎ
음냐, 적고 나니 설명이 ㅋㅋㅋ 어려운데, exptime 을 가진 녀석들에게는 그 시점에 삭제되고, exptime이 없는 넘들은 그 시간이 되어야 삭제되는 delay 효과가 납니다
더 정확한 설명 감사합니다. :-) 제가 expire 없는 것에 초점을 두고 결과 중심의 해석을 했네요! delay 란 단어가 이해를 어렵게한 측면이 있는 것 같습니다. 바꿔야겠어요. ㅋㅋ
아, 뭔가 제가 잘못알고 있는 듯한 느낌이 ㅋㅋㅋ, 일단 제가 좀 더 보고 다시 적을께요. 웬지 제가 지금 잘못된 정보를 넘긴다는 느낌을 지울수가 없네요 ㅋㅋ
근데 리플보고 고치려고했는데 생각해보니 delay란 단어는 안 적었네요 ㅋㅋㅋㅋ 어쨌든 보충이 필요한 것 같아요. 너무 심플하게 적었네. ㅎㅎ
다시 보니… 지연이라고 한글로 적었군요. ㅋㅋ ㅡ.,ㅡ;
@charsyam 그래도 댓글은 저에게 힘이 됩니다. ㅋㅋ 우하하하 감솨… 이런 과정도 좋습니다. ㅋㅋ
정확하게 delay가 맞습니다. ㅋㅋㅋ, 제가 코드를 잘못봤네요 ㅋㅋㅋ, 다만, delay 시간 보다 expire 가 뒤로 지정된 아이템의 경우 바로 삭제됩니다. 이게 정확하네요 ㅋㅋㅋ, 완전 잘못된 정보로 블로깅 할뻔했어요 ㅋㅋㅋ
좀 더 정리하려고 했는데 벌써 하셨네요. ㅋㅋ 저도 일단 헷갈리게 적은 것부터 다 수정해야겠어요.
[...] http://geekdani.wordpress.com/2012/05/19/memcached-flush-%EC%82%AC%EC%9A%A9%EC%8B%9C-%EC%A3%BC%EC%9D… [...]
저도 글 하나 포스팅 했습니다. ㅎㅎㅎ 보시고 틀린부분 지적부탁드려요 ㅎㅎㅎ