AWSMiddleTechnical

SQS Standard vs FIFO — в чём разница?

Standard — неограниченный TPS, at-least-once доставка, порядок не гарантирован; FIFO — строгий порядок внутри MessageGroupId, exactly-once, лимит 300 TPS (3000 с батчингом).

SQS Standard vs FIFO

Amazon SQS предлагает два типа очередей с принципиально разными гарантиями. Выбор зависит от требований к порядку сообщений и идемпотентности вашей системы.

Standard Queue

Standard — очередь с максимальной пропускной способностью и минимальными гарантиями порядка.

  • Пропускная способность: неограниченная (nearly unlimited TPS).
  • Доставка: at-least-once — сообщение может быть доставлено более одного раза. Потребитель обязан быть идемпотентным.
  • Порядок: best-effort — порядок не гарантируется, сообщения могут прийти не в том порядке, в котором были отправлены.
  • Цена: $0.40 за 1 миллион запросов.
  • Подходит для: email-рассылки, генерация отчётов, обработка изображений, задачи где дублирование или перестановка допустимы.

FIFO Queue

FIFO (First-In-First-Out) обеспечивает строгий порядок и exactly-once обработку внутри группы.

  • Пропускная способность: 300 TPS (без батчинга) или 3000 TPS с батчингом по 10 сообщений.
  • Доставка: exactly-once — дедупликация по MessageDeduplicationId (5-минутное окно).
  • Порядок: строгий внутри MessageGroupId. Разные группы обрабатываются параллельно.
  • Имя очереди: обязательно оканчивается на .fifo.
  • Цена: $0.50 за 1 миллион запросов.
  • Подходит для: банковские транзакции, обработка заказов, машины состояний, где порядок критичен.

Создание и отправка сообщений (Python / boto3)

import boto3, uuid

sqs = boto3.client("sqs", region_name="eu-central-1")

# --- Standard Queue ---
std_url = "https://sqs.eu-central-1.amazonaws.com/123456789012/my-standard-queue"

sqs.send_message(
    QueueUrl=std_url,
    MessageBody='{"event": "user.registered", "user_id": 42}',
)

# --- FIFO Queue ---
fifo_url = "https://sqs.eu-central-1.amazonaws.com/123456789012/my-order-queue.fifo"

sqs.send_message(
    QueueUrl=fifo_url,
    MessageBody='{"event": "order.created", "order_id": 99}',
    MessageGroupId="order-99",          # строгий порядок внутри группы
    MessageDeduplicationId=str(uuid.uuid4()),  # уникальный ID для exactly-once
)

Получение и удаление сообщений

# Получить до 10 сообщений, visibility timeout 30 сек
response = sqs.receive_message(
    QueueUrl=fifo_url,
    MaxNumberOfMessages=10,
    WaitTimeSeconds=20,   # long polling
    VisibilityTimeout=30,
)

for msg in response.get("Messages", []):
    print(msg["Body"])
    # После успешной обработки удалить
    sqs.delete_message(
        QueueUrl=fifo_url,
        ReceiptHandle=msg["ReceiptHandle"],
    )

MessageGroupId и параллелизм в FIFO

MessageGroupId — ключевой механизм масштабирования FIFO. Сообщения с одним GroupId обрабатываются строго последовательно одним потребителем за раз. Сообщения с разными GroupId обрабатываются параллельно. Для ускорения обработки распределяйте сообщения по множеству групп.

# Параллельная обработка: groupId = user_id
# Для одного пользователя — строгий порядок
# Разные пользователи — параллельно
for user_id, event in events:
    sqs.send_message(
        QueueUrl=fifo_url,
        MessageBody=event,
        MessageGroupId=f"user-{user_id}",
        MessageDeduplicationId=str(uuid.uuid4()),
    )

Ключевые различия в одной таблице

  • Порядок: Standard — best-effort; FIFO — гарантированный внутри группы.
  • Дублирование: Standard — возможно (at-least-once); FIFO — исключено в 5-мин окне (exactly-once).
  • TPS: Standard — неограниченно; FIFO — 300 / 3000 с батчингом.
  • Dead Letter Queue: поддерживают оба типа.
  • Lambda trigger: поддерживают оба; для FIFO Lambda обрабатывает сообщения группами.

Подводные камни

  • Standard at-least-once требует идемпотентности: одно и то же сообщение может прийти дважды; без защиты (idempotency key в БД) возможны двойные списания или двойные записи.
  • FIFO throughput лимит жёсткий: при пиковой нагрузке 300 TPS легко исчерпать; батчинг (SendMessageBatch до 10 сообщений) увеличивает до 3000, но не безлимитно.
  • MessageGroupId блокирует параллелизм: если все сообщения в одной группе, обработка будет строго последовательной — один consumer за раз, независимо от числа воркеров.
  • Окно дедупликации 5 минут: повторный MessageDeduplicationId блокирует доставку на 5 минут; после истечения то же значение снова будет принято.
  • Visibility timeout: если обработка занимает больше времени, чем visibility timeout, сообщение станет снова видимым и будет доставлено повторно — нужно вызывать ChangeMessageVisibility.
  • Нельзя конвертировать тип очереди: Standard нельзя превратить в FIFO и наоборот — нужно создавать новую очередь и мигрировать.
  • Long polling обязателен: без WaitTimeSeconds=20 возникают пустые получения, которые тоже тарифицируются и увеличивают стоимость.

Common mistakes

  • Не делать Standard consumer idempotent.
  • Считать FIFO глобально последовательной без group design.
  • Создавать один message group для всего high-throughput workload.

What the interviewer is testing

  • Различает at-least-once и FIFO ordering.
  • Понимает message group ID и deduplication.
  • Учитывает throughput/concurrency trade-offs.

Sources

Related topics