Обновить
62
Стас Выщепан@gandjustas

Оптимизирую программы

104
Подписчики
Отправить сообщение

Аллокации не коде методов Merge, а в самих асинхронных итераторах.

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

Звучит как попытка угадать будущее, которая в общем провальна

Потому что архитектура не очень видимо

У нас недавно всплыла проблема, но как на днях выяснили что разработчик накосячил.

Нет ли у вас проблем с проверкой открепленной подписи по ГОСТу с помощью Bouncy Castle?

Спасибо огромное за вашу статью

  1. Проприетарный криптопрошный PFX. Документации по нему нет, нужно заниматься сложным реверс-инжинирингом, есть некоторые статьи про конвертирование стандартного PKCS12 в формат КриптоПро, но обратная операция достаточно затруднительна — всё вдоль и поперек обмазано хитро считающимися контрольными суммами.

Внезапно я недавно сделал код, который достает закрытый ключ из сертификата такого формата. Если кому-то будет интересно могу написать статью.

  1. PFX по Р 1323565.1.041— 2022. Транспортный ключевой контейнер. Нет реализации на C#, но структура и логика создания описана в стандарте. Кстати, такой контейнер понимает также криптопровайдер VipNet CSP.

Можно ссылочку на стандарт?

Если у вас не напрямую из базы читали в dwh, а вы сначала из твоей системы отдавали по api данные в другую, а уже оттуда данные попадали в dwh, то тут могла бы помочь интеграция с этой системой на уровне данных. Тем более, судя по всему, там etl типа airflow

То есть целевая модель такая:

  • Вы выставляете в базе вьюху, которая отдает нужные данные одной таблицей

  • Обкладываете её индексами

  • Другая система подключается к вашей с правами только на чтение этой вьюхи

  • PROFIT!

Вы экономите огромное количество ресурсов на сериализацию данных

Но вы писали что другую систему изменить нельзя (единственный специалист по airflow занят на другой задаче), то просто поменяйте структуру у себя

То есть в вашу базу напрямую не ходили внешние приложение? Тогда почему вы не могли структуру вашей базы поменять?

Про покрывающие индексы стоит говорить если вы запросы в программе сделали с нудными полями. А у вас include, который все равно в select все потащит.

Покрывающий индекс при чтении выгоден всегда. Потому что обычны идекс скан - это поиск записи в индексе (одно логическое чтение), а потом получение записи из кучи (второе логическое чтение). Если вы сделаете «широкий индекс» при выборке относительно небольшого количества строк, то index only наверное всегда выиграет у index scan. Но вы получите большой импакт при записи, так как индексы надо будет обновлять и перестраивать.

Поэтому как общий подход делать все через index only я не могу рекомендовать, но для особо экстремальных случаев помогает даже покрывающий индекс , в котором все поля кроме одного включены.

Про работу над ошибками:

  1. В базах данных есть view, их как раз и нужно использовать при интеграции с другими системами на уровне данных. Причем Вы могли прямо в текущей базе сделать нормальную модель и отдать потребителям view.

  2. Это у вас НЕДОСТАТОЧНАЯ нормализация данных, как и в таблице коммуникантов. Недостаточная нормализация как раз увеличивает объемы, ухудшает возможности оптимизации с помощью индексов и приводит к конфликтам рассогласованности данных.

  3. Вы неверно употребляете термин «нормалмзация». Нормализация это отсутствие связей между не ключевыми полями в таблице и строгая связь с ключевым полем. У вас это просто ошибка моделирования.

  4. Есть хороший инженерный коэффициент - 6. Или более наукообразно - 2Пи. Система должна выдерживать шестикратное превшение нагрузки над «рабочими» значениями. То есть во время тесты вы должны были в 6 раз увеличить объемы данных для тестирования, если у вас проблема упирается именно в объем или rps, если система упирается в частоту запросов.

Выглядит как «из пушки по воробьям».

1) почему вы продолжали использовать include, а не вписали проекции только тех значений что нужны конкретно для dwh? Вряд ли там все поля таблицы используются

2) как следствие пункта выше: почему не пытались сделать покрывающие индексы и свести все к index only scan?

3) почему не применили filtered indexes, вы бы могли для целей dwh сделать индекс c where, чтобы из индекса убирать автоответчики ?

Кроме того можно было сделать в индексе where по дате, чтобы отсекать данные старше 90 дней и перестраивать индекс по ночам, причем конкурентно, чтобы не мешать другим. Получился бы всего один ddl запрос

4) возможно стоило попробовать перенести op_data в jsonb поле в самой activity, тогда и читать пришлось бы меньше (вероятно) и размер возвращемого датасета снизился бы (точно). Делать key-value хранилище в таблицах бд - не самое эффективное решение. В крайнем случае сделать json_agg (два array_agg на key и value)в запросе.

что из написанного вам непонятно? С чем из написанного вы не согласны?

Да, не точно написал. Vacuum не блокирует, но сильно замедляет запросы, так как читает и записывает множество страниц таблицы.

Разве не так сейчас вебсокеты работают https://datatracker.ietf.org/doc/html/rfc8441

Это если http2, но сейчас вроде все серверы и клиенты это поддерживают.

Сделал тест такого варианта https://habr.com/ru/articles/963120/
Очень сильно проигрывает транзакциям в БД, даже без реализации отката при потере связи.

Рукопашные транзакции могут оказаться быстрее если время обработки значительное, но мы тогда приходим к архитектуре с очередями в базе и асинхронной обработке.

Сохранить синхронность и сделать рукопашные транзакции, чтобы уменьшить ожидания на блокировках, в большинстве случаев приведет к замедлению. А если нужно просто уменьшить степень конкурентности, то проще блокировку сделать advisory lock, взять блокировку таблицы или очередь как в этом посте.

Сделал тест варианта с явными блокировками https://habr.com/ru/articles/963120/

В принципе любюй протокол палится своими заголовками. Даже VLESS, судя по описанию легко поддается определению. А не палится он за счет того, что маскируется под http2 с веб-сокетами. Даже не маскируется, он просто свою полезную нагрузку передает через h2+ws. Странно что об этом не сразу догадались.

Насколько я понимаю TLS пока еще никто читать не научился, потому что если научится, то это конец всей безопасности в вебе. Поэтому определить что внутри h2+ws траффика идет VPN туннель пока не могут.

А вот заблокировать ваш сайт и выписать штраф за рекламу ВПН для обхода блокировок - вполне. Странно что администрация хабра спит.

Я вам пишу как можно улучшить и сделать надежнее несильно усложняя код.

Что именно улучшить? Скорость работы? Надежность? Время написания?

Можете пример кода привести, который демонстрирует эти улучшения?

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

Я этим больше 20 лет занимаюсь. Практикой все проверено.

Это вообще ни о чем не говорит.

А вы какими догмами рассуждаете. Ярлыки навешиваете.

Если для вас ACID и гарантии СУБД это "догмы" и "ярлыки", тогда вы правы. Я вообще не считаю себя умнее разработчиков Postgres\SqlServer\MySQL и даже SQLite, чтобы думать что могу сделать ACID лучше, чем они за любое разумное время.

Ну, делайте как вам нравится. Никто не заставляет.

Code talks. Просто покажите пример.

Вы серьезно?

Да, у меня статья о том как эта проблема решается, если вы не заметили

Да вы видимо никогда не сталкивались с кучей блокировок из за больших транзакций. Вам что важно, надежность или мнимая "простота"? И зачем она будет если повиснет под нагрузкой.

В этой статье пример кода как раз сталкивается с большим количеством блокировок из-за больших транзакций.

Вам что важно, надежность или мнимая "простота"?

Конечно надежность, которая заключается как раз в соблюдении ACID на уровне запросов пользователей\клиентов сервиса.

Насчет резервов - можно предположить экзотический сценарий когда из за падения обработки останется зависший резерв по части строк. Так он по куче причин может быть.

Если используете транзакции, то не может быть.

Например в вашем случае, резерв полностью прошел но оплата не прошла.

Транзакция будет отменена, резерв не пройдет.

Или электрисество вырубилось.

Закоммиченная транзакция никуда не денется, незакоммиченная будет отмена. Это гарантия долговечности - D в ACID

Для разруливания таких ситуаций делают фоновые обработки, которые снимаю старые ненужные рещервы или такие вот аварийные заказы.

Это я и имею ввиду, когда говорю что "самопальные транзакции" гораздо более затратны. Кроме того у вас нет никакой защиты от Durty Reads.

 И вы без такой обработки не обойдетесь даже с вашим вариантом длинных транзакций.

Пример в статье показывает как обойтись без такой обработки.

Вы вообще статью прочитали? Код смотрели?

Да причем здесь WAL?

При том что вы пытаетесь его реализовать

Это же другой уровень. Все в приложении делается. Промежуточный статус млжно клиенту не показывать.

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

Отсутствие атомарности:

Предположим вы реализовали такой цикл с транзакциями внутри цикла. Внезапно на одной из итераций происходит падение БД (внезапная перезагрузка, oom-kill итд). Что будет делать ваш код? Клиент получит свою ошибку, но вам надо как-то откатить уже закомиченные транзакции. А если приложение падает в середине цикла, клиент получает отказ, а кто откатывать будет?

Отсутствие согласованности:

Кроме того можно рассмотреть сценарий параллельных резервирований:

  1. Клиент А зарезервировал товар 1 (транзакция закоммичена)

  2. Клиент Б зарезервировал товар 2 (транзакция закоммичена)

  3. Клиент А пытается резервировать товар 2, но запасы кончились, резрв товара 1 нужно откатить

Отсутствие независимости:

Кроме того ваше приложение скорее всего постоянно отдает остатки, и вы уменьшаете остаток, снижая его на время незавершенных резервов.

А в какой момент вы будете давать клиенту ответ?

Если клиент ждет пока статус документа не станет равен "зарезервировано", то вы просто изобрели свой WAL и поверх БД, у которой уже есть WAL. Ваш подход будет на порядок хуже использования транзакций.

Если клиент не ждет когда документ получит статус "зарезервировано", то я не понимаю как это должно работать. Предположим что у вас приложение, которое билеты в кино продает. Вы покупаете два билета, приложение вам говорит "Начато резервирование", так? А деньги когда списывать будет?

1
23 ...

Информация

В рейтинге
Не участвует
Откуда
Москва, Москва и Московская обл., Россия
Дата рождения
Зарегистрирован
Активность

Специализация

Архитектор программного обеспечения, Деливери-менеджер
Ведущий
C#
.NET Core
Entity framework
ASP.NET
Базы данных
Высоконагруженные системы
Проектирование архитектуры приложений
Git
PostgreSQL
Docker