문제

응용 프로그램 전송 속도를 900kbps로 제한하려고하지만 문제는 내가 사용하는 프로토콜이 메시지 지향적이고 메시지의 크기가 매우 다르다는 것입니다. 최대 125000 바이트까지 40 바이트의 메시지를 가질 수 있으며 모든 메시지는 원자 단위로 전송됩니다.

나는 토큰 버킷 버퍼를 구현하려고 시도했지만 낮은 버킷 크기를 설정하면 큰 패킷이 전송되지 않으며 더 큰 버킷은 전혀 제한없이 큰 버스트를 초래할 수 있습니다.

이것은 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;
}

그런 다음 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 링크를 통해 하나의 메시지로 125k를 보내면 약 900kbps 속도에 대해 거의 이야기 할 수 없습니다. 1Gbps의 패킷이 가득 차게 될 것이므로 더 낮은 링크가있는 경우 어딘가에 대기해야합니다. 이 경우 패킷 중 일부를 잃을 준비를하십시오.

그러나 사용중인 애플리케이션 및 전송 네트워크 프로토콜 (TCP/UDP/SCTP/...?)에 따라 네트워크의 패킷은 일반적으로 최대 1500 바이트이기 때문에 스택으로 쉐이핑 코드를 이동할 수 있습니다. 어쨌든 (다양한 네트워크/전송 프로토콜 헤더 포함)

테스트에 흥미로울 수있는 한 가지는입니다 http://www.linuxfoundation.org/en/net:netem - 목표가 소규모 용량 링크를 다루려고하는 경우. 또는 1Mbps 직렬 포트가 뒤로 연결된 두 개의 오래된 라우터를 잡습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top