0%

UDP

无连接

报文格式

image

  • 目标端口,16bit
  • 源端口,16bit
  • 包长度,16bit
  • 校验和,16bit

IP

报文格式

  • 版本,4bit
  • 首部长度,4bit
  • 服务类型TOS,8bit
  • 总长度,16bit
  • 标识,16bit
  • 标志,3bit
  • 片偏移,13bit
  • TTL,8bit,每经过一次路由器就会减1
  • 协议,8bit,如TCP(00001100),ICMP(00000001)
  • 首部校验和,16bit
  • 源IP地址,32bit
  • 目标IP地址,32bit
  • 选项
  • 数据

ICMP(Internet Control Message protocol),互联网控制报文协议

  • 用于确认IP包是否成功送达目标地址,报告发送过程中IP被废弃的原因和改善网络设置等

  • 查询报文类型

    标识符字段会记录由那个引用发送的ICMP包,同时选项数据中会记录发送时间,用于计算RT,说明路程的长短

    image

    • 0-回送应答
      ​IP报文中的头部类型字段,会用0标识​
    • 8-回送请求
      ​IP报文中的头部类型字段,会用8标识

  • 差错报文类型

    • 3-目标不可达

      • IP路由器无法发送IP数据包给目标地址时,会返回发送端主机一个目标不可达的ICMP消息,并将不可达原因记录在IP报文的代码字段
        ​0-网络不可达,路由表匹配不到对方的IP
        ​1-主机不可达,路由表没有主机的信息或者主机未连接网络
        ​2-协议不可达,如使用TCP访问对方主机时,能找到主机,但是TCP协议已被禁用
        ​3-端口不可达,对方主机没有监听对应的端口
        ​4-需要设置分片但设置了不分片
    • 4-远点抑制,增大IP数据包的传输间隔,缓和网络拥堵

    • 5-重定向或改变路由

    • 11-超时, TTL减为0时,数据包将被丢弃,会向发送方发送一个ICMP消息

  • Ping命令

IGMP

V1

优点

IGMPv1一共有两种报文,普查报文和成员报告报文,没有离组报文。

IGMPv1只有一种机制,响应抑制机制,没有离组机制。

缺点

IGMPv1没有查询器选举机制,需要PIM的DR来充当IGMPv1的查询器。

IGMPv1没有离组机制,对流量的控制性不好

来源:

https://zhuanlan.zhihu.com/p/387885523

TCP

  • 面向连接的、可靠的、基于字节流的传输层协议
    • 面向连接是指一对一
    • 可靠的是指无论网络链路中出现怎样的变化,TCP都可以保证一个报文一定能够到达接收端
    • 消息时没有边界的,多大都可以传输。消息时有序的
阅读全文 »

HTTP(应用层)

  • 超文本传输协议, 超文本包括文本、图片、视频、音频、压缩包等数据,基于请求/响应模型

报文格式

image

  • 请求行/状态行
    • 方法 URL 版本
    • 版本 状态 短语
  • 请求头/消息头
  • 消息体
阅读全文 »

优化原理

逻辑架构

image

  • 客户端层
  • 核心服务层,包括查询解析、分析、优化、缓存、内置函数、存储过程、试图、触发器等
  • 存储引擎,负责数据存储和提取

查询过程

image

  • 1.客户端向MySQL发送sql查询请求
    半双工通信
  • 2.服务器先检查查询缓存,如果命中则立即返回
    MySQL将缓存存放于一个应用表上(HashMap结构),因此两次查询的字符不同也会导致缓存没有命中,同时查询中包含自定义函数、存储过函数等都不会命中缓存
    查询缓存系统会更重查询中涉及的每个表,如果这些表发生任务变化,跟这个表相关的缓存都会失效,因此会带来性能的损耗
  • 3.服务器进行SQL解析,预处理、再由优化器生成执行计划
    • MySQL通过关键字进行语句解析,并生成对应的解析树
    • 预处理则是根据规则进一步检查解析树是否合法,如数据表或列是否存在
    • MySQL会由优化器生成执行计划,并选择一个成本最小的执行。一条查询可以有多种执行方式,优化器的作用就是找到最好的执行计划
  • 4.根据执行计划,调用存储引擎的API进行查询
    查询执行引擎根据执行计划逐步执行,通过调用存储引擎的接口完成
  • 5.将结果返回客户端并缓存
    缓存的前提是查询缓存被打开,结果集的返回是一个增量的过程。有可能MySQL在生成第一条结果时就返回给客户端,这样服务器就不用存储过多的数据消耗内存

Buffer Pool

什么是Buffer Pool

MySQL以Page页为单位,默认大小16K,会在Buffer Pool中划分出很多的缓存页,并用描述数据(元数据)记录缓存页所在的表空间 数据页编号、Buffer Pool地址等信息,底层采用链表数据结构管理Page

上图描述了Buffer Pool在innoDB中的位置,通过它所在的位置我们可以大概知道它的工作流程:

所有的更新和读取都是在Buffer Pool中进行。并由异步线程不断刷盘。查询数据时通过hash表快速定位到对应的缓存页

  • innodb 读操作,先从buffer_pool中查看数据的数据页是否存在,如果不存在,则将page从磁盘读取到buffer pool中。
  • innodb 写操作,先把数据和日志写入 buffer pool 和 log buffer,再由后台线程以一定频率将 buffer 中的内容刷到磁盘,「这个刷盘机制叫做Checkpoint」
阅读全文 »

全局锁(数据库只读)

  • FTWRL
    • 执行:
      flush tables with read lock
      执行后数据库处于只读状态,对数据的增删改查操作(select、insert、update、delete)以及对表结构的更改操作(alter table、drop table)都会被阻塞​
    • 执行:
      unlock tables
      释放全局锁,或者断开会话自动释放全局锁​
    • 主要应用于做全库逻辑备份,保证备份文件不会因备份期间数据库的更改而与预期不一致。
      数据量大的时候会导致业务受影响,因为数据库处于只读状态。因此可以利用MVCC的机制,在备份前开启事务,生成Read View进行保证可重复读,这样备份期间仍然可以对数据库进行增删操作,前提是数据库存储引擎支持事务(数据库只读,MVCC)

表级锁

表锁

语句 锁类别 用途
lock tables t read 表锁,读锁,共享锁 表共享锁之间不互斥,读读可以并行
lock tables t write 表锁,写锁,排他锁 表排他锁与任何锁都互斥,读写/写写都不可并行
  • 表锁除会限制别的线程读写外,也会限制当前线程后续的读写操作。即对表 t 加了【共享表锁】。当前线程及其他线程的后续写操作会被阻塞直至锁被释放

元数据锁(MDL)

  • 对数据库表进行CRUD操作时会自动加MDL读锁 – 读锁
  • 对数据库表结构进行变更操作时会自动加MDL写锁 – 写锁
  • MDL在事务提交后才会释放。在事务未提交前执行数据库表操作可能会导致数据库线程爆满。
    如:线程A在执行selct操作时会自动持有MDL读锁,此时线程B执行数据库表结构变更,则需要获取MDL 写锁,但由于事务未提交,读锁未释放,线程C获取写锁会被阻塞,进入队列等待。队列中【写锁获取优先级大于读锁】,一旦出现写锁等待,会阻塞后续的读锁获取,及阻塞其他的CURD操作线程

意向锁(InnoDB)

  • 意向锁是表级锁,不会和行级锁发生冲突,并且意向锁之间也不会发生冲突。
    只会和共享表锁、独占表锁发生冲突

  • 普通的select操作利用MVCC实现一致性读,是【无锁】的

    加锁方式 规则 锁类别
    select … lock in shard mode 先对表加上【意向共享锁】,再对读取的记录加上【排它锁】 意向锁,共享锁(S),排他锁
    select … for update 先对表加上【意向排他锁】,再对读取的记录加【排它锁】 意向锁,排他锁(X)
  • 执行插入、更新、删除操作前,需要先对表加上【意向共享锁】,再对记录加【排它锁】

  • 表锁和行锁之间满足【读读共享】、【读写互斥】、【写写互斥】
    如果没有【意向锁】,那么加【排他表锁】时需要遍历表里的所有记录,查看是否有记录存在【排它锁】,效率会很慢。
    有了【意向锁】之后,由于在对记录加排他锁之前,先会加上表级别的【意向排它锁】,那么在对记录加【排他锁时】,直接查看该表是否存在【意向排他锁】即可

    锁类型用途
    意向排他锁(IX)一个事务想给一个数据行加排他锁之前,必须先获得该表的IX锁
    意向共享锁(IS)一个事务给一个数据行加共享锁之前,必须先获得该表的IS锁
    当另外事务想给该表加表锁(S锁 或 X锁)时,只需查看该表上的IS锁和IX锁的加锁情况即可,不用再做遍历行锁的行为

AUTO-INC锁

  • 字段被声明为AUTO_INCREATMENT时,数据库会自动给该字段赋递增的值,通过AUTO-INC锁实现的

  • 在插入数据时,会加上AUTO-INC锁,插入语句执行完成后会释放。事务持有该锁的过程,其他事务的插入将会被阻塞排它锁

    • 大量数据插入时会影响性能。

    • MySQL 5.1.22版本后InnoDB提供了【轻量级】的锁实现自增

    • innodb_autoinc_lock_mode 变量控制选择AUTO-INC还是轻量级锁

      • 采用轻量级锁时,性能高但在并发插入时,自增长的值可能不是连续的,在主从复制的场景是【不安全】的
      等级锁类型
      innodb_autoinc_lock_mode = 0选用AUTO-INC锁
      innodb_autoinc_lock_mode = 2选用轻量级锁
      innodb_autoinc_lock_mode = 1(默认值)时混用两种锁

行级锁

Record Lock(记录锁)

  • 仅仅锁住索引记录的一行,也叫行锁;
  • 锁住的永远是索引记录而非记录本身。
  • 行记录锁是作用在索引记录(Key)上的锁。(B+树上的Key节点)

Gap Lock(间隙锁,前开后开)

锁加在不存在的空闲空间,可以是两个索引记录之间,也可能是第一个索引记录之前或最后一个索引之后的空间(可重复读级别下才会有间隙锁)

当我们用范围条件而不是相等条件索引数据,并请求共享或排他锁时,InnoDB会给符合条件的已有数据记录的索引项加锁;对于键值在条件范围内但并不存在的记录,叫做“间隙(GAP)”。

InnoDB也会对这个“间隙”枷锁,这种锁机制就是所谓的间隙锁(Next-Key锁)

间隙锁定之间不存在冲突关系如果一个事务对某个间隙中间加了锁,那么其他事务也可以在这个间隙中加锁,这些操作不冲突。它的存在,仅仅是为了防止其他事务在这个间隙中插入记录。

【前开后开】区间

  • Insert Intention Lock(插入意向锁)
    • 多个事务,在同一个索引,同一个范围区间插入记录时,如果插入的位置不冲突,不会阻塞彼此。
      • 插入意向锁 与 间隙锁/临键锁 是会冲突的,并发了会互相阻塞。
    • 不加插入意向锁,会 破坏间隙锁保护数据的隔离性。因为检测不到插入动作的冲突

Next-Key Lock(前开后闭)

  • 它是对记录【加锁的基本单位】,更新非唯一索引对应的记录(重点),会加上Next-Key Lock,同时锁住记录本身,以及数据相邻上游范围和相邻下游范围
    由【记录锁】和【间隙锁】组合而成

  • next-key lock 【前开后闭】区间

  • 某些场景下会退化成为【记录锁】或【间隙锁】

    场景状态
    唯一索引等值查询记录存在,会退化成为【记录锁】(记录锁,前开后闭区间)
    记录不存在,会退化成为【间隙锁】
    唯一索引范围查询会退化为加【记录锁】或【间隙锁】,也可能同时加两个锁
    非唯一索引等值查询记录存在时会加上next-key lock以及【间隙锁】
    记录不存在时,会加上多个【间隙锁】
    非唯一索引范围查询不会退化,只会加【next-key lock】
  • sql_safe_updates安全模式

    • 当变更表数据未添加Where条件时,会对所有记录加锁(多个Record锁+Gap锁,形成类似表锁的结构)

    • 即使加Where条件,若优化器最终选择全表,则仍全表加锁

    • 开启方法:sql_safe_updates=1

      • Update语句必须满足如下条件之一才能执行成功

        • 使用where子句,并且where子句中列必须为prefix索引列

        • 使用limit

        • 同时使用where子句和limit(此时where子句中列可以不是索引列)

      • Delete语句必须满足如下条件之一才能执行成功

        • 使用where子句,并且where子句中列必须为prefix索引列
        • 同时使用where子句和limit(此时where子句中列可以不是索引列)

锁与事务关系

锁操作锁处理
加锁在事务中,随着执行的SQL,按需获取锁。
过程中可能会有阻塞等待或死锁
释放锁事务提交时,自动释放本事务中所有的锁

死锁

概念

死锁的发生:多个事务,每个事务都已持有部分锁,然后进一步去获取对方事务持有的锁,互相等待。

死锁检测和处理

参数 作用
innodb_lock_wait_timeout 设置锁超时时间,默认50秒
innodb_deadlock_detect 开启死锁检测,在检测到死锁时回滚两条中的某一个事务(默认值on)

正常情况下采用第二种策略。主动死锁检测在发生死锁的时候,是能够快速发现并进行处理的。

如何减少死锁

  • 业务研发上,一般以乐观锁为主。

  • SQL尽量用索引,因为走索引才能用上行锁,更细粒度的锁,减少锁冲突的概率。

  • 减少大事务,用于减少持有锁的时间,进而降低冲突。

来源:

https://dev.mysql.com/doc/refman/5.6/en/innodb-locking.html#innodb-intention-locks

https://cloud.tencent.com/developer/article/1806998

日志

  • 主要日志
    • 二进制日志
    • 重做日志
    • 撤销日志
  • 其他日志
    • 错误日志
    • 查询日志
    • 中继日志
阅读全文 »

事务

事务(Transaction)是访问和更新数据的执行单元。事务中包含有个或者多个sql语句,要么都执行,要么都不执行。

  • 开启事务【开始记录一个事情中的多个任务】
  • 执行事务【正常情况下,一条语句就是一个任务】
  • 提交事务【成功】| 回滚事务【失败】

事务的作用:保证数据的最终一致性

阅读全文 »

MVCC

MVCC (Multiversion Concurrency Control),多版本并发控制,是Innodb实现事务回滚与并发的重要功能

目的:解决不可重复读,用于支持读已提交(RC)和可重复读(RR)隔离级别的实现

数据库的几种并发场景

场景 是否存在问题
读读 不存在数据安全问题
写写 有数据安全问题,更新丢失
读写 有线程安全问题,脏读、幻读、不可重复读(MVCC就是为了解决这种问题而存在的)

如果是RC隔离级别,那么每次在进行快照读的时候都会生成一个新的readview

如果是RR隔离级别,那么只有在当前事务第一次进行快照读的时候会生成readview,之后的快照读都会沿用当前的readview

RC和RR之间的区别就在于生成readview的时机不同

  • MVCC主要是用来解决【读-写】冲突的无锁并发控制,可以解决以下问题:

    • 在并发读写数据时,可以做到在读操作时不用阻塞写操作,写操作不用阻塞读操作,提高数据库并发读写的性能
    • 可以解决脏读,幻读,不可重复读等事务隔离问题,但不能解决【写-写】引起的更新丢失问题
  • MVCC与锁的组合

    一般数据库中都会采用以上MVCC与锁的两种组合来解决并发场景的问题,以此最大限度的提高数据库性能

    • MVCC + 悲观锁MVCC解决读-写冲突,悲观锁解决写-写冲突。
    • MVCC + 乐观锁MVCC解决读-写冲突,乐观锁解决写-写冲突。

通过上述描述,MVCC的作用可以概括为就是为了解决【读写冲突】,提高数据库性能的,而MVCC的实现又依赖【隐式字段】【undo日志】【版本链】【快照读和当前读】【读视图】。

阅读全文 »