├── DataStructure_Algorithm ├── 2022-04-01-Array&ArrayList&LinkedList.md ├── 2022-04-01-Array.md ├── 2022-04-01-ArrayList.md ├── 2022-04-01-LinkedList.md ├── 2022-04-08-BinarySearchTree.md ├── 2022-04-15-Heap.md ├── 2022-04-22-hash.md ├── 2022-04-29-B-Tree, B+Tree.md ├── 2022-05-10-Queue,Stack,Stable,Unstable.md ├── images │ ├── hash-chaining.png │ ├── hash-openaddressing.png │ ├── hash.png │ ├── heap-heapify.png │ ├── heap-insert2.png │ ├── heap-remove.png │ ├── heap_index.png │ └── types-of-heap.png └── 목차.md ├── Database ├── 2022-04-01-SQL과NoSQL.md ├── 2022-04-08-트랜잭션.md ├── 2022-04-15-Index.md ├── 2022-04-22-정규화와반정규화.md ├── 2022-04-29-SQL_Injection.md ├── 2022-05-10-Lock.md ├── README.md └── images │ └── transaction-status.png ├── DesignPattern └── Singleton Pattern.md ├── Java ├── 2022-04-01-jvm.md ├── 2022-04-07-garbageCollection.md ├── 2022-04-15-JavaThread.md ├── 2022-04-22-Generic.md ├── 2022-04-29-final, 불변 객체.md ├── 2022-05-10-reflection.md ├── 2022-05-24-equals&hashcode.md ├── 2022-05-24-filter,interceptor.md ├── images │ ├── compact.PNG │ ├── eden.PNG │ ├── gc_root.png │ ├── java-entry-wait-set.png │ ├── jvmheap.png │ ├── majorgc.PNG │ ├── majorgc2.PNG │ ├── mark.png │ ├── minorgc.PNG │ ├── minorgc2.PNG │ ├── sweep.PNG │ └── threadLifeCycle.jpg └── 목차.md ├── Network ├── 2022-04-01-OSI7계층.md ├── 2022-04-08 HTTP의 특징, 메소드, 상태코드.md ├── 2022-04-15-Cookie,Session,JWT.md ├── 2022-04-21-TCP_UDP.md ├── 2022-04-28-TLS&SSL.md ├── 2022-05-10-CORS.md ├── 2022-05-24-Web_Server,WAS,Servlet.md ├── 2022-06-09-WebSocket.md ├── 2022-06-16-DNS, Round-Robin.md ├── 2022-06-16-Redirect,Forward.md ├── 2022-07-12-HTTP3.md ├── 2022-07-18-VPC.md ├── 2022-07-19-Domain,DNS_Server.md ├── images │ ├── aimd.png │ ├── fast-transmit.png │ ├── handshake.gif │ ├── http3.png │ ├── one_key.png │ ├── slidingwindow.png │ ├── slow-start-chart.png │ ├── stopAndWait.png │ ├── tcp-header.png │ ├── tcp3handshake.png │ ├── tcp4handshake.png │ ├── tcp_udp.png │ ├── tcp_순서보장.PNG │ ├── tls_handshake.png │ ├── two_key.png │ ├── udpheader.png │ └── updtcp.png └── 목차.md ├── OS ├── 2022-04-01-프로세스와쓰레드.md ├── 2022-04-08-DeadLock.md ├── 2022-04-15-CPU_Scheduler.md ├── 2022-04-22-메모리관리.md ├── 2022-04-29-캐시.md ├── 2022-05-10-시스템 콜.md ├── images │ ├── MQ.png │ ├── NP.png │ ├── cp.png │ ├── cpu_ram_성능차이.png │ ├── memory_map.png │ ├── pipe.png │ ├── process.png │ ├── shared_memory.png │ ├── socket.png │ ├── syscall.png │ ├── thread.png │ ├── 메모리_계층_구조.png │ ├── 캐시_Latency.png │ ├── 캐시_메모리구조.png │ ├── 캐시_사용_사례.png │ ├── 캐시미스.png │ ├── 캐시히트.png │ └── 컴퓨터_동작_흐름.png └── 목차.md ├── README.md └── Spring ├── 2022-05-24-AOP.md ├── 2022-06-09-HttpMessageConverter.md ├── 2022-06-09-spring,springboot.md └── images ├── argumentResolver.png ├── handleMethodArgumentResolver.png ├── handleMethodReturnValueHandler.png ├── httpMessageConverter.png └── httpMessageConverter2.png /DataStructure_Algorithm/2022-04-01-Array&ArrayList&LinkedList.md: -------------------------------------------------------------------------------- 1 | # Array vs ArrayList vs LinkedList 2 | 3 | 이 중, 두 개 또는 세 개 모두를 짝지어서 비교하는 질문이 자주 나옵니다. 4 | 5 | *** 6 | 7 | ### Array 8 | 9 | 10 | 11 | - Index로 접근 가능함 12 | - 삭제,삽입 시 shift 발생 13 | - 고정 크기 14 | - 논리적 저장 순서와 물리적 저장 순서가 일치함 15 | 16 | *** 17 | 18 | ### Array List 19 | 20 | 21 | 22 | - Index로 접근 가능함 23 | - 삭제,삽입 시 shift 발생 24 | - 가변 크기 : 꽉 차면 새로 더 큰 배열을 할당한다 25 | - 내부적으로 배열로 구현되어있다. 26 | 27 | *** 28 | 29 | ### Linked List 30 | 31 | 32 | 33 | - Index로 접근 불가능 34 | - 탐색이 비교적 느리지만, 삭제, 삽입 시 shift 발생하지 않음 35 | - 가변 크기 : 새로운 요소가 추가될 때마다 메모리를 할당한다 (동적 메모리 할당) 36 | - 논리적 저장 순서와 물리적 저장 순서가 일치하지 않음 37 | -------------------------------------------------------------------------------- /DataStructure_Algorithm/2022-04-01-Array.md: -------------------------------------------------------------------------------- 1 | # Array 2 | 3 |

배열이란

4 | 5 | 가장 기본적인 자료구조로 여러개의 데이터를 저장하기 위해서 사용한다. 6 | 7 | **논리적 저장 순서와 물리적 저장 순서가** **일치한다.** 8 | 9 | 따라서 **인덱스로 원소에 접근**할 수 있다. 10 | 11 | 이로 인해 다음과 같은 특징이 있다. 12 | 13 | - 탐색 14 | - 원소의 인덱스 값을 알고 있으면 O(1)에 해당 원소로 접근할 수 있다. 15 | - **Random Access**가 가능하다. 16 | - 삭제 17 | - 특정 원소를 삭제 한 뒤, 1씩 shift를 해줘야 한다. 18 | - 특정 원소 삭제에는 O(1)이, shift에는 O(n)이 걸리기 때문에, 최종적으로 배열에서 최악의 삭제 시간 복잡도는 O(n)이 된다. 19 | 20 | 21 | - 삽입 22 | - 특정 원소를 삽입하기 위해서는, 해당 위치부터 1씩 shift를 실행한 뒤, 원소를 삽입해야 한다. 23 | - shift에는 O(n)이 걸리고 원소 삽입에는 O(1)이 걸리므로, 최종적으로 배열에서 최악의 삽입 시간 복잡도는 O(n)이 된다. 24 | 25 | 26 | 27 |

Java의 배열

28 | 29 | Java에서 배열은 같은 타입의 데이터를 연속된 공간에 나열시키고, 각 데이터에 인덱스를 부여해 놓은 자료구조이다. 30 | 31 | Java에서 배열은 다음과 같은 방법으로 선언할 수 있다. 32 | 33 | ```java 34 | //1.기본적인 배열 선언 방법 35 | 타입[] 변수; 36 | int[] intArray; 37 | double[] doubleArray; 38 | 39 | //2.값 목록으로 배열 생성 40 | 데이터타입[] 변수 = {값0, 값1, 값2, ...}; 41 | 42 | //3.배열 변수를 미리 선언한 후 값 목록으로 배열 생성하는 방법 43 | 타입[] 변수; 44 | 변수 = new 타입[]{값0, 값1, 값2, ...}; 45 | 46 | //4.new 연산자로 길이 지정해서 배열 생성 47 | 타입[] 변수 = new 타입[길이]; 48 | ``` 49 | 50 | 4번 같은 경우에는 데이터 타입 별로 다음과 같이 초기화가 된다. 51 | 52 | | 분류 | 데이터 타입 | 초기값 | 53 | | --- | --- | --- | 54 | | 정수 타입 | byte[]
char[]
short[]
int[]
long[]| 0
’\u0000’
0
0
0L | 55 | | 실수 타입 | float[]
double[] | 0.0F
0.0 | 56 | | 논리 타입 | boolean[] | false | 57 | | 참조 타입 | 클래스[]
인터페이스[] | null
null | 58 | 59 | ### Java 배열의 특징 60 | 61 | - 같은 타입의 데이터만 저장할 수 있다 62 | - 한 번 생성된 배열은 길이를 늘리거나 줄일 수 없다. 63 | - 길이를 늘리거나 줄이고 싶다면, 원하는 길이를 가진 새로운 배열을 생성하고, 기존 배열 항목을 새 배열로 복사해야한다. 64 | -------------------------------------------------------------------------------- /DataStructure_Algorithm/2022-04-01-ArrayList.md: -------------------------------------------------------------------------------- 1 | # Array List 2 | 3 | ## Java에서의 Array List란? 4 | 5 | Java에서 Array List는 List 인터페이스의 구현 클래스이다. 6 | 7 | 8 | 9 | ### Java의 ArrayList 특징 10 | 11 | - **객체가 인덱스로 관리된다.** 12 | - 배열과 달리 저장 용량을 초과한 객체들이 들어오면 자동적으로 저장 용량이 늘어난다. 13 | - 배열과 동일하게 삽입, 삭제 시 shift가 발생한다. 14 | - 배열과 동일하게 인덱스를 통해 random access가 가능하다. 15 | 16 | ### Java에서의 ArrayList 사용 방법 17 | 18 | ```java 19 | //1.선언 방법 20 | List list = new ArrayList(); 21 | List list = new ArrayList(저장용량); 22 | 23 | //2.삽입 24 | list.add(Object); //마지막에 데이터 추가 25 | list.add(index,Object); 26 | 27 | //3.값 변경 28 | list.set(index,Object); 29 | 30 | //4.삭제 31 | list.remove(Object); 32 | list.remove(index); 33 | list.clear(); 34 | ``` 35 | -------------------------------------------------------------------------------- /DataStructure_Algorithm/2022-04-01-LinkedList.md: -------------------------------------------------------------------------------- 1 | # Linked List 2 | 3 | ## Linked List란? 4 | 5 | Array의 삭제, 삽입의 시간 복잡도 한계를 해결하기 위한 선형 자료구조이다. 6 | 7 | 노드들의 연결로 이루어져 있으며, 각 노드는 데이터 필드와 다음 노드에 대한 참조를 포함하고 있다. 8 | 9 | 따라서 **논리적 저장순서와 물리적 저장 순서가 일치하지 않는다.** 10 | 11 | 12 | ## Linked List 종류 13 | 14 | 1. Singly Linked List (단일 연결 리스트) 15 | - 단일 연결 리스트는 위에서 설명한 가장 기본적인 연결 리스트이다. 16 | - 각 노드들은 데이터 값과 다음 노드에 대한 참조만을 가지고 있다. 17 | 18 | 19 | 2. Doubly Linked List (이중 연결 리스트) 20 | - 이중 연결 리스트는 단일 연결 리스트와 노드들이 가지고 있는 데이터가 다르다. 21 | - 각 노드들은 데이터 값과 이전 노드에 대한 참조, 다음 노드에 대한 참조를 가지고 있다. 22 | - 따라서, 단일 연결 리스트는 다음 노드에만 접근할 수 있지만, 이중 연결 리스트는 이전 노드와 다음 노드 모두에 접근할 수 있다. 23 | 24 | 25 | 26 | 27 | ## Linked List 특징 28 | 29 | - 동적 크기 30 | - Linked List는 배열과 다르게 길이가 정해져 있지 않다. 31 | - Random Access 불가능 32 | - Linked List는 배열과 다르게 random access가 불가능하다. 33 | - 따라서 탐색을 위해서는 첫 번째 노드부터 순차적으로 원소에 접근해야 한다. 34 | - **이중 연결 리스트**의 경우에는 첫 번째 노드 또는 끝 노드 부터 순차적으로 접근하기 때문에, 탐색해야 하는 엘리먼트가 반으로 줄어든다. 35 | - 탐색시 시간복잡도 : O(n) 36 | - 삽입, 삭제 용이 37 | - Linked List는 배열과 다르게 삽입,삭제시 shift가 필요 없다. 38 | - 원하는 위치 앞의 노드의 다음 노드 참조 값만 바꿔주면 된다. 39 | - 하지만 **단일 연결 리스트**의 경우, 삭제 또는 삽입할 위치 직전의 노드를 찾기 위해서는 탐색을 해야 하기 때문에, O(n)이다. 40 | - **이중 연결 리스트**의 경우, 삭제 또는 삽입할 위치의 노드의 참조를 현재 알고 있다면, O(1)이다. 41 | 42 | 43 | ## Java에서의 Linked List 44 | 45 | Java에서 Linked List는 List 구현 클래스로 제공된다. 46 | 47 | 이는 이중 연결 리스트로, 이전 노드와 다음 노드를 모두 참조할 수 있다. 48 | 49 | ### Linked List의 선언 및 사용 50 | 51 | ```java 52 | List list = new LinkedList(); 53 | 54 | //삽입 55 | list.add(Something); 56 | list.addFirst(Something); 57 | list.addLast(Something); 58 | list.add(index,Something); 59 | 60 | //삭제 61 | list.removeFirst(); 62 | list.removeLast(); 63 | list.remove(); 64 | list.remove(index); 65 | list.clear(); 모든 값 제거 66 | ``` 67 | -------------------------------------------------------------------------------- /DataStructure_Algorithm/2022-04-08-BinarySearchTree.md: -------------------------------------------------------------------------------- 1 | # 이진탐색트리(Binary Search Tree) 2 | 3 | ## 이진 트리 (Binary Tree) 4 | 5 | - 각 노드의 자식 노드가 최대 2개인 트리 6 | 7 | ## 이진 탐색 (Binary Search) 8 | 9 | - 배열 자료구조를 사용한다. 10 | - 배열은 조회에 강점이 있는 자료구조, 검색만 한다고 가정할 때는 트리구조가 필요없다. 11 | 12 | ## 이진탐색트리 (Binary Search Tree) 13 | 14 | **이진 탐색 + 트리 (연결리스트)** 15 | 16 | - 이진탐색 : 탐색에 소요되는 시간복잡도 O(logN) 17 | - 트리 (연결리스ㅛ트) : 삽입, 삭제의 시간복잡도는 O(1) 18 | - 두가지를 합하여 장점을 모두 얻는 것이 “이진탐색트리” 19 | - 효율적인 탐색 능력을 가지고, 자료의 삽입 삭제도 가능하다. 20 | 21 | ## 이진탐색트리 조건 22 | 23 | - 각 노드에 중복되지 않는 키(Key)가 있다. 24 | - 루트노드의 왼쪽 서브 트리는 해당 노드의 키보다 작은 키를 갖는 노드들로 이루어져 있다. 25 | - 루트노드의 오른쪽 서브 트리는 해당 노드의 키보다 큰 키를 갖는 노드들로 이루어져 있다. 26 | - 좌우 서브 트리도 모두 이진 탐색 트리여야 한다. 27 | 28 | ![이진탐색트리](https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbCe3QD%2Fbtq2ytHuN1Z%2FAi82KHYBlgY01j9hbwjOO1%2Fimg.png) 29 | 30 | ## 이진 탐색 트리 특징 31 | 32 | 1. BST의 Inorder Traveral을 수행하여 모든 키를 **정렬된 순서**로 가져올 수 있다. 33 | 34 | ⇒ 트리의 inorder traversal 결과 : 7, 11, 15, 50, 54, 62, 80 35 | 36 | > 중위순회(inorder) 방식 (왼쪽 - 루트 - 오른쪽) 37 | 38 | 39 | ![이진탐색트리](https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcg5ezX%2Fbtq2y4AZEqe%2FBIKAzOf74qQmD4vqEN6lP1%2Fimg.png) 40 | 41 | 1. BST의 검색에 대한 시간복잡도는 **균형 상태**이면 **O(logN)**의 시간이 걸리고 **불균형 상태**라면 **최대 O(N)** 시간이 걸린다. 42 | - 삽입, 검색, 삭제 시간복잡도는 모두 트리의 Depth에 비례한다. 43 | 44 | ![이진탐색트리](https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb5AX6Z%2Fbtq2BDbA4Sw%2FCDSV3lITsUrDIiss7ODMLk%2Fimg.png) 45 | 46 | > 편향된 트리는 시간복잡도가 O(N)이므로 트리를 사용할 이유가 사라진다. 47 | → 이를 바로 잡도록 도와주는 개선된 트리가 AVL Tree이다. 48 | > 49 | 50 | ## 이진탐색트리 연산 51 | 52 | ### 생성 53 | 54 | > 50, 15, 62, 70, 7, 54, 11 이진탐색트리 생성 55 | > 56 | 1. 50을 트리의 루트로 트리에 삽입한다. 57 | 2. 다음 요소를 읽고 루트 노드 요소보다 작으면 왼쪽 하위 트리의 루트로 삽입한다. 58 | 3. 그렇지 않으면 오른쪽 하위 트리 오른쪽 루트로 삽입한다. 59 | 60 | ![이진탐색트리](https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcexmJD%2Fbtq2z1DLANG%2FZFiFmM5657r46N4hKKzv91%2Fimg.png) 61 | 62 | ### 탐색 (Search) 63 | 64 | 1. **루트 노드의 키와 찾고자 하는 값을 비교**한다. 찾고자 하는 값이라면 탐색을 종료한다. 65 | 2. 찾고자 하는 값이 루트 노드의 키보다 작다면 왼쪽 서브 트리로 탐색을 진행한다. 66 | 3. 찾고자 하는 값이 루트노드의 키보다 크다면 오른쪽 서브트리로 탐색을 진행한다. 67 | 4. 위 과정을 찾고자 하는 값을 찾을 때까지 반복해서 진행한다. 검색 값이 없으면 null을 반환 68 | 69 | > key = 60 탐색 70 | > 71 | 72 | ![이진탐색트리](https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbDH5Xq%2Fbtq2D4F3nRp%2FUFt8cFNCzqfeytVgtvVLuk%2Fimg.png) 73 | 74 | ### 삽입 (Insert) 75 | 76 | 1. Root에서 시작 77 | 2. 삽입 값을 루트와 비교한다. 루트보다 작으면 왼쪽으로 재귀하고 크다면 오른쪽으로 재귀한다. 78 | 3. 리프 노드에 도달한 후 노드보다 크다면 오른쪽에 작다면 왼쪽에 삽입한다. 79 | 80 | > key = 10 삽입 81 | > 82 | 83 | ![이진탐색트리](https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmiB91%2Fbtq2DsUG16h%2FZBlqV9bktKWCSDfIfQYxT1%2Fimg.png) 84 | 85 | ### 삭제 (Delete) 86 | 87 | - 이진 검색 트리에서 노드를 삭제하는 세 가지 상황이 있다. 88 | 89 | ### 1. 삭제할 노드가 리프노드인 경우 90 | 91 | - 노드를 삭제하기만 하면 된다. 92 | 93 | > key = 1 삭제 94 | > 95 | 96 | ![이진탐색트리](https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FeudyFG%2Fbtq2GXflqdC%2FTvIXkjTgEWoVoyvOv4xQN1%2Fimg.png) 97 | 98 | ### 2. 삭제할 노드에 자식이 하나만 있는 경우 99 | 100 | - 노드를 삭제하고 자식 노드를 삭제된 노드의 부모에 직접 연결한다. 101 | 102 | > key = 30 삭제 103 | > 104 | 105 | ![이진탐색트리](https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd9YABr%2Fbtq2y4HJBqp%2FDbafbadT1SL5WSnKO6AFLK%2Fimg.png) 106 | 107 | ### 3. 삭제할 노드에 자식이 둘 있는 경우 108 | 109 | - 자식이 둘 있는 경우 successor 노드를 찾는 과정이 추가됩니다. 110 | 111 | > 참고 : 112 | > successor 노드란? 113 | > 1. right subtree에 최소값 114 | > 2. inorder 순회에서 다음 노드 115 | 116 | 117 | 1. 삭제할 노드를 찾는다. 118 | 2. 삭제할 노드의 successor 노드를 찾는다. 119 | 3. 삭제할 노드와 successor 노드의 값을 바꾼다. 120 | 4. successor 노드를 삭제 121 | 122 | > 이진탐색트리 key = 50 삭제 123 | 124 | 125 | ![이진탐색트리](https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkYDgz%2Fbtq2BCDKWPR%2FT5wAjm1PwyAAKq9NNYctV0%2Fimg.png) 126 | 127 | ## 이진 탐색 트리 시간복잡도 128 | 129 | ### 검색/삽입 시간복잡도 130 | 131 | - 모든 원소를 탐색하지 않는다. 132 | - 최악의 경우 트리의 높이 만큼 탐색한다. 133 | - 높이가 H인 경우 검색/삽입의 시간 복잡도는 O(H) 134 | - 원소의 개수로 표기 135 | - 원소의 개수가 N 이면 O(logN) (이진검색트리 구조가 균형 이진 트리인 경우) 136 | 137 | ### 삭제 시간 복잡도 138 | 139 | 삭제할 노드에 자식이 둘 있는 경우 140 | 141 | - 삭제 노드 탐색 O(H) 142 | - 대체 노드를 찾기 위한 서브 트리를 탐색 O(H) 143 | - 참조값 변경 O(1) 144 | 145 | 삭제 연산의 시간 복잡도는 O(H + H + 1) → O(2H) → O(H) , O(logN) 146 | 147 | ## 질문 148 | 149 | ### 1. BST와 Binary Tree에 대해서 설명하세요. 150 | 151 | 이진탐색트리(Binary Search Tree)는 **이진 탐색과 연결 리스트**를 결합한 자료구조이다. 152 | 153 | 이진 탐색의 **효율적인 탐색 능력을 유지**하면서, 빈번한 **자료 입력과 삭제**가 가능하다는 장점이 있다. 154 | 155 | 이진 탐색 트리는 왼쪽 트리의 모든 값이 반드시 부모 노드보다 작아야 하고, 반대로 오른쪽 트리의 모든 값이 부모 노드보다 커야 하는 **특징**을 가지고 있어야 한다. 156 | 157 | 이진 탐색 트리의 **탐색, 삽입, 삭제의 시간복잡도는 O(H)**이다. 트리의 높이에 영향을 받는데, 트리가 균형이 맞지 않으면 워스트 케이스가 나올 수 있다. (그래서 이 균형을 맞춘 구조가 AVL Tree이다) 158 | 159 | ### 2. 힙과 이진 탐색 트리의 공통점과 차이점 160 | 161 | - 공통점 : 힙과 이진 탐색 트리는 모두 이진 트리이다. 162 | - 차이점 163 | - 힙은 각 노드의 값이 자식 노드보다 크거나 같다. (최대 힙의 경우) 164 | - 이진 탐색 트리는 왼쪽 자식 노드의 값이 가장 작고, 그 다음 부모 노드, 그 다음 오른쪽 자식 노드 값이 가장 크다. 165 | - 이진 탐색 트리는 탐색을 위한 구조, 힙은 최대/최소값 검색을 위한 구조로 이해하면 된다. 166 | 167 | ![이진탐색트리](https://media.vlpt.us/images/nagosooo/post/0958aa5e-780e-4ec9-bcee-55ef1994acb9/%EC%8A%A4%ED%81%AC%EB%A6%B0%EC%83%B7%202021-10-27%20%EC%98%A4%ED%9B%84%202.27.28.png) 168 | 169 | ## 참고 170 | 171 | [https://yoongrammer.tistory.com/71](https://yoongrammer.tistory.com/71) 172 | 173 | [https://mommoo.tistory.com/101](https://mommoo.tistory.com/101) -------------------------------------------------------------------------------- /DataStructure_Algorithm/2022-04-15-Heap.md: -------------------------------------------------------------------------------- 1 | # Heap(힙) 2 | 3 | ## Heap이란? 4 | 힙은 **최댓값** 및 **최솟값**을 찾아내는 연산을 **빠르게** 하기 위해 고안된 **완전이진트리**를 기본으로 한 자료구조로서 다음과 같은 힙 속성을 만족합니다. (완전이진트리는 마지막 리프 노드를 제외한 모든 노드에서 자식들이 완전히 채워진 트리를 말합니다.) 5 | * A가 B의 부모노드(parent node)이면, A의 키(key) 값과 B의 키값 사이에는 대소 관계가 성립한다. 6 | * 키값 대소관계는 오로지 **부모와 자식 간에만 성립**되며 **형제사이에는 대소 관계가 성립되지 않음**. 7 | 8 | **최소/최댓값의 확인 및 삭제가 필요할 때** Heap을 사용하면 수행 속도가 빠르고 좋습니다. 9 | 10 | ## Heap의 종류 11 | ![types-of-heap.png](images/types-of-heap.png) 12 | 13 | ### 1. 최대 힙(Max Heap) 14 | 15 | * 부모노드의 키 값이 자식노드의 키값보다 항상 큰 힙 16 | 17 | * Key(부모노드) >= Key(자식노드) 18 | 19 | * 가장 큰 값이 루트노드에 있음 20 | 21 | ### 2. 최소 힙(Min Heap) 22 | 23 | * 부모노드의 키 값이 자식노드의 키값보다 항상 작은 힙 24 | 25 | * Key(부모노드) <= Key(자식노드) 26 | 27 | * 가장 작은 값이 루트노드에 있음 28 | 29 | 30 | ## 힙의 구현 31 | 힙은 일반적으로 **배열**로 표현합니다. 물론 연결리스트로도 구현이 가능하지만, 문제는 특정 노드의 '검색', '이동'과정이 조금 더 번거롭기 때문입니다. 32 | 33 | 구현을 쉽게 하기 위해 배열 인덱스 1부터 사용하는데요, 고유 번호(인덱스)를 통해 부모/자식노드를 구할때 아래와 같은 규칙이 있습니다. 34 | 35 | ### 힙에서의 부모 노드와 자식 노드의 관계 36 | * 왼쪽 자식의 인덱스 = (부모노드의 인덱스) * 2 37 | * 오른쪽 자식의 인덱스 = (부모노드의 인덱스) * 2 + 1 38 | * 부모의 인덱스 = (자식노드의 인덱스) / 2 39 | ![types-of-heap.png](images/heap_index.png) 40 | 41 | 42 | ## 삽입, 삭제로 깨진 힙을 재구조화(heapify) 43 | 힙에서 삽입, 삭제가 일어나게 되면 경우에 따라 최대 힙, 최소 엉덩이의 조건이 깨질 수 있습니다. 44 | 45 | 이러한 경우 해당 조건을 만족할 수 있게 노드들의 위치를 바꿔가며 힙을 재구조화(heapify)하는 과정이 필요합니다. 46 | 47 | 보통 힙에서 삽입과 삭제의 경우 연산 자체는 `O(1)`로 동작하지만, 재구조화(heapify)의 과정을 거치기 때문에 `O(logn)`의 시간복잡도를 가지게 됩니다. 48 | 49 | Max heap에서 heapify의 작업은 다음과 같습니다. 50 | 51 | 1. 요소 값과 자식 노드 값을 비교합니다. 52 | 2. 만약 자식 노드 값이 크다면 왼쪽 오른쪽 자식 중 가장 큰 값으로 교환합니다. 53 | 3. 힙 속성이 유지될 때까지 1,2번 과정을 반복합니다. 54 | 55 | 다음 그림은 값이 8인 노드에 대해 최대 힙 heapify를 수행하는 예입니다. 56 | ![heap-heapify.png](images/heap-heapify.png) 57 | 58 | Step 1. 첫 번째 노드 값(8)이 자식보다 작으므로 자식 중 가장 큰 오른쪽 자식 값(20)과 교환합니다. 59 | 60 | Step 2. 값이 8인 노드에서 heapify를 다시 시작합니다. 8이 왼쪽 자식 노드 13보다 작기 때문에 교환합니다. 61 | 62 | 이제 8이 leaf node이므로 heapify를 추가로 호출해도 힙 구조에 영향을 주지 않습니다. 63 | 64 | ## 힙(heap)의 삽입 65 | 66 | 힙의 삽입과정은 다음과 같습니다. 67 | 68 | 1. 힙의 마지막 노드에 새로운 노드를 삽입한다. `시간복잡도 O(1)` 69 | 2. 이후 부모 노드와 비교하면서 재구조화(heapify) 과정을 수행합니다. `시간복잡도 O(log N)` 70 | 71 | 즉, 삽입과정은 아래에서 위로 재구조화 과정이 이루어지게 되는것 입니다. 힙에서의 삽입 과정의 시간복잡도는 `O(log N)`이 됩니다. 72 | 73 | 아래의 예시는 최대 힙에 값 11을 갖는 노드를 삽입하고 재구조화하는 과정입니다. 74 | ![heap-insert2.png](images/heap-insert2.png) 75 | 76 | ## 힙(heap)의 삭제 77 | 78 | 힙의 삭제 과정은 다음과 같습니다. 79 | 80 | 1. 루트노드를 삭제합니다. `시간복잡도 O(1)` 81 | 2. 가장 마지막 말단 노드를 루트노드 자리에 대체합니다. 82 | 3. 이후 재구조화 과정을 수행합니다. `시간복잡도 O(log N)` 83 | 84 | 즉, 삭제 과정은 위에서 아래로 재구조화 과정이 이루어지게 됩니다. 힙에서의 삭제 과정의 시간복잡도는 `O(log N)`이 됩니다. 85 | 86 | 아래의 예시는 최대 힙에서 루트노드를 삭제한 후 재구조화하는 과정을 나타냅니다. 87 | ![heap-remove.png](images/heap-remove.png) 88 | 89 | ## 힙(heap)의 조회 90 | 91 | 최대 힙에서 최대 값인 루트 노트의 값을 조회할 경우 시간복잡도는 `O(1)`, 92 | 최소 힙에서 최소 값인 루트 노트의 값을 조회할 경우 시간복잡도는 `O(1)` 입니다. 93 | 94 | ## heap과 Priority Queue(우선순위 큐) 95 | 우선순위 큐는 가장 우선순위가 높은 데이터를 먼저 꺼내기 위해 고안된 자료구조입니다. 96 | 97 | 우선순위 큐는 보통 heap과 같이 거론되곤 하는데요. 이는 우선순위 큐가 주로 힙 자료구조를 사용해 구현되기 때문입니다. (배열, 연결리스트로 구현할 수 도 있지만 시간복잡도 측면에서 힙이 더 낫기 때문) 98 | 99 | ## heap과 BST의 차이점 100 | ### heap 101 | * Heap에서는 상위 level에 존재하는 값이 하위 level에 존재하는 값보다 우선순위가 높다. 102 | * 하지만 좌/우에서의 우선순위는 절대적이지 않다. 103 | * 왼쪽의 값이 우선순위가 높을 수도, 오른쪽의 값이 우선순위가 높을 수도 있다. 104 | * Heap에서는 root가 가장 우선순위가 높기 때문에 가장 작은 값을 추출하거나 가장 큰 값을 추출해야 하는 경우 사용한다. 105 | 106 | ### BST(Binary Search Tree) 107 | * BST에서는 왼쪽의 값이 오른쪽의 값보다 작다. 108 | * 하지만 상/하에서의 값은 절대적이지 않다. 109 | * 상위 level에 존재하는 값이 하위 level에 존재하는 값보다 클 수도, 작을 수도 있다. 110 | * BST는 (평균적으로) 탐색이 O(log n), 삽입/삭제가 O(log n)에 가능하기 때문에 탐색이 빈번하게 일어나는 경우 사용한다. 111 | 112 | 113 | ## 예상 질문 114 | 115 | * Heap은 기본적으로 어떤 자료구조를 사용하나요? 116 | 117 | * Heap의 삭제, 삽입의 원리와 시간복잡도는? 118 | 119 | * 우선순위 큐(Priority Queue)의 동작 원리가 어떻게 되나요? 120 | 121 | * Heap과 BST의 차이점이 무엇인가요? -------------------------------------------------------------------------------- /DataStructure_Algorithm/2022-04-22-hash.md: -------------------------------------------------------------------------------- 1 | # 해시(Hash) 2 | 3 | # 해시란? 4 | 5 | - 데이터를 효율적으로 관리하기 위해 임의의 길이 데이터를 고정된 길이 데이터로 매핑하는 것 6 | - 특정 해시 함수를 구현하여 데이터 값을 해시 값으로 매핑 7 | 8 | # 해시 함수 9 | 10 | - 정의 : 키를 고정된 길이의 해시로 변경해주는 함수 11 | - key → 입력값, hash → 출력값(저장 위치) 12 | 13 | ![hash](images/hash.png) 14 | 15 | 16 | # 장점 17 | 18 | - Key-Value가 1:1로 매핑되어 있기 때문에, 삽입, 삭제, 검색 연산이 모두 평균적으로 O(1) 시간 복잡도를 갖는다 19 | 20 | # 단점 21 | 22 | - 해시 충돌이 발생할 수 있다. 23 | - 순서나 관계가 있는 배열에는 어울리지 않는다 24 | - 공간 효율성이 떨어진다 → 데이터 저장 이전에 미리 저장공간이 필요하기 때문에, 공간을 만들었지만 채워지지 않는 경우가 발생할 수 있다 25 | - hash function의 의존도가 높다. 26 | 27 | # 해시함수 선택 28 | 29 | - `Trade-Off` : 상충 관계. 한 측면에서 이득을 얻으면 다른 부분에서 손해를 볼 수밖에 없음 30 | - 해시 함수는 무조건 복잡하다고 좋은 것이 아닌, 트레이드오프 관계에 있다. 31 | 32 | ## Value의 범위가 넓은 해시함수 33 | 34 | - 장점 35 | - 해시 충돌이 발생할 가능성이 줄어든다 36 | - 단점 37 | - value의 크기가 커지기 때문에 데이터 크기 면에서 공간 효율성이 떨어진다 38 | - value의 범위가 커지기 때문에 사전 공간의 공간 효율성이 떨어진다 39 | 40 | # 해시 충돌 41 | 42 | - 서로 다른 두 가지 Key를 해시 함수를 통해 얻은 해시 값이 동일한 현상 43 | - 해시 함수의 편향성 문제일 수도 있고, 해시 공간 부족 문제일 수도 있음 44 | - 해시 공간은 결국 유한하기 때문에, 해시 충돌은 필연적 45 | 46 | ## 해시 충돌 회피 방법 47 | 48 | 1. Chaining 49 | - 충돌 발생 시 동일한 버킷 내에 연결리스트 형식으로 저장하는 방법 50 | - 삽입의 경우 연결리스트에 추가하면 되므로 O(1), 탐색/삭제의 경우 최악의 경우 O(k) 가 걸림 51 | 52 | ![hash-chaining](images/hash-chaining.png) 53 | 54 | 1. Open Addressing 55 | - 해시함수로 얻은 해시 값에 따라 데이터와 키값을 저장하지만, 동일한 주소에 다른 데이터가 있을 경우 다른 주소도 활용할 수 있게 하는 기법 56 | - 삽입 시 계산한 해시 값에 대한 인덱스가 이미 차 있는 경우 다음 인덱스로 이동한다 57 | 58 | ![hash-openaddressing](images/hash-openaddressing.png) 59 | 60 | - 충돌 처리 기법 61 | - 선형 탐사 62 | - 고정 폭만큼 인접한 공간에 데이터를 삽입(K+n) 63 | - 데이터 밀집 현상이 일어날 수 있음 64 | - 제곱 탐사 65 | - 정해진 고정 폭을 제곱수로 변경하여 해시값의 중복을 피함(K + n^2) 66 | - 이중 해싱 67 | - 처음 해시함수로는 해시 값을 찾고, 두번째 해시함수로 탐사폭을 계산한다 68 | 69 | # 자바에서의 해시 70 | 71 | ## hashCode 72 | 73 | - 특정 해시 함수 알고리즘에 의해 생성된 정수 값 74 | - equals와 엮어서 자주 사용 75 | - 해시코드 규약이 존재 76 | - equals 비교에 사용되는 정보가 변경되지 않았다면, 애플리케이션이 실행되는 동안 그 객체의 hashCode 메소드는 몇 번을 호출해도 일관되게 항상 같은 값을 반환해야 한다.(단, 애플리케이션을 다시 실행한다면 이 값이 달라져도 상관없다.) 77 | - equals(Object)가 두 객체를 같다고 판단했다면, 두 객체의 hashCode는 똑같은 값을 반환해야 한다. 78 | - equals(Object)가 두 객체를 다르다고 판단했더라도, 두 객체의 hashCode가 서로 다른 값을 반환할 필요는 없다. 단, 다른 객체에 대해서는 다른 값을 반환해야 해시테이블의 성능이 좋아진다. 79 | 80 | ## 해시코드를 사용하는 자료 구조 81 | 82 | - Hash 자료 구조 83 | - HashSet 84 | - HashMap 85 | - HashTable 86 | - 해당 자료 구조를 활용할 때는, equals()메소드만 재정의하는 것이 아니라 hashCode() 메소드도 재정의하여 논리적 동등 객체일 경우 동일한 해시코드가 리턴되도록 해야 한다 -------------------------------------------------------------------------------- /DataStructure_Algorithm/2022-04-29-B-Tree, B+Tree.md: -------------------------------------------------------------------------------- 1 | ### Q . 주요 point 2 | 3 | - DB의 Index 구현체로 자주 사용되는 자료구조 4 | 5 | - B-Tree와 B+Tree의 차이점 6 | 7 |
8 | 9 | 10 | ## B-Tree(Balanced Tree) 11 | 12 | 13 | - 리프 노드들이 같은 레벨을 가질 수 있도록 편향되지 않는 트리(균형 이진 트리의 확장) 14 | 15 | - 이진 트리와 달리 2개 이상의 자식을 가질 수 있음(하나의 노드에 3개의 자식) 16 | 17 | - 하나의 노드에 여러 정보(key)를 담을 수 있음 18 | 19 | - 차수 : 하나의 노드가 가질 수 있는 자식 노드의 수 (차수가 N -> N차 B-Tree) 20 | 21 | ![image](https://user-images.githubusercontent.com/72663337/165939933-52b5754c-a46f-43b5-9eb2-b1a484010491.png) 22 | 23 | 24 | 출처 (https://velog.io/@emplam27/%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0-%EA%B7%B8%EB%A6%BC%EC%9C%BC%EB%A1%9C-%EC%95%8C%EC%95%84%EB%B3%B4%EB%8A%94-B-Tree) 25 | 26 | 27 | 28 | -> 하나의 블럭에 여러 자료(key)를 담기 때문에 더 많은 데이터를 저장소에 효율적으로 저장할 수 있음 29 | 30 |
31 | 32 | 33 | 하드디스크와 같은 외부 저장장치는 블럭 단위로 파일을 입출력하고, 이 때 입출력의 비용은 블럭 안의 파일 크기와는 상관 없이 블럭 단위로 정해진다. 34 | 35 | -> 하나의 블럭에 1byte파일/1000byte파일 저장되어 있든 둘의 비용은 차이가 없음 36 | 37 | => 하나의 블럭에 여러 데이터들을 동시 저장할 수 있다면 보다 효율적으로 사용이 가능함. 38 | 39 | 40 | 41 |
42 | 43 | ### 특징 44 | 45 | - 각 노드의 자료(key)들은 정렬되어 있음(중위) 46 | 47 | - key들은 중복되지 않음 48 | 49 | - 모든 리프 노드들은 같은 레벨(균형 트리) 50 | 51 | - N차 트리에서, leaf 노드가 아닌 노드들은 적어도 N/2개의 자식 노드를 가짐 52 | 53 |
54 | 55 | 56 | 57 | 58 | 59 | 60 | ### key 삽입 61 | 62 | if) 3차 B-Tree 63 | 64 | - 한 노드에 삽입될 수 있는 key의 수 최대 2개 65 | 66 | - 자식 노드 최대 3개 67 | 68 | 69 | 70 | 1. 삽입에 적절한 리프 노드를 검색하고, 2. 필요한 경우(최대 key의 수 초과) 리프 노드를 분할 71 | 72 |
73 | 74 | 75 | 76 | ***1) 분할이 일어나지 않을 때(리프 노드가 차지 않을 때)*** 77 | 78 | 79 | ![image](https://user-images.githubusercontent.com/72663337/165940237-abddb803-0614-4a0f-b9c1-5154275d5a77.png) 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 7 삽입 88 | ![image](https://user-images.githubusercontent.com/72663337/165940265-251ecadd-5346-47d3-8c84-7892e26c21be.png) 89 | 90 | 91 | 92 | 93 | `루프에서부터 삽입될 위치 탐색` 94 |
95 | 96 | 97 | ***2) 분할이 일어날 때*** 98 | 99 | 100 | 101 | 102 | 103 | 6 삽입 104 | ![image](https://user-images.githubusercontent.com/72663337/165940525-5f58bbbd-b0cb-4d2e-ad1d-cd0d7aef46fc.png) 105 | 106 | 107 | `한 노드가 가질 수 있는 최대 key의 개수를 초과` 108 | 109 | 110 | 111 | 112 | 노드의 분할 과정 이루어 짐 113 | 114 | ![image](https://user-images.githubusercontent.com/72663337/165940567-be68a78f-025e-40f5-99c8-aaa6ba866426.png) 115 | 116 | `중앙값(7)은 부모 노드로 병합` 117 | 6,7,8 key값을 갖고 있던 노드가 분할되고, 118 | 119 | 7 노드가 부모 노드로 삽입되어 6은 왼쪽 자식 노드, 8은 오른쪽 자식 노드로 설정됨 120 | 121 | 122 | 123 | 124 | 125 |
126 | 127 | 128 | 129 | 130 | 131 | ### key 삭제 132 | 133 | 134 | ***1) 삭제할 key가 leaf 인 경우*** 135 | 136 | 1-1) 트리 균형 조정이 필요하지 않은 경우 137 | 138 | key가 삭제된 후 노드의 key개수가 최소 key개수보다 클 때 139 | 140 | 141 | 142 | 12 삭제 143 | ![image](https://user-images.githubusercontent.com/72663337/165940753-93f79809-16a2-41f2-846b-94f9bdef04e6.png) 144 | 145 | 146 | 147 | 148 |
149 | 150 | 151 | 152 | 1-2) 균형 조정이 필요한 경우 153 | 154 | 삭제 후 노드의 key개수가 최소 개수에 도달하지 못할 때 155 | 156 | 157 | 158 | 1. 삭제되는 key의 자리와 부모key의 자리를 바꿈 159 | 160 | 2. 삭제 후 기존의 (왼쪽 형제 노드에서 가장 큰/오른쪽 형제 노드에서 가장 작은) 값으로 부모 key 위치를 대체함 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 13 삭제 169 | 170 | ![image](https://user-images.githubusercontent.com/72663337/165940791-7dd2497e-1b62-421b-89ab-8e37b1ac4d23.png) 171 | 172 | 173 | `13과 그의 부모key인 14가 교체되고(1)` 174 | 175 | 176 | ![image](https://user-images.githubusercontent.com/72663337/165940806-0ce2b06a-0437-46a5-b729-1cb9d31e3e9d.png) 177 | 178 | `기존 위치의 오른 형제 노드에서 가장 작은 값인 17이 부모key를 대체` 179 | 180 | 181 | 182 |
183 | 184 | 185 | 186 | 187 | 188 | ***2) 삭제할 key가 leaf노드가 아닌 경우*** 189 | 190 | 191 | inorder predecessor : 노드의 왼쪽 자손에서 가장 큰 key 192 | 193 | inorder successor : 노드의 오른쪽 자손에서 가장 작은 key 194 | 195 | 196 | 197 | 1. 현재 노드의 inorder predecessor/inorder successor (leaf node)와 삭제할 key의 자리를 바꿈 198 | 199 | 2. 삭제 후, 리프 노드의 삭제에서처럼 트리의 균형 조정 실행됨 200 | 201 | 202 | ![image](https://user-images.githubusercontent.com/72663337/165940867-aede67ef-e770-42fd-87ec-7b5264291de8.png) 203 | 204 | 205 | 206 | 11 삭제 207 | 208 | 209 | 210 | 211 | 212 | inorder predecessor(노드의 왼쪽 자손(트리)에서 가장 큰 key) 213 | 214 | ![image](https://user-images.githubusercontent.com/72663337/165940892-66c726c0-8ffa-426e-88ea-af56e45709ed.png) 215 | 216 | 217 | `위치 변환(1)` 218 | 219 | 220 | ![image](https://user-images.githubusercontent.com/72663337/165940948-f4ea55f8-fdc9-4323-9555-d9c1321ca6ca.png) 221 | 222 | `트리 균형 조정(2)` 223 | 224 | 225 |
226 | 227 | 228 | 229 | ## B+Tree 230 | 231 | ![image](https://user-images.githubusercontent.com/72663337/165941023-6944e6b7-7b96-4491-b629-e0936b96a914.png) 232 | 233 | 234 | 출처 (https://rebro.kr/167) 235 | 236 | 237 | **B-Tree와의 차이점** 238 | 239 | - 노드에 대한 **탐색 연산(검색 연산)** 을 개선한 트리 240 | 241 | - 같은 레벨의 모든 키 값들이 정렬되어 있고, **연결리스트 형태** 로 이어져 있음 -> 효율적인 순차 탐색 242 | 243 | - leaf node를 **데이터 노드** , leaf node가 아닌 노드를 **인덱스 노드**라고 함. 244 | 245 | - 키 값이 중복될 수 있음(인덱스 노드, 데이터 노드가 따로 존재하므로) 246 | 247 | - leaf node에서만 데이터가 검색되므로, 탐색의 시간복잡도는 항상 O(logN) 248 | 249 | 250 | 251 | - 데이터 노드에만 데이터가 존재하고, 인덱스 노드의 value값에는 다음 노드를 가리키는 포인터 주소가 존재함. 252 | 253 |
254 | 255 | ### Referencce 256 | 257 | 258 | 259 | https://velog.io/@emplam27/%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0-%EA%B7%B8%EB%A6%BC%EC%9C%BC%EB%A1%9C-%EC%95%8C%EC%95%84%EB%B3%B4%EB%8A%94-B-Tree 260 | 261 | 262 | 263 | https://ssocoit.tistory.com/217 264 | 265 | 266 | 267 | https://www.cs.usfca.edu/~galles/visualization/BTree.html 268 | 269 | 270 | 271 | www.cs.usfca.edu 272 | -------------------------------------------------------------------------------- /DataStructure_Algorithm/2022-05-10-Queue,Stack,Stable,Unstable.md: -------------------------------------------------------------------------------- 1 | # < Stack & Queue> 2 | 3 | ## 1. Stack 4 | 5 |
6 | 7 |
8 | 출처 : [https://zoosso.tistory.com/868](https://zoosso.tistory.com/868) 9 |
10 |
11 | 12 |

13 | 14 | Stack은 말 그대로 데이터를 쌓아 올린다는 의미를 가진 자료구조로, 입력과 출력이 한 곳으로 제한되어있다. 15 | 16 | Stack은 LIFO(Last-In-First-Out)에 따라 자료를 배열한다. 따라서 Stack은 배열과 달리 index를 통해 특정 항목에 접근할 수 없다. 하지만 데이터를 추가하거나 삭제할 때, 배열처럼 원소들을 하나씩 옆으로 밀어 줄 필요가 없기 때문에, O(1) 시간에 가능하다. (배열은 O(n)임) 17 | 18 |
19 | 20 | - pop : Stack에서 가장 위에 있는 항목을 제거한다. 21 | - push : 데이터 하나를 Stack의 가장 윗 부분에 추가한다. 22 | - peek : Stack의 가장 위에 있는 항목을 반환한다. 23 | - isEmpty : Stack이 비어 있을 때에 true를 반환한다. 24 | 25 |
26 | 27 | ```java 28 | public class MyStack{ 29 | private static class StackNode { 30 | private T data; 31 | private StackNode next; 32 | public StackNode(T data){ 33 | this.data= data; 34 | } 35 | } 36 | 37 | private StackNode top; 38 | 39 | public T Pop(){ 40 | if(top == null) throw new EmptyStackException(); 41 | T item = top.data; 42 | top = top.next; 43 | return item; 44 | } 45 | 46 | public void push(T item){ 47 | StackNode t = new StackNode(item); 48 | t.next = top; 49 | top = t; 50 | } 51 | 52 | public T peek(){ 53 | if (top == null) throw new EmptyStackException(); 54 | return top.data; 55 | } 56 | 57 | public boolean isEmpty(){ 58 | return top == null; 59 | } 60 | } 61 | ``` 62 | 63 |
64 | 65 | ## 2. Queue 66 | 67 |
68 | 69 |
70 | 출처 : [https://www.fun-coding.org/Chapter05-queue-live.html](https://www.fun-coding.org/Chapter05-queue-live.html) 71 |
72 |
73 | 74 |

75 | 76 | Queue는 Stack과 달리 입력과 출력에 각각의 한 쪽 끝을 제한한다. (한 쪽으로는 입력만, 한 쪽으로는 출력만 가능하다) 77 | 78 | Queue는 FIFO (First-In-First-Out) 순서를 따른다. 즉, 큐에 저장되는 항목들은 큐에 추가되는 순서로 제거된다. 79 | 80 |
81 | 82 | - enQueue() : 큐에 데이터 넣기 83 | - deQueue() : 큐에서 데이터 빼기 84 | - isEmpty() 85 | - isFull() 86 | 87 |
88 | 89 | - front : deQueue 할 위치 90 | - rear : enQueue 할 위치 (구현에 따라 다음 빈 칸을 나타내는 경우도 있고, 마지막 입력된 칸을 나타내는 경우도 있음) 91 | 92 |
93 | 94 | - 연결리스트로 구현한 큐 : front, rear 대신 first, last를 사용함. 연결리스트라 full 개념이 없음 95 | 96 | ```java 97 | public class MyQueue{ 98 | private static class QueueNode{ 99 | private T data; 100 | private QueueNode next; 101 | public QueueNode(T data){ 102 | this.data = data; 103 | } 104 | } 105 | 106 | private QueueNode first; 107 | private QueueNode last; 108 | 109 | public void add(T item){ 110 | QueueNode t = new QueueNode(item); 111 | if (last != null){ 112 | last.next = t; 113 | } 114 | last = t; 115 | 116 | if (first == null){ 117 | first = last; 118 | } 119 | } 120 | 121 | public T remove(){ 122 | if (first == null) throw new NoSuchElementException(); 123 | T data = first.data; 124 | first = first.next; 125 | if (first == null){ 126 | last = null; 127 | } 128 | return data; 129 | } 130 | 131 | public T peek(){ 132 | if (first == null) throw new NoSuchElementException(); 133 | return first.data; 134 | } 135 | 136 | public boolean isEmpty(){ 137 | return first == null; 138 | } 139 | } 140 | ``` 141 | 142 |
143 | 144 | 145 | ## 3. 원형큐 146 | 147 | ### (1) 배열을 사용한 Queue의 단점 148 | 149 | 배열을 사용한 Queue의 경우, 배열의 가장 앞에 있는 데이터를 꺼낸 후, 그 다음 인덱스의 데이터들을 한 칸씩 모두 이동해야 하는 단점이 있다. 150 | 151 | 따라서, 데이터 하나를 꺼낼 때 마다, O(n)만큼의 시간 복잡도를 요구하므로 비효율적이다. 152 | 153 | ### (2) 배열 Queue의 단점을 보완한 원형 큐 154 | 155 | 원형 큐는 다음 그림처럼 front는 첫번째 데이터를 가리키고 rear은 마지막 데이터를 가리키는 형태를 가지고 있다. 이 때문에, 기존의 배열 큐처럼 데이터를 매번 한 칸씩 이동시킬 필요가 없어서 데이터를 빠르게 처리할 수 있다. 156 | 157 | 158 | 159 | 원형 큐에 최초로 데이터를 추가한 후의 모습은 다음과 같다. 160 | 161 | 162 | 163 | 다음과 같은 원형 큐에서 데이터를 삭제해보자. 164 | 165 | 166 | 167 | front에 있는 어피치를 삭제하면 frotn가 그 다음 데이터인 프로도를 가리키게 된다. 그리도 데이터들의 이동은 나타나지 않는다. 168 | 169 | 170 | 171 | 원형 큐에서 데이터가 최대로 저장된 경우는 다음과 같다. 172 | 173 | 174 | 175 | 데이터가 꽉 찬 경우는 위처럼 front와 rear의 인덱스 차이가 한 칸 만큼 날 때이다. 176 | 177 | front와 rear이 같은 경우는 큐가 빈 경우인데, 꽉 찬 경우도 front와 rear이 같도록 만들면 큐가 빈 경우와 구분할 수 없기 때문에 위처럼 구현한다. 178 | 179 | ## 4. Stack 두 개로 Queue 구현하기 180 | 181 | ```java 182 | class MyQueue{ 183 | private Stack realStack = new Stack<>(); 184 | private Stack tempStack = new Stack<>(); 185 | 186 | public T push(T data){ 187 | while(!realStack.isEmpty()) 188 | tempStack.push(realStack.pop()); 189 | 190 | realStack.push(data); 191 | 192 | while(!tempStack.isEmpty()) 193 | realStack.push(tempStack.pop()); 194 | 195 | return data; 196 | } 197 | 198 | public T pop(){ 199 | return realStack.pop(); 200 | } 201 | } 202 | ``` 203 | 204 |
205 | 206 | # 207 | 208 | ## 1. Stable Sort 209 | 210 | Stable Sort란 정렬을 진행할 때, 같은 값의 숫자더라도 그 상대적인 위치가 유지되는 sorting 방식을 말한다. 211 | 212 | 다음과 같은 배열을 정렬할 때, 213 | 214 | | 3 (1) | 3 (2) | 4 | 2 | 1 | 5 | 3 (3) | 215 | | --- | --- | --- | --- | --- | --- | --- | 216 | 217 | 다음과 같이 3의 순서가 입력된 순서와 동일한 경우가 Stable Sort이다. 218 | 219 | | 1 | 2 | 3 (1) | 3 (2) | 3 (3) | 4 | 5 | 220 | | --- | --- | --- | --- | --- | --- | --- | 221 | 222 |
223 | 224 | ### (1) Stable Sort 종류 225 | 226 | - Insertion sort 227 | - Merge sort 228 | - Bubble sort 229 | - Selection sort : 구현 방식에 따라 Stable 할 수 있다. 230 | 231 |
232 | 233 | ## 2. Unstable Sort 234 | 235 | Unstable Sort란 정렬을 진행할 때, Stable Sort와 달리 상대적인 위치가 유지되지 않는 sorting 방식이다. 236 | 237 | 다음과 같은 배열을 정렬할 때, 238 | 239 | | 3 (1) | 3 (2) | 4 | 2 | 1 | 5 | 3 (3) | 240 | | --- | --- | --- | --- | --- | --- | --- | 241 | 242 | 다음과 같이 3의 순서가 입력된 순서와 달라질 가능성이 있는 정렬이 unstable sort 방식이다. 243 | 244 | | 1 | 2 | 3 (2) | 3 (1) | 3 (3) | 4 | 5 | 245 | | --- | --- | --- | --- | --- | --- | --- | 246 | 247 |
248 | 249 | ### (1) Unstable Sort 종류 250 | 251 | - Quick Sort 252 | - Heap Sort 253 | - Selection Sort : 구현 방식에 따라 Unstable 할 수 있다. 254 | -------------------------------------------------------------------------------- /DataStructure_Algorithm/images/hash-chaining.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prgrms-web-devcourse/BE-Team-R-CS-Study/d0535ce8aeb0166acb1ef886b431ecf3d25e5cfa/DataStructure_Algorithm/images/hash-chaining.png -------------------------------------------------------------------------------- /DataStructure_Algorithm/images/hash-openaddressing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prgrms-web-devcourse/BE-Team-R-CS-Study/d0535ce8aeb0166acb1ef886b431ecf3d25e5cfa/DataStructure_Algorithm/images/hash-openaddressing.png -------------------------------------------------------------------------------- /DataStructure_Algorithm/images/hash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prgrms-web-devcourse/BE-Team-R-CS-Study/d0535ce8aeb0166acb1ef886b431ecf3d25e5cfa/DataStructure_Algorithm/images/hash.png -------------------------------------------------------------------------------- /DataStructure_Algorithm/images/heap-heapify.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prgrms-web-devcourse/BE-Team-R-CS-Study/d0535ce8aeb0166acb1ef886b431ecf3d25e5cfa/DataStructure_Algorithm/images/heap-heapify.png -------------------------------------------------------------------------------- /DataStructure_Algorithm/images/heap-insert2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prgrms-web-devcourse/BE-Team-R-CS-Study/d0535ce8aeb0166acb1ef886b431ecf3d25e5cfa/DataStructure_Algorithm/images/heap-insert2.png -------------------------------------------------------------------------------- /DataStructure_Algorithm/images/heap-remove.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prgrms-web-devcourse/BE-Team-R-CS-Study/d0535ce8aeb0166acb1ef886b431ecf3d25e5cfa/DataStructure_Algorithm/images/heap-remove.png -------------------------------------------------------------------------------- /DataStructure_Algorithm/images/heap_index.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prgrms-web-devcourse/BE-Team-R-CS-Study/d0535ce8aeb0166acb1ef886b431ecf3d25e5cfa/DataStructure_Algorithm/images/heap_index.png -------------------------------------------------------------------------------- /DataStructure_Algorithm/images/types-of-heap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prgrms-web-devcourse/BE-Team-R-CS-Study/d0535ce8aeb0166acb1ef886b431ecf3d25e5cfa/DataStructure_Algorithm/images/types-of-heap.png -------------------------------------------------------------------------------- /DataStructure_Algorithm/목차.md: -------------------------------------------------------------------------------- 1 | # 목차 -------------------------------------------------------------------------------- /Database/2022-04-01-SQL과NoSQL.md: -------------------------------------------------------------------------------- 1 | # SQL과 NoSQL 2 | --- 3 | 4 | ## SQL이란 5 | SQL은 구조화된 쿼리 언어(Structured Query Language)의 약자로 데이터베이스 자체가 아니라 특정 유형의 데이터베이스와 상호 작용하는 데 사용하는 쿼리 언어입니다. 6 | 7 | SQL을 사용하면 관계형 데이터베이스 관리 시스템(RDBMS)에서 데이터를 저장, 업데이트, 삭제 및 검색을 할 수 있습니다. 8 | 9 | 이러한 데이터베이스에는 2가지 주요 특징이 있는데, 다음과 같습니다. 10 | 11 | * 데이터는 정해진(엄격한) 데이터 스키마(구조)에 따라 데이터베이스 테이블에 저장된다. 12 | * 데이터는 **관계**를 통해 연결된 여러 테이블에 분산된다. 13 | 14 | 관계형 데이터베이스에서는 엄격한 스키마 구조에 따라 테이블에 저장된다고 했는데 그렇다면 엄격한 스키마 구조라는 게 무엇을 의미하는 것일까요? 15 | 16 | ### 엄격한 스키마 17 | 엄격한 스키마라는 것은 관계형 데이터베이스에서 **스키마를 준수하지 않는 데이터는 저장할 수 없다**는 걸 뜻합니다. 18 | 19 | RDB에 저장된 데이터는 테이블의 레코드로 저장되며 각 테이블에는 명확하게 정의된 구조가 있습니다. 20 | 21 | 예를 들어, 아래와 같이 `Products`라는 테이블에 `id`, `name`, `price`, `description`이라는 필드가 있다고 생각해봅시다. 22 | 23 | 24 | 25 | 만약, 해당 Products(상품) 테이블에 상품에 대한 **재고 수**를 추가로 저장하고 싶다면? 또는 상품 데이터를 하나 추가하려는데, 해당 상품에 대한 가격을 모른다면 어떻게 될까요? (not null 가정) 26 | 27 | 앞서 말했듯 스키마에 맞지 않는 형식의 데이터는 저장할 수 없기 때문에 위와 같은 예시들은 저장이 불가능합니다. 28 | 29 | 30 | ### 관계 31 | SQL 기반의 데이터베이스의 다른 특징은 관계입니다. 이 관계는 테이블 간에 관계를 뜻하는데요, 데이터의 중복을 피하기 위해 여러 개의 테이블에 나누어서 `관계`를 이용합니다. 예를 들어 foreign key를 이용하는 것이죠. 32 | 33 | 34 | 35 | `Orders` 테이블을 보면, `user_id`와 `product_id`를 통해 어떤 사람이 어떤 상품을 주문했는지 알 수 있습니다. 36 | 37 | 이처럼 SQL은 각 테이블의 관계를 통해 테이블에 접근할 수 있고, 중복을 최소화하며 데이터를 다룰 수 있습니다. 38 | 39 | ## NoSQL이란 40 | 41 | NoSQL은 기본적으로 SQL과 반대되는 접근방식을 따르기 때문에 지어진 이름이라고 합니다. 42 | 앞서 설명했던 SQL의 특징을 NoSQL은 갖고 있지 않습니다. 43 | 44 | 즉, NoSQL의 특징은 다음과 같습니다. 45 | 46 | * 스키마 없음 47 | * 관계없음 48 | 49 | ### 스키마 없음 50 | SQL에서는 엄격한 스키마에 의해 정해진 스키마를 따르지 않는다면 데이터를 저장할 수 없었지만, NoSQL에서는 그렇지 않습니다. 다른 구조의 데이터를 같은 컬렉션(=SQL에서의 테이블)에 추가할 수 있습니다. 즉, 데이터 필드 추가에 있어서 자유롭다는 점입니다. 51 | 52 | NoSQL 세상에서는 레코드(record)를 문서(documents)라고 부르기도 합니다. 문서라는 용어가 생소할 수 있지만 쉽게 말해서 JSON과 비슷한 형태로 데이터를 가지고 있다는 게 특징입니다. 이러한 Document Database는 NoSQL 데이터베이스의 특성 중 하나입니다. 53 | 54 | 참고로 NoSQL 데이터베이스 별 특성은 4가지로 나누어집니다 55 | * Key-Value Database 56 | * Document Database 57 | * Column Family Database 58 | * Graph Database 59 | 60 | 본론으로 돌아와서, 위 SQL에서 예시로 상품(Products) 테이블에 상품에 대한 재고 수를 추가로 저장하고 싶다고 했습니다. NoSQL에서는 스키마에 대해 신경 쓸 필요가 없기 때문에 추가 저장이 가능하게 됩니다. 61 | ```json 62 | { 63 | id: 1, 64 | name: "배추", 65 | price: 1000, 66 | description: "싱싱함" 67 | } 68 | { 69 | id: 2, 70 | name: "양파", 71 | price: 1200, 72 | description: "매움", 73 | stock: 50 //재고 수 74 | } 75 | ``` 76 | 77 | ### 관계 없음 78 | 79 | NoSQL 데이터베이스는 관계가 없기 때문에 조인이라는 개념이 없고 **데이터 복제**라는 개념이 있습니다. 문서(documents)에 데이터를 한 번에 담을 수 있기 때문입니다. 80 | 81 | 컬렉션을 통해 데이터를 복제하여 각 컬렉션 일부분에 속하는 데이터를 정확하게 산출하게 되는데요, 82 | 아래의 사진을 보면 아시다시피 Users의 데이터를 Orders에 복제해서 사용합니다. 83 | 84 | 85 | 86 | 하지만 이러한 방식의 단점은 데이터가 중복되고, 만약 Users 컬렉션에만 데이터가 업데이트되었을 때 Orders 컬렉션에 복제된 User는 과거의 데이터를 가지고 있다는 점입니다. 87 | 88 | 따라서 특정 데이터를 같이 사용하는 모든 컬렉션에서 똑같은 데이터 업데이트를 수행할 수 있도록 해야 합니다. (Users 컬렉션 데이터 업데이트가 되면 Orders 컬렉션에 복제된 User 데이터도 같이 업데이트하는 방식) 89 | 90 | 어떻게 보면 번거로울 수 있지만 이러한 방식의 장점은 복잡하고 느린 조인을 사용할 필요가 없다는 것입니다. 왜냐면 필요한 모든 데이터가 하나의 컬렉션에 다 저장이 되어있기 때문입니다. 91 | 92 | ## 확장성 93 | 마지막으로 SQL과 NoSQL을 비교할 때 확장성을 많이 비교하곤 합니다. 94 | 95 | 데이터베이스를 보통 어떤 방식으로 확장시킬 수 있을까요? 96 | 97 | 확장은 2가지로 구별할 수 있습니다. 98 | 99 | * 수직적(vertical) 확장과 100 | * 수평적(horizontal) 확장 101 | 102 | 수직적 확장이란 단순히 데이터베이스 서버의 성능을 향상하는 것입니다. Scale-up이라고 보시면 될 거 같습니다. 103 | 104 | 반면에 수평적 확장은 더 많은 서버가 추가되고 데이터베이스가 전체적으로 분산됨을 의미합니다. Scale-out이라고 보시면 될 거 같습니다. 105 | 106 | 107 | 108 | 데이터가 저장되는 방식(관련 테이블, 관련 없는 컬렉션)으로 인해 SQL 데이터베이스는 일반적으로 수직 확장을 사용합니다. 수평 확장은 NoSQL 데이터베이스에서만 주로 사용한다고 합니다. 109 | 110 | SQL 데이터베이스에서 주로 수직 확장(Scale-Up)을 사용하는 이유가 뭘까요? 111 | 112 | 113 | 수평 확장도 가능하지만 이는 많은 유지보수 노력이 필요하기 때문인데요, 114 | 여기서 주목해야 할 요점은 SQL 데이터베이스의 테이블이 관련 데이터의 여러 테이블로 정규화되었음을 볼 수 있다는 것입니다. 115 | 116 | 이러한 테이블의 데이터를 여러 컴퓨터에서 분할하려면 관련 정규화된 데이터를 적절하게 분할해야 하므로 유지 보수가 어렵다는 점입니다. 117 | 118 | ## 예상 질문 및 답변 119 | 120 | * SQL과 NoSQL의 차이에 대해 설명해주세요 121 | 122 | SQL은 스키마가 정확히 정의되어 있어서 데이터를 엄격하게 관리할 수 있고, 테이블 간의 관계를 맺어 중복도를 낮추고 동시에 데이터 간의 종속성을 맺을 수 있다. 이에 따라 레코드를 매우 쉽게 검색할 수 있다. 123 | 124 | NOSQL은 스키마가 존재하지 않기에 높은 수준의 유연성을 제공하며 빅데이터와 대용량의 데이터를 빠른 시간에 안전하게 처리할 수 있다. 125 | 126 | * RDBMS와 비교했을 때 NoSQL의 장점을 설명해주세요 127 | 128 | 가장 큰 장점이라면 JOIN 처리가 없기 때문에 스케일 아웃을 통한 노드 확장 용이하다는 점이다. 뿐만 아니라 가변적인 데이터 구조로 데이터를 저장할 수 있어서 훨씬 더 유연성이 높다. 129 | 130 | * 어떤 상황에서 SQL을 쓰는 것이 적합할까요? 131 | 132 | 앱의 여러 부분에서 관련된 데이터(ex. join)가 자주 변경되는 경우 (NoSQL이라면 항상 여러 컬렉션을 수정해야 함) 133 | 134 | 명확한 스키마가 중요하며, 데이터 구조가 극적으로 변경되지 않을 때 (대부분 서비스는 스키마가 유동적인 경우가 거의 없다. ) 135 | 136 | * 어떤 상황에서 NoSQL을 쓰는 것이 적합할까요? 137 | 138 | 정확한 데이터 요구사항을 알 수 없을 때 139 | 140 | 읽기(read) 처리를 자주 하지만, 데이터를 자주 변경(update) 하지 않는 경우 (즉, 한 번의 변경으로 수십 개의 문서를 업데이트할 필요가 없는 경우) 141 | 142 | 데이터베이스를 수평으로 확장해야 하는 경우 ( 즉, 막대한 양의 데이터를 다뤄야 하는 경우) -------------------------------------------------------------------------------- /Database/2022-04-08-트랜잭션.md: -------------------------------------------------------------------------------- 1 | # 트랜잭션 2 | 6 | 7 | # 트랜잭션이란 8 | 9 | - 작업의 완전성을 보장해주는 단위 10 | - 논리적인 작업 셋을 완벽하게 처리하거나 처리하지 못할 경우 원상태로 복구가 가능해야 함 11 | - 사용자 입장 → 작업의 논리적 단위 12 | - 시스템 입장 → 데이터를 접근/변경하는 프로그램의 단위 13 | 14 | # 트랜잭션의 특성(ACID) 15 | 16 | ## 원자성(Atomicity) 17 | 18 | > 트랜잭션 중간에 어떠한 문제가 발생한다면 어떠한 작업 내용도 수행되서는 안되며 19 | 아무런 문제가 발생하지 않은 경우에만 모든 작업이 수행되어야 한다. 20 | > 21 | 22 | 26 | 27 | ## 일관성(Consistency) 28 | 29 | > 트랜잭션이 완료된 다음에도 트랜잭션이 일어나기 전의 상황과 동일하게 30 | 데이터의 일관성을 보장해야 한다. 31 | > 32 | 33 | 38 | 39 | ## 고립성(Isolation) 40 | 41 | > 각 트랜잭션은 서로 간섭 없이 독립적으로 수행되어야 한다. 42 | > 43 | 44 | 48 | 49 | ## 지속성(Durability) 50 | 51 | > 트랜잭션이 정상 종료된 다음에는 영구적으로 데이터베이스에 작업의 결과가 저장되어야 한다. 52 | > 53 | 54 | 58 | 59 | # 트랜잭션 상태 60 | 61 | ![트랜잭션의 상태](images/transaction-status.png) 62 | 63 | 트랜잭션의 상태 64 | 65 | - 활동(Active) : 트랜잭션이 실행 중인 상태 66 | - 실패(Failed) : 트랜잭션 실행에 오류가 발생하여 중단된 상태 67 | - 철회(Aborted) : 트랜잭션이 비정상적으로 종료되어 롤백 연산을 수행한 상태 68 | - 부분 완료(Partially Committed) : 트랜잭션 마지막 연산까지 실행했지만, 커밋 연산이 실행되기 전 상태 69 | - 완료(Committed) : 트랜잭션이 성공적으로 종료되어 커밋 연산을 실행한 후의 상태 70 | 71 | # 트랜잭션 연산 72 | 73 | - DB 단위에서 트랜잭션을 사용하기 위해 제공하는 쿼리문으로는 Commit, Rollback이 있다. 74 | 75 | ## Commit 76 | 77 | - 하나의 트랜잭션이 완료되었음을 데이터베이스 관리자에게 알려주기 위한 연산 78 | 79 | ## Rollback 80 | 81 | - 트랜잭션 처리가 비정상적으로 종료되어 데이터베이스의 일관성을 깨트렸을 때, 트랜잭션의 원자성을 제공하기 위해 해당 트랜잭션이 행한 모든 연산을 취소하는 연산 82 | - 해당 트랜잭션을 재시작하거나 폐기한다 83 | - DML에 해당하는 SQL을 취소하기 때문에, DDL에는 효과가 없다 84 | 85 | ## Savepoint 86 | 87 | - 현재의 트랜잭션을 잘게 분할하는 명령어 88 | - Rollback문과 같이 사용하여 특정 위치까지 Rollback할 수 있다 89 | - 여러 SQL을 수반하는 트랜잭션의 경우, 중간 단계에서 Savepoint를 지정할 수 있다 90 | 91 | # Database 설정 92 | 93 | - MySQL 94 | - 저장 엔진에 따라 다름 95 | - MySQL 5.1까지는 MyISAM으로, Transaction 지원 x 96 | - 이후 버전은 InnoDB로, Transaction 지원 97 | - 자동 Commit 98 | - `SET AUTOCOMMIT=1` 로 설정 가능, 모든 문장마다 자동으로 COMMIT 실행 99 | - 디폴트 값이 1이며, 세션마다 새로운 연결 시 자동으로 Autocommit 활성화 100 | - 이를 종료하기 위해서는 `SET AUTOCOMMIT=0` 을 수행하거나, 접속 시 autocommit을 false로 지정하고 접속하면 됨 101 | - SQL이 정상 종료된 경우 → 자동 Commit 102 | - DDL과 DCL이 수행된 경우 → 자동 Commit 103 | - 시스템에서 제공하는 자동 Rollback 104 | - SQL이 비정상 종료된 경우 → 자동 Rollback 105 | - 정전이 발생하거나 컴퓨터가 Down되었을 시 → 자동 Rollback 106 | - 수동 Commit 107 | - 자동 커밋이 설정되어 있는 상태에서, `START TRANSACTION` 명령을 통해 특정 구간에서 일시적인 트랜잭션을 생성할 수 있음 108 | - `COMMIT` 명령을 마지막으로 트랜잭션이 완료됨 109 | 110 | # 트랜잭션 스케줄 111 | 112 | ## 직렬 스케줄 113 | 114 | - 순서대로 하나씩 트랜잭션을 수행 115 | - 하나의 실행이 완료되면 다른 트랜잭션을 시작 116 | - 한 트랜잭션 동안 다른 트랜잭션의 영향을 받지 않으므로 모순이 발생하지 않는다 117 | 118 | ## 직렬화 스케줄 119 | 120 | - 병렬 프로그래밍의 장점을 갖고 있다 121 | - 트랜잭션이 동시에 자료 접근 연산을 교차하며 실행하면서 결과가 직렬 스케줄과 동일 122 | - 적절한 제어를 통해 일관성을 유지하는 스케줄 123 | 124 | # 트랜잭션에서의 병행 처리 문제 125 | 126 | - 데이터베이스는 트랜잭션이 독립적인 수행을 하도록 한다 127 | - 따라서 Locking을 통해 다른 트랜잭션이 관여하지 못하도록 막아야 한다 128 | - 하지만 무조건 Locking을 수행하면 데이터베이스의 성능이 떨어지게 됨 129 | - 효율적인 Locking 방법이 필요 130 | 131 | ## Locking 종류 132 | 133 | - 공유 Lock 134 | - 특정 자료에 공유 Lock을 걸면 다른 트랜잭션이 해당 자료를 갱신할 수 없다 135 | - 다른 트랜잭션이 읽는 것은 가능하다 136 | - 배타 Lock 137 | - 특정 자료에 배타 Lock을 걸면 다른 트랜잭션이 자료를 갱신할 수 없고, 읽을 수도 없다. 138 | - 배타 Lock이 걸린 자료는 공유 Lock을 갖고 있는 트랜잭션들에 의해 읽혀질 수 없다 139 | (Dirty read 방지 - 아래에서 설명) 140 | 141 | ## 트랜잭션 격리 수준(Isolation Level) 142 | 143 | 1. Read Uncommitted(level 0) 144 | - Select 문장이 수행되는 동안 해당 데이터에 Shared Lock이 걸리지 않는다 145 | - 트랜잭션에 처리중이거나 ***Commit되지 않은 데이터***를 다른 트랜잭션이 읽는 것을 허용 146 | - 데이터 정합성에 문제가 있어, 사실상 격리수준으로 인정되지 않음(Dirty Read 발생) 147 | 148 | ![image](https://user-images.githubusercontent.com/72663337/178438534-1a5f201f-177e-4ce9-9809-482dbec881d0.png) 149 | 150 | 151 | 트랜잭션1에서의 변경 사항이 아직 커밋되지 않았음에도, 트랜잭션1 이후에 시작된 트랜잭션2에서 그 변경 사항을 조회할 수 있다. 152 | 153 | 154 | -> Dirty Read 155 |
156 | 157 | 2. Read Committed(level 1) 158 | - Select 문장이 수행되는 동안 해당 데이터에 Shared Lock이 걸린다 159 | - 트랜잭션이 Commit되어 확정된 데이터만 읽는 것을 허용 160 | - 일반적인 SQL 서버의 Default Isolation Level 161 | 162 | ![image](https://user-images.githubusercontent.com/72663337/178439002-e05e8ec8-93bc-4ad5-8a5e-315ebde90d72.png) 163 | 164 | 165 | 위와 같이 트랜잭션1에서 업데이트 쿼리로 인해 레코드의 값이 바뀌었음에도, 트랜잭션2에서 이 레코드를 조회할 때는 트랜잭션1이 커밋되지 않았기 때문에, 백업되어 있는 업데이트 이전의 레코드 값이 조회된다. 166 | 167 |
168 | 169 | 170 | 3. Repeatable Read(level 2) 171 | 172 | - 트랜잭션이 시작되기 전에 Commit된 내용에 대해서만 조회가 가능하다 173 | - 자신의 트랜잭션 번호보다 낮은(먼저 일어난) 트랜잭션 번호에서 커밋된 사항만 확인 가능 174 | - 트랜잭션이 범위 내에서 조회한 데이터 내용이 항상 동일함을 보장 175 | - 다른 사용자는 트랜잭션 영역에 해당되는 데이터에 대한 수정 불가 176 | 177 | 178 | ![image](https://user-images.githubusercontent.com/72663337/178439281-d62d5c45-d6d3-4be6-972c-70cca20d2611.png) 179 | 180 | 해당 트랜잭션이 시작되기 전에 커밋된 내용에 대해서만 조회할 수 있다. 181 | UNDO 공간에 백업해두고, 그 값을 읽음 (공간에 대한 비용 소모) 182 | 183 |
184 | 185 | 186 | 4. Serializable(level 3) 187 | - 한 트랜잭션을 다른 트랜잭션과 완전히 분리하는 격리 수준 188 | - 트랜잭션이 완료될 때까지 Select 문장이 사용하는 테이블에 공유 Lock을 건다 189 | 190 | 191 |
192 | 193 | 194 | ## 낮은 단계의 트랜잭션 고립 수준에서 발생하는 문제 사항 195 | 196 | 1. Dirty Read 197 | - 아직 실행이 완료되지 않은 다른 트랜잭션에 의한 변경 사항을 보게 되는 상황 198 | - 커밋되지 않은 데이터를 다른 트랜잭션에서 읽을 수 있도록 허용할 때 발생 199 | - 예시 1 200 | 1. T1이 데이터에 접근하여 A→B로 데이터를 변경, 커밋을 하지 않았다 201 | 2. T2가 데이터를 Read한다, B를 확인 202 | 3. T1이 커밋을 하지 않고 Rollback한다 203 | 4. 실제 데이터는 A이지만 T2에서는 B로 읽게 된다 204 | - 해결 방안 205 | - Read Committed 격리 수준을 활용하여 커밋되어 확정된 데이터만 읽을 수 있도록 지정한다 206 |
207 | 208 | 2. Non-Repeatable Read 209 | - 한 트랜잭션에서 같은 쿼리를 두 번 수행할 때 그 사이에 다른 트랜잭션 값을 수정하거나 삭제하면서 두 쿼리의 결과가 다르게 나타나는 상황 210 | - 예시 1 211 | 1. T1에서 특정 데이터를 조회, A를 확인 212 | 2. T2에서 A 데이터를 B로 변경 213 | 3. T1에서 데이터를 다시 조회한 결과 B가 조회됨 214 | 215 | 216 | - 예시 2 217 | 218 | 219 |
220 | 221 | ![image](https://user-images.githubusercontent.com/72663337/178439721-050aa3ee-efa5-471e-96a6-1e59f42d28ef.png) 222 | 223 | 트랜잭션2가 끝나기 전에 트랜잭션1이 커밋되면, 하나의 트랜잭션(2번)에서는 똑같은 레코드의 조회(select)를 수행했음에도, 다른 결과를 조회하게 되는 문제가 생길 수 있다. (일관성 오류) 224 | 225 |
226 | - 해결 방안 227 | - Repeatable Read 격리 수준을 활용하여 이전 트랜잭션이 완료되었을 때의 데이터만 조회할 수 있도록 지정한다 228 | - Q) 이렇게 진행되면 Phantom Read도 해결되지 않나요? - [ISSUE #15](https://github.com/prgrms-web-devcourse/BE-Team-R-CS-Study/issues/15) 229 | 230 | 231 |
232 | 233 | 234 | 3. Phantom Read 235 | - 하나의 트랜잭션에서 일정 범위의 같은 쿼리를 두 번 실행했을 경우, 첫 번째 쿼리에서 없던 유령 레코드가 두 번째 쿼리에서 나타나는 상황, 첫 번째 쿼리에서 있던 레코드가 두 번째 쿼리에서 사라지는 상황 236 | - 예시 1 237 | 1. T1이 특정 조건으로 데이터들을 검색하여 결과를 얻는다 238 | 2. T2가 접근하여 해당 조건의 데이터 일부를 삭제하거나 추가한다 239 | 3. T1이 다시 해당 조건으로 데이터들을 조회하면 결과가 변경된다 240 | 241 | - 예시 2 242 | 243 |
244 | 245 | ![image](https://user-images.githubusercontent.com/72663337/178440290-68f86134-3018-4fe9-9bc2-c33f32f0ce91.png) 246 | 247 | 위와 같이 하나의 트랜잭션에서 일정 범위에 대한 같은 쿼리를 두 번 실행했을 때, 첫 쿼리에서는 없던 유령 레코드가 두 번째 쿼리에서는 나타나는 현상이 일어날 수 있다.(결과 집합이 달라짐) 248 | 범위 전체에 대해서는 보관하지 못하기 때문에 발생하는 문제 249 | 250 | 251 |
252 | 253 | 254 | - 해결 방안 255 | - Serializable 격리 수준이 가장 좋지만, 성능 저하 문제로 사용하지 않음 256 | - MySQL의 InnoDB는 멀티 버전 동시성 제어(MVCC)를 통해 어느정도 극복(next key lock) 257 | 258 | 259 | MVCC(Multi Version Concurrency Control) 260 | 261 | - InnoDB에서는 UNDO 로그를 이용하여 이 기능을 구현함. 262 | - UNDO 영역에 백업된 이전 데이터를 이용하여, 트랜잭션 시작 시점의 스냅샷을 통하여 Phantom read 현상을 해결할 수 있다. 263 | 264 | 265 | 266 | ### Reference 267 | https://kihyun-log.tistory.com/m/entry/트랜잭션-격리-수준ISOLATION-LEVEL 268 | -------------------------------------------------------------------------------- /Database/2022-04-15-Index.md: -------------------------------------------------------------------------------- 1 | # Index 2 |
3 | 4 | 5 | ## Q . Index 란? 6 | 7 | RDBMS에서, 테이블에 대한 검색 속도를 향상시키는 자료 구조 8 | 9 | 테이블 내의 컬럼 1개, 또는 여러 개의 컬럼을 이용하여 생성 가능 10 | 11 | ![image](https://user-images.githubusercontent.com/72663337/163573579-b9100955-dbf5-4d2c-85e0-198bf4c71eb4.png) 12 | 13 | 14 | 15 | 16 | - 해당 컬럼을 정렬 후 별도 공간에 이를 저장하여, 검색 시 테이블의 레코드를 full scan하지 않고 색인화 되어 있는 index 파일을 검색하여 검색 속도를 빠르게 함. 17 | 18 | 19 | 20 | - 원하는 값을 탐색하는 속도가 빠름 21 | 22 | 23 | 24 | 25 | ## Q . index의 장단점 26 | 27 | 28 | **장점** 29 | 30 | - 데이터들이 정렬된 형태를 갖고, 따라서 검색의 속도를 향상시킴 31 | 32 | 33 | 34 | 35 | 36 | **단점** 37 | 38 | - 인덱스가 Database의 10% 내외의 공간을 필요로 하므로, 이에 따른 추가적인 공간이 필요함 39 | 40 | - 테이블의 데이터가 변경될 때 인덱스를 재작성해야 하므로 성능이 떨어짐 41 | 42 | -> SELECT를 제외한 동작(INSERT, UPDATE, DELETE)의 성능에 악영향을 끼침 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | ## Q . 인덱스를 사용해야 하는 경우 51 | 52 | - 데이터의 양이 많고, 검색 작업이 수정 작업보다 빈번하게 일어나는 경우 53 | 54 | 55 | 56 | (1) where 절에서 자주 사용되는 column 57 | 58 | 59 | 60 | (2) 외래키가 사용되는 column 61 | 62 | 63 | 64 | (3) join에 자주 사용되는 column 65 | 66 | 67 | 68 | -> 조회 작업이 자주 일어나는 column 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | ## Q . 사용을 피해야 하는 경우 77 | - 테이블의 데이터를 업데이트할 때 인덱스를 재작성해야 하므로 성능이 떨어짐 78 | 79 | 80 | (1) Data 중복도가 높은 column 81 | - 해당 column을 통하여 데이터를 검색해야 하는데 중복도가 높으면 검색의 효율이 떨어짐 82 | 83 | 84 | 85 | (2) DML(INSERT, DELETE, UPDATE,, )이 자주 일어나는 column 86 | - **INSERT** 87 | 88 | - 데이터가 순서대로 정렬되어 있어야 하는 인덱스에서, 새로운 데이터가 입력되는 경우 89 | 90 | - 기존 인덱스 블록의 일부를 새 블록에 기록한 후, 그로 인해 생긴 기존 블록의 빈 공간에 새로운 데이터를 추가함. 91 | 92 | -> index split ( 인덱스의 블록이 두개로 나누어지는 현상.) 93 | 94 | --> 성능 면에서 저하 95 | 96 | 97 | 98 | 99 | 100 | - **DELETE** 101 | 102 | 103 | - 테이블에서 데이터가 삭제되는 경우, 지워진 후 다른 데이터가 그 공간을 활용할 수 있음 104 | - But 인덱스에서 데이터가 삭제되는 경우, 지워지지 않고 사용 안 됨 표시가 된다. 105 | 106 | 107 | 따라서 삭제 연산이 많아지면 108 | 109 | -> 테이블 데이터 수에 비하여 인덱스의 데이터가 지나치게 많아질 수 있음 110 | 111 | --> 인덱스를 사용함을 통한 수행 속도를 기대하기 어려워짐 112 | 113 | 114 | 115 | 116 | 117 | - **UPDATE** 118 | 119 | 인덱스에는 UPDATE 개념이 존재하지 않음. 120 | 121 | DELETE가 수행된 후, 새로운 데이터 INSERT가 수행됨 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | ## Q . Index 의 성능을 향상시키는 방법이란? 130 | **카디널리티(Cardinality)** 131 | 132 | : 한 컬럼이 갖고 있는 값의 상대적인 중복 정도 133 | 134 | -> 카디널리티가 높을수록(중복 정도가 낮을수록) 좋은 column 135 | 136 | 137 | 138 | 139 | 140 | **선택도(Selectivity)** 141 | 142 | - 특정 값을 얼마나 잘 선택할 수 있는지에 대한 지표 143 | 144 | - 특정 필드 값을 지정했을 때, 선택되는 레코드 수를 테이블 전체 레코드 수로 나눈 것 145 | 146 | ``` 147 | select count(1) from students where last_name="kim"; 148 | ``` 149 | 150 | ``` 151 | select count(1) from students where id=1; 152 | ``` 153 | 154 | `위의 예시에서, 두 번째 예시의 선택도가 더 낮음` 155 | 156 | -> 중복 정도가 적을수록 선택도가 낮음 157 | 158 | --> 선택도가 낮을수록 좋은 column 159 | 160 | 161 | 162 | **활용도** 163 | 164 | - 해당 컬럼이 작업에서 얼마나 활용되는지에 대한 값 165 | 166 | (쿼리를 날릴 때, where절에 자주 사용되는지) 167 | 168 | 169 | -> 활용도가 높을수록 좋은 column 170 | 171 | 172 | 173 | 174 | 175 | 176 | ## Q . Index 자료구조 177 | 178 | ### Hash 인덱스 알고리즘 179 | 180 | - 컬럼의 값을 해싱한 값을 기반으로 인덱스를 구현. 181 | 182 | -> 매우 빠른 검색 지원 (시간복잡도 O(1) ) 183 | 184 | - 값을 변형하여 인덱싱하기 때문에 값의 일부분으로 검색하는 등의 작업은 불가능하고, 185 | 186 | 같은 이유로 연속적인 데이터에 대한 순차 검색(부등호를 통한 비교 등..)이 불가능 187 | 188 | 189 | 190 | 191 | 192 | ### B+Tree 인덱스 알고리즘 193 | 194 | - 일반적으로 사용되는 알고리즘. 195 | 196 | 197 | - B-Tree(Balanced Tree, 편향되지 않은 트리)를 개선시킨 자료구조 B+Tree를 사용함 198 | 199 | - leaf node에만 데이터가 저장됨. 200 | 201 | -> 데이터의 순회 속도를 높임(리프노드들을 LinkedList로 연결하여, 순차 검색을 용이하게 함) 202 | 203 | 204 | 205 | ![B-tree](https://user-images.githubusercontent.com/72663337/163573680-1b72c36e-9b57-41a1-b7e9-6af91bdf5d4e.png) 206 | 207 | ![B+tree](https://user-images.githubusercontent.com/72663337/163573767-e0787645-272a-4493-a4a0-a3e580d8cfb2.png) 208 | 209 | 210 | 211 | 212 | 213 | 214 | ## Q . 해시 알고리즘보다 B+ Tree를 이용한 인덱스를 많이 쓰는 이유는? 215 | 216 | - B+Tree는 검색 작업에 있어서 해시보다는 비효율적인 시간복잡도를 가진다.(트리를 사용하기 때문에 O(logN)) 217 | 218 | - 하지만 해시의 데이터들은 정렬되어 있지 않고, B+Tree에서는 해시와는 다르게 순차 검색 연산을 효율적으로 수행할 수 있다. 219 | 이는 순차 검색 연산을 이용한 등호 연산(<, >)이 자주 발생하는 인덱스에서 큰 강점이기 때문에, 220 | 221 | - 해시 알고리즘 보다는 B+Tree를 이용한 인덱스가 주로 사용된다. 222 | 223 | 224 | 225 | 226 | 227 | 228 |
229 | 230 | ++ 231 |
232 | 233 | 234 | ## Q . Primary index(기본 인덱스) vs Secondary index(보조 인덱스) 235 | 236 | 237 | ### primary index(클러스터형 인덱스) 238 | 239 | - 기본 키를 포함하는 인덱스(테이블 당 하나씩만 존재) 240 | 241 | - 인덱스가 레코드와 직접적으로 연결되어 위치를 결정 242 | 243 | (키의 순서가 레코드의 순서를 결정지음. 정렬되어 있음) 244 | 245 | 246 | 247 | ### secondary index(비클러스터형 인덱스) 248 | 249 | - "보조하는" 인덱스 250 | 251 | - 일반적으로 속성에 unique가 지정된 컬럼이 보조 인덱스 역할을 함 252 | 253 | - 테이블 당 여러 개의 보조 인덱스 생성 가능 254 | 255 | 256 | 257 | - 레코드의 위치를 결정짓지는 않음.(정렬되어 있지 않음) 258 | 259 | - 레코드의 위치가 어딘지를 알려주는 역할.(포인터를 갖고 있음) 260 | 261 | 262 | 263 | 264 |
265 | 266 | 267 | ## Reference 268 | 269 | https://rebro.kr/167 270 | -------------------------------------------------------------------------------- /Database/2022-04-22-정규화와반정규화.md: -------------------------------------------------------------------------------- 1 | # 1. 정규화 2 | 3 | ## (1) 이상현상 (Anomaly) 4 | 5 | 데이터가 중복되는 경우 다음의 이상현상이 발생할 수 있다. 6 | 7 | ### ① 삽입 이상 8 | 9 | - 불필요한 데이터를 추가해야지 삽입할 수 있는 상황을 말한다. 10 | - 예시) 기본키가 {Student ID, Course ID}인 경우, Course를 수강하지 않은 학생은 Course ID가 없기 때문에, 억지로 미수강과 같은 Course ID를 만들어야지 삽입할 수 있다. 11 | 12 | ### ② 갱신 이상 13 | 14 | - 일부만 변경하여, 데이터가 불일치 하는 모순이 발생하는 문제 15 | - 예시) 만약 어떤 학생의 전공이 컴퓨터 → 음악으로 바뀌는 경우, 모든 Department를 음악으로 바꾸어야 함. 하지만 일부를 깜빡하고 바꾸지 못하는 경우, 모순이 발생한다. 16 | 17 | ### ③ 삭제 이상 18 | 19 | - 꼭 필요한 데이터까지 함께 삭제된ㄴ 문제 20 | - 예시) 만약 어떤 학생이 수강을 철회하는 경우, {Student ID, Department, Course Id, Grade} 정보 중 Student ID, Department와 같은 학생에 대한 정보도 함께 삭제됨 21 | 22 |
23 | 24 | ### (2) 정규화란? 25 | 26 | - 함수적 종속성은 X가 변화하면 Y도 변화하는지 확인한다. X의 값이 Y의 값을 유일하게 결정한다면 ”X는 Y를 함수적으로 결정한다”라고 말할 수 있다. 27 | - 함수적 종속성을 통해 나쁜 릴레이션을 판단할 수 있다. 28 | 29 | ⇒ 각각의 정규형마다 어떠한 함수적 종속성을 만족하는지에 따라 정규형의 정의되고, 그 정규형을 만족하지 못하는 정규형을 나쁜 릴레이션으로 파악한다. 30 | 31 | 32 | 정규화는 다음과 같은 장점을 가진다. 33 | 34 | - 데이터의 중복을 없애면서 불필요한 데이터를 최소화시킨다. 35 | - 무결성을 지키고, 이상 현상을 방지한다. 36 | - 테이블 구성을 논리적이고 직관적으로 할 수 있다. 37 | - 데이터베이스 구조를 확장에 용이해진다. 38 | 39 |
40 | 41 | ### (3) 제 1 정규화 42 | 43 | 제 1정규화는 테이블의 컬럼이 원자값을 갖도록 테이블을 분해하는 것이다. 44 | 45 |
46 | 47 |
48 | 출처 : https://github.com/gyoogle/tech-interview-for-developer/blob/master/Computer%20Science/Database/%EC%A0%95%EA%B7%9C%ED%99%94(Normalization).md 49 |
50 |
51 | 52 |
53 | 54 |
55 | 56 | 위의 경우 첫 번째와 두 번째 사람은 전화번호를 여러개 가지고 있다. 57 | 58 | 따라서, 테이블의 컬럼이 원자값을 갖도록 테이블을 분해해야한다. 59 | 60 |
61 | 62 |
63 | 출처 : https://github.com/gyoogle/tech-interview-for-developer/blob/master/Computer%20Science/Database/%EC%A0%95%EA%B7%9C%ED%99%94(Normalization).md 64 |
65 |
66 | 67 |
68 | 69 | ### (4) 제 2정규화 70 | 71 | 제 2정규화는 제 1정규화가 진행된 테이블에 대해서 진행된다. 72 | 73 | 단, 기본키가 하나일때는 건너뛸 수 있다. 74 | 75 | 제 2정규화에서는 테이블의 모든 컬럼이 완전 함수적 종속을 만족하도록 만든다. 76 | 77 | 즉, 테이블에서 기본키가 복합키로 묶여있을 때, 두 키 중 하나의 키가 결정자가 되어서는 안된다! 78 | 79 | ⇒ 기본키의 부분집합이 결정자가 되어서는 안된다! 80 | 81 |
82 | 83 |
84 | 출처 : https://github.com/gyoogle/tech-interview-for-developer/blob/master/Computer%20Science/Database/%EC%A0%95%EA%B7%9C%ED%99%94(Normalization).md 85 |
86 |
87 | 88 |
89 |
90 | 91 | 위의 경우 Manufacturer과 Model이 기본키이다. (밑줄!) 92 | 93 | 그런데, Manufcaturer 하나만으로도 Manufacturer Country를 결정할 수 있다. 94 | 95 | ⇒ 따라서 완전 함수적 종속을 만족하지 않는다고 할 수 있다. 96 | 97 |
98 | 99 |
100 | 출처 : https://github.com/gyoogle/tech-interview-for-developer/blob/master/Computer%20Science/Database/%EC%A0%95%EA%B7%9C%ED%99%94(Normalization).md 101 |
102 |
103 | 104 |

105 | 106 | 따라서 테이블을 위와 같이 나누어준다. 107 | 108 |
109 | 110 | ### (5) 제 3정규화 111 | 112 | 제 3정규화는 제 2정규화를 진행한 테이블에 대해 진행된다. 113 | 114 | 제 3정규화는 이행 함수 종속성을 제거한다. 115 | 116 | 이행 함수 종속성이란, 기본키를 제외하고 칼럼간에 종속성이 발생하는 것이다. 117 | 118 |
119 | 120 |
121 | 출처 : https://github.com/gyoogle/tech-interview-for-developer/blob/master/Computer%20Science/Database/%EC%A0%95%EA%B7%9C%ED%99%94(Normalization).md 122 |
123 |
124 | 125 |

126 | 127 | 위의 테이블에서 기본키는 Tournament와 Year이다. 128 | 129 | 이 때, 기본키가 아닌 Winner은 Winner Date of Birth를 결정할 수 있다. 130 | 131 | 따라서 이는 이행 함수 종속성이 발생했다고 볼 수 있다. 132 | 133 |
134 | 135 |
136 | 출처 : https://github.com/gyoogle/tech-interview-for-developer/blob/master/Computer%20Science/Database/%EC%A0%95%EA%B7%9C%ED%99%94(Normalization).md 137 |
138 |
139 | 140 |

141 | 142 | 제 3정규화를 진행하면 위와 같다. 143 | 144 |
145 | 146 | ### (6) BCNF (Boyce-Codd Normal Form) 147 | 148 | BCNF 정규화는 제 3정규화를 진행한 테이블에 대해 모든 결정자가 후보키가 되도록 테이블을 분해하는 것이다. 149 | 150 |
151 | 152 |
153 | 출처 : https://mangkyu.tistory.com/110 154 |
155 |
156 | 157 |

158 | 159 | 위의 테이블에서 학생 번호와 특강 이름이 기본키이다. 160 | 161 | 하지만, 특강 이름은 교수에 의해 결정된다. 162 | 163 | 즉, 교수는 특강 이름의 결정자이지만 후보키가 아니다. 164 | 165 | 따라서 위의 테이블을 다음과 같이 분해한다. 166 | 167 |
168 | 169 |
170 | 출처 : https://mangkyu.tistory.com/110 171 |
172 |
173 | 174 |

175 | 176 | 이제는 교수도 후보키가 되어서, BCNF 정규화를 만족시킨다. 177 | 178 |
179 | 180 | ### (7) 정규화의 문제점 181 | 182 | - 정규화는 데이터 조회시에 많은 Join을 유발하기 때문에 CPU와 메모리를 많이 사용한다. 또한 ㄴ응답 시간이 느려질 수 있다. 183 | 184 |
185 | 186 | # 3. 반정규화 187 | 188 | 정규화는 Join이 많이 발생하여 이로 인한 성능 저하가 나타나는 경우가 있다. 189 | 190 | 이 때, 성능향상을 위해 반정규화를 사용할 수 있다. 191 | 192 |
193 | 194 | ## (1) 반정규화란? 195 | 196 | 반정규화는 비정규화라고도 불린다. 197 | 198 | 반정규화는 데이터 베이스의 성능 향상을 위하여, 데이터 중복을 허용하고 조인을 줄이는 데이터베이스 성능 향상 방법이다. 199 | 200 | 일반적으로 조회에 대한 처리 성능이 중요하다고 판단될 때, 부분적으로 반정규화를 고려하게 된다. 201 | 202 | 반정규화는 조회 속도를 향상시키지만, 데이터 모델의 유연성은 낮아진다. 203 | 204 | 또한, 반정규화를 과하게 적용하다보면 데이터의 일관성과 무결성이 깨질 수 있고, 입력, 수정, 삭제의 질의문에 대한 응답 시간이 늦어질 수 있다. 205 | 206 |
207 | 208 | ## (2) 반정규화 방법 209 | 210 |
211 | 212 |
213 | 출처 : https://m.blog.naver.com/PostView.naver?isHttpsRedirect=true&blogId=bi1189&logNo=221508915632 214 |
215 |
216 | 217 |

218 | 219 | - 계산된 칼럼 추가 : 총판매액, 평균 잔고 등을 미리 계산하고, 그 결과를 특정 칼럼에 추가한다. 220 | - 테이블 수직분할 : 칼럼을 분할하여 새로운 테이블을 만든다. 221 | - 테이블 수평분할 : 테이블에 있는 값을 기준으로 테이블을 분할한다. 222 | - 테이블 병합 223 | - 1대1 관계의 테이블을 하나의 테이블로 병합해서 성능을 향상시킨다 224 | - 1대N 관계의 테이블을 병합해서 성능을 향상시킨다 → 많은 양의 데이터 중복 발생 225 | - 슈퍼 타입과 서브 타입 관계가 발생하면 테이블을 통합하여 성능을 향상시킨다 226 | 227 | ex) 고객 테이블이 있고 해당 테이블의 서브 타입인 개인 고객 테이블과 법인 고객 테이블이 있으면 세 테이블을 통합하여 성능을 향상시킨다. 228 | -------------------------------------------------------------------------------- /Database/2022-04-29-SQL_Injection.md: -------------------------------------------------------------------------------- 1 | # SQL Injection 2 | 3 | ## SQL Injection 4 | 5 | 9 | 10 | - 주로 개인정보를 빼낼 때 많이 사용되는 기법이다. 11 | 12 | ![Untitled](https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=http%3A%2F%2Fcfile21.uf.tistory.com%2Fimage%2F9920763C5C8890FB1AE43C) 13 | 14 | ## SQL Injection 종류 및 방법 15 | 16 | ### 1. Error based SQL Injection 17 | 18 | 22 | 23 | - 논리적 에러를 이용한 SQL Injection은 가장 많이 쓰이고, 대중적인 공격 기법 24 | 25 | ![Untitled](https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=http%3A%2F%2Fcfile22.uf.tistory.com%2Fimage%2F9958373C5C8890FA036E06) 26 | 27 | - 일반적으로 로그인 시 많이 사용되는 SQL 구문 28 | - 해당 구문에서 입력값에 대한 검증이 없음을 확인하고, 악의적인 사용자가 임의의 SQL 구문을 주입 (SQL Injection) 29 | - `' OR 1=1 --` 30 | - WHERE 절에 있는 싱글쿼터를 닫아주기 위한 싱글쿼터 `'` 31 | - `OR 1=1` 라는 구문을 이용해 WHERE 절을 모두 참으로 만든다. 32 | - `--`를 넣어줌으로 뒤의 구문을 모두 주석 처리 33 | - 결론적으로 Users 테이블에 있는 모든 정보를 조회하게 됨으로 써 가장 먼저 만들어 진 계정으로 로그인에 성공하게 된다. 34 | - 보통 관리자 계정을 맨 처음 만들기 때문에 관리자 계정에 로그인 할 수 있다. 35 | - 관리자 계정을 탈취한 악의적인 사용자는 관리자의 권한을 이용해 또 다른 2차피해를 발생 시킬 수 있게 된다. 36 | 37 | ### 2. Union based SQL Injection 38 | 39 | 43 | 44 | - Union 키워드는 두 개의 쿼리문에 대한 결과를 통합해서 하나의 테이블로 보여주게 하는 키워드 45 | 46 | > Union Injection을 성공하기 위한 두 가지 조건 47 | > 48 | > - 컬럼의 개수가 같아야 한다. 49 | > - 데이터 형이 같아야 한다. 50 | 51 | ![Untitled](https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=http%3A%2F%2Fcfile4.uf.tistory.com%2Fimage%2F99BD4C3C5C8890FA0A2D9F) 52 | 53 | - Board 라는 테이블에서 title과 contents 컬럼의 데이터랑 비교한 뒤 비슷한 글자가 있는 게시글을 검색하는 쿼리문 54 | - Union 키워드와 함께 컬럼 수를 맞춰서 SELECT 구문을 넣어주게 되면 두 쿼리문이 합쳐서서 하나의 테이블로 보여진다. 55 | - 인젝션 한 구문은 사용자의 id와 password를 요청하는 쿼리문 56 | - id : long 57 | - password : String 58 | - null 59 | - 사용자의 개인정보가 게시글(board)과 함께 화면에 보여지게 된다. 60 | 61 | ### 3. Blind SQL Injection 62 | 63 | 67 | 68 | ### **Boolean based SQL** 69 | 70 | - 로그인 폼에 SQL Injection이 가능하다고 가정 했을 때, 서버가 응답하는 **로그인 성공과 로그인 실패 메시지를 이용**하여, DB의 테이블 정보를 등을 추출해 낼 수 있다. 71 | 72 | ![Untitled](https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=http%3A%2F%2Fcfile3.uf.tistory.com%2Fimage%2F99525F3C5C8890F90ED03D) 73 | 74 | - Blind Injection을 이용해서 데이터베이스의 테이블 명을 알아내는 방법 75 | - 악의적인 사용자는 `abc123’ and ASCII(SUBSTR(SELECT name From information_schema.tables WHERE table_type=’base table’ limit 0,1)1,1)) > 100 --` 구문 주입 76 | - limit 키워드를 통해 information_schema.tables에 있는 하나의 테이블만 조회 (0행 부터 1행까지) 77 | - SUBSTR 함수로 첫 글자만, 그리고 마지막 ASCII 를 통해서 ascii 값으로 변환 78 | - SUBSTR(str, pos, len) ⇒ 1번째 문자열부터 1글자만 가져오기 79 | - 조회되는 테이블 명이 Users 라면 ‘U’ 자가 ASCII 값으로 조회 80 | - 뒤의 100 이라는 숫자 값과 비교를 하게 된다. 81 | - 거짓이면 로그인 실패, 참이 될 때까지 뒤의 100이라는 숫자를 변경해 가면서 비교를 하게 된다. 82 | - 성공되는 숫자값을 알게된다 ⇒ 문자열의 ASCII 값을 알게된다. 83 | - 공격자는 이 프로세스를 자동화 스크립트를 통해서 단기간 내에 **테이블 명**을 알아 낼 수 있다. 84 | 85 | > **INFORMATION_SCHEMA ⇒ 테이블의 메타데이터** 86 | - 테이블 메타데이터의 TABLES 및 TABLE_OPTIONS 87 | - 열 및 필드 메타데이터의 COLUMNS 및 COLUMN_FIELD_PATHS 88 | - 테이블 파티션 관련 메타데이터의 PARTITIONS 89 | > 90 | 91 | ### **Time based SQL** 92 | 93 | - **Sleep, Benchmark 가 되는 기준**으로 참과 거짓을 구별한다. 94 | 95 | ![Untitled](https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=http%3A%2F%2Fcfile24.uf.tistory.com%2Fimage%2F99CAFB395C889145133A37) 96 | 97 | - 테이터베이스의 길이를 알아내는 방법 98 | - 악의적인 사용자가 `abc123’ OR (LENGTH(DATABASE())=1 AND SLEEP(2)) --` 구문 주입 99 | - LENGTH 함수는 문자열의 길이를 반환 100 | - DATABASE 함수는 데이터베이스의 이름을 반환 101 | - LENGTH(DATABASE()) = 1 가 참이면 SLEEP(2) 가 동작, 거짓이면 동작X 102 | - 1 부분을 조작하여 **데이터베이스의 길이**를 알아 낼 수 있다. 103 | 104 | ## 대응방안 105 | 106 | ### 1. 입력 값에 대한 검증 107 | 108 | 112 | 113 | - SQL Injection 에서 사용되는 기법과 키워드는 엄청나게 많다. 114 | - 블랙리스트 기반으로 검증하게 되면 수많은 차단리스트를 등록해야 하고, 하나라도 빠지면 공격에 성공하게 되기 때문 115 | 116 | ### 2. PreparedStatement 구문 사용 117 | 118 | 122 | 123 | ![Untitled](https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTIh4U_0gkyPcwQznj5qKF9E15ngyPqt-36kdQ48PWhR4ohw7aRFDHURYGxKCA_uf2p5g&usqp=CAU) 124 | 125 | - DBMS 내부적으로 4가지 과정 (parse, bind, execute, fetch)을 거쳐 결과를 출력 126 | - 문법을 검사하기 위해서 parse 과정을 거치게 된다. 127 | 128 | ![Untitled](https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTnIdpC0DoNuw7M7IQ_3krBPnEjgRslNDot2A&usqp=CAU) 129 | 130 | - 일반적인 Statement를 사용하여 SELECT 쿼리를 입력했을 때에는 매법 parse부터 fetch까지 모든 과정을 수행한다. 131 | - Prepared Statement를 사용하는 경우에는 효율을 높이기 위해 parse 과정을 최초 1번만 수행 132 | - 자주 변경되는 부분을 변수로 선언해 두고, 매번 다른 값을 대입하여 사용한다. 133 | - 그 후 사용자의 입력 값을 문자열로 인식하게 하여 공격 쿼리가 들어간다고 하더라도, 사용자의 입력은 이미 의미 없는 **단순 문자열** 이기 때문에 전체 쿼리문도 공격자의 의도대로 작동하지 않는다. 134 | 135 | ### 3. Error Message 노출 금지 136 | 137 | 141 | 142 | - 공격자가 SQL Injection을 수행하기 위해서는 데이터베이스의 정보(테이블명, 컬럼명 등)가 필요하다. 143 | - 데이터베이스 에러 발생 시 따로 처리를 해주지 않았다면, 에러가 발생한 쿼리문과 함께 에러에 관한 내용을 반환해 준다. 144 | - 여기서 테이블명 및 컬럼명을 그리고 쿼리문이 노출이 될 수 있다. 145 | 146 | ## 예상 질문 147 | 148 | ### 1. SQL Injection 설명 149 | 150 | ### 2. SQL Injection 공격 방어 기법 151 | 152 | ## 참고문헌 153 | 154 | [https://noirstar.tistory.com/264](https://noirstar.tistory.com/264) 155 | 156 | [https://github.com/gyoogle/tech-interview-for-developer/blob/master/Computer Science/Database/SQL Injection.md](https://github.com/gyoogle/tech-interview-for-developer/blob/master/Computer%20Science/Database/SQL%20Injection.md) -------------------------------------------------------------------------------- /Database/2022-05-10-Lock.md: -------------------------------------------------------------------------------- 1 | # Lock(락) 2 | 3 | Lock이란 데이터의 일관성과 무결성을 유지하기 위해 트랜잭션의 순차적 진행을 보장해주는 방법입니다. (= 잠금) 4 | 5 | ### **데이터베이스 Lock Level** 6 | 7 | ![image](https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqvPPr%2FbtrBwtAdARb%2FIQ8IwKSxwR3QXpyscKZ1HK%2Fimg.png) 8 | 9 | 데이터베이스에서의 Lock 여러 Level을 갖습니다. 10 | 11 | Lock Level은 잠금이 요청되거나 사용될때의 리소스에 대한 범위를 설정합니다. 12 | 13 | - **Database Level** 14 | 15 | 데이터베이스 범위의 Lock은 데이터베이스 전체가 잠기게 됩니다. 16 | 17 | 해당 기능은 일반적으로 사용하지 않으며, 보통 스키마를 변경하거나 DB의 소프트웨어 버전을 올리는 등에 사용됩니다. 18 | 19 | - **Table Level** 20 | 21 | 테이블을 기준으로 Lock을 설정합니다. 테이블 전체와 관련 인덱스까지 모두 잠깁니다.   22 | 23 | 이는 테이블의 모든 행을 업데이트 하거나 전체 테이블에 영향을 주는 변경을 수행할때 사용됩니다.  24 | 25 | DDL(create, alter, drop 등) 구문과 함께 사용되며 DDL Lock이라고도 불립니다. 26 | 27 | - **Page Level** 28 | 29 | 페이지를 기준으로 Lock을 설정합니다.  30 | 31 | 보통 DB에 저장되는 데이터는 8KB 단위의 블럭을 단위로 저장되는데, 이를 페이지라고 불립니다. 32 | 33 | - **Row Level** 34 | 35 | 가장 세분화된 잠금 수준으로 1개의 행을 기준으로 Lock을 설정합니다. 36 | 37 | DML(insert, update, delete 등) 에 대한 Lock으로 가장 일반적으로 사용됩니다.  38 | 39 |
40 | 41 | ### **데이터베이스 Lock 종류** 42 | 43 | - **Exclusive (X) Lock  (= 베타 락, Write Lock)**  44 | 45 | 베타 락은 데이터에 변경을 가하는 **쓰기 명령**들에 대해 주어지는 락으로 Write Lock으로도 불리며, X로 표기합니다. 46 | 47 | 즉, 트랜잭션이 데이터를 변경할때 잠금합니다. 48 | 49 | 베타 락은 이름처럼 다른 트랜잭션이 해당 자원에 접근(ex, SELECT, INSERT..) 하는 것을 막습니다. 50 | 51 | 오직 하나의 트랜잭션만이 데이터에 대한 잠금을 걸 수 있다는 특징이 있습니다. 52 | 53 | - **Shared (S) Lock (= 공유 락, Read Lock)** 54 | 55 | 공유 락은 데이터를 변경하지 않는 **읽기 명령**에 대해 주어지는 락으로 Read Lock이라고도 불리며 Shared의 앞 글자를 따서 주로 S로 표기합니다. 즉, 트랜잭션이 데이터를 읽기 동안에만 잠금합니다. 56 | 57 | 여러 사용자가 동시에 데이터를 읽어도 데이터의 일관성에는 아무런 영향을 주지 않기 때문에, 공유 락끼리는 동시에 접근이 가능합니다. 58 | 59 | - **Intent (I) Lock (=내재 락)** 60 | 61 | 내재 락은 트랜잭션이 대상 데이터에 잠금을 걸 수 있을지 없을지를 **신속히 판단할 수 있게 도와주는 잠금**입니다. 62 | 63 | 내재 락은 공유 락과 베타 락 앞에 I 기호를 붙인 IS, IX, SIX 등이 있습니다. 64 | 65 | - Intent exclusive (IX) Lock (= 의도적 베타적 잠금)  66 | - Intent shared (IS) Lock (= 의도적 공유 잠금) 67 | - Shared intent exclusive (SIX) Lock (= 공유 및 의도적 베타적 잠금) 68 | 69 | 예를 들자면, 70 | 71 | 사용자 A가 테이블의 **하나의 로우(row)에 대해 베타 락(X)을 건 경우**, 사용자 B가 테이블 전체에 대한 락을 걸기 위해서는(ex, 스키마 변경) 사용자 A의 **트랜잭션이 끝날 때까지 기다려야 합니다**. 72 | 73 | 그러나, 사용자 B가 테이블에 **락(DDL Lock)을 걸 수 있는지 여부를 파악하기 위해** 테이블에 존재하는 **모든 로우와 관련된 락을 찾아보는 것은 매우 비효율적인 작업**입니다. 74 | 75 | 따라서, 데이터베이스는 사용자 A가 로우에 베타 락(X)을 거는 시점에, 해**당 로우의 상위 객체들(ex, 페이지, 테이블)에 대한 내재 락(IX)을 걸어**, 다른 사용자가 **더 큰 범위의 자원들에 대해 락을 걸 수 있는지 여부를 빠르게 파악**할 수 있도록 돕습니다. 76 | 77 | - **Update (U) Lock** 78 | 79 | 업데이트 락은 데이터를 수정하기 위해 베타 락(X)을 걸기 전, 데드 락을 방지하기 위해 사용되는 락입니다. 80 | 81 | 일반적으로 업데이트 락은 UPDATE 쿼리의 필터(WHERE)가 실행되는 과정에서 적용됩니다. 82 | 83 |
84 | 85 | ### **Optimistic Lock과 Pessimisitc Lock** 86 | 87 | - Optimistic Lock (낙관적 락) 88 | 89 | 말 그대로 트랜잭션 충돌이 발생하지 않는다는 가정을 하는게 낙관적 락입니다. 90 | 91 | DB가 제공하는 락 기능을 사용하지 않고 JPA가 제공하는 버전 관리 기능을 사용합니다. (@Version) 92 | 93 | 즉, **어플리케이션이 제공**하는 락이라고 볼 수 있습니다. 94 | 95 | 트랜잭션을 커밋하기 전까지 트랜잭션 충동을 알 수 없다는 점이 있습니다. 96 | 97 | ```java 98 | @Entity 99 | public class Board { 100 | @Id 101 | private String id; 102 | private String title; 103 | 104 | @Version 105 | private Integer version 106 | } 107 | ``` 108 | 109 | 위와 같은 Board 엔티티에서, 엔티티를 수정할때마다 version 필드가 자동으로 증가합니다. 110 | 111 | 그리고 엔티티를 수정할 때 **조회 시점의 버전**과 **수정 시점의 버전**이 **다르면** 예외를 발생시키는 것입니다. 112 | 113 | 예를 들어, 사용자 A와 사용자 B가 동일한 게시글을 수정한다고 가정해보겠습니다. 114 | 115 | A가 먼저 게시글을 다 수정하고 B가 수정을 하게 되면 version이 다르므로 (A가 수정하게 되면서 version값이 증가) 예외가 발생하게 됩니다. 116 | 117 | - Perssimistic Lock (비관적 락) 118 | 119 | 낙관적 락과 반대로 트랜잭션의 출동이 발생한다고 가정하고 락을 겁니다. 120 | 121 | DB가 제공하는 락 기능을 사용합니다. 데이터를 수정 시 즉시 트랜잭션 충돌을 알 수 있습니다. 122 | 123 | 위에 설명한 Exclusive Lock과 Shared Lock이 포함됩니다. 124 | 125 | --- 126 | 127 | 예상 질문 128 | 129 | - 낙관적 락과 비관적 락에 대해서 알고 있는지? 130 | - X Lock(배타 락)과 S Lock(공유 락)의 차이 131 | - 데이터베이스의 Lock Level이란? 132 | - 어플리케이션에서 락을 거는 방법 (낙관적 락), DB단 에서 락을 거는 방법 (비관적 락) -------------------------------------------------------------------------------- /Database/README.md: -------------------------------------------------------------------------------- 1 | # 목차 2 | 3 | * SQL과 NoSQL 4 | * 트랜잭션 -------------------------------------------------------------------------------- /Database/images/transaction-status.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prgrms-web-devcourse/BE-Team-R-CS-Study/d0535ce8aeb0166acb1ef886b431ecf3d25e5cfa/Database/images/transaction-status.png -------------------------------------------------------------------------------- /DesignPattern/Singleton Pattern.md: -------------------------------------------------------------------------------- 1 | ## 1. 싱글톤 패턴이란? 2 | 3 | 시스템 런타임, 환경 세팅에 대한 정보 등, 인스턴스가 여러 개일때, 문제가 생길 수 있는 경우가 있다. 이 때, 인스턴스를 오직 한 개만 만들어 제공하는 클래스가 필요하다. 이 때, 싱글톤 패턴을 사용하게 된다. 4 | 5 | 싱글톤 패턴은 어떤 클래스를 애플리케이션 내에서 제한된 인스턴스 개수, 주로 하나만 존재하도록 강제하는 패턴이다. 이렇게 하나만 만들어지는 클래스의 오브젝트는 애플리케이션 내에서 전역적으로 접근이 가능하다. 6 | 7 | 따라서 단일 오브젝트만 존재해야 하고, 이를 애플리케이션의 여러 곳에서 공유하는 경우에 주로 사용한다. 8 | 9 | - 인스턴스를 오직 한 개만 제공 10 | - 밖에서 생성자를 만들수 없어야 하므로, private한 생성자를 생성 11 | - Global하게 매번 같은 객체에 접근할 수 있게 한다. 12 | 13 | ## 2. 싱글톤 패턴의 구현 방법 14 | 15 | ### 1) 가장 간단한 방법 16 | 17 | ```java 18 | public class Settings { 19 | 20 | private static Settings instance; 21 | 22 | private Settings(){} 23 | 24 | public static Settings getInstance(){ 25 | if (instance == null){ //thread2 26 | //thread1 27 | instance = new Settings(); 28 | } 29 | 30 | return instance; 31 | } 32 | } 33 | ``` 34 | 35 | 해당 방법은 멀티 쓰레드 환경에서 안전하지 않다는 단점이 있다. 36 | 37 | thread 1이 instance가 null임을 확인하고 블록 안에 들어왔고, 아직 객체를 만들지 않았을 때, thread 2 또한 instance가 null임을 확인하고 블록 안에 들어가는 경우가 생길 수 있다. 38 | 39 | 이 때, thread1, thread2 둘 다 new Settings()를 호출해서 두 쓰레드가 가지고 있는 객체가 서로 다르게 된다. 40 | 41 | ### 2) Synchronized 키워드 사용하기 42 | 43 | ```java 44 | public class Settings { 45 | 46 | private static Settings instance; 47 | 48 | private Settings(){} 49 | 50 | public static synchronized Settings getInstance(){ 51 | if (instance == null){ 52 | instance = new Settings(); 53 | } 54 | 55 | return instance; 56 | } 57 | } 58 | ``` 59 | 60 | 이 방법은 thread safe하지만, synchronized를 통해 동기화를 진행하면서 성능에 불이익이 생길 수 있다. 61 | 62 | ### 3) 이른 초기화 사용하기 (Eager Initialization) 63 | 64 | ```java 65 | public class Settings { 66 | 67 | //이른 초기화 68 | private static final Settings INSTANCE = new Settings(); 69 | 70 | private Settings(){} 71 | 72 | public static Settings getInstance(){ 73 | return INSTANCE; 74 | } 75 | } 76 | ``` 77 | 78 | 해당 방법도 thread safe하다. 대신, 인스턴스를 미리 만든다는 점이 단점이 될 수 있다. 79 | 80 | 해당 생성자를 만드는데 리소스가 많이 들어가고 메모리가 많이 소비되었는데, 해당 인스턴스를 한 번도 안쓰면 메모리 낭비가 되기 때문이다. 81 | 82 | ### 4) Double Checked Locking 사용하기 83 | 84 | ```java 85 | public class Settings { 86 | 87 | private static volatile Settings instance; 88 | 89 | private Settings(){} 90 | 91 | public static Settings getInstance(){ 92 | if (instance == null){ 93 | synchronized(Settings.class){ 94 | if (instance == null){ 95 | instance = new Settings(); 96 | } 97 | } 98 | } 99 | return instance; 100 | } 101 | } 102 | ``` 103 | 104 | - volatile : 해당 변수를 Main memory에 저장해서 다른 쓰레드에서 읽을 때에도 값이 같도록 함 105 | 106 | 해당 방법은 instance가 null일 때만 synchronized 블록 안에 들어가기 때문에 2번 방법보다는 더 효율적이다. 107 | 108 | 다만 복잡한게 단점이다. 109 | 110 | ### 5) static inner 클래스 사용하기 (권장하는 방법 중 하나) 111 | 112 | ```java 113 | public class Settings { 114 | private Settings(){} 115 | 116 | private static class SettingsHolder{ 117 | private static final Settings INSTANCE = new Settings(); 118 | } 119 | 120 | public static Settings getInstance(){ 121 | return SettingsHolder.INSTANCE; 122 | } 123 | } 124 | ``` 125 | 126 | 해당 방법이 가장 대표적이고 권장되는 방식이다. 127 | 128 | 해당 방법은 lazy loading이 가능하다는 장점이 있다. 129 | 130 | ## 3. Spring에서 Singleton을 사용하는 이유? 131 | 132 | 스프링은 대부분 서버환경에서 사용된다. 서버환경에는 여러가지 비즈니스 로직들이 있고 서버는 해당 비즈니스 로직을 담당하는 오브젝트들이 참여하는 계층형 구조로 이뤄진 경우가 대부분이다. 133 | 134 | 그런데 매번 클라이언트에서 요청이 올 때 마다 각 로직을 담당하는 오브젝트를 새로 만들어서 사용한다면 어떻게 될까? 135 | 136 | ex) 요청 한 번에 5개의 오브젝트가 새로 만들어지고 500개의 요청이 1초당 들어오게 된다면 초당 2500개의 오브젝트가 생성됨 137 | 138 | → 서버가 감당하기 힘든 부하가 걸리게 된다. 139 | 140 | **이러한 문제를 해결하고자 스프링은 빈을 싱글톤으로 관리하여 1개의 요청이 왔을 때 여러 쓰레드가 빈을 공유하도록 했다.** 141 | 142 | ## 4. 싱글톤 패턴의 한계 143 | 144 | - private 생성자를 갖고 있기 때문에 상속할 수 없다. 145 | - private 생성자를 가진 클래스는 다른 생성자가 없다면 상속이 불가능하다. 146 | - 싱글톤은 테스트하기가 힘들다. 147 | - 싱글톤은 만들어지는 방식이 제한적이기 때문에, Mock object 등으로 대체하기가 힘들고 직접 오브젝트를 만들어서 사용할 수밖에 없다. 148 | - 서버환경에서는 싱글톤이 하나만 만들어지는 것을 보장하지 못한다. 149 | - 서버에서는 클래스 로더의 구성에 따라 싱글톤 클래스임에도 하나 이상의 오브젝트가 만들어질 수 있다. 150 | - 싱글톤의 사용은 전역 상태를 만들 수 있기 때문에 바람직하지 못하다. 151 | - 싱글톤은 애플리케이션 어디든지 사용될 수 있기 때문에, 아무 객체나 자유롭게 접근하고 수정하고 공유할 수 있고, 이는 객체지향 프로그래밍에서는 권장되지 않는 방식이다. 152 | 153 | ### + 면접 질문 154 | 155 | - 싱글톤 패턴을 구현해보세요 (라이브 코딩) 156 | - 스프링에서 싱글톤 패턴을 사용하는 이유는 뭘까요? 157 | - 스프링에서 싱글톤 패턴이 기본값인데 프로토타입 스코프를 사용하는 경우는 어떤 경우일까요? 158 | -------------------------------------------------------------------------------- /Java/2022-04-01-jvm.md: -------------------------------------------------------------------------------- 1 | # 자바 가상 머신(Java Virtual Machine) 2 | 3 | ## 1. JVM 기능 4 | 5 | 1. JAVA와 OS사이에서 중개자 역할을 수행하여 JAVA가 OS에 구애받지 않고 재사용 가능하게 해준다. 6 | 2. 프로그램 메모리를 관리하고 최적화해준다. 7 | (Garbage Collection) 8 | 9 | ## 2. 자바프로그램 실행과정 10 | 11 | ![jvm](https://t1.daumcdn.net/cfile/tistory/25616D45576B854C3F) 12 | 13 | 1. 프로그램이 실행되면 JVM은 OS로부터 이 프로그램이 필요로 하는 메모리를 할당받는다. 14 | 2. 자바 컴파일러(javac)가 자바 소스코드(.java)를 읽어들여 자바 바이트코드(.class)로 변환시킨다 15 | (아직 컴퓨터가 읽을 수 없는 자바 가상 머신이 이해할 수 있는 코드) 16 | 3. 클래스 로더 17 | 동적로딩(Dynamic Loading)을 통해 필요한 클래스들을 로딩 및 링크하여 JVM의 메모리에 올린다. 18 | 4. 실행엔지(Execution Engine) 19 | JVM 메모리에 올라온 바이트 코드들을 명령어 단위로 하나씩 가져와서 실행합니다. 이때, 실행 엔진은 두가지 방식으로 해석된다 20 | 5. 해석된 바이트코드는 Runtime Data Areas에 배치되어 실질적인 수행이 이루어지게 된다. 21 | 22 | `이러한 실행과정 속에서 JVM은 필요에 따라 Thread Synchronization과 GC같은 관리작업을 수행한다.` 23 | 24 | ## 3. JVM 구성 25 | 26 | ### (1) Class Loader(클래스 로더) 27 | 28 | 클래스(.class 파일)를 JVM에 로드하고 메모리 영역에 배치하는 작업을 수행한다. 29 | 30 | 34 | 35 | - 로딩 36 | - .class 파일을 읽어서 클래스와 관련된 정보(FQCN, 클래스, 인터페이스, ENUM, 메소드, 변수)들을 JVM Memory 구조 중 메소드 영역에 저장 37 | - FQCN(Full Qualified Class Name) : 해당 클래스가 속해있는 패키지명을 모두 포함 한 정보 38 | - 링크 39 | - Verify(검증) → Prepare → Resolve 40 | - 검증 : 자바 언어 명세(Java Language Specification) 및 JVM 명세에 명시된 대로 구성되어 있는지 검사합니다. 41 | - 준비 : 클래스가 필요로 하는 메모리를 할당합니다. (필드, 메서드, 인터페이스 등등) 42 | - 분석 : 클래스의 상수 풀 내 모든 심볼릭 레퍼런스를 다이렉트 레퍼런스로 변경합니다. 43 | - 초기화 44 | - Static Variables 값을 할당 (**static 변수 초기화**) 45 | 46 | ### (2) Execution Engine(실행 엔진) 47 | 48 | 클래스를 실행시키는 역할. 49 | 바이트코드를 실제로 JVM내부에서 기계가 실행할 수 있는 형태로 변경한다. 50 | 두 가지 방식을 사용 51 | 52 | 1. Interpreter (인터프리터) 53 | - 바이트 코드 명령어를 하나씩 읽어서 해석하고 실행합니다. 54 | 하나하나의 실행은 빠르나, 전체적인 실행 속도가 느리다는 단점을 가집니다. 55 | 1. Just-In-Time Compiler (JIT 컴파일러) 56 | - 인터프리터의 단점을 보완하기 위해 도입된 방식 57 | - 인터프리터 방식으로 실행하다가 적절한 시점에 **바이트코드 전체를 컴파일하여 네이티브 코드**로 변경 58 | - 이후에는 해당 메서드를 더이상 인터프리팅 하지 않고, 바이너리 코드로 직접 실행하는 방식 59 | - 바이트 코드 전체가 컴파일된 바이너리 코드를 실행하는 것이기 때문에 전체적인 실행속도는 인터프리팅 방식보다 **빠릅니다**. 60 | 61 | ### (3) Runtime Date Areas 62 | 63 | - JVM이 운영체제 위에서 실행되면서 항당받는 메모리 영역 64 | - 총 5가지 영역으로 나누어진다. 65 | 66 | ![Runtime Date Areas](https://t1.daumcdn.net/cfile/tistory/992EE9465D08E9B903) 67 | 68 | - PC 레지스터 69 | 스레드가 어떤 명령어로 실행되어야 할지 기록하는 부분(JVM 명령의 주소를 가진다) 70 | - Stack 71 | 지역변수, 매개변수, 메서드 정보, 임시 데이터등을 저장 72 | - 네이티브 메서드 스택 73 | 실제 실행할 수 있는 기계어로 작성된 프로그램을 실행시키는 영역 74 | - 힙 75 | 런타임에 동적으로 할당되는 데이터가 저장되는 영역. 76 | - 객체나 배열 힙에 생성된다. 77 | - 힙에 할당된 데이터들은 가비지컬렉터의 대상이 된다. 78 | - 메서드 영역 (Method Area, Class Area, Static Area) 79 | - JVM이 시작될 때 생성되고, JVM이 읽은 각각의 클래스와 인터페이스에 대한 런타임 상수 풀, 필드 및 메서드 코드, 정적 변수, 메서드의 바이트 코드 등을 보관 80 | 81 | ### (4) Garbage Collection(가비지 컬렉션) 82 | 83 | - JVM이 프로그램 메모리 관리를 한다. 84 | - 가비지 컬렉션은 자바 프로그램에서 사용되지 않는 메모리를 지속적으로 찾아내서 제거하는 역할 85 | - 실행순서 86 | - 참조되지 않은 객체들을 탐색 후 삭제 87 | - 삭제된 객체의 메모리 반환 88 | - 힙 메모리 재사용 -------------------------------------------------------------------------------- /Java/2022-04-07-garbageCollection.md: -------------------------------------------------------------------------------- 1 | # GC(Garbage Collection) 2 | 3 | ## GC란? 4 | 5 | C, C++에서는 `free()`라는 메소드를 통해 할당된 메모리를 직접 해지 해줘야 합니다. 6 | 7 | 반면, 자바에서는 메모리 관리를 JVM에서 해주게 되는데 이를 위해 Garbage Collection을 사용합니다. 8 | 9 | GC는 JVM의 Heap 영역에서 사용하지 않는 객체를 삭제하는 프로세스를 말합니다. 10 | 11 | JVM의 힙(heap) 영역에는 Object 타입의 데이터들이 들어갑니다. (String, List, class 등) 12 | 13 | ## GC의 수거 대상: Reachability 14 | 15 | 그렇다면 GC는 어떻게 삭제할 객체와 아닌 객체를 ***구분***할까요? 16 | 17 | 우선, 이를 알아보기 전에 Unreachable Objects와 Reachable Objects에 대한 이해가 필요합니다. 18 | 19 | ```java 20 | public class Main { 21 | public static void main(String[] args) { 22 | Person person = new Person("a", "곧 참조되지 않음"); 23 | person = new Person("b", "참조가 유지됨"); 24 | //GC 발생 가정 시점 25 | } 26 | } 27 | 28 | //Person은 "name"과 "description"을 필드로 가지며, 생성자에서 차례대로 주입받게 됨. 29 | ``` 30 | 31 | 위의 코드를 보시면 person 처음에 "a"라는 이름을 가진 객체를 참조하게 됩니다. 32 | 33 | 하지만 바로 person이 "b"를 참조하게 되면서 "a"에 대한 참조를 잃어버리게 됩니다. 34 | 35 | 해당 main 함수가 종료되기 직전, GC가 발생한다고 가정해보면 "b"는 참조가 유지된 상태이지만 "a"는 참조되어있지 않은 상태이기 때문에 GC의 대상이 됩니다. 36 | 37 | 이처럼 ***참조되고 있는지***에 대한 개념을 reachability라고 하고, 참조된 상태를 reachable, 참조되지 않은 상태를 unreachable이라고 합니다. 38 | 39 | 즉, Unreachable Objects는 참조되지 않은 객체이며 Reachable Objects는 참조된 객체라고 볼 수 있습니다. 40 | 41 | 이제 다시 질문으로 돌아와서, GC는 어떻게 삭제할 객체와 아닌 객체를 ***구분***할까요? 42 | 43 | ![gc_root.png](images/gc_root.png) 44 | 45 | 사진과 같이 GC 루트에서부터 각각 참조하고 있는 객체들을 하나씩 하나씩 탐색해나갑니다. 46 | 47 | 그러면 참조된 객체들은 Reachable Objects, 참조되고 있지 않은 객체들을 Unreachable Objects 하다고 표현합니다. 이러한 Unreachable Objects가 GC의 수거 대상이 됩니다. 48 | 49 | 그렇다면 GC 루트가 될 수 있는 조건은 무엇일까요? 50 | 51 | JVM stack 영역의 지역변수나 파라미터들, 메소드 영역에 있는 static 데이터들, 자바 네이티브 인터페이스에 의해 생성된 객체들이 해당됩니다. 52 | 53 | ## GC의 동작 순서 54 | 55 | GC의 동작 순서는 다음과 같습니다. 56 | 57 | * Stop the world 58 | * Mark and Sweep, Compact 59 | 60 | ### Stop the world 61 | 62 | 우선 Stop the world에 대해 알아보자면, GC를 실행하기 위해 JVM이 어플리케이션 실행을 멈추는 것입니다. 63 | 64 | Stop the world가 발생하면 GC를 실행하는 쓰레드를 제외한 나머지 쓰레드들은 작업을 멈춥니다(stop). 65 | 66 | 그 후 GC 작업이 완료되면 중단했던 작업을 다시 시작합니다. 67 | 68 | stop the world가 실행되면 mark and sweep이라는 알고리즘이 작동하게 됩니다. 69 | 70 | ### Mark and Sweep, Compact 71 | 72 | ![mark.png](./images/mark.png) 73 | 74 | Mark는 GC 루트로부터 모든 변수를 스캔하면서 각각 어떤 객체를 참조하고 있는지 찾아서 마킹하는 과정입니다. 즉, 위에서 설명한 Reachable Objects와 Unreachable Objects를 식별하는 과정입니다. 75 | 76 | ![sweep.png](images/sweep.PNG) 77 | 78 | Sweep은 Unreachable Objects를 heap에서 제거하는 과정입니다. 79 | 80 | 그리고 알고리즘에 따라서 Compact 과정이 추가되기도 합니다. 81 | 82 | ![compact.png](images/compact.PNG) 83 | 84 | Compact는 Sweep 후 heap 영역에 듬성듬성 분산되어 남아 있는 객체들을 한 곳에 모아 메모리 단편화를 막아주는 작업입니다. 85 | 86 | 그래서 GC가 한번 수행될 때마다 Mark and Sweep, Compact 과정까지 한 사이클이 돌아가게 됩니다. 87 | 88 | ## heap 구조 89 | 90 | heap 영역에서 어떤 방식으로 GC가 발생하는지 heap 구조를 통해 세부적으로 알아봅시다. 91 | 92 | ![jvmheap.png](images/jvmheap.png) 93 | heap 영역은 크게 Young Generation과 Old Generation으로 나뉩니다. 94 | 95 | Young Generation은 새로운 객체들이 할당되는 영역이며 96 | 97 | Old Generation은 Young Generation에서 오랫동안 살아남은 객체들이 존재하는 영역입니다. 98 | 99 | 또한, Young Generation은 Eden, Survivor 0, Survivor 1로 나누어집니다. 100 | 101 | 이러한 heap 구조에서 GC가 언제 일어날까요? 102 | 103 | ## GC가 일어나는 경우 104 | 105 | GC는 Minor GC와 Major GC로 구분되는데요, 우선 Minor GC부터 알아보겠습니다. 106 | 107 | ![eden.png](images/eden.PNG) 108 | 109 | 새로운 객체가 Eden 영역에 할당이 됩니다. 그림과 같이 만약 더 이상 할당될 공간이 없다면 이때 Minor GC가 일어나게 되고 이때 Mark and Sweep이 발생하게 됩니다. 110 | 111 | ![minorgc.png](images/minorgc.PNG) 112 | 113 | 위 그림과 같이 Minor GC에서 살아남은 객체(파란색 박스)들은 Survivor 영역으로 이동합니다. 살아남지 못한 객체(하얀색 박스)들은 Sweep 과정을 통해 Eden 영역에서 삭제됩니다. 114 | 115 | ![minorgc2.png](images/minorgc2.PNG) 116 | 그 후 Survivor 영역에 있는 살아남은 객체들은 age 값이 1씩 증가합니다. 117 | 118 | 다시 Eden 영역이 꽉 차고 Minor GC가 발생하다 보면 Survivor 영역에 있는 객체의 age 값이 점점 증가하게 되겠죠? 119 | 120 | ![majorgc.png](images/majorgc.PNG) 121 | 이렇게 age 값이 증가하다가 객체의 age가 age threshold(임계점)에 도달하면 Old Generation으로 이동하게 됩니다. 122 | 123 | ![majorgc2.png](images/majorgc2.PNG) 124 | 이와 같은 과정을 반복하게 되어 Old generation이 꽉 차게 되면 Major GC가 발생하게 됩니다. 125 | 126 | ## Major GC와 Minor GC로 나누어진 이유 127 | 이렇게 나누어진 이유는 GC가 두 가지 가설하에 만들어졌기 때문인데요, 128 | 129 | * 대부분의 객체는 금방 접근 불가능 상태(unreachable)가 된다. (금방 garbage가 된다) 130 | * 오래된 객체에서 젊은 객체로의 참조는 아주 적게 존재한다. 131 | 132 | 그러므로 Minor GC는 매우 빈번하게 일어날 것이고, Major GC는 자주 일어나지도 않고, 일어나더라도 많은 객체가 정리되지 않기 때문에 분리했다고 볼 수 있습니다. 133 | 134 | ## 예상되는 질문 135 | * GC가 무엇인가요? 136 | * GC가 일어나는 이유에 관해 설명해주세요 137 | * GC 동작 과정에 대해 설명해주세요 138 | * GC가 Major GC와 Minor GC로 나뉜 이유가 무엇인가요 -------------------------------------------------------------------------------- /Java/2022-04-15-JavaThread.md: -------------------------------------------------------------------------------- 1 | # Java Thread, 동기화 2 | 3 | # Java에서 Thread 사용법 4 | 5 | ## Thread 클래스 상속 6 | 7 | ```java 8 | /** 9 | Thread module 기본 사용법 10 | **/ 11 | 12 | public class Sample extends Thread { 13 | @Override 14 | public void run() { // Thread 를 상속하면 run 메서드를 구현해야 한다. 15 | System.out.println("thread run."); 16 | } 17 | 18 | public static void main(String[] args) { 19 | Sample sample = new Sample(); 20 | sample.start(); // start()로 쓰레드를 실행한다. 21 | } 22 | } 23 | ``` 24 | 25 | - 기본적으로 run() 메서드를 Override 하고, start() 메서드를 이용하여 쓰레드를 실행한다. 26 | - 실제 start 메서드의 코드를 보면, start0라는 native method를 활용하여 context switching을 구현하고, start 메서드 내부에서는 단순히 현재 실행되고 있는 쓰레드들이 정상적으로 수행되고 있는지 판단 후 실행 중 쓰레드의 그룹에 넣어주는 행위만 수행하고 있다 27 | 28 | ```java 29 | /** 30 | Thread class 내 start 메소드 구현 31 | **/ 32 | public synchronized void start() { 33 | /** 34 | * This method is not invoked for the main method thread or "system" 35 | * group threads created/set up by the VM. Any new functionality added 36 | * to this method in the future may have to also be added to the VM. 37 | * 38 | * A zero status value corresponds to state "NEW". 39 | */ 40 | if (threadStatus != 0) 41 | throw new IllegalThreadStateException(); 42 | 43 | /* Notify the group that this thread is about to be started 44 | * so that it can be added to the group's list of threads 45 | * and the group's unstarted count can be decremented. */ 46 | group.add(this); 47 | 48 | boolean started = false; 49 | try { 50 | start0(); 51 | started = true; 52 | } finally { 53 | try { 54 | if (!started) { 55 | group.threadStartFailed(this); 56 | } 57 | } catch (Throwable ignore) { 58 | /* do nothing. If start0 threw a Throwable then 59 | it will be passed up the call stack */ 60 | } 61 | } 62 | } 63 | 64 | private native void start0(); 65 | ``` 66 | 67 | - run 메서드의 코드를 보면, Override를 위해 만들어진 코드 형태로 초기 실행 시 에러만 발생하지 않도록 핸들링해주고 있는 것을 볼 수 있다. 68 | 69 | ```java 70 | /** 71 | Thread class 내 run 메소드 구현 72 | **/ 73 | @Override 74 | public void run() { 75 | if (target != null) { 76 | target.run(); 77 | } 78 | } 79 | ``` 80 | 81 | - 결론적으로, Java에서는 jvm에서 thread의 context switching을 담당하고 있다. 82 | 83 | ## Runnable 인터페이스 구현 84 | 85 | ```java 86 | /** 87 | Runnable 인터페이스 기본 사용법 88 | **/ 89 | 90 | public class Sample implements Runnable { 91 | @Override 92 | public void run() { // run 메서드를 구현해야 한다. 93 | System.out.println("thread run."); 94 | } 95 | 96 | public static void main(String[] args) { 97 | Thread t = new Thread(new Sample()); // Runnable한 객체를 생성자로 받는 Thread 클래스를 생성한다 98 | t.start(); // start()로 쓰레드를 실행한다. 99 | } 100 | } 101 | ``` 102 | 103 | - 기본적인 사용법은 Thread 클래스와 동일하다. 하지만 인터페이스 형태로, run 메서드를 항상 구현해야 하고, Thread 해당 구현체를 Thread 객체의 생성자로 넣어 줌으로써 쓰레드를 생성할 수 있다. 104 | 105 | ```java 106 | /** 107 | Runnable한 객체를 이용한 Thread 생성 108 | **/ 109 | public Thread(Runnable target) { 110 | init(null, target, "Thread-" + nextThreadNum(), 0); 111 | } 112 | ``` 113 | 114 | - 여러 오버로딩된 생성자 중, 위의 생성자 형식을 활용했다고 볼 수 있다 115 | - 사용법은 거의 동일하지만, 인터페이스를 활용하기 때문에 상속 등에서 좀 더 유연하게 사용할 수 있다. 116 | 117 | ## run() 메서드 사용과 start()메서드 사용의 차이? 118 | 119 | - run()메서드를 사용할 때 120 | - 단순히 하나의 프로세스에서 쓰레드를 순차적으로 실행한다. 121 | - context switching이 발생하지 않는다. 122 | - start()메서드를 사용할 때 123 | - 위의 코드에서 볼 수 있듯, start0()라는 native 메서드를 활용하여 context switching 수행 124 | - JVM 내부에서 다수의 콜 스택을 번갈아가며 일처리를 수행하고, 동시에 작업하는 것처럼 보여 주는 것 125 | - 위의 두 구현 방법 모두에 해당한다 126 | 127 | # JAVA에서의 쓰레드 생명 주기 128 | 129 | ![thread-lifecycle](images/threadLifeCycle.jpg) 130 | 131 | 출처 : GeeksforGeeks 132 | 133 | - 총 6가지의 lifecycle이 존재한다. 134 | - 다양하게 표현되어 있고, Running을 표현하는 경우도 있지만, 실제로 Java 구현체를 확인해 보면 위와 같은 형태로, Thread.State라는 enum 클래스 형태로 구현되어 있다. 135 | 136 | ```java 137 | public enum State { 138 | NEW, 139 | RUNNABLE, 140 | BLOCKED, 141 | WAITING, 142 | TIMED_WAITING, 143 | TERMINATED; 144 | } 145 | ``` 146 | 147 | - NEW : 쓰레드가 처음 생성되고, 아직 시작되지 않은 상태 148 | - RUNNABLE : 실행 가능한 상태로, JVM 내에서는 실행 중이지만 프로세서와 같은 다른 리소스를 기다리고 있는 상태, 지속적으로 컨텍스트 스위칭이 일어날 수 있는 상태 149 | - BLOCKED : 모니터의 lock으로 인해 멈춰 있는 상태로, synchronized 상태의 블록이나 메소드에 진입하고자 할 때 다른 스레드들이 얻는 상태 → busy-waiting 150 | - WAITING : 대기 중인 스레드 상태로, 시간 초과가 존재하지 않는 wait()이나 join()을 활용하여 대기 중인 상태. notify()나 notifyAll()을 이용하여 깨워 줄 수 있음 → block-wakeup 151 | - TIMED_WAITING : 시간 제한이 존재하는 대기 상태로, sleep()이나 timeout이 존재하는 wait, join을 이용하여 대기 중인 상태 152 | - TERMINATED : 스레드의 실행이 완료된 상태 153 | 154 | # Java에서의 동기화 방법 155 | 156 | - 기본적으로 Java에서는 고수준의 Monitor와 같은 병행성 기법을 제공하고 있음 157 | 158 | ## synchronized 키워드 159 | 160 | - 객체 중심의 언어인 Java에서는 모든 객체가 모니터를 갖고 있음 → synchronized 이용 161 | - synchronized method 162 | - 해당 메서드가 존재하는 객체 인스턴스와 연결된 락 방법 163 | - 다른 스레드가 락을 소유한 경우 해당 메소드를 호출한 스레드는 BLOCKED 상태가 되고, 객체의 락에 존재하는 entry set에 추가됨 164 | - 스레드가 메소드를 종료하면 해당 객체에 대한 락이 해제 165 | 166 | ```java 167 | public class SynchronizedCounter { 168 | private int c = 0; 169 | 170 | public synchronized void increment() { 171 | c++; 172 | } 173 | 174 | public synchronized void decrement() { 175 | c--; 176 | } 177 | 178 | public synchronized int value() { 179 | return c; 180 | } 181 | } 182 | // 출처 : oracle java docs 183 | ``` 184 | 185 | - synchronized + wait + notify 186 | - 스레드가 락 문제가 아닌, 자원 등의 문제로 인해 대기해야 할수도 있음 187 | ex) 유한 버퍼에서 버퍼가 꽉 찬 경우 188 | → wait() 호출을 통해 락을 해제하고 조건이 충족될 때까지 기다림(WAITING 상태로 wait set에 추가) 189 | - 결론적으로 아래와 같은 그림 형태의 set으로 대기 190 | 191 | ![java-entry-wait-set](images/java-entry-wait-set.png) 192 | 193 | 출처 : Operating System Concepts(공룡책) 194 | 195 | - 일반적인 synchronized 메소드 종료 시, 이탈 스레드는 객체에 대한 락을 해제함으로써 entry set의 스레드에게 소유권을 넘겨줌 196 | - 그러나 특정 스레드가 synchronized 메소드 내부에서 notify() 호출을 수행하면 다른 일이 발생 197 | 1. wait set에서 스레드 선택 198 | 2. 해당 스레드를 entry set으로 이동 후 RUNNABLE 상태로 변경 199 | - synchronized block 200 | - 락의 획득과 해제 시점 → lock scope 201 | - 메소드 단위로 사용하면 lock scope가 너무 커질 수 있음 202 | - 메소드 내의 특정 코드 블록만 동기화 가능 203 | - 동일하게 해당 객체에 대한 객체 락 소유권 필요 204 | 205 | ```java 206 | // 자신 객체에 대한 synchronized block 207 | public void addName(String name) { 208 | synchronized(this) { 209 | lastName = name; 210 | nameCount++; 211 | } 212 | nameList.add(name); 213 | } 214 | 215 | // 별도 객체에 대한 synchronized block 설정도 가능 216 | public class MsLunch { 217 | private long c1 = 0; 218 | private long c2 = 0; 219 | private Object lock1 = new Object(); 220 | private Object lock2 = new Object(); 221 | 222 | public void inc1() { 223 | synchronized(lock1) { 224 | c1++; 225 | } 226 | } 227 | 228 | public void inc2() { 229 | synchronized(lock2) { 230 | c2++; 231 | } 232 | } 233 | } 234 | 235 | // 출처 : oracle java docs 236 | ``` 237 | 238 | 239 | ## volatile 키워드 240 | 241 | - 읽기, 쓰기의 경우 기본적으로 atomic함(long, double형 제외) 242 | (읽기+쓰기는 atomic한 행위 2회이므로 atomic하지 않음) 243 | - volatile 키워드를 사용하면 long, double 형도 atomic하게 읽고 쓸 수 있음 244 | - long, double primitive 형은 64비트 형태이기 때문에, 32비트씩 나누어서 읽어들이기 때문 245 | - java의 volatile 키워드는 즉각적으로 메인 메모리에 쓰거나 읽어오는 것을 보장하고, 가시성을 보장하는 키워드 246 | - 한 쓰레드에서만 쓰기 작업, 다른 쓰레드는 읽기 작업만 할 때 안전성 보장 247 | - 두 쓰레드가 동시에 쓰기 작업에 들어간다면 동시성 문제가 발생할 수 있음 248 | 249 | ## High Level Concurrency Objects 250 | 251 | ### Reentrant Lock 252 | 253 | - 단일 스레드가 소유하며 공유 자원에 대한 상호 배타적 액세스 제공 254 | - 공정성 매개변수 등의 추가 기능 제공 → 오래 기다린 스레드에 락 제공하는 기능 255 | 256 | ### Semaphore 257 | 258 | - 카운팅 세마포어 제공 259 | - acquire와 release를 통해 인터럽트를 방어함 260 | - 락을 획득하려는 스레드가 인터럽트 되는 경우 acquire() 메소드가 InterruptedException을 발생 261 | 262 | ### Condition Variable 263 | 264 | - wait(), notify()메소드와 유사한 기능을 제공 265 | - ReentrantLock과 연계하여 사용 266 | - await()과 signal() 메소드를 활용 267 | - wait(), notify()와 다른 점은 스레드 번호를 통해 어떤 스레드가 signal 신호를 받을지 지정할 수 있다는 점 268 | 269 | ### Atomic Variable 270 | 271 | - 원자성을 보장해 주는 변수 272 | - synchronized 키워드 없이 동기화 문제 해결 273 | - CAS 알고리즘 활용 274 | * CAS(Compare-And-Swap) : 비교한 뒤 바꿔주는 것, 스레드에 저장된 값과 메인 메모리에 저장된 값을 비교하여 값이 같다면 새로운 값으로 치환해 준다. 275 | - 내부에 존재하는 여러 메소드들을 활용하여 원자성을 보장하는 연산을 수행할 수 있음 276 | - 동시에 쓰기 작업에 들어가는 경우에도 원자성을 보장 277 | 278 | ### Concurrent Collections 279 | 280 | - 스레드 동시성을 보장해 주는 컬렉션 객체 281 | - BlockingQueue, ConcurrentMap, ConcurrentNavigationMap 등의 다양한 동기화를 제공하는 Collections 객체들이 존재 282 | 283 | 참고문헌 284 | 285 | [https://docs.oracle.com/javase/tutorial/essential/concurrency/index.html](https://docs.oracle.com/javase/tutorial/essential/concurrency/index.html) 286 | 287 | [https://stackoverflow.com/questions/34387242/why-using-volatile-makes-long-and-double-atomic](https://stackoverflow.com/questions/34387242/why-using-volatile-makes-long-and-double-atomic) 288 | 289 | [https://docs.oracle.com/javase/8/docs/api/java/util/concurrent](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent) -------------------------------------------------------------------------------- /Java/2022-04-22-Generic.md: -------------------------------------------------------------------------------- 1 | # Generic 2 | 3 | ## Q . Generic 이란? 4 | 데이터 타입(Data type)을 일반화한다(generalize) 5 | 6 | 7 | 8 | 클래스, 또는 메소드에서 사용할 내부 데이터 타입을 클래스 작성 시가 아닌 컴파일 시에 지정하는 방법 9 | 10 | 클래스 내부가 아닌, 외부에서 인스턴스를 생성할 때 사용자에 의하여 타입이 지정됨 11 | 12 |
13 | 14 | ## Q . Generic type 의 장점 15 | 16 | - `안정성` 을 맡음. 17 | 18 | 객체의 타입을 컴파일 시에 체크하기에, 타입 안정성을 높이고 19 | 20 | 형변환을 할 필요가 없어 코드가 간결해 지고, 프로그램 성능이 향상됨 21 | 22 |
23 | 24 | 25 | ## Q . Object 대신 Generic을 사용하는 이유는? 26 | JDK 1.5 이전 버전에서는 Generic 대신 Object 타입을 이용함. 27 | 28 | - Object 사용 29 | 30 | ``` 31 | List list = new ArrayList(); 32 | list.add("hello"); //String 33 | list.add(100); //Integer 34 | 35 | //형변환 36 | String s = (String) list.get(0); 37 | Integer a = (Integer) list.get(1); 38 | 39 | //ClassCastException 40 | String a = (String) list.get(1); 41 | ``` 42 | 43 | **문제점** : 위와 같이 ClassCastException 가 발생할 수 있는 가능성이 있다. 44 | 45 | 46 |
47 | 48 | 49 | 50 | - Generic 사용 51 | ``` 52 | List list = new ArrayList(); 53 | list.add("hello"); 54 | String s = list.get(0); // no cast 55 | ``` 56 | 57 | 코드가 간결해지고, 형변환 코드가 요구되지 않음 58 | 59 | 60 | 61 | 62 | 63 | => 제네릭의 사용으로 예외 발생의 위험이 줄어들고, 코드가 간결해지는 안정성 생김 64 | 65 |
66 | 67 | ## 매개변수화 타입(Parameterized type) 68 | 69 | ``` 70 | //ArrayList.java 71 | 72 | public class ArrayList extends AbstractList 73 | implements List, RandomAccess, Cloneable, java.io.Serializable{ 74 | 75 | ... 76 | 77 | public E get(int index) { 78 | Objects.checkIndex(index, size); 79 | return elementData(index); 80 | } 81 | ``` 82 | 83 | 타입 파라미터 E를 이용하여 ArrayList 클래스를 설계할 때 리스트의 원소에 대한 타입을 지정하지 않음. 84 | 85 | 아래 구현된 get() 메소드에서도 반환 타입으로 E가 지정되어 있는 것을 볼 수 있음 86 | 87 |
88 | 89 | 90 | 이렇게 설계된 클래스를 사용할 때 91 | 92 | ``` 93 | ArryList stringList=new ArrayList<>(); 94 | ... 95 | String returnValue = stringList.get(1); 96 | ``` 97 | 98 | 위와 같이 인스턴스 생성 시 String 이라는 구체적인 타입을 지정함 99 | 100 | get() 메소드를 사용할 때에도 따로 형변환을 할 필요가 없이 그대로 사용하고 있음을 볼 수 있음 101 | 102 | 103 | 104 |
105 | 106 | 107 | ### 여러 가지 타입 변수 108 | 109 | |타입 변수|설명| 110 | |---|---| 111 | |T|Type| 112 | |E|Element| 113 | |K|Key| 114 | |N|Number| 115 | |V|Value| 116 | |R|Result| 117 | 118 |
119 | 120 | ## 제네릭 와일드 카드 121 | 어떤 용도로도 쓰일 수 있는 기호 122 | 123 | 위의 타입들을 모두 아우르는 사용 124 | 125 | 126 |
127 |
128 | 129 | `` 130 | 131 | 타입 변수 자체를 대치하는 것. 132 | 133 | 모든 클래스, 인터페이스 타입이 올 수 있음 134 | 135 | 136 | 137 | ### 한정적 타입(Bounded Type) 138 | 139 | 타입 변수들은 바운드(bound)될 수 있음. (제한) 140 | 141 | 받을 수 있는 타입들이 제한될 수 있음 142 | 143 | 144 | 145 | `` 146 | 147 | E 객체의 하위 클래스(서브 클래스)만 올 수 있다.(자신 포함) 148 | 149 | ``` 150 | //HashMap.java 151 | public HashMap(Map m) { 152 | this.loadFactor = DEFAULT_LOAD_FACTOR; 153 | putMapEntries(m, false); 154 | } 155 | ``` 156 | 157 | - HashMap의 생성자 부분 코드 158 | 159 | 인자로 넣어지는 Map 객체의 ?(Key), ?(Value) 의 객체 타입이 제한되고 있는 것을 볼 수 있음. 160 | 161 | 162 | 163 | IF) 164 | 165 | `HashMap hashMap=new HashMap(map);` 166 | 167 | -> map의 Key, Value 타입은 String 타입이거나 그의 서브 클래스 타입으로 제한된다는 의미 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | `` 176 | 177 | E 객체의 상위 클래스(부모 클래스)만 올 수 있다.(자신 포함) 178 | 179 | 180 |
181 | 182 | ## Q . 제네릭을 사용할 수 없는 경우는? 183 | **new** 184 | 185 | ex) `int arr[]= new int[10];` 186 | 187 | 188 | 189 | - heap 영역에 메모리를 할당함 190 | 191 | -> 메모리를 할당하기 위해서는 타입을 알아야 하지만 192 | 193 | heap에 메모리가 할당되는 시점(프로그램 실행 시)에서는 타입 T가 무엇인지를 알 수 없음 194 | 195 | 196 | 197 |
198 | 199 | **static ** 200 | 201 | 타입 T는 인스턴스 생성 시 어떤 타입인지 결정됨. 202 | 203 | -> 모든 객체에 대하여 동일하게 동작해야 하는 static에 타입 변수 T를 사용할 수 없음. 204 | 205 | 206 | 207 | 208 |
209 | 210 | 211 | ## Q . 제네릭이 하위 버전(JDK 1.5 이전)과 호환되어 동작될 수 있는 이유는? 212 | - 제네릭 코드의 제거 시기와 연관 213 | 제너릭 타입 T의 타입이 결정되는 시기 => 컴파일 시점 214 | 215 | 컴파일 시 컴파일러에 의해 자동으로 검사되어 타입 변환됨. 216 | 217 | 218 | 219 | => 코드 내의 모든 제네릭 타입은 제거되고, 컴파일된 class 파일에는 어떠한 제네릭 타입도 포함되지 x (자동으로 형변환 코드 추가) 220 | 221 | 222 | 223 | ==> 제너릭이 사용되지 않는 이전 버전과도 호환 가능 224 | 225 |
226 | 227 | 228 | ## Reference 229 | https://docs.oracle.com/javase/tutorial/java/generics/why.html 230 | 231 | https://dev-coco.tistory.com/28 232 | -------------------------------------------------------------------------------- /Java/2022-04-29-final, 불변 객체.md: -------------------------------------------------------------------------------- 1 | ## 1. Java에서의 final 2 | 3 | - final : 최종적이라는 뜻 4 | - 한 번만 할당 가능하다 5 | 6 | → 해당 선언이 최종 상태이고, 결코 수정될 수 없음을 뜻함 7 | 8 | → 즉, 재할당하려고 하면 컴파일 오류가 발생하여 바로 확인이 가능하다. 9 | 10 | - final 키워드는 클래스, 필드, 메소드 선언 시에 사용할 수 있다. 11 | 12 | → 어느 선언에 사용되느냐에 따라서 의미가 조금씩 달라진다. 13 | 14 |
15 | 16 | ## 2. final을 사용하는 이유? 17 | 18 | - 값에 대한 검증이 필요하지 않다 → 로직 구현에 집중 19 | - 서비스 안정성이 높아짐 20 | - 버그 발생 가능성이 줄어든다. 21 | - 버그를 찾는 시점이 빨라짐 (컴파일 타임에 확인 가능) 22 | - 코드 품질이 높아져 변화에 좀 더 빠르게 대응할 수 있다. 23 | 24 |
25 | 26 | ## 3. final 필드와 상수 27 | 28 | - final 필드 = 최종적인 필드 29 | - final 필드는 초기값이 저장되면 해당 값이 최종적인 값이 되어서 프로그램 실행 도중에 수정할 수 없다는 것 30 | 31 | ```java 32 | final 타입 필드 [= 초기값]; 33 | ``` 34 | 35 |
36 | 37 | ### (1) final 필드의 초기값을 줄 수 있는 방법 38 | 39 | final 필드의 초기값을 줄 수 있는 방법은 딱 두 가지 뿐이다. 40 | 41 | - 필드 선언시에 주는 방법 : 단순 값인 경우 42 | 43 | ```java 44 | final String name = "Ella"; 45 | ``` 46 | 47 | - 생성자에서 주는 방법 48 | - 복잡한 초기화 코드가 필요하거나 객체 생성시에 외부 데이터로 초기화 해야 하는 경우 49 | - 만약에 생성자에서 모든 final 필드를 초기화 하지 않으면 컴파일 에러가 발생함 50 | 51 | ```java 52 | public class Person{ 53 | final String name; 54 | public Person(String name){ 55 | this.name = name; 56 | } 57 | } 58 | ``` 59 | 60 |
61 | 62 | ## 4. final 클래스 63 | 64 | - class 앞에 final 키워드를 붙이게 되면, 이 클래스는 최종적인 클래스이므로 상속할 수 없는 클래스가 된다. 65 | 66 | → 즉, final 클래스를 부모로 갖는 자식 클래스는 만들 수 없다. 67 | 68 | 69 | ```java 70 | public final class 클래스 { ... } 71 | ``` 72 | 73 | - Java 표준 API에서 제공하는 String 클래스가 대표적인 final 클래스이다. 74 | 75 | → 따라서, String 클래스를 상속하는 자식 클래스를 만들 수 없다. 76 | 77 |
78 | 79 | 80 | ## 5. final 메소드 81 | 82 | - 메소드를 선언할 때, final 키워드를 붙이게 되면, 이 메소드는 최종적인 메소드이므로 오버라이딩을 할 수 없는 메소드가 된다. 83 | 84 | → 즉, 부모 클래스를 상속해서 자식 클래스를 선언할 때, 부모 클래스에 선언된 final 메소드는 자식 클래스에서 재정의 할 수 없다 85 | 86 | 87 | ```java 88 | //부모 클래스 89 | public class Car{ 90 | public int speed; 91 | 92 | public void speedUp() { speed += 1; } 93 | public final void stop(){ 94 | System.out.println("차를 멈춤"); 95 | speed = 0; 96 | } 97 | } 98 | ``` 99 | 100 | ```java 101 | //자식 클래스 102 | public class SportsCar extends Car{ 103 | @Override 104 | public void speedUp(){ speed += 10;} 105 | // stop()은 오버라이딩 불가능 106 | } 107 | ``` 108 | 109 |
110 | 111 | ## 6. finally 블록 112 | 113 | finally 블록은 try-catch-finally 블록의 finally 블록을 말한다. 114 | 115 | 즉, 예외 발생 여부와 상관없이 항상 실행할 내용이 있을 경우에 finally 블록을 사용한다. 116 | 117 | finally 블록은 다음과 같은 경우에 실행되지 않는다. 118 | 119 | - try/catch 블록 수행 중에 가상 머신이 종료됨 120 | - try/catch를 수행하고 있던 스레드가 죽어버림 121 | 122 | - **자바의 finally 블록은 try-catch-finally의 try블록 안에 return문을 넣어도 실행되는가?** 123 | - Answer 124 | 125 | 실행된다. finally 블록은 try 블록이 종료되는 순간 실행된다. try 블록에서 벗어나려고 해도(return, continue, break 혹은 exception을 통해서), finally 블록은 실행될 것이다. 126 | 127 | 128 |
129 | 130 | ## 7. finalize() 131 | 132 | 참조하지 않는 객체는 GC가 힙 영역에서 자동적으로 소멸시키는데, GC는 객체를 소멸하기 직전에 마지막으로 객체의 소멸자인 finalize()를 실행시킨다. 133 | 134 | finalize() 메소드는 Object 클래스에 존재하며, 기본적으로 실행 내용이 없다. 135 | 136 | 만약 객체가 소멸되기 전에 특정한 일을 수행하게 만들고 싶다면, Object의 finalize()를 재정의하면 된다. 137 | 138 | ```java 139 | public class Counter{ 140 | private int no; 141 | public Counter(int no){ 142 | this.no = no; 143 | } 144 | @Overrride 145 | protected void finalize() throws Throwable{ 146 | System.out.println(no + "번 객체의 finalize()가 실행됨"); 147 | } 148 | } 149 | ``` 150 | 151 | GC가 실행시키는 메소드이므로 finalize() 메소드가 호출되는 시점을 명확하지 않다. 152 | 153 | → 프로그램이 종료될 때, 즉시 자원을 해제하거나 즉시 데이터를 최종 저장해야 한다면, 일반 메소드에서 작성하고 프로그램이 종료될 때 명시적으로 메소드를 호출하는 것이 좋다. 154 | 155 | 명시적으로 finalize()를 호출하는 2가지 메소드가 있다. 156 | 157 | - System.gc() 158 | - GC 수행을 명령하는 메소드 159 | - GC가 발생하면, 소멸의 대사이 되는 인스턴스는 결정되지만, 이것이 실제 소멸로 바로 이어지지 않고, 인스턴스의 실제 소멸로 이어지지 않는 상태에서 프로그램이 종료될 수도 있다. 160 | 161 | → 종료가 되면 어차피 인스턴스는 소멸되기 때문 162 | 163 | - System.runFinalization() 164 | - GC에 의해서 소멸이 결정된 인스턴스를 즉시 소멸시키는 메소드 165 | 166 |
167 | 168 | ## 8. 불변 객체란? 169 | 170 | - 한 번 생성되면 상태를 수정할 수 없는 객체 171 | 172 | → 생성이 된 불변 객체는 신뢰할 수 있다. 173 | 174 | 175 | - 가변 객체로 사용하는 경우, 멀티쓰레드에 의해 로직에는 문제가 없어도 값이 예상과 다르게 나올 수 있다. 176 | 177 | → 스레드 동기화 문제 178 | 179 | → 불변 객체를 통해 스레드 동기화 문제 방지 가능 180 | 181 | - 불변 객체는 가변 객체보다 설계하고 구현하고 사용하기 쉬우며, 오류가 생길 여지도 적고 훨씬 안전함 182 | 183 | - 불변 객체를 사용하는 경우 객체가 가지는 값마다 새로운 객체가 필요하다. 따라서 메모리 누수와 새로운 객체를 계속 생성해야하기 때문에 성능 저하를 발생시킬 수 있다. 184 | 185 |
186 | 187 | ## 9. 불변객체 만들기 188 | 189 | 불변 객체를 만드는 기본적인 아이디어는 필드에 final을 사용하고, Setter를 구현하지 않는 것이지만, 불변 객체의 필드 중 참조 타입이 있는 경우엔 추가적인 작업이 필요하다. 190 | 191 |
192 | 193 | ### (1) 원시 타입만 있는 불변 객체 194 | 195 | final 키워드를 사용한다. 196 | 197 | final 필드만 있기 때문에, 당연히 setter는 구현할 수 없다. 198 | 199 | ```java 200 | public class ExampleObject{ 201 | private final int value; 202 | public ExampleObject(final int value){ 203 | this.value = value; 204 | } 205 | } 206 | ``` 207 | 208 |
209 | 210 | ### (2) 참조 타입이 있는 불변 객체 211 | 212 | 참조 타입이 있는 경우에는 단순히 final 키워드를 사용하고, Setter를 작성하지 않는 것으로는 불변 객체를 만들 수 없다. 213 | 214 | 불변 객체의 참조 변수 또한 불변이어야 한다. 참조 변수가 일반 객체인 경우는 참조 변수도 불변 객체로 만들면 되지만, Java에서 제공하는 객체 타입을 사용하는 경우는 어떻게 해야할까? 215 | 216 | - 참조 변수가 일반 객체인 경우 217 | 218 | ```java 219 | public class Animal { 220 | private final Age age; 221 | 222 | public Animal(final Age age) { 223 | this.age = age; 224 | } 225 | } 226 | 227 | //참조 변수도 불변 객체로 만들기 228 | class Age { 229 | private final int value; 230 | 231 | public Age(final int value) { 232 | this.value = value; 233 | } 234 | } 235 | ``` 236 | 237 | - Java가 제공하는 Array를 사용할 경우 238 | 239 | ```java 240 | public class ArrayObject { 241 | 242 | private final int[] array; 243 | 244 | //전달받는 array를 그대로 array에 할당하는 것이 아닌 복사본을 할당한다 245 | //-> 외부에서 변경될 가능성이 있기 때문 246 | public ArrayObject(final int[] array) { 247 | this.array = Arrays.copyOf(array,array.length); 248 | } 249 | 250 | //array field를 그대로 리턴하는 것이 아닌 복사본을 리턴한다 251 | //-> 외부에서 변경될 가능성이 있기 때문 252 | public int[] getArray() { 253 | return (array == null) ? null : array.clone(); 254 | } 255 | } 256 | ``` 257 | -------------------------------------------------------------------------------- /Java/2022-05-10-reflection.md: -------------------------------------------------------------------------------- 1 | ## 1. Reflection이란? 2 | 3 | 7 | 8 | - 컴파일 시간 (Compile Time)이 아니라 **실행 시간(Run Time)**에 동적으로 특정 클래스의 정보를 객체화를 통해 분석 및 추출해낼 수 있는 프로그래밍 기법이다. 9 | - 자바에서 이미 로딩이 완료된 클래스에서 (JVM위에 올라감) 또 다른 클래스를 동적으로 로딩(Dynamic Loading)하여 생성자(Constructor), 멤버 필드(Member Variables) 그리고 멤버 메서드(Member Method) 등을 사용할 수 있는 기법 10 | 11 | ### “구체적인 클래스 타입을 알지 못해도” 12 | 13 | ⇒ 구체적인 클래스 타입을 알지 못해도, 클래스 정보에 접근이 가능하다는 것이 무슨 뜻인지 알아보자. 14 | 15 | ### Example 16 | 17 | ```java 18 | public class Customer { 19 | private String name; 20 | private int number; 21 | 22 | public Customer() { 23 | } 24 | 25 | public Customer(String name, int number) { 26 | this.name = name; 27 | this.number = number; 28 | } 29 | 30 | public void printIndex() { 31 | System.out.println("Reflection"); 32 | } 33 | 34 | private void printHello() { 35 | System.out.println("hello world"); 36 | } 37 | } 38 | ``` 39 | 40 | ```java 41 | public static void main(String[] args) { 42 | Object obj = new Customer("CHOI", 1); 43 | obj.printIndex(); // 컴파일 에러 44 | } 45 | ``` 46 | 47 | - 자바는 컴파일러를 사용한다. 즉 컴파일 타임에 타입이 결정된다. 48 | - obj라는 이름의 객체는 컴파일 타임에 Object로 타입이 결정됐기 때문에 Object 클래스의 인스턴스 변수와 메서드만 사용할 수 있다. 49 | - 생성된 obj라는 객체는 **Object 클래스라는 타입**만 알 뿐, Customer 클래스라는 **구체적인 타입을 모른다**. 50 | 51 | > 결국 컴파일러가 있는 자바는 구체적인 클래스를 모르면 해당 클래스의 정보에 접근할 수 없다는 것을 알 수 있다. 52 | ⇒ Reflection **구체적인 클래스 타입을 알지 못해도 클래스 정보에 접근**할 수 있게 해준다. 53 | > 54 | 55 | ### Relection 사용해서 접근 56 | 57 | ```java 58 | public static void main(String[] args) throws Exception { 59 | Object obj = new Customer("CHOI", 1); 60 | Class customerClass = Customer.class; 61 | // Class customerClass = Class.forName("devcourse.reflection.Customer"); 62 | Method printIndex = customerClass.getMethod("printIndex"); 63 | printIndex.invoke(obj); // invoke(메서드를 실행시킬 객체) 64 | 65 | // Reflection 출력 66 | 67 | } 68 | ``` 69 | 70 | - obj라는 객체는 Object 클래스라는 타입이지만 Customer 클래스의 printIndex 메서드에 접근하고 실행시킬 수 있다. 71 | 72 | ## 2. Reflection의 클래스 정보 접근 73 | 74 | ### 클래스에 선언된 생성자, 메서드, 필드 75 | 76 | ```java 77 | public static void main(String[] args) throws Exception { 78 | 79 | Class customerClass = Class.forName("devcourse.reflection.Customer"); 80 | 81 | // 클래스 내 선언된 메서드의 목록 출력 82 | Constructor[] constructors = customerClass.getConstructors(); 83 | for (Constructor constructor : constructors) { 84 | System.out.println(constructor.toString()); 85 | 86 | } 87 | /* 88 | public devcourse.reflection.Customer() 89 | public devcourse.reflection.Customer(java.lang.String,int) 90 | */ 91 | System.out.println(); 92 | 93 | // 클래스 내 선언된 메서드의 목록 출력 94 | Method[] methods = customerClass.getDeclaredMethods(); 95 | for (Method method : methods) { 96 | System.out.println(method.toString()); 97 | } 98 | /* 99 | public void devcourse.reflection.Customer.printIndex() 100 | private void devcourse.reflection.Customer.printHello() 101 | */ 102 | System.out.println(); 103 | 104 | // 클래스 내 선언된 필드의 목록 출력 105 | Field[] fields = customerClass.getDeclaredFields(); 106 | for (Field field : fields) { 107 | System.out.println(field.toString()); 108 | } 109 | /* 110 | private java.lang.String devcourse.reflection.Customer.name 111 | private int devcourse.reflection.Customer.number 112 | */ 113 | } 114 | ``` 115 | 116 | > **getMethods VS getDeclaredMethods** 117 | getMethods 118 | public 접근지정자 메서드만 접근 가능하다. 119 | getDeclaredMethods 120 | 접근지정자와 상관없이 class 안의 모든 메서드에 접근 가능하다. 121 | > 122 | 123 | ### Reflection을 이용해서 Private 필드, 메서드 접근 124 | 125 | ```java 126 | // private field, method 접근 127 | public static void main(String[] args) throws Exception { 128 | Class myClass = Class.forName("devcourse.reflection.Customer"); 129 | 130 | Constructor constructor = myClass.getConstructor(); // 기본 생성자 사용 131 | Customer customer = (Customer) constructor.newInstance(); 132 | 133 | Field field = myClass.getDeclaredField("name"); 134 | field.setAccessible(true); 135 | field.set(customer, "CHOI"); 136 | System.out.println(field.get(customer)); 137 | // CHOI 출력 138 | 139 | Method printHello = myClass.getDeclaredMethod("printHello"); 140 | printHello.setAccessible(true); 141 | printHello.invoke(customer); 142 | // hello world 출력 143 | } 144 | ``` 145 | 146 | - 기본 생성자만 있다면 setter, getter 없어도 심지어 private 변수와 메서드에도 접근가능하다. 147 | 148 | ## 3. Reflection 원리 149 | 150 | 자바에서는 JVM이 실행되면 사용자가 작성한 자바 코드가 컴파일러를 거쳐 바이트 코드로 변환되어 static 영역에 저장된다. 151 | 152 | Reflection API는 이 정보를 활용한다. 153 | 154 | 그래서 클래스 이름만 알고 있다면 언제든 static 영역을 뒤져서 정보를 가져올 수 있다. 155 | 156 | ## 4. Reflection의 단점 157 | 158 | - 성능 오버헤드 159 | - 컴파일 타임이 아닌 런타임에 동적으로 타입을 분석하고 정보를 가져오므로 JVM을 최적화 할 수 없다. 160 | - 추상화 161 | - 직접 접근할 수 없는 private 인스턴스 변수, 메서드에 접근하기 때문에 내부를 노출하면서 추상화가 깨진다. 162 | 163 | > 애플리케이션 개발보다는 프레임워크나 라이브러리에서 많이 사용된다. 164 | 어떤 클래스를 만들지 예측할 수 없기 때문에 동적으로 해결해주기 위해 Reflection을 사용한다. 165 | > 166 | 167 | ## 5. Reflection의 활용 168 | 169 | ### 1. BeanFactory (Spring Container) 170 | 171 | - Bean은 애플리케이션이 실행한 후 런타임에 객체가 호출될 때 동적으로 객체의 인스턴스를 생성하는데 이때 BeanFactory에서 Reflection을 사용한다. 172 | 173 | ### 2. Spring JPA 174 | 175 | - “JPA의 Entity 객체에는 기본 생성자가 있어야 한다.” 176 | - JPA에서 Entity에 대한 객체를 생성하기 위해서 Java Reflection을 사용한다. 177 | 178 | ### 3. @Requestbody 179 | 180 | - @RequestBody을 사용하면 ObjectMapper가 JSON Field와 Java Field (Dto)를 매칭 시킨다. 181 | - 이때 Reflection을 사용해서 값을 주입해준다. 182 | 183 | ⇒ Dto의 setter는 필요없다, Dto에 기본 생성자가 필요하다. 184 | 185 | > Reflection API로 가져올 수 없는 정보 중 하나가 생성자의 인자(Paramter 정보) 186 | 그래서 기본 생성자가 반드시 있어야 객체를 생성할 수 있다. 187 | 기본 생성자로 객체를 생성하고 필드 값 등은 Reflection으로 넣어준다. 188 | > 189 | 190 | ## 예상 질문 191 | 192 | 1. Reflection이 무엇인가? 193 | - 런타임에서 클래스 및 클래스의 생성자, 메서드, 필드를 조작하고 검사하는 역할을 맞는다. (조작 검사 시에 클래스의 구체적 타입을 알지 못한다) 194 | 1. Reflection의 활용 -------------------------------------------------------------------------------- /Java/2022-05-24-equals&hashcode.md: -------------------------------------------------------------------------------- 1 | ## equals() 2 | 3 | ### (1) equals 규약 4 | 5 | - 반사성 : `A.equals(A) == true` 6 | - 대칭성 : `A.equals(B) == B.equals(A)` 7 | - 추이성 : `A.equals(B) && B.equals(C), A.equals(C)` 8 | - 일관성 : `A.equals(B) == A.equals(B)` 9 | - null-아님 : `A.equals(null) == false` 10 | 11 | ### (2) equals() Overriding 방법 12 | 13 | ```java 14 | public class User { 15 | private String name; 16 | private int age; 17 | 18 | @Override 19 | public boolean equals(Object o) { 20 | // 1. 자기 자신의 참조인지 확인한다. 21 | if (this == o) { 22 | return true; 23 | } 24 | 25 | // 2. 올바른 타입인지 확인한다. (User Class인지 확인) 26 | if (!(o instanceof User)) { 27 | return false; 28 | } 29 | 30 | // 3. 입력된 값을 올바른 타입으로 형변환 한다. 31 | User user = (User) o; 32 | 33 | // 4. 입력 객체와 필드가 일치하는지 확인한다. 34 | return age == user.age && Objects.equals(name, user.name); 35 | } 36 | } 37 | ``` 38 | 39 | - equals 구현 방법 4단계 40 | - == 연산자를 사용해 자기 자신의 참조인지 확인한다. 41 | - instanceof 연산자로 올바른 타입인지 확인한다. 42 | - 입력된 값을 올바른 타입으로 형변환 한다. 43 | - 입력 객체와 자기 자신의 대응되는 핵심 필드가 일치하는지 확인한다. 44 | 45 | ## hashCode() 46 | 47 | ### (1) hashCode 규약 48 | 49 | - equals 비교에 사용하는 정보가 변경되지 않았다면 **hashCode는 매번 같은 값을 리턴**해야 한다. (변경되거나, 애플리케이션을 다시 실행했다면 달라질 수 있다.) 50 | - **equals가 두 객체를 같다고 판단했다면, 두 객체의 hashCode의 값도 같아야 한다.** 51 | - 두 객체에 대한 equals가 다르더라도, **hashCode의 값은 같을 수 있지만** 해시 테이블 성능을 고려해 다른 값을 리턴하는 것이 좋다. (필수 X) 52 | - 성능이 느려지지만 문제는 없다. 53 | 54 | ### (2) hashCode 구현 55 | 56 | ```java 57 | public class User { 58 | private String name; 59 | private int age; 60 | 61 | @Override 62 | public int hashCode() { 63 | int result = Integer.hashCode(age); 64 | result = 31 * result + (name == null ? 0 : name.hashCode()); 65 | 66 | return result; 67 | } 68 | } 69 | ``` 70 | 71 | - 핵심 필드 하나의 값을 해쉬값을 계산해서 result 값을 초기화 한다. 72 | - hashCode 계산 73 | - 기본 타입은 Type(Wrapper class).hashCode 74 | - `Integer.hashCode(age)` 75 | - 참조 타입은 해당 필드의 hashCode 76 | - `name.hashCode()` 77 | - 배열은 Arrays.hashCode 78 | - `Arrays.hashCode(list)` 79 | - `result = 31 * result + 해당 필드의 hashCode` 계산 80 | - result 리턴 81 | 82 | > 왜 31 인가? 83 | 홀수 선택, 31을 썻을 때 해쉬 충돌이 가장 적었다. 84 | > 85 | 86 | ## “equals와 hashCode를 같이 재정의 해야 하는 이유” 87 | 88 | ### 1. equals만 재정의 하는 경우 89 | 90 | ```java 91 | public class User { 92 | private String name; 93 | private int age; 94 | 95 | @Override 96 | public boolean equals(Object o) { 97 | if (this == o) { 98 | return true; 99 | } 100 | 101 | if (!(o instanceof User)) { 102 | return false; 103 | } 104 | 105 | User user = (User) o; 106 | 107 | return age == user.age && Objects.equals(name, user.name); 108 | } 109 | } 110 | ``` 111 | 112 | ### Test 113 | 114 | ```java 115 | public class HashMapTest { 116 | public static void main(String[] args) { 117 | Set set = new HashSet<>(); 118 | 119 | User user1 = new User("name", 20); 120 | User user2 = new User("name", 20); 121 | 122 | // 같은 인스턴스, 다른 hashCode 123 | System.out.println(user1.equals(user2)); // true 출력 124 | System.out.println(user1.hashCode()); 125 | System.out.println(user2.hashCode()); // 다른 hashcode 출력 126 | 127 | set.add(user1); 128 | set.add(user2); 129 | 130 | System.out.println(set.size()); // 2 출력 131 | } 132 | } 133 | ``` 134 | 135 | - Collection에 중복되지 않은 User 객체만 넣으라고 요구사항을 받아 Set 자료구조를 사용해야 한다는 상황 136 | - 추가된 두 User 객체의 필드 값이 모두 같지만 각 객체의 hashcode 값이 다르다. 137 | 138 | > 즉, hash 값을 사용하는 Collection (HashSet, HashMap)을 사용할 대 문제가 발생 한다. 139 | > 140 | 141 | ## 2. 발생 이유 142 | 143 | - hash 값을 사용하는 Collection (HashMap, HashSet, HashTable)은 객체가 논리적으로 같은지 비교할 때 아래 그림과 같은 과정을 거친다. 144 | 145 | ![hash](https://tecoble.techcourse.co.kr/static/c248e8d79140c18ed9895d1c95dd7ad0/54e75/2020-07-29-equals-and-hashcode.png) 146 | 147 | - hashCode 메서드의 리턴 값을 비교한 후 일치하면 equals 메서드의 리턴 값이 true여야 논리적으로 같은 객체라고 판단한다. 148 | - HashSet에 User 객체를 추가할 때 다른 hashcode에 의해 다른 객체 판단하고 HashSet에 각각 추가되었다. 149 | - User 객체에 hashCode 메서드가 재정의 되어있지 않아서 Object 클래스의 hashCode 메서드가 사용되었다. 150 | 151 | > Object 클래스의 hashCode 메서드는 **객체의 고유한 주소 값**을 int 값으로 변환한다. 152 | > 153 | 154 | ## 3. 결론 “항상 같이 재정의 해주어야 할까?” 155 | 156 | - hash 값을 사용하는 Collection을 사용하지 않는다면, equals와 hashCode를 같이 재정의하지 않아도 된다고 생각할 수 있다. 157 | - 하지만 요구사항은 항상 변할 수 있다. 158 | - 또한 협업 환경이라면 동료는 당연히 equals와 hashCode를 같이 재정의 했을 것이라고 생각하고 hash 값을 사용하는 Collection을 사용할 수 있다. 159 | - **equals와 hashCode를 항상 같이 재정의** 해주는 것이 좋다. 160 | 161 | ### 1. Intellij의 Generate 사용 162 | 163 | ```java 164 | public class User { 165 | private String name; 166 | private int age; 167 | 168 | @Override 169 | public boolean equals(Object o) { 170 | if (this == o) { 171 | return true; 172 | } 173 | if (o == null || getClass() != o.getClass()) { 174 | return false; 175 | } 176 | User user = (User) o; 177 | return age == user.age && Objects.equals(name, user.name); 178 | } 179 | 180 | @Override 181 | public int hashCode() { 182 | return Objects.hash(name, age); 183 | } 184 | } 185 | ``` 186 | 187 | - Object.hash 메서드를 호출하는 로직으로 hashCode 메서드가 재정의 되었다. 188 | 189 | ```java 190 | // Objects.class 191 | public static int hash(Object... values) { 192 | return Arrays.hashCode(values); 193 | } 194 | ``` 195 | 196 | ```java 197 | // Arrays.class 198 | public static int hashCode(Object a[]) { 199 | if (a == null) 200 | return 0; 201 | 202 | int result = 1; 203 | 204 | for (Object element : a) 205 | result = 31 * result + (element == null ? 0 : element.hashCode()); 206 | 207 | return result; 208 | } 209 | ``` 210 | 211 | - Objects.hash() 사용 시 hashCode 함수를 단 한 줄로 작성할 수 있다. (장점) 212 | - Objects.hash 메서드 **속도가 느리다.** (단점) 213 | - 입력 인수를 담기 위한 배열이 만들어진다. 214 | - 입력중 기본 타입이 있다면 박싱과 언방식도 거쳐야 한다. 215 | 216 | > - 성능에 아주 민감하지 않은 대부분의 프로그램은 간편하게 Objects.hash 메서드를 사용해서 hashCode 메서드를 재정의해도 문제 없다. 217 | - 민감한 경우에는 **직접 재정의**해주는 것이 좋다. 218 | > 219 | 220 | ### 2. Lombock 사용 221 | 222 | ```java 223 | @EqualsAndHashCode 224 | public class User { 225 | private String name; 226 | private int age; 227 | } 228 | ``` 229 | 230 | ```java 231 | public class User { 232 | private String name; 233 | private int age; 234 | 235 | public User() { 236 | } 237 | 238 | public boolean equals(Object o) { 239 | if (o == this) { 240 | return true; 241 | } else if (!(o instanceof User)) { 242 | return false; 243 | } else { 244 | User other = (User)o; 245 | if (!other.canEqual(this)) { 246 | return false; 247 | } else if (this.age != other.age) { 248 | return false; 249 | } else { 250 | Object this$name = this.name; 251 | Object other$name = other.name; 252 | if (this$name == null) { 253 | if (other$name != null) { 254 | return false; 255 | } 256 | } else if (!this$name.equals(other$name)) { 257 | return false; 258 | } 259 | 260 | return true; 261 | } 262 | } 263 | } 264 | 265 | protected boolean canEqual(Object other) { 266 | return other instanceof User; 267 | } 268 | 269 | public int hashCode() { 270 | int PRIME = true; 271 | int result = 1; 272 | int result = result * 59 + this.age; 273 | Object $name = this.name; 274 | result = result * 59 + ($name == null ? 43 : $name.hashCode()); 275 | return result; 276 | } 277 | } 278 | ``` 279 | 280 | - 장점 281 | - 필드 추가시 코드 수정이 필요 없다. 282 | 283 | 필요에 의해 직접 정의 해야 하는 상황이 아니라면 lombok 혹은 Intellij generate를 사용하자. 284 | 285 | ## 참조 286 | 287 | **Java.doc (Class Object)** 288 | 289 | https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/Object.html 290 | 291 | **Java equals() 및 hashCode()** 292 | 293 | https://www.baeldung.com/java-equals-hashcode-contracts 294 | 295 | **Guide to hashCode()** 296 | 297 | https://www.baeldung.com/java-hashcode -------------------------------------------------------------------------------- /Java/2022-05-24-filter,interceptor.md: -------------------------------------------------------------------------------- 1 | 2 | ***Q . Filter와 Interceptor의 비교(차이점, 공통점)*** 3 | 4 | 5 |
6 | 7 | 8 | 어떤 작업의 앞, 중간, 뒤의 ***공통 업무***(웹 통신과 관련한)들를 분리해서 처리할 수 있는 방법 9 | 10 | AOP와 엮이기도 함. 11 | 12 | (웹 통신을 기준으로 하는 게 아니라, 비즈니스 로직에 대한 중복 업무에 대하여 동작, ex : @Transactional) 13 | 14 | 15 | 16 | 17 | ![image](https://user-images.githubusercontent.com/72663337/170065702-cdd8a7e2-fa72-441b-b52c-da22744efc64.png) 18 | 19 | 20 | `(https://justforchangesake.wordpress.com/2014/05/07/spring-mvc-request-life-cycle/)` 21 | 22 | 23 | 24 |
25 | 26 | ## Filter 27 | 28 | Dispatcher Servlet(Front controller) 의 앞단에서 정보를 처리(Spring 범위 밖에서 처리, Spring Context 외부) 29 | 30 | 보통은 URL 패턴에 따라 실행됨.(CORS filter, Spring Security) 31 | 32 | 33 | 34 | - 인코딩 변환처리, XSS 방어, 인증(Spring Security), CORS 등을 구현할 때 사용 35 | - Servlet에서 처리하기 전후를 다룸(Servlet Request, Response를 조작할 수 있음) -> doFilter method 36 | - Filter chain 37 | 38 |
39 | 40 | 41 | Filter interface 를 implements 하여 구현 42 | 43 | 44 | ``` 45 | public interface Filter { 46 | default void init(javax.servlet.FilterConfig filterConfig) throws javax.servlet.ServletException { /* compiled code */ } 47 | 48 | void doFilter(javax.servlet.ServletRequest servletRequest, javax.servlet.ServletResponse servletResponse, javax.servlet.FilterChain filterChain) throws java.io.IOException, javax.servlet.ServletException; 49 | 50 | default void destroy() { /* compiled code */ } 51 | } 52 | ``` 53 | 54 |
55 | 56 | 57 | Spring Security 에서의 Filter 적용과 Filter chain 예시 58 | 59 | (웹 요청을 가로채어 사용자에 대한 인증, 권한 소유 확인) 60 | 61 | ![image](https://user-images.githubusercontent.com/72663337/170066497-762f62af-ac2e-4c23-9057-a276627fd992.png) 62 | 63 | `Filter Chain` 64 | 65 | 66 | ``` 67 | //debug true 어노테이션을 통하여 실행되는 Security Filter들을 확인 68 | @EnableWebSecurity(debug=true) 69 | public class WebSecurityConfig extends WebSecurityConfigurerAdapter { 70 | 71 | @Override 72 | protected void configure(HttpSecurity http) throws Exception { 73 | http 74 | ... 75 | 76 | ``` 77 | 78 | 79 | 80 | 81 | ![image](https://user-images.githubusercontent.com/72663337/170066658-3e92b187-31d5-43e4-81d9-b24ec46536fd.png) 82 | 83 | 84 | 85 | 86 | 87 | `Spring Security의 Filter chain` 88 | 89 | 90 |
91 | 92 | 93 | 94 | ## Interceptor 95 | 요청에 대한 ***작업 전/후***에서 처리 96 | 97 | - Spring MVC에서 제공하는 API(Spring context) 98 | - Dispatcher servlet이 controller를 호출하기 전에 작동 99 | - 세션에 대한 체크, 인증 처리 100 | - preHandle, postHandle,(handler를 실행하기 전,후) afterCompletion(view 랜더링한 후) 등 메소드에 따라 실행 시점을 다르게 가져갈 수 있음 101 | 102 | 103 | ![image](https://user-images.githubusercontent.com/72663337/170066825-f20d1f5f-f827-4f6a-a44d-f91c29f7caff.png) 104 | 105 | 106 | 107 | `Interceptor flow(https://velog.io/@y_dragonrise/Spring-Interceptor-%EA%B0%9C%EB%85%90-%EB%B0%8F-%ED%9D%90%EB%A6%84)` 108 | 109 | 110 | HandlerInterceptor implements 하여 구현 111 | 112 | 113 | ``` 114 | public interface HandlerInterceptor { 115 | default boolean preHandle(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response, java.lang.Object handler) throws java.lang.Exception { /* compiled code */ } 116 | 117 | default void postHandle(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response, java.lang.Object handler, @org.springframework.lang.Nullable org.springframework.web.servlet.ModelAndView modelAndView) throws java.lang.Exception { /* compiled code */ } 118 | 119 | default void afterCompletion(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response, java.lang.Object handler, @org.springframework.lang.Nullable java.lang.Exception ex) throws java.lang.Exception { /* compiled code */ } 120 | } 121 | 122 | ``` 123 | 124 | 125 | 126 | + 127 | 128 | Dispatcher Servlet 내에서 작동하기 때문에 ControllerAdvice, ExceptionHandler등으로 예외 처리가 가능함. 129 | 130 | 131 | 132 | 133 | 134 | 135 |
136 | 137 | 138 | #### 공통점 139 | - 웹 통신과 연관된 ***공통 작업***을 분리하여 처리하는 역할을 가짐. 140 | 141 | 142 | 143 | 144 | #### 차이점 145 | 146 | | |filter|interceptor| 147 | |:---:|:---:|:---:| 148 | |실행 시점 |Dispatcher Servlet에 Request가 들어가기 전| Controller를 호출하기 전| 149 | |등록 Container |Web Container |Spring Container| 150 | |Requeset, Response 조작| 가능| 불가능| 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 |
160 | 161 | ### Reference 162 | 163 | 164 | 165 | https://velog.io/@y_dragonrise/Spring-Interceptor-%EA%B0%9C%EB%85%90-%EB%B0%8F-%ED%9D%90%EB%A6%84 166 | 167 | 168 | https://supawer0728.github.io/2018/04/04/spring-filter-interceptor/ 169 | 170 | 171 | https://baek-kim-dev.site/61 172 | 173 | 174 | https://junhyunny.github.io/spring-boot/filter-interceptor-and-aop/ 175 | 176 | -------------------------------------------------------------------------------- /Java/images/compact.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prgrms-web-devcourse/BE-Team-R-CS-Study/d0535ce8aeb0166acb1ef886b431ecf3d25e5cfa/Java/images/compact.PNG -------------------------------------------------------------------------------- /Java/images/eden.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prgrms-web-devcourse/BE-Team-R-CS-Study/d0535ce8aeb0166acb1ef886b431ecf3d25e5cfa/Java/images/eden.PNG -------------------------------------------------------------------------------- /Java/images/gc_root.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prgrms-web-devcourse/BE-Team-R-CS-Study/d0535ce8aeb0166acb1ef886b431ecf3d25e5cfa/Java/images/gc_root.png -------------------------------------------------------------------------------- /Java/images/java-entry-wait-set.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prgrms-web-devcourse/BE-Team-R-CS-Study/d0535ce8aeb0166acb1ef886b431ecf3d25e5cfa/Java/images/java-entry-wait-set.png -------------------------------------------------------------------------------- /Java/images/jvmheap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prgrms-web-devcourse/BE-Team-R-CS-Study/d0535ce8aeb0166acb1ef886b431ecf3d25e5cfa/Java/images/jvmheap.png -------------------------------------------------------------------------------- /Java/images/majorgc.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prgrms-web-devcourse/BE-Team-R-CS-Study/d0535ce8aeb0166acb1ef886b431ecf3d25e5cfa/Java/images/majorgc.PNG -------------------------------------------------------------------------------- /Java/images/majorgc2.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prgrms-web-devcourse/BE-Team-R-CS-Study/d0535ce8aeb0166acb1ef886b431ecf3d25e5cfa/Java/images/majorgc2.PNG -------------------------------------------------------------------------------- /Java/images/mark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prgrms-web-devcourse/BE-Team-R-CS-Study/d0535ce8aeb0166acb1ef886b431ecf3d25e5cfa/Java/images/mark.png -------------------------------------------------------------------------------- /Java/images/minorgc.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prgrms-web-devcourse/BE-Team-R-CS-Study/d0535ce8aeb0166acb1ef886b431ecf3d25e5cfa/Java/images/minorgc.PNG -------------------------------------------------------------------------------- /Java/images/minorgc2.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prgrms-web-devcourse/BE-Team-R-CS-Study/d0535ce8aeb0166acb1ef886b431ecf3d25e5cfa/Java/images/minorgc2.PNG -------------------------------------------------------------------------------- /Java/images/sweep.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prgrms-web-devcourse/BE-Team-R-CS-Study/d0535ce8aeb0166acb1ef886b431ecf3d25e5cfa/Java/images/sweep.PNG -------------------------------------------------------------------------------- /Java/images/threadLifeCycle.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prgrms-web-devcourse/BE-Team-R-CS-Study/d0535ce8aeb0166acb1ef886b431ecf3d25e5cfa/Java/images/threadLifeCycle.jpg -------------------------------------------------------------------------------- /Java/목차.md: -------------------------------------------------------------------------------- 1 | # 목차 -------------------------------------------------------------------------------- /Network/2022-04-01-OSI7계층.md: -------------------------------------------------------------------------------- 1 | # OSI 7계층 2 |
3 | 4 | ![osi](https://user-images.githubusercontent.com/72663337/161380658-12153c27-9b45-4a93-94c3-8d5c79ce4ae0.png) 5 | ## Q . OSI 7계층이란? 6 | 7 | - 컴퓨터 네트워크 프로토콜 디자인과 통신을 계층으로 나누어 설명한 모델 8 | 9 | - 통신 접속에서 완료까지의 과정을 7단계로 정의한 국제 표준 규약 10 | 11 | - 각 계층은 독립적이며, 각 계층별로 필요한 헤더가 추가되면서 캡슐화(전송) 12 | 13 | 14 | ### 응용 계층(Application layer) 15 | - 사용자와 네트워크 사이의 연결(서비스 제공) 16 | 17 | - 데이터 생성 18 | 19 | - HTTP, FTP 프로토콜 20 | 21 | ### 표현 계층(Presentation layer) 22 | - 데이터 표현이 상이한 프로세스에 대하여 형식 설정 23 | 24 | 데이터가 하위 계층으로 향할 때(발신) : 통신에 알맞은 형태로 데이터를 변환 25 | 26 | 데이터가 상위 계층으로 향할 때(수신) : 사용자가 이해할 수 있는 형태로 변환 27 | 28 | ### 세션 계층(Session layer) 29 | - 데이터의 통신을 위한 사용자 간 연결을 유지, 동기화 30 | 31 | ### 전송 계층(Transport layer) 32 | - 상위 3계층과 하위 3계층의 인터페이스를 담당 33 | 34 | - 신뢰성 있는 통신 확보 35 | 36 | - TCP, UDP 37 | 38 | - 흐름 제어, 혼잡 제어(전송되는 데이터의 손실이 일어나지 않도록 함.) 39 | 40 | - Segment 형태 41 | 42 | - 장비 : 스위치 43 | 44 | ### 네트워크 계층(Network layer) 45 | - 단말기 간 최적화된 데이터 전송을 위한 경로 제공 46 | 47 | -> 경로를 선택하고, 경로에 따라 패킷 전달 48 | 49 | - IP 주소를 통하여 목적지로 데이터를 전송함 50 | 51 | - Packet 형태 52 | 53 | - 장비 : 라우터(Router). 무선공유기.. 54 | 55 | ### 데이터링크 계층(Data Link layer) 56 | - 에러 검출, 전송 오류 제어 57 | 58 | - MAC Address를 통하여 통신(내부망) 59 | 60 | `하나의 공유기에 여러 기기가 연결되었을 때의 네트워크를 내부망 이라고 한다.` 61 | 62 | - Frame 형태 63 | 64 | ### 물리 계층(Physical layer) 65 | - 0과 1의 비트 정보를 케이블(또는 무선)로 전송 66 | 67 | - 케이블을 통한 전송을 위해 데이터를 전기 신호로 변환 68 | 69 | - 장비 : 허브(Hub) 70 | 71 | ## Q . OSI 7계층을 나누는 이유는? 72 | - 통신이 일어나는 과정이 각 단계별로(계층별로) 파악될 수 있음 73 | 74 | - 통신의 흐름을 한 눈에 알아보기 쉬움 75 | 76 | - 특정 위치에 이상이 생겼을 때, 그 단계의 에러만을 고쳐 문제를 해결할 수 있음. 77 | 78 | - 또한 각 계층에 대한 캡슐화, 은닉의 가능하다는 이점 79 | 80 | ## Q . Router란 무엇인가? 81 | 네트워크 장비. 네트워크 계층에서 동작 82 | 83 | 데이터를 현 네트워크에서 다른 네트워크로 전송하는 역할, 전송을 위한 경로를 선택함 84 | 85 |
86 | 87 | ++ 88 | 89 | ## Q . TCP/IP 4계층이란? OSI 7계층과의 차이점은? 90 | 91 | - TCP/IP 프로토콜의 통신 과정을 4개의 계층 구조로 나타냄 92 | 93 | - OSI 모델을 기반으로 한, 실무적으로 적용될 수 있는 좀 더 단순화된 모형 94 | 95 | ![tcp-ip](https://user-images.githubusercontent.com/72663337/161381081-384770ab-16c1-41ad-8225-d247c55196d6.png) 96 | 97 | -------------------------------------------------------------------------------- /Network/2022-04-21-TCP_UDP.md: -------------------------------------------------------------------------------- 1 | # TCP/UDP 2 | 3 | ## TCP란? (Transmission Control Protocol) 4 | TCP는 신뢰성있는 데이터 통신을 가능하게 해주는 프로토콜입니다. 5 | 6 | TCP는 다음과 같은 특징을 갖는데요, 7 | * 특징: Connection 연결 (3-Way Handshake), 양방향 통신 8 | * 데이터의 순차 전송을 보장 9 | * Flow Control (흐름 제어) 10 | * Congestion Control(혼잡 제어) 11 | * Error Detection (오류 감지) 12 | 13 | 이러한 특징들에 대해 자세히 살펴보기전에 TCP의 헤더에 대해서 알아보겠습니다. 14 | 15 | ### TCP Header 16 | ![tcp-header.png](images/tcp-header.png) 17 | 18 | 위 사진은 TCP 헤더의 구조입니다. (TCP 세그먼트 구조라고도 부릅니다) 보시면 발신지 포트 번호인 Source port, 목적지 포트 번호인 Destination Port를 갖게 되며 데이터 순차 전송을 위해 Sequence Number, Acknowledgement Number을 갖습니다. 19 | 20 | 주목해야할 부분은 빨간색 네모 박스인데요, ACK, SYN, FIN 플래그를 갖습니다. 21 | 해당 플래그들은 3 Way-handshake, 4 Way-handshake에서 사용되어집니다. 22 | 23 | 그렇다면 3-Way Handshake와 4-Way Handshake에서 어떤 방식으로 사용될까요? 24 | 25 | ### 3-Way Handshake 26 | 3-Way Handshake란 클라이언트와 서버간의 가상회선을 수립하는 과정입니다. 즉, 클라이언트는 서버에 요청을 전송할 수 있는지, 서버는 클라이언트에게 응답을 전송할 수 있는지 확인하는 과정입니다. 27 | 28 | ![tcp3handshake.png](images/tcp3handshake.png) 29 | 30 | 여기서 사용되는 플래그는 SYN, ACK 플래그입니다. 31 | 32 | * SYN : 접속 요청(패킷 송신) 33 | * ACK : 요청 수락(패킷을 받았다고 응답) 34 | 35 | TCP의 3-way Handshaking 과정은 다음과 같습니다. 36 | 37 | 1. 클라이언트는 서버에 접속을 요청하는 SYN 패킷을 보냅니다. 이때 클라이언트는 SYN/ACK 응답을 기다리는 SYN_SENT 상태가 됩니다. 38 | 39 | 2. 서버는 SYN요청을 받고 클라이언트에게 요청을 수락한다는 ACK 와 SYN flag 가 설정된 패킷을 발송하고 클라이언트가 다시 ACK으로 응답하기를 기다립니다. 이때 서버는 SYN_RECEIVED 상태가 됩니다. 40 | 41 | 3. 클라이언트는 서버에게 ACK을 보내고 이후로부터는 연결이 이루어지고 데이터가 오갈 수 있습니다. 이때의 서버 상태가 ESTABLISHED 입니다. 42 | 43 | 위와 같은 방식으로 3-Way Handshake를 이용해 클라이언트 서버간 신뢰성 있는 연결을 맺게 되면 전송 순서가 보장되면서 순서 제어가 가능하게 됩니다. 44 | 45 | ![tcp_순서보장.png](images/tcp_순서보장.PNG) 46 | 47 | 위와 같이 패킷의 순서가 뒤바뀌는 일이 발생하지 않게 됩니다. 48 | 49 | ### 4-Way Handshake 50 | 3-Way Handshake가 연결을 수립하기 위한 과정이라면 4-Way는 연결을 종료하기 위해 수행되는 절차입니다. 51 | 52 | ![tcp4handshake.png](images/tcp4handshake.png) 53 | 54 | 여기서 사용되는 플래그는 FIN, ACK 플래그입니다. 55 | 56 | * FIN : 접속이 연결되었을 때, 끊어야 할 때 사용하는 FLAG BIT 57 | * ACK : 요청 수락(패킷을 받았다고 응답) 58 | 59 | TCP의 4-way Handshaking 과정은 다음과 같습니다. 60 | 61 | 1. 클라이언트가 연결을 종료하겠다는 FIN플래그를 전송합니다. 62 | 63 | 2. 서버는 FIN 플래그를 받은후 확인메시지 ACK를 클라이언트에 보냅니다. 그 후 일정시간 대기하며 자신의 통신이 끝날때까지 기다립니다. 64 | 65 | 3. 서버가 통신이 끝났으면 연결이 종료되었다고 클라이언트에게 FIN플래그를 전송합니다. 66 | 67 | 4. 클라이언트는 확인했다는 ACK 플래그를 다시 서버로 전송합니다. 68 | 69 | ### 흐름 제어 70 | 다음으로 TCP의 특징 중 하나인 흐름 제어에 대해서 알아보겠습니다. 71 | 72 | 흐름 제어란 수신단에서 소화할 수 있는 속도로 송신단에서 데이터를 보내는걸 일컫습니다. 73 | 74 | 즉, 데이터를 송신하는 곳과 수신하는 곳의 데이터 처리 속도를 조절하여 수신자의 버퍼 오버플로우를 방지하는 것(데이터의 처리 속도 조절)이라고 볼 수 있습니다. 75 | 76 | 이는 송신하는 곳에서 감당이 안되게 많은 데이터를 빠르게 보내 수신하는 곳에서 문제가 일어나는 것을 막습니다. 77 | 78 | [해결 방법] 79 | 80 | * Stop and Wait 81 | 82 | 매번 전송한 패킷에 대해 확인 응답을 받아야만 그 다음 패킷을 전송하는 방법 83 | 84 | ![stopAndWait.png](images/stopAndWait.png) 85 | 86 | * Sliding Window 87 | 88 | 수신측에서 설정한 윈도우 크기만큼 송신측에서 확인응답없이 세그먼트를 전송할 수 있게 하여 데이터 흐름을 동적으로 조절하는 제어기법 89 | 90 | ![slidingwindow.png](images/slidingwindow.png) 91 | 92 | 먼저 윈도우에 포함되는 모든 패킷을 전송하고, 그 패킷들의 전달이 확인되는대로 이 윈도우를 옆으로 옮김으로써 그 다음 패킷들을 전송하는 방식으로 동작됩니다. 93 | 94 | ### 혼잡 제어 95 | 96 | 혼잡 제어란 송신측의 데이터 전달과 네트워크의 처리속도 차이를 해결하기 위한 기법입니다. 97 | 98 | 송신자쪽에서 데이터를 보내도 네트워크 혼잡도 등의 이유로 데이터 처리 속도가 느려지고 수신자측에 도달하지 못하는 문제가 발생할 수 있습니다. 99 | 100 | 네트워크 내에 패킷의 수가 과도하게 증가하는 현상을 **혼잡**이라 하며, 혼잡 현상을 방지하거나 제거하는 기능을 **혼잡제어**라고 합니다. 101 | 102 | 흐름제어가 송신측과 수신측 사이의 전송속도를 다루는 반면, 혼잡제어는 호스트와 라우터를 포함한 보다 넓은 관점에서 전송 문제를 다루게 됩니다. 103 | 104 | [해결 방법] 105 | 106 | * AIMD(Additive Increase/Multicative Decrease) 107 | 108 | ![aimd.png](images/aimd.png) 109 | 110 | AIMD를 직역하자면 합 증가 / 곱 감소 방식입니다. 111 | 112 | 처음에 패킷을 하나씩 보내고 문제없이 도착하면 윈도우의 크기를 1씩 증가시켜가며 전송합니다. 113 | 114 | 만약 전송에 실패하면 윈도우 크기를 반으로 줄입니다. 115 | 116 | 이 방식은 윈도우 크기를 너무 조금씩 늘리기 때문에 네트워크의 모든 대역을 활용하여 제대로 된 속도로 통신하기까지 시간이 오래 걸린다는 단점이 있습니다. 117 | 118 | * Slow Start (느린 시작) 119 | 120 | ![slow-start-chart.png](images/slow-start-chart.png) 121 | 122 | 윈도우의 크기를 1, 2, 4, 8... 과 같이 2배씩 증가시킵니다. 123 | 124 | 혼잡이 감지되면 윈도우 크기를 1로 줄여버립니다. 125 | 126 | 시간이 지날수록 AIMD 보다 빠르게 윈도우 크기를 증가시킬 수 있다는 장점이 있습니다. 127 | 128 | * 빠른 재전송 129 | 130 | ![fast-transmit.png](images/fast-transmit.png) 131 | 132 | 위 사진과 같이 2번 데이터가 누락이 된 채로 송신측에서 계속 데이터를 보내주는 상황일 경우 133 | 수신측에서는 순서대로 잘 도착한 마지막 패킷의 다음 순번(2번)을 ACK 패킷에 실어서 보냅니다. 그리고 이런 중복 ACK를 3개를 받게 되면 재전송이 이루어지게 되는 과정입니다. 134 | 135 | 이는 송신 측은 자신이 설정한 타임아웃 시간이 지나지 않았어도 바로 해당 패킷을 재전송할 수 있기 때문에 보다 빠른 전송률을 유지할 수 있다는 장점이 있습니다. 136 | 137 | * 빠른 회복 138 | 139 | 빠른 회복은 혼잡한 상태가 되면 윈도우 크기를 1로 줄이지 않고 반으로 줄이고 선형증가시키는 방법입니다. 이 방법을 적용하면 혼잡 상황을 한번 겪고 나서부터는 AIMD 방식으로 동작합니다. 140 | 141 | TCP는 역사가 오래된만큼 이외에도 지속적으로 개선된 다양한 혼잡 제어 정책들을 가지고 있는데요, 142 | 143 | 각 혼잡 제어 정책은 어떤 시점을 혼잡한 상태라고 파악할 것인지, 혼잡 윈도우 크기를 줄이거나 키우는 방법을 개선하여 점점 발전해왔지만, 가장 기본적인 혼잡 제어 방법은 AIMD와 Slow Start라는 혼잡 회피 방법을 상황에 맞게 조합하는 것이라고 합니다. 144 | 145 | ## UDP란? (User Datagram Protocol) 146 | UDP는 TCP와 다르게 비 연결형, 신뢰성 없는 전송 프로토콜입니다. 데이터를 데이터그램 단위로 처리하는 프로토콜이라고도 불립니다. 147 | 148 | 여기서 데이터 그램이란 독립적인 관계를 지니는 패킷이라는 뜻이며 각각의 패킷은 독립적인 관계를 지니게 되어 독립적으로 처리하게 됩니다. 이 때문에 서버와 클라이언트는 1대1, 1대N, N대M으로 연결될 수 있습니다. 149 | 150 | 정보를 주고 받을때 정보를 보내거나 받는다는 신호 절차를 거치지 않으며 151 | 패킷 오버헤드가 적어 네트워크 부하가 감소되는 장점이 있습니다. 152 | 153 | 때문에 상대적으로 TCP보다 전송속도가 빠르며 신뢰성보다는 연속성이 중요한 스트리밍 서비스에 사용한다고 합니다. 154 | 155 | ### UDP Header 156 | 157 | ![udpheader.png](images/udpheader.png) 158 | 159 | UDP 헤더는 발신지 포트번호인 Source port와 목적지 포트번호인 Destionation port가 존재하며 헤더와 데이터를 합한 데이터 그램의 전체 길이를 정의하는 Total Length로 구성됩니다. 160 | 또, 헤더와 데이터를 모두 포함한 데이터 그램 전체에 대해 오류를 탐지하기 위해 사용되는 Checksum을 갖습니다. 161 | 162 | ### TCP와 UDP 비교 163 | 164 | ![tcp_udp.png](images/tcp_udp.png) 165 | 166 | * 예상 질문 167 | 168 | TCP의 특징에 대해서 설명해보세요. 169 | 170 | 혼잡 제어란 무엇인가요? 171 | 172 | 흐름 제어란 무엇인가요? 173 | 174 | 데이터의 순차 전송을 어떻게 보장하나요? 175 | 176 | TCP 3, 4 way handshake에 대해서 설명해보세요 177 | 178 | TCP와 UDP의 차이점에 대해 설명해보세요 -------------------------------------------------------------------------------- /Network/2022-04-28-TLS&SSL.md: -------------------------------------------------------------------------------- 1 | # TLS/SSL 2 | 3 | # TLS/SSL 4 | 5 | - TLS/SSL은 OSI 7계층에서 5계층에 해당 6 | - 암호화 레이어를 통해 Application 단의 암호화를 수행 7 | - 대칭키 암호화 기법과 비대칭 키 암호화 기법을 동시에 사용 8 | - TLS/SSL이라고 불리는 이유 9 | - SSL은 1994년 넷스케이프사에서 개발한 프로토콜, 사실상 업계 표준화 10 | - 이후 SSL이 업그레이드되던 중 SSL3.0에서 취약점이 발견되어, SSL3.0을 기반으로 IETF에서 TLS 프로토콜을 개발 11 | - 이때 이후 업계 표준은 TLS이지만 SSL도 혼용되어 사용 12 | 13 | # 암호화 방법 14 | 15 | - 암호화 기법에는 대표적으로 대칭 키 암호화 기법과 비대칭 키 암호화 기법이 있다. 16 | - 대칭 키 암호화 기법은 키가 1개이고, 비대칭 키 암호화 기법은 키가 2개이다. 17 | 18 | ## 대칭 키 암호화 19 | 20 | - 같은 키를 이용하여 암호화와 복호화를 진행 21 | - 암호화 키와 복호화 키가 동일함 22 | - 키를 교환하는 과정에서 도청 시 도청자가 복호화 가능, 따라서 신뢰성 있는 키 교환 과정 필요 23 | 24 | ![one_key](images/one_key.png) 25 | 26 | ## 비대칭 키 암호화 27 | 28 | - 암호화를 위한 키와 복호화를 위한 키가 다름 29 | - 키는 하나의 키쌍 형태로 존재 30 | - 외부에 공개하는 공개 키, 개인이 소유하는 비밀 키가 있음 31 | - 공개 키로 암호화할 시 비밀 키로만 복호화할 수 있고, 비밀 키로 암호화할 시 공개 키로만 복호화할 수 있음 32 | 33 | ![two_key](images/two_key.png) 34 | 35 | - 비대칭적인 특징 때문에 두 가지 방향으로 사용 36 | - 암호화 37 | - 공개된 공개 키 저장소에서 앨리스의 공개키를 수집 38 | - 밥이 앨리스의 공개 키로 암호화하여 전송 39 | - 앨리스는 본인의 개인 키를 이용해서만 복호화 가능, 다른 사람이 복호화가 불가능함을 보장 가능 40 | - 전자서명 41 | - 앨리스가 개인 키를 이용하여 암호화 진행(전자서명 생성) 42 | - 밥 공개된 공개 키 저장소에서 앨리스의 공개키를 수집 43 | - 생성된 전자서명을 밥에게 전달함 44 | - 밥은 앨리스의 공개키를 이용하여 전자서명 복호화, 이를 통해 앨리스가 보냈음을 보장할 수 있음 45 | 46 | # TLS/SSL에서 암호화 과정 47 | 48 | - 핸드셰이크 프로토콜을 통하여 대칭 키를 교환하는 과정을 거침 49 | 50 | ## Handshake 프로토콜 51 | 52 | ![tls_handshake](images/tls_handshake.png) 53 | 54 | - 총 4단계 과정을 거침 55 | 1. Hello 56 | - 클라이언트 → 서버 57 | - HELLO : 클라이언트가 서버에게 세션ID, 클라이언트가 지원하는 알고리즘 리스트, 버전, 클라이언트 생성 난수를 서버에 전달 58 | - 서버 → 클라이언트 59 | - HELLO : 서버가 클라이언트에게 세션ID, 선택한 알고리즘, 버전, 서버 생성 난수를 클라이언트에게 전달 60 | - HELLO 과정을 통해 공유하는 것 61 | - TLS/SSL 버전, 암호화 알고리즘, 키 생성을 위한 2개의 난수 62 | 2. Server Certificate 63 | - 서버 → 클라이언트 64 | - ServerCertificate : 서버의 인증서가 포함된 정보를 전달(서버의 공개키 포함) 65 | - ClientRequest : 클라이언트의 인증서를 통한 인증 요구(Optional) 66 | 3. Client Certificate 67 | - 클라이언트 → 서버 68 | - ClientCertificate : 클라이언트의 인증서가 포함된 정보를 보냄(클라이언트의 공개키 포함) 69 | - ClientKeyExchange : pre-master-secret을 생성하여 서버에게 전달, 이때 선택된 공개 키 알고리즘을 이용하여 서버와 공유(서버의 공개키로 암호화) 70 | 4. Ready 71 | - 클라이언트 → 서버 72 | - finished : 키 교환을 위한 정보를 모두 전달했음을 확인 73 | - 서버 → 클라이언트 74 | - finished : 키 교환을 위한 정보를 모두 확인하고, 전달받았음을 확인 75 | - 이후 교환한 pre-master-secret의 압축을 해제하여 master secret을 생성 76 | - 생성된 master secret을 기반으로 세션 키 생성 77 | - 이후 세션 키를 이용하여 대칭 키 암호화 통신 진행 -------------------------------------------------------------------------------- /Network/2022-05-10-CORS.md: -------------------------------------------------------------------------------- 1 | 2 | ### 주요 질문 3 | #### Q . CORS란? 사용하는 이유. 동작 방식에 대하여 4 | 5 | #### Q . 개발을 하면서 CORS 관련하여 경험하였던 이슈 -> 해결 방법은? 6 | 7 | 8 | 9 |
10 | 11 | # CORS(Cross Origin Resource Sharing) 12 | - 합의 된 출처들 간의(Cross Origin) 요청을 허용해주기 위해(Resource Sharing) 만들어진 규칙 13 | 14 | 15 | 16 | ### SOP(Same-Origin Policy) 17 | 18 | : 같은 출처끼리만 리소스를 공유할 수 있다. 19 | 20 | - 웹 브라우저에 내장된 기본 정책 21 | 22 |
23 | 24 | 25 | ![image](https://user-images.githubusercontent.com/72663337/167573451-504d15d3-8f15-40d1-921e-7edcffe6b838.png) 26 | 27 | `CORS 설정을 하지 않은 경우 SOP 정책에 의한 에러` 28 | - http://localhost:3000 에서 http://localhost:8080/api/v2/products 로의 접근이 CORS 정책에 의하여 차단되었다. 29 | 30 | 31 | 32 | 33 | 34 | 보통 프론트 단에서 API로 정보를 받아오기 위해 HTTP 요청을 보냈을 때 접하게 되는 에러 35 | 36 | 브라우저에서 ***출처(Origin)*** 가 다른 곳과 요청을 주고 받는 것을 허용하지 않아 생기게 됨. 37 | 38 |
39 | 40 | CORS라는 예외 규칙을 만들어 출처는 다르지만 합의 된 출처들 간의 요청을 허용 41 | 42 | 43 |
44 | 45 | 46 | ## 출처(Origin) 47 | 48 | 49 | ![image](https://user-images.githubusercontent.com/72663337/167573825-2e5cf037-6686-4d97-a350-15af5bae8c94.png) 50 | 51 | 52 | `URL의 구조(https://www.grabbing.me/URL-018cdd1bb4b541fab6246569244fcf93)` 53 | 54 | ***Origin : Protocol + Host + Port*** 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 |
63 | 64 | Ex) 65 | 66 | `http://localhost:8080/api/v1/products` 와의 비교 67 | 68 | ![image](https://user-images.githubusercontent.com/72663337/167574630-1a3fa644-b92f-4c55-8f3a-86e47f1c0333.png) 69 | 70 | 71 | |URL| 일치 여부 | 이유 | 72 | |----------------------|----|--------------| 73 | |http://localhost:3000 | x | 포트 번호가 다름 | 74 | |https://localhost:8080 | x | 프로토콜이 다름 | 75 | |http://localhost:8080/new-order | o | 경로는 다르지만 출처는 동일 | 76 | 77 | 78 | 79 | 80 |
81 | 82 | 83 | 84 | ## CORS를 사용하는 이유 85 | 소스 코드와 같은 정보가 노출되기 쉬운 웹 클라이언트 환경에서, 86 | 87 | (개발자 도구를 키거나, 페이지 소스 보기 등으로 소스 코드가 노출되는 것과 같은) 88 | 89 | 90 | 91 | 다른 출처와의 통신 시 92 | 93 | XSS, CSRF와 같은 공격으로 악성 소스가 삽입되거나, 정보가 탈취될 수 있는 위험 가능성이 존재함. 94 | 95 |
96 | 97 | => 요청 및 응답에 대해 CORS 정책을 준수하는지를 검사하여 안전한 요쳥인지를 판단하기 위함 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | ## CORS의 동작 방식 106 | - 요청 시 헤더 Origin 필드에 요청을 보내는 출처를 함께 담아 전송(***OPTIONS***) 107 | 108 | - 이후 서버에서는 응답 헤더의 ***Access-Control-Allow-Origin*** 필드를 통해 리소스에 대한 접근이 허용된 출처를 담아 응답 전송 109 | 110 | - 응답을 받은 브라우저는 자신이 보냈던 Origin과 Access-Control-Allow-Origin을 비교하여 유효성 여부를 판단 111 | 112 | 113 | 114 | 115 | 116 | ### Preflight 117 | ***예비 요청***을 통하여 CORS 정책 위반 여부를 판단하고, 118 | 119 | 후에 ***본 요청***을 보냄 120 | 121 | 122 | ![image](https://user-images.githubusercontent.com/72663337/167574979-ce7b4949-fb97-421e-a5d8-60763f4dfa79.png) 123 | 124 | 125 | `Preflight` 126 | 127 | 128 |
129 | 130 | 131 | 132 | 예비 요청 133 | 134 | ![image](https://user-images.githubusercontent.com/72663337/167575157-971bb464-eead-4dfc-98f1-81c68f623c8f.png) 135 | 136 | 137 | `예비 요청에 대한 응답` 138 | 139 | Access-Control-Allow-~ 필드를 통하여 CORS 정책을 확인한 후, 본 요청을 전송 140 | 141 | 142 | 143 |
144 | 145 | 146 | ![image](https://user-images.githubusercontent.com/72663337/167575353-982e2680-03ec-407c-a6bb-456b60a26585.png) 147 | 148 | 149 | `본 요청에 대한 응답` 150 | 151 | -> GET 메소드를 이용하여 본 요청을 보냈음을 알 수 있음. 152 | 153 | 154 | 155 | 156 | 157 |
158 | 159 | ### Simple Request 160 | 예비 요청을 보내지 않고 바로 서버에게 본 요청을 보냄. 161 | 162 | 본 요청에 대한 응답 헤더를 통하여 CORS 위반 여부를 확인함. 163 | 164 |
165 | 166 | 167 | ![image](https://user-images.githubusercontent.com/72663337/167575619-abdb9c96-568e-4383-b144-24999688b17d.png) 168 | 169 | 170 | `Simple Request` 171 | 172 | 173 | 다음과 같은 조건을 만족할 때에만 사용 가능하다. 174 | 175 | 176 | 177 | - GET, HEAD, POST method Request 이어야 한다. 178 | - Accept, Accept-Language, Content-Language, Contene-Type, DPR, Downlink, Save-Data, Viewport-Width, Width를 제외한 헤더는 사용 불가능하다. 179 | - Content-Type을 사용하는 경우에는 application/x-www-form-urlencoded, multipart/form-data, text/plain만 허용된다. 180 | 181 | 182 | => 사실상 위의 조건들을 모두 만족시키는 것은 쉽지 않다. 183 | 184 | 185 | 186 |
187 | 188 | 189 | ### Credentialed Request 190 | 인증된 요청을 사용하는 방식. 191 | 192 | 서로의 통신에 있어서 보안을 더 강화하고자 할 때 사용 193 | 194 | ***credentials*** 옵션을 통하여 요청에 인증 정보를 담음 195 | 196 | 197 |
198 | 199 | 200 | ***credentials*** 201 | 202 | - same-origin : ***같은 출처*** 내에서 인증 정보를 사용 203 | - include : ***모든 요청***에 인증 정보를 사용함 204 | 205 |
206 | 207 | 208 | 이 옵션을 사용하면 CORS 위반 여부 판단 시 Origin 값만 확인하는 것이 아닌 다음과 같은 규칙이 추가된다. 209 | 210 | - Access-Control-Allow-Origin 에는 * 값을 사용할 수 없고, 명시적인 URL 이어야 한다. 211 | - 응답 헤더에는 Access-Control-Allow-Credentials : true 가 반드시 존재해야한다. 212 | 213 | 214 | ![image](https://user-images.githubusercontent.com/72663337/167575838-bafb1eff-b185-4142-ba12-6c4f463299f8.png) 215 | 216 | 217 | `credentials 옵션 규칙 예시` 218 | 219 | 220 | => 서버의 Access-Control-Allow-Origin 값이 * 로 설정되어 있기 때문에 CORS 정책을 위반하였다는 에러가 출력된다. 221 | 222 | 223 | 224 | 225 |
226 | 227 | 228 | 229 | 230 | ## CORS 에러가 발생하였을 때의 해결 방식 231 | 232 | 233 | 1. Spring에서의 해결 방식 234 | 235 | 236 | 237 | 1) WebMvcConfigurer에서 정책 설정 238 | 239 | 240 | ``` 241 | @Configuration 242 | public class ApiConfig implements WebMvcConfigurer { 243 | 244 | @Override 245 | public void addCorsMappings(CorsRegistry registry) { 246 | registry.addMapping("/api/v1/**").allowedOrigins("*"); 247 | } 248 | ... 249 | ``` 250 | 251 | allowedOrigins, allowedMethods 등의 메소드를 통하여 설정 가능 252 | 253 | 254 | 255 |
256 | 257 | 258 | 259 | 260 | 261 | 2) @CrossOrigin annotation을 통하여 설정 262 | 263 | 264 | ``` 265 | @CrossOrigin(originPatterns = "*") 266 | @RestController 267 | @RequestMapping("/api/v1") 268 | public class RestProductController { 269 | ... 270 | ``` 271 | 272 | originPatterns 값을 이용하여 origin에 대한 설정이 가능하다. 273 | 274 | 275 | 276 |
277 | 278 | 279 | 280 | 2. (개발 과정에서) 브라우저에서 Proxy를 사용하여 요청을 대리하게 함으로써 CORS 위반을 우회하는 방식 281 | 282 | - CORS 정책을 사용하는 것이 브라우저이므로 가능 283 | 284 | 285 | 286 | 287 |
288 | 289 | 290 | ### Reference 291 | 292 | https://www.grabbing.me/URL-018cdd1bb4b541fab6246569244fcf93 293 | URL 구조 이해하기 294 | 295 | 296 | https://steady-coding.tistory.com/616 297 | [Spring] Spring에서 CORS 이슈를 해결하는 방법 298 | 299 | 300 | 301 | 302 | -------------------------------------------------------------------------------- /Network/2022-05-24-Web_Server,WAS,Servlet.md: -------------------------------------------------------------------------------- 1 | # Web Server, WAS, Servlet 2 | 3 | ## 1. Web Server란? 4 | 5 | ### (1) Web Server의 개념 6 | 7 | - 하드웨어 : Web 서버가 설치되어 있는 컴퓨터 8 | - 소프트웨어 : 웹 브라우저 클라이언트로부터 HTTP 요청을 받아 정적인 컨텐츠(.html .jpeg .css 등)를 제공하는 컴퓨터 프로그램 9 | - Ex) Apache Server, Nginx, IIS(Windows 전용 Web 서버) 등 10 | 11 |
12 | 13 | ### (2) Web Server의 기능 14 | 15 | - HTTP 프로토콜을 기반으로 하여 클라이언트(웹 브라우저 또는 웹 크롤러)의 요청을 서비스 하는 기능을 담당한다. 16 | - 요청에 따라 아래의 두 가지 기능 중 적절하게 선택하여 수행한다. 17 | 1. 정적인 컨텐츠 제공 : WAS를 거치지 않고 바로 자원을 제공한다. 18 | 2. 동적인 컨텐츠 제공을 위한 요청 전달 : 클라이언트의 요청(Request)을 WAS에 보내고, WAS가 처리한 결과를 클라이언트에게 전달(응답, Response)한다. 19 | 20 |
21 | 22 | ### (3) Web Server가 필요한 이유? 23 | 24 | 클라이언트한테 이미지 파일을 포함한 HTML을 보내는 과정을 생각해보자. 25 | 26 | 이미지 파일과 같은 정적인 파일들은 HTML이 클라이언트한테 보내질 때, 함께 가는 것이 아니다. 27 | 28 | 클라이언트는 HTML 문서를 먼저 받고, 그에 맞게 필요한 이미지 파일들을 다시 서버한테 요청하면, 그제서야 서버는 해당하는 이미지 파일들을 보내준다. 29 | 30 | 따라서, Web Server는 요청을 WAS까지 보내지 않고 정적인 파일들을 앞단에서 빠르게 보내준다. 31 | 32 |
33 | 34 | ## 2. WAS (Web Application Server)란? 35 | 36 | ![Untitled](https://user-images.githubusercontent.com/50768959/169973892-574352e7-9b81-47a3-bab6-42712fe9a921.png) 37 | 38 | 출처 : [https://gmlwjd9405.github.io/2018/10/27/webserver-vs-was.html](https://gmlwjd9405.github.io/2018/10/27/webserver-vs-was.html) 39 | 40 | ### (1) WAS의 개념 41 | 42 | WAS는 동적인 컨텐츠를 제공하기 위해 만들어진 Application Server로 웹 컨테이너 또는 서블릿 컨테이너라고도 불린다. 43 | 44 | 서블릿 컨테이너는 서블릿 객체를 자동으로 생성 및 호출하고, 서블릿 컨테이너가 종료될 때, 서블릿 객체들 또한 종료시켜준다. 45 | 46 | 즉, 서블릿 컨테이너는 서블릿의 생명 주기를 관리한다. 47 | 48 | Ex) Tomcat, JBoss, Jeus 등 49 | 50 |
51 | 52 | ### (2) WAS의 역할 53 | 54 | - WAS = Web Server + Web Container 55 | 56 | 주로 프로그램 실행 환경과 DB 접속 기능을 제공하고, 비즈니스 로직을 수행한다. 또한 트랜잭션 관리 기능도 제공한다. 57 | 58 |
59 | 60 | ### (3) WAS가 필요한 이유? 61 | 62 | 웹 페이지에는 정적 컨텐츠와 동적 컨텐츠가 모두 존재한다. 63 | 64 | 이 때, Web Server만을 이용한다면 사용자가 원하는 요청에 대한 결과값을 모두 미리 다 만들어 놓고 서비스를 해야한다. 하지만 이렇게 수행하기에는 자원이 절대적으로 부족하다. 65 | 66 | 따라서 WAS를 통해 요청에 맞는 비즈니스 로직을 실행 후, 그때 그때 결과를 동적으로 만들어서 제공함으로써 자원을 효율적으로 사용할 수 있다. 67 | 68 |
69 | 70 | ## 3. Web Server와 WAS를 구분하는 이유? 71 | 72 | ![Untitled 1](https://user-images.githubusercontent.com/50768959/169973929-e1661acc-c476-4406-b686-b45946db5684.png) 73 | 74 | 출처 : [https://gmlwjd9405.github.io/2018/10/27/webserver-vs-was.html](https://gmlwjd9405.github.io/2018/10/27/webserver-vs-was.html) 75 | 76 | WAS는 정적 컨텐츠, 동적 컨텐츠 모두 제공할 수 있으니까, WAS가 Web Server의 기능까지 모두 수행하면 되지 않을까? 77 | 78 | 왜 굳이 Web Server와 WAS를 구분해서 사용하는걸까? 79 | 80 | 그 이유에는 다음과 같은 것들이 있다. 81 | 82 |
83 | 84 | ### (1) 기능을 분리하여 서버 부하를 방지한다. 85 | 86 | WAS는 DB 조회 등 비즈니스 로직을 처리하느라 바쁘다. 87 | 88 | 만약에 정적 컨텐츠 요청까지 WAS가 처리한다면 서버 부하가 커지게 되고, 동적 컨텐츠의 처리가 지연됨에 따라 빨리 처리할 수 있는 정적 컨텐츠 처리까지 지연되게 된다. 89 | 90 | 이로 인해 페이지 노출 시간까지 늘어나게 된다. 91 | 92 |
93 | 94 | ### (2) 물리적으로 분리하여 보안 강화 95 | 96 | SSL에 대한 암복호화 처리에 Web Server를 사용한다. 97 | 98 |
99 | 100 | ### (3) 여러 대의 WAS를 연결 가능 101 | 102 | Web Server는 Load Balancing을 위해 사용할 수도 있는데, 이 때, fail over(장애 극복), fail back 처리에 유리하다. 103 | 104 | 특히 대용량 웹 어플리케이션의 경우 여러 개의 서버를 사용하게 되는데, Web Server와 WAS를 분리하여 무중단 운영을 위한 장애 극복에 쉽게 대응할 수 있다. 105 | 106 | 예를 들어, 앞 단의 Web Server에서 오류가 발생한 WAS를 이용하지 못하도록 한 후, WAS를 재시작함으로써 사용자는 오류를 느끼지 못하고 이용할 수 있다. 107 | 108 | **즉, 자원 이용의 효율성 및 장애 극복, 배포 및 유지 보수의 편의성을 위해 Web Server와 WAS를 분리한다.** 109 | 110 | **Web Server를 WAS 앞에 두고 필요한 WAS를 Web Server에 플러그인 형태로 설정하면 더욱 효율적인 분산 처리가 가능하다.** 111 | 112 |
113 | 114 | ## 4. Servlet이란? 115 | 116 | Servlet에 대한 정의를 위키백과에서 찾아보면 다음과 같다. 117 | 118 | 119 | **⭐ 자바 서블릿(Java Servlet)은 자바를 사용하여 웹페이지를 동적으로 생성하는 서버측 프로그램 혹은 그 사양을 말한다.** 120 | 121 | 122 | Servlet의 역할을 좀 더 정리해보자면 다음과 같다. 123 | 124 | - 클라이언트의 요청에 따라 적절한 Controller에게 요청 전달 125 | - 비즈니스 프로세스를 제외한 WAS에서 하는 기본적인 요청, 응답 제어에 관련된 처리 126 | 127 |
128 | 129 | ### (1) Servlet의 동작 방식 130 | ![Untitled 2](https://user-images.githubusercontent.com/50768959/169973954-ccff1a68-4e77-4c41-892a-405833ea593f.png) 131 | 132 | 133 | 출처 : [https://gmlwjd9405.github.io/2018/10/27/webserver-vs-was.html](https://gmlwjd9405.github.io/2018/10/27/webserver-vs-was.html) 134 | 135 | 1. Web Server는 웹 브라우저 클라이언트로부터 HTTP 요청을 받는다. 136 | 2. Web Server는 클라이언트의 요청(Request)을 WAS에 보낸다. 137 | 3. WAS는 관련된 Servlet을 메모리에 올린다. 138 | 4. WAS는 web.xml을 참조하여 해당 Servlet에 대한 Thread를 생성한다. 139 | - 매번 Thread를 생성하게 되면 속도도 늦어지고 생성 비용도 많이 들게 되고, 쓰레드 생성에 제한을 걸 수 없어서 서버가 죽을 수 있다. 140 | - 따라서, WAS는 쓰레드 풀을 사용한다. 141 | 142 | → 쓰레드가 미리 생성되어 있어 속도 및 생성 비용 면에서 장점이 있고, 쓰레드 개수에 제한을 걸 수 있기 때문에 안전한 처리가 가능하다. 143 | 144 | 5. HttpServletRequest와 HttpServletResponse 객체를 생성하여 Servlet에 전달한다. 145 | - Thread는 Servlet의 service() 메서드를 호출한다. 146 | - service() 메서드는 요청에 맞게 doGet() 또는 doPost() 메서드를 호출한다. 147 | 6. doGet() 또는 doPost() 메서드는 인자에 맞게 생성된 적절한 동적 페이지를 Response 객체에 담아 WAS에 전달한다. 148 | 7. WAS는 Response 객체를 HttpResponse 형태로 바꾸어 Web Server에 전달한다. 149 | 8. 생성된 Thread를 종료하고, HttpServletRequest와 HttpServletResponse 객체를 제거한다. 150 | 151 |
152 | 153 | ### (2) Servlet 객체 154 | 155 | 만약 Client한테서 요청이 올 때 마다 계속 Serlvet 객체를 생성한다면 굉장히 비효율적일것이다. 156 | 157 | 따라서 최초 로딩 시점에 Servlet 객체를 미리 만들어두고 재활용을 하고, 해당 Servlet 객체는 싱글톤으로 관리가 된다. 즉, 모든 Client 요청을 같은 서블릿 객체를 사용하개 된다. 158 | 159 | → 공유 변수, 상태를 관리하지 않도록 주의해야 한다. 160 | 161 |
162 | 163 | ### (3) Servlet의 생명 주기 164 | 165 | 1. init : Servlet Instance 생성 166 | - 클라이언트의 요청이 들어오면 컨테이너는 해당 서블릿이 메모리에 있는지 확인하고, 없을 경우 init()메소드를 호출하여 적재한다. 167 | - init()메소드는 처음 한번만 실행되기 때문에, 서블릿의 쓰레드에서 공통적으로 사용해야하는 것이 있다면 오버라이딩하여 구현하면 된다. 168 | - 실행 중 서블릿이 변경될 경우, 기존 서블릿을 파괴하고 init()을 통해 새로운 내용을 다시 메모리에 적재한다 169 | 2. Service : 실제 기능 수행 170 | - 클라이언트의 요청에 따라서 service()메소드를 통해 요청에 대한 응답이 doGet()가 doPost()로 분기됩니다. 171 | - 이 때, 가장 먼저 처리하는 과정으로 생성된 HttpServletRequest, HttpServletResponse에 의해 request와 response객체가 제공됩니다. 172 | 3. Destroy : Servlet Instance 삭제 173 | - 컨테이너가 서블릿에 종료 요청을 하면 destroy()메소드가 호출된다. 174 | - 종료시에 처리해야하는 작업들은 destroy()메소드를 오버라이딩하여 구현하면 된다. 175 | - 보통 서블릿 컨테이너가 종료되는 시점에 호출하며, 특정 servlet 로드/언로드 시에도 사용된다. 176 | -------------------------------------------------------------------------------- /Network/2022-06-09-WebSocket.md: -------------------------------------------------------------------------------- 1 | # Web Socket 2 | 3 | ## 웹 소켓이란? 4 | 5 | 9 | 10 | - **실시간 알림, 실시간 채팅** 등 실시간이라는 키워드가 들어가는 기능들을 위해서는 대부분 웹 소켓 기술이 필요하다. 11 | 12 | ## HTTP VS 웹소켓 13 | 14 | ### HTTP 15 | 16 | - 비연결성 (connectionless) 17 | - HTTP는 클라이언트와 서버간 접속을 유지하지 않는다. 18 | - 단방향 통신 19 | - 서버에서 클라이언트로의 요청이 불가능하다. 20 | 21 | ### 웹소켓 22 | 23 | - 양방향 통신 24 | - 데이터 송수신을 동시에 할 수 있다. 25 | - Client와 Server가 서로 원할 때 데이터를 주고 받는다. 26 | - 연결지향 27 | 28 | > 초기 웹의 탄생 목적은 문서 전달과 하이퍼링크를 통한 문서 연결이였다. 29 | 웹을 위한 HTTP 프로토콜은 실시간 채팅과 같은 기능에 매우 부적합한 모델이다. 30 | > 31 | 32 | ## HTTP 실시간성 기술 33 | 34 | HTTP를 이용해서 실시간성을 구현할 수 있는 기술. 35 | 36 | ### (1) Polling 37 | 38 | - 서버로 **주기적으로 요청하여 결과를 확인**하는 방식 39 | - 값이 없더라도 빈 값을 응답 받는다. 40 | - 요청 주기 짧으면 불필요한 요청/응답 트래픽이 많이 발생한다. 41 | - 요청에 대한 서부 부담이 크지 않거나 실시간 메시지 전달이 크게 중요하지 않는 서비스에 적합 42 | 43 | ![https://d2.naver.com/content/images/2015/06/helloworld-1052-2.png](https://d2.naver.com/content/images/2015/06/helloworld-1052-2.png) 44 | 45 | ### (2) Long Polling 46 | 47 | - 요청에 대한 응답을 **서버 이벤트 발생 시점에 받는 방식** 48 | - polling 방식에 비해 불필요한 트래픽을 덜 유발한다. 49 | - 실시간 메시지 전달이 중요하지만 서버의 상태 변경이 빈번하지 않는 서비스에 적합 50 | 51 | ![https://d2.naver.com/content/images/2015/06/helloworld-1052-3.png](https://d2.naver.com/content/images/2015/06/helloworld-1052-3.png) 52 | 53 | ### (3) HTTP Streaming 54 | 55 | - 서버에 요청 보내고 끊기지 않은 연결상태에서 끊임없이 데이터 수신 56 | - 응답마다 다시 요청해야 하는 Long Polling에 비해 효율적이며, 서버의 상태 변경이 잦은 경우에 유리하다. 57 | - 연결을 길게 맺고 있는 경우 유효성 관리 등의 부담이 발생한다. 58 | - 보통 특정 시간을 주기로 연결을 재설정하도록 구현하는 방식으로 해결 59 | 60 | ![https://d2.naver.com/content/images/2015/06/helloworld-1052-4.png](https://d2.naver.com/content/images/2015/06/helloworld-1052-4.png) 61 | 62 | > 세가지 방법 다 HTTP를 통신하기에 **Request와 Response 둘다 Header가 불필요하게 크다.** (실시간 채팅에는 부적합) 63 | > 64 | > - Protocol에 대한 스펙의 변화가 필요하다. 65 | 66 | ## 웹 소켓의 동작 방식 67 | 68 | ![https://github.com/NKLCWDT/cs/raw/main/images/websocket.png](https://github.com/NKLCWDT/cs/raw/main/images/websocket.png) 69 | 70 | ### 1. Opening Handshake 71 | 72 | - 웹 소켓은 전이중 통신이므로, **연속적인 데이터 전송의 신뢰성을 보장**하기 위해 Handshake 과정을 진행한다. 73 | - 기존의 다른 TCP 기반의 프로토콜은 TCP layer에서의 Handshake를 통해 연결을 수립하는 반면, 웹 소켓은 **HTTP 요청 기반으로 Handshake 과정**을 거쳐 연결을 수립한다. 74 | 75 | (1) 웹 소켓은 연결을 수립하기 위해 `Upgrade 헤더` 와 `Connection 헤더` 를 포함하는 HTTP 요청을 보낸다. 76 | 77 | ![https://user-images.githubusercontent.com/50273712/129447412-30e32809-b1fe-4e95-9d7a-85553f3ab92b.png](https://user-images.githubusercontent.com/50273712/129447412-30e32809-b1fe-4e95-9d7a-85553f3ab92b.png) 78 | 79 | - **Upgrade** 80 | - 현재 protocol에서 다른 protocol로 업그레이드 또는 변경 할때 사용한다. (websocket으로 변경) 81 | - 이 값이 없거나 다른 값이면 cross-protocol attack 이라고 간주하여 웹 소켓 접속을 중지시킨다. 82 | - **Connection** 83 | - 현재의 전송 완료 후 network를 유지할 것인지에 대한 정보 84 | - upgrade 값이 없거나 다른 값이면 웹 소켓 연결 중지 85 | - Sec-WebSocket-Key 86 | - 유효한 요청인지 확인하기 위해 사용하는 키 값 87 | - Sec-webSocket-Protocol 88 | - 사용하고자 하는 하나 이상의 웹 소켓 프로토콜 지정 89 | - Origin 90 | - 클라이언트의 주소 91 | 92 | (2) 통상적인 상태 코드 200 대신, **웹 소켓 서버의 응답**은 다음과 같다. 93 | 94 | ![https://user-images.githubusercontent.com/50273712/129448362-0ada9130-1181-4d3b-ac4b-33bd4130b00d.png](https://user-images.githubusercontent.com/50273712/129448362-0ada9130-1181-4d3b-ac4b-33bd4130b00d.png) 95 | 96 | - 101 Switching Protocols 97 | - “프로토콜 전환”을 서버가 승인했음을 알리는 코드 98 | - Upgrade와 Connection은 동일하게 넣어주어야 한다. 99 | - Sec-WebSocket-Accept 100 | - 클라이언트로부터 받은 Sec-WebSocket-Key를 사용하여 계산된 값 101 | - 클라이언트에서 계산한 값과 일치하지 않으면 연결 수립하지 않는다. 102 | 103 | 108 | 109 | ### 2. Data transfer 110 | 111 | - 웹소켓 연결수립이 되면 데이터 전송이 시작된다. 112 | - Client와 Server가 message라는 개념으로 데이터 주고 받는다. 113 | - 프레임으로 구성된 메시지라는 논리적 단위로 송수신 114 | 115 | ### 3. Closing Handshake 116 | 117 | - 클라이언트나 서버가 커넥션 종료를 위한 컨트롤 프레임 전송 118 | - 웹 소켓 연결은 주로 새로고침이나 창 닫기 등의 이벤트 발생 시 닫힌다. 119 | 120 | ## 웹 소켓 프로토콜 특징 121 | 122 | - 최초 접속에서만 HTTP 프로토콜 위에서 handshaking을 하기 때문에 HTTP header를 사용한다. 123 | - 웹소켓을 위한 별도의 포트는 없으면, 기존 포트(http-80, https-443)을 사용 124 | - 프레임으로 구성된 메시지라는 논리적 단위로 송수신 125 | - **메시지에 포함될 수 있는 교환 가능한 메시지는 텍스트와 바이너리** 126 | 127 | ## 웹소켓 한계 128 | 129 | - 웹소켓은 HTML5 표준 기술이다. 130 | - HTML5 이전의 기술로 구현된 서비스에서 웹 소켓처럼 사용할 수 있도록 도와주는 기술 131 | - Socket.io, SockJS 132 | - 브라우저와 웹 서버의 종류와 버전을 파악하여 가장 적합한 기술을 선택하여 사용하는 방식 133 | - WebSocket은 문자열과 바이너리 두 가지 유형의 메시지 타입만 받는다. 134 | - 메세지의 내용에 대해서는 정의하지 않는다. 135 | - 해당 메시지가 어떤 요청인지 136 | - 어떤 포맷으로 오는지 137 | - 메시지 통신 과정을 어떻게 처리해야 하는지 138 | - 때문에 WebSocket방식은 sub-protocols을 사용해서 주고 받는 메시지의 형태를 약속하는 경우가 많다. 139 | - STOMP 140 | 141 | ### Reference 142 | 143 | [https://github.com/NKLCWDT/cs/blob/main/Network/웹소켓.md](https://github.com/NKLCWDT/cs/blob/main/Network/%EC%9B%B9%EC%86%8C%EC%BC%93.md) 144 | 145 | [https://tecoble.techcourse.co.kr/post/2021-08-14-web-socket/](https://tecoble.techcourse.co.kr/post/2021-08-14-web-socket/) -------------------------------------------------------------------------------- /Network/2022-06-16-DNS, Round-Robin.md: -------------------------------------------------------------------------------- 1 | ## DNS(Domain Name System) 2 | 3 | - IP 주소 테이블을 가지고 있는 서버 4 | - 사용자가 웹 사이트에 접속하기 `google.com` 과 같은 도메인을 입력하지만, 원칙적으로는 IP 주소를 통하여 접속을 해야함. DNS는 여기서 도메인이 가리키는 IP 주소를 브라우저에게 반환하여 접속을 가능하게 함. 5 | 6 | ![image](https://user-images.githubusercontent.com/72663337/175243348-e3edf541-4f9a-4791-8c6b-59082af986a5.png) 7 | 8 | `DNS 서버(https://www.geeksforgeeks.org/working-of-domain-name-system-dns-server/)` 9 | 10 | 11 | 12 | 13 | ### Round Robin 14 | - 프로세스에 CPU를 할당하는 스케줄링 기법 중 하나. 15 | - 시분할 시스템, 일정한 시간단위로 CPU 할당 16 | - 프로세스 간의 우선순위를 두지 않음. 17 | 18 | 19 | ### DNS의 round robin 20 | - DNS 서버 구성되는 방식 중 하나. 21 | - 도메인에 대한 IP 요청 시 round-robin 방식을 통하여 IP가 반환 22 | - 요청 시마다 DNS에서 반환되는 IP가 바뀜 23 | - DNS를 통하여 서버 트래픽을 분산시킴. 24 | - 로드 밸런서와 같은 부하를 분산해 주는 중간 장비가 필요하지 않다. (자동적으로 반환되는 IP 값이 바뀌며 부하가 분산되기 때문) 25 | 26 | 27 | 28 | ![image](https://user-images.githubusercontent.com/72663337/175243527-14d77474-756e-4057-9752-1510ee60fe2f.png) 29 | 30 | 31 | `DNS Round Robin (https://byeongyeon.tistory.com/80)` 32 | 33 | 34 | 35 | 36 | ### 단점 37 | - 균등한 트래픽의 분산이 어려움 38 | - 도메인에 대한 IP 주소를 요청하는 브라우저 등에서 DNS로부터 전달받은 주소 결과를 캐싱 -> 다음 요청 시에 DNS에서 반환되는 IP 주소 값이 변하고, 따라서 웹 브라우저에서 사용하는 IP 주소도 바뀌어야 하지만 캐싱되어 있는 값 때문에 그렇지 못함. 39 | - 한 클라이언트에 대한 요청은 분산될 수 있지만, 여러 사람이 요청을 보내는 경우에는 균등한 분산이 이루어진다고 보장할 수 없음 40 | - 서버가 다운되어도 확인이 불가능함 41 | - 로드밸런서의 경우에는 서버들의 상태를 관찰하며 서버가 제대로 작동하는지 여부를 판단하며 분산을 조절할 수 있는데, DNS에서는 이런 작업을 할 수 없음 42 | 43 | 44 | 45 | 46 | 47 | 48 | ### 극복 방법 49 | 50 | 1. Round robin 방식을 보완한 방식 51 | 52 | 53 | #### 다중화 구성 방식(Synchronous Time-Division Multiplexing) 54 | 55 | ex : AWS Route53, Dyn DNS 서비스 56 | 57 | AP 서버에 VIP(Virtual IP)를 부여하여 다중화를 구성하고, 58 | 59 | 각 AP 서버를 **Health check** 후 이상이 감지되면 VIP를 정상 AP 서버로 인계하는 방식을 사용함. 60 | 61 | 62 | 63 | -> DNS 서버에 실시간으로 서버의 상태를 확인할 수 있는 값을 추가하여, 이 값을 통하여 서버 상태를 확인(Health check)하고 우회 루트를 제공하거나, 에러를 전송하는 방식 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 2. 다른 DNS 스케줄링 알고리즘 72 | #### 가중치 편성 방식 알고리즘(Weighted round robin) 73 | 74 | 각 웹 서버에 가중치를 부여하여 분산 비율을 정함. 75 | 76 | 처리 능력이 높을수록 가중치가 크게 설정됨. 77 | 78 | 79 | 80 | #### Least Connnection 81 | 82 | 접속 클라이언트 수가 가장 적은 서버의 IP 주소를 반환함. 83 | 84 | 로드밸런서가 접속 정보를 알려주는 작업을 수행해야 함. 85 | 86 | 87 |
88 | 89 | 90 | 91 | ### 결론 92 | 93 | 여러 웹 서버로 트래픽을 분산시키는 단순하고 편리한 방식. 94 | 95 | 가용성이 필요한(항상 서비스되어야 하는) 서비스에 round robin 방식을 사용하는 것은 좋지 않다. 96 | 97 | 가용성이 요구되는 경우, 다중화 구성 방식이 적용되는 게 권장된다. 98 | 99 | 100 | 101 | 102 | 103 | 104 | #### Reference 105 | 106 | https://velog.io/@dbstjrwnekd/DNS-Round-Robin 107 | 108 | 109 | 110 | 111 | 112 | http://dailusia.blog.fc2.com/blog-entry-362.html 113 | 114 | -------------------------------------------------------------------------------- /Network/2022-06-16-Redirect,Forward.md: -------------------------------------------------------------------------------- 1 | # Redirect & Forward 2 | 3 | ## 리다이렉트 (Redirect) 4 | 5 | 9 | 10 | - 리다이렉트가 일어나면 URL 주소가 바뀌면서 다시 접속되는 것을 확인할 수 있다. 11 | 12 | ![https://mdn.mozillademos.org/files/13785/HTTPRedirect.png](https://mdn.mozillademos.org/files/13785/HTTPRedirect.png) 13 | 14 | - Client가 Server에 Resource를 요청한다. 15 | - Server는 **HTTP 응답 상태코드 3XX**와 함께 **Location 헤더에 Redirect 주소**를 받아서 보낸다. 16 | - Client는 새로운 주소값으로 다시 Resource를 요청한다. 17 | - 클라이언트는 HTTP 응답 상태코드 3XX를 통해 리다이렉트를 인지하고 Location 헤더를 통해서 Redirect 경로로 재요청한다. 18 | - Server는 새로운 Resource를 응답한다. 19 | 20 | ### Redirection & HTTP Response Status Code 21 | 22 | - HTTP Response Status Code는 요청에 대한 웹서버의 응답을 나타내는 코드를 말한다. 23 | - 3XX 모두 사용자를 새로운 URL로 이동시키는 코드이다. 24 | 25 | **1. 영구 리다이렉션 (301, 308)** 26 | 27 | - 리소스의 URI가 영구적으로 이동 28 | - ex) /members → /users 29 | - 원래의 URL을 사용하지X 30 | - 301 (Moved permanently) 31 | - 리다이렉트시 요청 메서드가 GET으로 변하고, 본문이 제거될 수 있다. 32 | - 308 (Permanent Redirect) 33 | - 리다이렉트시 요청 메서드와 본문 유지 (처음 POST를 보내면 리다이렉트도 POST 유지) 34 | 35 | **2. 일시적인 리다이렉션 (302, 307, 303)** 36 | 37 | - 리소스의 URI가 일시적으로 변경 38 | - 주문 완료 후 주문 내역 화면으로 이동 (Post, Redirect, Get) 39 | - 302 (Found) 40 | - 리다이렉트시 요청 메서드가 GET으로 변하고, 본문이 제거될 수 있다. 41 | - 307 (Temporary Redirect) 42 | - 리다이렉트시 요청 메서드와 본문 유지 43 | - 303 (See Other) 44 | - 리다이렉트시 요청 메서드가 Get으로 변경 45 | 46 | ## Forward 47 | 48 | 52 | 53 | - 서버에서 포워딩된 URL의 리소스를 확인하여 클라이언트에 응답한다. 54 | - 요청된 URL의 변화가 없다. 55 | - 클라이언트 입장에서는 Forward가 일어났는지 모른다. 56 | 57 | ![https://nesoy.github.io/assets/posts/20180409/2.png](https://nesoy.github.io/assets/posts/20180409/2.png) 58 | 59 | - Client가 Server에 Resource를 요청합니다. 60 | - Server는 Web Container에 의해 LoginServlet에서 HelloServlet로 forward하게 된다. 61 | - Server는 최종적으로 Hello의 결과를 응답하게 된다. 62 | - Client는 한번의 요청으로 결과를 받을 수 있다. 63 | 64 | > Forward는 Web Contrainer의 내부에서 이동하기 때문에 request와 response 객체를 공유할 수 있다. (내부에서 자원을 공유) 65 | > 66 | 67 | ## Spring에서의 Redirect & Forward 68 | 69 | ### 1. Redirect 70 | 71 | - `String` 72 | - 접두사 “redirect:”와 함께 반환 되면 `UrlBasedViewResolver` 는 이를 리다이렉션이 발생해야 한다는 특별한 표시로 인식한다. 73 | - `ModelAndView` 74 | - `httpServletResponse.sendRedirect()` 75 | - `RedirectView` 76 | - `ResponseEntity` 77 | 78 | ```java 79 | @Controller 80 | public class RedirectController { 81 | 82 | @GetMapping("/redirect1") 83 | public String redirect1() { 84 | return "redirect:https://www.naver.com"; 85 | } 86 | 87 | @GetMapping("/redirect2") 88 | public ModelAndView redirect2() { 89 | return new ModelAndView("redirect:https://www.naver.com"); 90 | } 91 | 92 | @GetMapping("/redirect3") 93 | public RedirectView redirect3() { 94 | RedirectView redirectView = new RedirectView("https://www.naver.com"); 95 | return redirectView; 96 | } 97 | 98 | @GetMapping("/redirect4") 99 | public ResponseEntity redirect4() { 100 | return ResponseEntity.status(HttpStatus.FOUND).location(URI.create("https://www.naver.com")).build(); 101 | } 102 | 103 | @GetMapping("/redirect5") 104 | public void redirect5(HttpServletResponse httpServletResponse) throws IOException { 105 | httpServletResponse.sendRedirect("https://www.naver.com"); 106 | } 107 | 108 | } 109 | ``` 110 | 111 | - @Controller 그리고 @RestController에서 모두 사용가능한 방식이다. 112 | - String 방식 제외 113 | - String 방식은 바로 json 문자열로 직렬화되어 Return 되어진다. 114 | 115 | > @Controller VS @RestController 116 | - @Controller 117 | String, ModelAndView Return 타입인 경우 해당 문자열 ViewName을 가지는 html을 찾아서 반환한다. 118 | - @RestController 119 | Return String - json 문자열로 직렬화되어 Return 120 | Return ModelAndView - viewName을 가지는 html 파일이 있는 경우 찾아서 반환 121 | > 122 | 123 | ### 2. Forward 124 | 125 | - `String` 126 | - 접두사 “forward:”와 함께 반환 되면 `UrlBasedViewResolver` 는 이를 리다이렉션이 발생해야 한다는 특별한 표시로 인식한다. 127 | - `ModelAndView` 128 | - `InternalResourceView` 129 | 130 | ```java 131 | @Controller 132 | public class ForwardController { 133 | 134 | @GetMapping("/hello") 135 | public String hello() { 136 | return "index"; 137 | } 138 | 139 | @GetMapping("/forward1") 140 | public String forward1() { 141 | return "forward:/hello"; 142 | } 143 | 144 | @GetMapping("/forward2") 145 | public ModelAndView forward2() { 146 | return new ModelAndView("forward:/hello"); 147 | } 148 | 149 | @GetMapping("/forward3") 150 | public InternalResourceView forward3(HttpServletResponse httpServletResponse) throws IOException { 151 | return new InternalResourceView("/hello"); 152 | } 153 | 154 | } 155 | ``` 156 | 157 | ### 3. Forward가 일어나는 위치는 어디일까? 158 | 159 | **DispatcherServlet** 160 | 161 | ![https://blog.kakaocdn.net/dn/Sz6DV/btq9zjRpUGv/68Fw4fZtDwaNCZiCFx57oK/img.png](https://blog.kakaocdn.net/dn/Sz6DV/btq9zjRpUGv/68Fw4fZtDwaNCZiCFx57oK/img.png) 162 | 163 | - 포워드의 경우 각각의 URL에 대해서 각각 인터셉터 통과하는 반면, 필터는 처음 요청했던 URL만 통과한다. 164 | 165 | ### 4. String, ModelAndView로 반환하는 경우 Spring은 redirect, forward를 어떻게 인식할까? 166 | 167 | - String은 HandlerAdapter에서 ModelAndView로 감싸진다. 168 | 169 | ```java 170 | public class UrlBasedViewResolver extends AbstractCachingViewResolver implements Ordered { 171 | public static final String REDIRECT_URL_PREFIX = "redirect:"; 172 | public static final String FORWARD_URL_PREFIX = "forward:"; 173 | 174 | protected View createView(String viewName, Locale locale) throws Exception { 175 | if (!this.canHandle(viewName, locale)) { 176 | return null; 177 | } else { 178 | String forwardUrl; 179 | if (viewName.startsWith("redirect:")) { 180 | forwardUrl = viewName.substring("redirect:".length()); 181 | RedirectView view = new RedirectView(forwardUrl, this.isRedirectContextRelative(), this.isRedirectHttp10Compatible()); 182 | String[] hosts = this.getRedirectHosts(); 183 | if (hosts != null) { 184 | view.setHosts(hosts); 185 | } 186 | 187 | return this.applyLifecycleMethods("redirect:", view); 188 | } else if (viewName.startsWith("forward:")) { 189 | forwardUrl = viewName.substring("forward:".length()); 190 | InternalResourceView view = new InternalResourceView(forwardUrl); 191 | return this.applyLifecycleMethods("forward:", view); 192 | } else { 193 | return super.createView(viewName, locale); 194 | } 195 | } 196 | } 197 | } 198 | ``` 199 | 200 | - `redirect:` 으로 시작하는 경우 `RedirectView` 으로 만들어서 리턴 201 | - `forward:` 으로 시작하는 경우 `InternalResourceView` 으로 만들어서 리턴 202 | 203 | ![https://blog.kakaocdn.net/dn/wwwmy/btrfqEhmPHM/NoO6akCJOMkVZQPyIU1zQk/img.png](https://blog.kakaocdn.net/dn/wwwmy/btrfqEhmPHM/NoO6akCJOMkVZQPyIU1zQk/img.png) 204 | 205 | - 즉, ModelAndView 객체는 ViewResovler(`UrlBasedViewResolver`)를 통해 View(`RedirectView` , `InternalResourceView`)로 반환된다. 206 | 207 | ## Reference 208 | 209 | [https://developer.mozilla.org/ko/docs/Web/HTTP/Redirections](https://developer.mozilla.org/ko/docs/Web/HTTP/Redirections) 210 | 211 | [https://www.baeldung.com/spring-redirect-and-forward](https://www.baeldung.com/spring-redirect-and-forward) -------------------------------------------------------------------------------- /Network/2022-07-12-HTTP3.md: -------------------------------------------------------------------------------- 1 | # HTTP/3 2 | 3 | **HTTP/3** : QUIC(Quick UDP Internet Connections)프로토콜 위에서 돌아가는 HTTP 4 | ![](images/http3.png) 5 | 6 |
7 |
8 | 9 | 10 | ## TCP의 단점 11 | ![](images/updtcp.png) 12 | 13 | 신뢰성을 보장하기 위해 속도가 느립니다. 여기서 신뢰성은 송신자가 보낸 패킷을 순서에 맞게 그리고 유실없이 수신자가 받는 것을 의미합니다. 이렇게 신뢰성을 보장하기 위해서 TCP는 아래와 같이 여러한 장치들이 마련되어있습니다. 14 | 15 | 16 | - 3 Way Handshake 17 | : 통신을 시작하고 종료할 때 미리 서버에 물어보고 연결을 하고 시작합니다 18 | 19 | - HOLB(Head of line Blocking) : HTTP/2를 포함해 이전버전들도 가지고 있는 문제로 패킷이 순서를 지켜서 전달되야하다보니 중간에 문제가 생기면 전체 패킷이 늦어지게 됩니다. 20 | 21 |
22 |
23 | 24 | 속도를 높이기 위해서는 이런 것들을 건드려야하는데 TCP가 생길때부터 정의된 표준이기 때문에 제한사항이 많습니다. 즉 원하는대로 뜯어고치기가 쉽지 않았던 것입니다! 결국 그래서 선택한 것이 UDP입니다. 25 | 26 |
27 |
28 |
29 |
30 | 31 | 32 | ## UDP기반 QUIC프로토콜 채택 33 | - QUIC : TCP가 가지고 있는 여러 문제들을 해결하고 속도의 한계를 뛰어넘고자 구글이 개발한 UDP 기반의 프로토콜 34 | 35 | - UDP : 데이터그램 방식을 사용하는 프로토콜이기 때문에 패킷간의 순서가 없이 독립적입니다. 목적지만 정해져있을 뿐 어떤 경로를 타서 목적지로 가는지는 중요하지 않기 때문에 연결설정을 하지 않습니다. 즉 3 Way Handshake과정이 필요가 없습니다. 36 | 37 | 38 | 그렇다면 UDP를 사용하면 속도는 챙기고 신뢰성은 버리는 것인가??? NO!!! 39 | 40 |

41 |
42 |
43 | 44 | ## UDP 커스터마이징 및 장점 45 | UDP는 하얀 도화지 같은 프로토콜입니다. 즉 UDP는 데이터 전송 이외에 아무것도 정해지지않은 프로토콜입니다. UDP자체는 신뢰성을 보장하지 않지만 어떻게 커스터마이징 하냐에 따라 달라질 수 있습니다. 46 | 47 | 구글이 커스터마이징한 QUIC의 TCP대비 장점을 살펴보겠습니다 48 | 49 |
50 |
51 | 52 | ### 1. 연결 설정 시 레이턴시 감소 53 | 54 | ![](images/handshake.gif) 55 | 클라이언트가 보낸 요청을 서버가 처리하고 다시 클라이언트가 받는 것까지를 RTT(Round Trip Time)이라고 합니다. TCP + TLS 는 연결시에 1RTT + 2RTT로 총 3 RTT가 필요합니다. 반면에 QUIC는 첫번째 핸드쉐이크 때 연결에 필요한 정보와 데이터를 한번에 줘버립니다. 따라서 서버가 응답만 온다면 연결이 된 것으로 보고 총 1RTT만 필요로 합니다. 56 | 57 | 이게 가능한 이유는 세션키를 교환하기 전에 서버의 Connection ID를 사용하여 생성한 특별한 키인 `초기화 키(Initial Key)`를 사용하여 통신을 암호화하기 때문입니다. 58 | 59 | 물론 이후의 TLS 1.3이 나오면서 TLS도 위와 비슷하게 동작합니다. 60 | 61 | 62 |
63 |
64 | 65 | 66 | ### 2. 패킷 손실 감지에 걸리는 시간 단축 67 | TCP는 통신과정에서 생긴 에러를 ARQ 방식 즉, 재전송을 통해서 에러를 해결합니다. 그 중에서도 `Stop and Wait ARQ` 를 사용하며 이 방법은 패킷을 전송하고 일정시간이 지나도 적절한 답변이 오지 않으면 패킷을 다시보내는 방식입니다. 68 | 69 | QUIC도 ARQ방식으로 패킷손실을 감지하고 TCP오 유사하게 동작하지만 몇가지 개선점이 있습니다. 70 | 71 | 그중에서 대표적인 것은 타임아웃시간을 동적으로 계산할 때 정확한 RTT를 측정하기 위해 ACK가 어떤 응답에 대한 것인지 알기위해 타임스탬프를 찍어주는 것을 개선시킨 것입니다. QUIC는 이를 위한 공간을 헤더에 따로 만들고 패킷마다 고유한 번호를 부여해서 순서를 파악합니다. 이를 통해 패킷손실감지에 걸리는 시간을 단축합니다. 72 | 73 | 74 | 75 |
76 |
77 | 78 | ### 3. 클라이언트의 IP가 바뀌어도 연결이 유지됨 79 | TCP의 경우 송신자와 수신자의 IP주소 포트를 통해서 연결을 식별하기 때문에 중간에 클라이언트 IP가 바뀌기라도 하면 연결이 끊기고 다시 핸드쉐이크과정을 거쳐야합니다. 80 | 81 | 반면에 QUIC는 Connection ID를 통해서 연결을 식별합닌다. Connection ID는 랜덤한 값일 뿐, 클라이언트의 IP와는 전혀 무관한 데이터이기 때문에 클라이언트의 IP가 변경되더라도 기존의 연결을 계속 유지할 수 있습니다. 이는 새로 연결을 생성할 때 거쳐야하는 핸드쉐이크 과정을 생략할 수 있게합니다. 82 | 83 | 84 |
85 |
86 |
87 |
88 | 89 | ## 앞으로.. 90 | QUIC의 장점만 살펴보았지만 사실 아직 부족한 점과 우려되는 점들이 많은 프로토콜입니다. 하지만 벌써 웹사이트 중에 25.2% 정도가 HTTP/3를 사용하고 있습니다. 앞으로 개선해나가며 발전된다면 곧 HTTP/2를 따라잡을 수 있지않을까합니다. 91 | 92 |
93 |
94 |
95 |
96 | 97 | ### 참고 98 | - https://evan-moon.github.io/2019/10/08/what-is-http3/ 99 | - https://donggov.tistory.com/188 100 | 101 | 102 | 103 | -------------------------------------------------------------------------------- /Network/2022-07-18-VPC.md: -------------------------------------------------------------------------------- 1 | # VPC 2 |
3 | 4 | ## VPC개념 5 | VPC는 Virtual Private Cloud의 약자이며 사용자가 리소스를 구분해서 관리할 수 있습니다. VPC를 사용했을 때 좋은 이유는 아래의 사진을 보면 알 수 있습니다. 6 | 7 | VPC적용전 8 | 9 | ![](https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbj02NL%2Fbtq4dcQTFtq%2F300daUZ8ikEtZGPdhnU30k%2Fimg.png) 10 | 11 | 12 | VPC적용후 13 | 14 | ![](https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcZd3VV%2Fbtq4eKGt56L%2FdVWt2cbgpb15IkJUqLWiVk%2Fimg.png) 15 | 16 | 17 | 확실히 깔끔하게 정리되어서 리소스(Instance)들이 관리되는 것이 보이죠? VPC가 없었다면 리소스끼리 구분없이 관리되기 때문에 시스템 복잡도가 큽니다. 인터넷과의 통신도 훨씬 비효율적일 것입니다. 18 | 19 |


20 | 21 | ## 구성요소 22 |
23 | 24 | ### 1. VPC 25 | VPC는 독립적인 하나의 네트워크를 구성하는 가장큰 단위입니다. Region에 종속되며 RFC1918이라는 사설IP대역에 맞춰 설계해야합니다. 26 | 27 | - 10.0.0.0 ~ 10.255.255.255(10/8 prefix) 28 | 29 | - 172.16.0.0 ~ 172.31.255.255(182.16/12 prefix) 30 | 31 | - 192.168.0.0 ~ 192.168.255.255(192.168/16 prefix) 32 | 33 | 각 대역폭마다 사설IP의 prefix가 다릅니다. 예를 들어 첫번째에 해당되는 경우 IP의 첫번재 영역을 00001010.으로 고정시키고 나머지 주소에 해당되는 IP주소를 할당할 수 있습니다. 34 | 35 | VPC에서 한번 설정된 IP대역은 수정할 수 없으며 각각의 VPC는 독립적이기 때문에 서로 통신할 수 없습니다. 36 | 37 |


38 | 39 | ### 2. Subnet(서브넷) 40 | VPC의 IP주소를 나누어 리소스가 배치되는 물리적인 주소 범위를 뜻합니다. VPC를 나눴다고 생각하면 됩니다. 하나의 가용영역에 하나의 서브넷이 연결됩니다. 41 | 42 | 서브넷은 크게 Public과 Private로 나뉩니다. 인터넷과 연결되어있는 Public Subnet은 아웃바운드, 인바운드로 트래픽을 주고받습니다. 반면 Private Subnet은 인터넷과 연결되어있지 않습니다. 43 | 44 |


45 | 46 | ### 3. Router(라우터) 47 | VPC안에서 네트워크 요청을 처리하기위해 거쳐가는 거점이며 Routing Table에는 각 라우터에서 길을 찾아갈 수 있는 정보가 쓰여있습니다. 따라서 요청이 발생하면 가장 먼저 라우터로 트래픽을 전송합니다. 일반적으로 VPC 내부 네트워크에 해당하는 주소는 local로 향합니다. 48 | 49 | ![](https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdesaOh%2Fbtq4dMxY76n%2FJt4C5umce4a59mKUfoIzeK%2Fimg.png) 50 | 51 |


52 | 53 | ### 4. Internet Gateway(인터넷 게이트웨이) 54 | VPC 리소스가 인터넷과 통시을 하기위해 인터넷과 VPC를 연결하는 게이트웨이입니다. Public Subnet의 리소스들이 여기에 해당됩니다. 이런 요청은 라우터에 도착해서 먼저 목적지 IP주소가 VPC내부인지 확인합니다. 이에 해당하지 않으면 외부로 전송되어야하기 때문에 IGW(internet gateway)로 보내집니다. 55 | 56 | ![](https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbazdRh%2Fbtq4ejhZXir%2FJSixVUkarIcZ68hzfYiiQK%2Fimg.png) 57 | 58 |

59 | 이렇게 Public은 인터넷과 직접 통신을 하기 때문에 보안에 신경을 써줘야합니다. 따라서 크게 두가지를 통해서 리소스에 대한 인바운드, 아웃바운드 트래픽의 보안정책을 설정합니다. 60 | 61 | - **ACL(Access Control Layer)** 62 | : stateless하게 동작하며 기본적으로 모든 트래픽이 허용되어있기 때문에 불필요한 트래픽 차단필요합니다. Subnet단위로 설정이 가능합니다. 63 | 64 |
65 | 66 | - **보안그룹** 67 | : 모든 접근을 차단하는 것이 기본설정. 따라서 필요한 설정을 추가해줘야합니다. Subnet전체와 각각의 Instance에서도 설정이 가능합니다. 68 | 69 |

70 | 71 | ![](https://2482909075-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M6ivT9AfNVmiT1Q6B2U%2Fsync%2F3b772d88407ba5c4f326b76cc177309127a97938.png?generation=1602351053822314&alt=media) 72 | 73 | > 두 보안설정이 충돌하면 보안그룹이 더 높은 우선순위를 가집니다. 74 | 75 | 76 |


77 | 78 | ### 5. NAT Gateway(나트 게이트웨이) 79 | Private Subnet의 트래픽중 인터넷과 통신이 필요한 경우 NAT gateway를 활용합니다. Private는 직접 통신은 불가능하기 때문에 Public에 속한 인스턴스로 전송해서 인터넷과 접속하도록 우회해야합니다. Private에서 온 요청이 VPC외부를 목적지로 한다면 Public에 존재하는 NAT gateway로 트래픽을 전송합니다. 그러면 Public에서 이를 처리해줍니다. 이렇게 Private는 아웃바운드로만 통신이 가능합니다. 80 | 81 | 82 | ![](https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FLEKCb%2Fbtq4f9M6s6v%2FOh1stJ4lyLrVGwXzkF6d80%2Fimg.png) 83 | -------------------------------------------------------------------------------- /Network/2022-07-19-Domain,DNS_Server.md: -------------------------------------------------------------------------------- 1 | ## Domain 이란? 2 | 3 | 7 | 8 | - IP 주소는 12자리의 숫자로 되어 있기 때문에 사람이 외우기 힘들다는 단점이 있다. 9 | - 이러한 문제를 해결하기 위해 IP 주소를 사람이 기억하기 쉬운 문자로 표현한 주소 10 | 11 | ![https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb0r55g%2FbtqN014kHQs%2FTTCKKIQVaY5aj5Pp8mIZQK%2Fimg.png](https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb0r55g%2FbtqN014kHQs%2FTTCKKIQVaY5aj5Pp8mIZQK%2Fimg.png) 12 | 13 | - 도메인은 ‘naver.com’처럼 몇 개의 의미있는 문자들과 .의 조합으로 구성된다. 14 | 15 | > IP 주소 16 | - IP 주소란 많은 컴퓨터들이 인터넷 상에서 서로를 인식하기 위해 지정받은 식별용 번호 17 | > 18 | 19 | ## DNS (Domain Name System) 20 | 21 | 25 | 26 | - 도메인은 사람의 편의성을 위해 만든 주소이므로 실제로는 컴퓨터가 이해할 수 있는 IP 주소로 변환하는 작업이 필요하다. 27 | - 이때, 사용할 수 있도록 미리 도메인 네임과 함께 해당하는 IP 주소값을 한 쌍으로 저장하고 있는 일종의 데이터베이스 이다. 28 | - 사용자가 웹 브라우저에 도메인 이름을 입력했을 때, 이름에 대한 IP 주소로 변환 요청을 **쿼리**라고 부른다. 29 | 30 | ## Domain Name Space 31 | 32 | 36 | 37 | - Domain은 계층 구조를 가지고 있다. 38 | - 인터넷에서 사용되는 도메인은 IP 주소와 마찬가지로 전 세계적으로 고유하게 존재하여야 하므로 임의로 만들거나 변경할 수 없다. 39 | - 도메인 이름은 규칙을 따르고 있다. 40 | 41 | ![https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbmht3K%2FbtrfcYhFCqu%2FPe3QTHhIiKBev9IJrTeRY1%2Fimg.png](https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbmht3K%2FbtrfcYhFCqu%2FPe3QTHhIiKBev9IJrTeRY1%2Fimg.png) 42 | 43 | - 통상적으로 도메인의 가장 끝 점에 있는 점(.) 은 생략된다. 44 | - 이 점(.) 을 **Root 도메인**이라고 하며 가장 최상위 도메인이다. 45 | - 최상위 도메인의 직속 하위 도메인을 **Top-level 도메인**이라고 부른다. (ex. com, net. co.kr) 46 | - Top-level 도메인의 직속 하위 도메인을 **Second-level 도메인**이라고 부른다. 47 | - Second-level 도메인의 직속 하위 도메인을 **Sub 도메인**이라고 부른다. 48 | - 이러한 각각의 도메인을 **전담하는 독자적인 서버 컴퓨터가 존재**한다. 49 | 50 | ![https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdE6y10%2FbtqOP4gTdWD%2FOvcpFElloTi1FFBFLteYbk%2Fimg.png](https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdE6y10%2FbtqOP4gTdWD%2FOvcpFElloTi1FFBFLteYbk%2Fimg.png) 51 | 52 | ## Name Server (DNS 서버) 53 | 54 | - 도메인은 **도메인 계층 구조를 반영한 네임 서버에 저장, 관리**된다. 55 | - 각 DNS 서버는 도메인 계층의 일부 영역을 담당하고 그 영역에 속한 도메인을 관리한다. 56 | - 상위 계층 DNS 서버는 하위 계층의 도메인에 대한 정보를 관리하고 하위 계층 DNS 서버의 IP 주소를 가지고 있다. 57 | 58 | ![https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fm3SSL%2FbtqNZMM62oH%2FYqEKX3MBYyGVXry1Mu4vrK%2Fimg.png](https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fm3SSL%2FbtqNZMM62oH%2FYqEKX3MBYyGVXry1Mu4vrK%2Fimg.png) 59 | 60 | - Root Name Server는 하위 계층인 k, com의 정보를 관리하고 kr, com Name Server의 IP 주소가 등록되어 있다. 61 | 62 | > DNS는 전 세계의 수많은 도메인을 효율적으로 저장하고 관리하기 위해서 **도메인을 계층화**하고, **계층의 일부 영역을 Name Server가 분산 관리**하는 시스템으로 설계, 운영되고 있다. 63 | > 64 | 65 | > 웹 브라우저에 도메인 입력시 가장 처음 PC 에 있는 Cache를 탐색한다. 없으면 DNS Server 질의를 시작한다. 66 | > 67 | 68 | ## DNS Server 질의 과정 69 | 70 | ### 1. Local DNS Server (기지국 DNS 서버) 71 | 72 | ![https://www.wisewiredbooks.com/csbooks/ch3-network-internet/img/dns-iterated-step1.jpg](https://www.wisewiredbooks.com/csbooks/ch3-network-internet/img/dns-iterated-step1.jpg) 73 | 74 | - DNS 쿼리 과정에서 해당 IP를 찾기 위해 가장 먼저 찾는 DNS 서버 75 | - 기본적으로 컴퓨터 LAN 선을 통해 인터넷이 연결되면, 인터넷을 사용할 수 있게 IP를 할당해주는 통신사 (KT, SK, LG 등…) 에 해당되는 각 **통신사의 DNS 서버**가 등록된다. 76 | - Local DNS Server에 찾는 도메인 주소가 있다면 IP 주소 반환한다. 77 | - Local DNS Server에 찾는 도메인 주소가 없다면 Root DNS 서버에 물어본다. 78 | 79 | ### 2. Root DNS Server 80 | 81 | ![https://www.wisewiredbooks.com/csbooks/ch3-network-internet/img/dns-iterated-step2.jpg](https://www.wisewiredbooks.com/csbooks/ch3-network-internet/img/dns-iterated-step2.jpg) 82 | 83 | - Local DNS Server에 해당 도메인에 대한 IP 주소가 없을 때, Local DNS Server는 Root DNS 서버에게 물어본다. 84 | - Root DNS는 최상위 DNS 서버로 Root DNS부터 시작해서 Node DNS 서버에게로 차례차례 물어보게 됩니다. 85 | - 전세계적으로 13개의 Root DNS Server가 존재한다. 86 | - ROOT 13대가 넘어가면 DNS 질의시 사용되는 메시지 사이즈가 512 바이트가 넘어가게 된다. (UDP 사용) 87 | - 애니캐스트 어드레싱을 사용하면 루트 서버 인스턴스의 실제 수를 더 크케 잡을 수 있으며 그 수는 1034 (2020.01.11 기준) 88 | 89 | [Root Server Technical Operations Association](https://root-servers.org/) 90 | 91 | ### 3. Top-Level Domain DNS Server 92 | 93 | ![https://www.wisewiredbooks.com/csbooks/ch3-network-internet/img/dns-iterated-step3.jpg](https://www.wisewiredbooks.com/csbooks/ch3-network-internet/img/dns-iterated-step3.jpg) 94 | 95 | - Root DNS Server에 해당 도메인 주소가 없다면 최상위 DNS Server에게 다시 물어본다. 96 | - Root DNS Server는 최상위 DNS 서버의 주소를 알려준다. 97 | 1. 국가 코드 최상위 도메인 (Country Code Top-Level Domain, ccTLD) 98 | - ex) .kr, .jp, .CN, .US 99 | 1. 일반 최상위 도메인 (generic top-level domain, gTLD) 100 | - ex) .com, .net, .org 101 | 102 | ### 4. 반복적 질의 103 | 104 | ![https://www.wisewiredbooks.com/csbooks/ch3-network-internet/img/dns-iterated-step4.jpg](https://www.wisewiredbooks.com/csbooks/ch3-network-internet/img/dns-iterated-step4.jpg) 105 | 106 | - google.com의 네임서버 주소에 질의를 하면 google.com의 IP 주소를 응답해준다. 107 | - TLD DNS Server에 IP 주소가 없다면 2차, 3차 도메인 Server에게 질의하면서 IP 주소를 찾을 때까지 반복한다. 108 | 109 | ### 5. DNS Cache 저장 110 | 111 | - 위 과정을 통해 PC가 “google.com”의 IP주소를 성공적으로 받아왔다고 가정해보자. 112 | - PC에는 DNS Cache라는 Cache를 활용해 Cache 안에 해당 Domain Name 주소를 저장한다. (운영체제의 DNS) 113 | - TTL 이전에 다시 “google.com”에 다시 방문하기 위해 다시 접속을 시도한다면 DNS Server 쿼리는 일어나지 않고 Cache에서 IP 주소를 찾아 사용한다. 114 | - TTL - Time To Live 115 | - Cache에 저장되는 시간 116 | 117 | ## Reference 118 | 119 | [https://hwan-shell.tistory.com/320](https://hwan-shell.tistory.com/320) 120 | 121 | [https://better-together.tistory.com/128?category=887984](https://better-together.tistory.com/128?category=887984) 122 | 123 | [https://www.wisewiredbooks.com/csbooks/ch3-network-internet/dns.html](https://www.wisewiredbooks.com/csbooks/ch3-network-internet/dns.html) -------------------------------------------------------------------------------- /Network/images/aimd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prgrms-web-devcourse/BE-Team-R-CS-Study/d0535ce8aeb0166acb1ef886b431ecf3d25e5cfa/Network/images/aimd.png -------------------------------------------------------------------------------- /Network/images/fast-transmit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prgrms-web-devcourse/BE-Team-R-CS-Study/d0535ce8aeb0166acb1ef886b431ecf3d25e5cfa/Network/images/fast-transmit.png -------------------------------------------------------------------------------- /Network/images/handshake.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prgrms-web-devcourse/BE-Team-R-CS-Study/d0535ce8aeb0166acb1ef886b431ecf3d25e5cfa/Network/images/handshake.gif -------------------------------------------------------------------------------- /Network/images/http3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prgrms-web-devcourse/BE-Team-R-CS-Study/d0535ce8aeb0166acb1ef886b431ecf3d25e5cfa/Network/images/http3.png -------------------------------------------------------------------------------- /Network/images/one_key.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prgrms-web-devcourse/BE-Team-R-CS-Study/d0535ce8aeb0166acb1ef886b431ecf3d25e5cfa/Network/images/one_key.png -------------------------------------------------------------------------------- /Network/images/slidingwindow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prgrms-web-devcourse/BE-Team-R-CS-Study/d0535ce8aeb0166acb1ef886b431ecf3d25e5cfa/Network/images/slidingwindow.png -------------------------------------------------------------------------------- /Network/images/slow-start-chart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prgrms-web-devcourse/BE-Team-R-CS-Study/d0535ce8aeb0166acb1ef886b431ecf3d25e5cfa/Network/images/slow-start-chart.png -------------------------------------------------------------------------------- /Network/images/stopAndWait.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prgrms-web-devcourse/BE-Team-R-CS-Study/d0535ce8aeb0166acb1ef886b431ecf3d25e5cfa/Network/images/stopAndWait.png -------------------------------------------------------------------------------- /Network/images/tcp-header.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prgrms-web-devcourse/BE-Team-R-CS-Study/d0535ce8aeb0166acb1ef886b431ecf3d25e5cfa/Network/images/tcp-header.png -------------------------------------------------------------------------------- /Network/images/tcp3handshake.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prgrms-web-devcourse/BE-Team-R-CS-Study/d0535ce8aeb0166acb1ef886b431ecf3d25e5cfa/Network/images/tcp3handshake.png -------------------------------------------------------------------------------- /Network/images/tcp4handshake.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prgrms-web-devcourse/BE-Team-R-CS-Study/d0535ce8aeb0166acb1ef886b431ecf3d25e5cfa/Network/images/tcp4handshake.png -------------------------------------------------------------------------------- /Network/images/tcp_udp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prgrms-web-devcourse/BE-Team-R-CS-Study/d0535ce8aeb0166acb1ef886b431ecf3d25e5cfa/Network/images/tcp_udp.png -------------------------------------------------------------------------------- /Network/images/tcp_순서보장.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prgrms-web-devcourse/BE-Team-R-CS-Study/d0535ce8aeb0166acb1ef886b431ecf3d25e5cfa/Network/images/tcp_순서보장.PNG -------------------------------------------------------------------------------- /Network/images/tls_handshake.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prgrms-web-devcourse/BE-Team-R-CS-Study/d0535ce8aeb0166acb1ef886b431ecf3d25e5cfa/Network/images/tls_handshake.png -------------------------------------------------------------------------------- /Network/images/two_key.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prgrms-web-devcourse/BE-Team-R-CS-Study/d0535ce8aeb0166acb1ef886b431ecf3d25e5cfa/Network/images/two_key.png -------------------------------------------------------------------------------- /Network/images/udpheader.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prgrms-web-devcourse/BE-Team-R-CS-Study/d0535ce8aeb0166acb1ef886b431ecf3d25e5cfa/Network/images/udpheader.png -------------------------------------------------------------------------------- /Network/images/updtcp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prgrms-web-devcourse/BE-Team-R-CS-Study/d0535ce8aeb0166acb1ef886b431ecf3d25e5cfa/Network/images/updtcp.png -------------------------------------------------------------------------------- /Network/목차.md: -------------------------------------------------------------------------------- 1 | # 목차 -------------------------------------------------------------------------------- /OS/2022-04-01-프로세스와쓰레드.md: -------------------------------------------------------------------------------- 1 | # 프로세스 vs 쓰레드 2 | 3 | # 프로세스 4 | 5 | - 실행 중인 프로그램으로, 메모리에 적재되어 CPU의 할당을 받을 수 있는 상태 6 | - 컴퓨터에서 연속적으로 실행되고 있는 컴퓨터 프로그램 7 | - 메모리에 올라와 실행되고 있는 프로그램의 인스턴스 8 | - 운영체제로부터 시스템 자원을 할당받는 작업의 단위 9 | - 프로세스 제어 블록(PCB) 존재 10 | - 전체적으로, 일종의 실행된 프로그램을 의미하고 있음 11 | 12 | ## 쓰레드와 비교되는 가장 큰 특징 13 | 14 | - 각각 독립된 메모리 영역을 갖고 있음 15 | 16 | ![process.png](images/process.png) 17 | 18 | - Code, Data, Stack, Heap 구조 19 | - 프로세스당 최소 1개의 스레드를 갖고 있다(메인스레드) 20 | - 각 프로세스는 별도의 주소 공간에서 실행되며, 다른 프로세스의 변수나 자료구조에 직접 접근할 수 없고, 접근을 위해서는 프로세스 간 통신(IPC)를 활용해야 함 21 | 22 | ## IPC 23 | 24 | ### IPC 표준 25 | 26 | - System V IPC 27 | - POSIX IPC 28 | 29 | ### 다양한 IPC 설비 30 | 31 | - PIPE 32 | - 익명의 pipe를 통해 동일한 ppid를 가진 프로세스 간 단방향 통신 지원 33 | - 부모-자식 프로세스 간 통신 시 사용 34 | - read-write 각각 block 모드로 작동 35 | 36 | ![pipe.png](images/pipe.png) 37 | 38 | - Named PIPE 39 | - 이름이 정해진 pipe를 통해 프로세스 간 단방향 통신 지원 40 | - 연관 없는 프로세스 간 통신 시 사용 41 | - read-write 각각 block 모드로 작동 42 | 43 | ![NP.png](images/NP.png) 44 | 45 | - Message Queue 46 | - 메모리를 사용한 pipe, 구조체 기반 통신 47 | - 프로세스간 다양한 통신에서 사용 가능 48 | - 커널에서 제공하는 Message Queue이므로 EnQueue하는데 제한이 잇을 수 있음 49 | 50 | ![MQ.png](images/MQ.png) 51 | 52 | - Shared Memory 53 | - 시스템 상의 공유 메모리 주소를 활용 54 | - 일정한 크기의 메모리를 프로세스간에 공유 55 | - 커널에서 관리 56 | - 프로세스간 read-write를 모두 필요로 할때 사용 57 | - 프로세스 간 메모리 크기가 동일해야 함 58 | 59 | ![shared_memory.png](images/shared_memory.png) 60 | 61 | - Memory Map 62 | - 파일을 프로세스의 메모리에 일정 부분 매핑시켜서 사용 63 | - 파일로 대용량 데이터를 공유할때 활용 64 | 65 | (내용추가 필요할 듯) 66 | 67 | ![memory_map.png](images/memory_map.png) 68 | 69 | - Socket 70 | - 네트워크 소켓통신을 통한 데이터 공유 71 | - 원격으로 프로세스간 데이터 공유 시 사용 72 | - 데이터 세그먼트 처리 중요 73 | 74 | ![socket.png](images/socket.png) 75 | 76 | - 시그널 77 | - 유닉스 시스템에서 사용되는 IPC 78 | - 특정한 신호를 바로 다른 프로세스로 보낼 수 있음 79 | 80 | # 쓰레드 81 | 82 | - 프로세스 내에서 실행되는 여러 흐름의 단위 83 | - 프로세스의 특정 수행 경로 84 | - 프로세스가 할당받은 자원을 이용하는 실행의 단위 85 | - 전체적으로, 한 프로세스 내에서 실행 또는 흐름의 단위를 의미하고 있음 86 | 87 | ## 프로세스와 비교되는 특징 88 | 89 | - 프로세스 내에서 Stack만 별도로 할당받고, Code, Data, Heap 영역은 공유 90 | 91 | ![thread.png](images/thread.png) 92 | 93 | - 한 프로세스 내에서 동작되기 때문에, 주소 공간 및 자원을 공유하되, 쓰레드마다 존재하는 지역 변수는 스택에 저장하면서 동작한다. 94 | - 각각의 쓰레드는 별도의 레지스터와 스택을 갖고 있음 95 | - 한 쓰레드가 프로세스 자원을 변경하면, 다른 이웃 쓰레드도 즉시 확인 가능 96 | 97 | # 멀티프로세스 vs 멀티스레드 98 | 99 | ## 멀티프로세스 100 | 101 | - 하나의 응용프로그램을 여러 개의 프로세스로 구성하여 각 프로세스가 하나의 태스크를 처리하도록 하는 것 102 | - 장점 103 | - 여러 자식 프로세스 중 하나에 문제가 발생하더라도 자식 프로세스 하나만 죽기 때문에 영향의 확산이 없다 104 | - 멀티스레드에서 발생할 수 있는 공유 메모리 문제가 상대적으로 적다 105 | - 단점 106 | - Context Switching에서의 오버헤드 발생 107 | - 캐시 메모리 초기화 등 무거운 작업이 진행되고, 많은 시간이 소모된다. 108 | - 각각 독립된 메모리 영역을 할당받기 때문에, Context Switching이 발생하면 캐시에 있는 모든 데이터를 리셋하고 다시 가져와야 함 109 | - 프로세스 간 복잡한 통신 기법 110 | - 각각 독립된 메모리 영역을 할당받기 때문에 프로세스 사이의 변수를 공유할 수 없고, IPC를 활용해야 한다. 111 | 112 | ## 멀티스레드 113 | 114 | - 하나의 응용프로그램을 여러개의 스레드로 구성하고 각 스레드가 하나의 작업을 처리하도록 하는 것 115 | - 대부분 멀티 스레딩을 기본으로 하고 있음 116 | - 웹이 대표적인 멀티스레드 응용 프로그램 117 | - 장점 118 | - 시스템 자원 소모 감소 119 | - 프로세스를 생성하여 자원을 할당하는 시스템 콜 감소, 자원 관리 효율성 증가 120 | - 시스템 처리량 증가(처리비용 감소) 121 | - 스레드간 데이터를 주고받는것이 쉬움 122 | - 스레드 간 작업량이 작아 Context Switching 시간이 짧음 123 | - 간단한 통신 방법으로 인한 프로그램 응답 시간 단축 124 | - 스택 영역을 제외한 메모리 공유, 통신의 부담이 적음 125 | - 단점 126 | - 설계에 유의해야 함 127 | - 디버깅이 까다로움(여러 스레드가 동시에 돌아가기 때문) 128 | - 단일 프로세스 시스템은 효과를 기대하기 어려움 129 | - 다른 프로세스에서 스레드 제어 불가능(프로세스 밖에서 스레드 제어 불가) 130 | - 자원 공유 문제 발생(동기화 문제, critical section) 131 | - 하나의 스레드에 문제가 발생하면 전체 프로세스 영향 -------------------------------------------------------------------------------- /OS/2022-04-08-DeadLock.md: -------------------------------------------------------------------------------- 1 | # DeadLock 2 |
3 | 4 | ## Q . 교착 상태란? 5 | 6 | 둘 이상의 프로세스가 자원을 점유한 상태에서 7 | 서로 다른 프로세스가 점유하고 있는 자원을 요구하여, 무한 대기하는 상태 8 | 9 | ![img](https://user-images.githubusercontent.com/72663337/162190762-ac878aba-0134-49e8-9a50-dd731eb8f791.png) 10 | 11 | 12 | 13 | - 시스템적으로 한정된 자원을 여러 곳에서 사용하려고 할 때 발생함. 14 | 15 | 16 | ## Q . 교착 상태의 발생 조건이란? 17 | 18 | 4가지 조건이 존재하며, 모든 조건이 충족되어야 교착 상태가 발생함. 19 | 20 | 1. 상호 배제(Mutual exclusion) 21 | 22 | 자원은 한 번에 한 프로세스만 사용할 수 있음 23 | 24 | 25 | 26 | 2. 점유 대기(Hold and wait) 27 | 28 | 최소한 하나의 자원을 점유하고 있는 동시에, 29 | 30 | 다른 프로세스에 할당되어 사용하고 있는 자원을 추가로 점유하기 위해 대기하는 프로세스가 존재해야 함. 31 | 32 | 33 | 34 | 3. 비선점(No preemption) 35 | 36 | 다른 프로세스에 이미 할당된 자원은 사용이 끝날 때까지 강제로는 빼앗을 수 없음. 37 | 38 | 39 | 40 | 4. 순환 대기(Circular wait) 41 | 42 | 대기 프로세스들이 순환하는 형태로 다음 자원을 대기하고 있는 상태를 말함. 43 | 44 | 45 | ## Q . DeadLock 해결 방법이란? 46 | 47 | 교착 상태를 예방/회피 48 | - 교착 상태가 발생하기 전 가능성을 제하는 해결 방식. 49 | 50 | 51 | 52 | 1. 예방(prevention) 53 | 교착 상태 발생 조건 중 하나를 제거하며 해결함 54 | 55 | 56 | -> (-) 자원 낭비가 심함. 57 | 58 | 59 | 2. 회피(Avoidance) 60 | 교착 상태 발생을 피하는 방식 61 | 62 | 63 | `안정 상태(Safe state) : 프로세스들이 요청하는 모든 자원을 교착 상태 없이 할당 가능한 상태` 64 | 65 | `안전 순서(Safe sequence) : 프로세스들에게 자원을 할당하는 작업을 할 때 교착 상태가 발생하지 않는 특정 순서` 66 | 67 | 68 | 69 | -> 자원의 할당 후에도 시스템이 항상 safe state에 있을 수 있도록 자원을 할당하는 방식 70 | 71 | 72 | ### Q . Banker's Algorithm 73 | 74 | - 은행원 알고리즘(Banker's Algorithm) 75 | 76 | - 다익스트라 알고리즘에서 기반함 77 | 78 | - 프로세스의 자원 요구가 있을 때, 자원 할당 후에도 safe state로 남아 있는지 시뮬레이션하여 교착 상태를 회피함. 79 | 80 | - 대기 중인 모든 프로세스들에 대하여 교착 상태 가능성을 조사함 81 | 82 | - 안정 상태이면 자원을 할당하고, 아닐 시에는 다른 프로세스가 자원을 해지할 때까지 대기함. 83 | 84 | 85 | ### 교착 상태를 탐지/회복 86 | - 교착 상태가 되는 것을 허용하며, 그 후 회복을 위해 교착 상태를 탐지하고, 회복하는 해결 방식 87 | 88 | 89 | 90 | 1. 탐지(Detection) 91 | 92 | 자원 할당 그래프를 통하여 교착 상태를 탐지함. 93 | (사이클 o -> 교착 상태 o) 94 | 자원 요청 시, 탐지 알고리즘을 실행시킴 95 | 96 | 97 | 98 | 2. 회복(Recovery) 99 | 100 | 탐지 기법을 통하여 교착 상태를 발견한 후, 회복하기 위한 방식을 사용 101 | 102 | 교착 상태를 일으킨 프로세스를 종료하거나(1), 할당된 자원을 해제(2)시켜 회복함. 103 | 104 | 105 | 106 | (1) 프로세스 종료 107 | 108 | 109 | 1) 교착 상태에 빠진 모든 프로세스를 중단 110 | 111 | 112 | 2) 교착 상태가 해결될 때까지 하나씩 프로세스를 중지함 113 | 114 | 프로세스들을 하나씩 중단시킬 때마다 탐지 알고리즘을 호출, 교착 상태를 탐지하며 회복 115 | 116 | 117 | 118 | (2) 할당된 자원을 해제 119 | 120 | 이미 할당된 자원을 교착 상태가 해결될 때까지 다른 프로세스에 할당한 후, 되돌려 주는 방식 121 | 122 |
123 | 124 | ++ 125 | 126 | ## Q . 뮤텍스와 스핀락이란? 127 | 다수의 프로세스가 공유 중인 자원을 동시에 수정할 때 생기는 "동기화 문제" 를 해결하는 방식 128 | 129 | 상호 배제(mutual exclusion)과 연관이 있음. 130 | 131 | 132 | `임계 구역(Critical section)` 133 | 134 | 프로세스 간 공유 자원에 접근할 때 문제가 발생하지 않도록 접근을 제한하는 영역 135 | 136 | `lock - unlock` 137 | 138 | 임계 구역에 접근 - 임계 구역에 접근하지 못하는 상태 139 | 140 | 141 | ### 스핀락 142 | 143 | 특정 자원에 대한 접근 권한을 획득(lock)하기 전, 144 | 145 | busy waiting 상태로 접근 가능할 때까지 재시도하는 방식으로 대기하며, 146 | 147 | 권한을 획득한 후엔 내부 코드 작업을 수행하고 종료 후에는 권한을 해제(unlock)하는 방식으로 작동함 148 | 149 | -> 스레드에 대하여 문맥 교환(context switching)가 일어나지 않음 150 | 151 | --> 선점 기간 동안에는 다른 프로세스의 작업이 지연될 수 있음 152 | 153 | ``` 154 | wait(S){ 155 | //busy waiting 156 | while(S<=0); 157 | 158 | //lock 159 | S--; 160 | } 161 | 162 | //unlock 163 | signal(S){ 164 | S++; 165 | } 166 | ``` 167 | --> 짧게 수행될 수 있는 작업에 대하여 주로 사용됨. 168 | 169 | ### 뮤텍스(Mutex, MUTual EXclusion) 170 | 171 | 접근 권한 획득(lock) 전에는 sleep 상태로 대기하며, 172 | 173 | wakeup 후에 권한 획득을 시도함 174 | 175 | ``` 176 | do{ 177 | //sleep(대기 상태) 178 | wait(mutex); 179 | 180 | //** 181 | 182 | 대기 상태 종료 후 lock 183 | critical section 184 | 185 | **// 186 | 187 | //unlock 188 | signal(mutex); 189 | 190 | }while(true); 191 | ``` 192 | 193 | ## Q . 스핀락과 뮤텍스 방식의 공통점 194 | 195 | 자원의 획득(lock) 해제(unlock)를 통하여 공유 자원에 대한 접근 권한을 관리함 196 | 197 | 198 | ## Q . 스핀락과 뮤텍스 방식의 차이 199 | 200 | lock 상태를 갖기 전 대기할 때, 201 | 202 | 스핀락 방식은 busy-waiting 상태로 대기하며, 다른 작업을 하지 않음(context switching을 하지 않음) 203 | 204 | 뮤텍스 방식의 경우에는 자원의 접근을 대기할 때 다른 작업을 동시에 진행하며 대기함(context switching) 205 | -------------------------------------------------------------------------------- /OS/2022-04-15-CPU_Scheduler.md: -------------------------------------------------------------------------------- 1 | # 1. 스케줄러 2 | 3 | 스케줄러란 어떤 프로세스에게 자원을 할당할지를 결정하는 운영체제 커널의 코드를 지칭한다. 4 |

5 | 6 | ## (1) 프로세스 상태 종류 7 | 8 | ### ① new : 프로세스 생성중 9 | 10 | - 프로세스를 위한 자료구조는 생성 완료 11 | - 메모리 획득은 승인받지 못함 12 | 13 | ### ② ready : 준비가 다 된 프로세스가 CPU를 기다리는 상태 14 | 15 | - 프로세스가 메모리 적재된 상태로 실행하는데 필요한 자원을 모두 얻은 상태 16 | - 아직 CPU는 받지 못함 17 | - ready 상태인 프로세스는 여러개가 존재할 수 있음 18 | 19 | ### ③ running : 프로세스가 CPU를 할당받아, 명령어을 실행하고 있는 상태 20 | 21 | - CPU가 하나이면 실행중인 프로세스는 매 시점 하나뿐임 22 | 23 | ### ④ blocked : CPU를 할당받아도 당장은 명령을 실행할 수 없는 상태 24 | 25 | - ex) 입출력 작업이 진행 중인 경우 26 | 27 | ### ⑤ terminated : 프로세스 실행 종료 28 | 29 | - 프로세스는 종료되었으나, 운영체제가 프로세스와 관련된 자료구조를 완전히 정리하지 못함 30 | 31 | ### ⑥ suspended : 프로세스 중지 상태 32 | 33 | - suspended 상태의 프로세스는 메모리를 강제로 뺏긴 상태로 특정한 이유로 프로세스의 수행이 정지된 상태를 의미함 34 | - 외부에서 다시 재개시키지 않는 이상 다시 활성화 될 수 없음 35 | - 중기 스케줄러에 의해 디스크로 스왑 아웃된 프로세스의 상태가 대표적인 suspended상태라 할 수 있음 36 | - Suspended Ready : ready 상태의 프로세스가 디스크로 swap out 37 | - Suspended  Blocked : blocked 상태의 프로세스가 디스크로 swap out 38 | 39 |

40 | ## (2) 프로세스를 스케줄링하기 위한 큐 41 | 42 | ### ① Ready Queue (준비 큐) 43 | 44 | - 준비 상태에 있는 프로세스들을 줄 세우기 위한 큐 45 | 46 | ### ② Device Queue (장치 큐) 47 | 48 | - 운영체제는 특정 자원을 기다리는 프로세스들을 줄 세우기 위해 자원 별로 device queue를 둔다. 49 | - ex) disk I/O queue 50 | 51 | ### ③ Job Queue (작업 큐) 52 | 53 | - 시스템 내의 모든 프로세스를 관리하기 위한 큐 54 | - 프로세스의 상태와 무관하게 현재 시스템 내에 있는 모든 프로세스가 작업 큐에 속하게 된다. 55 | 56 |

57 | ## (3) 스케줄러 종류 58 | 59 | ![Untitled](https://user-images.githubusercontent.com/50768959/163463210-ee5f1bf0-cde5-49b9-bc0b-99160b3af31c.png) 60 | 61 | 출처 : [https://technote-mezza.tistory.com/70](https://technote-mezza.tistory.com/70) 62 | 63 | ### ① 장기 스케줄러 (Long-term scheduler / Job scheduler) 64 | 65 | 한정된 메모리에 많은 프로세스들이 단기간에 메모리에 올라올 경우, 디스크에 임시로 저장된다. 디스크에 저장되어있는 프로세스 중 어떤 프로세스에 메모리를 할당하여 ready queue로 보낼지 결졍하는 역할을 한다. 66 | 67 | - 메모리와 디스크 사이의 스케줄링을 담당 68 | - 프로세스에 메모리 및 리소스를 할당한다. 69 | - 실행중인 프로세스의 수를 제어한다. 70 | - 프로세스의 상태 : **new → ready** 71 | - 수십 초 내지 수 분 단위로 가끔 호출됨 → 상대적으로 속도가 느려도 된다. 72 | 73 | ### ② 단기 스케줄러 (Short-term scheduler / CPU scheduler) 74 | 75 | 준비 상태의 프로세스 중에서 어떤 프로세스를 다음번에 실행 상태로 만들 것인지 결정한다. 76 | 77 | → Ready queue의 프로세스들 중 어떤 프로세스에게 CPU를 할당할 것인가를 결정한다. 78 | 79 | - 프로세스에 CPU를 할당 80 | - 프로세스의 상태 : **ready → running → waiting → ready** (이라고 나와있는데 ready → running만 아닌가..?) 81 | - 밀리초 정도의 시간 단위로 매우 빈번하게 호출됨 → 수행 속도가 충분히 빨라야 함 82 | 83 | ### ③ 중기 스케줄러 (Medium-term scheduler / Swapper) 84 | 85 | - 실행중인 프로세스의 수를 제어한다. 86 | - 여유 공간 마련을 위해 프로세스를 통째로 메모리에서 디스크로 쫓아냄 (swapping) 87 | - blocked 상태는 다른 I/O 작업을 기다리는 상태이기 때문에 스스로 ready state로 돌아갈 수 있지만 suspended상태는 외부적인 이유로 suspending 되었기 때문에 스스로 돌아갈 수 없다. 88 | 89 | (I/O 작업때문에 blocked된 애는 I/O작업을 끝내면 “나 다했어!”하고 스스로 ready state로 돌아가지만, swapped out된 애들은 사용자가 그걸 필요로 할 때까지 무한 대기해야함!) 90 | 91 | - 프로세스의 상태 : **ready ↔ suspended, blocked ↔ suspended** 92 | 93 |

94 | # 2. CPU 스케줄러 종류 95 | 96 | ⭐ 스케줄링 효율성 비교 기준 97 | 98 | - Turnaround time : 종료된 시간 - 처음 생성된 시간 (ready queue에 들어온 시간) 99 | - Response time : 처음 프로세스가 실행된 시간 - 처음 생성된 시간 (ready queue에 들어온 시간) 100 | 101 |
102 | 103 | ### ① First Come, First Served (FCFS) 104 | 105 | - 이름 그대로 먼저 들어온 애들을 먼저 실행한다. 106 | - **비선점형**(Non-Preemptive) 스케줄링 : 프로세스들이 CPU를 한번 잡으면 본인 일을 다 끝낼 때 까지 CPU를 반환하지 않음 107 | 108 | 109 | 110 | 111 | - 이 경우 평균 turnaround time은 20이 된다. 112 | - 하지만 다음 같은 경우에는 평균 turnaround time은 110이 된다. 113 | 114 | 115 | 116 | → Convoy Effect : 소요 시간이 긴 프로세스가 먼저 도달하여 효율성을 낮추는 현상 117 | 118 |
119 | 120 | ### ② Shortes Job First (SJF) 121 | 122 | (얘는 대부분 정리되어 있는 것과 제가 학교 강의로 들은 내용이랑 달라서 논의가 필요합니다!) 123 | 124 | - 이름 그대로 실행시간이 짧은 것 부터 실행한다. 125 | - **비선점형** 스케줄링 126 | 127 | 128 | 129 | 130 | - 이 경우 평균 turnaround time이 50으로 감소하게 된다. 131 | 132 | → 하지만 이 경우는 모든 프로세스가 동시에 들어왔을 때만 성립한다. 133 | 134 | 135 | 136 | - 이 경우, A가 먼저 들어와서 **Convoy effec**t 가 여전히 발생한다. 137 | - 또한, 사용시간이 긴 프로세스는 거의 영원히 CPU를 할당받을 수 없는 **Starvation** 문제가 발생할 수 있다. 138 | 139 |
140 | 141 | ### ③ ****SRTF(Shortest Remaining Time First) == STCF (Shortest Time to Completion First)**** 142 | 143 | (SJF의 선점형 버전) 144 | 145 | - 새로운 프로세스가 도착할 때마다 새로운 스케줄링이 이루어진다. 146 | 147 | → 새로운 프로세스까지 포함해서 가장 남은 시간이 짧은 프로세스부터 실행한다. 148 | 149 | - **선점형**(Preemptive) 스케줄링 : 현재 수행중인 프로세스한테서 CPU를 뺏을 수 있다. 150 | 151 | 152 | 153 | 154 | - Starvation 현상 : 사용시간이 긴 프로세스는 오랫동안 CPU를 할당받지 못할 수 있다. 155 | - 남은 CPU burst time을 예측하기가 힘들다. 156 | 157 |
158 | 159 | ### ④ Priority Scheduling 160 | 161 | - 우선순위가 가장 높은 프로세스에게 CPU를 할당하는 스케줄링 162 | - (우선순위 알고리즘은 다양하다.) 163 | - 선점형 스케줄링(Preemptive) 방식 : 더 높은 우선순위의 프로세스가 도착하면 실행중인 프로세스를 멈추고 CPU 를 선점한다. 164 | - 비선점형 스케줄링(Non-Preemptive) 방식 : 더 높은 우선순위의 프로세스가 도착하면 Ready Queue 의 Head 에 넣는다. 165 | - Starvation : 우선순위가 낮은 프로세스는 계속해서 CPU를 얻지 못한다. 166 | 167 | → 해결방법 : aging → 아무리 우선순위가 낮은 프로세스라도 오래 기다리면 우선순위를 높여주자. (방법은 여러가지가 있다) 168 | 169 |
170 | 171 | ### ⑤ Round Robin 172 | 173 | - 현대적인 CPU 스케줄링 174 | - 각 프로세스는 동일한 크기의 할당 시간(time quantum)을 갖게 된다. 175 | - 할당 시간이 지나면 프로세스는 선점당하고 ready queue 의 제일 뒤에 가서 다시 줄을 선다. 176 | - CPU 사용시간이 랜덤한 프로세스들이 섞여있을 경우에 효율적 177 | - 프로세스의 context 를 save 할 수 있기 때문에 가능하다. → Context Switching이 이루어질 수 있다. 178 | - 장점 179 | - Response time이 빨라진다 : n 개의 프로세스가 ready queue 에 있고 할당시간이 q(time quantum)인 경우 각 프로세스는 q 단위로 CPU 시간의 1/n 을 얻는다. 즉, 어떤 프로세스도 (n-1)q time unit 이상 기다리지 않는다. 180 | - 프로세스가 기다리는 시간이 CPU 를 사용할 만큼 증가한다 : 공정한 스케줄링이라고 할 수 있다. 181 | - 주의할 점 182 | - 설정한 time quantum이 너무 커지면 FCFS와 같아진다. 183 | - 너무 작아지면 스케줄링 알고리즘의 목적에는 이상적이지만 잦은 context switch 로 overhead 가 발생한다. 184 | 185 | → 적당한 time quantum을 설정하는 것이 중요함 186 | -------------------------------------------------------------------------------- /OS/2022-04-29-캐시.md: -------------------------------------------------------------------------------- 1 | # 캐시 2 | 3 | ![캐시_사용_사례.png](images/캐시_사용_사례.png) 4 | 오늘날 캐싱은 하드웨어 수준에서 그치는 게 아니라 운영체제, CDN, DNS 등의 네트워킹 계층, 그리고 웹 애플리케이션 및 데이터베이스를 비롯한 다양한 기술 계층에 걸쳐 적용되고 활용되고 있습니다. 5 | 6 | ### 캐시란 무엇일까요? 7 | 8 | 캐시란 자주 필요한 데이터가 값의 복사본을 일시적으로 저장, 보관하기 위해 사용하는 곳입니다. 9 | 10 | 이러한 캐시를 사용하는것을 캐싱이라고 부릅니다. 11 | 12 | 캐시를 왜 사용하는 것 일까요? 13 | 14 | ## 캐시 메모리의 도입 15 | 컴퓨터의 동작 흐름을 통해 캐시 메모리의 도입에 대해 알아보겠습니다. 16 | 17 | ![컴퓨터_동작_흐름.png](images/컴퓨터_동작_흐름.png) 18 | 컴퓨터의 동작 흐름을 간단히 보자면, 하드 디스크에 있는 데이터를 RAM에서 불러오고 CPU는 RAM에 저장되어있는 데이터를 이용하여 연산작업을 수행합니다. 19 | 20 | 21 | ![cpu_ram_성능차이.png](images/cpu_ram_성능차이.png) 22 | 위 그래프는 연도별 CPU와 RAM 간의 성능 차이 그래프입니다. CPU는 해를 거듭할수록 성능이 급격하게 좋아지는 반면, RAM은 그렇지 않다는걸 알 수 있습니다. 23 | 24 | 이렇게 격차가 벌어지는 이유는 CPU와 다르게 메모리는 **속도보다 메모리 자체 용량을 늘리는게 주 목표이기 때문입니다.** 25 | 26 | CPU는 데이터를 처리하기 위해 메모리와 끊임없이 데이터를 주고받아야 하는 구조입니다. 27 | 28 | 결과적으로 위와 같이 CPU와 메모리 간 성능 차이가 점점 더 벌어지고 이렇게 된다면 **메모리가 CPU의 데이터 처리 속도를 쫓아가지 못해 CPU가 메모리를 기다려야 하는 병목현상이 발생**합니다. 29 | 30 | 따라서 이 병목현상을 완화하기 위해 CPU와 메인 메모리 사이에 **크기는 작지만 속도가 빠른 캐시 메모리를 두고**, 31 | 32 | 캐시 메모리에 향후 재사용할 가능성이 클 것으로 예상되는 데이터의 복사본을 저장해둔 후 CPU가 요청하는 데이터를 바로 전달할 수 있도록 합니다. 33 | 34 | 즉, CPU와 메모리간 데이터 처리 속도, 병목 현상을 해결하기 위해 캐시 메모리가 도입되었습니다. 35 | 36 | 캐싱은 CPU와 RAM 사이에서만 사용되는 것은 아닙니다. 메모리 계층 구조를 통해 더 알아보겠습니다. 37 | 38 | ## 메모리 계층 구조 39 | ![메모리_계층_구조.png](images/메모리_계층_구조.png) 40 | L1~ L3 캐시를 사용하는 메모리 계층 구조 41 | 캐시 메모리를 포함한 컴퓨터의 메모리 계층 구조는 위와 같습니다. 42 | 43 | 계층의 위에 있을수록 속도가 빠르고 비싸며 CPU와 가깝습니다. 44 | 45 | 여기서의 특징은 메모리 계층 구조에서 **한 계층은 바로 아래 계층에 대하여 캐싱 작업을 수행**합니다. 46 | 47 | L1은 L2의 캐시 역할, L2는 L3의 캐시 역할, L3는 메인 메모리와 디스크의 캐시 역할을 수행하는 식입니다. 48 | 49 | 여러 개의 캐시를 활용한 계층구조를 사용하여 임시 정보를 저장해 성능을 개선시킬 수 있기 때문에 캐시를 사용합니다. 50 | 51 | 이와 같은 **메모리 계층 구조의 목적**은 캐싱을 이용하여 빠르고 작은 메모리와 크고 느린 메모리의 장점을 조합해서 **크고 빠른 메모리**처럼 행동하도록 만드는 것입니다. 52 | 53 | ## L1, L2, L3 Cache 54 | ![캐시_Latency.png](images/캐시_Latency.png) 55 | 56 | 위 메모리 계층 구조에서 나온 L1, L2, L3 캐시에 대해 알아보겠습니다. 여기서의 L은 `Level`을 뜻합니다. 57 | 58 | **L1 캐시**는 일반적으로 CPU 칩 안에 내장되어 데이터 사용/참조에 가장 먼저 사용됩니다. L1 캐시는 보통 8~64KB 정도의 용량으로 CPU가 가장 빠르게 접근하게 되며, 여기서 데이터를 찾지 못하면, 이제 L2 캐시 메모리로 넘어갑니다. 59 | 60 | L1 캐시는 CPU 내부에 존재하므로 L1 캐시에서 데이터를 참조할 경우 속도 저하는 발생하지 않습니다. 61 | 62 | L1 캐시는 속도를 위해 I 캐시와 D 캐시로 나눕니다. 63 | 64 | * Instruction Cache (I캐시): 메모리의 code 영역 데이터를 다루는 캐시. 65 | * Data Cache (D캐시): code 영역을 제외한 모든 데이터를 다루는 캐시. 66 | 67 | 68 | 하지만 메인 메모리의 모든 데이터를 L1 캐시에 저장할 수 없기에 L1 캐시에 없는 데이터를 CPU가 요구할 경우 속도의 저하로 이어질 수 있습니다. 그렇기 때문에 L2 캐시를 하나 더 둬서 이용하게 됩니다. 69 | 70 | 71 | **L2 캐시**는 L1보다 훨씬 크지만 동시에 느립니다. 일반적으로 64KB~4MB 정도가 사용되며 L2 캐시는 CPU 회로판에 별도의 칩으로 내장됩니다. 앞서 말한 대로 L1 캐시에서 데이터를 먼저 찾고, 이를 찾지 못하면 L2 캐시로 넘어가 데이터를 찾습니다. L2 캐시는 L1 캐시보다 느리지만, 일반 메모리(RAM)보다는 빠릅니다. 72 | 73 | **L3 캐시**도 동일한 원리로 작동됩니다. 보통 L2 캐시로 충분하기 때문에 웬만한 프로세서에서는 L3를 달고 있지 않다고 합니다. 하지만 멀티 코어 시스템에서 사용하게 되면 더 높은 수준의 캐시로 승격된다고 합니다. 74 | 75 | ## 캐시 라인 76 | 캐시(cache)는 CPU와 가까이에 위치하면서 빈번하게 사용되는 데이터를 놔두는 장소입니다. 77 | 78 | 하지만 캐시가 아무리 가까이 있더라도 찾고자 하는 데이터가 어느 곳에 저장되어 있는지 몰라 모든 데이터를 순회해야 한다면 시간이 오래 걸리게 됩니다. 79 | 80 | 즉, 캐시에 목적 데이터가 저장되어 있다면 바로 접근하여 출력할 수 있어야 캐시가 의미 있어집니다. 81 | 82 | 그렇기 때문에 **캐시에 데이터를 저장할 때 접근에 대한 정보를 태그들로 나타낸 자료구조**에 저장하게 되는데 이를 **캐시 라인**이라고 합니다. 83 | 84 | 이 캐시 라인은 밑에 설명할 캐시 메모리 구조에서 나타납니다. 85 | 86 | ## 캐시 메모리의 구조 87 | ![캐시_메모리구조.png](images/캐시_메모리구조.png) 88 | 89 | 90 | 캐시 메모리는 S개의 집합(Set)으로 이뤄져 있고, 각 집합은 E개의 캐시 라인(Cache Line)을 저장합니다. 91 | 92 | 각 캐시 라인은 메인 메모리에서 가져오는 **블록(Block)** 하나와 그것이 유효한지를 나타내는 **유효 비트(Valid Bit)**, 그리고 동일한 집합에 들어올 수 있는 다른 블록들과 구별하기 위한 **태그(Tag)**를 저장합니다. 93 | 94 | 95 | 96 | 다시 말하자면, 각각의 **캐시 블록(Cache Block)**은 데이터를 담고 있으며 97 | 98 | **태그(Tag)**는 캐시 블록의 고유 식별 값으로 CPU 프로세서는 캐시 태그 값을 통해 캐시 블록에 접근할 수 있습니다. 99 | 100 | 101 | 102 | 또한, **유효 비트**를 통해 해당 캐시 블록에 올바른 데이터가 저장되어 있는지 나타내 줍니다. 103 | 104 | 만약 캐시 블록이 비어있거나 올바르지 못한 값을 가지고 있다면 유효 비트는 0으로 설정되어 유효한 블록이 없다는 걸 알려줍니다. 105 | 106 | ## 캐시의 지역성 107 | 다시 돌아와서, **재사용할 가능성이 클 것으로 예상되는 데이터의 복사본을 저장**함으로써 **캐싱**을 할 수 있다고 했습니다. 108 | 109 | 그렇다면 재사용할 가능성이 큰지 어떻게 알 수 있을까요? 110 | 111 | 이는 캐시의 지역성을 통해 이를 알 수 있습니다. 112 | 113 | **지역성**이란 데이터 접근이 시간적 혹은 공간적으로 가깝게 일어나는 것을 의미합니다. 114 | 115 | 지역성의 전제조건은 모든 데이터를 균등하게 참조하는 것이 아니라 **일부 특정 데이터에 대해서 더 많이 참조하는 경향**이 있다는 것입니다. 116 | 117 | 캐시에서 지역성에는 시간 지역성과 공간 지역성이 있습니다. 118 | 119 | ### 시간적 지역성 120 | * 시간적 지역성이란, 특정 데이터가 한 번 접근되었을 경우, 가까운 미래에 또 한번 데이터에 접근할 가능성이 높은 것을 의미합니다. 121 | * 최근에 참조된 주소의 내용은 곧 다음에 다시 참조되는 특성입니다. 122 | * 메모리 상 같은 주소에 여러 차례 읽기 쓰기를 수행할 경우 상대적으로 작은 크기의 캐시를 사용해도 효율성을 높일 수 있습니다. 123 | 124 | 예를 들어 반복문에서의 조건 변수 i를 예로 들 수 있습니다. 125 | 126 | ### 공간적 지역성 127 | * 공간적 지역성이란, 특정 데이터와 가까운 주소가 순서대로 접근되는 경우를 의미합니다. 128 | * 한 메모리 주소에 접근할 때 그 주소뿐 아니라 해당 블록을 전부 캐시에 가져옵니다. 129 | * 이때 메모리 주소를 오름차순이나 내림차순으로 접근한다면, 캐시에 이미 저장된 같은 블록의 데이터를 접근하게 되므로 캐시의 효율성이 크게 향상될 수 있습니다. 130 | 131 | 132 | 예를 들어 순서대로 접근할 가능성이 큰 배열이 있습니다. 133 | 134 | **시간 지역성, 공간 지역성을 충족하는 예제** 135 | ```java 136 | for(int i=0; i<3; i++) { 137 | data[i+1] = data[i] + 1; 138 | } 139 | ``` 140 | 위는 시간, 공간적 지역성을 충족하는 간단한 코드 예제입니다. 141 | 142 | 위의 배열에서 변수 i를 선언 후 재 접근하므로 **시간 지역성(가까운 미래에 또 한 번 데이터 접근)**이라고 볼 수 있습니다. 143 | 144 | data 배열에 인덱스 0부터 1,2 순차적으로 접근하므로 **공간 지역성(가까운 주소가 순서대로 접근)**이라고 볼 수 있습니다. 145 | 146 | ## 캐시 히트와 캐시 미스 147 | 지역성의 원리를 이용해 캐시에 데이터들을 넣었습니다. 그러면 이제 CPU가 메모리에 데이터를 요청할 때, 메인 메모리에 접근하기 앞서 캐시 메모리에 접근하여 데이터 존재 여부를 확인하겠죠 148 | 149 | 이때 캐시 메모리가 해당 데이터를 가지고 있다면 **캐시 히트**라고 하며 150 | 151 | ![캐시히트.png](images/캐시히트.png) 152 | 153 | 154 | 해당 데이터가 없어서 메인 메모리에서 가져와야 한다면 **캐시 미스**라고 합니다. 155 | 156 | ![캐시미스.png](images/캐시미스.png) 157 | 158 | 159 | 위에 소개했던 L1~L3 캐시에서 연산에 필요한 데이터가 L1 캐시에 있다면 캐시 히트, 160 | 161 | 만약 L1 캐시에 없다면 캐시 미스 후 L2 캐시를 검사하여 L2 캐시에 있다면 캐시 히트, 162 | 163 | 만약 L2 캐시에도 없다면 캐시 미스 후 L3 캐시를 검사하여 L3 캐시에 있다면 캐시 히트, 164 | 165 | 만약 L3 캐시에도 없다면 캐시 미스 후 메인 메모리에서 데이터를 가져옵니다. 166 | 167 | 168 | --- 169 | 예상되는 질문 170 | 171 | * 캐시란 무엇인가요? 172 | * 캐시를 사용하는 이유가 무엇인가요? 173 | * 캐시의 지역성에 대해 설명해보세요 -------------------------------------------------------------------------------- /OS/2022-05-10-시스템 콜.md: -------------------------------------------------------------------------------- 1 | # 시스템 콜 2 | 3 | # 시스템 콜 4 | 5 | - `커널 모드`에서 사용 가능한 서비스에 대한 인터페이스를 제공 6 | - 일반적으로 C/C++언어로 작성된 함수 형태로 제공 7 | - 간단한 프로그램이라도 운영체제의 기능을 아주 많이 사용하게 됨 → API에 따라 프로그램을 설계함으로써 매개변수, 반환값을 이용하여 함수의 사용이 가능 8 | 9 | ![syscall](images/syscall.png) 10 | 11 | - API를 사용하는 이유 12 | - 프로그램의 호환성 - 같은 API를 지원하면 어느 시스템이건 컴파일/실행 가능 13 | - 실제 시스템 콜은 더 자세한 명세가 필요하므로 API가 더 쉬움 14 | - 대부분의 API는 사실상 시스템 콜과 유사함 15 | - 런타임 환경 16 | - 특정 응용 프로그램을 실행하는 데 필요한 전체 소프트웨어 및 연계 소프트웨어를 모두 통틀어 지칭 17 | - 시스템 콜 인터페이스 제공 18 | - 시스템 콜 예제 19 | 20 | ```bash 21 | cp input.txt output.txt 22 | ``` 23 | 24 | - 위와 같은 명령이 있다고 생각해 보자. 25 | - 문장 입력에 I/O 시스템 콜 사용 26 | - cp라는 프로그램을 이용하는데, 해당 프로그램 내부적으로 시스템 콜을 활용하여 구현되어 있음 27 | - input.txt 파일이 접근 가능한 파일인지 확인하는 시스템 콜 28 | - output.txt라는 파일이 쓰기 가능한 파일인지 확인하는 시스템 콜 29 | - 파일을 저장하는 시스템 콜 30 | 31 | ![cp](images/cp.png) 32 | 33 | - 운영체제에게 매개변수를 전달하는 방법(시스템 콜 매개변수) 34 | - 레지스터를 통해 전달 35 | - 레지스터보다 많은 경우 메모리 내 블록/테이블에 저장하고 블록 주소를 통해 전달 36 | - 리눅스에서는 5개 이하일 때 레지스터를 쓰고, 5개가 넘으면 스택에 넣어서 전달 37 | - 유형 38 | - 프로세스 제어 39 | - 실행, 제어 전환, 종료 등 수행 상태 제어 40 | - 공유 데이터를 위한 Lock 시스템 콜 41 | - 파일 조작 42 | - 파일 생성/삭제, 열기/닫기, 읽기/쓰기, 커서 위치 변경, 되감기 43 | - 파일 속성 획득, 속성 설정 44 | - 파일 이동/복사 45 | - 장치 관리 46 | - 장치 요청 - 독점적 사용 보장 47 | - 장치 릴리즈 - 사용 종료 48 | - 파일 형태로 장치 관리, 열기/닫기, 읽기/쓰기, 위치 변경 등 활용 49 | - 파일과 유사한 구조가 많아서 파일-장치 구조로 결합 50 | - 정보 유지 51 | - 현재 시간, 날짜 리턴 52 | - 메모리 덤프 53 | - 한 명령어 실행(single step) 모드를 활용하면 모든 명령 이후 트랩을 실행시켜 디버깅 가능 54 | - strace는 실행될 때마다 각 시스템 콜 나열해서 디버깅 해줌 55 | - time profile을 위한 정규 타이머 인터럽트(일정 시간마다 프로그램 카운터 값 기록) 56 | - 모든 프로세스 정보에 접근, 특정 프로세스 정보를 획득하고 설정 57 | - 통신 58 | - 호스트 이름, 프로세스 이름 가져오기 59 | - Open, Close 60 | - Accept, Wait for connection 61 | - 서버에서의 read_msg, write_msg 62 | - 공유 메모리 모델에서 공유 메모리 접근을 위한 create, attach 63 | - 보호 64 | - 권한 설정, 권한 가져오기 65 | - 허가된 유저, 불허된 유저 확인 66 | 67 | # 대표적인 예제 68 | 69 | - fork() → 빈출 70 | - 현재 프로세스와 동일한 새로운 프로세스를 생성할 때 사용 71 | - child process를 생성하기 위한 시스템 콜 72 | - 특징 73 | - 부모 프로세스 : 리턴 값이 자식 프로세스의 PID 74 | - 자식 프로세스 : 리턴 값이 0 75 | - 자식 프로세스는 열린 파일과 같은 자원, 권한, 스케줄링 속성을 부모 프로세스로부터 상속 76 | - 쓰기 시 복사(copy-on-write) 사용 77 | - 자식 프로세스가 시작할 때 부모의 페이지를 당분간 함께 사용 78 | - 둘중 한 프로세스가 공유중인 페이지에 쓸 때(변경점이 생겼을 때) 복사본을 생성 79 | - 수정을 하는 페이지에 대해서만 복사본이 생김 → 코드와 같은 곳은 자식과 부모 간 그대로 공유 80 | - 별도의 수정이 없을 시 vfork를 사용할 수도 있음(쓰기 시 복사 미사용, 데이터 영역 공유) 81 | - 데몬 프로세스의 경우 PID가 1인 systemd에서 fork되어 생성됨, 모든 데몬 프로세스의 루트 프로세스는 systemd 82 | - exec() 83 | - 특정 바이너리 파일을 메모리로 적재하고, 기존 프로그램을 파괴하는 명령 84 | - 기존 프로세스에 새로운 프로세스를 덮어쓰기 하는 작업 85 | - 특징 86 | - 포크 이후 사용하면 부모 프로세스와 커널 자원을 공유하는 통신 가능한 다른 프로세스가 생성되는 것으로 볼 수 있음 87 | - 메모리가 새로운 프로세스로 대체되는 과정 -------------------------------------------------------------------------------- /OS/images/MQ.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prgrms-web-devcourse/BE-Team-R-CS-Study/d0535ce8aeb0166acb1ef886b431ecf3d25e5cfa/OS/images/MQ.png -------------------------------------------------------------------------------- /OS/images/NP.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prgrms-web-devcourse/BE-Team-R-CS-Study/d0535ce8aeb0166acb1ef886b431ecf3d25e5cfa/OS/images/NP.png -------------------------------------------------------------------------------- /OS/images/cp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prgrms-web-devcourse/BE-Team-R-CS-Study/d0535ce8aeb0166acb1ef886b431ecf3d25e5cfa/OS/images/cp.png -------------------------------------------------------------------------------- /OS/images/cpu_ram_성능차이.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prgrms-web-devcourse/BE-Team-R-CS-Study/d0535ce8aeb0166acb1ef886b431ecf3d25e5cfa/OS/images/cpu_ram_성능차이.png -------------------------------------------------------------------------------- /OS/images/memory_map.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prgrms-web-devcourse/BE-Team-R-CS-Study/d0535ce8aeb0166acb1ef886b431ecf3d25e5cfa/OS/images/memory_map.png -------------------------------------------------------------------------------- /OS/images/pipe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prgrms-web-devcourse/BE-Team-R-CS-Study/d0535ce8aeb0166acb1ef886b431ecf3d25e5cfa/OS/images/pipe.png -------------------------------------------------------------------------------- /OS/images/process.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prgrms-web-devcourse/BE-Team-R-CS-Study/d0535ce8aeb0166acb1ef886b431ecf3d25e5cfa/OS/images/process.png -------------------------------------------------------------------------------- /OS/images/shared_memory.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prgrms-web-devcourse/BE-Team-R-CS-Study/d0535ce8aeb0166acb1ef886b431ecf3d25e5cfa/OS/images/shared_memory.png -------------------------------------------------------------------------------- /OS/images/socket.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prgrms-web-devcourse/BE-Team-R-CS-Study/d0535ce8aeb0166acb1ef886b431ecf3d25e5cfa/OS/images/socket.png -------------------------------------------------------------------------------- /OS/images/syscall.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prgrms-web-devcourse/BE-Team-R-CS-Study/d0535ce8aeb0166acb1ef886b431ecf3d25e5cfa/OS/images/syscall.png -------------------------------------------------------------------------------- /OS/images/thread.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prgrms-web-devcourse/BE-Team-R-CS-Study/d0535ce8aeb0166acb1ef886b431ecf3d25e5cfa/OS/images/thread.png -------------------------------------------------------------------------------- /OS/images/메모리_계층_구조.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prgrms-web-devcourse/BE-Team-R-CS-Study/d0535ce8aeb0166acb1ef886b431ecf3d25e5cfa/OS/images/메모리_계층_구조.png -------------------------------------------------------------------------------- /OS/images/캐시_Latency.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prgrms-web-devcourse/BE-Team-R-CS-Study/d0535ce8aeb0166acb1ef886b431ecf3d25e5cfa/OS/images/캐시_Latency.png -------------------------------------------------------------------------------- /OS/images/캐시_메모리구조.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prgrms-web-devcourse/BE-Team-R-CS-Study/d0535ce8aeb0166acb1ef886b431ecf3d25e5cfa/OS/images/캐시_메모리구조.png -------------------------------------------------------------------------------- /OS/images/캐시_사용_사례.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prgrms-web-devcourse/BE-Team-R-CS-Study/d0535ce8aeb0166acb1ef886b431ecf3d25e5cfa/OS/images/캐시_사용_사례.png -------------------------------------------------------------------------------- /OS/images/캐시미스.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prgrms-web-devcourse/BE-Team-R-CS-Study/d0535ce8aeb0166acb1ef886b431ecf3d25e5cfa/OS/images/캐시미스.png -------------------------------------------------------------------------------- /OS/images/캐시히트.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prgrms-web-devcourse/BE-Team-R-CS-Study/d0535ce8aeb0166acb1ef886b431ecf3d25e5cfa/OS/images/캐시히트.png -------------------------------------------------------------------------------- /OS/images/컴퓨터_동작_흐름.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prgrms-web-devcourse/BE-Team-R-CS-Study/d0535ce8aeb0166acb1ef886b431ecf3d25e5cfa/OS/images/컴퓨터_동작_흐름.png -------------------------------------------------------------------------------- /OS/목차.md: -------------------------------------------------------------------------------- 1 | # 목차 -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CS-Study 2 | 3 | ### 목적 4 | 5 | 기술 면접 시 CS 관련 질문에 대해 정확히 대답할 수 있고, 꼬리 질문까지 대답할 수 있도록 합니다. 6 | 7 | 항상 왜? 라는 질문과 함께 단순 암기가 아니라 제대로 된 이해를 목적으로 합니다. 8 | 9 | 단순 암기가 된다면 꼬리 질문에 대한 대답을 하지 못하게 됩니다. 10 | 11 | 주제를 다룰때는 예상질문을 토대로 개념적으로 공부할 수 있도록 합니다. 12 | 13 | ### 진행 방법 14 | 15 | 매주 각자 1개의 주제를 선정 후 해당 주제를 통해 나올 수 있는 면접 질문과 이에 대해 어떻게 답변할지, 개념적인 설명에 대해 정리합니다. 16 | 17 | ### Commit 메세지 규칙 18 | commit 메세지 컨벤션의 경우 `docs: 문서 수정에 대한 커밋` 으로 진행합니다. 19 | 20 | ### PR 규칙 21 | PR 제목의 경우 다음과 같은 규칙을 따릅니다 22 | ``` 23 | [주제][이름] 포스팅 제목 24 | ex) [운영체제][박우진] 프로세스와 스레드의 차이 25 | ``` 26 | 27 | ### 파일 제목 규칙 28 | 각 주제에 맞게 .md 파일을 생성할때 파일 이름에 대한 컨벤션은 다음과 같이 합니다. 29 | 30 | `yyyy-mm-dd-주제.md` 31 | 32 | ex) `2022-04-01-SQL과NOSQL.md` 33 | 34 | ### 다루는 주제들 35 | * 네트워크 36 | * 운영체제 37 | * 데이터베이스 38 | * 자료구조 & 알고리즘 39 | * 자바 40 | * 스프링 41 | * 디자인 패턴 42 | -------------------------------------------------------------------------------- /Spring/2022-05-24-AOP.md: -------------------------------------------------------------------------------- 1 | ## **AOP란?** 2 | 3 | AOP는 **Aspect Oriented Programming**의 약자로 **관점 지향 프로그래밍**이라고 불립니다.  4 | 5 | 관점 지향이라고 하니 의미가 크게 와닿지 않을 수 있는데요,   6 | 7 | 기능을 **핵심 비즈니스 기능**과 **공통기능**으로 **구분**하고, 모든 비즈니스 로직에 들어가는 **공통기능의 코드를 개발자의 코드 밖에서 필요한 시점에 적용**하는 프로그래밍 방식이라고 볼 수 있습니다. 8 | 9 | 아래의 예시 코드를 통해 더 자세히 알아보겠습니다. 10 | 11 | ```java 12 | @Slf4j 13 | @Service 14 | @RequiredArgsConstructor 15 | public class UserService { 16 | 17 | private final UserRepository userRepository; 18 | 19 | public long join(UsercreateRequest userCreateRequest) { 20 | //트랜잭션 begin 21 | //로깅 22 | //비즈니스 로직 23 | //트랜잭션 commit 24 | } 25 | 26 | } 27 | ``` 28 | 29 | 위와 같이 사용자를 관리하기 위한 **UserService**가 존재한다고 했을 때, 회원가입 메소드로 **join**을 구현한다고 가정하겠습니다. 30 | 31 | 해당 메소드를 구현할 때 비즈니스 로직 이외에 **트랜잭션, 로깅 등**을 포함하게 되는데 32 | 33 | 이는 비즈니스 로직보다는 **부가 기능**에 가깝다고 볼 수 있습니다. 34 | 35 | 핵심 비즈니스 로직을 담고 있지는 않지만 애플리케이션에 부가됨으로써 의미를 갖는 특별한 모듈입니다. 36 | 37 | 만약 join이라는 메소드 이외에 다른 메소드에서도 트랜잭션, 로깅 처리 등을 반복적으로 사용하게 된다면 38 | 39 | 이를 **공통적으로 처리해줄 수 있는 무언가**가 있으면 좋지 않을까요? 40 | 41 | AOP가 바로 그 역할을 해주게 됩니다. 42 | 43 | 트랜잭션, 로깅, 메소드 실행 시간 체크 등 **부가 기능을 모듈화하고 핵심 비즈니스 로직에서 분리해 재사용하는 것이** AOP의 취지라고 볼 수 있습니다.  44 | 45 | (이러한 **부가 기능**을 횡단 관심사(Cross-cutting concerns)라고 부르기도 합니다.) 46 | 47 | ![횡단_관심사](https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FyZZMO%2FbtrCWQNcmKc%2FY6uQ3uqiwVmt6lcIeH5Jlk%2Fimg.png) 48 | 49 | 50 | AOP를 사용하게 되면 중복되는 코드 제거, 효율적인 유지보수, 높은 생산성 등의 장점이 있게 되는 것이죠. 51 | 52 | (AOP는 OOP와 같은 일종의 패러다임이기 때문에 각 언어마다 AOP에 대한 구현체가 있습니다.) 53 | 54 | AOP에서 등장하는 용어는 다음과 같습니다. 55 | 56 | ### **AOP의 용어** 57 | 58 | - Target: 어떤 대상에 부가 기능을 부여할 것인가 59 | - Advice: 어떤 부가 기능인지? Before, AfterReturning, AfterThrowing, After, Around 60 | - Join point: 어디에 적용할 것인가? **메소드**, 필드, 객체, 등 61 | - Point cut: advice가 적용될 지점, Spring AOP에서는 advice가 적용될 메소드를 선정 62 | 63 | (Spring AOP는 메소드 조인 포인트만 지원합니다) 64 | 65 | ### **Spring에서의 AOP 사용 예시** 66 | 67 | 아래의 예제와 함께 Spring에서 AOP를 어떻게 적용하는지 보겠습니다.  68 | 69 | ```java 70 | @Slf4j 71 | @Aspect 72 | @Component 73 | public class LoggingAspect { 74 | 75 | @Pointcut("within(com.prgrms.domain.user.service.UserService)") 76 | private void advicePoint() { 77 | } 78 | 79 | @Around("advicePoint()") 80 | public void loggingAround(ProceedingJoinPoint joinPoint) throws Throwable { 81 | MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature(); 82 | 83 | log.info("Before call method: {}", methodSignature.getName()); 84 | 85 | Object result = joinPoint.proceed(); // 타겟 메소드 실행 86 | 87 | log.info("After call method: {}", methodSignature.getName()); 88 | 89 | } 90 | 91 | } 92 | ``` 93 | 94 | 위는 예시로 봤던 UserSerivce 클래스 내 모든 메소드에 로깅 AOP를 적용한 예제 코드입니다. 95 | 96 | @PointCut 어노테이션을 통해 AOP를 적용될 대상을 정의해줍니다. 97 | 98 | 현재 com.prgrms.domain.user.service 패키지 내 UserService 내 모든 메소드에 적용하도록 명시해줬습니다. 99 | 100 | @Around 어노테이션을 통해 타겟 메소드의 실행 전과 후에 AOP를 적용하도록 해줬습니다. 101 | 102 | Advice 설정은 5가지로 정의할 수 있습니다. 103 | 104 | - @Around: 타겟 메소드 실행 전과 후 105 | - @Before: 타겟 메소드 실행 전 106 | - @After: 타겟 메소드 실행 후 107 | - @AfterReturning: 타겟 메소드 호출이 정상적으로 종료 된 후 108 | - @AfterThrowing: 타겟 메소드에서 예외가 발생한 경우 109 | 110 | 위의 예시로 본다면 타겟 메소드 실행 전과 후에 로그를 남기도록 AOP를 설정해줬다는 걸 알 수 있습니다. 111 | 112 | 이제 조금 더 자세히 Spring에서 AOP의 동작원리에 대해 알아보겠습니다. 113 | 114 | ### **Spring AOP 동작 원리** 115 | 116 | Spring AOP에서는 프록시를 사용하게 되는데요, 프록시는 타겟의 역할을 대신해주는 대리자라고 볼 수 있습니다.  117 | 118 | ![동작원리](https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdK5tDV%2FbtrCWQGnGZJ%2Fy7inyXOZqRrG60YGyZRagK%2Fimg.png) 119 | 120 | 121 | 예를 들어 위 이미지에서 클라이언트가 타겟을 호출하게 되면, 122 | 123 | 타겟이 아닌 프록시가 대신 호출되어 부가 기능과 비즈니스 로직을 수행하게 됩니다. 124 | 125 | 정리하자면 다음과 같습니다. 126 | 127 | - 스프링은 Aspect의 적용 대상(target)이 되는 객체에 대한 Proxy를 만들어 제공 128 | - 대상 객체(Target)를 사용하는 코드는 대상객체(Target)를 Proxy를 통해서 간접적으로 접근 129 | - Proxy는 공통기능(Advice)을 실행한 뒤 대상 객체(Target)의 실제 메서드를 호출하거나 또는 대상객체(Target)의 실제 메소드가 호출된 뒤 공통기능(Advice)을 실행 130 | - 타겟을 감싸는 프록시는 Runtime에 생성 131 | 132 | ### **Spring AOP 프록시 종류** 133 | 134 | Spring에서는 AOP의 프록시를 적용하기 위해 JDK dynamic proxy와 CGLIB을 사용합니다. 135 | 136 | - JDK dynamic proxy 137 | 138 | **JDK dynamic proxy**는 타깃 대상이 Interface를 구현하는 클래스면 인터페이스를 기반으로 프록시 객체를 생성하기 때문에 인터페이스에 정의되지 않는 메서드에 대해서는 AOP가 적용되지 않는 단점이 있습니다. (private 메소드) 139 | 140 | JDK dynamic proxy는 내부적으로 **Reflection**을 이용합니다. 141 | 142 | - CGLIB 143 | 144 | **CGLIB**은 타깃 대상이 인터페이스를 구현하고 있지 않고 바로 클래스를 사용한다면, 스프링은 CGLIB를 이용하여 클래스에 대한 프록시 객체를 생성합니다. 145 | 146 | CBLIB는 **대상 클래스를 상속받아 구현**합니다. 따라서 클래스가 final인 경우에는 프록시를 생성할 수 없습니다. 147 | 148 | 위에 예시로 봤던 UserService에 AOP를 적용하고 해당 클래스를 출력해보면 아래와 같이 CGLIB이 적용된 걸 알 수 있습니다. 149 | 150 | ``` 151 | System.out.println(userService.getClass().getName()); 152 | ``` 153 | 154 | ![CGLIB](https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FunG7h%2FbtrCTFZKI1v%2FPX5y6ye3GPGt9EPLGhkDZK%2Fimg.png) 155 | 156 | 157 | Spring에서 제공하는 @Transactional도 Spring AOP 중 하나인데, CGLIB을 활용합니다. 158 | 159 | 실제로 적용되는지 확인해봤는데,  160 | 161 | 클래스에 어느 하나의 메소드라도 @Transactional이 적용되었다면 해당 클래스는 CGLIB으로 프록시 객체를 사용하는걸 알 수 있었습니다. 162 | 163 | 또한, 클래스에 @Transactional을 적용시켰다면 해당 클래스는 CGLIB으로 프록시 객체를 사용하는걸 알 수 있었습니다. 164 | 165 | --- 166 | 167 | AOP 관련 질문 168 | 169 | - Spring에서 AOP란 무엇인가요? 170 | - 횡단 관심사(cross-cutting concerns)에 대해 설명해주세요 171 | - Spring AOP Proxy에 대해 설명해주세요 -------------------------------------------------------------------------------- /Spring/2022-06-09-HttpMessageConverter.md: -------------------------------------------------------------------------------- 1 | # HTTP 메시지 컨버터 2 | 3 | Spring에서는 HTTP 메시지 컨버터를 이용해 XML, JSON과 같은 형식의 RequestBody 혹은 ResponseBody를 다룰수 있게 됩니다. 4 | 5 | 대표적으로 HTTP 메시지 컨버터는 `@RequestBody`, `@ResponseBody` 등을 사용할때 동작하게 됩니다. 6 | 7 | - `@RequestBody` 사용 예시 8 | 9 | ```java 10 | @PostMapping("/hello") 11 | public ResponseEntity create(@RequestBody HelloDto helloDto) { 12 | helloService.doSomething(helloDto); 13 | return new ResponseEntity<>(HttpStatus.OK); 14 | } 15 | ``` 16 | 17 | - `@ResponseBody` 사용 예시 18 | 19 | ```java 20 | @ResponseBody 21 | @GetMapping("/hello/{id}") 22 | public HelloDto getOne(@PathVariable long id) { 23 | return helloService.get(id); 24 | } 25 | ``` 26 | 27 | 위와 같이 사용하게 될 경우, Spring은 **메시지 컨버터를 사용해** HTTP 요청이나 응답을 메시지로 변환시켜줍니다. 28 | 29 | 우선 HTTP 메시지 컨버터를 알아보기 전에, `Argument Resolver`와 `ReturnValueHandler`에 대한 이해가 필요합니다. 30 | 31 | → `Argument Resolver`와 `ReturnValueHandler`가 **HTTP 메시지 컨버터를 사용**하기 때문 32 | 33 | ## Argument Resolver와 ReturnValueHandler 34 | 35 | ### 1. Argument Resolver 36 | 37 | ![Untitled](images/argumentResolver.png) 38 | 39 | `Argument Resolver`는 컨트롤러의 파라미터, 애노테이션 정보를 기반으로 컨트롤러(핸들러)가 필요로 하는 다양한 파라미터의 값(객체)를 생성해줍니다. 40 | 41 | 정확한 명칭은 `Argument Resolver`가 아니라 `HandlerMethodArgumentResolver` 입니다. 42 | 43 | - `HandlerMethodArgumentResolver` 내부 구현 코드 44 | 45 | ![Untitled](images/handleMethodArgumentResolver.png) 46 | 47 | `supportsParameter()` 를 호출해 해당 파라미터를 지원하는지 확인 후 48 | 49 | 만약 지원하는 파라미터라면 `resolveArgument()` 를 호출해서 객체를 생성해줍니다. 50 | 51 | 이렇게 생성된 객체는 컨트롤러의 파라미터로 전달되어집니다. 52 | 53 | 54 | 55 | ### 2. ReturnValueHandler 56 | 57 | `ReturnValueHandler`도 `ArgumentResolver`와 비슷합니다만 다른점은 컨트롤러의 반환값을 변환해준다는 점입니다. 58 | 59 | 정확한 명칭은 `HandlerMethodReturnValueHandler` 로 줄여서 `ReturnValueHandler`라고 부릅니다. 60 | 61 | - `HandlerMethodReturnValueHandler` 내부 구현 코드 62 | 63 | ![Untitled](images/handleMethodReturnValueHandler.png) 64 | 65 | 이 부분도 Argument Resolver와 마찬가지로 `supportsReturnType()` 을 이용해 66 | 67 | 해당 리턴타입을 지원하는지 확인 후 `handleReturnValue()` 를 호출해 리턴값에 대한 처리를 해줍니다. 68 | 69 | 70 | 71 | 위에 소개한 **Argument Resolver**와 **ReturnValueHandler 전부** **HTTP 메시지 컨버터를 이용**합니다. 72 | 73 | 그렇다면 다시 메시지 컨버터가 어떻게 동작되는지 알아보겠습니다. 74 | 75 | ## HTTP 메시지 컨버터 76 | 77 | ### 1. 동작원리 78 | 79 | ![Untitled](images/httpMessageConverter.png) 80 | 81 | 요청과 응답의 경우에서의 HTTP 메시지 컨버터에 대해 알아보겠습니다. 82 | 83 | HTTP 메시지 컨버터는 HTTP 요청과 HTTP 응답 둘다에서 사용됩니다. 84 | 85 | - 요청 86 | - Argument Resolver가 HTTP 메세지 컨버터를 호출해 필요한 객체를 생성합니다. 87 | - `@RequestBody` , `HttpEntity(RequestEntity)` 에 적용 88 | - `HttpEntity`는 `ResponseEntity` 의 상위 클래스다. header와 body를 담을 수 있음 89 | - 응답 90 | - ReturnValueHandler가 HTTP 메시지 컨버터를 호출해 응답 결과를 생성합니다. 91 | - `@ResponseBody` , `HttpEntity(ResponseEntity)` 에 적용 92 | 93 | - `HTTPMessageConverter` 내부 구현 코드 94 | 95 | ![Untitled](images/httpMessageConverter2.png) 96 | 97 | `canRead()` , `canWrite()` : 메시지 컨버터가 해당 클래스와 미디어 타입을 지원하는지 확인 98 | 99 | `read()` , `write()` : 메시지 컨버터를 통해 메시지를 읽고 쓰는 기능 100 | 101 | ### 2. HTTP 메시지 컨버터의 대표적인 구현체들 102 | 103 | ```java 104 | 0 = ByteArrayHttpMessageConverter 105 | 1 = StringHttpMessageConverter 106 | 2 = MappingJackson2HttpMessageConverter 107 | ... 108 | ``` 109 | 110 | 스프링 부트는 다양한 메시지 컨버터를 제공하는데, 대상 클래스 타입과 미디어 타입 둘을 체크해서 111 | 사용여부를 결정합니다. 112 | 113 | 만약 만족하지 않으면 다음 메시지 컨버터로 우선순위가 넘어갑니다. 114 | 115 | 요청에서는 **파라미터의 클래스 타입**과 **HTTP 요청 메시지 헤더에서의** **Content-Type**을 통해 메시지 컨버터가 결정되고 116 | 117 | 응답에서는 **리턴에 대한 클래스 타입**과 **HTTP 요청 메시지 헤더에서의** **Accept**를 통해 메시지 컨버터가 결정됩니다. 118 | 119 | - `ByteArrayHttpMessageConverter` : byte[] 데이터를 처리 120 | - 클래스 타입: byte[] , 미디어타입: **/** 121 | - 요청 예) @RequestBody byte[] data 122 | 123 | ```java 124 | content-type: application/json 125 | 126 | @RequestMapping 127 | public void hello(@RequetsBody byte[] data) {} 128 | ``` 129 | 130 | - 응답 예) @ResponseBody return byte[] , accept: application/octet-stream 131 | 132 | ```java 133 | accept:application/octet-stream 134 | 135 | @ResponseBody 136 | @RequestMapping 137 | public byte[] hello() { 138 | byte[] result = helloSerivce.doSomething(); 139 | return result ; 140 | } 141 | ``` 142 | 143 | - `StringHttpMessageConverter` : String 문자로 데이터를 처리 144 | - 클래스 타입: String , 미디어타입: **/** 145 | - 요청 예) @RequestBody String data 146 | 147 | ```java 148 | content-type: application/json 149 | 150 | @RequestMapping 151 | public void hello(@RequetsBody String data) {} 152 | ``` 153 | 154 | - 응답 예) @ResponseBody return "ok", accept: text/plain 155 | 156 | ```java 157 | accept:text/plain 158 | 159 | @ResponseBody 160 | @RequestMapping 161 | public String hello() { 162 | return "ok"; 163 | } 164 | ``` 165 | 166 | - `MappingJackson2HttpMessageConverter` : json 데이터를 처리 167 | - 클래스 타입: 객체 또는 HashMap , 미디어타입: application/json 관련 168 | - 요청 예) @RequestBody HelloData data 169 | 170 | ```java 171 | content-type: application/json 172 | 173 | @RequestMapping 174 | void hello(@RequetsBody HelloData data) {} 175 | ``` 176 | 177 | - 응답 예) @ResponseBody return helloData, accept: application/json 관련 178 | 179 | ```java 180 | accept:application/json 181 | 182 | @ResponseBody 183 | @RequestMapping 184 | public HelloDto hello() { 185 | helloDto helloData = helloSerive.doSomething(); 186 | return helloData; 187 | } 188 | ``` 189 | 190 | 191 | ## 정리 192 | 193 | - HTTP 요청 데이터 읽기 194 | - HTTP 요청이 오고, 컨트롤러에서 @RequestBody , HttpEntity 파라미터를 사용 195 | - 메시지 컨버터가 메시지를 읽을 수 있는지 확인하기 위해 `canRead()` 를 호출 196 | - 대상 클래스 타입을 지원하는가. 197 | 예) @RequestBody 의 대상 클래스 ( byte[] , String , HelloData ) 198 | - HTTP 요청의 Content-Type 미디어 타입을 지원하는가. 199 | 예) text/plain , application/json , */* 200 | - `canRead()` 조건을 만족하면 `read()` 를 호출해서 객체 생성하고, 반환 201 | - HTTP 응답 데이터 생성 202 | - 컨트롤러에서 @ResponseBody , HttpEntity 로 값이 반환 203 | - 메시지 컨버터가 메시지를 쓸 수 있는지 확인하기 위해 `canWrite()` 를 호출 204 | - 대상 클래스 타입을 지원하는가. 205 | 예) return의 대상 클래스 ( byte[] , String , HelloData ) 206 | - HTTP 요청의 Accept 미디어 타입을 지원하는가.(더 정확히는 @RequestMapping 의 produces ) 207 | 예) text/plain , application/json , */* 208 | - `canWrite()` 조건을 만족하면 `write()` 를 호출해서 HTTP 응답 메시지 바디에 데이터를 생성 -------------------------------------------------------------------------------- /Spring/2022-06-09-spring,springboot.md: -------------------------------------------------------------------------------- 1 | ### Spring(Spring framework) 2 | 3 | > The Spring Framework provides a comprehensive programming and configuration model for modern Java-based enterprise applications - on any kind of deployment platform. 4 | 5 | 6 | - 스프링 프레임워크는 자바 기반의 어플리케이션을 위한 프로그래밍을 제공한다. 7 | 8 | 9 | - 객체 지향의 특징을 잘 활용할 수 있게 해주고, 개발자로 하여금 비즈니스 로직 구현에만 집중할 수 있게 하여 생산성을 높임 10 | 11 | - (DI, IoC) 12 | 13 | 14 |
15 | 16 | 17 | ### SpringBoot 18 | >Spring Boot makes it easy to create stand-alone, production-grade ***Spring based Applications*** that you can "just run". 19 | We take an opinionated view of the Spring platform and third-party libraries so you can get started with minimum fuss. Most Spring Boot applications need ***minimal Spring configuration.*** 20 | 21 | 22 | - 스프링 기반의 어플리케이션을 쉽게 만들 수 있게 해 주는 프로젝트 23 | 24 | - 약간의 설정(minimal Spring configuration)만으로도 어플리케이션을 제작할 수 있게 해 줌. 25 | 26 | 27 | 28 | ![image](https://user-images.githubusercontent.com/72663337/172805496-5f74c87b-3178-41b8-bb71-8a16415028b6.png) 29 | 30 | 31 | 32 | - => SpringBoot는 Spring framework를 쉽게 사용할 수 있게 해주는 도구. 33 | 34 | 35 | 36 |
37 | 38 | 39 | 40 | ### SpringBoot 사용 시 달라지는 점 41 | 42 | #### 1. 의존성 관리 43 | 44 | 45 | **Spring** 46 | 47 | - 여러 의존성들을 추가할 때 필요한 의존성에 대한 호환되는 버전을 알고 있어야 하고, 개발자가 이를 직접 명시해 주어야 함. 48 | 49 | ``` 50 | 51 | org.hamcrest 52 | hamcrest 53 | 2.2 54 | compile 55 | 56 | 57 | org.junit.jupiter 58 | junit-jupiter 59 | 5.8.2 60 | compile 61 | 62 | 63 | org.mockito 64 | mockito-core 65 | 4.5.1 66 | compile 67 | 68 | .. 69 | ``` 70 | 71 | - test를 위하여 필요한 의존성들을 추가하는 경우(jupiter, hamcrest...) 72 | 73 | 위와 같이 의존성 버전을 맞추어 설정해 주어야 함!! 74 | 75 | 76 | 77 |
78 | 79 | 80 | 81 | ***SpringBoot*** 82 | 83 | ``` 84 | 85 | org.springframework.boot 86 | spring-boot-starter-test 87 | test 88 | 89 | ``` 90 | 91 | - 자동으로 다수의 의존성이 정의되었기 때문에 간단하게 설정을 끝낼 수 있다. (ex : spring-boot-starter ) 92 | 93 | - spring-boot-starter-test 의존성 추가를 통해 위의 의존성들을 대체할 수 있음 94 | 95 | 96 | 97 | ![image](https://user-images.githubusercontent.com/72663337/172805621-308a62d0-d85d-4957-a793-bebfe62090ad.png) 98 | 99 | 100 | - spring-boot-starter-test 내부(jupitor, mokito 등의 라이브러리들을 내장하고 있음을 description에서부터도 알 수 있다.) 101 | 102 | 103 |
104 | 105 | 106 | #### 2. 설정의 자동화 107 | 108 | 109 | ***Spring*** 110 | 111 | - configuration 파일(설정값들을 정의하는 파일)에 bean 들을 명시적으로 작성하는 방식으로 등록시켜주어야 함. 112 | 113 | ... 114 | @Bean 115 | public DataSource dataSource() { 116 | 117 | var dataSource = DataSourceBuilder.create() 118 | .url("jdbc:mysql://localhost:2215/test-voucher_prgrms") 119 | .username("test") 120 | .password("test123") 121 | .type(HikariDataSource.class) 122 | .build(); 123 | 124 | return dataSource; 125 | } 126 | 127 | @Bean 128 | public JdbcTemplate jdbcTemplate(DataSource dataSource) { 129 | return new JdbcTemplate(dataSource); 130 | } 131 | ... 132 | - 데이터베이스와의 연결을 위해 빈들을 등록해주어야 함 133 | 134 | 135 | 136 | 137 | 138 | ***SpringBoot*** 139 | 140 | - AutoConfiguration 기능으로 위를 대체할 수 있음 141 | 142 | 143 | 144 | ![image](https://user-images.githubusercontent.com/72663337/172806194-bce44f5d-80e7-4226-a394-4586ceb039a2.png) 145 | 146 | 147 | - 부트 프로젝트에서 사용되는 @SpringBootApplication 148 | 149 | 150 | 151 | ![image](https://user-images.githubusercontent.com/72663337/172806308-35be8c20-483b-4970-b016-a6bc117cf94f.png) 152 | 153 | 154 | @SpringBootApplication 어노테이션 안에 설정을 자동으로 세팅해주는 여러 어노테이션이 동작하고 있음. 155 | 156 | 157 | 자동 설정을 도와주는 어노테이션을 보면 158 | 159 | ***@ComponentScan*** 160 | 161 | - 패키지들을 스캔하면서 Bean으로 등록할 클래스들을 탐색/등록 162 | 163 | ***@EnableAutoConfiguration*** 164 | 165 | - 마찬가지로 Spring.factories라는 설정 파일을 통하여 설정값들에 따라 추가적으로 Bean 등록 166 | 167 | 168 | 169 | 위의 어노테이션에 의해 프로젝트에서 요구되는 Bean들이 생성/등록되며, 설정 파일에 명시해주지 않아도 자동 설정이 이루어지게 됨. 170 | 171 | 172 |
173 | 174 | 175 | #### 3. 내장 WAS(Web Application Server) 176 | 177 | ***Spring*** 178 | 179 | 프로젝트를 war(Web application ARchive) 파일로 패키징 -> WAS 설치 -> 설치한 WAS 서버에 WAR 파일을 올려 배포 180 | 181 | 182 | 183 | 184 | 185 | ***SpringBoot*** 186 | 187 | 내장된 WAS 서버를 갖고 있기 때문에 위와 같은 과정은 필요 없음 188 | 189 | Run 버튼을 누르는 것만으로도 서버 위에서 프로젝트를 동작시킬 수 있음 190 | 191 | 192 | 193 | 194 |
195 | 196 | 197 | #### 4. 모니터링 198 | - 실행 중 어플리케이션의 상태를 모니터링, 관리할 수 있는 기능 199 | 200 | - Actuator(CPU, JVM memory 사용률, 로그, endpoint에서의 작업 관리 등) 를 통하여 모니터링 과정이 이루어 짐. 201 | 202 | (민감 정보를 제공할 수 있기 때문에 운영 시에는 spring security를 사용하는 방법 등을 통해 보안에 신경을 써주어야 함.) 203 | 204 | 205 | 206 | 207 | 208 |
209 | 210 | ### 결론 211 | 212 | SpringBoot는 Spring framework를 통한 프로젝트에 대하여 자동 설정을 쉽게 해주는 프로젝트. 213 | 214 | 개발자가 설정 세팅과 같은 문제에 소모하는 비용을 줄이게 함. 215 | 216 | 217 | 218 |
219 | 220 | ### Reference 221 | 222 | https://spring.io/projects/spring-framework 223 | 224 | 225 | http://theeye.pe.kr/archives/2014 226 | 227 | 228 | https://www.youtube.com/watch?v=6h9qmKWK6Io 229 | 230 | 231 | 232 | 233 | -------------------------------------------------------------------------------- /Spring/images/argumentResolver.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prgrms-web-devcourse/BE-Team-R-CS-Study/d0535ce8aeb0166acb1ef886b431ecf3d25e5cfa/Spring/images/argumentResolver.png -------------------------------------------------------------------------------- /Spring/images/handleMethodArgumentResolver.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prgrms-web-devcourse/BE-Team-R-CS-Study/d0535ce8aeb0166acb1ef886b431ecf3d25e5cfa/Spring/images/handleMethodArgumentResolver.png -------------------------------------------------------------------------------- /Spring/images/handleMethodReturnValueHandler.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prgrms-web-devcourse/BE-Team-R-CS-Study/d0535ce8aeb0166acb1ef886b431ecf3d25e5cfa/Spring/images/handleMethodReturnValueHandler.png -------------------------------------------------------------------------------- /Spring/images/httpMessageConverter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prgrms-web-devcourse/BE-Team-R-CS-Study/d0535ce8aeb0166acb1ef886b431ecf3d25e5cfa/Spring/images/httpMessageConverter.png -------------------------------------------------------------------------------- /Spring/images/httpMessageConverter2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prgrms-web-devcourse/BE-Team-R-CS-Study/d0535ce8aeb0166acb1ef886b431ecf3d25e5cfa/Spring/images/httpMessageConverter2.png --------------------------------------------------------------------------------