За последние 24 часа нас посетили 62154 программиста и 1784 робота. Сейчас ищут 783 программиста ...

Кеш на одну секунду…

Тема в разделе "PHP для новичков", создана пользователем artuska, 24 июл 2009.

  1. artuska

    artuska Активный пользователь

    С нами с:
    6 авг 2007
    Сообщения:
    61
    Симпатии:
    0
    Адрес:
    Riga, Latvia
    Здравствуйте!

    Есть статья, к статье есть древовидные комментарии. Комментарии, естественно, кешируются — абсолютно все дерево, ни по каким страницам не разбито (например, на Хабре, у любой статьи дерево каментов посмотрите). Кешируется все средствами PEAR::Cache_Lite — из базы вытаскиваем комментарии, генерируем ХТМЛ код и кешируем его в файлик.

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

    Так вот вопрос — что и как здесь кешировать — ибо через секунду появится 1–3 новых комментария и смысл кеша просто пропадает. Что делать? (В Гугле ответ не искал, т.к. даже не могу сформулировать по каким ключевым словам (кроме «cache») искать :)))

    UPD
    Достаточно комментариев по-делу, я рад, что тема получила отклик, но проблема (в принципе) еще не решена. Поэтому, хочу здесь еще кое-что прояснить.

    Как вы уже поняли, ситуация надуманная. Естественно, нету у меня ресурса на котором зарегистрировано стотыщ мильёнов человек и в онлайне сидят несколько миллионов одновременно и поэтому комментарии к статьям сыпятся каждую секунду. Это просто пример. Возможно преувеличенный, но не думаю, что 1 комментарий каждую секунду это что-то новое для сервиса с огромной посещаемостью.

    Неужели ни у кого никогда не возникало вопроса — а что делать с кешем, если его приходится обновлять очень часто. Каковы тогда его достоинства и нужен ли он вообще, если мне приходится каждую, скажем, секунду-три его удалять и обновлять? Получается, что кеш просто несостоятелен. Тогда что идет ему на замену, какая технология?

    Псевдорешения проблемы
    Предлагают отказаться от файлового кеша и использовать памяь (memcached). Ок, спасибо, я знаю что такое memcached, но суть проблемы не в файловом или другом типе кеширования. Как файлы мне придется стирать/обновлять каждую секунду, так и memcache мне придется очищать/обновлять каждую секунду. И тот и другой подход теряет смысл.

    Предлагают делать кеш каждые, скажем, 100 секунд, к примеру. Или нелинейной функцией рассчитывать время кеширования. Окей. Тогда, получается, что вновьзашедшему пользователю будет выдаваться старый кеш! — Прошло 100 секунд, сделали кеш, следующий кеш будет сделан через 100 секунд… А что будет видеть пользователь, который зашел на 175-ой секунде? Ога, праильно, он будет видеть старый кеш семидесяти пяти (75) секундной давности. А у нас по условию, за эти 75 секунд добавляется куча новых комментов. Но пользователь будет вынужден лицезреть их только на 200-ой секунде. Пффф…

    Предлагают делать кеш каждые, скажем, 100 секунд, к примеру, а в промежутках выдавать этот самый кеш + новые комментарии, взятые из базы. Мдяяя… ну и как вы это организуете? Древовидные комментарии — добавление коммента идет либо в конец всех комментов, либо в какую-нибудь ветку. Ну и как, скажем новые комментарии мы будем впихивать в уже существующий кеш? В конец кеша да, без проблем. А в ветку? Яваскиптом? Ппц, дорогая редакция.

    Все предложенные решения несостоятельны. Детский сад.

    Решение проблемы
    Проблема не решена.
    Придется делать как в ЖЖ (примерно — я, лично, не знаю, как у них там все организовано) или комбинировать —
    1) разбивать комменты на страницы и кешировать каждую страницу;
    2) кешировать каждый комментарий первого уровня и его ветку
    3) комбинировать 1-й и 2-й способы.
    Так, примерно, и происходит в ЖЖ — вот только прекрасно видно сверхтормознутость (в каментах у Темы, скажем) и невозможность создать больше 10 000 комментариев.

    UPD2
    Вообщем, тема может быть закрыта. Остановлюсь на версии, что даже кеш на 1 секнду будет успешен и сделает то, что от него требуется.
     
  2. Koc

    Koc Активный пользователь

    С нами с:
    3 мар 2008
    Сообщения:
    2.253
    Симпатии:
    0
    Адрес:
    \Ukraine\Dnepropetrovsk
    хороший вопрос. После того как на него ответят, я задам другой, похожий.
     
  3. Andrey5555

    Andrey5555 Активный пользователь

    С нами с:
    29 ноя 2007
    Сообщения:
    486
    Симпатии:
    0
    Адрес:
    Киев
    Так если коменты так быстро появляються это похоже больше на спам, а спам нечего кешировать
     
  4. artuska

    artuska Активный пользователь

    С нами с:
    6 авг 2007
    Сообщения:
    61
    Симпатии:
    0
    Адрес:
    Riga, Latvia
    Нет, это не спам, все пользователи зарегистрированные. И вообще, не в этом дело.
     
  5. Koc

    Koc Активный пользователь

    С нами с:
    3 мар 2008
    Сообщения:
    2.253
    Симпатии:
    0
    Адрес:
    \Ukraine\Dnepropetrovsk
    Andrey5555
    причем тут спам? нормальные комменты появляются

    вопрос другой
     
  6. neverlose

    neverlose Активный пользователь

    С нами с:
    27 авг 2008
    Сообщения:
    1.112
    Симпатии:
    20
    Ответ прост. При добавлении комментария, очищать/обновлять кэшь.
     
  7. artuska

    artuska Активный пользователь

    С нами с:
    6 авг 2007
    Сообщения:
    61
    Симпатии:
    0
    Адрес:
    Riga, Latvia
    Мне кажется, ты страдаешь интеллектом. Прочитай внимательно вопрос и ситуацию.
    И не «кэш», а «кеш».
     
  8. TheShock

    TheShock Активный пользователь

    С нами с:
    30 май 2009
    Сообщения:
    1.255
    Симпатии:
    0
    Адрес:
    Київ
    artuska, неужели будет так критично, если пользователи увидят сообщение не сразу же после добавления, а через 5 секунд? Почему бы не поставить кеш от 5 секунд? Тем более, это только крайне незначительная часть сайта с такой посещаемостью и необходимостью столь регулярного обновления.
     
  9. artuska

    artuska Активный пользователь

    С нами с:
    6 авг 2007
    Сообщения:
    61
    Симпатии:
    0
    Адрес:
    Riga, Latvia
    Хм, хорошая мысль, но юзер привык видеть свое сообщение сразу же. Иначе он добавит комментарий, но не увидит его после обновления страницы, следовательно, возьмет и второй раз тот же комментарий добавит. В результате через 5 секнуд у нас будут 2 одниаковых коммента. Так не годится.

    В любом случае, даже такой кеш (на 5 секунд, как вы предлогаете) несостоятелен — ну что это за кеш на 5 секунд? Абсурд. Пропадает смысл кеша.
     
  10. TheShock

    TheShock Активный пользователь

    С нами с:
    30 май 2009
    Сообщения:
    1.255
    Симпатии:
    0
    Адрес:
    Київ
    artuska, давай на "ты".
    А что если сделать ДжавоСкрипт. Пользователь нажал кнопку "отправить" - сообщение передалось Аджаксом, закоммитилось и появилось на странице, а пользователь даже не знает, что оно пока не обновилось в кеше. А можно и написать: "Появится на виду у всех через 4 секунды"

    А в чем проблема? Если добавляется 5 комментариев в секунду к теме, то это где-то 100 просмотров за секунду (я думаю). Значит данные будут получены из кеша 500 раз. По-моему этого уже достаточно, чтобы кеш считался молодцом, что так хорошо отработал. А когда количество комментариев уменьшается до 1 за 10 секунд - можно уже кешировать сразу после обновления комментария.
     
  11. artuska

    artuska Активный пользователь

    С нами с:
    6 авг 2007
    Сообщения:
    61
    Симпатии:
    0
    Адрес:
    Riga, Latvia
    Про Аякс это без проблем так сделать. Это не обсуждается.
    Так же, проблема не с тем, кто постит комментарий, а с теми, кто их читает. За 5 секунд запостятся примерно 10 новых комментов, но люди их не увидят, если зайдут на сайт в промежутке между 1-й и 5-й секундой. Человек будет обновлять броузер каждую секунду и только на 6-й секунде появятся новые комменты.

    Но вообщем, я согласен. Не очень изящное решение, но окей, пускай будет.
    Итак, первое решение найдено — обновлять кеш в некий промежуток времени (5 секунд, а не каждую секунду, как было в начале обсуждения).

    Но проблема остается не решенной. А самый корень проблемы — это несостоятельность кеша, если его нужно обновлять каждую секунду или каждые 5 секунд. Как не крути с секундами, но проблема остается.
     
  12. kostyl

    kostyl Guest

    Вот в этом вся правда. Если он не состоятелен - не надо его делать. Начинай кешировать спустя 5 минут после публикации материала. До этого не кешируй. Это что так трудно сделать или это не стандартно, какие проблемы?
     
  13. artuska

    artuska Активный пользователь

    С нами с:
    6 авг 2007
    Сообщения:
    61
    Симпатии:
    0
    Адрес:
    Riga, Latvia
    Мдяяя… вот ты выдал. 5 минут. Пять! Это целых пять минут я должен выдават устаревший кеш? Ты думаешь о чем вообще говоришь?

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

    Если он не состоятелен, то его нужно сделать состоятельным.
     
  14. kostyl

    kostyl Guest

    Не тупим, я что не правильно выразился? Поясняю еще раз. Выдаем свежие данные спустя 5 минут после публикации. Потом НАЧИНАЕМ керишровать.
    Пишется нелинейная функция, которая управляет временем кеширвания. Но обычно она сперва не кеширует вовсе или кеширует довольно долго. Поэтому см. вариант выше.
     
  15. artuska

    artuska Активный пользователь

    С нами с:
    6 авг 2007
    Сообщения:
    61
    Симпатии:
    0
    Адрес:
    Riga, Latvia
    Дык я не туплю. Смотри, что ты предлагаешь:
    0 минут 0 секунд — опубликовалась статья
    от 0:00 минут до 5:00 минут — публикуются комментарии. Это значит, что в этот промежуток пользователи заходят на сайт и каждый раз идет выборка комментариев из базы данных. Зашел юзер, произошел коннект к базе и выборка комментов, зашел второй юзер, скажем, через 10 секунд — опять коннект и выборка и так далее в течении 5-и минут. Ппц. А за 5 минут зайдет человек 100 — сто коннектов и выборок из базы.

    Дальше.
    от 5:00 и далее — ты предлагаешь начинать кешировать комменты. Окей. Ровно в 5 минут я сделал кеш. Прошло, например, 10 секунд, добавилось около 20 новых комментов, зашел пользователь — и что он видит? А видит он еще старый кеш без этих новых 20-и комментариев. Ппц.

    Ты это имеешь ввиду?
     
  16. kostyl

    kostyl Guest

    Ну ладно, я не имею в виду строго пять минут. Я делаю упор на то что надо динамически менять время кеширвания. Пять минут это я так ляпнул. Сделай -логарифм + 1 частоты обновления. Тоесть через некоторое время частота обновления становиться постоянной, в первые моменты времени она довольна велика и стремиться к отсутствию кеширования. Так понятнее?
     
  17. TheShock

    TheShock Активный пользователь

    С нами с:
    30 май 2009
    Сообщения:
    1.255
    Симпатии:
    0
    Адрес:
    Київ
    artuska¸ а ты сообщи пользователям, что материал показывается с отставанием и покажи время до следующего обновления :)
     
  18. artuska

    artuska Активный пользователь

    С нами с:
    6 авг 2007
    Сообщения:
    61
    Симпатии:
    0
    Адрес:
    Riga, Latvia
    Я тебя прекрасно понял.
    Но твоим способом следуя, получится так, что в некоторые промежутки времени пользователю будет выдаваться старый кеш.
     
  19. Koc

    Koc Активный пользователь

    С нами с:
    3 мар 2008
    Сообщения:
    2.253
    Симпатии:
    0
    Адрес:
    \Ukraine\Dnepropetrovsk
    короче как я понял решения нет. Что ж, может Psih или 440hz с ГО что-либо насоветуют за выходные.
     
  20. sylex

    sylex Активный пользователь

    С нами с:
    9 ноя 2008
    Сообщения:
    625
    Симпатии:
    0
    Адрес:
    Омск
    интересно, что это за проект такой, где комменты сыпятся с такой скоростью..

    а может тут вовсе не нужен файловый кэш, а memcache?
     
  21. 440Hz

    440Hz Старожил
    Команда форума Модератор

    С нами с:
    21 дек 2012
    Сообщения:
    8.003
    Симпатии:
    1
    Адрес:
    Оттуда
    есть. я на dezinfo делал. там все лежит в мемкеше. в кеш сыпется все, что можно, в том числе куски HTMLи SQL данные на уровне результатов выборок. когда что-то добавляется то я сбрасываю нужные ключи в кеше и при следующем запросе кеш снова генерится.

    т.е. есть пост. он закеширован. как только пользователь добавляет камент, то я сюбрасывю кеш поста, топовые показатели (ТОП5 юзеров), ну и что-то там еще уже не помню.

    т.е. логика такая

    1. в кеш все, что можно, благо memcache это позволяет.
    2. при добавлении/изменении данных я удаляю нужные ключи из кеша и при следующих запросах в кеш ляжет новая инфа.
    3. далее п1.

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


    собственно кому интересно:

    грузится аяксом.
    addcomm.php

    PHP:
    1.  
    2. <?php
    3.  
    4.  
    5. function StopWord($text) {
    6.  
    7.  
    8. /*
    9.  
    10. стоп слова. ищется полное вхождение,
    11. т.е. если такое словосочетание встрeчается
    12. каммент просто не поститься.
    13.  
    14.  
    15. */
    16.  
    17. $w[] = 'ziza';
    18. $w[] = 'trinixy';
    19. $w[] = 'kolyan';
    20. $w[] = 'колян';
    21. $w[] = 'vvw';
    22. $w[] = 'money';
    23. $w[] = 'васи.нет';
    24. $w[] = 'vasi';
    25. $w[] = 'Деньги';
    26. $w[] = 'Яндекс';
    27. $w[] = 'mixeron';
    28. $w[] = 'затрат';
    29. $w[] = 'фишки';
    30. $w[] = 'fishki';
    31. $w[] = 'pаrk';
    32. $w[] = 'x';
    33. $w[] = 'name';
    34. $w[] = 'upload';
    35. $w[] = 'files';
    36. $w[] = 'zippp';
    37.  
    38.  
    39.  // ггг
    40.  
    41.     foreach($w as $a) {
    42.         if(strstr($text,$a)) return false;
    43.     }
    44.  
    45.     return true;
    46.  
    47. }
    48.  
    49.  
    50. if(isset($_REQUEST['q'])) extract($_REQUEST['q']);
    51.  
    52. $id   = (int) isset($post) ? $post : 0;
    53.  
    54. $form = true;
    55.  
    56.  
    57. if($id) {
    58.  
    59.  
    60.     if(!empty($nick) AND !empty($text) AND StopWord($text)) {
    61.  
    62.         $nick = trim($nick);
    63.         $text = trim($text);
    64.  
    65.         $name = htmlspecialchars(ResolveSlashes($nick));
    66.    
    67.         $nick = mysql_escape_string(ResolveSlashes($nick));
    68.         $text = ResolveSlashes($text);
    69.  
    70.  
    71.         if( ( !strstr($text,'http://') AND !strstr($nick,'http://') ) AND !empty($nick) AND !empty($text)) {
    72.  
    73.             $add = true;
    74.  
    75.             if($OOPSGlobal['SES']->uid->uid == '0')
    76.                 $last = $OOPSGlobal["SES"]->db->QueryObject("SELECT * FROM `comments` WHERE user = '".$OOPSGlobal['SES']->uid->uid."' ORDER BY date DESC LIMIT 1");
    77. //              $last = $OOPSGlobal["SES"]->db->QueryObject("SELECT * FROM `comments` WHERE post = $id AND user = '".$OOPSGlobal['SES']->uid->uid."' ORDER BY date DESC LIMIT 1");
    78.             else
    79.                 $last = $OOPSGlobal["SES"]->db->QueryObject("SELECT * FROM `comments` WHERE user = '".$OOPSGlobal['SES']->uid->uid."' ORDER BY date DESC LIMIT 1");
    80.             if($last) {
    81.  
    82.                 if( (time() - $last->date) < 30 ) {
    83.                     $add = false;
    84.                     $form = false;
    85.  
    86.                     $div .= 'извините. слишком быстро. мы не справляемся. =)<br /><br />';
    87.                     $click = "doLoad('forminfo','formtext','addcomm', { 'post' : {$id}}); return false;";
    88.                     $div .= '<a href="#" OnClick="'.$click.'">а нука исчо?</a>';
    89.                                
    90.                 }
    91.  
    92.             }
    93.  
    94.             if($add) {
    95.  
    96.                 $div .= 'спасибо <B>'.$name.'</B>. ощущения подпитаны...<br /><br />';
    97.                 $click = "doLoad('forminfo','formtext','addcomm', { 'post' : {$id}}); return false;";
    98.                 $div .= 'подпитать <a href="#" OnClick="'.$click.'">исче</a>, посмотреть <a href="#endcomments" >что писнулось</a> или <a href="http://li.ru/go?http://www.dezinfo.net/comments/">что пишут</a> другие?';
    99.  
    100.                 $text = mysql_escape_string($text);
    101.  
    102.  
    103.                 $cnt = $OOPSGlobal["SES"]->db->Count('comments',"post = {$id}");
    104.  
    105.                 $OOPSGlobal["SES"]->db->Query("INSERT INTO `comments` (`nick`,`text`,`date`,`ips`,`post`,`user`) VALUES('{$nick}','{$text}',".time().",'".OOPSGetIP()."',{$id},'".$OOPSGlobal['SES']->uid->uid."')");
    106.  
    107.                 $OOPSGlobal["SES"]->db->Query("UPDATE `posts` SET COMM = COMM + 1 WHERE id = $id");
    108.        
    109.                     if($OOPSGlobal['SES']->uid->uid != '0') {
    110.                         if($cnt == 0) {
    111.                             $OOPSGlobal["SES"]->db->Query("UPDATE `oops_users` SET POSTS = POSTS + 1, NAH = NAH + 1 WHERE id = '".$OOPSGlobal['SES']->uid->uid."'");
    112.                         } else {
    113.                             $OOPSGlobal["SES"]->db->Query("UPDATE `oops_users` SET POSTS = POSTS + 1 WHERE id = '".$OOPSGlobal['SES']->uid->uid."'");
    114.                         }
    115.                     }
    116.  
    117.                     $mkey = 'postcomm'.$id;
    118.                     $MEMCACHE->Delete($mkey);
    119.  
    120.                     $MEMCACHEKEY = "post.{$id}.1.0";
    121.                     $MEMCACHE->Delete($MEMCACHEKEY);
    122.                     $MEMCACHEKEY = "post.{$id}.1.1";
    123.                     $MEMCACHE->Delete($MEMCACHEKEY);
    124.  
    125.                     $MEMCACHE->Delete('index.0.1');
    126.                     $MEMCACHE->Delete('postsleaders');
    127.                     $MEMCACHE->Delete('top5userscamm');
    128.                     $MEMCACHE->Delete('comments');
    129.  
    130.                 $js  = "doLoad('camminfo','cammtext','showcamm', { 'page' : 1, 'post' : $id }, 'секундочку. ща добавим...');";
    131.  
    132.                 $form = false;
    133.             }
    134.         }
    135.  
    136.     }
    137.    
    138. }
    139.  
    140. if($form) {
    141.  
    142.     if($OOPSGlobal['SES']->uid->uid != '0') {
    143.  
    144.         $nick = htmlspecialchars($OOPSGlobal['SES']->uid->displayname);
    145.  
    146.         $div .= <<<ENDDIV
    147.  
    148.         <form id="sendcomm" method="post" enctype="multipart/form-data">
    149.         <input type=hidden name=post value="$id">
    150.         <input type=hidden name=nick value="$nick">
    151.         Имя: <B>$nick</B><br />
    152.         Сообщение:<br />
    153.         <textarea id="wtxt" name="text" class="int" rows=5></textarea>
    154.         </form>
    155.         <a href="#" OnClick="return doLoadForm('addcomm',document.getElementById('sendcomm'));">Оставить комментарий</a><br><p><b><font size=1>Кто скажет "баян" - тот писька :)</font></b>   
    156.    
    157. ENDDIV;
    158.    
    159.     } else {
    160.  
    161. /*
    162.         $div .= <<<ENDDIV
    163.  
    164.         <form id="sendcomm" method="post" enctype="multipart/form-data">
    165.         <input type=hidden name=post value="$id">
    166.         Имя:<br />
    167.         <input name="nick" type=text class="in"><br />
    168.         Сообщение:<br />
    169.         <textarea id="wtxt" name="text" class="int" rows=5></textarea>
    170.         </form>
    171.         <a href="#" OnClick="return doLoadForm('addcomm',document.getElementById('sendcomm'));">Оставить комментарий</a><br><p><b><font size=1>Кто скажет "баян" - тот писька :)</font></b>
    172.    
    173. ENDDIV;
    174.  
    175. */
    176.  
    177.         $div .= <<<ENDDIV
    178.  
    179.         <div style="padding: 10px; border: 1px solid red;color: red">
    180.  
    181.         писать в каменты могут только <a href="/registration/">зарегистрированные</a> пользователи.
    182.  
    183.         </div>
    184.    
    185. ENDDIV;
    186.    
    187.    
    188.     }
    189.  
    190. }
    191.  
    192.  
    193. ?>
    194.  
     
  22. Советую:
    Кешировать данные в определенный промежуток - 100 кооментов набежало - ты их закешировал. свежие пока отображаются стандартно. Набежало еще - обновил кеш. Не обязательно 100, число подбирается индивидуально.
     
  23. Koc

    Koc Активный пользователь

    С нами с:
    3 мар 2008
    Сообщения:
    2.253
    Симпатии:
    0
    Адрес:
    \Ukraine\Dnepropetrovsk
    Оно-то понятно, что у нормальных пацанов кеш не в файлах а в памяти. Я пока что присматриваюсь к APC. Но там не совсем ясно как сбрасывать по ключам. У меня будут наверно очень длинные имена переменных.

    Так ТС от этого и пытается избавиться. Он же говорит, что в первые N минут посты сыпятся пачками.

    флоппик
    во. Этот вариант мне по нраву.

    Теперь мой вопрос. Замечено, что сейчас стало модно показывать дату поста в виде "отправлено секунду назад", обновляешь - "10 секунд назад", прошло 2 дня - "2 дня назад". Это замечено в trac'е, redmine, activecollab, ... . Как быть в таком случае? Первый промежуток времени не кешируем совсем?

    upd: да-да, результаты вывода из БД можно кешировать, они не меняются в общем-то. Тут про то, что если б я хотел кешировать результаты парсинга.
     
  24. neverlose

    neverlose Активный пользователь

    С нами с:
    27 авг 2008
    Сообщения:
    1.112
    Симпатии:
    20
    Ах да, ты наверное слишком умён, раз ищешь помощи на форуме :lol:
     
  25. artuska

    artuska Активный пользователь

    С нами с:
    6 авг 2007
    Сообщения:
    61
    Симпатии:
    0
    Адрес:
    Riga, Latvia
    Достаточно умен, чтобы не быть самонадеянным, а спросить совета у тех, кто умнее меня.
    А ты даже не дочитал мой первый пост, но уже рвешься пестрить саркастическими шутками.