(java || kotlin) && devOps
369 subscribers
6 photos
1 video
6 files
306 links
Полезное про Java и Kotlin - фреймворки, паттерны, тесты, тонкости JVM. Немного архитектуры. И DevOps, куда без него
Download Telegram
Всем привет!

Современная разработка - это микросервисы, микросервисы - это много внешних взаимодействий, а внешние взаимодействия - это API.
Каким должно быть хорошее API?

1) API должно быть версионировано. Все течет, все меняется: бизнес-требования, новые типы потребителей. О версионировании нужно подумать заранее.

2) Сервер и клиенты поддерживают работу с несколькими версиями API. Это позволит избежать синхронных внедрений двух и более микросервисов. Синхронное внедрение - это сложно и повышает вероятность нарушить все наши "девятки" (SLA)

3) API описано схемой. Король горы для REST запросов - OpenAPI. Отмечу, что в отличие от JSON Schema или XSD OpenAPI описывает не модель данных, а web сервис целиком: поддерживаемые HTTP методы - GET, POST,..., коды ответов HTTP, параметры запроса, заголовки.

4) CDC тестирование - https://martinfowler.com/articles/consumerDrivenContracts.html#Consumer-drivenContracts
В чем суть: создается контракт - человеко и машиночитаемое описание тест-кейсов для API, на основании которых генерируются API тесты для поставщика и потребителя. Примеры реализаций:
Spring Cloud Contract https://docs.spring.io/spring-cloud-contract/docs/current/reference/html/getting-started.html#getting-started-three-second-tour
Pact https://docs.pact.io/5-minute-getting-started-guide
Надо отметить, что OpenAPI и CDS в ряде моментов дублируют информацию, об этой проблеме и возможном решении для Spring можно почитать тут: https://springframework.guru/defining-spring-cloud-contracts-in-open-api/

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

6) API должно содержать trace_id - уникальный идентификатор операции. trace_id генерируется на клиенте и копируется в каждый последующий запрос по всем микросервисам. Потом с помощью таких инструментов, как Jaeger дерево запросов визуализируется, что упрощает отлавливание ошибок

7) в API не должно быть ничего лишнего. Добавляем то, что нужно клиенту, если появляется новые требования - версионируем API. Иначе получим аналог "божественного объекта" - https://ru.wikipedia.org/wiki/Божественный_объект

#API #arch #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
Всем привет!

Небольшая заметка, пример как рождаются унифицирующие стандарты в разработке.

Этапы развития распределенной трассировки - очень полезной технологии для отслеживания пути запроса между микросервисами, о которой я уже несколько раз писал:

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
Ещё интересный доклад - про нетривиальное использование трейсинга (tracing).

Начнём с того, что далеко не у всех он настроен. Окей, настроили. Теперь нам проще разбирать проблемы на ПРОМ в микросервисной архитектуре.

Все?

Нет) А если взять трейсы за некий период, отсемплировать их уменьшив объём и сложить их в графовую БД? Получим реверс-инжиниринг архитектуры. Причём это будет не «мертвая» архитектура, по кем-то когда-то написанной аналитике, а настоящая. Да, не 100% точная, из-за мертвых интеграций и поломанного трейсинга, но все же. Что с ней можно сделать? Контролировать... архитектуру. Например:
- Общая схема вызовов
- Циклические ссылки
- Длина цепочек вызовов
- Лишние с точки зрения разделения на бизнес-домены связи
- Критичность сервисов - сервисы, которые чаще всего используются другими сервисами
- Однотипные вызовы, которые можно объединить в batch запрос
- Вызовы в цикле
- Анализ использования практики Graceful degradation

Сама идея - практически бесплатный для бизнес-команд инструмент анализа архитектуры - отлично IMHO.

P.S. для этих же целей в теории можно использовать данные из Service Mesh, только добавляется ещё один снижающий точность фактор - не все компоненты находятся в облаке (и не все компоненты в облаке используют Service Mesh)

P.P.S. Конечно идея идеально подходит для компаний а-ля Яндекс и Авито (собственно в Авито ее и внедрили) - там, где нет жёсткого контроля интеграций на уровне согласования аналитики. Но IMHO в любом случае можно использовать как контрольный механизм, ещё одну «сеть»

#arch #tracing