reactive reference architecture -...
TRANSCRIPT
Reactive Reference Architecture
Markus Jura @markusjura
Nilanjan Raychaudhuri @nraychaudhuri
s
Big dataMassive Learning Platform
http://allthingsd.com/files/2013/07/minions-‐640x327.jpg
3
Principles of Reactive Systems
Architecture
4
Web (Play)
backend (Akka)
Journal (Cassandra)
Fast data processing (Spark)
http://cdn1.ssninsider.com/wp-‐content/uploads/2013/08/despicable-‐me-‐2-‐minions-‐e1375818315418.png
Problem: Splitting application
Monolithic
7
Splitting MLP
8
Frontend nodes
Backend nodes
Akka Distributed Pub/Sub• Location transparency
• Publish/Subscribe
• Dynamically add/remove
9
Distributed Pub/Sub Mediator
10
Frontend nodes
Backend nodes
M M
M M M
Code
Frontend
12
// Starting up the mediatorval mediator = DistributedPubSubExtension(system).mediator
// Sending message through mediatormediator ? DistributedPubSubMediator.Send(“/user/course-aggregate”, CreateCourse(course), localAffinity = true)
Backend
13
// Starting up the mediatorval mediator = DistributedPubSubExtension(system).mediator
// Setting up the servicesval courseAggregate = system.actorOf(CourseRepository.props, "course-aggregate")mediator ! DistributedPubSubMediator.Put(courseAggregate)val levelAggregate = system.actorOf(LevelRepository.props, "level-aggregate")mediator ! DistributedPubSubMediator.Put(levelAggregate)
http://cdn1.ssninsider.com/wp-‐content/uploads/2013/08/despicable-‐me-‐2-‐minions-‐e1375818315418.png
Problem: Distributed State
State on single node
16
Frontend nodes
Backend nodes
State across nodes
17
Frontend nodes
Backend nodes
Akka Cluster Sharding
• Partition actors across Cluster
• Location transparency
• Rebalancing
18
How does it work?
19
Shard Coordinator
Shard Region 1 Shard Region 2
Code
Backend: Create ShardRegion
21
// Backend: Start cluster sharing in non-proxy mode ClusterSharding(system).start( "users", Some(User.props), UserSharding.idExtractor, UserSharding.shardResolver())
Backend: Shard Resolver & Id Extractor
22
// Extract the user shard// Rule of thumb: 10 times the max numbers of sharding nodesdef shardResolver(shardCount: Int = 20) = { case UserService.Envelope(email, _) => email.hashCode % shardCount.toString }
// Extract the id and payload of the user actorval idExtractor: ShardRegion.IdExtractor = { case UserService.Envelope(email, payload) => (email, payload)}
Frontend
23
// Send message via shard regionshardRegion ? UserService.Envelope(email, GetUser(email))
// Start sharding in proxy mode on every frontend node val shardRegion: ActorRef = ClusterSharding(system).start( "users", None, UserSharding.idExtractor, UserSharding.shardResolver())
Problem: Loosing State
State in memory
25
Frontend nodes
Backend nodes
Persist state
26
Frontend
Backend
Akka Persistence
• Stores state in Journal DB
• Event Sourcing
• Restore state
27
Code
Write user state
29
class User extends PersistentActor {
// User id / sharding extractor id override def persistenceId: String = self.path.name
// Persist UserCreated event to Cassandra journal override def receiveCommand: Receive = { case UserService.CreateUser(userProgress) => persist(UserCreated(userProgress)) { userCreated => // Update user state onUserCreated(userCreated) sender() ! UserService.UserCreated } } ...
Recover user state
30
...
// Replay UserCreated message to recover stateoverride def receiveRecover: Receive = { case e: UserCreated => onUserCreated(e)}
http://cdn1.ssninsider.com/wp-‐content/uploads/2013/08/despicable-‐me-‐2-‐minions-‐e1375818315418.png
Problem: Replicate Cache
Singleton Cache
33
Frontend nodes
Backend nodes
C
What is CRDT?
34
Conflict-free replicated data type is a type of specially designed data structure used to achieve strong eventual consistency
Great talk on CRDT by Sean Cribbs: Eventually Consistent Data Structures
CvRDT
35
CvRDT - Example
36
CmRDT
37
Akka Data replication• CRDT for Akka cluster
• Replicated in-memory data store
• Supports many types: (GSet, ORSet, PNCounter…)
38
CRDT Replicator
39
Frontend nodes
Backend nodes
C CR R
R R R
Code
Frontend
41
//starting up the replicatorval replicator = DataReplication(system).replicator
//get cache entryval f = replicator ? Get(key, ReadLocal, None)
Backend
42
//starting up the replicatorval replicator = DataReplication(system).replicator
//updating the cache replicator ! Update(Course.cacheKey, GSet.empty, WriteLocal)
(_ + courseCreated.course)
Q & Option[A]
@nraychaudhuri@markusjura
44
React.js
frontend
REST API Actors
backend
Cache
PubSub CRDTPersistenceCluster Sharding
journal
©Typesafe 2014 – All Rights Reserved