Redis

redis-cluster

1. 概念
  • 为何要搭建Redis集群。Redis是在内存中保存数据的,而我们的电脑一般内存都不大,这也就意味着Redis不适合存储大数据,适合存储大数据的是Hadoop生态系统的Hbase或者是MogoDB。

  • Redis更适合处理高并发,一台设备的存储能力是很有限的,但是多台设备协同合作,就可以让内存增大很多倍,这就需要用到集群

  • redis 3.0之后版本支持redis-cluster集群,它是Redis官方提出的解决方案,Redis-Cluster采用无中心结构,每个节点保存数据和整个集群状态,每个节点都和其他所有节点连接。

  • 客户端与 redis 节点直连,不需要中间 proxy 层.客户端不需要连接集群所有节点,连接集群中任何一个可用节点即可。

    所有的 redis 节点彼此互联(PING-PONG机制),内部使用二进制协议优化传输速度和带宽。

2. 分布式存储机制-槽
  • redis-cluster 把所有的物理节点映射到[0-16383]slot 上,cluster 负责维护

  • Redis 集群中内置了 16384 个哈希槽,当需要在 Redis 集群中放置一个 key-value 时,redis 先对 key 使用 crc16 算法算出一个结果,然后把结果对 16384 求余数,这样每个key 都会对应一个编号在 0-16383 之间的哈希槽,redis 会根据节点数量大致均等的将哈希槽映射到不同的节点

  • 例如三个节点:槽分布的值如下:

    • SERVER1: 0-5460

    • SERVER2: 5461-10922

    • SERVER3: 10923-16383

3. 容错机制-投票

选举过程是集群中所有master参与,如果半数以上master节点与故障节点通信超过(cluster-node-timeout),认为该节点故障,自动触发故障转移操作. 故障节点对应的从节点自动升级为主节点。

  • 什么时候整个集群不可用?

    如果集群任意master挂掉,且当前master没有slave.集群进入fail状态,也可以理解成集群的slot映射[0-16383]不完成时进入fail状态。

redis的事务

1.概念

可以一次执行多个命令,本质是一组命令的集合(队列)。一个事务中的所有命令都会序列化,按顺序地串行化执行而不会被其它命令插入,不许加塞。

2.特点

redis的事务是弱原子性,弱事务的;关系型数据库是强原子性的。

3.弱原子性的表现
  1. 正常执行

    127.0.0.1:6379[15]> multi
    OK
    127.0.0.1:6379[15]> set k1 v1
    QUEUED
    127.0.0.1:6379[15]> set k2 v2
    QUEUED
    127.0.0.1:6379[15]> get k1
    QUEUED
    127.0.0.1:6379[15]> exec
    1) OK
    2) OK
    3) "v1"
    
  2. 放弃事务

    127.0.0.1:6379[15]> multi
    OK
    127.0.0.1:6379[15]> set k1 v1
    QUEUED
    127.0.0.1:6379[15]> set k2 v2
    QUEUED
    127.0.0.1:6379[15]> discard
    OK
    127.0.0.1:6379[15]> get k1
    (nil)
    
  3. 全体连坐

    语法错误,会导致全体连坐,都失败

    127.0.0.1:6379[15]> multi
    OK
    127.0.0.1:6379[15]> set k1 v1
    QUEUED
    127.0.0.1:6379[15]> set k2 v2
    QUEUED
    127.0.0.1:6379[15]> set k3
    (error) ERR wrong number of arguments for 'set' command
    127.0.0.1:6379[15]> exec
    (error) EXECABORT Transaction discarded because of previous errors.
    127.0.0.1:6379[15]> get k1
    (nil)
    
  4. 冤有头债有主

    逻辑错误,哪个错误找哪个

    127.0.0.1:6379[15]> multi
    OK
    127.0.0.1:6379[15]> set k1 v1
    QUEUED
    127.0.0.1:6379[15]> set k2 2
    QUEUED
    127.0.0.1:6379[15]> incr k2
    QUEUED
    127.0.0.1:6379[15]> incr k1
    QUEUED
    127.0.0.1:6379[15]> exec
    1) OK
    2) OK
    3) (integer) 3
    4) (error) ERR value is not an integer or out of range
    
4.乐观锁机制

watch

监视一个或多个key,如果执行事物之前被其他key修改,那么事物会被提交成功吗? 不能。

如果没有监视这个key,那么在事物中这个key被其他操作修改后,能成功吗? 能unwatch 取消watch命令对所有key的监视

代码:

两个线程

set balance 1000
watch balance
multi
set balance 1
exec
watch balance
multi
set balance 2
exec (结果为nil)

先执行exec的修改成功,因为进入事务后尚未提交,watch认为没有改变,就可以提交;线程2提交的时候发现已经和预期不一样了。

redis的持久化策略

AOF+RDB

持久化策略-RDB

1. 什么是RDB?

RDB 是 Redis 默认的持久化方案。在指定的时间间隔内,执行指定次数的写操作,则会将内存中的数据写入到磁盘中。即在指定目录下生成一个dump.rdb文件。Redis 重启会通过加载dump.rdb文件恢复数据。

2.RDB之被动持久化
save 900 1:表示900 秒内如果至少有 1 个 key 的值变化,则保存
save 300 10:表示300 秒内如果至少有 10 个 key 的值变化,则保存
save 60 10000:表示60 秒内如果至少有 10000 个 key 的值变化,则保存

总结:redis 的rdb 策略在开启时,当有满足其任意一个条件时,都会触发被动持久化,生成dump.rdb 文件

3.RDB之主动持久化

当我们使用flushall,flushDB,save ,和bgsave时都会触发主动持久化

3.1save持久化

save 持久化将造成redis 数据阻塞,是一个同步持久化方案,即当我们在执行save操作时,在save未执行完毕时,无法执行其他操作。

save操作会造成阻塞

3.2bgsave 持久化

bgsave是异步的,不会造成阻塞(在fork子进程阶段会产生阻塞),在持久化结束后,会生成dump.rdb文件。

bgsave持久化原理:

底层会fork 出一条子进程,这条子进程来进行持久化操作,而主进程进行相应其他操作,在子进程进行持久过程中,会生成temp.rdb,当子进程持久化结束后,会用temp.rdb 去替换 dump.rdb
在这里插入图片描述

总结:RDB:被动持久化方案,采用的是bgsave方案,适合大规模数据恢复,但可能会损失一个时间段的数据(因为此时并未触发持久化就宕机了)

持久化策略-AOP

1. AOP是什么?

aof 的出现是为了弥补rdb的不足,因为rdb会损失一部分数据,aof (默认关闭)以日志的方式来记录用户的每一次写操作在磁盘上,在需要恢复数据时,从磁盘的aof 文件中,重新执行这些指令,从而恢复数据。

2.rdb和aof优先级

aop 优先级较高,如果有aof 文件先加载aof 文件,如果没有aof文件才会去加载dump.rdb文件。

3.Redis 的同步策略
命令描述
appendfsync always表示每次写入都执行fsync,以保证数据同步到磁盘,效率很低;
appendfsync everysec表示每秒执行一次fsync,可能会导致丢失这1s数据,默认选项
appendfsync no由操作系统保证数据同步到磁盘,速度最快,但是不太安全;

Redis 同步数据流程:

在这里插入图片描述

Redis 会将这些写的内容,写如到缓冲区aof_buf中,然后由同步策略来决定到底是如何进行持久化,默认情况下是1s

4.AOF的重写机制
4.1 重写以及原理介绍
  • aof 是将client 的写操作要记录在appendonly.aof的文件中,那么势必导致appendonly.aof文件越来越大,为了给aof文件进行压缩,redis 采用重写的方式来实现对aof文件进行压缩
  • 关于aof重写机制条件的配置
命令描述
auto-aof-rewrite-percentage :100当aof文件大小为原来的百分之一百
auto-aof-rewrite-min-size 64mb:64mb当aof文件大小大于64mb

当同上满足以上两个条件,redis 将对aof 文件进行重写,同时也可以使用bgrewriteaof 让其自动重写 。

  • 重写原理:

在这里插入图片描述

  • 当开始重写时,对aof进程执行bgrwriteaof 的指令
  • 父进程收到这个指令后,会进行fork 子进程(此时主进程阻塞),由子进程按照第四步来完成数据的重写生成新的aof文件
  • 当子进程fork 结束后,通过5-1 产生信号通知主进程已经fork完毕,可以继续接受请求,同时将写命令依然写入AOF缓冲区 3-1 (aof_buf),并根据appendfsync策略同步到硬盘即旧的aof文件中,保证原有AOF机制的正确,由于子进程只能共享fork操作时的内存数据。父进程依然在响应命令,因此Redis使用AOF重写缓冲区(aof_rewrite_buf)保存这部分新日志,防止新AOF文件生成期间丢失这部分数据,在执行aof完毕后,将 aof_rewrite_buf中的这些数据 追加到 新的aof文件中,也就是说,在执行重写的过程中,写指令是同时追加到aof_buf和 aof_rewrite_buf中的。
  • 最后 5-3 利用新的aof 文件去替换旧的aof 文件

Redis 过期策略和淘汰机制

一、过期策略
1. 为什么要有过期策略
  • 内存是很宝贵的,我们不能让数据永久存储在内存中, 所以对于某些数据我们在操作时,需要对其指令过期时间,当过期时间到达后,redis 会采用过期策略来处理这些过期的key
2.Key过期的三种策略
2.1 定时删除(了解)

在设置key的过期时间的同时,为该key创建一个定时器,当过期的时间到了,那么redis 就会将这个key删除,这种方式虽然可以精确的删除过期的时间key,但会对cpu造成极大的负担,所以redis 并不采用这种方式来删除过期时间key

2.2 定期删除

每隔一段时间执行一次删除过期key操作,采用这种方式对cpu 负担不大,但可能会产生一些漏网之鱼,从而导致内存中还存在部分过期的key

原理如下:
在这里插入图片描述

  • Redis 会依次扫描 内部的16 个库
  • 每次循环随机选择每个db中的20个key,判断其是否过期
  • 如果没有25% 的key 过期,那么表明该库处于健康状态,则开始遍历下一个db
  • 如果超过25%的key过期,那么会判断当前循环是否已经超过了规定的扫描时间,如果未超过,则继续遍历该db,再抽取25 %的key判断是否过期,如果超过时间,则同样开始下一个db的循环

2.3 惰性删除

正是因为定期删除可能会导致部分过期的key无法删除,所以redis 除了采用定期删除以外,还采用了惰性删除,惰性删除,是在我们去获取key时,首先判断这个key是否过期,如果过期,那么Redis 才会将这个key删除,同时返回一个null给client。

而Redis 采用的过期策略:就是惰性删除+ 定期删除

二、淘汰机制

淘汰机制: 当redis 的内存达到最大值后,redis 对内存的处理方案

2.1 配置文件&讲解
# MAXMEMORY POLICY: how Redis will select what to remove when maxmemory
# is reached. You can select among five behaviors:
#
# volatile-lru -> remove the key with an expire set using an LRU algorithm
# allkeys-lru -> remove any key according to the LRU algorithm
# volatile-random -> remove a random key with an expire set
# allkeys-random -> remove a random key, any key
# volatile-ttl -> remove the key with the nearest expire time (minor TTL)
# noeviction -> don't expire at all, just return an error on write operations 
    
# The default is:
#
# maxmemory-policy noeviction

由配置文件可知:当Redis 达到最大内存后,你可以采用上述五个方案让Redis淘汰掉内存中的数据

命令描述
volatile -lru最近最少使用 针对的是设置了过期的key
allkeys-lru最近最少使用 针对所有的key
volatile-random随机移除 针对的是设置了过期的key
allkeys-random随机移除 针对所有的key
volatile-ttl移除规定时间内,更早过期的key 针对的是设置了过期的key
noeviction完全不管,仅仅只是在写操作时返回一个错误即可

redis 的主从和哨兵

1. 读写分离

读写分离基本原理:让主数据库处理事务性增、改、删操作(INSERT、UPDATE、DELETE)操作,而从数据库处理SELECT查询操作。

读写分离的好处:

  1. 将读操作和写操作分离到不同的数据库上,避免主服务器出现性能瓶颈
  2. 主服务器进行写操作时,不影响查询应用服务器的查询性能,降低阻塞,提高并发
  3. 数据拥有多个容灾副本,提高数据安全性,同时当主服务器故障时,可立即切换到其他服务器,提高系统可用性
2. redis主从

配从不配主

命令:

查看当前主机状态

127.0.0.1:6379[15]> info replication
# Replication
role:master
connected_slaves:0
master_repl_offset:0
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0

如何变成主机变成别的从机: slaveof 主库 ip 主库端口

SLAVEOF 127.0.0.1 6379

实现的效果:

  1. 主机可写可读
  2. 从机只能读
  3. 更新方面的问题
    • 如果是从机第一次连接上主机: 全量更新
    • 如果是一直连接着主机,当主机数据增多,从机增量更新 runid
3. 投票

哨兵:

  1. 创建sentinel.conf文件

    sentinel monitor host6379(被监控数据库名字(自己起名字)) 127.0.0.1 6379 1
    
  2. 投票

    ./redis-sentinel sentinel.conf
    

效果:主机挂了之后,从机自我投票变成master

redis的缓存穿透

1. 定义

缓存穿透是指缓存和数据库中都没有的数据,而用户不断发起请求,如发起为id为“-1”的数据。这时的用户很可能是攻击者,攻击会导致数据库压力过大。

2. 如何解决

  1. 制ip(运维角度)
  2. 将所有商品的商品id 放到集合中,当用户过来查询时,先判断要查询的商品是否存在集合中,如果集合中有对应数据,才进入下一步。

3. 缺陷

集合太大,假设10亿商品,每个商品id都是15位整型的id,需要大概500g的缓存,明显不可能, 如何解决?采用布隆过滤器。

4. 布隆过滤器

bloom算法类似一个hash set,用来判断某个元素(key)是否在某个集合中。对于每个key,只需要k个比特位,每个存储一个标志,用来判断key是否在集合中。

算法:

  1. 首先需要k个hash函数,每个函数可以把key散列成为1个整数
  2. 初始化时,需要一个长度为n比特的数组,每个比特位初始化为0
  3. 某个key加入集合时,用k个hash函数计算出k个散列值,并把数组中对应的比特位置为1
  4. 判断某个key是否在集合时,用k个hash函数计算出k个散列值,并查询数组中对应的比特位,如果所有的比特位都是1,认为在集合中。

优点:不需要存储key,节省空间

缺点:

  1. 算法判断key在集合中时,有一定的误判概率(哈希冲突)
  2. 无法删除

典型的应用场景:

电商数据库查询、垃圾邮件过滤、爬虫去重

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值