С DevOps метрики начинают быть среди нефункциональных требований, которые любое приложение должно принести в область. Прежде чем идти дальше, я хотел бы сделать несколько замечаний:
- Метрики не только о нефункциональных вещах. Многие показатели представляют очень важный KPI для бизнеса. Например, для интернет-магазина бизнес должен знать, сколько клиентов покидают процесс оформления заказа и на каком экране. Правда, есть несколько решений для достижения этой цели, хотя все они основаны на веб-технологиях (Google Analytics приходит на ум) и метрики могут также потребоваться для разных архитектур. И наличие всех метрик в одном бэкэнде означает, что их можно легко соотнести.
- Метрики, как и любая другая NFR ( например, регистрация и обработка исключений), должны разрабатываться и управляться заранее, а не выдвигаться в качестве запоздалой мысли. Откуда я это знаю? Ну, один из моих последних проектов был сосредоточен только на функциональных требованиях, и только в конце концов руководство проекта осознало важность NFR. Поверьте мне, когда я говорю, что это было ужасно — и это стоило намного дороже, чем если бы оно было разработано на ранних этапах проекта.
- Метрики имеют накладные расходы. Однако без метрик невозможно повысить производительность. Просто прими это и живи с этим.
Входные данные следующие: приложение основано на Spring MVC, а показатели должны быть агрегированы в графите . Мы начнем с использования отличного проекта Metrics : он не только выполняет свою работу, его документация очень высокого качества и доступна под дружественной лицензией OpenSource Apache v2.0.
Тем не менее, давайте представим «стандартную» базовую архитектуру для управления этими компонентами.
Во-первых, хотя Metrics предлагает конечную точку Graphite, это требует настройки в каждой среде, что усложняет работу, особенно на рабочих станциях разработчиков. Для этого мы отправим метрики в JMX и представим jmxtrans в качестве промежуточного компонента между JMX и графитом. Поскольку каждая JVM предоставляет службы JMX, это не требует настройки, когда в этом нет необходимости, и не влияет на производительность.
Во-вторых, как разработчики, нам обычно нравится разрабатывать все с нуля, чтобы показать, насколько мы хороши — или иногда потому, что они не просматривали документацию. Моя точка зрения, как инженера-программиста, заключается в том, что я бы не стал изобретать велосипед и сосредоточиться на задаче в конце. Фактически Spring Boot уже интегрируется с Metrics через компонент Actuator. Однако он предоставляет только GaugeService — для отправки уникальных значений, а CounterService — для увеличения / уменьшения значений. Это может быть достаточно для FR, но не для NFR, поэтому мы могли бы немного подправить.
Поток будет выглядеть так: Код> Spring Boot> Метрики> JMX> Графит
Отправной точкой является создание аспекта, поскольку показатель производительности является сквозной задачей:
@Aspect public class MetricAspect { private final MetricSender metricSender; @Autowired public MetricAspect(MetricSender metricSender) { this.metricSender = metricSender; } @Around("execution(* ch.frankel.blog.metrics.ping..*(..)) ||execution(* ch.frankel.blog.metrics.dice..*(..))") public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable { StopWatch stopWatch = metricSender.getStartedStopWatch(); try { return pjp.proceed(); } finally { Class<?> clazz = pjp.getTarget().getClass(); String methodName = pjp.getSignature().getName(); metricSender.stopAndSend(stopWatch, clazz, methodName); } } }
Единственное, что выходит за рамки обычного — это использование автопроводки, так как аспекты, кажется, не могут быть целью явной разводки (пока?). Также обратите внимание, что сам аспект не взаимодействует с Metrics API, он делегирует только выделенному компоненту:
public class MetricSender { private final MetricRegistry registry; public MetricSender(MetricRegistry registry) { this.registry = registry; } private Histogram getOrAdd(String metricsName) { Map<String, Histogram> registeredHistograms = registry.getHistograms(); Histogram registeredHistogram = registeredHistograms.get(metricsName); if (registeredHistogram == null) { Reservoir reservoir = new ExponentiallyDecayingReservoir(); registeredHistogram = new Histogram(reservoir); registry.register(metricsName, registeredHistogram); } return registeredHistogram; } public StopWatch getStartedStopWatch() { StopWatch stopWatch = new StopWatch(); stopWatch.start(); return stopWatch; } private String computeMetricName(Class<?> clazz, String methodName) { return clazz.getName() + '.' + methodName; } public void stopAndSend(StopWatch stopWatch, Class<?> clazz, String methodName) { stopWatch.stop(); String metricName = computeMetricName(clazz, methodName); getOrAdd(metricName).update(stopWatch.getTotalTimeMillis()); } }
Отправитель делает несколько интересных вещей (но без состояния):
- Возвращает новый
StopWatch
для аспекта, чтобы передать обратно после выполнения метода - Он вычисляет имя метрики в зависимости от класса и метода
- Он останавливает
StopWatch
и отправляет времяMetricRegistry
- Обратите внимание , что также лениво создает и регистрирует новый
Histogram
сExponentiallyDecayingReservoir
экземпляром. Поведение по умолчанию — предоставитьUniformReservoir
, который хранит данные вечно и не подходит для наших нужд.
Последний шаг — сообщить Metrics API о необходимости отправки данных в JMX. Это можно сделать в одном из классов конфигурации, предпочтительно в классе, предназначенном для метрик, с использованием @PostConstruct
аннотации для желаемого метода.
@Configuration public class MetricsConfiguration { @Autowired private MetricRegistry metricRegistry; @Bean public MetricSender metricSender() { return new MetricSender(metricRegistry); } @PostConstruct public void connectRegistryToJmx() { JmxReporter reporter = JmxReporter.forRegistry(metricRegistry).build(); reporter.start(); } }
JConsole должна выглядеть следующим образом. Обледенение, все метрики Spring Boot по умолчанию также доступны:
Источники для этой статьи доступны в «формате» Maven.
Чтобы идти дальше:
- Общая документация Code Hale’s Metrics
- Особенности гистограммы и резервуара
- Spring Boot общая документация
- Интеграция Spring Boot и Metrics