Redis와 MySQL 간의 이중 쓰기 일관성은 캐시와 데이터베이스를 사용하여 동시에 데이터를 저장하는 시나리오(주로 동시성이 높은 경우), 데이터 일관성을 보장하는 방법을 의미합니다. 둘 사이(내용은 동일하거나 최대한 가깝습니다) .
정상 비즈니스 프로세스:
읽기는 문제가 아니라 쓰기 작업(업데이트)이 문제입니다. 이때 몇 가지 문제가 발생할 수 있습니다. 먼저 데이터베이스를 업데이트한 다음 캐싱 작업을 수행해야 합니다. 캐시를 다룰 때에는 캐시를 업데이트할 것인지, 캐시를 삭제할 것인지, 아니면 캐시를 먼저 업데이트한 후 데이터베이스를 업데이트할 것인지를 고려해야 합니다. 캐시?
이러한 질문을 계속해 보겠습니다.
먼저 업데이트 캐시와 삭제 캐시의 두 가지 유형이 포함된 작업 캐시에 대해 이야기하겠습니다.
캐시를 업데이트하시겠습니까? 캐시를 삭제하시겠습니까?
데이터베이스를 먼저 업데이트한다고 가정합니다(캐시를 먼저 운영한 다음 데이터베이스를 운영하는 것이 더 문제가 되기 때문에 나중에 논의할 것입니다)
두 개의 요청이 동시에 동일한 데이터를 수정하는 경우 순서가 뒤바뀌어 오래된 데이터가 캐시에 존재할 수 있습니다. 후속 읽기 요청에서는 이전 데이터를 읽고, 캐시가 무효화된 경우에만 데이터베이스에서 올바른 값을 얻을 수 있습니다.
캐시가 실패하면 요청 B는 데이터베이스에서 데이터를 쿼리하고 이전 값을 가져올 수 있습니다. 이때 A는 데이터베이스를 업데이트하고, 데이터베이스에 새로운 값을 쓰고, 캐시를 삭제하라는 요청을 받습니다. 요청 B는 이전 값을 캐시에 기록하여 더티 데이터를 생성합니다
위에서 볼 수 있듯이 더티 데이터에 대한 요구 사항은 캐시 업데이트 요구 사항보다 높습니다.
시간이 데이터베이스 읽기 + 캐시 쓰기 시간
업데이트 시 데이터베이스는 일반적으로 잠겨 있으며 읽기 작업의 속도는 쓰기 작업의 속도보다 훨씬 빠르므로 세 번째 문제가 발생할 확률은 극히 낮습니다(물론 일어날 수도 있습니다)
참고: 저는 실제로 잘 이해가 안가는데, 단순히 발생 확률은 낮은 것 같은데, 네트워크 지연이나 기타 상황이 발생하면 이런 일도 발생하지 않을까요? 좋은 의도를 가진 분이 혼란을 해소해주셨으면 좋겠는데, 어쨌든 이해가 안 되네요.따라서 캐시 삭제를 선택할 때는 성능과 일관성을 최적화하기 위해 다른 기술도 결합해야 합니다. 예:
캐시를 업데이트할 때마다 캐시가 업데이트되지만, 캐시에 있는 데이터는 즉시읽어지지
않을 수 있으며, 이로 인해 자주 액세스하지 않는 많은 데이터가 캐시에 저장됩니다. . , 캐시 리소스 낭비입니다. 그리고 캐시에 기록된 값이 데이터베이스에 있는 값과 일대일로 일치하지 않는 경우가 많으며, 데이터베이스에 먼저 쿼리한 후 일련의 "계산"을 통해 값을 얻을 가능성이 높습니다. 값이 캐시에 기록되기 전에. 이
업데이트 캐시방식은 캐시 활용도가 낮을 뿐만 아니라 시스템 성능 낭비를 초래한다는 것을 알 수 있습니다. 그래서 우리는 일반적으로 캐시 삭제캐시를 먼저 업데이트한 다음 데이터베이스를 업데이트하는 것을 고려합니다
데이터를 업데이트할 때먼저 새 데이터를 캐시(Redis)에 쓴 다음 새 데이터를 데이터베이스에 씁니다( MySQL)하지만 문제가 있습니다.
: 사용자가 자신의 닉네임, 시스템 먼저 새 별명을 캐시에 쓴 다음 데이터베이스를 다시 업데이트합니다. 그러나 데이터베이스를 업데이트하는 과정에서 네트워크 장애나 데이터베이스 다운타임 등의 비정상적인 상황이 발생해 데이터베이스의 닉네임이 수정되지 않는 문제가 발생했다. 이런 방식으로 캐시의 별명은 데이터베이스의 별명과 일치하지 않게 됩니다. 캐시 업데이트는 성공했지만 데이터베이스 업데이트가 지연되어 다른 요청에서 오래된 데이터를 읽게 됩니다 예: 사용자가 제품을 주문하면 시스템이 먼저 주문 상태를 다음 위치에 기록합니다. 캐시를 삭제한 다음 데이터베이스를 업데이트합니다. 그러나 데이터베이스를 업데이트하는 과정에서는 동시성이 크거나 기타 이유로 인해 데이터베이스 쓰기 속도가 캐시 쓰기 속도보다 느려집니다. 이러한 방식으로 다른 요청은 캐시에서 주문 상태를 지불된 것으로 읽지만 데이터베이스에서는 주문 상태를 지불되지 않은 것으로 읽습니다. 캐시 업데이트가 성공했지만 데이터베이스 업데이트 전에 캐시와 데이터베이스를 쿼리하고 이전 데이터를 캐시에 다시 쓰고 새 데이터를 덮어쓰는 다른 요청이 있습니다 예: 사용자 A는 자신의 아바타를 수정하여 서버에 업로드했습니다. 시스템은 먼저 새 아바타 주소를 캐시에 기록하고 이를 사용자 A에게 반환하여 표시합니다. 그런 다음 새 아바타 주소를 데이터베이스로 업데이트합니다. 그런데 이 과정에서 사용자 B가 사용자 A의 개인 홈페이지를 방문하여 캐시에서 새로운 아바타 주소를 읽어 들였습니다. 캐시 무효화는 캐시 만료 정책이나 재시작 작업과 같은 기타 이유로 인해 캐시가 지워지거나 만료될 수 있습니다. 이때, 사용자 B는 다시 사용자 A의 개인 홈페이지를 방문하여 데이터베이스에서 이전 아바타 주소를 읽어와 다시 캐시에 기록합니다. 이로 인해 캐시의 아바타 주소가 데이터베이스의 주소와 일치하지 않을 수 있습니다. 위에서 많이 언급했지만 요약하자면 캐시 업데이트에 성공했지만 데이터베이스가 업데이트되지 않았습니다(업데이트 실패) 결과적으로 캐시에는 최신 값이 저장되고 데이터 인벤토리에는 이전 값이 저장되었습니다. 값. 캐시가 실패하면 데이터베이스의 이전 값을 가져옵니다. 저도 나중에 헷갈렸는데, 데이터베이스 업데이트 실패로 인해 발생한 문제인데, 데이터베이스 업데이트가 성공했다는 것만 확인하면 데이터 불일치 문제를 해결할 수 있을까요? 데이터베이스 업데이트가 완료될 때까지 데이터베이스를 유지합니다. 나중에 알고 보니 제가 너무 순진했고 다음과 같은 문제가 많았습니다. 데이터베이스 업데이트 실패의 원인이 데이터베이스 다운타임이나 네트워크 장애인 경우 데이터베이스 업데이트를 계속해서 재시도하면 문제가 발생할 수 있습니다. 부담이 커지고 지연이 발생하면 데이터베이스 복구가 어려워질 수도 있습니다. 데이터베이스 업데이트 실패의 원인이 데이터 충돌이나 비즈니스 로직 오류인 경우 데이터베이스 업데이트를 지속적으로 재시도하면 데이터 손실이나 데이터 혼란이 발생할 수 있으며 심지어 다른 사용자의 데이터에도 영향을 미칠 수 있습니다. 데이터베이스 업데이트를 위해 계속해서 재시도를 한다면, 재시도의 멱등성과 순서를 어떻게 보장할 것인지, 재시도 과정에서 발생하는 예외를 어떻게 처리할 것인지 고려해야 합니다. 따라서 이 방법은 그다지 좋은 해결책은 아닙니다. 업데이트 작업이 있으면 데이터베이스 데이터를 먼저 업데이트한 다음 해당 캐시 데이터를 업데이트하세요 하지만 이 솔루션에도 다음과 같은 몇 가지 문제와 위험이 있습니다. : 데이터베이스가 성공적으로 업데이트되었지만 캐시 업데이트에 실패하면 이전 데이터는 캐시에 유지되지만 데이터베이스에는 이미 새 데이터, 즉 더티 데이터가 포함되어 있습니다. 데이터베이스 업데이트와 캐시 업데이트 사이에 다른 요청이 동일한 데이터를 쿼리하고 캐시가 존재하는 것으로 확인되면 캐시에서 이전 데이터를 읽습니다. 이로 인해 캐시와 데이터베이스 간에 불일치가 발생하기도 합니다. 따라서 업데이트 캐시 작업을 사용할 때 누가 먼저 오든 후자에서 예외가 발생하면 비즈니스에 영향을 미치게 됩니다. (여전히 위의 그림) 그러면 데이터 일관성을 보장하기 위해 예외를 처리하는 방법 이러한 문제의 원인은 멀티 스레드 동시성으로 인해 발생하므로 가장 간단한 방법은 잠금(분산 잠금)입니다. . 두 스레드가 동일한 데이터를 수정하려면 변경하기 전에 각 스레드가 분산 잠금을 적용해야 합니다. 잠금을 획득한 스레드만 데이터베이스 및 캐시를 업데이트할 수 있으며 잠금을 획득하지 못한 스레드는 실패를 반환합니다. 다음 재시도를 기다리세요. 그 이유는 동시성 문제를 방지하기 위해 운영 데이터와 캐시를 하나의 스레드로만 제한하기 때문입니다. 하지만 잠금은 시간도 많이 걸리고 노동집약적이므로 절대 권장하지 않습니다. 또한 캐시가 업데이트될 때마다 캐시에 있는 데이터를 즉시 읽지 못할 수도 있으며, 이로 인해 자주 액세스하지 않는 많은 데이터가 캐시에 저장되어 캐시 리소스가 낭비될 수 있습니다. 그리고 캐시에 기록된 값이 데이터베이스에 있는 값과 일대일로 일치하지 않는 경우가 많으며, 데이터베이스에 먼저 쿼리한 후 일련의 "계산"을 통해 값을 얻을 가능성이 높습니다. 값이 캐시에 기록되기 전에. 이 데이터베이스 업데이트 + 캐시 업데이트 솔루션은 캐시 활용도가 낮을 뿐만 아니라 시스템 성능 낭비를 초래한다는 것을 알 수 있습니다. 그래서 지금은 다른 해결책을 고려해야 합니다. 캐시 삭제 업데이트 작업이 있으면 해당 캐시 데이터를 먼저 삭제한 후 업데이트하세요. 데이터베이스 데이터 그러나 이 솔루션에는 다음과 같은 몇 가지 문제와 위험도 있습니다. 캐시를 삭제한 후 데이터베이스 업데이트에 실패하면 캐시가 손실되고 다음 쿼리에서 데이터를 다시 로드해야 합니다. 데이터베이스에 대한 부담과 응답 시간이 증가합니다. 캐시 삭제와 데이터베이스 업데이트 사이에 동일한 데이터에 대한 다른 요청이 있고 캐시가 존재하지 않는 것으로 확인되면 데이터베이스에서 이전 데이터를 읽어 캐시에 기록합니다. 이로 인해 캐시와 데이터베이스 간에 불일치가 발생합니다. 업데이트 작업이 있으면 데이터베이스 데이터를 먼저 업데이트하고 캐시를 삭제하세요 실제로 위에서 말씀드렸는데 다시 말씀드리죠 it again 캐시 무효화 요청 B는 데이터베이스에서 데이터를 쿼리하고 이전 값을 가져오도록 요청할 수 있습니다. 이때 A는 데이터베이스를 업데이트하고, 데이터베이스에 새로운 값을 쓰고, 캐시를 삭제하라는 요청을 받습니다. 요청 B는 이전 값을 캐시에 기록하여 더티 데이터를 생성합니다 위에서 볼 수 있듯이 더티 데이터에 대한 요구 사항은 캐시 업데이트 요구 사항보다 높습니다. 캐시 무효화 읽기 요청 + 쓰기 요청 동시성 데이터베이스 업데이트 + 캐시 삭제 시간이 데이터베이스 읽기 + 캐시 쓰기 시간 보다 짧습니다. 처음 두 개는 매우 만족스럽습니다. 세 번째 사항을 살펴보겠습니다. 과연 이런 일이 일어날까요? 업데이트 시 데이터베이스는 일반적으로 잠겨 있으며 읽기 작업은 쓰기 작업보다 훨씬 빠르므로 세 번째 지점이 발생할 확률은 극히 낮습니다. 이중 쓰기 문제의 경우 더 적합한 솔루션은 업데이트하는 것입니다. 물론 특정 상황에서는 특정 분석이 필요하므로 일반화할 수는 없습니다. 이러한 작업 후에 발생할 문제를 설명했는데 이러한 문제를 방지하는 방법은 무엇입니까? 먼저 캐시를 삭제한 다음 데이터베이스를 업데이트한 다음 비동기 스레드 또는 메시지 대기열을 사용하여 캐시를 다시 작성하세요. 먼저 데이터베이스를 업데이트한 후 캐시를 삭제하고 합리적인 만료 시간을 설정하여 캐시의 효율성을 보장하세요. 분산 잠금 또는 낙관적 잠금을 사용하여 동시 액세스를 제어하고 한 번에 하나의 요청만 캐시와 데이터베이스를 작동할 수 있도록 보장합니다. …… 다음은 이중 쓰기 일관성을 보장하는 몇 가지 일반적인 방법입니다. 위에서 언급한 것처럼 2단계가 실패하면 다시 시도해서 최대한 고치려고 노력하지만, 위에서 언급한 것처럼 재시도 비용이 너무 비싸서 실패합니다' 다시 반복하지 마십시오. 재시도 방식은 리소스를 차지하므로 비동기식으로 진행하겠습니다. 캐시를 삭제하거나 업데이트할 때 작업이 실패하면 오류가 즉시 반환되지 않습니다. 대신 일부 메커니즘(예: 메시지 대기열, 예약된 작업, binlog 구독 등)을 통해 캐시 재시도 작업이 트리거됩니다. 이 방법을 사용하면 캐시를 동기적으로 재시도할 때 성능 손실과 차단 문제를 피할 수 있지만 캐시와 데이터베이스 데이터가 일치하지 않는 시간이 길어집니다. 메시지 대기열은 신뢰성을 보장합니다: 대기열에 기록된 메시지는 성공적으로 소비될 때까지 손실되지 않습니다(프로젝트 재시작에 대해 걱정할 필요가 없습니다) 메시지 대기열은 메시지 성공적인 전달을 보장합니다.: 다운스트림은 대기열에서 메시지를 가져오고 성공적인 소비 후에 메시지를 삭제합니다. 그렇지 않으면 재시도 요구 사항에 따라 메시지를 계속해서 소비자에게 전달합니다. 메시지 대기열을 비동기식으로 사용하기 캐시를 다시 시도한다는 것은 정보가 변경되면 데이터베이스가 먼저 업데이트되고 삭제에 성공하면 모두가 기뻐한다는 의미입니다. 삭제에 실패하면 삭제해야 하는 키가 메시지 큐로 전송됩니다. 또한 소비자 스레드는 메시지 대기열에서 삭제할 키를 검색하고 해당 키를 기반으로 Redis 캐시를 삭제하거나 업데이트합니다. 작업이 실패하면 메시지 큐로 다시 전송되어 재시도됩니다. 참고: 먼저 삭제하지 않고 메시지 대기열로 직접 보낼 수도 있고 메시지 대기열을 그대로 둘 수도 있습니다. 예를 들어 사용자 정보 테이블이 있는 경우 Redis에 사용자 정보를 저장하려고 합니다. . 다음은 메시지 대기열 비동기 재시도 캐싱을 사용하는 솔루션을 예로 들어 수행할 수 있는 단계입니다. 사용자 정보가 변경되면 먼저 데이터베이스를 업데이트하고 성공적인 결과를 프런트 엔드에 반환합니다. 캐시 삭제가 성공하면 작업이 종료됩니다. 실패하면 캐시 삭제 또는 업데이트 작업에 대한 메시지(예: 키 및 작업 유형 포함)가 생성되어 전송됩니다. 메시지 대기열에 추가합니다(예: Kafka 또는 RabbitMQ 사용). 또한 메시지 큐에서 이러한 메시지를 구독하고 가져오고 메시지 내용을 기반으로 Redis에서 해당 정보를 삭제하거나 업데이트하는 소비자 스레드가 있습니다. 캐시가 성공적으로 삭제되거나 업데이트되면 반복 작업을 피하기 위해 메시지가 메시지 대기열에서 제거(폐기)됩니다. 캐시 삭제 또는 업데이트가 실패한 경우 지연 시간 또는 재시도 제한 설정과 같은 실패 전략을 구현한 다음 재시도를 위해 메시지를 메시지 대기열로 다시 보냅니다. 일정 횟수를 초과한 후에도 재시도에 실패할 경우 비즈니스 계층에 오류 메시지가 전송되고 로그가 기록됩니다. 일관성을 달성하기 위해 binlog를 사용하는 기본 아이디어는 binlog 로그를 사용하여 데이터베이스 변경 작업을 기록한 다음 마스터-슬레이브 복제 또는 증분 백업을 통해 데이터를 동기화하거나 복원하는 것입니다. 예를 들어 마스터 데이터베이스와 슬레이브 데이터베이스가 있는 경우 마스터 데이터베이스에서 binlog를 활성화하고 슬레이브 데이터베이스를 복제 노드로 설정할 수 있습니다. 이러한 방식으로 마스터 데이터베이스에서 변경 작업이 발생하면 해당 binlog 로그를 슬레이브 데이터베이스로 보내고 슬레이브 데이터베이스는 binlog 로그를 기반으로 동일한 작업을 수행하여 데이터 일관성을 보장합니다. 또한 특정 시점 이전에 데이터를 복원해야 하는 경우 binlog 로그를 사용하여 이를 달성할 수도 있습니다. 먼저, 해당 시점 이전의 가장 최근의 전체 백업 파일을 찾아 대상 데이터베이스에 복원해야 합니다. 그런 다음 해당 시점 이전의 모든 증분 백업 파일(즉, binlog 로그 파일)을 찾아 대상 데이터베이스에 순서대로 적용해야 합니다. 이런 방식으로 목표 시점 이전의 데이터 상태를 복원할 수 있습니다. Binlog를 사용하여 Redis 캐시를 실시간으로 업데이트/삭제하세요. Canal을 사용하면 캐시 업데이트를 담당하는 서비스가 MySQL 슬레이브 노드로 위장하고 MySQL로부터 Binlog를 수신하여 Binlog를 구문 분석하고 실시간 데이터 변경 정보를 얻은 다음 변경 정보를 기반으로 Redis 캐시를 업데이트/삭제합니다. 지연 이중 삭제 전략을 사용하는 경우 스레드 A와 B의 실행 프로세스는 다음과 같습니다. 스레드 A가 먼저 캐시의 사용자 정보를 삭제합니다. 스레드 A가 사용자 정보를 읽습니다. 데이터베이스에서 사용자 점수가 1000인 것으로 확인되었습니다 스레드 A는 사용자 점수에 100을 더해 1100이 되어 데이터베이스에 업데이트됩니다. 스레드 A는 5초 동안 Sleep 상태입니다. 데이터베이스가 동기화될 만큼 충분함) 스레드 A가 캐시에 있는 사용자 정보를 다시 삭제합니다 스레드 B가 먼저 캐시에 있는 사용자 정보를 삭제합니다 스레드 B가 데이터베이스에서 사용자 정보를 읽고 (스레드 A가 업데이트되었기 때문에) 사용자 포인트가 1100임을 발견합니다 스레드 B는 사용자 포인트에서 50을 빼고 1050으로 데이터베이스에 업데이트합니다. 스레드 B는 5초 동안 휴면합니다(이 시간이 충분하다고 가정) 데이터베이스 동기화를 위해) Thread B가 캐시를 다시 삭제합니다. 사용자 정보 최종 결과: 데이터베이스의 사용자 포인트는 1050이며 캐시에 사용자 정보가 없습니다. 다음에 사용자 정보를 쿼리할 때는 데이터베이스에서 가져와서 캐시에 기록하는 대신 먼저 캐시에서 읽습니다. 이는 데이터 일관성을 보장합니다. 지연 이중 삭제는 동시성이 높은 시나리오, 특히 데이터 수정 작업이 빈번하고 쿼리 작업이 거의 없는 상황에 적합합니다. 이를 통해 데이터베이스에 대한 부담을 줄이고 성능을 향상시키는 동시에 데이터의 최종 일관성을 보장할 수 있습니다. 지연된 이중 삭제는 데이터베이스에 마스터-슬레이브 동기화 지연이 있는 시나리오에도 적합합니다. 데이터베이스를 업데이트한 후 슬레이브 데이터베이스에서 동기화가 완료되기 전에 캐시된 이전 데이터를 읽고 캐시에 다시 쓰는 것을 방지할 수 있기 때문입니다. 참고: 이 대기 시간은 비즈니스 로직 데이터를 읽는 데 걸리는 시간 + 수백 밀리초입니다. 읽기 요청이 종료되었는지 확인하기 위해 쓰기 요청은 읽기 요청으로 인해 발생할 수 있는 캐시된 더티 데이터를 삭제할 수 있습니다.
데이터베이스를 먼저 업데이트한 후 캐시를 업데이트하세요
캐시를 먼저 삭제한 후 데이터베이스를 업데이트하세요
데이터베이스를 먼저 업데이트한 후 캐시를 삭제하세요
Solution
1. 재시도
2. 비동기식 재시도
2.1 메시지 대기열을 사용하여 재시도 구현
2.2 Binlog는 비동기 재시도 삭제를 구현합니다.
MySQL의 binlog 로그는 삽입과 같은 데이터베이스 변경 작업을 기록합니다. 업데이트, 삭제 등 binlog 로그에는 두 가지 주요 기능이 있습니다. 하나는 마스터-슬레이브 복제이고 다른 하나는 증분 백업입니다. 마스터-슬레이브 복제는 마스터 데이터베이스의 데이터를 하나 이상의 슬레이브 데이터베이스에 동기화하여 데이터 동기화를 달성하는 프로세스입니다. 마스터 데이터베이스는 자체 binlog 로그를 슬레이브 데이터베이스로 보내고, 슬레이브 데이터베이스는 데이터 일관성을 보장하기 위해 binlog 로그를 기반으로 동일한 작업을 수행합니다. 이 접근 방식을 구현하면 데이터 가용성과 안정성이 향상되고 로드 밸런싱과 오류 복구가 달성될 수 있습니다.
증분 백업은 전체 백업을 기반으로 데이터베이스 변경 사항을 정기적으로 백업하는 것을 말합니다. 전체 백업은 데이터베이스 전체 데이터를 파일로 완전히 백업하는 것을 의미합니다. 목적은 최신 상태로 복원하기 위해 데이터베이스의 최신 변경 사항을 이전 백업과 병합하는 것입니다. 이렇게 하면 백업에 소요되는 공간과 시간을 절약할 수 있을 뿐만 아니라 어느 시점으로든 데이터를 쉽게 복원할 수 있습니다.
이 시점에서 우리는 데이터베이스와 캐시의 일관성을 보장하기 위해 "데이터베이스를 먼저 업데이트한 후 캐시를 삭제하는" 솔루션을 채택하고 "Message Queue"와 협력하는 것이 권장된다는 결론을 내릴 수 있습니다. 또는 "변경 로그 구독" 방법을 사용하세요. 3. 지연된 이중 삭제우리는 먼저 데이터베이스를 업데이트한 다음 캐시를 삭제하는 데 중점을 둡니다. 캐시를 먼저 삭제한 다음 데이터베이스를 업데이트하려면 어떻게 해야 합니까? 캐시를 먼저 삭제한 다음 데이터베이스를 업데이트하는 것에 대해 앞서 말한 내용을 기억하세요. 그러면 이전 값이 캐시를 덮어쓰게 됩니다. 이전 값만 삭제하면 끝이라는 원칙입니다. 이중 삭제의 기본 아이디어는 다음과 같습니다.
데이터베이스 업데이트를 방지하기 위해 다른 스레드가 만료된 캐시 데이터를 읽고 다시 캐시에 쓴 후에 이 조치를 취하여 데이터 불일치가 발생했습니다. 예를 들어, 사용자 정보 테이블이 있고 그 중 하나가 사용자 포인트라고 가정해 보겠습니다. 이제 두 개의 스레드 A와 B가 동시에 사용자 포인트를 운영하고 있습니다.
위 내용은 Redis와 MySQL 간의 이중 쓰기 일관성 문제를 해결하는 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!