Your SlideShare is downloading. ×
0

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×
Saving this for later? Get the SlideShare app to save on your phone or tablet. Read anywhere, anytime – even offline.
Text the download link to your phone
Standard text messaging rates apply

Decomposing applications for deployability and scalability(SpringSource webinar)

1,608

Published on

Today, there are several trends that are forcing application architectures to evolve. Users expect a rich, interactive and dynamic user experience on a wide variety of clients including mobile …

Today, there are several trends that are forcing application architectures to evolve. Users expect a rich, interactive and dynamic user experience on a wide variety of clients including mobile devices. Applications must be highly scalable, highly available and run on cloud environments. Organizations often want to frequently roll out updates, even multiple times a day. Consequently, it’s no longer adequate to develop simple, monolithic web applications that serve up HTML to desktop browsers.

In this talk we describe the limitations of a monolithic architecture. You will learn how to use the scale cube to decompose your application into a set of narrowly focused, independently deployable back-end services and an HTML 5 client. We will also discuss the role of technologies such as Spring and AMQP brokers. You will learn how a modern PaaS such as Cloud Foundry simplifies the development and deployment of this style of application.

Published in: Technology, Business
0 Comments
12 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
1,608
On Slideshare
0
From Embeds
0
Number of Embeds
2
Actions
Shares
0
Downloads
79
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. © 2013 Spring, by PivotalChris RichardsonAuthor of POJOs in ActionFounder of the original CloudFoundry.com@crichardsonchris.richardson@springsource.comhttp://plainoldobjects.comDecomposing applications fordeployability and scalability
  • 2. @crichardsonPresentation goalHow decomposing applicationsimproves deployability andscalabilityandsimplifies the adoption of newtechnologies
  • 3. @crichardsonAbout Chris
  • 4. @crichardson(About Chris)
  • 5. @crichardsonAbout Chris()
  • 6. @crichardsonAbout Chris
  • 7. @crichardsonAbout Chrishttp://www.theregister.co.uk/2009/08/19/springsource_cloud_foundry/
  • 8. @crichardsonvmc push About-ChrisDeveloper Advocate
  • 9. @crichardsonAgendaThe (sometimes evil) monolithDecomposing applications into servicesDeveloping and deploying servicesHow do services communicate?
  • 10. @crichardsonLet’s imagine you are buildingan e-commerce application
  • 11. @crichardsonTomcatTraditional web applicationarchitectureBrowserWARMySQLDatabaseShippingServiceAccountingServiceInventoryServiceStoreFrontUIdeveloptestdeploySimple toApachescale
  • 12. @crichardsonBut there are problems witha monolithic architecture
  • 13. @crichardsonIntimidates developers
  • 14. @crichardsonObstacle to frequentdeploymentsNeed to redeploy everything to change one componentInterrupts long running background (e.g. Quartz) jobsIncreases risk of failureFear of changeUpdates will happen less oftene.g. Makes A/B testing UI really difficult
  • 15. @crichardsonOverloads your IDE andcontainerSlows down development
  • 16. @crichardsonShipping teamAccountingEngineeringObstacle to scalingdevelopmentE-commerceapplication
  • 17. @crichardsonWARShippingAccountingInventoryServiceStoreFront UIShipping teamAccounting teamInventory teamUI TeamObstacle to scalingdevelopment
  • 18. @crichardsonLots of coordination andcommunication requiredObstacle to scalingdevelopmentI wantto update the UIButthe backend is not workingyet!
  • 19. @crichardsonRequires long-term commitmentto a technology stack
  • 20. @crichardsonAgendaThe (sometimes evil) monolithDecomposing applications into servicesDeveloping and deploying servicesHow do services communicate?
  • 21. @crichardson
  • 22. @crichardsonThe scale cubeX axis- horizontal duplicationZaxis-datapartitioningY axis -functionaldecompositionScalebysplittingsimilarthingsScale bysplittingdifferent things
  • 23. @crichardsonY-axis scaling - application levelWARShippingServiceAccountingServiceInventoryServiceStoreFrontUI
  • 24. @crichardsonY-axis scaling - application levelStore front web applicationshipping web applicationinventory web applicationApply X axis cloning and/or Z axis partitioning to each serviceAccountingServiceStoreFrontUIaccounting web applicationShippingServiceInventoryService
  • 25. @crichardsonPartitioning strategies...Partition by verb, e.g. shipping servicePartition by noun, e.g. inventory serviceSingle Responsibility PrincipleUnix utilities - do one focussed thing well
  • 26. @crichardsonPartitioning strategiesToo fewDrawbacks of the monolithic architectureToo many - a.k.a. Nano-service anti-patternRuntime overheadPotential risk of excessive network hopsPotentially difficult to understand systemSomething of an art
  • 27. @crichardsonhttp://highscalability.com/amazon-architecturehttp://techblog.netflix.com/http://www.addsimplicity.com/downloads/eBaySDForum2006-11-29.pdfhttp://queue.acm.org/detail.cfm?id=1394128Real world examples
  • 28. @crichardsonThere are drawbacks
  • 29. @crichardsonComplexity
  • 30. @crichardsonMultiple databases&Transaction management
  • 31. @crichardsonImplementing and deployingfeatures that span multipleservices
  • 32. @crichardsonWhen to use it?In the beginning:•You don’t need it•It will slow you downLater on:•You need it•Refactoring is painful
  • 33. @crichardsonBut there are many benefitsScales development: develop, deploy and scale each serviceindependently, e.g. update UI independentlySimplifies distributed development and outsourcingImproves fault isolationEliminates long-term commitment to a single technology stackModular, polyglot, multi-framework applications
  • 34. @crichardsonTwo levels of architectureSystem-levelServicesInter-service glue: interfaces and communication mechanismsSlow changingService-levelInternal architecture of each serviceEach service could use a different technology stackPick the best tool for the jobRapidly evolving
  • 35. @crichardsonIf services are small...Regularly rewrite using a better technology stackAdapt system to changing requirements and bettertechnology without a total rewritePick the best developers rather than best <pick alanguage> developers polyglot culture
  • 36. @crichardsonThe human body as a system
  • 37. @crichardson50 to 70 billion of your cells dieeach day
  • 38. @crichardsonYet you (the system) remain you
  • 39. @crichardsonCan we build software systemswith these characteristics?http://dreamsongs.com/Files/WhitherSoftware.pdfhttp://dreamsongs.com/Files/DesignBeyondHumanAbilitiesSimp.pdf
  • 40. @crichardsonAgendaThe (sometimes evil) monolithDecomposing applications into servicesDeveloping and deploying servicesHow do services communicate?
  • 41. @crichardsonServices come in all shapesand sizes
  • 42. @crichardsonExample service: Spring MVC@Controllerclass TwilioController {@Autowiredvar surveyManagementService: SurveyManagementService = _@RequestMapping(value = Array("/begincall.html"))@ResponseBodydef beginCall(@RequestParam("From") callerId: String) = {surveyManagementService.findSurveyByCallerId(callerId) match {...case Some(survey) =><Response><Say>{ survey.prompt }</Say><Gather action="handleresponse.html" method="POST" numDigits="1">{for ((choice, index) <- survey.choices zipWithIndex)yield <Say>Press { index } for { choice }</Say>}</Gather><Say>We are sorry you could not decide</Say><Hangup/></Response>}}
  • 43. @crichardsonExample: standalone appmain()SpringIntegration
  • 44. @crichardsonExample service: NodeJSvar express = require(express), http = require(http), amqp = require(‘amqp’)....;server.listen(8081);...var amqpCon = amqp.createConnection(...);io.sockets.on(connection, function (socket) {function amqpMessageHandler(message, headers, deliveryInfo) {var m = JSON.parse(message.data.toString());socket.emit(‘tick’, m);};amqpCon.queue(“”, {},function(queue) {queue.bind(“myExchange”, “”);queue.subscribe(amqpMessageHandler);});});Simple portable way todeliver AMQP messagesto the browser
  • 45. @crichardsonExample service: Sinatrarequire sinatrapost / dophone_number = params[:From]registration_url ="#{ENV[REGISTRATION_URL]}?phoneNumber=#{URI.encode(phone_number, "+")}"<<-eof <Response> <Sms>To complete registration please go to #{registration_url}</Sms> </Response>eofend
  • 46. @crichardsonService deployment optionsVM or Physical MachineLinux Container/LXCJVMJAR/WAR/OSGI bundle/...Isolation, manageabilityDensity/efficiencyYou could do this yourself but ...
  • 47. @crichardsonPaaS dramatically simplifies deploymentApplicaon  Service  InterfaceOSS communityPrivate  Clouds  PublicCloudsMicroCloudsData ServicesOther ServicesMsg ServicesvFabricPostgresvFabricRabbitMQTMAdditional partners services …
  • 48. @crichardsonCloud Foundry featuresOne step deployment: vmc pushSingle applicationService-oriented applicationEasy platform service provisioning: vmc create-serviceSimple scaling: vmc instances app-name +/- NHealth monitoring and automated recovery
  • 49. @crichardsonBenefits of PaaSSimplifies and automates deploymentEliminates barriers to adding new serviceEliminates barriers to using a new platform serviceImposes conventions: packaging, configuration anddeploymentEnforces consistencyEliminates accidental complexity
  • 50. @crichardsonAgendaThe (sometimes evil) monolithDecomposing applications into servicesDeveloping and deploying servicesHow do services communicate?
  • 51. @crichardsonInter-service communicationoptionsSynchronous HTTP asynchronous AMQPFormats: JSON, XML, Protocol Buffers, Thrift, ...Asynchronous is preferredJSON is fashionable but binary formatis more efficient
  • 52. @crichardsonStoreFrontUIwgrus-store.warAccountingServicewgrus-billing.warInventoryServicewgrus-inventory.warShippingServicewgrus-shipping.warMySQLRabbitMQ(MessageBroker)Asynchronous message-based communication
  • 53. @crichardsonBenefitsDecouples client from server: client unaware of server’scoordinates (URL)Message broker buffers message when server is down/slowSupports a variety of communication patterns, e.g. point-to-point, pub-sub, ...
  • 54. @crichardsonDrawbacksAdditional complexity of message brokerRequest/reply-style communication is more complex
  • 55. @crichardsonSpring IntegrationProvides the building blocks for a pipesand filters architectureEnables development of applicationcomponents that areloosely coupledinsulated from messaging infrastructureMessaging defined declaratively
  • 56. @crichardsonSynchronous RESTShippingServiceStoreFrontUIwgrus-store.warAccountingServicewgrus-billing.warwgrus-shipping.warInventoryServicewgrus-inventory.warMySQLREST...
  • 57. Pros and cons of RESTProsSimple and familiarRequest/reply is easyBrowser and firewallfriendlyNo intermediate brokerConsOnly supports request/replyServer must beavailableClient needs to knowURL(s) of server(s)
  • 58. @crichardsonSpring MVC makes REST easy@Controllerpublic class AccountController {@Autowiredprivate MoneyTransferService moneyTransferService;@RequestMapping(value = "/accounts/{accountId}", method = RequestMethod.GET)@ResponseBodypublic 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) {...}URLmatching &destructuringobjectXML/JSONXML/JSONobject
  • 59. @crichardsonAbout Hypertext As The Engine OfApplication State (HATEOAS)$ curl http://cf-auto-scaler.cloudfoundry.com{"links": [ {"rel":"autoscaledapps", "href":"http://cf-auto-scaler.cloudfoundry.com/autoscaledapps"}]}The wellknown URLLinklink type$ curl http://cf-auto-scaler.cloudfoundry.com/autoscaledapps{"content":[{"name":"vertx-clock","links":[{"rel":"self","href":"http://cf-auto-scaler.cloudfoundry.com/autoscaledapps/vertx-clock"},{"rel":"rules","href":"http://cf-auto-scaler.cloudfoundry.com/autoscaledapps/vertx-clock/rules"}]}],...}Links to act on this app
  • 60. @crichardsonSpring HATEOAS@Controller@RequestMapping(value = "/autoscaledapps")public class AutoscaledAppController {@RequestMapping(value = "/{appName}", method = RequestMethod.GET)public HttpEntity<AutoscaledAppResource> get(@PathVariable String appName) {AutoscaledAppResource ar = new AutoscaledAppResource(appName);ar.add(linkTo(AutoscaledAppController.class).slash(appName).withSelfRel());ar.add(linkTo(AutoscaledAppController.class).slash(appName).slash("rules").withRel("rules"));return new HttpEntity<AutoscaledAppResource>(ar);}...}https://github.com/SpringSource/spring-hateoaspublic class AutoscaledAppResourceextends ResourceSupport {private String name;
  • 61. @crichardsonConsuming RESTful WSRestTemplate restTemplate = new RestTemplate();AccountInfo accountInfo = new AccountInfo(...);URI accountUrl =restTemplate.postForLocation("http://localhost/accounts", accountInfo);ResponseEntity<AccountInfo> accountInfoResponse =restTemplate.getForEntity(accountUrl, AccountInfo.class);Assert.assertEquals(HttpStatus.SC_OK, accountInfoResponse.getStatusCode());AccountInfo accountInfo2 = accountInfoResponse.getBody();...
  • 62. @crichardsonThe Spring REST shell$ rest-shellhttp://localhost:8080:> baseUri http://cf-auto-scaler.cloudfoundry.comhttp://cf-auto-scaler.cloudfoundry.com:> discoverrel href=======================================================================autoscaledapps http://cf-auto-scaler.cloudfoundry.com/autoscaledappshttp://cf-auto-scaler.cloudfoundry.com:> follow --rel autoscaledappshttp://cf-auto-scaler.cloudfoundry.com/autoscaledapps:> post --from src/test/resources/examplejson/createapp1.json --follow true1 files uploaded to the server using POSThttp://cf-auto-scaler.cloudfoundry.com/autoscaledapps/vertx-clock:> discoverrel href================================================================================self http://cf-auto-scaler.cloudfoundry.com/autoscaledapps/vertx-clockrules http://cf-auto-scaler.cloudfoundry.com/autoscaledapps/vertx-clock/ruleshttp://cf-auto-scaler.cloudfoundry.com/autoscaledapps/vertx-clock:> follow --rel ruleshttp://cf-auto-scaler.cloudfoundry.com/autoscaledapps/vertx-clock/rules:> post--from src/test/resources/examplejson/createrule1.json --follow true1 files uploaded to the server using POSThttp://cf-auto-scaler.cloudfoundry.com/autoscaledapps/vertx-clock/rules/idle:> uphttp://cf-auto-scaler.cloudfoundry.com/autoscaledapps/vertx-clock/rules:> up
  • 63. @crichardsonWriting code that callsservices
  • 64. @crichardsonThe need for parallelismProductDetailsControllerProduct DetailsRecommendationsReviewsgetProductDetails()getRecomendations()getReviews()Call inparallelDisplayProduct
  • 65. @crichardsonFutures are a greatconcurrency abstractionAn object that will contain the result of a concurrentcomputation http://en.wikipedia.org/wiki/Futures_and_promisesHides the underlying concurrency mechanism: threads orasyncFuture<Integer> result =executorService.submit(new Callable<Integer>() {... });Java has basic futures. Wecan do much better....
  • 66. @crichardsonBetter: Futures with callbacksval 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
  • 67. @crichardsonEven better: Composable Futuresval f1 = Future { ... ; 1 }val f2 = Future { ... ; 2 }val f4 = f2.map(_ * 2)assertEquals(4, Await.result(f4, 1 second))val fzip = f1 zip f2assertEquals((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 FuturesTransforms FutureCombines two futuresTransforms list of futures to afuture containing a list
  • 68. @crichardsonUsing Scala futuresdef callB() : Future[...] = ...def callC() : Future[...] = ...def callD() : Future[...] = ...val future = for {(b, c) <- callB() zip callC();d <- callD(b, c)} yield dval result = Await.result(future, 1 second)Two calls execute in parallelAnd then invokes DGet the result of DScala Futures
  • 69. @crichardsonHandling partial failuresService A Service BDown?Slow?Down?Slow?
  • 70. @crichardsonAbout Netflix> 1B API calls/day1 API call average 6 service callsFault tolerance is essentialhttp://techblog.netflix.com/2012/02/fault-tolerance-in-high-volume.html
  • 71. @crichardsonHow to run out of threadsTomcatExecute threadpoolHTTP RequestThread 1Thread 2Thread 3Thread nService A Service BIf service B isdown then threadwill be blockedXXXXXEventually all threadswill be blocked
  • 72. @crichardsonTheir approachNetwork timeouts and retriesInvoke remote services via a bounded thread poolUse the Circuit Breaker patternOn failure:return default/cached datareturn error to callerhttps://github.com/Netflix/Hystrix
  • 73. @crichardsonSummary
  • 74. @crichardsonMonolithic applications aresimple to develop and deployBUT have significantdrawbacks
  • 75. @crichardsonApply the scale cubeModular, polyglot, andscalable applicationsServices developed,deployed and scaledindependently
  • 76. @crichardsonCloud  Provider  InterfaceApplicaon  Service  InterfacePrivate  Clouds  PublicCloudsMicroCloudsData ServicesOtherServicesMsg Services.jsCloud Foundry helps
  • 77. @crichardsonQuestions?@crichardson chris.richardson@springsource.comhttp://plainoldobjects.com - code and slideswww.springsource.org
  • 78. 78Learn More. Stay Connected.Download now:• springsource.org/spring-tool-suite-download (eclipse plugin)• springsource.org/download/community (zip)• springsource.org/spring-framework#maven (maven)Monthly Newsletter: springsource.org/news-eventsTwitter: twitter.com/springsourceYouTube: youtube.com/user/SpringSourceDevRSS Feed: feeds.feedburner.com/springsource/OEVELinkedIn: springsource.org/linkedin

×