redis内存优化( 二 )


假如我们想使用redis存储许多小对象,这些对象可以使用json字符串表示,也可能是html片段和简单的key->boolean键值对 。概况的说,一切皆字符串,都可以使用string:string的形式表示.
我们假设要缓存的对象使用数字后缀进行编码,如:

  • object:102393
  • object:1234
  • object:5
我们可以这样做 。每次SET的时候,把key分为两部分,第一部分当做一个key,第二部当做散列表字段 。比如“object:1234”,分成两部分:
  • a Key named object:12
  • a Field named 34
我们使用除最后2个数字的部分作为key,最后2个数字做为散列表的字段 。使用命令:
【redis内存优化】HSET object:12 34 somevalue如你所见,每个散列表将(理论上)包含100个字段,这是CPU资源和内存资源之间的一个折中.
另一个需要你关注的是在这种模式下,无论缓存多少对象,每个散列表都会分配100个字段 。因为我们的对象总是以数字结尾,而不是一个随机的字符串 。从某些方面来说,这是一种隐性的预分片 。
对于小数字怎么处理?比如object:2,我们采用object:作为key,所有剩下的数字作为一个字段 。所以object:2和object:10都会被存储到key为object:的散列表中,但是一个使用2作为字段,一个使用10作为字段 。
这种方式将节省多少内存?
我使用了下面的Ruby程序进行了测试:
require 'rubygems'require 'redis'Useoptimization = truedef hash_get_key_field(key) s = key.split(":") if s[1].length > 2 {:key => s[0]+":"+s[1][0..-3], :field => s[1][-2..-1]} else {:key => s[0]+":", :field => s[1]} endenddef hash_set(r,key,value) kf = hash_get_key_field(key) r.hset(kf[:key],kf[:field],value)enddef hash_get(r,key,value) kf = hash_get_key_field(key) r.hget(kf[:key],kf[:field],value)endr = Redis.new(0..100000).each{|id| key = "object:#{id}" if UseOptimization hash_set(r,key,"val") else r.set(key,"val") end}在redis2.2的64位版本上测试结果:
  • 当开启优化时使用内存1.7M
  • 当未开启优化时使用内存11M
从结果看出,这是一个数量级的优化,我认为这种优化使redis成为最出色的键值缓存 。


推荐阅读