Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save apssouza22/cfe5a6b36193d3b0ff5aa4902b37b644 to your computer and use it in GitHub Desktop.
Save apssouza22/cfe5a6b36193d3b0ff5aa4902b37b644 to your computer and use it in GitHub Desktop.
The term “Microservices Architecture” is now a popular term and in order to keep updated as a software developer, I’ve been putting some effort to get a good understanding about this architecture and the better way of implementing it in Java using Spring technologies.
I was working in a nice company with a great team and a good tech stack, however, we were not using the cutting edge Java features such as Java 8 and Microservices architectures in that moment, so I had to start looking for that knowledge outside the company. I wanted to play with the Java 8 and Microservices and the best way of doing it is hands on code, building something, then I decided to create a To Do system using as many fun stuffs as possible and I will try to write a series of posts talking about this experience.
The intention of this blog series is to have a source code walkthrough with many concepts and technologies put in place and combined within a whole system composed with different microservices. I’m not planning to go deep in the concepts and tools, we have a lot of posts about those out there, the intention here is to present an application example containing patterns, tools, technologies used to develop microservices.
This is a studying application and we have intentionally made it as simple as possible to make the source code easy to understand. The application will be available and ready to run on your computer to use as a reference.
We are going to work with a "To Do" application which will be composed of 8 applications (Reminder, User, Service discovery server, Mailer, OAuth Server, System integration test, API Gateway, Web application client).
Some patterns, tools and technologies that you will see in this system:
Spring Boot, Spring Data, Spring Cloud Eureka, Load Balancing with Ribbon, Declarative REST Clients with Feign, Software Circuit Breakers with Hystrix, Monitoring using Hystrix dashboard and Turbine, Security with Spring Security OAuth, OAuth2 with JWT, Aspect Oriented Programing with Spring AOP, Distributed events with Kafka, Maven Multimodule project, Event Sourcing, CQRS, REST, Web Sockets and all developed using Java 8.
This first post is going to provide an overview of the whole project and in the coming posts, I will explain more deeply about what and how we are using the components in each microservice.
In the image above you can see how our system interacts along with all microservices. The user will access a Web Application written using Angular 2, it will connect to an OAuth Authorization Server which will be a central point of where users and authorities can be assigned. This server will return a JSON Web Token containing info about the client with its authorities and the grated scope. After the user being authenticated and with the token, the Web Application will be able to talk to the API gateway, it will take the JWT, verify if it’s coming from the Authorization Server then make calls to the microservices and build the response.
The User service is being used by the OAuth server to get the user’s authentication details and also it is being used by the API gateway to get user’s information.
The Remainder Service is where are placed the ToDo functionalities, The ToDo service has a scheduled job to check for reminders and notify the user by email, the emails are sent by the Mailer Service which is triggered from Reminder service by event using Kafka.
The System Integration Test is a Java application responsible for reaching the Reminder service’s endpoints.
Connecting Microservices
In the Microservice architecture, we have to deal with many microservices running in different IPs and ports, therefore we need to find a way of managing each address without hard coding, that is where Netflix Eureka comes to rescue, it is a client-side service discovery that allows services to find and communicate with each other automatically. We are using Spring Cloud Eureka in our system and you will need to have a look at how it works to understand how our services REST are communicating between different microservices. Once Eureka cares about where the services are running we can add instances and apply load balancing to distribute the incoming application traffic between our microservices.
In our system, we are using Netflix Ribbon as a client-side load balancer that enables us to achieve fault tolerance and increase the reliability and availability through redundancy. We are using Netflix Foreign for writing declarative REST client and integrate Ribbon and Eureka to provide a load balance HTTP client.
Our system has some dependencies and we are trying to isolate our application from dependency failure using Netflix Hystrix Circuit Breaker, it helps stop cascading failures and allows us to fail fast and rapid recovery, or add fallbacks. Hystrix maintains a thread-pool for each dependency and rejects requests (instead of queuing requests) if the thread-pool becomes exhausted. It provides circuit-breaker functionality that can stop all requests to a dependency. You can also implement fallback logic when a request fails, is rejected or timed-out.
Authentication
Security is something very important when we are developing any system and with microservices architecture is not different. The question: “How can I maintain security in my microservices” comes up immediately, and the first answer is OAuth2! And definitely OAuth2 is a very good solution, it is a well-known authorization technology, it is widely used for Google, Facebook, Github at their APIs.
It’s impossible to talk about security and don’t mention Spring Security and in our project we are using it along with OAuth2.
Spring Security and OAuth2 are obvious choices when talking about secure distributed system, however, we are adding one more element to our security concern, it is JWT (JSON Web Token). Using only OAuth we would need to have an OAuth Authorization Server to authenticate the user, generate the token and also an endpoint for the Resource servers to ask if the token is valid and which permission does it grant, requiring twice more request to the Authorization Server than we really need. JWT provides a simple way of transmitting the permissions and user data in the access token and once all data is already in the token string the resource servers don’t need to ask for token checks. All the information is serialised into JSON first, encoded with base64 and finally signed with a private RSA key, it assumes that all resource servers will have a public key to check if the token was signed for the proper private key and deserialize the token to have the information.
You can have a look at the OAuth2 Authorization Server(OAuth-server) and the Resource Server(API Gateway) implementations to see the code looks like. The implementation was done following mainly this blog post.
REST
In our system we have 2 interaction styles, we have synchronous and asynchronous, for the async style we are using distributed events with Kafka, following the model publish/subscribe and for synch, we have REST style supporting JSON and XML.
There are 4 levels of maturity of RESTful, starting at level 0, as described for Martin Fowler here and our services is in the level 2 because I decided not implement the Hypermedia Controls using the HATEOAS design pattern for the simplicity.
Because we are using Spring Cloud, we have out-of-box some scalability patterns which are placed in our HTTP connections that worth to be mentioned: Circuit breaker, Bulkheads, Load Balancing, Connection pooling, timeouts and retry.
Distributed Event
As mentioned above our communication between the Reminder service and Mailer service is done asynchronously using Kafka to distribute our events across the others Microservices. In the Reminder service we have a scheduled task to check for reminders time and publish the event RemainderFound where there will be a subscribed event in the Mailer service which will start the process of sending an email to the user. I invite you to have a look at how we are doing this integration and how I wrote the serialization/ deserialization of the data sent to Kafka in the Kafka event Module.
Event sourcing and CQRS
Monolithic applications typically have a single relational database and we can use ACID transactions, as a result, our application can simply begin a transaction, change multiple rows, and commit the transaction if everything go right and rollback if something goes wrong. Unfortunately to deal with data access in the microservice architecture is much more complex due to the data be distributed in different databases and implement the business transactions across multiple services is a big challenge.
In our "ToDo" project we are using events to deal with business transaction that spans multiple services, and you can look at the implementation of Event Sourcing with CQRS applied in the Mailer service. You will see how to separate Reads and Writes that enable us to scale each part easily. We are using a relational database as an event store and then distributing the events using Kafka, we will need to make these 2 actions Atomic and avoid to store the event and not publish in a eventual JVM crash. I’m not using Kafka as the event store because is simpler to construct the aggregates from a relational database and we are trying to make things easy here.
As you can notice, we already have a lot of things in this project, but there are still many challenges that are not addressed here yet, however this is a project in development and we are planning adding more stuffs into it, such as Spring cloud config, Containers with Docker, continuous integration with Jenkins, Distributed trace with Spring Sleuth, Logging management with ELK and more. So keep tuned on our Github repository to see more fun things.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment