Your SlideShare is downloading. ×
Decompose That WAR! Architecting for Adaptability, Scalability, and Deployability
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×

Introducing the official SlideShare app

Stunning, full-screen experience for iPhone and Android

Text the download link to your phone

Standard text messaging rates apply

Decompose That WAR! Architecting for Adaptability, Scalability, and Deployability

2,317
views

Published on

It’s no longer acceptable to develop large, monolithic, single-language, single-framework Web applications. In this session, you will learn how to use the scale cube to decompose your monolithic Web …

It’s no longer acceptable to develop large, monolithic, single-language, single-framework Web applications. In this session, you will learn how to use the scale cube to decompose your monolithic Web application into a set of narrowly focused, independently deployable services. The presentation discusses how a modular architecture makes it easy to adopt newer and better languages and technologies. You will learn about the various communication mechanisms—synchronous and asynchronous—that these services can use.

Published in: Technology, Education

0 Comments
12 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
2,317
On Slideshare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
68
Comments
0
Likes
12
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
No notes for slide

Transcript

  • 1. @crichardson Decompose That WAR! Architecting for Adaptability, Scalability, and Deployability Chris Richardson Author of POJOs in Action Founder of the original CloudFoundry.com @crichardson chris@chrisrichardson.net http://plainoldobjects.com
  • 2. @crichardson Presentation goal How decomposing applications improves deployability and scalability and simplifies the adoption of new technologies
  • 3. @crichardson About Chris
  • 4. @crichardson (About Chris)
  • 5. @crichardson About Chris()
  • 6. @crichardson About Chris
  • 7. @crichardson About Chris http://www.theregister.co.uk/2009/08/19/springsource_cloud_foundry/
  • 8. @crichardson About Chris
  • 9. @crichardson Agenda The (sometimes evil) monolith Decomposing applications into services How do services communicate? API gateway design Refactoring the monolith
  • 10. @crichardson Let’s imagine you are building an online store
  • 11. @crichardson Tomcat Traditional web application architecture Browser WAR MySQL Database Review Service Product Info Service Recommendation Service StoreFrontUI develop test deploy Simple to Apache/ Load balancer scale JSF Spring MVC Spring Hibernate Order Service
  • 12. @crichardson But there are problems with a monolithic architecture
  • 13. @crichardson Users expect a rich, dynamic and interactive experience
  • 14. @crichardson Browser WAR StoreFrontUI Model View Controller Presentation layer evolution.... HTML / HTTP Old style UI architecture isn’t good enough
  • 15. @crichardson Browser - desktop and mobile Web application RESTful Endpoints Model View Controller ...Presentation layer evolution JSON-REST HTML 5 - JavaScript Native mobile client IoS or Android Event publisher Events Static content No elaborate, server-side web framework required
  • 16. @crichardson Intimidates developers
  • 17. @crichardson Obstacle to frequent deployments Need to redeploy everything to change one component Interrupts long running background (e.g. Quartz) jobs Increases risk of failure Fear of change Updates will happen less often - really long QA cycles e.g. Makes A/B testing UI really difficult Eggs in one basket
  • 18. @crichardson Overloads your IDE and container Slows down development
  • 19. @crichardson Shipping team Accounting Engineering Obstacle to scaling development E-commerce application
  • 20. @crichardson WAR Review service Product Info service Recommendation service StoreFrontUI Reviews team Product Info team Recommendations team UI team Obstacle to scaling development Order serviceOrders team
  • 21. @crichardson Lots of coordination and communication required Obstacle to scaling development I want to update the UI But the backend is not working yet!
  • 22. @crichardson Requires long-term commitment to a technology stack
  • 23. @crichardson Agenda The (sometimes evil) monolith Decomposing applications into services How do services communicate? API gateway design Refactoring the monolith
  • 24. @crichardson
  • 25. @crichardson 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
  • 26. @crichardson Y-axis scaling - application level WAR Review Service Product Info Service Recommendation Service StoreFrontUI Order Service
  • 27. @crichardson Y-axis scaling - application level Store front web application reviews web application recommendations web application Apply X axis cloning and/or Z axis partitioning to each service product info web application Review Service Product Info Service Recommendation Service StoreFrontUI Order Service orders web application
  • 28. @crichardson Partitioning strategies... Partition by verb, e.g. shipping service Partition by noun, e.g. inventory service Single Responsibility Principle Unix utilities - do one focussed thing well
  • 29. @crichardson Partitioning strategies Too few Drawbacks of the monolithic architecture Too many - a.k.a. Nano-service anti-pattern Runtime overhead Potential risk of excessive network hops Potentially difficult to understand system Something of an art
  • 30. @crichardson Example micro-service class RegistrationSmsServlet extends RegistrationSmsScalatraStack { post("/") { val phoneNumber = request.getParameter("From") val registrationUrl = System.getenv("REGISTRATION_URL") + "?phoneNumber=" + encodeForUrl(phoneNumber) <Response> <Sms>To complete registration please go to {registrationUrl}</Sms> </Response> } } For more on micro-services see @fgeorge52
  • 31. @crichardson Real world examples http://highscalability.com/amazon-architecture http://techblog.netflix.com/ http://www.addsimplicity.com/downloads/ eBaySDForum2006-11-29.pdf http://queue.acm.org/detail.cfm?id=1394128
  • 32. @crichardson There are drawbacks
  • 33. @crichardson Complexity See Steve Yegge’s Google Platforms Rant re Amazon.com
  • 34. @crichardson Multiple databases & Transaction management
  • 35. @crichardson Implementing features that span multiple services
  • 36. @crichardson When to use it? In the beginning: •You don’t need it •It will slow you down Later on: •You need it •Refactoring is painful
  • 37. @crichardson But there are many benefits
  • 38. @crichardson Smaller, simpler apps Easier to understand and develop Reduced startup time - important for GAE Less jar/classpath hell Who needs OSGI?
  • 39. @crichardson Scales development: develop, deploy and scale each service independently
  • 40. @crichardson Improves fault isolation
  • 41. @crichardson Eliminates long-term commitment to a single technology stack Modular, polyglot, multi- framework applications
  • 42. @crichardson Two levels of architecture System-level Services Inter-service glue: interfaces and communication mechanisms Slow changing Service-level Internal architecture of each service Each service could use a different technology stack Pick the best tool for the job Rapidly evolving
  • 43. @crichardson Easily try other technologies ... and fail safely
  • 44. @crichardson Agenda The (sometimes evil) monolith Decomposing applications into services How do services communicate? API gateway design Refactoring the monolith
  • 45. @crichardson Inter-service communication options Synchronous HTTP asynchronous AMQP Formats: JSON, XML, Protocol Buffers, Thrift, ... Asynchronous is preferred JSON is fashionable but binary format is more efficient
  • 46. @crichardson StoreFrontUI Product Info service Recommendation service Review service RabbitMQ (Message Broker) Asynchronous message-based communication Order service
  • 47. Pros and cons of messaging Pros Decouples client from server Message broker buffers messages Supports a variety of communication patterns Cons Additional complexity of message broker Request/reply-style communication is more complex
  • 48. Spring Integration Provides the building blocks for a pipes and filters architecture Enables development of application components that are loosely coupled insulated from messaging infrastructure Messaging defined declaratively
  • 49. @crichardson Order Service Messaging Gateway Channel Service Activator Shipping service Development time: same JVM @Service public class OrderServiceImpl { @Autowired private ShippingService shippingService; public void placeOrder() { String orderId = generateOrderId(); … shippingService.shipOrder(orderId); } } @Service public class ShippingServiceImpl { public void shipOrder(String orderId) { .... } } shipOrder()
  • 50. @crichardson Order Service Messaging Gateway Channel Service Activator Shipping service AMQP RabbitMQ AMQP Channel Test and production: distributed Application code is unchanged
  • 51. @crichardson Synchronous REST Recommendation service StoreFrontUI Product Info service Review service REST ... Order service
  • 52. Pros and cons of REST Pros Simple and familiar Request/reply is easy Firewall friendly No intermediate broker Cons Only supports request/ reply Server must be available Client needs to know URL(s) of server(s)
  • 53. @crichardson Spring MVC makes REST easy @Controller public class AccountController { @Autowired private MoneyTransferService moneyTransferService; @RequestMapping(value = "/accounts/{accountId}", method = RequestMethod.GET) @ResponseBody public AccountInfo getAccount(@PathVariable String accountId) { Account account = moneyTransferService.findAccountByid(accountId); return makeAccountInfo(account); } @RequestMapping(value = "/accounts", method = RequestMethod.POST) @ResponseStatus( HttpStatus.CREATED ) public void createAccount(@RequestBody AccountInfo accountInfo, UriComponentsBuilder builder, HttpServletResponse response) { ... } URL matching & destructuringobject XML/JSON XML/JSON
  • 54. @crichardson Agenda The (sometimes evil) monolith Decomposing applications into services How do services communicate? API gateway design Refactoring the monolith
  • 55. @crichardson Use an API gateway Browser Model View Controller HTML 5 - JavaScript Product Info service Recommendation Service Review service REST REST AMQP API Gateway Model View Controller Native App Single entry point Client specific APIs Protocol translation
  • 56. @crichardson Netflix API Gateway http://techblog.netflix.com/2013/01/optimizing-netflix-api.html Device specific end points
  • 57. @crichardson Developing an API gateway Java EE web technologies Netty-based technology stack Non-Java options: e.g. Node.JS
  • 58. @crichardson API gateway design issues
  • 59. @crichardson The need for parallelism Product Details API Product Info Recommendations Reviews getProductDetails() getRecomendations() getReviews() Call in parallel get Product Details
  • 60. @crichardson Futures are a great concurrency abstraction An object that will contain the result of a concurrent computation http://en.wikipedia.org/wiki/Futures_and_promises Future<Integer> result = executorService.submit(new Callable<Integer>() {... }); Java has basic futures. We can do much better....
  • 61. @crichardson Better: Futures with callbacks val f : Future[Int] = Future { ... } f onSuccess { case x : Int => println(x) } f onFailure { case e : Exception => println("exception thrown") } Guava ListenableFutures, Java 8 CompletableFuture, Scala Futures
  • 62. @crichardson Even better: Composable Futures val f1 = Future { ... ; 1 } val f2 = Future { ... ; 2 } val f4 = f2.map(_ * 2) assertEquals(4, Await.result(f4, 1 second)) val fzip = f1 zip f2 assertEquals((1, 2), Await.result(fzip, 1 second)) def asyncOp(x : Int) = Future { x * x} val f = Future.sequence((1 to 5).map { x => asyncOp(x) }) assertEquals(List(1, 4, 9, 16, 25), Await.result(f, 1 second)) Scala Futures Transforms Future Combines two futures Transforms list of futures to a future containing a list
  • 63. @crichardson Composing concurrent requests using Scala Futures class ProductDetailsService @Autowired()(....) { def getProductDetails(productId: Long) = { val productInfoFuture = productInfoService.getProductInfo(productId) val recommendationsFuture = recommendationService.getRecommendations(productId) val reviewsFuture = reviewService.getReviews(productId) for (((productInfo, recommendations), reviews) <- productInfoFuture zip recommendationsFuture zip reviewsFuture) yield ProductDetails(productInfo, recommendations, reviews) } } Asynchronously creates a Future containing result
  • 64. @crichardson Handling partial failures Product Details Controller Product Info Recommendations Reviews getProductDetails() getRecomendations() getReviews() get Product Details X
  • 65. @crichardson About Netflix > 1B API calls/day 1 API call average 6 service calls Fault tolerance is essential http://techblog.netflix.com/2012/02/fault-tolerance-in-high-volume.html
  • 66. @crichardson How to run out of threads Tomcat Execute thread pool HTTP Request Thread 1 Thread 2 Thread 3 Thread n Service A Service B If service B is down then thread will be blocked XX X X X Eventually all threads will be blocked
  • 67. @crichardson Their approach Network timeouts and retries Invoke remote services via a bounded thread pool Use the Circuit Breaker pattern On failure: return default/cached data return error to caller https://github.com/Netflix/Hystrix
  • 68. @crichardson Agenda The (sometimes evil) monolith Decomposing applications into services How do services communicate? API gateway design Refactoring the monolith
  • 69. @crichardson How do you decompose your 10 M LOC monolithic application?
  • 70. @crichardson Strategy #1: Stop digging
  • 71. @crichardson New functionality = service Monolith Service Anti-corruption layer Glue code Pristine
  • 72. @crichardson Sounds simple but... Dependencies between monolith and service e.g. Common entities Building the anti-corruption layer can be challenging Must replicate data between systems ...
  • 73. @crichardson Strategy #2: extract services
  • 74. @crichardson Module service ... WAR Module
  • 75. @crichardson ... Module service WAR Service Anti-corruption layer
  • 76. @crichardson What to extract? Have the ideal partitioned architecture in mind: Partitioned by verb or noun Start with troublesome modules: Frequently updated Stateful components that prevent clustering Conflicting resource requirements
  • 77. @crichardson Service Domain model 2 Monolith Untangling dependencies API A API B API C Domain model 1 A C B X Z Y Trouble!
  • 78. @crichardson Useful idea: Bounded context Different services have a different view of a domain object, e.g. User Management = complex view of user Rest of application: User = PK + ACL + Name Different services can have a different domain model Services exchange messages to synchronize data
  • 79. @crichardson Customer management Untangling orders and customers Order management Order Service placeOrder() Customer Service availableCredit() updateCustomer() Customer creditLimit ... has ordersbelongs toOrder total Invariant: sum(order.total) <= creditLimit available credit= creditLimit - sum(order.total) Trouble!
  • 80. @crichardson Customer management Replicating the credit limit Order management Order Service placeOrder() Customer creditLimit ... Order total Customer’ creditLimit CreditLimitChangedEvent sum(order.total) <= creditLimit Customer Service updateCustomer() Simplified
  • 81. @crichardson Customer management Maintaining the openOrderTotal Order management Order Service placeOrder() Customer Service availableCredit() Customer creditLimit ... Order customerId total = creditLimit - openOrderTotal OpenOrderTotalUpdated openOrderTotal
  • 82. @crichardson Refactoring a monolith is not easy BUT the alternative is far worse
  • 83. @crichardson Summary
  • 84. @crichardson Monolithic applications are simple to develop and deploy BUT have significant drawbacks
  • 85. @crichardson Apply the scale cube Modular, polyglot, and scalable applications Services developed, deployed and scaled independently
  • 86. @crichardson Use a modular, polyglot architecture Browser Model View Controller HTML 5 - JavaScript Product Info service Recommendation Service Review service REST REST AMQP Front-end server Model View Controller Native App API Gateway Event delivery
  • 87. @crichardson Questions? @crichardson chris@chrisrichardson.net http://plainoldobjects.com