Потеря данных при репликации, IB 7.5

Access Violation, некорректное выполнение запросов или вызовов API, ошибки утилит командной строки, в общем все, что вам мешает работать

Модераторы: kdv, dimitr

Kabaev Sergey
Сообщения: 35
Зарегистрирован: 16 авг 2007, 15:13

Потеря данных при репликации, IB 7.5

Сообщение Kabaev Sergey » 16 авг 2007, 16:34

Столкнулся с потерей данных при репликации. Не решал ли кто-либо подобную проблему? Вот описание:

IB 7.5, режиим SuperServer, Win Server 2003, HyperThread включен.
Есть две базы - Оперативная и Аналитическая. В Оперативной данные текущего дня, в Аналитческой базе данные за год. Нынешний объем Аналитической базы 8 гигов. Ведется непрерываная репликация данных с Оперативной на Аналитическую. Кол-во перекачиваемых записей в сутки ~500.000. Пиковая нагрузка при перекачке ~30-50 записей/сек. Одновременных соединений с базой Оперативной ~50. С Аналитической ~10-15. Backup-restore Аналитической базы выполняется крайне редко, слишком долгая процедура.

Описание структуры данных базы на пальцах.
Есть таблица T_BENTITY (состояние бизнес-объекта, primary key field BEID). На эту таблицу ссылаются все таблицы с бизнес-объектами, у них тоже есть ссылочное поле BEID. Все изменения во всех таблицах Оперативной базы через механизм триггеров попадают в очередь репликации (одно изменение-одна запись в очереди). В очередь репликации записи обычно вываливаются небольшими блоками (1-1000 записей). Оттуда репликатор их последовательно проталкивает в Аналитическую базу.

Репликатор свой, работает непрерывно, режим работы транзакций ReadComitted, Wait. Использует компоненты IBX 6.08. На каждую запись в очереди репликации в обоих базах (Аналитике и в Оперативной) открывается по отдельной транзакции. Успешно прокачанной запись считается, если:
а) соотв. запрос в Аналитике прошел без exception. Если запрос типа update и закончился без exception, но ничего в Аналитической базе не поменял, то запись считается ошибочной;
б) запись успешно удалена из очереди репликации.
Поcле успешного окончания запись удаляется из очереди репликации.
По каждой записи ведётся лог - прошла или не прошла - во внешнем текстовом файле. Примечание: кол-во изменных записей в update запросах считывается через свойствo RowsAffected компонента TIBSQL.

Теперь описание проблемы.

Один из типичных случаев, выдран из лог-файла репликатора, как пример.
Рассматриваем две таблицы T_BENTITY (бизнес-сущность), T_RGOODS (прибывший товар). T_RGOODS ссылается на T_BEID по полю BEID.

16.08 3:09:58 Тип: Ok
SEQID: 27711
SQL: INSERT INTO T_BENTITY (BTIME,BCLASSID,BOWNERBEID,BSTATEID,BUSERBEID,BEID) VALUES ('2007-08-15 23:38:13.0000',310,1,11,1,2072261010057931)
SQLCHECK:

ЗЫ: INSERT INTO T_BENTITY в Аналитическую базу прошел успешно,
транзакция закрыта нормально.

16.08 3:09:58 Тип: Ok
SEQID: 27712
SQL: INSERT INTO T_RGOODS (RSALES,DUMMY,BARCODE,BEID,GDATE,GTIME,RECELINEID,UNKNOWNF,WDATE,RGOODSID,LOTID,UnMarked,MDATE,PARTNERID) VALUES (0,0,951763070814,2072261010057931,'2007-08-15','23:38:00.0000',2072261000000838,0,'2007-08-15',2072261000014885,1,0,'2007-08-15',2061861000000052)
SQLCHECK:

ЗЫ: INSERT INTO T_RGOODS прошел успешно, эта запись ссылается на только что вставленную запись в T_BENTITY

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

16.08 8:50:24 Тип: Внимание!
SEQID: 180354
SQL: UPDATE T_BENTITY SET BTIME='2007-08-16 08:50:07.0000', BCLASSID=310, BOWNERBEID=1, BSTATEID=15, BUSERBEID=1 WHERE BEID=2072261010057931
SQLCHECK: SELECT BEID FROM T_BENTITY WHERE BEID=2072261010057931
Update(delete) запрос не подействовал

ЗЫ попытка update записи в T_BENTITY. НО!!!! запись не найдена, update не выполнен, выдана ошибка. Репликатор сразу пытается исправить ошибку в базе и заново вставить пропавшую запись, есть у него такое умение. Вставка проходит успешно. Т.е. записи в Аналитической базе действительно не было, т.к. при исправляющей вставке не было ошибки по главному ключу. В предыдущих версиях репликатора исправляющей вставки не было, и обычно далее следовали ошибки при update-ах записей ссылающихся на T_BENTITY (в рассматриваемом случае это T_RGOODS)

Странная какая-то картинка. Такая ситуация была бы допустима, если какое-то рабочее место удалит запись в T_BENTITY из Аналитики, но это возможно только в том случае, если удалят ссылающуюся на неё T_RGOODS. А её никто не удалял, она в базе есть, это проверено.

Ошибок в логе IB за рассматриваемы промежуток времени не было. Были только INET/inet_error: read errno = 10054 - потеря коннекта с клиентом.

И еще IB был перезапущен за три минуты перед первоначальной вставкой, вот сообщение в логе

DC-DBS2 (Server) Thu Aug 16 03:03:11 2007
SERVER/set_process_affinity: hyper-threading ProcessAffinityMask is 3

DC-DBS2 (Server) Thu Aug 16 03:03:11 2007
SERVER/set_process_affinity: setting ProcessAffinityMask to 3

DC-DBS2 (Server) Thu Aug 16 03:03:11 2007
Server: setting SWEEP_QUANTUM to 250, USER_QUANTUM to 500,
SWEEP_YIELD_TIME to 0 ms, and MAX_THREADS to 1000
SQL_COMPILER_RECURSION to 2000


В-общем, прошу помощи!
Последний раз редактировалось Kabaev Sergey 16 авг 2007, 17:02, всего редактировалось 1 раз.

Merlin
Динозавр IB/FB
Сообщения: 1502
Зарегистрирован: 27 окт 2004, 11:44

Re: Потеря данных при репликации, IB 7.5

Сообщение Merlin » 16 авг 2007, 16:56

Kabaev Sergey писал(а): Backup-restore Аналитической базы выполняется крайне редко, слишком долгая процедура.

ЗЫ: INSERT INTO T_BENTITY в Аналитическую базу прошел успешно,
транзакция закрыта нормально.

SQL: UPDATE T_BENTITY SET BTIME='2007-08-16 08:50:07.0000', BCLASSID=310, BOWNERBEID=1, BSTATEID=15, BUSERBEID=1 WHERE BEID=2072261010057931

SQLCHECK: SELECT BEID FROM T_BENTITY WHERE BEID=2072261010057931
Update(delete) запрос не подействовал

ЗЫ попытка update записи в T_BENTITY. НО!!!! запись не найдена, update не выполнен, выдана ошибка. Репликатор сразу пытается исправить ошибку в базе и заново вставить пропавшую запись, есть у него такое умение. Вставка проходит успешно. Т.е. записи в Аналитической базе действительно не было, т.к. при исправляющей вставке не было ошибки по главному ключу.
Похоже на повреждённые индексы в аналитической базе. Тогда

Код: Выделить всё

SELECT BEID FROM T_BENTITY WHERE BEID=2072261010057931+0
должен вернуть две записи. Если это так - кроме b/r предстоит повозиться с истреблением дубликатов и восстановлением ссылочной целостности. Рестор в тот же файл делать не пытаться!

stix-s
Заслуженный разработчик
Сообщения: 557
Зарегистрирован: 13 дек 2005, 11:52

Re: Потеря данных при репликации, IB 7.5

Сообщение stix-s » 16 авг 2007, 17:07

Kabaev Sergey писал(а): Оттуда репликатор их последовательно проталкивает в Аналитическую базу.

Репликатор свой, работает непрерывно, режим работы транзакций !
репликатор просто инсертит(апейтит) в БД Аналитики или имеет право при каких-либо условиях там и удалять?
база аналитики только на чтение для пользователей или нет?
поскольку вы редко делаете бакап/рестор для аналитики (если вообще делали?), возможно и проверки над данной базой не запускали?
я к тому, что могли появиться ошибки (как сказал Merlin), которые вы проглядели
ЗЫ
Возможно лог при бакап/ресторе аналитики даст дополнительную информацию, несмотря на потраченное время, но только НЕ рестор в рабочую аналитику, а в новую базу
Последний раз редактировалось stix-s 16 авг 2007, 17:11, всего редактировалось 1 раз.

Kabaev Sergey
Сообщения: 35
Зарегистрирован: 16 авг 2007, 15:13

Сообщение Kabaev Sergey » 16 авг 2007, 17:08

Выполнил запрос

SELECT BEID FROM T_BENTITY WHERE BEID=2072261010057931+0

результат - одна запись

WildSery
Заслуженный разработчик
Сообщения: 1738
Зарегистрирован: 05 июн 2006, 16:19

Сообщение WildSery » 16 авг 2007, 17:11

Не понял про T_RGOODS. Там у тебя FK или нет?
Если нет - почему нельзя удалить мастер-запись?

Так же я не понял, откуда очевидно, что "ЗЫ: INSERT INTO T_BENTITY в Аналитическую базу прошел успешно". Только из лога репликатора?
На случай, если с базой и индексами всё ок - первым делом лезем в код репликатора, и смотрим, а не проглотит ли он по try...except какую-нибудь хитровывернутую ошибку вставки/коммита.

Kabaev Sergey
Сообщения: 35
Зарегистрирован: 16 авг 2007, 15:13

Сообщение Kabaev Sergey » 16 авг 2007, 17:11

stix-s: репликатор просто инсертит(апейтит) в БД Аналитики или имеет право при каких-либо условиях там и удалять?
база аналитики только на чтение для пользователей или нет?

Репликатор может удалить запись если соотв. запрос будет в очереди репликации. Но в данном случае для того чтобы удалить T_BENTITY нужно сперва удалить ссылающуюся на него запись в T_RGOODS. Там стоит огранчение целостности. Удаления T_RGOODS не было.

WildSery
Заслуженный разработчик
Сообщения: 1738
Зарегистрирован: 05 июн 2006, 16:19

Сообщение WildSery » 16 авг 2007, 17:16

Kabaev Sergey писал(а):Там стоит огранчение целостности
Т.е. сейчас запись в T_RGOODS ссылается вникуда?
Тогда у тебя точно битый индекс.

Kabaev Sergey
Сообщения: 35
Зарегистрирован: 16 авг 2007, 15:13

Сообщение Kabaev Sergey » 16 авг 2007, 17:18

WildSery писал(а):Не понял про T_RGOODS. Там у тебя FK или нет?
Если нет - почему нельзя удалить мастер-запись?

Так же я не понял, откуда очевидно, что "ЗЫ: INSERT INTO T_BENTITY в Аналитическую базу прошел успешно". Только из лога репликатора?
На случай, если с базой и индексами всё ок - первым делом лезем в код репликатора, и смотрим, а не проглотит ли он по try...except какую-нибудь хитровывернутую ошибку вставки/коммита.
Да стоит FK.

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

try{
if ( DM->TAC->Active == false)
DM->TAC->StartTransaction();
if ( DM->TOC->Active == false )
DM->TOC->StartTransaction();

// выполним запрос в АС
applyTrLogRecordToAC( sTrLog );

// удалить запись из очереди репликации
deleteRecordFormTrLog( sTrLog );

// подтвердить транзакции в АС
DM->TAC->Commit();
trRecordApplyedToAC = true;

// ... и ОС
DM->TOC->Commit();

// вывод в лог сообщения
saveMessageToLog( sTrLog, lmtRegular, "");
}
catch ( Exception & ex )
{
..... // обработка ошибок
}

Kabaev Sergey
Сообщения: 35
Зарегистрирован: 16 авг 2007, 15:13

Сообщение Kabaev Sergey » 16 авг 2007, 17:18

WildSery писал(а):
Kabaev Sergey писал(а):Там стоит огранчение целостности
Т.е. сейчас запись в T_RGOODS ссылается вникуда?
Тогда у тебя точно битый индекс.
Да. При условии, что не было исправляющей вставки. На старых версия репликатора за такой пропавшей записью следовали кучи ошибок, если были попытки update любых ссылающихся на неё записей.

Kabaev Sergey
Сообщения: 35
Зарегистрирован: 16 авг 2007, 15:13

Сообщение Kabaev Sergey » 16 авг 2007, 17:42

GFIX-ом БД Аналитики проверяли, ошибок не было.

Если индексы кривые, то вроде бы должна помочь проверка на поиск максимального значения (или я неправ?)

Сейчас выполнил
SELECT max(BEID) FROM T_RGOODS
и
SELECT max(BEID) FROM T_BENTITY

ошибок не было.

Merlin
Динозавр IB/FB
Сообщения: 1502
Зарегистрирован: 27 окт 2004, 11:44

Сообщение Merlin » 16 авг 2007, 17:45

Kabaev Sergey писал(а):Выполнил запрос

SELECT BEID FROM T_BENTITY WHERE BEID=2072261010057931+0

результат - одна запись
Прощения прошу, сглючил второпях. Надо

SELECT BEID FROM T_BENTITY WHERE BEID+0=2072261010057931

Merlin
Динозавр IB/FB
Сообщения: 1502
Зарегистрирован: 27 окт 2004, 11:44

Сообщение Merlin » 16 авг 2007, 17:47

Kabaev Sergey писал(а):GFIX-ом БД Аналитики проверяли, ошибок не было.

Если индексы кривые, то вроде бы должна помочь проверка на поиск максимального значения (или я неправ?)

Сейчас выполнил
SELECT max(BEID) FROM T_RGOODS
и
SELECT max(BEID) FROM T_BENTITY

ошибок не было.
Господи, да при чём тут макс. Проверить надо конкретную запись запросом, не использующим индекс.

Радикальное средство - b/r. Но он в такой ситуации может не пройти.

Kabaev Sergey
Сообщения: 35
Зарегистрирован: 16 авг 2007, 15:13

Сообщение Kabaev Sergey » 16 авг 2007, 19:04

А! Т.е. нужно было написать что-то типа
SELECT FROM T_BENTITY WHERE BEID = ....
PLAN T_BENTITY NATURAL ?

Ок, спасибо за совет. Завтра попробую.

stix-s
Заслуженный разработчик
Сообщения: 557
Зарегистрирован: 13 дек 2005, 11:52

Сообщение stix-s » 16 авг 2007, 20:13

Merlin писал(а):
Радикальное средство - b/r. Но он в такой ситуации может не пройти.
Последнее жутко заинтересовало
1 при битом индексе, если я правильно понял, можем поиметь дубли, несмотря на FK
2 путем танцев с бубном вокруг БД мы эти дубли находим
3 корежим вручную некое поле, дабы однозначно убить одну запись из дублей
4 убиваем ее
5 делаем b/r (в другую базу естессно)
6 вопрос - почему в данном случае рестор не отработает? ведь дубль по FK мы уже убили?

Merlin
Динозавр IB/FB
Сообщения: 1502
Зарегистрирован: 27 окт 2004, 11:44

Сообщение Merlin » 16 авг 2007, 20:25

stix-s писал(а):
Merlin писал(а):
Радикальное средство - b/r. Но он в такой ситуации может не пройти.
Последнее жутко заинтересовало
1 при битом индексе, если я правильно понял, можем поиметь дубли, несмотря на FK
2 путем танцев с бубном вокруг БД мы эти дубли находим
3 корежим вручную некое поле, дабы однозначно убить одну запись из дублей
4 убиваем ее
5 делаем b/r (в другую базу естессно)
6 вопрос - почему в данном случае рестор не отработает? ведь дубль по FK мы уже убили?
Этта... слово на... пишется раздельно, а зае...сь - с мягким знаком (С). Вредные дубли - они по PK, а не по FK. Это раз. О том и речь, что это сначала надо сделать, иначе можно напороться. Два - это таки FK. То есть, при повреждённых индексах в подчинённых таблицах могут оказаться записи-сИроты, а не дубликаты. Их тоже надобно будет выявить и, анализируя нарушения, принимать по ним решения - грохать, переводить на другого родителя или вставлять этого исчезнувшего после других нарушений, не связанных с индексами, родителя. Последнее бывает после лечения некоторых серьёзных повреждений через gfix -verify и gfix -mend. Единственная в моей практике база, на которую я таки плюнул и восстановил суточный бакап содержала около сотни тысяч таких сирот, руками в обозримое время было не разгрести.

Dimitry Sibiryakov
Заслуженный разработчик
Сообщения: 1436
Зарегистрирован: 15 сен 2005, 09:05

Сообщение Dimitry Sibiryakov » 17 авг 2007, 07:57

Чисто для проверки: какой диалект у базы и подключения?

Kabaev Sergey
Сообщения: 35
Зарегистрирован: 16 авг 2007, 15:13

Сообщение Kabaev Sergey » 17 авг 2007, 14:22

Диалект базы SQL 3. А вот что такое диалект подключения не знаю.

Kabaev Sergey
Сообщения: 35
Зарегистрирован: 16 авг 2007, 15:13

Сообщение Kabaev Sergey » 17 авг 2007, 15:11

Прощения прошу, сглючил второпях. Надо

SELECT BEID FROM T_BENTITY WHERE BEID+0=2072261010057931
выполнил, выборка пустая

SELECT BEID FROM T_BENTITY WHERE BEID=2072261010057931
PLAN (T_BENTITY NATURAL)

Также пустая выборка

SELECT BEID FROM T_BENTITY WHERE BEID=2072261010057931+0

т.е. тот же запрос что выполнял вчера. Вчера была выбрана одна запись. Сегодня выборка пустая. Похоже финиш.

stix-s
Заслуженный разработчик
Сообщения: 557
Зарегистрирован: 13 дек 2005, 11:52

Сообщение stix-s » 17 авг 2007, 20:15

Kabaev Sergey писал(а): Диалект базы SQL 3. А вот что такое диалект подключения не знаю.
Грубо говоря - как строка соединения в репликаторе прописана
(с какм диалектом к базе цепляешься)

stix-s
Заслуженный разработчик
Сообщения: 557
Зарегистрирован: 13 дек 2005, 11:52

Сообщение stix-s » 17 авг 2007, 20:24

вообще-то Merlin вещал
SELECT BEID FROM T_BENTITY WHERE BEID+0=2072261010057931
бэкап/рестор, я так понимаю не пробовал?
я понимаю, что при размере БД 8 Г такое предложение выглядит страшновато, но:
если база аналитики долгое время была бесхозна, то возможно из-за мусора ее реальный размер гораздо меньше (нездоровый оптимизм), но на нормальном железе - это часа 2 не более, может стоит попробовать?
у мена игровая база 2Г (в смысле для экспериментов создал скриптом)
на машинке типа Целерон 2000 с Мб 512 - 30 мин бакап+40мин рестор, если канешно ничего другого не делать

Ответить