Redis 从放弃到入门

Redis 从放弃到入门

初识Redis

Redis是什么

Redis是基于键值对(key-value)的NoSql非关系型数据库

Redis特性

  1. 速度快 (读写性能 10万/秒

    • 数据存放于内存中 (内存在各硬件执行速度上最快)
    • 基于c语言开发
    • 单线程架构
    • 开源代码
      各硬件执行数速度:
  2. 基于键值对的数据结构服务器

  3. 丰富的功能

    • 提供键过期功能,实现缓存
    • 提供发布订阅功能,实现消息系统
    • 支持lua脚本,利用lua实现新的redis功能
    • 提供简单的事务,一定程度保证事务特性
    • 提供流水线(pipline)功能,客户端可一次性将批量命令传到redis,减少网路开销
  4. 简单稳定

    • redis源码少
    • 单线程模式
    • 不依赖于操作系统类库(如 memcache 依赖libevent库类库)
  5. 客户端语言多
    redis提供了简单的TCP通讯协议,方便多语言直接接入 。如 java/php/nodeJs/C++等

  6. 持久化 (将内存中数据保存至硬盘中)
    redis提供两张持久化数据方式:

    • RDB
    • AOF
  7. 主从复制

  8. 高可用和分布式

Redis能做什么

1、缓存
2、排行榜
3、计数器
4、社交网路
5、消息队列系统

Redis 的数据类型

  • 字符串
  • 列表
  • 哈希
  • 有序集合
  • 无序集合

字符串

1、命令

1.1设置字符串
set key value [ex seconds] [px milliseconds] [nx|xx]
set命令有几个选项:

  • ex seconds:为键设置秒级过期时间。 ·
  • px milliseconds:为键设置毫秒级过期时间。 ·
  • nx:键必须不存在,才可以设置成功,用于添加。 ·
  • xx:与nx相反,键必须存在,才可以设置成功,用于更新。

set的扩展命令 setexsetxx 作用和ex和nx选项是一样的。

1.2获取值 get
get key 不存在则返回nil (空)
1.3 批量设置值
mset key value [key value ...]
1.4 批量获取值 不存在的值返回nil (空)
mget key [key ...]
1.5 计数
incr key
返回3种结果:

  • 值不是整数,返回错误
  • 值是整数,返回自增后的结果
  • 键不存在,默认值为0 自增,返回结果1

除了incr命令,Redis提供了decr(自减)、incrby(自增指定数字)、 decrby(自减指定数字)、incrbyfloat(自增浮点数)
很多存储系统和编程语言内部使用CAS机制实现计数功能,会有一定的 CPU开销,但在Redis中完全不存在这个问题,因为Redis是单线程架构,任 何命令到了Redis服务端都要顺序执行。

1.5 不常用命令
(1)追加值 append append key value
(2)字符串长度 strlen key 返回value值的长度, 每个中文占用3个字节
(3)设置并返回原值getset key vaulegetsetset一样会设置值,但是不同的是,它同时会返回键原来的值

127.0.0.1:6379> getset hello world
 (nil)
 127.0.0.1:6379> getset hello redis 
 "world"

(4)设定指定位置的字符setrange key offset value

127.0.0.1:6379> set redis pest
 OK
127.0.0.1:6379> setrange redis 0 b 
(integer) 4 
127.0.0.1:6379> get redis 
"best"

(5)获取部分字符串getrange key start endstartend分别是开始和结束的偏移量,偏移量从0开始计算

127.0.0.1:6379> getrange redis 0 1 
"be"
2、内部编码

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

  • int: 8个字节长整型
  • embstr: 不大于39字节的字符串
  • raw: 大于39字节的字符串

查看key类型命令 object encoding key

127.0.0.1:6379> set key 8653 
OK
127.0.0.1:6379> object encoding key 
"int"

哈希

1、命令

1.1设置值hset key field value
1.2、获取值hget key field
1.3、删除值hdel key field [field ...] 返回成功删除的个数
1.4、计算field个数hlen key
1.5、批量设置或获取field-value 针对同一个key,多个field
hmset key field [field ...]
hmset key field value [field value ...]
1.6、判断field是否存在hexists key filed 存在返回1 ,不存在返回0
1.7、获取所有的fieldhkeys key
1.8、获取key下所有的valuehvals key
1.9、获取所有的field-valuehgetall key
1.10、field值自增hincrby 、hincrbyfloatincrbyincrbyfloat命令一样,但是它们作用域是filed
1.11、计算value的字符串长度(需要Redis3.2以上)hstrlen key field

哈希使用部分示例:

redis 127.0.0.1:6379> hset usr:1 name timor
(integer) 1
redis 127.0.0.1:6379> hget usr:1 // 只获取获取key会报错
(error) ERR wrong number of arguments for 'hget' command
redis 127.0.0.1:6379> hget usr:1 name // 通过获取field获取值
"timor"
redis 127.0.0.1:6379> hget usr:1 age // 不存在则返回nil
(nil)
redis 127.0.0.1:6379> hdel usr:1 name // 返回删除个数
(integer) 1
redis 127.0.0.1:6379> hdel usr:1 age
(integer) 0
redis 127.0.0.1:6379> hmset user:1 name timor age 35 city xiamen
OK
redis 127.0.0.1:6379> hmget user:1 name city
1) "timor"
2) "xiamen"
redis 127.0.0.1:6379> hkeys user:1
1) "name"
2) "city"
3) "age"
redis 127.0.0.1:6379> hgetall user:1 // 返回格式为filed 、value ...
1) "name"
2) "mike"
3) "city"
4) "xaimen"
5) "age"
6) "35"
2、内部编码

哈希类型的内部编码有2种:

  • ziplist(压缩列表):当哈希类型元素个数小于hash-max-ziplist-entries 配置(默认512个)、同时所有值都小于hash-max-ziplist-value配置(默认64 字节)
  • hashtable(哈希表):当哈希类型无法满足ziplist的条件时,Redis会使 用hashtable作为哈希的内部实现,因为此时ziplist的读写效率会下降,而 hashtable的读写时间复杂度为O(1)

ziplist使用更加紧凑的结构实现多个元素的连续存储,在节省内存方面比hashtable更加优秀

缓存用户信息3种方式比较:
1、原生字符串类型:每个属性一个键。

  • 优点:简单直观,每个属性都支持更新操作。
  • 缺点:占用过多的键,内存占用量较大,同时用户信息内聚性比较差, 此种方案一般不会在生产环境使用。

2、序列化字符串类型:将用户信息序列化后用一个键保存

  • 优点:简化编程,如果合理的使用序列化可以提高内存的使用效率
  • 缺点:序列化和反序列化有一定的开销,同时每次更新属性都需要把全部数据取出进行反序列化,更新后再序列化到Redis

3、哈希类型:每个用户属性使用一对field-value,但只用一个键保存

  • 优点:简单直观,如果使用合理可以减少内存空间的使用。
  • 缺点:要控制哈希在ziplist和hashtable两种内部编码的转换,hashtable会 消耗更多内存
// 方式1:
set user:1:name tom 
set user:1:age 23 
set user:1:city beijing
// 方式2:
set user:1 serialize(userInfo)
// 方式3:
hmset user:1 name timor age 35 city xiamen

列表

一个列表最多可以存储2^32-1个元素

1、操作示意图

(1)两端插入和弹出操作
在这里插入图片描述
(2)子列表获取和删除
在这里插入图片描述

2、列表的特点
  • 列表中的元素是有序的 (即 可通过索引下标获取某个元素或者某个范围内的元素列表)
  • 列表中的元素允许重复
    在这里插入图片描述
3、命令

3.1 添加元素
* 从右边插入rpush key value [value ...]
* 从左边插入元素lpush key value [value ...]
* 向某个元素前或者后插入元素 linsert key before|after pivot value
linsert命令会从列表中找到等于pivot的元素,在其前(before)或者后 (after)插入一个新的元素value

3.2 查找

  • 获取指定范围内的元素列表lrange key start end
    ①索引下标从左到右分别是0到N-1,但是从右到左分别是-1到-N。
    ②lrange中的end选项包含了自身,这个和很多编程语言不包含end不太相同
  • 获取列表指定索引下标的元素lindex key index
  • 获取列表长度llen key

3.3 删除

  • 从列表左侧弹出元素lpop key
  • 从列表右侧弹出rpop key
  • 删除指定元素lrem key count value
    count>0,从左到右,删除最多count个元素。 ·
    count<0,从右到左,删除最多count绝对值个元素。
    count=0,删除所有
  • 按照索引范围修剪列表ltrim key start end

3.4 修改指定索引下标的元素lset key index newValue
3.5 阻塞操作blpop key [key ...] timeoutbrpop key [key ...] timeout

1、如果多个键,那么brpop会从左至右遍历键,一旦有一个键 113
能弹出元素,客户端立即返回
2、如果多个客户端对同一个键执行brpop,那么最先执行brpop命 令的客户端可以获取到弹出的值

`blpop`和`brpop`是`lpop`和`rpop`的阻塞版本,它们除了弹出方向不同,使用方法基本相同
- `key[key...]`:多个列表的键。 
- `timeout`:阻塞时间(单位:秒)
1) 列表为空:若 timeout=3,则客户端要等到3秒后返回,若 timeout=0,则客户端一直阻塞等待
2)列表不为空:客户端会立即返回
// 在b元素前插入新元素java,返回结果为4,代表当前命令的长度
127.0.0.1:6379> linsert listkey before b java 
(integer) 4
// 元素列表值
127.0.0.1:6379> lrange listkey 0 -1 
1) "c" 
2) "java" 
3) "b" 
4) "a"
// 获取指定范围的元素
127.0.0.1:6379> lrange listkey 1 3 
1) "java" 
2) "b" 
3) "a"
// 获取当前列表最后一个元素 a
127.0.0.1:6379> lindex listkey -1 
"a"
// 下面操作会只保留列表listkey第2个到第4个元素
127.0.0.1:6379> ltrim listkey 1 3 
OK
127.0.0.1:6379> lrange listkey 0 -1 
1) "java" 
2) "b" 
3) "a"
// 列表为空:若 timeout=3,则客户端要等到3秒后返回,若 timeout=0,则客户端一直阻塞等待
127.0.0.1:6379> brpop list:test 3 
(nil) 
(3.10s) 
127.0.0.1:6379> brpop list:test 0 
...阻塞...
// 如果此期间添加了数据element1,客户端立即返回
127.0.0.1:6379> brpop list:test 3 
1) "list:test" 
2) "element1" 
(2.06s)
4、 内存编码

列表类型的内部编码有两种:

  • ziplist(压缩列表):当列表的元素个数小于list-max-ziplist-entries配置 (默认512个),同时列表中每个元素的值都小于list-max-ziplist-value配置时 (默认64字节),Redis会选用ziplist来作为列表的内部实现来减少内存的使用
  • linkedlist(链表):当列表类型无法满足ziplist的条件时,Redis会使用 linkedlist作为列表的内部实现

Redis3.2版本提供了quicklist内部编码,简单地说它是以一个ziplist为节 点的linkedlist,它结合了ziplist和linkedlist两者的优势,为列表类型提供了一种更为优秀的内部编码实现

5、使用场景
  • 消息队列
    Redis的lpush+brpop命令组合即可实现阻塞队列,生产 者客户端使用lrpush从列表左侧插入元素,多个消费者客户端使用brpop命令 阻塞式的“抢”列表尾部的元素,多个客户端保证了消费的负载均衡和高可用 性
  • 文章列表
    每个用户有属于自己的文章列表,现需要分页展示文章列表。此时可以 考虑使用列表,因为列表不但是有序的,同时支持按照索引范围获取元素
    Redis消息队列模型
    实际上列表的使用场景很多,在选择时可以参考以下口诀:
  • lpush+lpop=Stack(栈)
  • lpush+rpop=Queue(队列)
  • lpsh+ltrim=Capped Collection(有限集合)
  • lpush+brpop=Message Queue(消息队列)

集合

集合(set)类型也是用来保存多个的字符串元素,但和列表类型不一 样的是,集合中不允许有重复元素,并且集合中的元素是无序的,不能通过 索引下标获取元素。一个集合最多可以存储2^32-1个元素

集合类型

1、命令

1.1 添加元素sadd key element [element ...]返回成功添加的个数
1.2 删除元素srem key element [element ...]返回成功删除的个数
1.3 计算元素个数scard key scard的时间复杂度为O(1),它不会遍历集合所有元素,而是直接用 Redis内部的变量
1.4 判断是否在集合中sismember key element 在集合内返回1,反之返回0
1.5 随机从集合返回指定个数元素srandmember key [count] [count]是可选参数,不写则默认为1
1.6 从集合随机弹出元素spop key Redis从3.2版本开始,spop也支持[count]参数
1.7 获取所有元素smembers key返回结果是无序的

srandmemberspop都是随机从集合选出元素,两者不同的是spop命令 执行后,元素会从集合中删除,而srandmember不会

2、集合间操作

2.1 求多个集合的交集 sinter key [key ...]
2.2 求多个集合的并集 suinon key [key ...]
2.3 求多个集合的差集 sdiff key [key ...]
2.4 将交集、并集、差集的结果保存sinterstore destination key [key ...]suionstore destination key [key ...]sdiffstore destination key [key ...]

127.0.0.1:6379> exists myset // 检验key是否存在
(integer) 0 
127.0.0.1:6379> sadd myset a b c  // 添加元素
(integer) 3 
127.0.0.1:6379> sadd myset a b // 添加重复元素
(integer) 0
127.0.0.1:6379> srem myset a b  // 删除元素
(integer) 2 
127.0.0.1:6379> srem myset hello // 删除不存在元素
(integer) 0
127.0.0.1:6379> scard myset // 计算元素个数
(integer) 1
127.0.0.1:6379> sismember myset c // 验证c是否在集合中
(integer) 1
127.0.0.1:6379> srandmember myset 2 //随机返回指定个数元素
1) "a" 
2) "c" 

// 集合间操作
127.0.0.1:6379> sadd user:1:follow it music his sports 
(integer) 4 
127.0.0.1:6379> sadd user:2:follow it news ent sports 
(integer) 4
127.0.0.1:6379> sinter user:1:follow user:2:follow  // 求两集合间交集
1) "sports" 
2) "it"
127.0.0.1:6379> sunion user:1:follow user:2:follow // 求两集合并集
1) "sports" 
2) "it" 
3) "his" 
4) "news" 
5) "music" 
6) "ent"
127.0.0.1:6379> sdiff user:1:follow user:2:follow // 求两集合差集
1) "music" 
2) "his"


集合操作:交集、并集、差集

3、内部编码

集合类型的内部编码有2种:

  • intset(整数集合):当集合中的元素都是整数且元素个数小于set-max- intset-entries配置(默认512个)时,Redis会选用intset来作为集合的内部实 现,从而减少内存的使用。
  • hashtable(哈希表):当集合类型无法满足intset的条件时,Redis会使 用hashtable作为集合的内部实现。
4、使用场景
  • 给用户添加标签
  • 给标签添加用户
  • 删除用户下的标签
  • 删除标签下的用户
  • 计算用户共同感兴趣的标签

集合类型的应用场景通常为以下几种:
sadd=Tagging(标签)
pop/srandmember=Random item(生成随机数,比如抽奖)
sadd+sinter=Social Graph(社交需求)

有序集合

1、命令

1.1 添加成员zadd key score member [score member ...]返回结果代表成功添加成员的个数

Redis3.2为zadd命令添加了nx、xx、ch、incr四个选项:

  • nx:member必须不存在,才可以设置成功,用于添加。
  • xx:member必须存在,才可以设置成功,用于更新。
  • ch:返回此次操作后,有序集合元素和分数发生变化的个数
  • incr:对score做增加,相当于后面介绍的zincrby。

1.2 计算成员个数zcard key
1.3 计算某个成员的分数zscore key member 成员不存在则返回nil
1.4 计算成员的排名zrank key member // 从低到高zrevrank key member // 从高到低
1.5 删除成员zrem key member [member ...] 返回成功删除的个数
1.6 增加成员的分数zincrby key increment member
1.7 返回指定排名范围的成员,跟上withscores选项同时会返回成员的分数
zrange key start end [withscores] //从低到高
zrevrange key start end [withscores] //从高到低
1.8 返回指定分数范围的成员,[limit offset count]选项可以限制输出的起始位置和个数
zrangebyscore key min max [withscores] [limit offset count] // 分数从低到高返回
zrevrangebyscore key max min [withscores] [limit offset count] // 分数从高到低返回
1.9 返回指定分数范围成员个数zcount key min max
1.10 删除指定排名内的升序元素zremrangebyrank key start end
1.11 删除指定分数范围的成员 zremrangebyscore key min max

2、集合间操作

2.1 交集zinterstore destination numkeys key [key ...] [weights weight [weight ...]] [aggregate sum|min|max]
参数说明:

  • destination:交集计算结果保存到这个键
  • numkeys:需要做交集计算键的个数
  • key[key...]:需要做交集计算的键
  • weights weight[weight...]:每个键的权重,在做交集计算时,每个键中 的每个member会将自己分数乘以这个权重,每个键的权重默认是1
  • aggregate sum|min|max:计算成员交集后,分值可以按照sum(和)、 min(最小值)、max(最大值)做汇总,默认值是sum
    2.2 并集zunionstore destination numkeys key [key ...] [weights weight [weight ...]] [aggregate sum|min|max]参数个交集说明一致

3、内部编码
有序集合类型的内部编码有两种

  • ziplist(压缩列表):当有序集合的元素个数小于zset-max-ziplist- entries配置(默认128个),同时每个元素的值都小于zset-max-ziplist-value配 置(默认64字节)时,Redis会用ziplist来作为有序集合的内部实现,ziplist 可以有效减少内存的使用
  • skiplist(跳跃表):当ziplist条件不满足时,有序集合会使用skiplist作 为内部实现,因为此时ziplist的读写效率会下降

4、使用场景
4.1 添加/取消 用户赞数
zadd user:ranking:2021_07_15 mike 3// 用户mike获3个赞
zincrby user:ranking:2021_07_15 mike 1// 获赞之后在获赞
zrem user:ranking:2021_07_15 mike// 取消获赞,即删除成员
4.2 展示获取赞数最多的十个用户
zrevrangebyrank user:ranking:2021_07_15 0 9
4.3 展示用户信息以及用户分数
hgetall user:info:tom
zscore user:ranking:2016_03_15 mike
zrank user:ranking:2016_03_15 mike

127.0.0.1:6379 > zadd user:ranking 251 tom // 添加
(integer) 1
127.0.0.1:6379 > zcard user:ranking // 计算个数
(integer) 1
127.0.0.1:6379 > zscore user:ranking tom
"251"
127.0.0.1:6379 > zincrby user:ranking 9 tom // 给tom成员增加9分
"260"
127.0.0.1:6379 > zrange user:ranking 0 2 withscores // 获取指定排名范围的成员
1) "kris"
2) "1"
3) "frank"
4) "200"
5) "tim"
6) "220"
127.0.0.1:6379 > zrangebyscore user:ranking 200 tinf withscores //返回指定分数范围的成员
1) "frank"
2) "200"
3) "tim"
4) "220"

键管理

1、键重命名rename key newkey 在rename之前,新键名已经存在,那么它的值也将被覆盖 为了防止被强行rename,Redis提供了renamenx命令,确保只有newKey 不存在时候才被覆盖

注意点:

  • 由于重命名键期间会执行del命令删除旧的键,如果键对应的值比较 大,会存在阻塞Redis的可能性,这点不要忽视。 ·
  • 如果rename和renamenx中的key和newkey如果是相同的,在Redis3.2和之 前版本返回结果略有不同Redis3.2中会返回OK,Redis3.2之前的版本会提示错误
    2、随机返回一个键 randomkey
    3、键过期 ttl key 无论使用过期时间还是时间戳,秒级还是毫秒级,在Redis内部最终使用的都是pexpireat
    返回结果:
    -2,说明键key已经被删除
    -1:键没有设置过期时间
    >= 0: 键剩余的过期时间(ttl是秒,pttl是毫秒)
  • expire key seconds:键在seconds秒后过期。
  • expireat key timestamp:键在秒级时间戳timestamp后过期
  • expireat命令可以设置键的秒级过期时间戳expireat hello 1469980800
  • pexpire key milliseconds:键在milliseconds毫秒后过期
  • pexpireat key milliseconds-timestamp键在毫秒级时间戳timestamp后过期

注意事项:

  1. 如果expire key的键不存在,返回结果为0
  2. 如果过期时间为负值,键会立即被删除
  3. persist命令可以将键的过期时间清除
  4. 对于字符串类型键,执行set命令会去掉过期时间,这个问题很容易 在开发中被忽视 示例如下:
  5. Redis不支持二级数据结构(例如哈希、列表)内部元素的过期功 能,例如不能对列表类型的一个元素做过期时间设置。
  6. setex命令作为set+expire的组合,不但是原子执行,同时减少了一次 网络通讯的时间
127.0.0.1:6379 > expire hello 50 
(integer) 1 
127.0.0.1:6379 > ttl hello 
(integer) 46 
127.0.0.1:6379 > set hello world // 执行set命令
OK
127.0.0.1:6379 > ttl hello (integer)  // 过期时间变为永久
-1

4、迁移键
4.1 move key db move命令在Redis内部数据库之间迁移数据
4.2 dump+restore :
dump key
restore key ttl value
dump+restore可以实现在不同的Redis实例之间进行数据迁移的功能,整 个迁移的过程分为两步:
1)在源Redis上,dump命令会将键值序列化,格式采用的是RDB格式。
2)在目标Redis上,restore命令将上面序列化的值进行复原,其中ttl参 数代表过期时间,如果ttl=0代表没有过期时间

注意点
7. 整个迁移过程并非原子性 的,而是通过客户端分步完成的。
8. 迁移过程是开启了两个客户端连 接,所以dump的结果不是在源Redis和目标Redis之间进行传输,

move 、dump、migrate 三者间比较
5、遍历键
5.1 全量遍历键 keys pattern
pattern使用的是glob风格的通配符:

  1. *代表匹配任意字符。 ·代表匹配一个字符。
  2. []代表匹配部分字符,例如[1,3]代表匹配1,3,[1-10]代表匹配1到10 的任意数字。
  3. \x用来做转义,例如要匹配星号、问号需要进行转义。

5.2 渐进式遍历 scan cursor [match pattern] [count number]

  • cursor是必需参数,实际上cursor是一个游标,第一次遍历从0开始,每 次scan遍历完都会返回当前游标的值,直到游标值为0,表示遍历结束。
  • match pattern是可选参数,它的作用的是做模式的匹配,这点和keys的 模式匹配很像。
  • count number是可选参数,它的作用是表明每次要遍历的键个数,默认 值是10,此参数可以适当增大。
    scan采用渐进式遍历 的方式来解决keys命令可能带来的阻塞问题 【redis >=2.8版本】

6、数据库管理
6.1 切换数据库 select dbindex Redis默认配置中是有16个数据库,编号[0-15]
6.2 flushdb/flushall命令用于清除数据库,两者的区别的是flushdb只清除当前数据库,flushall会清除所有数据库
注意点
(1)flushdb/flushall命令会将所有数据清除,一旦误操作后果不堪设想,
(2)如果当前数据库键值数量比较多,flushdb/flushall存在阻塞Redis的可能性

功能分析

慢查询

1、慢查询日志定义:系统在命令执行前后计算每条命 令的执行时间,当超过预设阀值,就将这条命令的相关信息(例如:发生时 间,耗时,命令的详细信息)记录下来

客户端命令生命周期:

1 发送命令 -> 2 命令排队 -> 3 命令执行 -> 4 返回结果
慢查询只统计步骤【3 执行命令】的时间,所以没有慢查询并不代表客 户端没有超时问题

redis客户端命令生命周期
2、慢查询参数配置

  • 预设阀值slowlog-log-slower-than 单位是微秒(1秒=1000毫秒=1000000微秒),默认值是10000。Redis使用了一个列表来存储慢查询日 志,slowlog-max-len就是列表的最大长度
  • 慢查询最多存储条数 slowlog-max-len
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值