mysql、redis、zk、kafka、es、linux持久化横评
2023-07-05 09:37:26 0 举报
AI智能生成
知识要点和原理解析,详细信息和图片均在黄色图标的注释中,鼠标移动到黄色图标上即会显示,图片加载有时较慢。
作者其他创作
大纲/内容
mysql
InnoDB总体结构
内存部分由多个缓冲区构成
redolog与binlog两阶段提交<br>
图示
buffer pool数据落盘<br>
数据库关闭时,将所有脏页刷新到磁盘,这是默认的方式<br>
Master Thread操作,这个主线程会每秒、每10秒从脏页列表刷新一定比例的页到磁盘,这是个异步的操作,不会阻塞查询<br>
buffer pool中的free列表空闲页不足时,需要刷新一部分来自LRU列表的脏页<br>
redo log文件不可用时,需要强制刷新一部分,为了保证redo log的循环利用<br>
内存回收
3种页
1、free page<br>
2、clean page<br>
3、dirty page<br>
针对这3种页,InnoDB使用3种链表维护<br>
free list<br>
flush list<br>
lru list<br>
脏页刷盘<br>
1、从LRU 链表的冷数据区刷新部分页面到磁盘<br>
2、从 flush 链表中刷新一部分页面到磁盘<br>
3、主动刷盘内存池中被淘汰的脏页<br>
Buffer Pool缓存淘汰
使用LRU会遇到的问题<br>
预读<br>
大量数据涌入<br>
解决方法<br>
冷热分离LRU
优化点1:midpoint<br>
优化点2:old_blocks_time<br>
优化点3:减少热页在链表移动<br>
磁盘部分包括各种表空间<br>
行结构和页结构
ibd文件的逻辑结构<br>
Tablespace<br>
Segment<br>
段和索引是一一对应的关系<br>
段不对应表空间的某一连续物理区域<br>
问题
一个使用 InnoDB 表只有一个聚簇索引,一个索引对应两个段,每个段都是以区为单位申请空间,是否意味着一个新创建的表即使没什么数据也要占用2个空闲区(2M空间)?并且每新建一个索引就会多申请2M的空间?如果真的是这样分配空间,对于一些只有几条数据的表而言实在是太浪费空间。
某个段分配空间的策略
Extent<br>
问题
为什么提出区的概念,并用区管理页?<br>
如果没有区<br>
Page<br>
InnoDB的页结构<br>
用户记录 和 User Records 堆<br>
用户记录的物理结构——堆<br>
Infimum 和 Supremum记录<br>
用户记录的逻辑结构——单向链表<br>
软删除<br>
页目录 Page Directory<br>
页目录的构建过程<br>
页目录的每一个槽本质上就指向每个分组(的组长)的指针<br>
页面头部 Page Header<br>
文件头部 File Header<br>
数据页与记录的关系<br>
Row<br>
索引<br>
特性
B+树的每一层都会形成一个双向链表<br>
叶子节点是数据页,存储普通用户记录
非叶子节点也是数据页,存储目录项记录
目录项记录跟用户记录存储结构一致,只是存储的数据略有差异<br>
目录项记录至少有3个固定的列+隐藏列<br>
索引是有序的<br>
叶子节点之间是有序的<br>
叶子节点内是有序的<br>
同层非叶子节点之间是有序的<br>
非叶子节点内是有序的<br>
从数据页变成索引这件事<br>
数据页<br>
数据页结构<br>
空闲空间<br>
双向链表<br>
数据页目录
索引<br>
页分裂<br>
主键目录<br>
索引页
现在整个搜索过程就十分简单了<br>
Innodb索引结构和方案<br>
InnoDB的<font color="#f44336"><b>索引</b></font>方案<br>
用户记录页<br>
目录页<br>
目录页的页内查找:<font color="#f44336"><b>二分查找</b></font><br>
目录页也会发生页分裂<br>
主键索引(聚簇索引)和普通索引的区别<br>
二级索引<br>
联合索引的页<br>
redis
对象封装
redisObject
两层结构<br>
六种内部数据结构<br>
底层的实现:dict,sds,ziplist,quicklist,skiplist,intset<br>
五种外部数据类型<br>
暴露给外部的调用接口:string,list,hash,set,sorted set<br>
字段<br>
type<br>
OBJ_STRING<br>
OBJ_LIST<br>
OBJ_SET<br>
OBJ_ZSET<br>
OBJ_HASH<br>
encoding<br>
lru<br>
refcount<br>
ptr<br>
作用<br>
redisObjec是<b><font color="#f44336">联结两个层面的数据结构的桥梁</font></b><br>
<b><font color="#f44336">为多种数据类型提供一种统一的表示方式</font></b><br>
<b><font color="#f44336">允许同一类型的数据采用不同的内部表示</font></b>,从而在某些情况下尽量节省内存
<b><font color="#f44336">支持对象共享和引用计数</font></b>。当对象被共享的时候,只占用一份内存拷贝,进一步节省内存<br>
持久化
RDB
触发过程<br>
手动<br>
save 命令<br>
<b><font color="#f44336">阻塞 Redis 服务</font></b>,直到整个 RDB 持久化完成,<b><font color="#f44336">不建议</font></b><br>
bgsave 命令<br>
该模式下的 RDB 持久化由子进程完成,<b><font color="#f44336">非阻塞</font></b><br>
自动<br>
save m n<br>
RDB 数据恢复<br>
优缺点<br>
优点<br>
由于 RDB 文件是一个<b><font color="#f44336">非常紧凑</font></b>的二进制文件,所以<b><font color="#f44336">加载的速度快于 AOF 方式</font></b><br>
fork 子进程方式,<b><font color="#f44336">不会阻塞</font></b>
RDB 文件代表着 Redis 服务器的某一个时刻的全量数据,所以它非常<font color="#f44336"><b>适合做冷备份和全量复制的场景</b></font><br>
缺点<br>
<b><font color="#f44336">没办法做到实时持久化,会存在丢数据的风险</font></b>
AOF(默认关闭)<br>
目的<br>
<b><font color="#f44336">解决数据持久化的实时性</font></b>
执行流程<br>
命令写入<br>
文件同步<br>
文件重写<br>
手动触发<br>
自动触发<br>
优缺点<br>
优点<br>
相比于 RDB,<b><font color="#f44336">AOF 更加安全,默认同步策略为 everysec 即每秒同步一次</font></b>,所以顶多我们就失去一秒的数据<br>
根据关注点不同,AOF 提供了不同的同步策略,我们可以根据自己的需求来选择<br>
AOF 文件是以 append-only 方式写入,相比如 RDB 全量写入的方式,它没有任何磁盘寻址的开销,<b><font color="#f44336">写入性能非常高</font></b>
缺点<br>
由于 AOF 日志文件是命令级别的,所以相比于 RDB 紧致的二进制文件而言它的<b><font color="#f44336">加载速度会慢些</font></b><br>
AOF 开启后,支持的写 QPS 会比 RDB 支持的<b><font color="#f44336">写 QPS 低</font></b><br>
RDB 和 AOF 混合模式<br>
RDB-AOF 混合持久化<br>
1、在 AOF 重写阶段创建一个同时包含 RDB 数据和 AOF 数据的 <b><font color="#f44336">AOF 文件</font></b>,其中 <b><font color="#f44336">RDB 数据位于 AOF 文件的开头</font></b>,RDB<b>存储了服务器开始执行重写操作时 </b>Redis 服务器<b>的数据状态</b>(RDB 快照方案)。<br>
2、<b>重写操作执行之后</b>的 Redis 命令(即已存储当前RDB之后的命令),则会<b>继续 append 在 AOF 文件末尾</b>,<b>即 RDB 数据之后</b>(AOF 日志追加方案),一般这部分数据都会比较小<br>
1. Redis 重启的时候,则可以先加载 RDB 的内容,然后再加载 AOF 的日志内容。<br>
zk
zk持久化<br>
内存中的数据<br>
事务日志<br>
日志文件<br>
数据快照<br>
为什么需要快照<br>
快照数据主要时为了快速恢复
数据恢复<br>
恢复数据的时候,先恢复快照数据,再通过增量恢复事务日志中的数据。
kafka
Kafka Broker 写入数据的过程<br>
隐患:如果数据写入 PageCache 后 Kafka Broker宕机会怎样?机子宕机/掉电?<br>
<b><font color="#f44336">Kafka Broker 宕机: 消息不会丢失</font></b><br>
<b><font color="#f44336">机子宕机/掉电: 消息会丢失</font></b><br>
拓展:Kafka 日志刷盘机制<br>
推荐采用<b><font color="#f44336">默认值</font></b>,即不配置该配置,<b><font color="#f44336">交由操作系统自行决定何时落盘</font></b>,以提升性能。
相关配置<br>
针对 broker 配置<br>
针对 topic 配置<br>
查看 Linux 后台线程执行配置<br>
索引及日志文件
文件存储机制
<b><font color="#f44336">每个分区</font>就对应<font color="#f44336">一个Log对象</font>,在物理磁盘上则对应于一个子目录</b><br>
<b>日志段是Kafka保存消息的最小载体</b><br>
<b>kafka利用<font color="#f44336">分段+索引</font>的方式来解决查找效率问题</b>
参数<b><font color="#f44336">log.segment.bytes</font></b><br>
限定了每个日志段文件的大小,最大为1GB。
超过该限制会进行日志切分滚动<b><font color="#f44336">log rolling</font></b><br>
<b><font color="#f44336">active log segment</font></b>:正在被写入的日志
<font color="#f44336"><b>ConcurrentSkipListMap</b></font><br>
索引机制<br>
分类
偏移量索引文件<br>
格式<br>
index文件<br>
如何通过offset找到对应的消息?<br>
时间戳索引文件<br>
格式<br>
查找<br>
查找原理<br>
索引项<br>
<b><font color="#f44336">索引项间隔:log.index.interval.bytes</font></b>
<b><font color="#a23735">索引文件</font>以<font color="#f44336">稀疏索引</font>的方式来构建</b>
<b>稀疏索引是通过<font color="#f44336">MappedByteBuffer</font>将索引文件映射到内存中(<font color="#f44336">pageCache</font>),加快索引的查询速度</b>
索引文件排序<br>
<b><font color="#f44336">按照位移/时间戳升序排序</font></b><br>
用二分法查找索引,时间复杂度是O(logN)
检索原理<br>
稀疏矩阵<br>
ConcurrentSkipListMap
ConcurrentSkipListMap的方法<br>
MMAP(MappedByteBuffer)<br>
有限内存加载所有segment?
检索整体流程图
日志定位过程<br>
例子<br>
检索总结
<b>定位索引段segment</b>时使用<font color="#f44336"><b>跳表ConcurrentSkipListMap</b></font>
索引文件.index使用稀疏索引存储,每4k数据一个索引
使用二分法检索文件
索引文件使用MMAP映射到pageCache
日志切分
每个LogSegment中的日志数据文件大小均相等<br>
改进后的二分法<br>
log文件存储格式<br>
offset index<br>
传统二分法源码<br>
问题<br>
改进后的二分法<br>
源码<br>
效果<br>
为什么设置热区大小为8192字节<br>
es
<b>索引层面</b>的写入、更新、删除、合并
写入过程<br>
过程分解
首先,document会被写入in-memory buffer和translog日志文件<br>
每隔1秒,执行一次refresh操作<br>
refresh操作完成后,buffer会被清空<br>
图解<br>
为什么说Elasticsearch是准实时(NRT,near real-time)?<br>
实时查询 - <b><font color="#f44336">GetById</font></b><br>
Translog 事务日志<br>
写入机制<br>
图解<br>
flush过程<br>
触发flush操作<br>
第一步,将buffer中的现有数据refresh到os cache中生成segment,清空buffer<br>
把之前所有没有落盘的 segment 强制刷盘,确保写入物理文件。<br>
创建一个提交点,记录这次提交对应的所有 segment,写入 commit point 文件。<br>
清空 Translog,因为 Segment 都已经踏实落地了,之前的 Translog 就不需要了。<br>
触发清理动作的2个条件<br>
大小触发设定的阈值;<br>
30分钟
删除和更新<br>
update流程(<font color="#f44336"><b>部分更新</b></font>)
versionMap
主要用途在数据变更时的校验
_id与_uid的联系<br>
segment 合并<br>
定期合并<br>
合并完成时的活动<br>
合并也是在内存中完成的,此时数据还没有写到磁盘中
整体流程图<br>
图1
图2<br>
memory buffer的倒排索引,则必须等Segment内所有文档全部写入完毕后,会先对Term进行一个全排序,之后才能构建索引,所以必须要有一个memory-buffer先缓存所有文档。<br>
Elasticsearch的写入流程特性<br>
可靠性<br>
一致性<br>
原子性<br>
实时性<br>
隔离性<br>
linux
文件系统<br>
一切皆文件<br>
磁盘结构<br>
盘面
磁道<br>
扇区
磁盘的基本单位<br>
块
文件系统操作文件的最小单位
Linux文件系统<br>
分为两层
<font color="#f44336"><b>VFS(虚拟文件系统)</b></font>
VFS在linux架构中的位置<br>
具体文件系统
虚拟文件系统四大对象<br>
1、超级块<br>
2、索引节点:inode<br>
inode描述<br>
一个inode可以有多个文件名(<b>目录项:dentry</b>)来对应它
inode能描述文件占用的块数<br>
inode描述了文件大小和指向数据块的指针<br>
通过i节点实现文件的逻辑结构和物理结构的转换
inode怎样生成的?<br>
inode和文件的关系?<br>
3、目录项:dentry<br>
目录项和索引节点的关系:<font color="#f44336">多对一</font>
目录项和目录是一个东西吗?<br>
4、逻辑块<br>
文件数据是如何存储在磁盘的?<br>
inode保存指向逻辑块的指针:一对多
文件分配方式<br>
连续分配<br>
优点<br>
缺点
链式分配<br>
隐式链接<br>
优点
缺点<br>
显式链接<br>
优点
缺点
索引分配<br>
优点
文件的创建、增大、缩小很方便<br>
不会有碎片的问题<br>
支持顺序读写和随机读写
缺点<br>
如果文件很大
链式索引块
多级索引块<br>
空闲空间的管理<br>
空闲表法<br>
优点<br>
缺点<br>
碎片空间
空闲链表法<br>
优点
无碎片空间
缺点<br>
不能随机访问,工作效率低<br>
数据块的指针消耗了一定的存储空间
位图法<br>
索引节点、目录项以及文件数据关系图<br>
文件的存储<br>
块组<br>
目录的存储<br>
内存管理<br>
<b><font color="#f44336">虚拟内存</font></b>、内存管理单元(MMU)、物理内存<br>
映射关系管理<br>
分段<br>
分段机制会把程序的虚拟地址分成 4 个段<br>
好处
能产生连续的内存空间
不足之处<br>
内存碎片<br>
内存交换的效率低<br>
分页<br>
怎么解决分段的内存碎片、内存交换效率低的问题?<br>
如果内存空间不够:<font color="#f44336"><b>LRU</b></font>
虚拟地址和物理地址是如何映射的?
举例<br>
<b>简单的分页</b>有什么缺陷呢?<br>
多级页表<br>
二级页表空间分析
局部性原理<br>
不分级为何无法节省内存<br>
页表缓存TLB(Translation Lookaside Buffer)<br>
内存回收<br>
三种回收方式<br>
1、回收内核中的缓存<br>
2、swap 机制<br>
3、触发 OOM(Out Of Memory) 机制<br>
swap机制原理<br>
哪些进程的内存交换到硬盘中?<br>
<b><font color="#f44336">匿名内存页(数据段、堆段 和 栈段)</font></b>
LRU 内存淘汰算法<br>
主要构成
active_list<br>
inactive_list<br>
PG_referenced标志位<br>
流程<br>
申请一个匿名内存页<br>
匿名内存页被进程访问<br>
内存淘汰过程<br>
活跃链表 的内存页也有衰退的过程<br>
用户态与内核态的内存空间<br>
虚拟内存<br>
0 条评论
下一页