Redis的使用

一、redis介绍

概念:Redis,英文全称是Remote Dictionary Server(远程字典服务),非关系型数据库,是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API

与mysql的区别?

与MySQL数据库不同的是,Redis的数据是存在内存中的。它的读写速度非常快,每秒可以处理超过10万次读写操作。因此redis被广泛应用于缓存,另外,Redis也经常用来做分布式锁。除此之外,Redis支持事务、持久化、LUA 脚本、LRU 驱动事件、多种集群方案。

redis为什么这么快?

img

二、redis的五种基本数据类型

redis是key-value的存储结构,key都是String类型的,value有五种基本数据类型。如下:

在这里插入图片描述

1.String(字符串)

概念:redis中的value是String类型。 可以存储图片或者序列化对象,值最大512M。

使用:get key、set key value、 del key

场景:共享session、分布式锁、计数器、限流等。

2.hash(哈希)

概念:redis中的value是哈希结构,哈希结构本身就是key-value

使用:hset key field value、hget key field

场景:缓存用户信息等

3.list(列表)

概念:存储多个有序的字符串,最多可以存储2^32-1

使用:lpush key value [value …] 、lrange key start end

场景:消息队列,文章列表

  • lpush+lpop=Stack(栈)
  • lpush+rpop=Queue(队列)
  • lpsh+ltrim=Capped Collection(有限集合)
  • lpush+brpop=Message Queue(消息队列)

4.set(集合)

概念: 集合(set)类型也是用来保存多个的字符串元素,但是不允许重复元素

使用: sadd key element [element…] 、smembers key

场景:用户标签、生成随机数抽奖、社交需求

5.zset(有序集合)

概念: 已排序的字符串集合,同时元素不能重复

使用: zadd key score member [score member …]、zrank key member

场景: 排行榜,社交需求(如用户点赞)。

三、redis的使用场景

  • 缓存
  • 排行榜

当今互联网应用,有各种各样的排行榜,如电商网站的月度销量排行榜、社交APP的礼物排行榜、小程序的投票排行榜等等。Redis提供的zset数据类型能够实现这些复杂的排行榜。

比如,用户每天上传视频,获得点赞的排行榜可以这样设计:

1.用户Jay上传一个视频,获得6个赞,可以这样:
zadd user:ranking:2021-03-03 Jay 3

2.过了一段时间,再获得一个赞,可以这样:
zincrby user:ranking:2021-03-03 Jay 1

3.如果某个用户John作弊,需要删除该用户:
zrem user:ranking:2021-03-03 John

4.展示获取赞数最多的3个用户
zrevrangebyrank user:ranking:2021-03-03 0 2
  • 计数器应用

各大网站、APP应用经常需要计数器的功能,如短视频的播放数、电商网站的浏览数。这些播放数、浏览数一般要求实时的,每一次播放和浏览都要做加1的操作,如果并发量很大对于传统关系型数据的性能是一种挑战。Redis天然支持计数功能而且计数的性能也非常好,可以说是计数器系统的重要选择。

  • 共享Session

如果一个分布式Web服务将用户的Session信息保存在各自服务器,用户刷新一次可能就需要重新登录了,这样显然有问题。实际上,可以使用Redis将用户的Session进行集中管理,每次用户更新或者查询登录信息都直接从Redis中集中获取。

  • 分布式锁

几乎每个互联网公司中都使用了分布式部署,分布式服务下,就会遇到对同一个资源的并发访问的技术难题,如秒杀、下单减库存等场景。

用synchronize或者reentrantlock本地锁肯定是不行的。
如果是并发量不大话,使用数据库的悲观锁、乐观锁来实现没啥问题。
但是在并发量高的场合中,利用数据库锁来控制资源的并发访问,会影响数据库的性能。
实际上,可以用Redis的setnx来实现分布式的锁。

  • 社交网络

赞/踩、粉丝、共同好友/喜好、推送、下拉刷新等是社交网站的必备功能,由于社交网站访问量通常比较大,而且传统的关系型数据不太适保存 这种类型的数据,Redis提供的数据结构可以相对比较容易地实现这些功能。

  • 消息队列

消息队列是大型网站必用中间件,如ActiveMQ、RabbitMQ、Kafka等流行的消息队列中间件,主要用于业务解耦、流量削峰及异步处理实时性低的业务。Redis提供了发布/订阅及阻塞队列功能,能实现一个简单的消息队列系统。另外,这个不能和专业的消息中间件相比

  • 位操作

用于数据量上亿的场景下,例如几亿用户系统的签到,去重登录次数统计,某用户是否在线状态等等。腾讯10亿用户,要几个毫秒内查询到某个用户是否在线,能怎么做?千万别说给每个用户建立一个key,然后挨个记(你可以算一下需要的内存会很恐怖,而且这种类似的需求很多。这里要用到位操作——使用setbit、getbit、bitcount命令。原理是:redis内构建一个足够长的数组,每个数组元素只能是0和1两个值,然后这个数组的下标index用来表示用户id(必须是数字哈),那么很显然,这个几亿长的大数组就能通过下标和元素值(0和1)来构建一个记忆系统。

四、redis的三个问题:缓存击穿、缓存穿透、缓存雪崩

我们都知道,一个请求来了,首先查询的是redis,未命中缓存就会去查询数据,然后更新缓存,这种操作就会带来一些问题。问题如下:

4.1.缓存击穿

概念:缓存中的一些热点key在某个时间点过期,导致一些请求查询redis没有,但是查询数据库中有的数据。增大了数据库的压力,但不会雪崩,这就是缓存击穿。

解决方案:

​ a.设置key永不过期:就是对key不设置过期时间。但是热点数据快要过期时,异步线程去更新和设置过期时间。

​ b.使用互斥锁:缓存失效时,先不访问db,而是先使用某些成功返回带原子操作命令(redis的setNx),成功的时候,再去访问db数据库和设置缓存,否则就去重新获取缓存。

4.2.缓存穿透

概念:查询一个不存在redis和db的数据。每次请求都要到数据库查询,给数据库带来压力。

产生的几种情况:

​ ·业务设计的不合理

​ ·黑客非法请求攻击

​ ·缓存和数据库的数据误删

解决方案:

​ ·如果是非法请求,在api入口处,对参数进行校验,过滤非法值。

​ ·缓存设置空值或者默认值,如果有写请求进来,就更新缓存,同时设置过期时间,保证缓存与数据库的一致性。

​ ·使用布隆过滤器: 它由初始值为0的位图数组和N个哈希函数组成。一个对一个key进行N个hash算法获取N个值,在比特数组中将这N个值散列后设定为1,然后查的时候如果特定的这几个位置都为1,那么布隆过滤器判断该key存在。

4.3.缓存雪崩

概念:缓存中大量数据的过期时间到期,而查询数据量巨大,请求直接落在数据库上,引起数据库压力过大而宕机。还可能是redis的故障宕机,就可以搭建redis高可用集群了。

解决方案:

​ ·对于key的过期时间可以随机设置,让过期时间相对离散。

​ ·搭建集群,一台挂了还有其他redis节点可用。

五、redis的key过期策略

我们在set key的时候,可以给它设置一个过期时间:expire key 60,指定key60秒后过期,但是过期后,redis是怎么处理的?

答:有三种策略

1.定时过期

每个设置过期时间的key都需要创建一个定时器,到过期时间就会立即对key进行清除。该策略可以立即清除过期的数据,对内存很友好;但是会占用大量的CPU资源去处理过期的数据,从而影响缓存的响应时间和吞吐量。

2.惰性过期

只有当访问一个key时,才会判断该key是否已过期,过期则清除。该策略可以最大化地节省CPU资源,却对内存非常不友好。极端情况可能出现大量的过期key没有再次被访问,从而不会被清除,占用大量内存。

3.定期过期

每隔一定的时间,会扫描一定数量的数据库的expires字典中一定数量的key,并清除其中已过期的key。该策略是前两者的一个折中方案。通过调整定时扫描的时间间隔和每次扫描的限定耗时,可以在不同情况下使得CPU和内存资源达到最优的平衡效果。

expires字典会保存所有设置了过期时间的key的过期时间数据,其中,key是指向键空间中的某个键的指针,value是该键的毫秒精度的UNIX时间戳表示的过期时间。键空间是指该Redis集群中保存的所有键。

redis同时使用定时过期和惰性过期两种过期策略:

-假设Redis当前存放30万个key,并且都设置了过期时间,如果你每隔100ms就去检查这全部的key,CPU负载会特别高,最后可能会挂掉。
-因此,redis采取的是定期过期,每隔100ms就随机抽取一定数量的key来检查和删除的。
-但是呢,最后可能会有很多已经过期的key没被删除。这时候,redis采用惰性删除。在你获取某个key的时候,redis会检查一下,这个key如果设置了过期时间并且已经过期了,此时就会删除。

六、redis的内存淘汰策略

如果定期删除漏掉了很多过期的key,然后也没走惰性删除。就会有很多过期key积在内存内存,直接会导致内存爆的。或者有些时候,业务量大起来了,redis的key被大量使用,内存直接不够了,运维小哥哥也忘记加大内存了。难道redis直接这样挂掉?不会的! redis有内存淘汰策略。

volatile-lru:当内存不足以容纳新写入数据时,从设置了过期时间的key中使用LRU(最近最少使用)算法进行淘汰;
allkeys-lru:当内存不足以容纳新写入数据时,从所有key中使用LRU(最近最少使用)算法进行淘汰。
volatile-lfu:4.0版本新增,当内存不足以容纳新写入数据时,在过期的key中,使用LFU算法进行删除key。
allkeys-lfu:4.0版本新增,当内存不足以容纳新写入数据时,从所有key中使用LFU算法进行淘汰;
volatile-random:当内存不足以容纳新写入数据时,从设置了过期时间的key中,随机淘汰数据;。
allkeys-random:当内存不足以容纳新写入数据时,从所有key中随机淘汰数据。
volatile-ttl:当内存不足以容纳新写入数据时,在设置了过期时间的key中,根据过期时间进行淘汰,越早过期的优先被淘汰;
noeviction:默认策略,当内存不足以容纳新写入数据时,新写入操作会报错。

七、redis的持久化机制

Redis是基于内存的非关系型K-V数据库,既然它是基于内存的,如果Redis服务器挂了,数据就会丢失。为了避免数据丢失了,Redis提供了持久化,即把数据保存到磁盘。

Redis提供了RDB和AOF两种持久化机制,它持久化文件加载流程如下:
在这里插入图片描述

7.1.RDB

概念:全称 redis database: 就是把内存数据以快照的形式保存到磁盘上。

RDB持久化,是指在指定的时间间隔内,执行指定次数的写操作,将内存中的数据集快照写入磁盘中,它是Redis默认的持久化方式。执行完操作后,在指定目录下会生成一个dump.rdb文件,Redis 重启的时候,通过加载dump.rdb文件来恢复数据。RDB触发机制主要有以下几种:

在这里插入图片描述

优点:适合大规模数据恢复,如备份、全量复制。

缺点:没办法做到实时持久化

7.2.AOF

概念:全称 append only file: 采用日志的形式来记录每个写操作,追加到文件中,重启时再重新执行AOF文件中的命令来恢复数据。它主要解决数据持久化的实时性问题。默认是不开启的。

aof工作流程如下:

在这里插入图片描述

优点:数据的一致性和完整性更高

缺点: AOF记录的内容越多,文件越大,数据恢复变慢

八、redis的高可用

我们在项目中使用Redis,肯定不会是单点部署Redis服务的。因为,单点部署一旦宕机,就不可用了。为了实现高可用,通常的做法是,将数据库复制多个副本以部署在不同的服务器上,其中一台挂了也可以继续提供服务。Redis 实现高可用有三种部署模式:主从模式,哨兵模式,集群模式

8.1.主从模式

主从模式中,Redis部署了多台机器,有主节点,负责读写操作,有从节点,只负责读操作。从节点的数据来自主节点,实现原理就是主从复制机制

主从复制包括全量复制,增量复制两种。一般当slave第一次启动连接master,或者认为是第一次连接,就采用全量复制,全量复制流程如下:

img

1.slave发送sync命令到master。
2.master接收到SYNC命令后,执行bgsave命令,生成RDB全量文件。
3.master使用缓冲区,记录RDB快照生成期间的所有写命令。
4.master执行完bgsave后,向所有slave发送RDB快照文件。
5.slave收到RDB快照文件后,载入、解析收到的快照。
6.master使用缓冲区,记录RDB同步期间生成的所有写的命令。
7.master快照发送完毕后,开始向slave发送缓冲区中的写命令;
8.salve接受命令请求,并执行来自master缓冲区的写命令

redis2.8版本之后,已经使用psync来替代sync,因为sync命令非常消耗系统资源,psync的效率更高。

slave与master全量同步之后,master上的数据,如果再次发生更新,就会触发增量复制。

当master节点发生数据增减时,就会触发replicationFeedSalves()函数,接下来在 Master节点上调用的每一个命令会使用replicationFeedSlaves()来同步到Slave节点。执行此函数之前呢,master节点会判断用户执行的命令是否有数据更新,如果有数据更新的话,并且slave节点不为空,就会执行此函数。这个函数作用就是:把用户执行的命令发送到所有的slave节点,让slave节点执行。流程如下:
img

8.2.哨兵模式

由一个或多个Sentinel实例组成的Sentinel系统,它可以监视所有的Redis主节点和从节点,并在被监视的主节点进入下线状态时,自动将下线主服务器属下的某个从节点升级为新的主节点。但是呢,一个哨兵进程对Redis节点进行监控,就可能会出现问题(单点问题),因此,可以使用多个哨兵来进行监控Redis节点,并且各个哨兵之间还会进行监控。
img

哨兵的作用:

  • 发送命令,等待Redis服务器(包括主服务器和从服务器)返回监控其运行状态;
  • 哨兵监测到主节点宕机,会自动将从节点切换成主节点,然后通过发布订阅模式通知其他的从节点,修改配置文件,让它们切换主机;
  • 哨兵之间还会相互监控,从而达到高可用。

哨兵的工作模式:

  1. 每个Sentinel以每秒钟一次的频率向它所知的Master,Slave以及其他Sentinel实例发送一个 PING命令。
    2.如果一个实例(instance)距离最后一次有效回复 PING 命令的时间超过 down-after-milliseconds 选项所指定的值, 则这个实例会被 Sentinel标记为主观下线。
    3.如果一个Master被标记为主观下线,则正在监视这个Master的所有 Sentinel 要以每秒一次的频率确认Master的确进入了主观下线状态。
    4.当有足够数量的 Sentinel(大于等于配置文件指定的值)在指定的时间范围内确认Master的确进入了主观下线状态, 则Master会被标记为客观下线。
    5.在一般情况下, 每个 Sentinel 会以每10秒一次的频率向它已知的所有Master,Slave发送 INFO 命令。
    6.当Master被 Sentinel 标记为客观下线时,Sentinel 向下线的 Master 的所有 Slave 发送 INFO 命令的频率会从 10 秒一次改为每秒一次
    7.若没有足够数量的 Sentinel同意Master已经下线, Master的客观下线状态就会被移除;若Master 重新向 Sentinel 的 PING 命令返回有效回复, Master 的主观下线状态就会被移除。

8.3.集群模式

哨兵模式基于主从模式,实现读写分离,它还可以自动切换,系统可用性更高。但是它每个节点存储的数据是一样的,浪费内存,并且不好在线扩容。因此,Cluster集群应运而生,它在Redis3.0加入的,实现了Redis的分布式存储。对数据进行分片,也就是说每台Redis节点上存储不同的内容,来解决在线扩容的问题。并且,它也提供复制和故障转移的功能。

Cluster集群节点的通讯

一个Redis集群由多个节点组成,各个节点之间是怎么通信的呢?通过Gossip协议!

Redis Cluster集群通过Gossip协议进行通信,节点之前不断交换信息,交换的信息内容包括节点出现故障、新节点加入、主从节点变更信息、slot信息等等。常用的Gossip消息分为4种,分别是:ping、pong、meet、fail。

九、redis的安装

9.1windows下安装

默认端口:6379

1.下载地址: https://github.com/tporadowski/redis/releases

2.解压

在这里插入图片描述

3.当前目录下,cmd命令: redis-server.exe redis.windows.conf

在这里插入图片描述

4.双击redis-cli.exe启动客户端连接服务端 或者 命令: redis-cli.exe -h 127.0.0.1 -p 6379

5.在客户端输入 “ping”,出现“PONG”,即证明连接成功。

在这里插入图片描述

9.2Linux下安装

1.下载地址:http://redis.io/download,下载最新稳定版本。

2.本教程使用的最新文档版本为 2.8.17,下载并安装:

$ wget http://download.redis.io/releases/redis-2.8.17.tar.gz
$ tar -zxvf redis-2.8.17.tar.gz
$ cd redis-2.8.17
$ make

make完后 redis-2.8.17目录下会出现编译后的redis服务程序redis-server,还有用于测试的客户端程序redis-cli,两个程序位于默认安装路径是 /usr/local/bin目录下:

3.启动redis服务.

$ cd src
$ ./redis-server

使用指定配置文件使用下面命令启动。redis.conf 是一个默认的配置文件。我们可以根据需要使用自己的配置文件。

$ cd src
$ ./redis-server ../redis.conf

如果redis设置有密码,则需要现认证才能发送信息,"123456"是redis的密码

127.0.0.1:6379> auth "123456"

启动redis服务进程后,就可以使用测试客户端程序redis-cli和redis服务交互了。 比如:

$ cd src
$ ./redis-cli -p 6379
redis>ping
PONG

redis默认不是后台启动,需要修改配置文件: 将daemonize的值修改为yes

vim redis.conf

4.查看redis的进程

ps -ef|grep redis

5.关闭redis服务:客户端和服务器都会关闭

127.0.0.1:6379> shutdown

9.3Ubuntu 下安装

在 Ubuntu 系统安装 Redis 可以使用以下命令:

$sudo apt-get update

$sudo apt-get install redis-server

启动 Redis

$ redis-server

查看 redis 是否启动

$ redis-cli

以上命令将打开以下终端:

redis 127.0.0.1:6379>

127.0.0.1 是本机 IP ,6379 是 redis 服务端口。现在我们输入 PING 命令。

redis 127.0.0.1:6379> ping
PONG

以上说明我们已经成功安装了redis。

十、redis客户端的连接工具

1.下载redis客户端连接工具:RedisDesktopManager

2.双击启动rdm.exe

在这里插入图片描述

3.连接redis服务器

在这里插入图片描述

4.使用

在这里插入图片描述

十一、Redis的命令

11.1 连接redis服务器命令

1.连接本地redis服务命令:redis-cli

2.远程连接redis服务命令:redis-clo -h host -p port -a password

11.2 keys的常用命令

del key key存在时删除key

exists key 检查key是否存在

expire key seconds(秒) 为key设置过期时间,以秒计算

expire key timestamp(毫秒) 设置key的过期时间以毫秒计算

persist key 移除key的过期时间,key将持久保持

keys * 查询所有的键名

pttl key 以毫秒为单位返回key的剩余过期时间

randomkey  从当前数据库中随机返回一个key

rename key newkey  修改key的名称

renamenx key newkey 当newkey不存在时,将key改名为newkey

move key  db  将当前数据库的key移动到给定的数据库db当中

type key  返回key所存储值的类型

11.3 String类型的命令

set key value   设置指定key的value

get key   获取指定key的value

getset key value 为key设置新value,并返回key的旧value

mget  key1  key2 key3.....获取一个或多个key的value

setnx key value   key不存在时设置key的value

strlen  key 返回key所存储的字符串的长度

mset key1  value1   key2 value2 ....同时设置一个或多个key-value对

incr key 将key中存储的数字值增加1 

decr key 将key中存储的数字值减一。

incrby key increment  将key所存储的值加上给定的增量值increment

append key value     如果key存储的值是一个字符串,append命令将指定的value追加到key原来bvalue的末尾。

11.4 Hash类型的命令

hset key field value [field value]:  存放指定key的field和value值

hdel key filed1 field2   删除一个或多个哈希表字段

hexists key field 查看哈希表key中,指定的字段是否存在

hget key field  获取存储在哈希表中指定字段的值

hgetall key 获取在哈希表中指定key的所有字段和值

hincrby key field increment 为哈希表key中指定的字段的整数值加上增量increment

hkeys key  获取所有哈希表中的字段

hlen key  获取哈希表中字段的数量

hmget key field1 field2  获取所有给定字段的值

hmset key field1 value1 field2 value3 .......   同时将多个field-value(域-值)对设置到哈希表key中

hvals key获取哈希表中所有的值

11.5 List(列表)类型的命令

llen key 获取列表长度

lpop key 移出并获取列表的第一个元素

lpush key value1 value2...  将一个或多个值插入到列表的头部

lpushx key value 将一个值插入到已存在的列表的头部

lrange key 0    -1    获取指定范围内的元素

lrem key count value 移除列表中的元素

lset key index value  通过索引(下标)设置列表元素的值

ltrim key 0  6  对一个列表进行修剪   让列表只保留指定区间内的元素,不在指定区间的元素都将被删除

rpop key   移除列表的最后一个一个元素,返回值为移除的元素

rpoplpush  列表      列表     移除列表的最后一个元素,并将该元素添加到另一个列表并返回

Rpush key value1 value2  在列表中添加一个或多个值

rpushx key value  为已存在的列表添加值

11.6 Set(集合)类型的命令

Set 是 String 类型的无序集合。集合成员是唯一的,这就意味着集合中不能出现重复的数据。

sadd key member1....向集合添加一个或多个成员

scard key   获取集合的成员数

sdlff  key1    key2返回第一个集合和第二个集合(其他集合)之间的差异

sinter key1  key2    返回给定所有集合的交集

sismember key member  判断member元素是否是集合key的成员

smembers key  返回集合中的所有成员

smove source destination member   将member元素从source集合移动到 destination集合

spop key  移除并返回集合中的一个随机元素

srandmember key   数字    返回集合中一个或多个随机数

srem key member1 .....  移除集合中一个或多个成员

sunion key1  key2  返回所有给定集合的并集

11.7 Zset(有序集合)的命令

zset集合和无序集合一样都是string类型元素的集合,且不允许重复的成员。

不同的是每个元素都会关联一个 double 类型的分数。redis 正是通过分数来为集合中的成员进行从小到大的排序。

有序集合的成员是唯一的,但分数(score)却可以重复。

zadd key score1 member1  【score2 member2】  向有序集合添加一个或多个成员,或者更新已经存在的分数

zcard key  获取有序集合的成员数

zcount key min  max计算在有序集合中指定区间分数的成员数

zrange key start stop  withscores  通过索引区间返回有序集合指定区间内的成员

zrevrangebyscore key max min  withscores  返回有序集合中指定分数区间内的成员,分数从高到低排序

zscore key member 返回有序集合中,成员的分数值
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值