dev.toDavid Whitney 이 작성한 Architecture for Everyone 번역 자료입니다. 번역에 문제가 있다면 댓글 달아주시구요. 원문을 보시기를 추천드립니다

누군가 두려운 아키텍처 단어를 말했고 당신은 아키텍트가 아닙니다.

누군가가 계산 복잡성에 대한 당신의 이해에 도전 할 때 웹 페이지에 위젯을 배치를 시도 할 때 두려운가요? 두려워하지 마세요. 생각보다 복잡하지 않습니다.

아키텍처는 접근하기 어렵고 접근 제한(gate-kept)되고 “어려운 컴퓨터 과학(hard computer science)”으로 유명합니다. 평균 웹 스케일(average-to-web-scale)의 웹 어플리케이션을 위해 사용하는 대부분의 소프트웨어 아키텍처는 놀랍도록 유사합니다.

아키텍트가 아닌 사람(not-architects)과 웹 프로그래머들을 위한 간단한 아키텍처 입문서를 통해 아마 어디에서나 볼 수 있을 기본과 전문 용어와 아키텍처 패턴을 다루게 될 겁니다.

웹 서버 란 무엇입니까?

기본부터 시작하겠습니다. “웹”또는 “월드 와이드 웹” - 오래된 존댓말을 사용하는 인터넷에 연결된 많은 컴퓨터들 일 뿐 입니다. 웹은 연결된 컴퓨터에서 “리소스”(read: web pages)를 검색하는 방법을 설명하는 일련의 규칙입니다.

간단히 말해 “웹 서버”는 “HTTP 프로토콜” (원격 컴퓨터에 보낼 수있는 일련의 명령)을 구현하여 “이봐, 컴퓨터, 나에게 그 문서를 보내라”라고 말합니다. 만약 친숙하게 들리면 그것은 당신의 웹 브라우저가 작동하는 방식이기 때문입니다.

www.my-awesome-website.com을 브라우저에 입력하면 컴퓨터에서 실행되는 코드가 “http request”을 만들어 주소표시줄에 입력 한 URL (read: the website address)과 연결된 웹 서버로 보냅니다.

따라서 웹 서버 - 인터넷에 연결된 원격 컴퓨터에서 실행되는 프로그램은 요청을 수신할 때 요청을 듣고 데이터를 반환합니다. 이것이 실제로 작동한다는 사실은 작은 기적(small miracle)이며 DNS (my-awesome-website.com을 IP 주소로 바꾸는 것)와 많은 네트워킹, 라우팅 및 스위칭을 기반으로 합니다. 깊게 들어 가지 않는 한 실제 용어에 대해 너무 많이 알 필요는 없습니다.

범용 웹 서버가 많이 있습니다 - 현실적으로 Apache, NGINX 및 Microsoft IIS와 특정 웹 서버 개발 스택이 혼합되어 있는 것을 볼 수 있을 것입니다 (Node.js는 ASP.NET CORE for C# 과 HTTP4K for Kotlin 처럼 자체적으로 제공됩니다).

HTTP는 어떻게 작동합니까? 그리고 그 아키텍처 인가요?

웹 프로그래밍을 조금이라도 했다면 HTTP를 조금은 알고 있을 것입니다.

그것은 “하이퍼 텍스트 전송 프로토콜(The Hyper Text Transfer Protocol)”을 의미하며 그것은 당신의 브라우저가 웹 서버와 대화 하는 방식입니다. 간단한 로우 HTTP “요청 메시지(request message)”를 살펴 보겠습니다.

GET http://www.davidwhitney.co.uk/ HTTP/1.1
Host: www.davidwhitney.co.uk
Connection: keep-alive
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64…
Accept: text/html,application/xhtml+xml,application/xml;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: en-GB,en-US;q=0.9,en;q=0.8

HTTP의 기본 사항은 이해하기 쉽습니다 - 필수 “request line”이 있습니다. 이 비트에는 동사(GET, POST, PUT, HEAD 중 하나), URL(웹 주소)과 프로토콜 버전(HTTP/1.1)이 포함되어 있습니다.

그런 다음 선택적인 요청 헤더 필드(bunch of optional request header fields)가 많이 있습니다 - 다른 모든 것 - 이 정보는 웹 서버에 전달하는 추가 정보로 생각하세요. 헤더 다음에는 빈 줄과 선택적인 본문이 있습니다. HTTP/1.1입니다. 우리는 여기서 끝났습니다. 서버는 비슷한 형태로 응답합니다.

HTTP/1.1 200 OK
Cache-Control: public,max-age=1
Content-Type: text/html; charset=utf-8
Vary: Accept-Encoding
Server: Kestrel
X-Powered-By: ASP.NET
Date: Wed, 11 Dec 2019 21:52:23 GMT
Content-Length: 8479


<!DOCTYPE html>
<html lang="en">...

첫 번째 줄은 상태 코드이며 헤더와 응답 본문이 있습니다. 그거에요. 웹 서버는 요청 내용에 따라 원하는 것을 보낼 수 있으며 요청하는 소프트웨어는 응답을 해석 할 수 있어야합니다. 올바르게 요청하고 적절하게 대응하는 데는 많은 뉘앙스가 있지만 기본은 동일합니다.

웹은 디자인 패턴 REST의 구현입니다. - “표현 상태 전송(Representational State Transfer)”을 나타냅니다. - 사람들이 REST에 대해 많이 이야기하는 것을 들을 수 있습니다 - 로이 필딩의 박사학위 논문에서 정의 되었습니다. 더 중요한 것은 당시 HTTP/1.0이 어떻게 작동했는지에 대한 설명이었고 필딩의 HTTP/1.1에서의 작업과 동시에 문서화 되었습니다.

따라서 웹은 기본적으로 RESTful입니다. REST는 HTTP 작동 방식을 설명합니다.

짧은 버전? 어딘가에 컴퓨터 (웹 페이지, 문서, 이미지 등)의 상태를 나타내는 고유 한 주소 지정 가능 URI (웹 주소). 클라이언트가 요청한 내용에 따라 해당 상태(state)의 표현이 다를 수 있습니다.

HTTP와 REST, 그리고 아키텍처 스타일이 하나로 통합되어 있습니다.

웹 응용 프로그램의 아키텍처는 어떤 모습일까요?

다양한 아키텍처 패턴에 따라 좋은 소프트웨어를 작성할 수 있지만 대부분의 사람들은 소수의 공통 패턴을 고수합니다.

“The MVC App”

MVC – model view controller - 응용 프로그램의 처리 로직과 프로그램의 프리젠테이션 로직을 분리하는 심플한 디자인 패턴입니다. MVC는 Ruby on Rails의 성공으로 (패턴은 수십 년 이전이었지만 ) 실제로 주목을 받아 왔고 대부분의 사람들이 “MVC”라고 말하면 코드가 몇 가지 다른 디렉토리로 구성되는 “Rails-style” MVC 앱을 말하고 있습니다.

/controllers
/models
/views

Rails는 “routing”과 실용적인 기본값(sensible defaults)에 대한 아이디어와 함께 “컨벤션 오버 컨벤션 (convention over configuration)”을 널리 사용했습니다. 이것은 ASP.NET MVC에 의해 거의 도매로 복제되었으며 그 이후로 거의 모든 다른 MVC 프레임 워크로 복제되었습니다.

넓은 범위의 일반화로서 기본적으로 다음과 같은 URL이 있는 경우

http://www.mycoolsite.com/Home/Index

“routes”를 사용하는 MVC 프레임워크 - 어떤 것을 찾을 위치를 정의하는 규칙 - 컨트롤러 디렉토리에서 (프로그래밍 언어에 따라) “HomeController”파일 또는 모듈을 찾아보십시오. “Index”라는 함수가있을 수 있습니다. 이 함수는 모델을 반환합니다 - 일부 데이터 - “view”에 의해 렌더링 됩니다. - views 폴더의 HTML 템플릿

MVC 프레임워크는 “routes” (사물을 찾는 위치를 정의하는 규칙)를 사용하여 컨트롤러 디렉토리 내에서 “HomeController” 파일 또는 모듈(프로그래밍 언어에 따라 다름)을 시도하고 찾을 수 있습니다.

“Index”라는 함수가 있을 수 있습니다. 이 함수는 views 폴더에서 HTML 템플릿 인 “view”로 렌더링된 모델 (일부 데이터)을 반환합니다.

다른 프레임워크는 이 작업을 약간 다르게 수행하지만 핵심 아이디어는 동일합니다. 데이터 페이지를 리턴하고 웹에서 입력을 처리하는 기능과 함께 컨트롤러별로 그룹화 된 기능.

“API가 있는 싱글 페이지 앱”

SPA는 매우 일반적이며 Angular, React 및 Vue.js와 같은 클라이언트 측 웹 프레임워크에서 널리 사용됩니다. 여기서 유일한 차이점은 MVC앱을 가져와 대부분의 작업을 클라이언트 측으로 옮기는 것입니다.

여기에 취향의 몇 가지가 있습니다 - 클라이언트 사이드 MVC, MVVM (model-view-view-model) 및 (FRP) 함수 반응식 프로그래밍(functional reactive programming)이 있습니다. 그 차이는 처음에는 미묘하게 보일 수 있습니다.

Angular “models, views and controllers” 패턴 준수 - 사용자의 웹 브라우저 에서 실행됩니다.

React – functional reactive programming의 구현 - 좀 더 유연하지만 데이터의 상태 변경 이벤트에 더 관심이 있습니다 – 종종 데이터에 Redux와 같은 일부 이벤트 저장소를 사용합니다.

MVVM은 데이터를 제공하는 것 (model)과 UI (뷰 모델이 제공하는 것) 사이에 양방향 바인딩이 있는 싱글 페이지 앱에서 동일하게 사용됩니다.

이러한 모든 클라이언트 무거운 JavaScript 프레임워크 아래 일반적으로 “MVC앱”과 거의 구별되지 않는 API이지만 미리 렌더링된 페이지를 반환하는 대신 클라이언트가 UI에 “바인딩(bind)”하는 데이터를 반환합니다.

“CDN 또는 기타 dumb 서버에서 호스팅되는 정적 사이트”

아마도 집합의 특이점 일 것입니다. - 20대(20-teens)에서 정적 웹 사이트가 다시 부활했습니다. 컴퓨터에서 코드를 계속 실행하면 트래픽이 많은 웹 사이트를 확장하기 어렵습니다.

워드프레스와 같은 비교적 복잡하고 성능이 좋지 않은 콘텐츠 관리 시스템을 구축하는 데 많은 시간과 비용이 들었으며, 이로 인해 많은 비용과 하드웨어가 필요했습니다.

결과적으로 컨텐츠 렌더링을 “개발 시간” 운동으로 전환하면 비용과 확장성 측면에서 뚜렷한 이점이 있습니다. 실행중인 코드가 없으면 충돌 하지 않습니다!

따라서 정적 사이트 제너레이터는 점점 더 인기를 끌고 있습니다. - 일반적으로 일반적인 프론트엔드 웹 개발 스택을 사용할 수 있지만 빌드 도구를 사용하여 모든 파일을 생성하여 dumb 웹 서버 또는 CDN에 번들 및 배포 할 수 있습니다. 다음과 같은 도구를 참조하세요 - Gatsby, Hugo, Jekyll, Wyam

“다른 것”

웹앱을 따르는 다른 아키텍처 타입이 있습니다. - 변환된(트랜스파일) 프레임워크가 서서히 증가하는 추세 (WebAssembly의 C# 용 블레이드 및 Kotlin의 JavaScript 컴파일 대상) - 오늘날 지배적인 Javascript 프레임워크의 엄청난 인기와 함께 이들은 모두 잘 어울리려고 노력합니다.

왜 다른 것을 선택해야합니까?

까다로운 질문입니다. 솔직히 말해서 그것은 취향의 문제이며 모두 웹 어플리케이션을 만들기에 완벽하게 적절한 방법입니다.

서버 렌더링 (Server-rendered) MVC 앱은 인터렉티브 기능이 낮은 웹 사이트에 적합합니다. 높은 충실도(high fidelity) 프론트엔드가 증가하는 추세지만 그와 비슷한 방대한 범주의 웹 사이트가 있습니다. - 웹 응용 프로그램이 아닌 웹 사이트 - 대규모 툴체인의 복잡성 비용은 종종 투자 가치가 없습니다.

높은 충실도 UX를 필요로 하는 모든 것, 거의 기본적으로 React, Angular 또는 Vue 앱입니다. 프로그래밍 모델은 반응형 사용자 경엠에 적합하며 사용하지 않으면 대부분 직접 재발명하게 됩니다.

정적 사이트? 블로그, 마케팅 마이크로 사이트, 컨텐츠 관리 시스템, 실제 컨텐츠가 가장 귀중한 상호 작용 인 모든 곳에 적합합니다. 확장성이 뛰어나고 기본적으로 충돌 하지 않으며 운영 비용이 저렴합니다.

HTTP API, Rest, GraphQL, 프론트엔드를 위한 백엔드

결국 API와 상호작용하게 될 겁니다. 이런 것들을 복잡하게 만들기 위해 많은 용어가 사용되지만 핵심은 간단합니다. 사용하거나 빌드하는 대부분의 API는 “REST-ish”가 됩니다.

브라우저에서와 같은 종류의 “HTTP 요청”을 발행할 수 있으며 대부분 JSON 응답을 반환합니다.

브라우저가 수행하는 것과 동일한 종류의 “HTTP 요청”을 발행(issuing)하며 주로 JSON 응답을 반환합니다 (때로는 XML이지만). 이러한 대부분의 API를 JSON-RPC 또는 XML-RPC로 설명하는 것이 안전합니다.

밀레니엄 시대에 “SOAP”(simple object access protocol) API 표준화에 대한 추진이 있었으며 좋은 것들이 많이 제공되었지만 사람들은 XML이 읽기번거롭다는 것을 발견하고 인기가 감소했습니다.

아이러니하게도 SOAP (일관된 메시지 엔벨로프 형식, 보안 고려 사항, 스키마 검증)에서 해결 된 많은 것들이 Swagger (현재 OpenAPI)와 JSON:API 같은 새로운 개방형 표준을 사용하여 JSON 위에서 “해결(re-solved)” 되어야 했습니다.

우리는 이미 웹에 있던 것들을 재발명(re-inventing) 하는데 능숙합니다.

그렇다면 REST API를 JSON-RPC가 아닌 REST API로 만드는 이유는 무엇입니까?

묻지 않아서 다행입니다.

REST의 핵심은 HTTP를 통해 리소스에 발생할 수 있는 작업을 모델링하는 것입니다. REST가 좋은 아키텍처 스타일 인 이유에 대해 자세히 알아 보려면 Jim Webber의 Rest in Practice라는 훌륭한 책이 있습니다. (그리고 REST에 대한 많은 현대적인 분석은 상대적으로 정보가 없으며 SOAP 이전의 처리와 크게 다르지 않습니다).

사람들은 REST와 REST가 아닌 것에 대해 정말로 관심을 가지며 JSON-RPC를 REST로 설명하여 REST에 관심이 있는 사람들을 화나게 할 것입니다.

사람들은 진정 무엇이 REST가 아닌 것에 관심이 있으며 JSON-RPC를 REST로 설명하여 REST에 관심이있는 사람들을 화나게 할 것입니다. JSON-RPC는 REST 디자인의 품질을 설명하는 모델인 리처드슨 성숙도 모델(Richardson Maturity Model)의 “level 0”입니다 - REST 디자인의 품질을 설명하는 모델. 몇 가지 작업을 수행하여 RESTish, Sane, 알맞은 JSON-RPC를 구축 할 수 있으므로 걱정하지 마십시오.

먼저 HTTP VERB를 올바르게 사용하고, 페치 (및 부작용이 없는) GET, “작업 중”에 대한 POST, “클라이언트에 의해 상태가 컨트롤되는 항목 생성”에 대한 PUT을 사용해야 합니다. 그 다음 API를 논리적 “리소스” (핵심 도메인 개념 “고객”, “제품”, “카탈로그”등)으로 구성해야합니다.

마지막으로 API와의 상호 작용에 올바른 HTTP 응답 코드를 사용합니다.

“응용 프로그램 상태(state)의 엔진으로 하이퍼 미디어”를 사용하지 않을 수도 있지만 아무도 당신의 피를 뽑으러 오는 사람이 없을 정도로 충분히 잘할 것입니다.

당신은 또한 충분히 수행하여 완전히 RESTful API의 혜택을 많이 얻을 수 있습니다. - 자원은 HTTP를 통해 탐색 할 수 있을 것입니다, 문서는 캐치할 수 (cachable) 있습니다. API는 가장 일반적인 도구에서 작동합니다. swagger 또는 OpenAPI 라이브러리를 사용하여 스키마를 생성하면 대부분의 사람들이 하는 작업을 거의 수행할 수 있습니다.

그러나 나는 hackernews에서 REST Sux와 GraphQL이 가야할 길이라고 읽었습니다.

예, 우리도 그 게시물을 읽었습니다.

GraphQL은 혼란스럽게도 HTTP API 및 스키마 툴의 표준인 쿼리 언어입니다. 클라이언트 사이드에 많은 웹 앱이 확산되면서 GraphQL은 클라이언트에 반환해야 할 데이터의 정의를 클라이언트 코드 자체로 효과적으로 푸시하여 인기를 얻었습니다.

이러한 종류의 “프론트엔드에서 쿼리” 스타일이 제안 된 것은 이번이 처음이 아니며 마지막이 아닐 수도 있습니다. GraphQL을 이전의 접근 방식 (특히 Microsoft의 OData)과 약간 차별화하는 것은 타입 및 쿼리가 일부 SQL 스토리지에 직접 매핑되는 것이 아니라 서버 측에서 Resolver 코드로 구현된다라는 아이디어입니다.

이는 몇 가지 이유에서 유용합니다. 이는 GraphQL이 도메인의 여러 이기종 API에 대한 단일 API 일 수 있음을 의미하며, 클라이언트가 하위 집합을 지정할 수 있도록하여 REST API에서 흔히 발생하는 “over fetching” 문제를 해결합니다. 반환하려는 데이터 중 하나이며, 또한 anti-corruption(부패방지) 레이어의 역할을 하여 기본 스토리지에 대한 무제한 액세스를 방지합니다.

GraphQL은 또한 웹 또는 모바일 앱이 말하는 단일 연결 지점이 되도록 설계되어 성능 최적화에 매우 유용합니다. - 간단히 말해, 와이어를 통해 하나의 API가 모든 내부 API 자체를 (대기 시간이 많은 경우) 모바일 앱 호출보다 대기 시간이 짧은 다운스트림 API를 호출하는 것이 더 빠릅니다.

GraphQL은 실제로 API를 스키마화하는 스마트하고 효과적인 방법이며 가장 친한 친구가 아닌 프론트 엔드를 위한 백엔드 인 BFF를 제공하여 빠르게 변경할 수 있습니다.

BFF? 도대체 BFF는 무엇입니까?

이 문제를 상상해보세요 - 100개의 팀이 있는 MEGACORP에서 일하고 있거나 팀 (기억하지 못하며 격주로 명명법의 이름을 바꿉니다) - 각각 마이크로 서비스 세트를 담당합니다.

당신은 단지 몇 가지 작업을 수행 하려고 하는 웹 프로그래머, 그리고 새로운 기능 방금 시작 했습니다. 문서를 읽습니다.

이 문서에서는 OAuth 토큰과 클레임이 필요한 여러 API 간에 호출을 오케스트레이션하는 방법을 설명하며, 결국에는 반짝이는 새 기능을 갖게 됩니다.

따라서 API 호출을 작성하면 모든 데이터가 전송에 안전한지 확인해야 하는 보안 위험은 물론 클라이언트에서 데이터를 계속 전송하는 데 걸리는 시간이 느려질 수 있다는 것을 깨닫게 됩니다. 이것은 당신이 영원히 가장 친한 친구가 필요한 이유입니다.

죄송합니다, 프론트 엔드를 위한 백 엔드.

BFF는 하나의 응용 프로그램 만 제공하는 API입니다. 내부 도메인 (MEGACORPS BUSINESS)을 제공하는 응용 프로그램의 내부 언어로 변환합니다. 인증, 속도 제한, 한 번 이상 하 고 싶지 않은 일 등을 처리합니다. 서버의 블필요한 라운드 트립(roundtrips)을 줄이고 데이터를 대상 응용 프로그램에 더 적합하도록 변환합니다.

당신이 제어하는 API라고 생각하십시오. 단지 당신의 앱을 위해서.

그리고 GraphQL 및 OData와 같은 툴은 BFF에 탁월합니다. GraphQL은 요청을 일괄 처리하여 이러한 호출을 최적화하는 데 도움이되는 Apollo 및 Apollo-Server와 같은 탁월한 툴을 사용하여 최신 JavaScript 기반 프런트엔드에서 특히 잘 작동합니다.

그것은 또한 꽤 프론트 엔드 개발 친화적인(front-end-dev) - 쿼리 및 스키마는 json과 매우 유사하며, 스택을 “자바 스크립트까지 내려 간다(javascript all the way down)”고 먼 백엔드 팀에 알리지 않고 유지합니다.

당신이 볼 수 있는 다른 것들과 이유

이제 우리는 웹 서버, 웹 앱 및 API를 이해하고 있습니다. 현대 웹 프로그래밍보다 더 많은 것이 있습니까? 가장 자주 접하게 될 것들이 있습니다.

로드 밸런싱 (Load Balancing)

사이트에 트래픽이 있다면 운이 좋지만 서비스형 플랫폼 제공 업체를 사용하지 않을 만큼 운이 좋지 않은 경우 어떤 시점에서 로드밸런서를 실행할 것입니다. 당황하지 마십시오. 로드 밸런서는 구식 언어를 사용하거나, 심술궂은 sysops에 의해 운영되는 경우가 많거나, NGINX의 사본을 실행하고 있습니다.

모든 로드 밸런서는 응용 프로그램 (또는 응용 프로그램)에 대한 HTTP 요청을 수락하고 사용량이 많지 않은 서버를 선택하여 요청을 전달합니다.

로드 밸런서가 소프트웨어의 특히 “핫 경로(hot path)”를 하드웨어 전용 풀로 분산하여 안전하게 유지하거나 장애로부터 격리하는 것을 볼 수 있습니다.

SSL 인증서를 처리 하는데 사용 하는 로드 밸런서를 볼 수도 있습니다 - 이것을 SSL 종료(SSL Termination) 라고 합니다.

분산 캐싱 (Distributed caching)

하나의 컴퓨터가 일부 데이터를 메모리에 저장할 수 있다면 많은 컴퓨터가… 더 많은 데이터를 저장할 수 있습니다!

분산 캐싱은 “Memcached”에 의해 개척되었습니다 - 2003년 블로그 플랫폼 Livejournal을 확장하기 위해 작성되었습니다. 당시 Memcached는 Livejournal이 비교적 적은 수의 서버에서 모든 최신 항목의 캐시 사본을 공유 할 수 있도록 지원하여 동일한 하드웨어의 데이터베이스 서버로드를 대폭 줄였습니다.

메모리 캐시는 계산하기에 “무거운” 결과를 저장하는 데 사용되며, 시간이 걸리거나 서버 소프트웨어를 실행하는 모든 다른 컴퓨터에서 일관 되어야 합니다. 약간의 네트워크 대기 시간과 교환하여 응용 프로그램에서 사용 가능한 총 메모리 양을 모든 서버에서 사용할 수있는 모든 메모리의 합계로 만듭니다.

분산 캐싱은 “캐시 스탬프”를 방지하는 데에도 유용합니다. 비분산 캐시가 실패하고 모든 클라이언트가 캐시된 데이터는 모든 클라이언트에 의해 다시 계산되지만, 메모리를 공유함으로써 전체 캐시 실패의 확률은 현저히 낮아지고, 발생하더라도 일부 데이터만 다시 계산됩니다.

분산 캐시는 어디에나 있으며 모든 주요 호스팅 제공 업체는 memcached 또는 redis 호환 (읽기 : memcached 클라이언트 라이브러리를 사용하여 액세스 할 수 있음) 관리 캐시를 지원하는 경향이 있습니다.

분산 캐시의 작동 방식을 이해하는 것은 매우 간단합니다. 항목을 추가 할 때 생성되는 키 (해당 항목을 검색하는 데 사용하는 것)에는 캐시에 해당 데이터를 저장하는 컴퓨터의 주소나 이름이 포함됩니다. 분산 캐시 클러스터의 일부인 컴퓨터에서 키를 생성하면 동일한 키가 생성됩니다.

이는 캐시와 상호 작용하는 클라이언트 라이브러리가 사용될 때 데이터 검색을 위해 호출해야하는 컴퓨터를 이해함을 의미합니다.

이와 같이 대용량의 공유 메모리 풀을 분리하는 것은 현명합니다. 매우 빠른 검색이 가능하기 때문입니다. 한 컴퓨터에서 항목을 검색하기 위해 많은 양의 메모리를 스캔 할 필요가 없기 때문입니다.

Content Delivery Networks (CDNs)

CDN은 전세계의 다른 사람들이 운영하는 웹 서버입니다. 데이터를 업로드하면 모든 “edges” (“전 세계의 모든 서버에 대해 의미하는 바보같은 용어”)에 걸쳐 데이터를 복제하여 누군가가 귀하의 콘텐츠를 요청할 때 DNS 응답은 자신과 가까운 서버를 반환하며 해당 콘텐츠를 가져 오는 데 걸리는 시간이 훨씬 빠릅니다.

CDN을 운영하는 메커니즘은 하나를 사용하는 것보다 훨씬 복잡하지만 정적 에셋 (이미지!) 또는 특히 큰 파일 (비디오! 큰 이진 파일)이 많은 경우에 적합합니다. 또한 서버의 전체 부하를 줄이는 데 매우 유용합니다.

CDN으로의 오프로드는 최소한의 비용으로 추가 성능을 얻을 수있는 가장 쉬운 방법 중 하나입니다.

디자인 패턴에 대해 이야기해 봅시다! 그게 진짜 아키텍쳐 입니다.

"Design patterns are just bug fixes for your programming languages"
"디자인 패턴은 프로그래밍 언어에 대한 버그 수정일 뿐입니다."

사람들은 마치 성배처럼 디자인 패턴에 대해 이야기 할 것입니다 - 그러나 모든 디자인 패턴은 사람들이 자주 해결하는 문제에 대한 해답입니다. 그것을 해결 하는 허용된 방법이 있습나다. 언어, 도구 또는 프레임워크가 더 좋았다면 아마도 우리를 위해 일할 것입니다 (실제로 새로운 언어 기능 및 도구는 종종 시간이 지남에 따라 디자인 패턴을 사용하지 않습니다).

매우 일반적인 몇 가지를 빠르게 살펴 보겠습니다.

  • MVC – “데이터 모델, UI 코드 및 비즈니스 로직을 분리하여 혼동하지 않도록하십시오”
  • ORM – “Object-Relational mapping” - 매핑 라이브러리와 구성된 규칙을 사용하여 메모리 내 개체의 저장소를 관계형 저장소로 관리합니다. 객체와 저장 위치를 함께 혼동하지 마십시오.
  • Active Record – “모든 개체는 데이터베이스에 연결되어 있는지 신경 쓰는 웹 양식일 뿐이므로 자신을 저장할 수 있어야 합니다!”
  • Repository – “모든 데이터 액세스가이 클래스에 있습니다. 데이터와 상호 작용하여 로드합니다.”
  • Decorator – “개체, 클래스 또는 함수 주위에 ‘데코레이터(decorators)’를 추가하거나 감싸서 원래 구현을 변경하지 않고 캐싱 또는 로깅과 같은 일반적인 동작을 추가합니다.”
  • Dependency Injection – “클래스나 함수가 어떤 것에 의존하는 경우, 의존성을 제공하는 것은 호출자 (종종 사용중인 프레임 워크)의 책임입니다”
  • Factory – “이 중 하나를 만드는 데 필요한 모든 코드를 한 곳에, 한 곳에만 넣으십시오”
  • Adapter – “어댑터를 사용하여 다른 방식으로는 작동하지 않는 것들 사이의 간격을 메워 내부 데이터 표현을 외부 표현으로 변환합니다. 트위터 응답을 YourSocialMediaDataStructure로 변환하는 것처럼”
  • Command – “각 개별 작업 또는 요청은 단일 장소에서 구현됩니다”
  • Strategy – “스왑 인 아웃할 수 있는 여러 가지 작업 방법 정의”
  • Singleton – “전체 응용 프로그램에서 이 중 하나만 있습니다”.

이것은 여러분이 듣게 될 패턴 전문 용어의 일부에 대한 완전하지 않은 목록입니다. 디자인 패턴에 대한 특별한 것은 없다, 그들은 단지 1990 년대 버전의 허용하고 인기있는 stackoverflow의 대답입니다.

마이크로 서비스 아키텍처

마이크로 서비스 아키텍처는 서비스 지향 디자인의 “제 3의 물결”입니다.

마이크로 서비스 아키텍처는 서비스 지향 설계의 “세 번째 물결”에 불과합니다.

어디서 왔나요?

90년대 중반, “COM+”(컴포넌트 서비스) 및 SOAP은 작은 컴포넌트로 분할하여 배포 위험을 줄여 인기가 있었습니다. - 프로세스 경계를 넘어서 이야기하는 표준적이고 비교적 간단한 방법을 제공

이로 인해 분산 시스템을 위한 “3-tier” 와 이후의 “n-tier” 아키텍처가 대중화 되었습니다.

N-Tier는 실제로 “데이터 계층, 비즈니스 로직 계층 및 프레젠테이션 계층 분리”의 약어입니다. 이것은 일부 사람들에게 효과적이지만 시스템 전체의 수평 슬라이스는 전체 변경을 마치기 위해 모든 “tier”를 변경해야하기 때문에 문제가 발생했습니다. 이 파급 효과는 신뢰성에 좋지 않습니다.

그 후 제품 공급업체가 참여하고 SOAP는 복잡하고 유행에 뒤쳐졌으며 사람들은 이로 인해 사람들은 “제2의 물결”을 향해 나아갔습니다. - 게릴라(Guerrilla) SOA. 비슷한 디자인, 격식 없는, 더 완벽한 수직 슬라이스, 적은 공급 업체 미들웨어.

이로 인해 Netflix가 대기 시간과 내결함성 시스템을 위한 플랫폼 인 hystrix를 홍보 할 때와 같이 더 작고 더 민첩한 서비스가 확산되었습니다.

마이크로 서비스 아키텍처 (James Lewis와 Martin Fowler에 의해)브랜드 SOA의 세 번째 물결(third wave)은 매우 인기 있지만 아마도 잘 이해되지 않을겁니다.

마이크로 서비스의 특징 : 작다, 독립적으로 유용하게 사용, 독립적으로 버전 전환 가능, 특정 도메인 기능 또는 작업을 실행하는 독립적으로 운송(shippable) 가능한 서비스

마이크로 서비스가 자주하는 것 : 취성(Brittle), 상호 의존적 HTTP를 통해 데이터 액세스 객체로 작용하는 근시안적인 서비스, 종종 유행처럼 도미노로 실패한다.

좋은 마이크로 서비스 디자인은 몇 가지 간단한 규칙을 따릅니다.

  • 데이터 중심이 아닌 역할(role)/오퍼레이션 기반
  • 항상 데이터 저장소를 소유
  • 외부 인터페이스 또는 메시지로 통신
  • 함께 변화하고 함께 의존하는 것은 실제로 같은 것입니다
  • 모든 서비스는 내결함성이 있으며 종속성의 중단에서 살아남을 수 있습니다.

이러한 특성을 나타내지 않는 마이크로 서비스는 비밀 분산된 단일체일 가능성이 높습니다. 괜찮습니다. 많은 사람들이 규모에 따라 분산 된 단일체를 운영하지만 어느 시점에서 고통을 느낄 것입니다.

6각형 아키텍처 (Hexagonal Architectures)

이제 이것은 “Real Architecture TM”처럼 들립니다!

Alistair Cockburn에서 정의한 “the ports and adapters” 패턴으로도 알려진 6각형 아키텍처는 “real application architecture” 어드바이스 중 하나입니다.

간단히 말해서 모든 논리, 비즈니스 규칙, 도메인 관련 사항들이 프레임워크, 종속성, 데이터 저장소, 메시지 버스, 리포지토리 또는 UI와 관련없는 형태로 존재해야 합니다.

모든 “외부 (outside stuff)”는 내부 모델에 “적용(adapted)”되고 필요할 때 주입됩니다.

정말 어떤 모습일까요? 모든 로직은 프레임워크 코드, 글루 또는 외부 데이터 파일, 모듈 또는 클래스에 있습니다.

왜? 웹 프레임 워크 나 일부 깨진(broken) API를 방해하지 않고 모든 것을 개별적으로 테스트 할 수 있음을 의미합니다. 응용 프로그램을 설계하는 안전한 방법은 이러한 모든 외부 문제를 논리에서 제거하는 것입니다.

“12 가지 요소 앱”으로 설명 된 두 번째, 매우 인기있는 접근 방식이 있습니다. - 대부분 동일한 설계 목표를 공유하며 몇 가지 규범적 규칙이 위에 추가된다.

Scaling

스케일링은 직접 시도하면 힘들기 때문에 절대 직접 시도하지 마십시오.

공급업체가 제공한 클라우드 추상화를 사용하여 Google 앱 엔진, Azure 웹 앱 또는 AWS Lambda와 같은 클라우드 추상화를 사용하여 오토스케일링 지원을 사용할 수 있습니다.

서버리스 스택에 API를 배치하십시오. 추상화가 많을수록 스케일링이 더 쉬워집니다.

“스케일아웃만이 비용 효율적”이라는 통설이 있지만, 성공한 많은 기업들이 소수의 대형 머신이나 VM을 통해 규모를 확장할 수 있었습니다. 스케일아웃은 다른 이점(흔히 지역 분산 관련 또는 가용성 영역 간 복원력)을 제공하지만 “더 많은 힘”이라는 레이블이 있는 유일한 보조 도구라면 나쁘지 않다.

분산 시스템의 아키텍처 패턴

분산 시스템을 구축하는 것은 하나의 앱을 구축하는 것보다 어렵습니다. 아무도 그렇게 많이 이야기하지 않지만, 그렇습니다. 모든 것을 작은 조각으로 나눌 때 실패하는 것이 훨씬 쉽지만 제대로 맞으면 완전히 다운 될 가능성은 적습니다.

항상 유용한 몇 가지가 있습니다.

어디에나 Circuit Breaker

서킷 브레이킹은 나가는 연결을 마치 전기 회로인 것처럼 모델링하는 유용한 분산 시스템 패턴입니다. 주어진 회로를 통한 호출 성공을 측정하여 호출이 실패하면 “퓨즈를 끊어”실패한 요청을 보내지 않고 아웃 바운드 요청을 큐잉합니다.

잠시 후 단일 요청이 회로를 통해 흐르도록하고 ( “반 열림”상태) 성공하면 회로를 다시 “닫고”대기 된 모든 요청을 흐르게합니다.

Circuit Breaker는 사용자가 알고 있을 때 실패하지 않도록하기 위한 놀라운 방법입니다. 당신의 부름(call)으로 어려움을 겪고있는 서비스를 보호합니다.

호출하는 API를 소유하고 있음을 알게되면 Circuit Breaker에 더욱 감사할 것입니다.

멱등성과 재시도 (Idempotency and Retries)

모든 Circuit Breaker의 무료 디자인 패턴 – 모든 아웃 바운드 연결을 재시도 정책으로 마무리하고 백 오프(back-off)해야 합니다.

이것은 무엇을 의미합니까? 이중 제출의 경우(멱등성) 호출을 비파괴(non-destructive)로 디자인 해야 하며 오류에 대해 다시 시도하도록 구성된 호출이 있는 경우 반복적으로 오류가 발생할 때 조금(기하급수 적으로) 백오프(backoff) 해야 합니다. - 최소한의 복구 시간을 요구하는 것을 제공합니다.

격벽 (Bulkheads)

격벽은 잠수함의 물리적 격벽에서 영감을 얻었습니다. 잠수함 선체의 일부가 손상되면 격벽이 닫히고 잠수함의 나머지 부분이 침수되지 않습니다. 꽤 멋진 비유이며 격리에 관한 것입니다.

예약된 리소스, 용량 또는 물리적 하드웨어는 소프트웨어의 일부에 대해 보호될 수 있으므로 시스템의 한 부분의 중단이 다른 부분으로 번질 수 없도록 할 수 있습니다.

멀티 스레드 시스템의 특정 호출에 대해 최대 동시성 제한을 설정하고 시간 제한 (타임아웃에 더 나은, 잠금 및 fall over)을 신중하게 사용하며 중요한 비즈니스 기능 (체크 아웃 또는 지불)을 위해 하드웨어 또는 용량을 예약 할 수도 있습니다.

replay/message 로그가 있는 이벤트 중심 아키텍처

이벤트/메시지 기반 아키텍처는 설계에 대한 인바운드 호출이 동기적이지 않기 때문에 탄력적입니다. 큐에 버퍼링 된 이벤트를 사용하면 시스템은 특별한 고려없이 중단, 확장 및 축소, 롤링 업그레이드를 지원할 수 있습니다. 정상적인 작동 모드는 “큐에서 읽기”이며 예외적인 상황에서는 변경되지 않습니다.

여러 프로세서가 대기열에서 메시지를 소비하기 위해 경쟁하는 경쟁 컨슈머 패턴(competing consumers pattern)과 결합하면 - 여러 프로세서가 큐에서 메시지를 소비하기 위해 경쟁하는 경우 - 큐 및 이벤트 중심 아키텍처로 좋은 성능을 위해 쉽게 확장 할 수 있습니다.

이를 위해 Kubernetes가 필요한가요?

아니요. 아마도 Google과 같은 종류의 확장 문제가 없을 것입니다.

도커와 컨테이너의 대중화로 인해 IaaS(Infrastructure-as-a-Service)에 대한 “거의 플랫폼과 같은” 추상화를 제공하는 것들에 많은 과대 광고가 있습니다. 이것들은 모두 매우 비싸고 힘든 일입니다.

어떤식으로든 관리 할 수 있다면 가능한한 순수한 관리 플랫폼에 가장 가까운 것을 사용하십시오. Azure App Services, Google App Engine 및 AWS Lambda는 프로그래머로서 생산성 향상에 도움이됩니다. 프로덕션 환경에서 보다 쉽게 운영 할 수 있으며 더 설명과 지원 됩니다.

Kubernetes (종종 자극적으로 k8s로 약식, 그것은 투구 같은 esoterically 명명 된 추가의 멋진 생태계와 함께, 그리고 플럭스)는 풀 타임 운영팀을 운영해야하며 심지어 EKS/AKS/GKS의 “관리 공급 업체 모드”에서도 학습 곡선이 필요합니다. 대안보다 훨씬 가파릅니다.

Heroku? App Services? App Engine? 이것들은 몇 분에서 몇 시간 만에 직접 제작할 수있는 것들입니다.

다양한 곳에서 Kubernetes를 사용하여 “클라우드 중립(Cloud neutral)” 솔루션으로 추진해야 한다는 압박감을 볼 수 있습니다. – 하지만 snake oil입니다. 클라우드 중립적이라는 것은 클라우드 공급업체를 전환하는 (예외적으로 드문) 시나리오가 아니라 클라우드 마이그레이션 비용(추상화 유지, 유용한 공급업체 특정 기능으로부터 의문의 이동 을 격리)을 영구적으로 지불하는 것을 의미합니다.

기술의 책임있는 사용에는 문제에 가장 적합한 것을 사용하고 규모를 확장하는 것이 포함됩니다.

합리적인 권장 사항

항상 가능한 가장 간단한 일을 하세요. 아키텍처는 모든 추상적 개념처럼 비용이 듭니다.

대부분의 경우 가장 좋은 아키텍처는 가장 간단하고 가장 유연하게 변경할 수 있습니다.