Thursday, July 12, 2012

Riak Java Client Distilled

In this blog, we will show how to use Riak Java client to,
  • Create/update objects
  • Enable and search by secondary index
  • Add links and walk links
  • Enable and search by free text through MapReduce

Riak Configuration

There are a few configuration changes that we will need to make to app.config to enable secondary index and listening for all ports,
  1. Change back end to use ELevelDB, the only storage engine that supports secondary index
  2. Change localhost or 127.0.0.1 to 0.0.0.0 for all IP addresses so Riak will listen on all ports
  3. Enable Riak for search by modifying app.config file
  4. {riak_search, [
                    %% To enable Search functionality set this 'true'.
                    {enabled, true}
                   ]}
    

Riak Java Client

All Riak server access is done through a Riak client.

Which Riak Client to Use
Riak Java library offers two types of Riak clients, which is very confusion. We found that most tasks can be accomplished using the pbc (low level protocol buffer client) client, except for the following exceptions that one must use the HPTT client,
  • Enable free text search for buckets
How to Obtain a Riak Client

 RiakClient riakClient = RiakFactory.pbcClient(host, port);  

Shutdown Riak Client in the End

One must shutdown all active risk client before shutting down the application/Tomcat server itself.
 riakClient.shutdown();  

Create, Update, and Lookup Object

Riak Client API offers a few annotations to indicate a particular field and we highly recommend use them rather than playing around the metadata ourselves,

  • The Riak Key field (through @RiakKey annotation)
  • A Riak secondary index field (through @RiakIndex annotation)
  • A Riak links collection field (through @RiakLinks annotation)
When we persist an annotated object through Riak client, Riak client will process the key, secondary indices, and links first before handling the object to Jackson for serializing into JSON string and storing the JSON string in Riak. If we choose to manage the object serialization/deserialization through Jackson ourselves, we must also handle the metadata changes like a new secondary index is added/removed or new links are added or removed. If not handled carefully, we could easily lose the existing secondary indices/links when an object is updated.

Here is an example highlighting the usage of above annotations,

 public class JsonObject  
 {  
   @JsonProperty  
   String bucket;  
   
   @RiakKey  
   String key;  
   
   @JsonProperty  
   String name;  
   
     
   @RiakLinks  
   @JsonIgnore  
   Collection<RiakLink> riakLinks = new ArrayList<RiakLink>();  
   
     
   @RiakIndex(name = "uri")  
   @JsonProperty  
   String uriIndex;  
   
  }  

To save/update an object,

 this.riakClient.createBucket(bucket).execute().store(object).execute();  
   

To lookup an object by key,
   
 @Override  
   public <T> T get(final String bucket, final String key, final Class<T> kclass)  
   {  
     try  
     {  
       return this.riakClient.fetchBucket(bucket).execute().fetch(key, kclass).execute();  
     }  
     catch (final RiakRetryFailedException e)  
     {  
       throw new RuntimeException(e);  
     }  
   }  

Secondary Index Creation and Retrieval
When an object's field has @RiakIndex annotated, secondary index is automatically created/updated when the object is stored or updated.

To look up an object based on secondary index,

 public List<String> fetchIndex(final String bucket, final String indexName, final String indexValue)  
   {  
     try  
     {  
   
       return this.riakClient.fetchBucket(bucket).execute().fetchIndex(BinIndex.named(indexName))  
           .withValue(indexValue).execute();  
     }  
     catch (final RiakException e)  
     {  
       throw new RuntimeException(e);  
     }  
   
     // Collection<String> collection = results.getResult(String.class);  
   }  

Riak Search
Riak search must be enabled at the bucket level before Riak will index properties on all objects in the bucket. To

 bin/search-cmd install my_bucket_name  
To execute a Riak search on a given bucket,
 @Override  
   public Collection<JsonObject> search(final String bucket, final String criteria)  
   {  
     try  
     {  
       final MapReduceResult mapReduceResult = this.riakClient.  
           mapReduce(bucket, criteria)  
           .addMapPhase(new NamedJSFunction("Riak.mapValuesJson")).execute();  
       return mapReduceResult.getResult(JsonObject.class);  
     }  
     catch (final Exception e)  
     {  
       throw new RuntimeException(e);  
     }  
   }  
Where parameter bucket is the bucket name and the criteria is the search criteria like "type=Folder" or "(type=Folder AND name=Hello)".

Riak Link Walking
Riak link walking apparently only with HTTP client, not the pbc client for some reason.

Here is a sample code to link walk a specific number of steps from the current object, identified by key.
  @Override  
   public List<List<String>> walk(  
                   final String bucket, // bucket name  
                   final String key,  // originating object key  
                   final String linkName,  // link name  
                   final int steps   // number of steps to walk. Riak will stop if it can't walk further  
                   )  
   {  
     final List<List<String>> walkResults = new ArrayList<List<String>>();  
   
     try  
     {  
       final LinkWalk linkWalk = this.riakHttpClient.walk(this.riakHttpClient.createBucket(bucket).execute().fetch(key)  
           .execute());  
   
       for (int i = 0; i < steps; i++)  
       {  
         linkWalk.addStep(bucket, linkName, true);  
       }  
       final WalkResult walkResult = linkWalk.execute();  
   
       final Iterator<Collection<IRiakObject>> it = walkResult.iterator();  
       while (it.hasNext())  
       {  
         final List<String> list = new ArrayList<String>();  
         final Collection<IRiakObject> collections = it.next();  
   
         for (final IRiakObject riakObject : collections)  
         {  
           list.add(riakObject.getKey());  
         }  
         if (list.size() > 0)  
         {  
           walkResults.add(list);  
         }  
       }  
     }  
     catch (final Exception e)  
     {  
       throw new RuntimeException(e);  
     }  
   
     return walkResults;  
   }  

Tuesday, July 10, 2012

Why We Chose Riak


In this blog, we will discuss why we chose Riak as one of the persistence storage engines for our next generation platform. In the next blog, we will show how to use Riak Java client library to create and update objects, creating new secondary index, links, and free text search.

Object Model
Just recap our dual object model, one for external interfacing RESTful Web Services and the internal persistence object model below.

We store only JSONWrapper objects in Riak, along with the appropriate relationships and links. We also need to search for objects based on their name, type, etc.

Why We Chose Riak

I have been playing around with Riak for the past month and came to the conclusion that Riak is a good  option for our next generation platform, for the following reasons;

Ever-Evolving Object Model
The highly adaptive nature of our object model is not a good fit for the traditional ORM on top of RDBMS, as the object model is highly customizable from customer and customer and may evolve from version to version. The transitional ORM would require RDBMS schema to continuously keep up with our ever-evolving object model, requiring enormous efforts on Engineering, Testing, and Operations.

The platform really does not care about the customized and highly evolved properties of object types. In other words, the platform only needs to know a pre-defined set of object properties for persistence and relationship resolution purpose and does not need to know all the other properties.

Riak, on the other hand, gives us the flexibility for storing opaque objects and we decide to store objects as JSON rather than Java objects or XML because JSON serialization is much more flexible and compact and needs far less storage than Java or XML.

High Availability and Multi-Data Center Support
Riak is built as a distributed data storage, with tunable read and write replica strategy.
Riak Enterprise offers multi-data center replication.

Free Text Search 
Riak comes with build-in free text search support, built on top of Lucene.

Adjacency Link Walking
Our object model relies on adjacent link between objects and it is critical to be able to follow the object graph through these adjacency links. Riak offers MapReduced based link walking functionality so we can easily retrieve all objects that are linked to a particular object through any levels of links.

Secondary Index Support
Like RDBMS, Riak offers secondary index support in addition to primary key lookup.

Multi-Tenant Support
Our platform must support multi-tenancy for security, partition and performance reasons, which is not trivial to accomplish in a RDBMS environment.

Riak, on the other hand, partitions data naturally in buckets and buckets are distributed across different nodes. Tenants can be mapped to buckets and data level security can be accomplished through securing access to buckets. If we store  a tenant related data in the same bucket, a user can only access the data if he has access to the bucket and he can't access any objects not belong to accessible buckets.

Ad Hoc Query Support Through MapReduce
Riak provides us the ability to run Ad Hoc queries through the entire data set, through a series Map and Reduce phases. The only limitation is that MapReduce is executed in memory and must complete with a timeout limit. This is not a major concern given the size of data set.

Performance
Riak is based on a distributed data model, which should perform better than master-slave type of model.

Operation and Monitoring Support
Riak ships with a UI monitoring tool and a set of commends for other administrative tasks like backup/restore, etc.

Concerns about Riak
We do have concerns regarding Riak from a business perspective. Even though Riak is an open source solution, its commercial backer Basho is still relatively young and the user community is not as big as Hadoop, Cassandra, or MongoDB.

To mitigate the risk, we built a persistence abstraction layer that allows us to swamp Riak with a different NoSQL technology in the future if necessary.




Monday, July 9, 2012

Building an Adaptive Object Model

In this series of blogs, we will discuss how we build our next generation platform using Jeresy, Jackson, JSON, and Riak. But first, we will show how to build an adaptive object model, supporting multiple versions of object types simultaneously.

Object Model Requirement

For our platform, we are storing various types of configuration objects, with parent/child relationship linking objects together. Each object type has a set of fixed pre-defined properties and a set of custom properties, which can vary from customer to customers.

Support Versioned Objects

As our platform evolves, our object model will need to adapt and evolve, which means we need to support and store different versions of same object type. Properties can be added or removed between different versions.

Building an Adaptive Object Model

After some exploring, we decided to go with two set of object models, an explicit object model for Web Services and a generic persistence object model.

Here is a picture of the two object models,

The generic object graph approach consists of two layers of abstraction, a wrapper object and an inner JSON object. The wrapper layer contains the following static information that does not change from one version to another, like,

  • Object name
  • Object key
  • Object type
  • Object uri
  • Object version
  • A relationship map
  • Parent id
and a map representation of the inner JSON object.

The inner JSON object is the JSON object created by the user or will be returned to the user. The inner JSON object can be different from version to version and from type to type. Since the platform does not need to know what is actually stored in the inner JSON object, other than a set of standard fields, like,
  • Object name
  • Object type
  • Object version
The platform just stores the wrapper object, with inner object as an opaque map. Since the wrapper object structure does not change based on version or type and the inner object is stored as a generic Map type, the platform does not need to change every time we add a new object type or change an existing object type.

Object Validation

However, we still need to validate user supplied JSON object to make sure that it matches the correct version of the object type. We accomplish this by creating a set of validating classes and register them by type and version. When we receiving an object creation request, we will first deserialize the input JSON to a raw Map type and pull out the type and version from the map object. Then we look up the validation class based on type and version and then deserialize the input JSON object again based on the validation class.

When a new type is introduced or new version of type is introduced, we just update the validation map with the new configuration and deploy the new classes and nothing else needs to be changed.

Sequence Diagram for Web Services

Create a New Object through Web Services.

Get an Object through Web Services.






Tuesday, June 19, 2012

First Impression on Riak vs mongoDB vs Cassandra/HBase

As part of the building out the next generation technology platform, we would like to explore NoSQL solutions to compliment our existing platform, which is built on RDBMS, primarily Oracle.

I have used mongoDB, Cassandra and HBase in the past life and I am eager to learn what Riak could offer as an alternative NoSQL solution.

In the next few weeks, I will be publishing our findings, lessons learned along the way. In this post, I will give my first un-biased impression on Riak vs other NoSQL technologies.

First Impression on Riak

Riak is an open source, distributed database solution, written in Erlang and supported by Basho. From first glimpse, it offers the following nice features,
  • Objects are stored by buckets and keys
  • Really nice HTTP API (for developing/debugging purpose)
  • Horizontal and linear scalability
  • Masterless replication with tunable read/write consistency level
  • Consist Key Hashing and even load distribution
  • Automatically rebalancing when new nodes are introduced or removed
  • Support Linkage between objects, a nature way to build hierarchy object model
  • Complex query support including secondary index, free text search, and MapReduce support
  • Excellent client library support
  • Thousands of name branded customers
From the first glance, Riak is very much like Cassandra with automatic cluster management, nicer API, and much less complexity in terms of cluster management and learning curve (no more Thrift API).

On the other other hand, Riak is a strict name/value pair model and does not offer column family or super column family support, as supported in Cassandra/HBase. I guess we can simulate column family support by turning bucket into row key, and keys into column family columns.

Overall, Riak looks like a good candidate for our prototyping and I will share our experience in the next  few blogs.

Performance Tuning Hibernate Transaction Flush Mode

I have been using Hibernate on and off for the post ten years and here are some tips and tools that I have used to help me identify, tune, and improve Hibernate performance.

Tip 1 Use a good JDBC Profiler

My personal favorite is Elvyx, which is easy to install, configure, and use. While Hibernate SQL log is useful, it is not easy to read and it won't show the actual parameters sent to the database. Elvyx, on the other hand, has a UI that will show both unbound (similar to Hibernate) and bound SQL, which shows the actual parameters in the SQL. Elvyx UI also allows us to do the following,
  • Sort the queries
  • Total time eclipsed summary graph
  • Drill down to a single query and how execution status
  • Export data into Excel and other formats

A JDBC profiler should be used as part of the development, QA process to catch potential performance issues and in production to help trouble shoot live performance issues.

In Development and QA

In development, JDBC profiler should be used to profile every Web Services call or every single page-turn for web applications, to identify the following potential performance issues,
  • Hibernate is generating the correct SQL (from HQL)
  • Hibernate is loading just right amount of data (use lazy loading whenever possible)
  • Hibernate is generating the correct amount of SQL calls. An abnormal amount of SQL calls per web service call or per web page turn indicates poor design and potential performance issue
  • Look for SQL that is taking long time to execute. Examine the explain plan and make sure the plan makes sense. If the generated sql does not meet requirement, consider rewriting the query or using native SQL or a function or a stored procedure for better performance

In Production

Since Elvyx is not intrusive and does not recompiling application or any other type of special treatment, it is ideal to trouble shoot live production performance issue. Simple deploy, configure, restart, and start troubleshooting.

Tip 2 Understand Transaction Flush Mode

Most people don't understand Hibernate Transaction Flush Mode and what is the most appropriate Flush mode to use. Wrong Transaction Flush mode will lead to huge performance issues.

What is Transaction Flush Mode

Hibernate does not flush every add or update transaction to the database. Rather Hibernate collects them and waits for the right time to flush them all t the database. And the right time is defined by the Transaction Flush mode. There are four Flush mode,

  • Always, the session is flushed every query
  • Commit, the session is flushed when transaction is committed
  • Manuel, the session is flushed manually, i.e., Hibernate will NOT flush session to the database during query or commit time
  • Auto, default Flush mode and yet the most confusion one. The session is flushed before a query is executed or transaction is committed

Why we need transaction Flush mode?

Database transaction is expensive and does not perform well so Hibernate turns auto commit off. Hibernate defers database transaction until the end when all necessary database updates have been made.

For example, in a transaction, we can do the following,
  1. Begin transaction
  2. Create employee A
  3. Create employee B
  4. Associate A with its manager C
  5. Associate B with its manager D
  6. Commit transaction
Instead of 4 separate transactions, we only need a single transaction. Very efficient.

Now, if we change the follow a little,
  1. Begin transaction
  2. Create employee A
  3. Create employee B
  4. Associate A with its manager C
  5. Look up all employees reporting to C
  6. Associate B with its manager D
  7. Look up all employees reporting to D
  8. Commit transaction
If we don't' call transaction flush before step 5 and step 7, we will get incorrect results, because the query results won't include the newly created employee A and B. If we want to include newly created results in the query results before committing them to the database, we must flush the pending transactions (creation of employee A and B) to the database before they can be included in a later query.

Hibernate default Flush mode, AUTO, is designed to be overly cautious and does a database flush every time before executing a query. It is designed to protect novice user but it does come with a hefty performance penalty.

What is the Performance Penalty associated with Database Transaction Flushing

Hibernate does not keep track of which object has been modified in session object. In order to do a proper transaction flush, it must first determine which object has changed in the session by going through ALL the objects in the session and comparing the current object with what's in the database one object at a one. This process is extremely CPU intensive and only gets worse if one has a lot of objects loaded in the session, which is typical in a bulk load/update type of transactions.

Default Flush Mode introduces Performance Problem during Bulk Operations

We had a page that creates a new campaign based on an existing campaign template via a deep copying . A campaign object could contain possibly hundreds of other objects. A typical flow is like the following,

  • Begin Transaction
  • Retrieve the template campaign
  • Shallow copy and save the top level campaign objects
  • For each top level campaign object 
    • Retrieve next level campaign objects
    • Shallow copy and save the secondary level campaign objects
  • Iterate through all nested objects
  • Commit Transaction
A typical copy operation takes 30 minutes. This clearly indicates a performance issue. After further investigation, we traced the problem back to hefty performance cost introduced by database transaction flush.

For each select statement like retrieving the next level campaign objects, Hibernate does a database flush and as the number of objects loaded in the session increases, the time to determine the "dirty" objects increases dramatically. And there is absolute NO need to do database flush, since we are NOT making any changes to existing objects, only creating new ones.

The solution is to switch the default flush mode to COMMIT. This cuts the execution time from 30 minutes to 3 seconds.

So next time if an operation takes abnormal long time to execute and it is not being held up by the database itself, check Hibernate transaction flush mode carefully. Typically I use either MANUEL or COMMIT for any type of bulk operations or read-only operations.

Tip 3 Use Batch Operations

As we have shown before, Hibernate carries huge performance penalty if we execute one query at a time, because of the overhead related to database transaction management. However, we can reduce this cost dramatically if we can batch a set of operations together and carry them out in a single transaction or a single query.
We had a page displaying a grid, which can be sorted or filtered by a set of criteria. The original implementation performs poorly because it is implemented like the following,
  • Select a set of user ids based on the selection criteria
  • Get each user for each returned user id
A must better performant implementation is like,
  • Select a set of user ids based on selection criteria
  • For every 300 user id
    • Select users where user id in (the set of 300 users)
The second implementation is typically 10 to 20 times faster than the first one.

Friday, June 15, 2012

How to Update Facebook Status on user's behalf

In the previous blog entry, "how to tweet on user's behalf", we talked about how to tweet on user's behalf through Twitter application. In this blog, we will discuss similar function on Facebook, i.e., how to update status on user's behalf. And necessary steps are very similar,

  1. Create a Facebook campaign specific application
  2. Obtain an access token for a particular Facebook account. This process does require user to log into his/her Facebook account and explicitly grant permission to the Facebook app, which will post on user's behalf. Once the access token is retrieved, we can post on the user's behalf through the app. Unlike Twitter, the access token currently does expire in 60 days, upon which we must go through the same process of obtaining a new access token. Not very user friendly in our opinion.

Setting up a Facebook Application

Step1. Go to https://developers.facebook.com/
Step2. Fill in necessary information,
App ID/App Key and App Secret will be used in obtaining access token.

Obtaining Access Token

Obtain an access token for a particular Facebook account. This process does require user to log into his/her Facebook account and explicitly grant permission to the Facebook app, which will post on user's behalf. Once the access token is retrieved, we can post on the user's behalf through the app. Unlike Twitter, the access token currently does expire in 60 days, upon which we must go through the same process of obtaining a new access token. Not very user friendly in our opinion.

Here is the high level flow for obtaining a Facebook access token,

Here is the detailed sequence diagrams on obtaining access token,
Once an access token is granted, we can start updating user's status as the following,

HTTP POST "https://graph.facebook.com/" + facebookUser + "/feed?access_token=" + token + "&message=" + URLEncoder.encode(message, "utf-8");

How to Tweet on user's behalf

As part of multichannel campaign, we would like to tweet on customer's behalf. In order to accomplish that, we need the following,

  • Create a Twitter application, which will tweet on customer's behalf. The application should also contain the appropriate campaign information and URL
  • Obtain an access token for a particular Twitter handle or handles. This process does require user to log into his/her Twitter accounts and explicitly grant permission to the Twitter app, which will tweet on user's behalf. Once the access token is retrieved, we can tweet on the user's behalf through the app. The access token currently does not expire, except for in the situation where user changes his password or revokes the access permission explicitly
In the blog, we walk through the necessary steps on how to obtain an access token.

Setting up a Twitter Application

Step1: Log into https://dev.twitter.com/apps/new
Step2: Filling the necessary information for the App, including the appropriate information for the Campaign,
Consumer Key, Consumer secret, and Callback URL will be used in obtaining access token.

Obtaining Twitter Access Token

Obtaining Twitter access token does require user to log into his/her Twitter accounts and explicitly grant permission to the Twitter app, which will tweet on user's behalf. Once the access token is retrieved, we can tweet on the user's behalf through the app. The access token currently does not expire, except for in the situation where user changes his password or revokes the access permission explicitly.

Here is a high level interaction diagram on this process,

Here is the corresponding sequence diagram,

Once an access token and associated token secret are obtained, we can store them in a persistent storage
and tweet on behalf of the user.
Twitter native Web Services API is very hard to use and we highly recommend going with Twitter4j.