Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Migrating existing monolith to serverless in 8 steps

137 views

Published on

Refactoring a monolith to serverless can be intimidating, but there are discrete steps that you can take to simplify the process. In this talk, AWS Serverless Hero Yan Cui outlines 8 steps to successfully refactor your monolith and highlight key decision points such as language and tooling choices.

Published in: Technology
  • Be the first to comment

  • Be the first to like this

Migrating existing monolith to serverless in 8 steps

  1. 1. Refactoring a monolith to serverless in 8 steps Yan Cui @theburningmonk
  2. 2. @theburningmonk theburningmonk.com
  3. 3. @theburningmonk theburningmonk.com FASTER CH€AP€R SCALABLE RESILIENT SECURE
  4. 4. @theburningmonk theburningmonk.com
  5. 5. @theburningmonk theburningmonk.com
  6. 6. @theburningmonk theburningmonk.com **** me, that’s pretty far..
  7. 7. @theburningmonk theburningmonk.com 6 months, 6 devs
  8. 8. @theburningmonk theburningmonk.com 95% cost saving compared to existing EC2-based solution
  9. 9. @theburningmonk theburningmonk.com velocity went from months to days
  10. 10. Yan Cui http://theburningmonk.com @theburningmonk AWS user for 10 years
  11. 11. http://bit.ly/yubl-serverless
  12. 12. Yan Cui http://theburningmonk.com @theburningmonk Developer Advocate @
  13. 13. Yan Cui http://theburningmonk.com @theburningmonk Independent Consultant advisetraining delivery
  14. 14. theburningmonk.com/courses
  15. 15. realworldserverless.com
  16. 16. Learn GraphQL and AppSync by building a Twitter clone with these technologies appsyncmasterclass.com
  17. 17. @theburningmonk theburningmonk.com you can do it too, but you have to first create the conditions where success is allowed to happen
  18. 18. Step 1. Reverse Conway’s Maneuver
  19. 19. @theburningmonk theburningmonk.com “organizations which design systems ... are constrained to produce designs which are copies of the communication structures of these organizations” Conway’s Law
  20. 20. “we’re doing serverless, but why aren’t thing going faster?”
  21. 21. @theburningmonk theburningmonk.com
  22. 22. @theburningmonk theburningmonk.com centralised team Team A Team B Team C Team D …
  23. 23. @theburningmonk theburningmonk.com centralised team Team A Team B Team C Team D … bottoleneck
  24. 24. @theburningmonk theburningmonk.com “but the developers don’t understand AWS and how our infrastructure is set up”
  25. 25. @theburningmonk theburningmonk.com “but the developers don’t understand AWS and how our infrastructure is set up” let’s solve this problem instead!
  26. 26. @theburningmonk theburningmonk.com the best way to improve system reliability is to put its developers on the on-call rota
  27. 27. @theburningmonk theburningmonk.com Reverse Conway’s Maneuver “sturcture your organization to match the software you intent to produce”
  28. 28. @theburningmonk theburningmonk.com “we want software that are made up of small, loosely-coupled components, that can be deployed and scaled indepedently, and can fail indepedently affecting each other”
  29. 29. @theburningmonk theburningmonk.com small, autonomous teams that can innovate and move quickly, and fail in isolation
  30. 30. @theburningmonk theburningmonk.com trust, but verify
  31. 31. @theburningmonk theburningmonk.com provide guidance and context over centralized control & gatekeeping
  32. 32. @theburningmonk theburningmonk.com align teams with problems, not solutions
  33. 33. @theburningmonk theburningmonk.com don’t let everyone start all at once!
  34. 34. @theburningmonk theburningmonk.com find your Pioneers and Settlers create a success story first http://bit.ly/398gv5e
  35. 35. @theburningmonk theburningmonk.com accept that your teams need to skill up
  36. 36. @theburningmonk theburningmonk.com https://www.jeremydaly.com/newsletter
  37. 37. Step 2. Identify service boundaries
  38. 38. be a toe-dipper
  39. 39. @theburningmonk theburningmonk.com
  40. 40. @theburningmonk theburningmonk.com start with low-risk, non-critical business processes
  41. 41. @theburningmonk theburningmonk.com incrementally migrate the legacy system by gradually replacing pieces of functionalities to the new system Strangler Pattern
  42. 42. @theburningmonk theburningmonk.com
  43. 43. @theburningmonk theburningmonk.com
  44. 44. @theburningmonk theburningmonk.com
  45. 45. @theburningmonk theburningmonk.com
  46. 46. @theburningmonk theburningmonk.com
  47. 47. @theburningmonk theburningmonk.com
  48. 48. @theburningmonk theburningmonk.com Services… are autonomous
  49. 49. @theburningmonk theburningmonk.com Services… are autonomous have clear boundaries
  50. 50. @theburningmonk theburningmonk.com Services… are autonomous have clear boundaries own their data
  51. 51. @theburningmonk theburningmonk.com Services… are autonomous have clear boundaries own their data are loosely coupled through shared contracts
  52. 52. @theburningmonk theburningmonk.com beware the “entity service” anti-pattern
  53. 53. @theburningmonk theburningmonk.com
  54. 54. Step 3. Organize your codebase
  55. 55. @theburningmonk theburningmonk.com github repo github repo github repo github repo github repo github repo github repo github repo github repo
  56. 56. @theburningmonk theburningmonk.com github repo github repo github repo github repo github repo github repo github repo github repo github repo
  57. 57. @theburningmonk theburningmonk.com monorepo
  58. 58. @theburningmonk theburningmonk.com github repo
  59. 59. @theburningmonk theburningmonk.com
  60. 60. @theburningmonk theburningmonk.com share code through symlinks + webpack
  61. 61. @theburningmonk theburningmonk.com one CI/CD that deploys them all (in parallel)
  62. 62. @theburningmonk theburningmonk.com
  63. 63. @theburningmonk theburningmonk.com good for small teams/startups
  64. 64. @theburningmonk theburningmonk.com All the benefits, none of the downsides (yet)
  65. 65. @theburningmonk theburningmonk.com one repo per service
  66. 66. @theburningmonk theburningmonk.com github repo github repo github repo github repo user-api timeline-api relationship-api search-api
  67. 67. @theburningmonk theburningmonk.com
  68. 68. @theburningmonk theburningmonk.com one CI/CD pipeline per service
  69. 69. @theburningmonk theburningmonk.com shared infrastructure (VPCs, etc.) in separate repo
  70. 70. @theburningmonk theburningmonk.com ref shared infra via CFN output, SSM param, etc.
  71. 71. @theburningmonk theburningmonk.com share code through shared libs (NPM, maven, etc.)
  72. 72. @theburningmonk theburningmonk.com shared code vs shared service
  73. 73. @theburningmonk theburningmonk.com https://theburningmonk.com/2018/02/aws-lambda-how-best-to-manage-shared-code-and-shared-infrastructure/
  74. 74. Step 4. Pick your tools
  75. 75. @theburningmonk theburningmonk.com deployment framework, CI, monitoring, etc.
  76. 76. @theburningmonk theburningmonk.com there’s NO “best tool” for X pick the best one for YOU and stick to it
  77. 77. @theburningmonk theburningmonk.com
  78. 78. @theburningmonk theburningmonk.com https://lumigo.io/blog/comparison-of-lambda-deployment-frameworks
  79. 79. @theburningmonk theburningmonk.com don’t write your own deployment framework
  80. 80. @theburningmonk theburningmonk.com standardization maximizes instituational knowledge sharing
  81. 81. Step 5. Keep functions simple
  82. 82. @theburningmonk theburningmonk.com what got you here won’t get you there
  83. 83. @theburningmonk theburningmonk.com if (path == “/user” && method == “GET”) { return getUser(…); } else if (path == “/user” && method == “DELETE”) { return deleteUser(…); } else if (path == “/user” && method == “POST”) { return createUser(…); } else if …. Monolithic Functions
  84. 84. @theburningmonk theburningmonk.com GET /user POST /user DELETE /user Single-Purposed Functions
  85. 85. @theburningmonk theburningmonk.com author: yan.cui feature: user-api user-api-dev Monolithic Single-Purposed author: yan.cui feature: user-api user-api-dev-get-user author: yan.cui feature: user-api user-api-dev-create-user author: yan.cui feature: user-api user-api-dev-delete-user
  86. 86. @theburningmonk theburningmonk.com author: yan.cui feature: user-api user-api-dev Monolithic Single-Purposed author: yan.cui feature: user-api user-api-dev-get-user author: yan.cui feature: user-api user-api-dev-create-user author: yan.cui feature: user-api user-api-dev-delete-user find related functions by prefix
  87. 87. @theburningmonk theburningmonk.com author: yan.cui feature: user-api user-api-dev Monolithic Single-Purposed author: yan.cui feature: user-api user-api-dev-get-user author: yan.cui feature: user-api user-api-dev-create-user author: yan.cui feature: user-api user-api-dev-delete-user discoverability (without having to dig into the code)
  88. 88. @theburningmonk theburningmonk.com author: yan.cui feature: user-api user-api-dev Monolithic Single-Purposed author: yan.cui feature: user-api user-api-dev-get-user author: yan.cui feature: user-api user-api-dev-create-user author: yan.cui feature: user-api user-api-dev-delete-user what does it do?
  89. 89. @theburningmonk theburningmonk.com author: yan.cui feature: user-api user-api-dev Monolithic Single-Purposed author: yan.cui feature: user-api user-api-dev-get-user author: yan.cui feature: user-api user-api-dev-create-user author: yan.cui feature: user-api user-api-dev-delete-user dynamodb:GetItem dynamodb:PutItem dynamodb:DeleteItem
  90. 90. @theburningmonk theburningmonk.com author: yan.cui feature: user-api user-api-dev Monolithic Single-Purposed author: yan.cui feature: user-api user-api-dev-get-user author: yan.cui feature: user-api user-api-dev-create-user author: yan.cui feature: user-api user-api-dev-delete-user dynamodb:GetItem dynamodb:PutItem dynamodb:DeleteItem no least privilege…
  91. 91. @theburningmonk theburningmonk.com author: yan.cui feature: user-api user-api-dev Monolithic Single-Purposed author: yan.cui feature: user-api user-api-dev-get-user author: yan.cui feature: user-api user-api-dev-create-user author: yan.cui feature: user-api user-api-dev-delete-user require(x) require(y) require(z)
  92. 92. @theburningmonk theburningmonk.com author: yan.cui feature: user-api user-api-dev Monolithic Single-Purposed author: yan.cui feature: user-api user-api-dev-get-user author: yan.cui feature: user-api user-api-dev-create-user author: yan.cui feature: user-api user-api-dev-delete-user require(x) require(y) require(z)
  93. 93. @theburningmonk theburningmonk.com
  94. 94. @theburningmonk theburningmonk.com more dependecies equals slower cold start
  95. 95. @theburningmonk theburningmonk.com author: yan.cui feature: user-api user-api-dev Monolithic Single-Purposed author: yan.cui feature: user-api user-api-dev-get-user author: yan.cui feature: user-api user-api-dev-create-user author: yan.cui feature: user-api user-api-dev-delete-user require(x) require(y) require(z) worse cold start performance
  96. 96. @theburningmonk theburningmonk.com keep functions simple, and single-purposed
  97. 97. Step 6. Migrate to new service
  98. 98. @theburningmonk theburningmonk.com Monolith DB Feature A Feature C Feature B Feature D Feature E Feature F Monolith
  99. 99. @theburningmonk theburningmonk.com Monolith DB Feature A Feature C Feature B Feature D Feature E Feature F Monolith
  100. 100. @theburningmonk theburningmonk.com Monolith DB Monolith Feature A Feature C Feature B Feature D Feature EFeature F Service DB
  101. 101. @theburningmonk theburningmonk.com Monolith DB Monolith Feature A Feature C Feature B Feature D Feature EFeature F Service DB
  102. 102. @theburningmonk theburningmonk.com Monolith DB Monolith Feature A Feature C Feature B Feature D Feature EFeature F Service DB requires challenging & risky coordinated update!
  103. 103. @theburningmonk theburningmonk.com Monolith DB Monolith Feature A Feature C Feature B Feature D Feature EFeature F Service
  104. 104. @theburningmonk theburningmonk.com Monolith DB Monolith Feature A Feature C Feature B Feature D Feature EFeature F Service migrate the least critical component first
  105. 105. @theburningmonk theburningmonk.com Monolith DB Monolith Feature A Feature C Feature B Feature D Feature EFeature F Service
  106. 106. @theburningmonk theburningmonk.com Monolith DB Monolith Feature A Feature C Feature B Feature D Feature EFeature F Service
  107. 107. @theburningmonk theburningmonk.com Monolith DB Monolith Feature A Feature C Feature B Feature D Feature EFeature F Service DB
  108. 108. @theburningmonk theburningmonk.com Monolith DB Monolith Feature A Feature C Feature B Feature D Feature EFeature F Service DB if your system can tolerate a small downtime, then do the data migration with a downtime!
  109. 109. @theburningmonk theburningmonk.com Monolith DB Monolith Feature A Feature C Feature B Feature D Feature EFeature F Service DB if not… consider this approach
  110. 110. @theburningmonk theburningmonk.com Monolith DB Monolith Feature A Feature C Feature B Feature D Feature EFeature F Service DB write read treat new DB as a read-through/ write-through cache
  111. 111. @theburningmonk theburningmonk.com Monolith DB Monolith Feature A Feature C Feature B Feature D Feature EFeature F Service DB write read migration also run one-off migration job in the background
  112. 112. @theburningmonk theburningmonk.com Monolith DB Monolith Feature A Feature C Feature B Feature D Feature EFeature F Service DB
  113. 113. context is king
  114. 114. start up
  115. 115. STABILITY
  116. 116. @theburningmonk theburningmonk.com maintain API compatibility (all versioning schema sucks…)
  117. 117. @theburningmonk theburningmonk.com prefer synchronizing data over synchronous API calls
  118. 118. @theburningmonk theburningmonk.com System A System B System C System D User User System EUser structural weakness
  119. 119. @theburningmonk theburningmonk.com System A System B System C System D User User System EUser cascade failures cascade failures cascade failures
  120. 120. @theburningmonk theburningmonk.com System C System DUser upsert
  121. 121. @theburningmonk theburningmonk.com be mindful of GDPR! avoid synchronousing PII data
  122. 122. Step 7. Rethink testing
  123. 123. @theburningmonk theburningmonk.com acceptance integration unit no. of tests in the monolith…
  124. 124. @theburningmonk theburningmonk.com most Lambda functions are simple and have a single purpose, the risk of shipping broken software has largely shifted to how they integrate with other services
  125. 125. @theburningmonk theburningmonk.com acceptance integration unit won’t catch many integration problems
  126. 126. Paul Johnston The serverless approach to testing is different and may actually be easier. http://bit.ly/2t5viwK
  127. 127. LambdaAPI Gateway DynamoDB
  128. 128. LambdaAPI Gateway DynamoDB Unit Tests
  129. 129. LambdaAPI Gateway DynamoDB Unit Tests Mock/Stub
  130. 130. is our request correct? is the request mapping set up correctly?is the API resources configured correctly? are we assuming the correct schema? LambdaAPI Gateway DynamoDB is Lambda proxy configured correctly? is IAM policy set up correctly? is the table created? what unit tests will not tell you…
  131. 131. @theburningmonk theburningmonk.com a passing test is not a guarantee that something works
  132. 132. @theburningmonk theburningmonk.com optimize for working software, not your feedback loop (feedback loop is an important ingredient, but not the goal!)
  133. 133. @theburningmonk theburningmonk.com avoid local simulation, they’re more work than is worth it, and hides common failure modes such as misconfigured permissions and resource policies pro tip #1
  134. 134. @theburningmonk theburningmonk.com prefer high-level functional tests pro tip #2
  135. 135. @theburningmonk theburningmonk.com integration tests exercise system’s Integration with its external dependencies my code
  136. 136. @theburningmonk theburningmonk.com acceptance tests exercise system End-to-End from the outside my code
  137. 137. @theburningmonk theburningmonk.com only use mocks for AWS services to simulate hard-to-create failure cases pro tip #3
  138. 138. @theburningmonk theburningmonk.com but always mock your own APIs during integration testing - they’re not as stable as AWS services and you know it! pro tip #4
  139. 139. @theburningmonk theburningmonk.com use temporary stacks to run e2e tests pro tip #5 https://theburningmonk.com/2019/09/why-you-should-use-temporary-stacks-when-you-do-serverless
  140. 140. @theburningmonk theburningmonk.com https://theburningmonk.com/2019/09/how-to-include-sns-and-kinesis-in-your-e2e-tests How to include SNS and Kinesis in your e2e tests
  141. 141. Step 8. Resilience as a service
  142. 142. @theburningmonk theburningmonk.com observability, observability, observability
  143. 143. @theburningmonk theburningmonk.com use queues to amortize traffic spikes between services
  144. 144. @theburningmonk theburningmonk.com use sagas to manage distributed transactions
  145. 145. @theburningmonk theburningmonk.com use circuit breakers to prevent cascade failures
  146. 146. @theburningmonk theburningmonk.com use bulkheads to isolate blast radius
  147. 147. @theburningmonk theburningmonk.com go multi-region, active-active
  148. 148. @theburningmonk theburningmonk.com #1 apply Reverse Conway’s Maneuver #2 identify service boundaries #3 organize your codebase #4 pick your tools #5 keep functions simple #6 migrate to new service (gracefully) #7 rethink testing #8 resilience as a service
  149. 149. https://theburningmonk.com/hire-me AdviseTraining Delivery “Fundamentally, Yan has improved our team by increasing our ability to derive value from AWS and Lambda in particular.” Nick Blair Tech Lead
  150. 150. Learn GraphQL and AppSync by building a Twitter clone with these technologies appsyncmasterclass.com
  151. 151. @theburningmonk theburningmonk.com github.com/theburningmonk

×