Amazon SQS
고친 사람 github-actions[bot]
Amazon SQS 는 일을 맡기는 쪽과 그 일을 처리하는 쪽이 서로를 모른 채 일을 주고받게 해 줍니다. 아마존이 운영하는 큐 서비스입니다. 맡기는 쪽은 할 일을 큐에 넣고 바로 자기 일로 돌아갑니다. 처리하는 쪽은 여유가 생겼을 때 하나씩 꺼내 갑니다.
쉽고 빠른 이해
SQS 는 나중에 할 일을 적어 두는 줄입니다. 주문을 받은 서버가 「이 주문의 영수증 메일을 보내라」 라는 쪽지를 줄에 던져 놓으면, 메일을 담당하는 서버가 그 쪽지를 가져가 처리합니다.
줄이 없으면 주문 서버가 메일 서버를 직접 불러야 합니다. 메일 서버가 느려지면 주문 응답까지 같이 느려지고, 메일 서버가 멈추면 주문도 실패합니다. 줄을 사이에 두면 한쪽이 멈춰도 다른 쪽은 하던 일을 계속합니다.
어떻게 도나:
- 보내는 쪽이 메시지를 큐에 넣습니다
- 받는 쪽이 큐에 물어보고 메시지를 받아 갑니다
- 다 처리한 메시지는 받는 쪽이 직접 지웁니다
대가가 있습니다. 넣은 순서대로 나온다는 약속이 기본 큐에는 없습니다. 같은 메시지를 두 번 받는 일도 생깁니다. 받는 쪽은 두 번 처리해도 결과가 달라지지 않게 짜야 합니다.
상세
이 절은 SQS 를 세 갈래로 나눠 봅니다. 서버를 두지 않는다는 것이 무엇을 바꾸는지, 메시지 하나가 들어와 사라지기까지 어떤 단계를 거치는지, 이 큐가 약속하지 않는 것이 무엇인지입니다. 주문이 들어오면 영수증 메일을 보내는 일감을 줄곧 예로 씁니다.
SQS 는 Simple Queue Service 의 줄임말입니다. AWS(Amazon Web Services, 아마존 웹 서비스)가 빌려주는 서비스 가운데 하나입니다. 설치하는 프로그램이 아니라 아마존이 운영하는 서버에 요청을 보내 쓰는 물건입니다.
보내는 쪽과 받는 쪽을 떼어 놓는다
큐는 들어온 순서대로 쌓아 두었다가 하나씩 꺼내는 줄입니다. SQS 가 이 줄을 두 프로그램 사이에 놓으면, 두 프로그램이 서로를 직접 부르지 않게 됩니다.
메시지를 넣는 쪽을 생산자, 꺼내 가는 쪽을 소비자라고 부릅니다. 생산자는 소비자가 어느 서버에 몇 대 떠 있는지 모릅니다. 아는 것은 큐의 이름 하나뿐입니다. 큐에서 메시지를 꺼내 처리하는 이 프로그램을 워커라고도 부릅니다.
flowchart TD
P["주문 서버 · 생산자"] --> Q["SQS 큐"]
Q --> W1["메일 워커 1"]
Q --> W2["메일 워커 2"]
Q --> W3["메일 워커 3"]
이렇게 떼어 놓으면 소비자가 멈춰도 생산자는 계속 돕니다. 메일 워커가 전부 내려가 있어도 주문은 정상으로 받아지고, 메시지는 큐에 쌓인 채 기다립니다. 워커가 올라오면 쌓인 것부터 처리합니다.
속도 차이도 큐가 흡수합니다. 주문이 한꺼번에 몰리는 동안에는 큐가 불어나고, 한산해지면 워커가 밀린 것을 따라잡습니다. 큐가 감당할 수 없을 만큼 계속 쌓이면 그때는 워커를 늘립니다.
워커를 여러 대로 늘려도 조율할 일이 없습니다. 한 메시지는 한 워커에게만 건네지므로, 워커들이 서로 「이건 내가 가져간다」를 말할 필요가 없습니다.
서버를 두지 않는 큐
큐를 직접 세우려면 메시지를 맡아 두는 프로그램인 메시지 브로커를 어딘가에 띄워야 합니다. 그 순간 브로커는 지켜야 할 서버가 하나 더 늘어난 것입니다.
지켜야 할 것이 적지 않습니다. 브로커가 쓰는 디스크가 차지 않게 봐야 하고, 한 대가 죽어도 큐가 살아 있게 이중화해야 하고, 판올림도 직접 합니다. 브로커가 멈추면 그 큐에 기대던 서비스가 전부 함께 섭니다.
SQS 는 이 서버를 아마존이 대신 굴리게 합니다. 쓰는 쪽은 큐 이름을 하나 만들고 요청을 보내면 됩니다. 담을 수 있는 메시지 수를 미리 정하지 않아도 되고, 몰려들면 몰려드는 만큼 받아 둡니다.
대가는 이 큐가 우리 네트워크 안에 없다는 것입니다. 넣고 꺼내는 일이 전부 인터넷 너머로 오가는 요청이라 한 번 왕복하는 시간이 붙습니다. 요청을 보낸 수만큼 요금도 붙습니다.
붙잡히는 것도 있습니다. 큐를 다루는 코드가 AWS 의 호출 방식에 맞춰 쓰이므로, 나중에 다른 곳으로 옮기려면 그 코드를 고쳐야 합니다. 이렇게 한 사업자의 방식에 매이는 것을 벤더 고착이라고 부릅니다.
누가 이 큐에 넣고 꺼낼 수 있는지도 우리가 짜지 않습니다. AWS 의 권한 관리 서비스인 AWS IAM(Identity and Access Management, 신원 및 접근 관리)에 「이 역할은 이 큐에서 메시지를 받아도 된다」를 적어 두는 방식입니다.
받는 쪽이 물어서 가져간다
SQS 와는 HTTP(HyperText Transfer Protocol) 요청으로 이야기합니다. 넣을 때도 꺼낼 때도 지울 때도 각각 요청 하나를 보냅니다.
여기서 관리형 서비스다운 모양이 하나 나옵니다. 큐가 워커에게 연결을 걸어 메시지를 밀어 주지 않습니다. 워커가 「가져갈 것 있나」를 스스로 물어봅니다. 이렇게 받는 쪽이 주기적으로 물어보는 방식을 폴링이라고 부릅니다.
빈 큐에 계속 물어보면 빈손으로 돌아오는 요청만 쌓입니다. 그래서 요청을 받은 큐가 바로 「없다」 고 답하지 않고 메시지가 들어올 때까지 잠깐 기다렸다 답하는 방식을 씁니다. 이것을 롱 폴링이라고 부릅니다.
가져가도 바로 사라지지 않는다
메시지를 건네자마자 지워 버리면, 그 메시지를 받은 워커가 처리 도중에 죽었을 때 일감이 통째로 없어집니다. SQS 는 지우는 일을 워커에게 맡겨서 이 구멍을 막습니다.
워커가 메시지를 받으면 그 메시지는 큐에서 사라지지 않고 잠시 다른 워커에게 안 보이는 상태가 됩니다. 이 안 보이는 기간을 가시성 타임아웃이라고 부릅니다. 워커는 처리를 끝낸 뒤에 삭제 요청을 따로 보내고, 그때 메시지가 없어집니다.
sequenceDiagram
participant 워커
participant 큐
워커->>큐: 메시지 달라
큐-->>워커: 영수증 메일 보내라
Note over 큐: 이 메시지를 잠시 감춘다
워커->>큐: 다 했다. 지워라
Note over 큐: 삭제 요청이 안 오면 다시 보이게 한다
그래서 처리 중에 워커가 죽어도 일감이 남습니다. 삭제 요청이 오지 않은 채 감춰 두는 기간이 끝나면 메시지가 다시 보이고, 다른 워커가 그것을 가져갑니다.
감추는 기간은 처리에 걸리는 시간보다 넉넉하게 잡습니다. 처리가 아직 안 끝났는데 메시지가 다시 보이면, 같은 일을 다른 워커가 한 번 더 하게 됩니다.
두 번 처리될 수 있다
처리를 끝내고 삭제 요청을 보내기 직전에 워커가 죽으면, 그 메시지는 이미 처리됐는데도 다시 보이게 됩니다. 다음 워커가 같은 일을 또 합니다.
이렇게 「빠뜨리지는 않지만 두 번 갈 수는 있다」는 약속을 적어도 한 번 전달이라고 부릅니다. 메시지를 잃지 않는 쪽을 택하면 중복은 따라옵니다.
그래서 받는 쪽이 같은 메시지를 두 번 처리해도 결과가 한 번 처리한 것과 같아야 합니다. 이 성질을 멱등성이라고 부릅니다. 영수증 메일이라면 이미 보낸 주문 번호를 적어 두고, 같은 번호가 또 오면 보내지 않는 식입니다.
계속 실패하는 메시지는 따로 모은다
내용이 깨진 메시지는 몇 번을 가져가도 처리에 실패합니다. 실패하면 다시 보이고, 다시 가져가고, 또 실패합니다. 이렇게 큐를 맴돌며 워커를 붙잡는 메시지를 독약 메시지라고 부릅니다.
SQS 는 되돌아온 횟수를 세어 두었다가, 정해 둔 횟수를 넘긴 메시지를 다른 큐로 옮깁니다. 이렇게 실패한 메시지만 모으는 큐를 데드 레터 큐라고 부릅니다.
본 큐는 막히지 않고 계속 돕니다. 사람은 나중에 데드 레터 큐만 열어 무엇이 왜 실패했는지 살펴봅니다.
순서와 중복을 어디까지 약속하나
SQS 의 큐는 두 종류입니다. 하나는 표준 큐이고, 다른 하나는 넣은 순서대로 꺼낸다는 뜻의 FIFO(First In First Out, 먼저 들어온 것이 먼저 나간다) 큐입니다. 무엇을 약속하고 무엇을 포기하는지가 다릅니다.
| 표준 큐 | FIFO 큐 | |
|---|---|---|
| 순서 | 넣은 순서와 달라질 수 있습니다 | 넣은 순서 그대로 나옵니다 |
| 중복 | 같은 메시지가 두 번 올 수 있습니다 | 같은 메시지를 걸러 냅니다 |
| 받아 내는 양 | 더 많이 받습니다 | 표준 큐보다 적게 받습니다 |
순서를 지키려면 앞엣것이 나가기 전에 뒤엣것을 먼저 내보낼 수 없습니다. 그만큼 한꺼번에 받아 낼 수 있는 양이 줄어듭니다.
고르는 기준은 순서가 결과를 바꾸느냐입니다. 「계좌를 만들고 입금한다」처럼 뒤바뀌면 틀리는 일은 FIFO 큐로 갑니다. 영수증 메일처럼 순서가 결과를 안 바꾸는 일은 표준 큐로 갑니다.
큐에 담지 않는 것
한 메시지에 담을 수 있는 크기에는 상한이 있습니다. 이미지나 첨부 파일처럼 큰 것은 Amazon S3(Simple Storage Service, 심플 스토리지 서비스) 같은 저장소에 두고, 큐에는 그 저장소에서 찾을 이름만 실어 보냅니다.
큐는 보관소도 아닙니다. 아무도 안 가져간 메시지는 한동안 기다리다 지워집니다. 나중에 다시 들춰 봐야 하는 기록이라면 큐 말고 저장소나 데이터베이스에 따로 남깁니다.
지나간 메시지를 다시 읽을 수도 없습니다. 한 번 삭제되면 그것으로 끝입니다. 같은 메시지를 여러 소비자가 각자 읽어야 하거나 지난 것을 처음부터 다시 흘려보내야 하면 Apache Kafka 처럼 읽은 뒤에도 남기는 방식을 찾습니다.
한 메시지를 여러 곳에 동시에 보내는 일도 큐 하나로는 안 됩니다. 한 메시지는 한 소비자에게만 가기 때문입니다. 이럴 때는 Amazon SNS(Simple Notification Service) 같은 발행-구독 서비스를 앞에 두고 그 아래에 큐를 여러 개 붙입니다.
관련 항목
Amazon SQS 가 속하는 상위 분류
AWS · 메시지 큐 · 관리형 서비스 · 클라우드 컴퓨팅 · 미들웨어
Amazon SQS 를 이루는 구성 요소
큐 · 메시지 · 생산자 · 소비자 · 워커 · 데드 레터 큐 · 표준 큐 · FIFO 큐
Amazon SQS 가 메시지를 주고받는 방식
폴링 · 롱 폴링 · 가시성 타임아웃 · HTTP · REST API · AWS SDK · 배치 전송
Amazon SQS 가 지키거나 포기하는 전달 성질
적어도 한 번 · 정확히 한 번 · 최대 한 번 · 순서 보장 · 중복 제거 · 멱등성 · 내구성
Amazon SQS 와 짝지어 쓰는 AWS 서비스
Amazon SNS · AWS Lambda · Amazon S3 · Amazon EC2 · CloudWatch · AWS IAM · AWS IoT Core
Amazon SQS 를 대신할 수 있는 다른 메시지 기반
Apache Kafka · RabbitMQ · Amazon MQ · Amazon Kinesis · Redis · Celery
Amazon SQS 가 떠받치는 설계 개념
비동기 처리 · 결합도 · 작업 큐 · 이벤트 기반 아키텍처 · 백프레셔 · 재시도 · 지수 백오프 · 큐잉 이론
Amazon SQS 를 굴릴 때 터지는 문제
독약 메시지 · 중복 처리 · 메시지 유실 · 큐 적체 · 벤더 고착
다른 이름: SQS · Simple Queue Service · 아마존 SQS