Акула (в) IT
522 subscribers
4 photos
69 links
Канал о прекрасном в мире IT. Вайтпейперы по распределённым системам, БД и всему что с ними связанно. 🦈

По вопросам/советам/предложениям: @aquatir
Download Telegram
Сегодня команда разработки SpaceX будет на реддите рассказывать о том, как они работают. Все ещё можно написать свой вопрос. Должно быть очень интересно! 🦈
🔥1
Когда вырасту, обязательно стану секурити ресерчером! Крутейший и подробнейший лонгрид почти по всем топ 10 уязвимостям OWASP в веб сервисах Apple

https://samcurry.net/hacking-apple/
🔥1
Как будто по заказу к предыдущему посту! Интерактивные туториалы в стиле html академии по самым популярным уязвимостям.
🔥1
Forwarded from ITGram
Kontra OWASP Top 10 is a collection of free interactive tutorials about most popular vulnerabilities and some recent security incidents. Beautiful, clickable, illustrative.
🔥1
Сделай это за меня! (1/2)

Большую часть времени руководить чем-то или за что-то отвечать довольно весело. Можно влиять на процессы вокруг, видеть
явный эффект от своей работы, помогать людям развиваться и достигать своих целей. Но у меня почему-то постоянно горит от этой деятельности, так что зумерам и не снилось! Полотно ниже - рефлексия на тему "что не так с миддл-менеджментом aka лидством в IT".

Во-первых, про миддл менеджмент. Будем рассматривать лида первого уровня, вся команда которого состоит из individual contributor'ов - программистов / тестировщиков / аналитиков и т.д. Возможно у больших дядь с лидами в подчинении боль уже совершенно другая, тут уж я не в курсе.

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

Навскидку, поле деятельности лида состоит минимум из 5 вещей:

1. Управление процессами внутри команды. Деятельность, направленная на то, чтобы вверенная или набранная команда работала эффективнее и более прогнозируемо. Вообще не имеет ничего общего с технической работой условного синьора. Абсолютно другой набор навыков, практик и подходов.
2. Внутренние коммуникации. Здесь имеется ввиду коммуникация с соседями - аналитиками, тестировщиками, фронтендерами для бекенда и наоборот. В общем, с людьми которые уже не команда, но еще и не очень далеко, чтобы общаться по почте и на Вы.
3. Непосредственный вклад в основную деятельность команды. Для разработчика - писать конфиги и код, для тестировщика - тестировать. То чем когда-то занимался лид, который раньше был миддлом или сеньором. То чем он бы хотел заниматься побольше, но ситуацию часто бывает против.
4. Опосредованный вклад в прогресс команды и компании. Сюда относится крайне полезная, но НЕ основная деятельность, которая помогает эту самую основную деятельность выполнять лучше. Это может быть и написание документации, и разбор инцидентов с продакшона, и написание библиотек, и выкорчевыванием требований из головы заказчиков.
5. Внешние взаимодействия. Например, общение с провайдерами какого-то там вашего сервиса SMSок или с инженерами компании-партнера. Сюда же можно отнести то что вроде как пункт номер 2 - общение с людьми из одной копании, если оно происходит долго через почту, без сроков и гарантий, и в особенности на Вы!

Это мы все еще только идем к проблеме, осталось чуть-чуть! Можно ли заниматься всеми ими? Да не вопрос! Эффективно? Вот тут уже начинаются проблемы. Из этих видов деятельности что-то похожее между собой имеют только 3, 4, так как это по большей части "техническая экспертиза" и 2, 5, так как это про общение с человеками, работу с ожиданиями и договоренности. Получается чтобы эффективно делать все, нужно разбираться минимум в 3 областях знаний - что такое процессы и как ими управлять (1), обладать хардскилами (3-4) и уметь говорить с людьми и получать от них то что хочется (2, 5).

Проблема здесь, как и практически во всем, что связано с людьми, заключается в неоправданных ожиданиях. Приходит, значит, к нашему юному лиду его начальник и говорит: "сделай это за меня!". Не прямо такими словами, конечно. Формулировки варьируются от "пожалуйста, займись <... вот этим ...>" до чейта еще ничего не сделано по задаче <... в трекере нет, слышу в первый раз ...>". С одной стороны угроза жизни важная задача, с другой стороны - несостоятельность и в половине видов деятельности, которыми нужно заниматься. Хорошо быть разработчиком, страдать с мнимым синдромом самозванца, когда от тебя ничего кроме пары коммитов в день и не требуют. Жизнь лида же - это как жизнь волка из советской игры, где из 4 разных труб падают яйца, при чем все яйца совершенно разного размера и формы (разные виды деятельности), и у вас нет времени даже подумать, как бы сделать так, чтобы яйца не падали, так как все время их нужно ловить!
Сделай это за меня! (2/2)

До кучи, кому мало своей некомпетентности, добавим еще 1 бич юных лидов - полный вагон обязанностей в отсутствии полномочий. Вы, конечно, "руководите" коллективом, но можете ли вы повлиять на запрлаты этих людей? Или уволить их всех к чертям? Можно конечно как Жанна д'Арк быть прирожденными лидером и вести всех за собой на чистой харизме и вдохновляющих речах, но когда у вас нет права подписывать документы на отпуск, вы уж конечно извините, но с руководством это имеет мало общего. Доброе слово - это хорошо, но с реальными проблемами иногда хотелось бы справиться пистолетом.

Вот и получается, что лиду нужно бежать со всех ног, чтобы только остаться на месте. Это мы еще не дошли до самого интересного. Смотрите, раз полномочий особых нет, то какая деятельность страдает в первую очередь? Правильно, та, где полномочия больше всего нужны! А это наша цифра 1 - управление процессами внутри команды. Раз мы ей больше не занимаемся, время на эту деятельность равномерно распределяется по другим областям. Насколько этот пункт важнее остальных четырех? Давайте попробуем представить идеальный мир и порассуждать дальше.

Возьмем 5 видов деятельности из поста выше и расставим их в кучки просто ради эксперимента:

Берем 2, 3, 4. Немного общения с коллегами + оба технических навыка. Получаем... синьор разработчика.
Берем 2 и 5. Вся работа - сплошная болтовня. Получаем менеджера!
2, 4, 5 - говорит со всеми и всем помогает, но код сам не пишет... Это же продуктовнер!

Оказывается четырьмя из пяти видами деятельности может заниматься помимо лида еще несколько человек. Получается что главная и основная работа лида, которую не может делать никто кроме этого самого лида - это управление процессом внутри команды! Та самая деятельность, на которую лид забил, так как у него нет возможности ей заниматься из-за отсутствия полномочий! Значит, нужно всего-то дать ему пистолет и все станет хорошо! Но только пока пистолета не было, время на эту задачу уже распределилось по другим задачам. Занавес.
🔥1
Fault-tolerant виртуалки VMWare (1/2)

#shark_whitepaper

Идея создать хештег про вайтпейперы у меня была давно, т.к. их количество в reading list уже перевалило штук за 30, и каждую неделю увеличивается еще на 2-3. Попробую раз в неделю рассказывать вам о какой-нибудь новой или старой (или очень старой...) работе, которая как максимум может быть полезна в современном мире. Или как минимум почешет ту самую мышцу, из-за которой мы зачем-то продолжаем постоянно читать про про новые языки, фреймворки и все такое прочее.

Итак, сегодняшний вайтпейпер - The Design of a Practical System for Practical System for Fault-Tolerant Virtual Machines Fault-Tolerant Virtual Machines https://pdos.csail.mit.edu/6.824/papers/vm-ft.pdf

О чем: как VMwar делают fault-tolerant репликацию ВМ.

В чем вообще беда: традиционно репликация ВМ делается через копирование состояния CPU, памяти и I/O девайсов. Если часто идут сигналы - нужно много копировать, а это большой сетевой канал. Вот было бы здорово, если бы можно было копировать, но при этом не съедать на это весь канал.

Оказывается, эту проблему можно решить, если рассматривать ВМ, как конечный автомат. На вход основной ВМ подаются сигналы, она изменяет свое состояние, а также записывает их в некий logging channel. Эти сигналы читаются второй ВМ, обрабатываются, и если результат работы детерминированный, то обе ВМ оказываются в идентичном состоянии. Такой подход в статье зовется Deterministic Replay. Помимо этого также необходимо задерживать ответный сигнал основной ВМ, пока дополнительная ВМ не увидит его в логе (Output Rule). При этом, так как выходной сигнал – это асинхронный I/O, в целом нет необходимости блокировать всю ВМ на время репликации, хотя при сильных задержках такая необходимость может и возникнуть.

Все еще остается проблема недетерминированных операций, таких как вычитывание времени дня, но такие кейсы можно выделить и решать в индивидуальном порядке. Ну и конечно, еще нужно подумать о том, как одна ВМ будет сменять другую. Поэтому нужно добавить хардбиты между основной и репликой, чтобы знать когда упало и научиться брать через любимый test-and-set значение свойства "я основная ВМ", чтобы можно было передать управления (fault tolerant должен предусматривать fault!).
🔥1
Fault-tolerant виртуалки VMWare (2/2)

Самое удивительно, как много проблем в мире решаются приблизительно похожим метод — записыванием событий в лог. Тут тебе и write-ahead-log в БД и репликация брокеров сообщений и event sourcing и что вообще только не придумаешь!

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

У нас неделю назад на работе внезапно упала на слое разработки (хоть здесь повезло!) мега-виртуалка, на которой жил и мастер кубера, и инстанс постгреса, и кафка, и что там только еще не жило, так как маленький стартапчик, делаем как умеем. Такое большое событие, конечно, заметили, и сразу была вызвана оперативная бригада админов, постановивших, что виртуалка, на которой все это добро жило, умерла и стартовать через рестарт отказывается. ВМ была оперативно поднята из бекапа, все сервисы снова развернуты, и какое-то время все было хорошо... пока не начали происходить аномальные события.

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

Через какое-то время пришла в голову идея зайти в логи постгреса, который нам радостно сообщил, что ядро у вас багованное, обновитесь. Ну и еще ошибки записи в лог файлы 🤔


2021-02-15 14:34:09.543 UTC [45268] ERROR: unexpected data beyond EOF in block 6 of relation base/16384/16642
2021-02-15 14:34:09.543 UTC [45268] HINT: This has been seen to occur with buggy kernels; consider updating your system.


Разумеется, мысли что дело в поломавшемся ядре не было ни о кого. С чего бы вдруг ядру работать-работать и сломаться, но что делать как-то тоже непонятно. Выяснять что там случилось на слое разработки никто не хотел, поэтому решили восстановить из более старой версии бекапа виртуалки (не получилось в первый раз - получится во второй!), после чего постгрес перестал говорить, что у вас багованное ядро, а просто потерял 70% данных, вместе с кафкой.

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

И сделали для себя важный вывод. Не нужно решать задачу "сделать бекапы". Нужно решать задачу "восстановления при катастрофах". Бекап, из которого никто хотя бы раз не восстанавливался, возможно попросту не работает.
🔥1
Real Time

Эволюция естественных языков — крайне занимательный процесс. Существует несколько подходов / теорий на тему того, как это происходит. Тут и фактор экономии усилий (зачем нужны лишние буквы?), фактор лени, да и просто устаревание старых терминов. Забавно что в IT этот процесс протекает исключительно быстро.

Я как уже рассказывал немного о той-самой работе Роя Филдинга, о понятии архитектура, которое она вводит, и о том что REST — это не другое название для HTTP API, а полноценный архитектурный стиль, являющийся базой для ни много ни мало стандартов HTTP 1.1 и 2.0. Наверное скоро настанет время рассказать более подробно. Тем не менее, меньше 20 лет понадобилось, чтобы изначальный смысл слова REST забылся, и теперь RESTом (или даже RESTful) зовется любое API, которое используется больше, чем единственный http метод POST и хоть как-то разумно именует url'ы, если урлы вообще есть. Это я еще не вспоминаю про гипермедиа, существование которого является совершенно необходимым условием, чтобы API мог называться REST / RESTful.

Где-то на одном уровне с RESTом по частоте неправильного использования находится и понятие real time. Слишком часто в литературе real time приравнивается к "почти мгновенно", хотя фактически этот термин имеет вообще мало отношения к скорости, а говорит скорее о гарантиях. Сегодня я расскажу что к чем и чем отличаются non real-time системы от soft / firm и hard real time.

Итак, приступим. Понятие real-time зародилось в жутко бородатые годы. Из банальной википедии следует, что самый старый цитируемый источник относится аж к 1965 году! В то время как вы понимаете, проблемы производительности IT систем очень сильно отличались от современных. POSIX тогда еще не было, домашних компьютеров в целом тоже, амазон и гугл обещали появиться через 30 лет и 33 года соответственно. Зато было много разных математиков, которые изучили разные прикольные штуки. Одной из таких штук является создание систем реального времени.

А что если бы мы могли делать системы, которые отвечают строго в рамках заданных временных границ на все запросы к ним, даже при наличии параллельных задач? Т.е. вы пихаете в систему какие-то данные, а она вам говорит "этот запрос я закончу не позже X, а этот не позже Y". Если прямо совсем цитировать википедию, система реального времени — это система, корректность которой зависит не только от логической корректности, но и от времени, когда операция была завершена. Соответственно real-time системы разделяются в зависимости от того, что будет, если не уложиться в заданные временные ограничения:

- Hard real-time системы. Не уложиться в дедлайн == отказ системы. Такие системы часто сочетают в себе механические элементы. Пример: принтер. Лазер должен светить строго в определенный момент. Не раньше и не позже.
- Firm real-time система. Пропустить дедлайн можно... но полезность результата в таком случае равняется нулю. Пример: роботы для высокочастотной торговли. Если решение не принято вовремя — его уже нет смысла принимать. Часто такие системы не включают в классификацию, так как есть еще и третий вид.
- Soft real-time системы. При пропуске дедлайна, наблюдается деградация полезности результата. Деградация при этом может быть довольно стремительная. Не получил вовремя GPS сигнал — скорее всего старый сигнал можно не ждать, так как его полностью заменит новый, но совсем небольшие опоздания в принципе допускаются.

Так вот, главная задача системы реально времени — это не высокая производительность, а постоянное время ответа. Загрузил 10 запросов, получил 10 ответов через 10 секунд. Загрузил 10000, получил 10000 через 10000 секунд. Поэтому для их реализации используются немного другие операционные системы (другая реализация шедулера задач) и немного другие библиотеки. И хоть супер-быстрый-реактивный сервис на вашем любимом языке и вправду летает, называть его системой реального времени, скорее всего не совсем корректно. А если корректно — для этого нужно показывать график с плоской чертой latency в любом процентиле, а не throughput.
🔥1
Maturity модели документации.

#shark_whitepaper

- Вайтпейрпер 1
- Вайтпейперт 2

Есть вбить в гугл "documentation maturnity model" возвращается какое-то немыслимое количество статей и вайтпейперов. Те две, которые я взял в качестве основы, лишь пример. Проблема документации в современных системах, на мой взгляд - это следующий этап развития глобального тренда микросервисной архитектуры, и об этом определенно стоит говорить.

Итак, в чем суть. Мы уже знаем, что микросервисы — это скорее всего будущее разработки программного обеспечения, потому что ни один другой способ разработки ПО не обеспечивает такую простоту скалирования команд, одновременно обеспечивая такой уровень доступность. Вы просто нанимаете еще одну 2-pizza team, и они начинают практически независимо от всех остальных команд приносить полезность. Как минимум так оно должно работать в теории. Но тут есть парочка больших жирные НО. На практике оказывается, что чтобы быть независимым, нужно понимать, что происходит вокруг. Тут на помощь как раз должна приходит документация, но часто ее качество оставляет желать лучшего. Сегодня я постараюсь рассмотреть понятие maturity model, на примере документации программного обеспечения.

Maturity model - это с одной стороны определитель вашего текущего уровня развитости некоторого аспекта разработка, а с другой стороны указатель на то, какие сложности есть на вашем уровне, и какой шаг нужно предпринять следующим, чтобы стать более взрослой организацией. Если речь идет о разработке ПО, их вообще довольно много. Начать можно с CMM, затем плавно перейти к SECMM CMMIВ, в общем, читать неперечитать. В случае с документацией все чуть-чуть проще, можно выделить 5 уровней развитости:

1. Неконтроллируемая / ручная документация. Основные признаки: лишь отдельные люди понимают важность и цели ведения документации. Документация редкая и неполная. Нет ни процесса ни требований к содержанию. Как правило, обновление документации - это индивидуальные усилия, которые происходят не в рамках установленных процессов, а по воле отдельно взятых личностей.
2. Полуавтоматическая / неконсистентная. Появляются стандарты ведения документации, но им следуют еще не все. Появляется возможность автоматического создания части документации (Например, openapi).
3. Полуавтоматическая / конкретная. Появляются правила, когда и в каком объеме нужно вести документацию. Стандарты к продукту документации закреплены, и все их придерживаются (продукт — это как выглядит документация, какие элементы блок-схем используются и т.д.). Появляется возможность связывать части документации между собой через гиперссылки.
4. Автоматическая / статическая. Стандарты к процессу создания документации закреплены, и все их придерживаются. Ключевое различие с предыдущем пунктом - процесс vs продукт. На 3 пункте было важно, чтобы созданная документация отвечала поставленным требованиям. На 4 уровне важность смещается в сторону процесса. Здесь необходимо, чтобы документация создавалась постоянно, при этом соответствовала правилам. Организации на таком уровне могут страдать от чрезмерной документации. Любое действие всегда описывается, но где описывается не всегда понятно, так как поиска по документации, возможно, еще нет.
5. Автоматическая / динамическая / персонализированная. Документация умеет подстраиваться под читателя. Можно выделить лишь те части, которые в настоящий момент интересны. Можно создавать свою версию документации и просматривать историчность изменений. Этот уровень недостижим без специальных инструментов для чтения и поддержки документации. Как правило, они разрабатываются внутри организации. Помимо персонализации, также должны существовать средства поиска по документации.

Что и как с этим делать? Шаг номер 1 — определить текущий уровень. Шаг номер 2 — работать над улучшениями. Здесь важно не прыгать выше головы и не решать проблемы на уровень выше. Если документация пишется хаотично и бессистемно (уровень 1) — сначала нужно систематизировать продукт документации (ур. 2), а лишь потом переходить к уровню 3 — вводить процессы по написанию этой документации
🔥1
Отзыв на Microservices Patterns.

Книги о том как правильно делать микросервисы у меня часто оставляют двоякое ощущение. Здесь тебе расписывают роскошные easy-to-use hides-complexity решения, но почему об этих решениях редко говорят на конференциях матерые инженеры... Не считая CEO компаний, которые делают IT продукты для микросервисов (как автор!) или консалтеров. С другой стороны, опыт поддержки решений в настоящем продакшене после каждой главы непристойно орет: "врёте, сударь!". Нельзя просто взять и решить проблему распределенных транзакций через Саги. Потому что, помимо проблемы технической (как это делать?), есть еще проблема поддержки. Как этот код потом менять? Как объяснить новому человеку принцип работы саги из 10 частей? Наконец, как решать проблемы, когда что-то пойдет не так? И не предлагайте мне тесты и меры предосторожности, если даже вся аутентификация в гугле может сломаться из-за бага, внесенного за пару месяцев до инцидента!

Будем считать, настроение задано. Мне редко не нравятся книги. Обычно я об этом молчу, но здесь молчать невозможно, так как паттерны микросервисов — книга, которая может вас похоронить под сложность системы, которую она предлагает создать! Давайте по существу.

Рассказ начинается с грустной истории девушки Mary — CTO компании по доставке еды Food to Go, день которой был испорчен очередным совещанием на тему, почему разработка опять продолбала все сроки. Проблема имеет глобальный характер, а значит и решать её нужно глобально — переписыванием всего на микросервисы!

В следующих главах речь идет о решении разных проблем в МС архитектуре. Везде есть ссылки на довольно удобный ресурс, где в стиле банды четырех кратко описываются те или иные паттерны. Каждая глава логически состоит из двух частей. В первой приводится теоретическое описание паттерна, его плюсы, а вот минусы почему-то иногда опускаются. Во второй идут примеры на фреймворке автора, который к тому же построен поверх Spring'а. Да, книга называется Microservices Patterns: with examples in Java не случайно. Так как фреймворк один из тех easy-to-use hides-complexity решений, вы вроде можете понять код, но это все равно что читать псевдокод, так как все спрятано под магический DSL. Как оно работает под коробкой остается загадкой. Тем более остается загадкой, как эти примеры кода можно будет использовать у себя.

Немного есть и на тему тестирования микросервисов. Здесь все стандартно, пирамида, моки, кусочек про consumer driven contract. К сожалению, нет ничего про chaos engineering, но зато есть очень много про то что end-to-end это slow и brittle и вообще не делайте их. С этой позицией я не согласен категорически! Но об этом я поворчу в следующий раз. Также есть обзор техник деплоя от "деплоим jar'ик" до "деплоим в кубер".

И наконец глава, которая практически оправдала эту книгу! Глава 13 - refactoring to microservices. Почти в конце книге находится фраза, которая могла бы поменять все мое отношение к этому произведению, если бы она была в начале. Фраза, которая даже не удостоилась фирменной рамочки, как максимально важная мысль!

> You should first try simpler solutions. If, and only if, you still have software delivery problems should you then migrate to the microservice architecture.

Тысячу раз, да! Во-первых, ни одно техническое или организационное решение не имеет смысла, вне контекста проблемы! Во-вторых, любое решение — это компромисс (trade-off). При чем компромисс не только между "здесь у нас такие-то технические свойства, а здесь сякие-то", но также между "время можно потратить на это или на то". Кто из вас с пустым беклогом, пусть первый бросит в нее камень! Между простым и быстрым решением, которое почти решит проблему и сложным и долгим, которое решит её полностью, часто правильным будет первое, а не второе.

А что касается книги, если у вас и так гора опыта и bullshit фильтр выкручен на максимум — смело читайте, не повредит. Листинги можно пропускать. Если вы только знакомитесь с миром микросервисов, начните лучше с Фаулера, а затем переходите к его гайду.
🔥1
The Calculus of Service Availability

#shark_whitepaper

Сегодняшняя красивая большая пдфка формально не является вайтпейпером, т.к. выпущена не университетом, особо ничего нового не изучает и написана не в две колонки. Тем не менее, я не могу пропустить публикации инженеров гугла (когда рано или поздно их нахожу...), т.к. во-первых, питаю слабость ко всем этим SRE штукам, а во-вторых, емкие, но при этом содержательные тексты — большая редкость.

Итак, в работе кратко рассказывает, чем вообще живут SRE, и начинается все с простой математики availability:

Availability = MTTF / (MTTF + MTTR)

Где:
Availability — доступность. Какой процент времени система может корректно делать свою работу (обрабатывать запросы, перекладывать сообщения, и т.д.)
MTTF (Mean time to failure) — среднее время до отказа. Обратная величина от частоты сбоев.
MTTR (Mean time to repair) — среднее время до исправления. Здесь имеется ввиду время, через которое система придет в свои изначальное корректное состояние. Т.е. недостаточно придумать, как починить, нужно еще и применить решение.

Главная фишка этой математики в том, что из нее можно делать довольно очевидные выводы. Как повысить доступность? Смотрим на уравнение, и видим, что путей всего два:

1. Увеличить числитель, т.е. увеличить среднее время между отказами (MTTF). Делать это можно при помощи более обширного тестирования, более аккуратного деплоя (В рамках rollout policy, если такая есть, к примеру) или уменьшением скоупа отказа: географическая изоляция отказов, шардирование, graceful degradation и т.д.
2. Уменьшить знаменатель, т.е. сократить время на обнаружение и устранение проблемы (MTTR). Как говориться, быстро поднятое упавшим не считается. Здесь помогает настройка мониторинга и алертинга, интеллектуальные системы восстановления и развертывания, а также, что не менее важно, обучение сотрудников и chaos engineering.

Вторая интересная мысль из статьи — доступность сервиса не может быть больше общей доступности всех зависимостей. Если ваша БД лежит 53 минуты в течение года (99.99%), то даже при вашей 100% доступности, 53 минуты в течение года вы тоже будете не работать. Отсюда следствие: доступность зависимостей должна быть больше, чем ваша. Иначе, математика не сходится.

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

Ну и самое главное. Как гугл решает свои проблемы — это бесспорно интересно, но может не иметь вообще никакого отношения к вашему продукту.
👍1🔥1
История CAP теоремы (1/6)

#shark_whitepaper

Буквально вчера меня триггернуло на фразу "CAP теорема — это миф" от интервьювера. В этом посте мы поговорим о том, как вообще эта теорема появилась на свет, что она значит, и немного затронем важность ограничений, при чтении любых работ по Computer Science. Тема очень обширная, поэтому весь рассказ растянется не только на несколько постов, но и на несколько дней.

Началось все в 2000 году, когда Eric Brewer (ныне — VP of infrastructure в гугле) выступил вот с этой презентацией на кейноуте симпозиума по принципам распределенных систем (PODC). Это большая крутая конференция про все распределенное, которая проходит ежегодно уже почти 40 лет. К моменту этого выступления, мир уже оперировал аббревиатурой BASE на равне с ACID, но вот фундаментальный трейд-офф между CConsistency, AAvailability и Ppartition tolerance был объявлен именно здесь (как минимум, так обычно считается в литературе).

В изначальной постановке трейд-офф звучит как "Consistency, Availability, Partition Tolerance. You can have at most two of these properties for any shared-data system". В этой же презентации приводятся примеры всех трех видов систем. В качестве CA систем приводятся Single-site databases и LDAP. Это важное замечание, так как через какое-то время, различные работы придут к выводу, что разделить CA и CP системы довольно сложно. Хотя бы потому что кратковременное отсутствие сети можно моделировать через отсутствие availability и наоборот (Такого мнения спустя 12 лет придерживается как сам автора, так и спустя 10 лет не только автор).

Вторая важная вещь, которая озвучивается в кейноуте — это DQ principle. Вводится он следующим образом:

Data/query * Queries/sec = constant = DQ

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

Data/query
— это сколько корректных данных возвращается из одного запроса,
queries/second
— это производительность ака throughput. Здесь надо оговориться, что речь идет про очень большие и распределенные системы, а сам кейноут должен нести практически смысл. В реальных системах часть данных может быть уже внутри системы, но еще не реплецирована на необходимое количество нод, т.е. существует часть данных, которые уже внутри системы, но еще недоступны. Именно поэтому понятие "количество корректных данных" (data/query) имеет значимый смысл.

Данный принцип утверждает, что в рамках работающей системы нельзя одновременно повысить и качество данных (data/query) и количество обрабатываемых запросов (queries/second). Как минимум без изменения программы / ос / сервера. Забавно, что этот трейдофф consistency/throughput/latency будет через десяток лет рассматриваться уже другими учеными, но об этом мы еще поговорим.

Но вернемся к CAP. В презентации утверждение про "возьми 2 из 3" формулируется как теорема, что фактически неверно. Теорема должна иметь доказательство, т.е. правильнее это было бы назвать другим словом, например принцип CAP или гипотеза CAP, как это делают многие последующие работы.
🔥2👍1
История CAP теоремы (2/6)

Когда же принцип CAP стал теоремой? Это произошло в 2002 году в вайтпейпере под авторством Seth Gilbert и Nancy Lynch. Я очень советую почитать сам вайтпейпер, т.к. доказательство элементарное в рамках тех ограничений, которые задаются для рассматриваемой системы. Если что, то же самое доказательство есть с картинками, тут уж точно все станет понятно (Нет, серьезно, универские доказательства из матана в десятки раз более замудренные, чем то что написано в работе по CAP)

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

- Рассматривается асинхронная модель взаимодействия. Асинхронная это значит 2 вещи. Во-первых, невозможно отличить отказ системы от "тормозов". Во-вторых, любое сообщение может доставляться и обрабатываться неопределенное, но не бесконечное время. В целом первое следует из второго.
- Consistency рассматривается, как атомарность или линеаризуемость. Это значит, что система для внешнего наблюдателя всегда выглядит так, словно она состоит из одного сервера. Более формально, в линеаризуемой системе всегда существует линейная упорядоченность (total order) всех операций относительно единственно-верных часов.
- Partition Toleranse вернее partition (разделение сети) рассматривается как бессрочное разделение.
- Availability. Здесь формулируется как "любая не вышедшая из строя нода должна возвращать корректный результат".

Сама формулировка теоремы следующая:

> It is impossible in the asynchronous network model to implement a read/write data object that guarantees the following properties:
- Availability
- Atomic consistency
in all fair executions (including those in which messages are lost)


Обратите внимание, что уже на уровне формулировки не учитывается возможность существования CA систем. Формулировка вообще ничего не говорит про "выбери 2 из 3". После этой теоремы, идет еще следствие из нее, в котором говорится, что условие недостижимо даже при отсутствии пропавших сообщений.

Приблизительно здесь заканчивается первая половина всей работы! Во второй рассматриваются менее строгие системы, а именно системы, оперирующие в partially synchronous модели. Это модель, в которой у каждой ноды есть свои часы (не синхронизированные между друг другом). Так вот, в такой системе все еще невозможность обеспечить одновременно availability и atomic consistency в общем случае, но это становится возможно если не потерять ни одного сообщения.

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

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

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

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

Получается, что главная проблема CAP теоремы в целом заключается в том, что модель и ограничения, в рамках которых она рассматривается, практически неприменима для реального мира. Тем не менее эта работа все еще корректна и верна! Неприменима вовсе не то же самое, что неверна. С другой стороны, раз уж она не применима практически всегда, почему вендоры хранилищ данных так любят говорить CP у них или AP? Вот это уже вопрос, на который у меня нет ответа.

На этом пока что все. В следующих постах мы рассмотрим, что нового появилось рядом с CAP за следующие ~ 15 лет после её выхода.
🔥1
История CAP теоремы (3/6)

Продолжаем наш рассказ. Следующая важная веха вокруг CAP теоремы случилось аж спустя 12 лет с момента первой презентации. Автором этого огромного поста снова стал Eric Brewer. Забавно, что факт доказательства теоремы им практически полностью игнорируется. Но с другой стороны, оно и понятно, потому что у CAP есть 2 жизни. Первая — это формальные доказательства, задача которых задать верхнюю и нижнюю границу возможного. А второе — это реальные системы, в которых существуют реальные трейдоффы. Им и посвящен этот пост.

Статья начиная с разъяснений, почему нельзя просто так брать определение из теоремы и кричать, что тут у вас AP, а тут CP — настоящие системы слишком сложны.

Во-первых, partition tolerance предполагает, что система знает о разделении. Это, к сожалению, не всегда так. Сеть может разрываться в неожиданных местах, так что для одной части системы некоторая нода недоступна, а для другой части доступна. Более того, независимые части системы в целом могут продолжать работу даже при разделении сети. Возьмем, например, сервис такси в Северной Америке и Европе. Всегда ли необходимо наличие связи между ними? Скорее всего нет, так как никто не будет вызывать такси из Вашингтона в Амстердам. При этом эти 2 части могут продолжать обрабатывать запросы, даже когда сети между ними нет.

Во-вторых, разделение сети — далеко не единственная возможная проблема. Система вполне может потерять и доступность, и консистентность после неудачного релиза. А для некоторых систем недоступностью будет слишком высокие задержки, хотя запросы все еще будут обрабатываться (например, биржевые роботы). Строго говоря, консистентность и доступность — это не бинарные понятия. Является ли доступной система, которая успешно возвращает 99% данных, а 1% произвольно дропает? С точки зрения формальных определений — нет. С точки зрения стриминг-портала, вполне себе рабочий вариант.

В-третих, чему посвящена основная часть статьи, отказ от консистентности в пользу доступности часто недостижим. Лучше что можно сделать — это отложить момент наступления консистентности. Никто не любит, когда их данные теряются. Как быть?

Для начала, было бы хорошо обнаруживать недоступность между компонентами. Здесь человечество изобрело уже множество подходов от синхронных health чеков с таймаутами (напомню, что формально CAP рассматривается в асинхронной системе. Синхронных операций в такой системе нет) до алгоритмов консенсуса. Следующие шаг — перейти в явный режим работы при разделении сети, а при восстановлении, собственно, провести компенсации.

Звучит хорошо, на практике все не так просто. Чтобы корректно восстановить консистентность, после возобновления сетевой доступности, нужно знать как минимум все инварианты системы. Инварианты — это условия, которые должна оставаться верными в любой ситуации. Баланс не может быть меньше нуля, у пользователя может быть ровно 1 аккаунт, по одному закажу должен быть ровно один платеж и прочие-прочие-прочие ситуации. Знать и учитывать все это сложно. Еще сложнее, уметь корректно разрешать конфликтные ситуации. Пусть за время конфликта один и тот же заказ сначала отменился, а чуть попозже взял и оплатился. Что делать? Поди его там разбери, что хотел сделать пользовать!
🔥1
История CAP теоремы (4/6)

Поэтому предлагается решать такие конфликты аж четырьмя способами:

1. После обнаружения разделения сети, не позволять делать часть операций. Дубовый и прямолинейный способ, единственное что, пользователи страдают, а также определить, какие операции опасные, а какие нет для конфликтов восстановления — задача непростая.

2. Собирать отладочную информацию. Например, собирать version vectors, а после восстановления, объединять их в консистентное состояние. В теории хорошо, на практике зависит от того, как долго длится разъединение, и какие операции происходят.

3. Использовать коммутативные и иммутабельные операции, а еще лучше даже conflict-free replicated data types. Проблема в том что не все можно реализовать на CRDT. Особенно тяжело для них выполнять инварианты. Сложить несколько плюсов и минусов баланса — просто. Сложить две разные корзины товаров, как множества тоже просто. Сделать так, чтобы ни одна операция не вывела баланс за нуль — сложно.

4. Вести аудит операций, а затем запускать компенсирующую логику. Подход похож на version vectors, но может быть реализован самыми неожиданными способами. Например, банк может взимать плату за овердрафт, в качестве компенсации за то что баланс уменьшился ниже нуля, если сможет доказать, что это пользовать сам одновременно снял деньги в банкомате и перевел на другой счет.

Как обычно, в реальном мире простых решений нет. Формальные доказательства не спасают, а только заставляются задумываться. Но история CAP теоремы все еще не закончена...
🔥2
История CAP теоремы (5/6)

Следующая важная работа для истории CAP это "утверждение" PACELC (произносится pass-elk) под авторством Daniel J. Abadi. Иногда ее называют "теорема PACELC", что совершенно неверно, т.к. сама работа не содержит формальных доказательств, это скорее рассуждения и логические выводы. Исторически она вышла на пару месяцев раньше, чем 12-лет-спустя, но статьи друг от друга не зависят и представляют разные элементы одних и тех же трейдоффов.

Формулировка следующая:

PACELC: if there is a partition (P), how does the system trade off availability and consistency (A and C); else (E), when the system is running normally in the absence of partitions, how does the system trade off latency (L) and consistency (C)?

Если в 12-лет-спустя говорится, что от консистентности нельзя в принципе оказаться, то тут автор предлагает задуматься, какие трейдоффы нужно делать еще до того, как разделение сети произойдет. А трейдоффы здесь между консистеностью и задержками (latency). Забавно что в самой-самой первой презентации от Eric Brewer (о ней см. пост #1) было аналогичное утверждение в виде DQ принципа. Нельзя одновременно улучшить и консистентность и производительность vs нельзя одновременно улучшить консистеность и latency.

Рассуждения строятся следующим образом. Если система highly available, то потеря ноды с данными не должна автоматически приводить к потере данных. Значит, данные нужно реплицировать. Рассмотрим все возможные методы репликации и посмотрим, какие в них вылезают трейдоффы.

Вариант 1: Данные реплицируются во все n реплик одновременно. Если вся репликация синхронная — любой отказ это недоступность, а мы строим "highly available". Если отказ одной реплики не проблема, значит автоматически должен существовать алгоритм репликации, который включает восстановление как минимум корректного порядка сообщений. Значит есть какая-то лишняя работа == есть задержки. Нужно выбирать делать более консистентный и медленный алгоритм или наоборот.

Вариант 2: Данные направляются в определенные ноды, а лишь затем реплицируются. Например write master - read slave репликация. По этому пути есть 2 дороги:
- 2.1: Синхронная репликация. Общая задержка равна времени на самый длительный запрос в лучшем случае. В худшем и того больше. Нужно выбирать на сколько нод реплицировать, т.е. прямо сразу приходим к consistency vs latency.
- 2.2: Асинхронная репликация. Здесь могут быть такие проблемы с консистентность, как Read Your Writes, Write Follow Reads и прочие интересные особенности (см. правый кусок дерева здесь). Их можно так или иначе обойти, но об этом надо думать, принимать решение, и писать исполняемый код, а значит трейдвофф между задержками и консистентностью тоже есть.

Вариант 3: Данные направляются в произвольную ноду (не прямо произвольную, конечно, а например в любую из какого-то кворума). В сущности что здесь, что в варианте 2 проблемы и решения совершенно одинаковые, так что снова есть тредофф latency vs consistency.

С подходом PACELC система может классифицироваться 4 буквами. В качестве примера автор говорит, что MongoDB это PA/EC. При наличии партиций (PA) она остается доступной, т.к. отделенная от остального кластера нода продолжает писать в rollback директорию. При этом без партиций (EC) гарантируется консистеность в первую очередь... Как минимум в соответствии с документацией. Кому интересно, в статье еще рассматривается VoltDB/H-Store (PC/EC), PNUTS (PC/EL) и DynamoDB, Cassandra, Riak (PA/EL). Хотя "рассматривается" это сильно сказано, там по одному параграфу.

А еще хорошие новости! Мне осталась буквально 1 работа и мы закончим с CAPом... пока что.
🔥1
История CAP теоремы (6/6)

Последняя работа, о которой я бы хотел упомянуть, это критика CAP от Martin Kleppman, того самого автора книжки с кабанчиком.

Первая часть посвящена, собственно, разбору CAP из 3 частей. Что не так, что не понятно, где термины даются не четко, и какие из этого всего вытекают проблемы. К концу даже доказывается ряд теорем, очень похожих на CAP, но без двусмысленных формулировок. Эта часть на 100% формальная, и мы её пропустим, но сама терминология и доказательство поразительно лаконичны. Рекомендую почитать, если вам нравится такой формат.

Вторая часть рассказывает про фреймворк delay-sensitivity. Идея заключается в том, что в настоящий момент существует пропасть между теоретическими изысканиями, такими как формальное доказательство CAP теоремы и практическими системами. Например, в современном мире слишком высокая задержка (latency) приравнивается к недоступности сервиса (SLA/O, вот это все). Значит нужно построить такую модель терминов, которая помогла бы разговаривать на одном языке исследователям и разработчикам, при этом покрывала бы реальные кейсы.

Модель выстраивается в 2 этапа. Сначала задаются теоретические нижние границы времени выполнения операций чтения и записи для разных уровней консистентности в зависимости от сетевых задержек (обозначаются здесь через d). Каждый уровень сопровождается ссылкой на доказательство.

- linearizability — и чтение, и запись O(d). Пруф.
- sequential consistency — либо чтение, либо запись O(d). Второе из двух может быть O(1). Пруф.
- casual consistency — обе операции за O(1). Пруф 1, пруф 2.

Следует помнить, что наличие формального доказательства вовсе не обозначает применимость в реальном мире. Например, оказывается что casually consistent хранилище может и читать и писать за константу. Вот только для этого нужно передавать еще мешок данных, по которым можно определить эту самую casualty, что в реальных системах нецелесообразно. Поэтому, в частности, в реальном мире существуют более слабые гарантии, например eventually consistent системы.

А дальше, собственно, идет терминология delay-sensitivity фреймворка:

- Availability следует считать эмпирической величиной, равной проценту успешных запросов от количества общих в период времени. Чуть подробнее про эмпирическое значение availability я писал тут.
- Delay-sensitive — это свойство алгоритма, обозначающее, что ему нужно ждать задержку d пока шаг выполнится. В противоположность ставиться delay-insensitive, которым ждать не нужно. Как пример — запись в мастер может сделаться сразу же, а вот репликация данных в другие ноды минимум за d.
- Network Faults. Должны включать в себя не только полный network partition, но так же и периодические потери пакетов (ака "сеть моргнула") и внезапное превышение средних задержек. Все три показателя важны для реальной системы.
- Fault Tolerance — следует использовать вместо понятия partition tolerance. Алгоритм должен описывать какие ошибки он может пережить (например, потерю менее половины нод), а также что происходит, если лимит ошибок превышен.
- Consistency должен обозначать одну из известных моделей. Слово strong consistency не имеет смысла и лишь усложняет понимание.

Приживется ли терминология, покажет лишь время. Работа молодая, ей едва ли стукнуло 6 лет!

А на этом наш сказ про CAP закончился. Осталось только подвести итог:

- Под словом CAP понимают две вещи. Первая — формально доказанное утверждение, которое практически не имеет применений в реальности. Вторая — набор суждений про вечный трейдофф consistency/availability/latency/throughput/что-угодно-ещё.
- Разделение сети (partition tolerance) — это возможная, но далеко не единственная ошибка, которая может возникнуть в системе. В реальном мире нужно защищаться от всего.
- Доступность (Availability) в литературе и в реальном мире — две в сущности независимые вещи. В работах это "возможность получить результат", в мире — эмпирическая метрика.
- Даже без явных ошибок, в распределенной системе есть трейдоффы, а все эти консистентности и доступности — не бинарные величины, а точки на спектре.
🔥2
Про алгоритмы на собеседованиях

За последнюю неделю, я наткнулся аж на раз и два поста про то, как неправильно большие компании нанимают разработчиков. Истории звучат всегда как под копирку... либо «десять тысяч лет я делаю реальный софт, а меня не берут», либо «задачи непрактичные и бесполезные. Кому нужны ваши алгоритмы». Позиции кандидатов можно посочувствовать, но это скучно, поэтому время вызывать адвоката дьявола.

Начнём издалека. IT системы постоянно растут, обрабатывают все больше и больше запросов-в-секунду и петабайт-в-месяц. Каждые новые x10, а то и х5 клиентов требует рефакторингов, новых подходов, архитектуры. Создание чего-либо с нуля это дорого, долго и никаких гарантий, поэтому по возможности предпочтение отдаётся "проверенным решениям". Зачем писать свою кеш-систему, если можно взять готовую? Для чего думать над корректной асинхронностью, если уже изобрели системы обмена сообщениями?

Подход подкупает логичностью. Возьмём решение, которое у кого-то уже сработало, реализуем у себя. Затем оставим на веки вечные, до тех пор, пока оно справляется с нагрузкой / профилем / объемом данных / и т.д. Естественно все нужные нам параметры замерим. Получается и риски минимизировали, и время на разработку сократили, и еще можно хвастаться, что у нас в стеке +1 модный баззворд. Красота!

Вернёмся снова к компаниям и их собеседованиям. Вы создатель нового успешного стартапа, наняли первых пятерых разработчиков методом... разговора по душам конечно же, как же ещё, ведь вы люто ненавидите алгоритмические задачки на интервью. Проходит несколько месяцев. Теперь в компании уже 50 разработчиков. Проводить собеседования самому становится тяжело, поэтому функция оценки кандидата уходит в команды. Но вот незадача, то наймут короля токсичности, то супер-звезду, которому через полгода надоест, то сэра самозванца (не тот, который синдром, а тот который бездарен в своей профессии) Надо что-то делать...

Начинает создаваться некий формальный процесс найма, цель которого — нанимать более подходящих кандидатов. Как и в IT, этот процесс покрывается метриками от оценки кандидата до среднего времени жизни сотрудника и удовлетворённости своей работой. Появляются пулы вопросов, обязательная culture fit часть, exit-интервью, круговые ревью, в общем используются готовые решения, которые у кого-то уже сработали.

Ваш стартап стал серьёзной компанией. Теперь вы нанимаете по 50 человек в месяц, вы уже мыслите числами и метриками. При вашем текущем подходе только 60% кандидатов выходят на средний уровень производительности команды за 4 месяца. Получается остальные 40% не дотягивают! Возможно, думаете вы, проблема в том, что к нам приходят технически слабо подготовленные специалисты. Ваш Вице-Президент-По-HR советует вам посмотреть на опыт компании "условно-гугл" и давать алгоритмические задачи. Вам эта идея противна, но с ней соглашается совет директоров. Придется делать. Но мы же большая и умная компания, поэтому проведём A/B тест. 80% кандидатов поведём по старому процессу, а 20% по-новому, с алгоритмами.

И о чудо, через полгода замеров оказывается, что из тестовой когорты, которая проходила алгоритмические задачи, вышло на нужную вам производительность за 4 месяца 89% сотрудников. Это на 29% больше, чем ранее, прирост почти в два раза! Вы не верите в алгоритмы, пытаетесь еще одной A/B когорте дать упрощенные задачки, метрика падает до 63%. Следующей даёте 3 дизайн секции и 1 на программирование. Поднимается до 74%, но это не 89%. Да что же такое! Вам самому противно в душе, но цифры говорят, что алгоритмы работают, а остальные подходы не работают.

Вас ненавидят в интеренатах, поносят "не имеющие ничего общего с реальностью" алгоритмические секции. Но почему-то когда процесс найма становится другим, кандидаты нанимаются плохие. Да, ваш процесс раз в месяц отсеивает очередного создателя homebrew (если что, он извинился), да ваш HR бренд в каком-то смысле страдает... Но ведь оно работает. А работает — не трогай. Хочешь поменять — сначала измерь. Только не пытайся доказать, что с алгоритмами статистически и вправду лучше найм, не поверят!
🔥1