Ayende @ Rahien

My name is Oren Eini
Founder of Hibernating Rhinos LTD and RavenDB.
You can reach me by phone or email:


+972 52-548-6969

, @ Q c

Posts: 6,128 | Comments: 45,550

filter by tags archive

RavenDB & HTTP Caching

time to read 4 min | 766 words

The RavenDB’s Client API uses the session / unit of work model internally. That means that this code will only go to the database once:


And that all three calls will return the same instance as well. This is just the identity map at work, and with NHibernate, it is also called the first level cache or the session level cache.

Having implemented that, a natural progression was to ask what about the second level cache. NHibernate’s second level cache is complicated (it takes an hour just to explain how exactly it works, and that is when skipping on all the actual implementation details).

For a while, my response was that we don’t actually need that, RavenDB is fast enough that we don’t need caching. Except that I forgot about the Fallacies of Distributed Computing, the first three rules of which state:

  • The network is reliable.
  • Latency is zero.
  • Bandwidth is infinite.

Most specifically, caching can help with the third rule, since when you are querying potentially large documents (or over a large set of documents), you are going to spend most of your time just on the network, sending bytes to and fro.

It is to avoid that that we actually need caching.

I was slightly depressed that I actually had to implement the same complicated logic as NHibernate for caching, so I dawdled in implementing this. And suddenly it dawned on me that as usual, I was being stupid.

RavenDB is REST based. One of the important parts of REST is that:

As on the World Wide Web, clients are able to cache responses. Responses must therefore, implicitly or explicitly, define themselves as cacheable or not to prevent clients reusing stale or inappropriate data in response to further requests. Well-managed caching partially or completely eliminates some client–server interactions, further improving scalability and performance.

RavenDB is an HTTP server, in the end. Why not use HTTP caching?

That required some thought, I’ll admit. It couldn’t be that simple, right?

HTTP Caching is a somewhat complex topic, if you think it is not, talk to me after reading this 24 pages document describing it. But in essence, I am actually using only a small bit of it.

Whenever RavenDB sends a response to a GET request (the only thing that can be safely cached), it adds an ETag header. The ETag header stands for Entity Tag, and it changes every time that the resource is changed.

RavenDB already generated ETags for documents and attachments, those are part of how we implement optimistic concurrency. But since we already had those, we could now move to the next stage, and that was to have the client remember the responses for all the GET requests and when a new request for a Url that we already GET before, it will generate a If-None-Match header for the request.

RavenDB then checks whatever the ETag that the client holds matches the ETag on the server, and if so, will generate a 304 Not Modified response. That instruct the client that it can use the cached response safely.

In order to fully implement caching on the client, that was all we had to do. On the server side, we had to modify a few endpoints to properly generate an ETag and 304 if the client sent us the current If-None-Match value. With RavenDB, this is handled very deep in the guts of the client api, directly on top of the HTTP layer. It is always on by default and it should drastically reduce the amount of data across the network when the data hasn’t been modified.

Please note that unlike NHibernate’s second level cache, we don’t need a distributed cache to ensure consistency. Each node has its own local cache, but all of them will always get valid results, thanks to RavenDB’s ETag checks. In fact, the biggest challenge was actually involved in figuring out how to cheaply generate a valid ETag without performing the actual work for the request Smile.


Jason Meckley

So, http (2nd level) cache is on by default, just update the client and server binaries? That is frictionless :)

Brian Vallelunga

This is really great, but I have an implementation question. Where is the client cache stored? Is it in the DocumentSession object, DocumentStore, or somewhere else?

I ask because in a web application the DocumentSession will likely be created and destroyed per request, making the cache not too useful, unless it's a static property of the session that sticks around.

Ayende Rahien

This is stored in AppDomain level, it is a static property


Can cache size be somehow limited?

El Jobso

Yep Oren, welcome to The Internet ;-) , a place that is essentially a Representational Resource State Transporation System.

All you need (well, 99.9%) is already there!

Ayende Rahien


Internally this is a MemoryCache with the name:


You can configure this any way you want.


ha, I was at a .NET user group session by Glenn Block about the next WCF api for http endpoint where he explain exactly that.

Wouldn't it be possible to use it? It is available on codeplex I think.

Cassio Tavares

Ayende, are you using any third party API to implement REST and JSON serialization?

Like stephane said, Glenn Block is ahead of a project to support REST over WCF. There is OpenRasta too but I would like to hear more opinions.

I know that WCF REST doesn't support ETag yet but will in future. Probably OpenRasta already support it.

Ayende Rahien


Can you send me a link to this?

Ayende Rahien


no, just standard http call from .NET

Cassio Tavares

Glenn is working on this project


His blog - http://codebetter.com/glennblock/

But I'm pretty sure ETag is not implemented

It is in preview version and lacks docs, but is open source. You can digest it in one morning. :)

Ayende Rahien


I have a working version, one that supports ETags and caching and everything.

It is not a burden to maintain, so I think I'll not use it.

Ayende Rahien


Take a look at how this implemented in RavenDB:


Maybe 20 lines of code, and it works. No configuration, no need to understand an extensibility mechanism.


Ayende I was simply responding to the question of ETags. I wasn't necessarily saying you should take a dependency on it.


Just as a side note, the code for the processors is going to get much cleaner / less verbose.

Ayende Rahien


Am I mistaken, or is the code you posted the server code?


Yes that is just an illustration of the server side of generating ETags.

Comment preview

Comments have been closed on this topic.


  1. The worker pattern - 18 hours from now

There are posts all the way to May 30, 2016


  1. The design of RavenDB 4.0 (14):
    26 May 2016 - The client side
  2. RavenDB 3.5 whirl wind tour (14):
    25 May 2016 - Got anything to declare, ya smuggler?
  3. Tasks for the new comer (2):
    15 Apr 2016 - Quartz.NET with RavenDB
  4. Code through the looking glass (5):
    18 Mar 2016 - And a linear search to rule them
  5. Find the bug (8):
    29 Feb 2016 - When you can't rely on your own identity
View all series


Main feed Feed Stats
Comments feed   Comments Feed Stats