RestTemplate에 관한 고찰
RestTemplate이란?
RestTemplate은 Spring에서 제공하는 Http Client이다.
기본적으로 동기식으로 작동한다.
RestTemplate은 직접 Http 요청의 수행을 담당하지는 않는다.
직접 수행하는 클래스를 한번 래핑한 어댑터 역할의 클래스이다.
기본적으로는 jdk에서 제공하는 HttpUrlConnection 클래스를 이용한다고 한다.
RestTemplate의 문제가 하나 있는데, RestTemplate은 매 Http 요청마다 Connection을 생성한다.
그렇기 때문에 매 연결마다 Three-Way Handshake
를 거친다는 의미이고 이는 빈번하게 발생할 경우 성능의 문제가 될 수 있다.
RestTemplate을 사용할 때 Connection Pool
을 설정하기 위해선 HttpComponentsClientHttpRequestFactory를 사용해야한다.
사용법은 간단하다.
val httpClient = HttpClients.custom()
.setMaxConnTotal(3)
.setMaxConnPerRoute(3)
.build()
val factory = HttpComponentsClientHttpRequestFactory(httpClient)
factory.setReadTimeout(5000)
factory.setConnectTimeout(3000)
val restTemplate = RestTemplate(factory)
위와 같이 HttpClient를 커스텀하여 최대 연결 가능한 연결 개수를 설정하고 factory의 생성자의 인자로 넘겨준다.
factory는 최대 타임아웃을 설정하고 RestTemplate에 생성자에 인자로 넘겨주면 된다.
setMaxConnTotal은 최대 커넥션의 개수이고,
setMaxConnPerRoute는 IP/domain name당 최대 커넥션 개수이다.
setReadTimeout은 Read시 최대 연결 시간이며,
setConnectTimeout은 서버 연결시 최대 타임아웃 시간이다.
여기까지 공부하면 대충 RestTemplate이 뭔지는 감이 온다.
그런데 오늘 팀원인 버나드가 SimpleClientHttpRequestFactory
에 관한 이야기를 해주셨고, 해당 Factory는 처음 들어봐서 공부를 좀 해보았다.
SimpleClientHttpRequestFactory 넌 누구니?
기본적으로 RestTemplate을 Default로 설정하면 SimpleClientHttpRequestFactory가 생성된다.
SimpleClientHttpRequestFactory는 공식 문서에 따르면 AsyncClientHttpRequestFactory
라는 인터페이스와 ClientHttpRequestFactory
를 구현한 클래스이다.
ClientHttpRequestFactory
는 이름만 봐도 기본적인 Factory 기능을 담당하는 인터페이스이다.
우리가 중요하게 봐야할 친구는 AsyncClientHttpRequestFactory
이 친구이다.
AsyncClientHttpRequestFactory
는 이름에서도 알 수 있다 싶이 Thread-Safe
한 기능을 제공해준다는 의미이며, 다시 말하면 RestTemplate을 Default로 만들면 RestTemplate은 기본적으로 Thread-Safe
하다고 말할 수 있겠다.
그러나 우리는 앞서 HttpComponentsClientHttpRequestFactory
를 사용했으니 둘의 차이점에 대해서도 알아볼 필요가 있겠다.
SimpleClientHttpRequestFactory과 HttpComponentsClientHttpRequestFactory의 차이
SimpleClientHttpRequestFactory와 HttpComponentsClientHttpRequestFactory의 가장 큰 차이는 Connection Pool의 생성여부이다.
SimpleClientHttpRequestFactory의 경우 이름 그대로 Factory에 간단한 설정만 지원하기 때문에 Connection Pool에 대한 설정을 할 수 없다.
때문에 Connection Pool의 설정이 필요하다면 HttpComponentsClientHttpRequestFactory를 사용하는 것이 적절하다.
Spring에서 쓸만한 다른 Http Client는 없나?
현재 팀에서 새로운 프로젝트의 기술스택을 논의하고 있는데, Http Client를 어떤 것을 사용할지에 대해 고심하고 있었다.
동기식 프로그래밍을 할 것이므로 RestTemplate을 사용해도 상관은 없으나 뭔가 새롭게 사용하고 싶은 기술이 있다면 자유롭게 이야기해보라고 하셨다.
팀에서 가장 시니어이신 버나드의 추천은 RxKotlin과 Retrofit의 조합을 사용하는 것인데, Retrofit의 경우 주로 안드로이드 계열에서 많이 사용하는 라이브러리이지만 서버사이드에서 종종 사용한다고 한다. (11번가)
나는 WebClient(Webflux)를 제안했었는데, 비동기 처리 외에는 딱히 RestTemplate보다 나은 점을 찾지 못해서 버나드의 말씀대로 RxKotlin과 Retrofit를 사용하려고 했었다.
근데 좀 조사하다보니 우연히 Feign이라는 라이브러리를 알게 되었다.
Fegin?
Fegin은 Netflix에서 개발된 Http Client Binder이다.
생산성이 굉장히 뛰어나서 웹 서비스 클라이언트를 쉽게 작성할 수 있다는 장점을 갖고 있다.
단점은 텍스트 기반 HTTP API기 때문에 파일 다운로드나 업로드를 위한 binary data
를 다룰 수 없다는 점인데 이것을 제외하곤 장점이 굉장히 많은 라이브러리이다.
RestTemplate보다 생산성이 높다고 하니 이번 프로젝트에 한번 사용해볼만 한 것 같다.
또한 Retrofit과 Feign을 서버사이드에서 사용할 때 비교를 해놓은 글이 있는데 관심있는 사람은 보길 바란다.
https://www.javacodemonk.com/retrofit-vs-feign-for-server-side-d7f199c4
해당 글에서는 Android 개발이라면 Retrofit을, MicroService 기반의 서버사이드라면 Feign을 사용하는 것이 좋겠다고 결론을 내렸다.
그 이유는 Springboot에서 Feign을 적용하는 방법은 의존성 추가하나만 해주고 애노테이션 몇개 달면 끝이다.
이미 Spring Cloud에서는 Feign을 Http Client로 지원하고 있어서 더욱 적합하다고 생각했다.
러닝커브가 완만하고 생산성이 높은 것이 이 라이브러리의 가장 큰 장점인데, 이번 프로젝트가 주로 신입들이 주도해서 진행하는 프로젝트인 만큼 생산성이 높은 라이브러리를 쓰는게 좋다고 생각하였다.
이미 배달의 민족에서도 Feign을 적용하였고 운영상 문제도 없다고 하여 사용해보는 것도 나쁘지 않을 것 같다.
Reference
https://multifrontgarden.tistory.com/249
https://kwonnam.pe.kr/wiki/java/apache_http_client