Sunday, May 24, 2015

Redis on CentOS vs Azure Redis (install/config + perf test using Jedis java client)

Redis on CentoOS :-
1.      pre-req (yum install make gcc wget)
2.      Download a stable redis tar file from http://download.redis.io/releases/
3.      tar –xvf <the file, downloaded via wget/curl from #1>, make, make test, make install :- yum install <package>
4.      ensure that file limits are adequate. Adjust the parameters from the below files.
a.      /etc/security/limits.conf (optional)
b.      /etc/sysctl.conf
                                                    i.     sysctl vm.overcommit_memory=1 (or else redis-server will warn you on startup)
                                                   ii.     sysctl -w fs.file-max=100000
                                                  iii.     the above changes will last only for the session, for the permanent change, edit the file
5.      Add redis-server to chkconfig
a.       move the executables from the directory where the make install was run to /etc/init.d
6.      Or in lieu of 1 through 4 above steps use yum install redis (you need to have the correct EPEL; http://dl.fedoraproject.org/pub/epel/, select based on the architecture, etc.)
7.      Assign a password in redis.conf
8.      Start redis either through service start redis or redis-server (inside redis-stable/src in the same directory where the make install was fired.
9.      Ensure that redis is running
a.      ps –ef  | grep redis
b.      netstat –nap | grep redis (ensure that 6379 which is the default port or any port if you have changed the port in the redis.conf) (as root/privileged user)
c.      ss -nlp|grep redis (as root/privileged user)
d.      redis-cli ping
e.      connect redis-cli (try commands http://redis.io/commands)

Redis on Azure :-
Create a service. I used 2.5G capacity. Collect the key (password), check off the SSL (in production you shouldn’t but I did deliberately because the test on my localhost was conducted not over SSL, thus removed the additional overhead of encrypt/decrypt), port.

Test using Java :-
1.      pre-requisite:
a.      java
b.      maven (optional)
c.      eclipse (optional) or any ide
2.      Approach :
a.      using maven or
b.      download jar file and create a Java class file in your favorite editor and use CLI (javac and java)
3.      Pick a client from redios.io. (I used Jedis)
4.      Insure that Jedis java client library is compatible with the Jedis server
5.      Maven artifact for jedis (http://mvnrepository.com/artifact/redis.clients/jedis/)
6.      Test via a java program.
                        Jedis jedis = new Jedis("localhost", 6379);
                        jedis.auth("password");
                        jedis.set("myid", "my id's value");
                        System.out.println("Output:" + jedis.get("myid"));
                        jedis.close();

A (quick and dirty) performance test :-
You should use distributed multi machine test launch pad. Ensure that the client (test) machines have sufficient RAM, appropriate bandwidth, no other substantial programs running on them, etc. Ensure that the redis-server is optimized with sufficient memory, less latency IOPs (persistence SSDs, SAN, NAS (not preferred over SAN), etc.)…you get the point…there are so many variables that can help improve the performance.
The test program executes sequentially write to the cache.

Java client code for the test:
            static String value = "qwertyuiopasdfghjkl;zxcvbnm,./qwertyuiopasdfghjkl;zxcvbnm,./qwertyuiopasdfghjkl;zxcvbnm,./qwertyuiopasdfghjkl;zxcvbnm,./qwertyuiopasdfghjkl;zxcvbnm,./qwertyuiopasdfghjkl;zxcvbnm,./qwertyuiopasdfghjkl;zxcvbnm,./qwertyuiopasdfghjkl;zxcvbnm,./qwertyuiopasdfghjkl;zxcvbnm,./qwertyuiopasdfghjkl;zxcvbnm,./qwertyuiopasdfghjkl;zxcvbnm,./qwertyuiopasdfghjkl;zxcvbnm,./qwertyuiopasdfghjkl;zxcvbnm,./qwertyuiopasdfghjkl;zxcvbnm,./qwertyuiopasdfghjkl;zxcvbnm,./qwertyuiopasdfghjkl;zxcvbnm,./qwertyuiopasdfghjkl;zxcvbnm,./qwertyuiopasdfghjkl;zxcvbnm,./qwertyuiopasdfghjkl;zxcvbnm,./qwertyuiopasdfghjkl;zxcvbnm,./qwertyuiopasdfghjkl;zxcvbnm,./qwertyuiopasdfghjkl;zxcvbnm,./qwertyuiopasdfghjkl;zxcvbnm,./qwertyuiopasdfghjkl;zxcvbnm,./qwertyuiopasdfghjkl;zxcvbnm,./qwertyuiopasdfghjkl;zxcvbnm,./qwertyuiopasdfghjkl;zxcvbnm,./qwertyuiopasdfghjkl;zxcvbnm,./qwertyuiopasdfghjkl;zxcvbnm,./qwertyuiopasdfghjkl;zxcvbnm,./qwertyuiopasdfghjkl;zxcvbnm,./qwertyuiopasdfghjkl;zxcvbnm,./qwertyuiopasdfghjkl;zxcvbnm,./qwertyuiopasdfghjkl;zxcvbnm,./124"; //1K

        long outerbound = 10000;
        String host = "localhost";
        int port = 6379;
        String password = null;

        if (args.length >= 1) {
                outerbound = Long.parseLong(args[0]);
        }
        if (args.length >= 2) {
                host = args[1];
        }
        if (args.length >= 3) {
                port = Integer.parseInt(args[2]);
        }
        if (args.length >= 4) {
                password = args[3];
        }

        System.out.println("total sets:" + outerbound + ",host:" + host + ",port:" + port + ",password:"+password);

//      JedisPool pool = new JedisPool(new JedisPoolConfig(), "localhost", 6379, Protocol.DEFAULT_TIMEOUT, "password");
        Jedis jedis = new Jedis(host, port);
        if (password != null) {
                jedis.auth(password);
        }
        long i = 0;
        long startTime = System.currentTimeMillis();
        try {
//              Jedis jedis = pool.getResource();
                for (i=0; i < outerbound; i++) {
                        jedis.set(""+i, value);
                }
        } catch (Exception e) {
                e.printStackTrace();
                long stopTime = System.currentTimeMillis();
                long elapsedTime = stopTime - startTime;
                System.out.println("error at: " + i + ", time taken: " + elapsedTime);
                throw e;
        } finally {
//              pool.destroy();
                jedis.close();
        }
        long stopTime = System.currentTimeMillis();
        long elapsedTime = stopTime - startTime;
        System.out.println("out: " + elapsedTime);

Troublshoot:
·        make MALLOC=libc  (or yum install jemalloc-devel)
[zmalloc.h:50:31: error: jemalloc/jemalloc.h: No such file or directory
zmalloc.h:55:2: error: #error "Newer version of jemalloc required"]
·        update-alternatives --display java | grep 1.8 (find the proper version of Java to use)
Test in a VM in Azure:
VM: A1. (hence no SSDs or premium storage; for production load you might want premium storage for the redis database persistence file.)
Cmd: starttime=`echo $(($(date +%s%N)/1000000))`;/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.45-28.b13.el6_6.x86_64/jre/bin/java -cp .:jedis-2.7.2.jar App 100 localhost;finishtime=`echo $(($(date +%s%N)/1000000))`; echo 'starttime:' $starttime, 'endtime:' $endtime; diff=`expr $starttime - $endtime`; echo 'diff:' $diff
·        Name of the java program.
·        Number of 1024 char messages to be written to the cache.
·        Redis server host
·        %s :- seconds since 1970-01-01 00:00:00 UTC, %N :- nano seconds
Stats:
Redis running in A1:
Num of 1K messages
Execution time from within jvm in milli
Comment
Execution time including creation & destruction of jvm in milli
100
146

953846
1000
311

981507
10000
1697

995653
100000
9959

1008997
1000000
51536 (error) 513714 after successive writes
redis.clients.jedis.exceptions.JedisConnectionException: java.net.SocketTimeoutException: Read timed out
[Because A1 reached its IOPs limit. For production use Premium storage (DS series at the moment)]
1901596

Redis on Azure C2 (2.5GB): Client run from an A1 standard VM. Please note of the VM n/w bandwidth (though MSFT doesn’t publish the n/w bandwidth in/out…but higher the VM the better n/w i/o.)

Num of 1K messages
Execution time from within jvm in milli
Comment
Execution time including creation & destruction of jvm in milli
100
97

7293642
1000
667

6873256
10000
6407

7242799
100000
57571

7340372
1000000
575820

7443979
10000000
1033785 (error), after successive 1828914 writes
redis.clients.jedis.exceptions.JedisDataException: OOM command not allowed when used memory > 'maxmemory'.
[Ran out of memory on Azure Redis]
8124634

Monday, May 11, 2015

Azure API Management – a quick start (create a test WS in requestb.in, setup Azure API management, and test using SOAP UI/Azure API management developer portal)



1.      Sign up for Azure.
2.      Create an API Management Service

a.      First Screen:
                                                    i.     Give a service name (the UI has validation that makes this name unique across all Azure).
                                                   ii.     Select  a subscription
                                                  iii.     Select a region
b.      Second screen:
                                                    i.     Provide an org name
                                                   ii.     Provide an email id (appears as “from” in email communication)
c.      Third screen (optional):
                                                    i.     Select the pricing tier (developer/standard/premium)
3.      Browse (developer view) and Manage (publisher view) functionalities can be launched from the bottom of the api service webpage

4.      Create a test webservice (if you don’t have one J)


a.      You might use requestb.in
b.      Collect the request url
5.      Select Manage (where? Mentioned above)
6.      Create a product


Enter “Title”, “Description”, uncheck “Require subscription”….(we are only testing…)
7.      Create an API to the test webservice


Enter “Web API name”, “web service url” (the one collected from above requestb.in), “Web api url suffix”, and products (with the one created above)
8.      Create an “Operation” for the newly created API

9.      Test API: Launch “Browse” (for developer portal)
10.   Go to Product or API from the menu bar.  

11.   Select the newly created Product followed by the API or API directly.
Products:

API:

12.   Select the operation

13.   Select “Tryit” and then Submit the request
14.   Validate the response


15.   Check requestb.in for the request/response

16.   Test the exposed API through SOAP UI

17.   Check the Analytics in publisher portal

Check Activity, etc.