Skip to content
isdnetworks
Go back

명령 하나에 서버가 멈췄다

세션이 몇 개나 있는지 궁금해서 redis-cli 로 붙어 KEYS * 를 쳤다. 그 순간 게임 접속이 멈췄다.

Table of contents

Open Table of contents

세션 수를 세려던 명령

몇 초 뒤에 결과가 나왔는데 키가 이백팔십만 개가 넘었다. 그동안 서비스 전체가 응답을 못 하고 있었다.

조회만 하는 명령이라 아무 영향이 없을 것으로 생각했다. 실제로는 그 시간 동안 다른 모든 요청이 대기하고 있었다.

Redis 는 명령을 한 번에 하나씩 처리한다. 여러 요청이 동시에 와도 순서대로 하나씩 처리하고 그동안 나머지는 기다린다.

이 성질 덕분에 INCR 같은 것이 여러 요청에 섞여도 자료가 안 깨진다. 대신 오래 걸리는 명령이 하나 들어오면 그 시간 동안 전부가 멈춘다. KEYS 가 정확히 그런 종류였다.

자료구조 크기에 비례한다

KEYS 는 저장된 키 전체를 훑는다. 매뉴얼에도 복잡도가 데이터베이스의 키 개수에 대한 O(N) 이라고 적혀 있고 운영 환경에서는 극도로 조심해서 쓰라고 경고한다. 디버깅이나 키 구조를 바꾸는 특별한 작업용이지 평소 코드에 넣을 것이 아니라는 말도 함께 있다.

같은 성질을 가진 명령이 더 있었다. SMEMBERS 로 집합 원소를 전부 가져오거나 LRANGE 0 -1 로 목록 전체를 가져오는 것들이다. 전부 자료구조의 크기에 비례해서 시간이 든다. 개발할 때는 자료가 적어서 이 성질이 안 드러난다.

매뉴얼은 노트북에서 백만 개짜리를 40 밀리초에 훑는다고 적어 뒀다. 우리는 몇 초가 걸렸는데 훑는 시간보다 이백팔십만 개의 키 문자열을 한 번에 만들어 보내는 쪽이 컸던 것으로 보인다.

나눠서 훑는 방법

전체를 훑어야 할 때는 SCAN 을 쓰라고 매뉴얼이 안내한다. 커서를 받아서 조금씩 나눠 훑는 방식이다.

한 번에 조금만 보고 돌아오므로 그 사이에 다른 요청이 처리된다. 대신 훑는 도중에 자료가 바뀌면 같은 키가 두 번 나올 수 있다. 정확한 스냅숏 대신 서비스가 안 멈추는 것을 얻는 교환이었다.

크기를 모르는 채로 전부 달라고 하지 않는다

개수만 필요한 경우에는 훑지 않고 얻는 방법도 있었다. DBSIZE 는 키 개수를 바로 돌려주고 SCARDLLEN 도 마찬가지다. 세션을 집합 하나에 모아 두면 SCARD 한 번이면 끝난다.

운영 서버에서는 rename-commandKEYS 자체를 못 쓰게 만들었다. 조심하는 것보다 못 하게 하는 것이 확실하다. 크기를 모르는 채로 전부 달라고 하지 않는 것이 이 일에서 남은 규칙이었다.

정리


Share this post on:

Previous Post
서버를 사는 대신 빌려 쓰기 시작했다 — 처음 한 달의 기록
Next Post
두 처리기가 같은 작업을 집었다