面试题答案
一键面试可能原因分析
- 片键选择不合理:
- 若片键选择的字段在高并发写入时存在热点,比如使用了单调递增字段(如时间戳)作为片键,所有新写入的数据都会集中在一个或少数几个分片上,导致这些分片成为写入瓶颈。
- 片键字段的基数过低,即不同片键值的数量少,使得数据分布不均匀,部分分片负载过高。
- 写入集中时间段压力:在特定时间段内大量写入,超出了当前集群架构和配置所能承受的写入能力,即使片键设计合理,也可能出现性能瓶颈。
优化片键设计
- 选择合适片键:
- 对于读多写少且写入集中在特定时间段的场景,可以考虑选择具有高基数且分布均匀的字段作为片键。例如,如果数据中有用户ID字段,不同用户ID数量多且分布均匀,使用用户ID作为片键可以更好地分散写入压力。
- 避免使用单调递增字段(如时间戳)作为片键。如果业务逻辑依赖时间顺序,可以结合其他字段,如时间戳与用户ID组合作为复合片键,这样既能保证数据一定的顺序性,又能分散写入压力。
- 动态调整片键:如果业务数据特点允许,可以在写入高峰和低谷时期动态调整片键。比如在写入低谷时期,根据数据的其他特征重新分片,以优化在高峰时期的写入性能。
应对复杂读写场景综合解决方案
- MongoDB配置参数调整:
- 写入相关参数:
w
参数:根据业务需求适当降低写入确认级别,例如设置w = 1
,表示写入操作只需在主节点确认写入成功即可返回,而不需要等待所有副本节点同步完成,这样可以提高写入性能,但可能会牺牲一定的数据安全性。j
参数:如果业务允许,可以关闭日志持久化(j = false
),因为日志写入会增加写入操作的开销。但这也会带来数据丢失风险,在系统崩溃时可能无法恢复未持久化到日志的数据。
- 缓存相关参数:
- 调整
mmapv1
存储引擎的wiredTiger
缓存大小参数(storage.wiredTiger.engineConfig.cacheSizeGB
),根据服务器内存情况,适当增加缓存大小,以提高读性能。因为读多写少场景下,更多数据可以缓存在内存中,减少磁盘I/O。
- 调整
- 写入相关参数:
- 架构层面优化:
- 读写分离:利用MongoDB副本集的读写分离功能,将读操作路由到副本节点。可以通过应用程序层面的驱动配置,指定读偏好为
secondaryPreferred
或secondary
,这样大部分读操作会从副本节点读取数据,减轻主节点的读压力,同时不影响写入操作在主节点的进行。 - 引入缓存层:在应用程序和MongoDB之间引入缓存层,如Redis。对于经常读取且不频繁变化的数据,先从缓存中读取。当缓存中没有数据时,再从MongoDB读取,并将数据写入缓存。这样可以大大减轻MongoDB的读压力,提高整体系统的响应速度。
- 水平扩展:在写入高峰时期,可以临时增加分片数量,以分散写入压力。当写入低谷时期,可以适当减少分片数量,以优化存储和管理成本。同时,可以增加副本集成员数量,提高读性能和数据可用性。
- 读写分离:利用MongoDB副本集的读写分离功能,将读操作路由到副本节点。可以通过应用程序层面的驱动配置,指定读偏好为