質問

アプリケーションの送信料金を900kbpsに制限しようとしていますが、問題は私が使用するプロトコルがメッセージ指向であり、メッセージのサイズが非常に異なることです。最大125000バイトまでの40バイトからのメッセージを持つことができ、すべてのメッセージはアトミックユニットとして送信されます。

トークンバケットバッファーを実装しようとしましたが、低いバケットサイズを設定した場合、大きなパケットが送信されることはなく、大きなバケットは大きなバーストになり、まったく制限されません。

これは私の小さな実装です。

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;
}

次に、main()のどこかに:

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);
}
役に立ちましたか?

解決

Max_burst(最初にTBF->容量に割り当てられます)で最大メッセージサイズを制限しています - TBF->トークンはその価値を超えて増加することはないので、このチェックのために大きなメッセージが送信されることはありません。

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

したがって、コードは実際にバーストの厳しい制限をmax_burstに設定します。したがって、このバーストサイズが必要な場合は、メッセージを断片化する必要があります。

これがリミッターを挿入できるコードの唯一の場所であると仮定すると、上記の部分を次のものに置き換えると、より良い結果が得られる可能性があります。

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

セマンティックはわずかに異なりますが、平均して長期間にわたって、探しているレートをほぼ得る必要があります。もちろん、1Gbpsリンクを介して1つのメッセージに125kを送信する場合、900kbpsのレートについてはほとんど話すことができません - 1Gbpsのパケットのバーストが完全になり、より低いスピードリンクがある場合にどこかでキューに入れる必要があります - したがってその場合、一部のパケットを失う準備をしてください。

ただし、使用しているアプリケーションとトランスポートネットワークプロトコル(TCP/UDP/SCTP/...?)に応じて、ネットワーク上のパケットは通常最大1500バイトのみであるため、シェーピングコードをスタックに移動することをお勧めします。とにかく(さまざまなネットワーク/トランスポートプロトコルヘッダーが含まれます)

テストに興味があるかもしれないことが1つです http://www.linuxfoundation.org/en/net:netem - 目標がより小さな容量のリンクに取り組むことを試みている場合。または、1Mbpsシリアルポートが背中に接続されたいくつかの古いルーターをつかみます。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top