MicroservicesInAction ch1
MicroservicesInAction ch1
MEAP Edition
Manning Early Access Program
Microservices in Action
Version 3
Copyright 2017 Manning Publications
For more information on this and other Manning titles go to
www.manning.com
©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/microservices-in-action
welcome
Thank you for purchasing the MEAP for Microservices in Action. We’re very excited to release
these first few chapters and we are looking forward to completing the book. This book is a
pragmatic guide for engineers who want to build and run well-designed, stable and resilient
microservice applications.
Microservices – applications built from loosely-coupled, autonomous services – can help
engineering teams deliver complex, long-running applications at pace without sacrificing
maintainability. Developing microservices drastically changed how we approached designing,
deploying and monitoring our applications; with this book we’re hoping to share the lessons
we learnt.
You’ll find the first three chapters of the book in this first MEAP release. In these chapters,
we explore approaches for designing services and architecting microservice applications, as
well as our thoughts on the underlying architectural principles and common challenges of
microservice development.
This book consists of four parts. Looking ahead, later chapters will further explore the
design, deployment and monitoring of microservice applications. The rest of Part 2 will
examine functional decomposition, microservice messaging, designing for reliability and
service frameworks.
Part 3 of this book covers deployment. We’ll demonstrate how you can get deployment
right for your services: being able to deploy rapidly and reliably is the difference between
success and failure for many microservice applications.
And in Part 4, we’ll examine how microservices increase the complexity of monitoring, and
how to build the tools you’ll need to support debugging, alerting and understanding system
behaviour.
Lastly, we hope you’ll take advantage of the Author Online Forum. We’ll be reading your
comments and responding throughout the MEAP. We deeply appreciate your feedback – it will
help us write a better book!
©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/microservices-in-action
brief contents
PART 1: THE LAY OF THE LAND
1 Designing and Running Microservices
2 Microservices at SimpleBank
PART 2: DESIGN
3 Architecture of a Microservice Application
4 Designing New Features
5 Distributed and (A)synchronous
6 Designing Reliable Services
7 Building a Reusable Microservice Framework
PART 3: DEPLOYMENT
8 Deploying Microservices
9 Deployment with Containers and Schedulers
10 Building a Delivery Pipeline for Microservices
PART 4: MONITORING & OBSERVABILITY
11 Building a Monitoring System
12 Using Logs and Traces to Understand Behaviour
13 Diagnosing Issues in an Evolving Application
14 Monitoring Deployments
©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/microservices-in-action
1
1
Designing and Running
Microservices
Software developers strive to craft effective and timely solutions to complex problems. The
first problem we usually try and solve is: what does our customer want? If we’re skilled (or
lucky), we get that right. But our efforts rarely stop there. Our successful application
continues to grow: we debug issues; we build new features; we keep it available and running
smoothly.
Even the most disciplined teams can struggle to sustain their early pace and agility in the
face of a growing application. At worst, our once simple and stable product becomes both
intractable and delicate: instead of sustainably delivering more value to our customers, we are
fatigued from outages, anxious about releasing, and too slow to deliver new features or fixes.
Neither our customers nor our developers are happy.
Microservices promise a better way to sustainably deliver business impact. Rather than a
single monolithic unit, applications built in this style are composed from loosely-coupled,
autonomous services. By building services that “do one thing well”, we can avoid the inertia
and entropy of large applications. Even in existing applications, we can progressively extract
functionality into independent services to make our whole system more maintainable.
©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/microservices-in-action
2
When we started working with microservices, we quickly realized that building smaller and
more self-contained services was only one part of running a stable and business-critical
application. After all, any successful application will spend much more of its life in production
than a code editor. To deliver value with microservices, our team couldn’t be focused on build
alone. We needed to be skilled at operations: deployment, observation and diagnosis.
Gather together the things that change for the same reasons. Separate those things that change for
different reasons.
In a monolithic application, we try and design for these properties at a class, module or library
level. In a microservice application, we aim instead to attain these properties at the level of
independently deployable units of functionality. A single microservice should be highly
cohesive: it should be responsible for some single capability within an application. Likewise,
the less that each service knows about the inner workings of other services, the easier it is to
make changes to one service – or capability – without forcing changes to others.
To get a better picture of how a microservices application fits together, let’s start by
considering some of the features of an online investment tool:
• Opening an account
• Depositing and withdrawing money
• Placing orders to buy or sell positions in financial products e.g. shares
• Modelling risk and making financial predictions
1. A user creates an order to sell some shares of a stock from their account
2. This position is reserved on their account, so it can’t be sold multiple times
3. It costs money to place an order on the market – the account is charged a fee
4. The system needs to communicate that order to the appropriate stock market
©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/microservices-in-action
3
Figure 1.1 shows how placing that sell order might look as part of a microservices application.
Figure 1.1 The flow of communication through microservices in an application that allows users to sell
positions in financial shares
In addition to these three characteristics, we can identify two more fundamental attributes of
microservices:
©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/microservices-in-action
4
comprehend.
The idea that microservices are “responsible” for coordinating actions in a system is the crucial
difference between this approach and traditional service-oriented architectures (SOAs). Those
types of systems often used Enterprise Service Buses (ESBs) or more complex orchestration
standards to externalize messaging and process orchestration from applications themselves.
In this model, services often lacked cohesion, as business logic was increasingly added to the
service bus, rather than the services themselves.
It’s interesting to think about how decoupling functionality in the above system helps us be
more flexible in the face of changing requirements. Imagine that you need to change how
fees are calculated. You could make and release those changes to the Fees service without
any change to its upstream or downstream services. Or imagine an entirely new requirement:
when an order is placed, we need to alert our risk team if it doesn’t match normal trading
patterns. It would be easy to build a new microservice to perform that operation based on an
event raised by the Orders service, without changing the rest of the system.
©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/microservices-in-action
5
Conversely, microservice applications are an example of Y-axis scaling, where a system may
be decomposed to address the unique scale needs of different functionality.
Let’s revisit our investment tool as an example:
If we build these features as microservices, we can choose the ideal technical tools to solve
each problem, rather than trying to fit square pegs into round holes. Likewise, autonomy and
independent deployment means that their underlying resource needs can be managed
separately. Interestingly, this also implies a natural way to limit failure: if our financial
prediction service fails, that failure is unlikely to cascade to the market trading or investment
account services.
So, microservice applications have some interesting technical properties:
• Building services along the lines of single capabilities places natural bounds on size and
responsibility.
• Autonomy allows us to develop, deploy and scale services independently.
Beyond these properties, we believe there are underlying principles that should drive your
technical and organizational decisions when building and running a microservice application.
Let’s explore them now.
• Autonomy
• Resilience
• Transparency
• Automation
• Alignment
AUTONOMY
We’ve established that microservices are autonomous. That is, each service operates and
changes independently of others. To ensure that autonomy, we need to design our services
so that they’re:
©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/microservices-in-action
6
Figure 1.3.
• Independently deployable: services will be developed in parallel, often by multiple
teams. Being forced to deploy these in lock-step or in an orchestrated formation would
result in risky and anxious deployments. Ideally we want to use our smaller services to
enable rapid, frequent and small releases.
Figure 1.3 Services may be loosely coupled by communicating through defined contracts that hide
implementation details
Autonomy is also cultural. It’s vital that accountability for and ownership of services is
delegated to teams responsible for delivering business impact. As we’ve established,
organizational design has an influence on system design. Owning their own services allows
teams to build iteratively and make decisions based on their local context and goals. Likewise,
this model is ideal for promoting end-to-end ownership, where a team is responsible for a
service in both development and production.
NOTE In Chapter 4 we’ll discuss developing responsible and autonomous engineering teams, and why this is
crucial when working with microservices.
RESILIENCE
©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/microservices-in-action
7
Consider our investment tool again. If the Market service is unavailable, the order won’t
be placed to market. However, this still means that the order can still be requested by a user,
and picked up later when the downstream functionality becomes available. 1
Conversely, splitting out our application into multiple services will multiply points of failure.
This also means that we need to account for what happens when failure does occur in order to
prevent cascades. This involves both design – favoring asynchronous interaction where
possible, using circuit breakers and timeouts appropriately – and operations – using provable
continuous delivery techniques and robustly monitoring system activity.
TRANSPARENCY
Most importantly, we need to know when a failure has actually occurred – rather than one
system, a microservices application depends on the interaction and behavior of multiple
services, possibly built by different teams. At any point, our system should be transparent
and observable to ensure that we both observe and diagnose problems.
Every service in our application will produce business, operational and infrastructure
metrics, application logs and request traces – so we’ll need to make sense of a huge amount
of data.
AUTOMATION
ALIGNMENT
Lastly, it’s critical that we align our development efforts in the right way. Fundamentally, we
should aim to structure our services, and therefore our teams, around business concepts. This
leads to higher cohesion.
To understand why this is important, let’s examine the alternative. Many traditional SOAs
deployed the technical tiers of an application separately – UI, business logic, integration, data.
We can call this horizontal decomposition. This is problematic, as cohesive functionality
becomes spread across multiple systems. New features may require coordinated releases to
1
Although if the user was aiming to get a particular price on their stock, this might not actually be a good idea!
©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/microservices-in-action
8
multiple services; new features may become unacceptably coupled to others at the same level
of technical abstraction.
Instead, a microservices system should be biased toward vertical decomposition: each
service should align to a single business capability, encapsulating all relevant technical layers.
NOTE In rare instances it might make sense to build a service that implements a technical capability, such
as integration with a third-party service, if this is required by multiple services.
We should also be mindful of the consumers of our services. To ensure a stable system, we
need to ensure we’re developing patiently and maintaining backwards compatibility – whether
explicitly or by running multiple versions of a service – to ensure that we don’t force other
teams to upgrade or break complex interactions between services.
Working with these five principles in mind will help us develop microservices well, leading
to systems that are highly amenable to change, stable and scalable. Now that we’ve
established some key principles behind microservices, let’s explore why they’re a compelling
technique for the development of long-running complex applications.
Pressure Description
Volumes The volume of activity performed by a system may outgrow the capacity of original
technology choices
International expansion International expansion is similar to growth in processing volumes, but may also lead to
data consistency, availability and latency challenges
New features New features may not be cohesive with existing features, or may be better solved by
different technologies
2
Martin Fowler expands on this pattern: http://martinfowler.com/bliki/MonolithFirst.html
©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/microservices-in-action
9
Engineering team growth As a team grows larger, lines of communication increase. New developers spend more
time comprehending the existing system.
Technical debt Increased complexity in a system – including debt from previous build decisions –
increase the difficulty of making changes
For example, Hailo wanted to expand internationally – which would have been challenging with
their original architecture – but also increase their pace of feature delivery. 3 Soundcloud
wanted to be more productive, as the complexity of their original monolithic application was
holding them back. 4 Sometimes the shift coincided with a change in business priority: Netflix
famously moved from physical DVD distribution to content streaming. Some of these
companies completely decommissioned their original monolith. But for many, this is an
ongoing process, with a monolith surrounded by a constellation of smaller services.
As microservice architecture has been more widely popularized – and as early adopters
have open-sourced, blogged and presented the practices that worked for them – teams have
increasingly begun greenfield projects with microservices, rather than building a single
application first. For example, Monzo started with microservices as part of their mission to
build a better and more scalable bank. 5
But what makes this architecture a good choice? There are plenty of successful businesses
built on monolithic software – Basecamp 6, StackOverflow and Etsy spring to mind – and
there’s a wealth of orthodox software development practice and knowledge fall back on. In
some companies, technical heterogeneity might be an obvious reason. For example, at Onfido
we started building microservices when we introduced a product driven by machine learning –
not a great fit for our original Ruby stack! Nevertheless, it’s not always so clear-cut.
Let’s consider the nature of complex systems. At the beginning of the chapter, we
mentioned that software developers strive to craft elegant and timely solutions to complex
problems. But the software systems we build are inherently complex. No methodology or
architecture can eliminate the essential complexity at the heart of such a system.
But that’s no reason to get downhearted! What we can do is ensure that the development
approaches we take result in good complex systems, rather than poor ones. Let’s think about
what we’re trying to achieve as software developers. Dan North puts it well:
The goal of software development is to sustainably minimize lead time to positive business impact.
The hard part in complex software systems is delivering value sustainably in the face of
change; to continue to deliver with agility, pace and safety even as the system becomes larger
3
https://sudo.hailoapp.com/services/2015/03/09/journey-into-a-microservice-world-part-1/
4
http://philcalcado.com/2015/09/08/how_we_ended_up_with_microservices.html
5
https://speakerdeck.com/mattheath/building-microservice-architectures-in-go
6
David Heinemeier Hansson coined the term “Majestic Monolith” to describe how 37Signals built Basecamp: https://m.signalvnoise.com/the-majestic-
monolith-29166d022228#.6674fa2ze
©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/microservices-in-action
10
and more complex. Therefore, we believe a good complex system is one where two factors
are minimized throughout the system’s lifecycle: friction and risk.
Friction limits our velocity and agility, and therefore our ability to deliver business impact.
As a monolith grows, the following factors may lead to friction:
• Change cycles are coupled together, leading to higher coordination barriers and higher
risk of regression
• Soft module and context boundaries invite chaos in undisciplined teams, leading to
tight or unanticipated coupling between components.
• Size alone can be painful: CI jobs, releases – even local application start-up – become
slower.
We can’t claim these qualities are true for all monoliths, but unfortunately they’re true for
most that we’ve encountered. Likewise, these types of challenges are a common thread in the
stories of the companies we mentioned above.
So how can microservices help? Isolating and minimizing dependencies at build time –
whether between teams or on existing code – allows developers to move faster. Table 1.3
compares microservices to monolithic applications regarding friction.
Development (Teams) Coupled; Sequential; Potentially impacting Independent; Parallel; Not impacting
other teams other teams
Technical debt Potentially spread across the whole application Encapsulated per service
You can see that microservices are easy to build and reason about individually. This is
beneficial both for the productivity of development in a growing organization, but also provides
a compelling and flexible paradigm for coping with increased scale or smoothly introducing
new technologies.
The small size of microservices is also a great enabler of continuous delivery. Deploys in
large applications can be risky and involve lengthy change, regression and verification cycles.
By deploying smaller elements of functionality, we better isolate changes to our active system,
reducing the risk of each individual deploy.
At this point, we can come to two conclusions:
• Developing small, autonomous services can reduce friction in the development of long-
running complex systems
• By delivering cohesive and independent pieces of functionality, we can build a system
©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/microservices-in-action
11
that is malleable and resilient in the face of change, helping us to sustainably deliver
business impact
That doesn’t mean everyone should build microservices. It’d be wonderful if there was an
objective answer to the question “do I need microservices?”, but unfortunately we can only
say “it depends” – on your team, on your company, and on the nature of the system that
you’re building. If the scope of your system is trivial, then it’s unlikely that you’ll gain benefits
that outweigh the added complexity of building and running this type of fine-grained
application. But if you’ve faced any of the challenges we mentioned earlier in this section,
then microservices could be a compelling solution.
Next, let’s dig a little deeper and explore the costs and complexity of designing and
running microservices.
Let’s look at how these challenges impact the design and runtime phases of microservice
development.
7
SOA is a wooly term. Although many principles of SOA are similar to microservices, the definition of the former is inextricably associated with heavyweight,
enterprise vendor tools, such as ESBs. A good overview of the differences between the two approaches is available here: http://oreil.ly/2ctDv4F
©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/microservices-in-action
12
together, they’re loosely coupled, and individually, encapsulate highly cohesive elements of
functionality. This is an evolutionary process: the scope of our services may change over
time, and we’ll often choose to carve out new functionality from, or even retire, existing
services.
But making those choices is challenging – and even more so at the start of developing an
application! The primary driver of loose coupling is the boundaries you establish between
services; getting those wrong will lead to services that are resistant to change, and overall, a
less malleable and flexible application.
Each microservice is responsible for a single capability. Identifying these capabilities requires
knowledge of the business domain of your application. Especially early in an application’s
lifetime, your domain knowledge might be at best incomplete, or at worst, incorrect.
Figure 1.4 Incorrect service scoping decisions may require complex and costly refactoring across service
boundaries.
Inadequate understanding of your problem domain can result in poor design choices. In a
microservices application, the increased rigidity of a service boundary – when compared to a
module within a monolithic application – means that the downstream cost of poor scoping
decisions is likely to be higher:
©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/microservices-in-action
13
These activities are illustrated in Figure 1.4. Of course, making design decisions based on
insufficient domain knowledge is hardly unique to microservices! The difference is in the
impact of those decisions.
NOTE In Chapters 2 and 4 we’ll discuss best practices for identifying and scoping services, using an example
application.
Anyone who’s designed an API might know how hard these properties are to achieve!
Contracts become the glue between services. Over time, contracts may need to evolve, but
need to maintain backwards-compatibility for existing collaborators. These twin tensions –
between stability and change – are challenging to navigate.
In larger organisations, it’s very likely that a microservice application will be built and run by
multiple teams, each taking responsibility for different microservices. Each team may have its
own goals, their own way of working, and their own delivery lifecycle. It can be difficult to
design a cohesive system when you also need to reconcile the timelines and priorities of other
independent teams!
Coordinating the development of any substantial microservice application will therefore
require the agreement and reconciliation of priorities and practices across multiple teams in
order to achieve overall business goals.
Lastly, designing microservices applications means designing distributed systems. There are
many fallacies made in the design of distributed systems, 8 including:
8
https://pages.cs.wisc.edu/~zuyu/files/fallacies.pdf
©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/microservices-in-action
14
It’s clear that assumptions that we might make in non-distributed systems – such as the
speed and reliability of method calls – are no longer appropriate and can lead to poor,
unstable implementation. Instead, you will need to consider latency, reliability and the
consistency of state across your application.
Figure 1.5 Possible points of failure when placing a sell order include database and network
Consider the questions we might need to answer when this application is in production:
• If something goes wrong and our user’s order isn’t placed, how would we determine
where the fault occurred?
• How do we deploy a new version of a service without affecting order placement?
• How do we know which services were meant to be called?
©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/microservices-in-action
15
Rather than eliminating risk, microservices move that cost later in the lifecycle of our system:
reducing friction in development, but increasing the complexity of how we deploy, verify and
observe our application in operation.
A microservices approach suggests an evolutionary approach to system design: ideally new
features can be added independently, without change to existing services. This minimizes the
cost and risk of change. But a decoupled and continuously changing system is also more
difficult to understand. Let’s build a new feature for our investment tool (Figure 1.6). At our
bank, we segment customers into tiers – gold, silver and bronze – based on how many orders
they place a month:
Figure 1.6 Services interact to qualify or disqualify a customer for a reward tier
©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/microservices-in-action
16
Imagine a bug is logged: the wrong fee was charged to a customer! To work out what
happened, we first need some way of tracing how the system did behave (what services where
called, in which order, and what was the outcome), but we also need some way of knowing
how the system should have behaved.
The above are both relatively simple examples. It’s not a leap to suspect that this could
get harder: imagine you’re deploying the market service in New York, Hong Kong, Tokyo and
London to minimize latency between the service and local stock exchanges. You might even
scale up and scale down capacity when the market opens and closes. It’s awesome that
microservices let us do this – rather than a cookie-cutter deploy of a single application – but
running that kind of application clearly isn’t straightforward!
Ultimately, we face two different operational challenges in microservices: observability and
multiple points of failure. Let’s focus on each of those in turn.
We touched on the importance of transparency back in Section 1.1.2. But why is it harder in
microservice applications? It’s because we need to understand the big picture. That big
picture needs to be assembled from multiple jigsaw pieces: the data each service produces
needs to be correlated and linked together to ensure we understand what each service does
within the wider context of delivering some business output. Individual service logs provide a
partial view of system operation: we need to use both microscope and wide-angle lens to
understand the system in full.
Likewise, because we’re running multiple applications, there may be – depending on how
we choose to deploy them – a less obvious correlation between underlying infrastructural
metrics – like memory and CPU usage – and the actual application. These metrics are still
useful, but less of a focus than they might be in a monolithic system.
Therefore, to have a transparent and observable system, we need to collect information
from multiple data sources and correlate that in some useful way. Ideally this information can
be observed both live – at the point of execution – and historical. But we also need to figure
out how to compare that to our expectations and assumptions about how our services should
operate.
We’re probably not being too pessimistic if we say that everything that can fail, will fail. It’s
important that we start with that mindset: if we assume weakness and fragility in the
constituent parts of our system, then that can better inform how we design, deploy and
monitor that system – rather than getting too surprised when something does go wrong!
Therefore, we need to consider how our system will continue operating despite the failures
of individual components. This implies that individually, services will need to become more
robust – considering error checking, failover and recovery.
©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/microservices-in-action
17
Thankfully, this is also an opportunity: we may be able to retain partial service in the face
of isolated failure.
NOTE In Chapter 6 we’ll teach you how to design resilient and reliable services.
Figure 1.7 The key iterative stages – design, deploy and observe – in the microservice development lifecycle.
Making well-reasoned decisions in each of these three stages will help you build applications
that are resilient yet flexible, even in the face of changing requirements and increasing
complexity. Let’s walk through each stage and consider the steps you’ll take to deliver an
application with microservices.
©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/microservices-in-action
18
That’s quite a lot of ground to cover! For now, let’s touch on each of the above so you can see
why each of these considerations is vital to a well-designed microservice application.
MONOLITH-FIRST?
There are two opposing trends to starting with microservices: monolith-first or microservices-
only. Advocates of the former reason that you should always start by the monolith, as you
won’t understand the component boundaries in your system at an early stage, as the cost of
getting these wrong is much higher in a microservices application.
On the other hand, the boundaries you might choose in a monolith are not necessarily the
same as you’d choose in a well-designed microservice application. Although velocity of
development may be slower to begin with, microservices will reduce friction and risk in future
development. Likewise, as tooling and frameworks mature, microservices best practice is
becoming increasingly less daunting to pick up.
Nevertheless, the advice in this book should be useful, regardless of whether you’re
thinking of migrating away from your monolith or starting afresh.
SCOPING SERVICES
Choosing the right level of responsibility for each service – its scope - is one of the most
difficult challenges in designing a microservice application. You’ll need to model services
based on the business capabilities they provide to an organization.
This isn’t straightforward! Consider our example from the beginning of this chapter: how
might our services change if we wanted to introduce a new, special type of orders? We’d have
three options to solve this problem (Figure 1.8):
Figure 1.8. Scoping functionality involves making decisions about whether capabilities belong in existing
services or require new services to be designed.
©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/microservices-in-action
19
Each of these options has pros and cons, which will impact the cohesiveness and coupling
between services in your application.
NOTE In Chapter 2 and 4, we’ll explore service scoping and how to make optimal decisions about service
responsibility.
COMMUNICATION
RESILIENCY
In a distributed system, a service can’t trust it’s collaborators. Not necessarily because
they’re coded poorly, or because of human error – but because we can’t safely assume the
network between or behavior of those services is reliable or predictable.
This means that you’ll need to design services that work defensively, by backing off in the
event of errors, limiting request rates from poor collaborators, and dynamically finding healthy
services.
CONSISTENCY
Once the application is distributed – where the application’s underlying state data is spread
across a multitude of places – consistency becomes challenging. We may not have guarantees
of the order of operations. It will be difficult to maintain ACID-like transactional guarantees
when actions take place across multiple services. This will affect design at the application
level: you will need to consider how a service might operate in an inconsistent state and how
to rollback in the event of transaction failure.
©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/microservices-in-action
20
involved in deploying a new service. Without this, you’ll invest all your energy in plumbing,
rather than creating value for customers.
In this book, we’ll teach you how to construct a reliable road to production for existing and
new services. The cost of deploying new services must be negligible to enable rapid
innovation. Likewise, this process should be standardized to simplify the system operation and
ensure consistency across different services. To achieve this, you’ll need to:
We’ve heard reliable deployment described as “boring”. Not in the sense that it’s unexciting,
but that it’s incident-free. Unfortunately, we’ve seen too many teams where the opposite is
true: deploying software is stressful and encourages unhealthy “all hands on deck” behavior.
This is bad enough for one service – if you’re deploying any number of services, the anxiety
alone will drive you mad! Let’s look at how these three steps lead to stable and reliable
microservice deploys.
It often seems like every language and framework has its own deployment tool. Python has
Fabric, Ruby has Capistrano, Elixir has exrm, and so on. And then the deployment
environment itself is complex: what server does an application run on? What are the
application’s dependencies on other tools? How do we actually start that application? At
runtime, an application dependencies (Figure 1.9) are broad and might include libraries,
binaries and OS packages (such as ImageMagick or libc), and OS processes (such as cron or
fluentd).
Figure 1.9 An application exposes an operational API and has many different types of dependency,
including libraries, binary dependencies and supporting processes.
©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/microservices-in-action
21
Continuous delivery is a practice where developers produce software that can be reliably
released to production at any time. Imagine a factory production line: to continuously deliver
software, we build similar pipelines to take our code from commit to live operation. Figure
1.10 illustrates a simple pipeline. Each stage of the pipeline provides feedback to the
development team on the correctness of their code.
Earlier, we mentioned that microservices are an ideal enabler of continuous delivery, as their
smaller size means that they can be developed quickly and released independently. However,
©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/microservices-in-action
22
• Building a set of validations through which our software must pass. At each stage of
our deployment process, we should be able to prove the correctness of our code.
• Automating the pipeline that delivers our code from commit to production.
Building a provably correct deployment pipeline will allow developers to work safely and at
pace as they iteratively develop services. Such a pipeline is a repeatable and reliable process
of delivering new features. Ideally we should be able to standardize the validations and steps
in our pipeline and use them across multiple services, further reducing the cost of deploying
new services.
Continuous delivery also reduces risk, because the quality of the software produced and
the team’s agility in delivering changes are both increased. From a product perspective, this
may mean we can work in a leaner fashion – rapidly validating our assumptions and iterating
on them.
NOTE In Part 3, we’ll build a continuous delivery pipeline using the Pipeline feature of the freely available
Jenkins continuous integration tool. We’ll also explore different deployment patterns such as canaries and
blue-green deployments.
Once we release a service, it’s not necessarily much use by itself. Our services need to
interact and collaborate to perform some useful function. We need to be sure that this is
reliable: that services can easily find point-to-point collaborators and can register with
appropriate queues to receive event-driven messages. For point-to-point collaborators, load
must be balanced across multiple instances. If instances fail – and they will – collaborators
need to be redirected to healthy services.
This is known more generally as service discovery. Within an ecosystem of microservices,
this can be especially challenging given the potentially large number of services and the
dynamic nature of service collaboration – services that work together today may work
together in different ways in the future.
NOTE In Chapter 12, we’ll explore different approaches to service discovery, such as server-side and client-
side discovery, and the role of service registries.
©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/microservices-in-action
23
Systems will fail, whether due to bugs introduced; runtime errors; network failures or
hardware problems 9. Over time, the cost of eliminating unknown bugs and errors becomes
higher than the cost of being able to react quickly and effectively when they occur.
Monitoring and alerting systems allow us to diagnose problems and determine the causes
for failures. We may have automated mechanisms reacting to the alerts that will spawn new
container instances in different data centers or react to load issues by increasing the number
of running instances of a service.
To minimize the consequences of those failures and the cascading of those throughout the
system we need to be able to identify and reduce all dependencies between services and
architect them in ways that will allow for partial degradation. One service going down should
not bring down the whole application.
It is important to think about the possible failure points of our applications, recognize that
failure will always happen and prepare accordingly.
To understand behavior across our services, we need to prioritize transparency in design and
implementation. Collecting logs and metrics – and unifying these for analytical and alerting
purposes – allows us to build a single source of truth to resort to when monitoring and
investigating the behavior of our system.
As we mentioned in Section 1.3.2, anything outside of the unique capability each service
offers can be standardized and abstracted. You can think of each service as an onion. At the
center of that onion, we have the unique business capability offered by that service.
Surrounding that, we have layers of instrumentation – business metrics, application logs,
operational metrics and infrastructure metrics – that make that capability observable. Each
request to the system can then be traced through these layers. The data collected from these
layers would then be pushed to an operational data store for analytics and alerting. This is
illustrated in Figure 1.11.
9
You’ve even got to watch out for squirrels: http://www.datacenterknowledge.com/archives/2012/07/09/outages-surviving-electric-squirrels-ups-
failures!
©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/microservices-in-action
24
Figure 1.11 A microservice should provide multiple layers of observable data, regardless of the business
capability it serves. This data should be considered into an operational data store.
In Part 4 of this book, we’ll discuss how to build a monitoring system for microservices; how to
collect appropriate data; and how to use that data to produce a “live” model for a complex
microservice application.
©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/microservices-in-action
25
organizations which design systems ... are constrained to produce designs which are copies of the
communication structures of these organizations
“Constrained” might suggest that these communication structures might limit and constrict the
effective development of a system. In fact, microservices practice implies the opposite: that a
powerful way to avoid friction and tension in building systems is to design an organization in
the shape of the system you intend to build.
Deliberate symbiosis with organizational structure is just one example of common
microservices practice. To be able to realize benefits from microservices and adequately
manage their complexity, we need to develop working principles and practices that are
effective for that type of application, rather than using the same techniques that we used to
build monoliths.
1.5 Summary
This chapter introduced microservice applications, discussed the challenges of designing and
running them well, and gave an overview of the design, deployment and monitoring practices
we’ll focus on throughout this book. In this chapter, you learned that:
Teams adopting microservices need to be operationally mature and focus on the entire
lifecycle of a service, not just at the design and build stages
©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/microservices-in-action