Source-linked AI summary
Migrating to Cloud-Native Architectures Using Microservices: An Experience Report
Armin Balalaie, Abbas Heydarnoori, Pooyan Jamshidi
TL;DR
Cloud migration often fails to realize cloud benefits when legacy architectures are merely virtualized, while existing approaches rarely treat cloud-native architectures as first-class citizens. The paper reports an ongoing migration of SSaaS from an on-premise monolith to microservices, describing the process and lessons learned. It concludes that microservices can support needed scalability and availability flexibility, but introduces complexities that require careful consideration and may make another solution preferable.
Problem
On-premise architectures may not exploit cloud benefits after migration, while existing approaches rarely consider cloud-native architectures as first-class citizens.
Method
The paper reports experience and lessons learned from migrating the on-premise SSaaS application to microservices.
Results
The migration was performed incrementally through re-architecting, introducing supporting services, and enabling Continuous Delivery.
Takeaways & Limitations
Microservices can deliver benefits in contexts requiring high flexibility in scalability and availability.
Takeaways & Limitations
Microservices is not a one-fit-all solution because it introduces complexities, and another architectural style or solution may solve some problems more easily.
Abstract
from arXiv · showhide
Migration to the cloud has been a popular topic in industry and academia in recent years. Despite many benefits that the cloud presents, such as high availability and scalability, most of the on-premise application architectures are not ready to fully exploit the benefits of this environment, and adapting them to this environment is a non-trivial task. Microservices have appeared recently as novel architectural styles that are native to the cloud. These cloud-native architectures can facilitate migrating on-premise architectures to fully benefit from the cloud environments because non-functional attributes, like scalability, are inherent in this style. The existing approaches on cloud migration does not mostly consider cloud-native architectures as their first-class citizens. As a result, the final product may not meet its primary drivers for migration. In this paper, we intend to report our experience and lessons learned in an ongoing project on migrating a monolithic on-premise software architecture to microservices. We concluded that microservices is not a one-fit-all solution as it introduces new complexities to the system, and many factors, such as distribution complexities, should be considered before adopting this style. However, if adopted in a context that needs high flexibility in terms of scalability and availability, it can deliver its promised benefits.
1 Introduction
Cloud migration requires more than moving legacy applications into virtualized environments, because cloud benefits depend on architectures that support availability and scalability. The paper reports an ongoing migration of SSaaS to microservices and the associated challenges and lessons.
- Simply moving a legacy architecture to a virtualized environment may prevent applications from benefiting fully from the cloud.
- Cloud-native architectures such as microservices inherently support availability and scalability needed to exploit cloud environments.
- Microservices address monolithic-system shortcomings through small services that can be understood, deployed, and scaled independently.
- Existing cloud-migration approaches largely emphasize automation and migration patterns without treating cloud-native architectures as first-class citizens.
- The paper reports an ongoing PegahTech project migrating the on-premise SSaaS application to microservices, including challenges and lessons learned.
2 Background
Microservices packages software as independently deployable services and relies on supporting practices such as Continuous Delivery and DevOps. Its distributed structure requires components that manage configuration, discovery, load distribution, fault tolerance, and external access.
- Continuous Delivery and DevOps: Continuous Delivery automates software delivery for on-demand deployment, while DevOps emphasizes developer–operations collaboration to improve agility.
- Microservices: Microservices organizes software as small services that run independently, communicate through lightweight mechanisms, and represent business capabilities.
- Supporting Components: Microservices requires supporting components because distributing business logic across services introduces operational complexities.
- Supporting Components: A Configuration Server separates source code from configuration, allowing configuration changes without redeploying code.
- Supporting Components: Service Discovery tracks available service instances, and a Load Balancer distributes requests among those instances.
- Supporting Components: Circuit Breaker patterns mitigate losses from failures among dependent services, while an Edge Server routes external traffic to internal services.
3 The Architecture of SSaaS Before the Migration
SSaaS began as a Java and Spring application offering server-side services to mobile developers, with several components and manual production deployment. Growing requirements exposed needs for reusable resources, decentralized data governance, automated deployment, and scalable service management.
- SSaaS Before Migration: SSaaS aimed to provide mobile developers server-side programming facilities and eventually scale to millions of users.
- SSaaS Before Migration: The initial RDBMS-as-a-Service functionality let developers define schemas and receive SDKs for target platforms such as Android or iOS.
- SSaaS Before Migration: SSaaS used Java, Spring, Oracle 11g, Maven, and a shared Git repository, but production deployment was manual and lacked test cases.
- SSaaS Before Migration: Before migration, SSaaS comprised five components, with solid arrows denoting service-call direction and dashed arrows denoting library dependencies.
- Migration Drivers: New services such as Chat as a Service exposed a need for reusable database and backing-resource reservation across services.
- Migration Drivers: The migration addressed decentralized metadata ownership, automated deployment, and scalable service-instance discovery and load balancing.
- Migration Drivers: New requirements led to new services, which in turn introduced non-functional requirements that motivated adopting microservices.
4 The Target Architecture of SSaaS After the Migration
The target architecture re-architects SSaaS into microservices using Spring-based and Netflix OSS components, with services organized around cohesive domain entities.
- Target architecture: The migration introduced microservices-specific components and re-architected SSaaS into the target architecture.The final architecture is depicted in Figure 2.
- Technology stack: Spring Boot and Spring Cloud were selected to provide embedded servers and separate configuration from source code.Spring Cloud Context and Config Server support the configuration separation recommended by Continuous Delivery.
- Technology stack: Eureka, Ribbon, Hystrix, and Zuul provide service discovery, load balancing, circuit breaking, and edge-server functions.Ribbon was chosen for Spring and Eureka integration and because it is an internal load balancer.
- Data and service boundaries: Services were organized around cohesive entity sets, with each service exclusively creating and updating the entities it owns.Other services may keep copies for caching but must account for possible staleness.
- Data and service boundaries: The planned refactorings included separating chat metadata, resource management, developer information, and DeveloperData responsibilities into services.DeveloperData was transformed from a library into a service, requiring dependent services to make service calls.
5 Migration Steps
SSaaS migration was planned as an incremental, eight-step process that preserved end-user operation while adding automated delivery and container-based deployment support.
- Migration approach: Migration toward the target architecture was incremental and designed to avoid affecting end-users.The process was divided into eight steps.
- Continuous integration pipeline: The project established a continuous integration pipeline using GitLab, Jenkins, Artifactory, and Docker Registry.These tools served as the code repository, CI server, artifact repository, and private image repository.
- Containerization: Containerization was selected for microservices because it supports isolated service instances with lower overhead than virtualization.Containers also provide consistent environments and portability across supporting platforms.
5.2 Transforming DeveloperData to a Service
DeveloperData was changed from a library into a Spring Boot service exposing a REST API, separating dependent services from its internal structure and entity governance.
- Service transformation: DeveloperData was changed to Spring Boot and exposed through a REST API.DeveloperServices and ContentServices were adapted to make service calls instead of method calls.
- Service transformation: Service-level dependency prevents dependent services from being affected when DeveloperData’s internal structure changes.DeveloperData becomes the single service governing its entities rather than an integration database.
- Configuration separation: Configuration was separated from source code using Docker, Spring Cloud Configuration Server, and Spring Cloud Context.This permits configuration changes without redeploying source code.
5.4 Introducing Edge Server
The migration introduced an Edge Server and dynamic service-collaboration components to shield clients from internal changes and improve service-call resilience.
- Edge Server: An Edge Server was introduced to minimize the effect of internal service-architecture changes on end-users.DeveloperWebsite was adapted accordingly.
- Dynamic service collaboration: Service Discovery and Load Balancer enable dependent services to locate one another.The Circuit Breaker supports resilience during service calls.
- Dynamic service collaboration: Introducing these components early made developers more comfortable with the concepts and increased migration speed.The authors also connect the components with introducing new services.
- Resource management: A Resource Manager was added by extracting server-related entities from DeveloperData and adding database-reservation features.DeveloperServices was adapted to use the new service for database reservations.
5.7 Introducing ChatServices and DeveloperInfoServices
The final re-architecting step introduced DeveloperInfoServices and ChatServices by separating developer entities and chat metadata responsibilities, producing the target architecture.
- The final re-architecting step introduced DeveloperInfoServices and ChatServices.DeveloperInfoServices extracted developer-related entities, while ChatServices persisted chat metadata and handled chat service instance creation.
- DeveloperInfoServices was created by factoring developer-related entities such as Developer from DeveloperData.
- ChatServices persisted chat service instance metadata and handled chat service instance creation.
- These changes led to the target architecture depicted in Figure 2.
5.8 Clusterization
The project clusterized deployment by running services across CoreOS instances with Kubernetes, completing an incremental migration that also integrated Continuous Delivery.
- Containerization was selected for its low overhead, with lightweight operating systems supporting many containers.
- The team deployed services on a CoreOS cluster with Kubernetes agents instead of a single server.
- The final delivery pipeline was documented in Figure 8.
- The migration evolved incrementally across re-architecting, supporting services, and Continuous Delivery together.
6 Lessons Learned
The migration exposed operational and organizational challenges, including development deployment burden, fragile service contracts, skill requirements, and risks from uncontrolled technological diversity.
- Development deployment becomes difficult because developers must deploy dependent services to run isolated services locally.The project used Docker Compose to deploy dependent services from a private Docker registry.
- Service contracts are error-prone because small contract changes can break part or all of the system.The authors discuss service versioning, Tolerant Reader, and consumer-driven contracts as ways to address this risk.
- Microservices require skilled developers familiar with distributed systems and supporting services such as registries and load balancers.
- Uncontrolled use of multiple languages and data stores can create chaos and make the system unmaintainable.The authors recommend controlled standards and service development templates for each language.
- Microservices was beneficial in this project because the system needed flexibility and supporting technologies eased migration and development.The authors nevertheless state that the introduced complexities require substantial effort and that another architectural solution might fit some problems better.
7 Conclusions and Future Work
The paper reports an experience migrating an on-premise application to microservices, documents the migration and Continuous Delivery practices, and proposes reusable migration patterns as future work.
- The paper reports experience migrating an on-premise application to the microservices architectural style.
- It presents the system architecture before and after migration, the migration steps, and the importance of Continuous Delivery.
- Future work will consolidate the practices into reusable, well-defined patterns for migrating on-premise applications to microservices.The patterns are intended to generalize the project’s process and be instantiated independently.