17.14. Alta Disponibilidade de Armazenamento (HAST)

Contribuido por Daniel Gerzo.
Com contribuições de Freddie Cash, Pawel Jakub Dawidek, Michael W. Lucas e Viktor Petersson.

A alta disponibilidade é um dos principais requisitos em aplicativos de negócios sérios e o armazenamento altamente disponível é um componente-chave nesses ambientes. No FreeBSD, o framework Alta Disponiblidade de Armazenamento (HAST) permite o armazenamento transparente dos mesmos dados em várias máquinas fisicamente separadas conectadas por uma rede TCP/IP. HAST pode ser entendido como um RAID1 (mirror) baseado em rede, e é similar ao sistema de armazenamento DRBD® usado na plataforma GNU/Linux®. Em combinação com outros recursos de alta disponibilidade do FreeBSD, como o CARP, o HAST possibilita a criação de um cluster de armazenamento altamente disponível, resistente a falhas de hardware.

A seguir estão as principais características do HAST:

Depois de ler esta seção, você saberá:

Antes de ler esta seção, você deve:

O projeto HAST foi patrocinado pela Fundação FreeBSD com o apoio de http://www.omc.net/ e http://www.transip.nl/.

17.14.1. Operação HAST

O HAST fornece replicação síncrona em nível de bloco entre duas máquinas físicas: o primário, também conhecido como o nó master, e o secundário, ou nó slave. Essas duas máquinas juntas são chamadas de cluster.

Como o HAST funciona em uma configuração primária-secundária, ele permite que apenas um dos nós do cluster esteja ativo a qualquer momento. O nó primário, também chamado de active, é aquele que irá lidar com todas as solicitações de I/O para dispositivos gerenciados por HAST. O nó secundário é automaticamente sincronizado a partir do nó primário.

Os componentes físicos do sistema HAST são o disco local no nó primário e o disco no nó secundário remoto.

O HAST opera de forma síncrona em um nível de bloco, tornando-o transparente para sistemas de arquivos e aplicativos. O HAST fornece provedores GEOM regulares em /dev/hast/ para uso por outras ferramentas ou aplicativos. Não há diferença entre o uso de dispositivos HAST e discos ou partições brutas.

Cada operação de gravação, exclusão ou liberação é enviada para o disco local e para o disco remoto sobre TCP/IP . Cada operação de leitura é fornecida a partir do disco local, a menos que o disco local não esteja atualizado ou ocorra um erro de I/O. Nesses casos, a operação de leitura é enviada para o nó secundário.

HAST tenta fornecer recuperação rápida de falhas. Por esse motivo, é importante reduzir o tempo de sincronização após a interrupção de um nó. Para fornecer sincronização rápida, o HAST gerencia um bitmap no disco de extensões sujas e sincroniza apenas aquelas durante uma sincronização regular, com exceção da sincronização inicial.

Existem muitas maneiras de lidar com a sincronização. O HAST implementa vários modos de replicação para lidar com diferentes métodos de sincronização:

  • memsync: Este modo reporta uma operação de gravação como concluída quando a operação de gravação local é finalizada e quando o nó remoto reconhece a chegada dos dados, mas antes de realmente armazenar os dados. Os dados no nó remoto serão armazenados diretamente após o envio da confirmação. Este modo destina-se a reduzir a latência, mas ainda fornece boa confiabilidade. Este modo é o padrão.

  • fullsync: Este modo relata uma operação de gravação como concluída quando a gravação local e a gravação remota são concluídas. Este é o modo de replicação mais seguro e mais lento.

  • async: Este modo relata uma operação de gravação como concluída quando a gravação local é concluída. Este é o modo de replicação mais rápido e mais perigoso. Ele deve ser usado somente ao replicar para um nó distante, onde a latência é muito alta para outros modos.

17.14.2. Configuração do HAST

O framework HAST consiste em vários componentes:

  • O daemon hastd(8) que fornece sincronização de dados. Quando este daemon é iniciado, ele carregará automaticamente geom_gate.ko.

  • O utilitário de gerenciamento de usuário, hastctl(8).

  • O arquivo de configuração hast.conf(5). Este arquivo deve existir antes de iniciar o hastd.

Usuários que preferem construir estaticamente o suporte a GEOM_GATE no kernel devem adicionar esta linha ao arquivo de configuração do kernel personalizado e reconstruir o kernel usando as instruções em Capítulo 8, Configurando o kernel do FreeBSD:

options	GEOM_GATE

O exemplo a seguir descreve como configurar dois nós na operação mestre-escravo/primário-secundário usando HAST para replicar os dados entre os dois. Os nós serão chamados hasta, com um endereço IP 172.16.0.1, e hastb, com um endereço IP 172.16.0.2. Ambos os nós terão um disco rígido dedicado /dev/ad6 do mesmo tamanho para a operação HAST. O conjunto HAST, por vezes referido como um recurso ou o provedor GEOM em /dev/hast/, será chamado test.

A configuração do HAST é feita usando o arquivo /etc/hast.conf. Este arquivo deve ser idêntico nos dois nós. A configuração mais simples é:

resource test {
	on hasta {
		local /dev/ad6
		remote 172.16.0.2
	}
	on hastb {
		local /dev/ad6
		remote 172.16.0.1
	}
}

Para uma configuração mais avançada, consulte hast.conf(5).

Dica:

Também é possível usar nomes de host nas instruções remote se os hosts forem resolvidos e definidos no arquivo /etc/hosts ou no DNS local.

Uma vez que a configuração exista em ambos os nós, o conjunto HAST pode ser criado. Execute esses comandos nos dois nós para colocar os metadados iniciais no disco local e para iniciar hastd(8):

# hastctl create test
# service hastd onestart

Nota:

Não é possível usar os provedores GEOM com um sistema de arquivos existente ou converter um armazenamento existente em um pool gerenciado por HAST. Esse procedimento precisa armazenar alguns metadados no provedor e não haverá espaço suficiente disponível em um provedor existente.

Um nó HAST primário ou secundário é selecionado por um administrador, ou software como Heartbeat, usando hastctl(8). No nó primário, hasta, execute este comando:

# hastctl role primary test

Execute este comando no nó secundário, hastb:

# hastctl role secondary test

Verifique o resultado executando hastctl em cada nó:

# hastctl status test

Verifique a linha status na saída. Se disser degraded, algo está errado com o arquivo de configuração. Ele deve dizer complete em cada nó, o que significa que a sincronização entre os nós foi iniciada. A sincronização é concluída quando hastctl status relata 0 bytes de extensões sujas.

O próximo passo é criar um sistema de arquivos no provedor GEOM e montá-lo. Isso deve ser feito no nó primário. A criação do sistema de arquivos pode levar alguns minutos, dependendo do tamanho do disco rígido. Este exemplo cria um sistema de arquivos UFS em /dev/hast/test :

# newfs -U /dev/hast/test
# mkdir /hast/test
# mount /dev/hast/test /hast/test

Uma vez que o framework HAST esteja configurado corretamente, o passo final é garantir que o HAST seja iniciado automaticamente durante a inicialização do sistema. Adicione esta linha ao /etc/rc.conf:

hastd_enable="YES"

17.14.2.1. Configuração de Failover

O objetivo deste exemplo é construir um sistema de armazenamento robusto que seja resistente à falha de qualquer nó. Se o nó primário falhar, o nó secundário estará lá para assumir o controle, verificar e montar o sistema de arquivos e continuar a trabalhar sem perder um único bit de dados.

Para realizar essa tarefa, o Protocolo de Redundância de Endereços Comuns (CARP) é usado para fornecer failover automático na camada IP. O CARP permite que vários hosts no mesmo segmento de rede compartilhem um endereço IP. Configure o CARP em ambos os nós do cluster de acordo com a documentação disponível em Seção 31.10, “Protocolo Comum de Redundância de Endereços (CARP)”. Neste exemplo, cada nó terá seu próprio endereço de gerenciamento IP e um endereço IP compartilhado de 172.16.0.254. O nó principal HAST do cluster deve ser o nó mestre CARP.

O pool HAST criado na seção anterior está agora pronto para ser exportado para os outros hosts da rede. Isso pode ser feito exportando-o através do NFS ou Samba, usando o endereço IP 172.16.0.254 compartilhado. O único problema que permanece não resolvido é um failover automático caso o nó primário falhe.

Caso as interfaces do CARP subam ou desçam, o sistema operacional FreeBSD gera um evento devd(8), tornando possível observar mudanças de estado nas interfaces do CARP. Uma alteração de estado na interface CARP é uma indicação de que um dos nós falhou ou voltou a ficar online. Esses eventos de mudança de estado tornam possível executar um script que manipulará automaticamente o failover HAST.

Para capturar mudanças de estado nas interfaces do CARP, adicione esta configuração ao /etc/devd.conf em cada nó:

notify 30 {
	match "system" "IFNET";
	match "subsystem" "carp0";
	match "type" "LINK_UP";
	action "/usr/local/sbin/carp-hast-switch master";
};

notify 30 {
	match "system" "IFNET";
	match "subsystem" "carp0";
	match "type" "LINK_DOWN";
	action "/usr/local/sbin/carp-hast-switch slave";
};

Nota:

Se os sistemas estiverem executando o FreeBSD 10 ou superior, substitua carp0 pelo nome da interface configurada CARP.

Reinicie o devd(8) em ambos os nós para colocar a nova configuração em vigor:

# service devd restart

Quando o estado da interface especificada é alterado subindo ou descendo, o sistema gera uma notificação, permitindo que o subsistema devd(8) execute o script de failover automático especificado, /usr/local/sbin/carp-hast-switch . Para maiores esclarecimentos sobre esta configuração, consulte devd.conf(5).

Aqui está um exemplo de um script de failover automatizado:

#!/bin/sh

# Original script by Freddie Cash <fjwcash@gmail.com>
# Modified by Michael W. Lucas <mwlucas@BlackHelicopters.org>
# and Viktor Petersson <vpetersson@wireload.net>

# The names of the HAST resources, as listed in /etc/hast.conf
resources="test"

# delay in mounting HAST resource after becoming master
# make your best guess
delay=3

# logging
log="local0.debug"
name="carp-hast"

# end of user configurable stuff

case "$1" in
	master)
		logger -p $log -t $name "Switching to primary provider for ${resources}."
		sleep ${delay}

		# Wait for any "hastd secondary" processes to stop
		for disk in ${resources}; do
			while $( pgrep -lf "hastd: ${disk} \(secondary\)" > /dev/null 2>&1 ); do
				sleep 1
			done

			# Switch role for each disk
			hastctl role primary ${disk}
			if [ $? -ne 0 ]; then
				logger -p $log -t $name "Unable to change role to primary for resource ${disk}."
				exit 1
			fi
		done

		# Wait for the /dev/hast/* devices to appear
		for disk in ${resources}; do
			for I in $( jot 60 ); do
				[ -c "/dev/hast/${disk}" ] && break
				sleep 0.5
			done

			if [ ! -c "/dev/hast/${disk}" ]; then
				logger -p $log -t $name "GEOM provider /dev/hast/${disk} did not appear."
				exit 1
			fi
		done

		logger -p $log -t $name "Role for HAST resources ${resources} switched to primary."


		logger -p $log -t $name "Mounting disks."
		for disk in ${resources}; do
			mkdir -p /hast/${disk}
			fsck -p -y -t ufs /dev/hast/${disk}
			mount /dev/hast/${disk} /hast/${disk}
		done

	;;

	slave)
		logger -p $log -t $name "Switching to secondary provider for ${resources}."

		# Switch roles for the HAST resources
		for disk in ${resources}; do
			if ! mount | grep -q "^/dev/hast/${disk} on "
			then
			else
				umount -f /hast/${disk}
			fi
			sleep $delay
			hastctl role secondary ${disk} 2>&1
			if [ $? -ne 0 ]; then
				logger -p $log -t $name "Unable to switch role to secondary for resource ${disk}."
				exit 1
			fi
			logger -p $log -t $name "Role switched to secondary for resource ${disk}."
		done
	;;
esac

Em poucas palavras, o script executa essas ações quando um nó se torna mestre:

  • Promove o pool de HAST para primário no outro nó.

  • Verifica o sistema de arquivos no pool HAST.

  • Monta o pool.

Quando um nó se torna secundário:

  • Desmonta o conjunto HAST.

  • Degrada o pool HAST para secundário.

Cuidado:

Este é apenas um script de exemplo que serve como prova de conceito. Ele não manipula todos os cenários possíveis e pode ser estendido ou alterado de qualquer forma, por exemplo, para iniciar ou interromper os serviços necessários.

Dica:

Para este exemplo, foi utilizado um sistema de arquivos padrão UFS. Para reduzir o tempo necessário para a recuperação, é possível usar um sistema de arquivos UFS ou ZFS com journal ativado.

Informações mais detalhadas com exemplos adicionais podem ser encontradas em http://wiki.FreeBSD.org/HAST.

17.14.3. Solução de problemas

O HAST geralmente deve funcionar sem problemas. No entanto, como acontece com qualquer outro produto de software, pode haver momentos em que ele não funciona como deveria. As origens dos problemas podem ser diferentes, mas a regra geral é garantir que o horário esteja sincronizado entre os nós do cluster.

Quando estiver fazendo troubleshooting no HAST, o nível de depuração de hastd(8) deve ser aumentado iniciando hastd com -d. Esse argumento pode ser especificado várias vezes para aumentar ainda mais o nível de depuração. Considere também usar -F, que inicia o hastd em primeiro plano.

17.14.3.1. Recuperando-se da Condição de Split-brain

Split-brain ocorre quando os nós do cluster não conseguem se comunicar entre si e ambos são configurados como primários. Esta é uma condição perigosa porque permite que ambos os nós façam alterações incompatíveis nos dados. Esse problema deve ser corrigido manualmente pelo administrador do sistema.

O administrador deve decidir qual nó tem alterações mais importantes ou executar a mesclagem manualmente. Então, deixe o HAST executar a sincronização completa do nó que possui os dados quebrados. Para fazer isso, emita esses comandos no nó que precisa ser ressincronizado:

# hastctl role init test
# hastctl create test
# hastctl role secondary test

All FreeBSD documents are available for download at https://download.freebsd.org/ftp/doc/

Questions that are not answered by the documentation may be sent to <freebsd-questions@FreeBSD.org>.
Send questions about this document to <freebsd-doc@FreeBSD.org>.