Spring Microservices Material
Spring Microservices Material
To understand the design differences between monolithic and µServices, let's take an example of
a restaurant table-booking application. This app may have many services such as customers,
bookings, analytic and so on, as well as regular components such as presentation and database.
We'll explore three different designs here – traditional monolithic design, monolithic design
with services and µServices design.
In traditional monolithic design, everything is bundled in the same archive such as presentation
code,application logic and business logic code, and DAO and related code that interacts with the
database files or another source.
Monolithic design with services:
The following diagram depicts the monolithic application with different services; here services
are being used with a presentation component. All services, the presentation component, or any
other components are bundled together:
MicroServices Design:
The following third design depicts the µServices. Here, each component represents autonomy.
Each component could be developed, built, tested, and deployed independently. Here, even the
application UI component could also be a client and consume the µServices. For the purpose of
our example, the layer designed is used within µService.
The API gateway provides the interface where different clients can access the individual services
and solve the following problems:
What to do when you want to send different responses to different clients for the same
service. For example, a booking service could send different responses to a mobile client
(minimal information) and a desktop client (detailed information) providing different
details and something different again to a third-party client.
Similarly, in the second design figure, we can see a variant of the first figure where all services
could have their own layers and form different APIs, but, as shown in the figure, these are also
all bundled together.
But In µServices, design components are not bundles together and have loose coupling. Each
service has its own layers and DB and is bundled in a separate archive. All these deployed
services provide their specific API such as Customers, Bookings, or Customer which are ready to
consume. Even the UI is also deployed separately and designed using µService. For this reason,
it provides various advantages over its monolithic design. But It would also be noted that there
are some exceptional cases where monolithic app development is highly successful, like
peer-to-peer e-commerce web applications.
MicroServices:
MicroServices are an architecture style used by many organizations to develop more physically
separated modular applications to achieve a high degree of agility, speed of delivery, and scale.
Evolution Of MicroServices
Many organizations such as Netflix, Amazon, and eBay successfully used the
divide-and-conquer technique to functionally partition their monolithic applications into smaller
atomic units, each performing a single function. These organizations solved a number of issues
they were experiencing with their monolithic applications. Following the success of these
organizations, many other organizations started adopting this as a common pattern to re factor
their monolithic applications. Later, evangelists termed this pattern as the MicroServices
architecture.
In most cases, layers are physically spreadable, whereas modules within a layer are hardwired.
As we can note in the preceding diagram, the boundaries are inversed in the MicroServices
architecture. Each vertical slice represents a micro service.
Each microservice has its own presentation layer, business layer, and database layer. By doing
so, changes to one micro service do not impact others.
The honeycomb is an ideal analogy for representing the evolutionary microservices architecture.
In the real world, bees build a honeycomb by aligning hexagonal wax cells. They start small,
using different materials to build the cells. Construction is based on what is available at the time
of building. Repetitive cells form a pattern and result in a strong fabric structure. Each cell in the
honeycomb is independent but also integrated with other cells.
By adding new cells, the honeycomb grows organically to a big, solid structure. The content
inside each cell is abstracted and not visible outside. Damage to one cell does not damage
other cells, and bees can reconstruct these cells without impacting the overall honeycomb.
Principles of MicroServices
we will examine some of the principles of the MicroServices architecture. These principles are
"must have" when designing and developing MicroServices.
The “Single Responsibility Per Service” principle is one of the principles defined as part of the
SOLID design pattern. It states that a unit should only have one responsibility. There are five
principles to be followed while designing a class, these five principles are said to be SOLID:
Source:
http://c2.com/cgi/wiki?PrinciplesOfObjectOrientedDesign
This implies that a unit, either a class, a function, or a service, should have only one
responsibility. At no point should two units share one responsibility or one unit have more than
one responsibility. A unit with more than one responsibility indicates tight coupling.
As shown in the preceding diagram, Customer, Product, and Order are different functions of an
e- commerce application. Rather than building all of them into one application, it is better to
have three different services, each responsible for exactly one business function, so that
changes to one responsibility will not impair others.
In the preceding scenario, Customer, Product, and Order will be treated as three independent
MicroServices.
Principle-2: Autonomous
In traditional application developments, we build a WAR or an EAR, then deploy it into a JEE
application server, such as with JBoss, WebLogic, WebSphere, and so on. We may deploy
multiple applications into the same JEE container. In the MicroServices approach, each
microservice will be built as a fat Jar, embedding all dependencies and run as a standalone
Java process.
As shown in the preceding diagram, MicroServices get their own containers for execution.
Containers are portable, independently manageable, lightweight run time environments.
Container technologies, such as Docker, are an ideal choice for MicroServices deployment.
Characteristics Of MicroServices:
There is no single, concrete, and universally accepted definition for MicroServices. However, all
successful MicroServices implementations exhibit a number of common characteristics.
Therefore, it is important to understand these characteristics rather than sticking to theoretical
definitions.
In the MicroServices world, services are first-class citizens. Micro services expose service
endpoints as APIs and abstract all their realization details. The internal implementation logic,
architecture, and technologies (including programming language, database, quality of services
mechanisms, and so on) are completely hidden behind the service API.
Well-designed MicroServices are aligned to a single business capability, so they perform only
one function. As a result, one of the common characteristics we see in most of the
implementations of the MicroServices are with smaller system components.
Hence in selecting supporting technologies, such as web containers, we will have to ensure that
they are also lightweight so that the overall System components remains manageable.
As MicroServices are autonomous and abstract everything behind service APIs, it is possible to
have different architectures for different MicroServices. A few common characteristics that we
see in MicroServices implementations are:
Different services use different versions of the same technologies. One MicroService may be
written on Java 1.7, and another one could be on Java 1.8.
Different languages are used to develop different MicroServices, such as one MicroService is
developed in Java and another one in Scala.
Different architectures are used, such as one microservice using the Redis cache to serve
data, while another microservice could use MySQL as a persistent data store.
As Hotel Search is expected to have high transaction volumes with demanded performance
requirements, it is implemented using Erlang. In order to support predictive searching,
Elasticsearch is used as the data store.
At the same time, Hotel Booking needs more ACID transactional characteristics. Therefore, it is
implemented using MySQL and Java.
In these two micro services, the internal implementations are hidden behind service endpoints
defined as REST/JSON over HTTP as MicroServices First Class Citizens.
As indicated in the preceding diagram, automations are typically applied during the
development, test, release, and deployment phases:
The development phase is automated using version control tools such as Git together with
Continuous Integration (CI) tools such as Jenkins, Travis CI, and so on. Automation of a full
build on every code check-in is also achievable with microservices.
The testing phase will be automated using testing tools such as Selenium, Cucumber, and
other AB testing strategies.As microservices are aligned to business capabilities, the number
of test cases to automate is fewer compared to monolithic applications, hence regression
testing on every build also becomes possible. As microservices are aligned to business
capabilities, the number of test cases to automate is fewer compared to monolithic
applications, hence regression testing on every build also becomes possible.
Automated deployments are handled using tools such as Spring Cloud, Kubernetes, Mesos,
and Marathon.
The ecosystem capabilities include: DevOps processes, API gateways, service registry, service
routing, centralized log management, extensive monitoring and flow control mechanisms.
Unfortunately, data access becomes much more complex when we move to a MicroServices
architecture. That is because the data owned by each microservice is private to that microservice
and can only be accessed via its API. Encapsulating the data ensures that the MicroServices are
loosely coupled and can evolve independently of one another. If multiple services access the
same data, schema updates require time‑consuming, coordinated updates to all of the services.
The solution is to use an event-driven architecture. In this architecture, a microservice publishes
an event when something notable happens, such as when it updates a business entity. Other
MicroServices subscribe to those events. When a microservice receives an event it can update its
own business entities, which might lead to more events being published.
As MicroServices are evolved from SOA, many characteristics of MicroServices are similar to
SOA. Let's first examine the definition of SOA.
A service:
Is a logical representation of a repeatable business activity that has a specified outcome (e.g.,
check customer credit, provide weather data, consolidate drilling reports). It is self-contained. It
may be composed of other services.It is a "black box" to consumers of the service."
The core difference between SOA and MicroServices lies in the size and scope. As the word
"micro" suggests, it has to be significantly smaller than what SOA tends to be. Microservice is a
small(er) independently deployable unit. A SOA can be either a monolith or it can be comprised
of multiple MicroServices. Martin Fowler says he likes to think SOA to be a superset of
MicroServices.
SOA initially started with SOAP, XML/WSDL Micro Service architecture uses REST API.
In SOA, services share the data storage Each service can have an independent data
storage
Micro Service Relations with Twelve-Factor apps
The code base principle advises that each application has a single code base. There can be
multiple instances of deployment of the same code base, such as development, testing, and
production.Code is typically managed in a source control system such as Git, Subversion, and so
on.
As per this each microservice should have its own code base, and this code base is not shared
with any other microservice. It also means that one microservice has exactly one code base.
2) Bundling dependencies
Each microservice should bundle all the required dependencies and execution libraries such as
the HTTP listener and so on in the final executable bundle.
3) Externalizing configurations
All services need to talk to some external resources during the life cycle of their execution. For
example, they could be listening or sending messages to a messaging system, sending an e-mail,
persisting data to database, and so on. All these services should be reachable through a URL
without complex communication requirements.
In the MicroServices world, MicroServices either talk to a messaging system to send or receive
messages, or they could accept or send messages to other service APIs. In a regular case, these
are either HTTP endpoints using REST and JSON or TCP- or HTTP-based messaging endpoints.
5) Externalizing logs
In a MicroServices ecosystem, this is very important as we are breaking a system into a number
of smaller services, which could result in decentralized logging. If they store logs in a local
storage, it would be extremely difficult to correlate logs between services.
In development, the microservice may direct the log stream to stdout, whereas in production,
these streams will be captured by the log shippers and sent to a central log service for storage
and analysis.
6) Exposing services through port bindings
Port binding is one of the fundamental requirements for MicroServices to be autonomous and
self-contained. MicroServices embed service listeners as a part of the service itself.
This principle suggests that processes should be stateless and share nothing. All MicroServices
should be designed as stateless functions. If there is any requirement to store a state, it should be
done with a backing database or in an in-memory cache.
This principle states the importance of keeping development and production environments as
identical as possible.This is primarily to manage the cost of infrastructure. The downside is that
if production fails, there is no identical environment to re-produce and fix the issues.
Not only is this principle valid for MicroServices, but it is also applicable to any application
development.
Apart from application services, most applications provide admin tasks as well. This principle
advises to use the same release bundle as well as an identical environment for both application
services and admin tasks. Admin code should also be packaged along with the application code.
Not only is this principle valid for microservices, but also it is applicable to any application
development.
MicroServices may make use of parallel processing and concurrency frameworks to further
speed up or scale up the transaction processing.
This principle advocates a strong isolation between the build, release, and run stages.
The build stage: refers to compiling and producing binaries by including all the assets required.
The release stage: refers to combining binaries with environment-specific configuration
parameters.
The pipeline is unidirectional, so it is not possible to propagate changes from the run stages back
to the build stage. Essentially, it also means that it is not recommended to do specific builds for
production; rather, it has to go through the pipeline.
In MicroServices, the build will create executable JAR files, including the service run time such
as an HTTP listener. During the release phase, these executable will be combined with release
configurations such as production URLs and so on and create a release version, most probably as
a container similar to Docker. In the run stage, these containers will be deployed on production
via a container scheduler.
Implementing a Micro Service:
Step-1: Configure the application with server port and database configurations as shown below:
As we are using Hibernate4 to perform the crud with database, we were also have been
configured the hibernate related properties.