redis-objects de Hash


redis-objectsでHashを扱う場合のちょっとしたメモ書きです。

Redis::Objects

Redisで扱えるデータ型

REDIS_CLASS_NAMES = [:Counter, :HashKey, :List, :Lock, :Set, :SortedSet, :Value]

https://github.com/nateware/redis-objects/blob/master/lib/redis/objects.rb

https://github.com/nateware/redis-objects/blob/master/lib/redis/objects/hashes.rb
のおかげでRedis::Objectsをincludeすれば
簡単にRedisのHashを扱えるようになります。
実際のredisへの操作は
https://github.com/nateware/redis-objects/blob/master/lib/redis/hash_key.rb
で行うようです

HashKey

Redis::Helpers::CoreCommandsをincludeしていますので、
storeメソッドでredisのHSETコマンドを実行して、Hashを登録したり、
valuesメソッドでredisのHVALSコマンドを実行して、Hashの値を取得できたりします。

また、Enumerableをincludeしていますので、

...
    def all
      h = redis.hgetall(key) || {}
      h.each{|k,v| h[k] = unmarshal(v, options[:marshal_keys][k]) }
      h
    end
...
    def each(&block)
      all.each(&block)
    end
...

eachメソッドを使った際にkeyとvalueのペアがhashの配列として
取得できたりします。(たぶん)

Redisクライアント(redis-cli)で接続して確認

キーの一覧
>hkeys [hash name]
hashのキー一覧
>hvals [hash name]
hashの値一覧
>HGETALL [hash name]
hashのキーと値を交互に出力

ちなみに、
ActiveRecordを介して登録した場合は
モデル名:ID:指定したキー
という形になります。
https://github.com/nateware/redis-objects#option-1-model-class-include

また、プロジェクトや環境ごとにキーを区別したいときは
redis-namespace
も一緒に使うといいと思います。

ziplistとhashtable

hash-max-ziplist-entriesとhash-max-ziplist-value
を設定することでziplistを使うための閾値をあげることができます。

ziplistを使う

下記をredis.confに設定

hash-max-ziplist-entries 512
hash-max-ziplist-value 64

>redis-cli INFO memory

used_memory:1007360
used_memory_human:983.75K
used_memory_rss:4890624
used_memory_rss_human:4.66M
used_memory_peak:5134560
used_memory_peak_human:4.90M
total_system_memory:8589934592
total_system_memory_human:8.00G
used_memory_lua:37888
used_memory_lua_human:37.00K
maxmemory:0
maxmemory_human:0B
maxmemory_policy:noeviction
mem_fragmentation_ratio:4.85
mem_allocator:libc

keyが500のhashを登録してみます。
>hashes=""
>for i in {1..500} ; do hashes="$hashes field-name-$i field-value-$i" ; done
>redis-cli HMSET hash01 $hashes

used_memory:1023840
used_memory_human:999.84K
used_memory_rss:4907008
used_memory_rss_human:4.68M
used_memory_peak:5134560
used_memory_peak_human:4.90M
total_system_memory:8589934592
total_system_memory_human:8.00G
used_memory_lua:37888
used_memory_lua_human:37.00K
maxmemory:0
maxmemory_human:0B
maxmemory_policy:noeviction
mem_fragmentation_ratio:4.79
mem_allocator:libc

すると
1023840 - 1007360 = 16480 bytes

ziplistを使わない

下記をredis.confに設定

hash-max-ziplist-entries 50
hash-max-ziplist-value 5

>redis-cli flushall
>redis-cli INFO memory

used_memory:1007520
used_memory_human:983.91K
used_memory_rss:1974272
used_memory_rss_human:1.88M
used_memory_peak:1007520
used_memory_peak_human:983.91K
total_system_memory:8589934592
total_system_memory_human:8.00G
used_memory_lua:37888
used_memory_lua_human:37.00K
maxmemory:0
maxmemory_human:0B
maxmemory_policy:noeviction
mem_fragmentation_ratio:1.96
mem_allocator:libc

>hashes=""
>for i in {1..500} ; do hashes="$hashes field-name-$i field-value-$i" ; done
>redis-cli HMSET hash01 $hashes

used_memory:1075664
used_memory_human:1.03M
used_memory_rss:2048000
used_memory_rss_human:1.95M
used_memory_peak:1075664
used_memory_peak_human:1.03M
total_system_memory:8589934592
total_system_memory_human:8.00G
used_memory_lua:37888
used_memory_lua_human:37.00K
maxmemory:0
maxmemory_human:0B
maxmemory_policy:noeviction
mem_fragmentation_ratio:1.90
mem_allocator:libc

1075664 - 1007232 = 68432 bytes

ziplistを使った場合の16480bytesに対して、
使わない場合は68432bytesとなりました。
少ないデータ量の場合はziplistを使ったほうがメモリ効率はよいようです。

データ件数を増やしてみましょう

ziplistを使わない

for j in {1..10000} ; do 
  hashes=""
  for i in {1..500} ; do 
    hashes="$hashes field-name-$i field-value-$i"
  done
  redis-cli HMSET "hash$j" $hashes 
done
used_memory:1007392
used_memory_human:983.78K
used_memory_rss:3211264
used_memory_rss_human:3.06M
used_memory_peak:2322992
used_memory_peak_human:2.22M
total_system_memory:8589934592
total_system_memory_human:8.00G
used_memory_lua:37888
used_memory_lua_human:37.00K
maxmemory:0
maxmemory_human:0B
maxmemory_policy:noeviction
mem_fragmentation_ratio:3.19
mem_allocator:libc
used_memory:1279824
used_memory_human:1.22M
used_memory_rss:2285568
used_memory_rss_human:2.18M
used_memory_peak:1279824
used_memory_peak_human:1.22M
total_system_memory:8589934592
total_system_memory_human:8.00G
used_memory_lua:37888
used_memory_lua_human:37.00K
maxmemory:0
maxmemory_human:0B
maxmemory_policy:noeviction
mem_fragmentation_ratio:1.79
mem_allocator:libc

ziplistを使う



redis-objectsを使う場合は