diff --git a/README.md b/README.md index ce1294a..fb994cd 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,8 @@ # Вопросы для собеседования на Java Developer - - -# Тут могут быть ошибки/неточности - используйте на свой страх и риск. Но буду благодарен, если укажете на косяки) - -+ [ООП](#ООП) ++ [Проектирование ПО](sd.md) ++ [ООП](#ООП) ++ [JVM](#jvm) + [Java Core](#java-core) + [Java Collections Framework](#java-collections) + [Java 8](#java-8) @@ -12,6 +10,7 @@ + [Потоки ввода-вывода в Java](#Потоки-вводавывода-в-java) + [Сериализация](#Сериализация) + [Многопоточность](#Многопоточность) ++ [Реактивное программирование](#реактивное-программирование) + [Базы данных](#Базы-данных) + [SQL](#sql) + [JDBC](#jdbc) @@ -24,9 +23,11 @@ + [Servlets, JSP, JSTL](#servlets-jsp-jstl) + [UML](#uml) + [XML](#xml) ++ [Языки разметки: XML, JSON, YAML](ml.md) + [Основы HTML](#Основы-html) + [Основы CSS](#Основы-css) + [Основы Web](#Основы-web) ++ [Apache Kafka](#apache-kafka) + [Дополнительные материалы](#Дополнительные-материалы) ## ООП @@ -52,6 +53,16 @@ [к оглавлению](#Вопросы-для-собеседования-на-java-developer) +## JVM ++ [За что отвечает JVM](jvm.md#За-что-отвечает-JVM) ++ [Classloader](jvm.md#Classloader) ++ [Области данных времени выполнения](jvm.md#Области-данных-времени-выполнения) ++ [Frames](jvm.md#Frames) ++ [Execution Engine](jvm.md#Execution-Engine) ++ [Полезные ссылки](jvm.md#Полезные-ссылки) + +[к оглавлению](#Вопросы-для-собеседования-на-java-developer) + ## Java Core + [Чем различаются JRE, JVM и JDK?](core.md#Чем-различаются-jre-jvm-и-jdk) + [Какие существуют модификаторы доступа?](core.md#Какие-существуют-модификаторы-доступа) @@ -454,6 +465,20 @@ [к оглавлению](#Вопросы-для-собеседования-на-java-developer) +## Реактивное программирование + +* [Что такое реактивное программирование и чем оно отличается от процедурного программирования?](reactive.md#что-такое-реактивное-программирование-и-чем-оно-отличается-от-процедурного-программирования) +* [Объясните концепцию потоков данных в реактивном программировании](reactive.md#объясните-концепцию-потоков-данных-в-реактивном-программировании) +* [Что такое паттерн Observer и как он лежит в основе реактивного программирования?](reactive.md#что-такое-паттерн-observer-и-как-он-лежит-в-основе-реактивного-программирования) +* [Опишите роль Observable и Observer в реактивном программировании](reactive.md#опишите-роль-observable-и-observer-в-реактивном-программировании) +* [Что такое backpressure в контексте реактивного программирования?](reactive.md#что-такое-backpressure-в-контексте-реактивного-программирования) +* [Объясните разницу между Hot и Cold Observable](reactive.md#объясните-разницу-между-hot-и-cold-observable) +* [Какова роль Подписки в реактивном программировании?](reactive.md#какова-роль-подписки-в-реактивном-программировании) +* [Как отписаться от потока для предотвращения утечки памяти?](reactive.md#как-отписаться-от-потока-для-предотвращения-утечки-памяти) +* [Какие есть операторы в Project Reactor и для чего они используются?](reactive.md#какие-есть-операторы-в-project-reactor-и-для-чего-они-используются) + +[к оглавлению](#Вопросы-для-собеседования-на-java-developer) + ## Базы данных + [Что такое _«база данных»_?](db.md#Что-такое-база-данных) + [Что такое _«система управления базами данных»_?](db.md#Что-такое-система-управления-базами-данных) @@ -855,6 +880,69 @@ [к оглавлению](#Вопросы-для-собеседования-на-java-developer) +## Apache Kafka + +* [Что такое Apache Kafka?](kafka.md#что-такое-apache-kafka) +* [Основные компоненты Kafka](kafka.md#основные-компоненты-kafka) + +**Архитектура компонентов** + +* Topic + * [Архитектура топика](kafka.md#архитектура-топика) + * [Настройки топика Kafka](kafka.md#настройки-топика-kafka) +* Broker + * [Архитектура брокера](kafka.md#архитектура-брокера) + * [Настройки брокера Kafka](kafka.md#настройки-брокера-kafka) +* Producer + * [Архитектура продюсера](kafka.md#архитектура-продюсера) + * [Настройки продюсера](kafka.md#настройки-продюсера) + * [Пример конфигурации Kafka Producer](kafka.md#пример-конфигурации-kafka-producer) +* Consumer + * [Архитектура консюмера](kafka.md#архитектура-консюмера) + * [Настройки консюмера](kafka.md#настройки-консюмера) + * [Пример конфигурации Kafka Consumer](kafka.md#пример-конфигурации-kafka-consumer) + +**Kafka API** + +* [Основные API Kafka](kafka.md#основные-api-kafka) +* [Какова роль Producer API?](kafka.md#какова-роль-producer-api) +* [Какова роль Consumer API?](kafka.md#какова-роль-consumer-api) +* [Какова роль Connector API?](kafka.md#какова-роль-connector-api) +* [Какова роль Streams API?](kafka.md#какова-роль-streams-api) +* [Какова роль Transactions API?](kafka.md#какова-роль-transactions-api) +* [Какова роль Quota API?](kafka.md#какова-роль-quota-api) +* [Какова роль AdminClient API?](kafka.md#какова-роль-AdminClient-api) + +**Kafka Consumer** + +* [Для чего нужен координатор группы?](kafka.md#для-чего-нужен-координатор-группы) +* [Для чего нужен Consumer heartbeat thread?](kafka.md#для-чего-нужен-consumer-heartbeat-thread) +* [Как Kafka обрабатывает сообщения?](kafka.md#как-kafka-обрабатывает-сообщения) +* [Как Kafka обрабатывает задержку консюмера?](kafka.md#как-kafka-обрабатывает-задержку-консюмера) +* [Для чего нужны методы subscribe() и poll()?](kafka.md#для-чего-нужны-методы-subscribe-и-poll) +* [Для чего нужен метод position()?](kafka.md#для-чего-нужен-метод-position) +* [Для чего нужны методы commitSync() и commitAsync()?](kafka.md#для-чего-нужны-методы-commitsync-и-commitasync) + +**Другие вопросы** + +* [Для чего нужен идемпотентный продюсер?](kafka.md#для-чего-нужен-идемпотентный-продюсер) +* [Для чего нужен интерфейс Partitioner?](kafka.md#для-чего-нужен-интерфейс-partitioner) +* [Для чего нужен Broker log cleaner thread?](kafka.md#для-чего-нужен-broker-log-cleaner-thread) +* [Для чего нужен Kafka Mirror Maker?](kafka.md#для-чего-нужен-kafka-mirror-maker) +* [Для чего нужна Schema Registry?](kafka.md#для-чего-нужна-schema-registry) +* [Для чего нужен Streams DSL?](kafka.md#для-чего-нужен-streams-dsl) +* [Как Kafka обеспечивает версионирование сообщений?](kafka.md#как-kafka-обеспечивает-версионирование-сообщений) +* [Как потребители получают сообщения от брокера?](kafka.md#как-потребители-получают-сообщения-от-брокера) + +**Сравнение с другими компонентами и системами** + +* [В чем разница между Kafka Consumer и Kafka Stream?](kafka.md#в-чем-разница-между-kafka-consumer-и-kafka-stream) +* [В чем разница между Kafka Streams и Apache Flink?](kafka.md#в-чем-разница-между-kafka-streams-и-apache-flink) +* [В чем разница между Kafka и Flume?](kafka.md#в-чем-разница-между-kafka-и-flume) +* [В чем разница между Kafka и RabbitMQ?](kafka.md#в-чем-разница-между-kafka-и-rabbitmq) + +[к оглавлению](#Вопросы-для-собеседования-на-java-developer) + ## Дополнительные материалы + [4 толковых канала на Youtube про технические собеседования](https://habr.com/ru/post/454264/) + [A list of fancy questions I've been asked during the interviews I had](https://github.com/d1mnewz/interviews) @@ -863,8 +951,14 @@ + [What to ask an interviewer during a tech interview](https://hackernoon.com/what-to-ask-an-interviewer-during-a-tech-interview-865a293e548c) + [Spring Boot Interview Questions](https://www.baeldung.com/spring-boot-interview-questions) + [Top Spring Framework Interview Questions](https://www.baeldung.com/spring-interview-questions) ++ [Spring Interview Questions](https://www.interviewbit.com/spring-interview-questions/) ++ [Hibernate Interview Questions](https://www.adaface.com/blog/hibernate-interview-questions/) ++ [Java Interview Questions](https://labex.io/interview-questions/java) [к оглавлению](#Вопросы-для-собеседования-на-java-developer) ## Источники + [Вопросы на собеседование Junior Java Developer](https://jsehelper.blogspot.ru) + ++ merged from [link1](https://github.com/enhorse/java-interview) last merge 17.10.2025 ++ merged from [link2](https://github.com/timmson/java-interview) last merge 17.10.2025 diff --git a/jvm.md b/jvm.md new file mode 100644 index 0000000..d6a622c --- /dev/null +++ b/jvm.md @@ -0,0 +1,677 @@ +[Вопросы для собеседования](README.md) + +# Java Virtual Machine ++ [Что такое Java?](#что-такое-java) ++ [Почему стоить использовать Java?](#почему-стоить-использовать-java) ++ [Какие основные отличия в версиях Java?](#какие-основные-отличия-в-версиях-java) ++ [Чем различаются JRE, JVM и JDK?](#чем-различаются-jre-jvm-и-jdk) ++ [За что отвечает _JVM_?](#за-что-отвечает-jvm) ++ [Расскажите про Classloader](#расскажите-про-classloader) ++ [Расскажите о Run-Time Data Area](#расскажите-о-run-time-data-area) ++ [Как рассчитать объем, который занимают объекты в памяти?](#как-рассчитать-объем-который-занимают-объекты-в-памяти) ++ [Расскажите о Frames](#расскажите-о-frames) ++ [Что такое Execution Engine?](#что-такое-execution-engine) ++ [Для чего нужен сборщик мусора?](#для-чего-нужен-сборщик-мусора) ++ [Как работает сборщик мусора?](#как-работает-сборщик-мусора) ++ [Какие разновидности сборщиков мусора реализованы в виртуальной машине HotSpot?](#какие-разновидности-сборщиков-мусора-реализованы-в-виртуальной-машине-hotspot) ++ [Опишите алгоритм работы какого-нибудь сборщика мусора реализованного в виртуальной машине HotSpot](#опишите-алгоритм-работы-какого-нибудь-сборщика-мусора-реализованного-в-виртуальной-машине-hotspot) ++ [Что такое Safepoints (применительно к HotSpot JVM)?](#что-такое-safepoints-применительно-к-hotspot-jvm) ++ [Что такое HeapDump и TreadDump?](#что-такое-heapdump-и-treaddump) ++ [Что такое профилирование?](#что-такое-профилирование) ++ [Как обнаружить причину утечки памяти (memory leak)?](#как-обнаружить-причину-утечки-памяти-memory-leak) ++ [Какие существуют рекомендации к стилю кода на Java?](#какие-существуют-рекомендации-к-стилю-кода-на-java) ++ [Какие языки (кроме Java) могут быть использованы в разработке ПО, исполняемого в среде JVM?](#какие-языки-кроме-java-могут-быть-использованы-в-разработке-по-исполняемого-в-среде-jvm) + +## Что такое Java? + +__Java__ (произноситься как "джава") — строго типизированный объектно-ориентированный язык программирования и одноимённая платформа, разработанные компанией Sun Microsystems (в последующем приобретённой компанией Oracle). Разработка ведётся сообществом, организованным через Java Community Process, язык и основные реализующие его технологии распространяются по лицензии GPL. Права на торговую марку принадлежат корпорации Oracle. + +Приложения Java обычно транслируются в специальный байт-код, поэтому они могут работать на любой компьютерной архитектуре, для которой существует реализация JVM (виртуальной Java-машины). Дата официального выпуска — 23 мая 1995 года. На текущий момент один из самых популярных языков программирования и де-факто платформа по умолчанию в разработке ПО уровня предприятия. + +Основные области применения: приложения для Android-устройств, веб-сервисы и сайты, промежуточное ПО, микропрограммы для встраиваемых систем. + +[к оглавлению](#java-virtual-machine) + +## Почему стоить использовать Java? + ++ Независимость от аппаратной архитектуры. ++ Автоматическое управление памятью. ++ Расширенные возможности обработки исключительных ситуаций. ++ Богатый набор средств фильтрации ввода-вывода. ++ Набор стандартных коллекций: массив, список, стек и т. п. ++ Наличие простых средств создания сетевых приложений (в том числе с использованием протокола RMI). ++ Наличие классов, позволяющих выполнять HTTP-запросы и обрабатывать ответы. ++ Встроенные в язык средства создания многопоточных приложений, которые потом были портированы на многие языки (например + Python). ++ Унифицированный доступ к базам данных: + + на уровне отдельных SQL-запросов — на основе JDBC, SQLJ; + + на уровне концепции объектов, обладающих способностью к хранению в базе данных — на основе Java Data Objects ( + англ.) и Java Persistence API. ++ Поддержка обобщений (начиная с версии 1.5). ++ Поддержка лямбд, замыканий, встроенные возможности функционального программирования (с 1.8) ++ Экосистема содержит громадное количество библиотек, реализующих различные протоколы, подходы и API, как открытые так и + проприетарные. + +[к оглавлению](#java-virtual-machine) + +## Какие основные отличия в версиях Java? + +##### Версия 1.0 - 23 января 1996 + +##### Версия 1.1 - 19 февраля 1997 + ++ __Inner Classes__. ++ __Reflection API__. ++ __JavaBeans__. ++ __JDBC__. ++ __Collections framework__. + +##### Версия 1.2 - 8 декабря 1998 + ++ __`strictfp` keyword__. ++ __JDBC__. + +##### Версия 1.3 - 8 мая 2000 + ++ __HotSpot VM included__. + +##### Версия 1.4 - 6 февраля 2002 + ++ __`assert` keyword__. ++ __NIO.2 library__ - API для работы с неблокирующим вводом-выводом. ++ __Logging API__. + +##### Версия 5 - 30 сентября 2004 года + ++ __Enum__ - перечислимые типы. ++ __Annotations__ - аннотации, специальные интерфейсы. ++ __Generics__ - средства обобщённого программирования. ++ __Varargs__ - методы с неопределённым числом параметров. ++ __Autoboxing/Unboxing__ — автоматическое преобразование между скалярными типами Java и соответствующими + типами-обёртками. ++ __Static import__ - импорт статических полей и методов. ++ __Foreach__ - итератор по коллекции объектов. ++ __Javadoc comments__ - Javadoc-комментариев. + +##### Версия 6 - 11 декабря 2006 года + ++ __Scripting Language Support__ - общий API для скриптовых языков и встроенный JS-движок Mozilla Rhino. ++ __JDBC 4.0__. ++ __Java Compiler API__ - возможность программного вызова java-компилятора. ++ __JAXB 2.0__. ++ __PLuggable Annotations__. ++ __@Override__ - использование аннотации для маркирования методов, реализующих интерфейс или расширяющих родительский + класс. + +##### Версия 7 - 7 июля 2011 года + ++ __InvokeDynamic__ - поддержка динамических языков программирования. ++ __Strings in switch__. - строки в switch-выражениях. ++ __The try-with-resources statement__ - автоматическое управление ресурсами, реализующими интерфейс + java.lang.AutoCloseable. ++ __Diamond operator <>__ - улучшенное вычисление типов при создании обобщенных экземпляров. ++ __Simplified varargs method declaration__ - перенос предупреждения "unsafe operation" вместо объявления метода с + переменным количеством аргументов. ++ __Binary integer literals__ - префикс _0b_ (int i = 0b0101) ++ __Underscores in numeric literals__ - подчеркивания в числах (int i = 1_000) ++ __Catching multiple exception types__ - перехват нескольких типов исключений в одном блоке catch (catch(SQLException | + IOException e)). ++ __DualPivotQuickSort__ - в качестве стандартного алгоритма для сортировки примитивов. ++ __TimSort__ - в качестве стандартного алгоритма для сортировки объектов. ++ __Concurrency utilities__ - новый синхронизатор Phaser, включён легковесный механизм fork/join. ++ __NIO.2 library__ - добавлены пакеты java.nio.file, java.nio.file.attribute и java.nio.file.spi. + +##### Версия 8 - 18 марта 2014 года + ++ __Lambda expressions__ - выражения в функциональном стиле. ++ __@FunctionalInterface__ - функциональные интерфейсы. ++ __Stream API__. - возможность выполнения последовательности операций над элементами массива, а также возможность + производить их параллельно (parallelStream). ++ __Method Reference__ - ссылки на методы и конструкторы, оператор `::`. ++ __Repeatable annotations__ - возможность использовать аннотации одного типа несколько раз над одним объектом. ++ __Interface default method__ - методы по умолчанию для интерфейсов. ++ __Annotation on Java types__ - аннотации на типы данных. ++ __Reflection for method parameters__ - рефлексия для параметров методов. ++ __Date & Time API (java.time)__ - новое api для работы с датами и временем. ++ __Remove the PermGen__ - удален _PermGen_, изменен способ хранения мета-данных классов. + +##### Версия 9 - 21 сентября 2017 года + ++ __HTTP/2 support__. ++ __Jshell__ - поддержка REPL-подхода (Read-Eval-Print-Loop) в Java. ++ __JigSaw project__ - поддержка модуляризации в Java. ++ __Stream API updates__. ++ __Immutable collevtions__ - создании и инициализация коллекций в одну строку. ++ __Concurrency updates__ - реализация Reactive Streams (в т.ч. класс `Flow`). ++ __class Optional__ - класс для сбора not-null объектов. ++ __Complete the removal of underscore from the set of legal identifier names__ - запрет подчёркивания в именах классов. ++ __Support for private methods in interfaces__- private и static private методы в интерфейсах. ++ __Compact strings__ - хранение строк в кодировке LATIN-1, если это возможно. + +##### Версия 10 - 20 марта 2018 года + ++ __Local-variable type inference__ - ключевое слово `var`, что избавляет от необходимости указывать тип локальной + переменной явно. ++ __Stream API updates__. ++ __Concurrency updates__. + +##### Версия 11 - 25 сентября 2018 года + ++ __Local-Variable Syntax for Lambda Parameters__ - ключевое слово `var` в локальных Лямбда-переменных, например при + использовании аннотаций. ++ __Launch Single-File Source-Code Programs__ - запуск приложения одной командой `java HelloWorld.java`. ++ __Remove The Java EE and CORBA Modules__ — удалены модули Java EE и COBRA. + +##### Версия 12 - 19 марта 2019 года + ++ __Switch Expressions__ - новая форма метки switch “case L ->” чтобы очевидным образом показать, что будет выполняться + только код справа от метки, если эта метка – подходящая. + +##### Версия 13 - 17 сентября 2019 года + ++ __Text Blocks__ - Использование `"""` для создания текстовых блоков без экранирования спец. символов. ++ __Reimplement the legacy Socket API__ - новая реализацию `NioSocketImpl`. Она больше не требует нативного кода, тем + самым упрощая перенос на разные платформы. + +##### Версия 14 - 17 марта 2020 года + ++ __Records__ - записи похожи на перечисления и позволяют упростить код. По сути, они заменяют классы, у которых есть + состояние, но нет поведения - есть поля, нет методов. ++ __Pattern Matching for instanceof__. ++ __Remove the Concurrent Mark Sweep (CMS) Garbage Collector__. + +[к оглавлению](#java-virtual-machine) + +## Чем различаются JRE, JVM и JDK? + +__JVM__, Java Virtual Machine (Виртуальная машина Java) — основная часть среды времени исполнения Java (JRE). +Виртуальная машина Java исполняет байт-код Java, предварительно созданный из исходного текста Java-программы +компилятором Java. JVM может также использоваться для выполнения программ, написанных на других языках программирования. + +__JRE__, Java Runtime Environment (Среда времени выполнения Java) - минимально-необходимая реализация виртуальной машины для исполнения Java-приложений. Состоит из JVM и стандартного набора библиотек классов Java. + +__JDK__, Java Development Kit (Комплект разработки на Java) - JRE и набор инструментов разработчика приложений на языке Java, включающий в себя компилятор Java, стандартные библиотеки классов Java, примеры, документацию, различные утилиты. + +Коротко: __JDK__ - среда для разработки программ на Java, включающая в себя __JRE__ - среду для обеспечения запуска Java программ, которая в свою очередь содержит __JVM__ - интерпретатор кода Java программ. + +[к оглавлению](#java-virtual-machine) + +## За что отвечает _JVM_? + ++ Загрузка, проверка и исполнение байт-кода; ++ Предоставление среды выполнения для выполнения байт-кода; ++ Управление памятью и очисткой мусора (Garbage collection); + +Виртуальная машина Java (Java Virtual Machine) - это механизм, предоставляющий среду выполнения для управления Java-кодом или приложениями. +Виртуальная машина является независимой оболочкой исполнения кода, благодаря которой возможен её запуск на любой ОС, +без влияния ОС на выполняемую программу. + +JVM работает с 2 типами данных: примитивные типы (__primitive types__) и ссылочные типы (__reference types__). + +__Примитивы__ + +JVM работает с примитивными значениями (целыми числами и числами с плавающей точкой). По сути, JVM - это 32-битная машина. +Типы `long` и `double`, которые являются 64-битными, поддерживаются изначально, но занимают две единицы памяти в `frame's local` +или стеке операндов, поскольку каждая единица составляет 32 бита. +Типы `boolean`, `byte`, `short` и `char` имеют расширенный знак (кроме `char` с нулевым расширением) и работают как 32-разрядные целые числа, так же, как и типы `int`. +Меньшие типы имеют только несколько специфических для типа инструкций для загрузки, хранения и преобразования типов. +`boolean` значение работает как 8-битное `byte` значения, где 0 представляет значение __false__, а 1 - значение __true__. + +__Типы ссылок и значения__ + +Существует три типа ссылочных типов: типы классов, типы массивов и типы интерфейсов. +Их значения являются ссылками на динамически создаваемые экземпляры классов, массивы или экземпляры классов, +которые реализуют интерфейсы соответственно. + +[к оглавлению](#java-virtual-machine) + +## Расскажите про Classloader + +Загрузчик классов является частью JRE, которая динамически загружает Java классы в JVM. +Обычно классы загружаются только по запросу. Система исполнения в Java не должна знать о файлах и файловых системах +благодаря загрузчику классов. __Делегирование является важной концепцией__, которую выполняет загрузчик. Загрузчик классов +отвечает за поиск библиотек, чтение их содержимого и загрузку классов, содержащихся в библиотеках. +Эта __загрузка__ обычно выполняется __«по требованию»__, поскольку она не происходит до тех пор, пока программа не вызовет класс. +__Класс с именем может быть загружен только один раз данным загрузчиком классов.__ + +При запуске JVM, используются три загрузчика классов: + ++ Bootstrap class loader (Загрузчик класса Bootstrap) ++ Extensions class loader (Загрузчик класса расширений) ++ System class loader (Системный загрузчик классов) + +__Загрузчик класса Bootstrap__ загружает основные библиотеки Java, расположенные в папке `/jre/lib`. +Этот загрузчик является частью ядра JVM, написан на нативном коде. + +__Загрузчик класса расширений__ загружает код в каталоги расширений +(`/jre/lib/ext`, или любой другой каталог, указанный системным свойством `java.ext.dirs`). + +__Системный загрузчик__ загружает код, найденный в `java.class.path`, который сопоставляется с переменной среды `CLASSPATH`. +Это реализуется классом `sun.misc.Launcher$AppClassLoader`. + +Загрузчик классов выполняет три основных действия в строгом порядке: + ++ Загрузка: находит и импортирует двоичные данные для типа. ++ Связывание: выполняет проверку, подготовку и (необязательно) разрешение. + + Проверка: обеспечивает правильность импортируемого типа. + + Подготовка: выделяет память для переменных класса и инициализация памяти значениями по умолчанию. + + Разрешение: преобразует символические ссылки из типа в прямые ссылки. ++ Инициализация: вызывает код Java, который инициализирует переменные класса их правильными начальными значениями. + +__Пользовательский загрузчик классов__ + +Загрузчик классов написан на Java. Поэтому возможно создать свой собственный загрузчик классов, не понимая тонких деталей JVM. +У каждого загрузчика классов Java есть родительский загрузчик классов, определенный при создании экземпляра нового +загрузчика классов или в качестве системного загрузчика классов по умолчанию для виртуальной машины. + +Что делает возможным следующее: + ++ загружать или выгружать классы во время выполнения (например, динамически загружать библиотеки во время выполнения, + даже из ресурса HTTP). + Это важная особенность для: + + реализация скриптовых языков; + + использование bean builders; + + добавить пользовательскую расширение; + + позволяя нескольким пространствам имен общаться. Например, это одна из основ протоколов CORBA / RMI; ++ изменить способ загрузки байт-кода (например, можно использовать зашифрованный байт-код класса Java); ++ модифицировать загруженный байт-код (например, для переплетения аспектов во время загрузки при использовании + аспектно-ориентированного программирования); + +[к оглавлению](#java-virtual-machine) + +## Расскажите о Run-Time Data Area + +Run-Time Data Areas. JVM выделяет множество областей данных во время выполнения, которые используются во время выполнения программы. Некоторые участки данных +созданы JVM во время старта и уничтожаются во время её выключения. Другие создаются для каждого потока и уничтожаются, когда поток уничтожается. + +__The pc Register (PCR)__ + +Виртуальная машина Java может поддерживать много потоков исполнения одновременно. Каждый поток виртуальной машины Java имеет свой собственный регистр PC (programm counter). +В любой момент каждый поток виртуальной машины Java выполняет код одного метода, а именно текущий метод для этого потока. +Если этот метод не является native, регистр pc содержит адрес инструкции виртуальной машины Java, выполняемой в настоящее время. + +Коротко говоря: для одного потока существует один PCR, который создается при запуске потока. PCR хранит адрес выполняемой сейчас инструкции JVM. + +__Java Virtual Machine Stacks__ + +Каждый поток в JVM имеет собственный стек, созданный одновременно с потоком. Стек в JVM хранит frames. +Стеки в JVM могут иметь фиксированный размер или динамически расширяться и сжиматься в соответствии с требованиями вычислений. + +__Heap__ + +JVM имеет heap (кучу), которая используется всеми потоками виртуальной машины Java. +Куча - это область данных времени выполнения, из которой выделяется память для всех экземпляров и массивов классов. +Куча создается при запуске виртуальной машины. Хранилище для объектов восстанавливается автоматической системой +управления данными (известной как сборщик мусора); объекты никогда не освобождаются явно. +JVM не предполагает какого-либо конкретного типа системы автоматического управления хранением данных, +и метод управления может быть выбран в соответствии с системными требованиями разработчика. +Куча может иметь фиксированный размер или может быть расширена в соответствии с требованиями вычислений и может быть сокращена, +если большая куча становится ненужной. Память для кучи не должна быть смежной. + +__Method Area__ + +JVM имеет область методов, которая является общей для всех потоков. Она хранит структуры для каждого класса, такие как пул констант, данные полей и методов, +а также код для методов и конструкторов, включая специальные методы, используемые при инициализации классов и экземпляров, и инициализации интерфейса. +Хотя область метода является логически частью кучи, простые реализации могут не обрабатываться сборщиком мусора. Область метода может иметь +фиксированный размер или может быть расширена в соответствии с требованиями вычислений и может быть сокращена, если большая область метода становится ненужной. + +__Run-Time Constant Pool__ + + A run-time constant pool существует для каждого класса или интерфейса в рантайме и представлено constant_pool таблицей в *.class файле. + Он содержит несколько видов констант: от числовых литералов, известных во время компиляции, до ссылок на методы и поля, + которые должны быть разрешены во время выполнения. Сам run-time constant pool выполняет функцию, + аналогичную функции таблицы символов для обычного языка программирования, хотя он содержит более широкий диапазон данных, чем типичная таблица символов. + Каждый run-time constant pool отделён от JVM's method area. JVM создаёт run-time constant pool вместе с созданием class или interface. + +__Native Method Stacks__ + +Реализация виртуальной машины Java может использовать обычные стеки, обычно называемые «стеки Си», для поддержки native methods (методов, написанных на языке, отличном от языка программирования Java). + +[к оглавлению](#java-virtual-machine) + +## Как рассчитать объем, который занимают объекты в памяти? + +Заголовок объекта занимает 12 байт: + +| Название | Размер, байт | Описание | +|---------------------|--------------|-----------------------------------------------| +| Class pointer | 4 | Ссылка на описание класса | +| Mark word | 8 | Набор флагов, описывающих состояние объекта | + +Пример приведен для x32 или x64 систем c размером Heap меньше 32 Гбайт и включенной `-XX:UseCompressedOops`. Иначе размер ссылки буде 8 байт. Также в структуре объекта есть поля. Размер объекта выравнивается по 8 байт. + +Пример: + ++ `new Integer()` - 12 байт (заголовок) + 4 байта (int) = 16 байт ++ `new Long()` - 12 байт (заголовок) + 8 байта (long) + 4 байта (выравнивание) = 24 байта ++ `new int[N]` - 12 байт (заголовок) + 4 байта (поле размер) + N *4 байта (значения) = 16 + N* 4 байт ++ `new byte[N]` - 12 байт (заголовок) + 4 байта (поле размер) + N *1 байта (значения) = 16 + N* 1 байт ++ `new Integer[N]` - 12 байт (заголовок) + 4 байта (поле размер) + N *4 байта (ссылки на значения) + N* 16 байт ( + значения) = 16 + N * 20 байт ++ `new String()` - 12 байт (заголовок) + 4 байта (ссылка на массив byte[]) + 4 байта (hash) + 1 байт (coder) + 3 байта ( + выравнивание) = 24 байта + +Размер объектов в можно узнать, воспользовавшись утилитой `Java Object Layout`. + +[к оглавлению](#java-virtual-machine) + +## Расскажите о Frames + +Frame используется для хранения данных и частичных результатов, а также для выполнения динамического связывания, возврата значений для методов и отправки исключений. +Новый frame создается каждый раз, когда вызывается метод. Frame уничтожается, когда завершается вызов метода, +является ли это завершение нормальным или резким (он генерирует неперехваченное исключение). Frames выделяются из стека потока, создающего frame. +Каждый frame имеет свой собственный массив локальных переменных, свой собственный стек операндов и ссылку на пул констант во время выполнения класса текущего метода. +Размеры массива локальных переменных и стека операндов определяются во время компиляции и предоставляются вместе с кодом для метода, связанного с фреймом. +Таким образом, размер структуры данных frame-а зависит только от реализации виртуальной машины Java, и память для этих структур может быть выделена одновременно при вызове метода. + +Только один frame активен в любой точке данного потока управления - метода выполнения, и это frame называется текущим, а его метод известен как текущий метод. +Класс, в котором определен текущий метод, является текущим классом. Операции над локальными переменными и стеком операндов обычно выполняются со ссылкой на текущий frame. + +Frame перестает быть текущим, если его метод вызывает другой метод или если его метод завершается. Когда метод вызывается, новый frame создается и становится текущим, +когда управление переходит к новому методу. При возврате метода текущий frame передает результат вызова метода, если таковой имеется, в предыдущий frame. +Текущий frame затем отбрасывается, так как предыдущий frame становится текущим. Обратите внимание, что frame, созданный потоком, +является локальным для этого потока и на него не может ссылаться ни один другой поток. + +__Локальные переменные__ + +Каждый frame содержит массив переменных, известных как его локальные переменные. Длина массива локальных переменных frame определяется во время компиляции +и предоставляется в двоичном представлении класса или интерфейса вместе с кодом для метода, связанного с frame-ом. +Единичная локальная переменная может хранить значение типа: boolean, byte, char, short, int, float, reference, or returnAddress. +Пара локальных переменных может хранить значение типов: long или double. + +Локальные переменные адресуются путем индексации. Индекс первой локальной переменной равен нулю. + +Значение типа long или типа double занимает две последовательные локальные переменные. + +JVM использует локальные переменные для передачи параметров при вызове метода. При вызове метода класса все параметры передаются в последовательных локальных переменных, +начиная с локальной переменной 0. При вызове метода экземпляра локальная переменная 0 всегда используется для передачи ссылки на объект, +для которого вызывается метод экземпляра (this в Java). Любые параметры впоследствии передаются в последовательных локальных переменных, начиная с локальной переменной 1. + +__Стеки операндов (Operand Stacks)__ + +Каждый frame содержит стек «последний вошел - первый вышел» (LIFO), известный как стек операндов. Максимальная глубина стека операндов frame-a +определяется во время компиляции и предоставляется вместе с кодом для метода, связанного с frame-ом. + +Стек операнда пуст при создании frame-a, который его содержит. JVM предоставляет инструкции для загрузки констант +или значений из локальных переменных или полей в стек операндов. Другие инструкции JVM берут операнды из стека операндов, +оперируют с ними и помещают результат обратно в стек операндов. Стек операндов также используется для подготовки параметров +для передачи в методы и для получения результатов метода. + +Для примера, инструкция __iadd__ суммирует два int значения. От стека операндов требуется, чтобы два int значения были наверху стека. +Значения удаляются из стека, операция __pop__. Суммируются и их сумма помещается в стек операндов. + +__Динамическое связывание (Dynamic Linking)__ + +Каждый frame содержит ссылку на run-time constant pool для типа текущего метода для поддержки динамического связывания кода метода. +Доступ к вызываемым методам и переменным осуществляется через символические ссылки из class файла. +Динамическое связывание преобразует эти символьные ссылки на методы в конкретные ссылки на методы, загружая классы по мере необходимости +для разрешения пока еще не определенных символов, и преобразует обращения к переменным в соответствующие смещения в структурах хранения, +связанных с расположением этих переменных во время выполнения. + +Позднее связывание методов и переменных вносит изменения в другие классы, которые метод использует с меньшей вероятностью нарушить этот код. + +__Нормальное завершение вызова метода__ + +Вызов метода завершается нормально, если этот вызов не вызывает исключение, либо непосредственно из JVM, либо в результате выполнения явного оператора throw. +Если вызов текущего метода завершается нормально, то значение может быть возвращено вызывающему методу. +Это происходит, когда вызванный метод выполняет одну из инструкций возврата, выбор которых должен соответствовать типу возвращаемого значения (если оно есть). + +Текущий frame используется в этом случае для восстановления состояния инициатора, включая его локальные переменные и стек операндов, +с соответствующим образом увеличенным программным счетчиком инициатора, чтобы пропустить инструкцию вызова метода. +Затем выполнение обычно продолжается в frame вызывающего метода с возвращенным значением (если оно есть), помещаемым в стек операндов этого frame. + +__Резкое завершение вызова метода__ + +Вызов метода завершается преждевременно, если при выполнении инструкции JVM в методе выдает исключение, и это исключение не обрабатывается в методе. +Выполнение команды __athrow__ также приводит к явному выбрасыванию исключения, и если исключение не перехватывается текущим методом, +приводит к неожиданному завершению вызова метода. Вызов метода, который завершается внезапно, никогда не возвращает значение своему вызывающему. + +[к оглавлению](#java-virtual-machine) + +## Что такое Execution Engine? + +Байт-код, назначенный __run-time data areas__, будет выполнен __execution engine__. Механизм выполнения считывает байт-код и выполняет его по частям. + +__Interpreter__ + +Интерпретатор интерпретирует байт-код быстро, но выполняется медленно. Недостаток интерпретатора заключается в том, что когда один метод вызывается несколько раз, каждый раз требуется новая интерпретация. + +__JIT Compiler__ + +JIT-компилятор устраняет недостатки интерпретатора. Механизм выполнения будет использовать помощь интерпретатора при преобразовании байт-кода, +но когда он находит повторный код, он использует JIT-компилятор, который компилирует весь байт-код и изменяет его на собственный код. +Этот нативный код будет использоваться непосредственно для повторных вызовов методов, которые улучшают производительность системы. + ++ Генератор промежуточного кода (Intermediate Code Generator). Производит промежуточный код. ++ Code Optimizer. Отвечает за оптимизацию промежуточного кода, сгенерированного выше. ++ Генератор целевого кода (Target Code Generator). Отвечает за генерацию машинного кода или родной код. ++ Профилировщик (Profiler). Специальный компонент, отвечающий за поиск горячих точек, то есть, вызывается ли метод несколько раз или нет. + +__Garbage Collector__ +Garbage Collector ("сборщик мусора") функционирует в фоновом режиме во время работы твоей программы, собирает ставшие ненужными объекты, которые в дальнейшем будут удалены. Таким образом, он освобождает память для создания новых объектов в будущем. На самом деле сборщик мусора не один, а несколько. + +[к оглавлению](#java-virtual-machine) + +## Для чего нужен сборщик мусора? + +Сборщик мусора (Garbage Collector) должен делать всего две вещи: + ++ Находить мусор - неиспользуемые объекты. (Объект считается неиспользуемым, если ни одна из сущностей в коде, выполняемом в данный момент, не содержит ссылок на него, либо цепочка ссылок, которая могла бы связать объект с некоторой сущностью приложения, обрывается); ++ Освобождать память от мусора. + +Существует два подхода к обнаружению мусора: + ++ _Reference counting_; ++ _Tracing_ + +__Reference counting__ (подсчёт ссылок). Суть этого подхода состоит в том, что каждый объект имеет счетчик. Счетчик хранит информацию о том, сколько ссылок указывает на объект. Когда ссылка уничтожается, счетчик уменьшается. Если значение счетчика равно нулю, - объект можно считать мусором. Главным минусом такого подхода является сложность обеспечения точности счетчика. Также при таком подходе сложно выявлять циклические зависимости (когда два объекта указывают друг на друга, но ни один живой объект на них не ссылается), что приводит к утечкам памяти. + +Главная идея подхода __Tracing__ (трассировка) состоит в утверждении, что живыми могут считаться только те объекты, до которых мы можем добраться из корневых точек (_GC Root_) или других с живых объектов. Всё остальное - мусор. + +Существует 4 типа корневых точки: + ++ Локальные переменные и параметры методов; ++ Потоки; ++ Статические переменные; ++ Ссылки из JNI. + +Самое простое java приложение будет иметь корневые точки: + ++ Локальные переменные внутри `main()` метода и параметры `main()` метода; ++ Поток, который выполняет `main()`; ++ Статические переменные класса, внутри которого находится `main()` метод. + +Таким образом, если мы представим все объекты и ссылки между ними как дерево, то нам нужно будет пройти с корневых узлов (точек) по всем рёбрам. При этом узлы, до которых мы сможем добраться - не мусор, все остальные - мусор. При таком подходе циклические зависимости легко выявляются. HotSpot VM использует именно такой подход. + +--- +Для очистки памяти от мусора существуют два основных метода: + ++ _Copying collectors_ ++ _Mark-and-sweep_ + +При __copying collectors__ подходе память делится на две части «from-space» и «to-space», при этом сам принцип работы такой: + ++ Объекты создаются в «from-space»; ++ Когда «from-space» заполняется, приложение приостанавливается; ++ Запускается сборщик мусора. Находятся живые объекты в «from-space» и копируются в «to-space»; ++ Когда все объекты скопированы «from-space» полностью очищается; ++ «to-space» и «from-space» меняются местами. + +Главный плюс такого подхода в том, что объекты плотно забивают память. Минусы подхода: + +1. Приложение должно быть остановлено на время, необходимое для полного прохождения цикла сборки мусора; +2. В худшем случае (когда все объекты живые) «form-space» и «to-space» будут обязаны быть одинакового размера. + +Алгоритм работы __mark-and-sweep__ можно описать так: + ++ Объекты создаются в памяти; ++ В момент, когда нужно запустить сборщик мусора приложение приостанавливается; ++ Сборщик проходится по дереву объектов, помечая живые объекты; ++ Сборщик проходится по всей памяти, находя все не отмеченные куски памяти и сохраняя их в «free list»; ++ Когда новые объекты начинают создаваться они создаются в памяти доступной во «free list». + +Минусы этого способа: + +1. Приложение не работает, пока происходит сборка мусора; +2. Время остановки напрямую зависит от размеров памяти и количества объектов; +3. Если не использовать «compacting», то память будет использоваться не эффективно. + +Сборщики мусора HotSpot VM используют комбинированный подход __Generational Garbage Collection__, который позволяет использовать разные алгоритмы для разных этапов сборки мусора. Этот подход опирается на том, что: + ++ большинство создаваемых объектов быстро становятся мусором; ++ существует мало связей между объектами, которые были созданы в прошлом и только что созданными объектами. + +[к оглавлению](#java-virtual-machine) + +## Как работает сборщик мусора? + +Механизм сборки мусора - это процесс освобождения места в куче, для возможности добавления новых объектов. + +Объекты создаются посредством оператора `new`, тем самым присваивая объекту ссылку. Для окончания работы с объектом достаточно просто перестать на него ссылаться, например присвоив переменной ссылку на другой объект или значение `null`; прекратить выполнение метода, чтобы его локальные переменные завершили свое существование естественным образом. Объекты, на которые отсутствуют ссылки, принято называть мусором (_garbage_). + +Виртуальная машина Java, применяя механизм сборки мусора, гарантирует, что любой объект, обладающий ссылками, остается в памяти — все объекты, которые недостижимы из исполняемого кода, ввиду отсутствия ссылок на них, удаляются с высвобождением отведенной для них памяти. Точнее говоря, объект не попадает в сферу действия процесса сборки мусора, если он достижим посредством цепочки ссылок, начиная с корневой (_GC Root_) ссылки, т.е. ссылки, непосредственно существующей в выполняемом коде. + +Память освобождается сборщиком мусора по его собственному «усмотрению». Программа может успешно завершить работу, не исчерпав ресурсов свободной памяти или даже не приблизившись к этой черте и поэтому ей так и не потребуются «услуги» сборщика мусора. + +Мусор собирается системой автоматически, без вмешательства пользователя или программиста, но это не значит, что этот процесс не требует внимания вовсе. Необходимость создания и удаления большого количества объектов существенным образом сказывается на производительности приложений и если быстродействие программы является важным фактором, следует тщательно обдумывать решения, связанные с созданием объектов, — это, в свою очередь, уменьшит и объем мусора, подлежащего утилизации. + +[к оглавлению](#java-virtual-machine) + +## Какие разновидности сборщиков мусора реализованы в виртуальной машине HotSpot? + +Java HotSpot VM предоставляет разработчикам на выбор четыре различных сборщика мусора: + ++ __Serial (последовательный)__ — самый простой вариант для приложений с небольшим объемом данных и не требовательных к + задержкам. На данный момент используется сравнительно редко, но на слабых компьютерах может быть выбран виртуальной + машиной в качестве сборщика по умолчанию. Использование Serial GC включается опцией `-XX:+UseSerialGC`. ++ __Parallel (параллельный)__ — наследует подходы к сборке от последовательного сборщика, но добавляет параллелизм в + некоторые операции, а также возможности по автоматической подстройке под требуемые параметры производительности. + Параллельный сборщик включается опцией `-XX:+UseParallelGC`. ++ __Concurrent Mark Sweep (CMS)__ — нацелен на снижение максимальных задержек путем выполнения части работ по сборке + мусора параллельно с основными потоками приложения. Подходит для работы с относительно большими объемами данных в + памяти. Использование CMS GC включается опцией `-XX:+UseConcMarkSweepGC`. ++ __Garbage-First (G1)__ — создан для замены CMS, особенно в серверных приложениях, работающих на многопроцессорных + серверах и оперирующих большими объемами данных. _G1_ включается опцией Java `-XX:+UseG1GC`. + +[к оглавлению](#java-virtual-machine) + +## Опишите алгоритм работы какого-нибудь сборщика мусора реализованного в виртуальной машине HotSpot + +__Serial Garbage Collector (Последовательный сборщик мусора)__ был одним из первых сборщиков мусора в HotSpot VM. Во +время работы этого сборщика приложения приостанавливается и продолжает работать только после прекращение сборки мусора. + +Память приложения делится на три пространства: + ++ _Young generation_. Объекты создаются именно в этом участке памяти. ++ _Old generation_. В этот участок памяти перемещаются объекты, которые переживают «minor garbage collection». ++ _Permanent generation_. Тут хранятся метаданные об объектах, _Class data sharing (CDS)_, _пул строк (String pool)_. + Permanent область делится на две: только для чтения и для чтения-записи. Очевидно, что в этом случае область только + для чтения не чистится сборщиком мусора никогда. В Java 8 и выше отсутствует, пул строке переехал в основную память, + метаданные в нативную память JVM. + +Область памяти Young generation состоит из трёх областей: _Eden_ и двух меньших по размеру _Survivor spaces_ - _To +space_ и _From space_. Большинство объектов создаются в области Eden, за исключением очень больших объектов, которые не +могут быть размещены в ней и поэтому сразу размещаются в Old generation. В Survivor spaces перемещаются объекты, которые +пережили по крайней мере одну сборку мусора, но ещё не достигли порога «старости» (_tenuring threshold_), чтобы быть +перемещенными в Old generation. + +Когда Young generation заполняется, то в этой области запускается процесс лёгкой сборки (_minor collection_), в отличие от процесса сборки, проводимого над всей кучей (_full collection_). Он происходит следующим образом: в начале работы одно из Survivor spaces - To space, является пустым, а другое - From space, содержит объекты, пережившие предыдущие сборки. Сборщик мусора ищет живые объекты в Eden и копирует их в To space, а затем копирует туда же и живые «молодые» (то есть не пережившие еще заданное число сборок мусора) объекты из From space. Старые объекты из From space перемещаются в Old generation. После лёгкой сборки From space и To space меняются ролями, область Eden становится пустой, а число объектов в Old generation увеличивается. + +Если в процессе копирования живых объектов To space переполняется, то оставшиеся живые объекты из Eden и From space, которым не хватило места в To space, будут перемещены в Old generation, независимо от того, сколько сборок мусора они пережили. + +Поскольку при использовании этого алгоритма сборщик мусора просто копирует все живые объекты из одной области памяти в другую, то такой сборщик мусора называется _copying_ (копирующий). Очевидно, что для работы копирующего сборщика мусора у приложения всегда должна быть свободная область памяти, в которую будут копироваться живые объекты, и такой алгоритм может применяться для областей памяти сравнительно небольших по отношению к общему размеру памяти приложения. Young generation как раз удовлетворяет этому условию (по умолчанию на машинах клиентского типа эта область занимает около 10% кучи (значение может варьироваться в зависимости от платформы)). + +Однако для сборки мусора в Old generation, занимающем большую часть всей памяти, используется другой алгоритм. + +В Old generation сборка мусора происходит с использованием алгоритма _mark-sweep-compact_, который состоит из трёх фаз. В фазе _Mark_ (пометка) сборщик мусора помечает все живые объекты, затем, в фазе _Sweep_ (очистка) все не помеченные объекты удаляются, а в фазе _Compact_ (уплотнение) все живые объекты перемещаются в начало Old generation, в результате чего свободная память после очистки представляет собой непрерывную область. Фаза уплотнения выполняется для того, чтобы избежать фрагментации и упростить процесс выделения памяти в Old generation. + +Когда свободная память представляет собой непрерывную область, то для выделения памяти под создаваемый объект можно использовать очень быстрый (около десятка машинных инструкций) алгоритм _bump-the-pointer_: адрес начала свободной памяти хранится в специальном указателе, и когда поступает запрос на создание нового объекта, код проверяет, что для нового объекта достаточно места, и, если это так, то просто увеличивает указатель на размер объекта. + +Последовательный сборщик мусора отлично подходит для большинства приложений, использующих до 200 мегабайт кучи, работающих на машинах клиентского типа и не предъявляющих жёстких требований к величине пауз, затрачиваемых на сборку мусора. В то же время модель «stop-the-world» может вызвать длительные паузы в работе приложения при использовании больших объёмов памяти. Кроме того, последовательный алгоритм работы не позволяет оптимально использовать вычислительные ресурсы компьютера и последовательный сборщик мусора может стать узким местом при работе приложения на многопроцессорных машинах. + +[к оглавлению](#java-virtual-machine) + +## Что такое Safepoints (применительно к HotSpot JVM)? + +В HotSpot JVM механизм паузы «stop-the-world» называется __safepoint__. Во время safepoint все потоки, исполняющие java-код приостанавливаются. Потоки, исполняющие нативный код, могут продолжать работать пока, не будут прерваны JVM (попытка доступа к объектам Java через JNI, вызов метода Java или возврат из нативного кода в Java приостановит поток до конца safepoint). Остановка всех потоков необходима, чтобы убедиться, что safepoint-инициатор имеет эксклюзивный доступ к структурам данных JVM и может делать всё что угодно, например перемещение объектов в куче или замена кода метода, который в настоящее время выполняется (перемещение в стеке). + +__Как работают safepoints?__ +Протокол Safepoint в HotSpot JVM является общим. Каждый поток приложения проверяет статус safepoint и паркуется в безопасном состоянии в этой точке. Для скомпилированного кода JIT вставляет в код проверки safepoint в определенных точках (обычно после возврата вызовов или при обратном переходе цикла). Для интерпретируемого кода JVM имеет две таблицы диспетчеризации байт-кода, и если требуется safepoint, JVM переключает таблицы, чтобы включить его проверку. + +Сама проверка статуса Safepoint реализована очень нетривиально. Обычная проверка переменных памяти потребует дорогостоящих барьеров памяти. Хотя проверка safepoints реализована через барьер. Затем требуется безопасная точка, JVM отключает отображение страницы с этим адресом, вызывая сбой страницы в потоке приложения (который обрабатывается обработчиком JVM). Таким образом, HotSpot поддерживает свой JITed-код, совместимый с конвейером процессора, но при этом обеспечивает правильную семантику памяти (unmap страницы создает барьер памяти для ядер обработки). + +__Когда safepoint используется?__ + ++ Пауза GC ++ Деоптимизация кода ++ Flushing code cache ++ Class redefinition (e.g. hot swap or instrumentation) ++ Biased lock revocation ++ Various debug operation (e.g. deadlock check or stacktrace dump) + +Источник: [http://blog.ragozin.info/2012/10/safepoints-in-hotspot-jvm.html](http://blog.ragozin.info/2012/10/safepoints-in-hotspot-jvm.html) + +[к оглавлению](#java-virtual-machine) + +## Что такое HeapDump и TreadDump? + +__HeapDump__ - снимок текущей памяти, позволяет разобраться в потребление памяти, например, при её утечке. + +__ThreadDump__ - снимок стеков всех поток, позволяет разбираться в проблемах многопоточности, например, находить взаимные блокировки. + +[к оглавлению](#java-virtual-machine) + +## Что такое профилирование? + +__Профилирование__ — сбор характеристик работы программы, таких как время выполнения отдельных фрагментов (обычно подпрограмм), число верно предсказанных условных переходов, число кэш-промахов и т. д. Инструмент, используемый для анализа работы, называют профилировщиком или профайлером (англ. profiler). Обычно выполняется совместно с оптимизацией программы. + +__Профилировщики__ - программы, производящие профилирование, делятся на 2 типа: + ++ _Инструментирующие_ - модифицируют программный код, оказывают значительное влияние н производительность. ++ _Сэмплирующие_ - не влияют напрямую на исполняемый код. + +[к оглавлению](#java-virtual-machine) + +## Как обнаружить причину утечки памяти (memory leak)? + +Как правило, следствием утечки памяти становится замедление приложения и/или появление `OutOfMemoryError: xxx`. + +Что может быть причиной: + ++ __Неверно сконфигурированная JVM__ - удалите все ключи jvm, и попробуйте воспроизвести проблему. ++ __Объективная нехватка памяти__ - добавьте ее в Heap (`-Xmx` / `-Xms`) и PermGen (`-XX:PermSize` / `-XX:MaxPermSize`) для версий Java 7 и ниже. ++ __Утечка в загрузчике классов (class loader)__ - ограничьте Metaspace `-XX:MaxMetaSpaceSize={unlimited}` для версий Java 8 и выше, чтобы ограничить потребление физической памяти и локализовать проблему. ++ __Ошибки проектирования__ - незакрытые потоки ввод-вывода, зависшие потоки (threads), ... + +Рекомендации по диагностированию: + ++ __Утилиты VisaulVM, MissonControl, jstat, jmap__ - для анализа состояния JVM в моменте. ++ __Включение GC-логов__ - `-XX:PrintGCDetails` и других. Их можно анализировать с помощью GCLogAnalyzer или GCViewer. ++ __Включение создания дампа памяти при ошибке `OutOfMememoryError: xxx`__ `- XX:HeadDumpOnOutOfMemoryError` и `-XX:HeapDumpPath=`. Анализ дампа можно производить с помощью Memory Analyzer (MAT). + +[к оглавлению](#java-virtual-machine) + +## Какие существуют рекомендации к стилю кода на Java? + +Рекомендации к стилю кода отражены в документе __Java Code Conventions__. + +[к оглавлению](#java-virtual-machine) + +## Какие языки (кроме Java) могут быть использованы в разработке ПО, исполняемого в среде JVM? + +_Компилируемые в байт-код Java_: +_Scala_ — объектно-ориентированный и функциональный язык; +_Kotlin_ — объектно-ориентированный язык, используется, в том числе для разработки Android-приложений; +_Clojure_ — функциональный язык, диалект Lisp; +_Ceylon_ — объектно-ориентированный язык со строгой статической типизацией. + +__Интерпретируемые__: +_Jacl_ - реализация TCL; +_Jython_ — реализация Python; +_JRuby_ — реализация Ruby; +_Groovy_ — сценарный язык; +_Nashorn_ — реализация JavaScript. + +[к оглавлению](#java-virtual-machine) + +[Вопросы для собеседования](README.md) diff --git a/kafka.md b/kafka.md new file mode 100644 index 0000000..c579cbf --- /dev/null +++ b/kafka.md @@ -0,0 +1,1420 @@ +[Вопросы для собеседования](README.md) + +# Apache Kafka +* [Что такое Apache Kafka?](#что-такое-apache-kafka) +* [Основные компоненты Kafka](#основные-компоненты-kafka) + +**Архитектура компонентов** + +* Topic + * [Архитектура топика](#архитектура-топика) + * [Настройки топика Kafka](#настройки-топика-kafka) +* Broker + * [Архитектура брокера](#архитектура-брокера) + * [Настройки брокера Kafka](#настройки-брокера-kafka) +* Producer + * [Архитектура продюсера](#архитектура-продюсера) + * [Настройки продюсера](#настройки-продюсера) + * [Пример конфигурации Kafka Producer](#пример-конфигурации-kafka-producer) +* Consumer + * [Архитектура консюмера](#архитектура-консюмера) + * [Настройки консюмера](#настройки-консюмера) + * [Пример конфигурации Kafka Consumer](#пример-конфигурации-kafka-consumer) + +**Kafka API** + +* [Основные API Kafka](#основные-api-kafka) +* [Какова роль Producer API?](#какова-роль-producer-api) +* [Какова роль Consumer API?](#какова-роль-consumer-api) +* [Какова роль Connector API?](#какова-роль-connector-api) +* [Какова роль Streams API?](#какова-роль-streams-api) +* [Какова роль Transactions API?](#какова-роль-transactions-api) +* [Какова роль Quota API?](#какова-роль-quota-api) +* [Какова роль AdminClient API?](#какова-роль-AdminClient-api) + +**Kafka Consumer** + +* [Для чего нужен координатор группы?](#для-чего-нужен-координатор-группы) +* [Для чего нужен Consumer heartbeat thread?](#для-чего-нужен-consumer-heartbeat-thread) +* [Как Kafka обрабатывает сообщения?](#как-kafka-обрабатывает-сообщения) +* [Как Kafka обрабатывает задержку консюмера?](#как-kafka-обрабатывает-задержку-консюмера) +* [Для чего нужны методы subscribe() и poll()?](#для-чего-нужны-методы-subscribe-и-poll) +* [Для чего нужен метод position()?](#для-чего-нужен-метод-position) +* [Для чего нужны методы commitSync() и commitAsync()?](#для-чего-нужны-методы-commitsync-и-commitasync) + +**Другие вопросы** + +* [Для чего нужен идемпотентный продюсер?](#для-чего-нужен-идемпотентный-продюсер) +* [Для чего нужен интерфейс Partitioner?](#для-чего-нужен-интерфейс-partitioner) +* [Для чего нужен Broker log cleaner thread?](#для-чего-нужен-broker-log-cleaner-thread) +* [Для чего нужен Kafka Mirror Maker?](#для-чего-нужен-kafka-mirror-maker) +* [Для чего нужна Schema Registry?](#для-чего-нужна-schema-registry) +* [Для чего нужен Streams DSL?](#для-чего-нужен-streams-dsl) +* [Как Kafka обеспечивает версионирование сообщений?](#как-kafka-обеспечивает-версионирование-сообщений) +* [Как потребители получают сообщения от брокера?](#как-потребители-получают-сообщения-от-брокера) + +**Сравнение с другими компонентами и системами** + +* [В чем разница между Kafka Consumer и Kafka Stream?](#в-чем-разница-между-kafka-consumer-и-kafka-stream) +* [В чем разница между Kafka Streams и Apache Flink?](#в-чем-разница-между-kafka-streams-и-apache-flink) +* [В чем разница между Kafka и Flume?](#в-чем-разница-между-kafka-и-flume) +* [В чем разница между Kafka и RabbitMQ?](#в-чем-разница-между-kafka-и-rabbitmq) + + +## Что такое Apache Kafka? + +Это распределённая система с открытым исходным кодом, разработанная для высокоскоростной передачи больших объёмов данных +с минимальной задержкой. + +### Преимущества + +* Персистентность данных +* Высокая производительность +* Независимость пайплайнов обработки +* Возможность просмотреть историю записей заново +* Гибкость в использовании + +### Когда использовать + +* λ-архитектура или k-архитектура +* Стриминг больших данных +* Много клиентов (producer и consumer) +* Требуется кратное масштабирование + +### Чего в Kafka нет из коробки + +* Это не брокер сообщений +* Отложенные сообщения +* DLQ +* AMQP / MQTT +* TTL на сообщение +* Очереди с приоритетами + +[к оглавлению](#apache-kafka) + +## Основные компоненты Kafka + +* **Producer (Производитель)** — приложение, которое публикует сообщения в топики Kafka +* **Consumer (Потребитель)** — приложение, которое подписывается на топики и читает сообщения +* **Broker (Брокер)** — сервер Kafka, который принимает, хранит и распределяет сообщения. В кластере Kafka может быть несколько брокеров +* **Topic (Топик)** — логическое разделение, по которому организуются данные. Производители отправляют сообщения в топики, а потребители читают из них +* **Partition (Раздел)** — каждый топик разделён на партиции для параллельной обработки. Сообщения в партициях упорядочены +* **Zookeeper** — сервис, используемый Kafka для управления состоянием кластера и координации брокеров. +Однако в новых версиях Kafka отказывается от Zookeeper в пользу собственного механизма метаданных KRaft (Kafka Raft). +Это новая внутренняя архитектура метаданных Kafka, которая устраняет зависимость от Zookeeper. Она основана на Raft-консенсусе, +позволяя Kafka брокерам самостоятельно управлять метаданными и координировать взаимодействие между собой. + +[к оглавлению](#apache-kafka) + +## Архитектура топика + +* **Топик разбит на партиции** — сообщения в топике распределяются по партициям для более эффективной параллельной обработки и хранения +* **Партиции хранятся на диске** — Kafka сохраняет данные на диск, что позволяет долговременно хранить сообщения +* **Партиции делятся на сегменты** — сегмент представляет собой обычный файл на диске, сегменты делятся на пассивные и активный. + Запись происходит в активный сегмент +* **Данные удаляются либо по времени, либо по размеру**. Удаление происходит посегментно, с самого старого сегмента + * **retention.bytes** - по максимальному размеру + * **retention.ms** - по времени +* **Сообщение можно быстро найти по его Offset** — каждому сообщению в партиции присваивается уникальный смещающий индекс (offset), по которому можно легко найти сообщение + +[к оглавлению](#apache-kafka) + +## Настройки топика Kafka + +### Репликация + +* `replication.factor` + * **Описание**: Количество реплик для каждой партиции топика + * **Пример**: `replication.factor=3` +* `min.insync.replicas` + * **Описание**: Минимальное количество синхронизированных реплик + * **Пример**: `min.insync.replicas=2` + +### Хранение данных + +* `retention.ms` + * **Описание**: Время хранения сообщений в топике в миллисекундах + * **Пример**: `retention.ms=604800000` (7 дней) +* `retention.bytes` + * **Описание**: Максимальный объём данных в топике, после чего старые сообщения удаляются + * **Пример**: `retention.bytes=10737418240` (10 GB) +* `segment.bytes` + * **Описание**: Размер сегмента логов топика + * **Пример**: `segment.bytes=1073741824` (1 GB) + +### Политики очистки + +* `cleanup.policy` + * **Описание**: Как Kafka обрабатывает старые сообщения + * **Значения**: `delete`, `compact` + * **Пример**: `cleanup.policy=delete` + +### Партиции + +* `num.partitions` + * **Описание**: Количество партиций в топике + * **Пример**: `num.partitions=3` + +[к оглавлению](#apache-kafka) + +## Архитектура брокера + +* **У каждой партиции свой лидер** — в Kafka для каждой партиции в топике назначается лидер-брокер, который отвечает + за запись и чтение данных +* **Сообщения пишутся в лидера** — производители отправляют сообщения напрямую в брокер-лидер партиции +* **Данные реплицируются между брокерами** — для обеспечения отказоустойчивости Kafka реплицирует данные партиций на + другие брокеры, которые становятся репликами +* **Автоматический фейловер лидера** — в случае сбоя брокера-лидера Kafka автоматически назначает новый лидер из числа + реплик, обеспечивая бесшовную работу системы + +[к оглавлению](#apache-kafka) + +## Настройки брокера Kafka + +### Репликация и консистентность + +* `min.insync.replicas` + * **Описание**: Минимальное количество синхронизированных реплик для подтверждения записи + * **Пример**: `min.insync.replicas=2` +* `unclean.leader.election.enable` + * **Описание**: Разрешает выбор лидера из неактуальных реплик, если нет синхронизированных реплик + * **Пример**: `unclean.leader.election.enable=false` + +### Логирование и хранение данных + +* `log.dirs` + * **Описание**: Директория на диске, где хранятся логи партиций + * **Пример**: `log.dirs=/var/lib/kafka/logs` +* `log.retention.hours` + * **Описание**: Максимальное время хранения данных в логах + * **Пример**: `log.retention.hours=168` (7 дней) +* `log.segment.bytes` + * **Описание**: Максимальный размер сегмента лога, после чего создаётся новый + * **Пример**: `log.segment.bytes=1073741824` (1 GB) + +### Производительность и задержки + +* `num.network.threads` + * **Описание**: Количество потоков для обработки сетевых запросов + * **Пример**: `num.network.threads=3` +* `num.io.threads` + * **Описание**: Количество потоков для ввода-вывода + * **Пример**: `num.io.threads=8` +* `socket.send.buffer.bytes` + * **Описание**: Размер буфера для отправки данных по сети + * **Пример**: `socket.send.buffer.bytes=102400` + +### Управление сообщениями + +* `message.max.bytes` + * **Описание**: Максимальный размер сообщения, которое брокер может принять + * **Пример**: `message.max.bytes=1048576` (1 MB) +* `replica.fetch.max.bytes` + * **Описание**: Максимальный размер данных для запроса реплики + * **Пример**: `replica.fetch.max.bytes=1048576` (1 MB) + +### Безопасность + +* `ssl.keystore.location` + * **Описание**: Путь к хранилищу ключей SSL + * **Пример**: `ssl.keystore.location=/var/private/ssl/kafka.keystore.jks` +* `ssl.truststore.location` + * **Описание**: Путь к хранилищу доверенных сертификатов + * **Пример**: `ssl.truststore.location=/var/private/ssl/kafka.truststore.jks` + +[к оглавлению](#apache-kafka) + +## Архитектура продюсера + +* **Создание сообщения (Record)**: Продюсер формирует сообщение, содержащее ключ (необязательный), значение и метаданные, + такие как время отправки. Сообщение отправляется в топик (Topic), который состоит из одной или нескольких партиций +* **Выбор партиции**: Если ключ сообщения указан, Kafka использует его для хеширования и определения, в какую партицию + записать сообщение (сообщения с одинаковым ключом попадают в одну и ту же партицию). Если ключа нет, Kafka распределяет + сообщения по партициям с помощью round-robin или по другим правилам +* **Отправка сообщений в буфер (Batching)**: Для повышения производительности продюсер Kafka не отправляет каждое сообщение + по отдельности, а группирует несколько сообщений в пакеты (batching), прежде чем отправить их брокеру. Это снижает + сетевые задержки и нагрузку на брокера +* **Сжатие (Compression)**: Для уменьшения объёма передаваемых данных продюсер может сжимать сообщения с использованием + таких алгоритмов, как GZIP, Snappy или LZ4. Сжатие снижает нагрузку на сеть и хранение, но добавляет небольшие накладные + расходы на процессор +* **Асинхронная отправка**: Продюсер отправляет пакеты сообщений асинхронно. Это означает, что сообщения записываются в + буфер памяти и отправляются брокеру, не ожидая завершения предыдущих операций. Это повышает пропускную способность +* **Подтверждения (Acknowledgments)**: Kafka позволяет настраивать уровень подтверждений от брокеров +* **Ретрай и идемпотентность**: Если отправка сообщения не удалась, продюсер может повторить попытку отправки (ретрай). + Также можно включить идемпотентный режим продюсера, что предотвращает повторную отправку одного и того же сообщения в + случае сбоя, обеспечивая отправку уникального сообщения один раз +* **Error handling**: Продюсер обрабатывает ошибки при отправке сообщений. В зависимости от настроек продюсер может + попытаться переотправить сообщение или сообщить о проблеме через callback + +### Резюме + +* Продюсер выбирает партицию для сообщения +* Продюсер выбирает уровень гарантии доставки +* В продюсере можно тюнить производительность + +[к оглавлению](#apache-kafka) + +## Настройки продюсера + +### Bootstrap-серверы (`bootstrap.servers`) + +* **Описание**: Указывает адреса брокеров Kafka, к которым продюсер должен подключаться для отправки сообщений +* **Пример**: `bootstrap.servers: localhost:9092,localhost:9093` +* **Зачем это нужно**: Kafka продюсер использует эти брокеры для получения метаданных о кластере (например, информация о топиках и партициях). Эти брокеры служат точками входа в кластер Kafka. + +### Сериализация ключа и значения + +Продюсер должен преобразовывать (сериализовать) данные в байтовый формат перед отправкой в Kafka + +* **Ключевая настройка для сериализации ключа:** + * `key.serializer` + * Пример: `key.serializer: org.apache.kafka.common.serialization.StringSerializer` +* **Ключевая настройка для сериализации значения:** + * `value.serializer` + * Пример: `value.serializer: org.apache.kafka.common.serialization.StringSerializer` + +**Варианты сериализаторов:** +* `StringSerializer` для строк +* `ByteArraySerializer` для массива байтов +* `LongSerializer` для чисел +* Также можно реализовать свои собственные сериализаторы + +### Отправка сообщений в буфер + +Продюсер Kafka отправляет сообщения асинхронно, и для этого используется буферизация сообщений + +* **batch.size**: Размер одного пакета (batch), который продюсер отправляет брокеру + * **Описание**: Определяет количество байтов сообщений, которые могут быть буферизованы в одном пакете перед отправкой брокеру + * **Пример**: `"batch.size": 16384` (16 KB) + * **Зачем это нужно**: Большие пакеты могут повысить производительность, но могут увеличить задержки +* **linger.ms**: Максимальное время ожидания перед отправкой пакета + * **Описание**: Продюсер может немного подождать, пока буфер накопит сообщения, чтобы отправить больше данных за один раз + * **Пример**: `linger.ms: 5` (время ожидания 5 мс) + * **Зачем это нужно**: Позволяет продюсеру собирать больше сообщений в пакете перед отправкой, что может улучшить эффективность использования сети +* **buffer.memory**: Размер выделенной памяти для буферизации сообщений + * **Описание**: Общий объем памяти, который продюсер может использовать для хранения сообщений, ожидающих отправки + * **Пример**: `buffer.memory: 33554432` (32 MB) + * **Зачем это нужно**: Если буфер заполняется, продюсер приостанавливает отправку сообщений, пока буфер не освободится + +### Сжатие сообщений + +Продюсер может сжимать сообщения для уменьшения объема передаваемых данных + +* **compression.type** + * **Описание**: Указывает тип сжатия для сообщений + * **Пример**: `compression.type: gzip` (варианты: none, gzip, snappy, lz4, zstd) + * **Зачем это нужно**: Сжатие уменьшает объем данных, передаваемых по сети, что может снизить нагрузку на сеть и хранилище, + особенно при больших объемах сообщений. Однако это может потребовать дополнительных ресурсов на сжатие/разжатие + +### Распределение сообщений по партициям (партицирование) + +* **partitioner.class** + * **Описание**: определяет логику, по которой продюсер выбирает партицию для каждого сообщения + * **Примеры**: + * **если настройка не задана**, по умолчанию используется `DefaultPartitioner` , который может распределять сообщения по партициям + равномерно или на основе ключа сообщения + * `partitioner.class: o.a.k.clients.producer.RoundRobinPartitioner` использует метод Round Robin для распределения сообщений + * `partitioner.class: o.a.k.clients.producer.UniformStickyPartitioner` равномерно отправляет сообщения, привязываясь + к партиции на короткий промежуток времени, чтобы уменьшить нагрузку на брокеры + +### Подтверждения (acks) + +Настройка определяет, как много брокеров должны подтвердить получение сообщения перед тем, как продюсер будет считать его +успешно отправленным + +* **acks** + * **Описание**: Определяет количество подтверждений от брокеров + * **Значения**: + * `0`: Продюсер не ждёт подтверждений (самая быстрая отправка, но высокий риск потери сообщений) + * `1`: Продюсер ждёт подтверждения от лидера партиции + * `all` (или `-1`): Продюсер ждёт подтверждений от всех реплик (наибольшая надежность, но увеличенные задержки) + * **Пример**: `acks: all` + * **Зачем это нужно**: Позволяет выбрать баланс между скоростью и надежностью отправки данных. + +### Дополнительные важные настройки + +* **Количество повторных попыток (retries):** + * **Описание**: Определяет, сколько раз продюсер должен попытаться отправить сообщение при неудаче + * **Пример**: `retries: 3` + * **Зачем это нужно**: Если произошёл временный сбой, продюсер может попытаться повторить отправку сообщений, что + увеличивает шанс доставки +* **Идемпотентность продюсера (enable.idempotence):** + * **Описание**: Включение идемпотентного режима, что предотвращает дублирование сообщений при сбоях + * **Пример**: `enable.idempotence: true` + * **Зачем это нужно**: Гарантирует, что каждое сообщение будет доставлено ровно один раз +* **Максимальный размер сообщения (max.request.size):** + * **Описание**: Максимальный размер сообщения, которое продюсер может отправить брокеру + * **Пример**: `max.request.size: 1048576` (1 MB) + * **Зачем это нужно**: Ограничивает размер сообщений, которые могут быть отправлены, чтобы избежать перегрузки сети и брокеров. +* **Таймаут ожидания подтверждений (request.timeout.ms):** + * **Описание**: Максимальное время ожидания подтверждения от брокера + * **Пример**: `request.timeout.ms: 30000` (30 секунд) + * **Зачем это нужно**: Помогает избежать бесконечного ожидания ответа от брокера в случае его сбоя + +[к оглавлению](#apache-kafka) + +## Пример конфигурации Kafka Producer + +```java +import org.apache.kafka.clients.producer.KafkaProducer; +import org.apache.kafka.clients.producer.ProducerRecord; +import java.util.Properties; + +public class KafkaStringArrayProducer { + + public static void main(String[] args) { + // Настройки Kafka Producer + Properties props = new Properties(); + props.put("bootstrap.servers", "localhost:9092"); + props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer"); + props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer"); + + // Создание Kafka Producer + KafkaProducer producer = new KafkaProducer<>(props); + + String key = "user123"; + String[] value = {"message1", "message2", "message3"}; + + // Создание записи и добавление заголовков + ProducerRecord record = new ProducerRecord<>("my_topic", key, value); + record.headers().add("traceId", "someTraceId"); + + // Отправка сообщения в Kafka + producer.send(record, (metadata, exception) -> { + if (exception != null) { + System.out.println("Ошибка при отправке сообщения: " + exception.getMessage()); + } else { + System.out.println("Сообщение отправлено в топик " + metadata.topic() + " с партицией " + metadata.partition()); + } + }); + + producer.close(); + } +} +``` + +```properties +acks=all +retries=3 +compression.type=gzip +``` + +### С использованием Spring Kafka + +```java +import org.apache.kafka.clients.producer.ProducerConfig; +import org.apache.kafka.common.serialization.StringSerializer; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.kafka.core.KafkaTemplate; +import org.springframework.kafka.core.DefaultKafkaProducerFactory; +import org.springframework.kafka.core.ProducerFactory; +import org.springframework.kafka.config.ConcurrentMessageListenerContainer; +import org.springframework.kafka.listener.MessageListenerContainer; +import org.springframework.kafka.producer.Producer; +import org.springframework.kafka.producer.ProducerRecord; + +import java.util.HashMap; +import java.util.Map; + +@EnableKafka +@Configuration +public class KafkaProducerConfig { + + @Autowired + private KafkaProperties kafkaProperties; + + @Bean + public Map producerConfigs() { + Map props = new HashMap<>(); + props.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, kafkaProperties.getServer()); + props.put(ProducerConfig.CLIENT_ID_CONFIG, kafkaProperties.getProducerId()); + props.put( + ProducerConfig.INTERCEPTOR_CLASSES_CONFIG, + "com.example.configuration.kafka.KafkaProducerLoggingInterceptor" + ); + + if ("SASL_SSL".equals(kafkaProperties.getSecurityProtocol())) { + props.put("ssl.truststore.location", kafkaProperties.getSslTrustStoreLocation()); + props.put("ssl.truststore.password", kafkaProperties.getSslTrustStorePassword()); + props.put("ssl.truststore.type", kafkaProperties.getSslTrustStoreType()); + props.put("ssl.keystore.type", kafkaProperties.getSslKeyStoreType()); + + props.put("sasl.mechanism", kafkaProperties.getSaslMechanism()); + props.put("security.protocol", kafkaProperties.getSecurityProtocol()); + props.put("sasl.jaas.config", kafkaProperties.getJaasConfigCompiled()); + } + + return props; + } + + @Bean + public ProducerFactory producerFactory() { + var stringSerializerKey = new StringSerializer(); + stringSerializerKey.configure(Map.of("key.serializer.encoding", "UTF-8"), true); + stringSerializerKey.configure(Map.of("serializer.encoding", "UTF-8"), true); + + var stringSerializerValue = new StringSerializer(); + stringSerializerValue.configure(Map.of("value.serializer.encoding", "UTF-8"), false); + stringSerializerValue.configure(Map.of("serializer.encoding", "UTF-8"), false); + + return new DefaultKafkaProducerFactory<>(producerConfigs(), stringSerializerKey, stringSerializerValue); + } + + @Bean + public KafkaTemplate kafkaTemplate() { + return new KafkaTemplate<>(producerFactory()); + } +} +``` + +```java +import org.springframework.kafka.core.KafkaTemplate; +import org.springframework.stereotype.Service; + +@Service +public class KafkaProducerService { + + private final KafkaTemplate kafkaTemplate; + + public KafkaProducerService(KafkaTemplate kafkaTemplate) { + this.kafkaTemplate = kafkaTemplate; + } + + public void sendMessage(String message, String key, String topic) { + try { + log.info("Sending message {}", data); + kafkaTemplate.send(topic, key, message); + log.info("Successfully send message {}", data); + } catch (Exception ex) { + log.error("Failed send message to {} topic by key {}", key, topic); + throw ex; + } + } +} +``` + +```java +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequestMapping("/kafka") +public class KafkaController { + + @Autowired + private KafkaProducerService kafkaProducerService; + + @PostMapping("/send") + public String sendMessage(@RequestParam String message, @RequestParam String key, @RequestParam String topic) { + kafkaProducerService.sendMessage(message, key, topic); + return "Message sent to Kafka!"; + } +} +``` + +### С использованием Spring Cloud Stream + +```yaml +spring: + cloud: + stream: + bindings: + output: + destination: my_topic + kafka: + binder: + brokers: localhost:9092 +``` + +```java +import org.springframework.cloud.stream.annotation.EnableBinding; +import org.springframework.cloud.stream.messaging.Source; +import org.springframework.integration.support.MessageBuilder; +import org.springframework.messaging.Message; +import org.springframework.stereotype.Service; + +@Service +@EnableBinding(Source.class) // Подключение к каналу сообщений +public class KafkaStreamProducer { + + private final Source source; + + public KafkaStreamProducer(Source source) { + this.source = source; + } + + public void sendMessage(String message) { + Message msg = MessageBuilder.withPayload(message).build(); + source.output().send(msg); // Отправка сообщения в Kafka + } +} +``` + +```java +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequestMapping("/kafka-stream") +public class KafkaStreamController { + + @Autowired + private KafkaStreamProducer kafkaStreamProducer; + + @PostMapping("/send") + public String sendMessage(@RequestParam String message) { + kafkaStreamProducer.sendMessage(message); + return "Message sent to Kafka via Spring Cloud Stream!"; + } +} +``` + +[к оглавлению](#apache-kafka) + +## Архитектура консюмера + +Потребители используют **Kafka Consumer API** для взаимодействия с брокерами Kafka. Они получают сообщения и обрабатывают +их согласно своей логике. Потребители могут быть объединены в группы **Consumer Groups**. + +### Резюме + +* "Smart" консюмер +* Консюмер опрашивает кафку +* Консюмер отвечает за гарантию обработки +* Автоматические фейловер в консюмер-группе +* Независимая обработка разными консюмер-группе + +### Компоненты + +#### Consumer Group + +Kafka использует концепцию Consumer Groups, что позволяет нескольким потребителям работать вместе, чтобы параллельно +обрабатывать данные из топиков. Каждый потребитель в группе обрабатывает только часть данных из топика, обеспечивая масштабируемость и балансировку нагрузки. + +* Все сообщения из одного Kafka Topic делятся между всеми потребителями в группе +* Если в группе несколько потребителей, Kafka гарантирует, что каждая партиция топика будет обрабатываться только одним потребителем +* В случае если один из потребителей выходит из строя, его партиции автоматически перераспределяются между оставшимися активными потребителями + +#### Offset (Смещение) + +Потребитель отслеживает offset каждой партиции, чтобы понимать, с какого сообщения продолжать чтение. Смещение — это +уникальный идентификатор каждого сообщения в партиции. + +Потребители могут хранить offset в Kafka или вне её (например, в базе данных или файловой системе). Если потребитель +отключается, он может возобновить обработку с того места, где остановился, прочитав сохранённый offset. + +#### Poll (Опрос) + +Потребители используют метод poll() для опроса Kafka на наличие новых сообщений. Это асинхронный процесс, и Kafka будет +отправлять потребителю доступные сообщения по мере их поступления. + +* Потребитель может указывать тайм-аут, после которого метод poll() вернёт пустой результат, если сообщений нет. +* Потребитель должен обрабатывать сообщения, а затем снова опрашивать Kafka для получения новых данных. + +### Процесс работы + +1. **Инициализация**: Потребитель подключается к Kafka-брокерам и присоединяется к consumer group. Он получает информацию о партиции топика, который будет читать. +2. **Подписка на топик**: Потребитель подписывается на определённые топики с помощью метода `subscribe()`. +3. **Опрос**: Потребитель вызывает метод `poll()` для получения новых сообщений. Если в очереди есть сообщения, они передаются потребителю для обработки. +4. **Обработка сообщений**: Потребитель обрабатывает сообщения, извлекая полезную информацию из каждого. +5. **Подтверждение обработки**: После обработки сообщения потребитель подтверждает обработку с помощью `commit()`. + Это обновляет **offset**, позволяя потребителю продолжить чтение с места, на котором остановился. +6. **Обработка ошибок**: В случае ошибки потребитель может решить, как повторить обработку сообщения + (например, с использованием механизма повторных попыток). +7. **Завершение работы**: Когда потребитель завершает обработку, он выходит из consumer group и может закрыть соединение с Kafka. + +[к оглавлению](#apache-kafka) + +## Настройки консюмера + +* **bootstrap.servers** — список брокеров, к которым будет подключаться потребитель +* **group.id** — идентификатор группы потребителей +* **auto.offset.reset** — настройка поведения при отсутствии offset (`earliest` для чтения с самого начала или `latest` для чтения с конца) +* **enable.auto.commit** — указывает, должен ли потребитель автоматически коммитить offset. Если `false`, потребитель должен делать это вручную +* **auto.commit.interval.ms** — определяет интервал времени между автоматическими коммитами offset сообщений, если включена автоматическая фиксация +* **max.poll.records** — максимальное количество сообщений, которые потребитель будет получать за один вызов `poll()` +* **session.timeout.ms** — максимальное время без общения с Kafka перед тем, как потребитель считается недоступным +* **client.rack** — используется для указания серверной стойки или дата-центра. Это особенно важно в случае, если у вас + есть распределённая инфраструктура Kafka с несколькими стойками или дата-центрами, где сообщения могут быть реплицированы + между разными физическими местоположениями (например, несколькими дата-центрами). + +### Что такое Rack в контексте Kafka? + +**Rack** — это метка, которая идентифицирует физическое местоположение брокеров Kafka. В Kafka можно задать rack для каждого брокера +с помощью параметра `broker.rack`, чтобы управлять репликацией данных, предпочтительно размещая реплики на разных физических машинах или в разных дата-центрах. + +**Преимущества использования client.rack** + +* **Снижение задержек**: Kafka будет предпочитать, чтобы данные попадали в тот же rack, где находится клиент, что уменьшает время отклика +* **Повышенная отказоустойчивость**: С правильной настройкой client.rack и broker.rack можно улучшить отказоустойчивость + за счет размещения реплик в разных физически удаленных местах +* **Лучшее использование ресурсов**: Правильное распределение нагрузки по rack помогает избежать перегрузки одного физического местоположения + +[к оглавлению](#apache-kafka) + +## Пример конфигурации Kafka Consumer + +```java +import org.apache.kafka.clients.consumer.ConsumerConfig; +import org.apache.kafka.clients.consumer.KafkaConsumer; +import org.apache.kafka.common.serialization.StringDeserializer; + +import java.time.Duration; +import java.util.HashMap; +import java.util.Map; +import java.util.Collections; + +public class KafkaConsumerExample { + + public static void main(String[] args) { + String bootstrapServers = "localhost:9092"; + String groupId = "my-consumer-group"; + String topic = "my-topic"; + + // Настройки Consumer + Map consumerConfigs = new HashMap<>(); + consumerConfigs.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers); + consumerConfigs.put(ConsumerConfig.GROUP_ID_CONFIG, groupId); + consumerConfigs.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class); + consumerConfigs.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class); + consumerConfigs.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "earliest"); + + // Создание Consumer + KafkaConsumer consumer = new KafkaConsumer<>(consumerConfigs); + + // Подписка на тему + consumer.subscribe(Collections.singletonList(topic)); + + try { + // Чтение сообщений из Kafka + while (true) { + var records = consumer.poll(Duration.ofSeconds(1)); + records.forEach(record -> System.out.println("Received message: " + record.value())); + } + } finally { + consumer.close(); + } + } +} +``` + +**At least once** + +Чтобы гарантировать обработку сообщений хотя бы один раз, нужно коммитить после обработки. + +```java +import org.apache.kafka.clients.consumer.KafkaConsumer; +import org.apache.kafka.clients.consumer.ConsumerConfig; +import org.apache.kafka.common.serialization.StringDeserializer; + +import java.time.Duration; +import java.util.HashMap; +import java.util.Map; +import java.util.Collections; + +public class KafkaConsumerAtLeastOnce { + + public static void main(String[] args) { + try { + // Чтение сообщений + while (true) { + var records = consumer.poll(Duration.ofSeconds(1)); // Ожидание 1 секунду для получения сообщений + process(records); + consumer.commitAsync(); // Commit после обработки + } + } finally { + consumer.close(); // Закрытие consumer + } + } +} +``` + +**At most once** + +Чтобы гарантировать обработку сообщений не более одного раза, нужно коммитить до обработки или включить авто-подтверждение смещений +`enable.auto.commit=true`. + +```java +import org.apache.kafka.clients.consumer.KafkaConsumer; +import org.apache.kafka.clients.consumer.ConsumerConfig; +import org.apache.kafka.common.serialization.StringDeserializer; + +import java.time.Duration; +import java.util.HashMap; +import java.util.Map; +import java.util.Collections; + +public class KafkaConsumerAtLeastOnce { + + public static void main(String[] args) { + try { + // Чтение сообщений + while (true) { + var records = consumer.poll(Duration.ofSeconds(1)); // Ожидание 1 секунду для получения сообщений + consumer.commitAsync(); // Commit перед обработкой + process(records); + } + } finally { + consumer.close(); // Закрытие consumer + } + } +} +``` + +### С использованием Spring Kafka + +```java +@EnableKafka +@Configuration +public class KafkaConsumerConfig { + + @Autowired + private KafkaProperties kafkaProperties; + + @Bean + public ConsumerFactory consumerFactory() { + return new DefaultKafkaConsumerFactory<>(consumerConfigs()); + } + + @Bean + public Map consumerConfigs() { + Map configs = new HashMap<>(); + configs.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, kafkaProperties.getServer()); + configs.put(ConsumerConfig.GROUP_ID_CONFIG, kafkaProperties.getConsumerGroupId()); + configs.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class); + configs.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class); + return configs; + } + + @Bean + public KafkaListenerContainerFactory> kafkaListenerContainerFactory() { + ConcurrentMessageListenerContainerFactory factory = new ConcurrentMessageListenerContainerFactory<>(); + factory.setConsumerFactory(consumerFactory()); + return factory; + } +} +``` + +```java +import org.springframework.kafka.annotation.KafkaListener; +import org.springframework.messaging.handler.annotation.Header; +import org.springframework.stereotype.Service; + +@Service +public class KafkaConsumer { + + @KafkaListener(topics = "my_topic", groupId = "group_id") + public void listen(@Payload String message, + @Header("traceId") String traceId, + @Header("correlationId") String correlationId) { + System.out.println("Received message: " + message); + System.out.println("Trace ID: " + traceId); + System.out.println("Correlation ID: " + correlationId); + } +} +``` + +**At least once** + +```yaml +spring: + kafka: + consumer: + enable-auto-commit: false # Отключение авто-commit + auto-offset-reset: earliest # Начинать чтение с самого начала (если нет смещения) + group-id: my-consumer-group + max-poll-records: 500 # Максимальное количество сообщений для обработки за один раз + listener: + ack-mode: manual # Ручное подтверждение +``` + +```java +import org.apache.kafka.clients.consumer.ConsumerConfig; +import org.springframework.kafka.annotation.EnableKafka; +import org.springframework.kafka.annotation.KafkaListener; +import org.springframework.kafka.listener.MessageListener; +import org.springframework.kafka.listener.MessageListenerContainer; +import org.springframework.kafka.listener.config.DefaultMessageListenerContainer; +import org.springframework.kafka.core.ConsumerFactory; +import org.springframework.kafka.listener.ConcurrentMessageListenerContainer; +import org.springframework.kafka.core.DefaultKafkaConsumerFactory; +import org.springframework.kafka.listener.MessageListener; +import org.springframework.kafka.listener.MessageListenerContainer; + +@EnableKafka +public class AtLeastOnceConsumer { + + @KafkaListener(topics = "my-topic", groupId = "my-consumer-group") + public void listen(String message, Acknowledgment acknowledgment) { + System.out.println("Received message: " + message); + // Обработка сообщения + // Подтверждение смещения вручную после успешной обработки + acknowledgment.acknowledge(); + } +} +``` + +**At most once** + +```yaml +spring: + kafka: + consumer: + enable-auto-commit: true # Включение авто-commit + group-id: my-consumer-group + auto-offset-reset: earliest # Начинать чтение с самого начала + max-poll-records: 100 # Максимальное количество сообщений для обработки за один раз +``` + +```java +import org.springframework.kafka.annotation.KafkaListener; + +public class AtMostOnceConsumer { + + @KafkaListener(topics = "my-topic", groupId = "my-consumer-group") + public void listen(String message) { + System.out.println("Received message: " + message); + // Обработка сообщения... + // Смещение будет автоматически зафиксировано после получения сообщения + } +} +``` + +### С использованием Spring Cloud Stream + +```yaml +spring: + cloud: + stream: + bindings: + input: + destination: my-topic + group: my-consumer-group + content-type: application/json + kafka: + binder: + brokers: localhost:9092 + auto-create-topics: false +``` + +```java +import org.springframework.cloud.stream.annotation.EnableBinding; +import org.springframework.cloud.stream.annotation.StreamListener; +import org.springframework.messaging.handler.annotation.Payload; +import org.springframework.stereotype.Service; + +@Service +@EnableBinding(KafkaProcessor.class) // Указывает на интерфейс, с которым связывается этот сервис +public class KafkaConsumerService { + + // Метод будет слушать сообщения из указанного канала + @StreamListener("input") + public void handle(@Payload String message) { + System.out.println("Received message: " + message); + } +} +``` + +```java +import org.springframework.cloud.stream.annotation.Input; +import org.springframework.messaging.SubscribableChannel; + +public interface KafkaProcessor { + + @Input("input") // Имя канала, которое мы используем в application.yml + SubscribableChannel input(); +} +``` + +**At least once** + +```yaml +spring: + cloud: + stream: + bindings: + input: + destination: my-topic + group: my-consumer-group + content-type: application/json + consumer: + ackMode: manual # Ручное подтверждение + maxAttempts: 3 # Максимальное количество попыток +``` + +```java +import org.springframework.cloud.stream.annotation.EnableBinding; +import org.springframework.cloud.stream.annotation.StreamListener; +import org.springframework.messaging.Message; +import org.springframework.messaging.handler.annotation.Header; +import org.springframework.messaging.simp.SimpMessagingTemplate; +import org.springframework.stereotype.Component; + +@Component +@EnableBinding(Sink.class) // Sink - это интерфейс, предоставляющий Binding для входных сообщений +public class AtLeastOnceConsumer { + + @StreamListener(Sink.INPUT) + public void handleMessage(Message message, @Header(name = "kafka_offset") String offset) { + // Обработка сообщения + System.out.println("Received message: " + message.getPayload()); + // После успешной обработки подтверждаем сообщение + // Spring Cloud Stream автоматически подтвердит сообщение после завершения метода + // благодаря ackMode=manual и настроенному acknowledgment + } +} +``` + +**At most once** + +```yaml +spring: + cloud: + stream: + bindings: + input: + destination: my-topic + group: my-consumer-group + content-type: application/json + consumer: + ackMode: batch # Автоматическое подтверждение после пакета сообщений +``` + +```java +import org.springframework.cloud.stream.annotation.EnableBinding; +import org.springframework.cloud.stream.annotation.StreamListener; +import org.springframework.messaging.Message; +import org.springframework.stereotype.Component; + +@Component +@EnableBinding(Sink.class) +public class AtMostOnceConsumer { + + @StreamListener(Sink.INPUT) + public void handleMessage(Message message) { + // Обработка сообщения + System.out.println("Received message: " + message.getPayload()); + // Смещение будет автоматически зафиксировано после получения сообщения + } +} +``` + +**Mostly Once** + +Это гибридный режим, который стремится быть чем-то средним между At least once и At most once. Он предполагает, что сообщения +будут доставлены обычно один раз, но иногда, в случае сбоев, может быть обработано больше одного раза. Для реализации +такого режима в Spring Cloud Stream потребуется дополнительная логика, например, фильтрация дублированных сообщений или +использование уникальных идентификаторов сообщений. + +В рамках Spring Cloud Stream, можно обработать Mostly Once с использованием уникальных идентификаторов сообщений или +кеширования состояния, чтобы отфильтровать повторно обработанные сообщения. + +```yaml +spring: + cloud: + stream: + bindings: + input: + destination: my-topic + group: my-consumer-group + content-type: application/json + consumer: + ackMode: manual # Ручное подтверждение + maxAttempts: 3 # Максимальное количество попыток +``` + +```java +import org.springframework.cloud.stream.annotation.EnableBinding; +import org.springframework.cloud.stream.annotation.StreamListener; +import org.springframework.messaging.Message; +import org.springframework.messaging.handler.annotation.Header; +import org.springframework.messaging.simp.SimpMessagingTemplate; +import org.springframework.stereotype.Component; + +import java.util.HashSet; +import java.util.Set; + +@Component +@EnableBinding(Sink.class) +public class MostlyOnceConsumer { + + private Set processedMessageIds = new HashSet<>(); + + @StreamListener(Sink.INPUT) + public void handleMessage(Message message, @Header("messageId") String messageId) { + if (processedMessageIds.contains(messageId)) { + System.out.println("Duplicate message: " + messageId); + return; // Пропускаем дублированное сообщение + } + // Обработка сообщения + System.out.println("Received message: " + message.getPayload()); + // Добавляем идентификатор в обработанные + processedMessageIds.add(messageId); + // После успешной обработки подтверждаем сообщение вручную + // Spring Cloud Stream подтвердит сообщение после выполнения метода + } +} +``` + +[к оглавлению](#apache-kafka) + +## Основные API Kafka + +* Producer API +* Consumer API +* Streams API +* Connector API + +[к оглавлению](#apache-kafka) + +## Какова роль Producer API? + +Используется для публикации потока сообщений в топики Kafka. Он управляет партицированием сообщений, сжатием и балансировкой +нагрузки между несколькими брокерами. Продюсер также отвечает за повторные неудачные попытки публикации и может быть +настроен на различные уровни гарантий доставки. + +[к оглавлению](#apache-kafka) + +## Какова роль Consumer API? + +Обеспечивает механизм для потребления сообщений топиков. Оно позволяет приложениям и микросервисам читать данные, +поступающие в Kafka, и обрабатывать их для дальнейшего использования, будь то хранение, анализ или реактивная обработка. + +[к оглавлению](#apache-kafka) + +## Какова роль Connector API? + +Connector API в Apache Kafka является частью Kafka Connect, которая представляет собой инфраструктуру для интеграции +внешних систем с Kafka. Connector API играет ключевую роль в упрощении процесса подключения различных источников данных +и систем-приемников к Kafka, предоставляя возможность автоматического перемещения данных между ними. + +[к оглавлению](#apache-kafka) + +## Какова роль Streams API? + +Это компонент Apache Kafka, предназначенный для создания приложений и микросервисов, которые обрабатывают потоки данных +в реальном времени. Его основная роль заключается в том, чтобы позволить разработчикам легко обрабатывать и анализировать +данные, поступающие в виде непрерывных потоков из топиков. Kafka Streams API предоставляет высокоуровневый интерфейс для +выполнения таких операций, как фильтрация, агрегация, объединение данных и вычисление оконных функций. + +[к оглавлению](#apache-kafka) + +## Какова роль Transactions API? + +Kafka Transactions API позволяет выполнять атомарные обновления для нескольких топиков. Он включает exactly-once +гарантию для приложений, которые читают данные из одного топика и пишут в другой. Это особенно полезно для приложений потоковой +обработки, которым необходимо гарантировать, что каждое входное событие влияет на выходные данные ровно один раз, даже в случае сбоев. + +[к оглавлению](#apache-kafka) + +## Какова роль Quota API? + +Quota API позволяет настраивать квоты для каждого клиента для ограничения скорости создания или потребления данных, чтобы +один клиент не потреблял слишком много ресурсов брокера. Это помогает обеспечить справедливое распределение ресурсов и +предотвратить сценарии отказа в обслуживании. + +[к оглавлению](#apache-kafka) + +## Какова роль AdminClient API? + +AdminClient API предоставляет операции для управления топиками, брокерами, конфигурацией и другими объектами Kafka. +Его можно использовать для создания, удаления и описания топиков, управления списками ACL, получения информации о кластере и +программного выполнения других административных задач. + +[к оглавлению](#apache-kafka) + +## Kafka Consumer + +## Для чего нужен координатор группы? + +Координатор группы отвечает за управление группами потребителей. Он управляет членством в группах потребителей, назначает +партиции потребителям внутри группы и управляет фиксацией смещения. Когда потребитель присоединяется к группе или покидает ее, +координатор группы запускает перебалансировку для переназначения партиций среди оставшихся потребителей. + +[к оглавлению](#apache-kafka) + +## Для чего нужен Consumer heartbeat thread? + +Consumer Heartbeat Thread отвечает за отправку периодических сигналов брокеру Kafka (в частности, координатору группы). +Эти сигналы указывают на то, что потребитель жив и все еще является частью группы потребителей. Если потребитель не отправляет +данные сигналы в течение настроенного периода, он считается неживым, и координатор группы инициирует перебалансировку +для переназначения его партиций другим потребителям в группе. + +[к оглавлению](#apache-kafka) + +## Как Kafka обрабатывает сообщения? + +Kafka поддерживает два основных способа обработки сообщений: +* **Queue**: каждое сообщение обрабатывается одним потребителем в группе потребителей. Это достигается за счет наличия + в группе нескольких потребителей, каждый из которых считывает данные из отдельных партиций. +* **Publish-Subscribe**: все сообщения обрабатываются всеми потребителями. Это достигается за счет того, что каждый + потребитель находится в своей собственной группе потребителей, что позволяет всем потребителям читать все сообщения. + +[к оглавлению](#apache-kafka) + +## Как Kafka обрабатывает задержку консюмера? + +Задержка (лаг) консюмера в Kafka относится к разнице между оффсетом последнего созданного сообщения и оффсетом последнего +полученного сообщения. Kafka предоставляет инструменты и API для мониторинга задержек консюмеров такие, как инструмент +командной строки Kafka Consumer Groups и API AdminClient. Высокая задержка консюмеров может указывать на проблемы с +производительностью или недостаточную пропускную способность консюмеров. Kafka не обрабатывает задержки автоматически, +но предоставляет информацию, необходимую приложениям для принятия решений о масштабировании или оптимизации производительности. + +[к оглавлению](#apache-kafka) + +## Для чего нужны методы subscribe() и poll()? + +Метод subscribe() используется для подписки на один или несколько топиков. Фактически он не извлекает никаких данных. +Метод poll(), с другой стороны, используется для извлечения данных из топиков. Он возвращает записи, которые были опубликованы +с момента последнего запроса топиков и партиций. Метод poll() обычно вызывается в цикле для непрерывного получения данных. + +[к оглавлению](#apache-kafka) + +## Для чего нужен метод position()? + +Метод position() возвращает смещение следующей записи, которая будет извлечена для данной партиции. Это полезно для +отслеживания хода получения данных и может использоваться в сочетании с методом committed(), чтобы определить насколько +сильно потребитель отстал от своего последнего комита оффсета. Эта информация может быть ценной для мониторинга и +управления показателями потребителей. + +[к оглавлению](#apache-kafka) + +## Для чего нужны методы commitSync() и commitAsync()? + +Эти методы используются для фиксации смещений: +* **commitSync()**: синхронно фиксирует последнее смещение, возвращенное poll(). Он будет повторять попытку до тех пор, + пока не завершится успешно или не столкнется с непроверяемой ошибкой. +* **commitAsync()**: асинхронно фиксирует смещения. Он не повторяет попытку при сбое, что делает его более быстрым, + но менее надежным, чем commitSync(). Выбор между этими методами зависит от баланса между производительностью и надежностью, + требуемого приложением. + +[к оглавлению](#apache-kafka) + +## Другие вопросы + +## Для чего нужен идемпотентный продюсер? + +Идемпотентный продюсер гарантирует exactly-once гарантию доставки, предотвращая дублирование записей в Kafka в случае +повторных попыток отправки сообщений. Это важно для поддержания целостности данных и правильности их обработки в системе, +особенно в распределенных системах, где могут возникать ошибки связи или сбои. + +[к оглавлению](#apache-kafka) + +## Для чего нужен интерфейс Partitioner? + +Интерфейс Partitioner в Producer API определяет в какую партицию топика будет отправлено сообщение. Partitioner по-умолчанию +использует хэш ключа (если он присутствует) для выбора партиции, гарантируя, что сообщения с одним и тем же ключом всегда +отправляются в одну и ту же партицию. Могут быть реализованы пользовательские Partitioner для управления распределением +сообщений по партициям на основе определенной бизнес-логики или характеристик данных. + +[к оглавлению](#apache-kafka) + +## Для чего нужен Broker log cleaner thread? + +Поток очистки журнала в Kafka отвечает за выполнение сжатия журнала. Сжатие журнала - это механизм, при котором Kafka +удаляет избыточные записи, сохраняя только последнее значение для каждого ключа. Это полезно в тех случаях, когда требуется +только последнее обновление для данного ключа, например, для обслуживания changelog или состояния БД. Программа очистки журналов +периодически запускается для сжатия соответствующих партиций. + +[к оглавлению](#apache-kafka) + +## Для чего нужен Kafka Mirror Maker? + +Это инструмент, позволяющий реплицировать данные между кластерами Kafka, потенциально находящихся в разных дата-центрах. +Он работает, потребляя данные из одного кластера и передавая в другой. Можно использовать для создания резервной копии данных, +объединения данных из нескольких дата-центров в единое хранилище или для переноса данных между кластерами. + +[к оглавлению](#apache-kafka) + +## Для чего нужна Schema Registry? + +Kafka Schema Registry предоставляет RESTful интерфейс для хранения и извлечения схем Avro. Schema Registry используется +совместно с Kafka для обеспечения совместимости схем данных между производителями и потребителями. Это особенно полезно +при разработке моделей данных с течением времени, сохраняя обратную и прямую совместимость. + +[к оглавлению](#apache-kafka) + +## Для чего нужен Streams DSL? + +Kafka Streams DSL предоставляет высокоуровневый API для операций потоковой обработки. Он позволяет разработчикам описывать +сложную логику обработки, такую как фильтрация, преобразование, агрегирование и объединение потоков данных. DSL абстрагирует +многие низкоуровневые детали потоковой обработки, упрощая создание и обслуживание приложений потоковой обработки. + +[к оглавлению](#apache-kafka) + +## Как Kafka обеспечивает версионирование сообщений? + +Сама по себе Kafka не обеспечивает версионирование сообщений напрямую, но предоставляет механизмы, позволяющие реализовывать +управление версиями. Одним из распространенных подходов является включение поля версии в схему сообщения. Для более сложных задач +управления версиями используются реестры схем (например, Confluent Schema Registry), которые могут управлять изменением схемы и совместимостью. + +[к оглавлению](#apache-kafka) + +## Как потребители получают сообщения от брокера? + +Kafka использует pull-модель для извлечения сообщений. Потребители запрашивают сообщения у брокеров, а не брокеры +отправляют сообщения потребителям. Это позволяет потребителям контролировать скорость, с которой они получают сообщения. +Потребители отправляют запросы на получение данных от брокера, указывая топик, партицию и начальное смещение для каждой партиции. +Брокер отвечает сообщениями с объемом до указанного максимального предела в байтах. + +[к оглавлению](#apache-kafka) + +## В чем разница между Kafka Streams и Apache Flink? + +Kafka Streams и Apache Flink — это два мощных инструмента для обработки потоков данных в режиме реального времени, но +они различаются по архитектуре, возможностям и сценариям применения. + +### Сравнение Kafka Streams и Apache Flink + +| **Критерий** | **Kafka Streams** | **Apache Flink** | +|------------------------|---------------------------------------------|-----------------------------------------| +| **Архитектура** | Встроенная библиотека, работающая внутри приложения. Зависит от Kafka. | Независимая распределенная система потоковой обработки данных с возможностью интеграции с различными источниками и приемниками данных. | +| **Обработка данных** | Обрабатывает потоки событий непосредственно из Kafka. Подходит для обработки событий и транзакционных данных с минимальной задержкой. | Поддерживает как потоковую (streaming), так и пакетную (batch) обработку данных. Специализируется на сложной обработке событий с гибкими возможностями управления состоянием. | +| **Зависимость от Kafka**| Построена исключительно вокруг Kafka. Требует Kafka для получения и отправки данных. | Работает с широким спектром источников данных (Kafka, HDFS, базы данных и т. д.). Kafka — лишь один из многих источников. | +| **Установка** | Легко интегрируется в существующее Java/Scala-приложение как библиотека. Не требует развертывания кластеров. | Требует отдельного кластера для выполнения, что подходит для высокопроизводительных распределенных систем. | +| **Управление состоянием** | Встроенное состояние с использованием RocksDB, также поддержка репликации состояния. | Имеет развитую систему управления состоянием, поддерживает сложные функции восстановления состояния и обработки данных. | +| **Гарантия доставки** | Поддерживает "at-least-once" и "exactly-once" семантику, когда Kafka настроена соответствующим образом. | Имеет гибкие гарантии доставки: поддержка "exactly-once", "at-least-once" и "at-most-once". | +| **Масштабируемость** | Масштабируется автоматически вместе с Kafka-партициями. Каждая инстанция потребителя Kafka обрабатывает свою партицию. | Поддерживает масштабирование на уровне задач (task), с более гибкой моделью масштабирования и управления ресурсами. | +| **Обработка событий** | Подходит для обработки событий с низкой задержкой и транзакционными требованиями. | Специализируется на сложной обработке событий, таких как windowing, агрегирование и работа с изменяющимся состоянием. Поддерживает сложные аналитические операции. | +| **Инструменты и API** | Легковесная библиотека с простыми API для работы с потоками данных. Основные операции — фильтрация, маппинг, объединение потоков, windowing. | Продвинутая система с богатыми API для сложных вычислений, поддерживающая потоковую и пакетную обработку, обработку событий и контроль сложных бизнес-процессов. | +| **Требования к ресурсам**| Менее ресурсоемка, так как не требует отдельного кластера. Работает в рамках JVM-приложения. | Требует более высоких вычислительных ресурсов, так как выполняется на отдельном кластере и поддерживает высокую степень параллелизма. | + +### Когда выбрать Kafka Streams +- Если вы уже используете Kafka и вам нужна легковесная библиотека для обработки данных непосредственно внутри вашего приложения. +- Для сценариев с низкой задержкой, где данные приходят из Kafka и должны быть быстро обработаны с минимальными накладными расходами. +- Если вам нужно встроить обработку потоков данных в существующую Java/Scala программу без необходимости развертывания отдельных кластеров. + +### Когда выбрать Apache Flink +- Если вы работаете с потоковой и пакетной обработкой данных, где источники и приемники могут быть не только Kafka, но и другие системы (например, HDFS, базы данных). +- Для сложных задач обработки событий, требующих управления состоянием, временных окон, аналитики и восстановления после сбоев. +- Если ваш проект требует высокой производительности, гибкости, точных гарантий доставки и распределенной обработки в кластере. + +### Заключение +- **Kafka Streams** — это идеальный выбор, если ваша инфраструктура уже основана на Kafka, и вам нужна быстрая и легковесная обработка потоков данных. +- **Apache Flink** — это мощный инструмент для сложных аналитических задач, потоковой обработки данных в режиме реального + времени с поддержкой сложных схем обработки, который предоставляет больше возможностей для работы с разнообразными источниками данных. + +[к оглавлению](#apache-kafka) + +## В чем разница между Kafka Consumer и Kafka Stream? + +**Kafka Consumer** - это клиент, который читает данные из топика и производит некоторую обработку. Обычно используется для +простых сценариев получения данных. **Kafka Stream**, с другой стороны, более подвинутый клиент, который может потреблять, +обрабатывать и класть данные обратно в Kafka. Он предоставляет DSL для сложных операций потоковой обработки, таких как +фильтрация, преобразование, агрегирование и объединение потоков. + +[к оглавлению](#apache-kafka) + +## В чем разница между Kafka и Flume? + +**Apache Kafka** и **Apache Flume** — это два популярных инструмента для обработки и передачи данных, однако они имеют +разные цели и архитектуры. Вот основные различия между ними: + +### 1. **Назначение и использование** +- **Kafka**: Это распределенная платформа для потоковой передачи данных, которая обеспечивает высокую пропускную способность +и низкую задержку для обработки больших объемов данных. Kafka используется для создания стриминговых приложений и обработки +данных в реальном времени. Она может быть использована для передачи логов, событий, метрик и других данных, требующих +высокой доступности и масштабируемости. +- **Flume**: Это распределенная система для сбора, агрегации и передачи логов и событий. Flume обычно используется для +доставки логов с серверов в HDFS, HBase или другие системы хранения данных. Его основное предназначение — это сбор данных +из различных источников (например, лог-файлов) и передача их в системы хранения или аналитики. + +### 2. **Архитектура** +- **Kafka**: В Kafka данные отправляются в топики и партиции, которые могут быть независимо прочитаны несколькими потребителями. +Kafka ориентирована на высокую пропускную способность и масштабируемость. Это решает задачу обработки потоковых данных и +событий в реальном времени. +- **Flume**: Flume состоит из **источников (sources)**, **каналов (channels)** и **приемников (sinks)**. Источник получает +данные, канал их буферизует, а приемник отправляет их в конечную систему. Flume использует систему "event-based" и часто +применяется для сбора логов. + +### 3. **Хранение данных** +- **Kafka**: Kafka сохраняет сообщения на диске в течение длительного времени (по умолчанию — до 7 дней) в топиках. +Потребители могут читать данные в любой момент времени, и Kafka поддерживает концепцию **сохранения и ретрансляции данных**. +- **Flume**: Flume не имеет встроенного механизма долговременного хранения. Он просто передает данные в назначенные места +хранения (например, HDFS). Данные в Flume не сохраняются долго, и если система хранения не доступна, они теряются. + +### 4. **Производительность** +- **Kafka**: Kafka предназначен для работы с высокими объемами данных. Он поддерживает масштабируемость как по производителям, +так и по потребителям, и может обрабатывать миллионы сообщений в секунду с минимальной задержкой. +- **Flume**: Flume может быть менее масштабируемым по сравнению с Kafka и больше ориентирован на сбор логов и событий +с различных источников. Хотя Flume тоже может обрабатывать большие объемы данных, он не предназначен для работы с +такими большими потоками, как Kafka. + +### 5. **Использование и кейсы** +- **Kafka**: Используется для стриминга данных, аналитики в реальном времени, интеграции различных систем, работы с +большими данными и построения событийных приложений. +- **Flume**: Используется для сбора, агрегации и передачи логов и событий в системы хранения, такие как HDFS, HBase, +или внешние системы. Это идеальный выбор для организации потоков логирования и мониторинга. + +### 6. **Поддержка и интеграция** +- **Kafka**: Kafka поддерживает широкий спектр интеграций и может быть использован с различными системами для построения +распределенных приложений и аналитических решений. +- **Flume**: Flume ориентирован на интеграцию с Hadoop-экосистемой, и основное его использование — это интеграция с HDFS, +HBase и другими хранилищами данных в этой экосистеме. + +### 7. **Потребительская модель** +- **Kafka**: Kafka поддерживает много потребителей, которые могут читать из одного и того же топика независимо, а также +возможность **повторного прочтения данных**. +- **Flume**: Flume имеет фиксированную схему доставки данных и не поддерживает такую гибкость, как Kafka в части потребителей и обработки. + +### 8. **Гарантии доставки** +- **Kafka**: Kafka поддерживает **гарантии доставки** с различными уровнями подтверждения (acknowledgment), а также может +обеспечивать **доставку сообщений точно один раз** (exactly-once semantics). +- **Flume**: Flume обеспечивает базовые гарантии доставки, но они менее строгие, чем у Kafka, и больше ориентированы на +устойчивость к сбоям, а не на гарантированную доставку. + +[к оглавлению](#apache-kafka) + +## В чем разница между Kafka и RabbitMQ? + +**RabbitMQ** и **Apache Kafka** — это две популярные системы обмена сообщениями, каждая из которых имеет свои особенности +и используется для разных типов приложений. Вот основные различия между ними: + +### 1. **Архитектура** +- **RabbitMQ** использует **очереди сообщений**. Сообщения отправляются в очередь, и один потребитель извлекает сообщение +из очереди для обработки. +- **Apache Kafka** использует **топики и партиции**. Сообщения отправляются в топики, которые могут быть разделены на +партиции, и несколько потребителей могут читать эти сообщения в любом порядке. Kafka ориентирован на большие потоки данных и масштабируемость. + +### 2. **Модель доставки сообщений** +- **RabbitMQ**: Сообщения передаются в очереди, и каждый потребитель получает одно сообщение. Сообщения могут быть +подтверждены (acknowledged) или отклонены (rejected). RabbitMQ гарантирует, что сообщение будет доставлено хотя бы одному потребителю. +- **Kafka**: Сообщения сохраняются в топиках на длительный срок, и потребители могут читать их в любом порядке. Kafka +гарантирует доставку сообщений всем потребителям, если они подписаны на топик, и может позволить многократное чтение старых сообщений. + +### 3. **Гарантии доставки** +- **RabbitMQ**: Предоставляет подтверждения доставки и может повторно отправить сообщение, если потребитель не подтвердил +его получение. Можно настроить разные уровни надежности (например, за счет использования подтверждений или транзакций). +- **Kafka**: Сообщения сохраняются на диске, что позволяет потребителям считывать их в любое время. Kafka гарантирует +доставку сообщений при определенной конфигурации репликации и сохранения. + +### 4. **Производительность и масштабируемость** +- **RabbitMQ**: Лучше подходит для небольших и средних систем, где требуется высокая надежность и гарантированная доставка. +Он поддерживает **горизонтальное масштабирование**, но требует дополнительных усилий для настройки и управления. +- **Kafka**: Отличается высокой **производительностью** и возможностью обработки больших объемов данных. Kafka легко +масштабируется за счет **партиционирования** и репликации данных. + +### 5. **Потребительская модель** +- **RabbitMQ**: Один потребитель получает одно сообщение. Если потребитель не успевает обработать сообщение, оно может быть повторно отправлено. +- **Kafka**: Потребители могут читать сообщения независимо друг от друга. Kafka сохраняет все сообщения в топиках, +и потребители могут читать их в любое время. Kafka также поддерживает концепцию **групп потребителей**, где каждый +потребитель группы обрабатывает разные партиции. + +### 6. **Использование и кейсы** +- **RabbitMQ**: Идеален для обработки запросов и ответов, распределенных приложений, микросервисов с гарантией доставки, +бизнес-процессов с очередями задач. +- **Kafka**: Используется для обработки потоков данных, интеграции с большими данными, записи журналов, мониторинга, +обработки событий в реальном времени и сохранения больших объемов данных для последующего анализа. + +### 7. **Производители и потребители** +- **RabbitMQ**: Один производитель отправляет сообщения в очередь, и несколько потребителей могут обрабатывать эти сообщения. +- **Kafka**: Множество производителей могут отправлять сообщения в топики, и несколько потребителей могут читать их +одновременно, поддерживая масштабируемость. + +### 8. **Сообщения и хранение** +- **RabbitMQ**: Сообщения удаляются из очереди после их обработки потребителем. Хранение сообщений обычно краткосрочное. +- **Kafka**: Сообщения сохраняются на диске в топиках до тех пор, пока не истечет срок хранения (по конфигурации). +Это позволяет повторно читать данные. + +[к оглавлению](#apache-kafka) diff --git a/ml.md b/ml.md new file mode 100644 index 0000000..47b98a3 --- /dev/null +++ b/ml.md @@ -0,0 +1,259 @@ +[Вопросы для собеседования](README.md) + +# Языки разметки: XML, JSON, YAML ++ [Что такое _XML_?](#что-такое-xml) ++ [Что такое _DTD_?](#что-такое-dtd) ++ [Чем _well-formed XML_ отличается от _valid XML_?](#чем-well-formed-xml-отличается-от-valid-xml) ++ [Что такое «_пространство имен_» в XML?](#что-такое-пространство-имен-в-xml) ++ [Что такое XSD? В чём его преимущества перед XML DTD?](#что-такое-xsd-в-чём-его-преимущества-перед-xml-dtd) ++ [Какие типы существуют в XSD?](#какие-типы-существуют-в-xsd) ++ [Какие вы знаете методы чтения XML? Опишите сильные и слабые стороны каждого метода](#какие-вы-знаете-методы-чтения-xml-опишите-сильные-и-слабые-стороны-каждого-метода) ++ [Когда следует использовать _DOM_, а когда _SAX_, _StAX_ анализаторы?](#когда-следует-использовать-dom-а-когда-sax-stax-анализаторы) ++ [Какие вы знаете способы записи XML?](#какие-вы-знаете-способы-записи-xml) ++ [Что такое _JAXP_?](#что-такое-jaxp) ++ [Что такое _XSLT_?](#что-такое-xslt) ++ [Что такое _JSON_?](#что-такое-json) ++ [Что такое _JSON схема_?](#что-такое-json-схема) ++ [Сравните _JSON_ и _XML_](#сравните-json-и-xml) ++ [Что такое _YAML_?](#что-такое-yaml) ++ [Сравните _JSON_ и _YAML_?](#сравните-json-и-yaml) + +## Что такое _XML_? + +__XML, eXtensible Markup Language (расширяемый язык разметки)__ - язык с простым формальным синтаксисом, хорошо приспособленный для создания и обработки документов программами и одновременно удобный для чтения и создания документов человеком. + +XML расширяем, он не фиксирует разметку, используемую в документах и разработчик волен создавать разметку в соответствии с потребностями конкретной области, будучи ограниченным лишь синтаксическими правилами языка. + +[к оглавлению](#Языки-разметки-XML-JSON-YAML) + +## Что такое _DTD_? + +__DTD, Document Type Definition (определение типа документа)__ — это заранее определённый свод правил, задающий связи между элементами и атрибутами. + +> Например, DTD для HTML гласит, что тэг `DIV` должен быть внутри тэга `BODY` и может встречаться многократно, `TITLE` — в `HEAD` и всего один раз, а `SCRIPT` – и там, и там сколь угодно раз. + +DTD обычно описывается непосредственно в документе в виде строки-формулировки, начинающейся с `` или отдельном файле. + +[к оглавлению](#Языки-разметки-XML-JSON-YAML) + +## Чем _well-formed XML_ отличается от _valid XML_? + +В зависимости от уровня соответствия стандартам документ может быть «well-formed» («правильно построенный»), либо «valid» («действительный»). + +Основные признаки _well-formed XML_ следуют из формального описания стандарта: + ++ Документ имеет ровно один корневой элемент, в котором лежат все остальные. То есть, `......` - это не XML-документ. ++ Все открытые теги обязаны быть закрыты. HTML, например, допускает не закрывать многие теги (`

`, ``, `

  • `, `` и многие другие). В XML так делать нельзя. ++ Для одиночных тегов (типа `
    `) , чтобы отличать их от открывающих, предусмотрена специальная запись: `
    `. Но можно написать и полностью `

    `. ++ Имена тегов регистрозависимые. Если вы открываете тег ``, то его надо закрывать именно таким же, `` не допускается. ++ Теги не могут нарушать вложенность. Вот такого не должно быть: `...`. ++ Все атрибуты тегов обязаны быть заключены в двойные кавычки (`"`). ++ Есть три символа - `<`, `>` и `&`, которые обязаны быть экранированы везде с помощью `<`, `>` и `&`. Внутри атрибутов надо экранировать еще и двойную кавычку с помощью `"`. ++ Все символы в документе обязаны соответствовать заявленной кодировке. + +Документ является _valid_, если он сформирован с соблюдением всех синтаксических правил корректности конкретного XML, т.е. соответствует _DTD_. + +__*well-formed XML* - корректен синтаксически (может быть разобран парсером), а _valid XML_ - корректен как синтаксически так и семантически (удовлетворяет правилам заранее описанных словаря и грамматики (DTD)).__ + +[к оглавлению](#Языки-разметки-XML-JSON-YAML) + +## Что такое «_пространство имен_» в XML? + +__Пространство имён XML (XML namespace)__ - это идентифицируемая с помощью ссылки URI коллекция имен, используемых в XML документах для обозначения типов элементов и именования атрибутов. Пространство имен XML отличается от тех «пространств имен», которые обычно используются в компьютерных дисциплинах, тем, что в варианте для XML оно имеет внутреннюю структуру, и, с математической точки зрения, набором не является. + +> Пространства имён объявляются с помощью XML атрибута `xmlns`, значением которого должен быть _URI_ и префикса, однозначно идентифицирующего пространство имён каждого элемента. + +Все имена элементов в пределах пространства имён должны быть уникальны. + +В общем случае пространство имён XML не требует, чтобы был определён его словарь. + +XML-документ может содержать имена элементов и атрибутов из нескольких словарей XML. В каждом словаре задано своё пространство имён — так разрешается проблема неоднозначности имён элементов и атрибутов. + +[к оглавлению](#Языки-разметки-XML-JSON-YAML) + +## Что такое XSD? В чём его преимущества перед XML DTD? + +__XSD, XML Schema Definition, XML Schema (XML схема)__ — язык описания структуры XML-документа. В частности, XML Schema описывает: + ++ _словарь_ - имена элементов и атрибутов; ++ _модель содержания_ - взаимосвязи между элементами и атрибутами, а также их ++ _структуру_ документа; ++ используемые _типы данных_. + +__Преимущества XSD перед DTD__ заключаются в следующем: + ++ DTD, в отличие от XSD, не является XML и имеет свой собственный синтаксис. В связи с этим могут возникать разнообразные проблемы с кодировкой и верификацией XML-документов. + ++ При использовании XSD XML-парсер может проверить не только правильность синтаксиса XML документа, но также его структуру, модель содержания и типы данных. В XML DTD существует лишь один тип данных – строка и если, например, в числовом поле будет текст, то документ всё же сможет пройти верификацию, так как XML DTD не сможет проверить тип данных. + ++ Нельзя поставить в соответствие одному XML документу больше одного DTD. А следовательно и верифицировать документ можно лишь одним DTD описанием. XSD расширяем, и позволяет подключать несколько словарей для описания типовых задач. + ++ XSD обладает встроенными средствами документирования, позволяющими создавать самодостаточные документы, не требующие дополнительного описания. + +[к оглавлению](#Языки-разметки-XML-JSON-YAML) + +## Какие типы существуют в XSD? + +__Простой тип__ - это определение типа для значения, которое может использоваться в качестве содержимого элемента или атрибута. Этот тип данных не может содержать элементы или иметь атрибуты. + +```xsd + +... +45.50 +``` + +__Сложный тип__ - это определение типа для элементов, которые могут содержать атрибуты и другие элементы. + +```xsd + + + + + +... +45.50 +``` + +[к оглавлению](#Языки-разметки-XML-JSON-YAML) + +## Какие вы знаете методы чтения XML? Опишите сильные и слабые стороны каждого метода + +__DOM (Document Object Model)__ - _объектный_ - считывает XML, воссоздавая его в памяти в виде объектной структуры при +этом XML документ представляется в виде набора тегов – узлов. Каждый узел может иметь неограниченное количество дочерних +узлов. Каждый дочерний тоже может содержать несколько уровней потомков или не содержать их вовсе. Таким образом в итоге +получается некое дерево. + +> ➖ Низкая скорость работы. + +> ➖ Расходует много памяти. + +> ➕ Прост в программировании. + +> ➕ Если в XML много объектов с перекрёстными ссылками друг на друга, достаточно дважды пройтись по документу: первый +> раз создать объекты без ссылок и заполнить словарь «название-объект», второй раз — восстановить ссылки. + +> ➕ При ошибке в XML в памяти остаётся созданная на половину структура XML, которая будет автоматически уничтожена. + +> ➕ Пригоден как для чтения так и для записи. + +__SAX (Simple API for XML)__ _событийный_ - читает XML документ, реагируя на появляющиеся события (открывающий или закрывающий тег, строку, атрибут) вызовом предоставляемых приложением обработчиков событий. При этом, в отличие от DOM, не сохраняет документ в памяти. + +> ➕ Высокая скорость работы + +> ➕ Расходует мало памяти. + +> ➗ Довольно сложен в программировании. + +> ➖ Если в XML много объектов с перекрёстными ссылками друг на друга, надо организовать временное хранение строковых ссылок, чтобы потом, когда документ будет считан, преобразовать в указатели. + +> ➖ При ошибке в XML в памяти остаётся структура, созданная на половину, предметной отрасли; программист должен своими руками корректно уничтожить её. + +> ➖ Пригоден только для чтения. + +__StAX (Stream API for XML)__ _потоковый_ - состоящий из двух наборов API для обработки XML, которые обеспечивают разные уровни абстракции. API с использованием курсора позволяет приложениям работать с XML как с потоком лексем (или событий); приложение может проверить статус анализатора и получить информацию о последней проанализированной лексеме, а затем перейти к следующей. Второй, высокоуровневый API, использующий итераторы событий, позволяет приложению обрабатывать XML как серию объектов событий, каждый из которых взаимодействует с фрагментом XML-структуры приложения. Всё, что требуется от приложения - это определить тип синтаксически разобранного события, отнести его к соответствующему конкретному типу и использовать соответствующие методы для получения информации, относящейся к событию. + +> ➗ Сохраняет преимущества, которые есть в SAX по сравнению с DOM. + +> ➕ Не основан на обратных вызовах обработчиков, приложению не придется обслуживать эмулированное состояние анализатора, как это происходит при использовании SAX. + +> ➖ Пригоден только для чтения. + +[к оглавлению](#Языки-разметки-XML-JSON-YAML) + +## Когда следует использовать _DOM_, а когда _SAX_, _StAX_ анализаторы? + +DOM - естественный выбор, когда объектом предметной области является сам XML: когда нужно знать и иметь возможность изменять структуру документа, а также в случае многократного использования информации из документа. + +Для быстрого одноразового чтения оптимальным является использование SAX или StAX. + +[к оглавлению](#Языки-разметки-XML-JSON-YAML) + +## Какие вы знаете способы записи XML? + +__Прямая запись__ - пишет XML тег за тегом, атрибут за атрибутом. + +> ➕ Высокая скорость работы. + +> ➕ Экономия памяти: при использовании не создаётся промежуточных объектов. + +> ➖ Пригоден только для записи. + +__Запись DOM (Document Object Model)__ - создаёт полную структуру XML и только потом записывает её. + +> ➖ Низкая скорость работы. + +> ➖ Не оптимальный расход памяти. + +> ➕ Пригоден как для записи так и для чтения. + +[к оглавлению](#Языки-разметки-XML-JSON-YAML) + +## Что такое _JAXP_? + +__JAXP, The Java API for XML Processing (Java API для обработки XML)__ — набор API, упрощающих обработку XML данных в программах написанных на Java. Содержит реализации DOM, SAX и StAX парсеров, поддерживает XSLT и возможность работать с DTD. + +[к оглавлению](#Языки-разметки-XML-JSON-YAML) + +## Что такое _XSLT_? + +__XSLT, eXtensible Stylesheet Language Transformations__ — язык преобразования XML-документов. + +XSLT создавался для применения в _XSL (eXtensible Stylesheet Language)_ - языке стилей для XML. Во время XSL-преобразования XSLT-процессор считывает XML-документ и таблицу(ы) стилей XSLT. На основе инструкций, которые процессор находит в таблице(ах) стилей XSLT, он вырабатывает новый XML-документ или его фрагмент. + +[к оглавлению](#Языки-разметки-XML-JSON-YAML) + +## Что такое _JSON_? + +__JSON, JavaScript Object Notation__ — текстовый формат обмена данными, основанный на JavaScript. + +JSON представляет собой (в закодированном виде) одну из двух структур: + ++ _Набор пар «ключ:значение»_; ++ _Упорядоченный набор значений_. + +Ключом может быть только строка (регистрозависимая: имена с буквами в разных регистрах считаются разными). + +В качестве значений могут быть использованы: + ++ _Объект_ — неупорядоченное множество пар «ключ:значение», заключённое в фигурные скобки `{ }`. Ключ описывается строкой, между ним и значением стоит символ `:`. Пары ключ-значение отделяются друг от друга запятыми; ++ _Массив (одномерный)_ — упорядоченное множество значений. Массив заключается в квадратные скобки `[ ]`. Значения разделяются запятыми. ++ _Число_; ++ _Литералы_ `true`, `false` и `null`; ++ _Строка_ — упорядоченное множество из нуля или более символов Unicode, заключенное в кавычки `" "`. Символы могут быть указаны с использованием escape-последовательностей, начинающихся с обратной косой черты `\`, или записаны шестнадцатеричным кодом в кодировке UTF-8 в виде `\uFFFF`. + +[к оглавлению](#Языки-разметки-XML-JSON-YAML) + +## Что такое _JSON схема_? + +__JSON Schema__ — один из языков описания структуры JSON-документа, используя синтаксис JSON. + +Это самоописательный язык: при его использовании для обработки данных и описания их допустимости могут использоваться одни и те же инструменты сериализации/десериализации. + +[к оглавлению](#Языки-разметки-XML-JSON-YAML) + +## Сравните _JSON_ и _XML_ + +... + +[к оглавлению](#Языки-разметки-XML-JSON-YAML) + +## Что такое _YAML_? + +... + +[к оглавлению](#Языки-разметки-XML-JSON-YAML) + +## Сравните _JSON_ и _YAML_? + +... + +[к оглавлению](#Языки-разметки-XML-JSON-YAML) + +# Источники + ++ [Википедия](https://ru.wikipedia.org/wiki/XML) ++ [CIT Forum](http://citforum.ru/internet/xnamsps/index.shtml#ns-decl) ++ [Quizful](http://www.quizful.net/interview/java/xml-and-parsers) + +[Вопросы для собеседования](README.md) + diff --git a/reactive.md b/reactive.md new file mode 100644 index 0000000..17f0ef8 --- /dev/null +++ b/reactive.md @@ -0,0 +1,584 @@ +[Вопросы для собеседования](README.md) + +# Реактивное программирование +* [Что такое реактивное программирование и чем оно отличается от процедурного программирования?](#что-такое-реактивное-программирование-и-чем-оно-отличается-от-процедурного-программирования) +* [Объясните концепцию потоков данных в реактивном программировании](#объясните-концепцию-потоков-данных-в-реактивном-программировании) +* [Что такое паттерн Observer и как он лежит в основе реактивного программирования?](#что-такое-паттерн-observer-и-как-он-лежит-в-основе-реактивного-программирования) +* [Опишите роль Observable и Observer в реактивном программировании](#опишите-роль-observable-и-observer-в-реактивном-программировании) +* [Что такое backpressure в контексте реактивного программирования?](#что-такое-backpressure-в-контексте-реактивного-программирования) +* [Объясните разницу между Hot и Cold Observable](#объясните-разницу-между-hot-и-cold-observable) +* [Какова роль Подписки в реактивном программировании?](#какова-роль-подписки-в-реактивном-программировании) +* [Как отписаться от потока для предотвращения утечки памяти?](#как-отписаться-от-потока-для-предотвращения-утечки-памяти) +* [Какие есть операторы в Project Reactor и для чего они используются?](#какие-есть-операторы-в-project-reactor-и-для-чего-они-используются) + +## Что такое реактивное программирование и чем оно отличается от процедурного программирования? + +### Основные принципы + +**Процедурное программирование** - это подход, при котором программа состоит из последовательности инструкций, выполняемых одна за другой. +В процедурном программировании акцент делается на определении функций и процедур, которые выполняют определенные задачи. +Этот подход хорошо подходит для решения задач, требующих четкого алгоритма действий. + +**Реактивное программирование**, с другой стороны, фокусируется на обработке потоков данных и событий. +В реактивном программировании программа реагирует на изменения в данных или событиях, происходящих в реальном времени. +Реактивное программирование позволяет создавать более гибкие и эффективные системы, способные адаптироваться к изменениям +в данных и событиях без необходимости явного управления асинхронными задачами. + +Процедурное программирование представляет данные в виде единственного значения, хранящегося в переменной. +Реактивное программирование представляет собой непрерывный поток данных, на который могут подписаться несколько наблюдателей. + +[к оглавлению](#реактивное-программирование) + +## Объясните концепцию потоков данных в реактивном программировании + +Концепция потоков данных в реактивном программировании заключается в представлении данных как непрерывно изменяющегося потока, +который автоматически распространяется через систему. Это отличается от традиционного императивного программирования, где данные +обычно обрабатываются как отдельные элементы и изменения должны явно инициироваться кодом. + +В реактивном программировании данные представлены как поток событий, каждое из которых может содержать новое значение или изменение состояния. +Система автоматически реагирует на эти изменения, обновляя свое состояние соответствующим образом. Это позволяет создавать +приложения, которые эффективно обрабатывают большие объемы данных и быстро реагируют на изменения, происходящие в реальном времени. + +Примером может служить система управления данными, которая автоматически обновляет пользовательский интерфейс при изменении данных в базе. +В таком случае, пользовательский интерфейс будет автоматически обновляться каждый раз, когда происходит изменение данных, +без необходимости явного запроса на обновление со стороны пользователя. + +Реактивное программирование основано на шаблоне Наблюдатель (Observer) + +### Ключевые компоненты +* **Наблюдаемый (Observable)** представляет источник данных. При изменении его состояния (или при создании новых данных) изменения передаются наблюдателям +* **Наблюдатель (Observer)** подписывается на Observable и получает уведомления о любых изменениях состояния или новых данных +* **Подписка (Subscription)** устанавливает взаимосвязь между наблюдаемым и наблюдателем. Подписка может быть "один к одному" или "один ко многим" +* **Операторы (Operators)** часто называемые функциями преобразования, они позволяют изменять или адаптировать данные из наблюдаемого объекта до того, как они попадут к наблюдателю +* **Планировщики (Schedulers)** помогают управлять временем и порядком выполнения операций в таких сценариях, как фоновая работа и обновления пользовательского интерфейса +* **Subjects** совмещают роли объекта наблюдения и наблюдателя. Это могут быть как источники данных, так и потребители данных + +### Процесс передачи данных +* **Эмиссия (Emission)** - данные создаются в наблюдаемом объекте и отправляются его наблюдателям +* **Фильтрация (Filtering)** - операторы могут просматривать входящие данные, пересылая только те, которые соответствуют определенным критериям +* **Трансформация (Transformation)** - данные изменяются — например, путем их мапинга перед передачей наблюдателю +* **Нотификация (Notification)** - информирование наблюдателей при поступлении новых данных + +### Основные характеристики потоков +* **Непрерывность (Continuous)** - поток данных сохраняется, что позволяет осуществлять взаимодействие в режиме реального времени +* **Асинхронность (Asynchronous)** - не гарантируется, что события будут происходить в определенном порядке, что позволяет выполнять неблокирующие операции +* **Однонаправленность (One-directional)** - данные передаются от Observable к его подписчикам, обеспечивая однонаправленный поток + +### Типы потоков по количеству подписчиков +* **Unicast Streams** - у каждого наблюдателя есть эксклюзивное подключение к наблюдаемому источнику +* **Broadcast Streams** - позволяет нескольким наблюдателям подписаться на один объект наблюдения. Каждый наблюдатель +получает полный набор данных, что может быть проблематично, если речь идет о конфиденциальности данных + +### Типы потоков по поведению +* **Hot Observable** - эти последовательности передают данные независимо от присутствия наблюдателя. +Если подписывается новый наблюдатель, он начинает получать данные с точки подписки +* **Cold Observable** - здесь передача данных начинается только после подписки. Любой новый наблюдатель получит данные с самого начала + +### Backpressure +Данный механизм регулируют скорость, с которой данные публикуются в поток. Это необходимо, чтобы справиться с потенциальным +переполнением или узкими местами из-за различий в скоростях обработки данных. + +Например, в RxJava интерфейсы `Observable` и `Flowable` отличаются тем, что последний включает поддержку backpressure. +С `Flowable` можно использовать настраиваемую стратегию backpressure, чтобы контролировать скорость публикации Observable относительно скорости потребления Subscriber + +### Практическое применение +Будь то обработка асинхронных вызовов API или управление вводом данных пользователем, потоки данных обеспечивают надежную +и гибкую основу для многих повседневных задач программирования. + +Можно использовать ряд операторов, таких как `map`, `filter`, `debounce`, и `throttle`, для преобразования данных +и манипулирования ими, исходя из конкретных требований. + +Широкое внедрение реактивных библиотек, таких как RxJava для Android или RxJS для Web, подчеркивает +полезность потоков данных в современной разработке программного обеспечения. + +[к оглавлению](#реактивное-программирование) + +## Что такое паттерн Observer и как он лежит в основе реактивного программирования? + +Паттерн Observer, также известный как Publish/Subscribe или Event Listener, является поведенческим шаблоном проектирования, +который позволяет объектам следить за изменениями в других объектах и реагировать на них. Это один из самых популярных и +полезных шаблонов, который упрощает код и повышает его гибкость. В основе реактивного программирования лежит идея о том, +что система должна реагировать на изменения внешних источников данных или событий. Паттерн Observer идеально подходит для +реализации этой концепции, поскольку он позволяет объектам автоматически получать уведомления об изменениях в других объектах +и соответствующим образом обновлять свое состояние. + +Пример использования паттерна Observer в веб-разработке может включать систему уведомлений для пользователей. Когда новая +статья добавляется на сайт, все подписчики должны быть уведомлены об этом. В этом случае, класс Subject будет отвечать +за управление подписчиками и их уведомление об изменениях, а класс Observer будет представлять собой простого наблюдателя, +который выводит сообщение о новой статье при получении уведомления, таким образом обеспечивается **слабую связность (loose coupling)**. + +Применение паттерна Observer в веб-разработке может быть полезно для обработки событий пользовательского интерфейса, +реализации системы уведомлений для пользователей, отслеживания изменений состояния приложения и реагирования на них. +Однако важно помнить, что чрезмерное использование паттерна может привести к усложнению кода и затруднить отладку. + +### Ключевые компоненты +* **Subject** - источник данных или событий. Наблюдатели подписываются на Subject для получения уведомлений об изменениях +* **Observer** - наблюдатель получает уведомления, когда состояние Subject изменяется + +В реактивной конфигурации Subject отвечает за публикацию изменений, а Observers подписываются на эти изменения. +Это исключает явное обращение к источникам данных и подчеркивает **модель потока данных (datastream model)**. + +### Пример кода паттерна Observer + +```java +import java.util.ArrayList; +import java.util.List; + +interface Observer { + void update(); +} + +class Subject { + private List observers = new ArrayList<>(); + private int state; + + public int getState() { + return state; + } + + public void setState(int state) { + this.state = state; + notifyAllObservers(); + } + + public void attach(Observer observer) { + observers.add(observer); + } + + public void notifyAllObservers() { + for (Observer observer : observers) { + observer.update(); + } + } +} + +class ConcreteObserver implements Observer { + private String name; + private Subject subject; + + public ConcreteObserver(String name, Subject subject) { + this.name = name; + this.subject = subject; + } + + @Override + public void update() { + System.out.println("Observer " * name * " updated. New state: " * subject.getState()); + } +} + +public class Main { + public static void main(String[] args) { + Subject subject = new Subject(); + ConcreteObserver observer1 = new ConcreteObserver("One", subject); + ConcreteObserver observer2 = new ConcreteObserver("Two", subject); + + subject.attach(observer1); + subject.attach(observer2); + + subject.setState(5); + } +} +``` +В данном примере Subject ведет список подписавшихся Observers и уведомляет их при изменении его состояния. + +[к оглавлению](#реактивное-программирование) + +## Опишите роль Observable и Observer в реактивном программировании + +**Наблюдатели** являются потребителями данных, в то время как **наблюдаемые** являются источником или производителем данных. + +### Ключевые концепции +* **Наблюдаемый (Observable)** - передает данные или сигналы, которые могут быть любых типов, включая пользовательские события +* **Наблюдатель (Observer)** - получает уведомление, когда Observable отправляет данные +* **Подписка (Subscription)** - связующее звено между объектом наблюдения и наблюдателем +* **Операторы (Operators)** - позволяют преобразовывать, фильтровать, комбинировать или обрабатывать поток данных, +публикуемый наблюдаемым объектом, до того, как он достигнет наблюдателя + +### Пример кода: Observable и Observer + +### Java 9* + +**Определить Subscriber** + +```java +import java.util.concurrent.Flow; + +public class SimpleSubscriber implements Flow.Subscriber { + private Flow.Subscription subscription; + + @Override + public void onSubscribe(Flow.Subscription subscription) { + this.subscription = subscription; + subscription.request(1); // Запрашиваем первый элемент + } + + @Override + public void onNext(String item) { + System.out.println("Received: " * item); + subscription.request(1); // Запрашиваем следующий элемент + } + + @Override + public void onError(Throwable throwable) { + System.err.println("Error: " * throwable.getMessage()); + } + + @Override + public void onComplete() { + System.out.println("All items received"); + } +} +``` + +**Определить Publisher** + +```java +import java.util.concurrent.Flow; +import java.util.concurrent.SubmissionPublisher; +import java.util.concurrent.TimeUnit; + +public class SimplePublisher { + + public static void main(String[] args) throws InterruptedException { + // Создаем издателя + SubmissionPublisher publisher = new SubmissionPublisher<>(); + + // Создаем подписчика + SimpleSubscriber subscriber = new SimpleSubscriber(); + + // Регистрируем подписчика в издателе + publisher.subscribe(subscriber); + + // Публикуем элементы + System.out.println("Publishing data items..."); + String[] items = {"item1", "item2", "item3"}; + for (String item : items) { + publisher.submit(item); + TimeUnit.SECONDS.sleep(1); + } + + // Закрываем издателя + publisher.close(); + + // Ждем некоторое время, чтобы подписчик обработал все элементы + TimeUnit.SECONDS.sleep(3); + } +} +``` + +### Project Reactor + +```java +import reactor.core.publisher.Flux; + +public class ReactorExample { + + public static void main(String[] args) { + // Создаем Flux для публикации данных + Flux flux = Flux.just("Hello", "World", "From", "Reactor"); + + // Подписываемся на Flux и выводим каждый элемент + flux.subscribe( + item -> System.out.println("Received: " * item), + error -> System.err.println("Error: " * error), + () -> System.out.println("All items received") + ); + } +} +``` + +[к оглавлению](#реактивное-программирование) + +## Что такое backpressure в контексте реактивного программирования? + +**Backpressure** - это концепция в реактивном программировании, которая имеет дело с ситуацией, когда производитель (или издатель) +генерирует данные быстрее, чем потребитель (или подписчик) может их обработать. Управление backpressure позволяет системе +оставаться отзывчивой и не перегружаться. + +### Ключевые концепции backpressure + +* **Producer (Publisher)** - компонент, который производит данные +* **Consumer (Subscriber)** - компонент, который потребляет данные +* **Flow Control** - механизм, который гарантирует, что производитель не перегрузит потребителя слишком большим объемом данных + +### Почему важно backpressure? + +В реактивной системе, если потребитель не выдерживает скорость, с которой производитель производит данные, это может привести к следующим проблемам: +* **Переполнение памяти (Memory Overflow)** - необработанные элементы могут накапливаться в памяти, что приводит к ошибкам нехватки памяти +* **Увеличение задержки (Latency Increase)** - система может перестать отвечать по мере роста очереди необработанных элементов +* **Исчерпание ресурсов (Resource Exhaustion)** - системные ресурсы (процессор, память) могут быть исчерпаны, что приводит к снижению производительности или сбоям + +### Стратегии управления backpressure в Project Reactor + +* **Буферизация (Buffering)** - входящие элементы хранятся в буфере до тех пор, пока потребитель не сможет их обработать + * **onBackpressureBuffer(100)** + +```java +import reactor.core.publisher.Flux; +import reactor.core.scheduler.Schedulers; + +public class BackpressureExample { + + public static void main(String[] args) { + Flux flux = Flux.range(1, 1000) + .onBackpressureBuffer(100); // Устанавливаем стратегию backpressure + + flux.publishOn(Schedulers.boundedElastic()) + .subscribe( + item -> { + try { + Thread.sleep(10); // Имитируем медленного потребителя + System.out.println("Received: " * item); + } catch (InterruptedException e) { + e.printStackTrace(); + } + }, + error -> System.err.println("Error: " * error), + () -> System.out.println("All items received") + ); + } +} +``` + +* **Отбрасывание (Dropping)** - отбрасывает элементы, если потребитель не может их обработать + * **onBackpressureDrop()** +* **Новейшие элементы (Latest)** - сохраняет только последние элементы, удаляя предыдущие + * **onBackpressureLatest()** +* **Ошибка (Error)** - сигнализирует об ошибке, когда backpressure не может быть обработано + * **onBackpressureError()** +* **Контроль скорости запроса (Control Request Rate)**: явно контролирует скорость, с которой потребитель запрашивает элементы у производителя + * **request(n)** - метод в реализации Subscriber для управления потоком + +```java +import reactor.core.publisher.BaseSubscriber; +import reactor.core.publisher.Flux; + +public class ControlledRequestExample { + + public static void main(String[] args) { + Flux flux = Flux.range(1, 1000); + + flux.subscribe(new BaseSubscriber() { + @Override + private void hookOnSubscribe(Subscription subscription) { + request(1); // Запрашиваем один элемент при подписке + } + + @Override + private void hookOnNext(Integer value) { + try { + Thread.sleep(10); // Эмитируем медленный процесс + System.out.println("Received: " * value); + request(1); // Запрашиваем следующий элемент после обработки текущего + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + @Override + private void hookOnComplete() { + System.out.println("All items received"); + } + + @Override + private void hookOnError(Throwable throwable) { + System.err.println("Error: " * throwable.getMessage()); + } + }); + } +} +``` + +[к оглавлению](#реактивное-программирование) + +## Объясните разницу между Hot и Cold Observable + +В реактивном программировании термины hot и cold observable (или издатели в контексте Project Reactor) описывают, как они +создают потоки данных и обрабатывают их. Основное различие между ними заключается в том, как они обрабатывают подписки +и когда начинают выдавать элементы. + +### Cold Observables + +Начинают выдавать элементы только тогда, когда подписчик подписывается на них. Каждый подписчик получает всю последовательность +элементов с самого начала. Это означает, что каждый раз, когда подписывается новый подписчик, Observable воспроизводит всю последовательность элементов. + +#### Характеристики + +* **Ленивое исполнение (Lazy Evaluation)** - данные не производятся, пока не будет хотя бы одного подписчика +* **Множественные подписки (Multiple Subscriptions)** - каждый подписчик получает полную последовательность элементов независимо от других подписчиков +* **Воспроизводимость (Reproducibility)** - каждый подписчик видит одну и ту же последовательность элементов с самого начала, что делает поток воспроизводимым + +#### Пример + +```java +import reactor.core.publisher.Flux; + +public class ColdObservableExample { + + public static void main(String[] args) { + Flux coldFlux = Flux.just("A", "B", "C", "D") + .doOnSubscribe(subscription -> System.out.println("Subscribed to Cold Observable")); + + // First subscription + coldFlux.subscribe(item -> System.out.println("Subscriber 1: " * item)); + + // Second subscription + coldFlux.subscribe(item -> System.out.println("Subscriber 2: " * item)); + } +} +``` + +### Hot Observables + +Начинают выдавать элементы независимо от наличия подписчиков. Подписчики получают только те элементы, которые были отправлены +после их подписки. Это означает, что если подписчик подпишется с опозданием, он пропустит элементы, которые были отправлены до подписки. + +#### Характеристики + +* **Жадное исполнение (Eager Evaluation)** - публикация элементов происходит сразу после создания, даже если подписчиков нет +* **Общий поток данных (Shared Data Stream)** - все подписчики используют один и тот же источник данных и получают элементы, отправленные после подписки +* **Невоспроизводимость (Non-Reproducibility)** - подписчики могут видеть разные части последовательности в зависимости от того, когда они подписались + +#### Пример + +```java +import reactor.core.publisher.Flux; +import reactor.core.publisher.ConnectableFlux; + +import java.time.Duration; + +public class HotObservableExample { + + public static void main(String[] args) throws InterruptedException { + ConnectableFlux hotFlux = Flux.just("A", "B", "C", "D") + .delayElements(Duration.ofMillis(500)) + .publish(); + + // Запускаем публикацию элементов + hotFlux.connect(); + + // Первая подписка (начинает получать данные немедленно) + hotFlux.subscribe(item -> System.out.println("Subscriber 1: " * item)); + Thread.sleep(750); // Ждем отправку элементов + + // Вторая подписка (пропускает первый элемент) + hotFlux.subscribe(item -> System.out.println("Subscriber 2: " * item)); + + // Останавливаем работу основного потока, чтобы увидеть выходные данные + Thread.sleep(2000); + } +} + +``` + +### Ключевые отличия + +| Критерий | Hot Observables | Cold Observables | +|----------------|--------------------------------------------------------|-------------------------------------------------------------------------------------------| +| Обмен данными | Один поток для всех подписчиков | У каждого подписчика свой независимый поток | +| Время подписки | Получает данные в зависимости от времени подписки | Получает все данные, даже если подпишется позже | +| Жизненный цикл | Работает независимо от подписок | Запускает генерацию данных только, когда есть подписка | +| Асинхронность | Может генерировать и передавать данные без подписчиков | Передача данных начинается после подписки, что часто приводит к синхронной передаче | + +### Практическое применение + +Cold Observables полезны для: +* Данные, которые необходимо воспроизвести для каждого подписчика, такие как чтение из файла, выполнение HTTP-запроса или +генерация новой случайной последовательности. +* Сценарии, в которых последовательность элементов должна быть согласованной и воспроизводимой для каждого подписчика. + +Hot Observables полезны для: +* Данные, которые создаются непрерывно и которыми необходимо делиться между несколькими подписчиками, такие как события +мыши, обновления цен на акции или данные датчиков. +* Сценарии, в которых подписчики должны получать только текущие и будущие события, а не прошлые. + +[к оглавлению](#реактивное-программирование) + +## Какова роль Подписки в реактивном программировании? + +Подписка абстрагирует от того, как данные получаются или генерируются + +### Основные функции +`Subscription` обычно предлагает два основных метода: +* **Request** - информирует источник данных о количестве элементов, которые потребитель готов получить +* **Cancel** - останавливает поток данных, освобождая любые ресурсы, такие как обработчики файлов или сетевые подключения + +### Общая концепция +`Subscription` - интерфейс, действующий как соглашение между источником данных и потребителем данных. Он обеспечивает +передачу данных с учетом управления потоком, backpressure и ресурсами. + +### Управление backpressure +Реализации интерфейса `Publisher` в реактивных потоках оценивают готовность подписчика обрабатывать входящие данные +с учетом текущего состояния потока данных. Этот механизм, известный как backpressure, направлен на предотвращение перегрузки +путем указания источнику данных соответствующим образом адаптировать скорость передачи данных. + +`request` - метод интерфейса `Subscription` является основным каналом, по которому подписчик сообщает источнику данных +о своей текущей возможности принимать данные, тем самым регулируя backpressure. + +### Управление ресурсами +Для определенных источников данных, таких как файлы, потоки ввода-вывода или базы данных, могут потребоваться определенные +ресурсы. Интерфейс `Subscription` предоставляет средства для освобождения этих ресурсов, когда передача данных больше не требуется. + +После вызова метода `cancel` источник данных может предпринять соответствующие действия, такие как закрытие файла или +прекращение сетевого взаимодействия. + +[к оглавлению](#реактивное-программирование) + +## Как отписаться от потока для предотвращения утечки памяти? + +* Использовать `Disposable`: получить Disposable из подписки и вызвать метод `dispose`, чтобы отменить ее +* Использовать `BaseSubscriber`: наследоваться от класса BaseSubscriber и вызвать потом метод `dispose` +* Использовать операторы при создании потока: + * `take`: автоматически отменит подписку после получения некоторого количества элементов + * `timeout`: автоматически отменяет подписку, если в течение указанного срока не будет отправлено никаких элементов. + +Best Practice: стоит настраивать отмену подписки, связывая ее с жизненным циклом какого-либо компонента + +[к оглавлению](#реактивное-программирование) + +## Какие есть операторы в Project Reactor и для чего они используются? + +Операторы в реактивном программировании служат для создания, преобразования, фильтрации или объединения различных потоков данных. + +### Операторы создания +* `just`: создает Flux/Mono, который публикует указанные элементы +* `fromArray`: создает поток, который генерирует элементы из массива +* `fromIterable`: создает Flux, который генерирует элементы из итерируемого объекта +* `fromStream`: создает Flux из stream Java +* `fromCallable`: создает Mono из Callable +* `fromRunnable`: создает Mono из Runnable +* `fromSupplier`: создает Mono от Supplier +* `range`: создает FLux, который выдает диапазон целых чисел +* `interval`: создает Flux, который выдает long значения через регулярные промежутки времени +* `empty`: создает пустой Flux/Mono, который завершается немедленно +* `error`: создает Flux/Mono, который немедленно сигнализирует об ошибке +* `never`: создает Flux/Mono, который не создает какой-либо элемент и не завершается +* `defer`: создает новый Flux/Mono для каждой подписки + +### Операторы трансформации +* `map`: преобразует объекты, публикуемые Flux/Mono. +* `flatMap`: преобразует каждый элемент в поток, а затем соединяет их в один поток +* `concatMap`: как flatMap, но поддерживает порядок публикуемых элементов +* `switchMap`: когда он получает данные от нового потока, то сразу отписывается от предыдущего и подписывается на новый +* `scan`: Накапливайте состояние каждого элемента. +* `buffer`: собирает элементы в как список внутри Flux +* `window`: публикует коллекцию элементов как Flux (окно фиксированного размера) внутри Flux +* `groupBy`: группирует элементы по ключу + +### Операторы фильтрации +* `filter`: пропускает только те элементы, которые удовлетворяют условию +* `distinct`: пропускает только уникальные элементы +* `take`: ограничивает количество элементов, публикуемых потоком +* `takeWhile`: публикует элементы, пока условие истинно +* `takeUntil`: публикует элементы, пока условие не станет истинно +* `skip`: пропускает определенное количество элементов в начале потока +* `skipWhile`: пропускает элементы, пока условие истинно +* `skipUntil`: пропускает элементы, пока условие не станет истинно + +### Операторы объединения +* `merge`: объединяет потоки в один параллельно, сохраняя порядок элементов (активная подписка) +* `concat`: объединяет потоки последовательно, ожидая завершения первого потока, затем второго и так далее (отложенная подписка) +* `zip`: объединяет элементы из нескольких потоков в пары +* `combineLatest`: объединяет указанным способом последние значения из нескольких потоков +* `startWith`: добавляет в начало потока к исходным элементам новые элемент(ы) diff --git a/sd.md b/sd.md new file mode 100644 index 0000000..6f7d54b --- /dev/null +++ b/sd.md @@ -0,0 +1,609 @@ +[Вопросы для собеседования](README.md) + +# Проектирование ПО ++ [Что такое _«интернационализация»_, _«локализация»_?](#что-такое-интернационализация-локализация) ++ [Что такое Big O («O большое»)?](#что-такое-big-o-o-большое) ++ [Рассчитайте сложность следующей функции](#рассчитайте-сложность-следующей-функции) ++ [Какие Вы знаете алгоритмы сортировки?](#какие-вы-знаете-алгоритмы-сортировки) ++ [Опишите термин «технический долг»](#опишите-термин-технический-долг) ++ [Что означает «унаследованный код»?](#что-означает-унаследованный-код) ++ [Что такое _UML_?](#что-такое-uml) ++ [Что такое _«диаграмма»_, _«нотация»_ и _«метамодель»_ в UML?](#что-такое-диаграмма-нотация-и-метамодель-в-uml) ++ [Какие существуют типы диаграмм в UML?](#какие-существуют-типы-диаграмм-в-uml) ++ [Какие виды отношений существуют в структурной диаграмме классов в UML?](#какие-виды-отношений-существуют-в-структурной-диаграмме-классов-в-uml) ++ [Что такое SOLID?](#что-такое-solid) ++ [Что такое _«шаблон проектирования»_?](#что-такое-шаблон-проектирования) ++ [Назовите основные характеристики шаблонов](#назовите-основные-характеристики-шаблонов) ++ [Типы шаблонов проектирования](#типы-шаблонов-проектирования) ++ [Приведите примеры основных шаблонов проектирования](#приведите-примеры-основных-шаблонов-проектирования) ++ [Приведите примеры порождающих шаблонов проектирования](#приведите-примеры-порождающих-шаблонов-проектирования) ++ [Приведите примеры структурных шаблонов проектирования](#приведите-примеры-структурных-шаблонов-проектирования) ++ [Приведите примеры поведенческих шаблонов проектирования](#приведите-примеры-поведенческих-шаблонов-проектирования) ++ [Что такое шаблон MVC?](#что-такое-шаблон-mvc) ++ [Что такое GRASP?](#что-такое-grasp) ++ [Что такое _«антипаттерн»_? Какие антипаттерны вы знаете?](#что-такое-антипаттерн-какие-антипаттерны-вы-знаете) ++ [Что такое Domain-driven design?](#что-такое-domain-driven-design) ++ [Какие бывают гарантии доставки сообщений?](#какие-бывают-гарантии-доставки-сообщений) ++ [Расскажите про Event-driven Architecture](#расскажите-про-event-driven-architecture) ++ [Расскажите про Service-oriented Architecture (SOA)?](#расскажите-про-service-oriented-architecture-soa) ++ [Что такое _микросервисы_?](#что-такое-микросервисы) ++ [Расскажите про Enterprise Integration Patterns (EIP)?](#расскажите-про-enterprise-integration-patterns-eip) ++ [Расскажите про Patterns of Enterprise Applications Architecture (PoEAA)?](#расскажите-про-patterns-of-enterprise-applications-architecture-poeaa) ++ [Расскажите про CQRS?](#расскажите-про-cqrs) ++ [Расскажите про Event Sourcing?](#расскажите-про-event-sourcing) ++ [Что такое ACID?](#что-такое-acid) ++ [В чем смысл CAP теоремы?](#в-чем-смысл-cap-теоремы) ++ [Что такое BASE-архитектура?](#что-такое-base-архитектура) ++ [Что такое CRDT?](#что-такое-crdt) + +## Что такое _«интернационализация»_, _«локализация»_? + +__Интернационализация (internationalization)__ - способ создания приложений, при котором их можно легко адаптировать для разных аудиторий, говорящих на разных языках. + +__Локализация (localization)__ - адаптация интерфейса приложения под несколько языков. Добавление нового языка может внести определенные сложности в локализацию интерфейса. + +[к оглавлению](#проектирование-по) + +## Что такое Big O («O большое»)? + +__Big O («O большое»)__ - математическое обозначение для сравнения асимптотического поведения функций. Другими словами в программировании Big O показывает _верхнюю границу_ зависимости между _входными параметрами_ функции и _количеством операций_, которое выполнит процессор. + +При расчёте Big O: + ++ отбрасываем константы и неважную сложность, ++ последовательные действия — сложение, вложенные действия — умножения. + +В алгоритмах, где каждую итерацию берётся половина элементов, сложность будет включать O(log N), так как максимальное количество итераций равно 2^N, +где N - количество элементов. + +Существует также Θ («тета») для точной верхней и нижней оценки, Ω («омега большое») для неточной нижней оценки границы. + +[к оглавлению](#проектирование-по) + +## Рассчитайте сложность следующей функции + +````java +int[] a = int[N]; //N - натуральное число +int s = 0; +for (int i = 0; i < a.length; i++) { + for (int j = i; i < a.length; i++) { + s = i + j; + } +} +```` + +Первый массив O(N), второй массив O(N + (N-1) + (N-2) + ... + 2 + 1), т.е. общий будет равен O (N^2/2). Отбрасывая константы, получаем в итоге __O ( +N^2)__. + +[к оглавлению](#проектирование-по) + +## Какие Вы знаете алгоритмы сортировки? + +В таблице ниже приведены основные виды сортировок и оценка времени выполнения + +| __Название__ | __Лучшее__ | __Среднее__ | __Худшее__ | +|----------------|-------------|----------------|----------------| +| Quicksort | Ω(n log(n)) | Θ(n log(n)) | O(n^2) | +| Mergesort | Ω(n log(n)) | Θ(n log(n)) | O(n log(n)) | +| Timsort | Ω(n) | Θ(n log(n)) | O(n log(n)) | +| Heapsort | Ω(n log(n)) | Θ(n log(n)) | O(n log(n)) | +| Bubble Sort | Ω(n) | Θ(n^2) | O(n^2) | +| Insertion Sort | Ω(n) | Θ(n^2) | O(n^2) | +| Selection Sort | Ω(n^2) | Θ(n^2) | O(n^2) | +| Tree Sort | Ω(n log(n)) | Θ(n log(n)) | O(n^2) | +| Shell Sort | Ω(n log(n)) | Θ(n(log(n))^2) | O(n(log(n))^2) | +| Bucket Sort | Ω(n+k) | Θ(n+k) | O(n^2) | +| Radix Sort | Ω(nk) | Θ(nk) | O(nk) | +| Counting Sort | Ω(n+k) | Θ(n+k) | O(n+k) | +| Cubesort | Ω(n) | Θ(n log(n)) | O(n log(n)) | + + +[к оглавлению](#проектирование-по) + +## Опишите термин «технический долг» + +__Технический долг__ (Technical debt) — это метафора программной инженерии, обозначающая накопленные в программном коде или архитектуре проблемы, связанные с пренебрежением к качеству при разработке программного обеспечения и вызывающие дополнительные затраты труда в будущем. Технический долг обычно незаметен для конечных пользователей продукта, а связан с недостатками в сопровождаемости, тестируемости, понятности, модифицируемости, переносимости. + +Общие причины технического долга (может быть несколько): + ++ _Давление заказчика_, когда требуется выпустить что-то раньше, чем будут сделаны все необходимые изменения, может вылиться в накопление технического + долга. ++ _Отсутствие процессов или понимания_, когда заказчик не имеет понятия о технической задолженности и принимает решения без учёта последствий. ++ _Сильное зацепление компонентов_, когда декомпозиция системы выполнена неправильно или недостаточно гибко, чтобы адаптироваться к изменениям + бизнес-потребностей. ++ _Отсутствие тестов_ — ускоренная разработка и применение быстрых рискованных исправлений («костылей») для исправления ошибок. ++ _Отсутствие взаимодействия между командами_, неэффективное управление знаниями в организации. Например, отсутствие наставничества в команде + разработчиков. ++ _Отложенный рефакторинг_ — чем дольше задерживается рефакторинг, и чем больше написано кода, использующего текущее состояние проекта, тем больше + накапливается технический долг, который нужно "оплатить" при следующем рефакторинге. ++ _Отсутствие опыта_, когда разработчики просто не умеют проектировать программные системы или писать качественный код. + +Рефакторингом называют процедуру переработки внутренней структуры без изменения внешнего контракта, например для снижения технического долга. + +[к оглавлению](#проектирование-по) + +## Что означает «унаследованный код»? + +__Унаследованный код__ (legacy code) нередко употребляется как жаргонное обозначение трудноизменяемого кода, который совершенно непонятен. На самом +деле унаследованный код — это просто код без тестов. + +Изменения в коде делаются двумя основными способами: + ++ _правка наудачу (Edit and Pray)_ ++ _покрытие и модификация (Cover and Modify)_ + +В основу метода Cover and Modify положен принцип работы с «сеткой безопасности». Это своего рода покров из тестов, который мы надеваем на код в +процессе работы, чтобы исключить из него утечку неудачных изменений. Имея в своем распоряжении хороший набор тестов, окружающий фрагмент кода, мы +можем вносить изменения и быстро обнаруживать их положительное или отрицательное воздействие на код. + +[к оглавлению](#проектирование-по) + +## Что такое _UML_? + +__UML__ – это унифицированный графический язык моделирования для описания, визуализации, проектирования и документирования объектно-ориентированных систем. UML призван поддерживать процесс моделирования на основе объектно-ориентированного подхода, организовывать взаимосвязь концептуальных и программных понятий, отражать проблемы масштабирования сложных систем. + +Отличительной особенностью UML является то, что словарь этого языка образуют графические элементы. Каждому графическому символу соответствует конкретная семантика, поэтому модель, созданная одним человеком, может однозначно быть понята другим человеком или программным средством, интерпретирующим UML. Отсюда, в частности, следует, что модель системы, представленная на UML, может автоматически быть переведена на объектно-ориентированный язык программирования, то есть, при наличии хорошего инструментального средства визуального моделирования, поддерживающего UML, построив модель, мы получим и заготовку программного кода, соответствующего этой модели. + +[к оглавлению](#проектирование-по) + +## Что такое _«диаграмма»_, _«нотация»_ и _«метамодель»_ в UML? + +__Диаграмма__ - графическое представление совокупности элементов модели в форме связного графа, вершинам и ребрам (дугам) которого приписывается определенная семантика + +__Нотация__ – совокупность символов и правила их применения, используются для представления понятий и связей между ними. +Нотация диаграммы определяет способ представления, ассоциации, множественности. Причем эти понятия должны быть точно определены. + +__Метамодель__ – диаграмма, определяющая нотацию. +Метамодель помогает понять, что такое хорошо организованная, т.е. синтаксически правильная, модель. + +[к оглавлению](#проектирование-по) + +## Какие существуют типы диаграмм в UML? + +### Структурные диаграммы: + +__классов (Class diagram)__ описывает структуру системы, демонстрирующая классы системы, их атрибуты, методы и зависимости между классами. + +__объектов (Object diagram)__ демонстрирует полный или частичный снимок моделируемой системы в заданный момент времени. На диаграмме объектов отображаются экземпляры классов (объекты) системы с указанием текущих значений их атрибутов и связей между объектами. + +__компонентов (Component diagram)__ показывает разбиение программной системы на структурные компоненты и связи (зависимости) между компонентами. + ++ __развёртывания/размещения (Deployment diagram)__ служит для моделирования работающих узлов и артефактов, развёрнутых на них. + ++ __пакетов (Package diagram)__ используется для организации элементов в группы по какому-либо признаку с целью упрощения структуры и организации работы с моделью системы. + ++ __профилей (Profile diagram)__ действует на уровне метамодели и показывает стереотип класса или пакета. + ++ __композитной/составной структуры (Composite structure diagram)__ демонстрирует внутреннюю структуру класса и, по возможности, взаимодействие элементов (частей) его внутренней структуры. + + + __кооперации (Collaboration diagram)__ показывает роли и взаимодействие классов в рамках кооперации. + +### Диаграммы поведения: + +__деятельности (Activity diagram)__ показывает разложение некоторой деятельности на её составные части. Под деятельностью понимается спецификация исполняемого поведения в виде координированного последовательного и параллельного выполнения подчинённых элементов — вложенных видов деятельности и отдельных действий, соединённых между собой потоками, которые идут от выходов одного узла к входам другого. Диаграммы деятельности используются при моделировании бизнес-процессов, технологических процессов, последовательных и параллельных вычислений. + +__состояний/автомата/конечного автомата (State Machine diagram)__ представляет конечный автомат с простыми состояниями, переходами и композитными состояниями. Конечный автомат (State machine) — спецификация последовательности состояний, через которые проходит объект или взаимодействие в ответ на события своей жизни, а также ответные действия объекта на эти события. Конечный автомат прикреплён к исходному элементу (классу, кооперации или методу) и служит для определения поведения его экземпляров. + +__вариантов использования/прецедентов (Use case diagram)__ отражает отношения существующие между актёрами и вариантами использования. Основная задача — представлять собой единое средство, дающее возможность заказчику, конечному пользователю и разработчику совместно обсуждать функциональность и поведение системы. + +__взаимодействия (Interaction diagram)__: + ++ __коммуникации (Communication diagram)__ изображает взаимодействия между частями композитной структуры или ролями кооперации при этом явно указываются отношения между элементами (объектами), а время как отдельное измерение не используется (применяются порядковые номера вызовов). + ++ __последовательности (Sequence diagram)__ показывает взаимодействия объектов, упорядоченные по времени их проявления. + ++ __обзора взаимодействия (Interaction overview diagram)__ — разновидность диаграммы деятельности, включающая фрагменты диаграммы последовательности и конструкции потока управления. + ++ __синхронизации (Timing diagram)__ — альтернативное представление диаграммы последовательности, явным образом показывающее изменения состояния на линии жизни с заданной шкалой времени. Может быть полезна в приложениях реального времени. + +[к оглавлению](#проектирование-по) + +## Какие виды отношений существуют в структурной диаграмме классов в UML? + +### Взаимосвязи классов + +__Обобщение (Generalization)__ показывает, что один из двух связанных классов (подтип) является частной формой другого (супертипа), который называется обобщением первого. На практике это означает, что любой экземпляр подтипа является также экземпляром супертипа. Обобщение также известно как _наследование_, _«is a» взаимосвязь_ или _отношение «является»_. + +> «Табурет» является подтипом «Мебели». + +__Реализация (Implementation)__ — отношение между двумя элементами модели, в котором один элемент (клиент) реализует поведение, заданное другим (поставщиком). Реализация — отношение целое-часть. Поставщик, как правило, является абстрактным классом или классом-интерфейсом. + +> «Кровать» реализует поведение «Мебели для сна» + +### Взаимосвязи объектов классов + +__Зависимость (Dependency)__ обозначает такое отношение между классами, что изменение спецификации класса-поставщика может повлиять на работу зависимого класса, но не наоборот. + +> «Расписание занятий» имеет зависимость от «Списка предметов». При изменении списка предметов расписание занятий будет вынуждено изменится. Однако изменение расписания занятий никак не влияет на список предметов. + +__Ассоциация (Association)__ показывает, что объекты одной сущности (класса) связаны с объектами другой сущности таким образом, что можно перемещаться от объектов одного класса к другому. Является общим случаем композиции и агрегации. + +> «Студент» и «Университет» имеют ассоциацию т.к. студент может учиться в университете и этой ассоциации можно присвоить имя «учится в». + +__Агрегация (Aggregation)__ — это разновидность ассоциации в отношении между целым и его частями. Как тип ассоциации агрегация может быть именованной. Одно отношение агрегации не может включать более двух классов (контейнер и содержимое). Агрегация встречается, когда один класс является коллекцией или контейнером других. Причём по умолчанию, агрегацией называют агрегацию по ссылке, то есть когда время существования содержащихся классов не зависит от времени существования содержащего их класса. Если контейнер будет уничтожен, то его содержимое — нет. + +> «Студент» не является неотъемлемой частью «Группы», но в то же время, группа состоит из студентов, поэтому следует использовать агрегацию. + +__Композиция (Composition)__ — более строгий вариант агрегации. Известна также как агрегация по значению. Композиция имеет жёсткую зависимость времени существования экземпляров класса контейнера и экземпляров содержащихся классов. Если контейнер будет уничтожен, то всё его содержимое будет также уничтожено. + +> «Факультет» является частью «Университета» и факультет без университета существовать не может, следовательно, здесь подходит композиция. + +### Общие взаимосвязи + +__Зависимость__ — это слабая форма отношения использования, при котором изменение в спецификации одного влечёт за собой изменение другого, причём обратное не обязательно. Возникает, когда объект выступает, например, в форме параметра или локальной переменной. Существует несколько именованных вариантов. Зависимость может быть между экземплярами, классами или экземпляром и классом. + +__Уточнение отношений__ имеет отношение к уровню детализации. Один пакет уточняет другой, если в нём содержатся те же самые элементы, но в более подробном представлении. + +__Мощность/кратность/мультипликатор отношения__ означает число связей между каждым экземпляром класса (объектом) в начале линии с экземпляром класса в её конце. Различают следующие типичные случаи: + +| Нотация | Объяснение | Пример | +|----------|----------------------------|-----------------------------------------------| +| 0..1 | Ноль или один экземпляр | кошка имеет или не имеет хозяина | +| 1 | Обязательно один экземпляр | у кошки одна мать | +| 0..*или* | Ноль или более экземпляров | у кошки могут быть, а может и не быть котят | +| 1..* | Один или более экземпляров | у кошки есть хотя бы одно место, где она спит | + +[к оглавлению](#проектирование-по) + +## Что такое SOLID? + +SOLID (сокр. от англ. single responsibility, open-closed, Liskov substitution, interface segregation и dependency inversion) в программировании — мнемонический акроним, введённый Michael Feathers для первых пяти принципов, названных Робертом Мартином в начале 2000-х, которые означали пять основных принципов объектно-ориентированного программирования и проектирования. При создании программных систем использование принципов SOLID способствует созданию такой системы, которую будет легко поддерживать и расширять в течение долгого времени. Принципы SOLID — это руководства, которые также могут применяться во время работы над существующим программным обеспечением для его улучшения - например для удаления «дурно пахнущего кода». + ++ __Принцип единственной ответственности (The Single Responsibility Principle, SRP)__ — принцип ООП, обозначающий, что каждый объект должен иметь одну ответственность и эта ответственность должна быть полностью инкапсулирована в класс. Все его поведения должны быть направлены исключительно на обеспечение этой ответственности. ++ __При́нцип откры́тости/закры́тости (The Open Closed Principle, OCP)__ - принцип ООП, устанавливающий следующее положение: «программные сущности (классы, модули, функции и т. п.) должны быть открыты для расширения, но закрыты для изменения». ++ __Принцип подстановки Барбары Лисков (Liskov Substitution Principle, LSP)__ - в объектно-ориентированном программировании является специфичным определением подтипа, предложенным Барбарой Лисков в 1987 году на конференции в основном докладе под названием Абстракция данных и иерархия. ++ __Принцип разделения интерфейса (Interface Segregation Principle, ISP)__ - данный принцип говорит, что слишком «толстые» интерфейсы необходимо разделять на более маленькие и специфические, чтобы программные сущности маленьких интерфейсов знали только о методах, которые необходимы им в работе. ++ __Принцип инверсии зависимостей (Dependency inversion principle, DIP)__ - важный принцип объектно-ориентированного программирования, используемый для уменьшения зацепления в компьютерных программах. Является частным случаем «Инверсии контроля» (Inversion of Control). + +[к оглавлению](#проектирование-по) + +## Что такое _«шаблон проектирования»_? + +__Шаблон (паттерн) проектирования (design pattern)__ — это проверенное и готовое к использованию решение. Это не класс и не библиотека, которую можно подключить к проекту, это нечто большее - он не зависит от языка программирования, не является законченным образцом, который может быть прямо преобразован в код и может быть реализован по разному в разных языках программирования. + +Плюсы использования шаблонов: + ++ снижение сложности разработки за счёт готовых абстракций для решения целого класса проблем. ++ облегчение коммуникации между разработчиками, позволяя ссылаться на известные шаблоны. ++ унификация деталей решений: модулей и элементов проекта. ++ возможность отыскав удачное решение, пользоваться им снова и снова. ++ помощь в выборе выбрать наиболее подходящего варианта проектирования. + +Минусы: + ++ слепое следование некоторому выбранному шаблону может привести к усложнению программы. ++ желание попробовать некоторый шаблон в деле без особых на то оснований. + +[к оглавлению](#проектирование-по) + +## Назовите основные характеристики шаблонов + ++ __Имя__ - все шаблоны имеют уникальное имя, служащее для их идентификации; ++ __Назначение__ назначение данного шаблона; ++ __Задача__ - задача, которую шаблон позволяет решить; ++ __Способ решения__ - способ, предлагаемый в шаблоне для решения задачи в том контексте, где этот шаблон был найден; ++ __Участники__ - сущности, принимающие участие в решении задачи; ++ __Следствия__ - последствия от использования шаблона как результат действий, выполняемых в шаблоне; ++ __Реализация__ - возможный вариант реализации шаблона. + +[к оглавлению](#проектирование-по) + +## Типы шаблонов проектирования + ++ Основные (Fundamental) - основные строительные блоки других шаблонов. Большинство других шаблонов использует эти + шаблоны в той или иной форме. ++ Порождающие шаблоны (Creational) — шаблоны проектирования, которые абстрагируют процесс создание экземпляра. Они + позволяют сделать систему независимой от способа создания, композиции и представления объектов. Шаблон, порождающий + классы, использует наследование, чтобы изменять созданный объект, а шаблон, порождающий объекты, делегирует создание + объектов другому объекту. ++ Структурные шаблоны (Structural) определяют различные сложные структуры, которые изменяют интерфейс уже существующих + объектов или его реализацию, позволяя облегчить разработку и оптимизировать программу. ++ Поведенческие шаблоны (Behavioral) определяют взаимодействие между объектами, увеличивая таким образом его гибкость. + +[к оглавлению](#проектирование-по) + +## Приведите примеры основных шаблонов проектирования + ++ __Делегирование (Delegation pattern)__ - Сущность внешне выражает некоторое поведение, но в реальности передаёт + ответственность за выполнение этого поведения связанному объекту. ++ __Функциональный дизайн (Functional design)__ - Гарантирует, что каждая сущность имеет только одну обязанность и + исполняет её с минимумом побочных эффектов на другие. ++ __Неизменяемый интерфейс (Immutable interface)__ - Создание неизменяемого объекта. ++ __Интерфейс (Interface)__ - Общий метод структурирования сущностей облегчающий их понимание. ++ __Интерфейс-маркер (Marker interface)__ - В качестве атрибута (как пометки объектной сущности) применяется наличие или + отсутствие реализации интерфейса-маркера. В современных языках программирования вместо этого применяются атрибуты или + аннотации. ++ __Контейнер свойств (Property container)__ - Позволяет добавлять дополнительные свойства сущности в контейнер внутри + себя, вместо расширения новыми свойствами. ++ __Канал событий (Event channel)__ - Создаёт централизованный канал для событий. Использует сущность-представитель для + подписки и сущность-представитель для публикации события в канале. Представитель существует отдельно от реального + издателя или подписчика. Подписчик может получать опубликованные события от более чем одной сущности, даже если он + зарегистрирован только на одном канале. + +[к оглавлению](#проектирование-по) + +## Приведите примеры порождающих шаблонов проектирования + ++ __Абстрактная фабрика (Abstract factory)__ - Класс, который представляет собой интерфейс для создания других классов. ++ __Строитель (Builder)__ - Класс, который представляет собой интерфейс для создания сложного объекта. ++ __Фабричный метод (Factory method)__ - Делегирует создание объектов наследникам родительского класса. Это позволяет + использовать в коде программы не специфические классы, а манипулировать абстрактными объектами на более высоком + уровне. ++ __Прототип (Prototype)__ - Определяет интерфейс создания объекта через клонирование другого объекта вместо создания + через конструктор. ++ __Одиночка (Singleton)__ - Класс, который может иметь только один экземпляр. + +[к оглавлению](#проектирование-по) + +## Приведите примеры структурных шаблонов проектирования + ++ __Адаптер (Adapter)__ - Объект, обеспечивающий взаимодействие двух других объектов, один из которых использует, а + другой предоставляет несовместимый с первым интерфейс. ++ __Мост (Bridge)__ - Структура, позволяющая изменять интерфейс обращения и интерфейс реализации класса независимо. ++ __Компоновщик (Composite)__ - Объект, который объединяет в себе объекты, подобные ему самому. ++ __Декоратор(Decorator)__ - Класс, расширяющий функциональность другого класса без использования наследования. ++ __Фасад (Facade)__ - Объект, который абстрагирует работу с несколькими классами, объединяя их в единое целое. ++ __Приспособленец (Flyweight)__ - Это объект, представляющий себя как уникальный экземпляр в разных местах программы, + но по факту не являющийся таковым. ++ __Заместитель (Proxy)__ - Объект являющийся посредником между двумя другими объектами и реализующий/ограничивающий + доступ к объекту, к которому обращаются через него. + +[к оглавлению](#проектирование-по) + +## Приведите примеры поведенческих шаблонов проектирования + ++ __Цепочка обязанностей (Chain of responsibility)__ - Предназначен для организации в системе уровней ответственности. ++ __Команда (Command)__ - Представляет действие. Объект команды заключает в себе само действие и его параметры. ++ __Интерпретатор (Interpreter)__ - Решает часто встречающуюся, но подверженную изменениям, задачу. ++ __Итератор(Iterator)__ - Представляет собой объект, позволяющий получить последовательный доступ к элементам + объекта-агрегата без использования описаний каждого + __из объектов, входящих в состав агрегации. ++ __Посредник (Mediator)__ - Обеспечивает взаимодействие множества объектов, формируя при этом слабую связанность и + избавляя объекты от необходимости явно ссылаться друг на друга. ++ __Хранитель (Memento)__ - Позволяет не нарушая инкапсуляцию зафиксировать и сохранить внутренние состояния объекта + так, чтобы позднее восстановить его в этих состояниях. ++ __Наблюдатель(Observer)__ - Определяет зависимость типа «один ко многим» между объектами таким образом, что при + изменении состояния одного объекта все зависящие от него оповещаются об этом событии. ++ __Состояние (State)__ - Используется в тех случаях, когда во время выполнения программы объект должен менять своё + поведение в зависимости от своего состояния. ++ __Стратегия (Strategy)__ - Предназначен для определения семейства алгоритмов, инкапсуляции каждого из них и + обеспечения их взаимозаменяемости. ++ __Шаблонный метод (Template method)__ - Определяет основу алгоритма и позволяет наследникам переопределять некоторые шаги алгоритма, не изменяя его структуру в целом. ++ __Посетитель (Visitor)__ - Описывает операцию, которая выполняется над объектами других классов. При изменении класса Visitor нет необходимости изменять обслуживаемые классы. + +[к оглавлению](#проектирование-по) + +## Что такое шаблон MVC? + +__Model-View-Controller (MVC, «Модель-Представление-Контроллер», «Модель-Вид-Контроллер»)__— схема разделения данных приложения, пользовательского интерфейса и управляющей логики на три отдельных компонента: модель, представление и контроллер — таким образом, что модификация каждого компонента может осуществляться независимо. + ++ __Модель (Model)__ - предоставляет данные и реагирует на команды контроллера, изменяя своё состояние. ++ __Представление (View)__ - отвечает за отображение данных модели пользователю, реагируя на изменения модели. ++ __Контроллер (Controller)__ - интерпретирует действия пользователя, оповещая модель о необходимости изменений. + +[к оглавлению](#проектирование-по) + +## Что такое GRASP? + +__GRASP (англ. general responsibility assignment software patterns)__ — шаблоны, используемые в объектно-ориентированном проектировании для решения общих задач по назначению ответственностей классам и объектам. В книге Крейга Лармана «Применение UML и шаблонов проектирования» описано 9 таких шаблонов: каждый помогает решить некоторую проблему, возникающую как в объектно-ориентированном анализе, так и в практически любом проекте по разработке программного обеспечения. Таким образом, шаблоны «G.R.A.S.P.» — хорошо документированные, стандартизированные и проверенные временем принципы объектно-ориентированного анализа, а не попытка привнести что-то принципиально новое. + ++ __Информационный эксперт (Information Expert)__ - ответственность должна быть назначена тому, кто владеет максимумом необходимой информации для исполнения. Если его не учесть — получится спагетти-код, в котором трудно разобраться. ++ __Создатель (Creator)__ - класс должен создавать экземпляры тех классов, которые он может _содержать или агрегировать_, _записывать_, _использовать_, _инициализировать, имея нужные данные_. ++ __Контроллер (Controller)__ - отвечает за операции, запросы на которые приходят от пользователя, и может выполнять сценарии одного или нескольких вариантов использования (например, создание и удаление). Не выполняет работу самостоятельно, а делегирует компетентным исполнителям. ++ __Слабое зацепление (Low Coupling)__ - мера неотрывности элемента от других элементов (либо мера данных, имеющихся у него о них). ++ __Высокая связность (High Cohesion)__ - мера сфокусированности предметных областей его методов. ++ __Полиморфизм (Polymorphism)__ - [Что такое _«полиморфизм»_?](001-oop.md#Что-такое-полиморфизм). ++ __Чистая выдумка (Pure Fabrication)__ - Не относится к предметной области, но уменьшает зацепление, повышает связность, упрощает повторное использование, отражает концепцию сервисов в модели проблемно-ориентированного проектирования. ++ __Посредник (Indirection)__ - слабое зацепление между элементами системы (и возможность повторного использования) обеспечивается назначением промежуточного объекта их посредником. ++ __Устойчивость к изменениям (Protected Variations)__ - Шаблон защищает элементы от изменения другими элементами (объектами или подсистемами) с помощью вынесения взаимодействия в фиксированный интерфейс, через который (и только через который) возможно взаимодействие между элементами. Поведение может варьироваться лишь через создание другой реализации интерфейса. + +[к оглавлению](#проектирование-по) + +## Что такое _«антипаттерн»_? Какие антипаттерны вы знаете? + +__Антипаттерн (anti-pattern)__ — это распространённый подход к решению класса часто встречающихся проблем, являющийся неэффективным, рискованным или непродуктивным. + +__Poltergeists (полтергейсты)__ - это классы с ограниченной ответственностью и ролью в системе, чьё единственное предназначение — передавать информацию в другие классы. Их эффективный жизненный цикл непродолжителен. Полтергейсты нарушают стройность архитектуры программного обеспечения, создавая избыточные (лишние) абстракции, они чрезмерно запутанны, сложны для понимания и трудны в сопровождении. Обычно такие классы задумываются как классы-контроллеры, которые существуют только для вызова методов других классов, зачастую в предопределенной последовательности. + +Признаки появления и последствия антипаттерна + ++ Избыточные межклассовые связи. ++ Временные ассоциации. ++ Классы без состояния (содержащие только методы и константы). ++ Временные объекты и классы (с непродолжительным временем жизни). ++ Классы с единственным методом, который предназначен только для создания или вызова других классов посредством временной ассоциации. ++ Классы с именами методов в стиле «управления», такие как startProcess. + +Типичные причины + ++ Отсутствие объектно-ориентированной архитектуры (архитектор не понимает объектно-ориентированной парадигмы). ++ Неправильный выбор пути решения задачи. ++ Предположения об архитектуре приложения на этапе анализа требований (до объектно-ориентированного анализа) могут также вести к проблемам на подобии этого антипаттерна. + +__Внесенная сложность (Introduced complexity)__: Необязательная сложность дизайна. Вместо одного простого класса выстраивается целая иерархия интерфейсов и классов. Типичный пример «Интерфейс - Абстрактный класс - Единственный класс реализующий интерфейс на основе абстрактного». + +__Инверсия абстракции (Abstraction inversion)__: Сокрытие части функциональности от внешнего использования, в надежде на то, что никто не будет его использовать. + +__Неопределённая точка зрения (Ambiguous viewpoint)__: Представление модели без спецификации её точки рассмотрения. + +__Большой комок грязи (Big ball of mud)__: Система с нераспознаваемой структурой. + +__Божественный объект (God object)__: Концентрация слишком большого количества функций в одной части системы (классе). + +__Затычка на ввод данных (Input kludge)__: Забывчивость в спецификации и выполнении поддержки возможного неверного ввода. + +__Раздувание интерфейса (Interface bloat)__: Разработка интерфейса очень мощным и очень сложным для реализации. + +__Волшебная кнопка (Magic pushbutton)__: Выполнение результатов действий пользователя в виде неподходящего (недостаточно абстрактного) интерфейса. Например, написание прикладной логики в обработчиках нажатий на кнопку. + +__Перестыковка (Re-Coupling)__: Процесс внедрения ненужной зависимости. + +__Дымоход (Stovepipe System)__: Редко поддерживаемая сборка плохо связанных компонентов. + +__Состояние гонки (Race hazard)__: отсутствие предвидения возможности наступления событий в порядке, отличном от ожидаемого. + +__Членовредительство (Mutilation)__: Излишнее «затачивание» объекта под определенную очень узкую задачу таким образом, что он не способен будет работать с никакими иными, пусть и очень схожими задачами. + +__Сохранение или смерть (Save or die)__: Сохранение изменений лишь при завершении приложения. + +[к оглавлению](#проектирование-по) + +## Что такое Domain-driven design? + +Предметно-ориентированное проектирование (реже проблемно-ориентированное, англ. Domain-driven design, DDD) — это набор принципов и схем, направленных на создание оптимальных систем объектов. Сводится к созданию программных абстракций, которые называются моделями предметных областей. В эти модели входит бизнес-логика, устанавливающая связь между реальными условиями области применения продукта и кодом. Предметно-ориентированное проектирование не является какой-либо конкретной технологией или методологией. DDD — это набор правил, которые позволяют принимать правильные проектные решения. Данный подход позволяет значительно ускорить процесс проектирования программного обеспечения в незнакомой предметной области. Подход DDD особо полезен в ситуациях, когда разработчик не является специалистом в области разрабатываемого продукта. К примеру: программист не может знать все области, в которых требуется создать ПО, но с помощью правильного представления структуры, посредством предметно-ориентированного подхода, может без труда спроектировать приложение, основываясь на ключевых моментах и знаниях рабочей области. + +[к оглавлению](#проектирование-по) + +## Какие бывают гарантии доставки сообщений? + ++ __At-most-once delivery__ (“как максимум однократная доставка”). Это значит, что сообщение не может быть доставлено больше одного раза. При этом сообщение может быть потеряно. ++ __At-least-once delivery__ (“как минимум однократная доставка”). Это значит, что сообщение никогда не будет потеряно. При этом сообщение может быть доставлено более одного раза. ++ __Exactly-once delivery__ (“строго однократная доставка”). Все сообщения доставляются строго единожды. + +[к оглавлению](#проектирование-по) + +## Расскажите про Event-driven Architecture + +__Архитектура, управляемая событиями__ (англ. _event-driven architecture, EDA_) является шаблоном архитектуры программного обеспечения, позволяющим создание, определение, потребление и реакцию на события. + +Событие можно определить как «существенное изменение состояния». Например, когда покупатель приобретает автомобиль, состояние автомобиля изменяется с «продаваемого» на «проданный». Системная архитектура продавца автомобилей может рассматривать это изменение состояния как событие, создаваемое, публикуемое, определяемое и потребляемое различными приложениями в составе архитектуры. + +Этот архитектурный шаблон может применяться при разработке и реализации приложений и систем, передающих события среди слабосвязанных программных компонентов и служб. Система, управляемая событиями, обычно содержит источники событий (или агентов) и потребителей событий (или стоков). Стоки ответственны за ответную реакцию, как только событие возникло. Реакция может полностью или не полностью создаваться стоком. К примеру, сток может отвечать лишь за фильтрацию, преобразование и доставку события другому компоненту, либо он может создать собственную реакцию на это событие. Первая категория стоков может основываться на традиционных компонентах, таких как промежуточное программное обеспечение для обмена сообщениями, а вторая категория стоков (формирующая собственную реакцию в процессе работы) может потребовать наличия более подходящей платформы выполнения транзакций. + +Создание приложений и систем в рамках архитектуры, управляемой событиями, позволяет им быть сконструированными способом, способствующим лучшей интерактивности, поскольку системы, управляемые событиями, по структуре более ориентированы на непредсказуемые и асинхронные окружения. + +Архитектура, управляемая событиями соответствует _сервисно-ориентированной архитектуре (SOA)_, поскольку сервисы могут активироваться триггерами, срабатывающими от входящих событий. + +Эта парадигма особенно полезна в случае, когда сток не предоставляет собственного исполнения действий. + +[к оглавлению](#проектирование-по) + +## Расскажите про Service-oriented Architecture (SOA)? + +__Сервис-ориентированная архитектура__ (англ. _service-oriented architecture, SOA_) — модульный подход к разработке программного обеспечения, основанный на использовании распределённых, слабо связанных (англ. loose coupling) заменяемых компонентов, оснащённых стандартизированными интерфейсами для взаимодействия по стандартизированным протоколам. + +Программные комплексы, разработанные в соответствии с сервис-ориентированной архитектурой, обычно реализуются как набор веб-служб, взаимодействующих по протоколу SOAP, но существуют и другие реализации (например, на базе jini, CORBA, на основе REST). + +Интерфейсы компонентов в сервис-ориентированной архитектуре инкапсулируют детали реализации (операционную систему, платформу, язык программирования) от остальных компонентов, таким образом обеспечивая комбинирование и многократное использование компонентов для построения сложных распределённых программных комплексов, обеспечивая независимость от используемых платформ и инструментов разработки, способствуя масштабируемости и управляемости создаваемых систем. + +[к оглавлению](#проектирование-по) + +## Что такое _микросервисы_? + +__Микросервисная архитектура__ (англ. microservice architecture, MSA) — вариант сервис-ориентированной архитектуры программного обеспечения, направленный на взаимодействие насколько это возможно небольших, слабо связанных и легко изменяемых модулей — _микросервисов_. + +Свойства, характерные для микросервисной архитектуры: + ++ модули можно легко заменить в любое время: акцент на простоту, независимость развёртывания и обновления каждого из микросервисов; ++ модули организованы вокруг функций: микросервис по возможности выполняет только одну достаточно элементарную функцию; ++ модули могут быть реализованы с использованием различных языков программирования, фреймворков, связующего программного обеспечения, выполняться в различных средах контейнеризации, виртуализации, под управлением различных операционных систем на различных аппаратных платформах: приоритет отдаётся в пользу наибольшей эффективности для каждой конкретной функции, нежели стандартизации средств разработки и исполнения; +архитектура симметричная, а не иерархическая: зависимости между микросервисами одноранговые. + +[к оглавлению](#проектирование-по) + +## Расскажите про Enterprise Integration Patterns (EIP)? + +__Шаблоны интеграции корпоративных приложений__ (англ. _enterprise integration patterns, EIP_) состоят из 65 шаблонов, которые описывают использование приложений уровня предприятия и _связующего программное обеспечения, ориентированного на обработку сообщений_ (англ. _message-oriented middleware, MOM_). + +Реализуются такими продуктами, как Spring Integration, Apache Camel, Red Hat Fuse, Mule ESB and Guarana DSL. + +[к оглавлению](#проектирование-по) + +## Расскажите про Patterns of Enterprise Applications Architecture (PoEAA)? + +Каталог архитектурных шаблонов приложений уровня предприятия, состоит из следующих категорий: + ++ __Domain Logic Patterns__ ++ __Data Source Architectural Patterns__ ++ __Object-Relational Behavioral Patterns__ ++ __Object-Relational Structural Patterns__ ++ __Object-Relational Metadata Mapping Patterns__ ++ __Web Presentation Patterns__ ++ __Distribution Patterns__ ++ __Offline Concurrency Patterns__ ++ __Session State Patterns__ ++ __Base Patterns__ + +[к оглавлению](#проектирование-по) + +## Расскажите про CQRS? + +__Разделение ответственности на команды и запросы__ (англ. command-query responsibility segregation, CQRS) — шаблон проектирования для разделения операций чтения и записи, где первый - это запрос, а второй - команда. Команды изменяют состояние и, следовательно, приблизительно эквивалентны вызову метода для агрегатных корней / сущностей. Запрашивает состояние запроса, но не изменяет его. CQRS является производным архитектурным шаблоном из шаблона проектирования под названием «Разделение команд и запросов» (CQS), который был придуман Бертраном Мейером. В то время как CQRS не требует DDD, проектирование на основе домена делает явным различие между командами и запросами вокруг концепции совокупного корня. Идея состоит в том, что данный агрегатный корень имеет метод, соответствующий команде, и обработчик команд вызывает метод в агрегатном корне. Совокупный корень отвечает за выполнение логики операции и выдачу либо количества событий, либо ответа об ошибке (перечисление / номер исключения или результата выполнения) ИЛИ (если не используется Event Sourcing (ES)), просто изменяющего свое состояние для сохранить реализацию, такую ​​как ORM, для записи в хранилище данных, в то время как обработчик команд отвечает за рассмотрение проблем инфраструктуры, связанных с сохранением состояния или событий совокупного корня, и создание необходимых контекстов (например, транзакций). + +[к оглавлению](#проектирование-по) + +## Расскажите про Event Sourcing? + +__(англ. event sourcing, ES)__ - шаблон проектирования, который гарантирует, что ваши сущности (согласно _DDD_) не +отслеживают свое внутреннее состояние посредством прямой сериализации или ORM, а посредством чтения и фиксации событий в +хранилище событий. В тех случаях, когда ES объединяется с CQRS и DDD, совокупные корни отвечают за тщательную проверку и +применение команд (часто с помощью вызова методов их экземпляров из обработчика команд), а затем за публикацию одного +или нескольких событий, которые также являются основой для которые агрегированные корни основывают свою логику для +работы с вызовами методов. Следовательно, входные данные представляют собой команду, а выходные данные представляют +собой одно или несколько событий, которые транзакционно (единая фиксация) сохраняются в хранилище событий, а затем часто +публикуются в брокере сообщений для пользы тех, кто заинтересован (часто представления интересуются; они затем +запрашиваются с помощью Query-сообщений). При моделировании ваших агрегатных корней для выходных событий вы можете +изолировать внутреннее состояние даже дальше, чем это было бы возможно при проецировании данных чтения из ваших +сущностей, как это делается в стандартных n-уровневых архитектурах передачи данных. Одним из существенных преимуществ +этого является то, что такие инструменты, как средства аксиоматической проверки теорем (например, Microsoft Contracts и +CHESS), проще в применении, поскольку совокупный корень полностью скрывает свое внутреннее состояние. События часто +сохраняются в зависимости от версии совокупного корневого экземпляра, что дает модель предметной области, которая +синхронизируется в распределенных системах вокруг концепции оптимистичного параллелизма. + +[к оглавлению](#проектирование-по) + +## Что такое ACID? + +В информатике акроним ACID описывает требования к транзакционной системе (например, к СУБД), обеспечивающие наиболее надёжную и предсказуемую её работу. + ++ __Атомарность (англ. atomicity)__ - гарантирует, что никакая транзакция не будет зафиксирована в системе частично. Будут либо выполнены все её подоперации, либо не выполнено ни одной. Поскольку на практике невозможно одновременно и атомарно выполнить всю последовательность операций внутри транзакции, вводится понятие «отката» (rollback): если транзакцию не удаётся полностью завершить, результаты всех её до сих пор произведённых действий будут отменены и система вернётся во «внешне исходное» состояние — со стороны будет казаться, что транзакции и не было. (Естественно, счётчики, индексы и другие внутренние структуры могут измениться, но, если СУБД запрограммирована без ошибок, это не повлияет на внешнее её поведение.) + ++ __Согласованность (англ. consistency)__. Транзакция, достигающая своего нормального завершения (EOT — end of transaction, завершение транзакции) и, тем самым, фиксирующая свои результаты, сохраняет согласованность базы данных. Другими словами, каждая успешная транзакция по определению фиксирует только допустимые результаты. Это условие является необходимым для поддержки четвёртого свойства. + +Согласованность является более широким понятием. Например, в банковской системе может существовать требование равенства суммы, списываемой с одного счёта, сумме, зачисляемой на другой. Это бизнес-правило и оно не может быть гарантировано только проверками целостности, его должны соблюсти программисты при написании кода транзакций. Если какая-либо транзакция произведёт списание, но не произведёт зачисления, то система останется в некорректном состоянии и свойство согласованности будет нарушено. + +Наконец, ещё одно замечание касается того, что в ходе выполнения транзакции согласованность не требуется. В нашем примере, списание и зачисление будут, скорее всего, двумя разными подоперациями и между их выполнением внутри транзакции будет видно несогласованное состояние системы. Однако не нужно забывать, что при выполнении требования изоляции никаким другим транзакциям эта несогласованность не будет видна. А атомарность гарантирует, что транзакция либо будет полностью завершена, либо ни одна из операций транзакции не будет выполнена. Тем самым эта промежуточная несогласованность является скрытой. + ++ __Изолированность (англ. isolation)__. Во время выполнения транзакции параллельные транзакции не должны оказывать влияния на её результат. Изолированность — требование дорогое, поэтому в реальных БД существуют режимы, не полностью изолирующие транзакцию (уровни изолированности Repeatable Read и ниже). + ++ __Стойкость (англ. durability)__ +Независимо от проблем на нижних уровнях (к примеру, обесточивание системы или сбои в оборудовании) изменения, сделанные успешно завершённой транзакцией, должны остаться сохранёнными после возвращения системы в работу. Другими словами, если пользователь получил подтверждение от системы, что транзакция выполнена, он может быть уверен, что сделанные им изменения не будут отменены из-за какого-либо сбоя. + +[к оглавлению](#проектирование-по) + +## В чем смысл CAP теоремы? + +__Теорема CAP__ — эвристическое утверждение, что в любой реализации распределённых вычислений возможно обеспечить не более двух из трёх следующих свойств: + ++ __C - (англ. consistency) согласованность данных__ — во всех вычислительных узлах в один момент времени данные не противоречат друг другу; ++ __A - (англ. availability) доступность__ — любой запрос к распределённой системе завершается корректным откликом, однако без гарантии, что ответы всех узлов системы совпадают; ++ __P - (англ. partition tolerance) устойчивость к разделению__ — расщепление распределённой системы на несколько изолированных секций не приводит к некорректности отклика от каждой из секций. + +[к оглавлению](#проектирование-по) + +## Что такое BASE-архитектура? + +__BASE (англ. Basically Available, Soft-state, Eventually consistent)__ — базовая доступность, неустойчивое состояние, согласованность в конечном счёте - подход построения распределённых систем. Такой подход напрямую противопоставляется ACID. + ++ __Basically Available (базовая доступность)__ - подразумевается такой подход к проектированию приложения, чтобы сбой в некоторых узлах приводил к отказу в обслуживании только для незначительной части сессий при сохранении доступности в большинстве случаев. ++ __Soft-state (неустойчивое состояние)__ - подразумевает возможность жертвовать долговременным хранением состояния сессий (таких, как промежуточные результаты выборок, информация о навигации, контексте), при этом концентрируясь на фиксации обновлений только критичных операций. ++ __Eventually consistent (согласованность в конечном счёте)__ - трактуется, как возможность противоречивости данных в некоторых случаях, но при обеспечении согласования в практически обозримое время, посвящено значительное количество самостоятельных исследований. + +[к оглавлению](#проектирование-по) + +## Что такое CRDT? + +__Бесконфликтные реплицированные типы данных (англ. Conflict-free replicated data type, CRDT)__ - структуры, в которых обеспечивается сильная согласованность в конечном счёте (англ. strong eventual consistency,SEC) и монотонность состояний. Из известных, описанных в работах и реализованных в библиотеках, есть такие структуры: + ++ __G-Counter__ - (grow-only) монотонно увеличивающийся счётчик ++ __PN-Counter__ - (positive-negative) счётчик, который можно уменьшать ++ __LWW-Register__ - (last-writer-wins) регистр с принципом последняя запись приоритетнее ++ __MV-Register__ - (multi-value) регистр с несколькими значениями ++ __G-Set__ - множество элементов без удаления ++ __2P-Set__ - с приоритетным удалением ++ __PN-Set__ - использует счётчик операций включения-удаления ++ __LWW-Set__ - с приоритетом времени операции ++ __OR-Set__ - (observed-remove) список с идентификаторами + +[к оглавлению](#проектирование-по) + +[Вопросы для собеседования](README.md)