spring boot에서 aop를 이용해 xray 구성하기
- Repository = xray
시작하기
API 호출을 많이 당하고? 있는 서버가 있는데, 문득 어떤 API를 많이 호출하고 있는지 확인 해보고 싶어져서 AWS의 x-ray를 사용해서 tracing 해보고 싶어졌다
Spring boot, aop, aws x-ray 를 사용해서 api를 tracing 해보자.
(해당 포스팅은 로컬 mac환경에서 테스트해 본 것을 기준으로 할 꺼다)
X-RAY 데몬 설치하기
x-ray sdk가 전송하는 데이터가 x-ray 서비스에 도달하려면 데몬이 실행 중 이어야 한다.
xray 데몬을 설치하기 전에 aws x-ray 서비스에 데이터를 전송할 권한이 있어야하는데, 나는 로컬에서 할 것이기 때문에 로컬에다가 자격증명(credentials) 하면된다.
aws iam에서 xray 권한을 가진 user를 만들고, cli로 credentials 해준다.
$ aws configure
AWS Access Key ID [None]: 엑세스키
AWS Secret Access Key [None]: 시크릿키
Default region name [None]: ap-northeast-2
Default output format [None]: text
다음 아래 xray 데몬을 다운 받아야하는데
위 가이드에서 참고하여 다운로드 후 압축해제 해준다.
(나의 로컬 환경은 OS X라서 aws-xray-daemon-macos-3.x.zip(sig) 를 다운)
이제 다운받은 데몬을 각 환경에 맞게 실행해주면 된다.
./xray_mac -o -n ap-northeast-2
이렇게 실행하면 아래와 같이 2000 port로 실행 성공한 것을 확인 할 수 있다.
[Info] Initializing AWS X-Ray daemon 3.2.0
[Info] Using buffer memory limit of 81 MB
[Info] 1296 segment buffers allocated
[Info] Using region: ap-northeast-2
[Info] HTTP Proxy server using X-Ray Endpoint : https://xray.ap-northeast-2.amazonaws.com
[Info] Starting proxy http server on 127.0.0.1:2000
Spring boot에서 dependencies 추가
이제 x-ray 트레이싱을 위해 gradle에 dependency를 추가해 주자.
// xray 관련
dependencyManagement {
imports {
mavenBom('com.amazonaws:aws-xray-recorder-sdk-bom:2.4.0')
}
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-aop'
annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor'
annotationProcessor 'org.projectlombok:lombok'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
compile 'com.h2database:h2'
testImplementation('org.springframework.boot:spring-boot-starter-test') {
exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
}
// xray 관련
compile("com.amazonaws:aws-xray-recorder-sdk-core")
compile("com.amazonaws:aws-xray-recorder-sdk-aws-sdk")
compile("com.amazonaws:aws-xray-recorder-sdk-aws-sdk-instrumentor")
compile("com.amazonaws:aws-xray-recorder-sdk-apache-http")
compile("com.amazonaws:aws-xray-recorder-sdk-spring")
}
디펜던시 추가 시 datasource 가 필수인듯(추후에 다시 설명) 해서 jpa도 추가하고, 프로퍼티에서 datasource도 설정해준다.
aop를 사용해서 트레이싱할 예정이니 aop도 추가해주자.
전역 레코더 구성, TracingFilter 설정
아래 코드를 생성하여 AWSXRayRecorderBuilder를 전역에 설정해주고,
샘플링 룰을 설정할 수 있는 sampling-rules.json 파일도 생성해준다.
이 레코더가 json형태의 데이터(세그먼트)를 생성하여 데몬에 전달하는 듯 하다.
세그먼트를 생성할 때의 규칙을 해당 설정 json파일(sampling-rules.json)에 정의하면
허용 url, 허용 method, rate 등 세그먼트에 대한 규칙을 설정할 수 있다.
package com.isntyet.test.aws.xray.config;
import com.amazonaws.xray.AWSXRay;
import com.amazonaws.xray.AWSXRayRecorderBuilder;
import com.amazonaws.xray.javax.servlet.AWSXRayServletFilter;
import com.amazonaws.xray.plugins.EC2Plugin;
import com.amazonaws.xray.strategy.sampling.CentralizedSamplingStrategy;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.servlet.Filter;
import java.net.URL;
@Configuration
public class WebConfig {
static {
AWSXRayRecorderBuilder builder = AWSXRayRecorderBuilder.standard().withPlugin(new EC2Plugin());
URL ruleFile = WebConfig.class.getResource("/sampling-rules.json");
builder.withSamplingStrategy(new CentralizedSamplingStrategy(ruleFile));
AWSXRay.setGlobalRecorder(builder.build());
}
@Bean
public Filter TracingFilter() {
return new AWSXRayServletFilter("JoTest");
}
}
- /src/main/resources/sampling-rules.json
{
"version": 1,
"default": {
"fixed_target": 1,
"rate": 1
}
}
TracingFilter 에서는 AWSXRayServletFilter를 통해서 세그먼트 이름을 fix 할 수 있다.
XrayInspector 생성 (aop)
aop를 활용하면 특별한 로직을 추가하지 않아도 쉽게 설정할 수 있다.
- aop 활성화
@SpringBootApplication @EnableAspectJAutoProxy public class XrayApplication { public static void main(String[] args) { SpringApplication.run(XrayApplication.class, args); } }
aop를 활성화 해주고
- XrayInspector
package com.isntyet.test.aws.xray.interceptor; import com.amazonaws.xray.entities.Subsegment; import com.amazonaws.xray.spring.aop.AbstractXRayInterceptor; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; import org.springframework.stereotype.Component; import java.util.Map; @Aspect @Component public class XrayInspector extends AbstractXRayInterceptor { @Override protected Map<String, Map<String, Object>> generateMetadata(ProceedingJoinPoint proceedingJoinPoint, Subsegment subsegment) { return super.generateMetadata(proceedingJoinPoint, subsegment); } @Override @Pointcut("@within(com.amazonaws.xray.spring.aop.XRayEnabled) && bean(*Controller)") public void xrayEnabledClasses() { } }
AbstractXRayInterceptor 를 상속받은 XrayInspector를 구현해준다.
xrayEnabledClasses 포인트컷에서 설정한 것 처럼 XRayEnabled 설정된 Controller bean이 래핑되어 해당 컨트롤러에서 추적이 될것이다.
이전에 datasource 설정이 필요하다고 했는데 이유는 AbstractXRayInterceptor 를 들어가보면
@Pointcut("execution(public !void org.springframework.data.repository.Repository+.*(..))") protected void springRepositories() { }
부분에서 data repository 가 포인트컷에 들어가 있기 때문에 datasource 설정을 해주지 않으면 실행이 되지 않는다ㅡㅡ;;
테스트 controller 만들기
이제 테스트로 호출해 볼 api가 필요하니 controller를 구성해보자.
- XrayController
@RestController @XRayEnabled public class XrayController { private XrayService xrayService; public XrayController(XrayService xrayService){ this.xrayService = xrayService; } @GetMapping("/test") public String test(){ return "test"; } @GetMapping("/real") public String real(){ String testStr = xrayService.testStr(); System.out.println(testStr); return testStr; } }
대충 스트링이 반환되게 구성하고 @XRayEnabled 를 꼭 기입하여 xray 활성화를 시켜준다.
API 테스트
이제 준비가 끝났으니 만들어진 api를 호출해보면 이전에 실행해놓은 데몬에 로그가 찍힐것이다.
- 데몬 로그
[Info] 1296 segment buffers allocated [Info] Using region: ap-northeast-2 [Info] HTTP Proxy server using X-Ray Endpoint : https://xray.ap-northeast-2.amazonaws.com [Info] Starting proxy http server on 127.0.0.1:2000 [Info] Successfully sent batch of 1 segments (0.632 seconds) [Info] Successfully sent batch of 1 segments (0.027 seconds)
이렇게 ‘Successfully’ 라고 뜨면 성공한것이다.
-
aws의 x-ray 서비스 콘솔의 트레이스 메뉴
위와 같이 트레이싱 되어 url, 평균응답시간, 트레이스 비율 등을 볼 수 있다.
Comments