목차
回复内容:
백엔드 개발 PHP 튜토리얼 如果缓存失效,瞬间大量请求可能会直接访问数据库,请问如何在代码层面应该怎么处理?

如果缓存失效,瞬间大量请求可能会直接访问数据库,请问如何在代码层面应该怎么处理?

Jun 06, 2016 pm 04:43 PM
cache data database return write

最近有人问我这个问题,我个人没有这方面的实战经验。我个人的想法是,由于访问数据库并写入缓存需要一定的时间。可能导致较早的部分请求直接读取数据库,当这部分数据要写入缓存时,判断缓存是否存在,不存在则写入,存在则不写入,并返回结果。
if ($cache) {
return $cache;
} else {
$data = read database;
if (!$cache) write $cache $data;
return $data;
}

但思前想后,觉得这样的回答似乎没有正确回答多个请求同时读取数据库的问题,虽然可以屏蔽后期的请求直接访问数据库,但前期还是有多了链接直接访问了数据库。不知道各位是否有更好的解决方案。求教!

回复内容:

答案都在问题里了。

「如果缓存失效」

在设计的时候就可以把 cache 设计成持久化的,避免因为失效导致缓存被穿透。如果对稳定性有更高的要求,就在 cache 上下功夫做灾备。比如 redis 的主从模式,rdb dump 等等。

如果系统或者涉及 cache 的 feature 是第一次上线,则需要提前对缓存做预热。方法有很多,写脚本或者灰度发布的方式都可以。


「瞬间大量的请求会访问数据库」

这里有两个问题,一是瞬间大量的请求怎么处理,二是如何避免这么多请求对数据库造成压力。

具体如何实施还得看业务场景,但解决的思路就是尽可能避免瞬间大量的请求,再就是大量请求产生时不要让数据库压力过大。

限流的方法要看业务场景,并非所有场景都适合限流所以这里不多说。所以这里要限制的是后端到数据库的最大连接数自己数据库自己能接受的最大连接数。只要请求数据库设计合理,即使有瞬间很高的并发一般也不会造成什么实际的问题。

所以怎么从代码层面解决这个问题,是取决于你是如何设计这个系统的。 二级缓存。把数据放在一个失效时间比较长的key里。雪崩的时候加锁,保证只有一个php进程访问数据库,其余的看到锁就不再访问,直接返回在缓存里的数据。效果就是虽然好几个人没看到最新的数据,再刷一下就成了。抢到锁的看到了最新数据。锁可以用mc的add来实现。在我大渣浪的时候这套东西扛过nba的直播,c好几十k,数据库没事,带宽才是问题 facebook 放过一篇论文《Scaling Memcache at Facebook》有讨论过这个问题:

3.2.1 Leases
We introduce a new mechanism we call leases to address two problems: stale sets and thundering herds.

其中 "thundering herds" 正是楼主提到的数据库穿透问题,一个热的缓存如果失效,在第一个访问数据库的请求得到结果写入缓存之前,期间的大量请求打穿到数据库;然后 “stale set” 属于数据一致性问题,假如一个实例更新了数据想去刷新缓存,而另一个实例读 miss 尝试读取数据库,这时两次缓存写入顺序不能保证,可能会导致过期数据写入缓存。

这两个问题都是 look-aside cache 所固有的,需要提供一个机制来协调缓存的写入,这篇论文给出的方案就是 lease 机制,限制同一时刻一个键只有拥有唯一 lease 的客户端才能有权写入缓存:
  • 如果 get 某键读 miss,返回客户端一个 64 位的 lease;
  • 然后该键在写入之前如果收到 get 请求,将返回一个 hot miss 报错,客户端依据它判断自己要稍后重试,而不向数据库读取数据;
  • 如果该键收到 delete 请求,那么会使 lease 失效;持有失效 lease 的 set 请求仍将成功,但后来的 get 请求将得到 hot miss 报错,并携带一个新的 lease;这里的 hot miss 报错中带有最后的值,但认为它处于 stale 状态,留给客户端去判断是否采用它,在一致性要求不严格的场景中可以进一步减少数据库请求;

这一来允许 memcache 服务端协调数据库的访问,从而解决这两个问题。

不过 lease 方案并不完美,因为 1. 需要改 memcache;2. 仍泄露逻辑到客户端,要求客户端遵循 lease 和 hot miss 的约定。

在 facebook 后面的论文《TAO: Facebook's Distributed Data Store for the Social Graph》中介绍TAO 系统尝试解决的问题之一提到:

Distributed control logic: In a lookaside cache architecture the control logic is run on clients that don’t communicate with each other. This increases the number of failure modes, and makes it difficult to avoid thundering herds. Nishtala et al. provide an in-depth discussion of the problems and present leases, a general solution [21]. For objects and associations the fixed API allows us to move the control logic into the cache itself, where the problem can be solved more efficiently.

也就是说,我们并不一定非 look aside cache 不可,如果把缓存的修改入口封装起来,走 write though cache,就不需要分布式地去协调所有客户端,在一个地方排队就够了。

References
  • Scaling Memcache at Facebook
  • TAO: Facebook's Distributed Data Store for the Social Graph
  • quora.com/How-does-the-
根据实际场景选择方案,访问数据库的请求处理使用队列并对同样的请求做加锁处理是比较稳妥的解决思路。
这种问题业内有个名词,叫雪崩效应,就是说集群在正常负载的时候没有问题,一旦其中几台服务器崩了,服务器过载的压力压到后端数据库上面,就会导致整个集群像雪崩一样完全崩溃。
读多写少的业务场景下
对于这种问题,缓存挡在数据库服务器前面是必须的,即问题的解决方案之一,根据sql查询的条件在缓存服务器层面做锁处理,同样的请求只放一个到后端数据库上面,其它请求则阻塞等待数据更新。
其次是挡住这些缓存大批失效导致的峰值,不允许直接连接数据库进行查询,在缓存服务器向数据库发起的请求处理上全部都要使用队列,把峰值分摊到更长的时间段上避免后端数据库受到冲击。
此外为了避免大批缓存失效又重新生成的这些缓存再次同时失效的问题,缓存服务器的数据缓存时间需要去一个时间令牌分发的服务器申请令牌,在基本缓存时间的基础上,再加上一个令牌缓存时间,将峰值分摊到更长的时间上。
这样的处理可以避免数据库负载被峰值请求冲垮。
写入比例更大的业务场景下:
对数据更新频繁且实时性要求较高的时候,比如直播室场景,抢购场景,缓存失效时间很短。需要考虑业务切分,把同类业务路由到不同服务器上面,独立开来。尽可能把写入负载分摊到单点集群可以承担的程度。技术上面可选的策略就和业务相关度很大了,类似直播室的场景,甚至不需要走到数据库服务器,业务都在缓存上面周转,持久化到数据库的业务则走异步扔队列里面慢慢处理。电商抢购这类必须要校验的业务又不一样,但是思路还是同样的,秒杀业务瞬时进来的业务太大,那就加验证码加排队,总之尽可能拖延提交订单的时间,把瞬时负载分摊到系统可以接受的时间段内,数据库层面依然还是加锁与队列,不过在队列入队上还需要做个锁,一旦排队长度超过商品总数的一个倍数(具体按需求过往订单支付成功率计算),则加锁将后续请求挡住不再入队。
还有很多写入业务量非常极端的场景,类似LBS产品的地理位置更新,SNS产品的消息推送,大致思路都是类似的,加锁和队列,数据库层面尽可能选用写入性能优良的nosql承担这些持久化的需求。否则也尽可能减少索引的使用,比如把mysql当key-value数据库用等形式,尽可能减少写入的性能消耗提高。 在DB的监控或者接口层面处理 高并发其实是区分宏观和微观的,你理解的并发是同一时刻多个请求读数据库,但是其实请求对于计算机一定不是同一时刻,只是宏观上是同时。比如1-10毫秒之间或者微秒之间,那么其实计算机是怎么处理的呢?说白了是会对计算操作,io操作做独立的进程来分配处理器的任务,内存的分配,比如同一时刻你在读数据库,同一时刻又有别的io操作,那么你这里也可以再模拟一下计算机这种设计。

比如你在写缓存时,把这个写操作推到一个独立的进程,做一个写缓存的队列,然后再做一个检测进程来组织这个队列的处理顺序和失败分支,比如提前和后排,比如写缓存操作失败了,那么进行队列的下一个任务或者再试一次。所有写入成功的缓存数据再推入缓存池,那么这个队列会保留更新缓存的所有任务,也不会阻塞主进程,也就是用户访问的主进程不会被阻塞。他们只是去读缓存池的数据,不关心时效。如果写得慢就读老的,甚至数据库挂了,都不会影响用户读数据。

并发的概念再仔细想想都是在一个相对的时间里来看待的。计算机会自己处理,你也不用太操心,业务代码只需要解决阻塞的问题就ok了。

ps:我是个前端,大过年无聊瞎扯的…折叠吧。

再补充一下,如果缓存失效了,这个问题要解决的是缓存的容灾处理办法,比如多个缓存池快速切换,负载均衡等。超大量请求直接访问数据库,这个可以用多机多数据库,多个进程来读,来解决。我觉得从代码层面不太好做…

因为解决办法是扩容加分配请求到多机,不能实时扩容又想支持高并发大量请求是不可能的啊…光让驴跑不给吃草,就想着怎么给驴美容不好用啊…

-------

专业上这种雪崩后缓存穿透直接到了db层,实际先挂的是带宽,db不会是瓶颈,之后要解决可以使用最大连接数来控制读数据库,超过的使用2级缓存来做,之后预警,或者动态扩容机制来解决。(咨询的后端同事) throttle 解决之道就在书上, 在(书名忘记了,封面上有动车的那个)那个小书上开始就是介绍的这个问题,然后提出了好几种的解决方案。。 三本书,操作系统,数据库原理,分布式系统。很古老的问题。
1、假设单机缓冲。锁机制就可以了,因为你的问题是读数据,不是别的。无论是多进程还是多线程,加锁就可以了。
2、用缓冲池,降低等待的延迟。
3、以上是操作系统的内容。
4、如果同时有更新操作,要考虑数据一致性的问题,即悲观锁或乐观锁。 1、服务本身要提供过载保护、熔断机制,说到底就是限流,要懂得保护自己
2、缓存重建的时候要加锁,cache mutex
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.

핫 AI 도구

Undresser.AI Undress

Undresser.AI Undress

사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover

AI Clothes Remover

사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool

Undress AI Tool

무료로 이미지를 벗다

Clothoff.io

Clothoff.io

AI 옷 제거제

AI Hentai Generator

AI Hentai Generator

AI Hentai를 무료로 생성하십시오.

인기 기사

R.E.P.O. 에너지 결정과 그들이하는 일 (노란색 크리스탈)
2 몇 주 전 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. 최고의 그래픽 설정
2 몇 주 전 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. 아무도들을 수없는 경우 오디오를 수정하는 방법
2 몇 주 전 By 尊渡假赌尊渡假赌尊渡假赌

뜨거운 도구

메모장++7.3.1

메모장++7.3.1

사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전

SublimeText3 중국어 버전

중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기

스튜디오 13.0.1 보내기

강력한 PHP 통합 개발 환경

드림위버 CS6

드림위버 CS6

시각적 웹 개발 도구

SublimeText3 Mac 버전

SublimeText3 Mac 버전

신 수준의 코드 편집 소프트웨어(SublimeText3)

discuz 데이터베이스 오류를 해결하는 방법 discuz 데이터베이스 오류를 해결하는 방법 Nov 20, 2023 am 10:10 AM

discuz 데이터베이스 오류에 대한 해결 방법은 다음과 같습니다. 1. 데이터베이스 구성을 확인합니다. 2. 데이터베이스 서버가 실행 중인지 확인합니다. 4. 데이터를 백업합니다. 6. Discuz를 다시 설치합니다. 7. 서버 리소스를 확인하세요. 8. Discuz 공식 지원팀에 문의하세요. Discuz 데이터베이스 오류를 해결하려면 여러 측면에서 시작하여 점차적으로 문제의 원인을 식별하고 이에 상응하는 조치를 취하여 복구해야 합니다.

누출로 Intel Arrow Lake-U, -H, -HX 및 -S의 주요 사양 공개 누출로 Intel Arrow Lake-U, -H, -HX 및 -S의 주요 사양 공개 Jun 15, 2024 pm 09:49 PM

Intel Arrow Lake는 Lunar Lake와 동일한 프로세서 아키텍처를 기반으로 할 것으로 예상됩니다. 즉, Intel의 새로운 LionCove 성능 코어가 경제적인 Skymont 효율성 코어와 결합될 것입니다. Lunar Lake는 Ava에서만 사용할 수 있습니다.

C 언어의 return 사용법에 대한 자세한 설명 C 언어의 return 사용법에 대한 자세한 설명 Oct 07, 2023 am 10:58 AM

C 언어에서 return의 사용법은 다음과 같습니다. 1. 반환 값 유형이 void인 함수의 경우 return 문을 사용하여 함수 실행을 조기에 종료할 수 있습니다. 2. 반환 값 유형이 void가 아닌 함수의 경우 return 문은 함수 실행을 종료하는 것입니다. 결과는 호출자에게 반환됩니다. 3. 함수 실행을 조기에 종료합니다. 함수 내부에서는 return 문을 사용하여 함수 실행을 조기에 종료할 수 있습니다. 함수가 값을 반환하지 않는 경우.

입사하고 나서 Cache가 뭔지 이해하게 됐어요 입사하고 나서 Cache가 뭔지 이해하게 됐어요 Jul 31, 2023 pm 04:03 PM

실제로는 이렇습니다. 당시 리더가 perf 하드웨어 성능 모니터링 작업을 지시했습니다. perf를 사용하는 동안 perf list 명령을 입력했는데 다음 정보가 표시되었습니다. 내 작업은 이러한 캐시 이벤트를 활성화하는 것입니다. 하지만 요점은 이러한 누락과 로드가 무엇을 의미하는지 전혀 모른다는 것입니다.

Java에서 return 및 finally 문의 실행 순서는 무엇입니까? Java에서 return 및 finally 문의 실행 순서는 무엇입니까? Apr 25, 2023 pm 07:55 PM

소스 코드: publicclassReturnFinallyDemo{publicstaticvoidmain(String[]args){System.out.println(case1());}publicstaticintcase1(){intx;try{x=1;returnx;}finally{x=3;}}}# 출력 위 코드의 출력은 간단히 결론을 내릴 수 있습니다. return은 finally 전에 실행됩니다. 바이트코드 수준에서 무슨 일이 일어나는지 살펴보겠습니다. 다음은 case1 메소드의 바이트코드 일부를 가로채서 소스 코드를 비교하여 각 명령어의 의미를 주석으로 표시합니다.

캐시를 사용하면 컴퓨터 속도가 빨라지는 이유는 무엇입니까? 캐시를 사용하면 컴퓨터 속도가 빨라지는 이유는 무엇입니까? Dec 09, 2020 am 11:28 AM

캐시를 사용하면 CPU의 대기 시간이 단축되므로 컴퓨터 속도가 향상될 수 있습니다. 캐시는 CPU와 메인 메모리 DRAM 사이에 위치한 작지만 고속의 메모리입니다. 캐시의 기능은 CPU 데이터 입출력 속도를 높이는 것입니다. 캐시는 용량은 작지만 속도가 빠르며, 메모리 속도는 낮지만 용량이 큽니다. 시스템 성능은 향상됩니다. 크게 개선되었습니다.

캐시란 무엇입니까? 캐시란 무엇입니까? Nov 25, 2022 am 11:48 AM

캐시(Cache)는 캐시 메모리(Cache Memory)라고 하며 중앙처리장치와 메인 메모리 사이에 있는 고속 소용량 메모리로 일반적으로 고속 SRAM으로 구성된다. CPU와 메모리 사이의 속도 차이가 시스템 성능에 미치는 영향을 줄이거 나 제거합니다. 캐시 용량은 작지만 빠르며, 메모리 속도는 낮지만 용량이 큽니다. 스케줄링 알고리즘을 최적화하면 시스템 성능이 크게 향상됩니다.

데이터베이스를 삭제할 수 없습니다. 데이터베이스가 존재하지 않습니다. - MySQL 오류 해결 방법: 데이터베이스를 삭제할 수 없습니다. 데이터베이스가 존재하지 않습니다. 데이터베이스를 삭제할 수 없습니다. 데이터베이스가 존재하지 않습니다. - MySQL 오류 해결 방법: 데이터베이스를 삭제할 수 없습니다. 데이터베이스가 존재하지 않습니다. Oct 05, 2023 am 11:46 AM

MySQL 오류 해결 방법: 데이터베이스를 삭제할 수 없습니다. 데이터베이스가 존재하지 않습니다. 개요: MySQL은 일반적으로 사용되는 관계형 데이터베이스 관리 시스템입니다. MySQL을 사용할 때 데이터베이스 생성, 데이터베이스 삭제 및 기타 작업을 포함하여 데이터베이스를 관리해야 하는 경우가 많습니다. 그러나 데이터베이스를 삭제할 때 "Can'tdropdatabase'database_name';databasedoesn'texist"라는 오류 메시지가 나타나는 경우가 있습니다. 즉, 데이터베이스를 삭제할 수 없습니다.

See all articles