Performance Zone is brought to you in partnership with:

Yuexiang has posted 2 posts at DZone. View Full User Profile

Fast Clojure/Java Web Apps on Nginx Without Any Java Web Server

01.17.2014
| 10891 views |
  • submit to reddit

Nginx-Clojure  is a Nginx module for embedding Clojure or Java programs, typically those Ring based handlers. It is an opensource project hosted on Github, the site url is HERE. With it we can develope high performance Clojure/Java web apps on Nginx without any Java web server and with several benefits:

  • Clojure/Java controlled static files will get almost the same performance with Nginx static file service.
  • We just deploy one Nginx (compiled with Nginx-Clojure module) server instead of Nginx + some Java web server, eg. Tomcat, Jetty etc.
  • Ring Handler  is dead easy compared to Java Servlet
  • We can use Nginx modules such as GZip, Image Filter etc. with our static and dynamic content on the fly without any cost of Proxy level.
There are three typical examples for writing a configuration about Ring handlers :

1. Pure Java Handler

package my;

import nginx.clojure.Constants;
import clojure.lang.AFn;
import clojure.lang.IPersistentMap;
import clojure.lang.PersistentArrayMap;

public class HelloHandler extends AFn {

	@Override
	public Object invoke(Object r) {
		IPersistentMap req = (IPersistentMap) r;

		// get some info from req. eg. req.valAt(Constants.QUERY_STRING)
		// ....

		// prepare resps, more details about Ring handler on this site
		// https://github.com/ring-clojure/ring/blob/master/SPEC
		Object[] resps = new Object[] {
				Constants.STATUS,
				200,
				Constants.HEADERS,
				new PersistentArrayMap(new Object[] {
						Constants.CONTENT_TYPE.getName(), "text/plain" }),
				Constants.BODY, "Hello Java & Nginx!" };
		return new PersistentArrayMap(resps);
	}

}

In nginx.conf, eg.

location /java {
  clojure;
  clojure_code '
  (do (import \'[my HelloHandler]) (HelloHandler.) )
  ';
 }


2. Inline Clojure Handler

       location /clojure {
          clojure;
          clojure_code ' 
                        (fn[req]
                          {
                            :status 200,
                            :headers {"content-type" "text/plain"},
                            :body  "Hello Clojure & Nginx!" 
                            })
          ';
       }



3. External Clojure Handler

(ns my.hello)
(defn hello-world [request]
  {:status 200
  :headers {"Content-Type" "text/plain"}
  :body "Hello World"})


You should set your clojure JAR files to class path, see JVM path & class path in Nginx-Clojure README.

       location /myClojure {
          clojure;
          clojure_code ' 
          (do
               (use \'[my.hello])
                 hello-world))
          ';
       }


For more details and more useful examples for Compojure which is a small routing library for Ring that allows web applications to be composed of small, independent parts, please refer to https://github.com/weavejester/compojure

By the way the result of simple performance test with Nginx-Clojure is inspiring, more details can be got HERE  . Here 's the simple testing results , Nginx-Clojure is almost 6 times faster than Nginx-Php5


Published at DZone with permission of its author, Yuexiang Zhang.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

Yuexiang Zhang replied on Tue, 2014/08/05 - 8:44pm

From nginx-clojure v0.2.4, we can use new derective handler_type and handler_name for easier work.

e.g.

Inline handler

    handler_type 'clojure'; # or handler_type 'groovy'
    handler_code '....'; 

External handler

handler_type 'clojure'; # or handler_type 'java' / handler_type 'groovy'
handler_name 'my.test/InitHandler';  # or for java it maybe 'my.test.MyJavaInitHandler'


Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.