Деплой кода процедур
Мурат Кабилов, Avito
PostgreSQL meetup @ Avito 09.04.2016
Контекст
• много хранимых процедур >500
• большой размер базы ~2 TB, большой TPS
• много разработчиков
• много веток
2
Проблема
• деплоить несколько версий процедур на одной базе
• удобное версионировение кода хранимых процедур
• применение DDL изменений
• массовые update'ы
3
Решение «Zalando»
• под каждую выкатку создавать схему со всеми х/п
• замена search_path
• плюсы: простое решение. Схема дает самодостаточность
• минусы: много изменений для системного каталога
версия отражается в названии схемы
4
Решение
• деплоить только изменившиеся хранимые процедуры
• название хранимой процедуры содержит версию
• иметь php-словарь с маппингом хранимая процедура — версия
• приложение «решает» какую версию использовать
версия отражается в названии хранимой процедуры
5
GIT
• [master]
• [public.item_save.sql]
• [public.get_matrixes.sql]
• [master2]
• [public.phone_save.sql]
• [public.phone_validate.sql]
• [xrpc.clear.sql]
• [payments.pushup.sql]
6
GIT
• содержимое public.get_matrixes.sql:


CREATE OR REPLACE FUNCTION public.get_matrixes(OUT o_matrix_id integer)

RETURNS SETOF integer

LANGUAGE sql

AS $function$

select

matrix_id as o_matrix_id

from my_schema.matrix_probabilities

order by matrix_id;

$function$
ALTER FUNCTION public.get_matrixes SET work_mem = '100 MB';
• инициализация/дамп, например, через pg_get_functiondef()
7
Маппинг. БД
• Таблица stored_procedures:
• branch_name — имя ветки
• fn_name — имя хранимой процедуры
• fn_md5 — хеш от файла хранимой процедуры
• ver_id — порядковый номер версии хранимой процедуры
8
Маппинг. Приложение
• Файл-словарь Obj_Sproc_Version.php:
<?php

// generated by Obj_Dict_Indexed::storeDict() (see Obj_SPVersion::getDict())

return [

'public.get_matrixes@master' => 1,

'public.item_save@master' => 15,

'payments.pushup@master2' => 0,

'xrpc.clear@master2' => 3,
...

9
Деплой
• содержимое public.get_matrixes.sql:


CREATE OR REPLACE FUNCTION public.get_matrixes_ver2(OUT o_matrix_id
integer)

RETURNS SETOF integer

LANGUAGE sql

AS $function$

select

matrix_id as o_matrix_id

from my_schema.matrix_probabilities

order by matrix_id desc;

$function$
10
Деплой
11
-[ RECORD 1 ]-+---------------------------------
branch | master
fn_name | public.get_matrixes
fn_md5 | e0b02d8234e3bfe283bccad31c1f88fd
ver_id | 1
-[ RECORD 2 ]-+---------------------------------
branch | AVITO-3311-matrix-order-desc
fn_name | public.get_matrixes
fn_md5 | 1b05d042fd37384e47e4403fa65a8f3a
ver_id | 2
Деплой
• Файл-словарь Obj_Sproc_Version.php:
<?php

// generated by Obj_Dict_Indexed::storeDict() (see Obj_SPVersion::getDict())

return [

'public.get_matrixes@master' => 2,

'public.item_save@master' => 15,

'payments.pushup@master2' => 0,

'xrpc.clear@master2' => 3,
...

12
Плюсы и минусы
• Плюсы:
• выкатываются только измененные хранимые процедуры
• можно хранить несколько версий х/п в одной базе
• легкий «откат»
• Минусы:
• трудности при использовании внутренних х/п
13
Что дальше?
Решить проблему использования внутренних х/п
Деплой v2
• Две схемы: base, diff
• Два пользователя со след. search_path: User_A: base, User_B: diff, base.
• Приложение использует User_A
16
Деплой v2
• При выкатке, все изменившиеся хранимые процедуры создаются в diff
схеме
• После деплоя х/п новая версия приложения начинает использовать
User_B
• По окончанию выкладки php кода, переносим х/п из diff в base. 

Меняем местами search_path у пользоватлей:

User_A: diff, base, User_B: base
• Приложение использует User_B
17
18
• выкатываются только измененные хранимые процедуры
• нет проблем с использованием внутренних хранимых процедур
• откат через деплой
Итог
Вопросы?

"Деплой кода процедур" Мурат Кабилов (Avito)

  • 1.
    Деплой кода процедур МуратКабилов, Avito PostgreSQL meetup @ Avito 09.04.2016
  • 2.
    Контекст • много хранимыхпроцедур >500 • большой размер базы ~2 TB, большой TPS • много разработчиков • много веток 2
  • 3.
    Проблема • деплоить нескольковерсий процедур на одной базе • удобное версионировение кода хранимых процедур • применение DDL изменений • массовые update'ы 3
  • 4.
    Решение «Zalando» • подкаждую выкатку создавать схему со всеми х/п • замена search_path • плюсы: простое решение. Схема дает самодостаточность • минусы: много изменений для системного каталога версия отражается в названии схемы 4
  • 5.
    Решение • деплоить толькоизменившиеся хранимые процедуры • название хранимой процедуры содержит версию • иметь php-словарь с маппингом хранимая процедура — версия • приложение «решает» какую версию использовать версия отражается в названии хранимой процедуры 5
  • 6.
    GIT • [master] • [public.item_save.sql] •[public.get_matrixes.sql] • [master2] • [public.phone_save.sql] • [public.phone_validate.sql] • [xrpc.clear.sql] • [payments.pushup.sql] 6
  • 7.
    GIT • содержимое public.get_matrixes.sql: 
 CREATEOR REPLACE FUNCTION public.get_matrixes(OUT o_matrix_id integer)
 RETURNS SETOF integer
 LANGUAGE sql
 AS $function$
 select
 matrix_id as o_matrix_id
 from my_schema.matrix_probabilities
 order by matrix_id;
 $function$ ALTER FUNCTION public.get_matrixes SET work_mem = '100 MB'; • инициализация/дамп, например, через pg_get_functiondef() 7
  • 8.
    Маппинг. БД • Таблицаstored_procedures: • branch_name — имя ветки • fn_name — имя хранимой процедуры • fn_md5 — хеш от файла хранимой процедуры • ver_id — порядковый номер версии хранимой процедуры 8
  • 9.
    Маппинг. Приложение • Файл-словарьObj_Sproc_Version.php: <?php
 // generated by Obj_Dict_Indexed::storeDict() (see Obj_SPVersion::getDict())
 return [
 'public.get_matrixes@master' => 1,
 'public.item_save@master' => 15,
 'payments.pushup@master2' => 0,
 'xrpc.clear@master2' => 3, ...
 9
  • 10.
    Деплой • содержимое public.get_matrixes.sql: 
 CREATEOR REPLACE FUNCTION public.get_matrixes_ver2(OUT o_matrix_id integer)
 RETURNS SETOF integer
 LANGUAGE sql
 AS $function$
 select
 matrix_id as o_matrix_id
 from my_schema.matrix_probabilities
 order by matrix_id desc;
 $function$ 10
  • 11.
    Деплой 11 -[ RECORD 1]-+--------------------------------- branch | master fn_name | public.get_matrixes fn_md5 | e0b02d8234e3bfe283bccad31c1f88fd ver_id | 1 -[ RECORD 2 ]-+--------------------------------- branch | AVITO-3311-matrix-order-desc fn_name | public.get_matrixes fn_md5 | 1b05d042fd37384e47e4403fa65a8f3a ver_id | 2
  • 12.
    Деплой • Файл-словарь Obj_Sproc_Version.php: <?php
 //generated by Obj_Dict_Indexed::storeDict() (see Obj_SPVersion::getDict())
 return [
 'public.get_matrixes@master' => 2,
 'public.item_save@master' => 15,
 'payments.pushup@master2' => 0,
 'xrpc.clear@master2' => 3, ...
 12
  • 13.
    Плюсы и минусы •Плюсы: • выкатываются только измененные хранимые процедуры • можно хранить несколько версий х/п в одной базе • легкий «откат» • Минусы: • трудности при использовании внутренних х/п 13
  • 14.
  • 15.
  • 16.
    Деплой v2 • Двесхемы: base, diff • Два пользователя со след. search_path: User_A: base, User_B: diff, base. • Приложение использует User_A 16
  • 17.
    Деплой v2 • Привыкатке, все изменившиеся хранимые процедуры создаются в diff схеме • После деплоя х/п новая версия приложения начинает использовать User_B • По окончанию выкладки php кода, переносим х/п из diff в base. 
 Меняем местами search_path у пользоватлей:
 User_A: diff, base, User_B: base • Приложение использует User_B 17
  • 18.
    18 • выкатываются толькоизмененные хранимые процедуры • нет проблем с использованием внутренних хранимых процедур • откат через деплой Итог
  • 19.