《深入探究 php-apcu 实现原理》-- 第一回:apcu的简介、优缺点及使用场景

在业务开发的某些场景中使用了apcu进行整体的性能优化,也取得了不错的效果,所以前两年就一直想写写相关的主题

市面上写redis的文章或者书籍铺天盖地,但是去谈apcu的却没有多少,有一些也是科普性的如何安装和使用,所以老赵这里总结一下自己所得,做个分享。

我这篇文章的主要结构大概是这样的:

1.apcu在缓存中地位及使用场景,与redis、mysql或者其他的一些nosql数据库如何搭配使用

2.apcu的源代码在哪里,主要涉及哪些技术点

 1.APCU是什么?在什么样的场景使用?

官方对于apc的解释如下,可选的php缓存技术。apc包含两个方面,一方面对于本身代码级别的缓存,另一方面是提供给编码者使用的类似于redis的set、get这样的接口。在php 某个版本之后,apcu所提供的用户缓存部分被保存下来了

The Alternative PHP Cache (APC) is a free and open opcode cache for PHP. Its goal is to provide a free, open, and robust framework for caching and optimizing PHP intermediate code

apcu扩展使用的方法是这样的:

<?php
$bar = ‘BAR‘;
apcu_add(‘foo‘, $bar);
var_dump(apcu_fetch(‘foo‘));
echo "\n";
$bar = ‘NEVER GETS SET‘;
apcu_add(‘foo‘, $bar);
var_dump(apcu_fetch(‘foo‘));
echo "\n";
?>

大体上来说,使用的api侧与memcahe、redis或者其他的基于磁盘的nosql使用的方式似乎没什么差别,我画了一个典型的web架构的示意图,来标识出来他们各自之间的区别

《深入探究 php-apcu 实现原理》--  第一回:apcu的简介、优缺点及使用场景

一般现在的架构模式下,负载均衡机器、服务集群、redis集群、mysql集群式相互独立运维的,也就是我所画出来的clusterA、clusterB、clusterC、clusterD,按照现在比较流行微服务划分(我对微服务的概念不是很熟),服务间使用网络协议调用

apcu是基于共享内存技术建设的,多个cgi之间访问apcu中的cache可以完全等同于访问自己进程的一块内存一样,不需要发任何的网络请求。

而不管是redis、mysql或者其他的独立服务的cache都需要发网络请求,即使存储和服务部署在同一机器上也仍然需要采用本地sock进行网络请求,何况在虚拟化的趋势下,这些存储服务一定是独立运行的。

按照计算机存储器层次结构的理论,访问内存的速度大概在纳秒级别 ,网络请求的速度在毫秒级别,同机架或者同机房的机器可能在1/10ms左右,还不考虑服务稳定性的情况下。

简单的进行存取测试,速度至少在千倍以上提升,但是apc在实际的使用中还是存在一定的局限性:

  1. 以扩展的方式接入,跟php这门语言有很强的耦合,而redis作为独立服务存在,使用协议接入
  2. apcu受限于单机内存的限制,扩展受阻,而目前的redis集群模式已经可以做到动态扩容,理论上无容量风险
  3. apcu数据存于单机内存,多机器之间的数据无法共享,这是他使用场景有限的最大阻碍

所以,我再使用场景中一般用apcu来缓存数据量小、但是读取量大或者瞬间读取量大的场景。

比如:

1.你是一个开放平台,你需要对客户请求做鉴权,这个token过来的请求可以访问哪些path请求。这个场景下,用户的token及可访问的path信息持久化在mysql中,变更频次小,数据量小,但是可能每秒有10W次请求

这个场景就比较适合apc,相比于直接请求mysql/redis的架构,可以给服务省掉10w - N 次/s的网络消耗,N为容器数目

2.抢购的场景下,假设量比较大,那么可以使用apc来做s级别的缓存元信息,以防止对于存储服务的瞬间链接量过大,导致失败的情况。

几个关键字:数据大小小、读取量大、配置信息、无状态

而有状态的信息你还是选择mysql/redis,所以这么来看,他的场景的确是有限。但是在有限场景也能发挥他的价值,作为php多进程之间通信的一种方式,也顺利帮我优化了几万/s的mysql、redis请求。

对于现在的web服务端编程而言,单个api请求带来的io转化次数是影响服务性能、稳定性的最大的因素(前提是没有慢sql),我曾经见到一个api平均转化了80次mysql,如果请求突增,加机器都很难解决统一rpc请求的日志,做好access_cps / rpc_cps 指标监控及上线前的准入还是非常重要的,当然两份日志求交也可以天级别分析出哪些api可能需要优化了

2.APCU源码及涉及的技术点?

作者深知我们这些phper扑在了创造互联网价值创造的一线,基础相对薄弱,面对C代码可能一头雾水,特地写了一篇英文的Readme,详细的介绍了实现所用到的技术及原理,多贴心

apcu源码的git地址在: https://github.com/krakjoe/apcu

实现说明文档在源码目录中的 TECHNOTES.txt文件下,当然看懂这系列文章的背后,你是需要补充一下内存方向的一些基本知识的:

  1. php  SAPI是什么?MINIT、RINIT阶段做了什么?及扩展开发需要做的一些事情
  2. 关于进程中内存的布局、共享内存技术、虚拟内存与物理内存、内存管理与分配

介绍先到这里,暂时给自己立个flag,后面的连载节奏是:

  1. php生命周期及扩展相关知识,具体结合apcu在每个阶段做了什么,为后续的技术点展开做好知识预告
  2. 从内存共享,引出mmap、shm等技术点,从而再复习一下进程中内存的布局、虚拟内存与mmap等的关系
  3. 进程间可以共享内存了,如何分配内存? 引 出molloc、free等基于堆的内存分配的实现及与apcu的内存分配器
  4. 内存分配之后,上层的数据结构如何构建能够做到基于key的数据检索?过期键如何实现

《深入探究 php-apcu 实现原理》--  第一回:apcu的简介、优缺点及使用场景