Consistência read-after-write num cluster Galera
Um cluster Galera ou Percona XtraDB certifica um write no commit e aplica-o nos outros nós um instante depois, e um read encaminhado para esse intervalo vê o passado.
Neste artigo 6 secções
- Num cluster baseado em certificação, commit significa que o write foi certificado em todos os nós, não que todos os nós o aplicaram. A aplicação acontece um instante depois, tipicamente entre dezenas e algumas centenas de milissegundos.
- Um read balanceado para um nó que ainda não aplicou o write devolve a linha antiga. Num CMS, isso lê-se como uma edição perdida: o editor guarda, atualiza a página, vê o texto antigo e volta a guardar por cima da versão mais recente. Nenhum erro é lançado em lado nenhum.
- O wsrep_sync_wait fecha o intervalo ao fazer um read esperar até o seu nó estar em dia. Custa o apply lag nos reads que se seguem a um write, por isso restringe-se às sessões que precisam dele e fica desligado nas páginas que uma edge cache serve.
Commit significa certificado, não aplicado
Um cluster Galera executa uma transação num nó. No commit, esse nó difunde o write set para o cluster, cada nó certifica-o face aos write sets já em curso, e o commit regressa ao cliente. A partir desse momento, o write é durável no cluster e ordenado de forma idêntica em todo o lado.
O que ainda não aconteceu é a aplicação. Cada nó pega no write set certificado e aplica-o à sua própria cópia dos dados, nas suas próprias applier threads, ligeiramente depois de o commit ter regressado. Há dois relógios a correr: a certificação é ao nível do cluster e faz parte do commit; a aplicação é local e vem depois. Num cluster saudável, a distância entre os dois é de dezenas a algumas centenas de milissegundos. Cresce durante picos de writes, transações grandes e alterações de esquema, e é visível como um wsrep_local_recv_queue diferente de zero no nó que está atrasado.
Para onde vai o read
Um cluster com reads balanceados envia os reads para onde o proxy decidir. Um pedido escreve no nó A; o pedido seguinte do mesmo utilizador, algumas centenas de milissegundos depois, lê no nó B. Se o nó B recebeu mas ainda não aplicou o write set, responde com a linha tal como estava antes do write. Do ponto de vista do nó B, a resposta está correta: é o seu estado committed. Nada é registado, nada dispara um alarme, e a monitorização do lag fica em silêncio porque foi construída para apanhar lag sustentado, não os primeiros cem milissegundos a seguir a uma transação.
É por isso que o sintoma parece aleatório. Depende de que nó o balanceador escolheu, da rapidez com que o utilizador voltou e de quão ocupados estavam os appliers naquele instante.
Como se manifesta numa aplicação
O padrão é um write seguido de imediato por um read do mesmo utilizador, a cair num nó diferente. Num CMS é o parágrafo desaparecido: guardar, atualizar, texto antigo, reescrever, guardar, e a segunda gravação sobrepõe-se à primeira. Numa loja online é uma encomenda que não existe na página de confirmação. Num fluxo de autenticação é um token que acabou de ser emitido e não é encontrado.
Dois outros mecanismos produzem uma história semelhante e vale a pena excluí-los primeiro. A back-forward cache de um browser pode repor uma cópia desatualizada de um formulário, e uma nova gravação escreve então essa cópia desatualizada. Um plugin pode fazer um read-modify-write na mesma linha a partir de dois pedidos. Ambos são reais e nenhum deles é o cluster. Um ciclo que escreve um timestamp num nó e o lê de volta nos outros separa-os num minuto.
A definição: wsrep_sync_wait
O wsrep_sync_wait é uma bitmask. Com o bit 1 ativo, um SELECT espera até o nó ter aplicado todos os write sets recebidos até esse momento antes de ser executado. O read tem então a garantia de ver tudo o que foi committed em qualquer ponto do cluster antes de começar. Pode ser definido para uma sessão, que é o âmbito certo para um percurso de edição ou de checkout, ou globalmente quando toda a carga de trabalho é sensível ao read-after-write.
-- for one session: the request path that writes and then reads
SET SESSION wsrep_sync_wait = 1;
-- for the whole node: my.cnf, under [mysqld]
wsrep_sync_wait = 1A alternativa é o encaminhamento: enviar os reads que se seguem a um write para o nó que escreveu, com regras de query no proxy ou na aplicação. Funciona para os percursos que cobre. Um percurso de código que ninguém encaminhou reabre o intervalo, e é por isso que a definição é preferível onde o custo pode ser pago: trata o mecanismo, não um percurso através dele.
O que custa e onde pagá-lo
Um read sob wsrep_sync_wait espera que o applier local fique em dia, por isso paga o apply lag uma vez por cada read que se segue a um write. Num cluster saudável, são dezenas a algumas centenas de milissegundos. As sessões autenticadas, os percursos de administração e edição e o checkout são onde esse custo compra alguma coisa. As páginas anónimas servidas a partir de uma edge cache não tocam na base de dados num hit e não são afetadas. A definição entra em vigor na instrução seguinte e reverte da mesma forma, por isso pode ser medida no local, com a carga de trabalho real, em vez de estimada.
Como verificar o seu próprio cluster
Três leituras resolvem a questão. Se os reads esperam de todo; quanto um nó fica atrasado durante um pico de writes; e com que frequência um read-after-write entre nós vê de facto o passado, a partir de um ciclo que escreve num nó e lê nos outros.
SHOW GLOBAL VARIABLES LIKE 'wsrep_sync_wait'; -- 0 means reads do not wait
SHOW GLOBAL STATUS LIKE 'wsrep_local_recv_queue'; -- received, not yet appliedOperamos clusters Percona XtraDB com reads balanceados atrás de ProxySQL e HAProxy e conseguimos responder a essas três perguntas para qualquer cluster que operamos, incluindo o que a definição custa nessa carga de trabalho específica.
Respostas diretas
A replicação do Galera é síncrona?+
A certificação é: o write é certificado em todos os nós antes de o commit regressar. A aplicação em cada nó acontece um instante depois. As duas metades contam, e a segunda é onde vivem os problemas de read-after-write.
Porque é que o meu CMS perde edições num cluster?+
Um read a seguir a uma gravação foi encaminhado para um nó que tinha recebido o write set mas ainda não o tinha aplicado. O editor viu o conteúdo antigo, reescreveu-o e guardou por cima da versão mais recente. Não é produzido nenhum erro, e é por isso que parece intermitente.
Limpar a cache ajuda?+
Normalmente não. A cache guardou o que a base de dados devolveu, e por um momento a base de dados devolveu o passado. Diagnostique o percurso do read. Aqui a cache transporta o sintoma, não é a causa.
Quanto custa o wsrep_sync_wait?+
O apply lag, pago nos reads que se seguem a um write, tipicamente dezenas a algumas centenas de milissegundos num cluster saudável. As páginas servidas a partir de uma edge cache não são afetadas. Restrinja-o por sessão para o pagar apenas onde importa.
Opera um cluster com reads balanceados?
Fale com um engenheiro sobre se o read-after-write está ativo e quanto custa no seu caso.
Fale com um engenheiroChegou ao fim.
Ponha a leitura em prática
O que executa?
Fale-nos da carga de trabalho, do tráfego e dos requisitos de recuperação. Comece pelo configurador de servidores ou discuta os detalhes com um engenheiro.
Escrito pelos engenheiros que constroem e operam a infraestrutura que descreve.Fale com um engenheiro
