Reactive Reference Architectures Nilanjan Raychaudhuri @nraychaudhuri Markus Jura @markusjura Massive Learning Platform Big data http://allthingsd.com/files/2013/07/minions-‐640x327.jpg Principles of Reactive Systems 3 Architecture Web (Play) backend (Akka) Journal (Cassandra) Fast data processing (Spark) 4 http://cdn1.ssninsider.com/wp-‐content/uploads/2013/08/despicable-‐me-‐2-‐minions-‐e1375818315418.png Problem: Splitting application Monolithic 7 Splitting MLP Frontend nodes Backend nodes 8 Akka Distributed Pub/Sub • Location transparency • Publish/Subscribe • Dynamically add/remove 9 Distributed Pub/Sub Mediator Frontend nodes M M M M M Backend nodes 10 Code Frontend // Starting up the mediator val mediator = DistributedPubSubExtension(system).mediator // Sending message through mediator mediator ? DistributedPubSubMediator.Send(“/user/course-aggregate”, CreateCourse(course), localAffinity = true) 12 Backend // Starting up the mediator val mediator = DistributedPubSubExtension(system).mediator // Setting up the services val courseAggregate = system.actorOf(CourseRepository.props, "course-aggregate") mediator ! DistributedPubSubMediator.Put(courseAggregate) val levelAggregate = system.actorOf(LevelRepository.props, "level-aggregate") mediator ! DistributedPubSubMediator.Put(levelAggregate) 13 http://cdn1.ssninsider.com/wp-‐content/uploads/2013/08/despicable-‐me-‐2-‐minions-‐e1375818315418.png Problem: Distributed State State on single node Frontend nodes Backend nodes 16 State across nodes Frontend nodes Backend nodes 17 Akka Cluster Sharding • Partition actors across Cluster • Location transparency • Rebalancing 18 How does it work? Shard Coordinator Shard Region 1 Shard Region 2 19 Code Backend: Create ShardRegion // Backend: Start cluster sharing in non-proxy mode ClusterSharding(system).start( "users", Some(User.props), UserSharding.idExtractor, UserSharding.shardResolver()) 21 Backend: Shard Resolver & Id Extractor // Extract the user shard // Rule of thumb: 10 times the max numbers of sharding nodes def shardResolver(shardCount: Int = 20) = { case UserService.Envelope(email, _) => email.hashCode % shardCount.toString } // Extract the id and payload of the user actor val idExtractor: ShardRegion.IdExtractor = { case UserService.Envelope(email, payload) => (email, payload) } 22 Frontend // Start sharding in proxy mode on every frontend node val shardRegion: ActorRef = ClusterSharding(system).start( "users", None, UserSharding.idExtractor, UserSharding.shardResolver()) // Send message via shard region shardRegion ? UserService.Envelope(email, GetUser(email)) 23 Problem: Loosing State State in memory Frontend nodes Backend nodes 25 Persist state Frontend Backend 26 Akka Persistence • Stores state in Journal DB • Event Sourcing • Restore state 27 Code Write user state 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 } } ... 29 Recover user state ... // Replay UserCreated message to recover state override def receiveRecover: Receive = { case e: UserCreated => onUserCreated(e) } 30 http://cdn1.ssninsider.com/wp-‐content/uploads/2013/08/despicable-‐me-‐2-‐minions-‐e1375818315418.png Problem: Replicate Cache Singleton Cache Frontend nodes C Backend nodes 33 What is CRDT? 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 34 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 Frontend nodes C R R R R C R Backend nodes 39 Code Frontend //starting up the replicator val replicator = DataReplication(system).replicator //get cache entry val f = replicator ? Get(key, ReadLocal, None) 41 Backend //starting up the replicator val replicator = DataReplication(system).replicator //updating the cache replicator ! Update(Course.cacheKey, GSet.empty, WriteLocal) (_ + courseCreated.course) 42 Q & Option[A] @nraychaudhuri @markusjura frontend React.js REST API Cache Actors backend PubSub Cluster Sharding Persistence CRDT journal 44 ©Typesafe 2014 – All Rights Reserved
© Copyright 2024