Sequences, LINQ, Rx, & Reaqtor Part 6: Reaqtor
To understand Reaqtor, it is necessary to understand Rx (the Reactive Extensions for .NET). And to understand Rx, it is necessary to understand how C# works with sequences of items. In this series I have outlined the ideas at the heart of Reaqtor, and how they are handled in C#. In this final part, we see how all of the preceding articles in this series finally lead us to Reaqtor: a server technology that is able to host persistent Rx subscriptions, defined as LINQ queries.
As an example of what you might do with this, consider an application that wants to detect when a customer broadband router is experiencing a higher error rate than the average for the exchange to which the router is attached. A typical broadband provider will have millions of customers across hundreds of exchanges. These systems generate huge volumes of monitoring data, and it is necessary to identify and understand problems as they arise to pre-empt customer problems in order to reduce support costs and improve the customer's experience.
You could arrange for network health events be made available inside Reaqtor as event sources that can be subscribed to. You could then feed these events through the GroupBy
operator to separate the data out by exchange, and then through a Buffer
operator to calculate a rolling average error rate for each exchange as a whole. The results of this could then be made available within Reaqtor as an event source that other subscriptions can use.
You could then define subscriptions for each individual customer's router. (Remember, there will be millions of these routers, but Reaqtor is designed to handle that kind of scale easily.) Again we could use Buffer
to calculate a rolling error rate, and then feed these through a Where
clause that compares the router-specific error rate with the average for that router's exchange, only allowing through events that are above the average.
This way, you can get notifications from individual devices if they start to experience high failure rates while avoiding getting swamped by such notifications if it turns out that a large number of devices attached to the same exchange are all reporting similar failures due to an exchange-level problem. By combining a highly localized point of view (events from an individual router in a particular customer's house) with broader context (aggregated performance at the level of a whole telephone exchange) you can better understand the information you're seeing, e.g., you can distinguish between problems with individual pieces of equipment and broader failures.
This sort of logic can be expressed as LINQ queries using standard operators. These queries then get transferred into the 'Query Engine' inside Reaqtor (possibly via a 'Query Coordinator', which can optimize queries, and work out how to distribute them across multiple Query Engines to improve scale).
These then become long running queries which (unlike with ordinary Rx subscriptions) can continue to run long after the code that initially set them up has stopped running. Reaqtor has failover support enabling queries to migrate to new servers if the server they are running on needs to reboot, or just fails.
The basic abstraction underpinning this is the same one we saw in the first article in this series—a sequence of items. Processing and combination is enabled by the LINQ features. We're able to do this reactively—in response to live events as they happen—thanks to Rx, which has been augmented by Reaqtive to add with the additional concepts required for persistent, long-running subscriptions. Remotable expression trees enable both the remote instantiation of such subscriptions, but also their persistence. And Reaqtor then provides the runtime services required to make all of that real, offering a host environment for Rx-like subscriptions, with persistence, checkpointing, and failover, and it has a proven track record of scaling to tens of millions of customers.