mysql에서 메시징 대기열 테이블을 구현하는 가장 좋은 방법은 무엇입니까?
제가 이와 같은 것을 구현하는 것은 아마 열 번째일 것입니다. 제가 생각해 낸 솔루션에 대해 100% 만족한 적은 없었습니다.
"적절한" 메시징 시스템 대신 mysql 테이블을 사용하는 것이 매력적인 이유는 대부분의 응용프로그램이 이미 다른 작업(내가 해왔던 대부분의 작업에 대해 mysql인 경향이 있음)에 대해 일부 관계형 데이터베이스를 사용하는 반면, 극히 일부 응용프로그램은 메시징 시스템을 사용하기 때문입니다.또한 관계형 데이터베이스는 매우 강력한 ACID 속성을 가지고 있지만 메시징 시스템은 그렇지 않은 경우가 많습니다.
첫 번째 아이디어는 다음과 같습니다.
테이블 작업 생성(id auto_message가 null 기본 키가 아닙니다.메시지 텍스트가 null이 아닙니다.process_id varbinary(255) null 기본 null,키 작업_key(process_id));
다음은 다음과 같습니다.
작업에 삽입("blah blah') 값;
dequeue는 다음과 같습니다.
시작;process_id가 ID 제한 1에 의한 null 순서인 작업에서 *를 선택합니다.업데이트 작업 세트 process_id = ? 어디서 ID = ?; -- 방금 받은 모든 것.커밋;응용 프로그램에 (ID, 메시지) 반환, 완료 후 정리
테이블과 엔큐는 좋아 보이지만 디큐는 좀 신경이 쓰입니다.롤백할 가능성은 얼마나 됩니까?아니면 막힐까요?O(1)-ish로 만들려면 어떤 키를 사용해야 합니까?
아니면 제가 하고 있는 일보다 더 나은 해결책이 있을까요?
디큐는 좀 더 간결할 수 있습니다.트랜잭션 롤백에 의존하는 대신 명시적인 트랜잭션 없이 하나의 아토믹 문으로 이 작업을 수행할 수 있습니다.
UPDATE jobs SET process_id = ? WHERE process_id IS NULL ORDER BY ID ASC LIMIT 1;
그런 다음 다음 작업을 풀 수 있습니다(브래킷 []은(는) 세부 정보에 따라 선택 사항을 의미합니다).
SELECT * FROM jobs WHERE process_id = ? [ORDER BY ID LIMIT 1];
몇 개의 메시지 큐 시스템을 구축했는데 어떤 유형의 메시지를 말씀하시는 건지 잘 모르겠습니다만, 큐 해제의 경우(단어인가요?)저도 당신과 같은 일을 했습니다.당신의 방법은 간단하고 깨끗하고 견고해 보입니다.제 작업이 최고라는 것은 아니지만, 많은 사이트의 대규모 모니터링에 매우 효과적인 것으로 입증되었습니다.(오류 기록, 대량 전자 메일 마케팅 캠페인, 소셜 네트워킹 공지)
제 투표: 걱정하지 마세요!
브라이언 에이커는 얼마 전에 대기열 엔진에 대해 이야기했습니다.에 대한 이야기가 있었습니다.SELECT table FROM DELETE
구문도 마찬가지입니다.
처리량이 걱정되지 않는 경우 언제든지 SELECT GET_LOCK()을 뮤텍스로 사용할 수 있습니다.예:
SELECT GET_LOCK('READQUEUE');
SELECT * FROM jobs;
DELETE FROM JOBS WHERE ID = ?;
SELECT RELEASE_LOCK('READQUEUE');
그리고 만약 여러분이 정말로 화려해지고 싶다면, 저장된 절차로 포장하세요.
MySQL 8을 할 수 .NOWAIT
그리고.SKIP LOCKED
특수 잠금 메커니즘으로 복잡함을 방지하기 위한 키워드:
START TRANSACTION;
SELECT id, message FROM jobs
WHERE process_id IS NULL
ORDER BY id ASC LIMIT 1
FOR UPDATE SKIP LOCKED;
UPDATE jobs
SET process_id = ?
WHERE id = ?;
COMMIT;
전통적으로 해킹, 비정상적인 특수 테이블 또는 열, 신뢰할 수 없는 솔루션 또는 동시성 상실 없이는 이를 달성하기 어려웠습니다.
SKIP LOCKED
매우 많은 수의 소비자에게 성능 문제를 야기할 수 있습니다.
그러나 트랜잭션 롤백 시 작업이 자동으로 완료된 것으로 표시되는 작업은 처리되지 않습니다.이를 위해 포인트 적립이 필요할 수 있습니다.그러나 그것이 모든 경우를 해결하지는 못할 수 있습니다.트랜잭션 실패 시 실행할 작업을 설정하고 싶지만 트랜잭션의 일부입니다!
향후에는 일치된 행을 반환할 수 있는 업데이트와 같은 사례를 최적화하는 데 도움이 되는 더 많은 기능이 있을 수 있습니다.변경 로그의 새로운 기능에 대한 정보를 계속 제공하는 것이 중요합니다.
여기 현재 스레드의 process_id 없이 작업하거나 테이블을 잠그는 데 사용한 솔루션이 있습니다.
SELECT * from jobs ORDER BY ID ASC LIMIT 0,1;
$row 배열로 결과를 가져오고 다음을 실행합니다.
DELETE from jobs WHERE ID=$row['ID'];
그런 다음 영향을 받는 행(mysql_attented_rows)을 가져옵니다.영향을 받는 행이 있으면 $row 배열에서 작업을 처리합니다.영향을 받는 행이 0개인 경우 다른 프로세스가 이미 선택한 작업을 처리하고 있음을 의미합니다.행이 없을 때까지 위의 단계를 반복합니다.
저는 이것을 100,000 행의 'jobs' 테이블로 테스트했고 위와 같은 20개의 동시 프로세스를 생성했습니다.경주 조건은 발생하지 않았습니다.위 쿼리를 수정하여 처리 플래그가 있는 행을 업데이트하고 실제로 처리한 후 해당 행을 삭제할 수 있습니다.
while(time()-$startTime<$timeout)
{
SELECT * from jobs WHERE processing is NULL ORDER BY ID ASC LIMIT 0,1;
if (count($row)==0) break;
UPDATE jobs set processing=1 WHERE ID=$row['ID'];
if (mysql_affected_rows==0) continue;
//process your job here
DELETE from jobs WHERE ID=$row['ID'];
}
이러한 종류의 작업에는 적절한 메시지 큐(ActiveMQ, RabbitMQ 등)를 사용해야 한다는 것은 말할 필요도 없습니다.그러나 호스트가 소프트웨어를 업데이트할 때 정기적으로 문제를 해결하기 때문에 문제를 해결할 수 있는 방법은 적을수록 좋습니다.
Quartz.NET을 사용할 것을 제안합니다.
SQL Server, Oracle, MySql, SQLite 및 Firebird에 대한 공급자가 있습니다.
이 스레드에는 표시 가능해야 하는 설계 정보가 있습니다.
견적서 작성:
제가 과거에 성공적으로 사용한 것은 다음과 같습니다.
MsgQueue 테이블 스키마
MsgId ID - NULL이 아님
MsgTypeCode varchar(20) - NULL이 아닙니다.
SourceCode varchar(20) -- 메시지 삽입 프로세스 -- NULLable
상태 문자(1) - '대기 중이면 새로 만들기', 처리 중이면 'A'(활성), 'C' 완료, 기본값 'N' -- NULL 아님
CreateTime datetime -- 기본 GETDATE() -- NULL이 아닙니다.
Msg varchar(255) -- NULL 가능
사용자의 메시지 유형은 프로세스 삽입과 프로세스 읽기 사이의 계약에 부합하는 메시지로, XML 또는 다른 표현 선택으로 구성되어 있습니다(예를 들어 JSON은 경우에 따라 유용합니다).
그런 다음 0-to-n 프로세스를 삽입하고 0-to-n 프로세스를 통해 메시지를 읽고 처리할 수 있습니다. 각 읽기 프로세스는 일반적으로 단일 메시지 유형을 처리합니다.로드 밸런싱을 위해 프로세스 유형의 여러 인스턴스를 실행할 수 있습니다.
판독기는 메시지 하나를 끌어다 놓고 상태를 "A"active로 변경합니다.완료되면 상태가 "C" 완료로 변경됩니다.감사 추적을 유지할지 여부에 따라 메시지를 삭제할 수 있습니다.상태 = 'N' 메시지는 MsgType/Timestamp 순으로 풀되므로 MsgType + State + CreateTime에 인덱스가 있습니다.
변형:
E 오류 상태입니다.
판독기 프로세스 코드의 열입니다.
상태 전환에 대한 타임스탬프입니다.
이것은 당신이 설명하고 있는 것처럼 여러 가지를 수행할 수 있는 멋지고, 확장 가능하고, 눈에 보이는 간단한 메커니즘을 제공했습니다.데이터베이스에 대한 기본적인 이해가 있다면, 그것은 매우 완벽하고 확장 가능합니다.원자 상태 전환 트랜잭션으로 인해 잠금 롤백 등에 문제가 발생한 적은 없습니다.
중간 테이블을 사용하여 대기열의 오프셋을 유지할 수 있습니다.
create table scan(
scan_id int primary key,
offset_id int
);
여러 개의 검색이 진행 중이므로 검색당 오프셋이 하나씩 발생할 수 있습니다.스캔 시작 시 offset_id = 0을 초기화합니다.
begin;
select * from jobs where order by id where id > (select offset_id from scan where scan_id = 0) asc limit 1;
update scan set offset_id = ? where scan_id = ?; -- whatever i just got
commit;
마지막 오프셋만 유지하면 됩니다.이렇게 하면 상당한 공간(레코드당 process_id)도 마찬가지입니다.이것이 논리적으로 들리기를 바랍니다.
언급URL : https://stackoverflow.com/questions/423111/whats-the-best-way-of-implementing-a-messaging-queue-table-in-mysql
'programing' 카테고리의 다른 글
Angular2: 정의되지 않은 속성 'name'을(를) 읽을 수 없습니다. (0) | 2023.08.05 |
---|---|
mySQL의 데이터 유형 "Time"이 Access에서 "Datetime"으로 바뀝니다. (0) | 2023.08.05 |
어떻게 하면 매트플롯립 플롯의 출력을 SVG로 얻을 수 있습니까? (0) | 2023.08.05 |
목록 사이의 공백을 설정하는 방법Android에서 항목 보기 (0) | 2023.08.05 |
테이블의 열 이름이 동일한 레코드에 대해 여러 테이블을 쿼리하는 방법 (0) | 2023.08.05 |