Java技术–Redis

五大基础数据结构:

  • List;Set;ZSet;Hash;String
  • 后续添加了如BitMap;Stream等数据结构

跳表:

ZSet的底层数据结构就是跳表,简单来说就是:

在一个基础链表之上新增几条链表,将基础链表的数据以抛硬币的方式决定这个数据在第几层。

然后链表的遍历从最上面的链表开始,有点类似二分查找。

ZSet为何选择跳表而非B+树:

因为B+树的最大优点就是减少磁盘IO,而Redis是纯内存操作。

比任何树的代码都更加简单

更新操作时只需要修改指针,而不用树的自旋平衡。

Redis中的Hash表是怎样扩容的:

创建一个新的哈希表,因为Redis是单线程的,所以数据量很大的时候可能会引发阻塞。所以只有在新的更新操作执行前,Redis会偷摸的进行一次顺序的数据搬迁,直至完成数据搬迁。扩容过程中的所有操作都会在两张表上执行,比如查询操作:查询旧表,若无结果则去查询新表,而新增操作只在新表。

String的数据结构:

在Redis中String用SDS结构存储,而非普通的字符串。

SDS内部维护了:len(字符串长度)+alloc(空间长度)+flags(SDS类型)+buf(内容)

当需要对字符串读取、操作时可以单独操作某个结构,速度快。

Redis为什么快:

  • Redis是基于内存操作的,并且数据结构高效。它的性能瓶颈是内存和带宽,而非CPU,自然选择单线程就够。
  • Redis单线程模型省去了多线程的线程切换开销和竞争
  • 采用IO多路复用技术:(多路:多个客户端;复用:复用同一个线程)
    • 维护一个主事件监控器,当某个服务器请求IO到达的时候,内核会将它放进就绪队列,并通知事件处理进行处理,从而避免了无效阻塞

Redis的原子性

对于Redis自身执行命令来说,因为是单线程所以是没有并发问题的

但是在程序调用Redis的过程中是有并发问题的,而原子性可以通过Lua脚本来解决

虽然Redis自身有提供事务功能,但是其不具备回滚的能力,大部分场景都不适用。

日志:

Redis是基于内存进行操作的,所以当掉电或重启时数据会丢失。

所以可以通过三种方式进行刷盘(持久化到硬盘):

  • AOF日志:当Redis执行一条操作命令时,就以追加的方式写入到日志文件中
  • RDB快照:将某时刻的内存数据统一以二进制的方式写入到硬盘之中
  • 混合持久化:在AOF日志重写前(AOF日志体积过大),先以RDB的方式将内存数据写进日志文件,再执行AOF的追加写操作。重启时先重放RDB部分,再回放AOF的操作命令。

AOF日志:

有三种执行策略:

  • Always:一旦操作命令完成时,立即写入磁盘
  • EverySecond:每隔一秒写入一次
  • No:由操作系统自行决定,一般是cache写满时

优点:数据安全性强,不易丢失。追加写方式,性能好。有重写机制,体积适中

缺点:因为记录的都是操作,回放的时候需要重新写一遍,性能开销巨大

RDB快照:

通过快照的方式记录某一时刻的内存数据,备份恢复的速度很快。

快照操作由子进程进行快照记录,不阻塞主线程。因为是定时任务所以体积比AOF小。

缺点是两个快照之间的数据会丢失。

Redis的缓存淘汰和过期删除:

缓存淘汰:

  • 对有TTL的数据进行淘汰:
    • 随机淘汰;最久未使用;最不常用;最早过期;
  • 对所有数据范围进行淘汰:
    • 随机淘汰;最久未使用;最不常用

过期删除:

  • 惰性删除:
    • 当对这个key访问或修改时,先查询TTL是否过期,是则删除,返回null
  • 定期删除:
    • 定期从数据库随机抽查一部分key,并删除TTL过期的Key,如果删除的Key大于1/4,则继续抽查

而Redis默认是采用两者都用的方式。

Redis集群

主从复制过程:

  • 全量同步:
    • 1.从库向主库发起请求
    • 2.主库接收后进行RDB快照,并将快照传输给从库
    • 3.同时在传输过程中会记录AOF。后将AOF传给从库
    • 4.从库接收后清空当前数据后载入快照数据,并根据AOF回放数据,以保证主从的数据一致性
  • 增量同步:允许断点续传
    • 主库的写操作命令传给从库时,不仅会将写命令传输给从库,还会同步传输给缓冲池
    • 当从库断网重连后,会从缓冲池中读取命令数据。
    • 主库从库通过缓存池中各自的偏移量记录传输进程,以实现断点续传。

全量同步的开销比较大,所以推荐扩大缓冲池内存以采用增量同步的方式

tips:主从库一般为读写分离,主库负责写,从库负责读。因为集群有不可避免的数据一致性问题,所以写操作必须由主库负责。

哨兵机制:

设立专门的哨兵节点,他会监控主节点是否故障,若故障则立即选择从节点选举为主节点,并且通知其他所有节点。

哨兵机制的主节点选举算法:

当一个哨兵发现主节点挂了(主观下线),会询问其他哨兵,如果超过一定数量的哨兵都认为主节点挂了,此时判定为客观下线。

之后通过投票来选举领头哨兵(Leader)【总票数要一半以上,谁先发请求就投给谁】。领头哨兵会通过一些条件从从节点中筛选出新的主节点。

tips:哨兵集群至少需要3个,因为成为Leader至少需要一半以上(3/2=1.5→2票),这样如果一个哨兵挂了至少也能通过投票

大Key问题及其解决办法:

  • 问题:
    • 占内存大,可能引发Redis使用缓存淘汰策略而导致有用的key被淘汰,甚至内存爆满
    • 内存碎片大,拖慢Redis性能
    • 对大Key的读写费劲,阻塞线程
    • 主从复制的开销变大
  • 解决办法:
    • 对大Key进行取模等操作,将一个大Key分散到多个key中
    • 定时清理维护Key

热Key问题及其解决办法:导致单个Redis节点过热甚至导致崩溃

  • 解决办法:
    • 将热Key通过主从复制的方式拷贝到从节点中,从而分散热度
    • 采用读写分离架构,主节点只做写操作,从节点承担读操作

Redis和MySQL数据一致性问题:

缓存是通过牺牲强一致性来提高性能,不适用于强一致性的场景

  • 读操作:如果未命中缓存,则先读取数据库,再写入缓存
  • 写操作:先更新数据库,再删除缓存
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇