Correctly publish PHP code for instance sharing

Source: Internet
Author: User
Tags apc lstat symlink zend


Almost every PHP programmer has published code that may have been synced via FTP or rsync , or it may have been updated with svn or git . An active project may have to be published several times a day, but the reality is that few people notice the details, in fact there are a lot of holes in it, and you probably don't know it in the pit.

A properly implemented publishing system should at least support atomic publishing. If each version represents a separate state, then during the release, any request can be executed in a single state. This is called support for Atomic publishing; Conversely, if a request crosses a different state during a release, it cannot be called an atomic release. Let's take an example to illustrate this: assuming that a request requires include two PHP files, respectively, a.php and b.php , when include a.php done, publish the code, and then include b.php , if handled improperly, it may result in an older version of the a.php And the new version b.php exist in the same request, in other words, the atomic release is not implemented.

There are a lot of good release code tools in the open source world, such as the Capistrano of the Ruby community, where the process is basically to publish the code into a completely new directory, and then soft-link to the real publishing directory.

├──current-releases/v1└──releases    ├──v1    │   ├──foo.php    │   └──bar.php    └──v2        ├──foo.php        └──bar.php

However, given the specifics of PHP itself, it would be very difficult to achieve a real atom release if it was simply applied to the above process. To clarify why, you need to understand the two concepts in PHP Cache :

    • OpCode cache

    • Realpath Cache

First chat opcode cache , basically is apc or zend opcode , about its role, we are already very familiar with, needless to say, need to pay attention to is a lot of apc bugs, such as open the APC.ENABLE_CLI configuration will have a lot of supernatural problems, so say opcode cache or do can use zend opcache , if need to cache data, can use APCU. In addition, the selection of the apc zend opcode cache key is different: apc Select the file inode , zend opcode Select the file path .

To talk about realpath cache , its role is to buffer the access to the file information IO operation, most of the time it is transparent to us, so many people do not know its existence, it is necessary to pay attention to the realpath cache process level, that is, each php-fpm of the The process has its own independence realpath cache .

Suppose that during the release of the code, opcode cache or the data is out of realpath cache date, then there will be a part of the cache is old files, some of the cache is a non-atomic release of new files, in order to avoid this situation, we should ensure that the cache expires long enough, preferably unless we manually refresh, Otherwise never expires, corresponding to the configuration is: Turn off Apc.stat, opcache.validate_timestamps configuration, set a large enough realpath_cache_size, Realpath_cache_ttl configuration, The necessary monitoring is always good.

Related technical details are particularly trivial, it is recommended that you read the following information carefully:

    • realpath_cachephp ' s Opcache extension reviewatomic deploys at Etsycache invalidation for scripts in symlinked folders

When you publish your code with a soft link, the first problem you usually encounter is that the new code doesn't take effect! Even if the call to the Apc_clear_cache or Opcache_reset method is not valid, restarting php-fpm naturally solves the problem, but the restart is too heavy for the scripting language! Is there no other way than to reboot?

In fact, the problem arises mainly because it opcode cache is through the realpath cache acquisition of file information, even if the soft link has pointed to a new location, but if the realpath cache old data is still stored, there is opcode cache still no way to know the existence of the new code, by default, Realpath_ The CACHE_TTL cache is valid for two minutes, which means it may take up to two minutes for the code to take effect. In order for the publication to take effect as soon as possible, the process needs to be cleared 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);    }

So in the apc environment basically can work, but in the zend opcode environment may also have problems. Because Opcache.revalidate_path is turned off by default, the values of unresolved symbolic links are cached, which can cause the soft links to be changed and not take effect, so zend opcode when using a soft link, depending on the situation, you may need to opcache.revalidate_pathactivation.

For more information, refer to PHP's Opcache extension review.

BTW: If you need to reset manually opcode cache , you need to be aware that because it is based on the concept of SAPI , so you can not directly at the command line with the Apc_clear_cache or Opcache_reset method to reset the cache, of course, there is always a way, That is to use Cachetool to impersonate the request at the command line fastcgi .

Analysis here, we may wish to reflect on: in PHP , the sub-publishing is a tricky issue, in the final analysis is due to the contradiction between soft links and caches. Whether opcode cache or not, realpath cache PHP 's inherent caching characteristics, based on the objective needs can not be bypassed, so there is a way to bypass the soft link to make it a maginot line of defense? The answer is NGINX $realpath _root:

    Fastcgi_param script_filename $realpath _root$fastcgi_script_name;    Fastcgi_param document_root $realpath _root;

With $realpath_root , even if the DOCUMENT_ROOT directory contains soft links,NGINX will also point to the soft link to the real path to PHP, that is to say, for php , soft links no longer exist! However, at the cost of each request,NGINX has to pass a relatively expensive IO operation to obtain $realpath_root the value, through the strace command we can monitor the process, current from foo the process:

In this example, the pressure test found that after the use of the $realpath_root performance of about 5% , but discerning eye a bit can be found, although $realpath_root led to lstat and readlink operation, but the lstat number of operations is proportional to the depth of the directory, that is, the eye The deeper the recording, the more execution times, and the greater the lstat performance degradation. If you can reduce the depth of the publishing directory, you can expect to reduce some of the performance losses.

At the end of the Deployer, it is a good tool in PHP , there are many features, such as support for parallel publishing, concrete demonstration such as, the left is serial, the right side is parallel, using "vvv" can get more detailed information:

But Deployer has a slight flaw in the atomic release, see release/symlink code:

<?php//Deploy:releaserun ("CD {{Deploy_path}} && if [-H release]; then RM release; Fi "), Run (" Ln-s $releasePath {deploy_path}}/release ");//Deploy:symlinkrun (" CD {{Deploy_path}} && LN-SFN {{ Release_path}}, run ("CD {{Deploy_path}} && rm release"); >

In release the time, it is first removed and then created, is a two-step non-atomic operation, at symlink the time, appears to 「ln -sfn」 be a single-step atomic operation, is actually also wrong:

shell> strace LN-SFN releases/foo currentsymlink ("Releases/foo", "current")      =-1 eexist (File exists) unlink (" Current ")                       = 0symlink (" Releases/foo "," current ")      = 0

As strace we can clearly see, although surface use 「ln -sfn」 is a one-step operation, but the internal is still in accordance with the deletion and then create the logic of execution, in fact, should be used in conjunction with 「ln & mv」 :

shell> LN-SFN releases/foo current.tmpshell> mv-ft current.tmp Current

First, by ln creating a temporary soft link, and then by mv implementing atomic operations, if you use strace monitoring, the options you find are mv 「T」 actually only performing an rename operation, so it's atomic.

BTW: Before and 「ln -sfn」 after use, if you use to stat view the old and new files inode , you may find that they have the same inode value, it seems to contradict our conclusions, in fact, it is only the reuse of deleted values (if you want to verify, pay attention to the Linux will be reused and theMac will not be reused).

It is said that 1000 people have 1000 hamlet in their hearts, but I hope that all PHP programmers in the release of PHP code can use a method, that is the method described in this article, the correct method.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.