← CCNP Enterprise: núcleo ENCOR e operação
15 / 17 · 55 MIN

QoS: bursts, filas e orçamento de atraso

Calcula conformidade de bursts e espera em fila, identificando os limites de cada modelo.

Taxa média e burst são dimensões distintas

O primeiro modelo usa um policer com um único token bucket, inicialmente cheio, reposição contínua e descarte de pacotes inteiros quando faltam tokens. A taxa é 8 000 000 bits/s, equivalente a 1 000 bytes por milissegundo, e o bucket tem 2 000 bytes. Quatro pacotes de 1 000 bytes chegam no instante zero. Os dois primeiros encontram crédito; os outros dois são descartados. Um quinto pacote chega aos 10 ms e encontra o bucket novamente cheio. A média destes 5 000 bytes numa janela de 10 ms é 4 Mb/s, abaixo de 8 Mb/s, mas essa média não descreve a pressão do burst inicial.

Caso: uma fila resolve perdas mas viola atraso

O segundo modelo é uma fila FIFO a taxa fixa de 8 Mb/s, sem crédito de burst. Não pretende reproduzir um shaper específico da Cisco. Cada pacote de 1 000 bytes demora 1 ms a ser servido. Com capacidade de 4 000 bytes, os quatro pacotes iniciais entram e terminam aos 1, 2, 3 e 4 ms; o quarto espera 3 ms antes de ser servido. Com capacidade de 2 000 bytes, os dois últimos do burst são descartados. A capacidade inclui o pacote em serviço, e transmissões concluídas no instante t libertam espaço antes das chegadas nesse instante. O resultado depende destes pressupostos explícitos.

Policing, shaping e capacidade finita

Policing pode descartar ou remarcar excesso conforme a ação configurada; o nosso modelo implementa apenas descarte. Shaping usa espera e scheduling para controlar saída, mas a fila é finita e pode perder pacotes. Não concluas que qualquer shaping elimina perdas ou que qualquer policer tem o mesmo comportamento de um único bucket. Depois de um longo período sem tráfego, o crédito do modelo continua limitado a 2 000 bytes. Um pacote de 3 000 bytes nunca cabe nesse bucket, mesmo após esperar. Em produção, confirma taxa, burst, unidades, ações e contabilização de overhead da implementação antes de escolher uma alteração.

Um excesso sustentado não cabe num pequeno orçamento

Num modelo fluido separado, entram 150 Mb/s e saem 100 Mb/s durante 200 ms. Sem perdas nem reação dos emissores, acumulam-se 1 250 000 bytes. Se as chegadas pararem nesse momento, a drenagem demora 100 ms a 100 Mb/s. Mantendo o excesso durante 20 segundos, a acumulação seria 125 000 000 bytes e a drenagem 10 segundos. Estes cálculos usam unidades decimais e não incluem overhead, TCP ou capacidade finita. Aumentar a fila pode absorver um burst breve, mas não cria capacidade para uma carga persistentemente superior ao serviço. Para APS, relaciona o limite de atraso com a janela de batch e as transações concorrentes.

Reproduzir e comparar com a rede real

Guarda o script completo abaixo como simulate.py e executa python3 simulate.py /tmp/qos-evidence.json. Só usa a biblioteca padrão Python e grava resultados locais; não acede à rede. Duas execuções foram verificadas com 19 asserções cada. Modifica uma variável de cada vez: tamanho do bucket, capacidade da FIFO, intervalo entre chegadas ou duração do excesso. Antes de transportar uma conclusão para um projeto, recolhe medições de bursts, drops, atraso e classificação na plataforma real. O modelo não contém TCP, overhead, várias filas, prioridade ou o scheduler de um fabricante. Um valor calculado não é um SLA medido nem uma configuração aprovada para produção.

# Save as simulate.py; run: python3 simulate.py /tmp/qos-evidence.json
"""Original didactic models. No network/device access or Cisco scheduler emulation."""
from collections import deque
from fractions import Fraction
import datetime,hashlib,json,pathlib,sys

def inputs(arrivals,rate_bps,capacity):
    if rate_bps<=0 or capacity<=0:raise ValueError('Positive rate and capacity required')
    previous=Fraction(0)
    for ms,size in arrivals:
        if ms<previous or ms<0 or size<=0:raise ValueError('Ordered nonnegative times and positive sizes required')
        previous=Fraction(ms)

def police(arrivals,rate_bps,bucket_bytes):
    """One bucket, initially full, continuous refill, whole-packet exceed drop."""
    inputs(arrivals,rate_bps,bucket_bytes);rate=Fraction(rate_bps,8000)
    tokens=Fraction(bucket_bytes);last=Fraction(0);rows=[]
    for index,(ms,size) in enumerate(arrivals):
        at=Fraction(ms);tokens=min(Fraction(bucket_bytes),tokens+(at-last)*rate);before=tokens
        admitted=tokens>=size
        if admitted:tokens-=size
        rows.append({'packet':index+1,'arrivalMs':float(at),'bytes':size,'tokensBefore':float(before),'admitted':admitted,'tokensAfter':float(tokens)})
        last=at
    return rows

def fifo(arrivals,rate_bps,capacity_bytes):
    """Fixed-rate FIFO serializer; capacity includes the packet in service.
    Completions at time t free capacity before arrivals at t. No token credit.
    """
    inputs(arrivals,rate_bps,capacity_bytes);pending=deque();last_finish=Fraction(0);rows=[]
    for index,(ms,size) in enumerate(arrivals):
        at=Fraction(ms)
        while pending and pending[0][0]<=at:pending.popleft()
        used=sum(s for _,s in pending);admitted=used+size<=capacity_bytes
        row={'packet':index+1,'arrivalMs':float(at),'bytes':size,'occupiedBytesBefore':used,'admitted':admitted}
        if admitted:
            start=max(at,last_finish);finish=start+Fraction(size*8000,rate_bps)
            pending.append((finish,size));last_finish=finish
            row.update(startMs=float(start),finishMs=float(finish),waitMs=float(start-at),totalMs=float(finish-at))
        rows.append(row)
    return rows

def match(criteria,mode):
    if not criteria or mode not in ['any','all']:raise ValueError('Nonempty criteria and any/all mode required')
    return any(criteria) if mode=='any' else all(criteria)

def backlog(arrival_bps,service_bps,duration_ms):
    if arrival_bps<0 or service_bps<=0 or duration_ms<0:raise ValueError('Invalid rate or duration')
    queued=max(Fraction(0),Fraction((arrival_bps-service_bps)*duration_ms,8000))
    return {'queuedBytes':float(queued),'drainMsIfArrivalsStop':float(queued*8000/service_bps)}

def run():
    checks=[]
    def verify(name,condition):
        if not condition:raise AssertionError(name)
        checks.append(name)
    arrivals=[(0,1000),(0,1000),(0,1000),(0,1000),(10,1000)]
    policed=police(arrivals,8_000_000,2000);wide=fifo(arrivals,8_000_000,4000);small=fifo(arrivals,8_000_000,2000)
    verify('full bucket admits first two burst packets',[x['admitted']for x in policed]==[True,True,False,False,True])
    verify('dropped packets do not consume unavailable tokens',policed[2]['tokensAfter']==policed[3]['tokensAfter']==0)
    verify('idle refill is capped at bucket size',policed[4]['tokensBefore']==2000)
    verify('four-kilobyte FIFO admits entire input',all(x['admitted']for x in wide))
    verify('FIFO exposes increasing burst wait',[x['waitMs']for x in wide]==[0,1,2,3,0])
    verify('FIFO completion includes one millisecond serialization',[x['finishMs']for x in wide]==[1,2,3,4,11])
    verify('two-kilobyte FIFO drops excess burst packets',[x['admitted']for x in small]==[True,True,False,False,True])
    oversized=police([(1000,3000)],8_000_000,2000)
    verify('packet larger than bucket cannot conform even after idle',not oversized[0]['admitted'])
    continuous=police([(0,1000),(1,1000),(2,1000)],8_000_000,1000)
    verify('one packet per millisecond conforms at eight megabits',all(x['admitted']for x in continuous))
    equality=fifo([(0,1000),(1,1000)],8_000_000,1000)
    verify('same-time completion frees queue space before arrival',all(x['admitted']for x in equality))
    fractional=fifo([(0,700)],8_000_000,1000)
    verify('serialization preserves sub-millisecond result',fractional[0]['finishMs']==0.7)
    classification=[{'dscpEF':a,'authorizedSource':b,'matchAny':match([a,b],'any'),'matchAll':match([a,b],'all')}for a,b in [(False,False),(False,True),(True,False),(True,True)]]
    verify('any accepts either criterion',[x['matchAny']for x in classification]==[False,True,True,True])
    verify('all requires both criteria',[x['matchAll']for x in classification]==[False,False,False,True])
    short=backlog(150_000_000,100_000_000,200);long=backlog(150_000_000,100_000_000,20_000)
    verify('short excess creates 1.25 MB backlog',short=={'queuedBytes':1250000.0,'drainMsIfArrivalsStop':100.0})
    verify('twenty-second excess creates 125 MB backlog',long=={'queuedBytes':125000000.0,'drainMsIfArrivalsStop':10000.0})
    verify('no positive backlog when service exceeds arrival',backlog(80_000_000,100_000_000,200)['queuedBytes']==0)
    for label,args in [('negative time',[(-1,1000)]),('unordered times',[(2,1000),(1,1000)]),('zero packet',[(0,0)])]:
        try:police(args,8_000_000,2000)
        except ValueError:checks.append('rejects '+label)
        else:raise AssertionError(label)
    return {'checkedAt':datetime.datetime.now(datetime.timezone.utc).isoformat(),'scriptSha256':hashlib.sha256(pathlib.Path(__file__).read_bytes()).hexdigest(),'checks':checks,'inputs':{'rateBps':8000000,'bucketBytes':2000,'arrivals':arrivals},'policer':policed,'fifo4000':wide,'fifo2000':small,'oversized':oversized,'classification':classification,'fluidBacklog':{'short':short,'long':long},'assumptions':['Original deterministic teaching models, not IOS XE execution or physical measurements','Decimal rates: bps means bits/second; queue/bucket sizes mean bytes','Policer: one initially full bucket, continuous refill, drop when a whole packet cannot conform, no remarking','FIFO: fixed service rate without token credit or priority; capacity includes in-service packet; same-time departures happen first','Fluid backlog: constant offered and service rates, no feedback or losses; drain time assumes arrivals stop','No TCP dynamics, packet overhead, vendor scheduler, microburst capture or SLA measurement']}

if __name__=='__main__':
    report=run();pathlib.Path(sys.argv[1]).write_text(json.dumps(report,indent=2)+'\n')
    print(json.dumps({'checks':len(report['checks']),'modelOnly':True,'networkAccess':False}))
NA PRÁTICA

No modelo de 8 Mb/s, quatro pacotes de 1 000 bytes precisam de 4 ms de serviço; uma fila maior não reduz esse trabalho.

Armadilhas comuns

Bits confundidos com bytes; média como prova de ausência de bursts; fila infinita presumida; simulação como medição de hardware.

Tópicos relacionados: QoS: classificação, confiança e contratos · Arquitetura e capacidade sobrevivente

Leva esta ideia contigo

Explicita unidades e pressupostos, e aceita perdas e atraso com evidência que corresponda ao serviço.

Criar conta

Referência: Compare Traffic Policing and Traffic Shaping to Limit Bandwidth · 350-401 ENCOR v1.2, effective 2026-03-19; core component of CCNP Enterprise

CCNP® e Cisco® são marcas registadas da Cisco Systems, Inc. e/ou das suas afiliadas. A dr.pt é uma plataforma de preparação independente e não está afiliada, associada, patrocinada, autorizada nem aprovada por Cisco. Os conteúdos e as perguntas são originais, não são perguntas oficiais de exame, e concluir os nossos testes não atribui nem garante qualquer certificação. Os nomes são usados apenas para identificar o tema. Todas as outras marcas pertencem aos respetivos titulares.