Skip to content

Commit 57f00ec

Browse files
committed
Improve docs on Persistent (DB) Connections
php/doc-en@e7e4ffe
1 parent 63e8fdc commit 57f00ec

File tree

2 files changed

+193
-75
lines changed

2 files changed

+193
-75
lines changed
Lines changed: 182 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<!-- $Revision$ -->
3-
<!-- EN-Revision: 0799f7789c50a11b746ad713cc8787e4b04dd926 Maintainer: hirokawa Status: ready -->
4-
<!-- CREDITS: shimooka,mumumu -->
3+
<!-- EN-Revision: e7e4ffe9a10a4dcd9903a7abf125a811d0eda023 Maintainer: mumumu Status: ready -->
54
<chapter xml:id="features.persistent-connections" xmlns="http://docbook.org/ns/docbook">
65
<title>持続的データベース接続</title>
76

7+
<simplesect>
8+
<title>持続的データベース接続って何?</title>
89
<simpara>
910
持続的接続は、スクリプトの実行終了時にも閉じられないリンクです。
1011
持続的接続が要求された時、PHPは(前もってオープンされたままになって
@@ -15,20 +16,32 @@
1516
す。
1617
</simpara>
1718
<simpara>
18-
Webサーバーの動作及び負荷の分散に関して熟知していない人は、持続的接
19-
続において何が行われないかに関してミスを犯す可能性があります。特に、
20-
持続的接続は、同じリンクで'ユーザーセッション'をオープンする機能
21-
やトランザクションを効率的に確立する機能やその他のあらゆる機能を提
22-
供<emphasis>しません</emphasis>。つまり、言いたいことを極めて簡単に述べると、持続的接続
23-
は非持続的接続で使用できない <emphasis>いかなる</emphasis> 機能も提
24-
供しません。
19+
特性の接続を要求する方法はありませんし、
20+
既存の接続と新しい接続のどちらを取得できるかを保証する方法もありません。
21+
(すべての接続が使用中の場合や、
22+
リクエストが別の接続プールを持つ、
23+
別のワーカーによって処理される場合があります)
2524
</simpara>
2625
<simpara>
27-
なぜ?
26+
つまり、PHP の持続的接続が使えない場合があるということです。
27+
たとえば以下の場合です:
2828
</simpara>
29+
<simplelist>
30+
<member>特定のデータベースセッションを、特定のWebユーザーに割り当てる場合</member>
31+
<member>複数のリクエストにまたがる、巨大なトランザクションを生成する場合</member>
32+
<member>あるリクエストでクエリを発行し、クエリの結果を別のリクエストで収集する場合</member>
33+
</simplelist>
2934
<simpara>
30-
これは、Webサーバーの動作により行われるべきものです。Webページを生
31-
成するためにPHPを利用するWebサーバーには、3種類の方法があります。
35+
持続的接続は、
36+
持続的でない接続にできない機能は <emphasis>全く</emphasis>
37+
提供しません。
38+
</simpara>
39+
</simplesect>
40+
41+
<simplesect xml:id="persistent-connections.web">
42+
<title>Webリクエスト</title>
43+
<simpara>
44+
Webサーバーを PHP と統合し、Webページを生成させる方法はふたつあります:
3245
</simpara>
3346
<simpara>
3447
最初は、CGI "ラッパー"としてPHPを使用する方法です。このように実行し
@@ -40,9 +53,10 @@
4053
続しないのです。
4154
</simpara>
4255
<simpara>
43-
2番目は、最も一般的ですが、PHPをマルチプロセスWebサーバー(現在は
44-
Apacheのみが含まれます)のモジュールとして実行する方法です。マルチプ
45-
ロセスサーバーは、通常、実際にWebページを送信する複数のプロセス(子)
56+
2番目は、最も一般的ですが、PHP を PHP-FPM か、
57+
マルチプロセスWebサーバー(現在はApacheのみが含まれます)
58+
のモジュールとして実行する方法です。
59+
マルチプロセスサーバーは、通常、実際にWebページを送信する複数のプロセス(子)
4660
を管理するプロセス(親)を有しています。リクエストがクライアントから
4761
来ると、親プロセスは、他のクライアントにすでに送信を行っていないク
4862
ライアントの一つに渡します。このため、同じクライアントが2番目のリク
@@ -52,76 +66,167 @@
5266
それぞれのページは SQL サーバーへの確立された接続を再利用することが
5367
できます。
5468
</simpara>
69+
<note>
70+
<para>
71+
Webリクエスト で使用されているメソッドを確認するには、
72+
<function>phpinfo</function> の出力における "Server API" の値、
73+
または Webリクエスト から実行した <constant>PHP_SAPI</constant>
74+
の値を確認してください。
75+
</para>
76+
<para>
77+
サーバーAPI が "Apache 2 Handler" や "FPM/FastCGI" の場合、
78+
持続的接続は同じワーカーで処理されるリクエスト間で使われます。
79+
これら以外の値の場合、
80+
持続的接続はそれぞれのリクエストを処理したあとは持続しません。
81+
</para>
82+
</note>
83+
</simplesect>
84+
85+
<simplesect xml:id="persistent-connections.cli">
86+
<title>コマンドラインのプロセス</title>
5587
<simpara>
56-
最後の方法は、PHPをマルチスレッドWebサーバーのプラグインとして使用する
57-
方法です。現在、PHP は、WSAPI, NSAPI を(Windows上で)サポー
58-
トしており、Netscape FastTrack、Microsoftの Internet Information
59-
Server (IIS)、O'Reillyの WebSite Proのようなマルチスレッド型サーバー
60-
のプラグインとしてPHPを使用することが可能です。この場合の動作は前記
61-
のマルチプロセス型モデルと同様です
62-
</simpara>
63-
<simpara>
64-
持続的接続が機能を全く付加しないとしたら、優れている点はなんでしょう?
88+
コマンドラインから実行する PHP は、
89+
スクリプトごとに新しいプロセスを使います。
90+
持続的接続は、コマンドラインから実行するスクリプト間では共有されません。
91+
よって、cron やコマンドからのような一時的なスクリプトから、
92+
持続的接続を使ってもなんの役にも立ちません。
93+
とはいっても、役に立つ場面はあるかもしれません
94+
たとえば、たくさんのリクエストや、
95+
個別のタスクがそれぞれのデータベース接続を必要とする多数のタスクを処理する
96+
アプリケーションサーバーを書いている場合が挙げられます。
6597
</simpara>
98+
</simplesect>
99+
100+
<simplesect xml:id="persistent-connections.why">
101+
<title>持続的接続をなぜ使うのか?</title>
66102
<simpara>
67-
答えはかなり簡単です。効率です。持続的接続は、SQLサーバーへ接続する
68-
オーバーヘッドが大きい場合には有効です。このオーバーヘッドが実際に
69-
大きいがどうかは様々な要因に依存します。例えば、データベースの種類、
70-
Webサーバーが動作するのと同じコンピューターで動作しているか、SQLサー
71-
バーを動作させているマシンの負荷、等となります。肝心なのは、接続の
72-
オーバーヘッドが高い場合、持続的接続は著しいということです。持続的
73-
接続は、SQLサーバーへの接続を要求するページをリクエスト毎に処理する
103+
持続的接続は、SQLサーバーへ接続するオーバーヘッドが大きい場合には有効です。
104+
このオーバーヘッドが実際に大きいがどうかは様々な要因に依存します。
105+
例えば、データベースの種類、
106+
Webサーバーが動作するのと同じコンピューターで動作しているか、S
107+
QLサーバーを動作させているマシンの負荷、等となります。
108+
肝心なのは、接続のオーバーヘッドが高い場合、
109+
持続的接続は著しく効果があるということです。
110+
持続的接続は、SQLサーバーへの接続を要求するページをリクエスト毎に処理する
74111
代わりに子プロセスが動作中の間一回しかサーバーへの接続を行わないよ
75112
うにします。このことは、持続的接続をオープンしたプロセス毎にサーバー
76113
への持続的接続をオープンするということになります。例えば、20の異なっ
77114
た子プロセスがSQLサーバーへの持続的接続を行うスクリプトを実行した場
78115
合、各子プロセス毎にSQLサーバーへの20の異なった接続が行われます。
79116
</simpara>
117+
</simplesect>
118+
119+
<simplesect xml:id="persistent-connections.drawbacks.conn-limits">
120+
<title>ありうる欠点: 接続数の上限</title>
121+
<simpara>
122+
しかし、データベースへの接続数を制限して使用している場合に、
123+
持続的な子プロセスの接続数がその数を超えるる場合は、
124+
持続的接続には気をつけたほうが良い欠点がいくつかあります。
125+
もしデータベースの同時接続数の制限が16だとして、
126+
サーバーに多くのアクセスがあったため、
127+
17個の子プロセスが接続しようとするとそのうちの一つは接続に失敗します。
128+
もしスクリプトにコネクションをシャットダウンしないようなバグ
129+
(例えば無限ループ)があると16程度の同時接続しか許容しないデータベース
130+
はすぐにダメになってしまいます。
131+
</simpara>
132+
<simpara>
133+
持続的接続は通常、特定の時点で開く接続数を増加させます。
134+
これはアイドル状態のワーカーが、
135+
以前処理したリクエスト用の接続を保持し続けるためです。
136+
リクエストの急増に対応するために多数のワーカーが起動された場合、
137+
それらのワーカーが開いた接続は、
138+
ワーカーが終了するかデータベースサーバーが接続を閉じるまで残ります。
139+
</simpara>
140+
<simpara>
141+
データベースサーバーが許可する最大接続数が、
142+
Webリクエストワーカーの最大数(それに cron
143+
ジョブや管理接続などのその他の使用分を加えた数)
144+
よりも大きいことを確認してください。
145+
</simpara>
146+
<simpara>
147+
放棄された接続や、アイドル状態の接続(タイムアウト)の処理方法について、
148+
データベースのドキュメントで確認してください。
149+
タイムアウトを長く設定すると、
150+
同時に開かれる持続的接続の数が大幅に増加する可能性があります。
151+
</simpara>
152+
</simplesect>
153+
154+
<simplesect xml:id="persistent-connections.drawbacks.state">
155+
<title>Potential Drawbacks: Maintaining Connection State</title>
80156
<simpara>
81-
しかし、気をつけなければならないことが一つあります。それはデータ
82-
ベースへの接続数を制限して使用している場合に、持続的な子プロセスの
83-
接続数がその数を超えると問題が発生し得ることです。もしデータベース
84-
の同時接続数の制限が16だとして、サーバーに多くのアクセスがあったため
85-
17個の子プロセスが接続しようとするとそのうちの一つは接続に失敗しま
86-
す。もしスクリプトにコネクションをシャットダウンしないようなバグ(
87-
例えば無限ループ)があると16程度の同時接続しか許容しないデータベース
88-
はすぐにダメになってしまいます。使用しているデータベースが、中断さ
89-
れた、もしくは使用されていないコネクションをどのように扱うかを確認
90-
してみてください。
91-
</simpara>
92-
<warning>
93-
<simpara>
94-
持続的接続を使用する際にはまだいくつか心に留めておく必要がある注意
95-
点があります。一つは持続的接続でテーブルをロックする場合にスクリプト
96-
が何らかの理由でロックを外し損ねると、それ以降に実行されるスクリプト
97-
がその接続を使用すると永久にブロックしつづけてしまい、ウェブサーバーか
98-
データベースサーバーを再起動しなければならなくなるということです。もう
99-
一つはトランザクションを使用している場合に、トランザクションブロック
100-
が終了する前にスクリプトが終了してしまうと、そのブロックは次に同じ接
101-
続を使用して実行されるスクリプトに引き継がれる、ということです。
102-
どちらの場合でも
103-
<function>register_shutdown_function</function>を使用してテーブルの
104-
ロックを解除したりトランザクションをロールバックする簡単なクリーン
105-
アップ関数を登録することができます。しかしそれよりも良い方法は、テー
106-
ブルロックやトランザクションを使用するスクリプトでは持続的接続を使用
107-
せず、問題を完全に避けて通ることです(他の箇所で使用する分には問題あ
108-
りません)。
109-
</simpara>
110-
</warning>
111-
<simpara>
112-
重要なことをまとめます。持続的接続は、標準的な接続に1対1の割りつけ
113-
を行うように設計されています。このことは、<emphasis>常に</emphasis>
114-
持続的接続を非持続的接続で置きかえ、かつ動作を変更しないということ
115-
ができることを意味します。持続的接続は、スクリプトの効率を変える
116-
<emphasis>かもしれません</emphasis>(おそらく変えます)が、動作は変更しません!
117-
</simpara>
118-
<para>
119-
<function>ibase_pconnect</function>, <function>ociplogon</function>,
120-
<function>odbc_pconnect</function>, <function>oci_pconnect</function>,
121-
<function>pfsockopen</function>, <function>pg_pconnect</function>
122-
も参照ください。
123-
</para>
157+
一部のデータベース拡張モジュールは、
158+
接続が再利用される際にクリーンアップを自動的に実行します。
159+
このクリーンアップのタスクを、
160+
アプリケーション開発者の裁量に委ねる拡張モジュールもあります。
161+
選択したデータベース拡張モジュールとアプリケーション設計によっては、
162+
スクリプト終了前に手動でのクリーンアップが必要になる場合があります。
163+
接続を予期しない状態に陥らせる可能性のある変更には以下が含まれます:
164+
</simpara>
165+
<simplelist>
166+
<member>データベースの選択 / デフォルトのデータベース</member>
167+
<member>テーブルロック</member>
168+
<member>未コミットのトランザクション</member>
169+
<member>一時テーブル</member>
170+
<member>プロファイリングのような、特定の設定や機能を有効にした接続</member>
171+
</simplelist>
172+
<simpara>
173+
クリーンアップが行われていない、
174+
または閉じられていないテーブルロックやトランザクションは、
175+
他のクエリが無限にブロックされる原因となるほか、
176+
その後の接続の再利用によって予期しない変更が生じる可能性があります。
177+
</simpara>
178+
<simpara>
179+
誤ったデータベースが選択されている場合、
180+
その後の接続の再利用ではクエリが期待通りに実行できなくなります
181+
(スキーマが十分に類似している場合、
182+
誤ったデータベース上でクエリが実行される可能性があります)。
183+
</simpara>
184+
<simpara>
185+
一時テーブルがクリーンアップされない場合、
186+
後続のリクエストでは同じテーブルを再作成できません。
187+
</simpara>
188+
<simpara>
189+
クリーンアップは、クラスのデストラクタまたは
190+
<function>register_shutdown_function</function>を使用して実装できます。
191+
また、クリーンアップの機能を組み込んだ、
192+
専用の接続プールプロキシの使用も検討するとよいでしょう。
193+
</simpara>
194+
</simplesect>
195+
196+
<simplesect xml:id="persistent-connections.final-words">
197+
<title>おわりに</title>
198+
<simpara>
199+
既に述べた持続的接続の振る舞いと、あり得る欠点を考慮すると、
200+
持続的接続を使う場合は、必ず慎重に検討を行うべきです。
201+
持続的接続を使う場合は、
202+
アプリケーションを追加で変更し、
203+
データベースサーバーとWebサーバーおよび/またはPHP-FPMを慎重に設定すべきです。
204+
</simpara>
205+
<simpara>
206+
サーバーへ接続するオーバーヘッドの原因を調査・修正する別の代替案
207+
(例:データベースサーバーへのDNS逆引きの無効化)や、
208+
専用の接続プールプロキシを検討してください。
209+
</simpara>
210+
<simpara>
211+
高トラフィックのWeb APIについては、代替のランタイムや、
212+
長時間実行可能なアプリケーションサーバーの使用を検討してください。
213+
</simpara>
214+
</simplesect>
124215

216+
<simplesect role="seealso" xml:id="persistent-connections.seealso">
217+
&reftitle.seealso;
218+
<para>
219+
<simplelist>
220+
<member><function>ibase_pconnect</function></member>
221+
<member><function>oci_pconnect</function></member>
222+
<member><function>odbc_pconnect</function></member>
223+
<member><function>pfsockopen</function></member>
224+
<member><function>pg_connect</function></member>
225+
<member><link linkend="mysqli.persistconns">MySQLi and Persistent Connections</link></member>
226+
<member><link linkend="pdo.connections">PDO Connection Management</link></member>
227+
</simplelist>
228+
</para>
229+
</simplesect>
125230
</chapter>
126231

127232
<!-- Keep this comment at the end of the file
@@ -140,4 +245,7 @@ sgml-exposed-tags:nil
140245
sgml-local-catalogs:nil
141246
sgml-local-ecat-files:nil
142247
End:
248+
vim600: syn=xml fen fdm=syntax fdl=2 si
249+
vim: et tw=78 syn=sgml
250+
vi: ts=1 sw=1
143251
-->

reference/pdo/connections.xml

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<!-- $Revision$ -->
3-
<!-- EN-Revision: d861a1bcea24f05e52e4938c1ecdf9d70326d7aa Maintainer: takagi Status: ready -->
3+
<!-- EN-Revision: e7e4ffe9a10a4dcd9903a7abf125a811d0eda023 Maintainer: takagi Status: ready -->
44
<!-- CREDITS: hirokawa,shimooka,mumumu -->
55

66
<chapter xml:id="pdo.connections" xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink">
@@ -137,6 +137,16 @@ $dbh = new PDO('mysql:host=localhost;dbname=test', $user, $pass, array(
137137
そのドライバは持続的な接続を使用しません。
138138
</para>
139139
</note>
140+
<warning>
141+
<para>
142+
PDO は、持続的接続のクリーンアップを一切行いません。
143+
一時テーブル、ロック、トランザクション、その他の状態依存の変更が、
144+
接続の以前の使用から残存し、予期せぬ問題を引き起こす可能性があります。
145+
詳細については、
146+
<link linkend="features.persistent-connections">持続的データベース接続</link>
147+
を参照ください。
148+
</para>
149+
</warning>
140150
<note>
141151
<para>
142152
PDO ODBC ドライバを使用しており、ODBC ライブラリが ODBC

0 commit comments

Comments
 (0)