序言
在构建系统时,我们都离不开对数据的存储和获取,而对于数据库的应用和设计应当是每个后端开放人员、架构师、DBA等等人员都需要去深入学习理解的基础知识(特别是构建数据密集型应用),最近在看 高性能 MySQL 第三版和MySQL 技术内幕,所以写一下笔记梳理一下知识,这两本书都比较偏上层,底层知识涉及并不太多,想了解更加底层的人推荐阅读一下数据库系统实现 (第 2 版)和数据库系统概念等书籍。
MySQL简介
MySQL是一个单进程多线程支持并发处理的关系型数据库(不支持并行),并且支持跨平台,可移植,在各平台底层实现各有不同的情况下,基本上能够保证各平台上的物理体系结构的一致性,其灵活性、开源、高性能、跨平台等特点深受企业和开发人员的喜爱。
MySQL数据库实例在系统上表现为一个进程,实例启动时,按照/etc/my.cnf -> /etc/mysql/my.cnf -> /usr/local/mysql/etc/my.cnf -> /root/my.cnf等顺序读取默认配置的参数来启动数据库实例,配置文件以最后一个中的参数为准。
数据库和实例:两个词有着不同的定义
- 数据库:物理操作系统文件和其他类型文件的 集合,文件可以是存放于内存之中的文件也可以是磁盘之中的
- 实例:MySQL数据库由后台线程和一个共享内存区域组成
数据库是文件的集合,数据库实例是处理用户请求并执行对应操作的一个程序,数据库实例才是真正用于操作数据库文件的。
MySQL实例逻辑架构
MySQL实例的逻辑架构大致分为3层:
第一层:里面的东西并不是MySQL所独有的,大多数基于网络的客服端/服务端的工具都有类似的架构
- 图中的1:客户端连接者们,如Linux中MySQL操作终端,java中的jdbc等等
- 2 :连接池组件处理各个连接,授权认证,安全等等
- 3 : 管理服务和工具服务
第二层:核心层,包括解析、分析、优化、换成、以及所有的内置函数,所有跨存储引擎的功能都在这一次实现:存储过程、触发器、视图等等
- SQL接口组件
- 5:查询分析器组件
- 6:优化器组件(执行计划生成,索引选择)
- 7:缓存组件
第三层:插拔式存储引擎和文件系统:
- 8:插拔式存储引擎
- 9:物理文件
注:以上模块归属那一层是大概分的,可能存在不准确情况
连接MySQL
连接MySQL是一个客户端连接进程和MySQL实例进行通信的建立,MySQL不论在哪一种平台都提供了TCP/IP套接字的连接方式,当通过TCP/IP连接到实例时,MySQL会首先去判断该用户是否存在,密码是否正确,然后检查一张权限视图,是否有权限执行某些特定的操作等等。
每个客户端连接都会在MySQL实例进程中拥有一个线程,这个连接的查询都会在这个单独的线程中执行,实例会缓存这个线程,所以不需要为每一个新建的连接创建和销毁线程,但是MySQL默认如果客户端连接线程如果连续8小时都没对实例进行任何的操作会自动的销毁掉这个线程,关闭这个 长连接,等再次请求时则会抛出Lost connection to MySQL server during query。异常
使用线程池
MySQL5.5以上允许线程池插件,可以使用池中少量的线程来服务大量的连接,
在面对有限的昂贵连接资源时,频繁的打开物理连接后就关闭,造成系统性能低下时,我们可以使用线程来避免,线程池是一个在程序启动时就建立足够的数据库连接,由一个池来管理这些连接的线程,当有请求时则从池中直接获取连接去操作数据库,执行完成后将连接重新放回连接池来达到连接的重用,避免消耗内存资源,并且当请求流量突增时或减少时,可以动态增加或减少池中的连接数,并拥有监控或者诊断等等功能
因为第一代连接池一般采用单线程同步的架构设计(例如 DBCP…),所以我们可以选择第二代采用了多线程模型的Druid,关于连接池包含了很多内容,在后续的章节再详细简介
MySQL的存储引擎
从逻辑架构图中我们可以看到MySQL中的存储引擎是插拔式的,即我们可以根据需求选择对应的存储引擎,其中可以分为MySQL官方的和第三方提供的
InnoDB 存储引擎
MySQL主推并且5.5.8之后默认和最常用的一款存储引擎,主要面向在线事务处理(OLTP Online transaction processing)的应用,支持行锁、外键、事务、并发版本控制、预读、二次写、插入缓冲、自适应哈希等等强大的功能,具备高可用、高性能、高拓展等特性,我们之后会都会围绕这个引擎来细讲这些内容
MyISAM 存储引擎
MyISAM 是MySQL 5.5.8之前默认的存储引擎,主要面向在线分析处理 (OLAP Online analytical processing)的应用,不支持事务、表所、支持全文索引、不支持崩溃后的安全恢复、缓冲池只缓存索引文件,不缓存数据文件、采用赫夫曼编码静态算法(利用不同的字符内容编码加出现的频率组合来生成带权霍夫曼二叉树节约内存空间,出现频率越高在树中的层级越低,前缀编码越短)来压缩数据等特性,MyISAM 设计简单,数据以紧密格式存储,所以在某些场景下的性能很好(例如:只读场景)
NDB存储引擎
NDB是一个集群存储引擎,分布式的、share-nothing的、容灾的、高可用的数据库组合,其连接操作是在MySQL数据库层完成的,因此复杂的连接操作需要巨大的网络开销,查询速度也会变得很慢
Memory 存储引擎
Memory 将表中的数据存放在内存中,所以重启时会导致数据丢失,适合用来存储临时数据的临时表和数据仓库的维度表,默认使用哈希索引,只支持表锁,所以并发性能不理想,存储变长字段时会按照定长字段的方式进行存储,因此也会浪费一定的内存,并且不支持BlOB和Text类型
Archive 存储引擎
Archive 是用来高速插入和压缩功能的,只支持insert和select操作,使用zlib算法将数据行进行压缩后再存储,可以达到1:10的压缩比例,适合拿来存储归档数据(日志信息和数据采集类),使用行锁来提高并发操作,但是本身不是事务安全的,所以会存在一定的数据不一致问题
Federated 存储引擎
Federated 是访问其他MySQL服务器的一个代理,会创建一个到远程MySQL服务器的客户端连接,并将查询传输到远程服务器执行,然后提取或者发送需要的数据,不支持异构数据库表
Maria 存储引擎
Maria 可以看作MyISAM的后续版本,支持缓存数据和所以文件,行锁设计,提供并发版本控制、支持事务和非事务等安全选项、更好的BlOB字符类型处理的功能
其他存储引擎
除了上面的7种还有许多存储引擎,包括第三方的,有OLTP类、OLAP类、面向列的、社区提供的种种存储引擎,这些存储引擎加起来的数量非常多
存储引擎的选择
MySQL官方手册提供了一些常用的存储引擎直接的不同之处的对比,包括存储容量的限制、事务支持、锁的粒度等等,见上图
大部分情况下,InnoDB都是正确的选择,除非需要用到某些InnoDB不具备的特性,并且没有其他的办法可以替代,否则都应该优先选择InnoDB引擎。除非万不得已,否则建议不要混合使用多种不同的存储引擎,可能会带来一系列的复杂的问题,以及一些潜在的bug和边界问题
选择不同的存储引擎是,应考虑的因素:
- 事务支持:需要则选择InnoDB,不需要且都是select和insert操作则采用MyISAM(日志型应用)
- 备份支持:需要在线热备份选择InnoDB是基本的要求
- 崩溃恢复:相对而言MyISAM崩溃后发生损坏的概率比InnoDB要高很多,而且恢复的速度也要慢
- 特有的特性:如果一个存储引擎拥有一些关键的特性,同时又缺乏一些必要的特性,那么有时候不得不做折中的考虑,或者在架构设计上做一些取舍
日志型应用
这一类有着高要求的插入速度,数据库不能成为瓶颈,MyISAM或者Archive存储引擎对这类应用比较合适,因为他们开销低,而且插入速度非常块
只读或者大部分情况都只读的表
典型的读多写少的业务,如果不介意MyISAM崩溃恢复的问题,选用MyISAM存储引擎是比较合适的,否则还是建议采用InnoDB,在很多场景下,InnoDb的速度都比MyISAM快,特别是使用聚集索引或者将需要的数据放到内存中的情况下
MyISAM随着应用压力的上升,可能会迅速的恶化,导致各种锁竞争、数据丢失、崩溃等问题
订单处理
需要选择有事务的存在引擎,并且可能需要支持外键,InnoDB是最合适的选择
大数据量
数据太大的话,则需要建立数据仓库,Infobright是MySQL数据仓库最成功的解决方案,如果不适合则可以使用TokuDB,或者采用InnoDB,不过就需要进行例如分库分表,数据分片等处理
小结
这里简单的解释了一些MySQL,通篇文章并没有讲关于底层的实现,都是大致的做个介绍,特别是MySQL核心层还有存储引擎层都忽略了,所以接下来都会用多个专题来总结这些原理,详细解释
参考内容
《高性能MySQL 第三版》
《MySQL 技术内幕》