Getting Started with JayNats: Zero-Copy Real-time CDC in Minutes
A tutorial-style blog post showcasing JayNats as a zero-copy, low-latency messaging broker with seamless CDC
If you're building real-time applications, you've probably dealt with messaging brokers and change data capture (CDC) separately. Kafka for events, Debezium for CDC, Redis for caching—the modern microservices architecture is a symphony of moving parts.
But what if I told you that you could have zero-copy, low-latency messaging with type-safe CDC in a single Java library?
Enter JayNats - a production-ready messaging broker built with Java's Foreign Function & Memory API, optimized for sub-microsecond latency with zero-copy operations. It just so happens to ship with CDC out of the box.
What is JayNats?
JayNats is, first and foremost, a zero-copy, low-latency messaging broker powered by Java's new FFM API. While it ships with CDC capabilities as a showcase feature, its core mission is providing the fastest, most efficient message passing in the JVM ecosystem.
Key Features
- Zero-copy operations with FFM for unparalleled performance
- Sub-microsecond latency for message processing
- Built-in CDC with automatic schema discovery
- Type-safe JOOQ Records - no JSON, no manual parsing
- Simple, consistent API across all use cases
- Production-ready with real-time demo at https://akilisha.com
Beyond CDC: JayNats as a Messaging Broker
Before diving into CDC, let's see JayNats in its primary role: zero-copy messaging. The beauty is the API remains consistent whether you're doing simple pub/sub or advanced CDC.
Event-Driven Architecture
import com.jaynats.stream.MessageBroker;
import com.jaynats.stream.SimpleMessageBroker;
MessageBroker broker = new SimpleMessageBroker();
broker.createTopic("user-events", 1).get();
// Publisher
broker.publish("user-events", "User registered: john@example.com".getBytes()).get();
// Subscribers
broker.subscribe("user-events", message -> {
System.out.println("📧 " + new String(message.data()));
});
Microservices Communication
// Service A: Order Service
MessageBroker broker = new SimpleMessageBroker();
broker.createTopic("orders", 1).get();
broker.publish("orders", orderJson.getBytes()).get();
// Service B: Payment Service (in a different process)
broker.subscribe("orders", message -> {
Order order = parseOrder(message.data());
processPayment(order);
});
Pub/Sub Patterns
// Multiple subscribers to the same topic
broker.subscribe("notifications", message -> {
emailService.send(new String(message.data()));
});
broker.subscribe("notifications", message -> {
smsService.send(new String(message.data()));
});
// Publish once, fan out to all
broker.publish("notifications", "User logged in".getBytes()).get();
Real-Time Data Streaming
// High-frequency sensor data with zero-copy performance
broker.createTopic("sensor-data", 1).get();
void onSensorReading(double temperature) {
byte[] data = serialize(temperature);
broker.publish("sensor-data", data).get(); // Sub-microsecond latency!
}
broker.subscribe("sensor-data", message -> {
double temp = deserialize(message.data());
updateDashboard(temp);
});
Notice the pattern? Simple, consistent, powerful. The same API works for everything.
The Live Demo
Before we dive into the code, check out the live demo at https://akilisha.com. Connect your PostgreSQL database and watch changes appear in real-time with type-safe, zero-copy event processing!
Getting Started - It's Actually This Simple
The beauty of JayNats is in its simplicity. For CDC, you simply provide your JDBC credentials. That's it. Schema discovery, model generation, trigger creation, and type-safe event mapping are all handled automatically by the library.
Step 1: Add Dependencies
Gradle:
dependencies {
implementation 'com.akilisha.oss:jaynats-stream:1.0.0'
implementation 'com.akilisha.oss:jaynats-stream-cdc:1.0.0'
}
Maven:
<dependency>
<groupId>com.akilisha.oss</groupId>
<artifactId>jaynats-stream</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>com.akilisha.oss</groupId>
<artifactId>jaynats-stream-cdc</artifactId>
<version>1.0.0</version>
</dependency>
Or clone the repository from GitHub to build locally.
Step 2: Write Some Code
import com.jaynats.stream.cdc.CDCManager;
import com.jaynats.stream.cdc.generated.tables.records.UsersRecord;
public class RealTimeApp {
public static void main(String[] args) {
// Just provide your database URL
CDCManager cdc = new CDCManager(
"jdbc:postgresql://localhost:5432/mydb",
"output/models"
);
// Start CDC - the library handles EVERYTHING
try {
cdc.startCDC("users", "orders").get();
System.out.println("✅ CDC started! Schema discovered, models generated, ready to go!");
// Subscribe with type-safe JOOQ Records
cdc.subscribeToTableTyped("users", UsersRecord.class, event -> {
UsersRecord user = event.getData(); // ← Typed JOOQ Record!
System.out.println("📧 Email: " + user.getEmail());
System.out.println("👤 Name: " + user.getName());
// Full IDE autocomplete, compile-time safety!
});
// Or use the flexible API for JSON access
cdc.subscribeToTable("orders", event -> {
String json = event.getJsonData(); // ← Raw JSON available too
System.out.println("📦 Order: " + json);
});
// Keep running
Thread.sleep(Long.MAX_VALUE);
} catch (Exception e) {
e.printStackTrace();
}
}
}
That's it! No manual triggers. No SQL setup. No schema management. Just JDBC credentials.
What Happens Under the Hood
When you call startCDC("users", "orders"), JayNats:
- ✅ Connects to your PostgreSQL database
- ✅ Discovers the schema for the specified tables
- ✅ Generates JOOQ model classes (
UsersRecord,OrdersRecord, etc.) - ✅ Creates database triggers automatically
- ✅ Sets up real-time LISTEN/NOTIFY connections
- ✅ Maps events to typed JOOQ Records
All transparently. Zero manual work.
Type Safety Out of the Box
The real magic is in the type safety. No more parsing JSON strings:
// Before (manual JSON parsing)
cdc.subscribeToTable("users", event -> {
String json = event.getJsonData();
JSONObject obj = new JSONObject(json);
String email = obj.getString("email"); // 😰 Runtime error prone
});
// After (JOOQ Records)
cdc.subscribeToTableTyped("users", UsersRecord.class, event -> {
UsersRecord user = event.getData(); // ← Strongly typed!
String email = user.getEmail(); // ← IDE autocomplete!
Integer id = user.getId(); // ← Compile-time type checking!
}); // 😎 Refactoring-safe, validation at compile time
Streaming to the Live Demo
Want to see your database changes on https://akilisha.com in real-time?
Quick Start
# Build the CDC CLI
./gradlew :jaynats-stream-cdc:build
# Run it
java -jar jaynats-stream-cdc/build/libs/jaynats-stream-cdc-1.0.0.jar \
--url jdbc:postgresql://localhost:5432/mydb \
--target https://akilisha.com
Visit https://akilisha.com, start the demo, and your database changes appear in real-time with zero-copy performance!
Why JayNats?
🚀 Zero-Copy Performance
- Java FFM API for zero-copy memory operations
- Sub-microsecond latency for message processing
- Virtual threads for massive concurrency
🎯 Intelligent, Self-Aware
- Automatic schema discovery - just provide credentials
- Zero configuration - it figures out what to do
- Type-safe by default - JOOQ Records everywhere
🏗️ Production-Ready
- Single JVM process - no external dependencies
- Modern Java 23 with latest features
- Live demo at https://akilisha.com
🎨 Consistent API Across Use Cases
The same simple API works for everything:
// Standalone messaging
broker.publish("events", data);
broker.subscribe("events", handler);
// CDC (with zero-copy underneath)
cdc.startCDC("users", "orders");
cdc.subscribeToTableTyped("users", UsersRecord.class, handler);
Whether you're building event-driven architectures, microservices communication, or real-time database synchronization, JayNats provides the same intuitive, consistent experience. No learning curve when switching between use cases.
Advanced Use Cases
Real-time Analytics
cdc.subscribeToTableTyped("orders", OrdersRecord.class, event -> {
OrdersRecord order = event.getData(); // ← Typed!
updateDashboard(order.getAmount(), order.getCustomerId());
});
Event Sourcing
cdc.subscribeToAllChanges(event -> {
eventStore.append(event); // ← Type-safe event stream
});
Microservices Sync
cdc.subscribeToTableTyped("users", UsersRecord.class, event -> {
UsersRecord user = event.getData(); // ← Zero JSON conversion!
distributedCache.put(user.getId(), user);
});
The Philosophy
JayNats is intelligent and self-aware. You shouldn't have to:
- ❌ Manually create triggers
- ❌ Write SQL procedures
- ❌ Parse JSON strings
- ❌ Manage schema manually
- ❌ Learn different APIs for different use cases
You just provide credentials for CDC or create a broker for messaging. JayNats handles the rest, delivering typed, zero-copy events with sub-microsecond latency and a consistent, intuitive API across all use cases.
From simple pub/sub to complex CDC, the same beautiful simplicity throughout.
Next Steps
- Try the live demo: https://akilisha.com
- Check out the code: GitHub
-
Explore examples: Clone and check
jaynats-examplesmodule
JayNats: Zero-copy messaging with intelligent CDC. Just add credentials. 🚀
For the latest updates and contributions, visit GitHub
Top comments (0)