public
Description: actor-based memcache client library
Homepage:
Clone URL: git://github.com/robey/smile.git
robey (author)
Mon Nov 02 17:16:31 -0800 2009
commit  4b323c75f7a9b720c41b67cc7cd4f4dce436feb0
tree    49b8d25bb3389f470f830787ba79ac2c791f4e17
parent  a3a701c320ed38c0a8addb5f0e9fa25499e2cfa7 parent  a536e9b2c496dd56097e8805f31a9c81848c2046
smile /
name age message
file .gitignore Mon Jul 21 22:35:34 -0700 2008 some ignores. [robey]
file LICENSE Tue Mar 10 15:08:02 -0700 2009 fix license: apache 2. [robey]
file README.md Tue Sep 15 18:40:45 -0700 2009 incremental docs. [robey]
directory ant/ Thu Jan 08 23:57:30 -0800 2009 update scala-build. [robey]
file build.xml Thu Feb 26 17:37:17 -0800 2009 stop building docs for now. [robey]
directory docs/ Sat Oct 04 01:02:54 -0700 2008 add pretty block diagram. [robey]
directory ivy/ Tue Oct 20 14:18:13 -0700 2009 Bump to 0.8.10 Add stresstestclass back to ivy.... [John Kalucki]
directory src/ Tue Oct 20 14:49:36 -0700 2009 Add some test tracing. [John Kalucki]
file test.conf Wed Jan 07 17:56:07 -0800 2009 slight cleanup. [robey]
README.md

SMILE

Smile is a memcache library for scala which is intended to be fast and highly concurrent. It is open-sourced under the Apache 2 license.

All the standard key hashing functions are supported (CRC-ITU, FNV, and Ketama). Support for round-robin ("default") and Ketama key distributions is built-in. User-defined key hashing and distribution functions can be trivially added via the API.

Server lists and configuration may be set manually or via configgy blocks. User-defined key hashing and distribution may be specified in the config block -- just be sure to add them via the API first! :)

Author: Robey Pointer robeypointer@gmail.com

Strategy

Mina is used as a library for handling asynchronous I/O via java NIO, and the memcache protocol is implemented using the naggati DSL for building Mina protocol state machines. I/O events are forwarded to scala actors, with one actor for each memcache server connection. It acts like a thread-pool but ensures that each server's traffic is handled sequentially, with very simple code.

Structure

Performance

A performance test is included as an ant target. It requires you to have 3 memcached servers running on localhost, on ports 11211, 11212, and 11213:

$ ant manygets
manygets:
     [java] serial gets: 1000
     [java] toasters: 1000 in 797 msec (0.80 msec each)
     [java] parallel gets: 1000 on 10 threads
     [java] toasters: 10000 in 2992 msec (0.30 msec each)
     [java] parallel gets: 1000 on 10 threads from 3 servers
     [java] toasters: 10000 in 2048 msec (0.20 msec each)

The first test does 1000 memcache "get" operations in a row, from a single thread. The second does 1000 each from 10 different threads, to verify that performance increases. The third does the same test but randomly picks one of three memcache servers for each "get", to simulate a real-world environment where you would have more than one memcache server, and could run operations on each server in parallel.

API

To get/set UTF-8 strings using a single-node memcache cluster on localhost:

val cache = MemcacheClient.create(Array("localhost"), "default", "crc32-itu")
cache.set("name", "smile")
cache.get("name")

Configuration

Configuration can be done with a configgy block, like so:

memcache {
  distribution = "ketama"
  hash = "fnv1a-64"
  namespace = "widgets"
  servers = [ "memcache1:11211", "memcache2:11211", "memcache3:11211" ]
}

The name "memcache" is arbitrary -- use whatever name you want, and pass the nested block into MemcacheClient.create.

TO-DO

  • Support more than just get and set. At least delete, add, and append.

  • Expose the stats command in some useful way.