Upgrade to Pro — share decks privately, control downloads, hide ads and more …

The Serverless Way

Rob Allen
November 20, 2018

The Serverless Way

Serverless applications feel different and you need know why! In this talk I will look at how to design your application the serverless way.

The session will discuss how serverless applications embrace cloud services and live in a world where there are many separate parts, each responsible to for one thing. I'll cover the architectural patterns we use to design a serverless application including handling their stateless nature, how to use multiple functions for a task and leveraging event processing to trigger further functions. I will then turning my attention to showing you how to put these into practice by looking at how they can be implemented in an Apache OpenWhisk application.

By the end of the session, you'll be well placed to design and build your own serverless apps that take full advantage of the decentralised world they live in.

Presented TopConf, Tallinn, November 2018

Rob Allen

November 20, 2018
Tweet

More Decks by Rob Allen

Other Decks in Programming

Transcript

  1. Container deployments 1. Platform (e.g. Kubernetes) 2. Application (e.g. Cloud

    Foundry) 3. Serverless (e.g. OpenWhisk) Rob Allen ~ @akrabat
  2. Serverless? The first thing to know about serverless computing is

    that "serverless" is a pretty bad name to call it. - Brandon Butler, Network World Rob Allen ~ @akrabat
  3. AKA: Functions as a Service • Code • Deployed to

    the cloud • Executed in response to an event • On-demand scaling • Pay for execution, not when idle Rob Allen ~ @akrabat
  4. Use-cases Synchronous Service is invoked and provides immediate response (HTTP

    requests: APIs, chat bots) Asynchronous Push a message which drives an action later (web hooks, timed events, database changes) Rob Allen ~ @akrabat
  5. Use-cases Synchronous Service is invoked and provides immediate response (HTTP

    requests: APIs, chat bots) Asynchronous Push a message which drives an action later (web hooks, timed events, database changes) Streaming Continuous data flow to be processed Rob Allen ~ @akrabat
  6. Benefits • No need to think about servers • Concentrate

    on application code • Pay only for what you use, when you use it • Language agnostic: • NodeJS, Python, Swift, Go, Java, C#, PHP, Ruby, etc Rob Allen ~ @akrabat
  7. Challenges • Start up latency • Time limit • State

    is external • DevOps is still a thing Rob Allen ~ @akrabat
  8. When should you use serverless? • Occasional server needs on

    a static site • Variable traffic levels • Additional compute without extending current platform • Responding to web hooks • Any web app that you want to be cheaper to run! Rob Allen ~ @akrabat
  9. Hello World AWS Lambda: def my_handler(event, context): name = event.get("name",

    "World") message = 'Hello {}!'.format(name) return {'message': message} Rob Allen ~ @akrabat
  10. Hello World Apache OpenWhisk: def main(args): name = args.get("name", "World")

    message = 'Hello {}!'.format(name) return {'message': message} Rob Allen ~ @akrabat
  11. Hello World Google Cloud Functions def hello_http(request): name = request.json.get("name",

    "World") message = 'Hello {}!'.format(name) return message Rob Allen ~ @akrabat
  12. Hello World Azure Cloud Functions import azure.functions as func def

    main(req: func.HttpRequest, msg: func.Out[func.QueueMessage]) -> str: name = req.params.json.get("name", "World") message = 'Hello {}!'.format(name) msg.set(message) return message Rob Allen ~ @akrabat
  13. The anatomy of an action def main(args): # Marshall inputs

    from event parameters name = args.get("name", "World") # Do the work message = 'Hello {}!'.format(name) # return result return {'message': message} Rob Allen ~ @akrabat
  14. The anatomy of an action def main(args): # Marshall inputs

    from event parameters name = args.get("name", "World") # Do the work message = 'Hello {}!'.format(name) # return result return {'message': message} Rob Allen ~ @akrabat
  15. The anatomy of an action def main(args): # Marshall inputs

    from event parameters name = args.get("name", "World") # Do the work message = 'Hello {}!'.format(name) # return result return {'message': message} Rob Allen ~ @akrabat
  16. The anatomy of an action def main(args): # Marshall inputs

    from event parameters name = args.get("name", "World") # Do the work message = 'Hello {}!'.format(name) # return result return {'message': message} Rob Allen ~ @akrabat
  17. Creating your action in OpenWhisk $ wsk action create hello

    hello.py ok: updated action hello Rob Allen ~ @akrabat
  18. Running your action in OpenWhisk $ wsk action create hello

    hello.py ok: updated action hello $ wsk action invoke hello --result --param name Rob Rob Allen ~ @akrabat
  19. Running your action in OpenWhisk $ wsk action create hello

    hello.py ok: updated action hello $ wsk action invoke hello --result --param name Rob { "message": "Hello Rob!" } Rob Allen ~ @akrabat
  20. Access from the web API Gateway provides: • API routing

    • Rate limiting • Authentication • Custom domains Rob Allen ~ @akrabat
  21. API Gateway $ wsk api create /myapp /hello GET hello

    ok: created API /myapp/hello GET for action /_/hello Rob Allen ~ @akrabat
  22. API Gateway $ wsk api create /myapp /hello GET hello

    ok: created API /myapp/hello GET for action /_/hello $ curl https://example.com/myapp/hello?name=Rob Rob Allen ~ @akrabat
  23. API Gateway $ wsk api create /myapp /hello GET hello

    ok: created API /myapp/hello GET for action /_/hello $ curl https://example.com/myapp/hello?name=Rob { "message": "Hello Rob!" } Rob Allen ~ @akrabat
  24. Event providers (feeds) • Webhook triggers: • GitHub • Slack

    • Databases: CouchDB • Message Queues: Kafka • Mobile Push • Scheduled Rob Allen ~ @akrabat
  25. Structure If it's non-trivial, software engineering principles apply! • Use

    multiple methods • Use multiple files Rob Allen ~ @akrabat
  26. Structure If it's non-trivial, software engineering principles apply! • Use

    multiple methods • Use multiple files • Integrate reusable dependencies Rob Allen ~ @akrabat
  27. Example from Adobe CIF-Magento function postCoupon(args) { const validator =

    new InputValidator(args, ERROR_TYPE) .checkArguments().mandatoryParameter('id') if (validator.error) { return validator.buildErrorResponse(); } const cart = new MagentoCart(args, cartMapper.mapCart, 'guestcart'); return cart.byId(args.id).addCoupon(args.code).then(function () { return cart.byId(args.id).get(); }).catch(error => { return cart.handleError(error); }); } Rob Allen ~ @akrabat
  28. Example from Adobe CIF-Magento function postCoupon(args) { const validator =

    new InputValidator(args, ERROR_TYPE) .checkArguments().mandatoryParameter('id') if (validator.error) { return validator.buildErrorResponse(); } const cart = new MagentoCart(args, cartMapper.mapCart, 'guestcart'); return cart.byId(args.id).addCoupon(args.code).then(function () { return cart.byId(args.id).get(); }).catch(error => { return cart.handleError(error); }); } Rob Allen ~ @akrabat
  29. Example from Adobe CIF-Magento function postCoupon(args) { const validator =

    new InputValidator(args, ERROR_TYPE) .checkArguments().mandatoryParameter('id') if (validator.error) { return validator.buildErrorResponse(); } const cart = new MagentoCart(args, cartMapper.mapCart, 'guestcart'); return cart.byId(args.id).addCoupon(args.code).then(function () { return cart.byId(args.id).get(); }).catch(error => { return cart.handleError(error); }); } Rob Allen ~ @akrabat
  30. Example from Adobe CIF-Magento function postCoupon(args) { const validator =

    new InputValidator(args, ERROR_TYPE) .checkArguments().mandatoryParameter('id') if (validator.error) { return validator.buildErrorResponse(); } const cart = new MagentoCart(args, cartMapper.mapCart, 'guestcart'); return cart.byId(args.id).addCoupon(args.code).then(function () { return cart.byId(args.id).get(); }).catch(error => { return cart.handleError(error); }); } Rob Allen ~ @akrabat
  31. Infrastructure as Code composer.sequence( composer.if( 'binday/authenticate', composer.if( 'binday/validate', composer.if( 'binday/is_intent_setday',

    'binday/set_bin_day', 'binday/get_next_bin_day' ), 'binday/send_failure' ), 'binday/send_failure' ), 'binday/format_output_for_alexa' ) Rob Allen ~ @akrabat
  32. Tips & tricks • Make troubleshooting easier: • Ability to

    disable event triggers • Identifiers that run throughout functions for a single "operation" • Don't forget HTTP circuit breakers - retry with a back-off algorithm • Tune memory settings for each function - affects price (& performance) Rob Allen ~ @akrabat