JavaRush /Java Blog /Random-KO /Java 마이크로서비스 가이드. 1부: 마이크로서비스 기본 사항 및 아키텍처

Java 마이크로서비스 가이드. 1부: 마이크로서비스 기본 사항 및 아키텍처

Random-KO 그룹에 게시되었습니다
이 가이드에서는 Java 마이크로서비스가 무엇인지, 이를 설계하고 생성하는 방법을 알아봅니다. 또한 Java 마이크로서비스 라이브러리와 마이크로서비스 사용 가능성에 대한 질문도 다룹니다. Java 마이크로서비스 번역 및 적용 : 실용 가이드 .

Java 마이크로서비스: 기본

마이크로서비스를 이해하려면 먼저 마이크로서비스가 아닌 것을 정의해야 합니다. "모놀리스"가 아닌가요? Java 모놀리스는 무엇이며 장점이나 단점은 무엇입니까? Java 마이크로서비스 가이드.  1부: 마이크로서비스 기본 및 아키텍처 - 1

Java 모놀리스란 무엇입니까?

당신이 은행이나 핀테크 스타트업에서 일하고 있다고 상상해 보세요. 사용자에게 새 은행 계좌를 개설하는 데 사용할 수 있는 모바일 앱을 제공합니다. Java 코드에서는 컨트롤러 클래스가 존재하게 됩니다. 단순화하면 다음과 같습니다.
@Controller
class BankController {

    @PostMapping("/users/register")
    public void register(RegistrationForm form) {
        validate(form);
        riskCheck(form);
        openBankAccount(form);
        // etc..
    }
}
다음을 수행하려면 컨트롤러가 필요합니다.
  1. 등록 양식을 확인했습니다.
  2. 이용자 주소의 위험성을 확인하여 은행계좌 제공 여부를 결정합니다.
  3. 은행 계좌를 개설했습니다.
클래스는 BankController배포를 위해 나머지 소스와 함께bank.jar 또는bank.war 파일로 패키징됩니다. 이는 은행을 운영하는 데 필요한 모든 코드가 포함된 오래된 단일체입니다. 대략적으로 .jar(또는 .war) 파일의 초기 크기는 1MB에서 100MB 사이입니다. 이제 서버에서 .jar 파일을 간단히 실행할 수 있습니다. 이것이 Java 애플리케이션을 배포하기 위해 수행해야 할 전부입니다. Java 마이크로서비스 가이드.  1부: 마이크로서비스 기본 및 아키텍처 - 2그림, 왼쪽 상단 직사각형: 모노(리딕) 은행 java -jarbank.jar(앱 서버에 cp .war/.ear) 배포. 오른쪽 직사각형: 브라우저를 엽니다.

Java 모놀리스의 문제점은 무엇입니까?

Java 모놀리스에는 본질적으로 잘못된 것이 없습니다. 그러나 경험에 따르면 프로젝트에서 다음과 같은 경우가 발생합니다.
  • 많은 프로그래머/팀/컨설턴트가 일하고 있습니다.
  • ...아주 모호한 요구 사항으로 고객의 압력을 받고 있는 동일한 단일체에 대해...
  • 몇년 안에...
... 그러면 이 경우 작은bank.jar 파일은 혼자서도 엄청난 기가바이트의 코드로 변합니다. 이는 배포는커녕 접근조차 하기 힘들 정도입니다.

Java 모놀리스의 크기를 줄이는 방법은 무엇입니까?

자연스러운 질문이 생깁니다. 단일체를 더 작게 만드는 방법은 무엇입니까? 현재 귀하의bank.jar은 하나의 JVM, 하나의 서버에서 하나의 프로세스로 실행되고 있습니다. 그 이상도 이하도 아닌. 그리고 지금 당장 다음과 같은 논리적인 생각이 떠오를 수도 있습니다. “하지만 위험 검증 서비스는 우리 회사의 다른 부서에서도 사용할 수 있습니다! 내 모놀리식 뱅킹 애플리케이션과 직접적인 관련이 없습니다! 아마도 모놀리스에서 잘라내어 별도의 제품으로 배포해야 할까요? 즉, 기술적으로 말하면 별도의 Java 프로세스로 실행하는 것입니다.”

Java 마이크로서비스란 무엇입니까?

실제로 이 문구는 이제 메소드 호출이 riskCheck()BankController에서 이루어지지 않음을 의미합니다. 모든 보조 클래스가 포함된 이 메소드 또는 Bean 컴포넌트는 자체 Maven 또는 Gradle 프로젝트로 이동됩니다. 또한 뱅킹 모놀리스와 독립적으로 버전 제어하에 배포 및 배치됩니다. 그러나 이 전체 추출 프로세스는 마이크로서비스의 정의가 해석될 수 있으므로 새로운 RiskCheck 모듈 자체를 마이크로서비스로 전환하지 않습니다. 이로 인해 팀과 회사 내에서 빈번한 논의가 이루어집니다.
  • 프로젝트 마이크로에는 5-7개의 클래스가 있나요?
  • 100개 또는 1000개의 클래스... 아직도 마이크로인가요?
  • 마이크로서비스는 일반적으로 클래스 수와 관련이 있나요?
이론적인 추론을 뒤로하고 대신 실용적인 고려 사항을 고수하여 다음을 수행해 봅시다.
  1. 크기나 도메인 경계에 관계없이 별도로 배포된 모든 서비스를 마이크로서비스라고 부르겠습니다.
  2. 서비스 간 통신을 준비하는 방법에 대해 생각해 봅시다. 마이크로서비스에는 서로 통신할 수 있는 방법이 필요합니다.
요약하자면, 이전에는 은행 운영을 위한 견고한 단일체인 하나의 JVM 프로세스가 있었습니다. 이제 뱅킹 모놀리스 JVM 프로세스와 자체 JVM 프로세스 내에서 실행되는 별도의 RiskCheck 마이크로서비스가 있습니다. 이제 위험을 확인하려면 모놀리스에서 이 마이크로서비스를 호출해야 합니다. 어떻게 해야 하나요?

Java 마이크로서비스 간 통신을 설정하는 방법은 무엇입니까?

일반적으로 동기식 통신과 비동기식 통신이라는 두 가지 옵션이 있습니다.

동기 통신: (HTTP)/REST

일반적으로 마이크로서비스 간의 동기화된 통신은 XML 또는 JSON을 반환하는 HTTP 및 REST 유사 서비스를 통해 발생합니다. 물론 다른 옵션도 있을 수 있습니다. 최소한 Google 프로토콜 버퍼를 사용하세요 . 즉각적인 응답이 필요한 경우 REST 통신을 사용하는 것이 좋습니다. 우리의 예에서는 계좌를 개설하기 전에 위험 확인이 필요하기 때문에 이것이 바로 수행되어야 하는 작업입니다. 위험 점검이 없으면 계정이 없습니다. 아래의 " 동기식 Java REST 호출에 가장 적합한 라이브러리 " 섹션에서 도구에 대해 논의하겠습니다 .

메시징 - 비동기 통신

비동기식 마이크로서비스 통신은 일반적으로 JMS 구현과 메시지를 교환하거나 AMQP 와 같은 프로토콜을 사용하여 수행됩니다 . 여기에 "보통"이라고 쓴 이유는 이메일/SMTP 통합 수를 과소평가할 수 없다고 가정해 보겠습니다. 즉각적인 응답이 필요하지 않을 때 사용하세요. 예를 들어, 사용자가 "지금 구매" 버튼을 클릭하면 귀하는 송장을 생성하려고 합니다. 이 프로세스는 사용자의 구매 요청-응답 주기 내에서 발생해서는 안 됩니다. 아래에서는 비동기식 Java 메시징 에 가장 적합한 도구에 대해 설명합니다 .

예: Java의 REST API 호출

동기식 마이크로서비스 통신을 선택한다고 가정해 보겠습니다. 이 경우, 낮은 수준의 Java 코드(위에 제시된 코드)는 다음과 같습니다. (여기서 낮은 수준이란 마이크로서비스 통신의 경우 일반적으로 실제 HTTP 호출에서 사용자를 추상화하는 클라이언트 라이브러리가 생성된다는 사실을 의미합니다.)
@Controller
class BankController {

    @Autowired
    private HttpClient httpClient;

    @PostMapping("/users/register")
    public void register(RegistrationForm form) {
        validate(form);
        httpClient.send(riskRequest, responseHandler());
        setupAccount(form);
        // etc..
    }
}
코드를 기반으로 이제 두 개의 Java(마이크로) 서비스인 Bank와 RiskCheck를 배포해야 한다는 것이 분명해졌습니다. 결과적으로 두 개의 JVM 프로세스가 실행됩니다. Java 마이크로서비스 가이드.  1부: 마이크로서비스 기본 및 아키텍처 - 3이것이 Java 마이크로서비스 프로젝트를 개발하는 데 필요한 전부입니다. 하나의 모놀리식 파일 대신 더 작은 청크(.jar 또는 .war 파일)를 빌드하고 배포하기만 하면 됩니다. 질문에 대한 대답은 여전히 ​​불분명합니다. 어떻게 모놀리스를 마이크로서비스로 잘라야 할까요? 이 조각들은 얼마나 작아야 하며, 올바른 크기를 결정하는 방법은 무엇입니까? 점검 해보자.

Java 마이크로서비스 아키텍처

실제로 기업은 다양한 방식으로 마이크로서비스 프로젝트를 개발합니다. 접근 방식은 기존 모놀리스를 마이크로서비스 프로젝트로 변환하려는지 아니면 프로젝트를 처음부터 시작하려는지에 따라 달라집니다.

모놀리스에서 마이크로서비스까지

가장 논리적인 아이디어 중 하나는 기존 모놀리스에서 마이크로서비스를 추출하는 것입니다. 여기서 접두사 "마이크로"가 실제로 추출된 서비스가 매우 작다는 의미는 아니며 반드시 그런 것은 아닙니다. 이론적 배경을 살펴보자.

아이디어: 모놀리스를 마이크로서비스로 나누기

마이크로서비스 접근 방식은 레거시 프로젝트에 적용될 수 있습니다. 그 이유는 다음과 같습니다.
  1. 대부분의 경우 이러한 프로젝트는 유지/변경/확장하기 어렵습니다.
  2. 개발자부터 경영진까지 모두가 단순화를 원합니다.
  3. (상대적으로) 명확한 도메인 경계가 있습니다. 이는 소프트웨어가 수행해야 하는 작업을 정확히 알고 있음을 의미합니다.
예제로 돌아가면 이는 Java 뱅킹 모놀리스를 보고 이를 도메인 경계를 넘어 세분화할 수 있음을 의미합니다.
  • 따라서 사용자 데이터(예: 이름, 주소, 전화번호) 처리를 별도의 마이크로서비스인 "계정 관리"로 분리하는 것이 합리적입니다.
  • 또는 앞서 언급한 "Risk Checker Module"은 사용자의 위험 수준을 확인하고 다른 많은 프로젝트나 심지어 회사의 부서에서도 사용할 수 있습니다.
  • 또는 PDF 형식이나 우편으로 송장을 보내는 송장 발행 모듈입니다.

아이디어 구현: 다른 사람이 하도록 놔두기

위에 설명된 접근 방식은 종이 및 UML 형식의 다이어그램에서 훌륭하게 보입니다. 그러나 모든 것이 그렇게 간단하지는 않습니다. 이를 실제로 구현하려면 진지한 기술적 준비가 필요합니다. 단일체에서 추출하는 것이 무엇인지에 대한 이해와 추출 프로세스 자체 사이의 격차는 엄청납니다. 대부분의 엔터프라이즈 프로젝트는 개발자가 7년 된 Hibernate 버전을 최신 버전으로 업그레이드하는 것을 두려워하는 단계에 도달합니다. 라이브러리도 함께 업데이트되지만 실제로 무언가가 손상될 위험이 있습니다. 그렇다면 이제 동일한 개발자가 데이터베이스 트랜잭션 경계가 불분명한 고대 레거시 코드를 파헤쳐 잘 정의된 마이크로서비스를 추출해야 합니까? 대개 이 문제는 매우 복잡하며 화이트보드나 건축 회의에서 "해결"할 수 없습니다. Java 마이크로서비스 가이드.  1부: 마이크로서비스 기본 및 아키텍처 - 4Twitter 개발자 @simonbrown의 말을 인용하자면: 이 말을 계속해서 반복하겠습니다... 사람들이 모놀리스를 올바르게 구축할 수 없다면 마이크로서비스는 도움이 되지 않습니다. 사이먼 브라운

마이크로서비스 아키텍처를 기반으로 처음부터 프로젝트 시작

새 Java 프로젝트의 경우 이전 부분에서 번호가 매겨진 세 가지 항목이 약간 다르게 보입니다.
  1. 깨끗한 상태에서 시작하므로 유지 관리할 "수하물"이 없습니다.
  2. 개발자들은 앞으로도 일을 단순하게 유지하고 싶어합니다.
  3. 문제: 도메인 경계에 대한 그림이 훨씬 모호합니다. 소프트웨어가 실제로 무엇을 해야 하는지 모릅니다(힌트: 민첩함 ;))
이로 인해 기업은 Java 마이크로서비스를 사용하여 새로운 프로젝트를 시도하고 있습니다.

기술적인 마이크로서비스 아키텍처

첫 번째 요점은 개발자에게 가장 명백한 것처럼 보이지만 이를 강력하게 반대하는 사람들도 있습니다. Hadi Hariri는 IntelliJ의 "Extract Microservice" 리팩토링을 권장합니다. 다음 예제는 매우 단순화되어 있지만 실제 프로젝트에서 관찰된 구현은 불행하게도 그와 크게 다르지 않습니다. 마이크로서비스 이전
@Service
class UserService {

    public void register(User user) {
        String email = user.getEmail();
        String username =  email.substring(0, email.indexOf("@"));
        // ...
    }
}
하위 문자열 Java 마이크로서비스 사용
@Service
class UserService {

    @Autowired
    private HttpClient client;

    public void register(User user) {
        String email = user.getEmail();
        //теперь вызываем substring microservice via http
        String username =  httpClient.send(substringRequest(email), responseHandler());
        // ...
    }
}
따라서 명확한 이유 없이 Java 메소드 호출을 HTTP 호출로 래핑하는 것입니다. 그러나 그 이유 중 하나는 경험이 부족하고 Java 마이크로서비스 접근 방식을 강요하기 때문입니다. 권장사항: 이렇게 하지 마세요.

워크플로 중심의 마이크로서비스 아키텍처

다음 일반적인 접근 방식은 Java 마이크로서비스를 워크플로 기반 모듈로 나누는 것입니다. 실제 사례: 독일에서는 (공공) 의사에게 가면 의료 CRM 시스템에 귀하의 방문을 기록해야 합니다. 보험금을 받기 위해 그는 귀하의 치료(및 다른 환자의 치료)에 대한 데이터를 XML을 통해 중개자에게 보냅니다. 브로커는 이 XML 파일을 보고 (단순화):
  1. 올바른 XML 파일이 수신되었는지 확인합니다.
  2. 절차의 타당성을 확인할 것입니다. 예를 들어, 산부인과 의사로부터 하루에 세 번의 치아 세척 절차를 받은 한 살짜리 아이는 다소 의심스러워 보입니다.
  3. XML을 다른 관료적 데이터와 결합합니다.
  4. 지불을 시작하기 위해 XML 파일을 보험 회사에 전달합니다.
  5. 그리고 그 결과를 의사에게 보내며 "성공" 또는 "이해가 되는 즉시 이 녹음을 다시 보내주십시오"라는 메시지를 전달합니다.
메모. 이 예에서 마이크로서비스 간의 통신은 아무런 역할을 하지 않지만 의사가 즉각적인 피드백을 받지 못하기 때문에 메시지 브로커(예: RabbitMQ)에 의해 비동기적으로 수행될 수 있습니다. Java 마이크로서비스 가이드.  1부: 마이크로서비스 기본 및 아키텍처 - 5다시 말하지만, 이는 서류상으로는 훌륭해 보이지만 자연스러운 질문이 발생합니다.
  • 하나의 XML 파일을 처리하려면 6개의 애플리케이션을 배포해야 합니까?
  • 이러한 마이크로서비스는 정말로 서로 독립적인가요? 서로 독립적으로 배포할 수 있나요? 버전과 API 체계가 다르나요?
  • 검증 마이크로서비스가 작동하지 않는 경우 신뢰성 마이크로서비스는 무엇을 합니까? 시스템이 아직 작동하고 있나요?
  • 이러한 마이크로서비스는 동일한 데이터베이스를 공유합니까(확실히 DB 테이블에 일부 공통 데이터가 필요함), 아니면 각각 고유한 데이터를 갖고 있습니까?
  • … 그리고 훨씬 더.
흥미롭게도 위의 다이어그램은 이제 각 서비스가 정확하고 잘 정의된 고유한 목적을 갖기 때문에 더 단순해 보입니다. 예전에는 무서운 단일체처럼 보였습니다. 이러한 Java 마이크로서비스 가이드.  1부: 마이크로서비스 기본 및 아키텍처 - 6다이어그램의 단순성에 대해 논쟁을 벌일 수 있지만 이제는 이러한 추가적인 운영 문제를 해결해야 합니다.
  • 하나의 애플리케이션만 배포하는 것이 아니라 최소한 6개를 배포해야 합니다.
  • 마이크로서비스 아키텍처를 얼마나 확장하려는지에 따라 여러 데이터베이스를 배포해야 할 수도 있습니다.
  • 각 시스템이 온라인 상태이고 제대로 작동하는지 확인해야 합니다.
  • 마이크로서비스 간의 호출이 실제로 복원력이 있는지 확인해야 합니다(Java 마이크로서비스를 복원력 있게 만드는 방법 참조).
  • 그리고 이 설정이 의미하는 모든 것 - 로컬 개발 설정부터 통합 테스트까지.
따라서 권장 사항은 다음과 같습니다.
  • Netflix가 아닌 경우(아마도 Netflix가 아닐 가능성이 높습니다)...
  • 개발 환경을 여는 매우 강력한 작업 기술이 없으면 5초 안에 쉽게 복원되는 프로덕션 데이터베이스를 버리는 혼란 원숭이가 발생합니다.
  • 또는 @monzo처럼 느껴질 수 있다는 이유만으로 1,500개의 마이크로서비스를 기꺼이 시험해 볼 의향이 있습니다.
→ 이러지 마세요. 이제 덜 과장된 표현이 되었습니다. 도메인 경계를 넘어 마이크로서비스를 모델링하려는 시도는 상당히 합리적으로 보입니다. 그러나 이는 하나의 워크플로를 작은 개별 부분(XML 수신, XML 유효성 검사, XML 전달)으로 분할해야 한다는 의미는 아닙니다. 따라서 Java 마이크로서비스로 새 프로젝트를 시작할 때 도메인 경계가 여전히 매우 모호할 때마다 마이크로서비스의 크기를 낮은 수준으로 유지하도록 노력하십시오. 나중에 언제든지 더 많은 모듈을 추가할 수 있습니다. 그리고 새로운 인프라를 지원하기 위해 팀/회사/부서에 고급 DevOps가 있는지 확인하세요.

다중 언어 또는 팀 중심 마이크로서비스 아키텍처

마이크로서비스 개발에 대한 거의 자유주의적인 세 번째 접근 방식이 있습니다. 팀이나 개인이 원하는 수의 언어나 마이크로서비스를 사용하여 사용자 스토리를 구현할 수 있도록 허용하는 것입니다(마케터들은 이 접근 방식을 "다언어 프로그래밍"이라고 부릅니다). 따라서 위에 설명된 XML 유효성 검사 서비스는 Java로 작성될 수 있는 동시에 유효성 검사 마이크로서비스는 Haskell로 작성될 수 있습니다(수학적으로 탄탄하게 만들기 위해). 보험 전달 마이크로서비스의 경우 Erlang을 사용할 수 있습니다(실제로 확장이 필요하기 때문입니다;). 개발자의 관점에서 재미있어 보일 수 있는 것(격리된 환경에서 완벽한 언어로 완벽한 시스템을 개발하는 것)은 사실 조직이 원하는 것이 아닙니다: 균질화와 표준화. 이는 귀하가 미래에 보다 친환경적인 환경으로 나아갈 때 다른 개발자가 귀하의 Haskell 마이크로서비스를 계속 지원할 수 있도록 상대적으로 표준화된 언어, 라이브러리 및 도구 세트를 의미합니다. Java 마이크로서비스 가이드.  1부: 마이크로서비스 기본 및 아키텍처 - 8역사를 보면 표준화는 일반적으로 너무 깊이 뿌리박혀 있습니다. 예를 들어, Fortune 500대 기업의 개발자들은 Spring이 "회사의 기술 로드맵의 일부가 아니기" 때문에 Spring을 사용하는 것이 허용되지 않는 경우도 있었습니다. 그러나 다중 언어 접근 방식으로의 완전한 전환은 거의 동일하며 동전의 반대편입니다. 권장 사항: 다중 언어 프로그래밍을 사용하려는 경우 동일한 프로그래밍 언어 생태계 내에서 다양성을 줄이십시오. 따라서 Java와 Haskell을 사용하는 것보다 Kotlin과 Java를 함께 사용하는 것이 더 좋습니다(두 언어 모두 JVM을 기반으로 하며 서로 100% 호환됩니다). 다음 부분 에서는 Java 마이크로서비스 배포 및 테스트에 대해 알아봅니다.
코멘트
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION