The labs on this site need JavaScript to run. The same content is written out below.
Learn › Architecture and operations › Splitting into services
Gateway and gradual migration
Breaking up a huge server piece by piece without stopping it
You put a gateway in front of an existing server (a monolith) that holds every feature in one lump, and hand requests over to new services one route at a time. The address that users see does not change.
Checked against documentation and standards · The path and weight predicates of Spring Cloud Gateway
Concepts in this lab
- API gateway
- The single entry point that receives all client requests first and forwards them to the right internal service. It handles common functions such as authentication, rate limiting, and logging in one place. Clients do not need to know the layout and addresses of the internal services.
- Strangler fig pattern
- A way to replace an existing system gradually by moving features to a new system one at a time, instead of replacing it all at once. At the front, where requests arrive, only the requests for features that have been moved go to the new system, and the existing system keeps handling the rest. When all features have been moved, the existing system is removed.
- Monolithic architecture and microservice architecture
- A monolithic architecture builds all features as one application and deploys them together. A microservice architecture splits the features into small services, and each one is developed, deployed, and scaled independently. With microservices, each service can be deployed and scaled separately and failures are isolated, but the complexity of communication between services, data consistency, and operations grows a lot.
- Reverse proxy
- A server that receives client requests on behalf of internal servers, forwards them to those servers, and returns their responses to the client. The client does not know the actual servers directly. Its roles include distributing requests across several servers, handling TLS, caching, and protecting the internal servers.
- Rolling, blue-green, and canary deployments
- Ways to deploy a new version without interrupting the service. A rolling deployment replaces servers with the new version a few at a time, in turn. A blue-green deployment prepares a complete, separate environment for the new version and then switches the traffic all at once. A canary deployment applies the new version to only some users first, checks that there are no problems, and then expands it gradually.
Try these
- Default settings — Only the order route is handed over to the new service.
- Only 10% of orders first — Verifies the new service with a small share of real requests.
- Before migration — Every request goes to the existing server.
- Migration complete — No requests go to the existing server, so it can be shut down.
- Requests with no token — The gateway filters them out at the entrance.
Running with the default settings
- All of the user's requests come in through one place, the gateway. After doing the common work (token validation, logging, rate limiting), the gateway looks at the path and decides which server behind it to pass the request to. The user does not know how many servers are behind it.
- GET /orders/1: The path starts with /orders. This path is configured to be passed to the new service. → Order service (new)
- POST /payments: The path starts with /payments. It is not a path with its own rule, so it goes to the existing server. → Existing server (monolith)
- GET /members/me: The path starts with /members. It is not a path with its own rule, so it goes to the existing server. → Existing server (monolith)
- POST /orders: The path starts with /orders. This path is configured to be passed to the new service. → Order service (new)
- GET /orders/2: The path starts with /orders. This path is configured to be passed to the new service. → Order service (new)
- GET /members/7: The path starts with /members. It is not a path with its own rule, so it goes to the existing server. → Existing server (monolith)
- POST /orders: The path starts with /orders. This path is configured to be passed to the new service. → Order service (new)
- GET /payments/9: The path starts with /payments. It is not a path with its own rule, so it goes to the existing server. → Existing server (monolith)
- GET /orders/3: The path starts with /orders. This path is configured to be passed to the new service. → Order service (new)
- GET /orders/4: The path starts with /orders. This path is configured to be passed to the new service. → Order service (new)
Result of this run
- You do not move every feature at once; you split them off one route at a time. If something goes wrong with a new service, you can change the configuration back and send the requests to the existing server again (the data the new service has written has to be handled separately). Because the new system gradually wraps around the existing one and replaces it, this approach is called the strangler fig pattern.
Code
# Spring Cloud Gateway
spring.cloud.gateway:
routes:
- id: order
uri: http://order-service
predicates:
- Path=/orders/**
- id: legacy # everything else goes to the existing server
uri: http://legacy-monolith
predicates:
- Path=/**
# Common filters: token validation, request logging, rate limiting
Assumptions of this model
This is a fixed example of 10 requests. The ratio setting is assigned in a simple way so that the difference shows within the 10 requests (for 50%, order requests alternate; for 10%, only the fifth order request goes to the new service). The configuration example follows the path and weight predicates of Spring Cloud Gateway. Separating the data and synchronizing the two systems, which are the hardest parts of moving a feature, are not covered.
Previous lab: Saga and outbox · Next lab: CI/CD pipelines