Redis와 MySQL의 이중 쓰기 캐시가 일치하지 않으면 어떻게 해야 합니까? 솔루션 공유

青灯夜游
풀어 주다: 2022-03-15 11:20:18
앞으로
2353명이 탐색했습니다.

Redis와 MySQL의 이중 쓰기 캐시가 일치하지 않으면 어떻게 해야 하나요? 이 기사에서는 캐시 이중 쓰기 불일치 문제를 해결하는 방법을 공유하겠습니다. 도움이 되기를 바랍니다.

Redis와 MySQL의 이중 쓰기 캐시가 일치하지 않으면 어떻게 해야 합니까? 솔루션 공유

redis와 mysql 이중 쓰기 캐시는 일관성이 없습니다.

Redis와 MySQL의 이중 쓰기 캐시가 일치하지 않으면 어떻게 해야 합니까? 솔루션 공유

그러나 캐시 업데이트 측면에서 현재 이러한 솔루션을 분석하는 포괄적인 블로그는 없습니다. 그래서 그 블로거는 모든 사람들로부터 비난을 받을 각오를 하고 떨면서 이 글을 썼습니다. 更新完数据库,是更新缓存呢,还是删除缓存。又或者是先删除缓存,再更新数据库,其实大家存在很大的争议。

Text

캐시된 데이터의 만료 시간 설정

먼저 설명하겠습니다. 이론적으로 캐시의 만료 시간을 설정하는 것은 최종 일관성을 보장하는 솔루션입니다. 이 솔루션에서는 캐시에 저장된 데이터의 만료 시간을 설정할 수 있습니다. 모든 쓰기 작업은 데이터베이스에 따라 달라지며 캐시 작업에만 최선을 다하면 됩니다. 즉, 데이터베이스 쓰기가 성공하고 캐시 업데이트가 실패하면 만료 시간에 도달하는 한 후속 읽기 요청은 자연스럽게 데이터베이스에서 새 값을 읽고 캐시를 다시 채웁니다. 따라서 다음에 논의되는 아이디어는 캐시의 만료 시간을 설정하는 솔루션에 의존하지 않습니다.

여기에서는 먼저 세 가지

업데이트 전략에 대해 논의합니다.

    데이터베이스를 먼저 업데이트한 다음 캐시를 업데이트합니다.
  1. 캐시를 먼저 삭제한 다음 데이터베이스를 업데이트합니다.
  2. 데이터베이스를 먼저 업데이트한 다음 캐시를 삭제합니다.
데이터베이스를 먼저 업데이트한 다음 캐시를 업데이트하세요

이 계획은 일반적으로 모두가 반대합니다. 왜? 다음 두 가지 사항이 있습니다.

    첫 번째 이유(스레드 안전 관점)
(1) 스레드 A가 데이터베이스를 업데이트했습니다.

(2) 스레드 B가 데이터베이스를 업데이트했습니다.
(3) 스레드 B가 캐시를 업데이트했습니다.
(4) 스레드 A 캐시 업데이트

즉, A에게 캐시 업데이트를 요청하는 것이 B에게 캐시 업데이트를 요청하는 것보다 빨라야 한다는 의미입니다. 그러나 네트워크 및 기타 이유로 인해 B는 A보다 먼저 캐시를 업데이트했습니다. 이로 인해 더티 데이터가 생성되므로 고려되지 않습니다.

    이유 2(비즈니스 시나리오 관점)
(1) 데이터베이스 쓰기 시나리오가 많고 데이터 읽기 시나리오가 적은 비즈니스 요구가 있는 경우 이 솔루션을 채택하면 데이터가 전혀 읽히지 않게 됩니다. 자주 업데이트되어 성능이 낭비됩니다.

(2) 데이터베이스에 쓰는 값이 캐시에 직접 기록되지 않는 경우 일련의 복잡한 계산을 거친 후 캐시에 기록되어야 합니다. 그러면 데이터베이스에 기록될 때마다 캐시에 기록된 값을 다시 계산하는 것은 의심할 여지 없이 성능 낭비입니다. 분명히 캐시를 삭제하는 것이 더 적절합니다.

캐시를 먼저 삭제한 후 데이터베이스를 업데이트하세요

이 솔루션이 불일치를 일으키는 이유는 다음과 같습니다. 동시에 하나는 A에게 업데이트 작업을 수행하도록 요청하고 다른 하나는 B에게 쿼리 작업을 수행하도록 요청합니다. 그러면 다음과 같은 상황이 발생합니다.

(1) A에게 쓰기 작업을 수행하고 캐시를 삭제하도록 요청

(2) B에게 쿼리하여 캐시가 존재하지 않음을 확인하도록 요청
(3) B에게 데이터베이스에 쿼리하도록 요청 이전 값 가져오기
(4) B에게 이전 값 검색 요청 값이 캐시에 기록됨
(5) A에게 새 값을 데이터베이스에 기록하도록 요청

위 상황은 불일치로 이어질 수 있습니다. 또한 캐시에 대한 만료 시간 전략을 설정하지 않으면 데이터는 항상 더티 데이터가 됩니다.

그럼 어떻게 해결하나요? 지연 이중 삭제 전략 채택

캐시 지연 이중 삭제
public class CacheServiceImpl implements ICacheService {

    @Resource
    private RedisOperator redisOperator;
    
    @Autowired
    private IShopService shopService;

    //1. 采用延时双删,解决数据库和缓存的一致性
    @Override
    public void updateHotCount(String id) {
        try {
            //删除缓存
            redisOperator.del("redis_key_" + id);
            //更新数据库
            shopService.updataHotShop();
            Thread.sleep(1000);//休眠1秒
            //延时删除
            redisOperator.del("redis_key_" + id);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }


    }

    @Override
    public Integer getHotCount(String id) {
        return null;
    }}
로그인 후 복사

설명:

    캐시를 먼저 제거한 다음
  1. 데이터베이스에 기록합니다
  2. 1초 동안 잠자기한 후 캐시를 제거합니다(
  3. 이런 식으로 , 캐시로 인해 캐시된 더티 데이터가 다시 삭제됩니다. )

위 상황을 고려하여 독자는 자신의 프로젝트에서 시간이 많이 걸리는 데이터 읽기 비즈니스 로직을 평가해야 합니다. 그런 다음 데이터 쓰기를 위한 대기 시간은 데이터 읽기에 소요되는 비즈니스 로직의 시간에 수백 밀리초를 더한 값을 기준으로 합니다. 이는 읽기 요청이 종료되고 쓰기 요청이 읽기 요청으로 인해 캐시된 더티 데이터를 삭제할 수 있도록 하는 것입니다.

데이터베이스가 읽기-쓰기 분리 아키텍처를 채택하면 어떻게 될까요? (메인 라이브러리는 쓰기 작업을 담당하고, 슬레이브 라이브러리는 읽기 작업을 담당합니다)

알겠습니다. 이 경우 데이터 불일치 이유는 다음과 같습니다. 하나는 A를 요청합니다. 업데이트 작업을 수행하고 다른 하나는 업데이트 작업을 수행하도록 B에게 요청합니다.

(1) A에게 쓰기 작업 수행을 요청하고, 캐시를 삭제하고, A에게 기본 라이브러리에 데이터를 쓰도록 요청하고, 아직 슬레이브 라이브러리 동기화를 시작하지 않았습니다.

(2) (1초 이내) B에게 쿼리를 요청합니다. 캐시를 찾았지만 캐시를 찾을 수 없는 경우 B에게 이동을 요청합니다. 데이터베이스에서 쿼리할 때 마스터-슬레이브 동기화가 아직 완료되지 않았으며 이전 값을 찾았으며 이전 값이 캐시에 기록됩니다.

(3) 마스터 데이터베이스는 마스터-슬레이브 동기화를 완료하고 슬레이브 데이터베이스는 새로운 값으로 변경됩니다

위 프로세스는 데이터 불일치 문제이며 이중 삭제 지연 전략도 사용됩니다. 그런데 슬립 시간은 마스터-슬레이브 동기화 지연 시간에 수백 ms를 더한 값으로 수정됩니다

이 동기화 제거 전략을 채택하면 처리량이 줄어들면 어떻게 해야 할까요?

좋아요, 그러면 두 번째 삭제를 비동기식으로 만드세요. 스레드를 직접 시작하고 비동기적으로 삭제하세요. 이런 방식으로 서면 요청은 반환되기 전에 일정 시간 동안 잠을 자지 않아도 됩니다. 이렇게 하면 처리량이 늘어납니다.

두 번째 삭제인데, 삭제에 실패하면 어떻게 해야 하나요?

두 번째 삭제에 실패하면 다음과 같은 상황이 발생하기 때문에 매우 좋은 질문입니다. 여전히 두 개의 요청이 있는데, 하나는 A에게 업데이트 작업을 수행하도록 요청하고 다른 하나는 B에게 쿼리 작업을 수행하도록 요청합니다.

(1) A에게 쓰기 작업을 수행하도록 요청합니다. 그리고 캐시를 삭제합니다.
(2) B에게 쿼리하여 캐시가 존재하지 않음을 발견하도록 요청합니다.
(3) B에게 이전 값을 가져오기 위해 데이터베이스를 쿼리하도록 요청합니다.
(4) B에게 이전 값을 캐시에 쓰도록 요청합니다.
( 5) A에게 새 값을 데이터베이스에 쓰도록 요청합니다.
(6) 요청 A가 요청 B를 삭제하려고 시도합니다. 캐시된 값에 쓰는 데 실패했습니다.

그렇습니다. 두 번째 캐시 삭제에 실패하면 캐시와 데이터베이스 불일치가 다시 발생합니다.

어떻게 해결하나요?

구체적인 해결 방법은 먼저 데이터베이스를 업데이트한 후 캐시를 삭제하는 업데이트 전략에 대한 블로거의 분석을 살펴보겠습니다.

캐시 삭제 재시도 메커니즘

지연 이중 삭제이든, 데이터베이스를 먼저 운영한 후 캐시를 삭제하는 Cache-Aside이든, 캐시 삭제 실패로 인해 데이터 불일치 문제가 발생할 수 있습니다. 두 번째 단계 . 이 솔루션을 사용하여 최적화할 수 있습니다. 삭제에 실패하면 몇 번 더 삭제하여 캐시 삭제가 성공했는지 확인하세요~ 그러면 삭제 캐시 재시도 메커니즘

Redis와 MySQL의 이중 쓰기 캐시가 일치하지 않으면 어떻게 해야 합니까? 솔루션 공유

  1. 을 도입할 수 있습니다. (1) 데이터베이스 업데이트
    (2) 다양한 문제로 인해 캐시 삭제에 실패했습니다.
    (3) 삭제해야 할 키를 메시지 대기열로 보냅니다.
    (4) 메시지를 직접 소비하고 삭제해야 할 키를 얻습니다.
    (5) 성공할 때까지 삭제 작업을 계속 재시도합니다.

하지만 이 솔루션은 업무 코드에 많은 침입을 유발한다는 단점이 있습니다. 따라서 두 번째 옵션이 있습니다. 두 번째 옵션에서는 구독 프로그램을 시작하여 데이터베이스의 binlog를 구독하여 작동해야 하는 데이터를 얻습니다. 애플리케이션에서 새 프로그램을 시작하여 이 구독 프로그램에서 정보를 얻고 캐시를 삭제합니다.

biglog를 비동기적으로 읽고 캐시를 삭제합니다

Redis와 MySQL의 이중 쓰기 캐시가 일치하지 않으면 어떻게 해야 합니까? 솔루션 공유

프로세스는 아래 그림과 같습니다.

(1) 데이터베이스 데이터 업데이트
(2) 데이터베이스는 binlog 로그에 작업 정보를 기록합니다
( 3) 구독자 추출 필수 데이터 및 키 꺼내기
(4) 정보를 얻기 위해 새로운 비업무용 코드 조각을 시작합니다
(5) 캐시 작업을 삭제하고 삭제에 실패했는지 확인
(6) 정보 보내기 to the message queue
(7) 메시지를 다시 수신하여 큐의 데이터를 얻고 작업을 다시 시도합니다.

Remarks: 위의 binlog 구독 프로그램에는 mysql에 canal이라는 미리 만들어진 미들웨어가 있으며, 이는 binlog 로그 구독 기능을 완료할 수 있습니다. Oracle의 경우 블로거는 현재 사용할 수 있는 기성 미들웨어가 있는지 알지 못합니다. 또한 재시도 메커니즘의 경우 블로거는 메시지 대기열을 사용합니다. 일관성 요구 사항이 그다지 높지 않은 경우 프로그램에서 새 스레드를 시작하고 가끔씩 다시 시도하면 됩니다. 이를 유연하게 사용할 수 있지만 저는 단지 아이디어를 제공할 뿐입니다.

이 글은 실제로 인터넷에 존재하는 일관성 솔루션을 요약한 것입니다. 먼저 캐시를 삭제한 후 데이터베이스를 업데이트하는 업데이트 전략에 대해서는 메모리 큐를 유지할 계획도 있습니다. 블로거가 이를 살펴보고 구현이 매우 복잡하고 불필요하다고 느꼈으므로 이를 제공할 필요가 없습니다. 기사에서. 마지막으로, 여러분 모두가 뭔가를 얻었기를 바랍니다.

【관련 추천: mysql 비디오 튜토리얼

위 내용은 Redis와 MySQL의 이중 쓰기 캐시가 일치하지 않으면 어떻게 해야 합니까? 솔루션 공유의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

관련 라벨:
원천:jianshu.com
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿
회사 소개 부인 성명 Sitemap
PHP 중국어 웹사이트:공공복지 온라인 PHP 교육,PHP 학습자의 빠른 성장을 도와주세요!