
Microservices – Not a free lunch - olalonde
http://highscalability.com/blog/2014/4/8/microservices-not-a-free-lunch.html
======
Someone
See also:

    
    
      - Subroutines - Not a free lunch
      - Libraries - Not a free lunch
      - Client-Server - Not a free lunch
      - OO - Not a free lunch
      - Multiprocessing - Not a free lunch
    

Many of these arguments apply to these, too. The main difference is that of
scale. Latency and call overhead are way larger than for the examples I gave.

Improved tooling can bring both down, but not by that much. That's why you
will not see many micro services that are truly micro. You won't see (I hope)
a 'printf' micro service, or not even a 'ICU' micro service. A regex service
might make sense, if the 'string' it searches in is large and implicit in the
call (say a service that searches Wikipedia), but by that time, it starts to
look like a Database query. Is that still micro?

~~~
possibilistic
(My company loves microservices, so I'll weigh in at a really high level.)

The author speaks of the complexity in managing and coordinating processes in
a distributed system. By designing a microservice, you trade simplicity of
software design for increased operational complexities. There's a shift in
terms of problem solving too--it migrates from the cross functional engineers
to the DevOps and distributed systems engineers.

Don't get me wrong--I think microservices are brilliant and make reasoning
about application design easier. But be prepared to bring in some heavy
engineering talent to coordinate all the things. Until there are open source
frameworks for handling the difficult bits, it might be unwise for a start-up
to go the microservice route. Microservices are purposed for scale (since
reasoning about traffic is easier with a simpler service and there predictable
traffic patterns from a microservice's clients).

Edit :

In terms of the examples you mention, I you may have the wrong idea. Think
about fulfilling a specific goal or class of functionality, and make that a
microservice: email gateway microservice, user/session microservice(s), SMS
gateway microservice, etc. Each is a component that responds to various
request types (you really should use RPC instead of REST for deadlines,
retries, cancellation, pooling, etc.), but they all sit within a single domain
of purpose. The service could be stateless or not, but you try to make the
requests idempotent to aid client reasoning.

To again cite your example, several services may use regex, but there might be
only one authority on "normalized input" (eg. addresses, etc.). Or maybe there
is a client lib for that.

This brings up another point. Services at the periphery (dependency graph-
wise) are coordinated by interior services. That can get complicated...

------
olalonde
On a related note, is anyone aware of any tool(s) to declaratively describe an
application architecture and automate its deployment on something like AWS or
in a single virtual machine + docker? For example "I want 10 replicated
microservice1 processes and 5 replicated microservice2 processes in front of a
nginx load balancer. Also, throw in a Redis and a PostgreSQL database." This
would be immensely useful for (one man show) developers who don't necessarily
have the time or experience to "properly" setup and fine tune infrastructure.
I think what I'm describing is known as "Infrastructure as code" in DevOps
parlance.

Edit: Since this question is getting many replies, I'll be a bit more specific
in what I am looking for. Is there a tool that would let me describe the
infrastructure and deploy it on a given cloud provider _but also_ have the
ability to deploy the same infrastructure on my local machine (using
VMs/docker) for development purposes.

~~~
chrisan
> Edit: Since this question is getting many replies, I'll be a bit more
> specific in what I am looking for. Is there a tool that would let me
> describe the infrastructure and deploy it on a given cloud provider but also
> have the ability to deploy the same infrastructure on my local machine
> (using VMs/docker) for development purposes.

Seems like the [https://www.hashicorp.com/](https://www.hashicorp.com/) guys
would have something, perhaps Terraform/Atlas?

I have not done this yet obviously but am in the same boat as you for our
company goals this year

~~~
jacques_chester
What I liked most about Terraform was the explicit separation of planning and
execution.

------
DanielBMarkham
I'm really happy to see DevOps, CD, and Microservices take off, although, as
usual, I'm a little perplexed as to why we need new slang. But hey, if it
works to get the message out, I'm all for it.

These things are not new, but like so many other ideas, they're just old ideas
re-appearing in a context that had forgotten about them.

Traditionally, many of the potential problems the author relates have been
solved by architectural conceits. For instance, standardize on a programming
language and datastore, then share all persistence-related files. (I'd
strongly suggest a FP language, preferably used in a pure manner). Then you've
decreased the "plumbing" issues by a couple orders of magnitude, lowered the
skill bar for bringing in new programmers, and you can start talking about
using some common testing paradigms to work on the other issues.

I'm a huge fan of microservices, but it's good to talk about the bad parts
too, lest the hype overrun the reality.

~~~
waps
It's just a technology cycle. Microservices have serious disadvantages as
well, which will cause their elimination in, oh, 5 years if they're lucky.

1) They're not really simple. If you take essential functions like a key-value
store, that'd be a microservice. Simple ? Yeah right. Business logic ...
simple ? Yeah right.

2) It's slower. You can wine all you want, but when it comes right down to it,
there's a reason people avoid crossing the network, and the microservice
approach essentially comes close to crossing the network every single time you
cross module boundaries. You'll be spending 50%+ of your cpu time marshalling
and unmarshalling and waiting for transmission, even on the same system.

This also manifests in all these "no-sql" datastores. They have all the
problems of sql datastores, but they have one more. There's no way to have
indexes. So in a table indexing all your sales by "id", the only way to find
sales of product "X" is by going through each and every record (you can build
indexes yourself, but it's not easy and it's sure as hell not flexible. Plus I
guarantee you'll do it wrong the first 10 times). This means that retrieving
10 sales records takes the exact same amount of time as generating the yearly
sales reports. In other words : you won't be doing it, because it takes too
long.

3) There's just so damn many of them if you want to achieve anything useful.
Every single one of them needs to be sufficiently well-designed to operate
like an individual web server. So (d)dos-resistance, fairness, anti-slowloris,
anti-starvation, autoscaling, resource exhaustion (like maximum number of file
descriptors ...) correct sharding, access control (not too tight, not too
loose, ... correct caching of security credentials, ...), and load testing,
you've thought of all that for that "really small and dumb" service that
basically copies information across the payment/non-payment firewall right ?
If you haven't ... prepare to be surprised.

A related problem here is the shear amount of diagnostic monitoring you'll
need.

4) They are inflexible, and don't deal well with different data types (this is
one of the things object oriented programming solved). They work well when
they deal with strings, or with company-standard datatypes. Only companies
don't like to have company-wide standards. Yeah, I know Sun and to a lesser
extent Facebook succeed at it, but does your company ? Last time I consulted
at a bank they had systems interoperating using every interchange format from
fixed-width fields (old cobol code), 5 different kinds of xml, and of course
json and a dozen binary formats. Microservices can't work in such an
environment. It destroys the flexibility of individual actors. The argument
here, of course, is that that is a good thing, and I'd say you're right, but
you've just created yourself a hell of a lot of enemies, some of them
powerful.

5) It's extremely hard to orchestrate integration across multiple
microservices. The first thing this will manifest in is testing. How do I test
one service ? The answer is "unit tests" or "a system test". But this is the
result of a fundamental misunderstanding. As a company, or even an IT
department, you don't really care if unit tests and/or system tests succeed
for a microservice. You care that if you connect a -> b -> c -> d -> e -> f ->
g (and usually this is a network of microservices, not a sequence) that you
can sell gizmos on your website.

Testing if that works requires throwing up three dozen services. Now first,
having watched the netflix talks, they do this. Congrats. That's can't be
easy. They also talk about the disadvantages : they have 3 teams doing nothing
other that making that work, and it eats a significant part of their AWS
resources. They can't do it on developer's workstations, nor even on a number
of them.

The second thing this will manifest in is the cross-microservice redesign. Say
a new law comes in. With a payment we now need to have a scan of the driver's
licence of the buyer (say "gizmos" are treated like alcohol). So we simply
need an extra image field going through the payment system. Oh-oh. The payment
system is 8 microservices, and therefore around 64 interfaces to the rest of
the system. Let's be generous ... only about 30 need to be redesigned. There
is nothing to help. Refactoring, or even type checking doesn't work across
microservice boundaries.

This presents 2 problems.

First is that it's a hell of a lot of work, even though most services only do
basic things and don't care about the new data. But they still copy the data,
save it, ... each of them needs logic to deal with missing data (historical
data for instance), and the copy from one json dict to another needs to be
implemented. And as you'll find every microservice has it's own methods for
dealing with said datatype, you'll be checking up to 8 libraries for
marshalling problems.

Second is testing. Any error you make won't come up unless you're testing
multiple of those services simultaneously. If you manage to have just a bit
more complexity in your system, those problems won't come out until the
massive full-system integration test. You know, the one you can't do yourself,
and even your whole department can't do. Oh-oh. That's an awfully long
feedback loop to find those 3 dozen places where you forgot to copy that field
across.

~~~
DanielBMarkham
Your comment was in some ways better than the original article! Thanks.

But, as you know, many of these problems are either solved or non-existent in
Big-Monolithic-App-land.

So -- take the things that worked there and use them. Like I said, a common
set of shared source code that handles all persistence means all apps can talk
to each other using the same code. Changes don't break the chain. Stuff can be
fixed in one spot. And so on.

The orchestration and testing pieces deserve special attention. I think you're
going to end up with as many folks writing test/monitor/break code as you are
microswervices. And that's probably a good thing. But you need to plan for
that.

As far as the hype cycle, I've seen this over and over again. As far as I can
tell, the driver is over-specialization of developers. Some new buzzword comes
out, people teach and train around that, and suddenly you've got somebody
called a "DBA" that can't write a web service. So then you need a "Front-end"
guy, and so on. This industry is constantly labeling things, over-developing
them, creating work silos that lead to poor performance, then going back and
relabeling things again. There's some magic number of developers where you
need specialists, but it's not 10, or even 40. The longer you put off creating
silos, the better the entire effort is.

EDIT: In fact, I'll just say it: if you want to swim in the ocean of nirvana
that is microservices, use pure FP and share all the source code that involves
persistence.

~~~
parasubvert
There's been a drive towards "full stack developers" lately:
[http://www.laurencegellert.com/2012/08/what-is-a-full-
stack-...](http://www.laurencegellert.com/2012/08/what-is-a-full-stack-
developer/)

That said, most of human history has involved specialization, modularity, and
abstraction driving greater productivity.

So on one hand, you have work-silos, on the other you have the power of
modularity. I think difference with software is that most of the productivity
constraints happen at the interfaces. Teams need people that can integrate.
They can be generalists, or specialists in a few areas.

Earlier in your post you suggest:

"But, as you know, many of these problems are either solved or non-existent in
Big-Monolithic-App-land. So -- take the things that worked there and use them.
Like I said, a common set of shared source code that handles all persistence
means all apps can talk to each other using the same code. Changes don't break
the chain. Stuff can be fixed in one spot. And so on."

IME, multiple teams using the same library can be helpful (if voluntary) or a
complete disaster (if forced). The incentives of the library maintainers are
not always that of every team.

------
polskibus
In my opinion the article does not put enough weight on lack of transactions
in a microservices architecture. Of course you can add distributed
transactions, but doing so makes the architecture much more intertwined and
much less error-proof.

~~~
macNchz
It's always fun diagnosing rarely occurring race conditions in a system with
many services, work queues, some eventual consistent components, and various
databases with their own transactions.

------
ExpiredLink
> _Implicit Interfaces_

This is a crucial point. 'We use microservices' does not say much unless you
can describe how you design consistent and granular service interfaces.
Otherwise you most probably just produce microservice spaghetti.

------
cs02rm0
I was prepared to be convinced, what in our field does bring nothing but
benefits? I didn't see much to worry about here though;

* who cares if you're deploying 20 services or 1 when you run your deploy script? * who doesn't have an operationally focused dev team? * who isn't already dealing with interfaces even if not micro services? * since when do micro services have a monopoly on distributed architectures or asynchronicity?

I can't agree testing is harder either. Too much fluff in this article to read
much value into it.

~~~
ryanbrunner
Regarding interfaces, dealing with an in-process, code level interface is just
on the surface simpler than dealing with an external interface like a JSON
endpoint. If you're working with a statically-typed language, the comparison
isn't even worth making - a contract that needs to be extensively tested turns
into a compile error. Even in a dynamically typed language, the tooling to
test that methods are being called correctly are much more mature and
developed than determining that two independent services are conforming to the
same contract.

~~~
ayrx
Just wondering out loud: maybe it's possible that tooling for this just hasn't
been written yet?

Something along the lines of declaratively stating what a JSON endpoint should
be like and having a tool automatically assert that the services conform to
that interface doesn't look impossible.

~~~
logicchains
F# could do this with type providers. Or, something like Google Protocol
Buffers could be used.

~~~
cs02rm0
Or Java with JAX-RS. Or one of probably hundreds of alternatives.

------
aidos
I enjoyed the article. As ever, there are tradeoffs and your milage will vary
using different approaches.

This doesn't seem like an entirely fair comparison:

 _" It seems to me that all three of these options are sub-optimal as opposed
to writing the piece of code once and making it available throughout the
monolithic application."_

There's a different scenario that could have played out with how to share a
library between different services. You could have written the bulk of your
application in the same language, like a monolithic application but split into
several services. In that case you could create a library for your tax
calculations and use it freely within your services.

For me, I split my application into a small number of services and, as much as
possible, split things out into libraries to make reuse simple (more
libraries, thiner applications).

Sometimes I use different languages, but when I do, I consider very carefully
whether the (rather large) tradeoff that presents will be worth it in the long
run for what I'm getting in the short term.

A question: when people talk about microservices, how small are they talking?

~~~
blatherard
The OP addresses this as one of the three options:

 _The final option is to share resources such as a tax calculating library
between the services. This can be useful, but it won 't always work in a
polyglot environment and introduces coupling which may mean that services have
to be released in parallel to maintain the implicit interface between them.
This coupling essentially mitigates a lot of the benefits of Microservices
approaches._

~~~
aidos
I rambled a little - my point was that by avoiding te polyglot language
situation you make things easier (and closer to the monolithic application). I
take the other point though, parallel releases are harder.

------
gbog
Listing the difficulties on microservices is useful, but let's not forget the
difficulties encountered in monolithic big applications, which are the reason
for splitting into smaller pieces.

In the big app 1) a single syntax error breaks everything. 2) simply loading
all the app takes a huge part of ram, and tests are very slow. 3) there is a
gigantic dependency tree, as when you depend on a module you also depend on
every ones of the module dependencies. 4) Almost no one knows everything about
the app. 5) it is impossible to split the company into separate services
without getting fights about shared code and architecture decision.

~~~
cpks
It's a false dichotomy. The split isn't about no abstractions vs. services,
but about whether the abstractions should be behind a network boundary. Let's
look at these one at a time.

1) A single syntax error will _still_ break everything in a microservices
architecture if the service in question is any essential service. In my
experience, most services are essential. In a dynamically linked architecture,
the failure occurs when you try to pull in the library. In a well-designed
dynamically linked architecture, you can opt to not pull in optional
components.

2) If you're an idiot and build everything monolithicly. A well-designed non-
services architecture has many independent and independently testable
libraries. Integration testing does require the whole system, both with and
without services. In this case, both the resource usage and startup time is
much lower without services.

3) Ditto for services, if you do integration work. Not so for independent
libraries, if you do not.

4) Question of where you put the abstractions, not how you make them.

5) Again, question of where you put the abstractions, not how you make them.

The key reason for services is isolation, failover, and independent
deployability.

There are a bunch of programmers out there who were only taught one way to
make abstractions (be that services, objects, or what-not), and assume
everything else means abstractionless spaghetti code. That's simply not the
case. Structured, functional, and other modes of programming have the same
quality of abstractions as OO. Likewise for whether you link statically,
dynamically, or over a services boundary.

~~~
pron
Not to mention the big performance hit of marshaling data, and the waste of
resource when running separate processes.

Another important performance hit has to do with scheduling and
multithreading, as crossing IO boundaries (even on the same machine) coalesce
all threads into one (and then multiplex the work again on the other end).

------
matthewmacleod
Not a fan of microservices myself - IME it pushes the complexity that exists
in any application into implicit interfaces and dependencies between
microservices. The difference is that we have better tools for managing this
complexity at the application level than we do at the operation level.

Still a big proponent of SOA generally, though. I think the granularity when
defining "service" is ultimately going to vary from application to
application, however, leaving the sweet spot slightly larger than e.g.
Amazon's microservices.

~~~
parasubvert
I'm not sure I understand this.

SOA == microservices, basically. Arguably one could say that Microservices =
SOA minus ESBs, which is what necessitated the new term. IOW, don't hide your
mess of dependencies in a black box, expose and manage them where they're
needed.

The granularity of the service is generally determined by the size and
responsibility of the maintaining team, and will vary from company to company.

With regards to tooling, I'm curious what you're referring to. Some selection
of tools like Splunk, AppDynamics, New Relic, or Boundary certainly can handle
both applications and microservice chains, no?

~~~
matthewmacleod
I've reconsidered what I wrote above – you're right. I'd built a mental model
of what "microservice" and "SOA" meant that apparently isn't entirely in line
with what others are commonly using.

I maintain that it's not a panacea, and that complexity is pulled into other
places (operations) where we perhaps don't have equally effective tools at
this point. I'd also argue that it's difficult to understand the correct level
of granularity (and potentially expensive to fix errors in this decision). But
it's not the problem I made it out to be.

~~~
parasubvert
I agree with the above. It's not a panacea but it seems to be worth exploring
further as a way (not THE way) to manage (not cure) scale/complexity in multi-
team environments.

------
programminggeek
Fundamentally, there isn't a huge difference between microservices and
monotlic apps if both systems do the same thing. However, a lot of the issues
of general complexity are more apparent in one approach or the other.

For example, breaking changes are breaking changes in either system. It's not
an issue of architecture style, it's a matter of business needs changing, and
thus protocols change. A change in protocol breaks the existing protocol.

We understand this intuitively when you are talking about a de-facto protocol
like HTTP, but we seem to think our own programs are somehow different. They
aren't.

Architecture is about taking the essential complexity of a problem and
creating components and protocols to solve a problem in a way that makes the
most sense for the team trying to solve it. Monolithic apps or microservices
then should be a question more of what your team is going to execute well as
much as it is a question of which structure more elegantly solves the problem
at hand.

------
mavdi
I've pretty much faced all of the problems mentioned in this article. An
application is set of services with a certain complexity that work together.
In some cases this complexity just gets transferred from service level to
orchestration level.

Don't get me wrong, I love microservices and will try to use them in all my
future work, but I think where people often go wrong is that they over commit
to it without realising the downsides. I often see people casually using AMQP
queues for pretty much everything, only when they need the worker service to
talk back to the originating service that they realise they've made a wrong
architectural decision.

~~~
muffs
Can you elaborate on your latter point? Why is that considered an incorrect
architectural decision?

~~~
marktangotango
For example if the caller needs the result of a possible long running task, ie
success or fail, then it has to maintain state in a way to associate the async
queue message back to the task. Zeromq has the concept of request/reply to
handle this, its more problematic with plain old queues, the solution ive
worked with is mq for tasks, rest calls for results. Yes it sucks.

~~~
muffs
Awesome, thanks for the explanation.

------
blablabla123
Why is highavailabilty.com slower than most other websites? :>

~~~
ExpiredLink
Because it's highavailabilty.com, not highspeed.com.

