Daos и нагрузки

11.08.2010

У меня есть важный вопрос к программистам. Нужна ваша помощь! Но сперва должен извиниться перед рекламодателями: вчера или сегодня сбросились все рекламные строчки. Извините, восстановить это невозможно.

Почему пропали данные?

В Daos не используются базы данных типа MySQL, всё работает на файлах. В самых первых версиях это иногда было причиной сбоев: при совпадении, когда файл одновременно и запрашивался и записывался. После я выпустил обновление, в котором проблема решалась с помощью встроенного в PHP механизма блокировки файлов (flock).

Однако, всё равно с тех пор было два или три аналогичных инцидента у моих клиентов и вот случилось это и со мной (было бы справедливо, если бы сразу произошло на моей площадке).

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

Вот эти две злополучные функции: http://pastie.org/1084477

Правильно они написаны или есть какая-то трудноуловимая ошибка?

P.S. Есть ещё маленькая вероятность, что проблема локализована где-то снаружи этих функций, а не внутри.

Комментарии

  1. # kulikov: 

    это пипец. :)

    первый раз вижу такой извращенный способ сохранять данные в файл.

    может проще сериализовывать? нахрен строку из вар_экспорта в виде пхп кода сохранять а потом эвалить?

    у этого твоего даоса исходники открыты?

    а вобще я бы рассмотрел. возможность перехода на sqlite. его более чем достаточно для твоих задач.

    и файлы лочить надо только при записи. чтение можно без локов делать

  2. # oddman: 

    +1 за sqlite
    я не спец по PHP, но вроде sqlite там встроен, тогда проблем вообще ноль

  3. # chodex

    flock поддерживается только относительно новыми файловыми системами, в *nix носит рекомендательный характер, а в некоторых системах и вовсе его работа не гарантируется.
    flock
    Из-за этого и могут быть подобные сбои

  4. # aktuba

    Никак не пойму – чем тебя базы не устраивают?

  5. #  Тормоз

    может проще сериализовывать

    Не проще. Сериализация глючит, если попадутся спецсимволы, например.

    у этого твоего даоса исходники открыты?

    Да.

    и файлы лочить надо только при записи. чтение можно без локов делать

    В данном случае нельзя.

    flock поддерживается только относительно новыми файловыми системами, в *nix носит рекомендательный характер, а в некоторых системах и вовсе его работа не гарантируется.

    Вот блин. Может, тогда перейти на вариант с копированием/удалением файла?

    А sqlite разве на любом хостинге есть? Да и если всё равно работу с БД изучать надо, лучше уж на MySQL перейти.

    Никак не пойму – чем тебя базы не устраивают?

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

  6. # Kichrum

    sqlite конечно вариант.
    Вообще базы выучить не помешает ;) Язык SQL очень похож на английский, вроде сложного ничего нет. Я лично за пару дней выучил SQL по курсам Oracle (SQL везде фактически один, так что в MySQL прекрасно применяю эти же знания).

  7. # chodex

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

  8. # Bitman

    Подсмотрел когда то решение. Надо писать через временный файл потом переименование. У кого то cms там работает, если не изменяет склероз, то в Блоголёте вроде.

  9. #  Тормоз

    Вот я тогда изучал варианты как раз, в том числе и с переименованием. Но не помню сейчас, почему выбрал именно решение с flock. Были какие-то доводы против переименований.

  10. # Bitman

    Порылся, вроде нашёл похожее www.linkexchanger.su…

  11. #  Тормоз

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

  12. # kulikov: 

    я знаю всего один символ, ломающий сериализацию. это \0 (null byte). встречается он при сериализации объектов с private или protected переменными. и при желании легко экранируется. в остальном сериализация работает отлично.

    sqlite лучше mysql именно потому что не требует доп. настроек. достаточно лишь прроверить что sqlite доступна в нашей сборке пхп. никаких юзеров/паролей/баз данных создавать не надо.

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

    где можно посмотреть исходники, раз они открыты?

  13. # aktuba

    >Это усложнение установки для пользователя.

    Да ладно… Что, у кого-то проблемы с установкой WP или DLE? Едиственное, что надо будет предусмотреть – чтобы названия таблиц не совпали случайно (использовать префиксы, например)…

    >Ну и пока у меня просто знаний не хватает, ни разу ничего не делал с базами.

    Ну это дело попровимое, когда есть желание ;) Очень советую использовать какой-то враппер для базы, например этот: forum.dklab.ru/viewt…

  14. # kulikov: 

    обе функции меняются на

    // запись
    file_put_contents($file, serialize($dataArray), LOCK_EX);

    // чтение
    $dataArray = unserialize(file_get_contents($file));

  15. #  Тормоз

    в остальном сериализация работает отлично.

    Не хочу спорить и вспоминать детали, но в своё время намучался я с этой сериализацией (см. комменты), поэтому сознательно выбрал именно такой вариант, как есть сейчас. Да и какие минусы ты видишь? Сериализованный файл невозможно нормально читать и править, а мои можно и без всяких проблем.

    sqlite лучше mysql именно потому что не требует доп. настроек. достаточно лишь прроверить что sqlite доступна в нашей сборке пхп. никаких юзеров/паролей/баз данных создавать не надо.

    Ну а если нет в сборке? Когда делаешь продукт, который должен работать на большинстве хостингов, приходится учитывать.

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

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

    где можно посмотреть исходники, раз они открыты?

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

    Ну это дело попровимое, когда есть желание ;) Очень советую использовать какой-то враппер для базы…

    Да, я про них знаю, спасибо. Выберу что-нибудь. Было бы круто, кстати, чтобы был какой-то класс абстракции, то есть возможность одинаковой работы как с MySQL так и с файлами.

    обе функции меняются на…

    Не меняются. В первых версиях так и было и всё ломалось нахрен. Практика. Не всегда всё работает так, как задумано. Особенно с PHP :)

  16. # Anton: 

    SQLite только в новой версии стал более менее быстро работать с INSERT‘ами. С SQLite придется использоваться PDO, скорее всего.

    И зачем использовать serialize/unserialize? Ведь PHP5.2 уже давно на дворе, да и DAOS, надеюсь, на UTF-8 – вполне можно json_encode/json_decode обойтись.

    И анлок файла делать не обязательно – он сам делается при fclose($handle);

  17. #  Тормоз

    вполне можно json_encode/json_decode обойтись.

    Тоже глючит. Обещания красивые, но JSON в PHP не работает нормально (опять же, не вспомню сейчас деталей), при этом далеко не везде установлен.

  18. # Anton: 

    Уже сколько пользуюсь – проблем ни разу не замечал. Кроме, конечно, использования кривой кодировки. По спеке, json только utf-8 поддерживает.

    Да и есть он везде, где php >= 5.2.

  19. # Anton: 

    Еще предложил бы NoSQL-хранилища, но далеко не все хостинги поддерживают это дело, к сожалению.

  20. # Anton: 

    И раз уж пошла такая пьянка… В мануале по flock есть такое дело:

    «On some operating systems flock() is implemented at the process level. When using a multithreaded server API like ISAPI you may not be able to rely on flock() to protect files against other PHP scripts running in parallel threads of the same server instance!»

  21. #  Тормоз

    А у тебя русские символы после JSON не перекодируются в ужасные нечитаемые последовательности? Это лишь одна из проблем была. Я потом углубился в изучение всяких сериализаций, даже до Google Protocol Buffer дошёл, и в результате принял решение хранить данные в файле через var_export. Я считаю, что это решение красивое и не вижу в нём ни одного недостатка в сравнении с JSON и другими сериализациями.

  22. # kulikov: 

    :) весело у тебя все.
    это не работает, тут что-то глючит.

    <blockquote>Если файл не лочить, чтение данных может произойти в момент, когда файл меняется, значит данные будут пустые или порченые.</blockquote>

    чтение из файла не может произойти когда он меняется именно потому, что он будет залочен на время изменения. лочить файл при чтении НЕ НАДО. сто пудов.

  23. # kulikov: 

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

  24. # Markus: 

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

  25. #  Тормоз

    Плюнул и сделал с базой. у кого посещений не много у тех все нормально будет.

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

  26. # Evgeny Sergeev: 

    Можно сделать свою блокировку – на время записи создавать файл и удалять его после записи, так же при чтении

  27. #  art

    не знаю за эти функции, но у меня раньше юзалось блокировка переименованием. че нить типа file.txt в file.lock и куй к нему че обратится по старому имени

  28. # anonymous: 

    эх, давно я не брал в руки шашку.

    у тебя race condition между flock($file, LOCK_UN) и fclose($file).
    не отпускай локи, close это сделает за тебя.
    алсо, стоит проверять код возврата close, что-бы удостовериться в успешности записи.

  29. # anonymous: 

    вдогонку
    > flock поддерживается только относительно новыми файловыми системами
    fucking nonsense.
    flock появился 27 лет назад, а не всегда работает он только для удалённых файловых систем (nfs, etc)

  30. # samlowry

    Тоже подумалось — sqlite.

    Про «медленно работает с инсертами» — тут они не нужны. Про то, где он стоит —

    The SQLite extension is enabled by default as of PHP 5. Before that time the SQLite library is needed.

  31. #  Тормоз

    у тебя race condition между flock($file, LOCK_UN) и fclose($file).

    Не понял, что ты имел в виду.
    Можно по-русски? :)

    Про «медленно работает с инсертами» — тут они не нужны.

    А статистика показов?

  32. # Жилинский

    У меня уже второй раз так строчки слетают. В прошлый раз ты вроде даже не поверил :D

  33. #  Тормоз

    Вот блин. Постараюсь решить эту проблему в самое ближайшее время. Кстати, у тебя сейчас вообще Daos отключен что ли?

  34. # Casher99: 

    Я считаю что не нужно придумывать велосипед и использовать MySQL. Всё красиво и стабильно. И быстродействие на высоте.

    flock действительно иногда тупит от настроек сервака.

  35. # Djalin: 

    извиняюсь за свои 5 копеек а как дела с XML?

  36. #  Тормоз

    А что с XML?

  37. # ПистоГанза

    Тормоз, бэкапы то для кого придумали?

  38. # djalin

    rumba.net.ru – говорит на XML – лутше чем на файлах… чесно не знаю просто предположение

  39. # AleDas: 

    $file = fopen($file, ‘a’);

    fseek($file, 0); ftruncate($file, 0);

    не равно $file = fopen($file, ‘w+’); ?

    опять же.. в мануале рекомендуют b добавлять…
    wb+ и rb+

  40. # phpdude

    тормоз, ну не гони на json, не гони))) это обычное экранироение не альфабетикал последовательностей в их ютф яваскрипт коды. если не веришь – почитай что такое json :D

    атомарные операции аля – переименование в нужный файл должны помочь 100%.

  41. # anonymous: 

    @Тормоз
    en.wikipedia.org/wik…

    просто убери flock($file, LOCK_UN) из кода.

    дело в том, что отпуская лок до закрытия файла ты допускаешь ситуацию, в которой не все операции записи ещё выполнены, но чтение или новые операция записи уже возможны.

    так-же проверяй коды возврата write и close.

    более подробно все эти вещи описаны в man 2 flock и man 2 close.

  42. # Bitman

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

  43. # Клиент : 

    Тормоз, переведи DAOS на sqlite – будет очень удобно

  44. # Sterx: 

    SQL – это легко. А пошаговый (1-2 шага) инсталятор сделает для юзера процесс незаметным

  45. # Djalin: 

    Я против баз так как ето допольнительный геморой при псмене хостинга и бекапах.
    Особенно для юзера.

  46. # samlowry

    Статистика — сохраняется чем-то другим. От логов до клиент-сервер базы. Для отдачи инфы — SQLite.

  47. # Жилинский

    Да, отключен.
    Старые строчки похерились, новые не покупают. Чего ему висеть…

  48. # anonymous: 

    Тормоз, сделай DAO для бизнес-сущностей и разные драйвера — для баз, для файлов.

  49. #  Тормоз

    это обычное экранироение не альфабетикал последовательностей в их ютф яваскрипт коды

    Я понимаю, что это такое, но не понимаю зачем коверкать нормальный русский текст, если файл всё равно в UTF-8.

  50. # phpdude

    >> но не понимаю зачем коверкать нормальный русский текст, если файл всё равно в UTF-8.

    потому что это яваскрипт, а там так – по стандарту, ведь неизвестно в принципе браузерам в какой кодировке файл, поэтому и используется «экранирование»

  51. #  Тормоз

    ведь неизвестно в принципе браузерам в какой кодировке файл

    А серверные заголовки зачем придумали? Всё известно.

  52. # phpdude

    а сервер откуда знает? :)

    не переспоришь, потому что я прав)

  53. #  Тормоз

    Ты не прав :) Сервер настроить не проблема, да и не всегда от сервера это зависит. Если я JSON вывожу через PHP, например, я могу послать заголовок (и так и делаю для всех файлов). Какие проблемы-то?

  54. # phpdude

    проблема в слишком много «если», поэтому и используется «наверняка», а не гадание на манной гуще.

  55. #  Тормоз

    Ну вот поэтому вместо модного JSON я использую обычный родной для PHP формат :) Кстати, меня тут в извращённости обвинили, но никак не аргументировали. Не вижу недостатков у вставки корректного PHP-файла с массивом. Теоретически это может быть менее быстро, чем сериализация и наверняка медленней базы данных, но вряд ли это существенно.

  56. # phpdude

    уху, варэекспорт медленнее сериализации, заметно будет на больших массивах.

    а сравнивать с базой обе эти вещи))) ну скажу так – соединение с бд порвет по медлительности практически любую сериализацию в мыслимых пределах количества элементов в массиве :)

    я сам использую сериализацию.

  57. #  Тормоз

    Хм. То есть именно ты Daos тоже сделал бы на файлах вместо БД?

  58. # phpdude

    я бы сделал его на memcachedb чисто ради прикола :D

    тормоз, я байки погнал, если чо завтр потрещим, вставать ран, спокойной :)

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

  59. #  Тормоз

    Давай, добрых снов. Чисто приколом мне нельзя руководствоваться, тогда вообще продаж не будет :) А деньги мне нужны.

  60. # СОДА

    memcachedb – это как хардкор мод в диабле, советую все проекты хранить так!

  61. #  Тормоз

    А пользователям, которые ничего про это не знают как быть? Вешаться? :)

  62. # aktuba

    >ну скажу так – соединение с бд порвет по медлительности практически любую сериализацию

    Ребят, вы о чем? Приземлитесь – у вас же не миллионы показов в секунду. Да, соединение с базой медленнее, чем работа с массивом или со строкой, но В ДАННОМ ПРОЕКТЕ это не важно! А какие плюсы дает база: отсутствие такого бага, как в посте, возможность хранить неограниченно историю рекламы на сайте и многое другое. Да хотя бы возможность отслеживания уникальных показов и уникальных кликов! Только за это рекламодатели спасибо скажут! Учитывая данные, которые работают в Daos – прикручивай mysql и не парься.

    P.S.: вот только sqlite не надо plz. Да, sqlite меньше, проще и т.д., чем mysql. НО! Не на каждом хостинге есть, медленее, чем mysql. Да и не поддерживает многие вещи.

  63. # anonymous: 

    @Тормоз
    моё пояснение было понято или нет?

  64. #  Тормоз

    Тормоз, сделай DAO для бизнес-сущностей и разные драйвера — для баз, для файлов.

    Это? Нет, не понято :) Можно человеческим языком?

  65. # anonymous: 

    @Тормоз
    нет, это другой анонимус. там совсем нерелевантное твоей ситуации предложение.

    вот это пояснение

  66. #  Тормоз

    Понял теперь, спасибо. Но остаётся неясным вопрос, почему я так сделал изначально :) Блин, вот когда много времени проходит с момента написания кода, вспомнить уже тяжело. Наверняка не просто так же.

  67. # Одесский Сисадмин

    Я кстати тебе давно писал про это
    Прикручивать надо memcache, все sql идут в жопу

  68. # ПистоГанза: 

    В жопу идет как раз мемкеш, которого нет на большинстве хостингов =)

  69. # Одесский Сисадмин

    Большинство хостингов – говно

  70. # you: 

    Тормоз: Но сперва должен извиниться перед рекламодателями: вчера или сегодня сбросились все рекламные строчки

    Вчера приобрел Daos($66), а только что прочитал этот топ.
    Очень важно!!
    Тормоз, а на сегодняшний день решена проблема со сбрасыванем рекламных строчек?!! Мы, допустим, не хотим выглядеть обманщиками перед своими пользователями.
    6 000 уников, 60 000 просмотров

  71. # Тормоз

    А я выгляжу обманщиком что ли? Все строчки вернул вручную тогда, ну а сейчас вообще проблема решена. Ещё с 17 октября.

    Лично у меня с тех пор были сбросы ещё два или три раза, но это связано с внезапной перезагрузкой сервера. В таких условиях и база могла бы полететь. Каждый раз просто откатывался на прошлый день в резервных копиях, без всяких проблем.

    Про случаи сброса у других людей с тех пор ничего не известно. Скорей всего их просто не было.

Комментирование этой статьи закрыто.

Интересное Покупки ТехникаРазное Отдых Статьи Строительство Услуги Общество Хобби Культура Советы Уют