Assets In A Farm Enviroment.

I have this scenario:

Front end with lighttpd, using FastCGI to send work to backend php-cgi instances in lots of servers. Each of this servers has a copy of the Yii app, which uses tons of extensions which obviously publish assets. Currently the assets directory is located in a NFS shared by all PHP servers, but this causes a huge performance problem. I would like to have the assests directly in the lighttpd machine, but in a "pre published" way, not needeing PHP to publish the assets in "runtime", neither having to check the files for modifications.

Is there already a way to do this?

If not, I was thinking on extending the assets manager to publish the assets files using FTP or SCP, and keeping a central record (maybe in a MySQL database) of published assets and timestamps of publishings). This looks a bit of a hack, but I can’t think in other way to do this.

Have similar situation, but still using NFS (load balancing proxy exposes assets directory to all PHP servers).

If you have some better solution (your idea looks with FTP publication and SQL storage looks very nice) - share it if possible.

Personally I think NFS sucks big time, but I have had no resources to try iSCSI or something else. Currently I’m trying to compile the ssh2 extension from PECL, but it looks like broken in Ubuntu 12.04 server :S Better will try FTP, and let my assets extension open to be configurable regarding the protocol.

More soon…

Ok, this are my notes on my proposed solution:

  1. You must avoid using the [font=“Courier New”]–with-curlwrappers[/font] flag when compiling PHP, because if you use it, the [font=“Courier New”]ftp://[/font] stream won’t work for functions like [font=“Courier New”]mkdir[/font] or [font=“Courier New”]is_dir[/font].

  2. The [font=“Courier New”]CAssetManager._basePath[/font] must be changed to protected, we can not extend the class the way we need. Please Yii maintainers, change the access for this! :rolleyes:

  3. All what is needed is this (kind of magic :D ):


<?php


/**

 * AAsetManager extends CAssetManager to allow to publish assets to an FTP server as well.

 *

 * @author MetaYii

 */

class AAssetManager extends CAssetManager

{

	/**

     * Sets the root directory storing published asset files. This could use the

	* ftp:// wrapper.

	*

	* @see See {@link http://php.net/manual/en/wrappers.ftp.php}

	*

     * @param string $value the root directory or FTP url storing published asset files

     * @throws CException if the base path is invalid

     */

	public function setBasePath($value)

	{

		if(($basePath=realpath($value))!==false && is_dir($basePath) && is_writable($basePath)) {

			$this->_basePath = $basePath;

  	}

  	elseif (strpos($value, 'ftp://')==0) {

 		$this->_basePath = $value;

  	}

		else {

			throw new CException(Yii::t('yii','CAssetManager.basePath "{path}" is invalid. Please make sure the directory exists and is writable by the Web server process.',

				array('{path}'=>$value)));

  	}

	}

}

Then in the components section of the configuration file, use something like:


   'assetManager'=>array(

  	'class'=>'AAssetManager',

  	'basePath'=>'ftp://luser:idontknow@ftp.example.com/assets',

  	'baseUrl'=>'/assets'

   ),

Where [font=“Courier New”]ftp.example.com[/font] is the same server as the webserver, where [font=“Courier New”]assets[/font] is the web-published directory. That’s it, so simple.

Tomorrow the next chapter: "avoiding to send filemtime calls to the FTP server". I guess this wil be more complex. But still, the FTP access seems to be faster than the NFS access (not properly benchmaked yet).

Ok, I found something very interesting. The copy to a FTP server seems to work fine with PHP 5.4, but it seems that with 5.2 (yes, still), it is not working due to some weird encoding management and you end with random files truncated when transferred. I say it’s caused by 5.2 because the FTP server is the same in the two enviroments where I tested. Anyone else has had this issue?

I believe that the s3assetmanager extension may help you.

Well, this is a new version of the class AAssetManager, which now senses PHP version and uses the appropiate way to transfer the files: for < 5.3.0, ftp_* functions and for >= 5.3.0 streams. It also works with locks, which currently should be placed in a NFS share (yes, I know, the goal is to totally get rid of NFS, but at least the access to NFS is reduced to a file_exists call per asset or asset’s directory).

You can use the component like this, modified depending on your setup:


'assetManager'=>array(

   'class'=>'AAssetManager',

   'basePath'=>'ftp://assets:password@static.example.com/assets',

   'baseUrl'=>'/assets',

   'newDirMode'=>'0755',

   'lockAssets'=>true,

   'lockPath'=>'/nfs/share/assets/',

),

Feel free to test it.

Update: improved, we don’t need to touch the lock every time.