Share
Embed
On the criteria for decomposing systems into microservices
Mucon 2016 keynote, 7 November
Adrian Colyer
November 07, 2016
Transcript
49 slides
-
Adrian Colyer | @adriancolyer On the criteria to be used
in decomposing systems into microservices -
Copyright: Maxim Popov, 123RF Stock Photo What does it take
to succeed with microservices? 1 2 System design Platform & processes 3 Culture -
A module is a unit of work assignment Copyright: Maxim
Popov, 123RF Stock Photo 1. Shorten development time 2. Improve system flexibility 3. Improve understandability -> better overall design 4. Independent deployment 5. Fine-grained scaling 6. Fault isolation -
Copyright: Maxim Popov, 123RF Stock Photo “The effectiveness of a
modularization is dependent upon the criteria used in dividing the system into modules.” -
“...it is almost always incorrect to begin the decomposition of
a system into modules on the basis of a flowchart.” “ We propose instead that one begins with a list of difficult design decisions or design decisions which are likely to change. Each module is then designed to hide such a decision from the others.” “ Since, in most cases, design decisions transcend time of execution, modules will not correspond to steps in the processing…” -
Copyright: Maxim Popov, 123RF Stock Photo “The connections between microservices
are all of the assumptions which the microservices make about each other.” -
“We may make only those changes which do not violate
the assumptions made by other microservices about the service being changed.” Open (internal) source considered harmful! -
Great user experience Rapid delivery Support future change What comes
first? And how soon to divide into microservices? -
“The earlier in the lifecycle of a project that you
make a decision, the more difficult it is likely to be to change it as assumptions grow around it.” -
Circa 1979 (& 2016!) Common Problems 1. We were behind
schedule and wanted to deliver an early release, but found that we couldn’t subset the system 2. We wanted to add a simple feature, but found it would have required rewriting all or most of the current code. 3. We wanted to simplify the system by removing some feature, but taking advantage of it meant rewriting large sections of the code 4. We wanted a custom deployment (e.g. in dev, or test environments) but the system wasn’t flexible enough. -
Four steps to a better system structure Identify subsets first
Apply Information hiding Hierarchical virtual machines Design the uses structure -
“To avoid the problems that we have described as a
‘chain of data transforming components’ it is necessary to stop thinking of the system in terms of components that correspond to steps in the processing. This way of thinking dies hard...” -
“In many software design projects, the decisions about what other
component programs to use are left to individual systems programmers… Unless some restraint is exercised, one may end up with a system in which nothing works until everything works.” -
THE RULES: Microservice A is allowed to use microservice B
iff: • A is essentially simpler because it uses B • B is not substantially more complex because it is allowed to use A • There is a useful subset containing B and not A • There is no conceivable useful subset containing A but not B And of course, it does not introduce any cycles into the dependency graph -
About that first rule... A is essentially simpler because it
uses B Broken when A calls B, for B’s benefit! There’s no better information hiding than not knowing a service is there at all. Making an RPC call leaks: • There is a service • It’s here • It’s currently available Events are very powerful in this situation. -
Source: Exploring complex networks, Nature vol. 410, 2001 Erdös -
Rényi Random Graph n microservices c connections phase transition at c = n/2 -> giant connected component -
“After examining hundreds of error-prone DRSpaces over dozens of open
source and commercial projects, we have observed that there are just a few distinct types of architecture issues, and these occur over and over again…” -
BF = Bug Frequency, BC = Bug churn, CF =
Change Frequency, CC = Change Churn How much worse for architecture hotspots? -
MAIN SOURCES OF MAINTENANCE COSTS: 1. Unstable interface 2. Implicit
cross-module dependency 3. Unhealthy interface inheritance hierarchy 4. Cross-module cycle 5. Cross-package cycle -
The data says: The two most important areas to pay
attention to are • the interfaces of the modules and how well they hide information so that changes can be made without cascades, and • the uses structure of the system -
Identifying and quantifying architectural debt: • Architectural debts consume 85%
of the total project maintenance effort in projects studied • The top five modularity debts alone consume 61% of the total effort • Modularity violation is the most common and expensive debt overall - it accounts for 82% of the total effort in HBase! • Top debts only involve a small number of files/modules, but consume a large amount of the total project effort • About half of all architectural debts accumulate interest at a constant rate. -
“Defining interfaces is the most important part of system design.
Usually it is also the most difficult, since the interface design must satisfy three conflicting requirements: an interface should be simple, it should be complete, and it should admit a sufficiently small and fast implementation.” -
LAMPSON’S LAWS: 1. Capture the minimum essentials of an abstraction,
don’t rush to generalize 2. Don’t promise more than you know how to deliver. Especially don’t add features for the few that penalise the many 3. Make it fast, rather than general or powerful 4. Sometimes, it’s worth a lot of work to make a fast implementation of a clean and powerful interface. But only when you already know the importance of the interface. -
Lampson: make sure your interface affords an efficient implementation. Clements
et al.: here’s how (Scalable Commutativity Rule) 2013 -
“whenever interface operations commute, they can be implemented in a
way that scales.” How to design a commutative interface: 1. Decompose compound operations(*) 2. Embrace specification non-determinism 3. Permit weak ordering 4. Release resources asynchronously -
4 patterns for scalable implementations 1. Layer scalability (hierarchies of
virtual machines…) 2. Defer work 3. Precede pessimism with optimism 4. Don’t read unless necessary -
“Recently, a lot of interest has been shown in microservices.
In these systems, there are multiple services each with its own code and data, and ability to operate independently of its partners… This paper proposes there are a number of seminal differences between data inside a service and data sent into the space outside of the service boundary.” -
Monoliths live in the “now” As time marches forward and
transactions commit, each new transaction perceives the output of the transactions that preceded it. The executing logic of the service lives with a clear and crisp sense of “now” Copyright: Maxim Popov, 123RF Stock Photo -
“Going to microservices is like going from Newton’s physics to
Einstein’s physics. Newton’s time marched forward uniformly with instant knowledge at a distance. Before microservices, distributed computing strove to make many systems look like one with RPC, 2PC etc.. In Einstein’s universe, everything is relative to one’s perspective. Microservices has “now” inside (a service) and the “past” arriving in messages.” -
Refactor -> Extract Microservice Refactor -> Change Model of Space
and Time Copyright: Maxim Popov, 123RF Stock Photo -
Copyright: Maxim Popov, 123RF Stock Photo Now: inside a microservice
Past: messages arriving from other services Future: commands sent to other services -
“Operands may live either in the past or the future
depending on their usage pattern. They live in the past if they have copies of unlocked information from a distant service. They live in the future if they contain proposed values that hopefully will be used if the operator is successfully completed. Between the services, life is in the world of “then”… This means that data on the outside lives in the world of “then”. It is past or future but it is not now.” -> It is up to the microservices themselves to reconcile now and then. -
Data on the Outside • Immutable • Identifiable, e.g. “The
New York Times” ? • Stable • Any referenced data is also immutable • Messages themselves are also immutable (think retries) “Stable data has an unambiguous and unchanging interpretation across space and time… One excellent technique for the creation of stable data is the use of time-stamping and/or versioning.” -
The data says: The two most important areas to pay
attention to are • the interfaces of the modules and how well they hide information so that changes can be made without cascades, and • the uses structure of the system Pay attention to data on the inside vs data on the outside Don’t forget the power of events / messages Some takeaways -
A new paper every weekday Published at https://blog.acolyer.org. 01 Delivered
Straight to your inbox If you prefer email-based subscription to read at your leisure. 02 Announced on Twitter I’m @adriancolyer. 03 Go to a Papers We Love Meetup A repository of academic computer science papers and a community who loves reading them. 04 Share what you learn Anyone can take part in the great conversation. 05 -
Adrian Colyer | @adriancolyer Paper links • On the criteria
to be used in decomposing systems into modules https://blog.acolyer.org/2016/09/05/on-the-criteria-to-be-used-in-decomposing-systems-into-modules/ • Information distribution aspects of design methodology: https://blog.acolyer.org/2016/10/17/information-distribution-aspects-of-design-methodology/ • Designing software for ease of extension and contraction: https://blog.acolyer.org/2016/10/31/designing-software-for-ease-of-extension-and-contraction/ • Hotspot patterns: The formal definition and automatic detection of architecture smells https://blog.acolyer.org/2016/06/10/hotspot-patterns-the-formal-definition-and-automatic-detection-of-architecture-smells/ • Identifying and quantifying architectural debt https://blog.acolyer.org/2016/06/13/identifying-and-quantifying-architectural-debt/ • Exploring complex networks https://blog.acolyer.org/2015/05/25/exploring-complex-networks/ • Hints for computer system design https://blog.acolyer.org/2016/09/16/hints-for-computer-system-design/ • The scalable commutativity rule: designing scalable software for multicore processors https://blog.acolyer.org/2015/04/24/the-scalable-commutativity-rule-designing-scalable-software-for-multicore-processors/ • Data on the outside vs data on the inside https://blog.acolyer.org/2016/09/13/data-on-the-outside-versus-data-on-the-inside/