// Python Dev

RabbitMQ как мост между внешним и внутренним контуром

Опубликовано 03.04.2026

Брокеры очередей обычно воспринимаются как инструмент внутри одной системы — развязать микросервисы, сгладить пики нагрузки, организовать фоновые задачи. Но есть куда менее очевидное применение: использовать брокер как точку доступа к данным, которые физически находятся внутри организации и наружу не выходят.

На практике любая попытка дать внешний доступ к внутренним данным быстро превращается в инфраструктурный проект: согласования, безопасность, сетевые ограничения. Даже простая задача вроде «получить баланс клиента» может упереться в недели работы и участие нескольких команд.


Данные внутри, запрос снаружи

Типичная ситуация: есть внешнее приложение — личный кабинет, мобильное приложение или партнёрский сервис — которому нужно получить актуальные данные из внутренней системы. Например, баланс клиента из биллинга.

Стандартные варианты здесь один хуже другого. Открыть порт наружу — самый очевидный, который первым же и отклоняют безопасники, и правильно делают. Поднять VPN — звучит разумно, но на практике это отдельный проект со своими согласованиями, сертификатами и поддержкой, и далеко не всегда возможный на стороне внешней системы, особенно если это чужое облако. Белый IP — его может просто не быть: провайдер даёт динамику за NAT, и пробросить соединение снаружи внутрь без дополнительной инфраструктуры невозможно. Для небольших компаний и филиалов это совершенно обычная ситуация.

Реальный кейс

В одном из проектов нужно было реализовать Telegram-бота для провайдера, через которого пользователь мог посмотреть текущий баланс. Проблема в том, что биллинг-система находилась в закрытом контуре внутри датацентра и имела SOAP API, доступный только изнутри сети. Открывать доступ наружу было запрещено, VPN на стороне бота реализовать невозможно, а сам бот работал в облаке. В итоге даже простой запрос «показать баланс» превращался в задачу интеграции между полностью изолированными системами.


Брокер снаружи как точка встречи

Идея простая, но неочевидная: поднять инстанс RabbitMQ не внутри организации, а снаружи — рядом с внешним приложением, на публично доступном сервере. Этот брокер одновременно доступен и внешней системе, и внутренней — потому что внутренний сервис сам инициирует исходящее соединение наружу, а исходящие соединения, в отличие от входящих, почти никогда не блокируются файрволом или NAT.

Схема получается такая: внешнее приложение кладёт запрос в очередь на брокере. Сервис внутри организации слушает эту очередь, забирает запрос, идёт в биллинг или любой другой внутренний источник, и кладёт ответ в другую очередь. Внешнее приложение забирает ответ.

Данные попадают наружу ровно тогда, когда они нужны, и только те, которые были запрошены. Внутренняя система остаётся закрытой — она сама решает, когда и что отдавать.


RPC поверх очередей: асинхронность без боли

Очевидная сложность такой схемы — асинхронность. Когда запросов много, нужно понимать, какой ответ относится к какому запросу. Можно маркировать каждое сообщение вручную, но RabbitMQ предоставляет готовый механизм — RPC поверх очередей.

Работает это так: клиент при отправке запроса указывает имя временной очереди, на которую ждёт ответ (reply_to), и уникальный correlation_id. Внутренний сервис обрабатывает запрос и отправляет ответ не в общую очередь, а напрямую на эту временную очередь с тем же correlation_id. Клиент просто ждёт своего ответа — без лишней логики маршрутизации.

Реализовывать это руками необязательно — RPC поверх RabbitMQ уже поддерживают готовые библиотеки. Например, FastStream предоставляет удобный декларативный интерфейс: подписчик на очередь описывается как обычная async-функция, а механизм reply_to и correlation_id библиотека берёт на себя. Код становится компактнее и читается как обычный сервис, а не как работа с брокером напрямую.

Ниже — минимальный пример на pika, чтобы было понятно, что происходит под капотом.

Клиент (внешняя система)

import pika, uuid

connection = pika.BlockingConnection(pika.ConnectionParameters('broker.example.com'))
channel = connection.channel()

# Временная очередь для ответа — RabbitMQ сам её удалит после отключения
result = channel.queue_declare(queue='', exclusive=True)
reply_queue = result.method.queue
correlation_id = str(uuid.uuid4())

channel.basic_publish(
    exchange='',
    routing_key='billing.requests',
    properties=pika.BasicProperties(
        reply_to=reply_queue,
        correlation_id=correlation_id,
    ),
    body='{"client_id": 42, "action": "get_balance"}'
)

# Ждём ответа именно на наш запрос
for method, props, body in channel.consume(reply_queue):
    if props.correlation_id == correlation_id:
        print(f"Баланс: {body.decode()}")
        channel.cancel()
        break

Обработчик (внутренний сервис)

import pika, json

connection = pika.BlockingConnection(pika.ConnectionParameters('broker.example.com'))
channel = connection.channel()
channel.queue_declare(queue='billing.requests')

def on_request(ch, method, props, body):
    request = json.loads(body)
    balance = get_balance_from_billing(request['client_id'])  # обращение к внутреннему источнику

    ch.basic_publish(
        exchange='',
        routing_key=props.reply_to,
        properties=pika.BasicProperties(correlation_id=props.correlation_id),
        body=str(balance)
    )
    ch.basic_ack(delivery_tag=method.delivery_tag)

channel.basic_consume(queue='billing.requests', on_message_callback=on_request)
channel.start_consuming()

Это превращает асинхронное взаимодействие в почти синхронное с точки зрения кода: отправил запрос — подождал — получил ответ. При этом никакого дополнительного состояния хранить не нужно.


Что в итоге

Такая схема закрывает сразу несколько проблем без лишней инфраструктуры: не нужен белый IP, не нужен VPN, не нужно открывать доступ во внутренний контур. Авторизация и шифрование решаются на уровне RabbitMQ — TLS и credentials заменяют всю инфраструктуру API-ключей и токенов. Развернуть это можно за день-два: два небольших сервиса и один инстанс брокера.

Это не универсальный инструмент. Но в задачах, где нужно дать доступ к данным из закрытого контура по запросу — биллинг, внутренние CRM, учётные системы — это один из самых простых и дешёвых вариантов. Для потоковой передачи больших объёмов или сценариев с жёсткими требованиями по задержке схема подходит хуже — там уже нужны другие инструменты.

// Python Dev

Другие статьи Python Dev

Все статьи

// Python Projects

Проекты Python Dev

Все проекты

// Contact

Нужна помощь?

Свяжись со мной и я помогу решить проблему

Отправить заявку
Написать и получить быстрый ответ