Back to Kafka Fundamentals: Topics, Partitions, Offsets
Q5Question 5 of 18

When should you choose Kafka over Solace, and when should you choose Solace over Kafka?

Key Concepts
  • Choose Kafka when you need durable event retention, deterministic replay, event sourcing, and stream processing.
  • Choose Solace when consumers have diverse, frequently changing routing needs and you want broker-native hierarchical filtering.
  • Kafka excels at partitioned horizontal scale with per-key ordering and very high sequential throughput.
  • Solace excels at low-latency fan-out to many selective consumers with multi-protocol access.
  • Kafka has a rich ecosystem: Kafka Streams, ksqlDB, Connect, broad client and connector support.
  • The two are complementary, not competing: Solace routes live events, Kafka stores them durably.
  • Forcing one tool into the other's role causes problems: topic proliferation in Kafka or fighting Solace's retention model.

Definition

Choose Kafka when you must store and replay the event history; choose Solace when you must route live events flexibly to ever-changing consumers.

The choice between Kafka and Solace depends on which core model matches your dominant requirement.

  • Kafka – a durable, partitioned, append-only log that excels at long-term retention, deterministic replay, event sourcing, stream processing (Kafka Streams, ksqlDB), and horizontal scale by partition.
  • Solace – a broker-centric message router whose strength is broker-native hierarchical topic routing with wildcard subscriptions, low-latency fan-out, and multi-protocol access (JMS, MQTT, AMQP, REST).
  • Kafka ecosystem – Kafka Streams, ksqlDB, Kafka Connect, Schema Registry, and broad client support give Kafka a rich processing and integration platform.
  • Solace routing – consumers express interest with wildcards, new routing needs are new subscription patterns, and no new topics are created.
  • Complementary use – many banks run both: Solace for real-time selective distribution and Kafka as the durable replayable backbone.

Think of Kafka as National Bank of India's permanent ledger vault. Every transaction is written down in order and kept for years so you can replay the exact history, rebuild any report, and feed analytics. Think of Solace as the bank's smart internal mail room. It does not keep letters forever, but it is brilliant at instantly sorting each letter to exactly the desks that asked for that kind of letter, even as desks keep changing what they want. If your need is "remember everything and replay it," you want the vault. If your need is "deliver the right slice to the right desk right now," you want the mail room.

Understanding the Concepts

When should you choose Kafka?

Choose Kafka when the dominant requirement is durable streaming, replay, or high-throughput event processing.

Durable retention and replay. Kafka retains records on disk for a configured time (days, weeks, or indefinitely with compaction). Each consumer group tracks its own offset, so a consumer can rewind and replay from any point. This is what makes event sourcing possible: the log of events is the source of truth, and you rebuild state by replaying.

BASH
# Reset the settlement consumer group to replay all trade events
bin/kafka-consumer-groups.sh --bootstrap-server kafka-1:9092 \
  --group settlement-group \
  --topic bank.trade-events \
  --reset-offsets --to-earliest --execute
TEXT
Expected output:
GROUP              TOPIC               PARTITION  NEW-OFFSET
settlement-group   bank.trade-events   0          0
settlement-group   bank.trade-events   1          0
settlement-group   bank.trade-events   2          0

Stream processing ecosystem. Kafka Streams lets you write topologies that read topics, do joins, windowed aggregations, and stateful transforms, and write results back to Kafka with exactly-once semantics. ksqlDB lets you express the same logic with SQL.

JAVA
package com.bank.kafka.streams;

import org.apache.kafka.streams.KafkaStreams;
import org.apache.kafka.streams.StreamsBuilder;
import org.apache.kafka.streams.StreamsConfig;
import org.apache.kafka.streams.kstream.KStream;
import org.apache.kafka.streams.kstream.TimeWindows;
import org.apache.kafka.streams.kstream.Materialized;
import org.apache.kafka.common.serialization.Serdes;
import java.time.Duration;
import java.util.Properties;

/**
 * Kafka Streams: count transactions per account in 5-minute windows.
 * Pankaj uses this to detect suspicious activity at National Bank of India.
 */
public class FraudDetectionStream {

    public static void main(String[] args) {
        Properties props = new Properties();
        props.put(StreamsConfig.APPLICATION_ID_CONFIG, "fraud-detection");
        props.put(StreamsConfig.BOOTSTRAP_SERVERS_CONFIG, "kafka-1:9092");
        props.put(StreamsConfig.DEFAULT_KEY_SERDE_CLASS_CONFIG, Serdes.String().getClass());
        props.put(StreamsConfig.DEFAULT_VALUE_SERDE_CLASS_CONFIG, Serdes.String().getClass());

        StreamsBuilder builder = new StreamsBuilder();
        KStream<String, String> transactions = builder.stream("bank.transactions");

        transactions
            .groupByKey()
            .windowedBy(TimeWindows.ofSizeWithNoGrace(Duration.ofMinutes(5)))
            .count(Materialized.as("txn-count-store"))
            .toStream()
            .filter((key, count) -> count > 10)
            .to("bank.suspicious-accounts");

        KafkaStreams streams = new KafkaStreams(builder.build(), props);
        streams.start();
        System.out.println("Fraud detection stream started.");
        System.out.println("Accounts with >10 txns in 5 min -> bank.suspicious-accounts");
    }
}
TEXT
Expected output:
Fraud detection stream started.
Accounts with >10 txns in 5 min -> bank.suspicious-accounts

Partitioned horizontal scale with ordering. A Kafka topic is split into partitions, each an ordered log. All events for one account (keyed by account ID) stay ordered within a partition while the topic scales across brokers and consumers.

JAVA
package com.bank.kafka;

import org.apache.kafka.clients.producer.KafkaProducer;
import org.apache.kafka.clients.producer.ProducerRecord;
import java.math.BigDecimal;
import java.util.Properties;

/**
 * Rajesh produces transactions keyed by account ID.
 * All events for SAV2001 go to the same partition, preserving order.
 */
public class PartitionedOrderProducer {

    public static void main(String[] args) {
        Properties props = new Properties();
        props.put("bootstrap.servers", "kafka-1:9092");
        props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
        props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");
        props.put("acks", "all");

        try (KafkaProducer<String, String> producer = new KafkaProducer<>(props)) {
            String accountId = "SAV2001";
            // All three events for SAV2001 go to the same partition
            producer.send(new ProducerRecord<>("bank.transactions", accountId,
                "{\"type\":\"CREDIT\",\"amount\":" + new BigDecimal("50000.00") + "}"));
            producer.send(new ProducerRecord<>("bank.transactions", accountId,
                "{\"type\":\"DEBIT\",\"amount\":" + new BigDecimal("10000.00") + "}"));
            producer.send(new ProducerRecord<>("bank.transactions", accountId,
                "{\"type\":\"CREDIT\",\"amount\":" + new BigDecimal("75000.00") + "}"));

            System.out.println("3 events for " + accountId + " -> same partition, ordered");
        }
    }
}
TEXT
Expected output:
3 events for SAV2001 -> same partition, ordered

When should you choose Solace?

Choose Solace when the dominant requirement is flexible, broker-side routing to heterogeneous consumers.

Diverse, changing routing needs. Solace lets consumers express interest with hierarchical wildcard subscriptions. When a desk changes what it wants, it adjusts its subscription pattern. No topics are created, no producers are modified.

JAVA
package com.bank.solace;

import com.solacesystems.jcsmp.JCSMPFactory;
import com.solacesystems.jcsmp.JCSMPSession;
import com.solacesystems.jcsmp.JCSMPProperties;
import com.solacesystems.jcsmp.Topic;

/**
 * Priya changes her subscription from all Mumbai to all India.
 * No broker changes, no topic creation, no producer modification.
 */
public class DynamicSubscriptionChange {

    public static void main(String[] args) throws Exception {
        JCSMPProperties properties = new JCSMPProperties();
        properties.setProperty(JCSMPProperties.HOST, "solace-broker:55555");
        properties.setProperty(JCSMPProperties.VPN_NAME, "nbi-vpn");
        properties.setProperty(JCSMPProperties.USERNAME, "priya");

        JCSMPSession session = JCSMPFactory.onlyInstance().createSession(properties);
        session.connect();

        // Remove old subscription
        Topic oldSub = JCSMPFactory.onlyInstance().createTopic("txn/IN/Mumbai/>");
        session.removeSubscription(oldSub);
        System.out.println("Removed: txn/IN/Mumbai/>");

        // Add new subscription: all of India
        Topic newSub = JCSMPFactory.onlyInstance().createTopic("txn/IN/>");
        session.addSubscription(newSub);
        System.out.println("Added: txn/IN/>");
        System.out.println("Priya now receives all India transactions.");
        System.out.println("No topics created. No producer changes.");

        session.closeSession();
    }
}
TEXT
Expected output:
Removed: txn/IN/Mumbai/>
Added: txn/IN/>
Priya now receives all India transactions.
No topics created. No producer changes.

Multi-protocol access. Solace supports JMS, MQTT, AMQP, and REST in addition to its native protocol. This matters in mixed enterprise estates where different systems use different protocols.

Low-latency selective fan-out. Solace delivers only matching messages to each consumer, so consumers stay thin and receive data with low latency.

How do Kafka and Solace compare?

| Feature | Kafka | Solace |
|---|---|---|
| Core model | Durable append-only log | Broker-centric hierarchical router |
| Retention | Days, weeks, or indefinite | Persistence available but not primary strength |
| Replay | Yes, reset offset to any point | Not designed for long-horizon replay |
| Routing | Flat topics, consumer-side filtering | Broker-side wildcard matching |
| Throughput | Very high sequential throughput | Optimized for fan-out, not log throughput |
| Stream processing | Kafka Streams, ksqlDB | External processor needed |
| Protocol | Kafka binary protocol | JMS, MQTT, AMQP, REST, native |
| Topic creation | Explicit, pre-created | Publish-time string, no creation step |
| Consumer diversity | Same topic, same data to all | Wildcard patterns, each consumer gets its slice |
| Ecosystem | Broad: Connect, Schema Registry, clients | Enterprise: bridging, multi-protocol, guaranteed messaging |

JAVA
package com.bank.comparison;

public class KafkaVsSolaceDecision {
    public static void main(String[] args) {
        System.out.println("Decision matrix:");
        System.out.println();
        System.out.println("Need durable retention + replay?     -> Kafka");
        System.out.println("Need event sourcing (log = truth)?   -> Kafka");
        System.out.println("Need stream processing?              -> Kafka");
        System.out.println("Need high sequential throughput?      -> Kafka");
        System.out.println();
        System.out.println("Need diverse, changing routing?       -> Solace");
        System.out.println("Need broker-side wildcard filtering?  -> Solace");
        System.out.println("Need multi-protocol (JMS/MQTT/AMQP)? -> Solace");
        System.out.println("Need low-latency selective fan-out?   -> Solace");
        System.out.println();
        System.out.println("Need both durable storage + routing?  -> Both!");
    }
}
TEXT
Expected output:
Decision matrix:

Need durable retention + replay?     -> Kafka
Need event sourcing (log = truth)?   -> Kafka
Need stream processing?              -> Kafka
Need high sequential throughput?      -> Kafka

Need diverse, changing routing?       -> Solace
Need broker-side wildcard filtering?  -> Solace
Need multi-protocol (JMS/MQTT/AMQP)? -> Solace
Need low-latency selective fan-out?   -> Solace

Need both durable storage + routing?  -> Both!

What are common mistakes in choosing?

Wrong: forcing Kafka to do fine-grained routing.

This causes topic proliferation. Creating hundreds of topics to match Solace-like routing leads to operational nightmares.

JAVA
package com.bank.comparison;

public class WrongForceKafkaRouting {
    public static void main(String[] args) {
        System.out.println("WRONG: Forcing Kafka to route finely");
        System.out.println("  Created 1800 topics for 3 types x 50 cities x 4 acct x 3 sizes");
        System.out.println("  Result: partition explosion, ACL nightmare, days to add a city");
        System.out.println();
        System.out.println("CORRECT: Use Solace for fine-grained routing");
        System.out.println("  One hierarchical namespace, wildcard subscriptions");
        System.out.println("  Adding a city: publisher sends new topic string, done");
    }
}
TEXT
Expected output:
WRONG: Forcing Kafka to route finely
  Created 1800 topics for 3 types x 50 cities x 4 acct x 3 sizes
  Result: partition explosion, ACL nightmare, days to add a city

CORRECT: Use Solace for fine-grained routing
  One hierarchical namespace, wildcard subscriptions
  Adding a city: publisher sends new topic string, done

Wrong: forcing Solace to be a long-horizon replayable ledger.

Solace's persistence model is different from Kafka's partitioned log. Using Solace for seven-year compliance retention and full replay fights its design.

JAVA
package com.bank.comparison;

public class WrongForceSolaceLedger {
    public static void main(String[] args) {
        System.out.println("WRONG: Using Solace as 7-year compliance ledger");
        System.out.println("  Solace is not designed for long-horizon reprocessing");
        System.out.println("  Cannot reset offset and replay months of events");
        System.out.println();
        System.out.println("CORRECT: Use Kafka for durable retention");
        System.out.println("  retention.ms=220752000000 (7 years)");
        System.out.println("  Reset consumer group to earliest and replay all");
    }
}
TEXT
Expected output:
WRONG: Using Solace as 7-year compliance ledger
  Solace is not designed for long-horizon reprocessing
  Cannot reset offset and replay months of events

CORRECT: Use Kafka for durable retention
  retention.ms=220752000000 (7 years)
  Reset consumer group to earliest and replay all

How are they used together in practice?

Many banks run both. Solace handles real-time selective routing to desks. Kafka acts as the durable event backbone for retention, analytics, and event sourcing. A bridge connects them so events flow through both.

JAVA
package com.bank.architecture;

public class ComplementaryArchitecture {
    public static void main(String[] args) {
        System.out.println("=== National Bank of India Architecture ===");
        System.out.println();
        System.out.println("Solace (live routing):");
        System.out.println("  Mumbai desk: txn/IN/Mumbai/>");
        System.out.println("  Large txn monitor: txn/*/*/*/*/large");
        System.out.println("  Brazil ops: txn/BR/>");
        System.out.println("  Each desk gets only its slice, low latency");
        System.out.println();
        System.out.println("Kafka (durable backbone):");
        System.out.println("  bank.transactions topic, 7-year retention");
        System.out.println("  Analytics reads full stream");
        System.out.println("  Compliance replays for audits");
        System.out.println("  Kafka Streams computes fraud scores");
        System.out.println();
        System.out.println("Bridge: Solace -> Kafka Connect sink");
        System.out.println("  Every routed event also lands in Kafka");
        System.out.println("  Kafka is the system of record");
    }
}
TEXT
Expected output:
=== National Bank of India Architecture ===

Solace (live routing):
  Mumbai desk: txn/IN/Mumbai/>
  Large txn monitor: txn/*/*/*/*/large
  Brazil ops: txn/BR/>
  Each desk gets only its slice, low latency

Kafka (durable backbone):
  bank.transactions topic, 7-year retention
  Analytics reads full stream
  Compliance replays for audits
  Kafka Streams computes fraud scores

Bridge: Solace -> Kafka Connect sink
  Every routed event also lands in Kafka
  Kafka is the system of record

What about throughput and latency differences?

Kafka achieves very high throughput because its broker is simple: it appends to a sequential log and reads sequentially from disk. This design is optimized for batched, high-volume workloads. Solace achieves low per-message latency because the broker evaluates subscriptions and delivers directly to interested consumers.

The trade-off is that Kafka's simplicity gives it throughput at the cost of routing flexibility, while Solace's routing intelligence gives it flexibility at the cost of broker CPU.

JAVA
package com.bank.comparison;

public class ThroughputVsLatency {
    public static void main(String[] args) {
        System.out.println("Kafka throughput:");
        System.out.println("  Sequential disk I/O + batching");
        System.out.println("  Millions of records/sec per cluster");
        System.out.println("  Optimized for high-volume streaming");
        System.out.println();
        System.out.println("Solace latency:");
        System.out.println("  Direct broker-to-consumer delivery");
        System.out.println("  Sub-millisecond for matching + delivery");
        System.out.println("  Optimized for selective fan-out");
        System.out.println();
        System.out.println("Choose based on dominant need:");
        System.out.println("  High volume -> Kafka");
        System.out.println("  Low latency selective delivery -> Solace");
    }
}
TEXT
Expected output:
Kafka throughput:
  Sequential disk I/O + batching
  Millions of records/sec per cluster
  Optimized for high-volume streaming

Solace latency:
  Direct broker-to-consumer delivery
  Sub-millisecond for matching + delivery
  Optimized for selective fan-out

Choose based on dominant need:
  High volume -> Kafka
  Low latency selective delivery -> Solace

What about the ecosystem difference?

Kafka has a much larger ecosystem. Kafka Streams and ksqlDB give native stream processing. Kafka Connect provides hundreds of connectors. Schema Registry manages Avro, Protobuf, and JSON schemas. The client library support spans every major language.

Solace has strong enterprise features: multi-protocol access, guaranteed messaging with persistent queues, and bridging capabilities, but it does not have an equivalent native stream-processing ecosystem.

JAVA
package com.bank.comparison;

public class EcosystemComparison {
    public static void main(String[] args) {
        System.out.println("Kafka ecosystem:");
        System.out.println("  - Kafka Streams (Java stream processing)");
        System.out.println("  - ksqlDB (SQL stream processing)");
        System.out.println("  - Kafka Connect (100+ connectors)");
        System.out.println("  - Schema Registry (Avro, Protobuf, JSON)");
        System.out.println("  - Clients: Java, Python, Go, .NET, Node.js, C/C++");
        System.out.println();
        System.out.println("Solace ecosystem:");
        System.out.println("  - Multi-protocol: JMS, MQTT, AMQP, REST, native");
        System.out.println("  - Guaranteed messaging with persistent queues");
        System.out.println("  - Bridging (Solace-Kafka, Solace-Solace)");
        System.out.println("  - Event Portal for design and governance");
        System.out.println("  - No native stream processing (use external)");
    }
}
TEXT
Expected output:
Kafka ecosystem:
  - Kafka Streams (Java stream processing)
  - ksqlDB (SQL stream processing)
  - Kafka Connect (100+ connectors)
  - Schema Registry (Avro, Protobuf, JSON)
  - Clients: Java, Python, Go, .NET, Node.js, C/C++

Solace ecosystem:
  - Multi-protocol: JMS, MQTT, AMQP, REST, native
  - Guaranteed messaging with persistent queues
  - Bridging (Solace-Kafka, Solace-Solace)
  - Event Portal for design and governance
  - No native stream processing (use external)

What should a senior engineer know?

The senior insight is that these are complementary, not competing, and forcing one into the other's role creates problems.

  • Forcing Kafka to route finely causes topic proliferation. Forcing Solace to be a seven-year replayable ledger fights its design.
  • Pick one system of record (usually Kafka) so if the two diverge you know which is authoritative.
  • The bridge between them is a first-class component: monitor it, because a stalled bridge breaks either durability or live delivery.
  • Kafka's operational expertise is more widely available than Solace's, which matters for hiring and on-call.
JAVA
package com.bank.comparison;

public class SeniorDecisionPoints {
    public static void main(String[] args) {
        System.out.println("Senior decision points:");
        System.out.println("1. Match tool to dominant requirement");
        System.out.println("2. Never force one tool into the other's role");
        System.out.println("3. Pick one system of record (usually Kafka)");
        System.out.println("4. Monitor the bridge as first-class infra");
        System.out.println("5. Consider operational expertise availability");
        System.out.println("6. Kafka ecosystem is larger and more mature");
        System.out.println("7. Complementary > competitive");
    }
}
TEXT
Expected output:
Senior decision points:
1. Match tool to dominant requirement
2. Never force one tool into the other's role
3. Pick one system of record (usually Kafka)
4. Monitor the bridge as first-class infra
5. Consider operational expertise availability
6. Kafka ecosystem is larger and more mature
7. Complementary > competitive

Visual Overview

DIAGRAM
  Decision Flow: Kafka vs Solace

  What is the dominant requirement?
         │
         ├── Durable retention + replay?
         │        └── Kafka
         │
         ├── Event sourcing (log = truth)?
         │        └── Kafka
         │
         ├── Stream processing (Streams/ksqlDB)?
         │        └── Kafka
         │
         ├── High sequential throughput?
         │        └── Kafka
         │
         ├── Diverse, changing routing needs?
         │        └── Solace
         │
         ├── Broker-side wildcard filtering?
         │        └── Solace
         │
         ├── Multi-protocol (JMS/MQTT/AMQP)?
         │        └── Solace
         │
         └── Both durable storage + routing?
                  └── Both! (Bridge them)

  Common Bank Architecture:

  ┌──────────────────┐       ┌──────────────────┐
  │   Solace           │       │   Kafka            │
  │   (live routing)   │──────►│   (durable store)  │
  │                    │ bridge│                    │
  │  Mumbai desk ◄─┐  │       │  Analytics group   │
  │  Brazil ops  ◄─┤  │       │  Fraud group       │
  │  Large txn   ◄─┘  │       │  Compliance replay │
  └──────────────────┘       └──────────────────┘

Key Takeaway

The choice between Kafka and Solace comes down to which core model your dominant requirement needs. Kafka is a durable, partitioned, append-only log, so you choose it for long-term retention, deterministic replay, event sourcing, stream processing with Kafka Streams and ksqlDB, and high-throughput partitioned scaling. Solace is a broker-centric hierarchical router, so you choose it when consumers have diverse and frequently changing routing needs, when you want broker-side wildcard filtering without creating new topics, and when multi-protocol access and low-latency selective fan-out matter more than long-term replay.

At National Bank of India, Pankaj applied this split directly. Compliance needed seven-year trade retention and the ability to replay the entire history for audits, so that went to Kafka. Meanwhile, trading desks each wanted a different and often-changing slice of the live transaction feed without waiting for a platform team to create topics, so that went to Solace with wildcard subscriptions. A bridge captured every routed event into Kafka as the authoritative system of record.

The key senior insight is that these are complementary rather than competing. Forcing Kafka to route finely causes topic proliferation, and forcing Solace to be a long-horizon replayable ledger fights its design. Match the tool to the dominant requirement and let them work together.

Remember one sentence: Kafka stores and replays the event history; Solace routes live events flexibly to the right consumers; and in a bank you usually run both.

---

Share
Use ← → arrow keys to navigate