이메일 대기열 인 간단한 표가 있습니다.Innodb 트랜잭션 또는 테이블이 잠겨 있습니까?
CREATE TABLE `emails_queue_batch` (
`eq_log_id` int(11) NOT NULL DEFAULT '0',
`eq_to` varchar(120) CHARACTER SET utf8 DEFAULT NULL,
`eq_bcc` varchar(80) CHARACTER SET utf8 DEFAULT '',
`eq_from` varchar(80) CHARACTER SET utf8 DEFAULT NULL,
`eq_title` varchar(100) COLLATE utf8_unicode_ci DEFAULT NULL,
`eq_headers` varchar(80) CHARACTER SET utf8 DEFAULT NULL,
`eq_content` longtext CHARACTER SET utf8,
`eq_sid` int(11) DEFAULT '0',
`eq_type` int(11) DEFAULT '0' COMMENT 'email type',
`eq_esp` int(11) DEFAULT '0',
PRIMARY KEY (`eq_log_id`),
KEY `email` (`eq_to`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci
여러 스레드가 한 번에 50 개의 행을 반복적으로 읽고 행을 삭제합니다.
$db->query(" LOCK TABLE $table WRITE ");
$query= "SELECT * FROM $table LIMIT ".CHUNK_SIZE. " " ;
$emails2send=$db->get_results ($query);
if (!empty ($emails2send)){
// DELETE EMAIL
$eq_log_ids = array();
foreach ($emails2send as $email) $eq_log_ids[]= $email->eq_log_id ;
$query= "DELETE FROM $table WHERE eq_log_id IN (".implode(',', $eq_log_ids).") ";
$db->query ($query);
$db->query (" UNLOCK TABLES "); // unlock the table so other sessions can read next rows
........ code processing the read rows here .............
} else { // if !empty emails2send
// $emails2send is empty
$db->query (" UNLOCK TABLES; ");
$stop_running=true; // stop running
}
또 다른 스레드 (들)을 동시에 테이블에 쓰기 :
내가 사용한 것과 같은 행을 두 번 읽기를 방지합니다. 나는이 구성이 읽기 및 쓰기 모두 잠긴 테이블로 인해 교착 상태에 있다는 것을 이해하지 못합니다.내 질문 : 이 솔루션은 올바른 솔루션을 잠그기 때문에 각 행을 한 번만 읽고 한 번만 읽습니다.
또는 트랜잭션으로 처리하는 것이 더 나은가요? 그렇다면 어떤 종류입니까? 나는 거래 경험이 없다.
올바른 해결책은 실제 메시지 대기열 (예 : RabbitMQ 또는 ActiveMQ)을 사용하는 것입니다. 사실상 큐로 트랜잭션 데이터베이스를 사용하면 데이터베이스 큐에서 하나의 스레드 읽기로만 제한하지 않는 한 항상 잠금 경합 및 교착 상태가 발생합니다. –
고마워, 잘하고있어. 메시지 대기열에 대한 한 가지 문제점은 문제가 발생하고 예를 들어 이메일 일괄 처리를 취소해야하는 경우 대기열에서 선택적으로 삭제할 수 없다는 것입니다. – Nir
지난 일자리 중 하나에서 우리는 데이터베이스에 작업을 보관했지만 "디스패처"프로세스는 실행할 준비가되었을 때 작업을 끌어와 MQ에 게시했습니다. 발송자가 단일 스레드 인 한 사용자가 묻는 문제는 피할 수 있습니다. 그런 다음 MQ는 많은 작업자 스레드에서 읽을 수 있습니다. 이는 균형을 유지합니다. MQ에 게시 될 때까지 DB의 작업을 삭제하거나 수정할 수 있습니다. –