Redis内存数据库
查询发生全量i/o
内存和磁盘读写速度相差五到十万倍
GBK 中一个汉字占两个字节
UTF-8中的一个汉字占三个字节
Set key1 中
STRLEN key1 3
Set key2 123
STRLEN key2 3
Redis2.8单机安装,3.0以后的版本才支持集群安装
- 编译安装:
- yum -y install gcc tcl -y
- tar xf redis-2.8.18.tar.gz
- make
- make PREFIX=/opt/sxt/redis install
- export REDIS_HOME=/opt/sxt/redis
- export PATH=$PATH:$REDIS_HOME/bin
- utils目录:
- ./install_server.sh
- 启动:
- 程序+配置:不同的配置产生多个实例程序
- 端口号,持久化数据目录
- Redis key 值是二进制安全的,这意味着可以用任何二进制序列作为key值,从形如”foo”的简单字符串到一个JPEG文件的内容都可以。空字符串也是有效key值
- Key取值原则
键值不需要太长,消耗内存,且在数据中查找这类键值的计算成本较高
键值不宜过短,可读性较差
String:
- String:(strlen)
- 基本操作是字符串操作,追加,截取
- set,get,apend。。。。。。
- 数值类型计算
- 位图
- 基本操作是字符串操作,追加,截取
- 字符串是一种最基本的Redis值类型。Redis字符串是二进制安全的,这意味着一个Redis字符串能包含任意类型的数据
例如: 一张JPEG格式的图片或者一个序列化的Ruby对象
- 一个字符串类型的值最多能存储512M字节的内容
- key : string
- value: string
登录客户端后,获取帮助
Help
Help <tab>
Help set
Help @string
- 设置字符串值 set get
- SET key value [EX seconds] [PX milliseconds] [NX|XX]
- EX 设置过期时间,秒,等同于SETEX key seconds value
- PX 设置过期时间,毫秒,等同于PSETEX key milliseconds value
- NX 键不存在,才能设置,等同于SETNX key value
- XX 键存在时,才能设置
- SET key value [EX seconds] [PX milliseconds] [NX|XX]
- 设置多个键的字符串值
- MSET key value [key value ...] mget
- 键不存在时,设置字符串值
- MSETNX key value [key value ...]
- 注意:这是原子操作
事例: set s1 abc
set s2 12
set se abc ex 15
mset s3 3 s4 4 s5 5
msetnx s5 A5 s6 6
- 过期
- Redis中可以给Key设置一个生存时间(秒或毫秒),当达到这个时长后,这些键值将会被自动删除
- 设置多少秒或者毫秒后过期
- EXPIRE key seconds
- get key
- set key val ex 10
- PEXPIRE key milliseconds
- 设置在指定Unix时间戳过期
- EXPIREAT key timestamp
- PEXPIREAT key milliseconds-timestamp
- 删除过期
- PERSIST key
- 生存时间
- Time To Live,Key的剩余生存时间
- 查看剩余生存时间
- TTL key
- PTTL key
- key存在但没有设置TTL,返回-1
- key存在,但还在生存期内,返回剩余的秒或者毫秒
- key曾经存在,但已经消亡,返回-2(2.8版本之前返回-1)
事例:set se abc ex 15
ttl s6
expire s6 60
pttl s6
persist s6
pttl s6
EXPIREAT cache 1355292000
PEXPIREAT mykey 1555555555005
- 查找键
- KEYS pattern
- pattern取值
- * 任意长度字符
- ? 任意一个字符
- [] 字符集合,表示可以是集合中的任意一个
事例: keys s*
keys s?
keys s[13]
keys *
keys ??
- 键类型
- TYPE key
- object encoding key
- 键是否存在
- EXISTS key
- 键重命名
- RENAME key newkey
- RENAMENX key newkey
- 键删除
- DEL key [key ...]
- 获取值
- GET key
- 获取多个给定的键的值
- MGET key [key ...]
- 返回旧值并设置新值
- GETSET key value
- 如果键不存在,就创建并赋值
- 字符串长度
- STRLEN key
- object encoding key > val 底层存储的数据结构类型
- 追加字符串
- APPEND key value
- 如果键存在就追加;如果不存在就等同于SET key value
- 获取子字符串 索引
- GETRANGE key start end
- 0 3
- 索引值从0开始,负数表示从字符串右边向左数起,-1表示最有一个字符
- 01234
- 1a2a3a
- -5 -4 -3 -2 -1
- 覆盖字符串
- SETRANGE key offset value
事例: APPEND s6 123
getrange s1 1 2
getrange s1 0 -1
getrange s1 -2 -1
getrange s1 0 10000
SETRANGE s6 3 e
SETRANGE s6 3 efghijk
SETRANGE newkey 5 hello
SETRANGE s6 3 efghijk
- 步长1的增减
- INCR key
- DECR key
- 字符串值会被解释成64位有符号的十进制整数来操作,结果依然转成字符串
- 步长增减 float
- INCRBY key decrement
- DECRBY key decrement
- 字符串值会被解释成64位有符号的十进制整数来操作,结果依然转成字符串
位图bitmap 【字节数组】
- 位图不是真正的数据类型,它是定义在字符串类型中
- 一个字符串类型的值最多能存储512M字节的内容
- 位上限:2^(9+10+10+3)=2^32b
- 设置某一位上的值
- SETBIT key offset value 0/1
- offset偏移量,从0开始
- 获取某一位上的值
- GETBIT key offset
- 返回指定值0或者1在指定区间上第一次出现的位置
- BITPOS key bit [start] [end]
- 0 1 0 0 0 0 0 1 A
- 0 1 0 0 0 0 1 0 B
事例:
set str1 ab
setbit str1 6 1
setbit str1 7 0
get str1 结果为:bb
- 位操作
-
-
- 0 1 0 0 0 0 0 1
- 1 1 1 0 0 0 0 1
- 1 1 1 0 0 0 0 1
-
- 对一个或多个保存二进制位的字符串 key 进行位元操作,并将结果保存到 destkey 上
- operation 可以是 AND 、 OR 、 NOT 、 XOR 这四种操作中的任意一种
- BITOP AND destkey key [key ...] ,对一个或多个 key 求逻辑并,并将结果保存到 destkey
- BITOP OR destkey key [key ...] ,对一个或多个 key 求逻辑或,并将结果保存到 destkey
- BITOP XOR destkey key [key ...] ,对一个或多个 key 求逻辑异或,并将结果保存到 destkey
- BITOP NOT destkey key ,对给定 key 求逻辑非,并将结果保存到 destkey
- 除了 NOT 操作之外,其他操作都可以接受一个或多个 key 作为输入
- 当 BITOP 处理不同长度的字符串时,较短的那个字符串所缺少的部分会被看作 0
-
空的 key 也被看作是包含 0 的字符串序列
- 统计指定位区间上值为1的个数 字节
- bitpos key bit(0/1) start end > start end bit位的索引
- BITCOUNT key [start] [end] > start end Byte位的索引 正负方向
- set k ab bitcount k 1 1
- 从左向右从0开始,从右向左从-1开始,注意官方start、end是位,测试后是字节
- BITCOUNT testkey 0 0表示从索引为0个字节到索引为0个字节,就是第一个字节的统计
- BITCOUNT testkey 0 -1等同于BITCOUNT testkey
- 最常用的就是 BITCOUNT testkey
事例: Redis的二进制位
set s1 ab
bitcount s1
bitcount s1 0 0
bitcount s1 1 1
set ch 中
bitcount ch
bitcount ch 2 2
- 登录不同的库
- redis-cli --help
- redis-cli -n 2
- 清除当前库数据
- FLUSHDB
- 清除所有库中的数据
- FLUSHALL
位图事例:
- 网站用户的上线次数统计(活跃用户)
用户ID为key,天作为offset,上线置为1 366> 000000000000000
366 /8 50Byte 16 50
key: sean value: 11 1 000000000000000000010000000000000000
ID为500的用户,今年的第1天上线、第30天上线
SETBIT u500 1 1 1 0 0 000 0 …….1 0 00 0 > 365 /8 46 Byte
SETBIT u500 30 1
BITCOUNT sean 0 -1
KYES u*
- 按天统计网站活跃用户
天作为key,用户ID为offset,上线置为1
求一段时间内活跃用户数 500 / 8 366 * 63Byte
SETBIT 20160601 15 1 1 0 0 0 00 00 00 0 00 00 0
SETBIT 20160603 123 1 0 0 0 0 00 00 00 0 00 00 0
SETBIT 20160606 123 1 1 0 0 0 00 00 00 0 00 00 0
求6月1日到6月10日的活跃用户
BITOP OR aaa 20160601 20160602 20160603 20160610
BITCOUNT aaa 0 -1
结果为2
List列表 数组:
- 基于Linked List实现
- 元素是字符串类型
- 列表头尾增删快,中间增删慢,增删元素是常态
- 元素可以重复出现
- 最多包含2^32-1元素
- 列表的索引
- 从左至右,从0开始
- 从右至左,从-1开始
- list:
- 队列:L/R R/L
- 栈: L/L R/R
- 数组:LINDEX LSET
- 阻塞:BL BR
- 命令说明
- B block 块,阻塞
- L left 左
- R right 右
- X exist 存在
- 左右或者头尾压入元素 string set key “abc”
- LPUSH key value [value ...]
- LPUSHX key value
- RPUSH key value [value ...]
- RPUSHX key value
- 左右或者头尾弹出元素
- LPOP key
- RPOP key
- 从一个列表尾部弹出元素压入到另一个列表的头部 string getset
- RPOPLPUSH source destination
- 返回列表中指定范围元素
- LRANGE key start stop
- LRANGE key 0 -1 表示返回所有元素
- 获取指定位置的元素
- LINDEX key index
- 设置指定位置元素的值
- LSET key index value
- 列表长度,元素个数 string strlen
- LLEN key LRANGE KEY 0 -1
- 从列表头部开始删除值等于value的元素count次,LIST 可以重复出现
- LREM key count value
- count > 0 : 从表头开始向表尾搜索,移除与 value 相等的元素,数量为 count
- count < 0 : 从表尾开始向表头搜索,移除与 value 相等的元素,数量为 count 的绝对值
- count = 0 : 移除表中所有与 value 相等的值
- 举例
- RPUSH listkey c abc c ab 123 ab bj ab redis list
- LREM listkey 2 ab
- LRANGE listkey 0 -1
- 去除指定范围 外 元素
- LTRIM key start stop
- 举例
- RPUSH listkey c abc c ab 123 ab bj ab redis list
- LTRIM listkey 0 -1
- LTRIM listkey 1 -1
- LTRIM listkey 1 10000
- 微博的评论最后500条
- LTRIM u1234:forumid:comments 0 499
- 在列表中某个存在的值(pivot)前或后插入元素
- LINSERT key BEFORE|AFTER pivot value
- key和pivot不存在,不进行任何操作
- 举例
- RPUSH lst Clojure C Lua
- LINSERT lst AFTER C Python
- LINSERT lst BEFORE C Ruby
- 阻塞
- 如果弹出的列表不存在或者为空,就会阻塞
- 超时时间设置为0,就是永久阻塞,直到有数据可以弹出
- 如果多个客户端阻塞在同一个列表上,使用First In First Service原则,先到先服务
- 左右或者头尾阻塞弹出元素
- BLPOP key [key ...] timeout
- BRPOP key [key ...] timeout
- 从一个列表尾部阻塞弹出元素压入到另一个列表的头部
- BRPOPLPUSH source destination timeout
Hash散列:
- 由field和关联的value组成的map键值对
- field和value是字符串类型
- 一个hash中最多包含2^32-1键值对
- 设置单个字段
- HSET key field value
- HSETNX key field value
- key的filed不存在的情况下执行,key不存在直接创建
- 设置多个字段
- HMSET key field value [field value ...]
- 返回字段个数
- HLEN key
- 判断字段是否存在
- HEXISTS key field
- key或者field不存在,返回0
- 返回字段值
- HGET key field
- 返回多个字段值
- HMGET key field [field ...]
- 返回所有的键值对
- HGETALL key
- 返回所有字段名
- HKEYS key
- 返回所有值
- HVALS key
- 在字段对应的值上进行整数的增量计算
- HINCRBY key field increment
- 在字段对应的值上进行浮点数的增量计算
- HINCRBYFLOAT key field increment
- 删除指定的字段
- HDEL key field [field ...]
- 举例
- HINCRBY numbers x 100
- HINCRBY numbers x -50
- HINCRBYFLOAT numbers x 3.14
- HDEL numbers x
- 节约内存空间
- 每创建一个键,它都会为这个键储存一些附加的管理信息(比如这个键的类型,这个键最后一次被访问的时间等等)
- 所以数据库里面的键越多,redis数据库服务器在储存附加管理信息方面耗费的内存就越多,花在管理数据库键上的CPU也会越多在字段对应的值上进行浮点数的增量计算
- 不适合hash的情况
- 使用二进制位操作命令:因为Redis目前支持对字符串键进行SETBIT、GETBIT、BITOP等操作,如果你想使用这些操作,那么只能使用字符串键,虽然散列也能保存二进制数据
- 使用过期键功能:Redis的键过期功能目前只能对键进行过期操作,而不能对散列的字段进行过期操作,因此如果你要对键值对数据使用过期功能的话,那么只能把键值对储存在字符串里面
- 事例:微博的好友关注
用户ID为key,Field为好友ID,Value为关注时间
user:1000 user:606 20150808
xz pl 2011 zs 1949
- 用户维度统计
统计数包括:关注数、粉丝数、喜欢商品数、发帖数
用户为Key,不同维度为Field,Value为统计数
比如关注了5人
HSET user:100000 follow 5
HINCRBY user:100000 follow 1
Set集合
- 无序的、去重的
- 元素是字符串类型
- 最多包含2^32-1元素
- 增加一个或多个元素
- SADD key member [member ...]
- 如果元素已经存在,则自动忽略
- 举例
- SADD friends peter
- SADD friends jack tom john
- SADD friends may tom
- 移除一个或者多个元素
- SREM key member [member ...]
- 元素不存在,自动忽略
- 举例
- SREM friends peter
- SREM friends tom john
- 返回集合包含的所有元素
- SMEMBERS key
- 如果集合元素过多,例如百万个,需要遍历,可能会造成服务器阻塞,生产环境应避免使用
- 检查给定元素是否存在于集合中
- SISMEMBER key member
- 集合的无序性
- SADD friendsnew "peter" "jack" "tom" "john" "may" "ben"
- SADD anotherfriends "peter" "jack" "tom" "john" "may" "ben"
- SMEMBERS friends
- SMEMBERS anotherfriends
- 注意, SMEMBERS 有可能返回不同的结果,所以,如果需要存储有序且不重复的数据使用有序集合,存储有序可重复的使用列表
- 集合的无序性
- SADD friendsnew "peter" "jack" "tom" "john" "may" "ben"
- SADD anotherfriends "peter" "jack" "tom" "john" "may" "ben"
- SMEMBERS friends
- SMEMBERS anotherfriends
- 注意, SMEMBERS 有可能返回不同的结果,所以,如果需要存储有序且不重复的数据使用有序集合,存储有序可重复的使用列表
- 随机返回集合中指定个数的
- SRANDMEMBER key [count]
- 如果 count 为正数,且小于集合基数,那么命令返回一个包含 count 个元素的数组,数组中的元素各不相同。如果 count 大于等于集合基数,那么返回整个集合 最多返回整个集合 conut>=0
- 如果 count 为负数,那么命令返回一个数组,数组中的元素可能会重复出现多次,而数组的长度为 count 的绝对值 count < 0 长度为count绝对值,元素可能重复
- 如果 count 为 0,返回空
- 如果 count 不指定,随机返回一个元素
- 举例
- SADD friend "peter" "jack" "tom" "john" "may" "ben"
- SRANDMEMBER friends 3
- SRANDMEMBER friends -5
- 返回集合中元素的个数
- SCARD key
- 键的结果会保存信息,集合长度就记录在里面,所以不需要遍历
- 随机从集合中移除并返回这个被移除的元素
- SPOP key
- 把元素从源集合移动到目标集合
- SMOVE source destination member
- 差集
- SDIFF key [key ...],从第一个key的集合中去除其他集合和自己的交集部分
- SDIFFSTORE destination key [key ...],将差集结果存储在目标key中
- 举例
- SADD number1 123 456 789
- SADD number2 123 456 999
- SDIFF number1 number2
- 交集
- SINTER key [key ...],取所有集合交集部分
- SINTERSTORE destination key [key ...],将交集结果存储在目标key中
- 举例
- SADD number1 123 456 789
- SADD number2 123 456 999
- SINTER number1 number2
- 并集
- SUNION key [key ...],取所有集合并集
- SUNIONSTORE destination key [key ...],将并集结果存储在目标key中
- 举例
- SADD number1 123 456 789
- SADD number2 123 456 999
- SUNION number1 number2
事例:
新浪微博的共同关注
需求:当用户访问另一个用户的时候,会显示出两个用户共同关注哪些相同的用户
设计:将每个用户关注的用户放在集合中,求交集即可
实现如下:
peter={'john','jack','may'}
ben={'john','jack','tom'}
那么peter和ben的共同关注为:
SINTER peter ben 结果为 {'john','jack'}
SortedSet有序集合
- 类似Set集合
- 有序的、去重的
- 元素是字符串类型
- 每一个元素都关联着一个浮点数分值(Score),并按照分值从小到大的顺序排列集合中的元素。分值可以相同
- 最多包含2^32-1元素
- 增加一个或多个元素
- ZADD key score member [score member ...]
- 如果元素已经存在,则使用新的score
- 举例
- ZADD fruits 3.2 香蕉
- ZADD fruits 2.0 西瓜
- ZADD fruits 4.0 番石榴 7.0 梨 6.8 芒果
- 移除一个或者多个元素
- ZREM key member [member ...]
- 元素不存在,自动忽略
- 举例
- ZREM fruits 番石榴 梨 芒果
- ZREM fruits 西瓜
- 显示分值
- ZSCORE key member
- 举例
- ZSCORE fruits 芒果
- ZSCORE fruits 西瓜
- 增加或者减少分值
- ZINCRBY key increment member
- increment为负数就是减少
- 举例
- ZINCRBY fruits 1.5 西瓜
- ZINCRBY fruits -0.8 香蕉
- 返回元素的排名(索引)
- ZRANK key member
- 举例
- ZRANK fruits 西瓜
- ZRANK fruits 番石榴
- ZRANK fruits 芒果
- 返回元素的逆序排名
- ZREVRANK key member
- 举例
- ZREVRANK fruits 西瓜
- ZREVRANK fruits 番石榴
- ZREVRANK fruits 芒果
- 返回指定索引区间元素
- ZRANGE key start stop [WITHSCORES]
- 如果score相同,则按照字典序lexicographical order 排列
- 默认按照score从小到大,如果需要score从大到小排列,使用ZREVRANGE
- 举例
- ZRANGE fruits 0 2
- ZRANGE fruits -5 -4
- 返回指定索引区间元素
- ZREVRANGE key start stop [WITHSCORES]
- 如果score相同,则按照字典序lexicographical order 的 逆序 排列
- 默认按照score从大到小,如果需要score从小到大排列,使用ZRANGE
- 举例
- ZREVRANGE fruits 0 2
- ZREVRANGE fruits -5 -4
- 返回指定分值区间元素
- ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count]
- 返回score默认属于[min,max]之间,元素按照score升序排列,score相同字典序
- LIMIT中offset代表跳过多少个元素,count是返回几个。类似于Mysql
- 使用小括号,修改区间为开区间,例如(5、(10、5)
- -inf和+inf表示负无穷和正无穷
- 举例
- ZRANGEBYSCORE fruits 4.0 7.0
- ZRANGEBYSCORE fruits (4 7
- ZRANGEBYSCORE fruits -inf +inf
- 移除指定排名范围的元素
- ZREMRANGEBYRANK key start stop
- 举例
- ZREMRANGEBYRANK fruits 0 2
- ZRANGE fruits 0 -1
- 移除指定分值范围的元素
- ZREMRANGEBYSCORE key min max
- 举例
- ZREMRANGEBYSCORE fruits 3.0 5.0
- ZRANGE fruits 0 -1
- 返回集合中元素个数
- ZCARD key
- 返回指定范围中元素的个数
- ZCOUNT key min max
- ZCOUNT fruits 4 7
- 并集
- ZUNIONSTORE destination numkeys key [key ...] [WEIGHTS weight] [AGGREGATE SUM|MIN|MAX]
- numkeys指定key的数量,必须
- WEIGHTS选项,与前面设定的key对应,对应key中每一个score都要乘以这个权重
- AGGREGATE选项,指定并集结果的聚合方式
- SUM:将所有集合中某一个元素的score值之和作为结果集中该成员的score值
- MIN:将所有集合中某一个元素的score值中最小值作为结果集中该成员的score值
- MAX:将所有集合中某一个元素的score值中最大值作为结果集中该成员的score值
- 举例
- ZADD scores1 70 tom 80 peter 60 john
- ZADD scores2 90 peter 60 ben
- ZUNIONSTORE scores-all 2 scores1 scores2
- ZUNIONSTORE scores-all1 2 scores1 scores2 AGGREGATE SUM
- ZUNIONSTORE scores-all2 2 scores1 scores2 WEIGHTS 1 0.5 AGGREGATE SUM
- 交集
- ZINTERSTORE destination numkeys key [key ...] [WEIGHTS weight] [AGGREGATE SUM|MIN|MAX]
- numkeys指定key的数量,必须
- WEIGHTS选项,与前面设定的key对应,对应key中每一个score都要乘以这个权重
- AGGREGATE选项,指定并集结果的聚合方式
- SUM:将所有集合中某一个元素的score值之和作为结果集中该成员的score值
- MIN:将所有集合中某一个元素的score值中最小值作为结果集中该成员的score值
- MAX:将所有集合中某一个元素的score值中最大值作为结果集中该成员的score值
- 事例:网易音乐排行榜
分析
每首歌的歌名作为元素(先不考虑重复)
每首歌的播放次数作为分值
ZREVRANGE来获取播放次数最多的歌曲(就是最多播放榜了,云音乐热歌榜,没有竞价,没有权重)
- 新浪微博翻页
新闻网站、博客、论坛、搜索引擎,页面列表条目多,都需要分页
blog这个key中使用时间戳作为score
ZADD blog 1407000000 '今天天气不错'
ZADD blog 1450000000 '今天我们学习Redis'
ZADD blog 1560000000 '几个Redis使用示例'
ZREVRANGE blog 0 10
ZREVRANGE blog 11 20
- 京东图书畅销榜
ZADD bookboard-001 1000 'java' 1500 'Redis' 2000 'haoop'
ZADD bookboard-002 1020 'java' 1500 'Redis' 2100 'haoop'
ZADD bookboard-003 1620 'java' 1510 'Redis' 3000 'haoop'
ZUNIONSTORE bookboard-001:003 3 bookboard-001 bookboard-002 bookboard-003 AGGREGATE MAX
并集,使用max
注意:参与并集运算的集合较多,会造成Redis服务器阻塞,因此最好放在空闲时间或者备用服务器上进行计算