32
Реализация восстановления после аварий Сергей Бурладян

Реализация восстановления после аварий / Сергей Бурладян (Avito)

  • Upload
    ontico

  • View
    996

  • Download
    3

Embed Size (px)

Citation preview

Реализация восстановленияпосле аварий

Сергей Бурладян

Avito• база 2 Тб• 4 сервера: master, standby index, standby site, standby

backup• 4 реплики * 2: сайта, индексации, платежей, дельты

объявлений• sphinx• экспорт в DWH• xrpc (pgq)• xdb: 16 баз, шардинг• 6 часов backup• 4 часа восстановления из backup, 8 часов применения

WAL• простой 10 минут

AvitoКак всё это не потерять при авариях?

Аварии• Master

• Standby

• Sphinx

• DWH

• Xrpc

• Xdb

• Replica

• Backup

Master• UPDATE без WHERE

• backup standby, 12 часов задержки применения WAL

– pg9.2: if [ "$ftime" -gt "$apply_time" ]

– pg9.4: recovery_min_apply_delay (commit time)

Master• promote standby

• асинхронная репликация

– теряем часть транзакций

– необходимы процедуры восстановления

• руками сложно, скрипт переключения

Masterpromote создаёт на новом мастере параллельную ветвь времени, а все остальные остаются в старой

• в DWH объявления, которых нет

• xrpc отработал для несуществующих данных

• sphinx выдаёт несуществующие объявления

• sequences начались снова с момента аварии

• логические реплики не работают

MasterНе всё так плохо :-)

• выгрузить в DWH промежуток аварии с запасом в час снова

– 10 минут — мало изменят отчёты, можно игнорировать

• xrpc, повезло:

– геокодинг

– локально для асинхронных вызовов на мастере

– карма

– TODO, "обратные" функции, триггеры типа undo londiste

MasterНе всё так плохо :-)

• sphinx

– сайта, через 10 минут создан с нуля

– backoffice, не критично, зарефрешить последний час, пересоздаётся с нуля раз в месяц

• sequences, открутить важные вперёд на 100 000

– item_id

– user_id

– order_id

• UNDO для логических реплик

Undo• subscriber undo [TICK_ID]

– rewind all tables with it UNDO log

• subscriber add-undo-all

– enable UNDO log on all tables

• subscriber remove-undo-all

– disable UNDO log on all tables

• --enable-undolog

– replay generate UNDO log

Undo• триггер на таблицах subscriber

• undo_log таблица с 'I,'U','D', hstore и tick_id

• получение tick_id с мастера

• все строки во всех наблюдаемых таблицах с tick_id больше мастера — отменить

– INSERT -> DELETE

– UPDATE -> UPDATE

– DELETE -> INSERT

• londiste.completed: last_tick_id = master tick_id

Скрипт переключения• 3 standby — выбираем ближайший к мастеру

• останавливаем другие standby

– pg9.2, pg9.4 можно не перезапускать

• promote

• сдвиг sequences вперёд

• londiste undo

• запускаем standby

• ждём новый timeline на standby

• обновление в DNS

Скрипт переключения• ждём новый timeline на standby

– нет SQL функции

– протокол репликации:

psql -h "$host" -F' ' -c 'IDENTIFY_SYSTEM' \

'dbname=replication replication=true'

systemid | timeline | xlogpos

---------------------+----------+------------

6080348884119699418 | 1 | 1/4E0E42D0

Standby• 3 standby

• всё на мастер с потерей части трафика

• быстрое создание нового

– из архива (1 Gbp, NFS HDD) — 12 часов

– с соседнего standby pg_basebackup (10 Gbps, SSD, мало WAL применять) — 4-6 часа

Sphinx сайта• отдельная реплика для индексации

• данные подготовлены и разложены для быстрой вычитки в sphinx

• реплика: все данные в shared_buffers

• полная вычитка всех активных объявлений и перестроение всего индекса каждые 10 минут

• через 10 минут — все индексы готовы заново!

Экспорт в DWH• отдельная реплика со всеми дельтами всех

объявлений за последние 4 дня

– ручной запуск экспорта с указанием промежутка времени

• архив за полгода

• в крайнем случае — pause standby и заново выгрузить все объявления

Базы-клиенты xrpc• так как xrpc поверх pgq — можно заново проиграть

(redo) часть событий на восстановленной базе

Xdb• бинарная репликация

• 8 машин, standby на соседней

xdb1 -> xdb2, xdb2 -> xdb3, ..., xdb8 -> xdb1

• задержка проигрывания — 4 дня

Реплика• на основе возможностей postgres

– view

– deferred триггер

• подготавливаются данные на мастере в таблице

• londiste реплицирует готовые данные в реплику

Реплика• мастер: набор таблиц с данными для выдачи на сайте

• deferred триггер на каждой, вызывает refresh функцию

• view site_data_v с join по item_id

• таблица site_data_m

• refresh функция:– блокировка item_id– delete from site_data_m where item_id = i_item_id– insert into site_data_m select * from site_data_v where

item_id = i_item_id

• londiste на site_data_m

Реплика• отдельный сервер (* N)

• shared_buffers = sizeof(site_data_m + indexs)

• всё в памяти, fsync=off

• 7000 TPS чтение

• 1000 событий в сек. в очередь на мастере

• londiste (pgq): учёт транзакций, tick_id

Авария реплики• pgq — два или больше потребителя одной очереди

• переключаемся на копию

• упавшую — копируем с рабочей

• заново инициализировать — долго

– реплика сайта — 4 часа

– реплика индексации — 8 часов

• делаем копию с оставшейся реплики

Авария репликиАлгоритм копирования:

• stop londiste

• преподписать к очереди

• pg_dump -f

• pg_restore -j10

• repca: UPDATE londiste.consumer

• master: UPDATE pgq.subscription

• start londiste

• 15 минут!

Авария реплики– pgqadm ticker.conf unregister ОЧЕРЕДЬ 'название londiste

consumer'– pgqadm ticker.conf register ОЧЕРЕДЬ 'название londiste consumer'– pgqadm ticker.conf status; ждём Lag больше, чем у копии

1) pg_dump -Fc -h prod_host --serializable-deferrable dst_db pg_restore -Fc -d dst_db -j10

2) dst: select * from londiste.completed

3) src: select * from pgq.consumer where co_name = 'название londiste consumer'

4) src: select * from pgq.subscription where sub_consumer = 'id из (3)'

5) src: update pgq.subscription set sub_last_tick = 'tick_id из (2)', sub_batch = null, sub_next_tick = null where sub_consumer = 'id из (3)'

Backup• fsync в archive_command

– сейчас — копия в облаке

• в планах: два сервера

– archive_command на оба

– restore_command с двух

– pg9.2 pg_receivexlog не работает● как защититься от удаления WAL при checkpoint?

(в 9.4 сделали --slot)● не делает fsync (в 9.5 сделали --synchronous)● не проверяет целостность при запуске

Backup и streaming• в архив пишет master (archive_command), а копия идёт

со standby

• backup завершился, а master не успел отправить WAL в архив = битый backup

– pg9.2 не используем streaming :-)

– pg9.2 12 часов задержка backup сервера

– pg9.5 archive_mode=always, пишем в архив со standby!

Backup, проверкаскрипт для проверки, распаковка на тестовый сервер:

• запуск кластера, recovery.conf: recovery_end_command

• ждём RECOVERY_END, перезапуск для log: 'end-of-recovery checkpoint', 'database system is ready'

• анализ csvlog файла, пропускаем SQLSTATE '57P03' # 'the database system is starting up'

– есть только severity: LOG

– для каждой базы вызываем: select check_backup(last_txtime)

● например, create_time - last_txtime < 1 минута

Backup, проверкаredo_start = backup_label: START WAL LOCATIONrecovery_end = pg_controldata: Minimum recovery ending location

• сообщения, анализируемые в log файле– 'redo starts at ([0-9A-F/]+)': redo_start– 'consistent recovery state reached at ([0-9A-F/]+)':

recovery_end– 'redo done at ([0-9A-F/]+)'– 'last completed transaction was at log time ([0-9-]+ [0-

9:.]+\+[0-9]+)': last_txtime– 'archive recovery complete'– 'database system is ready to accept connections'

• vacuum базы, sec scan, index scan– отказались, отчёты по восстановленной базе

Синхронная репликация• приложение-сервисы

• сервис платежей

– отдельный кластер master-slave

– синхронная репликация

• так как только платежи — TPS и latency сети хватает

• можно восстанавливаться и при асинхронной репликации

• недостаточно восстановить postgres, нужно думать о связанных системах

– логическая репликация

– внешние индексы (sphinx)

– экспорт данных (DWH и т.п)

• тестирование резервных копий

ZooKeeper?

Спасибо за внимание!