缓存ABC

Intro

缓存是一种比较常见的用来将提高系统性能的方式。从线程缓存、进程缓存、到内存缓存再到分布式缓存再到CDN,都是属于缓存的范畴。

缓存的本质是空间换时间以提高读的效率,牺牲一些内存空间来换取之后的快速读取与访问。

缓存3问

为什么需要缓存?

一般在项目中,最消耗性能的地方就是后端服务了,而后端的数据库的读写频率常常都是不均匀分布的,而且大多情况是读多写少,并且读操作(select)还会有一些复杂的判断条件,比如 like、group、join 等等,这些语法是非常消耗性能的,所有会出现很多的慢查询,因此业务量上来之后,数据库很容易在读操作的环节遇到瓶颈。

添加了缓存之后,针对绝大多数的读多写少的业务来说能够很大程度上提高业务的qps、提高系统的反应速度,提升用户的用户体验。

使用缓存会遇到哪些问题呢?

  1. 数据一致性问题

虽然缓存可以提高整体性能,但是它也可能会带来别的问题。例如使用缓存之后,就相当于把数据存放了2份,一份是在数据库中,另一份存放在缓存中。当有新的数据要写入或者旧数据需要更新的时候,如果我们只更新了其中一份数据源,那两边的数据就不一致了,这里就涉及到使用缓存的一个原则,如果数据有很强的一致性要求就要慎重考虑是否适合使用缓存了。

  1. 缓存过期时间问题

    设计缓存的过期时间必须与业务实际情况相结合。因为如果设计的过期时间太短了,那会导致缓存效果不佳,仍会造成频繁的从数据库中往缓存里写数据。如果缓存设计的过期时间过长又会导致内存空间的浪费。

  2. 缓存的命中率问题

    这也是设计缓存中需要存放哪些数据的很重要一点,如果缓存命中率过低,就会失去缓存效果。一般对于热点数据而言,要保证命中率达到70%以上效果最佳。

  3. 缓存的击穿/穿透/雪崩问题

  • 缓存击穿

一般的缓存系统,都是按照key去缓存查询,如果不存在对应的value,就应该去后端系统查找(比如db)。如果key对应的value是一定不存在的,并且对该key并发请求量很大,就会对后端系统造成很大的压力。在高并发下,多线程同时查询同一个资源,如果缓存中没有这个资源,那么这些线程都会去数据库查找,对数据库造成极大压力,缓存失去存在的意义

  • 缓存雪崩

当缓存服务器重启或者大量缓存集中在某一个时间段失效,这样在失效的时候,也会给后端系统(比如db)带来很大压力。

  • 缓存穿透

缓存穿透是指用户查询数据,在数据库没有,自然在缓存中也不会有。这样就导致用户查询的时候,在缓存中找不到,每次都要去数据库中查询。

什么样的情景下使用缓存

  • 读多写少的业务场景
  • 对数据一致性性要求不高,允许一定时间内的数据不一致
  • 允许缓存丢失,使用缓存要考虑缓存miss的处理

缓存的更新策略具体有哪些?

典型的缓存模式,一般有如下几种:

  • Cache Aside

  • Read/Write Through

  • Write Behind

每种模式都有不同的特点,适应与不同的项目场景,下面来依次看看:

Cache Aside 模式

这是大家经常用到的一种策略模式。这种模式主要流程如下:

应用在查询数据的时候,先从缓存Cache中读取数据,如果缓存中没有,则再从数据库中读取数据,得到数据库的数据之后,将这个数据也放到缓存Cache中。

如果应用要更新某个数据,也是先去更新数据库中的数据,更新完成之后,则通过指令让缓存Cache中的数据失效。

这里为什么不让更新操作在写完数据库之后,紧接着去把缓存Cache中的数据也修改了呢?

主要是因为这样做的话,就有2个写操作的事件了,担心在并发的情况下会导致脏数据,举个例子:

假如同时有2个请求,请求A和请求B,并发的执行。请求A是要去读数据,请求B是要去更新数据。初始状态缓存中是没有数据的,当请求A读到数据之后,准备往回写的时候,此刻,请求B正好要更新数据,更新完了数据库之后,又去把缓存更新了,那请求A再往缓存中写的就是旧数据了,属于脏数据。

那么 Cache Aside 模式就没有脏数据问题了吗?不是的,在极端情况下也可能会产生脏数据,比如:

假如同时有2个请求,请求A和请求B,并发的执行。请求A是要去读数据,请求B是要去写数据。假如初始状态缓存中没有这个数据,那请求A发现缓存中没有数据,就会去数据库中读数据,读到了数据准备写回缓存中,就在这个时候,请求B是要去写数据的,请求B在写完数据库的数据之后,又去设置了缓存失效。这个时候,请求A由于在数据库中读到了之前的旧数据,开始往缓存中写数据了,此时写进入的就也是旧数据。那么最终就会导致,缓存中的数据与数据库的数据不一致,造成了脏数据。

不过这种概率比上面一种概率要小很多。所以整体而言  Cache Aside 模式 还是一种比较简单实用的方式。

Read/Write Through 模式

这个模式其实就是将 缓存服务 作为主要的存储,应用的所有读写请求都是直接与缓存服务打交道,而不管最后端的数据库了,数据库的数据由缓存服务来维护和更新。不过缓存中数据变更的时候是同步去更新数据库的,在应用的眼中只有缓存服务。

流程就相当简单了:

应用要读数据和更新数据都直接访问缓存服务,缓存服务同步的将数据更新到数据库

这个模式出现脏数据的概率比较低,但是太依赖缓存服务了,对缓存服务的稳定性有较大要求。

Write Behind 模式

这个模式就是 Read/Write Through 模式 的一个变种。区别就是 Read/Write Through 模式的缓存写数据库的时候是同步的,而 Write Behind 模式 的缓存操作数据库是异步的。

流程如下:

应用要读数据和更新数据都直接访问缓存服务

缓存服务异步的将数据更新到数据库(通过异步任务)

这个模式的特点就是速度很快,效率会非常高,但是数据的一致性比较差,还可能会有数据的丢失情况,实现逻辑也较为复杂。

Reference

Contact

contact me:weihanli@outlook.com

缓存ABC的更多相关文章

  1. Vue 组件&组件之间的通信 之 template模板引用与动态组件的使用

    template模板引用 在component的template中书写大量的HTML元素很麻烦. Vue提供了<template>标签,可以在里边书写HTML,然后通过ID指定到组建内的t ...

  2. .NET缓存框架CacheManager在混合式开发框架中的应用(1)-CacheManager的介绍和使用

    在我们开发的很多分布式项目里面(如基于WCF服务.Web API服务方式),由于数据提供涉及到数据库的相关操作,如果客户端的并发数量超过一定的数量,那么数据库的请求处理则以爆发式增长,如果数据库服务器 ...

  3. node(Buffer缓存区)

    // 创建buffer类 var buf=new buffer(10); var buf=new buffer([10,20,30,40]); var buf=new buffer("www ...

  4. HashMap实现缓存(二)

    package com.cache; import java.util.*; //Description: 管理缓存 //可扩展的功能:当chche到内存溢出时必须清除掉最早期的一些缓存对象,这就要求 ...

  5. HappyAA服务器部署笔记2(nginx的静态资源缓存配置)

    我近期对服务器进行了少量改进,虽然之前使用了nginx反向代理之后性能有所提高,但仍然不够,需要使用缓存来大幅度提高静态资源的访问速度. 服务器上的静态资源主要有这些:png, jpg, svg, j ...

  6. python对缓存(memcached,redis)的操作

    1.Memcached Memcached 是一个高性能的分布式内存对象缓存系统,用于动态Web应用以减轻数据库负载.它通过在内存中缓存数据和对象来减少读取数据库的次数,从而提高动态.数据库驱动网站的 ...

  7. 处理ios webview 更新缓存本地css、js后webview缓存无法更新的问题

    项目中需要使用app本地css.js,并且可以根据服务下发自动更新本地css.js.测试发现只要更新后的css或者js和更新前路径一致,webview加载的还是更新前的css.js.怀疑是webvie ...

  8. Java 中常用缓存Cache机制的实现

    所谓缓存,就是将程序或系统经常要调用的对象存在内存中,一遍其使用时可以快速调用,不必再去创建新的重复的实例.这样做可以减少系统开销,提高系统效率. 所谓缓存,就是将程序或系统经常要调用的对象存在内存中 ...

  9. PHP缓存机制Output Control详解

    开启OB缓存的方式有如下两种: 1. php.ini中开启 output_buffering = 4096 启用了此指令,那么每个PHP脚本都相当于一开始就调用了ob_start()函数,PHP5.5 ...

随机推荐

  1. [Swift]LeetCode230. 二叉搜索树中第K小的元素 | Kth Smallest Element in a BST

    Given a binary search tree, write a function kthSmallest to find the kth smallest element in it. Not ...

  2. [Swift]LeetCode514. 自由之路 | Freedom Trail

    In the video game Fallout 4, the quest "Road to Freedom" requires players to reach a metal ...

  3. [Swift]LeetCode530. 二叉搜索树的最小绝对差 | Minimum Absolute Difference in BST

    Given a binary search tree with non-negative values, find the minimum absolute difference between va ...

  4. [Swift]LeetCode819. 最常见的单词 | Most Common Word

    Given a paragraph and a list of banned words, return the most frequent word that is not in the list ...

  5. [Swift]LeetCode933. 最近的请求次数 | Number of Recent Calls

    Write a class RecentCounter to count recent requests. It has only one method: ping(int t), where t r ...

  6. MySQL casting from decimal to string(mysql decimal 转 varchar)

    今天群里一个哥们问我mysql怎么将decimal转成varchar,经过查阅资料发现,mysql好像不能将decimal直接转换成varchar,但是可以转成char,原文链接:http://sta ...

  7. 【netty】(2)---搭建一个简单服务器

    netty(2)---搭建一个简单服务器 说明:本篇博客是基于学习慕课网有关视频教学.效果:当用户访问:localhost:8088 后 服务器返回 "hello netty"; ...

  8. Event(事件)的传播与冒泡

    特性说明和原理图: 标准浏览器和Ie9+浏览器都支持事件的冒泡和捕获,而IE8-浏览器只支持冒泡 标准和Ie9+浏览器用stopPropagation()或cancelBubble阻止事件传播,而ie ...

  9. Unity资源打包学习笔记(一)、详解AssetBundle的流程

    转载请标明出处:http://www.cnblogs.com/zblade/ 本文参照unity官网上对于assetBundle的一系列讲解,主要针对assetbundle的知识点做一个梳理笔记,也为 ...

  10. Asp.Net Core 程序部署到Linux(centos)生产环境(二):docker部署

    运行环境 照例,先亮环境:软件的话我这里假设你已经批准好了.net core 运行环境,未配置可以看我的这篇[linux(centos)搭建.net core 运行环境] 腾讯云 centos:7.2 ...