RPC 는 기술 문서를 읽다보면, 현업에서 흔히 접하게 되는 용어지만 은근히 개념을 이해하기는 쉽지 않다.

 

RPC 의 개념을 인터넷에서 (혹은 최근에 핫한 ChatGPT 에서) 찾아보자면 다음과 같이 나온다.

 

Remote Procedure Call 은 원격 컴퓨터나 프로세스에 존재하는 함수를 호출하는데 사용하는 프로토콜로, 원격지의 프로세스를 동일 프로세스의 함수를 호출하는 것 처럼 사용하는 것을 말한다.

 

하지만 위의 개념을 읽고 한번에 와닿는 사람들은 많지 않을 것이라고 생각한다. 실제로 현업의 엔지니어들도 애매모호하게 해석하게 되는 개념 중 하나이다.

 

그도 그런게 RPC 는 특정 프로토콜 이라기 보다는 전통적인 개념의 API 호출 규약이기 때문이다.

예시를 보면 이해가 보다 쉬울 것이다.

 

POST /sayHello HTTP/1.1
HOST: api.example.com
Content-Type: application/json

{"name": "Tom"}

 

위의 예시는 HTTP 위에서 구현된 RPC 방식의 예시이다. 위의 HTTP 스키마는 HTTP Client (웹 브라우저) 를 통해 HTTP Server (웹 서버) 에 전달될 것이고, WAS 는 위의 프로토콜을 처리하기 위한 로직을 구현하게 된다.

 

여기서 보통은 "그냥 HTTP 프로토콜 아닌가?" 라는 생각이 들 것이고, 그 생각은 맞다.

하지만 일반적인 REST API 처럼 보인다면, 엄밀히 따지자면 그렇지 않다. RPC 와 REST 의 차이점은 다음과 같다.

 

  REST RPC
Protocol HTTP  프로토콜에 무관 (TCP, UDP, HTTP, WebSocket, ...)
Scheme Resource 기반의 API 인터페이스
(예) 강아지 목록을 반환하는 API 를 GET /dogs 로 설계
Action 기반의 API 인터페이스
(예) 강아지 목록을 반환하는 API 를 POST /listDogs 로 설계
Design RESTful API 는 Stateless 를 전제 제약이나 규약이 없음

 

즉, RPC 는 서버와 클라이언트가 통신하기 위한 API 의 통신 패러타임 중 하나이고, REST API 와 비교될 수 있는 차원의 개념이라고 할 수 있다.

RPC 는 기본적으로 정해진 구조를 갖고있지는 않지만, 기본적인 Terminology 를 몇가지 갖고있다.

 

  • IDL (Interface Definition Language) : 서로 다른 언어로 작성된 서비스들 사이에서 공통된 인터페이스를 정의하기 위한 중간 언어
  • Stub : 서버와 클라이언트는 서로 다른 주소 공간을 사용하므로 함수 호출에 사용된 매개변수를 변화해줘야하며, 그 역할을 담당한다
    • client stub - 함수 호출에 사용된 파라미터의 변환(Marshalling) 및 함수 실행 후 서버에서 전달된 결과의 반환
    • server stub - 클라이언트가 전달한 매개변수의 역변환(Unmarshalling) 및 함수 실행 결과 변환을 담당

그리고 위의 개념에 따라서 다음과 같은 순서로 통신이 이뤄지게 된다.

 

  • IDL 을 사용하여 호출 규약을 정의한다. IDL 파일을 rpcgen 으로 컴파일하면 stub code 가 자동으로 생성
  • Stub Code 에 명시된 함수는 원시 코드의 형태로 상세 기능은 server 에서 구현된다. Stub 코드는 서버/클라이언트에서 각각 빌드된다
  • 클라이언트에서 stub 에 정의된 함수를 사용 시 client stub 은 RPC runtime 을 통해 함수를 호출하고 서버는 수신된 Procedure 호출에 대해 처리 후 결과를 반환
  • 클라이언트는 서버로부터 응답을 받고 함수를 로컬에 있는 것처럼 사용할 수 있다

 

이해가 잘 되지 않는다면 쉽게 말해서, RPC 는 이를 해석하고 처리하기 위한 Client / Server 가 존재하며, 그 사이에 규약(IDL) 을 정의하고 IDL 을 클라이언트측 / 서버측 Stub 을 통해 해석하고 비즈니스 로직을 구현한다고 보면 된다. 

 

RPC 는 RESTful API 에 비해 복잡하며, 프로젝트에 따라 Learning Curve 가 있기 때문에,

근래에 RPC 의 개념은 전통적인 방식으로는 잘 사용되지 않으며 gRPC (Google RPC) 와 같은 발전된 개념으로 사용되어진다.

 

RESTful API 가 갖는 개념적 제한에서 벗어나서 보다 자유로운 설계를 위해 사용되는 개념이고, gRPC 와 같은 Modern RPC 는 Micro Service Architecture 등에서 Internal Bidirectional Communication 을 위해 사용되어진다.

 

 

위의 예시는 gRPC 를 이용해서 Micro Service Architecture 를 구현하는 방식을 보여준다. gRPC 의 경우 Protobuf 를 스키마로 사용하기 때문에, 통신을 위한 서버-클라이언트 간에 .proto 파일에 대한 별도 관리가 필요하다.

 

Protobuf 는 구글이 만든 언어 및 플랫폼 중립적인 Data Format 으로, 일반적인 JSON Serialize / Deserialize 대비 효율적인 통신이 큰 장점이다. 관련해서는 블로그의 다음 글을 참고해볼 수 있다.

 

현업에서 RPC 는 주로, 웹 서비스 보다는 게임이나 IoT, Device 등 Non HTTP 기반 산업에서 보다 많이 보이는 형태이지만 Micro Service Architecture 가 시장에 자리잡기 시작하면서 Modern RPC 형태로 많이 보이고 있다.

 

기술이 어떻게 진화할지 모르겠지만 여러 기술적인 문제를 해결하기 위한 시도 중 하나로 알아둘 법한 패러다임이라고 생각되어진다.

 

 

 

분산 환경의 처리는 일반적인 환경의 구성과 많이 다르며 분산시스템의 특이성에 대한 개념들이 있다.

특히나 자주 듣게 되는 단어 중 하나는 결과적 일관성(Eventual Consistency) 라는 개념으로, 분산 시스템(Distributed System) 을 운영하게 되면 흔치않게 접하게 된다.

이는 개념과 관련된 이론이 그만큼 중요한 내용임을 반증한다.

 

먼저 예로 들은 Eventual Consistency 에 대해 설명하자면 이는 분산 컴퓨팅(Distributed Computing) 에서 고가용성(High Availability)을 보장하기 위한 방법의 하나로

"주어진 데이터에 대한 변경이 없다면 해당 Element 에 대한 모든 Access 는 가장 최근에 변경된 내용을 가리킨다" 는 정의를 말한다.

분산 시스템에서 데이터를 조회할 때 모든 시스템이 동일한 데이터를 가질 수 있다고 보장할 수는 없으며 결과적 일관성은 어느 시점에는 데이터가 다를 수 있지만, 결국에는 모든 시스템이 최신의 데이터를 가질 수 있도록 보장된다는 내용이다.

 

분산 환경에서는 데이터에 대해 단지 "시간" 뿐 아니라 "공간(다른 시스템)" 도 고려의 대상이 된다.

 

이는 BASE 원칙의 일종으로 분류되기도 한다. BASE 원칙이란 다음의 원칙들이 포함된다.

- Basically Available : 일반적인 Read / Write 에 대한 동작이 "가능한만큼" 지원된다.

(여기서 가능한만큼 이라 함은, 동작이 가능하나 Consistency 에 대한 보장이 되지않는다는 점이다.)

- Soft state : Consistency 가 보장되지 않기 때문에 상태(State) 에 대해 Solid 하게 정의하지 못하다.

- Eventually consistent : 위에 언급된 Eventual Consistency 개념에 따라 충분한 시간이 흐르면 모든 시스템 환경 내에서 데이터는 최신의 데이터가 보장된다.

 

BASE 원칙은 전통의 트랜잭션 시스템을 위한 ACID 원칙에 반대된다. 이는 분산 환경에서 나타나는 특징이기 때문이다.

이러한 특징에 대해 CAP Theorem 은 다음 3가지 조건을 모두 만족하는 분산 시스템을 만드는 것이 불가능함을 정의한다.

 

- 일관성(Consistency) : 모든 시스템의 데이터는 어떤 순간에 항상 같은 데이터를 갖는다.

- 가용성(Availability) : 분산 시스템에 대한 모든 요청은 내용 혹은 성공/실패에 상관없이 응답을 반환할 수 있다.

- 내구성(Partition Tolerance) : 네트워크 장애 등 여러 상황에서도 시스템은 동작할 수 있다.

 

분산환경 특징 상 3가지 성질을 모두 만족할 수는 없고, 일반적으로 다음과 같이 선택된다.

 

- CP (Consistency & Partition Tolerance) : 어떤 상황에서도 안정적으로 시스템은 운영되지만 Consistency 가 보장되지 않는다면 Error 를 반환한다. (어떤 경우에도 데이터가 달라져서는 안된다.)

이는 매 순간 Read / Write 에 따른 정합성이 일치할 필요가 있는 경우 적합한 형태이다.

 

- AP (Availability & Partition Tolerance) : 어떤 상황에서도 안정적으로 시스템은 운영된다. 또한 데이터와 상관없이 안정적인 응답을 받을 수 있다. 다만 데이터의 정합성에 대한 보장은 불가능하다. (특정 시점에 Write 동기화 여부에 따라 데이터가 달라질 수 있다.)

이는 결과적으로는 일관성이 보장된다는 Eventual Consistency 를 보장할 수 있는 시스템에 알맞는 형태이다.

 

 

서버시스템 및 분산시스템에 있어서 핵심적인 개념이므로 잘 정리해두고 아키텍처를 고려할 때 항상 생각해두자

다음은 AWS 공식 홈페이지의 Well architectured 를 위한 5가지 성질을 정의한 내용이다.

https://aws.amazon.com/ko/architecture/well-architected/

 

AWS Well-Architected – 안전하고 효율적이며 클라우드가 지원되는 애플리케이션을 구축

Well-Architected 프레임워크는 애플리케이션에 사용할 보안, 성능, 복원력 및 효율성이 뛰어난 인프라를 구축하는 클라우드 아키텍트를 돕기 위해 개발되었습니다. 5가지 기반인 운영 우수성, 보안, 안정성, 성능 효율성 및 비용 최적화를 기반으로 하는 이 프레임워크는 고객 및 파트너가 아키텍처를 평가하고, 지속적으로 확장되는 설계를 구현하기 위한 일관적인 접근 방식을 제공합니다. 이제 AWS Well-Architected Tool을 사용할 수 있습

aws.amazon.com

1. 운영 우수성(Operational Excellence)

비즈니스 가치를 제공하고 시스템을 실행 및 모니터링하는 데 중점을 둔다.

변경관리 및 자동화, 이벤트 응답, 일상적인 운영의 성공적인 관리 와 같은 항목들이 고려되어야 한다.

Operational Excellence 를 위한 다음과 같은 원칙들이 있다.

 

 - Perform operations as code : Cloud 환경에서도 일반 어플리케이션 코드를 만들 때처럼 작업의 프로시저와 이벤트에 대한 동작을 구현해야 한다. 휴먼 에러를 배제하고 이벤트 중심으로 구동되게끔 설계해야 한다.

 

 - Annotate documentation : 매빌드 이후에 Document 를 만들도록 자동화시키는 것이 중요하다. Cloud 환경에서는 documentation 을 자동화시킬 수 있다.

 

 - Make frequent, small, reversible changes : Component 들의 주기적 업데이트를 가능하게 하고, 실패 시 Rollback 이 가능해야 한다.

 

 - Refine operations procedures frequently : 주기적으로 프로세스를 향상시킬 방법을 고안해야 한다.

 

 - Anticipate failure : 프로세스가 실패로 이어질 상황을 시뮬레이션 해보는 것이 필요하다.

 

 - Learn from all operational failures : Operation failure 에 대해 정리하고 학습해야 한다.

 

* Operational Excellence 를 위해 AWS Config 를 통해 테스트를 준비하고, Amazon CloudWatch 를 통해 모니터링하며, Amazon ES(Elastic Search Service) 를 통해 로그를 분석하는 것이 좋다.

 

2. 보안(Security)

정보 및 시스템을 보호하는 중점가치이다.

데이터 기밀성 및 무결성, 권한 관리를 통한 사용자 작업 식별 및 관리, 시스템 보호와 보안 이벤트 제어와 같은 항목들이 고려되어야 한다.

Security 요소를 위해 다음과 같은 원칙들이 있다.

 

 - Implement a strong identity foundation : 최소 권한의 원칙과 의무에 대한 권한을 AWS Resources단위로 부여한다.

 

 - Enable traceability : 모든 동작은 모니터링과 알람이 가능하게끔 해야한다. 로그 시스템을 통합시켜놓음으로써 자동화가 가능하다.

 

 - Apply security at all layers : 모든 계층에 보안 요소를 포함시킨다. (edge network, VPC, subnet, Load Balancer, instances, OS, application)

 

 - Automate security best practices : Security mechanism 을 자동화시킨다. 버전관리를 하듯 템플릿을 관리한다.

 

 - Protect data in transit and at rest : 데이터에 대해서도 Encryption, Tokenization, Access control 등을 적용한다.

 

 - Prepare for security events : 갑작스런 보안 사고에 대비해 simulation 해보고, 탐지 속도, 탐지력, 복원력 을 측정해보는 것이 좋다.

 

* Security 를 위해 IAM, CloudTrail(API Call 추적), Amazon VPC, Amazon CloudFront(CDN 데이터의 보안), 데이터 보안을 위한 RDS, S3, AWS KMS(Key management system), CloudFormation / CloudWatch(시뮬레이션 및 모니터링) 등을 이용하는 것이 좋다.

 

3. 안정성(Reliability)

비즈니스 및 고객 요구를 충족시키기 위해 장애를 예방하고 신속하게 복구할 수 있는 능력에 중점을 둔다.

기본요소, 복구계획 및 변경 처리와 같은 항목들이 고려되어야 한다.

Reliability 를 위해 고려해야할 원칙들은 다음과 같다.

 

 - Test recovery procedures : System fail 및 fail 에 대한 recovery 상황을 테스팅하고 전략을 수립할 수 있기 때문에, 시나리오에 알맞게 recover 동작을 테스트해보는 것이 필요하다.

 

 - Automatically recover from failure : Key Performance Indicator(KPI) 를 모니터링함으로써 이상상태에 대한 Threshold 값을 세팅할 수 있고 복구를 자동화할 수 있다.

 

 - Scale horizontally to increase aggregate system availability : Horizontal scaling 은 Single Failure 가 전체 시스템에 영향이 미치지않게끔 구성할 수 있게 한다. 구조를 수평적으로 작게 나누고 합치는 형태의 구조를 사용한다.

 

 - Stop guessing capacity : 온프레미스 환경의 흔한 오류 원인은 Resource 포화상태이다. 클라우드 환경에서는 Load 를 모니터링하고 System utilization 을 통해 Provisioning 을 자동화할 수 있다. (Under/Over provisioning 의 방지)

 

 - Manage change in automation : 인프라 구성의 변화는 자동화되어야 한다.

 

* 사용가능한 AWS 서비스들로 AWS IAM, AWS CloudTrail, AWS Config, AWS CloudFormation, AWS KMS 등의 서비스가 있다.

 

4. 성능 효율성(Performance Efficiency)

IT 및 컴퓨팅 리소스를 효율적으로 사용하는데 중점을 둔다.

요구사항에 적합한 리소스 유형 및 크기, 성능 모니터링 정보를 바탕으로 한 효율성 유지와 같은 항목들이 고려되어야 한다.

Performance Efficiency 를 위해 고려해야할 원칙들은 다음과 같다.

 

 - Democratize advanced technologies : 새로운 기술이 있을 때, 클라우드 환경에서는 쉽게 적용시킬 수 있다.

 

 - Go global in minutes : Multiple Region 에 몇번의 클릭만으로 배포가 가능하다. 이는 고객 입장에서도 적은 비용으로 만족감을 느낄 수 있는 서비스의 특성이 된다.

 

 - Use serverless architecture : 클라우드의 서버리스 아키텍쳐는 서버를 직접 구동하고 운용할 필요성을 크게 줄여준다. 

 

 - Experiment more often : 가상의 자동화된 환경에서 테스트는 좀 더 빠르게 이루어질 수 있다.

 

 - Mechanical sympathy : 기술적 접근 방법을 고려한다.

 

* Performance Efficiency 를 위해, Auto Scaling, Amazon EBS, Amazon RDS, Amazon Route53, ElastiCache, CloudFront 와 같은 서비스들이 활용될 수 있다.

 

5. 비용 최적화(Cost Optimization)

불필요한 비용의 발생을 방지하고 지출 내용을 파악하여 가장 적합한 수의 적절한 리소스 사용에 초점을 둔다.

지출분석을 통해 초과비용 없이 비즈니스 요구사항을 만족시키는 조정 항목들이 고려되어야 한다.

Cost Optimization 을 위해 다음 원칙들이 고려되어야 한다.

 

 - Adopt a consumption model : 필요한 만큼의 컴퓨팅 리소스에 대해서만 비용이 지출되어야 하고 비즈니스 요구에 따라 사용량이 조절되어야 한다. (예측해서 많이 잡거나 해서는 안된다.)

 

 - Measure overall efficiency : 비즈니스의 전체 workload 와 output 을 측정해야 한다.

 

 - Stop spending money on data center operations : 인프라 관리비용 자체에 돈을 더 쓰면 안된다.

 

 - Analyze and attribute expenditure : Cloud 환경에서는 시스템의 사용량을 조회하고 비용을 산정하기 쉽다. ROI 를 측정하고 Resource 를 최적화하자.

 

 - Use managed services to reduce cost of ownership : Cloud 환경을 이용하면 email 을 보낸다던지하는 운영의 비용이 감축된다.

 

* AWS Cost Explorer 를 사용해서 비용 산정량을 확인할 수 있다. AWS Budget 은 사용량에 따라 향후 사용량을 예측할 수 있게 지원한다.

또한 Resource 를 Amazon Aurora 와 같은 것을 사용하면 라이센스 비용을 절감할 수 있고, Auto Scaling 은 스케일링의 효율성을 증가시켜준다.

 

 

처음 클라우드 기반 아키텍처를 설계할 때 상당히 도움이 되었었던 내용들이다.

클라우드 기반 아키텍처 설계를 담당하게 되었다면 꼭 알아두고 복습하자.

 

 

SOA(Software Oriented Architecture) 란, 2000년대 초반부터 IT 업계 전반에 걸쳐 녹아든 IT System 의 패러다임이다.

 

고전의 Client-Server Architecture 에서 EJB 로 대표되는 n-Tier Model Architecture 로 진화한 웹 아키텍쳐는 2000년대 이후부터 비즈니스 요구사항에 발빠르게 대처하기 위한 구조로 Service-Oriented Architecture 라는 아키텍쳐로 진화한다.

 

SOA 란, 그전까지의 Application 의 Massive 한 기능들을 비즈니스적인 용도로 분류하고 기능 단위로 묶어서 하나의 표준 Interface 를 통해 각각을 "서비스" 로써 조합하는 Software Architecture 이다.

 

IT 업계의 요구사항이 많아지고 변화가 빨라짐에 따라 이에 대처하기 위해 나타난 Architecture 이고, 구성요소를 3가지로 분류한다.

 

1. Service Consumer - 서비스의 사용자. 사용자는 실제 클라이언트(End-User) 또는 다른 서비스가 될 수 있다.

2. Service Provider - 서비스 사용자에 요청에 맞는 서비스를 제공. Provider 는 다른 Service 의 Consumer 가 될 수도 있다.

3. Service Registry - 서비스의 정보를 저장한다. Provider 가 Registry 를 통해 Consumer 에게 서비스를 제공한다.

 

여기서 중요한건 Service Provider 와 Service Consumer 로, 이들은 실제 서비스의 유저 뿐 아니라 소프트웨어 아키텍처 내부의 "모듈" 도 대상이 될 수 있다. 

즉, SOA 는 비즈니스적으로 구분된 Service 들을 느슨하게 연결하며, 각 컴포넌트를 독립적으로 운용하여 조립이 가능하게끔 한다.

 

일반적으로 Service 를 위해 서비스 기능별로 모듈을 분리하고, 각 모듈이 다른 모듈과 상호작용할 수 있도록 만들어진 Architecture 를 SOA 라고 이해하면 된다.

 

여기까지 이해했으면 떠오르는 최근의 Architecture 모델이 있을 수 있다.

바로 Micro Service Architecture(MSA) 이다.

 

Micro Service Architecture 역시 각 서비스를 독립적으로 운용하며 서비스들을 조합하여 End User 에게 서비스를 제공하는 형태로 이루어진다. 그렇다면 이는 SOA 와 같은 아키텍처인가?

 

결론부터 말하자면, Micro Service Architecture 는 SOA 의 부분집합이라고 할 수 있다.

정확히는 SOA 는 패러다임이며, 그를 위한 Architecture 의 초안이고, Micro Service Architecture 는 SOA 의 패러다임을 따르되, 그 아키텍처를 따르지 않는다.

 

SOA 와 MSA 의 차이점

 

1. SOA 는 모듈의 의존성은 줄이되 모듈 내에서 공유할 수 있는건 최대한 공유하는 정책을 사용한다.

반면, MSA 는 가능한 공유하지 않고 모듈들이 독립적으로 운용될 수 있도록 아키텍처를 디자인 한다.

 

2. SOA 는 서비스의 Flow 를 유지하려하지만, MSA 는 Flow 의 구별을 요구한다.

가령, 서비스 내에서 결제를 하고자 할때, SOA 는 관련된 루틴을 수행하여 결제를 지원함으로써, 유저에게 제공해주는 "서비스" 를 1차 목적으로 한다.

반면, MSA 는 유저에게 관련된 루틴과 결제 루틴을 별도로 이용하게끔 한다. 즉 서비스 내의 독립이 아닌 독립된 서비스를 지향한다.

그렇다보니 SOA 아키텍처는 대게 어느정도 업격한 Protocol 과 Message 체계를 운용하게 되고, MSA 의 경우 별도의 체계가 없이 경량화된 프로토콜을 통해 운용되게 된다.

 

3. SOA 는 서비스들의 재사용에 중점을 두지만 MSA 는 서비스들의 독립을 추구한다.

이는 블로그 내 다른 포스팅에서 언급한 적 있는 Monolithic Architecture 와 유사한 부분으로, SOA 는 MSA 에 비해 보다 Monolithic Architecture 에 가깝다.

(참조 : https://jins-dev.tistory.com/entry/%EC%A0%84%ED%86%B5%EC%9D%98-%EC%86%8C%ED%94%84%ED%8A%B8%EC%9B%A8%EC%96%B4-%EC%95%84%ED%82%A4%ED%85%8D%EC%B2%98-%EB%AA%A8%EB%8D%B8-%EB%AA%A8%EB%86%80%EB%A6%AC%EC%8B%9DMonolithic-%EC%95%84%ED%82%A4%ED%85%8D%EC%B2%98)

 

 

아키텍처를 디자인하는 일은 늘 어려운 일이고, 실무에서의 경험을 상당히 요하는 일이다.

아키텍처의 디자인과 이해를 위해서는 최신 트렌드 뿐 아니라 과거의 모델까지도 숙지해두는 것이 필요하겠다.

 

좀 더 자세한 설명은 다음 링크를 참조해보자.

https://dzone.com/articles/microservices-vs-soa-2

https://www.bmc.com/blogs/microservices-vs-soa-whats-difference/

 

 무중단 배포란 알고있는대로, 서버를 실제로 서비스할 때 서비스적 장애와 배포에 있어서 부담감을 최소화할 수 있게끔 서비스가 중단되지 않고도 코드를 Deploy할 수 있는 기술이다


예전에는 배포 자체가 하나의 거대한 일이었고, 이를 위한 팀과 개발팀이 날을 잡고 새벽에 배포하는 일이 잦았지만, 최근에는 무중단 배포 기능을 탑재한 Deploy 자동화 툴을 이용해서 개발자들이 스스로 배포까지 담당하는 DevOps 의 역할을 하게되면서, DevOps 의 필수 기술 중 하나가 되었다.


 무중단 배포 방식에는 주로 사용되는 것들에 AWS에서 Blue-Green 무중단 배포(Blue는 기존버전, Green은 새로운버전. Router를 통해 Blue로 이동하는 트래픽을 Green으로 변경시켜준다. 원리는 동일하다.), Docker를 이용한 웹서비스 무중단 배포가 있다


IDC에서 직접 L4 스위치를 이용해서 하는 방안도 간단하지만, 이는 비용적으로 효율적이지 않아 많이 없어지는 추세이다


또한 NginX 등을 이용해서 저렴하게 무중단 배포를 하는 방식도 있다


이 방법을 사용하면 클라우드 인프라가 갖춰져있지 않아도 되고 별도의 인스턴스를 갖고 있지 않아도 가능하다

(Spring jar 2개를 여러 포트에 나눠서 배포하고 그 앞에 NginX 로 밸런싱해주면 된다.)


 무중단 배포의 원리




간단한 원리는 위와 같다. 핵심은 Reverse Proxy 가 서로 다른 인스턴스의 각기 다른 포트와 서브 도메인으로 연결하고, 지속적으로 Health Check 하면서 배포시 서브도메인을 메인 도메인으로 Switching 해주고, 배포가 끝나면 다시 메인도메인으로 Reload 해주는 것이다


이 구조에서 주의해야할 점은, 배포가 서비스에 영향을 주지 않도록 해야한다는 것이다. 예를들어 DB의 구조를 바꾸는 JPA와 같은 기술들이 사용되어 있을 경우 검토가 필요하다.


 도커 컨테이너를 이용하면 이는 매우 간단해진다

하나의 이미지에서 여러 컨테이너를 생성해서 호스트의 docker 명령어를 이용해서 손쉽게 서버 이중화 및 Switch, Reload 가 이루어진다

빌드 서버에서 이미지를 만들고 해당 이미지를 distribution 을 통해 다른 서버에서 이를 가져오는 식으로 구성된다.


 도커의 Service Discovery 라는 개념을 이용하면 nGinX 를 통해 배포할 때의 단점인 설정 파일의 수정과 재시작이 수반되어야 한다는점과 Proxy 대상 IP Port 가 고정이어야 한다는 점, Health Check 오버헤드를 피할 수 있다


Service Discovery는 서버들의 정보를 포함한 정보들을 저장해서 가져오고, 값의 변화가 일어날 때 이벤트 형식으로 설정을 수정하고 재시작하는 개념이다.




위의 구조에서는 Key/value 스토어를 이용해서 서버 정보를 저장하였으며 Configuration Manager 가 이를 watch하면서 이벤트 방식으로 설정 파일을 만들고 기존 파일에 덮어 쓰는 작업을 하고 있다


docker에서 대표적인 Service discovery tool docker-gen 이 있다


자세한 내용 참조

(https://subicura.com/2016/06/07/zero-downtime-docker-deployment.html)


실습가능한 참조 링크

http://jojoldu.tistory.com/267




Spring 의 Bean 들은 대게 Singleton 패턴으로 정의되며 Application Context 에서 관리되는 형태로 개발자는 사용하게 된다.


그렇게 때문에 상당수의 개발자들이 Spring 의 각 Bean 들은 Thread Safety 가 보장된 안전한 Bean Object 이며 Spring 은 해당 동시성 문제에서 자유롭다고 여기는 경향이 있다.


하지만 정확히 Spring Bean 들은 Thread 의 Safety 와 무관하다. 


Spring Container 는 Object 들 각각에 대한 Life cycle 을 갖고 있으며 Container 내에서 하나만 존재하도록 보장하지만 그것이 Thread-Safe 를 말하는 것은 결코 아니며, Spring framework 는 오히려 이 책임을 개발자에게 맡긴다.


만약 Non-Thread-Safe Object 가 Injection 된다면 해당 객체는 쓰레드에 안전하지 않으며 개발자가 직접 핸들링해주어야 한다.


그렇다면 Bean 에 대해 어떤 방식으로 Thread Safety 를 부여할 수 있을까?


(1) Builder Pattern 의 사용

  간단하면서도 Tricky 한 방식으로 Builder Pattern 을 사용하면 좋다.

 Builder 패턴을 이용하면 객체의 Setter 를 정의하지 않은 상태에서 생성자만으로 객체의 Mutation 을 관리할 수 있으며, Spring 의 Bean 들은 Container 에 의해 life cycle 관리가 위임된다.

 따라서 Builder Pattern 을 통해 Set 을 관리하면 간단하면서도 명확히 Thread Safe 를 구현할 수 있다.


(2) Stateless Bean

  Bean 을 상태값과 무관하게 동작할 수 있는 Bean 으로 설계하는 것이다. 

  Bean 이 특정 상태를 나타내는 변수를 계속 메모리에 들고 상주하는 형태가 아닌, 가장 단순한 형태의 도메인 모델로 사용이 추천된다.


(3) Lock the beans

  가장 최후의 수단으로 여겨야 하는 방법으로 Bean 에 대해 Thread Safe 하게 설계를 하는 것이다. Spring 은 Lower level Library 들을 통해 Bean 단위의 Lock 을 지원하고 있으며 이를 통해 병렬처리에 있어서 동시성 문제의 해결이 필요하다.


물론 실제로 Safe 하지 않은 상황을 고려해야할 경우는 많지 않지만, 각기 다른 Request 를 공통으로 분류해야한다거나, 내부에서 Internal Thread 를 구동하는 경우에는 반드시 신경써보자.





CQRS(Command and Query Responsibility Segregation) 란 .Net 기반으로 발전되고 있는 설계 방법론으로 명령과 쿼리의 역할을 구분하는 것이다. 


이는 데이터에 대한 조작 Create, Insert, Delete 와 데이터에 대한 조회 Select 를 구분하는 것에서 출발한다.


어플리케이션을 개발할 때, 컨텐츠를 위한 데이터 모델은 계속해서 복잡도가 올라가게 된다.




특히 주로 사용되는 위의 모델처럼 데이터 변경과 조회는 보통 하나의 데이터모델을 사용하게 되는데, 어플리케이션의 복잡도가 증가할 수록 각 API 기능의 책임이 어떤 데이터 모델에 있는지는 불분명해진다.


이는 설계에 있어서 초기 의도를 지워버리는 역할을 하며 많은 경우의 레거시 코드들이 이런 기반으로 생겨나게 된다.


CQRS 는 이러한 고민에서 출발하며, 데이터에 대한 조회(Query) 와 데이터에 대한 조작(Command) 을 분리함으로써 이 문제를 해결하고자 한다.


기본적으로 CQRS 를 적용하기 위해서는 Command 을 위한 도메인 모델과 Query 를 위한 도메인 모델을 분리한다.



분리된 각각의 도메인 모델을 DB에 적용하는 방안으로는 몇가지가 있다.


(1) Simple


 : 같은 Scheme 을 가진 DB를 사용하며, Command / Query 시에 데이터에 대한 Converting 을 거친 후 DB에 CRUD 에 대한 작업을 수행한다.

 이 경우에는 일반 어플리케이션과 같으며 도메인 모델만 분리한 상태로 개발이 쉽고 적용이 간단하다.



(2) Premium


 : Command 를 위한 DB와 Query 를 위한 DB를 분리하는 형식으로, 데이터의 정합성을 위한 RDB를 Command 용 DB로 분리하고 Query 가 간편한 NoSQL 을 Query 용 DB로 주로 사용한다.

 이렇게 동일한 데이터에 대해 다수의 저장소를 운용하는 방식을 Polyglot Storage 라 하며 이 경우 용도에 맞는 저장소를 골라서 좀 더 알맞게 사용이 가능하다.

 하지만 분리된 저장소 각각에 대한 데이터 동기화 이슈를 Broker 등을 이용해 처리해주어야 하는 점은 이슈가 되며 책임의 소재나 로깅 등에 있어 신뢰도 확보를 위한 작업이 필요하다.



(3) Event Sourcing


 : Event Sourcing 이란 Application 내의 설계를 컨텐츠 기반이 아닌 기능 기반으로 하면서 이러한 "이벤트(Event)" 자체를 DB에 저장하는 방식을 말한다.

 이렇게 함으로써 이벤트에서 사용하는 도메인 모델은 컨텐츠를 위한 DB에 Write 되고 Query 시에는 이벤트를 저장한 DB로부터 해당 컨텐츠를 바탕으로 데이터를 만들어서 가져온다.

 도메인 모델에 대한 Command 가 따로 저장되고, Query 를 위한 도메인 모델은 Event DB로부터 불러오는 방식 때문에

 Event Sourcing 의 Architecture를 적용함에 있어서 CQRS 는 필수적인 설계 방식이 된다.

 CQRS 를 적용하는 데 있어서도 가장 큰 시너지를 낼 수 있는 Architecture 의 하나이다.


<향후 Event Sourcing Architecture에 대해서는 추가로 정리한다.>


CQRS 가 실무에 적용되는 데 있어 아직은 국내외적으로 불확실성이 있는 듯 하지만, 주목해볼만한 패턴인 것은 틀림없다.


(참고자료 : https://docs.microsoft.com/en-us/previous-versions/msp-n-p/dn568103(v=pandp.10))


마이크로 서비스 아키텍처 (Micro Service Architecture) 란, 최근에 각광받고 있는 웹 기반 분산 서비스 시스템 아키텍처를 말하며, 이러한 아키텍처를 갖는 서비스 자체를 마이크로 서비스 (Micro Service) 라 한다.


앞선 포스팅에서 언급한 모놀리식(Monolithic) 아키텍처가 하나의 어플리케이션 또는 서비스가 여러개의 모듈이 결합된 강건한 형태의 아키텍처를 갖는다면, 마이크로 서비스 아키텍처는 반대로 독립된 각각의 모듈을 조립하여 만드는 하나의 서비스를 위한 아키텍처라고 볼 수 있다.

(참조(모놀리식 아키텍처) : http://jins-dev.tistory.com/entry/%EC%A0%84%ED%86%B5%EC%9D%98-%EC%86%8C%ED%94%84%ED%8A%B8%EC%9B%A8%EC%96%B4-%EC%95%84%ED%82%A4%ED%85%8D%EC%B2%98-%EB%AA%A8%EB%8D%B8-%EB%AA%A8%EB%86%80%EB%A6%AC%EC%8B%9DMonolithic-%EC%95%84%ED%82%A4%ED%85%8D%EC%B2%98?category=760149)


즉, Software 설계 시에 Loose Coupling 을 위하여 고려되는 "모듈화" 의 개념이 Web API 를 이용하여 서비스 레벨로 확장된 것으로 이해하면 편하다.


이는 오래된 개념이며, 최근에 클라우드 시스템 및 도커 등의 발달로 인해 보다 손쉬운 구현이 가능해지면서 대세로 자리잡고 있다.


마이크로 서비스 아키텍처는 작은 서비스들의 컬렉션으로 구성된다. 각각의 작은 서비스 단위들은 단일 비즈니스 기능을 구현할 수 있어야 한다.



 마이크로 서비스 아키텍처에서 서비스는 작고 독립적이며 느슨하게 결합되어 있다. 각 서비스는 작은 개발 팀이 관리할 수 있는 개별 코드 베이스이다. 서비스들을 독립적으로 배포할 수 있으며 팀이 전체 응용 프로그램을 다시 빌드한 후 재배치하지 않고도 기존 서비스를 업데이트 할 수 있다


서비스는 해당 데이터 또는 외부 상태를 유지해야하고 이는 별도의 데이터 레이어를 갖는 기존의 모델과 다른점이다. 각 서비스들은 API를 사용하여 통신하고, 구현 내용은 감춰진다. 각 서비스들은 동일한 기술 스택, 라이브러리 또는 프레임워크를 공유할 필요가 없다.


 마이크로 서비스 아키텍처는 노드 간의 서비스들을 관리할 수 있는 특징적인 구성요소를 지닌다. 또한 서비스 목록을 조회하거나 클라이언트로부터 들어오는 API의 진입점을 별도 인터페이스의 게이트웨이로 분리하는 특징을 지닌다. 이는 API 서버일수도, 어드민 형태의 웹페이지일 수도 있다.


 마이크로 서비스 아키텍처가 사용되는 경우는 빠른 릴리즈 개발 속도가 요구되거나 고확장성이 필요한 복합적인 프로그램, 많은 하위도메인을 가진 거대한 프로그램 또는 소규모 개발 팀으로 구성된 조직에 유용하다. 이는 다음과 같은 이점들로 인해 기인한다.


-      독립배포 : 전체 프로그램을 다시 배포하지 않고도 업데이트가 가능하다. 이에 따라 버그 수정 및 릴리즈 관리가 용이하고 위험부담이 덜하다.


-      독립개발 : 독립적인 개발팀들에 의해 개발될 수 있다.


-      집중화된 소규모팀 : 팀이 각 서비스에만 집중할 수 있다.


-      결함격리 : 한 서비스가 다운되더라도 전체 서비스에 영향을 미치지 않는다.


-      혼합기술스택 : 각 서비스에 적합한 기술을 선택하여 조합할 수 있다.


-      세분화된 확장성 : 서비스를 독립적으로 확장할 수 있다. 이에 따라 리소스의 유연한 운용이 가능하다.


 위와 같은 장점을 갖고 있음에도 아직 마이크로 서비스 아키텍처는 모놀리식 아키텍처에 비해 복잡하며 독립된 구조로 인해 통합적인 유지 관리가 어려워질 수 있다. 가령 에러가 난 서비스의 권한이 다른 팀에 있다면, 그 부분의 보수를 위해서 우리가 직접 수정하는 것이 아닌 커뮤니케이션이 필요하게 된다.


또한 서비스 구성에 있어 네트워크 정체 및 통신에 신경을 써줘야 하며 데이터 일관성 및 버전 관리가 중요해진다. 그리고 프로젝트 진행에 있어 팀원들이 이루는 문화가 중요해진다. 이러한 기조에서 알맞은 개발 문화가 개발자가 운영까지 담당하는 DevOps(데브옵스) 문화라 할 수 있다.

 

 





 모놀리식 아키텍처란, 마이크로서비스의 각광에 따라 마이크로서비스가 아닌 전통의 아키텍처를 지칭하는 의미로 생겨난 단어이다. 위의 그림에서 처럼 모든 모듈은 서비스 내부의 Product 형태로 종속되어 있으며, 서비스에만 집중할 수 있는 구조로 되어 있다.


이는 Monolithic 이라는 단어의 뜻 그대로 하나의 Massive 한 Context 형태의 아키텍처를 의미하며 

하나의 서비스 또는 어플리케이션이 하나의 거대한 아키텍처를 가질 때, Monolithic 하다고 한다. 


 모놀리식 아키텍처를 갖는 Software의 특징은 그 자체로 강건하며 내부 요소간의 Dependency 를 크게 가질 수 있다는 점이다. 그리고 이는 필연적으로 구조적인 Coupling 이 강력하게 유지되는 결과를 초래한다. 


 또한 각 비즈니스 컴포넌트들이 하나의 강한 결합 구조를 지니며 통일성이 있다.

이는 비즈니스 로직이 서비스에 최적화된 코드를 만들어내는데 좀 더 집중할 수 있는 반면 복합적인 예외를 만들 수 있는 위험성을 내포하게 된다.



장점과 단점


 개발 초기에는 단순한 아키텍처 구조와 개발의 용이함이 큰 장점이지만 규모가 커짐에 따라 복잡도가 심각하게 증가한다.


 가령 토이 프로젝트를 한다고 생각해보자. 생각이 흐르는대로 Prototyping 을 할 때는 구조가 복잡하고 Dependency 가 크더라도 손쉽게 만들 수 있으며 오히려 모듈별로 분리하고 나누는 것은 코드의 최적화 및 구현에 방해가 되는 경우가 많다.


 그러나 프로토 타이핑 이후에 새로운 컨텐츠를 추가하거나 새로운 팀원이 생겼을 때 문제는 시작된다. 이 거대한 구조가 본인에게는 간단하고 쉬울 수 있으나 새로운 팀원에게는 가혹하게 느껴질 것이다.


 또한 최근 클라우드 환경이 각광받으면서 두드러지게된 단점으로 하나의 모듈을 수정하기 위해서는 전체 어플리케이션의 배포가 수반되며 서버 기동, 빌드 및 배포 시간이 오래걸린다는 점이 있다.


마이크로 서비스 아키텍처 관련 포스팅에서 한번 더 언급을 하겠으나, 일반적으로 마이크로서비스 아키텍처의 Scalability 복잡도가 N+M 이라면 모놀리식 아키텍처의 복잡도는 N*M 형태로 증가하기 때문에 컨테이너의 과부하와 배포 및 스케일링의 어려움을 겪게 된다.


또한 기술 스택의 선택폭이 좁아지며 많은 문제를 해결하기 위해 보다 강력하고 탄탄한 기술력이 요구된다. 이는 내부 구성요소들 간의 강력한 Dependency 문제 때문이다. 한 모듈의 선택은 다른 외부 모듈에서 버그를 초래할 수 있다. 따라서 사용하고자 하는 프로젝트의 큰 그림이 아키텍처 구성 단계에서 그려져 있어야 문제를 최소화할 수 있다.


 최근에는 많은 서비스들이 초창기에 모놀리식으로 개발되고 향후 마이크로서비스 아키텍처로 구조를 변경한다. 

혹은 인프라가 잘 갖추어진 회사에서라면 여러분을 도와줄 많은 플랫폼들이 이미 마이크로 서비스 아키텍처로 존재할 것이다.



+ Recent posts