AWS XRay - это сервис трассировки, который позволяет отслеживать запросы в распределенных системах и даже профилировать ваши сервисы. Не вдаваясь в подробности того, как работает XRay, он в основном отслеживает ваш сервис и отправляет данные о каждом запросе к сервису через UDP демону, который собирает эти данные и отправляет их в AWS.
Этот демон, когда он запущен локально или в EC2, является локальным по отношению к машине, на которой запущена служба, и доступен через порт 2000. Это конфигурация по умолчанию для расположения хоста демона.
При работе в Kubernetes вам необходимо настроить демон для работы на каждом узле. Согласно документации по настройке XRay с Kubernetes, вы можете переопределить значение по умолчанию, установив переменную среды AWS_XRAY_DAEMON_ADDRESS
с требуемым хостом, или вы можете установить системную переменную JVM com.amazonaws.xray.emitters.daemonAddress
. Также имеется ссылка на это в SDK. документация.
Из-за моего варианта использования и того, как мы делимся конфигурациями в моей организации, я хотел бы использовать метод установки переменной среды.
Согласно документации, мы устанавливаем его при развертывании с помощью наших диаграмм управления:
env:
- name: AWS_XRAY_DAEMON_ADDRESS
value: aws-xray-daemon.default
Выполнив выполнение в модуле, в котором запущена служба, и запустив printenv
, мы видим, что это значение успешно установлено при развертывании.
Проблема:
Когда XRay пытается профилировать и отправлять данные демону, выдается SdkClientException
:
com.amazonaws.SdkClientException: Unable to execute HTTP request: Connect to 127.0.0.1:2000 [/127.0.0.1] failed: Connection refused (Connection refused)
at com.amazonaws.http.AmazonHttpClient$RequestExecutor.handleRetryableException(AmazonHttpClient.java:1201) ~[aws-java-sdk-core-1.11.739.jar!/:na]
at com.amazonaws.http.AmazonHttpClient$RequestExecutor.executeHelper(AmazonHttpClient.java:1147) ~[aws-java-sdk-core-1.11.739.jar!/:na]
at com.amazonaws.http.AmazonHttpClient$RequestExecutor.doExecute(AmazonHttpClient.java:796) ~[aws-java-sdk-core-1.11.739.jar!/:na]
at com.amazonaws.http.AmazonHttpClient$RequestExecutor.executeWithTimer(AmazonHttpClient.java:764) ~[aws-java-sdk-core-1.11.739.jar!/:na]
at com.amazonaws.http.AmazonHttpClient$RequestExecutor.execute(AmazonHttpClient.java:738) ~[aws-java-sdk-core-1.11.739.jar!/:na]
at com.amazonaws.http.AmazonHttpClient$RequestExecutor.access$500(AmazonHttpClient.java:698) ~[aws-java-sdk-core-1.11.739.jar!/:na]
at com.amazonaws.http.AmazonHttpClient$RequestExecutionBuilderImpl.execute(AmazonHttpClient.java:680) ~[aws-java-sdk-core-1.11.739.jar!/:na]
at com.amazonaws.http.AmazonHttpClient.execute(AmazonHttpClient.java:544) ~[aws-java-sdk-core-1.11.739.jar!/:na]
at com.amazonaws.http.AmazonHttpClient.execute(AmazonHttpClient.java:524) ~[aws-java-sdk-core-1.11.739.jar!/:na]
at com.amazonaws.services.xray.AWSXRayClient.doInvoke(AWSXRayClient.java:1607) ~[aws-java-sdk-xray-1.11.739.jar!/:na]
at com.amazonaws.services.xray.AWSXRayClient.invoke(AWSXRayClient.java:1574) ~[aws-java-sdk-xray-1.11.739.jar!/:na]
at com.amazonaws.services.xray.AWSXRayClient.invoke(AWSXRayClient.java:1563) ~[aws-java-sdk-xray-1.11.739.jar!/:na]
at com.amazonaws.services.xray.AWSXRayClient.executeGetSamplingRules(AWSXRayClient.java:800) ~[aws-java-sdk-xray-1.11.739.jar!/:na]
at com.amazonaws.services.xray.AWSXRayClient.getSamplingRules(AWSXRayClient.java:771) ~[aws-java-sdk-xray-1.11.739.jar!/:na]
at com.amazonaws.xray.strategy.sampling.pollers.RulePoller.pollRule(RulePoller.java:65) ~[aws-xray-recorder-sdk-core-2.4.0.jar!/:na]
at com.amazonaws.xray.strategy.sampling.pollers.RulePoller.lambda$start$0(RulePoller.java:46) ~[aws-xray-recorder-sdk-core-2.4.0.jar!/:na]
at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source) ~[na:na]
at java.base/java.util.concurrent.FutureTask.runAndReset(Unknown Source) ~[na:na]
at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(Unknown Source) ~[na:na]
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source) ~[na:na]
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) ~[na:na]
at java.base/java.lang.Thread.run(Unknown Source) ~[na:na]
...
Это означает, что AWS SDK не использует эту переменную среды, как указано в документации, а просто использует значение по умолчанию 127.0.0.1:2000
.
Затем я покопался в коде SDK, чтобы узнать, как он извлекает эту переменную, и обнаружил, что код, который ее запускает, использует System.getenv("AWS_XRAY_DAEMON_ADDRESS")
, как показано ниже:
/**
* Environment variable key used to override the address to which UDP packets will be emitted. Valid values are of the form `ip_address:port`. Takes precedence over any system property,
* constructor value, or setter value used.
*/
public static final String DAEMON_ADDRESS_ENVIRONMENT_VARIABLE_KEY = "AWS_XRAY_DAEMON_ADDRESS";
/**
* System property key used to override the address to which UDP packets will be emitted. Valid values are of the form `ip_address:port`. Takes precedence over any constructor or setter value
* used.
*/
public static final String DAEMON_ADDRESS_SYSTEM_PROPERTY_KEY = "com.amazonaws.xray.emitters.daemonAddress";
public DaemonConfiguration() {
String environmentAddress = System.getenv(DAEMON_ADDRESS_ENVIRONMENT_VARIABLE_KEY);
String systemAddress = System.getProperty(DAEMON_ADDRESS_SYSTEM_PROPERTY_KEY);
if (setUDPAndTCPAddress(environmentAddress)) {
logger.info(String.format("Environment variable %s is set. Emitting to daemon on address %s.", DAEMON_ADDRESS_ENVIRONMENT_VARIABLE_KEY, getUDPAddress()));
} else if (setUDPAndTCPAddress(systemAddress)) {
logger.info(String.format("System property %s is set. Emitting to daemon on address %s.", DAEMON_ADDRESS_SYSTEM_PROPERTY_KEY, getUDPAddress()));
}
}
Я подумал, может, я неправильно установил переменную окружения? Поэтому я добавил журнал получения переменной среды при запуске службы и обнаружил, что JVM действительно может найти значение:
Код:
System.out.println("System.getenv(\"AWS_XRAY_DAEMON_ADDRESS\")" + " = " + System.getenv("AWS_XRAY_DAEMON_ADDRESS"))
Вывод:
System.getenv("AWS_XRAY_DAEMON_ADDRESS") = aws-xray-daemon.default
Насколько я могу судить, этот код в точности соответствует тому, что должен запускаться AWS SDK, и тем не менее, кажется, что он никогда не запускается, и если это так, он не дает такого же результата, как то, что я тестировал с помощью своего журналы.
Работая локально, я не могу воспроизвести эту проблему, поскольку он выбирает хост, который я указал из переменных моей локальной среды. Я также подтвердил, что вставленный выше код AWS SDK достигается при локальном запуске с использованием точек останова.
Любые идеи?
Фрагмент Gradle:
ext {
...
springCloudVersion = "Greenwich.RELEASE"
awsCoreVersion = '1.11.739'
awsXrayVersion = '2.4.0'
...
}
dependencyManagement {
imports {
mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
mavenBom "com.amazonaws:aws-java-sdk-bom:${awsCoreVersion}"
mavenBom "com.amazonaws:aws-xray-recorder-sdk-bom:${awsXrayVersion}"
}
}
dependencies {
...
implementation "com.amazonaws:aws-java-sdk-core"
implementation "com.amazonaws:aws-xray-recorder-sdk-core"
implementation "com.amazonaws:aws-xray-recorder-sdk-aws-sdk"
implementation "com.amazonaws:aws-xray-recorder-sdk-spring"
implementation "com.amazonaws:aws-xray-recorder-sdk-apache-http"
implementation "com.amazonaws:aws-xray-recorder-sdk-sql-postgres"
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-security'
...
}
Другая информация:
- Запуск в Spring Boot v2.2.1
- OpenJDK v11.0.4
- Gradle v6.0.1
Другие попытки: - Я попытался установить переменную среды через Dockerfile
. Результат был тот же.