InnoDB 表空间

这应该是 MySQL 原理中最底层的部分了,我们存在 MySQL 中的数据,到底在磁盘上长啥样。你可能会说,数据不都存储在聚簇索引中吗?但很遗憾,你并没有回答我的问题。我会再问你,那聚簇索引在磁盘上又长啥样?

就像 Redis 的 RDB 文件,最终落在磁盘上就是一个真真切切的 dump.rdb 文件,而 MySQL 就显得有点迷,我们只知道通过 SQL 去拿数据,并不知道数据最终是以什么方式进行存储的。当然,了解其底层的存储逻辑,并不仅仅是为了满足好奇心这么简单。

其底层的存储方式,会影响到聚簇索引中数据的存储,进而影响到 MySQL 的 DML(Data Manipulation Language) 性能,所以对底层存储逻辑有个清晰的认知,就能够在某些对性能有着极致追求的场景下,帮助我们对 MySQL 进行优化。

表在磁盘上到底长啥样

继续阅读InnoDB 表空间

MySQL 页完全指南——浅入深出页的原理

之前写了一些关于 MySQL 的 InnoDB 存储引擎的文章,里面好几次都提到了页(Pages)这个概念,但是都只是简要的提了一下。例如之前在聊 InnoDB内存结构 时提到过,但当时的重点是内存架构,就没有展开深入。

我发现有好几次都需要提到页,那我就正好拿一篇来详细的讲讲 InnoDB 中的页。

页是什么

首先,我们需要知道,页(Pages)是 InnoDB 中管理数据的最小单元。Buffer Pool 中存的就是一页一页的数据。再比如,当我们要查询的数据不在 Buffer Pool 中时,InnoDB 会将记录所在的页整个加载到 Buffer Pool 中去;同样的,将 Buffer Pool 中的脏页刷入磁盘时,也是按照页为单位刷入磁盘的。

不了解 Buffer Pool 的、或者感兴趣的可以去文章开头给的链接熟悉一下

页的概览

我们往 MySQL 插入的数据最终都是存在页中的。在 InnoDB 中的设计中,页与页之间是通过一个双向链表连接起来。

而存储在页中的一行一行的数据则是通过单链表连接起来的。

继续阅读MySQL 页完全指南——浅入深出页的原理

缓存与数据库的双写一致性

这几天瞎逛,不知道在哪里瞟到了缓存的双写,就突然想起来这块虽然简单,但是细节上还是有足够多我们可以去关注的点。这篇文章就来详细聊聊双写一致性

首先我们知道,现在将高速缓存应用于业务当中已经十分常见了,甚至可能跟数据库的频率不相上下。你的用户量如果上去了,直接将一个裸的 MySQL 去扛住所有压力明显是不合理的。

这里的高速缓存,目前业界主流的就是 Redis 了,关于 Redis 相关的文章,之前也有聊过,在此就不赘述,感兴趣的可以看看:

额,不列出来我都没感觉关于 Redis 我居然写了这么多…言归正传。

在我们的业务中,普遍都会需要将一部分常用的热点数据(或者说不经常变但是又比较多的数据)放入 Redis 中缓存起来。下次业务来请求查询时,就可以直接将 Redis 中的数据返回,以此来减少业务系统和数据库的交互。

这样有两个好处,一个是能够降低数据库的压力,另一个自不必说,对相同数据来说能够有效的降低 API 的 RT(Response Time)。

继续阅读缓存与数据库的双写一致性

深入剖析 MySQL 自增锁

之前的文章把 InnoDB 中的所有的锁都介绍了一下,包括意向锁、记录锁…自增锁巴拉巴拉的。但是后面我自己回过头去看的时候发现,对自增锁的介绍居然才短短的一段。

其实自增锁(AUTO-INC Locks)这块还是有很多值得讨论的细节,例如在并发的场景下,InnoDB 是如何保证该值正确的进行自增的,本章就专门来简单讨论一下 InnoDB 中的自增锁。

什么是自增锁

之前我们提到过,自增锁是一种比较特殊的表级锁。并且在事务向包含了 AUTO_INCREMENT 列的表中新增数据时就会去持有自增锁,假设事务 A 正在做这个操作,如果另一个事务 B 尝试执行 INSERT语句,事务 B 会被阻塞住,直到事务 A 释放自增锁。

这怎么说呢,说他对,但是他也不完全对。

继续阅读深入剖析 MySQL 自增锁

简单了解 MySQL 中相关的锁

本文主要是带大家快速了解 InnoDB 中锁相关的知识

为什么需要加锁

首先,为什么要加锁?我想我不用多说了,想象接下来的场景你就能 GET 了。

你在商场的卫生间上厕所,此时你一定会做的操作是啥?锁门。如果不锁门,上厕所上着上着,啪一下门就被打开了,可能大概也许似乎貌似有那么一丁点的不太合适。

数据也是一样,在并发的场景下,如果不对数据加锁,会直接破坏数据的一致性,并且如果你的业务涉及到钱,那后果就更严重了。

锁门表情包

锁的分类

在 InnoDB 中,都有哪些锁?其实你应该已经知道了很多了,例如面试中会问你存储引擎 MyISAM 和 InnoDB 的区别,你会说 MyIASM 只有表锁,但是 InnoDB 同时支持行锁和表锁。你可能还会被问到乐观锁和悲观锁的区别是啥。

锁的概念、名词很多,如果你没有对锁构建出一个完整的世界观,那么你理解起来就会比较有阻碍,接下来我们把这些锁给分一下类。

继续阅读简单了解 MySQL 中相关的锁

浅入浅出 MySQL 索引

索引是什么?为什么要有mysql 索引,解决了什么问题,其底层的原理是什么?为什么使用B+树做为解决方案?用其他的像哈希索引或者B树不行吗?

简单了解索引

首先,索引(Index)是什么?如果我直接告诉你索引是数据库管理系统中的一个有序的数据结构,你可能会有点懵逼。

为了避免这种情况,我打算举几个例子来帮助你更容易的认识索引

继续阅读浅入浅出 MySQL 索引

深入了解Zookeeper核心原理

之前的文章Zookeeper基础原理&应用场景详解中将Zookeeper的基本原理及其应用场景做了一个详细的介绍,虽然介绍了其底层的存储原理、如何使用Zookeeper来实现分布式锁。但是我认为这样也仅仅只是了解了Zookeeper的一点皮毛而已。所以这篇文章就给大家详细聊聊Zookeeper的核心底层原理。不太熟悉Zookeeper的可以回过头去看看。

ZNode

这个应该算是Zookeeper中的基础,数据存储的最小单元。在Zookeeper中,类似文件系统的存储结构,被Zookeeper抽象成了树,树中的每一个节点(Node)被叫做ZNode。ZNode中维护了一个数据结构,用于记录ZNode中数据更改的版本号以及ACL(Access Control List)的变更。

有了这些数据的版本号以及其更新的Timestamp,Zookeeper就可以验证客户端请求的缓存是否合法,并协调更新。

而且,当Zookeeper的客户端执行更新或者删除操作时,都必须要带上要修改的对应数据的版本号。如果Zookeeper检测到对应的版本号不存在,则不会执行这次更新。如果合法,在ZNode中数据更新之后,其对应的版本号也会一起更新

继续阅读深入了解Zookeeper核心原理

Zookeeper基础原理&应用场景详解

简单了解Zookeeper

Tips: 如果之前对Zookeeper不了解的话,这里大概留个印象就好了

Zookeeper是一个分布式协调服务,可以用于元数据管理、分布式锁、分布式协调、发布订阅、服务命名等等。

例如,Kafka中就是用Zookeeper来保存其集群中的相关元数据,例如Broker、Topic以及Partition等等。同时,基于Zookeeper的Watch监听机制,还可以用其实现发布、订阅的功能。

在平常的常规业务使用场景下,我们几乎只会使用到分布式锁这一个用途。

Zookeeper内部运行机制

Zookeeper的底层存储原理,有点类似于Linux中的文件系统。Zookeeper中的文件系统中的每个文件都是节点(Znode)。根据文件之间的层级关系,Zookeeper内部就会形成这个这样一个文件树。

在Linux中,文件(节点)其实是分类型的,例如分为文件、目录。在Zookeeper中同理,Znode同样的有类型。在Zookeeper中,所有的节点类型如下:

继续阅读Zookeeper基础原理&应用场景详解

详细了解 InnoDB 内存结构及其原理

最近发现,文章太长的话,包含的信息量较大, 并且需要更多的时间去阅读。而大家看文章,应该都是利用的一些碎片时间。所以我得出一个结论,文章太长不太利于大家的吸收和消化。所以我之后会减少文章的长度,2-3K字就差不多,也能够快速的阅读完。

之前写过一篇文章「简单了解InnoDB原理」,现在回过头看,其实里面只是把缓冲池(Buffer Pool),重做日志缓冲(Redo Log Buffer)、插入缓冲(Insert Buffer)和自适应哈希索引(Adaptive Hash Index)等概念简单的介绍了一下。

除此之外还聊了一下MySQL和InnoDB的日志,和两次写,总的来说算是一个入门级别的介绍,这篇文章就来详细介绍一下InnoDB的内存结构

InnoDB内存结构

其大致结构如下图。

InnoDB内存的两个主要区域分别为Buffer PoolLog Buffer,此处的Log Buffer目前是用于缓存Redo Log。而Buffer Pool则是MySQL或者说InnoDB中,十分重要、核心的一部分,位于主存。这也是为什么其访问数据的效率高,你可以暂时把它理解成Redis那样的内存数据库,因为我们更新和新增当然它不是,只是这样会更加方便我们理解。

继续阅读详细了解 InnoDB 内存结构及其原理

RocketMQ基础概念剖析和源码解析

Topic

Topic是一类消息的集合,是一种逻辑上的分区。为什么说是逻辑分区呢?因为最终数据是存储到Broker上的,而且为了满足高可用,采用了分布式的存储。

这和Kafka中的实现如出一辙,Kafka的Topic也是一种逻辑概念,每个Topic的数据会分成很多份,然后存储在不同的Broker上,这个「份」叫Partition。而在RocketMQ中,Topic的数据也会分布式的存储,这个「份」叫MessageQueue

其分布可以用下图来表示。

这样一来,如果某个Broker所在的机器意外宕机,而且刚好MessageQueue中的数据还没有持久化到磁盘,那么该Topic下的这部分消息就会完全丢失。此时如果有备份的话,MQ就可以继续对外提供服务。

为什么还会出现没有持久化到磁盘的情况呢?现在的OS当中,程序写入数据到文件之后,并不会立马写入到磁盘,因为磁盘I/O是非常耗时的操作,在计算机来看是非常慢的一种操作。所以写入文件的数据会先写入到OS自己的缓存中去,然后择机异步的将Buffer中的数据刷入磁盘。

继续阅读RocketMQ基础概念剖析和源码解析