使用类变量缓存大量静态数据

3

首先,让我解释一下情况,我有以下内容:

"Node"类,具有以下属性:

  • node_id(唯一)
  • node_name(唯一)

还有一个"NodeConnection"类,具有以下属性:

  • node_from
  • node_to

我们将拥有大约100万到300万个节点和大约300万到1000万个节点连接。

在导入节点和连接后,它们不会改变

对于Rails应用程序的每个请求,我们将根据可能的节点名称查找大约10到100个节点ID。我们必须查找几百到几千个节点连接。

目前,我们在没有任何缓存的情况下进行了原型设计(因此,需要进行大量的数据库查询),响应时间非常慢(如2分钟)。 因此,我们切换到通过memcached缓存节点和连接。

得到了性能提升,但仍然缺乏性能。(因为我们为每个NodeConnection调用Cache.read,这是每个请求中的数千个调用)

现在,我们尝试使用Classvariable进行缓存,并获得了巨大的性能提升。(响应时间在几百毫秒内)

# Pseudocode below
class Node
  def nodes
    @@nodes ||= get_nodes
  end
  def node_connections
    @@node_connections ||= get_node_connections
  end
end

因此,我想询问这种解决方案的优点缺点

目前我遇到的缺点:

  • 每个Rails实例都必须建立自己的缓存(自己的ClassVariables)-> 总内存使用率更高
  • 初始化缓存需要时间(1-3分钟),所以我们不能在请求中完成此操作

是否有其他解决方案可以高效地缓存大型(>100MB)且静态(数据在应用程序生命周期内不会更改)的数据,以便同一台机器上的所有Rails实例都可以快速访问此缓存(!)?


只是一个想法,不知道好坏 - 你尝试过使用 Struct 而不是实际类,或者使用自定义的 C 绑定吗?这也可以提高性能。 - m_x
我会看一下。你可能有一些关于C绑定的资源吗? - Deradon
1
另一个好或坏的想法:编写一个小的C应用程序,在本地UNIX套接字上提供数据,并自己缓存数据。 - m_x
1
这是一个开始:http://ruby-doc.org/docs/ProgrammingRuby/html/ext_ruby.html - m_x
所以你有节点和节点连接 - 听起来它们可以连接成树或图?需要更多细节来考虑一个数据结构,可以容纳这些项目。原因是:memcache很快,但加载数百万个缓存似乎很慢。我会尝试将节点和节点连接打包到一个数据结构中,并将整个数据结构存储在memcache中。预热可以通过初始化程序、加载钩子和cron作业完成(对于这种东西仍然喜欢它们)。 - Florian Pilz
这是一个图表。不幸的是,memcache默认每个项目只能存储1MB(出于良好的原因,我已经阅读过了)。目前,我正在将项目存储在块中(例如每个memcache项目25k个节点)。但即使是1k个memcache项目,也太多了,无法实时读取。当前解决方案: 将所有数据缓存到memcached中,并在Rails实例启动时加载到Ruby(通过类属性)。为此解决方案编写了一个LookUpTable-Gem,但仍有一些工作要做。该解决方案的缺点:
  • 内存使用 -> 这将限制服务器上运行的Rails实例数量
- Deradon
1个回答

3
似乎是一个非常具体的情况,但为了避免需要每个进程内存缓存(即类变量)自然升温,我建议调查编写脚本热身过程并从初始化器内运行的可行性...你的应用程序可能需要更长时间启动,但用户不必等待。
注意,如果您使用像Unicorn这样支持预加载应用程序代码的工具,在派生工作进程之前,可以将其初始化的影响降至最小化。

感谢 Unicorn 的提示。我会尝试一下。(Unicorn 的另一个好处是:在使用 Nginx 和 Passenger 时遇到了一些问题) - Deradon

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接