`

PHP缓存之APC-简介、存储结构和操作

    博客分类:
  • php
 
阅读更多

 

      Alternative PHP Cache (APC) 是一个开放自由的PHP opcode 缓存。它的目标是提供一个自由、 开放,和健全的框架用于缓存和优化PHP的中间代码。它为我们提供了缓存和优化PHP的中间代码的框架。 APC的缓存分两部分:系统缓存和用户数据缓存。

 

  • 系统缓存 它是指APC把PHP文件源码的编译结果缓存起来,然后在每次调用时先对比时间标记。如果未过期,则使用缓存的中间代码运行。默认缓存 3600s(一小时)。但是这样仍会浪费大量CPU时间。因此可以在php.ini中设置system缓存为永不过期(apc.ttl=0)。不过如果这 样设置,改运php代码后需要重启WEB服务器。目前使用较多的是指此类缓存。
  • 用户数据缓存 缓存由用户在编写PHP代码时用apc_store和apc_fetch函数操作读取、写入的。如果数据量不大的话,可以一试。如果数据量大,使用类似memcache此类的更加专著的内存缓存方案会更好。

在APC中我们也可以享受APC带来的缓存大文件上传进度的特性,需要在php.ini中将apc.rfc1867设为1,并且在表单中加一个隐藏域 APC_UPLOAD_PROGRESS,这个域的值可以随机生成一个hash,以确保唯一。

 

APC与PHP内核的交互

 

APC是作为一个扩展添加到PHP体系中的。因此,按照PHP的扩展规范,它会有PHP_MINIT_FUNCTION、 PHP_MSHUTDOWN_FUNCTION、PHP_RINIT_FUNCTION、PHP_RSHUTDOWN_FUNCTION等宏定义的函数。 在PHP_MINIT_FUNCTION(apc)中有调用apc_module_init中,并且在此函数中通过重新给 zend_compile_file赋值以替换系统自带的编译文件过程,从而将APC自带的功能和相关数据结构插入到整个PHP的体系中。

 

这里会有一个问题,如果出现多个zend_compile_file的替换操作呢?在实际使用过程,这种情况会经常出现,比如当我们使用 xdebug扩展时,又使用了apc,此时PHP是怎么处理的呢?不管是哪个扩展,在使用zend_compile_file替换时,都会有一个自己的 compile_file函数(替换用),还有一个作用域在当前扩展的,一个旧的编译函数:old_compile_file。相当于每个扩展当中都保留 了一个对于前一个编译函数的引用,形成一个单向链表。并且,所有最终的op_array都是在新的zend_compile_file中通过 old_compile_file生成,即都会沿着这条单向链表,将编译的最终过程传递到PHP的zend_compile_file实现。在传递过程 中,每经过一个节点,这些节点都会增加一些属于自己的数据结构,以实现特定的需求。

 

APC内部存储结构

 

在APC内部,对于系统缓存和用户缓存分别是以两个全局变量存储,从代码逻辑层面就隔离了两种缓存,当然,这两种存储的实现过程和数据结构是一样的,它们都是apc_cache_t类型,如下:

 

 
    /* {{{ struct definition: apc_cache_t */
    struct apc_cache_t {
        void* shmaddr;                共享缓存的本地进程地址
        cache_header_t* header;       缓存头,存储在共享内存中
        slot_t** slots;               缓存的槽数组,存储在共享内存中
        int num_slots;                存储在缓存中的槽个数
        int gc_ttl;                   GC列表中槽的最大生存时间
        int ttl;                      如果对槽的访问时间大于这个TTL,需要则移除这个槽
        apc_expunge_cb_t expunge_cb;  /* cache specific expunge callback to free up sma memory */
        uint has_lock;                为可能存在的造成同一进程递归锁而存在的标记 /* flag for possible recursive locks within the same process */
    };
    /* }}} */

 

对于一个缓存,apc_cache_t类型的变量是其入口,它包含了这个缓存的一些全局信息。每个缓存都会有多个缓存槽,包含在slots字段 中,slots的个数包含在num_slots字段,槽的过程时间控制在于ttl字段。对于用户缓存和系统缓存,默认情况下系统缓存数量为1000,实际 上APC创建了1031个,也就是说默认情况下APC最少可以缓存1031个文件的中间代码。当然这个值还需要考虑内存大小,计算slot的key后的分 布等等。更多的关于缓存的统计信息存储在header字段中,header字段结构为cache_header_t,如下:

 

 
struct cache_header_t {
        apc_lck_t lock;             读写锁,独占阻塞缓存锁
        apc_lck_t wrlock;           写锁,为防止缓存爆满
        unsigned long num_hits;     缓存命中数
        unsigned long num_misses;   缓存未命中数
        unsigned long num_inserts;  插入缓存总次数
        unsigned long expunges;     清除的总次数
        slot_t* deleted_list;       指向被清除的槽的链表
        time_t start_time;          以上计数器被重置的时间
        zend_bool busy;             当apc在忙于清除缓存时告诉客户端此时状态的标记
        int num_entries;            统计的实体数
        size_t mem_size;            统计的被用于缓存的内存大小
        apc_keyid_t lastkey;        用户缓存最后一写入的key
    };

 

一个缓存包含多个slots,每个slot都是一个slot结构体的变量,其结构如下:

 

 
    struct slot_t {
        apc_cache_key_t key;        槽的key
        apc_cache_entry_t* value;   槽的值
        slot_t* next;               链表中的下一个槽
        unsigned long num_hits;     这个bucket的命中数/* number of hits to this bucket */
        time_t creation_time;       槽的初始化时间
        time_t deletion_time;       槽从缓存被移除的时间 /* time slot was removed from cache */
        time_t access_time;         槽的最后一次被访问的时间
    };

 

每个槽包含一个key,以apc_cache_key_t结构体存储;包含一个值,以apc_cache_entry_t结构体存储。如下:

 

 
    typedef struct apc_cache_key_t apc_cache_key_t;
    struct apc_cache_key_t {
        apc_cache_key_data_t data;
        unsigned long h;              /* pre-computed hash value */
        time_t mtime;                 /* the mtime of this cached entry */
        unsigned char type;
        unsigned char md5[16];        /* md5 hash of the source file */
    };

 

结构说明如下:

 

  • data字段 apc_cache_key_data_t类型,一个联合体,存储key的关联信息,比如对于系统缓存,其可能会存储文件的路径或OS的文件device/inode;对于用户缓存可能会存储用户给定的标识或标识长度。
  • h字段 文件完整路径或用户给定的标识的hash值,使用的hash算法为PHP自带的time33算法;或者文件所在device和inode的和
  • mtime字段 缓存实体的修改时间
  • type字段 APC_CACHE_KEY_USER:用户缓存; APC_CACHE_KEY_FPFILE:系统缓存(有完整路径); APC_CACHE_KEY_FILE: 系统缓存(需要查找文件)
  • md5字段 文件内容的MD5值,这个字段与前面四个字段不同,它是可选项,可以通过配置文件的apc.file_md5启用或禁用。并且这个值是在初始化实体时创建 的。看到这里源文件的md5值,想起之前做过一个关于MySQL数据表中访问路径查询的优化,开始时通过直接查询路径字段,在数据量达到一定级别时,出现 了就算走索引还是会很慢的情况,各种方案测试后,采用了以新增一个关于访问路径的md5值查询解决。

 

除了入口,APC在最终的数据存储上对于系统缓存和用户缓存也做了区分,在_apc_cache_entry_value_t分别对应file和user。

 

 
    typedef union _apc_cache_entry_value_t {
        struct {            
            char *filename; /* absolute path to source file */
            zend_op_array* op_array;     存储中间代码的op_array
            apc_function_t* functions; /* array of apc_function_t's */
            apc_class_t* classes; /* array of apc_class_t's */
            long halt_offset; /* value of __COMPILER_HALT_OFFSET__ for the file */
        } file;                         file结构体 系统缓存所用空间,包括文件名,,
        struct {
            char *info;
            int info_len;
            zval *val;
            unsigned int ttl;           过期时间
        } user;                         ser结构体 用户缓存所用空间
    } apc_cache_entry_value_t;

如图所示:

 

 

 

 

APC缓存存储结构

 

初始化

在APC扩展的模块初始化函数(PHP_MINIT_FUNCTION(apc))中,APC会调用apc_module_init函数初始化缓存 所需要的全局变量,如系统缓存则调用apc_cache_create创建缓存全局变量apce_cache,默认情况下会分配1031个slot所需要 的内存空间,用户缓存也会调用同样的方法创建缓存,存储在另一个全局变量apc_user_cache,默认情况下会分配4099个内存空间。这里分配的 空间的个数都是素数,在APC的代码中有一个针对不同数量的素数表primes(在apc_cache.c文件)。素数的计算是直接遍历素数表,找到表中 第一个比需要分配的个数大的素数。

缓存key生成规则

APC的缓存中的每个slot都会有一个key,key是 apc_cache_key_t结构体类型,除了key相关的属性,关键是h字段的生成。 h字段决定了此元素落于slots数组的哪一个位置。对于用户缓存和系统缓存,其生成规则不同。

  • 用户缓存通过apc_cache_make_user_key函数生成key。通过用户传递进来的key字符串,依赖PHP内核中的hash函数(PHP的hashtable所使用的hash函数:zend_inline_hash_func),生成h值。
  • 系统缓存通过apc_cache_make_file_key函数生成key。通过APC的配置项apc.stat的开关来区别对待不同的方案。 在打开的情况下,即 apc.stat= On 时,如果被更新则自动重新编译和缓存编译后的内容。此时的h值是文件的device和inode相加所得的值。在关闭的情况下,即 apc.stat=off时,当文件被修改后,如果要使更新的内容生效,则必须重启Web服务器。此时h值是根据文件的路径地址生成,并且这里的路径是绝 对路径。即使你是使用的相对路径,也会查找PG(include_path)定位文件,以取得绝对路径,所以使用绝对路径会跳过检查,可以提高代码的效 率。

添加缓存过程

以用户缓存为例,apc_add函数用于给APC缓存中添加内容。如果key参数为字符串中,APC会根据此字符串生成key,如果key参数为数 组,APC会遍历整个数组,生成key。根据这些key,APC会调用_apc_store将值存储到缓存中。由于这是用户缓存,当前使用的缓存为 apc_user_cache。执行写入操作的是apc_cache_make_user_entry函数,其最终调用 apc_cache_user_insert执行遍历查询和写入操作。与此对应,系统缓存使用apc_cache_insert执行写入操作,其最终都会 调用_apc_cache_insert。

不管是用户缓存还是系统缓存,大体的执行过程类似,步骤如下:

  1. 通过求余操作,定位当前key的在slots数组中的位置: cache->slots[key.h % cache->num_slots];
  2. 在定位到slots数组中的位置后,遍历当前key对应的slot链表,如果存在slot的key和要写入的key匹配或slot过期,清除当前slot。
  3. 在最后一个slot的后面插入新的slot。

原文:http://www.phppan.com/2012/06/php-opcode-cache-apc-1/

  • 大小: 45.4 KB
分享到:
评论

相关推荐

    基于S7-300PLC与MCGS6.2的饮料罐装生产线自动化控制系统设计,包含仿真、程序、IO表与电气原理,实现自动操作、灌装报警及瓶数记录功能 ,基于PLC的饮料罐装生产线控制系统设计 S7-30

    基于S7-300PLC与MCGS6.2的饮料罐装生产线自动化控制系统设计,包含仿真、程序、IO表与电气原理,实现自动操作、灌装报警及瓶数记录功能。,基于PLC的饮料罐装生产线控制系统设计。 S7-300PLC MCGS6.2仿真 仿真,程序,IO表,电气原理图,6500字说明。 实现功能有: (1)系统通过开关设定为自动操作模式,一旦启动,则传送带的驱动电机启动并一直保持到停止开关动作或罐装设备下的传感器检测到一个瓶子时停止;瓶子装满饮料后,传送带驱动电机必须自动启动,并保持到又检测到一个瓶子或停止开关动作。 (2)当瓶子定位在灌装设备下时,停顿1秒,罐装设备开始工作,灌装过程为5秒钟,罐装过程应有报警显示,5秒后停止并不再显示报警。 (2)用两个传感器和若干个加法器检测并记录空瓶数和满瓶数,一旦系统启动,必须记录空瓶和满瓶数,设最多不超过99999999瓶。 (4)可以手动对计数器清零(复位)。 ,关键词:S7-300PLC; MCGS6.2仿真; 传送带驱动电机; 传感器检测; 瓶装; 空瓶数; 满瓶数; 报警显示; 自动操作模式; 灌装设备。,基于S7-300PLC的饮料罐装

    python加密货币时间序列预测源码+数据集-最新出炉.zip

    python加密货币时间序列预测源码+数据集-最新出炉 加密货币分析: 对各种加密货币的数据进行分析和研究。可能会使用到从各种来源收集的数据,包括但不限于加密货币的价格、市值、交易量、交易时间等信息。 探索加密货币市场的趋势和模式,例如价格的波动情况、不同加密货币之间的相关性等。 数据处理与操作: 可能使用 Python 语言(Kaggle 上常用的数据分析语言),并运用一些数据处理和分析的库,如 pandas 用于数据的读取、清洗、整理和转换操作,将原始的加密货币数据转换为更易于分析的格式。 可视化展示: 通过可视化工具,如 matplotlib 或 seaborn 库,将加密货币的信息以图表的形式展示出来,以帮助直观地理解数据中的关系和趋势。 统计分析或预测: 可能会进行一些基本的统计分析,如计算加密货币价格的均值、中位数、标准差等统计量,以描述数据的特征。 或者使用机器学习或时间序列分析的方法对加密货币的价格进行预测,根据历史数据预测未来价格走势。 例如,使用 scikit-learn 进行简单的回归分析: 数据挖掘与特征提取: 挖掘加密货币数据中的特征,如找出影响价格的关键因素,对数据中的特征进行筛选和提取,以帮助更好地理解加密货币的市场行为。

    面对程序设计GJava

    类和对象、继承、封装、多态、接口、异常

    TF_demo1_keras.ipynb

    gee python相关教程

    夜间灯光数据 2023年全球_中国夜间灯光数据合集(数据权威)

    夜间灯光强度(平均灯光强度)的高低反映了一个地区城市化发展的水平,平均灯光强度越高,说明该地区城市群越多,城市化程度越高。夜间灯光数据现在越来越广泛地应用于经济增长分析、经济地理、城市经济学、数字经济等众多领域。 本数据包括三套: [1]中国类DMSP-OLS灯光数据1992-202 [2]中国超长序列灯光数据1984-2020 [3]全球类NPP-VIIRS夜间灯光数据2000-2022 包括:全国各省、市、县夜间灯光数据 矫正后夜间灯光数据 细分:标准差、平均值、总值、最大值和最小值

    工程项目总监绩效考核表.xls

    工程项目总监绩效考核表

    (数据权威)各省份一般公共预算转移支付数据(附送地级市转移支付)

    首先解释一下什么叫转移支付。其实,这和养老金的中央调剂是一样的。 每年,地方都要向中央缴纳财政。而中央又要根据各地方的财政实力,给予转移支付。比如一些经济弱省,本身财政收入就不够支出的,还得上交一部分给中央,怎么维持财政运转?由于各省市直接的财政收入能力存在差异,中央为实现各个地方的公共服务水平平等,于是便有了财政转移支付制度。 简单理解就是富省养穷省。 2022年全国一般预算内财政收入203703亿元,给地方转移支付了97144.75亿元,转移支付数额创下新高。

    基于门控卷积和堆叠自注意力的离线手写汉字识别算法研究.pdf

    基于门控卷积和堆叠自注意力的离线手写汉字识别算法研究.pdf

    逐月中国工业用水空间分布数据集(数据权威)

    【数据介绍】   作为第二大人类部门用水,高质量的工业用水格网数据对于水资源研究和管理至关重要。中国工业用水格网数据(China Industrial Water Withdrawal dataset, CIWW)基于超过 40 万家企业数据、月度工业产品产量数据和连续工业用水统计数据制作得到的一套1965-2020年逐月中国工业用水数据集,其空间分辨率为 0.1°和 0.25°。数据集包括工业用水、企业数量和企业生产总值(辅助数据)等变量,可被用于水文、地理学、环境、可持续发展等方面科学研究。 【数据来源】   数据来源为《中国经济普查年鉴》(省级工业取水量、工业产出)、《中国工业企业数据库》(企业地理位置、产值)、《中国工业产品产量数据库》(工业产品月生产量),以及《中国水资源公报》和(Zhou et al, 2020, PNAS)的工业用水量数据。 【数据处理】 首先通过2008年企业分布数据、经济普查年鉴中分省分部门的工业用水量和工业产值计算得到分省分部门工业用水效率和工业产品产量数据,得到了2008年逐月工业用水数据。然后结合中国水资源公报和相关文献中省级工业用水数据,以2008年工业用水的时空格局作为基础分配工业用水数据,最终得到1965-2020年逐月工业用水的格网数据。详细方法见High-resolution mapping of monthly industrial water withdrawal in China from 1965 to 2020 (Hou et al, 2024, ESSD). 将数据集与统计数据记录和其他数据集进行了验证,结果表示在时间尺度和空间尺度上都与统计数据具有一致性,相比已有工业用水数据有更好的精度。

    65 -质量管理部经理绩效考核表1.xlsx

    65 -质量管理部经理绩效考核表1

    11 -电脑部经理绩效考核表1.xlsx

    11 -电脑部经理绩效考核表1

    大英赛写作必备:实用英语万能句及其应用技巧

    内容概要:本文提供了针对大学生英语竞赛写作准备的重要资源——一系列通用的英文句子模板。这些模板涵盖了现代经济社会的各种话题,从科技进步到环境保护,以及个人品质和社会责任等,并且适用于论述类文章、观点对比和个人见解的表达。文章通过对每一句话的应用环境解释和语法提示,确保使用者可以在实际写作中正确且有效地应用这些表达方式。 适合人群:正在准备参加大学生英语竞赛的学生及其他希望提高书面表达能力的学习者。 使用场景及目标:考生能够在竞赛时间内迅速构建思路完整的文章,增强语言表达的流利性和规范性;帮助学习者积累高级词汇,提升英语写作水平并培养良好的思维逻辑。 阅读建议:结合历年优秀范文进行深入学习,熟悉不同类型话题下的表述方法;练习将提供的句子融入自身创作的文章中,通过不断修订和完善来巩固记忆。同时也可以用于日常的英语写作训练当中。

    法律事务专员绩效考核表.xls

    法律事务专员绩效考核表

    apache-commons-digester-javadoc-1.8.1-19.el7.x64-86.rpm.tar.gz

    1、文件内容:apache-commons-digester-javadoc-1.8.1-19.el7.rpm以及相关依赖 2、文件形式:tar.gz压缩包 3、安装指令: #Step1、解压 tar -zxvf /mnt/data/output/apache-commons-digester-javadoc-1.8.1-19.el7.tar.gz #Step2、进入解压后的目录,执行安装 sudo rpm -ivh *.rpm 4、安装指导:私信博主,全程指导安装

    永磁同步电机磁场定向控制(矢量控制)Simulink仿真模型波形展现与解析,永磁同步电机的磁场定向控制(矢量控制)simulink仿真模型,波形完美 ,核心关键词:永磁同步电机; 磁场定向控制(矢量控

    永磁同步电机磁场定向控制(矢量控制)Simulink仿真模型波形展现与解析,永磁同步电机的磁场定向控制(矢量控制)simulink仿真模型,波形完美 ,核心关键词:永磁同步电机; 磁场定向控制(矢量控制); Simulink仿真模型; 波形完美;,永磁同步电机矢量控制仿真模型:磁场完美调控,波形精确无误

    07 -储运部经理绩效考核表1.xlsx

    07 -储运部经理绩效考核表1

    OQC检验员(成品出货检验员)绩效考核表.xls

    OQC检验员(成品出货检验员)绩效考核表

    基于Matlab2020b的电机控制算法:无传感FOC算法Simulink仿真模型及实践指导,定位+电流闭环强拖+ 角度渐变切+ 速度电流双闭环+ 无传感器角度估算SMO+ PLL 控制方式 Sim

    基于Matlab2020b的电机控制算法:无传感FOC算法Simulink仿真模型及实践指导,定位+电流闭环强拖+ 角度渐变切+ 速度电流双闭环+ 无传感器角度估算SMO+ PLL 控制方式 Simulink 仿真模型 (Matlab2020b版本)以及教授模型搭建 这是一种常用的无传感FOC电机控制算法,掌握这种算法的基本原理,并有仿真模型在手,就可以用它来指导实践中的程序调试,做到实际项目不盲目调试。 模型特点: 1. 所有模块都做到了模块化,各个模块分区清楚,结构清晰。 2. 所有电机和控制参数均在m文件中体现,变量注释清楚,随用随改。 3. 速度环和电流环PI参数均实现自动整定。 4. 模型采用标幺值系统。 5. 各状态切使用stateflow,模型结构清晰。 6.通用表贴和内嵌式电机。 ,定位;电流闭环强拖;角度渐变切换;速度电流双闭环;无传感器角度估算SMO;PLL控制方式;Simulink仿真模型;Matlab2020b版本建模;教授模型搭建;模块化设计;参数自动整定;标幺值系统;Stateflow应用;通用表贴和内嵌式电机。,基于Matlab 2020b的FOC电机

Global site tag (gtag.js) - Google Analytics