开发者社区> 问答> 正文

MongoDB + Redis 任务队列性能瓶颈问题

问题背景: 近期在重构公司内部一个重要的任务系统,由于原来的任务系统使用了MongoDB来保存任务,客户端从MongoDB来取。假设这样的情况,一个md5需要针对N种情况做任务处理,如果用到MongoDB的数组,只需要将一个md5作为一条任务,其中包含一个长度为N的待处理任务列表(只有N个子任务都处理完后整个任务才算处理完毕),这样整个任务系统的数量级就变为原来的 1/N。

细节描述:
1.当MongoDB的任务数量增多的时候,数组查询相当的慢,任务数达到5K就已经不能容忍了。
2.任务处理每个md5对应的N个子任务必须要全部完成才从MongoDB中删除
3.任务在超时后可以重置

改进方案如下:
由于原有代码的耦合,不能完全抛弃MongoDB,所以决定加一个Redis缓存。一个md5对应的N个子任务分发到N个Redis队列中(拆分子任务)。一个单独的进程从MongoDB中向Redis中将任务同步,客户端不再从MongoDB取任务。这样做的好处是抛弃了原有的MongoDB的数组查询,同步进程从MongoDB中取任务是按照任务的优先级偏移(已做索引)来取,所以速度比数组查询要快。这样客户端向Redis的N个队列中取子任务,把任务结果返回原来的MongoDB任务记录中(根据md5返回子任务)。

改进过程遇到的问题:
由于客户端向MongoDB返回时候会有一个update操作,如果N个子任务都完成,就将任务从MongoDB中删除。这样的一个问题就是,经过测试后发现MongoDB在高并发写的情况下性能很低下,整个任务系统任务处理速度最大为200/s(16核, 16G, CentOS, 内核2.6.32-358.6.3.el6.x86_64),原因大致为在频繁写情况下,MongoDB的性能会由于锁表操作急剧下降。

具体问题: 能否提出一个好的解决方案,能够保存任务状态(子任务状态),速度至少超过MongoDB的?

展开
收起
落地花开啦 2016-02-28 10:32:59 4122 0
1 条回答
写回答
取消 提交回答
  • 喜欢技术,喜欢努力的人

    仅供参考
    1.索引,正如楼上所说,你应该已经为数组加上了索引。但是值得注意的是,数组字段的索引比普通字段的索引体积要大很多(具体取决于数组的大小,数组越大,索引所占的空间越大)。这样就可能会导致一个问题:索引并不(完全)在内存里! 后果是,每次查询都需要涉及到额外的IO操作,性能会急剧下降。
    2.查询返回文档的大小。如果每次返回查询的文档数据量较大,而且客户端与mongodb并不处于同一机器上,那就会增加了网络传输所需的时间(不要小看这点时间),所以尽可能只返回所需要的字段。
    3.update-in-place. 由于schemaless的特性,mongodb会为每条文档记录预留一些空间给增加额外的字段或数据时使用,提高update的性能。但如果你文档的大小频繁地扩展(增加字段,增加数组长度等),那就会导致写的性能问题:mongodb需要把增长了的文档移动(move)到别的地方。(相当于从硬盘的一个位置移动另一个更空闲的位置)这时候的性能会大大下降。
    mongodb是一个内存型的数据库,如果你的热点数据都在内存上,它的性能会非常优异,而这很大程度取决与你的Schema设计。

    2019-07-17 18:49:24
    赞同 展开评论 打赏
问答排行榜
最热
最新

相关电子书

更多
开源数据库 MongoDB 专场 MongoDB疑难杂症分析及优化 立即下载
阿里云MongoDB云服务构建 立即下载
饿了么高级架构师陈东明:MongoDB是如何逐步提高可靠性的 立即下载