phpfpm起多个进程的原因是因为在请求-响应期间单个phpfpm被阻塞,为了满足及时响应其他请求的需要而增加phpfpm的数量。为了减少单次请求消耗掉的时间,减少不必要的cpu、内存消耗,我们可以安装opcache和apcu。opcache可以避免每次请求都要读取php脚本文件生成opcode的过程。而apcu可以在多次不同的请求之间共享一些信息,避免每次请求查询这些公共信息造成额外的网络请求和数据库查询。
在原有的docker镜像中安装opcache命令为
docker-php-ext-install opcache
需要配置一下opcahce
- zend_extension=opcache
- opcache.enable=1
- opcache.enable_cli=1
- opcache.memory_consumption=44
- opcache.interned_strings_buffer=1
- opcache.max_accelerated_files=100000
- opcache.max_wasted_percentage=72
- opcache.use_cwd=1
- opcache.validate_timestamps=0
- opcache.revalidate_freq=0
- opcache.fast_shutdown=1
- opcache.consistency_checks=0
- opcache.blacklist_filename=/src/.opcacheignore
opcache扩展位置
zend_extension=opcache.so
启用opcache
opcache.enable=1
使用共享内存大小
opcache.memory_consumption=200
字符串缓存大小
opcache.interned_strings_buffer=8
最大缓存文件数量
opcache.max_accelerated_files=8000
出现异常,立即释放全部内存
opcache.fast_shutdown=1
最大允许占用内存百分比,超过此限制会重启进程
opcache.max_wasted_percentage=20
如果置为1,则将当前路径加入到文件key中,以避免可能产生的同文件名的文件key冲突
opcache.use_cwd=1
文件检测周期
revalidate_freq=3600
启用文件缓存时间戳
opcache.validate_timestamps=1
黑名单中的文件描述的文件不会被opcache缓存
opcache.blacklist_filename
php opcache缺点,PHP Opcache 注意事项以及调优
可以通过 opcache_get_status(false) 这个函数监控opcache的实际消耗,控制opcache给予的资源,目前返回信息如下
- array(7) {
- ["opcache_enabled"]=>
- bool(true)
- ["cache_full"]=>
- bool(false)
- ["restart_pending"]=>
- bool(false)
- ["restart_in_progress"]=>
- bool(false)
- ["memory_usage"]=>
- array(4) {
- ["used_memory"]=>
- int(43161896)
- ["free_memory"]=>
- int(359491288)
- ["wasted_memory"]=>
- int(0)
- ["current_wasted_percentage"]=>
- float(0)
- }
- ["interned_strings_usage"]=>
- array(4) {
- ["buffer_size"]=>
- int(16777216)
- ["used_memory"]=>
- int(288256)
- ["free_memory"]=>
- int(16488960)
- ["number_of_strings"]=>
- int(6567)
- }
- ["opcache_statistics"]=>
- array(13) {
- ["num_cached_scripts"]=>
- int(18)
- ["num_cached_keys"]=>
- int(20)
- ["max_cached_keys"]=>
- int(130987)
- ["hits"]=>
- int(34)
- ["start_time"]=>
- int(1663285335)
- ["last_restart_time"]=>
- int(0)
- ["oom_restarts"]=>
- int(0)
- ["hash_restarts"]=>
- int(0)
- ["manual_restarts"]=>
- int(0)
- ["misses"]=>
- int(18)
- ["blacklist_misses"]=>
- int(0)
- ["blacklist_miss_ratio"]=>
- float(0)
- ["opcache_hit_rate"]=>
- float(65.384615384615)
- }
- }
实际使用内存42m,字符串使用内存0.28m,我们可以给容器内存70m,最大浪费空间不能超过50/70 = 72%
安装apcu命令如下
pecl install apcu
需要配置一下apcu
- extension=apcu
- apc.enabled=1
- apc.shm_segments=1
- apc.shm_size=5M
- apc.entries_hint=0
- apc.ttl=3600
- apc.gc_ttl=0
- apc.slam_defense=0
- apc.coredump_unmap=true
由于composer是每次请求都要去处理的依赖,可以使用acpu进行优化
composer install --no-dev -o --prefer-dist --no-scripts --no-suggest --classmap-authoritative --apcu-autoloader
通过 apcu_sma_info() 这个函数查看实际acpu内存的使用情况,我的是
- array(4) {
- ["num_seg"]=>
- int(1)
- ["seg_size"]=>
- float(5242752)
- ["avail_mem"]=>
- float(5226136)
- ["block_lists"]=>
- array(1) {
- [0]=>
- array(1) {
- [0]=>
- array(2) {
- ["size"]=>
- int(5226104)
- ["offset"]=>
- int(16712)
- }
- }
- }
- }
一个 5242752 字节内存,可用 5226136 字节,使用了 16616 ,约0.02m,我们给1m内存就够用了
apcu常用的一些函数如下
-
- // 设置一个缓存,失效时间单位为秒。时间可选,默认永不失效(非重启)
- var_dump(apcu_store("bool_store", FALSE, 5));
- var_dump(apcu_store("string_store", "string", 10));
- var_dump(apcu_store("int_store", 999, 15));
- var_dump(apcu_store("float_store", 99.99, 20));
- var_dump(apcu_store("array_store", [1, 2, 3, 4, 5], 25));
-
- // 更新一个key的值
- $old = 1;
- $new = 2;
- apcu_add("cas", $old);
- var_dump(apcu_cas("cas", $old, $new));
-
- // 自增
- apcu_add("inc", 1);
- $success = false;
- var_dump(apcu_inc("inc", 10, $success));
- apcu_fetch("inc");
- var_dump($success);
-
- // 自减,可以为负数
- apcu_add("dec", 100);
- $success = false;
- var_dump(apcu_dec("dec", 10, $success));
- apcu_fetch("dec");
- var_dump($success);
-
- // 判断key是否存在,当参数为数组时返回数组,数组key为APCu缓存的key,值为bool类型true或false
- apcu_add("int", 1);
- apcu_add("string", "string");
- var_dump(apcu_exists("int"));
- var_dump(apcu_exists(["int", "string"]));
-
- // 以原子方式获取或生成缓存
- $entry = apcu_entry("entry", function ($key) {
- return ["entry" => "this is entry"];
- }, 100);
- var_dump($entry);
- $success = false;
- var_dump(apcu_fetch("entry", $success));
- var_dump($success);
-
- // 清除全部缓存
- // var_dump(apcu_clear_cache());