Go создает микросервисный фреймворк на основе grpc — интегрированной opentracing.

задняя часть Микросервисы Go gRPC
Go создает микросервисный фреймворк на основе grpc — интегрированной opentracing.

1 Обзор

Есть такой сценарий, когда мы разделяем микросервис, запрос будет обрабатываться несколькими сервисами перед возвратом, в это время, если сервис выйдет из строя на запрошенной ссылке, будет сравнима сложность устранения неполадок. Для анализа может потребоваться просмотр логов сервисов, через которые проходит запрос, когда десятки или сотни экземпляров сервиса, это, несомненно, ужасно. Поэтому для решения этой проблемы и появилась трассировка цепочки вызовов.

2.opentracing

1.1 Роль opentracing

Трассировка цепочки вызовов была впервые написана Google вDapperВ данной работе предлагается, чтобыOpenTracingВ основном он определяет соответствующие протоколы и интерфейсы, поэтому, если каждый язык реализует отчетность данных в соответствии с интерфейсом и протоколом Opentracing, информация о вызовах может собираться единообразно.

Как показано на рисунке выше, интерфейс может сначала пройти через веб-фреймворк, а затем вызвать службу аутентификации.В цепочке вызовов службы, через которые проходит запрос, нумеруются и собираются вместе, чтобы сформировать логическую связь.Таким образом , мы можем видеть, что запрос прошел через какие сервисы, таким образом формируя сервис-зависимую топологию.

Как указано выше, общая ссылка состоит из каждой ссылки, и каждая ссылка представляет собой службу, через которую проходит.Потребление времени можно использовать для анализа узкого места системы.Когда запрос возвращается медленно, вы можете проверить потребление времени определенной ссылкой, чтобы проанализировать, какая служба имеет более высокую задержку, а теперь проанализировать конкретные проблемы в конкретных службах.

1.2 ключевые термины опентрейнинга

  • Трассы (цепочка вызовов)
    Ссылка вызова однозначно идентифицируется с помощью TraceID. Например, запрос обычно представляет собой трассировку, а трассировка состоит из отрезков всех путей.

  • Промежутки (диапазон вызовов)
    Если служба не была введена, она будет разделена, и каждый диапазон будет однозначно идентифицирован по идентификатору spanID.

  • Теги диапазона
    Метка span, например, span вызывает redis, а метка redis может быть установлена, так что, выполнив поиск по ключевому слову redis, мы можем запросить все связанные span и трассировки.

  • Место багажа (с данными)
    Дополнительные данные, состоящие из пары ключ:значение, могут дать более описательную информацию цепочке вызовов за счет дополнительных данных, но, учитывая проблему передачи, дополнительных данных должно быть как можно меньше.

1.3 jaeger & zipkin

В настоящее время реализации с открытым исходным кодом включаютzipkinтак же какjaeger

  • молния zipkin в основном написан на Java. Он передает данные сборщику через библиотеку отчетов каждого языка. Затем сборщик сохраняет данные и предоставляет их на передний дисплей пользовательского интерфейса через API.

  • егерь jaeger реализован компанией go, разработан компанией uber и в настоящее времяcloud nativeПроект, процесс аналогичен zipkin, добавление такого компонента, как jager-agent.Официальная рекомендация для этого компонента - развернуть по одному на каждую машину, а затем сообщать данные на дисплей хранилища коллектора через этот компонент. Кроме того, сделана адаптация к зипкину.Вообще-то они тоже использовали зипкин в начале,и им пришлось строить свои колеса для спины Мао? См. их объяснение.Связь

В целом, оба могут в основном могут соответствовать функциям OpenCatwacing, и конкретный выбор можно сочетать с собственным технологическим стеком и хобби.

2. встроенная трассировка grpc

Интегрировать opentracing с grpc несложно, потому что сервер grpc и вызывающая сторона соответственно объявляют две функции обратного вызова, UnaryClientInterceptor и UnaryServerInterceptor, так что вам нужно только переписать эти две функции обратного вызова и вызвать интерфейс opentracing в переписанной функции обратного вызова для создания отчетов. , может.
При инициализации передайте переписанную функцию обратного вызова и в то же время выберите одну из двух для инициализации jager или zipkin, а затем вы можете начать отслеживание распределенной цепочки вызовов.

Посмотреть полный кодgrpc-wrapper

2.1 Клиентская сторона

func OpenTracingClientInterceptor(tracer opentracing.Tracer) grpc.UnaryClientInterceptor {
	return func(
		ctx context.Context,
		method string,
		req, resp interface{},
		cc *grpc.ClientConn,
		invoker grpc.UnaryInvoker,
		opts ...grpc.CallOption,
	) error {

        //从context中获取spanContext,如果上层没有开启追踪,则这里新建一个
        //追踪,如果上层已经有了,测创建子span.
		var parentCtx opentracing.SpanContext
		if parent := opentracing.SpanFromContext(ctx); parent != nil {
			parentCtx = parent.Context()
		}
		cliSpan := tracer.StartSpan(
			method,
			opentracing.ChildOf(parentCtx),
			wrapper.TracingComponentTag,
			ext.SpanKindRPCClient,
		)
		defer cliSpan.Finish()

        //将之前放入context中的metadata数据取出,如果没有则新建一个metadata
		md, ok := metadata.FromOutgoingContext(ctx)
		if !ok {
			md = metadata.New(nil)
		} else {
			md = md.Copy()
		}
		mdWriter := MDReaderWriter{md}

        //将追踪数据注入到metadata中
		err := tracer.Inject(cliSpan.Context(), opentracing.TextMap, mdWriter)
		if err != nil {
			grpclog.Errorf("inject to metadata err %v", err)
		}
        //将metadata数据装入context中
		ctx = metadata.NewOutgoingContext(ctx, md)
        //使用带有追踪数据的context进行grpc调用.
		err = invoker(ctx, method, req, resp, cc, opts...)
		if err != nil {
			cliSpan.LogFields(log.String("err", err.Error()))
		}
		return err
	}
}

2.2 на стороне сервера

func OpentracingServerInterceptor(tracer opentracing.Tracer) grpc.UnaryServerInterceptor {
	return func(
		ctx context.Context,
		req interface{},
		info *grpc.UnaryServerInfo,
		handler grpc.UnaryHandler,
	) (resp interface{}, err error) {
                //从context中取出metadata
		md, ok := metadata.FromIncomingContext(ctx)
		if !ok {
			md = metadata.New(nil)
		}
               //从metadata中取出最终数据,并创建出span对象
		spanContext, err := tracer.Extract(opentracing.TextMap, MDReaderWriter{md})
		if err != nil && err != opentracing.ErrSpanContextNotFound {
			grpclog.Errorf("extract from metadata err %v", err)
		}
                //初始化server 端的span
		serverSpan := tracer.StartSpan(
			info.FullMethod,
			ext.RPCServerOption(spanContext),
			wrapper.TracingComponentTag,
			ext.SpanKindRPCServer,
		)
		defer serverSpan.Finish()
		ctx = opentracing.ContextWithSpan(ctx, serverSpan)
             //将带有追踪的context传入应用代码中进行调用
		return handler(ctx, req)
	}
}

Поскольку OpenTraacing определяет связанный интерфейс, реализованы JAEGER и Zipkin, поэтому об этом можно сообщить с помощью JAEGER, а Zipkin можно сообщить.

3. Эффекты

Информация о домашней странице службы jaeger

Информация о каждой цепочке вызовов

4. Ссылка

zipkin
jaeger
OpenTracing
grpc-wrapper