上午的時候, 有同事來找我說上週新上線的一個使用mcrypt的腳本, 響應很是慢, 可是服務器的各項指標都正常, 不知道是什麼緣由.php
通過了解, 一個簡單的可重現的腳本以下:html
- <?php
- $dmcryptText = "dummy";
- $key = "foobar";
- $size = mcrypt_get_iv_size(MCRYPT_BLOWFISH,MCRYPT_MODE_ECB);
- $iv = mcrypt_create_iv($size); //注意這裏
- $m = mcrypt_ecb(MCRYPT_BLOWFISH, $key, $dmcryptText, MCRYPT_DECRYPT, $iv);
- var_dump($m);
當20個併發請求這個腳本的時候, 咱們會發現Apache的響應時間急劇上升…安全
考慮到這個問題可能具備必定的廣泛性, 因而我想我仍是寫一篇文章來介紹下這個坑, 防止後來人再次踩到.bash
PHP的Mcrypt擴展的mcrypt_create_iv, 若是你不指定的話, 默認使用/dev/random(Linux上), 做爲隨機數產生器. (也許有的同窗已經知道緣由了, 呵呵, 那就能夠略過了)服務器
這裏的問題就在於/dev/random, 它的random pool依賴於系統的中斷來產生. 當系統的中斷數不足, 不夠產生足夠的隨機數, 那麼嘗試讀取的進程就會等待, 也就是會hang住, 來看一個簡單的例子:併發
- $ dd if=/dev/random bs=1024k count=1
當你的機器不夠繁忙的時候, 你會發現, 輸出的速度很慢, 偶爾還有停頓…dom
問題就出在了這裏, 當你20個併發請求的時候, 服務器的中斷數不夠, 產生不了足夠的隨機數給mcrypt, 繼而致使PHP進程等待, 從而表現出, 響應時間變長測試
解決的辦法就是, 改用/dev/urandom, /dev/urandom也是一個產生隨機數的設備, 可是它不依賴於系統中斷.spa
- <?php
- $dmcryptText = "dummy";
- $key = "foobar";
- $size = mcrypt_get_iv_size(MCRYPT_BLOWFISH,MCRYPT_MODE_ECB);
- $iv = mcrypt_create_iv($size, MCRYPT_DEV_URANDOM); //注意這裏
- $m = mcrypt_ecb(MCRYPT_BLOWFISH, $key, $dmcryptText, MCRYPT_DECRYPT, $iv);
- var_dump($m);
修改後測試, 問題解決, 一切正常…..net
Weibo上SAE的同窗 @胥昕ops提供了一個不須要修改PHP代碼的解決方案:
胥昕ops: SAE 二三月份遇到的這個問題,一條命令秒殺此問題,
- $ rngd -r /dev/urandom -o /dev/random -t 1
用urandom的結果填充entropy池子,這樣既保證了entropy池的數量,也保證了隨機性
然而, 爲何PHP使用/dev/random做爲默認, 這是由於理論上來講, /dev/urandom在必定的狀況下, 可能會被可預測(參看: /dev/random), 因此通常上認爲, /dev/urandom不如/dev/random安全.
後記, 你們看手冊, 必定也要看手冊下面的評論, 呵呵, 有不少東西在評論中, 是有提到的, 以下面這條評論, 來自mcrypt_create_iv: