동시 테이블 기반 큐를 구현하는 가장 좋은 방법


11

처리 할 링크 대기열을 나타내는 테이블이 MySQL에 있습니다. 링크는 외부 앱에서 하나씩 처리되고 결국 삭제됩니다. 이것은 대량 대기열이며 여러 서버에 걸쳐 처리 응용 프로그램의 여러 인스턴스가 있습니다.

하나의 앱만 각 레코드를 선택하도록하려면 어떻게해야합니까? 기록을 신고 / 잠그는 방법이 있습니까?

현재 두 개 이상의 동일한 링크를 선택하지 않으려면 각 인스턴스가 ID의 MOD를 기준으로 특정 레코드 세트 만 선택하도록 허용하지만 대기열 처리를 늘리는 투명한 방법은 아닙니다. 새 인스턴스를 추가하여 속도를 높입니다.


내 진언 : "대기하지 말고 그냥하세요". 즉, 작업을 대기열에 넣는 대신 프로세스를 시작하여 작업을 수행하십시오.
Rick James

답변:


8

첫째, MySQL은 특히 매우 역동적 인 경우이를 구현할 수있는 최악의 소프트웨어 중 하나입니다. 그 이유는 MEMORY 및 MyISAM과 같은 엔진에는 전체 테이블 잠금 만 있고 InnoDB와 같은 더 적합한 엔진은 쓰기 페널티가 높고 (ACID 속성 제공) 공간적으로나 시간적으로 가까운 레코드에 액세스하는 데 최적화되어 있기 때문입니다 (메모리에 설정되어 있음). ). MySQL에 대한 좋은 변경 알림 시스템도 없습니다. 폴링으로 구현해야합니다. 있습니다 더 그 작업을 위해 최적화 된 소프트웨어의 조각 수십 .

그러나 성능 / 효율 요구 사항이 그리 높지 않은 경우 이러한 종류의 액세스를 성공적으로 구현하는 것을 보았습니다. 많은 사람들이 비즈니스 로직의 작은 부분만을 위해 완전한 별도의 기술을 도입하고 유지할 여유가 없습니다.

SELECT FOR UPDATE찾고자하는 직렬화입니다. UPDATE / DELETE는 실행중인 MYSQL 트랜잭션 중에 항상 행을 잠그지 만 프로세스가 진행되는 동안 큰 트랜잭션을 피할 수 있습니다.

START TRANSACTION;
SELECT * FROM your_table WHERE state != 'PROCESSING' 
  ORDER BY date_added ASC LIMIT 1 FOR UPDATE;
if (rows_selected = 0) { //finished processing the queue, abort}
else {
UPDATE your_table WHERE id = $row.id SET state = 'PROCESSING'
COMMIT;

// row is processed here, outside of the transaction, and it can take as much time as we want

// once we finish:
DELETE FROM your_table WHERE id = $row.id and state = 'PROCESSING' LIMIT 1;
}

MySQL은 행을 선택할 때 하나를 제외한 모든 동시 선택을 잠 그게됩니다. 이로 인해 많은 연결이 동시에 잠길 수 있으므로 초기 트랜잭션을 가능한 한 작게 유지하고 한 번에 하나 이상의 행을 처리하십시오.


감사. LIMIT를 10으로 변경하여 성능이 더 큰 잠금으로 인해 이익을 얻을 수 있다고 생각하십니까?
Miguel E

@MiguelE 일반적으로 처리 시간이 많을수록 다른 거래와 충돌 할 가능성이 적을수록 좋습니다. 그러나 경우에 따라 다를 수 있습니다. 또한 반대 효과 (더 많은 트랜잭션이 잠김)를 유발할 수도 있습니다. 항상 먼저 테스트하십시오. 또한 테이블을 적절하게 인덱싱하는 것이 중요하거나 일부 격리 모드에서 전체 테이블 잠금이 발생할 수 있습니다.
jynus

1
프로세스가 중단되고 시간 초과 메커니즘을 구현하려는 경우 행 처리를 시작한 날짜를 추적하는 것이 좋습니다.
Julian

3

이 기사 에서 설명했듯이 MySQL 8은 SKIP LOCKED와 NO WAIT를 모두 지원합니다.

SKIP LOCKED는 다른 동시 트랜잭션에 의해 이미 잠긴 잠금을 건너 뛸 수 있도록 작업 대기열 (일괄 처리 대기열)을 구현하는 데 유용합니다.

NO WAIT는 동시 트랜잭션이 잠금에 관심이있는 잠금을 해제 할 때까지 대기하지 않도록하는 데 유용합니다. WAIT가 없으면 잠금이 해제 될 때까지 (현재 잠금을 보유한 트랜잭션에 의해 커밋 또는 해제 시간에) 기다리거나 잠금 획득 시간이 초과 될 때까지 기다려야합니다. 따라서 NO WAIT는 값이 잠금 제한 시간처럼 작동 0합니다.

SKIP LOCK 및 NO WAIT에 대한 자세한 내용은 이 기사를 확인 하십시오 .


0

오프라인 DBCC 검사 (백업 복원을 수행하는 두 대의 서버와 DBCC checkdb)와 비슷한 작업을 수행했습니다. 한 서버는 어제 31 개의 서버 백업을 모두 수집하여 대기열에 넣은 다음 해당 서버와 다른 대기열을 해당 대기열에서 가져옵니다. 서버가 많지는 않지만 방법은 동일해야합니다. 응용 프로그램 서버가 날짜 / 시간 필드와 해당 앱 서버 이름 또는 더 나은 숫자 ID로 "앱 서버"필드를 업데이트하는 대기열에 대해 업데이트 쿼리를 실행하도록합니다. 이로 인해 잠금이 발생하거나 다음 행을 얻는 다른 서버의 잠금이 이미 있으면 차단되고 다른 앱이 다음 행을 가져 오기를 기다릴 수 있습니다. 그런 다음 앱이 앱 필드에 대한 대기열에서 최신 레코드를 가져와 원하는 정보를 얻길 원합니다. MySQL 사용하기

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.