redis 用hashmap省内存的误解

redis 用hashmap省内存的误解,第1张

看过许多redis优化的案例,通过引入hashmap的方式将key散列到多个hashmap,

具体可以见:

Redis 利用Hash存储节约内存 - 刘本龙的专栏 - CSDN博客

我们得到如下公式:

原来是:

key1,key2,key3,key4,key5

变成

hash1:

key1:value1

key2:value2

key3:value2

hash2:

key4:value4

key5:value5

虽然名义上5个key变成了2个hashmap,但是每个filed还是会保存原始的key,所以从key减少的层面是行不通的,这个时候就要从底层储存结构去看。

redis对hashmap有一个优化,当filed数量比较少的时候(因为ziplist是用顺序遍历的方式查找元素,所以数量多了复杂度是o(N)肯定不合适。

),会用一个叫ziplist的结构保存,而不是传统的hash结构,ziplist有几个特点:

ziplist介绍

>

/

@param args

/

public static void main(String[] args) {

//连接 redis 服务

Jedis jedis = new Jedis( "1921688815" ,6379);

//密码验证-如果你没有设置 redis 密码可不验证即可使用相关命令

// jedisauth(" abcdefg ");

//简单的key-value 存储

jedisset( "redis" , "myredis" );

System out println(jedisget( "redis" ));

//在原有值得基础上添加,如若之前没有该key,则导入该key

//之前已经设定了 redis 对应" myredis ",此句执行便会使 redis 对应"myredisyourredis "

jedisappend( "redis" , "yourredis" );

jedisappend( "content" , "rabbit" );

// mset 是设置多个key-value值 参数(key1,value1,key2,value2,, keyn , valuen)

// mget 是获取多个key所对应的value值 参数(key1,key2,key3,, keyn ) 返回的是个list

jedismset( "name1" , "yangw" , "name2" , "demon" , "name3" , "elena" );

System out println(jedismget( "name1" , "name2" , "name3" ));

//map

Map<String,String> user = new HashMap<String,String>();

userput( "name" , "cd" );

userput( "password" , "123456" );

//map存入 redis

jedishmset( "user" , user);

// mapkey 个数

System out println(String format ( "len:%d" , jedishlen( "user" )));

//map中的所有键值

System out println(String format ( "keys: %s" , jedishkeys( "user" ) ));

//map中的所有value

System out println(String format ( "values: %s" , jedishvals( "user" ) ));

//取出map中的name字段值

List<String> rsmap = jedishmget( "user" , "name" , "password" );

System out println(rsmap);

//删除map中的某一个键值 password

jedishdel( "user" , "password" );

System out println(jedishmget( "user" , "name" , "password" ));

//list

jedisdel( "listDemo" );

System out println(jedislrange( "listDemo" , 0, -1));

jedislpush( "listDemo" , "A" );

jedislpush( "listDemo" , "B" );

jedislpush( "listDemo" , "C" );

System out println(jedislrange( "listDemo" , 0, -1));

System out println(jedislrange( "listDemo" , 0, 1));

//set

jedissadd( "sname" , "wobby" );

jedissadd( "sname" , "kings" );

jedissadd( "sname" , "demon" );

System out println(String format ( "set num: %d" , jedisscard( "sname" )));

System out println(String format ( "all members: %s" , jedissmembers( "sname")));

System out println(String format ( "is member: %B" , jedissismember( "sname" , "wobby" )));

System out println(String format ( "rand member: %s" , jedissrandmember("sname" )));

//删除一个对象

jedissrem( "sname" , "demon" );

System out println(String format ( "all members: %s" , jedissmembers( "sname")));

}

二、将自定义对象保存到redis中:

1、自定义pojo 实现Serializable 接口:

package cnmingyuanredis;

import javaioSerializable;

/

测试用 pojo ,实现了 Serializable ,以便进行系列化 *** 作

@author mingyuan

/

public class Person implements Serializable {

private static final long serialVersionUID = -3562550857760039655L;

private String name ;

private int age ;

public Person(){}

public Person(String name, int age) {

super ();

this name = name;

this age = age;

}

public String getName() {

return name ;

}

public void setName(String name) {

this name = name;

}

public int getAge() {

return age ;

}

public void setAge( int age) {

this age = age;

}

@Override

public String toString() {

return "Person [name=" + name + ", age=" + age + "]" ;

}

}

2、测试类:

package cnmingyuanredis;

import javaioByteArrayInputStream;

import javaioByteArrayOutputStream;

import javaioIOException;

import javaioObjectInputStream;

import javaioObjectOutputStream;

import redisclientsjedisJedis;

public class Test {

/

@param args

@throws IOException

@throws ClassNotFoundException

/

public static void main(String[] args) throws IOException,

ClassNotFoundException {

// Jedis redis = new Jedis ("1921688815");

Jedis redis = new Jedis( "1921688815" , 6379);

// connect可以不要,因为在执行set *** 作的时候会先进行判断客户端是否于服务器端建立了连接,若无,则启动连接过程

redisconnect();

String set = redisset( "mingyuan" , "1" );

System out println( " set result \t" + set);

redisincr( "mingyuan" );

String string = redisget( "mingyuan" );

System out println( " get result of key 'mingyuan' \t" + string);

// 下面是对对象进行存储的测试代码

ByteArrayOutputStream bos = new ByteArrayOutputStream();

ObjectOutputStream oos = new ObjectOutputStream(bos);

Person person = new Person( "liudehua" ,22);

ooswriteObject(person);

byte [] byteArray = bostoByteArray();

oosclose();

bosclose();

String setObjectRet = redisset( "mingyuan" getBytes(), byteArray);

System out println( " set object return \t" + setObjectRet);

byte [] bs = redisget( "mingyuan" getBytes());

ByteArrayInputStream bis = new ByteArrayInputStream(bs);

ObjectInputStream inputStream = new ObjectInputStream(bis);

Person readObject = (Person) inputStreamreadObject();

System out println( " read object \t" + readObjecttoString());

inputStreamclose();

bisclose();

redisdisconnect();

}

}

格式 setbit key bitoffset bitValue

定义在字符串类型上的面向位的 *** 作集合

实际使用场景:

1 统计日活 或者 换一种说法,app签到功能

连续签到 功能, 连续的key ,然后bitoffset 做一个按位与的 *** 作

key 是时间 bitoffset 是userId bitvalue 1或者0 ,代表是否登录

redis中字符串限制最大为512M,所以位图中最大可容纳2^32(42亿)个不同的位。

2 视频、文章等等的已读或未读状态

几个人已读

String、Hash、List、Set和Zset。

等同于java中的, Map<String,String> string 是redis里面的最基本的数据类型,一个key对应一个value。

应用场景 :String是最常用的一种数据类型,普通的key/value存储都可以归为此类,如用户信息,登录信息和配置信息等;

实现方式 :String在redis内部存储默认就是一个字符串,被redisObject所引用,当遇到incr、decr等 *** 作(自增自减等原子 *** 作)时会转成数值型进行计算,此时redisObject的encoding字段为int。

Redis虽然是用C语言写的,但却没有直接用C语言的字符串,而是自己实现了一套字符串。目的就是为了提升速度,提升性能。 Redis构建了一个叫做简单动态字符串(Simple Dynamic String),简称SDS。

Redis的字符串也会遵守C语言的字符串的实现规则,即 最后一个字符为空字符。然而这个空字符不会被计算在len里头。

Redis动态扩展步骤:

Redis字符串的性能优势

常用命令 :set/get/decr/incr/mget等,具体如下;

ps:计数器(字符串的内容为整数的时候可以使用),如 set number 1。

补充:

等同于java中的: Map<String,Map<String,String>> ,redis的hash是一个string类型的field和value的映射表, 特别适合存储对象。 在redis中,hash因为是一个集合,所以有两层。第一层是key:hash集合value,第二层是hashkey:string value。所以判断是否采用hash的时候可以参照有两层key的设计来做参考。并且注意的是, 设置过期时间只能在第一层的key上面设置。

应用场景 :我们要存储一个用户信息对象数据,其中包括用户ID、用户姓名、年龄和生日,通过用户ID我们希望获取该用户的姓名或者年龄或者生日;

实现方式 :Redis的Hash实际是内部存储的Value为一个HashMap,并提供了直接存取这个Map成员的接口。如,Key是用户ID, value是一个Map。 这个Map的key是成员的属性名,value是属性值 。这样对数据的修改和存取都可以直接通过其内部Map的Key(Redis里称内部Map的key为field), 也就是通过 key(用户ID) + field(属性标签) 就可以 *** 作对应属性数据。 当前HashMap的实现有两种方式 :当HashMap的成员比较少时Redis为了节省内存会采用类似一维数组的方式来紧凑存储,而不会采用真正的HashMap结构,这时对应的value的redisObject的encoding为zipmap,当成员数量增大时会自动转成真正的HashMap,此时redisObject的encoding字段为int。

常用命令 :hget/hset/hgetall等,具体如下:

等同于java中的 Map<String,List<String>> ,list 底层是一个链表,在redis中,插入list中的值,只需要找到list的key即可,而不需要像hash一样插入两层的key。 list是一种有序的、可重复的集合。

应用场景 :Redis list的应用场景非常多,也是Redis最重要的数据结构之一,比如twitter的关注列表,粉丝列表等都可以用Redis的list结构来实现;

实现方式 :Redis list的实现为一个 双向链表 ,即可以支持反向查找和遍历,更方便 *** 作,不过带来了部分额外的内存开销,Redis内部的很多实现,包括 发送缓冲队列 等也都是用的这个数据结构。

常用命令 :lpush/rpush/lpop/rpop/lrange等,具体如下:

性能总结 :

它是一个字符串链表,left、right都可以插入添加。

等同于java中的 Map<String,Set<String>> ,Set 是一种无序的,不能重复的集合。并且在redis中,只有一个key它的底层由hashTable实现的,天生去重。

应用场景 :Redis set对外提供的功能与list类似是一个列表的功能,特殊之处在于set是可以自动去重的,当你需要存储一个列表数据,又不希望出现重复数据时,set是一个很好的选择,并且 set提供了判断某个成员是否在一个set集合内的重要接口 ,这个也是list所不能提供的;如保存一些标签的名字。标签的名字不可以重复,顺序是可以无序的。

实现方式 :set 的内部实现是一个 value永远为null的HashMap,实际就是通过计算hash的方式来快速排重的,这也是set能提供判断一个成员是否在集合内的原因。

常用命令 :sadd/spop/smembers/sunion等,具体如下:

ZSet(Sorted Set:有序集合) 每个元素都会关联一个double类型的分数score,分数允许重复,集合元素按照score排序( 当score相同的时候,会按照被插入的键的字典顺序进行排序 ),还可以通过 score 的范围来获取元素的列表。

应用场景 :Redis sorted set的使用场景与set类似,区别是set不是自动有序的,而sorted set可以 通过用户额外提供一个优先级(score)的参数来为成员排序,并且是插入有序的,即自动排序。 当你需要一个有序的并且不重复的集合列表,那么可以选择sorted set数据结构,比如twitter 的public timeline可以以发表时间作为score来存储,这样获取时就是自动按时间排好序的。

底层实现 : zset 是 Redis 提供的一个非常特别的数据结构,常用作排行榜等功能,以用户 id 为 value ,关注时间或者分数作为 score 进行排序。实现机制分别是 zipList 和 skipList 。规则如下:

zipList:满足以下两个条件

skipList:不满足以上两个条件时使用跳表、组合了hash和skipList

为什么用skiplist不用平衡树?

主要从内存占用、对范围查找的支持和实现难易程度这三方面总结的原因。

拓展:mysql为什么不用跳表?

常用命令 :zadd/zrange/zrem/zcard等;

官网地址: >

以上就是关于redis 用hashmap省内存的误解全部的内容,包括:redis 用hashmap省内存的误解、redis 记录用户id 用一个map好,还是用hash、java 监听redis map是否有修改等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/web/9816659.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-05-02
下一篇2023-05-02

发表评论

登录后才能评论

评论列表(0条)

    保存