1 Обзор
Zipkin — это полнофункциональная система мониторинга ссылок, разработанная на основе статьи Google Dapper и разработанная Twitter.
Zipkin использует структуру Trace для представления трассировки запроса и делит каждую трассировку на несколько интервалов с зависимостями. В микросервисной архитектуре пользовательский запрос может обрабатываться несколькими службами в фоновом режиме, тогда каждая служба, обрабатывающая запрос, может пониматься как Span (который может включать службы API, службы кэширования, службы базы данных, службы отчетов и т. д.). . Конечно, эта служба может продолжать запрашивать другие службы, поэтому Span представляет собой древовидную структуру, отражающую отношения вызова между службами.
2. Схема архитектуры
Пунктирная линия — это функция, предоставляемая zipkin-сервером, который в основном включает в себя четыре модуля:
- Collector принимает данные, переданные клиентами, собирающими zipkin.
- Хранилище хранит собранные данные, по умолчанию это Память, которую можно настроить как MySQL, Cassandra, ES и т.д.
- API отвечает за запрос данных, хранящихся в хранилище, и предоставление их пользовательскому интерфейсу.
- Пользовательский интерфейс предоставляет простые веб-страницы.
Instrumented — это клиент, который собирает данные и отправляет их в zipkin. Основными собираемыми структурами данных являются Trace и Span.
3.Brave
Brave — это клиент zipkin для Java.
Обычно мы не пишем код, связанный с трассировкой, вручную, Brave предоставляет несколько готовых библиотек, которые помогают нам отслеживать некоторые конкретные запросы. Такие как dubbo, grpc, servlet, mysql, httpClient, kafka, springMVC и т. д.
/**
* 客户端具体怎么收集数据的demo
*/
public static void main(String[] args) throws Exception{
// 1.构建客户端发送工具
Sender sender = OkHttpSender.create("http://127.0.0.1:9411/api/v2/spans");
// 2.构建异步reporter
AsyncReporter asyncReporter = AsyncReporter.builder(sender)
.closeTimeout(500, TimeUnit.MILLISECONDS)
.build(SpanBytesEncoder.JSON_V2);
// 3.构建tracing上下文
Tracing tracing = Tracing.newBuilder()
.localServiceName("myService")
.spanReporter(asyncReporter)
.propagationFactory(ExtraFieldPropagation.newFactory(B3Propagation.FACTORY,"shuang"))
.currentTraceContext(ThreadContextCurrentTraceContext.create())
.build();
// 4.使用tracer创建span并操作start()和finish()方法
Tracer tracer = tracing.tracer();
Span span = tracer.newTrace().name("total").start();
Span action_1 = tracer.newChild(span.context()).name("action-1").start();
try {
Thread.sleep(500);
}finally {
action_1.finish();
}
Span action_2 = tracer.newChild(span.context()).name("action-2").start();
try {
Thread.sleep(500);
}finally {
action_2.finish();
}
try {
Thread.sleep(2000);
}finally {
span.finish();
}
}
3. Введение в трассировку
Несколько важных классов зависимостей в Tracing
- IP-адрес конечной точки, порт, имя службы приложений и другая информация.
- Reporter Сбор данных Reporter
- Пробоотборник, определяющий необходимость отбора проб трассировки в соответствии с TRACEID
- CurrentTraceContext привязывает TraceContext к ThreadLocal, чтобы текущий поток мог получить
- Распространение — это интерфейс, который может вводить и извлекать данные в объектный носитель данных и из него.
3.1Sampler
public abstract class Sampler {
/**
* 根据traceId是否需要采样
*/
public abstract boolean isSampled(long traceId);
}
Он предоставляет несколько реализаций сэмплера по умолчанию. ALWAYS_SAMPLE, NERVER_SAMPLE и сэмплер CountingSampler с определяемой частотой дискретизации.
4. Промежуток Введение
Основными интерфейсами для сбора и отправки данных являются Span.start() и Span.finish().
/**
* RealSpan依赖于Trace上下文,Recorder。
*/
static RealSpan create(TraceContext context, Clock clock, Recorder recorder) {
return new AutoValue_RealSpan(context, clock, recorder);
}
public Span start(long timestamp) {
recorder().start(context(), timestamp);
return this;
}
public void finish(long timestamp) {
recorder().finish(context(), timestamp);
}
public void finish(TraceContext context, long finishTimestamp) {
MutableSpan span = spanMap.remove(context);
if(span == null || noop.get()) return;
synchronized (span) {
span.finsh(finishTimestamp);
reporter.report(span.toSpan());
}
}
RealSpan вызывает start() и finish() для получения информации Span, связанной с TraceContext, записывает время начала и время окончания, а в конце вызывает метод отчета генератора отчетов и сообщает об этом zipkin.
5. Интеграция с SpringMVC
Brave использует механизм перехватчика, предоставляемый springMVC, для вызова предыдущего кода, связанного с диапазоном, до и после перехвата, то есть для мониторинга запроса.
<!-- Brave提供的拦截器 -->
<mvc:interceptors>
<bean class="brave.spring.webmvc.TracingHandlerInterceptor" factory-method="create">
<constructor-arg type="brave.http.HttpTracing" ref="httpTracing"/>
</bean>
</mvc:interceptors>
Вызовите методы span.start() и span.finish() в preHandle() и afterCompletion() соответственно, чтобы завершить отправку отчета на сервер zipkin. Подробности смотрите в соответствующем коде.
6. Интеграция с Mysql
Mysql также предоставляет интерфейс перехвата до и после выполнения sql.
/**
* mysql-connector.jar中提供的拦截接口
*/
public interface StatementInterceptorV2 extends Extension {
void init(Connection var1, Properties var2) throws SQLException;
ResultSetInternalMethods preProcess(String var1, Statement var2, Connection var3) throws SQLException;
boolean executeTopLevelOnly();
void destroy();
ResultSetInternalMethods postProcess(String var1, Statement var2, ResultSetInternalMethods var3, Connection var4, int var5, boolean var6, boolean var7, SQLException var8) throws SQLException;
}
Выполните span.start() в preProcess() и span.finish() в postProcess(). Подробности смотрите в соответствующем коде.
7. Другая интеграция промежуточного программного обеспечения опущена.
8. Резюме
Краткое введение в Zipkin. Хороший дизайн фреймворка принесет много удобств разработчикам. (Большинство клиентов zipkin реализованы на основе интерфейса перехвата.)