Balanceamento de carga round-robin por pacote para UDP

4

Eu preciso equilibrar o tráfego UDP entre um número de "servidores reais" e fazê-lo de uma forma verdadeiramente round-robin. Eu comecei com keepalived, mas inesperadamente descobri, que o LVS trata o tráfego UDP como uma "conexão" (o que quer que seja em termos de UDP ...). Na prática, isso significa que todo o tráfego de um determinado cliente vai para o mesmo "servidor real" o tempo todo (isso é um grande problema, porque alguns clientes podem gerar uma quantidade tão grande de tráfego, que o back-end único ficará sobrecarregado) .

Aparentemente, isso é um comportamento esperado, mas versões mais recentes do LVS têm um sinalizador "--ops", o que faz com que o LVS ignore seu comportamento acima mencionado, de forma que cada datagrama UDP seja tratado independentemente (isso é o que Eu quero!). Mas (sempre existe um, mas ..) essa funcionalidade não é exposta a partir do keepalived.conf.

Existe alguma solução lá fora, que vai me deixar

  • faça uma distribuição round-robin entre back-ends para UDP
  • detectar backends "mortos" e removê-los do round-robin (adicioná-los novamente quando eles se tornarem "vivos" também seria útil)

Deve ser baseado no Linux, obviamente. O round-robin de DNS, de qualquer forma, não funcionará realmente aqui, porque os clientes não estão cientes do DNS.

P.S. Eu vou tentar o pulso / piranha, mas lendo a documentação que eu juntei, ele não expõe o sinalizador "--ops" também. Eu também vou dar mon uma tentativa (faça mon verificar backends e adicionar / remover servidores reais invocando ipvsadm diretamente).

    
por shylent 27.04.2013 / 21:00

2 respostas

5

O requisito foi satisfeito da seguinte forma:

Instalei uma versão mais recente do ipvsadm (e seus módulos do kernel), a que suporta o --ops flag (1.26). Como o keepalived não expõe esse sinalizador em seu arquivo de configuração, você deve aplicá-lo manualmente. Felizmente, você pode fazer isso depois que o "serviço virtual" for criado (em termos de ipvsadm simples, você pode primeiro ipvsam -A um serviço virtual sem --ops e ipvsadm -E para adicionar um agendamento de pacotes).

Como o keepalived cria o serviço virtual para você, tudo o que você precisa fazer é editá-lo depois de criado, o que acontece quando o quorum é obtido para esse servidor virtual (basicamente, há um número suficiente de servidores reais em funcionamento). Veja como fica no arquivo keepalived.conf :

virtual_server <VIP> <VPORT> {
    lb_algo rr
    lb_kind NAT
    protocol UDP
    ...

    # Enable one-packet scheduling when quorum is gained
    quorum_up "ipvsadm -E -u <VIP>:<VPORT> --ops -s rr"

    ... realserver definitions, etc ...
}

Isso funciona, mas eu encontrei vários problemas (tipo de) com essa configuração:

  1. Há um pequeno intervalo de tempo (menos de um segundo, mais como 1/10), entre o quorum subindo e o script em quorum_up sendo executado. Quaisquer datagramas que consigam passar pelo diretor durante esse tempo criarão uma entrada de conexão no ipvsadm e os datagramas adicionais desse host / porta de origem ficarão presos no mesmo servidor real mesmo depois que o sinalizador --ops for adicionado . Você pode minimizar a chance de isso acontecer, certificando-se de que o serviço virtual nunca seja excluído depois de criado. Você faz isso especificando inhibit_on_failure flag em suas definições de servidor real para que elas não sejam excluídas quando o servidor real correspondente estiver inativo (quando todos os servidores reais forem excluídos, o serviço virtual também será excluído), mas seu peso será definido como zero (eles parar de receber tráfego então). Como resultado, o único tempo que os datagramas podem passar é durante a inicialização do keepalive (supondo que você tenha pelo menos um servidor real ativo naquele momento para que o quorum seja obtido imediatamente).
  2. Quando --ops está ativo, o diretor não reescreve o host / porta de origem dos datagramas, que os servidores reais enviam aos clientes para que o host / porta de origem sejam os do servidor real, que enviou esse datagrama específico. Isso pode ser um problema (era para os clientes meus ). Você pode alterar isso por SNAT 'desses datagramas com iptables.
  3. Eu notei uma carga significativa na CPU do sistema quando o diretor está sob carga. Acontece que a CPU está sobrecarregada pelo ksoftirqd. Isso não acontece se você desativar --ops . Presumivelmente, o problema é que o algoritmo de despacho de pacotes é acionado em cada datagrama, em vez de apenas o primeiro datagrama na "conexão" (se isso se aplica ao UDP ...). Eu realmente não encontrei o caminho para "consertar" isso, mas talvez eu não tenha tentado o suficiente. O sistema tem alguns requisitos de carga específicos e, sob essa carga, o uso do processador não atinge o máximo, nem há datagramas perdidos, portanto, esse problema não é considerado um show-stopper. Ainda é bastante alarmante embora.

Resumo: a configuração definitivamente funciona (também sob carga), mas os aros que se tem que pular e os problemas que eu encontrei (especialmente №3 .. talvez alguém sabe a solução?) significa que, dado o tempo, Eu teria usado um programa de espaço do usuário (escrito em C, provavelmente) para escutar em um soquete UDP e distribuir os datagramas recebidos entre servidores reais em conjunto com algo, que verificaria a integridade dos servidores reais para mim, SNAT in iptables para reescrever o host / porta de origem e keepalived no modo VRRP para HA.

    
por 24.05.2013 / 12:12
1

Deve haver uma maneira de fazer isso com o roteamento de caminhos múltiplos ....

O load-balancer e o realserver compartilham IPs em uma sub-rede (10.0.0 / 24). Para ambos os servidores reais, você adiciona o mesmo IP, de outra sub-rede, como secundário para a interface de loopback (172.16.1.1/32). É nesse endereço que seu serviço vai ouvir.

                              +-------------------------------------+
                         +----|A: eth0:10.0.0.2/24 lo:172.16.1.1/32 |
+--------------------+   |    +-------------------------------------+
|LB eth0:10.0.0.1/24 |---|
+--------------------+   |    +-------------------------------------+
                         +----|B: eth0:10.0.0.3/24 lo:172.16.1.1/32 |
                              +-------------------------------------+

e depois você pode usar:

 ip route add 172.16.1.1/32 nexthop via 10.0.0.2 nexthop via 10.0.0.3

Mas até agora a boa notícia: os kernels Linux aparentemente recentes armazenam em cache as rotas para que os pacotes da mesma fonte fiquem no mesmo destino. Existem alguns patches para desabilitar esse comportamento, mas todos parecem ser para kernels mais antigos (como o patch de equalização multipath para o kernel 2.4, mpath em 2.6). Talvez uma pesquisa mais completa possa encontrar um patch de trabalho para um kernel recente.

O failover que você pode perceber facilmente executando o CARP para 10.0.0.2 e 10.0.0.3. Então, o B assume o 10.0.0.2 quando o A desce.

    
por 28.04.2013 / 22:31