[토비의 스프링] 0장
학습 목적 결론부터 이야기하자면, 효율적인 개발을 하고 싶었다. SSAFY 를 통해 급하게 머릿속에 집어 넣은 지식으로 프로젝트를 맡고, 운좋게도 취업까지 할 수 있었다. 하지만 업무를 하면서 점점 한계를 느끼게 되어 스스로 기반을 다지고자 학습하고자 한다. 뿐만 아니라 스프링이 지향하는 바에 따라 개발을 진행하며, 말만 객체지향 언어를 사용하는 게 아닌 객체 지향적인 코드를 짜서 이에 대한 장점을 최대한 활용하기 위함도 있다. 객체 지향 프로그램으로 쉬운 유지보수 쉬운 테스트 코드의 재사용 등을 활용하기 위함이다. 스프링을 사용하는 이유 백엔드 웹 개발에서 스프링은 가장 많이 쓰는 프레임 워크 중 하나이다. 우리나라에서는 대부분의 기업에서 스프링을 사용하고, 전자 정부 표준 프레임 워크이기도 하다. 스..
2024.03.05
no image
인덱스(Index)란 ?
인덱스 인덱스란 추가적인 쓰기 작업과 저장 공간을 활용하여 데이터베이스 테이블의 검색 속도를 향상시키기 위한 자료구조로, 내부 데이터 구조는 트리 구조로 되어 있다. 책의 저자들은 책의 맨 앞 또는 맨 뒤에 색인을 추가하는데, 이는 마치 데이터베이스의 index와 같다 데이터베이스에서도 테이블의 모든 데이터를 검색하면 시간이 오래 걸리기 때문에 데이터와 데이터의 위치를 포함한 자료구조를 생성하여 빠르게 조회할 수 있도록 돕고 있다 인덱스를 활용하면, 데이터를 조회하는 SELECT 외에도 UPDATE나 DELETE의 성능이 함께 향상된다 이유는 해당 연산을 수행하려면 해당 대상을 조회해야만 작업을 할 수 있기 때문이다 UPDATE USER SET NAME='SUBIN' where NAME='KIM'; 만약..
2023.07.18
no image
동시성에 관련된 개념잡기(병렬성, 경쟁조건, 기아상태, 교착상태 등)
동시성 어떤 두 사건이 같은 시간에 일어나는 것 대부분의 웹 서버는 여러 개의 요청을 동시에 수행할 수 있고, 이는 작성한 코드가 동시에 수행될 수 있다. 프로그래밍을 하다 보면 이러한 동시성 처리가 필요한 경우가 있다. 하지만 동시성과 병렬성이 혼돈되어 사용되는 경우가 있어 한 번 정리해볼까한다. 동시성 vs 병렬성 동시성(Concurrency) 병렬성(Parallelism) 동시에 실행되는 것 같이 보이는 것 실제로 동시에 여러 작업이 처리되는 것 싱글 코어에서 멀티 스레드를 동작시키는 방식 멀티 코어에서 멀티 스레드를 동작시키는 방식 한 번에 많은 것을 처리 한 번에 많은 일을 처리 논리적인 개념 물리적인 개념 그림은 싱글 코어와 멀티 코어에서 동작하는 모습을 비교하는 그림이다. 싱글 코어에서는 2..
2023.07.11
CS
no image
Test Code ? 왜 그리고 어떻게 작성해야할까 ?
테스트 코드를 왜 작성하는 것인가 ? 첫번째, 디버깅 비용 절감 개발자가 총 개발 소요 시간중 온전히 요구사항에 대한 기능 개발을 하는 시간이 전체의 비중에 어느정도를 차지할까? 애플리케이션은 항상 내결함성을 가지고 있고 좋은 코드와 설계를 갖추더라도 결함의 존재자체를 부정할 수 없다 그래서 기능에 대한 버그는 항시 발생하고 그것을 해결하기 위해 개발자는 디버깅을 꾸준히 할 수 밖에 없다 프로젝트를 진행하다보면 문제를 해결하는 시간보다 문제를 찾기 위한 시간이 더 많이 소비되는 것을 알 수 있을 것이다. 어느 코드 블록에서 어떤 케이스에서 문제가 발생하는지 알기 힘들기때문이다 그렇다면 테스트 코드가 있는 프로젝트라면 어떨까 ? 견고한 테스트를 작성하더라도 완벽하게 결함을 없앨 순 없다 하지만 테스트 코드..
2023.07.04
TIL
no image
MSA
MSA(MicroService Architecture) 마이크로서비스란 작고, 독립적으로 배포 가능한 각각의 기능을 수행하는 서비스로 구성된 프레임워크라고 할 수 있다. 마이크로서비스는 완전히 독립적으로 배포가 가능하고, 다른 기술 스택(개발 언어, 데이터베이스등)이 사용 가능한 단일 사업 영역에 초점을 둔다 등장배경 Monolithic Architecture 소프트웨어의 모든 구성요소가 한 프로젝트에 통합되어 있는 형태이다. 웹 개발을 예로 들면 웹 프로그램을 개발하기 위해 모듈별로 개발하고, 개발이 완료된 웹 어플리케이션을 하나의 결과물로 패키징하여 배포된 형태를 말한다. 웹의 경우 WAR파일로 빌드되어 WAS에 배포하는 형태를 말하며, 주로 소규모 프로젝트에 사용된다. 하지만 일정 규모 이상의 서비..
2023.07.03
TIL
no image
[Spring] JPA
요약 객체와 관계형 데이터베이스 매핑으로 객체와 테이블 매핑하여 패러다임의 불일치 문제를 해결할 수 있는 방안으로, 생산성, 유지보수, 패러다임 불일치 해결, 데이터 접근 추상화와 벤더 독립성등의 장점을 가지고 있는 프레임워크 JPA(Java Persistence API) 자바 애플리케이션과 JDBC 사이에서 동작하며, ORM 기술 표준으로 사용되는 인터페이스의 모음 즉, 실제적으로 구현된 것이 아니라 구현된 클래스와 매핑을 해주기 위해 사용되는 프레임워크 JPA를 구현하는 대표적인 오픈소스로는 Hibernate가 있다 ORM(Object Relational Mapping) 객체와 관계형 데이터베이스의 데이터를 매핑하는 기술 ORM 프레임워크가 객체와 데이터베이스 중간에서 매핑 객체와 테이블을 매핑하여 ..
2023.06.28
no image
Redis ?
무조건 RDBMS를 사용해야하는 걸까? RDBMS는 실제 물리적 장치에 저장하기때문에 데이터를 영속적으로 관리할 수 있지만, 입출력에 다소 시간이 걸리는 단점이 존재한다. 이러한 여러가지 부분에 있어서 인증 토큰에 대해서는 Redis를 사용한다. Redis Remote Dictionary Server 약자로 Key-Value 구조의 비정형 데이터를 저장하고 관리하기 위한 오픈 소스 기반의 비관계형 데이터 베이스 관리 시스템 (NoSQL) 특징 Key-Value 구조의 비정형 데이터를 저장하고 관리하기 위한 오픈 소스 기반의 비관계형 데이터 베이스 관리 시스템 (NoSql) 데이터베이스, 캐시, 메세지 브로커로 사용된다 In-Memory 기반의 데이터 처리 및 저장을 제공하여 속도가 빠르지만 서버가 꺼지면..
2023.05.26
TIL
no image
FCM(Firebase Cloud Messaging)
FCM FCM은 Firebase Cloud Messaging의 약자로, 무료로 메시지를 안정적으로 전송할 수 있는 교차 플랫폼 메시징 솔루션이다. 모든 사용자에게 알림 메세지를 전송할 수도 있고, 그룹을 지어 메시지를 전송할 수도 있다. Firebase의 서비스는 요금 정책에 따라, 이용할 수 있는 범위가 다르지만 FCM은 요금 정책에 구분 없이 무료로 사용하는 것이 가능하다. 왜 사용하는가 ? FCM을 이용하면 플랫폼에 종송되지 않고 푸쉬 메시지를 전송할 수 있다 iOS, Android, Web 각 플랫폼에서 푸쉬 메시지를 보내려면 각 플랫폼 환경 iOS (APNS), Android (GCM)별로 개발해야 하는 불편함이 있는데 이를 하나로 통합하는 솔루션으로 플랫폼에 종속되지 않고 Push 메시지를 전..
2023.05.26
TIL

[토비의 스프링] 0장

개발의 숩
|2024. 3. 5. 14:36

학습 목적 

결론부터 이야기하자면, 효율적인 개발을 하고 싶었다.

SSAFY 를 통해 급하게 머릿속에 집어 넣은 지식으로 프로젝트를 맡고, 운좋게도 취업까지 할 수 있었다.

하지만 업무를 하면서 점점 한계를 느끼게 되어 스스로 기반을 다지고자 학습하고자 한다.

뿐만 아니라 스프링이 지향하는 바에 따라 개발을 진행하며, 

말만 객체지향 언어를 사용하는 게 아닌 객체 지향적인 코드를 짜서 이에 대한 장점을 최대한 활용하기 위함도 있다. 

객체 지향 프로그램으로 

  1. 쉬운 유지보수
  2. 쉬운 테스트
  3. 코드의 재사용

등을 활용하기 위함이다. 

 

스프링을 사용하는 이유

백엔드 웹 개발에서 스프링은 가장 많이 쓰는 프레임 워크 중 하나이다. 

우리나라에서는 대부분의 기업에서 스프링을 사용하고, 전자 정부 표준 프레임 워크이기도 하다.

스프링을 공부하게 된 계기또한 그렇다.

 

이뿐만 아니라 토비의 스프링을 읽으며 이해한 바는 아래와 같다.

엔터프라이즈 시스템 개발은 비즈니스적으로나 기술적으로나 점점 복잡해져왔고, 지금도 복잡해지고 있다.

즉, 개발자가 고려해야할 사항이 많아지고 그만큼 개발을 하기가 어려워졌다.

하지만 이러한 복잡함은 제거할 수 없는 요소이다. 대신 그 복잡함을 효과적으로 상대할 수 있는 전략과 기법이 필요해졌고

일단 가장 큰 문제인 비즈니스 복잡함과 기술적인 복잡함을 분리해내는 것이다.

이 문제를 깔끔하게 해결하는 것이 스프링이다.

 

 


 

스프링이란 무엇인가

  • 자바 기반의 다양한 애플리케이션을 만드는 것을 도와준다
    • 웹 뿐만 아니라 배치 등 다양한 영역을 포괄한다
  • 애플리케이션 코드에 언제나 존재하는 공통 영역에 대한 작성을 쉽고 깔끔하게 만들어준다
    • 공통 프로그래밍 모델이라는 것을 지원한다
    • 트랜잭션 처리, 다국어 처리, AOP 처리 등 애플리케이션에는 언제나 공통 영역이 존재한다
  • 애플리케이션에 자주 사용되는 다양한 기술 API도 제공한다
    • CGIB , Jackson(Object Mapper) 등

 

 

 

 

스프링 컨테이너

  • 스프링 설정 정보 (@Configuration) 로 생성된 객체들을 일반적으로 싱글톤으로 관리한다.
    • 물론 빈 스코프 설정에 따라 항상 싱글톤은 아닐 수 있다

객체지향 원칙을 지키기 어려운 싱글톤의 단점을 해소해준다

 

 

공통 프로그래밍 모델

IoC/DI

  • 제어의 역전과 의존성 주입
  • 싱글톤 패턴을 이용하면서도 객체지향의 다양한 이점을 활용할 수 있게 해준다
    • 변화에 유연한 설계를 돕는다

서비스 추상화

  • 비슷한 역할을 하는 다른 기술들을 묶어줌
  • ex) ProxyFactory는 JDK 동적 프록시, CGLB등 프록시 기술 선택의 기로에서 해방 시켜준다
  • es) DB 벤더에 영향을 받지 않는 트랜잭션 처리 기술

AOP

  • 애플리케이션에서 많은 메서드, 클래스 등에 공통 부가기능을 넣고 싶을 때 중복된 코드 없이 이를 실현할 수 있게 해준다
  • 로깅, 소요시간 측정 등에 사용될 수 있다

인덱스(Index)란 ?

개발의 숩
|2023. 7. 18. 17:44

인덱스

인덱스추가적인 쓰기 작업과 저장 공간을 활용하여 데이터베이스 테이블의 검색 속도를 향상시키기 위한 자료구조로, 내부 데이터 구조는 트리 구조로 되어 있다.

책의 저자들은 책의 맨 앞 또는 맨 뒤에 색인을 추가하는데, 이는 마치 데이터베이스의 index와 같다

데이터베이스에서도 테이블의 모든 데이터를 검색하면 시간이 오래 걸리기 때문에 데이터와 데이터의 위치를 포함한 자료구조를 생성하여 빠르게 조회할 수 있도록 돕고 있다

 

 

 

 

 

인덱스를 활용하면, 데이터를 조회하는 SELECT 외에도 UPDATE나 DELETE의 성능이 함께 향상된다

이유는 해당 연산을 수행하려면 해당 대상을 조회해야만 작업을 할 수 있기 때문이다

UPDATE USER SET NAME='SUBIN' where NAME='KIM';

만약 index를 사용하지 않은 컬럼을 조회해야 하는 상황이라면,

전체를 탐색하는 Full Scan(전체를 비교하여 탐색)을 수행하기 때문에 처리 속도가 떨어진다.

 

 

 

인덱스의 관리

DBMS는 index를 항상 최신의 정렬된 상태로 유지해야 원하는 값을 빠르게 탐색할 수 있다

그렇기 때문에 인덱스가 적용된 컬럼에 INSERT,UPDATE, DELETE가 수행된다면

각각 다음과 같은 연산을 추가적으로 해주어야 하며 그에 따른 오버헤드가 발생한다

  • INSERT : 새로운 데이터에 대한 인덱스를 추가함
  • UPDATE : 삭제하는 데이터의 인덱스를 사용하지 않는다는 작업을 진행함
  • DELETE : 기존의 인덱스를 사용하지 않음 처리하고, 갱신된 데이터에 대해 인덱스를 추가함

 

 

 

 

인덱스의 장단점

장점

  • 테이블을 조회하는 속도와 그에 따른 성능을 향상시킬 수 있다
  • 전반적인 시스템의 부하를 줄일 수 있다

단점

  • 인덱스를 관리하기 위해 DB의 약 10%에 해당하는 저장공간이 필요하다
  • 인덱스를 관리하기 위해 추가 작업이 필요하다
  • 인덱스를 잘못 사용할 경우 오히려 성능이 저하되는 역효과가 발생할 수 있다

 

 

만약 CREATE, DELETE, UPDATE가 빈번한 속성에 인덱스를 걸게 되면 인덱스의 크기가 비대해져서 성능이 오히려 저하되는 역효과가 발생할 수 있다. 이유 중 하나는 DELETE 와 UPDATE 연산 때문이다

앞서 설명한대로, UPDATE와 DELETE는 기존의 인덱스를 삭제하지 않고, 사용하지 않음 처리를 한다

만약 어떤 테이블에 UPDATE와 DELETE가 빈번하게 발생된다면 실제 데이터는 10만건이지만 인덱스는 훨씬 많이 존재하게 되어, SQL문 처리시 비대해진 인덱스에 의해 오히려 성능이 떨어지게 될 것이다

 

 

 

 

인덱스를 사용하면 좋은 경우

  • 규모가 작지 않은 테이블
  • INSERT, UPDATE, DELETE가 자주 발생하지 않는 컬럼
  • JOIN이나 WHERE 또는 ORDER BY에 자주 사용되는 컬럼
  • 데이터의 중복도가 낮은 컬럼
  • 기타 등등

인덱스를 사용하는 것만큼이나 생성된 인덱스를 관리해주는 것도 중요하다

그러므로 사용되지 않는 인덱스는 바로 제거해주어야 한다

 

 

 

 

 

인덱스의 자료구조

인덱스를 구현하기 위해서는 다양한 자료구조를 사용할 수 있는데, 가장 대표적인 해시 테이블B+Tree 대해 알아보도록 하자

 

해시 테이블(Hash Table)

해시 테이블은 (Key, Value)로 데이터를 저장하는 자료구조 중 하나로 빠른 데이터 검색이 필요할 때 유용하다

해시 테이블은 Key 값을 이용해 고유한 index를 생성하여 그 index에 저장된 값

을 꺼내오는 구조이다

 

해시 테이블 기반의 DB 인덱스는 (데이터 = 컬럼의 값, 데이터의 위치)를 (Key, Value)로 사용하여 컬럼의 값으로 생성된 해시를 통해 인덱스를 구현한다

 

 

해시 테이블의 시간 복잡도는 O(1)이며 매우 빠른 검색을 지원한다

 

 

하지만, DB 인덱스에서 해시 테이블이 사용되는 경우는 제한적인데, 해시가 등호 연산에만 특화되었기 때문이다

해시 함수는 값이 1이라도 달라지면 완전히 다른 해시 값을 생성하는데, 이러한 특성에 의해 부등호 연산(>,<)이 자주 사용되는 데이터베이스 검색을 위해서는 해시 테이블이 적합하지 않다

 

 

즉, 예를 들면 “나는”으로 시작하는 모든 데이터를 검색하기 위한 쿼리문은 인덱스의 혜택을 전혀 받지 못하게 된다.

이러한 이유로 데이터베이스의 인덱스에서는 B+Tree가 일반적으로 사용된다.

 

B+Tree

B+Tree는 DB의 인덱스를 위해 자식 노드가 2개 이상인 B-Tree를 개선시킨 자료구조로, 하드 디스크상에 구축하기에 알맞은 데이터 구조를 가지고 있어 DB에서 많이 사용된다.

 

 

BTree에 의해 어떻게 탐색이 빨라지는가

BTree에 데이터를 삽입할 때는 일정한 규칙에 따라 삽입할 필요가 있는데, 그 규칙 덕분에 검색할 때 일부 노드를 순회하는 것만으로 자연스럽게 찾고자 하는 데이터에 도달하게 된다

B+Tree는 모든 노드에 데이터를 저장했던 BTree와 다른 특성을 가지고 있다

  • 리프노드(데이터 노드)만 인덱스와 함께 데이터를 가지고 있고, 나머지 노드(인덱스 노드)들은 데이터를 위한 인덱스만 갖는다
  • 리프노드들은 LinkedList로 연결되어 있다
  • 데이터 노드 크기는 인덱스 노드의 크기와 같지 않아도 된다

B+트리는 각 노드 내에 자식 노드로의 포인터만 가지고 있고 포인터 이외에 데이터로서의 실제 값 등은 제일 마지막인 잎 노드에만 가지고 있는 구조로 DB에 데이터를 저장하는데 더 최적화된 데이터 구조이다

 

 

데이터베이스의 인덱스 컬럼은 부등호를 이용한 순차 검색 연산이 자주 발생될 수 있다

이러한 이유로 BTree의 리프노드들을 LinkedList로 연결하여 순차검색을 용이하게 하는 등 BTree를 인덱스에 맞게 최적화하였다

비록 B+Tree은 O(log n)의 시간 복잡도를 갖지만 해시 테이블보다 인덱싱에 더욱 적합한 자료구조가 되었다

물론, Best Case에 대해 리프 노드까지 가지 않아도 탐색할 수 있는 BTree에 비해 무조건 리프 노드까지 가야한다는 단점도 있다

 

 

 

 

인덱스 효과의 예

대규모가 되면 될수록 인덱스를 준비해놓느냐 아니냐에 따라 차이가 나게 된다

개인적인 용도의 작은 애플리케이션 정도라면 인덱스를 전혀 사용하지 않아도 충분한 속도로 동작한다

 

데이터가 1000건 정도라면 오히려 트리를 먼저 순회하는 오버 헤드가 더 커서 그냥 처음부터 찾아 내려가는 편이 더 빠른 경우일 수도 있다

그러나, 크기가 커지면 인덱스 없이는 시작부터 액세스할 수 없는 상황이므로 인덱스는 중요하다

 

  • MySQL
    • MySQL은 레코드 총 건수를 보고 인덱스를 사용하지 않는 편이 더 빠르다고 판단되면, 사용하지 않는 최적화 작업을 내부에서 어느정도 수행한다
    • MySQL에서는 인덱스를 걸어놓고 있는 컬럼을 대상으로 한 쿼리라도 던지는 SQL에 따라서는 인덱스가 사용되거나 사용되지 않기도 한다
    • MySQL에서 alter table 명령 등으로 명시적으로 인덱스를 추가한 경우 이외에도 Primary Key, UNIQUE 제약을 건 컬럼에도 인덱스를 가지고 있다 (show index 명령으로 인덱스 내용 확인)

 

복수의 칼럼이 인덱스 작용의 대상이 되는 경우 하나의 칼럼만 인덱스로 사용될 것이다

 

select * from entry where url like ‘~~~’ order by timestamp

url, timestamp 가 모두 index 걸려있을 때, 하나만 인덱스를 사용하고 나머지는 사용하지 않게 된다.

위의 경우 두개 모두 index로 태우려고 할 경우 (url, timestamp)를 쌍으로 한 복합 인덱스를 사용해야 한다

 

 

 

explain 명령에서 속도에 유의하라

자신이 SQL 수반하는 프로그램을 개발할 때 속도에 신경 쓰고자 할 때는 explain 명령으로 자신이 던지려고 하는 SQL에 제대로 인덱스가 작용하는지 여부를 확인하면서 개발하면 좋다

인덱스 작용법이라는 의미에서는 Extra 열도 중요하다

  • where 이외에 Using filesord, Using temporary가 나올 경우가 있다.
    • 각각 레코드 정렬에 외부(외부 파일을 사용한 정렬)이나 임시 테이블이 필요하다는 의미다
    • 그다지 틀이 좋은 쿼리라고 할 수 없으므로 가능한 나오지 않도록 쿼리나 인덱스를 튜닝해갈 필요가 있다.

explain 명령 자체의 결과는 실제로 SQL을 던졌을 때의 평가가 아니기때문에 explain 명령어가 빠르다고 빠른 쿼리는 아니다

 

 

 

💡 왜 파일 정렬이나 임시 테이블을 사용하지 않는 편이 좋은가

  • 임시 테이블은 내부 임시테이블 크기가 커서 디스크에 생성되면 성능 이슈가 발생하며, 임시테이블을 사용한 정렬이 FileSort에 해당되는데 이는 레코드가 많아질수록 쿼리의 응답 속도가 현저히 떨어지게 된다

 

 

마무리

인덱스에 대해 간단히 핵심만 다루고 있지만, PK, Index에 대해 자세히 알고 있는 것이 중요하다

 

 

 

 

더 알아보기

임시 테이블(Using Temporary)

MySQL 엔진이 스토리지 엔진으로부터 받아온 레코드를 정렬하거나 그룹핑 할 때는 내부적인 임시 테이블을 사용한다

MySQL 엔진이 사용하는 임시 테이블은 처음에는 메모리에 생성됐다가 테이블의 크기가 커지면 디스크로 옮겨진다

 

원본 테이블의 스토리지 엔진과 관계없이 임시 테이블이 메모리를 사용할 때는 MEMORY 스토리지 엔진을 사용하며,

디스크에 저장될 때는 MyISAM 스토리지 엔진을 이용한다

 

 

임시 테이블이 필요한 경우

  • ORDER BY와 GROUP BY에 명시된 칼럼이 다른 쿼리
  • ORDER BY나 GROUP BY에 명시된 칼럼이 조인의 순서상 첫번째 테이블이 아닌 쿼리
  • DISTINCT와 ORDER BY가 동시에 존재하는 경우 또는 DISTINCT가 인덱스로 처리되지 못하는 쿼리
  • UNION이나 UNION DISTICT가 사용된 쿼리
  • UNION ALL이 사용된 쿼리
  • 쿼리의 실행 계획에서 select_type이 DERIVED인 쿼리

해당 6가지 중 1~3번째 경우에는 Extra 칼럼에 “Using Temporary”가 표시되며, 4~6번째 경우에는 Extra 칼럼에 “Using Temporary”가 표시되지 않지만 임시테이블이 사용된다

 

 

주의 사항

내부 임시 테이블이 크기가 커서 디스크에 생성되면 성능 이슈가 발생한다

내부 임시 테이블이 디스크에 생성되었는지 여부를 파악하려면 아래의 명령어로 가능하다

SHOW SESSION STATUS LIKE 'Create_tmp%';

해당 쿼리의 결과로 생성된 임시 테이블의 상태를 파악할 수 있다

 

만약 처리해야하는 레코드 건수가 100만 건이라고 가정한다면, 해당 건의 데이터 디스크에 저장된다면 큰 부하가 발생하게 되므로 각별히 주의를 기울여야 한다

 

 

드라이빙 테이블 정렬(Using Filesort)

MySQL의 정렬 처리는 크게 2가지로 나뉜다

  • index를 이용한 정렬
  • File sort(”Using filesort”)

 

인덱스를 사용할 수 있는 경우

  1. ORDER BY에 명시된 칼럼이 제일 먼저 읽는 테이블에 속해야 한다
  2. ORDER BY절의 순서가 인덱스와 일치해야한다
  3. WHERE 절에 첫 번째 읽는 테이블에 대한 조건이 있다면, ORDER BY절도 같은 인덱스를 사용할 수 있어야 한다

인덱스를 사용하는 정렬은 완벽한 조건을 요구하는 만큼 처리가 빠르다

인덱스의 값이 정렬되어 있기때문에 해당 인덱스를 읽기만 하면 된다

 

 

MySQL은 인덱스를 통해 정렬할 수 없다면 FileSort를 사용한다

위에서의 임시 테이블을 사용한 정렬도 FileSort에 해당한다

 

FileSort는 레코드가 많아질수록 쿼리의 응답 속도가 현저히 떨어지게 된다

 

 

File Sort를 사용하는 경우

  1. 드라이빙 테이블만 정렬 (”Using filesort”)
  2. 임시 테이블을 이용한 정렬 (”Using temporary, Using filesort”)

드라이빙 테이블만 정렬된다는 방식은 조회하는 테이블 중 먼저 액세스되는 테이블만 SortBuffer에서 정렬해서 나머지 테이블과 조합하는 방식이다.

 

 

이 경우 SortBuffer로 테이블을 하나 옮겨서 정렬하는 작업이 필요하지만 임시 테이블을 이용하는 방법보다는 낫다

 

 

드라이빙 테이블만 정렬하는 방법을 사용할 수 없다면 임시 테이블을 사용해야 한다

임시 테이블을 이용한 정렬은 2개 이상의 테이블을 조인해서 그 결과를 전부 임시 테이블에 넣어서 정렬하는 방식이다

 

임시 테이블을 이용한 정렬은 모든 테이블의 결과를 임시 테이블에 넣고 정렬을 수행하므로 가장 느리다

특히, 레코드가 많아지면 임시 테이블이 디스크에 저장되면서, 대규모 서비스에서 치명적인 I/O 부하가 발생한다

 

 

이 경우 Application Layer나 Presentation Layer에서 정렬을 해서 뷰에 노출하는 것을 고려할 수 있다

 

 

 

🍀 참조

SQL - Using Temporary, Using Filesort 정리 (+ 임시 테이블, 파일 정렬)

 

 

동시성

어떤 두 사건이 같은 시간에 일어나는 것

대부분의 웹 서버는 여러 개의 요청을 동시에 수행할 수 있고, 이는 작성한 코드가 동시에 수행될 수 있다.

 

 

프로그래밍을 하다 보면 이러한 동시성 처리가 필요한 경우가 있다.

하지만 동시성과 병렬성이 혼돈되어 사용되는 경우가 있어 한 번 정리해볼까한다.

 

동시성 vs 병렬성

 

동시성(Concurrency) 병렬성(Parallelism)
동시에 실행되는 것 같이 보이는 것 실제로 동시에 여러 작업이 처리되는 것
싱글 코어에서 멀티 스레드를 동작시키는 방식 멀티 코어에서 멀티 스레드를 동작시키는 방식
한 번에 많은 것을 처리 한 번에 많은 일을 처리
논리적인 개념 물리적인 개념

 

그림은 싱글 코어와 멀티 코어에서 동작하는 모습을 비교하는 그림이다.

 

싱글 코어에서는 2개의 작업을 동시에 실행되는 것처럼 보이기 위해 번갈아 가면서 작업을 수행한다. 

이때, 다른 작업으로 바꾸어 실행할 때 내부적으로 Context switch가 일어난다

자세한 문맥교환은 다른 페이지에서 다루도록 하겠다.

 

 

그렇다면 우리가 동시성 이슈를 해결해야하는 이유는 무엇일까 ?

 

진행했던 프로젝트가 실제 적용될 수 있는 사례와 유사하니 이로 예시를 들어보겠다.

 

수량이 마지막 1개가 남아있는 시점에서 동시에 두 명의 유저가 요청을 하게 되었을 때 동시성 이슈가 해결되지 않을 경우, 둘 모두 성공하여 수량은 1개인데, 가져야 하는 사람이 2명인 난감한 상황이 펼쳐지게 된다. 이와 같은 상황에서 둘 모두 성공하는 것이 아니라 한 명만이 성공해야 하기때문에 동시성 이슈를 해결해야 한다.

 

위와 같은 상황을 경쟁 조건(race condition)이라고 한다.

 

 

 

경쟁 조건

여러 프로세스 및 스레드가 동시에 동일한 데이터(공유 데이터)를 조작할 때 타이밍이나 접근 순서에 따라 예상했던 결과가 달라질 수 있는 상황을 의미한다.

 

 

 

동시성 이슈의 문제점

  • 공유 데이터에 대해 예상 결과가 다르지만 오류가 발생하지 않는다.
  • 코드를 작성할 때는 로컬에서 개발하기때문에 파악하기 힘들다.
  • 비정형적으로 발생하기때문에 디버깅이 힘들 수 있다.

 

 

 

동시성 이슈를 해결하면서 주의사항

뮤텍스, 세마포어, Lock 과 같은 경우 상호 배제만 해결해주기때문에 교착상태기아상태를 발생할 수 있다.

 

 

기아상태 (Starvation)

특정 프로세스의 우선 순위가 낮아서 원하는 자원을 계속 할당 받지 못하는 상태를 말한다.

 

 

교착상태

교착상태(Dead Lock)은 둘 이상의 프로세스들이 자원을 점유한 상태에서 서로 다른 프로세스가 점유하고 있는 자원을 요구하며 무한정 기다리는 현상을 의미한다.

 

 

기아상태와 교착상태의 차이

교착상태는 프로세스가 자원을 얻지 못해 다음 처리를 하지 못하는 상태를 말하고,

기아상태는 프로세스가 원하는 자원을 계속 할당 받지 못하는 상태이다.

즉, 교착 상태는 여러 프로세스가 동일한 자원 점유를 원할 때 발생하고,

기아 상태는 여러 프로세스가 자원을 점유하기 위해 경쟁할 때 특정 프로세스는 영원히 자원 할당을 받지 못하는 것이다.

 

 

 

 

교착 상태 발생 조건

주로 멀티 프로그래밍 환경에서 한정된 자원을 얻기 위해 서로 경쟁하는 상황에서 발생한다.

교착상태가 발생하기 위해서는 다음의 4가지 조건이 충족되어야 하는데, 이 네가지 조건 중 하나라도 충족되지 않으면 교착상태가 발생하지 않는다.

 

  • 상호 배제(Mutual Exclusion)

자원은 한 번에 한 프로세스만이 사용할 수 있어야 한다.

상호 배제 기법에는 뮤텍스, 세마포어 등이 있다.

이 방법들은 상호 배제만 해결해주기 때문에 데드락기아상태가 발생할 수 있다.

  • 뮤텍스
    • Key에 해당하는 어떤 오브젝트가 있으며 이 오브젝트를 소유한 (스레드, 프로세스) 만이 공유자원에 접근할 수 있다.
    • 임계영역을 가진 스레드들의 실행 시간이 서로 겹치지 않고 각각 단독으로 실행되도록 하는 기술
    • 뮤텍스 객체는 제어되는 섹션에 하나의 스레드만 허용하기때문에 해당 섹션에 접근하려는 다른 스레드들을 강제적으로 막음으로써 첫 번째 스레드가 해당 섹션을 빠져나올 때까지 기다리도록 한다
  • 세마포어
    • 멀티 프로그래밍 환경에서 공유된 자원에 대한 접근을 제한하는 방법
    • 현재 공유자원에 접근할 수 있는 스레드, 프로세스의 수를 나타내는 값을 기반으로 한다
    • 세마포어는 공유 리소스에 접근할 수 있는 최대 허용치만큼 동시에 사용자 접근을 할 수 있게 한다.
    • 스레드들은 리소스 접근을 요청할 수 있고, 세마포어에서는 카운트가 하나씩 줄어들게 되며 리소스 사용을 마쳤다는 신호를 보내면, 세마포어 카운트가 하나 늘어나게 된다.
    • 이때 세마포어에서 발생할 수 있는 단점은 DeadLock 교착상태이다
  • 모니터

 

뮤텍스와 세마포어의 차이

  • 세마포어는 뮤텍스가 될 수 있지만, 뮤텍스는 세마포어가 될 수 없다.
  • 세마포어는 소유할 수 없으며, 뮤텍스는 소유할 수 있고, 소유주가 그에 대한 책임을 가진다.
  • 세마포어는 동기화 대상이 여러 개일때 사용하고, 뮤텍스는 동기화 대상이 오로지 하나일 때 사용된다.

 

 

  • 점유와 대기(Hold and Wait)

최소한 하나의 자원을 점유하고 있으면서 다른 프로세스에 할당되어 사용하고 있는 자원을 추가로 점유하기 위해 대기하는 프로세스가 있어야 한다.

 

  • 비선점(Non-preemption)

다른 프로세스에 할당된 자원은 사용이 끝날 때까지 강제로 빼앗을 수 없어야 한다.

 

  • 환형 대기(Circular Wait)

서로 다른 공유자원을 사용하기 위해 대기하는 프로세스들이 원형으로 구성되어 있어 자신에게 할당된 자원을 점유하면서 앞이나 뒤에 있는 프로세스의 자원을 요구한다.

 

 

교착 상태 해결 방안

  • 예방(Prevention)

교착상태가 발생하지 않도록 사전에 시스템을 제어하는 방법으로, 교착상태 발생의 4가지 조건 중에서 어느 하나를 제거한다. 즉, 자원 낭비가 가장 심한 해결 방법이다.

 

  • 상호 배제 부정 : 한 번에 여러 개의 프로세스가 공유 자원을 사용할 수 있도록 한다.
  • 점유 및 대기 부정 : 프로세스가 실행되기 전 필요한 모든 자원을 할당하여 프로세스 대기를 없애거나 자원이 점유되지 않은 상태에서만 자원을 요구한다.
  • 비선점 부정 : 자원을 점유하고 있는 프로세스가 다른 자원을 요구할 때 점유하고 있는 자원을 반납하고, 요구한 자원을 사용하기 위해 기다린다.
  • 환형대기 부정 : 자원을 선형 순서로 분류하여 고유 번호를 할당하고, 각 프로세스는 현재 점유한 자원의 고유 번호보다 앞이나 뒤 어느 한쪽 방향으로만 자원을 요구하도록 한다.

 

 

  • 회피(Avoidance)

교착상태가 발생할 가능성을 배제하지 않고 교착상태가 발생하면 적절히 피해나가는 방법으로, 주로 은행원 알고리즘(Banker’s Algorithm)이 사용된다.

 

은행원 알고리즘

  1. 은행원 알고리즘은 다익스트라가 제안한 기법으로, 은행에서 모든 고객의 요구가 충족되도록 현금을 할당하는데서 유래한 기법이다.
  2. 각 프로세스에게 자원을 할당하여 교착상태가 발생하지 않으면 모든 프로세스가 완료될 수 있는 상태를 안전상태, 교착상태가 발생할 수 있는 상태를 불안전 상태라고 한다.
  3. 은행은 자원을 할당한 후에도 안정 상태로 남아있는지 검사하여 안정 상태에 있으면 자원을 할당하고 그렇지 않으면 다른 프로세스들이 자원을 해제할 때까지 대기한다.
  4. 은행원 알고리즘을 적용하기 위해서는 자원의 양과 사용자(프로세스) 수가 일정해야 한다.
  5. 은행원 알고리즘은 프로세스의 모든 요구를 유햔한 시간안에 할당하는 것을 보장한다.

 

 

  • 탐지(Detection)

시스템에 교착상태가 발생했는지 점검하여 교착상태에 있는 프로세스와 자원을 발견한다.

교착 상태 발견 알고리즘과 자원 할당 그래프등을 사용할 수 있다.

 

 

  • 복구(Recovery)

교착상태를 일으킨 프로세스를 종료하거나 교착상태의 프로세스에 할당된 자원을 선점하여 프로세스나 자원을 회복한다.

 

프로세스 종료

  • 교착상태에 있는 프로세스를 종료
  • 교착상태에 있는 프로세스들을 하나씩 종료

 

자원 선점

  • 교착상태의 프로세스가 점유하고 있는 자원을 선점하여 다른 프로세스에게 할당하며, 해당 프로세스를 일시 정지시키는 방법이다. 우선순위가 낮은 프로세스, 수행된 정도가 적은 프로세스, 사용되는 자원이 적은 프로세스등을 위주로 해당 프로세스의 자원을 선점한다.

테스트 코드를 왜 작성하는 것인가 ?

 

첫번째, 디버깅 비용 절감

개발자가 총 개발 소요 시간중 온전히 요구사항에 대한 기능 개발을 하는 시간이 전체의 비중에 어느정도를 차지할까?

애플리케이션은 항상 내결함성을 가지고 있고 좋은 코드와 설계를 갖추더라도 결함의 존재자체를 부정할 수 없다 그래서 기능에 대한 버그는 항시 발생하고 그것을 해결하기 위해 개발자는 디버깅을 꾸준히 할 수 밖에 없다

 

 

프로젝트를 진행하다보면 문제를 해결하는 시간보다 문제를 찾기 위한 시간이 더 많이 소비되는 것을 알 수 있을 것이다. 어느 코드 블록에서 어떤 케이스에서 문제가 발생하는지 알기 힘들기때문이다

 

 

그렇다면 테스트 코드가 있는 프로젝트라면 어떨까 ?

 

견고한 테스트를 작성하더라도 완벽하게 결함을 없앨 순 없다

하지만 테스트 코드를 통해 오류를 줄일 수 있고, 빠르게 대처할 수 있다

 

테스트의 분류

아래의 그림과 같이 범위와 비중에 따라 세분류로 나누어지고 각각의 역할을 가지고 있다

테스트 피라미드

  • Unit Test (단위 테스트)
    • 도메인 모델과 비즈니스 로직을 테스트, 작은 단위의 코드 및 알고리즘 테스트
    • 하나의 모듈을 기준으로 독립적으로 진행되는 가장 작은 단위 테스트로, 여기서의 모듈은 애플리케이션에서 작동하는 하나의 메서드 혹은 기능을 의미한다
    • 해당 단위의 기능을 검증하고 예상되는 결과를 확인하는 목적으로 사용된다
  • Integration Test(통합 테스트)
    • 코드의 주요 흐름들을 통합적으로 테스트하며 주요 외부 의존성(ex. 데이터베이스)에 대해서 테스트
    • 여러 개의 모듈이나 시스템 구성 요소가 함께 동작할 때, 이들 간의 상호작용을 테스트하여 전체적인 시스템의 동작이 예상대로 이루어지는지 검증하는 테스트 방법으로 DB에 접근하거나 전체 코드와 다양한 환경이 제대로 작동하는지 확인하는데 필요한 모든 작업을 수행할 수 있다
  • e2e Test (인수 테스트, Acceptance Test)
    • 최종 사용자의 흐름에 대한 테스트이며 외부로부터의 요청부터 응답까지 기능이 잘 동작하는지에 대한 테스트
    • 즉, 사용자 시나리오를 기반으로 작성하여 소프트웨어가 제공해야 할 기능이나 사용자가 어떠한 목적으로 소프트웨어를 사용하는지에 대한 내용을 담고 있으며, 일반적으로 기능 테스트 이후 수행된다

이렇게 구분한 테스트 구간의 경계로 인해 문제가 되는 코드의 범위와 케이스를 빠르게 파악하고 수정할 수 있게 되었다.

테스트로 인해 결함을 최소화시켜 디버깅에 소모되는 시간을 줄어듬으로써, 서비스 개발자가 비즈니스 개발에 집중하면서 생산성 향상에 도움을 주게 된다.

 

 

두번째, 코드 변경에 대한 불안감 해소

애플리케이션에서 기능은 단일 하나의 요소(함수, 객체, 도메인)로 이루어지지 않고 여러 요소들이 서로 상호작용하고 협력하여 만들어지기때문에 하나의 기능을 수정할 때 구성된 요소가 다른 기능과 협력하고 있고 영향을 준다

그렇기때문에 회귀 버그를 겪게 되는 것이다

 

그렇다면 회귀 버그를 완전히 차단하고 예방할 수 있을까

 

회귀 버그는 예방하는 것이 아니라 관리하고 대처해야 한다

다시 말해 회귀 테스트를 해야 한다

 

회귀 테스트는 기능 추가나 오류 수정으로 인해 새롭게 유입되는 오류가 없는지 검증한다

테스트 코드는 그때 당시의 기능을 만들기 위해서만 필요한 코드가 아니다

그 이후에

  • 요구사항이 변경되어 기존 코드를 수정하거나
  • 더 나은 코드를 위해 리팩토링을 하거나

서비스가 지속 가능하게 발전하기 위해 필요한 코드이다

 

 

세번째, 더 나은 문서 자료

좋은 코드를 작성하기 위해 잘 읽히는 코드, 가독성 좋은 코드를 작성하기 위해 노력한다

하지만 서비스 복잡도가 늘어남에 따라 코드의 양이 많아지고 코드의 복잡성가 높아지게 된다

이러한 복잡한 요구사항이 중첩되어 있는 기능들은 신규 입사자나 투입자들이 이 코드를 이해하는데 많은 불편함을 겪게한다

 

 

보통은 편의를 위해 따로 문서화를 해두지만 쉽게 방치되는 문서화의 문제점이 있다

 

 

이 문제점이 발생하는 이유가 무엇일까?

두 대상을 분리하고 물리적인 거리감이라는 이유로 코드의 수정에 맞춰 문서의 최신화가 잘 이루어지지 않는 경우가 많기때문에 소스 코드외의 별도의 문서자료들은 관리 대상으로서 쉽게 제외되기때문에 신뢰하기 어려워진다

 

 

테스트를 작성할 때 가장 먼저 명세를 작성하면서 코드의 실제 동작을 기술함으로써 이 코드가 어떤 역할을 가졌는지 이해하는데 도와준다

기존에 중복된 메일이 있는 경우 회원가입을 할 수 없습니다.

문서화 테스트는 기능과 코드를 이해하는 데 도움을 준다

 

 

네번째, 좋은 코드는 테스트하기 쉽다

좋은 코드는 “변경하기 쉬운”이라는 형용사를 가지고 있다

이 의미는 약한 결합도를 가지고 있는 코드를 뜻하며 반대로 강결합이 되어있는 코드는 유지비용이 증감되어 저품질코드로 분류되어진다

 

외부의 영향을 받거나 내부적으로 의존성을 가지고 있는 코드는 변경에 유연하게 대응하지 못하고 재사용하기 어려운 코드들이다. 그렇기때문에 테스트를 작성하기 어려운 코드가 만들어지는 것이다

 

그렇다고 테스트하기 쉬운 코드가 모두 좋은 코드가 되는 것은 아니다. 하지만 테스트를 작성하면서 하나의 좋은 코드의 지표를 아래와 같이 세울 수 있게 된다

“만약 내가 작성한 코드가 테스트하기 어려운 코드라면 냄새나는 코드일 가능성이 높아”

 

다섯번째, 테스트 자동화

개발자의 기도메타는 본인이 작성한 코드가 실제 운영 환경에 배포됐을 때 불안감에 휩싸여 기도를 시작한다

 

하지만 자동화 테스트가 있는 순간부터 우리는 CI에서 우리가 작성한 테스트 코드로 버그가 배포되는 것을 방지할 수 있다.

변경에 대한 내성과 회귀 버그를 지속적인 코드 병합 단계에서 확인할 수 있으므로 소프트웨어의 품질 또한 높여준다

 

즉, 테스트 코드가 존재함으로써 안전감 있는 프로젝트, 개발자의 모습을 볼 수 있게 된다

 

 

코드를 잘 작성하는 방법 with Jest

지금까지는 “테스트 코드를 왜 작성하는 것인가?”에 대해서 5가지 이유를 알아보았다

테스트 코드를 작성해야 되는 이유를 알았다면 이제 테스트 코드를 어떻게 작성해야 하는지에 대해서 알아보겠다

 

 

첫번째, 테스트 코드는 DRY 보다는 DAMP 하게 작성하라

개발 원칙 중 DRY(Don’t Repeat Yourself) 원칙을 많이 들어봤을 것이다

개발자는 중복 코드를 싫어해 중복 코드가 보이면 그것을 어떻게든 없애려고 하는 경향이 있다

그렇다면 중복을 줄이기 전에 DAMP하게 테스트 코드를 작성하는 것을 고려해봐야 한다

 

 

DAMP 원칙Descriptive and Meaningful Phrases의 약자로 의미있고 설명적인 구문을 사용하라는 원칙이다

 

 

테스트 코드의 중복을 줄이면서 테스트 간의 결합도를 높일 수 있다 또한, 이전보다 가독성이 떨어져 테스트 코드를 작성하는 사람도 테스트 코드를 파악하는 사람도 어려운 테스트가 될 수 있다

 

 

이러한 문제를 해결하기 위해 테스트 코드의 리팩토링은 중복을 줄이는 것이 아니라 더 서술적이고 의미있게 작성하는 방향으로 이루어져야 한다

 

 

오히려 무작정 코드의 중복을 줄이면 테스트 간의 격리성이 떨어지고 테스트 본래의 의도가 점점 모호해져 파악을 제대로 할 수 없게 되어지기때문이다

 

 

Better :

  • 테스트의 중복을 줄이는 것이 아니라 더 서술적이고 의미있게 작성하는 방향으로 리팩터링을 해야 한다
  • 테스트는 서로 독립적이고 격리되어야 하기때문에 테스트 수정에 다른 테스트가 영향을 받지 않도록 해야 한다
  • DAMP 원칙을 지키면서 중복을 줄이는 방안으로는 테스트 픽스쳐 함수나 클래스등을 사용할 수 있다

 

 

두번째, 테스트는 구현이 아닌 결과를 검증하도록 한다

테스트 코드를 작성할 때 빠른 테스트를 위해 모의 객체를 사용할 때가 있다

모의 객체로 mock, spy, stub등을 사용하는 경우 테스트 대상의 구현을 알아야만 테스트를 작성할 수 있다

그런데, 이 부분을 남용하거나 잘못 사용하여 테스트를 작성하는 경우가 종종 있다

 

 

내부 구현이나 비공개(private) 메소드들은 언제든지 바뀔 여지가 있는 코드이기때문에 정보의 은닉을 위해 숨기는데 다시 정보를 꺼내여 테스트하는 것은 좋지 않다

 

 

테스트 코드는 내부 구현보다는 실행 결과에 집중하는 것이 리팩토링 내성을 높일 수 있다

 

 

지나친 모의 객체 남용과 내부 구현 검증은 오히려 리팩터링의 내성을 떨어뜨리고 유지보수를 더 어렵게 만든다

 

 

우리는 어떻게 라는 내부 구현 검증보다는 무엇을 이라는 결과 검증에 집중하여 테스트 코드를 작성해야 한다

 

Better :

  • 테스트 코드는 내부 구현이 아닌 실행 결과에 집중해야 한다
  • 의미 있는 테스트, 검증을 하자

 

 

세번째, 읽기 좋은 테스트를 작성하라

테스트 코드는 메인, 제품 코드을 위한 코드라 할지라도 우리의 책임이고 관리 대상이다

테스트 코드도 가독성이 좋아야하고 불명확한 테스트 코드는 읽는 행위도 유지보수 하는 행위도 어렵게 만든다

 

 

좋은 테스트 코드는 읽는 사람 입장에서 이 테스트를 이해하는데 필요한 모든 정보를, 테스트 케이스 본문에 담고 있는 테스트를 말한다

 

 

그리고 이와 동시에 관련없는 정보를 담지 말아야 한다

 

또한 테스트 코드의 가독성을 높이는 방법 중 하나는 테스트의 구조를 잘 잡는 것이다

 

 

테스트의 구조는 준비, 실행, 검증 3개의 구절로 나뉘어질 수 있다

각각의 구절을 AAA패턴(Arrange-Act-Assert 주석으로 구분)이나 GWT 패턴(given-when-then 행위 주석으로 구분)으로 구간을 나누어 작성하는 것이 좋다

*물론 구조를 위한 주석을 사용하지 않고 각 영역에 맞게 테스트 함수 내 코드를 구분해서 작성할 수 있다면 그 방안을 사용하는 것이 좋다

 

 

그리고 만약 테스트 안에 너무 많은 양의 코드가 존재한다면 이 부분을 좀 더 코드 재사용의 목적으로 모듈화(테스트 팩토리, 빌더, 헬퍼 메소드)해두면 쉽게 읽힐 수 있게 된다

 

 

Better :

  • 테스트 코드도 코드이므로 읽기 쉬운 코드를 작성하자
  • 무엇이 잘못되어 실패했는지, 어떻게 고쳐야 하는지를 파악하기 어려운 테스트를 작성하지 말자
  • 테스트 구조를 나누는 패턴과 테스트 코드를 모듈화하는 방법을 통해 테스트 코드를 읽기 쉽게 작성하자

 

 

네번째, 테스트 명세에 비즈니스 행위를 담도록 한다

마지막으로 테스트 명을 작성할 때도 유의할 점이 있다

테스트명은 퍼블릭 인터페이스와 마찬가지로 명확하게 의도가 들어나도록 작성이 되어야 한다

테스트 코드 작성 이유 중 좋은 테스트 코드는 우리가 작성한 코드의 문서이기에 명확한 의도가 담긴 명세가 되어야 한다

 

 

여기서 명확하게 의도가 드러나는 이름은 개발자의 용어가 아닌 비즈니스 행위를 담은 비개발자가 읽을 수 있게 설명되어야 한다

 

 

Bad:

if(’관리자를 생성한 후 관리자 정보를 확인한다.’)

 

Better:

if(’관리자 정보로 가입한다’)

이렇게 잘 작성된 이름은 다음과 같은 효과를 가지고 온다

  • 테스트 코드와 실행 로그를 확인하지 않아도, 동작을 유추할 수 있으며, 요구사항이 빠르게 공유가 될 수 있다
  • 영향 범위를 빠르게 파악할 수 있으며 유추를 통하여 빠른 복구를 할 수 있다

 

 

테스트 코드 작성이 어려운 이유

하지만 테스트 코드를 작성하는 것은 쉽지 않은 작업이며 시간과 비용이 많이 든다

  • 개발자들은 주로 코드 작성에 집중한다
  • 단위 테스트의 경우 테스트 케이스 수가 많아질 수 있으며, 작성하고 관리하는데 쉽지 않다
  • 코드 수정 및 리팩토링이 발생할때마다 테스트 코드도 같이 변경해주어야 한다
  • 테스트 코드를 작성하면서 발생하는 문제점도 해결해야 한다

 

 

마무리

테스트 코드는 시간과 비용이 들더라도 “지속 가능한 서비스, 프로젝트”를 위해 필수적인 요소 중 하나이다

 

 

간단한 프로젝트에서는 테스트 코드의 영향을 확인하긴 힘들겠지만 서비스를 제공하는 회사

즉, 실무에서는 서비스, 기능등을 올바르게 수행하여 서비스를 이용하는 사용자들에게 제공해주어야 하기때문에 더욱 더 실무에선 테스트 코드의 중요성을 알고 투자를 하고 있을 것이다.

뿐만아니라 문서의 역할도 하기에 혼자가 아닌 팀으로 개발 할 경우 테스트 코드는 코드의 생산성과 개발시간의 단축을 시킬 수 있는 중요한 작업 중 하나이다

 

 

 

 

 

 

 

테스트 코드를 왜 그리고 어떻게 작성해야 할까?

테스트 코드가 필요한 이유와 잘 작성하는 방법에 대해 공유합니다.

tech.inflab.com

 

'TIL' 카테고리의 다른 글

MSA  (0) 2023.07.03
Redis ?  (0) 2023.05.26
FCM(Firebase Cloud Messaging)  (0) 2023.05.26
[GreenCherry/React, Spring boot, PWA, FCM] FCM을 활용한 백그라운드에서 알림 구현  (0) 2023.05.25
[JPA] OSIV와 성능 최적화  (0) 2023.03.22

MSA

개발의 숩
|2023. 7. 3. 11:14

MSA(MicroService Architecture)

마이크로서비스란 작고, 독립적으로 배포 가능한 각각의 기능을 수행하는 서비스로 구성된 프레임워크라고 할 수 있다. 마이크로서비스는 완전히 독립적으로 배포가 가능하고, 다른 기술 스택(개발 언어, 데이터베이스등)이 사용 가능한 단일 사업 영역에 초점을 둔다

 

 

 

등장배경

Monolithic Architecture

소프트웨어의 모든 구성요소가 한 프로젝트에 통합되어 있는 형태이다.

웹 개발을 예로 들면 웹 프로그램을 개발하기 위해 모듈별로 개발하고, 개발이 완료된 웹 어플리케이션을 하나의 결과물로 패키징하여 배포된 형태를 말한다.

웹의 경우 WAR파일로 빌드되어 WAS에 배포하는 형태를 말하며, 주로 소규모 프로젝트에 사용된다.

하지만 일정 규모 이상의 서비스, 혹은 수백명 이상의 개발자가 투입되는 프로젝트에서 Monolithic Architecture는 한계를 보인다

 

 

 

Monolithic Architecture 한계

 

부분 장애가 전체 서비스의 장애로 확대될 수 있다.

개발자의 잘못된 코드 배포 또는 갑작스러운 트래픽 증가로 인해 성능에 문제가 생겼을 때, 서비스 전체의 장애로 확대될 수 있다.

 

부분적인 Scale-out이 어렵다

Monolithic Architecture에서는 사용되지 않는 다른 모든 서비스가 Scale-out되어야 하기때문에 부분 Scale-out이 어렵다

Scale-out : 여러 server로 나누어 일을 처리하는 방식

 

서비스의 변경이 어렵고, 수정시 장애의 영향도 파악이 힘들다

여러 컴포넌트가 하나의 서비스에 강하게 결합되어 있기때문에 수정에 대한 영향도 파악이 힘들다

 

배포 시간이 오래 걸린다

최근 어플리케이션 개발 방법은 CI/CD를 통한 개발부터 배포까지 빠르게 반영하는 추세이다.

그러나 규모가 커짐에 따라 작은 변경에도 높은 수준의 테스트 비용이 발생하기도 하며, 많은 사람이 하나의 시스템을 개발하여 배포하기때문에 영향을 줄 수 밖에 없다

 

한 Framework와 언어에 종속적이다

Spring Framework를 사용할 경우, 블록체인 연동 모듈을 추가할 때 node.js를 사용하는 것이 일반적이며 강세이다. 그러나 선정했던 Framework가 Spring이기때문에 Java를 이용하여 해당 모듈을 작성할 수 박에 없다.이러한 Monolithic Architecture의 한계를 보완하기 위해 MSA가 등장하게 되었다. 기존의 특정한 물리적인 서버에 서비스를 올리던 on-promise 서버 기반 Monolithic Architecture에서 이제는 클라우드 환경을 이용하여 서버를 구성하는 MicroService Architecture로 많은 서비스들이 전환되고 있다.

 

 

특징

MSA는 API를 통해서만 상호작용할 수 있다.

즉, 마이크로서비스는 서비스의 end-point(접근점)을 API 형태로 외부에 노출하고, 실질적인 세부사항은 모두 추상화한다. 내부의 구현 로직, 아키텍처와 프로그래밍 언어, 데이터베이스, 품질 유지 체계와 같은 기술적인 사항들은 서비스 API에 의해 철저하게 가려진다

따라서 SOA(Service Oriented Architecture)의 특징을 다수 공통으로 가진다

 

 

제대로 설계된 마이크로서비스는 하나의 비즈니스 범위에 맞춰 만들어지므로 하나의 기능만 수행한다

즉, 어플리케이션 출시처럼 하나의 목표를 향해 일하지만, 자기가 개발하는 서비스만 책임진다 또한, 여러 어플리케이션에서 재사용할 수 있어야 한다

 

어플리케이션은 항상 기술 중립적 프로토콜을 사용해 통신하므로 서비스 구현 기술과는 무관하다

따라서, 마이크로서비스 기반의 어플리케이션을 다양한 언어와 기술로 구축할 수 있다는 것을 의미한다

 

마이크로서비스는 SOA에서 사용되는 집중화된 관리체계를 사용하지 않는다.

마이크로서비스 구현체의 공통적인 특징 중 하나는 ESB(Enterprise Service Bus)와 같은 무거운 제품에 의존하지 않는다는 점이다. REST 등 가벼운 통신 아키텍처, 또는 Kafka등을 이용한 message stream을 주로 사용한다

 

 

장점

각각 개별의 서비스 개발을 빠르게 하며, 유지보수도 쉽게할 수 있도록 한다

각각의 서비스가 모듈화되어 있으며, 이러한 모듈끼리는 RPC 또는 message-driven API등을 이용하여 통신한다

 

팀 단위로 적절한 수준에서 기술 스택을 다르게 가져갈 수 있다

 

서비스별로 독립적 배포가 가능하다

따라서 지속적인 배포 CD도 모놀리식에 비해서 가볍게 할 수 있다

 

각각 서비스의 부하에 따라 개별적으로 scale-out이 가능하다

메모리, CPU적으로 상당부분 이득이 된다

 

 

단점

모놀리식에 비해 상대적으로 많이 복잡하다

서비스가 모두 분산되어 있기대문에 개발자는 내부 시스템의 통신을 어떻게 가져가야 할지 정해야 한다

또한, 통신의 장애와 서버의 부하등이 있을 경우 어떻게 트랜잭션을 유지할지 결정하고 구현해야 한다

 

트랜잭션 유지가 어렵다

모놀리식에서는 단일 트랜잭션을 유지하면 됐지만 MSA에서는 비즈니스에 대한 DB를 가지고 있는 서비스도 각기 다르고, 서비스의 연결을 위해서는 통신이 포함되기때문에 트랜잭션을 유지하는게 어렵다

 

통합 테스트가 어렵다

개발 환경과 실제 운영 환경을 동일하게 가져가는 것이 쉽지 않다

 

실제 운영 환경에 대해서 배포하는 것이 쉽지 않다

마이크로서비스의 경우 서비스 1개를 재배포한다고 하면 다른 서비스들과의 연계가 정상적으로 이루어지고 있는지도 확인해야 한다

 

 

기업으로 알아본 적용 사례

 

이모티콘 서비스는 왜 MSA를 선택했나?

성장을 위해 달려오느라 거대해진 이모티콘 서비스와 그만큼 많이 쌓인 기술 부채를 두고, 천년만년 행복하게 개발하려는 구성원들이 선택한 MSA. 기존 레거시 서비스가 단일 서버로 너무 큰 코

tech.kakao.com

 

넷플릭스로 알아보는 MSA | 인사이트리포트 | 삼성SDS

 

www.samsungsds.com

 

 

서비스 경량화를 위한 MSA 설계 시 고려사항 | 인사이트리포트 | 삼성SDS

 

www.samsungsds.com

 

 

11번가 주니어 개발자의 첫 MSA 설계 및 개발기 | 11번가 TechBlog — 11번가 기술블로그

안녕하세요. 11번가 주문개발팀 개발자 고다경입니다. 입사 후 파일럿 프로젝트를 진행한 것을 Product로 전환하는 과정을 담았습니다. 많이 부족한 글이지만 신입~주니어의 글이라 생각해주시고

11st-tech.github.io

 

 

 

 

SOA(Service Oriented Architecture)

대규모 컴퓨터 시스템을 구축할 때의 개념

업무상 일 처리에 해당하는 소프트웨어 기능을 서비스로 판단하고 그 서비스를 네트워크상에 연동하여 시스템 전체를 구축해가는 방법론이다. 업무 처리 변화를 시스템에 빠르게 반영하고자 하는 수요에 대응하기 위해 2004년부터 IT업계에서 주목하고 있다

  • 플랫폼에 종속되지 않는 표준 인터페이스를 통해 기업의 업무를 표현한 ‘느슨하게 연결되고(Loosly coupled) 상호 조합 가능한 소프트웨어
  • SOA에서는 각각의 서비스가 데이터 계층, 비즈니스 로직, 뷰에 대한 모듈을 모두 가지고 있고, 각 서비스 간의 의존성이 최소화된다
  • SOA시스템의 규모가 증가함에 따라 서비스의 중복이 발생할 수 있고, 이를 방지하기 위해 이미 구현된 서비스가 있는지 검색할 수 있어야 한다

SOA 아키텍처 모델

  1. Fundamental SOA(통합)
  2. Networked SOA(유연성과 통제 추가)
  3. Process Oriented SOA(민첩성의 추가)

[Spring] JPA

개발의 숩
|2023. 6. 28. 22:29

요약

객체와 관계형 데이터베이스 매핑으로 객체와 테이블 매핑하여 패러다임의 불일치 문제를 해결할 수 있는 방안으로, 생산성, 유지보수, 패러다임 불일치 해결, 데이터 접근 추상화와 벤더 독립성등의 장점을 가지고 있는 프레임워크

 

 

JPA(Java Persistence API)

자바 애플리케이션과 JDBC 사이에서 동작하며, ORM 기술 표준으로 사용되는 인터페이스의 모음

즉, 실제적으로 구현된 것이 아니라 구현된 클래스와 매핑을 해주기 위해 사용되는 프레임워크

JPA를 구현하는 대표적인 오픈소스로는 Hibernate가 있다

 

 

ORM(Object Relational Mapping)

객체와 관계형 데이터베이스의 데이터를 매핑하는 기술

  • ORM 프레임워크가 객체와 데이터베이스 중간에서 매핑
  • 객체와 테이블을 매핑하여 패러다임 불일치 문제 해결

 

JPA의 동작

JPA는 애플리케이션과 JDBC 사이에서 동작한다.

JPA는 JDBC API를 사용하여 데이터베이스와 데이터를 주고 받게 된다.

 

저장

  1. MemberDAO 클래스를 통해 persist()를 실행하면, JPA가 Entity 객체를 분석하여 SQL문을 생성한다
  2. JDBC API를 사용하여 DB에 생성된 INSERT SQL을 보내게 된다
  3. 이 과정에서 JPA는 객체와 데이터베이스 테이블의 패러다임 불일치를 해결한다

 

조회

  1. MemberDAO 클래스를 통해 find(id)를 실행하면, JPA는 SELECT SQL을 생성한다
  2. JDBC API를 사용하여 생성된 SELECT SQLD을 보낸다
  3. DB에서 반한된 정보를 ResultSet 매핑을 통해 객체로 변환해준다
  4. 이 과정에서도 패러다임 불일치 문제를 해결해준다

 

JPA를 사용하는 이유

생산성

  • JPA는 쿼리문을 별도로 작성할 필요가 없다
  • 데이터베이스 설계 중심의 패러다임을 객체 설계 중심으로 애플리케이션 개발이 가능하다

유지보수

  • JPA에서는 쿼리를 직접 작성하지 않기 때문에 필드가 변경되더라도 매핑 정보만 잘 연결하면 SQL문은 자동으로 작성된다
  • 개발자가 작성해야 할 SQL과 JDBC API 코드를 JPA가 대신 처리해줌으로 유지보수해야 하는 코드 수가 줄어든다

패러다임 불일치 문제 해결

상속, 연관관계, 객체, 그래프 탐색, 비교등을 설계 차이로 인해 발생하는 패러다임 불일치 문제를 해결한다

  • 객체는 상속 구조를 만들 수 있으며, 다형성 구현이 가능하지만, 관계형 데이터베이스의 테이블은 상속이라는 개념이 존재하지 않는다
  • 객체는 참조를 통해 관계를 표현하며 방향을 가지고 있으나, 관계형 데이터베이스는 외래 키를 통해 관계를 표현하며, 방향이 존재하지 않는다. 또한 다대다 관계 문제를 해결하기 위해 조인을 사용한다
  • 이외에도 다양한 패러다임 불일치 문제가 존재한다

데이터 접근 추상화와 벤더 독립성

  • 데이터베이스 기술에 종속되지 않도록 한다
  • 데이터베이스를 변경하면 JPA에게 다른 데이터베이스를 사용한다고 알려주기만 된다

 

 

JPA의 단점

복잡한 쿼리 처리

  • 복잡한 쿼리를 사용할 경우는 SQL문을 사용하는게 나을 수도 있다. JPA에서는 Native SQL을 통해 기존의 SQL문을 사용할 수 있지만 그러면 특정 데이터베이스에 종속된다는 단점이 생긴다. 이를 보완하기 위해서는 SQL과 유사한 기술인 JPQL을 지원한다

성능 저하 위험

  • 객체 간의 매핑 설계를 잘못했을 때 성능 저하가 발생할 수 있으며, 자동으로 생성되는 쿼리가 많기때문에 개발자가 의도하지 않는 쿼리로 인해 성능이 저하되기도 한다

학습

  • JPA를 사용하기 위해선 학습해야 할 것들이 많다
  • JPA를 사용해도 SQL을 알아야 Hibernate가 수행한 쿼리 확인 및 성능 모니터링이 가능하다

 

 

 

 

JDBC API

자바 프로그래밍 언어와 다양한 데이터베이스 SQL 또는 테이블 형태의 데이터 사이에 독립적인 연결을 지원하는 표준

즉, 다양한 형태의 관계형 데이터베이스에 접속하여 자바 프로그래밍 언어와 데이터베이스 사이에 데이터를 주고 받을 수 있도록 지원하는 표준 자바 응용 프로그래밍 인터페이스이다.

 

JDBC API 역할

JDBC API는 표준 응용 프로그래밍의 인터페이스만을 제공해주는 것이고,

실질적인 인터페이스의 메소드 기능들에 대한 실제 구현은 DBMS 제조사들이 자신들의 데이터베이스에 맞게 구현하여 제공하며, 이를 JDBC 드라이버라고 한다

 

JDBC 드라이버

DBMS 회사들이 자신들의 데이터베이스 시스템에 접근할 수 있도록 표준 JDBC 인터페이스에 명시된 메소드들을 구현한 것

따라서 JDBC API를 사용할 경우, 하나의 자바 응용 프로그램만으로 JDBC 드라이버를 제공하는 어떤 종류의 관계형 DBMS에도 접근이 가능할 것이며, 사용자들은 특정 회사의 데이터베이스의 정확한 사용 방법을 몰라도 JDBC API만 배우면 데이터베이스 응용 프로그램을 구현할 수 있는 것이다.

Redis ?

개발의 숩
|2023. 5. 26. 10:08

무조건 RDBMS를 사용해야하는 걸까?

RDBMS는 실제 물리적 장치에 저장하기때문에 데이터를 영속적으로 관리할 수 있지만,

입출력에 다소 시간이 걸리는 단점이 존재한다. 이러한 여러가지 부분에 있어서 인증 토큰에 대해서는 Redis를 사용한다.

 

Redis

Remote Dictionary Server 약자로 

Key-Value 구조의 비정형 데이터를 저장하고 관리하기 위한 오픈 소스 기반의 비관계형 데이터 베이스 관리 시스템 (NoSQL)

 

특징

  • Key-Value 구조의 비정형 데이터를 저장하고 관리하기 위한 오픈 소스 기반의 비관계형 데이터 베이스 관리 시스템 (NoSql)
  • 데이터베이스, 캐시, 메세지 브로커로 사용된다
  • In-Memory 기반의 데이터 처리 및 저장을 제공하여 속도가 빠르지만 서버가 꺼지면 모든 데이터가 사라지기 때문에 보조 데이터베이스로 사용된다.
  • 데이터를 디스크에 쓰는 구조가 아니라 메모리에서 데이터를 처리하기때문에 속도가 빠르다
  • String, Lists,Sets,Sorted Sets, Hashes 자료 구조를 지원한다
    • String : 가장 일반적인 key-value 구조의 형태
    • Sets : String의 집합, 여러 개의 값을 하나의 value에 넣을 수 있다
    • Sorted Sets : 중복된 데이터를 담지 않는 Set 구조에 정렬 Sort를 적용한 구조로 사용할 수 있다
    • Lists : Array 형식의 데이터 구조, List를 사용하면 처음과 끝에 데이터를 넣고 빼는 건 빠르지만 중간에 데이터를 삽입하거나 삭제하는 것은 어렵다
  • Single Threaded
    • 한 번에 하나의 명렁만 처리할 수 있다 그렇기 때문에 중간에 처리 시간이 긴 명령어가 들어오면 그 뒤에 명령어들은 모두 앞에 있는 명령어가 처리될 때까지 대기가 필요하다 (하지만 get, set 명령어의 경우 초당 10만 개 이상 처리할 수 있을 만큼 빠르다)

 

 

SOCK 프로젝트에선 Redis의 특징 중 Single Threaded를 활용하여 레시피 인기도 상승에 대한 로직을 구현하였다

 

구현 방식에 대한 자세한 내용은 다음 포스팅에 작성하도록 하겠다

 

 

 

데이터 베이스가 있는데도 Redis라는 인메모리 데이터 구조 저장소를 사용하는 이유가 무엇일까

데이터베이스는 데이터를 물리 디스크에 직접 쓰기때문에 서버에 문제가 발생하여 다운되더라도 데이터가 손실되지 않는다. 하지만 매번 디스크에 접근해야 하기때문에 사용자가 많아질수록 부하가 많아져서 느려질 수 있다

일반적으로 서비스 운영 초반이거나 규모가 작은, 사용자가 많지 않은 서비스의 경우에는 WEB -WAS -DB 의 구조로도 데이터베이스에 무리가 가지 않는다.

하지만 사용자가 늘어난다면 데이터베이스가 과부하될 수 있기때문에 이때 캐시 서버를 도입하여 사용한다

그리고 이 캐시 서버로 이용할 수 있는 것이 바로 Redis이다

캐시는 한번 읽어온 데이터를 임의의 공간에 저장하여 다음에 읽을 때는 빠르게 결괏값을 받을 수 있도록 도와주는 공간이다

같은 요청이 여러번 들어오는 경우 매번 데이터 베이스를 거치는 것이 아니라 캐시 서버에서 첫 번째 요청 이후 저장된 결괏값을 바로 내려주기때문에 DB의 부하를 줄이고 서비스의 속도도 느려지지 않는 장점이다

캐시 서버는 Look aside cashe 패턴Write Back 패턴이 존재한다

 

Look aside cache

  1. 클라이언트가 데이터 요청
  2. 웹 서버는 데이터가 존재하는지 Cache 서버 먼저 확인
  3. Cache 서버에 데이터가 존재하면, DB에 데이터를 조회하지 않고 Cache 서버에 있는 결괏값을 클라이언트에게 반환 (Cache Hit)
  4. Cache 서버에 데이터가 존재하지 않다면, DB에 데이터를 조회하여 Cache 서버에 저장하고 결괏값을 클라이언트에게 반환 (Cache Miss)

 

Write Back

  1. 웹 서버는 모든 데이터를 Cache 서버에 저장
  2. Cache 서버에 특정 시간 동안 데이터가 저장됨
  3. Cache 서버에 있는 데이터를 DB에 저장
  4. DB에 저장된 Cache 서버의 데이터를 삭제
  • insert 쿼리를 한 번씩 500번 날리는 것보다 insert 쿼리 500개를 붙여서 한 번에 날리는 것이 더 효율적이다는 원리이다
  • 이 방식은 들어오는 데이터들이 저장되기 전에 메모리 공간에 머무르는데 이때 서버에 장애가 발생하여 다운된다면 데이터가 손실될 수 있다는 단점이 있다

 

Redis 사용에 주의할 점

  • 서버에 장애가 발생했을 경우 그에 대한 운영 플랜이 꼭 필요하다
  • : 인메모리 데이터 저장소의 특성상, 서버에 장애가 발생했을 경우 데이터 유실이 발생할 수 있다
  • 메모리 관리가 중요하다
  • 싱글 스레드의 특성상, 한 번에 하나의 명령만 처리할 수 있다. 처리하는데 시간이 오래 걸리는 요청, 명령은 피해야 한다

이 외에도 Master-Slave 형식의 데이터 이중화 구조에 대한 Redis Replication, 분산 처리를 위한 Redis cluster, 장애 복구 시스템 Redis Sentinel, Redis Topology, Redis Sharding, Redis Failover 등의 Redis를 더 효율적으로 사용하기 위한 개념들이 존재한다

 

 

 

 

📮개인 공부를 위한 공간으로 틀린 부분이 있을 수도 있습니다.📮

문제점 및 수정 사항이 있을 시, 언제든지 댓글로 피드백 주시기 바랍니다.

FCM(Firebase Cloud Messaging)

개발의 숩
|2023. 5. 26. 09:16

FCM

FCM은 Firebase Cloud Messaging의 약자로, 무료로 메시지를 안정적으로 전송할 수 있는 교차 플랫폼 메시징 솔루션이다.

모든 사용자에게 알림 메세지를 전송할 수도 있고, 그룹을 지어 메시지를 전송할 수도 있다.

Firebase의 서비스는 요금 정책에 따라, 이용할 수 있는 범위가 다르지만 FCM은 요금 정책에 구분 없이 무료로 사용하는 것이 가능하다.

 

왜 사용하는가 ?

FCM을 이용하면 플랫폼에 종송되지 않고 푸쉬 메시지를 전송할 수 있다

iOS, Android, Web 각 플랫폼에서 푸쉬 메시지를 보내려면

각 플랫폼 환경 iOS (APNS), Android (GCM)별로 개발해야 하는 불편함이 있는데

이를 하나로 통합하는 솔루션으로 플랫폼에 종속되지 않고 Push 메시지를 전송할 수 있다.

 

A→ 어플리케이션 서버 → 클라우드 메시징 서버 → B 와 같은 형태로 작업을 처리하게 된다.

 

 

 

클라우드 메시징 서비스를 사용하면 어떤 이점이 있는가?

서버를 경유해서 실시간으로 푸쉬 메시지를 받으려면 사용자는 항상 서버에 접속해있어야 하는데, 이는 사용자 기기의 배터리 및 네트워크 리소스를 크게 낭비한다.N

클라우드 메시징 서버를 중간에 둠으로써, 사용자는 낮은 배터리와 네트워크의 사용만으로도 메세지를 실시간으로 송수신 처리를 할 수 있다.

위와 같은 이유로 대부분의 어플리케이션 서비스들은 클라우드 메시징 서버를 경유해서, 실시간으로 유저들에게 메시지를 전송해주고 있다.

 

 

 

FCM의 주요 특징

메세지 타입

  • FCM의 메세지 타입은 알림 메세지와 데이터 메시지로 구분할 수 있다.
  • 보통 알림 메세지와 데이터 메시지를 같이 혼용해서 사용한다
    • 예를 들어 휴태폰 푸시 알림 메세지는 알림 메세지를 이용하고, 알림 메시지를 클릭하였을 때 앱내 특정 페이지로 이동이나, 어떠한 액션은 데이터 메세지를 통해서 이뤄진다.

메세지 종류 알림 가능 여부 알림 저장 개수 알림 처리 방법

알림 메시지 가능 여러 알림을 저장하나, OS 환경마다 다름 앱이 백그라운드일 경우
데이터 메시지 가능 1개의 알림만 저장 앱이 포그라운드일 경우

티켓팅

  • 단일 기기, 기기 그룹, 주제를 구독한 기기 3가지 방식으로 클라이언트 앱에 메시지를 배포할 수 있다.

종류 대상 수 설명

단일 기기 1개 하나의 기기(앱 기준)
기기 그룹 20개 알림 키에 허용되는 그룹
주제 구독 1000개 등록 토큰에 구독된 기기

클라이언트 앱에서 메시지 전송

  • FCM을 이용하면 앱 서버에서 클라이언트 앱으로 다운 스트림 메시지를 보낼 수 있을 뿐만 아니라, 클라이언트 앱에서 앱 서버로도 업 스트림 메세지를 보낼 수 있다.
  • 하지만 클라이언트 앱에서 앱 서버로 업스트림 메세지를 보내기 위해서는 선행 조건이 필요하다. 그 부분은 밑에서 설명한다.

 

 

FCM의 동작 원리

크게 송신자, FCM Backend Server, 수신자로 구분한다.

A&rarr; 어플리케이션 서버 &rarr; 클라우드 메시징 서버 &rarr; B 와 같은 형태로 작업을 처리하게 된다.

송신자

주로 앱 서버, HTTP 프로토콜을 사용하는 서버, 우리가 흔히 사용하는 iOS, Android 운영체제를 사용하는 모바일 기기가 될 수 있다.

 

FCM Backend Server

실질적으로 앱 서버에서 요청을 받아서 메세지를 처리하는 서버에 해당된다.

메시지를 수신할 클라이언트는 자신의 정보를 FCM Backend Server에 등록해야 한다

메세지를 전송할 주체(앱 서버)는 등록된 정보를 획득해야 하며, 해당 정보로 다운 스트림 메시지를 전송한다.

앱 서버에서 FCM Backend Server에 메세지 요청을 보내고, FCM Backend Server는 사용자 기기에서 실행되는 클라이언트 앱에 메세지를 보내게 된다.

 

 

 

📮개인 공부를 위한 공간으로 틀린 부분이 있을 수도 있습니다.📮

문제점 및 수정 사항이 있을 시, 언제든지 댓글로 피드백 주시기 바랍니다.

 

'TIL' 카테고리의 다른 글

MSA  (0) 2023.07.03
Redis ?  (0) 2023.05.26
[GreenCherry/React, Spring boot, PWA, FCM] FCM을 활용한 백그라운드에서 알림 구현  (0) 2023.05.25
[JPA] OSIV와 성능 최적화  (0) 2023.03.22
[JPA] API 개발 고급 정리  (1) 2023.03.21