Redis各种数据类型的使用场景举例分析【一】


Redis官方的介绍:Redis 是完全开源免费的,遵守BSD协议,先进的key - value持久化产品。它通常被称为数据结构服务器,因为值(value)可以是字符串(String), 哈希(Map), 列表(list), 集合(sets) 和有序集合(sorted sets)等类型。 通过最近一直看公司的代码慢慢了解实际的运用和使用,记录下各种数据类型在我们项目中的运用,结合php的数组和mysql数据一起对比记录。 整个项目的背景介绍,类似与豆瓣的社区,有帖子,有图片,有相册,有小组,有粉丝,可以评论,可以赞。

【一】字符串(String)

字符串的功能比较简单单一,容易理解的,类比一个数组的key-value。由于其数据结构的简单,所以也是来做简单的事,比如统计所有的小组数目,所有的相册数目,因为这些数据属于整个项目。

//用户创建相册的操作,以ThinkPHP的ORM为例
$data = array('name'=>'梦康的相册','create_id'=>'1','create_time'=>time());
$res = M('ablum')->add($data);
if($res){
	//全站相册总数加一
	$redis->incr('ablumCount');
}

那么某个用户的相册总数应该怎么存呢?

可以继续使用String来存储

$reids->set('user:1:ablumNum',1000)//设置id为1的用户的相册数为1000

上面的key的设计原则是:object-type:id:field,从对象的角度来分析,一个用户对象,name,ablumNum,groupNum等都是他的成员属性,如果是从数据的角度来分析,则是user表里面的id为1的用户的ablum_num字段的数据。

新增一个需求:如果需要取出相册总数前十的用户,怎么排序呢?

就应该考虑使用有序集合(sorted sets),这个后面说。


【二】哈希(Map)

hashMap的使用场景,hashMap特别适合用于存储对象。 相较于将对象的每个字段存成单个string类型,将一个对象存储在hash类型中会占用更少的内存,并且可以更方便的存取整个对象。

用户ID为查找的key,存储的value用户对象包含姓名,年龄,生日等信息,如果用普通的key/value结构来存储,主要有以下2种存储方式:

第一种方式将用户ID作为查找key,把其他信息封装成一个对象以序列化的方式存储,这种方式的缺点是,增加了序列化/反序列化的开销,并且在需要修改其中一项信息时,需要把整个对象取回。

第二种方法是这个用户信息对象有多少成员就存成多少个key-value对儿,用用户ID+对应属性的名称作为唯一标识(id:name,id:age,id:birthday)来取得对应属性的值,虽然省去了序列化开销和并发问题,但是一个用户ID为重复存储了三次,如果存在大量这样的数据,内存浪费还是非常大的。


【三】列表(List)

redis的list类型其实就是一个每个子元素都是string类型的双向链表。我们可以通过push,pop操作从链表的头部或者尾部添加删除元素。这使得list既可以用作栈,也可以用作队列。

产品运营总会让你展示最近、最热、点击率最高、活跃度最高等等条件的top list。注意list有做排行榜的功能,但是list却不方便在中间插入。如果某一个排行榜,确定是一小时跑一次,而不用中途又去人工干预,那么就可以使用list。如果需要后期人工干预排行榜,则最好是使用zsets的结构,可以后期插入。


【四】集合(sets)

集合使用的好处是快速往集合里插入一个元素,删除一个元素,确定一个元素是否存在于该集合。使用到的场景就是一个用户的粉丝,数据模型就是一对多的情况,一个用户可能有N个粉丝,所以就可以选择集合的数据结构。

$key = "user:$user:fans";
//$fansArr 是粉丝数组
foreach($fansArr as $fans){
	$redis->sAdd($key, $fans['id']);
}


【五】有序集合(zsets)

有序集合在项目中使用的最多,因为其比较方便做分页查询,比较容易控制顺序。比如我们项目中对搜索结果的数据就以zsets的结构来存的。因为方便排序。比如一个壁纸的关键字会有很多图片,以大家的点赞数来降序排列。

$key = "tagid:$id:search";
$redis->multi(Redis::PIPELINE);
foreach ($imagesArr as $image){
	//把点赞数作为权重,图片的id作为值
    $redis->zAdd($key, $image['fav_num'], $image['id']);
}
$redis->exec();

比如现在壁纸的搜索结果已经存在了,但是又有一位原创用户自己手绘的质量非常高的壁纸上传,这个时候,这个质量非常高的壁纸却没有阅读量,就没有点赞数,也不会存在于搜索列表的前面,所以需要人工干预下,给该图片增加一些权重,放入对应的缓存中,这样就实时更新了。


以上的这些情景基本涵盖了redis的一些比较有特色的使用情况吧。


上一篇 下一篇

评论

登录后可发表评论