A Famosa qdisc CBQ :: Admirável Mundo Novo




Muito Bem Vindo

Prezado Leitor, a proposta desse Blog é compartilhar conhecimento com as pessoas que trabalham com Linux, Asterisk, OpenSER, e com tecnologia de voz sobre a rede IP em geral, através de tutoriais, dicas, howto, notícias entre outros assuntos.

Atente para termo de uso do conteúdo do blog no rodapé da página.

terça-feira, 6 de janeiro de 2009

A Famosa qdisc CBQ




9.5.4. A Famosa qdisc CBQ

Como dito antes, a CBQ é a qdisc disponível mais complexa, a mais exagerada, a última entendida, e provavelmente aquela mais enganadora para se implementar corretamente. Isso não é porque os autores sejam dementes ou incompetentes, longe disso, é justamente porque o algoritmo CBQ não é totalmente preciso e ele realmente não bate bem com na forma como o Linux funciona.

Além de ser classfull, o CBQ também é um shape-ador e é nesse aspecto que ele justamente não funciona muito bem. Ele funciona quase parecido. Se você tentar atrasar/descartar uma conexão 10mbit/s para 1mbit/s, o link ficaria ocioso 90% do tempo. Se não for, precisamos estrangular de sorte que ele FICA ocioso 90% do tempo.

Isso na prática é difícil de medir, assim alternativamente o CBQ deriva o tempo ocioso do número de microssegundos que transcorre entre requisições da camada de hardware por mais dados. Combinado, isso pode ser usado para aproximar quando o link estiver cheio ou vazio.

Isso é especialmente torturante e nem sempre se obtém resultados satisfatórios. Por exemplo, o que acontece com o link se a velocidade real de uma interface que não seja realmente capaz de transmitir precisamente os 100mbit/s de dados, possivelmente devido a um driver mal implementado? Um cartão de rede PCMCIA nunca alcançará também 100mbit/s devido à forma como o barramento é projetado – novamente, como calcularemos o tempo ocioso?

Isso é de fato péssimo se considerarmos dispositivos de rede não inteiramente real como PPP sobre Ethernet ou PPTP sobre TCP/IP. A banda efetiva nesse caso é provavelmente determinada pela eficiência de pipes com o espaço de usuário – o qual é enorme.

Pessoas que fizeram medidas descobriram que o CBQ nunca é preciso e às vezes perde totalmente o objetivo.

Em muitas circunstâncias, no entanto, ele funciona bem. Com a documentação fornecida aqui, você deve ser capaz de configurá-lo para funcionar bem em muitos casos.


9.5.4.1. Gerenciamento de banda em detalhe com o CBQ

Como já dito antes, o CBQ funciona assegurando que o link fique ocioso por um período de tempo suficiente longo justamente para forçar a queda da banda real para deixá-lo na taxa configurada. Para conseguir isso, ele calcula o tempo que deve decorrer entre a média de pacotes.

Durante as operações, o tempo ocioso efetivo é medido usando uma média de movimentação exponencial ponderada (EWMA), que considera pacotes recentes a fim de seja exponencialmente mais importante do que aqueles que passaram. O loadaverage do UNIX é calculado da mesma forma.

O tempo ocioso calculado é subtraído daquela EWMA medida, o número resultante é chamado ‘avgidle’. Um link perfeitamente carregado possui um avgidle zero: pacotes chegam exatamente uma vez em cada intervalo calculado.

Um link sobrecarregado possui um avgidle negativo e se ele ficar muito negativo, o CBQ derruba-o por um tempo e atinge então o ‘overlimit’.

Reciprocamente, um link ocioso pode juntar uma grande avgidle, que então permitiria largura de banda infinita após algumas horas de silêncio. Para evitar isso, o avgidle é igualado a maxidle.

Se existir overlimit, na teoria, o CBQ pode estrangula-se exatamente pela quantidade de tempo que foi calculado transcorrer entre pacotes, e depois passar um pacote, e estrangular novamente. Mas veja o parâmetro ‘minburst’ abaixo.

Esses são parâmetros que você pode especificar a fim de configurar o atraso/descarte/re-escalona (shaping):

avpkt

Tamanho médio de um pacote, medido em bytes. Necessário para calcular maxidle, que é derivado de maxburst, que é especificado nos pacotes.



bandwidth

A largura de banda física de seu dispositivo, necessário para calcular o tempo ocioso.



cell

O tempo que um pacote gasta para ser transmitido por um dispositivo que pode crescer nas etapas, baseado no tamanho do pacote. Um tamanho com pacote de 800 e 806 pode levar justamente bastante tempo para enviar, por exemplo – isso define a granularidade. Mais frequentemente definido como ‘8’. Precisa ser um número inteiro potência de dois.



maxburst

Esse número de pacotes é usado para calcular maxidle de sorte que quando avgidle estiver em maxidle, esse número de pacotes médios pode ser disparados antes de avgidle cair pra 0. Defina-o maior para ser mais tolerante a rajadas. Você não pode definir maxidle diretamente, somente através desse parâmetro.



minburst

Como mencionado antes, o CBQ precisa estrangular no caso de overlimit. A solução ideal é fazer assim exatamente para o tempo ocioso calculado, e passa 1 pacote. Para kernels UNIX, contudo, é geralmente difícil escalonar eventos menores do que 10ms, portanto é melhor estrangular por um período mais longo, e depois passar minburst pacotes de vez, e depois dormir por tempos minburst mais longos.

O tempo a esperar é chamado de offtime. Valores mais altos de 'minburst' levam ajustes mais preciso por tempo mais longo, mas para grandes rajadas na escala de tempo de milissegundos.



minidle

Se o 'avgidle' ficar abaixo de 0, atingiremos o overlimits e é preciso esperar até que 'avgidle' venha a ficar suficientemente grande para enviar um pacote. Para evitar uma rajada repentina a partir do instante do estrangulamento do link por um período de tempo prolongado, 'avgidle' é ressetado para 'minidle' se ele vier a ficar muito baixo.

O parâmetro 'minidle' é especificado em microssegundos com sinal negativo, assim 10 significa que 'avgidle' é igual a -10us.



mpu

Tamanho mínimo de pacote – necessário porque mesmo um pacote com tamanho zero é preenchido com 64bytes na Ethernet, e assim leva certo tempo para transmitir. O CBQ precisa saber disso para calcular precisamente o tempo ocioso.



rate

Taxa desejada que o tráfego deixa essa qdisc – esse é ‘o botão de ajuste de velocidade’!



Internamente, o CBQ possui um monte de ajustes para conseguir uma sintonia fina. Por exemplo, classes que são conhecidas por não ter dados enfileirados não são consultadas. Classes que antigem overlimit são penalizadas baixando suas prioridades efetivas. Tudo é muito inteligente e complicado.


9.5.4.2. Comportamento Classful do CBQ

Além do gerenciamento de tráfego, o uso da abordagem de tempo ocioso supracitado, o CBQ também age igual à fila PRIO no sentido de que as classes podem ter diferentes prioridades e que números de prioridade mais baixa serão varridos antes daqueles de prioridades mais altas.

Toda vez que um pacote a ser enviado na rede é requisitado pela camada de hardware, inicia um processo cíclico ponderado (WRR), começando pelas classes numeradas com prioridade mais baixas.

Elas são então agrupadas e enfileiradas se elas tiverem dados disponíveis. Se tiver então, ela retorna. Após ser permitido des-enfileirar um número de bytes em uma classe, a próxima classe dentro dessa prioridade é testada.


Os parâmetros seguintes controlam o processo WRR:

allot

Quando é perguntado ao CBQ externo por um pacote a ser enviado sobre a interface, ele tentará todas qdiscs internas (nas classes) na seqüência, na ordem do parâmetro ‘priority’. Toda vez que uma classe consegue seu objetivo, ela pode enviar somente uma quantidade limitada de dados. O parâmetro ‘allot’ é a unidade base dessa quantidade. Veja o parâmetro ‘weight’ para mais informação.



prio

O CBQ pode também agir igual ao dispositivo PRIO. Classes internas com prioridade mais alta são testadas primeiro, contanto que elas tenham tráfego, outras classes não são verificadas para tráfego.



weight

O parâmetro weight ajuda no processamento cíclico ponderado – Weighted Round Robin (WRR). Cada classe tem uma chance na seqüência. Se você tiver classes com mais largura de banda do que outras classes significativamente, faz sentido permiti-las enviar mais dados em um único ciclo do que em outras.



Uma disciplina CBQ adiciona todos os pesos sob uma classe, e os normaliza, assim você pode usar números arbitrários: somente as taxas são importantes. As pessoas têm usado ‘rate/10’ como regra geral e isso parece funcionar bem. O peso re-normalizado é multiplicado pelo parâmetro ‘allot’ para determinar quantos dados podem ser enviados de uma só vez.

Favor observe que todas as classes em uma hierarquia CBQ precisam compartilhar o mesmo número major!


9.5.4.3. Parâmetros CBQ que determina Compartilhamento & Empréstimo do link

Além de limitar puramente certos tipos de tráfego, é possível também especificar quais classes podem tomar emprestada largura de banda de outras classes ou, inversamente, emprestar largura de banda.

isolated/sharing

Uma classe quando é configurada com ‘isolated’, ou seja, isolada, não emprestará largura de banda a classes irmãs (sibling). Use isso se você tiver ações que competem entre si ou mutuamente antagônicas sobre o seu link que não desejam se permitirem livremente.

O programa de controle tc também entende o que é ‘sharing’, ou seja, compartilhamento, o que é inverso de ‘isolated’.



bounded/borrow

Uma classe também pode ser ‘bounded’, ou seja, restringida, o que significa que ela não vai tentar tomar emprestado largura de banda de classes irmãs (sibling). O programa tc entende também o que seja ‘borrow’, ou seja, pegar emprestado, o que é inverso de ‘bounded’.



Uma situação típica pode ser quando você tem duas ações sobre o seu link as quais são ambas ‘isolated’ e ‘bounded’, o que significa que elas são realmente limitadas a suas taxas designadas, e também não se permitirão compartilhar banda.

Dentro de tal classe de agência, podem existir outras classes que são permitidas negociar largura de banda.


9.5.4.4. Configuração Exemplo


1: root qdisc
|
1:1 child class
/ \
/ \
1:3 1:4 leaf classes
| |
30: 40: qdiscs
(sfq) (sfq)


Essa configuração limita o tráfego do servidor web a 5mbit e o tráfego SMTP a 3mbit. Juntos, eles não podem conseguir mais do que 6mbit. Possuímos uma placa de rede 100mbit e as classes podem se compartilhar.

# tc qdisc add dev eth0 root handle 1:0 cbq bandwidth 100Mbit \
avpkt 1000 cell 8

# tc class add dev eth0 parent 1:0 classid 1:1 cbq bandwidth 100Mbit \
rate 6Mbit weight 0.6Mbit prio 8 allot 1514 cell 8 maxburst 20 \
avpkt 1000 bounded


Essa parte instala a ‘root qdisc’ e a classe costumeira 1:1. A classe 1:1 é restringida, assim a banda total não pode exceder 6mbit.

Como já dito, o CBQ exige muitas opções de configuração. Contudo, todos os parâmetros são explicados acima. A configuração HTB correspondente é muito mais simples.

# tc class add dev eth0 parent 1:1 classid 1:3 cbq bandwidth 100Mbit \
rate 5Mbit weight 0.5Mbit prio 5 allot 1514 cell 8 maxburst 20 \
avpkt 1000

# tc class add dev eth0 parent 1:1 classid 1:4 cbq bandwidth 100Mbit \
rate 3Mbit weight 0.3Mbit prio 5 allot 1514 cell 8 maxburst 20 \
avpkt 1000


Essas são as nossas duas classes folha. Observe como escalamos o peso com a taxa configurada. Ambas as classes não são restringidas, mas elas são conectadas a classe 1:1 que é restringida. Assim a soma de banda das 2 classes nunca será maior do que 6mbit. Os parâmetros classid´s precisão estar dentro do mesmo número major que da qdisc pai, a propósito!

# tc qdisc add dev eth0 parent 1:3 handle 30: sfq
# tc qdisc add dev eth0 parent 1:4 handle 40: sfq


Ambas as classes possuem uma qdisc FIFO por padrão. Mas nós a substituímos por uma fila SFQ de modo que cada fluxo de dados seja tratado uniformemente.

# tc filter add dev eth0 parent 1:0 protocol ip prio 1 u32 match ip \
sport 80 0xffff flowid 1:3

# tc filter add dev eth0 parent 1:0 protocol ip prio 1 u32 match ip \
sport 25 0xffff flowid 1:4


Esses comandos, diretamente atrelados ao root, enviam tráfego as qdiscs corretas.

Observe que nós usamos o comando ‘tc class add’ para CRIAR classes dentro de uma qdisc, mas usamos ‘tc qdisc add’ para adicionar realmente qdiscs a essas classes.

Você pode estar curioso sobre o que acontecerá com o tráfego que não for classificado por qualquer das duas regras. Parece que nesse caso, os dados serão então processados dentro da 1:0, e que ficarão não limitados.

Se o tráfego SMTP+Web conjuntamente tentar exceder o limite configurado de 6mbit/s, a largura de banda será dividida de acordo com o parâmetro weight, dando 5/8 do tráfego ao servidor web e 3/8 ao servidor de email.

Com essa configuração você pode também dizer que o tráfego do webserver sempre conseguirá no mínimo 5/8 * 6 mbit = 3,75 mbit.


9.5.4.5. Outros parâmetros CBQ: split & defmap

Como já dito antes, uma qdisc classful precisa chamar filtros para determinar em qual classe um pacote será enfileirado.

Além de chamar o filtro, o CBQ oferece outras opções, defmap e split. Isso é um tanto complicado para entender, porém não é algo vital. Mas como esse é o único lugar sabido onde os parâmetros defmap e split são adequadamente explicado, eu estou colaborando com o melhor que posso.

Como você normalmente desejará filtrar somente pegando o campo Tipo de Serviço (Type of Service), uma sintaxe especial é fornecida. Sempre que o CBQ precisa calcular aonde um pacote precisa ser enfileirado, ele verifica se esse nó é um ‘nó split’. Se for, uma das sub-qdiscs indicará em qual ela desejará receber todos os pacotes com a prioridade correta configurada, porque precisa ser derivado do campo TOS, ou de opções de socket definidos por aplicações.

Os bits de prioridade de pacotes são dispostos na forma de ‘and lógico’ com o campo 'defmap' para verificar se existe um 'match'. Em outras palavras, isso é um atalho para criar um filtro muito rápido, que somente bate com certas prioridades. Um 'defmap ff' (hexadecimal) vai bater com tudo, um 'defmap 0' não vai bater com nada. Um exemplo de configuração pode ajudar a tornar as coisas mais claras.

# tc qdisc add dev eth1 root handle 1: cbq bandwidth 10Mbit allot 1514 \
cell 8 avpkt 1000 mpu 64

# tc class add dev eth1 parent 1:0 classid 1:1 cbq bandwidth 10Mbit \
rate 10Mbit allot 1514 cell 8 weight 1Mbit prio 8 maxburst 20 \
avpkt 1000


Prefácio ao padrão CBQ. Eu nunca conseguir usar absolutamente a quantidade de números exigidos!


As opções defmap se referem aos bits TC_PRIO, que são definidos a seguir:


TC_PRIO.. Num Corresponde ao TOS
-------------------------------------------------
BESTEFFORT 0 Maximize Reliablity
FILLER 1 Minimize Cost
BULK 2 Maximize Throughput (0x8)
INTERACTIVE_BULK 4
INTERACTIVE 6 Minimize Delay (0x10)
CONTROL 7


O número TC_PRIO corresponde aos bits, contados a partir da direita. Veja a seção pfifo_fast para se ter mais detalhes de como os bits TOS são convertidos em prioridades.

Agora as classes de tráfego interativo e de tráfego pesado:

# tc class add dev eth1 parent 1:1 classid 1:2 cbq bandwidth 10Mbit \
rate 1Mbit allot 1514 cell 8 weight 100Kbit prio 3 maxburst 20 \
avpkt 1000 split 1:0 defmap c0

# tc class add dev eth1 parent 1:1 classid 1:3 cbq bandwidth 10Mbit \
rate 8Mbit allot 1514 cell 8 weight 800Kbit prio 7 maxburst 20 \
avpkt 1000 split 1:0 defmap 3f


A ‘qdisc split’ é 1:0, que é onde a escolha será feita. O valor c0 é o binário para 11000000, 3f para 00111111, assim essas duas juntas casarão com tudo. A primeira classe bate com os bits 7 e 6, e consequentemente vai corresponder com o tráfego ‘interativo’ e de ‘controle’. A segunda classe bate com o resto.


O nó 1:0 agora tem uma tabela igual a:


priority send to

0 1:3
1 1:3
2 1:3
3 1:3
4 1:3
5 1:3
6 1:2
7 1:2


Para distração adicional, você pode também passar um ‘change mask’, que indica exatamente quais prioridades você deseja alterar. Você somente precisa usar isso se você estiver rodando ‘tc class change’. Por exemplo, para adicionar o tráfego de melhor esforço como 1:2, nós podemos executar isso:

# tc class change dev eth1 classid 1:2 cbq defmap 01/01


O mapa de prioridade em 1:0 agora se parece com:


priority send to

0 1:2
1 1:3
2 1:3
3 1:3
4 1:3
5 1:3
6 1:2
7 1:2


CORRIJAM-ME: Não testei ‘tc class change’, somente dei uma olhada nos fontes.













Autores Originais dos textos:

Bert Hubert (Netherlabs BV)
bert.hubert@netherlabs.nl

Thomas Graf (Autor de Seção)
tgraf@suug.ch

Gregory Maxwell (Autor de Seção)
greg@linuxpower.cx

Remco van Mook (Autor de Seção)
remco@virtu.nl

Martijn van Oosterhout (Autor de Seção)
kleptog@cupid.suninternet.com

Paul B Schroeder (Autor de Seção)
paulsch@us.ibm.com

Jasper Spaans (Autor de Seção)
jasper@spaans.ds9a.nl

Pedro Larroy (Autor de Seção)
piotr@member.fsf.org









Nenhum comentário:




Creative Commons License
Admirável Mundo Novo: Tudo Sobre Asterisk, OpenSER, Linux e Tecnologias de Voz sobre IP
by Cléviton Mendes de Araújo is licensed under a Creative Commons Atribuição 2.5 Brasil License.