Ruby on rails Rails:如何维护内存中的进程内搜索索引?

Ruby on rails Rails:如何维护内存中的进程内搜索索引?,ruby-on-rails,ruby,multithreading,Ruby On Rails,Ruby,Multithreading,我相信,如果我们保持一些嵌套哈希和数组的简单内存数据结构,我们可以在用户匹配和搜索功能中获得巨大的性能提升。这还不够复杂,不足以使用像ElasticSearch这样的专用内存搜索,而且它也不是关于自由文本搜索的。问题是如何保持更新 因此,我考虑在加载时保留一个线程,以便每隔5分钟左右刷新和替换存储在类变量中的索引(只需一两秒钟)。问题是这让人感觉很僵硬。保留一整条线只是为了坐在那里睡觉!在每个请求之后生成一个短生命周期的线程来检查是否到了更新的时候,这样做是否更好?但我不希望这种情况总是在错误的

我相信,如果我们保持一些嵌套哈希和数组的简单内存数据结构,我们可以在用户匹配和搜索功能中获得巨大的性能提升。这还不够复杂,不足以使用像ElasticSearch这样的专用内存搜索,而且它也不是关于自由文本搜索的。问题是如何保持更新

因此,我考虑在加载时保留一个线程,以便每隔5分钟左右刷新和替换存储在类变量中的索引(只需一两秒钟)。问题是这让人感觉很僵硬。保留一整条线只是为了坐在那里睡觉!在每个请求之后生成一个短生命周期的线程来检查是否到了更新的时候,这样做是否更好?但我不希望这种情况总是在错误的时刻用请求来争夺CPU。除了引入事件库(如事件机)之外,还有更标准的railsy方法吗?


我知道,当不由redis这样的中介机构管理时,这种共享状态通常是不受欢迎的,但我对突变风险非常满意,因为我将冻结这种数据结构。此外,这个索引有数万个散列键和文本项,因此我认为,对每个请求从redis进行反序列化将使许多好处付之东流。

这个问题有点矛盾;你同时要求用一种轻率的方式来解决你的问题,同时明确地打消了所有常见的解决方案,坚持你发明的计划是最合适的

听起来你最终会花很多精力来手工推出一个“不那么复杂”的解决方案。我强烈建议不要那样做。然而:

选择定时到期还是事件到期在很大程度上取决于您是拥有一个缓存,还是拥有多个独立的缓存。如果它是一个进程内缓存,并且您有多个进程,那么您没有实际的方法按需触发到期,并且必须采用计时器方法。(我看不出事件机在这里有什么关联。)


对于这项工作来说,Redis确实是一个更合适的工具。使用Redis的意义在于不需要反序列化所有内容:在Redis中进行查找,然后只反序列化匹配的部分

由于您有多个进程和多个硬件:无法避免数据过时、不同步。 发明你自己的缓存解决方案(用于查找、过期、同步、刷新、预加载和防止占用你所有的内存等)将比仅仅使用已经存在的东西更加复杂和容易出错(我想到了Redis,还有其他的)

我建议你去看看Redis商店。 虽然这将包括网络/反序列化,但我认为这是最有效的Rails方式,而且根据我的经验,速度足够快。 如果您已经尝试了此方法,但速度仍然很慢,那么您可以尝试其他解决方案。或者自己滚。但第一个衡量标准,不要只是假设。

我发现了一块受欢迎的宝石,它是由sidekiq的创建者制作的

我不会说这是一个完美的答案,因为它不是为长时间运行的线程而设计的,当我可以在一个控制器回调上启动自己的短命线程时,它可能会有点过头

其他回答者提出了一个很好的观点,即对于多个进程,我需要一种同步方法。Redis符合这个要求,我会使用它。但是,如果我们遵循问题的前提,即结构太大,无法在每个请求上从redis反序列化,那么我们需要一些额外的进程内并发来维护共享的反序列化缓存对象

我理解为什么其他回答者对这样的策略感到不舒服,比如ruby实际上不适合进程内并行,所以它不是我们文化的重要组成部分(在神秘的ruby 3.0之前,我们只能在进程内进行并发)。这并不意味着它永远都不是正确的答案


Suckrpunch以一种有轨的方式解决了后台处理的需求—非常像sidekiq—但进程内处理通过直接共享对象访问解决了这一问题。

那么您运行的是单个ruby进程吗?不,是许多进程,虽然有好几个集群,但每个进程都有一个数据结构副本是可以承受的。也许我不应该说railsy,但“rails开发者可能使用的一种明智的方法”。一些背景:我以前一直在把这个搜索微服务推向一个更为友好的面向对象的方向。但现在我们预计会出现严重的、突然的增长,而业绩现在是首要关注的问题。如果做出正确的决策,Ruby在性能上将远远不够。数据结构是一个散列,ID数组指向该散列。每个请求通常需要超过1000次密钥访问。为了让redis正常工作,我需要一个更加复杂和高度非规范化的数据结构。如果问题纯粹是关于让一个线程专用于保持缓存新鲜度的合理性(我们正在着手处理随之而来的线程安全问题),那么是的,这是一个完全合理的做法。Active Record有一个线程,它唯一的任务就是偶尔查找放错位置的DB连接。线程(尤其是空闲线程)真的没有那么贵。谢谢,这很有帮助。至于it是多进程的问题,我认识到其缺点是每个进程都需要一个数据结构副本。我突然想到,为了获得一致的结果,它们需要紧密同步。实现这一点的最有效方法是引入redis,将结果与辅助进程一起存储,并让每个进程每5分钟有一个线程对其进行反序列化。是的,它比预期的要复杂一点。与我能看到的备选方案相比,情况更糟,但嗯……好吧,但我经常使用redis缓存,并解释了为什么它不符合这一要求,而您还没有说明这一解释。至于陈旧数据的问题,f