【发布时间】:2023-03-10 17:28:01
【问题描述】:
我当前的设置存在问题,它无法按预期工作,并阻止我进一步开发启用服务器发送事件 (SSE) 的网站。我的主要问题可以在下面以粗体显示,但归结为“如何在乘客设置中从 Sinatra 网络应用程序启动额外线程?”。
我使用乘客 5.0.21 和 Sinatra 1.4.6。该应用程序是作为经典的 Sinatra 应用程序编写的,不是模块化的,但可以根据需要进行更改。
我已将指令 passenger_min_instances 3 放入 Nginx 配置中,以启动至少 3 个 Web 应用程序实例。我在我的 Sinatra 应用程序的 config.ru 文件中有两个 puts,因此当线程启动时,我会在 /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 并对 URL /debug 进行第一次 HTTP GET 访问时,进程被实例化并且其中一个进程为请求提供服务。我在/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
以CLASS 和CONFIGURE 开头的两条消息都打印在同一个线程中。我希望这会像它一样在进程实例化时发生,但它只发生了一次,让我认为Passenger 只触发了一个进程。但是我可以看到passenger-status --verbose 的3 个进程。另一个线程被创建(config.ru)来接收 RabbitMQ 消息。
如您所见,第一个进程已经处理了 1 个请求(为清楚起见而缩短了):
$ passenger-status --verbose
----------- General information -----------
Max pool size : 6
App groups : 1
Processes : 3
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: 1 Uptime: 2m 19s
CPU: 0% Memory : 18M Last used: 2m 19s ago
* PID: 1123 Sessions: 0 Processed: 0 Uptime: 2m 19s
CPU: 0% Memory : 3M Last used: 2m 19s ago
* PID: 1130 Sessions: 0 Processed: 0 Uptime: 2m 19s
CPU: 0% Memory : 2M Last used: 2m 19s ago
发布 RabbitMQ 消息供订阅者接收的 ruby 测试程序有时有效,有时无效。即使在给定时间内没有看到请求,Passenger 也可能会关闭正在运行的进程。日志中不显示任何内容。订阅者线程没有反馈,乘客本身也没有消息。
如果我刷新页面,我会收到 DEBUG 消息和 GET /debug 跟踪。 passenger-status --verbose 表明第一个进程现在已经处理了两个请求。
我在不同的测试中看到,我必须触发大量请求才能让乘客为其他 2 个进程提供服务请求,甚至启动最多 6 个新进程。让我们从同一 LAN 中的另一台机器执行此操作与root@backup:~# ab -A test:test -kc 1000 -n 10000 https://192.168.0.10:445/debug。乘客已启动最多 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 后端,但我认为它们在这里不相关。
我还想知道在 Sinatra Web 应用程序的情况下,Passenger 如何处理进程实例化。多个 Ruby 环境 ?如果启动多个进程,怎么会看起来类只实例化一次?即使启动多个进程,文件config.ru(甚至app.rb)是否只处理一次?我在网上阅读了很多东西,但无法弄清楚。
更一般地说,使用 Ruby、Nginx、Passenger 和 Sinatra 进行 SSE 的正确方法是什么。
为了清楚起见,下面列出了有关 Nginx 的详细信息。
Nginx 被配置为站在Passenger 前面的反向代理,Web 应用程序在server 和location / 下配置,具有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;
}
【问题讨论】:
标签: nginx rabbitmq sinatra passenger server-sent-events