使用Redis的使用Rails将提供这种特定类型的查询

问题描述:

我不知道这是不是要问这样的问题,正确的地方的任何性能优势,但这里有云:使用Redis的使用Rails将提供这种特定类型的查询

我有一个内联网样Rails 3应用程序管理大约20k用户,它们是嵌套集(预订树 - http://en.wikipedia.org/wiki/Nested_set_model)。 这些用户输入统计信息(数据,只是纯数值)。输入的统计数据被分配给类别(我们称之为指针)和一个星期数字。

这些数据被进一步处理和计算,以结果。 有些是根据用户活动+其他类别的结果计算的......等等。 用户输入的内容与他在报告中看到的内容并不总是相同的。

这些计算可能会非常棘手,有些种类有非常具体的公式。

但剩下的只是“给我所有输入的值的总和此类别该用户本星期/月/年”。

问题是那些统计需要也被求和用户的下选择的用户的子集(因此它基本上为所有用户返回用户下的所有值的总和,包括自我)。

这款应用程序已投入使用2年,它的工作相当出色......但越来越多的用户对于服务器价格较高的报告也很慢,比如“给我所有用户的列表在我自己和他们的统计数据中,其中一行由他们的小组汇总,一行为他们的个人统计“)。当然,用户希望(并且需要)他们的报告尽可能实际,5分钟以反映新输入的数据对他们来说太多了。这个特定的报告是他们最喜欢的:/ 要保持实时性,我们不能直接执行高密度的sqls ...这会杀死服务器。所以我只通过后台进程计算它们,前端只是读取结果。 那些sql语句是难以优化,我很高兴我已经从这种做法感动......

当前的应用程序是这样的(高速缓存是不是一种选择,见下文。):

  • 前端:当用户输入新数据时,它被保存到简单的mysql表中,如[user_id, pointer_id, date, value],并且还有插入队列。

  • 后端:再有就是calc_daemon过程,每5秒检查新“重新计算的请求”的队列。我们弹出请求,确定还有哪些需要重新计算(指针有依赖关系......最简单的情况是:当您更改星期统计信息时,我们必须重新计算月和年统计信息...)。它以简单的方式完成这种重新计算。我们通过自定义的每个指针来选择数据 - 由它们的类生成不同的sqls。

  • 这些计算结果被写回的MySQL,但分区表(一个表每年)。该表中的一行与[user_id, pointer_id, month_value, w1_value, w2_value, w3_value, w4_value]相似。这样,表格就有〜500k条记录(我基本上减少了5倍的记录)。
  • 当前端需要这些结果时,它对这些分区数据做了简单的总结,并带有2个连接(因为嵌套集conds)。

问题是,那些简单的sqls和sum,group-by-and-on-the-subtree可能每次需要200ms ......只是为了一些记录......我们需要运行很多这些sqls ...我认为他们已经根据explain优化了他们所能做到的最好...但是它们太难了。

所以......这样一个问题:

我可以重写这个使用Redis的(或其他快速键 - 值存储),看看从中任何好处时,我使用Ruby和Rails?正如我所看到的,如果我将它重写为使用redis,那么我将不得不运行更多的查询,而不是使用mysql,然后手动执行ruby中的数据...所以性能会受到影响相当...我真的不知道我是否可以使用redis编写所有可能的查询...将用户加载到rails中,然后执行类似于“redis”的操作,为用户提供总计1,2,3, 4,5 ......“似乎并不是正确的想法......但是也许redis中有一些功能可以使这更简单?)... 此外,树结构需要像嵌套集,即它不能在redis中有一个条目,对于某些用户(类似于children_for_user_10: [1,2,3]),因为树结构经常变化...所以我无法在这些分区表中获得这些总和,因为当树变化,我将不得不重新计算一切..这就是为什么我实时执行这些总和。)

或者你会建议我将此应用重写为不同的语言(java?)并计算内存中的结果吗? :)(我尝试过使用SOA方式,但是它失败了,因为我在Ruby中以XXX兆字节的数据结束了这种或那种方式......特别是在生成报告时......并且gc只是杀死了它.. )(并且副作用是一个生成报告会阻止整个rails应用程序:/)

欢迎提出建议。

+1

从另一个问题http://*.com/questions/4846243/redis-sum-of-scores-in-sorted-set它似乎总结在redis是一个不行。 – hellvinz

+0

感谢您的链接。看起来像使用键值存储与红宝石,这种应用程序要求它只是一个没有去......我可以想象建立一个服务,处理和缓存这些数据在内存中,并将它们用于所有用户(它会只保留最新的数据)..使用这样的redis会更简单,但它必须是快速的(即用php(bleh)或java(uhoh)编写):(或者我将不得不选择例如MongoDB ...这是另一种选择,我应该更新问题以包含它吗?在重写之前,我需要一些真实的体验......需要一周左右的时间:( –

+0

)我们在工作场所使用了Redis,并且我们发现如果你可以简化你的数据关系到Redis可以解释的东西,你可以获得巨大的性能提升。也就是说,我们大多数涉及连接的查询往往表明DB逻辑太多而无法卸载到Redis上(我们确实尝试过,但是必须计算Postgres将会正常工作的额外开销在我们的Rails应用程序中做的事情证明会让事情变得更糟,而不是更好:P) –

Redis会更快,它是一个内存数据库,但是你可以将所有这些数据放在内存中吗?正如注释中所指出的那样,不推荐使用redis键进行迭代,所以我不会使用它来存储原始数据。但是,Redis通常用于存储总和的结果(例如记录事件的计数),例如它具有快速的INCR命令。

我猜你会通过使用存储过程或比ruby更快的语言(例如C-inline或Go)来进行重新计算,从而获得足够的速度提升。你在重新计算中进行分组吗?是否有可能将分组更改为编码结果集的代码,然后手动检查“组”更改的时间。例如,如果您按用户循环并按循环在循环内分组,则将其更改为按用户和星期排序,并为用户和星期的当前值和先前值以及总和变量保留变量。

这是假设瓶颈是重新计算,您没有真正提到哪个部分太慢。