Streaming with Orleans
Orleans streaming is a feature of the Orleans framework that enables developers to write reactive applications that operate on a sequence of events in a structured way. Orleans streaming provides a set of abstractions and APIs that make thinking about and working with streams simpler and more robust. A stream is a logical entity that always exists and can never fail. Streams are identified by their StreamId. Streams allow the generation of data to be decoupled from its processing, both in time and space. Streams work uniformly across grains and Orleans clients, and can be compatible with and portable across a wide range of existing queuing technologies, such as Event Hubs, ServiceBus, Azure Queues, and Apache Kafka. Orleans streaming also supports dynamic stream bindings, transparent stream consumption lifecycle management, and extensible stream providers.
Orleans v.1.0.0 added support for streaming extensions to the programming model. Streaming extensions provide a set of abstractions and APIs that make thinking about and working with streams simpler and more robust. Streaming extensions allow developers to write reactive applications that operate on a sequence of events in a structured way. The extensibility model of stream providers makes the programming model compatible with and portable across a wide range of existing queuing technologies, such as Event Hubs, ServiceBus, Azure Queues, and Apache Kafka. There is no need to write special code or run dedicated processes to interact with such queues.
Why should I care?
If you already know all about Stream Processing and are familiar with technologies like Event Hubs, Kafka, Azure Stream Analytics, Apache Storm, Apache Spark Streaming, and Reactive Extensions (Rx) in .NET, you may be asking why should you care. Why do we need yet another Stream Processing System and how Actors are related to Streams? "Why Orleans Streams?" is meant to answer that question.
Programming model
There are several principles behind Orleans Streams Programming Model:
- Orleans streams are virtual. That is, a stream always exists. It is not explicitly created or destroyed, and it can never fail.
- Streams are identified by stream IDs, which are just logical names comprised of GUIDs and strings.
- Orleans Streams allow you to decouple the generation of data from its processing, both in time and space. That means that the stream producer and the stream consumer may be on different servers or in different time zones, and will withstand failures.
- Orleans streams are lightweight and dynamic. Orleans Streaming Runtime is designed to handle a large number of streams that come and go at a high rate.
- Orleans stream bindings are dynamic. Orleans Streaming Runtime is designed to handle cases where grains connect to and disconnect from streams at a high rate.
- Orleans Streaming Runtime transparently manages the lifecycle of stream consumption. After an application subscribes to a stream, it will then receive the stream's events, even in the presence of failures.
- Orleans streams work uniformly across grains and Orleans clients.
Quick-start sample
The Quick Start Sample is a good quick overview of the overall workflow of using streams in the application. After reading it, you should read the Streams Programming APIs to get a deeper understanding of the concepts.
Stream providers
Streams can come via physical channels of various shapes and forms and can have different semantics. Orleans Streaming is designed to support this diversity via the concept of Stream Providers, which is an extensibility point in the system.
Orleans provides several stream provider implementations:
Orleans currently includes several provider implementations:
- Simple Message (SMS), which uses direct grain calls and no backing storage system,
- Azure Queues, which uses Azure Storage Queues to store messages, and
- Azure EventHubs, which uses Azure EventHubs
For more information, see Stream Providers.
Stream semantics
Stream Subscription Semantics:
Orleans Streams guarantee Sequential Consistency for Stream Subscription operations. Specifically, when a consumer subscribes to a stream, once the Task
representing the subscription operation was successfully resolved, the consumer will see all events that were generated after it has subscribed. In addition, Rewindable streams allow you to subscribe from an arbitrary point in time in the past by using StreamSequenceToken. For more information, see Orleans stream providers.
Individual Stream Events Delivery Guarantees:
Individual event delivery guarantees depend on individual stream providers. Some provide only best-effort at-most-once delivery (such as Simple Message Streams (SMS) in versions of Orleans before 7.0, thereafter known as Broadcast Channel), while others provide at-least-once delivery (such as Azure Queue Streams). It is even possible to build a streaming provider that will guarantee exactly-once delivery.
Events Delivery Order:
Event order also depends on a particular stream provider. In SMS streams, the producer explicitly controls the order of events seen by the consumer by controlling the way it publishes them. Azure Queue streams do not guarantee FIFO order, since the underlying Azure Queues do not guarantee the order in failure cases. Applications can also control their stream delivery ordering by using StreamSequenceToken.
Streams implementation
The Orleans Streams Implementation provides a high-level overview of the internal implementation.
Code samples
More examples of how to use streaming APIs within a grain can be found here. We plan to create more samples in the future.