七、MySQL高级性能
7.1 分区表
MySQL在创建表时使用PARTITION BY 子句定义每个分区存放的数据
分区的一个主要目的是将数据按照一个较粗的力度分在不同的表中。这样做可以将相关的数据存放在一起
1)分区表的原理
SELECT 查询:当查询一个分区表的时候,分区层先打开并锁住所有的底层表,优化器先判断是否可以过滤部分分区,然后再调用对应的存储引擎接口访问各个分区的数据
INSERT操作:当写入一条记录时,分区层先打开并锁住所有的底层表,然后确定哪个分区接收这条记录,再将记录写入对应底层表
DELETE操作:当删除一条记录时,分区层先打开并锁住所有的底层表,然后确定数据对应的分区,最后对相应底层表进行删除操作
UPDATE操作:当更新一条记录时,分区层先打开并锁住所有的底层表,MySQL先确定需要更新的记录在哪个分区,然后取出数据并更新,再判断更新后的数据应该放在哪个分区,最后对底层表进行写入操作,并对原数据所在的底层表进行删除操作。
2)分区表的类型
根据范围进行分区,PARTITION分区子句中可以使用各种函数。但有一个要求,表达式返回的值要是一个确定的整数,且不能是一个常数,比如 YEAR() 或 TO_DAYS(),根据时间间隔进行分区。
MySQL还支持键值、哈希和列表分区
3)如何使用分区表
为了保证大数据量的可扩展性,一般有两个策略:
- 全量扫描数据,不要任何索引
- 索引数据,并分离热点
4)什么情况下会出问题
上面介绍的两个分区策略都基于两个非常重要的假设:查询都能够过滤(prunning)掉很多额外的分区、分区本身并不会带来很多额外的代价。
下面介绍一些可能会遇到的问题:
- NULL 值会使分区过滤无效;第一个分区是一个特殊的分区。假设按照 partition by range year(order_date) 分区,那么所有 order_date 为 NULL 或者是一个非法值的时候,记录都会被存到第一个分区
- 分区列和索引列不匹配:如果定义的索引列和分区列不匹配,会导致查询无法进行分区过滤
- 选择分区的成本可能很高
- 打开并锁住所有底层表的成本可能很高
- 维护分区的成本可能很高
如上所述,分区表不是什么 "银弹"。下面是目前分区实现中的一些其他限制:
- 所有分区都必须使用相同的存储引擎
- 分区函数中可以使用的函数和表达式也有一些限制
- 某些存储引擎不支持分区
5)查询优化
对于访问分区表来说,很重要的一点就是要在WHERE条件中带入分区列,有时候即使看似多余的也要带上,这样就可以让优化器能够过滤掉无需访问的分区
MySQL只能在使用分区函数的列本身进行比较时才能过滤分区,而不能根据表达式的值去过滤分区,即使这个表达式就是分区函数也不行。
八、优化服务器设置
创建一个好配置的最快方法不是从学习配置项开始。最好是从理解MySQL内核和行为开始。然后可以利用这些知识来指导配置MySQL。最后,可以将想要的配置和当前配置进行比较,然后纠正重要并且有价值的不同之处。
服务器的配置应符合它的工作负载、数据,以及应用需求,并不仅仅看硬件的情况。
MySQL有大量可以修改的参数-但不应该随便去修改。通常只需要把基本的项配置正确(大部分情况下只有很少一些参数是真正重要的),应该将更多的时间花在schema的优化、索引,以及查询设计上。在正确地配置了MySQL的基本配置项之后,再花力气去修改其他配置项的收益通常就比较小了。
另一个节省时间和避免麻烦的好办法是使用默认配置,除非是明确地知道默认值会有问题。很多人都是在默认配置下运行的。
8.1 MySQL配置的工作原理
首先应该知道的是MySQL从哪里获得配置信息:命令行参数和配置文件。在类UNIX系统中,配置文件的位置一般在 /etc/my.cnf
或者 /etc/m,ysql/my.cnf
。
任何打算长期使用的设置都应该写到全局配置文件,而不是在命令行特别指定。否则,如果偶然在启动时忘了设置就会有风险。把所有的配置文件放在同一个地方以方便检查也是个好方法。
一定要清楚地知道服务器配置文件的位置。
3)入门
应该始终通过监控来确认生产环境中变量的修改
把配置文件置于版本控制之下
8.2 什么不该做
首先,不要根据一些 "比率" 来调优。一个经典的按 "比率" 调优的经验法则是:键缓存的命中率应该高于某个百分比,如果命中率过低,则应该增加缓存的大小。这是非常错误的意见。
我们还建议避免调(tuning)这个词,我们更喜欢用"配置(configuration)" 或 "优化(optimize)" 来代替。"调优" 这个词,容易让人联想到一个缺乏纪律的新手对服务器进行微调,并观察发生了什么。
另外说一句,在互联网搜索如何配置并不总是一个好主意。可信的、声誉好的MySQL服务商一般比简单的互联网搜索更安全。
最后,不要相信很流行的内存消耗公式。
九、操作系统和硬件优化
MySQL服务器性能受制于整个系统最薄弱的环节,承载它的操作系统和硬件往往是限制因素。
9.1 什么限制了MySQL的性能
最常见的两个瓶颈是CPU和 I/O 资源。当数据可以放在内存中或者可以从磁盘中以足够快的速度读取时,CPU可能出现瓶颈。把大量的数据集完全放到大容量的内存在,以现在的硬件条件完全是可行的。
另一方面,I/O瓶颈,一般发生在工作所需的数据远远超过有效内存容量的时候。如果应用程序是分布在网络上,或者如果有大量的查询和低延迟的要求,瓶颈可以转移到网络上,而不再是磁盘 I/O。
十、复制
MySQL内建的复制功能是构建基于MySQL的大规模、高性能应用的基础,这类应用使用所谓的 "水平扩展" 的架构。我们可以通过为服务器配置一个或多个备库的方式来进行数据同步。复制功能不仅有利于构建高性能的应用,同时也是高可用性、可扩展性、灾难恢复、备份以及数据仓库等工作的基础。事实上,可扩展性和高可用性通常是相关联的话题。
10.1 复制概述
复制解决的基本问题是让一台服务器的数据与其他服务器保持同步。一台主库的数据可以同步到多台备库上,备库本身也可以被配置成另外一台服务器的主库。主库和备库之间可以有多重不同的组合方式。
MySQL支持两种复制方式:基于行的复制和基于语句的复制。这两种方式都是通过在主库记录二进制日志,在备库重放日志的方式来实现异步的数据复制。这意味着,在同一时间点备库上的数据可能与主库存在不一致,并且无法保证主备之间的延迟。
复制通常不会增加主库的开下,主要是启用二进制日志带来的开销。
2)复制如何工作
- 在主库上把数据更改记录到二进制日志(Bin Log)中
- 备库将主库上的日志复制到自己的中继(Relay Log)日志中
- 备库读取中继日志中的事件,将其重放到备库数据之上
10.2 配置复制
- 在每台服务器上创建复制账号
- 配置主库和备库
- 通知备库连接到主库并从主库复制数据
10.3 复制的原理
1)基于语句的复制
:主库会记录那些造成数据更改的查询,当备库读取并重放这些事件时,实际上只是把主库上执行过的SQL再执行一遍
好处:实现相当简单
缺陷:主库上的数据更新除了执行的语句外,可能还依赖于其他因素;更新必须是串行的,这需要更多的锁;不是所有的存储引擎都支持这种复制模式
2)基于行的复制
好处:可以正确地复制每一行,一些语句可以被更加有效地复制
和缺点:update table_name set isdel=0;
会把每一行的数据都记录到二进制日志中
10.4 复制拓扑
10.5 复制和容量规划
10.6 复制管理和维护
10.7 复制的问题和解决问题
10.8 复制有多快
10.9 MySQL复制的高级特性
10.10 其他复制技术
10.11 总结
十一、可扩展的MySQL
11.1 什么是可扩展性
性能定义为响应时间
可扩展性表明了当需要增加资源以执行更多工作时系统能够获得划算的等同提升的能力。
容量是一个和可扩展性相关的概念。系统容量表示在一定时间内能够完成的工作量,但容量必须是可以有效利用的。
我们将系统的真实容量定义为在保证可接受的性能的情况下能够达到的吞吐量。
容量和可扩展性并不依赖于性能。以高速公路上的汽车来类比的话:
- 性能是汽车的时速
- 容量是车道数乘以最大安全时速
- 可扩展性就是在不减慢交通的情况下,能增加更多车和车道的程度
在这个类比中,可扩展性依赖于多个条件:换道设计是否合理、路上有多少车抛锚或者发生事故,汽车行驶速度是否不同或者是否频繁变换车道-但一般来说和汽车的引擎是否强大无关。这并不是说性能不重要,性能确实重要,只是需要指出,即使系统性能不是很高也可以具备可扩展性。
从较高层次看,可扩展性就是能够通过增加资源来提升容量的能力。从有利的角度来看,容量可以简单地认为是处理负载的能力。
-
数据量:应用所能累计的数据量
-
用户量
-
用户活跃度
-
相关数据集的大小:如果用户存在关系,应用可能需要在整个相关联用户群体上执行查询和计算
通用可扩展性定律(USL)
线性扩展的偏差可通过两个因素来建立模型:无法并发执行的一部分工作,以及需要交互的另外一部分工作。
第一个因素建模就有了著名的 Amdahl 定律,它会导致吞吐量趋于平缓。
增加第二个因素-内部节点或者进程间的通信-到 Amdahl 定律就得出了 USL。这种通信的代价取决于通信信道的数量,而信道的数量将按照系统内工作者数量的二次方增长。因此最终开销比带来的收益增长得更快,这是产生扩展性倒退的原因。
它也揭示了一个构件高可扩展性系统的重要原则:在系统内尽量避免串行化和交互
11.2 扩展MySQL
垂直扩展 / 向上扩展:增加服务器
水平扩展 / 向下扩展:将任务分配到多台计算机
1)规划可扩展性
人们通常只有在无法满足增加的负载时才会考虑到可扩展性,具体表现为工作负载从CPU密集型变成I/O密集型,并发查询的竞争,以及不断增大的延迟。
主要原因是查询的复杂度增加或者内存中驻留着一部分不再使用的数据或者索引
2)为扩展赢得时间
优化性能:很多时候可以通过一个简单的改动来获得明显的性能提升
购买性能更好的硬件
4)向外扩展
可以把向外扩展(有时也称为横向扩展或者水平扩展)策略划分为三个部分:复制、拆分,以及数据分片
按功能拆分
数据分片
选择分区键
生成全局唯一ID
5)向内扩展
处理不断增长的数据和负载最简单的办法是对不再需要的数据进行归档和清理
保持活跃数据独立
十二、高可用性
实际上意味着 "更少的宕机时间"
12.1 什么是高可用性
高可用性不是绝对的,只是相对更高的可用性
高可用性实际上是在宕机造成的损失与降低宕机时间所花费的成本之间取一个平衡
有时候人们将可用性定义成服务正在运行得时间段。我们认为可用性的定义海报框应用是否能以足够好的性能处理请求。
12.2 导致宕机的原因
- 运行环境:支持数据库服务器运行得系统和资源集合,包括操作系统、硬盘以及网络等
- 性能问题
- 复制
- 各种类型的数据丢失或损坏
- 其他
需要注意的地方:
- 在运行环境的问题中,最普遍的问题是磁盘空间耗尽
- 在性能问题中,最普遍的宕机原因确实是运行很糟糕的SQL,但也不一定都是这个原因,比如也有很多问题是由于服务器Bug或错误的行为导致的
- 糟糕的Schema和索引设计师第二大影响性能的问题
- 复制问题通常由于主备数据不一致导致
- 数据丢失问题通常由于DROP TABLE的误操作导致,并总是伴随着缺少可用备份的问题
12.3 如何实现高可用性
首先,尝试避免导致宕机的原因来减少宕机时间。许多问题其实很容易避免。
第二,尽量保证在发生宕机时能够快速恢复。最常见的策略是在系统中制造冗余,并且具备故障转移能力。
平均时效时间(MTBF)
平均恢复时间(MTTR)
我们发现对系统变更管理的缺失是所有导致宕机的事件中最普遍的原因。典型的错误包括粗心的升级导致升级失败并遭遇一些Bug,或者是尚未测试就将Schema或查询语句的更改直接运行到线上,或者没有为一些失败的情况制定计划,例如达到了磁盘容量限制。另外一个导致问题的主要原因是缺少严格的评估,例如因为疏忽没有确认备份是否可以恢复。最后,可能没有正确地监控MySQL的相关信息。
所有的宕机事件都是由多方面的失效联合在一起导致的。
故障转移是一个双向过程,当服务器A失效,服务器B代替它,在修复服务器A后可以再替换回来。
十三、云端的MySQL
本章关注的重点是:它们在最终经济上和性能特性上的关键区别是什么
云是一个部署平台,而不是一种架构,理解这一点很重要。架构会受平台的影响,但平台和架构明显不同。
13.1 云的优点、缺点和相关误解
优点
- 云是一种将基础设施外包出去无须自己管理的方法
- 即用即付
- 随着供应商发布新的服务器和成本降低,云提供的价值越来越大
- 更轻松地准备好服务器和其他资源
- 代表了对基础设施的另一种思考方式-作为通过API来定义和控制的资源,支持更多的自动化操作
缺点
- 资源是共享并且不可预测的
- 无法保证容量和可用性
- 虚拟的共享资源导致排查故障更加困难
误解
- 云天生具备更好的可扩展性
- 云可以自动改善甚至保证可用性
- 云是唯一能提供【这里填入任意的优点】的东西
- 云是一个 "银弹"
13.2 MySQL在云端的经济价值
适合处于初级阶段的企业
云的另一种潜在的大用途是运行不是很重要的基础设施,例如集成环境、开发测试平台以及评估环节
13.3 云中的MySQL的可扩展性和高可用性
总的来说,在云端中扩展MySQL和在其他地方扩展没有太多的差别
十四、应用层优化(略)
十五、备份与恢复
再开始本章之前,让我们先澄清几个概念。首先,经常可以听到几个所谓的热备份、暖备份和冷备份。人们经常使用这些词来表示一个备份的影响:例如,“热” 备份不需要任何的服务停机时间。问题是对这些术语的理解因人而异。我们尽量避开这些术语,而直接说明某个特别的技术或工具对服务器的影响。
另外两个让人困惑的词是还原和恢复。
还原意味着从备份文件中获取数据,可以加载这些文件到MySQL里,也可以将这些文件放置到MySQL期望的路径中。
恢复一般意味着当某些异常发生后对一个系统或其部分的拯救。包括从备份中还原数据,以及使服务器完全恢复功能的所有必要步骤,例如重启MySQL,改变配置和预热服务器的缓存等。
在很多人的概念中,恢复意味着恢复崩溃后损坏的表。这与恢复一个完整的服务器是不同的。
15.1 为什么要备份
灾难恢复
人们改变想法:不必惊讶,很多人经常会在删除某些数据后又想要恢复这些数据
审计:有时候需要知道数据或Schema在过去的某个时间点是什么样的
测试
15.2 定义恢复需求
规划备份和恢复策略时,有两个重要的需求可以帮助思考:恢复点木点(PRO)和恢复时间目标(RTO)。它们定义了可以容忍丢失多少数据,以及需要等待多久将数据恢复。在定义RPO和RTO时,先尝试回答下面几类问题:
- 在不导致严重后果的情况下,可以容忍丢失多少数据?需要故障恢复,还是可以接受自从上次日常备份后所有的工作全部丢失?是否有法律法规的要求?
- 恢复需要再多长时间内完成?哪种类型的宕机是可接受的?哪种影响(例如:部分服务不可用)是应用和用户可以接受的?当那些场景发生时,又该如何持续服务?
- 需要恢复什么?常见的需求是恢复珍格格服务器,单个数据库,单个表,或仅仅是特定的事务或语句
建议将上面这些问题的答案明确地用文档记录下来,同时还应该明确备份策略,以及备份过程。
备份误区:复制就是备份
15.3 设计MySQL备份方案
- 在生产实践中,对于大数据库来说,物理备份是必需的
- 保留多个备份集
- 定期从逻辑备份(或者物理备份)中抽取数据进行恢复测试
- 保存二进制日志以用于基于故障时间点的恢复
- 通过演练整个恢复过程来测试备份和恢复
- 对安全性要仔细考虑
在规划备份时,有一些与性能相关的因素需要考虑:
- 锁时间
- 备份时间
- 备份负载
- 恢复时间
3)备份什么
最简单的策略是只备份数据和表定义
- 非显著数据,比如二进制日志和InnoDB事务日志
- 代码,比如存储过程和触发器
- 复制配置
- 服务器配置
- 选定的操作系统文件
增量备份和差异备份
差异备份:对自上次全备份后所有改变的部分而做的备份
增量备份:自从任意类型的上次备份后所有修改做的备份
15.6 从备份中恢复
如何恢复数据取决于是怎么备份的。可能需要以下部分或全部步骤。
- 停止MySQL服务器
- 记录服务器的配置和文件权限
- 将数据从备份中到MySQL数据目录
- 改变配置
- 改变文件权限
- 以限制访问模式重启服务器,等待完成启动
- 载入逻辑备份文件
- 检查和重放二进制日志
- 检测已经还原的数据
- 以完全权限重启服务器
15.9 总结
每个人都知道需要备份,但并不是每个人都意识到需要的是可恢复的备份。我们建议明确并记录恢复点目标和恢复时间目标,并且在选择备份系统时将其作为参考。
在日常基础上做恢复测试以确保备份可以正常工作也很重要。很多时候不会意识到数据随着时间已经增长到可能需要几天或几周才能再次导入的地步。
不要掉进备库就是备份的陷阱