Architecting for Reliability

Eliminating Hidden Failure Modes


Barry S. Stahl

Principal Engineer - AZNerds.net

@bsstahl@cognitiveinheritance.com

https://CognitiveInheritance.com

Transparent Half Width Image 800x800.png

Favorite Physicists & Mathematicians

Favorite Physicists

  1. Harold "Hal" Stahl
  2. Carl Sagan
  3. Richard Feynman
  4. Marie Curie
  5. Nikola Tesla
  6. Albert Einstein
  7. Neil deGrasse Tyson
  8. Niels Bohr
  9. Galileo Galilei
  10. Michael Faraday

Other notables: Stephen Hawking, Edwin Hubble, Leonard Susskind, Christiaan Huygens

Favorite Mathematicians

  1. Ada Lovelace
  2. Alan Turing
  3. Tim Berners-Lee
  4. Isaac Newton
  5. Emmy Noether
  6. Johannes Kepler
  7. René Descartes
  8. George Boole
  9. Carl Friedrich Gauss
  10. Grace Hopper

Other notables: Blaise Pascal, Daphne Koller, Grady Booch, Evelyn Berezin, Pascal Van Hentenryck

Fediverse Supporter

Logos.png

Some OSS Projects I Run

  1. Liquid Victor : Media tracking and aggregation [used to assemble this presentation]
  2. Prehensile Pony-Tail : A static site generator built in c#
  3. TestHelperExtensions : A set of extension methods helpful when building unit tests
  4. Conference Scheduler : A conference schedule optimizer
  5. IntentBot : A microservices framework for creating conversational bots on top of Bot Framework
  6. LiquidNun : Library of abstractions and implementations for loosely-coupled applications
  7. Toastmasters Agenda : A c# library and website for generating agenda's for Toastmasters meetings
  8. ProtoBuf Data Mapper : A c# library for mapping and transforming ProtoBuf messages

http://GiveCamp.org

GiveCamp.png

Achievement Unlocked

bss-100-achievement-unlocked-1024x250.png

Simple Example

  • Two Actions that Result in Changes

    • A - Send an eMail Message
    • B - Write the results to a DB
TwoActions-800x800.png
  The Process - High Level.png
  Simplest Case - Code Snippet.png Simplest Case - System States - Placeholder.png
  Simplest Case - Code Snippet.png Simplest Case - System States.png
  Commit After Send - Code Snippet.png Simplest Case - System States - Placeholder.png
  Commit After Send - Code Snippet.png Commit After Send - System States.png

Retry at the Client

Avoiding Dual-Writes - The Problem - Table - With Dependency - No Legend.png

Two At-A-Time

Is is NOT possible to reliably make more than one change to system state in a single execution context

Two changes can be made to system state in a single execution context if:

  • The 1st change is idempotent
  • The 2nd change is unreliable
Two Things at Once 800x800.jpg

Idempotence

[ īdemˈpōt(ə)nce , ˈēdemˌpōt(ə)nce ]

The ability to execute a task an arbitrary number of times (>1) and have the resulting state of the system be the same as if the task was executed once.

OnOff_600x400.jpg

What is a Dual-Write?

An attempt to make more than 1 reliable change to the state of a system in a single invocation

  • Reliable = Can reasonably be expected to occur ONCE*
    • Irrespective of:
      • Reliability of the environment
      • Reliability of any dependencies
  • Change = An ATOMIC modification
    • Database or Cache Update
    • Message Delivery
  • Invocation = Automated Response to a Signal
    • User Action
    • Message Received

Particularly Pernicious

  • Errors resulting from dual-writes can manifest in different ways
    • Duplicate Data or Actions
      • Duplicate Emails
      • Duplicate Billing
    • Missing Data or Actions
      • No email sent
      • No billing issued
    • Incomplete Data
      • Email sent but no record of it
  • Supporting these systems can be a nightmare
    • Difficult to identify when errors occur
    • Difficult to remediate
    • Extremely difficult to replicate

Avoiding Dual-Writes

Keep It Separate, Keep It Safe

  • Isolation Patterns
    • Transactional Outbox
    • Change-Data-Capture
    • Data Streaming
  • Coordination Patterns
    • Saga Orchestration
    • Saga Choreography
SafeSeparation-800x800.png

Isolation Patterns

Reliable Data Flow.png

Transactional Outbox

Goal: Reliably update a Data Store and trigger an additional action

  • A single atomic write that makes two updates
    • A change to the state stored in the DB
    • A command to execute a secondary process

Transactional Outbox Sequence

Outbox-Sequence-800px.png

Outbox Pattern

  • Advantages

    • Persist quickly
    • Captures every update
    • Uses familiar tech
  • Disadvantages

    • Hard to scale
    • Harder to fanout than other patterns
    • Uses DB as a queue
    • Adds weight to the persistance (trx)
    • Still susceptible to errors on commit

Change-Data-Capture

Goal: Reliably update a Data Store and trigger an additional action

  • A single atomic write that makes one update to the DB
  • The DB log is used to trigger the secondary action

CDC Sequence

CDC-Sequence-800px.png

Cosmos CDC

  • Advantages

    • Persist quickly
    • Easy to scale
    • Easy to fanout
  • Disadvantages

    • Not guaranteed to capture every update
    • Still susceptible to errors on commit

Data Streaming

Goal: Reliably persist a message and trigger additional actions

  • A single atomic write that makes one update to the message stream
  • The stream is used to trigger all actions

Streaming Data Sequence

Streaming-Sequence-800px.png

Data Streaming

  • Advantages

    • Persist quickly
    • Easy to scale
    • Easy to fanout
    • Captures every update
  • Disadvantages

    • Reliability is subject to persistance of the implementation
    • Still susceptible to errors on commit
StreamingInMotion-800x800.png

These Patterns are Similar

  • Persist the data first - then act on it
  • CDC & streaming are easy to fan out to N tasks
  • Outbox & streaming can provide strong guarantees
  • Most are still susceptible to errors on commit

  • These patterns can get very close to 4-9's
  • Use Idempotence whenever possible
  • Exactly-once delivery may be possible
ConvergencePoint-800x800.png

Avoiding Commit Errors

  • These patterns get very close to 4-9's
  • Use Idempotence whenever possible
  • Exactly-Once Delivery may be possible
    • Idempotent ingress (i.e. to Kafka)
    • Atomic updates of changes alongside queue offsets

The Saga Pattern

Goal: Trigger an orchestration or Choreography to perform multiple actions reliably

  • Orchestration - A single controller (orchestrator)
    • Responsible for triggering all actions
    • Including reversing transactions when needed
  • Choreography - Each service does one thing
    • Based on upstream events it receives
    • Then publishes results
    • Other services are responsible for responding to its events
Saga-Pattern-800x800.png

Saga Orchestration

Avoiding Dual-Writes - Saga Orchestration  1024x693 - White Background.png

My Ideal Architecture

Avoiding Dual-Writes - Ideal Architecture - 1080x364.png

Most Important Takeaway

Never "add on" inside an execution context

Summary

  • It is impossible to reliable take 2 actions in a single context
  • Best practice: Persist immediately, then take other actions
  • Use Outbox, CDC or Streaming to keep operations separate
  • Prefer CDC or Streaming for best fanout and scalability
  • Consider Sagas to orchestrate or choreograph complex interactions reliably
  • Never "add on"
TwoActions-800x800.png

Resources

QR_ArchitectingForReliability_800x800.png

Appendix A - Uptime Metrics

  • 3-9's (unimportant)

    • 99.9% uptime
    • 1 outage second in 1000
    • ~ 43 min / month
  • 4-9's (important)

    • 99.99% uptime
    • 1 outage second in 10,000
    • ~ 4.3 min / month
  • 5-9's (critical)

    • 99.999% uptime
    • 1 outage second in 100,000
    • ~ 0.43 min (26 sec) / month

Appendix B - Delivery Guarantees

  • At-Least Once

    • Every messages will be delivered 1+ times
    • The vast majority of message systems make this guarantee
  • At-Most once

    • Every message will be delivered 0-1 times
    • i.e. Logging
  • Exactly once

    • Every message will be delivered 1 and only 1 time
    • Very difficult and expensive
    • Limited usefulness while maintaining this guarantee
    • Combination of idempotent input and a downstream transaction