Microservice Architecture Fortified for Real-Time Communications
A strong backend spine will lead to more dynamic, scalable, and manageable deployment strategies for real-time communications and collaboration.
Not too long ago, this post would have started with a flaming manifesto for microservices: Break down the monolith! Divide and conquer!"... enterprise IT architects know the drill. Today though, that's hardly necessary. In fact, most enterprise architectures make it next to impossible not to construct your backend as a swarm of loosely coupled, highly specialized nodes.
But this flexibility comes at a price: Enterprise-scale microservice architectures quickly become highly complex. Load-balancing clusters, routing requests to endpoints, orchestrating distributed messaging, sharding storage layers, and facilitating concurrent read and write access are just some of the many challenges.
With the increasing move from request-response workflows to streaming real-time data -- be it for financial price distribution, social messaging, collaboration apps, or Internet of Things (IoT) data aggregation -- we have to rethink the way our services interact and share resources. If you're responsible for implementing and supporting real-time communications and collaboration, strengthening your backend's spine will help you create more dynamic, scalable, and manageable deployment strategies.
Outlining Solution Requirements
Our core challenges are reducing complexity and increasing scalability. A single solution can address both: a stronger backbone that unifies resource access and permissioning, as well as facilitates routing and inter-service communication. This requires a number of crucial changes:
- Data-sync instead of decoupled datastores and messaging - Traditionally, messaging and data storage are decoupled. Updates are written to the storage layer; nodes receive notification of the update via a pub-sub mechanism, and retrieve the new state using their own database connections. This comes with the overhead of multiple connections per node and multiple steps per update, leading to higher complexity and reduced performance. This approach is increasingly superseded by a concept called "data-sync," implemented by technologies such as deepstream.io and RethinkDB. Data-sync models the data-layer as a distributed state. Data-Objects are shared between microservices and clients alike, and can be manipulated and observed. Every change to an object is instantly distributed among all connected nodes.
- Dynamic RPCs instead of static route tables - In classic REST architectures, the available endpoints for remote procedure calls (RPC) are statically configured on a router/load balancer level -- and many enterprise-grade RPC frameworks, including Apache Thrift, go down a similar route. This means that changes or additions have to be propagated across multiple configurations and often require restarts/rolling updates. The advent of Advanced Message Queuing Protocol (AMQP) brokers such as RabbitMQ or ZeroMQ brought massive improvements by introducing pattern-based routing and dynamic exchange creation. However, these AMQP brokers still left the user with the task of implementing high-level patterns such as re-routing or metrics-based load balancing. Newer RPC frameworks, such as ZeroC's ICE or deepstream.io close the gap. Within such frameworks, microservices register the RPCs they can fulfill at runtime with a dynamic, distributed registry. Incoming requests are routed to the right endpoint and responses are returned to the requestor. Smart load-balancing, re-routing rejected requests, and other additional functionality make this a powerful, low-maintenance approach.
- Pub/sub messaging for inter-service communication - Publish/subscribe for loosely coupled many-to-many communication is a scalable and lightweight pattern for inter-component messaging. A separate message broker like Apache Kafka or an enterprise event bus like JBOSS Fuse handle this. Or, it also can be baked into a unified platform backbone.
- Permissioning messages before they enter the system - In many deployments, individual microservices have to contact the Active Directory server or identity provider to establish if a given client can perform a specific operation. Moving message permissioning to the gateway layer and making sure that messages are not only valid, but also permitted, improves security while decreasing complexity by centralizing this responsibility. This also helps to filter out malicious messages even before they enter the internal network/virtual private cloud.
Moving Toward a Solution
There's a fair choice of systems that can deliver aspects of these requirements, but the true power lies in combining them. RPCs can be used to book a transaction with a system and return a data-sync record name/stream handle to keep track of its status. Events can be used to quickly broadcast indicative price updates in a stock trading app, but leave it to data-sync to provide the final quote. Making all this functionality available from within a solid, secure, and horizontally scalable backbone that microservices and clients alike connect to can significantly decrease complexity while heightening scalability and fault-tolerance.