Press "Enter" to skip to content

Mcrypt响应慢的一个原因

上午的时候, 有同事来找我说上周新上线的一个使用mcrypt的脚本, 响应非常慢, 但是服务器的各项指标都正常, 不知道是什么原因.
经过了解, 一个简单的可重现的脚本如下:

<?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的响应时间急剧上升...
考虑到这个问题可能具有一定的普遍性, 于是我想我还是写一篇文章来介绍下这个坑, 防止后来人再次踩到.
PHP的Mcrypt扩展的mcrypt_create_iv, 如果你不指定的话, 默认使用/dev/random(Linux上), 作为随机数产生器. (也许有的同学已经知道原因了, 呵呵, 那就可以略过了)
这里的问题就在于/dev/random, 它的random pool依赖于系统的中断来产生. 当系统的中断数不足, 不够产生足够的随机数, 那么尝试读取的进程就会等待, 也就是会hang住, 来看一个简单的例子:

$ dd if=/dev/random bs=1024k count=1

当你的机器不够繁忙的时候, 你会发现, 输出的速度很慢, 偶尔还有停顿...
问题就出在了这里, 当你20个并发请求的时候, 服务器的中断数不够, 产生不了足够的随机数给mcrypt, 继而导致PHP进程等待, 从而表现出, 响应时间变长
解决的办法就是, 改用/dev/urandom, /dev/urandom也是一个产生随机数的设备, 但是它不依赖于系统中断.

<?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);

修改后测试, 问题解决, 一切正常....
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:

If you use /dev/random you need a well filled entropy pool or the application will block until enough good entropy comes available

30 Comments

  1. word hurdle
    word hurdle March 17, 2023

    这个是一个很有用的小提示,请问作者在哪个城市?

  2. ben
    ben July 27, 2016

    2016年了我还掉进这个坑……打死我都想不到问题出在这里。
    解决了困扰我几天的问题,特地来感谢一下

  3. Joffe
    Joffe December 29, 2014

    定期来看干货

  4. […] 其实随机数也是个坑,以前同事有遇到过这个问题,主要是由于memcached中随机数产出问题导致访问巨慢的问题,详见 laruence 大牛写的这篇blog。 […]

  5. chenlong
    chenlong March 19, 2013

    mark一下。向鸟哥学习!

  6. jim
    jim March 6, 2013

    支持鸟哥

  7. sanreqi
    sanreqi February 25, 2013

    不错收藏了

  8. shenzhe
    shenzhe November 6, 2012

    mt_rand相关函数也要有URANDOM这个参数就好了。
    鸟哥,整个呗。

  9. 盒子
    盒子 October 12, 2012

    mark.

  10. 王鹏你妹
    王鹏你妹 October 9, 2012

    王鹏你妹!汪你妹!据说现在这个很火啊!http://www.wangnimei.com/

  11. 南京搬家公司
    南京搬家公司 October 8, 2012

    过节之后先来博主博客看看..不知道博主过的怎么样哦?南京搬家公司http://www.bjhxrnj.com永远支持博主!

  12. 培训的目的
    培训的目的 October 8, 2012

    这个是一个很有用的小提示,请问作者在哪个城市?

  13. Pride Chung
    Pride Chung October 4, 2012

    这个很坑爹,我看见很多PHP的框架都有用到 Mcrypt

  14. 真人娱乐
    真人娱乐 October 1, 2012

    你好,楼主,可以跟你交换链接吗?

  15. 石家庄星座约会
    石家庄星座约会 September 27, 2012

    石家庄星座约会
    以星座为主题的同城约会,爱情交友,目前只同意女生加群。
    Q群:235893866

  16. 雪候鸟
    雪候鸟 September 26, 2012

    @hytest thanks, 已修正

  17. kulv2012
    kulv2012 September 25, 2012

    去年项目中也遇到过这个问题,后来改为URANDOM就OK了

  18. Jason Gian
    Jason Gian September 24, 2012

    鸟哥v5

  19. wiwi
    wiwi September 24, 2012

    那用MCRYPT_RAND 会有问题吗?

  20. Kearney
    Kearney September 24, 2012

    very good

Comments are closed.