转发:https://mengkang.net/356.html

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 表里面的 id1 的用户的 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)

redislist 类型其实就是一个每个子元素都是 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的一些比较有特色的使用情况吧。以后有新的收获再补。