[MSA] 스프링부트 gRPC vs FeignClient 성능 비교
시작하며
안녕하세요. 개발자 stark입니다.
드디어 gRPC 시리즈의 마지막 포스팅입니다! 이번 포스팅을 통해 gRPC와 FeignClient의 성능 차이를 알아보고 왜 gRPC를 사용하는 게 좋은지 그리고 어떻게 gRPC를 사용하기 위해 어떤 식으로 구성해야 하는지를 알게 될 것입니다.
제가 지금까지 열심히 MSA 프로젝트를 구성하고 gRPC서버, 클라이언트를 구성한 이유가 바로 성능 테스트를 위해서였습니다. 왜냐하면 MSA에서 어떤 통신 방식을 적용하는 것이 좋을지에 대해서 정말 많은 생각을 해왔기 때문입니다. 일반적으로는 Feign을 쓰는데 저는 아무리 봐도 gRPC가 더 좋을 것이라는 생각이 들었습니다.
왜냐하면 저는 MSA를 하면서 Feign도 써보고 너무 궁금해서 gRPC도 공부를 하며 써봤기 때문입니다. 그런데 제가 gRPC를 사용하면서 느낀 점이 gRPC가 생각보다 래퍼런스가 많지 않다는 것입니다. 그렇다 보니 아무리 gpt가 열심히 답변해 준다 하더라도 일반적으로 생각하기에 당연히 래퍼런스가 더 많고 안전하다는 생각이 드는 FeignClient를 주로 선택하게 되었습니다.
근데 저는 MSA를 구성하며 항상 이런 생각을 합니다. 가능한 Feign대신 gRPC를 사용하고 싶다. 단지 구글이라는 이름이 멋있어서 그런 게 아닙니다. Google이 아무런 이유도 없이 본인들만의 rpc 통신을 구성하고 사용했을 리가 없을 것이라는 생각이 들기 때문입니다.
분명 뭔가 이유가 있을 것이라고 생각했고 저는 그들의 세계를 아주 조금이라도 이해하고 싶어서 이런 식으로라도 성능 테스트를 구성하게 되었습니다. 사실 gRPC가 개발된 이유는 당연히 공식적으로는 밝혀진 게 있겠지만 정확한 탄생 비화는 당시의 구글 팀원들만 알겠죠?
지금부터 우리는 아래의 그림과 같이 Stark라는 개발자가 회원 조회 요청을 보내면 Tomcat으로 구성된 스프링부트 클라이언트 서버가 api 요청을 받아서 1번 gRPC 요청을 하는 방식과 2번 Feign http 요청을 하는 방식으로 성능을 비교해 볼 것입니다.
자 마지막 목차를 봅시다. (모든 코드는 각 시리즈 포스팅에 github 주소가 적혀있습니다!)
1. SpringBoot gRPC 서버 구성하기 (회원가입, 조회 api 설계)
2. SpringBoot gRPC 클라이언트 구성하기 (회원 조회 feignClient, gRPC 클라이언트 구성)
3. MSA 서버 간 인증 적용하기 (jwt 서버 토큰 구성, gRPC 인터셉터 적용)
(현 게시글) 4. locust로 http와 gRPC의 성능 비교하기
그럼 지금부터 gRPC의 성능 테스트를 해봅시다. Let's go~~
테스트 환경설정 진행하기
이번 테스트를 구성할 때 참 많은 고민을 했습니다. 왜냐하면 http 요청에 일반적으로는 spring의 tomcat을 사용하고 gRPC는 기본적으로 netty를 사용하기 때문에 결과적으로 스레드를 사용하는 방식이 다를 텐데 이런 상황에는 스레드풀 크기를 동일하게 설정해서 테스트하는 게 맞을까? 아니면 그냥 최적의 설정이나 기본 설정으로 테스트하는 게 맞을까? 이런 고민들은 끝이 나지 않았습니다. 그래서 일단 그냥 기본 설정(권장)대로 진행해 봤습니다!
일단 gRPC 스레드를 설정해 봅시다. 핵심 포인트는 다음과 같습니다.
- 이벤트 루프 모델 활용 : Netty는 blocking 작업을 피하고 이벤트 루프 내에서 빠르게 처리하는 것을 전제로 설계되어 있습니다. 기본적으로 CPU 코어 수에 기반해 스레드를 할당하는데, 일반적으로 availableProcessors * 2 정도가 권장됩니다. (gRPC는 내부적으로 Netty의 기본 이벤트 루프를 사용하므로 별도의 스레드풀을 강제로 늘릴 필요는 없습니다.)
@Configuration
public class GrpcServerConfig {
@Bean
public GrpcServerConfigurer grpcServerConfigurer() {
return serverBuilder -> {
if (serverBuilder instanceof NettyServerBuilder nettyServerBuilder) {
// 기본 이벤트 루프 스레드 외에 blocking 작업 처리를 위한 별도 Executor 사용
int availableProcessors = Runtime.getRuntime().availableProcessors();
// blocking 작업이 많은 경우 CPU 코어 수의 2배 정도의 스레드를 사용
ExecutorService blockingExecutor = Executors.newFixedThreadPool(availableProcessors * 2);
nettyServerBuilder
.executor(blockingExecutor)
.maxInboundMessageSize(10 * 1024 * 1024) // 예: 최대 10MB 메시지
.keepAliveTime(30, TimeUnit.SECONDS)
.keepAliveTimeout(5, TimeUnit.SECONDS)
.permitKeepAliveWithoutCalls(true);
}
};
}
}
다음으로 Feign을 동작시킬 Tomcat의 스레드풀도 설정해 봅시다. 핵심 포인트는 다음과 같습니다.
- Blocking I/O 특성 : Tomcat은 기본적으로 요청당 하나의 스레드를 사용합니다. 따라서 동시 요청이 많은 경우 최대 스레드 수(maxThreads)를 충분히 확보하는 것이 중요합니다. 운영 환경에서 Tomcat의 기본 maxThreads 값은 200 정도가 일반적입니다. 가만히 놔두면 알아서 200개를 사용하지만 그래도 명시적으로 작성해 봤습니다.
@Configuration
public class TomcatServerConfig implements WebServerFactoryCustomizer<TomcatServletWebServerFactory> {
@Override
public void customize(TomcatServletWebServerFactory factory) {
factory.addConnectorCustomizers(connector -> {
// Tomcat 10 이상 또는 최신 JDK에서는 아래와 같이 cast할 수 있습니다.
if (connector.getProtocolHandler() instanceof Http11NioProtocol protocol) {
protocol.setMaxThreads(200); // 동시 요청을 감당할 최대 스레드 수
protocol.setMinSpareThreads(20); // 유휴 상태에서도 유지할 최소 스레드 수
protocol.setConnectionTimeout(30000); // 연결 타임아웃 (30초)
}
});
}
}
참고사항 (소스코드 및 시리즈 설명)
지금까지 제가 gRPC를 기본적으로 세팅하고 설정하는 방법을 알려드렸기에 http 요청에 대한 설명이 많이 부족했을 것입니다. 저는 테스트 환경을 동일하게 구성하기 위해서 FeignClient 요청 시에도 서버 간의 jwt 인증을 진행하도록 Spring Security에 Filter를 적용시켜 주었습니다. 코드는 아래의 github에 있으니 직접 해보고 싶으시거나 궁금하신 분은 확인 부탁드립니다~
소스코드는 하단의 github에 있습니다. 편하게 가져다 사용하셔도 됩니다!
- gRPC 서버 프로젝트 소스코드입니다. (Github)
GitHub - wlsdks/grpc-server-example: SpringBoot3.x.x 버전 grpc 예제 프로젝트 (gRPC 서버 예시 코드이며 클라이
SpringBoot3.x.x 버전 grpc 예제 프로젝트 (gRPC 서버 예시 코드이며 클라이언트와 함께 봐주세요) - wlsdks/grpc-server-example
github.com
- gRPC 클라이언트 프로젝트 소스코드입니다. (Github)
GitHub - wlsdks/grpc-client-example: SpringBoot3.x.x 이상 버전의 grpc 예제 프로젝트 (gRPC 서버 코드와 함께 확
SpringBoot3.x.x 이상 버전의 grpc 예제 프로젝트 (gRPC 서버 코드와 함께 확인해주세요) - wlsdks/grpc-client-example
github.com
참고로 gRPC 성능 테스트를 진행하려면 위의 2개 프로젝트를 모두 실행해야 합니다. 또한 회원가입과 로그인을 해야만 테스트가 가능하므로 꼭 postgreSQL를 실행해주셔야 합니다. (h2로 구성하셔도 됩니다!)
gRPC 시리즈 총모음입니다. 이전 글을 통해서도 얻어갈 수 있는 것이 많을 것입니다.
- 1탄: SpringBoot gRPC 서버 구성하기 (회원가입, 조회 api 설계)
[MSA] SpringBoot에 gRPC 서버 구성하기: 회원 서비스 만들기
시작하며안녕하세요. 개발자 stark입니다.최근 업무가 조금 바빠져서 블로그에 글을 작성하지 못했는데요. 설이기도 하고 정리할 시간이 생겨서 오랜만에 글을 적게 되었습니다. 제가 이번 연도
curiousjinan.tistory.com
- 2탄: SpringBoot gRPC 클라이언트 구성하기 (회원 조회 feignClient, gRPC 클라이언트 구성)
[MSA] SpringBoot에 gRPC 클라이언트 구성하기
시작하며안녕하세요. 개발자 stark입니다. 이전 포스팅에서는 gRPC 서버를 구성해 봤습니다. 이번에는 gRPC 클라이언트 서버를 구성해 봅시다.지금 구성중인 프로젝트는 MSA이기 때문에 최소 2개의
curiousjinan.tistory.com
- 3탄: MSA 서버 간 인증 적용하기 (jwt 서버 토큰 구성, gRPC 인터셉터 적용)
[MSA] SpringBoot에서 gRPC 인터셉터로 서버간 jwt 인증 구현
시작하며안녕하세요. 개발자 stark입니다!이번 포스팅에서는 gRPC를 사용한 MSA 프로젝트에 서버 간 인증 기능을 구현해 볼 것입니다. MSA 프로젝트에서는 각 서버 간의 통신이 매우 빈번하게 발생
curiousjinan.tistory.com
테스트를 위해 Locust 세팅하기
locust를 실행하기 위해 docker-compose.yml을 생성합니다.
version: '3.8'
services:
master:
image: locustio/locust
ports:
- "8089:8089"
volumes:
- ./:/mnt/locust
command: -f /mnt/locust/locustfile.py --master -H http://host.docker.internal:8091
worker:
image: locustio/locust
volumes:
- ./:/mnt/locust
command: -f /mnt/locust/locustfile.py --worker --master-host master
# docker-compose up -d --scale worker=3 명령어로 worker를 3개로 늘릴 수 있음
# http://localhost:8089 접속 후 테스트를 실행할 수 있음
이후 locust 테스트를 위한 python 코드를 작성합니다.
- 저는 locustfile.py라는 이름으로 프로젝트 내부에서 src과 같은 위치에 파일을 생성해 주었습니다. 하단의 코드를 보면 api가 적혀있는데 실제로 프로젝트에 선언해 준 api입니다. 이 api는 각각 gRPC 통신과 Feign통신을 진행합니다. 위의 github에 들어가셔서 소스코드를 확인하실 수 있습니다. (이번 포스팅은 테스트 결과를 설명드리기 위함이라 코드는 생략합니다.)
- 참고로 하단의 코드를 보면 @task(0), @task(1)이 있고 주석이 되어있는데 저는 각 api별로 테스트를 하기 위해 매번 주석을 바꿔가면서 locust를 재실행했습니다. (docker 완전 종료 후 주석 변경하고 재실행) 물론 동시에 2개의 api에 고르게 부하를 줄 수도 있지만 진정한 테스트는 하나만 확실하게 보는 것 아니겠습니까?
from locust import HttpUser, task, between
import json
class GrpcVsFeignTest(HttpUser):
wait_time = between(0.1, 0.5)
token = "Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ0ZXN0QHRlc3QuY29tIiwiaWF0IjoxNzM3ODk4NTU2LCJleHAiOjE3Mzc5MDIxNTZ9.3YJctScdUDKW33L664ReW7MoyBxkx5W2iRsQHsJgz4U"
def on_start(self):
self.client.headers = {"Authorization": self.token}
@task(1)
# @task(0)
def test_grpc(self):
self.client.get("/api/test/grpc", params={"memberId": "1"}, name="gRPC Call")
@task(0)
# @task(1)
def test_feign(self):
self.client.get("/api/test/feign", params={"memberId": "1"}, name="Feign Call")
아! 여기서 아셔야 할 부분이 있는데 지금 파이썬 코드를 보면 최상단에 token으로 jwt를 넣어주고 있습니다. 왜냐하면 클라이언트 서버의 api는 유저의 accessToken을 받아서 인증이 통과하면 api를 호출하도록 보안을 적용해 두었기 때문입니다. 그러니 회원 서버 (프로젝트)에 가셔서 회원가입을 하고 로그인까지 해서 jwt를 발급받고 이 파일에 적어주셔야 합니다. (참고로 저는 토큰 만료기간을 짧게 설계했더니 테스트를 잔행 하던 도중 토큰이 깨지면서 오류가 발생하는 단점이 있었습니다 ㅠㅠ 그러니 만료기간을 충분히 늘려서 테스트하시는 걸 추천합니다.)
Locust에 접속해 봅시다.
이제 터미널에 아래 명령어를 입력합시다. (참고로 저는 docker-desktop을 사용 중입니다)
# docker-compose up -d --scale worker=3 명령어로 worker를 3개로 늘릴 수 있음
그리고 페이지에 접속해 줍니다.
# http://localhost:8089 접속 후 테스트를 실행할 수 있음
url에 localhost:8089를 입력하고 들어가면 아래와 같은 화면이 나올 것입니다.
이제 이 화면에서 테스트를 위한 설정값을 세팅해줘야 합니다.
- Number of Users (동시 사용자 수): 1000 users (한 번에 1000명의 사용자가 접속하는 시나리오를 시뮬레이션합니다.)
- Ramp-Up (램프업): 30 (사용자가 점진적으로 증가하는 속도는 초당 30명씩 추가되도록 설정합니다. 즉, 1000명의 사용자가 도달하기까지 서서히 부하가 증가합니다.)
- Test Duration (테스트 지속 시간): 10m (Advanced Options에서 10m, 즉 10분 동안 테스트를 진행하여 충분한 데이터를 수집합니다.)
첫 번째 테스트 진행
첫 번째 테스트로 받게 되는 응답 객체를 살펴봅시다. (굉장히 중요합니다)
- 별거 없는데? 이렇게 생각하실 수 있지만 profileImageBase64에 긴 문자열을 설정해 두었습니다. 우측으로 스크롤하시면 응답값이 계속해서 이어지는 것을 확인하실 수 있을 것입니다. 그리고 저는 이런 구조가 테스트에 영향을 줄 수 있다는 것을 이번 테스트로 배우게 되었습니다. (지금부터 테스트 결과를 보며 천천히 알아봅시다)
{
"id": 1,
"email": "test@test.com",
"name": "test",
"profileImageBase64": "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",
"address": {
"street": "123 Test St",
"city": "Test City",
"country": "Test Country",
"postalCode": "12345",
"additionalInfo": {
"building": "A",
"floor": "5",
"doorCode": "1234"
}
},
"contact": {
"phone": "123-456-7890",
"mobile": "098-765-4321",
"workPhone": "111-222-3333",
"emails": [
"work@test.com",
"personal@test.com"
],
"socialMedia": {
"twitter": "@testuser",
"linkedin": "linkedin.com/testuser",
"facebook": "fb.com/testuser"
}
},
"interests": [
"coding",
"testing",
"debugging"
],
"skills": [
"spring",
"java",
"grpc"
],
"metadata": "{\"lastLogin\":\"2024-01-23\",\"status\":\"active\",\"rank\":\"senior\"}"
}
첫 번째 gRPC 요청을 진행해 본 결과입니다.
- 테스트 설정은 이렇게 했습니다. "유저 = 1000명, "램프업=30", "총 시간 10분" 그리고 그 결과는 충격적이었습니다. 제 맥북 사양이 상당히 좋은 편인데 개인적으로 이 정도 요청에서 이렇게 RPS가 낮게 나오는 것은 처음 봤습니다.
이제 차트를 봅시다.
- 차트는 일반적인 스트레스 테스트에서 보이는 매우 안정적인 그래프를 보여줍니다.
아 이제 Feign 요청을 확인해 봅시다.
- 음....?? 결과를 보시면 성능 차이가 거의 없습니다. 사실상 gRPC나 Feign이나 성능이 동일하다고 봐도 될 것 같습니다. 제가 잘못 본 줄 알았습니다. 개인적으로는 gRPC 짱! 이러고 있었는데 이 테스트 결과를 보고 실망했습니다.
차트는 gRPC와 동일하게 매우 안정적입니다.
뭔가 잘못된 걸까요? 사실상 gRPC나 Feign이나 성능차이가 느껴지지 않습니다. 그러면 대체 왜 gRPC를 사용하는 걸까요? 그냥 유명한 Feign을 쓰면 될 텐데.. 비동기가 가능해서 사용하는 걸까요? 아직은 확실하지 않습니다. 그래서 저는 좀 더 다양한 테스트를 구성해 봤습니다. 다음 테스트는 사용자를 3000명으로 늘리고 램프도 100으로 늘려봤습니다. 물론 테스트 시간은 동일하게 10분을 적용시켰습니다.
두 번째 테스트 진행
두 번째 테스트는 3000명 100명씩 증가 총 10분으로 테스트를 변경하고 다시 진행했습니다.
- 제 생각은 당연히 사용자수가 많아지면 gRPC가 더 좋겠지? 였습니다. 그러나 아래 결과를 보시면 사실상 첫 번째 테스트와 다른 게 없습니다. 저는 오히려 신기합니다. 사용자가 3배나 늘었는데 성능은 좋아지지도 나빠지지도 않았고 서버가 터지지도 않았습니다.
그래프를 봅시다.????? 뭐죠.. 왜 이렇게 안정적인 걸까요? 사용자가 늘어났는데 성능은 그대로이면서 그래프는 안정적인 쉽게 이해하기 힘든 현상입니다.
자 그럼 Feign요청을 해봅시다. 뭔가 다를까요?
- 엥..? 얘도 똑같습니다. 1000명일 때와 크게 다른 게 없습니다. RPS가 조금 느려지긴 했다만 사실상 의미 없는 수준입니다.
그래프도 매우 안정적입니다. 사용자를 3000명으로 늘렸는데 말이죠..?
처음에는 굉장히 아리송했습니다. 그래서 계속 생각했습니다. 대체 왜 1000명이든 3000명이든 똑같을까? 적어도 사용자가 많으면 터지기라도 해야 하는 거 아닌가..? 근데 이런 생각을 부숴버리듯 결과적으로는 매우 평온하게 테스트가 진행되었고 두 번의 테스트는 사실상 결과가 동일합니다. 그리고 그래프도 gRPC, Feign 요청 둘 다 모두 굉장히 안정적으로 처리하고 있습니다.
저는 이 결과를 보며 1000명이든 3000명이든 RPS가 거의 동일하니 이런 생각이 들었습니다. 문자열을 워낙 길게 보내서 서버 간 통신에서 Payload를 받은 다음 객체로 변환화는 과정인 직렬화/역직렬화 단계에서 오래 걸려서 성능이 안 나오고 작업이 오래 걸려서 아무리 많은 요청이 들어와도 처리속도가 따라가지를 못하니 사람이 1000명이든 3000명이든 결국 두 테스트가 해낼 수 있는 작업량은 동일하게 나타나는 게 아닐까?
그래서 저는 일반적인 상황을 생각해 봤습니다. 사실 누가 회원 한 명의 데이터를 엔티티 5~6개로 나누고 이런 식으로 엄청나게 긴 문자열을 받을까요? 제가 애초에 잘못 설정한 것 같다는 생각이 들었습니다. 그리고 밑져야 본전입니다. 제 생각이 맞든 틀리든 가설을 세웠으면 실행해 봐야겠죠? 그래서 엔티티 구조를 완전히 바꿨습니다. 간단히 1개의 테이블로 변경하고 긴 문자열도 응답에서 없애버렸습니다. 그리고 이 상태로 세 번째 테스트를 진행해 봤습니다.
세 번째 테스트 (응답 JSON 재구성)
아래와 같이 응답을 아주 깔끔하게 변경했습니다.
- 응답을 변경한 뒤 이번에는 사용자를 1500명으로 설정하고 램프는 30 그리고 총시간은 이전 테스트들과 동일하게 10분으로 설정했습니다. 1000명으로 할 수도 있지만 이번에는 뭔지 모를 자신감이 있었습니다. 그래서 조금 더 높여봤습니다. 그리고 제게는 이번 테스트 결과가 달라야만 했습니다. 그렇지 않으면 왜 gRPC를 쓰는지 정말 모를 것만 같았기 때문입니다.
{
"id": 1,
"email": "test@test.com",
"name": "test",
"profileImageBase64": "",
"address": null,
"contact": null,
"interests": null,
"skills": null,
"metadata": null
}
드디어 정상적으로 테스트가 진행된 것 같습니다.
- 제발 비교할만한 수치가 나오기를 원했던 제 바람이 통했는지 RPS가 3943이라는 엄청난 성능을 보여줬습니다. 실패도 단 한건도 없고 매우 안정적인 것을 확인할 수 있습니다.
그래프 결과를 보면 조금 독특합니다.
- 전체적으로 부드럽게 흘러가는 것 같지만 "Response Times"를 보면 조금 불안정한 모습을 보입니다. 그래도 오류 없이 완전히 원했던 결과를 보여주는 것을 알 수 있습니다. 일단 에러가 하나도 없습니다!
자 그럼 대망의 Feign 테스트입니다. 너만 잘 나와주면 된다!!
- 헉..!! 제대로 테스트가 된 게 맞을까요? 어째서인지 Feign요청 테스트는 상당한 오류(Fails)를 보여줍니다. RPS는 1940이며 사실상 이것도 오류가 포함된 거라 별 의미가 없습니다.
그래프를 봅시다. 참담합니다.
- 그래프가 완전히 맛이 갔습니다. 위아래 왔다 갔다 난리입니다. 그리고 한 가지 알 수 있는 것은 완벽하진 않지만 오류가 발생한 지점을 잘 보시면 오류발생 이전에는 갑자기 서버의 RPS가 올라갑니다. 그리고 RPS가 높아지면 다음에 바로 오류가 발생하면서 RPS가 귀신같이 떨어집니다.
이번 테스트를 하면서 제 가정이 맞은 것 같다는 생각이 들었습니다. 결국 직렬화/역직렬화 이게 문제가 아니었을까요? Payload를 잘 관리해야 하는 이유가 이런 것이군요...? 아무 데이터나 막 던지면 큰일 날 것 같습니다.
결과를 보면 gRPC를 호출하는 api는 매우 안정적으로 처리하고 RPS도 상당히 높습니다. 반면 Feign을 호출하는 api에서는 실패도 계속 발생하고 매우 불안한 모습을 보여줍니다. 단순 수치로 성능을 보면 3943 : 1940으로 gRPC가 완전히 압도하는 모습을 보여주며 gRPC는 220만 개의 요청을 처리했지만 그중 단 하나의 오류도 발생하지 않았습니다. 하.. 이거지! 저는 이런 결과를 보고 싶었습니다. 구글이 만든 기술이라면 이 정도는 되어야지!
네 번째 테스트 (마지막 검증)
자 그럼 Response를 변경함으로써 테스트는 가능하게 되었습니다. 그러니 이제 스트레스 지수를 높여봅시다.
- 이번에는 사용자를 3000명으로 지정하고 램프 크기는 100으로 한 다음 총시간은 동일하게 10분으로 설정했습니다. 그리고 이 테스트 결과를 통해 저는 굉장히 중요한 인사이트를 얻게 되었습니다. 드디어 왜 gRPC를 쓰는지 확신하게 되었습니다.
이번 테스트 결과는 매우 흥미롭습니다.
- 분명 1000명에서 3000명으로 사용자를 늘렸는데 RPS가 낮아지긴커녕 오히려 4281로 이전의 3943보다 300이나 올랐습니다. 뭐죠...? 엄청납니다. 그리고 실패(Fails)는 단 1건도 나타나지 않았습니다. 정말 결과를 보면 미쳤다는 말밖에 나오지 않습니다.
그래프를 봅시다.
- 이번 테스트에서도 이전과 같이 Response Times만 조금 울퉁불퉁하고 나머지는 완전히 상태가 좋습니다.
자 그럼 Feign요청을 해봅시다.
- 헉.. 난리가 났습니다. 이전에는 1940이었는데 1830까지 떨어졌습니다. 300이 오른 gRPC와는 완전히 반대로 100이 내려갔습니다. 또한 실패를 보시면 이전 테스트는 실패가 13만 개였는데 이번에는 23만 개입니다. 사실상 저 RPS도 실패율이 반영된 것이니 실제로는 압도적으로 더 나빠진 것으로 보는 게 맞습니다. 이렇게 Feign 요청은 써먹을 수 없는 수준입니다.
그래프를 봅시다.
- 참담합니다. 정말 사용할 수 없을 정도의 성능을 보여줍니다. 그래프도 실패랑 성공이 거의 동일하게 복사한 것처럼 위아래에서 움직이고 있습니다.
이번 테스트로 저는 많은 것을 배웠습니다. gRPC든 Feign이든 가장 먼저 고려해야 할 것은 서버에서 어떤 형식의 데이터를 전달하는지와 그 구조가 어떤지를 꼭 파악하고 최적화해야 한다는 것입니다. 이전에 제가 모르고 엄청 긴 문자열을 사용했을 때와는 다르게 완전히 뚜렷한 성능 차이를 보여줍니다.
이번 테스트 결과를 분석해 보면 feign은 단순 계산해 보면 오류가 20%에 가깝습니다. 사실상 이 정도면 서버로의 기능은 불가능하다고 봐야 합니다. 3000명의 유저는 버티지 못한다고 봐야죠.. 반면 gRPC를 사용한 서버는 정말 놀랍다는 말밖에 안 나옵니다. 실패는 0개입니다. 그리고 모든 요청이 다 성공해서 100%를 보여주며 성능은 압도적으로 잘 나온다. 아주 예뻐죽겠습니다. 이래서 gRPC를 쓰나 봅니다.
마무리하며 (결론)
이번 테스트로 깨달음을 얻었습니다. gRPC, Feign 중 무엇을 사용할지 고민하실 텐데 만약 이동시킬 데이터의 용량 자체가 크다면 사실상 어떤 것을 사용해도 성능에는 의미가 없습니다. 그러니 gRPC가 좋다고 생각해서 무작정 도입해서는 안됩니다. 오히려 유지보수나 관리만 힘들어질 수도 있습니다. 기술은 항상 적재적소에 필요한 상황이 있으니 이런 사실을 모르고 도입하면 제가 처음 테스트했을 때처럼 좋지도 않은데 왜 gRPC 쓰는 거지? 이런 생각을 분명하게 될 것입니다. (물론 gRPC에는 압축 기능이 있긴 합니다.)
자 근데 응답 데이터를 최적화해서 다시 테스트를 해보면 이런 생각이 듭니다. gRPC는 신이잖아! 왜냐하면 토큰 인증도 되면서 성능은 Feign보다 더 좋고 구성하는 것도 쉽고 간단합니다. 이런 gRPC를 MSA 구성에서 쓰지 않을 이유가 있을까요? 그래서 저는 많은 개발자들이 MSA에 Feign을 사용하는 이유는 단순히 아직 gRPC에 대한 이런 검증 래퍼런스가 부족하기 때문이라고 생각합니다. 사실 제가 한 이 테스트도 잘못되었을 수도 있습니다. 그러니 더더욱 믿음을 가지고 사용하기가 힘든 것입니다.
그렇다고 하더라도 저는 제가 직접 테스트한 결과를 믿습니다. 즉, gRPC가 Feign보다 성능이 훨씬 좋다는 것을 믿습니다. 그리고 제일 중요한 건 이런 성능을 내기 위해서 Response를 최적화 시켜야 한다는 것입니다. 그래야만 압도적인 성능과 안정성을 보여줄 것입니다. 만약 구글처럼 상상하기도 힘든 어마어마한 트래픽을 항상 받아내야 한다면 어떤 기술을 선택할지는 고민할 필요도 없을 것 같습니다.
그러니 항상 주의합시다. 정말 큰 문자열 데이터를 이동시킬 예정이라면 그냥 Feign을 써도 됩니다. 기술 선택은 본인의 판단이고 그에 따라 어떤 성능이 나올지는 이렇게 테스트를 직접 해보시면 확신을 가질 수 있을 것입니다.
지금까지 gRPC 시리즈를 읽어주신 모든 분들께 감사드립니다. 많은 도움이 되었으면 좋겠습니다.
다들 즐거운 개발 합시다 :)