目录
Redis = Remote Dictionary Server,即远程字典服务。是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库(NoSQL数据库),并提供多种语言的API。与memcached一样,为了保证效率,数据都是缓存在内存中。区别的是redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步。
Redis官方是支持Linux系统的 Redis ;Windows 版本是非官方制作,用于本地测试等,这里安装的windows redis 版本为redis-7.0.11-windows 64位版本。
安装
1.解压压缩包到磁盘任意目录 打开redis.conf文件 根据需要,修改端口号、 设置密码、 内存等。
2.在安装目录下,使用cmd命令创建service服务
redis-server --service-install redis.conf --loglevel verbose
3.开启服务,登录redis,输入密码(password为conf里设置的requirepass值)
redis-server --service-start
redis-cli
auth password
为了方便使用,还可以安装 Another Redis Desktop Manager 工具来执行Redis命令,Redis默认16个数据库(db0~db15,一般只使用db0)
redis语法
通用指令
redis的大部分指令和数据类型有关,但也有一些比较基础的指令是通用的。
- KEYS 查询与pattern匹配的 keys。格式:KEYS [pattern]
- DEL 删除指定的 key,支持一次性删除多个。 格式:DEL key [key ...]
- TTL 查询一个 key 的剩余有效时间 格式:TTL key 返回值: 已过期:-2 永久有效:-1 仍有效:>=0
支持的pattern格式:
- h?llo 匹配 hello, hallo 和 hxllo
- h*llo 匹配 hllo 和 heeeello
- h[ae]llo 匹配 hello 和 hallo, 但不能匹配 hillo
- h[^e]llo 匹配 hallo, hbllo, ... 但不能匹配 hello
- h[a-b]llo 匹配 hallo 和 hbllo
五种数据类型
String、list、set、hash、zset(有序集合)
String的操作指令
SET 设置指定key的value。 语法:SET key value
GET 获取指定key的value。 语法:GET key
MSET和MGET 批量设置和获取多个值。 语法: MSET key value [key value] MGET key [key]
INCR increase:指定的key的数值加一,前提是指定的key的value可以转换为数值。 语法:INCR key。操作成功之后,会返回更新后的值。
INCRBY increase by:与INCR类似,但是可以指定增加的数值,可以传入负值从而实现减法。 语法:INCRBY KEY INCREAMENT
DECR decrease:INCR的相反操作。但可以通过INCRBY和-1实现,所以DECR比较少用到
set expire:设置一个值,同时设置其有效时间(以秒为单位),有效时间结束后,这个值将失效。语法:SETEX key seconds value
hash的操作指令
hash是一个 string 类型的 field(字段) 和 value(值) 的映射表,hash 特别适合用于存储对象。 类似于string类型,最基础的指令是 set 和 get 指令,hash相应的指令在前面有一个h前缀表示hash。 HSET和HMSET ,HMSET可以同时设置一个hash的多个字段。 在redis较新的版本中,HSET也支持同时设置多个字段了,HMSET已弃用。 语法:HSET key field value [field value ...]
HKEYS 获取一个哈希表中的所有字段 语法:HKEYS key
HVALS 获取一个哈希表中的所有值 语法:HVALS key
list的操作指令
list是简单的字符串列表,按照插入顺序排序。可以添加一个元素到列表的头部(左边)或者尾部(右边)。 列表的相关指令围绕几个关键字展开:B,L或R,PUSH或POP。B表示 block,即阻塞。 L或R指 left 或 right,指从列表的左边或右边进行操作。PUSH或POP是推入或弹出,是list新增或删减元素的操作。
LINDEX 根据index获取列表中指定位置的元素。 语法:LINDEX key index
LSET 编辑列表中指定位置的元素。 语法:LSET key index element
LLEN 获取列表的长度。 语法:LLEN key
set的操作指令
Set 是 String 类型的无序集合。集合成员是唯一的,这就意味着集合中不能出现重复的数据。
SADD 向集合中添加若干个成员。 语法:SADD key member [member ...]
SCARD 获取集合的成员数量。 语法:SCARD key
SMEMBERS 获取集合的所有成员。 语法:SMEMBERS key
SISMEMBER set-is-member:用于查询一个值是否是集合的成员之一。 语法:SISMEMBER key member
SREM set-remove:用于移除若干成员。 语法:SREM key member [member ...]
SRANDMEMBER set-random-member:随机获取指定数量的集合成员。 语法:SRANDMEMBER key [count] [count]参数可选,缺省值为1.
SPOP set-pop:随机弹出指定数量的集合成员。 语法:SPOP key [count]
关于多个集合的操作
SINTER 若干个集合的交集。 语法:SINTER key [key ...]
SUNION 若干个集合的并集。 语法:SUNION key [key ...]
zset的操作指令
有序集合的每一个成员都会携带一个double类型的score用于排序。 对于集合中的成员,score是可以相同的,但是member即成员不能相同。
ZADD 添加成员,先写score再写member,可以写多组。语法:ZADD key score1 member1 [score2 member2 ...]
ZCARD 获取集合的成员数量。 语法:ZCARD key
ZCOUNT 计算在有序集合中指定区间分数的成员数。 语法:ZCOUNT key min max
ZINCRBY 对指定成员的score加上增量increment. 语法:ZINCRBY key increment member,返回增加成功后的score
ZRANGE 通过索引区间返回有序集合指定区间内的成员。 语法:ZRANGE key start stop [WITHSCORES],start和stop是该有序集合排序之后的index区间。
ZRANGEBYSCORE 通过分数返回有序集合指定区间内的成员。 语法:ZRANGEBYSCORE key min max
ZRANK 返回指定成员的索引。 语法:ZRANK key member
ZREM 移除一个或多个成员。 语法:ZREM key member [member ...]
EXPIRE mykey time EXPIRE命令允许用户设置Key的过期时间,时间单位为秒
Redis的原子性命令
Redis提供了多个原子性命令,用于在单个操作中执行多个操作,确保它们在执行过程中不会被其他命令中断。以下是几个常见的原子性命令:
SETNX:如果指定的键不存在,则设置键的值为指定值。只在键不存在时执行。
GETSET:设置指定键的新值,并返回键之前的旧值。确保其他命令在SET和GET操作中间不会干扰。
INCR、DECR:对指定键的整数值进行递增或递减。保证在执行过程中不会有其他命令干扰。
MSET、MSETNX:分别用于设置多个键值对和多个不存在的键值对。确保设置操作在执行过程中不会被其他命令中断。
HSET、HSETNX:用于设置哈希表中指定字段的值,并返回是否成功设置。确保设置操作在执行过程中不会被其他命令中断。
LPUSH、RPUSH:分别在列表的头部和尾部插入一个或多个元素。确保在执行过程中不会有其他命令干扰。
缓存淘汰策略
三种缓存淘汰策略:
- FIFO- First In First Out ---- 先进先出
- LFU - Least Frequently Used ---- 最少 - 使用
- LRU - Least Recently Used ---- 最近 - 最少 - 使用
修改redis.conf文件,更改淘汰策略
maxmemory-policy allkeys-lru
Redis缓存的八种淘汰策略
- noeviction: 不会驱逐任何key,即当内存超出限制后,报错返回OOM,但不驱逐任何key(出厂默认配置)
- allkeys-lru: 对所有key使用LRU算法进行删除(推荐)
- volatile-lru: 对所有设置了过期时间的key使用LRU算法进行删除
- allkeys-random: 对所有key随机删除
- volatile-random: 对所有设置了过期时间的key随机删除
- volatile-ttl: 删除马上要过期的key
- allkeys-lfu: 对所有key使用LFU算法进行删除
- volatile-lfu: 对所有设置了过期时间的key使用LFU算法进行删除
缓存问题
缓存穿透
是指客户端请求的数据在缓存中和数据库中都不存在,这样缓存永远不会生效,这些请求都会打到数据库。
解决方案:发现数据不存在,就将null值打入Redis中
优点:实现简单,维护方便 缺点:额外的内存消耗,可能造成短期的不一致
缓存雪崩
是指在同一时段大量的缓存key同时失效或者Redis服务宕机,导致大量请求到达数据库,带来巨大压力
解决方案:
- 给不同的Key的TTL添加随机值(推荐) 设置过期时间TTL的时候,定义一个范围,追加该范围内的一个随机数。
- 利用Redis集群提高服务的可用性(使用集群提高可靠性)
- 给缓存业务添加降级限流策略(微服务的知识)
缓存击穿
缓存雪崩是因为大量的key同时过期所导致的问题,而缓存击穿则是部分key过期导致的严重后果。
缓存击穿问题也叫热点Key问题,就是⼀个被高并发访问并且缓存重建业务较复杂的key突然失效了,无数的请求访问会在瞬间给数据库带来巨大的冲击。
解决方案:
(1)互斥锁
简单的来说就是,并不是所有的线程都有 “ 资格 ” 去访问数据库,只有持有锁的线程才可以对其进行操作。 不过该操作有一个很明显的问题,就是会出现相互等待的情况。
(2)逻辑过期
不设置TTL,之前所说导致缓存击穿的原因就是该key的TTL到期了,所以我们在这就不设置TTL了,而是使用一个字段例如:expire表示过期时间(逻辑上的)。当我们想让它 “ 过期 ” 的时候,我们可以直接手动将其删除(热点key,即只是在一段时间内,其被访问的频次很高)
Redis的RDB与AOF
因为Redis数据基于内存读写,为了防止Redis服务器关闭或者宕机造成数据丢失,我们通常需要对Redis最磁极化,即:把内从中的数据(命令)保存一份到磁盘做一个备份,当Redis服务关闭或者宕机, 在Redis服务器重启的时候会从磁盘重新加载备份的数据,不至于数据丢失。 Redis 提供了两种不同级别的持久化方式:RDB和AOF,可以通过修改redis.conf来进行配置. 开启持久配置后,对Redis进行写操作,在Redis安装目录将会看到持久文件:“appendonly.aof”和“ dump.rdb
众所周知,Redis是通过AOF和RDB进行数据的持久化存储, Redis为了考虑效率,保存数据在内容中.并且考虑数据安全性,还做数据持久化,如果满足保存策略,就会把内存的数据保存到数据rdb文件,还来不及保存那部分数据存放到aof更新日志中。在加载时,把两个数据做一个并集。
RDB概念及原理
RDB是Redis DataBase的缩写,意为内存快照。因为Redis的数据时保存在内存中的,就意味着每当服务重启时都会导致内存中的数据丢失,这时候就需要RDB来进行数据恢复了。RDB就是说它每隔一段时间,会将Redis中的数据以RDB文件格式的形式对数据进行一个保存。在我们的服务重启后Redis会自动找到RDB文件中存储的数据并加载到内存中。 RDB又有两种持久化方案,分为全量快照和增量快照
优缺点:优点适合大规模的数据恢复。对数据完整性和一致性要求不高时适用。 缺点在一定间隔时间做一次备份,所以如果 redis 意外 down 掉的话,就会丢失最后一次快照后的所有修改。Fork 的时候,内存中的数据被克隆了一份,大致 2 倍的膨胀性需要考虑
#RDB 配置
dir C:/redis-7.0.11-windows/master-slave/
# 备份文件的名称 默认为dump.rdb
dbfilename dump.rdb
#rdb文件是否压缩,默认为yes
rdbcompression yes
# 是否检查备份文件的完整性,默认为yes
rdbchecksum yes
#当redis磁盘满时,是否停止redis写操作,默认为yes
stop-writes-on-bgsave-error yes
# 900sec(15分钟)后,如果至少有一个键改变(就进行持久化)
save 900 1
#在300秒(5分钟)后,如果至少10个键改变(就进行持久化)
save 300 10
#在60秒后,如果至少有10000个键被更改(就进行持久化)
save 60 10000
AOF概念及原理
AOF是Append Only File的缩写,是以独立日志的方式记录每次写操作的命令,服务重启时再重新执行AOF文件中的命令达到恢复数据的目的。因为RDB是每隔一段时间对数据进行一次快照,会有一个窗口期,但是对于有些业务,是不能容忍数据丢失的,这时候就需要结合AOF来进行持久化存储。他使用颗粒度更细的方式,通过记录每一条命令进行数据的持久化。 但是颗粒度更细意味着需要更多的内存,更低的性能和更慢的速度,所以一般我们都会结合RDB一起使用。 AOF会以日志的形式记录一段时间内的写操作(包括insert和update操作)。 每次对Redis中的数据进行写操作时都会新增一条修改内容的记录 每次在Redis重启后会根据AOF中记录的指令从头到尾执行一次
优缺点:优点appendfsync always:每次修改同步。同步持久化,每次发生数据变更会被立即记录到磁盘。性能较差,但数据完整性比较好。 appendfsync everysec:每秒同步。异步操作,每秒记录 ,如果一秒内宕机,有数据丢失。 appendfsync no:不同步。从不同步。缺点相同数据集的数据而言,AOF 文件要远大于 RDB 文件,恢复速度慢于 RDB。AOF 运行效率要慢于 RDB,每秒同步策略效率较好,不同步效率和 RDB 相同。
AOF 重写机制
随着Redis的运行,AOF的日志会越来越长,如果实例宕机重启,那么重放整个AOF将会变得十分耗时,而在日志记录中,又有很多无意义的记录,比如我现在将一个数据 incr 一千次,那么就不需要去记录这1000次修改,只需要记录最后的值即可。所以就需要进行 AOF 重写。 Redis 提供了bgrewriteaof指令用于对AOF日志进行重写,该指令运行时会开辟一个子进程对内存进行遍历,然后将其转换为一系列的 Redis 的操作指令,再序列化到一个日志文件中。完成后再替换原有的AOF文件,至此完成。 同样的也可以在redis.config中对重写机制的触发进行配置:通过将no-appendfsync-on-rewrite设置为yes,开启重写机制;auto-aof-rewrite-percentage 100意为比上次从写后文件大小增长了100%再次触发重写; auto-aof-rewrite-min-size 64mb意为当文件至少要达到64mb才会触发制动重写
#配置AOF持久化,默认为 no,即不开启
appendonly yes
# 备份文件的位置
#dir C:/redis-7.0.11-windows/master-slave/
#备份文件的名称,默认为appendonly.aof"
appendfilename "appendonly.aof"
# appendfsync aof持久化策略的配置:
#no:不执行fsync,由操作系统保证数据同步到磁盘,速度最快。
#always:每次写入都执行fsync,以保证数据同步到磁盘。
#everysec:每秒执行一次fsync,可能会导致丢失这1s数据。
appendfsync everysec
# 是否以append only模式作为持久化方式,默认使用的是rdb方式持久化,这种方式在许多应用中已经足够用了
# appendfsync no
#重写开启条件,默认自动重写大小为64MB 上一次重写占比100%,
#当AOF文件的大小超过上一次重写后大小的一定百分比时(默认为100),或者超过64MB
#Redis会自动启动AOF重写过程,以减小AOF文件的体积。
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
#Redis启动时,如果AOF文件被截断(部分数据被裁剪)的操作,默认为yes
# yes:忽略截断的部分,并警告用户。
# no:忽略截断并继续启动,不警告用户
aof-load-truncated yes
#是否添加RDB文件的内容,默认为yes,即在AOF文件中首先添加RDB文件的内容,以节省加载AOF文件时的时间。
#no 不添加RDB文件内容到AOF文件中。
aof-use-rdb-preamble yes
#在执行AOF重写期间是否禁止对AOF文件进行fsync。当Redis执行AOF重写时,它会生成一个新的AOF文件来替换现有的AOF文件,默认为 no
#即在AOF重写期间不禁用AOF文件的fsync操作。当Redis执行AOF重写时,它会在每个写入操作后同步AOF文件到硬盘,以提供持久化保证。
#如果设置为yes,则在AOF重写期间,Redis将禁止对AOF文件执行fsync操作。这意味着在重写期间,Redis不会将重写操作同步到硬盘。
no-appendfsync-on-rewrite no
发布与订阅
Redis发布与订阅是一种消息通信的模式:发送者(pub)发送消息,订阅者(sub)接收消息。
redis通过PUBLISH和SUBSCRIBE等命令实现了订阅与发布模式,这个功能提供两种信息机制,分别是订阅/发布到频道、订阅/发布到模式的客户端。
流程:
- 发布者发布消息
- 订阅者订阅消息
- 执行subscribe后客户端会进入订阅状态,仅可以使subscribe、unsubscribe、psubscribe和punsubscribe这四个属于"发布/订阅"之外的命令
订阅频道后的客户端可能会收到三种消息类型
- subscribe。表示订阅成功的反馈信息。第二个值是订阅成功的频道名称,第三个是当前客户端订阅的频道数量。
- message。表示接收到的消息,第二个值表示产生消息的频道名称,第三个值是消息的内容。
- unsubscribe。表示成功取消订阅某个频道。第二个值是对应的频道名称,第三个值是当前客户端订阅的频道数量,当此值为0时客户端会退出订阅状态,之后就可以执行其他非"发布/订阅"模式的命令了。