第五届字节跳动青训营Class16笔记 | 青训营笔记

346 阅读7分钟

这是我参与「第五届青训营 」笔记创作活动的第16天

1.经典技术

红包雨活动

给抖音账户扣除一个小目标,给羊老师账户扣除一个大目标:

UPDATE account_table SET balance = balance - '小目标' WHERE name ='抖音';
UPDATE account_table SET balance = balance + '小目标' WHERE name ='羊老师';

RDBMS(Relational Database Management System) 事务 ACID

  • 事务(Transaction):是由一组SQL语句组成的一个程序执行单元(Unit),它需要满足ACID特性
BEGIN;
UPDATE account_table SET balance = balance - '小目标' WHERE name ='抖音';
UPDATE account_table SET balance = balance + '小目标' WHERE name ='羊老师';
COMMIT;

以红包雨活动为例,给两个账户的操作要么同时成功,要么同时失败(A),两个操作也必须是合法的,两个账户信息必须从一个有效的状态到另一个有效的状态(C)。同一个账户在不同操作时应该是串行的(I),更新成功后,结果应该永久性地保留下来(D)。

2.发展历史

前DBMS

文件系统

1950s,1956年IBM发布了第一个磁盘驱动器--Model 305 RAMAC,这个阶段数据管理通过文件系统实现

DBMS时代

1960s,DBMS作为按照某种数据模型来组织、存储和管理数据的仓库这一定义产生

网状数据库

graph TD
College --> English
College --> Computer
College --> Math
English --> Tom
English --> Jerry
English --> Spike
Computer --> Jerry
Computer --> Spike
Math --> Tuffy
Math --> Spike

网状模型通过树状结构形成一个子节点对应多个父节点、一个父节点对应多个子节点的网状模型

层次数据模型

graph TD
College --> English
College --> Computer
College --> Math
English --> Tom
English --> Jerry
English --> Spike
Computer --> Jerry'
Computer --> Spike'
Math --> Tuffy
Math --> Spike''

层次模型通过树状结构形成一个子节点对应一个父节点、一个父节点对应多个子节点的网状模型

关系模型

CourseIdCoureseName...
1Tom...
2Jerry...
3Spike...

三种模型的比较

image.png

DBMS时代

SQL语言

1974年IBM的Ray Boyce和Don Chamberlin将Codd关系数据库的12条准则的数学定义以简单的关键字语法表现出来,提出了SQL(Structured Query Language)语言。

  • 语法风格接近自然语言;
  • 高度非过程化;
  • 面向集合对的操作方式;
  • 语言简洁,易学易用;

DBMS时代数据库发展进程

image.png

3.关键技术

一条SQL的一生

image.png

Parser

解析器(Parser)一般分为词法分析(Lexical anlysis)、语法分析(Syntax analysis)、语义分析(Semantic analyzer)等步骤 以红包雨活动的SQL为例:

UPDATE account_table SET balance = balance - '小目标' WHERE name ='抖音';

词法分析

  • 关键字:UPDATE/SET/WHERE
  • 表列名:account_table/balance/name
  • 常量:'小目标'/抖音
  • 运算符:'='/'-'
  • 结束符:';'

语法分析

struct UpdateStmt{
    Table: account_table
    Fields:balance;
    Values:balance-'小目标'
    Where: name='抖音';
    OrderBy:null;
    Limit:null;
}

语义分析

  • Table是否存在
  • balance/name是否存在
  • 常量'小目标'/'抖音'的类型是否合法

Optimizer

意义

SELECT * FROM A,B,C WHERE A.a1=B.b1 and A.a1=C.b1

执行这样一条SQL语句有三种方式:

image.png 优化器会选择其中执行效率最高的一条

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

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

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

代价:时间、IO、CPU、NET、MEM

Executor

火山模型

image.png

每个Operator调用Next操作,访问下层Operator,获得下层Opearator返回的一行数据,经过计算之后,将这行数据返回给上层

  • 优点:每个算子独立实现,相互之间没有耦合,逻辑结构简单
  • 缺点:每计算一条数据有多次函数调用开销,导致CPU效率不高

向量化模型

每个Operator每次操作计算不再是一行数据,而是一批数据(Batch N行数据),计算完成后向上层算子返回一个Batch。

优点:函数调用次数降低为1/N; CPU cache命中率更高;可以利用CPU提供的SIMD(Single Instruction Multi Data)机制

在SIMD机制下,对一个向量中的所有元素的操作是同步并行进行的

编译执行

将所有操作封装到一个函数里面,函数调用的代价也能大幅度降低

LLVM动态编译执行技术:根据用户的SQL,生成一段执行代码并且动态编译

存储引擎-InnoDB

image.png

In-Memory:

  • Buffer Pool
  • Change Buffer
  • Adaptive Hash Index
  • Log Buffer

On-Disk:

  • System Tablespace(ibdata1)
  • General Tablespaces(xxx.ibd)
  • Undo Tablespaces(xxx.ibu)
  • Temporary Tablespaces(xxx.ibt)
  • Redo Log(ib_logfileN)

Buffer Pool

image.png

每个chunk是128M的大小,在chunk中以16KB的大小分配页面,用block来标记,再将一组chunk分到一组Instance中,可以降低页面访问的吞吐

具体page_id到block的访问是通过HashMap<page_id,block*>来实现的

LRU算法

LRU算法目的是将经常使用的数据存放起来,并且将不常用的数据释放掉

image.png

Page

变长字段列表NULL值标志位Headerrow_idtrx_idroll_ptrCol1Col2Col3...ColN

Header

  • delete_mask:表示此条数据是否被删除
  • next_record:下一条数据的位置
  • record_type:表示当前数据类型

image.png Directory跳跃性地存储了一些数据的索引,当进行查找操作的时候,会先对目标索引进行二分查找,再进行一个很小的遍历操作来获取需要查找的数据。

B+ Tree

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

image.png

事务引擎

一致性通常由业务层面实现

Undo Log

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

image.png

Isolation与MVCC

MVCC的意义:

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

image.png

形成了一个数据从老版本到新版本的链表,有用户在更新数据的时候,读操作将会得到老版本的记录。

Redo Log

在事务提交前页面写盘:随机IO、写放大

随机IO是指数据保存在磁盘上的不同位置,操作时间连续但空间不连续的IO方式,随机I/O需要花费昂贵的磁头旋转和定位来查找。

image.png

写放大是指对于某一个Page的改动很小,但是写操作需要对整个Page进行一遍。

WAL(Write-ahead logging)

redo log是物理日志,记录的是页面的变化,它的作用是保证事务持久化。如果数据写入磁盘前发生故障,重启MySQL后会根据redo log重做

4.企业实践

大流量-Shading

问题背景

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

解决方案

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

实施效果

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

代理点通过哈希的方式分库分表,将同一结构化数据分布在不同的表上

流量突增-扩容

问题背景

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

解决方案

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

image.png

实施效果

  • 数据库集群提供更高的吞吐
  • 保证集群可以承担预期流量

流量突增-代理连接池

问题背景

  • 徒增流量导致大量建联
  • 大量建联导致负载变大,延时上升

解决方案

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

实施效果

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

总结

本节课程从RDBMS的前世今生讲起,介绍了当前比较常用的数据库MySQL的一些内部实现和优化机制,以及数据库事务的具体实现方式,最后使用一个企业实践作为案例来介绍部署层面的优化。