Фундаментальная и случайная сложность.
Мы живем в мире удивительного количества архитектурных баззвордов и технологий. CQRS, Event Sourcing, PWA, Reactive Applications... список можно продолжать. При этом нам всем хочется писать правильно и на верных технологиях.
Загвоздка заключается в том, что очень часто подобные решения являются избыточными, и мы, получая решение одной проблемы, сами себе попутно создаем еще десяток других.
Но для начала, давайте поговорим о сложности программного обеспечения в целом, т.к. именно сложность является корнем проблемы.
Как завещал товарищ Фредерик Брукс, есть 2 вида сложности при создании программного обеспечения: фундаментальная (essential) и случайная (accidental).
Фундаментальная сложность - это сама суть вашего бизнеса / сферы. Я последние пару месяцев работаю в компании, автоматизирующей рынок логистики. И, должен сказать, сам этот рынок совершенно безумный. Даже самая простейшая перевозка полной фуры из точки А в точку Б - это кипа документов, целая инфраструктура для трекинга, высчитывание ориентировочного времени прибытия/убытия в зависимости от данных геокодинга/пробок/погоды/etc и поверх этого еще пласт персонализированных настроек каждого отдельного перевозчика, кладовщика и клиента. Таким образом, фундаментальная сложность ПО для автоматизации этого рынка - высокая.
Случайная сложность - это все остальное, т.е. разность общей сложности вашего продукта без его фундаментальной сложности. Иными словами, все что не относится к фундаментальному - случайно. Тот факт, что для реализации "личного кабинета, в котором пользователь может прикреплять аватарку" вам нужно развернуть несколько http ручек и еще научиться работать с файлохранилищем - это случайность. Если у вас миллиард пользователей, а значит хранилище огромное и падает, а значит его нужно шардировать и реплицировать, а значит писать для этого код - это тоже случайность, но уже неизбежная.
Иными словами, создать софт с нулевым уровнем случайной сложности решительно невозможно.
При этом очень легко создать софт, обладающий катастрофически высокой случайной сложностью, но довольно низкой фундаментальной. Наша задача - оставить ровно столько случайного, сколько будет достаточно. Или отрезать всё лишнее. Или оставить лишь необходимое.
А это значит, что любое техническое решение должно проходить не только через призму "решает ли это нашу проблему", но также и через призму "является ли это наипростейшим работающим решением". KISS (Keep it simple, stupid)! YAGNI (You aren't gonna need it)! Все эти словечки как раз отсюда.
Но как же так. Как же, если у нас... высоконагруженная система! И нам нужно, чтобы работало быстро! Тут мой ответ такой: если вы достаточно развитая компания, чтобы, во-первых, регулярно производить нагрузочное тестирование, и во-вторых, регулярно анализировать рост этой нагрузки, иными словами, если вы с высокой вероятностью знаете вашу будущее нагрузку - вперед, оптимизируйте. Но оптимизация без минимальной попытки расчитать необходимые объемы - это трата средств бизнеса, инвесторов и выделение лишнего CO2 разработкой. (к слову, скачать яндекс-танк и замерить на примитивном уровне - это вопрос получаса времени)
Таким образом, большая часть попыток сделать special high-grade class of software that makes careful use of relevant software architecture design principles to build particularly customizable and extensible solutions to real problems (https://github.com/EnterpriseQualityCoding/FizzBuzzEnterpriseEdition) скорее всего в вашем случае - излише. Разве что вы точно знаете, что вы делаете.
Мы живем в мире удивительного количества архитектурных баззвордов и технологий. CQRS, Event Sourcing, PWA, Reactive Applications... список можно продолжать. При этом нам всем хочется писать правильно и на верных технологиях.
Загвоздка заключается в том, что очень часто подобные решения являются избыточными, и мы, получая решение одной проблемы, сами себе попутно создаем еще десяток других.
Но для начала, давайте поговорим о сложности программного обеспечения в целом, т.к. именно сложность является корнем проблемы.
Как завещал товарищ Фредерик Брукс, есть 2 вида сложности при создании программного обеспечения: фундаментальная (essential) и случайная (accidental).
Фундаментальная сложность - это сама суть вашего бизнеса / сферы. Я последние пару месяцев работаю в компании, автоматизирующей рынок логистики. И, должен сказать, сам этот рынок совершенно безумный. Даже самая простейшая перевозка полной фуры из точки А в точку Б - это кипа документов, целая инфраструктура для трекинга, высчитывание ориентировочного времени прибытия/убытия в зависимости от данных геокодинга/пробок/погоды/etc и поверх этого еще пласт персонализированных настроек каждого отдельного перевозчика, кладовщика и клиента. Таким образом, фундаментальная сложность ПО для автоматизации этого рынка - высокая.
Случайная сложность - это все остальное, т.е. разность общей сложности вашего продукта без его фундаментальной сложности. Иными словами, все что не относится к фундаментальному - случайно. Тот факт, что для реализации "личного кабинета, в котором пользователь может прикреплять аватарку" вам нужно развернуть несколько http ручек и еще научиться работать с файлохранилищем - это случайность. Если у вас миллиард пользователей, а значит хранилище огромное и падает, а значит его нужно шардировать и реплицировать, а значит писать для этого код - это тоже случайность, но уже неизбежная.
Иными словами, создать софт с нулевым уровнем случайной сложности решительно невозможно.
При этом очень легко создать софт, обладающий катастрофически высокой случайной сложностью, но довольно низкой фундаментальной. Наша задача - оставить ровно столько случайного, сколько будет достаточно. Или отрезать всё лишнее. Или оставить лишь необходимое.
А это значит, что любое техническое решение должно проходить не только через призму "решает ли это нашу проблему", но также и через призму "является ли это наипростейшим работающим решением". KISS (Keep it simple, stupid)! YAGNI (You aren't gonna need it)! Все эти словечки как раз отсюда.
Но как же так. Как же, если у нас... высоконагруженная система! И нам нужно, чтобы работало быстро! Тут мой ответ такой: если вы достаточно развитая компания, чтобы, во-первых, регулярно производить нагрузочное тестирование, и во-вторых, регулярно анализировать рост этой нагрузки, иными словами, если вы с высокой вероятностью знаете вашу будущее нагрузку - вперед, оптимизируйте. Но оптимизация без минимальной попытки расчитать необходимые объемы - это трата средств бизнеса, инвесторов и выделение лишнего CO2 разработкой. (к слову, скачать яндекс-танк и замерить на примитивном уровне - это вопрос получаса времени)
Таким образом, большая часть попыток сделать special high-grade class of software that makes careful use of relevant software architecture design principles to build particularly customizable and extensible solutions to real problems (https://github.com/EnterpriseQualityCoding/FizzBuzzEnterpriseEdition) скорее всего в вашем случае - излише. Разве что вы точно знаете, что вы делаете.
GitHub
GitHub - EnterpriseQualityCoding/FizzBuzzEnterpriseEdition: FizzBuzz Enterprise Edition is a no-nonsense implementation of FizzBuzz…
FizzBuzz Enterprise Edition is a no-nonsense implementation of FizzBuzz made by serious businessmen for serious business purposes. - EnterpriseQualityCoding/FizzBuzzEnterpriseEdition
🔥1
(1/2) А - Архитектура
Архитектура - самое неоднозначное слово в IT. В интернетах можно найти десятки определений, при чем половина из них будет друг другу противоречить. Если подумать, то этот хаос можно очень легко объяснить:
1. Первые публичные попытки придумать терминологию для IT начались в 50-60-ые годы. При этом основой для терминологии новой области знаний стало стоительство. Поэтому софт мы "билдим" или "конструируем", его структура - это "архитектура". А мы сами "девелоперы" или в лучшем случае "инженеры". (К слову, факапы сроков при стоительстве дело такое же распространенное, как и при разработке ПО. Возможно, во всем виновата терминология и майндсет, который она приносит)
2. Слово "архитектура" пытается вобрать в себя и структуру продукта, и набор красивых картинок/диаграмм, описывающих его, и стандартизацию способов расширения существующего ПО, и чуть ли не подход к организации команды для реализации архитектуры (Привет, закон Конвея)
3. Делу не помогает наличие всевозможных "архитекторов", которые занимаются совершенно разной деятельностью в зависимости от компании.
4. Придумать определение для слова "архитектура", не использовав другие термины, довольно сложно.
Многие деятели пытались создать хорошее определение, но мне больше всего по душе терминология, введенная Роем Филдингом в 2000 году в своей легендарной докторской Architectural Styles and the Design of Network-based Software Architectures (https://www.ics.uci.edu/~fielding/pubs/dissertation/software_arch.htm). Эта работа скорее знаменита как библия REST, но первая её часть как раз посвящена вопросу архитектуры.
Итак, вольный перевод определений по Филдингу.
Архитектура программного обеспечения - это абстракция времени исполнения программных элементов, во время выполнения некоторой фазы опреации. Система может состоять из множества уровней абстракции с различными фазами и операциями. Каждая такая фаза может иметь свою архитектуру.
Фундаментально важная часть этого определения - абстракция времени исполнения! Архитектура - это про то как работает в реальности. Это архиважное замечание, так как оно позволяет делать интересные и полезные выводы. Например, если на картинках у вас "идеальная архитектура", а SLO не выполняются и разработчики жалуются, значит у вас не идеальная архитектура, а архитектор, если такой имеется, не справляется со своими обязанностями.
В данном определении абстракция - это сокрытие конкретных деталей, для идентифицкации свойств.
Программные элементы - это общее название для программных компонентов, коннекторов и данных.
Программные компоненты - абстрактная единица программных инстукций и внутреннего состояния, трансформирующая данные, при помощи предоставляемого интерфейса.
Коннекторы - абстрактный механизм, определяющий способ взаимодействия программных компонентов между собой.
Данные - элемент информации, передаваемый от или к компоненту при помощи коннектора.
Мы получили красивое дерево определений. Архитектура - это рантайм абстракция над элементы, а видов элементов бывает три. Но хотелось бы еще ответить на вопрос как выглядит эта абстракция.
Архитектура определяется конфигурацией программных элементов в их взаимодействии для достижения определелнных функциональных и нефункциональных свойств (так же называется архитектурные свойства).
Конфигурация - это структура взаимоотношений абстрактных элементов во время исполнения фазы операции. Определение очень похоже на определение архитектуры, данное выше, но разница здесь в первом слове. Конфигурация - это структура, т.е. она может быть картинкой, диаграммой или топологией, а вот архитектура - это абстракция. Нельзя нарисовать архитектуру, но можно нарисовать конфигурацию архитектуры.
Архитектура - самое неоднозначное слово в IT. В интернетах можно найти десятки определений, при чем половина из них будет друг другу противоречить. Если подумать, то этот хаос можно очень легко объяснить:
1. Первые публичные попытки придумать терминологию для IT начались в 50-60-ые годы. При этом основой для терминологии новой области знаний стало стоительство. Поэтому софт мы "билдим" или "конструируем", его структура - это "архитектура". А мы сами "девелоперы" или в лучшем случае "инженеры". (К слову, факапы сроков при стоительстве дело такое же распространенное, как и при разработке ПО. Возможно, во всем виновата терминология и майндсет, который она приносит)
2. Слово "архитектура" пытается вобрать в себя и структуру продукта, и набор красивых картинок/диаграмм, описывающих его, и стандартизацию способов расширения существующего ПО, и чуть ли не подход к организации команды для реализации архитектуры (Привет, закон Конвея)
3. Делу не помогает наличие всевозможных "архитекторов", которые занимаются совершенно разной деятельностью в зависимости от компании.
4. Придумать определение для слова "архитектура", не использовав другие термины, довольно сложно.
Многие деятели пытались создать хорошее определение, но мне больше всего по душе терминология, введенная Роем Филдингом в 2000 году в своей легендарной докторской Architectural Styles and the Design of Network-based Software Architectures (https://www.ics.uci.edu/~fielding/pubs/dissertation/software_arch.htm). Эта работа скорее знаменита как библия REST, но первая её часть как раз посвящена вопросу архитектуры.
Итак, вольный перевод определений по Филдингу.
Архитектура программного обеспечения - это абстракция времени исполнения программных элементов, во время выполнения некоторой фазы опреации. Система может состоять из множества уровней абстракции с различными фазами и операциями. Каждая такая фаза может иметь свою архитектуру.
Фундаментально важная часть этого определения - абстракция времени исполнения! Архитектура - это про то как работает в реальности. Это архиважное замечание, так как оно позволяет делать интересные и полезные выводы. Например, если на картинках у вас "идеальная архитектура", а SLO не выполняются и разработчики жалуются, значит у вас не идеальная архитектура, а архитектор, если такой имеется, не справляется со своими обязанностями.
В данном определении абстракция - это сокрытие конкретных деталей, для идентифицкации свойств.
Программные элементы - это общее название для программных компонентов, коннекторов и данных.
Программные компоненты - абстрактная единица программных инстукций и внутреннего состояния, трансформирующая данные, при помощи предоставляемого интерфейса.
Коннекторы - абстрактный механизм, определяющий способ взаимодействия программных компонентов между собой.
Данные - элемент информации, передаваемый от или к компоненту при помощи коннектора.
Мы получили красивое дерево определений. Архитектура - это рантайм абстракция над элементы, а видов элементов бывает три. Но хотелось бы еще ответить на вопрос как выглядит эта абстракция.
Архитектура определяется конфигурацией программных элементов в их взаимодействии для достижения определелнных функциональных и нефункциональных свойств (так же называется архитектурные свойства).
Конфигурация - это структура взаимоотношений абстрактных элементов во время исполнения фазы операции. Определение очень похоже на определение архитектуры, данное выше, но разница здесь в первом слове. Конфигурация - это структура, т.е. она может быть картинкой, диаграммой или топологией, а вот архитектура - это абстракция. Нельзя нарисовать архитектуру, но можно нарисовать конфигурацию архитектуры.
🔥1
(2/2) А - Архитектура
Осталось ответить на самый важный вопрос... Какая практическая польза от всей этой пачки определений? Дело в том, что нам не так важна архитектура как таковая, как другой термин из той же работы Филдинга - архитектурный стиль. Т.е. конечный набор ограничений множества архитектурных элементов и конфигураций для достижения конечного же набора архитектурных свойств.
Здесь речь о следующем: представьте перед собой бесконечное множество всех возможных архитектурных элементов, вот у вас тут http сервисы, тут RPC, здесь очереди сообщений, а там нереляционные хранилища. Из этого конструктора хочется создать некий новый программный продукт. Как это сделать? С нашими определениями это просто - определить необходимые архитектурные свойства, которые важны нашему продукту. Эти свойства позволят ограничить условно-бесконечный набор элементов до некоторого подмножества, которое мы сможет использовать. При этом, возможно, кому-то уже приходилось в голову создать то что пытаетесь создать вы, и интересующий вас набор свойств можно получить при помощи определенного набора ограничений, называемых архитектурным стилем.
Например тот же Филдинг и REST. REST - это архитектурный стиль, определяемый через следующие ограничения:
1. Клиент-серверная архитектура. Т.е. явное разделение ответственности между инициатором взаимодействия и обработчиком.
2. Отсутствие состояний. Любой запрос должен содержать всю информацию, необходимую для его корректной обработки.
3. Кешируемость. Любое взаимодействие имеет возможность быть закешировано (наличие возможность не означает, что оно должно быть закешировано, но должен быть механизм, который позволяет это сделать)
4. Сложнопереводимое понятие layered system. Т.е. наличие иерархии компонентов, выполняющих разные функции, расположенные таким образом, что каждый компонент видит лишь своих соседей, и не знает, есть ли у этих соседей другие соседи.
5. Единый интерфейс - способ взаимодействия компонентов должен быть одинаковый. Например, все по HTTP, или все по RPC.
6. Code on demand (опциональное ограничение) - сервер имеет возможность расширять функциональность клиента при помощи передачи блоков кода (например, кидать в браузер JS код).
Определение необходимых архитектурных свойств на раннем этапе разработки программного продукта позволяет создать фундамент ограничений для принятия обоснованных технических решений. Явное обозначение необходимых свойства конечного продукта также позволет всей команде разработки лучше понимать, в каком направлении и почему двигается развитие архитектуры.
Осталось ответить на самый важный вопрос... Какая практическая польза от всей этой пачки определений? Дело в том, что нам не так важна архитектура как таковая, как другой термин из той же работы Филдинга - архитектурный стиль. Т.е. конечный набор ограничений множества архитектурных элементов и конфигураций для достижения конечного же набора архитектурных свойств.
Здесь речь о следующем: представьте перед собой бесконечное множество всех возможных архитектурных элементов, вот у вас тут http сервисы, тут RPC, здесь очереди сообщений, а там нереляционные хранилища. Из этого конструктора хочется создать некий новый программный продукт. Как это сделать? С нашими определениями это просто - определить необходимые архитектурные свойства, которые важны нашему продукту. Эти свойства позволят ограничить условно-бесконечный набор элементов до некоторого подмножества, которое мы сможет использовать. При этом, возможно, кому-то уже приходилось в голову создать то что пытаетесь создать вы, и интересующий вас набор свойств можно получить при помощи определенного набора ограничений, называемых архитектурным стилем.
Например тот же Филдинг и REST. REST - это архитектурный стиль, определяемый через следующие ограничения:
1. Клиент-серверная архитектура. Т.е. явное разделение ответственности между инициатором взаимодействия и обработчиком.
2. Отсутствие состояний. Любой запрос должен содержать всю информацию, необходимую для его корректной обработки.
3. Кешируемость. Любое взаимодействие имеет возможность быть закешировано (наличие возможность не означает, что оно должно быть закешировано, но должен быть механизм, который позволяет это сделать)
4. Сложнопереводимое понятие layered system. Т.е. наличие иерархии компонентов, выполняющих разные функции, расположенные таким образом, что каждый компонент видит лишь своих соседей, и не знает, есть ли у этих соседей другие соседи.
5. Единый интерфейс - способ взаимодействия компонентов должен быть одинаковый. Например, все по HTTP, или все по RPC.
6. Code on demand (опциональное ограничение) - сервер имеет возможность расширять функциональность клиента при помощи передачи блоков кода (например, кидать в браузер JS код).
Определение необходимых архитектурных свойств на раннем этапе разработки программного продукта позволяет создать фундамент ограничений для принятия обоснованных технических решений. Явное обозначение необходимых свойства конечного продукта также позволет всей команде разработки лучше понимать, в каком направлении и почему двигается развитие архитектуры.
🔥1
Минутка мудрости на тему correlation != causation из гугловский книжки по SRE.
С 2000 по 2009 год наблюдается корреляции между количеством полученных PhD по CS и... Потреблением сыра на душу населения
http://tylervigen.com/view_correlation?id=1099
Ресурс в целом прекрасный чтобы позалипать http://tylervigen.com/spurious-correlations
С 2000 по 2009 год наблюдается корреляции между количеством полученных PhD по CS и... Потреблением сыра на душу населения
http://tylervigen.com/view_correlation?id=1099
Ресурс в целом прекрасный чтобы позалипать http://tylervigen.com/spurious-correlations
Tylervigen
Computer science doctorates awarded (US) correlates with Per capita consumption of cheese (US)
Can you come up with a causal mechanism?
🔥1
Сегодня вышло продолжение "бестселлера" Google SRE Book: Building Secure and Reliable Systems: Best Practices for Designing, Implementing, and Maintaining Systems. Электронные версии доступны бесплатно.
Can a system be considered truly reliable if it isn't fundamentally secure? Or can it be considered secure if it's unreliable? Security is crucial to the design and operation of scalable systems in production, as it plays an important part in product quality, performance, and availability. In this book, experts from Google share best practices to help your organization design scalable and reliable systems that are fundamentally secure.
Can a system be considered truly reliable if it isn't fundamentally secure? Or can it be considered secure if it's unreliable? Security is crucial to the design and operation of scalable systems in production, as it plays an important part in product quality, performance, and availability. In this book, experts from Google share best practices to help your organization design scalable and reliable systems that are fundamentally secure.
🔥1
Есть такая заезженная рекомендация для one-on-one, о том что фидбек должен быть позитивным. Я всегда думал, что "позитивный фидбек" — это что-то хорошее, приятное, развивающие...
Но сегодня я узнал, что позитивный фидбек — это очень общее понятие для процесса, когда некоторое воздействие
Например, резонанса - это позитивный фидбек. GC spiral of death (это когда из-за увеличения использования памяти в JVM увеличивается частота GC, что увеличивает затраты CPU, что заставляет GC отрабатывать медленнее, что увеличивает затраты памяти и так до OutOfMemoryError) — это позитивный фидбек и из актуального, распространение паники и слухов в обществе — это тоже позитивный фибдек.
The more you know!
Но сегодня я узнал, что позитивный фидбек — это очень общее понятие для процесса, когда некоторое воздействие
A, приводит к увеличению B, что в свою очередь приводит к увеличению A (Сорс, конечно же, википедия https://en.wikipedia.org/wiki/Positive_feedback). Например, резонанса - это позитивный фидбек. GC spiral of death (это когда из-за увеличения использования памяти в JVM увеличивается частота GC, что увеличивает затраты CPU, что заставляет GC отрабатывать медленнее, что увеличивает затраты памяти и так до OutOfMemoryError) — это позитивный фидбек и из актуального, распространение паники и слухов в обществе — это тоже позитивный фибдек.
The more you know!
🔥1
Не работал в аутсорсе — не разработчик! (с)
https://medium.com/@MortyMerr/pain-driven-development-79d4cc7391ae
https://medium.com/@MortyMerr/pain-driven-development-79d4cc7391ae
Medium
Pain Driven Development
Собирательный образ русского аутсорса
🔥1
Очень красивая анимация о том, как работает алгоритм консенсуса raft.
http://thesecretlivesofdata.com/raft/
В конце есть ссылка на вайтпейпер https://raft.github.io/raft.pdf
http://thesecretlivesofdata.com/raft/
В конце есть ссылка на вайтпейпер https://raft.github.io/raft.pdf
🔥1
0.5 гугла из 100.
Навеяно прочтением той самой книжки по SRE от гугла. Каждую главу я поражался, насколько же мои проблемы бытовые по сравнению с "при размере гугла, вероятность один на миллион - все равно что происходит постоянно".
Как обычно балансируется трафик? На первом уровне весь ваш набор серверов умещается в запись о DNS. Дальше серверов становится больше, возможно появляется geoDNS, но скорее всего все заканчивается тем, что группы бекендов объединяются под виртуальными IP (VIP), который по Round-robin раскидывает запросы. Работает? Конечно. Но не когда вы обрабатывается по разным источникам от 10% до 40% мирового трафика в зависимости от материка и источника.
Представим что в кейсе гугла нам нужно, чтобы запросы с одного IP летели всегда на один и тот же бекенд. Получается на уровне VIP при балансировке запроса нам нужно держать огромную таблицу всех соединений клиентов к их целевым бекендам. Реализовать это не сложно, так как это по сути и есть NAT (https://ru.wikipedia.org/wiki/NAT), но это огромное количество данных, которые нужно где-то держать, и каким-то образом переносить в случае отказов. Не самое удачное решение, когда количество машин легко переваливает за десятки тысяч, а соединений за сотни и миллионы.
Одно из возможных решений - это похакать на втором уровне OSI пакет, подменив в нем MAC адрес назначения на адрес источника. Бекенд получает такой пакет и, минуя баналсировщик, отправляет его напрямую инициатору запроса. Это называется Direct Server Response. Проблема такого подхода в том, что он требует дописывать (и удалять) MAC адреса новых серверов на балансировщик, что становится затруднительным при таком количество машин.
Конечно с этой проблемой гугл справился решением, которое давным-давно придумали матерые сетевики (в данном случае - Cisco) — магии под названием Generic Routing Encapsulation (https://tools.ietf.org/html/rfc1702). Если в кратце то суть следущая: запихиваем IP пакет в другой пакет, получаем новый пакет IP+GRE. Отдаем этот пакет на бекенд. Бекенд игнорирует часть с GRE, и работает с адресами из IP части, а балансировщик не игнорирует и работает с другими адресами из GRE части. Получается бекенд и балансировщик могут находится хоть на разных континентах. Если адрес можно найти через маршрутизацию - он найдется.
Это все была балансировка до того, как запрос дошел в дата центр. Но ведь теперь его нужно сбалансировать на правильную машину внутри ДЦ! Мы конечно все прячемся за абстракцией, что датацентр - это большой компьютер (https://www.morganclaypool.com/doi/pdf/10.2200/S00193ED1V01Y200905CAC006), но чтобы это действительно было так, необходимо чтобы этот компьютер мог распределять трафик близко к оптимальному. Следует также учесть, что при масштабе гугла не все дата центры одинаковые, и даже внутри одного дата центра могут быть разные по характеристикам машины.
Эту проблему можно решать по-разному, но интуитивно правильное решение очень легко представить. Нужно всего лишь придумать как бы заставить все бекенды возвращать некую цифру "загруженности", которая должна учитывать: текущее количество запросов в единицу времени, количество ошибок в единицу времени и текущую утилизацию в виде CPU/памяти. При наличии такой функции, мы получаем возможность использовать взвешенный Round-robin, где вес - это динамическая характеристика, периодически обновляемая бекендом. При наличии такой характеристики сделать честную балансировку не составляет труда... Жалко что о самое интересной части - как же все-таки подсчитать веса всех этих характеристик гугл-таки умолчал в книжке по SRE :)
Навеяно прочтением той самой книжки по SRE от гугла. Каждую главу я поражался, насколько же мои проблемы бытовые по сравнению с "при размере гугла, вероятность один на миллион - все равно что происходит постоянно".
Как обычно балансируется трафик? На первом уровне весь ваш набор серверов умещается в запись о DNS. Дальше серверов становится больше, возможно появляется geoDNS, но скорее всего все заканчивается тем, что группы бекендов объединяются под виртуальными IP (VIP), который по Round-robin раскидывает запросы. Работает? Конечно. Но не когда вы обрабатывается по разным источникам от 10% до 40% мирового трафика в зависимости от материка и источника.
Представим что в кейсе гугла нам нужно, чтобы запросы с одного IP летели всегда на один и тот же бекенд. Получается на уровне VIP при балансировке запроса нам нужно держать огромную таблицу всех соединений клиентов к их целевым бекендам. Реализовать это не сложно, так как это по сути и есть NAT (https://ru.wikipedia.org/wiki/NAT), но это огромное количество данных, которые нужно где-то держать, и каким-то образом переносить в случае отказов. Не самое удачное решение, когда количество машин легко переваливает за десятки тысяч, а соединений за сотни и миллионы.
Одно из возможных решений - это похакать на втором уровне OSI пакет, подменив в нем MAC адрес назначения на адрес источника. Бекенд получает такой пакет и, минуя баналсировщик, отправляет его напрямую инициатору запроса. Это называется Direct Server Response. Проблема такого подхода в том, что он требует дописывать (и удалять) MAC адреса новых серверов на балансировщик, что становится затруднительным при таком количество машин.
Конечно с этой проблемой гугл справился решением, которое давным-давно придумали матерые сетевики (в данном случае - Cisco) — магии под названием Generic Routing Encapsulation (https://tools.ietf.org/html/rfc1702). Если в кратце то суть следущая: запихиваем IP пакет в другой пакет, получаем новый пакет IP+GRE. Отдаем этот пакет на бекенд. Бекенд игнорирует часть с GRE, и работает с адресами из IP части, а балансировщик не игнорирует и работает с другими адресами из GRE части. Получается бекенд и балансировщик могут находится хоть на разных континентах. Если адрес можно найти через маршрутизацию - он найдется.
Это все была балансировка до того, как запрос дошел в дата центр. Но ведь теперь его нужно сбалансировать на правильную машину внутри ДЦ! Мы конечно все прячемся за абстракцией, что датацентр - это большой компьютер (https://www.morganclaypool.com/doi/pdf/10.2200/S00193ED1V01Y200905CAC006), но чтобы это действительно было так, необходимо чтобы этот компьютер мог распределять трафик близко к оптимальному. Следует также учесть, что при масштабе гугла не все дата центры одинаковые, и даже внутри одного дата центра могут быть разные по характеристикам машины.
Эту проблему можно решать по-разному, но интуитивно правильное решение очень легко представить. Нужно всего лишь придумать как бы заставить все бекенды возвращать некую цифру "загруженности", которая должна учитывать: текущее количество запросов в единицу времени, количество ошибок в единицу времени и текущую утилизацию в виде CPU/памяти. При наличии такой функции, мы получаем возможность использовать взвешенный Round-robin, где вес - это динамическая характеристика, периодически обновляемая бекендом. При наличии такой характеристики сделать честную балансировку не составляет труда... Жалко что о самое интересной части - как же все-таки подсчитать веса всех этих характеристик гугл-таки умолчал в книжке по SRE :)
🔥1
Получается, login - тоже от слова log!
А Blog... это book log? Или взять web, отрезать первые 2 буквы, и приделать log - blog!
Еще интересная статья на тему. Первое упоминание "login" люди в комментариях находят еще в 60-ые! https://www.designcult.org/2011/08/why-do-we-call-in-logging-in.html
А Blog... это book log? Или взять web, отрезать первые 2 буквы, и приделать log - blog!
Еще интересная статья на тему. Первое упоминание "login" люди в комментариях находят еще в 60-ые! https://www.designcult.org/2011/08/why-do-we-call-in-logging-in.html
🔥1
От консистентности не скрыться! 1/2
Не так давно я решил по хардкору пройтись по матчасти того, что такое консистентность, и как это вообще все работает. Довольно быстро оказалось, что кроличья нора настолько глубока, что изучать эти вопросы можно еще пару (десятков) лет. Тем не менее, сегодня я постараюсь поделиться самыми интересными штуками, которые успел найти на текущий момент.
Есть поверье, что любой достаточно крупный проект, который живет в продакшене больше пары лет, рано или поздно обрастает странными конструкциями, которые по крону проверяют консистентность данных. Казалось бы, если одна и та же ошибка всплывает с определенной периодичность, найти причину такого поведения не составляет труда. На практике же, проблемы консистентности при ближайшем рассмотрении обрастают таким количеством предположений и гипотез, что разобраться в них становится решительно невозможно, проще и быстрее нафигачить по-быстрому скрипт, который за ночь исправит все косяки. Почему все так плохо? Давайте разбираться.
Во-первых, консистентность неотделима от конкурентного доступа. Это означает как минимум следующие: создать надежный тест на консистеность очень сложно. Это еще сложнее, чем делать тесты на производительность! Корень проблемы здесь таиться в том, что любые особенности работы при конкурентном доступе могут произойти, а могут и не произойти. Спасает только многократные запуск тестов, да и то не всегда.
Во-вторых, вас обманывают! Возьмем, например, уровни изоляции в RDBMS. Есть, значит, стандарт SQL-92 почти на 700 страниц (https://www.contrib.andrew.cmu.edu/~shadow/sql/sql1992.txt). А есть его всевозможные реализация. Реализации все разные и фактически предоставляют не ту модель консистентности, которая заявлена по стандарту. Подробнее об этом можно почитать здесь: https://github.com/ept/hermitage. Из забавного - Oracle не предоставляет честный serializable, а repeatable read в MS SQL иногда попросту не выполняется ¯\_(ツ)_/¯. О проблемах стандарта умные дяденьки вообще пишут, что он не очень хороший https://arxiv.org/ftp/cs/papers/0701/0701157.pdf. Пока к сожалению, мой мозг взрывается при прочтении этой работы. Как осилю - обязательно сделать tl/dr.
В-третьих, "моделей консистентности" не 4, как уровней изоляции, их как минимум 7, а как максимум при конкурентном доступе, да еще и в распределенной системе все 16 (супер-полезный ресурс на эту тему http://jepsen.io/consistency. прямоугольники кликабельны!). К слову, как только в вашем клиент-сервере появляется более 1 клиента или более 1 сервера, вы скорее всего попадаете в прекрасный мир распределенных систем, т.е. да, можно принять, что моделей консистентности 16 всегда.
В-четвертых, раз уж мы попали в распределенную систему - умножай сложность на 10, а теперь представим, что у нас хранилище, которое пытается обеспечить консистентность, внутри себя также реплицируется. А реплики, конечно же, падают. И иногда поднимаются. Маленькая распределенная система, как часть большой распределенной системы. И таких мини систем внутри вашего большого продукта могут быть иногда не 1 и не 2, а пару десятков.
Не так давно я решил по хардкору пройтись по матчасти того, что такое консистентность, и как это вообще все работает. Довольно быстро оказалось, что кроличья нора настолько глубока, что изучать эти вопросы можно еще пару (десятков) лет. Тем не менее, сегодня я постараюсь поделиться самыми интересными штуками, которые успел найти на текущий момент.
Есть поверье, что любой достаточно крупный проект, который живет в продакшене больше пары лет, рано или поздно обрастает странными конструкциями, которые по крону проверяют консистентность данных. Казалось бы, если одна и та же ошибка всплывает с определенной периодичность, найти причину такого поведения не составляет труда. На практике же, проблемы консистентности при ближайшем рассмотрении обрастают таким количеством предположений и гипотез, что разобраться в них становится решительно невозможно, проще и быстрее нафигачить по-быстрому скрипт, который за ночь исправит все косяки. Почему все так плохо? Давайте разбираться.
Во-первых, консистентность неотделима от конкурентного доступа. Это означает как минимум следующие: создать надежный тест на консистеность очень сложно. Это еще сложнее, чем делать тесты на производительность! Корень проблемы здесь таиться в том, что любые особенности работы при конкурентном доступе могут произойти, а могут и не произойти. Спасает только многократные запуск тестов, да и то не всегда.
Во-вторых, вас обманывают! Возьмем, например, уровни изоляции в RDBMS. Есть, значит, стандарт SQL-92 почти на 700 страниц (https://www.contrib.andrew.cmu.edu/~shadow/sql/sql1992.txt). А есть его всевозможные реализация. Реализации все разные и фактически предоставляют не ту модель консистентности, которая заявлена по стандарту. Подробнее об этом можно почитать здесь: https://github.com/ept/hermitage. Из забавного - Oracle не предоставляет честный serializable, а repeatable read в MS SQL иногда попросту не выполняется ¯\_(ツ)_/¯. О проблемах стандарта умные дяденьки вообще пишут, что он не очень хороший https://arxiv.org/ftp/cs/papers/0701/0701157.pdf. Пока к сожалению, мой мозг взрывается при прочтении этой работы. Как осилю - обязательно сделать tl/dr.
В-третьих, "моделей консистентности" не 4, как уровней изоляции, их как минимум 7, а как максимум при конкурентном доступе, да еще и в распределенной системе все 16 (супер-полезный ресурс на эту тему http://jepsen.io/consistency. прямоугольники кликабельны!). К слову, как только в вашем клиент-сервере появляется более 1 клиента или более 1 сервера, вы скорее всего попадаете в прекрасный мир распределенных систем, т.е. да, можно принять, что моделей консистентности 16 всегда.
В-четвертых, раз уж мы попали в распределенную систему - умножай сложность на 10, а теперь представим, что у нас хранилище, которое пытается обеспечить консистентность, внутри себя также реплицируется. А реплики, конечно же, падают. И иногда поднимаются. Маленькая распределенная система, как часть большой распределенной системы. И таких мини систем внутри вашего большого продукта могут быть иногда не 1 и не 2, а пару десятков.
🔥1
От консистентности не скрыться! 2/2
Так почему же все так плохо? Да просто потому что когда дело касается консистентности, ничего нельзя знать наперед. Предположения просто не работают, когда все RDBMS имплементируют стандарт по-разному, так еще и у всех разный уровень изоляции по-умолчанию. И это мы даже не начали смотреть, что там в "BASE" хранилищах. Там все совсем интересно! Рекомендую почитать парочку работ отсюда: http://jepsen.io/analyses
Многие из них устарели, но все равно занимательно, что вот в 2013 году Cassandra при своем last-write-wins может потерять 28% данных при обновлении. Сразу начинаешь думать, что может быть не стоит конкурентно мутировать данные с такими-то гарантиями.
Я вижу только 1 путь, как совладать с этим хаосом - учить матчасть.
Используете хранилище? Обязательно изучите, какие оно предоставляет гарантии консистентности, и как их задавать. Идеально - сделайте обертку над клиентом к хранилищу, чтобы НЕ ЗАДАТЬ уровень изоляции было нельзя.
Есть возможность использовать уровни изоляции аля SQL? Во-первых, посмотрите, какая модель консистености применяется в реальности, а во-вторых, посмотрите как воспроизвести основным проблемы. Например фантомное чтение (Phantom Read), он же G2: Anti-Dependency Cycles (write skew on predicate read) из https://github.com/ept/hermitage это очень частая операция. Всякий раз когда вы в рамках транзакции сначала считываете данные и затем, в зависимости от того, что считали, делаете или не делаете INSERT/CREATE/UPDATE - вы имеете возможность словить Phantom Read.
Отдельно стоит сказать, что "транзакция" не ограничена вашим хранилищем. Например популярный паттерн "запиши в бд и отправить в
1) запись в БД успешна, но в message broker ничего не ушло.
2) Запись в БД не произошла, но в message broker попало сообщение.
Хорошие новости заключаются в том, что эту проблему можно решить. Например при помощи outbox паттерна (https://microservices.io/patterns/data/transactional-outbox.html). Плохие новости, что при решении этой проблемы, мы напарываемся еще на 1 темный лес под названием Quality of Service (QoS). Тут помимо войны с наименованиями persistence/transactional VS at least (most) once, exactly once, есть еще и разные имплементации с разным поведением. Только все еще хуже - стандарта уровня SQL-92 для систем обмена сообщениями нет. Конкретно при реализации outbox паттерн мы попадает в замечательный мир at least once QoS, а значит нам снова нужно учить матчасть и пытаться понять, как превратить at least once в exactly once (спойлер: когда-нибудь до этой темы я тоже доберусь. Пока оставлю только ссылку о том, как оно работает в JMS: https://www.researchgate.net/publication/221178564_QoS_evaluation_of_JMS_An_empirical_approach)
Так вот все немного печально с консистентностью получилось. И кажется, кроме как выкурить все мануалы, ничего сделать-то и нельзя. На последок топ ссылок из этого поста, если читать 700 страничные стандарты пока не очень хочется:
1. http://jepsen.io/consistency. О том, какие вообще есть модели консистетности. Там же ссылка на analysis - чтива хватит на несколько недель!
2. https://github.com/ept/hermitage. Как разные RDBMS имлпментируют один и тот же стандарт SQL-92.
3. Книжка, благодаря которой появился проект Hermitage. Та самая "книга с кабанчиком" http://dataintensive.net/.
Так почему же все так плохо? Да просто потому что когда дело касается консистентности, ничего нельзя знать наперед. Предположения просто не работают, когда все RDBMS имплементируют стандарт по-разному, так еще и у всех разный уровень изоляции по-умолчанию. И это мы даже не начали смотреть, что там в "BASE" хранилищах. Там все совсем интересно! Рекомендую почитать парочку работ отсюда: http://jepsen.io/analyses
Многие из них устарели, но все равно занимательно, что вот в 2013 году Cassandra при своем last-write-wins может потерять 28% данных при обновлении. Сразу начинаешь думать, что может быть не стоит конкурентно мутировать данные с такими-то гарантиями.
Я вижу только 1 путь, как совладать с этим хаосом - учить матчасть.
Используете хранилище? Обязательно изучите, какие оно предоставляет гарантии консистентности, и как их задавать. Идеально - сделайте обертку над клиентом к хранилищу, чтобы НЕ ЗАДАТЬ уровень изоляции было нельзя.
Есть возможность использовать уровни изоляции аля SQL? Во-первых, посмотрите, какая модель консистености применяется в реальности, а во-вторых, посмотрите как воспроизвести основным проблемы. Например фантомное чтение (Phantom Read), он же G2: Anti-Dependency Cycles (write skew on predicate read) из https://github.com/ept/hermitage это очень частая операция. Всякий раз когда вы в рамках транзакции сначала считываете данные и затем, в зависимости от того, что считали, делаете или не делаете INSERT/CREATE/UPDATE - вы имеете возможность словить Phantom Read.
Отдельно стоит сказать, что "транзакция" не ограничена вашим хранилищем. Например популярный паттерн "запиши в бд и отправить в
X где X - это Kafka, Redis, другая система обмена сообщениями". Здесь тоже нужно быть очень осторожным, т.к. во-первых, настройки ack на отправку сообщений могут значительно влиять на работу всей системы в случае отказов, а во-вторых, вы на самом деле пытаетесь закомитить в две несвязанные системы. В далекие бородатые времена для этого делали XA-транзакции. Но не смотря на то, что сейчас про них все забыли, проблема транзакционности никуда не делать. В зависимости от реализации и от того, в какой момент вырубят свет, при прямолинейном подходе есть два исхода:1) запись в БД успешна, но в message broker ничего не ушло.
2) Запись в БД не произошла, но в message broker попало сообщение.
Хорошие новости заключаются в том, что эту проблему можно решить. Например при помощи outbox паттерна (https://microservices.io/patterns/data/transactional-outbox.html). Плохие новости, что при решении этой проблемы, мы напарываемся еще на 1 темный лес под названием Quality of Service (QoS). Тут помимо войны с наименованиями persistence/transactional VS at least (most) once, exactly once, есть еще и разные имплементации с разным поведением. Только все еще хуже - стандарта уровня SQL-92 для систем обмена сообщениями нет. Конкретно при реализации outbox паттерн мы попадает в замечательный мир at least once QoS, а значит нам снова нужно учить матчасть и пытаться понять, как превратить at least once в exactly once (спойлер: когда-нибудь до этой темы я тоже доберусь. Пока оставлю только ссылку о том, как оно работает в JMS: https://www.researchgate.net/publication/221178564_QoS_evaluation_of_JMS_An_empirical_approach)
Так вот все немного печально с консистентностью получилось. И кажется, кроме как выкурить все мануалы, ничего сделать-то и нельзя. На последок топ ссылок из этого поста, если читать 700 страничные стандарты пока не очень хочется:
1. http://jepsen.io/consistency. О том, какие вообще есть модели консистетности. Там же ссылка на analysis - чтива хватит на несколько недель!
2. https://github.com/ept/hermitage. Как разные RDBMS имлпментируют один и тот же стандарт SQL-92.
3. Книжка, благодаря которой появился проект Hermitage. Та самая "книга с кабанчиком" http://dataintensive.net/.
🔥1
Если вам когда-то хотелось узнать, как можно повалить древнеегипетский обелиск, то вот инструкция!
https://mobile.twitter.com/indyfromspace/status/1267271817439346689
https://mobile.twitter.com/indyfromspace/status/1267271817439346689
🔥1
Сегодня команда разработки SpaceX будет на реддите рассказывать о том, как они работают. Все ещё можно написать свой вопрос. Должно быть очень интересно! 🦈
🔥1
Когда вырасту, обязательно стану секурити ресерчером! Крутейший и подробнейший лонгрид почти по всем топ 10 уязвимостям OWASP в веб сервисах Apple
https://samcurry.net/hacking-apple/
https://samcurry.net/hacking-apple/
samcurry.net
We Hacked Apple for 3 Months: Here’s What We Found
Between the period of July 6th to October 6th myself, Brett Buerhaus, Ben Sadeghipour, Samuel Erb, and Tanner Barnes worked together and hacked on the Apple bug bounty program.
🔥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.
Kontra
Application Security Training For Developers | Kontra
Kontra is an Application Security Training platform built for modern development teams.
🔥1