簡體   English   中英

確保Rails和Sidekiq不會超過最大數據庫連接

[英]Ensure max database connections is not exceeded with Rails and Sidekiq

我正在使用帶有單線程Rails應用程序的Nginx和Phusion Passenger。 這是捕獲。 在該應用程序中,我使用多線程sidekiq來執行一些后台作業。 通常在我的database.yml中,我只需要將池值設置為1.這是一個例子:

default: &default
  adapter: mysql2
  encoding: utf8
  collation: utf8_unicode_ci
  pool: 1
  username: username
  password: password
  host: localhost

原因是因為每個tcp套接字連接打開,當http請求通過該套接字進入時,nginx將接收請求並將信息傳遞給乘客。 Passenger檢測到它的Rails應用程序,它產生一個Rails實例,它將響應轉換為html,然后發送回nginx,然后傳回給客戶端(瀏覽器)。因此對於每個乘客實例,我只需要一個數據庫連接,使用單線程Rails應用程序。

但是在我的sidekiq.yml中,我將並發設置為5:

:concurrency: 5 

這意味着對於每個乘客機架實例,我將有由sidekiq處理的5個並發線程加上主應用程序的一個連接,即一個乘客實例的總共6個數據庫連接。

當我查看乘客狀態時,我注意到max_pool_size設置為6:

----------- General information -----------
Max pool size : 6

那么這是否意味着乘客不會同時產生超過6個Rails實例? 如果是這樣的話,這是否意味着我的數學是正確的:6(實例)* 6(數據庫連接:5為sidekiq,1為主app)= 36(我的rails應用程序可以同時處理的總數據庫連接)。

現在我的mysql數據庫配置為處理151個最大並發連接。

SHOW VARIABLES LIKE "max_connections";
+-----------------+-------+
| Variable_name   | Value |
+-----------------+-------+
| max_connections | 151   |
+-----------------+-------+

我只是想確保我的數學是正確的乘客,鐵路和sidekiq。

首先,您的Sidekiq流程和您的Web服務器(在您的情況下,Passenger)是分開的。 Passenger的線程池大小對您的Sidekiq並發性沒有影響; 相反,您的Sidekiq配置指定單獨的並發。 所以,我們將分別考慮這兩個:

乘客

ActiveRecord數據庫池值是Web進程將在所有線程中使用的數據庫連接數。 如果您的Passenger服務器設置為多進程模式,則Web進程的最大連接數為db pool size * passenger pool size 另一方面,如果你在多線程模式下設置它(我建議如果可能),你的最大連接只是db pool size (乘以許多進程正在運行;例如,Puma默認運行)兩個進程最多包含15個線程,因此在這種情況下最大連接數為30)。

因此,如果您使用的是多線程模式,則池大小為1是絕對不夠的 - 您至少需要與預期的線程一樣大的池。 在多進程模式中, 1 可能有效,但我懷疑它是否真的值得從默認值5消失,直到遇到問題。

Sidekiq

Sidekiq總是以多線程模式運行(你可以在技術上運行多個進程,但我認為你不是)。 因此,如上所述,您希望連接池至少與線程數一樣大。 這可能意味着您在技術上需要兩個不同的db池值值,具體取決於Rails env是為Passenger啟動還是為Sidekiq啟動 - 請參閱Sidekiq repo上的此問題此有用的Heroku指南 ,了解有關如何使用的更多信息解決這個問題

綜上所述

不要忘記,除了上述所有內容之外,您可以輕松地讓多個服務器都運行相同的Rails應用程序,但只有一個數據庫具有一個連接限制。 如果您在多實例模式下運行Passenger,最多有6個進程,請將數據庫池大小設置為5,然后每個Web服務器節點最多使用30個連接。 如果它正在運行Sidekiq服務器,那么添加5。 您可能不需要多個Sidekiq服務器,因此4個Web節點@30個連接+一個Sidekiq進程@ 5個連接= 125個最大連接,完全在您的MySQL連接限制內。

我再次回顧了Passenger文檔,雖然上面的答案回答了這個問題,但我想補充一點細節:

  • HTTP客戶端通過TCP向Nginx發送請求
  • 加載到Nginx的Phusion Passenger檢查請求是否應由Passenger處理。 如果是,請求將發送到Passenger Core。
  • 使用負載平衡規則的乘客核心確定應將請求轉發到哪個進程。
  • Passenger核心還負責應用程序生成:如果它確定有更多的應用程序進程是必要的或有益的,那么它將根據用戶配置的限制進行:核心永遠不會產生比用戶配置的最大值更多的進程。
  • 客運核心還有監測和統計數據:乘客記憶統計和乘客身份
  • 如果應用程序進程崩潰,則會重新啟動應用程序進程。
  • 如果您沒有將其配置為向聯合站(一種監控Web服務)發送數據,則UstRouter處於空閑狀態並且不會消耗資源
  • Watchdog監控Passenger Core和UstRouter。 如果它們中的任何一個崩潰,它們將由Watchdog重新啟動。

    passenger-memory-stats將驗證上述三個進程以及衍生的機架應用程序:

 ------ Passenger processes ------ PID VMSize Private Name --------------------------------- 18355 419.1 MB ? Passenger watchdog 18358 1096.5 MB ? Passenger core 18363 427.2 MB ? Passenger ust-router 18700 818.9 MB 256.2 MB Passenger RubyApp: myapp_rack_rails 24783 686.9 MB 180.2 MB Passenger RubyApp: myapp_rack_rails 

乘客狀態顯示max_pool_size為6.也就是說,乘客核心最多會產生6個機架應用程序:

----------- General information -----------
Max pool size : 6
App groups    : 2
Processes     : 3

如另一個答案所述,ActiveRecord數據庫池值是Web進程將在所有線程中使用的數據庫連接數。

但由於我使用的是在多進程模式下設置的免費Passenger服務器,因此我的Web進程的最大連接數是db pool size *乘客池大小。 因此,由於乘客池大小為6,如果我的數據庫池大小為1,則為6 * 1 = 6.這將是6個最大數據庫連接。

Sidekiq始終以多線程模式運行。

如果有人想使用sidekiq,他們必須配置他們想要運行的線程數或使用默認值(25)。 如果他們正在使用數據庫(可能)然后沒有遇到連接超時錯誤,他們將需要在其數據庫池中至少具有與sidekiq線程一樣多的連接。 目前,他們必須在兩個不同的位置配置這兩個值,數據庫池在database.yml中用於ActiveRecord,而sidekiq連接可以通過命令行或sidekiq yml文件。 這是一個問題,因為當您修改需要修改兩個值的一個值時很難記住。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM