предисловие
В процессе разработки зонда Skywalking nginx в основном анализируются «Протокол передачи информации о межпроцессных ссылках Skywalking» и «Протокол сбора данных Skywalking Link». Реализация skywalking nginx probe сейчас завершена версия и находится онлайн в производственной среде.Заинтересованные друзья могут общаться. Эта статья основана на анализе Skywalking v5.0.0-GA.Хотя версия несколько устарела, ядро двух протоколов не сильно изменилось. Официальные английские названия и ссылки на документы двух протоколов следующие:
Для простоты понимания в этой статье будетSkywalking-Cross-Process-Propagation-Headers-Protocol-v1читать как跨进程链路信息传递协议,Trace-Data-Protocolчитать какSkywalking链路数据采集协议. У официальных лиц есть переводы двух соглашений на китайский язык, с которыми можно ознакомиться самостоятельно.
"Протокол передачи информации между процессами" сам по себе несложно понять, но при его реализации необходимо учитывать множество факторов. В этой серии статей исходный код зонда Java будет сочетаться с углубленным анализом. Эта статья посвящена объяснению链路IDпроцесс генерации.
Роль протокола передачи информации о межпроцессном соединении
В распределенной системе после того, как пользователь инициирует запрос данных, серверная система будет иметь несколько сервисных узлов для обработки запроса данных. Одной из важных функций системы отслеживания ссылок является возможность объективно и достоверно отражать последовательность обработки данных, логическую взаимосвязь, длительность менеджера, топологию и другую информацию на каждом сервисном узле. Как правило, процесс в системе действует как сервисный узел.跨进程Описание взято отсюда.
В полной распределенной системе каждый сервисный узел часто имеет разные компоненты, разные языки и разные технологические стеки. Например, службы Java, службы узлов, компоненты nginx и так далее. Для решения проблем генерации, передачи, идентификации, разбора и кодирования данных канала в разных узлах необходимо согласовать набор спецификаций, чтобы разные языки могли обрабатывать данные канала. тогда跨进程链路信息传递协议был рожден.
Введение в структуру исходного кода Java-агента Skywalking
Прежде чем говорить о логике генерации идентификатора сегмента трассировки, кратко представим структуру исходного кода Java-агента Skywalking.
В Skywalking v5.0.0-GA абстракция и инкапсуляция информации о ссылке Skywalking агентом Java находится в исходном коде.apm-sniffer/apm-agent-coreв модуле. В этой статье анализируется логика обработки данных канала этого модуля следующим образом.
-
Связать абстракцию модели данных и инкапсуляцию Функция состоит в том, чтобы инкапсулировать абстракцию данных, согласованную с протоколом данных канала, и в то же время она в целом совместима со спецификацией Opentracing. Ключевые категории следующие
org.apache.skywalking.apm.agent.core.context.trace.TraceSegmentorg.apache.skywalking.apm.agent.core.context.trace.TraceSegmentReforg.apache.skywalking.apm.agent.core.context.trace.EntrySpanorg.apache.skywalking.apm.agent.core.context.trace.ExitSpanorg.apache.skywalking.apm.agent.core.context.ids.DistributedTraceIds
-
Абстракция и инкапсуляция данных межпроцессных связей Фокус-класс это
org.apache.skywalking.apm.agent.core.context.ContextCarrier. То есть инкапсуляция спецификации протокола, описанная в этой статье. -
Связать абстракцию и инкапсуляцию модели сбора данных Фокус-класс это
org.apache.skywalking.apm.agent.core.context.TracingContext. TracingContext хранится в ThreadLocal, который содержит все данные в ссылке, а также методы управления данными и контроля, в основном контроль Span. При этом обеспечивает обработку данных ContextCarrier, в том числе:- Преобразование TraceSegment в ContextCarrier, т. е. org.apache.skywalking.apm.agent.core.context.TracingContext#inject
- Извлечь данные TraceSegment из данных ContextCarrier, т. е. org.apache.skywalking.apm.agent.core.context.TracingContext#extract
-
Модуль сбора данных Link Дело в том
org.apache.skywalking.apm.agent.core.context.ContextManagerДобрый. Класс ContextManager является центром для различных подключаемых модулей агента обхода неба. Подключаемые модули Skywalking различных компонентов, такие как mq, dubbo, tomcat, spring и другие подключаемые модули агента Skywalking, создают и контролируют данные, такие как TracingContext, TraceSegment, EntrySpan, ExitSpan и ContextCarrier, путем вызова ContextManager. Можно сказать, что ContextManager управляет жизненным циклом данных ссылки в агенте. -
Модуль загрузки данных ссылок Дело в том
org.apache.skywalking.apm.agent.core.remoteв упаковкеTraceSegmentServiceClientДобрый. После того как ContextManager соберет сегмент данных ссылки (TraceSegment) в узле, он уведомляет TraceSegmentServiceClient о необходимости передать данные на сервер Collector. который включаетTracingContextListenerУпаковано с прогулкой по небу内存MQкомпоненты, которые будут подробно проанализированы позже.
Каждая из вышеперечисленных частей включает в себя сложную логику обработки, которая будет подробно объяснена позже.
Процесс генерации идентификатора ссылки Skywalking и реализация Java
официальная документацияSkywalking-Cross-Process-Propagation-Headers-Protocol-v1Было сделано подробное описание, и эта статья объединяет реализацию Java для дальнейшего анализа.
1. Спецификация протокола идентификатора сегмента трассировки
The trace segment id is the unique id for the part of the distributed trace. Each id is only used in a single thread. The id includes three parts(Long), e.g. "1.2343.234234234
- The first one represents application instance id, which assigned by collector. (most likely just an integer value, would be helpful in protobuf)
- The second one represents thread id. (In Java most likely just an integer value, would be helpful in protobuf)
- The third one also has two parts 3.1. A timestamp, measured in milliseconds 3.2.A seq, in current thread, between 0(included) and 9999(included)
If you are using other language, you can generate your own id, but make sure it is unique and combined by three longs.
Точки спецификации
- Сегмент трассировки — это абстракция распределенной цепочки вызовов, которую можно понимать как каждый сервисный узел в распределенной системе.
- Протокол требует, чтобы идентификатор сегмента трассировки состоял из трех частей, и каждая часть представляла собой длинное значение. Три части данных соединены точками, чтобы сформировать строку идентификатора сегмента трассировки.
- Сгенерированная строка идентификатора сегмента трассировки должна только гарантировать, что идентификатор состоит из трех типов Long и является глобально уникальным. Нет единого мнения о логическом значении трех частей, которое может быть согласовано самими разработчиками.
- Правило трех частей идентификатора, сгенерированного агентом Java, является исходным описанием. То есть: первая часть представляет идентификатор экземпляра приложения, вторая часть — номер потока, а третья часть состоит из метки времени и последовательности автоинкремента.
2. Отследить процесс генерации идентификатора сегмента
Первый java-агент, путешествующий по небу, обеспечиваетorg.apache.skywalking.apm.agent.core.context.ids.IDКласс используется для описания структуры данных спецификации протокола и предоставляет метод проверки достоверности isValid и метод преобразования сериализации, а также переписывает методы toString, equals, hashCode.
Данные коллекции ссылок, передаваемые на сервер-сборщик через grpc, предоставляют метод преобразования для сериализации в данные protobuf. Такие какorg.apache.skywalking.apm.agent.core.context.trace.TraceSegment#transform,org.apache.skywalking.apm.agent.core.context.trace.TraceSegmentRef#transformЖдать.
Создание идентификатора сегмента трассировки происходит при создании экземпляра.TracingContextв процессе.TracingContext.new()Ссылка на диаграмму последовательности выглядит следующим образом:
Trace Segment Idпроцесс, позвонивorg.apache.skywalking.apm.agent.core.context.ids.GlobalIdGenerator#generateМетод генерирует строку идентификатора, которая удовлетворяет спецификации протокола.
3. Глобальный (распределенный) идентификатор трассировки и идентификатор сегмента трассировки
3.1 Различия
В Skywalking существует два типа глобально уникальных идентификаторов, а именно глобальный (распределенный) идентификатор трассировки и идентификатор сегмента трассировки. Глобальный (распределенный) идентификатор трассировки относится к уникальному идентификатору ссылки в распределенной системе. Идентификатор сегмента трассировки относится к идентификатору сегмента канала, сгенерированному сервисным узлом системы распределения, через который проходит канал. Два являются отношением один ко многим.
3.2 Процесс генерации
На приведенной выше диаграмме последовательности показано, что экземпляр TraceSegment создается при создании экземпляра TracingContext, а глобальный (распределенный) идентификатор трассировки и идентификатор сегмента трассировки генерируются одновременно с созданием экземпляра TraceSegment.Исходный код выглядит следующим образом:
public TraceSegment() {
this.traceSegmentId = GlobalIdGenerator.generate();
this.spans = new LinkedList<AbstractTracingSpan>();
this.relatedGlobalTraces = new DistributedTraceIds();
this.relatedGlobalTraces.append(new NewDistributedTraceId());
}
- Создать идентификатор сегмента трассировки
Среди них первая строка кода
this.traceSegmentId = GlobalIdGenerator.generate();, то есть генерируется идентификатор сегмента трассировки, и метод GlobalIdGenerator.generate() вызывается один раз. в строке 4 кодаnew NewDistributedTraceId()Создан глобальный (распределенный) идентификатор трассировки. Исходный код выглядит следующим образом, видно, что тот же вызовGlobalIdGenerator.generate()метод.
public class NewDistributedTraceId extends DistributedTraceId {
public NewDistributedTraceId() {
super(GlobalIdGenerator.generate());
}
}
- Создать глобальный (распределенный) идентификатор трассировки
Логика глобального идентификатора ссылки более сложная, и этот идентификатор инкапсулирован в java-агенте.
DistributedTraceIdsкласс, который добавляется через метод append классаNewDistributedTraceIdОбъект, представляющий данные глобального (распределенного) идентификатора трассировки. NewDistributedTraceId является подклассом DistributedTraceId, а класс DistributedTraceId является оболочкой для класса ID и предоставляет некоторые методы инструментов.DistributedTraceIdsПредставляет набор связанных идентификаторов ссылок, в большинстве случаев включается только один идентификатор ссылки.
3.3 О GlobalIdGenerator
Оба идентификатора генерируются путем вызова одного и того же метода, т.е.org.apache.skywalking.apm.agent.core.context.ids.GlobalIdGenerator#generate.
GlobalIdGenerator — это класс логической инкапсуляции, который создает глобальные строки идентификаторов. Посмотрите нижеGlobalIdGenerator#generateисходный код.
public static ID generate() {
if (RemoteDownstreamConfig.Agent.APPLICATION_INSTANCE_ID == DictionaryUtil.nullValue()) {
throw new IllegalStateException();
}
IDContext context = THREAD_ID_SEQUENCE.get();
return new ID(
RemoteDownstreamConfig.Agent.APPLICATION_INSTANCE_ID,
Thread.currentThread().getId(),
context.nextSeq()
);
}
Приведенный выше исходный код, наконец, возвращает структуру данных ID, инкапсулированную в соответствии со спецификацией протокола.Первый параметр — это идентификатор экземпляра текущего приложения, а второй параметр — номер текущего потока. Третий параметр получается с помощью метода IDContext.nextSeq(). IDContext получается из ThreadContext, поэтому IDContext уникален для потока. Исходный код IDContext прост для понимания: IDContext.nextSeq() возвращает строку, которая объединяет текущую отметку времени и самоувеличивающийся порядковый номер в потоке.
4. Резюме
Таким образом, когда начинается новая ссылка и создается экземпляр TraceSegment, первый вызовGlobalIdGenerator.generate()так какTrace Segment Id, второй звонокGlobalIdGenerator.generate()так какGlobal(Distributed) Trace Id.
5. Уведомление
org.apache.skywalking.apm.agent.core.context.trace.TraceSegmentЭто основной класс логики ссылок java-агента Skywalking, который будет объяснен отдельно позже.
Автор: Yiqixiu Senior Engineer-Frank