Pull to refresh
8
0

главный по тарелочкам

Send message

если мы говорим про PostgreSQL, то необходимостью перезапускать всю транзакцию в случае получения `serialization_failure` , ну и накладные расходы там достаточные

для Авито это, скорость, "микросервисность" (если это можно так назвать), и наличие нужного количества разработчиков на рынке труда. с php разработчиков вроде бы больше, но не удобно работать в микросервисной архитектуре. есть ещё питон, и он тоже в Авито используется достаточно широко.
со всеми остальными языками будут проблемы, в основном из-за найма.

пока не могу представить сценарий при котором , в современных СУБД нужна эксклюзивная блокировка строк и таблиц

любой биллинг

простой вопрос - сложный ответ. сильно зависит от задачи и что понимается под `языками где есть достаточное количество устоявшихся библиотек`. Когда принимается решение использовать тот или иной язык или фрэймворк это всегда многокритериальный выбор. Стоит учесть и свой опыт, и возможности языка и его runtime, и наличие нужных библиотек, наличие поддержки этих библиотек, наличие разработчиков на рынке и возможность их нанять. А так если сравнить го и любой другой развитый ЯП, просто как язык программирования, то вроде и нет никаких профитов.

есть ещё вариант использовать format но там остаётся проблема с концевым пробелом

select format('%s %s %s', 'Иванов', 'Иван', null);

'Иванов Иван '

select * from table1 - очень похож на перебор по ctid, но, не позволяет регулировать нагрузку, и держит открытую транзакцию на время всего select'а. иногда это критично.
По поводу индекса, с ним конечно удобнее, но не всегда он есть. если его строить для одной операции, то это ещё один SeqScan всей таблицы, открытая транзакция на время построения индекса, место на его хранение, повышенная нагрузка на запись при его создании, увеличенные ресурсы на его поддержку при изменениях в таблице.

есть ещё одна прелесть, которая не до конца раскрыта. предположим надо удалить строки по какому-нибудь условию, пусть этих строк в таблице достаточное количество (например до 50% в каждом блоке). delete from table1 where .... неприемлем потому что транзакция и блокировки. итерирование по какому-нибудь primary key допустимо, но не эффективно. Предположим в среднем у нас по 100 строк в блоке и 50 из них надо удалить. в худшем случае каждый блок (а PostgreSQL пишет и читает блоками) будет изменён 50 раз. 50 раз будет прочитан и записан на диск, записан в WAL, передан по сети на реплику, попадёт в бэкап... очень эффективно :) но если применить "фишку" ctidмы заменим Random Read/Write на Sequential Read/Write, и сможем сразу удалить все строки в одном блоке и один раз его записать снизив нагрузку в 50 раз. это очень грубо конечно, потому что есть ещё 2 уровня кэширования + индексы, распределение строк в таблице может быть не достаточно случайным, но для понимания сути это всё не важно.

логическая репликация londiste отличная штука, мы научились ей пользоваться там где она действительно нужна, пришлось правда создать достаточно много инструментов вокруг неё чтобы она удовлетворяла нашим требованиям. есть хорошее видео 2017-го года с воркшопа на хайлоаде где Миша, Костя, и Сергей подробно рассказывают как что устроено и что пришлось доработать
https://www.youtube.com/watch?v=vCYGOVa3w1g . Было круто, но... со временем компания выросла, скорость внедрения новых "фич" тоже, и все эти "кастомные" штуки, стали очень дороги в поддержке и скорее мешали, чем помогали. Поэтому целенаправленно пошли в сторону упрощения. И теперь нет никаких логических репликаций средствами DBA, никакого чтения с физических реплик. Реплики только для поддержания High Availability.

Не очень понял вопрос про обновление. Если имеется в виду обновление минорных версий, то схема примерно такая, поочерёдно обновляются физические реплики, потом одна из них становится мастером и обновляется оставшаяся реплика. Переключение мастера для приложения выглядит как обрыв коннекта с базой и небольшой даунтайм. С обновлением мажорных версий конечно всё чуточку сложнее, но схема примерно такая же. pgbouncer во всём этом не участвует и работает как простой прокси.

Нет, listen/notify для такого не подходят, там нет гарантий доставки, там потеря событий при отсоединении подписчика, и, кажется, есть какие-то ограничения на размер payload. Я, честно говоря, даже и не знаю где можно применять listen/notify, мы в своё время использовали как способ доставки метрик изнутри хранимых процедур, но это было ещё во времена когда много логики было скрыто в них. Вот, кстати, статья, на эту тему https://habr.com/ru/company/avito/blog/323900/.

А что про pgq, то мы используем вот это https://github.com/pgq . Ранее это было частью пакета утилит skytools которым skype в своё время реализовывал логическую репликацию londiste. Мы ранее тоже использовали, но отказались вообще от использования логической репликации в компани.

про vault в статье рассказано не совсем полно. на самом деле есть обёртка которая прокидывает секреты из vault в переменные окружения, и потом уже логины/пароли из переменных окружения используются как параметры для подключения внутри psql.Connect()

про detach, спасибо, посмотрю внимательнее. ещё я находил https://github.com/goinsane/xcontext/blob/master/xcontext.go#L14 по описанию может пригодиться, но использовать ещё не довелось

pgeon - это часть механизма CDC (change data capture) и доставки данных в Data Warehouse. если в двух словах - это триггер на таблице который логгирует изменения в pgq-очередь и обвязка над этим механизмом которая позволяет разработчику не задумываться о внутреннем устройстве. В общих чертах я рассказывал об этом на pgConf 2022, но, кажется, организаторы не публиковали видео, и вообще не уверен что опубликуют. Если аудитория проявит интерес к этой теме, то можно подумать о том чтобы рассказать более подробно в одной из статей.

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

Есть вариант чуть более эффективный - поиграться с row_security в PostgreSQL - но это тоже будет малоэффективно. по сравнению с предыдущим вариантом чуть более эффективно, потому что данные нескольких пользователей можно сгруппировать в одной базе, и чуть поднять "плотность" пользователей.

обычно разграничение прав делают на уровне кода, в каждой таблице есть колонка, типа userId и все запросы должны быть в стиле select * from table where user_id = SOME_USER_ID .

Чтобы исключить возможность разработчику случайно, или намеренно, получить доступ к чужим данным можно закрыть прямой доступ к таблицам, а работу с данными организовать через хранимые процедуры которые создаются и изменяются проверенными разработчиками, имеют доступ к таблицам благодаря опции security definer, принимают на вход jwt токен, и скрывают внутри себя всё операции по получению и изменению данных. Это было бы крутым решением, если бы не планируемые 100k запросов в секунду, для одной физической машины это выглядит многовато, данные придётся шардировать на несколько физических машин, это приведёт к тому что jwt токен придётся заменить на user_id (чтобы бэкэнд понимал к какому шарду коннектиться для выполнения запросов), а связку jwt -> user_id придётся хранить в отдельном сторадже.

вот как-то так :)

опечатка затесалась, спасибо, исправил

немного мякотки
( 
	select
		encode((select substring(get_raw_page('t_test2', 'main', 0) from (lp_off + t_hoff + 1) for (lp_len - t_hoff))), 'hex') as user_data
	from heap_page_items(get_raw_page('t_test2', 'main', 0)) as h limit 1
)
union all
(
	select
		encode((select substring(get_raw_page('t_test', 'main', 0) from (lp_off + t_hoff + 1) for (lp_len - t_hoff))), 'hex') as user_data
	from heap_page_items(get_raw_page('t_test', 'main', 0)) as h limit 1
)

и мы получаем как физически выглядят данные в тупле
t_test : 0a000000 14000000 1e000000 0b61626364 0b61626364 0b61626364
t_test2: 0b616263 64000000 0a000000 0b616263 64000000 14000000 0b616263 64000000 1e000000

в случае когда varchar'ы идут подряд не производится дополнительного выравнивания
ага, по README кстати не получилось, пришлось вместо npm install jsx поставить npm install react-tools
всё разбилось о
[8738:1015/234501:INFO:CONSOLE(83)] "Uncaught Error: Module did not self-register.", source: /home/timon/dev/sqltabs/node_modules/libpq/node_modules/bindings/bindings.js (83)
[8738:1015/234503:ERROR:channel.cc(299)] RawChannel read error (connection broken)
tsvector можно хранить в функциональном индексе
важно помнить что приём с конкатенацией полей в строку работает только до момента пока вам не встретится null :)
Ну, как я и предполагал, обычная реклама, матча как такового не было :)
вопросов больше не имею. спасибо за историческую справку :)
ну, на это я наткнулся уже после :)

Information

Rating
Does not participate
Location
Россия
Registered
Activity

Specialization

Backend Developer, Database Developer
PostgreSQL
Linux
Golang