LINUX.ORG.RU

Запись в БД из скрипта. Что делать если сервер временно не доступен?

 ,


0

1

Скрипт запускается по крону, формирует массив, значения из которого заносятся в цикле в базу mysql на удаленном сервере:

echo "INSERT INTO table (value1,value2) VALUES ('${Array[$i]}', '$Date');" \
| mysql -uuser -ppas -h some.host database

Иногда связь с сервером пропадает:

ERROR 2003 (HY000): Can't connect to MySQL server on  (110)

На ум приходят такие варианты:

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

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

★★

Я бы сделал так: при отсутствии связи делаем sleep на некоторое время, потом пробуем снова, если после трех попыток ничего не получилось, сохраняем данные локально, отправляем каким-либо образом уведомление админу. При следующем запуске пытаемся дописать неотправленные данные.

hippi90 ★★★★★
()

всегда писать в файл, а потом пытаться отправить неотправленные файлы

anonymous
()
Ответ на: комментарий от goingUp

это могут быть совершенно случайные обстоятельства, повлиять на которые нет возможности (сбои в работе интернет провайдеров и тп). собственно недоступность была обнаружена недавно и проявила она себя 3 раза за 4 года.

nerve ★★
() автор топика

Писать в файл. А еще не плохо присмотреться к транзакциям.

erfea ★★★★★
()

Это какбэ не задача программиста, варианты от «забить» и «повторить когда-нибудь» до «сообщить президенту».

ilovewindows ★★★★★
()

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

kachan ★★
()

Если вот прямо редко проблема возникает, то тупо

N=0
until echo "INSERT....| mysql"; do
  ((++N))
  if [ $N -eq 3 ] then
    mail -s"Mysql error" admin@example.com <<<"pechalka"
  fi
  sleep 10m
done
[ $N -ne 0 ] write_log "записали в базу с $N попытки"

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

legolegs ★★★★★
()
Последнее исправление: legolegs (всего исправлений: 1)

Посмотреть, как работает TCP congestion control, и использовать один из его методов восстановления.

iZEN ★★★★★
()
Последнее исправление: iZEN (всего исправлений: 1)
Ответ на: комментарий от kachan

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

nerve ★★
() автор топика
Ответ на: комментарий от legolegs

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

пока сделал так: если insert не проходит, то добавляем фанные в файл.

if ! echo "INSERT INTO table (value1,value2) \
           VALUES ('${Array[$i]}', '$Date');" \
   | mysql -uuser -ppas -h some.host database
  then
    echo "${Array[$i]} $Date" >> deferred
fi
при старте скрипта очередной раз проверяем - пустой ли файл и если нет, то пытаемся отправить из него данные. если отправка успешна - подчищаем файл.
if [ -s "deferred" ]; then
  while read -r val1 val2; do
    if echo "INSERT INTO orders (value1,value2) \
             VALUES ('$val1', '$val2');" \
       | mysql -usvn -psvn -h some.host database
      then
       sed -i '1d' deferred
    fi
  done < deferred
fi

nerve ★★
() автор топика
Последнее исправление: nerve (всего исправлений: 1)
Ответ на: комментарий от kachan

А смысл писать в файл? Если будет создаваться тот же запрос с теми же данными в след раз.

Не буквально это задача, но похожие я решаю через очередь в файлах или локальном mysql.

В частности в этом случае задача может так решаться.

Каждую порцию данных оформляем как задачу. Например, пишем в JSON-файл с указанием имени обработчика и данных для него.

Каталог с очередью задач в JSON мониторится обработчиком задач. Как только последний видит появление задачи (мониторинг по inotify и/или по cron), берёт один файл задачи, выполняет указанного там воркера/обработчика и если всё ок, то удаляет файл задачи. Если происходит какой-то отказ (например, нет связи с mysql и воркер из-за этого выпал с ошибкой), то до файла с задачей очередь дойдёт в другой раз.

KRoN73 ★★★★★
()
Ответ на: комментарий от KRoN73

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

kachan ★★
()
Ответ на: комментарий от nerve

Вы их и так получите в следующем запуске задачи(крона). Смысл писать в файлы? Зачем дублировать данные? Плюс делайте запросы пачками а не по 1, по 1к минимум, это быстрее.

kachan ★★
()
Ответ на: комментарий от kachan

делайте запросы пачками

с этим согласен

nerve ★★
() автор топика
Ответ на: комментарий от nerve

Плохое решение - сложное и ненадёжное.

1. В файл deferred лучше сразу класть SQL просто чтобы не нарваться на лишние ошибки парсинга при read.

2. Что если deferred выполнится не полностью? Если весь deferred выполняем за раз, то лучше его обернуть в BEGIN/COMMIT.

Например, так:

основной скрипт:

SQL="INSERT INTO table (value1,value2) \
           VALUES ('${Array[$i]}', '$Date');"
if ! mysql -uuser -ppas -h some.host database <<<"$SQL"
then
  echo "$SQL" >> deferred
fi

воркер:

if [ -s "deferred" ]; then
  if ( echo "BEGIN;"
       cat "deferred"
       echo "COMMIT;" ) \
       | mysql -usvn -psvn -h some.host database
  then
     : > deferred #truncate
  fi
fi

Остаётся небольшая вероятность дописывания deferred пока воркер его читает, это фиксится подходом «один таск - один файл», как Крон написал. Через mktemp несложно.

legolegs ★★★★★
()
Ответ на: комментарий от kachan

Избыточность какая-то

В чём конкретно?

засрать диск можно очень быстро

Если задачи не обрабатывать? Да. Но данные-то на обработку надо накапливать. Ты ещё скажи «INSERT в БД какие-то, так и базу засраь можно...»

вследствии с чем откажет пол системы

А, ну, если у тебя на весь сервер один раздел — то дальше можно не продолжать :)

KRoN73 ★★★★★
()
Ответ на: комментарий от KRoN73

>> Избыточность какая-то
В чём конкретно?

В данных, зачем их хранить в «10 местах» если они уже есть в базе?

>> засрать диск можно очень быстро

Если задачи не обрабатывать? Да. Но данные-то на обработку надо накапливать. Ты ещё скажи «INSERT в БД какие-то, так и базу засраь можно...»

Их не нужно накапливать, они уже есть.

А, ну, если у тебя на весь сервер один раздел — то дальше можно не продолжать :)

Нет, дело в том что все скрипты будут это делать, место закончится, и что дальше?

kachan ★★
()
Ответ на: комментарий от nerve

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

Что-то типо. id_from | id_to | status | table_from_id | table_to_id

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

Либо проще всего повторно посылать те же данные, просто перед началом работы при неудаче делать дифф 2х таблиц(дифф 2 таблицы по 10 лямов на норм серваке выполняется пару минут).

kachan ★★
()
Последнее исправление: kachan (всего исправлений: 1)
Ответ на: комментарий от kachan

В данных, зачем их хранить в «10 местах» если они уже есть в базе?

Такое впечатление, что мы разный тред читаем. Ничего, что в топикстарте как раз и стоит задача c гарантией сохранить данные в базу?

Откуда ты выкопал «10 мест»? JSON-так — место промежуточного хранения, куда скрипт с гарантией может быстро положить данные и откуда данные с гарантией уйдут потом в БД. После чего во временном хранилище будут удалены.

Их не нужно накапливать, они уже есть.

Ты сейчас про какую задачу? А то в топикстарте данные-то есть, но проблема их гарантированно сохранить.

дело в том что все скрипты будут это делать, место закончится, и что дальше?

Почему оно кончится? Потому что MySQL-сервер будет убит и не станет подниматься в течении года?

KRoN73 ★★★★★
()
Ответ на: комментарий от KRoN73

Откуда ты выкопал «10 мест»? JSON-так — место промежуточного хранения, куда скрипт с гарантией может быстро положить данные и откуда данные с гарантией уйдут потом в БД. После чего во временном хранилище будут удалены.

Будь у тебя больше 10-20к записей я думаю ты бы понял. Я работал с базой в которой сумарное количество актуальных записей по одной сущности больше 2х милиардов (еще раз повторюсь, только одна сущность). И если бы мы на ~300 наших кронов создавали сохранение в файлы то уже давно бы вся система навернулась, будь бы отключен коннект к бд хоть на 5 минут.

Ты сейчас про какую задачу?
Скрипт запускается по крону, формирует массив, значения из которого заносятся в цикле в базу mysql на удаленном сервере:

Про эту, данные есть раз есть откуда формировать.

Почему оно кончится? Потому что MySQL-сервер будет убит и не станет подниматься в течении года?

Будь у тебя хоть 10тб под это, оно закончится будь у тебя нормальные обьёмы данных.

kachan ★★
()
Ответ на: комментарий от KRoN73

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

kachan ★★
()
Ответ на: комментарий от kachan

которые нельзя будет сгенерить по прошествию времени.

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

nerve ★★
() автор топика
Ответ на: комментарий от kachan

Я работал с базой в которой сумарное количество актуальных записей по одной сущности больше 2х милиардов

Ну и какое отношение это имеет к задаче топикстартера?

KRoN73 ★★★★★
()

Фифо/сисв очередь, при фэйле записи — сложить обратно в очередь.

nihirash ★★★
()

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

И что это означает? Что база, пытаясь всосать этот кусок встаёт колом надолго? Но другие данные при этом нормально бы вставились?

vodz ★★★★★
()
Ответ на: комментарий от vodz

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

nerve ★★
() автор топика
Ответ на: комментарий от kachan

Что мешает генерить данные за

вы как-то не так поняли или я не понимаю.

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

что мешает генерить такие данные? уникальность данных.

nerve ★★
() автор топика
Ответ на: комментарий от nerve

означает буквально следующее

Оригинальное пояснение ТЗ «скрипт должен выполнится до конца».

вы как-то не так поняли или я не понимаю.

Ну так немудрено, с таким то описанием.

Вопрос то в чём? Если ждать записи генератор данных не может, значить надо сделать спуллинг. А если обязан убедиться, что записано, значить должен долбиться пока не запишется. Третьего не дано и вопрос в топике не понятен.

vodz ★★★★★
()
Ответ на: комментарий от kachan

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

Ыгсперд по хайлоаду и большим таблицам когда нибудь слышал слово «метрики» ? Ыгсперд ... знал бы чего это люди гибнут за металл бьются за гарантированную доставку онных :)

anonymous
()
Ответ на: комментарий от anonymous

Дампы никто теперь не сохраняет за время? «метрики» при чём?

kachan ★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.