Synchronous Reads, Asynchronous Writes refers to an architectural approach where data reads are performed synchronously through services, while data writes are performed asynchronously through a messaging system. This allows for decoupling of services, horizontal scaling of reads and writes, and loose coupling between systems. The key aspects are performing JSON RESTful reads through services like Sinatra, and pushing writes to a messaging system like RabbitMQ with routing keys to trigger downstream processing. This approach can help solve issues with monolithic Rails applications that do not scale effectively.
8. Data Reads Through
Well it means creating systems that
perform data reads through services.
data reads typically have to be
synchronous because a user is waiting on
Services
the operation. So they have to occur
inside the request/response life-cycle.
9. data writes through a
messaging or queuing
system
Often, a user doesnāt have to wait for
data to be written to receive a
response. So writes can be done
asynchronously outside of the request/
response life-cycle which mean you can
put them straight into a queue
14. Monolithic Applications
Also, having your entire application in one code
base and system doesnāt scale. This leads to
test suites that take more than 30 minutes to
Donāt Scale
run, deploys that push your entire application
just for a simple update.
24. Service Oriented Architecture
service oriented
architecture, but thatās
commonly associated with
things like SOAP, WSDL, and
a bunch of other heinous
things.
37. For your message format you should use
JSON. I know you can use XML, but...
JSON
38. XML is too
bloated and
XML Makes Children Cry
complex and
besides, it makes
children cry
39. I previously glossed over this picture. Itās
something called an asynchronous electric
motor, which is the only image I could conjure
Asynchronous
up to go with the term āasynchronousā
Writes
40. requires a
Messaging System
messaging
system to write
data through
41. For that I suggest
RabbitMQ , which is a
RabbitMQ
powerful messaging
system in addition to
having stuff as mundane
as a queue
42. And youāll of course need a data
Data Store
store. I donāt care which you
use, but it should probably be
designed to solve the problem
for a particular piece of your
application.
51. Joel Spolsky calls people
that exhibit this behavior
āArchitecture Astronautsā
āSometimes smart thinkers just don't know when to stop, and they create
these absurd, all-encompassing, high-level pictures of the universe that
are all good and ļ¬ne, but don't actually mean anything at all.
These are the people I call Architecture Astronauts. It's very hard to get
them to write code or design programs, because they won't stop thinking
about Architecture.ā
58. and then you add
some background
processing...
and then you realize that you canāt do
everything inside the request/response
cycle so you add in a background process.
For now weāll assume youāre using a
database backed queue like dj, bj, or some
other kind of ājā.
59. and then
you add
memcache...
but wait, then you realize
you need additional
performance so you add
memcache
60. server, duh!
and letās not
forget that itās
all fronted by
nginx or apache
61. and then you need more app
processing power so you add
t wo more ser vers and front
all that by ha proxy
62. so once youāve done
all that, where do
Where to from here?
you go?
63. maybe you add redis because
you heard Ezra or Chris or
somebody say itās awesome
and scales to inļ¬nity
64. and then you add
a read database
to eek out a
little more
performance
65. and the whole time your Rails
application code base is
growing with more logic and
additional background
processing
74. millions of RSS and
Atom feeds
Since weāre pre-launch we
deļ¬nitely donāt have the too
many users problem. The trafļ¬c
and complexity comes from
having to update millions of rss
and atom feeds
75. data from external
sources
Pulling in real time
engagement from
multiple external
sources
76. complex business logic
and complex business logic. every
time something enters our system
we have to perform many different
tasks that are interdependent.
Hereās just a taste of it: our feed
fetcher pulls in a new blog post from
somewhere
90. originally we set up
a ser vices based
design that looked
kind of like this. as
you can see there
are a bunch of
interconnections
and itās hard to
comprehend.
troubleshooting
failures was hard.
91. Each ser vice had to implement
HTTP + JSON
an http interface with json
formatted messages. This was
the only method for ser vice-
to-ser vice communication.
99. keep the HTTP
http services
for data reads,
which can be
cached and
Services for data reads
optimized
100. push writes through a
messaging system
data writes through a messaging
system with built in routing. It
also helps if itās optimized for
processing thousands of messages
per second and supports the
pubsub style
103. require 'rubygems'
require 'sinatra'
get '/entries/:id' do
Entry.find(params[:id]).to_json
end
now sinatra is awesome
because it makes creating a
service this easy.
112. first_request.on_complete do |response|
post = Post.new(JSON.parse(response.body))
# get the first url in the post
third_request =
Typhoeus::Request.new(post.links.first)
third_request.on_complete do |response|
# do something with that
end
hydra.queue third_request
post
end
115. 20.times do
r = Typhoeus::Request.new(
"http://localhost:3000/users/1")
hydra.queue r
end
hydra.run
116. hydra.cache_setter do |request|
@cache.set(
request.cache_key,
request.response,
request.cache_timeout) if
request.cache_timeout
end
hydra.cache_getter do |request|
@cache.get(request.cache_key)
end
128. these features enable you to build
an event based system, which is
Event Based System
exactly what we needed. when
certain updates happen, it should
kick off calculations elsewhere in
the system. Iāll get into that in a bit,
but ļ¬rst some rabbit speciļ¬cs
129. rabbit is an implementation
of an open protocol called
Advanced Message
Queueing Protocol or AMQP
AMQP
131. it has Exchanges and
it has a bunch of
features, but for the
purposes of
Asynchronous Writes,
Routing Keys too
exchanges and routing
keys are what we care
about most
138. So we have a fanout exchange called
entry.write. every queue bound to this
exchange will get messages published to it.
Here we have the three things we want to do.
First, index it for searching. Second, store it in
our key valuer store. Third, index in a
completely separate index used for data
research. So the search is Solr/lucene and the
research is Hadoop. Completely decoupled
systems.
139. Thatās how we write entries. Hereās
how we do event based processing on
those writes. so hereās an example
where we have a topic exchange
named āentry.notifyā. queues can be
bound to exchanges. so we have these
three queues
140. so take the example where
you have a message published
to the exchange with a
routing key of āinsertā.
141. the message would get
routed to the queue
bound with insert and
to the queue bound with
hash
142. now letās look at a message
with a routing key of
āupdate.clicks.rankā
143. based on the bindings, the
message gets dropped into the
update and hash queue (ones
on the right err left?)
156. http://localhost:3000/locks/names/
pauldix
one way is to have the
ser vice responsible
expose a uniqueness
getter. so once you GET
a lock, you write
through the queue.
159. Eric Brewerās CAP
theorem
in brewerās CAP theorem he talked
about the relationship bet ween three
requirements when building
distributed systems. consistency,
availability, and partition tolerance.
162. partition tolerance
when you replicate data across multiple
systems, you create the possibility of forming
a partition. this happens when one or more
systems lose connectivity to other systems.
partition tolerance is deļ¬ned formally as āno
set of failures less than total net work failure
is allowed to cause the system to respond
incorrectlyā
164. Werner Vogelsā
eventual consistency
āis a special form of weak
consistency. if no new updates are
made to an object, eventually all
accesses will return the last
updated value.ā