Cache缓存设计
缓存的适用场景:
缓存的目的是提高访问速度,减少不必要的开销,提高性能。那什么样的场景适用于缓存呢。试想一个多项式的计算是一个CPU bound的操作,如果频繁调用同一个多项式的结果。显然缓存结果是一个提高性能的方法。减少了不必要的CPU开销。另外就是提高访问速度。启动的时候,需要加载DB的数据到内存,如果有cache,那么重复get的时候,会优先从缓存获取。显然内存比走IO的db快。
并不是所有的数据都应用于缓存。经常更新的data就不适用于缓存。因为IO的开销没有减少。还要多出维护缓存的额外开销,另外要求强一致的系统也不能使用缓存,因为除非采用P2C,缓存和DB的之间不一致无法避免。
缓存的分类:
- 本地缓存(LRU,hashmap实现的cachebase类)
- 分布式缓存(Redis等)
两者的区分:
- 最重要的是本地缓存在多线程环境中,需要加锁,防止线程竞争. 缓存类的线程安全不同于STL中容器线程安全,因为缓存类提供的接口有限get,delete,set,可以内部封装缓存容器类。缓存单元无需提供线程安全. leveldb中类
LRUCache是一个缓存管理容器,需要提供线程安全,缓存的单元是LRUHandle,无需线程安全. 注意加锁mutex需要会影响性能,但是多线程加锁影响性能的关键是锁的竞争,所以要减少锁的粒度,由此减少竞争的概率.提高性能.Redis 本身是单线程的,所以天然线程安全. - redis支持水平拓展scale up,如果缓存内存过大,可以增加redis cluster模式。而本地内存仅限于单个应用。由于redis支持高可用,本地缓存不支持. 持久化的可以使down 机之后快速热启动. redis的数据结构丰富,针对不同的场景,应用不同类型的数据结构,本地缓存需要自己实现各个场景的cachebase基类.
- 本地缓存需要自己设计多缓存之间相互通知缓存更新的功能。redis天然支持,因为大家共用一份缓存。
- 都无法保证事务.
常见的缓存设计:
1. 本地缓存和DB 2.Redis和DB 3.多层缓存设计(本地缓存,Redis ,DB)
关键问题点:缓存过期的支持,缓存淘汰的支持,缓存更新通知机制的支持。缓存过期就是设置过期时间。每次get缓存的时候,如果超过过期时间,就把缓存删除,这是缓存的惰性删除。还有定期删除,和定时删除,定时删除最为精确,设置定时器,只要缓存过去就能快速的删除,但是需要检测,开销大。redis采用惰性和定期删除的策略。缓存过期的作用结果就是删除过期缓存,节省内存。还有一个关键的作用是让缓存失效。用于保证最终一致性。试想,如果db和redis的数据总是不一致,那么应该怎么办?根据一致性的需求,我们可以提出两个策略:1.一定时间内,一致性得到解决,通过定期去比较db version和redis version. 2.时间不确定,但是可以保证最终一致性。我们设置缓存过期时间。一旦缓存过期,就会删除内存。然后从db取最新的数据.
缓存淘汰的目的更多是在于保证缓存系统在内存不足的条件下能够继续使用。最后是多个缓存之间的更新通知机制,这个保证多缓存之间的一致性。
缓存更新通知机制:
本地缓存如果detect到其他缓存导致的db更新?这需要引入version版本号的概念。cachebase中维护一个m_version的成员变量,代表此id的cache的版本号,同时本地维护一个所有caches的map<id,counter>结构,id表示cache,counter表示版本。这个map更新时机有两处,1. 如果本地cache更新之后,需要increaseCounter那么这个map更新为最新的db值, 2,如果上次更新已经过了T时间,那么也会更新db最小值。 也就是说如果不是本地cache更新,那么map与DB的数据有T时间的mismatch。
m_version在每次getcacheObject的时候比较m_vesion与map[id]是否相等,如果不想等,就应该refresh缓存,从db加载最新的data到本地缓存。如此就实现了本地缓存监测由其他缓存导致的db更新。
关键点:要维护一个version_num的概念。且要考虑多进程条件下,多个本地缓存同时写的情况。因此increaseCounter函数是增加版本号,一定会取db最新的值加1。同时多进程同时写DB的顺序问题有数据库本身处理,可以实现sequence 访问,无需程序员考虑.如果两个进程同时写同一个db table且写入值相同,那么可以让后来的写入失败。
多级缓存的设计:
加入redis作为二级缓存,就构成二级缓存的系统,本地缓存和redis缓存,DB三者的同步更新更加复杂。因为db和redis之间的无法保证事务,需要分布式事务。副作用比本地和db之间大。缓存更新的策略通常包两种情况:
- 先删除缓存,再更新数据库。
- 先更新数据库,再删除缓存。 这两种情况在业界,大家对其都有自己的看法。具体怎么使用还得看各自的取舍。当然肯定会有人问为什么要删除缓存呢?而不是更新缓存呢?你可以想想当有多个并发的请求更新数据,你并不能保证更新数据库的顺序和更新缓存的顺序一致,那就会出现数据库中和缓存中数据不一致的情况。所以一般来说考虑删除缓存。
- 如果采用redis version和db version的策略,那么就可以用更新db,更新redis的策略,因为可以定期通过版本号保证一致性,毕竟之前的策略只是降低不一致性的可能性,但是不能完全避免。需要兜底,要么定期过期,要么通过version扫表
一种设计:

更新的步骤:
Cache缓存设计的更多相关文章
- LeetCode题解: LRU Cache 缓存设计
LeetCode题解: LRU Cache 缓存设计 2014年12月10日 08:54:16 邴越 阅读数 1101更多 分类专栏: LeetCode 版权声明:本文为博主原创文章,遵循CC 4 ...
- 一种小型后台管理系统通用开发框架中的Cache缓存设计
本篇博客记录一下我在实习的公司的后台管理系统开发框架中学习到的一种关于网站的缓存(Cache)的实现方法,我会在弄懂的基础上,将该方法在.net core上进行实现.因为公司开发都是基于.net fr ...
- CYQ.Data V5 分布式自动化缓存设计介绍
前方: 其实完成这个功能之前,我就在思考:是先把想法写了来,和大伙讨论讨论后再实现,还是实现后再写文论述自己的思维. 忽然脑后传来一个声音说:你发文后会进入发呆阶段. 所以还是静下心,让我轻轻地把代码 ...
- nginx+Memcached 缓存设计
单页面缓存方案 单静态页缓存 解决问题场景 常见的缓存设计利用System.Web.Cache 保存在内存内,效率高,可以减轻数据库访问的压力.但是Web除了获取数据之外,还有呈现页面渲染,生成HTM ...
- 注释驱动的 Spring cache 缓存介绍
概述 Spring 3.1 引入了激动人心的基于注释(annotation)的缓存(cache)技术,它本质上不是一个具体的缓存实现方案(例如 EHCache 或者 OSCache),而是一个对缓存使 ...
- [转]注释驱动的 Spring cache 缓存介绍
原文:http://www.ibm.com/developerworks/cn/opensource/os-cn-spring-cache/ 概述 Spring 3.1 引入了激动人心的基于注释(an ...
- paip.cache 缓存架构以及性能提升总结
paip.cache 缓存架构以及性能提升总结 1 缓存架构以及性能(贯穿读出式(LookThrough) 旁路读出式(LookAside) 写穿式(WriteThrough) 回写式 ...
- 注释驱动的 Spring cache 缓存介绍--转载
概述 Spring 3.1 引入了激动人心的基于注释(annotation)的缓存(cache)技术,它本质上不是一个具体的缓存实现方案(例如 EHCache 或者 OSCache),而是一个对缓存使 ...
- CYQ.Data V5 分布式自动化缓存设计介绍(二)
前言: 最近一段时间,开始了<IT连>创业,所以精力和写的文章多数是在分享创业的过程. 而关于本人三大框架CYQ.Data.Aries.Taurus.MVC的相关文章,基本都很少写了. 但 ...
随机推荐
- adf笔记
1>jsf页面js调试,手动添加debugger调试 方案:在页面中添加debugger,然后打开“开发者工具”(必须打开),直接运行页面自动跳转到debugger处. 2>jdevelo ...
- jQuery中deferred对象的使用(一)
在jquery1.5之后的版本中,加入了一个deferred对象,也就是延迟对象,用来处理未来某一时间点发生的回调函数.同时,还改写了ajax方法,现在的ajax方法返回的是一个deferred对象. ...
- python用sqlite3模块操作sqlite数据库-乾颐堂
SQLite是一个包含在C库中的轻量级数据库.它并不需要独立的维护进程,并且允许使用非标准变体(nonstandard variant)的SQL查询语句来访问数据库. 一些应用可是使用SQLite保存 ...
- vnpy自动化交易
c++ python 写的自动化交易平台 期货ctp
- 在linux下使用CMake构建应用程序
本文介绍了一个跨平台的自动化构建系统 CMake 在 linux 上的使用方法. CMake 是一个比 automake 更加容易使用的工具,能够使程序员从复杂的编译连接过程中解脱出来.文中通过一些例 ...
- pymsql的简单实用方法
在进行本文以下内容之前需要注意: 1.你有一个MySQL数据库,并且已经启动. 2.你有可以连接该数据库的用户名和密码 3.你有一个有权限操作的database 连接数据库 #导入pymsql imp ...
- 视觉SLAM实战(一):RGB-D SLAM V2
写在前面 首先打个广告.SLAM研究者交流QQ群:254787961.欢迎各路大神和小白前来交流. 看了前面三篇博文之后,是不是有同学要问:博主你扯了那么多有用没用的东西,能不能再给力一点,拿出一个我 ...
- css常用技巧:input提示文字;placeholder字体修改
1 很多网站都需要更改 <input>内部的placeholder 文字颜色属性:下面来介绍下这个技巧. 2 源代码: <!DOCTYPE html><html> ...
- ES6语法的新特性
ES6 就是ECMAScript 6是新版本JavaScript语言的标准.虽然目前已经更新到ES7,但是很多浏览器还不知处ES7语法,该标准仍在更新中,但目前部门网站都指出ES6的语法.目前ES6也 ...
- Java多线程设计模式(一)
目录(?)[-] Java多线程基础 Thread类的run方法和start方法 线程的启动 线程的暂时停在 线程的共享互斥 线程的协调 Single Threaded Execution Patte ...