Обработка больших данных php
Обработка больших объемов данных на PHP без тайм-аута браузера
У меня массив мобильных номеров, около 50 000. Я пытаюсь обрабатывать и отправлять массовые SMS на эти номера, используя сторонний API, но браузер замерзает в течение нескольких минут. Я ищу лучший вариант.
Обработка данных включает проверку типа мобильного номера (например, CDMA), назначение уникальных идентификаторов всем номерам для дальнейших ссылок, проверка уникальных сборов за сеть / страну и т. Д.
Я думал о очередности данных в базе данных и использовании cron для отправки около 5 тыс. Партиями каждую минуту, но это займет много времени, если будет много сообщений. Каковы мои другие варианты?
Я использую Codeigniter 2 на сервере XAMPP.
Я бы написал два сценария:
Я предполагаю, что эти числа находятся в базе данных, поэтому вам следует добавить новый столбец под названием isSent (или как вам нравится).
Этот следующий параграф, который вы набрали, должен быть поставлен в очередь и, возможно, сделан ночью / еженедельно / в случае необходимости. Если у вас нет определенной причины, это не должно делаться навалом по требованию. Вы даже можете добавить столбец в db, чтобы увидеть, когда он был последний раз проверен, чтобы, если число не было проверено, по крайней мере, за X дней, вы можете выполнить проверку этого числа по требованию.
Обработка данных включает проверку типа мобильного номера (например, CDMA), назначение уникальных идентификаторов всем номерам для дальнейших ссылок, проверку уникальных сборов за сеть / страну и т. Д.
Но это все еще возвращает вас к тому же вопросу о том, как это сделать для 50 000 номеров одновременно. Поскольку вы упомянули задания cron, я предполагаю, что у вас есть SSH-доступ к вашему серверу, что означает, что вам не нужен браузер. Эти задания cron могут выполняться через командную строку как таковую:
/ usr / bin / php /home/username/example.com/myscript.php
Моя рекомендация состоит в том, чтобы обрабатывать 1000 номеров за раз каждые 10 минут через cron и время, сколько времени потребуется, а затем сохранить его в БД. Поскольку вы используете задание cron, похоже, что это не чувствительные к времени SMS-сообщения, поэтому они могут быть распространены. Как только вы узнаете, сколько времени понадобилось для запуска этого скрипта 50 раз (50 * 1000 = 50 тыс.), Вы можете обновить свое задание cron, чтобы работать чаще / реже.
Кроме того, возможно, вы заметили set_time_limit (0), это скажет PHP не истекать тайм-аут после 30 секунд. Если вы можете изменить файл PHP.ini, вам не нужно вводить эту строку кода. Даже если вы можете редактировать файл PHP.ini, я по-прежнему рекомендую не изменять эту функцию, так как вы можете захотеть, чтобы другие страницы были в тайм-ауте.
Если это не одноразовая ситуация, подумайте над разработкой лучшего решения.
То, что вы в основном хотите, это очередь, которую может обрабатывать связанный с браузером процесс, и рабочие процессы 1-N могут читать и обновлять.
Помещение работы в очередь должно быть довольно недорогим – возможно, множество простых инструкций INSERT для SQL RDBMS.
Затем у вас может быть демона или два (или 100, распределенных на нескольких серверах), которые считываются из очереди и обрабатываются. Вы захотите быть осторожными здесь и избегать двух рабочих, которые берут на себя ту же задачу, но это не сложно скопировать.
Таким образом, ваш рабочий процесс, связанный с браузером, – это: нажмите кнопку, которая заставит кучу вещей быть добавленными в очередь, а затем перенаправляется на какой-то интерфейс «статус очереди», где пользователь может наблюдать за системой, чтобы пережевывать всю свою работу.
Такая система хороша, потому что ее легко масштабировать по горизонтали.
EDIT: ответ Christian Sciberras идет в этом направлении, за исключением того, что браузер заканчивает движение с обеих сторон (он добавляет в очередь, затем управляет рабочим процессом)
Cronjob был бы вашим лучшим выбором, я не понимаю, почему это займет больше времени, чем делать это в браузере, если ваша единственная проблема на данный момент – это время выхода браузера.
Обработка больших файлов в PHP с помощью генераторов
Представим, что нам необходимо разобрать большой файл с логами либо еще с какими-то данными.Как правило, при работе с большими файлами самой главной проблемой становится объем памяти потребляемый скриптом. Особенно это актуально на виртуальных хостингах, где объем выделяемой памяти, как правило ограничен.
Вот здесь то, нам и помогут PHP генераторы. О генераторах в PHP я уже рассказывал здесь. Их преимущество состоит в том, что для обработки даже очень больших файлов не требуется огромное количество памяти, а вполне достаточно то, что предоставляется дефолтной конфигурацией.
Итак, вот пример скрипта, который читает большой csv файл логов (допустим) и выполняет над ним какие-то операции:
В чем здесь преимущество спросите Вы? А вот, в чем. При вызове в цикле foreach функции-генератора getRows
не происходит чтение всего файла целиком, а происходит чтение одной строки из файла DATA_LOG.csv. Тем самым экономится память.
При каждом следующем выводе, эта функция будет выводить последующую порцию данных.
Таким образом, с введением генераторов в PHP у разработчиков появился мощный инструмент, который позволяет писать быстрые и экономные программы.
Копирование материалов разрешается только с указанием автора (Михаил Русаков) и индексируемой прямой ссылкой на сайт (http://myrusakov.ru)!
Добавляйтесь ко мне в друзья ВКонтакте: http://vk.com/myrusakov.
Если Вы хотите дать оценку мне и моей работе, то напишите её в моей группе: http://vk.com/rusakovmy.
Если Вы не хотите пропустить новые материалы на сайте,
то Вы можете подписаться на обновления: Подписаться на обновления
Если у Вас остались какие-либо вопросы, либо у Вас есть желание высказаться по поводу этой статьи, то Вы можете оставить свой комментарий внизу страницы.
Порекомендуйте эту статью друзьям:
Если Вам понравился сайт, то разместите ссылку на него (у себя на сайте, на форуме, в контакте):
Комментарии ( 0 ):
Для добавления комментариев надо войти в систему.
Если Вы ещё не зарегистрированы на сайте, то сначала зарегистрируйтесь.
Copyright © 2010-2021 Русаков Михаил Юрьевич. Все права защищены.
Обработка больших данных php
Есть большой массив, примерно 640.000 строк, если в файле, то 15Мб информации.
Как работать с таким массивом не перегружая сервер? В основном надо рандомно выбирать данные из него, порядка 2.000 строк за раз, при этом удаляя то, что было выбрано, т.е. уменьшая сам массив.
при всей моей нелюбви, должен сказать, что здесь, как-раз, задача для мускула. Файл перегнать в БД и пользовать.
Если есть желание остаться с файлом, то не мудрить, а читать файл построчно, одновременно записывая новый (без удаленных строк). Работать будет чуть медленнее, но зато не перегружая сервак.
Загнать этот массив в mysql базу.
Проблема в том, что таких массивов может быть и 100 и 1000
P.s. в мускул загонял, вес одного массива 20мб в таблице.
Критичен размер базы?
На самом деле есть потеря в дисковом пространстве при размещении подобной информации в базе.
Но при работе с массивами вы сталкиваетесь с некоторыми сложностями, а именно:
— во первых этой громадиной в памяти работать не совсем удобно.
— быстрое удаление из массива в php при таких размерах становится достаточно нетривиальной задачей.
когда я ее написал, была самая быстрая библиотека на питоне (или перле, точно не помню), там была скорость 5000 в секунду)
Очень странно. order by rand() жутко тормозная штука, которая при работе выбирает все записи из таблицы, потом их сортирует и часть (нужную) возвращает. Использовать ее при большом количестве записей это садизм. А Вы при4-5млн записей ее используете?
humbert:
Есть большой массив, примерно 640.000 строк, если в файле, то 15Мб информации.
Как работать с таким массивом не перегружая сервер? В основном надо рандомно выбирать данные из него, порядка 2.000 строк за раз, при этом удаляя то, что было выбрано, т.е. уменьшая сам массив.
1) Если строки ограниченного и небольшого размера, то можно упорядочить структуру, конвертнуть файл в файл со строками одного размера и с ними работать.
2) Загнать все-таки в базу. Неужели так велика разница между 15Мб в файлах и 20Мб в базе? Если еще важна скорость, то memory table могут неслабо помочь.
3) Вариант 2, только в sqllite загнать, что бы с мускулом не городить и с файлами по сути работать.
4) Можно сделать как предложил bearmen, его вариант это по сути создание своей простой БД, единственное преимущество которого в простоте. Но для простоты опять же годится sqllite
тоже заметил да не стал коментировать)
Как обрабатывать терабайты данных в 1000 потоков на PHP — Hadoop/MapReduce
Уже слышали про Bigdata? Ну да, веб растет, данных становится больше и их нужно держать под контролем и периодически анализировать. Базы данных — лопаются под нагрузкой, реляционная теория не совсем справляется с задачей, нужно решение. Маркетинг активно давит сверху, а железо острыми углами — снизу и попахивает суицидом.
В этом посте постараюсь дать конкретные работающие рецепты и куски кода с краткими теоретическими выводами, как же обрабатывать >=терабайты в >=1000 потоков на PHP. Чтобы можно было взять и решить задачу, не теряя времени и не забивая голову теорией.
Однако, если вдруг стало подташнивать и закружилась голова, можно дальше не читать — а полюбоваться на прекрасных птичек и забыть о вышенаписанном. Но будьте на чеку, Bigdata может завтра взять и постучаться в дверь 😉
Как обычно делается
Как обычно бывает в вебе. Складывают данные в БД, пока не лопнет. Если лопается, начинаются разговоры про MySQL sharding, partitioning, вспоминают про мульти-мастер кластер в оперативной памяти.
Если не помогает, начинаются поиски и внедрения NoSQL решения типа redis или облачного сервиса типа DynamoDB. Неплохо себя зарекомендовал в качестве эффективного поискового движка по объемным данным Sphinx.
Подсознательно идет расчет — сохраним в БД и потом проанализируем информацию. И это нередко работает. Но не всегда… и это «не всегда» становится чаще.
Данных еще больше, требуется он-лайн аналитика
Не всегда можно ответить бизнесу — подождем сутки, проанализируем логи/данные и дадим циферки. Бизнесу часто важно иметь циферки в онлайне, управлять ситуацией по приборам с живыми стрелочками.
Страшно представить управление самолетом путем анализа записанной в черные ящики информации один раз в сутки в гостинице для пилотов 🙂
Когда поток данных становится еще интенсивнее или бизнес-логика требует наличия текущей информации по еще не обработанным данным… Тогда нам помогают инструменты «потокового анализа» типа:
1) pinba
2) Amazon Kinesis
3) Потоковые парсеры на базе nginx/ragel
Полезно хотя бы один раз каждый из этих бесценных инструментов понять с листочком и карандашом, еще полезнее — «переспать» с мануалом и прототипом минимум ночь.
Особо хочется выделить здесь pinba за простоту настройки и легкость эксплуатации и минимум создаваемой нагрузки. Организовать сбор статистики по производительности веб-приложения в браузере его клиентов на основании js Navigation Timing API — делается в 2 файла на PHP на 30 строк.
Когда же нет возможности анализировать данные онлайн — начинаются поиски решения параллельного анализа накопленных данных и связанных с ним алгоритмов.
Параллельная обработка массивов данных
Есть список объектов, допустим это файлы в облаке s3, которых у вас — десятки миллионов. Как бы мы не доверяли облаку, нужно эти файлы периодически выгружать в другое облако/серверы. Каждый файл шифруется, сжимается, происходят другие операции и копируется.
Эти задачи подпадают под общий алгоритм «разделяй и властвуй»:
— распределяем задачки на части
— каждую часть обрабатываем отдельно и параллельно с другими частями
— объединяем результаты через агрегацию
Для PHP можно попытаться решить эту задачу используя очередь типа RabbitMQ и/или Gearman — но придется очень много повозиться для решения исключительных ситуаций, шардинга общей файловой системы, кластеризации на 20 серверов и т.п.
Поэтому если ваша задача может решиться в 30 потоков PHP на одном сервере — перечисленных инструментов, как правило, достаточно. Однако если вам «не повезло» и нужно за час обработать несколько терабайт и железа дают сколько унесешь — выход есть 🙂
Да, да, конечно это Hadoop, реализующий коррелирующую с фото девушек выше парадигму MapReduce 😉
Кому лень читать дальше и хочется узнать рецепт, вот пример исходной задачи и ее решения на Hadoop:
Нужно сжать, зашифровать и перенести 10 млн. файлов из бакета1 s3 в бакет2 s3.
Если делать средствами PHP на сервере, то можно форкануть максимум ну 20-30 потоков PHP, которые будут каждый выполняться в своем процессе. И это займет несколько недель. А объем данных растет и нужно системное решение.
Если то же самое делать средствами Hadoop, то задачу можно выполнить за час, но на большом количестве железок. Если выбрать разумное число железок с 15 потоками на каждой — то можно уложиться в 2 дня.
Т.е. если через полгода число файлов для обработки вырастет с 10 млн. до 50 млн., нужно будет поменять лишь одну циферку в конфиге запуска кластера Hadoop, увеличив число железок лишь.
Разве не красиво и системно? 🙂
Hadoop
Вообще это довольно большой продукт и недельки на 24/7 чтения мануалов наверно не хватит — но этого и не требуется. Мы научимся использовать эту технологию эффективно и быстро, экономя ваше и наше время.
Установка
Помимо установки java-софта потребуется еще настроить кластерную файловую систему. Зачем — а как будут ноды кластера обмениваться общими файлами? Но мы поступим хитрее — запустим кластер Hadoop в Амазоне. Там все уже настроено и установлено.
Подготовка map и reduce скриптов
Вот тут самое интересное в посте. Hadoop позволяет задействовать скрипты на любом языке — и провести сортировку файла на bash или обработку на PHP/Python/Perl.
Скриптики читают из стандартного ввода и пишут в стандартный вывод. Ну что может быть проще?
Скриптиков должно быть 2: mapper, reducer.
Если нужно просто распараллелить задачу на N серверов — достаточно написать один mapper.
Пример mapper
Если агрегированная статистика не нужна, второй скриптик — не нужен. Если нужна, пишем reducer:
Пример reducer
Инициализация серверов кластера
Т.к. скрипты наши на PHP, необходимо подготовить скрипт инициализации, выполняемый на каждом сервере кластера:
Выгружаем скрипты на PHP и bash в облако (s3)
Выгрузка данных для обработки в s3
Просто, например с помощью s3cmd, выгружаем исходные данные для обработки в папку в s3. Эти данные потом расплывутся по кластеру автоматически. Выгрузить можно сколько угодно данных и пусть кластер с ними мучается.
Запуск обработки данных в кластере
И напоследок такая вкусняшка — запускаем кластер для обработки наших данных.
Тут важно подобрать правильно число железок для размножения кластера — чем больше, тем конечно быстрее. В данном примере мы устанавливаем не больше 15 процессов на один сервер. Можно больше, это зависит от объема оперативной памяти, но осторожно — следим за ее расходом.
После отработки кластера в логах можно будет увидеть агрегированную статистику, логи также будут выгружены в s3.
Обычно скорость обработки, которая до этого делалась неделями — поражает, вдохновляет и выводит на новый уровень осознания IT-континиума не хуже последней части «300 спартанцев» 🙂
Итоги
В результате у вас появляется бизнес-инструмент, управляемый 2 скриптами на PHP. Число серверов (—num-instances 5) напрямую влияет на скорость обработки загруженного массива данных. В принципе никто не запрещает запустить 100 серверов с 10 потоками на каждом и обработать данные значительно быстрее, чем можно было сделать на одном сервере используя очередь заданий.
Используя данную технологию простым и понятным образом, мы на одном из наших проектов сократили время обработки десятков миллионов объектов в s3 с недель до 2 дней.
Коллеги, если есть вопросы, пожалуйста спрашивайте в комментах и посещайте наши конференции — мы с удовольствием поделимся опытом. И всем удачи в реализации веб-проектов и побед над Bigdata!
Как прочитать большой файл средствами PHP (не грохнув при этом сервак)
PHP разработчикам не так уж часто приходится следить за расходом памяти в своих приложениях. Сам движок PHP неплохо подчищает мусор за нами, да и модель веб-сервера с контекстом исполнения, «умирающим» после выполнения каждого запроса, позволяет даже самому плохому коду не создавать больших долгих проблем.
Однако, в некоторых ситуациях, мы можем столкнуться с проблемами нехватки оперативной памяти — например, пытаясь запустить композер на маленьком VPS, или при открытии большого файла на сервере не богатом ресурсами.
Последняя проблема и будет рассмотрена в этом уроке.
Мерила Успеха
При проведении любых оптимизаций кода, мы всегда должны замерять результаты его выполнения до и после, для того чтобы оценивать эффективность(или пагубность) наших оптимизаций.
Обычно измеряют загрузку CPU и использование оперативной памяти. Часто бывает, что экономия одного, ведёт к увеличенным затратам другого и наоборот.
В асинхронной модели приложения(мультипроцессорные и многопоточные) всегда очень важно следить как за процессором, так и за памятью. В классических приложениях контроль ресурсов становится проблемой лишь при приближении к лимитам сервера.
Измерять использование CPU внутри PHP плохая идея. Лучше использовать какую-либо утилиту, как top из Ubuntu или macOS. Если вы у вас Windows, то можно использовать Linux Subsystem, чтобы иметь доступ к top.
В этом уроке мы будем измерять использование памяти. Мы посмотрим, как память расходуется в традиционных скриптах, а затем применим парочку фишек для оптимизации и сравним результаты. Надеюсь, к концу статьи, читатель получит базовое понимание основных принципов оптимизации расхода памяти при чтении больших объемов данных.
Будем замерять память так:
Эту функцию мы будем использовать в конце каждого скрипта, и сравнивать полученные значения.
Какие есть варианты?
Существует много разных подходов для эффективного чтения данных, но всех их условно можно разделить на две группы: мы либо считываем и сразу же обрабатываем считанную порцию данных(без предварительной загрузки всех данных в память), либо вовсе преобразуем данные в поток, не заморачиваясь над его содержимым.
Давайте представим, что для первого варианта мы хотим читать файл и отдельно обрабатывать каждые 10000 строк. Нужно будет держать по крайней мере 10000 строк в памяти и передавать их в очередь(в какой бы форме она не была реализована).
Для второго сценария, предположим, мы хотим сжать содержимое очень большого ответа API. Нам не важно, что за данные там содержатся, важно вернуть их в сжатой форме.
В обоих случаях нужно считать большие объемы информации. В первом, нам известен формат данных, во втором, формат значения не имеет. Рассмотрим оба варианта.
Чтение Файла Строка За Строкой
Есть много функций для работы с файлами. Давайте напишем с их помощью свой ридер:
Тут мы считываем файл с работами Шекспира. Размер файла около 5.5MB и пиковое использование памяти 12.8MB.
А теперь, давайте воспользуемся генератором:
Файл тот же, а пиковое использование памяти упало до 393KB! Но пока мы не выполняем со считываемыми данными никаких операций, это не имеет практической пользы. Для примера, мы можем разбивать документ на части, если встретим две пустые строки:
Хотя мы разбили документ на 1,216 кусков, мы использовали лишь 459KB памяти. Всё это, благодаря особенности генераторов — объем памяти для их работы равен размеру самой большой итерируемой части. В данном случае, самая большая часть состоит из 101,985 символов.
Генераторы могут применяться и в других ситуациях, но данный пример хорошо демонстрирует производительность при чтении больших файлов. Возможно, генераторы один из лучших вариантов для обработки данных.
Пайпинг между файлами
В ситуациях, когда обработка данных не требуется, мы можем пробрасывать данные из одного файла в другой. Это называется пайпингом( pipe — труба, возможно потому что мы не видим что происходит внутри трубы, но видим что входит и выходит и неё). Это можно сделать с помощью потоковых методов. Но сперва, давайте напишем классический скрипт, который тупо передает данные из одного файла в другой:
Неудивительно, что этот скрипт использует намного больше памяти, чем занимает копируемый файл. Это связано с тем, что он должен читать и хранить содержимое файла в памяти до тех пор пока файл не будет скопирован полностью. Для маленьких файлов в этом нет ничего страшного, но не для больших.
Давайте попробуем стримить(или пайпить) файлы, один в другой:
Код довольно странный. Мы открываем оба файла, первый на чтение, второй на запись. Затем мы копируем первый во второй, после чего закрываем оба файла. Возможно будет сюрпризом, но мы потратили всего 393KB.
Для того чтобы осуществить задуманное этим способом потребовалось 581KB. Теперь попробуем сделать то же самое с помощью потоков.
Потратили немного меньше памяти(400KB) при одинаковом результате. А если б нам не нужно было сохранять картинку в памяти, мы могли бы сразу застримить её в stdout :
Другие потоки
Существуют и другие потоки, в/из которых можно стримить:
Фильтры
Есть еще одна фишка, которую мы можем использовать — это фильтры. Промежуточный вариант, который дает нам немного контроля над потоком, без необходимости детально погружаться в его содержимое. Допустим, мы хотим сжать файл. Можно применить zip extension:
Хороший код, но он потребляет почти 11MB. С фильтрами, получится лучше:
Здесь мы используем php://filter/zlib.deflate который считывает и сжимает входящие данные. Мы можем пайпить сжатые данные в файл, или куда-нибудь еще. Этот код использовал лишь 896KB.
Я знаю что это не совсем тот же формат, что и zip архив. Но задумайтесь, если у нас есть возможность выбрать иной формат сжатия, затратив в 12 раз меньше памяти, стоит ли это делать?
Чтобы распаковать данные, применим другой zip фильтр.
Вот парочка статей, для тех кому хотелось бы поглубже погрузиться в тему потоков: “Understanding Streams in PHP” и“Using PHP Streams Effectively”.
Кастомизация потоков
fopen и file_get_contents имеют ряд предустановленных опций, но мы можем менять их как душе угодно. Чтобы сделать это, нужно создать новый контекст потока:
В этом примере мы пытаемся сделать POST запрос к API. Прописываем несколько заголовков, и обращаемся к API по файловому дескриптору. Существует много других опций для кастомизации, так что не будет лишним ознакомиться с документацией по этому вопросу.
Создание своих протоколов и фильтров
Перед тем как закончить, давайте поговорим о создании кастомных протоколов. Если посмотреть в документацию, то можно увидеть пример:
Написание своей реализации такого тянет на отдельную статью. Но если все же озадачиться и сделать это, то можно будет легко зарегистрировать свою обертку для стримов:
Аналогичным образом, можно создать и кастомные фильтры потока. Пример класса фильтра из доков:
И его также легко зарегистрировать:
Хотя это не самая частая проблема, с которой мы мучаемся, очень легко накосячить при работе с большими файлами. В асинхронных приложениях, вообще очень просто положить весь сервер, если не контролировать использование памяти в своих скриптах
Надеюсь, что этот урок подарил вам несколько новых идей(или освежил их в памяти) и теперь вы сможете работать с большими файлами гораздо эффективнее. Познакомившись с генераторами и потоками( и перестав использовать функции по типу file_get_contents ) можно избавить наши приложения от целого класса ошибок. That seems like a good thing to aim for!