The OpenNET Project / Index page

[ новости /+++ | форум | теги | ]



Вариант для распечатки  
Пред. тема | След. тема 
Форум Разговоры, обсуждение новостей
Режим отображения отдельной подветви беседы [ Отслеживать ]

Оглавление

Релиз языка программирования PHP 7.3, opennews (?), 06-Дек-18, (0) [смотреть все]

Сообщения [Сортировка по времени | RSS]


70. "Релиз языка программирования PHP 7.3"  +/
Сообщение от fi (ok), 07-Дек-18, 12:13 
> file_exists() - бесполезная

ну не скажи - если файл используется для синхронизации - тот же lock
и в шеле постоянно такие проверки делаются.

Ответить | Правка | Наверх | Cообщить модератору

75. "Релиз языка программирования PHP 7.3"  +2 +/
Сообщение от userd (ok), 07-Дек-18, 12:37 
Давайте вынесем шелл за скобки, и собственно содержательную часть проверки существования файла - тоже.

Если lock делается через file_exists(), то это ошибка.
Если процесс установивший файл-блокировку "погибнет" не удалив файл (вариантов море, вплоть до нажатия кнопки ресет и выключения питания) то файл остаётся.

используйте flock:

http://www.opennet.ru/man.shtml?topic=flock&russian=0&catego...
http://www.opennet.ru/man.shtml?topic=flock&category=1&russi...
http://php.net/manual/en/function.flock.php

Ответить | Правка | Наверх | Cообщить модератору

82. "Релиз языка программирования PHP 7.3"  +/
Сообщение от SenaIVV (?), 07-Дек-18, 13:32 
Лет 10 точно использую кэш для сайтов, самая первая строка любого урла на любом моем сайте file_exists(файл в кэше на основании текущих переменных урла из .htaccess)

И далее уже сразу require_once(файлкэша) exit()
или пошло выполнение кода, который запросит все данные страницы и затем отдаст в браузер, ну и запишет в файл кэша это всё.

Любая отличная от file_exist функция при многотысячных тестах, выполняется медленнее, чтобы проверить существоваание файла кэша на диске.Включая прямое подключение файла с генерацией кода по ошибке.

Ответить | Правка | Наверх | Cообщить модератору

83. "Релиз языка программирования PHP 7.3"  –1 +/
Сообщение от blblblblbl (?), 07-Дек-18, 13:36 
мало запросов значит, ибо file_exists при инвалидации не атомарен и можно нарваться на dog pile при  генерации нового кеша
Ответить | Правка | Наверх | Cообщить модератору

84. "Релиз языка программирования PHP 7.3"  +/
Сообщение от SenaIVV (?), 07-Дек-18, 13:41 
Абсолютно никак такое не получить. Файл просто накроется новым параллельным кодом последнего пишущего, до момента следующей валидации. Говорю же - делал многтысячные тесты, включая параллельную нагрузку - все гуд, самое быстрое решение на текущий момент, НЕТ НИЧЕГО БЫСТРЕЕ!
Ответить | Правка | Наверх | Cообщить модератору

86. "Релиз языка программирования PHP 7.3"  +/
Сообщение от blblblblbl (?), 07-Дек-18, 13:54 
> Файл просто накроется новым параллельным кодом последнего пишущего

про это я и говорю, не должно быть более одного писателя ^_^
если писателей>1 значит исполнителей>1 значит кеш не работает какое-то время

Ответить | Правка | Наверх | Cообщить модератору

88. "Релиз языка программирования PHP 7.3"  +/
Сообщение от SenaIVV (?), 07-Дек-18, 14:06 
Если писать кэш одной строкой, один раз для файла, то без разницы сколько конкурирующих писателей будет - у всех текст один и тот же.

Первый вкатил весь кусок - читатель в этот момент еще не видит файла (нет ни fclose ни fflush).
Второй вкатил, последний вкатил - флуш. Так, как все писатели работают конкурентно без flock,  то очередь системная мгновенно производит (уже закэшированный после первого писателя) fwrite куска текста в файл - мгно-вен-но. Писатели заканичиваются мгновенно, и следующий читатель получает уже существование файла кэша.

На тестах я задавал овер нереальные условия, иногда, при настройках выделения памяти как на шаред хостингах (древних - по 64мб) я мог увидеть заполнение памяти очередью писателей.

Но в реальности (или при настройках выделения ресурсов по потребностям сайта) за 10 лет не было НИ ОДНОЙ ошибки связанной с этим, в реальных сайтах и приложениях.

Ответить | Правка | Наверх | Cообщить модератору

89. "Релиз языка программирования PHP 7.3"  +/
Сообщение от blblblblbl (?), 07-Дек-18, 14:22 
Я за 20 лет столько таких кешей повидал и к чему это приводит, что до сих пор удивляюсь, зачем допускать много писателей, которые исполнители.
Но в общем понятно, почему мало кто видит в чём проблема.
Это всё прокатывает, пока нет реально больших нагрузок, либо писатели отрабатывают так быстро, что кеш не нужен.
Ответить | Правка | Наверх | Cообщить модератору

90. "Релиз языка программирования PHP 7.3"  +/
Сообщение от SenaIVV (?), 07-Дек-18, 14:33 
Вам ан каком языке написать - тест: 64мб памяти (которых уже никогда не увидеть на реальном даже на шаред хостинге). Одновременных сессий 100, посетителей в минуту 6000, размер страницы 800Кб, длительность теста 1 час - но проблем. Что вы видели? Где вы видели? Поделитесь с нами слепыми, плиз.
Ответить | Правка | Наверх | Cообщить модератору

103. "Релиз языка программирования PHP 7.3"  +/
Сообщение от blblblblbl (?), 07-Дек-18, 15:26 
я никого уговаривать не собираюсь, делайте как хотите, размер памяти тут не при чём
Ответить | Правка | Наверх | Cообщить модератору

116. "Релиз языка программирования PHP 7.3"  +/
Сообщение от Аноним (116), 07-Дек-18, 17:16 
Есть пример с файловым кэшем для околореалтайм интерфейса. is_file + проверка контента (контент небольшой, порядка 1кб объёмом), 1000-1400 запросов в секунду, 2xE5520/8Gb рамы тянут такое только в путь. Причём это относительно вторичная задача на данном сервере. CPU load от этого счастья ~25%. Интерфейс - апач и fastcgi до php-fpm.
Ответить | Правка | К родителю #90 | Наверх | Cообщить модератору

117. "Релиз языка программирования PHP 7.3"  +/
Сообщение от Аноним (116), 07-Дек-18, 17:20 
Выглядит сие высокоуровнево вот так

        # first, try from cache
        if (is_array($data = self::readCache(self::$cacheId, $items, self::$cacheTimeout))) return $data; # valid cache
        
        # alas, could not validate cache, do the job retrieving data
        $fh = self::lockCache(self::$cacheId);
        
        # one more verification is needed here due to parallelism
        if (is_array($data = self::readCache(self::$cacheId, $items, self::$cacheTimeout, $fh))) return $data; # cache updated by someone and is valid

        ... update cache here ...

        # write and unlock cache, then return
        self::writeCache(self::$cacheId, $data);
        self::unlockCache($fh);
        return $data

Ответить | Правка | Наверх | Cообщить модератору

118. "Релиз языка программирования PHP 7.3"  +/
Сообщение от Аноним (116), 07-Дек-18, 17:25 
Ну и readCache с lockCache

    static protected function readCache($id, $items, $timeout = 500, $wLock = null)
    {
        $ok = false;

        if (@is_file(CT_ROOT."/cache/{$id}.info")) {
            $finfo = fopen(CT_ROOT."/cache/{$id}.info", 'rb');
            flock($finfo, LOCK_SH);
            fseek($finfo, 0, SEEK_SET);

            $data = array('info' => @unserialize(stream_get_contents($finfo)));
            if (is_array($data['info']) && isset($data['info']['timestamp']) && isset($data['info']['version']) && ($data['info']['version'] === CT_VERSION)) {
                if (abs((microtime(true) - $data['info']['timestamp']) * 1000) < $timeout) {
                    # cache is ok, demote write lock early if it exists
                    if ($wLock !== null) self::unlockCache($wLock);
                    
                    # read items now
                    $ok = true;
                    foreach ($items as $item)
                        if (@is_file(CT_ROOT."/cache/{$id}.{$item}")) $data[$item] = @unserialize(file_get_contents(CT_ROOT."/cache/{$id}.{$item}"));
                }
            }

            flock($finfo, LOCK_UN);
            fclose($finfo);
        }
        
        return $ok ? $data : false;
    }

    static public function lockCache($id)
    {
        $fh = fopen(CT_ROOT."/cache/{$id}.lock", 'ab+');
        flock($fh, LOCK_EX);
        return $fh;
    }

    static public function writeCache($id, &$data)
        $data['info'] = array('version' => CT_VERSION, 'timestamp' => microtime(true));

        foreach (array_keys($data) as $key) {
            switch ($key) {
                case 'valid':
                case 'changed':
                $data['info'][$key] = $data[$key];
                unset($data[$key]);
                break;
            }
        }

        $finfo = fopen(CT_ROOT."/cache/{$id}.info", 'ab+');
        flock($finfo, LOCK_EX);
        fseek($finfo, 0, SEEK_SET);
        ftruncate($finfo, 0);
        fwrite($finfo, serialize($data['info']));
        fflush($finfo);
        
        foreach ($data as $key => $val) {
            if ($key == 'info') continue;
            file_put_contents(CT_ROOT."/cache/{$id}.{$key}", serialize($val));
        }
        
        flock($finfo, LOCK_UN);
        fclose($finfo);
    }
    
    static public function unlockCache($fh)
    {
        flock($fh, LOCK_UN);
        fclose($fh);
    }

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

Ответить | Правка | К родителю #117 | Наверх | Cообщить модератору

119. "Релиз языка программирования PHP 7.3"  +/
Сообщение от blblblblbl (?), 07-Дек-18, 17:29 
кеш околореалтайм генерится? схема какая?
Ответить | Правка | Наверх | Cообщить модератору

121. "Релиз языка программирования PHP 7.3"  +/
Сообщение от Аноним (116), 07-Дек-18, 17:41 
Обновление кэша - три-четыре запроса поверх ZeroMQ к фоновым частям приложения + некоторая предобработка.
Ответить | Правка | К родителю #119 | Наверх | Cообщить модератору

122. "Релиз языка программирования PHP 7.3"  +/
Сообщение от Аноним (116), 07-Дек-18, 17:43 
Ну то есть писателей в моей схеме нет, читатели сами обновляют кэш.

В случае с писателями алгоритм почти не меняется. Только время валидности будет овердохера ("вечный" или около того в масштабах приложения кэш), и я ниже другому постеру откомментировал: инвалидация в писателе будет простейшая - берём всё ту же самую эксклюзивную блокировку, и банально удаляем кэш. Далее читатели всё сами обновят без нас.

Ответить | Правка | К родителю #119 | Наверх | Cообщить модератору

129. "Релиз языка программирования PHP 7.3"  +/
Сообщение от blblblblbl (?), 07-Дек-18, 18:35 
Под писателями я имею ввиду тех читателей, которые обнаружили невалидный кеш и пытаются его писать.

Собственно ещё вопрос, вот читатель видит протухший кеш и видит лок от другого процесса, он что делает? Судя по первому коду, он будет генерить $data, но кеш не обновит из-за чужого LOCK_EX

Ответить | Правка | К родителю #122 | Наверх | Cообщить модератору

131. "Релиз языка программирования PHP 7.3"  +/
Сообщение от Аноним (116), 07-Дек-18, 18:48 
Читатель видит протухший кэш и пытается взять LOCK_EX. Как только LOCK_EX взят - мы ещё раз проверяем кэш, его мог обновить другой читатель. Если это случилось - мы получили обновлённый кэш, снимаем лок, и ничего не генерим. В противном случае генерим, пишем, снимаем лок.
Ответить | Правка | К родителю #129 | Наверх | Cообщить модератору

132. "Релиз языка программирования PHP 7.3"  +/
Сообщение от blblblblbl (?), 07-Дек-18, 19:15 
Получается, что несколько потоков могут одновременно считать новое значение, т.к. время между "Как только LOCK_EX взят - мы ещё раз проверяем кэш" ненулевое, но достаточно малое, чтобы новый кеш мог быть ещё не обновлён другим потоком.
Ответить | Правка | К родителю #131 | Наверх | Cообщить модератору

135. "Релиз языка программирования PHP 7.3"  +/
Сообщение от Онаним (?), 08-Дек-18, 00:38 
Нет, не могут. Несколько потоков могут контендиться на LOCK_EX на время валидации кэша. На практике под 1200 запросов в секунду при интервале валидности кэша в 1 секунду оно чувствует себя нормально.

Почему не могут? Потому что как только LOCK_EX взят - никто больше его взять не сможет до завершения обновления "писателем". Таковым LOCK_EX будет отпущен не ранее, чем новое содержимое записано. После чего каждый ждущий "читатель" возьмёт LOCK_EX, считает кэш, убедится, что содержимое обновлено, и сразу же LOCK_EX отпустит. Чтение кэша - операция достаточно быстрая, поскольку таковой полностью сидит в кэше ОС.

Ответить | Правка | К родителю #132 | Наверх | Cообщить модератору

136. "Релиз языка программирования PHP 7.3"  +/
Сообщение от Онаним (?), 08-Дек-18, 01:09 
Для обхода конкуренции с ридерами и предотвращения рейсов сделана хитрость: лок-файл отдельный, и никогда не лочится как LOCK_SH, в отличие от файла кэша.

Как живут писатели:

Для проверки кэша мы лочим сам файл кэша (.info) как LOCK_SH, но только на время чтения-валидации. Зачем - чуть ниже. Если кэш не валиден, то мы берём LOCK_EX на локфайл (.lock). Как только мы взяли LOCK_EX для локфайла - никто больше, кроме нас, права обновлять кэш не имеет. Другие считавшие невалидный кэш и возжелавшие его обновить - встанут в очередь на пресловутый LOCK_EX для локфайла.

Для чего вторая проверка. Мы может быть таким же возжелавшим в очереди. То есть кто-то до нас взял LOCK_EX на локфайл и обновляет кэш, а мы его ждём. Как только обновляющий закончит работу - мы (ну или кто-то до нас) сможем взять LOCK_EX на локфайл. Взяв LOCK_EX на локфайл, мы проверяем кэш на предмет того, а не стал ли он валидным (не было ли кого до нас с LOCK_EX на локфайл). Если кэш валиден - значит его обновили, и мы сразу же сбрасываем LOCK_EX, потому что это contention point, и нас таких стоящих в очереди на LOCK_EX только чтобы убедиться, что кэш уже обновили, может быть много. После чего возвращаем содержимое кэша вызывающей стороне, работа закончена.

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

---

Как живут читатели:

Первый - валидация кэша. Когда мы валидируем и читаем кэш - мы лочим сам файл кэша на LOCK_SH. Для чего: чтобы не считать полузаписанные данные, если активен писатель. Желающий записать кэш писатель контендится с валидирующими читателями, ему нужен LOCK_EX на файл кэша.

Второй - мы не боремся ни с другими читателями (потому что LOCK_SH), ни с уже вставшими в очередь на LOCK_EX на локфайл для обновления кэша. Если первая валидация не удалась - мы сами превращаемся в таковых вставших в очередь. Если же мы попали в момент записи кэша писателем - сразу же, как только писатель закончит и отдаст LOCK_EX - мы считаем уже валидный кэш. Это уменьшает общий contention: вставшие в очередь желающие LOCK_EX на локфайл ещё будут продолжать драться между собой за этот лок, только чтобы свалидировать кэш во второй раз и отвалить с новым содержимым, однако новые читатели в очередь вставать перестанут сразу после записи кэша писателем.

---

Если сомневаетесь - можете даже диаграмму порисовать :), она тривиальна.

Ответить | Правка | К родителю #132 | Наверх | Cообщить модератору

91. "Релиз языка программирования PHP 7.3"  +/
Сообщение от SenaIVV (?), 07-Дек-18, 14:37 
И да, я же вам написал - люди делающие php не сопли жуют, а пишут код. Писатели отрабатывают мгновенно (ввиду того, что записываемый текст, отработка запросов и все события системы кэшируются, ввиду их равнозначности, и все последующие писатели просто не нагружают систему в принципе).

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

Ответить | Правка | К родителю #89 | Наверх | Cообщить модератору

120. "Релиз языка программирования PHP 7.3"  +/
Сообщение от Аноним (116), 07-Дек-18, 17:35 
Проще делать блокировку с обновлением при чтении, проверяя на обновление соседом - тогда не придётся обновлять кэш многочисленное число раз. Инвалидация в писателе тоже простейшая - берём всё ту же самую эксклюзивную блокировку, и удаляем кэш. Далее читатели всё сами обновят без нас.
Ответить | Правка | К родителю #88 | Наверх | Cообщить модератору

97. "Релиз языка программирования PHP 7.3"  +/
Сообщение от Ilya Indigo (ok), 07-Дек-18, 15:02 
> И далее уже сразу require_once(файлкэша) exit()

Если уж дело идёт про скорость, то require_once() - это костыль рукожопов, который нафиг не нужен нормальным программистам, а выполняется он медленнее чем require().

> Любая отличная от file_exist функция при многотысячных тестах, выполняется медленнее,

Логично, что проверка на существование и на доступность для чтения медленнее проверки только на существование. А без проверки вообще ещё быстрее будет!

Если у Вас, конечно, не оффтопик, то Вы получите ошибку, если окажется что файл существует, но он не доступен для чтения.

Ответить | Правка | К родителю #82 | Наверх | Cообщить модератору

102. "Релиз языка программирования PHP 7.3"  +1 +/
Сообщение от SenaIVV (?), 07-Дек-18, 15:23 
Нет, у меня такой ситуации не может быть, что файл есть, но не доступен для чтения - в этом и смысл и скорость конкурентной записи.

На счет require_once - если нет совпадающих пространств имен, одинакова скорость.
У меня нет таких пространств. Просто по привычке осталось с самых азов еще, всегда инклюдить и запрашивать исполнение через гарантию отсутствия дублей функций.

В самом начале такие коды были, что без этого было никуда :)

Ответить | Правка | Наверх | Cообщить модератору

107. "Релиз языка программирования PHP 7.3"  +/
Сообщение от Ilya Indigo (ok), 07-Дек-18, 15:59 
> Нет, у меня такой ситуации не может быть, что файл есть, но
> не доступен для чтения - в этом и смысл и скорость
> конкурентной записи.

Буду знать что file_exists() кому-то всё же нужна на мой взгляд в редкой для PHP ситуации.

> На счет require_once - если нет совпадающих пространств имен, одинакова скорость.
> У меня нет таких пространств. Просто по привычке осталось с самых азов
> еще, всегда инклюдить и запрашивать исполнение через гарантию отсутствия дублей функций.

Я тоже начинал с include_once() пока не понял, что всё кроме require() нужно забыть в PHP. А также ещё тогда не знал про spl_autoload_register, кстати...

define('WWW', $_SERVER['DOCUMENT_ROOT']);
define('ROOT', dirname(WWW));
spl_autoload_register(function($class)
{
    $file = ROOT.'/models/'.$class.'.php';
    if (is_readable($file))
        require($file);
});

Ответить | Правка | Наверх | Cообщить модератору

104. "Релиз языка программирования PHP 7.3"  +1 +/
Сообщение от SenaIVV (?), 07-Дек-18, 15:30 
И, кстати, на счет скорости проверки наличия - не все так очевидно. Я до теста считал, что прямое включение без проверки наличия файла и код в обработчике ошибок - быстрее (без кэширования, первый запрос такого типа отрабатывает быстрее, чем первая проверка наличия файла). Но при повторном вызове, file_exists сразу начинает выигрывать.
Ответить | Правка | К родителю #97 | Наверх | Cообщить модератору

133. "Релиз языка программирования PHP 7.3"  +/
Сообщение от hellobillyboy (?), 07-Дек-18, 20:32 
о! классное решение, выложи пожалуйста посмотреть на кодохостинг
https://govnokod.ru/php

спасибо!

Ответить | Правка | К родителю #82 | Наверх | Cообщить модератору

85. "Релиз языка программирования PHP 7.3"  +/
Сообщение от blblblblbl (?), 07-Дек-18, 13:51 
flock не панацея
нужно делать pid-файл через fopen x+ и проверять статус процесса, если файл существует
Ответить | Правка | К родителю #75 | Наверх | Cообщить модератору

92. "Релиз языка программирования PHP 7.3"  +/
Сообщение от Sw00p akaJerom (?), 07-Дек-18, 14:42 
версионность через симлинк
Ответить | Правка | Наверх | Cообщить модератору

98. "Релиз языка программирования PHP 7.3"  +/
Сообщение от blblblblbl (?), 07-Дек-18, 15:07 
это уже детали реализации, можно и через mv, смотря что делается, новый tmp тоже надо лочить и писать правильно
Ответить | Правка | Наверх | Cообщить модератору

99. "Релиз языка программирования PHP 7.3"  +/
Сообщение от blblblblbl (?), 07-Дек-18, 15:09 
т.е. если делаешь демона, то симлинк тут никаким боком, в остальном страдать версионностью можно разными способами :)
Ответить | Правка | К родителю #92 | Наверх | Cообщить модератору

124. "Релиз языка программирования PHP 7.3"  +/
Сообщение от fi (ok), 07-Дек-18, 18:12 
> используйте flock:

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

Ответить | Правка | К родителю #75 | Наверх | Cообщить модератору

Архив | Удалить

Рекомендовать для помещения в FAQ | Индекс форумов | Темы | Пред. тема | След. тема




Партнёры:
PostgresPro
Inferno Solutions
Hosting by Hoster.ru
Хостинг:

Закладки на сайте
Проследить за страницей
Created 1996-2024 by Maxim Chirkov
Добавить, Поддержать, Вебмастеру