Strong answer
Kafka is a durable, partitioned log: ordering is guaranteed only within a partition, consumers in a group share partitions, and delivery is at-least-once unless you engineer otherwise, so consumers must be idempotent. Redis is an in-memory data store used for caching, rate limiting, distributed locks with leases, and short-lived state, and it should be treated as losable unless persistence is configured deliberately. Resilience patterns (timeouts, retries with backoff, circuit breakers, bulkheads, and dead-letter topics) keep partial failures from cascading.
Java example
1@Component
2class PaymentEventsListener {
3 private final ProcessedEvents processed;
4 private final LedgerService ledger;
5
6 PaymentEventsListener(ProcessedEvents processed, LedgerService ledger) {
7 this.processed = processed;
8 this.ledger = ledger;
9 }
10
11 @KafkaListener(topics = "payments.captured", groupId = "ledger")
12 @Transactional
13 void on(PaymentCaptured event) {
14 if (!processed.markIfNew(event.eventId())) return; // idempotent consumer
15 ledger.record(event.orderId(), event.amount());
16 }
17}
18
19@Service
20class ShippingQuotes {
21 @CircuitBreaker(name = "carrier", fallbackMethod = "flatRate")
22 @Retry(name = "carrier")
23 @TimeLimiter(name = "carrier")
24 CompletableFuture<Quote> quote(Parcel parcel) {
25 return CompletableFuture.supplyAsync(() -> carrierApi.quote(parcel));
26 }
27
28 CompletableFuture<Quote> flatRate(Parcel parcel, Throwable cause) {
29 return CompletableFuture.completedFuture(Quote.flat(parcel));
30 }
31}