业务应用数据库压力过大解决方案
注意:原创文章,转载请注明出处。
引言
数据库炸了,加CPU加内存?或许还有更合适的方法,例如优化代码逻辑、合理利用中间件、横向扩展数据库配置。
之前在做业务应用系统压力测试项目的时候,发现性能不达标的应用,问题大多出在数据库上,服务器的资源才用了30%不到,数据库资源已经跑满的情况比比皆是。
应用系统数据库压力过大是每个业务经理都多多少少面临过的问题,那么解决的办法除了纵向提高数据库配置(扩容CPU、内存)之外,是否还有其他更高效的途径呢?
一、原因分析
众所周知,单台数据库实例配置的提升是有瓶颈的,特别是关系型数据库,当CPU和内存配置提高到一定程度后,性能就很难再有提高,即使对数据库的内核进行优化,也只能稍微抬高这个瓶颈线。
在我所经历过的应用系统压力测试工作中,发现大厂研发的应用产品,通常服务器压力和数据库压力是基本持平的,而中小型的软件开发商提供的产品,往往服务器还没体现出明显的压力,数据库却已经炸了。
有经验的软件开发工程师会思考如何在代码层面合理规划数据库和服务器所承受的压力,把一部分推拉数据库数据的功能模块转化为通过服务器缓存或计算来完成,从而将数据库压力转移到服务器上。
另外,我们还可以利用Redis、MQ等中间件的数据缓存、内容分发等功能,作为数据缓存站或中转站来分担数据库压力。
当已经无法再通过上述方案降低数据库压力后,我们还可以凭借分布式数据库、主从读写分离数据库支持横向扩展的能力,来提升数据库性能。理论上横向扩展数据库性能是可以无上限地提高数据库承压能力的。
综上所述,我准备从代码层、中间件、分布式三块来分享如何优化应用对数据库的使用,从而提升应用系统性能。
二、在代码层面消化数据库压力
在代码层面可以通过创建索引和转移压力两种方式给数据库减压。
创建索引
索引是MySQL和Oracle等数据库本身提供的功能,合理创建索引可以提高数据的检索效率,降低数据库服务器IO和CPU的消耗。
但由于索引也会降低更新表的速度,经常增删改的表或字段不适合创建索引,所以在开发初期,我们就应该根据数据库模型表和字段的作用来决定是否为该表建立索引,为数据记录较多的表中,频繁作为查询条件的字段建立索引。
转移压力
在代码层把数据库压力转移到服务器上,要求我们在编写代码的时候,时刻留意代码中是否有过多与数据库进行交互的行为,是否可以通过缓存或计算,来减少与数据库交互的次数。
例如一个功能模块的代码写下来,发现多次连接数据库,可以调整为一次性取出所有需要的数据,减少对数据库的查询次数。又例如模块中的某一个值,既可以通过逻辑运算得出,也可以通过数据库读取,在为减轻数据库压力的场景下,我们会选择前者。
三、给数据库请个保姆——中间件
能否合理使用中间件是考量一个开发技术经理能力的标准之一,利用各种中间件的优势,可以有效提高产品性能,减少资源消耗。在数据读取压力较大的场景中,往往会引入Redis和MQ中间件。
Redis
Redis缓存数据库是将数据以键值对的形式缓存在内存中的高效数据库。在开发中,我们可以将一些频繁读取的数据临时存放到Redis,例如中签公告、人员名单、产品清单等,用户在访问这些数据的时候,如果发现缓存中有数据,则无需调用数据库,直接从Redis获取。同时,由于内存的读写速率是普通机械硬盘的几百倍,使用Redis作为数据缓存不仅减轻了数据库的压力,数据的存取速度还特别快,可以有效提高数据的调取速率。
MQ
MQ消息队列中间件常用于流量消峰和消息分发。利用MQ将同一时刻的大量请求分散成一段时间来处理,可以有效减轻数据库负担;另外把消息发布到MQ中供多个客户端监听,也能达到减少数据查询次数的效果。
四、忍法——数据库分身术
上面几种方法是在应用系统的软实力上做文章,达到为数据库减压的目的,但面对真正庞大的流量袭来时,还是得下硬功夫——提升数据库自身的读写性能。
纵向提高数据库配置,加CPU、加内存,对性能的提升是有限的,幸运的是,目前大部分数据库都支持分布式架构,或主从读写分离架构。
分布式架构
分布式架构数据库由多个计算机系统设备共同组成一个数据库,提供完整的数据库服务,例如Oracle、MongoDB、TDSQL等,增加计算机系统的数量,就能提升整体数据库性能,理论上分布式架构数据库的性能可以无限提高,这就是为什么天猫能承受双十一几十亿并发压力的原因之一。
主从读写分离架构
主从读写分离架构是专门一个主数据库用来写入数据,另外搭建几个从数据库用于读取数据,主数据库会把数据的变更同步给几个从数据库,这样就能将数据库的读取压力分散到多台从数据库中,从而实现数据库的减压。
相比于前面几种方案,横向提高数据库性能的成本高昂,并且“本体”的能力到位了,“分身”才更能体现价值,产品本身优化到位了,分布式架构横向扩展的性价比才高,“软实力”和“硬功夫”两者需要有机结合。
五、总结
目前我参与开发的项目体量都比较小,数据库性能问题还没有凸显,但经过几次压力测试的项目工作,提前对大体量业务应用存在的性能障碍有了一定了解,并且经过一系列思考和查阅相关资料,总结了一些数据库压力过大的处理方法,在此分享给大家。如果各位还有其他的方案,或在工作中遇到了类似的问题,欢迎找我沟通探讨,互相学习。