Passenger、Sinatra、Nginx、RabbitMQ和SSE(Passenger如何启动进程以及Ruby线程在图片中的位置)
我的当前设置有问题,无法按预期工作,并阻止我进一步启用启用服务器发送事件(SSE)的网站。我的主要问题可以在下面粗体显示,但可以归结为“如何在乘客设置中从Sinatra web应用程序启动额外线程?” 我使用乘客5.0.21和Sinatra 1.4.6。该应用程序是作为一个经典的Sinatra应用程序编写的,不是模块化的,但如果需要可以更改 我已将指令Passenger、Sinatra、Nginx、RabbitMQ和SSE(Passenger如何启动进程以及Ruby线程在图片中的位置),nginx,rabbitmq,sinatra,passenger,server-sent-events,Nginx,Rabbitmq,Sinatra,Passenger,Server Sent Events,我的当前设置有问题,无法按预期工作,并阻止我进一步启用启用服务器发送事件(SSE)的网站。我的主要问题可以在下面粗体显示,但可以归结为“如何在乘客设置中从Sinatra web应用程序启动额外线程?” 我使用乘客5.0.21和Sinatra 1.4.6。该应用程序是作为一个经典的Sinatra应用程序编写的,不是模块化的,但如果需要可以更改 我已将指令passenger\u min\u instances 3放入Nginx配置中,以至少启动3个web应用程序实例。我在我的Sinatra应用程序的
passenger\u min\u instances 3
放入Nginx配置中,以至少启动3个web应用程序实例。我在我的Sinatra应用程序的config.ru
文件中有两个put
,因此当线程启动时,我在/var/log/nginx/passenger.log
中得到反馈,当线程通过RabbitMQ队列接收消息时:
...
Thread.new {
puts " [* #{Thread.current.inspect}] Waiting for logs. To exit press CTRL+C"
begin
q.subscribe(:block => true) do |delivery_info, properties, body|
puts " [x #{Thread.current.inspect}] #{body}"
end
rescue Interrupt => _
ch.close
conn.close
end
}
run Sinatra::Application
我期望该代码运行n次,n是由Passenger启动的进程数。看起来情况并非如此
此外,我的app.rb
包含了很多东西,可以简化为:
puts "(CLASS)... Inside thread #{Thread.current.inspect}"
configure do
puts "(CONFIGURE)... Inside thread #{Thread.current.inspect}"
end
get '/debug' do
puts "(DEBUG)... Inside thread #{Thread.current.inspect}"
end
当我重新启动Nginx并使第一个httpget访问URL/debug
时,进程被实例化,其中一个进程为请求提供服务。在/var/log/nginx/passenger.log
中我能得到什么
(CLASS)... Inside thread #<Thread:0x007fb29f4ca258 run>
(CONFIGURE)... Inside thread #<Thread:0x007fb29f4ca258 run>
[* #<Thread:0x007fb29f7f8038@config.ru:68 run>] Waiting for logs. To exit press CTRL+C
(DEBUG)... Inside thread #<Thread:0x007fb29f4ca8e8@/usr/lib/ruby/vendor_ruby/phusion_passenger
192.168.0.11 - test [30/Dec/2015:10:09:08 +0100] "GET /debug HTTP/1.1" 200 2184 0.0138
ruby测试程序发布RabbitMQ消息供订阅者接收,有时有效,有时无效。乘客可能会关闭正在运行的进程,即使它在给定的时间内没有看到请求。日志中没有显示任何内容。没有来自订阅者线程的反馈,也没有来自乘客本身的消息
如果我刷新页面,我会得到DEBUG
消息和get/DEBUG
跟踪<代码>乘客状态--verbose显示第一个进程现在已经处理了两个请求
我在不同的测试中看到,我必须发出大量请求,以使乘客与其他2个进程一起服务请求,甚至启动新进程,最多6个。让我们在同一局域网中的另一台机器上使用root@backup:~#ab-A测试:测试-kc 1000-n 10000https://192.168.0.10:445/debug
。Passenger已启动最多6个进程来处理请求,但是Passenger.log
文件中除了DEBUG
消息和GET/DEBUG
跟踪之外,我看不到任何内容,就好像没有启动其他进程一样
$ passenger-status --verbose
----------- General information -----------
Max pool size : 6
App groups : 1
Processes : 6
Requests in top-level queue : 0
----------- Application groups -----------
/home/hydro/web2/public:
App root: /home/hydro/web2
Requests in queue: 0
* PID: 1116 Sessions: 0 Processed: 664 Uptime: 16m 29s
CPU: 0% Memory : 28M Last used: 32s ago
* PID: 1123 Sessions: 0 Processed: 625 Uptime: 16m 29s
CPU: 0% Memory : 27M Last used: 32s ago
* PID: 1130 Sessions: 0 Processed: 614 Uptime: 16m 29s
CPU: 0% Memory : 27M Last used: 32s ago
* PID: 2105 Sessions: 0 Processed: 106 Uptime: 33s
CPU: 0% Memory : 23M Last used: 32s ago
* PID: 2112 Sessions: 0 Processed: 103 Uptime: 33s
CPU: 0% Memory : 22M Last used: 32s ago
* PID: 2119 Sessions: 0 Processed: 92 Uptime: 33s
CPU: 0% Memory : 21M Last used: 32s ago
因此,主要问题是:如何在每次进程启动时从Sinatra web应用程序进程启动(RabbitMQ订阅服务器)线程
我希望能够将数据发送到我的web应用程序进程,以便他们可以使用SSE将数据发送回web客户端。我希望每个web应用程序进程有两个线程:Sinatra使用的主线程和我的额外线程来做一些RabbitMQ的事情。还有一个Oracle数据库和一个Erlang后端,但我认为它们与此无关
我还想知道Passenger如何处理Sinatra web应用程序中的流程实例化。多Ruby环境?如果启动了多个进程,该类看起来怎么可能只实例化一次?文件config.ru
(甚至app.rb
)是否仅在启动多个进程时处理一次?我在网上读了很多东西,但是我想不出来
更一般地说,使用Ruby、Nginx、Passenger和Sinatra进行SSE的正确方式是什么
为清晰起见,下文提供了有关Nginx的详细信息
Nginx被配置为站在乘客前面的反向代理,web应用程序在服务器
和位置
下配置,使用SSL和HTTP基本身份验证以及以下指令:
location / {
proxy_buffering off;
proxy_cache off;
proxy_pass_request_headers on;
passenger_set_header Host $http_host;
passenger_set_header X-Real-IP $remote_addr;
passenger_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
passenger_set_header X-Forwarded-Proto $scheme;
passenger_set_header X-Remote-User $remote_user;
passenger_set_header Host $http_host;
passenger_min_instances 3;
proxy_redirect off;
passenger_enabled on;
passenger_ruby /home/hydro/.rbenv/versions/2.3.0/bin/ruby;
passenger_load_shell_envvars on;
passenger_nodejs /usr/bin/nodejs;
passenger_friendly_error_pages on;
}
我认为你目前的架构是错误的。您的Sinatra应用程序不应该与额外的线程混合使用,也不应该仅仅为了向您的客户端发送推送而保持活动状态——您应该有一个单独的推送服务器,专门用于推送消息,并让您的HTTP API做它最擅长的事情——直到收到请求为止 您提到您正在使用nginx,因此我建议您在本模块中进行编译: 现在,您可以摆脱RabbitMQ队列—任何需要将消息推送到推送订阅者之一的进程只需向该模块的RESTful API发送HTTP请求: 示例curl请求:
curl -s -v -X POST 'http://localhost/pub?id=my_channel_1' -d 'Hello World!'
当然,默认情况下,出于安全原因,此模块将只侦听本地主机的请求。我认为您是对的。我对建筑的选择是错误的。我喜欢使用HTTP的独立推送服务器的想法。它很容易与Erlang或Oracle数据库一起使用
curl -s -v -X POST 'http://localhost/pub?id=my_channel_1' -d 'Hello World!'