#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の実用的なテクニックはもっと知識積んでから勉強します...
明日最後ですね...なにかこ...