草庐IT

Redis 原理 - Hash

Broadm 2023-03-28 原文

Hash 数据结构

  1. 使用 ziplist
    当同时满足下面两个条件时,使用 ziplist 存储数据
    • 元素个数少于512个 (hash-max-ziplist-entries: 512)
    • 每个元素长度小于64字节 (hash-max-ziplist-value: 64)
  2. 不满足上面的条件, 使用 hashtable

Hash使用 ziplist 图解

可以看到, 当hash以ziplist编码存储时,键值对依次按顺序存放在ziplist中,key在前,value在后.

Hash使用 hashtable 图解

哈希表相关的数据结构

//字典
typedef struct dict {
    dictType *type; // 类型特定函数
    void *privdata; // 私有数据
    dictht ht[2]; // 每个字典使用两个哈希表,实现渐进式 rehash
    int rehashidx;   // rehash 索引,当 rehash 不在进行时,值为 -1
    int iterators; // 目前正在运行的安全迭代器的数量
} dict;

//哈希表
typedef struct dictht {
    dictEntry **table; // 哈希表数组
    unsigned long size; // 哈希表大小
    unsigned long sizemask; // 哈希表大小掩码,用于计算索引值, 总是等于 size - 1
    unsigned long used; // 该哈希表已有节点的数量
} dictht;

//哈希表节点
typedef struct dictEntry {
    void *key; // 键
    union {
        void *val; // 值, 正常是指向一个 redisObject
        uint64_t u64;
        int64_t s64;
    } v;
    struct dictEntry *next; // 指向下个哈希表节点,形成链表 (拉链法解决hash冲突)
} dictEntry;

哈希表图解

渐进式rehash流程

当hashtable需要扩容时,redis使用渐进式rehash

  1. 为ht[1]分配空间,此时字典同时持有ht[0]和ht[1]
  2. 将rehashidx设为0,表示rehash正式开始
  3. 在rehash期间,每次对字典执行任意操作时,程序除了执行对应操作之外,还会顺带将ht[0]在rehashidx索引上的所有键值对rehash到ht[1],操作完后将rehashidx的值 + 1
  4. Redis本身也会有事件轮询,哪怕没有命令访问,也会通过轮询事件逐渐完成数据迁移
  5. 当rehashidx的值增加到 ht[0].size,此时ht[0]的所有键值对都已经迁移到ht[1]了。程序会把ht[1]赋值给ht[0],并重新在ht[1]上新建一个空表。将rehashidx重新置为-1,以此表示rehash完成

Redis为什么需要渐进式rehash?

当存在超大的hashTable进行扩容时,如果不去渐进式扩容,单次扩容时间太长,扩容期间Redis服务不可用,将导致线程阻塞

Hash的常用命令

  • HSET key field value 将一个或多个field/value插入到哈希表中
  • HGET key field 返回key中指定 field 的 value 值
  • HKEYS key 返回哈希表 key 中的所有field
  • HGETALL key 返回哈希表 key 中,所有的field和value
  • HVALS key 返回哈希表 key 中的所有value
  • HEXISTS key field 检查哈希表 key 中,field 是否存在
  • HDEL key field 删除哈希表 key 中的一个或多个field
  • HLEN key 返回哈希表 key 中field的数量
  • HSETNX key field value :将哈希表 key 中的 field 的值设置为 value , 仅当 field 不存在时才会执行

有关Redis 原理 - Hash的更多相关文章

  1. ruby-on-rails - Rails 源代码 : initialize hash in a weird way? - 2

    在rails源中:https://github.com/rails/rails/blob/master/activesupport/lib/active_support/lazy_load_hooks.rb可以看到以下内容@load_hooks=Hash.new{|h,k|h[k]=[]}在IRB中,它只是初始化一个空哈希。和做有什么区别@load_hooks=Hash.new 最佳答案 查看rubydocumentationforHashnew→new_hashclicktotogglesourcenew(obj)→new_has

  2. ruby-on-rails - 如何从 format.xml 中删除 <hash></hash> - 2

    我有一个对象has_many应呈现为xml的子对象。这不是问题。我的问题是我创建了一个Hash包含此数据,就像解析器需要它一样。但是rails自动将整个文件包含在.........我需要摆脱type="array"和我该如何处理?我没有在文档中找到任何内容。 最佳答案 我遇到了同样的问题;这是我的XML:我在用这个:entries.to_xml将散列数据转换为XML,但这会将条目的数据包装到中所以我修改了:entries.to_xml(root:"Contacts")但这仍然将转换后的XML包装在“联系人”中,将我的XML代码修改为

  3. ruby - Ruby 的 Hash 在比较键时使用哪种相等性测试? - 2

    我有一个围绕一些对象的包装类,我想将这些对象用作散列中的键。包装对象和解包装对象应映射到相同的键。一个简单的例子是这样的:classAattr_reader:xdefinitialize(inner)@inner=innerenddefx;@inner.x;enddef==(other)@inner.x==other.xendenda=A.new(o)#oisjustanyobjectthatallowso.xb=A.new(o)h={a=>5}ph[a]#5ph[b]#nil,shouldbe5ph[o]#nil,shouldbe5我试过==、===、eq?并散列所有无济于事。

  4. java - 等价于 Java 中的 Ruby Hash - 2

    我真的很习惯使用Ruby编写以下代码:my_hash={}my_hash['test']=1Java中对应的数据结构是什么? 最佳答案 HashMapmap=newHashMap();map.put("test",1);我假设? 关于java-等价于Java中的RubyHash,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/22737685/

  5. ruby - 如何将 lambda 传递给 Hash.each? - 2

    如何将lambda传递给hash.each,以便我可以重复使用一些代码?>h={a:'b'}>h.eachdo|key,value|end=>{:a=>"b"}>test=lambdado|key,value|puts"#{key}=#{value}"end>test.call('a','b')a=b>h.each&testArgumentError:wrongnumberofarguments(1for2)from(irb):1:in`blockinirb_binding'from(irb):5:in`each'from(irb):5from/Users/jstillwell/.rv

  6. Ruby:行 "m = Hash.new {|h,k| h[k] = []}"完成了什么而 "Hash.new"没有完成? - 2

    一边学习thisRailscast我从Rack中看到了以下源代码:defself.middleware@middleware||=beginm=Hash.new{|h,k|h[k]=[]}m["deployment"].concat[[Rack::ContentLength],[Rack::Chunked],logging_middleware]m["development"].concatm["deployment"]+[[Rack::ShowExceptions],[Rack::Lint]]mendend我的问题是关于第三行。什么是传递block{|h,k|h[k]=[]}到Has

  7. ruby-on-rails - 在 Ruby 或 Rails 中,hash.merge({ :order => 'asc' }) can return a new hash with a new key. 什么可以返回带有已删除键的新散列? - 2

    在Ruby(或Rails)中,我们可以做到new_params=params.merge({:order=>'asc'})现在new_params是一个带有添加键:order的散列。但是是否有一行可以返回带有已删除key的散列?线路new_params=params.delete(:order)不会工作,因为delete方法返回值,仅此而已。我们必须分3步完成吗?tmp_params=paramstmp_params.delete(:order)returntmp_params有没有更好的方法?因为我想做一个new_params=(params[:order].blank?||para

  8. ruby object.hash - 2

    一个对象的散列值是什么意思?在什么情况下两个对象具有相同的哈希值??还有说Array|Hash不能是Hashkeys,这个跟对象的hash值有关系,为什么? 最佳答案 对于要存储在HashMap或哈希集中的对象,必须满足以下条件:如果认为两个对象相等,则它们的哈希值也必须相等。如果两个对象不被认为是相等的,那么它们的哈希值应该很可能不同(两个不同的对象具有相同哈希值的次数越多,对HashMap/集合的操作性能就越差)。因此,如果两个对象具有相同的哈希值,则很有可能(但不能保证)它们相等。上面“相等”的确切含义取决于散列方法的实现者。

  9. ruby-on-rails - Order Hash 并删除第一个键值对 - 2

    我有一个以时间戳为键的哈希。hash={"2016-05-31T22:30:58+02:00"=>{"path"=>"/","method"=>"GET"},"2016-05-31T22:31:23+02:00"=>{"path"=>"/tour","method"=>"GET"},"2016-05-31T22:31:05+02:00"=>{"path"=>"/contact_us","method"=>"GET"}}我订购了这个系列并得到了第一双这样的:hash.sort_by{|k,_|k}.first.first但是我该如何删除它呢?删除方法requiresyou知道key的准确

  10. ruby - 减少数组时使用 Hash.new 作为初始值 - 2

    我有一个这样的数组[1,1,2,3,3,3,4,5,5]我想计算每个数字出现的次数,我正在尝试这样做[1,1,2,3,3,3,4,5,5].reduce(Hash.new(0)){|hash,number|hash[number]+=1}问题是当我尝试运行它时出现以下错误NoMethodError:undefinedmethod`[]='for1:Fixnumfrom(irb):6:in`blockinirb_binding'from(irb):6:in`each'from(irb):6:in`reduce'from(irb):6我能像这样设置初始值吗,还是我弄错了?

随机推荐