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
Выполняя c вход в модуль, на котором запущена служба и работает 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
. Это имело тот же результат.