After a recent conference I had some good questions and discussions about the current state of services meshes (Istio in this case), thus decided to note down what I find interesting about them.
I'm a fan of infrastructure-level (
polyglot) service meshes. The premise excites me as much as Android ten years ago. Working over those years with
SOA, EDA, REST Hypermedia API's, API Management, Microservices and language-bound Services Meshes (
Netflix / Pivotal, Lightbend's
Reactive), I tend to be careful about the resolution of their promises though.
This post is about 3 lesser known effects of service meshes. My
last post already covered complexity, emergence and observability in a more general way so I'll limit those topics.
Reasoning
Horizontal scalability in the multi-core age is one of the main arguments behind basically all modern stateless software architectures.
Consistency in distributed systems, immutability and state-handling are often mentioned common properties, typically used to justify functional programming paradigms. To me it seems though, their most important common property is a complex, emergent network graph structure. Layers and tiers cannot represent contemporary systems anymore. Those systems have a complex adaptive graph structure in space (infrastructure, users, component interactions) and time (
versioning / one codebase,
rainbow releases, experiments,
DevOps, event order, routing).
We could observe a lot of frameworks in the last years quietly move towards
declarative graph alterations. The first I remember were
Android Intents and
Puppet. But more recently it was
React,
Tensorflow,
Beam,
Kubernetes,
Eve (RIP) not to forget the re-emergence of
SQL combined with flexible
consistency models and
stream processing.
All of those come with a robust, well-defined domain vocabulary and set of patterns that allows to precisely define desired behaviour. A graph encourages modularization and reuse, it allows for
division of labor: Better specialization while making the overall concept better understandable. This, in turn, allows a wider, more diverse group of people to
reason and converse about the
behaviour of the system. The shared language and
culture may hopefully enable them to learn alongside the system, what
Nora Bateson calls "symmathesy". It requires all actors in the system to define goals and dependencies, versioned together in one
codebase across layers and components, documentation, test (spec), customer support feedback and
architectural decisions. That's why all good
(micro) service-architecture principles contain continuous delivery and lean.
The biggest difference between those graph-based declarative approaches and Model-Driven concepts (MDD/MDA) is that they are bottom-up, and designed to support evolution*. Instead of requiring a canonical model, tribal ("bounded") domain language or strict interface contracts externally, it is very easy to implement
domain-event messaging on the infrastructure level, because the infrastructure itself has meaning, allowing for
independently composed distributed systems - in other words
choreographed rather than orchestrated.
The declarative, domain-event-driven approach shares some advantage of MDA though: The vocabulary, patterns, and visible graph of dependencies. It makes it a lot easier to follow, though, and a lot harder to ignore. Once the implications of changes to the graphs are commonly understood, it's a lot easier to reason about the graph (see, for instance, the
original Flume paper). On the low level that service meshes target, the infrastructure level, this quality makes it a lot easier to
reason and iteratively learn the entire system (including the mesh itself and the DevOps process around), and to version, document, track and test the system.