MariaDB/Galera에서 대기열 테이블로 교착 상태를 방지하려면 어떻게 해야 합니까?
기본적으로 선입선출 큐인 데이터베이스 테이블이 있습니다.행은 단순히 시스템의 다른 부분에 의해 테이블에 삽입되고 잊혀집니다.5분마다 대기열에서 항목을 처리하는 작업이 실행됩니다.처리할 각 행은 상태 필드가 보류 값에서 처리 값으로 변경됩니다.대기열의 후속 복제는 처리 중인 이전 대기열에 있는 항목의 복제로 일치되며 표시됩니다.대기열 처리기 작업은 맹목적으로 행을 삽입하는 시스템의 부분을 제외하고 테이블에 대해 어떤 것도 할 수 있는 유일한 작업입니다.
프로세서가 큐에 대해 수행하는 작업은 다음과 같습니다.
START TRANSACTION;
SELECT id
FROM api_queue
WHERE status=:status_processing
-- Application checks this result set is empty, then...
UPDATE api_queue qs
INNER JOIN api_queue qdupes ON qdupes.products_id=qs.products_id AND qdupes.action=qs.action
SET qdupes.status = IF(qs.id=qdupes.id, :status_processing, :status_processing_duplicate)
WHERE qs.id IN (:queue_ids) ;
COMMIT;
-- Each queue item is processed
-- Once processing is complete, we purge the queue
START TRANSACTION;
SELECT COUNT(*) AS total FROM api_queue WHERE status = :status_processing ;
-- Application sanity checks the number of processing items it's about to delete against how many it's processed, and then...
DELETE FROM api_queue WHERE status IN (:status_processing, :status_processing_duplicate) ;
COMMIT;
일반적으로 5분 안에 대기열에는 약 100개 항목의 백로그가 쌓이지만 카탈로그에서 많은 변경이 발생한 경우에는 수천 개 항목에 이를 수 있습니다.
첫 번째 트랜잭션은 일반적으로 교착 상태에 빠르지 않을 때(완료까지 0.1~0.2초) 매우 빠르지만, 약 10%의 경우 교착 상태에 빠지는 것으로 보입니다.
왜 이렇게 자주 잠기는 거지?트랜잭션이 현재 테이블의 모든 행을 잠그더라도 테이블에 새 행을 추가할 때 경합이 발생할 것으로 예상해야 합니까?그렇다면 왜 그럴까요?
의 첫 ( )가 있는 경우도 UPDATE
쿼리)가 실제로 적용되지 않는 것 같습니다. 관련 없는 버그일 수도 있다고 생각합니다.
내 대기열 테이블은 다음과 같습니다.
CREATE TABLE IF NOT EXISTS `api_queue` (
`id` int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
`products_id` int(11) NOT NULL,
`action` tinyint(3) NOT NULL,
`triggered_by` tinyint(3) NOT NULL,
`status` tinyint(1) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ;
나의 만트라: "줄 서지 말고, 그냥 하세요."MySQL에 구현된 큐가 너무 많아 이런저런 이유로 실패하는 것을 보았기 때문에 이렇게 말합니다.공통적인 이유는 항목을 삽입/확인/제거하는 데 드는 오버헤드가 "그냥 작업하는 것"만큼 비용이 많이 들 수 있기 때문입니다.그럼 왜 두 배의 비용이 드는 거지?그리고, 분명히, 대기열로 인해 추가적인 교착상태가 발생하고 있습니다.
알려주신 정보에 따르면 시스템은 5분마다 1500-3000을 처리할 수 있을 것입니다.그것은 "100"에서 "수천" 사이를 처리할 것입니다.
은 를 복잡해 보입니다.JOIN
그리고 단순히 1-in, 1-out이 아닌 다른 것들.
지금까지 제 의견을 거절하신다고 가정하면, 암호에 대한 비평을 진행하겠습니다.
SELECT ... FOR UPDATE
둘 다 필요할 수도 있습니다.SELECTs
.
그SELECT
옆에DELETE
아마도 그것과 합병될 수 있을 것입니다.DELETE
여러 테이블로DELETE
. 또는 트랜잭션에서 해당 코드와 더불어 해당 코드를 꺼내는 것이 가능할 수도 있습니다. (트랜지스터가 빨라지면 교착 상태가 발생할 가능성이 적습니다.)
작업 후 오류(잠금 등)를 확인하는 중입니다.COMMITs
, 그래요? 그때 갈레라가 맞았습니다.
사용시IN(...)
, 요소를 분류합니다.기본 코드는 아마도 행을 순서대로 잠그고 있을 것입니다.IN
요소들.이렇게 되면 교착 상태가 최대 3분의 1의 지연으로 전환될 수 있습니다.innodb_lock_wait_timeout
초.(이러한 지연은 교착 상태만큼 '나쁘지' 않습니다.)
교착 상태가 되면 거래를 반복하는 거죠? (그것이 교착 상태를 해결하는 간단한 방법입니다.)
편집(IN)
한 개의 스레드가 하는 경우UPDATE ... WHERE id IN (11,22)
그리고 또 다른 것은UPDATE ... WHERE id IN (22,11)
, 각 행이 하나씩 잠기면 다른 행이 잠기도록 시도하는 것은 교착 상태에 빠지기 때문에 하나는 다음과 같은 작업을 수행해야 합니다.ROLLBACK
. 대신 둘 다 (11,22)라고 말하면 (최악의 경우) 기다려야 할 것입니다 (그러나 교착 상태는 아닙니다).InnoDB 코드가 어떻게든 이것을 피할 수 있을 만큼 똑똑하지 않다는 것을 증거 없이 추측하고 있습니다.IN
교착 상태 -- 숫자를 정렬하거나, 원자적으로 잠금을 설정하거나, 무엇이든 간에 말입니다. (그리고 저는 cleaver= slower, 따라서 이런 드문 일이 일어나도 할 가치가 없다고 주장하고 싶습니다.)
언급URL : https://stackoverflow.com/questions/31161250/how-can-i-avoid-deadlocks-with-my-queue-table-on-mariadb-galera
'programing' 카테고리의 다른 글
복합 기본 키를 외부 키로 사용 (0) | 2023.10.11 |
---|---|
메타 값이 포함된 워드프레스 게시물 주문하기 (0) | 2023.10.11 |
npm init에서 "진입점"이란 무엇입니까? (0) | 2023.10.11 |
베어러TokenAccessDeniedHandler 클래스 정의를 찾을 수 없습니다. (0) | 2023.10.11 |
md-table - 열 너비 업데이트 방법 (0) | 2023.10.11 |