당신은 정말 "캐시"를 이해하고 있는가

I. 서론

매우 느리게 그래서 원래의 페이지가 될 수 있음을 열 수 있습니다 캐싱 "여 초." APP는 일반적으로 거의 모든 사이트를 방문 캐시의 사용을 포함한다.

따라서, 캐시 이외에 어떤 영향을뿐만 아니라, 데이터 액세스 속도를 높일 수 있습니다?

또한, 모든 단점을 피하면서 우리가 캐싱의 장점을 최대한 활용 할 수있는 방법을 두 가지 측면이있다?

이 문서는 캐시뿐만 아니라 아이디어의 사용을 이해하는 방법을 당신과 함께 공유를 제공합니다 우리는 영감을 바랍니다.

둘째, 캐시는 무엇을 할 수 있습니까?

앞서 언급 한 바와 같이, 우리는 가장 일반적인 이해는 우리가 페이지를 방문 할 때 매우 느린 시간을 여는 것입니다있는 캐시의 도입을 생각, 페이지가 너무 빨리 열립니다. 사실, 느린 빠르고 대신 디스크의 사용 메모리 읽기 및 쓰기 위하여, 캐시 메모리 기반을 구축하는 것입니다 빠른 때문에 캐시, 메모리 읽기 및 쓰기가 많은 배 빠른 하드 디스크보다 속도 기술적 인 관점에서, 상대적입니다 자연 미디어는 크게 데이터에 대한 액세스 속도를 향상시킬 수 있습니다.

이 프로세스는 후속 액세스에 대한 데이터 속도의 효과를 달성하기 위해 사용 된 메모리 저장 부에 접속 한 때 일반적이다.

미리 읽기 및 지연 서면 : 사실,뿐만 아니라, 두 개의 다른 중요한 캐시 사용 방법이 있습니다.

셋째, 미리 읽기

프리 페치는 프리로드 데이터를 읽어야하는, 메모리에로드되어 하드 드라이브의 제 1 부분 인 시스템 "미리 저장된"이라하고 서비스를 제공 할 수있다.

우리는 왜 그것을해야합니까? 일부 시스템은 이러한 요청이 데이터베이스에 직접 충돌하는 경우 요청 수만은 올 직면 할 것 때문에 시작되면 데이터베이스가 정상에 응답 할 수없는 매우 큰 압력 서지, 바로 아래에 포켓 일 수있다.

이 문제를 완화하기 위해, 우리는 해결하기 위해 "미리 읽기"를해야합니다.

어쩌면 당신도 캐시, 재생됩니다하거나 수행하지 수 있을까? 즉,로드 밸런싱 규모와 시간을하는 것입니다,이 문서에 나와 있지 않은 내용은, 공유 할 수있는 특별한 기회가있다.

"데이터 내보내기"의 "사전 판독"전방 버퍼를 첨가하면, "데이터 항목"후방 버퍼를 첨가 한 후 다음 "지연된 기록"은 말한다.

넷째, 쓰기 지연

당신은 아마 알다시피 데이터를 보장하는 메커니즘의 일련의 정확도가 기록 될 때 때문에, 데이터베이스 쓰기 속도는 속도를 읽는 것보다 느립니다. 당신이 속도를 기록 향상시키고 자한다면, 다음 중 하위 라이브러리 서브 테이블을, 또는 버퍼 캐시, 속도를 높이기 위해 디스크에 기록 후 한 시간 배치를 통해 수행된다.

교차 테이블 운전 조건 조합 문의 및 많은 부작용에 대한 세부 라이브러리 하위 테이블 큰, 복잡성의 도입 캐시의 도입보다 큰, 그래서 때문에, 우리는 캐싱 방식을 도입에 우선 순위를 부여해야한다.

那么,通过缓存机制来加速“写”的过程就可以称作“延迟写”,它是预先将需要写入磁盘或数据库的数据,暂时写入到内存,然后返回成功,再定时将内存中的数据批量写入到磁盘。

可能你会想,写到内存就认为成功,万一中途出现意外、断电、停机等导致程序异常终止的情况,数据不就丢失了吗?

是的,所以“延迟写”一般仅用于对数据完整性要求不是那么苛刻的场景,比如点赞数、参与用户数等等,可以大大缓解对数据库频繁修改所带来的压力。

其实在我们熟知的分布式缓存Redis中,其默认运用的持久化机制---RDB,也是这样的思路。

在一个成熟的系统中,能够运用到缓存的地方其实并不是一处。下面就来梳理一下我们在那些地方可以加“缓存”。

五、哪里可以加缓存?

在说哪里可以加缓存之前我们先搞清楚一个事情,我们要缓存什么?也就是符合什么特点的数据才需要加缓存?毕竟加缓存是一个额外的成本投入,得物有所值。

一般来说你可以用两个标准来衡量:

热点数据:被高频访问,如几十次/秒以上。

静态数据:很少变化,读大于写。

接下来就可以替他们找到合适的地方加缓存了。

缓存的本质是一个“防御性”的机制,而系统之间的数据流转是一个有序的过程,所以,选择在哪里加缓存就相当于选择在一条马路的哪个位置设路障。在这个路障之后的道路都能受到保护,不被车流碾压。

那么在以终端用户为起点,系统所用的数据库为终点的这条道路上可以作为缓存设立点的位置大致有以下这些:

每个设立点可以挡掉一些流量,最终形成一个漏斗状的拦截效果,以此保护最后面的系统以及最终的数据库。

下面简要描述一下每个运用场景以及需要注意的点。

六、缓存类别

1、浏览器缓存

这是离用户最近的可以作为缓存的地方,而且借助的是用户的“资源”(缓存的数据在用户的终端设备上),性价比可谓最好,让用户帮你分担压力。

当你打开浏览器的开发者工具,看到 from cache 或者 from memory cache、from disk cache 的时候,就意味着这些数据已经被缓存在了用户的终端设备上了,没网的时候也能访问到一部分内容就是这个原因。

这个过程是浏览器替我们完成的,一般用于缓存图片、js 与 css 这些资源,我们可以通过 Http 消息头中的 Cache-Control 来控制它,具体细节这里就不展开了。此外,js 里的全局变量、cookie 等运用也属于该范畴。

浏览器缓存是在用户侧的缓存点,所以我们对它的掌控力比较差,在没有发起新请求的情况下,你无法主动去更新数据。

2、CDN缓存

提供CDN服务的服务商,在全国甚至是全球部署着大量的服务器节点(可以叫做“边缘服务器”)。那么将数据分发到这些遍布各地服务器上作为缓存,让用户访问就近的服务器上的缓存数据,就可以起到压力分摊和加速效果。这在TOC类型的系统上运用,效果格外显著。

但是需要注意的是,由于节点众多,更新缓存数据比较缓慢,一般至少是分钟级别,所以一般仅适用于不经常变动的静态数据。

解决方式也是有的,就是在 url 后面带个自增数或者唯一标示,如 ?v=1001。因为不同的 url 会被视作“新”的数据和文件,被重新 create 出来。

3、网关(代理)缓存

很多时候我们在源站前面加一层网关,为的是做一些安全机制或者作为统一分流策略的入口。

同时这里也是做缓存的一个好场所,毕竟网关是“业务无关”的,它能够拦下来请求,对背后的源站也有很大的受益,减少了大量的CPU运算。

常用的网关缓存有Varnish、Squid与Ngnix。一般情况下,简单的缓存运用场景,用Ngnix即可,因为大部分时候我们会用它做负载均衡,能少引入一个技术就少一分复杂度。如果是大量的小文件可以使用Varnish,而 Squid 则相对大而全,运用成本也更高一些。

3、进程内缓存

可能我们大多数程序员第一次刻意使用缓存的场景就是这个时候。

一个请求能走到这里说明它是“业务相关”的,需要经过业务逻辑的运算。

也正因如此,从这里开始对缓存的引入成本比前面3种大大增加,因为对缓存与数据库之间的“数据一致性”要求更高了。

4、进程外缓存

这个大家也熟悉,就是 Redis 与 Memcached 之类,甚至也可以自己单独写一个程序来专门存放缓存数据,供其它程序远程调用。

这里先多说几句关于 Redis 和 Memcached 该怎么选择的思路。

对资源(CPU、内存等)利用率格外重视的话可以使用Memcached ,但程序在使用的时候需要容忍可能发生的数据丢失,因为纯内存的机制。如果无法容忍这单,并对资源利用率也比较豪放的话就可以使用Redis。而且Redis的数据库结构更多, Memcached 只有 key-value,更像是一个 NoSQL 存储。

5、数据库缓存

数据库本身是自带缓存模块的,否者也不会叫它内存杀手,基本上你给多少内存它就能吃多少内存。数据库缓存是数据库的内部机制,一般都会给出设置缓存空间大小的配置来让你进行干预。

最后,其实磁盘本身也有缓存。所以你会发现,为了让数据能够平稳地写到物理磁盘中真的是一波三折。

七、缓存是银弹吗?

可能你会想缓存那么好,那么应该多多益善,只要慢就上缓存来解决?

一个事物看上去再好,也有它负面的一面,缓存也有一系列的副作用需要考虑。除了前面提到的“缓存更新”和“缓存与数据的一致性”问题,还有诸如下边的这些问题:

1、缓存雪崩

大量的请求并发进入时,由于某些原因未起到预期的缓冲效果,哪怕只是很短的一段时间,导致请求全部转到数据库,造成数据库压力过重。解决它可以通过“加锁排队”或者“缓存时间增加随机值”。

2、缓存穿透

和缓存雪崩类似,区别是这会持续更长的时间,因为每次“cache miss”后依然无法从数据源加载数据到缓存,导致持续产生“cache miss”。解决它可以通过“布隆过滤器”或者“缓存空对象”。

3、缓存并发

一个缓存key下的数据被同时set,怎么保证业务的准确性?再加上数据库的话?进程内缓存、进程外缓存与数据库三者皆用的情况下呢?用一句话来概括建议的方案是:使用“先DB再缓存”的方式,并且缓存操作用delete而不是set。

4、缓存无底洞

虽然分布式缓存是可以无限横向扩展的,但是,集群下的节点真的是越多越好吗?当然不是,缓存也是符合“边际效用递减”规律的。

5、缓存淘汰

内存总是有限的,如果数据量很大,那么根据具体的场景定制合理的淘汰策略是必不可少的, 如 LRU、LFU 与 FIFO 等等。

八、总结

本文介绍了运用缓存的三种思路,然后梳理了在一个完整的系统中可以设立缓存的几个位置,并且分享了关于浏览器、CDN与网关(代理)等缓存的一些实用经验,没有具体展开来讲细节,只是希望我们对缓存有一个更加体系化的认识,希望能让我们变得更加全面。

 

每一篇博客都是一种经历,程序猿生涯的痕迹,知识改变命运,命运要由自己掌控,愿你游历半生,归来仍是少年。

欲速则不达,欲达则欲速!

更多精彩内容,首发公众号【素小暖】,欢迎关注。

发布了121 篇原创文章 · 获赞 12 · 访问量 8217

추천

출처blog.csdn.net/guorui_java/article/details/104557984