缓存
凡是位于速度相差较大的两种硬件之间,用于协调两者数据传输差异的结构,都称为cache。缓存可分为本地缓存和分布式缓存,在现在的系统架构中,缓存的地位可以说是非常高的。因为在互联网的时代,请求的并发量可能会非常高,在分布式数据库中,对高并发的要求越来越高,实现高并发的策略,需要借助一些缓存的实现机制,而缓存由于是在内存中处理,并不需要磁盘的IO,所以非常适合于高并发的处理,也就成为了各个系统中必不可少的一部分了。不过,由此产生的问题也是非常多的,其中一个就是如何保证数据库和缓存之间的数据一致性。由于数据库的操作和缓存的操作不可能在一个事务中,也就势必会出现数据库写入失败,缓存不能更新,缓存写入失败的补偿机制。这是我们必须要解决的问题,协调好与缓存机制之间的协调关系。来处理应用中的实际问题。
原理
分布式数据库系统中,数据分散存储在不同的数据节点。由于不同节点数据访问频率的多变性和差异性,导致各个节点的负载不均衡,降低了系统整体性能。因此,高效动态地组织管理系统缓存以提高分布式数据库整体性能,是当前的热点研究问题之一。自适应多级缓存机制采用实时动态分配缓存资源的技术,在提高分布式数据库系统查询响应速度的同时解决了热数据节点导致的系统瓶颈问题。提出了一种两层架构的并发执行策略,根据访问数据节点和数据表将并发SQL(Structured QueryLanguage)粗粒度地划分为多个可并发执行队列,提高SQL的并发执行速度;提出一种分区分级缓存管理策略,将缓存项按存储节点和数据表分区存储,按优先级分层管理,提高缓存匹配速度;将虚拟缓存技术引入缓存管理中,通过动态调整虚拟缓存与物理缓存映射关系将更多的缓存资源的分配给分布式数据库系统中响应速度慢的节点,解决了热数据节点导致的系统性能瓶颈问题;提出了自适应的缓存替换算法RFS(Replacement For Semantic)代替传统的LRU(Least Recently Used)方法,查询执行时间、历史命中时间间隔、命中类型以及缓存项所占空间大小作为替换权值的衡量指标,提高缓存命中率。系统测试与结果分析表明:在分布式数据库系统环境下,自适应多级缓存机制相比于单级静态缓存机制,整个系统响应速度提高了15%以上;相比于无缓存机制,响应速度提高了30%。RFS相比于传统的LRU缓存替换算法在性能上提升了20%。
实现方式
一般数据库缓存主要包括以下四种。
第一种:
单个对象的缓存(一个对象就是数据库一行记录),对于单个对象的缓存,用HashMap就可以了,稍微复杂一点用LRU算法包装一个HashMap,再复杂一点的分布式用memcached即可,没什么太难的;
第二种:
列表缓存,就像论坛里帖子的列表;
第三种:
长度的缓存,比如一个论坛板块里有多少个帖子,这样才方便实现分页。
第四种:
复杂一点的group,sum,count查询,比如一个论坛里按点击数排名的最HOT的帖子列表。
从理论上来说,给缓存设置过期时间,是保证最终一致性的解决方案。这种方案下,我们可以对存入缓存的数据设置过期时间,所有的写操作以数据库为准,对缓存操作只是尽最大努力即可。也就是说如果数据库写成功,缓存更新失败,那么只要到达过期时间,则后面的读请求自然会从数据库中读取新值然后回填缓存。
因此,接下来讨论的思路不依赖于给缓存设置过期时间这个方案。 在这里,我们讨论三种更新策略。
三种更新策略
先更新数据库,再更新缓存
是最简单的一种缓存双写方案,使用这种双写的方案,只要在数据成功写入数据库后,刷新缓存就可以了,代码简单,维护也很简单。但是,简单的前提下,带来的问题也是很直接的。
先删除缓存,再更新数据库
由于上述方式存在的问题,那么我们就考虑,能不能先删除缓存,在更新数据库,这样,在更新数据库的前后,由于缓存中没有数据了,请求就会穿透到数据库直接读取数据然后放入缓存,这样,缓存就不会被频繁的刷新了。不过,这样一来,新问题又出现了。有两个请求,一个请求A,一个请求B,请求A去写数据,请求B去读数据。当并发量高的时候,就会出现以下情况: 请求A进行写操作,删除缓存 -> 请求B查询发现缓存不存在 -> 请求B去数据库查询得到旧值 -> 请求B将旧值写入缓存 -> 请求A将新值写入数据库。这是,脏数据又出现了。如果我们没有设置缓存的过期时间,那么在下一次下入数据前,脏数据就会一直的存在。针对这种脏数据出现的情况,我们决定在写入数据后,增加一点延时,再删除一次数据,于是就有了方法三。
先更新数据库,再删除缓存
我们在把数据更新到数据库后,把删除缓存的消息加入到队列中,如果队列执行失败,就再次加入到队列执行直到成功为止。这样,我们就能够有效的保证数据库和缓存的数据一致性了,不管是读写分离还是其他情况,只要队列消息能够保证安全,那么缓存就一定会被刷新。
自适应的缓存替换算法RFS
缓存资源自适应调度算法,以及对传统的语义缓顾存匹配算法,缓存替换算法的改进,最后针对对语义缓存匹配算法造成的碎片问题,提出缓存项合并算法,提高缓存管理效率。
缓存资源调度算法
缓存机是能很好的提高分布式数据库的查询效率,但是缓存资源是有限的,需要有高效的缓存策略才能利用有限的缓存资源发挥最大作用。分布式数据库系统相对于集中式数据库系统,结构更加复杂,分布式的特性决定系统运行状态更加复杂多变。分布式数据库系统需要将缓存分区管理,缓存资源的分配是一个重要的研究内容。特别是分布式数据需要将SQL拆分执行。好的缓存资淅分配方式早将缓存资源及时的调度到系统执行性能瓶颈处,是缓存资源发挥更好的作用。
缓存匹配算法
缓存匹配:语义缓存将查询语义和查询结果按照特定形式组织起来,然后通过缓存语义匹配算法,从组成瞎了眼中搜索可用缓存数据,通过查询缓存裁剪技术将查询拆分成探测查询和剩余查询。缓存区满时缓存替换算法会选择淘汰旧缓存项,缓存数据的裁剪会导致缓存项超来超多,导致缓存维护开销境大,缓存合并算法能有效解决这个问题。
查询裁剪:查询与缓存的的相交方式可分为属性投影相关,谓词和混合相交三种情况。经过查询裁剪之后,原来与缓存项相交的查询被拆分成探测查询和剩余查询,探测查询可以从匹配级存项中导出查询结果,而剩余查询则会继续与其它缓存项匹配后继续裁剪。直到最后匹配完整个虚拟缓存区后,将剩余查询送到后端数据节点请法庭数据。
缓存替换算法
当有新缓存项需要存入缓存区,但是缓存区满时,需要通过缓存替换算法从缓存区中选择淘汰一个或者多个缓存项,来为新缓存项腾出位置。高效的缓存替换算法能将命中率高的缓存项保留在缓存区而淘汰命中率低的缓存项,从而提高缓存利用率。传统的缓存项替换算法大都采用LRU替换算法,即最少使用算法。该算法以最近命中时间间隔为替换权值的唯一参考。不能自适应的反应数据库的实时运行状态。针对语义缓存特点,提出一种自适应的缓存替缺钱算法RFS,将数据库实际运行信息与历史命中时间间隔和命中类型以及缓存项所占空间大小综合考虑分析的一种算法,能够自适应的随着数据库过劲行状态和缓存区状态的变化进行动态调整。
缓存合并算法的三种方式
第一种
是采取取全合并策略,将能合并的缓存项进行合并操作,这样做使得总体缓存项罗少,没有缓存碎片,缓存维护开销很低,但是取胜着合并的进行,单个缓存项会变得越来越大,而太大的组成存会限制缓存的利用率并增加查询裁剪开销。
第二种
是采取不合端午节策略,这样虽然能提高缓存的利用率,但是组成存碎片会越来越多,缓存切尔西和缓存项维护开销增大。
第三种
为上面两种方式的结合,在特定时间选择部分缓存项进行合并。 并不是所有的缓存项都能进行合并。语义缓存项合并的目录是简化语义缓存项的描述,减少语义缓存碎片。如果将相关的语义缓存项合并,如总是被相同的查询操作命中的两个缓存项,两次裁剪工作只需要一资完成,缓存匹配开销得降低。
优势与劣势
优势
- 响应更快,内存的速度远远大于磁盘和远程获取;
- 节省计算资源,直接缓存的是结果;
- 可以降低计算压力;
- 数据读写分离,高性能,高可用 。
劣势
- 数据脏读(过期失效和失效通知来处理) ;
- 热点数据难以识别;
- 分布式缓存数据跨网络传输,性能低于本地缓存。
面临挑战
- 缓存雪崩:由于原有缓存失效,新缓存为到期间所有原本应该访问缓存的请求都去查询数据库了,而对数据库、CPU和内存造成巨大压力,严重的会造成数据库宕机。从而形成一系列连锁反应,造成整个系统崩溃。
- 缓存穿透:缓存穿透是只用户查询数据,在数据库没有,自然在缓存中也不会有。这样就导致用户查询的时候,在缓存中找不到 ,每次都要去数据库再查询一遍,然后返回空(相当于进行了两次无用的查询)。这样请求就绕过缓存直接查数据库,这也是经常提的缓存命中率问题。
- 缓存预热:缓存预热就是系统上线后,将相关的缓存数据直接加载到缓存系统。这样就可以避免在用户请求的时候,先查询数据库,然后再将数据缓存的问题。用户直接查询事先预热的缓存数据。
- 缓存更新:缓存更新除了缓存服务器自带的缓存失效策略之外,我们还可以根据具体的业务需求进行自定义的缓存淘汰。
- 缓存降级:当访问量剧增、服务出现问题(如响应时间慢或不响应)或非核心服务影响到核心流程的性能时,仍然需要保证服务还是可用的,即使时有损服务。系统可以根据一些关键数据进行自动降级,也可以配置开关实现人工降级。降级的最终目的是保证核心服务可用,即使是有损的。如何有效应用本地和分布式缓存相结合的策略,合理划分两者的应用场景。
以上为缓存内容,「分布式技术专题」是由hubble数据库团队精心整编,专题会持续更新,欢迎大家保持关注。




