당신은 주제를 찾고 있습니까 “웹 아키텍처 – 스프링 5 기초 강의 4-1강 웹 아키텍처의 이해“? 다음 카테고리의 웹사이트 ppa.maxfit.vn 에서 귀하의 모든 질문에 답변해 드립니다: https://ppa.maxfit.vn/blog/. 바로 아래에서 답을 찾을 수 있습니다. 작성자 나무소리 이(가) 작성한 기사에는 조회수 451회 및 좋아요 13개 개의 좋아요가 있습니다.
웹 아키텍처 주제에 대한 동영상 보기
여기에서 이 주제에 대한 비디오를 시청하십시오. 주의 깊게 살펴보고 읽고 있는 내용에 대한 피드백을 제공하세요!
d여기에서 스프링 5 기초 강의 4-1강 웹 아키텍처의 이해 – 웹 아키텍처 주제에 대한 세부정보를 참조하세요
📒 Spring 프레임워크를 이용한 웹 프로그램 개발을 위한 기본 개념을 학습하는 강의 입니다. 웹 프레임워크의 기본 아키텍처에 대해서 학습합니다.
#스프링강좌 #스프링프로그래밍입문 #웹아키텍처 #SpringMVC
웹 아키텍처 주제에 대한 자세한 내용은 여기를 참조하세요.
신입 웹 개발자일 때 알았더라면 좋았을 기본 웹 아키텍처 개념
모던 웹 애플리케이션 아키텍쳐 개요. 위의 다이어그램은 우리 Storyblocks의 아키텍쳐를 꽤 잘 나타낸다. 당신이 경험 많은 웹 개발자가 아니라면 아마도 꽤 복잡 …
Source: kschoi.github.io
Date Published: 5/8/2021
View: 9934
웹 애플리케이션 아키텍쳐 기본 개념 – 클립소프트
작성자 : 조성철 차장. Web Application Architecture 기본 개념. web. 웹(Web) 기반 프로젝트를 수행하면서 그 구조에 대한 기본 지식이 없는 경우 엉뚱한 실수를 범 …
Source: clipsoft.co.kr
Date Published: 6/30/2021
View: 4384
웹 아키텍처의 구성 요소와 구조 – Medium
웹 아키텍처의 구성 요소와 구조. 구성 요소. 웹 브라우저 (클라이언트); 웹 서버; 웹 애플리케이션 서버 (WAS); DB 서버. 웹 브라우저.
Source: medium.com
Date Published: 5/1/2022
View: 7393
알아놓으면 좋은 10가지 모던 웹 아키텍쳐 컨셉 – Seonest
Modern web application architecture는 모든 개발자들이 알아야만 하는 클라우드 컴퓨팅 구성 요소가 있습니다. 저자는 Netflix, Medium, Airbnb, …
Source: www.seonest.net
Date Published: 6/10/2022
View: 1529
웹서비스 아키텍처 정리 – 온라인쇼핑 IT
웹어플리케이션 아키텍처. 사용자가 웹브라우저에서 www.nsmall.com 을 입력하면. 1. DNS (Domain Name System) : 인터넷 도메인으로 서버 IP 를 찾아 …
Source: skyksit.tistory.com
Date Published: 7/30/2022
View: 8062
웹 아키텍처 101 – 언어 감각 기르기
웹 개발자 일을 시작할 때 미리 알고 있었다면 좋았을 기본적인 웹 아키텍처 개념들. – 원문: https://engineering.veoblocks.com/web-architecture-101 …
Source: serisepomme.tistory.com
Date Published: 10/17/2022
View: 1021
웹서비스 백엔드 애플리케이션 아키텍처(1)-클린아키텍처 – 브런치
1. 클린 아키텍처 적용한 스프링 기반 애플리케이션 구축 | 제 글을 읽지 마세요! 최근에 나온 “만들면서 배우는 클린 아키텍처” 라는 책을 읽어 …
Source: brunch.co.kr
Date Published: 7/23/2021
View: 5856
웹 애플리케이션 아키텍처의 특징 – velog
[Web] 웹 애플리케이션 아키텍처의 특징. … 클라이언트와의 통신은 웹 서버가 전담 -> 네트워크 및 멀티 스레드 프로그래밍으로부터 탈출 …Source: velog.io
Date Published: 7/27/2022
View: 2605
주제와 관련된 이미지 웹 아키텍처
주제와 관련된 더 많은 사진을 참조하십시오 스프링 5 기초 강의 4-1강 웹 아키텍처의 이해. 댓글에서 더 많은 관련 이미지를 보거나 필요한 경우 더 많은 관련 기사를 볼 수 있습니다.

주제에 대한 기사 평가 웹 아키텍처
- Author: 나무소리
- Views: 조회수 451회
- Likes: 좋아요 13개
- Date Published: 2022. 1. 17.
- Video Url link: https://www.youtube.com/watch?v=MZ_4QoeD5MA
신입 웹 개발자일 때 알았더라면 좋았을 기본 웹 아키텍처 개념
신입 웹 개발자일 때 알았더라면 좋았을 기본 웹 아키텍처 개념
이 글은 미디엄의 Web Archtecture 101(https://engineering.videoblocks.com/web-architecture-101-a3224e126947) 글을 보기 쉽게 번역한 글입니다. Storyblocks라는 웹 서비스의 구성을 통해 입문자 관점에서 모던 웹 아키텍처를 설명해주고 있습니다.
모던 웹 애플리케이션 아키텍쳐 개요
위의 다이어그램은 우리 Storyblocks의 아키텍쳐를 꽤 잘 나타낸다. 당신이 경험 많은 웹 개발자가 아니라면 아마도 꽤 복잡하다고 생각할 것이다. 각각의 컴포넌트를 자세히 살펴보기 전에 아래의 예시를 살펴보면 조금 더 다가서기 쉬워질 것이다.
예시
사용자가 구글에서 “Strong Beautiful Fog And Sunbeams In The Forest”을 검색한다. 첫번째 검색 결과에 Storyblocks 사이트의 stock 사진이 함께 노출된다. 사용자는 결과를 클릭하고 브라우저는 이미지 상세 페이지로 이동한다. 보이지 않지만, 브라우저 내부에서는 DNS 서버에 Storyblocks 사이트에 어떻게 접속할 수 있는지 물어본 후 Storyblocks에 접근을 시도한다.
브라우저 요청은 Storyblocks 측의 로드 밸런서에 도착하고, 서비스를 운영하기 위해 동작 중인 10여 개의 서버 중 하나를 랜덤하게 선택해서 요청을 처리한다. 웹 서버는 캐싱 서비스에서 필요한 이미지 정보를 가져온 후 더 필요한 정보는 데이터베이스에 요청한다. 사용자에게 전달한 이미지의 컬러 프로필이 아직 만들어지지 않았음을 인지한 후 “컬러 프로필” 잡(job)을 잡 큐에 보낸다. 잡 서버는 큐에 추가된 것들을 비동기적으로 처리한 후 데이터베이스에 결과를 적절히 업데이트한다.
다음, 우리는 전체 텍스트(full-text) 검색 서비스에 사진의 제목을 전달해서 비슷한 사진들을 찾으려고 한다. 사용자가 Storyblocks의 멤버로 로그인했다면 그의 계정 정보를 계정 서비스에서 가져온다. 일련의 작업들이 끝난 후, 데이터 firehose에 페이지 뷰 이벤트를 발생시켜서 우리의 클라우드 스토리지 시스템에 기록하고, 그 정보는 분석가들이 비즈니스와 관련된 질의에 답하는 데 사용할 수 있도록 데이터 저장소(warehouse)에서 사용된다.
서버는 이제 HTML로 화면을 렌더링한 후 로드 밸런서를 통해서 사용자의 브라우저로 보낸다. 페이지는 CDN에 연결된 우리의 클라우드 스토리지 시스템에서 가져오는 자바스크립트와 CSS 파일을 포함하고 있다. 그래서 브라우저는 그 콘텐츠를 가져오기 위해 CDN에 접속한다. 마지막으로, 브라우저는 사용자가 볼 수 있는 콘텐츠를 렌더링한다.
이제 나는 각각의 컴포넌트들을 하나씩 소개할 것이다. 이는 당신이 앞으로 웹 아키텍쳐에 대해 생각해 볼 때 도움이 될 수 있는 좋은 심리 모델을 선사할 것이다. 나중에는 다른 시리즈의 글을 통해서 Storyblocks에서 얻은 경험을 바탕으로 추천하는 구체적인 구현 방법을 제공할 생각이다.
1. DNS
DNS는 “Domain Name Server”의 약자며 월드 와이드 웹(WWW)이 가능하도록 만드는 기반 기술이다. 가장 기본적인 레벨의 DNS는 도메인 이름(예. google.com)에서 IP 주소(예. 85.129.83.120)로의 키/값 조회를 제공한다. 이는 당신의 컴퓨터가 알맞은 서버에 요청을 보낼 수 있는 경로를 찾는 데 필요하다. 전화번호에 비유하자면 도메인 이름과 IP 주소의 차이는 “Jone Does에게 전화하기”와 “201-867–5309에 전화하기”의 차이다. Jone의 전화번호를 찾기 위해 전화번호부가 필요한 것처럼 도메인에서 IP 주소를 찾기 위해서는 DNS가 필요하다. DNS를 인터넷의 전화번호부라고 생각하면 된다.
여기서 더 깊게 들어갈 수 있는 많은 내용이 있지만, 입문 수준의 소개에는 크게 중요하지 않기 때문에 이쯤에서 다음으로 넘어가도록 하자.
2. 로드 밸런서
로드 밸런싱에 대해 자세히 알아보기 전에, 한발 뒤로 물러나서 수평적 vs 수직적 애플리케이션 확장(scaling)에 관해서 얘기해보자. 이들은 어떤 의미이며 어떤 차이가 있는가? 간단히 StackOverflow의 답변에 따르면 수평적 확장은 더 많은 장치를 새로 추가하는 것이고, 수직적 확장은 이미 사용하고 있던 장치의 성능(예. CPU, RAM)을 높이는 것이다.
웹 개발을 한다면 당신은 아마 언제나 수평적 확장을 원하게 될 텐데, 그 이유는 간단히 말해 서비스 중단을 막기 위해서다. 서버는 언제든지 고장이 날 수 있다. 네트워크는 속도가 느려질 수 있다. 데이터 센터에 정전이 발생할 수도 있다. 1대 이상의 서버를 가짐으로써 이러한 상황에 대비할 수 있으며 서비스는 멈추지 않고 계속 제공된다. 달리 말하면 ‘오류 내성’이 생긴다. 두 번째로, 수평적 확장은 애플리케이션 백엔드(웹 서버, 데이터베이스, 서비스 X, 기타 등등)들을 각각 다른 서버에서 돌림으로서 서로가 최소한으로 결합할 수 있도록 한다. 마지막으로, 수직적 확장은 언젠가 한계에 부딪힌다. 세상에는 당신의 앱이 하는 일을 모두 처리할 수 있을 만큼 강력한 성능을 가진 컴퓨터는 없다. 전형적인 사례로 구글의 검색 플랫폼을 생각하면 된다. 물론 구글 검색은 매우 큰 규모지만 수직적 확장의 한계는 작은 회사에도 적용될 수 있다. Storyblocks를 예로 들자면 서비스를 위해 150에서 400개의 AWS EC2 인스턴스를 동시에 구동하고 있다. 이 정도 규모를 수직적 확장으로 가능하게 하려 한다면 무척 힘든 일이 될 것이다.
좋다, 이제 로드 밸런서로 돌아가자. 그들은 수평적 확장이 가능하도록 만드는 마술이다. 그들은 들어오는 요청을 복제/미러링 된 수많은 애플리케이션 서버 중의 하나로 연결하고 서버의 응답을 다시 클라이언트로 보낸다. 모든 서버는 특정 요청을 같은 방식으로 처리해야 하며, 로드 밸런서는 이들 서버에 과부하가 걸리지 않도록 들어오는 요청을 적절히 분배해주는 일을 한다.
그게 전부다. 개념적으로 로드 밸런서는 꽤 직관적이다. 그 이면은 확실히 복잡하지만 입문에서는 거기까지 들어갈 필요는 없다.
3. 웹 애플리케이션 서버
고수준의 웹 애플리케이션 서버는 상대적으로 설명하기 간단하다. 그들은 사용자의 요청이 들어오면 핵심 비즈니스 로직을 실행하고 그 결과를 HTML에 담아 브라우저로 보낸다. 이 일을 하기 위해서는 보통 데이터베이스, 캐싱 계층, 잡 큐, 검색 서비스, 기타 마이크로 서비스, 데이터/로그 큐(queue) 등 무척 다양한 백엔드 인프라와 데이터를 주고받아야 한다. 앞서 언급했듯 당신은 사용자의 요청을 처리하기 위해 최소 2번, 보통 그보다 많은 횟수로 로드 밸런서에 연결될 것이다.
앱 서버 구현은 특정 언어(Node.js, Ruby, PHP, Scala, Java, C# .NET, …)를 선택하고 그에 맞는 웹 MVC 프레임워크(Express for Node.js, Ruby on Rails, Play for Scala, Laravel for PHP, …).를 선택해야 한다는 사실을 알아야 한다. 하지만 이들 언어와 프레임워크에 대해 깊이 알아보는 것은 이 글의 범위를 뛰어넘는다.
4. 데이터베이스 서버
모든 모던 웹 애플리케이션은 정보를 저장하기 위해 한 개 이상의 데이터베이스를 사용한다. 데이터베이스는 데이터 구조를 정의하고, 새로운 데이터를 삽입하고, 데이터를 찾고, 데이터를 수정하거나 삭제하고, 데이터로 연산을 수행하는 등의 일을 한다. 대부분은 웹 앱 서버는 잡 서버의 역할을 하는 데이터베이스 서버와 직접 통신한다. 거기에 더해서 각각의 백엔드 서비스는 애플리케이션의 다른 영역과 분리된 자신만의 데이터베이스를 가지고 있을 수 있다.
나는 이 글에서 각각의 아키텍쳐 요소와 관련된 기술을 깊이 살펴보는 일을 가능한 삼가려 하지만, 데이터베이스의 다음 단계 주제를 얘기하지 않으면 당신에게 해가 될 것 같다. 그것은 SQL과 NoSQL이다.
SQL은 “Structured Query Language”의 약자이며, 1970년대에 더 많은 사람들이 사용할 수 있도록 관계형 데이터 세트 질의(query)의 표준으로 만들어졌다. SQL 데이터베이스는 공통 ID(보통 숫자를 사용)로 연결된 테이블에 데이터를 저장한다. 간단한 예제로 사용자의 과거 주소 정보를 저장하는 과정을 살펴보자. 아마 사용자의 아이디로 연결된 user와 useraddress라는 2개의 테이블을 사용할 것이다. 아래의 이미지를 보자. 두 테이블은 useradress 의 user_id 컬럼이 user의 id 컬럼을 참조하고 있는 외래 키(foreign key)이기에 연결된 것이다.
만약 SQL에 대해서 잘 알지 못한다면 나는 Khan Academy에서 찾을 수 있는 것같은 같은 튜토리얼을 공부하길 강력히 권한다. SQL은 모든 웹 개발에서 사용되기 때문에 애플리케이션을 제대로 설계하기 위해서는 최소한 기본은 알아야 한다.
NoSQL, “Non-SQL”의 약자인 이것은 대규모 웹 애플리케이션에 의해 생성되는 많은 양의 데이터를 처리하기 위해 등장한 최신 데이터베이스 기술의 집합이다(SQL에서 파생된 기술 대부분은 수평적 확장이 어려우며 특정 지점에 도달하면 수직적 확장만이 가능하다). NoSQL에 대해서 전혀 알지 못한다면 다음과 같은 고수준의 안내서와 함께 시작하길 추천한다.
나는 당신이 SQL은 반드시 공부해야 한다는 사실을 명심하고 있었으면 한다. 왜냐하면, 이 소프트웨어 업계는 NoSQL 데이터베이스조차도 SQL 인터페이스로 데이터를 조정하고 있기 때문이다. 아직은 SQL의 지배에서 벗어날 방법은 없다.
5. 캐싱 서비스
캐싱 서비스는 정보를 거의 O(1) 시간 안에 찾을 수 있는 단순한 키/값 데이터 저장소를 제공한다. 애플리케이션은 캐싱 서비스를 통해 자원이 많이 소모되는 연산의 결과를 다시 계산하지 않고 캐시에서 가져옴으로써 효율을 높인다. 애플리케이션은 데이터베이스의 쿼리 결과, 외부 서비스 호출 결과, 주어진 URL의 HTML 등을 캐시에 저장한다. 다음은 실무에서 사용되는 몇몇 예제다.
구글은 일반적인 검색어인 ‘dog’나 ‘Taylor Swift’를 사용한 검색을 매번 실행하기보다는 결과를 캐시 한다.
페이스북은 당신이 로그인할 때 포스트 데이터, 친구 목록 등 많은 데이터를 캐시 한다. 페이스북의 자세한 캐시 기술은 여기에서 읽어볼 수 있다.
Storyblocks는 React 서버 사이드 렌더링으로 생성된 HTML, 검색 결과, 검색어 입력 자동완성 결과 등을 캐시 한다.
가장 널리 사용되는 캐싱 서버 기술 2개는 Redis와 Memcache다. 나는 다른 포스트에서 이들에 대해 더 자세히 다룰 예정이다.
6. 잡 큐(job queue) & 서버
거의 모든 웹 애플리케이션은 사용자의 요청에 대한 응답과는 직접적인 관련이 없는 작업을 백그라운드에서 비동기적으로 실행할 필요가 있다. 예를 들어 구글은 검색 결과를 얻기 위해 인터넷에서 데이터를 크롤링하고 인덱싱할 필요가 있다. 이는 당신이 검색을 요청할 때마다 실행되지 않으며 구글의 검색 엔진은 비동기적으로 웹을 크롤링하고 있다.
비동기적인 작업을 가능하게 하는 여러 가지 아키텍쳐가 있지만 가장 널리 사용되는 것은 “잡 큐” 아키텍처다. 이는 2개의 컴포넌트로 구성된다. “잡”으로 이루어진 큐, 그리고 큐에 들어있는 잡을 실행하는 1개 이상의 잡 서버가 그것이다.
잡 큐는 비동기적으로 실행될 잡 목록을 저장하고 있다. 대부분 애플리케이션이 결국에는 우선순위가 적용된 큐가 필요하게 되지만 가장 단순한 것은 first-in-first-out(FIFO) 큐다. 앱이 정기적인 일정이나 사용자에 의해 발생한 잡을 실행할 필요가 생기면, 그에 알맞은 잡을 큐에 추가하기만 하면 된다.
Storyblocks를 예로 들자면, 우리의 마켓플레이스를 지원하는 데 필요한 내부 작업에 잡 큐를 사용해서 힘을 실어주고 있다. 잡 큐를 통해 영상과 사진을 인코딩하고, 메타데이터 태그를 붙이기 위해 CSV를 처리하고, 사용자 통계를 취합하고, 비밀번호 재설정을 위한 이메일을 전송하는 등의 일을 한다. 우리는 간단한 FIFO 큐로부터 시작했지만 빠른 처리 속도가 중요한 민감한 비밀번호 재설정과 같은 작업을 위해 우선순위 큐로 업그레이드하게 되었다.
잡 서버는 잡을 처리 한다. 그들은 잡 큐를 가져와서 할 일이 있는지 확인하고, 있다면 큐에서 잡을 뽑아내서 실행한다. 잡 서버로 사용할 수 있는 언어와 프레임워크는 너무나 다양해서 이 글에서는 자세히 다루지 않겠다.
7. 전체 텍스트 검색 서비스
대부분은 아니지만 많은 웹 앱이 사용자가 텍스트 입력(보통 ‘쿼리’라고 불리는)을 입력을 하면 검색을 하고 가장 ‘관련 있는’ 결과를 보여주는 기능을 제공한다. 이 기능을 가능하게 하는 것은 보통 “전체 텍스트 검색”이라고 불린다. 전체 텍스트 검색은 쿼리 키워드를 포함하는 문서를 빠르게 찾기 위해 역 인덱스(inverted index)를 활용한다.
3개의 문서의 제목이 어떻게 역 인덱스로 변환되어서 특정 키워드를 포함한 제목을 가진 문서를 찾을 수 있도록 활용하는지를 보여주는 예제다. 보통 ‘in’, ‘the’, ‘with’ 같은 일반적인 단어(stop 단어라고 불린다)는 역 인덱스에 포함되지 않음을 주의 깊게 보라.
어떤 데이터베이스에서는 전체 텍스트 검색을 바로 사용할 수 있지만(MySQL은 전체 텍스트 검색을 지원한다), 보통 역 인덱스를 연산하고 쿼리 인터페이스를 제공하는 “검색 서비스”를 분리해서 운영하는 사례가 많다. 오늘날 가장 인기 있는 전체 텍스트 검색 플랫폼은 Elasticsearch지만 Sphinx 또는 Apache Solr 같은 다른 선택지도 있다.
8. 서비스
앱이 특정 규모에 도달하면 별도의 애플리케이션으로 분리해서 운영하기 위핸 ‘서비스’가 생기게 된다. 외부에는 노출되지 않지만, 앱과 다른 서비스와는 연동된다. Storyblocks을 예로 들자면 몇 개의 운영, 계획 서비스를 하고 있다.
계정 서비스는 우리의 모든 사이트의 사용자 정보를 저장해서 교차 판매 기회를 더 쉽게 제공하고, 더 일관적인 사용자 경험을 가능하게 한다. 컨텐츠 서비스는 우리의 모든 비디오, 오디오, 이미지의 메타데이터를 저장한다. 또 콘텐츠 다운로드 인터페이스와 다운로드 이력을 보여주는 기능을 제공한다. 결제 서비스는 고객이 카드로 결제할 수 있는 인터페이스를 제공한다. HTML → PDF 서비스는 HTML을 PDF로 변환하는 간단한 인터페이스를 제공한다.
9. 데이터
오늘날, 기업은 데이터를 어떻게 다루느냐에 따라 살고 죽는다. 최근 거의 모든 앱은 특정 규모에 도달하면 데이터를 제어, 저장, 분석하기 위해 데이터 파이프라인을 사용한다. 전형적인 파이프라인은 3개의 주요 단계를 가진다.
앱은 보통 사용자 상호작용으로 발생한 데이터를 데이터 ‘firehose’라 불리는 곳으로 전달한다. 그것은 데이터를 받아들이고 처리할 수 있는 스트리밍 인터페이스를 제공한다. 가공되지 않은 원시 데이터는 변형되거나(transformed) 추가 정보와 함께(augmented) 다른 firehose로 전달된다. AWS Kinesis와 Kafka는 이러한 작업을 위한 대표적인 기술이다. 원시 데이터와 최종 데이터는 모두 클라우드 스토리지에 저장된다. AWS Kinesis는 원시 데이터를 AWS의 클라우드 스토리지(S3)에 저장할 수 있도록 매우 쉽게 사용할 수 있는 ‘firehose’로 불리는 설정을 제공한다. 변형/추가된 데이터는 종종 분석을 위해 데이터 웨어하우스(DW)에서 로드된다. 우리는 AWS Redshift를 사용한다. 큰 기업에서는 Oracle이나 기타 독점적인 웨어하우스 기술을 사용하고 있지만, 스타트업 업계에서는 RedShift를 많이 사용하고 있으며 점유율도 계속 오르고 있다. 만약 데이터가 충분히 축적되었다면 Hadoop같은 NoSQL MapReduce 기술이 분석을 위해 필요하게 될 것이다.
처음에 제시한 아키텍쳐 다이어그램에서는 빠진 단계가 있다. 데이터 웨어하우스에서 앱과 서비스에서 사용중인 데이터베이스에서 데이터를 불러오는 과정이다. 예를 들어 Storyblocks에서 우리는 VideoBlocks, AudioBlocks, Storyblocks, 계정 서비스, 그리고 컨트리뷰터 포털 데이터베이스를 매일 밤 Redshift로 불러온다. 이는 사용자 상호작용 이벤트 데이터와 핵심 비즈니스 데이터를 함께 둠으로써 우리의 분석가에게 총체적인 데이터 집합을 제공한다.
10. 클라우드 스토리지
AWS에 의하면 “클라우드 스토리지는 인터넷을 통해 데이터를 저장, 접근, 공유할 수 있는 단순하고 확장성 있는 방법”이다. 당신은 로컬 파일 시스템에 저장할 수 있는 거의 모든 것을 RESTful API를 사용해서 HTTP를 통해 클라우드에 저장하고 접근할 수 있다. 아마존의 S3는 현재로써는 가장 인기 있는 클라우드 스토리지이며 Storyblocks에서는 비디오, 사진, 오디오 데이터, CSS, 자바스크립트, 사용자 데이터 등을 저장하기 위해 S3에 크게 의존하고 있다.
11. CDN
CDN은 ‘Content Delivery Network’의 약자며 HTML, CSS, 자바스크립트, 이미지 같은 정적인 데이터를 웹을 통해 1개의 원본(origin) 서버를 사용하는 것보다 더 빠르게 제공하기 위한 기술이다. 이는 콘텐츠를 전 세계의 많은 ‘엣지(edge)’ 서버에 분산시킴으로써 동작한다. 그리고 사용자는 데이터를 원본 서버 대신 가장 가까운 엣지 서버에서 다운로드한다. 예를 들어 아래의 이미지처럼 스페인에 있는 사용자가 뉴욕에 있는 원본 서버의 웹페이지에 접근하면 정적인 데이터는 대서양을 가로지르는 매우 느린 HTTP 요청을 하는 대신 영국에 있는 CDN ‘엣지’ 서버에서 빠르게 가져오는 것이다.
CDN에 대한 더 자세한 안내는 이 글을 살펴보길 바란다. 일반적인 웹 앱은 CSS, 자바스크립트, 이미지, 비디오 및 다른 정적인 데이터를 제공하기 위해 항상 CDN을 사용해야 한다. 어떤 앱은 정적인 HTML 페이지를 제공할 때도 CDN을 사용하기도 한다.
맺음말
웹 아키텍쳐 입문은 여기서 끝이다. 이 글이 도움되었으면 좋겠다. 나는 강의를 통해 웹 아키텍쳐의 몇몇 컴포넌트를 깊이 있게 살펴보는 시리즈를 내후년 안에 제공하려 한다.
출처 : https://blog.rhostem.com/posts/2018-07-22-web-architecture-101
알아놓으면 좋은 10가지 모던 웹 아키텍쳐 컨셉
10 Must-Know Concepts of Modern Web Architecture 이 글에 대한 번역과 작은 제 생각들을 작성해보았습니다.
들어가면서
Tim Berners-Lee님이 WWW를 발명한 후로 약 30년 정도가 지났습니다.
급격하게 websites와 web application이 발전되면서 다양한 온라인 행동을 브라우저를 통해서 진행할 수 있게 되었습니다.
최근에는 물리적 서비스의 모든 형태가 Cloud ecosystem 으로 옮겨지기 시작했습니다.
Modern web application architecture는 모든 개발자들이 알아야만 하는 클라우드 컴퓨팅 구성 요소가 있습니다.
저자는 Netflix, Medium, Airbnb, Facebook과 같은 거대 기업들에 대해 연구하고 다음 모던 웹 아키텍쳐를 구성하는 10가지 구성 요소에 대해 설명합니다.
Server Client Microservice Cloud Function Load Balancer API Gateway Message Queue CDN Database Services
1. Server
서버는 개인 네트워크나 인터넷을 통해 한 가지 서비스(또는 여러 서비스들)을 제공하는 컴퓨터를 말합니다.
디바이스(클라이언트로 지칭되는)는 서버에 연결할 수 있으며 제공된 서비스를 다른 네트워크 Port를 통해서 받을 수 있습니다.
서버는 제공되는 서비스에 기반하여 일반적으로 이름이 붙여집니다.
예를 들어, 만약 80 포트로부터 HTTP request를 수신하는 서버는 web server라고 불리어집니다. 그 외 파일 서버, 메일 서버, 인증 서버, DB 서버, ap 서버 등이 있습니다.
요즘에는 가상 서버들은 베어메탈 서버 보다 더 유명합니다.
베어메탈 서버 : 가상화를 위한 하이퍼바이저 OS 없이 물리 서버를 그대로 제공하는 것. 다른 클라우드 사용자의 영향을 받지 않는 단독 서버를 사용하는 것입니다.
즉, 물리적 서버 그대로를 서비스 받는 서버 입니다.
클라우드 서비스 제공자들은 hypervisor와 가상화 소프트웨어를 사용함으로써 그들의 물리 하드웨어 위에 가상 머신을 생성합니다.
클라우드 서비스 provider 3대장과 그 가상 머신 서비스들은…
2. Client
클라이언트는 서비스나 리소스를 얻기위해 그것을 제공하는 서버에 연결되는 디바이스 입니다.
클라이언트는 컴퓨터, 웹사이트, 소프트웨어, 임베디드 시스템이 될 수 있습니다.
예를 들어, 웹사이트를 방문한다면 브라우저가 클라이언트가 되는 것입니다.
서버 이름을 붙이는 것과 유사하게 클라이언트도 그들이 사용하는 서비스에 따라 이름이 붙여집니다. 이메일 클라이언트, 웹 클라이언트, DB 클라이언트, Chat 클라이언트 등이 있습니다.
클라이언트-서버 모델에서 특정 유저에게 특정 서비스를 제공하는 인증과 같은 기술들이 들어가게 됩니다.
여기에는 2가지 클라이언트 타입이 있습니다:
thin client: 일반적인 SPA(Single Page Application)과 같이 서버에 전적으로 의존하는 클라이언트 입니다.
thick client: thin client와 다르게 서버에 의존하지 않습니다. 서버에 데이터를 유지하는 standalone 어플리케이션과 유사합니다.
3. Microservice
Microservice는 어플리케이션을 느슨하게 결합된 서비스의 모임으로 구조화하는 서비스 지향 아키텍쳐(SOA) 스타일의 일종인 소프트웨어 개발 기법입니다.
일반적인 Monolithic 클라이언트-서버 기반 시스템은 몇가지 단점이 있습니다.
Monolithic 시스템에서 발생되는 에러는 전체 시스템에 영향을 미칩니다. 그래서 유지보수 작업 자체가 문제가 될 수 있습니다.
여기서 이러한 연결고리들을 제거하고자 나온게 Microservice 패턴입니다.
Microservice 패턴은 거대한 Monolithic 시스템을 Microservice라고 불리는 작은 서비스들로 나누어 decompose 하는 것을 목표로 둡니다.
Microservice는 특정 프로세스를 담당하는 느슨하게 결합되고 독립된 서비스를 가리킵니다.
만약 사용자 관리 시스템을 개발한다면, 이 시스템의 Microservice은 사용자 등록 서비스, 보고서 생성, 결제 프로세스등이 있을 수 있습니다.
웹 기반 소프트웨어 시스템에서는 대부분의 Microservice는 가상 머신 또는 가상 컨테이너 내에서 동작하는 RESTful APIs 입니다.
4. Cloud Function
서버 관리에 대한 걱정은 줄이고 코드 실행과 컴퓨팅 시간에 집중 – ncloud 클라우드 Function 소개글
Microservice는 코드 복잡성이 증가되면 무거워지고 유지보수하기 어렵게 될 수 있습니다.
또한, 일반적으로 가상 머신이나 컨테이너에서 클라이언트 연결을 항상 기다리기 때문에 인프라 비용이 증가할 수 있습니다.
serverless 개념은 거대 시스템을 serverless function(aka cloud function)이라고 하는 유지관리 하기 쉽게 더 작은 기능으로 쪼개는 방법을 도입했습니다.
serverless는 서버가 없다는 뜻이 아닙니다. 관리해야 할 서버가 없다는 것을 말합니다.
cloud function은 요청이 들어올 때에 활성화 됩니다.
그렇지 않다면 cloud function은 hibernation(수면) 모드로 들어갑니다.
cloud function의 lifecycle은 각 클라우드 서비스 제공자에 의해 개발된 특정 서버에 의해 다루어집니다.
개인이나 스타트업 기업은 적은 인프라 비용 때문에 cloud function을 선택하기도 합니다.
5. Load Balancer
둘 혹은 셋 이상의 자원에게 작업을 나누는 것을 의미합니다.
– load balancing_위키
Web 아키텍쳐에서 로드 밸런서는 Web 트래픽을 가용성에 따라 다른 서버로 보내는 구성요소입니다.
로드 밸런서 타입에는 크게 2가지가 있습니다.
HLB(Hardware-based Load Balancer)
SLB(Software-based Load Balancer)
요즘엔 기본적으로 HLB가 비싸고 물리 서버가 필요하기 때문에 HLB보단 SLB가 더 선호됩니다.
현재는 거의 모든 클라우드 서비스 provider에서 서비스들 중에 잘 알려진 서비스형(as-a-service) 모델을 사용한 로드 밸런서를 통합하여 제공합니다.
6. API Gateway
Amazon API Gateway는 어떤 규모에서든 개발자가 API를 손쉽게 생성, 게시, 유지 관리, 모니터링 및 보안 유지할 수 있도록 하는 완전관리형 서비스입니다. – aws api gateway
Web 어플리케이션은 다수의 API를 가질 수 있습니다. 그리고 모든 API는 사용제한범위 를 벗어나는 사용으로부터 보호되어져야 합니다.
API Gateway는 다수 API들이나 다른 서비스들로 접근할 수 있는 single point를 제공합니다.(흡사 Load Balancer와 유사합니다. )
API Gateway는 모든 클라이언트 요청을 매핑된 서비스로 보냅니다. API 관리 시스템의 한 부분으로 제공되는 것이 일반적입니다.
(API 관리 시스템은 API를 관리할 수 있는 GUI를 제공합니다.)
API Gateway는 모니터링, 속도 제한, 사용율, 버전관리 등과 같은 통합된 다양한 서비스를 제공합니다.
대게 RESTful API와 함께 제공되지만 SOAP, GraphQL, gRPC, TCP 등도 지원합니다.
7. Message Queue
마이크로서비스로 제공된 아키텍쳐에서 각 서비스들 사이에 RESTful API나 메시지 큐를 이용해 통신합니다.
메시지 큐는 마이크로서비스 사이에 pub-sub 아키텍쳐를 가진 비동기 메시지 채널을 만듭니다.
메시지 큐는 동기식 RESTful 인터페이스에 비해 몇가지 이점이 있습니다.
예를 들어 만약 REST 요청이 실패했을 때, 클라이언트(또는 initiator)가 오류 처리에 대한 책임을 가져가야 합니다. 또한, 오류를 일으켰던 REST 메시지를 버리게 되며 아무 곳에도 저장하지 않습니다.
반면, 메시지 큐는 모든 메시지를 유지합니다.
그러므로 생산자가 메시지를 보낼 때 소비자가 실패한다면 소비자는 다시 시작될 때 특정 메시지를 pick up 할 수 있습니다.
이러한 이점은 트랜잭션 안정성이 높아야되는 아키텍쳐일 때 메시지 큐를 선택할 경우 이점이 될 수 있습니다.
kafka라는 잘 알져진 시스템이 있습니다. AWS에서는 SQS 라는 이름으로 제공합니다.
8. CDN
Content Delivery Network: 콘텐츠 전송 네트워크
CDN는 웹 어플리케이션의 성능, 가용성, 보안을 향상시키기 위해 정적 콘텐츠를 캐쉬하는 지리적으로 분산된 서버를 가리킵니다.
일반적으로 웹 어플리케이션은 다양한 리소스로 구성됩니다. 이미지, 비디오, CSS 파일, JS 파일, HTML 파일 등이 있습니다.
사용자들이 웹 어플리케이션을 방문할 때마다 각 사용자들의 브라우저는 서버로부터 리소스를 받을 것입니다.
만약 물리적으로 서버 위치와 멀리 있는 사용자가 방문한다면 페이지 로딩 시간이 증가할 것입니다.(상식적으로)
CDN은 전 세계에 있는 서버들에 정적 컨텐츠를 캐쉬합니다. 그리고 클라이언트와 더 가까운 위치에서 제공하도록 하여 빠르게 로드할 수 있게 해줍니다.
더욱이 CDN 캐싱 서버가 원래 서버에 대한 프록시 서버 역할을 하기 때문에 DDoS 공격을 방어하거나 완화할 수 있습니다.
AWS CloudFront data center locations
CloudFlare data center locations
9. Database
Database(DB)는 데이터 다양한 형태의 정보들을 저장하는 구성 요소 입니다.
Database 유형에는 크게 2가지 종류가 있고 세세하게 몇 가지 종류가 더 있습니다.
SQL: 전통적인 관계형 데이터베이스
No-SQL: SQL(전통적인 관계형 데이터베이스)이 아닌 비관계형 데이터 베이스 Key-Value Document Graph …
데이터베이스 서버는 클라이언트와 통신 할 때 각 데이터베이스마다 사용되는 커뮤니케이션 프로토콜을 사용합니다.
예를 들어, MySQL은 MySQL Protocol을 사용합니다.
웹 설계자는 실제 요구 사항에 따라 데이터베이스 타입을 결정해야 합니다.
예를 들어, 만약 unique ID에 기반한 많은 user session을 저장해야될 필요가 있을 경우 key-value 타입의 No SQL DB가 좋은 결정이 될 수 있습니다.
10. Services
Web 어플리케이션은 인증, emaling, loggin, 모니터링, 머신 러닝, 결제 등등과 같은 다른 서비스들을 요구합니다.
또한 Web 어플리케이션은 개발, 아키텍쳐, 배포 시스템, CI/CD, Database, 호스팅, CDN, Searching/Indexing 등등이 필요합니다.
많은 오픈 소스 프레임워크는 이러한 서비스에 대해서 충족합니다. 그러나 이러한 오픈 소스 서비스는 설치하기 위한 인프라도 같이 필요합니다.
최근에는 많은 기업들이 as-a-service 모델 형식의 클라우드 서비스를 제공합니다.
이러한 서비스들을 잘 찾고 잘 이용한다면 비용이나 많은 노력들을 줄일 수 있고 최신 기술들을 적용할 수 있습니다.
저 또한 그러고 있고, 이런 부분에 있어서 정보라던지 시야를 넓히고 있어야 될 것 같습니다.
마무리
요즘에는 다양한 곳에서 많은 클라우드 서비스들이 많습니다.
aws는 말할 것도 없이 이런 것들 조차 지원돼? 하는 것들도 많습니다.
최근에는 개발 플랫폼 조차 github codespace처럼 브라우저에서도 개발할 수 있는 상당한 수준들의 플랫폼들이 나오고 있습니다.
항상 시야를 열고 다양한 정보를 받아들일 마음을 가지는 게 중요한 것 같습니다.
이젠 모든 플랫폼에서 클라우드 시대라는 것을 실감하고 있는 나날들이 이어져 나가는 것 같습니다.
웹서비스 아키텍처 정리
목적
온라인 이커머스의 구조를 이해한다
Web Architecture 101 : https://engineering.videoblocks.com/web-architecture-101-a3224e126947
웹어플리케이션 아키텍처
사용자가 웹브라우저에서 www.nsmall.com 을 입력하면
1. DNS (Domain Name System) : 인터넷 도메인으로 서버 IP 를 찾아주는 시스템 www.nsmall.com => XXX.XXX.XXX.XXX
도메인으로 IP 찾는 법 – https://zetawiki.com/wiki/%EB%8F%84%EB%A9%94%EC%9D%B8%EB%AA%85%EC%9C%BC%EB%A1%9C_IP_%ED%99%95%EC%9D%B8
를 통해서 10층 IDC 에 있는 웹서버 외부 IP 를 찾아서 접속이 된다
기술 : IP4, IP6, CIDR, A, CNAME, TTL (Time To Live) 등
2. Load Balancer 는 여러 대의 웹서버로 서비스를 운영하기 위해서 트래픽을 분산시켜주는 역할을 한다
– 회사에서는 L4 장비를 사용한다 (L4 는 port 단위로 서비스를 찾아주고, L7 은 도메인의 method (/wiki , /jira ) 단위로 서비스를 찾아준다)
기술 : L4, L7, ALB, inbound, outbound, 보안그룹, SSL, TLS 등
3. Web app Servers 는 Web 서버와 WAS (web application server) 를 같이 표현을 했다
– Web 서버는 정적인 컨텐츠 ( js, css, image) 를 서비스하고 WAS 서버는 동적인 컨텐츠 ( jsp, java )를 서비스 한다
– Web 서버 : IBM HTTP (EC 웹서버), 이메일 (WebToB) , 푸시 (Apache), 제휴 (Apache)
– WAS 서버 : IBM WebSphere (EC 어플리케이션서버), 이메일 (Jeus) , 푸시 (Tomcat), 제휴 (Tomcat)
기술 : Nginx, Apache, WebToB, Tomcat, Jeus, HTTP, MQTT
4. Database 는 데이터를 저장하여 사용한다
– 쇼핑몰 메인 DB 로 Oracle , WCS 의 설정 DB 로 IBM DB2, 이메일 DB 로 MS-SQL , 푸시 DB 로 MySQL , 제휴 DB 로 PostgreSQL 을 사용한다
– NoSQL 로 AWS Dynamo DB (MongoDB 기반) 를 사용한다
기술 : RDB, NoSQL
5. Caching service 는 데이터를 가져오는 비용이 높기 때문에 동일한 데이터를 요청할 때 메모리로 저장하고 메모리에서 정보를 가져오는 방식을 사용한다
– WCS 에서 Caching 처리하는 서비스를 이용한다 (서버IP 별로 캐쉬관리하는 웹페이지가 있음)
– 푸시에서 Redis 를 사용
기술 : Redis, Memcached, RabbitMQ 등
6a. Job Queue 는 대량의 서비스를 여러대의 서비스들이 처리하기 위해서 중간 버퍼 역할을 해주는 기능
– 회사에서 사용하지 않는다. 비동기 처리를 안해서 처리성능이 안좋다
6b. Job Servers 는 Queue 에 적제된 작업을 처리하거나, Batch 업무를 처리하는 서버
– 제휴 Quartz 를 사용한다
7. Full text search service 는 정보를 찾는 속도를 증가시키기 위해서 사용하는 검색 서비스
– 플랫폼의 상품 검색서버
– 인프라의 Splunk : 인프라 자원 사용량 수집 및 검색
8. Services 는 도메인 서비스 를 나타낸다. 이커머스 서비스들 회원가입, 상품, 매장, 로그인, 주문, 결제, 반품, CS
– 회사의 비즈니스 로직들이 전부 해당됨
9a. Data firehose 는 대량의 데이터를 (수집, 저장, 처리, 분석) 중에 수집하기 위한 기능
9b. Data warehouse 는 대량의 데이터를 (수집, 저장, 처리, 분석) 중에 저장하기 위한 기능
9c. Copy of data는 데이터를 고객에게 제공하기 위해서 공유 저장소에 데이터를 전달 해주는 기능
10. Cloud Storage 는 데이터를 내부에만 가지고 있지 않고 고객에게 제공하여 활용하기 위한 공유저장소
– AWS S3 서비스
11. CDN 는 컨텐츠(image, data, video) 를 전국적으로 또는 전세계적으로 더 빠르게 서비스할 수 있도록 제공해주는 서비스
– 쇼핑몰만 KT CDN 을 사용하고 있음
필요에 따른 아키텍처 고도화 순서
만들 서비스를 생각하고 거기에 맞는 개발 언어 > 프레임워크 선택
1단계 – PC 에 개발환경 구성
JAVA 개발언어로 개발을 하겠다고 결정
Spring Framework 설치
Apache Tomcat 설치
MySQL 설치
WAS 서버 1개 구성, DB 서버 1개 구성
2단계 – 서비스별로 독립된 서버환경
웹서버, DB서버, 어플리케이션 서버 등 서비스의 역할별로 독립된 서버 환경 구성
3단계 – 안정성 확보를 위한 이중화 구성 (플랫폼시스템 현재위치)
서비스를 하고 있는 서버가 다운 될 경우를 대비하여
서버를 2대 이상으로 구성하고 서버별로 네트워크 트래픽을 분산시켜줄 로드발란서를 중간에 구성해준다
4단계 – 불규칙한 트래픽의 유입을 대비한 자동확장 구성 (제휴시스템 위치)
사용자의 유입에 따라서 자원이 자동 증설 되는 구조를 갖추어야 고객의 증가에도 서비스 안정성이 확보된다
자동 증설을 위해서는 서버들이 언제든 추가될 수 있게 이미지로 관리되어야 하고
서버 추가에 따른 네트워크도 자동 연결이 되어야 하고
서비스용 소스도 버전관리가 되어야 한다
자동확장/감소되는 서버들의 모니터링도 자동화 되어서 수집/분석 되어야 한다
인프라가 소프트웨어 형태로 전환되어야 한다
4-2단계 – 불규칙한 트래픽의 유입을 더 빠른 속도로 대응한다 (VM => Container)
기존의 서버 자원을 VM 단위에서 Container 단위로 변경하여 초단위의 생성/삭제를 할 수 있게 한다
5단계 – 대량의 트랜젝션을 처리할 수 있는 비동기 구성
대량의 트랜젝션을 처리하기 위해서는 동기적 처리에서 비동기적 처리로 변경해야 한다
Cache 와 Queue 를 적극 도입하여 데이터/Task 를 처리해야 하고
RDB 보다는 NoSQL 을 도입하고
무거운 Java WAS 보다 경량 WEB 서버로 전환한다
Java 가 Node 보다 5배 이상 무겁다 (메모리를 많이 쓰고 서버기동도 훨씬 느리다)
6단계 – 비즈니스 로직으로 집중한다
대량의 고객들에게 서비스를 할 수 있는 아키텍처를 운영하기 위해서는 수많은 기술에 대한 역량이 있어야 하는데
인적자원의 한계가 있으니 가장 중요한 비즈니스 로직으로 인적 자원의 역량을 집중한다
서버단위의 서비스에서 기능단위의 서비스로 분리 되어야 하고 => 마이크로 서비스
서버 관리를 없애고 비즈니스 로직에 집중하는 서비스 아키텍처로 변환 => 서버리스
서버리스 아키텍처 예제
서버리스 : 직방, 빙글 과 같은 스타트업은 전체 구조가 서버리스
숨어져 있는 서비스들의 구성을 알 수 있게 되었고
서버에 대한 증설/패치/인프라운영이 줄어들었고
2019년도에는
서버리스 펑션들의 Step 관리 기능들이 추가되어 서버리스 펑션들의 관리를 도식화 하여 관리할 수 있게 되었다
개발언어의 제약이 없어졌고
서버리스 펑션의 연관성에 대한 성능 추적 모니터링이 가능하게 되었다
점점 더 고도화 되고 많은 서비스를 고객에게 제공해줘야 하는데
기술은 어려워지고 있고
결국 기업은 기술력을 갖은 사람을 확보하는게 관건이 아닌가 싶다
웹 아키텍처 101
웹 개발자 일을 시작할 때 미리 알고 있었다면 좋았을
기본적인 웹 아키텍처 개념들
위 도표에 저희 Storyblocks 서비스에서 사용중인 아키텍처가 상당히 잘 표현되어 있습니다. 숙련된 웹 개발자가 아닌 이상 도표가 복잡하다고 느낄 수 있습니다. 아키텍처를 이루고 있는 컴포넌트를 하나하나 자세히 들여다 보기 전에, 아래의 내용을 먼저 읽어본다면 접근하기가 좀 더 쉬워질 것입니다.
한 사용자가 구글에 “숲에 내리쬐는 강렬하고도 아름다운 햇살과 안개”를 검색합니다. 맨 처음 나온 검색 결과는 우리의 선구적인 스톡 사진 및 벡터 그래픽 사이트인, Storyblocks 사이트에서 나온 결과입니다. 사용자가 검색 결과 링크를 클릭하면 브라우저가 이미지 상세 페이지로 리다이렉트 합니다. 그 내부를 들여다보면, 사용자의 브라우저는 DNS 서버에 Storyblocks와 접촉할 방법을 알아내기 위해 요청을 보내게 됩니다. 브라우저가 보낸 요청은 로드 밸런서(load balancer)가 받게 됩니다. 사이트를 운영하는 데 사용하는 웹 서버가 10개 있다면, 이 중 하나 정도를 로드 밸런서가 임의로 선택하여 요청을 처리하도록 일을 맡깁니다. 웹 서버는 캐싱 서비스에서 이미지에 관한 정보를 찾아보고 여기서 못찾은 나머지 정보는 데이터베이스에서 가져오는(fetch) 작업을 합니다. 이미지 컬러 프로파일 계산 작업이 아직 끝나지 않았기 때문에, “컬러 프로파일” job을 job 큐에 보냅니다. 그러면 job 서버가 비동기로 큐에 들어있는 작업을 실행하여 받아온 결과를 가지고 데이터베이스를 알맞게 업데이트 합니다. 그 다음에 사용자는 이와 비슷한 사진을 더 찾아보려고, 검색 결과로 받아 본 사진의 제목을 입력합니다. 이 요청은 전문 검색 서비스(full text search service)에 전달 됩니다. 검색을 하기 위해 사용자는 Storyblocks 사이트에 회원 로그인을 하려고 하기 때문에, 계정 서비스에서 이 사용자의 계정 정보를 찾아 보는 작업이 진행됩니다. 마지막으로, 페이지 뷰 이벤트가 클라우드 스토리지 시스템에 기록될 목적으로 데이터 firehose로 전송됩니다. 그리하여 최종적으로 데이터 warehouse에 적재됩니다. 이렇게 적재된 데이터는 분석가들이 비즈니스 관련 질문에 답할 때 도움이 됩니다. 이제 서버에서는 HTML로 뷰를 렌더링하여 사용자 브라우저로 되돌려 보내는데, 이 때 뷰는 로드 밸런서를 먼저 거쳐 지나갑니다. 뷰 페이지에는 자바스크립트와 CSS 에셋이 포함되어 있는데, 이 파일들은 클라우드 스토리지 시스템에 들어갈 것들입니다. 그런데 클라우드 스토리지 시스템은 CDN에 연결되어 있으므로, 사용자 브라우저는 콘텐츠를 받아오기 위해 CDN과 접촉해 봅니다. 마지막으로 브라우저는 사용자가 페이지를 볼 수 있도록 화면에 렌더링 해줍니다.
다음으로는 컴포넌트를 하나씩 살펴보며 각각의 컴포넌트에 대한 “101” 소개를 해드리겠습니다. 앞으로도 발전할 웹 아키텍처에 대한 이해를 도와줄 좋은 멘탈 모델을 마련할 기회가 될 겁니다. 차후에는 Storyblocks에서 재직하며 배운것들을 바탕으로 추천하는 상세 구현 방법에 대해 설명하는 글을 후에 연재해 보도록 하겠습니다.
1. DNS
DNS는 “Domain Name Server(도메인 네임 서버)”의 약자이며, 월드 와이드 웹이 가능하게끔 만들어주는 핵심 기술입니다. 가장 기본적인 내용을 말하자면, DNS는 도메인 이름(예: google.com)을 가지고 IP 주소(예: 85.129.83.120)를 찾아낼 수 있는 키/값 조회(lookup) 기능을 제공합니다. 여러분 컴퓨터가 요청을 특정 서버로 올바르게 라우팅 하려면 이 기능이 필요합니다. 전화번호에 비유해 보자면, 도메인 이름과 IP 주소의 차이는 “홍길동에게 전화하기”와 “201-867-5309로 전화하기”의 차이라고 할 수 있습니다. 지난날에는 홍길동에게 전화를 걸려면 전화번호 책에서 찾아 볼 필요가 있었듯이, 해당 도메인을 찾아 가려면 DNS에서 IP 주소를 조회해야 합니다. 이러한 특성 때문에 DNS를 인터넷 상의 전화번호부라고 생각하셔도 됩니다.
이것 말고도 DNS에 대해서 알아볼 사항이 아주 많지만 101 단계에서는 모르더라도 큰일 나지 않기 때문에 넘어가도록 하겠습니다.
2. 로드 밸런서
로드 밸런싱에 대해 자세히 알아보기 전에, 한발 물러나서 수평적(horizontal) 애플리케이션 확장과 수직적(vertical) 애플리케이션 확장에 대해 먼저 논의해 볼 필요가 있습니다. 이 둘의 개념은 뭐고, 차이는 뭘까요? 여기 이 스택오버플로우 포스트에 매우 간단하게 설명이 되어 있습니다. 이에 따르면, 수평적 확장은 리소스 풀에 기계(machine)를 더 추가함으로써 확장시키는 것임에 비해, “수직적” 확장은 현재 사용중인 기계에 힘(예: CPU, RAM)을 더 추가함으로써 확장시키는 것을 뜻합니다.
웹 개발에서는 무언가 망가지는 상황이 발생하더라도 이를 최대한 단순하게 유지하기 위해, (거의) 언제나 수평적 확장을 선택하기 마련입니다. 서버에서는 무작위로 충돌이 납니다. 네트워크 품질은 종종 저하됩니다. 때때로 데이터 센터 연결이 전부 끊기기도 합니다. 서버를 두 대 이상 마련해 둔다면 서버 정지 상황에 대한 대비책을 마련할 수 있기 때문에 애플리케이션이 계속 돌아가도록 만들 수 있습니다. 다르게 말하자면, 여러분의 앱은 “오류에 대해 관용적(fault tolerant)”입니다. 수평적 확장을 선택하는 두번째 이유는 애플리케이션 백엔드(웹 서버, 데이터베이스, 어쩌구 서비스 등등)를 이루는 각각의 부분들이 서로 최소한으로 엮여져 있도록 하기 위해서 입니다. 이를 위해 각 부분을 서로 다른 서버에서 운영하게 됩니다. 세상의 어떤 컴퓨터도 애플리케이션에서 발생하는 연산을 혼자 다 수행할 정도로 충분하게 크지 않습니다. 이에 대한 전형적인 예로는 구글의 검색 플랫폼을 들 수 있습니다. 비록 구글보다 더 작은 규모의 회사에 해당되는 이야기이기는 하지만요. Storyblocks를 예시로 들자면 언제나 150-400개의 AWS EC2 인스턴스가 돌아가고 있습니다. 여기서 사용하는 컴퓨팅 파워를 수직적인 확장을 통해 전부 제공하려면 상당한 도전이 될 것 같습니다.
좋아요, 로드 밸런서로 돌아가 봅시다. 로드 밸런서는 수평적인 확장이 가능하게끔 만들어주는 마법의 소스입니다. 들어오는 요청을 서로의 이미지를 복제, 혹은 반영(mirror)하고 있는 수 많은 애플리케이션 서버 중 하나로 라우팅 처리해 주며, 앱 서버의 응답을 클라이언트로 다시 전송해 줍니다. 웹 서버는 모두 요청을 동일한 방식으로 처리하기 때문에, 오직 신경써야 할 일은 서버 하나라도 과부하 되지 않도록 요청을 분산시키는 일입니다.
이게 전부입니다. 개념적으로 보면 로드 밸런서는 상당히 직관적입니다. 내부를 보면 복잡한 점은 반드시 있지만, 101 단계에서 살펴볼 볼 필요까지는 없습니다.
3. 웹 애플리케이션 서버
웹 애플리케이션 서버는 고수준에서 볼 때 상대적으로 쉽게 설명할 수 있습니다. 사용자의 요청을 처리하여 사용자 브라우저로 HTML을 되돌려 보내주는 핵심 비즈니스 로직이 웹 애플리케이션 서버에서 실행됩니다. 이를 위해 서버는 보통 다양한 백엔드 인프라(데이터베이스, 캐싱 레이어, job 큐, 검색 서비스, 기타 마이크로서비스, 데이터/로깅 큐 등등)와 소통을 합니다. 위에서 언급한 것처럼, 웹 애플리케이션 서버는 최소 두 대 이상, 그리고 많은 경우 두 대보다 많이 사용하게 됩니다. 또한 사용자 요청을 처리하기 위해 로드 밸런서에 연결해 둡니다.
웹 서버를 구현하려면 특정 언어(Node.js – 역: Node.js는 JS 런타임 플랫폼인데 원문에서 언어에 들어가 있네요, Ruby, PHP, Scala, Java, C# .NET 등등)와 해당 언어를 위한 웹 MVC 프레임워크(Express, Ruby On Rails, Play, Laravel 등등)를 선택해야 합니다. 그러나 이들 언어와 프레임워크에 대한 세부사항은 이 글의 범위 밖에 있으므로 다루지 않겠습니다.
4. 데이터베이스 서버
최신 웹 애플리케이션은 모두 데이터베이스를 하나 이상 사용하여 정보를 저장해 둡니다. 데이터베이스를 사용하면 여러분만의 데이터 구조를 정의해 둘 수 있고, 새로운 데이터를 넣을 수도 있으며, 기존 데이터를 찾아내거나 삭제, 혹은 업데이트 할 수 있습니다. 이 외에도 데이터를 가지고 연산을 수행하는 등의 일을 할 수 있습니다. 웹 앱 서버는 거의 대부분 데이터베이스와 직접적으로 교류하며, job 서버도 마찬가지 일 것입니다. 웹 앱 서버 말고 다른 백엔드 서비스 역시 다른 애플리케이션과 분리된 자신만의 데이터베이스를 가지고 있을 수 있습니다.
이 글에서는 아키텍처 컴포넌트를 하나씩 깊게 살펴보는 일은 피하고 있으므로, SQL과 NoSQL 데이터베이스 대한 자세한 설명 역시 생략하는 실례를 범하도록 하겠습니다.
SQL은 “Structured Query Lanauge(구조화 질의어)”를 뜻하며, 대중적으로 접근할 수 있는 관계형 데이터 세트 대한 표준 질의 방식을 제공하기 위해 1970년대에 고안되었습니다. SQL 데이터베이스에는 테이블로 데이터를 저장하여 공통 ID(보통 정수형)로 테이블을 서로 연결시켜 둡니다. 사용자의 주소 정보를 저장하는 간단한 예시를 같이 살펴보도록 하겠습니다. 두 개의 테이블이 있는데, 하나는 users이고 다른 하나는 users_addresses라고 부릅니다. 두 테이블은 사용자의 id로 연결되어 있습니다. 더 간단한 설명을 원하신다면 아래 그림을 참고해 주세요. user_addresses의 user_id 열이 users 테이블의 id 열에 대한 “외부 키”이기 때문에 두 테이블은 서로 연결되어 있습니다.
SQL에 대해 잘 모르신다면, 여기 칸 아카데미의 수업과 같은 튜토리얼을 찾아 보는 것을 강력히 추천드립니다. 웹 개발할 때 아주 흔하게 사용되기 때문에 제대로 애플리케이션을 설계하려면 최소한 기본이라도 알아 두고 싶어질 것입니다.
NoSQL은 “Non-SQL(비-구조화 질의어)”를 뜻하며, 대규모 웹 애플리케이션에서 발생할 수 있는 대용량의 데이터를 처리하기 위해 나온 새로운 데이터 기술 셋을 가르킬 때 사용합니다. (대부분의 SQL류 언어는 수평적 확장이 매우 어렵고 오직 특정 시점에서 수직적으로 확장할 수만 있습니다.) NoSQL에 대해 아는 것이 없다면 아래와 같이 고수준에서 바라보는 소개글부터 읽어 보는 것을 권합니다.
또 한가지 당부해 드리고 싶은 것은, 이 산업에서는 대체로 NoSQL 데이터베이스 조차 SQL 인터페이스에 기대고 있기 때문에 아직 SQL에 대해 모르신다면 정말 배워둘 필요가 있습니다. 요즘에는 배우지 않고 버티는 것이 거의 불가능합니다.
5. 캐싱 서비스
캐싱 서비스는 간단한 키/값 데이터 저장 공간을 제공해 주며, 이를 통해 거의 O(1) 시간만 들이고도 정보를 저장하거나 찾아볼 수 있습니다. 캐싱 서비스에는 보통 수행 비용이 많이 드는 계산 결과를 저장해 두기 때문에, 다음에 그 결과값이 필요할 때 다시 계산을 수행하는 대신 캐시에서 결과값을 가져올 수 있습니다. 캐시에는 데이터베이스 쿼리 결과값, 외부 서비스 호출값, 특정 URL에 대한 HTML을 비롯해 다양한 종류의 값을 저장해 둘 수 있습니다. 실생활에서 찾아볼 수 있는 예제를 몇가지 들자면 다음과 같습니다.
구글에서는 “개”와 “테일러 스위프트”와 같이 흔한 검색 쿼리 대한 결과값을 매번 다시 계산하는 대신 캐시해 둡니다.
페이스북에서는 여러분이 로그인 했을 때 보이는 포스트 데이터, 친구 데이터 등등 많은 데이터를 캐시해 둡니다. 페이스북의 캐싱 기술을 더 알아보고 싶다면 이 글 을 읽어보세요.
StoryBlocks에서는 서버 사이드 리액트 렌더링, 검색 결과, 증분 검색 결과 등에 대한 HTML 산출물을 캐시해 둡니다.
널리 사용되는 캐싱 서버 기술 두가지를 들자면 Redis와 Memcache가 있습니다. 이에 대해서는 다른 글에서 좀 더 알아보도록 하겠습니다.
6. Job 큐 & 서버
웹 애플리케이션을 만들다 보면, 사용자 요청 응답과 직접적으로 관련이 없는 몇가지 특정 업무는 대부분 뒤에서 비동기로 처리해야 합니다. 예를 들어, 구글에서는 검색 결과 반환을 하기 위해 인터넷 전체에 대한 크롤링 및 인덱싱 작업을 해야 합니다. 그러나 이 작업은 여러분이 구글에서 검색을 할 때마다 수행되는 일이 아닙니다. 대신, 웹 크롤링 작업을 비동기로 진행하고 동시에 검색 인덱스를 업데이트 합니다.
비동기 작업을 가능하게 만들어 주는 아키텍처가 몇가지 있는데, 이 중에 제가 “job 큐” 아키텍처라고 부르는 것이 가장 널리 쓰입니다. 이 아키텍처는 앞으로 실행될 예정인 “job”으로 이루어진 큐, 그리고 하나 이상의 job 서버(보통 “워커”라고 부릅니다), 이렇게 두가지 컴포넌트로 구성되어 있습니다.
Job 큐에는 비동기로 실행되어야 하는 job 목록을 저장해 둡니다. Job 큐의 가장 간단한 구조는 선입선출(FIFO, first-in-first-out) 큐이긴 한데, 결국 나중에 가서는 대부분의 애플리케이션에서 우선 순위 큐 시스템(priority queing system)과 비슷한 종류의 것을 사용할 필요가 생깁니다. 정규 스케쥴, 또는 사용자 액션에 의해 앱에서 job이 실행되어야 할 필요가 발생하게 되면, 해당 job이 큐에 추가됩니다.
예를 들어 Storyblocks 서비스에서는 job 큐의 힘을 빌려 마켓플레이스 지원에 필요한 많은 양의 뒷단 작업을 처리 하였습니다. job을 통해 비디오와 사진을 인코딩하고, 메타 태그 CSV를 처리하고, 사용자 통계 자료를 모았으며, 패스워드 재설정 이메일도 보내는 등의 일을 했습니다. 처음에는 간단한 FIFO 큐로 시작했으나, 패스워드 재설정 메일 전송과 같이 촌각을 다투는 작업을 최대한 빠르고 확실하게 완료하기 위해 나중엔 결국 우선순위 큐로 업그레이드 했습니다.
Job 서버는 job을 처리합니다. 할 일이 있는지 보기 위해 job 큐의 상태를 폴링해 보고, 일이 있다면 큐에서 job을 pop 해와서 실행합니다. Job 서버를 만드는 데 선택할 수 있는 언어와 프레임워크는 웹 서버를 만들 때 만큼 많이 있지만, 이 글에서 다루지는 않겠습니다.
7. 전문 검색 서비스
거의는 아니지만, 그래도 많은 수의 웹 앱이 사용자가 입력한 텍스트(종종 “쿼리”라고 부릅니다)를 가지고 가장 “관련성 높은” 결과를 검색해 돌려주는 기능이 있습니다. 이런 기능을 제공해 주는 기술을 보통 “전문 검색(full-text search)”이라고 부르는데, 역색인(inverted text)의 힘을 빌려 쿼리 키워드가 포함된 문서를 빠르게 찾아내는 기술입니다.
몇몇 데이터베이스에서는 자체적인 전문 검색 기능을 지원하지만(예: MySQL), 보통은 역색인에 대한 계산 및 저장 작업을 수행하고 쿼리 인터페이스를 제공해 주는 “검색 서비스”를 따로 구동 시킵니다. Sphinx나 Apache Solr와 같은 다른 옵션이 있기는 하나, 오늘날 가장 유명한 전문 검색 플랫폼은 Elasticsearch입니다.
8. 서비스
엡이 특정 규모에 도달하면, 특정 “서비스”들은 따로 떼어 내어 별도의 애플리케이션으로 돌려야 할 필요가 생길 수 있습니다. 이들 서비스는 외부로는 노출이 되지 않지만, 해당 앱과 그 앱의 다른 서비스와는 교류를 합니다. 예를 들어 Storyblocks에서는 계획적으로 운용하는 몇가지 서비스가 있습니다.
계정 서비스는 사이트 전체에 걸쳐 있는 사용자 데이터를 저장하는 일을 합니다. 덕분에 손쉽게 교체 판매(cross-sell) 기회를 포착할 수 있고, 좀 더 통합적인 사용자 경험을 만들어 낼 수 있습니다.
콘텐츠 서비스는 모든 비디오, 오디오, 이미지 콘텐츠에 대한 메타데이터를 저장하는 일을 합니다. 또한 콘텐츠 다운로드 및 다운로드 히스토리 열람용 인터페이스를 제공하기도 합니다.
결제 서비스는 고객용 신용카드 청구 인터페이스를 제공해 줍니다.
HTML → PDF 서비스는 HTML 문서를 받아 PDF 문서로 변환해 돌려주는 간단한 인터페이스를 제공해 줍니다.
9. 데이터
오늘날에는 데이터를 얼마나 잘 활용하는가에 회사의 사활이 걸려 있습니다. 최신 앱의 경우, 거의 모든 앱이 특정 규모에 도달하게 되면 데이터 파이프라인을 도입해 데이터를 모으고, 저장하고, 분석하는 일을 하게됩니다. 파이프라인은 일반적으로 세가지 주요 단계로 구성되어 있습니다.
앱이 일단 데이터(보통은 사용자 상호작용 이벤트에 대한 데이터)를 데이터 “firehose”에 보냅니다. 데이터 firehose는 데이터를 받아들여 처리하는 스트리밍 인터페이스를 제공해 줍니다. firehose는 보통 원시 데이터를 받아서 이를 변형하거나 증분하여 다른 firehose로 보내는 일을 합니다. 이 목적으로 가장 많이 사용하는 기술은 AWS Kinesis와 Kafka 두가지가 있습니다. 원시 데이터 및 변형/증분 완료된 최종 데이터는 클라우드 스토리지에 저장됩니다. AWS Kinesis는 “firehose”라는 세팅을 제공해 주는데, 이를 사용하면 원시 데이터를 클라우드 스토리지(S3)으로 저장하는 작업 설정을 매우 쉽게 할 수 있습니다. 변형/증분된 데이터는 분석용으로 데이터 웨어하우스에 적재되는 경우가 종종 있습니다. 스타트업 업계에서 많이들 그러듯이 저희는 AWS Redshift를 사용했는데, 대기업에서는 Oracle이나 기타 독점적인 웨어하우스 기술을 자주 사용하기도 합니다. 데이터 셋의 크기가 충분히 크다면, Hadoop 같은 NoSQL 맵리듀스 기술이 분석에 필요할 수도 있습니다.
아키텍처 다이어그램에 그리지는 않았으나 또 다른 단계가 있는데, 바로 앱이나 서비스 운영 데이터베이스에서 데이터를 불러와 데이터 웨어하우스에 저장하는 작업입니다. 예시를 들자면 Storyblocks에서는 VideoBlocks, AudioBlocks, Storyblocks, 계정 서비스 및 contributor portal 데이터베이스를 Redshift로 매일 밤 불러옵니다. 분석가는 이 덕분에 핵심 비즈니스 데이터와 사용자 상호작용 이벤트 데이터를 같이 놓고 볼 수 있는 통합적인 데이터셋을 제공 받을 수 있습니다.
10. 클라우드 스토리지
AWS에 따르면, “클라우드 스토리지는 데이터를 저장하고, 접근하고, 인터넷 상에 공유할 수 있는 간단하면서 확장성을 갖춘 수단입니다”. 로컬 파일 시스템에 저장하는 파일은 거의 모두 HTTP RESTful API를 통해 클라우드 스토리지에 저장할 수 있고, 이에 접근할 수도 있습니다. 아마존의 S3 서비스는 클라우드 스토리지 서비스 중 아직까지는 가장 대중적인 서비스이며, Storyblocks에서도 비디오, 사진, 오디오 에셋, CSS, 자바스크립트 파일, 사용자 이벤트 데이터 등등을 저장하는 용도로 폭넓게 사용하고 있습니다.
11. CDN
CDN은 “Content Delivery Network(콘텐츠 전송 네트워크)”를 뜻하며 정적인 HTML, CSS, 자바스크립트, 이미지 파일 에셋을 단일 원천 서버에서 제공할 때보다 더 빠른 속도로 제공해주는 기술입니다. 전세계에 퍼져 있는 수많은 “엣지” 서버에 콘텐츠를 배분해 두기 때문에 사용자는 원천 서버가 아닌 “엣지” 서버에서 에셋을 다운로드하게 됩니다. 예를 들어 아래 이미지를 보면, 스페인에 사는 사용자가 원천 서버가 뉴욕에 있는 사이트에서 웹 페이지를 요청합니다. 그러나 페이지에 들어가는 정적 에셋은 영국에 있는 CDN “엣지” 서버에서 불러오기 때문에, 대서양을 가로지르는 HTTP 요청 횟수를 많이 줄일 수 있습니다.
좀 더 세세한 개론을 원한다면 이 글을 읽어 보세요. 보통 웹 앱은 CSS, 자바스크립트, 이미지, 비디오 및 기타 에셋 전송 용도로 CDN을 항상 사용해야 합니다. 정적인 HTML 페이지 전송할 때도 사용할 수 있습니다.
마치며
이제 웹 아키텍쳐 101 막을 내리도록 하겠습니다. 여러분께 이 글이 유용하기를 바랍니다. 내년이나 내후년 쯤에 기회가 된다면 여기서 설명한 컴포넌트 중 몇가지를 추려 자세하게 알아보는 201 시리즈 글을 연재하도록 하겠습니다.
웹서비스 백엔드 애플리케이션 아키텍처(1)-클린아키텍처
제 글을 읽지 마세요!
최근에 나온
“만들면서 배우는 클린 아키텍처” 라는 책을 읽어보시길 바랍니다. ^^
http://www.yes24.com/Product/Goods/105138479
“웹서비스 백엔드 애플리케이션 아키텍처”라는 주제로 글을 작성해서 공유합니다. 아키텍처에 대한 필자의 지극히 개인적인 생각을 정리하였습니다. 댓글로 피드백 해주시면 서로 배워가는 좋은 기회가 될 것 같습니다.
“웹서비스 백엔드 애플리케이션 아키텍처”
목차
1. 클린 아키텍처를 적용한 스프링 기반 애플리케이션 구축(이번 글)
2. 대용량 트래픽을 위한 백엔드 애플리케이션 캐싱 전략
3. 미정
글을 작성하면서
“클린 아키텍처”는 “로버트 C 마틴”의 소프트웨어 아키텍처 이론이다. 작년에 필자가 해당 원서를 읽고 서평을 작성했었다. 필자의 서평을 한번 읽어보고, 관심이 있는 개발자는 원서를 구매해서 보기를 추천한다.
https://brunch.co.kr/@springboot/130
이 글은, 클린 아키텍처 이론을 참고해서, 웹서비스 백엔드 애플리케이션 아키텍처에 대해서 이야기하는 글이다. 하지만, 필자가 영어 실력이 많이 부족해서, 원서의 내용을 100% 이해하지 못했고, 원서 내용을 필자의 시각으로 재해석했다. 필자의 이 글은, 평범한 개발자의 개인 의견일 뿐이다. 이 글에서 설명하는 내용이 “로버트 C. 마틴”이 주장하는 아키텍처 이론과 100% 일치하지 않을 수 있다는 점을 이해해주기를 바란다. 아키텍처에는 정답이 없다. 비즈니스 도메인 특성에 맞는 가장 적합한 아키텍처를 구축하는 것이 중요하다. 특정 아키텍처가 항상 정답이다 라고 말하고 싶지는 않고, 클린 아키텍처 역시 항상 정답이 아니라는 것을 생각하고, 이 글을 읽어주기를 바란다.
유명한 소프트웨어 엔지니어인 “켄트 벡”은 그의 저서 “켄트벡의 구현 패턴”에서 아래와 같은 명언을 남겼다.
아무리 장황하게 많은 패턴을 늘어놓더라도, 프로그래밍을 하면서 발생하는 모든 상황을 커버할 수 없다.
– “켄트 벡”
이 글을 쓰게 된 계기
필자는, “클린 아키텍처” 원서를 읽으면서, 필자가 그동안 경험해왔던 기술에 적용할 수 있을지에 대해서 생각을 해봤다. 예를 들어서, JPA 를 사용하는 스프링 애플리케이션에서 클린 아키텍처를 적용할 수 있을까 하는 생각이다. 이 내용에 대해서는 필자의 글 후반에 다시 작성하겠다.
“Software Architecture is The Art Of Drawing Lines That I Call Boundaries. – 로버트C. 마틴”
“소프트웨어 아키텍처는 경계라는 선을 그리는 예술이다. 이러한 경계들은 소프트웨어 요소들을 서로 분리하고 디펜던시 의존성을 제한한다. 아키텍트의 목표는 필요한 시스템을 구축하고 유지하는 데 필요한 인적 리소스를 최소화하는 것이다. 예를 들어서, 비즈니스 유스케이스와 데이터베이스 사이의 경계선을 그릴 수 있다. 그 선은 비즈니스 규칙이 데이터베이스에 대해 전혀 알지 못하도록 막았다. 그 결정은 데이터베이스의 선택과 실행을 뒤로 늦출 수 있었고, 데이터베이스에 의존한 문제가 발생하지 않았다. 중요한 것과 중요하지 않은 것 사이에 선을 긋는다. UI는 비즈니스 규칙에 영향을 미치지 않아야 하고, 데이터베이스는 UI에 영향을 미치지 않아야 한다. 물론, 대부분의 우리들은 데이터베이스는 비즈니스 규칙과 불가피하게 연결되어 있다고 믿고 있다. 하지만, 데이터베이스는 비즈니스 규칙이 간접적으로 사용할 수 있는 도구일 뿐이다. 그래서, 우리는 인터페이스 뒤에 데이터베이스를 놓을 수 있도록 설계를 해야 한다. 실제로 소프트웨어 개발, 기술의 역사는 확장 가능하고 유지 관리 가능한 시스템 아키텍처를 구축하기 위해 플러그인을 만드는 방법에 관한 이야기이다. 핵심 비즈니스 규칙은 다른 컴포넌트들과 독립적으로 유지된다. – 로버트 C. 마틴”
“로버트 C.마틴” 의 “클린 아키텍처”에서 가장 중요하게 강조하는 점은 바로, 디펜던시 의존성이다. 이 글은, 클린 아키텍처의 디펜던시 의존성에 대해서, 필자의 샘플 예시를 바탕으로 설명하겠다.
시스템 구성도 및 기본 설계
간단한 백엔드 API 서버를 구축할 것이다. API 요구사항은 아래와 같다.
블로그 검색 결과를 Rest API 로 제공한다.
블로그 데이터 조회는 오픈 API 를 사용한다.
사용자의 Request 가 있을 때마다 오픈 API 를 바로 호출하지 않고, 미리 저장해놓은 Cache 저장소에서 데이터를 가져온다.
어드민에서 주기적으로 Message 를 API 에 전송해서, 오픈API 결과를 캐싱하도록 요청한다.
해당 샘플은, 하루만에 구축할 수 있는 아주 간단한 시스템이다. 보통 무료 오픈 API 는 요청 콜 수 제한이 있다. 물론, 유료 계정을 사용하면 요청콜수 제한 없이 사용할 수는 있지만, 필자의 샘플에서는 무료 오픈 API 를 사용한다는 가정이다. 그래서, 데이터를 캐싱할 것이고, 사용자의 요청이 있을때는 캐싱 데이터를 제공할 것이다. 프론트에서 API 서버를 호출하면, 아래와 같이 블로그 정보를 JSON 의 형태로 제공할 것이다.
프론트에서는 전달받은 JSON 으로 화면에 렌더링을 할 것이다. 필자의 이 글에서는, 백엔드 중심으로 작성할 예정으로, 프론트에 대한 내용은 상세하게 서술하지 않겠다. 어쨋든, 캐싱 데이터는 레디스에 저장되고, 아래와 같이 직렬화되어서 저장이 될 것이다.
레디스에 저장되는 키는 “blog:articles:검색쿼리” 규칙으로 설계하였다. 만약 사용자가 “스프링부트” 라는 검색어로 블로그 정보를 조회한다면, 레디스에 저장되어 있는 “blog:articles:스프링부트” 라는 키 값을 조회해서 제공할 것이다. 물론, 위에서도 설명했지만 “스프링부트” 라는 검색어에 대한 데이터를 미리 캐싱처리해서 저장해놓을 것이다.
클린 아키텍처, 디펜던시 의존성
“클린 아키텍처” 이론의 디펜던시 의존성에 대해서 알아보자.
“<클린 아키텍처> 의 동심원은 소프트웨어의 각각 다른 레이어 영역을 나타낸다. 내부 원은 비즈니스 정책이다. 클린 아키텍처에서 가장 중요한 개념은 디펜던시(의존성) 규칙이다. 소스 코드 의존성은 내부에서만 상위 수준 정책을 가리키도록 해야 한다. 내부 원 안에 있는 어떤 것도 외부 원의 무언가에 대해서 전혀 알 수 없다. 외부 원에 있는 어떤 것도 내부 원들에 영향을 미치기를 원하지 않는다. Entities는 전사적으로 중요한 비즈니스 규칙을 요약한다. Entities 는 메서드를 포함하는 객체일 수도 있고, 데이터 구조일 수도 있다. Entities 는 가장 일반적이고 높은 수준의 규칙을 요약한다. 외부적인 무언가가 바뀌면 가장 덜 변해야 한다. UseCase는 애플리케이션별 비즈니스 규칙을 포함한다. 시스템의 모든 사용 사례를 캡슐화하고 구현한다. 이러한 사용 사례는 기업 간 데이터 흐름을 조정한다. UseCase 계층은 데이터베이스, UI 또는 어떤 공통 프레임워크 등 외부에 영향을 받을 것으로 기대하지 않으며, 외부 영역으로부터 격리되어야 한다. InterFace Adapter 계층은 컨트롤러와, 모델, 뷰 등 MVC 아키텍처를 포함하는 계층이다. 마지막으로 가장 바깥쪽 계층인, Framework & Drivers 영역은 일반적으로 데이터베이스 및 웹 프레임워크와 같은 도구로 구성된다. 사실, 이 네 개 영역 이상의 것이 필요할 수 있다. 그러나, 디펜던시 규칙은 항상 적용이 된다. 소스 디펜던시는 항상 안쪽을 가리키며, 내부로 이동함에 따라 추상화 수준이 높아진다. 이러한 규칙을 준수하는 것은 어렵지 않으며, 앞으로 많은 고민들을 해결해 줄 것이다. 소프트웨어를 계층으로 분리하고, 디펜던시 규칙을 준수함으로써, 데이터베이스나 웹 프레임워크와 같은 시스템이 외부 부분들이 쓸모없게 될 때, 그러한 쓸모없는 요소들을 최소한의 작업으로 대체할 수 있을 것이다. – 로버트 C. 마틴”
필자는, 클린 아키텍처의 디펜던시 의존성을 아래와 같이 재해석 하였다.
Entity, Domain : 엔티티 정의
UseCase : 비즈니스 규칙 정의
Service, Repository : 비즈니스 규칙 정의, UseCase 의 구체화
Controller : 애플리케이션 API 엔드포인트
Data Providers : UseCase 또는 Service, Repository 의 구현체
필자의 필력이 떨어지므로, 자세한 설명은 생략하고, 필자의 샘플 코드를 같이 보면서 설명하겠다. 패키지 구조는 아래와 같다.
패키지 레이어는 config, core, entry, provider 으로 구분된다. core 패키지가 가장 추상화 수준이 높은, 동심원에서 가장 안쪽의 영역이다. 참고로, 일반적으로 추상화수준이 높은 core 영역은 멀티모듈 또는 서브모듈로 구성하는 것도 가능하다. 이 글에서는, 일단, 단일 애플리케이션이라는 가정하게 작성하는 글이다. 멀티 모듈에 대해서 심도있게 알고 싶은 개발자는 아래 글을 읽어보길 바란다.
http://woowabros.github.io/study/2019/07/01/multi-module.html
필자가 구성한 샘플 코드의 다이어그램은 아래와 같다.
이미지가 선명하게 안보이는데, 브런치 이미지 업로드가 잘 안되는 경우가 있다. 필자에게는 아무런 이득이 없는 브런치를 때려치고, 하루빨리 미디엄 또는 괜찮은 블로그 서비스로 갈아타든가 해야할 것 같다. 주말에 취미도 없이 이렇게 집에서 글이나 쓰고 있고, 읽어주는 사람도 거의 없을텐데 수익은 1도 없고 회의감이 밀려온다.
하지만, 정신차리고 이번 글은 일단 잘 마무리해보자.
Core(UseCase, Entity, Domain, Service, Repository)
Core 패키지에는, 동심원에서 가장 안쪽 영역의 클래스와 인터페이스를 포함한다. 동심원의 가장 안쪽에 존재하기 때문에 추상화 수준은 가장 높다. Entity, Domain 패키지에는 기본적인 도메인 모델을 정의한다. 필자의 샘플 애플리케이션에서는 아래와 같이 Blog 라는 도메인 클래스를 정의하였다.
Blog 클래스는 오픈 API 를 통해서 가져온 데이터를 매핑할 것이다. 사실, DTO 클래스를 별도로 정의하는게 좋을 수도 있다. 일단, 이 글에서는 아주 간단하게 해당 클래스에 매핑할 예정이다. UseCase 패키지에는 BlogUseCase 라는 인터페이스를 정의한다. 두개의 메서드를 아래와 같이 정의하였다.
findBlogByQuery : 검색 쿼리에 맞는 블로그 정보를 조회한다.
updateBlogByQuery : 검색 쿼리에 맞는 블로그 정보를 업데이트 해서 캐시 저장소에 저장한다.
참고로, 리턴 타입이 Mono 이다. Mono 는 “Reactor” 에서 제공하는 Publisher 구현체이다. 스프링 웹플럭스에서는 “Reactor” 라이브러리를 사용하고, 필자의 이 글에서는 스프링 웹플럭스 기반으로 작성하였다. 리액티브 프로그래밍에 관심이 있는 개발자는 필자의 글을 읽어보길 바란다.
https://brunch.co.kr/magazine/reactor
BlogUseCase 인터페이스를 BlogService 라는 클래스에서 구현한다.
Controller –> UseCase
Controller(컨트롤러)는 애플리케이션의 엔드포인트이다. 프론트에서는 Controller 의 엔드포인트에 Request 를 한다. 필자의 컨트롤러에서는 BlogUseCase 인터페이스를 호출하는데, 아래 화면과 같이 인터페이스의 구현체를 직접 호출하지는 않는다.
컨트롤러에서는, 구현체를 직접 호출하지 않고 아래와 같이 인터페이스를 호출한다.
샘플 코드는 아래와 같다.
필자의 샘플 코드에서는 Controller 에서 UseCase 를 바로 호출했지만, Controller 에서 Service 를 호출해도 크게 상관은 없다. 이 글에서 강조하고 싶은 점은, Controller 는 UseCase 또는 Service 에 대해서 잘 알고 있어야 하지만, 반대로 UseCase 또는 Service 는 Controller 에 대해서 알지 못해야 한다는 사실이다. 필자의 동심원 그림을 다시 보자.
동심원의 안으로 갈수록 추상화 수준은 높아진다. 원 안쪽에 위치하는 UseCase, Service 는 자주 변경되지 않는다. 그보다 더 안쪽에 있는 Entity, Domain 는 거의 변경되지 않을 것이다. 원 안쪽에서의 변화가 원 바깥쪽에 영향을 미치는 것은 자연스러운 일이다. 즉, Controller 는 UseCase,Service 에 대해서 잘 알고 있기 때문에, UseCase 또는 Service 의 변경이 되면 Controller 도 변경을 해야한다. 하지만, 반대로 원 바깥에서의 변화는 원 안쪽에 영향을 주면 안된다. 즉, UseCase 또는 Service 는 Controller 에 대해서 잘 모르기 때문에, Controller 에서의 변화는 UseCase 에 영향을 주면 안된다. 이것이 바로 로버트 C. 마틴 의 “클린 아키텍처” 이론의 디펜던시 룰 이다.
혹시, 이해가 잘 되는가…?? 디펜던시 의존성에 대해서, 필자는 “안다,모른다” 로 표현하였다. 어쨋든, 이 개념을 잘 이해를 해야 필자의 재미없고, 지루한 이 글을 계속 읽을 수 있다.
Listener –> UseCase
Listener 는 Controller 과 동일한 영역이라고 생각하면 된다. 어쨋든, Listener 역시 엔드포인트이고, 메시지를 전달받는 끝점이다. 필자의 샘플 코드에서는, 블로그 검색 결과를 캐싱에 대한 업데이트 신호를 수신하게 된다. Listener 에서 UseCase 를 사용하는 방법은, 컨트롤러에서의 UseCase 호출 방식과 유사하다. BlogService 구현체를 직접 호출하지 않는다. 인터페이스를 호출할 것이다.
자세한 설명은 생략한다.
사실, 여기까지는 아주 중요한 내용은 아니다.
이제부터 집중해서 보자. 글 내용이 조금씩 어려워진다.
UseCase –> UseCase (1)
필자의 애플리케이션에서는, 오픈 API 를 사용해서 블로그 검색 결과를 조회할 것이다. 오픈 API 를 조회하는 기능의 인터페이스를 선언해보자. 파라미터로 검색 쿼리 문자열을 받고, 리턴 타입은 Mono
이다. 해당, 인터페이스를 구현하는 구현체를 작성한다. 레디스 캐싱 서버에 저장되어 있는 데이터를 조회하는 로직이다. 참고로, Spring Data Reactive Redis 의 ReactiveRedisOperations 를 사용하였다.
블로그 정보를 조회하는 해당 로직은, BlogUseCase 를 구현하는 BlogService 에서 호출해서 사용한다. BlogController 에서는 BlogUseCase 를 호출하는데, BlogUseCase 의 구현체인 BlogService 대해서 알아야할 필요가 없는데, BlogService 에서 호출하는 기능 역시 알 필요가 없다.
BlogService 에서 호출하는 FindBlogByQueryPort 구현체인 SimpleRedisProvider에 대해서, 컨트롤러 입장에서는 전혀 알 필요가 없다.
쉽게 이해가 잘 안될것이다. 아래 클래스 다이어그램을 보면서 우리 같이 생각해보자.
FindBlogByQueryPort 를 구현하는 SimpleRedisProvider 클래스 구현체는, 네이밍에서 알수 있듯이 레디스를 사용한다. BlogController 입장에서는, 데이터가 어디에 저장 되어있는지 전혀 알 필요가 없다. 해당 구현체가 레디스 인지, RDBMS 인지, Elasticsearch 인지 전혀 알 필요가 없다는 사실이다. BlogService 에서의 코드를 확인해보자. FindBlogByQueryPort 타입의 simpleRedisProvider 빈을 주입받는다.
주입받은 simpleRedisProvider 빈을 사용해서, findBlogByQuery 메서드를 호출할 뿐이다. 레디스인지, RDBMS 인지 전혀 알 필요가 없다. 단지, Mono
타입으로 리턴 받는다는 사실만 알 뿐이다. UseCase –> UseCase (2)
지금까지는 블로그 정보를 조회하는 로직에 대해서 알아봤다. 자… 하지만, 블로그 정보를 조회하기 위해서는, 기존에 이미 블로그 데이터가 레디스 서버에 저장이 되어있어야 한다. 블로그 검색 결과를 업데이트 하는 로직을 살펴보자. 블로그 정보는 오픈 API 에서 가져오기로 하였다. 필자는 네이버 오픈 API 를 사용할 것인데, FindBlogByQueryPort 를 구현하는 NaverBlogProvider 라는 구현체를 아래와 같이 만들었다.
오픈 API 정보를 조회하면, 그 데이터를 레디스에 저장해야할 것이다. 레디스에 저장하는 UpdateBlogByQueryPort 라는 인터페이스를 하나 정의해보자.
BlogService 의 코드를 보면 아래와 같이
오픈 API 의 데이터를 먼저 조회하고, 그 다음에 Redis 에 저장하는 로직이다.
UpdateBlogByQueryPort 를 구현하는 구현체는, 레디스 조회를 위해 만들었던 SimpleRedisProvider 컴포넌트에서 수행한다.
블로그 정보에 대한 업데이트에 대한 초기 요청은, 메시지 리스너에서 수행하는데, MessageListener 에서는, 데이터를 어디서 가져오는지, 어떤 캐시 저장소에 저장하는지 전혀 알지 못한다. 단지, MessageListener 클래스에서 BlogUseCase 의 updateBlogByQuery 메서드를 호출할 뿐이다.
참고로, UpdateBlogByQueryPort 와 FindBlogByQueryPort 는, 서로 각자의 책임을 갖고 있다. 즉, SRP (단일책임원칙)에 의해서 분리 되어있다. 하지만, 해당 두 인터페이스를 구현하는 SimpleRedisProvider 클래스는 두 책임을 모두 구현하는 형태로 구현을 하였다. 비록, 두개의 책임을 수행하는 클래스이지만, 다른 객체에서 이 클래스에 강하게 의존하지는 않기 때문에 크게 문제가 되지는 않는다고 생각한다.
저장소가 무엇인지 알 필요가 없다…라는 사실은
어떤 의미를 갖는가?
사실, 이 글에서 샘플 코드는 중요하지 않다. 우리가 알아야 하는 것은, 바로 디펜던시 의존성이다. 디펜던시는 동심원의 안쪽으로 의존한다. 바깥에 있는 영역은 안쪽에 의존하지만, 안쪽은 바깥쪽에 의존하지 않는다. 이 말을 풀어서 다시 설명하면, UpdateBlogByQueryPort 는 안쪽 원에서 UseCase 영역에 위치한다. SimpleRedisProvider 는 바깥쪽 영역 Provider 영역에 위치한다. SimpleRedisProvider 는 레디스 라는 저장소에 강한 의존성을 갖는다.
UpdateBlogByQueryPort 는 바깥쪽에 위치한 SimpleRedisProvider 에 의해서 영향을 받으면 안된다. 즉, UpdateBlogByQueryPort 는 어떤 저장소를 사용하는지에 대해서 알 필요가 없다. 저장소가 바뀐다고 해서 UpdateBlogByQueryPort 가 변해서는 안된다. BlogUseCase 를 구현하는 BlogService 에서 호출하는 UpdateBlogByQueryPort 는, 어떤 DB 를 사용하는지 모르기 때문에, 나중에 DB 를 변경하거나, 확장해도 전혀 문제가 되지 않는다. 즉, 아키텍처를 설계할 때 DB에 대한 선택을 최후로 미룰 수 있다는 얘기다. 우리는, 비즈니스 요구사항이 명확하게 정해진 이후에, DB 를 선택할 수 있고, 만약 어떤 문제가 발생해서 선택한 DB 를 사용하지 못하는 경우가 발생하면, 내부 로직에는 변함없이 DB 에 의존성을 갖고 있는 구현체만 변경하면 될 것이다.
이해를 돕기 위해서, 다른 예를 설명하겠다.
필자의 샘플에서는, 네이버 오픈API 를 사용한다. 만약 네이버 오픈API 카카오 오픈API 로 변경하고 싶다면 어떻게 될까?
동심원에 있는 FindBlogByQueryPort 는 변경이 되어서는 안된다. 바깥의 원에서 어떤일이 발생해도, 안쪽 원에 영향을 끼쳐서는 안된다. NaverBlogProvider 와 KakaoBlogProvider 는 FindBlogByQueryPort 를 구현하는 구현체이지만, 각자의 호출 로직은 다를 수 것이다. 오픈API 주소도 다를 것이고, 파라미터 또한 다를 것이다. 또한, NaverBlogProvider 에서는 WebClient 라는 모듈을 사용하는데, FindBlogByQueryPort 에서는 관여할 필요가 없다. 어떻게 호출하던 상관없이 Mono
타입으로 전달만 잘 받으면 된다. 더 많은 고민이 필요하다.(1)
클린 아키텍처는 항상 정답은 아니다. 글 초반에 작성했듯이, 필자가 이 글을 쓰게 된 결정적인 이유는 필자가 경험했던 기술에 클린 아키텍처를 접목할 수 있는지에 대한 고민 때문이다. 우리는 JPA 를 많이 사용하는데, JPA 는 엔티티 매핑을 위해서 @Entity 어노테이션을 사용한다. 필자가 이 글에서 설명한 클린 아키텍처 이론에 의하면, Entity 객체는 DB 에 의존성을 가지면 안된다. 디펜던시 룰에 의하면, Entity 는 DB 를 어떤걸 사용하는지 모른다. JPA 뿐만 아니라, 스프링에서 제공하는 Spring Data 기술 역시 Entity 클래스에 의존성을 가질 수 밖에 없다. Spring Data 기술이 추상화 기술로 DB 변경에 대한 가능성이 열려있지만, 그럼에도 불구하고 Entity 객체의 의존성을 가질 수 밖에 없다. JPA, 스프링 등의 기술은 클린 아키텍처 를 보장해주지 않는다. 이 글은, 클린 아키텍처에 대해서 논하는 글이지만, 클린 아키텍처를 무조건 사용하기 위해서 JPA 를 사용하면 안된다는 내용은 아니다. 아키텍처 이론에는 정답이 없다. 상황에 맞게, 서비스에 맞게, 개발자들의 역량에 맞게 아키텍처 를 설계해야 할 것이다.
더 많은 고민이 필요하다.(2)
클린 아키텍처 이론을 적용하기 위해서, 필자는 인터페이스를 적극적으로 활용하였다. 하지만, 필자는 너무 복잡한 인터페이스 추상화로 인해서 고통받은 경험이 너무 많다. 불필요한 추상화는 오히려 애플리케이션의 복잡도만 증가시킬 것이다. 필자의 생각과 일치하는, “켄트 벡의 구현패턴”을 참고하길 바란다.
“인터페이스 추가에는 비용이 발생한다. 인터페이스를 사용하게 된 경제적 이유로는 소프트웨어는 예측하기 어렵다는 점을 들 수 있다. 프로그램에 유연성이 필요한 이유는 고객의 요구사항이 종잡을 수 없게 변화하고, 기술 변화도 예측할 수 없기 때문이다. 소프트웨어는 유연해야 하지만, 유연성에는 비용이 들고, 어떤 부분에서 유연성이 필요할지 에측하기란 쉽지 않다. 따라서 실제 필요해지는 경우에만 시스템에 유연성을 부여하자는 결론에 이른다. – 켄트 벡”
마무리
주저리주저리 글을 작성했는데, 글이 너무 길어졌다. 재미없는 글이 되었는데, 혹시라도 정독해서 읽은 개발자가 있다면… 진심으로 감사하게 생각한다. 필자의 글은, 정답을 얘기하는 글이 아니다. 이 글은, 좋은 소프트웨어를 만들고 싶은 평범한 개발자의 고민이 담겨있는 글이다. 비록, “클린 아키텍처” 를 실무에서 적용할 수 있을지에 대해서는 아직 확신은 없지만, 소프트웨어를 잘 만들기 위한 노력은 끊임없이 해야할 것이다. 다음 글에서는 백엔드 애플리케이션의 캐싱 전략에 대해서 작성할 예정이다.
https://github.com/sieunkr/clean-architecture-sample
키워드에 대한 정보 웹 아키텍처
다음은 Bing에서 웹 아키텍처 주제에 대한 검색 결과입니다. 필요한 경우 더 읽을 수 있습니다.
이 기사는 인터넷의 다양한 출처에서 편집되었습니다. 이 기사가 유용했기를 바랍니다. 이 기사가 유용하다고 생각되면 공유하십시오. 매우 감사합니다!
사람들이 주제에 대해 자주 검색하는 키워드 스프링 5 기초 강의 4-1강 웹 아키텍처의 이해
- 넥스트리(주)
- IT교육
- TypeScript
- Spring
- 나무소리
- 자바스크립트
- 타입스크립트
- 스프링5
- 스프링부트
- 리액트
- 몹엑스
- 강좌
- 강의
- 자바
스프링 #5 #기초 #강의 #4-1강 #웹 #아키텍처의 #이해
YouTube에서 웹 아키텍처 주제의 다른 동영상 보기
주제에 대한 기사를 시청해 주셔서 감사합니다 스프링 5 기초 강의 4-1강 웹 아키텍처의 이해 | 웹 아키텍처, 이 기사가 유용하다고 생각되면 공유하십시오, 매우 감사합니다.