咱们应该接触过或者据说过数据库的性能瓶颈问题。对于一个单机应用而言,提高数据库性能的最快路径就是氪金 - 买更高性能的数据库服务器,只要钱到位,性能不是问题。git
可是当系统性能增长到必定地步时,你会发现,原先花 3000 块提高了 50% 的性能,如今花 30000 块,才提高了不到 10%。程序员
也就是说,咱们花了钱,但没有获得等价的性能提高,这个时候,咱们就要考虑数据库的可扩展性了。github
要讨论 MySQL 的可扩展性,就要先明确可扩展性的定义。在此以前,咱们先抛开 MySQL,专一于扩展性,搞清楚什么是扩展性,才能更有针对性的去提高数据库的扩展性。数据库
咱们经常把“可扩展性”、“高可用性”以及“性能”用做同义词,但事实上它们是彻底不一样的。简单来讲,性能是响应时间,可用性是宕机时间,而扩展性代表了当须要增长资源以执行更多工做时,系统可以得到等价的性能提高的能力。换种说法,可扩展性就是咱们可以尽量的花费相同的资源提高等价的性能。而缺少扩展能力的系统在达到收益递减的转折点后,将没法进一步增加。安全
容量是一个和可扩展性相关的概念。系统容量表示在必定时间内可以完成的工做量。服务器
容量和可扩展性并不依赖于性能。以高速公路上的汽车来类比的话:并发
在上面这个类比中,可扩展性依赖多个条件:换道设计是否合理、路上有多少车抛锚或发生事故、汽车行驶速度不一样以及是否频繁变换车道。但通常来讲,和汽车的引擎是否强大无关。性能
这并非说性能不重要,性能确实重要,只是要注意的是,即便系统性能不是很高的系统也能够具有可扩展性。优化
从较高层次看,可扩展性就是可以经过增长资源来提高容量的能力。网站
对于容量,咱们能够简单的认为是处理负载的能力,而从不一样的角度考虑负载对咱们优化扩展性颇有帮助。
数据量
应用所能累计的数据量是可扩展性最广泛的挑战,特别是对于如今的互联网应用而言,由于从不删除数据。
用户量
首先,即便每一个用户只有少许的数据,但在累计到必定数量的用户后,数据量也会开始不成比例的增加,且速度快过用户数增加。其次,更多的用户意味着要处理更多的事务,而且事务数可能和用户数不成比例。最后,大量用户也意味着更多复杂的查询。
用户活跃度
不是全部的用户活跃度都相同,而且用户活跃度也不老是不变的。若是用户忽然变得活跃,例如 github 给小团队免费开放了私有化仓库,那么其对应的负载可能会明显提高。要注意的是,用户活跃度不只仅指页面浏览数(PV),即便一样的 PV,若是网站的某个须要执行大量查询工做的功能变得更受欢迎,也可能致使更多的工做。
相关数据集的大小
若是用户间存在关系,应用可能须要在整个相关联用户群体上执行查询和计算,这比处理一个个的用户和用户数据要复杂的多。
说了这么多,只是为了让咱们更好的理解可扩展性的让咱们用下面图表来更明确的表达可扩展性。
假设有一个只有一台服务器的系统,而且可以测量它的最大容量,如图 1 所示:
假设咱们如今增长一台服务器,系统的能力加倍,如图 2 所示:
图 1-2 就是线性扩展。咱们增长了一倍的服务器,增长了一倍的容量。然而,理想是美好的,现实是骨感的。大部分系统并非线性扩展的,而是如图 1-3 所示的扩展方式:
大部分系统都只能以比线性扩展略低的扩展系数进行扩展。这就致使,多数系统最终会达到一个最大吞吐量临界点,超过这个点后增长投入可能反而会下降系统的吞吐量。
到这一步,你们对扩展性应该已经有一个较为清晰的概念了。在此基础上,让咱们再深刻一步:Amdahl 扩展 和 USL 扩展。
简而言之,USL 说的是线下扩展的误差可经过两个因素来创建模型:
在对第一个因素继续建模后,就有了著名的(听过这个著名吗?)阿姆达尔定律(Amdahl)。第一个因素最终会致使吞吐量趋于平缓。若是部分任务没法并行,那么无论你若是分而治之,该任务至少须要串行部分的时间。这句话很重要,让咱们用一个栗子再简单阐述下: 假设你们都作过韭菜煎蛋这道菜,咱们作这道菜时,有几个必要步骤:
就上面 3 个步骤而言,你能够在切韭菜的时候,让你女票帮你打蛋液,也就是说 一、2 是能够并行的,可是咱们能边切菜边煎吗?或者边打蛋液边煎吗?显示是不行的。所以,步骤 3 和 一、2 是串行的。
这时候,咱们就会发现,作韭菜煎蛋这个任务须要的时间 t 为:
t = MAX(t1, t2) + t3;
对第二个因素,须要交互的工做而言,交互就意味着内部节点间或者进程间的通讯。这种通讯的代价取决于通讯信道的数量,而信道的数量将按照系统内工做者数量的二次方增加,因此最终开销比带来的收益增加的更快,这就是产生扩展性倒退的缘由。由此和 Amdahl 定律,就得出了 USL。
图 4 阐明了目前讨论的三个概念:线性扩展、Amdahl 扩展以及 USL 扩展。而大多数真实系统看起来更像 USL 曲线。
至此,关于扩展性的概念描述告一段落。接下来,咱们回到正题,看看 MySQL 的扩展性如何规划。
什么状况下须要扩展?,这是个值得咱们牢记的问题。当咱们提到系统的可扩展性时,通常只有两种状况:
上述两种状况,大多数状况下咱们碰到的应该都是后者。具体表现为:
若是是可扩展的应用,能够简单地增长更多的服务器来分担负载。但若是是可扩展性比较差的,你就会发现 - 只剩下提升可扩展性这一条路可走。
只有一条路,那就且行且 996 吧!
走上了提高扩展性这条路,接下来的问题就是,如何提升可扩展性?这里比较困难的部分是**估算应用承担的负载到底有多少?**这个值不必定很是精确,但必须在必定的数量级范围内。什么?你问为何要在必定范围内?不清楚敌人的火力,我们是准备用高射炮打蚊子仍是用大刀对机枪呢?
除此以外,为了能帮助咱们更好的规划可扩展性,我们最好还能想清楚下面这个问题:
程序员们理想的开发环境应该是:计划先行、有足够可以一块儿战斗的同伴、有花不完的预算等等。但现实是:
正常状况下,提高系统的扩展性的难度可能要比重构的难度还要大。所以,在你没有彻底把系统摸熟悉,或对扩展性还模糊的时候,千万别给老板说要提高系统的扩展性。
在老板要求提高性能时,你要想尽一切办法知足他提高性能的需求,同时,要多想下如何提升系统的扩展性,为未来提高扩展性赢得时间。
能够经过如下工做先提高系统性能: