SlideShare a Scribd company logo
1 of 83
Download to read offline
Redis & Groovy & Grails



                               by Ted Naleid
                               http://naleid.com

Monday, June 20, 2011
“Redis is a collection of data
                        structures exposed over the
                                  network”


                                                  from: http://nosql.mypopescu.com/post/5403851771/what-is-redis

Monday, June 20, 2011
key/value store

               like memcached on steroids


Monday, June 20, 2011
Strings, Integers,
                                Lists, Hashes,
                              Sets & Sorted Sets
                        (& commonly expected operations with each data type)




Monday, June 20, 2011
in-memory storage



Monday, June 20, 2011
single-threaded



Monday, June 20, 2011
fast



Monday, June 20, 2011
“Memory is the new Disk,
                         Disk is the new Tape”
                                 - Jim Gray




Monday, June 20, 2011
Relative Latency
                           CPU Register - 1x
                            L2 Cache - 10x
                            Memory - 100x
                           Disk - 10,000,000x




                                                analogy from “Redis - Memory as the New Disk” - Tim Lossen &
                                                   http://en.wikipedia.org/wiki/Orders_of_magnitude_(speed)
Monday, June 20, 2011
CPU Register
                            1 yard




                                       photo: http://www.flickr.com/photos/limonada/904754668/

Monday, June 20, 2011
L2 Cache
                         10 yards




                                    photo: http://www.flickr.com/photos/plentyofants/2749262107

Monday, June 20, 2011
Memory
                        100 yards




                                    photo: http://www.flickr.com/photos/billmcintyre/264905933

Monday, June 20, 2011
Disk
        Minneapolis to New York to Miami
                   to Seattle
                        ~5600 miles




Monday, June 20, 2011
Simple wire protocol that
                              matches API


Monday, June 20, 2011
% telnet localhost 6379
    Escape character is '^]'.
    set foo bar
    +OK
    get foo
    $3
    bar
    rpush mylist first
    :1
    rpush mylist second
    :2
    lrange mylist 0 -1
    *2
    $5
    first
    $6
    second


Monday, June 20, 2011
clients for every* language

             *well not every language, but all the popular/semi-popular ones, you can easily write one if
                                           your language doesn’t have one




Monday, June 20, 2011
No dependencies
                            (451KB download)




Monday, June 20, 2011
Used in production by high
                  traffic sites that you’ve used


Monday, June 20, 2011
stackoverflow, craigslist,
                         github, disqus, digg &
                         blizzard entertainment


Monday, June 20, 2011
financially supported by
                         VMware/SpringSource


Monday, June 20, 2011
simple data structures make
                       redis flexible


Monday, June 20, 2011
write-through caching/
                             memoization


Monday, June 20, 2011
producer/consumer
                         message queues


Monday, June 20, 2011
publish/subscribe



Monday, June 20, 2011
atomic sequences/counters



Monday, June 20, 2011
other uses...
                             distributed locks, tag clouds, session tokens,
                        auto-complete prefixes, API rate limiting, leaderboards,
                        capped logs, random set items, A/B testing data storage,
                               unique per user product pricing/sorting




Monday, June 20, 2011
Redis Commands



Monday, June 20, 2011
Great Online Reference
                               http://redis.io/commands




Monday, June 20, 2011
Strings
                                            set


                        Redis REPL                            Groovy



                 > set foo bar                          redis.set("foo", "bar")
                                      foo         bar
                 OK                                     OK




Monday, June 20, 2011
Strings
                                            get


                        Redis REPL                            Groovy


                                      foo         bar

                 > get foo                              redis.get("foo")
                 "bar"                                  "bar"

                                                  bar




Monday, June 20, 2011
Exists
                                     exists (check key existence)


                        Redis REPL                                   Groovy


                                              foo     (nil)

           > exists foo                                             redis.exists("foo")
           (integer) 0                                              <= false

                                                        0




Monday, June 20, 2011
Integers
                                     incr (increment)


                        Redis REPL                       Groovy


                                        foo      1

           > incr foo                                   redis.incr("foo")
           (integer) 1                                  <= 1

                                                 1




Monday, June 20, 2011
Integers
                                     decr (decrement)


                        Redis REPL                       Groovy


                                        foo      0

           > decr foo                                   redis.decr("foo")
           (integer) 0                                  <= 0

                                                 0




Monday, June 20, 2011
Lists
                                     rpush (right push)


                        Redis REPL                                 Groovy



           > rpush foo baz                                redis.rpush("foo", "baz")
                                         foo     baz
           (integer) 1                                    <= 1




Monday, June 20, 2011
Lists
                                     rpush (right push)


                        Redis REPL                                 Groovy



           > rpush foo qux                                redis.rpush("foo", "qux")
                                      foo     baz qux
           (integer) 2                                    <= 2




Monday, June 20, 2011
Lists
                                     lpush (left push)


                        Redis REPL                                    Groovy



           > lpush foo bar                                   redis.lpush("foo", "bar")
                                     foo     bar   baz qux
           (integer) 3                                       <= 3




Monday, June 20, 2011
Lists
                                     lrange (slice of list)


                        Redis REPL                                     Groovy


                                      foo      bar   baz qux
           > lrange foo 0 -1                                   redis.lrange("foo", 0, -1)
           1) "bar"                                            <= [bar, baz, qux]
           2) "baz"
           3) "qux"
                                               bar   baz qux




Monday, June 20, 2011
Lists
                                     lrange (slice of list)


                        Redis REPL                                    Groovy


                                      foo      bar   baz qux
           > lrange foo 0 1                                    redis.lrange("foo", 0, 1)
           1) "bar"                                            <= [bar, baz]
           2) "baz"
                                                 bar   baz




Monday, June 20, 2011
Lists
                                     lpop (left pop)


                        Redis REPL                       Groovy


                                     foo      baz qux

           > lpop foo                                   redis.lpop("foo")
           "bar"                                        <= "bar"

                                                bar




Monday, June 20, 2011
Lists
                                     rpop (right pop)


                        Redis REPL                       Groovy


                                        foo     baz

           > rpop foo                                   redis.rpop("foo")
           "qux"                                        <= "qux"

                                                qux




Monday, June 20, 2011
Hashes
                                     hset (set key → value)


                        Redis REPL                                        Groovy



           > hset foo bar baz                                 redis.hset("foo", "bar", "baz")
                                     foo     bar    baz
           (integer) 1                                        <= 1




Monday, June 20, 2011
Hashes
                                     hset (set key → value)


                        Redis REPL                                         Groovy



                                              bar     baz
           > hset foo qux quxx                                redis.hset("foo", "qux", "quxx")
                                      foo
           (integer) 1                                        <= 1
                                              qux     quxx




Monday, June 20, 2011
Hashes
                                     hget (get value for key)


                        Redis REPL                                       Groovy

                                               bar         baz
                                      foo
                                               qux         quxx
           > hget foo bar                                         redis.hget("foo", "bar")
           "baz"                                                  <= "baz"

                                                     baz




Monday, June 20, 2011
Hashes
                                     hgetall (get all keys/values)


                        Redis REPL                                          Groovy
                                                   bar    baz
                                          foo
           > hgetall foo                           qux    quxx

           1) "bar"                                                  redis.hgetAll("foo")
           2) "baz"                                                  <= [bar:baz, qux:quxx]
           3) "qux"
           4) "quxx"                               bar    baz

                                                  qux     quxx




Monday, June 20, 2011
Hashes
                                     hvals (hash values)


                        Redis REPL                              Groovy
                                              bar     baz
                                      foo
                                              qux     quxx

           > hvals foo                                       redis.hvals("foo")
           1) "baz"                                          <= [baz, quxx]
           2) "quxx"
                                                baz quxx




Monday, June 20, 2011
Hashes
                                     hkeys (hash keys)


                        Redis REPL                            Groovy
                                             bar     baz
                                     foo
                                             qux    quxx

           > hkeys foo                                     redis.hkeys("foo")
           1) "bar"                                        <= [bar, qux]
           2) "qux"
                                               bar qux




Monday, June 20, 2011
Sets
                                     sadd (set add)


                        Redis REPL                           Groovy



            > sadd m1 jan                             redis.sadd("m1", "jan")
                                       m1      jan
            (integer) 1                               <= 1




Monday, June 20, 2011
Sets
                                     sadd (set add)


                        Redis REPL                          Groovy



                                               feb
            > sadd m1 feb                             redis.sadd("m1", "feb")
                                       m1
            (integer) 1                               <= 1
                                               jan




Monday, June 20, 2011
Sets
                                     sismember (membership test)


                        Redis REPL                                           Groovy
                                                     feb
                                              m1
                                                     jan
            > sismember m1 jan                                     redis.sismember("m1", "jan")
            (integer) 1                                            <= true

                                                      1




Monday, June 20, 2011
Sets
                                     sismember (membership test)


                        Redis REPL                                          Groovy
                                                     feb
                                              m1
                                                     jan
            > sismember m1 mar                                     redis.sismember("m1", "mar")
            (integer) 0                                            <= false

                                                      0




Monday, June 20, 2011
Sets
                                     smembers (get full set)


                        Redis REPL                                   Groovy
                                                    feb
                                           m1
                                                    jan
           > smembers m1                                       redis.smembers("m1")
           1) "feb"                                            <= [feb, jan]
           2) "jan"
                                                    feb

                                                    jan



Monday, June 20, 2011
Sets
                                     sinter (set intersection)


                        Redis REPL                                       Groovy
                                             feb            feb
                                     m1             m2
                                             jan            mar
         > sinter m1 m2                                           redis.sinter("m1", "m2")
         1) "feb"                                                 <= ["feb"]

                                                     feb




Monday, June 20, 2011
Sets
                                      sdiff (set difference)


                        Redis REPL                                      Groovy
                                             feb           feb
                                     m1            m2
                                             jan           mar
          > sdiff m1 m2                                          redis.sdiff("m1", "m2")
          1) "jan"                                               <= ["jan"]

                                                    jan




Monday, June 20, 2011
Sets
                                          sunion (set union)


                        Redis REPL                                        Groovy
                                               feb             feb
                                     m1              m2
         > sunion m1 m2                        jan             mar
         1) "mar"                                                    redis.sunion("m1", "m2")
         2) "jan"                                     mar            <= ["mar", "jan", "feb"]
         3) "feb"
                                                       jan

                                                      feb


Monday, June 20, 2011
Sorted Sets
                                      zadd (add with score)


                        Redis REPL                                    Groovy



          > zadd z1 1 jan                                     redis.zadd("z1", 1, "jan")
                                           z1      1 jan
          (integer) 1                                         <= 1




Monday, June 20, 2011
Sorted Sets
                                     zscore (score for member)


                        Redis REPL                                       Groovy
                                                    1 jan

                                             z1     2 feb

           > zscore z1 feb                          3 mar        redis.zscore("z1", "feb")
           "2"                                                   <= 2.0


                                                      2




Monday, June 20, 2011
Sorted Sets
                                        zrange (sorted subset)


                        Redis REPL                                          Groovy
                                                   1 jan

                                           z1      2 feb
           > zrange z1 0 1 withscores
           1) "jan"                                3 mar    redis.zrangeWithScores("z1", 0, 1)
           2) "1"                                           <= [["jan", 1], ["feb", 2]]
           3) "feb"
           4) "2"
                                                   1 jan

                                                   2 feb


Monday, June 20, 2011
Sorted Sets
                                zrangebyscore (subset having score range)


                        Redis REPL                                               Groovy
                                                       1 jan

                                               z1      2 feb
         > zrangebyscore z1 2 3 withscores
         1) "feb"                                      3 mar   redis.zrangeByScoreWithScores("z1",2,3)
         2) "2"                                                <= [["feb", 2], ["mar", 3]]
         3) "mar"
         4) "3"
                                                       2 feb

                                                       3 mar


Monday, June 20, 2011
Groovy Usage



Monday, June 20, 2011
Grape @Grab Annotation

          #! /usr/bin/env groovy
          @Grab('redis.clients:jedis:2.0.0')

          def redis = new redis.clients.jedis.Jedis("localhost")

          assert "PONG" == redis.ping()



Monday, June 20, 2011
Producer/Consumer
                             Example


Monday, June 20, 2011
Producer
                          pushes work on a list with lpush




         @Grab('redis.clients:jedis:2.0.0')

         redis = new redis.clients.jedis.Jedis("localhost")

         args.each { redis.lpush("welcome-wagon", it) }




Monday, June 20, 2011
Consumer
                        uses blpop (blocking left pop from list)


         @Grab('redis.clients:jedis:2.0.0')

         redis = new redis.clients.jedis.Jedis("localhost")

         println "Joining the welcome-wagon!"

         while (true) {
             def name = redis.blpop(0, "welcome-wagon")[1]
             println "Welcome ${name}!"
         }

Monday, June 20, 2011
Mass Producer
                        srandmember to randomly pick female name from set


         @Grab('redis.clients:jedis:2.0.0')
         redis = new redis.clients.jedis.Jedis("localhost")

         if (!redis.exists("female-names")) {
            new File("./female-names.txt").eachLine {redis.sadd("female-names",it)}
         }

         for (i in 1..100000) {
            redis.lpush("welcome-wagon", redis.srandmember("female-names"))
            if (i % 1000 == 0) println "Adding $i"
         }

                                                    female-names.txt from: http://antirez.com/post/autocomplete-with-redis.html
Monday, June 20, 2011
Groovy Demo



Monday, June 20, 2011
Grails Redis Plugin
                        https://github.com/grails-plugins/grails-redis




Monday, June 20, 2011
Plugin Config
                                        in Config.xml




          grails {
              redis {
                   poolConfig {
                       // jedis pool specific tweaks here, see jedis docs & src
                       // ex: numTestsPerEvictionRun = 4
                   }
                   port = 6379
                   host = "localhost"
              }
          }


Monday, June 20, 2011
Provides Caching Through
                              Memoization


Monday, June 20, 2011
RedisTagLib

          <redis:memoize key="mykey" expire="3600">
              <!--
                   insert expensive to generate GSP content here

                        content will be executed once, subsequent calls
                        will pull from redis (redis.get(“mykey”)) till the key expires
              -->
          </redis:memoize>



Monday, June 20, 2011
RedisService
                          Spring bean wraps pool connection




          // overrides propertyMissing and methodMissing to delegate to redis
          def redisService

          redisService.foo = "bar"
          assert "bar" == redisService.foo

          redisService.sadd("months", "february")
          assert true == redisService.sismember("months", "february")



Monday, June 20, 2011
RedisService
                        template methods manage pooled Redis connection




          redisService.withRedis { Jedis redis ->
              redis.set("foo", "bar")
          }




Monday, June 20, 2011
RedisService
                            template methods manage pooled Redis connection




          redisService.withRedis { Jedis redis ->

                        redisService.withTransaction { Transaction transaction ->
                            transaction.set("qux", "baz")
                            assertNull redis.get("qux")
                        }

                        assertEquals "baz", redis.get("qux")
          }



Monday, June 20, 2011
RedisService
                                   String memoization



          redisService.memoize("my-key") { Jedis redis ->
              // expensive operation we only want to execute once
          }


          def ONE_HOUR = 3600 // with optional timeout in seconds
          redisService.memoize("my-key-with-timeout", ONE_HOUR) { Jedis redis ->
              // expensive operation we want to execute every hour
          }



Monday, June 20, 2011
RedisService
                        Domain Class memoization (stores IDs hydrates from DB)




           def key = "user:$id:friends-books"

           redisService.memoizeDomainList(Book, key, ONE_HOUR) { redis ->
               // expensive process to calculate all friend’s books
               // stores list of Book ids, hydrates them from DB
           }




Monday, June 20, 2011
Example
                        Showing Products with Sort/Filter/Pagination Criteria




Monday, June 20, 2011
Other Memoization Methods
                        memoizeHash, memoizeHashField,
                         memoizeScore (sorted set score)




Monday, June 20, 2011
Grails Redis-GORM Plugin
                          http://grails.github.com/inconsequential/redis/




Monday, June 20, 2011
Uses SpringData to abstract
                          data layer


Monday, June 20, 2011
Can be used in conjunction
                        with Hibernate


Monday, June 20, 2011
Partial support for GORM
     including Dynamic Finders, Criteria, Named Queries and “Transactions”




Monday, June 20, 2011
Limitations
                        It requires explicit index mapping on fields you want to query

          package com.example

          class Author {

                        String name

                        static mapWith = "redis"
                        static hasMany = [books: Book]

                        static mapping = {
                            name index:true
                        }
          }
Monday, June 20, 2011
Under The Covers
                        MONITOR output for new Author(name: "Stephen King").save()




          1308027697.922839       "INCR" "com.example.Author.next_id"
          1308027697.940021       "HMSET" "com.example.Author:1" "name" "Stephen King" "version" "0"
          1308027697.940412       "SADD" "com.example.Author.all" "1"
          1308027697.943318       "SADD" "com.example.Author:id:1" "1"
          1308027697.943763       "ZADD" "com.example.Author:id:sorted" "1.0" "1"
          1308027697.944911       "SADD" "com.example.Author:name:Stephen+King" "1"




Monday, June 20, 2011
Questions?



Monday, June 20, 2011

More Related Content

Recently uploaded

Genislab builds better products and faster go-to-market with Lean project man...
Genislab builds better products and faster go-to-market with Lean project man...Genislab builds better products and faster go-to-market with Lean project man...
Genislab builds better products and faster go-to-market with Lean project man...Farhan Tariq
 
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptxPasskey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptxLoriGlavin3
 
Decarbonising Buildings: Making a net-zero built environment a reality
Decarbonising Buildings: Making a net-zero built environment a realityDecarbonising Buildings: Making a net-zero built environment a reality
Decarbonising Buildings: Making a net-zero built environment a realityIES VE
 
The State of Passkeys with FIDO Alliance.pptx
The State of Passkeys with FIDO Alliance.pptxThe State of Passkeys with FIDO Alliance.pptx
The State of Passkeys with FIDO Alliance.pptxLoriGlavin3
 
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024BookNet Canada
 
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...Wes McKinney
 
Long journey of Ruby standard library at RubyConf AU 2024
Long journey of Ruby standard library at RubyConf AU 2024Long journey of Ruby standard library at RubyConf AU 2024
Long journey of Ruby standard library at RubyConf AU 2024Hiroshi SHIBATA
 
Scale your database traffic with Read & Write split using MySQL Router
Scale your database traffic with Read & Write split using MySQL RouterScale your database traffic with Read & Write split using MySQL Router
Scale your database traffic with Read & Write split using MySQL RouterMydbops
 
Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...
Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...
Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...Alkin Tezuysal
 
Emixa Mendix Meetup 11 April 2024 about Mendix Native development
Emixa Mendix Meetup 11 April 2024 about Mendix Native developmentEmixa Mendix Meetup 11 April 2024 about Mendix Native development
Emixa Mendix Meetup 11 April 2024 about Mendix Native developmentPim van der Noll
 
From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .Alan Dix
 
Generative AI for Technical Writer or Information Developers
Generative AI for Technical Writer or Information DevelopersGenerative AI for Technical Writer or Information Developers
Generative AI for Technical Writer or Information DevelopersRaghuram Pandurangan
 
DevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsDevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsSergiu Bodiu
 
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxMerck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxLoriGlavin3
 
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptxUse of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptxLoriGlavin3
 
How to write a Business Continuity Plan
How to write a Business Continuity PlanHow to write a Business Continuity Plan
How to write a Business Continuity PlanDatabarracks
 
Testing tools and AI - ideas what to try with some tool examples
Testing tools and AI - ideas what to try with some tool examplesTesting tools and AI - ideas what to try with some tool examples
Testing tools and AI - ideas what to try with some tool examplesKari Kakkonen
 
How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.Curtis Poe
 
Assure Ecommerce and Retail Operations Uptime with ThousandEyes
Assure Ecommerce and Retail Operations Uptime with ThousandEyesAssure Ecommerce and Retail Operations Uptime with ThousandEyes
Assure Ecommerce and Retail Operations Uptime with ThousandEyesThousandEyes
 
Enhancing User Experience - Exploring the Latest Features of Tallyman Axis Lo...
Enhancing User Experience - Exploring the Latest Features of Tallyman Axis Lo...Enhancing User Experience - Exploring the Latest Features of Tallyman Axis Lo...
Enhancing User Experience - Exploring the Latest Features of Tallyman Axis Lo...Scott Andery
 

Recently uploaded (20)

Genislab builds better products and faster go-to-market with Lean project man...
Genislab builds better products and faster go-to-market with Lean project man...Genislab builds better products and faster go-to-market with Lean project man...
Genislab builds better products and faster go-to-market with Lean project man...
 
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptxPasskey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptx
 
Decarbonising Buildings: Making a net-zero built environment a reality
Decarbonising Buildings: Making a net-zero built environment a realityDecarbonising Buildings: Making a net-zero built environment a reality
Decarbonising Buildings: Making a net-zero built environment a reality
 
The State of Passkeys with FIDO Alliance.pptx
The State of Passkeys with FIDO Alliance.pptxThe State of Passkeys with FIDO Alliance.pptx
The State of Passkeys with FIDO Alliance.pptx
 
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
 
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...
 
Long journey of Ruby standard library at RubyConf AU 2024
Long journey of Ruby standard library at RubyConf AU 2024Long journey of Ruby standard library at RubyConf AU 2024
Long journey of Ruby standard library at RubyConf AU 2024
 
Scale your database traffic with Read & Write split using MySQL Router
Scale your database traffic with Read & Write split using MySQL RouterScale your database traffic with Read & Write split using MySQL Router
Scale your database traffic with Read & Write split using MySQL Router
 
Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...
Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...
Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...
 
Emixa Mendix Meetup 11 April 2024 about Mendix Native development
Emixa Mendix Meetup 11 April 2024 about Mendix Native developmentEmixa Mendix Meetup 11 April 2024 about Mendix Native development
Emixa Mendix Meetup 11 April 2024 about Mendix Native development
 
From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .
 
Generative AI for Technical Writer or Information Developers
Generative AI for Technical Writer or Information DevelopersGenerative AI for Technical Writer or Information Developers
Generative AI for Technical Writer or Information Developers
 
DevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsDevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platforms
 
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxMerck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
 
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptxUse of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
 
How to write a Business Continuity Plan
How to write a Business Continuity PlanHow to write a Business Continuity Plan
How to write a Business Continuity Plan
 
Testing tools and AI - ideas what to try with some tool examples
Testing tools and AI - ideas what to try with some tool examplesTesting tools and AI - ideas what to try with some tool examples
Testing tools and AI - ideas what to try with some tool examples
 
How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.
 
Assure Ecommerce and Retail Operations Uptime with ThousandEyes
Assure Ecommerce and Retail Operations Uptime with ThousandEyesAssure Ecommerce and Retail Operations Uptime with ThousandEyes
Assure Ecommerce and Retail Operations Uptime with ThousandEyes
 
Enhancing User Experience - Exploring the Latest Features of Tallyman Axis Lo...
Enhancing User Experience - Exploring the Latest Features of Tallyman Axis Lo...Enhancing User Experience - Exploring the Latest Features of Tallyman Axis Lo...
Enhancing User Experience - Exploring the Latest Features of Tallyman Axis Lo...
 

Featured

2024 State of Marketing Report – by Hubspot
2024 State of Marketing Report – by Hubspot2024 State of Marketing Report – by Hubspot
2024 State of Marketing Report – by HubspotMarius Sescu
 
Everything You Need To Know About ChatGPT
Everything You Need To Know About ChatGPTEverything You Need To Know About ChatGPT
Everything You Need To Know About ChatGPTExpeed Software
 
Product Design Trends in 2024 | Teenage Engineerings
Product Design Trends in 2024 | Teenage EngineeringsProduct Design Trends in 2024 | Teenage Engineerings
Product Design Trends in 2024 | Teenage EngineeringsPixeldarts
 
How Race, Age and Gender Shape Attitudes Towards Mental Health
How Race, Age and Gender Shape Attitudes Towards Mental HealthHow Race, Age and Gender Shape Attitudes Towards Mental Health
How Race, Age and Gender Shape Attitudes Towards Mental HealthThinkNow
 
AI Trends in Creative Operations 2024 by Artwork Flow.pdf
AI Trends in Creative Operations 2024 by Artwork Flow.pdfAI Trends in Creative Operations 2024 by Artwork Flow.pdf
AI Trends in Creative Operations 2024 by Artwork Flow.pdfmarketingartwork
 
PEPSICO Presentation to CAGNY Conference Feb 2024
PEPSICO Presentation to CAGNY Conference Feb 2024PEPSICO Presentation to CAGNY Conference Feb 2024
PEPSICO Presentation to CAGNY Conference Feb 2024Neil Kimberley
 
Content Methodology: A Best Practices Report (Webinar)
Content Methodology: A Best Practices Report (Webinar)Content Methodology: A Best Practices Report (Webinar)
Content Methodology: A Best Practices Report (Webinar)contently
 
How to Prepare For a Successful Job Search for 2024
How to Prepare For a Successful Job Search for 2024How to Prepare For a Successful Job Search for 2024
How to Prepare For a Successful Job Search for 2024Albert Qian
 
Social Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie InsightsSocial Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie InsightsKurio // The Social Media Age(ncy)
 
Trends In Paid Search: Navigating The Digital Landscape In 2024
Trends In Paid Search: Navigating The Digital Landscape In 2024Trends In Paid Search: Navigating The Digital Landscape In 2024
Trends In Paid Search: Navigating The Digital Landscape In 2024Search Engine Journal
 
5 Public speaking tips from TED - Visualized summary
5 Public speaking tips from TED - Visualized summary5 Public speaking tips from TED - Visualized summary
5 Public speaking tips from TED - Visualized summarySpeakerHub
 
ChatGPT and the Future of Work - Clark Boyd
ChatGPT and the Future of Work - Clark Boyd ChatGPT and the Future of Work - Clark Boyd
ChatGPT and the Future of Work - Clark Boyd Clark Boyd
 
Getting into the tech field. what next
Getting into the tech field. what next Getting into the tech field. what next
Getting into the tech field. what next Tessa Mero
 
Google's Just Not That Into You: Understanding Core Updates & Search Intent
Google's Just Not That Into You: Understanding Core Updates & Search IntentGoogle's Just Not That Into You: Understanding Core Updates & Search Intent
Google's Just Not That Into You: Understanding Core Updates & Search IntentLily Ray
 
Time Management & Productivity - Best Practices
Time Management & Productivity -  Best PracticesTime Management & Productivity -  Best Practices
Time Management & Productivity - Best PracticesVit Horky
 
The six step guide to practical project management
The six step guide to practical project managementThe six step guide to practical project management
The six step guide to practical project managementMindGenius
 
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...RachelPearson36
 

Featured (20)

2024 State of Marketing Report – by Hubspot
2024 State of Marketing Report – by Hubspot2024 State of Marketing Report – by Hubspot
2024 State of Marketing Report – by Hubspot
 
Everything You Need To Know About ChatGPT
Everything You Need To Know About ChatGPTEverything You Need To Know About ChatGPT
Everything You Need To Know About ChatGPT
 
Product Design Trends in 2024 | Teenage Engineerings
Product Design Trends in 2024 | Teenage EngineeringsProduct Design Trends in 2024 | Teenage Engineerings
Product Design Trends in 2024 | Teenage Engineerings
 
How Race, Age and Gender Shape Attitudes Towards Mental Health
How Race, Age and Gender Shape Attitudes Towards Mental HealthHow Race, Age and Gender Shape Attitudes Towards Mental Health
How Race, Age and Gender Shape Attitudes Towards Mental Health
 
AI Trends in Creative Operations 2024 by Artwork Flow.pdf
AI Trends in Creative Operations 2024 by Artwork Flow.pdfAI Trends in Creative Operations 2024 by Artwork Flow.pdf
AI Trends in Creative Operations 2024 by Artwork Flow.pdf
 
Skeleton Culture Code
Skeleton Culture CodeSkeleton Culture Code
Skeleton Culture Code
 
PEPSICO Presentation to CAGNY Conference Feb 2024
PEPSICO Presentation to CAGNY Conference Feb 2024PEPSICO Presentation to CAGNY Conference Feb 2024
PEPSICO Presentation to CAGNY Conference Feb 2024
 
Content Methodology: A Best Practices Report (Webinar)
Content Methodology: A Best Practices Report (Webinar)Content Methodology: A Best Practices Report (Webinar)
Content Methodology: A Best Practices Report (Webinar)
 
How to Prepare For a Successful Job Search for 2024
How to Prepare For a Successful Job Search for 2024How to Prepare For a Successful Job Search for 2024
How to Prepare For a Successful Job Search for 2024
 
Social Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie InsightsSocial Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie Insights
 
Trends In Paid Search: Navigating The Digital Landscape In 2024
Trends In Paid Search: Navigating The Digital Landscape In 2024Trends In Paid Search: Navigating The Digital Landscape In 2024
Trends In Paid Search: Navigating The Digital Landscape In 2024
 
5 Public speaking tips from TED - Visualized summary
5 Public speaking tips from TED - Visualized summary5 Public speaking tips from TED - Visualized summary
5 Public speaking tips from TED - Visualized summary
 
ChatGPT and the Future of Work - Clark Boyd
ChatGPT and the Future of Work - Clark Boyd ChatGPT and the Future of Work - Clark Boyd
ChatGPT and the Future of Work - Clark Boyd
 
Getting into the tech field. what next
Getting into the tech field. what next Getting into the tech field. what next
Getting into the tech field. what next
 
Google's Just Not That Into You: Understanding Core Updates & Search Intent
Google's Just Not That Into You: Understanding Core Updates & Search IntentGoogle's Just Not That Into You: Understanding Core Updates & Search Intent
Google's Just Not That Into You: Understanding Core Updates & Search Intent
 
How to have difficult conversations
How to have difficult conversations How to have difficult conversations
How to have difficult conversations
 
Introduction to Data Science
Introduction to Data ScienceIntroduction to Data Science
Introduction to Data Science
 
Time Management & Productivity - Best Practices
Time Management & Productivity -  Best PracticesTime Management & Productivity -  Best Practices
Time Management & Productivity - Best Practices
 
The six step guide to practical project management
The six step guide to practical project managementThe six step guide to practical project management
The six step guide to practical project management
 
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
 

Redis & Groovy integration for caching and messaging

  • 1. Redis & Groovy & Grails by Ted Naleid http://naleid.com Monday, June 20, 2011
  • 2. “Redis is a collection of data structures exposed over the network” from: http://nosql.mypopescu.com/post/5403851771/what-is-redis Monday, June 20, 2011
  • 3. key/value store like memcached on steroids Monday, June 20, 2011
  • 4. Strings, Integers, Lists, Hashes, Sets & Sorted Sets (& commonly expected operations with each data type) Monday, June 20, 2011
  • 8. “Memory is the new Disk, Disk is the new Tape” - Jim Gray Monday, June 20, 2011
  • 9. Relative Latency CPU Register - 1x L2 Cache - 10x Memory - 100x Disk - 10,000,000x analogy from “Redis - Memory as the New Disk” - Tim Lossen & http://en.wikipedia.org/wiki/Orders_of_magnitude_(speed) Monday, June 20, 2011
  • 10. CPU Register 1 yard photo: http://www.flickr.com/photos/limonada/904754668/ Monday, June 20, 2011
  • 11. L2 Cache 10 yards photo: http://www.flickr.com/photos/plentyofants/2749262107 Monday, June 20, 2011
  • 12. Memory 100 yards photo: http://www.flickr.com/photos/billmcintyre/264905933 Monday, June 20, 2011
  • 13. Disk Minneapolis to New York to Miami to Seattle ~5600 miles Monday, June 20, 2011
  • 14. Simple wire protocol that matches API Monday, June 20, 2011
  • 15. % telnet localhost 6379 Escape character is '^]'. set foo bar +OK get foo $3 bar rpush mylist first :1 rpush mylist second :2 lrange mylist 0 -1 *2 $5 first $6 second Monday, June 20, 2011
  • 16. clients for every* language *well not every language, but all the popular/semi-popular ones, you can easily write one if your language doesn’t have one Monday, June 20, 2011
  • 17. No dependencies (451KB download) Monday, June 20, 2011
  • 18. Used in production by high traffic sites that you’ve used Monday, June 20, 2011
  • 19. stackoverflow, craigslist, github, disqus, digg & blizzard entertainment Monday, June 20, 2011
  • 20. financially supported by VMware/SpringSource Monday, June 20, 2011
  • 21. simple data structures make redis flexible Monday, June 20, 2011
  • 22. write-through caching/ memoization Monday, June 20, 2011
  • 23. producer/consumer message queues Monday, June 20, 2011
  • 26. other uses... distributed locks, tag clouds, session tokens, auto-complete prefixes, API rate limiting, leaderboards, capped logs, random set items, A/B testing data storage, unique per user product pricing/sorting Monday, June 20, 2011
  • 28. Great Online Reference http://redis.io/commands Monday, June 20, 2011
  • 29. Strings set Redis REPL Groovy > set foo bar redis.set("foo", "bar") foo bar OK OK Monday, June 20, 2011
  • 30. Strings get Redis REPL Groovy foo bar > get foo redis.get("foo") "bar" "bar" bar Monday, June 20, 2011
  • 31. Exists exists (check key existence) Redis REPL Groovy foo (nil) > exists foo redis.exists("foo") (integer) 0 <= false 0 Monday, June 20, 2011
  • 32. Integers incr (increment) Redis REPL Groovy foo 1 > incr foo redis.incr("foo") (integer) 1 <= 1 1 Monday, June 20, 2011
  • 33. Integers decr (decrement) Redis REPL Groovy foo 0 > decr foo redis.decr("foo") (integer) 0 <= 0 0 Monday, June 20, 2011
  • 34. Lists rpush (right push) Redis REPL Groovy > rpush foo baz redis.rpush("foo", "baz") foo baz (integer) 1 <= 1 Monday, June 20, 2011
  • 35. Lists rpush (right push) Redis REPL Groovy > rpush foo qux redis.rpush("foo", "qux") foo baz qux (integer) 2 <= 2 Monday, June 20, 2011
  • 36. Lists lpush (left push) Redis REPL Groovy > lpush foo bar redis.lpush("foo", "bar") foo bar baz qux (integer) 3 <= 3 Monday, June 20, 2011
  • 37. Lists lrange (slice of list) Redis REPL Groovy foo bar baz qux > lrange foo 0 -1 redis.lrange("foo", 0, -1) 1) "bar" <= [bar, baz, qux] 2) "baz" 3) "qux" bar baz qux Monday, June 20, 2011
  • 38. Lists lrange (slice of list) Redis REPL Groovy foo bar baz qux > lrange foo 0 1 redis.lrange("foo", 0, 1) 1) "bar" <= [bar, baz] 2) "baz" bar baz Monday, June 20, 2011
  • 39. Lists lpop (left pop) Redis REPL Groovy foo baz qux > lpop foo redis.lpop("foo") "bar" <= "bar" bar Monday, June 20, 2011
  • 40. Lists rpop (right pop) Redis REPL Groovy foo baz > rpop foo redis.rpop("foo") "qux" <= "qux" qux Monday, June 20, 2011
  • 41. Hashes hset (set key → value) Redis REPL Groovy > hset foo bar baz redis.hset("foo", "bar", "baz") foo bar baz (integer) 1 <= 1 Monday, June 20, 2011
  • 42. Hashes hset (set key → value) Redis REPL Groovy bar baz > hset foo qux quxx redis.hset("foo", "qux", "quxx") foo (integer) 1 <= 1 qux quxx Monday, June 20, 2011
  • 43. Hashes hget (get value for key) Redis REPL Groovy bar baz foo qux quxx > hget foo bar redis.hget("foo", "bar") "baz" <= "baz" baz Monday, June 20, 2011
  • 44. Hashes hgetall (get all keys/values) Redis REPL Groovy bar baz foo > hgetall foo qux quxx 1) "bar" redis.hgetAll("foo") 2) "baz" <= [bar:baz, qux:quxx] 3) "qux" 4) "quxx" bar baz qux quxx Monday, June 20, 2011
  • 45. Hashes hvals (hash values) Redis REPL Groovy bar baz foo qux quxx > hvals foo redis.hvals("foo") 1) "baz" <= [baz, quxx] 2) "quxx" baz quxx Monday, June 20, 2011
  • 46. Hashes hkeys (hash keys) Redis REPL Groovy bar baz foo qux quxx > hkeys foo redis.hkeys("foo") 1) "bar" <= [bar, qux] 2) "qux" bar qux Monday, June 20, 2011
  • 47. Sets sadd (set add) Redis REPL Groovy > sadd m1 jan redis.sadd("m1", "jan") m1 jan (integer) 1 <= 1 Monday, June 20, 2011
  • 48. Sets sadd (set add) Redis REPL Groovy feb > sadd m1 feb redis.sadd("m1", "feb") m1 (integer) 1 <= 1 jan Monday, June 20, 2011
  • 49. Sets sismember (membership test) Redis REPL Groovy feb m1 jan > sismember m1 jan redis.sismember("m1", "jan") (integer) 1 <= true 1 Monday, June 20, 2011
  • 50. Sets sismember (membership test) Redis REPL Groovy feb m1 jan > sismember m1 mar redis.sismember("m1", "mar") (integer) 0 <= false 0 Monday, June 20, 2011
  • 51. Sets smembers (get full set) Redis REPL Groovy feb m1 jan > smembers m1 redis.smembers("m1") 1) "feb" <= [feb, jan] 2) "jan" feb jan Monday, June 20, 2011
  • 52. Sets sinter (set intersection) Redis REPL Groovy feb feb m1 m2 jan mar > sinter m1 m2 redis.sinter("m1", "m2") 1) "feb" <= ["feb"] feb Monday, June 20, 2011
  • 53. Sets sdiff (set difference) Redis REPL Groovy feb feb m1 m2 jan mar > sdiff m1 m2 redis.sdiff("m1", "m2") 1) "jan" <= ["jan"] jan Monday, June 20, 2011
  • 54. Sets sunion (set union) Redis REPL Groovy feb feb m1 m2 > sunion m1 m2 jan mar 1) "mar" redis.sunion("m1", "m2") 2) "jan" mar <= ["mar", "jan", "feb"] 3) "feb" jan feb Monday, June 20, 2011
  • 55. Sorted Sets zadd (add with score) Redis REPL Groovy > zadd z1 1 jan redis.zadd("z1", 1, "jan") z1 1 jan (integer) 1 <= 1 Monday, June 20, 2011
  • 56. Sorted Sets zscore (score for member) Redis REPL Groovy 1 jan z1 2 feb > zscore z1 feb 3 mar redis.zscore("z1", "feb") "2" <= 2.0 2 Monday, June 20, 2011
  • 57. Sorted Sets zrange (sorted subset) Redis REPL Groovy 1 jan z1 2 feb > zrange z1 0 1 withscores 1) "jan" 3 mar redis.zrangeWithScores("z1", 0, 1) 2) "1" <= [["jan", 1], ["feb", 2]] 3) "feb" 4) "2" 1 jan 2 feb Monday, June 20, 2011
  • 58. Sorted Sets zrangebyscore (subset having score range) Redis REPL Groovy 1 jan z1 2 feb > zrangebyscore z1 2 3 withscores 1) "feb" 3 mar redis.zrangeByScoreWithScores("z1",2,3) 2) "2" <= [["feb", 2], ["mar", 3]] 3) "mar" 4) "3" 2 feb 3 mar Monday, June 20, 2011
  • 60. Grape @Grab Annotation #! /usr/bin/env groovy @Grab('redis.clients:jedis:2.0.0') def redis = new redis.clients.jedis.Jedis("localhost") assert "PONG" == redis.ping() Monday, June 20, 2011
  • 61. Producer/Consumer Example Monday, June 20, 2011
  • 62. Producer pushes work on a list with lpush @Grab('redis.clients:jedis:2.0.0') redis = new redis.clients.jedis.Jedis("localhost") args.each { redis.lpush("welcome-wagon", it) } Monday, June 20, 2011
  • 63. Consumer uses blpop (blocking left pop from list) @Grab('redis.clients:jedis:2.0.0') redis = new redis.clients.jedis.Jedis("localhost") println "Joining the welcome-wagon!" while (true) { def name = redis.blpop(0, "welcome-wagon")[1] println "Welcome ${name}!" } Monday, June 20, 2011
  • 64. Mass Producer srandmember to randomly pick female name from set @Grab('redis.clients:jedis:2.0.0') redis = new redis.clients.jedis.Jedis("localhost") if (!redis.exists("female-names")) { new File("./female-names.txt").eachLine {redis.sadd("female-names",it)} } for (i in 1..100000) { redis.lpush("welcome-wagon", redis.srandmember("female-names")) if (i % 1000 == 0) println "Adding $i" } female-names.txt from: http://antirez.com/post/autocomplete-with-redis.html Monday, June 20, 2011
  • 66. Grails Redis Plugin https://github.com/grails-plugins/grails-redis Monday, June 20, 2011
  • 67. Plugin Config in Config.xml grails { redis { poolConfig { // jedis pool specific tweaks here, see jedis docs & src // ex: numTestsPerEvictionRun = 4 } port = 6379 host = "localhost" } } Monday, June 20, 2011
  • 68. Provides Caching Through Memoization Monday, June 20, 2011
  • 69. RedisTagLib <redis:memoize key="mykey" expire="3600"> <!-- insert expensive to generate GSP content here content will be executed once, subsequent calls will pull from redis (redis.get(“mykey”)) till the key expires --> </redis:memoize> Monday, June 20, 2011
  • 70. RedisService Spring bean wraps pool connection // overrides propertyMissing and methodMissing to delegate to redis def redisService redisService.foo = "bar" assert "bar" == redisService.foo redisService.sadd("months", "february") assert true == redisService.sismember("months", "february") Monday, June 20, 2011
  • 71. RedisService template methods manage pooled Redis connection redisService.withRedis { Jedis redis -> redis.set("foo", "bar") } Monday, June 20, 2011
  • 72. RedisService template methods manage pooled Redis connection redisService.withRedis { Jedis redis -> redisService.withTransaction { Transaction transaction -> transaction.set("qux", "baz") assertNull redis.get("qux") } assertEquals "baz", redis.get("qux") } Monday, June 20, 2011
  • 73. RedisService String memoization redisService.memoize("my-key") { Jedis redis -> // expensive operation we only want to execute once } def ONE_HOUR = 3600 // with optional timeout in seconds redisService.memoize("my-key-with-timeout", ONE_HOUR) { Jedis redis -> // expensive operation we want to execute every hour } Monday, June 20, 2011
  • 74. RedisService Domain Class memoization (stores IDs hydrates from DB) def key = "user:$id:friends-books" redisService.memoizeDomainList(Book, key, ONE_HOUR) { redis -> // expensive process to calculate all friend’s books // stores list of Book ids, hydrates them from DB } Monday, June 20, 2011
  • 75. Example Showing Products with Sort/Filter/Pagination Criteria Monday, June 20, 2011
  • 76. Other Memoization Methods memoizeHash, memoizeHashField, memoizeScore (sorted set score) Monday, June 20, 2011
  • 77. Grails Redis-GORM Plugin http://grails.github.com/inconsequential/redis/ Monday, June 20, 2011
  • 78. Uses SpringData to abstract data layer Monday, June 20, 2011
  • 79. Can be used in conjunction with Hibernate Monday, June 20, 2011
  • 80. Partial support for GORM including Dynamic Finders, Criteria, Named Queries and “Transactions” Monday, June 20, 2011
  • 81. Limitations It requires explicit index mapping on fields you want to query package com.example class Author { String name static mapWith = "redis" static hasMany = [books: Book] static mapping = { name index:true } } Monday, June 20, 2011
  • 82. Under The Covers MONITOR output for new Author(name: "Stephen King").save() 1308027697.922839 "INCR" "com.example.Author.next_id" 1308027697.940021 "HMSET" "com.example.Author:1" "name" "Stephen King" "version" "0" 1308027697.940412 "SADD" "com.example.Author.all" "1" 1308027697.943318 "SADD" "com.example.Author:id:1" "1" 1308027697.943763 "ZADD" "com.example.Author:id:sorted" "1.0" "1" 1308027697.944911 "SADD" "com.example.Author:name:Stephen+King" "1" Monday, June 20, 2011