Можно ли гарантированно записать информацию в две базы данных?
И так, у нас есть библиотека peewee с драйвером psycopg2 для работы с postgresql и библиотека redis для работы с (ого!) Redis.
Постепенно, в процессе работы программы наполняется некий буфер для записи в postgresql и некий pipeline для записи в redis. Далее с помощью менеджера контекста для атомарной операции (.atomic() ?) и bulk_create'ом внутри данные заливаются в postgresql, а после вызывается pipeline.execute() для редиса.
Каким образом можно гарантировать, что даже при внештатной ситуации - отключение света или kill процесса, данные либо запишутся в обе базы данных, либо не запишутся ни в одну?
Да, у обеих библиотек есть какие-то транзакции, но, получается, таким образом одна должна быть вложена в другую? Как это будет выглядеть, например?
Опишу, наверное, общую суть проблемы здесь, дабы не смазывать сам вопрос. В задаче нужно убить сразу двух зайцев - нужен быстрый доступ к данным, чтобы сравнивать определенное значение по определенному ключу (для этого используется redis) + хранение большого количества структурированных полей, по которым сравнение не идёт и которые вытаскивать нужно редко (для этого используется postgresql). В redis всё запихать не получится по причине того, что если всё упадёт, а редис ещё не записал данные на диск - потом будет бобо. В postgresql всё запихать тоже не получится по причине того, что нужно достаточно много селектов всего одного значения, которые выполнять нужно как можно быстрее.
В таких задачах первое, что приходит в голову - это распределённые транзакции и двухфазный коммит. Но сомневаюсь, что Redis это умеет. Самым простым и эффективным решением, КМК, было бы перекроить архитектуру: писать всё в PostgreSQL, а данные Redis формировать из постгреса.
Сергей Горностаев, Да, этот вариант я тоже рассматривал. При старте всего процесса, грубо говоря, работы программы писать в редис данные формата ключ => необходимое для быстрого чтения значение, но не будет ли это проблемой, например, если таким образом нужно будет записать миллион ключей? А если десять?
Сергей Горностаев, Кэш не думаю что подойдёт. Что программе нужно делать с началом работы - так это как можно быстрее определить, есть ли вообще данные по определенному ключу в базе данных, то есть первым же обращением. А закэшировать его раньше, чем оно произошло ... :) можно только скинув всё в быстрое хранилище заранее.
Отдельно обращаю пристальное внимание на настройки редиса. Он не запишет данные с настройкой fsync по-умолчанию. Дефолтный fsync для AOF режима лога записи у него - раз в секунду. То есть все данные до секунды работы длительности вы можете потерять при крахе ОС.
Redis не поддерживает протокол двухфазного коммита. И вы не можете сделать durable fsync в два места атомарно.
Поэтому просто это никак не сделать.
Что сделать можно - переделать логику, чтобы одна из баз могла при аварии привести данные в консистентный вид используя данные ведущей базы.