In this guest webinar by Kevin Webber, we cover the entire architecture of a Reactive system, from a responsive UI implemented with Vue.js, to a fully event sourced collection of microservices implemented with Java, Lagom, Cassandra, and Kafka.
For the full recording, visit: https://www.lightbend.com/blog/full-stack-reactive-in-practice-webinar
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
Full Stack Reactive In Practice
1.
2. Full Stack Reactive in Practice
Presenting a real-world CQRS
(command query responsibility
segregation) and ES (event
sourcing) architecture.
Kevin Webber
Director of Engineering @
Reading Plus
w: kevinwebber.ca
m: medium.com/@kvnwbbr
t: @kvnwbbr
3. — Reading Plus is an adaptive platform that helps K-12
students become successful readers and lifelong
learners
— We will be applying reactive techniques and
technologies to a mission with purpose
— Find us at https://readingplus.com and stay tuned for
upcoming engineering opportunities
4. Why Reactive?
— React, Vue, and other front-end frameworks are
enabling innovative user experiences
5. Why Reactive?
— React, Vue, and other front-end frameworks are
enabling innovative user experiences
— Meanwhile, relational databases continue to dominate
the server side
6. Why Reactive?
— React, Vue, and other front-end frameworks are
enabling innovative user experiences
— Meanwhile, relational databases continue to dominate
the server side
— Reactive principles and frameworks help create an
end-to-end event-driven channel, all the way up and
all the way down
7. Traditional architecture
— Unbounded in complexity and
side effects
— Putting React or Vue on top
won't help much
— Batch-mode, high-latency,
high-failure rates
— Has an impact
— Customer happiness?
— Developer joy?
— Visit TheDailyWTF :)
8. What we will cover
All references and examples will be in Java.
1. Designing reactive systems → Event Storming, DDD
2. Implementing reactive systems → Lagom, Play, Akka
3. Deploying reactive systems → sbt, Kubernetes
9. Part 1. Designing Reactive Systems
— Raw ingredients
— Commands & events
— Inception
— Event storming & DDD
— Fidelity
— Event modeling
— Handoff
— User stories
12. Event sourcing
— Commands are applied
against an entity, the entity
can accept or reject a
command
— If accepted, an entity will
generate an event and then
apply that event in order to
change state
13. Defining aggregate boundaries
— Structures implementation
around related items
— The yellow sticky in the
middle represents state
14. Defining bounded contexts
— Group together related
business concepts
— Contain domain complexity
— A single person can master an
aggregate
— A single team can master a
bounded context
15. How do we model a bounded context?
— Arrange events in linear order by time
— Events cluster into closely related groups (aggregates)
— Aggregates cluster into closely related groups
(bounded contexts)
— Event Storming helps discover the problem space
— Event Modeling creates a blueprint for a solution
17. Essential learning resources
— Book: Event Storming by Alberto Brandolini
— Book: Domain-Driven Design Distilled by Vaughn
Vernon
— Website: Event Modeling by Adam Dymitruk
18. Part 2. Implementation
— Tools
— Lagom, Play, and Akka
— Cassandra and Kafka
— Pa!erns
— Event sourcing, CQRS
— Architecture
— Interface, BFF, services
— Integration
— Point to point, streaming,
pub/sub
21. Placing a wire transfer
We'll cover the command channel first.
1. Create command
2. Send over REST
3. Direct command to entity
4. Create event
5. Change state
6. Publish event
24. API gateway
— Backend for Frontend (BFF) is
a pattern that involves
creating a 1:1 relationship
between backends and UIs
— The BFF then handles all calls
to various underlying
microservices (Portfolio,
Broker, Wires, etc)
— Also performs authentication,
authorization, etc
25. Play (command side API)
@Override
public ServiceCall<Transfer, TransferId> transferFunds() {
TransferId transferId = TransferId.newId();
return transfer ->
transferRepository
.get(transferId) // 1 (get reference to entity)
.ask(TransferCommand.TransferFunds.builder()
.source(transfer.getSourceAccount())
.destination(transfer.getDestinationAccount())
.amount(transfer.getFunds())
.build()
) // 2 (ask pattern)
.thenApply(done -> transferId);
}
26. BFF and Service Integration
— Play routes all commands and
queries to Lagom
microservices
— Lagom is a framework built on
top of Akka for developing
reactive microservices
— Based on the principles of
CQRS (Command Query
Responsibility Segregation)
27. Lagom (aggregates / entities)
— Based around persistent entities (aka, aggregates)
— Stored in memory for fast access
— Can be recovered via Cassandra as the event log
public class TransferEntity extends
PersistentEntity<TransferCommand,
TransferEvent,
Optional<TransferState>> {
// ...
}
28. Lagom (event sourcing)
— No mutable data, only
immutable state
— State is only changed on
successful event application
— Events are journaled
— Entity can always recover in-
memory by replaying events
from the journal
— Entities are not queried
directly, read-side queries are
backed by views
29. State machines
Let's say we're modeling an ATM
machine...
— This ATM machine has three
different states
— Each state has a different
behaviour for the same input
https://www.uml-diagrams.org/
state-machine-diagrams.html
35. Views
— Read side processors build a
precomputed table
— Queries are only against
precomputed tables
— Use this to populate data on
initial page load
36. Creating a portfolio
1. When each portfolio is
created, we create a portfolio
entity and then persist the
create event to the journal
2. A read side processor
subscribes to journal updates
3. With each update, the read
side processor updates a
projected view
Let's cover #3...
37. Lagom ReadSide processor
Update a precomputed query table (Cassandra) on every
new event we subscribe to.
@Override
public ReadSideHandler<PortfolioEvent> buildHandler() {
return readSide.<PortfolioEvent>builder("portfolio_offset") // 1
.setGlobalPrepare(this::prepareCreateTables) // 2
.setPrepare(tag -> prepareWritePortfolios()) // 3
.setEventHandler(Opened.class, this::processPortfolioChanged) // 4
.build();
}
private CompletionStage<Done> prepareWritePortfolios() {
return session
.prepare("INSERT INTO portfolio_summary (portfolioId, name) VALUES (?, ?)")
.thenApply(ps -> {
this.writePortfolios = ps;
return Done.getInstance();
});
}
38. Queries are then executed against the projected view for
a vastly lower latency user experience.
@Override
public ServiceCall<NotUsed, PSequence<PortfolioSummary>> getAllPortfolios() {
return request -> {
CompletionStage<PSequence<PortfolioSummary>> result =
db.selectAll("SELECT portfolioId, name FROM portfolio_summary;")
.thenApply(rows -> {
List<PortfolioSummary> summary = rows.stream().map(row ->
PortfolioSummary.builder()
.portfolioId(new PortfolioId(
row.getString("portfolioId")))
.name(row.getString("name"))
.build())
.collect(Collectors.toList());
return TreePVector.from(summary);
});
return result;
};
}
39. Streaming
1. Render initial page with precomputed view over HTTP/
REST
2. Switch to unidirectional streaming for updates (events
over WS)
3. Commands over REST will still cause full page
refreshes (can change unidirectional stream to BiDi
stream in future)
Instead, let's use the Lagom PubSub API to push updates
to the UI in real-time...
40. Streaming (Lagom)
This code exposes a Reactive Streams Source via Lagom,
which Play can then "attach" to.
@Override
public ServiceCall<NotUsed, Source<String, ?>> transferStream() {
return request -> {
// subscribe to events on a specific topic ("transfer")
final PubSubRef<String> topic =
pubSub.refFor(
TopicId.of(String.class,
"transfer"));
// return the Source as a future (standard async Java 8)
return CompletableFuture.completedFuture(topic.subscriber());
};
}
41. Streaming (architecture)
PubSub works by broadcasting
events to subscribers:
— Publisher is TransferEntity
— Subscriber is
WireTransferServiceImpl
— This will create a streaming
Source
44. WebSockets (Vue.js)
connect() {
this.socket = new WebSocket(
"ws://localhost:9000/api/transfer/stream");
this.socket.onopen = () => {
this.socket.onmessage = (e) => {
let event = JSON.parse(e.data);
var index = -1;
// 1. determine if we're updating a row (initiated)
// or adding a new row (completed)
for (var i = 0; i < this.transfers.length; i++) {
if (this.transfers[i].id === event.id) {
index = i;
break;
}
}
if (index === -1) {
// unshift is similar to push, but prepends
this.transfers.unshift({
// ... 3. create object with id, status, etc
});
} else {
let t = {
// ... 4. create object with id, status, etc
};
this.transfers.splice(index, 1, t);
this.updateCashOnHand();
}
};
};
}
45. Part 3. Deployment
— Packaging
— sbt, service boundaries
— Testing
— Deploying to Minikube
— Handling dependencies in
k8s such as Cassandra,
Kafka
— Deployment
— Production deployments
47. Reactive Stock Trader needs...
— Formation of a cluster so Lagom entities can stay
available in memory
— Connection to Cassandra and Kafka (in a "high-
availability" clustered configuration)
— Cassandra for the backing journal
— Kafka for the Lagom Message Broker API for
communication between services
49. In this example, we have a three node Kubernetes
cluster, with two bounded contexts spread across those
nodes. This offers resilience and scale.
50. Deploying to Minikube
Instructions are available here to help deploy Reactive
Stock Trader (along with Cassandra and Kafka) to
Minikube:
https://github.com/RedElastic/reactive-stock-trader/tree/
master/deploy/instructions
51. Conclusion
— CQRS separates writes and reads for reliability and
performance
— Event sourcing eliminates mutability concerns of
relational databases while preserving their query
capabilities
— Operationally Lagom is cloud-native and ready to
deploy to AWS, Azure, GCP, etc, via Kubernetes
52. What about serverless?
— For the foreseeable future we
need to understand how our
software interacts with the
runtime environment
— A serverless component may
be part of a reactive system,
but is not a replacement for a
reactive system
— Reactive systems enable
portability across cloud
vendors, whereas many
serverless offerings lock us in
53. Reactive in Practice
For a complete look at this
material, visit IBM Developer and
check out Reactive in Practice, a
12 part series (parts 8-12 to be
published mid-September).
https://developer.ibm.com/series/
reactive-in-practice/
Thanks to Dana Harrington,
Lightbend, and IBM.