嗨,老铁,欢迎来到我的博客!

如果觉得我的内容还不错的话,可以关注下我在 segmentfault.com 上的直播。我主要从事 PHP 和 Java 方面的开发,《深入 PHP 内核》作者之一。

[视频直播] PHP 进阶之路 - 亿级 pv 网站架构的技术细节与套路 直播中我将毫无保留的分享我这六年的全部工作经验和踩坑的故事,以及会穿插着一些面试中的 考点难点加分点

周梦康 发表于 2014-10-20 5334 次浏览 标签 : redis

Redis官方的介绍:Redis 是完全开源免费的,遵守BSD协议,先进的key - value持久化产品。它通常被称为数据结构服务器,因为值(value)可以是字符串(String), 哈希(Map), 列表(list), 集合(sets) 和有序集合(sorted sets)等类型。

通过最近一直看公司的代码慢慢了解实际的运用和使用,记录下各种数据类型在我们项目中的运用,结合php的数组和mysql数据一起对比记录。

整个项目的背景介绍,类似与豆瓣的社区,有帖子,有图片,有相册,有小组,有粉丝,可以评论,可以赞。

1.字符串(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),这个后面说。

2.哈希(Map)

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

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

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

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

详见:http://tech.it168.com/a2011/0818/1234/000001234478_all.shtml

3.列表(list)

redis的list类型其实就是一个每个子元素都是string类型的双向链表。我们可以通过push,pop操作从链表的头部或者尾部添加删除元素。这使得list既可以用作栈,也可以用作队列。
产品运营总会让你展示最近、最热、点击率最高、活跃度最高等等条件的top list。注意list有做排行榜的功能,但是list却不方便在中间插入。如果某一个排行榜,确定是一小时跑一次,而不用中途又去人工干预,那么就可以使用list。如果需要后期人工干预排行榜,则最好是使用zsets的结构,可以后期插入。

4.集合(sets)

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

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

如果某一个用户对其取消了关注,那么就从该集合里删除。如果之前选择了list则不方便实现了

$redis->sMove($key, $fans['id']);

5.有序集合(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的一些比较有特色的使用情况吧。以后有新的收获再补。

嗨,老铁,欢迎来到我的博客!

如果觉得我的内容还不错的话,可以关注下我在 segmentfault.com 上的直播。我主要从事 PHP 和 Java 方面的开发,《深入 PHP 内核》作者之一。

[视频直播] PHP 进阶之路 - 亿级 pv 网站架构的技术细节与套路 直播中我将毫无保留的分享我这六年的全部工作经验和踩坑的故事,以及会穿插着一些面试中的 考点难点加分点

评论列表

回复 周梦康 2014-12-29 22:52:14
节约内存:Instagram的Redis实践 http://blog.nosqlfan.com/html/3379.html