Небольшой оффтоп. Т.к. книжка простая, думал, что напишу пост за 10 минут. По факту неделю не мог собраться с мыслями) Точнее не мог для себя сформулировать, что же я из нее вынес. Книжка же не вода, в целом полезная. Сложно писать о простом)))
Интересно, чем им доклад не угодил?) https://highload.ru/moscow/2022/abstracts/8286 Я бы послушал)
highload.ru
Алексей Салмин на HighLoad++ 2022
В этом докладе я расскажу краткую историю развития ядра веб-поиска Яндекса за последние несколько лет. Основной задачей команды, которая разрабатывает наш движок, можно назвать экономию ресурсов. Экономия не является самостоятельной целью, но при этом имеет…
Всем привет!
Я уже писал, как логирование может влиять на производительность: https://t.me/javaKotlinDevOps/15
Соберу в одном посте несколько важных опций, касающихся быстродействия log4j. Казалось бы логгер, что там может быть сложного, но...
1) Пару слов про то, почему лучше объявлять логгер статической переменной https://logging.apache.org/log4j/2.x/manual/usage.html
2) Две оптимизации касающиеся шаблонов сообщений: строка с параметрами в виде {} вычисляется лениво если включен нужный уровень логирования. Плюс поддержка передачи параметров в виде лямбд позволяет лениво вычислить значение параметра. https://logging.apache.org/log4j/2.x/manual/api.html
Итого конструкции вида if (logger.isTraceEnabled()) становятся не нужны.
3) логирование может быть синхронным и асинхронным. Последнее очевидно быстрее, но у него есть минусы: в случае ошибок сообщения могут терятся без уведомления прикладного кода, под асинхронное логирование нужен отдельный поток. Детали https://logging.apache.org/log4j/2.x/manual/async.html Там же есть сравнение по производительности, и оно впечатляет.
4) Начиная с версии 2.6 log4j переиспользует временные объекты и т.об. уменьшает нагрузку на сборщик мусора: https://logging.apache.org/log4j/2.x/manual/garbagefree.html
По ссылке говорится об ограничениях garbage free режима и есть графики производительности.
5) Логирование в memory-mapped файлы - по сути это область в памяти, за синхронизацию которой на диск отвечает ОС. https://logging.apache.org/log4j/2.x/manual/appenders.html#MemoryMappedFileAppender
Ну и сравнение производительности с logback и разных Appenders https://logging.apache.org/log4j/2.x/performance.html
P.S. Бросается в глаза, что авторы библиотеки начиная с версии 2 заморочились с производительностью. Куча графиков, статей
#logging #log4j
Я уже писал, как логирование может влиять на производительность: https://t.me/javaKotlinDevOps/15
Соберу в одном посте несколько важных опций, касающихся быстродействия log4j. Казалось бы логгер, что там может быть сложного, но...
1) Пару слов про то, почему лучше объявлять логгер статической переменной https://logging.apache.org/log4j/2.x/manual/usage.html
2) Две оптимизации касающиеся шаблонов сообщений: строка с параметрами в виде {} вычисляется лениво если включен нужный уровень логирования. Плюс поддержка передачи параметров в виде лямбд позволяет лениво вычислить значение параметра. https://logging.apache.org/log4j/2.x/manual/api.html
Итого конструкции вида if (logger.isTraceEnabled()) становятся не нужны.
3) логирование может быть синхронным и асинхронным. Последнее очевидно быстрее, но у него есть минусы: в случае ошибок сообщения могут терятся без уведомления прикладного кода, под асинхронное логирование нужен отдельный поток. Детали https://logging.apache.org/log4j/2.x/manual/async.html Там же есть сравнение по производительности, и оно впечатляет.
4) Начиная с версии 2.6 log4j переиспользует временные объекты и т.об. уменьшает нагрузку на сборщик мусора: https://logging.apache.org/log4j/2.x/manual/garbagefree.html
По ссылке говорится об ограничениях garbage free режима и есть графики производительности.
5) Логирование в memory-mapped файлы - по сути это область в памяти, за синхронизацию которой на диск отвечает ОС. https://logging.apache.org/log4j/2.x/manual/appenders.html#MemoryMappedFileAppender
Ну и сравнение производительности с logback и разных Appenders https://logging.apache.org/log4j/2.x/performance.html
P.S. Бросается в глаза, что авторы библиотеки начиная с версии 2 заморочились с производительностью. Куча графиков, статей
#logging #log4j
Telegram
(java || kotlin) && devOps
Всем привет! Есть такое правило - в логах в ПРОДе не должно быть ничего лишнего. Т.е. с одной стороны логи нужны для хранения стек-трейса исключения и другой полезной при разборе ошибки информации. Есть много инструментов, позволяющих строить по логам метрики…
Всем привет!
В разработке сейчас много хайповых понятий, те же микросервисы, Service Mesh, GitOps, Serverless. Обо всем этом как-нибудь напишу, а сегодня пару мыслей про Cloud Native.
Если подумать, то для того, чтобы сделать native приложение для облака, нужно не так уж много.
1) k8s должен как-то понимать, что приложение поднялось и может принимать траффик. Для этого облачный сервис должен реализовать probes, они же healthchecks.
https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/
Вообще их три, но в случае простейшего приложения хватит одной - liveness. Остальные две нужны если приложение долго стартует - startup или может быть недоступно в процессе работы - readyness.
2) облачное приложение не должно долго стартовать. Причина: k8s при добавлении новых нод или подов, или изменения их настроек Anti-affinity (возможности совместной работы на одной ноде) в любой момент может погасить под и поднять его на другом сервере. Да, можно указать startup probe чтобы траффик не шел на долго стартующее приложение. Можно указать maxUnavailable https://kubernetes.io/docs/tasks/run-application/configure-pdb/ для того, чтобы k8s оставлял запас подов при изменении их численности. Но все это обходные пути. Если вспомнить про Spring Boot, то я бы сказал что ему есть куда расти в плане оптимизации, не зря сейчас растет популярность его альтернатив, стартующих существенно быстрее: Quarkus, Micronaut, Helidon и использования native images.
3) cloud native приложение не должно зависеть от локального состояния - кэширования данных локально. Все критичные для работы данные должны хранится или в storage, или на клиенте. Причина все та же - k8s в любой момент может поднять под на другом сервере, локальный кэш при этом теряется.
4) для cloud native приложения крайне рекомендуется отбрасывать метрики и поддерживать distributed tracing - https://opentelemetry.io/docs/concepts/what-is-opentelemetry/. Причина: перенос в облако упрощает разработку, как правило идет рука об руку с микросервисами, следовательно, сервисов становится существенно больше, следовательно, должны быть инструменты для отслеживания их состояния и более точного понимания, где проблема.
Что на мой взгляд не относится к критичным требованиям для Cloud native приложений.
1) поддержка Docker. В Docker можно засунуть практически любое приложение, есть куча официальных образов. Даже IBM Websphere и WildFly, хотя использование их в облаке выглядит странным) Вижу проблему только с Windows native приложениями, но их остается не так уже много
2) поддержка внутри приложения cloud \ fault tolerance функций: circuit breakers, retries, timeouts, service discovery. Например, этот функционал реализуется в Spring Cloud библиотеке. Почему так? Потому что в связке k8s + service mesh все эти функции можно реализовать на уровне облака. Не хочу сказать, что Spring Cloud и его аналоги не нужны, но точно не обязательны для облака.
3) использование REST API. С одной стороны для HTTP траффика k8s + service mesh дает больше возможностей по маршрутизации, но с другой стороны tcp трафик тоже маршрутизируется.
#cloud_native #microservices #spring_boot #tracing
В разработке сейчас много хайповых понятий, те же микросервисы, Service Mesh, GitOps, Serverless. Обо всем этом как-нибудь напишу, а сегодня пару мыслей про Cloud Native.
Если подумать, то для того, чтобы сделать native приложение для облака, нужно не так уж много.
1) k8s должен как-то понимать, что приложение поднялось и может принимать траффик. Для этого облачный сервис должен реализовать probes, они же healthchecks.
https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/
Вообще их три, но в случае простейшего приложения хватит одной - liveness. Остальные две нужны если приложение долго стартует - startup или может быть недоступно в процессе работы - readyness.
2) облачное приложение не должно долго стартовать. Причина: k8s при добавлении новых нод или подов, или изменения их настроек Anti-affinity (возможности совместной работы на одной ноде) в любой момент может погасить под и поднять его на другом сервере. Да, можно указать startup probe чтобы траффик не шел на долго стартующее приложение. Можно указать maxUnavailable https://kubernetes.io/docs/tasks/run-application/configure-pdb/ для того, чтобы k8s оставлял запас подов при изменении их численности. Но все это обходные пути. Если вспомнить про Spring Boot, то я бы сказал что ему есть куда расти в плане оптимизации, не зря сейчас растет популярность его альтернатив, стартующих существенно быстрее: Quarkus, Micronaut, Helidon и использования native images.
3) cloud native приложение не должно зависеть от локального состояния - кэширования данных локально. Все критичные для работы данные должны хранится или в storage, или на клиенте. Причина все та же - k8s в любой момент может поднять под на другом сервере, локальный кэш при этом теряется.
4) для cloud native приложения крайне рекомендуется отбрасывать метрики и поддерживать distributed tracing - https://opentelemetry.io/docs/concepts/what-is-opentelemetry/. Причина: перенос в облако упрощает разработку, как правило идет рука об руку с микросервисами, следовательно, сервисов становится существенно больше, следовательно, должны быть инструменты для отслеживания их состояния и более точного понимания, где проблема.
Что на мой взгляд не относится к критичным требованиям для Cloud native приложений.
1) поддержка Docker. В Docker можно засунуть практически любое приложение, есть куча официальных образов. Даже IBM Websphere и WildFly, хотя использование их в облаке выглядит странным) Вижу проблему только с Windows native приложениями, но их остается не так уже много
2) поддержка внутри приложения cloud \ fault tolerance функций: circuit breakers, retries, timeouts, service discovery. Например, этот функционал реализуется в Spring Cloud библиотеке. Почему так? Потому что в связке k8s + service mesh все эти функции можно реализовать на уровне облака. Не хочу сказать, что Spring Cloud и его аналоги не нужны, но точно не обязательны для облака.
3) использование REST API. С одной стороны для HTTP траффика k8s + service mesh дает больше возможностей по маршрутизации, но с другой стороны tcp трафик тоже маршрутизируется.
#cloud_native #microservices #spring_boot #tracing
Kubernetes
Configure Liveness, Readiness and Startup Probes
This page shows how to configure liveness, readiness and startup probes for containers.
For more information about probes, see Liveness, Readiness and Startup Probes
The kubelet uses liveness probes to know when to restart a container. For example, liveness…
For more information about probes, see Liveness, Readiness and Startup Probes
The kubelet uses liveness probes to know when to restart a container. For example, liveness…
Всем привет!
Сегодня короткое ревью на книжку Непрерывное развитие API. https://habr.com/ru/company/piter/blog/472522/
Несмотря на многообещающее название - не понравилась.
Слишком менеджерская и "капитанская".
По технике практически ноль.
Приведу несколько идей, достаточно полезных, чтобы примерно было понятно, о чем речь:
1) рассматривайте API как продукт, есть компании, где API - единственный продукт: Twillo, Stripe
2) в первую версию API надо вкладывать больше усилий, потом можно ее непрерывно улучшать небольшими шагами, Lean, Agile, все как мы любим)
3) документация для API важна, особенно примеры использования, также для больших организаций полезен реестр API и инструменты для тестирования типа тех, что предоставляет Swagger https://editor.swagger.io/
4) тестируйте создаваемое API со стороны клиента, это поможет лучше его спроектировать
5) мониторьте боевые сервера API как на предмет ошибок, так и для сбора общей статистики по числу запросов, времени выполенния, типичным последовательностям запросов. Возможно постоянно повторяющиеся последовательности вызовов можно заменить одним.
6) с ростом организации централизовано реализовывать API невозможно, поэтому большУю часть решений нужно отдавать в команды. Централизовано имеет смысл отбирать список допустимых протоколов\технологий, и, возможно, согласование и тестирование API
7) ключевые решения по API должны примимать опытные разработчики
8) во внешнее API стоит вкладывать больше усилий, чем во внутреннее
9) автоматизация тестирования API требует больших затрат на разработку и поддержку как и любая автоматизация, но в целом полезна
10) API должно помогать достижению целей организации, можно использовать KPI и OKR для определения, достигает ли API поставленных целей. Вот на этом шаге и бросил читать)
Итого: верхнеуровнево есть правильные мысли, но с практическая ценность маленькая. Не рекомендую.
#books #api
Сегодня короткое ревью на книжку Непрерывное развитие API. https://habr.com/ru/company/piter/blog/472522/
Несмотря на многообещающее название - не понравилась.
Слишком менеджерская и "капитанская".
По технике практически ноль.
Приведу несколько идей, достаточно полезных, чтобы примерно было понятно, о чем речь:
1) рассматривайте API как продукт, есть компании, где API - единственный продукт: Twillo, Stripe
2) в первую версию API надо вкладывать больше усилий, потом можно ее непрерывно улучшать небольшими шагами, Lean, Agile, все как мы любим)
3) документация для API важна, особенно примеры использования, также для больших организаций полезен реестр API и инструменты для тестирования типа тех, что предоставляет Swagger https://editor.swagger.io/
4) тестируйте создаваемое API со стороны клиента, это поможет лучше его спроектировать
5) мониторьте боевые сервера API как на предмет ошибок, так и для сбора общей статистики по числу запросов, времени выполенния, типичным последовательностям запросов. Возможно постоянно повторяющиеся последовательности вызовов можно заменить одним.
6) с ростом организации централизовано реализовывать API невозможно, поэтому большУю часть решений нужно отдавать в команды. Централизовано имеет смысл отбирать список допустимых протоколов\технологий, и, возможно, согласование и тестирование API
7) ключевые решения по API должны примимать опытные разработчики
8) во внешнее API стоит вкладывать больше усилий, чем во внутреннее
9) автоматизация тестирования API требует больших затрат на разработку и поддержку как и любая автоматизация, но в целом полезна
10) API должно помогать достижению целей организации, можно использовать KPI и OKR для определения, достигает ли API поставленных целей. Вот на этом шаге и бросил читать)
Итого: верхнеуровнево есть правильные мысли, но с практическая ценность маленькая. Не рекомендую.
#books #api
Хабр
Книга «Непрерывное развитие API. Правильные решения в изменчивом технологическом ландшафте»
Для реализации API необходимо провести большую работу. Чрезмерное планирование может стать пустой тратой сил, а его недостаток приводит к катастрофическим последствиям. В этой книге вы получите...
2022-11-23_13-13-49.png
42.8 KB
Всем привет! Недавно IDEA подсказала мне интересную фичу - построение UML диаграмм для класса. Показывает родителей, интерфейсы и аннотации. IMHO полезная фича. На скрине пример из нашего CI pipeline. Комбинация клавиш Ctrl+Alt+Shift+U или ⌥ ⇧ ⌘ U Детали здесь https://www.jetbrains.com/help/idea/class-diagram.html?keymap=secondary_macos И снова советую не выключать или включить если выключена "подсказку дня": Help -> Tip of the day #IDEA
Всем привет!
Пару слов про на мой взгляд достаточно важную, но часто недооцененную штуку, как комментарии к commit-ам в git. На самом деле к любой Version Control System, но у нас же на 95+% git)))
Что должно быть:
1) комментарии обязательны
2) в теле комментария должен быть тикет, по которому ведутся работы. В начале текста комментария. В идеале - один тикет. Если правка одной строки исправляет несколько багов\закрывает несколько задач - то лучше закрыть лишние тикеты как дубликаты. Если не хочется заводить тикет на каждый чих - можно завести и использовать тикет типа "мелкие правки"
3) любой комментарий должен быть содержательным, т.е. описывать суть изменений. Лучше не привязваться к именам файлов\классов, т.к. они меняются при рефакторинге, а оперировать понятиями предметной области
4) по длине рекомендую сильно не увлекаться, ограничиваться одной или несколькими фразами. Заодно и сommit-ы будут более атомарными, проще будет revert-ть.
5) формат сommit должен быть единообразным, можно даже контролировать это на сервере. Т.к. по моему опыту без контроля сложно придерживаться единообразия, периодически проскакивают неформатные комментарии)
6) конечная цель комментариев - чтобы список commit-ов нес полезную информацию и его можно было использовать как changelist сервиса
7) следствие из предыдущего пункта - можно и нужно использовать amend для слияния нескольких commit-ов в один. Единственное исключение - если ваш git server синхронизируется, в другую подсеть например, и синхронизация ломается при amend. Опять же при односторонней синхронизации проблему решить можно.
8) следующий уровень - перед созданием Pull request\Merge request можно отрефакторить список commit-ов - переименовать, слить несколько из середины. IDEA позволяет все это сделать. Также можно хардкорно, через коммандную строку с помощью rebase - https://habr.com/ru/post/201922/ С одной стороны так мы становится на путь перфекционизма, но помнить о такой возможности надо)
9) Описание формата commit должно быть в readme.md проекта
Отдельно хочу сказать про язык комментариев. Есть мнение о необходимости английского - я с ним не согласен. По желанию команды. Все-таки не все в совершенстве владеют английским, как среди текущих разработчиков сервиса, так и среди будущих. А читаемость прежде всего!) Да, в английском нет родов у глаголов, поэтому с ним проще. В русском лучшим вариантом кажется использовать стадательный залог - "сделано то-то". Добавление рода или числа - сделал\сделали\сделала - кажется лишней информацией.
Также отдельная тема - нужны ли какие-то специальные обозначения в commit message. Например, алиас для тип изменений: фича, багфикс, рефакторинг, конфиги, тесты. Или указание модуля, где менялся код. Считаю, что не обязательно, но может быть полезно.
#git #code_review
Пару слов про на мой взгляд достаточно важную, но часто недооцененную штуку, как комментарии к commit-ам в git. На самом деле к любой Version Control System, но у нас же на 95+% git)))
Что должно быть:
1) комментарии обязательны
2) в теле комментария должен быть тикет, по которому ведутся работы. В начале текста комментария. В идеале - один тикет. Если правка одной строки исправляет несколько багов\закрывает несколько задач - то лучше закрыть лишние тикеты как дубликаты. Если не хочется заводить тикет на каждый чих - можно завести и использовать тикет типа "мелкие правки"
3) любой комментарий должен быть содержательным, т.е. описывать суть изменений. Лучше не привязваться к именам файлов\классов, т.к. они меняются при рефакторинге, а оперировать понятиями предметной области
4) по длине рекомендую сильно не увлекаться, ограничиваться одной или несколькими фразами. Заодно и сommit-ы будут более атомарными, проще будет revert-ть.
5) формат сommit должен быть единообразным, можно даже контролировать это на сервере. Т.к. по моему опыту без контроля сложно придерживаться единообразия, периодически проскакивают неформатные комментарии)
6) конечная цель комментариев - чтобы список commit-ов нес полезную информацию и его можно было использовать как changelist сервиса
7) следствие из предыдущего пункта - можно и нужно использовать amend для слияния нескольких commit-ов в один. Единственное исключение - если ваш git server синхронизируется, в другую подсеть например, и синхронизация ломается при amend. Опять же при односторонней синхронизации проблему решить можно.
8) следующий уровень - перед созданием Pull request\Merge request можно отрефакторить список commit-ов - переименовать, слить несколько из середины. IDEA позволяет все это сделать. Также можно хардкорно, через коммандную строку с помощью rebase - https://habr.com/ru/post/201922/ С одной стороны так мы становится на путь перфекционизма, но помнить о такой возможности надо)
9) Описание формата commit должно быть в readme.md проекта
Отдельно хочу сказать про язык комментариев. Есть мнение о необходимости английского - я с ним не согласен. По желанию команды. Все-таки не все в совершенстве владеют английским, как среди текущих разработчиков сервиса, так и среди будущих. А читаемость прежде всего!) Да, в английском нет родов у глаголов, поэтому с ним проще. В русском лучшим вариантом кажется использовать стадательный залог - "сделано то-то". Добавление рода или числа - сделал\сделали\сделала - кажется лишней информацией.
Также отдельная тема - нужны ли какие-то специальные обозначения в commit message. Например, алиас для тип изменений: фича, багфикс, рефакторинг, конфиги, тесты. Или указание модуля, где менялся код. Считаю, что не обязательно, но может быть полезно.
#git #code_review
Хабр
Изменение коммитов в Git
Это пост для тех, кто начинает работу с Git. Все, что здесь написано по частям можно найти в многочисленных простынях о Git на Хабре. Но я подумал, что неплохо было бы иметь отдельный предельно...
Всем привет!
Интересная статья про динамическую перезагрузку properties https://www.baeldung.com/spring-reloading-properties в Java приложении.
Два варианта:
1) Apache Сommons Сonfiguration
2) Spring Cloud
Первое работает через отслеживание изменений в файле, второе - управляемое извне перечитывание после вызова /refresh endpoint.
#java #cloud #spring_boot
Интересная статья про динамическую перезагрузку properties https://www.baeldung.com/spring-reloading-properties в Java приложении.
Два варианта:
1) Apache Сommons Сonfiguration
2) Spring Cloud
Первое работает через отслеживание изменений в файле, второе - управляемое извне перечитывание после вызова /refresh endpoint.
#java #cloud #spring_boot
Baeldung
Reloading Properties Files in Spring | Baeldung
Learn a few approaches to getting property values to reload in Spring Beans, including Spring Cloud's refresh scope.
Привет! В новом поиске Яндекса обещают много чего интересного, но т.к блог про разработку - радует улучшенный поиск для разработчиков https://ya.ru/y2 Вот тут подробнее от разработчиков https://habr.com/ru/company/yandex/blog/688952/ Нейросети рулят!) P.S. Надо будет сравнить с Гуглом.
Y2 — новая версия поиска Яндекса
Теперь в Яндексе можно создавать детские аккаунты, смотреть иностранные видео сразу на русском и решать повседневные задачи ещё быстрее. Главная страница и приложение тоже совершенно новые: они сфокусированы именно на поиске, поэтому в них нет ничего лишнего.
Всем привет! Возвращаясь к сравнению поиска Яндекс и Google. См. скриншоты ниже. На первом месте у обоих stackoverflow, ответы сгрупированы, причем первый в списке совпадает. На втором скажем так "авторитетный" сайт, сайты разные. На третьем у обоих официальная документация, причем одна и та же статья по содержанию, хотя и из разных разделов. Из явных различий: у Яндекса вместился четвертый ответ, а у Google виден блок "похожие запросы", которого нет у Яндекса. Ну и результатов у Google побольше, но это логично) #search
Всем привет!
Я подозреваю почти все знают и используют такой фреймворк, как Mockito. По крайней мере судя по собеседованиям, которые я провожу и коду, который вижу)
Наверняка все знают mock, spy, when(...).thenAnswer.
Но я хотел бы рассказать про ряд его малоизвестных особенностей:
1) можно создавать тестовые двойники через Mockito.mock или Mockito.spy, а можно воспользоваться аннотациями над полями класса: @Mock и @Spy, главное не забыть вызвать MockitoAnnotations.openMocks(testClass); перед каждым вызовом тестового метода
2) Mockito с версии 2 научился mock-ать final методы и классы
3) Mockito также научился mock-ать static методы. Что ж, PowerMock теперь не нужен) Да, остаются private методы, но во-первых я бы их не тестировал, а во-вторых если очень надо - есть рефлексия
4) через verify можно делать сложные проверки поведения: что методы какого-то класса не вызывались, что вызывались только определенные методы класса и ничего более, сколько раз вызывался метод, с какими аргументами. Здесь главное не переборщить и не сделать тест слишком хрупким. Разделять тестирование бизнес-процесса и детали реализации
5) с помощью ArgumentCaptor можно захватить содержимое передаваемого в mock параметра и проанализировать его отдельными assert-ами. Полезно для сложных объектов или для анализа содержимого строки
6) как известно, двойники, созданные с помощью mock, по умолчанию не возвращают ничего при вызове метода, т.к. вызова не происходит. Можно захардкодить ответ в помощью Mockito.when(...).thenReturn. Но если нужно вернуть значение в зависимости от входных параметров, а настраивать реальный объект не хочется - есть два варианта: создать наследника интерфейса Answer, где в методе answer сформировать ответ, либо сделать то же самое c использованием Streams API и Mockito.when(...).thenAnswer
Когда искал ссылки для поста, нашел отличную статью, где описываются практически все описанные выше лайфхаки: https://habr.com/ru/post/444982
Ну разве что кроме mock static https://www.baeldung.com/mockito-mock-static-methods и возврата сложного ответа из mock при помощи Answer https://www.baeldung.com/mockito-mock-methods
Пост будет дополняться полезными фичами по мере их нахождения)
Как говорить читать не перечитать https://www.javadoc.io/doc/org.mockito/mockito-core/latest/org/mockito/Mockito.html
Stay tuned)
#unittest #mockito
Я подозреваю почти все знают и используют такой фреймворк, как Mockito. По крайней мере судя по собеседованиям, которые я провожу и коду, который вижу)
Наверняка все знают mock, spy, when(...).thenAnswer.
Но я хотел бы рассказать про ряд его малоизвестных особенностей:
1) можно создавать тестовые двойники через Mockito.mock или Mockito.spy, а можно воспользоваться аннотациями над полями класса: @Mock и @Spy, главное не забыть вызвать MockitoAnnotations.openMocks(testClass); перед каждым вызовом тестового метода
2) Mockito с версии 2 научился mock-ать final методы и классы
3) Mockito также научился mock-ать static методы. Что ж, PowerMock теперь не нужен) Да, остаются private методы, но во-первых я бы их не тестировал, а во-вторых если очень надо - есть рефлексия
4) через verify можно делать сложные проверки поведения: что методы какого-то класса не вызывались, что вызывались только определенные методы класса и ничего более, сколько раз вызывался метод, с какими аргументами. Здесь главное не переборщить и не сделать тест слишком хрупким. Разделять тестирование бизнес-процесса и детали реализации
5) с помощью ArgumentCaptor можно захватить содержимое передаваемого в mock параметра и проанализировать его отдельными assert-ами. Полезно для сложных объектов или для анализа содержимого строки
6) как известно, двойники, созданные с помощью mock, по умолчанию не возвращают ничего при вызове метода, т.к. вызова не происходит. Можно захардкодить ответ в помощью Mockito.when(...).thenReturn. Но если нужно вернуть значение в зависимости от входных параметров, а настраивать реальный объект не хочется - есть два варианта: создать наследника интерфейса Answer, где в методе answer сформировать ответ, либо сделать то же самое c использованием Streams API и Mockito.when(...).thenAnswer
Когда искал ссылки для поста, нашел отличную статью, где описываются практически все описанные выше лайфхаки: https://habr.com/ru/post/444982
Ну разве что кроме mock static https://www.baeldung.com/mockito-mock-static-methods и возврата сложного ответа из mock при помощи Answer https://www.baeldung.com/mockito-mock-methods
Пост будет дополняться полезными фичами по мере их нахождения)
Как говорить читать не перечитать https://www.javadoc.io/doc/org.mockito/mockito-core/latest/org/mockito/Mockito.html
Stay tuned)
#unittest #mockito
Хабр
Mockito и как его готовить
О статье Перед вами очередное руководство по Mockito. В нём я, с одной стороны, попытался описать функционал этой библиотеки так, чтобы незнакомый с нею читатель сразу получил возможность полноценно...
Всем привет!
Небольшая заметка, пример как рождаются унифицирующие стандарты в разработке.
Этапы развития распределенной трассировки - очень полезной технологии для отслеживания пути запроса между микросервисами, о которой я уже несколько раз писал:
1) появляются разные реализации трассировки, самые известные - Jaeger и Zipkin
2) в 2016 году создается независимый от вендора стандарт для клиентских библиотек создания трейсов и отправки данных трейсинга во внешнее хранилище - OpenTracing. В качестве хранилищ поддерживаются те же Jaeger и Zipkin. Под эгидой Google в 2017 году параллельно создается еще один, менее известный - OpenCensus
3) OpenTracing и OpenCensus объединяются в 2019 году в OpenTelemetry. https://opentelemetry.io/docs/concepts/what-is-opentelemetry/#hello-opentelemetry
Появляется также промежуточный слой collectors для маршрутизации и балансировки данных трассировки https://opentelemetry.io/docs/concepts/data-collection/
Причем под телеметрией понимаются не только трассировка, но и сбор метрик.
Естественно есть библиотека для Java.
Вроде бы конец истории...
4) Ребята из Micrometer, создавшие ранее фасад для отправки метрик в JVM приложениях, также решили "прибрать к рукам" :) и tracing, в 2022 году появляется Micrometer Tracing. Spring Boot 3, недавно вышедший, оперативно объявляет о его поддержке https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-3.0-Release-Notes. Судя по декларированной цели https://micrometer.io/docs/tracing#_purpose - не все еще используют OpenTelemetry, поэтому нужен новый фасад.
Что смущает. С одной стороны Micrometer Tracing вводит новый уровень абстракции: разделяет процессы создания трейса (tracer) и отправки его в хранилища (reporter) и, соответственно, поддерживает разные tracers и reporters. Это стандартный путь развития любой технологии.
С другой стороны он дублирует функционал OpenTelemetry, и новый уровень абстракции выглядит излишним.
Как говорится, будем посмотреть, что в итоге приживется. Spring Boot - конечно весомый козырь
P.S. Рекомендую ознакомится с терминологией распределенной трассировки - https://micrometer.io/docs/tracing#_glossary
И пара примеров внедрения:
https://habr.com/ru/company/ru_mts/blog/537892/
https://habr.com/ru/company/hh/blog/686414/
#tracing
Небольшая заметка, пример как рождаются унифицирующие стандарты в разработке.
Этапы развития распределенной трассировки - очень полезной технологии для отслеживания пути запроса между микросервисами, о которой я уже несколько раз писал:
1) появляются разные реализации трассировки, самые известные - Jaeger и Zipkin
2) в 2016 году создается независимый от вендора стандарт для клиентских библиотек создания трейсов и отправки данных трейсинга во внешнее хранилище - OpenTracing. В качестве хранилищ поддерживаются те же Jaeger и Zipkin. Под эгидой Google в 2017 году параллельно создается еще один, менее известный - OpenCensus
3) OpenTracing и OpenCensus объединяются в 2019 году в OpenTelemetry. https://opentelemetry.io/docs/concepts/what-is-opentelemetry/#hello-opentelemetry
Появляется также промежуточный слой collectors для маршрутизации и балансировки данных трассировки https://opentelemetry.io/docs/concepts/data-collection/
Причем под телеметрией понимаются не только трассировка, но и сбор метрик.
Естественно есть библиотека для Java.
Вроде бы конец истории...
4) Ребята из Micrometer, создавшие ранее фасад для отправки метрик в JVM приложениях, также решили "прибрать к рукам" :) и tracing, в 2022 году появляется Micrometer Tracing. Spring Boot 3, недавно вышедший, оперативно объявляет о его поддержке https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-3.0-Release-Notes. Судя по декларированной цели https://micrometer.io/docs/tracing#_purpose - не все еще используют OpenTelemetry, поэтому нужен новый фасад.
Что смущает. С одной стороны Micrometer Tracing вводит новый уровень абстракции: разделяет процессы создания трейса (tracer) и отправки его в хранилища (reporter) и, соответственно, поддерживает разные tracers и reporters. Это стандартный путь развития любой технологии.
С другой стороны он дублирует функционал OpenTelemetry, и новый уровень абстракции выглядит излишним.
Как говорится, будем посмотреть, что в итоге приживется. Spring Boot - конечно весомый козырь
P.S. Рекомендую ознакомится с терминологией распределенной трассировки - https://micrometer.io/docs/tracing#_glossary
И пара примеров внедрения:
https://habr.com/ru/company/ru_mts/blog/537892/
https://habr.com/ru/company/hh/blog/686414/
#tracing
OpenTelemetry
What is OpenTelemetry?
A short explanation of what OpenTelemetry is, and is not.
Всем привет!
Надеюсь все уже перешли на JUnit 5?
У JUnit 5 много крутых фич по сравнению с 4-й версией, например:
1) более удобная работа с параметризованными тестами через @ParametrizedTest, который вешается на метод - можно миксовать параметризированные и непараметризированные тесты в одном тестовом классе
2) возможность параметризировать не только входные параметры, но и все остальное в тесте с помощью динамически генерируемых тестов DynamicTests https://www.baeldung.com/junit5-dynamic-tests
3) есть возможность проверки исключений и таймаута через методы - assertThrows и assertTimeout. Это более правильно - assert идет после Act (я про Arrange-Act-Assert) и позволяет делать несколько проверок в одном тестовом методе
4) условное выполнение тестов в зависимости от среды: @EnabledOnOs, @EnabledOnJre, @EnabledIfSystemProperty, @EnabledIfEnvironmentVariable, также можно создавать свои условия
5) @RepeatedTest для повтора теста N раз
6) @DisplayName - полезно для задания говорящего имени теста для параметризированных тестов, к примеру
7) @Nested для складывания тестовых классов в "матрешку". Полезно, если у часть тестов нужно выполнить отнаследовавшись от базового класса
8) assertAll - объединение нескольких assert-ов в тесте. Полезно, как способ отключить fail fast режим проверок в JUnit - прогнать все assert-ы в тесте несмотря на падение одного из них.
9) ну и наконец механизм extensions. В 4-й версии был механизм Runner-ов, но его ограничение состояло в том, что на класс можно было повесить один Runner. А extensions может быть сколько угодно. Вот пример реализации BDD с помощью extension https://www.infoq.com/articles/deep-dive-junit5-extensions/ Здесь же есть пример 3-го способа параметризации теста - через ParameterResolver.
10) кроме всего прочего механизм extension добавляет store - контекст для обмена данными между тестами. Важно: для модульных тестов это антипаттерн, но нормально для интеграционных https://junit.org/junit5/docs/5.0.0/api/org/junit/jupiter/api/extension/ExtensionContext.Store.html
11) указание очередности тестов через @Order - полезно для тестирования отдельных шагов в интеграционном тесте. По умолчанию, кстати, тесты запускаются в алфавитном порядке https://www.baeldung.com/junit-5-test-order
В общем JUnit 5 догнал и перегнал TestNG, рекомендую к использованию если еще не пробовали.
#junit #unittests
Надеюсь все уже перешли на JUnit 5?
У JUnit 5 много крутых фич по сравнению с 4-й версией, например:
1) более удобная работа с параметризованными тестами через @ParametrizedTest, который вешается на метод - можно миксовать параметризированные и непараметризированные тесты в одном тестовом классе
2) возможность параметризировать не только входные параметры, но и все остальное в тесте с помощью динамически генерируемых тестов DynamicTests https://www.baeldung.com/junit5-dynamic-tests
3) есть возможность проверки исключений и таймаута через методы - assertThrows и assertTimeout. Это более правильно - assert идет после Act (я про Arrange-Act-Assert) и позволяет делать несколько проверок в одном тестовом методе
4) условное выполнение тестов в зависимости от среды: @EnabledOnOs, @EnabledOnJre, @EnabledIfSystemProperty, @EnabledIfEnvironmentVariable, также можно создавать свои условия
5) @RepeatedTest для повтора теста N раз
6) @DisplayName - полезно для задания говорящего имени теста для параметризированных тестов, к примеру
7) @Nested для складывания тестовых классов в "матрешку". Полезно, если у часть тестов нужно выполнить отнаследовавшись от базового класса
8) assertAll - объединение нескольких assert-ов в тесте. Полезно, как способ отключить fail fast режим проверок в JUnit - прогнать все assert-ы в тесте несмотря на падение одного из них.
9) ну и наконец механизм extensions. В 4-й версии был механизм Runner-ов, но его ограничение состояло в том, что на класс можно было повесить один Runner. А extensions может быть сколько угодно. Вот пример реализации BDD с помощью extension https://www.infoq.com/articles/deep-dive-junit5-extensions/ Здесь же есть пример 3-го способа параметризации теста - через ParameterResolver.
10) кроме всего прочего механизм extension добавляет store - контекст для обмена данными между тестами. Важно: для модульных тестов это антипаттерн, но нормально для интеграционных https://junit.org/junit5/docs/5.0.0/api/org/junit/jupiter/api/extension/ExtensionContext.Store.html
11) указание очередности тестов через @Order - полезно для тестирования отдельных шагов в интеграционном тесте. По умолчанию, кстати, тесты запускаются в алфавитном порядке https://www.baeldung.com/junit-5-test-order
В общем JUnit 5 догнал и перегнал TestNG, рекомендую к использованию если еще не пробовали.
#junit #unittests
Baeldung
Guide to Dynamic Tests in Junit 5 | Baeldung
Learn about dynamic tests introduced in JUnit 5 - a new programming model that supports full test lifecycle.
Всем привет!
Пару мыслей о BDD фреймворках, самым известным представителем которых является Cucumber.
Пример теста на Cucumber, чтобы было понятно о чем я:
Scenario: Eric wants to withdraw money from his bank account at an ATM
Given Eric has a valid Credit or Debit card
And his account balance is $100
When he inserts his card
And withdraws $45
Then the ATM returns $45
And his account balance is $55
Т.е по сути мы привязываем к методам в коде фразы естественного языка и т.об. можем написать тест как осмысленное предложение.
Мне не понятно, где это может быть полезно.
Основная трудность в BDD - требуется большая подготовительная работа по созданию "словаря", из которого будут конструироваться тесты. Причем если приложение сложное и развивается - работа становится постоянной. Вопрос - а нужно ли делать эту работу?
Рассмотрим возможные случаи использования.
1) разработчики для написания "системных" тестов, проверяющих сервис целиком? Не нужно, разработчику проще написать на обычном JUnit 5, максимум добавить туда Rest Assured как удобным способ в fluent стиле написать тест c четко выделенными стадиями Arrage-Act-Assert "в одну строчку". Оффтоп: почему я слово "в одну строчку" взял в кавычки думаю понятно, а вот насчет "системных" - с терминологией в классификации тестов все плохо, причем когда я начал эту тему изучать лет 6 назад - все было также))) Решение я вижу - определить терминологию в своей команде и ее придерживаться.
2) автотестеры, интеграционное тестирование, тестирование на заглушках, регресс? Как по мне если тестировщик решил перейти в касту автотестеров, то разбираться в Java или Kotlin он должен. Ну или в любом другом языке, где есть хороший тестовый фреймворк. И в DevOps немножко. Очень сложно сделать такую платформу для автотестов, где этих знаний не понадобится.
3) ручные тестировщики? Если тестировщик не хочет в автоматизацию, то я не верю, что BDD может чем-то помочь. Если не прав - хотелось бы узнать про такие кейсы. Снова оффтоп: тестировщик, который не хочет в автоматизацию, не равно плохой тестировщик. Есть роль тест-менеджера, определяющего полноту набора тест-кейсов, состав регресса, пишущего сценарии, и т.об. гарантирующий соответствие кода требованиям. Есть исследовательское тестирование, где автоматизация играет вспомогательную роль.
4) нагрузочное тестирование? Точно не про то: использовать или нет BDD - далеко не та проблема, которая важна для НТ. Профит не понятен
5) системные аналитики? Те, которых я видел "в живой природе", тесты не пишут. У них и так работы хватает: API, схема БД, сиквенс диаграммы, карта экранов, согласования, впитывание и трансформация мыслей продактов...
6) приемочные испытания. Тут развилка. Если мы говорим о приемке внутри одной организации - по моему опыту заинтересованные лица валидируют аналитику заранее, и приемка сводится к демострации и ответах на каверзные вопросы. Возможен прогон тех же автотестов, что и на стадии интеграционного тестирования. И наконец единственный кейс, где BDD может рулить - приемка на стороне организации-заказчика. Для них поставляемое ПО - черный ящик. И то, если процесс не по Agile, и заказчик в процессах команды разработки не участвует.
И еще небольшой гвоздик напоследок - сделать словарь для BDD легко, когда в нем 5-10-20 фраз. Т.е для небольшого приложения. А когда их станет не хватать? Тогда или нужная тяжелая работа по вычистке, универсализации, или словарь станет примитивным - оправь http запрос, прочитай заголовок ответа, а в этом случае BDD становится бесполезным.
#unittests #bdd #testing
Пару мыслей о BDD фреймворках, самым известным представителем которых является Cucumber.
Пример теста на Cucumber, чтобы было понятно о чем я:
Scenario: Eric wants to withdraw money from his bank account at an ATM
Given Eric has a valid Credit or Debit card
And his account balance is $100
When he inserts his card
And withdraws $45
Then the ATM returns $45
And his account balance is $55
Т.е по сути мы привязываем к методам в коде фразы естественного языка и т.об. можем написать тест как осмысленное предложение.
Мне не понятно, где это может быть полезно.
Основная трудность в BDD - требуется большая подготовительная работа по созданию "словаря", из которого будут конструироваться тесты. Причем если приложение сложное и развивается - работа становится постоянной. Вопрос - а нужно ли делать эту работу?
Рассмотрим возможные случаи использования.
1) разработчики для написания "системных" тестов, проверяющих сервис целиком? Не нужно, разработчику проще написать на обычном JUnit 5, максимум добавить туда Rest Assured как удобным способ в fluent стиле написать тест c четко выделенными стадиями Arrage-Act-Assert "в одну строчку". Оффтоп: почему я слово "в одну строчку" взял в кавычки думаю понятно, а вот насчет "системных" - с терминологией в классификации тестов все плохо, причем когда я начал эту тему изучать лет 6 назад - все было также))) Решение я вижу - определить терминологию в своей команде и ее придерживаться.
2) автотестеры, интеграционное тестирование, тестирование на заглушках, регресс? Как по мне если тестировщик решил перейти в касту автотестеров, то разбираться в Java или Kotlin он должен. Ну или в любом другом языке, где есть хороший тестовый фреймворк. И в DevOps немножко. Очень сложно сделать такую платформу для автотестов, где этих знаний не понадобится.
3) ручные тестировщики? Если тестировщик не хочет в автоматизацию, то я не верю, что BDD может чем-то помочь. Если не прав - хотелось бы узнать про такие кейсы. Снова оффтоп: тестировщик, который не хочет в автоматизацию, не равно плохой тестировщик. Есть роль тест-менеджера, определяющего полноту набора тест-кейсов, состав регресса, пишущего сценарии, и т.об. гарантирующий соответствие кода требованиям. Есть исследовательское тестирование, где автоматизация играет вспомогательную роль.
4) нагрузочное тестирование? Точно не про то: использовать или нет BDD - далеко не та проблема, которая важна для НТ. Профит не понятен
5) системные аналитики? Те, которых я видел "в живой природе", тесты не пишут. У них и так работы хватает: API, схема БД, сиквенс диаграммы, карта экранов, согласования, впитывание и трансформация мыслей продактов...
6) приемочные испытания. Тут развилка. Если мы говорим о приемке внутри одной организации - по моему опыту заинтересованные лица валидируют аналитику заранее, и приемка сводится к демострации и ответах на каверзные вопросы. Возможен прогон тех же автотестов, что и на стадии интеграционного тестирования. И наконец единственный кейс, где BDD может рулить - приемка на стороне организации-заказчика. Для них поставляемое ПО - черный ящик. И то, если процесс не по Agile, и заказчик в процессах команды разработки не участвует.
И еще небольшой гвоздик напоследок - сделать словарь для BDD легко, когда в нем 5-10-20 фраз. Т.е для небольшого приложения. А когда их станет не хватать? Тогда или нужная тяжелая работа по вычистке, универсализации, или словарь станет примитивным - оправь http запрос, прочитай заголовок ответа, а в этом случае BDD становится бесполезным.
#unittests #bdd #testing
Всем привет!
На каких принципах постороены современные высокопроизводительные системы?
Не претендую на полный список, но попробую собрать основные архитектурные принципы с примерами реализующих их систем.
1) shared nothing - каждый запрос на обновление пользовательских данных обрабатывается одним (!) экземпляром сервиса. Пропадает необходимость в распределенных транзакциях или использовании паттерна "Сага", и т.об. повышается скорость и надежность. Технически это горизонтальное масштабирование сервиса\балансировщиков\проксей плюс шардирование хранилища и кэша Примеры: Kafka, Kafka Streams, Spark, Terradata, Hadoop, Solr, ElasticSearch... На примере Kafka: каждый брокер получает свою долю партиций - частей на которые делятся топики - и отвечает за чтение, запись из них, а также репликацию данных. Да, всему кластеру Kafka приходится шарить метаданные о расположении партиций на брокерах - в Zookepper в текущих версиях и в специальных топиках с метаданными в последней версии. И да, ответственный за патрицию может меняться. Но за запросы к пользовательским данным в партиции в каждый момент времени отвечает один брокер, на остальные брокеры эта информация только реплицируется. Репликация проходит асинхронно, без привязки к запросу клиента. Еще примеры: https://dimosr.github.io/shared-nothing-architectures/
2) data locality - данные хранятся на той же ноде, где проходят вычисления. Нет лишних сетевых запросов - быстрее обработка данных. Примеры: Kafka Streams, Spark, Hadoop. На примере Kafka Streams - любые методы, агрегирующие и трансформирующие данные стрима, работают только с данными из тех партиций Kafka, которые лежат на локальной машине. Только так получится добиться приемлемой производительности поточной обработки данных (streaming) в распределенной системе.
3) append-only или log-based storage - данные сохраняются добавлением записи в файл, никаких обновлений и удалений на уровне записей не происходит, файлы ротируются, устаревшие файлы удаляются целиком. Где-то рядом хранится указатель на текущую запись в файле. Т.к последовательная запись на порядок быстрее случайной, то append-only сильно ускоряет запись. Примеры: снова Kafka, Hadoop, Lucene, этот же принцип лежит в основе техник write-ahead logging (WAL) в журналах упреждающей записи СУБД и CQRS + Event Sourcing. Немного о последней: https://www.baeldung.com/cqrs-event-sourcing-java . И о том, как работает WAL https://habr.com/ru/company/postgrespro/blog/459250/ И о том, как Kafka сохраняет данные: https://mbukowicz.github.io/kafka/2020/05/31/how-kafka-stores-messages.html
4) zero-copy - в общем случае данные при чтении из диска и к примеру отправке по сети копируются в памяти несколько раз из буфера в буфер. Почему? Потому что буферы у файлового драйвера, у сетевого драйвера и у Java разные. Но этого можно избежать и работать с данными из буфера ОС, если они не меняются вашим сервисом или меняются, но используются одним процессом. Естественно это ускоряет работу с данными. zero copy должен поддерживаться на уровне ОС, Linux поддерживает. Примеры использования: опять Kafka. Как это работает в Kafka https://andriymz.github.io/kafka/kafka-disk-write-performance/ Про zero copy в Java я упоминал в https://t.me/javaKotlinDevOps/17, вот тут детальнее https://shawn-xu.medium.com/its-all-about-buffers-zero-copy-mmap-and-java-nio-50f2a1bfc05c
to be continued
P.S. Во всех 4 пунктах упоминается Kafka, и это не случайность)
#arch #Kafka #performance
На каких принципах постороены современные высокопроизводительные системы?
Не претендую на полный список, но попробую собрать основные архитектурные принципы с примерами реализующих их систем.
1) shared nothing - каждый запрос на обновление пользовательских данных обрабатывается одним (!) экземпляром сервиса. Пропадает необходимость в распределенных транзакциях или использовании паттерна "Сага", и т.об. повышается скорость и надежность. Технически это горизонтальное масштабирование сервиса\балансировщиков\проксей плюс шардирование хранилища и кэша Примеры: Kafka, Kafka Streams, Spark, Terradata, Hadoop, Solr, ElasticSearch... На примере Kafka: каждый брокер получает свою долю партиций - частей на которые делятся топики - и отвечает за чтение, запись из них, а также репликацию данных. Да, всему кластеру Kafka приходится шарить метаданные о расположении партиций на брокерах - в Zookepper в текущих версиях и в специальных топиках с метаданными в последней версии. И да, ответственный за патрицию может меняться. Но за запросы к пользовательским данным в партиции в каждый момент времени отвечает один брокер, на остальные брокеры эта информация только реплицируется. Репликация проходит асинхронно, без привязки к запросу клиента. Еще примеры: https://dimosr.github.io/shared-nothing-architectures/
2) data locality - данные хранятся на той же ноде, где проходят вычисления. Нет лишних сетевых запросов - быстрее обработка данных. Примеры: Kafka Streams, Spark, Hadoop. На примере Kafka Streams - любые методы, агрегирующие и трансформирующие данные стрима, работают только с данными из тех партиций Kafka, которые лежат на локальной машине. Только так получится добиться приемлемой производительности поточной обработки данных (streaming) в распределенной системе.
3) append-only или log-based storage - данные сохраняются добавлением записи в файл, никаких обновлений и удалений на уровне записей не происходит, файлы ротируются, устаревшие файлы удаляются целиком. Где-то рядом хранится указатель на текущую запись в файле. Т.к последовательная запись на порядок быстрее случайной, то append-only сильно ускоряет запись. Примеры: снова Kafka, Hadoop, Lucene, этот же принцип лежит в основе техник write-ahead logging (WAL) в журналах упреждающей записи СУБД и CQRS + Event Sourcing. Немного о последней: https://www.baeldung.com/cqrs-event-sourcing-java . И о том, как работает WAL https://habr.com/ru/company/postgrespro/blog/459250/ И о том, как Kafka сохраняет данные: https://mbukowicz.github.io/kafka/2020/05/31/how-kafka-stores-messages.html
4) zero-copy - в общем случае данные при чтении из диска и к примеру отправке по сети копируются в памяти несколько раз из буфера в буфер. Почему? Потому что буферы у файлового драйвера, у сетевого драйвера и у Java разные. Но этого можно избежать и работать с данными из буфера ОС, если они не меняются вашим сервисом или меняются, но используются одним процессом. Естественно это ускоряет работу с данными. zero copy должен поддерживаться на уровне ОС, Linux поддерживает. Примеры использования: опять Kafka. Как это работает в Kafka https://andriymz.github.io/kafka/kafka-disk-write-performance/ Про zero copy в Java я упоминал в https://t.me/javaKotlinDevOps/17, вот тут детальнее https://shawn-xu.medium.com/its-all-about-buffers-zero-copy-mmap-and-java-nio-50f2a1bfc05c
to be continued
P.S. Во всех 4 пунктах упоминается Kafka, и это не случайность)
#arch #Kafka #performance
A curious mind
Shared-nothing architectures
An overview of shared-nothing architectures, their pros and cons
Всем привет!
Еще один широиспользуемый паттерн, более низкого уровня, чем описанные ранее: LMAX Disruptor.
https://lmax-exchange.github.io/disruptor/disruptor.html
Это готовая библиотека, решающая следующую задачу: есть упорядоченная очередь из каких-то данных, пишет в нее один поток, обрабатывать данные нужно в несколько потоков без блокировок. Реализована в виде кольцевого буфера и набора указателей на текущую ячейку буфера, по одному для каждого потока-читателя\писателя. В каждый момент времени в буфер пишет один поток, блокировки не ставятся, каждый поток может прочитать указатели других потоков и т.об. понять, с какими ячейками можно работать. Библиотеку достаточно хорошо пиарят, даже сам Мартин Фаулер: https://martinfowler.com/articles/lmax.html Использует log4j https://logging.apache.org/log4j/2.x/manual/async.html#UnderTheHood
Но вернемся к более общим архитектурным принципам: при реализации этой библиотеки используется принцип Mechanical Sympathy https://www.baeldung.com/lmax-disruptor-concurrency#1-mechanical-sympathy.
Суть его в следующем: хотя язык программирования и JVM в случае Java скрывают от нас кишочки компьютера - регистры процессора, кэши процессора 1,2,3 уровня, особенности работы процессора - для максимальной производительности их нужно учитывать. На примере LMAX Disruptor:
1) кольцевой буфер позволяет переиспользовать объекты в куче, уменьшая нагрузку на Garbage Collector
2) кольцевой буфер выделяется одним "куском", поэтому использует последовательные адреса в памяти, что ускоряет пакетное чтение из буфера - как за счет собственно последовательного чтения, так и зачет упреждающего кэширования процессором
3) одновременная запись в память приводит к взаимным сбросам кэша у различных ядер процессора, что плохо сказывается на производительности. В LMAX Disruptor, как я уже говорил, в каждый момент времени пишет в буфер один поток.
Все это вместе с отсутствием блокировок приводит к хорошей производительности.
Но к слову есть люди, считающие библиотеку слишком распиаренной - см. комментарии к статье https://dev.cheremin.info/2011/09/disruptor-1.html
#patterns #library
Еще один широиспользуемый паттерн, более низкого уровня, чем описанные ранее: LMAX Disruptor.
https://lmax-exchange.github.io/disruptor/disruptor.html
Это готовая библиотека, решающая следующую задачу: есть упорядоченная очередь из каких-то данных, пишет в нее один поток, обрабатывать данные нужно в несколько потоков без блокировок. Реализована в виде кольцевого буфера и набора указателей на текущую ячейку буфера, по одному для каждого потока-читателя\писателя. В каждый момент времени в буфер пишет один поток, блокировки не ставятся, каждый поток может прочитать указатели других потоков и т.об. понять, с какими ячейками можно работать. Библиотеку достаточно хорошо пиарят, даже сам Мартин Фаулер: https://martinfowler.com/articles/lmax.html Использует log4j https://logging.apache.org/log4j/2.x/manual/async.html#UnderTheHood
Но вернемся к более общим архитектурным принципам: при реализации этой библиотеки используется принцип Mechanical Sympathy https://www.baeldung.com/lmax-disruptor-concurrency#1-mechanical-sympathy.
Суть его в следующем: хотя язык программирования и JVM в случае Java скрывают от нас кишочки компьютера - регистры процессора, кэши процессора 1,2,3 уровня, особенности работы процессора - для максимальной производительности их нужно учитывать. На примере LMAX Disruptor:
1) кольцевой буфер позволяет переиспользовать объекты в куче, уменьшая нагрузку на Garbage Collector
2) кольцевой буфер выделяется одним "куском", поэтому использует последовательные адреса в памяти, что ускоряет пакетное чтение из буфера - как за счет собственно последовательного чтения, так и зачет упреждающего кэширования процессором
3) одновременная запись в память приводит к взаимным сбросам кэша у различных ядер процессора, что плохо сказывается на производительности. В LMAX Disruptor, как я уже говорил, в каждый момент времени пишет в буфер один поток.
Все это вместе с отсутствием блокировок приводит к хорошей производительности.
Но к слову есть люди, считающие библиотеку слишком распиаренной - см. комментарии к статье https://dev.cheremin.info/2011/09/disruptor-1.html
#patterns #library
lmax-exchange.github.io
LMAX Disruptor: High performance alternative to bounded queues for exchanging data between concurrent threads
Всем привет!
Возвращаясь к Kotlin и переходу на него с Java.
Может возникнуть вопрос - как начать писать в стиле Kotlin?
Ответ - начни с официальной документации.
Ключевые отличия от Java по мнению авторов: https://kotlinlang.org/docs/comparison-to-java.html
Идиомы - часто используемые куски кода, можно сказать низкоуровневые паттерны языка: https://kotlinlang.org/docs/idioms.html
Coding conventions https://kotlinlang.org/docs/coding-conventions.html
Примеры кода от авторов языка: https://play.kotlinlang.org/byExample/01_introduction/01_Hello%20world
Migration guide с Java https://kotlinlang.org/docs/java-to-kotlin-idioms-strings.html
P.S. Надо было раньше этот пост написать)
P.P.S Документацию иногда стоит почитать)
P....S А для самых хардкорных - как известно Kotlin написан на Kotlin. https://github.com/JetBrains/kotlin
#java #kotlin
Возвращаясь к Kotlin и переходу на него с Java.
Может возникнуть вопрос - как начать писать в стиле Kotlin?
Ответ - начни с официальной документации.
Ключевые отличия от Java по мнению авторов: https://kotlinlang.org/docs/comparison-to-java.html
Идиомы - часто используемые куски кода, можно сказать низкоуровневые паттерны языка: https://kotlinlang.org/docs/idioms.html
Coding conventions https://kotlinlang.org/docs/coding-conventions.html
Примеры кода от авторов языка: https://play.kotlinlang.org/byExample/01_introduction/01_Hello%20world
Migration guide с Java https://kotlinlang.org/docs/java-to-kotlin-idioms-strings.html
P.S. Надо было раньше этот пост написать)
P.P.S Документацию иногда стоит почитать)
P....S А для самых хардкорных - как известно Kotlin написан на Kotlin. https://github.com/JetBrains/kotlin
#java #kotlin
GitHub
GitHub - JetBrains/kotlin: The Kotlin Programming Language.
The Kotlin Programming Language. . Contribute to JetBrains/kotlin development by creating an account on GitHub.
Всем привет!
Снова про Kotlin.
Возможно не все знают, что в Kotlin изобрели свои стримы - sequences https://kotlinlang.org/docs/sequences.html#sequence.
Зачем? Во-первых есть Kotlin/JS и Kotlin/Native, где нет JDK и стримов. А еще Kotlin может работать на Java 6.
А во-вторых - реализация стримов сделана под Java, что приводит к более сложному API, чем "принято" в Kotlin и проблемами с null safety из-за использования типов Java под капотом. Но у стримов есть и плюсы) Сравнение см. https://proandroiddev.com/java-streams-vs-kotlin-sequences-c9ae080abfdc
P.S. Есть некая ирония в том, что стримы, которые сильно упрощают код Java, выглядят все же более тяжеловесно по сравнению с реализацией в Kotlin)
#kotlin #java
Снова про Kotlin.
Возможно не все знают, что в Kotlin изобрели свои стримы - sequences https://kotlinlang.org/docs/sequences.html#sequence.
Зачем? Во-первых есть Kotlin/JS и Kotlin/Native, где нет JDK и стримов. А еще Kotlin может работать на Java 6.
А во-вторых - реализация стримов сделана под Java, что приводит к более сложному API, чем "принято" в Kotlin и проблемами с null safety из-за использования типов Java под капотом. Но у стримов есть и плюсы) Сравнение см. https://proandroiddev.com/java-streams-vs-kotlin-sequences-c9ae080abfdc
P.S. Есть некая ирония в том, что стримы, которые сильно упрощают код Java, выглядят все же более тяжеловесно по сравнению с реализацией в Kotlin)
#kotlin #java
Medium
Java Streams vs. Kotlin Sequences
Java streams are available to use in Kotlin when targeting JDK 8 or later for backend applications. A common question is whether to use…
Всем привет!
Давно хотел написать про основные модели ветвления при работе c исходным кодом.
Итак поехали!
1) великий и ужасный gitflow.
Картинка: https://habrastorage.org/r/w1560/webt/ah/aw/yf/ahawyfcuk_rids2mljkuocattzg.jpeg
Описание: https://github.com/SergeFocus/git-flow
Думаю, многие его знают, но на всякий случай напомню суть.
Основная работа ведется в фичных ветках, для багов есть специальные bugfix ветки. Все они вливаются в develop через Pull Request\Merge request. Для выпуска на ПРОД создается релизная ветка, код из которой после выхода на ПРОД попадает в master. Для выпуска hotfix также предусмотрены отдельные ветки.
Почему gitflow "великий":
а) дает контроль над тем, что и когда попадет в релиз. Поэтому любим в enterprise.
б) хорошо подходит для opensource проектов, т.к. там как правило много релизов и есть внешние коммитеры, качество кода которых нужно контролировать
в) дисциплинирует разработчиков
Почему "ужасный":
а) слишком громоздкий, т.к. master и hotfix ветки часто выглядят излишними
б) работа в фичных ветках может приводить к накоплению там большого количества кода и, следовательно, увеличивает вероятность конфликта при слиянии. Причем чем больше становится ветка, тем сложнее ее влить - и для автора из-за конфликтов, и для ревьюверов из-за объема кода. И сам принцип фичных веток на это провоцирует. Этакая положительная обратная связь, положительная в том смысле, что усиливает сложность вливания с каждым днем и каждой строчкой кода.
в) при плавной раскате на ПРОМ не понятно, в какой момент код должен попадать в master. Ведь в течение периода раскатки, а это может быть неделя +, на ПРОМ будет 2 версии. Кроме того, в этом случае о вливании в master часто забывают, т.к. все равно все работают с develop.
2) модификация gitflow с несколькими develop ветками. Может применяться в больших компаниях, когда критически важно, чтобы код той или иной фичи не попал в релиз Х без явного согласования, а feature toggle не аргумент)
Либо при переходе на новую версию платформы, когда код разных develop просто не совместим. Важная практическая особенность - git не позволит создать ветку develop/2.0 при наличии просто develop, т.к. у них одинаковый префикс. Поэтому лучше заранее определиться с моделью.
Хотя конечно всегда можно достичь требуемого с помощью создания промежуточных веток.
3) github flow. Как следует из названия придумана на GitHub-е, доступна на нем из коробки.
Картинка: https://user-images.githubusercontent.com/6351798/48032310-63842400-e114-11e8-8db0-06dc0504dcb5.png
Детали: https://docs.github.com/ru/get-started/quickstart/github-flow
По сравнению с gitflow сильно упрощена: выброшены develop, hotfix, release, bugfix, оставлены 2 типа веток: master и feature и Pull Request.
Для обозначения релизов можно использовать тэги, напомню, в git tag и branch технически одинаковы, разница лишь в UI того же Bitbucket, Github, Gitlab.
Плюсы:
а) очень простая модель
Минусы:
а) master нужно поддерживать в production ready состоянии -> feature toggles, модульные тесты и дисциплина в команде
#git #vcs #branching
Давно хотел написать про основные модели ветвления при работе c исходным кодом.
Итак поехали!
1) великий и ужасный gitflow.
Картинка: https://habrastorage.org/r/w1560/webt/ah/aw/yf/ahawyfcuk_rids2mljkuocattzg.jpeg
Описание: https://github.com/SergeFocus/git-flow
Думаю, многие его знают, но на всякий случай напомню суть.
Основная работа ведется в фичных ветках, для багов есть специальные bugfix ветки. Все они вливаются в develop через Pull Request\Merge request. Для выпуска на ПРОД создается релизная ветка, код из которой после выхода на ПРОД попадает в master. Для выпуска hotfix также предусмотрены отдельные ветки.
Почему gitflow "великий":
а) дает контроль над тем, что и когда попадет в релиз. Поэтому любим в enterprise.
б) хорошо подходит для opensource проектов, т.к. там как правило много релизов и есть внешние коммитеры, качество кода которых нужно контролировать
в) дисциплинирует разработчиков
Почему "ужасный":
а) слишком громоздкий, т.к. master и hotfix ветки часто выглядят излишними
б) работа в фичных ветках может приводить к накоплению там большого количества кода и, следовательно, увеличивает вероятность конфликта при слиянии. Причем чем больше становится ветка, тем сложнее ее влить - и для автора из-за конфликтов, и для ревьюверов из-за объема кода. И сам принцип фичных веток на это провоцирует. Этакая положительная обратная связь, положительная в том смысле, что усиливает сложность вливания с каждым днем и каждой строчкой кода.
в) при плавной раскате на ПРОМ не понятно, в какой момент код должен попадать в master. Ведь в течение периода раскатки, а это может быть неделя +, на ПРОМ будет 2 версии. Кроме того, в этом случае о вливании в master часто забывают, т.к. все равно все работают с develop.
2) модификация gitflow с несколькими develop ветками. Может применяться в больших компаниях, когда критически важно, чтобы код той или иной фичи не попал в релиз Х без явного согласования, а feature toggle не аргумент)
Либо при переходе на новую версию платформы, когда код разных develop просто не совместим. Важная практическая особенность - git не позволит создать ветку develop/2.0 при наличии просто develop, т.к. у них одинаковый префикс. Поэтому лучше заранее определиться с моделью.
Хотя конечно всегда можно достичь требуемого с помощью создания промежуточных веток.
3) github flow. Как следует из названия придумана на GitHub-е, доступна на нем из коробки.
Картинка: https://user-images.githubusercontent.com/6351798/48032310-63842400-e114-11e8-8db0-06dc0504dcb5.png
Детали: https://docs.github.com/ru/get-started/quickstart/github-flow
По сравнению с gitflow сильно упрощена: выброшены develop, hotfix, release, bugfix, оставлены 2 типа веток: master и feature и Pull Request.
Для обозначения релизов можно использовать тэги, напомню, в git tag и branch технически одинаковы, разница лишь в UI того же Bitbucket, Github, Gitlab.
Плюсы:
а) очень простая модель
Минусы:
а) master нужно поддерживать в production ready состоянии -> feature toggles, модульные тесты и дисциплина в команде
#git #vcs #branching