深入理解RDBMS | 青训营笔记

81 阅读6分钟

这是我参与「第三届青训营 -后端场」笔记创作活动的第5篇笔记

基本概念

事务

是一组SQL语句组成的程序执行单元,它需要满足ACID特性

DBMS数据模型

网状模型:每个节点之间是多对多的关系。

层次模型:一对多关系。

关系模型:所有的数据都是一张二维表,无论实体还是关系。

SQL语言

1974年提出

结构化查询语言

关键技术

一条SQL的生命周期

Parser语法解析器解析SQL,生成一个语法树AST,给到优化器生成Plan,告诉Executor执行器到底怎么执行,从文件中读写数据、写入日志。

Parser, Optimizer, Executor 都是SQL引擎

DataFile, Log File 都是事务引擎

SQL引擎

Parser

一般分为词法分析、语法分析、语义分析等步骤

Optimizer

为什么需要优化器?

在可能的路径中,选择一个最优的路径。

一般先做一些条件化简,然后用基于代价的优化器。

基于规则的优化器(RBO Rule Base Optimizer)

  • 条件化简
  • 表连接优化
    • 总是小表先进行连接
  • Scan 优化
    • 唯一索引
    • 普通索引
    • 全表搜索

基于代价的优化器(CBO Cost Base Optimizer)

一个查询有多种执行方案,CBO会选择其中代价最低的方案去真正的执行。

什么是代价?时间(最主要)、IO、CPU、NET、MEM

不仅要考虑单点时间,往往要考虑分布式时延最低。

Executor

火山模型

查询树投影、过滤、请求,函数栈一层一层往下调用,数据是一层一层网上返回。

每个Operator调用Next操作,访问下层Opertor,获得下层Operator返回的一行数据。经过计算,返回结果给上一层。

优点:每个「算子」独立抽象实现,互相之间没有耦合,逻辑结构简单

缺点:每计算一条数据有多次函数调用开销,导致CPU效率不高。

向量化

和火山模型类似,但是每次返回的不再是一行数据,而是一批数据,计算完成后向上层算子返回一个Batch。

优点:函数调用次数降低为1/N,CPU cache命中率更高,可以利用CPU提供的SIMD(signle instruction multi data)机制

编译执行

用户SQL千变万化,不可能说穷举用户的所有SQL,给每一个SQL都预先写好一个函数。

将所有的操作封装到一个函数里,函数调用的代价大大降低。

存储引擎

InnoDB

分为两部分:内存中的结构和磁盘中的结构。

内存中结构主要是Buffer Pool,每次写入之前是先放到Buffer Pool中再进行写入操作的。

磁盘结构中东西很多,首先是System Tablespace 系统表空间,数据库使用要存储很多元数据,create table 叫什么,有什么索引,都是元信息。

Gerneral Tablespaces 存表数据的地方。

Buffer Pool

每个页面16k大小的内存空间

LRU机制:磁盘数据比内存远大,当访问数据时,内存数据肯定不足,需要从磁盘获取数据,放不下的话,就要淘汰的机制。把最常使用的数据留下来,很少使用的数据淘汰。管理内存空间。

Page

大小16K,在磁盘存储是按Page存储的

右下查找数据:二分查找+ 小的遍历

B+ tree 数据结构查找索引

页面中:

页目录中使用二分法快速定位到对应的槽,然后再遍历该槽对应分组中的记录即可快速找到指定的记录。

从根到叶的遍历:

中间节点存储。中间加点中是一个双向链表,如果是范围查询,可以很方便地进行遍历操作,获取范围数据。

\

事务引擎

Atomicity 与 Undo Log

如何将数据库回退到修改之间的状态?

Undo Log 实现

Undo Log 是「逻辑日志」,记录的是数据的增量变化。利用Undo Log可以进行事务回滚,从而保证事务的「原子性」。同时也实现了「多版本并发控制」(MVCC),解决读写冲突和一致性读的问题。

实现类似于执行sql的反义词。

Isolation 与 锁

如果两个操作同时进行,发生冲突怎么办?

读读:Share Lock 加共享锁

写写:Exclusive Lock 排他锁

读写:Share Lock Exclusive Lock

Isolation 与 MVCC

数据的多版本

通过数据的roll ptr属性形成一个链表,便于查询上一个版本,使得读写互不阻塞。

MVCC的意义:

  • 读写互不阻塞
  • 降低死锁概率
  • 实现一致性读

Durability 与 Redo Log

怎么保证事务结束后,对数据的修改永久的保存?

方案一:事务提交前Page写入disk

问题:

随机IO:随机写数据需要随机访问磁盘,代价很大;

写放大:数据可能只有10几个字节,但要写这个页面的数据(16KB)

方案二:WAL (Write-ahead logging)

redo log 是物理日志,记录的是页面的变化,作用是保证事务持久化。提交事务前一定要把日志写了。如果故障,重启后根据redo log重做。

企业实践

红包雨:

难点:流量大、流量突增、稳定性

大流量 - sharding

问题背景:

  • 单节点写容易成为瓶颈
  • 单机数据容量上限

解决方案:

  • 业务数据进行水平拆分
  • 代理层进行分片路由

实施效果:

  • 数据库写入性能线性扩展
  • 数据库容量线性扩展

流量突增 - 扩容

问题背景:

  • 活动流量上涨
  • 集群性能不满足要求

解决方案:

  • 扩容DB物理节点数量
  • 利用影子表进行压测

流量突增 - 代理连接池

问题背景:

  • 突增流量导致大量建联
  • 大量建联导致负载变大,延时上升,可能导致的DB连接被打死

解决方案:

  • 业务侧预热连接池
  • 代理侧预热连接池
  • 代理侧支持连接队列

实施效果:

  • 避免DB被突增流量打死
  • 避免代理和DB被大量建联打死

稳定性 & 可靠性

3AZ高可用

3A:在3个城市建立3个不同的机房,不同机房之间同过日志同步。

proxy:读写分离,分库分表,限流,流量调度

监控报警:实时监控集群运行状态

HA管理

问题背景:

  • db所在机器宕机
  • db节点异常宕机

解决方案:

  • ha服务监管、切换宕机节点
  • 代理支持配置热加载
  • 代理自动屏蔽宕机读节点

把机器下线去运维了,代理其他服务器。

\