Redis进阶学习

155 阅读10分钟

一 什么是redis?

Redis 是一个开源的,基于内存操作、支持多种数据结构的存储系统。

二 为什么要用redis?

我们主要用redis作为缓存中间件来实现分布式缓存。

因为传统的关系型数据库如Mysql已经不能适用所有的场景了,比如像秒杀的商品查询和库存扣减,APP首页的访问流量高峰等这些高并发场景,都很容易把数据库打崩,所以需要做数据的缓存,目前市面上比较常用的缓存中间件有 RedisMemcached 不过中和考虑了他们的优缺点,最后选择了Redis。

三 redis的功能和特点(和Memcached对比)

  • Redis 采用单线程模式处理请求。 而Memcached采用多线程异步IO的方式处理请求。

redis采用单线程的原因有2个:

  1. 一个是因为采用了非阻塞的I/O多路复用机制;
  2. 另一个是缓存数据都是内存操作 IO 时间不会太长,单线程可以避免线程频繁的上下文切换产生的cpu性能损耗问题。
  • Redis 支持数据持久化。而Memcached不支持数据持久化。

  • Redis 支持多种数据结构,例如String、 hash、list、set、sorted set。

    • 而Memcached只支持字符串。
  • Redis 提供主从同步机制,以及Cluster集群部署能力,能够提供高可用服务。

    • 而Memcached没有。

另外,使用 Memcached 有一些限制,这些限制在现在的互联网场景下很致命,成为大家选择RedisMongoDB的重要原因:

  • key 不能超过 250 个字节;
  • value 不能超过 1M 字节;
  • key 的最大失效时间是 30 天;
  • 只支持 K-V 结构,不提供持久化和主从同步功能。

四 Redis五种数据类型及其使用场景

redis 数据存储格式:

  • redis自身是一个Map类型的存储结构,其中所有的数据都是采用key:value的形式存储。
  • 我们讨论的数据类型,指的是存储的数据的类型,也就是value部分的类型,key部分永远都是字符串。

String

常用命令

  • 添加/修改指定key的值
set key value
  • 添加/修改指定key的值,并为其设定失效时间seconds秒
setex key seconds value 
psetex key milliseconds value //功能与上面一直,秒的单位不同
  • 当指定的 key 不存在时,为 key 设置指定的值
setnx key value
  • setnx 和 setex命令一起执行,保证setnxexpire的原子性
1. set key value [EX seconds] [PX milliseconds] [NX|XX]
2. EX seconds:设置失效时长,单位秒
3. PX milliseconds:设置失效时长,单位毫秒
4. NX:key不存在时设置value,成功返回OK,失败返回(nil)
5. XX:key存在时设置value,成功返回OK,失败返回(nil)
6. 
7. 案例:设置name=p7+,失效时长100s,不存在时设置
8. 1.1.1.1:6379> set name p7+ ex 100 nx
9. OK
10. 1.1.1.1:6379> get name
11. "p7+"
12. 1.1.1.1:6379> ttl name
13. (integer) 94

  • 获取指定key的值
get key
  • 删除指定的key和值
del key
  • 添加/修改多个key的值
mset key1 value1 key2 value2 …
  • 获取多个key的值
mget key1 key2 …
  • 获取指定key的值的字符个数(字符串长度)
strlen key
  • 追加信息到原始信息后部(如果原始信息存在就追加,否则新建)
append key value
  • String类型作为数值时的增减
incr key 	//自增1
incrby key increment  //增加指定数值
incrbyfloat key increment  //增加一个指定数值浮点数

decr key //自减1 
decrby key increment //减少指定数值

String的应用场景:

  • 缓存功能:String字符串是最常用的数据类型,不仅仅是Redis,各个语言都是最基本类型,因此,利用Redis作为缓存,配合其它数据库作为存储层,利用Redis支持高并发的特点,可以大大加快系统的读写速度、以及降低后端数据库的压力。
  • 计数器: 许多系统都会使用Redis作为系统的实时计数器,可以快速实现计数和查询的功能。而且最终的数据结果可以按照特定的时间落地到数据库或者其它存储介质当中进行永久保存。
  • 应用集群共享用户Session: 在多应用集群环境下,由于nginx负载均衡,用户重新刷新一次界面,可能需要访问一下数据进行重新登录,或者访问页面缓存Cookie,但是可以利用Redis将用户的Session集中管理,在这种模式只需要保证Redis的高可用,每次用户Session的更新和获取都可以快速完成。大大提高效率。

Hash

String类型存储的问题: 对于对象类型数据的存储,如果具有较为频繁的更新需求,操作会显得笨重,存容易,改麻烦。

所以对于对象类型数据的存储,如果具有较为频繁的更新需求,一般采用hash数据类型。

为了区别Redis中键值对的称呼,hash中的键成为field,而key特指Redis的键。

常用命令

  • 添加/修改数据
hset key field value
  • 获取数据
hget key field --获得指定key中 hash指定键的值
hgetall key --获得指定key的,hash全部数据
  • 删除数据
hdel key field1 [field2] -- 删除指定key中 hash指定键的值(可以多个)
  • 添加/修改多个数据
hmset key field1 value1 field2 value2
  • 获取多个数据
hmget key field1 field2 …
  • 获取哈希表中字段的数量
hlen key
  • 获取哈希表中是否存在指定的字段
hexists key field
  • 获取哈希表中所有的字段名和字段值
hkeys key  --字段名
hvals key  --字段值
  • 创建数据,如果有则不再创建,如果没有则创建
hsetnx key field value

hash类型应用场景

  • 电商网站购物车的设计与实现

image.png 解决方案:

image.png

  • 将商品的信息保存在字符串数据类型中
    • key为商品的id
    • value为商品信息json字符串

List

list类型:保存多个数据,底层使用双向链表存储结构实现,有序的。

常用命令

  • 添加数据
lpush key value1 [value2] …  --从链表左边添加数据
rpush key value1 [value2] …  --从链表右边添加数据
  • 获取数据
lrange key start stop   --获取从左数第start到stop个元素,从0开始 (获取全部数据结束索引设置为-1)
lindex key index   --查询第i个元素
llen key     --list的长度
  • 获取并移除数据
lpop key  --获取并删除list左边第一个元素
rpop key  --获取并删除list右边第一个元素
  • 阻塞式获取并移除数据
blpop key  timeout
brpop key  timeout
  • 移除指定数据
lrem key count value    --count为移除的数量,value为移除哪个值

list类型应用场景:

业务场景-列表数据的展示

  • twitter、新浪微博、腾讯微博中用户的关注列表需要按照用户的关注顺序进行展示,粉丝列表需要将最近关注的粉丝列在前面
    在这里插入图片描述

可以通过 lrange 命令,读取某个闭区间内的元素,可以基于 List 实现分页查询,这个是很棒的一个功能,基于 Redis 实现简单的高性能分页,可以做类似微博那种下拉不断分页的东西,性能高,就一页一页走。

实现消息队列

  • 消息队列:Redis中list数据类型的双向链表结构,可以轻松实现阻塞队列,可以使用左进右出的命令组成来完成队列的设计。比如:数据的生产者可以通过Lpush命令从左边插入数据,多个数据消费者,可以使用BRpop命令阻塞的“抢”列表尾部的数据。

Set

Set 是无序集合,会自动去重。

Set 类型:与hash存储结构完全相同,仅存储键,不存储值(nil),并且键是不允许重复的。也就是只有键没有值的hash。

常用命令

  • 添加数据
sadd key menber1 [member2]
  • 获取全部数据
smembers key
  • 删除数据
srem key member1 [member2]
  • 获取集合数据总量
scard key
  • 判断集合中是否包含指定数据
sismember key member1
  • 随机获取集合中指定数量的数据
srandmember key [count]
  • 随机获取集合中的某个数据并将该数据移出集合
spop key

redis应用于随机推荐类信息检索,例如热点歌单推荐,热点新闻推荐,热点旅游线路,应用APP推荐,大V推荐等。

  • 求两个集合的交、并、差集
sinter key1 [key2] //交集
sunion key1 [key2] //并集
sdiff key1 [key2] //差集(key1有但是key2没有的)
  • 求两个集合的交、并、差集并存储到指定集合中
sinterstore destination key1 [key2]
sunionstore destination key1 [key2]
sdiffstore destination key1 [key2]
  • 将指定数据从原始集合移动到目标集合中
smove source destination member  --member集合数据

set类型应用场景:

  • 业务场景-对数据进行快速的全局去重

  • 业务场景-共同好友

  • redis应用于随机推荐类信息检索,例如热点歌单推荐,热点新闻推荐,热点旅游线路,应用APP推荐,大V推荐等

sorted set

sorted_set类型:在set的存储结构基础上添加可排序字段。

常用命令

  • 添加数据
zadd key score1 member1 [score2 member2]
  • 获取数据
zrange key start stop [WITHSCORES] //按照从小到大的顺序,加上WITHSCORES,就会带上scores一起显示

zrevrange key start stop [WITHSCORES] //按照从大到小的顺序

image.png

  • 按条件获取数据
//返回有序集合中指定分数区间内的成员
zrangebyscore key min max [WITHSCORES] [LIMIT]

//返回有序集合中指定分数区间内的成员,分数从高到低排序
zrevrangebyscore key max min [WITHSCORES]
  • 删除数据
zrem key member1 [member2 …]
  • 条件删除
zremrangebyrank key start stop //移除有序集合中给定的索引区间的所有成员
zremrangebyscore key min max //移除有序集合中给定的分数区间的所有成员
  • 获取集合数据总量
zcard key //获取数据总量
zcount key min max //获取某一个分数范围内的数据总量
  • 集合交、并存储操作
//求交集,(destination:目标集合key, numkeys:集合数量)
zinterstore destination numkeys key1 [key2 …] 

//求并集,(destination:目标集合key, numkeys:集合数量)
zunionstore destination numkeys key1 [key2 …]

image.png

  • 获取数据对应的索引(排名)
zrank key member  //正数第几位, 数据的正序索引

zrevrank key member  //倒数第几位,数据的倒序索引
  • score 值获取与修改
 zscore key member  //获取数据元素的分数

 zincrby key increment member   //score递增increment
  • 注意:
  1. min与max用于限定搜索查询的分数条件
  2. start与stop用于限定查询范围,作用于索引,表示开始和结束索引
  3. offset与count用于限定查询范围,作用于查询结果,表示开始位置和数据总量

更多命令: www.runoob.com/redis/redis…

  • sorted_set 类型数据操作的注意事项
  1. score 保存的数据存储空间是64位。
  2. score保存的数据也可以是一个双精度的double值,基于双精度浮点数的特征,可能会丢失精度,使用时侯要慎重。
  3. sorted_set底层存储还是基于set结构的,因此数据不能重复,如果重复添加相同的数据,score值将会被反复覆盖,保留最后一次修改的结果。

sorted set类型应用场景:

  • 排行榜:有序集合经典使用场景。例如商品售卖的排行榜,视频网站需要对用户上传的视频做排行榜,榜单维护可能是多方面:按照时间、按照播放量、按照获得的赞数等。

  • Sorted Sets来做带权重的队列,比如普通消息的score为1,重要消息的score为2,然后工作线程可以选择按score的倒序来获取工作任务。让重要的任务优先执行。