Web常用缓存详解

本文围绕PHP网站缓存展开,介绍了从架构看缓存的目的与合理使用方式,涵盖文件类缓存、内存数据库(memcached、Redis)、浏览器缓存机制、服务器程序缓存(apache、PHP、mysql)等内容,还总结了缓存知识体系及需注意的时效性、可靠性、一致性等问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

文章目录

第一 知识结构

介绍在php网站中主要的缓存知识点,以一个商场的首页和几个核心页为例,实际应用这些技术。点评这些技术的优点和存在的问题

  1. 从架构看缓存
  2. 文件类缓存
  3. 内存数据库之memcached
  4. 内存数据库之redis
  5. 浏览器缓存机制
  6. 服务器程序的缓存

第二 从架构看缓存

2.1 布局缓存的目的

压力均分,减少对瓶颈环节的流量冲击;简化处理流程,提升整个流程的处理速度;持久化和固化数据

2.2 合理使用缓存

适合存放那些内容:缓存实时性变化要求不严格的内容(防止幻读);缓存经常访问但改动不频繁的内容;

2.3 哪些位置适合做缓存

在这里插入图片描述

第三章 文件类缓存

3.1 CDN缓存原理和介绍(涉及到cdn回源,缓存失效+主动推送更新文件)

3.1.1 特点:
  • 各地部署多套静态存储服务,本质上是空间成本换时间
  • 自动选择最近的节点内容,不存在再请求原始服务器
  • 适合存储更新很少的静态内容,文件更新慢
3.1.2 chrome浏览器的dns缓存设置

在这里插入图片描述

3.1.3 cdn缓存原理

在这里插入图片描述

3.2 数据文件缓存方案

在这里插入图片描述
将更新频率极低且读取机率高的数据缓存为文件,获取时不再查询数据库而是直接读和解析文件内容。

3.3 全页面的静态化(利用php函数来动态生成 .html的静态页面)

在这里插入图片描述
常见于CMS ,使用前后端分离的思路如Smarty把页面共用区域做成模板,并留下变量区域,后台修改内容时,把变量替换入模板,并生成HTML。用户访问时,直接显示HTML页面

特点:

  • 有利于搜索引擎优化seo,加快收录速度
  • 减轻服务器负担,减少数据库请求和运算量
  • 加快页面打开速度,便于cdn加速
  • 防止漏洞和入侵
  • 非常适合文章类网站

3.4 从页面片段缓存到Facebook的BigPipe技术

解决首页加载慢,渲染多少,传输多少

3.4.1 特点:
  • 将页面划分成一个个小块
  • 利用ob_flush() 与 flush() 将缓冲区的内容提前输出给浏览器
  • 浏览器在一个请求中不断的接收并渲染到页面,逐个小块显示出来(注:js部分,不需要立刻执行的部分,可以最后再eval进来 program data >> php buffer >> tcp buffer >> client browers)
3.4.2 做法:

修改nginx.conf

#新增
proxy_buffering off;
fastcgi_keep_conn on;

修改php.ini

;打开并修改output_buffering的值
output_buffering = off

重启nginx,php服务

sudo service nginx restart
sudo service php restart
3.4.3 相关的ob_函数 :
方法作用解释
ob_start()打开输出缓冲区
flush()将当期为止TCP buffer中的内容发送到用户的浏览器该函数不会对服务器或客户端浏览器的缓存模式产生影响。因此必须同时使用ob_flush()和flush()函数来刷新输出缓冲
ob_flush()将PHP buffer中的内容送出到TCP buffer中调用ob_flush()之后缓冲区内容将别丢弃
ob_get_contents()返回内部缓冲区的内容只是得到输出缓冲区的内容,但不清除它,没有激活则返回FALSE
ob_get_length()返回内部缓冲区的长度
ob_end_clean()删除内部缓冲区的内容,并且关闭内部缓冲区
Ob_end_flush()发送内部缓冲区的控制到浏览器,并且关不输出缓冲区
ob_implicit_flush()默认为关闭缓冲区打开绝对输出后,每个脚本输出都直接发送到浏览器,不再需要调用flush().

第四章 内存数据库之memcached

4.1 内存数据库 in-memory database

  • 内存数据库是将数据放在内存中直接操作的数据库(实际解决的是数据使用和存取的效率问题,而不是数据的持久化问题)
  • 解决数据使用效率的问题,减少IO消耗
  • 分为关系型内存数据库和非关系型内存数据库
  • 常见:memcached、Redis、FastDB、eXtremeDB

4.2 memcached的特征

  • 协议简单,使用简单的基于文本行的协议
  • 基于libevent事件处理,灵活调整服务器的连接数
  • 内存存储,存读速度快
  • 不互相通信的分布式,每个服务器只对自己的数据进行管理(crc32计算键值,把资料分散在不同的机器上)
  • 缺乏认证以及安全管理机制(把memcache放在防火墙之后,切不可将memcached端口放在外网当中)

4.3 Memcached工作原理和内存管理

在这里插入图片描述

4.4 Memcached 和 PHP 组件 安装使用

在这里插入图片描述

telnet HOST PORT   #验证是否成功

4.5 Memcached 基本使用

命令说明cli命令示例PHP写法
set存储set key flags exptime bytes [noreply] vlaueset(key,value,time()+300);
setMulti([key=>value],time()+300);
add不存在则存储add key flags exptime bytes [noreply] valueadd(key,value,3600);
replace存在则替换replace key flags exptime bytes [noreply] valuereplace(key, value, time()+300);
append已存在键后追加数据append key flags exptime bytes [noreply] valueappend(key, value);
prepend已存在键前追加数据prepend key flags exptime bytes [noreply] valueprepend(key, value);
cas最后一次取值后未修改再写入cas key flags exptime bytes unique_cas_token [noreply] vlauecase(cas_token, key, value);
get取值get key
gets key1 key2
get(key);
getMulti([key1,key2]);
gets获取带有cas令牌的值get key
gets key1 key2
get(key, cas);
getMulti([key1,key2], cas)
delete删除delete key [noreply]delete(key, time);
incr数字自增incr key numberincrement(key, number);
decr数字自减decr key numberdecrement(key, number);
stats统计信息statsgetStatus();

4.6 使用memcached 实现分布式算法

在这里插入图片描述

4.6.1 分布式算法之余数计算分散法

根据key来计算CRC ,然后结果对服务器数进行取模得到memcached服务器节点。服务器无法连接的时候,将尝试的连接次数加到key后面重新计算
在这里插入图片描述
缺点:添加或移除服务器时,几乎所有缓存要重建,还考虑雪崩式崩溃问题
在这里插入图片描述

4.6.2 分布式算法之一致性哈希算法

在这里插入图片描述

4.7 使用Memcached实现Session共享

在这里插入图片描述
Session存放在共用的Memcached中,实现多服务器共享

缺点:集群错误会导致用户无法登陆、回收机制可能导致用户掉线

修改php.ini

 [Session]
 ;session.save_handler = files
 session.save_handler = "memcached"
 ;session.save_path = "/var/lib/php/sessions"
 session.save_path = "tcp://192.168.1.1:11211"

4.8 memcache与memcached的区别

在这里插入图片描述

第五章 内存数据库之Redis

Redis 是完全开源免费的,遵守BSD协议,是一个高性能的key-value数据库。

5.1 Redis的特点

  • 简单的key-value存储,性能极高。
  • Redis拥有更多的数据结果和并支持更丰富的数据操作。
  • Redis支持数据持久化和数据恢复。
  • Redis的所有操作都是原子性的,支持事务(将操作存入队列,执行事务的过程中会拒绝掉其他的所有请求)。
  • 服务器支持AUTH密码验证(可以允许放在外网中)

5.2 Redis和PHP组件的安装和配置

在这里插入图片描述

redis-cli -h host -p port -a password

5.3 Redis客户端命令

命令说明cli命令示例
del删除keydel key
exists检查给定key是否存在exists key
keys查找所有匹配模式 pattern的keykeys pattern
type返回key所存储的值的类型type key
expire设置key的过期时间expire key time_in_seconds
ttl返回key的剩余过期时间ttl key
saveRDB持久化save
inforedis服务器的各种信息和统计数值info [section]
shutdown保存并停止所有客户端shutdown [nosave] [save]

5.4 Redis 字段类型

字段类型包括:String 字符串、Hash 散列/哈希、List 列表、Set 无序集合、Zset 有序集合

5.4.1 String类型
  • 最常见的数据类型
  • 可以为任何类型的字符串,比如二进制、json对象
  • 最大容量512M
命令说明cli示例php示例
set赋值set key valueset(key, value);
setex赋值并添加过期时间setex key expire valuesetex(key, expire, value);
get取值get keyget(key);
incr递增数字incr keyincr(key);
incrby递增指定的数字incrby key numberincrby(key, number);
decr递减数字decr keydecr(key);
decrby递减指定的数字decrby key numberdecrby(key, number);
incrbyfloat增加指定浮点数incrbyfloat key numberincrByFloat(key,float)
append向尾部追加值append key valueappend(key, value);
strlen获取字符串长度strlen keystrlen(key);
mset同时设置多key值mset key value [key1 v1 …]mSet([k=>v, k1=>v1]);
mget同时获取多key值mget key [k1 …]mGet([k,k1,k2]);
5.4.2 Hash类型
  • 与PHP的Array相似
  • 可以保存多个key=>value对,每个k-v都是字符串类型
  • 最多2^31-1个字段
命令说明cli命令示例PHP写法
hset赋值hset key field valuehset(key, fileld, value);
hmset赋值多个字段hmset key field value [f1 v1 …]hMset(key,[f1=>v1, f2=>v2]);
hget取值hget key fieldhGet(key, field);
hmget取多个字段的值hmget key field1 f2…hmGet(key, [f1, f2]);
hgetall取所有字段的值hgetall keyhGetAll(key);
hlen获取字段的数量hlen keyhLen(key);
hexists判断字段是否存在hexists key fieldhExists(key, field);
hsetnx当字段不存在时赋值hsetnx key field valuehSetNx(key, field, value)
hincrby增加数字hincrby key field numhIncrBy(key, field, num);
hdel删除字段hdel key fieldhDel(key, field);
hkeys获取所有字段名hkeys keyhKeys(key);
hvals获取所有字段值kvals keyhVals(key)
5.4.3 List类型(双向链表)
  • 实现方式为双向链表
  • 用于存储一个有序的字符串列表
  • 从队列的两端添加和弹出元素
  • 特别适合做消息队列
命令说明cli命令示例PHP写法
lpush向列表左端添加元素lpush k vlPush(k, v)
rpush向列表右端添加元素rpush k vrPush(k, v)
lpop从列表左端弹出元素lpop klPop(k);
rpop从列表右端弹出元素rpop krPop(k);
llen获取列表中元素个数llen keylSize(k);
lrange获取列表中某段元素lrange key start endlRange(k, s, e);
lrem删除列表中指定的值lrem k count vlRem(k, v, count);
lindex获取指定索引的元素值lindex key indexlGet(key,index);
lset设置指定索引的元素值lset key index valuelSet(key, index, value);
ltrim只保留列表指定片段ltrim key start endlTrim(key, start, end);
linsert向列表中插入元素linsert key before/after index valuelInsert(key, Redis::BEFORE, index, value)

**注:队列里的数据处理失败之后,应当继续把数据给rpush到队列中,防止消息丢失 **

5.4.4 set类型特点及命令(可用作去重,交/并/差集)
  • 集合中每个元素都是不同的
  • 元素最多为2^32-1
  • 元素没有顺序
命令说明cli命令示例PHP写法
sadd添加元素sadd k v[ v2 v3 …]sAdd(key,v);
srem删除元素Srem k v[v2 v3 …]sRem(k, v);
smembers获得集合中所有元素smembers ksMembers(k)
sismember判断元素是否存在集合中smember k vsisMember(k,v);
sdiff对集合做差集运算sdiff k k1[k2]sDiff(k,k1,k2);
sinter对集合做交集运算sinter k k1[k2]sInter(k, k1, k2)
sunion对集合做并集运算sunion k k1 [k2]sUnion(k, k1, k2)
scard获得集合中元素的个数scard ksCard(k);
sdiffstore对结果做差集并存储结果sdiffstore k k1 [k2]sDiffStore(k, k1, k2);
sinterstore对结果做交集并存储结果sinterstore k k1 [k2]sInterStore(k, k1, k2);
sunionstore对结果做并集并存储结果sunionstore k k1 [k2]sUnionStore(k, k1, k2);
srandmember随机获取集合中的元素srandmember k [count]sRandMember(k, 2);
spop随机弹出一个元素spop keysPop(k, 1);
5.4.5 zset类型(有序集合用的是反列表和跳跃表,所以比list更费内存)
  • 集合是有序的
  • 支持插入,删除,判断元素是否存在
  • 可以获取分数最高/最低的前N个元素
命令说明cli命令示例PHP写法
zadd添加元素zadd key k v[ k1 v1…]zAdd(k, 1 v)
zscore获取元素是分数zscore key valuezScore(k, v);
zrange获取正序排名在某范围的元素zrange key start endzRange(k, 0, -1)
zrevrange获取倒序排名在某范围的元素zrevrange key start endzrevrange(k,0, -1)
zincrby增加某个元素的分数zincrby key increment vzIncrBy(k, increment, v);
zcard获取集合中元素的格式zcard keyzSize(k);
zcount获取指定范围内的元素个数zcount key min maxzCount(k, start, end);
zrem删除一个或多个元素zrem k v[v2]zDelete(k,v);
zremrangebyrank按照排名范围删除元素zremrangebyrank key start endzRemrangebyrank(k, 0, 1);
zremrangebyscore按照分数范围删除元素zremrangebyscore key min maxzRemrangebyscore(k, 0, 3)
zrank获取正序排序的元素排名zrank key valuerRank(k, v);
zrevrank获取逆序排序的元素排名zrevrank key valuezRevRank(k, v);

5.5 Redis的持久化

5.5.1 方式
  • RDB 指定的时间间隔内保存数据快照
  • AOF 先把命令追加到操作日志的尾部,保存所有历史操作
5.5.2 RDB持久化-指定时间间隔内保存数据快照(适合灾难恢复)
#redis.cnf
#持久化策略
save 900 1		#每15分钟变更一次记录
save 300 10		#每5分钟变更10次
save 60 10000	#每1分钟变更10000次记录
#保存路径
dir /var/lib/redis
dbfilename dump.rdb

优点

  • 适合用户备份
  • fork 出子进程进行备份,主进程没有任何IO操作
  • 恢复大数据集时的速度快

缺点:

  • 特定条件下进行一次持久化,易丢失数据
  • 庞大数据时,保存时会出现性能问题
5.5.3 AOF 持久化-先把命令追加到操作日志的尾部,保存历史操作
#redis.cnf
dir /var/lib/redis
appendonly yes
appendfilename "appendonly.aof"
appendfsync everysec(异步)/always(同步)/no(不同步)

优点:

  • 数据非常完整,故障恢复丢失数据少
  • 可对历史操作进行处理

缺点:

  • 文件的体积大
  • 速度低于RDB且故障恢复速度慢

5.6 合理地使用Redis

  • 防止内存占满
    • 设置超时时间
    • 不存放过大文件
    • 不存放不常用数据
  • 提高使用效率
    • 合理使用不同的数据结构类型
    • 慎用正则处理或批量操作Hash、Set等

5.7 Redis Cluster集群

5.7.1 集群部署

在这里插入图片描述

5.7.2 Redis Cluster结构

在这里插入图片描述

5.7.3 注意事项

在这里插入图片描述

第六章 浏览器缓存机制

1. 浏览器处理网页的方式

在这里插入图片描述

2. 浏览器缓存方式

Header 字段输出方式
#常见的缓存方式包括 html/php/apache/nginx
#html输出方式
<meta http-equiv="Cache-Control" content="max-age=7200"
#php输出方式
header("Cache-Control: max-age=7200");
6.2.1 强缓存阶段的Header字段

缓存配置的优先级(Cache-control的参数通常会组合使用)
在这里插入图片描述

6.2.2 协商缓存阶段的Header字段

在这里插入图片描述

3. 合理使用浏览器缓存

  • 页面链接的请求无需做长时间缓存
  • 敏感数据像订单等不宜做缓存
  • 静态资源部分,通常会设定一个较长的缓存时间
  • 冷热数据分离,减少请求量
  • 不要随意修改文件,建议使用?version=** 调用多版本
  • 不建议使用ETag,尤其是分布式

第七章 服务器程序的缓存

7.1 apache缓存

7.1.1 apache的缓存机制
mod_expires.so #过期模块
mod_cache 缓存模块
7.1.2 apache过期模块

通过配置文件控制HTTP的"Expires:" 和"Cache-Control:" 头内容

#启用expires_ module模块
LoadModule expires_module modules/mod_expires.so
#启用有效期控制
ExpiresActive On
#GIF有效期为1个月
ExpiresByType image/gif A2592000
#HTML文档的有效期是最后修改时刻后的一星期
ExpiresByType text/html M604800
#以下的含义类似
ExpiresByType text/css "now plus 2 months "
ExpiresByType image/jpeg "access plus 2 months'

其中

ExpiresByType text/html “now plus 2 months”
#“ExpiresByType” =>有mime决定过期配置
#text/html =>html文件
#now => Access Now a(过期时间从访问时开始计算) | Modification M A(被访问文件的最后修改时间开始计算)
#months => years|months|weeks|days|hours|minutes|seconds

7.1.3 Apache缓存模块
  • mod cache :基于URI键的内容动态缓冲模块,缓存响应头和正文,以便在下一个请求时快速响应它
    • mod_ disk_ cache (Apache2.2) / mod_ cache_ disk (Apache2.4) 基于磁盘的缓冲模块
    • mod mem cache.so (Apache2.2)基于内存的缓冲模块,2 4版本已经移除
  • mod_ file_ cache 提供文件描述符缓存支持,加快与缓慢的文件系统服务器的文件访问,只能应用于静态文件

7.2 PHP缓存

7.2.1 PHP的APC和Opcache
  • Opcache是一种通过将解析的PHP脚本预编译的字节码存放在共享内存中来避免每次加载和解析PHP脚本的开销。
  • 解析器可以直接从共享内存读取已经缓存的字节码,从而大大提高PHP的执行效率。
  • APC是缓存、优化PHP中间代码的架构,可以缓存 Opcodes。
  • PHP5.5以后, Zend Opcache整合到PHP中,并可代替APC使用。此功能默认关闭。
7.2.2 php的执行过程

在这里插入图片描述

7.3 mysql缓存

7.3.1 mysql的缓存相关参数和优化点

在这里插入图片描述

#my.cnf
query_cache_size = 16M
query_cache_limit = 1M
query_cache_type = 1 #开启缓存 
show variables like "%query_cache%" #查询缓存是否开启
show status like "%Qcache%" #显示查询缓存空间的状态
7.3.2 mysql的memory存储
  1. 原理:创建表结构使用ENGINE=MEMORY生成内存表,表结构存在磁盘上的.frm文件中,服务器启动后,用此结构在内存中创建空白表,并默认使用hash索引。

  2. 优点:

    • 速度比其他存储引擎更快,适合做热点表的前置缓存
    • SQL操作与存储引擎一致
  3. 使用要点:

    • VARCHAR这样的可变长度类型将转换为固定长度
    • MYSQL4.1.0之前不支持auto_increment列
    • 不能包含BLOB或TEXT列
    • 重启数据丢失,如果有备份,会导致数据与备份不一致
    • 内存表数据大于max_heap_table_size设定值,超出数据会存储在磁盘上
    • 高负载时扩展性和混合写操作的并发处理性能不佳

第八章 总结

8.1 缓存知识体系

在这里插入图片描述

8.2 缓存需要注意事项

8.2.1 时效性和过期机制:
  • FIFO(first in first out)先进先出策略
  • LFU(less frequently used)最少使用策略
  • LRU(least recently used)最少使用策略
  • 过期时间
8.2.2 可靠性:
  • 介质类型
  • 允许的最大空间
  • 命中率(多指内存数据库)
  • 安全性能
8.2.3 一致性和压力处理:
  • 一致性
  • 缓存失效
  • 缓存穿透
  • 雪崩
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值