Why this matters
- VaultCommerce order-service creates one
KafkaProducerper JVM at startup — expensive to construct per request. - Serializer choice (String vs Avro) is fixed at producer creation and affects Schema Registry integration.
bootstrap.serversis only for initial metadata discovery — producers learn partition leaders dynamically.- First hands-on step before tuning acks, batching, or idempotence.
Minimal producer configuration
VaultCommerce's baseline producer sets bootstrap.servers to all three seed brokers, StringSerializer for keys (orderId), and KafkaAvroSerializer for values registered in Schema Registry. client.id includes pod name for traceability in broker logs.
Key points
- bootstrap.servers — initial broker list for cluster metadata discovery
- Serializers — convert key/value objects to bytes before send
- client.id — logical name in broker metrics and logs
- KafkaProducer — thread-safe; share one instance across application threads
- ProducerRecord — topic, optional partition, key, value, headers, timestamp
Lifecycle and resource management
Call producer.close(Duration) on shutdown to flush pending batches. Spring Boot's KafkaTemplate wraps a singleton producer. Never create a new producer per HTTP request — connection setup adds 50–200ms and exhausts broker connection limits.
VaultCommerce rollout checklist
Before promoting changes that touch vaultcommerce.orders.placed.v1 and vaultcommerce.payments.captured.v1, run the staging KRaft cluster (Kafka 3.7+, Schema Registry 7.x) through a 10k events/min soak test. Compare producer request latency p99 and consumer lag per group against the pre-deploy baseline. One shared producer per JVM. Document the change in the internal topic registry, attach Grafana screenshots to the change ticket, and keep an engineer on lag dashboards for 30 minutes after production rollout — roll back the service release before altering broker-level settings if lag or under-replicated partitions spike.
// VaultCommerce order-service — producer bean (Kafka 3.7+, Java 17)
@Configuration
public class KafkaProducerConfig {
@Bean
KafkaProducer<String, OrderPlaced> orderProducer(
@Value("${vault.kafka.bootstrap}") String bootstrap) {
Properties props = new Properties();
props.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrap);
props.put(ProducerConfig.CLIENT_ID_CONFIG, "order-service-" + hostname());
props.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
props.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, KafkaAvroSerializer.class);
props.put(ProducerConfig.ACKS_CONFIG, "all");
props.put("schema.registry.url", "https://schema-registry:8081");
return new KafkaProducer<>(props);
}
}
Quick recall
Everything you need if you only revisit this box.
- One shared producer per JVM.
- Serializers are set at construction time.
- bootstrap.servers is for discovery, not routing.
Test yourself
Answer these before moving on — recall is what makes it stick.