Redis vs MySQL vs Tokyo Tyrant (on EC2)

April 27, 2009

Update (28th April 2009) – Added Tokyo Tyrant

What is Redis?

Briefly, Redis is a key-value store that stores the values to disk periodically instead of after every set.

What is Tokyo Tyrant?

Tokyo Tyrant is similar to Redis – a key-value store.

Aim

This is a brief comparison of the performance of Redis and MySQL. It is not very thorough and is only to be used as an indication as to whether Redis may be worth your further investigation.

After a brief search I failed to find any performance comparisons of Redis and MySQL to determine if it was even worth my time looking at Redis. I appreciate they are very different beasts but in our database we have a lot of data that would fit very nicely into a key-value store.

So, the question I am trying to answer is “roughly how much performance can we gain from using Redis for storing simple data instead of MySQL?”. Then it is up to you to look at all the differences and decide whether it is worth pursuing a switch to Redis.

Note: I will be looking at other key-value stores in the near future 🙂

The Test

The two tests performed are:

  • Using 2 threads: set X items with the keys/values being consecutive numbers
  • Using 2 threads: randomly get these items Y times

Setup

  1. EC2 small instance.
  2. Default install of MySQL with a single InnoDB table for storing keys and values.
  3. Default make of Redis.
  4. Small Java benchmark programs sitting on the same box

Source Code

The numbers in these files are not the exact numbers I used (apart from using two client threads in both tests)

  1. Redis benchmark: http://pastebin.com/f5adb41b0
  2. MySQL benchmark: http://pastebin.com/m52fd35d1

Results

Mysql

3,030 sets/second.

4,670 gets/second.

Redis (In-memory only)

11,200 sets/second. (3.7x MySQL)

9,840 gets/second. (2.1x MySQL)

Tokyo Tyrant (Writing to disk)

9,030 sets/second. (3.0x MySQL)

9,250 gets/second. (2.0x MySQL)

Thoughts

Key-value stores are generally going to be faster than MySQL. They (generally) provide less functionality in the way of querying arbitrary columns and ACID compliance. This translates into faster performance on gets/sets.

Once again, it is worth pointing out that this is a very simple benchmark. My suspicion is that when you have lots of cross updates going on then Redis/Tyrant will have a greater performance boost over MySQL – but at the cost of transactionality.

My suspicion is that as the technology matures we are going to start seeing a big shift towards using key-value stores as the first port of call for data storage for websites. I expect it won’t be long before we start seeing hosts offering LAKP (Linux, Apache, a key-value store, PHP) as well as the more traditional LAMP offerings.

I would love to hear from anyone with real world experience and numbers of switching over to Redis… until I have some of my own to share anyway 🙂

Advertisements

C3P0: Tried to check-in a foreign resource!

March 25, 2009

Earlier today I encountered the following stack trace whilst using C3P0 and Hibernate:

com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool - An Exception occurred while trying to check a PooledConection into a ResourcePool.
com.mchange.v2.resourcepool.ResourcePoolException: ResourcePool [BROKEN!]: Tried to check-in a foreign resource!
	at com.mchange.v2.resourcepool.BasicResourcePool.checkinResource(BasicResourcePool.java:657)
	at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool$ConnectionEventListenerImpl.doCheckinResource(C3P0PooledConnectionPool.java:636)
	at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool$ConnectionEventListenerImpl.connectionClosed(C3P0PooledConnectionPool.java:630)
	at com.mchange.v2.c3p0.util.ConnectionEventSupport.fireConnectionClosed(ConnectionEventSupport.java:55)
	at com.mchange.v2.c3p0.impl.NewPooledConnection.fireConnectionClosed(NewPooledConnection.java:510)
	at com.mchange.v2.c3p0.impl.NewPooledConnection.markClosedProxyConnection(NewPooledConnection.java:381)
	at com.mchange.v2.c3p0.impl.NewProxyConnection.close(NewProxyConnection.java:1246)
	at org.hibernate.connection.C3P0ConnectionProvider.closeConnection(C3P0ConnectionProvider.java:92)
	at org.hibernate.jdbc.ConnectionManager.closeConnection(ConnectionManager.java:474)
	at org.hibernate.jdbc.ConnectionManager.aggressiveRelease(ConnectionManager.java:429)
	at org.hibernate.jdbc.ConnectionManager.afterTransaction(ConnectionManager.java:316)
	at org.hibernate.jdbc.JDBCContext.afterNontransactionalQuery(JDBCContext.java:268)
	at org.hibernate.impl.SessionImpl.afterOperation(SessionImpl.java:444)
	at org.hibernate.impl.SessionImpl.list(SessionImpl.java:1153)
	at org.hibernate.impl.QueryImpl.list(QueryImpl.java:102)

Apologies for the scroll bars… but hopefully this is indexed neatly by Google to help others!

After a bit of investigation it turned out this was due to a multi-threading issue and the solution can be summarised quite neatly:

never shut down Hibernate before all threads have finished what they’re doing (if they are using Hibernate)

Otherwise, you may get the above exception (or an equally unhelpful exception).


How I Test and Tweak CSS for Cross-Browser Compatibility

March 11, 2009

Motivation

Why bother supporting more than one browser? For anyone wanting to hit a large proportion of the population then supporting Firefox 2, Firefox 3, Internet Explorer 6 and Internet Explorer 7 are necessary to satisfy 89% of the market (browser stats). It may also be desirable to support Chrome and Safari to get to 96%.

That is a lot of platforms – all with their own behaviours and interpretations of specifications. I’ll ignore arguments about upgrading browsers / converging on one/two browsers as that is a big topic that is regularly argued about the world over.

So, here is how I cope with the joy of cross-browser compatibility

Testing

Before we can fix something we need to know it is broken. The approach I take is to try out the web site on all the browsers I want the site to work on – unfortunately, it’s not that simple to have all possible browsers on one machine.

Firefox 3 and Internet Explorer 7

These two are easy – I have them installed all the time on my development machine. They co-exist quite peacefully and give me no grief.

Firefox 2

Firefox 2 can be completely standalone as a portable app. Stick it in a folder and run it, at the same time as FF3. Here’s how

Internet Explorer 6

Rumour has it that you can install Internet Explorer 6 as a standalone application. I’ve had no luck with this approach. My approach is to use a virtual PC. Microsoft have kindly made Virtual PC 2007 available for free here. They also provide images for the common setups here.

Safari

This is available from Apple as a download for the PC, here.

Tweaking for Compatibility

So, we’ve now identified a problem with our site in one of the browsers. Searching the internet will usually reveal the necessary tweak for that browser. There are also countless tricks out there for making our CSS only appear to a particular browser. Such as:


/* Hide from IE-Mac \*/
#header {margin-bottom:3em}
#footer {margin-top:1.5em}
/* End hide */

I generally don’t like these approaches as they obfuscate our CSS to some extent, this then leads to mistakes. So, what do I prefer?

Browser specific CSS in browser specific files. For any of my sites my stylesheets will generally look like:

  • default.css – included by all browsers for the core style
  • ie6.css – included only by Internet Explorer 6
  • ie7.css – included only by Internet Explorer 7
  • ff2.css – included only by Firefox 2
  • Firefox 3 is omitted as I develop in Firefox 3 so that all stays in default.css

The important thing here is that the browser specific files are included after the default. This allows me to specify that a div shouldn’t be a float but instead should use relative positioning or whatever specific tweak is needed.

I feel that this yields much clearer CSS than the hack approach and is hence more maintainable. This also allows us to completely overhaul a design for a particular browser if it is giving us substantial grief. The disadvantages to this approach are that it increases the number of files to maintain.

My personal view is that I would rather have 4 clear and easy to maintain files rather than 1 hard to maintain file.

Implementing this is fairly easy in most systems. In PHP we can use $_SERVER[‘HTTP_USER_AGENT’] to get to it. We can even use Javascript / AJAX to do this.

But, isn’t this unreliable? Couldn’t a user fake this? (Or, a firewall). Sure. However, we’re trying to be pragmatic here – we can’t get a complex page to work 100% reliably on all browsers without doing CSS tricks so we have to do something that is maintainable.

If we keep as much as possible in the core stylesheet then the user shouldn’t have a terrible experience if their browser is mis-reported and so we shouldn’t be losing too many visitors to bad browser detection. We can even go one step further and ensure that the core style sheet gives a good (not perfect) view of the page in every browser without additional tweaking… then layer the tweaks on top!

Disclaimer

In the above I have outlined a method that may or may not be appropriate for your situation. If you have a little site with one page, a simple layout but it doesn’t work in all browsers then you’re probably better off using hacks. If you have a big site with lots of pages and a complex layout then you may want to consider layering your stylesheets.

As with all software development – use your brain. Read around. Make the decisions that are right for your project – never use a fork to eat soup.


Widgets in PHP – Eliminating Copy and Pasting

March 8, 2009

Recently I have been doing a lot of work on tidying up the front-end of our PHP app. One thing that struck me is the amount of re-use of code for various widgets – and not the good sort.

Our example – A customer quote

Throughout our app it is common to see copying and pasting being used to acheive certain looks and effects. As an example, if we want to display a quote from one of our customers we could use something like:

<div class="Quote">
  <div class='StartQuote'></div>
  <span>
    Awesome. Simply awesome.
  </span>
  <div class='EndQuote'></div>
</div>

With the appropriate styles this creates something looking like:

sample quotes image

I know that this trivial example can be done entirely in CSS – but we all encounter things that can’t be done entirely in CSS and cross-browser compatible.

What’s wrong with this?

You may now be asking yourself this question. We want our quotes to all look the same so we get it right once then being copying and pasting – what is wrong with that? Well:

  • If we want the look to change we’ve got to change it everywhere
  • We’re prone to making mistakes when copying and pasting
  • It’s quite a lot of effort and mess for something that should be simple

An Alternative – Widgets

What we really want to do is: say what we want at a higher level, e.g.

  <quote>
    Awesome. Simply awesome.
  </quote>

Then have this snippet be replaced with the correct HTML. I call this a ‘widget’ based approach – we now have quote widgets everywhere instead of chunks of HTML.

Nice goal – how do we get there?

One word (ish): post-processing. PHP has a little known set of functions called ob_start and ob_end_flush. These can be used to send all your output to a callback function:

ob_start(post_process);
// Lots of HTML / Widget code
ob_end_flush();

The post_process function takes a single string argument, the contents of the page, and returns a string, the post processed content – the content with the widgets replaced by the correct HTML.

Thoughts for the Future

I like this approach. I like being able to write my pages at the level that I’m thinking: quote here, panel there, calendar here… however, there isn’t yet a system that makes writing these new widgets easy – yet. Watch this space 🙂


AJDT and Ant

February 27, 2009

I’ve just had one of those mornings where you spend hours trying to crack a problem and just getting nowhere.

The problem was getting AspectJ to work under Ant but only by using the AJDT 1.6.3 Eclipse plugin.

Unfortunately, this is very poorly documented. Fortunately, this helps you make the right decision: don’t use AspectJ in Ant by relying on AJDT.

There is a very good reason for this (beyond it being hard to get working): you cannot rely on AJDT being available when compiling in anything other than Eclipse (e.g. from a CI server).

What’s the alternative? Download AspectJ and use these libraries directly in Ant – they’re well documented and just work.


Bug in Annotation Processing (Java 6 Update 12 / Eclipse)

February 26, 2009

Just uncovered a fun bug in one of the Java Compiler / Eclipse (haven’t checked to see which one is behaving exactly correctly).

If you are working Eclipse then the Eclipse compiler believes the following snippet of code is OK:

@org.hibernate.annotations.Table(
  appliesTo = "PendingVotes",
  indexes = {
    @Index(name = "VoteId", columnNames = { "VoteId" }),
  })

However, the Java compiler (Version 6, update 12) will report the following error:

annotation.java:6: illegal start of expression
})
^

Now, I’ll display that snippet again and highlight the problem:

@org.hibernate.annotations.Table(
  appliesTo = "PendingVotes",
  indexes = {
    @Index(name = "VoteId", columnNames = { "VoteId" }),
  })

See that sneaky little comma at the end? I believe this is valid syntax (it allows someone to add another item later and only alter a single line – useful for generating diffs).

Remove that comma and everything becomes pain free again.


Hello!

February 25, 2009

My view of blogging is that it is traditional to have a first post that says something profound about why the blog exists.

I’m not really sure what I am going to be putting on here. It’s mainly going to be technical and startup related… but I’m not going to put limits on it.

So, no grand purpose and nothing profound – yet. Watch this space.