【一文看懂 Redis 核心】 基础数据结构 架构设计 存储 集群

news2024/12/28 20:34:42

基础数据结构 & 架构设计 & 存储 & 集群

redis 简单来说其实就是一个基于内存的 key - value 数据库,它本身结构的前提就是 key - value 类似于 Java 中的 HashMap ,所以我们在聊 redis 的时候始终要记得这个前提,同时 redis 在执行读写操作命令时是串行执行的,这个特性使得 redis 可以用于实现分布式锁,同时因为是内存操作这个速度是极快的,并且以单线程执行也避免了线程切换所带来的消耗。

Redis 常用数据结构

String、Map、Set、List、ZSet (带权重的 Set 有点类似 Java 的 TreeSet)

redis 由 C 语言实现在底层 String 是自定义的数据结构 sds

struct sdshdr{
	int len;
	int free;
	char buf[];
}

对于 redis 来说,存储空间的节省十分重要,所以,在优化设计上下了很多功夫,在 3.2 版本之后 sds 区分了多个长度的版本

struct sdshdr5{
 	unsigned char flags; /* 前 3 位标识类型, 后 5 位标识长度 */
    char buf[];
}
struct __attribute__ ((__packed__)) sdshdr8 {
    uint8_t len; /* used */
    uint8_t alloc; /* excluding the header and null terminator */
    unsigned char flags; /* 3 lsb of type, 5 unused bits */
    char buf[];
};
struct __attribute__ ((__packed__)) sdshdr16 {
    uint16_t len; /* used */
    uint16_t alloc; /* excluding the header and null terminator */
    unsigned char flags; /* 3 lsb of type, 5 unused bits */
    char buf[];
};
struct __attribute__ ((__packed__)) sdshdr32 {
    uint32_t len; /* used */
    uint32_t alloc; /* excluding the header and null terminator */
    unsigned char flags; /* 3 lsb of type, 5 unused bits */
    char buf[];
};
struct __attribute__ ((__packed__)) sdshdr64 {
........

对于 redis 来说,其整体就是一个 hashtable ,通过哈希函数对于到相应的槽位,本质就是一个对象数组,同样使用拉链法解决哈希碰撞问题。

同时会准备两个 ht[2] 方便来进行数据的扩容以及搬运。这个搬运过程是分散的。

数组中存储对于的 value 的数据。

对于 List 的实现,redis 同样做了优化,如果直接使用 链表来在进行构建,那么可能会出现胖指针的问题(即数据占用内存很小维持数据所需要的指针占用内存却很大),提供了 zplist 即 quicklist 双端链表 + zplist 的结合实现,quicklist 就是带有双向指针的链表,不过元素是 zplist

zplist 是 redis 自定义的数据结构,其意在于使用连续的一组空间表示一组数据。entry 定义了 prerawlen 和 len 来标识寻找前一个元素、自身和后一个元素。

在这里插入图片描述

zset 的实现是 dict 字典(即 hashtable) + 跳表实现

Redis 持久化

RDB 和 AOF 以及 混合持久化

RDB 快照

save 60 1000 // 60s 1000 个键发生了改变后同步 RDB

RDB 是 Redis 默认的一种持久化方式,当时间段内累计的键值改动达到配置值时会触发 RDB 持久化,Redis 提供了 bgsave 写时复制的能力,即在不阻塞读写的同时进行持久化,RDB 存储的是二进制字节码文件,每次同步都会将 Redis 内存的全部数据生成新的 RDB 快照替换原来的快照,RDB 恢复速度较快,但是容易丢失一部分数据

AOF appand only file

不同于 RDB, AOF 是将每次执行的指令进行了存储,是一个极其安全的持久化方式,其恢复是根据 AOF 备份的指令进行指令重放。

可以配置每个命令都 flush 到 aof 文件,或者每秒刷一次。其安全性高,但是恢复数据的速度较慢

appendfsync always:每次有新命令追加到 AOF 文件时就执行一次 fsync ,非常慢,也非常安全。
appendfsync everysec:每秒 fsync 一次,足够快,并且在故障时只会丢失 1 秒钟的数据。
appendfsync no:从不 fsync ,将数据交给操作系统来处理。更快,也更不安全的选择。

AOF 可以对其存储的指令重写,优化掉键值得某些无限中间过程直接执行结果,这样可以优化恢复数据时重新执行指令的时间

auto‐aof‐rewrite‐min‐size 64mb //aof文件至少要达到64M才会自动重写,文件太小恢复速度本来就
很快,重写的意义不大
auto‐aof‐rewrite‐percentage 100 //aof文件自上一次重写后文件大小增长了100%则再次触发重写

混合持久化 4.0 开始支持

即结合 RDB 和 AOF 两种方式,AOF 在重写是不是优化指令,而是优化为 RDB 快照。在恢复时先载入快照数据,然后执行剩余的指令。

这样的结合即保证了安全性也提供了较快的恢复速度。

Redis 集群

主从

主从模式,一主一从,一主多从,主从模式可以分散服务的读数据压力,写数据仍由主节点负责。是最简单的一种集群模式。

主节点我们称其为 master 节点,从节点为 slave 。

数据同步:

对于首次与 master 建立长连接的 slave 节点,slave 会向主节点发生 PSYNC 命令,请求复制全量数据,这时主节点会执行 bgsave 将内存数据打包成为 rdb 文件进行持久化,在持久化期间新的可能引发数据变更的命令,主节点会记录在内存缓存中。

持久化完成后将全量 rdb 文件发送给 slave 节点,slave 将接收到的文件数据持久化生成 rdb 文件,然后加载到内存中。主节点在将期间缓存的数据变更指令同步给从节点,此时主从建立长连接,将持续同步后续的数据变更。达到主从数据一致。

当 slave 节点与主节点断连后会自动重新连接,如果主节点同时收到多个 slave 的连接请求 PSYNC 时,主节点不会进行多次的 bgsave ,会合并为一次,然后将这份 rdb 文件数据转发给多个并行的连接。

一般来说在主从断线重连后会进行数据的全量复制,但在 2.8 版本之后支持了 PSYNC 的断点续传功能,在一定的数据时效范围内可以进行断点续传,主从节点会记录 master 主进程 id 以及数据偏移 id ,重连后将从偏移 id 进行一个数据的续传,如果进程 id 发生变化或者 offset 太旧则会进行全量复制。

优点:

  1. 较单一 redis 服务可以分散集群读数据压力
  2. 多从节点备份,提高了数据存储的安全性

不足:

  1. 主节点宕机,整个集群将不可用,无法自动恢复,需要手动指定主节点
  2. 主从复制期间如果发生主节点宕机将丢失部分数据
  3. 只有一个主节点,服务的写入能力和存储能力将大大受限
  4. 过多的从节点可能会导致复制风暴(可以通过给 slave 下挂载 slave 来缓解主从复制风暴)

哨兵

哨兵模式是对主从模式主节点宕机无法自动恢复的一种补正,此模式下需要部署一个哨兵集群,其功能类似于服务注册与发现中心,客户端可以通过哨兵主节点发现 redis 服务,以及更新 redis 服务节点地址,同时对于主从 redis 服务进行监控,当主节点宕机后可以进行重新选主的操作。

集群(推荐)

集群模式是我们开发搭建大型服务项目最常用的,也是最推荐的,其支持主节点宕机自动选主,以及多个主节点同时提供写服务以分散数据写入以及数据存储压力,可以平滑扩容,(是基于 hash 算法,不同的 key hash 到不同的 master 节点中)

集群模式下,会将数据分为 16384 个槽位,每个主节点都会分配部分槽位,在操作键值时会进行槽位的计算,逻辑为:

hash-slot = crc16(key) % 16384

集群通信:

集群维护集群元数据的通信方式有两种:集中式通信和 gossip 协议通信,默认的 redis 集群采用 gossip 协议进行通信

元数据是指:集群节点信息,节点数量,主从角色,各节点共享信息等

集中式通信类似于很多中间件的元数据中心,所有的元数据信息集中在一个点上,优点是时效性好,可以快速感知,不足是所有元数据更新集中在一个点上,可能会导致元数据的存储压力。

gossip 协议包含多种消息,比如

meet :某节点给新节点发送,让新节点加入集群并进行集群通信

ping: 每个节点会频繁给其他节点发送 ping 消息,并且附带自身的元数据信息,集群节点间通过 ping 消息进行数据同步

pong: 对 ping 和 meet 的回复,同时附带自己的 元数据信息。也可以进行信息广播和更新

fail: 某个节点判断其他节点宕机后像集群发送 fail 同步该节点宕机的信息

gossip 优点在于是分散存储,信息是一步一步同步扩散到整个集群的,可能会存在一些延迟,但是集群的存储压力较小。

集群选主:

  1. slave 节点发现自己的 master 节点宕机
  2. 本机记录的 currentEpoch + 1 ,广播发送 FAILOVER_AUTH_REQUEST
  3. 其他 master 会响应该消息,并对于每个 epoch 只 ack 一次该消息
  4. slave 收到半数以上的 FAILOVER_AUTH_ACK 时会成为新的主节点并发送 pong 消息广播

建议

集群 master 个数最少三个,建议奇数个,slave 同样如此

选举过半机制防止集群脑裂。

注意集群的批量操作仅限于 key 可以落到同一个 slot 上的情况。如果非要有多个不同 key 进行批量操作,可以在 key 前面加 {xxx} 这样在计算 hash 槽时只会使用大括号中的值。

管道 Pipeline 和 Lua 脚本

简单说一下,pipeline 是同时提交多个 redis 命令,并且统一等待回复,这个好处仅在于减少多个命令和 redis 服务的通信,单各个命令的执行情况相互独立。

Lua 脚本是 redis 提供的非常强大的功能,其具备原子性可以替代 redis 的事务的功能。在事务上强烈建议使用 Lua 脚本。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/180032.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【SpringCloud】Feign 和 OpenFeign 两者的异同点

Feign 和 OpenFeign 两者共同点Feign和OpenFeign作用一样&#xff0c;都是进行远程调用的组件。里面都内置了 Ribbon。都是加在消费端的注解&#xff0c;让消费端可以调用其他生产者的服务。Feign 和 OpenFeign 两者区别&#xff08;1&#xff09;依赖不同Feign 的依赖<!-- …

十九、Gtk4-Ui file for menu and action entries

Ui file for menu 你可能认为构建菜单真的很麻烦。是的&#xff0c;程序很复杂&#xff0c;需要很多时间来编码。这种情况类似于构建小构建。当我们构建部件时&#xff0c;使用ui文件是避免这种复杂性的好方法。菜单也是如此。 菜单的ui文件有界面和菜单标签。文件以interfac…

JavaScript 基本认识

JavaScript 简介 JavaScript 是什么&#xff1f; JavaScript 是互联网最流行的脚本语言&#xff0c;这门语言可用于 HTML 和 Web&#xff0c;更可广泛用于服务器、PC、笔记本电脑、平板电脑和智能手机等设备。 JavaScript 是脚本语言&#xff1f; HTML 是超文本标记语言&am…

Groovy实现热部署

Groovy实现热部署一、概述二、准备工作2.1 规则接口IRule三、非Spring环境Groovy文件方式3.1 Groovy文件3.2 读取并生成实例3.3 使用这个实现四、数据库Groovy脚本方式4.1 Groovy脚本4.2 读取并生成实例五、Spring中使用Groovy的方式5.1 Groovy文件5.2 读取并生成实例5.3 使用这…

css sprite雪碧图制作,使用以及相关,图文gif

写在前面&#xff1a; 在网页制作中&#xff0c;雪碧图也是前端攻城狮必须掌握的一项小技能。百度词条对雪碧图的解释是&#xff1a;CSS雪碧 即CSS Sprite&#xff0c;也有人叫它CSS精灵&#xff0c;是一种CSS图像合并技术&#xff0c;该方法是将小图标和背景图像合并到一张图…

计算机组成原理 | 第一章:概论 | 冯诺依曼计算机 | 计算机硬件

文章目录&#x1f4da;冯诺依曼计算机的特点&#x1f4da;计算机硬件组成框图&#x1f4da;计算机硬件的主要技术指标&#x1f407;非时间指标&#x1f407;时间指标&#x1f511;计算技巧归纳&#x1f4da;小结&#x1f511;本章掌握要点&#x1f407;补充思考题&#x1f4da;…

[电商实时数仓] 用户行为数据和业务数据采集以及ODS层

文章目录1.数据仓库环境准备1.1 导入依赖1.2 创建相关包2.数据仓库运行环境2.1 Hbase环境2.2 模拟数据3.数仓开发之ODS层3.1 mysql配置修改3.2 FlinkCDC的程序3.3 结果检测1.数据仓库环境准备 1.1 导入依赖 <properties><java.version>1.8</java.version>&l…

为什么你的Facebook广告策略应该包括SEO

最近在看了很多关于 SEO的文章&#xff0c;今天想跟大家分享一些我个人关于 Facebook广告中的 SEO策略&#xff0c;以及它为什么是必要的。虽然在我看来&#xff0c;所有营销手段都需要结合 SEO才能发挥最大作用&#xff0c;但这并不意味着要完全放弃 SEO。如果你对以下问题感兴…

分享147个ASP源码,总有一款适合您

ASP源码 分享147个ASP源码&#xff0c;总有一款适合您 下面是文件的名字&#xff0c;我放了一些图片&#xff0c;文章里不是所有的图主要是放不下...&#xff0c; 147个ASP源码下载链接&#xff1a;https://pan.baidu.com/s/1us1KTsxeaZlosHsqvrkC5Q?pwd81pl 提取码&#x…

Leetcode:51. N 皇后(C++)

目录 问题描述&#xff1a; 实现代码与解析&#xff1a; 回溯&#xff1a; 原理思路&#xff1a; 问题描述&#xff1a; 按照国际象棋的规则&#xff0c;皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。 n 皇后问题 研究的是如何将 n 个皇后放置在 nn 的棋盘上&a…

数字电位器程控可调电阻ic

一、前言 数字电位器又叫可编程电阻器&#xff0c;是一种替代传统机械电位器的新型CMOS数字、模拟混合信号处理集成电路&#xff0c;不需要搭建复杂的电路环境即可简单的通过CPU数字通讯实现电路调节&#xff0c;数字电位器也不能完全替代传统的机械电位器&#xff0c;在很多场…

Sentinel(限流、熔断、降级)、SpringBoot整合Sentinel、Sentinel的使用-60

一&#xff1a;Sentinel简介 Sentinel就是分布式系统的流量防卫兵 随着微服务的流行&#xff0c;服务和服务之间的稳定性变得越来越重要。Sentinel 以流量为切入点&#xff0c;从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。 1.1 官方文档 官方文档&#…

基于OpenXR,Collabora推开源VI-SLAM AR/VR定位系统

XR最关键的难题之一就是定位&#xff0c;为了定位XR头显在现实世界中的位置和角度&#xff0c;厂商们采用了多种方案&#xff0c;比如机械传感器、惯性传感器、磁传感器、声学传感器等等。这些定位方式有一个共同的问题&#xff0c;那就是传感器不够完善&#xff0c;且会产生噪…

uniapp的父传子,子传父,子组件与父组件数据同步(.sync)的理解

父传子&#xff1a; 父调用 绑定的子组件中state然后 mystate1赋值false 给子组件中的state。并在子组件中显示父中传来的值。 注意要在子组件中设置 props【属性】不然父中的值无法传过去。 <view >开启{{mystate1}}</view> --调用子组件mypop&#xff0c;并传值…

学习记录673@项目管理之进度管理案例

本文主要是进度管理之关键链路法的案例。 案例 Perfect 项目的建设方要求必须按合同规定的期限交付系统&#xff0c;承建方项目经理李某决定严格执行项目进度管理&#xff0c;以保证项目按期完成。他决定使用关键路径法来编制项目进度网络图。在对工作分解结构进行认真分析后&…

05 二叉树前序/中序/后序线索化和找前驱、后继

1. 线索化代码 线索化需要先序/中序/后续遍历的过程&#xff0c;多了访问到节点时指针指向的问题 二叉树形状和运行结果 主函数 #include "func.h"// 二叉树线索化(便于找前驱和后继节点) // 1. 二叉树先序线索化 // 2. 二叉树中序线索化 // 3. 二叉树后序线索化//…

《MySQL》MySQL简单操作

最近开始了新的学习进度 进入MySQL数据库的学习 目录 一、MySQL启动方法 1.使用MySQL启动 2.使用cmd启动 二、数据库的简单操作命令 显示当前服务器上有哪些数据库 创建新的数据库 删除数据库 选中数据库 三、数据表的操作 数据类型 四、表的简单操作 查看数据库中的…

Java多线程-线程的生命周期

Java多线程-线程的生命周期 线程的状态 New 表示线程已创建&#xff0c;没启动的状态此时已经做了一些准备工作&#xff0c;还没有执行run方法中代码 Runnable 调用start方法之后的状态&#xff0c;表示可运行状态(不一定正在运行&#xff0c;因为调用start方法之后不一定立…

分享148个ASP源码,总有一款适合您

ASP源码 分享148个ASP源码&#xff0c;总有一款适合您 下面是文件的名字&#xff0c;我放了一些图片&#xff0c;文章里不是所有的图主要是放不下...&#xff0c; 148个ASP源码下载链接&#xff1a;https://pan.baidu.com/s/1e2PvBmXxZA8C3IelkP8ZtQ?pwdj7lp 提取码&#x…

node.js 安装步骤

1、下载安装包 Node.js 官方网站下载&#xff1a;Node.js 选择操作系统对应的包&#xff1a; 下载完成&#xff0c;安装包如下&#xff1a; 2、安装Node 打开安装&#xff0c;傻瓜式下一步即可&#xff1a; 选择安装位置&#xff0c;我这里装在D盘下&#xff1a; 安装成功&…