Хорошо, заголовок действительно очень субъективен. Но вот в чем проблема для меня.
Предпосылкой является то, что я хочу равномерно распределять попадания статического веб-содержимого на определенное количество серверов кэширования. Также должна ускориться доставка клиентам, поскольку используется несколько доменов и запросы не блокируют друг друга. Мне также не нужен классический балансировщик нагрузки, но я сразу же генерирую правильные ссылки в моем html-коде.
Я также хочу убедиться, что один и тот же URL-адрес всегда обслуживается одним и тем же сервером.
Поэтому я просто определил маленькая функция, которая возвращает хост для использования путем хеширования URL-адреса запроса и вычисляет по модулю количество используемых серверов:
function pseudocode_statify($url) { // $url looks like /folder1/folder2/file.jpg
return 'http://' . md5($url) % $num_of_servers .'.mydomain.com' . $url;
}
Сначала у меня было что-то вроде шестнадцатеричного декодирования и подстроки для предотвращения переполнения на месте, но обнаружил, что это просто работает хорошо, как описано выше.
Однако моя проблема в том, что если я запустил следующий тестовый сценарий:
for($i=0;$i<100000;$i++) {
$md5 = md5(uniqid($i).microtime().rand(1,999999999999));
$result[$md5%2]++;
}
Я ожидал равномерного распределения. это означает, что $ result [0] будет близко к значению $ result [1];
Это не тот случай.
Хорошо, здесь нет ничего особенного. Я бы просто согласился с тем фактом, что md5 не так равномерно распределен, как я думал, и пошел бы на другой алгоритм хеширования, такой как sha1 или что-то в этом роде.
Но я попытался воспроизвести результаты и нашел шаблон, который я не могу объяснить.
Соотношение всегда было около 2/1. На самом деле соотношение всегда было примерно от 1 / 2,16 до 1 / 2,17
Пример вывода некоторых запусков приведенного выше скрипта:
output was generated by: echo "ratio: ".$result[0]/$result[1]."\n";
ratio: 2.1757121534504
ratio: 2.1729411578062
ratio: 2.1726559360393
ratio: 2.1676895664225
ratio: 2.1667416128848
ratio: 2.1667115284133
ratio: 2.1677791605385
ratio: 2.1658969579688
ratio: 2.1668508131769
ratio: 2.1689292821741
Странно было то, что отношение сумм% 2 равно 1 и сумма% 2, равная 0 иногда чередовалась!
for($j = 0; $j<100;$j++) {
for($i=0;$i<100000;$i++) {
$md5 = md5(uniqid($i).microtime().rand(1,999999999999));
$result[$md5%2]++;
}
var_dump($result);
}
Я запускал сценарий из командной строки два раза и прервал его после трех запусков, и он произвел два следующих вывода:
joe@joe-laptop:/home/flimmit/httpdocs$ php test.php
PHP Notice: Undefined variable: result in /home/flimmit/httpdocs/test.php on line 6
PHP Notice: Undefined offset: 0 in /home/flimmit/httpdocs/test.php on line 6
PHP Notice: Undefined offset: 1 in /home/flimmit/httpdocs/test.php on line 6
array(2) {
[0]=>
int(68223)
[1]=>
int(31777)
}
array(2) {
[0]=>
int(136384)
[1]=>
int(63616)
}
array(2) {
[0]=>
int(204498)
[1]=>
int(95502)
}
^C
joe@joe-laptop:/home/flimmit/httpdocs$ php test.php
PHP Notice: Undefined variable: result in /home/flimmit/httpdocs/test.php on line 6
PHP Notice: Undefined offset: 1 in /home/flimmit/httpdocs/test.php on line 6
PHP Notice: Undefined offset: 0 in /home/flimmit/httpdocs/test.php on line 6
array(2) {
[1]=>
int(31612)
[0]=>
int(68388)
}
array(2) {
[1]=>
int(63318)
[0]=>
int(136682)
}
array(2) {
[1]=>
int(94954)
[0]=>
int(205046)
}
^C
joe@joe-laptop:/home/flimmit/httpdocs$
Как вы Вы можете видеть, что в первом случае первая запись результатов всегда выше, а во втором - наоборот. тот же сценарий.
Странно то, что я могу воспроизвести это поведение ТОЛЬКО при запуске скрипта несколько раз.
Я написал этот небольшой скрипт, чтобы воспроизвести «подкачку» и сгенерировать достаточно данных измерения:
for($j = 0; $j<100;$j++) {
for($i=0;$i<rand(1000,10000);$i++) {
$md5 = md5(uniqid($i).microtime().rand(1,99999999));
$result[$md5%2]++;
}
#var_dump($result);
echo "ratio: ".$result[0]/$result[1]." ".(($result[0]<$result[1]) ? "A":"B")."\n";
sleep(rand(2,5));
}
Но здесь он печатает только b , никогда не пятерки. Это заставило меня подумать, что в сценарии может быть семантическая ошибка, но я ее не обнаружил.
Я действительно застрял, и это меня очень беспокоит.
Итак, мои вопросы:
Вы можете порекомендовать любую литературу / веб-ссылки, где я мог прочитать о md5 немного глубже, включая дистрибутивы и т. д.
Вы можете объяснить / воспроизвести поведение? У меня здесь ошибка? (на самом деле это очень вероятно, но я не могу его найти)
Можете ли вы порекомендовать какой-либо другой алгоритм, который подходит для моего случая использования? Он не должен быть криптографическим или сильным, а должен быть быстрым, детерминированным и равномерно распределенным.