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