走进缓存的世界(二) - 缓存设计

简介: 系列文章 走进缓存的世界(一) - 开篇 走进缓存的世界(二) - 缓存设计 走进缓存的世界(三) - Memcache   如何设计缓存 主要考虑三个问题: 缓存哪些数据 如何缓存 如何保证数据一致性 缓存哪些数据  系统优化时有一句话必须切记:“优化无止境”,所以如果缓存不是必须的,请果断去掉,要知道越是业务上复杂的系统,对Cache的使用反而越简单,因为对于一个复杂、多变、历史悠久的系统,在Cache方面做过度设计会让人深陷其中;缓存的数据越多,系统的维护成本就越高,所以找准需要缓存的点尤为重要。

系列文章

 

如何设计缓存

主要考虑三个问题:

  • 缓存哪些数据
  • 如何缓存
  • 如何保证数据一致性

缓存哪些数据

 系统优化时有一句话必须切记:“优化无止境”,所以如果缓存不是必须的,请果断去掉,要知道越是业务上复杂的系统,对Cache的使用反而越简单,因为对于一个复杂、多变、历史悠久的系统,在Cache方面做过度设计会让人深陷其中;缓存的数据越多,系统的维护成本就越高,所以找准需要缓存的点尤为重要。一般情况下,我们只会缓存给系统带来巨大瓶颈的IO操作,在普通应用里尤其指由top SQL或者慢 SQL所带来的DAO查询;找准需要优化的sql,你可以找DBA帮忙。

如何缓存 

存储介质的选择: 你可以直接缓存在JVM内存里,也可以采用阿里云专门的缓存服务器,如tair、memcache等;

DB、文件其实也可以做缓存,他们一般缓存复杂计算的中间结果,一般很少用到;如果你的缓存是存放在jvm本地,那么通常是用map实现,如果缓存数据更新比较频繁且对数据正确性比较高,那么你需要考虑为其添加并发控制和失效策略。还有一点比较重要的就是,在集群环境下想要做到数据一致性比较困难,主动更新比较麻烦而且达不到其降低数据库IO操作的效果,所以本地缓存适用场景一般是在读访问非常高,而写操作极少,对数据一致性要求不是特别高的场景;如果采用专门的缓存服务器则避免了很多麻烦,阿里云的缓存系统tair,是我们经常使用的缓存中间件,它提供了很好的并发控制和失效机制,另外还提供了不同存储引擎可以供我们选择,如mdb,rdb,ldb;普通的缓存可以选择mdb和rdb,两者分别有memcache和redis的影子,其响应时间和高QPS的表现都非常好,但没有提供持久化,如果要确保数据不丢失可以采用ldb引擎存储,它提供了对数据持久化的支持,相反牺牲了一点点性能。

数据一致性

缓存意味着同样的数据可能有多份并存,如果你的代码没有考虑某种情况导致了两份数据不一致就会有问题发生。解决方法很简单,把你的业务逻辑、代码触发情况都考虑清楚,不要遗留没有触底的地方。

多处使用缓存会导致你的代码逻辑变得异常复杂,这也是为何说在非必要的时候,建议你不要用缓存的原因。

缓存一致性协议就是为了解决数据一致性问题而发明的。缓存一致性协议有多种,大多数计算机设备使用的都属于“窥探(snooping)”协议。

“窥探”的基本思想是,内存是共享资源,所有内存I/O传输都发生在一条共享的总线上,所有的处理器都能看到这条总线,所有处理器对内存的访问请求都要经过仲裁(arbitrate):同一个指令周期中,只有一个处理器可以读写内存中的被缓存的数据。窥探协议的思想是,缓存不仅仅在做内存传输的时候才和总线打交道,而是不停地在窥探总线上发生的数据交换,跟踪其他缓存在做什么。所以当一个缓存代表它所属的处理器去读写内存时,其他处理器都会得到通知,以此来使自己的缓存保持同步。只要某个处理器执行写操作,其他处理器马上就知道这块内存在它们自己的缓存中对应的段已经失效。

在直写模式下,这是很直接的,因为写操作一旦发生,它的效果马上会被“公布”出去。但是如果混着回写模式就有问题了。因为有可能在写指令执行过后很久,数据才会被真正回写到物理内存中。在这段时间内,其他处理器的缓存可能会去写同一块内存地址导致冲突。在回写模型中,简单把内存写操作的信息广播给其他处理器是不够的,我们需要做的是,在修改本地缓存之前,就要告知其他处理器。

搞懂了细节,就找到了处理回写模式这个问题的最简单方案。当处理器想写某个缓存段时,如果它没有独占权,它必须先发送一条“我要独占权”的请求给总线,这会通知其他处理器,把它们拥有的同一缓存段的拷贝失效(如果它们有的话)。只有在获得独占权后,处理器才能开始修改数据——并且此时,这个处理器知道,这个缓存段只有一份拷贝,在我自己的缓存里,这样一来就可以巧妙地避免了冲突。

目录
相关文章
|
7月前
|
缓存 应用服务中间件 数据库
【分布式技术专题】「缓存解决方案」一文带领你好好认识一下企业级别的缓存技术解决方案的运作原理和开发实战(多级缓存设计分析)
【分布式技术专题】「缓存解决方案」一文带领你好好认识一下企业级别的缓存技术解决方案的运作原理和开发实战(多级缓存设计分析)
161 1
|
缓存 Java Maven
Java 使用LRUmap设计一个简单的缓存场景
Java 使用LRUmap设计一个简单的缓存场景
536 0
Java 使用LRUmap设计一个简单的缓存场景
|
XML 存储 缓存
设计一个缓存策略,动态缓存热点数据
写在前面,因为我们最近的大作业项目需要用到热点排行这个功能,因为我们是要使用Elasticsearch来存储数据,然后最初设想是在ES中实现这个热点排行的功能,但是经过仔细思考,在我们这个项目中使用ES来做热点排行是一个很蠢的方式,因为我们这只是一个很小的排行,所以最终我们还是使用Redis来实现热点排行
471 1
设计一个缓存策略,动态缓存热点数据
|
存储 缓存 NoSQL
微服务实践01--微服务管理11--缓存02--分级缓存设计
微服务实践01--微服务管理11--缓存02--分级缓存设计
342 0
微服务实践01--微服务管理11--缓存02--分级缓存设计
|
缓存 前端开发 大数据
如何设计一个缓存函数
在项目中你有优化过自己写过的代码吗?或者在你的项目中,你有用过哪些技巧优化你的代码,比如常用的函数防抖、节流,或者异步懒加载、惰性加载等。
120 0
如何设计一个缓存函数
|
缓存 Java 数据库连接
第06篇:Mybatis缓存设计
MyBatis 内置了一个强大的事务性查询缓存机制,它可以非常方便地配置和定制。本篇文章,小编将会在最短的时间呢,通过观察源码来深刻了解Mybatis的 一级二级缓存;然后在说如何定制。
159 0
|
存储 缓存 运维
|
设计模式 存储 缓存
面试必问的缓存使用:如何保证数据一致性、缓存设计模式
缓存使用在现在的项目中非常常见,缓存在为我们带来便利的同时,也会带来一些常见的问题,如果不谨慎使用,可能会带来意想不到的结果。
553 0
面试必问的缓存使用:如何保证数据一致性、缓存设计模式
|
缓存 NoSQL Redis
一图看懂redis、缓存的设计
一图看懂redis、缓存的设计
160 0
一图看懂redis、缓存的设计
|
存储 缓存 Java
Spring注解缓存设计原理及实战
注解驱动的Spring Cache能够极大的减少我们编写常见缓存的代码量,通过少量的注释标签和配置文件,即可达到使代码具备缓存的能力,且具备很好的灵活性和扩展性。但是我们也应该看到,Spring Cache由于基于Spring AOP技术,尤其是动态的proxy技术,导致其不能很好的支持方法的内部调用或者非public方法的缓存设置,当然这些都是可以解决的问题。
482 0
Spring注解缓存设计原理及实战