[레코드와 파티션]

 

** 파티션은 데이터가 저장되는 공간이고, 이 데이터가 레코드라고 불립니다.

레코드마다 고유한 타임스탬프, 메시지 키, 메시지 값, 오프셋이 지정되서 파티션에 들어가게 됩니다.

타임스탬프
  . 레코드를 생성할 시점이 Unix time으로 들어가게 됨, 브로커에 들어갈 시간, 사용자가 설정한 시간도 들어갈 수 있음
메시지 키 
  . 데이터를 구분하는 값 -> 레코드가 들어갈 파티션을 정하거나, 순서를 정할때 사용하기 유용함
  . 보통의 경우 메시지 키를 따로 설정하지 않으면 NULL 값으로 들어가게 됨

메시지 값  
  . 실제로 사용할 데이터. 직렬화 되어 저장됨

오프셋 
  . 파티션에 저장될 때 레코드 별로 저장되는 번호
  . 한 개의 파티션에는 오프셋이 중복될 수 없음

 

 

[토픽과 파티션]


** 토픽은 파티션들의 묶음
으로, 한 개의 토픽은 일반적인 DB의 Table과 유사한 개념입니다.

토픽의 파티션에 저장된 데이터는 브로커가 데이터를 지우기 전까지는 삭제되지 않습니다.

토픽은 파티션을 한 개 이상 가져야 합니다. 그리고 파티션 개수가 많아질 수록 병렬 처리량을 늘릴 수 있습니다.
-> 컨슈머 그룹을 통해서 파티션 개수가 많을수록 병렬로 처리되는 데이터량, 시간당 처리되는 데이터량을 늘릴 수 있음

토픽 이름은 영대소문자, 숫자, 점, 언더바, 대시로 만들 수 있습니다.

 

 

[파티션 개수의 변경]


** 토픽에 있는 파티션 개수를 변경할 수(늘릴 수) 있음

데이터 처리량을 늘리고 싶을 때, 파티션 개수를 늘려서 처리할 수 있습니다.
-> 파티션 개수만큼 컨슈머 그룹을 늘릴 수 있기 때문
단, 이미 가지고 있는 파티션을 줄이는 것은 불가능합니다.

 

[토픽의 데이터 삭제]

 

** 토픽(파티션)에 저장된 데이터는 개별 삭제가 불가능합니다.

** 데이터의 삭제는 브로커가 관장하며, 토픽 단위로 데이터가 삭제되는 시점을 정할 수 있습니다.
각각의 레코드를 로그(Log)로 보기 때문에, insert/update가 불가능합니다.

데이터 삭제는 아래와 같이 2가지 옵션이 있습니다.
  . cleanup.policy = delete (데이터 레코드의 삭제)

     - retention.ms : 얼마정도 시간이 지나고 나면 삭제 처리
     - retentions.bytes : 얼마정도 데이터가 차고 나면 삭제 처리
  . cleanup.policy = compact (메시지 키 단위로 이전의 데이터를 삭제)
     - 주로 스트리밍 애플리케이션을 만들 때 사용

[데이터 파이프라인에 필요한 4가지]

 

- 높은 처리량, 확장성, 영속성, 고가용성

 

[카프카 특징#1 - 높은 처리량]

 

** 컨슈머/프로듀서가 브로커와 통신할 때 데이터를 묶어(배치) 전송
** 파티션 개수만큼 컨슈머를 늘려서 병렬 처리량을 늘릴 수 있음

카프카는 프로듀서가 브로커로 데이터를 보낼 때와 컨슈머가 브로커로부터 데이터를 받을 때, 데이터를 묶어서(배치) 전송합니다.
많은 양의 데이터를 송/수신할 대 맺어지는 네트워크 비용은 무시할 수 없는 규모입니다. 동일한 양의 데이터를 보낼 때 네트워크 통신 횟수를 최소한으로 줄이면, 동일 시간 내에 더 많은 양의 데이터를 전송 가능합니다.

 

많은 양의 데이터를 묶음 처리하는 배치로 빠르게 처리할 수 있기 때문에, 카프카는 대용량 실시간 로그 데이터를 처리하는데 적합합니다. 또한 카프카는 파티션과 컨슈머 개수를 늘려서, 병렬 처리량을 늘려서 동일 시간당 처리량을 극대화할 수도 있습니다.

 

[카프카 특징#2 - 확장성]

 

** 데이터의 양이 많아지거나 적어짐에 따라 무중단 스케일인/아웃 가능
** 처음에는 작은 서버 개수로 시작
** 데이터의 양이 많아지면 서버를 늘려서 대응 가능

데이터 파이프라인에서, 데이터가 얼마나 들어올지 예측하기는 매우 어렵습니다. 예상치 못한 특정 이벤트로 인해 100만 건 이상의 데이터가 갑자기 들어올 수도 있습니다. 카프카는 이러한 가변적인 환경에서도 데이터를 안정적으로 확장 가능하도록 설계되어 있습니다.

 

데이터가 적을 때는 카프카 클러스터의 브로커를 최소한의 개수로 운영하다가, 데이터가 많아지면 브로커 개수를 늘려서 스케일 아웃(Scale-out)할 수 있습니다. 반대로 데이터가 적어지고, 추가 서버들이 필요 없어지면 브로커 개수를 줄여서 스케일 인(Scale-in) 할 수 있습니다.

카프카의 스케일인/아웃 과정은 클러스터의 무중단 운영을 지원하기 때문에, 365일-24시간 데이터를 처리해야 하는 커머스와 은행 같은 BM에서도 안정적인 운영이 가능합니다.

 

[카프카 특징#3 - 영속성]

 

** 파일 시스템에 데이터를 저장
** 브로커에 이슈가 발생하여 종료되더라도 데이터 재사용 가능

영속성이란 데이터를 생성한 프로그램이 종료되더라도, 사라지지 않는 데이터의 특성을 의미합니다.

 

카프카는 다른 메시징 플랫폼과 다르게 전송받은 데이터를 메모리에 저장하지 않고, 파일 시스템에 적재합니다.

파일 시스템에 데이터를 적재하고 사용하는 것은, 보편적으로 느리다고 생각될 수 있지만 카프카는 OS 레벨에서 파일 시스템을 최대한 활용할 수 있는 방법을 적용했습니다.

 

OS에서는 파일 I/O 성능 향상을 위해 페이지 캐시 영역을 메모리에 따로 생성해서 사용하는데, 페이지 캐시 메모리 영역을 사용하여 한 번 읽은 파일 내용은 메모리에 저장시켰다가 다시 사용하는 방식이기 때문에 카프카가 파일 시스템에 데이터를 저장하고 전송 하더라도, 처리량(속도)이 높은 것입니다.

 

디스크 기반의 파일 시스템을 활용한 덕분에, 브로커와 애플리케이션이 장애 발생으로 갑자기 종료되더라도, 프로세스를 재시작하여 안전하게 데이터를 다시 처리할 수 있다는 장점이 있습니다.

 

[카프카 특징#3 - 고가용성]

 

** 일부 브로커에 이슈가 생기더라도 데이터 처리 지속 가능
** 온 프레미스/퍼블릭 클라우드에 적합한 브로커 옵션들이 준비됨

3개 이상의 서버들로 운영되는 상용 환경의 카프카 클러스터는, 일부 서버에 장애가 생겨도 무중단으로 안정하고 지속적으로 데이터를 처리할 수 있습니다.

 

클러스터로 이루어진 카프카는 데이터의 복제를 통해, 고가용성의 특징을 가집니다. 프로듀서로 전송받은 데이터를 여러 브로커 서버들 중 1대에만 저장하는 것이 아니라, 또 다른 브로커 서버에도 저장하는 것입니다.


한 서버에 장애가 발생하더라도, 복제된 데이터가 나머지 브로커 서버에 저장되어 있으므로 저장되어 있는 브로커 서버를 기준으로 지속적으로 데이터 처리가 가능합니다.

2011년 SNS 사이트인 Linked-in에서는 파편화된 데이터 수집 및 분배 아키텍처를 운영하는데 큰 어려움을 겪었습니다.

 

데이터를 생성하고 적재하기 위해서는, 데이터를 생성하는 소스 애플리케이션과 데이터가 최종 적재되는 타깃 애플리케이션들을 연결해야 하는데, 초기에는 단방향 통신을 통해 소스 애플리케이션에서 타깃 애플리케이션으로 연동하는 소스 코드를 직접 작성했고 아키텍처가 복잡하지 않았기 때문에 운영이 힘들지 않았습니다.

 

하지만 시간이 지날수록 아키텍쳐는 점점 거대해졌고, 소스와 타깃 애플리케이션의 개수가 많아지면서 문제가 생겼습니다. 데이터를 전송하는 라인이 기하급수적으로 복잡해지기 시작해져 소스-타깃을 연결하는 파이프라인의 개수가 많아지면서 소스코드 및 버전 관리 이슈가 많아졌습니다. 그리고 타깃 애플리케이션에 장애가 생기면 그 영향이 소스 애플리케이션에 그대로 전달되었습니다.

Kafka 도입 이전

이렇게 점점 복잡해지는 Linked-in 백엔드 아키텍쳐에서, 파편화된 데이터 파이프라인은 서비스를 안정적으로 운영하는 데에 걸림돌이 되었습니다. 이를 해결하기 위해 Linked-in 데이터 팀에서는 기존 상용 데이터 프레임워크와 오프 소스를 아키텍처에 녹여내서 데이터 파이프라인의 파편화를 개선하려고 시도했었습니다. 다양한 메시지 플랫폼과 ETL 툴을 이용했지만, 데이터 파이프라인의 복잡도를 낮춰주는 아키텍처가 되지는 않았습니다.

결국 Linked-in 데이터 팀은 신규 시스템을 만들기로 결정했고, 그 결과물이 바로 Apache Kafa입니다.

Kafka는 각각의 애플리케이션끼리 연결하여 데이터를 처리하는 것이 아니라 한 곳에 모아서 처리할 수 있도록 중앙 집중화했습니다. Kafka를 통해 웹사이트, 앱, 센서 등에서 취합한 데이터 스트림을 한 곳에서 실시간으로 관리할 수 있게 처리할 수 있게 되었습니다.

Kafka 도입 이후

 

카프카 내부에 데이터가 저장되는 파티션의 동작은 큐 자료구조와 유사합니다. 이 큐에 데이터를 보내는 것이 프로듀서(Producer)이고, 큐에서 데이터를 가져가는 것을 컨슈머(Consumer)라고 부릅니다.

 

상용 환경에서 Kafka는 최소 3대 이상의 서버에서 분산 운영해서 프로듀서를 통해 전송받은 데이터를 파일 시스템에 안전하게 기록합니다. 즉, 일부 서버에 장애가 발생해도 데이터를 지속적으로 복제하기 때문에 안전하게 운영 가능합니다.

 

또한 이렇게 주고받는 데이터를 배치 전송 하기때문에, 낮은 지연과 높은 데이터 처리량을 가지게 되었습니다.

즉 Kafka는 많은 양의 데이터를 안전하고 빠르게 처리하는 강점을 가지고 있기 때문에, 많은 IT 기업에서 사용하고 있습니다.

[레거시 데이터 아키텍처]

- 서비스에서 생성된 모든 데이터를 저장

- 필요에 따라 데이터를 조합하여 파생 데이터를 만듦

- 최종 사용할 서비스/사용자를 위해 서빙 데이터를 저장


- 레거시 데이터 아키텍처의 단점


초기 빅데이터 플랫폼은 End-to-End로 각 서비스 앱으로부터 데이터를 배치로 모았었는데, 이러한 구조는 유연하지 못했고 실시간으로 생성되는 데이터들에 대한 인사이트를 서비스 앱에 빠르게 전달하지 못하는 단점이 있었습니다.


또한 원천 데이터로부터 파생된 데이터의 히스토리를 파악하기가 어려웠고, 계속되는 데이터의 가공으로 인해 데이터가 파편화되면서 데이터 거버넌스를 지키기 어려웠습니다.

이를 해결하기 위해 개선한 아키텍처가 람다 아키텍처입니다.


[람다 아키텍처]

- 배치 레이어: 배치성 데이터를 모아서 특정 시간마다(시간, 일, 월 단위) 일괄 처리(=배치 데이터 처리)

- 스피드 레이어: 서비스에서 생성되는 원천 데이터를 실시간으로 분석(=실시간 데이터 처리)

- 서빙 레이어: 배치/스피드 레이어에서 처리한 데이터(가공된 데이터)를 최종 저장

배치 데이터에 비해 낮은 지연으로 분석이 필요한 경우, 스피드 레이어를 통해 데이터를 분석할 수 있습니다.

스피드 레이어에서 가공,분석된 실시간 데이터는 사용자 또는 서비스에서 직접 사용할 수 있지만, 필요한 경우 서빙 레이어로 데이터를 보내서 저장하고 사용합니다.

 

** 람다 아키텍쳐에서 카프카는 스피드 레이어에 위치  
-> 서비스 애플리케이션들의 실시간 데이터를 짧은 지연 처리/분석할 수 있기 때문 

 

 

- 람다 아키텍처의 단점

 

데이터를 분석/처리하는데 필요한 로직이 두벌로 각각의 레이어에 따로 존재한다
배치 데이터와 실시간 데이터를 융합하여 처리할 때 다소 유연하지 못한 파이프라인을 생성해야 한다.

 

데이터를 배치 처리하는 레이어와 실시간 처리하는 레이어를 분리한 람다 아키텍처는 데이터 처리 방식을 명확히 나눌 수 있었지만, 레이어를 두 개로 나뉘기 때문에 생기는 단점이 있습니다.


이를 해결하기 위해 한 개 로직을 추상화하여 배치 레이어와 스피드 레이어에 적용하는 형태를 고안한 트위터의 서밍 버드가 있었지만, 결국 컴파일 이후에는 배치 레이어와 스피드 레이어에 각각 디버깅과 배포를 해야했기 때문에 문제가 완벽하게 해결되지는 못했습니다.


이러한 람다 아키텍처의 단점을 해소하기 위해 제이 크랩스는 카파 아키텍처를 제안했습니다.


[카파 아키텍처]

- 카프카를 최초로 개발한 개발자 제이 크랩스(Jay Kreps)가 제안
- 배치 레이어를 제거하고 모든 데이터를 스피드 레이어에서 처리

- 배치 레이어 때문에 발생한 로직의 파편화, 디버깅, 배포, 운영 분리에 대한 이슈 제거

카파 아키텍처는 람다 아키텍처와 유사하지만, 배치 레이어를 제거하고 모든 데이터를 스피드 레이어에 넣어서 처리한다는 점이 다릅니다. 람다 아키텍처에서 단점으로 부각되었던 로직의 파편화, 디버깅, 배포, 운영 분리에 대한 이슈를 제거하기 위해 배치 레이어를 제거한 카파 아키텍처는 스피드 레이어에서 모든 데이터를 처리하므로 엔지니어들이 효과적으로 개발과 운영을 가능하게 했습니다.


[스트리밍 데이터 레이크 아키텍처]

- 2020년 카프카 서밋에서 제이 크랩스(Jay Kreps)가 제안
- 배치 데이터, 스트림 데이터 처리를 스트림 레이어에서 처리

- 처리 완료된 데이터를 스피드 레이어에 저장
- 마치 카프카가 하둡을 대체하는 것과 유사

2020년 카프카 서밋에서 제이 크랩스는 카파 아키텍처에서 서빙 레이어를 제거한 스트키밍 데이터 레이크를 제안했습니다.

제이 크랩스는 람다 아키텍처에서 스피드 레이어로 사용되는, 카프카의 분석과 프로세싱을 완료한 거대한 용량의 데이터를 오랜 기간 데이터를 저장하고 사용할 수 있다면, 서빙 레이어를 제거하여 서빙 레이어와 스피드 레이어가 이중으로 관리되는 운영 리소스를 줄일 수 있다고 생각했습니다.

데이터가 필요한 모든 고객과 서비스 애플리케이션은 카프카를 창조함으로써 데이터의 중복, 비정합성과 같은 문제에서 벗어날 수 있게 되는 것입니다.

 

하지만 아직은 카프카를 스트리밍 데이터 레이크로 사용하기 위해 개선해야 하는 부분이 많이 남아있습니다.


먼저 자주 접근하지 않는 데이터를 비싼 자원을 들여 유지할 필요가 없습니다. 카프카 클러스터에서 자주 접근하지 않는 데이터는 오브젝트 스토리지와 같이 저렴하고 안전한 저장소에 옮겨 저장하고, 자주 사용하는 데이터만 브로커에서 사용하는 구분 작업이 필요합니다.


카프카 클러스터가 단계별 저장소를 가질수 있도록 추가 기능을 개발중에 있고, 아마도 가까운 미래에는 콜드 데이터는 오브젝트 스토리지에, 핫 데이터는 카프카에서 활용할 수 있게 될 것으로 보입니다.

 

[카프카 서밋] https://www.kafka-subbit.org/

[컨플루언트 유튜브 채널: https://www.youtube.com/c/Confluent/videos

1. HashMap
   - Thread-Safe하지 못한 클래스
   - Multi-Thread 환경에서 안전하게 사용하기 위해 Collections.synchronizedMap(hashMap) 등으로 동기화 처리 필요
   - key, value에 null 허용

2. HashTable
   - 데이터 관련 메소드에 synchronized 처리가 되어있어 멀티 스레드 환경에서 안전하게 사용 가능
   - 동기화 Lock 때문에 속도가 느리다
   - key, value에 null을 허용하지 않음

3. ConcurrentHashMap
   
- HashTable처럼 항상 동기화 Lock을 걸지는 않고,
       . 빈 해시 버킷에 데이터를 삽입하는 경우, CAS(Compared And Swap)를 이용하여 원자성을 보장한다
       . 이미 데이터가 존재하는 해시 버킷 서로 다른 스레드가 접근 할 때만 동기화 Lock이 걸리게 된다
       . HashTable보다 성능면에서 우수
   - key, value에 null을 허용하지 않음

'~2022 > Java' 카테고리의 다른 글

[Java] HashMap, TreeMap, LinkedHashMap  (0) 2021.10.25
[Java] Atomic Class  (0) 2021.10.12
[Java] DTO와 VO의 차이  (0) 2021.08.22

1. HashMap
- 내부적으로 Entry 배열을 만들어 관리 (key-value 쌍의 개수에 따라 동적으로 크기가 증가하는 associate array)

- 객체의 hashCode() 메소드의 리턴 값을 기반으로 동작하되, 해시 충돌(Hash Collision)을 대비해 equals() 메소드까지 사용해서 key값이 정말 같은 경우에만 value를 리턴

- 키 값으로 사용할 클래스의 특성에 따라 필요한 경우 hashCode()메소드와 equals()메소드를 오버라이드

- 입력 순서나 key값의 정렬 순서는 지켜지지 않음
- 해시 함수를 사용하기 때문에 데이터 탐색에 O(1)의 시간복잡도를 갖는다
- Java HashMap의 동작 방식(Seperate Chaning): https://d2.naver.com/helloworld/831311 

  . 해시 충돌을 방지하기 위하여 Separate Chaining과 보조 해시 함수를 사용
  . 데이터가 많아지면, 충돌 시 성능 상 이점을 위해 데이터를 트리에 저장하여 관리
    ~Java 8에서는 Separate Chaning에서 하나의 해시 버킷에 8개 이상 키-값 쌍이 모이면 링크드 리스트를 트리로 변경
    ~버킷에 있는 데이터를 삭제하여 다시 개수가 6개에 이르면 다시 트리를 링크드 리스트로 변경 

 

 

2. TreeMap
- 내부적으로 RedBlack Tree로 저장하여 관리
- key로 사용할 클래스에 Comparator 인터페이스를 구현하면 key값을 기준으로 정렬된 상태를 유지할 수 있다

- 데이터 탐색에 O(logN)의 시간복잡도를 갖는다

 

3. LinkedHashMap
- Map.Entry 클래스를 구현한 Node 클래스로 내부에 before, after 멤버를 갖는 각 항목을 연결리스트 구조로 가지고 있음
- 데이터가 입력된 순서를 유지

'~2022 > Java' 카테고리의 다른 글

[Java] HashMap, HashTable, ConcurrentHashMap  (0) 2021.10.25
[Java] Atomic Class  (0) 2021.10.12
[Java] DTO와 VO의 차이  (0) 2021.08.22

Redis는 완전한 데이터 정합성을 보장하기 위해 아래와 같이 뮤텍스와 세마포어를 사용한다.

두 프로세스가 거의 동시에 세마포어를 얻으려고 하는 경우를 대비해 락을 걸어놓은 것 같다.

def acquire_semaphore_with_lock(conn, semname, limit, timeout=10):
   identifier = acquire_lock(conn, semname, acquire_timeout=.01)
   if identifier:
      try:
         return acquire_fair_semaphore(conn, semname, limit, timeout)
   finally:
      release_lock(conn, semname, identifier)

물론 데이터 정합성 측면의 trade-off를 감수하고 더 simple한 세마포어를 사용하는 옵션도 지원한다고 한다.

(다만 System clock을 사용해야 하며, 스레드가 세마포어 limit을 초과하여 data에 접근하는 경우가 발생할 수 있다.)

 

 

[참고 사이트]

https://redis.com/ebook/part-2-core-concepts/chapter-6-application-components-in-redis/6-3-counting-semaphores/6-3-4-preventing-race-conditions/

'~2022 > Database' 카테고리의 다른 글

[DB] ANSI SQL이란?  (0) 2021.08.22

Atomic Class는 volatile 키워드CAS 알고리즘을 사용해

다중 스레드 환경에서 읽기/쓰기 작업을 병행해도 Data의 정합성을 보장하는 Class이다.

스레드를 Blocking하지 않기 때문에 Syncronized 블록을 사용하는 것 보다 성능적면에서 유리하다.

 

** Atomic Integer와 int로 값 증가 iteration 시간 비교

    public static void main(String[] args) {

        long stAtomic = System.currentTimeMillis();
        long stAtomicNano = System.nanoTime();
        AtomicInteger atomicNum = new AtomicInteger(0);
        for (int i = 0; i < 1000_0000; i++) {
            atomicNum.addAndGet(1);
        }
        long etAtomic = System.currentTimeMillis();
        long etAtomicNano = System.nanoTime();
        System.out.println((etAtomic - stAtomic) + " ms");
        System.out.println((etAtomicNano - stAtomicNano) + " ns");

        long st = System.currentTimeMillis();
        long stNano = System.nanoTime();
        long num = 0;
        for (int i = 0; i < 1000_0000; i++) {
            num++;
        }
        long et = System.currentTimeMillis();
        long etNano = System.nanoTime();
        System.out.println((et - st) + " ms");
        System.out.println((etNano - stNano) + " ns");

        System.out.println(atomicNum);
        System.out.println(num);
    }

10만: 2.02 ms / 0.17 ms

100만: 6.59 ms / 4.91 ms

1000만: 45.84 ms / 4.33 ms

1억: 460.82 ms / 5.52 ms

10억: 4394.06 ms / 11.17 ms

 

'~2022 > Java' 카테고리의 다른 글

[Java] HashMap, HashTable, ConcurrentHashMap  (0) 2021.10.25
[Java] HashMap, TreeMap, LinkedHashMap  (0) 2021.10.25
[Java] DTO와 VO의 차이  (0) 2021.08.22

필터(Filter)

- 디스패처 서블릿(Dispatcher Servlet)에 요청이 전달되기 전/후에 url 패턴에 맞는 모든 요청에 대해 부갖가업을 처리할 수 있는 기능 제공

- 톰캣과 같은 웹 컨테이너에 의해 관리됨

- 추가 방법: javax.servlet의 Filter 인터페이스를 구현

- 스프링과 무관하게 웹 애플리케이션에 전역으로 처리해야 하는 작업들을 처리
    ex) 보안(XSS 방어), 요청에 대한 로깅 또는 감사, 이미지/데이터 압축 및 문자열 인코딩

- 다음 체인으로 넘기는 ServletRequest/ServletResponser 객체를 조작할 수 있다는 점에서 Interceptor보다 강력한 기술

 

인터셉터(Interceptor)

- 스프링이 제공하는 기술로, 디스패처 서블릿((Dispatcher Servlet)이 컨트롤러를 호출하기 전과 후에 요청과 응답을 참조하거나 가공하는 기능 제공

- 스프링 컨텍스트에서 동작

- 추가 방법: org.springframework.web.servlet의 HandlerInterceptor 인터페이스를 구현

- 클라이언트의 요청과 관련되어 전역적으로 처리해야 하는 작업들을 처리

    ex) 인증/인가 등의 공통 작업, API 호출에 대한 로깅 또는 감사, Controller로 넘겨주는 데이터 가공

- 인터셉터는 필터와 다르게 HttpServletRequest나 HttpServletResponse 등과 같은 객체 자체를 조작할 수는 없다
  대신 해당 객체가 내부적으로 갖는 값을 조작할 수는 있으므로 컨트롤러로 넘겨주기 위한 정보를 가공하기에 용이

- 클라이언트의 IP나 요청 정보들을 기록하기에 용이

 

AOP(Aspect Oriented Programming)

- 로깅, 트랜잭션, 예외/에러처리 등 비즈니스 레이어의 메서드에서 세밀하게 조정하고 싶을 때 사용

- Interceptor나 Filter와는 달리 메소드 전후의 지점에 자유롭게 설정이 가능하다.

- Interceptor와 Filter는 주소로 대상을 구분해서 걸러내야하는 반면, AOP는 주소, 파라미터, 애노테이션 등 다양한 방법으로 대상을 지정할 수 있다.(=포인트컷 설정으로 적용할 메서드를 선별해야 한다)

- Spring 컨트롤러는 타입이 일정하지 않고 리턴 값이 일정하지 않으므로, AOP 적용이 번거로울 수 있다.

 

** AOP의 Advice와 HandlerInterceptor의 가장 큰 차이는 파라미터의 차이다.

** Advice의 경우 JoinPoint나 ProceedingJoinPoint 등을 활용해서 호출하는 반면,

   HandlerInterceptor는 Filter와 유사하게 HttpServletRequest, HttpServletResponse를 파라미터로 사용한다.

 

 

[참고 사이트]

https://mangkyu.tistory.com/173

'~2022 > Spring' 카테고리의 다른 글

[Spring] Dependency Injection 종류와 장단점  (0) 2021.09.14
[Spring] AOP 개념 및 요약  (0) 2021.09.08

필드(Field) 방식 
- @Autowired 를 이용한 의존 자동 주입

   - 장점 : 설정 코드에서 직접 주입하지 않고 스프링이 자동으로 빈 객체를 주입. 간편한 코드를 짤 수 있다.

   ** 자동 주입할 빈이 없거나, 주입 대상에 일치하는 빈이 2개 이상이면 UnsatisfiedDependencyException
   ** @Qaulifier 어노테이션을 사용해 자동 주입할 빈을 지정할 수 있다.

   - 단점 : 프로그램의 복잡도가 증가하는 것을 알아차리기 힘들다.

생성자(Constructor) 방식
- 빈 객체를 생성하는 시점에 모든 의존 객체가 주입된다.

   - 장점: 빈 객체를 생성하는 시점에 필요한 모든 의존 객체를 주입받기 때문에 객체를 사용할 때 완전한 상태로 사용할 수 있다. (반면 세터 메서드 방식은 Setter에 인자로 넣어주지 않으면 오류가 발생할 수 있다.)

   - 장점: 순환 참조 코드를 짜면 BeanCurrentlyInCreationException 을 발생시켜 순환 참조를 사전에 방지할 수 있다.
          이는 생성자의 인자에 사용되는 빈을 찾거나 팩토리에서 만든 후에 생성자를 호출하기 때문이다.

   - 장점: 생성자 주입을 사용하게 되는 경우 생성자의 인자가 많아짐에 따라 복잡한 코드가 됨을 쉽게 알 수 있다.  
          -> 리팩토링하여 역할을 분리하는 등과 같은 코드의 품질을 톺이는 활동의 필요성을 더 쉽게 알 수 있다.   

   - 장점: 주입되는 객체를 final로 선언하여 초기화 후에 빈 객체가 변경되지 않도록(Immutable) 할 수 있다.   

   - 장점: 테스트 코드 작성이 편리하다. 단순 POJO를 이용한 테스트 코드를 만들 수 있다.

   - 단점: 생성자의 파라미터가 많을 경우 각 인자가 어떤 의존 객체를 설정하는지 알아내려면 생성자의 코드를 확인해야 한다.

세터 메서드(Setter Metohd) 방식
- 세터 메서드 이름을 통해 어떤 의존 객체가 주입되는지 알 수 있다.

   - 장점: 메서드 이름으로 어떤 의존 객체를 설정하는지 알 수 있다. 

   - 단점: 필요한 의존 객체를 전달하지 않아도 빈 객체가 생성되므로 NullPointerExeption이 발생할 수 있다.

 

+ Recent posts