state out of reach of the microservices
and provide older versions of the state
that are accessible in a scalable cache.
Sometimes, this leads to read-through
requests by the scalable cache to durable state that is not directly address-able to the calling microservice.
This is now becoming a tried and
true pattern. Figure 1 is taken from a
2007 paper by DeCandia et al. on Amazon’s Dynamo. 2 While the nomenclature is slightly different, it shows three
tiers of microservices accessing a back-end tier of different stores.
Durable state and session state.
Durable state is stuff that gets remembered across requests and persists
across failures. This may be captured
as database data, file-system files,
key values, and more. Durable state
is updated in a number of different
ways, largely dependent on the kind
of store holding it. It may be changed
by single updates to a key value or
file, or it may be changed by a transaction or distributed transaction
implemented by a database or other
store.
Session state is the stuff that gets remembered across requests in a session
but not across failures. Session state
exists within the endpoints associated
with the session. Multioperation transactions use a form of session state. 7
Session state is hard to do when the
session is smeared across service instances. If different microservices in
the pool process subsequent messages
in the transaction, session state is challenging to implement. It’s difficult to retain session state at the instance when
the next message to the pool may land
at a different service instance.
Data on the outside versus data on
the inside. The 2005 paper “Data on
the Outside Versus Data on the Inside” 5
speaks about the fundamental differences between data kept in a locked
transactional store (for example, a relational database) and data kept in other
representations.
Data on the inside refers to locked
transactionally updated data. It lives
in one place (for example, a database)
and at one time, the transactional
point in time.
Data on the outside is unlocked
and immutable, although it may be
versioned with a sequence of versions
that are in their own right immutable.
Outside data always has some form of
a unique identifier such as a URI (
uniform resource identifier) or a key. The
identifier may be implicit within a session or an environment. Outside data
typically is manifest as a message, file,
or key-value pair.
The Evolution of Durable
State Semantics
Storage systems and databases have
evolved through the decades and so
have the semantics of updating their
state. This section begins in the bad old
days when I first started building systems. Back in the 1970s and 1980s, disk
storage had to be carefully updated to
avoid trashing disk blocks. From there,
we move forward to atomic record updates and the challenges that arose before transactions. When transactions
came along a lot of things got a lot
easier—if you were making a change at
one place and one time. Adding cross-database and cross-time behavior led
to the same challenges you had with
more primitive storage systems. This
was helped by using messaging subsystems to glue stuff together.
Then, an interesting development
in storage occurred. Some stores are
fast but sometimes return stale values.
Others always return the latest value
but occasionally stall when one of the
servers is slow. This section shows how
predictable answers result in unpredictable latencies. 10 Finally, it examines the role immutable data can play
in supporting very large systems with
predictable answers and response
times for some business functions.
Careful replacement of disk
blocks. It used to be, back in the 1970s
and 1980s, that a disk write might
leave data unreadable. The write went
through a number of state changes
from the old V1 version, to unreadable
garbage, to the new V2 version. When
the disk head was writing a block, the
magnetic representation of the bits in
the block would be turned to mush on
the way to being updated to the new
version. A power failure would cause
you to lose the old value (see Figure 2).
When implementing a reliable application, it’s essential that you do not
lose the old value of the data. For example, if you’re implementing the trans-
Figure 1. Example of Amazon’s Dynamo microservice architecture.
Client Requests
Request Routing
Request Routing
Amazon
S3
Dynamo Instances
...
Other Datastores
Services
Aggregator
Services
Page
Rendering
Components