问题
I'm following this sample to create Signed URLs on CloudFront using PHP http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/CreateURL_PHP.html
And I have everything working fine and generating the Signed URLs for both RTMP Distributions and HTTP Distributions.
However I noticed that generating the Sign URL takes quite some time and I wonder what impact could have when used in production with thousands of requests.
I did some tests and it seems that the long time is taking is due to the php-openssl functions.
Here is the code:
<?php
class Cloudfront {
const KEYPAIRID = 'MYKEYPAIRID';
const PVTKEYFILE = '/home/keys/myprivatekey.pem';
public function rsa_sha1_sign($policy) {
$signature = "";
// load the private key
$fp = fopen(self::PVTKEYFILE, "r");
$priv_key = fread($fp, 8192);
fclose($fp);
$pkeyid = openssl_get_privatekey($priv_key);
// compute signature
openssl_sign($policy, $signature, $pkeyid);
// free the key from memory
openssl_free_key($pkeyid);
return $signature;
}
public function simulated_rsa_sha1_sign($policy) {
// create a simulated signature
$signature = "©3•{š(|i~'{µÜr…6—\L¶…ÙiÃÔh@ç÷S„Aóö¯‡d‰‹{¦ºxòrd)Xcª
Áh‚°Bgþ èòëÿô Š#CßFe ÓÒ>v1 R€¥#–þ*¸çGÀýƒ Ј¾F<t)eV7¿ø_ŒQÎiXXU s˜¦Ij:ý
ÒR ‹ÚQ§ Çm8à ºâ*+äÇjƒãýO 4 ~ Uöeóy˜¢93_0iy §âE– a÷f¥y¿ÈãÏ`‹ _ì`ß ½õ ‹*
ÁM‘çõD jrüB •d˜¥ èp Òü¿Ö NŒ«éoI X €v=RÌlŠ¤ /Á û9Yš¾î";
// load the private key file although is not actually used
$fp = fopen(self::PVTKEYFILE, "r");
$priv_key = fread($fp, 8192);
fclose($fp);
return $signature;
}
public function url_safe_base64_encode($value) {
$encoded = base64_encode($value);
// replace unsafe characters +, = and / with the safe characters -, _ and ~
return str_replace(
array('+', '=', '/'), array('-', '_', '~'), $encoded);
}
public function create_stream_name($stream, $signature, $expires) {
$result = $stream;
// if the stream already contains query parameters, attach the new query parameters to the end
// otherwise, add the query parameters
$separator = strpos($stream, '?') == FALSE ? '?' : '&';
$result .= $separator . "Expires=" . $expires . "&Key-Pair-Id=" . self::KEYPAIRID . "&Signature=" . $signature;
// new lines would break us, so remove them
return str_replace('\n', '', $result);
}
public function get_signed_stream_name($video_path, $expires) {
// this policy is well known by CloudFront, but you still need to sign it, since it contains your parameters
$canned_policy = '{"Statement":[{"Resource":"' . $video_path . '","Condition":{"DateLessThan":{"AWS:EpochTime":' . $expires . '}}}]}';
// sign the original policy, not the encoded version
$signature = $this->rsa_sha1_sign($canned_policy);
// make the signature safe to be included in a url
$encoded_signature = $this->url_safe_base64_encode($signature);
// combine the above into a stream name
$stream_name = $this->create_stream_name($video_path, $encoded_signature, $expires);
return $stream_name;
}
}
That's basically the same sample that CloudFront have on their docs. Then I created a controller were I make the calls to get_signed_stream_name() to generate the signed urls. I decided to do a while loop to see how long it takes to create 500 signed urls.
public function signedurl() {
// Script start
$start = microtime(true);
$this->load->helper('cloudfront');
$this->cloudfront = new Cloudfront();
$i = 1;
while ($i <= 500) {
$expires = time() + rand(300, 900);
$http_video_path = 'http://mydistribution.cloudfront.net/myvideo.mp4';
$signed_http_url = $this->cloudfront->get_signed_stream_name($http_video_path, $expires);
echo '<strong>HTTP Signed URL:</strong> <br />' . $signed_http_url;
echo '<br /><br />';
$i++;
}
// Script end
$time_taken = microtime(true) - $start;
echo $time_taken;
}
Generating 500 signed urls in that while loop took around 11 seconds on my local machine. Then I decided to change the like:
$signature = $this->rsa_sha1_sign($canned_policy);
to
$signature = $this->simulated_rsa_sha1_sign($canned_policy);
To see what happened if everything was run except invoking the php-openssl functions openssl_get_privatekey(), openssl_sign(), openssl_free_key().
I ran the same script with the 500 while loop and it took 0.090 seconds. So basically the php-openssl functions make the script a lot slower. Is this something I should be worried, it is normal since I'm generating these signed urls and it takes considerable processing power?
I did several tries and here are sample time it took for 3 of each.
Real code using OpenSSL functions generating 500 signed url calls:
11.135037899
11.6025328636
11.0253090858
500 URLs simulated without using the OpenSSL functions:
0.0828909873962
0.0903220176697
0.0916609764099
Also, I would like to know how I could create a signature that work for any file in the distribution. A wildcard that I could generate a signature that can be used for all the files under that folder or distribution. I read someplace that it was possible, but not sure how using those samples above. Maybe if I can create a single signature for each request instead of for each file returned in the request would be less intensive.
Thanks!
回答1:
Have you tried removing "fopen()" and using hard coded value for the private key?
Example:
function getPrivateKey() {
$privateKey = '-----BEGIN RSA PRIVATE KEY-----
abc
-----END RSA PRIVATE KEY-----';
return str_replace("\t", '', $privateKey);
}
If you still need the keys into external files, try using php include() and take advantage of APC caching.
For processing batches of private keys; You can use Iterator or scan_dir, scan your files based on regex, include your files and assign their contents into an array of SSL keys. Again, you will take advantage of APC. Unfortunately, I think that scandir() will need to access your file system. Generally this slows down things.
回答2:
I observe the same performance issue with Boto (AWS's Python SDK) which uses rsa
module to compute the signature. I think the problem simply comes down to the fact that RSA computation is slow in this context. I think/hope the solution lies in adjusting the setup or the workflow of dealing with private content.
来源:https://stackoverflow.com/questions/22053392/slow-performance-when-generating-cloudfront-signed-urls