redis面试题有一个出现频率很高的问题是,你们用什么数据结构,如果你回答hash表,那么面试官马上会追问为什么?老实说手写红黑树确实有些面试造火箭,但是redis有没用过hash优化内存,真的是一个菜鸟和高手的分水岭,我上一个实验你就能看出有多大的意义。
测试场景:
我们有三十万个简单的key,value就是1到300000,默认情况我们用key value的方式直接存入redis,这也是一般小公司未优化的实现方式。
public void run(){
for(int i=1;i<300000;i++){
redisTemplateFastJson.opsForValue().set("key" +i, i, 5, TimeUnit.MINUTES);
}
}
内存占用是31.56M
image.png
用hash的方式再做一次。
将三十万个key,用key值除于100的结果为hash表的索引,将余数作为hash表的field。所以三十万个key将得到3000个hash表,每个hash表有100个元素。
代码如下
public void runForZiplist(){
for(int i=1;i<300000;i++){
Integer left = (i/100);
Integer mod = (i%100);
String hash = "hash_"+ left;
HashOperations<String, String, Integer> vo = redisTemplateFastJson.opsForHash();
vo.put(hash, mod.toString(), i);
}
}
查看redis内存占用,只用了3.57M
image.png用了hash后取值方式需要做一些变化:
public void getHash(){
HashOperations<String, String, Integer> vo = redisTemplateFastJson.opsForHash();
for(int i=1; i<1000;i++){
Integer left = (i/100);
Integer mod = (i%100);
String hash = "hash_"+ left;
log.info("key:" +i +" value:"+vo.get(hash, mod.toString())); ;
}
}
可以看到取到的value值是正确的,只是多加了2行原始key到新key的转换代码,性能没有损失,内存占用却大大减少,原因就是hash结构在key和value符合一定条件下会用ziplist结构存储,超过这个条件才会用普通的字典存放,而ziplist因为其特殊的结构是可以省内存的。
image.png需要注意的是,ziplist是连续储存,从100个filed里取一个是也是顺序查找,所以如果一个hash表存上万个值,取值肯定是会变慢,程序在设计key的分裂算法时候需要注意,一般几百个就差不多了。
网友评论