av手机免费在线观看,国产女人在线视频,国产xxxx免费,捆绑调教一二三区,97影院最新理论片,色之久久综合,国产精品日韩欧美一区二区三区

php語言

如何正確發(fā)布PHP代碼

時(shí)間:2025-01-11 08:17:24 php語言 我要投稿
  • 相關(guān)推薦

如何正確發(fā)布PHP代碼

  幾乎每一個(gè) PHP 程序員都發(fā)布過代碼,可能是通過 ftp 或者 rsync 同步的,也可能是通過 svn 或者 git 更新的。一個(gè)活躍的項(xiàng)目可能每天都要發(fā)布若干次代碼,但是現(xiàn)實(shí)卻是很少有人注意其中的細(xì)節(jié),實(shí)際上這里面有好多坑,很可能你就在坑中卻渾然不知。下面是小編為大家?guī)淼年P(guān)于如何正確發(fā)布PHP代碼的知識(shí),歡迎閱讀。

  如何正確發(fā)布PHP代碼

  一個(gè)正確實(shí)現(xiàn)的發(fā)布系統(tǒng)至少應(yīng)該支持原子發(fā)布。如果說每一個(gè)版本都表示一個(gè)獨(dú)立的狀態(tài)的話,那么在發(fā)布期間,任何一次請(qǐng)求只能在單一狀態(tài)下被執(zhí)行。 如此稱之為支持原子發(fā)布;反之如果在發(fā)布期間,一次請(qǐng)求跨越不同的狀態(tài),那么就不能稱之為原子發(fā)布。我們不妨舉個(gè)例子來說明一下:假設(shè)一次請(qǐng)求需要 include 兩個(gè) PHP 文件,分別是 a.php 和 b.php,當(dāng) include a.php 完成后,發(fā)布代碼,接著 include b.php,如果處理不當(dāng)?shù)脑,那么就可能?huì)導(dǎo)致舊版本的 a.php 和新版本的 b.php 同時(shí)存在于同一個(gè)請(qǐng)求之中,換句話說就是沒有實(shí)現(xiàn)原子發(fā)布。

  開源世界里有很多不錯(cuò)的發(fā)布代碼工具,比如 ruby 社區(qū)的 capistrano,其流程大致就是發(fā)布代碼到一個(gè)全新的目錄,然后再軟鏈接到真正的發(fā)布目錄。

  .

  ├── current -> releases/v1

  └── releases

  ├── v1

  │   ├── foo.php

  │   └── bar.php

  └── v2

  ├── foo.php

  └── bar.php

  不過鑒于 PHP 本身的特殊性,如果只是簡(jiǎn)單套用上面的流程,那么將很難實(shí)現(xiàn)真正的原子發(fā)布。要理清個(gè)中緣由,還需要了解一下 PHP 中的兩個(gè) Cache 的概念:

  opcode cache

  realpath cache

  先聊聊 opcode cache,基本就是 apc 或者 zend opcode,關(guān)于它的作用,大家都已經(jīng)很熟悉,不必多言,需要注意的是 apc 的 bug 很多,比如開啟了 apc.enable_cli 配置后就會(huì)有很多靈異問題,所以說 opcode cache 還是盡可能使用 zend opcache 吧,如果需要緩存數(shù)據(jù),可以用 apcu。此外 apc 和 zend opcode 對(duì)緩存鍵的選擇有所差異:apc 選擇的是文件的 inode,zend opcode 選擇的是文件的 path。

  再聊聊 realpath cache,它的作用是緩沖獲取文件信息的 IO 操作,大多數(shù)時(shí)候它對(duì)我們而言是透明的,以至于很多人都不知道它的存在,需要注意的是 realpath cache 是進(jìn)程級(jí)別的,也就是說,每一個(gè) php-fpm 進(jìn)程都有自己獨(dú)立的 realpath cache。

  假設(shè)在發(fā)布代碼期間,opcode cache 或者 realpath cache 里的數(shù)據(jù)出現(xiàn)過期,那么就會(huì)出現(xiàn)一部分緩存是舊文件,一部分緩存是新文件的非原子發(fā)布的情況,為了避免出現(xiàn)這種情況,我們應(yīng)該保證緩存過期時(shí)間足夠長(zhǎng),最 好是除非我們手動(dòng)刷新,否則永遠(yuǎn)不過期,對(duì)應(yīng)到配置上就是:關(guān)閉 apc.stat、opcache.validate_timestamps 配置,設(shè)置足夠大的 realpath_cache_size、realpath_cache_ttl 配置,必要的監(jiān)控總是有好處的。

  相關(guān)的技術(shù)細(xì)節(jié)特別瑣碎,建議大家仔細(xì)閱讀如下資料:

  realpath_cache

  PHP’s OPCache extension review

  Atomic deploys at Etsy

  Cache invalidation for scripts in symlinked folders

  在采用軟鏈接發(fā)布代碼的時(shí)候,通常遇到的第一個(gè)問題多半是新代碼不生效!即便調(diào)用了 apc_clear_cache 或者 opcache_reset 方法也無效,重啟 php-fpm 自然是能夠解決問題,不過對(duì)腳本語言來說重啟太重了!難道除了重啟就沒有別的.辦法了么?

  BTW:如果需要手動(dòng)重置 opcode cache,需要注意的是因?yàn)樗腔?SAPI 的概念,所以不能直接在命令行下調(diào)用 apc_clear_cache 或者 opcache_reset 方法來重置緩存,當(dāng)然辦法總是有的,那就是使用 CacheTool 在命令行下模擬 fastcgi 請(qǐng)求。

  事實(shí)上之所以會(huì)出現(xiàn)這樣的問題,主要是因?yàn)?opcode cache 是通過 realpath cache 獲取文件信息,即便軟鏈接已經(jīng)指向了新位置,但是如果 realpath cache 里還保存著舊數(shù)據(jù)的話,opcode cache 依然無法知道新代碼的存在,缺省情況下,realpath_cache_ttl 緩存有效期是兩分鐘,這意味著發(fā)布代碼后,可能要兩分鐘才能生效。為了讓發(fā)布盡快生效,需要以進(jìn)程為單位清除 realpath cache:

  <?php

  $key = 'php.pid_' . getmypid();

  if (($rev = apc_fetch($key)) != DEPLOY_VERSION) {

  if($rev < DEPLOY_VERSION) {

  apc_store($key, DEPLOY_VERSION);

  }

  clearstatcache(true);

  }

  ?>

  如此在 apc 環(huán)境下基本就能工作了,但是在 zend opcode 環(huán)境下還可能有問題。因?yàn)樵谌笔∏闆r下 opcache.revalidate_path 是關(guān)閉的,此時(shí)會(huì)緩存符號(hào)鏈接的值,這會(huì)導(dǎo)致即便軟鏈接指向修改了,也永遠(yuǎn)無法生效,所以在使用 zend opcode 的時(shí)候,如果使用了軟鏈接,視情況可能需要把 opcache.revalidate_path 激活。

  分析到這里,我們不妨反思一下:在 PHP 中原子發(fā)布之所以是一個(gè)棘手的問題,歸根結(jié)底是因?yàn)檐涙溄雍途彺嬷g的的矛盾。不管是 opcode cache 還是 realpath cache,都是 PHP 固有的緩存特性,基于客觀需要無法繞開,如此說來是否有辦法繞開軟鏈接,使其成為馬奇諾防線呢?答案是 nginx 的 $realpath_root:

  fastcgi_param SCRIPT_FILENAME $realpath_root $fastcgi_script_name;

  fastcgi_param DOCUMENT_ROOT $realpath_root;

  有了 $realpath_root,即便 DOCUMENT_ROOT 目錄中含有軟鏈接,nginx 也會(huì)把軟鏈接指向的真正的路徑發(fā)給 PHP,也就是說,對(duì) PHP 而言,軟鏈接已經(jīng)不存在了!不過作為代價(jià),每一次請(qǐng)求,nginx 都要通過相對(duì)昂貴的 IO 操作獲取 $realpath_root 的值,通過 strace 命令我們能監(jiān)控這一過程,下圖從 current 到 foo 的過程:

  realpath

  在本例中,壓測(cè)發(fā)現(xiàn)使用 $realpath_root 后,性能下降了大約 5% 左右,不過明眼人一下就能發(fā)現(xiàn),雖然 $realpath_root 導(dǎo)致了 lstat 和 readlink 操作,但是 lstat 操作的次數(shù)是和目錄深度成正比的,也就是說目錄越深,執(zhí)行的 lstat 次數(shù)越多,性能下降也就越大。如果能夠降低發(fā)布目錄的深度,那么可以預(yù)計(jì)性能下降能夠控制在 1% 左右。

  結(jié)尾介紹一下 Deployer,它是 PHP 中做得比較好的工具,有很多特色,比如支持并行發(fā)布,具體演示如下圖,左邊是串行,右邊是并行,使用「vvv」能得到更詳細(xì)信息:

  deploy

  不過 Deployer 在原子發(fā)布上有一點(diǎn)瑕疵,具體見 deploy:release 代碼:

  <?php

  run("cd {{deploy_path}} && if [ -h release ]; then rm release; fi");

  run("ln -s $releasePath {{deploy_path}}/release");

  ?>

  也就是說,在切換軟鏈接的時(shí)候,它是先刪除再創(chuàng)建,是一個(gè)兩步操作,理論上如果有請(qǐng)求在這兩步中間進(jìn)入的話,那么將會(huì)出現(xiàn)找不到文件的錯(cuò)誤。

  問題到這里,大部分人會(huì)覺得使用「ln -sfn」就好了,實(shí)際上也是錯(cuò)誤的:

  shell> strace ln -sfn releases/foo current

  symlink("releases/foo", "current")      = -1 EEXIST (File exists)

  unlink("current")                       = 0

  symlink("releases/foo", "current")      = 0

  通過 strace 我們能清晰的看到,雖然表面上使用「ln -sfn」是一步操作,但是內(nèi)部依然是按照先刪除再創(chuàng)建的邏輯執(zhí)行的,實(shí)際上這里應(yīng)該搭配使用「ln & mv」:

  shell> ln -sfn releases/foo current.tmp

  shell> mv -fT current.tmp current

  先通過 ln 創(chuàng)建一個(gè)臨時(shí)的軟鏈接,再通過 mv 實(shí)現(xiàn)原子操作,此時(shí)如果使用 strace 監(jiān)控,會(huì)發(fā)現(xiàn) mv 的「T」選項(xiàng)實(shí)際上僅僅執(zhí)行了一個(gè) rename 操作,所以是原子的。

  據(jù)說一千個(gè)人的心中就有一千個(gè)哈姆雷特,不過我希望所有的 PHP 程序員在發(fā)布 PHP 代碼的時(shí)候都能采用一種方法,那就是本文介紹的方法,正確的方法。


【如何正確發(fā)布PHP代碼】相關(guān)文章:

PHP代碼如何規(guī)范02-13

PHP如何編寫易讀的代碼06-02

如何閱讀php源代碼02-19

如何寫出優(yōu)雅的PHP代碼07-24

PHP中如何實(shí)現(xiàn)crontab代碼05-30

如何在cmd下面寫php代碼06-21

如何在HTML中嵌入PHP代碼03-18

如何正確配置 Nginx + PHP03-01

php代碼如何實(shí)現(xiàn)命令行執(zhí)行05-19