欢迎阅读有关MongoDB性能最佳实践的系列博文的第六篇。
在本系列中,我们从多个重要维度上讨论实现大规模性能的关键考虑因素,包括:
- 数据建模与内存优化
- 查询模式和性能分析
- 索引
- 分片
- 事务和读/写关注
- 硬件和操作系统配置(本期讨论的内容)
- 基准测试
如果您在阿里云上部署MongoDB,那么阿里云会为您处理好有关硬件和操作系统配置的诸多考虑因素。您可以参考阿里云官网的产品规格文档来选择合适的实例规格。
如果您自己在本地部署MongoDB,那么您可以参考本文以下内容。
在支持的平台上运行
除了在阿里云上运行MongoDB,您还可以选择各种操作系统和处理器架构,从x86-64、ARM处理器到IBM POWER、大型计算机系统。请参考文档中的支持平台获取最新的硬件和操作系统支持矩阵。
确保工作集与内存适配
正如本系列的第一篇博文中所述,当应用程序的工作集(索引和最常访问的数据)与内存适配时,MongoDB的性能会达到最佳。内存大小是影响实例大小的最重要因素,如果内存不足,其他优化动作可能也无法显著提高数据库的性能。
更多信息请参考本系列的第一篇博文:数据建模与内存优化。
使用多个CPU内核
MongoDB的WiredTiger存储引擎架构能够高效地使用多个CPU内核。每个客户端的连接通常都有对应的线程,此外,后台还有执行检查点机制和缓存清除等任务的工作线程。您应根据并发客户端连接的数量来配备足够的CPU核数。请注意,投入更多的内存和磁盘IOPS对数据库性能的改善效果最大。
在阿里云MongoDB中,CPU核数和客户端最大连接数取决于您选择实例规格。您可以参考阿里云官网的实例规格表文档来选择合适的实例规格。
将每个服务器专用于系统中的单一角色
为了获得最佳性能,您应该在每个主机上运行一个mongod进程。
通过使用虚拟化或容器技术进行适当的内存和资源分配,多个MongoDB进程可以安全地运行在单个物理服务器上,而无需争夺资源。
对于某些用例(如多租户),用户会在同一主机上部署多个MongoDB进程。在这种情况下,您需要更改配置以确保每个进程都有足够的资源。
为了保证可用性,同一副本集的多个成员应部署在不同的物理硬件上(如电源或网络交换机),避免同时承担单点故障的风险。
配置WiredTiger缓存
WiredTiger存储引擎的内部缓存大小可以通过storage.wiredTiger.engineConfig.cacheSizeGB进行设置,其大小应足以容纳整个工作集。如果缓存没有足够的空间来加载额外的数据,WiredTiger将从缓存中驱逐页面,从而释放空间。
在默认设置下,storage.wiredTiger.engineConfig.cacheSizeGB为可用内存的50%再减 1 GB。应谨慎提高该值,因为这会占用操作系统的资源,而且随着文件系统缓存效率降低,WiredTiger的性能也会下降。请注意,MongoDB本身也会分配超出WiredTiger缓存的内存。
此外,由于MongoDB支持可变大小的记录,同时WiredTiger会创建可变大小的页面,因此预计会出现一些内存碎片,这将会消耗超出配置的内存。
使用多个查询路由
多个mongos进程(查询路由器)应分布在多台服务器上。您使用的mongos进程数量至少应与分片数量相同。阿里云MongoDB会自动为集群中的每个分片配置一个查询路由器。
在NUMA架构上使用内存交织策略
在具有非一致内存存取(NUMA)的系统上运行MongoDB可能会导致一系列问题,包括一段时间内性能下降、无法使用所有可用内存、高系统进程使用率。
当在NUMA硬件上运行MongoDB服务器和客户端时,您应该使用numactl --interleave命令配置内存交织策略。
网络压缩
作为分布式数据库,MongoDB在查询路由和节点间复制过程中依赖于高效的网络传输。基于snappy压缩算法,MongoDB集群间的网络流量最多可压缩80%,从而在带宽受限的环境中带来显著的性能优势,并降低网络成本。
您可以通过在连接字符串中添加compressors参数来启用压缩:mongodb://localhost/?compressors=snappy。
存储和磁盘I/O注意事项
尽管MongoDB通过内存数据结构执行所有读写操作,但数据会持久化到磁盘上,如果查询数据不在内存中,则会触发对磁盘的读取。因此,存储系统的性能对任何系统来说都至关重要。
您应使用高性能存储,以下考虑因素将帮助您使用最佳的存储配置,包括操作系统和文件系统设置。
(1)对于I/O密集型应用程序使用固态硬盘
在MongoDB中,大多数磁盘访问模式都不具备顺序属性,因此使用固态硬盘可以大幅提高性能。
使用SATA、PCIe和NVMe固态硬盘有非常高的性价比。与其花高价购买昂贵的旋转驱动器,还不如多买一些内存或固态硬盘。如果工作集不再适配内存,也应使用固态硬盘来读取密集型应用程序。
建议您将MongoDB的日志文件存储在单独的磁盘分区上。
大多数MongoDB部署都应使用RAID-10存储配置。RAID-5和RAID-6存在一些限制,可能无法提供足够的性能。MongoDB的副本集可以通过合理部署提高数据可用性,应同时考虑RAID等其他因素,从而共同满足所需的可用性SLA。您不需要购买SAN磁盘阵列就可以实现高可用性。
(2)对于存储和I/O密集型工作负载,请使用MongoDB的默认压缩功能
默认的snappy压缩通常可以减少50%或更多的存储占用,并且由于从磁盘中读取的位数更少了,因此还可以提高IOPs。任何压缩算法都要在存储效率和CPU开销之间做权衡,因此您需要在自己的环境中进行压缩测试。
MongoDB为文档和索引提供了一系列压缩选项。snappy压缩算法在高文档压缩率(通常为50%+,取决于数据类型)与低CPU开销之间实现平衡,zStandard和zlib库可以实现更高的压缩率,但在从磁盘读取数据时会产生额外的CPU开销。zStandard在MongoDB 4.2版本中引入,与zlib库相比CPU开销更低。
索引默认使用前缀压缩,可以减少索引存储的内存占用,为频繁访问的文档腾出更多的内存。测试表明,使用前缀算法的压缩率通常为50%,但仍然建议您使用自己的数据集进行测试。
您可以修改所有集合和索引的默认压缩设置,也可以在集合和索引的创建过程中根据特定需求进行配置。
(3)配置预读(readahead)
建议将预读设置在8到32之间。您可以使用blockdev --setra 命令来设置预读块大小。
(4)使用XFS文件系统,避免使用EXT4
由于在 WiredTiger 中使用 EXT4 时出现过性能问题,因此强烈建议使用XF。
(5)禁用访问时间设置
一些文件系统会保留文件最后一次被访问时的元数据。虽然这对某些应用程序可能有用,但在数据库中,这意味着每次数据库访问页面,文件系统都会进行一次写入操作,这将对系统的性能和吞吐量产生负面影响。
(6)禁用透明大页(Transparent Hugepages)
透明大页可能会增加额外的内存压力和CPU利用率,并对交换性能产生负面影响。
更多内容
有关最新的硬件和操作系统配置指南,请查看MongoDB Production Notes和Operations Checklist。
以上是本期性能最佳实践系列的内容。在本系列的下一篇文章中,我们将讨论基准测试。