redis精华

2021-04-18  本文已影响0人  voidFan

一 redis简介

Redis 优势:

Redis与Memcached 的优势与区别

redis为什么这么快

二 redis基础知识

  1. redis.conf常用配置说明:
    • demonize 以守护进程方式启动
    • logfile 日志文件路径
    • port 端口:默认端口6379
    • dir 工作目录,AOF和RDB持久化文件生成的目录
  2. 基本操作
./redis-server  /etc/redis.conf                # 服务端启动
./redis-cli -h <host> -p <port> -a <password>  # 客服端连接
./redis-cli shutdown                           # 客服端停止
ping                 # 测试客户端和服务器之间的连接是否有效,有效返回PONG
echo                 # 打印特定的信息, 如: echo 'HELLO WORLD'
quit/exit            # 断开当前客户端与服务器之间的连接,可以重连
shutdown             # 直接关闭服务器  
select <index>       # 切换数据库,默认有16个数据库(从零从始编号)
dbsize               # 查看当前数据库的key的数量
flushdb              # 清空当前库
flushall             # 清空所有库
set key value                         # 存入字符串键值对
mset key value [key value ...]        # 批量储字符串键值对
setnx key value                       # 存入一个不存在的字符串键值对
get key                               # 获取一个字符串的键值
mget key [key, key, key, ...]         # 批量获取字符串的键值
del key                               # 删除一个键
expire key seconds                    # 设置一个键的过期时间(秒)
#Redis 如何设置密码及验证密码?在连接客户端时,添加-a password参数来进行解锁
config set requirepass 123456         #设置密码
auth 123456                           #授权密码 

三 Redis中的事务: WATCH,MULTI,EXEC,DISCARD

Redis事务以MULTI命令开始,EXEC/DISCARD命令结束

MULTI     # 开启事务(MULTI:开启事务)
INCT key
GET key
DISCARD   # 取消事务(DISCARD: 取消事务)
###########################################
MULTI
INCR key
INCR key 
EXEC      # 执行事务(EXEC: 执行事务块中的命令)

Redis中的Watch机制,在开启事务前,使用WATCH命令监视指定的key,形成乐观锁

WATCH   # 监视一个或者多个key,
UNWATCH # 取消WATCH对所有的key的监视

Redis事务不能嵌套。如果再收到MULTI命令开启事务,直接返回错误

事务中的错误处理

  1. 语法错误: 命令不存在,参数错误. 如果有语法错误,Redis在EXEC后直接返回错误,正确的命令也不会被执行
  2. 运行错误:指在运行命令的时候出现的问题,错误的不会被执行,正确的会被执行

四 Redis持久化机制(RDB/AOF)

RDB

快照的方式将内存中的数据写入一个临时文件,恢复时,用这个临时文件来恢复数据。
数据的备份(save和bsave是已rdb方式持久化)

  1. save命令(同步指令):redis会创建一个RDB的二进制文件。如果有老的RDB文件,那么新的会替换掉老的文件。
  2. bgsave命令(异步指令):fork一个子进程来备份数据,生成一个RDB文件。
  1. 只有一个文件 dump.rdb,方便持久化。
  2. 容灾性好,一个文件可以保存到安全的磁盘。
  3. 性能最大化,fork 子进程来完成写操作,让主进程继续处理命令,所以是IO最大化。使用单独子进程来进行持久化,主进程不会进行任何IO操作,保证了redis的高性能)
  4. 相对于数据集大时,比AOF的启动效率更高。
  1. 数据安全性低。
  2. RDB 是间隔一段时间进行持久化,如果持久化之间 redis 发生故障,会发生数据丢失。所以这种方式更适合数据要求不严谨的时候。

AOF(Append-only file):记录命令行操作,将其保存为aof文件。

  1. 数据安全: AOF持久化可以配置redis.conf中的appendfsync属性实现。
    1. always:每一次写操作都会调用一次fsync,将数据记录到aof文件中.(性能有影响)
    2. everysec:每隔一秒进行一次fsync调用,将缓冲区中的数据写到磁盘。但是当这一 次的fsync调用时长超过1秒时。Redis会采取延迟fsync的策略,再等一秒钟。也就是在两秒后再进行fsync,这一次的fsync就不管会执行多长时间都会进行。这时候由于在fsync时文件描述符会被阻塞,所以当前的写操作就会阻塞。
    3. no:不会主动调用fsync去将AOF日志同步到磁盘。(操作系统自动调度刷磁盘,性能是最好的。)
  2. 通过append模式写文件,即使中途服务器宕机,可以通过 redis-check-aof工具解决数据一致性问题。
  3. AOF机制的 rewrite 模式。AOF 文件没被 rewrite 之前(文件过大时会对命令进行合并重写),可以删除其中的某些命令(比如误操作的 flushall))
  1. AOF文件比RDB文件大,且恢复速度慢。
  2. 数据集大的时候,比rdb启动效率低。

redis过期键的删除策略(淘汰策略)

  1. 定时删除:在设置键的过期时间的同时,创建一个定时器 timer). 让定时器在键的过期时间来临时,立即执行对键的删除操作。
  2. 惰性删除:放任键过期不管,但是每次从键空间中获取键时,都检查取得的键是否过期,如果过期的话,就删除该键;如果没有过期,就返回该键。
  3. 定期删除:每隔一段时间程序就对数据库进行一次检查,删除里面的过期键。至于要删除多少过期键,以及要检查多少个数据库,则由算法决定。
  4. Redis 的回收策略(6种淘汰机制)
    • volatile-lru:从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰
    • volatile-ttl:从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰
    • volatile-random:从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰
    • allkeys-lru:从数据集(server.db[i].dict)中挑选最近最少使用的数据淘汰
    • allkeys-random:从数据集(server.db[i].dict)中任意选择数据淘汰
    • no-enviction(驱逐):禁止驱逐数据

注意:volatile 和 allkeys 规定了是对已设置过期时间的数据集淘汰数据还是从全部数据集淘汰数据,
后面的 lru、ttl 以及 random 是三种不同的淘汰策略,再加上一种 no-enviction 永不回收的策略。

  1. 使用策略规则:
    • 如果数据呈现幂律分布,也就是一部分数据访问频率高,一部分数据访问频率低,则使用 allkeys-lru
    • 如果数据呈现平等分布,也就是所有的数据访问频率都相同,则使用allkeys-random

五 redis缓存穿透、缓存雪崩、缓存击穿

未命名绘图-缓存穿透.png

缓存穿透

  1. 定义:通过key去查缓存,但是不存在对应的value,就穿透到DB查询。(利用不存在的key攻击DB)
  2. 优化:

缓存击穿

未命名绘图-击穿雪崩.png
  1. 定义:对于设置了过期时间的 key,缓存在某个时间点过期的时候,
    恰好这时间点对这个 Key 有大量的并发请求过来,
    这些请求发现缓存过期一般都会从后端 DB 加载数据并回设到缓存,
    这个时候大并发的请求可能会瞬间把 DB 压垮。
  2. 优化:

缓存雪崩: 与缓存击穿的区别:雪崩是很多 key,击穿是某一个key 缓存。

  1. 定义:缓存服务器大量缓存集中在某一时间段失效。导致请求都直接打到DB,导致系统崩溃。
  2. 优化

六 redis集群

1. redis主从复制

  1. 作用:主从备份,防止节点宕机。使得读写分离,达到负载均衡的目的。
  2. 工作原理:Redis的主从结构可以采用一主多从或者级联结构,Redis主从复制可以根据是否是全量分为全量同步和增量同步
  3. 全量同步:Redis全量复制一般发生在Slave初始化阶段,这时Slave需要将Master上的所有数据都复制一份。具体步骤如下:
  1. 增量同步:Redis增量复制是指Slave初始化后开始正常工作时主服务器发生的写操作同步到从服务器的过程。 增量复制的过程主要是主服务器每执行一个写命令就会向从服务器发送相同的写命令,从服务器接收并执行收到的写命令。
  2. Redis主从同步策略:主从刚刚连接的时候,进行全量同步;全量同步结束后,进行增量同步。当然,如果有需要,slave 在任何时候都可以发起全量同步。redis 策略是,无论如何,首先会尝试进行增量同步,如不成功,要求从机进行全量同步。
  3. 注意点:如果多个Slave断线了,需要重启的时候,因为只要Slave启动,就会发送sync请求和主机全量同步,当多个同时出现的时候,可能会导致Master IO剧增宕机。

2. redis Sentinel

3. codis

七 redis应用场景

1. Redis实现分布式锁

所谓分布式锁就是在多个节点都可以访问的位置设置一个标志,
任务节点想访问被锁的资源时,首先尝试获取这个标志,
如果获取成功表示获取锁成功,如果获取失败表示获取锁失败,

使用redis实现分布锁,就是在准备一个redis节点,在redis设置一个key作为锁标志。
当key存在的时候就表示资源被锁,如果key不存在就说明资源处于空闲状态。

加锁的过程就是判断key是否存在,如果不存在就添加一个key.(注意:判断key是否存在和添加key的过程必须是原子操作)
可以使用redis的setnx方法,资源使用完成再将key删除释放锁。这里同样是原子操作。

问题一:如果持有锁的节点,在释放锁前宕机了,就会导致锁永远无法释放

解决:在添加key的时候设置一个过期时间,这样的话即使用持有锁的节点宕机了,Redis会自动释放锁。(还有问题二)

问题二:如果设置key的过期时间为20s, 如果一个请求一次操作时间超过20s, 那么就会导致持有锁的节点,还没有完成操作之前,锁就被redis给释放了。

解决:当某个节点获取到锁后,立刻启动一个子线程给自己续命。子线程的主要任务就是等key的过期时间到的时候,一般都是还剩1/3的时间的时候,就重新设置key的过期时间为20s, 当持有锁的节点完成操作之后,显式主动关闭子线程,然后释放锁。当持有锁的节点宕机之后,续命的子线程也会停止,锁也就自动释放了。

2. redis和mysql的双写一致性

方式一: 先更新缓存,再更新数据库

问题:如果更新缓存成功,更新数据库失败(缓存脏数据)

方式二: 先更新数据库, 再更新缓存

问题:高并发场景下
线程A更新了数据库中的数据。
这时由于网络或其它原因, 在线程A还没有来得及更新缓存的时候,线程B更新了数据库,同时也更新了缓存。
接着线程A才更新缓存,就导致线程B对缓存的更新丢失了,是不是有点像事件丢失的情况。

方式三:先删除缓存,再更新数据库

问题:这种方式,可以避免方式二中的缓存更新丢失的情况。
但是在高并发下,依然会有不一致的情况。
如:线程A先执行删除缓存,然后准备更新数据库。
这时线程B执行了读操作。发现缓存没有命中,所以从数据库读取,这时读取的是旧值。并肯线程B会将旧值写入缓存。
接着线程A完成了数据库的更新。【很明显数据库和缓存又出现了不一致的现象】
解决:在线程A完成数据库更新之后,稍作延迟,再删除一次缓存。【延迟时间>一次读作的时间】

方式四:先更新数据库,再删除缓存

问题:这种方式,存在数据不一致的场景
如: 线程A查询数据,正准备将数据写入缓存的时候。
线程B更新了数据库,然后执行了删除缓存的操作。
这时,线程A才把之前读取的旧值写入缓存。(这种现像出像的概率很底,因为写操作的时间大概率是比读操作的时间长,所以一般不会出现在一次读操作期间进行一次写操作)
解决:【延迟双删策略】(延迟双删的问题:如果删除缓存失败了怎么办)
尝试不断的循环删除,删除失败后,我们可以将要删除的key放入队列,然后重复尝试删除直到删除成功。

3. 热点数据存储

4. 排行榜

5. 分布式ID生成

6. 会话缓存(缓存一致性问题)

7.分布式队列/阻塞队列

8. redis限流的3种实现

Redis 常见性能问题和解决方案

  1. Master 最好不要写内存快照,如果 Master 写内存快照,save 命令调度 rdbSave函数,会阻塞主线程的工作,当快照比较大时对性能影响是非常大的,会间断性暂停服务
  2. 如果数据比较重要,某个 Slave 开启 AOF 备份数据,策略设置为每秒同步一
  3. 为了主从复制的速度和连接的稳定性,Master 和 Slave 最好在同一个局域网
  4. 尽量避免在压力很大的主库上增加从
  5. 主从复制不要用图状结构,用单向链表结构更为稳定,即:Master <Slave1<Slave2 <Slave3…这样的结构方便解决单点故障问题,实现 Slave 对 Master的替换。如果 Master 挂了,可以立刻启用 Slave1 做 Master,其他不变。

在选择缓存时,什么时候选择 redis,什么时候选择 memcached?

选择 redis 的情况

  1. 复杂数据结构,value 的数据是哈希,列表,集合,有序集合等这种情况下,会选择redis,
    因为 memcache 无法满足这些数据结构,最典型的的使用场景是,用户订单列表,用户消息,帖子评论等。
  2. 需要进行数据的持久化功能,但是注意,不要把 redis 当成数据库使用,如果 redis挂了,
    内存能够快速恢复热数据,不会将压力瞬间压在数据库上,没有 cache 预热的过程。
    对于只读和数据一致性要求不高的场景可以采用持久化存储
  3. 高可用,redis 支持集群,可以实现主动复制,读写分离,
    而对于 memcache 如果想要实现高可用,需要进行二次开发。
  4. 存储的内容比较大,memcache 存储的 value 最大为 1M。

选择 memcache 的场景

  1. memcache 的内存分配采用的是预分配内存池的管理方式,能够省去内存分配的时间,
    redis 是临时申请空间,可能导致碎片化。
  2. 虚拟内存使用,memcache 将所有的数据存储在物理内存里,redis 有自己的 vm 机制,
    理论上能够存储比物理内存更多的数据,当数据超量时,引发 swap,把冷数据刷新到磁盘上,
    从这点上,数据量大时,memcache 更快
  3. 网络模型,memcache 使用非阻塞的 IO 复用模型,
    redis 也是使用非阻塞的 IO 复用模型,
    但是 redis 还提供了一些非 KV 存储之外的排序,
    聚合功能,复杂的 CPU 计算,会阻塞整个 IO 调度,
    从这点上由于 redis 提供的功能较多,memcache 更快些
  4. 线程模型,memcache 使用多线程,主线程监听,
    worker 子线程接受请求,执行读写,这个过程可能存在锁冲突。
    redis 使用的单线程,虽然无锁冲突,但是难以利用多核的特性提升吞吐量。
上一篇 下一篇

猜你喜欢

热点阅读