问题背景: 近期在重构公司内部一个重要的任务系统,由于原来的任务系统使用了MongoDB来保存任务,客户端从MongoDB来取,至于为什么用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的性能会由于锁表操作急剧下降。
具体问题: (Think out of the Box)能否提出一个好的解决方案,能够保存任务状态(子任务状态),速度至少超过MongoDB的?
잠깐 생각한 후 참고용으로만 사용하세요.
개인적으로 질문자가 언급한 MongoDB 배열 쿼리 및 업데이트의 성능 문제는 스키마 설계 문제일 가능성이 높다고 생각합니다. 하지만 질문자는 구체적인 디자인을 제시하지 않았으므로 참고용으로 주목할 만한 몇 가지 사항을 제시하겠습니다.
Mongodb는 메모리 내 데이터베이스입니다. 모든 핫스팟 데이터가 메모리에 있으면 성능이 매우 뛰어나며 이는 주로 스키마 설계에 따라 달라집니다.
PS: mongodb가 항상 선전했던 Schemaless의 장점은 많은 사람들을 오해했습니다. 사실 이는 mongodb가 스키마를 설계할 필요가 없다는 점을 보여주기 위한 것입니다.
작업 대기열에 Rabbitmq를 고려해 볼 수도 있습니다. 또한 mongodb는 너무 느려서는 안 됩니다. 그렇죠? 아니면 제한 컬렉션을 사용해 보세요.