Eu tenho uma tabela no MySQL que representa uma fila de links a serem processados. Os links são processados por um aplicativo externo, um por um, e excluídos no final. Essa é uma fila de alto volume e tenho várias instâncias do aplicativo de processamento, espalhadas por vários servidores.
Como posso garantir que cada registro seja escolhido por apenas um aplicativo? Existe uma maneira de sinalizar / bloquear o registro?
No momento, para evitar dois ou mais capturar o mesmo link, estou permitindo que cada instância pegue apenas um determinado conjunto de registros (com base no MOD de seu ID), mas essa não é uma maneira transparente de aumentar o processamento da fila velocidade apenas adicionando novas instâncias.
Respostas:
Primeiro: o MySQL é um dos piores softwares possíveis para implementar isso, especialmente se for muito dinâmico. O motivo é que mecanismos como MEMORY e MyISAM têm apenas bloqueios de tabela completa, enquanto mecanismos mais adequados, como o InnoDB, têm uma penalidade de gravação mais alta (para fornecer propriedades ACID) e são otimizados para acessar registros que estão próximos espacial e temporalmente (aqueles configurados na memória ) Também não existe um bom sistema de notificação de alterações para o MySQL - ele deve ser implementado como uma pesquisa. Existem dezenas de softwares mais otimizados para essa tarefa .
Dito isto, vi implementar com êxito esse tipo de acesso se os requisitos de desempenho / eficiência não forem muito altos. Muitas pessoas não podem se dar ao luxo de introduzir e manter uma peça completa de tecnologia separada apenas por uma pequena parte da lógica de negócios.
SELECT FOR UPDATE
é o que você está procurando - ler serialização. Enquanto um UPDATE / DELETE sempre bloqueia a linha durante uma transação MYSQL em execução, convém evitar uma transação grande enquanto o processo está em andamento, portanto:O MySQL cuidará do bloqueio de todas as seleções simultâneas, exceto uma ao selecionar linhas. Como isso pode levar a muitas conexões bloqueadas ao mesmo tempo, mantenha a transação inicial o menor possível e tente processar mais de uma linha por vez.
fonte
Como expliquei neste artigo , o MySQL 8 introduziu suporte para SKIP LOCKED e NO WAIT.
SKIP LOCKED é útil para implementar filas de trabalhos (também conhecidas como filas de lotes), para que você possa pular os bloqueios que já estão bloqueados por outras transações simultâneas.
NO WAIT é útil para evitar a espera até que uma transação simultânea libere os bloqueios nos quais também estamos interessados em bloquear. Sem NO WAIT, precisamos aguardar até que os bloqueios sejam liberados (no momento da confirmação ou liberação pela transação que atualmente mantém os bloqueios) ou o tempo limite de aquisição do bloqueio. Portanto, NO WAIT atua como um tempo limite de bloqueio com um valor de
0
.Para mais detalhes sobre SKIP LOCK e NO WAIT, consulte este artigo .
fonte
Fiz algo semelhante com as verificações DBCC offline (dois servidores fazendo restaurações de backup e, em seguida, um DBCC checkdb). Um servidor reúne todos os 31 backups do servidor ontem e os coloca em uma fila e, em seguida, esse servidor e outro pull dessa fila. Embora não haja muitos servidores, o método deve permanecer o mesmo: faça com que o servidor de aplicativos execute uma consulta de atualização na fila, atualizando um campo de data / hora e um campo "servidor de aplicativos" com o nome desse servidor de aplicativos ou o ID numérico ainda melhor. Isso causará um bloqueio ou, se já houver um bloqueio de outro servidor que esteja obtendo a próxima linha, ele será bloqueado e aguardará o outro aplicativo concluir a obtenção da próxima linha. Você desejará que o aplicativo retire o registro mais recente da fila para o campo do aplicativo e obtenha as informações desejadas. Usando o MySQL '
fonte