网站logo怎么做动态图,wordpress 字,做一个网站赚钱吗,门户网站是指APCu
极简概括#xff1a; PHP 的开源内存缓存扩展#xff0c;类比Redis#xff0c;但是一般都用Redis#xff0c;所以APCu用的很少。官方文档#xff1a;https://www.php.net/manual/zh/apcu.configuration.php解决问题#xff1a;类比Redis做缓存组件#xff0c;提升…APCu
极简概括 PHP 的开源内存缓存扩展类比Redis但是一般都用Redis所以APCu用的很少。官方文档https://www.php.net/manual/zh/apcu.configuration.php解决问题类比Redis做缓存组件提升性能同步数据使用。适用场景轻量级的缓存适合写少读多的场景。缺少原子性、缺少多条指令无间隙执行不建议高并发时写多读多写多读少的场景下使用。优点 比Redis快一百多倍。运维成本低利用PHP扩展的方式实现无需与缓存组件进行网络通信。简单易用APCu 提供了简单而有效的接口容易上手。跨文件跨进程A文件set值B文件get值是可以获取到值的若做不到和变量没区别。 缺点 不支持远程独立部署。类型没有Redis的多适用场景仅限于缓存。数据无法做到常驻内存重启或出故障数据丢了就没了没有像Redis的RDB或AOF持久化机制。无法保证多个操作的原子性。可能存在超卖的问题。获取确定已经存在的值可能会遇到false获取结果不稳定。 注意从PHP 8.0.0开始不再支持apcu bc。
是否能像RedisLua一样保证多个操作原子性
不能。 Redis是单线程的意味着单位时间内只执行一个任务Redis让并发过来的任务强制串行执行。有Lua的加持保证多条指令无间隙执行。 APCu没有这个机制让操作要么都成功要么都失败要实现这一步需要手动写逻辑。
高并发下会有超卖的一致性问题吗
还好APCu有乐观锁机制可以防止超卖问题。
但APCu 没有互斥的锁机制互斥意味着并发过来的请求通过独占该资源让任务串行执行。
由于PHPNginx默认是多进程机制也可以调整为多线程用得少 假设一个场景 获取到值自增。进程P0获取到A的值为5的时候想要自增到6可能其它进程已经自增到8了。此时两步操作存在间隙又没有机制对此数据加锁防止被其它进程更改所以可能P0执行自增时会加到9这是个概率问题因此乐观锁的机制就显得非常重要。
安装
前提是安装好了PHP默认在/usr/local/php下并配置有/usr/local/php/bin目录的环境变量
cd /test
wget https://pecl.php.net/get/apcu-5.1.23.tgz
tar zxf apcu-5.1.23.tgz
phpize
./configure
make
make install相关配置php.ini
配置名值类型默认值说明apc.enabledint1设置为0以禁用APC。这在APC被静态编译到PHP中时非常有用因为没有其他方法可以禁用它。apc.shm_segmentsint1为编译器缓存分配的共享内存段的数量。如果APC共享内存不足但apc.shm_size设置为系统允许的最高值提高该值可能会防止APC耗尽其内存。apc.shm_sizeint32M每个共享内存段的大小apc.entries_hintint4096是用于设置APCu缓存的条目预期数量apc.ttlint0指定缓存中的条目在过期之前可以存在多长时间单位为秒。默认为0表示永不过期apc.gc_ttlint3600指定过期缓存条目被清理的时间间隔单位为秒apc.mmap_file_maskstringnull是用于配置在使用共享内存映射MMAP方式时的文件名模板。这个选项在某些情况下可以用于解决操作系统限制或者提高性能。默认情况下这个选项为空APCu会使用系统默认的文件名模板。设置apc.mmap_file_mask时你可以使用一些特殊的占位符来指定文件名的格式例如%s代表共享内存标识符的十六进制表示%p代表当前进程的PID进程标识符。这样可以确保每个进程使用不同的文件名避免冲突。一般情况下你不需要手动设置这个选项除非你遇到共享内存映射方面的特定问题或者有特殊需求。在大多数情况下使用默认设置即可满足需求apc.slam_defenseint1防止缓存雪崩多进程下每个进程都试图同时缓存同一个文件。此选项设置跳过尝试缓存未缓存文件的进程的百分比。或者将其视为单个进程跳过缓存的概率。例如设置为75意味着该进程有75%的概率不会缓存未缓存的文件。因此设置越高对缓存雪崩的防御就越强。将此项设置为0禁用此功能apc.enable_cliint0是否在cli模式下启用apc实测不生效apc.use_request_timeint0置控制是否APC应该使用请求时间来为文件加上时间戳。当启用时它可以确保在请求时间变化时刷新缓存文件这在某些情况下会很有用比如在开发或调试代码时apc.serializerstringphp用于配置APC序列化方式。apc.coredump_unmapint0启用APC处理信号如SIGSEGV该信号在收到信号时写入内核文件。当收到这些信号时APC将尝试取消共享内存段的映射以便将其从核心文件中排除。当接收到致命信号并且配置了大型APC共享内存段时此设置可以提高系统稳定性apc.preload_pathstringnull用于指定要预加载的PHP文件或目录的路径。预加载可以提高应用程序的性能因为它可以在应用程序启动时将指定的文件或目录加载到内存中从而减少了每次请求时的文件读取和解析时间。
使用
设置值注意缓存有值的情况下无法设置值类比Redis的setnx类型支持标量、数组、与对象这一点非常好。
bool apcu_add(key, val, ttl)获取缓存获取不到返回false并发情况下容易返回false
mixed apcu_fetch(key)乐观锁机制在旧值的基础上添加新的值
bool apcu_cas(key, int_old, int_new):清除所有缓存
bool apcu_clear_cache()递减参数2支持负数
int apcu_dec(key, 递减值, 函数返回结果赋值给变量, ttl秒)从缓存中删除某个元素
bool|array apcu_delete(array|string key)判断当前环境能否使用apcu
bool apcu_enabled()若key不存在则调用callback,并带有一个默认参数即key的值
null apcu_entry(key, callback, ttl)判断多个key或者单个key是否存在。当参数为array时函数返回只存在的key组成的数组
bool|array apcu_exists(string|array key)获取某个key的值若参数1是数组那么结果也是个数组只会返回存在的key的值若key有值参数2为true否则反之。
bool|array apcu_fetch(array|string key, $var);递增参数2支持负数
int apcu_inc(key, 递增值, 函数返回结果赋值给变量, ttl秒)将key的值存储缓存类比Redis的set若已存在可直接替换参数1也可以传输数组。
bool apcu_store(array|string key, val, ttl)压测对比连接Redis性能
方式轮次APCu耗时秒Redis耗时秒只读100000.0111.162只写100000.0121.062读写一次new Redis100000.0112.117读写多次new Redis100000.0113.646
只读APCu
?php$start microtime(true);
for($i 0; $i 10000; $i) {$key apcu. $i;apcu_fetch($key);
}echo microtime(true) - $start;只读Redis
?php
$redis new Redis();
$redis-connect(127.0.0.1, 6379);$start microtime(true);
for($i 0; $i 10000; $i) {$key redis . $i;$redis-get($key);
}echo microtime(true) - $start;只写APCu
?php$start microtime(true);
for($i 0; $i 10000; $i) {$key apcu. $i;apcu_add($key, $i);
}echo microtime(true) - $start;只写Redis
?php
$redis new Redis();
$redis-connect(127.0.0.1, 6379);$start microtime(true);
for($i 0; $i 10000; $i) {$key redis . $i;$redis-set($key, $i);
}echo microtime(true) - $start;读写一次new RedisAPCu
?php$start microtime(true);
for($i 0; $i 10000; $i) {$key apcu. $i;apcu_add($key, $i);apcu_fetch($key);
}echo microtime(true) - $start;读写一次new RedisRedis
?php
$redis new Redis();
$redis-connect(127.0.0.1, 6379);$start microtime(true);
for($i 0; $i 10000; $i) {$key redis . $i;$redis-set($key, $i);$redis-get($key);
}echo microtime(true) - $start;读写多次new RedisAPCu
?php$start microtime(true);
for($i 0; $i 10000; $i) {$key apcu. $i;apcu_add($key, $i);apcu_fetch($key);
}echo microtime(true) - $start;读写多次new RedisRedis
?php
$start microtime(true);
for($i 0; $i 10000; $i) {$redis new Redis();$redis-connect(127.0.0.1, 6379);$key redis . $i;$redis-set($key, $i);$redis-get($key);
}高并发下对APCu原子性测试
压测工具用ApiPOST我认为比ab工具好用。 压测前为了保证ApiPOST压测参数压测轮次 * 并发数 结果积的准确性特地用Redis做了多次测试发现参数是对的并发数大了就不对150以上这意味着压测工具应该没问题只是设备线程数不够。
?php
$redis new Redis();
$redis-connect(127.0.0.1, 6379);
$redis-decr(test_key);多条APCu语句执行能才能测试更能充分原子性并发100测试10轮次也就是1000次请求但是多次压测下来结果不对。apcu_fetch获取值动不动就是false导致结果重新赋值为10000在不存在的情况下赋初始值有并发问题但不是因为并发引起的而是因为apcu_fetch函数的问题获取不到值返回false。
?php
$key test_key;$res apcu_fetch($key);
if($res false) {apcu_add($key, 10000);
} else {apcu_delete($key);apcu_add($key, $res - 1);
}echo apcu_fetch($key);