알고리즘 스터디

StringTokenizer
기술 면접 스터디
MSA(Microservice Architecture)란?

MSA를
"하나의 큰 어플리케이션을 여러 개의 작은 어플리케이션으로 쪼개어 변경과 조합이 가능하도록 만든 아키텍쳐"
라고 한 줄 설명이 가능하다. 즉, 레고처럼 작은 부품 하나하나를 쌓아서 하나의 작품을 만들어 내는 것이다.
👀 그럼 MSA는 왜 생겨났을까?
애플리케이션 개발 초기에는 전체 소스 코드를 하나의 배포 유닛 (war 또는 ear)으로 내장시키는 'Monolithic' 방식을 사용했다. 하지만 기존 애플리케이션에 사소한 변경 사항이 있더라도 자체적인 QA(Quality Assurance) 주기에 따라 업데이트를 하거나 일부 서비스 업데이트로 오류가 발생한 경우 전체 시스템을 중단하고 오류를 해결하는 등의 다운 타임이 발생하는 일이 빈번했다.
👇 Monolithic?
BE + FE
Monolithic은 소프트웨어의 모든 구성요소가 한 프로젝트에 통합되어 있는 형태이며, 모듈별로 개발을 하고 개발이 완료된 하나의 결과물로 패키징 하여 배포되는 형태를 의미한다.
- 장점
- 개발 초기에는 단순한 아키텍처 구조와 개발 용이함
- 단점
- 서비스 규모가 커짐에 따라 전체 시스템 구조 파악 및 유지 보수가 어려워짐
- 부분 장애가 전체 서비스의 장애로 확대될 수 있음 (하나의 서비스가 모든 서비스에 영향을 미침)
- 배포 시간이 오래 걸림
- 하나의 Framework와 언어에 종속적
- 부분적인 Scale-out(여러 서버로 나누어서 일을 처리 방식)이 어려움
이러한 Monolithic의 단점을 보완하기 위해 MSA가 나오게 된 것 이다.
즉, 애플리케이션의 핵심 서비스를 분할하는MicroService Architecture라는 방식이 생겨났으며 각 서비스들을 독립적으로 구축하고 배포할 수 있게 되었다.

🟢 MSA 장점
- 분산형 개발을 통해 개발 주기가 단축되기 때문에 빠르고 유연한 배포가 가능 (출시 기간 단축)
- 서비스가 독립적이기 때문에 다른 서비스에게 영향을 주지 않음 (뛰어난 복구 능력)
- 서비스별 기술 도입 및 확장이 자유로움 (높은 확장성)
- 모놀리식 방식에 비해 애플리케이션이 모듈화 되고 규모가 작기 때문에 우려사항이 줄어듦 (손쉬운 배포)
- 다중 언어 지원(Polyglot) API를 사용 (향상된 개방성)
- 하나의 애플리케이션을 여러 부분으로 분할했기 때문에 각 서비스 업데이트 및 개선 용이 (편리한 액세스)
🔴 MSA 단점
- 각 서비스들은 API를 통해 통신하므로 네트워크 통신에 의한 오버헤드 발생
- 서비스별로 로그가 생성되므로 중앙 로그 모니터링이 존재 X
- 하나의 프로젝트에 수많은 서비스들이 존재하므로 모든 서비스 모니터링 오버헤드 증가
- 하나의 서비스에서 다른 서비스를 호출하므로 장애 발생 시 경로 및 장애 추적이 힘듦
- 서비스가 분산되어 있기 때문에 모놀리식에 비해 상대적으로 많이 복잡
👇 참고 블로그
제네릭에 대해서 설명하고, 컬렉션 클래스에서 왜 제네릭을 사용하는 지 설명해주세요.
제네릭 프로그래밍이란 하나의 데이터가 특정 데이터 타입에만 종속되지 않고 여러 데이터 타입을 가질 수 있는 기술에 중점을 두어 재사용성을 높일 수 있는 프로그램 방식이다.
나는 Generic 말 그대로 하나의 데이터 타입(String, int ...)에 종속되지 않는다는 말이라고 이해했다.
이 Box 클래스는 제네릭한 클래스이다. T가 중간 중간 껴있는 것을 확인할 수 있는데,
T는 내가 생성한 클래스도, 타입도 아니다. Generic 한 클래스를 만들기 위해 사용하는 제네릭 변수이다.
✅ Box.java
public class Box<T> {
private T t;
public void set(T t) {
this.t = t;
}
public T get() {
return t;
}
}
✅ Main.java
public class Main {
public static void main(String[] args) {
Box<Integer> box = new Box<Integer>();
box.set(10);
Integer i = box.get();
System.out.println(i.intValue());
}
}
Box<Integer> box = new Box<Integer>() 로 생성하면 앞서 Box.java의 T 값이 Integer가 되는 것이다.
그럼 Box 클래스는 Integer 타입의 데이터를 관리할 수 있는 객체로 활용되게 된다.
Box<String> box = new Box<String>() 으로 생성하면 Box 클래스는 String 타입의 데이터를 관리하고, Human 으로 생성하면 Human 타입의 데이터를 관리하게 된다.
이제 Box라는 클래스가 특정 데이터 타입에 종속되지 않는 Generic한 클래스가 된 것이다.
👀 그럼 T가 아니라 Object를 쓰면 어떨까?
Box.java
public class Box {
private Object t;
public void set(Object t) {
this.t = t;
}
public Object get() {
return t;
}
}
Main.java
public class Main {
public static void main(String[] args) {
Box box = new Box();
box.set(10);
//Integer i = box.get(); // 컴파일 에러
Integer i = (Integer) box.get();
System.out.println(i.intValue());
}
}
Integer i = box.get() 은 슈퍼클래스인 Object를 서브 클래스인 Integer가 참조하려는 형태이기 때문에 에러가 발생한다.
그래서 강제로 캐스팅하는 코드를 추가해주고 있다. 반면에 Generic 클래스를 사용하면 캐스팅하는 코드(형 변환)가 없다. Object를 사용하는 것보다 효율적이다. 추가적으로 Generic을 사용하면 컴파일 시점에 잡을 수 없었던 타입 에러를 검출 할 수 있다.
컬렉션 프레임워
해쉬맵은 널 허용 o, 해쉬테이블은 널허용 x
해쉬맵이랑 맵 차이?