2015-12-30 28 views
1

我的當前設置存在問題,它不像預期的那樣工作,並且阻止我進一步擁有服務器(SSE)啓用的網站。我的主要問題可以在下面以粗體顯示,但歸結爲「我如何從Passenger設置中的Sinatra Web應用程序啓動額外的線程?」。乘客,Sinatra,Nginx,RabbitMQ和SSE(乘客啓動過程以及Ruby線程在圖片中的位置)

我使用Passenger 5.0.21和Sinatra 1.4.6。該應用程序被編寫爲經典的Sinatra應用程序,不是模塊化的,但可以根據需要進行更改。

我已將指令passenger_min_instances 3置於Nginx配置中,以啓動至少3個啓動的web應用程序實例。我有兩個putsconfig.ru文件我的末日應用程序,以便當線程啓動我進去/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是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的,使第一HTTP GET訪問URL /debug,該過程被實例化和的一個進程服務於請求。我在/var/log/nginx/passenger.log中得到什麼?

(CLASS)... Inside thread #<Thread:0x007fb29f4ca258 run> 
(CONFIGURE)... Inside thread #<Thread:0x007fb29f4ca258 run> 
[* #<Thread:[email protected]:68 run>] Waiting for logs. To exit press CTRL+C 
(DEBUG)... Inside thread #<Thread:[email protected]/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 

開始CLASSCONFIGURE兩個消息都被印刷在同一線程內。我預計這會發生在流程實例化時間,但它只發生一次,這讓我認爲乘客只會觸發一個流程。但是我可以看到3個進程passenger-status --verbose。創建另一個線程(在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的消息。也許Passenger關閉了正在運行的流程,即使它在特定時間內沒有看到請求。日誌中沒有顯示任何內容。沒有來自訂閱者線程的反饋,沒有來自Passenger本身的消息。

如果我刷新頁面,我會得到DEBUG消息和GET /debug跟蹤。 passenger-status --verbose顯示第一個進程現在已經處理了兩個請求。

我在我的不同測試中看到,我必須發出很多請求來使其他2個進程發出Passenger serve請求,甚至啓動新進程最多6個。讓我們從另一臺機器局域網與
[email protected]:~# ab -A test:test -kc 1000 -n 10000 https://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 

所以,主要的問題是:我怎麼可以發動(RabbitMQ的用戶)線程從西納特拉Web應用程序每次開始處理時?

我希望能夠將數據發送到我的Web應用程序進程,以便他們可以使用SSE將其發送回Web客戶端。我想每個Web應用程序進程有兩個線程:Sinatra使用的主線程和我的額外線程來執行一些RabbitMQ內容。還有一個Oracle數據庫和一個Erlang後端,但我不認爲它們在這裏相關。

我也想知道Passenger如何在Sinatra Web應用程序的情況下處理進程實例。多個Ruby環境?如果多個進程啓動時,它看起來像只實例化了一次類似的情況呢?即使啓動多個進程,文件config.ru(甚至app.rb)是否僅處理一次?我在網上閱讀了很多東西,但無法弄清楚。

更一般地說,用Ruby,Nginx,Passenger和Sinatra做SSE的正確方法是什麼。

有關Nginx的詳細信息已在下面進行了闡述。

Nginx的配置爲在乘客前方一個反向代理的地位和Web應用程序serverlocation /下使用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; 
} 

回答

1

我覺得你目前的架構是錯的。您的Sinatra應用程序不應該與額外的線程混合在一起,或保持活動狀態,以便它可以發送推送給您的客戶 - 您應該有一個專用於推送消息的單獨推送服務器,並讓您的HTTP API執行最好的功能 - 睡覺,直到收到請求。

你提到你正在使用nginx的,所以我真的建議在此模塊中編譯:

https://github.com/wandenberg/nginx-push-stream-module

現在你可以擺脫你的RabbitMQ隊列 - 需要將任何進程消息給你推送的用戶之一隻需要發送一個HTTP請求到該模塊的REST API:

例捲曲要求:

curl -s -v -X POST 'http://localhost/pub?id=my_channel_1' -d 'Hello World!' 

當然,默認情況下,出於安全原因,該模塊僅會偵聽來自本地主機的請求。

+0

我認爲你是對的。我選擇的建築是錯誤的。我喜歡單獨推送服務器談論HTTP的想法。 Erlang或Oracle數據庫很容易使用。 – lkuty

+0

我還發現[nchan模塊](https://www.nginx.com/resources/wiki/modules/Nchan/) – lkuty