Solace PubSub+ and RabbitMQ are both smart-broker systems: the broker holds state, routes each message, and tracks acknowledgements. That is the opposite of Kafka’s distributed-log model where consumers track their own offsets. Because both Solace and RabbitMQ share the queue-and-route paradigm, the messaging concepts carry over cleanly. The real work is mapping Solace’s topic hierarchy onto RabbitMQ’s exchange-and-binding model and repointing your applications without losing messages.
Why teams leave Solace
The usual driver is licensing. Solace appliances and software brokers are sold per-connection and per-throughput tier, and the bill grows with every new service that connects. RabbitMQ is open source, runs on commodity VMs or Kubernetes, and has no per-connection license. If your volume is moderate and you do not need Solace’s hardware acceleration, the math often favors moving.
Topic hierarchies become exchanges and bindings
Solace routes on a hierarchical topic string like orders/us/west/created, with wildcards * (one level) and > (everything below). RabbitMQ does the same job with a topic exchange and routing keys, where * matches one word and # matches zero or more.
The translation is direct:
- Solace topic subscription
orders/us/>becomes a RabbitMQ binding with routing keyorders.us.#. - Solace
orders/*/west/createdbecomesorders.*.west.created. - A Solace durable queue with a topic subscription becomes a RabbitMQ queue bound to a topic exchange.
Note the separator changes from / to ., so any code that builds topic strings needs a small rewrite or a translation shim.
Declare the topology explicitly rather than letting it form implicitly:
rabbitmqadmin declare exchange name=orders type=topic durable=true
rabbitmqadmin declare queue name=orders.us.west durable=true \
arguments='{"x-queue-type":"quorum"}'
rabbitmqadmin declare binding source=orders \
destination=orders.us.west routing_key="orders.us.#"
Which client to point your apps at
If your apps use JMS against Solace, RabbitMQ ships a JMS client over AMQP 1.0, so much of the interface survives. The cleaner path for new code is the native AMQP 0-9-1 client, which exposes RabbitMQ’s confirms and prefetch directly.
Whatever client you pick, set these for parity with Solace guaranteed messaging:
- Publisher confirms on, so the broker acknowledges persisted messages.
delivery_mode=2(persistent) on every message that mattered as a Solace guaranteed message.- Consumer
prefetchtuned, since RabbitMQ pushes by default and an unbounded prefetch will swamp a slow consumer.
Bridging during cutover
Do not flip everything at once. Run both brokers in parallel and bridge them so producers can move independently of consumers. The Shovel plugin pulls from a Solace queue (over AMQP) and republishes into a RabbitMQ exchange, letting you migrate consumers first, then producers, then retire the Solace path.
Sequence the cutover per queue family rather than per application, since a single app often touches several flows with different guarantees. Move the consumers for one family onto RabbitMQ first and let the shovel feed them from Solace, so nothing is lost while the producers still publish to Solace. Once those consumers are stable, repoint the matching producers to RabbitMQ and let the residual Solace queue drain through the shovel to zero. Watch both brokers during the window: a Solace queue whose depth stops falling usually means a consumer never actually moved, and an unrouted message on the RabbitMQ side usually means a binding does not match the topic mapping you declared. Only retire the Solace path for a family once its queues are empty and the RabbitMQ flow has soaked under real load.
Validating what Solace gave you for free
- Ordering: Solace preserves per-queue order. RabbitMQ preserves order within a single queue and single consumer, but parallel consumers or requeue-on-nack can reorder. Pin ordering-sensitive flows to one consumer, or use a consistent-hash exchange to keep a key on one queue.
- Persistence: match Solace’s spool with durable queues plus persistent messages. Both ends must be durable or a restart drops the message.
- Dead-letter handling: Solace DMQs map to a dead-letter exchange. Set
x-dead-letter-exchangeand a routing key on the queue. - HA: replace Solace’s redundant pair with quorum queues, which use Raft replication across nodes. Classic mirrored queues are deprecated; do not build new HA on them.
Where Solace still wins
Be honest about this before you commit:
- Raw throughput. Solace hardware appliances push millions of messages per second with predictable latency. RabbitMQ on VMs will not match that ceiling.
- Multi-protocol bridging. Solace natively speaks MQTT, AMQP, JMS, REST, and WebSocket on one broker and bridges between them. RabbitMQ needs plugins and is less seamless.
- Dynamic routing and event mesh. Solace’s global event mesh links brokers across regions with dynamic message routing. RabbitMQ federation is coarser.
- Enterprise support. A vendor SLA covering production incidents is worth real money to some teams.
And if a workload is high-volume streaming with replay and large fan-out, neither broker is ideal: route that to Kafka instead of forcing it into RabbitMQ.
So, is it worth it?
Because Solace and RabbitMQ are both smart-broker systems, the migration is tractable: topics become topic exchanges, subscriptions become bindings, guaranteed messaging becomes durable quorum queues with confirms, and a Shovel bridge lets you cut over gradually. You give up appliance throughput, multi-protocol bridging, and event mesh, so keep streaming workloads on Kafka and keep Solace where its hardware and protocol breadth earn their license. Model the broker licensing you would shed against the VM, ops, and support cost of self-hosting RabbitMQ in the calculator above before you commit to the move.