Building a modern SaaS in 2020

Building a modern SaaS in 2020

Building a modern Software as a Service platform brings a lot of interesting engineering challenges. During this talk, I’m going to share my team’s journey of building a SaaS from scratch in 2020. First, we are going to start with the technologies and the architecture we picked. Then, we’ll go over the interesting challenge of implementing multitenancy. And we'll see how we benchmarked three different options and picked one. And last but not least, we’ll explore how every startup can use open source technologies to build observability infrastructure. And how to run their SaaS in production.

Eb44761e0fb3a5ec8e23ec28048dd7a5?s=128

Nikolay Stoitsev

November 07, 2020
Tweet

Transcript

  1. Building a modern SaaS in 2020 Nikolay Stoitsev, Engineering Manager

    @ Halo DX
  2. None
  3. None
  4. None
  5. Language Architecture Repo Structure Builds Running in Production Observability Multitenancy

  6. Language Architecture Repo Structure Builds Running in Production Observability Multitenancy

  7. Language evaluation Python JavaScript/Node.js Java C#/.NET Core

  8. Domain Specifics FIPS 140-2

  9. Node.js Can build with special OpenSSL

  10. Java Package with verified implementation of cryptographic algorithms

  11. None
  12. None
  13. DICOM

  14. Imaging Center

  15. Imaging Center Hospital

  16. HL7 Imaging Center Hospital

  17. HL7 DICOM

  18. Java and Spring Boot

  19. Angular

  20. Language Architecture Repo Structure Builds Running in Production Observability Multitenancy

  21. Microservices Discovery

  22. Microservices Discovery Load Balancing

  23. Microservices Discovery Load Balancing Circuit Breaking

  24. Microservices Discovery Load Balancing Circuit Breaking Testing

  25. Microservices Discovery Load Balancing Circuit Breaking Testing Debugging

  26. Monolith

  27. Failure Isolation

  28. 6 services

  29. Hexagonal Architecture Web Adapter Messaging Adapter Input Port Input Port

    Biz Logic Output Port Output Port Persistence Adapter Messaging
  30. Language Architecture Repo Structure Builds Running in Production Observability Multitenancy

  31. Multi Repo vs Mono Repo

  32. Mono Repo Easily introduce and refactor global features Ease code

    sharing and reuse Simple dependency management Flexible team boundaries and code ownership Collaboration across teams Atomic commits across services
  33. Build System Bazel • Fast and incremental builds • One

    tool to build multiple languages • Extensible • Google, Pinterest, Uber, Stripe Buck • Fast and incremental builds • One tool to build multiple languages • Helps you better understand your dependencies • Facebook, Airbnb
  34. Multi-Project Builds in Gradle

  35. Multi-Project Builds in Gradle • One root project • One

    subproject for each service • One subproject for shared libs • https://docs.gradle.org/current/userguide/multi_project_builds.html
  36. Multi-Project Builds in Gradle

  37. Nx for front-end monorepo https://github.com/nrwl/nx

  38. Gradle wrapper for front-end builds and running tests

  39. Language Architecture Repo Structure Builds Running in Production Observability Multitenancy

  40. Separate Dockerfile for each service

  41. Can have one Docker Compose for everything

  42. Nexus https://www.sonatype.com/nexus/repository-oss

  43. Why Nexus? Can store and distribute Maven/Java, npm, Helm, Docker

    Widely adopted Single source of truth for every component Easy to work with
  44. Build Process CI Code

  45. Build Process CI CD Code

  46. Build Process CI CD Build Docker Image Code

  47. Build Process CI CD Nexus Build Docker Image Code Docker

    Image
  48. Language Architecture Repo Structure Builds Running in Production Observability Multitenancy

  49. Kubernetes https://kubernetes.io

  50. Why Kubernetes? Deployment Scaling Self-healing Inter-service communication Storage orchestration Scalable

    and battle tested
  51. Great for engineers • Each service is accessed via a

    single domain • Logs are easy to read • A lot of materials on how to learn it
  52. https://github.com/rancher/rancher

  53. Monitoring and Grafana out of the box

  54. Configuring a service in Kubernetes • Deployment • Service •

    Config Map • Service Account • RBAC • Pod disruption budget • ....
  55. Helm https://github.com/helm/helm

  56. Helm • Abstraction over k8s that simplifies working with it

    • The building block in helm is called a helm chart • Help you define, install, and upgrade applications in k8s
  57. How to work with Helm • Search for “{technology} helm

    chart” • Download helm chart • Update values.yaml • $ helm install {release-name} {chart-name} --set {var}={val}
  58. Deploy Process CI CD Nexus Build Docker Image Docker Image

  59. Deploy Process CI CD Nexus Kubernetes Kubernetes Kubernetes

  60. Deploy Process CI CD Nexus Helm Update Kubernetes Kubernetes Kubernetes

  61. Deploy Process CI CD Nexus Helm Update Kubernetes Kubernetes Kubernetes

    Pull Image
  62. Language Architecture Repo Structure Builds Running in Production Observability Multitenancy

  63. SLF4J backed by Log4j2 https://github.com/qos-ch/slf4j

  64. Backend logging EFK - Elasticsearch, Fluentd, Kibana Pod Pod Pod

  65. Backend logging EFK - Elasticsearch, Fluentd, Kibana Pod Pod Pod

    Fluentd Fluentd Fluentd
  66. Backend logging EFK - Elasticsearch, Fluentd, Kibana Pod Pod Pod

    Fluentd Fluentd Fluentd Elasticsearch
  67. Backend logging EFK - Elasticsearch, Fluentd, Kibana Pod Pod Pod

    Fluentd Fluentd Fluentd Elasticsearch Kibana
  68. Front-end logging

  69. Front End Logging Library

  70. Front End Logging Library

  71. Front End Logging front end lib front end lib

  72. Front End Logging Backend Service Backend Service front end lib

    front end lib
  73. Front End Logging Backend Service Backend Service Fluentd Fluentd front

    end lib front end lib
  74. Front End Logging Backend Service Backend Service Fluentd Fluentd Elasticsearch

    Kibana front end lib front end lib
  75. Language Architecture Repo Structure Builds Running in Production Observability Multitenancy

  76. Subtenancy Org East West Sales Front Desk Sales Front Desk

  77. Materialized path (1) Org (2) East (3) West (4) Sales

    (5) Front Desk (6) Sales (7) Front Desk ID Path Name 1 1/ Org 2 1/2/ East 3 1/3/ West 4 1/2/4 Sales East 5 1/2/5 Front Desk East 6 1/3/6 Sales West 7 1/3/7 Front Desk West
  78. Closure table (1) Org (2) East (3) West (4) Sales

    (5) Front Desk (6) Sales (7) Front Desk ID Name 1 Org 2 East 3 West 4 Sales East 5 Front Desk East 6 Sales West 7 Front Desk West Ancestor Descendant 1 2 1 3 1 4 1 5 1 6 1 7 2 4 2 5 3 6 3 7 4 Null
  79. Keeping hierarchy and data separated (1) Org (2) East (3)

    West (4) Sales (5) Front Desk (6) Sales (7) Front Desk • Each records get a tag - 1, 2, 3, etc. • Each tag points to a node in the tree • Tag hierarchy is loaded separately • Queries are decorated with OR statements to match by tag
  80. Benchmark

  81. Benchmark

  82. Language Java and Spring Boot

  83. Language Architecture Java and Spring Boot Microservices

  84. Language Architecture Repo Structure Java and Spring Boot Microservices Monorepo

  85. Language Architecture Repo Structure Builds Java and Spring Boot Microservices

    Monorepo Gradle and Docker
  86. Language Architecture Repo Structure Builds Running in Production Java and

    Spring Boot Microservices Monorepo Gradle and Docker Kubernetes
  87. Language Architecture Repo Structure Builds Running in Production Observability Java

    and Spring Boot Microservices Monorepo Gradle and Docker Kubernetes EFK stack
  88. Language Architecture Repo Structure Builds Running in Production Observability Multitenancy

    Java and Spring Boot Microservices Monorepo Gradle and Docker Kubernetes EFK stack Separate hierarchy and data
  89. Thank you! Q&A Nikolay Stoitsev Engineering Manager at Halo DX