안녕하세요, 오늘은 Software Architecture 에 대해 정리해 보았습니다.
IT 발전과정
1960 ~ 1980s : Fragile Cowboys
💡 Fragile 은 사전적 의미 그대로 깨지기 쉬운 시스템이라는 특징을 가지고 있다.
- Mainframe, Hardware
- 메인 프레임 방식으로 하드웨어가 중심이 되었다.
- 소프트웨어 보다는 하드웨어의 사양에 맞추어 서비스가 구축되었다.
- 하드웨어가 워낙 고가의 장비이기 때문에 서비스의 기능 수정이나 추가가 힘들었다.
1990 ~ 2000s : Robust, Distributed
💡 1990 ~ 2000년대는 분산이라는 키워드로 아키텍처를 볼 수 있다.
- Changes
- 분산되어 시스템이 안정화 되었다.
- 분산된 시스템 덕분에 서비스의 불확실한 변화가 발생하여도 안정성 있는 서비스를 유지할 수 있게 됨
2010s~ : Resilient/Anti-Fragile, Cloud Native
💡 시스템이 Local 환경에서 Cloud로 이전되었다.
- Flow of Value의 지속적 개선
- Fragile과 반대되는 개념이 Anti-Fragile 이다.
- Cloud Native로 시스템이 구축되던 시기
- 확장성과 안정성이 강화됨
- 지속적인 개선 및 변경이 발생해도 시스템을 탄력적으로 운영할 수 있다.
정리
- 현대 : Anti-Fragile
- DevOps라는 IT 문화가 생겨났다.
- Cloud Native Architecture로 전환된 시기이다.

- Antifragile은 다른 개발 System이나 환경보다 시스템 변화가 적다
a. 변화에 바로 적응할 수 있다.
- 그럼에도 비용이 저렴하다.
Antifragile의 4가지 특징
💡 취약한 시스템들이 스트레스에 약할 때,
Antifragile 아키텍처는 변화에 대응하여 더 강력하고 적응력 있는 특징을 갖춘다.
1. Auto Scailing

- 시스템을 구성하고 있는 인스턴스를 하나의 Auto Scaling Group으로 묶는다.
- 최소 인스턴스를 지정할 수 있다.
- 사용량에 따라 인스턴스를 증가하도록 만들 수 있다.


💡 위와같은 작업을 운영자의 설정이 아니라 ****CPU, Memory, 네트워크, DB의 사용량이나
**조건에 따라서 처리하는 개념**이바로 **Auto scaling** 이다**.**
Micro Services
💡 기존 시스템이 하나의 거대한 형태로 구축되어 서비스 되었다면,
마이크로 서비스는 전체 서비스를 구성하고 있는 개별적인 모듈이나 기능을
독립적으로 개발하고 배포하고 운영할 수 있도록 세분화된 서비스라고 할 수 있다.
- AWS와 Netfilx의 Micro Service 구상도
- 넷플릭스와 아마존은 클라우드 서비스를 가장 잘 구축하고 활용하고 있는 업체로 알려져있다.
- 실제로 Spring Cloud의 초창기 라이브러리 중 많은 부분이 넷플릭스에서 개발되었다.
- 만들어진 라이브러리들이 Spring 진영에 기부된 것

- 넷플릭스 구상도에서 파란색은 서비스간의 연동이나 통신을 의미한다.
- 초록색은 넷플릭스라는 전체 서비스를 구축하고 있는 각각의 Microservices 이다.
- 마이크로 서비스는 Cloud Native Architecture Application의 핵심이다.
Chaos engineering
💡 급격하고 예측하지 못한 상황에서도 System이 안정적으로 견딜 수 있고
신뢰성을 쌓기위해 운영중인 소프트웨어 시스템에 실행하는 방법론
Chaos Engineering 개요
카오스 테스트(카오스 엔지니어링)란 무엇일까요?
한마디로 어떠한 경우에도 안정적으로 서비스를 제공할 수 있도록 구축되어야 한다는것을 의미.
Continuous deployments
💡 지난시간 배웠던 CI / CD 즉, 지속적인 통합과 지속적인 배포
CI / CD 라는 개념은 Cloud Naitve나 마이크로 서비스에서만 새롭게 사용되는것이 아니라
이전부터 시스템의 통합적인 관리와 운영을 위해 사용되었지만
Cloud Native나 마이크로 서비스에서 더욱 빛을 발하게 되었다.

-
Cloud Native Application은 수십, 수백개 이상의 마이크로 서비스로 도메인이 분리되어 개발된다.
-
수많은 서비스들을 하나하나 빌드, 테스트, 배포 하는 등의 작업을 수작업으로 한다고 가정한다면?
- 시스템 자체가 엄청나게 복잡해진다.
- 각각의 서비스를 빌드하고 배포하는 작업이 하나의 큰 업무가 된다.
-
마이크로 서비스들을 빌드하고 배포함에 있어서 자동화된 시스템을 구축하는것이 중요해졌다.
- 하나의 작업에서 다른 작업으로 연계되는 작업을 파이프 라인으로 연결 시킨다면
- 작은 변경 뿐만 아니라 전체적인 시스템 변경 측면에서도 빠르게 적용이 된다.
Cloud Native Architecture
💡 2010년대 이후부터 IT 시스템은 AntiFragile 혹은 Cloud Native Architecture의 형태로 발전해왔다.
- 기존에 Local 환경(사내 서버 등)으로 구축하여 운영하던 시스템을
Cloud 환경으로 전환하기 위해서 어떠한 구조가 필요한지 알아보자.
1. 확장성
-
확장 가능한 형태의 아키텍처
- 시스템의 수평적 확장 -> 더 많은 사용자의 요청을 처리할 수 있다.
- 즉, 확장된 시스템으로 인해 부하를 분산하여 가용성이 보장되었다.
- 시스템 확장은 Scale Up(수직 확장), Scale Out(수평확장) 크게 두가지로 나뉜다.
-
Scale Up, Scale Out

- Scale Up
- 수직적 확장
- 하드웨어의 사용을 높인다. (CPU, Memory 등의 스펙을 높인다)
- Scale Out
- 수평적 확장
- 같은 사양의 서버(인스턴스)를 여러대 배치
- 동시에 더 많은 사용자 요청을 처리할 수 있도록 만듦.
- 일반적으로 이렇게 시스템을 양적으로 늘리기 위해서는 하드웨어 비용이 증가
-
Cloud Service
- 업체로부터 가상의 서버, 가상의 저장소, 가상의 네트워크 등을 빌려서 사용하게 되었다.
- 시스템을 양적으로 늘리기 위해서 사용되던 비용을 최소화할 수 있게되었다.
- 증축시킨 서버를 사용하지 않을 경우엔 자유롭게 반납하여 비용을 낮출 수 있다.
- Cloud Service 업체를 사용하여 Auto Scailing 또한 가능하다.
- Cloud Native 에서는 가상서버 기술이 핵심이 되었다.
- 가상 서버와 리소스들은 모니터링 도구들을 통해 현재 사용량을 측정하기 쉽다.
-
Container 가상화
- 기존의 서버 가상화 방식과 더불어 컨테이너 방식의 가상화를 같이 사용하게 됨.
2. 탄력성
3. 장애 격리
- 특정 서비스에 오류가 발생해도 다른 서비스에 영향을 주지 않는다.
- 마이크로 서비스들은 하나의 작은 단위의 Application이다.
- 따라서 하나의 서비스에 생기는 오류 사항들을 다른쪽 서비스로의 영향을 최소화 할 수 있게된다.
Cloud Native Application
💡 Cloud Native Architecture에 의해 설계되고 구현되는 Application을 의미한다.

-
마이크로 서비스로 개발된다.
-
CI / CD 과정을 거치게 된다.
- 마이크로 서비스에 문제가 발생하였을 경우 바로 수정하여 다시 배포하는 과정을 반복할 수 있다.
- 이러한 특징을 DevOps라고 한다. 고객이 원하는 최선의 결과물을 빠르게 만드는것이 목적이다.
- 마이크로 서비스들을 클라우드 환경에 배포하고 사용하기 위해서는 컨테이너 가상화 기술을 사용하게 된다.
Cloud Native Application 특징
배포전략
- 시스템에 완성된 결과물을 배포하기 위해 사용되는 전략 두가지
- 카나리 배포
- 블루그린 배포

- 전체 사용자의 95% 가량의 비율은 이전 서비스를 사용하도록 한다.
- 전체 사용자의 5% 가량은 새로 만들어진 서비스를 사용하도록 한다.

- 이전 버전(Blud)에 있던 트래픽을 거의 동일한 새 버전(Green)으로 점진적으로 이전시킨다.
- 두 버전 모두 프로덕션 환경에서 실행 상태를 유지해야 한다.
DevOps
💡 Development와 운영을 뜻하는 Operation이 합쳐진 용어
개발, 운영 조직의 통합을 의미한다.
- 위와같은 통합으로 고객의 요구사항을 빠르게 반영하고 완성도 높은 결과물을 제시하는것에 목적이 있다.

기존의 엔터프라이즈 어플리케이션
-
고객의 요구사항에 맞게 도메인을 분석 후
시스템을 설계, 어플리케이션 구현, 테스트, 배포 과정을 거쳐 시스템 개발을 완료하게된다.
이러한 과정은 적게는 수개월 많게는 수년까지 걸리게 된다.
-
개발 조직에 따라서 중간 단계의 필수적인 과정이 있을 수 있다.
- 개발 기간이 길어지게 된다.
- 그만큼 변경 및 요구사항에 바로 대처하기 어렵다는 단점을 가질 수 있다.
-
고객의 요구사항은 언제든지 변경될 수 있다.
- 심지어 개발 마지막 단계에서 변경이 발생하기도 한다.
- 필요할 때마다 바로바로 수정될 수 있는 구조가 더욱 좋다.
-
필요할 때 마다 요구사항을 반영하고 테스트를 자주 하는것은 개발 일정이 지연될 수 있다
- 그럼에도 불구하고 최종적으로 고객의 요구사항에 맞는 오류없는 완성물이 나와야한다.
정리
- 통합, 테스트, 배포 하는 과정을 전체 개발이 완료될때 까지 끊임없이 진행하는것을 DevOps라 한다.
- Cloud Native Application은 이러한 DepOps 환경에 맞춰서 서비스의 구조를 작은 단위로
나눌 수 있게 함으로써 더 자주 통합, 테스트, 배포할 수 있는 구조가 되었다.
Container 가상화
💡 Cloud Native Architecture의 핵심
기존의 로컬 환경에서 운영해야만 했던 시스템을
Cloud 환경으로 이전해서 작은 비용으로 탄력성 있는
시스템을 구축할 수 있게된 배경에는 컨테이너 가상화 기술이 있다.

-
Traditional Deployment
- 기존의 하드웨어 가상화, 서버 가상화에 비하여 적은 리소스를 사용하여 가상화 서비스를 구축할 수 있다.
- 전통적인 방식은 하드웨어 시스템 위에 운영체제를 설치하고 그 다음 어플리케이션을 운영한다.
-
Virtualized Deployment
- 가상화를 통한 개발 시스템에서는 Hypervisor 기술을 통한 가상 머신을 기동한다.
- 가상머신은 시스템이 가지고있는 Hardware(호스트 시스템)를 나누어 사용한다.
- 각각의 가상머신에 Application을 운영할 수 있다.
- 하나의 가상머신은 독립적인 운영체제를 가지고 실행될 수 있다.
- 하지만 가상머신에서 작동되는 어플리케이션은 호스트 운영체제에 많은 부하를 주게된다.
- Container Deployment
- 운영체제 위에 컨테이너 가상화를 기동하기 위한 소프트웨어 서비스를 작동한다.
- 공통적인 라이브러리나 리소스를 공유하여 사용한다.
- 각자 필요한 부분에 대해서만 독립적인 영역에 실행할 수 있는 구조
- 기존의 하드웨어 가상화 기술보다 더 적은 리소스를 사용
- 컨테이너 가상화 위에서 동작하는 서비스들은 가볍고 빠르게 운영할 수 있다는 특징
12 Factors
💡 Cloud Native Application을 구축함에 있어서 고려해야할 12가지 항목
The Twelve-Factor App (한국어)

- Heroku 헤로쿠
- 자사의 고객들을 상대로 Cloud Service시에 발생했었던 문제점과 개선점
시행착오등을 바탕으로 가이드 라인을 만들어 배포하였다.
- 많은 Cloud Native Application에서 가이드를 바탕으로 어플리케이션을 설계, 개발, 운영하는데 사용

Base Code (코드 통합)
- 자체 Repository에 저장된 각 마이크로 서비스에 대한 단일 코드 베이스
- 버전을 제어하기위한 목적이 있다, 형상 관리를 위해서 코드를 한곳에서 배포하기 위함
- 개발, 운영에 배포하기 위해서 코드의 통일적인 관리가 필요하기 때문에 가장 중요한 항목으로 꼽힌다.
2. DEPENDENCY ISOLATION (종속성의 배제)
- 각 마이크로 서비스는 자체 종속성을 가지고 패키징 되어있다
- 전체 시스템에 영향을 주지 않는 상태에서 변경되고 내용을 수정할 수 있어야 한다.
3. CONFIGURATIONS (환경설정의 외부 관리)
- 하드코딩 되어있는 설정정보가 아니라 시스템 코드 외부에서 구성관리 도구를 통해서
마이크로 서비스에 필요한 작업들을 제어한다.
- 올바른 구성이 적용된 환경에서 동일한 배포가 전파될 수 있다.
4. LINKABLE BACKING SERVICES (백업 서비스의 분리, 서비스 지원)
- 예를들어 DB, Cache, Messaging Service, Broker 등을 이용해서
마이크로 서비스가 가져야할 기능들을 추가로 지원할 수 있는것을 말한다.
- 응용 프로그램 자체에서 필요한 BACKING System Resource를 분리하게 됨으로써
서로 상호가능한 서비스들의 Dependency를 갖지 않는 상태에서 작업할 수 있게 된다.
5. Build Release and Run, STAGES OF CREATION (개발, 테스트, 운영환경의 분리)
-
개발 서버에서 만들어진 코드를 배포하기 위해서 실행단계까지 옮기는 과정을 엄격하게 분리
-
각각은 고유한 아이디로 태그를 가지고 있어야 한다.
-
이전 상태로 돌아가는 롤백기능을 지원해야 한다.
-
CI / CD 시스템을 완벽하게 이용해서 자동화된 시스템을 구축하는것이 좋다.
6. STATELESS PROCESS (상태관리)
- 각각의 마이크로 서비스는 실행중인 다른 서비스와 분리된채 자체 프로세스에서 운영될 수 있어야 한다.
- 마이크로 서비스에 필요한 자원이 있다면 캐시, 데이터 저장소등을 이용하여 외부와 데이터 동기화 하면된다.
7. PORT BINDING (포트 바인딩)
- 각각의 마이크로 서비스는 자체 PORT에서 노출되는 인터페이스 및 기능이 있어야 한다.
- 위와같은 구조를 가지면 다른 마이크로 서비스와 격리가 가능해진다.
8. CONCURRENCY (동시성)
- 마이크로 서비스는 사용 가능한 가장 강력한 인스턴스 컴퓨터에서
가장 큰 인스턴스로 확장하는것과는 반대로
아주 많은 수의 서비스 동일한 프로세스를 복사해서 확장한다.
- 하나의 서비스가 여러가지 인스턴스에 동일한 형태로 복사되어 운영됨으로써 부하분산을 달성한다.
- 따라서 서비스가 여러 인스턴스에 나누어져 있기 때문에 동시성을 가진다.
9. DISPOSABILITY (서비스의 올바른 상태유지 )
- 서비스 인스턴스 자체가 삭제 가능해야한다.
- 확장성 기회를 높여야한다.
- 정상적으로 종료할 수 있어야 한다
- 컨테이너 가상화 도구로써 Docker등을 사용하면 위와같은 과정을 쉽게 해결할 수 있다.
10. DEVELOPMENT, PRODUCTION PARITY (개발과 운영환경의 통일)
- 개발 단계와 프로덕션 단계를 구분한다.
- 운영프로그램의 수명주기 전반에 걸쳐 서비스에 직접 Access하는 기능을 방지해야 한다.
- 환경 자체를 최대한 다른 서비스와 중복, 종속적이지 않은 상태로써 서비스를 유지할 수 있어야 한다.
11. LOGS (로그 분리)
- 로깅 시스템은 마이크로 서비스에 의해서 생성된 로그를 이벤트 스트림으로 처리해야한다.
- 로그를 출력하는 로직은 기존의 어플리케이션 로직과 분리되어
어플리케이션이 실행되지 않는 상태여도 로그만은 정상적으로 작동되어야 한다.
- 이러한 로그, 이벤트를 집계하기 위해서는 별도의 추가적인 서비스 혹은 모니터링 서비스를 사용할 수 있다.
12. ADMIN PROCESSES FOR EVENTUAL PROCESSES (관리 프로세스)
- 현재 운영되고 있는 모든 마이크로 서비스들은 어떤 상태로 사용되고 있는지 알아야 한다.
- 서비스들의 리소스가 현재 어떻게 사용되고 있는지 파악하기 위한 적절한 관리도구가 필요하다.
- 이러한 작업에는 리포팅 할 수 있는 기술이 포함되어 있어야 한다.
- 결과로 나온 데이터를 정리 및 분석하는 기능이 포함될 수 있다.
15 Factors
💡 최근에는 12가지에서 3가지가 추가된 15가지의 요인에 대하여 고민하여야 될 수 있다.
확실히 정해진것은 아님.
IBM Developer
1. API First
- 가지고 있는 모든 마이크로 서비스는 API 형태로 서비스가 제공된다.
- API를 구축하에 있어서 사용자측에서 어떠한 형태로 쓸것인가를 먼저 고민하여 개발해야 한다.
2. Telemetry
- 모든 지표는 수치화, 시각화되어 관리할 수 있는 항목이어야 한다.
3. Authentication and authorization
- API를 사용함에 있어서 인증 작업은 필수이다.
- 마이크로 서비스는 적절한 인증을 가지고 있는
리소스, 서비스, 외부시스템에 대해서는 데이터를 전달, 교환하는 것이 가능하여야 한다.
오늘의 코드카타
class Solution {
public int[] solution(int[] num_list) {
int[] answer = new int[num_list.length];
for (int i = 0; i < num_list.length; i++) {
answer[i] = num_list[num_list.length - i - 1];
}
return answer;
}
}
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
Solution solution = new Solution();
int[] a1 = {1, 2, 3, 4, 5};
int[] a2 = {1, 1, 1, 1, 1, 2};
int[] a3 = {1, 0, 1, 1, 1, 3, 5};
System.out.println(Arrays.toString(solution.solution(a1)));
System.out.println(Arrays.toString(solution.solution(a2)));
System.out.println(Arrays.toString(solution.solution(a3)));
}
}
배열 뒤집기