一、页面缓存

      1、为什么要用页面缓存

      系统的瓶颈往往是来自于数据库,我们可以使用缓存来减少对数据库的访问!

  2、怎么实现页面缓存

           1.页面缓存思路:

           首先我们需要明白,一个页面是从后端提高数据后,交给springMvc或者SpringBoot进行渲染,主要的页面消耗是在渲染这部分。因此我们需要在这之前进行拦截。(针对于依靠后端进行页面             跳转和渲染的缓存初始阶段)

           核心通用逻辑:当客户的请求到达后端时,先去redis中查询缓存,如果缓存中找不到,则进行数据库逻辑操作,然后渲染,存入缓存并返回给前端!如果在缓存中找到了则直接返回给前端。存             储在Redis缓存中的页面需要设置超时时间,缓存的时间长度根据页面数据变化频繁程度适当调整!目前大多数页面缓存都是在60~120秒,少数几乎不变化的可以调整到5分钟!

          2.热点数据缓存思路:

           所谓热点数据,就是指在某段时间内被频繁使用的对象数据。比如用户登录信息,用户在登录后,每次访问都会携带其cookie信息进入后端,当信息到达后端后,其cookie信息就是我们存在                 redis中的key值。在这一步我们会做四个操作,并且在某些时候可使用拦截器进行处理:

            <1>当用户操作进来的时候,我们获取到Cookie值并在Redis中查找,找到用户信息则刷新用户的登录时间并允许用户通过,找不到用户信息则拒绝用户继续往下!,在后面的数据操作中,如

                 果存在需要使用用户信息的操作,则去Redis中查找,如果存在则允许操作!

    <2>对于热点数据源,被高频访问的不缺分权限信息的热点数据,则设置全局缓存,定时更新则缓存数据,当有操作到此类的热点数据缓存则主动更新缓存中的信息,将用户拦截在数据之外!

    <3>当涉及到用户登录的热点数据被更新后,需要根据用户的token作为key值重新写入或者强制用户重新登录!

    <4>对于需要频繁更新的数据或写入数据的数据,比如点赞次数,在线人数,可以设置一个层级,在没有达到层级前写在缓存中,每次只更新缓存则可以,当到一定次数则写入数据库!

   3.页面局部缓存:

    热点数据缓存,页面静态化进行ajax请求信息更新,此类信息一般都是比较频繁发生变化的,涉及的可能是需要保存在数据库的操作,类似表格信息,即时刷新的数据等!如果是属于查看类的                  并且前端大量请求,可以经由于后端监控,定时写入缓存!

    核心通用逻辑:一般情况下封装以类名--对象名为组合的字符串作为Redis的Key值,然后存入数据库,每次访问到目标的方法都先去缓存读取,然后再处理!

       3、缓存雪崩和穿透问题

    缓存雪崩:缓存雪崩是指因为数据未加载到缓存中,或者缓存同一时间大面积的失效,在某一时刻大量的缓存没有命中,从而导致所有请求都去查数据库,导致数据库CPU和内存负载过高,                    甚至宕机!

    缓存穿透:查询一个数据库必然不存在的数据,那么缓存里面也没有。比如文章表中查询一个不存在的id,每次都会访问DB,如果有人恶意破坏,发送高频请求,那么很可能直接对DB造成                    影响。

         解决办法:对所有可能查询的参数以hash形式存储,在控制层先进行校验,不符合则丢弃。或者对于查询为空的字段,设置一个默认值在缓存中,如果查询到则返回默认值! 或者使                               用具备特点的key值,如果不符合则经由于系统过滤掉,不进入缓存也不进入数据库,此做法可以降低一定的压力,但是解决不了根本的问题。

    缓存失效:如果缓存集中在一段时间内失效,DB的压力凸显,DB负载急剧上升。这个没有完美解决办法,但可以分析用户行为,尽量让失效时间点均匀分布。

    缓存预热:系统部署时,防止用户一瞬间访问数据库,负载过大,由开发人员主动将数据加载到缓存中!

         单机---系统:手动刷新页面既可以了,或者定时缓存缓存

         分布式系统: 分布式系统问题在于数据量非常大,缓存可能会导致数据库宕机!通过程序进行单个缓存加载!

二、如何保证Mysql和Redis数据一致性

    1、方案一:延迟双删

        1.具体的步骤就是:1)先删除缓存

                2)再写数据库

                3)休眠一段时间

                4)再次删除缓存

        2.设置缓存过期时间:从理论上来说,给缓存设置过期时间,是保证最终一致性的解决方案。所有的写操作以数据库为准,只要到达缓存过期时间,则后面的读请求自然会从数据库                        中读取新值然后回填缓存

        3.弊端:结合双删策略+缓存超时设置,这样最差的情况就是在超时时间内数据存在不一致,而且又增加了写请求的耗时。

    2、方案二:异步更新缓存(基于订阅binlog的同步机制)          

                        1.技术整体思路:MySQL binlog增量订阅消费+消息队列+增量数据更新到redis

                1)读Redis:热数据基本都在Redis

                2)写MySQL:增删改都是操作MySQL

                3)更新Redis数据:MySQ的数据操作binlog,来更新到Redis

        2.Redis更新

              1)数据操作主要分为两大块:

              一个是全量(将全部数据一次写入到redis)

              一个是增量(实时更新)

              这里说的是增量,指的是mysql的update、insert、delate变更数据。

              2)读取binlog后分析 ,利用消息队列,推送更新各台的redis缓存数据。

               这样一旦MySQL中产生了新的写入、更新、删除等操作,就可以把binlog相关的消息推送至Redis,Redis再根据binlog中的记录,对Redis进行更新。

               其实这种机制,很类似MySQL的主从备份机制,因为MySQL的主备也是通过binlog来实现的数据一致性。

               这里可以结合使用canal(阿里的一款开源框架),通过该框架可以对MySQL的binlog进行订阅,而canal正是模仿了mysql的slave数据库的备份请求,使得Redis的数                             据更新达到了相同的效果。

               当然,这里的消息推送工具你也可以采用别的第三方:kafka、rabbitMQ等来实现推送更新Redis。