🌹🌹Если вы считаете, что моя статья вам полезна, не забудьте поставить звездочку на GitHub 🌹🌹
В последнее время я работаю со своими коллегами над созданием небольшой и красивой системы мониторинга производительности приложений (Pepper-Metrics).
Одним из требований является сбор данных о производительности отклика интерфейса Dubbo на стороне поставщика и на стороне потребителя, чтобы сохранить их в источнике данных или предоставить на принтер.
В этом контексте нам необходимо отслеживать каждый запрос и ответ от провайдера и потребителя. В Dubbo можно расширитьorg.apache.dubbo.rpc.Filter
реализация интерфейса.
0 org.apache.dubbo.rpc.Filter введение
Фильтр можно понимать как перехват вызывающего процесса.Перехватчик будет действовать каждый раз при вызове метода.При расширении нужно обратить внимание на влияние на производительность.
Пользовательские фильтры по умолчанию выполняются после существующих фильтров.
1 Реализация фильтра Pepper-Metrics-Dubbo
В нашем проекте этот подмодуль называетсяPepper-Metrics-Dubbo
, структура этого модуля следующая:
Pepper-Metrics-Dubbo
|-src/main/java
|-com.pepper.metrics.integration.dubbo
|-DubboProfilerFilterTemplate
|-DubboProviderProfilerFilter
|-DubboConsumerProfilerFilter
|-src/main/resources
|-META-INF
|-dubbo
|-org.apache.dubbo.rpc.Filter
существуетPepper-Metrics-Dubbo
середина,DubboProfilerFilterTemplate
класс реализуетorg.apache.dubbo.rpc.Filter
интерфейс.
Это класс шаблона, который определяетFilter.invoke()
Общая реализация метода, обусловленная спецификой профиля сбора, дляProvider
а такжеConsumer
Требуется другой сборщик, здесь через его подклассDubboProviderProfilerFilter
а такжеDubboConsumerProfilerFilter
реализованы отдельно.
Вышеупомянутые отношения классов можно описать следующей диаграммой:
DubboProfilerFilterTemplate примерно реализован следующим образом:
public abstract class DubboProfilerFilterTemplate implements Filter {
// Provider的收集器
static final Stats PROFILER_STAT_IN = Profiler.Builder
.builder()
.name("app.dubbo.request.in")
.build();
// Consumer的收集器
static final Stats PROFILER_STAT_OUT = Profiler.Builder
.builder()
.name("app.dubbo.request.out")
.build();
@Override
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
// 省略... 一些必要的准备工作
// 模板方法,before trace...
beforeInvoke(tags);
try {
Result result = invoker.invoke(invocation);
// 记录是否调用报错
if (result == null || result.hasException()) {
isError = true;
}
specialException = false;
return result;
} finally {
if (specialException) {
isError = true;
}
// 模板方法,after trace...
afterInvoke(tags, begin, isError);
}
}
abstract void afterInvoke(String[] tags, long begin, boolean isError);
abstract void beforeInvoke(String[] tags);
}
Два класса реализации следующие:
// Provider
@Activate(group = {PROVIDER})
public class DubboProviderProfilerFilter extends DubboProfilerFilterTemplate {
@Override
void afterInvoke(String[] tags, long begin, boolean isError) {
// 记录响应实现
PROFILER_STAT_IN.observe(System.nanoTime() - begin, TimeUnit.NANOSECONDS, tags);
// 并发数递减
PROFILER_STAT_IN.decConc(tags);
// 记录错误数
if (isError) {
PROFILER_STAT_IN.error(tags);
}
}
@Override
void beforeInvoke(String[] tags) {
// 并发数递增
PROFILER_STAT_IN.incConc(tags);
}
}
// Consumer
@Activate(group = {CONSUMER})
public class DubboConsumerProfilerFilter extends DubboProfilerFilterTemplate {
@Override
void afterInvoke(String[] tags, long begin, boolean isError) {
PROFILER_STAT_OUT.observe(System.nanoTime() - begin, TimeUnit.NANOSECONDS, tags);
PROFILER_STAT_OUT.decConc(tags);
if (isError) {
PROFILER_STAT_OUT.error(tags);
}
}
@Override
void beforeInvoke(String[] tags) {
PROFILER_STAT_OUT.incConc(tags);
}
}
После написания класса реализации вам необходимоresources
Настройте файл расширения Dubbo в каталоге.
существуетresources
Создать подMETA-INF/dubbo/org.apache.dubbo.rpc.Filter
файл со следующим содержимым:
dubboProviderProfiler=com.pepper.metrics.integration.dubbo.DubboProviderProfilerFilter
dubboConsumerProfiler=com.pepper.metrics.integration.dubbo.DubboConsumerProfilerFilter
Это позволяет Dubbo сканировать пользовательские точки расширения.
2 Использование пользовательского фильтра
Далее вам нужно настроить пользовательскую точку расширения в Dubbo и сообщить Dubbo, что я хочу использовать этот фильтр, соответственно вProvider
а такжеConsumer
Средняя конфигурация:
Первый взглядProvider
:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:property-placeholder/>
<dubbo:application name="demo-provider"/>
<dubbo:registry address="multicast://224.5.6.7:1234"/>
<bean id="demoService" class="com.pepper.metrics.sample.dubbo.spring.provider.DemoServiceImpl"/>
<!-- 在这里配置自定义的扩展点 -->
<dubbo:service filter="default,dubboProviderProfiler" interface="com.pepper.metrics.sample.dubbo.spring.api.DemoService" ref="demoService" />
</beans>
проиллюстрировать:
default
представляет существующую точку расширения,dubboProviderProfiler
Является нашей пользовательской точкой расширения, поэтому конфигурация означает, что наша пользовательская точка расширения выполняется после существующей точки расширения.
Точно так же вConsumer
Пользовательская точка расширения боковой конфигурации:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:property-placeholder/>
<dubbo:application name="demo-consumer"/>
<dubbo:registry address="multicast://224.5.6.7:1234"/>
<!-- 在这里配置自定义的扩展点 -->
<dubbo:reference filter="default,dubboConsumerProfiler" id="demoService" check="true" interface="com.pepper.metrics.sample.dubbo.spring.api.DemoService" />
</beans>
3 Автоматическая активация пользовательских точек расширения
Из вышеизложенного мы знаем, что наша пользовательская точка расширения должна изменить конфигурацию, чтобы она вступила в силу.Таким образом, происходит вторжение кода. Итак, можем ли мы представитьpepper-metrics-dubbo
После создания пакета jar он вступает в силу напрямую, без изменения конфигурации?
Ответ: конечно!
pepper-metrics-dubbo
Использование Dubbo при условии@Activate
механизм. Эту аннотацию можно использовать в классах или методах. Его цель — позволить Dubbo автоматически активировать это расширение, тем самым упростив настройку.
кProvider
Для случая взгляните на эту вещь вpepper-metrics-dubbo
Для чего его используют.
@Activate(group = {PROVIDER}) // is here
public class DubboProviderProfilerFilter extends DubboProfilerFilterTemplate {
@Override
void afterInvoke(String[] tags, long begin, boolean isError) {
// ...
}
@Override
void beforeInvoke(String[] tags) {
// ...
}
}
Во-первых, если только настроить@Activate
Аннотация, если вы не настроите ее свойства, автоматически активирует все точки расширения безоговорочно. В нашем проекте он будет активирован одновременноDubboConsumerProfilerFilter
а такжеDubboProviderProfilerFilter
.
Но в наших требованиях нет возможности активировать две точки расширения одновременно. При одновременной активации и поставщик услуг, и вызывающая сторона вызовут обе точки расширения. И что нам нужно, это вызов провайдераProvider
, звонит звонящийConsumer
.
Это можно сделать с помощьюgroup
реализовать. Определенныйgroup
После этого он активируется только для определенной группы.
В фильтре есть две группы:
String PROVIDER = "provider";
String CONSUMER = "consumer";
определяется какPROVIDER
действует только для провайдера, определенного какCONSUMER
Он действует только на вызывающего абонента или может быть определен одновременно, и он вступит в силу в то же время.
Таким образом, необходимо полагаться только наpepper-metrics-dubbo
Пакет может активировать точку расширения.
Ссылаться на
Добро пожаловать в мой публичный аккаунт WeChat