天天看点

【Redis 开发与运维】第2章 读书笔记第2章 API 的理解和使用

第2章 API 的理解和使用

2.1 预备

2.1.1 全局命令

2.1.2 数据结构和内部编码

每种基本类型数据结构都有自己的底层的内部编码实现。

Redis 这样设计有两种好处:

第一,它可以改进内部编码,而对外的数据结构和命令没有影响,这样一旦开发出更优秀的内部编码,无需改动外部数据结构和命令。

第二,多种内部编码实现可以再不同的场景发挥各自的优势。

2.1.3 单线程架构

Redis 使用了单线程架构和 I/O 多路复用模型来实现高性能的数据库服务。

为什么单线程还这么快?

第一,纯内存访问

第二,非阻塞 I/O

第三,单线程避免了线程切换和竞态产生的消耗。

2.2 字符串:string

键都是字符串类型

字符串类型的最大值不能超过512MB

2.2.1 命令

  1. 设置值
set key ex seconds value #设置秒级过期时间
set key px milliseconds value #设置毫秒级过期时间
set key value nx #键不存在时,设置成功
set key value xx #键存在时,设置成功,常用于更新操作

setex key secends value #类似于ex
setnx key value #类似于nx
           
  1. 获取值
get key
           
  1. 批量设置值
  1. 批量获取值
  1. 计数
incr key #自增
decr key #自减
incrby key #自增指定数字
decrby key #自减指定数字
incrbyfloat #自增浮点数
           

不常用命令

  1. 追加值
append key value
           
  1. 字符串长度
strlen key
           
  1. 设置并返回原值
getset key value
           
  1. 设定指定位置的字符
setrange key offset value
           
  1. 获取部分字符串
getrange key start end
           

2.2.2 内部编码

字符串类型内部编码有三种:

  1. int:8个字节的长整型
  2. embstr:小于等于39个字符的字符串
  3. raw:大于39个字节的字符串

2.2.3 典型使用场景

  1. 缓存功能
  2. 计数
  3. 共享Session
  4. 限速

2.3 哈希:hash

2.3.1命令

  1. 设置值
hset user:1 name tom
           
  1. 获取
hget user:1 name
           
  1. 删除值
hdel user2 name
           
  1. 批量设置,获取值
hmset user:2 name huangxuwei age 21 city chenzhou
OK
hmget user:2 name city
1) "huangxuwei"
2) "chenzhou"
           
  1. 计数
hlen user:1
           
  1. 判断是否存在
hexists user:1 name
           
  1. 获取所有 field
hkeys user:2
1) "name"
2) "age"
3) "city"
           
  1. 获取所有 value
hvals user:2
1) "huangxuwei"
2) "21"
3) "chenzhou"xxxxxxxxxx 127.0.0.1:6379> 
           
  1. 获取所有 field-value
hgetall user:2
1) "name"
2) "huangxuwei"
3) "age"
4) "21"
5) "city"
6) "chenzhou"
           

2.3.2 内部编码

  1. ziplist:更省内存
  2. hashtable:更快
  • 当field 个数较少且没有较大的 value 时,内部编码为 ziplist
  • 当 value 大于64字节,或者 field个数超过512时,内部编码由 ziplist 转为 hashtable

2.3.3 使用场景

哈希类型与关系型数据库的区别

  • 哈希类型是稀疏的,而关系型数据库是完全结构化的
  • 关系型数据库可以做复杂的关系查询,而 Redis 去模拟关系型复杂查询成本高

三种方法缓存用户信息

  1. 原生字符串类型
  2. 序列化字符串类型
  3. 哈希类型

2.4 列表:list

一个列表最多可以存储2的32次方减1个元素

有序可重复

2.4.1 命令

  1. 添加,查看,删除,获取长度
127.0.0.1:6379> rpush listkey key a b c d 1 2 3 4,5 #添加
(integer) 9
127.0.0.1:6379> lrange listkey 0 -1 #查看
1) "key"
2) "a"
3) "b"
4) "c"
5) "d"
6) "1"
7) "2"
8) "3"
9) "4,5"
127.0.0.1:6379> lpop listkey #左删除
"key"
127.0.0.1:6379> rpop listkey #右删除
"4,5"
127.0.0.1:6379> lrem listkey 1 a #删除指定元素
(integer) 1
127.0.0.1:6379> lrange listkey 0 -1
 1) "b"
 2) "c"
 3) "d"
 4) "e"
 5) "f"
 6) "g"
 7) "h"
 8) "i"
 9) "j"
10) "k"
11) "l"
12) "m"
13) "n"
127.0.0.1:6379> ltrim listkey 1 8 #保留指定区间
OK
127.0.0.1:6379> lrange listkey 0 -1
1) "c"
2) "d"
3) "e"
4) "f"
5) "g"
6) "h"
7) "i"
8) "j"
127.0.0.1:6379> llen listkey #获取长度
(integer) 4
           
  1. 修改操作
127.0.0.1:6379> rpush listkey java cpp python
(integer) 3
127.0.0.1:6379> lrange listkey 0 -1
1) "java"
2) "cpp"
3) "python"
127.0.0.1:6379> lset listkey 1 javaee #修改指定索引下标的元素
OK
127.0.0.1:6379> lset listkey 2 spring
OK
127.0.0.1:6379> lrange listkey 0 -1
1) "java"
2) "javaee"
3) "spring"
           
  1. 阻塞操作

2.4.2 内部编码

  • ziplist:当列表元素小于 list-max-ziplist-entries 配置值(512),同时列表中元素的值都小于 **list-max-ziplist-value **配置值(默认64字节)Redis 使用ziplist 来作为列表的内部编码以减少内存的使用。
  • linkedlist:当ziplist条件不满足时,Redis 使用linkedlist来作为列表的内部编码。
  • quicklist:Redis 3.2版本提供,它是一个 ziplist 为节点的 linkedlist,结合了两者的优势

2.4.3 使用场景

  1. 消息队列
  2. 文章列表

口诀:

  • lpush + lpop = Stack
  • lpush + rpop = Queue
  • lpush + ltrim =Capped Collection
  • lpush + brpop = Message Queue

2.5 集合:set

无序互异性

一个集合最多包含2的32次方减1个元素

Redis 不仅支持集合的增删查改,还支持集合取交集,并集,差集。

2.5.1 命令

集合内:

  1. 添加元素
sadd myset test a b c d
           
  1. 删除元素
srem myset test
           
  1. 计算元素个数
scard myset
           
  1. 查看所有元素
127.0.0.1:6379> SMEMBERS myset
1) "c"
2) "d"
3) "a"
4) "b"
           
  1. 判断元素是否在集合中
sismember myset a
           
  1. 随机从集合返回指定个数元素
127.0.0.1:6379> srandmember myset 2
1) "b"
2) "a"
           
  1. 随机从集合弹出元素
127.0.0.1:6379> spop myset
"c"
127.0.0.1:6379> smembers myset
1) "d"
2) "a"
3) "b"
           

集合间:

  1. 交集
127.0.0.1:6379> sadd user1 follow it music his sports
(integer) 5
127.0.0.1:6379> sadd user2 follow it news ent sports
(integer) 5
127.0.0.1:6379> sinter user1 user2
1) "follow"
2) "it"
3) "sports"
           
  1. 并集
127.0.0.1:6379> sunion user1 user2
1) "sports"
2) "follow"
3) "music"
4) "news"
5) "his"
6) "ent"
7) "it"
           
  1. 差集(与前后顺序有关)
127.0.0.1:6379> sdiff user1 user2
1) "his"
2) "music"
           
  1. 将交集,并集,差集的结果保存
127.0.0.1:6379> sinterstore user1_2 user1 user2
(integer) 3
127.0.0.1:6379> SMEMBERS user1_2
1) "sports"
2) "follow"
3) "it"
           

sinterstore:原命令+store

2.5.2 内部编码

  • intset:当集合元素全是整数且个数小于set-max-intset-entries配置值(默认值是512)时
  • hashtable:当intset条件不满足时

2.5.3 使用场景

  • 标签

2.6 有序集合:zset

有序互异

2.6.1 命令

集合内:

  1. 添加元素
127.0.0.1:6379> zadd user:ranking 251 tom
(integer) 1
127.0.0.1:6379> zadd user:ranking 251 tom 123 huang 11 xu 13 wei 222 2cosmos
           
  1. 计算排名
zrank key member
zrevrank key member

127.0.0.1:6379> zrank user:ranking xu
(integer) 0
127.0.0.1:6379> zrevrank user:ranking xu
(integer) 4
           
  1. 删除成员
127.0.0.1:6379> zrem user:ranking huang xu
(integer) 2
           
  1. 返回成员分数
127.0.0.1:6379> zrange user:ranking 0 2
1) "2cosmos"
2) "tom"
3) "wei"
127.0.0.1:6379> zrange user:ranking 0 2 withscores
1) "2cosmos"
2) "222"
3) "tom"
4) "251"
5) "wei"
6) "10013"
           
  1. 增加分数
127.0.0.1:6379> zincrby user:ranking 100000000 2cosmos
"100000222"
127.0.0.1:6379> zrange user:ranking 0 2 withscores #zrevrange 逆序
1) "tom"
2) "251"
3) "wei"
4) "10013"
5) "2cosmos"
6) "100000222"
           
  1. 返回指定分数范围的成员
127.0.0.1:6379> zrangebyscore user:ranking 1 100000 withscores
1) "tom"
2) "251"
3) "wei"
4) "10013"
           
  1. 返回指定分数范围成员个数
127.0.0.1:6379> zcount user:ranking 1 100000 
(integer) 2
           
  1. 删除指定范围分数成员
127.0.0.1:6379> zremrangebyscore user:ranking (250 +inf
(integer) 3
127.0.0.1:6379> zrangebyscore user:ranking 1 inf withscores
(empty array)
           

集合间:

  1. 交集
127.0.0.1:6379> zinterstore user:ranking:1_inter_2 2 user:rang:1 user:rang:2
(integer) 3

127.0.0.1:6379> zrange user:ranking:1_inter_2 0 -1 withscores
1) "wei"
2) "2"
3) "xu"
4) "24"
5) "huang"
6) "182"
           
  1. 并集
127.0.0.1:6379> zunionstore user:ranking:1_union_2 2 user:rang:1 user:rang:2
(integer) 5
127.0.0.1:6379> zrange user:ranking:1_union_2 0 -1 withscores
 1) "wei"
 2) "2"
 3) "xu"
 4) "24"
 5) "cosmos"
 6) "99"
 7) "cosmosweis"
 8) "99"
 9) "huang"
10) "182"
           

2.6.2 内部编码

  • ziplist:当有序集合元素小于zset-max-ziplist-entres配置值(默认为128个)时,同时每个元素的值都小于zset-max-ziplist-value配置值(默认为64字节)时,Redis使用ziplist 作为内部实现,ziplist可以有效减少内存的使用。
  • skiplist:当 ziplist 条件不满足时使用,提高读写效率。

2.6.3 使用场景

排行榜系统

  1. 添加用户赞数。
  2. 取消赞数。
  3. 展示获赞数最多的几个用户。
  4. 展示用户信息以及用户分数。

2.7 键管理

2.7.1 单个键管理

  1. 键重命名
rename key newkey
           

rename之前,newkey 已经存在的话,它的值会被覆盖。

为了被强行 rename,Redis 提供了 renamenx 命令

  • 重命名期间会del旧键,如果键对应的值过大,会存在阻塞问题。
  • rename newkey 已存在,Redis 3.2之前,返回错误;Redis 3.2之后,返回 OK。
  1. 随机返回一个键
randomkey
           
  1. 键过期
expire key secends #键在secends秒后过期

expireat key timesamp #键在秒级时间戳 timesamp 后过期

ttl #查看剩余过期时间

pttl #查看毫秒级过期时间

pexpire key millisecends #键在millisecends秒后过期

pexpireat key millisecends-timesamp #键在秒级时间戳 timesamp 后过期
           
  • 无论过期时间是时间戳,秒级,还是毫秒级,Redis 内部最终使用的都是 pexpireat。
  • 对于字符串类型键,执行 set 命令会去掉过期时间。
  • persist 命令可以将过期时间清除。
  • Redis 不支持二级数据结构内部元素的过期功能,例如不能对列表类型的一个元素设置过期时间。
  • setex 命令作为set + expire 的组合,不但是原子执行,同时减少了一次网络通信。
  1. 迁移键:把部分数据由一个 Redis 迁移到另一个 Redis
  • move:Redis 内部使用,内部数据库
  • dump+restore:Redis 之间使用
  • migrate:Redis 之间使用,实际上就是对dump,restore,set ,命令进行原子性整合

2.7.2 遍历键

  1. 全量遍历键:keys pattern(*,?,[1,2],\x)
  2. 渐进式遍历

Redis 2.8 之后:scan 命令

scan 并不能保证完整的遍历出来所有的键。

2.7.3 数据库管理

  1. select:切换数据库,Redis 默认有16个数据库
  2. flushdb/flushall:清空数据库

Redis 3.0 以后在弱化这个功能,Redis Cluster 只允许使用0号数据库

为什么:

  • Redis 是单线程的,
  • 调试和运维变得困难
  • 部分 Redis 客户端不支持这种方式

继续阅读