Redis 高可用方案深度解析
Redis 高可用一、主从复制1.1 主从复制概述主从复制是 Redis 高可用服务最基础的保证,实现方案就选择一个服务器作为 master,其他的服务器作为 slaver,一主多从,读写分离。这里注意一下,主从服务器之间的命令复制是异步进行的,不会等到从服务器都同步完才向客户端返回结果。所以,无法实现强一致性(数据时时刻刻都是一致的),只能达到最终一致性。 实际上,Redis 提供了主从库模式,以保证数据副本的一致,主从库之间采用的是读写分离的方式: 读操作:主库、从库都可以接收 写操作:首先到主库执行,然后,主库将写操作同步给从库 1.2 主从库第一次同步先来看看主从库间的第一次同步是如何进行的,这也是 Redis 实例建立主从库模式后的规定动作。当我们启动多个 Redis 实例的时候,它们相互之间就可以通过 replicaof(Redis 5.0 之前使用 slaveof)命令形成主库和从库的关系,之后会按照三个阶段完成数据的第一次同步。 例如,现在有实例 1(ip:172.16.19.3)和实例 2(ip:172.16.19.5),我们在实例 2 上执行以下这个命令:...
Redis 核心数据结构深度解析
Redis 核心数据结构一、全局 Hash 表1.1 全局 Hash 表概述为了实现从键到值的快速访问,Redis 使用了一个哈希表来保存所有键值对。一个哈希表,其实就是一个数组,数组的每个元素称为一个哈希桶。所以,我们常说,一个哈希表是由多个哈希桶组成的,每个哈希桶中保存了键值对数据。 如果值是集合类型的话,作为数组元素的哈希桶怎么来保存呢?其实,哈希桶中的元素保存的并不是值本身,而是指向具体值的指针。这也就是说,不管值是 String,还是集合类型,哈希桶中的元素都是指向它们的指针。 可以看到,哈希桶中的 entry 元素中保存了 *key 和 *value 指针,分别指向了实际的键和值,这样一来,即使值是一个集合,也可以通过 *value 指针被查找到。 因为这个哈希表保存了所有的键值对,所以,我也把它称为全局哈希表。哈希表的最大好处很明显,就是让我们可以用 O(1) 的时间复杂度来快速查找到键值对——我们只需要计算键的哈希值,就可以知道它所对应的哈希桶位置,然后就可以访问相应的 entry 元素。 你看,这个查找过程主要依赖于哈希计算,和数据量的多少并没有直接关系。也就是...
MySQL 事务深度解析
MySQL 事务深度解析一、事务 ACID1.1 简单介绍原子性(Atomicity) 也就是说这一串指令要么全部成功 要么全部失败 这点通过 begin 事务 commit 提交 rollback 回滚实现 其实就是 undo log 实现的 一致性(Consistency) 事务操作前后,数据满足一致性的约束,不会出现中间数据的情况 通过锁来实现,是在其他三个性质之上保证的 隔离性(Isolation) 多个事务执行时不会互相干扰 通过 MVCC 机制实现的 持久性(Durability) 事务处理之后,是要落盘的,而且即使系统故障数据也不会丢失 这点通过 log 日志实现 而且还是 redo log 1.2 总结 原子性通过 Undo Log 实现,保证事务要么全部成功要么全部回滚 隔离性通过 MVCC 和锁机制实现,保证并发事务互不干扰 持久性通过 Redo Log 和 WAL 机制保证,确保事务提交后即使宕机也不会丢失 一致性是事务执行前后数据库满足业务和约束规则的最终状态,它依赖于原子性、隔离性、持久性以及应用层的正确逻辑共同保证 二、SQL 的隔...
MySQL SQL 优化深度解析
MySQL SQL 优化一、执行流程1.1 SELECT 语句内部的执行步骤一条完整的 SELECT 语句内部的执行顺序是这样的: FROM 子句组装数据(包括通过 ON 进行连接) WHERE 子句进行条件筛选 GROUP BY 分组 使用聚集函数进行计算 HAVING 筛选分组 计算所有的表达式 SELECT 的字段 ORDER BY 排序 LIMIT 筛选 二、关键字的底层实现2.1 JOIN 的实现方式2.1.1 Index Nested-Loop Join(索引嵌套循环连接)(待补充内容) 优化方式: MRR(Multi-Range Read)优化 (待补充内容) 2.1.2 Simple Nested-Loop Join(简单嵌套循环连接)(待补充内容) 2.1.3 Block Nested-Loop Join(块嵌套循环连接)(待补充内容) 优化方式: (待补充内容) 2.1.4 Hash Join(哈希连接)(待补充内容) 2.2 ORDER BY 的实现方式2.2.1 全字段排序(待补充内容) 2.2.2 rowid 排序(待补充内容) 2.2...
MySQL 索引深度解析
MySQL 索引深度解析一、常见模型1.1 索引实现地点在 MySQL 中,索引是在存储引擎层实现的,所以并没有统一的索引标准,即不同存储引擎的索引的工作方式并不一样。(还记得前面存储引擎层实现了 undo log 的存储吗?)而即使多个存储引擎支持同一种类型的索引,其底层的实现也可能不同。 实现方式在 InnoDB 中,表都是根据主键顺序以索引的形式存放的,这种存储方式的表称为索引组织表。又因为前面我们提到的,InnoDB 使用了 B+树索引模型,所以数据都是存储在 B+树中的。 每一个索引在 InnoDB 里面对应一棵 B+树(想想 everything 先建立索引,然后再便于我们查找文件就知道了,又或者是 ES 的倒排索引,索引的目的就是加快查找速度)。 索引类型 主键索引 - 的叶子节点存的是整行数据。在 InnoDB 里,主键索引也被称为聚簇索引(clustered index) 非主键索引 - 的叶子节点内容是主键的值。在 InnoDB 里,非主键索引也被称为二级索引(secondary index) 主键索引和普通索引的查询区别根据上面的索引结构说明,我们来讨论...
MySQL 锁机制深度解析
MySQL 锁机制深度解析一、锁的种类1.1 按加锁粒度分类1.1.1 全局锁概念 顾名思义,全局锁就是对整个数据库实例加锁。MySQL 提供了一个加全局读锁的方法,命令是 Flush tables with read lock (FTWRL)。 当你需要让整个库处于只读状态的时候,可以使用这个命令,之后其他线程的以下语句会被阻塞: 数据更新语句(数据的增删改) 数据定义语句(包括建表、修改表结构等) 更新类事务的提交语句 典型使用场景 全局锁的典型使用场景是,做全库逻辑备份。也就是把整库每个表都 select 出来存成文本。 以前有一种做法,是通过 FTWRL 确保不会有其他线程对数据库做更新,然后对整个库做备份。注意,在备份过程中整个库完全处于只读状态。 问题分析 但是让整库都只读,听上去就很危险: 如果你在主库上备份,那么在备份期间都不能执行更新,业务基本上就得停摆 如果你在从库上备份,那么备份期间从库不能执行主库同步过来的 binlog,会导致主从延迟 不加锁的话,备份系统备份的得到的库不是一个逻辑时间点,这个视图是逻辑不一致的(所以在全库逻辑备份的时候要 STW...
MySQL 各种日志深度解析
MySQL 各种日志深度解析一、Double Write(二次写)1.1 脏页刷盘的风险是什么首先介绍一下 IO 的最小单位: 数据库 IO 的最小单位是 16K(MySQL 默认,Oracle 是 8K) 文件系统 IO 的最小单位是 4K(也有 1K 的) 磁盘 IO 的最小单位是 512 字节 因此,存在 IO 写入导致 page 损坏的风险。 1.2 ⭐二次写解决了什么问题提高了 InnoDB 的可靠性,用来解决部分写失败(partial page write 页断裂)。 一个数据页的大小是 16K,假设在把内存中的脏页写到数据库的时候,写了 2K 突然掉电,也就是说前 2K 数据是新的,后 14K 是旧的,那么磁盘数据库这个数据页就是不完整的,是一个坏掉的数据页。 redo 只能加上旧、校检完整的数据页恢复一个脏块,不能修复坏掉的数据页,所以这个数据就丢失了,可能会造成数据不一致,所以需要 Double Write。 当数据库正在从内存向磁盘写一个数据页时,数据库宕机,从而导致这个页只写了部分数据,这就是部分写失效,它会导致数据丢失。这时是无法通过重做日志恢复的,因...
MySQL 缓存机制深度解析
MySQL 缓存机制深度解析一、Buffer Pool(缓冲池)1.1 ⭐Buffer Pool 缓存的东西基本概念我们都知道 InnoDB 存储引擎会把存储的数据划分为多个页,并且是以页作为磁盘与内存交互的基本单位,一个页的大小是 16KB。 由于 Buffer Pool 是 InnoDB 存储引擎内部的结构,所以它们都是用页来划分空间的。 初始化过程在 MySQL 启动的时候,InnoDB 会为 Buffer Pool 申请一片连续的内存空间,然后按照 16KB 划分出一个一个的页,Buffer Pool 中的页被称为缓存页。此时这些缓存页都是空闲的,还没有写入磁盘中的页,之后随着程序的运行才会进行写入操作。 Lazy 初始化所以,在 MySQL 刚刚启动的时候,使用的虚拟内存很大,但是实际使用的物理内存其实很小,因为只有当这些虚拟内存被访问之后,操作系统才会触发缺页中断,申请物理内存,将虚拟地址和物理地址建立映射关系,这还有一个说法叫 lazy 初始化。 缓存内容当然,Buffer Pool 除了缓存索引页和数据页,还会缓存一些其他的页数据。 1.2 ⭐预读失效问题描述根据...
MySQL 存储引擎深度解析
MySQL 存储引擎深度解析一、InnoDB 架构1.1 MySQL 的数据是存放在哪的⭐ibdata1 共享表空间需要注意的是表的数据可以存储在共享表空间里面 也可以存储在独占表空间里面,这个参数由 innodb_file_per_table 控制 默认是开启的。不过实际上这个 ibdata1 文件还是存在的。 原理说明 如果启用了 innodb_file_per_table 参数,需要注意的是每张表的表空间内存放的只是数据、索引和插入缓冲 Bitmap 页,其他数据如: 回滚信息、插入缓冲索引页、系统事物信息、二次写缓冲(Double write buffer)等还是放在原来的共享表空间内。同时说明了一个问题: 即使启用了 innodb_file_per_table 参数共享表空间 ibdata1 还是会不断的增加其大小的 数据库空间占用来源数据库主要的空间占用来源于哪两部分。这里,我们还是针对 MySQL 中应用最广泛的 InnoDB 引擎展开讨论。 一个 InnoDB 表包含两部分,即:表结构定义和数据。 在 MySQL 8.0 版本以前,表结构是存在以.frm 为后缀...
MySQL 架构深度解析
MySQL 架构深度解析一、主从复制1.1 几种常见的主从复制模型主要有三种: 1. 同步复制性能差,可用性也差,一旦一个从库出现问题都会影响到业务 2. 异步复制(默认模型)MySQL 主库提交事务的线程不会等待 binlog 同步完成就会返回客户端结果,一旦主机宕机,数据就会发生丢失 3. 半同步复制MySQL 5.7 版本之后增加的一种复制方式,介于两者之间,事务线程不用等待所有的从库都完成复制,只要有一部分复制成功响应回来就行,即使主库宕机,至少还有一个从库有最新的数据,不存在数据丢失的风险。 二、分库分表2.1 垂直分库分表核心概念根据不同的业务功能/模块,将数据按表结构或库结构进行拆分。 垂直分库将不同业务模块的表拆到不同数据库中 垂直分表将一张表中的列划分为多个子表,按字段分类存储 2.2 水平分库分表核心概念把相同结构的数据,按一定规则划分到多个库或表中。 水平分表将一张表的数据行按规则拆分到多个表中 水平分库不仅拆表,还把多个分表分布到不同数据库中