tgindex
Евгений Козлов пишет про IT

Евгений Козлов пишет про IT

Статистика

14 лет пишу код, 10 - в прод. Руковожу командой инженеров в Т-Технологиях. 📌 Backend, Data, System Design 📌 Concurrency, Performance, Algorithms 📌 Infrastructure, Reliability 📌 Карьера, Менеджмент Для связи: @ea_kozlov

Последний пост
10 авг.
Последнее чтение
22:41
Постов за неделю
0
Всего постов
20
Тип
открытый
Язык
русский
Категория
Карьера
В каталоге с
13 авг.
Подписчики
2 836
+1 за 5 дн.
Сутки
+1
+0,04%
Неделя
 
Месяц
 
Просмотров на пост
2 130
20 постов
Вовлечённость
75,1%
к подписчикам
Постов в день
0,0
всего 20
Упоминаний
1
каналов
Охват размещения
оценка
1/24сутки в ленте
643
1/48двое суток
736
1/72трое суток
794

Оценка по просмотрам недавних постов: пост набирает почти всё за первые сутки.

Посты

  • Concurrency and Consistency. Non-blocking, lock-free and async. Пост №4. Obstruction-free или Гарантия отсутствия препятствий. В прошлом посте мы дали все необходимые определения и провели параллели. Но все таки мы с вами теоретики, а не практики, поэтому без кода обойтись не могло. Гарантию obstruction-free легче всего начать объяснять на примере кода, который мы все хотя бы раз в жизни писали - thread-safe структура данных закрытая мьютексом, например мой любимый счетчик: std::mutex m; int shared_value = 0; void increment() { m.lock(); // (*) shared_value++; // долгая критическая секция m.lock(); } Потоков N, где N > 1. Соответствует ли код obstruction-free? Нет, не соответствует. Вспоминаем как у нас работает ОС. У нас есть планировщик который может остановить выполнение программы в любой момент, чтобы дать ресурс кому то еще. И теперь ситуация: - Поток №1 захватывает мьютекс и его сразу же усыпляет ОС чтобы разбудить поток №2 - Поток №2 проснулся, пытается тоже сделать increment, но терпит неудачу, так как сосед уже захватил мьютекс. - Поток №2 после нескольких попыток засыпает потерпев неудачу. Видим, что нет ни малейшего намека на выполнение требований из определения термина. В программе нет конкуренции, один поток работает, но достигнуть прогресса не может, так как ресурс захвачен соседом. Поэтому делаем вывод - код работающий в блокирующем режиме синхронизации не соответствует гарантии obstrcution-free. ——— Еще ситуация, "работаем в криптовалюте" переводим виртуальные денежки между счетами, естественно с гарантиями отсутствия потерь и дублирования: struct Account { std::atomic<int> version; int balance; }; void transfer(Account& from, Account& to, int amount) { while (true) { int v1 = from.version.load(); int v2 = to.version.load(); int newFromBalance = from.balance - amount; int newToBalance = to.balance + amount; if (from.version.compare_exchange_strong(v1, v1 + 1)) { if (to.version.compare_exchange_strong(v2, v2 + 1)) { from.balance = newFromBalance; to.balance = newToBalance; return; // успех } from.version.store(v1); } } } Здесь ситуация отличается значительно. Если у нас несколько потоков, но работает только один - мы всегда будем достигать прогресса, так как у нас нет конкурентов за значения атомарных переменных. CAS операции всегда будут успешны и больше одной итерации в цикле нам не грозит. Такой код соответствует гарантии obstruction-free. Но обольщаться рано, не зря в быту обычно все упоминают lock-free а не obstruction-free ведь её недостаточно чтобы писать высокопроизводительные программы. В следующих постах разберемся с этим подробнее. Ваши идеи и соображения что не так с кодом выше буду ждать в комментариях😊 На этом все, спасибо что дочитали до конца, до встречи!

  • 8 авг.8483412

    Concurrency and Consistency. Non-blocking, lock-free and async. Пост №3. Что существует кроме Lock-Free? Гарантии в блокирующей и неблокирующей синхронизации. В посте №1 я дал определение понятию lock-free. Дальше сразу пошёл разбирать ABA-проблему, и это было ошибкой. Всё-таки важный кусочек базы я упустил, поэтому делаю шаг назад. Когда мы пишем код, мы так или иначе ожидаем от него определённой степени корректности. В случае с программами, в которых есть блокирующие примитивы синхронизации, нам важно, чтобы: - Примитив обеспечивал эксклюзивный доступ к критической секции - это гарантия mutual exclusion и, по сути, гарантия безопасности нашего кода. - В нашем коде отсутствовали взаимоблокировки - это гарантия deadlock freedom. - Поток, намеревающийся попасть в критическую секцию, гарантированно попадал в неё за конечное время - это гарантия starvation freedom. За дедлоки обычно отвечает программист, гарантии отсутствия голодания обычно падают на рантайм языка программирования (потому что в нём реализован примитив синхронизации) и рантайм ОС, потому что он планирует исполнение потоков. А какие есть гарантии в неблокирующей синхронизации? - Гарантия отсутствия препятствий (Obstruction-free): если поток активен и у него нет конкурентов, он должен исполнять полезные инструкции, демонстрировать прогресс. - Гарантия отсутствия блокировок (Lock-free): наш код гарантирует, что в случае конкурентного исполнения кто-то обязательно достигнет прогресса. - Гарантия отсутствия ожидания (Wait-free): каждый поток завершает операцию за ограниченное число шагов, независимо от того, что делают другие потоки. Очень похожие определения, но немного другими словами, не находите? В следующих постах мы на примерах посмотрим, что скрывается за каждым красивым словом. P.S. Канал переходит в режим Wait-Free, теперь посты гарантированно будут публиковаться за конечное количество дней😁 Я вернулся.

  • 23 мая2 0511839

    Несколько лет назад я написал целый цикл постов на тему виртуализации. Мотивация - расставить все точки над и, разобраться что есть что. Провести параллели и границы между контейнерами, виртуалками, а также объяснить понянтным языком что же такое Docker. Получилось 4 поста: - Введение в виртуализацию. Какая бывает, какие проблемы решает - Аппаратная виртуализация - Виртуализация на уровне ОС (Контейнеризация) - Истинно ли утверждение что Контейнеры это Docker? Почему я вспомнил об этих постах? Мой товарищ Никита у себя в канале взялся еще глубже препарировать тему и уже опубликовал пост о продвинутых технологиях на стыке виртуалок и контейнеров. Он посвящен OCI и тому что современные контейнеры стремятся быть абстракцией поверх VM, а не чем-то сбоку. И дальше идет разбор софта подтверждающего этот тезис. 🔖Контейнер ≠ Docker [1/3] by DevOps Brain Буду читать сам, поэтому могу смело советовать😊 Если вам такие посты заходят поддержите Никитоса лайком и подпиской❤️

  • 18 мая1 956239

    Concurrency and Consistency. Non-blocking, lock-free and async. ABA Problem Сегодня поговорим о проблеме неразрывно связанной с lock-free алгоритмами. Она возникает в коде на атомиках и демонстрирует наглядно что имея атомики в коде, казалось бы безопасный примитив можно выстрелить себе в ногу. Для воспроизведения проблемы нам нужны - Cтруктура данных с указателями. - Compare and Swap. Представим себе что у нас стоит задача реализовать потокобезопасный стек. Классическая реализация неезопасна, с мьютексом достаточно медленная для наших условий, остается вариант с атомиками. type Node[T any] struct { val T next atomic.Pointer[Node[T]] } type UnsafeStack[T any] struct { dummy *Node[T] top atomic.Pointer[Node[T]] } func NewUnsafeStack[T any]() *UnsafeStack[T] { s := &UnsafeStack[T]{dummy: &Node[T]{}} s.top.Store(s.dummy) return s } func (s *UnsafeStack[T]) Push(n *Node[T]) { for { top := s.top.Load() n.next.Store(top) if s.top.CompareAndSwap(top, n) { return } } } func (s *UnsafeStack[T]) Pop() *Node[T] { for { top := s.top.Load() if top == s.dummy { return nil } if s.top.CompareAndSwap(top, top.next.Load()) { return top } } } func (s *UnsafeStack[T]) Values() []T { var out []T for n := s.top.Load(); n != s.dummy; n = n.next.Load() { out = append(out, n.val) } return out } Основное отличие от версии которую бы мы написали с использованием мьютекса - бесконечные циклы в push, pop. Ведь если несколько потоков сделают вставку или извлечение то прочитанная в локальную память переменная top станет неактуальной и CAS операция будет неуспешной. Поэтому мы будем пытаться реализовать операцию до победного. Демонстрация ABA Для того чтобы продемонстрировать проблему в этом коде я подготовил Go Playground сниппет. Его суть: - Есть 2 горутины, одна пытается извлечь данные из стека (не через использование функции pop, а напрямую, это нужны чтобы имитировать прерывание в нужном месте программы). - Горутина №2 - это череда операций (pop, pop, push). В конце она пытается вставить узел который являлся изначальной вершиной стека. - Когда управление возвращается горутине №1 она не видит абсолютно ничего криминального и делает успешный CAS, хотя внутреннее представление элемента поменялось и ссылка на следующий элемент в стеке изменилась. На выходе получаем грязный стек c данными которых в нем быть не должно. Как решается проблема ABA? Чтобы решить проблему ABA можно взять одно из решений: - размечать узлы в стеке версиями. Этот подход подразумевает что адреса узлов сохраняются, но CAS все равно упадет из за несовпадения версий. - оборачивать внутри стека узлы в указатели, тогда у нас не будет повторения адресов и успешных CAS. Я для простоты покажу работающий код решения №2. Выводы ABA Problem это один из примеров того что может случиться когда мы пишем сложные программы в погоне за высоким перформансом. Посмотрите на получившийся код и вспомните как вы писали свой первый стек. И вот в голове маячат вопросы: - Стоит ли так извращаться? Ради чего это всё? - Насколько разница существенная? Это рассмотрим в следующем посте, а пока ставьте лайки и делитесь своим опытом работы с lock-free стеками и очередями.

  • 24 апр.2 1283838

    Concurrency Mindmap Написав пост про Lock-Free я осознал что за 2 года, с момента публикации самого первого поста у меня из головы некоторые моменты выпали напрочь (оно и понятно, не каждый день на работе сталкиваюсь с тем о чем рассказываю). Также пришел к выводу, что убер большие посты саммари по 20+ ссылок тяжело воспринимать тем кто подписался на канал недавно и только погружается в вопрос. А мне очень уж хочется по максимуму вас вовлекать, хоть материал не самый простой. На мой взгляд воспринимать большой скоуп информации помогают визуализации, поэтому я заморочился и оформил Mindmap по всем материалам. Мне он помог 100%, рассчитываю что он станет отправной точкой в тему Concurrency и позволит выбрать траекторию погружения и увидеть картину вширь. 💎 Исходник доступен по ссылке ----- 🔹 Concurrency, Threads & Processes 🔹 Concurrency & Consistency

  • 21 апр.1 9712822

    Concurrency and Consistency. Non-blocking, lock-free and async. Пост №1. В чем разница между Blocking, Non-blocking, lock-free? После написания десятков постов о традиционном способе синхронизации конкуррентных программ - блокирующей синхронизации, я задумался, а возможен ли другой путь? Я что-то слышал про lock-free алгоритмы, а также слышал что в распределенных системах существуют conflict-free структуры данных. Вдогонку к этому - флешбэки из десятых когда был максимальный хайп вокруг функционального программирования и отовсюда звучал тезис - "только на ФП языках получается трушный concurrency код". Что же там такого под капотом у этих языков чего нет у остальных я разобраться не успел, но у меня закрались сомнения от таких сильных заявлений, ведь какой бы не был язык все что мы пишем превращается в - syscalls для ядра ОС написанного на С. - инструкции для процессора. Поэтому в новом цикле постов будем развеивать туман. Начнем с разбора основных баззвордов. Блокирующий (blocking) вызов Понятие блокирующих функций мы подробно разбирали в прошлых постах. Во время работы один из потоков нашей программы может заблокироваться если наткнулся на блокирующий примитив синхронизации захваченный или например ему понадобилось вызвать системную функцию. В такие моменты исполнение инструкций потоком останавливается, поток засыпает. Разблокировка потока происходит по сигналу ОС или рантайма ЯП. Примеры блокирующих функций: - функции работы с сокетами (send, recv, accept) - функции работы с файлами (fsync, fdatasync) - синхронизация (pthread_mutex_lock, pthread_cond_wait, pthread_barrier_wait) - sleep 😊 Неблокирующий (non-blocking) вызов Тут все намного проще. Неблокирующая функция - та в которой нет вызовов блокирующих функций. И как следствие остановить выполнение такой функции может только ОС или рантайм языка программирования через вытесняющую многозадачность. Как обеспечивать синхронизацию в случае когда мы не можем себе позволить засыпать и передавать контроль ОС? Ответ - Spinlocks. Потому что это примитив с активным ожиданием, то есть он заставляет потоки постоянно крутится в ожидании освобождения ресурса. Lock-free Понятие lock-free обычно упоминают в контексте структур данных или алгоритмов. В общем случае это код в котором - Отсутствуют мьютексы. Как следствие невозможно уснуть и передать контроль ОС. Отсутствует блокирующая синхронизация - Отсутствуют спинлоки. Несмотря на неблокирующую логику спинлоков у нас в программе создается ситуация эксклюзивного владения и при захвате примитива одним потоком у остальных нет возможности продвигаться и делать полезную работу. С чем мы в итоге остаемся? Для того чтобы строить lock-free алгоритмы и логику у нас остается только один путь - самостоятельно писать код на атомарных операциях (CAS, TAS, FAA). Без этого с большой вероятностью наша программа будет работать некорректно, так как все равно даже без примитивов синхронизации потоки программы в любое время могут быть остановлены ОС и запущены спустя время. И если поток был остановлен где то посередине важной операции и такой сценарий не учтен в коде нас будут ждать сюрпризы😁 Нужно ли стремиться к lock-free коду? Когда мы пишем код, используем структуры данных, алгоритмы мы всегда взвешиваем все за и против. В Concurrency тоже самое. Алгоритм / структура данных построенный на Blocking примитивах работает предсказуемо и понятно, не самый сложный код. Поддержка в любом ЯП и ОС из коробки. Для низконагруженных приложений - обязательно к использованию. Под высокой нагрузкой может стать бутылочным горлышком. Алгоритмы и СД со спинлоками или трушные lock-free без них потенциально позволяют увеличить пропускную способность системы, но все равно существует риск пауз связанных с активным ожиданием. Плюс такие программы все таки сложнее проектировать и реализовывать. Подступаться к снаряду стоит после того как убедились что бутылочное горлышко именно в блокирующих примитивах. На этом первый пост всё, спасибо что читали, оставляйте комментарии и реакции, чтобы я видел что вы ждали посты❤️

  • 8 апр.1 8042117

    Concurrency, Synchronization and Consistency. Double checked locking problem Пока готовил материал для новых постов, понял что не рассказал о задачке с которой иногда приходится иметь дело в работе. Представьте что у нас конкурентное приложение. И в нем есть объект обязанный существовать в единственном экземпляре. С ним и будут работать наши потоки. Инициализация объекта тяжелая, занимает какое то время. Варианты: - Инициализация ресурса на старте. - Инициализация в момент запроса ресурса (lazy init). Вы с командой подумали и решили - на старте слишком долго, давайте делать лениво. Посидели, подумали и получилось вот так: type Cache struct { data map[string]string } type Service struct { cache *Cache mu sync.Mutex } func (s *Service) GetCache() *Cache { s.mu.Lock() defer s.mu.Unlock() if s.cache == nil { s.cache = &Cache{ data: make(map[string]string), } } return s.cache } Всё четко работает, но после релиза видите по метрикам и профилировщику что горутины начали конкурировать в этом кусочке кода (он вызывается часто). Надо что-то менять, и вы приходите к выводу - мьютекс нужен только когда объект не существует, иначе нужно просто вернуть ресурс. package main // код выше не изменился func (s *Service) GetCache() *Cache { if s.cache == nil { s.mu.Lock() defer s.mu.Unlock() if s.cache == nil { s.cache = &Cache{ data: make(map[string]string), } } } return s.cache } Все работает четко, но код слегка попахивает. Можно ли красивее? // код выше не изменился type Service struct { cache *Cache once sync.Once } func (s *Service) GetCache() *Cache { s.once.Do(func() { s.cache = &Cache{ data: make(map[string]string), } }) return s.cache } Это и есть Double Checked Locking (DCL). На первый взгляд может показаться что проблема высосана из пальца, но на самом деле Go просто обошелся малой кровью - спасибо за простую модель памяти. В Java раньше был целый челлендж с тем чтобы правильно написать подобный код - почитать об этом можно здесь и здесь. Вторая ссылка так вообще монументальная, под ней подписался в том числе Joshua Bloch - автор Effective Java. В его книге как раз есть глава посвященная этой проблеме. Если на моем канале есть джависты, ставьте 🐳 и рассказывайте как вы писали свой первый синглтон😁 Приходилось ли вам писать подобный код и к чему это привело?

  • 23 мар.1 9681810

    Мой коллега Матвей на прошлой неделе дебютировал на Хабре с классным лонгридом о своем опыте добавления в язык Golang "условного выражения". Все по полочкам, как мы любим - небольшое теоретическое введение, и очень много кода. Если вы интересуетесь компиляторами и дизайном языков - вам точно будет что обсудить с Матвеем в комментариях. Лайки и репосты горячо приветствуются😊 https://habr.com/ru/articles/1012900/

  • 22 мар.1 8561722

    Метрики? Метрики! Метрики...А есть ли жизнь за пределами Prometheus? Обычно инженеры подразумевают одно и тоже когда говорят про метрики и Prometheus. Мы работаем с PromQL синтаксисом, устанавливаем экспортеры расположенные в Github организации Prometheus. Выглядит так что это одно и тоже. Но что если нет? Краткая историческая справка Prometheus был создан на SoundCloud в 2012 году и с тех пор стал стандартом для мониторинга систем. Если упростить система мониторинга состоит из: - Приложения экспортирующего метрики. Это может быть ваше приложение с метриками оформленными вами. Для их экспорта вам требуется специальный SDK. Альтернатива - взять готовый экспортер для сбора стандартных метрик (кафки, постгреса, или просто вирт. машины). - Prometheus server. Отвечает за сбор метрик с целей. Экспорт метрик осуществляется за счет публикации HTTP ручки с набором метрик. И пром опрашивает раз в N секунд всё что оформлено в конфиге. Подсистема чтения данных и язык запросов встроены в Prometheus Server. - TSBD. Система отвечающая за долговременное хранение собранных метрик. Важно отметить что эта система поддерживает только Local Disks. Следствия такой архитектуры: - Горизонтальное масштабирование за счет ручного шардирования. Чтобы собирать метрики с большего количества целей нужно добавлять больше инстансов Prometheus Server и делить нагрузку между ними. Упереться можем как в диск там и в CPU/RAM.Также нужно отметить что у Prometheus нет встроенного инструменте для объединения всех инстансов prometheus в единую PromQL View для чтения. - Избыточность ресурсов. Диски дорогие, а данные на них устаревают. При этом возможна ситуация что данные хочется сохранить для редкого доступа. По Compute тоже все не так гладко, Prometheus это очень прожорливая штука. Тут на сцену выходят конкуренты и альтернативы: - Victoria Metrics. Написали все с нуля, добились лучших значений по сжатию данных, количеству метрик которые скрепятся в секунду, потребление RAM / CPU. Также был добавлен PUSH режим для того чтобы снять нагрузку с Prometheus Server (и не только). Также предоставляет vmselect - Query Engine для аггрегаций метрик с нескольких серверов хранящих метрики. - Thanos. Добавляет в архитектуру Prometheus возможность экспорта данных в S3. Ставится как sidecar рядом с приложением. На самом деле это всё. Почему? Потому что Thanos это скорее набор плагинов в дополнение к Prometheus. А Виктория это прям полноценная независимая экосистема. - Grafana Mimir. Узнал об этом звере когда готовил пост. Поддерживает S3. Целится в multi-tenant сценарии - когда у вас большой энтерпрайз, куча отделов и хочется выстроить правила игры для всех, с квотами и лимитами. 🔗 Заметка со сравнением 3х инструментов Как видите каждый инструмент так или иначе помогает закрыть слабые места ванильного Prometheus. VM так вообще ушли далеко вперед и создали свой коммерческий продукт. Для меня их история развития прям канонический пример композиции - как сделать свой продукт. Ребята повторили API Prometheus для того чтобы все ранее созданные библиотеки и практики остались совместимы. Если вы компания и у вас Prometheus - можно мигрировать на VM и удешевить инфру. На больших объемах эффект будет пропорционален. Делитесь в комментариях, что нового узнали, а также где хранятся метрики в вашей компании😊

  • 17 мар.1 7552132

    Метрики? Метрики! Метрики...Пишем и настраиваем алерты Прошлый пост очень тепло был принят вами, судя по реакцим и продвинутой статистике, поэтому я пошел дальше рыскать по закромам и генерить идеи чем бы еще интересным и полезным с вами поделиться. Сегодня хочется поговорить о развитии системы мониторинга за счет внедрения механизмов алертирования. Шаг №1 - Перестать глазами мониторить дашборды и графики 😑 Проблема - за дашбордами не уследить, слишком много визуализаций, можно что-то пропустить, да и много времени уходит. ✅ Решение - настроить уведомления для метрик которые достигли порогового значения. Называют их алерты. 🛠 Тулинг - https://github.com/prometheus/alertmanager. Позволяет настроить декларативно правила рассылки алертов по метрикам. Поддерживается множество получателей, в том числе Telegram. Шаг №2 - На какие события мне нужны алерты? Современные инструменты уже из коробки предоставляют стандартные метрики для того чтобы инженер мог по ним строить дашборды или алерты. Но чтобы построить хорошие алерты важно не только знать про наличие метрики но и специфику поведения системы. В написании правильного алерта для конкретного кусочка инфры поможет ресурс https://samber.github.io/awesome-prometheus-alerts/. Огромная шпаргалка по написания алертов для всего что только есть: - Базы данных, брокеры сообщений. - Оркестраторы. - Сеть, безопасность. - Прокси, балансировщики. - Runtime ЯП. Отличный практический инструмент для закрепления теории из прошлого поста. Для того чтобы собирать предложенные в гайде метрики понадобится настроить один или несколько экспортеров, так как по умолчанию метрики не экспортируются. Шаг №3 - Калибровка и тюнинг Алерты это конечно хорошо, но у них бывает неприятный эффект - они начинают досаждать и отвлекать. И нужно работать над observability также как и с кодом: отключением неактуальных алертов, добавлению новых, калибровка интервалов срабатывания (чтобы не спамил каждую секунду). Иначе есть риск что инженеры просто перестанут читать чат с алертами и он просто станет помойкой. А если все сделали правильно - алерты будут к месту, инженеры будут им доверять, а спамить они будут только в случае когда действительно "всё пропало"🙂 ------ На этом у меня всё, пишите в комментариях что у вас на проекте трекается алертами🙂

  • 14 мар.3 24257196

    Метрики? Метрики! Метрики...Или введение в Prometheus и Monitoring Ох уж это волшебное слово которое я слышу чуть ли не каждый день. Всем нужно что-то считать, оценивать. Визуализировать и оценивать реальность во всех ее проявлениях. Кто-то считает заработанные денежки, кто-то потраченные, кто-то и то и другое. В общем считать это нужное и полезное занятие. В том числе это нужно и нам - разработчикам. Для поддержки высокого уровня сервиса и построения надежных системм важно понимать как функционирует написанный нами код и железка на которой мы его развернули. А понимание можно извлечь только собирая информацию и вариантов у нас обычно 3 - логи, метрики, трейсы. Если с логами все интуитивно понятно - это фиксация фактов / событий в нашей системе. Их легко начать собирать и пользоваться ими, то с метриками дела обстоят веселее и стартануть в их сборе также быстро как с логами не получится, про трейсы вообще молчу. Но вернемся к метрикам. Я мог бы написать целое полотно, о том как это всё работает, но считаю что лучше будет поделиться с вами материалами которые помогли лично мне разобраться с тем как работает сбор метрик, их хранение и визуализация. Возможно они будут вам полезны и помогут сделать тот самый первый шаг к изучению предмета. 📖Шаг №1 - Нескучная теория Первым делом я советую прочитать цикл статей "Человеческим языком про метрики". Это настоящее сокровище, ничего лучше на русском языке мне не встречалось. Очень доходчиво, с примерами. Покрывается все - мат.аппарат, технические детали работы Prometheus, визуализация. Не разобраться в предмете не получится 👨‍🔬Шаг №2 - Закрепляем теорию Закрепить изученное в статье на практике можно с помочью https://demo.promlens.com. Это интерактивный визуализатор метрик по запросу. С возможностью разобрать запрос на этапы выполнения и получить пояснения. Можно засунуть в него свой эндпоинт для работы с метриками, а можно работать с источником по умолчанию https://demo.promlens.com/metrics Примеры метрик которые можно быстро засунуть в него и посмотреть результат доступен в шпаргалке https://promlabs.com/promql-cheat-sheet/ 🔬Шаг №3 - Экспериментируем на своей машине После быстрого освоения построения визуализаций и готовых метрик в браузере можно переходить поближе к коду и практическому применению. Как пример - можно взять репозиторий https://github.com/ContainerSolutions/k8s-deployment-strategies и посмотреть как работают в связке K8s + Prometheus + Grafana. Как происходит экспорт метрик, увидеть на графиках разницу стратегий деплоя приложения. Задача со звездочкой - добавить в свое приложение сбор стандартных runtime метрик. Гайд для Golang. 🤔Шаг №4 - А какие метрики мне нужны? После того как мы овладели инструментом может возникнуть соблазн начать собирать все что только можно. Или наоборот ступор от того что все ещё непонятно - а что собирать то? И у сообщества есть ответ на этот вопрос: - R.E.D. Metrics: Rate, Errors, and Duration - U.S.E. Metrics: Utilization, Saturation, and Errors - The “Four Golden Signals” Metrics: Latency, Traffic, Errors, and Saturation Эти метрики станут надежным фундаментом для вашей системы мониторинга. ------ На этом у меня всё, пишите в комментариях как вы осваивали метрики, что для вас было наиболее сложным в понимании. Ну или расскажите какую нибудь историю с ними связанную😅

  • 5 мар.3 0942984

    🚀 Demystifying memory management in modern programming languages Хочу с вами поделиться циклом статей, который мне пригодился во времена переката из Ruby в Go. Мне требовалось заново вспоминать всякие low level детали из-за специфики проекта и высокой нагрузки. Цикл о том как происходит управление памятью в языках программирования. Первый пост разбирает основы и дает ответы на общие вопросы - RAM, Stack, Heap, Malloc / Realloc. Дальше автор начинает разбирать популярные рантаймы (JVM, V8) и ЯП (Golang, Rust). Я такое люблю - когда коротко и понятным языком рассказывают базу. https://deepu.tech/memory-management-in-programming/

  • 2 мар.3 3992156

    Road to Highload Сегодня пост посвящен материалам команды Яндекс 360 о том как развивались их системы со временем и какие челленджи были на пути к желаемому всеми инженерами Highload. Из прошлых постов вы наверняка заметили, что мне обычно интересно не только читать про классные алгоритмы и модные штучки, но и искать ответы на вопросы "Зачем? Почему именно так?" Ребята декларируют намерение поделиться собственным опытом и дать те самые ответы, а не только "навалить базы". Поэтому я решил посмотреть, что же там внутри. В проекте 5 выпусков. Покрывают фундамент классического серверного приложения, а именно: - Сбор требований и его влияние на архитектуру системы, ее надежность и масштабируемость. - Проектирование API. Почему это важно, и чем чреваты ошибки. Мне этот выпуск отдельно запал в сердечко, потому что в нем было и про breaking changes и обратную совместимость, вещи с которыми я намучался😁 - Визуализация верхнеуровневой архитектуры как инструмент коммуникации и способ storytelling'a о системе. - Как справляться с ростом объема данных. Индексы, согласованность. Разбор трейдоффов. - Интеграции. Как подключать к своей системе внешние источники данных, челленжи и разбор популярных проблем. Я отсмотрел проект целиком и могу сказать - материал достойный. Все о чем ребята рассказали это не что-то на эльфийском, а то что имеет место быть в больших системах. В общем - рекомендую к просмотру. Для начинающих прям 100%. Расскажите в комментариях ваши впечатления от просмотра, а также делитесь своими любимыми материалами😊

  • 27 февр.3 5431875

    Security 101 for SaaS startups или "Что я бы хотел услышать от моего первого руководителя о безопасности" Завершаю неделю постов по безопасности еще одной великолепной заметкой на Github. Она о том как выстроить культуру работы с безопасностью в стартапе. В прошлых постах мы обсуждали в основном технические детали публикации нашего приложения наружу. Но на этом работа не заканчивается. Если мы всерьез настроены делать стартап и привлекать клиентов безопасность становится одним из важных фокусов работы. Законы и требования нынче суровы. А нанимать выделенного спеца по безопасности может оказаться неподъемной задачей. Но для начала это и не нужно, можно справиться самоcтоятельно если знать "правила гигиены". Начинается заметка с основ - работа с паролями и доступами, постепенно накручивая варианты развития событий с ростом компании. Заканчивается разбором различных рисков и тем как ими управлять. Гайд полезен в основном как mindmap / роадмап. Отсутствуют практические советы о том как конкретно что-то настраивать. Но подсвечиваются все зоны, которые обязаны быть во внимании CTO. Если вы сейчас кодите (возможно, на вайбе) свой стартап обязательно сохраните гайд. Кто знает, может настанет момент, когда практики и советы из него помогут вам не облажаться перед клиентами и законом 😊

  • 26 февр.1 7791219

    moz://a SSL Configuration Generator Вижу по статистике и реакциям - что последний пост вам зашел, поэтому решил эту неделю посвятить лайфхакам и прикладным инструментам по безопасности. Ранее я совсем на эту тему не писал в канале, сплошной Software Engineering & Computer Science 🙂. Хотя мне есть чем поделиться, так как приходилось уделять время этому аспекту. Допустим, сервер мы купили, настроили как положено. Что делать дальше? Правильно - задеплоить туда приложение. Вариантов масса. Справимся. Остается завершающий этап - публикация в интернет. И тут начинается интересное. По современным гайдлайнам и политикам безопасности любой ресурс в интернете должен работать по связке HTTPS + TLS. На этом шаге легко словить ступор и вообще забросить затею публикацию, или же забить и опубликовать все как есть (не надо). Можно конечно пойти советоваться с LLM, но это на свой страх и риск и наличие времени на перепроверку. Лично мне с задачей настройки безопасных соединений в разных видах ПО помогал портал от Мозиллы https://ssl-config.mozilla.org. Скриншот для ознакомления прилагается. Как сейчас помню настройку Nginx для магистерской диссертации. Расскажите в комментариях, как вы настраивали HTTPS для своего первого сайта?😊

  • 25 февр.3 01240117

    How To Secure A Linux Server Сейчас мы живем в удивительное время. С одной стороны все больше слоев абстракции над нашими компьютерами. Если раньше ОС считалась абстракцией над железом то сейчас мы вовсю работаем с виртуализацией всех видов и декларируем свои намерения в YAML не зная вообще конфигурации сервера. С другой стороны в последнее время как будто бы нам все чаще нужны личные виртуалки у хостинг-провайдера или даже собственный сервер дома. Кому то хочется приватности, кому-то контроля. А ещё есть те кто стремиться глубже погружаться в то как устроены вещи😊 Но здесь мы встаем на путь работы с голой ОС и отвечаем не только за развертывание приложения, но и общую безопасность. Когда я был джуном я вовсю работал с разного рода серверами, писал скрипты и даже отвечал за инфру небольших продуктов (вся инфра умещалась на одном сервере😊). Как следствие - чтобы справляться с вызовами на работе приходилось активно самообразовываться в теме безопасности. И тут мне здорово помогал (и помогает до сих пор) GitHub. Поначалу бездумно копируя, что уж греха таить, но со временем все больше понимая и вникая в суть советов я овладел навыком настраивать относительно защищенный сервер, за который не страшно. В общем, хочу с вами поделиться - How-To-Secure-A-Linux-Server Гайд лежит в моих закладках уже лет 6 точно, и что приятно - он эволюционирует и пользуется популярностью в сообществе. Самообразовывайтесь, пусть на ваших виртуалках никто не майнит бетховены и не рассылает спам😁

  • 20 февр.1 6291317

    Concurrency, Synchronization and Consistency. Иерархия накладных расходов. Спустя время глядя на цикл постов понял что в нем не хватило отдельного саммари c выводами о том как добавление синхронизации и согласованности влияет на производительность. Концептуальным проблемам мы посвятили достаточно времени, а перформансу можно было и побольше. И в этот момент мне совершенно случайно попалась статья, в которой автор буквально делает тоже самое, что и я в цикле постов - препарирует шаг за шагом механизмы синхронизации и демонстрирует бенчмарки. Она и подтолкнула меня к написанию бонус-поста. Задача - безопасно, согласованно и максимально быстро работать из нескольких потоков c переменной uint64, как со счетчиком. Бенчмарки собрать с 4 разных процессоров. Bench №1 - Блокирующая синхронизация / атомики. Самая наивная из возможных реализаций - использовать Mutex. Бенчмарки говорят - стоимость одной операции += для программы из 2х потоков - 125 наносекунд. И чем больше потоков тем дороже операция. Подобное поведение мы уже рассматривали в посте про нелинейную масштабируемость мьютексов. Можно ли сделать лучше? Да, например избавиться от мьютекса и взять: - атомарный uint64 и явно использовать Compare and Swap. - атомарный uint64 и довериться компилятору. Получилось неплохо, из интересного - CAS оказался на том же уровне что и мьютекс. Bench №2 - Бутылочное горлышко системных вызовов Автор реализует Ticket lock используя atomic + sched_yield(2) syscall. С помощью аналогичной связки я писал свой мьютекс на Go. Получается еще хуже чем в первом бенче, оно и понятно почему - больше взаимодействия с ОС. В настоящем мьютексе сделано поинтереснее, рассказывал об этом здесь и в статье про самописный mutex. Bench №3 - Неявное переключение контекста Автор идет дальше и предлагает 2 варианта как бы еще подступиться: - condvar которая бы позволила засыпать и пробуждать все ожидающие потоки - честная блокировка с очередью потоков. Почему называется честной - потому что ресурс передается строго в порядке в котором на него претендовали потоки. Первый вариант демонстрирует проблему thundering herd, так как мы пробуждем все потоки, а захватит ресурс только один, а остальные сожгут CPU и снова уснут. Можно былои не будить вовсе. Второй справился лучше. Ведь мы решили проблему thundering herd. Но всё равно никуда не годится, так как у этой реализации другая проблема - lock convoy. Bench №4 - 0 переключений контекста (без учета прерываний ОС) Что если sched_yield(2) заменить на ; и как следствие не отпускать ядро до момента пока у потока его не заберет ОС? Катастрофа и переход от наносекунд к микросекундам. Что мы видим? С каждым бенчем все хуже и хуже. Ощущение, что лучше чем стандартный атомик сделать невозможно. Но тут автор явно говорит - хватить демонстрировать проблемы, давайте попробуем сделать что-то реально классное. И сделал. Bench №5 - Шардируемый счетчик Если наша цель выжать максимум из рантайма нам нужно явно избегать конкуренции между ядрами за какие либо ресурсы. И чтобы этого добиться нужно явно код программы адаптировать к нашему железу. Автор продемонстрировал реализацию счетчика которая побеждает все предыдущие бенчмарки. ----- Если подытожить - на перформанс корректного многопоточного приложения посягают: - мьютексы со своей нелинейной масштабируемостью по количеству ядер; - атомики и ассемблер. CAS и FAA инструкции; - системные вызовы к ОС; - явные и неявные переключения контекста. - потребность иметь в программе строгий порядок и честность (lock convoy problem). - наличие логики создающей ситуацию когда потоки циклически пытаются захватить ресурс, но чаще терпят неудачу (thundering herd problem). И всего этого можно избежать заплатив цену. Что автор и продемонстрировал. Предлагаю вам взглянуть на код в конце статьи и ответить в комментариях - затащили ли бы вы подобное в production?

  • 27 янв.2 1312659

    The Missing README: A Guide for the New Software Engineer В этом году я решил сделать над собой волевое усилие и читать чуть чаще чем в прошлом. И первой книгой в 2026м году стала The Missing README. Она произвела на меня впечатление, и мне хочется поделиться им с вами. В чем посыл книги? The Missing README позиционирует себя как книга о том что же такое Software Engineering и как же выглядит тот самый Software Engineer. Считаю, что посыл у книги благородный, так как высшее образование сфокусировано на фундаментальных дисциплинах и не на каждой специальности есть возможность адаптировать программу под запросы стремительно развивающихся технологий. Книги и независимые авторы это способ кое-как угнаться😊 Из чего состоит работа SWE? Каждая глава книги посвящена одному аспекту, перечислю: - Работа с кодом. - Работоспособный код. - Управление зависимостями. - Тестирование. - Ревью кода. - Доставка (Деплой) ПО в общем и кода в частности. - Дежурства. В конце книги авторы уделяет время в том числе и архитектуре: - Как устроен процесс проектирования. Как оформляется документация. Предлагается простой шаблон архитектурного документа. - Подсвечивается основная проблема в разработке ПО - неопределенность и как с ней бороться. Как работать эволюционно с API и СУБД. Как видите список довольно объемный. Мне понравилось, что авторы объясняют вещи простым языком, в каждой главе есть разделы "Best Practices" и "Bad Practices". Для начинающего разработчика такие вещи помогут сориентироваться во всем многообразии вариантов. Особенно неожиданно и приятно было увидеть отдельную главу про дежурства. Важность soft skills для инженера Я был очень рад увидеть в книге отдельные главы о параграфы о том зачем расти инженеру в таких областях: - Коммуникация. - Лидерские качества. - Проактивность. Надежность. Доверие. - Умение учиться. - Умение задавать вопросы. Понятное дело, что сейчас уже об этом из каждого утюга вещают, но авторам от меня лайк за то что не сфокусировались только на хардах в книге. Взаимодействие с менеджерами. Планирование. Построение карьеры На десерт авторы оставляют главы о росте. Рассказывают про 1-1, как на них приходить. Как задавать тон беседе, что подсвечивать. Упоминают Situation-Behavior-Impact фреймворк для обратной связи. Помимо этого обсуждаются вопросы смены работы и распределения сил. Кому и зачем я советую прочитать книгу The Missing README - настоящее золото для инженеров только-только закончивших универ или курсы. Также она пригодится переходящим из небольших компаний или фриланса в компании с сотнями или тысячами инженеров. Благодаря ей вы действительно поймете, что из себя представляет промышленная разработка ПО, получите в свое распоряжение дорожную карту для развития на ближайшие несколько лет. Если вы уже опытный - будет полезно полистать (как это сделал я) ведь повторение - мать учения. Эта книга однозначно попадает в мой топ для инженеров наряду с: - 📖 Программирование Cloud Native. Микросервисы, Docker и Kubernetes - 📖 Web Scalability for Startup Engineers

  • 17 янв.1 8972728

    Concurrency, Synchronization and Consistency. Пост № 24. Подводим итоги. Что будет дальше? Пришло время подводить итоги, так как мы рассмотрели основные вызовы и челленджи: - Начали от самых основ связанных с железом и тем как устроена ЭВМ. - Углубились в детали работы процессора, рассмотрели как он эволюционировал со временем, какие трюки и идеи реализовывали инженеры для ускорения. - Рассмотрели цену каждой такой идеи, ее влияние на программиста и код. - Рассмотрели инструменты и примитивы позволяющие программистам писать корректные программы и обходить особенности разных моделей памяти. - Ну и напоследок рассмотрели концептуальные проблемы порождаемые многозадачным программированием. Могу сказать точно - написание цикла постов меня здорово прокачало. Я увидел на практике, что многие вещи которые упоминаются в кабанчике Клеппмана или распределенных системах Таненбаума присущи не только когда у тебя 2 отдельных ЭВМ, но и когда у тебя 2 или более ядер процессора в рамках одной машины. О чем буду писать дальше? С точки зрения хардов мне теперь интересно погрузиться в неблокирующую синхронизацию. Для меня пока это по большей части модное слово которым описывают что-то очень сложное и клевое. Хочется разобраться без прикрас, как обстоят дела на самом деле (вангую что там будет много про атомики). А дальше на этом багаже можно: - Вернуться к Distributed Systems, "подняться повыше по уровню абстракции"🙂 - На примере какой нибудь OLTP СУБД показать за счет чего работает магия WAL / MVCC / ACID. Если у вас есть идеи что еще можно рассмотреть, не стесняйтесь, пишите в ЛС или комментарии. ——— Спасибо вам, что читали. Буду рад если оставите комментарий с обратной связью по материалам. Мб чего-то не хватило или недостаточно подробно разобрал. Ну и по традиции - материалы пригодившиеся во время написания постов: Hardware 🔥Symmetric Multi-Processing. Linux Kernel Teaching - лекция по ядру Linux объясняющая SMP и то как он реализован в ядре. 🔥Explain the Von Neumann Architecture of A Computer - очень простым языком про архитектуру Фон-Неймана. Cache Coherency 🔥Myths Programmers Believe about CPU Caches - еще раз о том почему важно знать как устроен процессор. 🔥 A Primer on Cache Coherence Protocols - подробный гайд про протоколы когерентности. Mutexes / Spinlocks / Semaphores / RWMutex 🔥Building a Tiny Mutex - название говорит само за себя. 🔥Basics of Futexes - про те самые "быстрые" мьютексы на уровне ядра Linux поверх которых пишутся мьютексы в языках программирования. 🔥Choosing RWMutex + Linear scalable read-write lock - два гайда дающих полную картину по плюсам и минусам RWMutex. Memory Models 🔥Memory Model and Synchronization Primitive Part 1: Memory Barrier + Part 2: Memory Model 🔥Memory Models by Russ Cox (Go tech lead at Google) False Sharing 🔥[Golang] Memory-wall problem - статья про канонический пример демонстрирующий false sharing (обход матрицы) 📖 Оглавление

  • 31 дек.1 931425

    Провожаем 2025й, встречаем 2026й 30е числа декабря это время когда многие подводят итоги, ставят цели и формируют планы на будущее. Признаюсь честно - далек от этого. Я редко ставлю себе детализированные планы, скорее ставлю себе некоторые направления в которых двигаюсь. Многие вещи и идеи могут появиться по ходу и оказаться не менее интересными и ценными чем то что изначально запланировал. Мой 2025й был насыщенным на разные события. Даже слишком. А ещё оказался наверное самым сложным за всю мою "взрослую жизнь". Сижу, пишу пост и понимаю - отдал все свои силы без остатка. Несмотря на это подвести итоги нужно. Усталость пройдет, а вот воспоминания и события могут стереться из памяти со временем. Мне этого не хочется🙂 Да и я вас в этом году не очень то и баловал постами про себя, очень много хардовых хардов, и почти ничего личного. Поэтому пусть будет. ——— Q1 2025 🎉 Отметил 30летие в кругу близких людей. Родители провели тайную операцию и приехали втихую ко мне в Питер. 📺 Был ведущим книжного клуба. Вместе с ребятами провели 10 встреч, прочитали книгу Fundamentals of Data Engineering. ✍️Закончил первый по настоящему долгий цикл постов про Concurrency (писал на протяжении 6 месяцев). Очень глубоко прокачался сам и старался прокачивать вас. 🎒 В первый раз в жизни пошел учиться на IT курс. Получил сертификат. В процессе писал заметки в канале. 🎁 В первый раз в жизни по настоящему выиграл в лотерею. ФК Спартак Москва подарил мне PS 5 PRO 🎮 Q2 2025 🏠 Достиг цели к которой долго шел - купил большую квартиру в СПБ. Залез в долги, но к концу года расплатился😁 📺 Сходил на подкаст к Саше Поломодову. До этого побывал в гостях на подкасте у Кирилла Мокевнина ✈️ Путешествия: побывал в Екатеринбурге. Q3 2025 🎤Выступил на ИТ фестивале Сезон Кода в СПБ и на Yandex Scale c докладом про технические вызовы преодоленные за годы работы над Statist. ✍️Начал новый цикл постов по Concurrency посвященный согласованности и синхронизации. ✈️Путешествие в Великий Новгород. Памятник тысячелетию Руси оставил сильное впечатление. ✈️Путешествие в Мурманск. Одно из самых запоминающихся путеществий в жизни. Северное сияние, путешествие по островам на вертолете. Q4 2025 💪 Провел своей команде второе Performance Review как руководитель. Поучаствовал в реорганизации процессов и орг. структуры нашего отдела. В формировании целей и дальнейшей стратегии. ✈️Путешествия: Ереван. Армения оставила приятные впечатления, рассчитываю посетить еще как минимум один раз🙂 🎒Выступил в родной школе (п.г.т. Красная Гора Брянской области) с докладом о программировании и карьере разработчика. ✍️ Написал 2 статьи на Хабре. ——— Отдельно хочется отметить проект на работе: 📈 За год мы выросли примерно в 5 раз по нагрузке и объемам и это требовало от меня и команды сопоставимого роста по навыкам и усилиям. Много чего оптимизировали и ускорили, чтобы оставаться такими же эффективными и для клиентов все работало также классно как и в 2024м. 👨‍💼Я примерял на себя новые зоны ответственности. Техническое лидерство в продукте. Коммуникация с основными потребителями. Планирование миграций, Capacity Management. 🤼‍♂️Несколько членов моей команды получили повышения. Считаю это хорошим знаком и показателем, что проект важный и ценный, и в нем есть где себя проявить. ——— Чего хочу пожелать себе в 2026м: - Постараться находить больше времени и сил на посты в канале. - Поработать над подачей материала, чтобы зарождалась дискуссия. Мне этого очень не хватает. Пока не знаю как этого достичь без неискреннего кликбейта. - Чаще говорить слово нет. Беречь свое время и силы. Проанализировать куда уходил ресурс в 2025м году, и не допустить повторения в 2026м. - Вернуться в менторство. Пауза затянулась и мне это не нравится. ——— Фух, хорош😁 Дорогие подписчики, я поздравляю Вас с наступающим Новым годом и Рождеством. Желаю достижения всех намеченных целей, при этом с удовольствием и наслаждением от процесса. Вкусно кушайте, набирайтесь сил в кругу близких людей, чтобы в новом году всё сложилось волшебно!