• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
Developing applications with Cloud Services  #javaone 2012
 

Developing applications with Cloud Services #javaone 2012

on

  • 1,710 views

Cloud computing isn't just about application deployment. There are also a growing number of cloud-based web services that you can use to develop your application. One of the most well known is ...

Cloud computing isn't just about application deployment. There are also a growing number of cloud-based web services that you can use to develop your application. One of the most well known is Amazon's Simple Storage Service. But there are many others including web services for messaging, relational and NoSQL databases, email and telephony. Using these services allows you to build highly scalable applications without the pain and cost of having to develop and operate your own infrastructure.

In this presentation, you will learn about the benefits and drawbacks of these Web services; their typical use cases and how to use them. We will describe a location aware, telephony application that is built using cloud services. You will learn about strategies for building resilient, fault tolerant applications that consume cloud services.

Statistics

Views

Total Views
1,710
Views on SlideShare
1,198
Embed Views
512

Actions

Likes
1
Downloads
21
Comments
0

3 Embeds 512

http://plainoldobjects.com 509
https://twitter.com 2
https://si0.twimg.com 1

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

    Developing applications with Cloud Services  #javaone 2012 Developing applications with Cloud Services #javaone 2012 Presentation Transcript

    • DEVELOPING WITH CLOUD SERVICES Chris Richardson Author of POJOs in Action Founder of the original CloudFoundry.com @crichardson crichardson@vmware.com http://plainoldobjects.com/
    • Presentation goal How to build robust,scalable applications with Cloud Services
    • About Chris
    • (About Chris)
    • About Chris()
    • About Chris
    • About Chrishttp://www.theregister.co.uk/2009/08/19/springsource_cloud_foundry/
    • vmc push About-Chris Developer Advocate for CloudFoundry.comSignup at http://cloudfoundry.com promo code: cfjavaone
    • Agenda• Why use cloud services?• Developing location-based applications• Building SMS and telephony enabled applications• Developing robust, fault tolerant applications
    • Three phases of every galactic civilizationSurvivalInquirySophistication
    • Three phases of every galactic civilizationHow can we eat?Why do we eat?Where shall we have lunch?
    • Where shall we have lunch? Solved by VoteMeetEat.com
    • VoteMeetEat.com•What restaurants are nearby?•Which friends are close by?•Where do your friends prefer to eat? To sign up text "register" to 510-555-????
    • VoteMeetEat.com Restaurant database + SMS + Voice calls To sign up text "register" to 510-555-????
    • Key story: registration 5551212
    • Key story: registration +5105551212
    • Key story: voting 555 1212
    • Key story: announce location
    • VOTEMEETEAT.COMTo sign up text "register" to 510-555-????
    • High-level architecture DIY = DIFFICULT Telephony Friend Geo Integration DatabaseMobile VoteMeetPhone Eat Restaurant Database Do we really want to build all this?
    • Use cloud-based services• Highly scalable services• Someone else’s headache to develop and maintain• Provided by IaaS/PaaS• Provided by 3rd party
    • Cloud Foundry services
    • Thousands of 3rd party services http://www.slideshare.net/jmusser/j-musser-apishotnotgluecon2012 http://www.programmableweb.com/apis/directory
    • Cloud service trends• Predominantly REST• Predominantly JSON•> billion API calls/day: Twitter, Google, Facebook, Netflix, Accuweather, ...• Increasing number of API-only companies http://www.slideshare.net/jmusser/j-musser-apishotnotgluecon2012
    • Diverse
    • Benefits of cloud services• Someone else’s headache to develop and operate• Focus on your core business problem• Get up and running quickly• Elasticity• Capex Opex
    • Drawbacks of cloud services• Complexity and drawbacks of a distributed system• You are dependent on service provider
    • Risks of cloud services Urban Airship’s Strategic Partnership With SimpleGeo Turns Into An Acquisition
    • Cloud Services-based architecture Twilio MongoDBMobilePhone VoteMeetEat Factual.Com
    • DEMO
    • Agenda• Why use cloud services?• Developing location-based applications• Building SMS and telephony enabled applications• Developing robust, fault tolerant applications
    • Location-based services are hot!
    • Client-side APIs for finding locationW3C Geolocation API
    • BUT what about the server-side?
    • Lots of really difficult problems• Scalable, spatial database – CRUD records, find nearby• Data management – database of places, street information• Forward geo-coding: address lat/lon• Reverse geo-coding: lat/lon address• Maps• Directions Easier to use Geo-aaS
    • Examples of Geo-aaS• Maps • Freely available geographic• Forward and reverse geocoding database• Directions • Various APIs including• Elevation reverse geocoding• Places• Business+review database • Places database• Neighborhood database • Reverse geocoding Beware the terms of service
    • VOTEMEETEAT & Geotrait FriendService { def addOrUpdate(request : AddOrUpdateUserRequest) def findNearbyFriends(request : NearbyFriendsRequest) : FindNearbyFriendsResponse}trait RestaurantService { def findNearbyRestaurants(location: Location) : FindNearbyRestaurantResponse}
    • Implementing the friends database
    • MongoDB• Document-oriented database• Very fast, highly scalable and available• Rich query language that supports location- based queries• Provided by CloudFoundry.com
    • Storing friends in MongoDB MongoDB server Database: VoteMeetEat Collection: friendRecord { "_id": "+15105551212", "name": "Chris R.", "location": { "x": -122.25206103187264, "y": 37.847427441773796 } }
    • Spring Data for MongoDB• Provides MongoTemplate• Analogous to JdbcTemplate• Hides boilerplate code• Domain object Document mapping
    • Using Spring data: creating an index on location attribute@Componentclass MongoFriendService extends FriendService { @Autowired var mongoTemplate: MongoTemplate = _ @PostConstruct Collection name def createGeoIndex { val dbo = new BasicDBObject dbo.put("location", "2d") mongoTemplate.getCollection("friendRecord").ensureIndex(dbo) } Create geospatial 2d index
    • Using Spring Data: adding record@Componentclass MongoFriendService extends FriendService { override def addOrUpdate(request: AddOrUpdateUserRequest) = { val name = request.name val phoneNumber = request.phoneNumber val fr = new FriendRecord(phoneNumber, name, new Point(request.longitude, request.latitude)) mongoTemplate.save(fr) } case class FriendRecord(id : String, name : String, location : Point)
    • Using Spring Data: finding nearby friends@Componentclass MongoFriendService extends FriendService { override def findNearbyFriends(request: NearbyFriendsRequest) = { val location = new Point(request.longitude, request.latitude) val distance = new Distance(3, Metrics.MILES) val query = NearQuery.near(location).maxDistance(distance) val result = mongoTemplate.geoNear(query, classOf[FriendRecord]) val nearby = result.getContent.map(_.getContent) FindNearbyFriendsResponse(nearby.map(f => FriendInfo(f.name, f.id))) }
    • MongoDB and Cloud Foundry$ vmc create-service mongodb vme-mongo
    • Binding a service to an application $ vmc push vme-user --path web/target/ Application Deployed URL [cer-spring.cloudfoundry.com]: Detected a Java SpringSource Spring Application, is this correct? [Yn]: Memory Reservation (64M, 128M, 256M, 512M, 1G) [512M]: Creating Application: OKWould you like to bind anyany services to vme-user? [yN]: y Would you like to bind services to vme-user? [yN]: yWould you like to use an an existing provisioned [yN]: y Would you like to use existing provisioned service? service? [yN]: yThe The following provisioned services are available following provisioned services are available1: vme-mongo 1: vme-mongo2: mysql-135e0 2: mysql-135e0Please select one you wish to use: use: 1 Please select one you wish to 1Binding Service [vme-mongo]: OK OK Binding Service [vme-mongo]: Uploading Application: Checking for available resources: OK Processing resources: OK Packing application: OK Uploading (12K): OK Push Status: OK
    • Connecting to MongoDB <bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate"> <constructor-arg ref="mongoFactory" /> </bean> Outside of Cloud Foundry <beans profile="default"> <mongo:db-factory id="mongoFactory" dbname="surveygeo" /> </beans> Inside Cloud Foundry <beans profile="cloud"> <cloud:mongo-db-factory id="mongoFactory" /> </beans>
    • Implementing the restaurant database
    • Using Factual• Geographic database as a Service• Including 800,000 restaurants in the US• Pricing: 10K calls day free, pay per use
    • Factual API• RESTful/JSON interface • Uses 2-legged OAuth 1.0. • Geo and text filters • Pagination• Libraries for various languages
    • Restaurant Service@Serviceclass FactualRestaurantService extends RestaurantService { @Value("${factual_consumer_key}") var consumerKey: String = _ @Value("${factual_consumer_secret}") var consumerSecret: String = _ var factual: ThreadLocal[Factual] = _ @PostConstruct Not thread-safe def initialize { factual = new ThreadLocal[Factual] { override def initialValue() = new Factual(consumerKey, consumerSecret, true) } } override def findNearbyRestaurants(location: Location) = { val restaurants = factual.get.fetch("restaurants-us", new Query().within(new Circle(location.lat, location.lon, 1000)).limit(5)) val rs = for (map <- restaurants.getData) yield { RestaurantInfo(map.get("name").asInstanceOf[String]) } FindNearbyRestaurantResponse(rs.toList) 5 restaurants within 1km }...
    • Agenda• Why use cloud services?• Developing location-based applications• Building SMS and telephony enabled applications• Developing robust, fault tolerant applications
    • The telephony and SMS are important 7/ waking hr !http://blog.nielsen.com/nielsenwire/online_mobile/new-mobile-obsession- Nielsen u-s-teens-triple-data-usage/
    • Reporting traffic light problems in London
    • Google 2-Factor authentication
    • VoteMeetEat.com & Telephony• Handling registration SMS• Sending SMS notifying users to vote• Handling incoming voice call from voters: • Text-to-speech of restaurants options • Collecting digits entered via keypad• Sending SMS notification of voting results
    • DIY telephony = Difficult aS: y-a hon• Difficult to setup and operate Telep• Expensive e S MS/ to us ter• Complex SMS protocols Bet•…
    • Telephony/SMS - aaS• SMS • SMS• Inbound and outgoing calls • Inbound and outgoing calls• Recording and transcription • Recording and transcription • Twitter • IM
    • Twilio - Telephony and SMS as a service• REST API • Allocate phone numbers • Make and receive phone calls • Send and receive SMS messages• Pay per use: • Phone calls - per-minute • SMS – per SMS sent or received • Phone number – per month• Examples • OpenVBX is a web-based, open source phone system • StubHub – notifies sellers of a pending sale via phone • SurveyMonkey – interactive polling • Salesforce – SMS-based voting for 19,000 conference attendees
    • Using Twilio Manage resources Send SMS Initiate voice calls REST API Voice SMS Your Twilio HTTP GET/ Application POST TwiML doc Phone number Handle incoming SMS and voice callsSMS URL + VOICE URL Respond to user input
    • Handling SMS registration 5551212
    • Handling SMS registration HTTP POST http://≪smsUrl≫?From=≪PhoneNumber≫SMS SMS Twilio REGISTRATION <Response> <Sms>To complete registration please go to http://... </Sms> </Response>
    • Handling SMS registration TwiML document describing the response
    • Inviting users to vote 5551212
    • Inviting users to votePOST /2010-04-01/Accounts/≪AccountSID≫/SMS/Messages From=+15105551212&To=+14155551212&Body=≪MESSAGE≫Authorization: Basic .... Basic auth using Twilio AccountSid+AuthToken
    • Sending SMS using the Spring REST Template@Componentclass TwilioService { def sendSms(recipient : String, message : String) = { val response = postToTwilio("SMS/Messages", Map("From" -> twilioPhoneNumber, "To" -> recipient, "Body" -> message)) (response "SMSMessage" "Sid").text }
    • Sending SMS using the Spring@Component REST Templateclass TwilioService { TODO def postToTwilio(resourcePath : String, requestParams : Map[String, String]) = { val entity = makeEntity(requestParams) try { val response = restTemplate.postForObject(twilioUrl + "/Accounts/{accountSid}/{resource}", entity, classOf[String], accountSid, resourcePath) XML.loadString(response) } catch { case e : HttpClientErrorException if e.getStatusCode == HttpStatus.BAD_REQUEST => val body = e.getResponseBodyAsString() val xmlBody = XML.loadString(body) val code = Integer.parseInt((xmlBody "Code").text) val message = (xmlBody "Message").text throw new TwilioRestException(message, code) }}
    • Voting 555 1212
    • Voting HTTP POST http://≪voiceUrl≫?From=≪PhoneNumber≫ Survey ManagementCall <Response> Twilio <Say> Chris would like to meet and eat. </Say> <Gather action="handleresponse.html" method="POST" numDigits="1"> <Say>Press 1 for ....</Say> <Say>Press 2 for ....</Say> </Gather> </Response>
    • Voting HTTP POST http://....handleresponse.html? From=≪PhoneNumber≫&Digits=≪...≫ Survey ManagementDigits <Response> Twilio <Say>Thank you for choosing. The most popular place so far is ... </Say> <Pause/> <Say>You will hear from us soon. Good bye</Say> <Hangup/> </Response>
    • Voting code 1@Controllerclass TwilioController { @Autowired var surveyManagementService: SurveyManagementService = _ @RequestMapping(value = Array("/begincall.html")) @ResponseBody def beginCall(@RequestParam("From") callerId: String) = { surveyManagementService.findSurveyByCallerId(callerId) match { case None => <Response> <Say>Sorry dont recognize your number</Say> <Hangup/> </Response> 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> } }
    • Voting code 2class TwilioController { ... @RequestMapping(value = Array("/handleresponse.html")) @ResponseBody def handleUserResponse(@RequestParam("From") callerId: String, @RequestParam("Digits") digits: Int) = { val survey = surveyManagementService.recordVote(callerId, digits) <Response> <Say>Thank you for choosing. The most popular place so far is { survey.map(_.mostPopularChoice) getOrElse "oops" } </Say> <Pause/> <Say>You will hear from us soon. Good bye</Say> <Hangup/> </Response> }}
    • Agenda• Why use cloud services?• Developing location-based applications• Building SMS and telephony enabled applications• Developing robust, fault tolerant applications
    • The need for parallelism Service B b = serviceB() Call in parallel c = serviceC()Service A Service C d = serviceD(b, c) Service D
    • Java Futures are a great concurrency abstractionhttp://en.wikipedia.org/wiki/Futures_and_promises
    • Akka’s composable futures are even better
    • Using Akka futurestrait FriendService { def findNearbyFriends(request : NearbyFriendsRequest) : Future[FindNearbyFriendsResponse]} trait RestaurantService { def findNearbyRestaurants(location: Location) : Future[FindNearbyRestaurantResponse] } val friendsRequest = NearbyFriendsRequest.fromLocation(vmeRecord.location) for ( (nearbyFriends, nearbyRestaurants) <- friendsService.findNearbyFriends(friendsRequest) zip restaurantService.findNearbyRestaurants(vmeRecord.location) ) { .... } } Two calls execute in parallel
    • Using external web services = Distributed system Twilio MongoDBMobilePhone VoteMeetEat Factual.Com
    • Internally = Distributed System Survey management User management Registration SMS Rabbit MQ Registration web app VME management VME web app
    • Handling failureService A Service B Errors happen in distributed systems
    • About Netflix > 1B API calls/day1 API call average 6 service calls Fault tolerance is essential http://techblog.netflix.com/2012/02/fault-tolerance-in-high-volume.html
    • Use timeouts and retries Never wait forever Errors can be transient retry http://techblog.netflix.com/2012/02/fault-tolerance-in-high-volume.html
    • Use per-dependency bounded thread pool Service A Runnable 1 Task 1 Runnable 2 Task 2 Service B Runnable ... Task ... bounded queue bounded thread pool Fails fast if Limits number ofservice is slow or down outstanding requests http://techblog.netflix.com/2012/02/fault-tolerance-in-high-volume.html
    • Use a circuit breaker High error rate stop calling temporarily Down wait for it to come back up Slow gives it a chance to recoverClosed errors Open timeout success Half fail open http://techblog.netflix.com/2012/02/fault-tolerance-in-high-volume.html
    • On failure Return cached dataAvoidFailing Return default data Fail fast http://techblog.netflix.com/2012/02/fault-tolerance-in-high-volume.html
    • Aspects + Actors Dependency Caller Invoker Implements Aspect circuit breaker state machine CircuitBreakerEquivalent of Actorthread pool Worker Dependency Worker Actor Stub Actor
    • @DependencyProxy annotation trait RestaurantService { def findNearbyRestaurants(location: Location) : Future[FindNearbyRestaurantResponse] } @Service @DependencyProxy(circuitBreaker = "factualCircuitBreaker", timeoutInMilliseconds=750) class FactualRestaurantService extends RestaurantService { ... }
    • Aspect-based Async Execution@Aspectclass DependencyInvokingAspect { @Pointcut("execution(* (@DependencyProxy *).*(..))") def dependencyProxyMethods {} @Around("dependencyProxyMethods()") def invoke(jp: ProceedingJoinPoint) = { val a = AnnotationUtils.findAnnotation(jp.getTarget.getClass, classOf[DependencyProxy]) val actor = findActor(a) val timeout = Timeout(a.timeoutInMilliseconds milliseconds) actor.ask(InvokeDependency( () => jp.proceed())) (timeout) }} Ask actor to invoke jp.proceed() and return Future
    • Seehttps://github.com/cer/votemeeteat for the Actor code
    • SummaryCloud services are highly scalable services developed and operated by a 3rd party Let’s you focus on your core business problem Risk: provider is acquired and stops offering service Developing an application that reliably consumes cloud services requires careful design
    • @crichardson crichardson@vmware.com http://slideshare.net/chris.e.richardson/ Questions?Sign up for CloudFoundry.com using promo code cfjavaone