Redis
缓存Cache
缓存的概念
缓存是存储在计算机上的一个原始数据复制集,以便于访问。
缓存击穿
高并发的情况下,某个热门key突然过期,导致大 量请求在Redis未找到缓存数据,进而全部去访问DB请求数据,引起DB压力瞬间增大。
解决方案:
1.如果要求数据必须是新数据,则最好的方案则为热点数据设置为永不过期,然后加一个互 斥锁保证缓存的单线程写
缓存穿透
缓存穿透是指查询缓存和DB中都不存在的数据.比如用户需要查询一个数据,但是redis中没有 ,直接去请求数据库,如果很多用户同时去请求数据库,就会给数据库带来很大压力
解决方案:
1.利用互斥锁,缓存失效的时候,先去获得锁,得到锁了,再去请求数据库。没得到锁,则休眠一段时间重试
2.采用异步更新策略,无论key是否取到值,都直接返回
3.提供一个能迅速判断请求是否有效的拦截机制.比如,利用布隆过滤器
缓存雪崩
缓存中如果大量缓存在一段时间内集中过期了,这时候会发生大量的缓存击穿现象,所有的请求都落在了DB上,由于查询数据量巨大,引起DB压力过大甚至导致DB宕机
解决方案:
1.给缓存的失效时间,加上一个随机值,避免集体失效
2.使用互斥锁,但是该方案吞吐量明显下降了
3.设置热点数据永远不过期。
4.双缓存。
缓存一致性
当数据时效性要求很高时,需要保证缓存中的数据与数据库中的保持一致,需要保证缓存节点和副本中的数据也保持一致,不能出现差异现象。(集群同步)
解决方案:
一般会在数据发生更改的时,主动更新缓存中的数据或者移除对应的缓存。
布隆过滤器
判断一个元素是否存在一个集合中
布隆过滤器原理
布隆过滤器(Bloom Filter)的核心实现是一个超大的位数组和几个哈希函数。假设位数组的长度为m,哈希函数的个数为k
Redis简介
Redis是一个开源的,内存中的数据结构存储系统(基于内存存储),可以用作数据库,缓存和消息中间件.Redis 可以存储键和五种不同类型的值之间的映射。键的类型只能为字符串,值支持五种数据类型:字符串、列表、集合、散列表、有序集合。
优点
1.读写性能优异, Redis能读的速度是110000次/s,写的速度是81000次/s。
2.支持数据持久化,支持AOF和RDB两种持久化方式。
3.支持事务,Redis的所有操作都是原子性的,同时Redis还支持对几个操作合并后的原子性执行。
4.数据结构丰富,除了支持string类型的value外还支持hash、set、zset、list等数据结构。
5.支持主从复制,主机会自动将数据同步到从机,可以进行读写分离。
Redis的命令
Redis-cli连接Redis
-h :用于指定ip
-p :用于指定端口
-a :用于指定认证密码
Redis-cli操作Redis
操作Key
操作Key
exists 查询key是否存在
keys 查询是否存在指定的key
type 查询key的数据类型
scan 扫描当前库中所有的key
操作String
实用场景对于计算日活,月活(通过位运算)Json 普通文本
set :添加一条String类型数据
get :获取一条String类型数据
mset :添加多条String类型数据
mget :获取多条String类型数据
incr :增加1
decr:减少1
操作hash
场景 表记录存储
hset :添加一条hash类型数据
hget :获取一条hash类型数据
hmset :添加多条hash类型数据
hmget :获取多条hash类型数据
hgetAll :获取指定所有hash类型数据
hdel :删除指定hash类型数据(一条或多条)
操作list
场景 消息队列
lpush :左添加(头)list类型数据
rpush :右添加(尾)类型数据
lrange : 获取list类型数据start起始下标 end结束下标 包含关系
llen :获取条数
lrem :删除列表中几个指定list类型数据
lrem key count value
count > 0 从前向后删除count个value
count <0 从后向前删除 绝对值(count) 个value
count = 0 删除所有的value
操作set
场景 社交软件
交集
并集
差集
加关注
取消关注
sadd :添加set类型数据
smembers :获取set类型数据
scard :获取条数
srem :删除数据
sdiff key [key...] 差集
sunion key [key...] 并集
sinter key [key...] 交集
操作sorted set
场景 排行榜(音乐排行榜)
sorted set是通过分数值来进行排序的,分数值越大,越靠后。
zadd :添加sorted set类型数据
zrange :获取sorted set类型数据
zcard :获取条数
zrem :删除数据
zadd需要将Float或者Double类型分数值参数,放置在值参数之前
zscore
通用命令
操作失效时间:
expire 秒
pexpire key ttl 毫秒
pexpireat 指定毫秒数时间戳
expireat timestamp指定的秒数时间戳删除:
del :用于删除数据(通用,适用于所有数据类型)
hdel :用于删除hash类型数据
Redis的事务机制
Redis事务是一个单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。Redis的事务总是具有ACID中的一致性和隔离性,其他特性是不支持的。
Redis事务的主要作用就是串联多个命令防止别的命令插队
- Redis 不支持回滚,“Redis 在事务失败时不进行回滚,而是继续执行余下的命令”, 所以 Redis 的内部可以保持简单且快速。
组队阶段:
如果在一个事务中的命令出现错误,那么所有的命令都不会执行;执行阶段:
如果在一个事务中出现运行错误,那么正确的命令会被执行。
-
事务的错误处理
组队阶段某个命令出现了报告错误,执行时整个的所有队列会都会被取消。
执行阶段某个命令报出了错误,则只有报错的命令不会被执行,而其他的命令都会执行,不会回滚。 -
事务锁的机制
**悲观锁:**悲观锁在操作数据时比较悲观,认为别人会同时修改数据。因此操作数据时直接把数据锁住,直到操作完成后才会释放锁;上锁期间其他人不能修改数据。
**乐观锁:**在操作数据时非常乐观,认为别人不会同时修改数据。因此乐观锁不会上锁,只是在执行更新的时候判断一下在此期间别人是否修改了数据:如果别人修改了数据则放弃操作,否则执行操作。
Redis就是利用这种check-and-set机制实现事务的(
watch
已监视的key,只允许在当前终端的multi
和exec
间被修改,其他情况的修改都将导致watch和此事务的失败。CAS的实现主要通过watch
命令完成,也就是说在watch
一个key后,其他终端修改此key的值时,都将触发当前事务的失败。当前终端的watch
和multi
之间对key的修改,也会触发事务的失败)
WATCH key [key…] :
在执行multi之前,先执行watch key1 【key2】,可以监视一个或者多个key,如果在事务执行之前这个(或这些)key被其他命令所改动,那么事务将被打断,(但是,相同的客户端可能会在事务内部修改这些键,此时这个事务不会中止运行。)否则,Redis根本就不会进入事务。类似于乐观锁得机制,我不上锁,但是你修改不了,只能我自己改,我自己改,毫无影响,你要硬来改,我就报错。
UNWATCH
取消WTACH命令对所有key的监视,如果在执行WATCH命令之后,EXEC命令或者DISCARD命令先被执行了的话,那么就不需要再执行UNWATCH命令了
数据的持久化
redis是一个内存数据库,数据保存在内存中,虽然内存的数据读取速度快,但是很容易发生丢失。
Redis还为我们提供了持久化的机制,分别是RDB(Redis DataBase)和AOF(Append Only File),默认使用的是RDB模式
RDB
能够在指定的时间间隔内对你的数据进行快照存储
优点:
1、适合大规模的数据恢复!
2、对数据的完整性要求不高!
缺点:
1、需要一定的时间间隔进程操作!如果redis意外宕机了,这个最后一次修改数据就没有的了!
2、fork进程的时候,会占用一定的内容空间!
AOF
记录每次对服务器写的操作,当服务器重启的时候会重新执行这些命令来恢复原始的数据
优点:
1、每一次修改都同步,文件的完整性会更加好!
2、每秒同步一次,最多会丢失一秒的数据!
3、从不同步,效率最高的dd
缺点:
1、相对于数据文件来说,aof远远大于 rdb (aof文件比rdb文件大) ,修复的速度也比 rdb慢!
2、Aof 运行效率也要比 rdb 慢,所以我们redis默认的配置就是rdb持久化!
RDB和AOF的选择
- 成年人不做选择题
- 如果同时使用AOF和RDB,那么启动时以AOF为恢复数据的模板
- 选择的话,两者加一起才更好。
- 因为两个持久化机制你明白了,剩下的就是看自己的需求了,需求不同选择的也不一定,但是通常都是结合使用
主从复制
是指将一台Redis服务器的数据,复制到其他的Redis服务器。前者称为主节点(master/leader),后者称为从节点(slave/follower)
主要作用
①数据冗余:主从复制实现了数据的热备份,是持久化之外的一种数据冗余方式。
②故障恢复:当主节点出现问题时,可以由从节点提供服务,实现快速的故障恢复;实际上是一种服务的冗余。
③负载均衡:在主从复制的基础上,配合读写分离,可以由主节点提供写服务,由从节点提供读服务,分担服务器负载;尤其是在写少读多的场景下,通过多个从节点分担读负载,可以大大提高Redis服务器的并发量。
④高可用(集群)基石:主从复制还是哨兵和集群能够实施的基础,因此说主从复制是Redis高可用的基础。
Redis的哨兵
Redis的主从复制模式下,一旦主节点由于故障不能提供服务,需要手动将从节点晋升为主节点,同时还
要通知客户端更新主节点地址
Sentinel哨兵是redis官方提供的高可用方案,可以用它来监控多个Redis服务实例的运行情况
数据同步机制
-
Redis的主从结构可以采用一主多从或者级联结构,Redis主从复制可以根据是否是全量分为全量同步和
增量同步 -
主从刚刚连接的时候,进行全量同步;全同步结束后,进行增量同步。
-
全量同步
Redis全量复制一般发生在Slave初始化阶段,这时Slave需要将Master上的所有数据都复制一份
从服务器连接主服务器,发送SYNC命令;
主服务器接收到SYNC命名后,开始执行BGSAVE命令生成RDB文件并使用缓冲区记录此后执行的所有写命令;
主服务器BGSAVE执行完后,向所有从服务器发送快照文件,并在发送期间继续记录被执行的写命令;
从服务器收到快照文件后丢弃所有旧数据,载入收到的快照;
主服务器快照发送完毕后开始向从服务器发送缓冲区中的写命令;
从服务器完成对快照的载入,开始接收命令请求,并执行来自主服务器缓冲区的写命令; -
增量同步
Redis增量复制是指Slave初始化后开始正常工作时主服务器发生的写操作同步到从服务器的过程。
增量复制的过程主要是主服务器每执行一个写命令就会向从服务器发送相同的写命令,从服务
器接收并执行收到的写命令。 -
主从复制的异步特性
主从复制对于主redis服务器来说是非阻塞的:这意味着当从服务器在进行主从复制同步过程中,主redis仍然可以处理外界的访问请求;
主从复制对于从redis服务器来说也是非阻塞的:这意味着,即使从redis在进行主从复制过程中也可以接受外界的查询请求,只不过这时候从redis返回的是以前老的数据
哨兵功能与作用
监控(monitoring):
- Sentinel 会不断地检查你的主服务器和从服务器是否运作正常。
提醒(Notifation):
- 当被监控的某个 Redis 服务器出现问题时, Sentinel 可以通过 API 向管理员或者其他应用程序发送通知。
自动故障转移(Automatic failover):
- 当一个主服务器不能正常工作时, Sentinel 会开始一次自动故障迁移操作, 它会将失效主服
务器的其中一个从服务器升级为新的主服务器, 并让失效主服务器的其他从服务器改为复制
新的主服务器; 当客户端试图连接失效的主服务器时, 集群也会向客户端返回新主服务器的
地址, 使得集群可以使用新主服务器代替失效服务器。
哨兵工作原理
- 在redis sentinel中,一共有3个定时任务,通过这些任务,来发现新增节点和节点的状态。
- 每10秒每个sentinel节点对master节点和slave节点执行info操作
- 每2秒每个sentinel节点通过master节点的channel(sentinel:hello)交换信息
- 每1秒每个sentintel节点对master节点和slave节点以及其余的sentinel节点执行ping操作
- 主观下线(SDOWN):当前sentintel节点认为某个redis节点不可用。
一个哨兵发现主节点下线
- 如果一个实例(instance)距离最后一次有效回复PING命令的时间超过down-aftermilliseconds所指定值,那么这个实例会被Sentinel标记为主观下线。
- 如果一个主服务器被标记为主观下线,那么正在监视这个主服务器的所有Sentinel节点,要以
每秒一次的频率确认主服务器的确进入了主观下线状态。
- 客观下线(ODOWN)一定数量sentinel节点认为某个redis节点不可用。
多个哨兵发现主节点下线
- 如果一个主服务器被标记为主观下线,并且有足够数量的Sentinel(至少要达到配置文件指定的数量)在指定的时间范围内同意这一判断,那么这个主服务器被标记为客观下线。
- 在一般情况下,每个Sentinel会以每10秒一次的频率,向它已知的所有主服务器和从服务器发送INFO命令。当一个主服务器被Sentinel标记为客观下线时,Sentinel向下线主服务器的所有从服务器发送INFO命令的频率,会从10秒一次改为每秒一次。
- Sentinel和其他Sentinel协商主节点的状态,如果主节点处于SDOWN状态,则投票自动选出新的主节点。将剩余的从节点指向新的主节点进行数据复制。
- 当没有足够数量的Sentinel同意主服务器下线时,主服务器的客观下线状态就会被移除。
- 当主服务器重新向Sentinel的PING命令返回有效回复时,主服务器的主观下线状态就会被移除。
故障转移流程
- 哨兵内部领导者选举
1). 每个做主观下线的sentinel节点向其他sentinel节点发送上面那条命令,要求将设置为领导者。
2). 收到命令的sentinel节点如果还没有同意过其他的sentinel发送的命令(还未投过票),那
么就会同意,否则拒绝。
3). 如果该sentinel节点发现自己的票数已经过半且达到了quorum的值,就会成为领导者。
4). 如果这个过程出现多个sentinel成为领导者,则会等待一段时间重新选举。 - Master选举
选择slave-priority最高的slave节点
选择复制偏移量最大的节点
选runId最小的(启动最早) - 状态更换
选举出新的master节点,其余的节点变更为新的master节点的slave节点
原有的master节点重新上线,成为新的master节点的slave节点 - 通知客户端
当所有节点配置结束后,sentinel会通知客户端节点变更信息。
客户端连接新的master节点
Redis的高可用
在Redis中,实现高可用的技术主要包括持久化、复制、哨兵和集群
- 持久化:是最简单的持久化方法,主要作用数据备份,将数据存储到硬盘,保证数据不会丢失
- 复制:复制是高可用Redis的基础,哨兵和集群都是在复制基础上实现高可用的。
- 哨兵:在复制的基础上,哨兵实现了自动化的故障恢复。缺陷是写操作无法负载均衡,存储能力受到单机的限制。
- 集群:通过集群,Redis解决了写操作无法负载均衡以及存储能力受到单机限制的问题,实现了较为完善的高可用方案
一致性Hash
算法原理
- 取模
- 一致性的Hash算法是对
2的32方取模
- 整个空间按顺时针方向组织,圆环的正上方的点代表0,0点右侧的第一个点代表1,以此类推,2、3、4、5、6……直到2^32-1
- 这个由2^32个点组成的圆环称为Hash环
- 一致性的Hash算法是对
- 服务器
- 将各个服务器使用Hash进行一个哈希,这样每台机器就能确定其在哈希环上的位置
- 数据
- 数据key使用相同的函数Hash计算出哈希值,并确定此数据在环上的位置
- 定位
- 沿环顺时针“行走”,第一台遇到的服务器就是数据应该定位到的服务器
算法容错性
- 当我们添加服务器或者删除服务器它只影响处理节点的下一个节点
数据倾斜与虚拟节点
- 均匀一致性hash的目标是如果服务器有N台,客户端的hash值有M个
- 那么每个服务器应该处理大概M/N个用户的。也就是每台服务器负载尽量均衡
虚拟节点:
为了解决雪崩现象和数据倾斜现象,提出了虚拟节点这个概念。就是将真实节点计算多个哈希形成多个虚拟节点并放置到哈希环上,定位算法不变,只是多了一步虚拟节点到真实节点映射的过程
.Redis的Slot槽
Redis 集群中内置了 16384 个哈希槽,当需要在 Redis 集群中放置一个 key-value时,redis 先对 key(有效值)使用 crc16 算法算出一个结果,然后把结果对 16384 求余数,这样每个 key 都会对应一个编号在 0-16383 之间的哈希槽,redis 会根据节点数量大致均等的将哈希槽映射到不同的节点
- Redis集群使用
数据分片
(sharding)而非一致性哈希(consistencyhashing)来实现: - 一个Redis集群包含
16384个哈希槽
(hashslot),数据库中的每个键都属于这16384个哈希槽的其中一个,集群使用公式CRC16(key)%16384来计算键key于哪个槽,其中CRC16(key)语句用于计算键key的CRC16校验和 - 将一个哈希槽从一个节点移动到另一个节点不会造成节点阻塞,所以无论是添加新节点还是移除已存在节点,又或者改变某个节点包含的哈希槽数量,都不会造成集群下线。
- 对象保存到Redis之前先经过CRC16哈希到一个指定的Node上每个Node被平均分配了一个Slot段,对应着0-16383,Slot不能重复也不能缺失,否则会导致对象重复存储或无法存储。
- Node之间也互相监听,一旦有Node退出或者加入,会按照Slot为单位做数据的迁移
- Node1如果掉线了,0-5640这些Slot将会平均分摊到Node2和Node3上
- 优缺点
- 优点:
- 将Redis的写操作分摊到了多个节点上,提高写的并发能力,扩容简单。
- 缺点:
键都属于这16384个哈希槽的其中一个,集群使用公式CRC16(key)%16384来计算键key于哪个槽,其中CRC16(key)语句用于计算键key的CRC16校验和
- 优点:
- 将一个哈希槽从一个节点移动到另一个节点不会造成节点阻塞,所以无论是添加新节点还是移除已存在节点,又或者改变某个节点包含的哈希槽数量,都不会造成集群下线。
- 对象保存到Redis之前先经过CRC16哈希到一个指定的Node上每个Node被平均分配了一个Slot段,对应着0-16383,Slot不能重复也不能缺失,否则会导致对象重复存储或无法存储。
- Node之间也互相监听,一旦有Node退出或者加入,会按照Slot为单位做数据的迁移
- Node1如果掉线了,0-5640这些Slot将会平均分摊到Node2和Node3上
- 优缺点
- 优点:
- 将Redis的写操作分摊到了多个节点上,提高写的并发能力,扩容简单。
- 缺点:
- 每个Node承担着互相监听、高并发数据写入、高并发数据读出,工作任务繁重
- 优点: