2021-12-31

12/31 토큰인증

 1. 토큰을 api요청시마다 확인하는건 너무 과부하.. 따라서 한번 인증되면 - 캐싱해둔다. 이때는 RDB같은 file 혹은 디스크 IO기반의 저장소보다. 메모리기반의 저장소(redis, memcached)를 사용한다

2. MSA서비스에서의 인증 / 인가 방식

1) 모든 서비스api가 공유하는 중앙저장소 사용 : redis, memcached 등

2) api gateway 에서 직접 인증/인가 구현

3) api gateway 와 auth service협력하여 인증/인가 구현

3. 토큰인증

# 필요성?

- 모바일 app의 경우, web과 달리 cookie jar기능이 없다. 따라서 세션/쿠키 방식의 전통적인 인증인가가 불가능하다.

- 모바일 app의 경우 , json으로 데이터를 주고받는데. 웹은 html로 응답하므로 불일치가 발생한다. 

=> json방식 토큰인증을 사용하여 인증/인가를 일원화할수있다는 편리함? 장점이 있다.


# 취약점?

- 토큰인증이든 쿠키인증이든.. 탈취위험성에는 쌤쌤.

그럼 탈취되었다고 가정하고. 토큰의 경우에는 서버쪽에서 이 토큰의 유효기간을 끊어낼방법이 없다고한다 ? -> 그래서 이걸 해결하려고 공유 저장소를 사용한다 

-> 근데 이러면 결국 stateless하게 인증인가한다는 장점을 버리게 되는거 아니냐?라는 . 

결국엔 장단점이 있고... 아아 좀더 공부하자!!!

인증인가가 심오하구나. 쉽게쉽게 스프링시큐리티 붙이면 되지머~ 하고 볼게 아니다.!!!

2021-12-30

12/30 super() 호출

 - spring cloud gateway 에서 , 커스텀 필터를 만들때 주의사항

- AbstractGatewayFilterFactory 를 상속하여 apply 메서드를 구현한다

단. 상속하는 부모의 생성자는 제네릭 파라메터로 들어가는 C타입을 부르는 생성자 뿐이다.

그러나 자바에서는 생성자를 명시적으로 작성해주지 않았을때 기본생성자만 만들어주고, 만든 생성자가 있으면 기본생성자를 불러주지 않는다.

- 내가 CustomFilter 를 만들었을때 - 이 부모의 생성자를 불러주지 않아서 오류가 발생했다. 

- 명시적으로 부모의 생성자를 호출하든지 아니면 부모에 기본생성자를 추가해야 함 (당연히 이건 내가 클라이언트로서 사용하는거니까 불가능..) 

현재 AbstractGatewayFilterFactory의 기본생성자또한 자기 부모의 super를 호출하고 있음. 여기에 넘겨줄 C타입의 class 가 필요. 



2021-12-27

12/27 반복자의 상태와 컬렉션의 상태가 다를때 발생하는 에러

 


반복자의 상태와 컬랙션의 상태가 동기화 되지않기 때문에 에러가 발생한다.

(for-each문은 내부적으로 iterator로 해석됨.)

iterator를 명시적으로사용하고 remove를 호출하면 이러한 문제를 해결할 수 있지...만!!

이때문에 removeIf라는 메서드가 등장하였다!

2021-12-26

12/26 무한스트림 OOM을 주의하기 ㅋㅋㅋ

 

무한스트림을 생성한후 limit하는 걸 까먹었더니 생전처음 oom을 만났다... 웃기다 ㅋㅋ

12/26 비동기 논블로킹 서블릿 스레드

 1. 서블릿 스레드가 요청(작업)을 받는다(서블릿 스레드 풀에서.)  

2. 비지니스 로직을 처리한다 -> 이부분을 워커 스레드에게 위임하고 return

3. 워커스레드가 돌아오면, 서블릿스레드 풀에 그 작업이 다른 스레드에게 할당. 유저에게 response를 준다. 

-

논블로킹이 아니었을 경우

->2번에서 블로킹이 일어나므로. 해당 스레드 대기큐로 들어가서 쿨쿨 잔다.

-> 메모리 사용량은 올라가는데 cpu는 놀고있는 비효율적인 상황발생.

-

비동기 블로킹 / 비동기 논블로킹을 잘 구분해야!!


2021-12-25

12/25 람다 혹은 익명클래스 외부변수 접근 제약





 Variable used in lambda expression should be final or effectively final

- 람다, 익명클래스는 다른 스레드에서 실행될 수 있다.

- 만약에 람다,익명클래스가 외부변수에 자유롭게 접근할수있다고 해보자.

- 그 람다/익명클래스를 만든 스택은 이미 사라지고 free변수도 사라졌는데, 람다/익명클래스는 그 지역변수를 계속해서 참조하려고 하는 에러가 발생한다.

- 따라서 , final 혹은 effectively final 인 외부변수에만 람다/익명객체는 접근할 수 있다.

-원래는 final키워드를 명시적으로 붙이는것이 맞으나 1.7부터는 컴파일러가 알아서 붙여준다고 한다.

-그러므로 - 결론적으로 :

- 람다/익명객체는 외부변수에 자유롭게 접근 가능하다.

- 그러나 지역변수의 경우 스택에 위치하므로, effectively final한 특성을 가지고 있어야 한다.

- 위 코드의 경우 effectively final 해야한다는 특성을 어겼으므로 컴파일러가 final키워드를 붙여서 처리해줄수없다. 따라서 에러가 난다.


2021-12-24

12/24 스레드 무한정 생성해보기

 유투브가 버벅대고 다른 프로그램이 열리지않게 됨 ㅋㅋㅋㅋ 재밌다 ㅋㅋㅋ

스레드 무한생성하는 main두개 돌린결과..





12/24 리액티브 모델

 1. 메시지 드리븐 / 이벤트 드리븐

message driven : 하나의 목적지를 향한다.

event driven : 해당 이벤트가 등록된 컴포넌트를 향한다.

-> 이벤트 드리븐 모델에서는 특정 메시지와 특정 어플리케이션이 결합되지 않도록 하여, 유연성을 유지하고자 한다. 

2. 리액티브 프로그래밍 

- 반응성 : 유저에게 밀리세컨드 단위로, 좀더 빠르게 응답할수있어야 한다. 

- 회복성 : 장애가 일어났을때 회복할수있는 방법이 있어야 한다. 작업을 다른 어플리케이션에게 위임한다던지 등등. 

- 탄력성 : 부하가 가해졌을때 크기를 확장하는 등 탄력적으로 대응할 수 있어야 한다. 

- 이벤트 드리븐 : 발행 - 구독 방식으로 대응할 수 있어야 한다. 

3. 이벤트 드리븐 방식으로 인하여, 어떠한 하나의 어플리케이션에 장애가 일어나더라도 그 장애는 다른 어플리케이션으로 전파되지 않는다. 직접적으로 메시지로 연결되어있지 않기 때문이다. (kafka나. messageMQ를 쓰는데는 다 이유가 있던것이다...) 어떤 어플리케이션에 장애가 일어날 경우, 그 어플리케이션은 회복될때까지 격리된다. 
- 만약에 메시지 드리븐 방식이었다면, 해당 메시지가 특정 어플리케이션을 직접적으로 가리키므로, 장애가 일어나면 장애가 계속 연쇄적으로 전파되었을 것이다. 

- 하나의 공통된 DB에 의존하기 보다 카프카와 같은 발행-구독 기반 모델을 사용하여, 서로간의 결합도를 낮추고 - 좀더 장애에 탄력적인 서비스를 제공할 수 있게 된다.

12/24 블로킹과 논블로킹

 



일반적인 메서드의 경우 delay가 되는동안 - 해당 스레드는 아무작업을 하지않고 룰루랄랄라 하면서 네트워크/IO/DB에서 데이터 읽어오기 등등... 의 결과가 돌아오는 것을 기다린다. 이 동안 블로킹이되며 해당 스레드가 맡고있는 태스크가 있기 때문에 다른 작업이 할당되지 않는다. 


그러나 논블로킹으로 할경우 , 작업을 다른 스레드에게 맡기고 - 호출된 스레드는 바로 반환된다. 이렇게 함으로써 반환된 스레드는 다른 작업을 하고 있을 수 있다. CPU 연산작업도 하면서 네트워킹 기능도 수행하고 이렇게 효율적으로 스레드 자원을 사용할 수 있는것이다.

이러한 작업을 CompletableFuture 혹은 Future 를 통하여 구현할수있다. 

단 Future.get() 메서드를 불렀을때 작업이 완료되지않은 상태이면 그동안 블로킹이 되는데, 그렇기 때문에 타임아웃을 설정하는 등 고려해볼 수 있다. 

12/24 블로킹 주의하기

1. 블로킹이 되는 경우 : 스레드가 잠을 자는 상황 - 

 - 어떤 동작을 완료하기를 기다리거나 (Future 의 get 메서드)

- 외부와의 상호작용을 기다리는것 - (네트워크 통신, 데이터베이스 서버에서 데이터 가져오는 것 기다리기, 키보드 입력 기다리기 ) 

2. 블로킹이 되면, 해당 태스크가 할당된 스레드는 쿨쿨 잠잔다. 중요한 자원의 낭비!!

3. 따라서 블로킹이 될경우. 해당 스레드가 다른 작업을 할 수 있게끔 해야한다!!

4. ScheduledExecutorService를 통하여 이것을 할수있다

- 작업을 할당하고 - 자는동안. 블로킹을 해서 마냥 기다리는 것이아니라. 블로킹이 되면 일단 해당 스레드 종료!

 그리고 나서 네트워크통신이든 데이터베이스든 다시 입력이 들어오면. 스레드에게 작업을 할당하여 완료할수있도록 스케쥴링!!

12/24 스레드풀의 사용 주의점, concurrent 프로그래밍의 주의점

 1. java 5 부터 Executor와 ExecutorService를 제공한다. 

- 장점: 이를통하여, 이제 개발자는 스레드를 직접 다루지 않고 동시성프로그래밍을 하는 것이 가능해졌다.

- 어떠한 작업을 실행할지를 정의하는 것과, 작업을 제출하여 실행하는 것을 분리하였다. 

- ExecutorService가 스레드 스케쥴링 .. 큐 우선순위.. 작업할당을 알아서 해주므로 매우 편리하다!!

- 단점 : ExecutorService는 , 하나의 스레드에 하나의 작업만을 할당한다. 따라서, 만약에 5개의 스레드중 앞의 3개의 스레드가 잠을자거나 / IO요청이 일어나거나 /네트워크통신을 해야한다면 - 이들은 idle하게 놀고있음에도 불구하고, 이미 할당된 task가 완료되지 않아 룰루랄라하는 비효율적인 상황이 발생한다. 결국 남은 2개의 스레드가 나머지 작업들을 뻘뻘 해야한다. ㅠㅠ

2. concurrent 와 parallel의 차이

- fork-join을 생각하면, parallel로 이루어지는 작업에 대하여 보다 직관적으로 이해할 수 있다. 어떠한 작업을 제출하고, 그 반환을 메서드 안에서 기다린다. (엄격한 fork-join) 이것은 여러 스레드가 동시에 실행할 수 있다. 메서드가 시작되고 완료된 값을 return 한다. 분할 정복. 

- 반면, concurrent - 이를 테면, 여러 클라이언트의 작업을 동시에 처리하는 웹 서버. 는 상황이 다르다... 

- 비동기 프로그래밍이란, 메서드의 실행 -> 반환이 완료된 후에도, 그 작업이계속해서 이루어지는 것이다. 

3. 비동기 프로그래밍의 주의점

- 메서드가 실행되고, 반환 (return ) 된 이후에도 만들어진 태스크 실행이 계속되는 메서드를 비동기 메서드라고 한다. 

- 어떠한 문제가 발생할수있는가 ? 우선 '종료된 이후에도'라는 측면에 초점을 맞추어 생각해보자. 

- jvm은 유저가 만든 중요한 작업이 main이 실행된 후에도 계속될수있게끔 하기위하여 - main이 종료되더라도, 실행중인 task 가 있다면 종료되지 않는다. 하지만 그러면 메모리 leak이 발생하거나. 프로그램이 crash될 것이다. 

- 그럼 main이 종료될때 남아있는 task를 전부 강제종료 해버리자 ? -> 만약에 해당 task가 IO를 수행하면서 디스크에 파일을 쓰고있었는데 갑자기 강제종료당해서 작업이 중지된다면? 해당 파일은 못쓰는 파일이 될것이고 데이터에 손상이 가해질 것이다. 

-> 이러한 문제점의 해결책으로, setDemon을 하여 주요작업스레드가 종료되면 함께 종료하게 하거나.. ExecutorService와 같은 프레임워크를 사용하고 있는 경우 우아하게 종료를 해주는 습관을 가지는 것이 중요하다!!! 

- 어떤 스레드에 어떤 작업을 할당하였는지 추적하는 사고를 가지자!!

12/24 자바 동시성 프로그래밍

 1. 자바 동시성 프로그래밍 

2. 서비스 제공 환경의 변화

- 이제는 독립적으로 모든 서비스를 제공하는 어플리케이션 보다는.

- 여러 서비스들을 매쉬업하여 제공하는 서비스가 대부분이고

- 이 때문에. 마이크로서비스라는 모델도 등장하게 된것이다 - 

3. 서비스 매시업

- 이를테면 구글의 검색결과를 바탕으로 필터링한 데이터를 번역하고 트위터에서도 검색한 결과를 필터링하고... 그런 서비스를 제공해주고 싶다고 하자

- 그러면. 구글에서 검색한결과를 찾아오는 동안 해당 스레드가 블로킹되면 많은 지연이 발생할것이다

- 구글검색결과를 가져올동안. 트위터에서도 검색결과를 받고 번역작업을 동시에 실행하고 싶은것 - 

- 이를 달성하기 위하여 동시성 프로그래밍을 하고 성능향상 효과를 기대해 볼 수 있다

4. 동시성 / 병렬성

- 동시성은. 연관된 작업을 단일 코어 머신에서도 실행할 수 있다

- 병렬성은 하드웨어 수준에서 멀티코어를 지원할때 실행 . 여러작업을 fork -> join 하기 때문에. 외부 데이터에 영향을 받지 않는 안전한 함수여야 한다. 결합법칙이 성립해야한다. 

2021-12-19

1219 바인드 변수를 사용하기, I/O란

 1. 직접 막바로 파라메터를 날리는 것 X

2 . 바인드 파라메터 , 마이바티스로 치면 {#파라메터}를 사용한다

3. SQL은 각각 하나하나가 키가 된다.

select * from emp , SELECT * from emp 는 다른 SQL이다. 의미적으로는 같지만 - 자바의 메소드 처럼 이름을 따로 가지고 있지 않고, 그자체로 그냥 하나의 키가 된다. 조금의 변경사항이 반영되면 또 다른 SQL이 되고, 그때마다 파싱 및 옵티마이저의 비용계산과 로우소스생성이 이루어진다. 

4.  I/O란 ? = 잠. sleep.

디스크 i/o가 발생하면, 프로세스는 하던 일을 멈추고 대기큐에 들어가서 쉬고있는다. (디스크 i/o작업이 완료될때까지. ) 그래서 만약 i/o요청이 많이 들어오면 - 프로세스는 그만큼 쿨쿨 대기큐에서 잠을 자게 되므로, 성능이 느려질 수밖에 없다. 

5. 데이터베이스 저장 방식

테이블 스페이스 -> 세그먼트 (인덱스 , LOB, 테이블 등) -> 익스텐트(데이터가 더 필요할시 확장해주는 단위) -> 블록 (하나의 테이블이라고 이해해도 무방. )

하지만 물리적으로는 쪼개어서 데이터 파일에 저장될 수 있다.

2021-12-17

1217 DB 튜닝

 1. SQL 처리과정

1) SQL 파싱 : 문법에 틀린것이 없는지. 없는 테이블을 액세스하라는 것은 아닌지 검사한다. 

2) 실행계획 : 옵티마이저가 가능한 경로중에서 비용이 적은 것을 선택한다.

3) 처리 : 로우레벨의 언어로 SQL을 변환하여 실행한다. 


2. OLTP : 온라인 트랜잭션 시스템(프로그램) : 데이터를 컴퓨터를 이용하여 처리하는 것을 의미한다. 

3. 실행계획의 어려움 : 비용을 산정하여 비용이 가장 적은 것을 선택한다. 

이 비용산정에는 다양한 요소들이 고려되게 된다...

- 이를테면, 인덱스 스캔을 할지 풀스캔을할지. 인덱스를 쓴다면 어떤 인덱스를 쓸것인지 조인순서. 조인방법. CPU성능. IO방법. 지금까지의 통계치 등등. 아무리 알고리즘이 발달했다고는 하지만? 이러한 실행계획을 매번매번 짜는것은 옵티마이저에게 엄청난 고통이다. ㅜㅜ. 5개 테이블 조인한다고 생각했을때 조인순서만 고려해도 5팩토리얼개의 경우의 수이다....

-> 그래서 사용하는 것이 캐싱!

4. 캐시 히트 했을경우 소프트파싱 / 캐시실패했을 경우 하드파싱이라고 한다. 

5. 글로벌 영역에 캐싱해두었다가, 이것을 가져와서 실행하면 실행계획을 다시짜지않아도 되므로 훨씬 효율적이라고 할 수 있다. 

6. 힌트를 사용하여 옵티마이저에게 명시적으로 이렇게 수행해!! 라고 명령할 수 있다. 기본적으로 SQL은 질의언어 - 선언적 성격이기 때문에 그 방식(method)를 유저가 직접명령하지 않는다. 옵티마이저가 알아서 짜준다. 근데 넘 어려우니까.. 유저가 알고있는 요소를 옵티마이저에게 전달하여 좀더 효율적인 실행계획을 수행하도록 도와줄 수 있다는 것이다. 

2021-12-10

1210 유용한 스레드 관련 클래스

 1. ExecutorService 

Executors.어쩌구로 스태틱 생성자 호출해서 만들수도 있고

아니면 ThreadPoolExecutor 생성자 new 해서 좀더 세부적인 셋팅 할 수도 있다. 맥스 스레드 사이즈, 코어 스레드 사이즈 등등. 

2.  CountDownLatch

일단 생성자로 카운트를 받고

countdown() : 해당 카운트를 하나씩 감소 시킨다.

await() : 카운트가 0이되면, 기다리고 있던 스레드가 해소된다.

3. CyclicBarrier

CountDownLatch랑 비슷하다.

다른점은, CountDownLatch 는 await () 을 하고 있는 애한테만 영향이 간다.

근데 CyclicBarrier는 해당 카운트다운에 참여하고있는 모든 스레드가 기다리고, 한꺼번에 장벽이 풀리면서 쏵!!하고 작업을 수행한다.


아직 많이 헷갈림. ㅠㅠ

2021-12-08

1208 스트림은 주의해서 사용하라

 스트림을 이용하여 이중 for 문을 구현할수있다. 

스트림.of메서드를 사용하여 해당 리스트를 스트림으로 만든다. Arrays.stream() 메서드와 같은 역할을 한다. 



2021-12-05

1205 타입안전이종컨테이너를 고려하라

 


상속할경우- 런타임에도 해당 클래스의 타입이 지워지지 않고 남는다!! 

1205 제네릭과 가변인수를 함께 쓸때에는 신중하라

 

결국엔 List.of 메소드(varargs를 받는) 도 내부적으로 Object[] 배열을 만들어서 하나씩 넣고있다.

새로운 원소를 추가 삭제하는 것이 아니라 단순히 변환하여 전달하는 용도로 쓰여지고 있으므로 safe하다고 말할수있을것이다

근데 웃기는거는 12개? 까지는 of메서드 다 만들어뒀더라 ㅋㅋㅋㅋ 귀엽ㅋㅋㅋ성능최적화인듯 ㅋㅋ

1205 제네릭과 가변인수를 함께 쓸 때는 신중하라

 



가변인수를 받을경우

배열이 내부적으로 생성된다. (Object[])

해당 Object타입의 배열에는 어떠한 타입이든 들어갈수있으므로(배열은 공변)

힙오염이 발생하게 되고

class cast exception이 발생한다.!!


2021-12-04

1204 이왕이면 제네릭 메서드로 만들라

 

제네릭 메서드를 활용하여 타입안전한 메서드를 클라이언트에게제공한다!!!!

1204 이왕이면 제네릭 타입으로 만들라

 제네릭 타입의 stack만들기 

1번 : generic E타입을 받는 배열을 내부적으로 만들고

supressWarnings("unchecked")를 이용.

Object배열을 만든다음에 형변환한다



2번: 내부적으로 Object[] 배열을 만들고

원소를 내보낼떄 (pop()메소드) 에서 E타입으로 캐스팅하는 메소드 만든다



1204 로타입은 사용하지 말라

 

뭐야 결국엔 타입안전 안하다는 거 아니야?? 어이가. 없네??

2021-12-03

1203 상속을 고려해 설계하고 문서화하라. 그러지 않았다면 상속을 금지하라

 




오버라이드 한 메서드가 부모 클래스의 생성자에서 불리고 있었다.
-> 결과, 하위클래스의 생성자가 불리기도 전에 해당 메소드가 불리게 된다.
해당 오버라이드한 메서드가 하위클래스의 인스턴스를 조작하는 행위를 하고있었기때문에-
NPE가 발생했다!!
호움!!
비슷하게 주의해야 하는경우.
오버라이드한 메소드가 상위클래스 내부의 private메소드를 사용하여 무언가 작업을 하는경우.
상위클래스의 구현변경에 의해 하위클래스가 영향을 받는다!!
ex ) Set클래스를 extends 해서 addAll 메서드를 조작했더니, 영향을 받음...

0328 fdisk, mkfs, mount, fstab

 1. 하드디스크를 붙인다. 2. fdisk -l로 하드디스크를 확인한다.  - interactiive한 커맨드모드 사용하여 (m) 붙인 하드디스크의 파티셔닝을 한다.  - 마지막에 w를 해야 실제로 반영이 된다.  3. mkfs를 하여 어떤 파일시스...