@crichardson
Decompose That WAR!
Architecting for Adaptability,
Scalability, and Deployability
Chris Richardson
Author of ...
@crichardson
Presentation goal
How decomposing applications
improves deployability and
scalability
and
simplifies the adopt...
@crichardson
About Chris
@crichardson
(About Chris)
@crichardson
About Chris()
@crichardson
About Chris
@crichardson
About Chris
http://www.theregister.co.uk/2009/08/19/springsource_cloud_foundry/
@crichardson
About Chris
@crichardson
Agenda
The (sometimes evil) monolith
Decomposing applications into services
How do services communicate?
API ...
@crichardson
Let’s imagine you are
building an online store
@crichardson
Tomcat
Traditional web application
architecture
Browser
WAR
MySQL
Database
Review Service
Product Info
Servic...
@crichardson
But there are problems with
a monolithic architecture
@crichardson
Users expect a rich,
dynamic and interactive
experience
@crichardson
Browser
WAR
StoreFrontUI
Model
View Controller
Presentation layer evolution....
HTML / HTTP
Old style UI arch...
@crichardson
Browser - desktop and mobile Web application
RESTful
Endpoints
Model
View Controller
...Presentation layer ev...
@crichardson
Intimidates developers
@crichardson
Obstacle to frequent
deployments
Need to redeploy everything to change one component
Interrupts long running ...
@crichardson
Overloads your IDE and
container
Slows down development
@crichardson
Shipping team
Accounting
Engineering
Obstacle to scaling
development
E-commerce
application
@crichardson
WAR
Review service
Product Info service
Recommendation service
StoreFrontUI
Reviews team
Product Info team
Re...
@crichardson
Lots of coordination and
communication required
Obstacle to scaling
development
I want
to update the UI
But
t...
@crichardson
Requires long-term commitment
to a technology stack
@crichardson
Agenda
The (sometimes evil) monolith
Decomposing applications into services
How do services communicate?
API ...
@crichardson
@crichardson
The scale cube
X axis
- horizontal duplication
Z
axis
-data
partitioning
Y axis -
functional
decomposition
Sc...
@crichardson
Y-axis scaling - application level
WAR
Review
Service
Product Info
Service
Recommendation
Service
StoreFrontU...
@crichardson
Y-axis scaling - application level
Store front web application
reviews web application
recommendations web ap...
@crichardson
Partitioning strategies...
Partition by verb, e.g. shipping service
Partition by noun, e.g. inventory service...
@crichardson
Partitioning strategies
Too few
Drawbacks of the monolithic architecture
Too many - a.k.a. Nano-service anti-...
@crichardson
Example micro-service
class RegistrationSmsServlet extends RegistrationSmsScalatraStack {
post("/") {
val pho...
@crichardson
Real world examples
http://highscalability.com/amazon-architecture
http://techblog.netflix.com/
http://www.add...
@crichardson
There are drawbacks
@crichardson
Complexity
See Steve Yegge’s Google Platforms Rant re
Amazon.com
@crichardson
Multiple databases
&
Transaction management
@crichardson
Implementing features that
span multiple services
@crichardson
When to use it?
In the beginning:
•You don’t need it
•It will slow you down
Later on:
•You need it
•Refactori...
@crichardson
But there are many benefits
@crichardson
Smaller, simpler apps
Easier to understand and develop
Reduced startup time - important for GAE
Less jar/clas...
@crichardson
Scales development:
develop, deploy and scale
each service independently
@crichardson
Improves fault isolation
@crichardson
Eliminates long-term commitment
to a single technology stack
Modular, polyglot, multi-
framework applications
@crichardson
Two levels of architecture
System-level
Services
Inter-service glue: interfaces and communication mechanisms
...
@crichardson
Easily try other technologies
... and fail safely
@crichardson
Agenda
The (sometimes evil) monolith
Decomposing applications into services
How do services communicate?
API ...
@crichardson
Inter-service communication
options
Synchronous HTTP asynchronous AMQP
Formats: JSON, XML, Protocol Buffers, ...
@crichardson
StoreFrontUI
Product Info
service
Recommendation
service
Review service
RabbitMQ
(Message
Broker)
Asynchronou...
Pros and cons of messaging
Pros
Decouples client from
server
Message broker buffers
messages
Supports a variety of
communi...
Spring Integration
Provides the building blocks for a pipes
and filters architecture
Enables development of application
com...
@crichardson
Order
Service
Messaging
Gateway
Channel Service
Activator
Shipping
service
Development time: same JVM
@Servic...
@crichardson
Order
Service
Messaging
Gateway
Channel Service
Activator
Shipping
service
AMQP
RabbitMQ
AMQP Channel
Test an...
@crichardson
Synchronous REST
Recommendation
service
StoreFrontUI
Product Info
service
Review service
REST
... Order servi...
Pros and cons of REST
Pros
Simple and familiar
Request/reply is easy
Firewall friendly
No intermediate broker
Cons
Only su...
@crichardson
Spring MVC makes REST easy
@Controller
public class AccountController {
@Autowired
private MoneyTransferServi...
@crichardson
Agenda
The (sometimes evil) monolith
Decomposing applications into services
How do services communicate?
API ...
@crichardson
Use an API gateway
Browser
Model
View Controller
HTML 5 - JavaScript
Product Info
service
Recommendation
Serv...
@crichardson
Netflix API Gateway
http://techblog.netflix.com/2013/01/optimizing-netflix-api.html
Device specific
end points
@crichardson
Developing an API gateway
Java EE web technologies
Netty-based technology stack
Non-Java options: e.g. Node.JS
@crichardson
API gateway design issues
@crichardson
The need for parallelism
Product
Details
API
Product Info
Recommendations
Reviews
getProductDetails()
getReco...
@crichardson
Futures are a great
concurrency abstraction
An object that will contain the result of a concurrent
computatio...
@crichardson
Better: Futures with callbacks
val f : Future[Int] = Future { ... }
f onSuccess {
case x : Int => println(x)
...
@crichardson
Even better: Composable Futures
val f1 = Future { ... ; 1 }
val f2 = Future { ... ; 2 }
val f4 = f2.map(_ * 2...
@crichardson
Composing concurrent requests
using Scala Futures
class ProductDetailsService @Autowired()(....) {
def getPro...
@crichardson
Handling partial failures
Product
Details
Controller
Product Info
Recommendations
Reviews
getProductDetails()...
@crichardson
About Netflix
> 1B API calls/day
1 API call average 6 service calls
Fault tolerance is essential
http://techbl...
@crichardson
How to run out of threads
Tomcat
Execute thread
pool
HTTP Request
Thread 1
Thread 2
Thread 3
Thread n
Service...
@crichardson
Their approach
Network timeouts and retries
Invoke remote services via a bounded thread pool
Use the Circuit ...
@crichardson
Agenda
The (sometimes evil) monolith
Decomposing applications into services
How do services communicate?
API ...
@crichardson
How do you decompose
your 10 M LOC monolithic
application?
@crichardson
Strategy #1: Stop digging
@crichardson
New functionality = service
Monolith Service
Anti-corruption
layer
Glue code
Pristine
@crichardson
Sounds simple but...
Dependencies between monolith and service
e.g. Common entities
Building the anti-corrupt...
@crichardson
Strategy #2: extract services
@crichardson
Module service ...
WAR
Module
@crichardson
... Module service
WAR Service
Anti-corruption
layer
@crichardson
What to extract?
Have the ideal partitioned architecture in mind:
Partitioned by verb or noun
Start with trou...
@crichardson
Service
Domain model 2
Monolith
Untangling dependencies
API A API B API C
Domain model 1
A
C
B
X
Z
Y
Trouble!
@crichardson
Useful idea: Bounded context
Different services have a different view of a
domain object, e.g.
User Managemen...
@crichardson
Customer management
Untangling orders and customers
Order management
Order Service
placeOrder()
Customer Serv...
@crichardson
Customer management
Replicating the credit limit
Order management
Order Service
placeOrder()
Customer
creditL...
@crichardson
Customer management
Maintaining the openOrderTotal
Order management
Order Service
placeOrder()
Customer Servi...
@crichardson
Refactoring a monolith is not easy
BUT
the alternative is far worse
@crichardson
Summary
@crichardson
Monolithic applications are
simple to develop and deploy
BUT have significant
drawbacks
@crichardson
Apply the scale cube
Modular, polyglot, and
scalable applications
Services developed,
deployed and scaled
ind...
@crichardson
Use a modular, polyglot architecture
Browser
Model
View Controller
HTML 5 - JavaScript
Product Info
service
R...
@crichardson
Questions?
@crichardson chris@chrisrichardson.net
http://plainoldobjects.com
Upcoming SlideShare
Loading in...5
×

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

2,858
-1

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 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

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

  1. 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. 2. @crichardson Presentation goal How decomposing applications improves deployability and scalability and simplifies the adoption of new technologies
  3. 3. @crichardson About Chris
  4. 4. @crichardson (About Chris)
  5. 5. @crichardson About Chris()
  6. 6. @crichardson About Chris
  7. 7. @crichardson About Chris http://www.theregister.co.uk/2009/08/19/springsource_cloud_foundry/
  8. 8. @crichardson About Chris
  9. 9. @crichardson Agenda The (sometimes evil) monolith Decomposing applications into services How do services communicate? API gateway design Refactoring the monolith
  10. 10. @crichardson Let’s imagine you are building an online store
  11. 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. 12. @crichardson But there are problems with a monolithic architecture
  13. 13. @crichardson Users expect a rich, dynamic and interactive experience
  14. 14. @crichardson Browser WAR StoreFrontUI Model View Controller Presentation layer evolution.... HTML / HTTP Old style UI architecture isn’t good enough
  15. 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. 16. @crichardson Intimidates developers
  17. 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. 18. @crichardson Overloads your IDE and container Slows down development
  19. 19. @crichardson Shipping team Accounting Engineering Obstacle to scaling development E-commerce application
  20. 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. 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. 22. @crichardson Requires long-term commitment to a technology stack
  23. 23. @crichardson Agenda The (sometimes evil) monolith Decomposing applications into services How do services communicate? API gateway design Refactoring the monolith
  24. 24. @crichardson
  25. 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. 26. @crichardson Y-axis scaling - application level WAR Review Service Product Info Service Recommendation Service StoreFrontUI Order Service
  27. 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. 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. 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. 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. 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. 32. @crichardson There are drawbacks
  33. 33. @crichardson Complexity See Steve Yegge’s Google Platforms Rant re Amazon.com
  34. 34. @crichardson Multiple databases & Transaction management
  35. 35. @crichardson Implementing features that span multiple services
  36. 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. 37. @crichardson But there are many benefits
  38. 38. @crichardson Smaller, simpler apps Easier to understand and develop Reduced startup time - important for GAE Less jar/classpath hell Who needs OSGI?
  39. 39. @crichardson Scales development: develop, deploy and scale each service independently
  40. 40. @crichardson Improves fault isolation
  41. 41. @crichardson Eliminates long-term commitment to a single technology stack Modular, polyglot, multi- framework applications
  42. 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. 43. @crichardson Easily try other technologies ... and fail safely
  44. 44. @crichardson Agenda The (sometimes evil) monolith Decomposing applications into services How do services communicate? API gateway design Refactoring the monolith
  45. 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. 46. @crichardson StoreFrontUI Product Info service Recommendation service Review service RabbitMQ (Message Broker) Asynchronous message-based communication Order service
  47. 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. 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. 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. 50. @crichardson Order Service Messaging Gateway Channel Service Activator Shipping service AMQP RabbitMQ AMQP Channel Test and production: distributed Application code is unchanged
  51. 51. @crichardson Synchronous REST Recommendation service StoreFrontUI Product Info service Review service REST ... Order service
  52. 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. 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. 54. @crichardson Agenda The (sometimes evil) monolith Decomposing applications into services How do services communicate? API gateway design Refactoring the monolith
  55. 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. 56. @crichardson Netflix API Gateway http://techblog.netflix.com/2013/01/optimizing-netflix-api.html Device specific end points
  57. 57. @crichardson Developing an API gateway Java EE web technologies Netty-based technology stack Non-Java options: e.g. Node.JS
  58. 58. @crichardson API gateway design issues
  59. 59. @crichardson The need for parallelism Product Details API Product Info Recommendations Reviews getProductDetails() getRecomendations() getReviews() Call in parallel get Product Details
  60. 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. 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. 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. 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. 64. @crichardson Handling partial failures Product Details Controller Product Info Recommendations Reviews getProductDetails() getRecomendations() getReviews() get Product Details X
  65. 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. 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. 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. 68. @crichardson Agenda The (sometimes evil) monolith Decomposing applications into services How do services communicate? API gateway design Refactoring the monolith
  69. 69. @crichardson How do you decompose your 10 M LOC monolithic application?
  70. 70. @crichardson Strategy #1: Stop digging
  71. 71. @crichardson New functionality = service Monolith Service Anti-corruption layer Glue code Pristine
  72. 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. 73. @crichardson Strategy #2: extract services
  74. 74. @crichardson Module service ... WAR Module
  75. 75. @crichardson ... Module service WAR Service Anti-corruption layer
  76. 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. 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. 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. 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. 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. 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. 82. @crichardson Refactoring a monolith is not easy BUT the alternative is far worse
  83. 83. @crichardson Summary
  84. 84. @crichardson Monolithic applications are simple to develop and deploy BUT have significant drawbacks
  85. 85. @crichardson Apply the scale cube Modular, polyglot, and scalable applications Services developed, deployed and scaled independently
  86. 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. 87. @crichardson Questions? @crichardson chris@chrisrichardson.net http://plainoldobjects.com
  1. Gostou de algum slide específico?

    Recortar slides é uma maneira fácil de colecionar informações para acessar mais tarde.

×