조회 초당 1만 를 모두 받기로 했습니다. 누적 300억 개 중에서 키 하나를 찾는 일을 50ms 안에 끝내야 합니다.
조회는 소수의 링크에 몰린다
링크는 공유되면서 조회가 폭발하고 대부분은 거의 열리지 않습니다. 며칠 전에 만든 링크는 사실상 조회되지 않습니다.
그래서 누적 300억 개 을 모두 빠르게 찾을 필요가 없습니다. 인기 있는 소수를 메모리에 두면 대부분의 조회가 거기서 끝납니다.
| 캐시에 담는 양 | 덮는 조회 |
|---|---|
| 인기 상위 소수 | 대부분 |
| 전체 | 필요 없다. 담을 수도 없다 |
이 편중이 이 설계를 값싸게 만드는 성질입니다. 편중이 없다면 누적 300억 개 을 모두 빠르게 찾아야 하고 훨씬 비싼 설계가 됩니다.
캐시에 무엇을 어떻게 담나
키를 열쇠로, 목적지 주소를 값으로 담습니다. 값이 짧아 메모리 효율이 좋습니다.
담는 규칙은 단순합니다. 조회했는데 없으면 저장소에서 찾아 캐시에 넣습니다. 오래 안 쓰인 것부터 밀어냅니다.
만료를 짧게 둘 이유가 없습니다. 키와 목적지의 대응은 거의 바뀌지 않기 때문입니다. 다만 링크가 만료되거나 삭제될 때 캐시에서 지워야 하고, 그 처리를 빼먹으면 만료된 링크가 계속 동작합니다.
없는 키 조회가 문제가 된다
없는 키로 요청이 오면 캐시에 없고 저장소에도 없습니다. 그 요청은 매번 저장소까지 갑니다.
정상 사용자도 이런 요청을 만듭니다. 오타나 잘린 링크가 그렇습니다. 그런데 키를 훑어 보는 시도가 있으면 그 요청이 대량으로 들어옵니다.
| 대응 | 내용 |
|---|---|
| 없다는 사실도 캐시에 담는다 | 같은 키의 반복 요청을 막는다 |
| 요청량을 제한한다 | 훑어 보기를 늦춘다 |
없다는 사실을 담을 때는 짧게 둡니다. 방금 만든 키를 없다고 기억하면 그 링크가 잠깐 동작하지 않습니다.
저장소는 무엇으로 고르나
조회가 키 하나로 값 하나를 가져오는 형태뿐입니다. 범위 조회도, 여러 키를 묶는 트랜잭션도 필요 없습니다.
키-값 저장소가 정확히 맞는 모양입니다. 6장의 설계가 그것이고, 이 서비스는 그 저장소의 전형적인 사용자입니다.
캐시가 비면 무슨 일이 생기나
캐시 서버를 재시작하거나 늘리면 캐시가 비고, 그동안 모든 조회가 저장소로 갑니다. 초당 1만이 그대로 저장소를 때립니다.
앞의 아키타입에서 본 문제와 같습니다. 한 번에 비우지 않고 조금씩 채우는 방법으로 다룹니다. 캐시 서버를 늘릴 때 담당을 조금씩 옮기는 것이 안정 해시 설계에서 다룬 그 절차입니다.