幾乎每一個PHP 程式設計師都發布過程式碼,可能是透過 FTP 或 rsync 同步的,也可能是透過svn 或git 更新的。一個活躍的專案可能每天都要發布若干次程式碼,但是現實卻是很少有人注意其中的細節,實際上這裡面有好多坑,很可能你就在坑中卻渾然不知。
一個正確實現的發布系統至少應該支援原子發布。如果說每一個版本都表示一個獨立的狀態的話,那麼在發布期間,任何一次請求只能在單一狀態下執行。如此稱之為支持原子發布;反之如果在發布期間,一次請求跨越不同的狀態,那麼就不能稱之為原子發布。我們不妨舉個例子來說明一下:假設一次請求需要include
兩個PHP 文件,分別是a.php
和b.php
,當include a.php
完成後,發布程式碼,接著include b.php
,如果處理不當的話,那麼就可能會導致舊版本的a. php
和新版的b.php
同時存在於同一個請求之中,換句話說就是沒有實作原子發布。
開源世界裡有很多不錯的發布程式碼工具,例如 ruby 社群的capistrano,其流程大致就是發佈程式碼到一個全新的目錄,然後再軟連結到真正的發布目錄。
├── current -> releases/v1 └── releases ├── v1 │ ├── foo.php │ └── bar.php └── v2 ├── foo.php └── bar.php
不過鑑於 PHP 本身的特殊性,如果只是簡單地套用上面的流程,那麼將很難實現真正的原子發布。要理清個中緣由,還需要了解PHP 中的兩個Cache
的概念:
##opcode cache
正確發布PHP程式碼的實例分享 cache
opcode cache,基本上就是
apc 或
zend opcode,關於它的作用,大家都已經很熟悉,不必多言,需要注意的是
apc 的bug 很多,比如開啟了apc. enable_cli 配置後就會有很多靈異問題,所以說
opcode cache 還是盡可能使用
zend opcache 吧,如果需要快取數據,可以用apcu。此外
apc 和
zend opcode 對快取鍵的選擇有所差異:
apc 選擇的是檔案的
inode,
zend opcode 選擇的是檔案的
path。
正確發布PHP程式碼的實例分享 cache,它的作用是緩衝獲取文件資訊的
IO 操作,大多數時候它對我們而言是透明的,以至於很多人都不知道它的存在,需要注意的是正確發布PHP程式碼的實例分享 cache 是進程層級的,也就是說,每一個
php-fpm 進程都有自己獨立的
正確發布PHP程式碼的實例分享 cache。
opcode cache 或
正確發布PHP程式碼的實例分享 cache 裡的資料出現過期,那麼就會出現一部分快取是舊文件,一部分快取是新文件的非原子發布的情況,為了避免這種情況,我們應該保證緩存過期時間足夠長,最好是除非我們手動刷新,否則永遠不過期,對應到配置上就是:關閉apc.stat、opcache.validate_timestamps配置,設定足夠大的正確發布PHP程式碼的實例分享_cache_size、正確發布PHP程式碼的實例分享_cache_ttl 配置,必要的監控總是有好處的。
正確發布PHP程式碼的實例分享_cache PHP’s OPCache extension review Atomic 正確發布PHP程式碼的實例分享s at Etsy Cache invalidation for scripts in symlinked folders
php-fpm 自然是能夠解決問題,不過對腳本語言來說重啟太重了!難道除了重啟就沒有別的辦法了?
opcode cache 是透過
正確發布PHP程式碼的實例分享 cache 獲取文件信息,即便軟連結已經指向了新位置,但如果
正確發布PHP程式碼的實例分享 cache 裡還保存著舊資料的話,
opcode cache 依然無法知道新程式碼的存在,預設情況下,正確發布PHP程式碼的實例分享_cache_ttl 快取有效期是兩分鐘,這表示發布代碼後,可能要兩分鐘才能生效。為了讓發布盡快生效,需要以進程為單位清除
正確發布PHP程式碼的實例分享 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 環境下基本上就能工作了,但是在
zend opcode 環境下還可能有問題。因為在預設情況下opcache.revalidate_path 是關閉的,此時會快取未解析的符號連結的值,這會導致即便軟連結指向修改了,也無法生效,所以在使用
zend opcode的時候,如果使用了軟鏈接,視情況可能需要把
opcache.revalidate_path 啟動。
详细介绍参考:PHP’s OPCache extension review。
BTW:如果需要手动重置 opcode cache
,需要注意的是因为它是基于 SAPI 的概念,所以不能直接在命令行下调用 apc_clear_cache 或者 opcache_reset 方法来重置缓存,当然办法总是有的,那就是使用 CacheTool 在命令行下模拟 fastcgi
请求。
分析到这里,我们不妨反思一下:在 PHP 中原子发布之所以是一个棘手的问题,归根结底是因为软链接和缓存之间的的矛盾。不管是 opcode cache
还是 正確發布PHP程式碼的實例分享 cache
,都是 PHP 固有的缓存特性,基于客观需要无法绕开,如此说来是否有办法绕开软链接,使其成为马奇诺防线呢?答案是 NGINX 的 $正確發布PHP程式碼的實例分享_root:
fastcgi_param SCRIPT_FILENAME $正確發布PHP程式碼的實例分享_root$fastcgi_script_name; fastcgi_param DOCUMENT_ROOT $正確發布PHP程式碼的實例分享_root;
有了 $正確發布PHP程式碼的實例分享_root
,即便 DOCUMENT_ROOT
目录中含有软链接,NGINX 也会把软链接指向的真正的路径发给 PHP,也就是说,对 PHP 而言,软链接已经不存在了!不过作为代价,每一次请求,NGINX 都要通过相对昂贵的 IO 操作获取 $正確發布PHP程式碼的實例分享_root
的值,通过 strace
命令我们能监控这一过程,下图从 current
到 foo
的过程:
在本例中,压测发现使用 $正確發布PHP程式碼的實例分享_root
后,性能下降了大约 5% 左右,不过明眼人一下就能发现,虽然 $正確發布PHP程式碼的實例分享_root
导致了 lstat
和 readlink
操作,但是 lstat
操作的次数是和目录深度成正比的,也就是说目录越深,执行的 lstat
次数越多,性能下降也就越大。如果能够降低发布目录的深度,那么可以预计还能降低一些性能损耗。
结尾介绍一下 Deployer,它是 PHP 中做得比较好的工具,有很多特色,比如支持并行发布,具体演示如下图,左边是串行,右边是并行,使用「vvv」能得到更详细信息:
不过 Deployer 在原子发布上有一点瑕疵,具体见 release/symlink
代码:
<?php// 正確發布PHP程式碼的實例分享:releaserun("cd {{正確發布PHP程式碼的實例分享_path}} && if [ -h release ]; then rm release; fi"); run("ln -s $releasePath {{正確發布PHP程式碼的實例分享_path}}/release");// 正確發布PHP程式碼的實例分享:symlinkrun("cd {{正確發布PHP程式碼的實例分享_path}} && ln -sfn {{release_path}} current"); run("cd {{正確發布PHP程式碼的實例分享_path}} && rm release");?>
在 release
的时候,它是先删除再创建,是一个两步的非原子操作,在 symlink
的时候,看上去「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
操作,所以是原子的。
BTW:在使用「ln -sfn」
前后,如果使用 stat
查看新旧文件的 inode
的话,可能会发现它们拥有一样的 inode
值,看上去和我们的结论相悖,其实不然,实际上只是复用删除值而已(如果想验证,注意 Linux 会复用,Mac 不会复用)。
据说一千个人的心中就有一千个哈姆雷特,不过我希望所有的 PHP 程序员在发布 PHP 代码的时候都能采用一种方法,那就是本文介绍的方法,正确的方法。
相关推荐:
以上是正確發布PHP程式碼的實例分享的詳細內容。更多資訊請關注PHP中文網其他相關文章!

tomakephpapplicationsfaster,關注台詞:1)useopcodeCachingLikeLikeLikeLikeLikePachetoStorePreciledScompiledScriptbyTecode.2)MinimimiedAtabaseSqueriSegrieSqueriSegeriSybysequeryCachingandeffeftExting.3)Leveragephp7 leveragephp7 leveragephp7 leveragephpphp7功能forbettercodeefficy.4)

到ImprovephPapplicationspeed,關注台詞:1)啟用opcodeCachingwithapCutoredUcescriptexecutiontime.2)實現databasequerycachingingusingpdotominiminimizedatabasehits.3)usehttp/2tomultiplexrequlexrequestsandreduceconnection.4 limitesclection.4.4

依赖注入(DI)通过显式传递依赖关系,显著提升了PHP代码的可测试性。1)DI解耦类与具体实现,使测试和维护更灵活。2)三种类型中,构造函数注入明确表达依赖,保持状态一致。3)使用DI容器管理复杂依赖,提升代码质量和开发效率。

DatabasequeryoptimizationinPHPinvolvesseveralstrategiestoenhanceperformance.1)Selectonlynecessarycolumnstoreducedatatransfer.2)Useindexingtospeedupdataretrieval.3)Implementquerycachingtostoreresultsoffrequentqueries.4)Utilizepreparedstatementsforeffi

phpisusedforsenderemailsduetoitsbuilt-inmail()函數andsupportivelibrariesLikePhpMailerAndSwiftMailer.1)usethemail()functionForbasiceMails,butithasimails.2)butithasimail.2)

PHP性能瓶颈可以通过以下步骤解决:1)使用Xdebug或Blackfire进行性能分析,找出问题所在;2)优化数据库查询并使用缓存,如APCu;3)使用array_filter等高效函数优化数组操作;4)配置OPcache进行字节码缓存;5)优化前端,如减少HTTP请求和优化图片;6)持续监控和优化性能。通过这些方法,可以显著提升PHP应用的性能。

依賴性注射(DI)InphpisadesignPatternthatManages和ReducesClassDeptions,增強量強制性,可驗證性和MATIALWINABIOS.ItallowSpasspassingDepentenciesLikEdenciesLikedAbaseConnectionStoclasseconnectionStoclasseSasasasasareTers,interitationAseTestingEaseTestingEaseTestingEaseTestingEasingAndScalability。

cachingimprovesphpermenceByStorcyResultSofComputationsorqucrouctationsorquctationsorquickretrieval,reducingServerLoadAndenHancingResponsetimes.feftectivestrategiesinclude:1)opcodecaching,whereStoresCompiledSinmememorytssinmemorytoskipcompliation; 2)datacaching datacachingsingMemccachingmcachingmcachings


熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

SublimeText3漢化版
中文版,非常好用

mPDF
mPDF是一個PHP庫,可以從UTF-8編碼的HTML產生PDF檔案。原作者Ian Back編寫mPDF以從他的網站上「即時」輸出PDF文件,並處理不同的語言。與原始腳本如HTML2FPDF相比,它的速度較慢,並且在使用Unicode字體時產生的檔案較大,但支援CSS樣式等,並進行了大量增強。支援幾乎所有語言,包括RTL(阿拉伯語和希伯來語)和CJK(中日韓)。支援嵌套的區塊級元素(如P、DIV),

SecLists
SecLists是最終安全測試人員的伙伴。它是一個包含各種類型清單的集合,這些清單在安全評估過程中經常使用,而且都在一個地方。 SecLists透過方便地提供安全測試人員可能需要的所有列表,幫助提高安全測試的效率和生產力。清單類型包括使用者名稱、密碼、URL、模糊測試有效載荷、敏感資料模式、Web shell等等。測試人員只需將此儲存庫拉到新的測試機上,他就可以存取所需的每種類型的清單。

MinGW - Minimalist GNU for Windows
這個專案正在遷移到osdn.net/projects/mingw的過程中,你可以繼續在那裡關注我們。 MinGW:GNU編譯器集合(GCC)的本機Windows移植版本,可自由分發的導入函式庫和用於建置本機Windows應用程式的頭檔;包括對MSVC執行時間的擴展,以支援C99功能。 MinGW的所有軟體都可以在64位元Windows平台上運作。

SAP NetWeaver Server Adapter for Eclipse
將Eclipse與SAP NetWeaver應用伺服器整合。