LoginSignup
2
3

More than 5 years have passed since last update.

Railsでコネクションプール② 初心者→中級者へのSTEP24/25

Last updated at Posted at 2018-12-24

Railsでコネクションプール②

はじめに

前回、Mysqlを導入し、軽くconnection_poolについて触れました。
今回は実際にコードと共に確認してみます。

DB設定

設定ファイルは以下の通りでMySQLを使います。そしてプール数は5、

default: &default
  adapter: mysql2
  encoding: utf8
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: root
  password: 秘密
  host: localhost
  connect_timeout: 3

つまり、予想ではDBにアクセスする(クエリを作成する)スレッドを6つ作れば、一つは接続を待たされることになるはず。

スレッドを6つ作ってみる。

  def index
    1.upto(6) {|num|
      Thread.new do
        begin
          p User.find(num).name
        rescue
          p 'error' 
        end
      end
    }
  end

実行すると

Started GET "/users/" for 127.0.0.1 at 2018-12-24 23:09:02 +0900
   (1.1ms)  SET NAMES utf8,  @@SESSION.sql_mode = CONCAT(CONCAT(@@sql_mode, ',STRICT_ALL_TABLES'), ',NO_AUTO_VALUE_ON_ZERO'),  @@SESSION.sql_auto_is_null = 0, @@SESSION.wait_timeout = 2147483
   (1.7ms)  SET NAMES utf8,  @@SESSION.sql_mode = CONCAT(CONCAT(@@sql_mode, ',STRICT_ALL_TABLES'), ',NO_AUTO_VALUE_ON_ZERO'),  @@SESSION.sql_auto_is_null = 0, @@SESSION.wait_timeout = 2147483
   (0.4ms)  SET NAMES utf8,  @@SESSION.sql_mode = CONCAT(CONCAT(@@sql_mode, ',STRICT_ALL_TABLES'), ',NO_AUTO_VALUE_ON_ZERO'),  @@SESSION.sql_auto_is_null = 0, @@SESSION.wait_timeout = 2147483
   (0.3ms)  SET NAMES utf8,  @@SESSION.sql_mode = CONCAT(CONCAT(@@sql_mode, ',STRICT_ALL_TABLES'), ',NO_AUTO_VALUE_ON_ZERO'),  @@SESSION.sql_auto_is_null = 0, @@SESSION.wait_timeout = 2147483
   (0.4ms)  SET NAMES utf8,  @@SESSION.sql_mode = CONCAT(CONCAT(@@sql_mode, ',STRICT_ALL_TABLES'), ',NO_AUTO_VALUE_ON_ZERO'),  @@SESSION.sql_auto_is_null = 0, @@SESSION.wait_timeout = 2147483
Processing by UsersController#index as HTML
  Rendering users/index.html.haml within layouts/application
  Rendered users/index.html.haml within layouts/application (2.3ms)
Completed 200 OK in 30ms (Views: 23.3ms | ActiveRecord: 0.0ms)


  User Load (11.4ms)  SELECT  `users`.* FROM `users` WHERE `users`.`id` = 1 LIMIT 1
  User Load (14.4ms)  SELECT  `users`.* FROM `users` WHERE `users`.`id` = 2 LIMIT 1
"Lilly Littel"
  User Load (19.3ms)  SELECT  `users`.* FROM `users` WHERE `users`.`id` = 3 LIMIT 1
"Noemie Kautzer"
  User Load (19.7ms)  SELECT  `users`.* FROM `users` WHERE `users`.`id` = 4 LIMIT 1
"Lonny Bernier"
"Maryam Ankunding"
  User Load (0.4ms)  SELECT  `users`.* FROM `users` WHERE `users`.`id` = 6 LIMIT 1
"Ottis Schuster"
"error"

予想どうり、一つのスレッドだけ接続できてないですね。ではプール数を6に増やすとどうなるのでしょう。

default: &default
  adapter: mysql2
  encoding: utf8
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 6 } %>
  username: root
  password: yuusuke0476
  host: localhost
  connect_timeout: 3

pool数を設定し直しました。実行してみます。予想通りなら6つのスレッド全てに置いてuserの名前を取得してきてくれるはずです。

   (0.7ms)  SET NAMES utf8,  @@SESSION.sql_mode = CONCAT(CONCAT(@@sql_mode, ',STRICT_ALL_TABLES'), ',NO_AUTO_VALUE_ON_ZERO'),  @@SESSION.sql_auto_is_null = 0, @@SESSION.wait_timeout = 2147483
   (0.5ms)  SET NAMES utf8,  @@SESSION.sql_mode = CONCAT(CONCAT(@@sql_mode, ',STRICT_ALL_TABLES'), ',NO_AUTO_VALUE_ON_ZERO'),  @@SESSION.sql_auto_is_null = 0, @@SESSION.wait_timeout = 2147483
   (1.6ms)  SET NAMES utf8,  @@SESSION.sql_mode = CONCAT(CONCAT(@@sql_mode, ',STRICT_ALL_TABLES'), ',NO_AUTO_VALUE_ON_ZERO'),  @@SESSION.sql_auto_is_null = 0, @@SESSION.wait_timeout = 2147483
   (0.4ms)  SET NAMES utf8,  @@SESSION.sql_mode = CONCAT(CONCAT(@@sql_mode, ',STRICT_ALL_TABLES'), ',NO_AUTO_VALUE_ON_ZERO'),  @@SESSION.sql_auto_is_null = 0, @@SESSION.wait_timeout = 2147483
   (1.3ms)  SET NAMES utf8,  @@SESSION.sql_mode = CONCAT(CONCAT(@@sql_mode, ',STRICT_ALL_TABLES'), ',NO_AUTO_VALUE_ON_ZERO'),  @@SESSION.sql_auto_is_null = 0, @@SESSION.wait_timeout = 2147483
  User Load (3.9ms)  SELECT  `users`.* FROM `users` WHERE `users`.`id` = 6 LIMIT 1
"Ottis Schuster"
  User Load (13.8ms)  SELECT  `users`.* FROM `users` WHERE `users`.`id` = 5 LIMIT 1
"Carter Bednar"
  User Load (13.9ms)  SELECT  `users`.* FROM `users` WHERE `users`.`id` = 3 LIMIT 1
  User Load (14.6ms)  SELECT  `users`.* FROM `users` WHERE `users`.`id` = 2 LIMIT 1
"Noemie Kautzer"
Maryam Ankunding"
  User Load (11.3ms)  SELECT  `users`.* FROM `users` WHERE `users`.`id` = 1 LIMIT 1
"Lilly Littel"

"error"

....あれえぇ?エラーが消えない...てかちゃんとメッセージ出力しましょうね。rescueの部分を下記のように修正

  rescue => e
    p e
  end
  User Load (0.6ms)  SELECT  `users`.* FROM `users` WHERE `users`.`id` = 6 LIMIT 1
"Ottis Schuster"
  User Load (10.6ms)  SELECT  `users`.* FROM `users` WHERE `users`.`id` = 4 LIMIT 1
  User Load (11.9ms)  SELECT  `users`.* FROM `users` WHERE `users`.`id` = 5 LIMIT 1
"Lonny Bernier"
  User Load (1.0ms)  SELECT  `users`.* FROM `users` WHERE `users`.`id` = 2 LIMIT 1
"Carter Bednar"
Maryam Ankunding"

  User Load (1.1ms)  SELECT  `users`.* FROM `users` WHERE `users`.`id` = 1 LIMIT 1
"Lilly Littel"
#<ActiveRecord::ConnectionTimeoutError: could not obtain a connection from the pool within 5.000 seconds (waited 5.004 seconds); all pooled connections were in use>

could not obtain a connection from the pool?connectionが解放されてないっぽい?

スレッドが生きているのかなと思い、状態をみてみる(スレッドを6つ生成してから10秒後)下記を追加。

  sleep 10
  pp Thread.list
 #<Thread:0x007f98e55778c8@/ほにゃらら~~~/reactor.rb:249 sleep>,
 #<Thread:0x007f98e5577710@/ほにゃらら~~/thread_pool.rb:280 sleep>,
   .
   .
   .
   .
 #<Thread:0x007f98e5577710@/ほにゃらら~~/thread_pool.rb:280 sleep>,

ない...つまりスレッドはちゃんと終了している。なのにconnectionが解放されてない。
pool数が反映されない...なぜだ...

〜〜〜〜〜1時間後〜〜〜〜〜

rails再起動したらなおりました!!
これでちゃんと同時接続の確認ができました...
ちなみに今回のように1プロセスに複数のスレッドがあるようなことはほぼほぼ無いので、ご注意を、テストしたかったので強引なコード書いちゃいましたかね...

まとめ

このテーマむずかった...ググってたらRails以外の知識を必要として手こずりました。
ひとまず確認コードがかけてよかったです。connection_poolの実用的なテクニックはもっと知識積んでから勉強します...

明日最後ですね...なにかこ...

2
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
3