Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Building microservices with Scala, functional domain models and Spring Boot (#Devnexus)

In this talk you will learn about a modern way of designing applications that’s very different from the traditional approach of building monolithic applications that persist mutable domain objects in a relational database.We will talk about the microservice architecture, it’s benefits and drawbacks and how Spring Boot can help. You will learn about implementing business logic using functional, immutable domain models written in Scala. We will describe event sourcing and how it’s an extremely useful persistence mechanism for persisting functional domain objects in a microservices architecture.

Building microservices with Scala, functional domain models and Spring Boot (#Devnexus)

  1. 1. @crichardson Building microservices with Scala, functional domain models and Spring Boot Chris Richardson Author of POJOs in Action Founder of the original CloudFoundry.com @crichardson chris@chrisrichardson.net http://plainoldobjects.com http://microservices.io
  2. 2. @crichardson Presentation goal Share my experiences with building and deploying an application using Scala, functional domain models, microservices, event sourcing, CQRS, and Docker
  3. 3. @crichardson About Chris
  4. 4. @crichardson About Chris Founder of a buzzword compliant (stealthy, social, mobile, big data, machine learning, ...) startup Consultant helping organizations improve how they architect and deploy applications using cloud, micro services, polyglot applications, NoSQL, ... Creator of http://microservices.io
  5. 5. @crichardson For more information https://github.com/cer/event-sourcing-examples http://microservices.io http://plainoldobjects.com/ https://twitter.com/crichardson
  6. 6. @crichardson Agenda Why build event-driven microservices? Overview of event sourcing Designing microservices with event sourcing Implementing queries in an event sourced application Building and deploying microservices
  7. 7. @crichardson Tomcat Traditional application architecture Browser/ Client WAR/EAR RDBMS Customers Accounts Transfers Banking develop test deploy Simple Load balancer scale Spring MVC Spring Hibernate ... HTML REST/JSON ACID
  8. 8. @crichardson Limitations of the monolithic architecture Intimidates developers Obstacle to frequent deployments Overloads your IDE and container Obstacle to scaling development Modules having conflicting scaling requirements Requires long-term commitment to a technology stack
  9. 9. @crichardson Limitations of a single relational database Scalability Distribution Schema updates O/R impedance mismatch Handling semi-structured data
  10. 10. @crichardson Apply the scale cube X axis - horizontal duplication Z axis -data partitioning Y axis - functional decomposition Scale by splitting sim ilar things Scale by splitting different things
  11. 11. @crichardson Use a microservice architecture Banking UI Account Management Service MoneyTransfer Management Service Account Database MoneyTransfer Database Standalone services
  12. 12. @crichardson Use functionally decomposed and sharded relational databases
  13. 13. @crichardson Use NoSQL databases Avoids the limitations of RDBMS For example, text search Solr/Cloud Search social (graph) data Neo4J highly distributed/available database Cassandra … But most have a very limited transaction model
  14. 14. @crichardson Different modules use different types of databases IEEE Software Sept/October 2010 - Debasish Ghosh / Twitter @debasishg
  15. 15. @crichardson But this results in distributed data management problems
  16. 16. @crichardson Example #1 - SQL + Text Search engine Application MySQL ElasticSearch How to maintain consistency without 2PC? Product #1 Product #1
  17. 17. @crichardson Example #2 - Cassandra main table <=> index table Application Cassandra How to maintain consistency without 2PC? Main Table Denormalized view Index Table
  18. 18. @crichardson Example #3: Money transfer Account Management Service MoneyTransfer Management Service Account Database MoneyTransfer Database Account #2 Account #1 Money Transfer How to maintain consistency without 2PC?
  19. 19. @crichardson Event-based architecture to the rescue Components (e.g. services) publish events when state changes Components subscribe to events Maintains eventual consistency across multiple aggregates (in multiple datastores) Synchronize replicated data
  20. 20. @crichardson Event-driven synchronization: SQL + Text Search engine Catalog Service MySQL ElasticSearch Product #1 Product #1 Search Service Message Bus Insert Product Created Product Created Index Doc create product
  21. 21. @crichardson MoneyTransferService MoneyTransfer fromAccountId = 101 toAccountId = 202 amount = 55 state = INITIAL MoneyTransfer fromAccountId = 101 toAccountId = 202 amount = 55 state = DEBITED MoneyTransfer fromAccountId = 101 toAccountId = 202 amount = 55 state = COMPLETED Eventually consistent money transfer Message Bus AccountService transferMoney() Publishes: Subscribes to: Subscribes to: publishes: MoneyTransferCreatedEvent AccountDebitedEvent DebitRecordedEvent AccountCreditedEvent MoneyTransferCreatedEvent DebitRecordedEvent AccountDebitedEvent AccountCreditedEvent Account id = 101 balance = 250 Account id = 202 balance = 125 Account id = 101 balance = 195 Account id = 202 balance = 180
  22. 22. @crichardson To maintain consistency a service must atomically publish an event whenever a domain object changes
  23. 23. How to atomically update the datastore and publish event(s)? Use 2PC Guaranteed atomicity BUT Need a distributed transaction manager Database and message broker must support 2PC Impacts reliability Not fashionable 2PC is best avoided Use datastore as a message queue 1. Update database: new entity state & event 2. Consume event & mark event as consumed Eventually consistent mechanism See BASE: An Acid Alternative, http://bit.ly/ebaybase • BUT Tangled business logic and event publishing code • Difficult to implement when using a NoSQL database :-(
  24. 24. @crichardson Agenda Why build event-driven microservices? Overview of event sourcing Designing microservices with event sourcing Implementing queries in an event sourced application Building and deploying microservices
  25. 25. @crichardson Event sourcing For each aggregate in your domain model: Identify (state-changing) domain events Define Event classes For example, Account: AccountOpenedEvent, AccountDebitedEvent, AccountCreditedEvent ShoppingCart: ItemAddedEvent, ItemRemovedEvent, OrderPlacedEvent
  26. 26. @crichardson Persists events NOT current state Account balance open(initial) debit(amount) credit(amount) AccountOpened Event table AccountCredited AccountDebited 101 450 Account table X 101 101 101 901 902 903 500 250 300
  27. 27. @crichardson Replay events to recreate state Account balance AccountOpenedEvent(balance) AccountDebitedEvent(amount) AccountCreditedEvent(amount) Events
  28. 28. @crichardson Before: update state + publish events Two actions that must be atomic Single action that can be done atomically Now: persist (and publish) events
  29. 29. @crichardson Request handling in an event-sourced application HTTP Handler Event Store pastEvents = findEvents(entityId) Account new() applyEvents(pastEvents) newEvents = processCmd(SomeCmd) saveEvents(newEvents) Microservice A
  30. 30. @crichardson Event Store publishes events - consumed by other services Event Store Event Subscriber subscribe(EventTypes) publish(event) publish(event) Aggregate NoSQL materialized view update() update() Microservice B
  31. 31. @crichardson Event store implementations Home-grown/DIY geteventstore.com by Greg Young Talk to me about my project :-)
  32. 32. @crichardson Optimizing using snapshots Most aggregates have relatively few events BUT consider a 10-year old Account many transactions Therefore, use snapshots: Periodically save snapshot of aggregate state Typically serialize a memento of the aggregate Load latest snapshot + subsequent events
  33. 33. @crichardson Hybrid OO/Functional style example aggregate
  34. 34. @crichardson Aggregate traits Map Command to Events Apply event returning updated Aggregate
  35. 35. @crichardson Account - command processing Prevent overdraft
  36. 36. @crichardson Account - applying events Immutable
  37. 37. @crichardson Event Store API Reactive/Async API
  38. 38. @crichardson Functional example aggregate
  39. 39. @crichardson Aggregate type classes/implicits
  40. 40. @crichardson Functional-style MoneyTransfer Aggregate State Behavior
  41. 41. @crichardson FP-style event store Enables inference of T, and EV Tells ES how to instantiate aggregate and apply events
  42. 42. @crichardson Business benefits of event sourcing Built-in, reliable audit log Enables temporal queries Publishes events needed by big data/predictive analytics etc. Preserved history More easily implement future requirements
  43. 43. @crichardson Technical benefits of event sourcing Solves data consistency issues in a Microservice/NoSQL- based architecture: Atomically save and publish events Event subscribers update other aggregates ensuring eventual consistency Event subscribers update materialized views in SQL and NoSQL databases (more on that later) Eliminates O/R mapping problem
  44. 44. @crichardson Drawbacks of event sourcing Weird and unfamiliar Events = a historical record of your bad design decisions Handling duplicate events can be tricky Application must handle eventually consistent data Event store only directly supports PK-based lookup (more on that later)
  45. 45. @crichardson Agenda Why build event-driven microservices? Overview of event sourcing Designing microservices with event sourcing Implementing queries in an event sourced application Building and deploying microservices
  46. 46. @crichardson Identify your application’s bounded contexts = Subdomains / areas of functionality => microservice
  47. 47. @crichardson Partition the bounded context’s domain model into Aggregates
  48. 48. @crichardson The anatomy of a microservice Event Store HTTP Request HTTP Adapter Event Adapter Cmd Cmd Events Events Xyz Adapter Xyz Request microservice Aggregate
  49. 49. @crichardson Asynchronous Spring MVC controller Scala Future => Spring MVC DeferredResult
  50. 50. @crichardson MoneyTransferService DSL concisely specifies: 1.Creates MoneyTransfer aggregate 2.Processes command 3.Applies events 4.Persists events
  51. 51. @crichardson Handling events published by Accounts 1.Load MoneyTransfer aggregate 2.Processes command 3.Applies events 4.Persists events
  52. 52. @crichardson Agenda Why build event-driven microservices? Overview of event sourcing Designing microservices with event sourcing Implementing queries in an event sourced application Building and deploying microservices
  53. 53. @crichardson Let’s imagine that you want to display an account and it’s recent transactions...
  54. 54. @crichardson Displaying balance + recent credits and debits We need to do a “join: between the Account and the corresponding MoneyTransfers (Assuming Debit/Credit events don’t include other account, ...) BUT Event Store = primary key lookup of individual aggregates, ... Use Command Query Responsibility Segregation
  55. 55. @crichardson Command Query Responsibility Segregation (CQRS) Command-side Commands Aggregate Event Store Events Query-side Queries (Denormalized) View Events
  56. 56. @crichardson Query-side microservices Event Store Updater - microservice View Updater Service Events Reader - microservice HTTP GET Request View Query Service View Store e.g. MongoDB Neo4J CloudSearch update query
  57. 57. @crichardson Persisting account balance and recent transactions in MongoDB { id: "298993498", balance: 100000, transfers : [ {"transferId" : "4552840948484", "fromAccountId" : 298993498, "toAccountId" : 3483948934, "amount" : 5000}, ... ], changes: [ {"changeId" : "93843948934", "transferId" : "4552840948484", "transactionType" : "AccountDebited", "amount" : 5000}, ... ] } Denormalized = efficient lookup MoneyTransfers that update the account The debits and credits Current balance
  58. 58. @crichardson Persisting account info using MongoDB... class AccountInfoUpdateService (accountInfoRepository : AccountInfoRepository, mongoTemplate : MongoTemplate) extends CompoundEventHandler { @EventHandlerMethod def created(de: DispatchedEvent[AccountOpenedEvent]) = … @EventHandlerMethod def recordDebit(de: DispatchedEvent[AccountDebitedEvent]) = … @EventHandlerMethod def recordCredit(de: DispatchedEvent[AccountCreditedEvent]) = … @EventHandlerMethod def recordTransfer(de: DispatchedEvent[MoneyTransferCreatedEvent]) = … }
  59. 59. Other kinds of views AWS Cloud Search Text search as-a-Service View updater batches aggregates to index View query service does text search AWS DynamoDB NoSQL as-a-Service On-demand scalable - specify desired read/write capacity Document and key-value data models Useful for denormalized, UI oriented views
  60. 60. Benefits and drawbacks of CQRS Benefits Necessary in an event-sourced architecture Separation of concerns = simpler command and query models Supports multiple denormalized views Improved scalability and performance Drawbacks Complexity Potential code duplication Replication lag/eventually consistent views
  61. 61. @crichardson Agenda Why build event-driven microservices? Overview of event sourcing Designing microservices with event sourcing Implementing queries in an event sourced application Building and deploying microservices
  62. 62. @crichardson My application architecture API gateway Event Store Service 1 Service 2 Service ... Event Archiver Indexer AWS Cloud Search S3 NodeJS Scala/Spring Boot
  63. 63. @crichardson Building microservices with Spring Boot Makes it easy to create stand-alone, production ready Spring applications Automatically configures Spring using Convention over Configuration Externalizes configuration Generates standalone executable JARs with embedded web server Provides a standard foundation for all your microservices
  64. 64. @crichardson Spring Boot simplifies configuration Spring Container Application components Fully configured application Configuration Metadata •Typesafe JavaConfig •Annotations •Legacy XML Default Configuration Metadata Spring Boot You write less of this Inferred from CLASSPATH
  65. 65. @crichardson Tiny Spring configuration Scan for controllers Customize JSON serialization
  66. 66. @crichardson About auto-configuration Builds on Spring framework features @EnableAutoConfiguration - triggers the inclusion of default configuration @Conditional - beans only active if condition is satisfied Conditional on class defined on class path e.g. Mongo Driver implies Mongo beans Conditional on bean defined/undefined e.g. define Mongo beans if you haven’t
  67. 67. @crichardson The Main program
  68. 68. @crichardson Building with Gradle buildscript { repositories { mavenCentral() } dependencies { classpath("org.springframework.boot:spring-boot-gradle-plugin:1.1.8.RELEASE") } } apply plugin: 'scala' apply plugin: 'spring-boot' dependencies { compile "org.springframework.boot:spring-boot-starter-web" compile "org.springframework.boot:spring-boot-starter-data-mongodb" compile "org.springframework.boot:spring-boot-starter-amqp" compile "org.springframework.boot:spring-boot-starter-actuator" testCompile "org.springframework.boot:spring-boot-starter-test" } ... Ensures correct dependencies
  69. 69. @crichardson Running the microservice $ java -jar build/libs/spring-boot-restful-service.jar --server.port=8081 ... 2014-12-03 16:32:04.671 INFO 93199 --- [ main] n.c.m.r.main.UserRegistrationMain$ : Started UserRegistrationMain. in 5.707 seconds (JVM running for 6.553) $ curl localhost:8081/health {"status":"UP", "mongo":{"status":"UP","version":"2.4.10"}, "rabbit":{"status":"UP", ...} } Built in health checks Command line arg processing
  70. 70. @crichardson Jenkins-based deployment pipeline Build & Test microservice Build & Test Docker image Deploy Docker image to registry One pipeline per microservice
  71. 71. @crichardson Building Docker images cp ../build/libs/service.${1}.jar build/service.jar docker build -t service-${VERSION} . docker/build.sh Building only takes 5 seconds!
  72. 72. @crichardson Smoke testing docker images Smoke test Docker daemon Service containerGET /health POST /containers/create creates POST /containers/{id}/start Docker daemon must listen on TCP port
  73. 73. @crichardson Publishing Docker images docker tag service-${VERSION}:latest ${REGISTRY_HOST_AND_PORT}/service-${VERSION} docker push ${REGISTRY_HOST_AND_PORT}/service-${VERSION} docker/publish.sh Pushing only takes 25 seconds!
  74. 74. @crichardson CI environment runs on Docker EC2 Instance Jenkins Container Artifactory container EBS volume /jenkins- home /gradle-home /artifactory- home
  75. 75. @crichardson Updating the production environment Large EC2 instance running Docker Deployment tool: 1. Compares running containers with what’s been built by Jenkins 2. Pulls latest images from Docker registry 3. Stops old versions 4. Launches new versions One day: use Docker clustering solution and a service discovery mechanism, Most likely, AWS container service Mesos and Marathon + Zookeeper, Kubernetes or ???
  76. 76. @crichardson Summary Event sourcing solves key data consistency issues with: Microservices Partitioned SQL/NoSQL databases Use CQRS to implement materialized views for queries Spring Boot is a great foundation for microservices Docker is a great way to package microservices
  77. 77. @crichardson @crichardson chris@chrisrichardson.net http://plainoldobjects.com http://microservices.io

×