0% found this document useful (0 votes)
23 views

Reactive Stream Processing Rx4DDS - Sumant Tambe - CppCon 2015

Uploaded by

alan88w
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
23 views

Reactive Stream Processing Rx4DDS - Sumant Tambe - CppCon 2015

Uploaded by

alan88w
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 51

Your systems. Working as one.

Reactive Stream Processing in


Industrial IoT using DDS and Rx

Sumant Tambe, Ph.D. Sept. 21, 2015


Principal Research Engineer and Microsoft VC++ MVP
Real-Time Innovations, Inc.
@sutambe
© Real-Time Innovations, Inc.
Outline
• Industrial IoT Systems
• Reactive Systems
• Data Distribution Service
• Stream Processing
• Reactive Extensions (Rx)
• Rx4DDS
• Stream Processing Demos
with Shapes

9/21/2015 © Real-Time Innovations, Inc. 2


9/21/2015 © Real-Time Innovations, Inc. 3
9/21/2015 © Real-Time Innovations, Inc. 4
Industrial IoT Systems
Cannot stop processing the information.
Live within world-imposed timing.

9/21/2015 © Real-Time Innovations, Inc. Image source: Google Images 5


Image Credit: Cisco

9/21/2015 © 2015 RTI • 6


Responsive: Reacts to events
at the speed of environment Responsive

Resilient: fault-tolerant Elastic Resilient

Elastic/Scalable: Scales
easily up/down with load
and cpu cores. Event-Driven

Event-Driven: asynchronous, Messaging Middleware


loosely-coupled, modular,
pipelined
Reactive Manifesto: www.reactivemanifesto.org

9/21/2015 © Real-Time Innovations, Inc. 7


Reactive Manifesto

Jonas Boner: One of the authors of the Reactive Manifesto

9/21/2015 © Real-Time Innovations, Inc. 8


Reactive Middleware

9/21/2015 © Real-Time Innovations, Inc. 9


DDS: Data Connectivity Standard for the
Industrial IoT

Streaming
Sensors Events
Data

Real-Time Enterprise
Actuators
Applications Applications

© 2009 Real-Time Innovations, Inc.


DDS Communication Model

FILTER FILTER

9/21/2015 © 2015 RTI • 11


The DDS Standard Family

Application
DDS-C++ DDS-JAVA* DDS-IDL-C DDS-IDL-C#

DDS-SECURITY
DDS-XTYPES
DDS-RPC*

IDL 4.0 DDS v 1.4


DDS-WEB

RTPS v2.2
HTTP(s) UDP TCP** DTLS** TLS** SHARED-
IP MEMORY**

© 2015 RTI
12
STANDARD
API
Choice

AWESOME
9/21/2015 © 2015 RTI 13
A**

9/21/2015 © Real-Time Innovations, Inc. Image source: Amazon, Google 14


Stream Processing

An architectural style that operates on a


continuous sequence of data.

9/21/2015 © Real-Time Innovations, Inc. Image credit: eecs.berkeley.edu 15


Unix command line (pipes and filter)

9/21/2015 © Real-Time Innovations, Inc. 16


Data Pipelines

i/p
o/p

Where Once CombineLatest Select Scan Merge Raw Data


Reactive Extensions (Rx)
• Invented at Microsoft (Erik Meijer and team)
• API for composing asynchronous and event-
based programs using observable streams
• Rx = Observables + Composition
+ Schedulers
• Observables: First-class streams
• Composition: Filter, select, aggregate
(reduce), compose and perform time-based
operations on multiple streams
• Schedulers: Concurrency. Thread-pools, etc.
• Uses Functional Programming (Monadic)
• Rx.NET, RxJava, RxJS, RxCpp, RxRuby,
RxPython, and many more…
More info: https://speakerdeck.com/benjchristensen/reactive-programming-with-rx-at-qconsf-2014
9/21/2015 © Real-Time Innovations, Inc. 18
Duality of Push and Pull Interfaces (C#)

Pull Push
IEnumerator<out T> IObserver<in T>
T Current { get; } void OnNext(T value)
bool MoveNext() void OnCompleted()
void OnError(Exception ex)

IEnumerable<out T> IObservable<out T>


IEnumerator<T> GetEnumerator(); IDisposable Subscribe(IObserver<T>)

Duality (video):
http://channel9.msdn.com/Shows/Going+Deep/Expert-to-Expert-Brian-Beckman-and-Erik-Meijer-Inside-the-NET-Reactive-Framework-Rx

9/21/2015 © Real-Time Innovations, Inc. 19


Sync/Async, One/Many
Single Multiple
Sync T get_data() std::vector<T>::iterator

Async future<T> with rxcpp::observable<T>


.then() .next()
(hpx, boost, C++17)

9/21/2015 © Real-Time Innovations, Inc. 20


RxCpp Example (1/3)
rxcpp::observable<int> values =
rxcpp::observable<>::range(1, 5);

auto subscription = values.subscribe(


[](int v){ printf("OnNext: %d\n", v); },
[](){ printf("OnCompleted\n"); });

9/21/2015 © Real-Time Innovations, Inc. 21


RxCpp Example (2/3)
auto subscription =
rxcpp::observable<>::range(1, 5)
.map([](int i) { return 10*i; })
.filter([](int v) { return (v % 15) != 0; })
.subscribe(
[](int v){ printf("OnNext: %d\n", v); },
[](){ printf("OnCompleted\n"); });

9/21/2015 © Real-Time Innovations, Inc. 22


Map Marble Diagram

Credit: rxmarbles.com

9/21/2015 Real-Time Innovations, Inc. 23


RxCpp Example (3/3)
auto o1 =
rx::observable<>::interval(std::chrono::seconds(2));
auto o2 =
rx::observable<>::interval(std::chrono::seconds(3));
auto values = o1.map([](int i) { return char('A' + i); })
.combine_latest(o2);
values
.take(10)
.subscribe(
[](std::tuple<char, int> v) {
printf("OnNext: %c, %d\n",
std::get<0>(v), std::get<1>(v));
},
[]() { printf("OnCompleted\n"); });

9/21/2015 © Real-Time Innovations, Inc. 24


RxCpp Output

9/21/2015 © Real-Time Innovations, Inc. 25


9/21/2015 © 2015 RTI • 26
Rx4DDS = DDS + Rx
• Rx bindings for DDS data
– In C++11, C#, and JavaScript

• Anything that produces data


is an Observable
– Topics
– Discovery
– Statuses

More info: http://rticommunity.github.io/rticonnextdds-reactive/

9/21/2015 © 2015 RTI • 27


DDS for Distribution, Rx for Processing

Observable Observer

DataReader
DataWriter

DataReader

DataWriter
Processing
DataReader

9/21/2015 Real-Time Innovations, Inc. 28


DDS and Rx: A Great Match
DDS Rx
Design Methodology Data-Centric Reactive, Compositional

Architecture Distributed Publish-subscribe In-memory Observable-


Observer. Monadic
Anonymity/loose Publisher does not know about Observable does not know
coupling subscribers about observers
Data Streaming A Topic<T> is a stream of data An Observable<T> is a stream of
samples of type T object of type T
Stream lifecycle Instances (keys) have lifecycle Observables have lifecycle
(NewAliveDisposed) OnNext*[OnCompleted|OnError]

Data Publication Publisher may publish without any “Hot” Observables


subscriber
Data Reception Subscriber may read the same data “Cold” Observables
over and over
9/21/2015 © 2015 RTI • 29
Stream Processing Demos with Shapes
• 3 DDS Topics
– “Square”
– “Triangle”
– “Circle”

class ShapeType
{
string color; //@key
int shapesize;
int x;
int y;
}

9/21/2015 © Real-Time Innovations, Inc. 30


Solar System Demo

Link: https://youtu.be/mHNyEPeOPHg (1 min)

9/21/2015 Real-Time Innovations, Inc. 31


rx4dds::TopicSubscription<ShapeType>
topic_sub(participant, "Square", waitset, worker);

rx::observable<LoanedSample<ShapeType>> source =
topic_sub.create_observable();

rx::observable<ShapeType> square_track =
source >> rx4dds::complete_on_dispose()
>> rx4dds::error_on_no_alive_writers()
>> filter([](LoanedSample<ShapeType> s) {
return s.info().valid();
}) // skip invalid samples
>> map([](LoanedSample<ShapeType> valid) {
return valid.data();
}); // map samples to data
9/21/2015 Real-Time Innovations, Inc. 32
Map to Circle Track
int circle_degree = 0;

rx::observable<ShapeType> circle_track =
square_track
.map([circle_degree](ShapeType & square) mutable
{
circle_degree = (circle_degree + 3) % 360;
return shape_location(square, circle_degree);
})
.tap([circle_writer](ShapeType & circle) mutable {
circle_writer.write(circle);
}); // tap replaced as publish_over_dds later

9/21/2015 © Real-Time Innovations, Inc. 33


Map to Triangle Track
int tri_degree = 0;

rx::observable<ShapeType> triangle_track =
circle_track
.map([tri_degree](ShapeType & circle) mutable
{
tri_degree = (tri_degree + 9) % 360;
return shape_location(circle, tri_degree);
})
>> rx4dds::publish_over_dds(triangle_writer);

triangle_track.subscribe();

9/21/2015 Real-Time Innovations, Inc. 34


Naming Transformations (C++14)

auto skip_invalid_samples()
{
return [](auto src_observable) {
return src_observable
.filter([](auto & sample) {
return sample.info().valid()
});
};
}

9/21/2015 Real-Time Innovations, Inc. 35


Naming Transformations (C++11)
struct MapSampleToDataOp
{
template <class Observable>
rx::observable<typename Observable::value_type::DataType>
operator ()(Observable src) const
{
typedef typename Observable::value_type LoanedSample;
return src.map([](LoanedSample & sample) {
return sample.data()
});
}
};

inline MapSampleToDataOp map_samples_to_data()


{
return MapSampleToDataOp();
}

9/21/2015 Real-Time Innovations, Inc. 36


27,572 cables

Source:
9/21/2015
Google Images Real-Time Innovations, Inc. 37
Data Pipelines Demo Next

i/p
o/p

Where Once CombineLatest Select Scan Merge Raw Data


Data Pipelines Demo

Link: https://youtu.be/2Pz91e7yR5I (3 min)

9/21/2015 Real-Time Innovations, Inc. 39


rx4dds::TopicSubscription<ShapeType>
topic_sub(participant, "Square", waitset, worker);

auto grouped_stream =
topic_sub.create_observable()
>> group_by_instance ([](ShapeType & shape) {
return shape.color();
});

decltype(grouped_stream) ===
rx::observable<
rx::grouped_observable<
string, LoanedSample<ShapeType>
>
>
9/21/2015 Real-Time Innovations, Inc. 40
grouped_stream
.flat_map([circle_writer, triangle_writer]
(GroupedShapeObservable go) {
rx::observable<ShapeType> inner_transformed =
go >> to_unkeyed()
>> complete_on_dispose()
>> error_on_no_alive_writers()
>> skip_invalid_samples()
>> map_samples_to_data()
>> map_to_circle_track() // as shown before
>> publish_over_dds(
circle_writer, ShapeType(go.key())
>> map_to_triangle_track() // as shown before
>> publish_over_dds(
triangle_writer, ShapeType(go.key());
return inner_transformed;
}).subscribe();
9/21/2015 © Real-Time Innovations, Inc. 41
Dynamic Correlator

Link: https://youtu.be/tZutExU6r0w (1 min)


9/21/2015 Real-Time Innovations, Inc. 42
grouped_stream
.map([](GroupedShapeObservable go) {
return go >> rx4dds::to_unkeyed()
>> rx4dds::complete_on_dispose()
>> rx4dds::error_on_no_alive_writers()
>> rx4dds::skip_invalid_samples()
>> rx4dds::map_samples_to_data();
})
>> rx4dds::coalesce_alive()
>> map([](const vector<rxcpp::observable<ShapeType>> & srcs) {
return rx4dds::combine_latest(srcs);
})
>> rxcpp::switch_on_next()
>> rxcpp::map([](const std::vector<ShapeType> & shapes) {
return calculate_average(shapes);
})
>> rx4dds::publish_over_dds(triangle_writer, ShapeType(“ORANGE”));
9/21/2015 © Real-Time Innovations, Inc. 43
My ¢2 on FP in C++11
• Noisy!!
– Lambda captures, mutable
• Lambdas don’t extend local object lifetimes when captured
– Consequence: shared_ptr galore!
• Death by auto
– auto-heavy code is not readable
– Compiler errors far away from the erroneous line
– Please don’t remove types if you have them already
– Types are the best documentation
• RxCpp
– Learning Rx.NET, RxJS first strongly recommended
– Frequently very, very long observable types
– Use as_dynamic() but beware of performance implications

9/21/2015 Real-Time Innovations, Inc. 44


Resources
• Rx
– LearnRx (RxJS) by JHusain from Netflix
– Intro To Rx (Rx.NET) by Lee Campbell
– rxmarbles.com (interactive marble diagrams)
– ReactiveX.io (API docs in multiple languages)
• Rx4DDS Stream Processing
– Github [bit.ly/cppcon-rx4dds]
– Research Paper [link]
• DDS
– Object Management Group [http://portals.omg.org/dds]
– RTI [www.rti.com]

9/21/2015 Real-Time Innovations, Inc. 45


Thank You!

9/21/2015 Real-Time Innovations, Inc. 46


Extra Slides

9/21/2015 Real-Time Innovations, Inc. 47


Hot and Cold Observables
Hot Cold
Meaning Emits whether you are Emits when requested.
ready or not and Starts from the beginning
regardless of subscribers with every subscription
Examples 1. Mouse movements 1. Reading a file
2. User input 2. Database query
3. Stock prices 3. observable.interval
4. DDS Topic

Semantics Receiver must keep up or Receiver can exert


use sampling. backpressure
May lose data

9/21/2015 Real-Time Innovations, Inc. 48


Decoupling
• Separating production of data from consumption
• Two ways to produce (access) DDS data
– WaitSet-based blocking and dispatch (like select)
– Listener-based (m/w calls you back)
• Each has pros/cons and different APIs and leads
to very different code structure
• Observables allows us to change data production
technique without changing data consuming code
• Data consuming code is written in the same
declarative chaining style
9/21/2015 Real-Time Innovations, Inc. 49
DDS and Rx: A Great Match
DDS Concept Rx Concept/Type/Operator

Topic of type T An object that implements IObservable<T>, which internally creates a


DataReader<T>
Communication status, IObservable<SampleLostStatus>
Discovery event streams IObservable<SubscriptionBuiltinTopicData>
Topic of type T with key IObservable<IGroupedObservable<Key, T>>
type=Key
Detect a new instance Notify Observers about a new IGroupedObservable<Key, T> with
key==instance. Invoke
IObserver<IGroupedObservable<Key, T>>.OnNext()
Dispose an instance Notify Observers through
IObserver<IGroupedObservable<Key,T>>.OnCompleted()
Take an instance update of Notify Observers about a new value of T using
type T Iobserver<T>.OnNext()
Read with history=N IObservable<T>.Replay(N) (Produces a new IObservable<T>)

9/21/2015 © 2015 RTI • 50


DDS and Rx: A Great Match
DDS Concept Rx Concept/Type/Operation

Query Conditions Iobservable<T>.Where(…) OR


Iobservable<T>.GroupBy(…)
SELECT in CFT expression IObservable<T>.Select(...)

FROM in CFT expression DDSObservable.FromTopic(“Topic1”)


DDSObservable.FromKeyedTopic(“Topic2”)
WHERE in CFT expression IObservable<T>.Where(...)

ORDER BY in CFT expression IObservable<T>.OrderBy(...)

MultiTopic (INNER JOIN) IObservable<T>.Join(...)


.Where(...)
.Select(...)
Join between DDS and non- Join, CombineLatest, Zip
DDS data

9/21/2015 © 2015 RTI 51

You might also like