我们在课程里,详细解析了一个网站架构各个环节中,涉及到缓存的各种原理,以及它们各自的应用场景和适用对象。
然后咱们在这一节,再了解一下各种缓存使用后,还有什么可以优化的地方?
一:浏览器缓存,
浏览器缓存有两个使用原则:
一个是加大本地缓存的复用性,比如一些不经常改变的静态资源,比如图片、CSS、JS,尽量利用本地缓存,主要的通过Cache-Control:max-age
和 Expires
来进行控制,过期之后则使用 Last-Modified
来进行协商控制。
对于PHP生成的动态资源,如果不经常进行内容改变的话,可以用 header()
主动输出这些文件头。
另一个是尽量减少对服务器的请求量,这个主要集中在页面请求的时候,尽量把多个请求量,合并成一个,比如多个JS合并为一个,把多个小图标并成一个文件,然后就可以统一进行缓存。
二:DNS相关缓存
域名解析也是一个比较耗时间的地方,尽量使用Keep-alive,出来重用TCP-IP连接减少相应时间。
另外一个就是和京东淘宝一样,启用多个域名,来绕过浏览器域名的并发限制,让所有域名同时进行下载减少时间消耗,但注意,域名越多,dns解析也越多,因此这一项是需要按照需求进行平衡的,
三:WebServer相关
启用反向代理服务器,这个服务器不应该仅仅有请求转发的作用,而是应该配置为动态资源转发、静态资源进行缓存和加速,这样可以减少对应用服务器的压力,应用服务器也可以将一些生成的静态化资源,分发到反向代理服务器,使之成为一个缓存节点。
服务器在建设的时候,考虑到异步架构,对于一些非紧急处理的需求,进入消息队列进行处理,一旦主服务器出现故障或其他紧急需求,可以优先处理主服务器的需求,等待处理完成之后,继续处理消息队列。
四:Mysql相关
Mysql的缓存相对来说比较小,而且开关均有资源消耗,所以使用它需要谨慎,它比较适合存储一些消耗大量资源进行的查询,如汇总计算、连表、分页、排序等复杂查询。
缓存命中率相关参数,可以在命令行中使用 show global status
查询到,用 Qcache_hits / (Qcache_hits + Com_select)
来计算出来大约的命中率。不过实际查询缓存的命中率其实比较难以判断,可以通过禁用查询缓存,再重新打开,来判定对应的SQL是否已经触发了查询缓存?
一些查询语句中不确定的参数,如rand 、current_data 、查询结果过大等,都会导致无法进行缓存,另外查询缓存空间用光也会导致缓存的失效。除此之外,对于INNODB来说,表上启用了任何一个锁,都会导致该表的任何查询语句无法缓存。
由于Mysql查询缓存限制比较多,因此对于复杂的缓存需求,建议使用第三方缓存,比如Redis。
五:Redis
主要关注三个指标: 缓存命中、缓存一致性、缓存失效。
Redis的缓存命中:
这个不多说了。多查询日志和键值就能比较直观地算出命中率。尽量提高热点数据的命中率,以保证业务的高效性。
Redis的缓存一致性
同步方案:当有数据更新的时候,如果没有命中缓存直接更新数据库。如果命中了缓存,则更新缓存,然后更新数据库,这种可以比较好的保证缓存一致,代价是每一个请求都需要等待非内存部分,有较大的时间消耗,比较适用于强一致性,弱性能的需求。
异步方案:更新数据的时候,只更新缓存不更新数据库,然后直接返回,后续启用队列异步地批量更新数据库。这种方案响应速度快,比较适用于数据弱一致,但对性能要求高的需求中。
适当运用锁机制,解决各种一致性问题或者防止溢出,比如防止redis秒杀超发等问题。
Redis的缓存失效。
Redis在使用缓存的时候,每一个key都要设置对应的过期时间,但是注意这些时间应该都不一致,比如对于商城来说,用户访问首页的时候,就会同时生成很多的缓存,如果这些缓存的时间都相同,就会在同一个时间进行失效,一旦失效之后用户再进行访问,就需要同时生成所有缓存,这个时间点就会出现比较大的服务器压力。
解决方案很简单,生成缓存的时候,把过期时间设置成一个时间点外加一点随机数,这样首页中生成的所有缓存的时间就都不一致了,在一定程度上分散了缓存失效压力,
Redis及缓存穿透
缓存穿透是指,在缓存中未找到结果,而需要去数据库中继续查询,如果数据库中有记录,那么下一次查询就会被加速。
但是经常会出现的场景是,在数据库中也未找到对应记录,这样的话,每次请求依然会在数据库重新进行检索,如果这个请求是非常复杂的一种,这会造成比较大的流量压力
这种情况一般有两个解决方案:
一个是当查询数据为空的时候,把空结果也进行缓存,这样下次在检索的时候,就可以取到缓存内容了。
另外呢,也可以启用一个保护机制,增加一个标记key,用来标记原来的key。 当标记key存在的时候,直接返回null。 这种机制在实现的时候比较麻烦,主要是用于标记那些查询过于复杂的那些请求。
以上这些是对课程的补充,缓存的知识点比较零散,如果有相关问题,请在提问中询问,我会尽快回复。