知识结构: 1.从架构看缓存 2.文件类缓存 3.内存数据库之Memcached 4.内存数据库之Redis 5.浏览器缓存机制 6.服务器程序的缓存
压力均分,减少对瓶颈环节的流量冲击
简化处理流程,提升整个流程的处理速度
持久化和固化数据
缓存实时性变化要求不严格的内容(防止出现幻度)
缓存经常访问但改动不频繁的内容
网站架构图
注:DiskCache服务器硬件缓存技术
各地部署多套静态缓存服务,本质上是空间成本换时间
自动选择最近的节点内容,不存在再请求原始服务器
适合存储更新更少的静态内容,文件更新慢
将更新频率极低且读取几率高的数据缓存为文件
获取时不再查询数据库而是直接读和解析文件内容
常见于CMS,使用前后端分离的思路如Smarty把页面公用的区域做成模板,并且留下变量区域,后台修改内容时,把变量替换入模板,并且生成HTML,用户访问适合,直接显示HTML页面
特点:有利于搜索引擎优化SEO,加快收录速度
减轻服务器负担,减少数据库请求和运算量
加快页面打开速度,便于进行CDN加速
防止漏洞和入侵
非常适合于文章类网站
所涉及的代码片段:
而面对商城类的网站呢,静态页面就有些不太实际,尤其面对有些客户而制定的各自对应的商品,这个时候就用到了从页面片段缓存到facebook的BigPipe技术,这个技术主要是前后端结合的技术,主要解决的就是页面,尤其是首页,当内容特别多,加载特别慢的时候改进的问题
首先,网站的正规流程是:
program data(php在执行的时候,把数据准备好之后) =》
php buffer(暂存在php的缓存上) =》
tcp buffer(等到php完全执行后,丢给tcp buffer,这个是存在于nginx或者apache里的,然后由他们进行缓存,他们会读取其对应的html还有一些其他的元素,当整个文件完全完毕之后发给客户端) =》
client browers(客户端进行页面的渲染)
BigPipe技术:就是当页面还没有准备完成的时候,把页面分成一个个小块,处理的话利用每个快一个个处理,没处理完一个就存在buffer里面去,然后通知buffer先把数据传到客户端(相当于一边做着蛋糕一边给客户),浏览器在一个请求中不断接受并渲染到页面,逐块显示(JS,不要立刻执行的部分,可以最后再eval进来),为了支持这个技术,服务器也需要改动下
nginx配置: proxy_buffering off; fastcgi_keep_conn on;
php配置:关闭输出缓存 output_buffering=off;
所用的PHP方法:
相对于AJAX的优势:对服务器的压力只在于一次请求,不像一个ajax每次一个模块都要请求一次,形成多次请求
内存数据库是将数据放在内存中直接操作的数据库
解决数据使用效率的问题,减少IO消耗
分为关系型内存数据库和非关系型内存数据库
memcached特征:这是一个分布式高速缓存系统,协议简单,使用简单的基于文本行的协议,基于libevent事件处理,它将事件处理功能封装成一个接口,确保即使服务器端数量增加也能发挥出更好的功能,从而灵活调整服务器连接数,并且他是以k-v结构的键值数据库,内存存储,存读速度快,不互相通信的分布式,每个服务器只对自己的数据进行管理
在分布式架构中:memcached的api是使用crc32方式计算键值,然后把资料分散给不同的机器上,这些机器之间并没有联系,每个机器只对自己的资料数据进行管理,这样可以使多个服务器端协同工作,应用程序端通过指定缓存服务器的ip地址和端口连接到Memcached进行服务,从这些来看,Memcached特别适合做程序和数据库之间的中间层,它可以缓存数据库里面的查询结果,从而减少对数据库的访问次数,或者储存复杂逻辑运算的结果,这样减少重复的计算,这里注意的是Memcached这里并不支持持久化,这样的话一般作为系统的冗余,加速系统的处理,它作为缓存系统处理要考虑数据丢失所造成的影响,比如这些数据是否可以重复获得,或者在高并发的情况下这些数据的丢失是否造成网站架构的崩溃
安全方面:自身缺乏认证以及安全管制,这代表着把Memcached的服务放到防火墙后面,不能把Memcached的端口暴露到外网,这是一个非常危险的行为
Memcached工作原理和内存管理:
传统的内存相当于上图,这个时候当一个数据无效了,进行销毁,那他就会出现大量内存碎片,明显降低了操作系统对内存的管理效率
而Memcached会把内存分为多个Slab,每个Slab内分为多个Page,同一个Slab下的Page空间相同,page里面有很多Chunk,也就是最终放数据的地方,如果数据存取的话根据数据的大小来分配到相应的chunk下去,但是这样可能会造成大量的空间浪费,这个相当于用空间来换时间的办法,Memcache并不会主动释放,等到过期后,就不能通过key来获取他的值,但是当空间全部占用,他会使用最近最少使用算法来进行清理,这样做的优点是很大程度的减少了内存碎片,提升了服务性能
PHP组件和Memcached:
使用Memcached实现分布式算法:这是大数据下一个缓存解决方案,因为Memcached具有服务端互不通信的特点,这就需要Memcached通过程序来实现分布式,也就是通过我们写算法,来让程序找到对应的缓存服务器,为了保证各个服务器的压力均分,我们需要考虑怎么进行分摊压力,怎么来保证算法的命中率
常用的分布式算法:
1.分布式算法之余数计算分散法
根据Key来计算CRC,然后结果对服务器进行取模的到memcached服务器节点,服务器无法连接的时候,将尝试的连接次数加到key后面重新计算
2.分布式算法之一致性哈希算法
使得服务器的变动只能影响一个很小的范围,但是也没有解决雪崩问题,但是雪崩问题不只是算法能解决的问题了,想17年春晚的抢红包,淘宝也出现故障,负责人在知乎上说,用了双11三倍流量布置,但是依然低估了春晚的力量,只能说目前来说一致性哈希算法是常用的
分布式服务器集中式缓存来解决Session共享:
场景:假如你有很多用户,这些用户的登陆在不同服务器上,Session是生成对应的服务器上的,造成的结果是用户在使用的时候发现有的时候自己有权限,有的时候自己没有权限了
解决:因为缓存是集中式的,可以把session放到缓存里面的,对于php而言,它支持把session放到memcached里面的,这样操作之后,session就放到了公共区域,实现了多服务器共享,这样的话不仅解决了Session共享的问题,而且提高了性能,因为Session是以文件的形式存放在磁盘上的,如果数据量过大、有非常大压力的时候,就会出现大量IO问题,如果放到缓存里面,因为缓存是一般是基于内存的,速度特别快,很大的提高了效率
修改session存放方式:在php.ini中修改 session.save_path="ip:端口" session.save_handler="memcached"
如果单独页面想把session存放在缓存里面的话 ini_set("session.save_hander","memcached")
ini_set("session.save_path","ip:11211")
缺点:集群错误会导致用户无法登陆、回收机制可能导致用户掉线,比如memcached挂掉了,session就无法写入,导致客户无法正常登陆等问题
Memcache和Memcached的区别:
也就是说memcache基于php框架内开发的一个扩展,对于libmemcached这个组件提供了api,程序可以通过api来进行交互,所以在linux在编译memcached这个扩展的时候需要安装libmemcached这个库,另外Memcache实现了面向过程和面向对象的接口,而Memcached这个只是实现面向对象的接口,但是提供了更多的协议和调用方式,提供了比较高级的接口和方法,总体来说Memcached的适应性更广一些
Redis的特点:
完全开源免费,遵守BSD协议,是一个高性能的key-value数据库
简单的key-value存储,性能极高
Redis拥有更多的数据结构和并支持更丰富数据操作
Redis支持数据持久化和数据恢复
Redis的所有操作都是原子性的
服务器支持AUTH密码验证
Redis本身是支持事物的,它的原理是批量的把一些操作发送给队列进行缓存,然后收到这些命令进入事务的执行状态,而事务中的命令只要执行一次失败,就不会执行,而且在事务执行过程中,客户端其他的请求都会被拒绝掉,这样保证事务的一致性
Redis和PHP组件的安装和配置:
Redis客户端命令:
Set:
Hash类型:
Set类型:
Zset集合
Redis的持久化:
RDB:指定的时间间隔内保存数据快照 redis.conf save 300 10
AOF:先把命令追加到操作日志的尾部,保存所有历史操作
ROB优点:适合用于进行备份,fork出子进程进行备份,主进程没有任何IO操作,恢复大数据时的速度快
缺点:特定条件下进行一次持久化,易丢失数据,庞大数据时候,保存时会出现性能问题
AOF优点:数据非常完整,故障回复丢失数据少,可对历史操作进行处理 redis.conf:appednonly yes
缺点:文件的体积大,速度低于RDB且故障回复速度慢
Redis集群的方案:Redis Cluster(Redis官方提出来的解决方案)
五、浏览器缓存
浏览器缓存是用户在本地磁盘对用户最近的一次操作所产生的文档进行一次储存,如果用户再次浏览这个界面就会加载文档,主要一些静态资源,尽量的保存在客户端,用户请求的时候就不需要解析一遍了,这样可以减少服务器压力,减少了数据的传输
浏览器处理网页的方式:
Header字段 输出方式:
HTML:
PHP:
还可以通过nginx或者apache进行输出
强缓存 阶段的Header字段:反映头是200
大多数返回标签的时候前两个也会返回,这是向下的兼容性,保证以前的浏览器不会出问题,其中Pragma和Cache-control是双向字段,请求报文和响应报文都会有,其中它如果当请求的话,就是希望服务端返回什么数据,或者通过中间服务器,不要对这些东西进行缓存,而如果是服务端发送给浏览器,就是不要做那些操作,
其中 Pragma 表示页面是否缓存:no-cache(基本只有ie能实现,客户端定义没什么意义)
Expires:后面带了一个时间,也就是格林尼治时间,如果禁用缓存就没什么意义了,但是启用的话,多长时间到什么时候结束,是由这个说了算,比较精确 Sat, 31 Aug 2019 07:46:38 GMT
Cache-control:max-age=秒数(缓存最大的有效时间,当前时间开始到多少秒)
public\private 多页面共享\当前页面有效(还受https协议控制,如果是https,public自动转换为private)
no-cache\no-stoe\must-revalidate:不允许缓存(例如https认证的页面)\ 不允许存在用户磁盘了,存在内存中 \必须请求认证一般配合max-age使用,在多少秒后执行
流程:首次打开页面,服务器下发给浏览器Last_Modified(响应头)告诉它最后一次更新的时间,再次刷新的时候,if-Modified-since(是浏览器发送给服务器的一个字段(请求头))把上次提交的时间再传回去,重新传给了服务端,然后服务器会拿到这个时间与服务器的Last_Modified进行对比,如果传过去的时间和最后修改时间一样的话,就认为没有修改过,就会返回一个304,
服务器程序缓存:
Apache 缓存:两大模块 过期模块 mod_expires.so 缓存模块 mod_cache
通过配置文件控制HTTP的'Expires'和‘Cache-Control’头内容
Apapche 缓存模块:
关于这里Apapche官方还是比较谨慎的,除了配置文件外,几乎没有其他地方可以控制的,因为缓存具有命中率和时间的问题,所以很难用一些程序来主动的更新缓存。
mod_cache:基于URL键的内容动态缓冲模块,缓存响应头和正文,以便在下一个请求时快速相应它
mod_disk_cache(Apache2.2)/mod_cache_disk(Apache2.4)基于磁盘的缓冲模块
mod_mem_cache.so(Apache2.2)基于内存的缓冲模块,2.4版本已经移除
mod_file_cache提供文件描述符缓存支持,加快与缓慢的文件系统服务器的文件访问,只能应用于静态文件
而官方给出来的缓存模块都有时间限制的
PHP的APC和Opcache :
解释性的语言,这种语言事先不需要编译,而是在运行的时候才能翻译成机器语言,所以对于解释性语言来说每执行一次就需要翻译一次,所以导致效率非常的低
而PHP是一种经典的动态语言,所以它的步骤和其他语言是类似的,首先拿到一段代码,然后进行词语解析和语法解析,这个阶段后被翻译成一个个指令然后由zend虚拟机把这些指令一个个执行,而这些指令就是Opcache