2009-07-17 6 views
2

J'essaye de limiter mon taux d'envoi d'application à 900kbps mais le problème est que le protocole que j'utilise est orienté message et que les messages ont des tailles très différentes. Je peux avoir des messages de 40 octets jusqu'à 125000 octets et tous les messages sont envoyés comme unités atomiques.Seau à jetons ou seau fuyard pour les messages

J'ai essayé d'implémenter un tampon de seau de jetons mais si je définis une taille de seau faible, les gros paquets ne seront jamais envoyés et un seau plus grand produira une grande salve sans aucune limitation de débit.

Ceci est ma petite implémentation en C:

typedef struct token_buffer { 
    size_t capacity; 
    size_t tokens; 
    double rate; 
    uint64_t timestamp; 

} token_buffer; 


static uint64_t time_now() 
{ 
    struct timeval ts; 
    gettimeofday(&ts, NULL); 
    return (uint64_t)(ts.tv_sec * 1000 + ts.tv_usec/1000); 
} 

static int token_buffer_init(token_buffer *tbf, size_t max_burst, double rate) 
{ 
    tbf->capacity = max_burst; 
    tbf->tokens = max_burst; 
    tbf->rate = rate; 
    tbf->timestamp = time_now(); 
} 

static size_t token_buffer_consume(token_buffer *tbf, size_t bytes) 
{ 
    // Update the tokens 
    uint64_t now = time_now(); 
    size_t delta = (size_t)(tbf->rate * (now - tbf->timestamp)); 
    tbf->tokens = (tbf->capacity < tbf->tokens+delta)?tbf->capacity:tbf->tokens+delta; 
    tbf->timestamp = now; 

    fprintf(stdout, "TOKENS %d bytes: %d\n", tbf->tokens, bytes); 

    if(bytes <= tbf->tokens) { 
    tbf->tokens -= bytes; 
    } else { 
    return -1; 
    } 

    return 0; 
} 

Ensuite, quelque part dans le principal():

while(1) { 
    len = read_msg(&msg, file); 

    // Loop until we have enough tokens. 
    // if len is larger than the bucket capacity the loop never ends. 
    // if the capacity is too large then no rate limit occurs. 
    while(token_buffer_consume(&tbf,msg, len) != 0) {} 

    send_to_net(&msg, len); 
} 

Répondre

2

Vous limitez votre taille maximale des messages par max_burst (qui obtient affecté à tbf-> capacité au début) - puisque les jetons tbf-> n'augmente jamais au-delà de cette valeur, les plus gros messages ne seront jamais envoyés à cause de cette vérification:

if(bytes <= tbf->tokens) { 
    tbf->tokens -= bytes; 
    } else { 
    return -1; 
    } 

Donc, le code définit en effet une limite stricte sur burst à max_burst - vous devriez donc fragmenter vos messages si vous voulez cette taille de rafale.

En supposant qu'il est le seul endroit dans le code où vous pouvez insérer le limiteur, vous pourriez obtenir un meilleur résultat si vous remplacez la pièce ci-dessus:

if(tbf->tokens > 0) { 
    tbf->tokens -= bytes; 
} else { 
    return -1; 
} 

La sémantique sera légèrement différent, mais moyenne sur une longue période de temps, il devrait vous obtenir environ le taux que vous recherchez. Bien sûr, si vous envoyez 125K dans un message sur un lien 1gbps, on peut difficilement parler de débit de 900kbps - il s'agira d'une rafale complète de paquets de 1gbps, et ils devront être mis en file d'attente quelque part en cas de liaisons à basse vitesse. Soyez prêt à perdre certains des paquets dans ce cas. Mais, en fonction de votre application et du protocole de réseau de transport que vous utilisez (TCP/UDP/SCTP/...?), Vous pouvez déplacer le code de mise en forme dans la pile, car les paquets sur le réseau sont généralement seulement 1500 octets maximum de toute façon (qui inclut divers en-têtes de protocole de réseau/transport)

Une chose qui pourrait être intéressante pour le test est http://www.linuxfoundation.org/en/Net:Netem - si votre objectif tente d'attaquer les liens de plus petite capacité. Ou, prenez quelques routeurs plus anciens avec des ports série 1mbps connectés dos à dos.

Questions connexes