Microservice Implementation using Spring Cloud with Docker: Netflix Stack
Discovery server, API gateway ZUUL, ribbon, inter-services communication and docker
Microservices is an architectural design for building a distributed application using containers. Microservices get their name because each function of the application operates as an independent service. This architecture allows for each service to scale or update without disrupting other services in the application.
In this article, I will explain and implement bellow points
- What are microservice and their importance?
- Comparison between monolithic architecture and microservice architecture
- How Netflix stack (Eureka, ZUUL, Ribbon, etc) are the life saviour in our case?
- Details level descriptions of Netflix technology stack
- Describe and implement our proposed microservice architecture (service discovery, API gateway routing, and load balancing, inter microservice communication, and their load balancing, etc)
- Verify how microservices are connecting, how load balancing occurring based on data.
- Describe codebase and share code
Prerequisite : Before starting this article you need knowledge of docker, MongoDB, and spring boot. To do this you can check these articles
Infrscture architecture

Our applications business logic is given bellow
- User service is responsible for registering our customers. After successful registration user service will call the notification service for sending notification.
- User service has N number of instances. Here we will show examples for two instances and both are connected with the MySQL database. Both are deployed in the docker container.
- Notification service stores notification data into MongoDB database. User service calls this service after customer registration. It has also an N number of instances and we will give example for two instances. Both instances are also running on docker containers.
- MySQL and MongoDB both databases are running into the docker container.
Monolithic architecture
Monolithic architecture is considered to be a traditional way of building applications. A monolithic application is built as a single and indivisible unit. Usually, such a solution comprises a client-side user interface, a server side-application, and a database. It is unified and all the functions are managed and served in one place.
Traditional monolithic architecture is given bellow

Normally, monolithic applications have one large codebase and lack modularity. If developers want to update or change something, they access the same code base. So, they make changes in the whole stack at once.
Limitations of monolithic architecture are given bellow
- Tight coupling between components, as everything is in one application
- The Integrated Development Environment can become overloaded, and size may also slow down startup time
- You must redeploy the entire application on each update.
- Every element is closely related and dependent on the others, so it is difficult to change to new or advanced technology, language, or framework
- The impact of a change is usually not very well understood which leads to doing extensive manual testing.
- Monolithic applications can also be difficult to scale when different modules have conflicting resource requirements.
- Another problem with monolithic applications is reliability. Bug in any module (e.g. memory leak) can potentially bring down the entire process. Moreover, since all instances of the application are identical, that bug will impact the availability of the entire application.
- Monolithic applications have a barrier to adopting new technologies. Since changes in frameworks or languages will affect an entire application it is extremely expensive in both time and cost.
Microservice architecture
Microservices are a way of breaking large software projects into loosely coupled modules, which communicate with each other through simple Application Programming Interfaces (APIs).
Microservices have become increasingly popular over the past few years. They are an example of the modular architectural style, based on the philosophy of breaking large software projects into smaller, independent, and loosely coupled parts, which has gained prominence among developers for its dynamic and agile qualities in API management and execution of highly defined and discrete tasks.
In short, the microservice architectural style is an approach to developing a single application as a suite of small services, each running in its own process and communicating with lightweight mechanisms, often an HTTP resource API. - Martin Fowler
Advantages of microservice are given bellow
- all the services can be deployed and updated independently, which gives more flexibility.
- a bug in one microservice has an impact only on a particular service and does not influence the entire application. Also, it is much easier to add new features to a microservice application than a monolithic one.
- Split up into smaller and simpler components, a microservice application is easier to understand and manage. You just concentrate on a specific service that is related to a business goal you have.
- Maintenance in microservices is faster than in monolith. Smaller services are also easy to test, saving programmers time. Over time, it increases efficiency and saves money.
- Microservices are stable and most reliable. Breaking one part only affects that element, while the others remain intact. Such flexibility allows for a fast pace of development and the introduction of changes in one function without interfering with others.
- In the case of microservices, scalability is much easier because we can scale only those parts that require more resources.
- The engineering teams are not limited by the technology chosen from the start. They are free to apply various technologies and frameworks for each microservice.
- Any fault in a microservices application affects only a particular service and not the whole solution. So all the changes and experiments are implemented with lower risks and fewer errors.
Details of Netflix stack
Netflix OSS is a set of frameworks and libraries that Netflix wrote to solve some interesting distributed-systems problems at scale. With a few simple annotations, you can quickly enable and configure the common patterns inside your application and build large distributed systems with battle-tested Netflix components. The patterns provided include Service Discovery (Eureka), Circuit Breaker (Hystrix), Intelligent Routing (Zuul), and Client Side Load Balancing (Ribbon).
Service discovery (Eureka)
Service Discovery is one of the key tenets of a microservice-based architecture. Trying to hand configure each client or some form of convention can be difficult to do and can be brittle. Eureka is the Netflix Service Discovery Server and Client. The server can be configured and deployed to be highly available, with each server replicating state about the registered services to the others.
It does bellow things
- Eureka is a REST (Representational State Transfer) based service that is primarily used in the AWS cloud for locating services for the purpose of load balancing and failover of middle-tier servers.
- Service Discovery Server Netflix Eureka allows microservices to register themselves at runtime as they appear in the system landscape.
- It’s a registry where clients (your microservices) can connect to (register), making your Eureka server aware of where your microservices are located, how many there are, and if they’re healthy or not.
- Discovery Server helps to discover the service we required. When some service needs to access another service, Discovery Server provides all the endpoint details of the requested service to establish the connection.
- All of the services need to register with Discovery Server, otherwise, Discovery Server doesn’t know about that service.
Netflix Ribbon
- Netflix Ribbon is an Inter-Process Communication (IPC) cloud library. Ribbon primarily provides client-side load balancing algorithms.
- Dynamic Routing and Load Balancer Netflix Ribbon can be used by service consumers to lookup services at runtime.
- Ribbon load balancers provide service discovery in dynamic environments like a cloud. Integration with Eureka and Netflix service discovery component is included in the ribbon library
- the Ribbon API can dynamically determine whether the servers are up and running in a live environment and can detect those servers that are down
- Ribbon uses the information available in Eureka to locate appropriate service instances. If more than one instance is found, Ribbon will apply load balancing to spread the requests over the available instances.
- It provides a configurable load balancing rule. Ribbon supports RoundRobinRule, AvailabilityFilteringRule, WeightedResponseTimeRule out of the box and also supports defining custom rules
- The ribbon does not run as a separate service but instead as an embedded component in each service consumer.
- Ribbon API works based on the concept called “Named Client”. While configuring Ribbon in our application configuration file we provide a name for the list of servers included for the load balancing.
Discovery client
Every service must register with the Discovery Server. Here, our user service and notification service both are connected with the discovery server. Here both are discovery clients. Single service may have multiple instances.
Netflix Zuul: API GATEWAY
Zuul is the front door for all requests from devices and websites to the backend of the Netflix streaming application. As an edge service application, Zuul is built to enable dynamic routing, monitoring, resiliency, and security.
Routing is an integral part of a microservice architecture. For example, users may call for user service for user information or call notification service to get the latest notifications. Zuul is a JVM-based router and server-side load balancer by Netflix.
- Edge Server Zuul is (of course) our gatekeeper to the outside world, not allowing any unauthorized external requests to pass through.
- Zuul also provides a well-known entry point to the microservices in the system landscape.
- Zuul uses Ribbon to look up available services and routes the external request to an appropriate service instance.
- We don’t need to worry about Client-Side-Load-Balancing, Zuul is doing the Load-Balancing by using Ribbon.
- Zull also connected with the discovery server.
Zuul gives us a lot of insight, flexibility, and resiliency, in part by making use of other Netflix OSS components:
- Hystrix is used to wrap calls to our origins, which allows us to shed and prioritize traffic when issues occur.
- The proxy uses Ribbon to locate an instance to forward to via discovery, and all requests are executed in a hystrix command, so failures will show up in Hystrix metrics, and once the circuit is open the proxy will not try to contact the service.
How Netflix stack helps us in our architecture
Suppose our project is a monolithic application. Single project and a single database. The main bottlenecks of our project will be a single database. It will take a large time for the database to read and write during large traffic.
In our proposed microservice architecture NetFlix stack can solve our problem. Here we will break down user service and notification service with two different databases. Both services are independent based on their business and technology. User service is using RDBMS but notification service is using the NoSQL database.
Now both services are connected with the discovery server using Netflix client. For pick hour we can scale our instances using Docker or Kubernetes based on our traffic. After running the application, it will automatically connect with our discovery server.
Workflow is given bellow

The connected components on the discovery server are given bellow

- The top of the software is the discovery server. First, it runs and it will be ready to accept connection requests from Netflix clients. Discovery servers IP and port will be used by clients as discovery servers with default zone.
- User service and notification services both have two instances each. After starting of instance both will connect with the discovery server with its own IP and port. This is mainly a socket connection between client and server. Both instances may be in the same machine or different machines with different IP addresses.
- User service sometimes calls notifications service. But notification service has two instances. What instance will call? Netflix solved this problem using an interesting way. Each client has a different client id. Here, the user service id is USER-SERVICE and the notification service id is NOTIFICATION-SERVICE
- During service to service, calling ribbon plays an important role. It has all registries and the availability of each available node of the target service. It will take one instance based on a defined load balancing algorithm and a call based on service id.
- after the startup of the Zuul API gateway, it will connect with the discovery server as a client. All external components like mobile apps, web apps, external servers will call to Zuul gateway. It is public fetching service. Zuul will redirect requests to a specific server based on API patterns. Here ribbon will also provide service instances and balance client-side loads.
Implementation of our architecture
In our architecture, there are below databases
- Mysql database: For user service. You can run your database on docker or run it on your local machine. you will get DB scripts into the project folder.
- MongoDB database: For notification service. You can run your database on docker or run it on your local machine.
We have four projects in this architecture
- Discovery server
- User service
- Notification service
- ZUUL API gateway
Their implementation is given bellow
Discovery server (Eureka)
Here is the build.gradle file







