ScyllaDB is a highly scalable NoSQL database, fully compatible with Cassandra Query Language (CQL). Pairing it with Quarkus, a lightweight, cloud-native Java framework, can help small teams build efficient and scalable applications for Kubernetes environments. This article will guide you through setting up ScyllaDB with Quarkus, Kafka integration, Hexagonal architecture using jMolecules, and a robust monitoring solution.
Why Choose Quarkus for ScyllaDB?
Quarkus is designed for cloud-native development, making it an excellent choice for Kubernetes deployments. Its lightweight runtime, fast startup times, and rich ecosystem of extensions simplify development and integration with ScyllaDB. Here’s why it’s ideal for small teams:
- Developer Productivity: Live coding (hot reload) reduces feedback loop time.
- Cloud-Native: Built-in Kubernetes integration for seamless deployment.
- Performance: Optimized for low memory usage and fast startup times.
Setting Up ScyllaDB with Quarkus
1. Add the Cassandra Client Extension
Add the Quarkus Cassandra extension to your project to enable interaction with ScyllaDB:
For Gradle:
implementation("io.quarkus:quarkus-cassandra-client")
2. Configure ScyllaDB in application.properties
Provide connection details for your ScyllaDB cluster:
quarkus.cassandra.contact-points=127.0.0.1:9042
quarkus.cassandra.local-datacenter=datacenter1
quarkus.cassandra.keyspace=my_keyspace
quarkus.cassandra.request.timeout=10s
Replace 127.0.0.1:9042
with your ScyllaDB cluster’s contact points.
3. Use the Cassandra Client in Your Application
Inject the CqlSession
object to interact with ScyllaDB:
import com.datastax.oss.driver.api.core.cql.CqlSession;
import com.datastax.oss.driver.api.core.cql.SimpleStatement;
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
@ApplicationScoped
public class ScyllaDbService {
@Inject
CqlSession session;
public void insertData() {
String query = "INSERT INTO my_table (id, name) VALUES (?, ?)";
session.execute(SimpleStatement.newInstance(query, "123", "Test"));
}
public void fetchData() {
String query = "SELECT id, name FROM my_table";
session.execute(SimpleStatement.newInstance(query))
.all()
.forEach(row -> System.out.println(row.getString("name")));
}
}
4. Optimize Connection Pooling
Fine-tune connection pooling for performance:
quarkus.cassandra.session.builder.connection.pool.local.max=10
quarkus.cassandra.session.builder.connection.pool.remote.max=5
quarkus.cassandra.session.builder.idle.timeout=30s
Integrating Kafka with Quarkus
Apache Kafka is a powerful event streaming platform and a great fit for modern architectures. Quarkus provides seamless Kafka integration through its quarkus-kafka-client
extension.
1. Add Kafka Extension
Include the Kafka extension in your project:
implementation("io.quarkus:quarkus-smallrye-reactive-messaging-kafka")
2. Configure Kafka in application.properties
Provide Kafka broker details:
mp.messaging.incoming.my-topic.connector=smallrye-kafka
mp.messaging.incoming.my-topic.topic=my_topic
mp.messaging.incoming.my-topic.value.deserializer=org.apache.kafka.common.serialization.StringDeserializer
mp.messaging.outgoing.my-topic.connector=smallrye-kafka
mp.messaging.outgoing.my-topic.topic=my_topic
mp.messaging.outgoing.my-topic.value.serializer=org.apache.kafka.common.serialization.StringSerializer
3. Implement a Kafka Listener
Set up a reactive messaging listener:
import org.eclipse.microprofile.reactive.messaging.Incoming;
import javax.enterprise.context.ApplicationScoped;
@ApplicationScoped
public class KafkaConsumer {
@Incoming("my-topic")
public void consume(String message) {
System.out.println("Received message: " + message);
}
}
4. Send Messages to Kafka
Publish messages to Kafka using the reactive messaging API:
import org.eclipse.microprofile.reactive.messaging.Channel;
import org.eclipse.microprofile.reactive.messaging.Emitter;
import javax.inject.Inject;
@ApplicationScoped
public class KafkaProducer {
@Inject
@Channel("my-topic")
Emitter<String> emitter;
public void sendMessage(String message) {
emitter.send(message);
}
}
Adopting Hexagonal Architecture with jMolecules
Hexagonal architecture (also known as Ports and Adapters) promotes separation of concerns, making applications easier to maintain and extend. Using jMolecules helps enforce this pattern.
1. Define Domain Model
Create your domain model with jMolecules annotations:
import org.jmolecules.ddd.annotation.AggregateRoot;
import org.jmolecules.ddd.annotation.Entity;
@AggregateRoot
public class Order {
private String id;
private List<Item> items;
public Order(String id, List<Item> items) {
this.id = id;
this.items = items;
}
public void addItem(Item item) {
this.items.add(item);
}
}
@Entity
public class Item {
private String name;
private int quantity;
public Item(String name, int quantity) {
this.name = name;
this.quantity = quantity;
}
}
2. Implement Adapters
Create adapters for infrastructure and application layers:
Application Service:
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
@ApplicationScoped
public class OrderService {
@Inject
OrderRepository orderRepository;
public void createOrder(String id, List<Item> items) {
Order order = new Order(id, items);
orderRepository.save(order);
}
}
Infrastructure Adapter:
import javax.enterprise.context.ApplicationScoped;
@ApplicationScoped
public class OrderRepositoryImpl implements OrderRepository {
@Override
public void save(Order order) {
// Save logic (e.g., using ScyllaDB)
}
}
Monitoring Solution
For robust monitoring, consider using Prometheus and Grafana, along with tools like Loki for log aggregation.
1. Add Prometheus Extension
Include the Prometheus extension in your project:
implementation("io.quarkus:quarkus-smallrye-metrics")
2. Expose Metrics
Quarkus automatically exposes metrics at /q/metrics
. Configure Kubernetes ServiceMonitor to scrape these metrics.
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: quarkus-service-monitor
spec:
selector:
matchLabels:
app: quarkus-app
endpoints:
- port: http
path: /q/metrics
3. Add Logging with Loki
Use Loki for centralized logging. Integrate Loki with Quarkus:
-
Configure JSON logging in
application.properties
:quarkus.log.console.json=true quarkus.log.level=INFO
-
Forward logs to Loki using tools like Fluentd or Promtail.
4. Visualize in Grafana
- Import dashboards for Prometheus and Loki in Grafana.
- Use pre-built Quarkus dashboards for detailed insights into application performance.
Deploying ScyllaDB in Kubernetes
1. Use ScyllaDB Operator
The ScyllaDB Operator simplifies managing clusters in Kubernetes:
apiVersion: scylla.scylladb.com/v1
kind: ScyllaCluster
metadata:
name: scylla-cluster
spec:
version: "5.0.0"
datacenter:
name: dc1
racks:
- name: rack1
members: 3
Deploy the manifest with:
kubectl apply -f scylla-cluster.yaml
2. Resource Optimization
Define resource requests and limits for each pod:
resources:
requests:
memory: "128Mi"
cpu: "500m"
limits:
memory: "512Mi"
cpu: "1"
By combining Quarkus, ScyllaDB, Kafka, Hexagonal architecture with jMolecules, and robust monitoring tools, small teams can efficiently build and maintain scalable, cloud-native applications on Kubernetes. This comprehensive approach ensures high performance, maintainability, and observability for modern software systems.