문제 상황
최근 회사의 마이크로서비스 프레임워크를 사용하여 백엔드를 개발하면서 파이썬으로 작성된 서비스 인터페이스를 호출해야 했습니다. 여기서는 다른 언어 간의 인터페이스 호출을 위해 GRPC를 사용했습니다. 파이썬 서비스가 실행 중임을 알고 있었지만, 테스트 과정에서 백엔드에서 오류가 발생했습니다. 오류 메시지는 다음과 같습니다:
Caused by: io.grpc.StatusRuntimeException: UNAVAILABLE: io exception
Channel Pipeline: [SslHandler#0, ProtocolNegotiators$ClientTlsHandler#0, WriteBufferingAndExceptionHandler#0, DefaultChannelPipeline$TailContext#0]
at io.grpc.stub.ClientCalls.toStatusRuntimeException(ClientCalls.java:244)
at io.grpc.stub.ClientCalls.getUnchecked(ClientCalls.java:225)
at io.grpc.stub.ClientCalls.blockingUnaryCall(ClientCalls.java:142)
at AlarmCategory.AlarmCategoryGrpc$AlarmCategoryBlockingStub.getAlarmCategory(AlarmCategoryGrpc.java:169)
... 97 common frames omitted
Caused by: io.grpc.netty.shaded.io.netty.handler.ssl.NotSslRecordException: not an SSL/TLS record: 000018040000000000000400400000000500400000000600002000fe0300000001000004080000000000003f00010000080600000000000000000000000000
at io.grpc.netty.shaded.io.netty.handler.ssl.SslHandler.decodeJdkCompatible(SslHandler.java:1214)
at io.grpc.netty.shaded.io.netty.handler.ssl.SslHandler.decode(SslHandler.java:1282)
at io.grpc.netty.shaded.io.netty.handler.codec.ByteToMessageDecoder.decodeRemovalReentryProtection(ByteToMessageDecoder.java:498)
at io.grpc.netty.shaded.io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:437)
... 1 common frames omitted
문제 환경
| 소프트웨어 | 버전 |
|---|---|
| JDK | 8 |
| grpc | 1.29.0 |
| spring-boot | 2.1.8.RELEASE |
| grpc-client-spring-boot-starter | 2.7.0.RELEASE |
문제 원인
관련 문서를 확인한 결과, 동료의 파이썬 서비스는 GRPC를 PLAINTEXT 모드로 사용하고 있었지만, 제 클라이언트는 기본적으로 TLS 모드를 사용하고 있었습니다. 양쪽의 모드가 다르기 때문에 제 요청이 서버에서 파싱되지 않아 이 문제가 발생했습니다.
해결 방안
여기에는 두 가지 해결책이 있습니다:
1. 간단하고 빠른 방법
GRPC 사용을 간소화하기 위해 grpc-client-spring-boot-starter를 사용하고 있었기 때문에, 다음과 같이 설정 파일에 구성을 추가하기만 하면 됩니다:
grpc.client._서버이름_.negotiationType=PLAINTEXT
여기서 _서버이름은 개발자가 정의하는 값입니다. 이 방법을 사용하면 재시작 후 정상적으로 통신할 수 있었습니다!
2. 보안적이지만 조금 복잡한 방법
서버 측에서 TLS 모드를 사용하는 것입니다. 만약 서버 개발에 grpc-client-spring-boot-starter를 사용했다면, 해당하는 crt와 key 파일을 생성한 후 다음과 같이 구성을 추가할 수 있습니다(경로를 자신의 파일 경로로 수정해야 함). 그런 다음 재시작하면 됩니다.
grpc.server.security.enabled=true
grpc.server.security.certificateChain=file:certificates/server.crt
grpc.server.security.privateKey=file:certificates/server.key
결과
저는 첫 번째 방법을 사용하여 문제를 간단하고 빠르게 해결했습니다. 서버는 다른 언어로 작성되었기 때문에 수정을 위한 소통에 많은 시간과 노력이 필요했습니다. 현재는 테스트 단계이므로, 애플리케이션이 실행되도록 한 후 나중에 보완할 수 있습니다.
요약
다른 언어 간의 통신은 이미 성숙된 산업 표준 구성 요소를 사용하여 개발할 수 있습니다. 이를 통해 반복적인 작업을 줄이고 빠르게 개발을 반복하여 개발 주기를 단축할 수 있습니다.