在日常的OLTP型应用中,绝大部分时候我们都会通过索引来优化查询和排序的速度。但在某些特定的OLAP场景下,索引可能并不能帮上多少忙。本文将讨论在这些特定场景下利用micro-sharding来优化这些查询,以及优化后带来的性能提升和需要注意的问题。
警告:micro-sharding只在本文讨论的特定场合下适用,滥用或者错误地使用micro-sharding不旦达不到预期目标,更有可能造成性能下降。实际使用时请确保对micro-sharding有充分的理解并做好测试。
基本概念
什么是micro-sharding?
简单地说,micro-sharding就是在一台服务器上安装多于1个分片实例(通常是每个CPU核部署1个分片实例)的分片部署方式。
为什么需要micro-sharding?
在某些场景(特别是OLAP)场景下,我们需要更多的运算能力,而不太在意时间的消耗。查询的优化重点变为如何优化利用更多的运算资源。micro-sharding在这样的场景中可以更加充分地发挥MongoDB的运算能力而加速分析的过程。
典型应用场景
micro-sharding的典型应用场景是在OLAP下,对时间要求不敏感,需要大量的运算资源时。满足这样条件的场景包括但不限于:
– 参与运算的条件字段太多无法让查询有效命中索引时
– 对大量数据进行分析,命中索引与否无关紧要时
通常OLTP型应用中,MongoDB并非是一个CPU使用大户。其背后的原因大部分时候是因为索引在起作用。因此在索引不起作用或不能完全起作用的场景下,都可以把micro-sharding作为一个解决方案来考虑。它本质上是在把原本不会并行的操作(如aggregation,排序)并行化,从而充分使用运算资源来缩短运算时间,更加快速得到结果。
当然micro-sharding也并不是完全与索引矛盾的存在,很多时候还是可以从索引中受益的。举个例子,可以通过索引预处理出某个时间段的数据,再利用micro-sharding的运算能力分析这些数据;或者更一般的说,利用索引进行预处理缩小数据量,再使用micro-sharding处理剩下的工作。
实践
为了验证micro-sharding能带来多少性能收益,我们做一次实际的测试来比较一下micro-sharding到底能够带来多少性能提升。
硬件
选用AWS上的EC2结点m4.2xlarge
– CPU:8核
– 内存:32G
– 硬盘:50G SSD
集群架构
简单起见我们选择了3台EC2结点作为3个分片,每个分片的复制集均只有一个结点。
警告:实际生产环境中不要使用单结点复制集!
注意事项
- 默认情况下WT引擎使用系统内存的60%或1G作为缓存,因此多个实例位于一台服务器上时可能发生内存争抢的问题,需要配置好缓存大小,保证内存足够。
- 本例中内存大小足够容纳所有数据,所以不用考虑与磁盘的数据交换问题。实际情况中可能出现内存不足的情况,此时需要考虑文件系统缓存(压缩)和WT缓存(非压缩)的交换问题,如有可能使数据在压缩状态下容纳进文件系统缓存,也是不错的选择。实在无法容纳的情况下,则要考虑磁盘交换问题,此时磁盘有可能成为整个系统的瓶颈,整个性能曲线表现则可能与本测试中的表现不符。
- 为系统进程留下足够的CPU和内存。通常留1-2个CPU和少量内存即可。考虑使用cgroup或taskset控制整个mongodb的CPU使用。
测试方法
使用NodeJS和Apache JMeter模拟数据并进行全数据排序。本测试中使用的数据满足以下条件:
– 约1000万数据
– 单个文档大小约2.5k
– 片键选择为{_id: "hashed"}
评测方法:
– 计时时间为从操作开始到返回第一条结果集记录为止
– 在3台服务器上分别创建3片、6片、9片……24片,测试返回结果所需时间
– 比较片数不同的情况下返回结果集所需要的时间
– 比较使用WT引擎和全内存引擎效率差异
测试所使用的源代码和JMeter配置文件已放到我的Github上。
测试结果
片数 | 平均响应时间(秒) | 平均响应时间(内存引擎,秒) | 理论每片文档% | 内存引擎提升% |
---|---|---|---|---|
3 shards | 137.258 | 114.759 | 33.33333333 | 16.39% |
6 shards | 86.638 | 75.999 | 16.66666667 | 12.28% |
9 shards | 55.48 | 51.19 | 11.11111111 | 7.73% |
12 shards | 43.773 | 38.094 | 8.333333333 | 12.97% |
15 shards | 37.019 | 35.761 | 6.666666667 | 3.40% |
18 shards | 33.977 | 28.914 | 5.555555556 | 14.90% |
21 shards | 32.191 | 27.9 | 4.761904762 | 13.33% |
24 shards | 29.124 | 25.433 | 4.166666667 | 12.67% |
结论
- 排序所需时间和片数基本保持反比关系。
- 去掉一个最高分和最低分,内存引擎较普通引擎在排序效率上平均有12.6%的提升。