Foundry
URL 단축기 설계
심화
핵심

겹쳤을 때 다루기

확인과 저장을 한 번에 해야 틈이 없다

무작위로 뽑기로 했으니 드물게 겹칩니다. 사용률이 1퍼센트 미만이라 100번에 한 번 미만입니다. 드문 일을 어떻게 다루는지가 이 절의 주제입니다.

확인하고 저장하면 틈이 생긴다

확인 후 저장하면 그 사이에 다른 요청이 끼어들 수 있고 조건부 저장은 저장소가 판정한다 확인하고 넣으면 가: 없다 확인 나: 없다 확인 둘 다 저장한다 하나가 덮인다 조건부로 넣으면 가: 성공 나: 실패 저장소가 판정 실패한 쪽은 다시 뽑는다 확인과 저장을 한 번에 해야 틈이 없다

"이 키가 있는지 확인하고 없으면 저장한다" 는 두 단계입니다. 그 사이에 다른 요청이 같은 키를 저장할 수 있습니다.

초당 100 규모에서 이 틈이 실제로 걸리는지 계산해 봅니다. 겹칠 확률이 1퍼센트 미만이고 그중 두 요청이 같은 순간에 겹치는 것은 훨씬 드뭅니다. 드물지만 0이 아니고, 걸리면 링크 하나가 다른 대상으로 덮입니다.

사용자는 자기 링크가 남의 사이트로 가는 것을 보게 됩니다. 되돌릴 수 없는 종류의 오류입니다.

조건부 저장으로 저장소가 판정하게 한다

확인과 저장을 하나의 연산으로 만듭니다. "이 키가 없을 때만 저장" 을 저장소에 맡기면 둘 중 하나만 성공합니다.

가: 성공
나: 실패. 다시 뽑아 다시 시도

실패한 쪽은 새 키를 뽑습니다. 사용자는 그 사실을 알 필요가 없습니다.

키에 유일 제약을 걸어 두는 것이 가장 단순한 구현입니다. 제약 위반을 재시도 신호로 다룹니다.

재시도 횟수에 상한을 둔다

몇 번을 다시 뽑아도 계속 실패하면 두 가지 중 하나입니다.

원인신호
키 공간이 예상보다 많이 찼다실패율이 서서히 오른다
무작위 생성기가 고장났다실패율이 갑자기 치솟는다

두 경우 모두 사람이 알아야 합니다. 그래서 상한을 두고 넘으면 오류로 응답하며 경보를 올립니다. 무한히 재시도하면 그 요청이 서버 자원을 붙잡고, 원인은 감춰집니다.

재시도 횟수는 지표로도 남깁니다. 평균 시도 횟수가 곧 키 공간 사용률의 실측값이라 길이를 늘려야 할 시점을 알려 줍니다.

덮어쓰기를 절대 허용하지 않는다

키 저장에서 덮어쓰기를 허용하면 이 모든 장치가 무의미해집니다. 조건부 저장의 반대가 덮어쓰기입니다.

그리고 만료된 키를 되살리는 경로도 같은 위험을 만듭니다. 만료 처리와 새 발급이 같은 키를 다룰 수 있기 때문입니다. 이 문제는 마지막 개념에서 다룹니다.

사용자 지정 키가 들어오면

요구사항에서는 범위 밖이지만 나중에 추가될 수 있습니다. 그때는 사용자가 고른 키와 우리가 뽑는 키가 같은 공간을 씁니다.

미리 준비할 것은 하나입니다. 조건부 저장이 이미 있으면 사용자 지정 키도 같은 경로로 처리되고, 겹치면 사용자에게 "이미 쓰이는 키" 라고 알리면 됩니다. 구조가 준비돼 있으면 기능 추가가 작은 일이 됩니다.

면접에서 이렇게 나옵니다

Q.키가 겹쳤을 때 어떻게 처리하시겠습니까

확인과 저장을 하나의 연산으로 만들고, 실패하면 다시 뽑습니다.

"확인하고 없으면 저장" 은 두 단계라 그 사이에 다른 요청이 같은 키를 저장할 수 있습니다.

이 키가 없을 때만 저장한다
둘 중 하나만 성공한다
실패한 쪽은 새 키를 뽑아 다시 시도한다

키에 유일 제약을 걸어 두고 제약 위반을 재시도 신호로 다루는 것이 가장 단순한 구현입니다.

흔한 실수: 겹칠 확률이 낮으니 확인 후 저장으로 충분하다고 보는 것. 걸리면 링크 하나가 다른 대상으로 덮입니다. 사용자가 자기 링크를 눌렀을 때 남의 사이트로 가고, 되돌릴 수 없습니다.

Q.재시도를 몇 번까지 하시겠습니까

상한을 두고 넘으면 오류로 응답하며 경보를 올립니다.

계속 실패하면 원인이 둘 중 하나입니다.

원인신호
키 공간이 예상보다 찼다실패율이 서서히 오른다
무작위 생성기가 고장났다실패율이 갑자기 치솟는다

두 경우 모두 사람이 알아야 합니다. 무한히 재시도하면 그 요청이 자원을 붙잡고 원인은 감춰집니다.

그리고 평균 시도 횟수를 지표로 남깁니다. 그 값이 키 공간 사용률의 실측값이라 길이를 늘려야 할 시점을 알려 줍니다.

흔한 실수: 재시도 횟수를 넉넉히 두고 지표를 남기지 않는 것. 그러면 사용률이 올라가는 것을 아무도 모르고, 어느 날 갑자기 실패가 사용자에게 보이기 시작합니다.

Q.키 저장에서 덮어쓰기를 허용하면 어떻게 되나요

조건부 저장의 모든 장치가 무의미해집니다. 덮어쓰기가 조건부 저장의 반대입니다.

두 요청이 같은 키를 뽑았을 때 나중 것이 먼저 것을 덮으면, 먼저 만든 사용자의 링크가 조용히 다른 대상으로 바뀝니다.

그 사실을 알아챌 방법이 없습니다. 오류도 나지 않고 지표에도 남지 않습니다.

같은 위험이 만료 처리에도 있습니다. 만료된 키를 지우는 작업과 새 키 발급이 같은 키를 다룰 수 있습니다.

흔한 실수: 편의를 위해 저장을 덮어쓰기로 구현하는 것. 대부분의 저장에서는 무해한 선택이지만 키가 곧 사용자와의 약속인 곳에서는 가장 위험한 선택입니다.

Q.사용자 지정 키를 나중에 추가하려면 무엇을 준비하나요

조건부 저장이 이미 있으면 준비가 끝난 것입니다.

사용자가 고른 키와 우리가 뽑는 키가 같은 공간을 쓰므로 겹칠 수 있습니다. 조건부 저장 경로를 그대로 쓰면 겹칠 때 실패하고, 사용자에게 "이미 쓰이는 키" 라고 알리면 됩니다.

우리가 뽑은 키가 실패하면 다시 뽑는다
사용자가 고른 키가 실패하면 사용자에게 알린다

같은 판정에 다른 대응을 붙이는 것뿐입니다.

흔한 실수: 사용자 지정 키를 별도 저장소나 별도 공간에 두려는 것. 그러면 두 공간을 모두 확인해야 조회가 되고, 리디렉션 경로에 왕복이 하나 늘어납니다. 지연 예산이 그것을 허용하지 않습니다.

먼저 스스로 답해보고 아래 답변과 견줘보세요. 막히는 부분은 문제로 확인할 수 있어요.

읽었으면 문제로 확인해보세요

URL 단축기 설계 문제를 풀면 틀린 문제가 자동으로 노트에 쌓입니다. 가입 없이 5문제를 먼저 풀어볼 수도 있어요.