Redis学习(3)--hash

Redis基础篇–hash

hash

内部实现: 类似于JAVA的HashMap。也是数组+链表的二维结构。rehash不同,是渐进式rehash策略。

常见命令:
hset books java "think in java" #设置key为books,field为java,value为"think in java"
hgetall books #entries(),key和value间隔出现
hlen books# 获取map的长度
hmset books  java "effective java" python "learning python"#批量set

hset user age 18#设置age为18
hincrby user age 1 #执行自增操作
探索字典内部

字典是Redis服务器中出现最为频繁的复合型数据结构,除了hash结构的数据会用到字典(dict)外,整个redis数据库的所有key和value也组成了一个全局字典,还有带过期时间的key集合也是一个字典。zset集合中存储value和score值的映射关系也是通过字典结构实现的。

struct RedisDb {
	dict	* dict;         /* all keys key=>value */
	dict	* expires;      /* all expired keys key=>long(timestamp) */
	...
}
struct zset {
	dict		*dict; /* all values value=>score */
	zskiplist	*zsl;
}
内部实现
struct dict {
	...
	dictht ht[2];
}
struct dictEntry {
	void		* key;
	void		* val;
	dictEntry	* next;         /* 链接下一个entry */
}

struct dictht {
	dictEntry	** table;       /* 二维 */
	long		size;           /* 第一维数组的长度 */
	long		used;           /* hash表中的元素个数 */
	...
}

图5-4

如上图所示,字典结构内部包含两个hashtable,通常情况下只有一个hashtable是有值的,但是在字典扩缩容时,需要分配新的hashtable,然后进行渐进式搬迁,这时候两个hashtable存储的分别是旧的hashtable和新的hashtable。待搬迁结束后,旧的hashtable被删除,新的hashtable取而代之。

在这里插入图片描述

hashtable的结构与Java的HashMap几乎是一样的,都是通过分桶的方式解决hash冲突。第一维是数组,第二维是链表。如上图所示。

hash函数

Redis的字典默认的hash函数是siphash.

hash攻击

如果hash函数存在偏向性,黑客就可能利用这种偏向性对服务器进行攻击。存在偏向性的hash函数在特定模式下的输入会导致hash第二维链表长度极为不均匀,甚至所有的元素都集中到个别链表中,直接导致查询效率急剧下降,从O(1)退化到O(n),有限的服务器计算能力将会被hashtable的查找效率彻底拖垮。这就是所谓的hash攻击。

扩容条件

正常情况下,当hash表中的元素的个数等于第一维数组的长度时,就会开始扩容,扩容的新数组是原数组大小的2倍。不过如果redis正在做bgsave,为了减少内存页的过多分离(Copy On Write),Redis尽量不去扩容(dict_can_resize),但是如果hash表已经非常满了,元素的个数已经达到了第一维数组长度的5倍(dict_force_resize_ratio),说明hash表已经过于拥挤了,这个时候就会强制扩容。

缩容条件

当hash表因为元素逐渐被删除变得越来越稀疏时,Redis就会hash表进行缩容来减少hash表的第一维数组占用空间。缩容的条件是元素个数低于数组长度的10%。缩容不会考虑redis是否正在做bgsave。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值