去年项目组接了一个mongodb数据量上亿的项目,完成整体前后端的工作后,客户反应告警数据页面分页查询api响应太慢,要求优化,经过我们组人员1个月的不懈努力,终于完成的客户要求的目标(所有条件下分页查询单次api响应500ms以内,并发100api分页查询响应2s以内),写篇文章记录一下整体的优化思路
优化手段一:业务数据模型优化
业务模型优化是对整体性能提升效果最明显的手段,因此我放在第一位。使用这种手段我们要根据实际的业务场景选择合适的数据库模型
实际场景1举例:客户的告警记录页面需要展示设备的每一条告警名称、告警类型、告警等级、告警设备名称、类型、告警设备发生和处理时间、告警设备所属公司,并且查询条件可以设置为告警名、设备名、公司名、设备类型、告警发生时间,因此我们在数据库建模时尽量要把表的字段将这些信息全部涵盖,涉及查询条件的一定要单独用一个字段存储,方便后面的索引优化
实际场景2举例
优化手段二:数据库分库、分表
当数据量超过一定量级后,查询性能会明显下降,因此我们可以根据业务场景,将数据进行不同维度的分库、分表,减少单次查询访问数据表的数据量
场景1:我们可以按年做切分,将不同年份的数据存入不同的数据表,查询前先判断一下要查询的时间范围,然后再根据这个范围去响应的数据表查询
缺点:如果查询的时间范围横跨很大,我们要对多张表进行查询,增加了查询次数,并且分页问题比较难以处理,因此要根据实际的业务场景来决定分库分表的粒度
场景2:涉及统计
优化手段三:使用缓存
1)接口缓存
最有效的api性能优化手段,但弊端也很明显,缓存时间过长会导致最新的数据无法及时同步,所以需要根据实际场景选择合适的缓存时间
2)恒定数据缓存
对于那些一旦产生后就不会再更新的数据,考虑将他们放入缓存,减少mongo查询次数
场景1:跨年后,去年的数据会恒定不变的存入数据库,此时可将这部分数据缓存至内存中
场景2:有时我们的数据库中只存储了id,name信息存储在其他表中,此时我们可以将id和name的映射关系存入内存,减少mongo查询次数
优化手段四:使用多节点并配置读写分离
如果拥有多个Mongo节点,则可以配置读写分离,所有只涉及查询的数据库连接集中分配到某个读节点
优化手段五:优化索引
mongo查询可以使用.explain("executionStats")进行分析,最主要是要看是否避免全表扫描、是否使用索引、是否避免内存排序
索引的原理是在内存中建立了一个排序的列表,key是被添加索引字段的值,value是字段对应document的物理地址,通过查询这张表来避免全文索引,提升查询速度,同时每次给collection插入数据时也会同时给索引中新加入一条数据
索引的本质就是利用空间换时间,因为建立索引需要占用很大的存储空间,并且影响数据插入性能,因此不能滥用索引
常用的索引类型:普通索引、text、hashed
普通索引:查询时需要按照该字段排序,加普通索引最合适
text:查询时需要按照该字段模糊查询,加text索引最合适
hashed:查询条件包含该字段的==条件,加hashed索引最合适
优化手段六:优化查询语句
原则一:查询结果和条件不包含所有字段,则需要有限使用projection
原则二:优先使用match,再使用sort和group