TGViewer
Channel Public Channel
C# Short Posts 🔞

C# Short Posts 🔞

@dimasshortposts

Здесь я, Дима Афонченко @Undermove1, публикую короткие заметки о разработке (и около). Я не претендую на правильность высказываний и открыт к дискуссиям, исправлениям и конструктивной критике. С любыми деструктивными вещами можно приходить в комменты)
Subscribers
306
Photos
206
Videos
7
Links
211

Showing posts older than #416 · Back to latest

Older Posts 11 shown
Post #415 464
👽 Как защититься от космических лучей? Часть 3

Две части теории — теперь практика. Если не разобрались с прошлым постом, то я сделал интерактивную симуляцию кода Хэмминга, где можно пощупать всё руками:

🍔 HAMMING 🍔

🎓 А теперь к тому кто вообще это придумал?

А придумал Ричард Хэмминг аж в 1940-е годы. На фото как раз его компьютер Bell Model V — релейный монстр из 9000 реле. Ну как его. Он был одним из многих так сказать.

Реле — это такая катушка, которая притягивает контакт магнитом. Ток есть — замкнут (1). Нет — разомкнут (0). Из таких вот штук была построена вся память и логика. 9000 реле = компьютер. Типа 9000 тумблеров.

Так вот эти все реле залипали, окислялись, пружины в них уставали. В общем вся эта байда и без космических лучей ломалась 2-3 раза в день.

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

В будни за всей этой адской машиной следил оператор саппорта — чинил и перезапускал.

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

В какой-то момент он ушел с работы на выходные, предварительно поставив рассчет. А когда пришел в понедельник, то увидел, что машина сломалась в самом начал ерасчетов и все выходные ничего не делалала.

Достоверно неизвестно, что точно сказал тогда Хэмминг, но до нам дошла явно очищенная от американского фольклора фраза:

"Damn it, if the machine can detect an error, why can't it locate the position of the error and correct it?"

«Чёрт возьми, если машина может обнаружить ошибку, почему она не может найти её позицию и исправить?»

Уверен, что так он все и сказал. После чего в 1950 году вышла его статья "Error Detecting and Error Correcting Codes". Где и был представлен разобранный нами алгоритм. С тех пор прошло 76 лет.

🖥 Как это работает сейчас?

До недавнего времени проблема космических лучей не сильно всех волновала. Да и на самом деле биты могут флипнуться не только из-за них. Простого электромагнитного воздействия или банально сбоя в работе хардвера будет достаточно.

⚡ Инциденты

Amazon S3 (2008) — один перевёрнутый бит во внутреннем сообщении (без контрольной суммы) распространился по всем серверам. S3 лежал 8 часов.

Super Mario 64 (2013) — на стриме Марио телепортировался от бит-флипа. Значение высоты изменилось на один бит. Награда $1000 за воспроизведение не востребована.

😮 А как сегодня относятся к битым битам?

В 2009 Google опубликовала статью "DRAM Errors in the Wild”. В которой сообщила, что ошибки в памяти встречаются в 10-30x чаще чем думали. ~4000 исправлений на планку в год 😱 8% планок ловили ошибку за год.

В 2021 году плотность чипов так сильно увеличилась, что на DDR5 стали применять уже технологию Error Correction Codes (ECC)

То есть в 2021 году ECC стала де-факто стандартом в оперативке и основана как раз на кодах Хэмминга. Ибо они очень экономичные как по памяти так и по вычислениям. Алгоритм там немного модифицирован и позволяет исправить одну ошибку и отловить если их больше двух.

🅰️ Итого: Какую практическую пользу можно из этого извлечь? Ну помимо отмазки, что в вашей серверной стоит DDR4 и поэтому все так лагает под напором космической энергии.

Думаю, что тут можно извлечь красоту инженерной мысли! Идея Хэмминга безумно элегантная. На таких решениях можно учиться смиряться с несовершенством мира. Да, твои реле могут постоянно переключаться, припаиваться, космические лучи будут уничтожать твои бульки. Но ты всегда можешь сам отследить и восстановить то что поломалось. Это чем-то похоже на способность человека восстанавливаться после порезов.

Короче, вот такая серия постов. Я иногда пишу просто про такие вот инженерные штучки. Надеюсь, что они тут вам не мешаются и вы тоже от них кайфуете 🐈

#инженерныештучки #кодхэмминга #помехоустойчивость
  • ❤ 3
  • 🔥 2
Post #413 434
👽 Как защититься от космических лучей? Часть 2

Итак, как нам дешево защититься от космических лучей? Возьмём 11 бит данных:

1️⃣ 1️⃣ 0️⃣ 0️⃣ 1️⃣ 0️⃣ 1️⃣ 1️⃣ 0️⃣ 1️⃣ 1️⃣

Космический луч может испортить один бит. Как найти и исправить конкретный бит?

Первое что приходит в голову — разбить на группы и проверить чётность каждой. Но тогда мы знаем только в какой группе сбой, а не какой бит флипнулся. КПД те же 50%.

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

🟢 Решение — сетка 4×4

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

Но как это сделать? Во первых нашу линейку битов мы расположим в виде матрицы:


❓ ❓ ❓ 1️⃣

❓ 1️⃣ 0️⃣ 0️⃣

❓ 1️⃣ 0️⃣ 1️⃣

1️⃣ 0️⃣ 1️⃣ 1️⃣

Вопросики — контрольные биты на позициях-степенях двойки. Работают так же они будут позволять проверять четность. Но алгоритм тут чуть хитрее. Ибо каждыйц проверочный бит будет отвечать не за один столбец или одну строку, а сразу за две! Как это показано на пояснительном дикпике 1.

Теперь вычислим значения вопросиков:

К1: 1+1+0+1+0+1+1 = 5, нечётное → К1 = 1
К2: 1+0+0+1+1+1 = 4, чётное → К2 = 0
К4: 1+0+0+1+0+1+1 = 4, чётное → К4 = 0
К8: 1+0+1+1+0+1+1 = 5, нечётное → К8 = 1

Получилось что нам нужно хранить 16 бит вместо 11. КПД — 69%. Но на самом деле, чем больше бит нам нужно проверить, тем эффективнее будет этот алгоритм!

Готово! Защищённая последовательность:

1️⃣ 1️⃣ 0️⃣ 1️⃣

0️⃣ 1️⃣ 0️⃣ 0️⃣

1️⃣ 1️⃣ 0️⃣ 1️⃣

1️⃣ 0️⃣ 1️⃣ 1️⃣

☄️ Космический луч бьёт в позицию 3

Бит в правом верхнем углу переворачивается:
1 → 0.

1️⃣ 1️⃣ 0️⃣ 0️⃣

0️⃣ 1️⃣ 0️⃣ 0️⃣

1️⃣ 1️⃣ 0️⃣ 1️⃣

1️⃣ 0️⃣ 1️⃣ 1️⃣

Как найти нужный бит?

Прогоняем 4 проверки:

🟨 К1 (столбцы 1,3): сумма 5, нечётное → сбой!
🟦 К2 (столбцы 2,3): сумма 3, нечётное → тоже сбой!

Обе группы указывают на столбец 3. Ошибка одна — значит она там. Столбцы 1 и 2 чистые ✓

🟩 К4 (строки 1,3): сумма 4, чётное → ок ✓
🟧 К8 (строки 2,3): сумма 6, чётное → ок ✓

Строка 0, столбец 3 → позиция 3! Переворачиваем бит. Починено.

💡 Можно ещё проще: складываем номера сбойных групп. 1 + 2 = 3. Номер битого бита.

⁉️ Интерактивная визуализация:

Короче, на мощностях тележного редактора такие визуальные штуки объяснять довольно сложно. Но я заморочился и потратил вечерок на вайбкодинг визуализации. Поглядите ее. Там это все прям по шажочкам разложено и можно потыкать в разные биты и поиграться с космическими лучами. ГДЕ ЕЩЕ ВАМ ДАДУТ ПОИГРАТЬСЯ С КОСМИЧЕСКИМИ ЛУЧАМИ???

➡️ОТКРОЙ МЕНЯ ⬅️

Ну а в следующем посте, расскажу, как это работает применительно к нам и почему именно до 2021 года мы могли с уверенностью все валить на космические лучи. А сейчас уже не с такой уверенностью

#инженерныештучки #кодхэмминга #помехоустойчивость
  • ❤‍🔥 2
  • 👾 2
  • ❤ 1
Post #412 240

Forwarded from Dodo Engineering

Разбираемся в работе тестовых фреймворков в .NET! 🤓

Cитуация: написали вы функцию, кликнули в IDE на треугольник, а потом так раз и получили пачку зелёных галочек. Было? Было! А знаете ли вы, как устроен этот процесс? Ну вот как эти галочки получаются?

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

Спойлер: в тексте нет никакого заковыристого кейса, из-за которого Дима полез разбираться в dotnet test, зато есть много любопытных деталей и даже магии. В общем, переходите по ссылке ниже и изучайте вопрос вместе с Димой!

👉 Читать статью на Хабре
  • 🎉 7
  • ❤ 1
  • 👍 1
Post #411 214
Ффух, наконец вышла моя статья про то, как работают тестовые фреймворки. За эти три месяца, что статья готовилась, я уже раза три успел получить профиты от знаний который наросли при подготовке. 🐸
Post #410 272
👽 Как защититься от космических лучей? Часть 1

В 2003 году в городе Схарбек один из кандидатов на местных выборах внезапно получил на 4096 голосов больше, чем было физически возможно.

Конечно, нас таким не удивить. Но вот в Бельгии, где и проходило голосование, очень даже удивились и провели расследование. По результатам которого во всем обвинили космические лучи. ☄️

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

Не потому что космических лучей стало меньше, а потому что мы научились от них защищаться. И я хочу рассказать тут, как!

👿 Проблема
Давайте представим, что вы храните на диске или в памяти какую-то последовательность. К примеру 1011. И от этой последовательности зависит сломается ваша система или нет. Но в какой-то момент происходит вспышка на Солнце и ваша последовательность становится 1001. И вас будит алерт.

Вас просят предотвратить подобное в будущем. Как же это сделать?

🔢 Самое тупое решение — бит чётности

Идея: вы после каждых 4 бит добавляете пятый — контрольный. Его вы подбираете так, чтобы общее количество бит было в сумме чётным.

К примеру, для вашего числа:

1011 → 10111 (три единицы + одна контрольная = четыре, чётно)

Когда вы считываете это число, то просто суммируете все биты и если их сумма нечетная, как к примеру вот тут:

10011 ❌

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

10111 ✅

Это довольно хороший подход. Но как найти куда конкретно попал космический луч?

Самый простой вариант это хранить резервную копию, с которой бы мы сверялись в случае чего. Но КПД у такого решения конечно низкий, в районе 50%. А если быть точным, то именно 50%

Что означает, что на поддержание инфрастуктуры по защите от космических лучей вы будете тратить 50% оперативной памяти. Что конечно никто из менеджмента не одобрит. Проще закупиться шапочками из фольги. 🥈

Однако способ все же есть. И я попробую его в следующем посте объяснить. Оно того правда стоит!

#инженерныештучки #кодхэмминга #помехоустойчивость
  • 👾 2
  • 👻 1
Post #407 485
😂 Помните Semantic Kernel? Можете выкинуть. Тащите Agent Framework 1.0

Помните я писал про Semantic Kernel? Про то как можно за пару строчек кода собрать мини-агента с тулами, который сам решает что вызывать? Так вот — можете его выкинуть. 3 апреля Microsoft выкатили Agent Framework 1.0. Это не очередной превью — это стаблильнейший релиз от тех же людей, что делали SK. Фактически они взяли всё хорошее из SK, выкинули всё что бесило, и в итог переписали все с нуля.

Как говорится, устранили фатальный недостаток.

Главная боль SK была в том, что для всего нужен был объект Kernel. Хочешь тул зарегать — оберни в KernelPlugin, навесь [KernelFunction], добавь в Kernel.Plugins. Хочешь другого провайдера — отдельный класс агента (ChatCompletionAgent, OpenAIAssistantAgent, AzureAIAgent). Много обвязки.

В Agent Framework всё это выкинули. Вот что поменялось:

1️⃣ Один тип агента на всех провайдеров. ChatClientAgent работает с любым IChatClient — OpenAI, Azure, Anthropic, Ollama. Никаких отдельных классов.

2️⃣ Тулы без атрибутов. Не нужен [KernelFunction]. Берёшь любой C# метод, оборачиваешь в AIFunctionFactory.Create() — и готово. Description по-прежнему важен (как я и говорил — мусор на входе, мусор на выходе), но обвязки стало меньше.

3️⃣ Сессии из коробки. Не надо руками таскать ChatHistory. Вызвал agent.CreateSessionAsync() — и агент сам хранит историю переписки между вызовами.

4️⃣ Middleware pipeline. Вместо фильтров SK — полноценный пайплайн как в ASP.NET. Три уровня: перехват на уровне агента, на уровне вызова функций, на уровне IChatClient.

Покажу на примере. На пояснительном дикпике 1 — агент с тулами для работы с GitHub. Обратите внимание: никакого [KernelFunction], никакого Kernel.Plugins. Просто метод с [Description] и AIFunctionFactory.Create(). Минус целый один атрибут! 😳

А на дикпике 2 — сравнение старого SK и нового Agent Framework бок о бок. Тот же функционал, вдвое меньше кода.

А ещё там есть мультиагентные воркфлоу. На дикпике 3 — цепочка из трёх агентов: один исследует, второй пишет, третий редактирует. И всё это собирается в одного workflowAgent. Я вот тут чуток попробовал. Мне понраивлось в целом

А что с Semantic Kernel, кстати где он?

Ну вот тут кек. ☺️ Мы буквально только-только затащили SK в проект. 😀 Написали плагины, настроили агентный цикл, я даже посты про это написал!!! — и тут Microsoft такие: "а мы тут новый фреймворк сделали, старый в maintenance mode". Классика AI. А помните как мы угорали над фронтентдными фреймворками? Я вот сейчас плчу по тем временам. 😭

SK официально переходит в maintenance mode. Это значит: баг-фиксы и секьюрити патчи будут, но новых фич не будет — всё новое только в Agent Framework. Microsoft рекомендует мигрировать в течение 6–12 месяцев.
Гайд по миграции. 🫠

🅰️ Итого: Agent Framework — это то, чем SK хотел быть, но не мог из-за легаси. Выбрасывайте SK и срочно переходите на Agent Framework! Ладно, это шутка. Если уже используете SK — не паника, он ещё поддерживается, но мигрировать стоит. Если только начинаете — начинайте сразу с Agent Framework.

#csharp #dotnet #ai #agents #microsoft
  • 🔥 4
  • ❤‍🔥 1
  • 😈 1
Post #403 536
🛡 Rate Limiting, часть 3: распределённый лимит через MySQL

Итак, проблема простая: встроенный rate limiter считает in-memory. Каждый под живёт своей жизнью и ведёт свой счётчик. Юзер с лимитом в 10 запросов спокойно делает 20 — по 10 на каждый под (дикпик 1).

Итак, как сделать рейт-лимиты распределенными? И да, тут я изучал как это сделать через MySQL потому что у нас сейчас в работе MySQL, запросов пока что не очень много, и раздувать зависимости не хочется. Короче, обстановка позволяет такой эксперимент, а если что, не проблема первое время пожить с InMemory, а потом переехать на что-то более быстрое.

Так вот, я не нашел каких-то решений, которые бы имплементировали бы распределенную блокировку FixedWindow на MySQL из коробки. Но, как оказывается эта задача решается довольно понятно. Непросто, но хотя бы понятно.

🩳 Если говорить коротко, то вам нужно реализовать наследника для базового класса RateLimiter. Там есть пара методов, которые нужно заоверрайдить, но наверное самый главный – это AcquireAsyncCore. Который и будет выполнять чтение из базки.

🏓 Таблица в базке простая: ключ партиции (юзер/IP), ID окна, счётчик запросов и время истечения (дикпик 2).

Вся магия в INSERT ON DUPLICATE KEY UPDATE. Один SQL-запрос атомарно либо создаёт запись со счётчиком 1, либо инкрементит существующий. Если окно истекло — сбрасывает счётчик. Никаких транзакций, никаких локов — InnoDB сам разруливает на уровне строки (дикпик 3).

Реализованный класс со всеми запросами можно глянуть вот тут.

Дальше подключаем через extension method — по сути также как и встроенные лимитеры (дикпик 4). Для приложения ничего не меняется, просто теперь счётчик общий на все поды.

Опять же, MySQL тут мегаспорное решение. И тут конечно надо бы посоветовать Redis или что-то такое. Но думаю, что полезно просто узнать об этом подходе. Что вообще есть этот RateLimiter и что в целом его можно довольно быстро заимплементить на любом доступном хранилище.

🅰️ Итого: если вам нужен рейт-лимитер, то мы можете заюзать стандартную библиотечку. Если нужно сделать лимитер распределенным, то это тоже можно, нужно всего лишь корректно реализовать класец RateLimiter

#csharp #ratelimiting
  • ❤ 1
  • ❤‍🔥 1
  • 🔥 1
Post #399 599
🛡 Rate Limiting, часть 2: как это красиво прикрутить в ASP.NET Core

Окей, в первой части разобрались какие алгоритмы бывают. Теперь самое вкусное — как это всё настроить так, чтобы было не стыдно показать на код-ревью.

В Microsoft.AspNetCore.RateLimiting всё уже есть из коробки. Самый базовый вариант — создаёшь именованную политику и вешаешь на эндпоинт (за примером проследуйте на пояснительный дикпик 1).

Можно сделать и глобальный лимитер на всё приложение, но чаще нужны именованные политики — разные лимиты для разных эндпоинтов. А ещё есть PartitionedRateLimiter — он создаёт отдельное ведро токенов для каждого пользователя (дикпик 2). Один энтузиаст с циклом не мешает остальным.

К примеру, для моего API базы знаний план может быть такой:

1️⃣ эндпоинт article/smart-search, который дёргает LLM — жёсткий Token Bucket, 20 запросов в час на юзера.

2️⃣ Остальные эндпоинты — мягкий Fixed Window на 100 запросов в минуту. Health-чек — без лимитов, чтобы кубер не страдал. Всё это настраивается через именованные политики и атрибут EnableRateLimiting на контроллере (дикпик 3).

Ещё прикольный момент вычитал — как думаете, что возвращать когда лимит превышен?

Ответ: По дефолту просто 429, но можно красиво: клиент получает заголовок Retry-After с количеством секунд до следующей попытки 🕜. Вежливо и по стандарту (дикпик 4).

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

Об этом в следующей части. А пока спойлер: встроенный rate limiter считает in-memory, и каждый под живёт своей жизнью…

📦 Кстати, не пояснительными дикпиками едиными! 🍆 Вот пояснительный пример с кодом: https://github.com/Undermove/csharpshortpostsexamples/tree/main/RateLimitingExample

#csharp #ratelimiting
  • 💯 2
  • ❤ 1
  • 🌭 1
Post #398 509
🛡 Rate Limiting, часть 1: зачем тебе ограничивать запросы и какие алгоритмы вообще бывают

Помните серию постов про Геншин? Было давно конечно, но вдруг. Там я вскользь упомянул, что мы готовили систему к нагрузкам. Одна из штук, которую мы тогда настроили — rate limiting. По 3 запроса в минуту на пользователя, чтобы сплоченные школьники-анимешники не положили нам всё к чертям.

Сейчас снова вернулся к теме — планирую API для базы знаний с LLM под капотом, а там без лимитов один “энтузиаст” с циклом в консоли сожрёт весь бюджет. Полез разбираться и оказалось, что алгоритмов четыре штуки. Все они живут в Microsoft.AspNetCore.RateLimiting и подробно описаны в официальной документации.

🖥 Fixed Window — самый тупой и понятный. Окно в 1 минуту, в нём 10 запросов. Счётчик обнулился — снова 10 запросов. Проблема: на стыке двух окон можно пульнуть 20 запросов за секунду (10 в конце первого окна + 10 в начале второго). Для большинства задач это ок, но если у тебя что-то чувствительное — читай дальше.

🎚 Sliding Window — фиксит проблему стыков. Окно "скользит" вместе со временем. Вместо жёстких границ "с 12:00 до 12:01" оно считает запросы за последние 60 секунд от текущего момента. Плавнее, честнее, чуть дороже по ресурсам.

🪣 Token Bucket — у тебя ведро с токенами. Каждый запрос забирает токен. Токены подкапывают с постоянной скоростью. Ведро полное — можно сделать короткий всплеск запросов. Пустое — жди. Все вайбкодеры с этим алгоритмом точно знакомы, только с другой стороны баррикад))) Кайф в том, что это естественно разрешает burst-трафик, но держит среднюю скорость. Идеально для API, где пользователь может иногда хотеть пачку запросов подряд.

🐸 Concurrency Limiter — это вообще другая история. Не "сколько запросов в минуту", а "сколько запросов одновременно". Типа: максимум 5 параллельных запросов от одного юзера. Полезно когда у тебя тяжёлые операции — генерация отчётов, вызовы LLM — и ты не хочешь чтобы один клиент забил все потоки.

Для моего API базы знаний думаю брать Token Bucket — хочу разрешить человечку задать пачку вопросов подряд, но чтобы средняя скорость не превышала, скажем, 20 запросов в час. Ну и еще это просто звучит прикольнее всего 😄 Все остальное скучное какое-то

В следующей части — как это красиво прикрутить в ASP.NET Core через встроенный middleware, с разными лимитами для разных юзеров. Кстати, хорошее введение в тему написал Maarten Balliauw, один из авторов этого middleware (статья).

#csharp #ratelimiting
  • 🔥 5
  • 🐳 1
  • 😎 1
Post #396 313
Коллаба, которую мы заслужили!
Older posts →
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →