开发者学堂课程【MySQL 实战进阶:MySQL 高并发场景实战】学习笔记,与课程紧密联系,让用户快速学习知识
课程地址:https://developer.aliyun.com/learning/course/83/detail/1306
MySQL 高并发场景实战
内容介绍
一.问题和挑战
二.系统调优
三.架构调优
四.实例调优
五.内核调优
六.监控报警
七.流程管理和生态工具
八.总结
一.问题和挑战
阿里巴巴 CEO 逍遥子说“双11是商业界的奥林匹克”
双11开始于2009年,如图,双11期间,订单创建数,支付笔数和交易总额几乎逐年翻倍。随着这些数据的增长,双11在提供给商业界大量机会的同时,对于后端的技术、架构等各个模块也是比较好的技术的沉淀。
1.洪峰般地并发
如图所示,在0点的高峰,无论是系统的访问量还是数据库的访问量呈现接近90度上升趋势,在如此大的访问流量下,所有的核心链路的增删改查都是在数据库上操作,对应用和数据库都有比较大的冲击,
比如,复杂事务、链接数、锁竞争、线程调度等各个模块。
如果有复杂 SQL 或大事务的活还可能导致系统资源耗尽,整个数据库服务不可用,进而导致大促受到影响,甚至失败。比如:下单失败、网页无法打开、无法支付等。此外此类场景也会发生在在线教育、直播电商、在线协同办公等。
2.热点行更新
在大促的时候会有热点商品的售卖,而这些商品在数据库中只是一行记录,当单线程去更新一行记录时,性能非常高,但是当非常多的线程去并发更新一行记录时,整个数据库的性能会跌到趋近于零。在数据库中,由行锁来控制并发,在有非常多的竞争时,行锁的竞争十分激烈,并发越高,数据库的性能跌得越明显。
3.突发 SQL 访问
当缓存穿透或异常调用、有数据倾斜 SQL 、未创建索引 SQL 等情况发生时,在高并发场景下很容易导致数据库压力过大,响应过慢,导致应用链接释放慢,导致整个系统出现雪崩效应。
4.智能化运维
双十一期间有很多的实例,这些实例的水位管控,机器水位管控,高风险实例优化,在流量高峰期从收到警报、识别问题等,如果用人肉观察,从接受到报警到识别问题、诊断问题、解决问题至少需要十多分钟,足以在高并发的场景下给整个运维带来比较大的挑战。此外,我们结合一五场景以及商品畅卖的问题,以及技术设施的挑战等。
二.系统调优
针对以上问题,我们做出系统调优
1.容量评估
经验评估:预估压力/单机性能=服务器数量;应用机器设置、数据库设置等。
根据服务器数量以及应用机器的数量可以得出整个数据库的链接池的设置以及要扩充多少个实例、扩充多少台机器等,这些相应的配置也会出来。
通过经验的预估,也是一个预估值,能否支撑双十一的容量还是一个未知数,所以我们需要针对上述的预估做一个判断、验证。我们是通过压测来完成的。因为现在是分布式的系统,容量评估后,我们需要针对单个实例、单个应用单元以及单个应用模块来进行压测,所以需要单元压测。
单元压测:
验证单元内容量;验证单个系统容量。单元压测主要是完成单元内的验证,因为现在整个的架构很多是异地多国,不仅要验证双十一内的容量,还要验证单元内的容量是否充足,以及单个系统的容量,比如压测某个模块、交易模块等,这个容量是否是充足的。每个应用模块验证完了之后,我们还需要对整个链路来进行压测,即全链路压测。
全链路压测:
场景化压测;解决分布式系统容量评估。它是基于仿真化的测试,是最接近业务的系统值的。借助全链路压测,我们可以验证整个分布式系统的容量是否是充足的。
2. 性能评测
压测目的:发现基础设施的瓶颈、中间件瓶颈、系统容量瓶颈;发现分布式系统短板。
压测用途:保障大促容量充足,保障业务正常运转;保障核心功能、保证用户体验;评估大促成本(人工成本、机器成本以及整个运维保障的成本)。在前几年,我们的 slogan (标语)是,让用户买物品的时候,如丝般顺滑。
难点:真实业务场景压测;真实 SQL 模拟。
无压测不调优,压测十分重要。压测可分为基准测试和仿真测试。
基准测试:对于 MySQL 来说,我们可以用 sysbench 或者 mysqlslap 等。在官网上也有基于通用场景的测试,每一个实例所能达到的容量。在不同的业务场景下,它所能达到的容量是不同的。基准测试的场景相对比较简单,通过基本测试,我们可以预估实例在基准测试的情况下,所能达到的容量的最大值、极限值。通常情况下,真实的业务场景不太可能会超过基准测试的值。针对每一个实例,它所能达到的瓶颈,我们要做到心中有数。
真实的业务场景往往比基准测试的场景要复杂得多。阿里在双十一的场景下是如何进行基准测试的,其整个过程可以分为四个步骤。
第一步:首先,针对基准涉及到的业务模块来进行梳理,相应的也会梳理技术架构的模块,以及我们的容量预估是否是充足的。
第二步:梳理完之后,我们就需要制造数据,准备服务器、压测流量、业务请求。
第三步:正式进入压测的阶段。通过压测,我们可以发现短板,验证我们的容量是否是充足的,验证预案,比如我们想验证,在某个压力场景下降级某个预案会给系统减少多少的压力,这就可以在压测的阶段来验证完成。
验证压测执行完之后,我们需要根据发现的短板压测问题,架构的问题来进行针对性的优化,这个过程需要很多轮的压测。
阿里巴巴集团及各 BU 每年压测4000+次。13年全链路发现700+问题,14年发现500+问题,15年发现400+问题。每一年都能发现几百个以前压测没有发现的问题,所以,全链路压测已经成为双十一必备阶段,是准备大促的核武器。
3.性能测评工具
PTS(Performance Testing Service)
是面向所有技术背景人员的云化测试工具,可以理解为全链路压测工具。它是基于业务端发起,梳理完业务压测模块之后,进行构件请求。可以结合自己的实际的业务场景来随时发起,免去繁琐的搭建和维护成本,进而发现线上业务的短板以及需要优化的模块,来保证大促顺利进行。此外,如果想要单独压测 DB 的性能瓶颈,因为基于真实的业务此工具模拟还是比较难的。
DAS可以充分利用在采集以往真实的业务数据来进行到另外一个实例上回放,这是基于真实的场景的回放·,可以指定压力来验证单个实例的数据库的容量,比如翻6倍、10这样,是否能支撑地住系统的压力,为即将到来的短期业务高峰来做一个短期的准备。在这种情况下,应用不需要配合,由 DBA 或者运维人员来完成对 DB 的容量的压力的评估。或者,在业务上新之前验证 ADS 的规格是否能满足业务的需求。所以, DAS 可以很好地帮助我们基于真实业务来完成线上容量的压测。
4.性能评测需要注意什么
参数: RDS 参数对齐。如果要对比一两个参数在打开和关闭之后,以及设置不同的值对性能的影响,可以单独地做测试。一旦测试出来最优值,在压测之前,最好将参数调到最优值,不要在压测出现问题之后调参数。
网络:从压测机到 RDS 的网络延迟。一般情况下,购买实例时候, DAS 和 RDS 是在同一个 VDC内的。但是不排除,有的用户用线下的机器来连接本地的数据库,用本地的应用机器来连接 RDS 来进行对比,这是不合适的,因为压测机的 RDS 网络延迟和到本地数据库的延迟差异很大。
规格:RDS 规格对齐;不同规格 RDS 的性能差别比较大,如果想要测试 CPU 的性能,物理 IO 要少,数据量要小于内存大小。但是,对于大多数业务场景来说,都是涉及到物理 IO 的,实际业务场景都不是全内存操作,即数据量大于内存大小。
ESC 的网络带宽:阿里云的 ESC 是限制带宽的,如果想 ESC 带宽不受限制,需要购买比较大的网络带宽。以往有用户在做测试时, RDS 的资源没有弄满,压力无法提高,后来经过定位发现 ECS 的带宽打满了。所以,在准备压测的环境的时候,要把这些内容整理好。
三.架构调优
如果业务的访问都用数据库来支撑的话,成本太高。
缓存可以代替一部分关系性数据库在读方面的请求。此外,基于原理的设计以及成本方面的考虑,缓存的性能优于关系性数据库,而且·性价比更高。如果读多写少,针对于单个实例很难支撑,还可以借助于只读实例,它可以实现在线弹性地扩展读能力,读的业务请求可以实现隔离,比如,可以把清量分析型的以及吞数据型的在只读实例内完成。此外,每一个只读实例都有一个单独的链接地址,如果想要把某一类的业务和其他业务区分开、严格的隔离,比如,想要让托数据这一类的场景或者是某一类的只读的场景,它指到某一个实例上面访问的话,就可以单独地链接那一个只读实例的链接串。如果想要从整个的层面来控制主实例和只读实例的访问,就可以借助于负载均衡多项代理来完成,多项代理可以缓解大量的短链接的场景,使用代理后,就不用反复地变更应用内的链接地址,减少维护成本。使用多项代理之后,可以实现线上资源的扩展、承受更高的流量。如果是 RDS 的实例规格以及只读实例都已经升到最大,但仍然不能支撑业务的发展,
可以通过考虑升级 RDS ,来完成读写容量的扩展。
对于只读实例,大部分人最关心的问题就是主实例和只读实例的数据一致性,比如延迟以及中断这一类的场景,延迟是最常见的。
1.怎样降低只读实例和主实例的延迟
l 主实例的 DDL
占40%,如 alter、drop 、修改表、回收表空间等,需要 kill DDL 语句或用 DMS 的无锁变更等。
l 主实例的大事务
占20%,如大批量导入、删除、更新数据,都会产生大量的 binlog ,根据以往的经验,一个 binlog 最多有几十个 G ,MySQL 的 binlog 是在主实例完成之后才传到只读实例上,因此会产生延迟,需要将大事务拆分成为小事务进行批量提交,这样只读节点就可以迅速的完成事务的执行,不会造成数据的延迟。
l 主实例写入压力过大
占20%,如主实例规格较小、压力过大。这种情况需要升级主实例和只读实例的规格。
l 只读节点规格过小
占10%,这种情况升级只读实例规格。
l 其他(无主键)
占10%, RDS 目前已经支持对表添加隐式主键,但是对于以前历史创建的表需要进行重建才能支持隐式主键。
2.怎样提升缓存命中率
在高并发的场景下,写入压力过大,如何才能提升缓存的命中率。根据以往的经验,有四种更新方式:
Cache aside, Read through, Write through, Write behind caching
缓存的更新可以从 cache 里面读取数据,取到后返回,如果没有得到就从数据库里取,成功后返回缓存当中。
Read through 是如果没有读到,就更新缓存。
Write through :在数据更新时,如果发现缓存里面没有数据,就更新缓存。可以合并同一个数据的多次操作。
Write behind caching :类似于底层的操作系统一个机制。
但是,这四种方式都不能保证缓存命中率。
我们在做核心系统的时候有一个小巧思,这个能力也以产品的方式提供给大家了。
如图,应用程序写请求到 RDS ,读请求到 Redis 。RDS的变更数据,底层是通过数据变更的方式拿到增量数据后,更新 RDS 。
优点:
l 更新路径短,延迟低
l 缓存失败为异步流程,业务更新 DB 完成后直接返回,不需要关心缓存失效流程,整个更新路径短,更新延迟低。
l 应用简单可靠
l 应用无需实现复杂双写逻辑,比如既写 RDS 又写 Redis ,只需启动异步线程监听增量数据,更新缓存数据同步到 Redis 里即可。
l 应用更新无额外性能消耗
因为数据订阅是通过解析 DB 的增量日志来获取增量数据,获取数据的过程对业务、 DB 性能无损,同时又能保证缓存的命中率100%。无需对 DB 造成额外的压力,也不需要从业务中拿出一部分资源来从 DB 读取数据,然后再更新缓存。这对 DB 和业务来说都是比较好的调优方法。