画布 1
Redis常用命令
  命令规律
    在存在多个候选返回值的时候，redis会返回语义更加丰富的返回值。如返回成功或失败，可以直接返回true或false，但返回0既可以表示失败，也可以表示操作的操作数（operand）为0，而返回非0不仅可以告诉我们操作成功了，而且还会精确地告诉我们操作了多少个对象，可谓一举两得。这种设计思路遍布 Redis API 中。
SET 操作估计是唯一一个返回 OK 的API，其他 API 总是会返回新值或者旧值。
    len总代表数目，而strlen则代表字符串长度。具体的用途取决于它们拼接的数据结构是什么。
    redis里涉及区间的 end，都是闭区间的 end。
    index从左至右为0至N-1，从右至左为-1至-N。当我们不知道列表长度的时候，只能用-1表示最后一个元素。
    set -> mset -> hmset。
    strlen -> hstrlen
    用0和1来表示 true和false
  全局命令
    object encoding 查看键对应的对象编码
    type java 查看值的类型
    键管理
      单个键
        expire hello 10 修改已存在的键的超时时间为10秒，如果值为负值，键会立即被删除
        ttl hello 查看键剩余的生命周期，如果返回-2意味着键已被删除
        rename python java 换 key 名称，rename会删除掉 java 的旧值，所以值比较大的时候可能会阻塞 redis 实例（类似关系型数据库的 alter）。python会直接返回nil。
        renamenx python java 如果key不存在，则换 key 名称。这是为了防止误操作。
        randomkey 随机返回一个key
        expireat hello 2000 让一个键在一个特定的秒级时间戳过期
        pexpire hello 10 让一个键在10毫秒后过期
        persist hello 清除过期时间
        注意，如果字符串的value为string类型，set 操作也会去除过期时间。
Redis不支持二级数据结构（例如列表或者哈希）里元素的过期时间。
      迁移键
        move key db
        dump hello
restore hello 0 "\x00\x05world\t\x00\xc9#mH\x84/\x11s"
        migrate 127.0.0.1 6380 "" 0 5000 keys key1 key2 key3 migrate 原子化地结合了 dump、restore和del的操作，可以支持多个键操作。批量地迁移键到目标主机和端口，超时时间为5000
      遍历键
        keys * 可以使用glob模式通配符，显示具体的键名。复杂度O(N)，不建议生产使用。
          redis-cli keys videos | xargs redis-cli del
        scan 0 返回若干个键，而不是值。scan并不是并发安全的。相当于隔离性非常差的事务。
          HSCAN hello 0
          SSCAN hello 0
          zscan hello 0
      数据库管理
        dbsize 复杂度O（1），可以生产使用。但只显示数字。
        SELECT 0 切换到 db 0
        flushdb 清除当前db的所有数据！慎用
        flushall 清除所有db的所有数据！慎用
  性能消耗比较大的命令，可以用 scan 来优化
    keys *
    zrange、lrange 等需要翻页的命令
    smembers 等集合遍历操作
    hgetall 等遍历操作
    集合的交叉并操作
  外部数据结构命令
    string
      基础crud
        del java 删除 key
        exists java 确认 key 是否存在
        set java world ex 10 nx 如果不存在设置 java 为world，超时时间为10秒。
          mset a 1 b 2 c 3 批量赋值
          setnx hello wolrd 若不存在则设值
        get java 查看键的值
          mget a b c d 批量取值，取不到返回nil
      数字视角
        incr java
值不是整数，返回错误
值是整数，返回自增后的结果
值不存在，按照结果为0自增，返回结果1
          incrby java 10 增加整数10
          incrbyfloat java 4.3 增加浮点数 4.3
        dcr java
          decrby java 5
          没有 decrbyfloat 命令
      字符串视角
        append hello 123 返回最后结果的长度
        strlen hello 返回结果的长度
        getset hello world123 原子化地设值并返回旧值
        setrange hello 1 a 设值指定位置的字符，返回修改后的字符串长度
        getrange hello 1 2 设定指定位置的值，并返回。start 和 end 都是闭区间
      字节视角
        注意，大距离的 setbit 要申请大内存，很消耗性能
        getbit hello 10 把键的 offset 的位取出来，如果offset无值，则取0
        setbit hello 1000 1 把键的 offset 的位设值，只能设值0或1，返回旧值。
        bitcount hello 返回范围内设值的位值的数量
        BITPOS hello 0 范围内指定值（0或1）的第一个位置 O(N)
        用例
          用户签到
          用户在线状态
          统计活跃用户
          各种状态值
      用例
        缓存，特别是不常见的信息，如用户信息
        计数
        共享session 用户登录信息，用户会话内部状态
        限速
    hash
      基础crud
        hset user:1 name tom 设值，在 key 和 value 之间加入了一个 field
          hsetnx user:1 name jerry 若 field 不存在，则设值
          hmset user:1 name tom age 20 city beijing 批量设值
          hmget user:1 name age city 批量获取
        hget user:1 name 取值，在 key 和 value 之间加入了一个 field
        hdel user:1 name 删除 field，而不删除key
        hlen user:1 计算 key 数目
        hexists user:1 name 判断一个 field 是否存在
        hkeys user:1 遍历一个key下面所有的fields，实际上应该叫 hfields比较恰当。时间复杂度为O(N)。一个key下面的N比较小的时候，可以直接在生产上使用。
        hvals user:1 遍历一个key下面所有的 fields 的值
        hgetall user:1 遍历一个 key 下面所有的 fields 和值
      数字视角
        hincrby user:1 age 10 按照指定值加值，这里的命令没有缺省被加数1了，必须显式指定被加数
        hincrbyfloat user:1 age 5.1 按照指定值加浮点值，这里的命令没有缺省被加数1了，必须显式指定被加数
      字符串视角
        hstrlen user:1 name 获取一个 key 下面指定 field 的字符串长度
    list
1 可以存储多个元素
2 靠 index 有序存储
      基础crud
        rpush listkey c b a 从右至左插入元素，这个命令天然就是多参数的
        lpush listkey c b a 从左至右插入元素，这个命令天然就是多参数的
        lrange listkey 0 -1 按范围取元素
        linsert listkey before b java 在枢轴前后插入元素，注意方向和前后的关系
        LINDEX listkey -1 获取指定 index 的元素
        llen listkey 获取指定 key 的 size
        lpop listkey 列表类型总是没有删除操作，而使用弹出操作作为替代品
        lrem listkey 1 a 从左至右删除元素，1表示从左至右删除1个元素，0表示删除全部元素，-1表示从右至左删除1个元素
        LTRIM listkey 1 -1 保留列表的1到最后一个元素-即去掉第一个元素
        LSET listkey 1 python 设置特定 index 的元素的 value，这里的 index 不能 out of bound。
      阻塞操作
        blpop listkey1 listkey2 20 从左至右阻塞操作，第一个返回值总是 listkey1，只要有一个元素可以弹出，blpop就会立即返回。如果时间参数为0，则无限阻塞。可以使用这个命令制造一个延时队列、阻塞队列。blpop 可以同时监听多个 key，类似 selector 方案。每个 value 只能在多个客户端中被 pop 一次。
    set
1 类似 list
2 不能有重复元素
3 无序存储
      基础crud
        注意不是len，而是cardinality
        sadd myset a b c d 往集合里加元素，因为是无序的，所以也无所谓insert和左右
        srem myset a b 指名道姓直接删除集合里的元素
        scard myset 计算集合的大小，注意这不是len。直接使用内置变量，所以其操作时间复杂度为 O(1)。
        sismember myset d 确认 d 是不是 myset 的元素
        srandmember myset 1 从集合中随机弹出1个元素。因为强调 set 是无序的，所以产生了这个操作。
        srandmember myset 默认值为1
        spop myset 1 从集合中弹出一个元素，元素会被删除
        smembers myset 获取集合中的所有元素
      集合操作
        sinter myset1 myset2
求交集
          注意destinationkey的位置
          sinterstore interset myset1 myset2
因为集合操作比较耗时（m*n的乘法二项式复杂度），求交集并存储到目标key里。
        sunion myset1 myset2
求并集
          注意destinationkey的位置
          sunionstore unionset myset1 myset2 因为集合操作比较耗时（m*n的乘法二项式复杂度），求并集并存储到目标key里。
        sdiff myset1 myset2 求差集
          注意destinationkey的位置
          sdiff myset1 myset2 因为集合操作比较耗时（m*n的乘法二项式复杂度），求差集并存储到目标key里。
        用例
适合表达小范围的、可以穷举的值域
          sadd = tagging打标签
            要注意在一个事务里执行
            1 给标签建模，把标签加到用户-标签中间表上
2 把用户加到标签-用户中间表上
          spop/srandmembers = Random Item
            生成随机数
          sadd + sinter = social graph
    zset
1 元素不能重复
2 元素可以有score，score可以重复
3 靠 score 可以实现排序
4 其他同 set
      基础crud
        zadd user:ranking 250 tom 1 kris 91 mike 200 frank 220 tim 250 martin 给一个 zset 增加，成员，先写score再写元素。因为有这个排序操作，这个操作的时间复杂度是O(log(n))。也支持 nx、xx、ch、incr 几个 argument。
        zcard user:ranking 获取集合大小。时间复杂度O(1)。
        zscore user:ranking tom 获取集合中指定成员的分数
        zrank user:ranking tom 获取集合中指定成员的从低到高排名
        zrevrank user:ranking tom 获取集合中指定成员的从高到低排名
        zrem user:ranking tom 删除集合中指定成员
        zincrby user:ranking 10 tom 增加集合中指定成员的score
        zrange user:ranking 0 1 withscores 返回集合中从低到高指定排名的成员，withscores 可以被去掉
        zrevrange user:ranking 0 1 withscores 返回集合中从高到低指定排名的成员，withscores 可以被去掉
        zrangebyscore user:ranking 200 250 withscores 返回集合中从低到高指定分数范围的成员，withscores 可以被去掉。此外也支持开、闭区间、正负无穷参数。
        zrevrangebyscore user:ranking 250 200 withscores 返回集合中从高到低指定分数范围的成员（注意，参数是反的），withscores 可以被去掉。此外也支持开、闭区间、正负无穷参数。
        zcount user:ranking 200 250 返回集合中指定分数段的成员的数量
        zremrangebyrank user:ranking 0 2 删除集合中指定排名的成员
      集合操作
        zinterstore user:ranking:1_inter_0 2 user:ranking:1 user:ranking:2 交集聚合存储操作，2代表了要做交集的 keys 数目。如果不指定聚合类型，结果就是加权后相加sum。
        zinterstore user:ranking:1_inter_0 2 user:ranking:1 user:ranking:2 weights 1 0.5 aggregate max 交集聚合存储操作，2代表了要做交集的 keys 数目。1代表集合1的权重，0.5代表集合2的权重。
        zunionstore user:ranking:1_inter_0 2 user:ranking:1 user:ranking:2 并集聚合存储操作
      用例
        社交网络排行榜：
1 zadd user:ranking:2016_03_15 3 mike
2 zincrby user:ranking:2016_03_15 1 mike
3 zrem user:ranking:2016_03_15 mike
4 zrerangebyrank user:ranking:2016_03_15 0 9
5 hgetll user:info:tom
6 zscore user:ranking:2016_03_15 mike
7 zrank user:ranking:2016_03_15 mike
    用例
      储存用户信息比 string更好，因为它支持更细颗粒度的操作。把用户的属性单独制作成列或者使用大json，都不是很好的选择 - 它类似于MySQL支持的Json查询。
    用例
      使用阻塞队列（lpush + brpop）来实现负载均衡和高可用
      文章列表
        文章放在 hash里
        hash 的 key 放在 user的 list 里，然后用 getall 来获取结果。如果这样做对 IO 影响比较大，可以考虑使用 pipeline 机制。
        这是一个值得优化的case
      lpush + lpop = stack
      lpush + rpop = queue
      lpush + ltrim = Capped Collection
      lpush + brpop = Message Queue