c ++ 11 — Как правильно определить самый быстрый CDN, зеркало, сервер загрузки в Stack Overflow

Вопрос, с которым я борюсь, состоит в том, как определить в c++ тот, который является сервером с самым быстрым соединением для клиента, делает git клон или скачать tarball, Так что в основном я хочу выбрать из коллекции известен зеркала, с которых будет использоваться загрузка контента.

Следующий код я написал демонстрирует это то, что я пытаюсь достичь более четко, возможно, но я считаю, что это не то, что нужно использовать в производстве :).

Допустим, у меня есть два известных исходных зеркала git-1.exmple.com а также git-2.example.com и я хочу скачать tag-x.tar.gz от того, к которому клиент имеет лучшее соединение.

CDN.h

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <netdb.h>
#include <arpa/inet.h>
#include <sys/time.h>
using namespace std;

class CDN {
public:
long int dl_time;
string host;
string proto;
string path;
string dl_speed;
double kbs;
double mbs;
double sec;
long int ms;
CDN(string, string, string);
void get_download_speed();
bool operator < (const CDN&);
};
#endif

CDN.cpp

#include "CND.h"CDN::CDN(string protocol, string hostname, string downloadpath)
{
proto = protocol;
host = hostname;
path = downloadpath;
dl_time = ms = sec = mbs = kbs = 0;
get_download_speed();
}
void CDN::get_download_speed()
{
struct timeval dl_started;
gettimeofday(&dl_started, NULL);
long int download_start = ((unsigned long long) dl_started.tv_sec * 1000000) + dl_started.tv_usec;
char buffer[256];
char cmd_output[32];
sprintf(buffer,"wget -O /dev/null --tries=1 --timeout=2 --no-dns-cache --no-cache %s://%s/%s 2>&1 | grep -o --color=never \"[0-9.]\\+ [KM]*B/s\"",proto.c_str(),host.c_str(),path.c_str());
fflush(stdout);
FILE *p = popen(buffer,"r");

fgets(cmd_output, sizeof(buffer), p);
cmd_output[strcspn(cmd_output, "\n")] = 0;
pclose(p);

dl_speed = string(cmd_output);
struct timeval download_ended;
gettimeofday(&download_ended, NULL);
long int download_end = ((unsigned long long)download_ended.tv_sec * 1000000) + download_ended.tv_usec;

size_t output_type_k = dl_speed.find("KB/s");
size_t output_type_m = dl_speed.find("MB/s");

if(output_type_k!=string::npos) {
string dl_bytes = dl_speed.substr(0,output_type_k-1);
double dl_mb = atof(dl_bytes.c_str()) / 1000;
kbs = atof(dl_bytes.c_str());
mbs = dl_mb;
} else if(output_type_m!=string::npos) {
string dl_bytes = dl_speed.substr(0,output_type_m-1);
double dl_kb = atof(dl_bytes.c_str()) * 1000;
kbs = dl_kb;
mbs = atof(dl_bytes.c_str());
} else {
cout << "Should catch the errors..." << endl;
}
ms = download_end-download_start;
sec = ((float)ms)/CLOCKS_PER_SEC;
}
bool CDN::operator < (const CDN& other)
{
if (dl_time < other.dl_time)
return true;
else
return false;
}

main.cpp

#include "CDN.h"int main()
{
cout << "Checking CDN's" << endl;
char msg[128];
CDN cdn_1 = CDN("http","git-1.example.com","test.txt");
CDN cdn_2 = CDN("http","git-2.example.com","test.txt");
if(cdn_2 > cdn_1)
{
sprintf(msg,"Downloading tag-x.tar.gz from %s %s since it's faster than %s %s",
cdn_1.host.c_str(),cdn_1.dl_speed.c_str(),cdn_2.host.c_str(),cdn_2.dl_speed.c_str());
cout << msg << endl;

}
else
{
sprintf(msg,"Downloading tag-x.tar.gz from %s %s since it's faster than %s %s",
cdn_2.host.c_str(),cdn_2.dl_speed.c_str(),cdn_1.host.c_str(),cdn_1.dl_speed.c_str());
cout << msg << endl;
}
return 0;
}

Так что вы думаете и как бы вы подошли к этому. Какие альтернативы заменить это wget и добиться того же чистого пути в C ++

РЕДАКТИРОВАТЬ:
Как правильно указал @molbdnilo

ping измеряет задержку, но вы заинтересованы в пропускной способности.

Поэтому я отредактировал демонстрационный код, чтобы отразить это, однако вопрос остается тем же

-6

Решение

Для начала, попытка определить «самое быстрое зеркало CDN» — неточная наука. Не существует общепринятого определения того, что означает «самый быстрый». Самое большее, на что можно здесь надеяться, это выбрать разумную эвристику для того, что означает «самый быстрый», а затем измерить эту эвристику настолько точно, насколько это возможно в данных обстоятельствах.

В приведенном здесь примере кода выбранная эвристика показывает, сколько времени занимает загрузка файла примера с каждого зеркала через HTTP.

На самом деле это не такой уж плохой выбор. Вы могли бы обоснованно привести аргумент, что некоторые другие эвристики могут быть немного лучше, но основной тест на то, сколько времени потребуется для передачи файла образца с каждого зеркала-кандидата, я бы подумал, что это очень разумная эвристика.

Большая, большая проблема здесь, которую я вижу здесь, — это фактическая реализация этой эвристики. Способ, которым эта попытка — рассчитать время загрузки образца — здесь, выглядит не очень надежным, и в итоге он будет измерять целую кучу несвязанных факторов, которые не имеют никакого отношения к пропускной способности сети.

Я вижу здесь, по крайней мере, несколько возможностей, когда внешние факторы, совершенно не связанные с пропускной способностью сети, могут испортить измеренные значения времени и сделать их менее надежными, чем они должны быть.

Итак, давайте посмотрим на код и посмотрим, как он пытается измерить задержку в сети. Вот мясо этого:

sprintf(buffer,"wget -O /dev/null --tries=1 --timeout=2 --no-dns-cache --no-cache %s://%s/%s 2>&1 | grep -o --color=never \"[0-9.]\\+ [KM]*B/s\"",proto.c_str(),host.c_str(),path.c_str());
fflush(stdout);
FILE *p = popen(buffer,"r");

fgets(cmd_output, sizeof(buffer), p);
cmd_output[strcspn(cmd_output, "\n")] = 0;
pclose(p);

… и gettimeofday () используется для выборки системных часов до и после, чтобы выяснить, сколько времени это заняло. Хорошо, это здорово. Но что бы это на самом деле измерить?

Здесь очень помогает взять чистый лист бумаги и просто записать все, что здесь происходит, как часть popen() вызов, шаг за шагом:

1) Новый дочерний процесс fork()редактор Ядро операционной системы создает новый дочерний процесс.

2) Новый дочерний процесс exec() Ы /bin/bashили системная оболочка по умолчанию, передающая длинную строку, начинающуюся с «wget», за которой следует куча других параметров, которые вы видите выше.

3) Ядро операционной системы загружает «/ bin / bash» как новый дочерний процесс. Ядро загружает и открывает все общие библиотеки, которые обычно требуется для запуска системной оболочки.

4) Процесс оболочки системы инициализируется. Это читает $HOME/.bashrc файл и выполняет его, скорее всего, вместе с любыми стандартными файлами инициализации оболочки и сценариями, которые обычно делает ваша системная оболочка. Это само по себе может создать кучу новых процессов, которые должны быть инициализированы и выполнены, прежде чем процесс новой системной оболочки действительно доберется до …

5) … парсинг команды «wget», которую она изначально получила в качестве аргумента, и exec() используя это.

6) Ядро операционной системы теперь загружает «wget» как новый дочерний процесс. Ядро загружает и открывает все общие библиотеки, которые wget Процесс нуждается. Глядя на мою коробку Linux, «wget» загружает не менее 25 отдельных разделяемых библиотек, включая Kerberos и библиотеки ssl. Каждая из этих общих библиотек инициализируется.

7) wget Команда выполняет поиск DNS на хосте, чтобы получить IP-адрес веб-сервера для подключения. Если локальный DNS-сервер не имеет кэшированного IP-адреса имени хоста зеркала CDN, часто требуется несколько секунд, чтобы найти доверенные DNS-серверы DNS-зоны зеркал CDN, а затем запросить у них IP-адрес, перескочив таким образом и таким образом, через межтрубные

Теперь, один момент … Кажется, я забыл, что мы пытались сделать здесь … О, я помню: какое зеркало CDN «самое быстрое», загрузив файл примера с каждого зеркала, верно? Да, это должно быть так!

Теперь, что вся работа, проделанная выше, вся эта работа, связана с определением, какое зеркало контента является самым быстрым ???

Эээ … Не так много, как мне кажется. Теперь, ничто из вышеперечисленного не должно быть такими шокирующими новостями. В конце концов, все это описано на странице руководства popen (). Если вы читаете страницу руководства popen, она говорит вам, что … что она делает. Запускает новый дочерний процесс. Затем выполняет системную оболочку, чтобы выполнить запрошенную команду. И т. Д., И т. Д. …

Теперь мы не говорим об измерении временных интервалов, которые длятся много секунд или минут. Если мы пытаемся измерить что-то, что занимает много времени, относительные накладные расходы popen() подход был бы незначительным, и не о чем беспокоиться. Но ожидаемое время загрузки файла примера с целью выяснить, насколько быстро работает каждое зеркало контента, — я ожидаю, что фактическое время загрузки будет относительно коротким. Но мне кажется, что непроизводительные издержки, связанные с выполнением этих действий, созданием совершенно нового процесса и выполнением сначала системной оболочки, а затем команды wget с ее огромным списком зависимостей, будут статистически значимыми.

И, как я упоминал в начале, учитывая, что это пытается определить смутное туманное понятие «самое быстрое зеркало», которое уже является неточной наукой — мне кажется, что вы действительно хотите полностью избавиться от него. здесь неуместные накладные расходы — насколько это возможно, чтобы получить как можно более точный результат.

Таким образом, мне кажется, что вы действительно не хотите измерять здесь что-либо, кроме того, что вы пытаетесь измерить: пропускную способность сети. И вы, конечно же, не хотите измерять все, что происходит до того, как произойдет какая-либо сетевая активность.

Я все еще думаю, что попытка рассчитать время загрузки образца — разумное предложение. Что не разумно, так это все popen а также wget раздуваться. Итак, забудьте обо всем этом. Выкинь это в окно. Вы хотите измерить, сколько времени потребуется, чтобы загрузить образец файла поверх HTTPс каждого кандидата зеркало? Ну, почему бы тебе не только то?

1) Создать новый разъем().

2) Использование getaddrinfo(), чтобы выполнить поиск DNS и получить IP-адрес зеркала-кандидата.

3) соединять() к HTTP-порту зеркала.

4) Форматировать соответствующий HTTP GET запрос, и отправить его на сервер.

Вышеописанное в значительной степени делает то, что делает popen / wget, до этого момента.

И только сейчас я бы запустил часы, хватая ток gettimeofday(), затем подождите, пока я прочту весь образец файла из сокета, а затем возьмите текущий gettimeofday() еще раз, чтобы получить время окончания передачи, а затем рассчитать фактическое время, необходимое для получения файла с зеркала.

Только тогда у меня будет некоторая разумная уверенность в том, что я на самом деле буду измерять время, необходимое для получения файла примера из зеркала CDN, и полностью игнорирую время, необходимое для выполнения группы совершенно не связанных процессов; и затем, взяв один и тот же образец из нескольких зеркал CDN, можно надеяться на то, чтобы выбрать его, используя как можно больше разумной эвристики.

1

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]