DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Related

  • A Transaction-Grade Performance Blueprint for Spring Boot FinTech Microservices (Tracing, Histograms, and Kubernetes)
  • Building a Fault-Tolerant Microservices Architecture With Kubernetes, gRPC, and Circuit Breakers
  • Scaling Microservices With Docker and Kubernetes on Production
  • Building Reliable LLM-Powered Microservices With Kubernetes on AWS

Trending

  • Spring Boot Done Right: Lessons From a 400-Module Codebase
  • Slopsquatting: Building a Scanner That Catches AI-Hallucinated Packages Before They Reach Production
  • AI-Driven Integration in Large-Scale Agile Environments
  • Setting Up Claude Code With Ollama: A Guide
  1. DZone
  2. Software Design and Architecture
  3. Microservices
  4. Building Reactive Microservices With Spring WebFlux on Kubernetes

Building Reactive Microservices With Spring WebFlux on Kubernetes

Spring WebFlux on Kubernetes delivers high-throughput, low-latency I/O with fewer resources using reactive IO, Resilience4j, and metrics-based autoscaling.

By 
Mikhail Povolotskii user avatar
Mikhail Povolotskii
·
Oct. 30, 25 · Analysis
Likes (1)
Comment
Save
Tweet
Share
4.3K Views

Join the DZone community and get the full member experience.

Join For Free

Migrating from a monolithic Java 8 system to a reactive microservice architecture on Kubernetes allowed us to dramatically improve performance and maintainability. In this article, I’ll share our journey, key Spring Cloud Kubernetes features we adopted, the challenges we faced during development, and the lessons we learned along the way.

Business Logic

We have a data processing logic that streams information into S3 storage using Kafka, Spark Streaming, and Iceberg. Initially, we encountered multiple challenges, such as file optimization issues and Spark’s unpredictable memory behavior. After addressing these issues, we achieved significant cost savings. Once the insert service was completed, we needed to select an appropriate search engine service. We chose Trino as it fulfilled the needs of our data science department. We also serve customers who perform operations on our S3 data, which can result in high system load. Before this modernization, our platform ran on an old monolithic architecture built with Java 8, which created several performance and maintenance challenges.

Old Monolith Architecture

Our monolithic architecture was an example of a legacy design that lacked scalability and flexibility. It was a mix of MapReduce jobs, insert services connected to various databases, search services, and schema services. When one component experienced issues, the entire system — and therefore our customers — were affected. Small code fixes could take a significant amount of time due to the tightly coupled structure. Additionally, most of the libraries were deprecated, and updating them caused compatibility issues across the stack. We were limited by Java 8’s older garbage collection and incompatibility with modern libraries. We also relied on Zookeeper to store global parameters, which was cumbersome to maintain and added operational overhead.

New Reactive Architecture

We decided to extract the search service and rebuild it using reactive Spring technology on modern Java, deploying it via Spring Cloud Kubernetes. Spring Cloud Kubernetes provides Spring Cloud interface implementations that consume native Kubernetes services. After exploring its capabilities, we implemented several key features described below.

Key Spring Cloud Kubernetes Features

A. ConfigMap Property Source

Kubernetes provides a resource called ConfigMap to externalize configuration parameters in the form of key-value pairs or embedded application.properties or application.yaml files. The Spring Cloud Kubernetes Config project makes these ConfigMap instances available at application startup and triggers hot reloading of beans or the Spring context when changes are detected. This allows dynamic configuration without restarts.

Example configuration:

YAML
 
spring:
application:
name: cloud-k8s-app
cloud:
kubernetes:
config:
name: default-name
namespace: default-namespace
sources:
- name: c1
- namespace: n2
- namespace: n3
name: c3


B. Secrets Property Source

Kubernetes also supports Secrets for storing sensitive information such as passwords, OAuth tokens, and API keys. We integrated these using Spring Cloud Kubernetes Secrets configuration.

Example configuration:

YAML
 
cloud:
kubernetes:
secrets:
enabled: true
fail-fast: true
sources:
- name: Secret
           namespaces: hades-h3


C. Leader Election

Spring Cloud Kubernetes includes a leader election mechanism that implements Spring Integration’s leader election API using a Kubernetes ConfigMap. The following configuration enables leader election.

YAML
 
leader:
   enabled: true

When a pod becomes the leader, the following code executes:

@EventListener()
public void foo(OnGrantedEvent event) {
if (event.getContext() != null) {
logger.info(new LogEvent("I am foo leader."));
executeCreateView();
} else {
logger.info(new LogEvent("Skipping foo because I'm not the leader."));
}
 }


The method executeCreateView() creates a view every 30 seconds in our Trino search engine. We implemented the leader mechanism because only one instance should perform this operation, preventing race conditions among multiple pods.

D. Spring Cloud Kubernetes Configuration Watcher

Kubernetes allows mounting ConfigMaps or Secrets as volumes inside containers. When their contents change, the mounted volume updates automatically. We developed a GlobalConfig class responsible for reading configuration values from the Kubernetes ConfigMap. We used the @RefreshScope annotation so that any change in configuration automatically triggers a bean reload, allowing us to apply updates without restarting the application.

E. Spring Boot Actuator

Spring Boot Actuator provides production-ready features for monitoring, metrics collection, and health checks without requiring custom implementation. We integrated it to monitor application performance, analyze traffic, and track database states. We also used these metrics to build Grafana dashboards for better visibility.

Some of the metrics we collect with the help of the actuator

Some of the metrics we collect with the help of the actuator


Problems During Development

During testing, we observed an issue where CPU usage increased gradually over time. After a detailed investigation, we discovered that the Actuator was collecting metrics for every external IP calling the service, which caused a memory and CPU increase. We resolved this by using MeterFilter.deny() to filter out unnecessary metrics and retain only what we needed.

We also faced the challenge of designing a single class that could read configuration data from both the Kubernetes ConfigMap and local application resources. We implemented it as follows:

YAML
 
@ConfigurationProperties(prefix = "global")
@RefreshScope
@Configuration
public class GlobalConfig extends GitLabPush {

private String config;

public void setConfig(String config) {
this.config = config;
}
 }


The prefix “global” defines the upper level of the ConfigMap. When scanning, the field “config” is retrieved from the map with its associated values. Example ConfigMap entry:

Shell
 
global.config: {"field": "data"}


Another challenge arose when updating the Kubernetes ConfigMap via our API. We needed to synchronize these changes with our Argo projects, where YAMLs were stored. To ensure consistency, we added a pushToGit() function that used the GitLab API to automatically commit updates to the Git repository.

Lessons Learned

Refactoring our monolithic service into microservices provided a far more efficient development process, improved performance, and granted access to the full range of features in Spring Cloud Kubernetes. We gained scalability, dynamic configuration management, and simplified observability. This migration allowed our teams to deploy updates faster, recover from issues quickly, and reduce maintenance overhead.

Conclusion

Transitioning from a monolithic Java 8 architecture to a reactive microservice environment built with Spring WebFlux and Kubernetes transformed the reliability and agility of our system. The combination of ConfigMaps, Secrets, Leader Election, and Actuator monitoring enabled us to create a flexible, cloud-native platform ready to handle complex workloads at scale.

Kubernetes Spring Cloud microservices

Opinions expressed by DZone contributors are their own.

Related

  • A Transaction-Grade Performance Blueprint for Spring Boot FinTech Microservices (Tracing, Histograms, and Kubernetes)
  • Building a Fault-Tolerant Microservices Architecture With Kubernetes, gRPC, and Circuit Breakers
  • Scaling Microservices With Docker and Kubernetes on Production
  • Building Reliable LLM-Powered Microservices With Kubernetes on AWS

Partner Resources

×

Comments

The likes didn't load as expected. Please refresh the page and try again.

  • RSS
  • X
  • Facebook

ABOUT US

  • About DZone
  • Support and feedback
  • Community research

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 215
  • Nashville, TN 37211
  • [email protected]

Let's be friends:

  • RSS
  • X
  • Facebook