작업을 바로 처리하지 않고 큐에 넣어 두는 구조로 바꾸니 응답이 빨라졌다. 대신 전에 없던 문제가 생겼고 첫째가 같은 작업이 두 번 처리되는 것이었다.
Table of contents
Open Table of contents
최소 한 번이라는 보장
처음에는 우리가 두 번 넣은 줄 알았는데 확인해 보니 한 번이었다. 처리가 끝나고 완료 신호를 보내기 전에 죽거나 처리가 길어져 시간 초과로 판단되거나 연결이 잠깐 끊기면 재배달이 일어난다.
대부분의 큐가 보장하는 것은 최소 한 번이지 정확히 한 번이 아니다. 두 번 올 수 있다는 것이 결함이 아니라 전제이므로 그 전제 위에서 처리를 짜야 한다.
두 번 와도 괜찮게 만드는 두 방법
하나는 메시지의 고유 번호를 기록해 두고 이미 있으면 건너뛰는 것이다. 번호가 없으면 보내는 쪽에서 붙이게 했다.
여기에 함정이 있어서 확인과 기록 사이에 다른 처리가 끼면 둘 다 통과한다. 유일 제약으로 막았고 다른 하나는 여러 번 해도 결과가 같아지게 연산을 바꾸는 방법인데 알림 발송처럼 안 되는 것은 앞의 방법을 써야 했다.
순서가 보장되지 않는다
처리하는 쪽이 여럿이라 나중에 넣은 것이 먼저 처리되는 일이 있었다. 생성과 수정이 뒤집히면 수정할 대상이 없어 실패한다.
처리기를 하나로 줄이면 순서는 지켜지지만 큐를 쓴 이유가 없어진다. 그래서 같은 대상의 작업은 같은 처리기로 가게 하고 다른 대상끼리는 병렬로 두었다.
실패한 것을 빼 두는 자리
계속 재시도하면 영원히 실패하는 것이 큐를 막아 뒤의 정상 작업까지 밀린다. 바로 버리면 일시적 문제였을 때도 잃는다.
몇 번 재시도한 뒤 따로 빼 두는 방식으로 갔는데 처음에 그 자리를 안 봤다. 몇 주 뒤에 열어 보니 수백 건이 쌓여 있었으므로 빼 두는 것만으로는 부족하고 보는 절차가 있어야 했다.
밖에서는 정상으로 보이는 지연
큐가 밀려도 접수만 하는 응답은 여전히 빠르다. 밖에서 보면 정상인데 실제로는 처리가 안 되고 있는 상태가 되는데 이것은 큐를 쓰기 전에는 없던 문제다.
쌓인 개수와 넣은 시각에서 처리한 시각까지의 차이를 함께 봤다. 개수가 적어도 오래된 것이 남아 있으면 문제이므로 뒤쪽이 더 정확한 지표였다.
정리
- 큐는 대개 최소 한 번을 보장하고 정확히 한 번이 아니다
- 두 번 오는 것은 결함이 아니라 전제다
- 고유 번호를 기록하거나 여러 번 해도 결과가 같게 만든다
- 확인과 기록 사이의 틈은 유일 제약으로 막는다
- 순서가 보장되지 않으므로 같은 대상을 같은 처리기로 보낸다
- 실패를 계속 재시도하면 뒤의 정상 작업까지 밀린다
- 빼 두는 것만으로는 부족하고 보는 절차가 있어야 한다
- 접수 응답은 빠르므로 쌓인 개수와 처리 지연을 따로 본다