Ruby 在Sinatra中,是否可以将全局数据保存在内存中?
我正在向API服务器添加一个API。API服务器是由其他人基于Sinatra框架构建的。基本上它看起来像:Ruby 在Sinatra中,是否可以将全局数据保存在内存中?,ruby,sinatra,Ruby,Sinatra,我正在向API服务器添加一个API。API服务器是由其他人基于Sinatra框架构建的。基本上它看起来像: class ApiMain < Sinatra::Base get "/api/xx" {...} get "/api/yy" {...} end class-apiman
class ApiMain < Sinatra::Base
get "/api/xx" {...}
get "/api/yy" {...}
end
class-apiman
现在我添加了一个新的API,它返回从db加载的数据。对我的新API的调用预计会非常频繁,但数据不会经常更新,为了减少数据库的工作负载,我考虑将数据缓存在内存中,并且每分钟只从数据库加载一次。假设每分钟有1000个对我的API的调用,这样可以减少999次db访问
当我阅读Sinatra文档时,我看到“对于每个传入的请求,都会创建应用程序类的新实例,并且所有处理程序块都在该范围内运行。”
我是Sinatra的新手,我想知道是否有可能将数据缓存在可以与所有请求作用域共享的全局变量中?如果是,如何实现全局变量?非常感谢一个简短的示例。选择之一是使用
set
方法,该方法将数据存储在类变量中
require 'sinatra/base'
class App < Sinatra::Base
set :cache, {}
get "/?:word?" do
word = params[:word]
App.cache[word] ||= 0
App.cache[word] += 1
count = App.cache[word]
"`#{word}` was called #{count} times"
end
end
需要'sinatra/base'
类应用程序
您应该记住,这种方法有很多缺陷。您应该注意将此数据与其原始源同步。您应该注意不要意外地更改它,因为Ruby哈希可能会发生变异。每个进程都会有一份该数据的副本,等等。也许redis会做这项工作?是的,最终应该引入redis或memcached。但是现在,我们不想添加更多的组件。那么环境变量呢?)我猜env var不起作用,因为数据是一个哈希表。但是您可以使用
data.to_json
使其成为一个字符串。但我知道这绝对不是最好的解决方案。请注意:您混合了经典样式和模块化样式(),如果没有机架脚本,这个示例将无法正常工作<应该从configure
块中调用code>set。应使用settings.cache
而不是App.cache
访问缓存。此外,如果要在Puma这样的多线程web服务器下运行,我建议使用线程安全的Concurrent::Hash。这里有一个工作示例:@mwp,感谢您的反馈。我不是混合风格,它实际上是模块化风格:)。我没有把rackup文件放在它不是重点的地方(而且我不喜欢运行!如果app_file==0
)configure
和settings
只是yield self
和self
的一种糖分,但依我的口味,这个缓存根本不是配置的问题。因此,我更喜欢使用惯用的Sinatra setterset
,而不是在configure
块中,因为我觉得它在语义上更为正确。很抱歉,这里太迂腐了,但我仍然有一些顾虑。对于模块化风格,您应该要求使用'sinatra/base'
,并将您的应用程序包装在一个类中。对于经典风格,您应该要求使用“sinatra”
并保持应用程序内联。应用程序不会像您现在编写的那样响应任何请求,除非您从单独的机架脚本运行应用程序。@mwp,我的老习惯是要求整个sinatra
命名空间而不是sinatra/base
。我认为它起源于远古时代,当时根本没有sinatra/base
:)。(它仍然适用于sinatra
,因为它需要sinatra/base
内部)@mwp,但是是的,我应该更明确一些。非常感谢。