Comments 33
Это жесть какая то… Зачем каждый раз дергать внешний сервис, когда можно на крон повесить агента который обновлял бы 1 запись в базе, а уже все запросы формирования цены или просто вывода валюты брались из базы, и рядышком писать последнее обновление валюты 1 минуту назад или 3?
+1
Просто пример выбран неправильно.
Замените file_get_contents на что-то другое, синхронное, длительное и с ошибками.
Впрочем, и в общем случае лучше такие операции выносить в cron.
Замените file_get_contents на что-то другое, синхронное, длительное и с ошибками.
Впрочем, и в общем случае лучше такие операции выносить в cron.
+2
Как ни странно, описанная ситуация (правда, не для курсов валют) реальна: я её встречал десятки раз в жизни. И все шаги эволюции кэшестроения тоже.
Да, можно повесить демона в простейшем случае. И в сложнейшем тоже — об этом в следующей части.
Кстати, представьте, что показывается не одна пара, а для каждого пользователя своя. Запросы стоят каждый, таскать все пары получится слишком накладно…
Да, можно повесить демона в простейшем случае. И в сложнейшем тоже — об этом в следующей части.
Кстати, представьте, что показывается не одна пара, а для каждого пользователя своя. Запросы стоят каждый, таскать все пары получится слишком накладно…
+2
Кеширование индивидуальных данных будет малоэффективным, раз ими может пользоваться малое кол-во запросов.
Кроме того, сделать один SELECT на 100к строк, и сделать 100к SELECT-ов по одной строке тоже сильно отличаются по нагрузке.
Статический поллинг горячих (не всех, а именно часто используемых) данных (с последующей записью в кеш) все-таки самый эффективный способ, если критично важно уменьшить нагрузку на источник данных.
Стоит также упомянуть, что блокировки тоже реализуются множеством способом — чем дальше от программы (как с использованием внешнего мемкеша, например) — тем больше задержки и накладные расходы. В пределах сервера все же лучше использовать SysV или хотя бы fcntl. Не говоря уже о разного типа мютексах или, для php, соответствующих модулях, где используется разделяемая память.
Кроме того, сделать один SELECT на 100к строк, и сделать 100к SELECT-ов по одной строке тоже сильно отличаются по нагрузке.
Статический поллинг горячих (не всех, а именно часто используемых) данных (с последующей записью в кеш) все-таки самый эффективный способ, если критично важно уменьшить нагрузку на источник данных.
Стоит также упомянуть, что блокировки тоже реализуются множеством способом — чем дальше от программы (как с использованием внешнего мемкеша, например) — тем больше задержки и накладные расходы. В пределах сервера все же лучше использовать SysV или хотя бы fcntl. Не говоря уже о разного типа мютексах или, для php, соответствующих модулях, где используется разделяемая память.
+1
— Мы не знаем заранее, какие используются, особенно, когда пользователи могут поменять поведение в любой момент.
Но по закону Парето 80% запросов можно упихать в 20% кеша… Реальное распределение различается от случая к случаю. В случае с валютами, пары USD/RUR и EUR/RUR (+ обратные) скорее всего будут покрывать 80% случаев :)
— Хорошо, когда можно сделать SELECT на 100к строк. А еще лучше просто держать локальную реплику. Вот только при интеграции со внешними системами зачастую надо использовать тот API, какой есть.
— Да, рефреш кеша отдельным демоном это хорошо, об этом я писал в статье, и обязательно разверну в следующей части.
Крайне важно помнить, что если дать человеку сразу сложное решение, он спросит «нафига так сложно?» и сделает как ему кажется — просто и неправильно. И так пока не подорвётся.
Эта статья — ответ на вопрос, всплывавший многократно, почему кеш — не панацея, и вообще делает не то, что вы хотите. Если он применим в конкретном случае — хорошо. Но это совсем не очевидно, и при всей «очевидности» зачастую совсем не так.
— Статья совсем не о блокировках, и потому мы можем обсудить это в комментариях при желании — или вообще, напишете свою статью! Или я могу пройтись по вариантам — но только когда дойдут руки/ноги. Сказать можно много, вот только времени мало.
Напомню, что в статье мягко подразумевалось исполнение на appengine, так что это НЕ один сервер, а потому все способы блокировок, заточенные на single-server не имеют смысла.
Но по закону Парето 80% запросов можно упихать в 20% кеша… Реальное распределение различается от случая к случаю. В случае с валютами, пары USD/RUR и EUR/RUR (+ обратные) скорее всего будут покрывать 80% случаев :)
— Хорошо, когда можно сделать SELECT на 100к строк. А еще лучше просто держать локальную реплику. Вот только при интеграции со внешними системами зачастую надо использовать тот API, какой есть.
— Да, рефреш кеша отдельным демоном это хорошо, об этом я писал в статье, и обязательно разверну в следующей части.
Крайне важно помнить, что если дать человеку сразу сложное решение, он спросит «нафига так сложно?» и сделает как ему кажется — просто и неправильно. И так пока не подорвётся.
Эта статья — ответ на вопрос, всплывавший многократно, почему кеш — не панацея, и вообще делает не то, что вы хотите. Если он применим в конкретном случае — хорошо. Но это совсем не очевидно, и при всей «очевидности» зачастую совсем не так.
— Статья совсем не о блокировках, и потому мы можем обсудить это в комментариях при желании — или вообще, напишете свою статью! Или я могу пройтись по вариантам — но только когда дойдут руки/ноги. Сказать можно много, вот только времени мало.
Напомню, что в статье мягко подразумевалось исполнение на appengine, так что это НЕ один сервер, а потому все способы блокировок, заточенные на single-server не имеют смысла.
0
Тогда плюсую, хотя и не могу) Если бы вы написали это в начале статьи, вопросов бы к вам небыло. А так спасибо.
0
Не понимаю, если честно. В начале статьи вполне себе сказано, что у нас «есть доступ к базе» и показан API, как именно доступ есть.
Или что, если слова «база» то сразу SQL?
Или что, если слова «база» то сразу SQL?
0
UFO just landed and posted this here
А почему нельзя создать «демона» который будет обновлять данные в кеше каждые 5, 10, 30 секунд (в зависимости от времени суток или величина нагрузки или по какой-то иной логике), а пользвательские запросы всегда будут брать данные из кеша?
-3
Можно. Про это есть в статье.
+2
Только в статье описано почему это вредно, когда демон на PHP! Как там говорят, «Демон на PHP, Карл!» =)
Конечно он у вас сворует процесс и т.д. А если на Go/C/Crystal и тд демон? Он ни процессов PHP, ни время процессора, ни оперативки, ни сил и времени не будет отнимать.
Человека выше заминусили совсем зазря, ИМХО.
Конечно он у вас сворует процесс и т.д. А если на Go/C/Crystal и тд демон? Он ни процессов PHP, ни время процессора, ни оперативки, ни сил и времени не будет отнимать.
Человека выше заминусили совсем зазря, ИМХО.
0
Простите, мы точно говорим об одной и той же статье? Можно циатату?
0
В конце статьи разбор с простым примером, где часть процессов PHP «висят» и не выполняют полезную работу.
0
Прочитайте еще раз. Речь идёт не об отдельном обновляющем демоне, а о том, что вместо 100 запросов в секунду мы обрабатываем 1 запрос 2 секунды, и не можем обрабатывать остальные так же быстро.
Это относится к поведению обработчиков при внезапном «утяжелении» запросов к зависямостям. Неважно кто это — php/go/c. Да даже на асме, если мы внезапно начали промахиваться мимо кеша на границе линии (так как злой пользователь загрузил картинку не 800*600 а 799*599), эффективная производительность проседает неожиданно и на порядки.
Ну даже если у нас многопоточный обработчик на Си, у нас точно так же ограниченное число тредов, которые могут обрабатывать запросы, и если один из них становится занят надолго — эффективная пропускная способность падает. И нет, мы не можем просто запустить еще один тред вместо висящего (равно как вредно у PHP cтавить максимум 200 процессов, чтобы «всё равно обрабатывать пока медленные висят», так как дополнительный обработчик занимает ресурсы — он не только «спит, ожидая ответа», он еще занимать память, диск, сокеты, файловые дескрипторы и т.п., и сложно заранее сказать когда и какой из таких ресурсов исчерпается и с какой стороны прилетит по голове.
Это относится к поведению обработчиков при внезапном «утяжелении» запросов к зависямостям. Неважно кто это — php/go/c. Да даже на асме, если мы внезапно начали промахиваться мимо кеша на границе линии (так как злой пользователь загрузил картинку не 800*600 а 799*599), эффективная производительность проседает неожиданно и на порядки.
Ну даже если у нас многопоточный обработчик на Си, у нас точно так же ограниченное число тредов, которые могут обрабатывать запросы, и если один из них становится занят надолго — эффективная пропускная способность падает. И нет, мы не можем просто запустить еще один тред вместо висящего (равно как вредно у PHP cтавить максимум 200 процессов, чтобы «всё равно обрабатывать пока медленные висят», так как дополнительный обработчик занимает ресурсы — он не только «спит, ожидая ответа», он еще занимать память, диск, сокеты, файловые дескрипторы и т.п., и сложно заранее сказать когда и какой из таких ресурсов исчерпается и с какой стороны прилетит по голове.
+1
Перечитал =) Я больше говорил о Вашей архитектуре работы с кэшем из PHP. И комментатор выше я думаю так же подумал.
Почему Вы не стали в PHP-приложении ТОЛЬКО ЧИТАТЬ значения из кэша? Ну и добавили бы минимум логики в приложение, мол получили значение из кэша — радуемся, а не получили — не рисуем компонент, вставляем дефолтное значение(если имеет место быть) и тд. А вот отдельный скрипт по крону запускается(или демон на постоянку с засыпанием), идет в чужой сервис и пишет итоги в кэш. PHP-приложение знать не знает, откуда в кэше данные. Поделили ответственность, создали задел на будущее и тд. В такой архитектуре я не вижу причин появления проблем из поста. С моих глаз у Вас борьба с ветряными мельницами: затолкали конкурентную запись с чтением в логику приложения с кучей клиентов/тредов и давай воевать там =)
Почему Вы не стали в PHP-приложении ТОЛЬКО ЧИТАТЬ значения из кэша? Ну и добавили бы минимум логики в приложение, мол получили значение из кэша — радуемся, а не получили — не рисуем компонент, вставляем дефолтное значение(если имеет место быть) и тд. А вот отдельный скрипт по крону запускается(или демон на постоянку с засыпанием), идет в чужой сервис и пишет итоги в кэш. PHP-приложение знать не знает, откуда в кэше данные. Поделили ответственность, создали задел на будущее и тд. В такой архитектуре я не вижу причин появления проблем из поста. С моих глаз у Вас борьба с ветряными мельницами: затолкали конкурентную запись с чтением в логику приложения с кучей клиентов/тредов и давай воевать там =)
0
У меня к статье есть одна претензия: почему 1000 запросов в БД почему-то начало стоить денег?
-2
$args = ["currency1=".urlencode($currency1), "currency2=".urlencode($currency2)];
$rate = @file_get_contents($api_host."?".join("&", $args));
http_build_query в гугл еще не завезли?)
+2
Пусть меня заминусуют, но я в упор не вижу, когда $flags !== FALSE
+1
При memcache->get() либо:
— возвращает прочитаное значение ключа и возвращает связанные с ними флаги.
— возвращает FALSE в случае ошибки или отсутствия ключа
то есть если значения нет, то флаги не меняются; если значение есть — флаги это число, соответственно тип сменится с boolean на integer, следовательно, $flags станет точно не равно FALSE.
(сравнение !== учитывает типы, то есть 0 == FALSE, но при этом 0 !== FALSE)
— возвращает прочитаное значение ключа и возвращает связанные с ними флаги.
— возвращает FALSE в случае ошибки или отсутствия ключа
то есть если значения нет, то флаги не меняются; если значение есть — флаги это число, соответственно тип сменится с boolean на integer, следовательно, $flags станет точно не равно FALSE.
(сравнение !== учитывает типы, то есть 0 == FALSE, но при этом 0 !== FALSE)
0
Пример мне кажется немного надуманным, действительно правильнее использовать под такую задачу крон. Но с академической точки зрения очень хорошая иллюстрация грабель.
Более уместным был бы пример, как мне кажется, тяжелых запросов в базу данных, которые зависят от данных профиля пользователя (например выдача новостей по интересам)
Более уместным был бы пример, как мне кажется, тяжелых запросов в базу данных, которые зависят от данных профиля пользователя (например выдача новостей по интересам)
+1
Это второй виток петли — вам кажется, что это нагляднее только потому, что первый виток уже очевиден.
Могу только апеллировать к грустному опыту наблюдений как народ проходит по этим граблям раз за разом даже для таких простых случаев.
Второй и третий витки в работе. Чукча не писатель, чукча инженер, поэтому это требует много времени, терпение-с плиз.
Могу только апеллировать к грустному опыту наблюдений как народ проходит по этим граблям раз за разом даже для таких простых случаев.
Второй и третий витки в работе. Чукча не писатель, чукча инженер, поэтому это требует много времени, терпение-с плиз.
0
Конечно всегда найдутся еще грабли)
Но я хочу сказать, что если кто-то решает задачу из статьи прямо как написано, то это архитектурно не правильно. Задача веб сервера в том, чтобы как можно быстрее отработать request-response, а не мудрить сложную логику по вытягиванию данных и разруливанию race condition. Зачем множить это на кучи потоков, когда достаточно выделить лишь один, который будет заниматься конкретной задачей по актуализации данных в кеше.
Но я хочу сказать, что если кто-то решает задачу из статьи прямо как написано, то это архитектурно не правильно. Задача веб сервера в том, чтобы как можно быстрее отработать request-response, а не мудрить сложную логику по вытягиванию данных и разруливанию race condition. Зачем множить это на кучи потоков, когда достаточно выделить лишь один, который будет заниматься конкретной задачей по актуализации данных в кеше.
+1
Важно понимать, что это всего лишь паттерн: есть запрос, для него есть внешние данные, которые должны быть актуальны, но допускают некоторое отставание по времени.
Мы легко можем заменить во всей статье веб-фронтенд бэкенд API запросом, которому для вычисления нужна некая оценка курса. Или проверка факта что мы вообще сейчас выполняем эти запросы. Или еще что — миллион случаев, когда это вполне разумно сделать именно кешированием здесь и сейчас.
И несмотря на то, что для простого веб-фронтенда это действительно оверкилл, очень часто это реалии — начиная от shared hosting'ов где нет крона вообще (впрочем, выше уже писали, что я просто не умею настраивать несуществующие вещи), и заканчивая просто синдромом молотка (это когда всё кажется гвоздями, когда в руках молоток) у начинающих.
Собственно, из-за того, что уже несколько раз встречал синдром молотка, я и попытался описать в области максимально близкой для тех, кому это важно понять, принять и начать жить дальше уже иначе.
Мы легко можем заменить во всей статье веб-фронтенд бэкенд API запросом, которому для вычисления нужна некая оценка курса. Или проверка факта что мы вообще сейчас выполняем эти запросы. Или еще что — миллион случаев, когда это вполне разумно сделать именно кешированием здесь и сейчас.
И несмотря на то, что для простого веб-фронтенда это действительно оверкилл, очень часто это реалии — начиная от shared hosting'ов где нет крона вообще (впрочем, выше уже писали, что я просто не умею настраивать несуществующие вещи), и заканчивая просто синдромом молотка (это когда всё кажется гвоздями, когда в руках молоток) у начинающих.
Собственно, из-за того, что уже несколько раз встречал синдром молотка, я и попытался описать в области максимально близкой для тех, кому это важно понять, принять и начать жить дальше уже иначе.
0
Развивая тему про новостей по интересам.
Сейчас подумал, ведь чисто теоритически можно составить примерную карту заходов пользователя, и на основании этого прогноза подготавливать кэш на данный момент?
Для всех не залогиненных пользователей показывать 'стандартный кэш новостей на даный момент'.
Сейчас подумал, ведь чисто теоритически можно составить примерную карту заходов пользователя, и на основании этого прогноза подготавливать кэш на данный момент?
Для всех не залогиненных пользователей показывать 'стандартный кэш новостей на даный момент'.
+1
Цитата из статьи:
Да, на этом этапе это было перебором, поэтому вопросы организации хранения значений в кеше в принципе за скобками (даже замена LRU на статистические оценки могут дать определённые преимущества, вот только всегда можно создать такую нагрузку на систему, которая отравит и такой кеш, а потому это становится не важно для оценки наихудшего сценария).
Иметь постоянно работающий фоновый процесс для обновления кэша: процесс должен с заданной периодичностью проверять, не устаревает ли значение в кэше, и если срок жизни подходит к концу, а значение требовалось за время жизни кэша – обновляет его.
Да, на этом этапе это было перебором, поэтому вопросы организации хранения значений в кеше в принципе за скобками (даже замена LRU на статистические оценки могут дать определённые преимущества, вот только всегда можно создать такую нагрузку на систему, которая отравит и такой кеш, а потому это становится не важно для оценки наихудшего сценария).
0
Sign up to leave a comment.
Кэши для «чайников»