主要考虑三个问题:html
系统优化时有一句话必须切记:“优化无止境”,因此若是缓存不是必须的,请果断去掉,要知道越是业务上复杂的系统,对Cache的使用反而越简单,由于对于一个复杂、多变、历史悠久的系统,在Cache方面作过分设计会让人深陷其中;缓存的数据越多,系统的维护成本就越高,因此找准须要缓存的点尤其重要。通常状况下,咱们只会缓存给系统带来巨大瓶颈的IO操做,在普通应用里尤为指由top SQL或者慢 SQL所带来的DAO查询;找准须要优化的sql,你能够找DBA帮忙。redis
存储介质的选择: 你能够直接缓存在JVM内存里,也能够采用阿里云专门的缓存服务器,如tair、memcache等;sql
DB、文件其实也能够作缓存,他们通常缓存复杂计算的中间结果,通常不多用到;若是你的缓存是存放在jvm本地,那么一般是用map实现,若是缓存数据更新比较频繁且对数据正确性比较高,那么你须要考虑为其添加并发控制和失效策略。还有一点比较重要的就是,在集群环境下想要作到数据一致性比较困难,主动更新比较麻烦并且达不到其下降数据库IO操做的效果,因此本地缓存适用场景通常是在读访问很是高,而写操做极少,对数据一致性要求不是特别高的场景;若是采用专门的缓存服务器则避免了不少麻烦,阿里云的缓存系统tair,是咱们常用的缓存中间件,它提供了很好的并发控制和失效机制,另外还提供了不一样存储引擎能够供咱们选择,如mdb,rdb,ldb;普通的缓存能够选择mdb和rdb,二者分别有memcache和redis的影子,其响应时间和高QPS的表现都很是好,但没有提供持久化,若是要确保数据不丢失能够采用ldb引擎存储,它提供了对数据持久化的支持,相反牺牲了一点点性能。数据库
缓存意味着一样的数据可能有多份并存,若是你的代码没有考虑某种状况致使了两份数据不一致就会有问题发生。解决方法很简单,把你的业务逻辑、代码触发状况都考虑清楚,不要遗留没有触底的地方。缓存
多处使用缓存会致使你的代码逻辑变得异常复杂,这也是为什么说在非必要的时候,建议你不要用缓存的缘由。服务器
缓存一致性协议就是为了解决数据一致性问题而发明的。缓存一致性协议有多种,大多数计算机设备使用的都属于“窥探(snooping)”协议。并发
“窥探”的基本思想是,内存是共享资源,全部内存I/O传输都发生在一条共享的总线上,全部的处理器都能看到这条总线,全部处理器对内存的访问请求都要通过仲裁(arbitrate):同一个指令周期中,只有一个处理器能够读写内存中的被缓存的数据。窥探协议的思想是,缓存不只仅在作内存传输的时候才和总线打交道,而是不停地在窥探总线上发生的数据交换,跟踪其余缓存在作什么。因此当一个缓存表明它所属的处理器去读写内存时,其余处理器都会获得通知,以此来使本身的缓存保持同步。只要某个处理器执行写操做,其余处理器立刻就知道这块内存在它们本身的缓存中对应的段已经失效。jvm
在直写模式下,这是很直接的,由于写操做一旦发生,它的效果立刻会被“公布”出去。可是若是混着回写模式就有问题了。由于有可能在写指令执行事后好久,数据才会被真正回写到物理内存中。在这段时间内,其余处理器的缓存可能会去写同一块内存地址致使冲突。在回写模型中,简单把内存写操做的信息广播给其余处理器是不够的,咱们须要作的是,在修改本地缓存以前,就要告知其余处理器。oop
搞懂了细节,就找到了处理回写模式这个问题的最简单方案。当处理器想写某个缓存段时,若是它没有独占权,它必须先发送一条“我要独占权”的请求给总线,这会通知其余处理器,把它们拥有的同一缓存段的拷贝失效(若是它们有的话)。只有在得到独占权后,处理器才能开始修改数据——而且此时,这个处理器知道,这个缓存段只有一份拷贝,在我本身的缓存里,这样一来就能够巧妙地避免了冲突。性能