Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Server side caching of dynamic content with Nginx and Etags

I have a CouchDB DB, with an Nginx reverse proxy in front of it. Some responses from CouchDB take a long time to generate (yes, it was a bad choice, but need to stick with it for now), and I would like to cache them with Nginx. (Currently Nginx only does SSL.)

CouchDB supports Etags, so ideally what I would like is Nginx caching the Etags as well for dumb clients. The clients do not use Etags, they would just query Nginx, which goes to CouchDB with its cached Etag, and then either sends back the cached response, or the new one to the client.

My understanding based on the docs is that Nginx cannot do this currently. Have I missed something? Is there an alternative that supports this setup? Or the only solution is to invalidate the Nginx cache by hand?

like image 871
Gabor Csardi Avatar asked Feb 25 '15 16:02

Gabor Csardi


1 Answers

I am assuming that you already looked at varnish and did not find it suitable for your case. There are two ways you can achieve what you want.

With nginx

Nginx has a default caching mechanism that you can configure for your use.

If that does not help, you should give Nginx compiled with the 3rd party Ngx_Lua module a try. This is also conveniently packaged along with other useful modules and the required Lua environment as Openresty.

With Ngx_Lua, you can use the shared dictionary to cache your couchdb responses. As the name suggests shared dictionary uses a shared memory zone in Ngx_Lua's execution environment. This is similar to the way the proxy_cache works in Nginx(which also defines a shared memory zone in Nginx's execution environment) but comes with the added advantage that you can program it.

The steps required to build a couchdb cache are pretty simple (with this approach you don't need to send etags to the client)

  1. You make a request to couchdb
  2. You save the {Url-Etag:response} pair
  3. Next time the request comes to the same url query for etags using a HEAD request.
  4. If response etag matches the {Url-Etag:response} pair then send the cached response otherwise query couchdb again using (get/post) methods and update the {Url-Etag:response} pair before sending the response to the client.

Of course if you program a cache by hand you will have to define max cache size and a mechanism to remove old items from the cache. The lua_shared_dict directive can help you define a memory size for which the responses will be cached. When saving the values in the shared dictionary you can specify the time for which the value will remain the memory zone after which it will automatically expire. Combining the max cache size parameter and cache time parameter of the shared dictionary you should be able to program fairly complex caching mechanism for your users.

With erlang

Since couchdb is written in erlang you already have an erlang env on your machine. So if you can program in it you can create a very robust distributed cache with mnesia. The steps are the same. Erlang timers can be combined with gen_* behaviours to give you the automatic expiry of items and mnesia has functions to monitor it's memory usage and notify you about it. The two approaches are almost equivalent the only difference being that mnesia can be distributed.

Update

As @abyz suggested redis is also good choice when it comes to caching.

like image 106
Akshat Jiwan Sharma Avatar answered Sep 20 '22 02:09

Akshat Jiwan Sharma