PHPコードを正しく公開する方法

WBOY
リリース: 2016-06-23 13:04:23
オリジナル
1450 人が閲覧しました

ほぼすべての PHP プログラマーがコードを公開しており、そのコードは ftp または rsync を介して同期したり、svn または git を介して更新したりできます。活発なプロジェクトでは、1 日に数回コードがリリースされることがありますが、詳細に注意を払う人はほとんどいないのが現実で、実際には多くの落とし穴があり、知らないうちに落とし穴にはまっている可能性があります。

適切に実装されたパブリッシング システムは、少なくともアトミック パブリッシングをサポートする必要があります。各バージョンが独立した状態を表す場合、リリース期間中は、すべてのリクエストは単一の状態でのみ実行できます。これは、アトミック リリースのサポートと呼ばれます。逆に、リクエストがリリース中に異なる状態にまたがる場合、それはアトミック リリースとは言えません。例として、a.php と b.php という 2 つの PHP ファイルをリクエストに含める必要があるとします。a.php の組み込みが完了したら、コードを解放し、次に b.php を含めます。が適切に処理されない場合、古いバージョンの a.php と新しいバージョンの b.php が同じリクエスト内に同時に存在する可能性があります。つまり、アトミック リリースが実装されていません。

オープンソースの世界には、Ruby コミュニティの capistrano など、優れたコード公開ツールが多数あります。そのプロセスは、大まかに言うと、コードを新しいディレクトリに公開し、実際のリリース ディレクトリにソフト リンクすることです。

.├── current -> releases/v1└── releases    ├── v1    │   ├── foo.php    │   └── bar.php    └── v2        ├── foo.php        └── bar.php
ログイン後にコピー

ただし、PHP 自体の特殊性を考慮すると、上記のプロセスを単純に適用するだけでは真のアトミック パブリッシングを実現することは困難です。理由を明確にするためには、PHP の 2 つのキャッシュの概念も理解する必要があります:

  • オペコード キャッシュ
  • リアルパス キャッシュ

まずオペコード キャッシュについて話しましょう。以前は誰もが APC を使用していましたが、現在ではほとんどのキャッシュが使用されています。言うまでもなく、誰もがその機能に精通していますが、唯一注意する必要があるのは、apc と zend オペコードではキャッシュ キーの選択肢が異なるということです。apc はファイルの i ノードを選択し、zend オペコードは選択します。ファイルのパスを選択します。

realpath キャッシュについてもう一度話しましょう。その機能は、ほとんどの場合、ファイル情報を取得するための IO 操作をバッファすることであるため、多くの人はその存在を知りません。 realpath キャッシュはプロセス レベルです。つまり、各 php-fpm プロセスには独自の独立した realpath キャッシュがあります。

関連する技術的な詳細は非常に簡単なので、次の情報を注意深く読むことをお勧めします:

  • realpath_cache
  • PHP の OPCache 拡張機能のレビュー
  • Atomic は Etsy にデプロイ
  • シンボリックリンクされたフォルダー内のスクリプトのキャッシュの無効化
でソフト リンク リリース コードを使用する 作業中に通常最初に遭遇する問題は、新しいコードが有効にならないことです。 apc.stat または opcache.validate_timestamps 設定が有効であるかどうか、または apc_clear_cache または opcache_reset メソッドが呼び出されているかどうかに関係なく、php-fpm を再起動すると問題は自然に解決されますが、スクリプト言語にとって再起動は重すぎます。再起動する以外に方法はないのでしょうか?

実際、このような問題が発生する主な理由は、ソフト リンクが新しい場所を指していても、古いデータがまだリアルパス キャッシュに保存されている場合、オペコード キャッシュがリアルパス キャッシュを通じてファイル情報を取得するためです。オペコード キャッシュはまだ新しいコードの存在を認識できません。デフォルトでは、realpath_cache_ttl キャッシュの有効期間は 2 分です。つまり、コードが公開されてから有効になるまでに 2 分かかる場合があります。リリースをできるだけ早く有効にするには、リアルパス キャッシュをプロセス単位でクリアする必要があります:

<?php$key = 'php.pid_' . getmypid();if (($rev = apc_fetch($key)) != DEPLOY_VERSION) {    if($rev < DEPLOY_VERSION) {        apc_store($key, DEPLOY_VERSION);    }        clearstatcache(true);}?>
ログイン後にコピー

これは基本的に apc 環境で動作しますが、zend オペコード環境では問題が発生する可能性があります。 opcache.revalidate_path はデフォルトでオフになっているため、この時点でシンボリック リンクの値がキャッシュされます。そのため、zend オペコードを使用する場合、ソフト リンクは有効になりません。を使用する場合は、状況に応じて opcache.revalidate_path を有効にするのが最善です。

これを分析した後、よく考えてみてください。PHP においてアトミック パブリッシングが厄介な問題である理由は、最終的にはソフト リンクとキャッシュの間の矛盾によるものです。オペコード キャッシュであってもリアルパス キャッシュであっても、これらは PHP に固有のキャッシュ機能であり、客観的なニーズに基づいて回避することはできません。では、ソフト リンクを回避してマジノの防御線にする方法はあるのでしょうか。答えは nginx の $realpath_root です:

fastcgi_param SCRIPT_FILENAME $realpath_root $fastcgi_script_name;fastcgi_param DOCUMENT_ROOT $realpath_root;
ログイン後にコピー

$realpath_root を使用すると、DOCUMENT_ROOT ディレクトリにソフト リンクが含まれている場合でも、nginx はソフト リンクが指す実際のパスを PHP に送信します。つまり、PHP の場合、ソフト リンクはすでに No です。もっと長く存在します!ただし、その代償として、nginx はリクエストごとに比較的高価な IO 操作を通じて $realpath_root の値を取得する必要があります。このプロセスは strace コマンドを通じて監視できます。 以下に、current から foo までのプロセスを示します。

在本例中,压测发现使用 $realpath_root 后,性能下降了大约 5% 左右,不过明眼人一下就能发现,虽然 $realpath_root 导致了 lstat 和 readlink 操作,但是 lstat 操作的次数是和目录深度成正比的,也就是说目录越深,执行的 lstat 次数越多,性能下降也就越大。如果能够降低发布目录的深度,那么可以预计性能下降能够控制在 1% 左右。

结尾介绍一下 Deployer ,它是 PHP 中做得比较好的工具,有很多特色,比如支持并行发布,具体演示如下图,左边是串行,右边是并行,使用「vvv」能得到更详细信息:

deploy

不过 Deployer 在原子发布上有一点瑕疵,具体见 deploy:release 代码:

<?phprun("cd {{deploy_path}} && if [ -h release ]; then rm release; fi");run("ln -s $releasePath {{deploy_path}}/release");?>
ログイン後にコピー

也就是说,在切换软链接的时候,它是先删除再创建,是一个两步操作,理论上如果有请求在这两步中间进入的话,那么将会出现找不到文件的错误。

问题到这里,大部分人会觉得使用「ln -sfn」就好了,实际上也是错误的:

shell> strace ln -sfn releases/foo currentsymlink("releases/foo", "current")      = -1 EEXIST (File exists)unlink("current")                       = 0symlink("releases/foo", "current")      = 0
ログイン後にコピー

通过 strace 我们能清晰的看到,虽然表面上使用「ln -sfn」是一步操作,但是内部依然是按照先删除再创建的逻辑执行的,实际上这里应该搭配使用「ln & mv」:

shell> ln -sfn releases/foo current.tmpshell> mv -fT current.tmp current
ログイン後にコピー

先通过 ln 创建一个临时的软链接,再通过 mv 实现原子操作,此时如果使用 strace 监控,会发现 mv 的「T」选项实际上仅仅执行了一个 rename 操作,所以是原子的。

関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート