hybris page fragment caching with NGINX and memcached
Today’s post is a follow-up to the previous articles about caching.
I managed to integrate hybris with Nginx (as a reverse proxy) and memcached (as a storage for the cache). The key distinctive feature of this solution is that Nginx works with Memcached directly.
You can find all three solutions below. See the explanations of first two approaches in the previous articles on my blog (Page fragment caching and Varnish caching).
Why nginx?
Nginx is a high performance web/proxy server that powers the most busiest and heavy traffic websites in the world: Airbnb, Discovery Education, Dropbox, MaxCDN, Netflix, TED, WordPress.com, Zynga and much more. It includes caching features for both static and dynamic content, also can be setup as proxy for such backend platforms as hybris. There are two points explaining why I chose Nginx:- Unlike Varnish, It is capable to work with NoSQL directly
- Unlike Varnish, Nginx supports SSL by default.
- Nginx is a native web server, while Varnish is just a proxy cache layer.
- Along with your webservers, you will possibly have too many caching layers
Why memcached?
Basically because it is an only NoSQL database supported by Nginx. However, there are another strong point as well: Memcached is originally intended for caching. As for drawbacks.- Memcached is a memory storage. It is not persistent.
- Memcached is a key-value store while the MongoDB is a document store.
Hybris modifications
Architecture
The overall architecture is the same as explained in the previous article. The only differences are:- memcached instead of MongoDB
- SSI includes (NGINX) instead of ESI includes (Varnish)
- No /cache/get?key=XXX handler, because NGINX is capable to work with Memcached directly
Memcached client library
There is a number of libraries for Java to support memcached. I chose the Java client from Greg Whalin (https://github.com/gwhalin/Memcached-Java-Client/wiki).SSI includes
I simply replace the format of include tags: Varnish+MongoDB version (the previous solution):<ESI:include src="/cache/get?key=XXXX"/>NGINX+memcached version (this solution):
<--# include file="/cache/get?key=XXXX"/>Basically, for the NGINX configuration, I used you can use anything before “?” sign in the path: it will be ignored. The solution doesn’t imply fetching page fragments separately from the hybris side.
Hybris Memcached Service
There are the same methods as I used for the MongoDB hybris service.public interface ICacheService { public void connect() throws UnknownHostException; public Map<String, String> getMap(String key); public String get(String key); public String put(String key, String value, Map<String, String> attributes); }
public class MemcachedService implements ICacheService { ... }
Unlike MongoDB, memcached is a simple key-value storage, so I needed to create more than one key in put (key, value, attributes): put("a","b", { "attr1" -> "value1", "attr2" -> "value2" }) will put the following key-value pairs in the memcached storage: a->b a*attr1 -> a*value1 a*attr2 -> a*value2
NGINX configuration
In my environment, the hybris uses port #9001 and nginx uses port #39001.server { listen 39001; ssi on; location / { ssi on; set $memcached_key "===="; if ($arg_key != "") { set $memcached_key "$arg_key"; memcached_pass localhost:11211; } error_page 404 502 504 = @fallback; } location @fallback { proxy_pass http://localhost:9001; } }
Challenges
Building NGINX for Windows
NGINX for Windows comes with a limited set of modules. The required modules such as ngx_http_ssi_module and ngx_http_ssi_module are not included into the executable available for download. In order to build nginx with these modules, you need to build it from the sources. There are two ways on how to do it: use Visual C or Cygwin. I chose the second option, so follow in my footsteps- download Cygwin, nginx sources.
- install Cygwin and the modules required for C (automake, make, gcc etc)
- configure & make. Possibly you will have some problems with gzip module like I had. I took it out from the configuration (–without-http_gzip_module)
Controller page caching
In the Varnish+MongoDB solution, I used caching for the controller pages. In this solution, I decided not to cache these pages at all. The first reason is avoiding repetitions: you can implement this caching in a similar way explained earlier. The second reason is that this type of caching would add an unnecessary layer of complexity to the system. The controller pages set the cookies (session) and these cookies might be used by the components. If you use the cached version of the page, but the session is over, the page won’t be displayed properly. These complexities are common for any type of caching. So I decided to omit this part to avoid creating false illusions of simplicity.© Rauf Aliev, July 2016