redis入门之retwis

retwis是redis之父antirez在项目初期, 为了推广redis而写的一个迷你版twitter,同时还为此写了一个教程 介绍redis的数据类型以及如何使用它们构建一个高性能的web app。

这里对retwis学习做个小结。

redis数据类型

redis支持5种数据类型:string,list,set,ordered set和hash, 另外还支持Bitmap和HyperLogLog两种类型(暂未了解), 具体见文档

  • string

    字符串,可以用于存放浮点数和整数,redis不提供整型类型, 而是根据看具体的指令是否以整型的方式进行运算, 比如incr指令可以实现整数字符串的递增。

  • list

    列表,可以从左右两端插入或者弹出数据,LRANGE指令可以用于取其中一段范围的数据(分页功能)。 另外list中只能存放字符串。

  • set

    集合,其中的元素不会重复,元素是无序的。

  • sorted set

    也叫zset,与set类似,其中的元素不能重复。 但是,每个元素有一个score,redis可以据此对元素进行排序。

  • hash

    散利表,存储的就是一堆键值对(都只能是字符串)。

retwis数据模型

以下列出了retwis中使用到的key,其中第一行表示key, 后面紧跟着缩进一级的是存储的值的具体内容。

  • 用户信息

    记录“表”

    user:n(hash)    # key为user:n,其中n为用户id,比如user:1, user:2;(hash)表示类型为hash
        {
            "username"  -> $name    #"string" 表示键名就是字面值(literal string),$var表示变量值。
            "password"  -> $passwd
            "auth"      -> $secret
        }
    
    next_user_id(string)
        $id         # 每次加一的用户id
    

    用户名“索引”

    users(hash)     # 用户名到id的映射,相当于user的username列的索引
        {
            "name" -> $uid,
            ...
        }
    

    用户密码“索引”

    auths(hash)     # 用户secret到id的映射
        {
            "secret" -> $uid,
            ...
        }
    
  • 粉丝

    followers:n(zset)   # 用户n的粉丝,score为unix time
        [
            $unixtime:$uid,
            ...
        ]
    
  • 关注的人

    following:n(zset)   # 用户n的“关注的人”,score为unix time
        [
            $unixtime:$uid,
            ...
        ]
    
  • 微博“表”

    post:n(hash)        # user timeline,显示在用户n主页的。
        {
            "user_id"   -> $user_id
            "body"      -> $post_content
            "time"      -> $time
        }
    
    next_post_id(string)
        $id             # 每次加一的微博id
    
  • 用户发表的微博列表

    posts:n(list)       # 用户n发表的帖子
        [$pid, $pid, ..., $pid]
    
  • timeline

    timeline(list)  # 保存所有用户发表的post id,取最近1000个。
        [$pid, $pid, ..., $pid]
    
  • 最新注册的用户列表

    users_by_time(zset)     # timeline 中展示
        [
            $time:$uid,
            ...
        ]
    

redis数据建模

从传统的关系型数据库角度来看下redis如何进行数据建模。

如何实现关系数据库表?

对于实体对象(如用户),每个用户都有一个key。 每个key都是用对象名和id组成,中间加分隔符进行区分, 比如“user:123”表示用户id为123的用户对象。

这样的一个key,相当于关系数据库表中的一行,id就是其中的行id。

对象一般用hash类型表示,hash中的每个键表示一个属性; 而id因为已经包含在hash自身的键名中,故无须再另外保存一个hash键。

而对象的id,需要通过另一个存放正整数的字串key进行自增(incr指令)得到, 如上边的next_user_idnext_post_id,从而手动实现了MySQL中auto_increment功能。

如何实现关系数据库的索引?

如果需要对对象中的某一列键索引,需要在redis中建一个单独的存放此“列”的key,类型为hash。 hash中的每个键都是此“列”的值,值为对象id。 比如上面的users键,hash中的每一个键都是一个用户名,值是此用户的id。

另外,redis不支持根据值反查键名。

如果用MySQL表来表示用户,那么建表SQL大概是这样:

CREATE TABLE `userx` (
  `user_id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '相等于redis中的next_user_id键',
  `username` char(50) NOT NULL COMMENT 'redis中的user:n中的键',
  `password` char(50) NOT NULL COMMENT 'redis中的user:n中的键',
  `auth` char(50) NOT NULL COMMENT 'redis中的user:n中的键',
  PRIMARY KEY (`user_id`),
  KEY `users` (`username`) COMMENT 'redis中的users键',
  KEY `auths` (`auth`) COMMENT 'redis中的auths键'
) ENGINE=MyISAM DEFAULT CHARSET=utf8

其他

list和zset中的数据都是有序的,前者根据插入顺序有序,后者根据得分有序。 zset常用于需要按照时间顺序排列的数据。

PHP的session机制会导致应用无法水平扩展,因为session文件是直接保存在本机的文件系统中的。

social