Эшу быдлокодит
297 subscribers
135 photos
12 videos
7 files
170 links
Дневник C# разработчика.

Личка: @EshuMarabo
Гитхаб: https://github.com/vladzvx

Стек: C#, PostgreSQL
加入频道
На прошлых выходных был на конференции по экосистеме .Net, к которой относится мой основной язык - c#: DotNext.

В первый день прослушал 4 доклада, во второй - 5.

Далее будет серия постов по прослушанным докладам, с тегом #dotnext@eshu_coding

#conf
#dotnext, день 1, доклад 1.

Workflow архитектура сервисов в .Net

Узнал, что в природе существует отдельно выделяемая workflow-архитектура - построение приложения вокруг определенных путей, которые проходит в своем жизненном цикле бизнес-сущность.

Самый простой пример - заявление, курсирующие между начальникам, оставляющими визу или завораживающими на доработку.

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

Также в докладе рассказали о готовых либах, реализующих workflow в c#. По случаю может и пригодится.

P.S. Отдельным бонусом к либам идёт возможность генерации блок схемы наших workflow

#conf
👍2
#dotnext, день 1, доклад 2.

Когда 100% cpu ничего не значит.

Доклад был посвящен некоторым нюансам, понижающим производительность приложений когда в коде все нормально.

Основная полезная информация, которую я вынес - о механизме устройства конвейера виртуальных машин, за мощности которых мы платим хостерам.

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

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

Другой интересный момент - взятие лишнего десятка ядер CPU, как раз таки на такой случай, не спасает, а наоборот делает хуже. Чем больше запрашиваемые нами ресурсы - тем сложнее приткнуть нашу виртуалку туда, где они есть.

Ещё было занятно про k8s и гармоничные настройки потребления памяти, но кубером я пока не проникся, потому прошло мимо.

#conf
👍1
#dotnext, день 1, доклад 3.

Кафка и распродажи в Озоне.

Доклад был посвящен перемалыванию пиковых нагрузок в Озоне. Довольно много касалось Apache Kafka, ну и рассказывали что и как у них устроено. В целом - очень интересно, но прям совсем ничего нового. Хотя, поиграться с такими нагрузками желание появилось.

Из забавного - у них считается нормальным тестить на проде, точнее не тестить, а устраивать учения:)

#conf
😁3
#dotnext, день 1, доклад 4.

Dependecy Injection в тестах.

Автор из Яндекса пропагандировал использование стандартных практик написания кода внутри тестов, ну и рассказал об основных тестовых фреймворках в .Net (я и так знал, что использую самый дремучий - MSTest).

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

Пока наиболее оптимальным выглядит путь максимального говнокода с копипастой. И совсем чуть-чуть выноса повторяющихся простынь в отдельные методы.

#conf
#dotnext, день 2, доклад 1.

Экономия памяти в .Net.

Известно, что приложения на java/c# съедают память столько, сколько им дадут. Но если заморочиться - можно сократить потребление.

В докладе занимались загрузкой файлов со средним размером ~123 Мб. В среднем на загрузку такого файла уходило ~280 Мб памяти.

Путем разных непристойных действий с байтами автор ужал потребление памяти до ~2.7 Мб, т.е. в 100 раз. И даже не особо потерял в читаемости кода.

Во основном использовалось два подхода:
1. Пулинг объектов
2. Выделение памяти на стеке вместо кучи

В c# есть встроенный пул массивов, которые можно использовать как буферные объекты, не создавая новые и не забивая память новосоздаваемыми одноразовыми массивами.

А если таки надо создавать буферные короткоживущие объекты - можно попробовать разместить их на стеке. Использовать структуру. Или вообще аллоцировать кусочек стека и использовать его по своему усмотрению (главное не переусердствовать и не завалить все приложение со Stack Overflow Exception).

Список колдунств, применённых автором, просто чтобы не забыть:
1. stackalloc
2. ArrayPool
3. readonly ref struct
4. ValueStringBuilder (вытащенный внутренний класс из недр рантайма c#, базирующийся на стеке билдер строк).
5. TryFormat

Ещё была важная мысль - использовать бенчмарки в докере, чтобы сравнивать как работает код в целевой ОС, а не на Винде, где идёт разработка.

#csharp
#conf
👍1
#dotnext, день 2, доклад 2.

Убийцы производительности в c#.

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

1. Следить за логгером
2. Следить за использованием кучи больших объектов
3. Прежде чем тащить ArrayPool в проект - почитать Best practices по его использованию.

Ну и некоторые новые пакеты/инструменты для повышения производительности, просто чтобы не потерять:
RecyclableMemoryStream
Pipelines.Sockets.Unofficial
ArraySegment

#conf
👍1
#dotnext, день 2, доклад 3.

Знакомство с функциональной парадигмой и F#.

В целом, код в функциональной парадигме выглядит для привыкшего к ООП человека очень странно.

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

Но острого желания вот прямо сейчас изучить F# не возникло.

#conf
#dotnext, день 2, доклад 4.

PureDI.

Человек рассказывал о своем пет-проекте - фреймворке для реализации Dependency Injection. В целом, довольно нишевая штука, хотя и интересная.

Обладает некоторыми преимуществами перед стандартными средствами.

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

Ну и заодно доклад проиллюстрировал, для чего на практике нужен механизм SourceGen в .Net (при билде проекта запускается специальный инструмент и генерирует исходный код по сконфигурированным правилам, а потом собственно билдит проект с этим новргенеренным кодом).

#conf
#dotnext, день 2, доклад 5.

Linq: искусство запрашивать данные.

В c# принято общаться с базой через ORM - Entity Framework (EF). Он позволяет пропустить фазу написания sql запросов путем трансляции внутреннего шарпового языка написания запросов к коллекциям с данными - Linq - в sql запросы.

Но иногда эти запросы разрастаются и становятся нечитаемыми даже в c# даже без единой строки SQL.

В докладе давался обзор фреймворков, позволяющих сделать запросы читаемее. Вообще, подобная проблема передо мной уже стояла при создании сложных запросов к MongoDB. В итоге получилось редкостное уродство, ставшее легаси в момент коммита, так что я понимаю боль авторов. На случай возможного будущего погружения в те же дебри, но с EF, ниже приведу просто набор ключевых слов для поиска:

Подход к упрощению запросов - паттерн спецификация
AddHocSpecification
ReplaceVisitor
Linqkit
nein-linq
Projectable
EF7 - IQueryExpressionInterseptor
Sieve - для комбинации фильтров
AutoFilterer


#conf
👍1😁1
#dotnext, просмотр в записи.

B-Tree индексы в PostgreSQL.

Доклад получился крайне полезным: в связной легкодоступной форме пересказали то, что я в общем-то знал по устройству внутрянки BTree индексов.

Кроме того, в процессе доклада всплыла ещё масса полезностей, которые ускользнули от моего внимания ранее;

1. explain (analyze, costs off, buffers) - синтаксис для просмотра плана запроса с прогнозом числа чтений страниц. Heap fetches - тот самый прогноз походов в таблицу после сканирования индекса для проверки наличия записи в таблице (если она ещё не зачищена от мусора вакуумом).

2. Спикер заострил внимание на разнице index scan и index only scan в плане выполнения запросов (последний не полезет читать доп информацию из таблицы после выполнения, ему для выполнения хватит инфы их индекса).

3. Спикер рассмотрел разницу по работе с BTree индексом в случае индексирования по bigint и по uuid. bigint при добавлении растит индекс в одну сторону. uuid - растит хаотично, расходует больше оперативной памяти в процессе работы. Разница по быстродействию может доходить до 7 раз. Отчасти проблему решает использование uiid v7, в котором используется временная метка. Но это не про стандартную библиотеку c#:)

4. Удаленные из таблицы данные остаются какое-то время залипать в индексе и накручивают Heap fetches в плане выполнения запроса. Помогает не дожидаться долго и тяжёлого вакуума (процесс очистки от мусора) фича из PostgreSQL 14 - bottom-up deletion - зачистка индекса от мусора в процессе вставки новых данных.

5. Спикер упомянул интересный путь оптимизации запросов: учитывать сортировку в индексе и идти к результату с определенной стороны с помощью CTE, например вызовом рекурсивного подзапроса > treshold_value, с постепенным нарастанием treshold_value.

#postgresql
#conf
🔥1
Был в начале декабря на конференции Highload++ (да, только сейчас нашлось время оформить интересное услышанное в посты). Дальше посты будут под тегом #highload

Услышал ещё некоторые занятные вещи про постгресс.

Ситуация: таблица со счётчиками остатков товара на складе. На 100 строк, постоянно обновляется. При обновлении создаётся копия строки и хранится в блоке рядом с актуальной. В какой-то момент место в блоке кончается - приходится добавлять новую запись в индекс. В итоге под нагрузкой индекс забивается всяким мусором. Решение - индекс с датой последнего изменения, вычитывать последнее значение.

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

pg_stat_replication - посмотреть что происходит в репликации, какой из трёх занятых в ней процессов (отправка WAL по сети, прием WAL и складирование на диск, чтение и применение изменений к реплике) тормозит.

В постгресе 15+ prefetch при репликации по факту не используется, лучше отключить.

#postgresql
#conf
👍3🔥1
Продолжаю конспект интересных выступлений с конференции #highload

В Авито в качестве архитектурного паттерна используется "микросервисный ад", больше 4000 микросервисов. В итоге, чтобы понимать происходящее, они трассируют все запросы, а затем отправляют их в графовую базу neo4j, чтобы визуализировать все связи микросервисов и найти закономерности.

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

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

А самый глубокий запрос выстроился в цепочку длиной в 51 (!) микросервис, через http.

#conf
#highload
😱6😁2💩1🤣1
Продолжаю конспект интересных выступлений на #highload.

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

Спикер от hh рассказал об успешном применении другого подхода:
1. Монолит рефакторится так, чтобы выносимый в микросервис кусок был вынесен в отдельный модуль.
2. Модуль выносится в отдельный проект или пакет, одной строкой подключаемый в монолит.
3. Монолит начинает ходить в функционал будущего микросервиса сам к себе (!) по http.
4. После того, как убедились что все ок, модуль подключается в пустой проект, а в монолите меняется одна строка в конфигурации и он начинает ходить в микросервис.

#conf
#highload
👍5🥰1
Последний интересный доклад был про подход к описанию архитектуры системы - Enterprise architecture on a page. Спикер был из МТС. Суть доклада следующая - был взять относительно новый подход к описанию архитектуры системы, доработан под нужды МТС, а затем внедрен.

Интересна реакция аудитории: процентов 90 восприняли доклад "это что за бред?" А вот люди, близкие к архитектуре очень заинтересовались. Мне пока не хватает квалификации понять всю глубину идеи, но зачем оно нужно - более менее понятно. Для описания того, о чем вещал спикер просто приложу ссылку на исходную идею, получившую развитие в МТС.

#conf
#highload

P.S. Я сам до конца не проникся, ибо не дорос ещё
👍2🔥2