Web アプリケーションを開発する場合、データを保存するためにセッションを使用することがよくあります。しかし、PHP では Session を不適切に使用すると同時実行の問題が発生する可能性があることを知らない人もいるかもしれません。インドの医療業界向けソフトウェア ソリューション プロバイダーである Plus91 Technologies のシニア エンジニア、Kishan Gor 氏が個人ブログでこの問題について説明しました。
同じクライアントが複数のリクエストを同時に送信し、各リクエストがセッションを使用する場合、PHP セッション ロックの存在により、サーバーはこれらのリクエストに並列ではなく逐次的に応答します。これは、デフォルトで PHP がファイルを使用してセッション データを保存するためです。新しいセッションごとに、PHP はファイルを作成し、そこにデータを書き込み続けます。したがって、session_start() メソッドが呼び出されるたびに、Session ファイルが開かれ、ファイルの排他ロックが取得されます。このように、サーバー スクリプトがリクエストを処理しており、クライアントがセッションの使用も必要とするリクエストを送信した場合、前のリクエストが処理され、ファイルの排他ロックが解除されるまで、後者のリクエストはブロックされます。ただし、これは同じクライアントからの複数のリクエストにのみ限定されます。つまり、1 つのクライアントからのリクエストが別のクライアントからのリクエストをブロックすることはありません。
スクリプトが短い場合、これは通常問題ありません。ただし、スクリプトの実行に時間がかかると、問題が発生する可能性があります。最新の Web アプリケーション開発では、AJAX テクノロジを使用して複数のリクエストを送信し、同じページ内のデータを取得することが非常に一般的です。これらのリクエストがすべてセッションの使用を必要とする場合、最初のリクエストがサーバーに到着した後にセッション ロックが取得され、他のすべてのリクエストは、相互に依存関係がない場合でも、順番に処理される必要があります。これにより、ページの応答時間が大幅に増加します。
この問題を回避する方法は、session_write_close() メソッドを呼び出して、セッションを使用した直後にセッションを閉じることです。このようにして、現在のスクリプトがまだ処理を待機している場合でも、セッション ロックは解放されます。このメソッドを呼び出した後は、現在のスクリプトはセッションをさらに操作できなくなることに注意してください。
この記事で述べられている問題と意見は、session_start() メソッドを使用した PHP のデフォルトのセッション管理モードにのみ適用されることに注意してください。たとえば、一部のユーザーは、アプリケーションが AWS EC2 でホストされ、DynamoDB が正しく構成されていれば、セッション ロックの問題は発生しないと指摘しました。
サンプルコードを添付します:
セッション.php
-
- final class SessionController extends YafController_Abstract
- {
- public function setUserFileAction()
- {
- session_start();
- $_SESSION['user_name'] = 'xudianyang';
- $_SESSION['user_id '] = '123';
- sleep(3);
- echo json_encode($_SESSION);
- return false;
- }
- public function setLoginFileAction()
- {
- session_start();
- $_SESSION['last_time'] = time();
- echo json_encode($_SESSION);
- return false;
- }
- public functionindexFileAction()
- {
- // Auto Rend View
- }
- public function getSessionFileAction()
- {
- session_start() ;
- var_dump($_SESSION);
- return false;
- }
- public function setUserRedisAction()
- {
- $session = CoreFactory::session();
- $session->set('user_name', 'xudianyang' );
- $session->set('user_id', '123');
- sleep(3);
- echo json_encode($_SESSION);
- return false;
- }
- public function setLoginRedisAction()
- {
- $session = CoreFactory::session();
- $session->set('last_time', time());
-
- echo json_encode($_SESSION);
- return false;
- }
-
- public functionindexRedisAction()
- {
- // 自動レンドビュー
- }
-
- public function getSessionRedisAction()
- {
- $session = CoreFactory::session();
- var_dump($_SESSION);
-
- return false;
- }
- }
-
- indexfile.phtml
-
- 测试セッション并発行锁问题
-
-
-
- $.ajax( {
- URL: "/session/setUserFile",
- type: "get",
- dataType: "json",
- success: function(response){
- console.info(response.last_time);
- }
- });
- setTimeout(function(){
- $.ajax({
- url: "/session/setLoginFile",
- type: "get",
- dataType: "json",
- success: function(response){
- console.info(response .last_time);
- }
- });
- }, 300);
-
- 同時発行起2两个ajax请求
- < /html>
-
- indexredis.phtml
-
- <!doctype html&gt; 8">
-
-
- $.ajax({
- url: "/session/setUserRedis",
- type: "get",
- dataType: "json",
- success: function(response){
- console.info(response.last_time) ;
- }
- });
- setTimeout(function(){
- $.ajax({
- url: "/session/setLoginRedis",
- type: "get",
- dataType: "json",
- success: function(response ){
- console.info(response.last_time);
- }
- });
- }, 300);
-
- 同時発行起2两个ajax请求
-
|