-*- mode: org -*-
octopus - дальнейшее развитие идеи silverbox/tarantool, фреймворк для создание in-memory баз данных.
В комплекте идет с двумя модулями feeder и box. Первый необходим для репликации, второй - key-value хранилище.
Пример конфигурации - doc/example.cfg
Запуск: ./octopus -c doc/example.cfg –init-storage # инициализируем хранилище ./octopus -c doc/example.cfg # запускаем сервер
Клиентская библиотека протокола iproto
Бенчмарк для mod/box (silverbox)
$ irb -I mod/box/client/ruby -r silverbox irb(main):001:0> s = SilverBox.new ‘0:33013’ => #<SilverBox:0x000000025a3438 @object_space=0, @end_point=[“0”, 33013], @reconnect=true, @sock=#<TCPSocket:fd 4>> irb(main):002:0> s.ping => :pong irb(main):003:0> s.insert [1, “foo”, “bar”] => 1 irb(main):004:0> s.select 1 => “\x01\x00\x00\x00”, “foo”, “bar”
- wal_feeder_addr - адрес, откуда получаем данные.
- wal_feeder_filter - название фильтра. Фильтр - процедура, которая определена на мастере.
- wal_feeder_filter_type - тип фильтра - “lua”, “c” или “id”
“id” - ничего не делать
- ставится по умолчанию, если wal_feeder_filter пустой
“lua” - вызывать Lua функцию
- cтавится по умолчанию, если wal_feeder_filter не пустой.
“c” - если используется кустомный фидер, то есть возможность вызвать функцию, написанную на “c”.
- wal_feeder_filter_arg - строка, передаваемая как дополнительный аргумент фильтру.
Фильтр - функция, котороя посторочно получает данные репликации и может их изменять.
Наиболее доступным является фильтр на Lua. Фильтр должен быть зарегистрирован в таблице replication_filter, простейщий способ - создавать функции с именем вида replication_filter.имя_фильтра.
Аргументы фильтра: (row, arg)
- row - cdata<struct row_v12*>. Если фильтру передан дополнительный аргумент arg, то первый раз фильтр вызывается с row = nil
- arg - дополнительный аргумент, переданный с клиента. Передаётся каждый раз.
Фильтр должен вернуть либо строку либо nil. В последнем случае строка реплике не передается. Обратите внимание, что в этом случае будут дырки SCN, соответсвенно на реплике надо отключить опцию конфигурации panic_on_scn_gap .
Пример фильтра можно посмотреть в mod/feeder/src-lua/feeder.lua и test/07_test_replication.rb
Возможно изменение источника репликации на ходу: правим конфиг + reload conf в админ. интерфейс.
Никаких проверок реплика не делает, она просто начинает репликацию с нового адреса используя SCN на единцу больший чем ее собственный. Соответсвенно, если новый мастер имеет, например, другие настройки object_space, то все сломается.
Переключение обратно на старый мастер тоже надо делать с осторожностью: если в нем будут несовместимые апдейты (которые могли появится после того, как реплику переключили на временный мастер), то все сломается.
Чтение снапшота осуществляется командой ./octopus –cat file.snap. При этом данные выводятся в порядке, в котором они были записаны в файле; формат значений в тупле выбирается автоматически, он относительно удобен для просмотра на экране, но неудобен для машинной обработки. При помощи переменных окружения можно вывести только необходимые поля и неймспейсы, а также определить формат полей более явно.
- OCTOPUS_CAT_ROW_HEADER=0 - не выводить служебную информацию, оставить только данные тупла
- BOX_CAT_SNAP_SPACE=100 - вывести данные только из спейса 100
- BOX_CAT_FMT=’u @’ - формат, в котором выводятся данные тупла
Каждому полю тупла соответствует один символ формата; если очередное поле
не требуется выводить, на его месте необходимо поставить пробел.
– Форматы ‘i’, ‘u’ выводят числовые значения в знаковом и беззнаковом форматах соответственно.
– Формат ‘s’ - вывод данных в виде строки байт, не-ascii символы эскейпятся.
– Формат ‘@’ - комбинированный формат, действует по умолчанию.
Состояние сервера сохраняется на диске в двух типах файлов snap и xlog. Имя файла формируется как LSN первой записи в нем плюс расширение. В snap файлах сохраняется единомоментный снимок памяти сервера, а в xlog - WAL всех изменений. Таким образом, для полного востановления сервера необходим snap + все записи их xlog старше его.
————————–
————— | |
loading | ||||
remote_hot_stby | ||||
feeder | LOWRITE | FEEDER | ||
configured | v |
————— | | ——- |
<– | ||||||
primary | ||||||
+-lock_WAL-> | LOWRITE | feeder |
v | | | v v configured |
—————- ————- | – —- | |
local_hot_stby | ^ ^ | ok | –> | fail | —-+ | |
—————- | | ————–v—————
——-lock_WAL—- ———————–
-[Recovery recover_start] – Находим и читаем snapshot c наибольшим LSN -[Recovery recover_snap]
– находим самый свежий xlog, LSN которого меньше чем LSN снапшота. -[Recovery recover_cont] – сортируем все xlog файлы в порядке возрастания LSN и дочитываем оставшиеся файлы в цикле -[Recovery recover_remaining_wals] foreach xlog file -[Recovery recover_wal]
– Влючаем переодическое дочитываение xlog с диска. Для этого используются таймер + inotoify. [recover_follow]
while (row = -[XLogPuller fetch_row]) -[Recovery recover_row:row] -[Recovery apply_row:row] – Этот метод должен быть специфицирован в наследнике, и должен соответствующим образом менять состояние. -[Recovery apply] – обновление состояни Recovery: SCN, LSN, crc_hist
а -[Recovery apply:tag:] – нет.
Это связано со следующим фактом - мы обновляем эту crc сумму ввв
- Сохранение состояния на диск
- mod_prepare_update() – в этот момент модуль уже знает old_obj и obj
- -[Recovery submit_wal_row:] -[Recovery wal_pack_submit] – В случае успешной записи wal_pack_submit обновит run_crc_mod, если в переданной struct wal_row будут old_obj и obj != NULL
- mod_commit()
- Востановление с диска
При проигрывании записей мы обязаны обновлять run_crc_mod аналогично тому, как это делает -[Recovery wal_pack_submit] . Задача осложняется тем, что у нас нет ссылок на old_obj и obj и их невозможно получить, до тех пор, пока модуль не применит обновление.
Поэтому, обновление run_crc_mod отдано на откуп -[Recovery apply_row:].
- Репликация
Неприятность в том, что когда мы реплицируемся по сети мы как пишем на диск и так и применяем записи. Для того, что бы мы не обновляли run_crc_mod дважды делаем следующее:
- Прикладываем строчки с помощью -[Recovery recover_row:] (т.к этот же метод используется при востановлении с диска, то мы обновим run_crc)
- в -[Recovery wal_pack_append] передаем struct wal_row без установленных old_obj и obj и вызываем -[Recovery wal_pack_submit_x] для того что бы избежать обновления SCN и LSN (они обновлены на предыдушем шаге)