PHP缓存方式以及常用策略(zhuan)

一、PHP常用的缓存技术

1、代码级缓存

1)数据缓存:是指数据库查询PHP缓存机制,每次访问页面的时候,都会先检测相应的缓存数据是否存在,如果不存在,就连接数据库,得到数据,并把查询结果序列化后保存到文件中,以后同样的查询结果就直接从缓存表或文件中获得。

2)页面缓存:每次访问页面的时候,都会先检测相应的缓存页面文件是否存在,如果不存在,就重新动态生成,得新内容,显示页面并同时生成缓存页面文件,这样下次访问的时候页面文件就发挥作用了。(模板引擎和常见的一些PHP缓存机制类通常有此功能)

3)时间触发缓存:检查文件是否存在并且时间戳小于设置的过期时间,如果文件修改的时间戳比当前时间戳减去过期时间戳大,那么就用缓存,否则更新缓存。

4)内容触发缓存:当插入数据或更新数据时,强制更新PHP缓存机制。

5)静态缓存:是指静态化,直接生成HTML或XML等文本文件,有更新的时候重生成一次,适合于不太变化的页面。

2、服务器级缓存

1)内存缓存:著名就是Memcached,主要用于多台web服务器,是高性能的,分布式的内存对象PHP缓存机制系统,用于在动态应用中减少数据库负载,提升访问速度。

2)操作码缓存:就是在PHP代码解析编译的过程中进行缓存,主要有eaccelerator, apc, phpa,xcache等

3)数据库缓存:就是对sql语句及结果进行缓存,mysql中用的比较多,采用LRU(即least recently used 最近最少使用)算法。

4)基于反向代理的Web缓存:是指在外部请求过来时,设置缓存根据配置文件进行转向解析。这样,服务器请求就可以转发到我们指定的内部地址上,实际就相当于一个内容分发机。如:Nginx,SQUID(一个专用的代理服务器),mod_proxy(apache2以上又分为mod_proxy和mod_cache)。

二、500wan网站缓存机制

目前,500wan用到的缓存技术有:APC(默认), Memcache(全站), Redis(系统平台部), Quickcache(500pai,ledou,show).

网站中看到:类似

Others_EaCache::proc(‘getLotInfoByID_’);

这样的代码,就是用到了缓存机制,他是apc和memcache二级缓存的结合体。默认是用apc,当apc缓存不存在时,会调用memcache缓存。

Apc是什么?

apc它其实是一种php的缓冲器,也叫操作码缓存。它提供两种缓存功能,即缓存Opcode(目标文件),我们称之为apc_compiler_cache。同时它还提供一些接口用于将用户数据驻留在内存中,我们称之为apc_user_cache。我们应该是用到第二种,因为它用到apc_store(),而手册上说:使用apc_store()存储的变量 在不同的请求之间一直持久存在(直到从缓存系统中移除),即缓存在内存中。使用apc缓存时,需要安装apc扩展。

apc默认通过mmap(它将一个文件或者其它对象映射进内存)匿名映射创建共享内存,缓存对象都存放在这块”大型”的内存空间。由APC自行管理该共享内存。通过调整apc.shm_size、apc.num_files_hints、apc.user_entries_hint等参数的值可以使性能达到最佳。当apc.user_entries_hint设置的足够大时,它就相当于纯内存缓存了。当它设置很小时,会比memcahced还慢。

Acp如何缓存?

先看一下PHP代码的执行过程,PHP是解释型语言,对每个web请求都要执行 “解析-编译-执行” 的整个步骤,过程如下:

php解释过程

经过操作码缓存后:

因此当 PHP 脚本的缓存操作码存在时,可以跳过 PHP 请求流程的解析和编译步骤,直接执行缓存操作码并输出结果。明显缩短时间。

Memcache缓存

Memcached缓存属于内存缓存,它是以守护程序方式运行于一个或多个服务器中,随时接受客户端的连接操作,客户端可以由各种语言编写,目前已知的客户端 API 包括 Perl/PHP/Python/Ruby/Java/C#/C 等等。PHP 等客户端在与 memcached 服务建立连接之后,接下来的事情就是存取对象了,每个被存取的对象都有一个唯一的标识符 key,存取操作均通过这个 key 进行,保存到 memcached 中的对象实际上是放置内存中的,并不是保存在 cache 文件中的,这也是为什么 memcached 能够如此高效快速的原因。但是,这些对象并不是持久的,服务停止之后,里边的数据就会丢失。

Memcached对高并发请求效果很明显,用的最多是在缓存数据库数据,使用 memcached 之后,可以减少数据库连接、查询操作,数据库负载下来了,脚本的运行速度也提高了。

Redis与Memcached类似,数据都是缓存在内存中。区别的是redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步。

Quickcache是轻量级的页面缓存,实用于实效性不是很强的页面。

三、缓存使用会出现的问题

对于代码级缓存,除了服务器,网络会影响缓存,基本不会有什么大的问题。但是在高并发的应用中,服务器级缓存就可能会引起严重的问题,主要有以下三种情况:

1. 缓存穿透:500wan网站在接到用户请求时,会先判断缓存是否存在,如果存在就直接返回缓存内容,如果不存在,就直接查询DB,得到结果,缓存后再返回给用户。但是,如果用户请求的数据缓存中一直都不存在,那么就会直接查询DB,缓存就没起到作用了,如果请求量很大,就会给DB造成压力,甚至挂掉。

解决办法:对所有可能查询的参数以hash形式存储,在控制层先进行校验,不符合则丢弃。比如:用户请求某个用户abc的个人信息,但实际上abc用户并不存在,这里就会出现缓存穿透。如果在用户第一次请求时,以用户名作为一个key进行缓存,以后请教时,判断key是否存在,如果存在就返回定义好的结果,如果不存在,也不让它连续多次查询DB,这样就可以防止缓存被穿透了。

2.缓存失效:引起这个问题的主要原因还是高并发的时候。比如500wan网站默认缓存时间是10分钟,并发很高时可能会出在某一个时间 同时生成了很多的缓存,并且过期时间都一样,这个时候就可能引发一当过期时间到后,这些缓存同时失效,请求全部转发到DB,DB可能会压力过重。

解决办法:将缓存失效时间分散开,比如我们可以在原有的失效时间基础上增加一个随机值,比如1-5分钟随机,这样每一个缓存的过期时间的重复率就会降低,就很难引发集体失效的事件。

3.缓存雪崩:这种情况可能出现在并发访问时候。如果缓存集中在一段时间内失效,DB的压力凸显。当发生大量的缓存穿透,例如对某个失效的缓存的大并发访问就造成了缓存雪崩。

解决办法:解决这个问题,其实是在缓存穿透的防止阶段,我们对缓存查询加锁,如果KEY不存在,就加锁,然后查DB入缓存,然后解锁;其他进程如果发现有锁就等待,然后等解锁后返回数据或者进入DB查询。

http://www.thisuc.com/php_cache.html

Leave a Reply

 

 

 

You can use these HTML tags

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

Protected by WP Anti Spam