From 60111df4af07b0595033f98e8f024ea6628b0ae9 Mon Sep 17 00:00:00 2001 From: Han Date: Sat, 1 May 2021 01:06:02 +0900 Subject: [PATCH 001/142] Update README.md Add reference --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 569cfe9..9de1b3e 100644 --- a/README.md +++ b/README.md @@ -44,3 +44,7 @@ - 미팅 - 매주 화요일 20:00 ~ 20:30 까지 화상으로 그 주 진행한 스터디에 대해 피드백 하는 시간 - 해당 미팅에 참석하지 못할 경우, 해당 일 오전까지는 참가원에게 알려줘야함 + + ## 참고 + - [면접질문-JaeYeopHan](https://github.com/JaeYeopHan/Interview_Question_for_Beginner) + - [우테코-테크톡](https://www.youtube.com/watch?v=vNsZXC3VgUA&list=PLgXGHBqgT2TvpJ_p9L_yZKPifgdBOzdVH) From e1ffb4624a7de0470b83f2ae3d3a4f84457c818e Mon Sep 17 00:00:00 2001 From: choijangho Date: Sat, 1 May 2021 21:08:01 +0900 Subject: [PATCH 002/142] =?UTF-8?q?[1=EC=A3=BC=EC=B0=A8]=20=EC=BF=A0?= =?UTF-8?q?=ED=82=A4=20=EC=84=B8=EC=85=98=20=EC=A0=95=EB=A6=AC=20(hoi)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cookie-vs-session/hoi/README.md | 52 +++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 cookie-vs-session/hoi/README.md diff --git a/cookie-vs-session/hoi/README.md b/cookie-vs-session/hoi/README.md new file mode 100644 index 0000000..060d00e --- /dev/null +++ b/cookie-vs-session/hoi/README.md @@ -0,0 +1,52 @@ +# Cookie && Session + +### Cookie + +쿠키는 서버와 클라이언트 간 상태를 관리하는 유용한 기능입니다. 상태를 유지하지 않는 특징을 가진 통신 특성상 쿠키에 정보를 저장하고 서버와 클라이언트가 정보를 공유하여 이해할 수 있는 기능에는 로그인 유지와 같은 일들을 가능하게 합니다. + +**쿠키를 위한 헤더 필드** + +Set-Cookie (Response) : 상태 관리 개시를 위한 쿠키 정보 + +Cookie (Request) : 서버에서 수신한 쿠키 정보 + +### Set-Cookie + +서버에서 클라이언트의 쿠키 환경에 담을 수 있는 헤더 필드 입니다. + +- **Name=Value** : 쿠키에 부여된 이름과 값 (해당 필드는 필수) +- **Expires** : 쿠키의 유효 기간을 지정 (지정되지 않는 경우는 브라우저의 세션을 유지하는 기간만 적용) +- **Path** : 쿠키 적용 대상이 되는 서버 상의 디렉토리 +- **Domain** : 쿠키 적용 대상이 되는 도메인 명 +- **Secure** : HTTPS를 통신하는 경우만 쿠키 송신 +- **HttpOnly** : JavaScript상에서 쿠키 값에 적용하지 못하도록 제한하는 필드 + +위와 같이 서버에서 여러가지 속성을 통해서 쿠키 정보를 설정한 후 전달이 가능하고 클라이언트도 역시 JavaScript에서 쿠키를 담을 수 있습니다. + +### 쿠키의 한계 + +유용하게만 보인 쿠키에는 몇 가지 제약적인 사항이 존재합니다. + +- 4KB의 크기를 넘을 수 없습니다. 때문에 방대한 양의 데이터를 쿠키에 저장하는 일은 불가능 합니다. +- 도메인마다 다르지만 쿠키의 개수는 20개로 한정됩니다. + +### Session + +웹브라우저에는 정보를 저장할 수 있는 Storage가 존재하며 session과 local로 분류할 수 있습니다. +두 저장 공간은 각각 아래와 같은 차이를 가집니다. + +**localStorage** : 페이지 세션을 종료해도 데이터를 만료하지 않는다. + +**sessionStorage** : 페이지 세션이 종료되는 시점에 제거된다. + +또한 sessionStorage에 저장된 자료는 페이지에 해당하는 프로토콜별로 구분합니다. + +`http://my-web.com , [https://my-web.com](https://my-web.com) 이 둘은 서로 다른 저장 공간에 저장 !` + +### 참고 링크 + +만화로 배우는 HTTP & Network basic + +[https://ko.javascript.info/cookie](https://ko.javascript.info/cookie) + +[https://developer.mozilla.org/ko/docs/Web/API/Web_Storage_API/Using_the_Web_Storage_API](https://developer.mozilla.org/ko/docs/Web/API/Web_Storage_API/Using_the_Web_Storage_API) From 42a91776e442a5efa9502ccbc99e265b9ba1b6f4 Mon Sep 17 00:00:00 2001 From: choijangho Date: Sun, 2 May 2021 19:31:26 +0900 Subject: [PATCH 003/142] =?UTF-8?q?[1=EC=A3=BC=EC=B0=A8]=20SSL=20=ED=81=B4?= =?UTF-8?q?=EB=9D=BC=EC=9D=B4=EC=96=B8=ED=8A=B8=20=EC=9D=B8=EC=A6=9D=20?= =?UTF-8?q?=EC=88=98=EC=88=9C=20(hoi)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ssl-client-authentication-flow/hoi/README.md | 58 ++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 ssl-client-authentication-flow/hoi/README.md diff --git a/ssl-client-authentication-flow/hoi/README.md b/ssl-client-authentication-flow/hoi/README.md new file mode 100644 index 0000000..813e734 --- /dev/null +++ b/ssl-client-authentication-flow/hoi/README.md @@ -0,0 +1,58 @@ +### SSL 클라이언트 인증 수순 + +### 인증 + +클라이언트가 서버에게 자신을 알리고 정보를 받아오기 위해서는 자신을 인증하기 위한 여러가지 수단이 필요합니다. 대표적으로는 아래와 같은 정보를 활용하여 인증의 과정을 거칩니다. + +- 패스워드 : 개인이 설정한 문자열 형태의 정보 +- 원타임 토큰 : 본인의 고유 기기 등에 표시되는 휘발성의 패스워드 정보들 +- 전자 증명서 : 본인만이 가지고 있는 파일 형태의 증명서 정보 +- 바이오 매트릭스 : 지문인식 ,페이스 아이디와 같이 신체를 활용한 인증 정보 +- IC 카드 : 본인만이 가지고 있는 정보 + +### SSL + +SSL은 클라이언트와 서버의 통신에 있어서 HTTP/1.1이 사용하는 인증의 한 종류 입니다. HTTPS의 클라이언트 인증서를 이용하여 인증하는 방식을 뜻합니다. + +### SSL 클라이언트 인증의 인증 수순 + +SSL 클라이언트 인증은 증명서를 기반으로 인증 과정을 거칩니다. 따라서 클라이언트는 인증 전 클라이언트 환경에 증명서를 배포하고 인스톨하여 준비할 필요가 있습니다. + +1. 인증이 필요한 리소스의 리퀘스트가 존재할 경우 서버는 클라이언트에 `Certificate Request` 메세지를 송신 +2. 사전에 준비한 증명서를 선택 후 증명서와 함께 `Client Certificate` 메세지 송신 +3. 증명서의 유효성을 검증한 후 증명이 유효하다면 클라이언트의 공개키를 취득 후 HTTPS 암호를 개시 + +### SSL 클라이언트 인증과 2-factor 인증 + +**2-factor 인증(Multi-Factor Authentication)이 뭔가요 ?** 💁 + +위에서 여러 인증을 위한 수단에는 지식기반 , 소유기반 , 속성기반 인증을 사용하며, 이란 분류를 인증 펙터라고 합니다 ! +이렇게 분류된 여러 인증 펙터를 SSL은 폼 베이스 인증과 합쳐서 병용하는 인증 방법입니다. + +**2-factor는 어떻게 운용 하는가 ?** + +필수적으로 인증해야 하는 구간이 나의 컴퓨터와 유저 인증이라고 가정해 보록 하겠습니다. + +- 클라이언트 인증(내 컴퓨터,SSL) : SSL 증명서를 통해서 유효한 클라이언트 인증 +- 유저 인증(폼 베이스): 아이디, 패스워드를 통해서 유저 본인을 인증 (생체 인식 , IC 카드 토큰 등등 다양하게 활용 가능) + +### 무엇이 문제인가 ? + +SSL 인증은 증명서를 사용하고 그 증명서를 사용하기 위해서는 그만큼의 비용이 필요하게 됩니다. + +[https://www.ssl.com/ko/방법/웹-브라우저에서-클라이언트-인증-인증서-구성/](https://www.ssl.com/ko/%EB%B0%A9%EB%B2%95/%EC%9B%B9-%EB%B8%8C%EB%9D%BC%EC%9A%B0%EC%A0%80%EC%97%90%EC%84%9C-%ED%81%B4%EB%9D%BC%EC%9D%B4%EC%96%B8%ED%8A%B8-%EC%9D%B8%EC%A6%9D-%EC%9D%B8%EC%A6%9D%EC%84%9C-%EA%B5%AC%EC%84%B1/) + +위 링크는 SSL 인증 기관에서 증명서를 발급하는 방법이며 연간 비용에 대해서도 설명하고 있습니다. +증명서를 하나 발급하는데 연간 수만 원 부터 수백만 원까지 운용비가 들 수 있으며 따라서 정말 신뢰성 있는 사용자만 접근해야 하는지를 판단할 필요가 있습니다. 요즘 같이 코로나로 인해서 재택 근무가 많아지는 시기에 SSL은 좋은 인증 방식으로 운용될 수 있습니다. + +### 참고 링크 + +(서적) +그림으로 배우는 HTTP&Network Basic + +SSL 증명서 운용 비용 + +[https://www.ssl.com/ko/방법/웹-브라우저에서-클라이언트-인증-인증서-구성/](https://www.ssl.com/ko/%EB%B0%A9%EB%B2%95/%EC%9B%B9-%EB%B8%8C%EB%9D%BC%EC%9A%B0%EC%A0%80%EC%97%90%EC%84%9C-%ED%81%B4%EB%9D%BC%EC%9D%B4%EC%96%B8%ED%8A%B8-%EC%9D%B8%EC%A6%9D-%EC%9D%B8%EC%A6%9D%EC%84%9C-%EA%B5%AC%EC%84%B1/) + +Factor에 대한 글 +[https://m.blog.naver.com/n_privacy/221131898198](https://m.blog.naver.com/n_privacy/221131898198) From f5b5e77a214a98e7b329c3b89a183b776b2b45b3 Mon Sep 17 00:00:00 2001 From: 102092 Date: Sun, 2 May 2021 20:27:06 +0900 Subject: [PATCH 004/142] Add cookie-vs-session --- network/cookie-vs-session/README.md | 48 +++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 network/cookie-vs-session/README.md diff --git a/network/cookie-vs-session/README.md b/network/cookie-vs-session/README.md new file mode 100644 index 0000000..34da3e5 --- /dev/null +++ b/network/cookie-vs-session/README.md @@ -0,0 +1,48 @@ +# Cookie +- text file, plan text +- 클라이언트(웹 브라우저등..)에 저장됨 +- Key - Value의 구조로 저장됨. +- 클라이언트 사이드에 저장되기 때문에 그리 안전하지 못함. + - 즉 쿠키 정보를 수정하여, 잘못된 요청을 줄 수 있음. +- 클라이언트에서 받는 요청의 Header에 `Set-cookie` 가 있을 경우, 그 옵션에 따라 브라우저는 저장하게됨. + ``` + Set-Cookie: value[; expires=date][; domain=domain][; path=path][; secure] + ``` + +## Cookie Options +- domain + - 쿠키가 보내진 곳 + - 해당 값은 `Set-cookie` header에 포함된 값이어야 함. 그 값이 아닐 경우 무시될 수 있음. +- path + - url path + - 보통 `/` 많이 쓰는 듯. + - 왜? 루트 패스 이하 url에서 해당 쿠키를 이용하기 위해서.. +- secure + - flag option + - secure 옵션을 가지고 있는 쿠키는, request가 SSL, HTTPS protocol에 의해 만들어질 때만 서버에 전송되어질 수 있음. +- HttpOnly + - XSS를 방지하기 위해 등장 (cross-stie scripting) + - 해당 옵션을 가지고 있는 쿠키는 Javascript의 `document.cookie` 를 통해 접근할 수 없도록 되어있음 + + +# Session +- 위 쿠키와 거의 비슷, 다만 서버 쪽에 저장됨. + - 서버쪽에 저장되기 때문에, 사용자가 많아지면 서버쪽 메모리를 과다하게 사용하게 될 수 도 있음. +- 서버쪽에 저장되므로, 보안상에서 쿠키 보다는 나음. +- 클라이언트가 서버쪽에 요청을 보내면, 고유 ID를 담아서 내려주는 방식 + + +# Cookie vs Session +- 두가지 모두 사용자의 상태를 관리하기 위해서 존재함. +- 다만 어느 쪽 (클라이언트, 서버) 에 저장되는 지가 가장 큰 차이점. + +# 더 알아보면 좋을 내용.. +- Sticky session +- Session Clustering +- JWT Token + + +# 참고 +- https://humanwhocodes.com/blog/2009/05/05/http-cookies-explained/#:~:text=Quite%20simply%2C%20a%20cookie%20is,on%20a%20set%20of%20rules. +- https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie +- https://stackoverflow.com/questions/6253633/cookies-vs-sessions \ No newline at end of file From fea1cce3e0bc8c3ce740089d8fbb954dae004b84 Mon Sep 17 00:00:00 2001 From: 102092 Date: Sun, 2 May 2021 21:07:16 +0900 Subject: [PATCH 005/142] Add reference --- network/cookie-vs-session/README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/network/cookie-vs-session/README.md b/network/cookie-vs-session/README.md index 34da3e5..f3ae37c 100644 --- a/network/cookie-vs-session/README.md +++ b/network/cookie-vs-session/README.md @@ -45,4 +45,5 @@ # 참고 - https://humanwhocodes.com/blog/2009/05/05/http-cookies-explained/#:~:text=Quite%20simply%2C%20a%20cookie%20is,on%20a%20set%20of%20rules. - https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie -- https://stackoverflow.com/questions/6253633/cookies-vs-sessions \ No newline at end of file +- https://stackoverflow.com/questions/6253633/cookies-vs-sessions +- https://www.youtube.com/watch?v=y0xMXlOAfss \ No newline at end of file From ec657d8e3232e3fa03dc185ba3e9974a43a3da86 Mon Sep 17 00:00:00 2001 From: 102092 Date: Sun, 2 May 2021 21:48:52 +0900 Subject: [PATCH 006/142] Add ssl/tls --- .../ssl-client-authentication-flow/README.md | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 network/ssl-client-authentication-flow/README.md diff --git a/network/ssl-client-authentication-flow/README.md b/network/ssl-client-authentication-flow/README.md new file mode 100644 index 0000000..445af38 --- /dev/null +++ b/network/ssl-client-authentication-flow/README.md @@ -0,0 +1,52 @@ +# SSL +- Secure Sockets Layer, TLS (Tranport Layer Security) 전송 계층 보안 +- SSL 3.0을 개선시켜서 나온 게 TLS 1.0.. +- TLS 1.0 이 후 SSL은 deprecated 됨. + - 엄밀하게 말하면 SSL, TLS는 다른 것이지만.. + - SSL/TLS은 TLS를 의미하는 걸로 이해됨. + +# TLS +![image](https://user-images.githubusercontent.com/22140570/116811965-26833600-ab87-11eb-9847-004fb1385b24.png) +- 응용 계층 데이터를 암호화해주고, 암호화되어 전송 계층으로 들어온 데이터를 복호화 해주는 역할 +- TCP의 443포트 사용 +- 제공하는 3가지 기능 + 1. 암호화 Encryption (내가 보낸 데이터를, 원하는 상대방만 확인할 수 있도록) + 2. 인증 Authentication (내가 받은 데이터가, 원하는 상대방으로 부터 온 것인지 확인하는 것) + 3. 무결성 Integrity (메세지가 전송 중 위/변조 되지 않았음을 확인) +- HTTPS 의 기반 기술 + +## 어떻게 암호화 되는가? +![image](https://user-images.githubusercontent.com/22140570/116811987-44e93180-ab87-11eb-8d2a-1c08685f9dad.png) +- TLS HandShake를 이용 + + +## 어떻게 인증 하는가? +- TLS conection 을 성립하기 위해 필수적인 부분 + 즉 자신이 기대하고 있는 대상과 커넥션이 되어있는 지 확인하는 과정 +![image](https://user-images.githubusercontent.com/22140570/116813385-816c5b80-ab8e-11eb-90d8-5326a3e293f2.png) +- Alice, Bob은 서로 public key를 공유하고, +- Alice는 메세지를 자신의 private key로 암호화하여, Bob에게 보내면 +- Bob은 Alice의 public키로 해당 메세지를 인증한다. (Alice가 보냈구나!) + +- 사이트 간 인증 방법 +![image](https://user-images.githubusercontent.com/22140570/116813054-d7d89a80-ab8c-11eb-9343-fa1de8c5f85b.png) +- **Chain of Trust and Certificate Authorities** +1. Root CA는 중간 인증 기간에 인증서를 주고.. +2. 중간 인증 기간은 특정 사이트에 인증서를 준다.. +3. 해당 사이트에서 어떤 요청을 보낼 때, 브라우저는 중간 인증서에 공개키로 암호화하여 보낸다. + +## 어떻게 무결성을 확인 하는가? +![image](https://user-images.githubusercontent.com/22140570/116811906-b8d70a00-ab86-11eb-8b23-cf2afe2f5209.png) +1. 보내는 사람은 자신의 메세지를 MAC Algorithm을 통해 암호화하여 보냄 +2. 받는 사람은 메세지를 받은 후, 해당 메세지를 포함된 MAC Algorithm을 통해 암호화 하여 자신이 받은 데이터와 동일한지 판단. + +# 더 알아보면 좋은 내용.. + - X.509 certificates + - 공개키, 대칭키 암호화 + +# 참고 +- https://www.ssl.com/faqs/faq-what-is-ssl/ +- https://www.youtube.com/watch?v=EPcQqkqqouk&list=PLgXGHBqgT2TvpJ_p9L_yZKPifgdBOzdVH&index=74 +- https://hpbn.co/transport-layer-security-tls/ +- https://webactually.com/2018/11/16/http%EC%97%90%EC%84%9C-https%EB%A1%9C-%EC%A0%84%ED%99%98%ED%95%98%EA%B8%B0-%EC%9C%84%ED%95%9C-%EC%99%84%EB%B2%BD-%EA%B0%80%EC%9D%B4%EB%93%9C/ +- https://engineering.linecorp.com/ko/blog/best-practices-to-secure-your-ssl-tls/ \ No newline at end of file From 55a2631cb6588eda20c0b24611fd2a9bca6d0fdd Mon Sep 17 00:00:00 2001 From: 102092 Date: Tue, 4 May 2021 20:21:51 +0900 Subject: [PATCH 007/142] Modify directory --- network/cookie-vs-session/{ => han}/README.md | 0 network/ssl-client-authentication-flow/{ => han}/README.md | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename network/cookie-vs-session/{ => han}/README.md (100%) rename network/ssl-client-authentication-flow/{ => han}/README.md (100%) diff --git a/network/cookie-vs-session/README.md b/network/cookie-vs-session/han/README.md similarity index 100% rename from network/cookie-vs-session/README.md rename to network/cookie-vs-session/han/README.md diff --git a/network/ssl-client-authentication-flow/README.md b/network/ssl-client-authentication-flow/han/README.md similarity index 100% rename from network/ssl-client-authentication-flow/README.md rename to network/ssl-client-authentication-flow/han/README.md From 8b9da0a2fda45edd27be5d733da8e51877cbc59c Mon Sep 17 00:00:00 2001 From: 102092 Date: Tue, 11 May 2021 20:28:42 +0900 Subject: [PATCH 008/142] Add qna --- network/ssl-client-authentication-flow/han/README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/network/ssl-client-authentication-flow/han/README.md b/network/ssl-client-authentication-flow/han/README.md index 445af38..c7f1b91 100644 --- a/network/ssl-client-authentication-flow/han/README.md +++ b/network/ssl-client-authentication-flow/han/README.md @@ -49,4 +49,6 @@ - https://www.youtube.com/watch?v=EPcQqkqqouk&list=PLgXGHBqgT2TvpJ_p9L_yZKPifgdBOzdVH&index=74 - https://hpbn.co/transport-layer-security-tls/ - https://webactually.com/2018/11/16/http%EC%97%90%EC%84%9C-https%EB%A1%9C-%EC%A0%84%ED%99%98%ED%95%98%EA%B8%B0-%EC%9C%84%ED%95%9C-%EC%99%84%EB%B2%BD-%EA%B0%80%EC%9D%B4%EB%93%9C/ -- https://engineering.linecorp.com/ko/blog/best-practices-to-secure-your-ssl-tls/ \ No newline at end of file +- https://engineering.linecorp.com/ko/blog/best-practices-to-secure-your-ssl-tls/ + +# QnA \ No newline at end of file From 40efa3952695f128338173a0caa95438402ad262 Mon Sep 17 00:00:00 2001 From: 102092 Date: Tue, 11 May 2021 20:30:28 +0900 Subject: [PATCH 009/142] Add hamil qna --- network/ssl-client-authentication-flow/han/README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/network/ssl-client-authentication-flow/han/README.md b/network/ssl-client-authentication-flow/han/README.md index c7f1b91..b8408bd 100644 --- a/network/ssl-client-authentication-flow/han/README.md +++ b/network/ssl-client-authentication-flow/han/README.md @@ -51,4 +51,8 @@ - https://webactually.com/2018/11/16/http%EC%97%90%EC%84%9C-https%EB%A1%9C-%EC%A0%84%ED%99%98%ED%95%98%EA%B8%B0-%EC%9C%84%ED%95%9C-%EC%99%84%EB%B2%BD-%EA%B0%80%EC%9D%B4%EB%93%9C/ - https://engineering.linecorp.com/ko/blog/best-practices-to-secure-your-ssl-tls/ -# QnA \ No newline at end of file +# QnA + +## Hamil +- 쿠키와 세션은 상태를 유지하기 위해 사용한다고 하는데요. 그렇다면 상태를 유지하기 위해 어떤 방법을 사용하는 게 더 좋을까요? +- HTTPS 를 제공하는 사이트의 SSL 인증서를 직접 확인해보고, SSL 인증서에는 대표적으로 어떤 내용이 들어있는지 알아봅시다 \ No newline at end of file From 6071437b57b4cff45649bbc5fc09e5dcdb37f45f Mon Sep 17 00:00:00 2001 From: 102092 Date: Wed, 12 May 2021 21:44:56 +0900 Subject: [PATCH 010/142] Add hoi qna --- .../han/README.md | 31 +++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/network/ssl-client-authentication-flow/han/README.md b/network/ssl-client-authentication-flow/han/README.md index b8408bd..0365b62 100644 --- a/network/ssl-client-authentication-flow/han/README.md +++ b/network/ssl-client-authentication-flow/han/README.md @@ -54,5 +54,32 @@ # QnA ## Hamil -- 쿠키와 세션은 상태를 유지하기 위해 사용한다고 하는데요. 그렇다면 상태를 유지하기 위해 어떤 방법을 사용하는 게 더 좋을까요? -- HTTPS 를 제공하는 사이트의 SSL 인증서를 직접 확인해보고, SSL 인증서에는 대표적으로 어떤 내용이 들어있는지 알아봅시다 \ No newline at end of file +> 쿠키와 세션은 상태를 유지하기 위해 사용한다고 하는데요. 그렇다면 상태를 유지하기 위해 어떤 방법을 사용하는 게 더 좋을까요? + +- 어떤 상태 유지가 목적인지에 따라 갈릴듯 +- 로그인 상태 유지이면, 서버에서 관리하는 세션이 좀 더 안전한 방법이라 생각되고, +- 단순 유저의 행동을 기록하기 위해서라면, 중요한 내용이 아니라면, 쿠키를 통해 관리하는 게 좋은 선택으로 생각됨. + +> HTTPS 를 제공하는 사이트의 SSL 인증서를 직접 확인해보고, SSL 인증서에는 대표적으로 어떤 내용이 들어있는지 알아봅시다 + +- 이름 : *.google.com -> 특정 사이트가 아닌 꽤 많은 사이트들이 이 인증서가 보장하고 있는 듯 싶네요. +- 유효 기간 +- 공개키.. +- 확장키.. +- 지문 : 아마도 해당 인증서가 변조되었는지 판단하는 기준이지 않을까 합니다. + +## Hoi + +> 세션을 사용하면 서버에 부하가 갈수도 있다면 부하의 상황에 대비하여 어떤 해결책이 있나요 ? 클라이언트에 쿠키로 저장하는게 방법인지 궁금합니다. 간단한 예시 하나 부탁드려요 + +- 서버 마련된 세션 DB를 사용하는 것이 아닌, 세션 만을 위한 다른 DB를 사용하면 될 것 같네요. + +- 예를 들면, Redis 와 같은 DB를 사용하는 방향을 말씀드릴 수 있을 것 같아요. +- 즉 서버 쪽에 세션을 마련된 공간을 사용하면, 이용량이 늘어날수록 다른 서비스에 영향을 줄 수 있으니, +- 아예 세션만을 담당하는 DB를 마련 (Redis) 이곳에 Session 을 저장하고 다른 서버에서 사용하는 방식을 사용하는 방식 입니다 + +> 메세지의 무결성은 어떤식으로 보장해 주는지 궁금합니다 ! + +1. 자신의 메세지로 부터 나온 MAC (메세지 인증 코드) 같이 묶어 암호화 하여 수신자에게 전송 +2. 수신자는 메세지를 그대로 받고, 이 메세지로 부터 MAC'를 도출해내어서, +3. 처음 받은 MAC과 자신이 도출해놓은 MAC' 를 비교하여 메세지가 변조되었음을 감지한다고 합니다! \ No newline at end of file From 1535ac42b60e7e732559aef28b00d1973f9c3f07 Mon Sep 17 00:00:00 2001 From: 102092 Date: Wed, 12 May 2021 21:47:52 +0900 Subject: [PATCH 011/142] Modify directory --- {cookie-vs-session => network/cookie-vs-session}/hamill/README.md | 0 .../ssl-client-authentication-flow}/hamill/README.md | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename {cookie-vs-session => network/cookie-vs-session}/hamill/README.md (100%) rename {ssl-client-authentication-flow => network/ssl-client-authentication-flow}/hamill/README.md (100%) diff --git a/cookie-vs-session/hamill/README.md b/network/cookie-vs-session/hamill/README.md similarity index 100% rename from cookie-vs-session/hamill/README.md rename to network/cookie-vs-session/hamill/README.md diff --git a/ssl-client-authentication-flow/hamill/README.md b/network/ssl-client-authentication-flow/hamill/README.md similarity index 100% rename from ssl-client-authentication-flow/hamill/README.md rename to network/ssl-client-authentication-flow/hamill/README.md From 4dfa42d055e0ef079e663f871d1f781f695d2f7e Mon Sep 17 00:00:00 2001 From: 102092 Date: Mon, 17 May 2021 22:15:47 +0900 Subject: [PATCH 012/142] Add first draft --- network/http-1.1-vs-http-2.0/han/README.md | 101 +++++++++++++++++++++ network/web-cache/han/README.md | 73 +++++++++++++++ 2 files changed, 174 insertions(+) create mode 100644 network/http-1.1-vs-http-2.0/han/README.md create mode 100644 network/web-cache/han/README.md diff --git a/network/http-1.1-vs-http-2.0/han/README.md b/network/http-1.1-vs-http-2.0/han/README.md new file mode 100644 index 0000000..0508e5c --- /dev/null +++ b/network/http-1.1-vs-http-2.0/han/README.md @@ -0,0 +1,101 @@ +# HTTP/1.1 + +- 클라이언트 컴퓨터와, 웹 서버에서 정보를 교환할 떄 사용하는, top-level application protocol임 +- 클라이언트 `GET`, `POST` 라고 불리는 메서드를 text-basted request에 담아 서버에 보냄. + - 그러면 서버는 요청에 따른 리소스를 전달해줌. + +- 예시 + + ```http + GET /index.html HTTP/1.1 + Host: www.example.com + ``` + + - `GET` 메서드 + + - `www.example.com` 이라는 호스트에 `/index.html` 라는 자원을 요청하는 request + + - 만약 이 html에 포함된 image, stylesheet등의 다른 자원이 있다면, 첫번째 요청에 **모든 자원들이 전달되는 것은 아니다.** + + - 브라우저에서 필요할 때, 다시 서버에 요청하게 됨.![](https://assets.digitalocean.com/articles/cart_63893/Protocol_Stack.png) + +- 느리다.. 왜? + + - 헤더가 큼 -> 많은 메타 정보들이 들어가 있음. 특히 쿠키! + - HOL(Head Of Line) Blocking (특정 응답 지연) + - 클라이언트 ,서버 응답 순서가 동기화되어야하기 때문에, 어느 한곳에서 응답이 늦어지면.. 문제가 생김 + - RTT(Round Trip TIme) 증가 (양방향 지연) + + + +### Pipelining and Head-of-Line Blocking + +- 클라이언트에서 온 `GET` 메서드에 대해 서버가 응답을 보냈을 경우, 하나의 페이지를 제대로 그려서 사용자에게 보여주지 못함. + - 즉 리소스(image, style sheet)에 대한 추가적인 요청을 보내야함.. +- 만약 어떤 리소스에 대한 요청을 회수할 수 없는 상황이라면, 그 자체가 추후 진행되는 모든 리퀘스트를 막는 현상이 발생함. + + + +# HTTP/2.0 + +- 서버, 클라이언트간의 메세지를 주고받을 떄 사용하는 프로토콜임. + +- 그러나 HTTP 1.1을 이용했을 경우, 발생되는 문제(웹 페이지가 로드 될 때 생기는 지연)를 최소화하기 위해 등장 + +- binary framing layer임! + + - HTTP 1.1과 가장 구별되는 차이점 + - 즉 text로 주고받는 1.1에 비해서, 2.0은 binary 값으로 원하고자 하는 데이터를 주고 받을 수 있음 +- 하나의 TCP connection에서, 여러개의 데이터를 주고 받을 수 있게함. + + + +### Advantages of the Binary Framing Layer + +- 여러개의 데이터 스트림 환경을 두 기기간에 만듬. +- **Multiplexing!** +- 각각의 스트림들은 여러개의 메세지를 가질 수 있는데, 이 메세지의 포멧이 http request/response 형태임 + - 이 메세지들은 frames라는 단위로 나뉘어질 수 있음. +- 즉 하나의 커넥션에 여러개의 데이터를 주고 받을 수 있다는 장점이 있음. + +![](https://assets.digitalocean.com/articles/cart_63893/Streams_Frames.png) + + + +### Stream Prioritization + +- 요청 리소스간의 의존 관계를 설정해놓음 + - 왜? + - 여러 request들이 하나의 리소스를 얻기 위해 경쟁함으로써 생기는 성능 이슈를 방지하고, + - 개발자로 하여금 request의 우선순위를 정하게 하여, 좀 더 나의 어플리케이션 성능을 제공하기 위해 + + + +### Server push + +- 클라이언트는, html 자원을 요청했어도, 서버쪽에서 이에 필요한 자원들을 미리 보내주는 것을 의미. + - 클라이언트는 받은 자원을 캐시할 수도, 혹은 거부할 수도 있음. + + + +### Compression + +- binary framing layer를 사용하고 +- HPACK 알고리즘을 이용하여, 헤더를 압축함. + - 이를 통해 상당히 사이즈를 줄일 수 있음. +- 이 과정을 통해 서버-클라이언트 통신 과정에서 발생할 수 있는 지연을 줄일 수 있음. + + + + +# HTTP 1.1 vs 2.0 + +![](https://miro.medium.com/max/1328/1*rf2AnDQyHfGO_ThYfb-hWA.png) + + + +# 참고 + +- https://medium.com/@shlee1353/http1-1-vs-http2-0-%EC%B0%A8%EC%9D%B4%EC%A0%90-%EA%B0%84%EB%8B%A8%ED%9E%88-%EC%82%B4%ED%8E%B4%EB%B3%B4%EA%B8%B0-5727b7499b78 +- https://www.digitalocean.com/community/tutorials/http-1-1-vs-http-2-what-s-the-difference +- https://goldfishhead.tistory.com/26 \ No newline at end of file diff --git a/network/web-cache/han/README.md b/network/web-cache/han/README.md new file mode 100644 index 0000000..eac9cbd --- /dev/null +++ b/network/web-cache/han/README.md @@ -0,0 +1,73 @@ +# web-cache + +- 클라이언트, 서버 사이드에서 사용하는 용도로 나뉘어져 있음. +- 이미지 혹은 다른 파일들을 캐싱하는 것은, web page를 브라우징 하는 데 걸리는 딜레이를 줄여줌 + + + +## 종류 + +1. Browser cache +2. Proxy cache +3. Gateway cache + + + +## HTTP 1.1 cache-control + +- 이 옵션을 통해 다양한 조건을 설정할 수 있음. +- max-age=[sec] +- no-cache, no-store +- private 등등.. + + + +## 동작 방법 + +1. 클라이언트가 서버에 리소스를 요청하고, +2. 서버가 클라이언트의 요청을 검토하여, 있으면 해당 리소스와 헤더값을 응답함. +3. 클라이언트는 응답 받은 자원을 그리고, 응답 헤더에 따라 캐시 정책을 수행 + + + +### 응답 헤더에... + +1. LAST-MODIFIED + +![](https://t1.daumcdn.net/cfile/tistory/2453A54F558225240E) + + + +- 요청 보낼 때, `if-modified-since` 를 보내서, 서버는 이를 기반으로 해당 파일이 변경되었는지 확인하고 +- 변경되지 않았다면 304 Not modified 응답 +- 변경 되었다면 200과 새로운 파일 , Last modified 값을 헤더에 넣어 전송 +- 클라이언트는 304 일 경우, 캐시된 페이지를 로드하고, 200일 경우 새로 다운 받은 리소스를 캐시 한다음에, Last modified 값을 갱신.. + + + +2. ETAG + +- 1번과 비슷한 체크 과정을 거침 + + + +3. Expires + +- Expire 값과 비교하여, 기간 내라면 캐시에서 바로 로드 되도록. +- 기간이 지났다면 서버에게 요청이 가서, validation이 체크됨. + + + +4. Cache-control + +- max-age를 GMT와 비교, 기간 내라면 바로 캐시에서 바로 로드 됨. +- `Expires` 보다 우선 됨. + + + +# 참고 + +- https://en.wikipedia.org/wiki/Web_cache +- https://hahahoho5915.tistory.com/33 +- https://developer.mozilla.org/ko/docs/Web/HTTP/Caching + From 4f57875c9d5800e3c4fb73118b2500ca4bf7c882 Mon Sep 17 00:00:00 2001 From: choijangho Date: Tue, 18 May 2021 00:17:18 +0900 Subject: [PATCH 013/142] =?UTF-8?q?[1=EC=A3=BC=EC=B0=A8]=20:=20=ED=8F=B4?= =?UTF-8?q?=EB=8D=94=20=EA=B5=AC=EC=A1=B0=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- {cookie-vs-session => network/cookie-vs-session}/hoi/README.md | 0 .../ssl-client-authentication-flow}/hoi/README.md | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename {cookie-vs-session => network/cookie-vs-session}/hoi/README.md (100%) rename {ssl-client-authentication-flow => network/ssl-client-authentication-flow}/hoi/README.md (100%) diff --git a/cookie-vs-session/hoi/README.md b/network/cookie-vs-session/hoi/README.md similarity index 100% rename from cookie-vs-session/hoi/README.md rename to network/cookie-vs-session/hoi/README.md diff --git a/ssl-client-authentication-flow/hoi/README.md b/network/ssl-client-authentication-flow/hoi/README.md similarity index 100% rename from ssl-client-authentication-flow/hoi/README.md rename to network/ssl-client-authentication-flow/hoi/README.md From 36fb470a918f68cbf597154a4e91e0957ca23909 Mon Sep 17 00:00:00 2001 From: choijangho Date: Tue, 18 May 2021 00:26:06 +0900 Subject: [PATCH 014/142] =?UTF-8?q?[2=EC=A3=BC=EC=B0=A8]=20HTTP/1.1=20,=20?= =?UTF-8?q?HTTP/2.0=20,=20Web=20Cache=20=EC=A0=95=EB=A6=AC=20(hoi)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- network/http-1.1-vs-http-2.0/hoi/README.md | 133 +++++++++++++++++++++ web-cache/hoi/README.md | 45 +++++++ 2 files changed, 178 insertions(+) create mode 100644 network/http-1.1-vs-http-2.0/hoi/README.md create mode 100644 web-cache/hoi/README.md diff --git a/network/http-1.1-vs-http-2.0/hoi/README.md b/network/http-1.1-vs-http-2.0/hoi/README.md new file mode 100644 index 0000000..6e6b5b0 --- /dev/null +++ b/network/http-1.1-vs-http-2.0/hoi/README.md @@ -0,0 +1,133 @@ +# HTTP/1.1 vs HTTP/2.0 + +### HTTP 1.1 + +**HTTP/1.1**는 **HTTP/1.0**의 표준 버전이 나혼 이후에 몇달이 안되서 여러 사항이 개선되어 나온 현재까지 가장 많이 사용하는 표준 프로토콜 입니다. + +### **HTTP/1.1 Connection** + +**Connection**이 재사용될 수 있게 하여 임베드 된 탐색된 단일 문서들을 디스플레이하기 위해 **Connection**을 다시 열어서 사용했습니다. 추가적으로 HTTP/1.1 **Connection**의 동작은 하나의 **Connection**에 하나의 요청을 처리하도록 설계가 되어있습니다. HTTP/1.1의 단점이라고 불리는 것들은 **`Connection**에 하나의 요청을 처리` 의 특징과 관계가 많습니다. + +### HOL ( Head Of Line ) : 응답 지연 + +Head Of Line은 같은 큐의 첫번째 이 후 후순에 있는 작업 큐들이 첫 번째 패킷에 의해서 지연될 때 발생하는 성능 저하를 의미합니다. 단순하게는 처리 속도가 지연되고 최악의 경우 패킷 드랍의 경우까지 갈 수 있습니다. + +스위치는 패킷을 받는 3가지 순서로 구성되어 있습니다. + +`input` → `switching fabric` → `output` + +[switching fabric에 대한 글](https://www.netmanias.com/ko/post/qna/3127) + +아래의 사진은 첫 번째와 세 번째 입력이 같은 output(4)을 바라볼 때 switching fabric이 3번을 먼저 처리해버린다면 1번 입력 패킷은 첫번째 입력을 인터페이스로 보내지 못하게 됩니다. 순차적으로 처리하는 특성과 output의 제한으로 발생하는 현상을 `HOL Blocking` 라고 합니다. + +스크린샷 2021-05-17 오후 11 20 52 + +### RTL ( Route Trip Time ) : 불필요한 과정의 증가 + +HTTP/1.1 특징 중 하나에 `Connection` 은 하나의 일만 처리한다는 특징이 있습니다. 이럴 때 매번 요청마다 TCP의 `3-way Handshake`가 반복됩니다. `3-way Handshake` 같이 인증의 과정을 거치는 건 결국에 일련의 처리 과정을 거치는데 리소스를 투자하는 것으로 이해할 수 있으며 이는 네트워크 지연에 영향을 줍니다. + +### 무거운 Header 구조 + +**추가적으로 알아보면 좋은 토픽** + +- HTTP 파이프라이닝 + +### HTTP 2.0 + +스크린샷 2021-05-17 오후 11 37 22 + +위의 사진은 HTTP/1.1의 동시 전송 문제가 HTTP/2.0에서는 어떻게 처리되는지 나타냅니다. 순서를 지켜가며 통신이 이뤄지는 1.1과는 달리 2.0에서는 순서에 상관없이 응답을 받고 있습니다. + +### Multiplexed Streams + +`Multiplexed Streams` 의 특징은 한 커넥션으로 동시에 여러개의 메시지를 통신 할 수 있으며 수신에 있어서 순서가 상관 없다 라는 특징이 있습니다. + +### Stream Prioritization + +스트림의 우선 순위를 지정하여 웹이 받는 리소스를 보다 효과적으로 제어할 수 있습니다. HTML의 문서를 읽을 때 이미지 파일보다 CSS 파일 수신에 우선 순위를 두는 방식으로 렌더링을 보다 효과적으로 할 수 있습니다. + +- HTML 파일을 수신하고 웹 브라우저가 이를 읽는다. +- 우선 순위가 더 높은 CSS파일의 수신이 먼저 이뤄지고 웹 브라우저는 HTML DOM과 CSSOM 구조를 만들어 렌더링을 진행한다. +- 화면에 필요한 이미지 리소스를 요청하고 해당 위치에 렌더링을 진행한다. + +### Header Compression + +위에서 HTTP/1.1에서는 무거운 헤더 구조가 단점 중 하나로 말했는데 HTTP/2.0에서는 아래와 같은 방식으로 Header를 압축합니다. 이를 HPACK 압축방식이라 부릅니다. + +### Server Push + +클라이언트가 HTTP 문서를 수신한 후 HTTP/1.1은 리소스 요청이 필요한 라인에서 해당 리소스를 다시 서버에 요청하게 됩니다. 예를 들어서 아래의 과정과 같습니다. + +- HTML 구문 분석 중 +- CSS 파일을 만났다. +- CSS 파일 요청 +- HTML 구문 분석 중 +- 이미지 파일을 만났다. +- 이미지 파일 요청 + +하지만 HTTP/2.0 에서는 클라이언트가 요청할 리소스를 예측하여 해당 정보를 같이 보내는 방법으로 클라이언트의 추가적인 요청을 최소화 해줍니다. 이를 PUSH_PROMISE라고 부릅니다. + +### HTTP 1.1 + +**HTTP/1.1**는 **HTTP/1.0**의 표준 버전이 나혼 이후에 몇달이 안되서 여러 사항이 개선되어 나온 현재까지 가장 많이 사용하는 표준 프로토콜 입니다. + +### **HTTP/1.1 Connection** + +**Connection**이 재사용될 수 있게 하여 임베드 된 탐색된 단일 문서들을 디스플레이하기 위해 **Connection**을 다시 열어서 사용했습니다. 추가적으로 HTTP/1.1 **Connection**의 동작은 하나의 **Connection**에 하나의 요청을 처리하도록 설계가 되어있습니다. HTTP/1.1의 단점이라고 불리는 것들은 **`Connection**에 하나의 요청을 처리` 의 특징과 관계가 많습니다. + +### HOL ( Head Of Line ) : 응답 지연 + +Head Of Line은 같은 큐의 첫번째 이 후 후순에 있는 작업 큐들이 첫 번째 패킷에 의해서 지연될 때 발생하는 성능 저하를 의미합니다. 단순하게는 처리 속도가 지연되고 최악의 경우 패킷 드랍의 경우까지 갈 수 있습니다. + +스위치는 패킷을 받는 3가지 순서로 구성되어 있습니다. + +`input` → `switching fabric` → `output` + +[switching fabric에 대한 글](https://www.netmanias.com/ko/post/qna/3127) + +아래의 사진은 첫 번째와 세 번째 입력이 같은 output(4)을 바라볼 때 switching fabric이 3번을 먼저 처리해버린다면 1번 입력 패킷은 첫번째 입력을 인터페이스로 보내지 못하게 됩니다. 순차적으로 처리하는 특성과 output의 제한으로 발생하는 현상을 `HOL Blocking` 라고 합니다. + +스크린샷 2021-05-17 오후 11 55 55 + +### RTL ( Route Trip Time ) : 불필요한 과정의 증가 + +HTTP/1.1 특징 중 하나에 `Connection` 은 하나의 일만 처리한다는 특징이 있습니다. 이럴 때 매번 요청마다 TCP의 `3-way Handshake`가 반복됩니다. `3-way Handshake` 같이 인증의 과정을 거치는 건 결국에 일련의 처리 과정을 거치는데 리소스를 투자하는 것으로 이해할 수 있으며 이는 네트워크 지연에 영향을 줍니다. + +### 무거운 Header 구조 + +**추가적으로 알아보면 좋은 토픽** + +- HTTP 파이프라이닝 + +### HTTP 2.0 + +위의 사진은 HTTP/1.1의 동시 전송 문제가 HTTP/2.0에서는 어떻게 처리되는지 나타냅니다. 순서를 지켜가며 통신이 이뤄지는 1.1과는 달리 2.0에서는 순서에 상관없이 응답을 받고 있습니다. + +### Multiplexed Streams + +`Multiplexed Streams` 의 특징은 한 커넥션으로 동시에 여러개의 메시지를 통신 할 수 있으며 수신에 있어서 순서가 상관 없다 라는 특징이 있습니다. + +### Stream Prioritization + +스트림의 우선 순위를 지정하여 웹이 받는 리소스를 보다 효과적으로 제어할 수 있습니다. HTML의 문서를 읽을 때 이미지 파일보다 CSS 파일 수신에 우선 순위를 두는 방식으로 렌더링을 보다 효과적으로 할 수 있습니다. + +- HTML 파일을 수신하고 웹 브라우저가 이를 읽는다. +- 우선 순위가 더 높은 CSS파일의 수신이 먼저 이뤄지고 웹 브라우저는 HTML DOM과 CSSOM 구조를 만들어 렌더링을 진행한다. +- 화면에 필요한 이미지 리소스를 요청하고 해당 위치에 렌더링을 진행한다. + +### Header Compression + +위에서 HTTP/1.1에서는 무거운 헤더 구조가 단점 중 하나로 말했는데 HTTP/2.0에서는 아래와 같은 방식으로 Header를 압축합니다. 이를 HPACK 압축방식이라 부릅니다. + +### Server Push + +클라이언트가 HTTP 문서를 수신한 후 HTTP/1.1은 리소스 요청이 필요한 라인에서 해당 리소스를 다시 서버에 요청하게 됩니다. 예를 들어서 아래의 과정과 같습니다. + +- HTML 구문 분석 중 +- CSS 파일을 만났다. +- CSS 파일 요청 +- HTML 구문 분석 중 +- 이미지 파일을 만났다. +- 이미지 파일 요청 + +하지만 HTTP/2.0 에서는 클라이언트가 요청할 리소스를 예측하여 해당 정보를 같이 보내는 방법으로 클라이언트의 추가적인 요청을 최소화 해줍니다. 이를 PUSH_PROMISE라고 부릅니다. diff --git a/web-cache/hoi/README.md b/web-cache/hoi/README.md new file mode 100644 index 0000000..16ad229 --- /dev/null +++ b/web-cache/hoi/README.md @@ -0,0 +1,45 @@ +# Web Cache + +캐시는 프록시 서버와 클라이언트의 로컬 디스크에 보관된 리소스의 사본을 가리킵니다. 캐시 서버를 사용하면 예들들어 일정 시간동안은 실제 서버에 방문해서 리소스를 가져오는 것이 아니라 캐시 서버에서 리소스 사본을 응답하는 방식으로 실서버의 통신량과 통신 시간을 절약할 수 있는 이점이 있습니다. + +**(이용자 기준에서 실제 서버보다 캐시 서버의 거리가 더 가깝기 때문에 더욱 빠른 응답을 할 수 있습니다.)** + +**[프록시 서버는 무엇일까 ? 🧐](https://namu.wiki/w/%ED%94%84%EB%A1%9D%EC%8B%9C%20%EC%84%9C%EB%B2%84)** + +`클라이언트` < - > `캐시 서버` < - > `실서버` + +캐시 서버는 프록시의 기본 동작을 따르지만 큰 구분점은 실제 서버에서 받은 리소스를 자신의 디스크 또는 메모리에 저장한 후 클라이언트에게 제공한다는 차이점이 있습니다. + +**캐시의 유효기간** + +캐시 서버에 캐시된 리소스가 있는 경우라도 계속해서 캐시된 리소스를 제공하는건 아닙니다. 서버는 여러 리소스를 가지고 있으며 캐시 서버는 실제 서버의 사본에 불과합니다. 만약에 css 또는 png 같은 이미지 리소스 형식에 변경이 있다면 실제로 사용자는 화면이 깨진 형태 또는 이미지 리소스를 받을수도 있습니다. 따라서 캐시 서버는 캐싱된 리소스의 유효성을 주기적으로 확인하고 업데이트 여부를 확인하여 업데이트가 있다면 새로운 리소스를 받는 과정이 필요합니다. + +이 부분을 설명하기 위해서는 캐시 서버의 리소스 유효성에 대해서 설명이 필요합니다. + +**최초 컨텐츠 요청** + +`클라이언트` < - > `캐시 서버` < - > `실서버` + +- 클라이언트가 웹 브라우저에 이미지 리소스를 요청한다. +- 캐시 서버에 도달했을 때 캐시 서버는 캐시된 리소스가 없는걸 확인하고 실서버에 리소스를 요청한다. +- 실서버는 리소스와 함께 캐싱 유효성 , 기간을 판단하는 메타 태그 정보를 함께 전달한다. + +**last-modified :** **가장 마지막으로 업데이트 된 시기** + + **cache-control : 캐시 리소스의 유효 기간 해당 시간이 지났다면 캐시 서버는 실서버에 재요청하여 리소스를 업데이트** + + + + **cache-control 설명** + + **public : HTTP 응답 내에서 서버에 의해 사용될 수 있는 표준 Cache-Control 디렉티브를 의미합니다. public은 콘텐츠가 브라우저 및 중간 캐시에 의해 캐시 될 수 있음을 나타냅니다. HTTP 인증을 사용하는 요청에 대한 기본 개인 설정을 재정의합니다. 비공개와 상호 배타적입니다.** + + **immutable : 웹 브라우저는 max-age가 만료되지 않더라도 새로고침 시 캐시의 유효성을 검증하기 위한 캐시 검증을 요청합니다. immutable 속성은 max-age는 파일이 변동되지 않을것이라고 예측하고 검증의 과정을 거치지 않습니다. 이런 옵션은 좀 더 정확한 인증 과정 보다는 캐시 서버의 최적화에 도움이 되는 옵션입니다.** + + **max-age : 캐시 서버에 리소스를 사용하는 만료 시간입니다. 위와 같이 3153600의 값은 max-age를 설정할 수 있는 최대치인 1년을 표현하고 있습니다.** + +- 클라이언트는 위와 같은 정보들을 캐시 서버로 부터 수신 후 사용자에게 제공한다. + +**리소스를 다시 요청하는 순간에 cache-control의 max-age는 변동한다.** + +말그대로 만료 시간이 120ms로 지정된 cache-control 에 30초 이후에 다시 요청한다면 해당 메타 태그의 값은 120 - 30 = 90의 값으로 응답이 돌아오게 됩니다. From d5b02ad057ff1b0b0c79d11c8511b5d749178751 Mon Sep 17 00:00:00 2001 From: Han Date: Tue, 25 May 2021 21:18:21 +0900 Subject: [PATCH 015/142] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 9de1b3e..b465a56 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # lets-cs ## 스터디 규칙 -- 일정 : 04.27 ~ 05.27 +- 일정 : 05.25 ~ 06.25 - 주제 : 네트워크 - 진행 방식 - 2주가 하나의 사이클 @@ -30,7 +30,7 @@ - [ ] PR 질문에 대한 답변 작성 - [ ] 답변에 따른 PR 수정 - 기타 - - [ ] 2주에 1개 이상, 공부하고 싶은 주제에 대해 Pinned 된 이슈에 댓글을 작성 + - [ ] 매주 회고 스터디 미팅 참가 - PR - 1주차 - PR을 보낼 땐, 2개의 이슈에 대한 README.md 파일이 있어야함 From 626513f6b18fe945c2a69bb6b4294d84822dc78a Mon Sep 17 00:00:00 2001 From: choijangho Date: Tue, 1 Jun 2021 17:49:58 +0900 Subject: [PATCH 016/142] =?UTF-8?q?[3=ED=9A=8C=EC=B0=A8]=20TCP/IP=20,=20L4?= =?UTF-8?q?=20vs=20L7=20=EB=A1=9C=EB=93=9C=EB=B0=B8=EB=9F=B0=EC=84=9C=20?= =?UTF-8?q?=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- network/L4-vs-L7-load-balancer/hoi/README.md | 46 ++++++++++++++ network/TCP-IP-4-layer/hoi/README.md | 65 ++++++++++++++++++++ 2 files changed, 111 insertions(+) create mode 100644 network/L4-vs-L7-load-balancer/hoi/README.md create mode 100644 network/TCP-IP-4-layer/hoi/README.md diff --git a/network/L4-vs-L7-load-balancer/hoi/README.md b/network/L4-vs-L7-load-balancer/hoi/README.md new file mode 100644 index 0000000..fa1df26 --- /dev/null +++ b/network/L4-vs-L7-load-balancer/hoi/README.md @@ -0,0 +1,46 @@ +# L4 로드밸런서 vs L7 로드밸런서 + +### 로드밸런싱 (부하 분산) + +로드밸런싱은 다수의 클라이언트 , 즉 높은 트래픽이 생기는 상황을 대비하는 네트워크 기술의 일종입니다. +중앙처리장치 또는 저장장치와 같은 컴퓨터 리소스를 추가적으로 운용하며 부하의 상황에 작업을 나눔으로써 높은 트래픽이 생기는 상황에도 서버는 안정성을 유지할 수 있습니다. + +### 로드밸런서의 문제 해결 방식 + +- Scale-up : Server의 하드웨어 성능을 높히는 방법 +- Scale-out : 여러 대의 Server에 작업을 분산시키는 방법 + +### L4 로드밸런서 + +L4 로드밸런서는 Network Layer(TCP/UDP)에서 정의된 정보를 활영하여 클라이언트의 요청을 분산시키는 작업을 진행합니다.정의된 정보는 IP주소,포트,MAC 주소,전송 프로토콜을 활용하여 분산을 결정합니다. + +- Round-Robin : 세션을 각 서버에 순차적으로 맺어주는 방식 , 순서를 기반으로 하는 작업이라서 균등한 분산이 보장되지 않을때가 있음 +- 가충치 및 비율 할당 방식 : 서버마다 수신 비율을 정하고 그 비율에 맞춰서 분산하는 방식 , 분산된 서버의 성능이 다르다면 가장 좋은 성능을 가진 서버에 할당치를 높히고 낮은 서버는 상대적으로 적은 할당치를 가지게 설계가 가능 +- 최소 연결(Least Connection) : 가장 적은 세션을 찾아 해방 서버로 트래픽을 할당하는 방식 +- 응답 시간(Response Time) : 가장 빠른 응답 시간을 가지는 서버에 트래픽을 할당하는 방식 +- 해시 : 특정 IP 또는 포트를 가지는 사용자는 특정 서버에 할당되도록 하는 방식 +- 대역폭 : 서버들과 대역폭을 고려하여 트래픽을 분산 + +### L7 로드밸런서 + +L7 로드밸런서는 OSI 모델에서 가장 높은 애플리케이션 계층에서 작동합니다. 포트와 IP를 활용하는 L4의 활용과 함께 컨텐츠 위주의 정보도 분석하여 분산 라우팅에 대한 결정을 내릴 수 있습니다. 아래는 L7 로드밸런서가 분산에 활용하는 정보입니다. + +- URL 스위칭 (URL Switching) : 특정 URL의 하위 URL을 특정 서버에 할당하는 방식 + `specific/post` `specific/video` 와 같이 특정 URL을 가진다면 서버가 아닌 별도의 스토리지로 연결 +- 컨텍스트 스위칭(Context Switching) : 클라이언트가 요청한 특정 리소스는 특정 서버로 연결되는 방식 , 즉 어떤 리소스를 요청하는지를 판별하여 해당 서버로 갈 수 있도록 설계 가능 +- 쿠키 지속성(Persistence with Cookies) : 클라이언트가 가지고 있는 쿠키정보를 바탕으로 클라이언트가 접속했던 서버에 다시 연결하는 방식 + +### L4 / L7 의 성능 지표 + +L4 / L7 중 어떤 로드밸런서가 더 좋은 성능을 가지는지는 아래와 같은 지표를 기준으로 판별하게 됩니다. + +- 초당 연결수 : TCP 세션 시간당 처리의 수 +- 동시 연결수 : 동시에 최대로 세션 연결을 유지할 수 있는 수 +- 처리 용량 : UDP 프로토콜에 대한 로드밸런싱 성능 지표 (FWLB에서 중요) + FWLB : 기존에 한대의 방화벽을 사용할 때 하나의 방화벽에 부하가 집중되면서 품질 저하 & FW 장애와 같은 문제가 발생했고 이런 문제점 때문에 두대의 방화벽을 운용하는 방식이다. + + ![https://s3-us-west-2.amazonaws.com/secure.notion-static.com/c2fafe75-7689-4a36-97b7-345c407d1939/_2021-06-01__5.44.50.png](https://s3-us-west-2.amazonaws.com/secure.notion-static.com/c2fafe75-7689-4a36-97b7-345c407d1939/_2021-06-01__5.44.50.png) + +참고 자료 + +[https://www.stevenjlee.net/2020/06/30/이해하기-네트워크의-부하분산-로드밸런싱-load-balancing-그/](https://www.stevenjlee.net/2020/06/30/%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0-%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC%EC%9D%98-%EB%B6%80%ED%95%98%EB%B6%84%EC%82%B0-%EB%A1%9C%EB%93%9C%EB%B0%B8%EB%9F%B0%EC%8B%B1-load-balancing-%EA%B7%B8/) diff --git a/network/TCP-IP-4-layer/hoi/README.md b/network/TCP-IP-4-layer/hoi/README.md new file mode 100644 index 0000000..7ef241b --- /dev/null +++ b/network/TCP-IP-4-layer/hoi/README.md @@ -0,0 +1,65 @@ +# TCP/IP Protocol Stack 4 Layer + +TCP/IP의 4계층은 아래와 같이 구성되어 있다. + +- **Application Layer (응용 계층)** +- **Transport Layer (전송 계층)** +- **Internet Layer (인터넷 계층)** +- **Network Interface Layer (네트워크 인터페이스 계층)** + +### [1계층] Network Interface Layer (네트워크 인터페이스 계층) + +OSI 모델과 비교했을 때 (물리,데이터 링크) 계층에 해당합니다. + +### [2계층] **Internet Layer (인터넷 계층)** + +인터넷 계층의 가장 큰 역할은 오류 및 진단을 파악합니다. **IP(인터네트워킹 프로토콜)**는 패킷 교환 네트워크를 위해 설계되었지만 신뢰성이 없고 비연결형인 데이터그램 프로토콜이라는 특징을 가지고 있습니다. 따라서 IP는 전달을 위한 최선의 노력(best effort)만을 할 뿐 신뢰성을 위한 행위를 기반하진 않는다고 할 수 있습니다. + +**IP(인터네트워킹 프로토콜)**의 이런 특징 때문에 패킷 단위로 나눈 데이터가 유실될 가능성이 있으며 서로 다른 경로로 이동한 패킷의 순서가 보장되지 않는 경우도 있습니다. 이런 부분 때문에 IP는 상위 계층에 의존성을 가집니다. + +- IP : 비신뢰성 , 비연결지향 +- ARP : IP주소를 물리적인 주소로 변환 +- RARP : 물리 주소를 인터넷 주소로 변환 +- ICMP : 호스트에게 데이터그램의 문제점 발송 , 조회와 오류보고 메시지를 송신 +- IGMP : 수신자 그룹에게 메시지를 동시 전송 + +### [3계층] **Transport Layer (전송 계층)** + +전송 계층은 2개의 프로토콜(TCP , UDP)를 가지고 있습니다. + +```jsx +IP는 호스트 간 프로토콜로써 패킷을 물리적인 장치에서 다른 물리적 장치로 전달할 때 사용합니다. +``` + +**UDP** + +UDP는 TCP/IP와 대비해서 **단순한 프로세스**를 가지고 있습니다. 이런 특징 덕분에 속도적인 측면에서 이점을 가져갈 수 있으며 방대한 양의 데이터(비디오 , 큰 사이즈의 이미지 ....)를 송수신할 때 사용합니다. + +아래와 같은 정보만을 가지고 통신을 진행합니다. + +- 포트 주소 +- 검사합 +- 오류제어 +- 상위 계층으로부터 받은 데이터의 길이 + +**TCP** + +TCP는 신뢰성 있는 스트림 전송 프로토콜이라고 불립니다. UDP에 비해서 서버와 클라이언트 양 종단 간에 연결이 가능한 상태인지를 파악합니다. 이런 과정 덕분에 UDP보다 신뢰성이 있다고 판단되지만 여러 검증 과정을 거쳐야 하기 때문에 속도적인 측면에서는 UDP보다 떨어집니다. + +```jsx +**스트림은 연결 지향을 의미** + +TCP는 연결 지향을 위해서 3 way handshake를 사용합니다. +``` + +### **Application Layer (응용 계층)** + +OSI 모델과 비교했을 때 TCP/IP의 응용 계층은 OSI 모델의 3계층(세션,표현,응용)을 합친 역할을 합니다. 애플리케이션은 주로 아래와 같은 일들을 수행합니다. + +- 웹 브라우저(Port : 20 , 21) : 파일 송수신 +- 전자메일(Port : 25 , 110) : 메일 송수신 +- 원격 로그인(Port : 23): 원격 터미널 접속 +- 네트워크 관리 + +각 애플리케이션은 독자적인 통신 처리 과정이 필요하며 그 과정을 정의하는게 Application Protocol 입니다. +동작을 위해서 포트 번호를 활용하며 설계자 또는 개발자가 특정 네트워크 통신을 사용하기 위해서는 일반적인 애플리케이션 프로토콜 , 또는 필요에 따라서 독자적인 애플리케이션을 정의할 수 있습니다. From 7e1a81ef0e8ce7259f212fd4e74e129cf3b91c77 Mon Sep 17 00:00:00 2001 From: choijangho Date: Tue, 1 Jun 2021 17:56:25 +0900 Subject: [PATCH 017/142] =?UTF-8?q?Delete=20:=203=EC=A3=BC=EC=B0=A8=20?= =?UTF-8?q?=EC=A0=95=EB=A6=AC=20hoi?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- network/L4-vs-L7-load-balancer/hoi/README.md | 46 -------------- network/TCP-IP-4-layer/hoi/README.md | 65 -------------------- 2 files changed, 111 deletions(-) delete mode 100644 network/L4-vs-L7-load-balancer/hoi/README.md delete mode 100644 network/TCP-IP-4-layer/hoi/README.md diff --git a/network/L4-vs-L7-load-balancer/hoi/README.md b/network/L4-vs-L7-load-balancer/hoi/README.md deleted file mode 100644 index fa1df26..0000000 --- a/network/L4-vs-L7-load-balancer/hoi/README.md +++ /dev/null @@ -1,46 +0,0 @@ -# L4 로드밸런서 vs L7 로드밸런서 - -### 로드밸런싱 (부하 분산) - -로드밸런싱은 다수의 클라이언트 , 즉 높은 트래픽이 생기는 상황을 대비하는 네트워크 기술의 일종입니다. -중앙처리장치 또는 저장장치와 같은 컴퓨터 리소스를 추가적으로 운용하며 부하의 상황에 작업을 나눔으로써 높은 트래픽이 생기는 상황에도 서버는 안정성을 유지할 수 있습니다. - -### 로드밸런서의 문제 해결 방식 - -- Scale-up : Server의 하드웨어 성능을 높히는 방법 -- Scale-out : 여러 대의 Server에 작업을 분산시키는 방법 - -### L4 로드밸런서 - -L4 로드밸런서는 Network Layer(TCP/UDP)에서 정의된 정보를 활영하여 클라이언트의 요청을 분산시키는 작업을 진행합니다.정의된 정보는 IP주소,포트,MAC 주소,전송 프로토콜을 활용하여 분산을 결정합니다. - -- Round-Robin : 세션을 각 서버에 순차적으로 맺어주는 방식 , 순서를 기반으로 하는 작업이라서 균등한 분산이 보장되지 않을때가 있음 -- 가충치 및 비율 할당 방식 : 서버마다 수신 비율을 정하고 그 비율에 맞춰서 분산하는 방식 , 분산된 서버의 성능이 다르다면 가장 좋은 성능을 가진 서버에 할당치를 높히고 낮은 서버는 상대적으로 적은 할당치를 가지게 설계가 가능 -- 최소 연결(Least Connection) : 가장 적은 세션을 찾아 해방 서버로 트래픽을 할당하는 방식 -- 응답 시간(Response Time) : 가장 빠른 응답 시간을 가지는 서버에 트래픽을 할당하는 방식 -- 해시 : 특정 IP 또는 포트를 가지는 사용자는 특정 서버에 할당되도록 하는 방식 -- 대역폭 : 서버들과 대역폭을 고려하여 트래픽을 분산 - -### L7 로드밸런서 - -L7 로드밸런서는 OSI 모델에서 가장 높은 애플리케이션 계층에서 작동합니다. 포트와 IP를 활용하는 L4의 활용과 함께 컨텐츠 위주의 정보도 분석하여 분산 라우팅에 대한 결정을 내릴 수 있습니다. 아래는 L7 로드밸런서가 분산에 활용하는 정보입니다. - -- URL 스위칭 (URL Switching) : 특정 URL의 하위 URL을 특정 서버에 할당하는 방식 - `specific/post` `specific/video` 와 같이 특정 URL을 가진다면 서버가 아닌 별도의 스토리지로 연결 -- 컨텍스트 스위칭(Context Switching) : 클라이언트가 요청한 특정 리소스는 특정 서버로 연결되는 방식 , 즉 어떤 리소스를 요청하는지를 판별하여 해당 서버로 갈 수 있도록 설계 가능 -- 쿠키 지속성(Persistence with Cookies) : 클라이언트가 가지고 있는 쿠키정보를 바탕으로 클라이언트가 접속했던 서버에 다시 연결하는 방식 - -### L4 / L7 의 성능 지표 - -L4 / L7 중 어떤 로드밸런서가 더 좋은 성능을 가지는지는 아래와 같은 지표를 기준으로 판별하게 됩니다. - -- 초당 연결수 : TCP 세션 시간당 처리의 수 -- 동시 연결수 : 동시에 최대로 세션 연결을 유지할 수 있는 수 -- 처리 용량 : UDP 프로토콜에 대한 로드밸런싱 성능 지표 (FWLB에서 중요) - FWLB : 기존에 한대의 방화벽을 사용할 때 하나의 방화벽에 부하가 집중되면서 품질 저하 & FW 장애와 같은 문제가 발생했고 이런 문제점 때문에 두대의 방화벽을 운용하는 방식이다. - - ![https://s3-us-west-2.amazonaws.com/secure.notion-static.com/c2fafe75-7689-4a36-97b7-345c407d1939/_2021-06-01__5.44.50.png](https://s3-us-west-2.amazonaws.com/secure.notion-static.com/c2fafe75-7689-4a36-97b7-345c407d1939/_2021-06-01__5.44.50.png) - -참고 자료 - -[https://www.stevenjlee.net/2020/06/30/이해하기-네트워크의-부하분산-로드밸런싱-load-balancing-그/](https://www.stevenjlee.net/2020/06/30/%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0-%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC%EC%9D%98-%EB%B6%80%ED%95%98%EB%B6%84%EC%82%B0-%EB%A1%9C%EB%93%9C%EB%B0%B8%EB%9F%B0%EC%8B%B1-load-balancing-%EA%B7%B8/) diff --git a/network/TCP-IP-4-layer/hoi/README.md b/network/TCP-IP-4-layer/hoi/README.md deleted file mode 100644 index 7ef241b..0000000 --- a/network/TCP-IP-4-layer/hoi/README.md +++ /dev/null @@ -1,65 +0,0 @@ -# TCP/IP Protocol Stack 4 Layer - -TCP/IP의 4계층은 아래와 같이 구성되어 있다. - -- **Application Layer (응용 계층)** -- **Transport Layer (전송 계층)** -- **Internet Layer (인터넷 계층)** -- **Network Interface Layer (네트워크 인터페이스 계층)** - -### [1계층] Network Interface Layer (네트워크 인터페이스 계층) - -OSI 모델과 비교했을 때 (물리,데이터 링크) 계층에 해당합니다. - -### [2계층] **Internet Layer (인터넷 계층)** - -인터넷 계층의 가장 큰 역할은 오류 및 진단을 파악합니다. **IP(인터네트워킹 프로토콜)**는 패킷 교환 네트워크를 위해 설계되었지만 신뢰성이 없고 비연결형인 데이터그램 프로토콜이라는 특징을 가지고 있습니다. 따라서 IP는 전달을 위한 최선의 노력(best effort)만을 할 뿐 신뢰성을 위한 행위를 기반하진 않는다고 할 수 있습니다. - -**IP(인터네트워킹 프로토콜)**의 이런 특징 때문에 패킷 단위로 나눈 데이터가 유실될 가능성이 있으며 서로 다른 경로로 이동한 패킷의 순서가 보장되지 않는 경우도 있습니다. 이런 부분 때문에 IP는 상위 계층에 의존성을 가집니다. - -- IP : 비신뢰성 , 비연결지향 -- ARP : IP주소를 물리적인 주소로 변환 -- RARP : 물리 주소를 인터넷 주소로 변환 -- ICMP : 호스트에게 데이터그램의 문제점 발송 , 조회와 오류보고 메시지를 송신 -- IGMP : 수신자 그룹에게 메시지를 동시 전송 - -### [3계층] **Transport Layer (전송 계층)** - -전송 계층은 2개의 프로토콜(TCP , UDP)를 가지고 있습니다. - -```jsx -IP는 호스트 간 프로토콜로써 패킷을 물리적인 장치에서 다른 물리적 장치로 전달할 때 사용합니다. -``` - -**UDP** - -UDP는 TCP/IP와 대비해서 **단순한 프로세스**를 가지고 있습니다. 이런 특징 덕분에 속도적인 측면에서 이점을 가져갈 수 있으며 방대한 양의 데이터(비디오 , 큰 사이즈의 이미지 ....)를 송수신할 때 사용합니다. - -아래와 같은 정보만을 가지고 통신을 진행합니다. - -- 포트 주소 -- 검사합 -- 오류제어 -- 상위 계층으로부터 받은 데이터의 길이 - -**TCP** - -TCP는 신뢰성 있는 스트림 전송 프로토콜이라고 불립니다. UDP에 비해서 서버와 클라이언트 양 종단 간에 연결이 가능한 상태인지를 파악합니다. 이런 과정 덕분에 UDP보다 신뢰성이 있다고 판단되지만 여러 검증 과정을 거쳐야 하기 때문에 속도적인 측면에서는 UDP보다 떨어집니다. - -```jsx -**스트림은 연결 지향을 의미** - -TCP는 연결 지향을 위해서 3 way handshake를 사용합니다. -``` - -### **Application Layer (응용 계층)** - -OSI 모델과 비교했을 때 TCP/IP의 응용 계층은 OSI 모델의 3계층(세션,표현,응용)을 합친 역할을 합니다. 애플리케이션은 주로 아래와 같은 일들을 수행합니다. - -- 웹 브라우저(Port : 20 , 21) : 파일 송수신 -- 전자메일(Port : 25 , 110) : 메일 송수신 -- 원격 로그인(Port : 23): 원격 터미널 접속 -- 네트워크 관리 - -각 애플리케이션은 독자적인 통신 처리 과정이 필요하며 그 과정을 정의하는게 Application Protocol 입니다. -동작을 위해서 포트 번호를 활용하며 설계자 또는 개발자가 특정 네트워크 통신을 사용하기 위해서는 일반적인 애플리케이션 프로토콜 , 또는 필요에 따라서 독자적인 애플리케이션을 정의할 수 있습니다. From b2652f666b495238efb9a4ff68f9cc90fb944ef3 Mon Sep 17 00:00:00 2001 From: choijangho Date: Tue, 1 Jun 2021 17:57:57 +0900 Subject: [PATCH 018/142] =?UTF-8?q?[3=EC=A3=BC=EC=B0=A8]=20:=20=EC=A3=BC?= =?UTF-8?q?=EC=A0=9C=20=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- network/L4-vs-L7-load-balancer/hoi/README.md | 46 ++++++++++++++ network/TCP-IP-4-layer/hoi/README.md | 65 ++++++++++++++++++++ 2 files changed, 111 insertions(+) create mode 100644 network/L4-vs-L7-load-balancer/hoi/README.md create mode 100644 network/TCP-IP-4-layer/hoi/README.md diff --git a/network/L4-vs-L7-load-balancer/hoi/README.md b/network/L4-vs-L7-load-balancer/hoi/README.md new file mode 100644 index 0000000..94e906b --- /dev/null +++ b/network/L4-vs-L7-load-balancer/hoi/README.md @@ -0,0 +1,46 @@ +# L4 로드밸런서 vs L7 로드밸런서 정리 + +### 로드밸런싱 (부하 분산) + +로드밸런싱은 다수의 클라이언트 , 즉 높은 트래픽이 생기는 상황을 대비하는 네트워크 기술의 일종입니다. +중앙처리장치 또는 저장장치와 같은 컴퓨터 리소스를 추가적으로 운용하며 부하의 상황에 작업을 나눔으로써 높은 트래픽이 생기는 상황에도 서버는 안정성을 유지할 수 있습니다. + +### 로드밸런서의 문제 해결 방식 + +- Scale-up : Server의 하드웨어 성능을 높히는 방법 +- Scale-out : 여러 대의 Server에 작업을 분산시키는 방법 + +### L4 로드밸런서 + +L4 로드밸런서는 Network Layer(TCP/UDP)에서 정의된 정보를 활영하여 클라이언트의 요청을 분산시키는 작업을 진행합니다.정의된 정보는 IP주소,포트,MAC 주소,전송 프로토콜을 활용하여 분산을 결정합니다. + +- Round-Robin : 세션을 각 서버에 순차적으로 맺어주는 방식 , 순서를 기반으로 하는 작업이라서 균등한 분산이 보장되지 않을때가 있음 +- 가충치 및 비율 할당 방식 : 서버마다 수신 비율을 정하고 그 비율에 맞춰서 분산하는 방식 , 분산된 서버의 성능이 다르다면 가장 좋은 성능을 가진 서버에 할당치를 높히고 낮은 서버는 상대적으로 적은 할당치를 가지게 설계가 가능 +- 최소 연결(Least Connection) : 가장 적은 세션을 찾아 해방 서버로 트래픽을 할당하는 방식 +- 응답 시간(Response Time) : 가장 빠른 응답 시간을 가지는 서버에 트래픽을 할당하는 방식 +- 해시 : 특정 IP 또는 포트를 가지는 사용자는 특정 서버에 할당되도록 하는 방식 +- 대역폭 : 서버들과 대역폭을 고려하여 트래픽을 분산 + +### L7 로드밸런서 + +L7 로드밸런서는 OSI 모델에서 가장 높은 애플리케이션 계층에서 작동합니다. 포트와 IP를 활용하는 L4의 활용과 함께 컨텐츠 위주의 정보도 분석하여 분산 라우팅에 대한 결정을 내릴 수 있습니다. 아래는 L7 로드밸런서가 분산에 활용하는 정보입니다. + +- URL 스위칭 (URL Switching) : 특정 URL의 하위 URL을 특정 서버에 할당하는 방식 + `specific/post` `specific/video` 와 같이 특정 URL을 가진다면 서버가 아닌 별도의 스토리지로 연결 +- 컨텍스트 스위칭(Context Switching) : 클라이언트가 요청한 특정 리소스는 특정 서버로 연결되는 방식 , 즉 어떤 리소스를 요청하는지를 판별하여 해당 서버로 갈 수 있도록 설계 가능 +- 쿠키 지속성(Persistence with Cookies) : 클라이언트가 가지고 있는 쿠키정보를 바탕으로 클라이언트가 접속했던 서버에 다시 연결하는 방식 + +### L4 / L7 의 성능 지표 + +L4 / L7 중 어떤 로드밸런서가 더 좋은 성능을 가지는지는 아래와 같은 지표를 기준으로 판별하게 됩니다. + +- 초당 연결수 : TCP 세션 시간당 처리의 수 +- 동시 연결수 : 동시에 최대로 세션 연결을 유지할 수 있는 수 +- 처리 용량 : UDP 프로토콜에 대한 로드밸런싱 성능 지표 (FWLB에서 중요) + FWLB : 기존에 한대의 방화벽을 사용할 때 하나의 방화벽에 부하가 집중되면서 품질 저하 & FW 장애와 같은 문제가 발생했고 이런 문제점 때문에 두대의 방화벽을 운용하는 방식이다. + + ![https://s3-us-west-2.amazonaws.com/secure.notion-static.com/c2fafe75-7689-4a36-97b7-345c407d1939/_2021-06-01__5.44.50.png](https://s3-us-west-2.amazonaws.com/secure.notion-static.com/c2fafe75-7689-4a36-97b7-345c407d1939/_2021-06-01__5.44.50.png) + +참고 자료 + +[https://www.stevenjlee.net/2020/06/30/이해하기-네트워크의-부하분산-로드밸런싱-load-balancing-그/](https://www.stevenjlee.net/2020/06/30/%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0-%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC%EC%9D%98-%EB%B6%80%ED%95%98%EB%B6%84%EC%82%B0-%EB%A1%9C%EB%93%9C%EB%B0%B8%EB%9F%B0%EC%8B%B1-load-balancing-%EA%B7%B8/) diff --git a/network/TCP-IP-4-layer/hoi/README.md b/network/TCP-IP-4-layer/hoi/README.md new file mode 100644 index 0000000..ca1a317 --- /dev/null +++ b/network/TCP-IP-4-layer/hoi/README.md @@ -0,0 +1,65 @@ +# TCP/IP Protocol Stack 4 Layer 분석 + +TCP/IP의 4계층은 아래와 같이 구성되어 있다. + +- **Application Layer (응용 계층)** +- **Transport Layer (전송 계층)** +- **Internet Layer (인터넷 계층)** +- **Network Interface Layer (네트워크 인터페이스 계층)** + +### [1계층] Network Interface Layer (네트워크 인터페이스 계층) + +OSI 모델과 비교했을 때 (물리,데이터 링크) 계층에 해당합니다. + +### [2계층] **Internet Layer (인터넷 계층)** + +인터넷 계층의 가장 큰 역할은 오류 및 진단을 파악합니다. **IP(인터네트워킹 프로토콜)**는 패킷 교환 네트워크를 위해 설계되었지만 신뢰성이 없고 비연결형인 데이터그램 프로토콜이라는 특징을 가지고 있습니다. 따라서 IP는 전달을 위한 최선의 노력(best effort)만을 할 뿐 신뢰성을 위한 행위를 기반하진 않는다고 할 수 있습니다. + +**IP(인터네트워킹 프로토콜)**의 이런 특징 때문에 패킷 단위로 나눈 데이터가 유실될 가능성이 있으며 서로 다른 경로로 이동한 패킷의 순서가 보장되지 않는 경우도 있습니다. 이런 부분 때문에 IP는 상위 계층에 의존성을 가집니다. + +- IP : 비신뢰성 , 비연결지향 +- ARP : IP주소를 물리적인 주소로 변환 +- RARP : 물리 주소를 인터넷 주소로 변환 +- ICMP : 호스트에게 데이터그램의 문제점 발송 , 조회와 오류보고 메시지를 송신 +- IGMP : 수신자 그룹에게 메시지를 동시 전송 + +### [3계층] **Transport Layer (전송 계층)** + +전송 계층은 2개의 프로토콜(TCP , UDP)를 가지고 있습니다. + +```jsx +IP는 호스트 간 프로토콜로써 패킷을 물리적인 장치에서 다른 물리적 장치로 전달할 때 사용합니다. +``` + +**UDP** + +UDP는 TCP/IP와 대비해서 **단순한 프로세스**를 가지고 있습니다. 이런 특징 덕분에 속도적인 측면에서 이점을 가져갈 수 있으며 방대한 양의 데이터(비디오 , 큰 사이즈의 이미지 ....)를 송수신할 때 사용합니다. + +아래와 같은 정보만을 가지고 통신을 진행합니다. + +- 포트 주소 +- 검사합 +- 오류제어 +- 상위 계층으로부터 받은 데이터의 길이 + +**TCP** + +TCP는 신뢰성 있는 스트림 전송 프로토콜이라고 불립니다. UDP에 비해서 서버와 클라이언트 양 종단 간에 연결이 가능한 상태인지를 파악합니다. 이런 과정 덕분에 UDP보다 신뢰성이 있다고 판단되지만 여러 검증 과정을 거쳐야 하기 때문에 속도적인 측면에서는 UDP보다 떨어집니다. + +```jsx +**스트림은 연결 지향을 의미** + +TCP는 연결 지향을 위해서 3 way handshake를 사용합니다. +``` + +### **Application Layer (응용 계층)** + +OSI 모델과 비교했을 때 TCP/IP의 응용 계층은 OSI 모델의 3계층(세션,표현,응용)을 합친 역할을 합니다. 애플리케이션은 주로 아래와 같은 일들을 수행합니다. + +- 웹 브라우저(Port : 20 , 21) : 파일 송수신 +- 전자메일(Port : 25 , 110) : 메일 송수신 +- 원격 로그인(Port : 23): 원격 터미널 접속 +- 네트워크 관리 + +각 애플리케이션은 독자적인 통신 처리 과정이 필요하며 그 과정을 정의하는게 Application Protocol 입니다. +동작을 위해서 포트 번호를 활용하며 설계자 또는 개발자가 특정 네트워크 통신을 사용하기 위해서는 일반적인 애플리케이션 프로토콜 , 또는 필요에 따라서 독자적인 애플리케이션을 정의할 수 있습니다. From 578886f0852caec98f326356f89a3c83b18f20cb Mon Sep 17 00:00:00 2001 From: choijangho Date: Tue, 1 Jun 2021 18:00:27 +0900 Subject: [PATCH 019/142] =?UTF-8?q?Remove=20:=20=EC=8A=B9=EC=9D=B8=20?= =?UTF-8?q?=EB=B0=9B=EC=A7=80=20=EC=95=8A=EC=9D=80=20=EC=A0=95=EB=A6=AC=20?= =?UTF-8?q?=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- network/L4-vs-L7-load-balancer/hoi/README.md | 46 -------------- network/TCP-IP-4-layer/hoi/README.md | 65 -------------------- 2 files changed, 111 deletions(-) delete mode 100644 network/L4-vs-L7-load-balancer/hoi/README.md delete mode 100644 network/TCP-IP-4-layer/hoi/README.md diff --git a/network/L4-vs-L7-load-balancer/hoi/README.md b/network/L4-vs-L7-load-balancer/hoi/README.md deleted file mode 100644 index fa1df26..0000000 --- a/network/L4-vs-L7-load-balancer/hoi/README.md +++ /dev/null @@ -1,46 +0,0 @@ -# L4 로드밸런서 vs L7 로드밸런서 - -### 로드밸런싱 (부하 분산) - -로드밸런싱은 다수의 클라이언트 , 즉 높은 트래픽이 생기는 상황을 대비하는 네트워크 기술의 일종입니다. -중앙처리장치 또는 저장장치와 같은 컴퓨터 리소스를 추가적으로 운용하며 부하의 상황에 작업을 나눔으로써 높은 트래픽이 생기는 상황에도 서버는 안정성을 유지할 수 있습니다. - -### 로드밸런서의 문제 해결 방식 - -- Scale-up : Server의 하드웨어 성능을 높히는 방법 -- Scale-out : 여러 대의 Server에 작업을 분산시키는 방법 - -### L4 로드밸런서 - -L4 로드밸런서는 Network Layer(TCP/UDP)에서 정의된 정보를 활영하여 클라이언트의 요청을 분산시키는 작업을 진행합니다.정의된 정보는 IP주소,포트,MAC 주소,전송 프로토콜을 활용하여 분산을 결정합니다. - -- Round-Robin : 세션을 각 서버에 순차적으로 맺어주는 방식 , 순서를 기반으로 하는 작업이라서 균등한 분산이 보장되지 않을때가 있음 -- 가충치 및 비율 할당 방식 : 서버마다 수신 비율을 정하고 그 비율에 맞춰서 분산하는 방식 , 분산된 서버의 성능이 다르다면 가장 좋은 성능을 가진 서버에 할당치를 높히고 낮은 서버는 상대적으로 적은 할당치를 가지게 설계가 가능 -- 최소 연결(Least Connection) : 가장 적은 세션을 찾아 해방 서버로 트래픽을 할당하는 방식 -- 응답 시간(Response Time) : 가장 빠른 응답 시간을 가지는 서버에 트래픽을 할당하는 방식 -- 해시 : 특정 IP 또는 포트를 가지는 사용자는 특정 서버에 할당되도록 하는 방식 -- 대역폭 : 서버들과 대역폭을 고려하여 트래픽을 분산 - -### L7 로드밸런서 - -L7 로드밸런서는 OSI 모델에서 가장 높은 애플리케이션 계층에서 작동합니다. 포트와 IP를 활용하는 L4의 활용과 함께 컨텐츠 위주의 정보도 분석하여 분산 라우팅에 대한 결정을 내릴 수 있습니다. 아래는 L7 로드밸런서가 분산에 활용하는 정보입니다. - -- URL 스위칭 (URL Switching) : 특정 URL의 하위 URL을 특정 서버에 할당하는 방식 - `specific/post` `specific/video` 와 같이 특정 URL을 가진다면 서버가 아닌 별도의 스토리지로 연결 -- 컨텍스트 스위칭(Context Switching) : 클라이언트가 요청한 특정 리소스는 특정 서버로 연결되는 방식 , 즉 어떤 리소스를 요청하는지를 판별하여 해당 서버로 갈 수 있도록 설계 가능 -- 쿠키 지속성(Persistence with Cookies) : 클라이언트가 가지고 있는 쿠키정보를 바탕으로 클라이언트가 접속했던 서버에 다시 연결하는 방식 - -### L4 / L7 의 성능 지표 - -L4 / L7 중 어떤 로드밸런서가 더 좋은 성능을 가지는지는 아래와 같은 지표를 기준으로 판별하게 됩니다. - -- 초당 연결수 : TCP 세션 시간당 처리의 수 -- 동시 연결수 : 동시에 최대로 세션 연결을 유지할 수 있는 수 -- 처리 용량 : UDP 프로토콜에 대한 로드밸런싱 성능 지표 (FWLB에서 중요) - FWLB : 기존에 한대의 방화벽을 사용할 때 하나의 방화벽에 부하가 집중되면서 품질 저하 & FW 장애와 같은 문제가 발생했고 이런 문제점 때문에 두대의 방화벽을 운용하는 방식이다. - - ![https://s3-us-west-2.amazonaws.com/secure.notion-static.com/c2fafe75-7689-4a36-97b7-345c407d1939/_2021-06-01__5.44.50.png](https://s3-us-west-2.amazonaws.com/secure.notion-static.com/c2fafe75-7689-4a36-97b7-345c407d1939/_2021-06-01__5.44.50.png) - -참고 자료 - -[https://www.stevenjlee.net/2020/06/30/이해하기-네트워크의-부하분산-로드밸런싱-load-balancing-그/](https://www.stevenjlee.net/2020/06/30/%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0-%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC%EC%9D%98-%EB%B6%80%ED%95%98%EB%B6%84%EC%82%B0-%EB%A1%9C%EB%93%9C%EB%B0%B8%EB%9F%B0%EC%8B%B1-load-balancing-%EA%B7%B8/) diff --git a/network/TCP-IP-4-layer/hoi/README.md b/network/TCP-IP-4-layer/hoi/README.md deleted file mode 100644 index 7ef241b..0000000 --- a/network/TCP-IP-4-layer/hoi/README.md +++ /dev/null @@ -1,65 +0,0 @@ -# TCP/IP Protocol Stack 4 Layer - -TCP/IP의 4계층은 아래와 같이 구성되어 있다. - -- **Application Layer (응용 계층)** -- **Transport Layer (전송 계층)** -- **Internet Layer (인터넷 계층)** -- **Network Interface Layer (네트워크 인터페이스 계층)** - -### [1계층] Network Interface Layer (네트워크 인터페이스 계층) - -OSI 모델과 비교했을 때 (물리,데이터 링크) 계층에 해당합니다. - -### [2계층] **Internet Layer (인터넷 계층)** - -인터넷 계층의 가장 큰 역할은 오류 및 진단을 파악합니다. **IP(인터네트워킹 프로토콜)**는 패킷 교환 네트워크를 위해 설계되었지만 신뢰성이 없고 비연결형인 데이터그램 프로토콜이라는 특징을 가지고 있습니다. 따라서 IP는 전달을 위한 최선의 노력(best effort)만을 할 뿐 신뢰성을 위한 행위를 기반하진 않는다고 할 수 있습니다. - -**IP(인터네트워킹 프로토콜)**의 이런 특징 때문에 패킷 단위로 나눈 데이터가 유실될 가능성이 있으며 서로 다른 경로로 이동한 패킷의 순서가 보장되지 않는 경우도 있습니다. 이런 부분 때문에 IP는 상위 계층에 의존성을 가집니다. - -- IP : 비신뢰성 , 비연결지향 -- ARP : IP주소를 물리적인 주소로 변환 -- RARP : 물리 주소를 인터넷 주소로 변환 -- ICMP : 호스트에게 데이터그램의 문제점 발송 , 조회와 오류보고 메시지를 송신 -- IGMP : 수신자 그룹에게 메시지를 동시 전송 - -### [3계층] **Transport Layer (전송 계층)** - -전송 계층은 2개의 프로토콜(TCP , UDP)를 가지고 있습니다. - -```jsx -IP는 호스트 간 프로토콜로써 패킷을 물리적인 장치에서 다른 물리적 장치로 전달할 때 사용합니다. -``` - -**UDP** - -UDP는 TCP/IP와 대비해서 **단순한 프로세스**를 가지고 있습니다. 이런 특징 덕분에 속도적인 측면에서 이점을 가져갈 수 있으며 방대한 양의 데이터(비디오 , 큰 사이즈의 이미지 ....)를 송수신할 때 사용합니다. - -아래와 같은 정보만을 가지고 통신을 진행합니다. - -- 포트 주소 -- 검사합 -- 오류제어 -- 상위 계층으로부터 받은 데이터의 길이 - -**TCP** - -TCP는 신뢰성 있는 스트림 전송 프로토콜이라고 불립니다. UDP에 비해서 서버와 클라이언트 양 종단 간에 연결이 가능한 상태인지를 파악합니다. 이런 과정 덕분에 UDP보다 신뢰성이 있다고 판단되지만 여러 검증 과정을 거쳐야 하기 때문에 속도적인 측면에서는 UDP보다 떨어집니다. - -```jsx -**스트림은 연결 지향을 의미** - -TCP는 연결 지향을 위해서 3 way handshake를 사용합니다. -``` - -### **Application Layer (응용 계층)** - -OSI 모델과 비교했을 때 TCP/IP의 응용 계층은 OSI 모델의 3계층(세션,표현,응용)을 합친 역할을 합니다. 애플리케이션은 주로 아래와 같은 일들을 수행합니다. - -- 웹 브라우저(Port : 20 , 21) : 파일 송수신 -- 전자메일(Port : 25 , 110) : 메일 송수신 -- 원격 로그인(Port : 23): 원격 터미널 접속 -- 네트워크 관리 - -각 애플리케이션은 독자적인 통신 처리 과정이 필요하며 그 과정을 정의하는게 Application Protocol 입니다. -동작을 위해서 포트 번호를 활용하며 설계자 또는 개발자가 특정 네트워크 통신을 사용하기 위해서는 일반적인 애플리케이션 프로토콜 , 또는 필요에 따라서 독자적인 애플리케이션을 정의할 수 있습니다. From 48e24cba075332a9da9e6a937548c502212ed475 Mon Sep 17 00:00:00 2001 From: 102092 Date: Tue, 8 Jun 2021 20:03:51 +0900 Subject: [PATCH 020/142] Update web-cache directory --- {web-cache => network/web-cache}/hoi/README.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename {web-cache => network/web-cache}/hoi/README.md (100%) diff --git a/web-cache/hoi/README.md b/network/web-cache/hoi/README.md similarity index 100% rename from web-cache/hoi/README.md rename to network/web-cache/hoi/README.md From b8b6ed1c0f761b0d331c23816c0b707cad7358cd Mon Sep 17 00:00:00 2001 From: Han Date: Tue, 8 Jun 2021 20:43:58 +0900 Subject: [PATCH 021/142] Fix typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b465a56..4079717 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,7 @@ - 한 사람 당 각 주제에 대해 1개씩 질문 - 4개의 질문에 성심성의껏 답변을 작성 - 리뷰어는 이를 보고 PR을 승인할지 결정 - - 한명 이상의 리뷰어가 PR을 승인하면, 작성자는 PR을 머지 할 수 ㅇ있음 + - 한명 이상의 리뷰어가 PR을 승인하면, 작성자는 PR을 머지 할 수 있음 - 미팅 - 매주 화요일 20:00 ~ 20:30 까지 화상으로 그 주 진행한 스터디에 대해 피드백 하는 시간 - 해당 미팅에 참석하지 못할 경우, 해당 일 오전까지는 참가원에게 알려줘야함 From 14fcdfac4984675c231cfe5fe2b691940d1fa0b3 Mon Sep 17 00:00:00 2001 From: 102092 Date: Sun, 30 May 2021 20:31:26 +0900 Subject: [PATCH 022/142] Add L4 vs L7 load-balancer --- network/L4-vs-L7-load-balancer/han/README.md | 35 ++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 network/L4-vs-L7-load-balancer/han/README.md diff --git a/network/L4-vs-L7-load-balancer/han/README.md b/network/L4-vs-L7-load-balancer/han/README.md new file mode 100644 index 0000000..32b1101 --- /dev/null +++ b/network/L4-vs-L7-load-balancer/han/README.md @@ -0,0 +1,35 @@ +# L4, L7 이란? +![](https://avinetworks.com/wp-content/uploads/2018/10/l4-l7-network-services.png) +- OSI 7 layer에서 나오는 용어 +- L4는 Transport layer에 해당하고, L7는 Application Layer에 해당한다. +- L4에 해당하는 대표적인 프로토콜은 TCP/UDP +- L7에 해당하는 대표적인 프로토콜은 HTTP + +# Load balancer란? +- 트래픽을 분산하여 서버에게 보내, 이용자에게는 적절한 응답속도 및 이용성을 제공하고, 서버 측면에서는 부하를 나눠 부담시켜 가용성을 증대시키는 기술을 의미 + +## L4 Load balancer +- TCP/UDP 상에서, 분석하여 트래픽을 서버에 분배해서 보내는 것. + - 그 정보는 IP주소, 포트 번호, MAC주소 전송 프로토콜등이 있음.. + - 보통 port 정보를 바탕으로 트래픽을 분산. +- 만약에 서버 한대에, 각기 다른 포트로 여러 프로그램이 작동 중이고, 이에 트래픽을 분산시키고 싶다면 L4 이상 레벨에서 로드밸런서를 이용해야함. +- 또한, 주로 Round Robin 알고리즘을 사용해서 트래픽을 분배. + +![](https://post-phinf.pstatic.net/MjAxOTEyMTBfNCAg/MDAxNTc1OTU1MzY3OTM2.nG91HOEOh6Sc1AuUgbN3O4pcnEI-rh24UKSrrrjkrcsg.VcG18MidW4az7Oh0RQfRPLDBHNRyGayE1BsQxDImL3Ig.JPEG/L4-%EB%A1%9C%EB%93%9C%EB%B0%B8%EB%9F%B0%EC%8B%B1.jpg?type=w1200) + +## L7 Load balancer +- HTTP/HTTPS header, 쿠키의 내용으로 트래픽을 특정 서버로 분산 시키는 것. +- application level에서 행해지므로, 여러 정보(헤더, 쿠키...) 들을 기반으로 요청을 나눌 수 있다는 장점이 있음. + - 요청에 대해 상세한 정보를 기반으로 트래픽을 나눌 수 있기 때문에, 다른 레벨의 로드밸런서보다 좀 더 세분화하여 로드 밸랜싱을 할 수 있다는 장점이 있음. +- 특정 패턴 요청을 무시하거나, Dos/DDoS 같은 비정상적인 트래픽을 필터링하는 것도 이 단계에서 이루어짐. + +![](https://post-phinf.pstatic.net/MjAxOTEyMTBfMjA1/MDAxNTc1OTU1MzgxODY5.odnG4CRES0e5bH7sOKyWRP1c8uO_XC4VX9A3HPeI1JQg.lNL2eJYbMz6NX1e5YFzfHDMQHn4YrdOJR2VYHmq5e1Ig.JPEG/L7-%EB%A1%9C%EB%93%9C%EB%B0%B8%EB%9F%B0%EC%8B%B1.jpg?type=w1200) + +## L4 vs L7 +![](https://media.vlpt.us/images/makeitcloud/post/76db786e-1e41-4d91-aff7-9d3a5f6cde42/image.png) + +# 참고 +- https://avinetworks.com/glossary/l4-l7-network-services/ +- https://nesoy.github.io/articles/2018-06/Load-Balancer +- https://velog.io/@makeitcloud/%EB%9E%80-L4-load-balancer-vs-L7-load-balancer-%EB%9E%80 +- https://post.naver.com/viewer/postView.nhn?volumeNo=27046347&memberNo=2521903 \ No newline at end of file From f8561b49ccb954e4deba2d725321145a92fd4524 Mon Sep 17 00:00:00 2001 From: 102092 Date: Sun, 30 May 2021 21:11:55 +0900 Subject: [PATCH 023/142] Add TCP IP 4 layer --- network/TCP-IP-4-layer/han/README.md | 50 ++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 network/TCP-IP-4-layer/han/README.md diff --git a/network/TCP-IP-4-layer/han/README.md b/network/TCP-IP-4-layer/han/README.md new file mode 100644 index 0000000..568d157 --- /dev/null +++ b/network/TCP-IP-4-layer/han/README.md @@ -0,0 +1,50 @@ +# TCP/IP model +![](https://www.guru99.com/images/1/093019_0615_TCPIPModelW1.png) +- 개념적으로 위와 같이 4계층으로 나뉘어져 있음. +- 각각 계층이 가지고 있는 프로토콜들이 존재 +- TCP/IP는 여러 프로토콜을 모은 총칭을 의미하기도 함. + +## Application Layer +- 기본적으로 user와 직접적으로 소통하는 레벨 +- 유저가 로그인 하거나, +- 이메일 서비스를 제공하는 레벨 +- HTTP, FTP, SMTP, Telnet, DNS 프로토콜이 이에 해당함. + +## Transport Layer +- 자료의 송수신을 담당. +- TCP, UDP 프로토콜이 이에 해당 + +## Internet Layer +- IP를 이용해, 네트워크 노드간 전송과 라우팅 기능을 담당. +- 유저가 요청한 최종 목적지까지 연결되도록 연결성을 제공. +- IP, ARP, ICMP, IGMP가 이에 해당 + +## Network Layer +- 패킷을 네트워크 레이어로 전달하는 역할. +- MAC 주소를 이용해 패킷을 어디에 보내야할지 판단된다. + +# 송,수신 단계별 +![](https://media.vlpt.us/post-images/conatuseus/d6b2f390-d3c9-11e9-b578-e7ac71f50ec2/image.png) +- 네트워크 계층은 위 컨셉에서 인터넷 레이어를 의미하고, 링크 계층은 네트워크 레이어를 의미하는듯. + +# TCP and IP +- 아마도 이 두가지 프로토콜이 인터넷 통신에서 가장 중요하기 때문에, TCP/IP와 같은 명칭이 나오지 않았나 싶음. + +## TCP +- 2번째 계층 (트랜스포트) 에 해당 +- 클라이언트와 서버 둘이 신뢰할 수 있는 바이트 스트림을 열기 위해서 사용하는 프로토콜임. +- 신뢰를 형성하기 위해 3-hand-shaking등의 방법을 이용 + +## IP +- 3번째 계층에 해당하고 (Internet or 네트워크 계층) +- IP 주소는 통신 기기들이 서로 인식하기 위한 특수한 번호 + - 반면 MAC 주소는 각 네트워크 카트에 할당된 **고유한** 값 +![](https://media.vlpt.us/post-images/conatuseus/3508a100-d3da-11e9-b72b-91ecbe0f0a65/image.png) +- ARP라는 프로토콜을 이용하여, 수신지의 IP주소를 바탕으로 다음에 요청을 보낼 MAC주소를 조사할 수 있음. +- 위와 같이 계속 요청하다보면 결국 원하는 도착지에 도달하는 형식 + +# 참고 +- https://www.guru99.com/tcp-ip-model.html +- https://d2.naver.com/helloworld/47667 +- https://velog.io/@conatuseus/2019-09-10-2009-%EC%9E%91%EC%84%B1%EB%90%A8-xsk0ds2eqf +- [1% 네트워크](http://www.kyobobook.co.kr/product/detailViewKor.laf?mallGb=KOR&ejkGb=KOR&barcode=9788931556742) -> 102p...~ \ No newline at end of file From 77f274bec93a26f306d9b746becac8b7f8132bae Mon Sep 17 00:00:00 2001 From: 102092 Date: Tue, 8 Jun 2021 21:20:32 +0900 Subject: [PATCH 024/142] Add QnA --- network/L4-vs-L7-load-balancer/han/README.md | 29 +++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/network/L4-vs-L7-load-balancer/han/README.md b/network/L4-vs-L7-load-balancer/han/README.md index 32b1101..6119ffa 100644 --- a/network/L4-vs-L7-load-balancer/han/README.md +++ b/network/L4-vs-L7-load-balancer/han/README.md @@ -32,4 +32,31 @@ - https://avinetworks.com/glossary/l4-l7-network-services/ - https://nesoy.github.io/articles/2018-06/Load-Balancer - https://velog.io/@makeitcloud/%EB%9E%80-L4-load-balancer-vs-L7-load-balancer-%EB%9E%80 -- https://post.naver.com/viewer/postView.nhn?volumeNo=27046347&memberNo=2521903 \ No newline at end of file +- https://post.naver.com/viewer/postView.nhn?volumeNo=27046347&memberNo=2521903 + +--- + +# QnA + +## 1. TCP/IP vs OSI 7 layer +![image](https://user-images.githubusercontent.com/22140570/121183244-d5a9e000-c89e-11eb-8888-2df53fdb6be4.png) + +> 참고 +- https://www.guru99.com/difference-tcp-ip-vs-osi-model.html +- https://goitgo.tistory.com/25 + +## 2. 로드 밸런서가 필요한 이유 +![image](https://user-images.githubusercontent.com/22140570/121183397-fd00ad00-c89e-11eb-9c00-b8173aa65607.png) + +> 참고 +- https://newrelic.com/blog/best-practices/importance-local-load-balancing +- https://toma0912.tistory.com/87 + +## 3. L7 계층해서 사용하는 프로토콜 (HTTP 제외) +![image](https://user-images.githubusercontent.com/22140570/121183492-17d32180-c89f-11eb-820d-8669a9124869.png) + +## 4. ARP라는 프로토콜은 어떤식으로 동작하는가? +![image](https://user-images.githubusercontent.com/22140570/121183610-3b966780-c89f-11eb-87bc-5b7d80a22a26.png) +> 참고 +- https://www.practicalnetworking.net/series/arp/traditional-arp/ +- https://musclebear.tistory.com/12 \ No newline at end of file From 84a061875025616e2c5b46ca526a0701ebbb0ef9 Mon Sep 17 00:00:00 2001 From: 102092 Date: Tue, 8 Jun 2021 21:24:56 +0900 Subject: [PATCH 025/142] Update QnA --- network/L4-vs-L7-load-balancer/han/README.md | 17 ++-------------- network/TCP-IP-4-layer/han/README.md | 21 +++++++++++++++++++- 2 files changed, 22 insertions(+), 16 deletions(-) diff --git a/network/L4-vs-L7-load-balancer/han/README.md b/network/L4-vs-L7-load-balancer/han/README.md index 6119ffa..c0d5370 100644 --- a/network/L4-vs-L7-load-balancer/han/README.md +++ b/network/L4-vs-L7-load-balancer/han/README.md @@ -38,25 +38,12 @@ # QnA -## 1. TCP/IP vs OSI 7 layer -![image](https://user-images.githubusercontent.com/22140570/121183244-d5a9e000-c89e-11eb-8888-2df53fdb6be4.png) - -> 참고 -- https://www.guru99.com/difference-tcp-ip-vs-osi-model.html -- https://goitgo.tistory.com/25 - -## 2. 로드 밸런서가 필요한 이유 +## 1. 로드 밸런서가 필요한 이유 ![image](https://user-images.githubusercontent.com/22140570/121183397-fd00ad00-c89e-11eb-9c00-b8173aa65607.png) > 참고 - https://newrelic.com/blog/best-practices/importance-local-load-balancing - https://toma0912.tistory.com/87 -## 3. L7 계층해서 사용하는 프로토콜 (HTTP 제외) +## 2. L7 계층해서 사용하는 프로토콜 (HTTP 제외) ![image](https://user-images.githubusercontent.com/22140570/121183492-17d32180-c89f-11eb-820d-8669a9124869.png) - -## 4. ARP라는 프로토콜은 어떤식으로 동작하는가? -![image](https://user-images.githubusercontent.com/22140570/121183610-3b966780-c89f-11eb-87bc-5b7d80a22a26.png) -> 참고 -- https://www.practicalnetworking.net/series/arp/traditional-arp/ -- https://musclebear.tistory.com/12 \ No newline at end of file diff --git a/network/TCP-IP-4-layer/han/README.md b/network/TCP-IP-4-layer/han/README.md index 568d157..cc2616c 100644 --- a/network/TCP-IP-4-layer/han/README.md +++ b/network/TCP-IP-4-layer/han/README.md @@ -47,4 +47,23 @@ - https://www.guru99.com/tcp-ip-model.html - https://d2.naver.com/helloworld/47667 - https://velog.io/@conatuseus/2019-09-10-2009-%EC%9E%91%EC%84%B1%EB%90%A8-xsk0ds2eqf -- [1% 네트워크](http://www.kyobobook.co.kr/product/detailViewKor.laf?mallGb=KOR&ejkGb=KOR&barcode=9788931556742) -> 102p...~ \ No newline at end of file +- [1% 네트워크](http://www.kyobobook.co.kr/product/detailViewKor.laf?mallGb=KOR&ejkGb=KOR&barcode=9788931556742) -> 102p...~ + +--- + +# QnA + +## 1. TCP/IP vs OSI 7 layer +![image](https://user-images.githubusercontent.com/22140570/121183244-d5a9e000-c89e-11eb-8888-2df53fdb6be4.png) + +> 참고 +- https://www.guru99.com/difference-tcp-ip-vs-osi-model.html +- https://goitgo.tistory.com/25 + + +## 2. ARP라는 프로토콜은 어떤식으로 동작하는가? +![image](https://user-images.githubusercontent.com/22140570/121183610-3b966780-c89f-11eb-87bc-5b7d80a22a26.png) + +> 참고 +- https://www.practicalnetworking.net/series/arp/traditional-arp/ +- https://musclebear.tistory.com/12 \ No newline at end of file From d6856c8184ee364559c606b8d790593eb73a165f Mon Sep 17 00:00:00 2001 From: 102092 Date: Sat, 12 Jun 2021 15:43:13 +0900 Subject: [PATCH 026/142] Add proxy, gateway, tunnel --- network/proxy-gateway-tunnel/han/REAMDE.md | 38 ++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 network/proxy-gateway-tunnel/han/REAMDE.md diff --git a/network/proxy-gateway-tunnel/han/REAMDE.md b/network/proxy-gateway-tunnel/han/REAMDE.md new file mode 100644 index 0000000..669f27c --- /dev/null +++ b/network/proxy-gateway-tunnel/han/REAMDE.md @@ -0,0 +1,38 @@ +# Proxy +- 서버 혹은 프로그램 +- Proxy란 의미는 보통 '대체' 라는 의미로 사용되는 듯. +- 즉 클라이언트의 요청을 바로 서버에 전달되는 것이 아닌, Proxy 라는 서버 혹은 프로그램을 통해서 서버에 전달되도록 함. +- 이를 통해 얻는 장점? + - 서버의 보안성을 유지할 수 있음. (서버 IP를 숨김..) + - 서버에 리소스를 굳이 요청하지 않아도, 프록시 서버가 처리하도록 할 수 있음 (캐싱) +- 어느쪽에서 해당 기능을 사용하냐에 따라 Forward, Reverse로 나뉘는듯.. + ![](https://kinsta.com/wp-content/uploads/2020/08/Forward-Proxy-vs-Reverse-Proxy-Servers.png) + +## Forward Proxy +- gateway와 비슷한 역할 +- 프록시 서비스를 클라이언트쪽에 제공 +- 클라이언트의 IP등을 숨기고 요청을 보내는 등의 서비스가 Forward Proxy를 이용하는것에 해당하는 듯. +- [TOR](https://www.torproject.org/) + +## Reverse Proxy +- 클라이언트 요청을 서버로 바로 전달하지 않도록, 서버 앞단에 프록서 서버를 배치하는 것. +- 서버 보안성, 캐시, 로드밸런서등의 장점을 취득할 수 있음. +- `Nginx` 등이 이에 해당. + + +# Gateway +- 보통 인터넷 서비스에 필요한 장비를 일컫는 말. +- 라우터 역할 +- 프록시 여러 역할을 가지고 있기보다는, 단순하게 request, response를 **전달** 하는 역할만 있는 듯. + +# Tunnel +- 인터넷 상에서 이루어지는 논리적인 형태를 의미. + - 보통 두 endpoints 에서 이루어지는 연결을 의미함. +- local -- vpn -- internet 형태라면, 터널이 생겼다고 말할 수 있을듯. + - 이러한 터널은, local 혹은 도착치에서 각각 제거될 수 있을듯. + +# 참고 +- https://stackoverflow.com/questions/10377679/whats-distinction-of-http-proxy-tunnel-gateway +- https://developer.mozilla.org/en-US/docs/Web/HTTP/Proxy_servers_and_tunneling +- https://ko.wikipedia.org/wiki/%ED%94%84%EB%A1%9D%EC%8B%9C_%EC%84%9C%EB%B2%84 +- https://www.quora.com/What-are-the-differences-among-proxy-gateway-and-tunnel \ No newline at end of file From 9a87c7d1df795ce235e5ff127dafc1a672bb0851 Mon Sep 17 00:00:00 2001 From: 102092 Date: Sat, 12 Jun 2021 16:09:40 +0900 Subject: [PATCH 027/142] Add socket.io --- network/web-socket/han/REAMDE.md | 48 ++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 network/web-socket/han/REAMDE.md diff --git a/network/web-socket/han/REAMDE.md b/network/web-socket/han/REAMDE.md new file mode 100644 index 0000000..97f0c22 --- /dev/null +++ b/network/web-socket/han/REAMDE.md @@ -0,0 +1,48 @@ +# websocket이란? +- TCP 접속 중에, 쌍방향 통신 채널을 제공하도록 하는 통신 프로토콜을 의미 +- 보통 HTTP(80, 443) 위에서 동작하도록 설계되어 있음. + +## 등장 배경 +- 양방향 통신의 필요성 대두 +- 클라이언트가 요청을 보내면, 응답하는 전형적인 HTTP 프로토콜 방식의 한계 (화면 깜박임등..) +- 이를 해결하기 위해, Polling, Long Polling, Streaming 등의 방식이 나왔지만.. + - 기본적인 단방향 메세지 교환 규칙의 한계를 벗어날 순 없었음. + - 즉 진정한 의미에서 양방향, 상호교환 작용하는 웹이 필요해졌음. +- cf) Polling, Long Polling, Steaming 작동방식 참고 + - http://www.secmem.org/blog/2019/08/17/websocket-socketio/ + + +## websocekt 등장 +![](https://d2.naver.com/content/images/2015/06/helloworld-1336-1-1.png) +- 클라이언트와 서버와 간의 실시간 통신을 가능토록 해줌 + - 클라이언트 요청에 의해서. 서버가 응답을 주는 방식이 아닌, 서버가 데이터를 클라이언트에게 보내는 방식을 채택 + +## websocket protocol +``` +GET /... HTTP/1.1 +Upgrade: WebSocket +Connection: Upgrade +``` +- 헤더에 `Upgrade`항목을 붙여서, 서버에 요청함. +- 웹 서버에서 websocket 기능을 지원할 경우, + 1. 브라우저는 키를 랜덤 생성 + 2. 브라우저는 upgrade 헤더 항목과 함께 키를 서버에 보냄 + 3. 서버는 브라우저가 전송한 키를 바탕으로 토큰 생성 + 4. 서버는 토큰을 브라우저에게 돌려줌 + 5. 이제 서버 -- 브라우저는 Websocket 프로토콜을 기반으로 실시간 통신을 할 수있도록 연결되었다고 볼 수 있음. + + +# socekt.io 이란? +- Javascript 를 이용해서, 브라우저 종류와 상관없이 실시간 통신을 할 수 있도록 지원하는 라이브러리 +- 어떻게 여러 브라우저에서 사용할 수 있을까? + - 이용자는 하나의 API 만 사용하도록 유도하고, 해당 api 내부에서 이용자의 브라우저, 웹서버를 파악하여 가장 적절한 기술을 선택해서 사용하도록 설계되어있음. +- https://d2.naver.com/helloworld/1336 에서, 간단하게 테스트해볼 수 있다! + + +# websocket vs socekt.io +- + +# 참고 +- https://ko.wikipedia.org/wiki/%EC%9B%B9%EC%86%8C%EC%BC%93 +- https://d2.naver.com/helloworld/1336 +- https://socket.io/ \ No newline at end of file From 0c8882a8e1bd083a1f42f06a2b0bfe7e69bf2470 Mon Sep 17 00:00:00 2001 From: 102092 Date: Sat, 12 Jun 2021 16:15:30 +0900 Subject: [PATCH 028/142] Clean up code --- network/{web-socket => webSocket}/han/REAMDE.md | 2 -- 1 file changed, 2 deletions(-) rename network/{web-socket => webSocket}/han/REAMDE.md (98%) diff --git a/network/web-socket/han/REAMDE.md b/network/webSocket/han/REAMDE.md similarity index 98% rename from network/web-socket/han/REAMDE.md rename to network/webSocket/han/REAMDE.md index 97f0c22..fa65c98 100644 --- a/network/web-socket/han/REAMDE.md +++ b/network/webSocket/han/REAMDE.md @@ -39,8 +39,6 @@ Connection: Upgrade - https://d2.naver.com/helloworld/1336 에서, 간단하게 테스트해볼 수 있다! -# websocket vs socekt.io -- # 참고 - https://ko.wikipedia.org/wiki/%EC%9B%B9%EC%86%8C%EC%BC%93 From f3713f29cfea5ea2fd7d92bac2098f33eee56623 Mon Sep 17 00:00:00 2001 From: Han Date: Tue, 22 Jun 2021 20:20:31 +0900 Subject: [PATCH 029/142] Update README.md --- README.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 4079717..50e0d04 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ # lets-cs ## 스터디 규칙 -- 일정 : 05.25 ~ 06.25 -- 주제 : 네트워크 +- 일정 : 06.29 ~ 07.29 +- 주제 : 데이터베이스 - 진행 방식 - 2주가 하나의 사이클 - 1주차에는 질문에 대한 정리 및 PR, 2주차에는 PR 리뷰 및 수정을 진행 @@ -19,7 +19,6 @@ - 브랜치 전략 - Main - han - - hoi - hamil - 체크 리스트 From 6653465528ebf990d596bc416ad0e2a4139bf42b Mon Sep 17 00:00:00 2001 From: 102092 Date: Tue, 22 Jun 2021 20:58:33 +0900 Subject: [PATCH 030/142] Add QnA section --- network/proxy-gateway-tunnel/han/REAMDE.md | 14 +++++++++++++- network/webSocket/han/REAMDE.md | 13 +++++++++++-- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/network/proxy-gateway-tunnel/han/REAMDE.md b/network/proxy-gateway-tunnel/han/REAMDE.md index 669f27c..3cbd968 100644 --- a/network/proxy-gateway-tunnel/han/REAMDE.md +++ b/network/proxy-gateway-tunnel/han/REAMDE.md @@ -35,4 +35,16 @@ - https://stackoverflow.com/questions/10377679/whats-distinction-of-http-proxy-tunnel-gateway - https://developer.mozilla.org/en-US/docs/Web/HTTP/Proxy_servers_and_tunneling - https://ko.wikipedia.org/wiki/%ED%94%84%EB%A1%9D%EC%8B%9C_%EC%84%9C%EB%B2%84 -- https://www.quora.com/What-are-the-differences-among-proxy-gateway-and-tunnel \ No newline at end of file +- https://www.quora.com/What-are-the-differences-among-proxy-gateway-and-tunnel + +# QnA +![image](https://user-images.githubusercontent.com/22140570/122920106-fa707e00-d39b-11eb-833e-9e9a89521e67.png) +- 참고 + - https://www.techopedia.com/definition/5402/tunneling + - https://www.cloudflare.com/ko-kr/learning/network-layer/what-is-tunneling + +--- + +![image](https://user-images.githubusercontent.com/22140570/122920206-18d67980-d39c-11eb-8bb4-7c661db486ec.png) +- 프록시서버, 게이트웨이, 방화벽등등.. 어떤 역할을 담당하는 지에 따라서 다르게 이름 붙여지는듯. +- 다만 게이트웨이는 프로토콜 전환이 가능하고 어떤 계층(OSI) 에서도 사용가능하다는 점이 있을듯.. \ No newline at end of file diff --git a/network/webSocket/han/REAMDE.md b/network/webSocket/han/REAMDE.md index fa65c98..87f52b3 100644 --- a/network/webSocket/han/REAMDE.md +++ b/network/webSocket/han/REAMDE.md @@ -39,8 +39,17 @@ Connection: Upgrade - https://d2.naver.com/helloworld/1336 에서, 간단하게 테스트해볼 수 있다! - # 참고 - https://ko.wikipedia.org/wiki/%EC%9B%B9%EC%86%8C%EC%BC%93 - https://d2.naver.com/helloworld/1336 -- https://socket.io/ \ No newline at end of file +- https://socket.io/ + + +# QnA +![image](https://user-images.githubusercontent.com/22140570/122920441-60f59c00-d39c-11eb-875d-2f74a09c01ae.png) +- 참고 + - https://stackoverflow.com/questions/14133452/which-osi-layer-does-websocket-protocol-lay-on + +--- + +![image](https://user-images.githubusercontent.com/22140570/122920542-7a96e380-d39c-11eb-89cd-3e20f061e67e.png) From ba01cac07c88464717b86a55ae689720b4077e50 Mon Sep 17 00:00:00 2001 From: 102092 Date: Mon, 28 Jun 2021 22:20:39 +0900 Subject: [PATCH 031/142] Add index --- database/index-basic/han/README.md | 47 ++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 database/index-basic/han/README.md diff --git a/database/index-basic/han/README.md b/database/index-basic/han/README.md new file mode 100644 index 0000000..2b09f65 --- /dev/null +++ b/database/index-basic/han/README.md @@ -0,0 +1,47 @@ +# index란? +- 인덱스는 색인 +- 색인은 키워드가 문자 순으로 정렬, 해당 키워드가 있는 페이지가 적혀있음. + - 즉 정렬된 키워드를 탐색하여, 그 키워드에 대해 알아보기 위한 곳으로 인도해주는 역할을 하고 있다고 볼 수 있음. +- 데이터 베이스에서 인덱스는? + - 정렬된 데이터임. + - 즉 테이블에 본 데이터를 빠르게 찾기 위한, 특정한 형태로 생성되어 정렬된 형태의 데이터를 일컫는다고 생각하면 좋을듯. + +# index 구성 +![](https://t1.daumcdn.net/cfile/tistory/99240D3359FEEDA92A) +- key + pointer (실제 레코드를 가르키고 있는 페이지 id value) + +# index의 종류 +- B-tree, B+tree, Hash, Fractoal-Tree +- [B-tree vs B+tree 에 대해 더 알아보기..](https://zorba91.tistory.com/293) + +## MySQL +- 인덱스는 페이지 단위로 관리 +- 기본적으로 페이지 크기는 16kb +- MySQL은 DB engine으로 InnoDB를 사용 중이고 이는 B-tree 로 이루어져있다고 알려져있음. (확실하진 않다!) +- B-tree의 핵심은 데이터가 정렬된 상태로 유지되는 것. +- 그리고 리프, 브랜치 노드에 모두 데이터 저장 가능하다. +- [참고](https://stackoverflow.com/questions/65353975/how-to-view-the-b-tree-index-structure-generated-by-innodb-of-mysql) + +## Oracle +- B-tree, Bitmap, Partioned, Function-base, Domain.. 인덱스를 사용할 수 있다! +- [참고](https://docs.oracle.com/cd/B19306_01/server.102/b14200/statements_5010.htm) + +# index 는 어떤 컬럼에 거는 게 좋을까? +- 해당 컬럼의 Cardinality 가장 높은 것으로 잡아야함. +- Cardinality? + - 해당 컬럼의 중복된 수치 + - 중복도가 낮으면, Cardinality는 높고 (주민등록번호) + - 중복도가 높으면, Cardinality는 낮다 (성별..) +- 왜? + - 인덱스를 사용하는 이유는 원하는 컬럼에 빠르게 접근하기 위해. + - 중복도가 높은 값에 인덱스가 있으면.. 해당 인덱스는 효율이 떨어진다고 여겨질 수 있을 것이다. + + + +# 참고 +- 관계형 데이터 베이스 실전 입문 11장 +- https://mangkyu.tistory.com/96?category=761304 +- https://jojoldu.tistory.com/243 +- https://joosjuliet.github.io/index/ +- https://joosjuliet.github.io/index_structure/ +- https://joosjuliet.github.io/index_guidline/ From 29202471ec9ffdaed43a80645ba61a08a9f8da82 Mon Sep 17 00:00:00 2001 From: 102092 Date: Mon, 28 Jun 2021 22:26:44 +0900 Subject: [PATCH 032/142] Add mysql indexs.. --- database/index-basic/han/README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/database/index-basic/han/README.md b/database/index-basic/han/README.md index 2b09f65..e12ae2d 100644 --- a/database/index-basic/han/README.md +++ b/database/index-basic/han/README.md @@ -17,7 +17,9 @@ ## MySQL - 인덱스는 페이지 단위로 관리 - 기본적으로 페이지 크기는 16kb -- MySQL은 DB engine으로 InnoDB를 사용 중이고 이는 B-tree 로 이루어져있다고 알려져있음. (확실하진 않다!) +- MySQL은 DB engine으로 InnoDB를 사용 중이고 이는 B-tree 로 +이루어져있다고 알려져있음. (확실하진 않다!) + - 추가적으로 hash, full-text index등을 지원하는 등 (5.7 기준) - B-tree의 핵심은 데이터가 정렬된 상태로 유지되는 것. - 그리고 리프, 브랜치 노드에 모두 데이터 저장 가능하다. - [참고](https://stackoverflow.com/questions/65353975/how-to-view-the-b-tree-index-structure-generated-by-innodb-of-mysql) From 5eac7ebfd85020733f1166f8c442b64edf79fc8b Mon Sep 17 00:00:00 2001 From: Han Date: Tue, 29 Jun 2021 21:14:36 +0900 Subject: [PATCH 033/142] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 50e0d04..9fbdd66 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ ## 스터디 규칙 - 일정 : 06.29 ~ 07.29 -- 주제 : 데이터베이스 +- 주제 : **데이터베이스** - 진행 방식 - 2주가 하나의 사이클 - 1주차에는 질문에 대한 정리 및 PR, 2주차에는 PR 리뷰 및 수정을 진행 @@ -12,7 +12,7 @@ - 매주 체크 리스트에서 미달성 시, 하나 당 10,000원 차감 - 단, 체크 리스트 모두 미달성 시, 50,000원 차감 - 폴더 전략 - - 대주제 (네트워크) + - 대주제 (예시: 네트워크) - 이슈명 (cookie-vs-session, 소문자, dash 사용) - 브랜치명 (han) - README.md From 787657cced26940cd6d08ba8b1e811956b423428 Mon Sep 17 00:00:00 2001 From: Han Date: Tue, 29 Jun 2021 23:11:16 +0900 Subject: [PATCH 034/142] Update README.md Add reference --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 9fbdd66..c262ed6 100644 --- a/README.md +++ b/README.md @@ -46,4 +46,5 @@ ## 참고 - [면접질문-JaeYeopHan](https://github.com/JaeYeopHan/Interview_Question_for_Beginner) + - [Backend-Interview-Question](https://github.com/ksundong/backend-interview-question) - [우테코-테크톡](https://www.youtube.com/watch?v=vNsZXC3VgUA&list=PLgXGHBqgT2TvpJ_p9L_yZKPifgdBOzdVH) From 442ad76137d5cd6e0b5b880f2083158f235a09fa Mon Sep 17 00:00:00 2001 From: Jin Hyung Park Date: Sat, 3 Jul 2021 17:01:51 +0900 Subject: [PATCH 035/142] =?UTF-8?q?INDEX=20=EA=B8=B0=EB=B3=B8=20=EA=B0=9C?= =?UTF-8?q?=EB=85=90=20=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- database/index-basic/sigrid_index.md | 122 +++++++++++++++++++++++++++ 1 file changed, 122 insertions(+) create mode 100644 database/index-basic/sigrid_index.md diff --git a/database/index-basic/sigrid_index.md b/database/index-basic/sigrid_index.md new file mode 100644 index 0000000..0f72df6 --- /dev/null +++ b/database/index-basic/sigrid_index.md @@ -0,0 +1,122 @@ +# Database 7월 1주차 +### Index란 무엇인가? +#### 도입 +* 내가 데이터베이스 서적을 보고 있다고 치자. 그런데 이 DB 책이 한 1만 페이지 정도 된다고 가정해보자고. 내가 여기서 Index에 대한 설명을 찾고 싶다 라고 치면은 이걸 1만 페이지 내내 넘겨보면서 찾겠냐? 그건 절대 불가능하다. +* 물론 목차라는 것이 있지. 목차는 주로 중요한 Theme별로 서술이 되어 있다라는 거지. 그런데 말이야, 내가 이 저자가 Index를 얼마나 중요하게 생각하는 지 어떻게 알깜? Index 라는 단.어.를 목차에서 찾는 것도 졸라 빡시겠지? +* 그래서 보통 두꺼운 책은 책 맨 뒤에 색인이라는 게 있지. ABC 색인, 가나다 색인, 뭐 성경 목차에 따른 색인(토라 5경이 먼저 나오고...) 이런 식으로. 여기서 색인은 정확히 데이터베이스의 인덱스와 일치하는 개념이다. +* 예를 들어 내가 다음의 서적에서 Index를 찾는다고 가정하자. + ``` +1 Intro +2 Intro +3 Intro +512 SQL +513 SQL +5544 Optimizer +5545 Transaction +5546 Transaction +5547 Transaction +5700 Transaction +5701 Transaction +5702 ConcurrenctControl +5703 ConcurrenctControl +``` + +* 여기서 Transaction은 5545~5700까지 저장되어 있다. +* 이걸 쿼리로 찾아서 뒤져보려면 푸하하 전부 다 뒤져보면 된다. 브루트 포스다 ㅋㅋㅋ +``` +SELECT page +FROM db_book +WHERE title = 'Transaction'; +``` +* DB는 일단 5545번에 당도하더라도 뒤에 Transaction 관련된 DB가 더 있을 것이라고 생각한다. 그리고 실제로도 더 있다. 인간이라면 5545번을 찾고, 아 여기서부터가 Transaction이겠거니 생각하는데 컴퓨터는 멍청해서 다 뒤져본다. (그리고 실제로 갑자기 8000번부터 또 Transaction 파트 II 이거면 어떡할래?) +* 우리는 이러한 멍청한 방식을 Full Scan이라고 부른다. +#### 인덱스 만들어보기 +* 인덱스도 결국엔 하나의 테이블이다. index_title 이라는 이름의 테이블을 만들자. +* 우선 ‘Transaction’ 이라는 키워드를 쉽게 찾을 수 있도록 abc 순으로 정렬하면 좋을 것 같다. +``` +ConcurrenctControl 5702 +ConcurrenctControl 5703 +Transaction 5545 +Transaction 5546 +Transaction 5547 +Transaction 5700 +Transaction 5701 +``` +* 중복된 내용은 해당 내용의 가장 첫 번째 페이지만 남기고 전부 지워보겠다. +``` +ConcurrenctControl 5702 +Intro ... +SQL ... +Optimizer ... +Transaction 5545 +``` +* 편의상 위의 title외에 다른 title은 없다고 가정하자. +* 이제 DB는 index_title 테이블에서 2개의 데이터만 찾아보면 되며, 심지어 문자열 순으로 정렬까지 되어있기 때문에 더욱 빠르게 ‘Transaction’ 이라는 문자열을 수 있다. +#### 코쿼 멤버스를 찾아보자. +* 코쿼가 잘 되어가지고 졸업생이 1만 명이라고 치자. +``` +rowid name category location +1 Jane 2021 startup +2 Sigrid 2020 ROKAF +3 Han 2020 startup +4 Hamill 2020 NAVER +... +99 Dion 2020 KAKAO +... +101 노을 2021 startup +632 Solar 2020 startup +``` +* 어떤 리쿠르터가 2020 멤버스만 다 찾아보려고 한다고 치자 +``` +SELECT name, location +FROM book_store +WHERE category = '2020' +``` +결과는? +``` +name location +Sigrid ROKAF +Han Startup +Hamill NAVER +Dion KAKAO +Solar startup +``` +* 현재 인덱스가 없기 때문에, 10000개의 데이터를 모두 뒤져서 결과를 찾았을 것이다 (== full scan) +* 인덱스를 만들어보자! + * category를 기준으로 데이터를 찾고있기 때문에, category를 기준으로 정렬해주자. + * 그리고 DB가 쉽게 찾아갈 수 있도록 rowid를 같이 넣어주자. 이 때, 다른 컬럼까지 모두 인덱스에 넣어버리면 결국 원본 테이블과 내용이 똑같아져 공간 낭비이므로, rowid만 넣어주는 것이다. +``` +category id +2020 2 +2020 3 +2020 632 +... +2021 1 +2021 101 +``` +* 인덱스는 문자열 순서대로 정렬되어있기 때문에, ‘2020’ 라는 문자열을 계속 검색하다가 ‘2021’ 라는 문자열을 만나는 순간 이제 더이상 ‘2020’ 라는 문자열을 존재하지 않는다고 단정짓고 탐색을 종료할 수 있다. +* rowid가 주어지면 DB는 해당 데이터의 위치가 어디있는지 일일이 찾지 않아도 rowid를 통해 바로 접근할 수 있다. +* 내부적으로 데이터를 B-Tree라는 구조에 저장하기 때문에, ‘java’라는 문자열을 찾아낼 때 맨 처음부터 순차적으로 조회하는 것 보다 훨씬 빠르다. +* 그렇게 인덱스에서 찾아낸 rowid를 기준으로 쿼리를 날리면 된다. +``` +SELECT name, location +FROM codesquad_alumni +WHERE rowid IN (2, 3, ..., 632) + +``` +### 실제 사용 시에는 +실제 사용시에는 이러한 일련의 과정을 사용자가 직접 입력할 필요 없이 다음과 같이 인덱스를 생성해 놓으면 내부적으로 알아서 작동한다. +``` +CREATE INDEX graduate_year ON codesquad_alumni(category) + +``` +위와 같이 book_store 테이블의 category 컬럼에 index_category라는 인덱스를 생성한 후, 기존과 똑같이 사용하면 된다. + +``` +SELECT name, location +FROM codesquad_alumni +WHERE category = '2020' +``` +## 참고 + +https://itholic.github.io/database-index/ From 1d30cfc8ea9117efc496813ed06b09ca13757e53 Mon Sep 17 00:00:00 2001 From: 102092 Date: Sun, 4 Jul 2021 21:21:38 +0900 Subject: [PATCH 036/142] Add btree vs b+tree --- database/btree-vs-b+tree/han/README.md | 114 +++++++++++++++++++++++++ 1 file changed, 114 insertions(+) create mode 100644 database/btree-vs-b+tree/han/README.md diff --git a/database/btree-vs-b+tree/han/README.md b/database/btree-vs-b+tree/han/README.md new file mode 100644 index 0000000..77b0ff5 --- /dev/null +++ b/database/btree-vs-b+tree/han/README.md @@ -0,0 +1,114 @@ +# B tree, B+tree 란? +- 데이터 베이스의 인덱스를 구성하는 자료구조를 말함. +- 왜 공부해야할까? + - 어떻게 구성되어있는 지 이해하면, 인덱스 생성 및 사용에 이해도가 좀 더 높아지지 않을까. + +# B tree +- 핵심은 데이터가 **정렬** 된 상태로 트리 형태로 저장하고 있다는 점. +- Binary Search Tree랑 헷갈릴 수도 있음. + - B tree의 경우, Binary Search Tree와는 다르게, 자식 노드를 2개이 상 갖는 것이 가능. + - 그래서 B tree는 Binary Search Tree에서 비롯된 타입이라 볼 수 있음. +- 여러개의 key, value 값을 하나의 노드에 가지고 있고, key 를 중심으로 오름차순 정렬되어있음. + - 데이터베이스에서 key는 PK, 혹은 indexed column of row를 의미하고, + - value는 실제 record 값일 수도 혹은 참조하고 있는 값일 수도 있음. + - 노드란? + ![](https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqycZ2%2FbtqBQnr4QYG%2F7J8KpnmNaJiTjgS0K9TEIK%2Fimg.png) + - 위 그림에서 하나하나를 모두 노드라고 지칭 + - 다만 단계별로 Root, Brach, Leaf로 나뉘어서 부른다. + +## 페이지 란? +> .. the smallest unit of data that is exchanged/stored. + +- 데이터베이스에 저장되는 가장 작은 단위나 데이터를 일컫는 말인듯. +- InnoDB 에서 기본적으로 페이지 사이즈는 **16KB** +- 참고 + - https://stackoverflow.com/questions/4401910/mysql-what-is-a-page + +## 노드에 대해서 좀 더 알아보자 +- B tree를 만족하기 위한 노드 조건 + ``` +the nodes in a B-tree of order m can have a maximum of m children +each internal node (non-leaf and non-root) can have at least (m/2) children (rounded up) +the root should have at least two children – unless it’s a leaf +a non-leaf node with k children should have k-1 keys +all leaves must appear on the same level +``` +- 최대 M개 자식을 가질수 있는 B tree를 M차 B tree라고 함. + +- 노드들은 항상 그들의 자식노드들을 참고 하고 있으며, 이러한 참조는 해당 page ID임. + - pointer의 느낌 +- 또한 노드안에 있는 데이터는 반드시 **정렬** 된 상태 + +## 어떻게 B tree가 만들어질까? +![](https://www.baeldung.com/wp-content/uploads/sites/4/2020/05/btree1-1.png) +1. root 노드를 생성한다. + - 해당 노드는 key/value pair로 구성되며, key = 1, value는 *로 묘사한다. + - *의 의미는, 다른 레코드를 참조함을 의미한다. + - root 노드는 왼쪽, 오른쪽 서브트리로 갈 수 있는 pointer를 가지고 있다. + +![](https://www.baeldung.com/wp-content/uploads/sites/4/2020/05/btree2-1.png) +2. 2라는 key를 가진 노드를 추가한다. + - 현재 노드들은 key값을 기준으로 오름차순 정렬되어 있다. + +![](https://www.baeldung.com/wp-content/uploads/sites/4/2020/05/btree3-1.png) +3. 3이라는 key를 가진 노드를 추가한다. + - 이순간 b tree는 split operation 이라고 불리는 행위를 실행한다. + - 이 과정을 통해, left, middle , right node가 결정된다. + - 처음 root 노드는 1 키를 가지고 있는 노드 였지만, 2 키를 가지고 있는 노드로 바뀌었다. + +![](https://www.baeldung.com/wp-content/uploads/sites/4/2020/05/btree4-1-768x300-1.png) +4. 4라는 키를 가진 노드를 삽입한다. + - 이상태에서 B tree는 구조가 잡혀있기 때문에.. (3개이상의 노드가 삽입되었기 때문에) + - 해당 키 값이 root노드보다 큰지 작은지 판단할 수 있다. (현재는 크다.) + - right sub tree에 추가되고, right에 있는 노드들의 키값을 기준으로 오름차순 정렬된다. + +![](https://www.baeldung.com/wp-content/uploads/sites/4/2020/05/btree5-1-768x288-1.png) +5. 5라는 키를 가진 노드를 삽입한다. + - root 노드 + 1 갯수를 초과하여, child 노드가 구성되어질 수 없기 때문에.. + - 리밸랜생이 일어난다. + +![](https://www.baeldung.com/wp-content/uploads/sites/4/2020/05/btree6-2.png) +6. 6 노드를 삽입한다. + +![](https://www.baeldung.com/wp-content/uploads/sites/4/2020/05/btree7-1-1024x471-1.png) +7. 7 노드 삽입 + - 하는 순간 조건을 1번조건 만족시키기 위해 리밸랜싱 일어남 (현재 M=2, 하나의 노드는 최대 2개까지 자식노드를 가질 수 있음.) + - 오른쪽 서브 트리에서 하나를 상위로 올리게 되면.... (a non-leaf node with k children should have k-1 keys) 이 조건을 어기게됨. + - 그래서 우선 오른쪽 서브 트리에서.. 리밸랜싱 일어남. + - all leaves must appear on the same level를 만족시키기 위해 나머지 왼쪽 서브트리에서도 리밸랜싱.. + +![](https://www.baeldung.com/wp-content/uploads/sites/4/2020/05/btreefull-3.png) +8. 8, 9 노드 삽입 + - 8 노드를 삽입하면, 7 오른쪽에 붙었다가.. (each internal node (non-leaf and non-root) can have at least (m/2) children (rounded up)), 에 의거해 최대 2개까지 자식 노드를 가질 수 있으니.. 리밸랜싱 + +- insert, delete 과정 참고 + - https://cieske.tistory.com/60 + - https://www.cs.usfca.edu/~galles/visualization/BTree.html + + +# B+Tree +- B tree와 비교되는 가장 큰 차이점 + 1. 모든 leaf nodes 는 서로 연결되어 있음 (doubly linked list) + 2. internal node는 라우터처럼 leaf node 로 가는 중간다리 역할만 할 뿐이고, 실제 데이터가 저정되어 있는 page id 값은 leaf node 에만 저장이 된다. + +![](https://www.baeldung.com/wp-content/uploads/sites/4/2020/05/bplustreefull-2.png) +- 2,4 key가 중복됨을 볼 수가 있음. (interanl, leaf) +- 왜냐면 internal node는 satelite data를 가지고 있을 수 없기 때문에 +- leaf 노드는 반드시 key/value pair형태를 지니고 있어야함. + +## B+tree에서 검색은 어떻게 이루어지는가? +![](https://www.baeldung.com/wp-content/uploads/sites/4/2020/05/bplustreeSearch-1.png) +- Data는 leaf 노드에 저장됨을 알아야함. +- 즉 검색하고자 하는 key를 알고 있으면, root -> internal -> leaf 까지 내려가서 데이터를 찾을 수 있다는 뜻 + - 반면 btree는 root, interanl node에서도 데이터를 가지고 있다. +- B+trees는 range query 를 지원한다. + - 참고 + - https://cs.stackexchange.com/questions/90961/how-a-range-query-works-on-a-simple-btree + +# 참고 +- https://www.baeldung.com/cs/b-trees-vs-btrees +- https://zorba91.tistory.com/293 +- https://hyungjoon6876.github.io/jlog/2018/07/20/btree.html +- https://ko.wikipedia.org/wiki/B_%ED%8A%B8%EB%A6%AC +- https://www.geeksforgeeks.org/introduction-of-b-tree-2/ +- 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 From 2dcf07e1d994bc15272bc1c0af499aabb5c64f10 Mon Sep 17 00:00:00 2001 From: 102092 Date: Sun, 4 Jul 2021 21:21:49 +0900 Subject: [PATCH 037/142] Add btree vs b+tree --- database/btree-vs-b+tree/han/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/database/btree-vs-b+tree/han/README.md b/database/btree-vs-b+tree/han/README.md index 77b0ff5..1cc5dc7 100644 --- a/database/btree-vs-b+tree/han/README.md +++ b/database/btree-vs-b+tree/han/README.md @@ -90,6 +90,8 @@ all leaves must appear on the same level - B tree와 비교되는 가장 큰 차이점 1. 모든 leaf nodes 는 서로 연결되어 있음 (doubly linked list) 2. internal node는 라우터처럼 leaf node 로 가는 중간다리 역할만 할 뿐이고, 실제 데이터가 저정되어 있는 page id 값은 leaf node 에만 저장이 된다. +- internal node에 더 많은 key를 저장할 수 있다 (왜나면 키 외 다른 데이터는 저장하지 않으니까..) + - 이는 B+tree의 height가 Btree보다 낮음을 의미한다. ![](https://www.baeldung.com/wp-content/uploads/sites/4/2020/05/bplustreefull-2.png) - 2,4 key가 중복됨을 볼 수가 있음. (interanl, leaf) From 84432f809d01a2fa9cd538996a3e98a5e5e1c530 Mon Sep 17 00:00:00 2001 From: 102092 Date: Sun, 4 Jul 2021 21:55:04 +0900 Subject: [PATCH 038/142] Add transaction --- database/transaction-basic/han/REAMDE.md | 72 ++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 database/transaction-basic/han/REAMDE.md diff --git a/database/transaction-basic/han/REAMDE.md b/database/transaction-basic/han/REAMDE.md new file mode 100644 index 0000000..ed0bcc9 --- /dev/null +++ b/database/transaction-basic/han/REAMDE.md @@ -0,0 +1,72 @@ +# 트랜잭션이란? +- 데이터를 올바르게 보장하기 위해 고안된 방법 +- Database에 한정된 용어가 아님. + - 트랜잭션 이론 자체는 독립적인 이론이라 볼 수 있음 +- 데이터베이스 에서 트랜잭션은 2가지를 보장하기 위해 사용됨. + 1. 믿을수있는 작업 단위를 보장하기 위해 + - 작업 실패로 안한 정확한 복구를 허용하고, + - 실패를 하더라도 데이터베이스 시스템이 지속되어 운영되도록 보장해줌. + 2. 커밋 간에 독립적인 환경을 제공해주기 위해. +- 트랜잭션과 관계형 모델은 다른 이론. + - 그렇지만 데이터를 올바르게 보장하기 위해서, 양쪽 다 필요하는 상호보완적인 관계라 볼 수 있음. + +# 트랜잭션은 어떻게 작동하는가? +- 굉장히 복잡한 문제 +- 데이터베이스에서 보장해주는 레벨등에 따라 다를 수 있음. +- 스프링에서 `@Transaciotnal` 이 어떻게 작동할까..? + - 참고 : https://stackoverflow.com/questions/1099025/spring-transactional-what-happens-in-background + +# 트랜잭션 기능 +1. 동시 실행 제어 + - 데이터에 동시 엑세스하여 부정합이 일어나는 막음. +2. 크래시 복구 + - 예상하지 못한 사태가 일어났어도, 데이터는 올바르게 유지되도록 도와준다. + - 즉 트랜잭션 도중에.. 데이터 변경이 일어나고 해당 트랜잭션이 정상적으로 닫히지 않은 상태에서 프로그램이 비정상적으로 종료된다면.. 해당 트랜잭션은 롤백되며 데이터에 변화가 없도록 도와준다. + +## 부정합이 일어나지 않으려면..? +- 프로세스를 하나씩 차례대로 수행하도록 하면 됨. +- 다만, 위와 같은 방법은 처리 효율이 낮다. + - 왜? 병렬 처리를 하지 못하기 때문에. +- 수천개의 트랜잭션이 동시에 실행될 수도 있는데, 이 경우 순차적으로 실행하게 하는건 현실적이지 못할듯. + +## 그래서 나온 것이 스케쥴 관리 +- 트랜잭션의 일련의 과정을 나눔 + - 데이터 읽기, 쓰기로 +- 즉 처리 내용에 따라 다른 트랜잭션에 영향을 미치는 것이 있음 (쓰기 작업) + - 이런 작업이 언제 일어날 것인지, 스케쥴을 잘 짤 수 있다면.. 병렬 환경에서의 트랜잭션 효율이 올라가지 않을까? + +## 데이터의 정확성이란? +- 데이터가 올바르게 유지되는 상태 +- 개별 트랜잭션을 한 개씩 차례로 실행될 떄 나오는 결과 +- 즉 병렬적으로 스케쥴 하에서 실행되는 트랜잭션들을 통해 나온 데이터와, 순차적으로 트랜잭션들이 실행되어 나온 데이터가 같다면, 이 말은 데이터가 **올바르게** 유지되었다고 말할 수 있을 것임. + +# 트랜잭션의 특징 +- ACID +- 원자성 Atomicity + - 트랜잭션이 어중간하지 않게 도와준다. + - 즉 트랜잭션의 결과는 성공 아니면 실패 둘 중 하나밖에 없다. + - 그리고 실패했을 경우, 롤백 될 수 있음을 의미한다. + +- 일관성 Consistensy + - 트랜잭션을 실시한 전후에, 데이터가 일관성이 있어야한다. (데이터에 부정합이 없어야한다. + - 일관성이 있는지 없는지는 응용프로그램이 판단한다. + +- 격리성 Isolation + - 동시에 여러개의 트랜잭션이 실행 되었을 때, 트랜잭션 끼리는 서로 영향을 주지 않는다. + - 1,2,3라는 트랜잭션이 있고, A라는 데이터에 접근되어 실행된다고 할 때, 이러한 트랜잭션이 개밸젹, 순차적으로 실행된 것과 병렬적으로 실행된 것의 결과는 같아야한다. + +- 영속성 Durability + - 일단 커밋이 완료된 트랜잭션은 손상되지 않는다. + - 즉 트랜잭션이 완료되어, 데이터베이스에 변경이 일어났다면, 이러한 변경은 영구적으로 저장되어야 한다는 의미. + +# 더 알아보기 +- 스프링에서 사용되는 트랜잭션 + - https://www.baeldung.com/transaction-configuration-with-jpa-and-spring + - https://www.baeldung.com/spring-transactional-propagation-isolation +- 트랜잭션에서 발생해서는 안되는 상태들..? + - Inconsistent read, Dirty read, Non Repepeable read... + +# 참고 +- 관계형 데이터베이스 실전 입문 14장 +- https://en.wikipedia.org/wiki/Database_transaction#:~:text=A%20database%20transaction%20symbolizes%20a,any%20change%20in%20a%20database +- https://victorydntmd.tistory.com/129 \ No newline at end of file From 5836bf71a3aa5208e26f56ee942d190ecab66d22 Mon Sep 17 00:00:00 2001 From: Jin Hyung Park Date: Mon, 5 Jul 2021 01:53:13 +0900 Subject: [PATCH 039/142] move file directory --- database/index-basic/sigrid/sigrid_index.md | 122 ++++++++++++++++++++ 1 file changed, 122 insertions(+) create mode 100644 database/index-basic/sigrid/sigrid_index.md diff --git a/database/index-basic/sigrid/sigrid_index.md b/database/index-basic/sigrid/sigrid_index.md new file mode 100644 index 0000000..0f72df6 --- /dev/null +++ b/database/index-basic/sigrid/sigrid_index.md @@ -0,0 +1,122 @@ +# Database 7월 1주차 +### Index란 무엇인가? +#### 도입 +* 내가 데이터베이스 서적을 보고 있다고 치자. 그런데 이 DB 책이 한 1만 페이지 정도 된다고 가정해보자고. 내가 여기서 Index에 대한 설명을 찾고 싶다 라고 치면은 이걸 1만 페이지 내내 넘겨보면서 찾겠냐? 그건 절대 불가능하다. +* 물론 목차라는 것이 있지. 목차는 주로 중요한 Theme별로 서술이 되어 있다라는 거지. 그런데 말이야, 내가 이 저자가 Index를 얼마나 중요하게 생각하는 지 어떻게 알깜? Index 라는 단.어.를 목차에서 찾는 것도 졸라 빡시겠지? +* 그래서 보통 두꺼운 책은 책 맨 뒤에 색인이라는 게 있지. ABC 색인, 가나다 색인, 뭐 성경 목차에 따른 색인(토라 5경이 먼저 나오고...) 이런 식으로. 여기서 색인은 정확히 데이터베이스의 인덱스와 일치하는 개념이다. +* 예를 들어 내가 다음의 서적에서 Index를 찾는다고 가정하자. + ``` +1 Intro +2 Intro +3 Intro +512 SQL +513 SQL +5544 Optimizer +5545 Transaction +5546 Transaction +5547 Transaction +5700 Transaction +5701 Transaction +5702 ConcurrenctControl +5703 ConcurrenctControl +``` + +* 여기서 Transaction은 5545~5700까지 저장되어 있다. +* 이걸 쿼리로 찾아서 뒤져보려면 푸하하 전부 다 뒤져보면 된다. 브루트 포스다 ㅋㅋㅋ +``` +SELECT page +FROM db_book +WHERE title = 'Transaction'; +``` +* DB는 일단 5545번에 당도하더라도 뒤에 Transaction 관련된 DB가 더 있을 것이라고 생각한다. 그리고 실제로도 더 있다. 인간이라면 5545번을 찾고, 아 여기서부터가 Transaction이겠거니 생각하는데 컴퓨터는 멍청해서 다 뒤져본다. (그리고 실제로 갑자기 8000번부터 또 Transaction 파트 II 이거면 어떡할래?) +* 우리는 이러한 멍청한 방식을 Full Scan이라고 부른다. +#### 인덱스 만들어보기 +* 인덱스도 결국엔 하나의 테이블이다. index_title 이라는 이름의 테이블을 만들자. +* 우선 ‘Transaction’ 이라는 키워드를 쉽게 찾을 수 있도록 abc 순으로 정렬하면 좋을 것 같다. +``` +ConcurrenctControl 5702 +ConcurrenctControl 5703 +Transaction 5545 +Transaction 5546 +Transaction 5547 +Transaction 5700 +Transaction 5701 +``` +* 중복된 내용은 해당 내용의 가장 첫 번째 페이지만 남기고 전부 지워보겠다. +``` +ConcurrenctControl 5702 +Intro ... +SQL ... +Optimizer ... +Transaction 5545 +``` +* 편의상 위의 title외에 다른 title은 없다고 가정하자. +* 이제 DB는 index_title 테이블에서 2개의 데이터만 찾아보면 되며, 심지어 문자열 순으로 정렬까지 되어있기 때문에 더욱 빠르게 ‘Transaction’ 이라는 문자열을 수 있다. +#### 코쿼 멤버스를 찾아보자. +* 코쿼가 잘 되어가지고 졸업생이 1만 명이라고 치자. +``` +rowid name category location +1 Jane 2021 startup +2 Sigrid 2020 ROKAF +3 Han 2020 startup +4 Hamill 2020 NAVER +... +99 Dion 2020 KAKAO +... +101 노을 2021 startup +632 Solar 2020 startup +``` +* 어떤 리쿠르터가 2020 멤버스만 다 찾아보려고 한다고 치자 +``` +SELECT name, location +FROM book_store +WHERE category = '2020' +``` +결과는? +``` +name location +Sigrid ROKAF +Han Startup +Hamill NAVER +Dion KAKAO +Solar startup +``` +* 현재 인덱스가 없기 때문에, 10000개의 데이터를 모두 뒤져서 결과를 찾았을 것이다 (== full scan) +* 인덱스를 만들어보자! + * category를 기준으로 데이터를 찾고있기 때문에, category를 기준으로 정렬해주자. + * 그리고 DB가 쉽게 찾아갈 수 있도록 rowid를 같이 넣어주자. 이 때, 다른 컬럼까지 모두 인덱스에 넣어버리면 결국 원본 테이블과 내용이 똑같아져 공간 낭비이므로, rowid만 넣어주는 것이다. +``` +category id +2020 2 +2020 3 +2020 632 +... +2021 1 +2021 101 +``` +* 인덱스는 문자열 순서대로 정렬되어있기 때문에, ‘2020’ 라는 문자열을 계속 검색하다가 ‘2021’ 라는 문자열을 만나는 순간 이제 더이상 ‘2020’ 라는 문자열을 존재하지 않는다고 단정짓고 탐색을 종료할 수 있다. +* rowid가 주어지면 DB는 해당 데이터의 위치가 어디있는지 일일이 찾지 않아도 rowid를 통해 바로 접근할 수 있다. +* 내부적으로 데이터를 B-Tree라는 구조에 저장하기 때문에, ‘java’라는 문자열을 찾아낼 때 맨 처음부터 순차적으로 조회하는 것 보다 훨씬 빠르다. +* 그렇게 인덱스에서 찾아낸 rowid를 기준으로 쿼리를 날리면 된다. +``` +SELECT name, location +FROM codesquad_alumni +WHERE rowid IN (2, 3, ..., 632) + +``` +### 실제 사용 시에는 +실제 사용시에는 이러한 일련의 과정을 사용자가 직접 입력할 필요 없이 다음과 같이 인덱스를 생성해 놓으면 내부적으로 알아서 작동한다. +``` +CREATE INDEX graduate_year ON codesquad_alumni(category) + +``` +위와 같이 book_store 테이블의 category 컬럼에 index_category라는 인덱스를 생성한 후, 기존과 똑같이 사용하면 된다. + +``` +SELECT name, location +FROM codesquad_alumni +WHERE category = '2020' +``` +## 참고 + +https://itholic.github.io/database-index/ From 7edc5870312b3c9242e4de8e4e6bb4dbb4d166be Mon Sep 17 00:00:00 2001 From: Jin Hyung Park Date: Mon, 5 Jul 2021 02:05:28 +0900 Subject: [PATCH 040/142] =?UTF-8?q?feat:=20B-Tree=20=EA=B0=9C=EC=9A=94=20?= =?UTF-8?q?=ED=95=99=EC=8A=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- database/btree-vs-b+tree/B-Tree.md | 40 +++++++++ database/index-basic/sigrid_index.md | 122 --------------------------- 2 files changed, 40 insertions(+), 122 deletions(-) create mode 100644 database/btree-vs-b+tree/B-Tree.md delete mode 100644 database/index-basic/sigrid_index.md diff --git a/database/btree-vs-b+tree/B-Tree.md b/database/btree-vs-b+tree/B-Tree.md new file mode 100644 index 0000000..cf4fd2b --- /dev/null +++ b/database/btree-vs-b+tree/B-Tree.md @@ -0,0 +1,40 @@ +## B-Tree + +### 개요 + +* 이진 트리는 하나의 부모가 두 개의 자식을 갖는다. 구조가 간결해서 균형이 맞으면 ```OlogN``` 의 복잡도를 갖는다. + +* 하지만 균형이 맞지 않으면 선형탐색 급의 검색 효율을 갖는다. + +* B-Tree는 이진 트리를 확장한 것으로, 더 많은 자식을 가질 수 있도록 일반화한 것이다. + + * B-Tree는 자식 노드의 개수가 2개 이상인 트리를 말한다. + * B-Tree는 노드 내의 데이터가 1개 이상일 수 있다. + * 노드 내 최대 데이터 수가 2개이면 2차 B-Tree라고 부른다. + * B-Tree는 노드의 데이터 수가 n개라면 자식 노드의 개수는 (n+1) 개이다. + + ![btree조건](https://hyungjoon6876.github.io/jlog/assets/img/20180720/btree_1.png) + + * 노드의 데이터 수가 root에 3개이므로, 자식 노드의 개수는 4개이다. + + * 노드 내부의 데이터는 정렬되어 있어야 한다. + + * ```3 1 4``` 가 아니라 ```1 3 4``` 이어야 한다. + + * 노드의 자식 노드 데이터들은 노드 데이터를 기준으로 데이터보다 작은 값은 왼쪽 서브트리에, 큰 값은 오른쪽 서브트리에 이루어져야 한다. 이는 이진 트리와 동일한 논리이다. + + ![btree조건](https://hyungjoon6876.github.io/jlog/assets/img/20180720/btree_3.png) + + * Root 노드를 제외한 모든 M차 B-Tree의 노드는 적어도 M/2개의 데이터를 갖고 있어야 한다. + + ![btree조건](https://hyungjoon6876.github.io/jlog/assets/img/20180720/btree_4.png) + + * 다음과 같은 4차 B-Tree에서 Root 노드의 데이터 8의 왼쪽 서브트리 노드가 데이터가 1개이므로 조건에 부합하지 않는다. + + * `Leaf` 노드로 가는 경로의 길이는 모두 같아야 한다. 즉 `Leaf` 노드는 모두 같은 레벨에 존재해야 한다. + + ![btree조건](https://hyungjoon6876.github.io/jlog/assets/img/20180720/btree_5.png) + +### 참고 + +* https://hyungjoon6876.github.io/jlog/2018/07/20/btree.html \ No newline at end of file diff --git a/database/index-basic/sigrid_index.md b/database/index-basic/sigrid_index.md deleted file mode 100644 index 0f72df6..0000000 --- a/database/index-basic/sigrid_index.md +++ /dev/null @@ -1,122 +0,0 @@ -# Database 7월 1주차 -### Index란 무엇인가? -#### 도입 -* 내가 데이터베이스 서적을 보고 있다고 치자. 그런데 이 DB 책이 한 1만 페이지 정도 된다고 가정해보자고. 내가 여기서 Index에 대한 설명을 찾고 싶다 라고 치면은 이걸 1만 페이지 내내 넘겨보면서 찾겠냐? 그건 절대 불가능하다. -* 물론 목차라는 것이 있지. 목차는 주로 중요한 Theme별로 서술이 되어 있다라는 거지. 그런데 말이야, 내가 이 저자가 Index를 얼마나 중요하게 생각하는 지 어떻게 알깜? Index 라는 단.어.를 목차에서 찾는 것도 졸라 빡시겠지? -* 그래서 보통 두꺼운 책은 책 맨 뒤에 색인이라는 게 있지. ABC 색인, 가나다 색인, 뭐 성경 목차에 따른 색인(토라 5경이 먼저 나오고...) 이런 식으로. 여기서 색인은 정확히 데이터베이스의 인덱스와 일치하는 개념이다. -* 예를 들어 내가 다음의 서적에서 Index를 찾는다고 가정하자. - ``` -1 Intro -2 Intro -3 Intro -512 SQL -513 SQL -5544 Optimizer -5545 Transaction -5546 Transaction -5547 Transaction -5700 Transaction -5701 Transaction -5702 ConcurrenctControl -5703 ConcurrenctControl -``` - -* 여기서 Transaction은 5545~5700까지 저장되어 있다. -* 이걸 쿼리로 찾아서 뒤져보려면 푸하하 전부 다 뒤져보면 된다. 브루트 포스다 ㅋㅋㅋ -``` -SELECT page -FROM db_book -WHERE title = 'Transaction'; -``` -* DB는 일단 5545번에 당도하더라도 뒤에 Transaction 관련된 DB가 더 있을 것이라고 생각한다. 그리고 실제로도 더 있다. 인간이라면 5545번을 찾고, 아 여기서부터가 Transaction이겠거니 생각하는데 컴퓨터는 멍청해서 다 뒤져본다. (그리고 실제로 갑자기 8000번부터 또 Transaction 파트 II 이거면 어떡할래?) -* 우리는 이러한 멍청한 방식을 Full Scan이라고 부른다. -#### 인덱스 만들어보기 -* 인덱스도 결국엔 하나의 테이블이다. index_title 이라는 이름의 테이블을 만들자. -* 우선 ‘Transaction’ 이라는 키워드를 쉽게 찾을 수 있도록 abc 순으로 정렬하면 좋을 것 같다. -``` -ConcurrenctControl 5702 -ConcurrenctControl 5703 -Transaction 5545 -Transaction 5546 -Transaction 5547 -Transaction 5700 -Transaction 5701 -``` -* 중복된 내용은 해당 내용의 가장 첫 번째 페이지만 남기고 전부 지워보겠다. -``` -ConcurrenctControl 5702 -Intro ... -SQL ... -Optimizer ... -Transaction 5545 -``` -* 편의상 위의 title외에 다른 title은 없다고 가정하자. -* 이제 DB는 index_title 테이블에서 2개의 데이터만 찾아보면 되며, 심지어 문자열 순으로 정렬까지 되어있기 때문에 더욱 빠르게 ‘Transaction’ 이라는 문자열을 수 있다. -#### 코쿼 멤버스를 찾아보자. -* 코쿼가 잘 되어가지고 졸업생이 1만 명이라고 치자. -``` -rowid name category location -1 Jane 2021 startup -2 Sigrid 2020 ROKAF -3 Han 2020 startup -4 Hamill 2020 NAVER -... -99 Dion 2020 KAKAO -... -101 노을 2021 startup -632 Solar 2020 startup -``` -* 어떤 리쿠르터가 2020 멤버스만 다 찾아보려고 한다고 치자 -``` -SELECT name, location -FROM book_store -WHERE category = '2020' -``` -결과는? -``` -name location -Sigrid ROKAF -Han Startup -Hamill NAVER -Dion KAKAO -Solar startup -``` -* 현재 인덱스가 없기 때문에, 10000개의 데이터를 모두 뒤져서 결과를 찾았을 것이다 (== full scan) -* 인덱스를 만들어보자! - * category를 기준으로 데이터를 찾고있기 때문에, category를 기준으로 정렬해주자. - * 그리고 DB가 쉽게 찾아갈 수 있도록 rowid를 같이 넣어주자. 이 때, 다른 컬럼까지 모두 인덱스에 넣어버리면 결국 원본 테이블과 내용이 똑같아져 공간 낭비이므로, rowid만 넣어주는 것이다. -``` -category id -2020 2 -2020 3 -2020 632 -... -2021 1 -2021 101 -``` -* 인덱스는 문자열 순서대로 정렬되어있기 때문에, ‘2020’ 라는 문자열을 계속 검색하다가 ‘2021’ 라는 문자열을 만나는 순간 이제 더이상 ‘2020’ 라는 문자열을 존재하지 않는다고 단정짓고 탐색을 종료할 수 있다. -* rowid가 주어지면 DB는 해당 데이터의 위치가 어디있는지 일일이 찾지 않아도 rowid를 통해 바로 접근할 수 있다. -* 내부적으로 데이터를 B-Tree라는 구조에 저장하기 때문에, ‘java’라는 문자열을 찾아낼 때 맨 처음부터 순차적으로 조회하는 것 보다 훨씬 빠르다. -* 그렇게 인덱스에서 찾아낸 rowid를 기준으로 쿼리를 날리면 된다. -``` -SELECT name, location -FROM codesquad_alumni -WHERE rowid IN (2, 3, ..., 632) - -``` -### 실제 사용 시에는 -실제 사용시에는 이러한 일련의 과정을 사용자가 직접 입력할 필요 없이 다음과 같이 인덱스를 생성해 놓으면 내부적으로 알아서 작동한다. -``` -CREATE INDEX graduate_year ON codesquad_alumni(category) - -``` -위와 같이 book_store 테이블의 category 컬럼에 index_category라는 인덱스를 생성한 후, 기존과 똑같이 사용하면 된다. - -``` -SELECT name, location -FROM codesquad_alumni -WHERE category = '2020' -``` -## 참고 - -https://itholic.github.io/database-index/ From 02c81cdbb8af302424e7c23312d6b8b9bbc33897 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=B5=9C=ED=95=9C=EC=9A=B8?= Date: Mon, 5 Jul 2021 22:37:52 +0900 Subject: [PATCH 041/142] =?UTF-8?q?[6=EC=A3=BC=EC=B0=A8]=20B-tree=20vs=20B?= =?UTF-8?q?+tree?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- database/btree-vs-b+tree/hamill/README.md | 33 +++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 database/btree-vs-b+tree/hamill/README.md diff --git a/database/btree-vs-b+tree/hamill/README.md b/database/btree-vs-b+tree/hamill/README.md new file mode 100644 index 0000000..6c3e904 --- /dev/null +++ b/database/btree-vs-b+tree/hamill/README.md @@ -0,0 +1,33 @@ +# B-tree vs B+tree + +### B-tree + +B-tree는 노드가 inorder traversal로 정렬되는 자가 균형 이진 탐색 트리(self-balancing tree)로 알려져 있습니다. B-tree에서 노드는 둘 이상의 자식을 가질 수 있습니다. B-tree의 높이는 logMN 입니다. (여기서 M은 트리 순서, N은 노드 수입니다) 그리고 높이는 업데이트 할 때마다 자동으로 조정됩니다. B-tree에서 데이터는 왼쪽이 가장 낮은 값, 오른쪽이 가장 높은 값을 사용하여 특정 순서로 정렬됩니다. B-tree에 데이터나 키를 삽입하는 것은 이진 트리보다 더 복잡합니다. B-tree가 유지해야 하는 몇 가지 조건이 있습니다. + +- 모든 리프 노드는 동일한 수준에 있어야 한다. +- 리프 노드 위에는 빈 하위 트리가 없어야 한다. +- 높이는 가능한 한 낮아야 한다. + +![](https://media.geeksforgeeks.org/wp-content/uploads/20191219160544/Untitled-Diagram111.png) + +### B+tree + +B+tree는 트리의 리프 노드에만 데이터 포인터를 저장하여 인덱싱에 사용되는 B-tree의 단점을 제거합니다. 따라서 B+tree의 리프 노드 구조는 B-tree의 내부 노드 구조와 상당히 다릅니다. 데이터 포인터는 리프 노드에만 존재하기 때문에 리프 노드는 액세스하기 위해 디스크 파일 블록에 대한 해당 데이터 포인터와 함께 모든 키값을 반드시 저장해야 합니다. 또한 리프 노드는 레코드에 대한 정렬된 액세스를 제공하는데 연결됩니다(Moreover, the leaf nodes are linked to providing ordered access to the records). 따라서 리프 노드는 인덱스의 첫 번째 level을 형성하며 내부 노드는 multilevel 인덱스의 다른 level을 형성합니다. 리프 노드의 일부 주요 값은 내부 노드에도 나타나며, 단순히 레코드 검색을 제어하는 매체 역할을 합니다. + +![](https://media.geeksforgeeks.org/wp-content/uploads/Btree.jpg) + +
+ + +|No|B-tree|B+tree| +|:---|:---|:---| +|1. |모든 내부 및 리프 노드에는 데이터 포인터가 있습니다.|리프 노드에만 데이터 포인터가 있습니다.| +|2. |리프에서 모든 키를 사용 할 수 없기 때문에 검색에 더 많은 시간이 걸리는 경우가 많습니다.|모든 키는 리프 노드에 있으므로 검색이 더 빠르고 정확합니다.| +|3. |트리에서 키의 중복이 유지되지 않습니다.|중복 키가 유지되고 모든 노드가 리프에 있습니다.| +|4. |삽입에 더 많은 시간이 걸리며 때로는 예측 할 수 없습니다.|삽입이 더 쉽고 결과는 항상 동일합니다.| +|5. |내부 노드의 삭제는 매우 복잡하고 트리는 많은 변형을 거쳐야합니다.|모든 노드가 리프에서 발견되기 때문에 모든 노드의 삭제가 쉽습니다.| +|6. |리프 노드는 구조적(structural) 연결리스트로 저장되지 않습니다.|리프 노드는 구조적 연결리스트로 저장됩니다.| +|7. |중복 검색 키가 없습니다.|중복 검색 키가 있을 수 있습니다.| + +### 출처 +- https://www.geeksforgeeks.org/difference-between-b-tree-and-b-tree/ \ No newline at end of file From 338c500726bda2913278643d86a119b39ca41a8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=B5=9C=ED=95=9C=EC=9A=B8?= Date: Mon, 5 Jul 2021 23:01:33 +0900 Subject: [PATCH 042/142] =?UTF-8?q?[6=EC=A3=BC=EC=B0=A8]=20Transaction=20b?= =?UTF-8?q?asic?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- database/transaction-basic/hamill/README.md | 57 +++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 database/transaction-basic/hamill/README.md diff --git a/database/transaction-basic/hamill/README.md b/database/transaction-basic/hamill/README.md new file mode 100644 index 0000000..06d50c8 --- /dev/null +++ b/database/transaction-basic/hamill/README.md @@ -0,0 +1,57 @@ +# 데이터베이스에서 사용되고 있는 트랜잭션이란 무엇이고, 어떻게 동작하는가? + +### 트랜잭션 + +트랜잭션은 데이터베이스의 상태를 변환시키는 하나의 논리적 기능을 수행하기 위한 작업의 단위 또는 한 꺼번에 모두 수행되어야 할 일련의 연산들을 의미한다. + +### 트랜잭션 특징 + +1. 트랜잭션은 데이터베이스 시스템에서 병행 제어 및 회복 작업 시 처리되는 작업의 논리적 단위이다. +2. 사용자가 시스템에 대한 서비스 요구 시 시스템이 응답하기 위한 상태 변환 과정의 작업 단위이다. +3. 하나의 트랜잭션은 Commit 되거나 Rollback 된다. + +### 트랜잭션의 성질 + +**Atomicity 원자성** + +1. 트랜잭션의 연산은 데이터베이스에 모두 반영되든지 아니면 전혀 반영되지 않아야 한다. +2. 트랜잭션 내의 모든 명령은 반드시 완벽히 수행되어야 하며, 모두가 완벽히 수행되지 않고 어느 하나라도 오류가 발생하면 트랜잭션 전부가 취소되어야 한다. + +**Consitency 일관성** + +1. 트랜잭션이 그 실행을 성공적으로 완료하면 언제나 일관성 있는 데이터베이스 상태로 변환한다. +2. 시스템이 가지고 있는 고정 요소는 트랜잭션 수행 전과 트랜잭션 수행 완료 후의 상태가 같아야 한다. + +**Isolation 독립성, 격리성** + +1. 둘 이상의 트랜잭션이 동시에 병행 실행되는 경우 어느 하나의 트랜잭션 실행 중에 다른 트랜잭션의 연산이 끼어들 수 없다. +2. 수행중인 트랜잭션은 완전히 완료될 때까지 다른 트랜잭션에서 수행 결과를 참조할 수 없다. + +**Durability 영속성, 지속성** + +1. 성공적으로 완료된 트랜잭션의 결과는 시스템이 고장나더라도 영구적으로 반영되어야 한다. + +### 트랜잭션 연산 + +**Commit 연산** + +1. Commit 연산은 한 개의 논리적 단위(트랜잭션)에 대한 작업이 성공적으로 끝났고 데이터베이스가 다시 일관된 상태에 있을 때, 이 트랜잭션이 행한 갱신 연산이 완료된 것을 트랜잭션 관리자에게 알려주는 연산이다. + +**Rollback 연산** + +1. Rollback 연산은 하나의 트랜잭션 처리가 비정상적으로 종료되어 데이터베이스의 일관성을 깨뜨렸을 때, 이 트랜잭션의 일부가 정상적으로 처리되었더라도 트랜잭션의 원자성을 구현하기 위해 이 트랜잭션이 행한 모든 연산을 취소(Undo)하는 연산이다. +2. Rollback 시에는 해당 트랜잭션을 재시작하거나 폐기한다. + +### 트랜잭션 상태 + +![](https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F999C55345B6D2ED308) + +- 활동 (Active) : 트랜잭션이 실행중인 상태 +- 실패 (Failed) : 트랜잭션 실행에 오류가 발생하여 중단된 상태 +- 철회 (Aborted) : 트랜잭션이 비정상적으로 종료되어 Rollback 연산을 수행한 상태 +- 부분 완료 (Partially Committed) : 트랜잭션의 마지막 연산까지 실행했지만, Commit 연산이 실행되기 직전의 상태 +- 완료 (Committed) : 트랜잭션이 성공적으로 종료되어 Commit 연산을 실행한 후의 상태 + +### 출처 + +- [https://coding-factory.tistory.com/226](https://coding-factory.tistory.com/226) \ No newline at end of file From c60f1974927380b900b83d6a81beb26c4b54e1e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=B5=9C=ED=95=9C=EC=9A=B8?= Date: Mon, 5 Jul 2021 23:01:33 +0900 Subject: [PATCH 043/142] =?UTF-8?q?Revert=20"[6=EC=A3=BC=EC=B0=A8]=20Trans?= =?UTF-8?q?action=20basic"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 338c500726bda2913278643d86a119b39ca41a8a. --- database/transaction-basic/hamill/README.md | 57 --------------------- 1 file changed, 57 deletions(-) delete mode 100644 database/transaction-basic/hamill/README.md diff --git a/database/transaction-basic/hamill/README.md b/database/transaction-basic/hamill/README.md deleted file mode 100644 index 06d50c8..0000000 --- a/database/transaction-basic/hamill/README.md +++ /dev/null @@ -1,57 +0,0 @@ -# 데이터베이스에서 사용되고 있는 트랜잭션이란 무엇이고, 어떻게 동작하는가? - -### 트랜잭션 - -트랜잭션은 데이터베이스의 상태를 변환시키는 하나의 논리적 기능을 수행하기 위한 작업의 단위 또는 한 꺼번에 모두 수행되어야 할 일련의 연산들을 의미한다. - -### 트랜잭션 특징 - -1. 트랜잭션은 데이터베이스 시스템에서 병행 제어 및 회복 작업 시 처리되는 작업의 논리적 단위이다. -2. 사용자가 시스템에 대한 서비스 요구 시 시스템이 응답하기 위한 상태 변환 과정의 작업 단위이다. -3. 하나의 트랜잭션은 Commit 되거나 Rollback 된다. - -### 트랜잭션의 성질 - -**Atomicity 원자성** - -1. 트랜잭션의 연산은 데이터베이스에 모두 반영되든지 아니면 전혀 반영되지 않아야 한다. -2. 트랜잭션 내의 모든 명령은 반드시 완벽히 수행되어야 하며, 모두가 완벽히 수행되지 않고 어느 하나라도 오류가 발생하면 트랜잭션 전부가 취소되어야 한다. - -**Consitency 일관성** - -1. 트랜잭션이 그 실행을 성공적으로 완료하면 언제나 일관성 있는 데이터베이스 상태로 변환한다. -2. 시스템이 가지고 있는 고정 요소는 트랜잭션 수행 전과 트랜잭션 수행 완료 후의 상태가 같아야 한다. - -**Isolation 독립성, 격리성** - -1. 둘 이상의 트랜잭션이 동시에 병행 실행되는 경우 어느 하나의 트랜잭션 실행 중에 다른 트랜잭션의 연산이 끼어들 수 없다. -2. 수행중인 트랜잭션은 완전히 완료될 때까지 다른 트랜잭션에서 수행 결과를 참조할 수 없다. - -**Durability 영속성, 지속성** - -1. 성공적으로 완료된 트랜잭션의 결과는 시스템이 고장나더라도 영구적으로 반영되어야 한다. - -### 트랜잭션 연산 - -**Commit 연산** - -1. Commit 연산은 한 개의 논리적 단위(트랜잭션)에 대한 작업이 성공적으로 끝났고 데이터베이스가 다시 일관된 상태에 있을 때, 이 트랜잭션이 행한 갱신 연산이 완료된 것을 트랜잭션 관리자에게 알려주는 연산이다. - -**Rollback 연산** - -1. Rollback 연산은 하나의 트랜잭션 처리가 비정상적으로 종료되어 데이터베이스의 일관성을 깨뜨렸을 때, 이 트랜잭션의 일부가 정상적으로 처리되었더라도 트랜잭션의 원자성을 구현하기 위해 이 트랜잭션이 행한 모든 연산을 취소(Undo)하는 연산이다. -2. Rollback 시에는 해당 트랜잭션을 재시작하거나 폐기한다. - -### 트랜잭션 상태 - -![](https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F999C55345B6D2ED308) - -- 활동 (Active) : 트랜잭션이 실행중인 상태 -- 실패 (Failed) : 트랜잭션 실행에 오류가 발생하여 중단된 상태 -- 철회 (Aborted) : 트랜잭션이 비정상적으로 종료되어 Rollback 연산을 수행한 상태 -- 부분 완료 (Partially Committed) : 트랜잭션의 마지막 연산까지 실행했지만, Commit 연산이 실행되기 직전의 상태 -- 완료 (Committed) : 트랜잭션이 성공적으로 종료되어 Commit 연산을 실행한 후의 상태 - -### 출처 - -- [https://coding-factory.tistory.com/226](https://coding-factory.tistory.com/226) \ No newline at end of file From b1ff99c0bb6a9684e92a332760b3a784cb559371 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=B5=9C=ED=95=9C=EC=9A=B8?= Date: Mon, 5 Jul 2021 22:37:52 +0900 Subject: [PATCH 044/142] =?UTF-8?q?Revert=20"[6=EC=A3=BC=EC=B0=A8]=20B-tre?= =?UTF-8?q?e=20vs=20B+tree"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 02c81cdbb8af302424e7c23312d6b8b9bbc33897. --- database/btree-vs-b+tree/hamill/README.md | 33 ----------------------- 1 file changed, 33 deletions(-) delete mode 100644 database/btree-vs-b+tree/hamill/README.md diff --git a/database/btree-vs-b+tree/hamill/README.md b/database/btree-vs-b+tree/hamill/README.md deleted file mode 100644 index 6c3e904..0000000 --- a/database/btree-vs-b+tree/hamill/README.md +++ /dev/null @@ -1,33 +0,0 @@ -# B-tree vs B+tree - -### B-tree - -B-tree는 노드가 inorder traversal로 정렬되는 자가 균형 이진 탐색 트리(self-balancing tree)로 알려져 있습니다. B-tree에서 노드는 둘 이상의 자식을 가질 수 있습니다. B-tree의 높이는 logMN 입니다. (여기서 M은 트리 순서, N은 노드 수입니다) 그리고 높이는 업데이트 할 때마다 자동으로 조정됩니다. B-tree에서 데이터는 왼쪽이 가장 낮은 값, 오른쪽이 가장 높은 값을 사용하여 특정 순서로 정렬됩니다. B-tree에 데이터나 키를 삽입하는 것은 이진 트리보다 더 복잡합니다. B-tree가 유지해야 하는 몇 가지 조건이 있습니다. - -- 모든 리프 노드는 동일한 수준에 있어야 한다. -- 리프 노드 위에는 빈 하위 트리가 없어야 한다. -- 높이는 가능한 한 낮아야 한다. - -![](https://media.geeksforgeeks.org/wp-content/uploads/20191219160544/Untitled-Diagram111.png) - -### B+tree - -B+tree는 트리의 리프 노드에만 데이터 포인터를 저장하여 인덱싱에 사용되는 B-tree의 단점을 제거합니다. 따라서 B+tree의 리프 노드 구조는 B-tree의 내부 노드 구조와 상당히 다릅니다. 데이터 포인터는 리프 노드에만 존재하기 때문에 리프 노드는 액세스하기 위해 디스크 파일 블록에 대한 해당 데이터 포인터와 함께 모든 키값을 반드시 저장해야 합니다. 또한 리프 노드는 레코드에 대한 정렬된 액세스를 제공하는데 연결됩니다(Moreover, the leaf nodes are linked to providing ordered access to the records). 따라서 리프 노드는 인덱스의 첫 번째 level을 형성하며 내부 노드는 multilevel 인덱스의 다른 level을 형성합니다. 리프 노드의 일부 주요 값은 내부 노드에도 나타나며, 단순히 레코드 검색을 제어하는 매체 역할을 합니다. - -![](https://media.geeksforgeeks.org/wp-content/uploads/Btree.jpg) - -
- - -|No|B-tree|B+tree| -|:---|:---|:---| -|1. |모든 내부 및 리프 노드에는 데이터 포인터가 있습니다.|리프 노드에만 데이터 포인터가 있습니다.| -|2. |리프에서 모든 키를 사용 할 수 없기 때문에 검색에 더 많은 시간이 걸리는 경우가 많습니다.|모든 키는 리프 노드에 있으므로 검색이 더 빠르고 정확합니다.| -|3. |트리에서 키의 중복이 유지되지 않습니다.|중복 키가 유지되고 모든 노드가 리프에 있습니다.| -|4. |삽입에 더 많은 시간이 걸리며 때로는 예측 할 수 없습니다.|삽입이 더 쉽고 결과는 항상 동일합니다.| -|5. |내부 노드의 삭제는 매우 복잡하고 트리는 많은 변형을 거쳐야합니다.|모든 노드가 리프에서 발견되기 때문에 모든 노드의 삭제가 쉽습니다.| -|6. |리프 노드는 구조적(structural) 연결리스트로 저장되지 않습니다.|리프 노드는 구조적 연결리스트로 저장됩니다.| -|7. |중복 검색 키가 없습니다.|중복 검색 키가 있을 수 있습니다.| - -### 출처 -- https://www.geeksforgeeks.org/difference-between-b-tree-and-b-tree/ \ No newline at end of file From 0057cdfaced34ebc378c8c0e9edfd77c39104b29 Mon Sep 17 00:00:00 2001 From: Jin Hyung Park Date: Tue, 6 Jul 2021 19:17:53 +0900 Subject: [PATCH 045/142] Update B-Tree.md --- database/btree-vs-b+tree/B-Tree.md | 87 +++++++++++++++++------------- 1 file changed, 50 insertions(+), 37 deletions(-) diff --git a/database/btree-vs-b+tree/B-Tree.md b/database/btree-vs-b+tree/B-Tree.md index cf4fd2b..6dee89d 100644 --- a/database/btree-vs-b+tree/B-Tree.md +++ b/database/btree-vs-b+tree/B-Tree.md @@ -1,40 +1,53 @@ -## B-Tree +# B-Tree +* 이진 트리가 자식 노드가 최대 2개인 노드를 말하는 것이다. +* B-Tree는 자식 노드의 개수가 2개 이상인 트리를 말한다. + * 노드 내의 데이터가 1개 이상이다. + * 노드 내 최대 데이터 수가 2개라면 2차 B-Tree, 3개라면 3차 B-Tree 라고 말한다. + +### B-Tree 성립 조건 +* 노드의 데이터 수가 n개라면 자식 노드의 개수는 n+1개이다. +![](https://i.imgur.com/8HViFwf.png) + * root 노드에 데이터가 3개이므로 자식 노드의 개수는 4개이다. +* 노드의 데이터는 정렬된 상태이다. +![](https://i.imgur.com/qmbr7kf.png) +* 노드 데이터를 기준으로, 자식 노드의 데이터가 큰 값은 오른 쪽에, 작은 값은 왼쪽에 배치한다. +* Root 노드에 자식이 있다면, 자식은 2개 이상이다. +* Root 노드를 제외한 모든 노드는 적어도 M/2 개의 데이터를 갖고 있어야 한다. 즉, 4차부터는 2개 이상의 데이터를 갖고 있어야 한다. + ![](https://i.imgur.com/SrILCLR.png) +* Leaf 노드는 모두 같은 레벨에 존재해야 한다. + ![](https://i.imgur.com/QS8Rb4Z.png) + + +### 탐색 방법 +* 이진 트리와 동일하다. +* root 노드에서 시작해서 하향식으로 전개해나간다. + +### 삽입 방법 +![](https://i.imgur.com/s7CKiYC.png) +- 3차 B-Tree를 기준으로 한다. +- 가. 데이터를 탐색해 해당하는 Leaf 노드에 데이터를 삽입한다. +- 나. Leaf 노드가 꽉 찼으면 노드를 분리한다. + - 위의 예시에서 3차 B-Tree 이므로 Insert 7에서 꽉 찼다. + - 중간값을 부모 노드로 해서 분리한다. +- 다. 분리한 서브트리가 B-Tree조건에 맞지 않는다면 부모 노드로 올라가며 merge한다. + - 위의 insert12 에서 [9, 7, 12] 를 서브트리로 분리 하였으나 B-Tree 조건에 맞지 않는다. + - 다시 merge 하니 Leaf 노드가 모두 같은 레벨에 존재하지 않는다. + - Root 노드와 merge 함으로서 조건을 만족시켰다. + +### 삭제 방법 +![](https://i.imgur.com/r0PsDIA.png) +가. Leaf 노드에서 1을 삭제하면 구조가 깨진다. +나. 삭제한 노드의 부모 노드로 올라가며 데이터를 가져온다. +다. 1의 부모 노드와 형제 노드를 merge한다. +라. 부모 노드에서 자식 노드로 값을 가져오고, 자식 노드의 형제 노드와 merge 한다. +마. root 노드까지 올라가며 조건을 충족시킨다. + +### 결론: B-Tree는 언제든지 균형된(Balanced) 트리이다. + +![](https://i.imgur.com/lifYtSv.png) +* 테이블이 갱신되면 계속 균형이 깨지니까. 갱신 빈도가 높은 테이블에 작성되는 인덱스 같은 경우 인덱스 재구성을 해서 트리의 균형을 되찾는 작업이 필요하다. -### 개요 - -* 이진 트리는 하나의 부모가 두 개의 자식을 갖는다. 구조가 간결해서 균형이 맞으면 ```OlogN``` 의 복잡도를 갖는다. - -* 하지만 균형이 맞지 않으면 선형탐색 급의 검색 효율을 갖는다. - -* B-Tree는 이진 트리를 확장한 것으로, 더 많은 자식을 가질 수 있도록 일반화한 것이다. - - * B-Tree는 자식 노드의 개수가 2개 이상인 트리를 말한다. - * B-Tree는 노드 내의 데이터가 1개 이상일 수 있다. - * 노드 내 최대 데이터 수가 2개이면 2차 B-Tree라고 부른다. - * B-Tree는 노드의 데이터 수가 n개라면 자식 노드의 개수는 (n+1) 개이다. - - ![btree조건](https://hyungjoon6876.github.io/jlog/assets/img/20180720/btree_1.png) - - * 노드의 데이터 수가 root에 3개이므로, 자식 노드의 개수는 4개이다. - - * 노드 내부의 데이터는 정렬되어 있어야 한다. - - * ```3 1 4``` 가 아니라 ```1 3 4``` 이어야 한다. - - * 노드의 자식 노드 데이터들은 노드 데이터를 기준으로 데이터보다 작은 값은 왼쪽 서브트리에, 큰 값은 오른쪽 서브트리에 이루어져야 한다. 이는 이진 트리와 동일한 논리이다. - - ![btree조건](https://hyungjoon6876.github.io/jlog/assets/img/20180720/btree_3.png) - - * Root 노드를 제외한 모든 M차 B-Tree의 노드는 적어도 M/2개의 데이터를 갖고 있어야 한다. - - ![btree조건](https://hyungjoon6876.github.io/jlog/assets/img/20180720/btree_4.png) - - * 다음과 같은 4차 B-Tree에서 Root 노드의 데이터 8의 왼쪽 서브트리 노드가 데이터가 1개이므로 조건에 부합하지 않는다. - - * `Leaf` 노드로 가는 경로의 길이는 모두 같아야 한다. 즉 `Leaf` 노드는 모두 같은 레벨에 존재해야 한다. - - ![btree조건](https://hyungjoon6876.github.io/jlog/assets/img/20180720/btree_5.png) ### 참고 - -* https://hyungjoon6876.github.io/jlog/2018/07/20/btree.html \ No newline at end of file +* https://hyungjoon6876.github.io/jlog/2018/07/20/btree.html +* https://matice.tistory.com/8 From 710ca7161b16f053c4be5ab586bb4f6e14003356 Mon Sep 17 00:00:00 2001 From: Jin Hyung Park Date: Tue, 6 Jul 2021 19:32:24 +0900 Subject: [PATCH 046/142] Create B+Tree.md --- database/btree-vs-b+tree/B+Tree.md | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 database/btree-vs-b+tree/B+Tree.md diff --git a/database/btree-vs-b+tree/B+Tree.md b/database/btree-vs-b+tree/B+Tree.md new file mode 100644 index 0000000..478f947 --- /dev/null +++ b/database/btree-vs-b+tree/B+Tree.md @@ -0,0 +1,10 @@ +# B+Tree +![](https://i.imgur.com/kaVGSJH.png) +* B+tree의 경우 브랜치 노드에 key만 담아두고, data는 담지 않는다. + * 오직 리프 노드에만 key와 data를 저장하고, 리프 노드끼리 Linked list로 연결되어 있다. + +### B+Tree의 장점 +* 리프 노드를 제외하고 데이터를 담아두지 않는다. 따라서 메모리를 더 확보해서 더 많은 key를 수용할 수 있다. +* 하나의 노드에 더 많은 Key를 담을 수 있으므로 같은 데이터에 따라 트리의 높이는 더 낮아진다. (```=== cache hit```) +* 풀 스캔 시, B+Tree는 Leaf Node에 데이터가 모두 있으므로 단 한 번의 선형 탐색만 하면 된다. 따라서 B-Tree에 비해 빠르다. + * InnoDB에서는 B+Tree를 Double Linked List로 연결했다. From 1e3aabb7bf7933e82f961eae7c9451f2e5793771 Mon Sep 17 00:00:00 2001 From: Jin Hyung Park Date: Tue, 6 Jul 2021 19:53:02 +0900 Subject: [PATCH 047/142] Create transaction.md --- database/transaction.md | 63 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 database/transaction.md diff --git a/database/transaction.md b/database/transaction.md new file mode 100644 index 0000000..a983ea8 --- /dev/null +++ b/database/transaction.md @@ -0,0 +1,63 @@ +# 데이터베이스를 지탱하는 Transaction +## Transaction +* 하나의 작업을 수행하기 위해 필요한 연산들의 집합 + * 이를 ```논리적인 작업의 단위``` 라고 부른다. + * 트랜잭션 = 하나의 작업을 수행하기 위해 사용되는 SQL 문들의 집합 + * 트랜잭션의 모든 작업이 수행되거나(Commit), 또는 하나도 수행되지 않아야 (Rollback) 데이터베이스에 일관성을 유지할 수 있음 + +### ACID +#### Atomicity 원자성 +* 트랜잭션을 구성하는 연산이 모두 정상적으로 실행되거나, 또는 하나도 실행되지 않아야 한다는 all-or-nothing 방식을 의미한다. +* 트랜잭션을 수행하다가 장애가 발생하여 작업을 완료하지 못한다면? + * 지금까지 실행한 연산들을 모두 취소한다. + * DB를 트랜잭션 작업 이전의 상태로 되돌려 atomicity를 보장한다. + +### Consistency 일관성 +* 트랜잭션이 성공적으로 수행된 이후에도 데이터베이스가 일관되게 유지되어야 한다. 즉, 트랜잭션 전에도 일관되었다면 이후에도 일관되어야 한다. +* 예를 들어, 계좌 이체를 하기 전의 돈 거래의 합과 이후의 돈 거래의 합은 각기 같아야 한다. + +### Isolation 고립성 +* 현재 진행 중인 트랜잭션이 완료될 때까지, 트랜잭션의 중간 연산 과정에 다른 트랜잭션이 개입하지 못한다. 하나의 트랜잭션 연산이 **완료** 되어야 다음 트랜잭션으로 넘어갈 수 있다. +* 예를 들어, 계좌 이체 500원을 보낼 때 갑자기 300원이 결제되는 과정이 동시다발적으로 이루어질 수 없다. 500원을 보내는 트랜잭션이 먼저 발생되었으니 이게 끝나야 300원이 결제될 수 있다. + +### Durability 지속성 +* 트랜잭션이 성공적으로 완료된 이후에 데이터베이스에 저장되는 결과는 영구해야 한다. 시스템에 장애가 생기더라도 트랜잭션 작업 결과는 손실되지 않아야 한다. + +### Commit +* DB에 반영되는 순간은 트랜잭션 연산이 완료되는 순간이다. + +![](https://i.imgur.com/AbGykdB.png) +* commit 연산이 수행되어야 트랜잭션의 수행이 완료되고 데이터베이스에 영구히 기록된다. + +### Rollback +![](https://i.imgur.com/uem4fFM.png) +* 트랜잭션이 수행을 실패했음을 알려주는 선언 +* begin rollback하면 previous point of consistency로 돌아간다. +* 서로 모순되지 않도록 transaction 시작 이전의 DB로 돌아가 일관된 상태를 유지한다. + +### Cycle +![](https://i.imgur.com/JuezNpn.png) +* https://beginnersbook.com/2018/12/dbms-transaction-states/ +* 활동 상태 +* 부분 완료 상태 +* 완료 상태 +* 실패 상태 +* 철회 상태 + +### How to recover? +#### Immediate Updates 즉시 회복 기법 +* 트랜잭션 수행 도중 변경하면 변경 정보를 로그 파일에 저장하고, 트랜잭션이 부분 완료되기 전이라도 모든 변경 내용을 즉시 데이터베이스의 반영하는 기법. +* 로그 파일을 참조하여 REDO & UNDO 연산 모두 실행 + * Dump: copy the ‘whole database’ to other place regularly + * Log: save ‘before/after states’ of operations to files + * REDO 연산 + * 가장 최근에 저장한 데이터베이스 복사본을 가져온 후 로그를 이용해 복사본이 만들어진 이후에 실행된 모든 변경 연산을 재실행하여 장애가 발생하기 직전의 상태로 복구 + * UNDO 연산 + * 로그를 이용해 지금까지 실행된 모든 변경 연산을 취소하여 데이터베이스를 원래의 상태로 복구 + +#### Deferred Updates 지연 기법 +* 트랜잭션이 부분 완료 상태에 이르기까지 발생한 모든 변경 내용을 로그 파일에만 저장하고 데이터베이스에는 커밋이 발생할 때까지 저장하는 기법. +* 회복 과정에서 UNDO가 필요 없음. +* 데이터베이스의 원자성 보장 + +#### Checkpoint recovery From e70b3865afac844f95ed5b7c3da596b9765ca9e9 Mon Sep 17 00:00:00 2001 From: 102092 Date: Fri, 9 Jul 2021 21:46:55 +0900 Subject: [PATCH 048/142] Add br --- database/btree-vs-b+tree/han/README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/database/btree-vs-b+tree/han/README.md b/database/btree-vs-b+tree/han/README.md index 1cc5dc7..e939e9c 100644 --- a/database/btree-vs-b+tree/han/README.md +++ b/database/btree-vs-b+tree/han/README.md @@ -41,36 +41,43 @@ all leaves must appear on the same level ## 어떻게 B tree가 만들어질까? ![](https://www.baeldung.com/wp-content/uploads/sites/4/2020/05/btree1-1.png) + 1. root 노드를 생성한다. - 해당 노드는 key/value pair로 구성되며, key = 1, value는 *로 묘사한다. - *의 의미는, 다른 레코드를 참조함을 의미한다. - root 노드는 왼쪽, 오른쪽 서브트리로 갈 수 있는 pointer를 가지고 있다. ![](https://www.baeldung.com/wp-content/uploads/sites/4/2020/05/btree2-1.png) + 2. 2라는 key를 가진 노드를 추가한다. - 현재 노드들은 key값을 기준으로 오름차순 정렬되어 있다. ![](https://www.baeldung.com/wp-content/uploads/sites/4/2020/05/btree3-1.png) + 3. 3이라는 key를 가진 노드를 추가한다. - 이순간 b tree는 split operation 이라고 불리는 행위를 실행한다. - 이 과정을 통해, left, middle , right node가 결정된다. - 처음 root 노드는 1 키를 가지고 있는 노드 였지만, 2 키를 가지고 있는 노드로 바뀌었다. ![](https://www.baeldung.com/wp-content/uploads/sites/4/2020/05/btree4-1-768x300-1.png) + 4. 4라는 키를 가진 노드를 삽입한다. - 이상태에서 B tree는 구조가 잡혀있기 때문에.. (3개이상의 노드가 삽입되었기 때문에) - 해당 키 값이 root노드보다 큰지 작은지 판단할 수 있다. (현재는 크다.) - right sub tree에 추가되고, right에 있는 노드들의 키값을 기준으로 오름차순 정렬된다. ![](https://www.baeldung.com/wp-content/uploads/sites/4/2020/05/btree5-1-768x288-1.png) + 5. 5라는 키를 가진 노드를 삽입한다. - root 노드 + 1 갯수를 초과하여, child 노드가 구성되어질 수 없기 때문에.. - 리밸랜생이 일어난다. ![](https://www.baeldung.com/wp-content/uploads/sites/4/2020/05/btree6-2.png) + 6. 6 노드를 삽입한다. ![](https://www.baeldung.com/wp-content/uploads/sites/4/2020/05/btree7-1-1024x471-1.png) + 7. 7 노드 삽입 - 하는 순간 조건을 1번조건 만족시키기 위해 리밸랜싱 일어남 (현재 M=2, 하나의 노드는 최대 2개까지 자식노드를 가질 수 있음.) - 오른쪽 서브 트리에서 하나를 상위로 올리게 되면.... (a non-leaf node with k children should have k-1 keys) 이 조건을 어기게됨. @@ -78,6 +85,7 @@ all leaves must appear on the same level - all leaves must appear on the same level를 만족시키기 위해 나머지 왼쪽 서브트리에서도 리밸랜싱.. ![](https://www.baeldung.com/wp-content/uploads/sites/4/2020/05/btreefull-3.png) + 8. 8, 9 노드 삽입 - 8 노드를 삽입하면, 7 오른쪽에 붙었다가.. (each internal node (non-leaf and non-root) can have at least (m/2) children (rounded up)), 에 의거해 최대 2개까지 자식 노드를 가질 수 있으니.. 리밸랜싱 From a977a37cb93bcae24a7bb3b2063844bd071a42c0 Mon Sep 17 00:00:00 2001 From: 102092 Date: Fri, 9 Jul 2021 21:48:21 +0900 Subject: [PATCH 049/142] Fix text --- database/transaction-basic/han/REAMDE.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/database/transaction-basic/han/REAMDE.md b/database/transaction-basic/han/REAMDE.md index ed0bcc9..1666029 100644 --- a/database/transaction-basic/han/REAMDE.md +++ b/database/transaction-basic/han/REAMDE.md @@ -4,8 +4,8 @@ - 트랜잭션 이론 자체는 독립적인 이론이라 볼 수 있음 - 데이터베이스 에서 트랜잭션은 2가지를 보장하기 위해 사용됨. 1. 믿을수있는 작업 단위를 보장하기 위해 - - 작업 실패로 안한 정확한 복구를 허용하고, - - 실패를 하더라도 데이터베이스 시스템이 지속되어 운영되도록 보장해줌. + - 작업 실패로 안한 정확한 복구를 허용하고, + - 실패를 하더라도 데이터베이스 시스템이 지속되어 운영되도록 보장해줌. 2. 커밋 간에 독립적인 환경을 제공해주기 위해. - 트랜잭션과 관계형 모델은 다른 이론. - 그렇지만 데이터를 올바르게 보장하기 위해서, 양쪽 다 필요하는 상호보완적인 관계라 볼 수 있음. From 363ebc154ac27257b74882d312ed95d9afe1f2d0 Mon Sep 17 00:00:00 2001 From: Jin Hyung Park Date: Wed, 14 Jul 2021 19:25:53 +0900 Subject: [PATCH 050/142] update checkpoint recovery contents --- database/transaction.md | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/database/transaction.md b/database/transaction.md index a983ea8..089cc56 100644 --- a/database/transaction.md +++ b/database/transaction.md @@ -60,4 +60,24 @@ * 회복 과정에서 UNDO가 필요 없음. * 데이터베이스의 원자성 보장 -#### Checkpoint recovery +#### Checkpoint Recovery +#### Checkpoint +* 특정한 체크포인트로 설정한 지점을 기점으로, 해당 지점 이전에는 트랜잭션이 성공적으로 수행되어 디스크에 저장되어 있다고 보장할 수 있습니다. +* 실패가 일어날 경우, redo는 check point 시점부터 log를 따라가면서 트랜잭션을 수행합니다. undo는 트랜잭션을 거꾸로 재수행하면서 트랜잭션을 없던 일로 만듭니다 + +![image](https://user-images.githubusercontent.com/41055141/125605863-8ff54452-4279-44f7-a5c0-bcef1f3ff020.png) +* Transaction T1 +checkpoint 이전에 실행이 완료되었으므로 failure 되더라도 이미 disk에 저장이 된 상태이므로 회복을 하지 않습니다. +* Transaction T2 +checkpoint 이전에 실행된 내용은 disk에 반영이 되었으므로 check point 이후의 내용을 log를 따라가는 redo를 수행합니다. +* Transaction T3 +failure 시점에 실행중이였으므로 check point 시점으로 undo한 후, 트랜잭션을 재실행합니다. +* Transaction T4 +checkpoint 이후에 실행됐고 failure 시점 전에 실행이 끝났으므로 redo를 수행합니다. +* Transaction T5 +checkpoint 이후에 실행됐고 failure 시점에 실행중이였으므로 시작지점까지 undo한 후, 트랜잭션을 재실행합니다. + +그러니까 정리하자면, +* 체크포인트 시점 중간에 (스냅샷 찍는 도중에) 실행되는 트랜잭션은 모두 undo한다. +* 체크포인트 시점 이후에 실행된 트랜잭션은 모두 undo한다. +* undo list에 기록된 트랜잭션이 성공적으로 undo되면 이를 다시 redo한다. From 8cc1279074538283f78acf7db1c12e379145b7a9 Mon Sep 17 00:00:00 2001 From: Jin Hyung Park Date: Wed, 14 Jul 2021 19:26:25 +0900 Subject: [PATCH 051/142] move folder directory --- database/btree-vs-b+tree/{ => sigrid}/B+Tree.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename database/btree-vs-b+tree/{ => sigrid}/B+Tree.md (100%) diff --git a/database/btree-vs-b+tree/B+Tree.md b/database/btree-vs-b+tree/sigrid/B+Tree.md similarity index 100% rename from database/btree-vs-b+tree/B+Tree.md rename to database/btree-vs-b+tree/sigrid/B+Tree.md From 121a3869efdb95d2cee11d9a715854810aadbf12 Mon Sep 17 00:00:00 2001 From: Jin Hyung Park Date: Wed, 14 Jul 2021 19:26:38 +0900 Subject: [PATCH 052/142] move folder directory --- database/btree-vs-b+tree/{ => sigrid}/B-Tree.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename database/btree-vs-b+tree/{ => sigrid}/B-Tree.md (100%) diff --git a/database/btree-vs-b+tree/B-Tree.md b/database/btree-vs-b+tree/sigrid/B-Tree.md similarity index 100% rename from database/btree-vs-b+tree/B-Tree.md rename to database/btree-vs-b+tree/sigrid/B-Tree.md From 05679426c7fb90fdf7cfa0ef164bb61556221714 Mon Sep 17 00:00:00 2001 From: Jin Hyung Park Date: Wed, 14 Jul 2021 19:27:12 +0900 Subject: [PATCH 053/142] Update B-Tree.md --- database/btree-vs-b+tree/sigrid/B-Tree.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/database/btree-vs-b+tree/sigrid/B-Tree.md b/database/btree-vs-b+tree/sigrid/B-Tree.md index 6dee89d..c4e64a8 100644 --- a/database/btree-vs-b+tree/sigrid/B-Tree.md +++ b/database/btree-vs-b+tree/sigrid/B-Tree.md @@ -51,3 +51,14 @@ ### 참고 * https://hyungjoon6876.github.io/jlog/2018/07/20/btree.html * https://matice.tistory.com/8 + +# B+Tree +![](https://i.imgur.com/kaVGSJH.png) +* B+tree의 경우 브랜치 노드에 key만 담아두고, data는 담지 않는다. + * 오직 리프 노드에만 key와 data를 저장하고, 리프 노드끼리 Linked list로 연결되어 있다. + +### B+Tree의 장점 +* 리프 노드를 제외하고 데이터를 담아두지 않는다. 따라서 메모리를 더 확보해서 더 많은 key를 수용할 수 있다. +* 하나의 노드에 더 많은 Key를 담을 수 있으므로 같은 데이터에 따라 트리의 높이는 더 낮아진다. (```=== cache hit```) +* 풀 스캔 시, B+Tree는 Leaf Node에 데이터가 모두 있으므로 단 한 번의 선형 탐색만 하면 된다. 따라서 B-Tree에 비해 빠르다. + * InnoDB에서는 B+Tree를 Double Linked List로 연결했다. From 88f117f61d5cb97c44f8e6b2c63d15fd27520157 Mon Sep 17 00:00:00 2001 From: Jin Hyung Park Date: Wed, 14 Jul 2021 19:27:21 +0900 Subject: [PATCH 054/142] Rename B-Tree.md to README.md --- database/btree-vs-b+tree/sigrid/{B-Tree.md => README.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename database/btree-vs-b+tree/sigrid/{B-Tree.md => README.md} (100%) diff --git a/database/btree-vs-b+tree/sigrid/B-Tree.md b/database/btree-vs-b+tree/sigrid/README.md similarity index 100% rename from database/btree-vs-b+tree/sigrid/B-Tree.md rename to database/btree-vs-b+tree/sigrid/README.md From 25be67f21d9568613f2347fde0b009cc5279811e Mon Sep 17 00:00:00 2001 From: Jin Hyung Park Date: Wed, 14 Jul 2021 19:27:28 +0900 Subject: [PATCH 055/142] Delete B+Tree.md --- database/btree-vs-b+tree/sigrid/B+Tree.md | 10 ---------- 1 file changed, 10 deletions(-) delete mode 100644 database/btree-vs-b+tree/sigrid/B+Tree.md diff --git a/database/btree-vs-b+tree/sigrid/B+Tree.md b/database/btree-vs-b+tree/sigrid/B+Tree.md deleted file mode 100644 index 478f947..0000000 --- a/database/btree-vs-b+tree/sigrid/B+Tree.md +++ /dev/null @@ -1,10 +0,0 @@ -# B+Tree -![](https://i.imgur.com/kaVGSJH.png) -* B+tree의 경우 브랜치 노드에 key만 담아두고, data는 담지 않는다. - * 오직 리프 노드에만 key와 data를 저장하고, 리프 노드끼리 Linked list로 연결되어 있다. - -### B+Tree의 장점 -* 리프 노드를 제외하고 데이터를 담아두지 않는다. 따라서 메모리를 더 확보해서 더 많은 key를 수용할 수 있다. -* 하나의 노드에 더 많은 Key를 담을 수 있으므로 같은 데이터에 따라 트리의 높이는 더 낮아진다. (```=== cache hit```) -* 풀 스캔 시, B+Tree는 Leaf Node에 데이터가 모두 있으므로 단 한 번의 선형 탐색만 하면 된다. 따라서 B-Tree에 비해 빠르다. - * InnoDB에서는 B+Tree를 Double Linked List로 연결했다. From 6af75d1f929a771acdbffb3453d8dcf482be5c13 Mon Sep 17 00:00:00 2001 From: Jin Hyung Park Date: Wed, 14 Jul 2021 19:27:52 +0900 Subject: [PATCH 056/142] Rename sigrid_index.md to README.md --- database/index-basic/sigrid/{sigrid_index.md => README.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename database/index-basic/sigrid/{sigrid_index.md => README.md} (100%) diff --git a/database/index-basic/sigrid/sigrid_index.md b/database/index-basic/sigrid/README.md similarity index 100% rename from database/index-basic/sigrid/sigrid_index.md rename to database/index-basic/sigrid/README.md From 1a383f61b23c03242a264e028dda71b38e8e88e6 Mon Sep 17 00:00:00 2001 From: Jin Hyung Park Date: Wed, 14 Jul 2021 19:28:29 +0900 Subject: [PATCH 057/142] Rename database/transaction.md to database/transaction-basic/README.md --- database/{transaction.md => transaction-basic/README.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename database/{transaction.md => transaction-basic/README.md} (100%) diff --git a/database/transaction.md b/database/transaction-basic/README.md similarity index 100% rename from database/transaction.md rename to database/transaction-basic/README.md From e97552d2a799eb513d3e68287ded629eab663375 Mon Sep 17 00:00:00 2001 From: Jin Hyung Park Date: Sat, 17 Jul 2021 20:50:26 +0900 Subject: [PATCH 058/142] Rename database/transaction-basic/README.md to database/transaction-basic/sigrid/README.md --- database/transaction-basic/{ => sigrid}/README.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename database/transaction-basic/{ => sigrid}/README.md (100%) diff --git a/database/transaction-basic/README.md b/database/transaction-basic/sigrid/README.md similarity index 100% rename from database/transaction-basic/README.md rename to database/transaction-basic/sigrid/README.md From c01b0e8e9833a00c6d77b787903aa184343333b2 Mon Sep 17 00:00:00 2001 From: 102092 Date: Sun, 18 Jul 2021 17:55:09 +0900 Subject: [PATCH 059/142] Add issue frame --- database/join-in-sql/han/README.md | 0 database/normalization/han/README.md | 0 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 database/join-in-sql/han/README.md create mode 100644 database/normalization/han/README.md diff --git a/database/join-in-sql/han/README.md b/database/join-in-sql/han/README.md new file mode 100644 index 0000000..e69de29 diff --git a/database/normalization/han/README.md b/database/normalization/han/README.md new file mode 100644 index 0000000..e69de29 From 3719292cc1af6352af258ea9429f299cdd1b2c89 Mon Sep 17 00:00:00 2001 From: 102092 Date: Sun, 18 Jul 2021 21:55:27 +0900 Subject: [PATCH 060/142] Add 1,2,3 normailization --- database/normalization/han/README.md | 101 +++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) diff --git a/database/normalization/han/README.md b/database/normalization/han/README.md index e69de29..7266e39 100644 --- a/database/normalization/han/README.md +++ b/database/normalization/han/README.md @@ -0,0 +1,101 @@ +# 정규화란? +- 보통 데이터베이스 설계 이론을 의미하는 듯. (Normalization Theory) +- 관계형 데이터 베이스를 잘 다루고 이해하는 데 필요한 기술 + +# 왜 정규화를 하는가? + +1. 변칙을 방지할 수 있음. +- 변칙이란? + - 데이터가 논리적으로 불일치가 일어나는 상태 + - 모순이 발생한 상태 + - ![](https://www.guru99.com/database-normalization.html) + - Robet Phill 의 주소는 3 street 34 일수도.. 혹은 5 avenue 일 수도 있음 --> 이러한 데이터간 관계가 엇갈리는 경우를 모순이라 말하는 듯. + +2. 변칙을 발생 시키는 원인은? +- 중복 + - 중복되면, 데이터베이스에 낭비가 발생함. +- 즉 위 데이터로만 봤을 때, Robet Phill의 주소 데이터가 중복되기 때문에, 명확하지 않은 관계를 가지고 있게 되고 결국 변칙이 발생함. +- 이러한 중복을 제거하는 데 도움이 되는 것이 정규화 + +# 졍규형 +- 종류 + - 1NF (First Normal Form) + - 2NF (Second Normal Form) + - 3NF (Third Normal Form) + - BCNF (Boyce-Codd Normal Form) + - 4NF (Fourth Normal Form) + - 5NF (Fifth Normal Form) + - 6NF (Sixth Normal Form) +- 특징 + - 높은 단계의 정규형은 그 이전의 정규형 조건을 만족한다. + - DB 설계에서 가장 중요한 정규형은 BCNF 와 5NF + +## 제 1정규형 +- 조건 + - 릴레이션이어야 할 것. + - 즉 테이블에서 릴레이션이란 무엇인가, 어떤 것인가가 해당 유형의 주제 + - 테이블이 1NF 을 만족하기 위해 요건 + 1. 테이블의 셀은 반드시 **하나의 값**만 가지고 있어야함 + 2. 각각의 레코드(행)는 **유니크**해야함. + +- 만족하지 않는 형태 +![image](https://user-images.githubusercontent.com/22140570/126066503-8e56f2ca-eb3a-492e-9909-96662fe5b02e.png) + - COURS ID, GRADE에 여러개의 값을 가지고 있음. + +- 위 조건을 만족하는 형태 +![image](https://user-images.githubusercontent.com/22140570/126066539-533b53be-98c6-47be-a615-1ed96f6cdf4e.png) + + +- 관계 있는 개념들 + - Primary key, Composite key, 함수 종속성 FD(Functional Dependency) + + +## 제 2정규형 +- 조건 + - 제 1정규형을 만족하면서.. + - 후보키의 집합에서, 키가 아닌 속성(Non-prime Attribute) 에 연결되어 있는 함수 종속성이 제거된 상태 + +- 만족하지 않는 형태 +![image](https://user-images.githubusercontent.com/22140570/126066572-f2aa8568-55aa-41d1-9ceb-1c7c1f671f4f.png) + - Non trivial FD, 즉 자명하지 않는 함수 종속성이 존재한다. + - 위 릴레이션에서 어떤 함수 종속성이 존재하는가? + - 학번 -> 학부 + - 학번 -> 등록금 + - 학부 -> 등록금...등등 + - 학번 중복 + - 여기서 발생하는 중복을 줄여주면.. 제 2정규형을 만족할 수 있을듯 + - 어떻게 해결할 수 있을까? + - 한개의 릴레이션을, 여러개의 릴레이션으로 나누면 된다. (프로젝션) + - Non loss Decomposition을 생각하면서 릴레이션을 분해해야함. + - 즉 분해한 다음의 릴레이션에 포함된 정보를 이용해서, 원래의 릴레이션을 재구축 할 수 있어야함 + + - 다시 생각해보자.. + 1. 자명하지 않은 관계가 뭐가 있지? + 2. 과목코드랑 등록금. 성적과 학부. (다른 릴레이션을 가져야할듯) + 3. 그러면.. + - 학번 과목코드 성적 + - 학번 등록금 학부 + - 이렇게 나누면 될듯. +- 만족하는 형태 +![image](https://user-images.githubusercontent.com/22140570/126067334-1adbf269-72ed-486c-8455-fdb703787a1b.png) + + +## 제 3정규형 +- 조건 + - 제 2정규형을 만족하면서.. + - 추이 함수 종속성 (Transitive Dependency) 이 제거된 상태 +- 추이 함수 종속성이란? + - 학번 -> 학부 -> 등록금 + - 즉 학번을 알면, 학부를 알 수 있고, 학부를 알면 등록금을 알 수 있는 상태를 추이 함수 종속성을 가지고 있다고 한다. +- 이 관계에서도.. 중복이 발생한다. + - 찾아보면, 같은 학부이면 등록금이 같을 것이다.. + +- 만족하는 형태 +![image](https://user-images.githubusercontent.com/22140570/126067720-ad5dbfb5-f697-4b48-ad9f-71871454cfa6.png) + - 무손실 분해를 통해, 릴레이션을 나누고, 중복을 줄여주자 + +# 참고 +- 관계형 데이터베이스 실전 입문 3장 +- https://www.guru99.com/database-normalization.html +- https://lee-mandu.tistory.com/478?category=633572 +- https://yaboong.github.io/database/2018/03/09/database-normalization-1/ \ No newline at end of file From 1eac0519c46b61771d36b0b366a691f0ffc780b6 Mon Sep 17 00:00:00 2001 From: 102092 Date: Sun, 18 Jul 2021 22:49:28 +0900 Subject: [PATCH 061/142] Add join in sql --- database/join-in-sql/han/README.md | 41 ++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/database/join-in-sql/han/README.md b/database/join-in-sql/han/README.md index e69de29..b35291c 100644 --- a/database/join-in-sql/han/README.md +++ b/database/join-in-sql/han/README.md @@ -0,0 +1,41 @@ +# Join 이란? +- 둘 이상의 테이블을 연결하여 데이터를 검색하는 데 사용하는 방법 +- 보통 PK 혹은 FK 라는 공유되는 컬럼을 기준으로, 테이블을 연결함. + +# 종류 +![](https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F26242F48569460C734) +- 크게 보면 3가지 정도 있는 듯 + - INNER (교집합) + - LEFT/RIGHT (부분집합) + - OUTER (합집합) + +## INNER +![](https://i.stack.imgur.com/eJhrt.png) +- 동일한 조건 값에 있는 행만 반환 +- 보통 Join이라 말하면 Inner 조인을 의미하는 듯 + - 참고 : https://stackoverflow.com/questions/565620/difference-between-join-and-inner-join +- 대부분 INNER조인을 통해, Join문제를 해결해나가는 듯. + +## LEFT, RIGHT +![](https://i.stack.imgur.com/fZaT4.png) +![](https://i.stack.imgur.com/n9Bps.png) +- 어느쪽 테이블 위주로 합쳐지는가. +- LEFT는 왼쪽 테이블 기준으로, 매칭되는 컬럼이 있는 오른쪽 테이블 컬럼을 가져와서, 왼쪽 테이블에 붙인다. (왼쪽 + 공통 부분) + - 매칭되는 컬럼이 없을 경우 `NULL` 로 합쳐짐 +- RIGHT는 오른쪽 테이블 기준으로, 매칭되는 컬럼이 있는 왼쪽 테이블 컬럼을 가져와서 오른쪽 테이블에 붙인다. + +## OUTER +![](https://i.stack.imgur.com/aFHpq.png) +- 합집합 +- LEFT + RIGHT 조인의 결과 + +# 어떨떄 사용될까? +- 원하는 결과가, 하나의 테이블에 국한되지 않을 때 +- Domain간 관계가 맺어져 있을 떄 (OneToMany..등등) + +# 참고 +- https://pearlluck.tistory.com/46 +- https://dev.mysql.com/doc/refman/8.0/en/join.html +- https://stanleykou.tistory.com/entry/SQL-INNER-%EC%A1%B0%EC%9D%B8%EA%B3%BC-OUTER%EC%A1%B0%EC%9D%B8%EC%9D%B4-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80%EC%9A%94 +- https://edudeveloper.tistory.com/69 +- https://stackoverflow.com/questions/17946221/sql-join-and-different-types-of-joins \ No newline at end of file From 0a69d55ba711c3925ca5fe2a97698fe8c33ff732 Mon Sep 17 00:00:00 2001 From: Jin Hyung Park Date: Mon, 19 Jul 2021 19:31:46 +0900 Subject: [PATCH 062/142] Create README.md --- database/normalization/sigrid/README.md | 206 ++++++++++++++++++++++++ 1 file changed, 206 insertions(+) create mode 100644 database/normalization/sigrid/README.md diff --git a/database/normalization/sigrid/README.md b/database/normalization/sigrid/README.md new file mode 100644 index 0000000..9efe541 --- /dev/null +++ b/database/normalization/sigrid/README.md @@ -0,0 +1,206 @@ +# 데이터베이스 정규화 +## 정규화란 +#### 함수적 종속성을 이용해서 연관성 있는 속성들을 분류하고, 각 릴레이션들에서 이상현상이 생기지 않도록 하는 과정을 말한다. +* 정규화의 기본 목표는 중복된 데이터를 없애는 것이다. 즉, removing redundnacy를 해서 발생할 수 있는 anomalies를 방지한다. +* 중복된 데이터를 허용하지 않으면서 무결성(integrity)를 유지할 수 있다. 정규화를 거친 테이블을 각각의 테이블이 하나의 기능만 수행하게 되어서, 향후 업무가 증가하거나 변화해도 최소한의 수정만으로 처리할 수 있게 된다. +* 단점도 존재한다. 정규화를 한다는 것은 테이블을 세세하게 쪼갠다는 것인데 그 만큼 JOIN 연산을 많이 해야 하고 결국 조회할 때 성능이 떨어질 수밖에 없다. +## 이상현상의 종류 +![](https://i.imgur.com/yjYViCW.png) +* 위와 같은 테이블이 있다고 가정하자. + * 한 row를 유일하게 식별할 수 있는 복합키로 (학번, 과목코드) 가 있다고 가정하자. + * 한 학생은 하나의 학부에만 속할 수 있다. + +### 삽입 이상 Insertion Anomaly +#### 새 데이터를 삽입하기 위해 불필요한 데이터도 함께 삽입해야 하는 문제를 삽입이상 이라고 한다. + +* 수업을 하나도 수강하지 않은 학생이 있다고 하자. +* 현재 기본키는 복합키인 (학번, 과목코드) 이다. 따라서 과목코드는 불필요하게 NULL이 되어야 한다. 불필요한 NULL 값, 또는 ```미수강``` 과 같이 별도의 데이터가 불필요하게 들어가는 것을 ```삽입이상``` 이라고 부른다. + +### 갱신 이상 Update Anomaly +#### 중복 튜플 중 일부만 변경하여 데이터가 불일치하게 되는 모순의 문제를 갱신이상 이라고 한다. +* 야붕쿤이 컴공에서 전전으로 전과한다고 생각해보자. 그렇다면 우리는 위의 테이블에 있는 모든 야붕쿤의 row를 컴공에서 전전으로 바꿔야 한다. +* 트랜잭션이 일어나다가 에러가 발생해서 하나의 row에 변동사항이 적용되지 않았다고 가정한다면, 우리는 이것을 보고 ```갱신 이상```이라고 부른다. + +### 삭제 이상 Delete Anomaly +#### 튜플을 삭제하면 꼭 필요한 데이터까지 함께 삭제되는 데이터 손실의 문제를 삭제이상 이라고 한다. +* 팥빵이 POD032939 ID의 코스를 drop했다고 가정하자. 그렇다면 해당 row를 지워야 하는데 그럴 경우 테이블에서 아예 팥빵의 학생 정보가 모두 날라가게 된다. +* 수강취소를 반영하기 위해 학생등록정보를 모두 날리게 되는 것이다. 우리는 이것을 보고 ```삭제 이상```이라고 부른다. + +### 이상 현상이 발생하는 이유는 무엇인가? +#### 정규화가 되어 있지 않은 테이블 설계 때문이다. +* 개발할 때 우리가 OOP를 지향해서 관심사를 분리하면 코드의 재사용성과 유지보수의 편의성이 높아지는 것처럼 데이터베이스 설계에서도 비슷한 원칙이 적용된다. +* 이론적으로는 정규화를 수행하려면 속성들간의 관련성을 파악해야 하는데, 이 속성들간의 관련성을 ```함수적 종속성(Functional Dependency)``` 라고 한다. +* 일반적으로 하나의 릴레이션에는 하나의 함수적 종속성만이 존재하도록 정규화를 하게 된다. +## 함수적 종속성 Functional Dependency +* ```X->Y``` 가 있다고 가정하자. + * X는 결정자이다. + * Y는 종속자이다. + * Y는 X에 종속되어 있다. + +* 예시: 학생 테이블 + +![](https://i.imgur.com/m01SmBP.png) +* 학번에 의해서 학생 이름과 학부는 고유하게 결정된다. 해당 테이블에서 학번은 기본키이다. +* 학번은 결정자이며, 학생 이름과 학부는 종속자이다. +* 학생 이름과 학부는 학번에 종속되어 있다. +* 그래서 우리는 다음과 같이 표현할 수 있다. + * ```학번 -> (학생 이름, 학부)``` + +* 예시 2: 학생 테이블 2 + +![](https://i.imgur.com/1A0cGRX.png) +* 해당 테이블에서 (학번, 과목 코드) 가 기본키이자 복합키이다. +* 학번과 과목 코드에 따라서 성적이 결정된다. +* 학번과 과목 코드에 따라서 이름이 결정된다. +* 따라서 학번과 과목 코드는 결정자이며, 성적과 이름은 종속자이다. +* 성적과 이름은 학번과 과목 코드에 종속되어 있다. +* 그래서 우리는 다음과 같이 표현할 수 있다. + * ```(학번, 과목 코드) -> 성적``` + * ```(학번, 과목 코드) -> 이름``` +* 그런데 학번에 따라서 이름이 결정된다. +* 따라서 학번은 결정자이며, 이름은 종속자이다. +* 이름은 학번에 종속되어 있다. +* 그래서 우리는 다음과 같이 표현할 수 있다. + * ```학번 -> 이름``` + +#### 여기에서 우리는 이름이 해당하는 함수적 종속성이 두 개임을 발견할 수 있다. + +### 부분 함수적 종속 Partial Functional Dependency +#### 속성집합 Y 가 속성집합 X 의 전체가 아닌 일부분에도 함수적으로 종속됨을 의미한다. +* 우리는 위 테이블에서 (학번, 과목 코드) 가 기본키임을 알 수 있다. +* 따라서 속성집합 Y는 이름이고, 속성집합 X는 (학번, 과목 코드) 이다. +* 즉, 속성집합 Y는 속성집합 X의 전체에 함수적으로 종속되고 있다. + * ```(학번, 과목 코드) -> 이름``` +* 하지만 속성집합 X의 일부인 학번 만으로도 속성집합 Y의 함수종속 관계를 발견할 수 있다. +* 즉, 속성집합 Y는 속성집합 X의 일부에 함수적으로 종속되고 있다. + * ```학번 -> 이름``` +* 우리는 이러한 경우를 보고 부분 함수적 종속이라고 부른다. + +### 완전 함수적 종속 Full Functional Dependency +#### 속성집합 Y 가 속성집합 X 전체에 대해서만 함수적으로 종속된 경우를 말한다. +* 우리는 위 테이블에서 (학번, 과목 코드) 가 기본키임을 알 수 있다. +* 따라서 속성집합 Y는 성적이고, 속성집합 X는 (학번, 과목 코드) 이다. + * ```(학번, 과목 코드) -> 성적``` +* 속성집합 X의 전체를 참조하지 않고 속성집합 Y를 유일하게 분기할 수 없다. + * 위의 경우를 제외하고 함수 종속관계가 발견될 수 없다. +* 우리는 이러한 경우를 보고 완전 함수적 종속이라고 부른다. + +## 제 1 정규형 (1NF; First Normal Form) +#### 릴레이션에 속한 모든 속성의 도메인이 원자 값으로만 구성되어 있으면 제1정규형에 속한다. +* 여기서 원자 값 Atomic Value라는 것은 필드에 이름이 들어간다고 하면 + * ```박진형``` 이 들어가야 하지 + * ```박진형 김한울 박지성 ``` 이런 식으로 들어가면 곤란하다는 것이다. + +![](https://i.imgur.com/EILp1eM.png) + +* 관계형 데이터베이스의 릴레이션은 모든 속성이 원자 값을 가지는 특성이 있기 때문에, 최소한 제1정규형을 만족해야 릴레이션이 될 자격이 있다. +* 그래서 사실 제 1 정규형은 일반적인 정규화라고 보기는 힘들다. +* 아래의 형태가 잘 된 제 1 정규형의 형태이다. 위의 테이블은 제 1 정규형이 이루어지지 않은 형태이다. + +![](https://i.imgur.com/hsxeevH.png) + +## 제 2 정규형 (2NF; Second Normal Form)] +#### 제1정규형에 속하면서, 기본키가 아닌 모든 속성이 기본키에 완전 함수 종속되면 제2정규형이다. + +![](https://i.imgur.com/pCFYsZP.png) + +* 위에 있는 테이블의 기본키는 {학번, 과목코드} 이다. 해당 테이블의 함수적 종속성을 나타내면 다음과 같다. + * {학번, 과목코드} -> 성적 + * {학번, 과목코드} -> 학부 + * {학번, 과목코드} -> 등록금 + * 학번 -> 학부 + * 학번 -> 등록금 + * 학부 -> 등록금 +* 우리는 두 개의 부분 함수 종속성을 발견할 수 있다. + * 가) 학부 + * {학번, 과목코드} -> 학부 + * 학번 -> 학부 + * 나) 등록금 + * {학번, 과목코드} -> 등록금 + * 학번 -> 등록금 + * 예외) ```학부 -> 등록금``` 은 부분 함수 종속성이 아니다. + * 왜 일까? 부분 함수 종속성의 정의는 ```속성집합 X 의 전체가 아닌 일부분에도``` 종속되어 있는 것을 의미한다. + * 여기서 속성집합 X는 ```학부``` 이다. + * 따라서 속성집합 X가 ```학번, 과목코드``` 여서 집합의 일부인 ```학번``` 에도 종속되는 부분 함수 종속성의 경우와 다르다. + * 속성집합 X는 기본키일 필요도 없고 후보키일 필요조차도 없다. 따라서 학부도 속성집합 X가 될 수 있으므로, 완전 함수 종속성이라고 부를 수 있다. + +* 따라서 현재 ```학번->학부```, ```학번->등록금``` 두개의 부분 함수 종속성을 가지고 있다. 이를 제거해 주는 것을 제2정규화라고 한다. +* 학번, 학부, 등록금 속성을 가지는 학생 릴레이션과 학번, 과목코드, 성적 속성을 가지는 성적 릴레이션 둘로 나누어 주면 부분 함수 종속성을 제거할 수 있다. + * ```학번->학부``` 함수종속성으로 볼때, 학번만으로 학부에 대한 결정을 지을 수 있다. + * 하지만 현재 기본키가 (학번, 과목코드) 로 이루어져 있기 때문에 학번만으로 학부에 대한 결정을 짓는 것은 의미가 없다. 학번과 과목코드 두 개를 같이 이용해야 의미가 있다. + * 그래서 기본키가 학번인 테이블을 별도로 분리하여 학번 만으로 학부와 등록금을 변경할 수 있도록 만들어주는 과정이 부분 함수 종속성을 제거하는 제2정규화 과정이다. + +![](https://i.imgur.com/zNOJR8g.png) +* 릴레이션이 둘로 분해되면서 학부와 등록금에 대한 중복항목이 제거되었다. +* 정규화를 통해 분해된 릴레이션들이 JOIN을 통해 역정규화가 되면서 다시 원래대로 합쳐질 수 있어야 한다. +* 두 릴레이션 모두 제1정규형에 속하고, 기본키가 아닌 모든 속성이 기본키에 완전 함수 종속되므로 제2정규형을 만족한다. + +### 이행적 함수 이상 Transitive Functional Dependency +#### 만약, X, Y, Z 에 대해 X->Y 이고 Y->Z 이면 X->Z 가 성립한다고 했을 때, 우리는 이를 Z 가 X 에 이행적으로 함수 종속되었다고 한다. +* 제 2 정규화를 하더라도 이상현상이 발생할 수 있다. + * 삽입이상 + * 새로운 학부가 생기는 경우 등록된 학생(학번)이 없다면 학번속성이 NULL이 되므로 삽입할 수 없다. + * 갱신이상 + * 컴퓨터공학부 등록금이 400으로 오르는 경우 20800399, 21500399 둘 모두 바꾸어 주지 않으면 데이터 불일치 문제가 발생한다. + * 삭제이상 + * 21400001 학번을 가진 학생이 자퇴하는 경우, 기계공학부에 대한 정보가 함께 사라진다. +* 지금 위의 학생 릴레이션에서 다음과 같은 이행적 함수 이상을 발견할 수 있다. + * 학번 -> 학부 + * 학부 -> 등록금 + * 학번 -> 등록금 +* 어? 학번에 따라 등록금이 결정되는 것이 아니다. 학부에 따라 결정되는 것이다. +* 그래서 우리는 다음의 원칙에 따라 분류한다. + * ```X->Y, Y->Z 함수적 종속관계로 인해 X->Z 의 이행적 함수 종속 관계가 나타나면 [X, Y], [Y, Z] 두 릴레이션으로 분해한다.``` +![](https://i.imgur.com/mvKHaWm.png) +* 위의 테이블은 이행적 함수 이상을 제거한 학생과 학부 테이블이다. + +#### 제 3 정규형을 만족하면 이상 현상이 사라질까? +* 아니다. 후보키를 여러개 가지고 있는 릴레이션에서는 제3정규형을 만족하더라도 이상현상이 생길 수 있다. + +### 보이스-코드 정규형 (BCNF; Boyce-Codd Normal Form); Strong 3NF +#### X -> Y 는 trivial FD, 즉 Y 가 X 의 부분집합인 경우이거나, X 는 릴레이션 R 의 슈퍼키이다. +* Y가 X의 부분집합인 경우는 너무 자명하므로 넘어가도 되는 정의이다. + * 예를 들어 AA->A, AB->A와 같은 것들이다. +* 따라서 쉽게 바꾸어 실용적으로 말하자면, 모든 결정자가 SUPER KEY인 경우 BCNF 이다. + +![](https://i.imgur.com/qJamHf6.png) +* 위의 테이블은 BCNF를 위반하는 릴레이션을 보여주는 이론적 예시이다. +* 위 1NF를 만족하는 릴레이션의 경우, + * 기본키가 아닌 모든 속성이 기본키에 완전 함수 종속이므로 2NF 를 만족한다. + * (A, B) -> C + * (A, B) -> D + * (A, B) -> E + * 기본키가 아닌 모든 속성이 기본키에 이행적 함수 종속이 되지 않으므로 3NF 를 만족한다. + * (A, B) -> C -> B가 있지만, B는 기본키의 일부일 뿐이다. + * 그런데 결정자 C가 슈퍼키가 아니다. + * 기본키인 (A, B)는 슈퍼키이지만, 결정자 C에 따라 B는 중복될 수 있는 가능성이 있다. 따라서 결정자 C는 슈퍼키라고 결론지을 수 없다. + +* BCNF 위반 사례 +![](https://i.imgur.com/rijutAh.png) + * ```{Student, Course}``` 를 기본키로 선정한 경우 3NF 까지 만족하지만 BCNF 를 만족하지 않는 경우에도 삽입이상, 갱신이상, 삭제이상이 생길 수 있다. + * 삽입이상 + * Algorithms 라는 수업이 Honux 에 의해 열렸다고 하자. 하지만 수강생이 아무도 없는 경우 삽입할 수 없다. + * 갱신이상 + * Yagom 이 담당하는 강의가 바뀌게 될 경우 수강생의 수만큼 갱신해줘야 하므로 하나라도 빠뜨리면 데이터 불일치 문제가 발생할 여지가 있다. + * 삭제이상 + * 모찌가 자퇴해서 Computer Architecture 수업의 수강생이 없어지면 Alan Turing 이라는 강사도 사라진다. + +* 분해 + * 가. nontrivial FD X -> Y + * 나. 두 개의 릴레이션으로 분해한다. + * XY 로 구성된 릴레이션 하나 + * X 와 나머지 속성들로 구성된 릴레이션 하나 + + * 예시 + * nontrivial FD, 즉 서로의 부분 집합이 아닌 Instructor -> Course 를 찾았다. + * ```Instructor, Course, Student``` 한 개의 릴레이션을 두 개의 릴레이션으로 분해한다. + * Instructor 및 Course로 이루어진 릴레이션 + * Instructor 와 나머지 속성들로 구성된 릴레이션 + * Instructor, Student + * 분해한 두 개의 릴레이션에서 기존 릴레이션에서 결정자 역할을 했던 속성을 키로 해준다. 그러면 BCNF 까지 만족시키는 릴레이션 두 개가 생기게 된다. + + * 위 최종 테이블의 예시의 경우 학생과 강사를 직접 연결하고 있어, 다소 어색하다는 생각이 들 수 있다. 따라서 BCNF를 위반하지 않으려고 하나의 릴레이션에 모든 데이터 칼럼을 담기 보다는, BCNF를 만족하지 않았던 테이블의 데이터가 과목ID, 학생ID, 강사ID 를 외래키로 갖는 경우를 간접 참조하는 것이 좋겠다는 의견이 있다. + +### 참고한 자료 +* https://yaboong.github.io/database/2018/03/10/database-normalization-2/ +* http://www.vertabelo.com/blog/technical-articles/boyce-codd-normal-form-bcnf From b00165594d126e5c5a9b1741681ede7ec1762331 Mon Sep 17 00:00:00 2001 From: Jin Hyung Park Date: Mon, 19 Jul 2021 20:19:49 +0900 Subject: [PATCH 063/142] Create README.md --- database/join-in-sql/sigrid/README.md | 93 +++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 database/join-in-sql/sigrid/README.md diff --git a/database/join-in-sql/sigrid/README.md b/database/join-in-sql/sigrid/README.md new file mode 100644 index 0000000..0d0dcdd --- /dev/null +++ b/database/join-in-sql/sigrid/README.md @@ -0,0 +1,93 @@ +# JOIN 한 방에 정리하기 +![](https://i.imgur.com/qwGlsru.png) +* 깔끔하게 정리해보자. + +## LEFT JOIN & RIGHT JOIN +![](https://i.imgur.com/vpvJynA.png) + +#### A 테이블에 속한 것을 출력하는데, 이 때 A와 B의 교집합도 출력 +* A의 +``` +SELECT ---- +FROM -A- A LEFT JOIN -B- B +ON A.VALUE = B.VALUE +``` + +#### B 테이블에 속한 것을 출력하는데, 이 때 B와 A의 교집합도 출력 +``` +SELECT ---- +FROM -A- A RIGHT JOIN -B- B +ON A.VALUE = B.VALUE +``` + +### A 테이블에 속한 것을 출력하는데, A와 B의 교집합은 출력하지 않음 +![](https://i.imgur.com/Jwv3lJX.png) +``` +SELECT --- +FROM -A- A LEFT JOIN -B- B +ON A.VALUE = B.VALUE +WHERE B.VALUE IS NULL +``` + +### B 테이블에 속한 것을 출력하는데, B와 A의 교집합은 출력하지 않음 +``` +SELECT --- +FROM -A- A RIGHT JOIN -B- B +ON A.VALUE = B.VALUE +WHERE A.VALUE IS NULL +``` + +## INNER JOIN + +![](https://i.imgur.com/rb1x5Ah.png) + +#### 교집합만 출력 +``` +SELECT ---- +FROM -A- A INNER JOIN -B- B +ON A.VALUE = B.VALUE +``` + +## FULL OUTER JOIN +![](https://i.imgur.com/1GqOSTr.png) + +### 모두 다 출력 +``` +SELECT ---- +FROM -A- A FULL OUTER JOIN -B- B +ON A.VALUE = B.VALUE +``` +### 두 테이블의 교집합을 제외하고 출력 +![](https://i.imgur.com/BuzwD1h.png) +``` +SELECT ---- +FROM -A- A FULL OUTER JOIN -B- B +ON A.VALUE = B.VALUE +WHERE A.VALUE IS NULL OR B.VALUE IS NULL +``` + +## CROSS JOIN +#### Cartesian Product, 곧 곱집합이다. +* Cities 테이블 +![](https://i.imgur.com/mNiBHzI.png) +* Transport 테이블 +![](https://i.imgur.com/wsj8z8k.png) +* CROSS JOIN한 테이블 +![](https://i.imgur.com/EHN56mc.png) + +``` +SELECT * FROM cities CROSS JOIN transport; +SELECT * FROM cities JOIN transport; +SELECT * FROM cities, transport; +``` + +## SELF JOIN +#### 자기 자신과의 CROSS JOIN을 의미한다. +![](https://i.imgur.com/E4ovxoO.png) +``` +SELECT * FROM cities a (CROSS) JOIN cities b WHERE a.city <> b.city; +SELECT * FROM cities a, cities b WHERE a.city <> b.city; +``` +#### 사용 예제 +* SELF JOIN은 한 테이블 내의 row끼리 어떤 계산을 할 때 유용하게 쓰인다. +* 도시의 위,경도를 활용해 거리를 계산하는 예제이다. [링크](https://yahwang.github.io/posts/33) From 249ce82b0df73ee53036a5f9ef9eb95b5d8d33e6 Mon Sep 17 00:00:00 2001 From: 102092 Date: Tue, 27 Jul 2021 21:50:23 +0900 Subject: [PATCH 064/142] Add keys --- database/normalization/han/README.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/database/normalization/han/README.md b/database/normalization/han/README.md index 7266e39..cc89b4b 100644 --- a/database/normalization/han/README.md +++ b/database/normalization/han/README.md @@ -54,6 +54,13 @@ - 조건 - 제 1정규형을 만족하면서.. - 후보키의 집합에서, 키가 아닌 속성(Non-prime Attribute) 에 연결되어 있는 함수 종속성이 제거된 상태 + - 후보키는..? + - 그 릴레이션에 포함된 튜플의 값을 고유하게 하는 속성의 집합 + - 추가 속성이 없는 집합 + - 반면 슈퍼키는.. + - 슈퍼키도 튜플의 값을 고유하다는 점에서 후보키와 동일하지만, + - 추가 속성(고유한 값을 구하는데 도움되지 않는 값)을 가지고 있음. + - 그래서 후보키는 수퍼키의 일종이고, 다만 속성의 수가 최소한 - 만족하지 않는 형태 ![image](https://user-images.githubusercontent.com/22140570/126066572-f2aa8568-55aa-41d1-9ceb-1c7c1f671f4f.png) @@ -94,6 +101,18 @@ ![image](https://user-images.githubusercontent.com/22140570/126067720-ad5dbfb5-f697-4b48-ad9f-71871454cfa6.png) - 무손실 분해를 통해, 릴레이션을 나누고, 중복을 줄여주자 +## BCNF (보이스코드 정규형) +- 조건 + - 1, 2, 3 정규형 형태를 만족하면서.. + - 슈퍼키만 함수 종속하는 상태 +- 슈퍼키란? + - 각 행을 유일하게 식별할 수 있는 하나 또는 그 이상의 속성들의 집합 + - +- 만족하지 않는 형태 +![](https://i.imgur.com/qJamHf6.png) + - A, B 라는 후보키 외에, C 라는 속성을 통해, B를 찾을 수 있음. + - 슈퍼키로만 함수 종속이 유일하지 않다. + # 참고 - 관계형 데이터베이스 실전 입문 3장 - https://www.guru99.com/database-normalization.html From 7c7afca5102f5a3051140d2fc85384660c2e79ce Mon Sep 17 00:00:00 2001 From: 102092 Date: Tue, 27 Jul 2021 22:19:38 +0900 Subject: [PATCH 065/142] Add QnA --- database/normalization/han/README.md | 64 +++++++++++++++++----------- 1 file changed, 40 insertions(+), 24 deletions(-) diff --git a/database/normalization/han/README.md b/database/normalization/han/README.md index cc89b4b..e0163dc 100644 --- a/database/normalization/han/README.md +++ b/database/normalization/han/README.md @@ -23,9 +23,9 @@ - 2NF (Second Normal Form) - 3NF (Third Normal Form) - BCNF (Boyce-Codd Normal Form) - - 4NF (Fourth Normal Form) - - 5NF (Fifth Normal Form) - - 6NF (Sixth Normal Form) + - 4NF (Fourth Normal Form) --추후 + - 5NF (Fifth Normal Form) --추후 + - 6NF (Sixth Normal Form) --추후 - 특징 - 높은 단계의 정규형은 그 이전의 정규형 조건을 만족한다. - DB 설계에서 가장 중요한 정규형은 BCNF 와 5NF @@ -60,29 +60,23 @@ - 반면 슈퍼키는.. - 슈퍼키도 튜플의 값을 고유하다는 점에서 후보키와 동일하지만, - 추가 속성(고유한 값을 구하는데 도움되지 않는 값)을 가지고 있음. - - 그래서 후보키는 수퍼키의 일종이고, 다만 속성의 수가 최소한 + - 그래서 후보키는 수퍼키의 일종이고, 다만 속성의 수가 최소한임. - 만족하지 않는 형태 ![image](https://user-images.githubusercontent.com/22140570/126066572-f2aa8568-55aa-41d1-9ceb-1c7c1f671f4f.png) - Non trivial FD, 즉 자명하지 않는 함수 종속성이 존재한다. - - 위 릴레이션에서 어떤 함수 종속성이 존재하는가? - - 학번 -> 학부 - - 학번 -> 등록금 - - 학부 -> 등록금...등등 - - 학번 중복 - - 여기서 발생하는 중복을 줄여주면.. 제 2정규형을 만족할 수 있을듯 - - 어떻게 해결할 수 있을까? - - 한개의 릴레이션을, 여러개의 릴레이션으로 나누면 된다. (프로젝션) - - Non loss Decomposition을 생각하면서 릴레이션을 분해해야함. - - 즉 분해한 다음의 릴레이션에 포함된 정보를 이용해서, 원래의 릴레이션을 재구축 할 수 있어야함 - - - 다시 생각해보자.. - 1. 자명하지 않은 관계가 뭐가 있지? - 2. 과목코드랑 등록금. 성적과 학부. (다른 릴레이션을 가져야할듯) - 3. 그러면.. - - 학번 과목코드 성적 - - 학번 등록금 학부 - - 이렇게 나누면 될듯. + 1. {학번, 과목코드} : 키, {성적}, {학부}, {등록금} : 속성 + - 키 -> 속성 종속성이 있음. + 2. 그런데 부분 함수 종속성이 존재한다. + - {학번} -> {학부} + - {학번} -> {등록금} + - 중복이 존재한다. 학부, 등록금이 중복되어 들어가 있다 + 3. 제 2정규형에서는 부분 함수종속성 없애는 것이 핵심이다. 어떻게 없앨 것인가? + 4. 무손실 분해를 생각하면서 + 어떤 부분 함수 종속성이 있는지 생각하면서 + 5. 릴레이션을 나눈다. + - {학번, 과목코드} -> {성적} + - {학번} -> {학부}, {등록금} + - 만족하는 형태 ![image](https://user-images.githubusercontent.com/22140570/126067334-1adbf269-72ed-486c-8455-fdb703787a1b.png) @@ -107,7 +101,7 @@ - 슈퍼키만 함수 종속하는 상태 - 슈퍼키란? - 각 행을 유일하게 식별할 수 있는 하나 또는 그 이상의 속성들의 집합 - - + - 만족하지 않는 형태 ![](https://i.imgur.com/qJamHf6.png) - A, B 라는 후보키 외에, C 라는 속성을 통해, B를 찾을 수 있음. @@ -117,4 +111,26 @@ - 관계형 데이터베이스 실전 입문 3장 - https://www.guru99.com/database-normalization.html - https://lee-mandu.tistory.com/478?category=633572 -- https://yaboong.github.io/database/2018/03/09/database-normalization-1/ \ No newline at end of file +- https://yaboong.github.io/database/2018/03/09/database-normalization-1/ + +--- + +# QnA +![image](https://user-images.githubusercontent.com/22140570/127156592-c36bc217-08d7-46c1-8aaa-556d131862df.png) +- Trivial FD (Trivial Functional Dependecy) + - 자명한 함수 종속성 + - 자명한 함수 종속성은 릴레이션에서 제외될 수 없다는 특징을 가지고 있음. + - A -> B + - A 값을 알고 있으면 B를 알 수 있다. (B는 중복이 허용된다. 즉 C -> B 라는 릴레이션이 있다면, C를 통해 B 를 알아도 문제가 없다는 뜻) +- Non trivial FD + - 자명하지 않음 함수 종속성 + - A -> B 가 자명하지 않은 함수 종속성이면, A를 통해 B만 알 수 있는 것이 아닌, C도 D도 알 수 있다. + - 즉 A가 반복해서 나타난다. + +![image](https://user-images.githubusercontent.com/22140570/127156486-e78fdde3-0bdf-4b3e-9b20-b8fcc624739b.png) +- 부분 함수 종속성 + - 중복이 발생하고 있는 것. + - {이름, 학과} 라는 키가 있을 경우, {학년} 이라는 속성에 함수 종속성을 가지고 있음. + - 또한 {이름} -> {학년} 함수 종속이 함을 알 수 있고, 이름이 중복될 수 있기에, 여러 속성이 등록될 것임 (중복) + - 이 관계를 부분 함수 종속성을 가지고 있다고 말하는 듯. + - 제 2 정규형에서는 이러한 부분 함수 종속성을 없애는 (무손실 분해) 과정임. \ No newline at end of file From bb06352749dff0f2210ee5f0003609bb02eb7b6f Mon Sep 17 00:00:00 2001 From: Han Date: Tue, 27 Jul 2021 22:24:03 +0900 Subject: [PATCH 066/142] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c262ed6..2559a00 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # lets-cs ## 스터디 규칙 -- 일정 : 06.29 ~ 07.29 +- 일정 : 07.29 ~ 08.29 - 주제 : **데이터베이스** - 진행 방식 - 2주가 하나의 사이클 From 5f42856d7646538bb2a3c696ebdbc5a7b76cc067 Mon Sep 17 00:00:00 2001 From: Jin Hyung Park Date: Sun, 1 Aug 2021 13:10:19 +0900 Subject: [PATCH 067/142] =?UTF-8?q?feat:=20MySQL=20Query=20Plan=20?= =?UTF-8?q?=ED=95=99=EC=8A=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- database/mysql-query-plan/README.md | 237 ++++++++++++++++++++++++++++ 1 file changed, 237 insertions(+) create mode 100644 database/mysql-query-plan/README.md diff --git a/database/mysql-query-plan/README.md b/database/mysql-query-plan/README.md new file mode 100644 index 0000000..4438397 --- /dev/null +++ b/database/mysql-query-plan/README.md @@ -0,0 +1,237 @@ +# MySQL Query Plan +## MySQL Optimizer +* MySQL은 사용자가 요청한 쿼리 문장을 잘게 쪼개서 MySQL 서버가 이해할 수 있는 수준으로 나눈다. +* 이를 파싱이라고 하는데, 파싱 트리를 확인하면서 어느 테이블과 인덱스부터 읽는 것이 효율적인지 계산한다. + * 그래서 Client는 SQL 문장을 Parser에 전달하고 (1단계), + * Parser는 파싱 작업을 거쳐 Optimizer에게 전달한다. (2단계) + * Optimizer는 Query Plan을 작성하여 Executor에게 전달하고, Executor는 스토리지 엔진에서 결과 Set을 가져온다. (3단계) +![](https://i.imgur.com/ry2IEwt.png) + +* 만약 SQL 문법이 잘못되었다면 누가 에러를 반환할까? + * 파서가 반환한다. 파서가 문장을 분석하고 잘게 쪼개기 때문이다. +* 옵티마이저는 쿼리 플랜을 작성하는 데 있어 다음과 같은 사항을 고려한다. + * 불필요한 조건의 제거 및 복잡한 연산의 단순화 + * 여러 테이블의 조인이 있는 경우 어떤 순서로 테이블을 읽을지 결정 + * 각 테이블에 사용된 조건과 인덱스 통계 정보를 이용해 사용할 인덱스 결정 + * 가져온 레코드들을 임시 테이블에 넣고 다시 한번 가공해야 하는지 결정 +* 옵티마이저의 종류에는 무엇이 있을까? + * 1. 비용 기반 최적화(Cost-based optimizer, CBO) + * 쿼리를 처리할 수 있는 여러 가지 방법을 만든다. + * 각 단위 작업의 비용 정보 및 테이블의 통계 정보를 이용해 계획 별 비용을 산출한다. + * 2. 규칙 기반 최적화 방법(Rule-based optimizer, RBO) + * 거의 쓰이지 않는다. +* 대체 무슨 통계 정보(?)를 보고 쓴다는 것일까? + * 대략의 레코드 건수와 인덱스의 유니크한 값의 개수를 주로 참고한다. + * MySQL은 통계정보를 동적으로 관리하는 편이다. + * 오라클과 같은 전통적인 RDBMS는 통계정보만 따로 백업한다. + * 명령 중 'ANALYZE' 를 이용하면 통계 정보를 강제로 갱신할 수 있다. + * 인덱스 키값의 분포도(선택도)만 업데이트하며, 전체 테이블의 건수는 테이블의 전체 페이지 수를 이용해 예측한다. + * 예를 들어, InnoDB 테이블은 인덱스 페이지 중에서 8개 정도만 랜덤하게 선택해서 분석하고 그 결과를 인덱스의 통계 정보로 갱신한다. + +### EXPLAIN 명령 +* MySQL에서는 'EXPLAIN' 키워드를 이용해 실행계획에 대한 정보를 살펴 볼 수 있다. +* 테이블 구조가 다음과 같이 있다고 말해보자. + * member는 회원 정보이고, orders는 주문 목록, transaction은 해당 주문의 거래 정보이다. + +![](https://i.imgur.com/V3UwUaW.png) +* EXPLAIN 결과는 다음과 같이 나올 것이다. 여기서는 JSON 형식으로 출력된 결과에 대해 알아보자. +``` +explain +select m.*, o.*, t.* from member m +inner join orders o on m.id = o.member_id +inner join transaction t on o.transaction_id = t.id +where m.id in (1, 2, 33) +``` + +``` +{ + "query_block": { + "select_id": 1, + "cost_info": { + "query_cost": "449.03" + }, + "nested_loop": [ + { + "table": { + "table_name": "m", + "access_type": "range", + "possible_keys": [ + "PRIMARY" + ], + "key": "PRIMARY", + "used_key_parts": [ + "id" + ], + "key_length": "8", + "rows_examined_per_scan": 3, + "rows_produced_per_join": 3, + "filtered": "100.00", + "cost_info": { + "read_cost": "3.61", + "eval_cost": "0.60", + "prefix_cost": "4.21", + "data_read_per_join": "6K" + }, + "used_columns": [ + "id", + "email", + "name" + ], + "attached_condition": "(`sample`.`m`.`id` in (1,2,33))" + } + }, + { + "table": { + "table_name": "o", + "access_type": "ref", + "possible_keys": [ + "FKpktxwhj3x9m4gth5ff6bkqgeb", + "FKrylnffj7sn97iepyqadlfnsg0" + ], + "key": "FKpktxwhj3x9m4gth5ff6bkqgeb", + "used_key_parts": [ + "member_id" + ], + "key_length": "8", + "ref": [ + "sample.m.id" + ], + "rows_examined_per_scan": 90, + "rows_produced_per_join": 272, + "filtered": "100.00", + "cost_info": { + "read_cost": "63.00", + "eval_cost": "54.55", + "prefix_cost": "121.76", + "data_read_per_join": "279K" + }, + "used_columns": [ + "id", + "order_number", + "member_id", + "transaction_id" + ] + } + }, + { + "table": { + "table_name": "t", + "access_type": "eq_ref", + "possible_keys": [ + "PRIMARY" + ], + "key": "PRIMARY", + "used_key_parts": [ + "id" + ], + "key_length": "8", + "ref": [ + "sample.o.transaction_id" + ], + "rows_examined_per_scan": 1, + "rows_produced_per_join": 272, + "filtered": "100.00", + "cost_info": { + "read_cost": "272.73", + "eval_cost": "54.55", + "prefix_cost": "449.03", + "data_read_per_join": "820K" + }, + "used_columns": [ + "id", + "code", + "partner_transaction_id", + "payment_method_type" + ] + } + } + ] + } +} +``` + +#### Table +* 어느 테이블에 대한 접근을 하고 있는가? +* 여기서 m은 members, o는 orders, t는 transactions이다. + +#### ID +* id는 select 명령에 대한 순차적인 실행번호이다. +* Join은 개별적인 하나의 연산 단위로 취급하므로 모두 id가 1이라고 한다. (잘 이해가 안감.) + * 대신 서브쿼리가 있거나 UNION 연산이 있으면 id 안에서 2, 3...으로 내려갈 것이다. + +#### SELECT_TYPE +* select 문의 유형을 말한다. 각 유형은 아래와 같다 + * SIMPLE : 서브쿼리나 'union'이 없는 가장 단순한 select문을 말한다 + * ```SELECT * FROM USER;``` + * PRIMARY : 가장 바깥에 있는 select 문을 말한다 + * ```SELECT (요기) * FROM (SELECT * FROM USER) t;``` + * DERIVED : from 문 안에있는 서브쿼리의 select 문이다. + * ```SELECT * FROM (SELECT (요기) * FROM USER) t;``` + * SUBQUERY : 가장 바깥의 select 문에 있는 서브쿼리이다. + * DEPENDENT SUBQUERY : 기본적으로 SUBQUERY와 같은 유형이며, 가장 바깥의 select문에 '의존성'을 가진 서브쿼리의 select문이다. + ``` + SELECT * FROM user u1 WHERE EXISTS ( + SELECT * FROM user u2 WHERE u1.user_id = u2.user_id (요기) + ); + ``` + * UNCACHEABLE SUBQUERY + * UNION : union 문의 두번째 select 문을 말한다 + * DEPENDENT UNION : 바깥 쿼리에 의존성을 가진 union문의 두번째 select문을 말한다 + +#### type +* MySQL이 어떤식으로 테이블들을 조인하는지를 나타내는 항목이다. +* Type을 분석함으로써 어떤 인덱스가 사용되고 사용되지 않았는지를 알 수 있고, 이를 통해 어떤식으로 쿼리가 튜닝되어야 하는 지 분석할 수 있다. [출처](https://dev.mysql.com/doc/refman/8.0/en/explain-output.html) [출처 2](https://gradle.tistory.com/4) + * const: 하나의 매치되는 행만 존재하는 경우. 하나의 행이기 때문에 상수로 간주되며, 한번만 읽어들이기 때문에 무척 빠르다. + * eq_ref: 조인수행을 위해 각 테이블에서 하나의 행만이 읽혀지는 형태. const 타입 외에 가장 훌륭한 조인타입이다. + * It is used when all parts of an index are used by the join and the index is a PRIMARY KEY or UNIQUE NOT NULL index. + * ref: ref 조인에서 키의 가장 왼쪽 접두사 만 사용하거나 키가 PRIMARY KEY또는 UNIQUE 인덱스 가 아닌 경우 (즉, 조인이 키 값을 기반으로 단일 행을 선택할 수없는 경우) 사용된다. 사용되는 키가 몇 개의 행과 만 일치하는 경우 이는 좋은 조인 유형이다. + * index: 이 타입은 인덱스가 스캔되는걸 제외하면 ALL과 같다. 보통 인덱스 파일이 데이터 파일보다 작기 때문에 ALL보다 빠르다. 인덱스 스캔, 테이블의 특정 인덱스의 전체 엔트리에 접근한다. + * ALL: 이전 테이블과의 조인을 위해 풀스캔이 된다. 만약 조인에 쓰인 첫 테이블이 고정이 아니라면 비효율적이다. 그리고 대부분의 경우 아주 느리며, 보통 상수값이나 상수인 컬럼값으로 row를 추출하도록 인덱스를 추가하여 ALL 타입을 피할 수 있다. + * ref_or_null: 이 조인 유형은 ref와 비슷하지만 MySQL이 NULL값 을 포함하는 행을 추가로 검색한다는 점이 다르다. 이 조인 유형 최적화는 하위 쿼리를 해결하는 데 가장 자주 사용된다. + +* ALL, index 두 가지는 테이블 또는 특정 인덱스가 전체 행에 접근하기 때문에 테이블 크기가 크면 효율이 떨어진다. ref_or_null의 경우 NULL이 들어있는 행은 인덱스의 맨 앞에 모아서 저장하지만 그 건수가 많으면 MySQL 서버의 작업량이 방대해진다. 다시 말해서 ALL 이외의 접근 방식은 모두 인덱스를 사용한다. [출처](https://cheese10yun.github.io/mysql-explian/#explain-2) + +* 접근 방식이 ALL 또는 index인 경우는 그 쿼리로 사용할 수 있는 적절한 인덱스가 없다는 의미일 수도 있다. 위 쿼리에서 Country 테이블에 대한 접근은 ALL이지만 이는 WHERE 구의 조건을 지정하지 않았기 때문이다. 그러한 쿼리에서 드라이빙 테이블에 접근한다면 전체 행을 스캔 할수 밖에 없다. [출처](https://cheese10yun.github.io/mysql-explian/#explain-2) + +* 결론 +성능상 문제가 되는 부분은 index, all이 두가지 타입이 문제라는 것이다. + +#### key +possible_keys 필드에서 실제로 옵티마이저가 선택한 인덱스가 key가 된다. 위 EXPLAIN 에서는 County 테이블(첫 번째 행)의 Key는 NULL 인데 이는 행 데이터를 가져오기 위해 인덱스를 사용할 수 없다는 의미이다. + +#### extra +* EXPLAIN을 사용해 옵티마이저의 행동을 파악할 때 아주 중요하다. +* 특히 FileSort와 Using Temporary의 경우에는 쿼리 튜닝이 필요한 상태라는 의미이다. + +[출처](https://m.blog.naver.com/PostView.naver?isHttpsRedirect=true&blogId=websearch&logNo=221566208749) +* Using where + * 접근 방식을 설명한 것으로, 테이블에서 행을 가져온 후 추가적으로 검색조건을 적용해 행의 범위를 축소한 것을 표시한다. + * 인덱스에 포함된 컬럼들이 사용된 WHERE 조건들은 대부분 스토리지 엔진에서 인덱스를 읽을 때 체크되기 때문에 WHERE 절을 가진 쿼리가 모두 실행 계획상에 Using where 를 표시하는 것은 아니다. + * 때로는 Using where 가 있다는 사실이 다른 인덱스를 사용하면 쿼리를 더 효율적으로 만들 수 있다는 의미가 되기도 한다. +* Using index + * 테이블에는 접근하지 않고 인덱스에서만 접근해서 쿼티를 해결하는 것을 의미한다. 커버링 인덱스로 처리됨 index only scan이라고도 부른다 +* Using index for group-by + * Using index와 유사하지만 GROUP BY가 포함되어 있는 쿼리를 커버링 인덱스로 해결할 수 있음을 나타낸다 +* Using filesort + * ORDER BY 인덱스로 해결하지 못하고, filesort(MySQL의 quick sort)로 행을 정렬한 것을 나타낸다. MySQL 이 결과의 순서를 맞추기 위해 인덱스 순서로 테이블을 읽는 것이 아니라 외부 정렬을 사용해야 한다는 것을 의미한다. +* Using temporary + * MySQL 이 쿼리 결과를 정렬하기 위해 임시 테이블을 사용한다는 것을 의미한다. +* Using where with pushed + * 엔진 컨디션 pushdown 최적화가 일어난 것을 표시한다. 현재는 NDB만 유효 +* Using index condition + * 인덱스 컨디션 pushdown(ICP) 최적화가 일어났음을 표시한다. ICP는 멀티 칼럼 인덱스에서 왼쪽부터 순서대로 칼럼을 지정하지 않는 경우에도 인덱스를 이용하는 실행 계획이다. +* Using MRR + * 멀티 레인지 리드(MRR) 최적화가 사용되었음을 표시한다. +* Using join buffer(Block Nested Loop) + * 조인에 적절한 인덱스가 없어 조인 버퍼를 이용했음을 표시한다. +* Using join buffer(Batched Key Access) + * Batched Key Access(BKAJ) 알고리즘을 위한 조인 버퍼를 사용했음을 표시한다. + +### 기타 JOIN을 최적화하는 포인트? +* MySQL은 Nested Loop JOIN으로 되어있기 때문에 기준 테이블에서 조회되는 데이터양에 따라 연관 테이블의 데이터양이 결정되기 때문에 기준 테이블(왼쪽)의 데이터양을 줄이는 것이 관건이다. +* Outer Join은 지양한다. 꼭 필요한 경우만 사용한다. +* join시 조합 경우의 수를 줄이기 위해 복합 컬럼 index를 사용하는 것을 고려한다. + +## 기타 참고 사이트 +* https://wedul.site/452 +* https://cheese10yun.github.io/mysql-explian/#null From 5d05ceb0378a4b46b6e1722b5080320b921c99bd Mon Sep 17 00:00:00 2001 From: Jin Hyung Park Date: Sun, 1 Aug 2021 13:47:35 +0900 Subject: [PATCH 068/142] =?UTF-8?q?feat:=20=EB=8D=B0=EC=9D=B4=ED=84=B0?= =?UTF-8?q?=EB=B2=A0=EC=9D=B4=EC=8A=A4=EC=97=90=EC=84=9C=20=EC=82=AC?= =?UTF-8?q?=EC=9A=A9=EB=90=98=EB=8A=94=20=ED=82=A4=EC=9D=98=20=EC=A2=85?= =?UTF-8?q?=EB=A5=98=EC=99=80=20=EA=B0=9C=EB=85=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- database/type-of-keys/README.md | 174 ++++++++++++++++++++++++++++++++ 1 file changed, 174 insertions(+) create mode 100644 database/type-of-keys/README.md diff --git a/database/type-of-keys/README.md b/database/type-of-keys/README.md new file mode 100644 index 0000000..2adb754 --- /dev/null +++ b/database/type-of-keys/README.md @@ -0,0 +1,174 @@ +# 데이터베이스 논리적 모델: 키의 종류 +## 개론 +* 관계 데이터 모델 릴레이션의 특징 중 하나인 '튜플의 유일성' 은 키를 통하여 성취될 수 있다. +* 튜플의 유일성은 릴레이션에 똑같은 튜플이 존재하면 안되고, 모든 튜플에는 다른 튜플과 구별되는 유일한 특성이 있어야 된다는 것이었다. +* 이를 위하여 모든 속성을 이용하는 것보다 일부 속성만 이용하는 것이 효율성을 높일 수 있다. +* 이 때, 튜플들을 유일하게 구별해주는 역할은 속성 또는 속성들의 집합인 키가 한다. + +## Super Key +* 슈퍼키는 유일성의 특성을 만족하는 속성 또는 속성들의 집합이다. +* 유일성은 키가 갖추어야 하는 기본 특성으로, 하나의 릴레이션에서 키로 지정된 속성 값은 튜플마다 달라야 한다. + * 사용자의 이름 속성은 이름이 같은 사용자도 있을 수 있으므로 슈퍼키가 될 수 없다. + * 사용자 아이디는 모든 튜플을 구별할 수 있으므로 슈퍼키가 될 수 있다. + * 사용자 아이디 + 사용자 이름으로 구성된 속성 집합도 모든 튜플을 구별할 수 있다. 하지만, 불필요한 속성 값까지 확인하는 비효율적인 작업을 하게 된다. + +## Candidate Key +* 앞서 살펴보았듯이, 불필요한 속성 값까지 확인하는 비효율적인 작업을 하게되는 키가 존재한다. +* 그래서 꼭 필요한 속성의 집합만으로 튜플을 유일하게 구별할 수 있도록 하는 키가 후보키이다. 후보키는 유일성을 만족시키면서 동시에 최소성까지 만족하는 속성 또는 속성들의 집합이다. + * 최소성은 위에서 말한 것처럼 꼭 필요한 최소한의 속성들로만 키를 구성하여 튜플을 구별할 수 있게 하는 것을 말한다. +* 후보키가 되기 위해 만족해야 하는 유일성과 최소성의 특성은 새로운 튜플이 삽입되거나 기존 튜플의 속성 값이 바뀌어도 유지되어야 한다. + +## Primary Key +* 하나의 테이블에 존재하는 여러 후보키 중에서 기본적으로 사용할 키를 반드시 선택해야 하는데 이것을 기본키라고 한다. +* 기본키의 속성에는 다음을 고려하여야만 한다. + * 먼저, NULL 값을 가질 수 있는 속성이 포함된 후보키는 기본키로 부적합하다. 기본키가 NULL 값인 튜플은 다른 튜플들과 구별하여 접근하기 어려우므로 이런 가능성이 있는 키는 기본키로 선택하지 않는 것이 좋다. + * 값이 자주 변경될 수 있는 속성이 포함된 후보키는 기본키로 부적합하다. 기본키는 다른 튜플과 구별되는 값을 가지고 NULL 값은 허용하지 않으므로 이를 확인하는 작업이 필요한데, 만약 값이 자주 바뀐다면 기본키 값으로 적합한지를 지속해서 판단해야 하기 때문에 기본키로 부적합하다. + * 단순한 후보키를 기본키로 선택한다. + +## Alternate Key +* 대체키는 기본키로 선택되지 못한 후보키들이다. +* 대체키는 기본키를 대신할 수 있다. + +## Foreign Key +* 외래키는 어떤 릴레이션에 소속된 속성 또는 속성 집합이 다른 릴레이션의 기본키가 되는 키다. 즉, 다른 릴레이션의 기본키를 그대로 참조하는 속성의 집합이다. +* 외래키가 되는 속성과 기본키가 되는 속성의 이름은 달라도 된다. 하지만 외래키 속성의 도메인과 참조되는 기본키 속성의 도메인은 반드시 같아야 한다. + +![](https://i.imgur.com/HayFbDq.png) +[출처: 데이터베이스 개론 2판, 한빛아카데미](https://sangwoo0727.github.io/database/Database-4_key/) + +* 하나의 릴레이션에는 외래키가 여러 개 존재할 수도 있고, 외래키를 기본키로 사용할 수도 있고 외래키를 포함하여 기본키를 구성할 수도 있다. +* 추가로, 외래키는 반드시 다른 릴레이션을 참조할 필요는 없다. 참조하는 릴레이션과 참조되는 릴레이션이 같을 수도 있다. +* 외래키는 기본적으로는 기본키가 아니기 때문에 널 값을 가질 수도 있고 서로 다른 튜플이 같은 값을 가질 수도 있다. [스택 오버플로우 토론](https://stackoverflow.com/questions/7573590/can-a-foreign-key-be-null-and-or-duplicate) + +![](https://i.imgur.com/CTrl4om.png) + + +## Composite Key +* 두 개 이상의 컬럼이 합쳐져서 하나의 튜플을 구별할 수 있는 후보키가 될 수 있다고 할 때 우리는 이것을 복합키라고 부른다. +* 이전 스터디에서 (학번, 이름) 형태로 튜플로 묶어야 릴레이션에서 여러 칼럼을 독립적으로 구별할 수 있던 형태가 바로 복합키이다. +* 아래와 같이 주문 릴레이션에서 단일 속성으로는 튜플을 유일하게 식별하는 것이 불가능하므로 2개의 속성을 합한(고객번호, 도서번호)가 후보키가 되며 이렇게 2개 이상의 속성으로 이루어진 키를 복합키(Composite Key)이다. [출처](https://mangkyu.tistory.com/21) + +![](https://i.imgur.com/xKh7X8n.png) + +* 복합키의 속성들 중에서 먼저 정의한 속성에 대해서 클러스터드 인덱스[참고](https://gocoder.tistory.com/1826)가 정의되어지며, 주로 조회가 빈번하게 일어나는 속성을 먼저 정의하는 것이 좋다고 한다. +* JPA에서는 ```@IdClasss```, ```@EmbeddedID```를 이용하여 복합키를 매핑할 수 있다. [출처](https://techblog.woowahan.com/2595/) + +```java +// PayShop.java + +@Getter +@Entity +@NoArgsConstructor +public class PayShop { + + @EmbeddedId + private PayShopId id; + + private String shopName; + + @MapsId(value = "payId") + @ManyToOne(fetch = FetchType.LAZY) + private Pay pay; + + public PayShop(PayShopId id, + String shopName) { + this.id = id; + this.shopName = shopName; + } + + public void setPay(Pay pay) { + if (pay != null) { + pay.getPayShops().remove(this); + } + this.pay = pay; + this.pay.getPayShops().add(this); + } +} +// @MapsId 를 통해서 Pay에 있는 id 값을 자동으로 할동되게 할 수 있음. +``` +```java +//PayShopId.java +@Getter +@EqualsAndHashCode(onlyExplicitlyIncluded = true) +@Embeddable +@NoArgsConstructor +public class PayShopId implements Serializable { + + /** + * 테이블에서 정의하는 컬럼 사이즈 + */ + public static final int SHOP_NUMBER_SIZE = 12; + + @EqualsAndHashCode.Include + private PayDetailId payDetailId; + + @EqualsAndHashCode.Include + @Column + private String shopNumber; + + public PayShopId(PayDetailId payDetailId, + String shopNumber) { + Preconditions.checkArgument(shopNumber.length() <= SHOP_NUMBER_SIZE); + + this.payDetailId = payDetailId; + this.shopNumber = shopNumber; + } +} +// 위 예제와 같이 shopNubmer 라는 값의 컬럼사이즈를 초과해서 입력받아지지 않도록 체크를 할 수 있다. +``` + +## Surrogate Key vs Natural Key +### Surrogate Key 대체 키 +* 테이블을 이루는 컬럼들 가운데 유일하게 식별하기에 적합한 단일 후보키가 존재하지 않을 때, 임의의 식별번호로 이루어진 후보키를 추가할 수 있는데 이를 대체키라고 하다. [출처](https://ssayebee.github.io/wiki/surrogate_vs_natural_key.html) + * Surrogate key의 가장 큰 단점은 DB query가 복잡해진다는 점을 들수 있다. Business적으로 의미가 없는 key를 사용하기 때문에 간단한 query라도 join이 들어가게 되어서 복잡해지게 된다. +* 예를 들면 다음과 같다. [출처](https://rampart81.github.io/post/surrogate_key_vs_natural_key/) +``` +CREATE TABLE stock ( + id INT NOT NULL AUTO_INCREMENT, + ticker VARCHAR(20) NOT NULL, + price DECIMAL(35, 4), + PRIMARY KEY (ID) +); +``` +* id가 바로 surrogate key의 전형적인 예 이다. 여기서 id는 단순한 정수 값으로서 주식과는 아무 관련이 없는 정보지만 stock 테이블의 각 row를 대표하기 위한 id로 쓰인다. + +### Natural Key +* 테이블을 이루는 컬럼들 가운데 의미를 담고 있는 후보키 + * 아무리 고정 값의 필드를 자연키로 사용한다고 해도 대부분의 자연키는 언젠가 변할 수 있다. + * 또한, 만약 자연키가 문자열 이라면, 숫자 보다 비교를 하는데에 시간이 더 걸린다. +* 예를 들면 다음과 같다. +``` +CREATE TABLE stock ( + ticker VARCHAR(20) NOT NULL, + price DECIMAL(35, 4), + PRIMARY KEY (ticker) +); +``` +* id 필드를 없애고 대신에 ticker 필드를 primary key로 지정하였다. Surrogate key가 아니라 natural key를 primary key로 사용한 것이다. + * 위에서 설명한 첫 번째 단점이 여기서 부각된다. + * 주식 ticker도 값이 변할 수 있다. 예를 들어 LUCID 전기차 회사는 CCIV에서 LCID로 티커를 변경했다. + * 만일 ticker 값이 변하게 되면 그에 따른 관리를 해주는것이 굉장히 복잡하고 어려워질수 있다. + * 예를 들어, stock_info 와 portfolio 라는 table들이 stock table의 ticker 필드에 foreign key가 걸려 있다고 가정해보자. + * ticker 필드 값이 변하지 않으면 아무 문제 없지만 만일 ticker 값이 변해버리면 해당 ticker에 foreign key가 걸려있는 다른 table들의 row들도 전부 동시에 변경 해주어야 한다. + * 큰 규모의 실제 시스템에서는 DB 구조가 이보다 훨씬 복잡한 경우가 많으므로 모든 foreign key를 업데이트 시키는 일은 굉장히 어려워질수 있다. + * 이와 반면에 surrogate key는 변경되지 않는다. 처음부터 busienss 적인 의미가 없기 때문에 예상치 못하게 변경될 이유가 없는 것이다. + +### M:M 관계의 테이블이 있을 때, 대체 키를 이용할 것인가? 자연 키를 이용할 것인가? +* JPA 환경에서 대부분의 테이블을 별 생각없이 ```@GeneratedValue(strategy = GenerationType.IDENTITY)``` 해당 어노테이션을 사용해서 대체키를 이용해서 테이블을 만들었던 기억이 다들 있을 것이다. 꼭 그래야 하는가? +* Single Surrogate + * 모든 자식 테이블은 기본 키를 참조하기 위해서 단일 열만 필요로 한다. + * 외래 키로 모든 자식 테이블을 업데이트 할 필요 없이 테이블의 자연 키를 쉽게 업데이트 할 수 있다. + * 자연키 보다 더 많은 인덱스를 생성한다. +* Natural Composite key + * 인덱스를 덜 생성한다. + * 불필요한 열이 없어진다. + * 시퀀스 생성기가 필요 없기 떄문에 레코드 삽입이 빠르다. + * 복합키 중 하나를 업데이트 하면 모든 하위 테이블도 업데이트 해야한다. +* 요약 + * 복합키 VS 자연키 사용에 대한 질문은 데이터베이스 설계에 있어서 자주 다뤄지는 고전적인 주제라고 한다. + * 상황에 따라 어떤 것을 사용하는게 나을지 고민이 필요하다. + * Stack Overflow 에서는 대체키 사용을 추천했다. + +## 기타 참고 사이트 +* https://rampart81.github.io/post/surrogate_key_vs_natural_key/ +* https://ssayebee.github.io/wiki/surrogate_vs_natural_key.html From 415b59a715d80772ed878f0d312d1809a23d35c9 Mon Sep 17 00:00:00 2001 From: 102092 Date: Tue, 3 Aug 2021 20:04:34 +0900 Subject: [PATCH 069/142] Remove README files --- database/mysql-query-plan/README.md | 237 ---------------------------- database/type-of-keys/README.md | 174 -------------------- 2 files changed, 411 deletions(-) delete mode 100644 database/mysql-query-plan/README.md delete mode 100644 database/type-of-keys/README.md diff --git a/database/mysql-query-plan/README.md b/database/mysql-query-plan/README.md deleted file mode 100644 index 4438397..0000000 --- a/database/mysql-query-plan/README.md +++ /dev/null @@ -1,237 +0,0 @@ -# MySQL Query Plan -## MySQL Optimizer -* MySQL은 사용자가 요청한 쿼리 문장을 잘게 쪼개서 MySQL 서버가 이해할 수 있는 수준으로 나눈다. -* 이를 파싱이라고 하는데, 파싱 트리를 확인하면서 어느 테이블과 인덱스부터 읽는 것이 효율적인지 계산한다. - * 그래서 Client는 SQL 문장을 Parser에 전달하고 (1단계), - * Parser는 파싱 작업을 거쳐 Optimizer에게 전달한다. (2단계) - * Optimizer는 Query Plan을 작성하여 Executor에게 전달하고, Executor는 스토리지 엔진에서 결과 Set을 가져온다. (3단계) -![](https://i.imgur.com/ry2IEwt.png) - -* 만약 SQL 문법이 잘못되었다면 누가 에러를 반환할까? - * 파서가 반환한다. 파서가 문장을 분석하고 잘게 쪼개기 때문이다. -* 옵티마이저는 쿼리 플랜을 작성하는 데 있어 다음과 같은 사항을 고려한다. - * 불필요한 조건의 제거 및 복잡한 연산의 단순화 - * 여러 테이블의 조인이 있는 경우 어떤 순서로 테이블을 읽을지 결정 - * 각 테이블에 사용된 조건과 인덱스 통계 정보를 이용해 사용할 인덱스 결정 - * 가져온 레코드들을 임시 테이블에 넣고 다시 한번 가공해야 하는지 결정 -* 옵티마이저의 종류에는 무엇이 있을까? - * 1. 비용 기반 최적화(Cost-based optimizer, CBO) - * 쿼리를 처리할 수 있는 여러 가지 방법을 만든다. - * 각 단위 작업의 비용 정보 및 테이블의 통계 정보를 이용해 계획 별 비용을 산출한다. - * 2. 규칙 기반 최적화 방법(Rule-based optimizer, RBO) - * 거의 쓰이지 않는다. -* 대체 무슨 통계 정보(?)를 보고 쓴다는 것일까? - * 대략의 레코드 건수와 인덱스의 유니크한 값의 개수를 주로 참고한다. - * MySQL은 통계정보를 동적으로 관리하는 편이다. - * 오라클과 같은 전통적인 RDBMS는 통계정보만 따로 백업한다. - * 명령 중 'ANALYZE' 를 이용하면 통계 정보를 강제로 갱신할 수 있다. - * 인덱스 키값의 분포도(선택도)만 업데이트하며, 전체 테이블의 건수는 테이블의 전체 페이지 수를 이용해 예측한다. - * 예를 들어, InnoDB 테이블은 인덱스 페이지 중에서 8개 정도만 랜덤하게 선택해서 분석하고 그 결과를 인덱스의 통계 정보로 갱신한다. - -### EXPLAIN 명령 -* MySQL에서는 'EXPLAIN' 키워드를 이용해 실행계획에 대한 정보를 살펴 볼 수 있다. -* 테이블 구조가 다음과 같이 있다고 말해보자. - * member는 회원 정보이고, orders는 주문 목록, transaction은 해당 주문의 거래 정보이다. - -![](https://i.imgur.com/V3UwUaW.png) -* EXPLAIN 결과는 다음과 같이 나올 것이다. 여기서는 JSON 형식으로 출력된 결과에 대해 알아보자. -``` -explain -select m.*, o.*, t.* from member m -inner join orders o on m.id = o.member_id -inner join transaction t on o.transaction_id = t.id -where m.id in (1, 2, 33) -``` - -``` -{ - "query_block": { - "select_id": 1, - "cost_info": { - "query_cost": "449.03" - }, - "nested_loop": [ - { - "table": { - "table_name": "m", - "access_type": "range", - "possible_keys": [ - "PRIMARY" - ], - "key": "PRIMARY", - "used_key_parts": [ - "id" - ], - "key_length": "8", - "rows_examined_per_scan": 3, - "rows_produced_per_join": 3, - "filtered": "100.00", - "cost_info": { - "read_cost": "3.61", - "eval_cost": "0.60", - "prefix_cost": "4.21", - "data_read_per_join": "6K" - }, - "used_columns": [ - "id", - "email", - "name" - ], - "attached_condition": "(`sample`.`m`.`id` in (1,2,33))" - } - }, - { - "table": { - "table_name": "o", - "access_type": "ref", - "possible_keys": [ - "FKpktxwhj3x9m4gth5ff6bkqgeb", - "FKrylnffj7sn97iepyqadlfnsg0" - ], - "key": "FKpktxwhj3x9m4gth5ff6bkqgeb", - "used_key_parts": [ - "member_id" - ], - "key_length": "8", - "ref": [ - "sample.m.id" - ], - "rows_examined_per_scan": 90, - "rows_produced_per_join": 272, - "filtered": "100.00", - "cost_info": { - "read_cost": "63.00", - "eval_cost": "54.55", - "prefix_cost": "121.76", - "data_read_per_join": "279K" - }, - "used_columns": [ - "id", - "order_number", - "member_id", - "transaction_id" - ] - } - }, - { - "table": { - "table_name": "t", - "access_type": "eq_ref", - "possible_keys": [ - "PRIMARY" - ], - "key": "PRIMARY", - "used_key_parts": [ - "id" - ], - "key_length": "8", - "ref": [ - "sample.o.transaction_id" - ], - "rows_examined_per_scan": 1, - "rows_produced_per_join": 272, - "filtered": "100.00", - "cost_info": { - "read_cost": "272.73", - "eval_cost": "54.55", - "prefix_cost": "449.03", - "data_read_per_join": "820K" - }, - "used_columns": [ - "id", - "code", - "partner_transaction_id", - "payment_method_type" - ] - } - } - ] - } -} -``` - -#### Table -* 어느 테이블에 대한 접근을 하고 있는가? -* 여기서 m은 members, o는 orders, t는 transactions이다. - -#### ID -* id는 select 명령에 대한 순차적인 실행번호이다. -* Join은 개별적인 하나의 연산 단위로 취급하므로 모두 id가 1이라고 한다. (잘 이해가 안감.) - * 대신 서브쿼리가 있거나 UNION 연산이 있으면 id 안에서 2, 3...으로 내려갈 것이다. - -#### SELECT_TYPE -* select 문의 유형을 말한다. 각 유형은 아래와 같다 - * SIMPLE : 서브쿼리나 'union'이 없는 가장 단순한 select문을 말한다 - * ```SELECT * FROM USER;``` - * PRIMARY : 가장 바깥에 있는 select 문을 말한다 - * ```SELECT (요기) * FROM (SELECT * FROM USER) t;``` - * DERIVED : from 문 안에있는 서브쿼리의 select 문이다. - * ```SELECT * FROM (SELECT (요기) * FROM USER) t;``` - * SUBQUERY : 가장 바깥의 select 문에 있는 서브쿼리이다. - * DEPENDENT SUBQUERY : 기본적으로 SUBQUERY와 같은 유형이며, 가장 바깥의 select문에 '의존성'을 가진 서브쿼리의 select문이다. - ``` - SELECT * FROM user u1 WHERE EXISTS ( - SELECT * FROM user u2 WHERE u1.user_id = u2.user_id (요기) - ); - ``` - * UNCACHEABLE SUBQUERY - * UNION : union 문의 두번째 select 문을 말한다 - * DEPENDENT UNION : 바깥 쿼리에 의존성을 가진 union문의 두번째 select문을 말한다 - -#### type -* MySQL이 어떤식으로 테이블들을 조인하는지를 나타내는 항목이다. -* Type을 분석함으로써 어떤 인덱스가 사용되고 사용되지 않았는지를 알 수 있고, 이를 통해 어떤식으로 쿼리가 튜닝되어야 하는 지 분석할 수 있다. [출처](https://dev.mysql.com/doc/refman/8.0/en/explain-output.html) [출처 2](https://gradle.tistory.com/4) - * const: 하나의 매치되는 행만 존재하는 경우. 하나의 행이기 때문에 상수로 간주되며, 한번만 읽어들이기 때문에 무척 빠르다. - * eq_ref: 조인수행을 위해 각 테이블에서 하나의 행만이 읽혀지는 형태. const 타입 외에 가장 훌륭한 조인타입이다. - * It is used when all parts of an index are used by the join and the index is a PRIMARY KEY or UNIQUE NOT NULL index. - * ref: ref 조인에서 키의 가장 왼쪽 접두사 만 사용하거나 키가 PRIMARY KEY또는 UNIQUE 인덱스 가 아닌 경우 (즉, 조인이 키 값을 기반으로 단일 행을 선택할 수없는 경우) 사용된다. 사용되는 키가 몇 개의 행과 만 일치하는 경우 이는 좋은 조인 유형이다. - * index: 이 타입은 인덱스가 스캔되는걸 제외하면 ALL과 같다. 보통 인덱스 파일이 데이터 파일보다 작기 때문에 ALL보다 빠르다. 인덱스 스캔, 테이블의 특정 인덱스의 전체 엔트리에 접근한다. - * ALL: 이전 테이블과의 조인을 위해 풀스캔이 된다. 만약 조인에 쓰인 첫 테이블이 고정이 아니라면 비효율적이다. 그리고 대부분의 경우 아주 느리며, 보통 상수값이나 상수인 컬럼값으로 row를 추출하도록 인덱스를 추가하여 ALL 타입을 피할 수 있다. - * ref_or_null: 이 조인 유형은 ref와 비슷하지만 MySQL이 NULL값 을 포함하는 행을 추가로 검색한다는 점이 다르다. 이 조인 유형 최적화는 하위 쿼리를 해결하는 데 가장 자주 사용된다. - -* ALL, index 두 가지는 테이블 또는 특정 인덱스가 전체 행에 접근하기 때문에 테이블 크기가 크면 효율이 떨어진다. ref_or_null의 경우 NULL이 들어있는 행은 인덱스의 맨 앞에 모아서 저장하지만 그 건수가 많으면 MySQL 서버의 작업량이 방대해진다. 다시 말해서 ALL 이외의 접근 방식은 모두 인덱스를 사용한다. [출처](https://cheese10yun.github.io/mysql-explian/#explain-2) - -* 접근 방식이 ALL 또는 index인 경우는 그 쿼리로 사용할 수 있는 적절한 인덱스가 없다는 의미일 수도 있다. 위 쿼리에서 Country 테이블에 대한 접근은 ALL이지만 이는 WHERE 구의 조건을 지정하지 않았기 때문이다. 그러한 쿼리에서 드라이빙 테이블에 접근한다면 전체 행을 스캔 할수 밖에 없다. [출처](https://cheese10yun.github.io/mysql-explian/#explain-2) - -* 결론 -성능상 문제가 되는 부분은 index, all이 두가지 타입이 문제라는 것이다. - -#### key -possible_keys 필드에서 실제로 옵티마이저가 선택한 인덱스가 key가 된다. 위 EXPLAIN 에서는 County 테이블(첫 번째 행)의 Key는 NULL 인데 이는 행 데이터를 가져오기 위해 인덱스를 사용할 수 없다는 의미이다. - -#### extra -* EXPLAIN을 사용해 옵티마이저의 행동을 파악할 때 아주 중요하다. -* 특히 FileSort와 Using Temporary의 경우에는 쿼리 튜닝이 필요한 상태라는 의미이다. - -[출처](https://m.blog.naver.com/PostView.naver?isHttpsRedirect=true&blogId=websearch&logNo=221566208749) -* Using where - * 접근 방식을 설명한 것으로, 테이블에서 행을 가져온 후 추가적으로 검색조건을 적용해 행의 범위를 축소한 것을 표시한다. - * 인덱스에 포함된 컬럼들이 사용된 WHERE 조건들은 대부분 스토리지 엔진에서 인덱스를 읽을 때 체크되기 때문에 WHERE 절을 가진 쿼리가 모두 실행 계획상에 Using where 를 표시하는 것은 아니다. - * 때로는 Using where 가 있다는 사실이 다른 인덱스를 사용하면 쿼리를 더 효율적으로 만들 수 있다는 의미가 되기도 한다. -* Using index - * 테이블에는 접근하지 않고 인덱스에서만 접근해서 쿼티를 해결하는 것을 의미한다. 커버링 인덱스로 처리됨 index only scan이라고도 부른다 -* Using index for group-by - * Using index와 유사하지만 GROUP BY가 포함되어 있는 쿼리를 커버링 인덱스로 해결할 수 있음을 나타낸다 -* Using filesort - * ORDER BY 인덱스로 해결하지 못하고, filesort(MySQL의 quick sort)로 행을 정렬한 것을 나타낸다. MySQL 이 결과의 순서를 맞추기 위해 인덱스 순서로 테이블을 읽는 것이 아니라 외부 정렬을 사용해야 한다는 것을 의미한다. -* Using temporary - * MySQL 이 쿼리 결과를 정렬하기 위해 임시 테이블을 사용한다는 것을 의미한다. -* Using where with pushed - * 엔진 컨디션 pushdown 최적화가 일어난 것을 표시한다. 현재는 NDB만 유효 -* Using index condition - * 인덱스 컨디션 pushdown(ICP) 최적화가 일어났음을 표시한다. ICP는 멀티 칼럼 인덱스에서 왼쪽부터 순서대로 칼럼을 지정하지 않는 경우에도 인덱스를 이용하는 실행 계획이다. -* Using MRR - * 멀티 레인지 리드(MRR) 최적화가 사용되었음을 표시한다. -* Using join buffer(Block Nested Loop) - * 조인에 적절한 인덱스가 없어 조인 버퍼를 이용했음을 표시한다. -* Using join buffer(Batched Key Access) - * Batched Key Access(BKAJ) 알고리즘을 위한 조인 버퍼를 사용했음을 표시한다. - -### 기타 JOIN을 최적화하는 포인트? -* MySQL은 Nested Loop JOIN으로 되어있기 때문에 기준 테이블에서 조회되는 데이터양에 따라 연관 테이블의 데이터양이 결정되기 때문에 기준 테이블(왼쪽)의 데이터양을 줄이는 것이 관건이다. -* Outer Join은 지양한다. 꼭 필요한 경우만 사용한다. -* join시 조합 경우의 수를 줄이기 위해 복합 컬럼 index를 사용하는 것을 고려한다. - -## 기타 참고 사이트 -* https://wedul.site/452 -* https://cheese10yun.github.io/mysql-explian/#null diff --git a/database/type-of-keys/README.md b/database/type-of-keys/README.md deleted file mode 100644 index 2adb754..0000000 --- a/database/type-of-keys/README.md +++ /dev/null @@ -1,174 +0,0 @@ -# 데이터베이스 논리적 모델: 키의 종류 -## 개론 -* 관계 데이터 모델 릴레이션의 특징 중 하나인 '튜플의 유일성' 은 키를 통하여 성취될 수 있다. -* 튜플의 유일성은 릴레이션에 똑같은 튜플이 존재하면 안되고, 모든 튜플에는 다른 튜플과 구별되는 유일한 특성이 있어야 된다는 것이었다. -* 이를 위하여 모든 속성을 이용하는 것보다 일부 속성만 이용하는 것이 효율성을 높일 수 있다. -* 이 때, 튜플들을 유일하게 구별해주는 역할은 속성 또는 속성들의 집합인 키가 한다. - -## Super Key -* 슈퍼키는 유일성의 특성을 만족하는 속성 또는 속성들의 집합이다. -* 유일성은 키가 갖추어야 하는 기본 특성으로, 하나의 릴레이션에서 키로 지정된 속성 값은 튜플마다 달라야 한다. - * 사용자의 이름 속성은 이름이 같은 사용자도 있을 수 있으므로 슈퍼키가 될 수 없다. - * 사용자 아이디는 모든 튜플을 구별할 수 있으므로 슈퍼키가 될 수 있다. - * 사용자 아이디 + 사용자 이름으로 구성된 속성 집합도 모든 튜플을 구별할 수 있다. 하지만, 불필요한 속성 값까지 확인하는 비효율적인 작업을 하게 된다. - -## Candidate Key -* 앞서 살펴보았듯이, 불필요한 속성 값까지 확인하는 비효율적인 작업을 하게되는 키가 존재한다. -* 그래서 꼭 필요한 속성의 집합만으로 튜플을 유일하게 구별할 수 있도록 하는 키가 후보키이다. 후보키는 유일성을 만족시키면서 동시에 최소성까지 만족하는 속성 또는 속성들의 집합이다. - * 최소성은 위에서 말한 것처럼 꼭 필요한 최소한의 속성들로만 키를 구성하여 튜플을 구별할 수 있게 하는 것을 말한다. -* 후보키가 되기 위해 만족해야 하는 유일성과 최소성의 특성은 새로운 튜플이 삽입되거나 기존 튜플의 속성 값이 바뀌어도 유지되어야 한다. - -## Primary Key -* 하나의 테이블에 존재하는 여러 후보키 중에서 기본적으로 사용할 키를 반드시 선택해야 하는데 이것을 기본키라고 한다. -* 기본키의 속성에는 다음을 고려하여야만 한다. - * 먼저, NULL 값을 가질 수 있는 속성이 포함된 후보키는 기본키로 부적합하다. 기본키가 NULL 값인 튜플은 다른 튜플들과 구별하여 접근하기 어려우므로 이런 가능성이 있는 키는 기본키로 선택하지 않는 것이 좋다. - * 값이 자주 변경될 수 있는 속성이 포함된 후보키는 기본키로 부적합하다. 기본키는 다른 튜플과 구별되는 값을 가지고 NULL 값은 허용하지 않으므로 이를 확인하는 작업이 필요한데, 만약 값이 자주 바뀐다면 기본키 값으로 적합한지를 지속해서 판단해야 하기 때문에 기본키로 부적합하다. - * 단순한 후보키를 기본키로 선택한다. - -## Alternate Key -* 대체키는 기본키로 선택되지 못한 후보키들이다. -* 대체키는 기본키를 대신할 수 있다. - -## Foreign Key -* 외래키는 어떤 릴레이션에 소속된 속성 또는 속성 집합이 다른 릴레이션의 기본키가 되는 키다. 즉, 다른 릴레이션의 기본키를 그대로 참조하는 속성의 집합이다. -* 외래키가 되는 속성과 기본키가 되는 속성의 이름은 달라도 된다. 하지만 외래키 속성의 도메인과 참조되는 기본키 속성의 도메인은 반드시 같아야 한다. - -![](https://i.imgur.com/HayFbDq.png) -[출처: 데이터베이스 개론 2판, 한빛아카데미](https://sangwoo0727.github.io/database/Database-4_key/) - -* 하나의 릴레이션에는 외래키가 여러 개 존재할 수도 있고, 외래키를 기본키로 사용할 수도 있고 외래키를 포함하여 기본키를 구성할 수도 있다. -* 추가로, 외래키는 반드시 다른 릴레이션을 참조할 필요는 없다. 참조하는 릴레이션과 참조되는 릴레이션이 같을 수도 있다. -* 외래키는 기본적으로는 기본키가 아니기 때문에 널 값을 가질 수도 있고 서로 다른 튜플이 같은 값을 가질 수도 있다. [스택 오버플로우 토론](https://stackoverflow.com/questions/7573590/can-a-foreign-key-be-null-and-or-duplicate) - -![](https://i.imgur.com/CTrl4om.png) - - -## Composite Key -* 두 개 이상의 컬럼이 합쳐져서 하나의 튜플을 구별할 수 있는 후보키가 될 수 있다고 할 때 우리는 이것을 복합키라고 부른다. -* 이전 스터디에서 (학번, 이름) 형태로 튜플로 묶어야 릴레이션에서 여러 칼럼을 독립적으로 구별할 수 있던 형태가 바로 복합키이다. -* 아래와 같이 주문 릴레이션에서 단일 속성으로는 튜플을 유일하게 식별하는 것이 불가능하므로 2개의 속성을 합한(고객번호, 도서번호)가 후보키가 되며 이렇게 2개 이상의 속성으로 이루어진 키를 복합키(Composite Key)이다. [출처](https://mangkyu.tistory.com/21) - -![](https://i.imgur.com/xKh7X8n.png) - -* 복합키의 속성들 중에서 먼저 정의한 속성에 대해서 클러스터드 인덱스[참고](https://gocoder.tistory.com/1826)가 정의되어지며, 주로 조회가 빈번하게 일어나는 속성을 먼저 정의하는 것이 좋다고 한다. -* JPA에서는 ```@IdClasss```, ```@EmbeddedID```를 이용하여 복합키를 매핑할 수 있다. [출처](https://techblog.woowahan.com/2595/) - -```java -// PayShop.java - -@Getter -@Entity -@NoArgsConstructor -public class PayShop { - - @EmbeddedId - private PayShopId id; - - private String shopName; - - @MapsId(value = "payId") - @ManyToOne(fetch = FetchType.LAZY) - private Pay pay; - - public PayShop(PayShopId id, - String shopName) { - this.id = id; - this.shopName = shopName; - } - - public void setPay(Pay pay) { - if (pay != null) { - pay.getPayShops().remove(this); - } - this.pay = pay; - this.pay.getPayShops().add(this); - } -} -// @MapsId 를 통해서 Pay에 있는 id 값을 자동으로 할동되게 할 수 있음. -``` -```java -//PayShopId.java -@Getter -@EqualsAndHashCode(onlyExplicitlyIncluded = true) -@Embeddable -@NoArgsConstructor -public class PayShopId implements Serializable { - - /** - * 테이블에서 정의하는 컬럼 사이즈 - */ - public static final int SHOP_NUMBER_SIZE = 12; - - @EqualsAndHashCode.Include - private PayDetailId payDetailId; - - @EqualsAndHashCode.Include - @Column - private String shopNumber; - - public PayShopId(PayDetailId payDetailId, - String shopNumber) { - Preconditions.checkArgument(shopNumber.length() <= SHOP_NUMBER_SIZE); - - this.payDetailId = payDetailId; - this.shopNumber = shopNumber; - } -} -// 위 예제와 같이 shopNubmer 라는 값의 컬럼사이즈를 초과해서 입력받아지지 않도록 체크를 할 수 있다. -``` - -## Surrogate Key vs Natural Key -### Surrogate Key 대체 키 -* 테이블을 이루는 컬럼들 가운데 유일하게 식별하기에 적합한 단일 후보키가 존재하지 않을 때, 임의의 식별번호로 이루어진 후보키를 추가할 수 있는데 이를 대체키라고 하다. [출처](https://ssayebee.github.io/wiki/surrogate_vs_natural_key.html) - * Surrogate key의 가장 큰 단점은 DB query가 복잡해진다는 점을 들수 있다. Business적으로 의미가 없는 key를 사용하기 때문에 간단한 query라도 join이 들어가게 되어서 복잡해지게 된다. -* 예를 들면 다음과 같다. [출처](https://rampart81.github.io/post/surrogate_key_vs_natural_key/) -``` -CREATE TABLE stock ( - id INT NOT NULL AUTO_INCREMENT, - ticker VARCHAR(20) NOT NULL, - price DECIMAL(35, 4), - PRIMARY KEY (ID) -); -``` -* id가 바로 surrogate key의 전형적인 예 이다. 여기서 id는 단순한 정수 값으로서 주식과는 아무 관련이 없는 정보지만 stock 테이블의 각 row를 대표하기 위한 id로 쓰인다. - -### Natural Key -* 테이블을 이루는 컬럼들 가운데 의미를 담고 있는 후보키 - * 아무리 고정 값의 필드를 자연키로 사용한다고 해도 대부분의 자연키는 언젠가 변할 수 있다. - * 또한, 만약 자연키가 문자열 이라면, 숫자 보다 비교를 하는데에 시간이 더 걸린다. -* 예를 들면 다음과 같다. -``` -CREATE TABLE stock ( - ticker VARCHAR(20) NOT NULL, - price DECIMAL(35, 4), - PRIMARY KEY (ticker) -); -``` -* id 필드를 없애고 대신에 ticker 필드를 primary key로 지정하였다. Surrogate key가 아니라 natural key를 primary key로 사용한 것이다. - * 위에서 설명한 첫 번째 단점이 여기서 부각된다. - * 주식 ticker도 값이 변할 수 있다. 예를 들어 LUCID 전기차 회사는 CCIV에서 LCID로 티커를 변경했다. - * 만일 ticker 값이 변하게 되면 그에 따른 관리를 해주는것이 굉장히 복잡하고 어려워질수 있다. - * 예를 들어, stock_info 와 portfolio 라는 table들이 stock table의 ticker 필드에 foreign key가 걸려 있다고 가정해보자. - * ticker 필드 값이 변하지 않으면 아무 문제 없지만 만일 ticker 값이 변해버리면 해당 ticker에 foreign key가 걸려있는 다른 table들의 row들도 전부 동시에 변경 해주어야 한다. - * 큰 규모의 실제 시스템에서는 DB 구조가 이보다 훨씬 복잡한 경우가 많으므로 모든 foreign key를 업데이트 시키는 일은 굉장히 어려워질수 있다. - * 이와 반면에 surrogate key는 변경되지 않는다. 처음부터 busienss 적인 의미가 없기 때문에 예상치 못하게 변경될 이유가 없는 것이다. - -### M:M 관계의 테이블이 있을 때, 대체 키를 이용할 것인가? 자연 키를 이용할 것인가? -* JPA 환경에서 대부분의 테이블을 별 생각없이 ```@GeneratedValue(strategy = GenerationType.IDENTITY)``` 해당 어노테이션을 사용해서 대체키를 이용해서 테이블을 만들었던 기억이 다들 있을 것이다. 꼭 그래야 하는가? -* Single Surrogate - * 모든 자식 테이블은 기본 키를 참조하기 위해서 단일 열만 필요로 한다. - * 외래 키로 모든 자식 테이블을 업데이트 할 필요 없이 테이블의 자연 키를 쉽게 업데이트 할 수 있다. - * 자연키 보다 더 많은 인덱스를 생성한다. -* Natural Composite key - * 인덱스를 덜 생성한다. - * 불필요한 열이 없어진다. - * 시퀀스 생성기가 필요 없기 떄문에 레코드 삽입이 빠르다. - * 복합키 중 하나를 업데이트 하면 모든 하위 테이블도 업데이트 해야한다. -* 요약 - * 복합키 VS 자연키 사용에 대한 질문은 데이터베이스 설계에 있어서 자주 다뤄지는 고전적인 주제라고 한다. - * 상황에 따라 어떤 것을 사용하는게 나을지 고민이 필요하다. - * Stack Overflow 에서는 대체키 사용을 추천했다. - -## 기타 참고 사이트 -* https://rampart81.github.io/post/surrogate_key_vs_natural_key/ -* https://ssayebee.github.io/wiki/surrogate_vs_natural_key.html From ac88ec70adf848c55bf74fd0b0ea0b0a27d6baba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=B5=9C=ED=95=9C=EC=9A=B8?= Date: Tue, 20 Jul 2021 18:57:46 +0900 Subject: [PATCH 070/142] =?UTF-8?q?[7=EC=A3=BC=EC=B0=A8]=201,2,3=EC=B0=A8?= =?UTF-8?q?=20=EC=A0=95=EA=B7=9C=ED=99=94=EB=9E=80=3F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- database/normalization/hamill/README.md | 60 +++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 database/normalization/hamill/README.md diff --git a/database/normalization/hamill/README.md b/database/normalization/hamill/README.md new file mode 100644 index 0000000..b17aaf3 --- /dev/null +++ b/database/normalization/hamill/README.md @@ -0,0 +1,60 @@ +# 1,2,3차 정규화란 무엇인가? +그리고 정규화는 어떻게 이용 될 수 있을까? + +### 데이터베이스 정규화란? + +데이터베이스 정규화는 **데이터 중복을 줄이고 데이터 무결성을 개선하기 위해** 이른바 정규 형식(normal forms)에 따라 **데이터베이스(일반적으로 관계형 데이터베이스)를 구조화하는 프로세스**입니다. + +정규화에는 데이터베이스 무결성 제약 조건에 따라 종속성이 적절하게 적용되도록 데이터베이스의 열(어트리뷰트) 및 테이블(릴레이션)을 구성하는 작업이 수반됩니다. 이는 합성(새 데이터베이스 디자인 생성) 또는 분해(기존 데이터베이스 디자인 개선) 프로세스를 통해 일부 공식 규칙을 적용하여 수행됩니다. -Wikipedia- + +### 정규화를 하는 이유 + +테이블(릴레이션)을 수정(삽입, 삭제, 수정)하려고 할 때 충분히 정규화되지 않은 테이블(릴레이션)에서 다음과 같은 부작용(side-effects)이 발생 할 수 있습니다. + +- 삽입 이상(Insertion anomaly) : 새 데이터를 삽입하기 위해 불필요한 데이터도 함께 삽입해야 하는 문제 +- 삭제 이상(Deletion anomaly) : 중복 튜플 중 일부만 변경되어 데이터가 불일치하게 되는 문제 +- 갱신 이상(Update anomaly) : 튜플을 삭제하면 꼭 필요한 데이터까지 함께 삭제해야되는 데이터 손실 문제 + +### 제 1 정규화 만족(Satisfying 1NF) + +제 1 정규화란 테이블의 컬럼이 원자값(Atomic Value, 하나의 값)을 갖도록 테이블을 분해하는 것입니다. 예를 들어 아래와 같은 고객 취미 테이블이 존재한다고 하면, + +![https://s3-us-west-2.amazonaws.com/secure.notion-static.com/5e7484c1-0b14-4a20-82c1-1816137a8d0a/Untitled.png](https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbNbQUm%2FbtqT18yag04%2FpTXJX3wB23ouk8az7EgWQ1%2Fimg.png) + +위의 테이블에서 추신수와 박세리는 여러 개의 취미를 가지고 있기 때문에 제 1 정규형을 만족하지 못하고 있다고 할 수 있다. 그렇기 때문에 이를 제 1 정규화하여 분해 할 수 있다. 이를 변경하면 다음과 같다. + +![https://s3-us-west-2.amazonaws.com/secure.notion-static.com/b2997f98-5fd1-4fff-82af-aacc1233a086/Untitled.png](https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbMlNZj%2FbtqT17FWVot%2FjUKTAUyOdrH83pRraKw3K0%2Fimg.png) + +### 제 2 정규화 만족(Satisfying 2NF) + +제 2 정규화란 **제 1 정규화를 진행한 테이블에 대해 완전 함수 종속을 만족하도록 테이블을 분해**하는 것이다. 여기서 **완전 함수 종속이라는 것은 기본키의 부분집합이 결정자가 되어선 안된다는 것을 의미**한다. + +예를 들어 아래와 같은 수강 강좌 테이블을 살펴보면, + +![https://s3-us-west-2.amazonaws.com/secure.notion-static.com/1aae974c-310a-4796-a333-10c9a18ab0da/Untitled.png](https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FylbaZ%2FbtqT8Jc4K3s%2F0VFTPoKKFkbxZghKWDwKo1%2Fimg.png) + +이 테이블에서 기본키는 { 학생번호, 강좌이름 }으로 복합키다. 그리고 { 학생번호, 강좌이름 }인 기본키는 강의실을 결정하고 있다. { 학생번호, 강좌이름 } → { 강의실 } 그런데 여기서 강의실이라는 컬럼은 기본키의 부분집합인 강좌이름에 의해 결정 될 수 있다. { 강좌이름 } → { 강의실 } + +그렇기 때문에 위의 테이블의 경우 다음과 같이 기존의 테이블에서 강의실을 분해하여 별도의 테이블로 관리한다면 제 2 정규형을 만족시킬 수 있다. + +![https://s3-us-west-2.amazonaws.com/secure.notion-static.com/f6d89ef4-0e01-48ea-b51c-5884d0086b19/Untitled.png](https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbluCnc%2FbtqT7VEOf04%2FMe8DfY7rtycgJPYlYQKEWK%2Fimg.png) + +### 제 3 정규화 만족(Satisfying 3NF) + +제 3 정규화란 **제 2 정규화를 진행한 테이블에 대해 이행적 종속을 없애도록 테이블을 분해**하는 것이다. 여기서 이행적 종속이라는 것은 A → B, B → C가 성립할 때 A → C가 성립되는 것을 의미한다. + +예를 들어 아래와 같은 계절 학기 테이블을 살펴보면, + +![https://s3-us-west-2.amazonaws.com/secure.notion-static.com/9cc60a31-5204-49d0-b95b-f8088c58aee5/Untitled.png](https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FenwN1N%2FbtqUeiMyErd%2FsP8NKCe70NKsZncGuhO9uK%2Fimg.png) + +기존 테이블에서 학생 번호는 강좌 이름을 결정하고 있고, 강좌 이름은 수강료를 결정하고 있다. 그렇기 때문에 이를 { 학생 번호, 강좌 이름 } 테이블과 { 강좌 이름, 수강료 } 테이블로 분해해야 한다. + +이행적 종속을 제거하는 이유는 비교적 간단하다. 예를 들어 501번 학생이 수강하는 강좌가 스포츠경영학으로 변경되었다고 할 때, 이행적 종속이 존재한다면 501번 학생은 스포츠경영학이라는 수업을 2만원의 수강료로 듣게 된다. 물론 강좌 이름에 맞게 수강료를 다시 변경 할 수 있지만, 이러한 번거러움을 해결하기 위해 제 3 정규화를 하는 것이다. 즉, 학생 번호를 통해 강좌 이름을 참조하고, 강좌 이름으로 수강료를 참조하도록 테이블을 분해해야 하며 그 결과는 다음과 같다. + +![https://s3-us-west-2.amazonaws.com/secure.notion-static.com/8a117583-49b0-4581-a32f-f818b086270c/Untitled.png](https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fci1le3%2FbtqUeXnPnpD%2FyKkURqr8cZl21f5erx42QK%2Fimg.png) + +### 출처 + +- [https://en.wikipedia.org/wiki/Database_normalization](https://en.wikipedia.org/wiki/Database_normalization) +- [https://yaboong.github.io/database/2018/03/09/database-anomaly-and-functional-dependency/](https://yaboong.github.io/database/2018/03/09/database-anomaly-and-functional-dependency/) +- https://mangkyu.tistory.com/110 \ No newline at end of file From 6bd5111e78202e8a264fb3e65a7774bb1660b404 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=B5=9C=ED=95=9C=EC=9A=B8?= Date: Tue, 20 Jul 2021 19:16:14 +0900 Subject: [PATCH 071/142] =?UTF-8?q?[7=EC=A3=BC=EC=B0=A8]=20MySQL=20Join=20?= =?UTF-8?q?=EC=9D=B4=EB=9E=80=3F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- database/join-in-sql/hamill/README.md | 56 +++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 database/join-in-sql/hamill/README.md diff --git a/database/join-in-sql/hamill/README.md b/database/join-in-sql/hamill/README.md new file mode 100644 index 0000000..a253349 --- /dev/null +++ b/database/join-in-sql/hamill/README.md @@ -0,0 +1,56 @@ +# MySQL Join 은 무엇이고 어떤 것이 있을까? +### 개요 + +MySQL 조인에는 세 가지 유형이 있습니다. + +- MySQL INNER JOIN(또는 단순히 JOIN 이라고도 함) +- MySQL OUTER JOIN(또는 LEFT JOIN 이라고도 함) +- MySQL RIGHT OUTER JOIN(또는 RIGHT JOIN 이라고도 함) + +### MySQL INNER JOIN + +INNER JOIN은 조인 조건이 충족되는 여러 테이블의 모든 행을 반환하는데 사용됩니다. 가장 일반적인 조인 유형입니다. + +```sql +SELECT columns +FROM table1 +INNER JOIN table2 +ON table1.column = table2.column; +``` + +![https://static.javatpoint.com/mysql/images/image1.png](https://static.javatpoint.com/mysql/images/image1.png) + +### MySQL LEFT OUTER JOIN + +LEFT OUTER JOIN은 ON 조건에 지정된 왼쪽 테이블의 모든 행과 조인 조건이 충족되는 다른 테이블의 행만 반환합니다. + +```sql +SELECT columns +FROM table1 +LEFT [OUTER] JOIN table2 +ON table1.column = table2.column; +``` + +![https://static.javatpoint.com/mysql/images/image4.png](https://static.javatpoint.com/mysql/images/image4.png) + +### MySQL RIGHT OUTER JOIN + +RIGHT OUTER JOIN은 ON 조건에 지정된 오른쪽 테이블의 모든 행과 조인 조건이 충족되는 다른 테이블의 행만 반환합니다. + +```sql +SELECT columns +FROM table1 +RIGHT [OUTER] JOIN table2 +ON table1.column = table2.column; +``` + +![https://static.javatpoint.com/mysql/images/image7.png](https://static.javatpoint.com/mysql/images/image7.png) + +### 어떤 경우에 사용할까? + +조인은 일치하는 열을 기반으로 두 개 이상의 데이터베이스 테이블 간의 연결을 설정하여 테이블 간의 관계를 생성하기 위해 수행되는 SQL 작업입니다. 우리는 각각의 테이블에 대해서 조인을 사용하기도 하지만 정규화를 통해 분리한 테이블을 다시 합치는데 조인을 사용하기도 합니다. + +### 출처 + +- [https://www.javatpoint.com/mysql-join](https://www.javatpoint.com/mysql-join) +- [https://www.techopedia.com/definition/1213/join](https://www.techopedia.com/definition/1213/join) \ No newline at end of file From 12ad8f87fd13f0474e5aa3d00102c2853efd5317 Mon Sep 17 00:00:00 2001 From: 102092 Date: Mon, 2 Aug 2021 21:44:29 +0900 Subject: [PATCH 072/142] Add type of keys --- database/type-of-keys/han/README.md | 76 +++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 database/type-of-keys/han/README.md diff --git a/database/type-of-keys/han/README.md b/database/type-of-keys/han/README.md new file mode 100644 index 0000000..2f3f55a --- /dev/null +++ b/database/type-of-keys/han/README.md @@ -0,0 +1,76 @@ +# 데이터베이스에서 Key란? +- 데이터베이스 관리시스템에서 보통 키란, table (relation) 중 하나의 row (tuple) 가 유니크함을 나타내는 데 사용되는 속성을 의미하는 듯. +- 즉 해당 릴레이션에 똑같은 row (tuple) 이 존재하지 않음을 보장한다는 것. + +# 키의 종류 +- Primary Key, Candidate Key, Super Key, ForeignKey, Composite Key, Alternate Key, Unique Key, Natural Key.. + +# Primary key +- 보통 PK라 부른다. +- PK는 기본적으로 null 을 허용하거나, 중복을 허용하지 않는다. +- 즉 하나의 테이블에는, 그 PK가 유일함이 보장된다. +- 관계형 모델에는 기본키라는 개념이 없음. + - 릴레이션에 여러개의 후보키가 있는 경우, 이 키들은 의미적, 기능적으로 차이가 없고, 어느 키던지 아래 기본키로 설정할 수 있기 때문에 + +# Super key +- 슈퍼키 +- 슈퍼키는 모든 키들의 집합 +- 또한, 슈퍼키는 해당 row가 테이블에서 unique 함을 나타내는데 도와줌. +- 슈퍼키는 여러 가지 추가속성을 가지고 있음. + - 그리고 이 추가속성은 고유한 row를 나타냄에 있어 도움이 되지 않을 수도 있다. +- **참고 이미지** +![](https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F74FZR%2FbtqClyMJ0sx%2Fay7x7W2V3cWukTMoyYHp51%2Fimg.png) + - 후보키는 슈퍼키의 일종이며, 가지고 있는 추가속성의 수가 최소한 이다. + +# Candidate key +- 후보키 +- 릴레이션의 해당 row를 unique함을 나타낼 수 있는 속성들을 의미함. +- PK의 경우 , Candidate key 중 하나임. +- 후보키는 릴레이션에 한 개 이상 존재할 수 있다. + +# Alternate key +- 대체키 +- 후보키 중에서, PK로 선택받지 못한 키를 의미. + + +# Foreign key +- 외래키 +- 2개의 릴레이션(테이블) 의 관계를 정립하는 데 사용되는 키를 의미. +- 각각의 외래키는 보통 각 릴레이션의 PK에 해당할 것. + +# Composite key +- 복합키 +- 2개 혹은 더 많은 속성들로 이루어진 집합으로, 해당 row(tuple) 이 릴레이션에서 유니크함을 식별하는데 사용함. +- 각각의 속성을 나눠서 보면, 유니크하지 않을 수 있음 + - 즉 같이 합쳐서 있을 때, 집합으로 볼 때 유니크함이 보장됨을 알 수 있음. + +# Unique key +- 유니크 키 +- 릴레이션의 해당 row가 unique함을 나타낼 수 있음. +- PK란 다른점이라면.. nullable 하다는 점.. + - 그리고 PK는 테이블에서 하나의 컬럼에만 해당하지만, Unique 는 여러개 컬럼이 가능할듯..? +- 참고 + - https://blog.shovelman.dev/777 + +# Natural key +- 자연키 +- 이미 이 세상에 존재하는 어떤 단어나, 꼬리표를 키로 사용하는 것. +- 중복될 가능성이 있음. 예시 --> 사람 이름. +- 그럼 Natural key는 Database에서 PK로 사용될 수 없을까? + - 현실과 DB가 1:1 로 대응하고 있는 상황이라면.. ID로 사용해도 괜찮음. + +# Surrogate key +- 대체키 +- 릴레이션에 마땅한 후보키가 없을 경우, Database에서 식별을 위해 생성한, 선언된 키를 의미. +- 관계형 모델이는 자연키, 대체키란 개념이 없음. + - 관계형 모델이는 후보키, 슈포키 뿐이다. +- 참고 + - https://bunhere.tistory.com/45 + - https://www.toolbox.com/tech/data-management/question/the-difference-between-a-primary-key-and-a-surrogate-key-011407/ + +# 참고 +- https://www.upgrad.com/blog/types-of-keys-in-dbms/ +- https://kosaf04pyh.tistory.com/201 + +- 관계형 데이터 베이스 실전 입문 + - 3장, 6장 From 79847120e6505c21a094e454517e90b7aa47eaf4 Mon Sep 17 00:00:00 2001 From: 102092 Date: Mon, 2 Aug 2021 23:57:19 +0900 Subject: [PATCH 073/142] Add my sql query plan --- database/mysql-query-plan/han/README.md | 177 ++++++++++++++++++++++++ 1 file changed, 177 insertions(+) create mode 100644 database/mysql-query-plan/han/README.md diff --git a/database/mysql-query-plan/han/README.md b/database/mysql-query-plan/han/README.md new file mode 100644 index 0000000..162ce56 --- /dev/null +++ b/database/mysql-query-plan/han/README.md @@ -0,0 +1,177 @@ +# SELECT 쿼리 실행 순서 +- 작성하는 쿼리문의 순서와, 실제 DB에서 실행되는 순서가 다름. +- +- 보통 Select query 문법 순서 + 1. SELECT + 2. FROM + 3. WHERE + 4. GROUP BY + 5. ORDER BY +- 실제 실행 순서 + 1. FROM + - Sub Query.. 있으면 임시테이블 생성됨. + 2. ON + 3. JOIN + 4. WHERE + 5. GROUP BY + 6. HAVING + 7. SELECT + 8. DISTINCT + 9. ORDER BY + 10. LIMIT, OFFSET + +- 참고 + - https://dion-ko.tistory.com/85 + - https://daeuungcode.tistory.com/144 + + +# MySQL Explain +- 기본적으로 SELECT, INSERT, DELETE, REPLACE, UPDATE 쿼리문의 실행플랜을 분석하는 데 사용하는 키워드. +- 해당 쿼리를 실제 실행하는 것은 아니고, 데이터베이스에게 어떻게 실행할 건지 계획을 받아보는 방법임. +- 아래와 같이 사용함. +```sql +EXPLAIN +SELECT * +FROM foo +WHERE foo.bar = 'infrastructure as a service' OR foo.bar = 'iaas'; +``` +- `DESCRIBE` 라는 방법도 있는 데 이는 `Explain`이란 동일한 기능인듯. + - 참고 + - https://dev.mysql.com/doc/refman/5.7/en/describe.html + + +## Explain 결과 이해하기 + +### table +- 어떤 테이블에 접근하고 있는지 알려줌. + +### id +- SELECT를 몇번이나 실행하는 지의 숫자를 나타낸 값인듯. +- 해당 쿼리가 Subquery 또는 Union query를 포함하고 있지 않으면 항상 1의 값을 가짐. + +### select_type +- SELECT Query에 대한 타입 +- SIMPLE (서브쿼리, 유니온 쿼리 없이 실행된 쿼리) +- SUBQUERY +- UNION +- DERIVED +- 참고 + - https://dev.mysql.com/doc/refman/5.7/en/explain-output.html#explain_select_type + +### partitions +- 해당 테이블이 파티셔닝 되어있을 경우, 사용되는 필드 +- `NULL` 은 해당 쿼리에서 사용되는 테이블이 파티셔닝 되지 않았을을 의미 + + +### type +- 어떻게 해당 테이블에 접근하고 있는가를 나타낸 필드 +- 이 필드는 실행될 쿼리의 **효율성**을 판단하는 데 가장 중요한 필드 임 +- `system` + - 테이블에 하나의 row만 있을 경우 +- `const` + - 테이블에 하나의 매칭된 row만 있을 경우 + - 이 타입은 해당 쿼리가 굉장히 빠르게 실행될 수 있음을 의미 +- `eq_ref` + - 조인을 사용할 때 나타나는 타입 + - 이전 테이블과 조인을 할 때, 지금 테이블에서 하나의 로우만이 매칭된다는 의미인듯. + - **Join할 때의 best practice** + - 해당 row가 Prmiary key 혹은 Unique key이면서 NOT NULL인 인덱스 일 경우에 해당 타입이 사용됨. +- `ref` + - 조인을 사용할 때 나타나는 타입 + - Primary key, Unique key가 아닌 Key와 매칭되는 경우 + - 즉 조인할 때, 하나의 row만으로 되지 않는 경우 + - 만약에 매칭되는 row의 수가 적다면, 이 또한 조인할 경우 좋은 타입이라 말할 수 있음. +- `ref_or_null` + - `ref` 타입과 비슷 + - 그렇지만 해당 row `null` 이 포함된 row까지 탐색하고 있다는 뜻임. + ```sql + SELECT * FROM ref_table + WHERE key_column=expr OR key_column IS NULL; + ``` + - 아무래도 `null` 까지 탐색 조건에 들어가니, `ref` 타입보다는 별로이지 않을까. + +- `range` + - 인덱스를 사용해서, 특정 row 에 범위 접근할 때 사용되는 타입 + - Explain 결과 colum 중 `key` 는 해당 인덱스가 가리키고 있는 column임 + - `=`, `<>`, `>`, `>=`, `<`, `<=`, `IS NULL`, `<=>`, `BETWEEN`, `LIKE`, `IN()`, 연산자를 사용할 때 보통 나타나는 타입임 + ```sql + SELECT * FROM tbl_name + WHERE key_column = 10; + + SELECT * FROM tbl_name + WHERE key_column BETWEEN 10 and 20; + + SELECT * FROM tbl_name + WHERE key_column IN (10,20,30); + + SELECT * FROM tbl_name + WHERE key_part1 = 10 AND key_part2 IN (10,20,30); + ``` +- `ALL` + - 전체 행 스캔, 테이블에 존재하는 모든 데이터 접근 + - 대부분의 경우, 이 타입은 좋지 않음 + - 그래서 보통 인덱스를 추가하여, 해당 타입의 사용을 피함 +- `index` + - 인덱스 풀 스캔 + - 인덱스를 처음 부터 끝까지 검색하는 경우 + - 이 타입도 좋지 않음. + +- 참고 + - https://dev.mysql.com/doc/refman/5.7/en/explain-output.html#explain-join-types + +### possible_keys +- 사용 가능성이 있는 인덱스 목록을 말함. + +### key +- `possible_keys` 항목 중에, 실제 옵티마이저가 사용하겠다고 선택한 인덱스를 의미. +- 만약 컬럼이 `null` 이면, 인덱스를 사용할 수 없다는 의미인듯. + +### key_len +- `key` 필드 인덱스의 길이를 의미. +- 너무 길면 비효율적이다. + +### rows +- 이 전 컬럼들의 접근방식들을 이용하여, 데이터베이스에서 몇개의 row를 가지고 왔는지 의미하는 컬럼 +- 실제 행 수와는 반드시 일치하지는 않는다. + +### filtered +- `rows` 컬럼의 값이, WHERE 조건을 거쳤을 경우, 몇행이나 **남아있는지** 알려주는 컬럼. +- 실제 행 수와는 반드시 일치하지는 않는다. + +### extra +- 옵티마이저가 어떻게 동작할 지 알려주는 힌트. +- 이 컬럼이 `Using filesort` 나 `Using Temporary` 라는 값이면 해당 쿼리 실행에 성능적인 문제가 있을 수도 있음을 암시한다. + +- `Using filesort` + - `ORDERB BY` 조건에 있는 index를 사용할 수 없을 때, + - 해당 데이터의 정렬을 위해서, MySQL이 추가적인 작업이 필요함을 의미함. + - 모든 row를 읽고, sort key를 저장한다음에, 정렬하는 작업이 발생함. + - `sort_buffer_size` 만큼의 메모리 할당등이 필요하므로.. 엄청나게 많은 rows가 filesort 과정을 거친다면 데이터베이스에 부담이 될 수 있을듯. + - 참고 + - https://dev.mysql.com/doc/refman/5.7/en/order-by-optimization.html + +- `Using temporary` + - 이 쿼리를 위해, 임시적인 테이블 생성이 필요함을 의미. + - 보통 이 힌트는, 해당 쿼리의 `GROUP BY` 와 `ORDER BY`가 포함되어 있고, 다른 컬럼을 가르킬 경우 발생함. + +- `Using where` + - where 조건을 이용하여, `rows` 행을 `filterd` 하였음을 의미. + - `type` 이 `ALL` 혹은 `index` 타입이라면, 해당 쿼리에 뭔가 문제가 있다는 의미 + +- `Using index` + - 인덱스만을 가지고, 데이터를 추출했음을 의미함. + - `InnoDB` 의 경우, user-defined clustered index 를 가지고 있으면 그 인덱스가 `Extra` 에 나타나있지 않더라도, 사용되어질 수 있음. + - 단 그 type 은 `index` 이고, `key` 가 Primary일 경우 + + +# MySQL의 index 사용 +- 참고 + - https://stackoverflow.com/questions/586381/mysql-not-using-indexes-with-where-in-clause + + +# 참고 +- https://www.exoscale.com/syslog/explaining-mysql-queries/#:~:text=In%20MySQL%2C%20EXPLAIN%20can%20be,as%20a%20service'%20OR%20foo. +- https://cheese10yun.github.io/mysql-explian/ +- https://www.eversql.com/mysql-explain-example-explaining-mysql-explain-using-stackoverflow-data/ +- https://nomadlee.com/mysql-explain-sql/ +- https://www.sitepoint.com/using-explain-to-write-better-mysql-queries/#:~:text=Extra%20%E2%80%93%20contains%20additional%20information%20regarding,may%20indicate%20a%20troublesome%20query. \ No newline at end of file From 15dd32cffc906c1fcc5a506c33b4134dd6816a4f Mon Sep 17 00:00:00 2001 From: Jin Hyung Park Date: Tue, 3 Aug 2021 23:33:23 +0900 Subject: [PATCH 074/142] feat: MySQL Query Plan --- database/mysql-query-plan/sigrid/README.md | 237 +++++++++++++++++++++ 1 file changed, 237 insertions(+) create mode 100644 database/mysql-query-plan/sigrid/README.md diff --git a/database/mysql-query-plan/sigrid/README.md b/database/mysql-query-plan/sigrid/README.md new file mode 100644 index 0000000..4438397 --- /dev/null +++ b/database/mysql-query-plan/sigrid/README.md @@ -0,0 +1,237 @@ +# MySQL Query Plan +## MySQL Optimizer +* MySQL은 사용자가 요청한 쿼리 문장을 잘게 쪼개서 MySQL 서버가 이해할 수 있는 수준으로 나눈다. +* 이를 파싱이라고 하는데, 파싱 트리를 확인하면서 어느 테이블과 인덱스부터 읽는 것이 효율적인지 계산한다. + * 그래서 Client는 SQL 문장을 Parser에 전달하고 (1단계), + * Parser는 파싱 작업을 거쳐 Optimizer에게 전달한다. (2단계) + * Optimizer는 Query Plan을 작성하여 Executor에게 전달하고, Executor는 스토리지 엔진에서 결과 Set을 가져온다. (3단계) +![](https://i.imgur.com/ry2IEwt.png) + +* 만약 SQL 문법이 잘못되었다면 누가 에러를 반환할까? + * 파서가 반환한다. 파서가 문장을 분석하고 잘게 쪼개기 때문이다. +* 옵티마이저는 쿼리 플랜을 작성하는 데 있어 다음과 같은 사항을 고려한다. + * 불필요한 조건의 제거 및 복잡한 연산의 단순화 + * 여러 테이블의 조인이 있는 경우 어떤 순서로 테이블을 읽을지 결정 + * 각 테이블에 사용된 조건과 인덱스 통계 정보를 이용해 사용할 인덱스 결정 + * 가져온 레코드들을 임시 테이블에 넣고 다시 한번 가공해야 하는지 결정 +* 옵티마이저의 종류에는 무엇이 있을까? + * 1. 비용 기반 최적화(Cost-based optimizer, CBO) + * 쿼리를 처리할 수 있는 여러 가지 방법을 만든다. + * 각 단위 작업의 비용 정보 및 테이블의 통계 정보를 이용해 계획 별 비용을 산출한다. + * 2. 규칙 기반 최적화 방법(Rule-based optimizer, RBO) + * 거의 쓰이지 않는다. +* 대체 무슨 통계 정보(?)를 보고 쓴다는 것일까? + * 대략의 레코드 건수와 인덱스의 유니크한 값의 개수를 주로 참고한다. + * MySQL은 통계정보를 동적으로 관리하는 편이다. + * 오라클과 같은 전통적인 RDBMS는 통계정보만 따로 백업한다. + * 명령 중 'ANALYZE' 를 이용하면 통계 정보를 강제로 갱신할 수 있다. + * 인덱스 키값의 분포도(선택도)만 업데이트하며, 전체 테이블의 건수는 테이블의 전체 페이지 수를 이용해 예측한다. + * 예를 들어, InnoDB 테이블은 인덱스 페이지 중에서 8개 정도만 랜덤하게 선택해서 분석하고 그 결과를 인덱스의 통계 정보로 갱신한다. + +### EXPLAIN 명령 +* MySQL에서는 'EXPLAIN' 키워드를 이용해 실행계획에 대한 정보를 살펴 볼 수 있다. +* 테이블 구조가 다음과 같이 있다고 말해보자. + * member는 회원 정보이고, orders는 주문 목록, transaction은 해당 주문의 거래 정보이다. + +![](https://i.imgur.com/V3UwUaW.png) +* EXPLAIN 결과는 다음과 같이 나올 것이다. 여기서는 JSON 형식으로 출력된 결과에 대해 알아보자. +``` +explain +select m.*, o.*, t.* from member m +inner join orders o on m.id = o.member_id +inner join transaction t on o.transaction_id = t.id +where m.id in (1, 2, 33) +``` + +``` +{ + "query_block": { + "select_id": 1, + "cost_info": { + "query_cost": "449.03" + }, + "nested_loop": [ + { + "table": { + "table_name": "m", + "access_type": "range", + "possible_keys": [ + "PRIMARY" + ], + "key": "PRIMARY", + "used_key_parts": [ + "id" + ], + "key_length": "8", + "rows_examined_per_scan": 3, + "rows_produced_per_join": 3, + "filtered": "100.00", + "cost_info": { + "read_cost": "3.61", + "eval_cost": "0.60", + "prefix_cost": "4.21", + "data_read_per_join": "6K" + }, + "used_columns": [ + "id", + "email", + "name" + ], + "attached_condition": "(`sample`.`m`.`id` in (1,2,33))" + } + }, + { + "table": { + "table_name": "o", + "access_type": "ref", + "possible_keys": [ + "FKpktxwhj3x9m4gth5ff6bkqgeb", + "FKrylnffj7sn97iepyqadlfnsg0" + ], + "key": "FKpktxwhj3x9m4gth5ff6bkqgeb", + "used_key_parts": [ + "member_id" + ], + "key_length": "8", + "ref": [ + "sample.m.id" + ], + "rows_examined_per_scan": 90, + "rows_produced_per_join": 272, + "filtered": "100.00", + "cost_info": { + "read_cost": "63.00", + "eval_cost": "54.55", + "prefix_cost": "121.76", + "data_read_per_join": "279K" + }, + "used_columns": [ + "id", + "order_number", + "member_id", + "transaction_id" + ] + } + }, + { + "table": { + "table_name": "t", + "access_type": "eq_ref", + "possible_keys": [ + "PRIMARY" + ], + "key": "PRIMARY", + "used_key_parts": [ + "id" + ], + "key_length": "8", + "ref": [ + "sample.o.transaction_id" + ], + "rows_examined_per_scan": 1, + "rows_produced_per_join": 272, + "filtered": "100.00", + "cost_info": { + "read_cost": "272.73", + "eval_cost": "54.55", + "prefix_cost": "449.03", + "data_read_per_join": "820K" + }, + "used_columns": [ + "id", + "code", + "partner_transaction_id", + "payment_method_type" + ] + } + } + ] + } +} +``` + +#### Table +* 어느 테이블에 대한 접근을 하고 있는가? +* 여기서 m은 members, o는 orders, t는 transactions이다. + +#### ID +* id는 select 명령에 대한 순차적인 실행번호이다. +* Join은 개별적인 하나의 연산 단위로 취급하므로 모두 id가 1이라고 한다. (잘 이해가 안감.) + * 대신 서브쿼리가 있거나 UNION 연산이 있으면 id 안에서 2, 3...으로 내려갈 것이다. + +#### SELECT_TYPE +* select 문의 유형을 말한다. 각 유형은 아래와 같다 + * SIMPLE : 서브쿼리나 'union'이 없는 가장 단순한 select문을 말한다 + * ```SELECT * FROM USER;``` + * PRIMARY : 가장 바깥에 있는 select 문을 말한다 + * ```SELECT (요기) * FROM (SELECT * FROM USER) t;``` + * DERIVED : from 문 안에있는 서브쿼리의 select 문이다. + * ```SELECT * FROM (SELECT (요기) * FROM USER) t;``` + * SUBQUERY : 가장 바깥의 select 문에 있는 서브쿼리이다. + * DEPENDENT SUBQUERY : 기본적으로 SUBQUERY와 같은 유형이며, 가장 바깥의 select문에 '의존성'을 가진 서브쿼리의 select문이다. + ``` + SELECT * FROM user u1 WHERE EXISTS ( + SELECT * FROM user u2 WHERE u1.user_id = u2.user_id (요기) + ); + ``` + * UNCACHEABLE SUBQUERY + * UNION : union 문의 두번째 select 문을 말한다 + * DEPENDENT UNION : 바깥 쿼리에 의존성을 가진 union문의 두번째 select문을 말한다 + +#### type +* MySQL이 어떤식으로 테이블들을 조인하는지를 나타내는 항목이다. +* Type을 분석함으로써 어떤 인덱스가 사용되고 사용되지 않았는지를 알 수 있고, 이를 통해 어떤식으로 쿼리가 튜닝되어야 하는 지 분석할 수 있다. [출처](https://dev.mysql.com/doc/refman/8.0/en/explain-output.html) [출처 2](https://gradle.tistory.com/4) + * const: 하나의 매치되는 행만 존재하는 경우. 하나의 행이기 때문에 상수로 간주되며, 한번만 읽어들이기 때문에 무척 빠르다. + * eq_ref: 조인수행을 위해 각 테이블에서 하나의 행만이 읽혀지는 형태. const 타입 외에 가장 훌륭한 조인타입이다. + * It is used when all parts of an index are used by the join and the index is a PRIMARY KEY or UNIQUE NOT NULL index. + * ref: ref 조인에서 키의 가장 왼쪽 접두사 만 사용하거나 키가 PRIMARY KEY또는 UNIQUE 인덱스 가 아닌 경우 (즉, 조인이 키 값을 기반으로 단일 행을 선택할 수없는 경우) 사용된다. 사용되는 키가 몇 개의 행과 만 일치하는 경우 이는 좋은 조인 유형이다. + * index: 이 타입은 인덱스가 스캔되는걸 제외하면 ALL과 같다. 보통 인덱스 파일이 데이터 파일보다 작기 때문에 ALL보다 빠르다. 인덱스 스캔, 테이블의 특정 인덱스의 전체 엔트리에 접근한다. + * ALL: 이전 테이블과의 조인을 위해 풀스캔이 된다. 만약 조인에 쓰인 첫 테이블이 고정이 아니라면 비효율적이다. 그리고 대부분의 경우 아주 느리며, 보통 상수값이나 상수인 컬럼값으로 row를 추출하도록 인덱스를 추가하여 ALL 타입을 피할 수 있다. + * ref_or_null: 이 조인 유형은 ref와 비슷하지만 MySQL이 NULL값 을 포함하는 행을 추가로 검색한다는 점이 다르다. 이 조인 유형 최적화는 하위 쿼리를 해결하는 데 가장 자주 사용된다. + +* ALL, index 두 가지는 테이블 또는 특정 인덱스가 전체 행에 접근하기 때문에 테이블 크기가 크면 효율이 떨어진다. ref_or_null의 경우 NULL이 들어있는 행은 인덱스의 맨 앞에 모아서 저장하지만 그 건수가 많으면 MySQL 서버의 작업량이 방대해진다. 다시 말해서 ALL 이외의 접근 방식은 모두 인덱스를 사용한다. [출처](https://cheese10yun.github.io/mysql-explian/#explain-2) + +* 접근 방식이 ALL 또는 index인 경우는 그 쿼리로 사용할 수 있는 적절한 인덱스가 없다는 의미일 수도 있다. 위 쿼리에서 Country 테이블에 대한 접근은 ALL이지만 이는 WHERE 구의 조건을 지정하지 않았기 때문이다. 그러한 쿼리에서 드라이빙 테이블에 접근한다면 전체 행을 스캔 할수 밖에 없다. [출처](https://cheese10yun.github.io/mysql-explian/#explain-2) + +* 결론 +성능상 문제가 되는 부분은 index, all이 두가지 타입이 문제라는 것이다. + +#### key +possible_keys 필드에서 실제로 옵티마이저가 선택한 인덱스가 key가 된다. 위 EXPLAIN 에서는 County 테이블(첫 번째 행)의 Key는 NULL 인데 이는 행 데이터를 가져오기 위해 인덱스를 사용할 수 없다는 의미이다. + +#### extra +* EXPLAIN을 사용해 옵티마이저의 행동을 파악할 때 아주 중요하다. +* 특히 FileSort와 Using Temporary의 경우에는 쿼리 튜닝이 필요한 상태라는 의미이다. + +[출처](https://m.blog.naver.com/PostView.naver?isHttpsRedirect=true&blogId=websearch&logNo=221566208749) +* Using where + * 접근 방식을 설명한 것으로, 테이블에서 행을 가져온 후 추가적으로 검색조건을 적용해 행의 범위를 축소한 것을 표시한다. + * 인덱스에 포함된 컬럼들이 사용된 WHERE 조건들은 대부분 스토리지 엔진에서 인덱스를 읽을 때 체크되기 때문에 WHERE 절을 가진 쿼리가 모두 실행 계획상에 Using where 를 표시하는 것은 아니다. + * 때로는 Using where 가 있다는 사실이 다른 인덱스를 사용하면 쿼리를 더 효율적으로 만들 수 있다는 의미가 되기도 한다. +* Using index + * 테이블에는 접근하지 않고 인덱스에서만 접근해서 쿼티를 해결하는 것을 의미한다. 커버링 인덱스로 처리됨 index only scan이라고도 부른다 +* Using index for group-by + * Using index와 유사하지만 GROUP BY가 포함되어 있는 쿼리를 커버링 인덱스로 해결할 수 있음을 나타낸다 +* Using filesort + * ORDER BY 인덱스로 해결하지 못하고, filesort(MySQL의 quick sort)로 행을 정렬한 것을 나타낸다. MySQL 이 결과의 순서를 맞추기 위해 인덱스 순서로 테이블을 읽는 것이 아니라 외부 정렬을 사용해야 한다는 것을 의미한다. +* Using temporary + * MySQL 이 쿼리 결과를 정렬하기 위해 임시 테이블을 사용한다는 것을 의미한다. +* Using where with pushed + * 엔진 컨디션 pushdown 최적화가 일어난 것을 표시한다. 현재는 NDB만 유효 +* Using index condition + * 인덱스 컨디션 pushdown(ICP) 최적화가 일어났음을 표시한다. ICP는 멀티 칼럼 인덱스에서 왼쪽부터 순서대로 칼럼을 지정하지 않는 경우에도 인덱스를 이용하는 실행 계획이다. +* Using MRR + * 멀티 레인지 리드(MRR) 최적화가 사용되었음을 표시한다. +* Using join buffer(Block Nested Loop) + * 조인에 적절한 인덱스가 없어 조인 버퍼를 이용했음을 표시한다. +* Using join buffer(Batched Key Access) + * Batched Key Access(BKAJ) 알고리즘을 위한 조인 버퍼를 사용했음을 표시한다. + +### 기타 JOIN을 최적화하는 포인트? +* MySQL은 Nested Loop JOIN으로 되어있기 때문에 기준 테이블에서 조회되는 데이터양에 따라 연관 테이블의 데이터양이 결정되기 때문에 기준 테이블(왼쪽)의 데이터양을 줄이는 것이 관건이다. +* Outer Join은 지양한다. 꼭 필요한 경우만 사용한다. +* join시 조합 경우의 수를 줄이기 위해 복합 컬럼 index를 사용하는 것을 고려한다. + +## 기타 참고 사이트 +* https://wedul.site/452 +* https://cheese10yun.github.io/mysql-explian/#null From 427ebaa40fc70277d5eba58cf72507f068119cbe Mon Sep 17 00:00:00 2001 From: Jin Hyung Park Date: Tue, 3 Aug 2021 23:34:29 +0900 Subject: [PATCH 075/142] =?UTF-8?q?feat:=20Type=20of=20Keys=20=ED=95=99?= =?UTF-8?q?=EC=8A=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- database/type-of-keys/sigrid/README.md | 174 +++++++++++++++++++++++++ 1 file changed, 174 insertions(+) create mode 100644 database/type-of-keys/sigrid/README.md diff --git a/database/type-of-keys/sigrid/README.md b/database/type-of-keys/sigrid/README.md new file mode 100644 index 0000000..2adb754 --- /dev/null +++ b/database/type-of-keys/sigrid/README.md @@ -0,0 +1,174 @@ +# 데이터베이스 논리적 모델: 키의 종류 +## 개론 +* 관계 데이터 모델 릴레이션의 특징 중 하나인 '튜플의 유일성' 은 키를 통하여 성취될 수 있다. +* 튜플의 유일성은 릴레이션에 똑같은 튜플이 존재하면 안되고, 모든 튜플에는 다른 튜플과 구별되는 유일한 특성이 있어야 된다는 것이었다. +* 이를 위하여 모든 속성을 이용하는 것보다 일부 속성만 이용하는 것이 효율성을 높일 수 있다. +* 이 때, 튜플들을 유일하게 구별해주는 역할은 속성 또는 속성들의 집합인 키가 한다. + +## Super Key +* 슈퍼키는 유일성의 특성을 만족하는 속성 또는 속성들의 집합이다. +* 유일성은 키가 갖추어야 하는 기본 특성으로, 하나의 릴레이션에서 키로 지정된 속성 값은 튜플마다 달라야 한다. + * 사용자의 이름 속성은 이름이 같은 사용자도 있을 수 있으므로 슈퍼키가 될 수 없다. + * 사용자 아이디는 모든 튜플을 구별할 수 있으므로 슈퍼키가 될 수 있다. + * 사용자 아이디 + 사용자 이름으로 구성된 속성 집합도 모든 튜플을 구별할 수 있다. 하지만, 불필요한 속성 값까지 확인하는 비효율적인 작업을 하게 된다. + +## Candidate Key +* 앞서 살펴보았듯이, 불필요한 속성 값까지 확인하는 비효율적인 작업을 하게되는 키가 존재한다. +* 그래서 꼭 필요한 속성의 집합만으로 튜플을 유일하게 구별할 수 있도록 하는 키가 후보키이다. 후보키는 유일성을 만족시키면서 동시에 최소성까지 만족하는 속성 또는 속성들의 집합이다. + * 최소성은 위에서 말한 것처럼 꼭 필요한 최소한의 속성들로만 키를 구성하여 튜플을 구별할 수 있게 하는 것을 말한다. +* 후보키가 되기 위해 만족해야 하는 유일성과 최소성의 특성은 새로운 튜플이 삽입되거나 기존 튜플의 속성 값이 바뀌어도 유지되어야 한다. + +## Primary Key +* 하나의 테이블에 존재하는 여러 후보키 중에서 기본적으로 사용할 키를 반드시 선택해야 하는데 이것을 기본키라고 한다. +* 기본키의 속성에는 다음을 고려하여야만 한다. + * 먼저, NULL 값을 가질 수 있는 속성이 포함된 후보키는 기본키로 부적합하다. 기본키가 NULL 값인 튜플은 다른 튜플들과 구별하여 접근하기 어려우므로 이런 가능성이 있는 키는 기본키로 선택하지 않는 것이 좋다. + * 값이 자주 변경될 수 있는 속성이 포함된 후보키는 기본키로 부적합하다. 기본키는 다른 튜플과 구별되는 값을 가지고 NULL 값은 허용하지 않으므로 이를 확인하는 작업이 필요한데, 만약 값이 자주 바뀐다면 기본키 값으로 적합한지를 지속해서 판단해야 하기 때문에 기본키로 부적합하다. + * 단순한 후보키를 기본키로 선택한다. + +## Alternate Key +* 대체키는 기본키로 선택되지 못한 후보키들이다. +* 대체키는 기본키를 대신할 수 있다. + +## Foreign Key +* 외래키는 어떤 릴레이션에 소속된 속성 또는 속성 집합이 다른 릴레이션의 기본키가 되는 키다. 즉, 다른 릴레이션의 기본키를 그대로 참조하는 속성의 집합이다. +* 외래키가 되는 속성과 기본키가 되는 속성의 이름은 달라도 된다. 하지만 외래키 속성의 도메인과 참조되는 기본키 속성의 도메인은 반드시 같아야 한다. + +![](https://i.imgur.com/HayFbDq.png) +[출처: 데이터베이스 개론 2판, 한빛아카데미](https://sangwoo0727.github.io/database/Database-4_key/) + +* 하나의 릴레이션에는 외래키가 여러 개 존재할 수도 있고, 외래키를 기본키로 사용할 수도 있고 외래키를 포함하여 기본키를 구성할 수도 있다. +* 추가로, 외래키는 반드시 다른 릴레이션을 참조할 필요는 없다. 참조하는 릴레이션과 참조되는 릴레이션이 같을 수도 있다. +* 외래키는 기본적으로는 기본키가 아니기 때문에 널 값을 가질 수도 있고 서로 다른 튜플이 같은 값을 가질 수도 있다. [스택 오버플로우 토론](https://stackoverflow.com/questions/7573590/can-a-foreign-key-be-null-and-or-duplicate) + +![](https://i.imgur.com/CTrl4om.png) + + +## Composite Key +* 두 개 이상의 컬럼이 합쳐져서 하나의 튜플을 구별할 수 있는 후보키가 될 수 있다고 할 때 우리는 이것을 복합키라고 부른다. +* 이전 스터디에서 (학번, 이름) 형태로 튜플로 묶어야 릴레이션에서 여러 칼럼을 독립적으로 구별할 수 있던 형태가 바로 복합키이다. +* 아래와 같이 주문 릴레이션에서 단일 속성으로는 튜플을 유일하게 식별하는 것이 불가능하므로 2개의 속성을 합한(고객번호, 도서번호)가 후보키가 되며 이렇게 2개 이상의 속성으로 이루어진 키를 복합키(Composite Key)이다. [출처](https://mangkyu.tistory.com/21) + +![](https://i.imgur.com/xKh7X8n.png) + +* 복합키의 속성들 중에서 먼저 정의한 속성에 대해서 클러스터드 인덱스[참고](https://gocoder.tistory.com/1826)가 정의되어지며, 주로 조회가 빈번하게 일어나는 속성을 먼저 정의하는 것이 좋다고 한다. +* JPA에서는 ```@IdClasss```, ```@EmbeddedID```를 이용하여 복합키를 매핑할 수 있다. [출처](https://techblog.woowahan.com/2595/) + +```java +// PayShop.java + +@Getter +@Entity +@NoArgsConstructor +public class PayShop { + + @EmbeddedId + private PayShopId id; + + private String shopName; + + @MapsId(value = "payId") + @ManyToOne(fetch = FetchType.LAZY) + private Pay pay; + + public PayShop(PayShopId id, + String shopName) { + this.id = id; + this.shopName = shopName; + } + + public void setPay(Pay pay) { + if (pay != null) { + pay.getPayShops().remove(this); + } + this.pay = pay; + this.pay.getPayShops().add(this); + } +} +// @MapsId 를 통해서 Pay에 있는 id 값을 자동으로 할동되게 할 수 있음. +``` +```java +//PayShopId.java +@Getter +@EqualsAndHashCode(onlyExplicitlyIncluded = true) +@Embeddable +@NoArgsConstructor +public class PayShopId implements Serializable { + + /** + * 테이블에서 정의하는 컬럼 사이즈 + */ + public static final int SHOP_NUMBER_SIZE = 12; + + @EqualsAndHashCode.Include + private PayDetailId payDetailId; + + @EqualsAndHashCode.Include + @Column + private String shopNumber; + + public PayShopId(PayDetailId payDetailId, + String shopNumber) { + Preconditions.checkArgument(shopNumber.length() <= SHOP_NUMBER_SIZE); + + this.payDetailId = payDetailId; + this.shopNumber = shopNumber; + } +} +// 위 예제와 같이 shopNubmer 라는 값의 컬럼사이즈를 초과해서 입력받아지지 않도록 체크를 할 수 있다. +``` + +## Surrogate Key vs Natural Key +### Surrogate Key 대체 키 +* 테이블을 이루는 컬럼들 가운데 유일하게 식별하기에 적합한 단일 후보키가 존재하지 않을 때, 임의의 식별번호로 이루어진 후보키를 추가할 수 있는데 이를 대체키라고 하다. [출처](https://ssayebee.github.io/wiki/surrogate_vs_natural_key.html) + * Surrogate key의 가장 큰 단점은 DB query가 복잡해진다는 점을 들수 있다. Business적으로 의미가 없는 key를 사용하기 때문에 간단한 query라도 join이 들어가게 되어서 복잡해지게 된다. +* 예를 들면 다음과 같다. [출처](https://rampart81.github.io/post/surrogate_key_vs_natural_key/) +``` +CREATE TABLE stock ( + id INT NOT NULL AUTO_INCREMENT, + ticker VARCHAR(20) NOT NULL, + price DECIMAL(35, 4), + PRIMARY KEY (ID) +); +``` +* id가 바로 surrogate key의 전형적인 예 이다. 여기서 id는 단순한 정수 값으로서 주식과는 아무 관련이 없는 정보지만 stock 테이블의 각 row를 대표하기 위한 id로 쓰인다. + +### Natural Key +* 테이블을 이루는 컬럼들 가운데 의미를 담고 있는 후보키 + * 아무리 고정 값의 필드를 자연키로 사용한다고 해도 대부분의 자연키는 언젠가 변할 수 있다. + * 또한, 만약 자연키가 문자열 이라면, 숫자 보다 비교를 하는데에 시간이 더 걸린다. +* 예를 들면 다음과 같다. +``` +CREATE TABLE stock ( + ticker VARCHAR(20) NOT NULL, + price DECIMAL(35, 4), + PRIMARY KEY (ticker) +); +``` +* id 필드를 없애고 대신에 ticker 필드를 primary key로 지정하였다. Surrogate key가 아니라 natural key를 primary key로 사용한 것이다. + * 위에서 설명한 첫 번째 단점이 여기서 부각된다. + * 주식 ticker도 값이 변할 수 있다. 예를 들어 LUCID 전기차 회사는 CCIV에서 LCID로 티커를 변경했다. + * 만일 ticker 값이 변하게 되면 그에 따른 관리를 해주는것이 굉장히 복잡하고 어려워질수 있다. + * 예를 들어, stock_info 와 portfolio 라는 table들이 stock table의 ticker 필드에 foreign key가 걸려 있다고 가정해보자. + * ticker 필드 값이 변하지 않으면 아무 문제 없지만 만일 ticker 값이 변해버리면 해당 ticker에 foreign key가 걸려있는 다른 table들의 row들도 전부 동시에 변경 해주어야 한다. + * 큰 규모의 실제 시스템에서는 DB 구조가 이보다 훨씬 복잡한 경우가 많으므로 모든 foreign key를 업데이트 시키는 일은 굉장히 어려워질수 있다. + * 이와 반면에 surrogate key는 변경되지 않는다. 처음부터 busienss 적인 의미가 없기 때문에 예상치 못하게 변경될 이유가 없는 것이다. + +### M:M 관계의 테이블이 있을 때, 대체 키를 이용할 것인가? 자연 키를 이용할 것인가? +* JPA 환경에서 대부분의 테이블을 별 생각없이 ```@GeneratedValue(strategy = GenerationType.IDENTITY)``` 해당 어노테이션을 사용해서 대체키를 이용해서 테이블을 만들었던 기억이 다들 있을 것이다. 꼭 그래야 하는가? +* Single Surrogate + * 모든 자식 테이블은 기본 키를 참조하기 위해서 단일 열만 필요로 한다. + * 외래 키로 모든 자식 테이블을 업데이트 할 필요 없이 테이블의 자연 키를 쉽게 업데이트 할 수 있다. + * 자연키 보다 더 많은 인덱스를 생성한다. +* Natural Composite key + * 인덱스를 덜 생성한다. + * 불필요한 열이 없어진다. + * 시퀀스 생성기가 필요 없기 떄문에 레코드 삽입이 빠르다. + * 복합키 중 하나를 업데이트 하면 모든 하위 테이블도 업데이트 해야한다. +* 요약 + * 복합키 VS 자연키 사용에 대한 질문은 데이터베이스 설계에 있어서 자주 다뤄지는 고전적인 주제라고 한다. + * 상황에 따라 어떤 것을 사용하는게 나을지 고민이 필요하다. + * Stack Overflow 에서는 대체키 사용을 추천했다. + +## 기타 참고 사이트 +* https://rampart81.github.io/post/surrogate_key_vs_natural_key/ +* https://ssayebee.github.io/wiki/surrogate_vs_natural_key.html From 904826278e016fa1461f25577fd9103281b04f27 Mon Sep 17 00:00:00 2001 From: 102092 Date: Tue, 10 Aug 2021 20:06:38 +0900 Subject: [PATCH 076/142] Fix typo --- database/mysql-query-plan/han/README.md | 1 - database/type-of-keys/han/README.md | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/database/mysql-query-plan/han/README.md b/database/mysql-query-plan/han/README.md index 162ce56..e11a81d 100644 --- a/database/mysql-query-plan/han/README.md +++ b/database/mysql-query-plan/han/README.md @@ -1,6 +1,5 @@ # SELECT 쿼리 실행 순서 - 작성하는 쿼리문의 순서와, 실제 DB에서 실행되는 순서가 다름. -- - 보통 Select query 문법 순서 1. SELECT 2. FROM diff --git a/database/type-of-keys/han/README.md b/database/type-of-keys/han/README.md index 2f3f55a..b0ac811 100644 --- a/database/type-of-keys/han/README.md +++ b/database/type-of-keys/han/README.md @@ -63,7 +63,7 @@ - 대체키 - 릴레이션에 마땅한 후보키가 없을 경우, Database에서 식별을 위해 생성한, 선언된 키를 의미. - 관계형 모델이는 자연키, 대체키란 개념이 없음. - - 관계형 모델이는 후보키, 슈포키 뿐이다. + - 관계형 모델이는 후보키, 슈퍼키 뿐이다. - 참고 - https://bunhere.tistory.com/45 - https://www.toolbox.com/tech/data-management/question/the-difference-between-a-primary-key-and-a-surrogate-key-011407/ From c5ec9554752e9795350408889eeb3555c30e3390 Mon Sep 17 00:00:00 2001 From: 102092 Date: Tue, 10 Aug 2021 20:18:12 +0900 Subject: [PATCH 077/142] Add qna --- database/mysql-query-plan/han/README.md | 17 +++++++++++++++-- database/type-of-keys/han/README.md | 5 +++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/database/mysql-query-plan/han/README.md b/database/mysql-query-plan/han/README.md index e11a81d..9e8d701 100644 --- a/database/mysql-query-plan/han/README.md +++ b/database/mysql-query-plan/han/README.md @@ -167,10 +167,23 @@ WHERE foo.bar = 'infrastructure as a service' OR foo.bar = 'iaas'; - 참고 - https://stackoverflow.com/questions/586381/mysql-not-using-indexes-with-where-in-clause - # 참고 - https://www.exoscale.com/syslog/explaining-mysql-queries/#:~:text=In%20MySQL%2C%20EXPLAIN%20can%20be,as%20a%20service'%20OR%20foo. - https://cheese10yun.github.io/mysql-explian/ - https://www.eversql.com/mysql-explain-example-explaining-mysql-explain-using-stackoverflow-data/ - https://nomadlee.com/mysql-explain-sql/ -- https://www.sitepoint.com/using-explain-to-write-better-mysql-queries/#:~:text=Extra%20%E2%80%93%20contains%20additional%20information%20regarding,may%20indicate%20a%20troublesome%20query. \ No newline at end of file +- https://www.sitepoint.com/using-explain-to-write-better-mysql-queries/#:~:text=Extra%20%E2%80%93%20contains%20additional%20information%20regarding,may%20indicate%20a%20troublesome%20query + + +# QnA + +## DB를 파티셔닝 이유는 무엇일까? +![image](https://user-images.githubusercontent.com/22140570/128856777-91593f01-d816-4142-9466-fef0c48991f5.png) + +## 클러스트 인덱스이란? +![image](https://user-images.githubusercontent.com/22140570/128857129-a45f3917-8f68-40d9-bb5a-e283032ae69d.png) + + +## SIMPLE, SUBUQUERY, UNION의 차이점은 무엇인가요? +![image](https://user-images.githubusercontent.com/22140570/128857270-50b49979-3ee4-4628-b535-7f7a38c0e809.png) + diff --git a/database/type-of-keys/han/README.md b/database/type-of-keys/han/README.md index b0ac811..96e44da 100644 --- a/database/type-of-keys/han/README.md +++ b/database/type-of-keys/han/README.md @@ -74,3 +74,8 @@ - 관계형 데이터 베이스 실전 입문 - 3장, 6장 + +# QnA + +## 데이터베이스 최소성, 유일성? +![image](https://user-images.githubusercontent.com/22140570/128857368-49e05cde-7ecf-4eb8-a623-715b5d175444.png) \ No newline at end of file From d28d66b1ffef48381e8dc4eec530bd261794f85a Mon Sep 17 00:00:00 2001 From: Han Date: Tue, 10 Aug 2021 20:52:31 +0900 Subject: [PATCH 078/142] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 2559a00..d4d3a93 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ # lets-cs ## 스터디 규칙 -- 일정 : 07.29 ~ 08.29 -- 주제 : **데이터베이스** +- 일정 : 08.10 ~ 09.10 +- 주제 : **네트워크** - 진행 방식 - 2주가 하나의 사이클 - 1주차에는 질문에 대한 정리 및 PR, 2주차에는 PR 리뷰 및 수정을 진행 From d3e81fced7e57d740b9f80f9a1bba82f877b62ce Mon Sep 17 00:00:00 2001 From: Jin Hyung Park Date: Sat, 14 Aug 2021 18:13:36 +0900 Subject: [PATCH 079/142] =?UTF-8?q?feat:=20=EB=84=A4=ED=8A=B8=EC=9B=8C?= =?UTF-8?q?=ED=81=AC=20CORS=20=ED=95=99=EC=8A=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- network/cors/sigrid/README.md | 140 ++++++++++++++++++++++++++++++++++ 1 file changed, 140 insertions(+) create mode 100644 network/cors/sigrid/README.md diff --git a/network/cors/sigrid/README.md b/network/cors/sigrid/README.md new file mode 100644 index 0000000..c49a17c --- /dev/null +++ b/network/cors/sigrid/README.md @@ -0,0 +1,140 @@ +## 네트워크: CORS란 무엇인가 +### CORS: Cross-Origin Resource Sharing +#### Origin +* URL 구조에서 Protocol + Host + Port를 합친 것을 의미함 +```console +location.source +> https://hackmd.io +``` +* 간단한 퀴즈: 다음 중 같은 출처가 아닌 것은? + * ```https://hackmd.io/about```: 같은 출처 + * ```https://hackmd.io:32/about```: 다른 출처(Port 다름) + * ```http://hackmd.io```: 다른 출처(Protocol 다름) + +### Same-Origin Policy +* Postman으로 API를 호출하면 잘 되는데, 브라우저로 호출하면 CORS 에러가 나는 이유는 무엇일까? +* 브라우저가 동일 출처 정책(Same Origin Policy)를 준수하기 때문에 그렇다. +* 예를 들어 hackmd.io 사이트에서 medium.com의 API를 호출하면 서로 다른 출처이므로 CORS 에러가 발생할 수 있다. +* 동일 출처 정책은 XSS나 XSRF 등의 보안 취약점을 노린 공격을 방어할 수 있다. +* 하지만 외부 리소스를 사용해야 하는 경우는 매우 많다. SOP 정책의 예외 사항이 CORS라고 할 수 있다. + +### CORS 동작 원리 +* Simple Request와 Preflight Request가 있지만, 주로 Preflight Request 방식이 선호된다. + +![](https://i.imgur.com/Wv9msLm.png) +* Preflight 요청은 실제 리소스를 요청하기 전에 OPTIONS라는 메서드를 통해 실제 요청을 전송할지 판단한다. +* OPTIONS 메서드로 서버에 예비 요청을 먼저 보내고, 서버는 이 예비 요청에 대한 응답으로 Access-Control-Allow-Origin 헤더를 포함한 응답을 브라우저에 보낸다. +* 브라우저는 단순 요청과 동일하게 Access-Control-Allow-Origin 헤더를 확인해서 CORS 동작을 수행할지 판단한다. + +### CORS 에러 해결 방법 +* 서버에서 ```Access-Control-Allow-Origin``` 헤더를 포함한 응답을 브라우저에 보내는 방식으로 CORS 에러를 해결할 수 있다. +* Node.js 기준으로 cors라는 라이브러리가 있고, Spring Boot에서는 WebMvcController를 설정해주면 된다. + +#### Access-Control-Allow-Origin: | * +* 헤더가 작성된 링크만 브라우저가 접근할 수 있도록 설정할 수 있다. +* 사용 예시 +``` +Access-Control-Allow-Origin: https://medium.com +``` +``` +Access-Control-Allow-Origin: * // 와일드 카드를 쓰면 모든 사이트 다 된다 +``` +* 서버에서 아래와 같이 응답 헤더를 설정해서 보내주면 된다. +```javascript= +router.options('/cors', (req, res, next) => { + res.set('Access-Control-Allow-Origin', '*') + res.send() +}) +router.put('/cors', (req, res, next) => { + res.set('Access-Control-Allow-Origin', '*') + res.send() +}) +``` +#### Access-Control-Allow-Methods: [, ]* +* 리소스 접근을 허용하는 HTTP 메서드를 지정해 주는 헤더이다. +```javascript= +router.options('/cors', (req, res, next) => { + res.set('Access-Control-Allow-Origin', '*') + res.set('Access-Control-Allow-Methods', req.get('Access-Control-Request-Method')) + res.send() +}) +router.put('/cors', (req, res, next) => { + res.set('Access-Control-Allow-Origin', '*') + res.send() +}) +``` +#### Access-Control-Expose-Headers: [, ]* +* 서버에서 응답 헤더에 Access-Control-Expose-Headers를 추가해 줘야 브라우저의 자바스크립트에서 헤더에 접근할 수 있다. +```javascript= +router.options('/cors', (req, res, next) => { + res.set('Access-Control-Allow-Origin', '*') + res.set('Access-Control-Allow-Methods', req.get('Access-Control-Request-Method')) + res.send() +}) +router.put('/cors', (req, res, next) => { + res.set('Access-Control-Allow-Origin', '*') + res.set('Access-Control-Expose-Headers', 'X-Custom-Beomy') + res.set('X-Custom-Beomy', 'Bemoy') + res.send() +}) +``` + +#### Access-Control-Allow-Headers: [, ]* +* 브라우저에서 보내는 요청 헤더에 포함된 Access-Control-Request-Headers 헤더에 대한 응답 결과이다. +```javascript= +router.options('/cors', (req, res, next) => { + res.set('Access-Control-Allow-Origin', '*') + res.set('Access-Control-Allow-Methods', req.get('Access-Control-Request-Method')) + res.set('Access-Control-Allow-Headers', req.get('Access-Control-Request-Headers')) + res.send() +}) +router.put('/cors', (req, res, next) => { + res.set('Access-Control-Allow-Origin', '*') + console.log(req.get('X-Custom-Request')) // Beomy + res.send() +}) +``` +#### Access-Control-Max-Age: +* preflight 요청 결과를 캐시 할 수 있는 시간을 나타낸다. +* 아래와 같이 초 단위로 캐시 시간을 설정한다. +``` +Access-Control-Max-Age: 60 +``` +* 위의 코드는 60초 동안 preflight 요청을 캐시 하는 코드이다. +* 60초 동안 OPTIONS 메서드를 사용하는 예비 요청을 보내지 않습니다. +```javascript= +router.options('/cors', (req, res, next) => { + res.set('Access-Control-Allow-Origin', '*') + res.set('Access-Control-Allow-Methods', req.get('Access-Control-Request-Method')) + res.set('Access-Control-Max-Age', 60) + res.send() +}) +router.put('/cors', (req, res, next) => { + res.set('Access-Control-Allow-Origin', '*') + res.send() +}) +``` +#### Access-Control-Allow-Credentials: true +* 자바스크립트 요청에서 credentials가 include일 때 요청에 대한 응답을 할 수 있는지를 나타낸다. +* false로 설정해 주고 싶을 경우에는 헤더를 생략하면 된다. +```javascript= +router.options('/cors', (req, res, next) => { + res.set('Access-Control-Allow-Origin', 'https://www.google.com') + res.set('Access-Control-Allow-Methods', req.get('Access-Control-Request-Method')) + res.set('Access-Control-Allow-Credentials', true) + res.send() +}) +router.put('/cors', (req, res, next) => { + res.set('Access-Control-Allow-Origin', 'https://www.google.com') + res.set('Access-Control-Allow-Credentials', true) + res.send() +}) +``` +* Access-Control-Allow-Credentials: true 추가 뿐만 아니라, Access-Control-Allow-Origin 헤더도 와일드카드가 아닌 출처를 명시해주어야 한다. + +## 프록시 서버 +* 프론트엔드와 백엔드 사이에 프록시 서버를 두어서 CORS를 해결할 수 있다. +* 개발 환경에서는 Webpack Dev Server 등의 라이브러리를 사용하여 프록시 설정을 할 수 있다. + +## 참고 링크 +* https://beomy.github.io/tech/browser/cors/ From f5d38ec178fe120820ba264c6dce64d624466118 Mon Sep 17 00:00:00 2001 From: Jin Hyung Park Date: Sun, 15 Aug 2021 00:51:20 +0900 Subject: [PATCH 080/142] =?UTF-8?q?Revert=20"=EC=98=A4=ED=83=80=20?= =?UTF-8?q?=EC=88=98=EC=A0=95"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit b1167fb68585d803e35b000b9e823a9750b723c9. --- database/mysql-query-plan/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/database/mysql-query-plan/README.md b/database/mysql-query-plan/README.md index b086727..6baa63a 100644 --- a/database/mysql-query-plan/README.md +++ b/database/mysql-query-plan/README.md @@ -81,7 +81,7 @@ MySQL이 인덱스에 얼마나 많은 바이트를 사용하고 있는지를 ### rows -원하는 행을 찾기 위해 얼마나 많은 행을 읽어야 할지에 대한 예측값을 의미한다. +원하는 행을 찾기 위해 얼마나 많은 행을 읽어야 할지에 대한 예측값을 의미한ㄸ. ### extra From ce5f8f09c459707d7dd412cb730f5288c0578183 Mon Sep 17 00:00:00 2001 From: Jin Hyung Park Date: Sun, 15 Aug 2021 00:59:29 +0900 Subject: [PATCH 081/142] =?UTF-8?q?feat:=20=EB=84=A4=ED=8A=B8=EC=9B=8C?= =?UTF-8?q?=ED=81=AC=20Blocking=20vs=20Non-Blocking=20=ED=95=99=EC=8A=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../blocking-vs-nonblocking/sigrid/README.md | 285 ++++++++++++++++++ 1 file changed, 285 insertions(+) create mode 100644 network/blocking-vs-nonblocking/sigrid/README.md diff --git a/network/blocking-vs-nonblocking/sigrid/README.md b/network/blocking-vs-nonblocking/sigrid/README.md new file mode 100644 index 0000000..bf04cfc --- /dev/null +++ b/network/blocking-vs-nonblocking/sigrid/README.md @@ -0,0 +1,285 @@ +# Blocking vs Non-blocking +## Synchronous vs Asynchronous +### Synchronous +* 동기는 두 가지 이상의 작업이 서로 시간을 맞추어 행동하는 것을 의미한다. +* 호출한 함수가 다른 호출한 함수의 작업이 끝나 결과값을 반환하기를 기다리거나, 지속적으로 호출된 함수에게 확인 요청을 하는 경우가 있다. +* 작업 A와 작업 B가 있다고 가정하자. + * 작업 A와 작업 B의 시작 시간과 종료 시간이 같으면 동기라고 볼 수 있다. + * 쓰레드 A, 쓰레드 B가 동시에 작업을 시작하고 종료하는 경우 + * 메소드 리턴 시간 A와 결과를 전달받는 시간 B가 일치한 경우 + * 작업 A가 끝나는 시간과 작업 B가 시작하는 시간이 같으면 동기라고 볼 수 있다. + +### Asynchronous +* 비동기는 두 가지 이상의 작업을 할 때 대상들이 서로의 시간을 맞추지 않고 행동하는 것을 의미한다. +* 호출하는 함수가 호출되는 함수에게 작업을 맡겨놓고 더 이상 신경을 쓰지 않는 경우가 있다. + +### Blocking vs Non-Blocking +* 블록킹과 논블록킹은 직접 제어할 수 없는 대상을 어떻게 처리할 것인가에 따라 나눠지는 개념이다. +* 직접 제어할 수 없는 대상으로는 I/O, 멀티 쓰레드 동기화 등이 있다. + +#### Blocking +* 블록킹은 직접 제어할 수 없는 대상의 작업이 끝날 때까지 제어권을 넘겨주지 않는 것이다. +* 예를 들어 호출하는 함수가 I/O를 요청했을 때 I/O 처리가 완료될 때까지 아무 일도 하지 못한 채 기다리는 것을 말한다. + +#### Non-Blocking +* 논블록킹은 직접 제어할 수 없는 대상의 작업 처리 여부와 무관하게 처리하는 것을 의미한다. +* 예를 들어 호출하는 함수가 I/O를 요청했을 때 I/O 처리 여부와 상관없이 바로 자신의 작업을 할 수 있는 것을 말한다. + +#### Synchronous Blocking I/O +![](https://i.imgur.com/v6uOhUA.png) +```java= +device = IO.open() +// 이 Thread는 데이터를 읽을 때까지 아무 일도 할 수 없음 +data = device.read() +print(data) +``` +* Synchronous: 애플리케이션의 ```read()``` 메소드가 리턴하는 시간과 커널에서 결과를 가져오는 시간이 일치한다. +* Blocking: 커널의 작업이 완료될 때까지 대기한다. + +#### Synchronous Non-Blocking I/O +![](https://i.imgur.com/BRrD3I6.png) +```python= +device = IO.open() +ready = False +while not ready: + print("There is no data to read!") + + # 다른 작업을 처리할 수 있음 + + # while 문 내부의 다른 작업을 다 처리하면 데이터가 도착했는지 확인한다. + ready = IO.poll(device, IO.INPUT, 5) +data = device.read() +print(data) +``` +* Synchronous: read() 메서드(애플리케이션)가 리턴하는 시간과 커널에서 결과를 가져오는 시간이 일치한다. +* Non-Blocking: 애플리케이션으로부터 요청을 받은 커널은 작업 완료 여부와 상관없이 바로 반환하여 제어권을 애플리케이션에게 넘겨준다. 커널의 작업이 완료되면 작업 결과를 애플리케이션에게 반환한다. +* 대표적인 예로는 멀티플랙싱을 수행하는 select(), epoll() 함수가 있다. +* Application에서 I/O를 요청 후 바로 return되어 다른 작업을 수행하다가 특정 시간에 데이터가 준비가 다되었는지 상태를 확인한다. 데이터의 준비가 끝날 때까지 틈틈이 확인을 하다가 완료가 되었으면 종료된다. +* 여기서 주기적으로 체크하는 방식을 폴링(Polling) 이라고 한다. 그러나 이러한 방식은 작업이 완료되기 전까지 주기적으로 호출하기 때문에 불필요하게 자원을 사용하게 된다. + +#### Asynchronous Non-Blocking I/O (AIO) +![](https://i.imgur.com/GrI8VfR.png) +```python= +ios = IO.IOService() +device = IO.open(ios) + +def inputHandler(data, err): + "Input data handler" + if not err: + print(data) + +device.readSome(inputHandler) +# 이 thread는 데이터가 도착했는지 신경쓰지 않고 다른 작업을 처리할 수 있다. +ios.loop() +``` +* Asynchronous: readSome() 메서드(애플리케이션)가 리턴하는 시간과 커널에서 결과를 가져오는 시간이 일치하지 않는다. +* Non-Blocking: 애플리케이션으로부터 요청을 받은 커널은 작업 완료 여부와 상관없이 바로 반환하여 제어권을 애플리케이션에게 넘겨준다. 작업이 끝나면 애플리케이션에게 시그널 또는 콜백을 보낸다. +* 대표적인 예로는 윈도우에서 멀티플랙싱을 수행하는 IOCP가 있다. +* I/O 요청을 한 후 Non-Blocking I/O와 마찬가지고 즉시 리턴된다. 허나, 데이터 준비가 완료되면 이벤트가 발생하여 알려주거나, 미리 등록해놓은 callback을 통해서 이후 작업이 진행된다. 이전 두 I/O의 문제였던 Blocking이나 Polling이 없기 때문에 자원을 보다 더 효율적으로 사용할 수 있다. + +#### Asynchronous Blocking +* 비동기이면서도 블록킹을 하는 경우는 비효율적이므로 자주 사용되지 않는다고 한다. +* 하지만 Asynchronous Non-Blocking 모델 중에서 Blocking 형태로 동작하는 모델이 있는 경우 의도와 다르게 Asynchrnous Blocking으로 동작하는 경우가 있다고 한다. +* 예를 들어, Node.js는 비동기로 작업하려고 하지만 MySQL 드라이버가 Blocking 방식으로 동작하므로 어쩔 수 없이 Asynchronous Blocking 방식으로 동작한다고 한다. + +#### 본격 Case Study : 박 상병님, 저희 짬통 언제 버리러 가나요? +* Blocking & Synchronous +``` +김 일병 : 박 상병님, 오늘 짬통 언제 버리러 갑니까? +박 상병 : 있어봐, 중대 운전병에게 물어볼게. +김 일병 : (...) +대표님 : (수고하십니다 XX대대 상병 박공군입니다) +김 일병 : (과정 지켜봄.. 궁금함.. 계속 서 있음) +이 병장: 김 일병, 언제 버리러 가는거야? +김 일병: (박 상병님 전화 받고 있는 것을 수화기를 들고 같이 듣고 있음) 지금 전화 중이십니다. 잠시만 기다려주십시오. +이 병장: 오오 알겠어. +``` +* Blocking & Asynchronous +``` +김 일병 : 박 상병님, 오늘 짬통 언제 버리러 갑니까? +박 상병 : 있어봐, 중대 운전병에게 물어볼게. +김 일병 : (...) +대표님 : (수고하십니다 XX대대 상병 박공군입니다) +김 일병 : (과정 지켜봄.. 궁금함.. 계속 서 있음) +이 병장: 김 일병, 언제 버리러 가는거야? +김 일병: (아무런 일도 하지 않으며 말한다) 잘 모르겠습니다. 뭐 전화오면 박 상병님께서 알려주시지 않겠습니까? +이 병장: 흠.. 폐급인가? +``` + +* Non-blocking & Synchronous +``` +김 일병 : 박 상병님, 오늘 짬통 언제 버리러 갑니까? +박 상병 : 있어봐, 중대 운전병에게 물어볼게. +김 일병 : 넵! +박 상병 : (수고하십니다 XX대대 상병 박공군입니다) +김 일병 : 연락 되셨습니까? +박 상병 : 이병이 받던데. 좀 이따 해볼게. +김 일병 : 연락 되셨습니까? +박 상병 : 운전병 제초하러 갔대. 나중에 전화준댄다. +이 병장 : 김 일병, 언제 버리러 간대? +박 상병 : (...) +이 병장 : 이 폐급 새끼 또 내 말 씹네.. 존나 빡친다;; +김 일병 : 연락 되셨습니까? +박 상병 : ㅅㅂ 왜 자꾸 물어보냐 너 폐급이냐? 아직 전화 안왔다니까; +``` + +* Non-blocking & Asynchronous +``` +김 일병 : 박 상병님, 오늘 짬통 언제 버리러 갑니까? +박 상병 : 있어봐, 중대 운전병에게 물어볼게. +김 일병 : 넵! +박 상병 : (수고하십니다 XX대대 상병 박공군입니다) +박 상병 : 오늘 9시에 간댄다. 준비하자. +김 일병 : 넵! 짬통 일병들이랑 옮기고 있겠습니다. +``` + +#### 정리 +* Blocking/NonBlocking + * Blocking/NonBlocking은 호출되는 함수가 바로 리턴하느냐 마느냐가 관심사다. + * 호출된 함수가 바로 리턴해서 호출한 함수에게 제어권을 넘겨주고, 호출한 함수가 다른 일을 할 수 있는 기회를 줄 수 있으면 NonBlocking이다. + * 그렇지 않고 호출된 함수가 자신의 작업을 모두 마칠 때까지 호출한 함수에게 제어권을 넘겨주지 않고 대기하게 만든다면 Blocking이다. + +* Synchronous/Asynchronous + * Synchronous/Asynchronous는 호출되는 함수의 작업 완료 여부를 누가 신경쓰냐가 관심사다. + * 호출되는 함수에게 callback을 전달해서, 호출되는 함수의 작업이 완료되면 호출되는 함수가 전달받은 callback을 실행하고, 호출하는 함수는 작업 완료 여부를 신경쓰지 않으면 Asynchronous다. + * 호출하는 함수가 호출되는 함수의 작업 완료 후 리턴을 기다리거나, 또는 호출되는 함수로부터 바로 리턴 받더라도 작업 완료 여부를 호출하는 함수 스스로 계속 확인하며 신경쓰면 Synchronous다. + +### 추가 설명 +* Blocking 방식은 요청하고 응답 올때까지 기다리는 방식이고, Non-Blocking 방식은 요청하고 딴 일하다 나중에 응답신호가 오면 결과를 읽어 처리하는 방식이다. +* 동기방식은 요청자와 제공자사이에 계속 Connection이 맺어져 있어야 하고, 비동기방식은 Connection은 끊어지고 서로간에 이벤트를 통해 통신하는 방식이다. +* 비동기방식은 요청자와 제공자 사이에 Message Broker라는 또 다른 서비스가 중계해주지만, 동기 방식은 요청자 어플리케이션에 비동기 처리를 하는 로직이 있다. +* 최근 흔히 사용하는 REST API는 동기 방식이고 보통 Non-Blocking방식으로 통신한다. +* Frontend와 backend사이는 거의 대부분 동기+non-blocking 방식으로 구현한다. +* 비동기방식 패턴 중 제일 대표적인 것이 Publish/Subscribe (또는 Producer-Consumer) 패턴이다. + * Publisher인 유튜버들은 구독을 요청할 수 있는 채널을 만들고, 그 채널에 동영상을 계속 publishing해둔다. + * Subscriber인 사용자가 특정 유튜브채널을 구독 신청하면 새로운 동영상이 업로드 될때 첫화면에 추천동영상으로 받아보거나 모바일앱 알림 등으로 받아 볼 수 있게 된다. + * 즉, 사용자는 구독만 해놓고 있으면 새 동영상 올라올때까지 Youtube에 머물러 있을 필요가 없다. + * 비동기 메시징 방식은 추후 CS 스터디 주제로 발제할 생각이다. + * 이런 비동기 방식을 사용하는 이유는 큰 서비스를 이루는 마이크로서비스 중 하나가 실패해도 전체적인 서비스는 그대로 진행되도록 하기 위함이다. + * 예를 들어 쇼핑몰 상품 주문 시 주문서비스, 결제서비스, 배송서비스가 필요한데 동기방식으로 하면 결제나 배송 서비스에 문제가 생기면 상품 주문은 실패하게 된다. + * 그러나 비동기방식을 사용하면 Queue에 처리해야할 메시지가 있기 때문에 일시적 장애가 발생해도 복구가 되면 처리 가능하다. 따라서 상품 주문은 어떠한 경우에도 정상적으로 처리될 수 있게 된다. +* 일반적으로 Front와 Backend 서비스간에는 동기방식을 사용하고, backend의 서비스들간에는 비동기방식을 사용한다. +* 또한 데이터 조회 서비스는 동기방식을 사용하고, 데이터 변경 서비스는 비동기방식을 사용한다. + +### Spring WebFlux란 무엇일까? +* Non-blocking을 통해서 적은 수의 리소스로 동시성을 다룰 수 있게 해주는 프레임워크이다. +* 우리가 Spring MVC와 RDBMS를 사용하고 있으면 Blocking I/O를 사용하고 있는 것이다. +* Application에서 I/O 요청을 한 후 완료되기 전까지는 Application이 Block이 되어 다른 작업을 수행할 수 없다. 이는 해당 자원이 효율적으로 사용되지 못하고 있음을 의미한다. +* 물론, Blocking 방식임에도 불구하고 마치 Block이 안된듯이 동작하는 것처럼 보인다. 이는 멀티 쓰레드 기반의 방식이기 때문이다. 정확히는, 하나의 쓰레드가 블록되는 순간 다른 쓰레드가 동작하도록 함으로써 블록 문제를 해결하였다. +* 하지만 쓰레드 간의 Context Switching 등의 비용이 존재하므로, 여러 개의 I/O를 동시다발적으로 효율적인 처리를 하려면 논블로킹으로 처리해야만 한다. + +#### Blocking I/O 예시: RestTemplate +* RestTemplate은 Multi-Thread와 Blocking방식을 사용한다. +* Thread pool은 요청자 어플리케이션 구동시에 미리 만들어 놓는다. +* Request는 먼저 Queue에 쌓이고 가용한 스레드가 있으면 그 스레드에 할당되어 처리된다. +* 즉, 1 요청 당 1 스레드가 할당됩니다. +* 각 스레드에서는 Blocking방식으로 처리되어 응답이 올 때까지 그 스레드는 다른 요청에 할당될 수 없다. +* 아래는 RestTemplate을 Connection Pool에 Spring Bean으로 등록하기 위한 예제이다. + * 요청 당 20개의 RestTemplate client를 만들고, 최대 50개까지 증가할 수 있도록 했다. + +```java= +@Configuration +public class RestTemplateConfig { + public RestTemplate getRestTemplate(int defaultMaxPerRoute, int maxTotal) { + PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(); + connManager.setDefaultMaxPerRoute(defaultMaxPerRoute); + connManager.setMaxTotal(maxTotal); + + HttpClient client = HttpClientBuilder.create().setConnectionManager(connManager).build(); + + HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(client); + factory.setConnectTimeout(3000); + factory.setReadTimeout(3000); + + return new RestTemplate(factory); + + } + + @Bean + public RestTemplate coffeeRestTemplate() { + return getRestTemplate(20, 50); + } +} +``` +* 요청을 처리할 스레드가 있으면 아무런 문제가 없지만, 스레드가 다 차는 경우 이후의 요청은 Queue에 대기하게 된다. +* 대부분의 문제는 네트워킹이나 DB와의 통신에서 생기는데 이런 문제가 여러 스레드에서 발생하면 가용한 스레드수가 현저하게 줄어들게 되고, 결국 전체 서비스는 매우 느려지게 된다. +* RestTemplate을 이용하여 API 중 응답 시간이 약 3초 정도 걸리는 요청을 3번 반복하는 예제를 제시한다. +```java= +@Test +public void blocking() { + final RestTemplate restTemplate = new RestTemplate(); + + final StopWatch stopWatch = new StopWatch(); + stopWatch.start(); + + for (int i = 0; i < 3; i++) { + final ResponseEntity response = + restTemplate.exchange(THREE_SECOND_URL, HttpMethod.GET, HttpEntity.EMPTY, String.class); + assertThat(response.getBody()).contains("success"); + } + + stopWatch.stop(); + + System.out.println(stopWatch.getTotalTimeSeconds()); +} +``` +* Spring의 HTTP 요청 라이브러리인 RestTemplate을 사용하여 3초가 걸리는 API를 3번 호출하였다. 결과는 9.xx초가 나온다. 이유는 I/O가 요청 중일 때에는 아무 작업도 할 수 없기 때문이다. + +#### Non-Blocking I/O: WebClientSpring WebClient +* Spring WebClient는 Single Thread와 Non-Blocking방식을 사용한다. +* Core 당 1개의 Thread를 이용한다. +![](https://i.imgur.com/7MP2vt0.png) + + +[그림출처](https://luminousmen.com/post/asynchronous-programming-blocking-and-non-blocking) + +* 각 요청은 Event Loop내에 Job으로 등록이 된다. +* Event Loop는 각 Job을 제공자에게 요청한 후, 결과를 기다리지 않고 다른 Job을 처리한다. Event Loop는 제공자로부터 callback으로 응답이 오면, 그 결과를 요청자에게 제공한다. +* WebClient는 이렇게 이벤트에 반응형으로 동작하도록 설계되었다고 한다. +* 아래 예제는 위에서 제시한 요청시간이 약 3초 정도 걸리는 동일한 API를 가져왔다고 가정한 것이다. +```java= +@Test +public void nonBlocking3() throws InterruptedException { + final StopWatch stopWatch = new StopWatch(); + stopWatch.start(); + for (int i = 0; i < LOOP_COUNT; i++) { + this.webClient + .get() + .uri(THREE_SECOND_URL) + .retrieve() + .bodyToMono(String.class) + .subscribe(it -> { + count.countDown(); + System.out.println(it); + }); + } + + count.await(10, TimeUnit.SECONDS); + stopWatch.stop(); + System.out.println(stopWatch.getTotalTimeSeconds()); +} +``` +* WebFlux에서 제공하는 WebClient를 사용해서 위와 동일하게 3초가 걸리는 API를 호출하였다. for문 안의 변수인 LOOP_COUNT는 100으로 코드상에서 설정되어있다. 3초 걸리는 API를 100번 호출한다 하더라도 3.xx초 밖에 걸리지 않는다. +* 만약, Blocking을 위처럼 많은 요청을 동시에 처리하려면 그 만큼의 Thread이 생성되어야 한다. 그러나 이렇게 처리한다 해도 Context Swiching에 의한 오버헤드가 존재할 것이다. + +### 성능비교 +* 아래는 RestTemplate을 사용하는 Spring Boot1과 WebClient를 사용하는 Spring Boot2의 성능비교 결과이다. +* ![](https://i.imgur.com/ACQsu6g.png) + +* 1000명까지는 비슷하지만 동시사용자가 늘수록 RestTemplate은 급격하게 느려지는것을 볼 수 있다. +[그림출처](https://alwayspr.tistory.com/44) +* Spring 커뮤니티에서는 RestTemplate을 이미 Depreciated시키고 WebClient를 사용할것을 강력히 권고하고 있다. +``` +NOTE: As of 5.0 this class is in maintenance mode, +with only minor requests for changes and bugs to be accepted going forward. +Please, consider using the org.springframework.web.reactive.client.WebClient +which has a more modern API and supports sync, async, and streaming scenarios. +``` + +## 참고한 링크 +* https://velog.io/@codemcd/Sync-VS-Async-Blocking-VS-Non-Blocking-sak6d01fhx +* https://devahea.github.io/2019/04/21/Spring-WebFlux%EB%8A%94-%EC%96%B4%EB%96%BB%EA%B2%8C-%EC%A0%81%EC%9D%80-%EB%A6%AC%EC%86%8C%EC%8A%A4%EB%A1%9C-%EB%A7%8E%EC%9D%80-%ED%8A%B8%EB%9E%98%ED%94%BD%EC%9D%84-%EA%B0%90%EB%8B%B9%ED%95%A0%EA%B9%8C/ +* https://happycloud-lee.tistory.com/220 +* https://happycloud-lee.tistory.com/154?category=902418 +* https://musma.github.io/2019/04/17/blocking-and-synchronous.html +* http://homoefficio.github.io/2017/02/19/Blocking-NonBlocking-Synchronous-Asynchronous/ \ No newline at end of file From a60aa4d91b98a384a35be8432762398226f700d8 Mon Sep 17 00:00:00 2001 From: Jin Hyung Park Date: Sun, 15 Aug 2021 01:01:28 +0900 Subject: [PATCH 082/142] =?UTF-8?q?feat:=20=EB=84=A4=ED=8A=B8=EC=9B=8C?= =?UTF-8?q?=ED=81=AC=20CORS=20=ED=95=99=EC=8A=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- network/cors/sigrid/README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/network/cors/sigrid/README.md b/network/cors/sigrid/README.md index c49a17c..a816a65 100644 --- a/network/cors/sigrid/README.md +++ b/network/cors/sigrid/README.md @@ -1,6 +1,6 @@ -## 네트워크: CORS란 무엇인가 -### CORS: Cross-Origin Resource Sharing -#### Origin +# 네트워크: CORS란 무엇인가 +## CORS: Cross-Origin Resource Sharing +### Origin * URL 구조에서 Protocol + Host + Port를 합친 것을 의미함 ```console location.source @@ -137,4 +137,4 @@ router.put('/cors', (req, res, next) => { * 개발 환경에서는 Webpack Dev Server 등의 라이브러리를 사용하여 프록시 설정을 할 수 있다. ## 참고 링크 -* https://beomy.github.io/tech/browser/cors/ +* https://beomy.github.io/tech/browser/cors/ \ No newline at end of file From 08868ff8ae92a95d3b16a7422e316dd31dc0cf24 Mon Sep 17 00:00:00 2001 From: Jin Hyung Park Date: Sun, 15 Aug 2021 01:07:07 +0900 Subject: [PATCH 083/142] =?UTF-8?q?Revert=20"feat:=20=EB=84=A4=ED=8A=B8?= =?UTF-8?q?=EC=9B=8C=ED=81=AC=20CORS=20=ED=95=99=EC=8A=B5"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit d3e81fced7e57d740b9f80f9a1bba82f877b62ce. --- network/cors/sigrid/README.md | 140 ---------------------------------- 1 file changed, 140 deletions(-) delete mode 100644 network/cors/sigrid/README.md diff --git a/network/cors/sigrid/README.md b/network/cors/sigrid/README.md deleted file mode 100644 index a816a65..0000000 --- a/network/cors/sigrid/README.md +++ /dev/null @@ -1,140 +0,0 @@ -# 네트워크: CORS란 무엇인가 -## CORS: Cross-Origin Resource Sharing -### Origin -* URL 구조에서 Protocol + Host + Port를 합친 것을 의미함 -```console -location.source -> https://hackmd.io -``` -* 간단한 퀴즈: 다음 중 같은 출처가 아닌 것은? - * ```https://hackmd.io/about```: 같은 출처 - * ```https://hackmd.io:32/about```: 다른 출처(Port 다름) - * ```http://hackmd.io```: 다른 출처(Protocol 다름) - -### Same-Origin Policy -* Postman으로 API를 호출하면 잘 되는데, 브라우저로 호출하면 CORS 에러가 나는 이유는 무엇일까? -* 브라우저가 동일 출처 정책(Same Origin Policy)를 준수하기 때문에 그렇다. -* 예를 들어 hackmd.io 사이트에서 medium.com의 API를 호출하면 서로 다른 출처이므로 CORS 에러가 발생할 수 있다. -* 동일 출처 정책은 XSS나 XSRF 등의 보안 취약점을 노린 공격을 방어할 수 있다. -* 하지만 외부 리소스를 사용해야 하는 경우는 매우 많다. SOP 정책의 예외 사항이 CORS라고 할 수 있다. - -### CORS 동작 원리 -* Simple Request와 Preflight Request가 있지만, 주로 Preflight Request 방식이 선호된다. - -![](https://i.imgur.com/Wv9msLm.png) -* Preflight 요청은 실제 리소스를 요청하기 전에 OPTIONS라는 메서드를 통해 실제 요청을 전송할지 판단한다. -* OPTIONS 메서드로 서버에 예비 요청을 먼저 보내고, 서버는 이 예비 요청에 대한 응답으로 Access-Control-Allow-Origin 헤더를 포함한 응답을 브라우저에 보낸다. -* 브라우저는 단순 요청과 동일하게 Access-Control-Allow-Origin 헤더를 확인해서 CORS 동작을 수행할지 판단한다. - -### CORS 에러 해결 방법 -* 서버에서 ```Access-Control-Allow-Origin``` 헤더를 포함한 응답을 브라우저에 보내는 방식으로 CORS 에러를 해결할 수 있다. -* Node.js 기준으로 cors라는 라이브러리가 있고, Spring Boot에서는 WebMvcController를 설정해주면 된다. - -#### Access-Control-Allow-Origin: | * -* 헤더가 작성된 링크만 브라우저가 접근할 수 있도록 설정할 수 있다. -* 사용 예시 -``` -Access-Control-Allow-Origin: https://medium.com -``` -``` -Access-Control-Allow-Origin: * // 와일드 카드를 쓰면 모든 사이트 다 된다 -``` -* 서버에서 아래와 같이 응답 헤더를 설정해서 보내주면 된다. -```javascript= -router.options('/cors', (req, res, next) => { - res.set('Access-Control-Allow-Origin', '*') - res.send() -}) -router.put('/cors', (req, res, next) => { - res.set('Access-Control-Allow-Origin', '*') - res.send() -}) -``` -#### Access-Control-Allow-Methods: [, ]* -* 리소스 접근을 허용하는 HTTP 메서드를 지정해 주는 헤더이다. -```javascript= -router.options('/cors', (req, res, next) => { - res.set('Access-Control-Allow-Origin', '*') - res.set('Access-Control-Allow-Methods', req.get('Access-Control-Request-Method')) - res.send() -}) -router.put('/cors', (req, res, next) => { - res.set('Access-Control-Allow-Origin', '*') - res.send() -}) -``` -#### Access-Control-Expose-Headers: [, ]* -* 서버에서 응답 헤더에 Access-Control-Expose-Headers를 추가해 줘야 브라우저의 자바스크립트에서 헤더에 접근할 수 있다. -```javascript= -router.options('/cors', (req, res, next) => { - res.set('Access-Control-Allow-Origin', '*') - res.set('Access-Control-Allow-Methods', req.get('Access-Control-Request-Method')) - res.send() -}) -router.put('/cors', (req, res, next) => { - res.set('Access-Control-Allow-Origin', '*') - res.set('Access-Control-Expose-Headers', 'X-Custom-Beomy') - res.set('X-Custom-Beomy', 'Bemoy') - res.send() -}) -``` - -#### Access-Control-Allow-Headers: [, ]* -* 브라우저에서 보내는 요청 헤더에 포함된 Access-Control-Request-Headers 헤더에 대한 응답 결과이다. -```javascript= -router.options('/cors', (req, res, next) => { - res.set('Access-Control-Allow-Origin', '*') - res.set('Access-Control-Allow-Methods', req.get('Access-Control-Request-Method')) - res.set('Access-Control-Allow-Headers', req.get('Access-Control-Request-Headers')) - res.send() -}) -router.put('/cors', (req, res, next) => { - res.set('Access-Control-Allow-Origin', '*') - console.log(req.get('X-Custom-Request')) // Beomy - res.send() -}) -``` -#### Access-Control-Max-Age: -* preflight 요청 결과를 캐시 할 수 있는 시간을 나타낸다. -* 아래와 같이 초 단위로 캐시 시간을 설정한다. -``` -Access-Control-Max-Age: 60 -``` -* 위의 코드는 60초 동안 preflight 요청을 캐시 하는 코드이다. -* 60초 동안 OPTIONS 메서드를 사용하는 예비 요청을 보내지 않습니다. -```javascript= -router.options('/cors', (req, res, next) => { - res.set('Access-Control-Allow-Origin', '*') - res.set('Access-Control-Allow-Methods', req.get('Access-Control-Request-Method')) - res.set('Access-Control-Max-Age', 60) - res.send() -}) -router.put('/cors', (req, res, next) => { - res.set('Access-Control-Allow-Origin', '*') - res.send() -}) -``` -#### Access-Control-Allow-Credentials: true -* 자바스크립트 요청에서 credentials가 include일 때 요청에 대한 응답을 할 수 있는지를 나타낸다. -* false로 설정해 주고 싶을 경우에는 헤더를 생략하면 된다. -```javascript= -router.options('/cors', (req, res, next) => { - res.set('Access-Control-Allow-Origin', 'https://www.google.com') - res.set('Access-Control-Allow-Methods', req.get('Access-Control-Request-Method')) - res.set('Access-Control-Allow-Credentials', true) - res.send() -}) -router.put('/cors', (req, res, next) => { - res.set('Access-Control-Allow-Origin', 'https://www.google.com') - res.set('Access-Control-Allow-Credentials', true) - res.send() -}) -``` -* Access-Control-Allow-Credentials: true 추가 뿐만 아니라, Access-Control-Allow-Origin 헤더도 와일드카드가 아닌 출처를 명시해주어야 한다. - -## 프록시 서버 -* 프론트엔드와 백엔드 사이에 프록시 서버를 두어서 CORS를 해결할 수 있다. -* 개발 환경에서는 Webpack Dev Server 등의 라이브러리를 사용하여 프록시 설정을 할 수 있다. - -## 참고 링크 -* https://beomy.github.io/tech/browser/cors/ \ No newline at end of file From b66348ff5035081fffdb80426fb3796309c4e72b Mon Sep 17 00:00:00 2001 From: Jin Hyung Park Date: Sun, 15 Aug 2021 01:08:11 +0900 Subject: [PATCH 084/142] =?UTF-8?q?feat:=20=EB=84=A4=ED=8A=B8=EC=9B=8C?= =?UTF-8?q?=ED=81=AC=20CORS=20=ED=95=99=EC=8A=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- network/cors/sigrid/README.md | 140 ++++++++++++++++++++++++++++++++++ 1 file changed, 140 insertions(+) create mode 100644 network/cors/sigrid/README.md diff --git a/network/cors/sigrid/README.md b/network/cors/sigrid/README.md new file mode 100644 index 0000000..a816a65 --- /dev/null +++ b/network/cors/sigrid/README.md @@ -0,0 +1,140 @@ +# 네트워크: CORS란 무엇인가 +## CORS: Cross-Origin Resource Sharing +### Origin +* URL 구조에서 Protocol + Host + Port를 합친 것을 의미함 +```console +location.source +> https://hackmd.io +``` +* 간단한 퀴즈: 다음 중 같은 출처가 아닌 것은? + * ```https://hackmd.io/about```: 같은 출처 + * ```https://hackmd.io:32/about```: 다른 출처(Port 다름) + * ```http://hackmd.io```: 다른 출처(Protocol 다름) + +### Same-Origin Policy +* Postman으로 API를 호출하면 잘 되는데, 브라우저로 호출하면 CORS 에러가 나는 이유는 무엇일까? +* 브라우저가 동일 출처 정책(Same Origin Policy)를 준수하기 때문에 그렇다. +* 예를 들어 hackmd.io 사이트에서 medium.com의 API를 호출하면 서로 다른 출처이므로 CORS 에러가 발생할 수 있다. +* 동일 출처 정책은 XSS나 XSRF 등의 보안 취약점을 노린 공격을 방어할 수 있다. +* 하지만 외부 리소스를 사용해야 하는 경우는 매우 많다. SOP 정책의 예외 사항이 CORS라고 할 수 있다. + +### CORS 동작 원리 +* Simple Request와 Preflight Request가 있지만, 주로 Preflight Request 방식이 선호된다. + +![](https://i.imgur.com/Wv9msLm.png) +* Preflight 요청은 실제 리소스를 요청하기 전에 OPTIONS라는 메서드를 통해 실제 요청을 전송할지 판단한다. +* OPTIONS 메서드로 서버에 예비 요청을 먼저 보내고, 서버는 이 예비 요청에 대한 응답으로 Access-Control-Allow-Origin 헤더를 포함한 응답을 브라우저에 보낸다. +* 브라우저는 단순 요청과 동일하게 Access-Control-Allow-Origin 헤더를 확인해서 CORS 동작을 수행할지 판단한다. + +### CORS 에러 해결 방법 +* 서버에서 ```Access-Control-Allow-Origin``` 헤더를 포함한 응답을 브라우저에 보내는 방식으로 CORS 에러를 해결할 수 있다. +* Node.js 기준으로 cors라는 라이브러리가 있고, Spring Boot에서는 WebMvcController를 설정해주면 된다. + +#### Access-Control-Allow-Origin: | * +* 헤더가 작성된 링크만 브라우저가 접근할 수 있도록 설정할 수 있다. +* 사용 예시 +``` +Access-Control-Allow-Origin: https://medium.com +``` +``` +Access-Control-Allow-Origin: * // 와일드 카드를 쓰면 모든 사이트 다 된다 +``` +* 서버에서 아래와 같이 응답 헤더를 설정해서 보내주면 된다. +```javascript= +router.options('/cors', (req, res, next) => { + res.set('Access-Control-Allow-Origin', '*') + res.send() +}) +router.put('/cors', (req, res, next) => { + res.set('Access-Control-Allow-Origin', '*') + res.send() +}) +``` +#### Access-Control-Allow-Methods: [, ]* +* 리소스 접근을 허용하는 HTTP 메서드를 지정해 주는 헤더이다. +```javascript= +router.options('/cors', (req, res, next) => { + res.set('Access-Control-Allow-Origin', '*') + res.set('Access-Control-Allow-Methods', req.get('Access-Control-Request-Method')) + res.send() +}) +router.put('/cors', (req, res, next) => { + res.set('Access-Control-Allow-Origin', '*') + res.send() +}) +``` +#### Access-Control-Expose-Headers: [, ]* +* 서버에서 응답 헤더에 Access-Control-Expose-Headers를 추가해 줘야 브라우저의 자바스크립트에서 헤더에 접근할 수 있다. +```javascript= +router.options('/cors', (req, res, next) => { + res.set('Access-Control-Allow-Origin', '*') + res.set('Access-Control-Allow-Methods', req.get('Access-Control-Request-Method')) + res.send() +}) +router.put('/cors', (req, res, next) => { + res.set('Access-Control-Allow-Origin', '*') + res.set('Access-Control-Expose-Headers', 'X-Custom-Beomy') + res.set('X-Custom-Beomy', 'Bemoy') + res.send() +}) +``` + +#### Access-Control-Allow-Headers: [, ]* +* 브라우저에서 보내는 요청 헤더에 포함된 Access-Control-Request-Headers 헤더에 대한 응답 결과이다. +```javascript= +router.options('/cors', (req, res, next) => { + res.set('Access-Control-Allow-Origin', '*') + res.set('Access-Control-Allow-Methods', req.get('Access-Control-Request-Method')) + res.set('Access-Control-Allow-Headers', req.get('Access-Control-Request-Headers')) + res.send() +}) +router.put('/cors', (req, res, next) => { + res.set('Access-Control-Allow-Origin', '*') + console.log(req.get('X-Custom-Request')) // Beomy + res.send() +}) +``` +#### Access-Control-Max-Age: +* preflight 요청 결과를 캐시 할 수 있는 시간을 나타낸다. +* 아래와 같이 초 단위로 캐시 시간을 설정한다. +``` +Access-Control-Max-Age: 60 +``` +* 위의 코드는 60초 동안 preflight 요청을 캐시 하는 코드이다. +* 60초 동안 OPTIONS 메서드를 사용하는 예비 요청을 보내지 않습니다. +```javascript= +router.options('/cors', (req, res, next) => { + res.set('Access-Control-Allow-Origin', '*') + res.set('Access-Control-Allow-Methods', req.get('Access-Control-Request-Method')) + res.set('Access-Control-Max-Age', 60) + res.send() +}) +router.put('/cors', (req, res, next) => { + res.set('Access-Control-Allow-Origin', '*') + res.send() +}) +``` +#### Access-Control-Allow-Credentials: true +* 자바스크립트 요청에서 credentials가 include일 때 요청에 대한 응답을 할 수 있는지를 나타낸다. +* false로 설정해 주고 싶을 경우에는 헤더를 생략하면 된다. +```javascript= +router.options('/cors', (req, res, next) => { + res.set('Access-Control-Allow-Origin', 'https://www.google.com') + res.set('Access-Control-Allow-Methods', req.get('Access-Control-Request-Method')) + res.set('Access-Control-Allow-Credentials', true) + res.send() +}) +router.put('/cors', (req, res, next) => { + res.set('Access-Control-Allow-Origin', 'https://www.google.com') + res.set('Access-Control-Allow-Credentials', true) + res.send() +}) +``` +* Access-Control-Allow-Credentials: true 추가 뿐만 아니라, Access-Control-Allow-Origin 헤더도 와일드카드가 아닌 출처를 명시해주어야 한다. + +## 프록시 서버 +* 프론트엔드와 백엔드 사이에 프록시 서버를 두어서 CORS를 해결할 수 있다. +* 개발 환경에서는 Webpack Dev Server 등의 라이브러리를 사용하여 프록시 설정을 할 수 있다. + +## 참고 링크 +* https://beomy.github.io/tech/browser/cors/ \ No newline at end of file From 915eeb0e19fc9adbae7f233db2423f8ac42953f6 Mon Sep 17 00:00:00 2001 From: Jin Hyung Park Date: Sun, 15 Aug 2021 14:40:32 +0900 Subject: [PATCH 085/142] Delete README.md --- network/cors/sigrid/README.md | 140 ---------------------------------- 1 file changed, 140 deletions(-) delete mode 100644 network/cors/sigrid/README.md diff --git a/network/cors/sigrid/README.md b/network/cors/sigrid/README.md deleted file mode 100644 index a816a65..0000000 --- a/network/cors/sigrid/README.md +++ /dev/null @@ -1,140 +0,0 @@ -# 네트워크: CORS란 무엇인가 -## CORS: Cross-Origin Resource Sharing -### Origin -* URL 구조에서 Protocol + Host + Port를 합친 것을 의미함 -```console -location.source -> https://hackmd.io -``` -* 간단한 퀴즈: 다음 중 같은 출처가 아닌 것은? - * ```https://hackmd.io/about```: 같은 출처 - * ```https://hackmd.io:32/about```: 다른 출처(Port 다름) - * ```http://hackmd.io```: 다른 출처(Protocol 다름) - -### Same-Origin Policy -* Postman으로 API를 호출하면 잘 되는데, 브라우저로 호출하면 CORS 에러가 나는 이유는 무엇일까? -* 브라우저가 동일 출처 정책(Same Origin Policy)를 준수하기 때문에 그렇다. -* 예를 들어 hackmd.io 사이트에서 medium.com의 API를 호출하면 서로 다른 출처이므로 CORS 에러가 발생할 수 있다. -* 동일 출처 정책은 XSS나 XSRF 등의 보안 취약점을 노린 공격을 방어할 수 있다. -* 하지만 외부 리소스를 사용해야 하는 경우는 매우 많다. SOP 정책의 예외 사항이 CORS라고 할 수 있다. - -### CORS 동작 원리 -* Simple Request와 Preflight Request가 있지만, 주로 Preflight Request 방식이 선호된다. - -![](https://i.imgur.com/Wv9msLm.png) -* Preflight 요청은 실제 리소스를 요청하기 전에 OPTIONS라는 메서드를 통해 실제 요청을 전송할지 판단한다. -* OPTIONS 메서드로 서버에 예비 요청을 먼저 보내고, 서버는 이 예비 요청에 대한 응답으로 Access-Control-Allow-Origin 헤더를 포함한 응답을 브라우저에 보낸다. -* 브라우저는 단순 요청과 동일하게 Access-Control-Allow-Origin 헤더를 확인해서 CORS 동작을 수행할지 판단한다. - -### CORS 에러 해결 방법 -* 서버에서 ```Access-Control-Allow-Origin``` 헤더를 포함한 응답을 브라우저에 보내는 방식으로 CORS 에러를 해결할 수 있다. -* Node.js 기준으로 cors라는 라이브러리가 있고, Spring Boot에서는 WebMvcController를 설정해주면 된다. - -#### Access-Control-Allow-Origin: | * -* 헤더가 작성된 링크만 브라우저가 접근할 수 있도록 설정할 수 있다. -* 사용 예시 -``` -Access-Control-Allow-Origin: https://medium.com -``` -``` -Access-Control-Allow-Origin: * // 와일드 카드를 쓰면 모든 사이트 다 된다 -``` -* 서버에서 아래와 같이 응답 헤더를 설정해서 보내주면 된다. -```javascript= -router.options('/cors', (req, res, next) => { - res.set('Access-Control-Allow-Origin', '*') - res.send() -}) -router.put('/cors', (req, res, next) => { - res.set('Access-Control-Allow-Origin', '*') - res.send() -}) -``` -#### Access-Control-Allow-Methods: [, ]* -* 리소스 접근을 허용하는 HTTP 메서드를 지정해 주는 헤더이다. -```javascript= -router.options('/cors', (req, res, next) => { - res.set('Access-Control-Allow-Origin', '*') - res.set('Access-Control-Allow-Methods', req.get('Access-Control-Request-Method')) - res.send() -}) -router.put('/cors', (req, res, next) => { - res.set('Access-Control-Allow-Origin', '*') - res.send() -}) -``` -#### Access-Control-Expose-Headers: [, ]* -* 서버에서 응답 헤더에 Access-Control-Expose-Headers를 추가해 줘야 브라우저의 자바스크립트에서 헤더에 접근할 수 있다. -```javascript= -router.options('/cors', (req, res, next) => { - res.set('Access-Control-Allow-Origin', '*') - res.set('Access-Control-Allow-Methods', req.get('Access-Control-Request-Method')) - res.send() -}) -router.put('/cors', (req, res, next) => { - res.set('Access-Control-Allow-Origin', '*') - res.set('Access-Control-Expose-Headers', 'X-Custom-Beomy') - res.set('X-Custom-Beomy', 'Bemoy') - res.send() -}) -``` - -#### Access-Control-Allow-Headers: [, ]* -* 브라우저에서 보내는 요청 헤더에 포함된 Access-Control-Request-Headers 헤더에 대한 응답 결과이다. -```javascript= -router.options('/cors', (req, res, next) => { - res.set('Access-Control-Allow-Origin', '*') - res.set('Access-Control-Allow-Methods', req.get('Access-Control-Request-Method')) - res.set('Access-Control-Allow-Headers', req.get('Access-Control-Request-Headers')) - res.send() -}) -router.put('/cors', (req, res, next) => { - res.set('Access-Control-Allow-Origin', '*') - console.log(req.get('X-Custom-Request')) // Beomy - res.send() -}) -``` -#### Access-Control-Max-Age: -* preflight 요청 결과를 캐시 할 수 있는 시간을 나타낸다. -* 아래와 같이 초 단위로 캐시 시간을 설정한다. -``` -Access-Control-Max-Age: 60 -``` -* 위의 코드는 60초 동안 preflight 요청을 캐시 하는 코드이다. -* 60초 동안 OPTIONS 메서드를 사용하는 예비 요청을 보내지 않습니다. -```javascript= -router.options('/cors', (req, res, next) => { - res.set('Access-Control-Allow-Origin', '*') - res.set('Access-Control-Allow-Methods', req.get('Access-Control-Request-Method')) - res.set('Access-Control-Max-Age', 60) - res.send() -}) -router.put('/cors', (req, res, next) => { - res.set('Access-Control-Allow-Origin', '*') - res.send() -}) -``` -#### Access-Control-Allow-Credentials: true -* 자바스크립트 요청에서 credentials가 include일 때 요청에 대한 응답을 할 수 있는지를 나타낸다. -* false로 설정해 주고 싶을 경우에는 헤더를 생략하면 된다. -```javascript= -router.options('/cors', (req, res, next) => { - res.set('Access-Control-Allow-Origin', 'https://www.google.com') - res.set('Access-Control-Allow-Methods', req.get('Access-Control-Request-Method')) - res.set('Access-Control-Allow-Credentials', true) - res.send() -}) -router.put('/cors', (req, res, next) => { - res.set('Access-Control-Allow-Origin', 'https://www.google.com') - res.set('Access-Control-Allow-Credentials', true) - res.send() -}) -``` -* Access-Control-Allow-Credentials: true 추가 뿐만 아니라, Access-Control-Allow-Origin 헤더도 와일드카드가 아닌 출처를 명시해주어야 한다. - -## 프록시 서버 -* 프론트엔드와 백엔드 사이에 프록시 서버를 두어서 CORS를 해결할 수 있다. -* 개발 환경에서는 Webpack Dev Server 등의 라이브러리를 사용하여 프록시 설정을 할 수 있다. - -## 참고 링크 -* https://beomy.github.io/tech/browser/cors/ \ No newline at end of file From 4a1d7b4e3cae2a71d8dd300e59298dc03757216c Mon Sep 17 00:00:00 2001 From: Jin Hyung Park Date: Sun, 15 Aug 2021 14:40:43 +0900 Subject: [PATCH 086/142] Delete README.md --- .../blocking-vs-nonblocking/sigrid/README.md | 285 ------------------ 1 file changed, 285 deletions(-) delete mode 100644 network/blocking-vs-nonblocking/sigrid/README.md diff --git a/network/blocking-vs-nonblocking/sigrid/README.md b/network/blocking-vs-nonblocking/sigrid/README.md deleted file mode 100644 index bf04cfc..0000000 --- a/network/blocking-vs-nonblocking/sigrid/README.md +++ /dev/null @@ -1,285 +0,0 @@ -# Blocking vs Non-blocking -## Synchronous vs Asynchronous -### Synchronous -* 동기는 두 가지 이상의 작업이 서로 시간을 맞추어 행동하는 것을 의미한다. -* 호출한 함수가 다른 호출한 함수의 작업이 끝나 결과값을 반환하기를 기다리거나, 지속적으로 호출된 함수에게 확인 요청을 하는 경우가 있다. -* 작업 A와 작업 B가 있다고 가정하자. - * 작업 A와 작업 B의 시작 시간과 종료 시간이 같으면 동기라고 볼 수 있다. - * 쓰레드 A, 쓰레드 B가 동시에 작업을 시작하고 종료하는 경우 - * 메소드 리턴 시간 A와 결과를 전달받는 시간 B가 일치한 경우 - * 작업 A가 끝나는 시간과 작업 B가 시작하는 시간이 같으면 동기라고 볼 수 있다. - -### Asynchronous -* 비동기는 두 가지 이상의 작업을 할 때 대상들이 서로의 시간을 맞추지 않고 행동하는 것을 의미한다. -* 호출하는 함수가 호출되는 함수에게 작업을 맡겨놓고 더 이상 신경을 쓰지 않는 경우가 있다. - -### Blocking vs Non-Blocking -* 블록킹과 논블록킹은 직접 제어할 수 없는 대상을 어떻게 처리할 것인가에 따라 나눠지는 개념이다. -* 직접 제어할 수 없는 대상으로는 I/O, 멀티 쓰레드 동기화 등이 있다. - -#### Blocking -* 블록킹은 직접 제어할 수 없는 대상의 작업이 끝날 때까지 제어권을 넘겨주지 않는 것이다. -* 예를 들어 호출하는 함수가 I/O를 요청했을 때 I/O 처리가 완료될 때까지 아무 일도 하지 못한 채 기다리는 것을 말한다. - -#### Non-Blocking -* 논블록킹은 직접 제어할 수 없는 대상의 작업 처리 여부와 무관하게 처리하는 것을 의미한다. -* 예를 들어 호출하는 함수가 I/O를 요청했을 때 I/O 처리 여부와 상관없이 바로 자신의 작업을 할 수 있는 것을 말한다. - -#### Synchronous Blocking I/O -![](https://i.imgur.com/v6uOhUA.png) -```java= -device = IO.open() -// 이 Thread는 데이터를 읽을 때까지 아무 일도 할 수 없음 -data = device.read() -print(data) -``` -* Synchronous: 애플리케이션의 ```read()``` 메소드가 리턴하는 시간과 커널에서 결과를 가져오는 시간이 일치한다. -* Blocking: 커널의 작업이 완료될 때까지 대기한다. - -#### Synchronous Non-Blocking I/O -![](https://i.imgur.com/BRrD3I6.png) -```python= -device = IO.open() -ready = False -while not ready: - print("There is no data to read!") - - # 다른 작업을 처리할 수 있음 - - # while 문 내부의 다른 작업을 다 처리하면 데이터가 도착했는지 확인한다. - ready = IO.poll(device, IO.INPUT, 5) -data = device.read() -print(data) -``` -* Synchronous: read() 메서드(애플리케이션)가 리턴하는 시간과 커널에서 결과를 가져오는 시간이 일치한다. -* Non-Blocking: 애플리케이션으로부터 요청을 받은 커널은 작업 완료 여부와 상관없이 바로 반환하여 제어권을 애플리케이션에게 넘겨준다. 커널의 작업이 완료되면 작업 결과를 애플리케이션에게 반환한다. -* 대표적인 예로는 멀티플랙싱을 수행하는 select(), epoll() 함수가 있다. -* Application에서 I/O를 요청 후 바로 return되어 다른 작업을 수행하다가 특정 시간에 데이터가 준비가 다되었는지 상태를 확인한다. 데이터의 준비가 끝날 때까지 틈틈이 확인을 하다가 완료가 되었으면 종료된다. -* 여기서 주기적으로 체크하는 방식을 폴링(Polling) 이라고 한다. 그러나 이러한 방식은 작업이 완료되기 전까지 주기적으로 호출하기 때문에 불필요하게 자원을 사용하게 된다. - -#### Asynchronous Non-Blocking I/O (AIO) -![](https://i.imgur.com/GrI8VfR.png) -```python= -ios = IO.IOService() -device = IO.open(ios) - -def inputHandler(data, err): - "Input data handler" - if not err: - print(data) - -device.readSome(inputHandler) -# 이 thread는 데이터가 도착했는지 신경쓰지 않고 다른 작업을 처리할 수 있다. -ios.loop() -``` -* Asynchronous: readSome() 메서드(애플리케이션)가 리턴하는 시간과 커널에서 결과를 가져오는 시간이 일치하지 않는다. -* Non-Blocking: 애플리케이션으로부터 요청을 받은 커널은 작업 완료 여부와 상관없이 바로 반환하여 제어권을 애플리케이션에게 넘겨준다. 작업이 끝나면 애플리케이션에게 시그널 또는 콜백을 보낸다. -* 대표적인 예로는 윈도우에서 멀티플랙싱을 수행하는 IOCP가 있다. -* I/O 요청을 한 후 Non-Blocking I/O와 마찬가지고 즉시 리턴된다. 허나, 데이터 준비가 완료되면 이벤트가 발생하여 알려주거나, 미리 등록해놓은 callback을 통해서 이후 작업이 진행된다. 이전 두 I/O의 문제였던 Blocking이나 Polling이 없기 때문에 자원을 보다 더 효율적으로 사용할 수 있다. - -#### Asynchronous Blocking -* 비동기이면서도 블록킹을 하는 경우는 비효율적이므로 자주 사용되지 않는다고 한다. -* 하지만 Asynchronous Non-Blocking 모델 중에서 Blocking 형태로 동작하는 모델이 있는 경우 의도와 다르게 Asynchrnous Blocking으로 동작하는 경우가 있다고 한다. -* 예를 들어, Node.js는 비동기로 작업하려고 하지만 MySQL 드라이버가 Blocking 방식으로 동작하므로 어쩔 수 없이 Asynchronous Blocking 방식으로 동작한다고 한다. - -#### 본격 Case Study : 박 상병님, 저희 짬통 언제 버리러 가나요? -* Blocking & Synchronous -``` -김 일병 : 박 상병님, 오늘 짬통 언제 버리러 갑니까? -박 상병 : 있어봐, 중대 운전병에게 물어볼게. -김 일병 : (...) -대표님 : (수고하십니다 XX대대 상병 박공군입니다) -김 일병 : (과정 지켜봄.. 궁금함.. 계속 서 있음) -이 병장: 김 일병, 언제 버리러 가는거야? -김 일병: (박 상병님 전화 받고 있는 것을 수화기를 들고 같이 듣고 있음) 지금 전화 중이십니다. 잠시만 기다려주십시오. -이 병장: 오오 알겠어. -``` -* Blocking & Asynchronous -``` -김 일병 : 박 상병님, 오늘 짬통 언제 버리러 갑니까? -박 상병 : 있어봐, 중대 운전병에게 물어볼게. -김 일병 : (...) -대표님 : (수고하십니다 XX대대 상병 박공군입니다) -김 일병 : (과정 지켜봄.. 궁금함.. 계속 서 있음) -이 병장: 김 일병, 언제 버리러 가는거야? -김 일병: (아무런 일도 하지 않으며 말한다) 잘 모르겠습니다. 뭐 전화오면 박 상병님께서 알려주시지 않겠습니까? -이 병장: 흠.. 폐급인가? -``` - -* Non-blocking & Synchronous -``` -김 일병 : 박 상병님, 오늘 짬통 언제 버리러 갑니까? -박 상병 : 있어봐, 중대 운전병에게 물어볼게. -김 일병 : 넵! -박 상병 : (수고하십니다 XX대대 상병 박공군입니다) -김 일병 : 연락 되셨습니까? -박 상병 : 이병이 받던데. 좀 이따 해볼게. -김 일병 : 연락 되셨습니까? -박 상병 : 운전병 제초하러 갔대. 나중에 전화준댄다. -이 병장 : 김 일병, 언제 버리러 간대? -박 상병 : (...) -이 병장 : 이 폐급 새끼 또 내 말 씹네.. 존나 빡친다;; -김 일병 : 연락 되셨습니까? -박 상병 : ㅅㅂ 왜 자꾸 물어보냐 너 폐급이냐? 아직 전화 안왔다니까; -``` - -* Non-blocking & Asynchronous -``` -김 일병 : 박 상병님, 오늘 짬통 언제 버리러 갑니까? -박 상병 : 있어봐, 중대 운전병에게 물어볼게. -김 일병 : 넵! -박 상병 : (수고하십니다 XX대대 상병 박공군입니다) -박 상병 : 오늘 9시에 간댄다. 준비하자. -김 일병 : 넵! 짬통 일병들이랑 옮기고 있겠습니다. -``` - -#### 정리 -* Blocking/NonBlocking - * Blocking/NonBlocking은 호출되는 함수가 바로 리턴하느냐 마느냐가 관심사다. - * 호출된 함수가 바로 리턴해서 호출한 함수에게 제어권을 넘겨주고, 호출한 함수가 다른 일을 할 수 있는 기회를 줄 수 있으면 NonBlocking이다. - * 그렇지 않고 호출된 함수가 자신의 작업을 모두 마칠 때까지 호출한 함수에게 제어권을 넘겨주지 않고 대기하게 만든다면 Blocking이다. - -* Synchronous/Asynchronous - * Synchronous/Asynchronous는 호출되는 함수의 작업 완료 여부를 누가 신경쓰냐가 관심사다. - * 호출되는 함수에게 callback을 전달해서, 호출되는 함수의 작업이 완료되면 호출되는 함수가 전달받은 callback을 실행하고, 호출하는 함수는 작업 완료 여부를 신경쓰지 않으면 Asynchronous다. - * 호출하는 함수가 호출되는 함수의 작업 완료 후 리턴을 기다리거나, 또는 호출되는 함수로부터 바로 리턴 받더라도 작업 완료 여부를 호출하는 함수 스스로 계속 확인하며 신경쓰면 Synchronous다. - -### 추가 설명 -* Blocking 방식은 요청하고 응답 올때까지 기다리는 방식이고, Non-Blocking 방식은 요청하고 딴 일하다 나중에 응답신호가 오면 결과를 읽어 처리하는 방식이다. -* 동기방식은 요청자와 제공자사이에 계속 Connection이 맺어져 있어야 하고, 비동기방식은 Connection은 끊어지고 서로간에 이벤트를 통해 통신하는 방식이다. -* 비동기방식은 요청자와 제공자 사이에 Message Broker라는 또 다른 서비스가 중계해주지만, 동기 방식은 요청자 어플리케이션에 비동기 처리를 하는 로직이 있다. -* 최근 흔히 사용하는 REST API는 동기 방식이고 보통 Non-Blocking방식으로 통신한다. -* Frontend와 backend사이는 거의 대부분 동기+non-blocking 방식으로 구현한다. -* 비동기방식 패턴 중 제일 대표적인 것이 Publish/Subscribe (또는 Producer-Consumer) 패턴이다. - * Publisher인 유튜버들은 구독을 요청할 수 있는 채널을 만들고, 그 채널에 동영상을 계속 publishing해둔다. - * Subscriber인 사용자가 특정 유튜브채널을 구독 신청하면 새로운 동영상이 업로드 될때 첫화면에 추천동영상으로 받아보거나 모바일앱 알림 등으로 받아 볼 수 있게 된다. - * 즉, 사용자는 구독만 해놓고 있으면 새 동영상 올라올때까지 Youtube에 머물러 있을 필요가 없다. - * 비동기 메시징 방식은 추후 CS 스터디 주제로 발제할 생각이다. - * 이런 비동기 방식을 사용하는 이유는 큰 서비스를 이루는 마이크로서비스 중 하나가 실패해도 전체적인 서비스는 그대로 진행되도록 하기 위함이다. - * 예를 들어 쇼핑몰 상품 주문 시 주문서비스, 결제서비스, 배송서비스가 필요한데 동기방식으로 하면 결제나 배송 서비스에 문제가 생기면 상품 주문은 실패하게 된다. - * 그러나 비동기방식을 사용하면 Queue에 처리해야할 메시지가 있기 때문에 일시적 장애가 발생해도 복구가 되면 처리 가능하다. 따라서 상품 주문은 어떠한 경우에도 정상적으로 처리될 수 있게 된다. -* 일반적으로 Front와 Backend 서비스간에는 동기방식을 사용하고, backend의 서비스들간에는 비동기방식을 사용한다. -* 또한 데이터 조회 서비스는 동기방식을 사용하고, 데이터 변경 서비스는 비동기방식을 사용한다. - -### Spring WebFlux란 무엇일까? -* Non-blocking을 통해서 적은 수의 리소스로 동시성을 다룰 수 있게 해주는 프레임워크이다. -* 우리가 Spring MVC와 RDBMS를 사용하고 있으면 Blocking I/O를 사용하고 있는 것이다. -* Application에서 I/O 요청을 한 후 완료되기 전까지는 Application이 Block이 되어 다른 작업을 수행할 수 없다. 이는 해당 자원이 효율적으로 사용되지 못하고 있음을 의미한다. -* 물론, Blocking 방식임에도 불구하고 마치 Block이 안된듯이 동작하는 것처럼 보인다. 이는 멀티 쓰레드 기반의 방식이기 때문이다. 정확히는, 하나의 쓰레드가 블록되는 순간 다른 쓰레드가 동작하도록 함으로써 블록 문제를 해결하였다. -* 하지만 쓰레드 간의 Context Switching 등의 비용이 존재하므로, 여러 개의 I/O를 동시다발적으로 효율적인 처리를 하려면 논블로킹으로 처리해야만 한다. - -#### Blocking I/O 예시: RestTemplate -* RestTemplate은 Multi-Thread와 Blocking방식을 사용한다. -* Thread pool은 요청자 어플리케이션 구동시에 미리 만들어 놓는다. -* Request는 먼저 Queue에 쌓이고 가용한 스레드가 있으면 그 스레드에 할당되어 처리된다. -* 즉, 1 요청 당 1 스레드가 할당됩니다. -* 각 스레드에서는 Blocking방식으로 처리되어 응답이 올 때까지 그 스레드는 다른 요청에 할당될 수 없다. -* 아래는 RestTemplate을 Connection Pool에 Spring Bean으로 등록하기 위한 예제이다. - * 요청 당 20개의 RestTemplate client를 만들고, 최대 50개까지 증가할 수 있도록 했다. - -```java= -@Configuration -public class RestTemplateConfig { - public RestTemplate getRestTemplate(int defaultMaxPerRoute, int maxTotal) { - PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(); - connManager.setDefaultMaxPerRoute(defaultMaxPerRoute); - connManager.setMaxTotal(maxTotal); - - HttpClient client = HttpClientBuilder.create().setConnectionManager(connManager).build(); - - HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(client); - factory.setConnectTimeout(3000); - factory.setReadTimeout(3000); - - return new RestTemplate(factory); - - } - - @Bean - public RestTemplate coffeeRestTemplate() { - return getRestTemplate(20, 50); - } -} -``` -* 요청을 처리할 스레드가 있으면 아무런 문제가 없지만, 스레드가 다 차는 경우 이후의 요청은 Queue에 대기하게 된다. -* 대부분의 문제는 네트워킹이나 DB와의 통신에서 생기는데 이런 문제가 여러 스레드에서 발생하면 가용한 스레드수가 현저하게 줄어들게 되고, 결국 전체 서비스는 매우 느려지게 된다. -* RestTemplate을 이용하여 API 중 응답 시간이 약 3초 정도 걸리는 요청을 3번 반복하는 예제를 제시한다. -```java= -@Test -public void blocking() { - final RestTemplate restTemplate = new RestTemplate(); - - final StopWatch stopWatch = new StopWatch(); - stopWatch.start(); - - for (int i = 0; i < 3; i++) { - final ResponseEntity response = - restTemplate.exchange(THREE_SECOND_URL, HttpMethod.GET, HttpEntity.EMPTY, String.class); - assertThat(response.getBody()).contains("success"); - } - - stopWatch.stop(); - - System.out.println(stopWatch.getTotalTimeSeconds()); -} -``` -* Spring의 HTTP 요청 라이브러리인 RestTemplate을 사용하여 3초가 걸리는 API를 3번 호출하였다. 결과는 9.xx초가 나온다. 이유는 I/O가 요청 중일 때에는 아무 작업도 할 수 없기 때문이다. - -#### Non-Blocking I/O: WebClientSpring WebClient -* Spring WebClient는 Single Thread와 Non-Blocking방식을 사용한다. -* Core 당 1개의 Thread를 이용한다. -![](https://i.imgur.com/7MP2vt0.png) - - -[그림출처](https://luminousmen.com/post/asynchronous-programming-blocking-and-non-blocking) - -* 각 요청은 Event Loop내에 Job으로 등록이 된다. -* Event Loop는 각 Job을 제공자에게 요청한 후, 결과를 기다리지 않고 다른 Job을 처리한다. Event Loop는 제공자로부터 callback으로 응답이 오면, 그 결과를 요청자에게 제공한다. -* WebClient는 이렇게 이벤트에 반응형으로 동작하도록 설계되었다고 한다. -* 아래 예제는 위에서 제시한 요청시간이 약 3초 정도 걸리는 동일한 API를 가져왔다고 가정한 것이다. -```java= -@Test -public void nonBlocking3() throws InterruptedException { - final StopWatch stopWatch = new StopWatch(); - stopWatch.start(); - for (int i = 0; i < LOOP_COUNT; i++) { - this.webClient - .get() - .uri(THREE_SECOND_URL) - .retrieve() - .bodyToMono(String.class) - .subscribe(it -> { - count.countDown(); - System.out.println(it); - }); - } - - count.await(10, TimeUnit.SECONDS); - stopWatch.stop(); - System.out.println(stopWatch.getTotalTimeSeconds()); -} -``` -* WebFlux에서 제공하는 WebClient를 사용해서 위와 동일하게 3초가 걸리는 API를 호출하였다. for문 안의 변수인 LOOP_COUNT는 100으로 코드상에서 설정되어있다. 3초 걸리는 API를 100번 호출한다 하더라도 3.xx초 밖에 걸리지 않는다. -* 만약, Blocking을 위처럼 많은 요청을 동시에 처리하려면 그 만큼의 Thread이 생성되어야 한다. 그러나 이렇게 처리한다 해도 Context Swiching에 의한 오버헤드가 존재할 것이다. - -### 성능비교 -* 아래는 RestTemplate을 사용하는 Spring Boot1과 WebClient를 사용하는 Spring Boot2의 성능비교 결과이다. -* ![](https://i.imgur.com/ACQsu6g.png) - -* 1000명까지는 비슷하지만 동시사용자가 늘수록 RestTemplate은 급격하게 느려지는것을 볼 수 있다. -[그림출처](https://alwayspr.tistory.com/44) -* Spring 커뮤니티에서는 RestTemplate을 이미 Depreciated시키고 WebClient를 사용할것을 강력히 권고하고 있다. -``` -NOTE: As of 5.0 this class is in maintenance mode, -with only minor requests for changes and bugs to be accepted going forward. -Please, consider using the org.springframework.web.reactive.client.WebClient -which has a more modern API and supports sync, async, and streaming scenarios. -``` - -## 참고한 링크 -* https://velog.io/@codemcd/Sync-VS-Async-Blocking-VS-Non-Blocking-sak6d01fhx -* https://devahea.github.io/2019/04/21/Spring-WebFlux%EB%8A%94-%EC%96%B4%EB%96%BB%EA%B2%8C-%EC%A0%81%EC%9D%80-%EB%A6%AC%EC%86%8C%EC%8A%A4%EB%A1%9C-%EB%A7%8E%EC%9D%80-%ED%8A%B8%EB%9E%98%ED%94%BD%EC%9D%84-%EA%B0%90%EB%8B%B9%ED%95%A0%EA%B9%8C/ -* https://happycloud-lee.tistory.com/220 -* https://happycloud-lee.tistory.com/154?category=902418 -* https://musma.github.io/2019/04/17/blocking-and-synchronous.html -* http://homoefficio.github.io/2017/02/19/Blocking-NonBlocking-Synchronous-Asynchronous/ \ No newline at end of file From f59a9ff2f07176f9b38b658ded119622527479b6 Mon Sep 17 00:00:00 2001 From: Jin Hyung Park Date: Sun, 15 Aug 2021 14:41:06 +0900 Subject: [PATCH 087/142] =?UTF-8?q?feat:=20Blocking=20vs=20Non-Blocking=20?= =?UTF-8?q?=ED=95=99=EC=8A=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../blocking-vs-non-blocking/sigrid/README.md | 285 ++++++++++++++++++ 1 file changed, 285 insertions(+) create mode 100644 network/blocking-vs-non-blocking/sigrid/README.md diff --git a/network/blocking-vs-non-blocking/sigrid/README.md b/network/blocking-vs-non-blocking/sigrid/README.md new file mode 100644 index 0000000..e32a423 --- /dev/null +++ b/network/blocking-vs-non-blocking/sigrid/README.md @@ -0,0 +1,285 @@ +# Blocking vs Non-blocking +## Synchronous vs Asynchronous +### Synchronous +* 동기는 두 가지 이상의 작업이 서로 시간을 맞추어 행동하는 것을 의미한다. +* 호출한 함수가 다른 호출한 함수의 작업이 끝나 결과값을 반환하기를 기다리거나, 지속적으로 호출된 함수에게 확인 요청을 하는 경우가 있다. +* 작업 A와 작업 B가 있다고 가정하자. + * 작업 A와 작업 B의 시작 시간과 종료 시간이 같으면 동기라고 볼 수 있다. + * 쓰레드 A, 쓰레드 B가 동시에 작업을 시작하고 종료하는 경우 + * 메소드 리턴 시간 A와 결과를 전달받는 시간 B가 일치한 경우 + * 작업 A가 끝나는 시간과 작업 B가 시작하는 시간이 같으면 동기라고 볼 수 있다. + +### Asynchronous +* 비동기는 두 가지 이상의 작업을 할 때 대상들이 서로의 시간을 맞추지 않고 행동하는 것을 의미한다. +* 호출하는 함수가 호출되는 함수에게 작업을 맡겨놓고 더 이상 신경을 쓰지 않는 경우가 있다. + +### Blocking vs Non-Blocking +* 블록킹과 논블록킹은 직접 제어할 수 없는 대상을 어떻게 처리할 것인가에 따라 나눠지는 개념이다. +* 직접 제어할 수 없는 대상으로는 I/O, 멀티 쓰레드 동기화 등이 있다. + +#### Blocking +* 블록킹은 직접 제어할 수 없는 대상의 작업이 끝날 때까지 제어권을 넘겨주지 않는 것이다. +* 예를 들어 호출하는 함수가 I/O를 요청했을 때 I/O 처리가 완료될 때까지 아무 일도 하지 못한 채 기다리는 것을 말한다. + +#### Non-Blocking +* 논블록킹은 직접 제어할 수 없는 대상의 작업 처리 여부와 무관하게 처리하는 것을 의미한다. +* 예를 들어 호출하는 함수가 I/O를 요청했을 때 I/O 처리 여부와 상관없이 바로 자신의 작업을 할 수 있는 것을 말한다. + +#### Synchronous Blocking I/O +![](https://i.imgur.com/v6uOhUA.png) +```java= +device = IO.open() +// 이 Thread는 데이터를 읽을 때까지 아무 일도 할 수 없음 +data = device.read() +print(data) +``` +* Synchronous: 애플리케이션의 ```read()``` 메소드가 리턴하는 시간과 커널에서 결과를 가져오는 시간이 일치한다. +* Blocking: 커널의 작업이 완료될 때까지 대기한다. + +#### Synchronous Non-Blocking I/O +![](https://i.imgur.com/BRrD3I6.png) +```python= +device = IO.open() +ready = False +while not ready: + print("There is no data to read!") + + # 다른 작업을 처리할 수 있음 + + # while 문 내부의 다른 작업을 다 처리하면 데이터가 도착했는지 확인한다. + ready = IO.poll(device, IO.INPUT, 5) +data = device.read() +print(data) +``` +* Synchronous: read() 메서드(애플리케이션)가 리턴하는 시간과 커널에서 결과를 가져오는 시간이 일치한다. +* Non-Blocking: 애플리케이션으로부터 요청을 받은 커널은 작업 완료 여부와 상관없이 바로 반환하여 제어권을 애플리케이션에게 넘겨준다. 커널의 작업이 완료되면 작업 결과를 애플리케이션에게 반환한다. +* 대표적인 예로는 멀티플랙싱을 수행하는 select(), epoll() 함수가 있다. +* Application에서 I/O를 요청 후 바로 return되어 다른 작업을 수행하다가 특정 시간에 데이터가 준비가 다되었는지 상태를 확인한다. 데이터의 준비가 끝날 때까지 틈틈이 확인을 하다가 완료가 되었으면 종료된다. +* 여기서 주기적으로 체크하는 방식을 폴링(Polling) 이라고 한다. 그러나 이러한 방식은 작업이 완료되기 전까지 주기적으로 호출하기 때문에 불필요하게 자원을 사용하게 된다. + +#### Asynchronous Non-Blocking I/O (AIO) +![](https://i.imgur.com/GrI8VfR.png) +```python= +ios = IO.IOService() +device = IO.open(ios) + +def inputHandler(data, err): + "Input data handler" + if not err: + print(data) + +device.readSome(inputHandler) +# 이 thread는 데이터가 도착했는지 신경쓰지 않고 다른 작업을 처리할 수 있다. +ios.loop() +``` +* Asynchronous: readSome() 메서드(애플리케이션)가 리턴하는 시간과 커널에서 결과를 가져오는 시간이 일치하지 않는다. +* Non-Blocking: 애플리케이션으로부터 요청을 받은 커널은 작업 완료 여부와 상관없이 바로 반환하여 제어권을 애플리케이션에게 넘겨준다. 작업이 끝나면 애플리케이션에게 시그널 또는 콜백을 보낸다. +* 대표적인 예로는 윈도우에서 멀티플랙싱을 수행하는 IOCP가 있다. +* I/O 요청을 한 후 Non-Blocking I/O와 마찬가지고 즉시 리턴된다. 허나, 데이터 준비가 완료되면 이벤트가 발생하여 알려주거나, 미리 등록해놓은 callback을 통해서 이후 작업이 진행된다. 이전 두 I/O의 문제였던 Blocking이나 Polling이 없기 때문에 자원을 보다 더 효율적으로 사용할 수 있다. + +#### Asynchronous Blocking +* 비동기이면서도 블록킹을 하는 경우는 비효율적이므로 자주 사용되지 않는다고 한다. +* 하지만 Asynchronous Non-Blocking 모델 중에서 Blocking 형태로 동작하는 모델이 있는 경우 의도와 다르게 Asynchrnous Blocking으로 동작하는 경우가 있다고 한다. +* 예를 들어, Node.js는 비동기로 작업하려고 하지만 MySQL 드라이버가 Blocking 방식으로 동작하므로 어쩔 수 없이 Asynchronous Blocking 방식으로 동작한다고 한다. + +#### 본격 Case Study : 박 상병님, 저희 짬통 언제 버리러 가나요? +* Blocking & Synchronous +``` +김 일병 : 박 상병님, 오늘 짬통 언제 버리러 갑니까? +박 상병 : 있어봐, 중대 운전병에게 물어볼게. +김 일병 : (...) +대표님 : (수고하십니다 XX대대 상병 박공군입니다) +김 일병 : (과정 지켜봄.. 궁금함.. 계속 서 있음) +이 병장: 김 일병, 언제 버리러 가는거야? +김 일병: (박 상병님 전화 받고 있는 것을 수화기를 들고 같이 듣고 있음) 지금 전화 중이십니다. 잠시만 기다려주십시오. +이 병장: 오오 알겠어. +``` +* Blocking & Asynchronous +``` +김 일병 : 박 상병님, 오늘 짬통 언제 버리러 갑니까? +박 상병 : 있어봐, 중대 운전병에게 물어볼게. +김 일병 : (...) +대표님 : (수고하십니다 XX대대 상병 박공군입니다) +김 일병 : (과정 지켜봄.. 궁금함.. 계속 서 있음) +이 병장: 김 일병, 언제 버리러 가는거야? +김 일병: (아무런 일도 하지 않으며 말한다) 잘 모르겠습니다. 뭐 전화오면 박 상병님께서 알려주시지 않겠습니까? +이 병장: 흠.. 폐급인가? +``` + +* Non-blocking & Synchronous +``` +김 일병 : 박 상병님, 오늘 짬통 언제 버리러 갑니까? +박 상병 : 있어봐, 중대 운전병에게 물어볼게. +김 일병 : 넵! +박 상병 : (수고하십니다 XX대대 상병 박공군입니다) +김 일병 : 연락 되셨습니까? +박 상병 : 이병이 받던데. 좀 이따 해볼게. +김 일병 : 연락 되셨습니까? +박 상병 : 운전병 제초하러 갔대. 나중에 전화준댄다. +이 병장 : 김 일병, 언제 버리러 간대? +박 상병 : (...) +이 병장 : 이 폐급 새끼 또 내 말 씹네.. 존나 빡친다;; +김 일병 : 연락 되셨습니까? +박 상병 : ㅅㅂ 왜 자꾸 물어보냐 너 폐급이냐? 아직 전화 안왔다니까; +``` + +* Non-blocking & Asynchronous +``` +김 일병 : 박 상병님, 오늘 짬통 언제 버리러 갑니까? +박 상병 : 있어봐, 중대 운전병에게 물어볼게. +김 일병 : 넵! +박 상병 : (수고하십니다 XX대대 상병 박공군입니다) +박 상병 : 오늘 9시에 간댄다. 준비하자. +김 일병 : 넵! 짬통 일병들이랑 옮기고 있겠습니다. +``` + +#### 정리 +* Blocking/NonBlocking + * Blocking/NonBlocking은 호출되는 함수가 바로 리턴하느냐 마느냐가 관심사다. + * 호출된 함수가 바로 리턴해서 호출한 함수에게 제어권을 넘겨주고, 호출한 함수가 다른 일을 할 수 있는 기회를 줄 수 있으면 NonBlocking이다. + * 그렇지 않고 호출된 함수가 자신의 작업을 모두 마칠 때까지 호출한 함수에게 제어권을 넘겨주지 않고 대기하게 만든다면 Blocking이다. + +* Synchronous/Asynchronous + * Synchronous/Asynchronous는 호출되는 함수의 작업 완료 여부를 누가 신경쓰냐가 관심사다. + * 호출되는 함수에게 callback을 전달해서, 호출되는 함수의 작업이 완료되면 호출되는 함수가 전달받은 callback을 실행하고, 호출하는 함수는 작업 완료 여부를 신경쓰지 않으면 Asynchronous다. + * 호출하는 함수가 호출되는 함수의 작업 완료 후 리턴을 기다리거나, 또는 호출되는 함수로부터 바로 리턴 받더라도 작업 완료 여부를 호출하는 함수 스스로 계속 확인하며 신경쓰면 Synchronous다. + +### 추가 설명 +* Blocking 방식은 요청하고 응답 올때까지 기다리는 방식이고, Non-Blocking 방식은 요청하고 딴 일하다 나중에 응답신호가 오면 결과를 읽어 처리하는 방식이다. +* 동기방식은 요청자와 제공자사이에 계속 Connection이 맺어져 있어야 하고, 비동기방식은 Connection은 끊어지고 서로간에 이벤트를 통해 통신하는 방식이다. +* 비동기방식은 요청자와 제공자 사이에 Message Broker라는 또 다른 서비스가 중계해주지만, 동기 방식은 요청자 어플리케이션에 비동기 처리를 하는 로직이 있다. +* 최근 흔히 사용하는 REST API는 동기 방식이고 보통 Non-Blocking방식으로 통신한다. +* Frontend와 backend사이는 거의 대부분 동기+non-blocking 방식으로 구현한다. +* 비동기방식 패턴 중 제일 대표적인 것이 Publish/Subscribe (또는 Producer-Consumer) 패턴이다. + * Publisher인 유튜버들은 구독을 요청할 수 있는 채널을 만들고, 그 채널에 동영상을 계속 publishing해둔다. + * Subscriber인 사용자가 특정 유튜브채널을 구독 신청하면 새로운 동영상이 업로드 될때 첫화면에 추천동영상으로 받아보거나 모바일앱 알림 등으로 받아 볼 수 있게 된다. + * 즉, 사용자는 구독만 해놓고 있으면 새 동영상 올라올때까지 Youtube에 머물러 있을 필요가 없다. + * 비동기 메시징 방식은 추후 CS 스터디 주제로 발제할 생각이다. + * 이런 비동기 방식을 사용하는 이유는 큰 서비스를 이루는 마이크로서비스 중 하나가 실패해도 전체적인 서비스는 그대로 진행되도록 하기 위함이다. + * 예를 들어 쇼핑몰 상품 주문 시 주문서비스, 결제서비스, 배송서비스가 필요한데 동기방식으로 하면 결제나 배송 서비스에 문제가 생기면 상품 주문은 실패하게 된다. + * 그러나 비동기방식을 사용하면 Queue에 처리해야할 메시지가 있기 때문에 일시적 장애가 발생해도 복구가 되면 처리 가능하다. 따라서 상품 주문은 어떠한 경우에도 정상적으로 처리될 수 있게 된다. +* 일반적으로 Front와 Backend 서비스간에는 동기방식을 사용하고, backend의 서비스들간에는 비동기방식을 사용한다. +* 또한 데이터 조회 서비스는 동기방식을 사용하고, 데이터 변경 서비스는 비동기방식을 사용한다. + +### Spring WebFlux란 무엇일까? +* Non-blocking을 통해서 적은 수의 리소스로 동시성을 다룰 수 있게 해주는 프레임워크이다. +* 우리가 Spring MVC와 RDBMS를 사용하고 있으면 Blocking I/O를 사용하고 있는 것이다. +* Application에서 I/O 요청을 한 후 완료되기 전까지는 Application이 Block이 되어 다른 작업을 수행할 수 없다. 이는 해당 자원이 효율적으로 사용되지 못하고 있음을 의미한다. +* 물론, Blocking 방식임에도 불구하고 마치 Block이 안된듯이 동작하는 것처럼 보인다. 이는 멀티 쓰레드 기반의 방식이기 때문이다. 정확히는, 하나의 쓰레드가 블록되는 순간 다른 쓰레드가 동작하도록 함으로써 블록 문제를 해결하였다. +* 하지만 쓰레드 간의 Context Switching 등의 비용이 존재하므로, 여러 개의 I/O를 동시다발적으로 효율적인 처리를 하려면 논블로킹으로 처리해야만 한다. + +#### Blocking I/O 예시: RestTemplate +* RestTemplate은 Multi-Thread와 Blocking방식을 사용한다. +* Thread pool은 요청자 어플리케이션 구동시에 미리 만들어 놓는다. +* Request는 먼저 Queue에 쌓이고 가용한 스레드가 있으면 그 스레드에 할당되어 처리된다. +* 즉, 1 요청 당 1 스레드가 할당됩니다. +* 각 스레드에서는 Blocking방식으로 처리되어 응답이 올 때까지 그 스레드는 다른 요청에 할당될 수 없다. +* 아래는 RestTemplate을 Connection Pool에 Spring Bean으로 등록하기 위한 예제이다. + * 요청 당 20개의 RestTemplate client를 만들고, 최대 50개까지 증가할 수 있도록 했다. + +```java= +@Configuration +public class RestTemplateConfig { + public RestTemplate getRestTemplate(int defaultMaxPerRoute, int maxTotal) { + PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(); + connManager.setDefaultMaxPerRoute(defaultMaxPerRoute); + connManager.setMaxTotal(maxTotal); + + HttpClient client = HttpClientBuilder.create().setConnectionManager(connManager).build(); + + HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(client); + factory.setConnectTimeout(3000); + factory.setReadTimeout(3000); + + return new RestTemplate(factory); + + } + + @Bean + public RestTemplate coffeeRestTemplate() { + return getRestTemplate(20, 50); + } +} +``` +* 요청을 처리할 스레드가 있으면 아무런 문제가 없지만, 스레드가 다 차는 경우 이후의 요청은 Queue에 대기하게 된다. +* 대부분의 문제는 네트워킹이나 DB와의 통신에서 생기는데 이런 문제가 여러 스레드에서 발생하면 가용한 스레드수가 현저하게 줄어들게 되고, 결국 전체 서비스는 매우 느려지게 된다. +* RestTemplate을 이용하여 API 중 응답 시간이 약 3초 정도 걸리는 요청을 3번 반복하는 예제를 제시한다. +```java= +@Test +public void blocking() { + final RestTemplate restTemplate = new RestTemplate(); + + final StopWatch stopWatch = new StopWatch(); + stopWatch.start(); + + for (int i = 0; i < 3; i++) { + final ResponseEntity response = + restTemplate.exchange(THREE_SECOND_URL, HttpMethod.GET, HttpEntity.EMPTY, String.class); + assertThat(response.getBody()).contains("success"); + } + + stopWatch.stop(); + + System.out.println(stopWatch.getTotalTimeSeconds()); +} +``` +* Spring의 HTTP 요청 라이브러리인 RestTemplate을 사용하여 3초가 걸리는 API를 3번 호출하였다. 결과는 9.xx초가 나온다. 이유는 I/O가 요청 중일 때에는 아무 작업도 할 수 없기 때문이다. + +#### Non-Blocking I/O: WebClientSpring WebClient +* Spring WebClient는 Single Thread와 Non-Blocking방식을 사용한다. +* Core 당 1개의 Thread를 이용한다. +![](https://i.imgur.com/7MP2vt0.png) + + +[그림출처](https://luminousmen.com/post/asynchronous-programming-blocking-and-non-blocking) + +* 각 요청은 Event Loop내에 Job으로 등록이 된다. +* Event Loop는 각 Job을 제공자에게 요청한 후, 결과를 기다리지 않고 다른 Job을 처리한다. Event Loop는 제공자로부터 callback으로 응답이 오면, 그 결과를 요청자에게 제공한다. +* WebClient는 이렇게 이벤트에 반응형으로 동작하도록 설계되었다고 한다. +* 아래 예제는 위에서 제시한 요청시간이 약 3초 정도 걸리는 동일한 API를 가져왔다고 가정한 것이다. +```java= +@Test +public void nonBlocking3() throws InterruptedException { + final StopWatch stopWatch = new StopWatch(); + stopWatch.start(); + for (int i = 0; i < LOOP_COUNT; i++) { + this.webClient + .get() + .uri(THREE_SECOND_URL) + .retrieve() + .bodyToMono(String.class) + .subscribe(it -> { + count.countDown(); + System.out.println(it); + }); + } + + count.await(10, TimeUnit.SECONDS); + stopWatch.stop(); + System.out.println(stopWatch.getTotalTimeSeconds()); +} +``` +* WebFlux에서 제공하는 WebClient를 사용해서 위와 동일하게 3초가 걸리는 API를 호출하였다. for문 안의 변수인 LOOP_COUNT는 100으로 코드상에서 설정되어있다. 3초 걸리는 API를 100번 호출한다 하더라도 3.xx초 밖에 걸리지 않는다. +* 만약, Blocking을 위처럼 많은 요청을 동시에 처리하려면 그 만큼의 Thread이 생성되어야 한다. 그러나 이렇게 처리한다 해도 Context Swiching에 의한 오버헤드가 존재할 것이다. + +### 성능비교 +* 아래는 RestTemplate을 사용하는 Spring Boot1과 WebClient를 사용하는 Spring Boot2의 성능비교 결과이다. +* ![](https://i.imgur.com/ACQsu6g.png) + +* 1000명까지는 비슷하지만 동시사용자가 늘수록 RestTemplate은 급격하게 느려지는것을 볼 수 있다. +[그림출처](https://alwayspr.tistory.com/44) +* Spring 커뮤니티에서는 RestTemplate을 이미 Depreciated시키고 WebClient를 사용할것을 강력히 권고하고 있다. +``` +NOTE: As of 5.0 this class is in maintenance mode, +with only minor requests for changes and bugs to be accepted going forward. +Please, consider using the org.springframework.web.reactive.client.WebClient +which has a more modern API and supports sync, async, and streaming scenarios. +``` + +## 참고한 링크 +* https://velog.io/@codemcd/Sync-VS-Async-Blocking-VS-Non-Blocking-sak6d01fhx +* https://devahea.github.io/2019/04/21/Spring-WebFlux%EB%8A%94-%EC%96%B4%EB%96%BB%EA%B2%8C-%EC%A0%81%EC%9D%80-%EB%A6%AC%EC%86%8C%EC%8A%A4%EB%A1%9C-%EB%A7%8E%EC%9D%80-%ED%8A%B8%EB%9E%98%ED%94%BD%EC%9D%84-%EA%B0%90%EB%8B%B9%ED%95%A0%EA%B9%8C/ +* https://happycloud-lee.tistory.com/220 +* https://happycloud-lee.tistory.com/154?category=902418 +* https://musma.github.io/2019/04/17/blocking-and-synchronous.html +* http://homoefficio.github.io/2017/02/19/Blocking-NonBlocking-Synchronous-Asynchronous/ From dd16dad4868988ee8adf722e873b1548d5663a92 Mon Sep 17 00:00:00 2001 From: Jin Hyung Park Date: Sun, 15 Aug 2021 14:41:36 +0900 Subject: [PATCH 088/142] =?UTF-8?q?feat:=20=EB=84=A4=ED=8A=B8=EC=9B=8C?= =?UTF-8?q?=ED=81=AC=20CORS=20=ED=95=99=EC=8A=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- network/cors/sigrid/README.md | 139 ++++++++++++++++++++++++++++++++++ 1 file changed, 139 insertions(+) create mode 100644 network/cors/sigrid/README.md diff --git a/network/cors/sigrid/README.md b/network/cors/sigrid/README.md new file mode 100644 index 0000000..6936b5f --- /dev/null +++ b/network/cors/sigrid/README.md @@ -0,0 +1,139 @@ +# 네트워크: CORS란 무엇인가 +## CORS: Cross-Origin Resource Sharing +### Origin +* URL 구조에서 Protocol + Host + Port를 합친 것을 의미함 +```console +location.source +> https://hackmd.io +``` +* 간단한 퀴즈: 다음 중 같은 출처가 아닌 것은? + * ```https://hackmd.io/about```: 같은 출처 + * ```https://hackmd.io:32/about```: 다른 출처(Port 다름) + * ```http://hackmd.io```: 다른 출처(Protocol 다름) + +### Same-Origin Policy +* Postman으로 API를 호출하면 잘 되는데, 브라우저로 호출하면 CORS 에러가 나는 이유는 무엇일까? +* 브라우저가 동일 출처 정책(Same Origin Policy)를 준수하기 때문에 그렇다. +* 예를 들어 hackmd.io 사이트에서 medium.com의 API를 호출하면 서로 다른 출처이므로 CORS 에러가 발생할 수 있다. +* 동일 출처 정책은 XSS나 XSRF 등의 보안 취약점을 노린 공격을 방어할 수 있다. +* 하지만 외부 리소스를 사용해야 하는 경우는 매우 많다. SOP 정책의 예외 사항이 CORS라고 할 수 있다. + +### CORS 동작 원리 +* Simple Request와 Preflight Request가 있지만, 주로 Preflight Request 방식이 선호된다. + +![](https://i.imgur.com/Wv9msLm.png) +* Preflight 요청은 실제 리소스를 요청하기 전에 OPTIONS라는 메서드를 통해 실제 요청을 전송할지 판단한다. +* OPTIONS 메서드로 서버에 예비 요청을 먼저 보내고, 서버는 이 예비 요청에 대한 응답으로 Access-Control-Allow-Origin 헤더를 포함한 응답을 브라우저에 보낸다. +* 브라우저는 단순 요청과 동일하게 Access-Control-Allow-Origin 헤더를 확인해서 CORS 동작을 수행할지 판단한다. + +### CORS 에러 해결 방법 +* 서버에서 ```Access-Control-Allow-Origin``` 헤더를 포함한 응답을 브라우저에 보내는 방식으로 CORS 에러를 해결할 수 있다. +* Node.js 기준으로 cors라는 라이브러리가 있고, Spring Boot에서는 WebMvcController를 설정해주면 된다. + +#### Access-Control-Allow-Origin: | * +* 헤더가 작성된 링크만 브라우저가 접근할 수 있도록 설정할 수 있다. +* 사용 예시 +``` +Access-Control-Allow-Origin: https://medium.com +``` +``` +Access-Control-Allow-Origin: * // 와일드 카드를 쓰면 모든 사이트 다 된다 +``` +* 서버에서 아래와 같이 응답 헤더를 설정해서 보내주면 된다. +```javascript= +router.options('/cors', (req, res, next) => { + res.set('Access-Control-Allow-Origin', '*') + res.send() +}) +router.put('/cors', (req, res, next) => { + res.set('Access-Control-Allow-Origin', '*') + res.send() +}) +``` +#### Access-Control-Allow-Methods: [, ]* +* 리소스 접근을 허용하는 HTTP 메서드를 지정해 주는 헤더이다. +```javascript= +router.options('/cors', (req, res, next) => { + res.set('Access-Control-Allow-Origin', '*') + res.set('Access-Control-Allow-Methods', req.get('Access-Control-Request-Method')) + res.send() +}) +router.put('/cors', (req, res, next) => { + res.set('Access-Control-Allow-Origin', '*') + res.send() +}) +``` +#### Access-Control-Expose-Headers: [, ]* +* 서버에서 응답 헤더에 Access-Control-Expose-Headers를 추가해 줘야 브라우저의 자바스크립트에서 헤더에 접근할 수 있다. +```javascript= +router.options('/cors', (req, res, next) => { + res.set('Access-Control-Allow-Origin', '*') + res.set('Access-Control-Allow-Methods', req.get('Access-Control-Request-Method')) + res.send() +}) +router.put('/cors', (req, res, next) => { + res.set('Access-Control-Allow-Origin', '*') + res.set('Access-Control-Expose-Headers', 'X-Custom-Beomy') + res.set('X-Custom-Beomy', 'Bemoy') + res.send() +}) +``` + +#### Access-Control-Allow-Headers: [, ]* +* 브라우저에서 보내는 요청 헤더에 포함된 Access-Control-Request-Headers 헤더에 대한 응답 결과이다. +```javascript= +router.options('/cors', (req, res, next) => { + res.set('Access-Control-Allow-Origin', '*') + res.set('Access-Control-Allow-Methods', req.get('Access-Control-Request-Method')) + res.set('Access-Control-Allow-Headers', req.get('Access-Control-Request-Headers')) + res.send() +}) +router.put('/cors', (req, res, next) => { + res.set('Access-Control-Allow-Origin', '*') + console.log(req.get('X-Custom-Request')) // Beomy + res.send() +}) +``` +#### Access-Control-Max-Age: +* preflight 요청 결과를 캐시 할 수 있는 시간을 나타낸다. +* 아래와 같이 초 단위로 캐시 시간을 설정한다. +``` +Access-Control-Max-Age: 60 +``` +* 위의 코드는 60초 동안 preflight 요청을 캐시 하는 코드이다. +* 60초 동안 OPTIONS 메서드를 사용하는 예비 요청을 보내지 않습니다. +```javascript= +router.options('/cors', (req, res, next) => { + res.set('Access-Control-Allow-Origin', '*') + res.set('Access-Control-Allow-Methods', req.get('Access-Control-Request-Method')) + res.set('Access-Control-Max-Age', 60) + res.send() +}) +router.put('/cors', (req, res, next) => { + res.set('Access-Control-Allow-Origin', '*') + res.send() +}) +``` +#### Access-Control-Allow-Credentials: true +* 자바스크립트 요청에서 credentials가 include일 때 요청에 대한 응답을 할 수 있는지를 나타낸다. +* false로 설정해 주고 싶을 경우에는 헤더를 생략하면 된다. +```javascript= +router.options('/cors', (req, res, next) => { + res.set('Access-Control-Allow-Origin', 'https://www.google.com') + res.set('Access-Control-Allow-Methods', req.get('Access-Control-Request-Method')) + res.set('Access-Control-Allow-Credentials', true) + res.send() +}) +router.put('/cors', (req, res, next) => { + res.set('Access-Control-Allow-Origin', 'https://www.google.com') + res.set('Access-Control-Allow-Credentials', true) + res.send() +}) +``` +* Access-Control-Allow-Credentials: true 추가 뿐만 아니라, Access-Control-Allow-Origin 헤더도 와일드카드가 아닌 출처를 명시해주어야 한다. + +## 프록시 서버 +* 프론트엔드와 백엔드 사이에 프록시 서버를 두어서 CORS를 해결할 수 있다. +* 개발 환경에서는 Webpack Dev Server 등의 라이브러리를 사용하여 프록시 설정을 할 수 있다. + +## 참고 링크 From b2ca8ecd488e936b413980c807e13d851886ee3c Mon Sep 17 00:00:00 2001 From: Jin Hyung Park Date: Sun, 15 Aug 2021 14:42:36 +0900 Subject: [PATCH 089/142] Delete README.md --- network/cors/sigrid/README.md | 139 ---------------------------------- 1 file changed, 139 deletions(-) delete mode 100644 network/cors/sigrid/README.md diff --git a/network/cors/sigrid/README.md b/network/cors/sigrid/README.md deleted file mode 100644 index 6936b5f..0000000 --- a/network/cors/sigrid/README.md +++ /dev/null @@ -1,139 +0,0 @@ -# 네트워크: CORS란 무엇인가 -## CORS: Cross-Origin Resource Sharing -### Origin -* URL 구조에서 Protocol + Host + Port를 합친 것을 의미함 -```console -location.source -> https://hackmd.io -``` -* 간단한 퀴즈: 다음 중 같은 출처가 아닌 것은? - * ```https://hackmd.io/about```: 같은 출처 - * ```https://hackmd.io:32/about```: 다른 출처(Port 다름) - * ```http://hackmd.io```: 다른 출처(Protocol 다름) - -### Same-Origin Policy -* Postman으로 API를 호출하면 잘 되는데, 브라우저로 호출하면 CORS 에러가 나는 이유는 무엇일까? -* 브라우저가 동일 출처 정책(Same Origin Policy)를 준수하기 때문에 그렇다. -* 예를 들어 hackmd.io 사이트에서 medium.com의 API를 호출하면 서로 다른 출처이므로 CORS 에러가 발생할 수 있다. -* 동일 출처 정책은 XSS나 XSRF 등의 보안 취약점을 노린 공격을 방어할 수 있다. -* 하지만 외부 리소스를 사용해야 하는 경우는 매우 많다. SOP 정책의 예외 사항이 CORS라고 할 수 있다. - -### CORS 동작 원리 -* Simple Request와 Preflight Request가 있지만, 주로 Preflight Request 방식이 선호된다. - -![](https://i.imgur.com/Wv9msLm.png) -* Preflight 요청은 실제 리소스를 요청하기 전에 OPTIONS라는 메서드를 통해 실제 요청을 전송할지 판단한다. -* OPTIONS 메서드로 서버에 예비 요청을 먼저 보내고, 서버는 이 예비 요청에 대한 응답으로 Access-Control-Allow-Origin 헤더를 포함한 응답을 브라우저에 보낸다. -* 브라우저는 단순 요청과 동일하게 Access-Control-Allow-Origin 헤더를 확인해서 CORS 동작을 수행할지 판단한다. - -### CORS 에러 해결 방법 -* 서버에서 ```Access-Control-Allow-Origin``` 헤더를 포함한 응답을 브라우저에 보내는 방식으로 CORS 에러를 해결할 수 있다. -* Node.js 기준으로 cors라는 라이브러리가 있고, Spring Boot에서는 WebMvcController를 설정해주면 된다. - -#### Access-Control-Allow-Origin: | * -* 헤더가 작성된 링크만 브라우저가 접근할 수 있도록 설정할 수 있다. -* 사용 예시 -``` -Access-Control-Allow-Origin: https://medium.com -``` -``` -Access-Control-Allow-Origin: * // 와일드 카드를 쓰면 모든 사이트 다 된다 -``` -* 서버에서 아래와 같이 응답 헤더를 설정해서 보내주면 된다. -```javascript= -router.options('/cors', (req, res, next) => { - res.set('Access-Control-Allow-Origin', '*') - res.send() -}) -router.put('/cors', (req, res, next) => { - res.set('Access-Control-Allow-Origin', '*') - res.send() -}) -``` -#### Access-Control-Allow-Methods: [, ]* -* 리소스 접근을 허용하는 HTTP 메서드를 지정해 주는 헤더이다. -```javascript= -router.options('/cors', (req, res, next) => { - res.set('Access-Control-Allow-Origin', '*') - res.set('Access-Control-Allow-Methods', req.get('Access-Control-Request-Method')) - res.send() -}) -router.put('/cors', (req, res, next) => { - res.set('Access-Control-Allow-Origin', '*') - res.send() -}) -``` -#### Access-Control-Expose-Headers: [, ]* -* 서버에서 응답 헤더에 Access-Control-Expose-Headers를 추가해 줘야 브라우저의 자바스크립트에서 헤더에 접근할 수 있다. -```javascript= -router.options('/cors', (req, res, next) => { - res.set('Access-Control-Allow-Origin', '*') - res.set('Access-Control-Allow-Methods', req.get('Access-Control-Request-Method')) - res.send() -}) -router.put('/cors', (req, res, next) => { - res.set('Access-Control-Allow-Origin', '*') - res.set('Access-Control-Expose-Headers', 'X-Custom-Beomy') - res.set('X-Custom-Beomy', 'Bemoy') - res.send() -}) -``` - -#### Access-Control-Allow-Headers: [, ]* -* 브라우저에서 보내는 요청 헤더에 포함된 Access-Control-Request-Headers 헤더에 대한 응답 결과이다. -```javascript= -router.options('/cors', (req, res, next) => { - res.set('Access-Control-Allow-Origin', '*') - res.set('Access-Control-Allow-Methods', req.get('Access-Control-Request-Method')) - res.set('Access-Control-Allow-Headers', req.get('Access-Control-Request-Headers')) - res.send() -}) -router.put('/cors', (req, res, next) => { - res.set('Access-Control-Allow-Origin', '*') - console.log(req.get('X-Custom-Request')) // Beomy - res.send() -}) -``` -#### Access-Control-Max-Age: -* preflight 요청 결과를 캐시 할 수 있는 시간을 나타낸다. -* 아래와 같이 초 단위로 캐시 시간을 설정한다. -``` -Access-Control-Max-Age: 60 -``` -* 위의 코드는 60초 동안 preflight 요청을 캐시 하는 코드이다. -* 60초 동안 OPTIONS 메서드를 사용하는 예비 요청을 보내지 않습니다. -```javascript= -router.options('/cors', (req, res, next) => { - res.set('Access-Control-Allow-Origin', '*') - res.set('Access-Control-Allow-Methods', req.get('Access-Control-Request-Method')) - res.set('Access-Control-Max-Age', 60) - res.send() -}) -router.put('/cors', (req, res, next) => { - res.set('Access-Control-Allow-Origin', '*') - res.send() -}) -``` -#### Access-Control-Allow-Credentials: true -* 자바스크립트 요청에서 credentials가 include일 때 요청에 대한 응답을 할 수 있는지를 나타낸다. -* false로 설정해 주고 싶을 경우에는 헤더를 생략하면 된다. -```javascript= -router.options('/cors', (req, res, next) => { - res.set('Access-Control-Allow-Origin', 'https://www.google.com') - res.set('Access-Control-Allow-Methods', req.get('Access-Control-Request-Method')) - res.set('Access-Control-Allow-Credentials', true) - res.send() -}) -router.put('/cors', (req, res, next) => { - res.set('Access-Control-Allow-Origin', 'https://www.google.com') - res.set('Access-Control-Allow-Credentials', true) - res.send() -}) -``` -* Access-Control-Allow-Credentials: true 추가 뿐만 아니라, Access-Control-Allow-Origin 헤더도 와일드카드가 아닌 출처를 명시해주어야 한다. - -## 프록시 서버 -* 프론트엔드와 백엔드 사이에 프록시 서버를 두어서 CORS를 해결할 수 있다. -* 개발 환경에서는 Webpack Dev Server 등의 라이브러리를 사용하여 프록시 설정을 할 수 있다. - -## 참고 링크 From 6abf18db13698f904e81d744aece042f3a693c95 Mon Sep 17 00:00:00 2001 From: Jin Hyung Park Date: Sun, 15 Aug 2021 14:43:04 +0900 Subject: [PATCH 090/142] =?UTF-8?q?feat:=20CORS=20=ED=95=99=EC=8A=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- network/cors/sigrid/README.md | 139 ++++++++++++++++++++++++++++++++++ 1 file changed, 139 insertions(+) create mode 100644 network/cors/sigrid/README.md diff --git a/network/cors/sigrid/README.md b/network/cors/sigrid/README.md new file mode 100644 index 0000000..6936b5f --- /dev/null +++ b/network/cors/sigrid/README.md @@ -0,0 +1,139 @@ +# 네트워크: CORS란 무엇인가 +## CORS: Cross-Origin Resource Sharing +### Origin +* URL 구조에서 Protocol + Host + Port를 합친 것을 의미함 +```console +location.source +> https://hackmd.io +``` +* 간단한 퀴즈: 다음 중 같은 출처가 아닌 것은? + * ```https://hackmd.io/about```: 같은 출처 + * ```https://hackmd.io:32/about```: 다른 출처(Port 다름) + * ```http://hackmd.io```: 다른 출처(Protocol 다름) + +### Same-Origin Policy +* Postman으로 API를 호출하면 잘 되는데, 브라우저로 호출하면 CORS 에러가 나는 이유는 무엇일까? +* 브라우저가 동일 출처 정책(Same Origin Policy)를 준수하기 때문에 그렇다. +* 예를 들어 hackmd.io 사이트에서 medium.com의 API를 호출하면 서로 다른 출처이므로 CORS 에러가 발생할 수 있다. +* 동일 출처 정책은 XSS나 XSRF 등의 보안 취약점을 노린 공격을 방어할 수 있다. +* 하지만 외부 리소스를 사용해야 하는 경우는 매우 많다. SOP 정책의 예외 사항이 CORS라고 할 수 있다. + +### CORS 동작 원리 +* Simple Request와 Preflight Request가 있지만, 주로 Preflight Request 방식이 선호된다. + +![](https://i.imgur.com/Wv9msLm.png) +* Preflight 요청은 실제 리소스를 요청하기 전에 OPTIONS라는 메서드를 통해 실제 요청을 전송할지 판단한다. +* OPTIONS 메서드로 서버에 예비 요청을 먼저 보내고, 서버는 이 예비 요청에 대한 응답으로 Access-Control-Allow-Origin 헤더를 포함한 응답을 브라우저에 보낸다. +* 브라우저는 단순 요청과 동일하게 Access-Control-Allow-Origin 헤더를 확인해서 CORS 동작을 수행할지 판단한다. + +### CORS 에러 해결 방법 +* 서버에서 ```Access-Control-Allow-Origin``` 헤더를 포함한 응답을 브라우저에 보내는 방식으로 CORS 에러를 해결할 수 있다. +* Node.js 기준으로 cors라는 라이브러리가 있고, Spring Boot에서는 WebMvcController를 설정해주면 된다. + +#### Access-Control-Allow-Origin: | * +* 헤더가 작성된 링크만 브라우저가 접근할 수 있도록 설정할 수 있다. +* 사용 예시 +``` +Access-Control-Allow-Origin: https://medium.com +``` +``` +Access-Control-Allow-Origin: * // 와일드 카드를 쓰면 모든 사이트 다 된다 +``` +* 서버에서 아래와 같이 응답 헤더를 설정해서 보내주면 된다. +```javascript= +router.options('/cors', (req, res, next) => { + res.set('Access-Control-Allow-Origin', '*') + res.send() +}) +router.put('/cors', (req, res, next) => { + res.set('Access-Control-Allow-Origin', '*') + res.send() +}) +``` +#### Access-Control-Allow-Methods: [, ]* +* 리소스 접근을 허용하는 HTTP 메서드를 지정해 주는 헤더이다. +```javascript= +router.options('/cors', (req, res, next) => { + res.set('Access-Control-Allow-Origin', '*') + res.set('Access-Control-Allow-Methods', req.get('Access-Control-Request-Method')) + res.send() +}) +router.put('/cors', (req, res, next) => { + res.set('Access-Control-Allow-Origin', '*') + res.send() +}) +``` +#### Access-Control-Expose-Headers: [, ]* +* 서버에서 응답 헤더에 Access-Control-Expose-Headers를 추가해 줘야 브라우저의 자바스크립트에서 헤더에 접근할 수 있다. +```javascript= +router.options('/cors', (req, res, next) => { + res.set('Access-Control-Allow-Origin', '*') + res.set('Access-Control-Allow-Methods', req.get('Access-Control-Request-Method')) + res.send() +}) +router.put('/cors', (req, res, next) => { + res.set('Access-Control-Allow-Origin', '*') + res.set('Access-Control-Expose-Headers', 'X-Custom-Beomy') + res.set('X-Custom-Beomy', 'Bemoy') + res.send() +}) +``` + +#### Access-Control-Allow-Headers: [, ]* +* 브라우저에서 보내는 요청 헤더에 포함된 Access-Control-Request-Headers 헤더에 대한 응답 결과이다. +```javascript= +router.options('/cors', (req, res, next) => { + res.set('Access-Control-Allow-Origin', '*') + res.set('Access-Control-Allow-Methods', req.get('Access-Control-Request-Method')) + res.set('Access-Control-Allow-Headers', req.get('Access-Control-Request-Headers')) + res.send() +}) +router.put('/cors', (req, res, next) => { + res.set('Access-Control-Allow-Origin', '*') + console.log(req.get('X-Custom-Request')) // Beomy + res.send() +}) +``` +#### Access-Control-Max-Age: +* preflight 요청 결과를 캐시 할 수 있는 시간을 나타낸다. +* 아래와 같이 초 단위로 캐시 시간을 설정한다. +``` +Access-Control-Max-Age: 60 +``` +* 위의 코드는 60초 동안 preflight 요청을 캐시 하는 코드이다. +* 60초 동안 OPTIONS 메서드를 사용하는 예비 요청을 보내지 않습니다. +```javascript= +router.options('/cors', (req, res, next) => { + res.set('Access-Control-Allow-Origin', '*') + res.set('Access-Control-Allow-Methods', req.get('Access-Control-Request-Method')) + res.set('Access-Control-Max-Age', 60) + res.send() +}) +router.put('/cors', (req, res, next) => { + res.set('Access-Control-Allow-Origin', '*') + res.send() +}) +``` +#### Access-Control-Allow-Credentials: true +* 자바스크립트 요청에서 credentials가 include일 때 요청에 대한 응답을 할 수 있는지를 나타낸다. +* false로 설정해 주고 싶을 경우에는 헤더를 생략하면 된다. +```javascript= +router.options('/cors', (req, res, next) => { + res.set('Access-Control-Allow-Origin', 'https://www.google.com') + res.set('Access-Control-Allow-Methods', req.get('Access-Control-Request-Method')) + res.set('Access-Control-Allow-Credentials', true) + res.send() +}) +router.put('/cors', (req, res, next) => { + res.set('Access-Control-Allow-Origin', 'https://www.google.com') + res.set('Access-Control-Allow-Credentials', true) + res.send() +}) +``` +* Access-Control-Allow-Credentials: true 추가 뿐만 아니라, Access-Control-Allow-Origin 헤더도 와일드카드가 아닌 출처를 명시해주어야 한다. + +## 프록시 서버 +* 프론트엔드와 백엔드 사이에 프록시 서버를 두어서 CORS를 해결할 수 있다. +* 개발 환경에서는 Webpack Dev Server 등의 라이브러리를 사용하여 프록시 설정을 할 수 있다. + +## 참고 링크 From 7140e1c78189af6f79c61c345982fab5dab77bf9 Mon Sep 17 00:00:00 2001 From: Jin Hyung Park Date: Sun, 15 Aug 2021 14:48:33 +0900 Subject: [PATCH 091/142] Update README.md --- network/blocking-vs-non-blocking/sigrid/README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/network/blocking-vs-non-blocking/sigrid/README.md b/network/blocking-vs-non-blocking/sigrid/README.md index e32a423..a738b3f 100644 --- a/network/blocking-vs-non-blocking/sigrid/README.md +++ b/network/blocking-vs-non-blocking/sigrid/README.md @@ -89,9 +89,9 @@ ios.loop() 박 상병 : 있어봐, 중대 운전병에게 물어볼게. 김 일병 : (...) 대표님 : (수고하십니다 XX대대 상병 박공군입니다) -김 일병 : (과정 지켜봄.. 궁금함.. 계속 서 있음) +김 일병 : (박 상병님 전화 받고 있는 것을 수화기를 들고 같이 듣고 있음) 이 병장: 김 일병, 언제 버리러 가는거야? -김 일병: (박 상병님 전화 받고 있는 것을 수화기를 들고 같이 듣고 있음) 지금 전화 중이십니다. 잠시만 기다려주십시오. +김 일병: (수화기로 전화 내용을 듣고 있으며 말한다) 지금 전화 중이십니다. 잠시만 기다려주십시오. 이 병장: 오오 알겠어. ``` * Blocking & Asynchronous @@ -117,8 +117,8 @@ ios.loop() 김 일병 : 연락 되셨습니까? 박 상병 : 운전병 제초하러 갔대. 나중에 전화준댄다. 이 병장 : 김 일병, 언제 버리러 간대? -박 상병 : (...) -이 병장 : 이 폐급 새끼 또 내 말 씹네.. 존나 빡친다;; +박 상병 : 하.. 조금 이따 연락 주신다고 하는데 저도 진짜 궁금합니다. +이 병장 : 그래? 알겠어. 김 일병 : 연락 되셨습니까? 박 상병 : ㅅㅂ 왜 자꾸 물어보냐 너 폐급이냐? 아직 전화 안왔다니까; ``` From 0ba65a91b0928474c7ede827638297a788c54715 Mon Sep 17 00:00:00 2001 From: Jin Hyung Park Date: Sun, 15 Aug 2021 14:52:04 +0900 Subject: [PATCH 092/142] Update README.md --- network/blocking-vs-non-blocking/sigrid/README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/network/blocking-vs-non-blocking/sigrid/README.md b/network/blocking-vs-non-blocking/sigrid/README.md index a738b3f..765315f 100644 --- a/network/blocking-vs-non-blocking/sigrid/README.md +++ b/network/blocking-vs-non-blocking/sigrid/README.md @@ -92,7 +92,9 @@ ios.loop() 김 일병 : (박 상병님 전화 받고 있는 것을 수화기를 들고 같이 듣고 있음) 이 병장: 김 일병, 언제 버리러 가는거야? 김 일병: (수화기로 전화 내용을 듣고 있으며 말한다) 지금 전화 중이십니다. 잠시만 기다려주십시오. -이 병장: 오오 알겠어. +이 병장: 오오 알겠어. 그런데 너 왜 마저 일 안 보는 거야? +김 일병: 네 버리러 가야하는데.. 언제 갈 지를 몰라서 일 하기가 조금 그렇습니다.. +이 병장: ??? 뭐지 ? ``` * Blocking & Asynchronous ``` From 16d84d2f66d5c5005234838801debad2508fff1e Mon Sep 17 00:00:00 2001 From: Jin Hyung Park Date: Sun, 15 Aug 2021 14:54:32 +0900 Subject: [PATCH 093/142] Update README.md --- network/blocking-vs-non-blocking/sigrid/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/network/blocking-vs-non-blocking/sigrid/README.md b/network/blocking-vs-non-blocking/sigrid/README.md index 765315f..1ee0bab 100644 --- a/network/blocking-vs-non-blocking/sigrid/README.md +++ b/network/blocking-vs-non-blocking/sigrid/README.md @@ -119,9 +119,9 @@ ios.loop() 김 일병 : 연락 되셨습니까? 박 상병 : 운전병 제초하러 갔대. 나중에 전화준댄다. 이 병장 : 김 일병, 언제 버리러 간대? -박 상병 : 하.. 조금 이따 연락 주신다고 하는데 저도 진짜 궁금합니다. -이 병장 : 그래? 알겠어. -김 일병 : 연락 되셨습니까? +김 일병 : 하.. 조금 이따 연락 주신다고 하는데 저도 진짜 궁금합니다. 일단 저는 화장실 청소 좀 하고 있겠습니다. +이 병장 : 그래? 알겠어. 박 상병이 전화 오면 알려주겠지. 조금 이따 물어보면 될 거 같아. +김 일병 : (다른 일 보다가 물어본다) 연락 되셨습니까? 박 상병 : ㅅㅂ 왜 자꾸 물어보냐 너 폐급이냐? 아직 전화 안왔다니까; ``` From c2355e88b6752de1fb1fa90263935f104506b9f6 Mon Sep 17 00:00:00 2001 From: 102092 Date: Mon, 2 Aug 2021 21:44:29 +0900 Subject: [PATCH 094/142] Add type of keys --- database/type-of-keys/han/README.md | 76 +++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 database/type-of-keys/han/README.md diff --git a/database/type-of-keys/han/README.md b/database/type-of-keys/han/README.md new file mode 100644 index 0000000..2f3f55a --- /dev/null +++ b/database/type-of-keys/han/README.md @@ -0,0 +1,76 @@ +# 데이터베이스에서 Key란? +- 데이터베이스 관리시스템에서 보통 키란, table (relation) 중 하나의 row (tuple) 가 유니크함을 나타내는 데 사용되는 속성을 의미하는 듯. +- 즉 해당 릴레이션에 똑같은 row (tuple) 이 존재하지 않음을 보장한다는 것. + +# 키의 종류 +- Primary Key, Candidate Key, Super Key, ForeignKey, Composite Key, Alternate Key, Unique Key, Natural Key.. + +# Primary key +- 보통 PK라 부른다. +- PK는 기본적으로 null 을 허용하거나, 중복을 허용하지 않는다. +- 즉 하나의 테이블에는, 그 PK가 유일함이 보장된다. +- 관계형 모델에는 기본키라는 개념이 없음. + - 릴레이션에 여러개의 후보키가 있는 경우, 이 키들은 의미적, 기능적으로 차이가 없고, 어느 키던지 아래 기본키로 설정할 수 있기 때문에 + +# Super key +- 슈퍼키 +- 슈퍼키는 모든 키들의 집합 +- 또한, 슈퍼키는 해당 row가 테이블에서 unique 함을 나타내는데 도와줌. +- 슈퍼키는 여러 가지 추가속성을 가지고 있음. + - 그리고 이 추가속성은 고유한 row를 나타냄에 있어 도움이 되지 않을 수도 있다. +- **참고 이미지** +![](https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F74FZR%2FbtqClyMJ0sx%2Fay7x7W2V3cWukTMoyYHp51%2Fimg.png) + - 후보키는 슈퍼키의 일종이며, 가지고 있는 추가속성의 수가 최소한 이다. + +# Candidate key +- 후보키 +- 릴레이션의 해당 row를 unique함을 나타낼 수 있는 속성들을 의미함. +- PK의 경우 , Candidate key 중 하나임. +- 후보키는 릴레이션에 한 개 이상 존재할 수 있다. + +# Alternate key +- 대체키 +- 후보키 중에서, PK로 선택받지 못한 키를 의미. + + +# Foreign key +- 외래키 +- 2개의 릴레이션(테이블) 의 관계를 정립하는 데 사용되는 키를 의미. +- 각각의 외래키는 보통 각 릴레이션의 PK에 해당할 것. + +# Composite key +- 복합키 +- 2개 혹은 더 많은 속성들로 이루어진 집합으로, 해당 row(tuple) 이 릴레이션에서 유니크함을 식별하는데 사용함. +- 각각의 속성을 나눠서 보면, 유니크하지 않을 수 있음 + - 즉 같이 합쳐서 있을 때, 집합으로 볼 때 유니크함이 보장됨을 알 수 있음. + +# Unique key +- 유니크 키 +- 릴레이션의 해당 row가 unique함을 나타낼 수 있음. +- PK란 다른점이라면.. nullable 하다는 점.. + - 그리고 PK는 테이블에서 하나의 컬럼에만 해당하지만, Unique 는 여러개 컬럼이 가능할듯..? +- 참고 + - https://blog.shovelman.dev/777 + +# Natural key +- 자연키 +- 이미 이 세상에 존재하는 어떤 단어나, 꼬리표를 키로 사용하는 것. +- 중복될 가능성이 있음. 예시 --> 사람 이름. +- 그럼 Natural key는 Database에서 PK로 사용될 수 없을까? + - 현실과 DB가 1:1 로 대응하고 있는 상황이라면.. ID로 사용해도 괜찮음. + +# Surrogate key +- 대체키 +- 릴레이션에 마땅한 후보키가 없을 경우, Database에서 식별을 위해 생성한, 선언된 키를 의미. +- 관계형 모델이는 자연키, 대체키란 개념이 없음. + - 관계형 모델이는 후보키, 슈포키 뿐이다. +- 참고 + - https://bunhere.tistory.com/45 + - https://www.toolbox.com/tech/data-management/question/the-difference-between-a-primary-key-and-a-surrogate-key-011407/ + +# 참고 +- https://www.upgrad.com/blog/types-of-keys-in-dbms/ +- https://kosaf04pyh.tistory.com/201 + +- 관계형 데이터 베이스 실전 입문 + - 3장, 6장 From b7b43f7813b21cca5deb5781bc570ef3b337d627 Mon Sep 17 00:00:00 2001 From: 102092 Date: Mon, 2 Aug 2021 23:57:19 +0900 Subject: [PATCH 095/142] Add my sql query plan --- database/mysql-query-plan/han/README.md | 177 ++++++++++++++++++++++++ 1 file changed, 177 insertions(+) create mode 100644 database/mysql-query-plan/han/README.md diff --git a/database/mysql-query-plan/han/README.md b/database/mysql-query-plan/han/README.md new file mode 100644 index 0000000..162ce56 --- /dev/null +++ b/database/mysql-query-plan/han/README.md @@ -0,0 +1,177 @@ +# SELECT 쿼리 실행 순서 +- 작성하는 쿼리문의 순서와, 실제 DB에서 실행되는 순서가 다름. +- +- 보통 Select query 문법 순서 + 1. SELECT + 2. FROM + 3. WHERE + 4. GROUP BY + 5. ORDER BY +- 실제 실행 순서 + 1. FROM + - Sub Query.. 있으면 임시테이블 생성됨. + 2. ON + 3. JOIN + 4. WHERE + 5. GROUP BY + 6. HAVING + 7. SELECT + 8. DISTINCT + 9. ORDER BY + 10. LIMIT, OFFSET + +- 참고 + - https://dion-ko.tistory.com/85 + - https://daeuungcode.tistory.com/144 + + +# MySQL Explain +- 기본적으로 SELECT, INSERT, DELETE, REPLACE, UPDATE 쿼리문의 실행플랜을 분석하는 데 사용하는 키워드. +- 해당 쿼리를 실제 실행하는 것은 아니고, 데이터베이스에게 어떻게 실행할 건지 계획을 받아보는 방법임. +- 아래와 같이 사용함. +```sql +EXPLAIN +SELECT * +FROM foo +WHERE foo.bar = 'infrastructure as a service' OR foo.bar = 'iaas'; +``` +- `DESCRIBE` 라는 방법도 있는 데 이는 `Explain`이란 동일한 기능인듯. + - 참고 + - https://dev.mysql.com/doc/refman/5.7/en/describe.html + + +## Explain 결과 이해하기 + +### table +- 어떤 테이블에 접근하고 있는지 알려줌. + +### id +- SELECT를 몇번이나 실행하는 지의 숫자를 나타낸 값인듯. +- 해당 쿼리가 Subquery 또는 Union query를 포함하고 있지 않으면 항상 1의 값을 가짐. + +### select_type +- SELECT Query에 대한 타입 +- SIMPLE (서브쿼리, 유니온 쿼리 없이 실행된 쿼리) +- SUBQUERY +- UNION +- DERIVED +- 참고 + - https://dev.mysql.com/doc/refman/5.7/en/explain-output.html#explain_select_type + +### partitions +- 해당 테이블이 파티셔닝 되어있을 경우, 사용되는 필드 +- `NULL` 은 해당 쿼리에서 사용되는 테이블이 파티셔닝 되지 않았을을 의미 + + +### type +- 어떻게 해당 테이블에 접근하고 있는가를 나타낸 필드 +- 이 필드는 실행될 쿼리의 **효율성**을 판단하는 데 가장 중요한 필드 임 +- `system` + - 테이블에 하나의 row만 있을 경우 +- `const` + - 테이블에 하나의 매칭된 row만 있을 경우 + - 이 타입은 해당 쿼리가 굉장히 빠르게 실행될 수 있음을 의미 +- `eq_ref` + - 조인을 사용할 때 나타나는 타입 + - 이전 테이블과 조인을 할 때, 지금 테이블에서 하나의 로우만이 매칭된다는 의미인듯. + - **Join할 때의 best practice** + - 해당 row가 Prmiary key 혹은 Unique key이면서 NOT NULL인 인덱스 일 경우에 해당 타입이 사용됨. +- `ref` + - 조인을 사용할 때 나타나는 타입 + - Primary key, Unique key가 아닌 Key와 매칭되는 경우 + - 즉 조인할 때, 하나의 row만으로 되지 않는 경우 + - 만약에 매칭되는 row의 수가 적다면, 이 또한 조인할 경우 좋은 타입이라 말할 수 있음. +- `ref_or_null` + - `ref` 타입과 비슷 + - 그렇지만 해당 row `null` 이 포함된 row까지 탐색하고 있다는 뜻임. + ```sql + SELECT * FROM ref_table + WHERE key_column=expr OR key_column IS NULL; + ``` + - 아무래도 `null` 까지 탐색 조건에 들어가니, `ref` 타입보다는 별로이지 않을까. + +- `range` + - 인덱스를 사용해서, 특정 row 에 범위 접근할 때 사용되는 타입 + - Explain 결과 colum 중 `key` 는 해당 인덱스가 가리키고 있는 column임 + - `=`, `<>`, `>`, `>=`, `<`, `<=`, `IS NULL`, `<=>`, `BETWEEN`, `LIKE`, `IN()`, 연산자를 사용할 때 보통 나타나는 타입임 + ```sql + SELECT * FROM tbl_name + WHERE key_column = 10; + + SELECT * FROM tbl_name + WHERE key_column BETWEEN 10 and 20; + + SELECT * FROM tbl_name + WHERE key_column IN (10,20,30); + + SELECT * FROM tbl_name + WHERE key_part1 = 10 AND key_part2 IN (10,20,30); + ``` +- `ALL` + - 전체 행 스캔, 테이블에 존재하는 모든 데이터 접근 + - 대부분의 경우, 이 타입은 좋지 않음 + - 그래서 보통 인덱스를 추가하여, 해당 타입의 사용을 피함 +- `index` + - 인덱스 풀 스캔 + - 인덱스를 처음 부터 끝까지 검색하는 경우 + - 이 타입도 좋지 않음. + +- 참고 + - https://dev.mysql.com/doc/refman/5.7/en/explain-output.html#explain-join-types + +### possible_keys +- 사용 가능성이 있는 인덱스 목록을 말함. + +### key +- `possible_keys` 항목 중에, 실제 옵티마이저가 사용하겠다고 선택한 인덱스를 의미. +- 만약 컬럼이 `null` 이면, 인덱스를 사용할 수 없다는 의미인듯. + +### key_len +- `key` 필드 인덱스의 길이를 의미. +- 너무 길면 비효율적이다. + +### rows +- 이 전 컬럼들의 접근방식들을 이용하여, 데이터베이스에서 몇개의 row를 가지고 왔는지 의미하는 컬럼 +- 실제 행 수와는 반드시 일치하지는 않는다. + +### filtered +- `rows` 컬럼의 값이, WHERE 조건을 거쳤을 경우, 몇행이나 **남아있는지** 알려주는 컬럼. +- 실제 행 수와는 반드시 일치하지는 않는다. + +### extra +- 옵티마이저가 어떻게 동작할 지 알려주는 힌트. +- 이 컬럼이 `Using filesort` 나 `Using Temporary` 라는 값이면 해당 쿼리 실행에 성능적인 문제가 있을 수도 있음을 암시한다. + +- `Using filesort` + - `ORDERB BY` 조건에 있는 index를 사용할 수 없을 때, + - 해당 데이터의 정렬을 위해서, MySQL이 추가적인 작업이 필요함을 의미함. + - 모든 row를 읽고, sort key를 저장한다음에, 정렬하는 작업이 발생함. + - `sort_buffer_size` 만큼의 메모리 할당등이 필요하므로.. 엄청나게 많은 rows가 filesort 과정을 거친다면 데이터베이스에 부담이 될 수 있을듯. + - 참고 + - https://dev.mysql.com/doc/refman/5.7/en/order-by-optimization.html + +- `Using temporary` + - 이 쿼리를 위해, 임시적인 테이블 생성이 필요함을 의미. + - 보통 이 힌트는, 해당 쿼리의 `GROUP BY` 와 `ORDER BY`가 포함되어 있고, 다른 컬럼을 가르킬 경우 발생함. + +- `Using where` + - where 조건을 이용하여, `rows` 행을 `filterd` 하였음을 의미. + - `type` 이 `ALL` 혹은 `index` 타입이라면, 해당 쿼리에 뭔가 문제가 있다는 의미 + +- `Using index` + - 인덱스만을 가지고, 데이터를 추출했음을 의미함. + - `InnoDB` 의 경우, user-defined clustered index 를 가지고 있으면 그 인덱스가 `Extra` 에 나타나있지 않더라도, 사용되어질 수 있음. + - 단 그 type 은 `index` 이고, `key` 가 Primary일 경우 + + +# MySQL의 index 사용 +- 참고 + - https://stackoverflow.com/questions/586381/mysql-not-using-indexes-with-where-in-clause + + +# 참고 +- https://www.exoscale.com/syslog/explaining-mysql-queries/#:~:text=In%20MySQL%2C%20EXPLAIN%20can%20be,as%20a%20service'%20OR%20foo. +- https://cheese10yun.github.io/mysql-explian/ +- https://www.eversql.com/mysql-explain-example-explaining-mysql-explain-using-stackoverflow-data/ +- https://nomadlee.com/mysql-explain-sql/ +- https://www.sitepoint.com/using-explain-to-write-better-mysql-queries/#:~:text=Extra%20%E2%80%93%20contains%20additional%20information%20regarding,may%20indicate%20a%20troublesome%20query. \ No newline at end of file From 132f0d291f9310db937a2fa477b583bc8f031c29 Mon Sep 17 00:00:00 2001 From: 102092 Date: Tue, 10 Aug 2021 20:06:38 +0900 Subject: [PATCH 096/142] Fix typo --- database/mysql-query-plan/han/README.md | 1 - database/type-of-keys/han/README.md | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/database/mysql-query-plan/han/README.md b/database/mysql-query-plan/han/README.md index 162ce56..e11a81d 100644 --- a/database/mysql-query-plan/han/README.md +++ b/database/mysql-query-plan/han/README.md @@ -1,6 +1,5 @@ # SELECT 쿼리 실행 순서 - 작성하는 쿼리문의 순서와, 실제 DB에서 실행되는 순서가 다름. -- - 보통 Select query 문법 순서 1. SELECT 2. FROM diff --git a/database/type-of-keys/han/README.md b/database/type-of-keys/han/README.md index 2f3f55a..b0ac811 100644 --- a/database/type-of-keys/han/README.md +++ b/database/type-of-keys/han/README.md @@ -63,7 +63,7 @@ - 대체키 - 릴레이션에 마땅한 후보키가 없을 경우, Database에서 식별을 위해 생성한, 선언된 키를 의미. - 관계형 모델이는 자연키, 대체키란 개념이 없음. - - 관계형 모델이는 후보키, 슈포키 뿐이다. + - 관계형 모델이는 후보키, 슈퍼키 뿐이다. - 참고 - https://bunhere.tistory.com/45 - https://www.toolbox.com/tech/data-management/question/the-difference-between-a-primary-key-and-a-surrogate-key-011407/ From 0f030048401e0adfddcf9d57e88ae5ccf8571e96 Mon Sep 17 00:00:00 2001 From: 102092 Date: Tue, 10 Aug 2021 20:18:12 +0900 Subject: [PATCH 097/142] Add qna --- database/mysql-query-plan/han/README.md | 17 +++++++++++++++-- database/type-of-keys/han/README.md | 5 +++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/database/mysql-query-plan/han/README.md b/database/mysql-query-plan/han/README.md index e11a81d..9e8d701 100644 --- a/database/mysql-query-plan/han/README.md +++ b/database/mysql-query-plan/han/README.md @@ -167,10 +167,23 @@ WHERE foo.bar = 'infrastructure as a service' OR foo.bar = 'iaas'; - 참고 - https://stackoverflow.com/questions/586381/mysql-not-using-indexes-with-where-in-clause - # 참고 - https://www.exoscale.com/syslog/explaining-mysql-queries/#:~:text=In%20MySQL%2C%20EXPLAIN%20can%20be,as%20a%20service'%20OR%20foo. - https://cheese10yun.github.io/mysql-explian/ - https://www.eversql.com/mysql-explain-example-explaining-mysql-explain-using-stackoverflow-data/ - https://nomadlee.com/mysql-explain-sql/ -- https://www.sitepoint.com/using-explain-to-write-better-mysql-queries/#:~:text=Extra%20%E2%80%93%20contains%20additional%20information%20regarding,may%20indicate%20a%20troublesome%20query. \ No newline at end of file +- https://www.sitepoint.com/using-explain-to-write-better-mysql-queries/#:~:text=Extra%20%E2%80%93%20contains%20additional%20information%20regarding,may%20indicate%20a%20troublesome%20query + + +# QnA + +## DB를 파티셔닝 이유는 무엇일까? +![image](https://user-images.githubusercontent.com/22140570/128856777-91593f01-d816-4142-9466-fef0c48991f5.png) + +## 클러스트 인덱스이란? +![image](https://user-images.githubusercontent.com/22140570/128857129-a45f3917-8f68-40d9-bb5a-e283032ae69d.png) + + +## SIMPLE, SUBUQUERY, UNION의 차이점은 무엇인가요? +![image](https://user-images.githubusercontent.com/22140570/128857270-50b49979-3ee4-4628-b535-7f7a38c0e809.png) + diff --git a/database/type-of-keys/han/README.md b/database/type-of-keys/han/README.md index b0ac811..96e44da 100644 --- a/database/type-of-keys/han/README.md +++ b/database/type-of-keys/han/README.md @@ -74,3 +74,8 @@ - 관계형 데이터 베이스 실전 입문 - 3장, 6장 + +# QnA + +## 데이터베이스 최소성, 유일성? +![image](https://user-images.githubusercontent.com/22140570/128857368-49e05cde-7ecf-4eb8-a623-715b5d175444.png) \ No newline at end of file From df189105106872cb24372c1615954553563b0d2f Mon Sep 17 00:00:00 2001 From: Han Date: Tue, 10 Aug 2021 20:52:31 +0900 Subject: [PATCH 098/142] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 2559a00..d4d3a93 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ # lets-cs ## 스터디 규칙 -- 일정 : 07.29 ~ 08.29 -- 주제 : **데이터베이스** +- 일정 : 08.10 ~ 09.10 +- 주제 : **네트워크** - 진행 방식 - 2주가 하나의 사이클 - 1주차에는 질문에 대한 정리 및 PR, 2주차에는 PR 리뷰 및 수정을 진행 From e9ac367f6033ee471fa98e83042a718e36e8048c Mon Sep 17 00:00:00 2001 From: Jin Hyung Park Date: Tue, 3 Aug 2021 23:33:23 +0900 Subject: [PATCH 099/142] feat: MySQL Query Plan --- database/mysql-query-plan/sigrid/README.md | 237 +++++++++++++++++++++ 1 file changed, 237 insertions(+) create mode 100644 database/mysql-query-plan/sigrid/README.md diff --git a/database/mysql-query-plan/sigrid/README.md b/database/mysql-query-plan/sigrid/README.md new file mode 100644 index 0000000..4438397 --- /dev/null +++ b/database/mysql-query-plan/sigrid/README.md @@ -0,0 +1,237 @@ +# MySQL Query Plan +## MySQL Optimizer +* MySQL은 사용자가 요청한 쿼리 문장을 잘게 쪼개서 MySQL 서버가 이해할 수 있는 수준으로 나눈다. +* 이를 파싱이라고 하는데, 파싱 트리를 확인하면서 어느 테이블과 인덱스부터 읽는 것이 효율적인지 계산한다. + * 그래서 Client는 SQL 문장을 Parser에 전달하고 (1단계), + * Parser는 파싱 작업을 거쳐 Optimizer에게 전달한다. (2단계) + * Optimizer는 Query Plan을 작성하여 Executor에게 전달하고, Executor는 스토리지 엔진에서 결과 Set을 가져온다. (3단계) +![](https://i.imgur.com/ry2IEwt.png) + +* 만약 SQL 문법이 잘못되었다면 누가 에러를 반환할까? + * 파서가 반환한다. 파서가 문장을 분석하고 잘게 쪼개기 때문이다. +* 옵티마이저는 쿼리 플랜을 작성하는 데 있어 다음과 같은 사항을 고려한다. + * 불필요한 조건의 제거 및 복잡한 연산의 단순화 + * 여러 테이블의 조인이 있는 경우 어떤 순서로 테이블을 읽을지 결정 + * 각 테이블에 사용된 조건과 인덱스 통계 정보를 이용해 사용할 인덱스 결정 + * 가져온 레코드들을 임시 테이블에 넣고 다시 한번 가공해야 하는지 결정 +* 옵티마이저의 종류에는 무엇이 있을까? + * 1. 비용 기반 최적화(Cost-based optimizer, CBO) + * 쿼리를 처리할 수 있는 여러 가지 방법을 만든다. + * 각 단위 작업의 비용 정보 및 테이블의 통계 정보를 이용해 계획 별 비용을 산출한다. + * 2. 규칙 기반 최적화 방법(Rule-based optimizer, RBO) + * 거의 쓰이지 않는다. +* 대체 무슨 통계 정보(?)를 보고 쓴다는 것일까? + * 대략의 레코드 건수와 인덱스의 유니크한 값의 개수를 주로 참고한다. + * MySQL은 통계정보를 동적으로 관리하는 편이다. + * 오라클과 같은 전통적인 RDBMS는 통계정보만 따로 백업한다. + * 명령 중 'ANALYZE' 를 이용하면 통계 정보를 강제로 갱신할 수 있다. + * 인덱스 키값의 분포도(선택도)만 업데이트하며, 전체 테이블의 건수는 테이블의 전체 페이지 수를 이용해 예측한다. + * 예를 들어, InnoDB 테이블은 인덱스 페이지 중에서 8개 정도만 랜덤하게 선택해서 분석하고 그 결과를 인덱스의 통계 정보로 갱신한다. + +### EXPLAIN 명령 +* MySQL에서는 'EXPLAIN' 키워드를 이용해 실행계획에 대한 정보를 살펴 볼 수 있다. +* 테이블 구조가 다음과 같이 있다고 말해보자. + * member는 회원 정보이고, orders는 주문 목록, transaction은 해당 주문의 거래 정보이다. + +![](https://i.imgur.com/V3UwUaW.png) +* EXPLAIN 결과는 다음과 같이 나올 것이다. 여기서는 JSON 형식으로 출력된 결과에 대해 알아보자. +``` +explain +select m.*, o.*, t.* from member m +inner join orders o on m.id = o.member_id +inner join transaction t on o.transaction_id = t.id +where m.id in (1, 2, 33) +``` + +``` +{ + "query_block": { + "select_id": 1, + "cost_info": { + "query_cost": "449.03" + }, + "nested_loop": [ + { + "table": { + "table_name": "m", + "access_type": "range", + "possible_keys": [ + "PRIMARY" + ], + "key": "PRIMARY", + "used_key_parts": [ + "id" + ], + "key_length": "8", + "rows_examined_per_scan": 3, + "rows_produced_per_join": 3, + "filtered": "100.00", + "cost_info": { + "read_cost": "3.61", + "eval_cost": "0.60", + "prefix_cost": "4.21", + "data_read_per_join": "6K" + }, + "used_columns": [ + "id", + "email", + "name" + ], + "attached_condition": "(`sample`.`m`.`id` in (1,2,33))" + } + }, + { + "table": { + "table_name": "o", + "access_type": "ref", + "possible_keys": [ + "FKpktxwhj3x9m4gth5ff6bkqgeb", + "FKrylnffj7sn97iepyqadlfnsg0" + ], + "key": "FKpktxwhj3x9m4gth5ff6bkqgeb", + "used_key_parts": [ + "member_id" + ], + "key_length": "8", + "ref": [ + "sample.m.id" + ], + "rows_examined_per_scan": 90, + "rows_produced_per_join": 272, + "filtered": "100.00", + "cost_info": { + "read_cost": "63.00", + "eval_cost": "54.55", + "prefix_cost": "121.76", + "data_read_per_join": "279K" + }, + "used_columns": [ + "id", + "order_number", + "member_id", + "transaction_id" + ] + } + }, + { + "table": { + "table_name": "t", + "access_type": "eq_ref", + "possible_keys": [ + "PRIMARY" + ], + "key": "PRIMARY", + "used_key_parts": [ + "id" + ], + "key_length": "8", + "ref": [ + "sample.o.transaction_id" + ], + "rows_examined_per_scan": 1, + "rows_produced_per_join": 272, + "filtered": "100.00", + "cost_info": { + "read_cost": "272.73", + "eval_cost": "54.55", + "prefix_cost": "449.03", + "data_read_per_join": "820K" + }, + "used_columns": [ + "id", + "code", + "partner_transaction_id", + "payment_method_type" + ] + } + } + ] + } +} +``` + +#### Table +* 어느 테이블에 대한 접근을 하고 있는가? +* 여기서 m은 members, o는 orders, t는 transactions이다. + +#### ID +* id는 select 명령에 대한 순차적인 실행번호이다. +* Join은 개별적인 하나의 연산 단위로 취급하므로 모두 id가 1이라고 한다. (잘 이해가 안감.) + * 대신 서브쿼리가 있거나 UNION 연산이 있으면 id 안에서 2, 3...으로 내려갈 것이다. + +#### SELECT_TYPE +* select 문의 유형을 말한다. 각 유형은 아래와 같다 + * SIMPLE : 서브쿼리나 'union'이 없는 가장 단순한 select문을 말한다 + * ```SELECT * FROM USER;``` + * PRIMARY : 가장 바깥에 있는 select 문을 말한다 + * ```SELECT (요기) * FROM (SELECT * FROM USER) t;``` + * DERIVED : from 문 안에있는 서브쿼리의 select 문이다. + * ```SELECT * FROM (SELECT (요기) * FROM USER) t;``` + * SUBQUERY : 가장 바깥의 select 문에 있는 서브쿼리이다. + * DEPENDENT SUBQUERY : 기본적으로 SUBQUERY와 같은 유형이며, 가장 바깥의 select문에 '의존성'을 가진 서브쿼리의 select문이다. + ``` + SELECT * FROM user u1 WHERE EXISTS ( + SELECT * FROM user u2 WHERE u1.user_id = u2.user_id (요기) + ); + ``` + * UNCACHEABLE SUBQUERY + * UNION : union 문의 두번째 select 문을 말한다 + * DEPENDENT UNION : 바깥 쿼리에 의존성을 가진 union문의 두번째 select문을 말한다 + +#### type +* MySQL이 어떤식으로 테이블들을 조인하는지를 나타내는 항목이다. +* Type을 분석함으로써 어떤 인덱스가 사용되고 사용되지 않았는지를 알 수 있고, 이를 통해 어떤식으로 쿼리가 튜닝되어야 하는 지 분석할 수 있다. [출처](https://dev.mysql.com/doc/refman/8.0/en/explain-output.html) [출처 2](https://gradle.tistory.com/4) + * const: 하나의 매치되는 행만 존재하는 경우. 하나의 행이기 때문에 상수로 간주되며, 한번만 읽어들이기 때문에 무척 빠르다. + * eq_ref: 조인수행을 위해 각 테이블에서 하나의 행만이 읽혀지는 형태. const 타입 외에 가장 훌륭한 조인타입이다. + * It is used when all parts of an index are used by the join and the index is a PRIMARY KEY or UNIQUE NOT NULL index. + * ref: ref 조인에서 키의 가장 왼쪽 접두사 만 사용하거나 키가 PRIMARY KEY또는 UNIQUE 인덱스 가 아닌 경우 (즉, 조인이 키 값을 기반으로 단일 행을 선택할 수없는 경우) 사용된다. 사용되는 키가 몇 개의 행과 만 일치하는 경우 이는 좋은 조인 유형이다. + * index: 이 타입은 인덱스가 스캔되는걸 제외하면 ALL과 같다. 보통 인덱스 파일이 데이터 파일보다 작기 때문에 ALL보다 빠르다. 인덱스 스캔, 테이블의 특정 인덱스의 전체 엔트리에 접근한다. + * ALL: 이전 테이블과의 조인을 위해 풀스캔이 된다. 만약 조인에 쓰인 첫 테이블이 고정이 아니라면 비효율적이다. 그리고 대부분의 경우 아주 느리며, 보통 상수값이나 상수인 컬럼값으로 row를 추출하도록 인덱스를 추가하여 ALL 타입을 피할 수 있다. + * ref_or_null: 이 조인 유형은 ref와 비슷하지만 MySQL이 NULL값 을 포함하는 행을 추가로 검색한다는 점이 다르다. 이 조인 유형 최적화는 하위 쿼리를 해결하는 데 가장 자주 사용된다. + +* ALL, index 두 가지는 테이블 또는 특정 인덱스가 전체 행에 접근하기 때문에 테이블 크기가 크면 효율이 떨어진다. ref_or_null의 경우 NULL이 들어있는 행은 인덱스의 맨 앞에 모아서 저장하지만 그 건수가 많으면 MySQL 서버의 작업량이 방대해진다. 다시 말해서 ALL 이외의 접근 방식은 모두 인덱스를 사용한다. [출처](https://cheese10yun.github.io/mysql-explian/#explain-2) + +* 접근 방식이 ALL 또는 index인 경우는 그 쿼리로 사용할 수 있는 적절한 인덱스가 없다는 의미일 수도 있다. 위 쿼리에서 Country 테이블에 대한 접근은 ALL이지만 이는 WHERE 구의 조건을 지정하지 않았기 때문이다. 그러한 쿼리에서 드라이빙 테이블에 접근한다면 전체 행을 스캔 할수 밖에 없다. [출처](https://cheese10yun.github.io/mysql-explian/#explain-2) + +* 결론 +성능상 문제가 되는 부분은 index, all이 두가지 타입이 문제라는 것이다. + +#### key +possible_keys 필드에서 실제로 옵티마이저가 선택한 인덱스가 key가 된다. 위 EXPLAIN 에서는 County 테이블(첫 번째 행)의 Key는 NULL 인데 이는 행 데이터를 가져오기 위해 인덱스를 사용할 수 없다는 의미이다. + +#### extra +* EXPLAIN을 사용해 옵티마이저의 행동을 파악할 때 아주 중요하다. +* 특히 FileSort와 Using Temporary의 경우에는 쿼리 튜닝이 필요한 상태라는 의미이다. + +[출처](https://m.blog.naver.com/PostView.naver?isHttpsRedirect=true&blogId=websearch&logNo=221566208749) +* Using where + * 접근 방식을 설명한 것으로, 테이블에서 행을 가져온 후 추가적으로 검색조건을 적용해 행의 범위를 축소한 것을 표시한다. + * 인덱스에 포함된 컬럼들이 사용된 WHERE 조건들은 대부분 스토리지 엔진에서 인덱스를 읽을 때 체크되기 때문에 WHERE 절을 가진 쿼리가 모두 실행 계획상에 Using where 를 표시하는 것은 아니다. + * 때로는 Using where 가 있다는 사실이 다른 인덱스를 사용하면 쿼리를 더 효율적으로 만들 수 있다는 의미가 되기도 한다. +* Using index + * 테이블에는 접근하지 않고 인덱스에서만 접근해서 쿼티를 해결하는 것을 의미한다. 커버링 인덱스로 처리됨 index only scan이라고도 부른다 +* Using index for group-by + * Using index와 유사하지만 GROUP BY가 포함되어 있는 쿼리를 커버링 인덱스로 해결할 수 있음을 나타낸다 +* Using filesort + * ORDER BY 인덱스로 해결하지 못하고, filesort(MySQL의 quick sort)로 행을 정렬한 것을 나타낸다. MySQL 이 결과의 순서를 맞추기 위해 인덱스 순서로 테이블을 읽는 것이 아니라 외부 정렬을 사용해야 한다는 것을 의미한다. +* Using temporary + * MySQL 이 쿼리 결과를 정렬하기 위해 임시 테이블을 사용한다는 것을 의미한다. +* Using where with pushed + * 엔진 컨디션 pushdown 최적화가 일어난 것을 표시한다. 현재는 NDB만 유효 +* Using index condition + * 인덱스 컨디션 pushdown(ICP) 최적화가 일어났음을 표시한다. ICP는 멀티 칼럼 인덱스에서 왼쪽부터 순서대로 칼럼을 지정하지 않는 경우에도 인덱스를 이용하는 실행 계획이다. +* Using MRR + * 멀티 레인지 리드(MRR) 최적화가 사용되었음을 표시한다. +* Using join buffer(Block Nested Loop) + * 조인에 적절한 인덱스가 없어 조인 버퍼를 이용했음을 표시한다. +* Using join buffer(Batched Key Access) + * Batched Key Access(BKAJ) 알고리즘을 위한 조인 버퍼를 사용했음을 표시한다. + +### 기타 JOIN을 최적화하는 포인트? +* MySQL은 Nested Loop JOIN으로 되어있기 때문에 기준 테이블에서 조회되는 데이터양에 따라 연관 테이블의 데이터양이 결정되기 때문에 기준 테이블(왼쪽)의 데이터양을 줄이는 것이 관건이다. +* Outer Join은 지양한다. 꼭 필요한 경우만 사용한다. +* join시 조합 경우의 수를 줄이기 위해 복합 컬럼 index를 사용하는 것을 고려한다. + +## 기타 참고 사이트 +* https://wedul.site/452 +* https://cheese10yun.github.io/mysql-explian/#null From d1fb92ca0e0444ffc2856ba940682d967d7cc51a Mon Sep 17 00:00:00 2001 From: Jin Hyung Park Date: Tue, 3 Aug 2021 23:34:29 +0900 Subject: [PATCH 100/142] =?UTF-8?q?feat:=20Type=20of=20Keys=20=ED=95=99?= =?UTF-8?q?=EC=8A=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- database/type-of-keys/sigrid/README.md | 174 +++++++++++++++++++++++++ 1 file changed, 174 insertions(+) create mode 100644 database/type-of-keys/sigrid/README.md diff --git a/database/type-of-keys/sigrid/README.md b/database/type-of-keys/sigrid/README.md new file mode 100644 index 0000000..2adb754 --- /dev/null +++ b/database/type-of-keys/sigrid/README.md @@ -0,0 +1,174 @@ +# 데이터베이스 논리적 모델: 키의 종류 +## 개론 +* 관계 데이터 모델 릴레이션의 특징 중 하나인 '튜플의 유일성' 은 키를 통하여 성취될 수 있다. +* 튜플의 유일성은 릴레이션에 똑같은 튜플이 존재하면 안되고, 모든 튜플에는 다른 튜플과 구별되는 유일한 특성이 있어야 된다는 것이었다. +* 이를 위하여 모든 속성을 이용하는 것보다 일부 속성만 이용하는 것이 효율성을 높일 수 있다. +* 이 때, 튜플들을 유일하게 구별해주는 역할은 속성 또는 속성들의 집합인 키가 한다. + +## Super Key +* 슈퍼키는 유일성의 특성을 만족하는 속성 또는 속성들의 집합이다. +* 유일성은 키가 갖추어야 하는 기본 특성으로, 하나의 릴레이션에서 키로 지정된 속성 값은 튜플마다 달라야 한다. + * 사용자의 이름 속성은 이름이 같은 사용자도 있을 수 있으므로 슈퍼키가 될 수 없다. + * 사용자 아이디는 모든 튜플을 구별할 수 있으므로 슈퍼키가 될 수 있다. + * 사용자 아이디 + 사용자 이름으로 구성된 속성 집합도 모든 튜플을 구별할 수 있다. 하지만, 불필요한 속성 값까지 확인하는 비효율적인 작업을 하게 된다. + +## Candidate Key +* 앞서 살펴보았듯이, 불필요한 속성 값까지 확인하는 비효율적인 작업을 하게되는 키가 존재한다. +* 그래서 꼭 필요한 속성의 집합만으로 튜플을 유일하게 구별할 수 있도록 하는 키가 후보키이다. 후보키는 유일성을 만족시키면서 동시에 최소성까지 만족하는 속성 또는 속성들의 집합이다. + * 최소성은 위에서 말한 것처럼 꼭 필요한 최소한의 속성들로만 키를 구성하여 튜플을 구별할 수 있게 하는 것을 말한다. +* 후보키가 되기 위해 만족해야 하는 유일성과 최소성의 특성은 새로운 튜플이 삽입되거나 기존 튜플의 속성 값이 바뀌어도 유지되어야 한다. + +## Primary Key +* 하나의 테이블에 존재하는 여러 후보키 중에서 기본적으로 사용할 키를 반드시 선택해야 하는데 이것을 기본키라고 한다. +* 기본키의 속성에는 다음을 고려하여야만 한다. + * 먼저, NULL 값을 가질 수 있는 속성이 포함된 후보키는 기본키로 부적합하다. 기본키가 NULL 값인 튜플은 다른 튜플들과 구별하여 접근하기 어려우므로 이런 가능성이 있는 키는 기본키로 선택하지 않는 것이 좋다. + * 값이 자주 변경될 수 있는 속성이 포함된 후보키는 기본키로 부적합하다. 기본키는 다른 튜플과 구별되는 값을 가지고 NULL 값은 허용하지 않으므로 이를 확인하는 작업이 필요한데, 만약 값이 자주 바뀐다면 기본키 값으로 적합한지를 지속해서 판단해야 하기 때문에 기본키로 부적합하다. + * 단순한 후보키를 기본키로 선택한다. + +## Alternate Key +* 대체키는 기본키로 선택되지 못한 후보키들이다. +* 대체키는 기본키를 대신할 수 있다. + +## Foreign Key +* 외래키는 어떤 릴레이션에 소속된 속성 또는 속성 집합이 다른 릴레이션의 기본키가 되는 키다. 즉, 다른 릴레이션의 기본키를 그대로 참조하는 속성의 집합이다. +* 외래키가 되는 속성과 기본키가 되는 속성의 이름은 달라도 된다. 하지만 외래키 속성의 도메인과 참조되는 기본키 속성의 도메인은 반드시 같아야 한다. + +![](https://i.imgur.com/HayFbDq.png) +[출처: 데이터베이스 개론 2판, 한빛아카데미](https://sangwoo0727.github.io/database/Database-4_key/) + +* 하나의 릴레이션에는 외래키가 여러 개 존재할 수도 있고, 외래키를 기본키로 사용할 수도 있고 외래키를 포함하여 기본키를 구성할 수도 있다. +* 추가로, 외래키는 반드시 다른 릴레이션을 참조할 필요는 없다. 참조하는 릴레이션과 참조되는 릴레이션이 같을 수도 있다. +* 외래키는 기본적으로는 기본키가 아니기 때문에 널 값을 가질 수도 있고 서로 다른 튜플이 같은 값을 가질 수도 있다. [스택 오버플로우 토론](https://stackoverflow.com/questions/7573590/can-a-foreign-key-be-null-and-or-duplicate) + +![](https://i.imgur.com/CTrl4om.png) + + +## Composite Key +* 두 개 이상의 컬럼이 합쳐져서 하나의 튜플을 구별할 수 있는 후보키가 될 수 있다고 할 때 우리는 이것을 복합키라고 부른다. +* 이전 스터디에서 (학번, 이름) 형태로 튜플로 묶어야 릴레이션에서 여러 칼럼을 독립적으로 구별할 수 있던 형태가 바로 복합키이다. +* 아래와 같이 주문 릴레이션에서 단일 속성으로는 튜플을 유일하게 식별하는 것이 불가능하므로 2개의 속성을 합한(고객번호, 도서번호)가 후보키가 되며 이렇게 2개 이상의 속성으로 이루어진 키를 복합키(Composite Key)이다. [출처](https://mangkyu.tistory.com/21) + +![](https://i.imgur.com/xKh7X8n.png) + +* 복합키의 속성들 중에서 먼저 정의한 속성에 대해서 클러스터드 인덱스[참고](https://gocoder.tistory.com/1826)가 정의되어지며, 주로 조회가 빈번하게 일어나는 속성을 먼저 정의하는 것이 좋다고 한다. +* JPA에서는 ```@IdClasss```, ```@EmbeddedID```를 이용하여 복합키를 매핑할 수 있다. [출처](https://techblog.woowahan.com/2595/) + +```java +// PayShop.java + +@Getter +@Entity +@NoArgsConstructor +public class PayShop { + + @EmbeddedId + private PayShopId id; + + private String shopName; + + @MapsId(value = "payId") + @ManyToOne(fetch = FetchType.LAZY) + private Pay pay; + + public PayShop(PayShopId id, + String shopName) { + this.id = id; + this.shopName = shopName; + } + + public void setPay(Pay pay) { + if (pay != null) { + pay.getPayShops().remove(this); + } + this.pay = pay; + this.pay.getPayShops().add(this); + } +} +// @MapsId 를 통해서 Pay에 있는 id 값을 자동으로 할동되게 할 수 있음. +``` +```java +//PayShopId.java +@Getter +@EqualsAndHashCode(onlyExplicitlyIncluded = true) +@Embeddable +@NoArgsConstructor +public class PayShopId implements Serializable { + + /** + * 테이블에서 정의하는 컬럼 사이즈 + */ + public static final int SHOP_NUMBER_SIZE = 12; + + @EqualsAndHashCode.Include + private PayDetailId payDetailId; + + @EqualsAndHashCode.Include + @Column + private String shopNumber; + + public PayShopId(PayDetailId payDetailId, + String shopNumber) { + Preconditions.checkArgument(shopNumber.length() <= SHOP_NUMBER_SIZE); + + this.payDetailId = payDetailId; + this.shopNumber = shopNumber; + } +} +// 위 예제와 같이 shopNubmer 라는 값의 컬럼사이즈를 초과해서 입력받아지지 않도록 체크를 할 수 있다. +``` + +## Surrogate Key vs Natural Key +### Surrogate Key 대체 키 +* 테이블을 이루는 컬럼들 가운데 유일하게 식별하기에 적합한 단일 후보키가 존재하지 않을 때, 임의의 식별번호로 이루어진 후보키를 추가할 수 있는데 이를 대체키라고 하다. [출처](https://ssayebee.github.io/wiki/surrogate_vs_natural_key.html) + * Surrogate key의 가장 큰 단점은 DB query가 복잡해진다는 점을 들수 있다. Business적으로 의미가 없는 key를 사용하기 때문에 간단한 query라도 join이 들어가게 되어서 복잡해지게 된다. +* 예를 들면 다음과 같다. [출처](https://rampart81.github.io/post/surrogate_key_vs_natural_key/) +``` +CREATE TABLE stock ( + id INT NOT NULL AUTO_INCREMENT, + ticker VARCHAR(20) NOT NULL, + price DECIMAL(35, 4), + PRIMARY KEY (ID) +); +``` +* id가 바로 surrogate key의 전형적인 예 이다. 여기서 id는 단순한 정수 값으로서 주식과는 아무 관련이 없는 정보지만 stock 테이블의 각 row를 대표하기 위한 id로 쓰인다. + +### Natural Key +* 테이블을 이루는 컬럼들 가운데 의미를 담고 있는 후보키 + * 아무리 고정 값의 필드를 자연키로 사용한다고 해도 대부분의 자연키는 언젠가 변할 수 있다. + * 또한, 만약 자연키가 문자열 이라면, 숫자 보다 비교를 하는데에 시간이 더 걸린다. +* 예를 들면 다음과 같다. +``` +CREATE TABLE stock ( + ticker VARCHAR(20) NOT NULL, + price DECIMAL(35, 4), + PRIMARY KEY (ticker) +); +``` +* id 필드를 없애고 대신에 ticker 필드를 primary key로 지정하였다. Surrogate key가 아니라 natural key를 primary key로 사용한 것이다. + * 위에서 설명한 첫 번째 단점이 여기서 부각된다. + * 주식 ticker도 값이 변할 수 있다. 예를 들어 LUCID 전기차 회사는 CCIV에서 LCID로 티커를 변경했다. + * 만일 ticker 값이 변하게 되면 그에 따른 관리를 해주는것이 굉장히 복잡하고 어려워질수 있다. + * 예를 들어, stock_info 와 portfolio 라는 table들이 stock table의 ticker 필드에 foreign key가 걸려 있다고 가정해보자. + * ticker 필드 값이 변하지 않으면 아무 문제 없지만 만일 ticker 값이 변해버리면 해당 ticker에 foreign key가 걸려있는 다른 table들의 row들도 전부 동시에 변경 해주어야 한다. + * 큰 규모의 실제 시스템에서는 DB 구조가 이보다 훨씬 복잡한 경우가 많으므로 모든 foreign key를 업데이트 시키는 일은 굉장히 어려워질수 있다. + * 이와 반면에 surrogate key는 변경되지 않는다. 처음부터 busienss 적인 의미가 없기 때문에 예상치 못하게 변경될 이유가 없는 것이다. + +### M:M 관계의 테이블이 있을 때, 대체 키를 이용할 것인가? 자연 키를 이용할 것인가? +* JPA 환경에서 대부분의 테이블을 별 생각없이 ```@GeneratedValue(strategy = GenerationType.IDENTITY)``` 해당 어노테이션을 사용해서 대체키를 이용해서 테이블을 만들었던 기억이 다들 있을 것이다. 꼭 그래야 하는가? +* Single Surrogate + * 모든 자식 테이블은 기본 키를 참조하기 위해서 단일 열만 필요로 한다. + * 외래 키로 모든 자식 테이블을 업데이트 할 필요 없이 테이블의 자연 키를 쉽게 업데이트 할 수 있다. + * 자연키 보다 더 많은 인덱스를 생성한다. +* Natural Composite key + * 인덱스를 덜 생성한다. + * 불필요한 열이 없어진다. + * 시퀀스 생성기가 필요 없기 떄문에 레코드 삽입이 빠르다. + * 복합키 중 하나를 업데이트 하면 모든 하위 테이블도 업데이트 해야한다. +* 요약 + * 복합키 VS 자연키 사용에 대한 질문은 데이터베이스 설계에 있어서 자주 다뤄지는 고전적인 주제라고 한다. + * 상황에 따라 어떤 것을 사용하는게 나을지 고민이 필요하다. + * Stack Overflow 에서는 대체키 사용을 추천했다. + +## 기타 참고 사이트 +* https://rampart81.github.io/post/surrogate_key_vs_natural_key/ +* https://ssayebee.github.io/wiki/surrogate_vs_natural_key.html From ccdd36a307c1a6376865c81417b9335be9bdef34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=B5=9C=ED=95=9C=EC=9A=B8?= Date: Tue, 3 Aug 2021 19:09:34 +0900 Subject: [PATCH 101/142] =?UTF-8?q?[8=EC=A3=BC=EC=B0=A8]=20=EB=8D=B0?= =?UTF-8?q?=EC=9D=B4=ED=84=B0=EB=B2=A0=EC=9D=B4=EC=8A=A4=20=ED=82=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- database/type-of-keys/hamill/README.md | 57 ++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 database/type-of-keys/hamill/README.md diff --git a/database/type-of-keys/hamill/README.md b/database/type-of-keys/hamill/README.md new file mode 100644 index 0000000..29887cd --- /dev/null +++ b/database/type-of-keys/hamill/README.md @@ -0,0 +1,57 @@ +# 데이터베이스에서 사용되는 키의 개념과 종류 + +### 키(Key)란? + +키는 데이터베이스에서 조건에 만족하는 튜플을 찾거나 순서대로 정렬할 때 튜플들을 서로 구분 할 수 있는 기준이 되는 속성(attribute)를 말한다. + +### 키의 종류 + +#### 후보키(Candidate Key) + +1. 후보 키는 릴레이션을 구성하는 속성들 중에서 튜플을 유일하게 식별하기 위해 사용하는 속성들의 부분집합, 즉, 기본키로 사용 할 수 있는 속성들을 말한다. +2. 하나의 릴레이션 내에서는 중복된 튜플들이 있을 수 없으므로 모든 릴레이션에는 반드시 하나 이상의 후보키가 존재한다. +3. 후보키는 릴레이션에 있는 모든 튜플에 대해서 유일성과 최소성을 만족시켜야 한다. + +```jsx +유일성: 하나의 키값으로 하나의 튜플만을 유일하게 식별 할 수 있어야한다. +최소성: 모든 레코드들을 유일하게 식별하는데 꼭 필요한 속성만으로 구성되어 있어야한다. + +릴레이션: 테이블 +속성: 릴레이션 최상단에 위치한 이름, 전화번호, 학과 등과 같은 것 +튜플 또는 레코드: 릴레이션의 각 행 +``` + +#### 기본키(Primary Key) + +1. 기본키는 후보키 중에서 선택한 메인 키이다. +2. 하나의 릴레이션에서 특정 튜플을 유일하게 구별 할 수 있는 속성이다. +3. Null 값을 가질 수 없다. +4. 기본키로 정의된 속성에는 동일한 값이 중복되어 저장 될 수 없다. + +#### 대체키(Alternate Key) + +1. 후보키가 둘 이상일 때 기본키를 제외한 나머지 후보키들을 말한다. +2. 보조키라고도 한다. + +#### 슈퍼키(Super Key) + +1. 슈퍼키는 하나의 릴레이션 내에 있는 속성들의 집합으로 구성된 키 +2. 슈퍼키는 릴레이션을 구성하는 모든 튜플에 대해 유일성을 만족시키지만, 최소성은 만족시키지 못한다. + +```text +최소성: 쉽게 설명하면 키를 구성하는 속성들이 진짜 각 튜플을 구분하는데 꼭 필요한 속성들로만 +구성되어 있냐?를 의미합니다. 굳이 없어도 될 속성들을 넣지 말자는 말입니다. 예를 들어 다음과 +같은 키(주민번호, 이름, 나이)가 있다면, 물론 현재의 키는 각 튜플을 구분할 수 있습니다. +주민번호, 이름, 나이가 모두 같은 사람을 없을 테니깐요. 근데 생각해보면 이름, 나이를 빼고도 +주민번호만으로 각 튜플을 유일하게 식별할 수 있습니다. 이때 이름, 나이를 빼면 해당 키는 최소성을 만족합니다. +``` + +#### 외래키(Foregin Key) + +1. 관계를 맺고 있는 릴레이션 R1, R2에서 릴레이션 R1이 참조하고 있는 릴레이션 R2의 기본키와 같은 R1 릴레이션의 속성을 외래키라고 한다. +2. 외래키는 참조되는 릴레이션의 기본키와 대응되어 릴레이션 간에 참조관계를 표현하는데 중요한 도구이다. + + +#### 출처 +- [https://coding-factory.tistory.com/220](https://coding-factory.tistory.com/220) +- [https://kosaf04pyh.tistory.com/201](https://kosaf04pyh.tistory.com/201) \ No newline at end of file From 0669a5f89d536219b59fd4ab9ac1c703266791fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=B5=9C=ED=95=9C=EC=9A=B8?= Date: Tue, 3 Aug 2021 20:14:34 +0900 Subject: [PATCH 102/142] =?UTF-8?q?[8=EC=A3=BC=EC=B0=A8]=20mysql=20?= =?UTF-8?q?=EC=BF=BC=EB=A6=AC=20=ED=94=8C=EB=9E=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- database/mysql-query-plan/README.md | 96 +++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 database/mysql-query-plan/README.md diff --git a/database/mysql-query-plan/README.md b/database/mysql-query-plan/README.md new file mode 100644 index 0000000..6baa63a --- /dev/null +++ b/database/mysql-query-plan/README.md @@ -0,0 +1,96 @@ +### 쿼리 플랜이란? + +SQL을 처리하는 최저비용의 경로를 생성해주는 DBMS 내부 핵심엔진인 쿼리 옵티마이저가 쿼리를 수행할 때 생성한 최적의 처리 경로를 쿼리 플랜이라고 합니다. + +MySQL에서는 실행 할 쿼리문 앞에 explain 키워드를 이용해 쿼리플랜에 대한 정보를 살펴 볼 수 있습니다. 쿼리 플랜을 사용하면 이슈가 발생하는 쿼리에 대한 이해를 도울 뿐만 아니라, 어떻게 최적화 시킬지에 대한 인사이트를 제공합니다. + +### 사용 방법 + +```sql +EXPLAIN [EXTENDED] SELECT ... FROM ... WHERE ... +``` + +[https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdbbqa9%2FbtqD8PMH5VI%2FzlEXJRccyWVzs9eFeLK9A1%2Fimg.png](https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdbbqa9%2FbtqD8PMH5VI%2FzlEXJRccyWVzs9eFeLK9A1%2Fimg.png) + +### 항목 설명 + +- id: select 아이디로 SELECT를 구분하는 번호 +- select_type: select에 대한 타입 +- table: 참조하는 테이블 +- type: 조인 혹은 조회 타입 +- possible_keys: 데이터를 조회 할 때 DB에서 사용 할 수 있는 인덱스 리스트 +- key: 실제로 사용 할 인덱스 +- key_len: 실제로 사용 할 인덱스의 길이 +- ref: Key 안의 인덱스와 비교하는 컬럼(상수) +- rows: 쿼리 실행 시 조사하는 행 수립 + +### id + +행이 어떤 SELECT 구문을 나타내는 지를 알려주는 것으로 구문에 서브 쿼리나 UNION이 없다면 SELECT는 하나밖에 없기 때문에 모든 행에 대해 1이란 값이 부여되지만 이외의 경우에는 원 구문에서 순서에 따라 각 SELECT 구문들에 순차적으로 번호가 부여된다. + +### select_type + +select 문의 타입 + +- SIMPLE: 단순 select (union이나 서브쿼리가 없는 SELECT문) +- PRIMARY: 서브쿼리를 사용 할 경우 서브쿼리의 외부에 있는 쿼리(첫 번째 쿼리) UNION을 사용 할 경우 UNION의 첫 번째 SELECT 쿼리 +- UNION: UNION 쿼리에서 Primary를 제외한 나머지 SELECT +- DEPENDENT UNION: UNION과 동일하나, 외부쿼리에 의존적임(값을 공급받음) +- UNION RESULT: UNION 쿼리의 결과물 +- SUBQUERY: 서브 쿼리 또는 서브 쿼리를 구성하는 여러 쿼리 중 첫 번째 SELECT문 +- DEPENDENT SUBQUERY: 서브쿼리와 동일하나, 외부 쿼리에 의존적임(값을 공급 받음) +- DERIVED: SELECT로 추출된 테이블(FROM 절에서의 서브쿼리 또는 Inline View) +- UNCACHEABLE SUBQUERY: 서브쿼리와 동일하지만 공급되는 모든 값에 대해 서브 쿼리를 재처리. 외부 쿼리에서 공급되는 값이 동일하더라도 캐쉬된 결과를 사용 할 수 있음 +- UNCACHEABLE UNION: UNION과 동일하지만 공급되는 모든 값에 대하여 UNION 쿼리를 재처리 + +### table + +행이 어떤 테이블에 접근하는지를 보여주는 것으로 대부분의 경우 테이블 이름이나 SQL에서 지정된 별명 같은 값을 나타낸다. + +### type + +- system: 테이블에 단 한 개의 데이터만 있는 경우 +- const: SELECT에서 Primary Key 혹은 Unique Key를 상수로 조회하는 경우로 많아야 한 건의 데이터만 있음 +- eq_ref: 조인 할 때 Primary Key +- ref: 조인 할 때 Primary Key 혹은 Unique Key가 아닌 Key로 매칭하는 경우 +- ref_or_null: ref와 같지만 null이 추가되어 검색되는 경우 +- index_merge: 두 개의 인덱스가 병합되어 검색이 이루어지는 경우 +- unique_subquery: 다음과 같이 IN 절 안에 서브쿼리에서 Primary Key가 오는 특수한 경우 + - SELECT * FROM tab01 WHERE col01 IN (SELECT Primary Key FROM table01); +- index_subquery: unique_subquery와 비슷하나 Primary Key가 아닌 인덱스인 경우 + - SELECT * FROM tab01 WHERE col01 IN (SELECT key01 FROM tab02); +- range: 특정 범위 내에서 인덱스를 사용하여 원하는 데이터를 추출하는 경우로, 데이터가 방대하지 않다면 단순 SELECT 문에서는 나쁘지 않음 +- index: 인덱스를 처음부터 끝까지 찾아서 검색하는 경우로, 일반적으로 인덱스 풀스캔이라고 함 +- all: 테이블을 처음부터 끝까지 검색하는 경우 일반적으로 테이블 풀스캔이라고 함 + +### possible_keys + +쿼리에서 접근하는 컬럼들과 사용된 비교 연산자들을 바탕으로 어떤 인덱스를 사용 할 수 있는지를 표시해준다. + +### key + +테이블에 접근하는 방법을 최적화하기 위해 어떤 인덱스를 사용하기로 결정했는지를 나타낸다. + +### key_len + +MySQL이 인덱스에 얼마나 많은 바이트를 사용하고 있는지를 보여준다. MySQL에서 인덱스에 있는 컬럼들 중 일부만 사용한다면 이 값을 통해 어떤 컬럼이 사용되는지를 계산 할 수 있다. + +### ref + +키 컬럼에 나와있는 인덱스에서 값을 찾기위해 선행 테이블의 어떤 컬럼이 사용되었는지를 나타낸다. + +### rows + +원하는 행을 찾기 위해 얼마나 많은 행을 읽어야 할지에 대한 예측값을 의미한ㄸ. + +### extra + +- using index: 커버링 인덱스라고 하며 인덱스 자료 구조를 이용해서 데이터를 추출 +- using where: where 조건으로 데이터를 추출. type이 ALL 혹은 index 타입과 함께 표현되면 성능이 좋지 않다는 의미 +- using filesort: 데이터 정렬이 필요한 경우로 메모리 혹은 디스크 상에서의 정렬을 모두 포함. 결과 데이터가 많은 경우 성능에 직접적인 영향을 줌 +- using temporary: 쿼리 처리 시 내부적으로 tempory table이 사용되는 경우를 의미함 + +### 출처 + +- [https://nomadlee.com/mysql-explain-sql/](https://nomadlee.com/mysql-explain-sql/) +- [https://ibks-platform.tistory.com/374](https://ibks-platform.tistory.com/374) \ No newline at end of file From af7533764cb0d3432be10b1a6306f254894fccc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=B5=9C=ED=95=9C=EC=9A=B8?= Date: Mon, 9 Aug 2021 23:51:41 +0900 Subject: [PATCH 103/142] =?UTF-8?q?=EC=98=A4=ED=83=80=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- database/mysql-query-plan/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/database/mysql-query-plan/README.md b/database/mysql-query-plan/README.md index 6baa63a..b086727 100644 --- a/database/mysql-query-plan/README.md +++ b/database/mysql-query-plan/README.md @@ -81,7 +81,7 @@ MySQL이 인덱스에 얼마나 많은 바이트를 사용하고 있는지를 ### rows -원하는 행을 찾기 위해 얼마나 많은 행을 읽어야 할지에 대한 예측값을 의미한ㄸ. +원하는 행을 찾기 위해 얼마나 많은 행을 읽어야 할지에 대한 예측값을 의미한다. ### extra From 082cb6ff4aea40f044413ec383f045d3416a6545 Mon Sep 17 00:00:00 2001 From: 102092 Date: Mon, 16 Aug 2021 17:05:19 +0900 Subject: [PATCH 104/142] Fix repo --- database/mysql-query-plan/{ => hamil}/README.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename database/mysql-query-plan/{ => hamil}/README.md (100%) diff --git a/database/mysql-query-plan/README.md b/database/mysql-query-plan/hamil/README.md similarity index 100% rename from database/mysql-query-plan/README.md rename to database/mysql-query-plan/hamil/README.md From 368af7238e9ac8fa92d0b07ba70160883e7cf2a2 Mon Sep 17 00:00:00 2001 From: 102092 Date: Mon, 16 Aug 2021 02:43:23 +0900 Subject: [PATCH 105/142] Add blocking, non-blocking --- network/blocking-vs-nonblocking/han/README.md | 146 ++++++++++++++++++ 1 file changed, 146 insertions(+) create mode 100644 network/blocking-vs-nonblocking/han/README.md diff --git a/network/blocking-vs-nonblocking/han/README.md b/network/blocking-vs-nonblocking/han/README.md new file mode 100644 index 0000000..de45a46 --- /dev/null +++ b/network/blocking-vs-nonblocking/han/README.md @@ -0,0 +1,146 @@ +# blocking, non-blocking + +- 막는다, 안 막는다. --> 무엇을? + - 제어할 수 없는 대상을.. +- 동기, 비동기화 차이가 확실히 있을듯 한데, 개념상 헷갈리는 측면이 있는듯. +- 네트워크 보다는 운영체제..에 가까운 주제이지 않을까 + + + +## blocking + +- **블로킹** +- 직접 제어할 수 없는 대상을 처리하는 방법에 대한 내용 + - 즉 직접 제어할 수 없는 대상의 작업이 끝날 때 까지 기다린다 (return 값을 받을 때 까지) +- 주로 I/O, 멀티쓰레드 동기화 작업에서 많이 사용되는 개념. + + + +## non-blocking + +- **논블로킹** +- blocking과 반대되는 개념. +- 직접 제어할 수 없는 대상의 작업 상태와는 상관 없이, 자신의 작업을 게속 진행할 수 있음. +- 예를 들면 **I/O** 작업 완료 여부와 상관 없이, 다음 코드로 넘아갈 수 있다. + + + +# synchronous, asynchronous + +- 동기, 비동기 +- 시간을 함께 맞춘다, 시간을 함께 맞추지 않는다. +- 어떤 대상 간의 **시간**을 맞추거나, 맞추지 않는 것이 핵심인듯. + + + +## synchronous + +- 두 가지 이상의 대상(함수, 스레드등) 이 서로 시간을 맞추어 동작하면 동기라고 보는듯. + +![](https://media.vlpt.us/post-images/codemcd/7e027a20-4a1d-11ea-99c6-dd89d1c118fe/SpringCamp-AsyncSpring-2.png) + +- A가 완료되는 시점에, B가 시작하는 **시간** 이다. +- 끝나는 시간과 , 시작하는 시간이 같다 + + + +## asynchronous + +- A가 완료되는 시점에, B가 실행되지 않음. +- 즉 A는 B가 언제 완료되는지 신경쓰지 않는 것을 의미. + + + +# 차이점에 대해 + +- blocking vs synchronous + + - blocking의 경우, 대상(스레드, 애플리케이션) 의 상태를 나타내는 말인듯, 블로킹, 멈춰있음. 되어있다.,,, + - 현재 내 상태 + - synchronous의 경우, 시간이 연결되는 느낌. + - 즉 A,B synchronous하다 라는 의미는, A에서 B를 콜한다고 할 때, B가 끝나는 시간(return)에, A의 시간이 다시 흐르는 경우를 의미하는듯. + - 둘이, 완전히 다른 의미는 아닌듯 보여진다. 어디에 초점을 두고 있는 지에 따라 다르지 않을까 + +- non-blocking vs asynchronous + + - non-blocking의 경우, 대상의 상태가 멈춰 있지 않음. 결과를 기다리지 않고 제어권이 바로 반환되며, 다음 동작을 지속한다. + + - polling? + + - > 애플리케이션은 디바이스 드라이버에게 “A, B, C 사건이 일어날 때 알려줘. 그 때까지 좀 잘게” 라고 말하는 것이 `poll()` 이고... + + - 결과값을 알기 위해서 시스템 레벨에서 사용하는 방법인듯. + + - asynchronous의 경우, 시간이 연결되어 있지 않음. + + - A,B가 asynchronous하다는 의미는, A -> B를 콜하였을 경우, B가 리턴하는 시간과(A가 동작을 시작하는 시간), B에서 결과값을 가져오는 시간이 일치하지 않는다. + - 즉 B에서 결과값을 가져오지 않더라도, A의 시간은 흐른다. + + + + + +# 예시 + +## synchronous + blocking + +```javascript +device = IO.open() +data = device.read() +print(data) +``` + +![](https://media.vlpt.us/post-images/codemcd/8c51a790-4a1d-11ea-a77e-bff20a601eb8/synchronous-blocking-IO.png) + + + +- kernel에서 read response하는 시간과, application에서 read() 마무리 하는 시간이 맞물린다 (동기) +- application thread는 read()를 실행한 순간, kernel 에서 하는 작업이 마무리 될 때 까지 가디렸다 (블로킹) + + + +## sychronous + non-blocking + +```javascript +device = IO.open() +ready = False +while not ready: + print("There is no data to read!") + ready = IO.poll(device, IO.INPUT, 5) +data = device.read() +print(data) +``` + + + +![](https://media.vlpt.us/post-images/codemcd/982dd930-4a1d-11ea-a77e-bff20a601eb8/Synchronous-non-blocking-IO.png) + +- while 문은 IO.poll() 작업 결과 여부와 상관 없이 계속 돈다 (non-blocking) + - 반면 asychronous의 경우, poll하는 작업이 없다 (즉 Kernel에서 작업이 끝나면 application에 알려준다) +- read() 메서드가 실행되는 시간과, Kernel 의 작업이 완료되는 시간은 동일하다. (synchronous) + + + +## asynchronous + non-blocking + +![](https://media.vlpt.us/post-images/codemcd/9dd91ca0-4a1d-11ea-a77e-bff20a601eb8/Asynchronous-non-blocking-IO.png) + +- read () 하는 순간, Kernel로 콜이 감. read I/O 에 대한 결과값 상관 없이, 제어권이 리턴됨 (non-blocking) +- Kernel에서 실행되고 있는 작업이 끝나는 순간, 해당 결과값이 전달된다. + - 이 시간은 현재 application의 흐르고 있는 시간과 일치하지 않는다 (asynchronous) + + + +## asynchronous + blocking + +![](https://media.vlpt.us/images/wonhee010/post/bc20459f-02fe-431a-a1d0-8d5016a964f9/zKF0CgK.png) + +- Node + MySQL + + + +# 참고 + +- https://stackoverflow.com/questions/2625493/asynchronous-and-non-blocking-calls-also-between-blocking-and-synchronous +- https://velog.io/@codemcd/Sync-VS-Async-Blocking-VS-Non-Blocking-sak6d01fhx +- https://velog.io/@wonhee010/%EB%8F%99%EA%B8%B0vs%EB%B9%84%EB%8F%99%EA%B8%B0-feat.-blocking-vs-non-blocking \ No newline at end of file From c608620e387071da8cd8330621869f283b33108a Mon Sep 17 00:00:00 2001 From: 102092 Date: Mon, 16 Aug 2021 13:29:19 +0900 Subject: [PATCH 106/142] Add cors --- network/cors/han/README.md | 242 +++++++++++++++++++++++++++++++++++++ 1 file changed, 242 insertions(+) create mode 100644 network/cors/han/README.md diff --git a/network/cors/han/README.md b/network/cors/han/README.md new file mode 100644 index 0000000..4aff782 --- /dev/null +++ b/network/cors/han/README.md @@ -0,0 +1,242 @@ +# CORS란? + +- Cross-Origin Resource Sharing 정책을 의미함. +- 왜 사용할까? + - 가져오는 리소스의 최소한의 안전성을 보장하기 위해. + - 안정성은, 악의적인 목적을 가진 리소스는 아니다를 보장하기 위해. + + + +## Origin이란? + +![](https://evan-moon.github.io/static/e25190005d12938c253cc72ca06777b1/6af66/uri-structure.png) + +- `origin` 이 같다는 건, `Protocol` + `Host` + `Port` 가 같음을 의미한다. + - 보통 web 주소에서 포트번호가 주어지지 않으면 80 임. +- 이 세가지 중에 하나만 달라도, 다른 `Origin` 으로 판단된다. + - 즉 `CORS` 오류가 발생한다. + - 다른 `Origin` 에서 가져오는 리소스 이므로, 안정성을 보장할 수 없다 라는 취지의 오류가 발생한다는 의미인듯. + + + +# Same - Origin Policy + +- 리소스 요청을 제한하는 두 가지 정책 + - CORS + - SOP + +- SOP? + - [RFC 6454](https://tools.ietf.org/html/rfc6454#page-5) 에서 처음 등장한 정책 + - **같은 Origin의 리소스만 공유할 수 있음**을 명시한 규칙 + - 다른 출처의 리소스에 접근할 수 있는 몇가지 예외 조항이 있음 + 1. CORS 정책을 지킨 요청 + 2. 실행가능한 스크립트, 렌더될 이미지, 스타일 시트 요청. + +- 2번에 해당하는 자원을 요청한다면.. + + ```html + + + ``` + + - CORS 위반하지 않고 요청 자체는 성공. + - 해당 요청 헤더들에 `Sec-Fetch-Mode: no-cors` 가 포함되어 있음. + - 이 헤더가 있으면, 브라우저는 해당 필드값이 `no-cors` 인 경우에 다른 출처여도 CORS 위반 여부를 검사하지 않는다. + - 그러면 이 헤더값을 이용해서 CORS 정책을 우회할 수 있지 않을까? + - 못함. + - 브라우저는 이 헤더값을 이용해서 온 응답에 대해 javascript에서 사용하지 못하도록 해놨음 + + + +- SOP를 지키려면 많은 어려움이 있다. + - 웹 환경에서는 다른 Origin으로 부터 자원을 불러오는 이유는 흔하다. 즉 이용상 불편함이 많음 + - 그래서 CORS가 등장. + - 최소한의 원칙 (Origin) 을 어길 수 있으려면, **요청과 응답 헤더에 적절한 CORS에 대한 정보**가 있어야함. +- Same Origin 예시 + +![image](https://user-images.githubusercontent.com/22140570/129508965-f4021eee-2492-4996-87bb-737d78c62774.png) + +- 위에서도 언급했듯이, URL 구성요소 중 `Scheme`, `Host`, `Port` 3가지로 판단. +- 또한 출처를 비교하는 것은 **브라우저에서 구현된 스펙**(서버가 아니다) + - 어떠한 리소스 요청이(CORS 정책을 위반하는) 서버에게 가는 데, 해당 서버가 같은 출처에서만 보낸 요청을 받겠다는 로직이 있는 경우가 아니라면, 서버는 **정상적으로 응답**을 함 + - 그렇지만 브라우저가 받은 응답을 분석해서, **CORS 정책 위반이라 판단**(Same-Origin이 아니면..)되면 그 응답을 사용하지 않고 버린다. +- 다시 말하자면, CORS는 **브라우저의 구현 스펙에 포함되는 정책**이기에, 브라우저를 통하지 않고 서버간 통신을 할 때는 이 정책이 적용되지 않는다. + - 즉 브라우저 - 서버 통신 시에, CORS 오류가 발생했더라도, 서버쪽 로그는 정상 응답을 했다고 남는다. + + + + + +# CORS 어떻게 동작할까? + +- 요청 + - HTTP 프로토콜을 사용해서 리소스 사용 요청을 보내게 되는데, **요청 헤더의 Orgin 이라는 필드**에 출처를 함께 담아서 보냄. + - `Origin: https://evan-moon.github.io` +- 응답 + - 서버가 이 요청에 대한 응답을 내려줄 때, **Response Header에 Access-Control-Allow-Origin** 이라는 값에, 응답 리소스에 접근할 수 있도록 허용한 Origin을 내려줌. +- 브라우저 + - 응답 받은 브라우저는 자신이 보낸 request header Origin 과 서버가 보내준 response의 Access-Control-Allow-Origin 을 비교해본다음에, 유효한 응답인지 아닌지를 **판단**한다. + - 최종 판단은 브라우저가! + + + +## Preflight Request + +- 예비요청을 의미함. +- 일반적으로 개발할 대 가장 많이 마주치는 시나리오 +- 이 상황일 때는, 브라우저는 요청을 한번에 보내지 않고, **예비요청** + **본 요청**으로 나눠서 서버로 전송. + - HTTP method 중에 `OPTIONS` 가 사용된다. +- 예비요청의 역할은, 브라우저 스스로... 해당 요청(본 요청)을 보내기 전에 미리 보내서, 안전한 요청(CORS를 위한반 요청이 아닌지 등..) 인지 확인하는 듯함. + +![](https://evan-moon.github.io/static/c86699252752391939dc68f8f9a860bf/6af66/cors-preflight.png) + +- Preflight request example + + ```http + OPTIONS https://evanmoon.tistory.com/rss + + Accept: */* + Accept-Encoding: gzip, deflate, br + Accept-Language: en-US,en;q=0.9,ko;q=0.8,ja;q=0.7,la;q=0.6 + Access-Control-Request-Headers: content-type + Access-Control-Request-Method: GET + Connection: keep-alive + Host: evanmoon.tistory.com + Origin: https://evan-moon.github.io + Referer: https://evan-moon.github.io/2020/05/21/about-cors/ + Sec-Fetch-Dest: empty + Sec-Fetch-Mode: cors + Sec-Fetch-Site: cross-site + ``` + + - 이러한 옵션 요청에는 본 요청에 대한 정보도 포함되어있음. + - `Access-Control-Request-Headers` 는 본 요청에서 사용할 `Content-Type` 헤더를 알려주거나 + - `Access-Control-Request-Method` 를 이용해서 본 요청에서 사용할 메서드가 무엇인지 서버에게 미리 알려주고 있는 것. + +- Server response + + ```http + OPTIONS https://evanmoon.tistory.com/rss 200 OK + + Access-Control-Allow-Origin: https://evanmoon.tistory.com + Content-Encoding: gzip + Content-Length: 699 + Content-Type: text/xml; charset=utf-8 + Date: Sun, 24 May 2020 11:52:33 GMT + P3P: CP='ALL DSP COR MON LAW OUR LEG DEL' + Server: Apache + Vary: Accept-Encoding + X-UA-Compatible: IE=Edge + ``` + + - 응답 부분에서 `Access-Control-Allow-Origin` 은 요청과 같음. (Same-Origin 이구나..) + + - 즉 해당 서버에서 이 리소스에 접근할 수 있는 `Origin` 은 위 자원이라고 브라우저에게 이야기 해줌. + + - 다른 출저에서 이 리소스를 요청할 경우, `CORS` 오류가 발생함을 알게 될 것. + + - 예상 에러 + + ```text + 🚨 Access to fetch at ‘https://evanmoon.tistory.com/rss’ from origin ‘https://evan-moon.github.io’ has been blocked by CORS policy: + Response to preflight request doesn’t pass access control check: The ‘Access-Control-Allow-Origin’ header has a value ‘http://evanmoon.tistory.com’ that is not equal to the supplied origin. + Have the server send the header with a valid value, or, if an opaque response serves your needs, set the request’s mode to ‘no-cors’ to fetch the resource with CORS disabled. + ``` + +- 정리 + + - CORS 정책 위반과, 응답 성공 여부는 상관 없음 + - CORS 정책 위반이어도 `200` 이 나올 수 있음. + - 중요한 것은 예비 요청의 성공/실패 여부가 아니라, 서버에서 온 응답 헤더에 유효한 `Access-Control-Allow-Origin` 이 있는 지 임. + + + +## Simple Request + +- [단순 요청](https://developer.mozilla.org/ko/docs/Web/HTTP/CORS#%EC%A0%91%EA%B7%BC_%EC%A0%9C%EC%96%B4_%EC%8B%9C%EB%82%98%EB%A6%AC%EC%98%A4_%EC%98%88%EC%A0%9C) +- 예비 요청(Preflight) 을 보내지 않고, 서버에게 본 요청을 보낸 후에, 서버에서 온 응답 헤더에 `Access-Control-Allow-Origin` 을 확인하여, 브라우저가 **CORS 정책 위반 여부**를 검사하는 방식 + +![](https://evan-moon.github.io/static/d8ed6519e305c807c687032ff61240f8/6af66/simple-request.png) + +- 아무때나 사용할 수 있는 것이 아닌, 특정 조건을 만족하는 경우에만 예비 요청을 생략(단순 요청)하고 보낼 수 있음. + + 1. 요청의 메소드는 `GET`, `HEAD`, `POST` 중 하나여야 한다. + + 2. `Accept`, `Accept-Language`, `Content-Language`, `Content-Type`, `DPR`, `Downlink`, `Save-Data`, `Viewport-Width`, `Width`를 제외한 헤더를 사용하면 안된다. + + 3. 만약 `Content-Type`를 사용하는 경우에는 `application/x-www-form-urlencoded`, `multipart/form-data`, `text/plain`만 허용된다. + +- 그렇지만, 이러한 경우는 거의 없다고 보면 된다. + + + +## Credentialed Request + +- 인증된 요청을 사용하는 방법. +- 다른 출처 간 통신에서, 좀 더 보안을 강화하고 싶을 때 사용하는 방법임. +- 기본적으로 브라우저가 제공하는 비동기 리소스 요청 API는 XMLHttpRequest 객체나 fetch API는 별도의 옵션 없이 브라우저의 쿠키 정보나, 인증과 관련된 헤더를 함부로 요청에 담지 않음. + - 이 때 요청에 인증과 관련된 정보를 담을 수 있도록 해주는 것이 **credentials 옵션**임. +- 이 옵션에는 3가지 값이 있음. + +![image](https://user-images.githubusercontent.com/22140570/129509948-efc20cc3-7547-443e-befc-01c41ec1df54.png) + + + +- `incldue` + + - 이 옵션을 사용해서 리소스 요청에 인증 정보가 포함된다면, + - 브라우저는 다른 출처 리소스를 요청할 때 단순히 `Access-Control-Allow-Origin` 만 확인하는 것이 아닌 **뭔가 더 확인하는 과정**을 거치게 됨 + + - 요청 (fetch api 이용) + + ```javascript + fetch('https://evan-moon.github.io/feed.xml', { + credentials: 'include',... + }); + ``` + + - 응답 + + ```text + 🚨 Access to fetch at ’https://evan-moon.github.io/feed.xml’ from origin + ’http://localhost:8000’ has been blocked by CORS policy: + The value of the ‘Access-Control-Allow-Origin’ header in the response must not be the wildcard ’*’ + when the request’s credentials mode is ‘include’. + ``` + + - 브라우저가 알려주고 있음. + - credential option이 `include` 일 경우(모든 요청에 인증정보가 담길 경우), + - 모든 요청을 허용하는 `*` 를 `Access-Control-Allow-Origin` 헤더에 사용하면 안된다고 알려주는 오류임. (모든 요청을 허용하지 말라는 의미인듯. 보안적으로 좋지 않으므로..) + - 즉 모든 요청에 인증 정보가 담겨있는 상태에서, 다른 출처 리소스를 요청하게 되면 브라우저는 CORS 위반을 검사하는 룰에 밑에 두가지를 추가하게됨. + 1. 서버 응답 헤더의 `Access-Control-Allow-Origin`에는 *를 사용할 수 없으며, 명시적인 URL이어야 함. + 2. 서버 응답 헤더에는 반드시 `Allow-Control-Allow-Credentials: true`가 존재해야함. + + + +# CORS 해결 + + + +## Access-Control-Allow-Origin 셋팅하기 + +- 서버에서 `Access-Control-Allow-Origin` 에 알맞은 값을 세팅해주는 것. + - 단`*` 를 사용하는 것은, 이상한 출처에서 오는 요청까지 모두 허용하겠다는 의미로 심각한 보안 이슈가 발생할 수 있음. + - 그래서 가급적이면 어떠한 출처에서 오는 요청을 허용할지 명시해주는 것이 좋다. +- 그리고 Nginx, Apache같은 Web Server에서 허용해 줄수도 있지만, 불편하기 때문에 소스코드 내 미들웨어 등에서 위 같은 세팅하는 것을 추천. + - 예시 : Spring —> Cors Mapping 설정 해주는 것. + + + +## 리버스 프록싱 + +- nginx등에서 제공하는 proxy 기능을 이용하여, 브라우저에게 마치 CORS 정책을 지키고 있는 것처럼 알려주는 방법 +- webpack에서도 이러한 기능을 제공해 줄 수 있는듯. +- 즉 브라우저 요청 (`:80/api/me`) -> 리버스 프록싱 (`:80/server/api/me`) -> 서버 (`:8080/server/..`) + - 실제로 보면, CORS 정책을 어긴 것이지만, + - 중간에 Origin을 바꿔서 요청함으로써, 브라우저가 최종적으로 판단하기에는 CORS 어기지 않을 것 처럼 된다. + +# 참고 + +- https://evan-moon.github.io/2020/05/21/about-cors/ +- https://velog.io/@jesop/SOP%EC%99%80-CORS +- https://www.nginx.com/resources/glossary/reverse-proxy-server/ \ No newline at end of file From 4e055b4ecf1984e329382f6ec161b396cb810661 Mon Sep 17 00:00:00 2001 From: Jin Hyung Park Date: Mon, 16 Aug 2021 21:08:59 +0900 Subject: [PATCH 107/142] Delete README.md --- .../blocking-vs-non-blocking/sigrid/README.md | 287 ------------------ 1 file changed, 287 deletions(-) delete mode 100644 network/blocking-vs-non-blocking/sigrid/README.md diff --git a/network/blocking-vs-non-blocking/sigrid/README.md b/network/blocking-vs-non-blocking/sigrid/README.md deleted file mode 100644 index 1ee0bab..0000000 --- a/network/blocking-vs-non-blocking/sigrid/README.md +++ /dev/null @@ -1,287 +0,0 @@ -# Blocking vs Non-blocking -## Synchronous vs Asynchronous -### Synchronous -* 동기는 두 가지 이상의 작업이 서로 시간을 맞추어 행동하는 것을 의미한다. -* 호출한 함수가 다른 호출한 함수의 작업이 끝나 결과값을 반환하기를 기다리거나, 지속적으로 호출된 함수에게 확인 요청을 하는 경우가 있다. -* 작업 A와 작업 B가 있다고 가정하자. - * 작업 A와 작업 B의 시작 시간과 종료 시간이 같으면 동기라고 볼 수 있다. - * 쓰레드 A, 쓰레드 B가 동시에 작업을 시작하고 종료하는 경우 - * 메소드 리턴 시간 A와 결과를 전달받는 시간 B가 일치한 경우 - * 작업 A가 끝나는 시간과 작업 B가 시작하는 시간이 같으면 동기라고 볼 수 있다. - -### Asynchronous -* 비동기는 두 가지 이상의 작업을 할 때 대상들이 서로의 시간을 맞추지 않고 행동하는 것을 의미한다. -* 호출하는 함수가 호출되는 함수에게 작업을 맡겨놓고 더 이상 신경을 쓰지 않는 경우가 있다. - -### Blocking vs Non-Blocking -* 블록킹과 논블록킹은 직접 제어할 수 없는 대상을 어떻게 처리할 것인가에 따라 나눠지는 개념이다. -* 직접 제어할 수 없는 대상으로는 I/O, 멀티 쓰레드 동기화 등이 있다. - -#### Blocking -* 블록킹은 직접 제어할 수 없는 대상의 작업이 끝날 때까지 제어권을 넘겨주지 않는 것이다. -* 예를 들어 호출하는 함수가 I/O를 요청했을 때 I/O 처리가 완료될 때까지 아무 일도 하지 못한 채 기다리는 것을 말한다. - -#### Non-Blocking -* 논블록킹은 직접 제어할 수 없는 대상의 작업 처리 여부와 무관하게 처리하는 것을 의미한다. -* 예를 들어 호출하는 함수가 I/O를 요청했을 때 I/O 처리 여부와 상관없이 바로 자신의 작업을 할 수 있는 것을 말한다. - -#### Synchronous Blocking I/O -![](https://i.imgur.com/v6uOhUA.png) -```java= -device = IO.open() -// 이 Thread는 데이터를 읽을 때까지 아무 일도 할 수 없음 -data = device.read() -print(data) -``` -* Synchronous: 애플리케이션의 ```read()``` 메소드가 리턴하는 시간과 커널에서 결과를 가져오는 시간이 일치한다. -* Blocking: 커널의 작업이 완료될 때까지 대기한다. - -#### Synchronous Non-Blocking I/O -![](https://i.imgur.com/BRrD3I6.png) -```python= -device = IO.open() -ready = False -while not ready: - print("There is no data to read!") - - # 다른 작업을 처리할 수 있음 - - # while 문 내부의 다른 작업을 다 처리하면 데이터가 도착했는지 확인한다. - ready = IO.poll(device, IO.INPUT, 5) -data = device.read() -print(data) -``` -* Synchronous: read() 메서드(애플리케이션)가 리턴하는 시간과 커널에서 결과를 가져오는 시간이 일치한다. -* Non-Blocking: 애플리케이션으로부터 요청을 받은 커널은 작업 완료 여부와 상관없이 바로 반환하여 제어권을 애플리케이션에게 넘겨준다. 커널의 작업이 완료되면 작업 결과를 애플리케이션에게 반환한다. -* 대표적인 예로는 멀티플랙싱을 수행하는 select(), epoll() 함수가 있다. -* Application에서 I/O를 요청 후 바로 return되어 다른 작업을 수행하다가 특정 시간에 데이터가 준비가 다되었는지 상태를 확인한다. 데이터의 준비가 끝날 때까지 틈틈이 확인을 하다가 완료가 되었으면 종료된다. -* 여기서 주기적으로 체크하는 방식을 폴링(Polling) 이라고 한다. 그러나 이러한 방식은 작업이 완료되기 전까지 주기적으로 호출하기 때문에 불필요하게 자원을 사용하게 된다. - -#### Asynchronous Non-Blocking I/O (AIO) -![](https://i.imgur.com/GrI8VfR.png) -```python= -ios = IO.IOService() -device = IO.open(ios) - -def inputHandler(data, err): - "Input data handler" - if not err: - print(data) - -device.readSome(inputHandler) -# 이 thread는 데이터가 도착했는지 신경쓰지 않고 다른 작업을 처리할 수 있다. -ios.loop() -``` -* Asynchronous: readSome() 메서드(애플리케이션)가 리턴하는 시간과 커널에서 결과를 가져오는 시간이 일치하지 않는다. -* Non-Blocking: 애플리케이션으로부터 요청을 받은 커널은 작업 완료 여부와 상관없이 바로 반환하여 제어권을 애플리케이션에게 넘겨준다. 작업이 끝나면 애플리케이션에게 시그널 또는 콜백을 보낸다. -* 대표적인 예로는 윈도우에서 멀티플랙싱을 수행하는 IOCP가 있다. -* I/O 요청을 한 후 Non-Blocking I/O와 마찬가지고 즉시 리턴된다. 허나, 데이터 준비가 완료되면 이벤트가 발생하여 알려주거나, 미리 등록해놓은 callback을 통해서 이후 작업이 진행된다. 이전 두 I/O의 문제였던 Blocking이나 Polling이 없기 때문에 자원을 보다 더 효율적으로 사용할 수 있다. - -#### Asynchronous Blocking -* 비동기이면서도 블록킹을 하는 경우는 비효율적이므로 자주 사용되지 않는다고 한다. -* 하지만 Asynchronous Non-Blocking 모델 중에서 Blocking 형태로 동작하는 모델이 있는 경우 의도와 다르게 Asynchrnous Blocking으로 동작하는 경우가 있다고 한다. -* 예를 들어, Node.js는 비동기로 작업하려고 하지만 MySQL 드라이버가 Blocking 방식으로 동작하므로 어쩔 수 없이 Asynchronous Blocking 방식으로 동작한다고 한다. - -#### 본격 Case Study : 박 상병님, 저희 짬통 언제 버리러 가나요? -* Blocking & Synchronous -``` -김 일병 : 박 상병님, 오늘 짬통 언제 버리러 갑니까? -박 상병 : 있어봐, 중대 운전병에게 물어볼게. -김 일병 : (...) -대표님 : (수고하십니다 XX대대 상병 박공군입니다) -김 일병 : (박 상병님 전화 받고 있는 것을 수화기를 들고 같이 듣고 있음) -이 병장: 김 일병, 언제 버리러 가는거야? -김 일병: (수화기로 전화 내용을 듣고 있으며 말한다) 지금 전화 중이십니다. 잠시만 기다려주십시오. -이 병장: 오오 알겠어. 그런데 너 왜 마저 일 안 보는 거야? -김 일병: 네 버리러 가야하는데.. 언제 갈 지를 몰라서 일 하기가 조금 그렇습니다.. -이 병장: ??? 뭐지 ? -``` -* Blocking & Asynchronous -``` -김 일병 : 박 상병님, 오늘 짬통 언제 버리러 갑니까? -박 상병 : 있어봐, 중대 운전병에게 물어볼게. -김 일병 : (...) -대표님 : (수고하십니다 XX대대 상병 박공군입니다) -김 일병 : (과정 지켜봄.. 궁금함.. 계속 서 있음) -이 병장: 김 일병, 언제 버리러 가는거야? -김 일병: (아무런 일도 하지 않으며 말한다) 잘 모르겠습니다. 뭐 전화오면 박 상병님께서 알려주시지 않겠습니까? -이 병장: 흠.. 폐급인가? -``` - -* Non-blocking & Synchronous -``` -김 일병 : 박 상병님, 오늘 짬통 언제 버리러 갑니까? -박 상병 : 있어봐, 중대 운전병에게 물어볼게. -김 일병 : 넵! -박 상병 : (수고하십니다 XX대대 상병 박공군입니다) -김 일병 : 연락 되셨습니까? -박 상병 : 이병이 받던데. 좀 이따 해볼게. -김 일병 : 연락 되셨습니까? -박 상병 : 운전병 제초하러 갔대. 나중에 전화준댄다. -이 병장 : 김 일병, 언제 버리러 간대? -김 일병 : 하.. 조금 이따 연락 주신다고 하는데 저도 진짜 궁금합니다. 일단 저는 화장실 청소 좀 하고 있겠습니다. -이 병장 : 그래? 알겠어. 박 상병이 전화 오면 알려주겠지. 조금 이따 물어보면 될 거 같아. -김 일병 : (다른 일 보다가 물어본다) 연락 되셨습니까? -박 상병 : ㅅㅂ 왜 자꾸 물어보냐 너 폐급이냐? 아직 전화 안왔다니까; -``` - -* Non-blocking & Asynchronous -``` -김 일병 : 박 상병님, 오늘 짬통 언제 버리러 갑니까? -박 상병 : 있어봐, 중대 운전병에게 물어볼게. -김 일병 : 넵! -박 상병 : (수고하십니다 XX대대 상병 박공군입니다) -박 상병 : 오늘 9시에 간댄다. 준비하자. -김 일병 : 넵! 짬통 일병들이랑 옮기고 있겠습니다. -``` - -#### 정리 -* Blocking/NonBlocking - * Blocking/NonBlocking은 호출되는 함수가 바로 리턴하느냐 마느냐가 관심사다. - * 호출된 함수가 바로 리턴해서 호출한 함수에게 제어권을 넘겨주고, 호출한 함수가 다른 일을 할 수 있는 기회를 줄 수 있으면 NonBlocking이다. - * 그렇지 않고 호출된 함수가 자신의 작업을 모두 마칠 때까지 호출한 함수에게 제어권을 넘겨주지 않고 대기하게 만든다면 Blocking이다. - -* Synchronous/Asynchronous - * Synchronous/Asynchronous는 호출되는 함수의 작업 완료 여부를 누가 신경쓰냐가 관심사다. - * 호출되는 함수에게 callback을 전달해서, 호출되는 함수의 작업이 완료되면 호출되는 함수가 전달받은 callback을 실행하고, 호출하는 함수는 작업 완료 여부를 신경쓰지 않으면 Asynchronous다. - * 호출하는 함수가 호출되는 함수의 작업 완료 후 리턴을 기다리거나, 또는 호출되는 함수로부터 바로 리턴 받더라도 작업 완료 여부를 호출하는 함수 스스로 계속 확인하며 신경쓰면 Synchronous다. - -### 추가 설명 -* Blocking 방식은 요청하고 응답 올때까지 기다리는 방식이고, Non-Blocking 방식은 요청하고 딴 일하다 나중에 응답신호가 오면 결과를 읽어 처리하는 방식이다. -* 동기방식은 요청자와 제공자사이에 계속 Connection이 맺어져 있어야 하고, 비동기방식은 Connection은 끊어지고 서로간에 이벤트를 통해 통신하는 방식이다. -* 비동기방식은 요청자와 제공자 사이에 Message Broker라는 또 다른 서비스가 중계해주지만, 동기 방식은 요청자 어플리케이션에 비동기 처리를 하는 로직이 있다. -* 최근 흔히 사용하는 REST API는 동기 방식이고 보통 Non-Blocking방식으로 통신한다. -* Frontend와 backend사이는 거의 대부분 동기+non-blocking 방식으로 구현한다. -* 비동기방식 패턴 중 제일 대표적인 것이 Publish/Subscribe (또는 Producer-Consumer) 패턴이다. - * Publisher인 유튜버들은 구독을 요청할 수 있는 채널을 만들고, 그 채널에 동영상을 계속 publishing해둔다. - * Subscriber인 사용자가 특정 유튜브채널을 구독 신청하면 새로운 동영상이 업로드 될때 첫화면에 추천동영상으로 받아보거나 모바일앱 알림 등으로 받아 볼 수 있게 된다. - * 즉, 사용자는 구독만 해놓고 있으면 새 동영상 올라올때까지 Youtube에 머물러 있을 필요가 없다. - * 비동기 메시징 방식은 추후 CS 스터디 주제로 발제할 생각이다. - * 이런 비동기 방식을 사용하는 이유는 큰 서비스를 이루는 마이크로서비스 중 하나가 실패해도 전체적인 서비스는 그대로 진행되도록 하기 위함이다. - * 예를 들어 쇼핑몰 상품 주문 시 주문서비스, 결제서비스, 배송서비스가 필요한데 동기방식으로 하면 결제나 배송 서비스에 문제가 생기면 상품 주문은 실패하게 된다. - * 그러나 비동기방식을 사용하면 Queue에 처리해야할 메시지가 있기 때문에 일시적 장애가 발생해도 복구가 되면 처리 가능하다. 따라서 상품 주문은 어떠한 경우에도 정상적으로 처리될 수 있게 된다. -* 일반적으로 Front와 Backend 서비스간에는 동기방식을 사용하고, backend의 서비스들간에는 비동기방식을 사용한다. -* 또한 데이터 조회 서비스는 동기방식을 사용하고, 데이터 변경 서비스는 비동기방식을 사용한다. - -### Spring WebFlux란 무엇일까? -* Non-blocking을 통해서 적은 수의 리소스로 동시성을 다룰 수 있게 해주는 프레임워크이다. -* 우리가 Spring MVC와 RDBMS를 사용하고 있으면 Blocking I/O를 사용하고 있는 것이다. -* Application에서 I/O 요청을 한 후 완료되기 전까지는 Application이 Block이 되어 다른 작업을 수행할 수 없다. 이는 해당 자원이 효율적으로 사용되지 못하고 있음을 의미한다. -* 물론, Blocking 방식임에도 불구하고 마치 Block이 안된듯이 동작하는 것처럼 보인다. 이는 멀티 쓰레드 기반의 방식이기 때문이다. 정확히는, 하나의 쓰레드가 블록되는 순간 다른 쓰레드가 동작하도록 함으로써 블록 문제를 해결하였다. -* 하지만 쓰레드 간의 Context Switching 등의 비용이 존재하므로, 여러 개의 I/O를 동시다발적으로 효율적인 처리를 하려면 논블로킹으로 처리해야만 한다. - -#### Blocking I/O 예시: RestTemplate -* RestTemplate은 Multi-Thread와 Blocking방식을 사용한다. -* Thread pool은 요청자 어플리케이션 구동시에 미리 만들어 놓는다. -* Request는 먼저 Queue에 쌓이고 가용한 스레드가 있으면 그 스레드에 할당되어 처리된다. -* 즉, 1 요청 당 1 스레드가 할당됩니다. -* 각 스레드에서는 Blocking방식으로 처리되어 응답이 올 때까지 그 스레드는 다른 요청에 할당될 수 없다. -* 아래는 RestTemplate을 Connection Pool에 Spring Bean으로 등록하기 위한 예제이다. - * 요청 당 20개의 RestTemplate client를 만들고, 최대 50개까지 증가할 수 있도록 했다. - -```java= -@Configuration -public class RestTemplateConfig { - public RestTemplate getRestTemplate(int defaultMaxPerRoute, int maxTotal) { - PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(); - connManager.setDefaultMaxPerRoute(defaultMaxPerRoute); - connManager.setMaxTotal(maxTotal); - - HttpClient client = HttpClientBuilder.create().setConnectionManager(connManager).build(); - - HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(client); - factory.setConnectTimeout(3000); - factory.setReadTimeout(3000); - - return new RestTemplate(factory); - - } - - @Bean - public RestTemplate coffeeRestTemplate() { - return getRestTemplate(20, 50); - } -} -``` -* 요청을 처리할 스레드가 있으면 아무런 문제가 없지만, 스레드가 다 차는 경우 이후의 요청은 Queue에 대기하게 된다. -* 대부분의 문제는 네트워킹이나 DB와의 통신에서 생기는데 이런 문제가 여러 스레드에서 발생하면 가용한 스레드수가 현저하게 줄어들게 되고, 결국 전체 서비스는 매우 느려지게 된다. -* RestTemplate을 이용하여 API 중 응답 시간이 약 3초 정도 걸리는 요청을 3번 반복하는 예제를 제시한다. -```java= -@Test -public void blocking() { - final RestTemplate restTemplate = new RestTemplate(); - - final StopWatch stopWatch = new StopWatch(); - stopWatch.start(); - - for (int i = 0; i < 3; i++) { - final ResponseEntity response = - restTemplate.exchange(THREE_SECOND_URL, HttpMethod.GET, HttpEntity.EMPTY, String.class); - assertThat(response.getBody()).contains("success"); - } - - stopWatch.stop(); - - System.out.println(stopWatch.getTotalTimeSeconds()); -} -``` -* Spring의 HTTP 요청 라이브러리인 RestTemplate을 사용하여 3초가 걸리는 API를 3번 호출하였다. 결과는 9.xx초가 나온다. 이유는 I/O가 요청 중일 때에는 아무 작업도 할 수 없기 때문이다. - -#### Non-Blocking I/O: WebClientSpring WebClient -* Spring WebClient는 Single Thread와 Non-Blocking방식을 사용한다. -* Core 당 1개의 Thread를 이용한다. -![](https://i.imgur.com/7MP2vt0.png) - - -[그림출처](https://luminousmen.com/post/asynchronous-programming-blocking-and-non-blocking) - -* 각 요청은 Event Loop내에 Job으로 등록이 된다. -* Event Loop는 각 Job을 제공자에게 요청한 후, 결과를 기다리지 않고 다른 Job을 처리한다. Event Loop는 제공자로부터 callback으로 응답이 오면, 그 결과를 요청자에게 제공한다. -* WebClient는 이렇게 이벤트에 반응형으로 동작하도록 설계되었다고 한다. -* 아래 예제는 위에서 제시한 요청시간이 약 3초 정도 걸리는 동일한 API를 가져왔다고 가정한 것이다. -```java= -@Test -public void nonBlocking3() throws InterruptedException { - final StopWatch stopWatch = new StopWatch(); - stopWatch.start(); - for (int i = 0; i < LOOP_COUNT; i++) { - this.webClient - .get() - .uri(THREE_SECOND_URL) - .retrieve() - .bodyToMono(String.class) - .subscribe(it -> { - count.countDown(); - System.out.println(it); - }); - } - - count.await(10, TimeUnit.SECONDS); - stopWatch.stop(); - System.out.println(stopWatch.getTotalTimeSeconds()); -} -``` -* WebFlux에서 제공하는 WebClient를 사용해서 위와 동일하게 3초가 걸리는 API를 호출하였다. for문 안의 변수인 LOOP_COUNT는 100으로 코드상에서 설정되어있다. 3초 걸리는 API를 100번 호출한다 하더라도 3.xx초 밖에 걸리지 않는다. -* 만약, Blocking을 위처럼 많은 요청을 동시에 처리하려면 그 만큼의 Thread이 생성되어야 한다. 그러나 이렇게 처리한다 해도 Context Swiching에 의한 오버헤드가 존재할 것이다. - -### 성능비교 -* 아래는 RestTemplate을 사용하는 Spring Boot1과 WebClient를 사용하는 Spring Boot2의 성능비교 결과이다. -* ![](https://i.imgur.com/ACQsu6g.png) - -* 1000명까지는 비슷하지만 동시사용자가 늘수록 RestTemplate은 급격하게 느려지는것을 볼 수 있다. -[그림출처](https://alwayspr.tistory.com/44) -* Spring 커뮤니티에서는 RestTemplate을 이미 Depreciated시키고 WebClient를 사용할것을 강력히 권고하고 있다. -``` -NOTE: As of 5.0 this class is in maintenance mode, -with only minor requests for changes and bugs to be accepted going forward. -Please, consider using the org.springframework.web.reactive.client.WebClient -which has a more modern API and supports sync, async, and streaming scenarios. -``` - -## 참고한 링크 -* https://velog.io/@codemcd/Sync-VS-Async-Blocking-VS-Non-Blocking-sak6d01fhx -* https://devahea.github.io/2019/04/21/Spring-WebFlux%EB%8A%94-%EC%96%B4%EB%96%BB%EA%B2%8C-%EC%A0%81%EC%9D%80-%EB%A6%AC%EC%86%8C%EC%8A%A4%EB%A1%9C-%EB%A7%8E%EC%9D%80-%ED%8A%B8%EB%9E%98%ED%94%BD%EC%9D%84-%EA%B0%90%EB%8B%B9%ED%95%A0%EA%B9%8C/ -* https://happycloud-lee.tistory.com/220 -* https://happycloud-lee.tistory.com/154?category=902418 -* https://musma.github.io/2019/04/17/blocking-and-synchronous.html -* http://homoefficio.github.io/2017/02/19/Blocking-NonBlocking-Synchronous-Asynchronous/ From f15c605457bc00a44cb20bd1be653e971f26d050 Mon Sep 17 00:00:00 2001 From: Jin Hyung Park Date: Mon, 16 Aug 2021 21:09:09 +0900 Subject: [PATCH 108/142] Delete README.md --- network/cors/sigrid/README.md | 139 ---------------------------------- 1 file changed, 139 deletions(-) delete mode 100644 network/cors/sigrid/README.md diff --git a/network/cors/sigrid/README.md b/network/cors/sigrid/README.md deleted file mode 100644 index 6936b5f..0000000 --- a/network/cors/sigrid/README.md +++ /dev/null @@ -1,139 +0,0 @@ -# 네트워크: CORS란 무엇인가 -## CORS: Cross-Origin Resource Sharing -### Origin -* URL 구조에서 Protocol + Host + Port를 합친 것을 의미함 -```console -location.source -> https://hackmd.io -``` -* 간단한 퀴즈: 다음 중 같은 출처가 아닌 것은? - * ```https://hackmd.io/about```: 같은 출처 - * ```https://hackmd.io:32/about```: 다른 출처(Port 다름) - * ```http://hackmd.io```: 다른 출처(Protocol 다름) - -### Same-Origin Policy -* Postman으로 API를 호출하면 잘 되는데, 브라우저로 호출하면 CORS 에러가 나는 이유는 무엇일까? -* 브라우저가 동일 출처 정책(Same Origin Policy)를 준수하기 때문에 그렇다. -* 예를 들어 hackmd.io 사이트에서 medium.com의 API를 호출하면 서로 다른 출처이므로 CORS 에러가 발생할 수 있다. -* 동일 출처 정책은 XSS나 XSRF 등의 보안 취약점을 노린 공격을 방어할 수 있다. -* 하지만 외부 리소스를 사용해야 하는 경우는 매우 많다. SOP 정책의 예외 사항이 CORS라고 할 수 있다. - -### CORS 동작 원리 -* Simple Request와 Preflight Request가 있지만, 주로 Preflight Request 방식이 선호된다. - -![](https://i.imgur.com/Wv9msLm.png) -* Preflight 요청은 실제 리소스를 요청하기 전에 OPTIONS라는 메서드를 통해 실제 요청을 전송할지 판단한다. -* OPTIONS 메서드로 서버에 예비 요청을 먼저 보내고, 서버는 이 예비 요청에 대한 응답으로 Access-Control-Allow-Origin 헤더를 포함한 응답을 브라우저에 보낸다. -* 브라우저는 단순 요청과 동일하게 Access-Control-Allow-Origin 헤더를 확인해서 CORS 동작을 수행할지 판단한다. - -### CORS 에러 해결 방법 -* 서버에서 ```Access-Control-Allow-Origin``` 헤더를 포함한 응답을 브라우저에 보내는 방식으로 CORS 에러를 해결할 수 있다. -* Node.js 기준으로 cors라는 라이브러리가 있고, Spring Boot에서는 WebMvcController를 설정해주면 된다. - -#### Access-Control-Allow-Origin: | * -* 헤더가 작성된 링크만 브라우저가 접근할 수 있도록 설정할 수 있다. -* 사용 예시 -``` -Access-Control-Allow-Origin: https://medium.com -``` -``` -Access-Control-Allow-Origin: * // 와일드 카드를 쓰면 모든 사이트 다 된다 -``` -* 서버에서 아래와 같이 응답 헤더를 설정해서 보내주면 된다. -```javascript= -router.options('/cors', (req, res, next) => { - res.set('Access-Control-Allow-Origin', '*') - res.send() -}) -router.put('/cors', (req, res, next) => { - res.set('Access-Control-Allow-Origin', '*') - res.send() -}) -``` -#### Access-Control-Allow-Methods: [, ]* -* 리소스 접근을 허용하는 HTTP 메서드를 지정해 주는 헤더이다. -```javascript= -router.options('/cors', (req, res, next) => { - res.set('Access-Control-Allow-Origin', '*') - res.set('Access-Control-Allow-Methods', req.get('Access-Control-Request-Method')) - res.send() -}) -router.put('/cors', (req, res, next) => { - res.set('Access-Control-Allow-Origin', '*') - res.send() -}) -``` -#### Access-Control-Expose-Headers: [, ]* -* 서버에서 응답 헤더에 Access-Control-Expose-Headers를 추가해 줘야 브라우저의 자바스크립트에서 헤더에 접근할 수 있다. -```javascript= -router.options('/cors', (req, res, next) => { - res.set('Access-Control-Allow-Origin', '*') - res.set('Access-Control-Allow-Methods', req.get('Access-Control-Request-Method')) - res.send() -}) -router.put('/cors', (req, res, next) => { - res.set('Access-Control-Allow-Origin', '*') - res.set('Access-Control-Expose-Headers', 'X-Custom-Beomy') - res.set('X-Custom-Beomy', 'Bemoy') - res.send() -}) -``` - -#### Access-Control-Allow-Headers: [, ]* -* 브라우저에서 보내는 요청 헤더에 포함된 Access-Control-Request-Headers 헤더에 대한 응답 결과이다. -```javascript= -router.options('/cors', (req, res, next) => { - res.set('Access-Control-Allow-Origin', '*') - res.set('Access-Control-Allow-Methods', req.get('Access-Control-Request-Method')) - res.set('Access-Control-Allow-Headers', req.get('Access-Control-Request-Headers')) - res.send() -}) -router.put('/cors', (req, res, next) => { - res.set('Access-Control-Allow-Origin', '*') - console.log(req.get('X-Custom-Request')) // Beomy - res.send() -}) -``` -#### Access-Control-Max-Age: -* preflight 요청 결과를 캐시 할 수 있는 시간을 나타낸다. -* 아래와 같이 초 단위로 캐시 시간을 설정한다. -``` -Access-Control-Max-Age: 60 -``` -* 위의 코드는 60초 동안 preflight 요청을 캐시 하는 코드이다. -* 60초 동안 OPTIONS 메서드를 사용하는 예비 요청을 보내지 않습니다. -```javascript= -router.options('/cors', (req, res, next) => { - res.set('Access-Control-Allow-Origin', '*') - res.set('Access-Control-Allow-Methods', req.get('Access-Control-Request-Method')) - res.set('Access-Control-Max-Age', 60) - res.send() -}) -router.put('/cors', (req, res, next) => { - res.set('Access-Control-Allow-Origin', '*') - res.send() -}) -``` -#### Access-Control-Allow-Credentials: true -* 자바스크립트 요청에서 credentials가 include일 때 요청에 대한 응답을 할 수 있는지를 나타낸다. -* false로 설정해 주고 싶을 경우에는 헤더를 생략하면 된다. -```javascript= -router.options('/cors', (req, res, next) => { - res.set('Access-Control-Allow-Origin', 'https://www.google.com') - res.set('Access-Control-Allow-Methods', req.get('Access-Control-Request-Method')) - res.set('Access-Control-Allow-Credentials', true) - res.send() -}) -router.put('/cors', (req, res, next) => { - res.set('Access-Control-Allow-Origin', 'https://www.google.com') - res.set('Access-Control-Allow-Credentials', true) - res.send() -}) -``` -* Access-Control-Allow-Credentials: true 추가 뿐만 아니라, Access-Control-Allow-Origin 헤더도 와일드카드가 아닌 출처를 명시해주어야 한다. - -## 프록시 서버 -* 프론트엔드와 백엔드 사이에 프록시 서버를 두어서 CORS를 해결할 수 있다. -* 개발 환경에서는 Webpack Dev Server 등의 라이브러리를 사용하여 프록시 설정을 할 수 있다. - -## 참고 링크 From ea622881b8d0079d07054336367f2f39d31d1d9a Mon Sep 17 00:00:00 2001 From: Jin Hyung Park Date: Mon, 16 Aug 2021 21:11:20 +0900 Subject: [PATCH 109/142] =?UTF-8?q?feat:=20Blocking=20vs=20Non-Blocking=20?= =?UTF-8?q?=ED=95=99=EC=8A=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../blocking-vs-nonblocking/sigrid/README.md | 287 ++++++++++++++++++ 1 file changed, 287 insertions(+) create mode 100644 network/blocking-vs-nonblocking/sigrid/README.md diff --git a/network/blocking-vs-nonblocking/sigrid/README.md b/network/blocking-vs-nonblocking/sigrid/README.md new file mode 100644 index 0000000..1ee0bab --- /dev/null +++ b/network/blocking-vs-nonblocking/sigrid/README.md @@ -0,0 +1,287 @@ +# Blocking vs Non-blocking +## Synchronous vs Asynchronous +### Synchronous +* 동기는 두 가지 이상의 작업이 서로 시간을 맞추어 행동하는 것을 의미한다. +* 호출한 함수가 다른 호출한 함수의 작업이 끝나 결과값을 반환하기를 기다리거나, 지속적으로 호출된 함수에게 확인 요청을 하는 경우가 있다. +* 작업 A와 작업 B가 있다고 가정하자. + * 작업 A와 작업 B의 시작 시간과 종료 시간이 같으면 동기라고 볼 수 있다. + * 쓰레드 A, 쓰레드 B가 동시에 작업을 시작하고 종료하는 경우 + * 메소드 리턴 시간 A와 결과를 전달받는 시간 B가 일치한 경우 + * 작업 A가 끝나는 시간과 작업 B가 시작하는 시간이 같으면 동기라고 볼 수 있다. + +### Asynchronous +* 비동기는 두 가지 이상의 작업을 할 때 대상들이 서로의 시간을 맞추지 않고 행동하는 것을 의미한다. +* 호출하는 함수가 호출되는 함수에게 작업을 맡겨놓고 더 이상 신경을 쓰지 않는 경우가 있다. + +### Blocking vs Non-Blocking +* 블록킹과 논블록킹은 직접 제어할 수 없는 대상을 어떻게 처리할 것인가에 따라 나눠지는 개념이다. +* 직접 제어할 수 없는 대상으로는 I/O, 멀티 쓰레드 동기화 등이 있다. + +#### Blocking +* 블록킹은 직접 제어할 수 없는 대상의 작업이 끝날 때까지 제어권을 넘겨주지 않는 것이다. +* 예를 들어 호출하는 함수가 I/O를 요청했을 때 I/O 처리가 완료될 때까지 아무 일도 하지 못한 채 기다리는 것을 말한다. + +#### Non-Blocking +* 논블록킹은 직접 제어할 수 없는 대상의 작업 처리 여부와 무관하게 처리하는 것을 의미한다. +* 예를 들어 호출하는 함수가 I/O를 요청했을 때 I/O 처리 여부와 상관없이 바로 자신의 작업을 할 수 있는 것을 말한다. + +#### Synchronous Blocking I/O +![](https://i.imgur.com/v6uOhUA.png) +```java= +device = IO.open() +// 이 Thread는 데이터를 읽을 때까지 아무 일도 할 수 없음 +data = device.read() +print(data) +``` +* Synchronous: 애플리케이션의 ```read()``` 메소드가 리턴하는 시간과 커널에서 결과를 가져오는 시간이 일치한다. +* Blocking: 커널의 작업이 완료될 때까지 대기한다. + +#### Synchronous Non-Blocking I/O +![](https://i.imgur.com/BRrD3I6.png) +```python= +device = IO.open() +ready = False +while not ready: + print("There is no data to read!") + + # 다른 작업을 처리할 수 있음 + + # while 문 내부의 다른 작업을 다 처리하면 데이터가 도착했는지 확인한다. + ready = IO.poll(device, IO.INPUT, 5) +data = device.read() +print(data) +``` +* Synchronous: read() 메서드(애플리케이션)가 리턴하는 시간과 커널에서 결과를 가져오는 시간이 일치한다. +* Non-Blocking: 애플리케이션으로부터 요청을 받은 커널은 작업 완료 여부와 상관없이 바로 반환하여 제어권을 애플리케이션에게 넘겨준다. 커널의 작업이 완료되면 작업 결과를 애플리케이션에게 반환한다. +* 대표적인 예로는 멀티플랙싱을 수행하는 select(), epoll() 함수가 있다. +* Application에서 I/O를 요청 후 바로 return되어 다른 작업을 수행하다가 특정 시간에 데이터가 준비가 다되었는지 상태를 확인한다. 데이터의 준비가 끝날 때까지 틈틈이 확인을 하다가 완료가 되었으면 종료된다. +* 여기서 주기적으로 체크하는 방식을 폴링(Polling) 이라고 한다. 그러나 이러한 방식은 작업이 완료되기 전까지 주기적으로 호출하기 때문에 불필요하게 자원을 사용하게 된다. + +#### Asynchronous Non-Blocking I/O (AIO) +![](https://i.imgur.com/GrI8VfR.png) +```python= +ios = IO.IOService() +device = IO.open(ios) + +def inputHandler(data, err): + "Input data handler" + if not err: + print(data) + +device.readSome(inputHandler) +# 이 thread는 데이터가 도착했는지 신경쓰지 않고 다른 작업을 처리할 수 있다. +ios.loop() +``` +* Asynchronous: readSome() 메서드(애플리케이션)가 리턴하는 시간과 커널에서 결과를 가져오는 시간이 일치하지 않는다. +* Non-Blocking: 애플리케이션으로부터 요청을 받은 커널은 작업 완료 여부와 상관없이 바로 반환하여 제어권을 애플리케이션에게 넘겨준다. 작업이 끝나면 애플리케이션에게 시그널 또는 콜백을 보낸다. +* 대표적인 예로는 윈도우에서 멀티플랙싱을 수행하는 IOCP가 있다. +* I/O 요청을 한 후 Non-Blocking I/O와 마찬가지고 즉시 리턴된다. 허나, 데이터 준비가 완료되면 이벤트가 발생하여 알려주거나, 미리 등록해놓은 callback을 통해서 이후 작업이 진행된다. 이전 두 I/O의 문제였던 Blocking이나 Polling이 없기 때문에 자원을 보다 더 효율적으로 사용할 수 있다. + +#### Asynchronous Blocking +* 비동기이면서도 블록킹을 하는 경우는 비효율적이므로 자주 사용되지 않는다고 한다. +* 하지만 Asynchronous Non-Blocking 모델 중에서 Blocking 형태로 동작하는 모델이 있는 경우 의도와 다르게 Asynchrnous Blocking으로 동작하는 경우가 있다고 한다. +* 예를 들어, Node.js는 비동기로 작업하려고 하지만 MySQL 드라이버가 Blocking 방식으로 동작하므로 어쩔 수 없이 Asynchronous Blocking 방식으로 동작한다고 한다. + +#### 본격 Case Study : 박 상병님, 저희 짬통 언제 버리러 가나요? +* Blocking & Synchronous +``` +김 일병 : 박 상병님, 오늘 짬통 언제 버리러 갑니까? +박 상병 : 있어봐, 중대 운전병에게 물어볼게. +김 일병 : (...) +대표님 : (수고하십니다 XX대대 상병 박공군입니다) +김 일병 : (박 상병님 전화 받고 있는 것을 수화기를 들고 같이 듣고 있음) +이 병장: 김 일병, 언제 버리러 가는거야? +김 일병: (수화기로 전화 내용을 듣고 있으며 말한다) 지금 전화 중이십니다. 잠시만 기다려주십시오. +이 병장: 오오 알겠어. 그런데 너 왜 마저 일 안 보는 거야? +김 일병: 네 버리러 가야하는데.. 언제 갈 지를 몰라서 일 하기가 조금 그렇습니다.. +이 병장: ??? 뭐지 ? +``` +* Blocking & Asynchronous +``` +김 일병 : 박 상병님, 오늘 짬통 언제 버리러 갑니까? +박 상병 : 있어봐, 중대 운전병에게 물어볼게. +김 일병 : (...) +대표님 : (수고하십니다 XX대대 상병 박공군입니다) +김 일병 : (과정 지켜봄.. 궁금함.. 계속 서 있음) +이 병장: 김 일병, 언제 버리러 가는거야? +김 일병: (아무런 일도 하지 않으며 말한다) 잘 모르겠습니다. 뭐 전화오면 박 상병님께서 알려주시지 않겠습니까? +이 병장: 흠.. 폐급인가? +``` + +* Non-blocking & Synchronous +``` +김 일병 : 박 상병님, 오늘 짬통 언제 버리러 갑니까? +박 상병 : 있어봐, 중대 운전병에게 물어볼게. +김 일병 : 넵! +박 상병 : (수고하십니다 XX대대 상병 박공군입니다) +김 일병 : 연락 되셨습니까? +박 상병 : 이병이 받던데. 좀 이따 해볼게. +김 일병 : 연락 되셨습니까? +박 상병 : 운전병 제초하러 갔대. 나중에 전화준댄다. +이 병장 : 김 일병, 언제 버리러 간대? +김 일병 : 하.. 조금 이따 연락 주신다고 하는데 저도 진짜 궁금합니다. 일단 저는 화장실 청소 좀 하고 있겠습니다. +이 병장 : 그래? 알겠어. 박 상병이 전화 오면 알려주겠지. 조금 이따 물어보면 될 거 같아. +김 일병 : (다른 일 보다가 물어본다) 연락 되셨습니까? +박 상병 : ㅅㅂ 왜 자꾸 물어보냐 너 폐급이냐? 아직 전화 안왔다니까; +``` + +* Non-blocking & Asynchronous +``` +김 일병 : 박 상병님, 오늘 짬통 언제 버리러 갑니까? +박 상병 : 있어봐, 중대 운전병에게 물어볼게. +김 일병 : 넵! +박 상병 : (수고하십니다 XX대대 상병 박공군입니다) +박 상병 : 오늘 9시에 간댄다. 준비하자. +김 일병 : 넵! 짬통 일병들이랑 옮기고 있겠습니다. +``` + +#### 정리 +* Blocking/NonBlocking + * Blocking/NonBlocking은 호출되는 함수가 바로 리턴하느냐 마느냐가 관심사다. + * 호출된 함수가 바로 리턴해서 호출한 함수에게 제어권을 넘겨주고, 호출한 함수가 다른 일을 할 수 있는 기회를 줄 수 있으면 NonBlocking이다. + * 그렇지 않고 호출된 함수가 자신의 작업을 모두 마칠 때까지 호출한 함수에게 제어권을 넘겨주지 않고 대기하게 만든다면 Blocking이다. + +* Synchronous/Asynchronous + * Synchronous/Asynchronous는 호출되는 함수의 작업 완료 여부를 누가 신경쓰냐가 관심사다. + * 호출되는 함수에게 callback을 전달해서, 호출되는 함수의 작업이 완료되면 호출되는 함수가 전달받은 callback을 실행하고, 호출하는 함수는 작업 완료 여부를 신경쓰지 않으면 Asynchronous다. + * 호출하는 함수가 호출되는 함수의 작업 완료 후 리턴을 기다리거나, 또는 호출되는 함수로부터 바로 리턴 받더라도 작업 완료 여부를 호출하는 함수 스스로 계속 확인하며 신경쓰면 Synchronous다. + +### 추가 설명 +* Blocking 방식은 요청하고 응답 올때까지 기다리는 방식이고, Non-Blocking 방식은 요청하고 딴 일하다 나중에 응답신호가 오면 결과를 읽어 처리하는 방식이다. +* 동기방식은 요청자와 제공자사이에 계속 Connection이 맺어져 있어야 하고, 비동기방식은 Connection은 끊어지고 서로간에 이벤트를 통해 통신하는 방식이다. +* 비동기방식은 요청자와 제공자 사이에 Message Broker라는 또 다른 서비스가 중계해주지만, 동기 방식은 요청자 어플리케이션에 비동기 처리를 하는 로직이 있다. +* 최근 흔히 사용하는 REST API는 동기 방식이고 보통 Non-Blocking방식으로 통신한다. +* Frontend와 backend사이는 거의 대부분 동기+non-blocking 방식으로 구현한다. +* 비동기방식 패턴 중 제일 대표적인 것이 Publish/Subscribe (또는 Producer-Consumer) 패턴이다. + * Publisher인 유튜버들은 구독을 요청할 수 있는 채널을 만들고, 그 채널에 동영상을 계속 publishing해둔다. + * Subscriber인 사용자가 특정 유튜브채널을 구독 신청하면 새로운 동영상이 업로드 될때 첫화면에 추천동영상으로 받아보거나 모바일앱 알림 등으로 받아 볼 수 있게 된다. + * 즉, 사용자는 구독만 해놓고 있으면 새 동영상 올라올때까지 Youtube에 머물러 있을 필요가 없다. + * 비동기 메시징 방식은 추후 CS 스터디 주제로 발제할 생각이다. + * 이런 비동기 방식을 사용하는 이유는 큰 서비스를 이루는 마이크로서비스 중 하나가 실패해도 전체적인 서비스는 그대로 진행되도록 하기 위함이다. + * 예를 들어 쇼핑몰 상품 주문 시 주문서비스, 결제서비스, 배송서비스가 필요한데 동기방식으로 하면 결제나 배송 서비스에 문제가 생기면 상품 주문은 실패하게 된다. + * 그러나 비동기방식을 사용하면 Queue에 처리해야할 메시지가 있기 때문에 일시적 장애가 발생해도 복구가 되면 처리 가능하다. 따라서 상품 주문은 어떠한 경우에도 정상적으로 처리될 수 있게 된다. +* 일반적으로 Front와 Backend 서비스간에는 동기방식을 사용하고, backend의 서비스들간에는 비동기방식을 사용한다. +* 또한 데이터 조회 서비스는 동기방식을 사용하고, 데이터 변경 서비스는 비동기방식을 사용한다. + +### Spring WebFlux란 무엇일까? +* Non-blocking을 통해서 적은 수의 리소스로 동시성을 다룰 수 있게 해주는 프레임워크이다. +* 우리가 Spring MVC와 RDBMS를 사용하고 있으면 Blocking I/O를 사용하고 있는 것이다. +* Application에서 I/O 요청을 한 후 완료되기 전까지는 Application이 Block이 되어 다른 작업을 수행할 수 없다. 이는 해당 자원이 효율적으로 사용되지 못하고 있음을 의미한다. +* 물론, Blocking 방식임에도 불구하고 마치 Block이 안된듯이 동작하는 것처럼 보인다. 이는 멀티 쓰레드 기반의 방식이기 때문이다. 정확히는, 하나의 쓰레드가 블록되는 순간 다른 쓰레드가 동작하도록 함으로써 블록 문제를 해결하였다. +* 하지만 쓰레드 간의 Context Switching 등의 비용이 존재하므로, 여러 개의 I/O를 동시다발적으로 효율적인 처리를 하려면 논블로킹으로 처리해야만 한다. + +#### Blocking I/O 예시: RestTemplate +* RestTemplate은 Multi-Thread와 Blocking방식을 사용한다. +* Thread pool은 요청자 어플리케이션 구동시에 미리 만들어 놓는다. +* Request는 먼저 Queue에 쌓이고 가용한 스레드가 있으면 그 스레드에 할당되어 처리된다. +* 즉, 1 요청 당 1 스레드가 할당됩니다. +* 각 스레드에서는 Blocking방식으로 처리되어 응답이 올 때까지 그 스레드는 다른 요청에 할당될 수 없다. +* 아래는 RestTemplate을 Connection Pool에 Spring Bean으로 등록하기 위한 예제이다. + * 요청 당 20개의 RestTemplate client를 만들고, 최대 50개까지 증가할 수 있도록 했다. + +```java= +@Configuration +public class RestTemplateConfig { + public RestTemplate getRestTemplate(int defaultMaxPerRoute, int maxTotal) { + PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(); + connManager.setDefaultMaxPerRoute(defaultMaxPerRoute); + connManager.setMaxTotal(maxTotal); + + HttpClient client = HttpClientBuilder.create().setConnectionManager(connManager).build(); + + HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(client); + factory.setConnectTimeout(3000); + factory.setReadTimeout(3000); + + return new RestTemplate(factory); + + } + + @Bean + public RestTemplate coffeeRestTemplate() { + return getRestTemplate(20, 50); + } +} +``` +* 요청을 처리할 스레드가 있으면 아무런 문제가 없지만, 스레드가 다 차는 경우 이후의 요청은 Queue에 대기하게 된다. +* 대부분의 문제는 네트워킹이나 DB와의 통신에서 생기는데 이런 문제가 여러 스레드에서 발생하면 가용한 스레드수가 현저하게 줄어들게 되고, 결국 전체 서비스는 매우 느려지게 된다. +* RestTemplate을 이용하여 API 중 응답 시간이 약 3초 정도 걸리는 요청을 3번 반복하는 예제를 제시한다. +```java= +@Test +public void blocking() { + final RestTemplate restTemplate = new RestTemplate(); + + final StopWatch stopWatch = new StopWatch(); + stopWatch.start(); + + for (int i = 0; i < 3; i++) { + final ResponseEntity response = + restTemplate.exchange(THREE_SECOND_URL, HttpMethod.GET, HttpEntity.EMPTY, String.class); + assertThat(response.getBody()).contains("success"); + } + + stopWatch.stop(); + + System.out.println(stopWatch.getTotalTimeSeconds()); +} +``` +* Spring의 HTTP 요청 라이브러리인 RestTemplate을 사용하여 3초가 걸리는 API를 3번 호출하였다. 결과는 9.xx초가 나온다. 이유는 I/O가 요청 중일 때에는 아무 작업도 할 수 없기 때문이다. + +#### Non-Blocking I/O: WebClientSpring WebClient +* Spring WebClient는 Single Thread와 Non-Blocking방식을 사용한다. +* Core 당 1개의 Thread를 이용한다. +![](https://i.imgur.com/7MP2vt0.png) + + +[그림출처](https://luminousmen.com/post/asynchronous-programming-blocking-and-non-blocking) + +* 각 요청은 Event Loop내에 Job으로 등록이 된다. +* Event Loop는 각 Job을 제공자에게 요청한 후, 결과를 기다리지 않고 다른 Job을 처리한다. Event Loop는 제공자로부터 callback으로 응답이 오면, 그 결과를 요청자에게 제공한다. +* WebClient는 이렇게 이벤트에 반응형으로 동작하도록 설계되었다고 한다. +* 아래 예제는 위에서 제시한 요청시간이 약 3초 정도 걸리는 동일한 API를 가져왔다고 가정한 것이다. +```java= +@Test +public void nonBlocking3() throws InterruptedException { + final StopWatch stopWatch = new StopWatch(); + stopWatch.start(); + for (int i = 0; i < LOOP_COUNT; i++) { + this.webClient + .get() + .uri(THREE_SECOND_URL) + .retrieve() + .bodyToMono(String.class) + .subscribe(it -> { + count.countDown(); + System.out.println(it); + }); + } + + count.await(10, TimeUnit.SECONDS); + stopWatch.stop(); + System.out.println(stopWatch.getTotalTimeSeconds()); +} +``` +* WebFlux에서 제공하는 WebClient를 사용해서 위와 동일하게 3초가 걸리는 API를 호출하였다. for문 안의 변수인 LOOP_COUNT는 100으로 코드상에서 설정되어있다. 3초 걸리는 API를 100번 호출한다 하더라도 3.xx초 밖에 걸리지 않는다. +* 만약, Blocking을 위처럼 많은 요청을 동시에 처리하려면 그 만큼의 Thread이 생성되어야 한다. 그러나 이렇게 처리한다 해도 Context Swiching에 의한 오버헤드가 존재할 것이다. + +### 성능비교 +* 아래는 RestTemplate을 사용하는 Spring Boot1과 WebClient를 사용하는 Spring Boot2의 성능비교 결과이다. +* ![](https://i.imgur.com/ACQsu6g.png) + +* 1000명까지는 비슷하지만 동시사용자가 늘수록 RestTemplate은 급격하게 느려지는것을 볼 수 있다. +[그림출처](https://alwayspr.tistory.com/44) +* Spring 커뮤니티에서는 RestTemplate을 이미 Depreciated시키고 WebClient를 사용할것을 강력히 권고하고 있다. +``` +NOTE: As of 5.0 this class is in maintenance mode, +with only minor requests for changes and bugs to be accepted going forward. +Please, consider using the org.springframework.web.reactive.client.WebClient +which has a more modern API and supports sync, async, and streaming scenarios. +``` + +## 참고한 링크 +* https://velog.io/@codemcd/Sync-VS-Async-Blocking-VS-Non-Blocking-sak6d01fhx +* https://devahea.github.io/2019/04/21/Spring-WebFlux%EB%8A%94-%EC%96%B4%EB%96%BB%EA%B2%8C-%EC%A0%81%EC%9D%80-%EB%A6%AC%EC%86%8C%EC%8A%A4%EB%A1%9C-%EB%A7%8E%EC%9D%80-%ED%8A%B8%EB%9E%98%ED%94%BD%EC%9D%84-%EA%B0%90%EB%8B%B9%ED%95%A0%EA%B9%8C/ +* https://happycloud-lee.tistory.com/220 +* https://happycloud-lee.tistory.com/154?category=902418 +* https://musma.github.io/2019/04/17/blocking-and-synchronous.html +* http://homoefficio.github.io/2017/02/19/Blocking-NonBlocking-Synchronous-Asynchronous/ From 42900acb0415fb75475b998092a06151c072361a Mon Sep 17 00:00:00 2001 From: Jin Hyung Park Date: Mon, 16 Aug 2021 21:13:33 +0900 Subject: [PATCH 110/142] =?UTF-8?q?feat:=20=EB=84=A4=ED=8A=B8=EC=9B=8C?= =?UTF-8?q?=ED=81=AC=20CORS=20=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- network/cors/sigrid/README.md | 141 ++++++++++++++++++++++++++++++++++ 1 file changed, 141 insertions(+) create mode 100644 network/cors/sigrid/README.md diff --git a/network/cors/sigrid/README.md b/network/cors/sigrid/README.md new file mode 100644 index 0000000..601de34 --- /dev/null +++ b/network/cors/sigrid/README.md @@ -0,0 +1,141 @@ +# 네트워크: CORS란 무엇인가 +## CORS: Cross-Origin Resource Sharing +### Origin +* URL 구조에서 Protocol + Host + Port를 합친 것을 의미함 +```console +location.source +> https://hackmd.io +``` +* 간단한 퀴즈: 다음 중 같은 출처가 아닌 것은? + * ```https://hackmd.io/about```: 같은 출처 + * ```https://hackmd.io:32/about```: 다른 출처(Port 다름) + * ```http://hackmd.io```: 다른 출처(Protocol 다름) + +### Same-Origin Policy +* Postman으로 API를 호출하면 잘 되는데, 브라우저로 호출하면 CORS 에러가 나는 이유는 무엇일까? +* 브라우저가 동일 출처 정책(Same Origin Policy)를 준수하기 때문에 그렇다. +* 예를 들어 hackmd.io 사이트에서 medium.com의 API를 호출하면 서로 다른 출처이므로 CORS 에러가 발생할 수 있다. +* 동일 출처 정책은 XSS나 XSRF 등의 보안 취약점을 노린 공격을 방어할 수 있다. +* 하지만 외부 리소스를 사용해야 하는 경우는 매우 많다. SOP 정책의 예외 사항이 CORS라고 할 수 있다. + +### CORS 동작 원리 +* Simple Request와 Preflight Request가 있지만, 주로 Preflight Request 방식이 선호된다. + +![](https://i.imgur.com/Wv9msLm.png) +* Preflight 요청은 실제 리소스를 요청하기 전에 OPTIONS라는 메서드를 통해 실제 요청을 전송할지 판단한다. +* OPTIONS 메서드로 서버에 예비 요청을 먼저 보내고, 서버는 이 예비 요청에 대한 응답으로 Access-Control-Allow-Origin 헤더를 포함한 응답을 브라우저에 보낸다. +* 브라우저는 단순 요청과 동일하게 Access-Control-Allow-Origin 헤더를 확인해서 CORS 동작을 수행할지 판단한다. + +### CORS 에러 해결 방법 +* 서버에서 ```Access-Control-Allow-Origin``` 헤더를 포함한 응답을 브라우저에 보내는 방식으로 CORS 에러를 해결할 수 있다. +* Node.js 기준으로 cors라는 라이브러리가 있고, Spring Boot에서는 WebMvcController를 설정해주면 된다. + +#### Access-Control-Allow-Origin: | * +* 헤더가 작성된 링크만 브라우저가 접근할 수 있도록 설정할 수 있다. +* 사용 예시 +``` +Access-Control-Allow-Origin: https://medium.com +``` +``` +Access-Control-Allow-Origin: * // 와일드 카드를 쓰면 모든 사이트 다 된다 +``` +* 서버에서 아래와 같이 응답 헤더를 설정해서 보내주면 된다. +```javascript= +router.options('/cors', (req, res, next) => { + res.set('Access-Control-Allow-Origin', '*') + res.send() +}) +router.put('/cors', (req, res, next) => { + res.set('Access-Control-Allow-Origin', '*') + res.send() +}) +``` +#### Access-Control-Allow-Methods: [, ]* +* 리소스 접근을 허용하는 HTTP 메서드를 지정해 주는 헤더이다. +```javascript= +router.options('/cors', (req, res, next) => { + res.set('Access-Control-Allow-Origin', '*') + res.set('Access-Control-Allow-Methods', req.get('Access-Control-Request-Method')) + res.send() +}) +router.put('/cors', (req, res, next) => { + res.set('Access-Control-Allow-Origin', '*') + res.send() +}) +``` +#### Access-Control-Expose-Headers: [, ]* +* 서버에서 응답 헤더에 Access-Control-Expose-Headers를 추가해 줘야 브라우저의 자바스크립트에서 헤더에 접근할 수 있다. +```javascript= +router.options('/cors', (req, res, next) => { + res.set('Access-Control-Allow-Origin', '*') + res.set('Access-Control-Allow-Methods', req.get('Access-Control-Request-Method')) + res.send() +}) +router.put('/cors', (req, res, next) => { + res.set('Access-Control-Allow-Origin', '*') + res.set('Access-Control-Expose-Headers', 'X-Custom-Beomy') + res.set('X-Custom-Beomy', 'Bemoy') + res.send() +}) +``` + +#### Access-Control-Allow-Headers: [, ]* +* 브라우저에서 보내는 요청 헤더에 포함된 Access-Control-Request-Headers 헤더에 대한 응답 결과이다. +```javascript= +router.options('/cors', (req, res, next) => { + res.set('Access-Control-Allow-Origin', '*') + res.set('Access-Control-Allow-Methods', req.get('Access-Control-Request-Method')) + res.set('Access-Control-Allow-Headers', req.get('Access-Control-Request-Headers')) + res.send() +}) +router.put('/cors', (req, res, next) => { + res.set('Access-Control-Allow-Origin', '*') + console.log(req.get('X-Custom-Request')) // Beomy + res.send() +}) +``` +#### Access-Control-Max-Age: +* preflight 요청 결과를 캐시 할 수 있는 시간을 나타낸다. +* 아래와 같이 초 단위로 캐시 시간을 설정한다. +``` +Access-Control-Max-Age: 60 +``` +* 위의 코드는 60초 동안 preflight 요청을 캐시 하는 코드이다. +* 60초 동안 OPTIONS 메서드를 사용하는 예비 요청을 보내지 않습니다. +```javascript= +router.options('/cors', (req, res, next) => { + res.set('Access-Control-Allow-Origin', '*') + res.set('Access-Control-Allow-Methods', req.get('Access-Control-Request-Method')) + res.set('Access-Control-Max-Age', 60) + res.send() +}) +router.put('/cors', (req, res, next) => { + res.set('Access-Control-Allow-Origin', '*') + res.send() +}) +``` +#### Access-Control-Allow-Credentials: true +* 자바스크립트 요청에서 credentials가 include일 때 요청에 대한 응답을 할 수 있는지를 나타낸다. +* false로 설정해 주고 싶을 경우에는 헤더를 생략하면 된다. +```javascript= +router.options('/cors', (req, res, next) => { + res.set('Access-Control-Allow-Origin', 'https://www.google.com') + res.set('Access-Control-Allow-Methods', req.get('Access-Control-Request-Method')) + res.set('Access-Control-Allow-Credentials', true) + res.send() +}) +router.put('/cors', (req, res, next) => { + res.set('Access-Control-Allow-Origin', 'https://www.google.com') + res.set('Access-Control-Allow-Credentials', true) + res.send() +}) +``` +* Access-Control-Allow-Credentials: true 추가 뿐만 아니라, Access-Control-Allow-Origin 헤더도 와일드카드가 아닌 출처를 명시해주어야 한다. + +## 프록시 서버 +* 프론트엔드와 백엔드 사이에 프록시 서버를 두어서 CORS를 해결할 수 있다. +* 개발 환경에서는 Webpack Dev Server 등의 라이브러리를 사용하여 프록시 설정을 할 수 있다. + +## 참고 링크 +* https://beomy.github.io/tech/browser/cors/ +* https://evan-moon.github.io/2020/05/21/about-cors/ From 87195a50a75f303afbda356c32eef7c49c2941b8 Mon Sep 17 00:00:00 2001 From: 102092 Date: Tue, 17 Aug 2021 23:00:37 +0900 Subject: [PATCH 111/142] Remove misplace file --- database/mysql-query-plan/README.md | 96 ----------------------------- 1 file changed, 96 deletions(-) delete mode 100644 database/mysql-query-plan/README.md diff --git a/database/mysql-query-plan/README.md b/database/mysql-query-plan/README.md deleted file mode 100644 index 6baa63a..0000000 --- a/database/mysql-query-plan/README.md +++ /dev/null @@ -1,96 +0,0 @@ -### 쿼리 플랜이란? - -SQL을 처리하는 최저비용의 경로를 생성해주는 DBMS 내부 핵심엔진인 쿼리 옵티마이저가 쿼리를 수행할 때 생성한 최적의 처리 경로를 쿼리 플랜이라고 합니다. - -MySQL에서는 실행 할 쿼리문 앞에 explain 키워드를 이용해 쿼리플랜에 대한 정보를 살펴 볼 수 있습니다. 쿼리 플랜을 사용하면 이슈가 발생하는 쿼리에 대한 이해를 도울 뿐만 아니라, 어떻게 최적화 시킬지에 대한 인사이트를 제공합니다. - -### 사용 방법 - -```sql -EXPLAIN [EXTENDED] SELECT ... FROM ... WHERE ... -``` - -[https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdbbqa9%2FbtqD8PMH5VI%2FzlEXJRccyWVzs9eFeLK9A1%2Fimg.png](https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdbbqa9%2FbtqD8PMH5VI%2FzlEXJRccyWVzs9eFeLK9A1%2Fimg.png) - -### 항목 설명 - -- id: select 아이디로 SELECT를 구분하는 번호 -- select_type: select에 대한 타입 -- table: 참조하는 테이블 -- type: 조인 혹은 조회 타입 -- possible_keys: 데이터를 조회 할 때 DB에서 사용 할 수 있는 인덱스 리스트 -- key: 실제로 사용 할 인덱스 -- key_len: 실제로 사용 할 인덱스의 길이 -- ref: Key 안의 인덱스와 비교하는 컬럼(상수) -- rows: 쿼리 실행 시 조사하는 행 수립 - -### id - -행이 어떤 SELECT 구문을 나타내는 지를 알려주는 것으로 구문에 서브 쿼리나 UNION이 없다면 SELECT는 하나밖에 없기 때문에 모든 행에 대해 1이란 값이 부여되지만 이외의 경우에는 원 구문에서 순서에 따라 각 SELECT 구문들에 순차적으로 번호가 부여된다. - -### select_type - -select 문의 타입 - -- SIMPLE: 단순 select (union이나 서브쿼리가 없는 SELECT문) -- PRIMARY: 서브쿼리를 사용 할 경우 서브쿼리의 외부에 있는 쿼리(첫 번째 쿼리) UNION을 사용 할 경우 UNION의 첫 번째 SELECT 쿼리 -- UNION: UNION 쿼리에서 Primary를 제외한 나머지 SELECT -- DEPENDENT UNION: UNION과 동일하나, 외부쿼리에 의존적임(값을 공급받음) -- UNION RESULT: UNION 쿼리의 결과물 -- SUBQUERY: 서브 쿼리 또는 서브 쿼리를 구성하는 여러 쿼리 중 첫 번째 SELECT문 -- DEPENDENT SUBQUERY: 서브쿼리와 동일하나, 외부 쿼리에 의존적임(값을 공급 받음) -- DERIVED: SELECT로 추출된 테이블(FROM 절에서의 서브쿼리 또는 Inline View) -- UNCACHEABLE SUBQUERY: 서브쿼리와 동일하지만 공급되는 모든 값에 대해 서브 쿼리를 재처리. 외부 쿼리에서 공급되는 값이 동일하더라도 캐쉬된 결과를 사용 할 수 있음 -- UNCACHEABLE UNION: UNION과 동일하지만 공급되는 모든 값에 대하여 UNION 쿼리를 재처리 - -### table - -행이 어떤 테이블에 접근하는지를 보여주는 것으로 대부분의 경우 테이블 이름이나 SQL에서 지정된 별명 같은 값을 나타낸다. - -### type - -- system: 테이블에 단 한 개의 데이터만 있는 경우 -- const: SELECT에서 Primary Key 혹은 Unique Key를 상수로 조회하는 경우로 많아야 한 건의 데이터만 있음 -- eq_ref: 조인 할 때 Primary Key -- ref: 조인 할 때 Primary Key 혹은 Unique Key가 아닌 Key로 매칭하는 경우 -- ref_or_null: ref와 같지만 null이 추가되어 검색되는 경우 -- index_merge: 두 개의 인덱스가 병합되어 검색이 이루어지는 경우 -- unique_subquery: 다음과 같이 IN 절 안에 서브쿼리에서 Primary Key가 오는 특수한 경우 - - SELECT * FROM tab01 WHERE col01 IN (SELECT Primary Key FROM table01); -- index_subquery: unique_subquery와 비슷하나 Primary Key가 아닌 인덱스인 경우 - - SELECT * FROM tab01 WHERE col01 IN (SELECT key01 FROM tab02); -- range: 특정 범위 내에서 인덱스를 사용하여 원하는 데이터를 추출하는 경우로, 데이터가 방대하지 않다면 단순 SELECT 문에서는 나쁘지 않음 -- index: 인덱스를 처음부터 끝까지 찾아서 검색하는 경우로, 일반적으로 인덱스 풀스캔이라고 함 -- all: 테이블을 처음부터 끝까지 검색하는 경우 일반적으로 테이블 풀스캔이라고 함 - -### possible_keys - -쿼리에서 접근하는 컬럼들과 사용된 비교 연산자들을 바탕으로 어떤 인덱스를 사용 할 수 있는지를 표시해준다. - -### key - -테이블에 접근하는 방법을 최적화하기 위해 어떤 인덱스를 사용하기로 결정했는지를 나타낸다. - -### key_len - -MySQL이 인덱스에 얼마나 많은 바이트를 사용하고 있는지를 보여준다. MySQL에서 인덱스에 있는 컬럼들 중 일부만 사용한다면 이 값을 통해 어떤 컬럼이 사용되는지를 계산 할 수 있다. - -### ref - -키 컬럼에 나와있는 인덱스에서 값을 찾기위해 선행 테이블의 어떤 컬럼이 사용되었는지를 나타낸다. - -### rows - -원하는 행을 찾기 위해 얼마나 많은 행을 읽어야 할지에 대한 예측값을 의미한ㄸ. - -### extra - -- using index: 커버링 인덱스라고 하며 인덱스 자료 구조를 이용해서 데이터를 추출 -- using where: where 조건으로 데이터를 추출. type이 ALL 혹은 index 타입과 함께 표현되면 성능이 좋지 않다는 의미 -- using filesort: 데이터 정렬이 필요한 경우로 메모리 혹은 디스크 상에서의 정렬을 모두 포함. 결과 데이터가 많은 경우 성능에 직접적인 영향을 줌 -- using temporary: 쿼리 처리 시 내부적으로 tempory table이 사용되는 경우를 의미함 - -### 출처 - -- [https://nomadlee.com/mysql-explain-sql/](https://nomadlee.com/mysql-explain-sql/) -- [https://ibks-platform.tistory.com/374](https://ibks-platform.tistory.com/374) \ No newline at end of file From bd6e80dde06ae8a97f68ea89b28dc76f0cd95e46 Mon Sep 17 00:00:00 2001 From: Jin Hyung Park Date: Thu, 26 Aug 2021 00:57:41 +0900 Subject: [PATCH 112/142] =?UTF-8?q?feat:=20TCP=20Keep-Alive=20=EB=84=A4?= =?UTF-8?q?=ED=8A=B8=EC=9B=8C=ED=81=AC=20=ED=95=99=EC=8A=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- network/tcp-keep-alive/sigrid/README.md | 180 ++++++++++++++++++++++++ 1 file changed, 180 insertions(+) create mode 100644 network/tcp-keep-alive/sigrid/README.md diff --git a/network/tcp-keep-alive/sigrid/README.md b/network/tcp-keep-alive/sigrid/README.md new file mode 100644 index 0000000..4827f32 --- /dev/null +++ b/network/tcp-keep-alive/sigrid/README.md @@ -0,0 +1,180 @@ +# TCP Keep-Alive란? +* 인터넷에 연결된 컴퓨터 간의 정보 를 안정적이고 순서대로, 에러없이 통신할 수 있게 해주는 것이 TCP +* TCP 기반의 통신에서 세션을 어떻게 유지하는 가에 대한 문제이다. +* TCP Keep-Alive란 두 종단(end-point)간 맺어진 세션을 지속적으로 유지해서 통신이 일어날 때마다 이미 **존재하고 있는** 세션을 이용하도록 한다. + +## TCP three handshaking +![](https://i.imgur.com/zwBoGxw.png) +* TCP는 **연결 지향적** 이라고 하는데 이름부터가 transmission connection protocol이다. + +### STEP 1 + +![](https://i.imgur.com/3Rdep2h.png) + +* Client는 SYN 패킷을 보낸다. + * SYN, ACK 패킷에는 모두 ISN이라고 하는 initial sequence number가 있는데, 이는 random하게 구성된다. + * 서버에서 SYN+ACK 패킷을 보내기를 기다리는 상태, 곧 SYN_SENT 상태가 된다. + * SYN(Synchronization) : 연결 요청, 세션을 설정하는데 사용되며 초기에 Sequence Number를 보냄 + +### STEP 2 +![](https://i.imgur.com/aDwwCsa.png) + +* Server는 Listen 상태로 Port 서비스가 가능한 상태여야 한다. +* Server는 연결 요청을 받게 되고, 연결 수락을 위해 ACK(a+1) + SYN(b) 패킷을 보낸다. + * 이 때 b는 Server의 Sequence Number를 뜻하고, ACK를 보낼때 Client로 부터 받은 Sequence Number인 a에 +1 한 값을 보낸다. + * ACK(Acknowlegdement) : 승인을 뜻한다. + +### STEP 3 +![](https://i.imgur.com/lPZnevo.png) +* Client는 SYN(b)를 받아 Server에게 ACK(b+1) 패킷을 보낸다. + +### Wireshark로 보기 +* 위 3번의 과정을 거치게 되면 Client와 Server 간의 연결이 성립(Establish)이 되어 Server로 부터 데이터를 받게 된다. + +![](https://i.imgur.com/Z8HXvb3.png) + +* Client가 Server에게 SYN(0)을 보낸다. +* Server는 Client에게 ACK(1) + SYN(0)을 보낸다. +* Client는 Server에게 ACK(1)을 보낸다. +* 연결이 성립되었으므로 4번째 줄을 보면 Client가 Server에게 HTTP 프로토콜로 ```/wp-admin/``` 의 정보를 요청한다. + +[참고](https://lactea.kr/entry/Network-%E2%80%93-tcp-%EC%97%B0%EA%B2%B0-%EB%B6%84%EC%84%9D#recentComments) + +### 연결을 해제하는 four way hand shake +![](https://i.imgur.com/Q2ssguZ.png) +* ESTABLISHED 상태가 된 연결을 대상으로 한다. +* TCP 커넥션 종료는 클라이언트와 서버 어느 쪽에서도 할 수 있기 때문에, 클라이언트와 서버로 나누지 않고 active close와 passive close로 나눈다. + * Active close: TCP 연결 해제 요청한 쪽, 그러니까 트래픽을 전송(request)하고 정상적으로 전송 되었으면 연결을 끊는 쪽 + * Passive close: TCP 연결 해제 요청을 받은 쪽, 트래픽을 받는 쪽(api 서버라고 치면 클라이언트에게 응답을 주는 쪽) +* 아래의 예시에서는 Client가 Active close, Server가 Passive close라고 가정하자. +1. Client가 연결을 종료 하겠다고 FIN 패킷을 보낸다. (Client는 FIN_WAIT1 상태) +2. Server는 FIN을 받고 확인 메시지인 ACK를 보낸다. (Server는 그 후 데이터를 모두 보낼 때까지 잠깐 TIME_OUT or CLOSE_WAIT 상태가 되며, Client는 FIN_WAIT2 상태가 된다) +3. 데이터를 다 보냈을 경우, Server는 연결이 종료 되었다고 FIN 패킷을 Client에게 보낸다. (Server는 LAST_ACK 상태가 된다) +4. Client는 FIN 패킷을 받고 확인 메시지인 ACK를 보낸다. (Client는 아직 서버로 부터 받지 못한 데이터가 있을 것을 대비해 일정 시간 동안 세션을 남겨놓고 패킷을 기다리는 과정을 거치기 위해 TIME_WAIT 상태가 된다) +5. Server는 소켓 연결을 close 한다. + +[참고 1](https://tech.kakao.com/2016/04/21/closewait-timewait/) +[참고 2](https://smjeon.dev/etc/tcp-state/) + +### 최종 정리 +![](https://i.imgur.com/o8n4nbc.png) + + +### ISN은 Randomnize 한 번호이다 +* Wireshark가 위에서는 ```relatively``` sequence한 번호를 보여주기는 하는데 이는 그냥 편의를 위해서 그렇게 표시한 것이다. +* 실제로는 32비트로 random한 난수를 사용하는데, 그 이유는 서버 측에서 SYN을 보고 패킷을 구분하는데 난수가 아닌 순차적인 number로 전송된다면 이전의 connection에서 온 패킷으로 오해할 수 있는 여지가 있어서 그렇다고 한다. +* Connection을 맺을 때 사용하는 포트(port)는 유한 범위 내에서 사용하고 시간이 지남에 따라 재사용된다. 따라서 두 통신 호스트가 과거에 사용된 포트 번호 쌍을 사용하는 가능성이 존재한다. +* 이는 실제로 TCP Sequence Prediction Attacks라고 하는 해킹 기법과도 연관이 있어서 난수를 사용해야 한다고 한다. [참고](https://github.com/dreamgonfly/TIL/blob/master/TCP-Sequence-Prediction-Attack.md#why-is-initial-sequence-numberisn-random) + +``` +In the first two steps of the 3-way handshake, both computers exchange an initial sequence number (ISN). This number can be arbitrary, and should in fact be unpredictable to defend against TCP sequence prediction attacks. +``` + +[참고](https://packetlife.net/blog/2010/jun/7/understanding-tcp-sequence-acknowledgment-numbers/) + +## 그런데 매번 handshaking 하면 불편하다 +* 매 통신마다 3 way handshaking을 하고 있으면 매우 불편할 것이다. 특히 통신량이 많고 지속적인 경우라면 더더욱 그렇다. +* 통신이 지속적으로 이뤄진다면 기존에 성사된 세션을 유지할 수 있는 방법은 없을까 고민할 수 있다. 그것이 바로 TCP Keep Alive이다. + +![](https://i.imgur.com/DZgNegh.png) +* 위의 그림을 보면 TCP Keepalive는 일정 시간이 지나면 연결된 세션의 두 종단이 서로 살아 있는지 확인하는 아주 작은 byte의 패킷을 보낸다. +* 연결을 유지하고 싶은 쪽에서 보내면 되니까 클라이언트던 서버던 한 쪽에서 보내기만 하면 된다. +* 현재 네트워크 소켓의 keepalive 설정이 어떤지 확인하고 싶으면 ```netstat``` 명령어를 활용하면 된다. + +``` +# netstat -napo +root@server1:~# netstat -napo +Active Internet connections (servers and established) +Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name Timer +tcp 0 0 0.0.0.0:111 0.0.0.0:* LISTEN 576/rpcbind off (0.00/0/0) +tcp 0 0 0.0.0.0:465 0.0.0.0:* LISTEN 1322/master off (0.00/0/0) +... +tcp 0 0 10.0.2.15:22 10.0.2.2:51040 ESTABLISHED 1787/sshd: vagrant keepalive (7198.14/0/0) +... +udp 0 0 0.0.0.0:111 0.0.0.0:* 576/rpcbind off (0.00/0/0) +.... +``` +* 제일 마지막 열에 있는 Timer 항목을 통해서 현재 소켓에 설정된 타이머 값을 볼 수 있다. ESTABLISHED 상태의 소켓에서는 Keepalive 타이머를 확인할 수 있다. + * sshd 데몬이 사용하는 소켓에 keepalive 옵션이 켜져 있고 타이머가 70초 가량 남아있다. +* 해당 타이머의 시간이 다 되면 연결이 살아있는지를 확인하는 작은 패킷을 하나 보낸다. +* 대부분의 애플리케이션에서는 TCP Keepalive 기능을 제어할 수 있는 명령어를 제공하니까 이를 활용하면 되겠다. + +### 실제 서비스에서는 어떻게 활용할 수 있는가 +* DB 서버 한대와 애플리케이션 서버 한 대가 있다고 가정한다. +* 만약 DB 서버에서 설정된 iptables로 인해 FIN패킷을 받지 못해서, 클라이언트 입장에서는 DB서버와의 연결이 끊어졌는지 알 방법이 없다고 가정하자. +* 그렇다면 클라이언트 측 소켓은 여전히 ESTABLISHED로 연결이 지정되어 있을 것이다. +* 하지만 keepalive옵션을 활용한 소켓이기 때문에 keepalive 타이머에 설정된 일정 시간이 지나면 keepalive 패킷에 대한 응답을 받지 못했기 때문에 소켓이 종료된다. +* 이를 통해 TCP Keepalive를 활용하여 좀비 커넥션을 종료시킬 수 있다라고 하는 것이다. + +[참고](https://jihooyim1.gitbooks.io/linuxbasic/content/contents/08.html) + +### Case Study - MQ 서버와 로드 밸런서 +* 비동기적인 작업을 하기 위해서 메시지큐 서버를 이용한다고 해보자. 메시지큐 서버를 이중화하기 위하여 로드 밸런싱도 해본다고 쳐보자. +* 클라이언트는 여러 대의 MQ 서버 중 한 대에 붙어야 하는데, 만약 자기가 연결한 서버에 오류가 났다면 로드 밸런서에 의존해서 해당 오류를 deroute해야 한다. +![](https://i.imgur.com/g4FRmP1.png) +* 아무런 이슈없이 이중화까지 잘 동작할 것 같은 이 MQ구조에 어떤 문제가 있을까? + * 클라이언트에서는 간헐적으로 타임아웃이 발생하며, 서버에서는 사용하지 않는 것으로 보이는 소켓이 ESTABLISHED 상태로 유지되고 있다는 두 가지 이슈가 있다. +* 왜 이런 문제가 나타나는 것일까? + * 로드 밸런서는 클라이언트와 서버간 TCP handshake를 끝내고 정상적으로 맺어진 세션들을 세션 테이블에 저장한다. + * 그래서 두 종단 간에 세션이 정상적으로 맺어져 있음을 기억하고 클라이언트의 요청을 특정 서버로 보낼 수 있다. + * 로드 밸런서에는 Idle timeout기능이 있는데, 일정 시간동안 사용되지 않은 세션을 세션테이블에서 정리하는 기능이 있다. 그런데 로드 밸런서의 세션 테이블에서만 지워진다는 것이고 두 종단의 세션 테이블이 지워졌음을 알리는 역할은 하지 않는다. + * 만약 로드 밸런서의 idle timeout 에 걸리면 클라이언트와 서버는 알아채지 못하지만 둘 사이의 세션 정보는 로드 밸런서에서 사라지게 되는 것이다. + * 클라이언트는 요청을 보냈지만 제대로된 응답을 받지 못하고 RST 패킷("너 누구냐")을 받았기 때문에 TCP Handshake를 맺고 다시 요청을 보내야한다. + * 그리고 이때 소요되는 시간이 애플리케이션에서 설정한 타임아웃 임계치를 넘어가게 되면서 Timeout Exception을 경험하게 된다. + * 서비스의 특성상 사용자의 요청이 적은 새벽 시간대에는 맺어져 있는 세션으로 패킷이 흐르지 않을 가능성이 크며, 바로 이때 idle timeout에 걸려서 커넥션 풀로 열어놓은 세션들이 로드 밸런서에서 지워지는 일이 발생한다. + * 지워진 후에 클라이언트가 다시 한번 요청을 보내면 로드 밸런서는 자신에게 연결되어있는 서버 중 아무 서버에게나 이 패킷을 전달한다. (어디로 갈 지는 로드 밸런서의 밸런싱 정책에 따를 수밖에 없다) + * 아주 운좋게 기존에 연결된 서버에 패킷이 전달되면 문제가 없겠지만, 그렇지 않은 경우라면 서버쪽에서는 연결도 맺지 않은 클라이언트가 데이터를 쓰겠다고 요청하니 당연히 거부 의사를 밝히게 되고, 클라이언트는 타임아웃을 경험하게 된다. + * 그러면 클라이언트는 자신이 현재 관리하고 있는 커넥션 풀이 잘못되어 있음을 인지하고 새롭게 커넥션을 열어서 새로운 서버와 연결한다. + * 문제는 기존에 연결되어 있던 서버는 클라이언트의 이런 작업을 전혀 알 수 없기 때문에 계속해서 연결되어 있다고 착각하고, 이런 경우 들이 모여서 서버쪽에 다량의 좀비 커넥션이 남게 되는 것이다. +* 어떻게 해결할 수 있는가? + * 로드 밸런서의 Idle timeout에 걸리지 않도록 keepalive 관련 파라미터들을 수정해서 적용하면 지속적으로 세션을 유지할 수 있게 된다. + +[참고](https://jihooyim1.gitbooks.io/linuxbasic/content/contents/08.html) + +### 결론 +* TCP 종단간의 연결 유지를 위한 TCP Keepalive에 대해 살펴보았다. +* TCP Keepalive는 특히 네트워크 단절 등 여러가지 이유로 발생할 수 있는 좀비 커넥션을 방지하는데 큰 도움이 된다. +* TCP 환경은 언제든지 패킷 손실이 일어날 수 있으며 FIN패킷도 손실될 수 있다. +* 커널은 TCP keepalive라는 기능을 제공해서 종단 간의 세션을 유지하거나, 비정상적인 소켓이라고 판단 되면 정리할 수 있도록 도와준다. +* 다양한 애플리케이션들에서 TCP Keepalive를 지원하며, 필요하다고 판단되면 해당 애플리케이션에서 어떻게 TCP Keepalive 옵션을 켤 수 있는지 찾아서 설정해주어야 한다. + +## TCP Header +### Segments +* TCP 패킷을 '세그먼트' 라고 부른다. +### Source port, Destination port +* 세그먼트의 출발지와 목적지를 나타내는 필드로, 각각 16 bits 를 할당받는다. +* 이때 출발지와 목적지의 주소를 판별하기 위해서는 IP 주소와 포트 번호가 필요하다. TCP에서는 port number만 갖고 있다. IP 주소는 하위 계층 network에서 알려줄테니까... +### Sequence Number +* 시퀀스 번호는 전송하는 데이터의 순서를 의미하며, 32 bits를 할당받는다. +* 시퀀스 번호를 활용하여 수신자는 쪼개진 세그먼트의 순서를 파악하여 올바른 순서로 데이터를 재조립할 수 있게 된다. +* 송신자가 최초로 데이터를 전송할 때는 이 번호를 랜덤한 수로 초기화 한다. +* 이후 자신이 보낼 데이터의 1 bytes당 시퀀스 번호를 1씩 증가시키며 데이터의 순서를 표현하다 4,294,967,296를 넘어갈 경우 다시 0부터 시작한다. + +### Acknowledgement Number +* 승인 번호는 데이터를 받은 수신자가 예상하는 다음 시퀀스 번호를 의미하며, 32 bits를 할당받는다. +* 연결 설정과 연결 해제 때 발생하는 핸드쉐이크 과정에서는 ```상대방이 보낸 시퀀스 번호 + 1로 자신의 승인 번호```를 만든다. +* 실제로 데이터를 주고 받을 때는 ```상대방이 보낸 시퀀스 번호 + 자신이 받은 데이터의 bytes```로 승인 번호를 만든다. +* 만약, ```tcpdump```를 사용하여 패킷을 검사해보면 송신 측이 보낸 데이터의 길이만큼 수신 측의 승인 번호가 증가하는 모습을 확인할 수 있다. + +### Data Offset +* 전체 세그먼트 중에서 헤더가 아닌 데이터가 시작되는 위치가 어디부터인지를 표시한다. 32bit word 단위이다. 32bit 체계에서의 1 Word = 4 bytes를 의미하니까, 이 필드의 값에 4를 곱하면 세그먼트에서 헤더를 제외한 실제 데이터의 시작 위치를 알 수 있게 된다. + +### Flags +* ACK: Acknowledgment(승인 번호) 필드에 값이 채워져있음을 알리는 플래그. 이 플래그가 0이라면 승인 번호 필드 자체가 무시된다. +* RST: Reset 플래그. 이미 연결이 확립되어 ESTABLISHED 상태인 상대방에게 연결을 강제로 리셋해달라는 요청의 의미이다. +* SYN: Synchronize 플래그. 상대방과 연결을 생성할 때, 시퀀스 번호의 동기화를 맞추기 위한 세그먼트임을 의미한다. +* FIN: Finish 플래그. 상대방과 연결을 종료하고 싶다는 요청인 세그먼트임을 의미한다. + +### Window Size +* 윈도우 사이즈 필드에는 한 번에 전송할 수 있는 데이터의 양을 의미하는 값을 담는다. 2^16 = 65536 만큼 데이터를 표현할 수 있다. 이게 64KB인데 너무 작으니까, 그래서 비트를 왼쪽으로 시프트하는 방식으로 윈도우 사이즈의 최대 크기를 키울 수 있는 방식도 사용하고 있다고 한다. 몇 번 시프트할 지는 옵션 필드의 WSCALE 필드를 사용하여 표기한다고 한다. + +### Checksum +* 체크섬은 데이터를 송신하는 중에 발생할 수 있는 오류를 검출하기 위한 값이다. +* 수신 측은 데이터를 받으면 1의 보수를 취하지 않은 값인 10001010까지만 만든 다음, 이 값과 송신 측이 보낸 체크섬을 더해서 모든 비트가 1이라면 이 데이터가 정상이라고 판단할 수 있다. + +### Options +* 옵션 필드는 TCP의 기능을 확장할 때 사용하는 필드들이며, 이 필드는 크기가 고정된 것이 아니라 가변적이다. +* 그래서 수신 측이 어디까지가 헤더고 어디서부터 데이터인지 알기 위해 위에서 설명한 데이터 오프셋 필드를 사용하는 것이다. +* 대표적인 옵션으로는 윈도우 사이즈의 최대 값 표현을 확장할 수 있는 WSCALE 있다. + +[출처](https://evan-moon.github.io/2019/11/10/header-of-tcp/) From 01e4147fc27b0bb6f82afaebbecf9bbfc2b40066 Mon Sep 17 00:00:00 2001 From: Jin Hyung Park Date: Fri, 27 Aug 2021 00:44:21 +0900 Subject: [PATCH 113/142] =?UTF-8?q?feat:=20CSRF=20XSS=20=ED=95=99=EC=8A=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- network/csrf-xss/sigrid/README.md | 33 +++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 network/csrf-xss/sigrid/README.md diff --git a/network/csrf-xss/sigrid/README.md b/network/csrf-xss/sigrid/README.md new file mode 100644 index 0000000..3ee4870 --- /dev/null +++ b/network/csrf-xss/sigrid/README.md @@ -0,0 +1,33 @@ +# CSRF XSS 공격 +## CSRF: Cross-Site Request Forgery +* 사이트간 요청 위조라는 뜻인데, Cross-Origin 정책을 우회해야 공격에 성공하니 해당 정책을 우회하는 특징을 가지고 있다. +* CSRF는 **사용자가** 의도하지 않은 행위를 취하도록 만드는 공격이다. +* CSRF는 "한 쪽으로만" 공격하는 행위인데, 왜냐면 공격자가 피해 PC로 HTTP 요청을 보내게 유도할 수는 있지만 공격자가 "요청에 대한 응답을 받지는" 못하기 때문이다. +* 브라우저가 HTTP Request를 보낼 때 쿠키 안에 Session 값을 기본적으로 넣기 때문에 해당 공격이 가능하다. + * 쿠키에 세션 id나 accessToken을 인증에 이용하는 구조에 CSRF 취약점이 있다면 해커는 CSRF 공격으로 API 콜 요청시 자동으로 인증 정보가 쿠키에 담겨 서버로 보내진다. 공격자는 유저 권한으로 정보를 가져오거나 액션을 수행할 수 있다. + +### 방어하는 방법 +* localstorage나 쿠키에 access token을 저장하지 말고 다른 곳에 보관한다. 요청에 보내는 쿠키에는 refresh token을 받아와서 새로운 access token을 가져온다. (secure httpOnly의 경우에도 마찬가지) +* Referrer를 검증한다. 지금 접속한 페이지가 어느 곳에서 왔는지를 검증하면 기초적인 CSRF 공격은 다 방어할 수 있게 된다. +* Spring Security CSRF 토큰 활용한다. 세션에 난수 값을 저장하고 이를 타임리프 form에다가 hidden 값으로 보낸다. 사용자가 request를 보낼 때 난수 값이 맞지 않으면 40X 에러코드를 뿝어낸다. [참고](https://velog.io/@max9106/Spring-Security-csrf) + +## XSS: Cross Site Scripting +* 서버 측에서 제공되는 스크립트가 아니라, 임의의 공격자가 웹사이트에 자기 스크립트 올려서 그걸 사용자가 실행하게 해서 피해보도록 한다. +* 그러니까 서버와는 관련이 없고 **클라이언트**와 관련이 있다. +### Stored XSS +* 게시판에다가 자기 스크립트 올리고 사용자가 그걸 클릭해서 피해를 볼 수 있으면 저장형 XSS 공격이다. 게시물을 클릭하면 스크립트가 실행되어 사용자의 쿠키가 털리는 경우이다. [참고](https://rjswn0315.tistory.com/175) +### Reflected XSS +* 마치 "반사" 된다고 표현하는 데, 사용자가 공격자가 걸어놓은 악성 링크를 타고 들어가면 공격 스크립트 코드가 "삽입된" 사이트로 이동하게 되고 입력된 스크립트가 반사되어 실행한다. +* 예를 들어 User 이름을 적는 form이 있는 사이트로 접속한다고 했을 때, 해당 form에다가 미리 script를 적어놓은 악성 링크로 피싱하여 접속한다고 쳤을 때, 악성 링크를 클릭할 경우 마치 이름을 적는 form 사이트 인 것처럼 보이지만 실제로는 해커가 심어놓은 스크립트가 실행되는 것이다. [참고](https://rjswn0315.tistory.com/176) +### DOM-based XSS +* URL에서 #이후에 입력받은 값은 서버측에 전송되지 않는점을 이용하여 공격하는 방식. # 뒤에 스크립트를 넣는다. +* 해당 방식은 서버측에서 Script를 필터링할 수 없다. [참고](https://www.acunetix.com/blog/articles/dom-xss-explained/) +[참고 2](https://ddungkill.tistory.com/135) + +## 대응 방안 +* XSS 공격이 무서운 이유는 localstorage 안에서는 쿠키의 모든 정보를 접근하고 편집하고 삭제할 수 있기 때문이다. +* Cookie에서 HttpOnly 옵션을 설정하여 HTTP용 통신에서만 쿠키 정보에 접근하도록 만들고 JavaScript에서는 가져올 수 없게 설정할 수 있다. 그런데 HttpOnly property를 켜놓게 되면 SPA 환경에서 AJAX 통신을 할 수 없다는 단점이 존재한다. [참고3](https://jhyuxxk.tistory.com/7) +* 사용자로부터 받은 신뢰할 수 없는 입력의 경우 Espace 과정을 거친다. HTML Body 등을 만났을 때 실행하지 않고 Escape한다는 의미이다. [참고](https://onlydev.tistory.com/78) + * Escape: 특정 문자를 원래의 기능에서 벗어나게 변환하는 행위 + * 참고로, 이전에 페이스북이 Stored XSS 버그 바운티가 있었는데, 해시태그가 SNS에서 많이 쓰다보니 #을 encoding하지 않기로 했는데 그러다보니 #을 URL 바로 뒤에다가 붙여서 해당 링크로 forwarding할 수 있게 하는 버그였다. [참고](https://www.hahwul.com/2018/03/21/hacking-hsah-tag-xss-escape-quot-with/) +* Double Submit Cookies라는 방법도 있다고 한다. Same Origin Policy에 따라 도메인이 다르면 이전 도메인의 쿠키 값에 접근하지 못하도록 한다. 이를 이용하여 스크립트 단에서 요청시 난수를 생성하고 이를 쿠키에 저장한다. 동일한 난수 값을 요청 파라미터에 저장하여 서버에 전송했을 때 두 난수 값이 서로 일치하면 올바른 요청이라고 판단하고 아니라면 기각한다. 서버에서 토큰값을 저장할 필요가 없어 세션 검증보다 가볍다. [링크](https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html) From a17b6b62d8b426f482fde47747d87b4b0ee02076 Mon Sep 17 00:00:00 2001 From: 102092 Date: Sun, 29 Aug 2021 23:29:36 +0900 Subject: [PATCH 114/142] Add csrf-xss, tcp-keep-alive --- network/csrf-xss/han/README.md | 78 ++++++++++++++++++++ network/tcp-keep-alive/han/REAMDE.md | 106 +++++++++++++++++++++++++++ 2 files changed, 184 insertions(+) create mode 100644 network/csrf-xss/han/README.md create mode 100644 network/tcp-keep-alive/han/REAMDE.md diff --git a/network/csrf-xss/han/README.md b/network/csrf-xss/han/README.md new file mode 100644 index 0000000..f085649 --- /dev/null +++ b/network/csrf-xss/han/README.md @@ -0,0 +1,78 @@ +# CSRF + +- Cross Site Request Forgery +- 사이트 간 요청 위조 + - 요청을 보내는 데, 그 요청이 정상적인 요청이 아니다. + - 뭔가 목적을 위해서, 요청을 위조해서 보냈음. + +![](https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcnluOR%2FbtqAslpDWKV%2FjUdwVwOTxZUL1qMA5jGCd1%2Fimg.png) + +- 사용자 (희생자) 가 자신의 의지와는 무관하게 특정 웹 사이트를 공격하게 만드는 것. + - 즉 공격 목표인 웹 서버 - 희생자 클라이언트 브라우저의 간에 신뢰상태에 있는 것을 기반으로 + - 희생자는 정상적인 서비스를 이용하지만, + - 그 내부적인 요청에는 공격자가 원하는 요청(희생자는 원하지 않는 요청)까지 포함되어 있음을 의미한다. +- 해당 공격은 유저 (희생자) 가 로그인 상태이어야만 유의미한 공격이 된다. + + + +## 어떻게 하면 막을 수 있을까? + +1. Referer 체크 + - 해당 요청이 신뢰할 만한 페이지에서 발생한 것인지 확인. + - 이 또한 조작할 수 있음. +2. 토큰 발급 + - 로그한 유저에게만 토큰을 발급해서, 요청 시에 해당 토큰도 함께 보내도록 + - 이 토큰이 유효할 때만, 해당 요청을 처리하도록.. +3. Spring Security + - https://zzang9ha.tistory.com/341 + +# XSS + +- Cross site scripting + +- 공격자는 해당 사이트에 접속하는 사용자로 하여금 원하지 않는 scripting(malicious code)을 실행시키게 만드는 것을 의미. + + - 이를 통해, 쿠키, 세션등에 담긴 정보등을 탈취할 수 있음. + - 혹은 사이트 이용자로 하여금 원하지 않는 동작 을 하게 만들거나.. + +- 보통 이러한 공격으로 인한 결과가, CSRF 취약점을 통한 결과보다 심각할 경우가 많음. + +- 3가지 타입이 존재한다. + + - **Stored XSS**, **Reflected XSS,** and **DOM-based XSS** + - 스크립트를 저장해놓거나, (Stored XSS) + - URL 변수 부분에 입력하거나 .. 특정결과를 바로 노출시키거나 (Reflected XSS) + - URL 변수 입력을 통해서, HTM DOM 파싱에서 문제를 일으키거나.. (DOM-based XSS) + +## 보통 어떻게 동작할까? + +- API 호출에, script를 삽입 + + ``` + https://example.com/search?query= + ``` + + + +- 아래 사진과 같은 결과가 나올 수 있음 (제대로 방어가 안되어있으면) + +![](https://miro.medium.com/max/626/0*m9RzWEjGqOK-rNk9.png) + + + + + + +## 어떻게 하면 막을 수 있을까? + + 1. Database의 유저가 작성한 값이 저장될 때, 검증하도록 하는 방법 + - script와 비슷한 구조를 모두 필터링하거나.. + - 일부 태그만 허용하는 방식 + 2. Automatic HTML escaping + +# 참고 + +- https://program-developer.tistory.com/99 +- https://lucete1230-cyberpolice.tistory.com/23 +- https://portswigger.net/web-security/csrf/xss-vs-csrf\ +- https://medium.com/humanscape-tech/xss%EC%99%80-csrf-fe0e219b4c38 \ No newline at end of file diff --git a/network/tcp-keep-alive/han/REAMDE.md b/network/tcp-keep-alive/han/REAMDE.md new file mode 100644 index 0000000..7d92db2 --- /dev/null +++ b/network/tcp-keep-alive/han/REAMDE.md @@ -0,0 +1,106 @@ +# TCP keepalive란 무엇이고 왜 필요할까? + +- TCP 연결을 맺는 과정에서, 3 way handshake 해야 한다. +- 그런데 주기적으로 연결을 맺어야 하는데, 매번 이러한 과정을 거쳐가야하는 것은 불필요하다고 볼 수 있음. +- 그래서 처음 맺은 연결(세션)을 그대로 사용할 수는 없을까? +- 이 결과 나온 것이 `keepalive` + + + +## TCP keepalive 패킷 흐름 + +![](https://jihooyim1.gitbooks.io/linuxbasic/content/contents/img/flow_packets_in_TCP_keepalive.png) + +- TCP keepalive 환경에서, 세션이 일단 맺어져 있으면, 일정 시간이 지나면 패킷을 보내서 연결이 살아있는지 확인한다. +- 이러한 확인은 클라이언트, 서버 둘 중에 어느 곳에서라든지 할 수 있다. + - 즉 클라이언트, 서버 중에 한 곳에서만이라도 `keepalive` 를 사용하면 해당 기능이 유지된다. + + + +## 현재 사용하고 있는 네트워크 소켓 확인하기 + +- `netstat -napo` + +``` +# netstat -napo +root@server1:~# netstat -napo +Active Internet connections (servers and established) +Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name Timer +tcp 0 0 0.0.0.0:111 0.0.0.0:* LISTEN 576/rpcbind off (0.00/0/0) +tcp 0 0 0.0.0.0:465 0.0.0.0:* LISTEN 1322/master off (0.00/0/0) +... +tcp 0 0 10.0.2.15:22 10.0.2.2:51040 ESTABLISHED 1787/sshd: vagrant keepalive (7198.14/0/0) +... +udp 0 0 0.0.0.0:111 0.0.0.0:* 576/rpcbind off (0.00/0/0) +.... +``` + +- Timer 항목에서 확인할 수 있고 +- state ESTABLISHED인 소켓에서 keepalive 상태고, 약 70초 정도 남아있음을 알려줌 + + + + + +## TCP keepalive 파라미터 + +- TCP Keepalive를 유지하는데 필요한 커널 파라미터들 +- 총 3개 있음. + +``` +root@server1:~# sysctl -a |grep -i keepalive + +net.ipv4.tcp_keepalive_time = 240 (1) +net.ipv4.tcp_keepalive_probes = 3 (2) +net.ipv4.tcp_keepalive_intvl = 30 (3) +``` + +- **net.ipv4.tcp_keepalive_time** + - keepalvie 소켓의 유지시간을 의미. +- **net.ipv4.tcp_keepalive_probes** + - keepalive패킷을 보낼 최대 전송 횟수를 정의 + - keepalive 패킷은, 이제 세션이 연결되어있는지 확인하는 패킷 + - 이 패킷에 한번 응답하지 않았다고 바로 끊진 않고, 여기에 정의된 횟수 만큼 시도해보고 + - 응답이 없으면 연결을 끊는 과정을 거친다. +- **net.ipv4.tcp_keepalive_intvl** + - keepalive 재전송 패킷을 보내는 주기 + - keepalive패킷을 보냈는 데, 해당 패킷에 대해 응답이 없을 때 몇초 후 다시 패킷을 보낼 것인가 정의하는 것을 의미한다. + + + +## TCP keepalive와 HTTP keepalive + +- TCP keepalive는 두 종단(TCP) 간의 연결을 유지하기 위함이지만, +- HTTP keepalive는 최대한 연결을 유지하는 것이 목적이다. + +- `apache`, `nginx`와 같은 웹 애플리케이션에도 keepalive timeout 이라는 것이 존재 + - HTTP/1.1에서 지원하는 keepalive를 위한 설정 항목 + - https://hodolman.com/16 +- 위 두개의 값이 모두 60이라하면.. + - TCP keepalive는 60초 간격으로 연결이 유지되어있는지 확인하고, keepalive 패킷에 응답이 없으면 연결을 끊는다 + - HTTP keepalive는 60초 동안 연결을 유지하고, 60초 지난 후에도 요청이 없으면 연결이 끊는다. +- etc + - [Tomcat](https://ehdvudee.tistory.com/30) + + + +## 참고 + +- https://jihooyim1.gitbooks.io/linuxbasic/content/contents/08.html +- https://devidea.tistory.com/60 + + + +# Java, Spring connection + +- Tomcat과 통신할 때, +- Java URL 클래스를 사용할 때, 커넥션이 어떻게 관리되는지, +- Spring restTemplate을 사용할 때, 커넥션도 다르게 관리되는듯. +- 보통 HTTP 스펙내에서 connetion들이 설정되는 듯 + + + +## 참고 + +- https://taes-k.github.io/2019/11/27/spring-java-connections/ + From fb55f9c09962abfaad8e3a3f976835687b1d3b8e Mon Sep 17 00:00:00 2001 From: Han Date: Tue, 7 Sep 2021 20:36:27 +0900 Subject: [PATCH 115/142] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d4d3a93..4cb26af 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ # lets-cs ## 스터디 규칙 -- 일정 : 08.10 ~ 09.10 -- 주제 : **네트워크** +- 일정 : 09.07 ~ 09.28 +- 주제 : **운영체제** - 진행 방식 - 2주가 하나의 사이클 - 1주차에는 질문에 대한 정리 및 PR, 2주차에는 PR 리뷰 및 수정을 진행 From 436f7a04defd93211e24cc8fece21b6bcf4ff9df Mon Sep 17 00:00:00 2001 From: Jin Hyung Park Date: Sun, 12 Sep 2021 13:37:09 +0900 Subject: [PATCH 116/142] =?UTF-8?q?feat:=20=EC=93=B0=EB=A0=88=EB=93=9C?= =?UTF-8?q?=EC=99=80=20=ED=94=84=EB=A1=9C=EC=84=B8=EC=8A=A4=20=EC=B0=A8?= =?UTF-8?q?=EC=9D=B4=20=EB=B9=84=EA=B5=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../process-vs-thread/sigrid/README.md | 112 ++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 operating-system/process-vs-thread/sigrid/README.md diff --git a/operating-system/process-vs-thread/sigrid/README.md b/operating-system/process-vs-thread/sigrid/README.md new file mode 100644 index 0000000..e68a0f4 --- /dev/null +++ b/operating-system/process-vs-thread/sigrid/README.md @@ -0,0 +1,112 @@ +# 프로세스와 쓰레드 차이가 뭐에요? +# 프로세스 +## 사전적 정의 +* 프로세스: OS로부터 자원을 할당받는 작업의 단위 +* 쓰레드: 할당받은 자원을 실행하는 실행의 단위 +* 즉, Application 1개가 프로세스가 되고 프로세스 내에서 여러 가지 분기 처리를 쓰레드가 담당 + +```그림4. 여러 Process를 관리하는 운영체제의 모습을 도식화한 모델``` +![](https://i.imgur.com/cmfURuf.png) +## 프로레스는 다음을 포함한다 +* Stack: 스택 영역은 함수 안에서 선언된 지역변수, 매개변수, 리턴값, 등이 저장되고 함수 호출시 기록하고 종료되면 제거한다. +* Data Section: 데이터 영역은 코드에서 선언한 전역 변수와 정적(static) 변수가 저장되는 영역이다. 데이터 영역은 프로그램의 시작과 함께 할당되어 종료될 때 소멸된다. +* Heap: 힙 영역은 관리가 가능한 데이터 이외의 다른 형태의 데이터를 관리하기 위한 공간(Free Space)이다. + * 이 공간은 동적 메모리 할당 공간이므로 사용이 끝나면 운영체제가 쓸수 있도록 반납해야 한다. + * 프로그램이 실행하는 순간 프로그램이 사용할 메모리 크기를 고려하여 메모리의 할당이 이루어지는 데이터 또는 스택과 같은 정적 메모리 할당과는 대조적이다. + * 동적 메모리 할당은 어느 시점에 어느 정도의 공간을 할당할 수 있을지 정확히게 예측할 수 없으므로, 런타임에 확인가능하다. +* Text Section: 코드 영역은 실행할 프로그램의 코드 및 매크로 상수가 기계어 형태로 저장되는 영역이다. CPU는 코드영역에 저장된 명령어를 하나씩 처리한다. +* Program Counter: 프로세스 내부의 레지스터에 위치. 다음에 실행할 명령어의 **주소** 를 갖고 있음. +* 하나의 프로세서는 하나의 프로세스만 처리. 따라서 ready(프로세스에 작업이 할당되기를 기다리거나) waiting(프로세스가 프로세서에 할당되기를 기다리거나) running이거나 셋 중 하나임. +## Context Switching +* 멀티태스킹은 프로세스를 여러 개 동시에 처리하는 개념이 아니다. 대신, CPU는 한 번에 하나의 명령어만 처리할 수 있으므로 동시에 가깝게 Context를 switch해가며 마치 동시에 처리하는 것처럼 보이게 하는 것이다. +* 하나의 프로세스가 CPU를 사용하고 있는 상태에서, 다른 프로세스가 CPU를 활용하도록 하기 위하여 **이전의 프로세스 상태를 보관하고 다음 프로세스의 상태를 적재하는 것이다** +* Context Switching은 OS 내부의 Scheduler에 의해 제어된다. CPU를 효율적으로 사용하고 관리할 수 있는가는 스케줄러에 따라 결정된다. +* 이 작업들이 계속 해서 반복되는데, 이러한 일련과정들을 Context Switching이라고 한다. Context Switching도 메모리에 I/O를 하는 작업이기 때문에 실행되는 프로세스의 수가 많거나, Context Switching의 빈번한 발생은 Overhead를 발생시켜 성능 저하를 가져온다. +## CPU Scheduler +* 프로세스는 System에 들어오면 ```job queue```에 놓여진다. +* 이 중 주 메모리(RAM)에 존재하며 process state가 ready 상태인 프로세스는 ```ready queue```에 다시 놓여진다. ready queue는 linkedlist 형태로 PCB (process control block; 프로그램 카운터, 레지스트리 집합 정보 등 프로세스가 어디까지 갔는지 정보 포함) 를 포인팅하게 된다. +![](https://i.imgur.com/Ua9VTW1.png) +![](https://i.imgur.com/CxMmyVK.png) +* 새로운 프로세스는 처음에 ready queue에 놓인다. 프로세스는 CPU를 할당받을 때(dispatch)까지 ready queue에서 대기한다. 프로세스에 CPU가 할당되어 실행되면 아래 사건들 중 하나가 발생할 수 있다. + * 프로세스가 I/O(입출력)을 요청하여 I/O queue에 넣어질 수 있다. + * 프로세스가 child process를 생성하고 그 프로세스의 종료를 기다릴 수 있다. + * 프로세스가 interrupt의 결과에 따라 강제로 CPU로부터 제거되어 ready queue에 다시 놓일 수 있다. +* 프로세스는 결국 waiting state에서 ready state로 전환되고 다시 ready queue에 넣어진다. 프로세스는 종료될 때까지 이 주기를 계속하며, 종료되면 모든 queue에서 삭제되고 프로세스의 PCB와 자원을 반납(deallocate)한다. +* 스케줄러에는 Long-term과 Short-term 총 2가지가 있다. + * Long-term: 하드 디스크에서 메모리로 프로세스를 적재(ready)한다. 실행간격이 길다. + * 메모리에 있는 프로세스의 수를 제어하는데 I/O bound vs CPU bound processes를 적합하게 혼합하는 것이 중요하다. + * IO 바운드 작업의 경우 input과 output 동작에 더 많은 시간을 할애 하며 CPU 바운드 프로세스는 CPU에서 더 많은 시간을 할애한다. 그래서 균형잡히게 스케줄링을 해야 한다. + * Short-term: ready 큐에 있는 프로세스 중 어느 것을 running으로 둘 것인지를 선택한다. 실행간격이 짧다. CPU 스케줄러는 높은 burst time을 가지는 프로세스들로 인해 CPU 자원이 'starvation' 하지 않도록 관리해야 한다. +* 스케줄링 알고리즘에는 다음과 같은 것이 있어 간단하게 보고 넘어간다. + * FCFS: First Come, First Serve 의 약자로, 먼저 도착한 프로세스를 처리하는 스케쥴링 + * SJF: Shorted Job First의 약자로, 최단 작업을 우선하는 스케쥴링 + * Priority Scheduling: 미리 주어진 프로세스의 우선 순위에 따라서 스케쥴링 + * RR: Round Robin의 약자로, 정해진 시간에 주어진 만큼 프로세스를 할당한 뒤 작업이 끝난 프로세스는 레디큐의 가장 마지막에 가서 재할당 + * Multilevel-Queue: 레디큐를 여러개의 큐로 분류하여 각 큐가 각각 다른 스케쥴링 알고리즘을 가지는 방식 + * Multilevel-Feedback-Queue: Multilevel-Queue는 특정 프로세스가 큐에 고정되어 있지만, Multilevel-Feedback-Queue는 큐와 큐 사이에 프로세스가 이동하는 것을 허용 +## PCB와 프로세스의 상태 +### 개요 +![](https://i.imgur.com/Y7r4kGu.png) +* 위 그림을 보면 executing되다가 다른 프로세스 P1을 수행시키기 위해 PCB0에다가 P0프로세스 정보를 저장, 레지스터에 PCB1에 저장되어있던 process 1 정보를 가져와 P1을 수행. 이런 저장공간이 PCB인 것임. +* 사실 이렇게 수행중인 프로세스를 변경할 때 레지스터에 프로세스의 정보가 바뀌는 것을 Context Switching이라고 하는 것임. +* Context Switching 문맥교환 이란 CPU가 이전의 프로세스 상태를 PCB에 보관하고, 또 다른 프로세스의 정보를 PCB에서 읽어 레지스터에 적재하는 과정임. 프로세스가 준비 -> 실행, 실행 -> 준비, 실행 -> 대기 등으로 상태 변경될 때 발생 +* 즉 PCB가 필요한 이유는 바로 Context Switching 때문 + * CPU가 여러 프로세스를 빠르게 번갈아가면서 작업하기 위해서는 프로세스에 대한 정보 및 상태를 저장/복원 할 필요가 있다. +### 저장 정보 +* OS 별로 다르지만, 일반적으로 다음과 같은 정보가 포함된다. + * 프로세스 식별자(PID;Process ID) + * 프로세스 상태(Process State) + ![](https://i.imgur.com/uvObTeM.png) + * 프로그램 계수기(Program Counter) + * CPU 레지스터 및 일반 레지스터 + * CPU 스케줄링 정보 + * 메모리 관리 정보 + * 프로세스 계정 정보 + * 입출력 상태 정보 +## Inter-Process Communication +### 개요 +* 각 프로세스는 별도의 공간에서 실행되기 때문에, 한 프로세스에서 다른 프로세스의 메모리영역에 접근할 수 없다. 프로세스는 자신에게 할당된 메모리 내의 정보만 접근할 수 있는데, 이는 안전성을 위해 운영체제에서 자기 프로세스의 메모리만 접근하도록 강제하고 있다는 것이다. +* 만약 프로세스가 다른 프로세스 자원에 접근하려면 IPC(Inter-Process Commnuication)를 사용해야 한다. +* IPC란 운영체제 상에서 실행 중인 프로세스 간에 정보를 주고받는 것을 말한다 IPC의 종류로는 메일슬롯, 파이프, 소켓, 시그널, 공유 메모리 등이 있다. +# 쓰레드 +```메모리 관점에서 본 프로세스와 쓰레드``` +![](https://i.imgur.com/cAef0R6.png) +* 스레드는 한 프로세스 내에서 동작되는 흐름으로 프로세스 내에서 Stack 영역만 별도로 할당 받고, 부모 프로세스의 Code, Data, Heap 영역은 공유 한다. +* 즉, 프로세스 내에서 자식 스레드들은 서로 주소 공간이나 자원들을 공유하면서 실행될 수 있다. +## 멀티 프로세스 vs 멀티 쓰레드 +* Key: 하나의 프로그램을 프로세스로 나눌 것인가, 쓰레드로 나눌 것인가? +### 멀티 프로세스 +![](https://i.imgur.com/pnvQ8ZU.png) +* 멀티 프로세스란 하나의 애플리케이션을 여러 개의 프로세스로 구성하여 각 프로세스가 하나의 작업(task)을 처리하도록 하는 것이다. + * 장점: 하나의 프로세스가 잘못 되어도 나머지 작업은 잘 처리됨. 구현이 비교적 간단하고, 각 프로세스들이 독립적으로 동작하며 자원의 서로 다르게 할당된다. + * 단점: Context Switching 비용이 발생함. 프로세스 간 통신을 하기 위해서는 IPC를 통해야 한다. 메모리 사용량이 많다. +### 멀티 쓰레드 +![](https://i.imgur.com/xp8m96Z.png) +* 멀티 스레드란 하나의 애플리케이션을 하나의 프로세스 내부에 여러 개의 스레드로 구성하여 하나의 스레드가 하나의 작업을 처리하도록 하는 것이다. +* 멀티스레드 사용 이유: 사용자와 상호작용하는 애플리케이션에서 단일 스레드로 Network 또는 DB 와 같은 긴 작업(Long-running task) 을 수행하는 경우 해당 작업을 처리하는 동안 사용자와 상호작용 불능 상태가 되기 때문이다. + * 장점: 시스템 자원 소모 감소, 자원 공유의 유용성 (쓰레드는 부모 프로세스와 stack 영역 등 자원 및 메모리를 공유). 처리 비용의 감소 (속도의 향상, Context Switching 비용이 없기 때문임). + * 단점: 동기화와 교착상태에 취약. (추후 CS 스터디 주제로 포함해도 좋겠네요. [참고 링크](https://chanhuiseok.github.io/posts/cs-2/) [참고 링크 2](https://popcorntree.tistory.com/6)) + * 동기화와 비슷하게 [Race 조건](https://close852.tistory.com/68)에 있어서 디버깅하거나 테스트하기가 힘듬. 멀티 쓰레드의 단점은 어느 쓰레드가 먼저 실행될 지를 알 수 없다는 것임. +### 비교 +[참고](https://charlezz.medium.com/process%EC%99%80-thread-%EC%9D%B4%EC%95%BC%EA%B8%B0-5b96d0d43e37) +* 멀티 스레드는 멀티 프로세스에 비해 상당한 이점을 가지는 반면 위험 부담 크다. +* 장점 + * 자원의 효율성 증대 + * 멀티 프로세스로 실행되는 작업을 멀티 스레드로 실행할 경우 프로세스를 생성하여 자원을 할당하는 비용이 적고, 스레드는 프로세스 내의 메모리를 공유하기 때문에 독립적인 프로세스와 달리 스레드 간 데이터를 주고 받는 것이 간단해지고 시스템 자원 소모가 줄어든다. + * 응답 시간 단축 및 처리 비용 감소 + * 프로세스간 IPC를 사용하여 통신하는 것은 상대적으로 비용이 크다. + * 하지만 스레드는 프로세스의 메모리 영역을 공유하여 스레드 간의 통신 비용이 적게 든다. + * 또한 프로세스간의 Context Switching은 느린 반면 쓰레드간의 Context Switching 은 빠른데, 그 이유는 Context Switching 시 스레드는 Stack 영역만 처리하면 되기 때문이다. +* 단점 + * 멀티 스레드의 안정성 문제 + * 여러 개의 스레드가 동일한 데이터 공간(Critical Section)을 공유하면서 이들을 수정한다는 점에 필연적으로 생기는 문제이다. + * 멀티 프로세스의 프로그램은 문제가 생기면 해당 프로세스가 중단되거나 중단 시키고 다시 시작하면 된다. + * 하지만 멀티 스레드 방식의 프로그램에서는 하나의 스레드가 자신이 사용하던 데이터 공간을 망가뜨린다면, 해당 데이터 공간을 공유하는 모든 스레드를 망가뜨릴 수 있다. +* 해결하기 위한 노력 + * 이를 [해결하는 방법](https://chul2-ing.tistory.com/43)은 임계 구역, 세파모어, 뮤텍스 등이 있다고 함. 추후 스터디 주제로! + * Critical Section: 임계 구역(critical section) 또는 공유변수 영역은 둘 이상의 스레드가 동시에 접근해서는 안되는 공유 자원(자료 구조 또는 장치)을 접근하는 코드의 일부를 말한다. + * Thread Safe: 여러 쓰레드에서 동시에 호출하더라도 멱등성을 보장하는 것을 의미한다. 함수가 전역 변수를 호출하면 thread safe하지 않다고 말하는 이유가 여기에서 있다. + * 물어볼 수 있는 질문들: 프로세스와 달리 쓰레드는 서로의 자원을 공유하는데 이때 무엇을 조심해야 하는가? [링크](https://brunch.co.kr/@babosamo/100) + * Thread safe하지 않게 만들 수 있는 방법의 예시는? + * Thread safe하지 않은 환경을 Thread Safe하게 바꿀 수 있는 방법은? + * 답변 키워드: 동기화, mutext, semaphore, synchronized From 7bda945f66e658746c329569756bf56f9446ff11 Mon Sep 17 00:00:00 2001 From: Jin Hyung Park Date: Sun, 12 Sep 2021 13:58:39 +0900 Subject: [PATCH 117/142] =?UTF-8?q?feat:=20CPU=20=EC=8A=A4=EC=BC=80?= =?UTF-8?q?=EC=A4=84=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- operating-system/scheduling/sigrid/README.md | 55 ++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 operating-system/scheduling/sigrid/README.md diff --git a/operating-system/scheduling/sigrid/README.md b/operating-system/scheduling/sigrid/README.md new file mode 100644 index 0000000..d8fd3ec --- /dev/null +++ b/operating-system/scheduling/sigrid/README.md @@ -0,0 +1,55 @@ +# 스케줄링 기법 +* 스케줄링(scheduling)은 다중 프로그래밍을 가능하게 하는 운영 체제의 동작 기법이다. +* OS는 프로세스에게 CPU 등의 자원 배정을 적절히 하여 시스템 성능을 개선한다. +## 평가 기준 +* CPU 사용률(CPU Utilization) + * 전체 시스템 시간 중 CPU가 작업을 처리하는 시간의 비율 +* 처리량(Throughput) + * CPU가 단위 시간당 처리하는 프로세스의 개수 +* 응답 시간(Response Time) + * 대화식 시스템에서 요청 후 응답이 오기 시작할 때까지의 시간 +* 대기 시간(Waiting Time) + * 프로세스가 준비 큐 내에서 대기하는 시간의 총합 +* 반환 시간(Turnaround Time) + * 프로세스가 시작해서 끝날 때까지 걸리는 시간 +## Preemptive vs Non-preemptive +* 비선점형 스케줄링(Non-preemptive Scheduling) + * 프로세스가 종료되거나 프로세스가 스스로 자발적으로 중지될 때까지 계속 실행되도록 보장한다. + * 순서대로 처리되고, 응답 시간을 예상할 수 있으며, 스케줄러 호출 빈도가 낮고, Context Switching overhead가 적다. 일괄 처리 시스템에 적합하다. + * CPU 사용 시간이 긴 하나의 프로세스에 의해 처리율이 떨어질 수 있다는 단점이 있다. + * 비선점형 스케쥴링은 수행시간이 긴 프로세스가 자원을 점유하게 되면 그 이후에 실행되어야 할 프로세스들이 기아 상태에 빠지게 된다. +* 선점형 스케줄링(Preemptive Scheduling) + * 선점권은 실행 대기 중인 프로세스에 있다. + * 다른 프로세스가 실행 중인 프로세스를 중지하고 CPU를 강제로 점유할 수 있다. + * 모든 프로세스에게 CPU 사용 시간을 동일하게 부여할 수 있다. 빠른 응답시간에 적합하며 긴급한 프로세서를 제어할 수 있다. + * 선점형 스케쥴링은 프로세스의 우선순위에 따라 스케쥴링을 하게됩니다. 따라서 우선순위가 낮은 프로세스는 자원을 할당받지 못하게 되는 기아 현상(starvation)이 발생할 수 있다. +## Static vs Dynamic +* 정적 스케줄링(Static Scheduling): 프로세스에 부여된 우선순위가 바뀌지 않는다. +* 동적 스케줄링(Dynamic Scheduling): 스케줄링 과정에서 프로세스의 우선순위를 변동시킨다. +## 종류 +* 비선점 프로세스 스케줄링 + * FCFS 스케줄링(First Come First Served Scheduling) + * 먼저 자원 사용을 요청한 프로세스에게 자원을 할당해 주는 방식의 스케줄링 알고리즘 + * SJF 스케줄링(Shortest Job First Scheduling) + * 평균 대기 시간을 최소화하기 위해 CPU 점유 시간이 가장 짧은 프로세스에 CPU를 먼저 할당하는 방식. + * 요구 시간이 긴 프로세스는 기아 상태가 발생할 수 있으며, 대기 상태에 있는 프로세스의 요구시간에 대한 정확한 자료를 얻기 어렵다는 문제점이 있다. + * 단기 스케줄링 보다는 장기 스케줄링에 유리하다. + * HRRN 스케줄링(Highest Response Ratio Next Scheduling) + * 프로세스 처리의 우선 순위를 CPU 처리 기간과 해당 프로세스의 대기 시간을 동시에 고려해 선정하는 스케줄링 알고리즘이다. SJF 스케줄링의 문제점을 보완해 개발된 스케줄링이다. + * ```우선순위 = (대기시간+처리시간) / 처리시간``` +* 선점 프로세스 스케줄링 + * RR 스케줄링(Round Robin Scheduling) + * 시분할 시스템을 위한 선점형 스케줄링 방식. 프로세스들 사이에 우선순위를 두지 않고, 순서대로 시간단위(Time Quantum)로 CPU를 할당하는 방식의 CPU 스케줄링 알고리즘이다. + * 보통 시간 단위는 10 ms ~ 100 ms 정도이다. 시간 단위동안 수행한 프로세스는 준비 큐의 끝으로 밀려나게 된다. 문맥 전환의 오버헤드가 큰 반면, 응답시간이 짧아지는 장점이 있어 실시간 시스템에 유리하다. + * SRTF 스케줄링(Shortest Remaining-Time First Scheduling) + * SJF 스케줄링을 선점 형태로 수정한 방식. 현재 작업 중인 프로세스를 중단시키고 최단 잔여시간 프로세스의 처리를 시작하는 방식이다. 선점형 SJF 스케줄링 또는 SRT (Shortest Remaining Time) 스케줄링이라고도 한다. + * 다단계 큐 스케줄링(Multilevel Queue Scheduling) + * 커널 내의 준비 큐를 여러 개의 큐로 분리하여 큐 사이에도 우선순위를 부여하는 스케줄링 알고리즘이다. 또한, 각각의 큐에 대해 다른 스케줄링 알고리즘을 적용하기도 한다. + * 프로세스들은 조건에 맞는 큐에 영구적으로 할당된다. + * 다단계 피드백 큐 스케줄링(Multilevel Feedback Queue Scheduling) + * 다단계 큐 스케줄링에서 한 단계 발전된 방식. 다단계 큐 스케줄링에서는 프로세스가 하나의 큐에 영구적으로 할당되지만, 다단계 피드백 큐 스케줄링에서는 프로세스들이 큐를 갈아탈 수 있다. Aging 등의 방식으로 대기 시간이 긴 프로세스를 높은 우선순위 큐에 올려 기아 상태를 막을 수 있다. + * RM 스케줄링(Rate Monotonic Scheduling) + * EDF 스케줄링(Earliest Deadline First Scheduling) +## 링크 +* https://www.geeksforgeeks.org/preemptive-and-non-preemptive-scheduling/ +* https://dhkdn9192.github.io/computer_science/cpu-scheduling-algorithm/ From 1af1249902b32cae48338b68b3a9c3c5d1aebfc1 Mon Sep 17 00:00:00 2001 From: Jin Hyung Park Date: Sun, 12 Sep 2021 14:25:28 +0900 Subject: [PATCH 118/142] =?UTF-8?q?feat:=20=EB=A9=94=EB=AA=A8=EB=A6=AC=20?= =?UTF-8?q?=EA=B4=80=EB=A6=AC=20=EA=B8=B0=EB=B2=95=20=EA=B0=84=EB=8B=A8=20?= =?UTF-8?q?=EB=B9=84=EA=B5=90=20(=ED=8E=98=EC=9D=B4=EC=A7=95=EA=B3=BC=20?= =?UTF-8?q?=EC=84=B8=EA=B7=B8=EB=A9=98=ED=85=8C=EC=9D=B4=EC=85=98)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../linux-memory-managment/sigrid/README.md | 80 +++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 operating-system/linux-memory-managment/sigrid/README.md diff --git a/operating-system/linux-memory-managment/sigrid/README.md b/operating-system/linux-memory-managment/sigrid/README.md new file mode 100644 index 0000000..ba706af --- /dev/null +++ b/operating-system/linux-memory-managment/sigrid/README.md @@ -0,0 +1,80 @@ +# 리눅스 메모리 관리 기법 간단히 알아보기 +* 여러 프로세스를 동시에 실행하는 경우 프로세스 크기가 서로 달라 메모리를 어떻게 나누어 사용할지에 대한 문제가 생긴다. +## 가상 메모리 Virtual Memory +* 가상 메모리는 메모리 사용량이 늘어나면서, HDD/SDD의 일부를 확장 RAM처럼 사용할 수 있도록 하는 기술이다. +* 커널은 실제 메모리(RAM)에 올라간 메모리 블록들 중 당장 쓰이지 않는 것을 디스크에 저장한다. 이를 통하여 사용 가능한 메모리 영역을 늘릴 수 있다. +* 만약 디스크에 저장되었던 메모리 블록이 다시 필요하게 되면, 해당 블록을 RAM에 다시 올린다. 대신 다른 블록을 디스크로 내린다. +* 하지만 HDD/SDD를 읽고 쓰는 시간은 RAM보다 약 천배 정도 느리기 때문에 프로그램 실행은 그만큼 더디게 된다. +* 가상 메모리로 쓰이는 HDD/SDD의 영역을 Swap space라고 한다. +* CPU가 특정 프로세스의 어떤 공간을 참조할 때는 우선 가상 주소를 먼저 참조하고, 가상 주소에 해당하는 실제 물리 주소를 참조하게 된다. +## MMU +* CPU가 가상 메모리에 접근하기 위해 물리 메모리의 가상 주소를 참조할 때마다 매번 이를 물리 주소로 변환을 하게 되니까 이 시간을 짧게 하려고 MMU라는 하드웨어 칩의 지원을 받는다. MMU는 가상 주소를 물리 주소로 빠르게 변환해주는 역할을 한다. +* 프로세스 생성 시 물리 메모리 레지스터(PCB)에 페이지 테이블 정보가 생성된다. +* PCB 등에서 해당 페이지 테이블에 접근이 가능하고, 관련 정보는 물리 메모리에 적재한다. +* 프로세스 구동 시, 해당 페이지 테이블의 base 주소 (시작 주소)가 별도의 레지스터(CR3)에 저장된다. +* 즉 CPU가 가상 주소에 접근 시, MMU가 CR3를 통해 페이지 테이블 base 주소에 접근해서 물리 주소를 가져온다. + +## 연속 할당 기법 +* 프로그램 전체를 하나의 공간에 연속적으로 할당하는 기법이다. +* 고정 분할 할당(정적 할당) + * 프로그램 전체가 주 기억장치에 위치해야 한다. + * 주기억장치 고정된 크기로 분할한다. 프로그램이 분할된 영역보다 클 경우 들어갈 수 없다. 내부, 외부 단편화 발생하여 낭비가 많다. +* 가변 분할 할당(동적 할당) + * 고정 분할 기법처럼 미리 분할해놓는 것이 아니라 프로그램을 주기억장치에 적재 시 필요한 크기로 분할한다. 고정 분할 기법보다 단편화를 줄일 수 있지만 영역과 영역 사이 단편화가 발생할 수 있다. + +## 비연속 할당 기법(분산 할당 기법) +* 프로그램을 특정 단위의 조각으로 나누어 주기억장치 내에 분산하여 할당한다. +* 하나의 프로세스에서 특정 시간 동안 쓰는 메모리 영역은 4GB 중 아주 일부분이기 때문에 일부분만 실제 물리 메모리에 올려놓고 쓰자는 것이 가상 메모리의 컨셉이다. +* 이 때 정도의 사이즈만큼 메모리에 올릴 지에 대한 결정이 필요하다(100MB? 1GB? 등). 이를 페이지(page)라는 단위로 다루겠다고 하는 것이 바로 페이징 시스템이다. +### 페이징 +* 가상 메모리를 일정한 크기로 나눈 블록 +* 크기가 동일한 페이지 단위 +* 가상 주소 공간과 이에 매칭되는 물리 주소 공간을 관리 +* 페이지 번호를 기반으로 가상 주소와 물리 주소의 매핑 정보를 기록하고 사용 + * 리눅스의 경우 4GB의 가상 메모리를 4KB 단위로 쪼개서 페이징하고 페이지 번호를 붙임 + * 페이지 단위로 물리 메모리에 넣고, 해당 데이터를 찾을 때에도 페이지 번호를 기반으로 주소를 찾게 된다. + +### 프레임 +* 물리 메모리를 일정한 크기로 나눈 블록(page와 동일한 크기) +* 프로세스(4GB)의 PCB(Process Control Block)에 Page Table 구조체를 가리키는 주소가 들어 있음 +* Page Table에는 가상 주소와 물리 주소 간 매핑 정보가 있음 +![](https://i.imgur.com/TS55cDT.png) + +### 페이지 테이블 +* 가상 주소에 있는 페이지 번호와 해당 페이지의 첫 물리 주소 정보를 매핑한 표 +``` +가상 주소 v = (p, d)라면 +p: 페이지 번호 +d: 페이지 처음부터 떨어진 정도 (위치) +``` + +## 세그멘테이션 기법 +* 가상 메모리를 서로 크기가 다른 논리적 단위인 세그먼트(Segment)로 분할하는 기법 + * 페이징 기법에서는 가상 메모리를 같은 크기의 블록으로 분할하는 것과 대조됨 +* [외부 단편화](https://m.blog.naver.com/rbdi3222/220623825770)가 일어나기 쉽다. 평균 세그먼트의 크기가 작을 수록 외부 단편화 문제는 줄어든다. +### 주소 변환 +* 주소 변환을 위해 세그먼트의 위치 정보를 가지고 있는 세그먼테이션 매핑 테이블이 필요하다. +* 이 테이블은 limit(세그먼트 크기)과 base(물리 메모리상의 시작 주소 정보)를 갖는다. +* 가상 주소를 (S,D)로 표현한다. S는 세그먼트의 No이고, D는 세그먼트 시작 지점에서 해당 주소까지의 거리를 의미한다. 물리주소는 ```base[S]+D``` 로 계산한다. +``` +No limit base +0 280 120 +1 120 450 +2 100 630 +… … … +``` +* 논리주소 (2, 100) => 물리주소 630+100 = 730번지 +* 논리주소 (1, 200) => 거리가 세그먼트의 크기(120)보다 크기 때문에 메모리 관리자는 해당 프로세스를 강제 종료한다. (trap(사용자가 의도치 않게 일으키는 인터럽트)을 발생시킴) + +### 참고: 단편화 문제 Fragmentation Problem +* 내부 단편화 문제(Internal Fragmentation Problem) - (페이지 기법) + * 페이지 블록만큼 데이터가 딱 맞게 채워져 있지 않을 때 공간 낭비 +* 외부 단편화 문제(External Fragmentation Problem) - (세그멘테이션 기법) + * 물리 메모리가 원하는 연속된 크기의 메모리를 제공해주지 못하는 경우 + +## 참고 +* http://egloos.zum.com/sweeper/v/2988689 +* https://velog.io/@gndan4/OS-%EA%B0%80%EC%83%81-%EB%A9%94%EB%AA%A8%EB%A6%AC +* https://colinch4.github.io/2020-02-02/%EB%A9%94%EB%AA%A8%EB%A6%AC-%ED%95%A0%EB%8B%B9-%EA%B8%B0%EB%B2%95/ +* https://higunnew.tistory.com/61 +* https://www.geeksforgeeks.org/difference-between-paging-and-segmentation/ From d0bf345fc651c8d8644414a5587dc6882f837ed8 Mon Sep 17 00:00:00 2001 From: 102092 Date: Sun, 12 Sep 2021 18:09:52 +0900 Subject: [PATCH 119/142] Add process vs thread --- .../process-vs-thread/han/README.md | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 operating-system/process-vs-thread/han/README.md diff --git a/operating-system/process-vs-thread/han/README.md b/operating-system/process-vs-thread/han/README.md new file mode 100644 index 0000000..caf2bc2 --- /dev/null +++ b/operating-system/process-vs-thread/han/README.md @@ -0,0 +1,48 @@ +# 프로세스란? + +- 메모리에 올라와서, 독립적으로 실행 중인 프로그램을 의미한다. +![image](https://user-images.githubusercontent.com/22140570/132981855-c1124ab9-4342-462a-baec-9445e476559d.png) +- 프로세스는 운영체제로 부터 독립적인 메모리 영역을 할당받고, + - 할당받는 메모리 영역은 `Code, Data, Stack, Heap`의 구조로 되어있음. +- 프로세스는 최소 한 개의 스레드(메인 스레드)를 가지고, +- 각 프로세스는 별도의 주소 공간에서 실행되고, 다른 프로세의 메모리에 접근할 수 없음. + - 프로세스간 통신을 하려면 IPC(inter-process-communication) 을 사용해야함. + - 파이프, 파일, 소켓등을 이용해야한다는 말. + + +# 스레드란? +- 프로세스가 할당받는 자원을 이용하는 실행의 단위. +- 프로세스보다 작은 의미. +- 프로레스 안에서의 흐름을 의미함. +![image](https://user-images.githubusercontent.com/22140570/132981870-6323ffb1-506a-49b7-bc98-adb9f40ecba2.png) +- 스레드는 프로세스 내에서 각각 `Stack` 를 **따로** 할당 받고, Code, Data, Heap 영역을 공유함. +- 프로세스 내의 주소 공간이나 자원을 스레드간 공유한다. +- 각각의 스레드는 별도의 **레지스터, 스택** 을 가지고 있고, 프로세스 안에 있는 힙 공간도 읽고 쓰는 것도 가능함. 즉 힙은 공유하는 공간임 + +# 자바 스레드 란? +- 일반 스레드와 차이 없음. +- JVM이 운영체제 역할을 할 뿐. +- 자바에서는 프로세스가 존재하지 않고, 스레드만 존재. +- 자바 스레드는 JVM에 의해 스케쥴되어 실행되는 코드 블럭이라고 할 수 있음. + +# 멀티 프로세스란? +- 하나의 응용 프로그램을 여러 개의 프로세스로 구성하여, 각 프로세스가 하나의 작업을 처리하도록 하는 것. + - **장점** : 여러 개의 자식 프로세스 중 하나에 문제가 발생하면 그 프로세스만 죽이면 되어서 다른 프로세스에는 영향을 주지 않음. + - **단점** : Context Switching 오버헤드 발생, 즉 프로세스는 각각의 독립적인 메모리 공간을 할당 받았기에, 프로세스간 공유할 수 있는 정보가 없어서 Context Swithing이 발생하면 캐쉬에 있는 데이터를 리셋하고, 다시 캐쉬정보를 불러와야함. 이과정에서 오버헤드가 발생함. +- Context Switching? + - CPU에서는 여러 프로세스가 돌아가면서 작업을 처리하는 데, 이렇게 공수교대 하는 과정을 문맥 교환이라 말한다. + - 자세히 보면, 현재 CPU에서 실행 중인 프로세스가 대기상태로 들어가면서 현재 프로세스의 상태(context)를 보관하고, 다음 실행 대기 중인 프로세스가 동작하기 위해서, 이전 프로세스의 상태가 다리 load되는 작업을 의미한다. + +# 멀티 스레드란? +- 하나의 응용프로그램(프로세스)를 여러개의 스레드로 구성하고, 각 스레드로 하여금 하나의 작업을 처리하게 하는 것. +- 웹 서버는 대표적인 멀티 스레드 응용 프로그램 + - 장점 → 시스템 소모 자원 감소 즉 자원의 효율성을 극대화, 프로세스를 생성하여 자원을 할당하려는 시스템 call이 줄어들어, 시스템 자원을 효율적으로 관리할 수 있음. + - 그리고 시스템의 처리량이 증가한다. 왜? 스레드 간 데이터를 주고 받는 것이 간단하고, 스레드 사이의 작업량이 프로세스에 비해 상대적으로 작기 때문에 Context Switching이 빠르다. + - 스레드는 프로세스의 영역 중 stack을 제외한 모든 영역을 공유하기에 스레드간 통신 부담이 적다는 것이 이유. + - 단점 → 자원 공유에서 발생하는 동기화 문제. , 하나의 스레드에서 문제가 생길 경우 발생하는 문제 + +# 멀티 프로세스 대신 왜 멀티 스레드를 사용할까? +![image](https://user-images.githubusercontent.com/22140570/132981913-4aac8898-0020-42bb-bd8b-6bb2b2c224ed.png) +- 프로그램을 여러 개 실행 시키는 것 보다는, 하나의 프로그램에서 여러 작업을 해결토록 하는 것이 낫다. +- 자원의 효율성, 처리 비용도 감소, 심지어는 응답 시간도 단축되기 때문에 +- 왜? 프로세스 간 문맥교환은 비용이 큰 작업. \ No newline at end of file From 7bef38d7b27abfefec6da1bd2a2d3a28747eb741 Mon Sep 17 00:00:00 2001 From: 102092 Date: Sun, 12 Sep 2021 18:13:58 +0900 Subject: [PATCH 120/142] Add reference --- operating-system/process-vs-thread/han/README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/operating-system/process-vs-thread/han/README.md b/operating-system/process-vs-thread/han/README.md index caf2bc2..4d593d3 100644 --- a/operating-system/process-vs-thread/han/README.md +++ b/operating-system/process-vs-thread/han/README.md @@ -45,4 +45,8 @@ ![image](https://user-images.githubusercontent.com/22140570/132981913-4aac8898-0020-42bb-bd8b-6bb2b2c224ed.png) - 프로그램을 여러 개 실행 시키는 것 보다는, 하나의 프로그램에서 여러 작업을 해결토록 하는 것이 낫다. - 자원의 효율성, 처리 비용도 감소, 심지어는 응답 시간도 단축되기 때문에 -- 왜? 프로세스 간 문맥교환은 비용이 큰 작업. \ No newline at end of file +- 왜? 프로세스 간 문맥교환은 비용이 큰 작업. + +# 참고 +- https://gmlwjd9405.github.io/2018/09/14/process-vs-thread.html +- https://www.youtube.com/watch?v=1grtWKqTn50 \ No newline at end of file From 184f8a8e7c2dc07a54f6c526689cfb765ead4dd3 Mon Sep 17 00:00:00 2001 From: 102092 Date: Sun, 12 Sep 2021 20:42:48 +0900 Subject: [PATCH 121/142] Add scheduling --- operating-system/scheduling/han/README.md | 92 +++++++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 operating-system/scheduling/han/README.md diff --git a/operating-system/scheduling/han/README.md b/operating-system/scheduling/han/README.md new file mode 100644 index 0000000..45624c3 --- /dev/null +++ b/operating-system/scheduling/han/README.md @@ -0,0 +1,92 @@ +# CPU Scheduling + +![](https://www.cs.uic.edu/~jbell/CourseNotes/OperatingSystems/images/Chapter6/6_01_CPU_BurstCycle.jpg) + +- 어떤 프로그램이든, CPU Bursts 와 I/O Burst가 반복되면서 실행된다 +- CPU Bursts? + - load store, add store, read from file 을 의미. + - 아마도 I/O 작업을 제외한, CPU 작업을 의미하는듯 + +- 그런데 CPU가 행하는 job은 여러가지가 있다. + +![](https://www.cs.uic.edu/~jbell/CourseNotes/OperatingSystems/images/Chapter6/6_02_CPU_Histogram.jpg) +- 위 자료는 CPU burst time 분포도 + - 좌측은 I/O bound job, 우측 그래프는 CPU bound Job이다. + - CPU를 짦게 쓰면서, 빈도(frequency) 가 잦으며, 중간에 I/O 가 끼어드는 잡이 있고, + - CPU를 길게 쓰는 CPU bound job이 있음. +- 다시 말해, 여러 종류의 Job이 깄기에 CPU와 I/O 장치에서 사용되는 시스템 자원을 효율적으로 분배할 필요성이 생긴다. + +> *I/O bound job(process)* +- 사람과 작업하는, +- CPU를 길게 잡고 있기 보다는 짦게, 빈도수를 많이 잡으면서 I/O에 더 많은 시간을 투자하는 잡 + +> *CPU bound job(process)* +- 계산 위주의 job + +## CPU Scheduler & Dispatcher +- 스케쥴러는 `Ready` 상태의 프로세스 중에 CPU를 할당해줄 프로세스를 고르는 역할을 담당. + - 즉 운영체제 안에서 CPU의 스케쥴을 하는 기능. +- 디스페쳐는 실제로 CPU에게 프로세스를 할당. + - `Context switch` (문맥 교환)을 통해 CPU 제어권을 스케쥴러가 선택한 프로세스에게 넘기는 기능. + +> *CPU 스케쥴링은 어떨때 일어날까?* +- 프로세스가.. + 1. Running -> Blocked (ex) I/O작업으로 넘어간 경우) + 2. Running -> Ready (할당시간 만료 될 경우, timer interrrupt) + 3. Blocked -> Ready (I/O작업이 끝난 경우, 인터럽트를 걸어서 CPU를 넘겨줌) + 4. Terminate + +# CPU Scheduling Algorithms + +## First-Come, First-Served (FCFS) +- 들어온 순서대로 처리하는 방법. +- 가장 많이 사용됨. +- 비효율적일 수도 있음. (waiting time 이 크다.) + - 왜? 들어오는 순서대로 처리되니 오래 걸리는 job을 잡고 있을 수도 있고, 그 뒤에 금방 끝나는 잡들이 있을 수 있음. + +## Shortest-Job-First (SJF) +- FCFS 를 개선하고자 나온 알고리즘 +- CPU burst가 가장 짧은 프로세스를 먼저 실행 (waiting time이 작다) +- 이 알고리즘에는 2가지 타입이 있음. + - preemptive(선점), non-preemptive(비선점) + - 작업 실행 중에, 새로 들어온 잡에 처리하는 시간이, 지금 남은 시간보다 짦다? (마치기 까지 남은 시간 2초, 새로 들어온 잡이 완료되는 시간 1초) + - preemptive의 경우, 새로 들어온 잡을 실행 + - non-preemptive의 경우, 현재 실행 중인 잡을 계속 실행 +- 그런데 실행 시간을, 실행해보지도 않고 어떻게 예측하지? + - 이 전에 실행되었던 잡들을 기반으로 판단? + - 이게 정확할 것이라는 보장이 없음. + +## Priority +- 우선 순위가 높은 프로세스를 먼저 스케쥴링 하는 기법 +- 어떻게 우선 순위를 할당할까? + - FCFS 방법으로 혹은 SJF 방법으로 할당 가능하다. +- 기본적으로 우선 순위 할당은, 그 프로세스의 **중요 정도**에 따라 할당된다. + - 이러한 중요도는, 운영체제에 의해 결정될 수도 혹은 외부적으로 결정될 수도 있음. +- 문제점은 starvation + - 기아 상태 + - 다시 말해, 우선 순위가 낮은 프로세스는 만약에 상대적으로 우선 순위가 높은 프로세스가 계속 들어온다면 CPU를 할당받을 수 없다는 문제가 있음. + - 즉 우선 순위가 낮은 프로세스가 무한정 대기하는 일이 벌어질 수 있음. + - `aging` 이라는 기법을 통해 이를 해결할 수 있는듯. + - 프로세스에 나이를 정하고, 일정 나이가 찬 프로세스는 우선 순위에 상관없이 무조건 CPU를 할당 받을 수 있도록 설정.. + +## Round-Robin (RR) +- 한 라운드에 조금씩 전부 CPU를 쓸 수 있도록 분배하고, 이를 반복하는 스케쥴링 기법. +- 모두(프로세스) 에게 공평하게 CPU를 사용할 수 있도록 돌아간다. +- 문제점은 Context swtiching 에서 발생하는 오버 헤드 + - 매번 스위칭 하면서 발생하는 오버헤드가 비효율적일 수 있음. + +## Multilevel Queue +- 여러개의 큐를 이용하여, 프로세스를 나누고,큐에 서로 다른 스케쥴링 기법을 적용하는 방법 +- 운영체제가 만들어낸 프로세스가 우선 순위가 높고, 그 다음이 사용자와 상호작용하는 프로세스. +- 사용자와 상호작용하는 프로세스가 관리되는 큐에는 빠른 응답 타입을 갖기 위해서.. + - RR 알고리즘 사용하고, +- 운영체제가 만들어낸 프로세스를 관리하는 큐에는 + - FCFS 알고리즘이 사용될 가능성이 큰 듯. + +# 참고 +- https://zzsza.github.io/development/2018/07/29/cpu-scheduling-and-process/ +- https://velog.io/@ssseungzz7/OS-CPU-Scheduling +- https://jhnyang.tistory.com/155 +- https://jhnyang.tistory.com/158?category=815411 +- https://jhnyang.tistory.com/28 +- http://www.kyobobook.co.kr/product/detailViewKor.laf?ejkGb=KOR&mallGb=KOR&barcode=9791158903589 \ No newline at end of file From 0cc0263443e625ea98f864558ab2ea4850f13ad3 Mon Sep 17 00:00:00 2001 From: 102092 Date: Mon, 13 Sep 2021 22:37:40 +0900 Subject: [PATCH 122/142] Add linux memory management --- .../linux-memory-management/han/README.md | 138 ++++++++++++++++++ 1 file changed, 138 insertions(+) create mode 100644 operating-system/linux-memory-management/han/README.md diff --git a/operating-system/linux-memory-management/han/README.md b/operating-system/linux-memory-management/han/README.md new file mode 100644 index 0000000..d619b34 --- /dev/null +++ b/operating-system/linux-memory-management/han/README.md @@ -0,0 +1,138 @@ +# Memory Management + +- 메모리 주소는 물리적, 논리적 주소 있음. +- `Logical Address` + - 가상 주소 + - 프로세스 마다 독립적으로 가지는 주소 공간 + - 0번지 부터 시작되고, + - **CPU가 보는 주소**임. +- `Physical Address` + - 물리 주소 + - 논리 주소에 + 하나의 주소 값이 더해진 값 (유일) + - 메모리에, 실제 올라가는 위치를 말함. +- `Symbolic Address` + - 코드 + - 컴파일러는 이 주소를 읽고, 논리 주소로 바꿔준다. + - 컴파일러가 심볼릭 주소를 논리 주소로 바꿔준 값은 중복 될 수 있음. + +> *Memory Management Unit* + +- 위에서도 살펴봤듯이, 컴파일러가 심볼릭 주소를 논리주소로 바꾸는 값은 중복될 수 있음. +- 그런데 CPU가 보는 값은 **논리 주소** +- 그러면 컴파일러로 바꾼 값이, 중복 될 수 있는데 어떻게 컴파일러 마다 독립적인 값을 메모리에서 찾을 수 있는 걸까? + - 하드웨어 적인 도움이 필요하다. + - 주소 변환을 위한 하드웨어 + - CPU 는 메모리에 접근할 떄, MMU의 도움을 받는다. + - base register, limit register 를 통해 이게 **해당 프로세스의 요청**이 맞는지 확인 (해당 프로세스 요청 범위에 맞는 물리적 주소인지 확인) + +## Swapping +- 프로세스를 일시적으로 메모리에서 backing store로 쫒아 내는 것. +- 우선 순위가 낮은 프로그램을 쫒아 냈다가, 다시 불러냈다가 하는 방법 +- 해당 방법을 실행하는 데 시간이 오래걸린다는 단점이 있음. + +## Dynamic Loading +- 그때 그때 필요할 때마다 메모리에 올리는 방식. + +## Overlays +- 프로세스 동작에 필요한 부분만 메모리에 올림. + +## Paging +- Non contiguous allocation (현대 컴퓨터에서 가장 많이 사용되는 기법) +- 물리 메모리를 동일한 크기의 frame으로 나누고, +- 논리 메모리(swap memory)를 동일한 크기의 page로 나눔 (frame가 같은 크기) + +![image](https://user-images.githubusercontent.com/22140570/132986737-81b8959c-388d-4c73-a5ee-d1d3d13aabdc.png) +- 페이지 테이블을 이용하여, 논리 - 물리 메모리간의 중간 다리 역할로 사용 +- 페이지 테이블을 프로세스 마다 존재, 그리고 이 페이지 테이블은 메모리에 저장됨. (Shared Page에 있음) +- TLB를 통해 페이지 테이블로의 접근 시도를 줄임. (최적화) + +> *TLB Translation Look aside Buffer* + +![image](https://user-images.githubusercontent.com/22140570/132986916-ccca529b-c1d3-4a97-b666-b2405c47ba61.png) +- 일종의 캐쉬 메모리 +- 주소 변환을 해주는 계층 +- CPU가 논리 주소를 요청하면, page table 에 접근하기 전에 우선적으로 살펴보는 공간. +- 여기 CPU에서 요청하는 논리 주소가 있으면 바로 변환해서 물리 메모리에서 가져옴. + - 없으면 page table을 참조해서 물리 주소를 가져옴. + - 그리고 요청한 논리 주소를 TLB에 저장해 둠 + + +# 리눅스가 메모리를 관리하는 방법 +- swap 공간에서 메모리 주소를 가져오려면 운영체제의 도움이 필요하다. + + +## 가상 메모리 사용 +- Virtual Memory + - Swap memory + physical memroy + +## I/O 장치 관리 +- CPU가 논리 주소를 요청하면, TLB에 있는 지 확인 +- 없으면, 해당 프로세스를 중단 +- 여기서 리눅스(운영체제) 등장 +- 운영체제는 해당 프로세스가 왜 멈췄는 지 다시 한번 확인 (악의적인 요청이 아닌지) +- 논리주소를 기반으로, 하드 디스크의 Swap 공간에서 해당하는 메모리 주소를 가져오고, TLB에 그 주소(논리)를 등록 +- Page table에 해당 주소 등록 +- 운영체제는 다시 프로세스를 동작 + +> *Page fault* +- CPU에서 요청한 논리 주소 값을 변환하여 메모리에서 찾았는 데, 해당 공간에 아무런 데이터가 없는 현상 +- 이 현상이 발생하면, 리눅스는 해당 논리주소에 대한 값을 disk 에서 찾는다. +- 그리고 physical memory에 올린다. +- 그 주소를 page table에 저장한다. + +> *Page replacement* +- page fault가 발생한다. +- page의 위치를 disk에서 찾는다. +- physical memory에 빈 공간이 있는 지 확인한다 (frame 확인) + - 있으면 해당 프레임 사용 + - 없으면? page replacement 진행 +- 물리 공간에서 쫒아낼 frame을 선정한다. +- 이 프레임을 disk에 저장한다. (page table도 업데이트) +- 올리고자 하는 정보를 비어있는 frame 에 올린다 (page table 또 업데이트) +- 이제 프로세스 다시 진행 + +> *Thrasing* +![image](https://user-images.githubusercontent.com/22140570/133093189-d6a033f1-ea4f-4f7b-b3a0-1da097fba6ad.png) + +- Page fault rate가 높아져서, CPU는 할일이 없어지는 현상 +- 프로세스 page는 swap in, out으로 매우 바쁘게 돌아가지만, 상대적으로 CPU는 한가해지는 현상을 의미한다. +- 이를 방지하고자 working set model, page-fault frequency 를 사용하기도 함 + + +# 메모리 고갈사항, CPU 사용률 확인 +- [htop](https://happist.com/557995/%EC%84%9C%EB%B2%84-%EB%AA%A8%EB%8B%88%ED%84%B0%EB%A7%81-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%A8-htop-%EC%82%AC%EC%9A%A9-%EB%B0%A9%EB%B2%95-ubuntu) 명령어를 통해, 모니터링 해보자 + +- 메모리 고갈되면 발생하는 사항 + - 프로세스 Swap 활발, CPU 사용율 하락 + - Thrashing 발생 + - 해소되지 않을 경우, Out of Memory 판단 + - 중요도가 낮은 프로세스를 찾아 강제 종료 + +- CPU 사용률 체크 + - CPU 사용률이 급격하게 떨어지는 구간이 있으면, + - 메모리 적재량 확인 (메모리가 고갈 되었다?) + - 추가적인 서버 자원을 배치 + +# 정리 + +## 페이징 기법 내에서 리눅스가 메모리를 가져오는 순서 + +![](https://t1.daumcdn.net/cfile/tistory/993CFA45600D5C1923?original) + +1. Symbolic address 가 컴파일러를 통해, Logical Address로 바꿔준다. +2. Logical Address를 통해 리눅스에 있는 **MMU** 로 보낸다 +3. Phsical Address로 변환 전에, 논리주소를 통해 TLB를 찾아본다. + - TLB에 논리주소에 맵핑된 값(물리 주소)이 있으면, 바로 해당 물리 주소에 있는 데이터를 불러옴. + - 없으면 다음 단계로. +4. Page table을 참조하여, 해당 물리 주소를 가져옴. 그리고 이 주소를 TLB에 저장해둔다. + - 이 과정에서 Page table에 논리 주소에 해당하는 값이 없으면 Page fault. + - 해당 page에 대한 정보를 disk 에서 찾는다. 그리고 메모리에 올린다. + - 만약에 메모리에 올릴 수 없으면? (Page replacement 진행) + + +# 참고 +- https://www.youtube.com/watch?v=qxmdX449z1U +- http://www.kyobobook.co.kr/product/detailViewKor.laf?ejkGb=KOR&mallGb=KOR&barcode=9791158903589 +- http://web.mit.edu/rhel-doc/4/RH-DOCS/rhel-isa-ko-4/s1-memory-virt-details.html +- https://wogh8732.tistory.com/395 +- https://m.blog.naver.com/4717010/220015472363 \ No newline at end of file From f39121566272ef90bc00bb9a7d2c043e37f43bb8 Mon Sep 17 00:00:00 2001 From: 102092 Date: Fri, 1 Oct 2021 20:58:05 +0900 Subject: [PATCH 123/142] Add qna --- .../linux-memory-management/han/README.md | 118 +++++++++++++++++- 1 file changed, 117 insertions(+), 1 deletion(-) diff --git a/operating-system/linux-memory-management/han/README.md b/operating-system/linux-memory-management/han/README.md index d619b34..1ddb286 100644 --- a/operating-system/linux-memory-management/han/README.md +++ b/operating-system/linux-memory-management/han/README.md @@ -135,4 +135,120 @@ - http://www.kyobobook.co.kr/product/detailViewKor.laf?ejkGb=KOR&mallGb=KOR&barcode=9791158903589 - http://web.mit.edu/rhel-doc/4/RH-DOCS/rhel-isa-ko-4/s1-memory-virt-details.html - https://wogh8732.tistory.com/395 -- https://m.blog.naver.com/4717010/220015472363 \ No newline at end of file +- https://m.blog.naver.com/4717010/220015472363 + + + +# QnA + +## Logical Address와 Physical Address가 별도로 존재하는 이유는 무엇일까요? + +- Multi-process 환경에서 발생할 수 있는 충돌을 최소화 하기 위해서 +- 혹은 한정된 Physical Memory, Address 에도, 좀 더 확장성 있게 사용하기 위해서 (Logical Address를 통해) + +- 참고 + - https://stackoverflow.com/questions/29771977/purpose-of-logical-address/47988290 + + + +## Address Binding에 대해 설명 + +- 데이터를 메모리에 올리는 걸 Address Binding이라 하는듯. +- 언제 올리는 지에 따라서.. + 1. Compile time에 메모리에 올릴 수 있고, + 2. 혹은 Load time 프록그램을 실행 전에 + 3. Execution time 실행 시에도 올릴 수 있음! (신기) + +- 참고 + +- https://jhnyang.tistory.com/133 + + + +## 컴파일러가 심볼릭 주소를 논리주소로 바꾸는 값은 중복될 수 있음 왜? + +![](https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F4zMbZ%2FbtqNqZGuKdJ%2Fo7F7BrEAr7ILddV77RESs1%2Fimg.png) + +- Address binding 과 관련 있는듯. + +- symbolic address는 컴파일을 통해 Logcial Addess로 변환 되는데, 이 때 나온 값이 중복 될 수 있음. +- 왜? + - 프로세스 별로 컴파일이라는 과정을 유니크하게 보장할 수는 없을듯. + + + +## MMU가 base register, limit register를 사용하는 이유 + +- Address binding 과 관련 있는듯. +- 프로세스 마다 접근할 수 있는 구역을 설정하기 위해서, 보장해주기 위해서 사용하는듯 + + + +## Dynamic Loading과 Virtual Memory는 어떤 관계 + +- CPU가 바라보는 주소가 있는 공간이 Virtual Memory +- Dynamic Loading의 경우, 메모리 공간을 효율적으로 사용하기 위한 기법 + +- 둘 다 메모리 부족을 해결하기 위해서 등장한 기법, 방법으로 이해되어요. + - 전자의 경우 Virtual Memory라는 가상공간을 통해서 Physical Memory의 부족을 해소 + - 후자의 경우 프로그램에서 사용하는 부분만 Physical Memory에 올림으로써 해소 + + + +## Dynamic Loading vs Overlays vs Virtual Memory vs Paging 차이 + +> Dynamic Loading + +- 프로그램을 Physical Memory에 동적(필요할 때 마다) 올림. +- 프로그래머가 직접 컨드롤할 수 있는 부분도 있는듯 (코드 레벨에서 조절할 수 있다는 의미인듯) + + + +> Overlays + +- Dynamic Loading과 비슷 +- 다만, 메모리보다 프로세스가 더 클 경우 사용되는 기법(Dynamic Loading은 이와 같을 경우 해결이 불가능한듯) + + + +> Virtual Memory + +- Physical Memory 부족을 위해 나온 개념 +- CPU가 바라보로 있는 주소이고, 프로세스마다 독립적인 공간을 보장받을듯 싶음. + + + +> Paging + +- Logical Address를 Page 라는 블록으로 분할하고 관리하는 기법 +- 즉 프로세스를 일정 크기로 잘라서 메모리에 적재하는 방식 +- 참고적으로 Page는 Logical Address를 나눈 크기를 의미하고, Frame은 Physical Memory를 나눈 크기를 의미 + + + +- 참고 + - https://jhnyang.tistory.com/44 + - https://jhnyang.tistory.com/290 + + + +## Page Fault 발생 과정 + +1. CPU 가 Logical Address를 가지고 page table에 들어감. +2. 이 때 가져온 Logical Address 해당 프로세스에서는 사용되지 않는 주소이던지, Logical Address에 해당하는 Physical Address의 주소가 Page Table에 없을 경우 Invalid 판단이 내려집니다. 이 경우 page fault handler가 실행되어요. +2.1 전자의 경우 해당 요청 명령이 abort되고, +2.2 후자의 경우 physical memory에 올라갈 공간 (frame)을 확보합니다. +3. 요청한 Logical Address에 대한 정보를 Disk에서 읽어서 Physical Memory에 가져옵니다. +4. 그리고 그에 대한 정보를 Page table을 업데이트 합니다. + + + +- 즉 위 절차를 통해 생각해볼 때, 메모리 공간 데이터의 경우 아래 2가지 시나리오가 있지 않을까 싶네요 + +1. 요청한 Logical Address에 대한 정보가 page table, physical memory 에도 없을 경우 (위 절차를 밟아서..다시 가져올듯) +2. 원하는 데이터가 physical memory(메모리)에 있는데, page table에는 없는 경우 아마도 MMU를 통해 메모리에서 찾은 후 page table을 업데이트하겠네요. + + + +- 참고 + - https://data-engineer.tistory.com/53 \ No newline at end of file From da9be3eba13738f9a9cc70fc0074e9cd5ff373e2 Mon Sep 17 00:00:00 2001 From: Jin Hyung Park Date: Sat, 9 Oct 2021 05:05:40 +0900 Subject: [PATCH 124/142] =?UTF-8?q?Deadlock=20=ED=95=99=EC=8A=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- operating-system/deadlock/sigrid/README.md | 83 ++++++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 operating-system/deadlock/sigrid/README.md diff --git a/operating-system/deadlock/sigrid/README.md b/operating-system/deadlock/sigrid/README.md new file mode 100644 index 0000000..b5f04fd --- /dev/null +++ b/operating-system/deadlock/sigrid/README.md @@ -0,0 +1,83 @@ +# 데드락이란 무엇인가 +## 정의 +* 운영체제에서 데드락이란, 시스템 자원에 대한 요구가 엇갈린 상태를 의미한다. +* 둘 이상의 프로세스가 다른 자원의 프로세스를 점유하다보니, 무한 대기(루프) 상태에 빠지게 되는 것을 의미한다. +* 즉, Deadlock은 다른 프로세스 또는 쓰레드가 소유한 자원을 요청한 행위가 서로에게 행해져 모든 프로세스 또는 쓰레드가 block이 되는 상태를 의미한다. +* A lock occurs when multiple processes try to access the same resource at the same time. + * One process loses out and must wait for the other to finish. +* A deadlock occurs when the waiting process is still holding on to another resource that the first needs before it can finish. +## 예시 1 +![](https://i.imgur.com/MEXzKoF.png) +* 쓰레드 T0이 리소스 1에 대한 Lock이 걸려 있는 상태이지만, 해당 쓰레드가 모든 일을 끝마치려면 리소스 2에 대한 자원이 필요한 상태이다. +* 쓰레드 T1이 리소스 2에 대한 Lock이 걸려 있는 상태이지만, 해당 쓰레드가 모든 일을 끝마치려면 리소스 1에 대한 자원이 필요한 상태이다. +## 예시 2 +### 서로가 사용하고 있는 Semaphore를 요청하여 Block에 걸리게 되는 경우 +* 다음과 같이 두 개의 코드가 주어졌다고 생각하자. +``` +Process1 +owns lock A +requests lock B +``` +``` +Process2 +owns lock B +requests lock A +``` +* 여기서 프로세스 1은 lock A를 갖고 있는데, 이는 A에 대한 세마포어(semaphore)를 갖고 있다는 뜻이다. 이와 달리, 프로세스 2는 lock B를 갖고 있는데, 이는 B에 대한 세마포어(semaphore)를 갖고 있다는 뜻이다. +* 세마포어는 한 곳에서 사용 중이라면, 다른 프로세스를 차단하는 목적으로 사용된다. 프로세스 1이 lock B를 요청할 경우, lock B는 현재 사용 중이므로 프로세스 1은 lock B가 release되기 전까지 Block 상태에서 대기하게 된다. +* 프로세스 2도 마찬가지이다. lock A를 요청할 경우, 현재 lock A는 사용 중이므로 프로세스 2는 lock A가 release되기 전까지 Block 상태에서 대기하게 된다. +![](https://i.imgur.com/n86eluU.png) +## 예시 3 +### Recursive Lock +* 프로세스 1이 한 semaphore를 갖고 있다. 해당 semaphore는 다른 프로세스가 접근할 수 없게 된다. 이 떄, 프로세스 1은 똑같은 semaphore에 접근을 요청한다. 이러한 경우, 해당 semaphore는 접근할 수 없음으로 데드락에 빠지게 된다. +![](https://i.imgur.com/a6f89wO.png) +## 예시 4 +### 범죄자와 경찰 +![](https://i.imgur.com/lWTXmAi.png) +* Imagine a criminal holds an hostage and against that, a cop also holds an hostage who is a friend of the criminal. In this case, criminal is not going to let the hostage go if cop won't let his friend to let go. Also the cop is not going to let the friend of criminal let go, unless the criminal releases the hostage. This is an endless untrustworthy situation, because both sides are insisting the first step from each other. +* So simply, when two threads needs two different resources and each of them has the lock of the resource that the other need, it is a deadlock. + +## Deadlock의 상태 +* 일반적으로 프로세스는 리소스를 사용하기 위해서는 사전에 요청을 거쳐야 하고, 다음과 같은 과정을 거친다. + * Request: 리소스 사용을 요청할 때 즉각 받아들여지지 않는다면, 프로세스는 리소스 사용이 가능해질 때까지 대기해야 한다. 주된 함수 연산으로는 ```call(), malloc()``` 등이 있다. + * Use: 쓰레드가 자원을 사용하는 단계이다. 프린터를 사용하고 있거나, 파일을 읽고 있다. + * Release: 프로세스는 리소스 사용을 중지(relinquish)한다. 따라서 해당 자원은 다른 프로세스가 사용 가능해진다. 주된 함수 연산으로는 ```close(), free(), delete()``` 등이 있다. +* 커널이 매니징하느냐? 애플리케이션이 매니징하느냐? 에 따라 차이가 있는데 아무래도 커널이 관리해주는 것이 개발자 입장에서는 불필요한 소요를 줄이는 일이지 않을까 싶다. + * 커널이 매니징한다는 것은, 커널이 어떤 리소스가 free이고 어디에 allocate 되어 있고를 모두 파악한다는 소리다. 현재 process의 queue를 관리해서 어느 프로세스가 다음 리소스의 사용을 원하는 지를 확인한다. + * Application이 매니징한다는 것은, mutex나 wait(), signal() 함수 호출로 인하여 컨트롤 되는 것을 의미한다. + +## Deadlock의 4가지 조건 +* Mutual Exclusion: 최소 한 개의 리소스가 non-sharable한 상태로 특정한 프로세스나 쓰레드에 의해 사용되고 있어야 한다. 만약 다른 프로세스가 해당 리소스 사용 요청을 보내면, 해당 프로세스는 리소스가 사용 가능할 때까지 기다려야 한다. +* Hold and Wait: 프로세스는 동시에 하나의 리소스를 갖고 있으면서 또 다른 프로세스나 쓰레드가 점유하고 있는 리소스 사용을 요청할 수 있다. +* No Preemption: 임의의 프로세스가 리소스를 소유한다고 가정하자. 그렇다면 다른 프로세스나 쓰레드는 해당 프로세스나 쓰레드가 스스로 리소스를 내려 놓기 전까지는 강제로 끌어내릴 수 없다. +* Circular wait: A set of processes { P0, P1, P2, . . ., PN } must exist such that every P[ i ] is waiting for P[ ( i + 1 ) % ( N + 1 ) ]. (해당 조건은 Hold and Wait 조건을 support하는 것 같다) + +## 데드락, 어떻게 해결할 것인가 +## 데드락을 예방 Prevention 하기 +* Not allowing the system to get into a deadlocked state. 위의 4가지 조건을 모두 충족시키지 않으면서 가능하다. +* 자원의 상호 배제 조건 방지 : 한 번에 여러 프로세스가 공유 자원을 사용할 수 있게 한다. 다만, 추후 동기화 문제가 생길 수 있다. +* 점유 대기 조건 방지 : 프로세스 실행에 필요한 모든 자원을 한꺼번에 요구하고 허용할 때까지 작업을 보류해서, 나중에 또다른 자원을 점유하기 위한 대기 조건을 성립하지 않도록 한다. +* 비선점 조건 방지 : 이미 다른 프로세스에게 할당된 자원이 선점권이 없다고 가정할 때, 높은 우선순위의 프로세스가 해당 자원을 선점할 수 있도록 합니다. +* 순환 대기 조건 방지 : 자원을 순환 형태로 대기하지 않도록 일정한 한 쪽 방향으로만 자원을 요구할 수 있도록 합니다. +* 데드락 예방(Prevention)은 시스템의 처리량이나 효율성을 떨어트리는 단점이 있다. + +### 데드락 회피(avoidance) +* 시스템의 프로세스들이 요청하는 모든 자원을, 데드락을 발생시키지 않으면서도 차례로 모두에게 할당해 줄 수 있다면 안정 상태(safe state)에 있다고 한다. +* 그리고 이처럼 특정한 순서로 프로세스들에게 자원을 할당, 실행 및 종료 등의 작업을 할 때 데드락이 발생하지 않는 순서를 찾을 수 있다면, 그것을 안전 순서(safe sequence)라고 부른다. +* 불안정 상태는 안정 상태가 아닌 상황을 말한다. 데드락 발생 가능성이 있는 상황이며, 교착 상태(데드락)는 불안정 상태일 때 발생할 수 있다. +* 회피 알고리즘은 자원을 할당한 후에도 시스템이 항상 Safe state에 있을 수 있도록 할당을 허용하자는 것이 특징이다. +* 은행원 알고리즘: 은행원 알고리즘의 경우, 이처럼 미리 최대 자원 요구량을 알아야 하고, 할당할 수 있는 자원 수가 일정해야 하는 등 사용에 있어 제약조건이 많고, 그에 따른 자원 이용도 하락 등의 문제가 있을 수 있다. + +### 데드락 탐지 및 회복(Detection) +* 탐지 + * Allocation, Request, Available 등으로 시스템에 데드락이 발생했는지 여부를 탐색 + * 현재 시스템의 자원 할당 상태를 파악 +* 회복 + * 순환 대기에서 벗어나 데드락으로부터 회복하기 위한 방법을 사용 + * 단순히 프로세스를 1개 이상 중단시키기: 상태에 빠진 모든 프로세스를 중단하거나, 프로세스를 하나씩 중단 시킬 때마다 탐지 알고리즘으로 데드락을 탐지하면서 회복시키는 방법: 매번 탐지 알고리즘을 호출 및 수행해야 하므로 부담이 되는 작업일 수 있음 + * 자원 선점하기: 프로세스에 할당된 자원을 선점해서, 교착 상태를 해결할 때까지 그 자원을 다른 프로세스에 할당해 주는 방법 + +#### Reference +* 더 알아보기 좋은 자료(영문): https://www.cs.uic.edu/~jbell/CourseNotes/OperatingSystems/7_Deadlocks.html +* https://stackoverflow.com/questions/34512/what-is-a-deadlock +* https://chanhuiseok.github.io/posts/cs-2/ From ac26bf2acfa475dd63c2724b358072095c5571da Mon Sep 17 00:00:00 2001 From: 102092 Date: Sun, 10 Oct 2021 22:48:52 +0900 Subject: [PATCH 125/142] Fix typo --- .../sigrid/README.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename operating-system/{linux-memory-managment => linux-memory-management}/sigrid/README.md (100%) diff --git a/operating-system/linux-memory-managment/sigrid/README.md b/operating-system/linux-memory-management/sigrid/README.md similarity index 100% rename from operating-system/linux-memory-managment/sigrid/README.md rename to operating-system/linux-memory-management/sigrid/README.md From a31706fa01518f95c042f1ad4e057b3f4acc6195 Mon Sep 17 00:00:00 2001 From: 102092 Date: Sun, 10 Oct 2021 22:49:57 +0900 Subject: [PATCH 126/142] Revert deadlock --- operating-system/deadlock/sigrid/README.md | 83 ---------------------- 1 file changed, 83 deletions(-) delete mode 100644 operating-system/deadlock/sigrid/README.md diff --git a/operating-system/deadlock/sigrid/README.md b/operating-system/deadlock/sigrid/README.md deleted file mode 100644 index b5f04fd..0000000 --- a/operating-system/deadlock/sigrid/README.md +++ /dev/null @@ -1,83 +0,0 @@ -# 데드락이란 무엇인가 -## 정의 -* 운영체제에서 데드락이란, 시스템 자원에 대한 요구가 엇갈린 상태를 의미한다. -* 둘 이상의 프로세스가 다른 자원의 프로세스를 점유하다보니, 무한 대기(루프) 상태에 빠지게 되는 것을 의미한다. -* 즉, Deadlock은 다른 프로세스 또는 쓰레드가 소유한 자원을 요청한 행위가 서로에게 행해져 모든 프로세스 또는 쓰레드가 block이 되는 상태를 의미한다. -* A lock occurs when multiple processes try to access the same resource at the same time. - * One process loses out and must wait for the other to finish. -* A deadlock occurs when the waiting process is still holding on to another resource that the first needs before it can finish. -## 예시 1 -![](https://i.imgur.com/MEXzKoF.png) -* 쓰레드 T0이 리소스 1에 대한 Lock이 걸려 있는 상태이지만, 해당 쓰레드가 모든 일을 끝마치려면 리소스 2에 대한 자원이 필요한 상태이다. -* 쓰레드 T1이 리소스 2에 대한 Lock이 걸려 있는 상태이지만, 해당 쓰레드가 모든 일을 끝마치려면 리소스 1에 대한 자원이 필요한 상태이다. -## 예시 2 -### 서로가 사용하고 있는 Semaphore를 요청하여 Block에 걸리게 되는 경우 -* 다음과 같이 두 개의 코드가 주어졌다고 생각하자. -``` -Process1 -owns lock A -requests lock B -``` -``` -Process2 -owns lock B -requests lock A -``` -* 여기서 프로세스 1은 lock A를 갖고 있는데, 이는 A에 대한 세마포어(semaphore)를 갖고 있다는 뜻이다. 이와 달리, 프로세스 2는 lock B를 갖고 있는데, 이는 B에 대한 세마포어(semaphore)를 갖고 있다는 뜻이다. -* 세마포어는 한 곳에서 사용 중이라면, 다른 프로세스를 차단하는 목적으로 사용된다. 프로세스 1이 lock B를 요청할 경우, lock B는 현재 사용 중이므로 프로세스 1은 lock B가 release되기 전까지 Block 상태에서 대기하게 된다. -* 프로세스 2도 마찬가지이다. lock A를 요청할 경우, 현재 lock A는 사용 중이므로 프로세스 2는 lock A가 release되기 전까지 Block 상태에서 대기하게 된다. -![](https://i.imgur.com/n86eluU.png) -## 예시 3 -### Recursive Lock -* 프로세스 1이 한 semaphore를 갖고 있다. 해당 semaphore는 다른 프로세스가 접근할 수 없게 된다. 이 떄, 프로세스 1은 똑같은 semaphore에 접근을 요청한다. 이러한 경우, 해당 semaphore는 접근할 수 없음으로 데드락에 빠지게 된다. -![](https://i.imgur.com/a6f89wO.png) -## 예시 4 -### 범죄자와 경찰 -![](https://i.imgur.com/lWTXmAi.png) -* Imagine a criminal holds an hostage and against that, a cop also holds an hostage who is a friend of the criminal. In this case, criminal is not going to let the hostage go if cop won't let his friend to let go. Also the cop is not going to let the friend of criminal let go, unless the criminal releases the hostage. This is an endless untrustworthy situation, because both sides are insisting the first step from each other. -* So simply, when two threads needs two different resources and each of them has the lock of the resource that the other need, it is a deadlock. - -## Deadlock의 상태 -* 일반적으로 프로세스는 리소스를 사용하기 위해서는 사전에 요청을 거쳐야 하고, 다음과 같은 과정을 거친다. - * Request: 리소스 사용을 요청할 때 즉각 받아들여지지 않는다면, 프로세스는 리소스 사용이 가능해질 때까지 대기해야 한다. 주된 함수 연산으로는 ```call(), malloc()``` 등이 있다. - * Use: 쓰레드가 자원을 사용하는 단계이다. 프린터를 사용하고 있거나, 파일을 읽고 있다. - * Release: 프로세스는 리소스 사용을 중지(relinquish)한다. 따라서 해당 자원은 다른 프로세스가 사용 가능해진다. 주된 함수 연산으로는 ```close(), free(), delete()``` 등이 있다. -* 커널이 매니징하느냐? 애플리케이션이 매니징하느냐? 에 따라 차이가 있는데 아무래도 커널이 관리해주는 것이 개발자 입장에서는 불필요한 소요를 줄이는 일이지 않을까 싶다. - * 커널이 매니징한다는 것은, 커널이 어떤 리소스가 free이고 어디에 allocate 되어 있고를 모두 파악한다는 소리다. 현재 process의 queue를 관리해서 어느 프로세스가 다음 리소스의 사용을 원하는 지를 확인한다. - * Application이 매니징한다는 것은, mutex나 wait(), signal() 함수 호출로 인하여 컨트롤 되는 것을 의미한다. - -## Deadlock의 4가지 조건 -* Mutual Exclusion: 최소 한 개의 리소스가 non-sharable한 상태로 특정한 프로세스나 쓰레드에 의해 사용되고 있어야 한다. 만약 다른 프로세스가 해당 리소스 사용 요청을 보내면, 해당 프로세스는 리소스가 사용 가능할 때까지 기다려야 한다. -* Hold and Wait: 프로세스는 동시에 하나의 리소스를 갖고 있으면서 또 다른 프로세스나 쓰레드가 점유하고 있는 리소스 사용을 요청할 수 있다. -* No Preemption: 임의의 프로세스가 리소스를 소유한다고 가정하자. 그렇다면 다른 프로세스나 쓰레드는 해당 프로세스나 쓰레드가 스스로 리소스를 내려 놓기 전까지는 강제로 끌어내릴 수 없다. -* Circular wait: A set of processes { P0, P1, P2, . . ., PN } must exist such that every P[ i ] is waiting for P[ ( i + 1 ) % ( N + 1 ) ]. (해당 조건은 Hold and Wait 조건을 support하는 것 같다) - -## 데드락, 어떻게 해결할 것인가 -## 데드락을 예방 Prevention 하기 -* Not allowing the system to get into a deadlocked state. 위의 4가지 조건을 모두 충족시키지 않으면서 가능하다. -* 자원의 상호 배제 조건 방지 : 한 번에 여러 프로세스가 공유 자원을 사용할 수 있게 한다. 다만, 추후 동기화 문제가 생길 수 있다. -* 점유 대기 조건 방지 : 프로세스 실행에 필요한 모든 자원을 한꺼번에 요구하고 허용할 때까지 작업을 보류해서, 나중에 또다른 자원을 점유하기 위한 대기 조건을 성립하지 않도록 한다. -* 비선점 조건 방지 : 이미 다른 프로세스에게 할당된 자원이 선점권이 없다고 가정할 때, 높은 우선순위의 프로세스가 해당 자원을 선점할 수 있도록 합니다. -* 순환 대기 조건 방지 : 자원을 순환 형태로 대기하지 않도록 일정한 한 쪽 방향으로만 자원을 요구할 수 있도록 합니다. -* 데드락 예방(Prevention)은 시스템의 처리량이나 효율성을 떨어트리는 단점이 있다. - -### 데드락 회피(avoidance) -* 시스템의 프로세스들이 요청하는 모든 자원을, 데드락을 발생시키지 않으면서도 차례로 모두에게 할당해 줄 수 있다면 안정 상태(safe state)에 있다고 한다. -* 그리고 이처럼 특정한 순서로 프로세스들에게 자원을 할당, 실행 및 종료 등의 작업을 할 때 데드락이 발생하지 않는 순서를 찾을 수 있다면, 그것을 안전 순서(safe sequence)라고 부른다. -* 불안정 상태는 안정 상태가 아닌 상황을 말한다. 데드락 발생 가능성이 있는 상황이며, 교착 상태(데드락)는 불안정 상태일 때 발생할 수 있다. -* 회피 알고리즘은 자원을 할당한 후에도 시스템이 항상 Safe state에 있을 수 있도록 할당을 허용하자는 것이 특징이다. -* 은행원 알고리즘: 은행원 알고리즘의 경우, 이처럼 미리 최대 자원 요구량을 알아야 하고, 할당할 수 있는 자원 수가 일정해야 하는 등 사용에 있어 제약조건이 많고, 그에 따른 자원 이용도 하락 등의 문제가 있을 수 있다. - -### 데드락 탐지 및 회복(Detection) -* 탐지 - * Allocation, Request, Available 등으로 시스템에 데드락이 발생했는지 여부를 탐색 - * 현재 시스템의 자원 할당 상태를 파악 -* 회복 - * 순환 대기에서 벗어나 데드락으로부터 회복하기 위한 방법을 사용 - * 단순히 프로세스를 1개 이상 중단시키기: 상태에 빠진 모든 프로세스를 중단하거나, 프로세스를 하나씩 중단 시킬 때마다 탐지 알고리즘으로 데드락을 탐지하면서 회복시키는 방법: 매번 탐지 알고리즘을 호출 및 수행해야 하므로 부담이 되는 작업일 수 있음 - * 자원 선점하기: 프로세스에 할당된 자원을 선점해서, 교착 상태를 해결할 때까지 그 자원을 다른 프로세스에 할당해 주는 방법 - -#### Reference -* 더 알아보기 좋은 자료(영문): https://www.cs.uic.edu/~jbell/CourseNotes/OperatingSystems/7_Deadlocks.html -* https://stackoverflow.com/questions/34512/what-is-a-deadlock -* https://chanhuiseok.github.io/posts/cs-2/ From 4a3dcee99b1168e2017f86e1c7bc930b70084e8f Mon Sep 17 00:00:00 2001 From: 102092 Date: Sun, 10 Oct 2021 23:26:39 +0900 Subject: [PATCH 127/142] Add deadlock --- operating-system/deadlock/han/README.md | 125 ++++++++++++++++++++++++ 1 file changed, 125 insertions(+) create mode 100644 operating-system/deadlock/han/README.md diff --git a/operating-system/deadlock/han/README.md b/operating-system/deadlock/han/README.md new file mode 100644 index 0000000..ca01381 --- /dev/null +++ b/operating-system/deadlock/han/README.md @@ -0,0 +1,125 @@ +# Deadlock이란? + +- 교착 상태 +- 프로세스나 스레드가, 어떤 특정 이벤트를 기다리고 있는데, 그 이벤트는 발생할 수 없는 상태에 놓여있음. + - 즉 쓸 데 없이, 기다리고 있는 상태를 의미하는듯. + + + +## 실제 시스템에서 교착 상태 + +- Database (MySQL) + + - **상호 거래 패턴** + + ![image](https://user-images.githubusercontent.com/22140570/136698857-2e340bae-151d-47fa-85a1-c22c007c8f0e.png) + + - 트랜잭션 1 은 A를 점유하고 있음., 트랜잭션 2는 B를 점유하고 있음. + - 이 상태에서 트랜잭션1 는 B에게 접근하려 함 (이미 트랜잭션 2가 점유하고 있는 상태) + - 그런데 트랜잭션 2은 A에 접근하려 함 (이미 트랜잭션 1이 점유하고 있는 상태임) + - 점유가 풀려야, 해당 데이터에 접근할 수 있는데, 현재 상태로 보아서, 점유가 풀릴 수가 없는 상태임. (교착 상태) + + + +## 교착 상태를 만족하기 위한 4가지 필요조건 + +- 아래 4가지 조건은 만족하게 되면, 교착 상태에 빠지게 된다. + + + +### 상호 배제 조건 + +- mutual exclusion condition +- 한번에 프로세스 하나만 해당 자원을 사용할 수 있음. + - 다른 프로세스가 위 자원을 사용하려 하면, 기다려야 한다. + + + +### 점유와 대기 조건 + +- hold and wait condition +- 자원을 최소한 하나 보유하고, 다른 프로세스에 할당된 자원을 위해 대기하는 프로세스가 존재. + + + +### 비 선점 조건 + +- nopremption condition +- 이미 할당된 자원을 강제로 뻈을수는 없음 + + + +### 순환 대기 조건 + +- circular wait conditon +- 대기 프로세스의 집합이 순한 형태로 자원을 대기 + + + + + +## 교착 상태 해결 방법 + +### 예방 + +- 위 4가지 발생 조건 중에, 하나라도 발생하지 않도록 하는 것. +- 예를 들면 상호 배제 조건 의 경우, **여러 프로세스** 들이 해당 자원을 사용할 수 있도록 해주는 것. + + + +### 회피 + +> *Safe sequence, Safe state* + +- 안전 상태? + - 프로세스들이 요청하는 모든 자원을, 교착 상태에 빠지지 않으면서 모두에게 자원을 할당해줄 수 있는 상태 +- 안전 순서? + - 특정 순서로 프로세스들에게 자원을 할당해줬더니, 교착 상태가 발생하지 않았음. 이러한 순서. +- 불안전 상태? + - 안전 상태가 아닌 상태 + - 교착 상태 발생 가능성이 있다. + +- 은행원 알고리즘 + + - 시스템을 안전 / 불안전 상태로 구분 + - 불안전 상태이면, 할당할 자원을 고정, 프로세스 수도 고정, 제한된 시간안에 자원 반납등의 조건이 전제됨. + +- 회피 전략을 즉 자원을 요청할 때마다, 시스템의 안전 상태를 파악해야함 (오버헤드 심함) + + - 이러한 점 때문에, 해당 전략을 사용하는 시스템은 거의 없다. + + + +### 탐지 및 복구 + +- 교착 상태가 자주 발생한다면 사용. +- 교착 상태는 **필요악** + - 왜? + - 교착 상태는 안 만들어지는게 좋지만, 교착 상태가 발생할 수 없는 환경을 만들어 버린다면, 할당된 자원을 효율적으로 사용하는 것은 불가능한 일이 됨. +- 탐지 + - Allocation, Request, Available + - **순환 대기 조건**이 존재하는 지 탐지함 (시스템의 자원 상태를 확인함) + - 탐지 알고리즘을 사용..해서 오버헤드 존재 + +- 복구 + - 순환 대기를 깨서, 교착 상태로 부터 회복하도록 함. + - 순환 대기에 포함된 프로세스의 제어권을 빼고 롤백.. 혹은 순환 대기가 깨질 때까지 프로세스 종료 + - 어떤 프로세스를 깰까? + - 시스템마다 다른 기준으로 우선 순위 + - MySQL의 경우, 트랜잭션의 크기가 가장 작은.. + +### 무시 + +- 교착 상태가 드물게 발생한다면 이 방법을 사용 +- 드물게 발생하는데, 굳이 교착 상태 해결 비용을 미리 지불할 필요는 없을듯. +- 즉 교착 상태가 발생했다? 그러면 사용자가 원인이 되는 프로세스, 스레드를 죽이는 방법을 택함. + + + +# 참고 + +- https://www.youtube.com/watch?v=FXzBRD3CPlQ + +- https://chanhuiseok.github.io/posts/cs-2/ +- http://www.kyobobook.co.kr/product/detailViewKor.laf?mallGb=KOR&ejkGb=KOR&barcode=9788993712476 + From 50e37b891ffabd935da010586952858ddcb4836d Mon Sep 17 00:00:00 2001 From: 102092 Date: Mon, 11 Oct 2021 16:59:07 +0900 Subject: [PATCH 128/142] Add extra --- operating-system/deadlock/han/README.md | 52 ++++++++++++++++++++----- 1 file changed, 42 insertions(+), 10 deletions(-) diff --git a/operating-system/deadlock/han/README.md b/operating-system/deadlock/han/README.md index ca01381..a9a175c 100644 --- a/operating-system/deadlock/han/README.md +++ b/operating-system/deadlock/han/README.md @@ -1,10 +1,12 @@ # Deadlock이란? - 교착 상태 -- 프로세스나 스레드가, 어떤 특정 이벤트를 기다리고 있는데, 그 이벤트는 발생할 수 없는 상태에 놓여있음. - - 즉 쓸 데 없이, 기다리고 있는 상태를 의미하는듯. +- 둘 이상의 프로세스가 각자가 가지고 있는 자원을 보유한 채, 외부 조치 없는 한 영원히 그 상태에서 기다리고 있는 상황을 의미. + - 즉 어떤 자원을 가지고 있고 + 무슨 이유에서 인지, 외부 조치 없이는 무조건 기다리게 되어있는 상황을 의미 + + ## 실제 시스템에서 교착 상태 @@ -24,34 +26,48 @@ ## 교착 상태를 만족하기 위한 4가지 필요조건 - 아래 4가지 조건은 만족하게 되면, 교착 상태에 빠지게 된다. + - 아래 4가지 중에 하나만이라도 생기지 않도록 할 수 있다면, 교착 상태는 절대 발생하지 않는다. ### 상호 배제 조건 -- mutual exclusion condition +> *mutual exclusion condition* + +- 자원의 배타적인 사용이라 부르기도 함. + - 한번에 프로세스 하나만 해당 자원을 사용할 수 있음. - 다른 프로세스가 위 자원을 사용하려 하면, 기다려야 한다. + - 한정된 자원에 대한 프로세스들의 사용 경쟁을 의미. ### 점유와 대기 조건 -- hold and wait condition -- 자원을 최소한 하나 보유하고, 다른 프로세스에 할당된 자원을 위해 대기하는 프로세스가 존재. +> *hold and wait condition* + +- 자원의 부분 할당이라 부르기도 함. + - 각각의 프로세스는 자신의실행 전체 과정에서 자원이 필요할 때 마다, 일부분을 확보, 실행해나가다가, 할당 불가능한 자원 때문에 교착 상태에 빠진다. + +- 즉 프로세스는 자원을 최소한 하나 보유하고, 다른 프로세스에 할당된 자원을 위해 대기하는 프로세스가 존재함을 의미. ### 비 선점 조건 -- nopremption condition +> *nopremption condition* + +- 자원의 선점 불가능성이라 부르기도 함. + - 이미 할당된 자원을 강제로 뻈을수는 없음 + - 즉 자원의 선점 불가능성을 고수하는 경우, 해당 조건 때문에 교착 상태를 일으키는 조건을 만족하게 되기도 함. ### 순환 대기 조건 -- circular wait conditon +> *circular wait conditon* + - 대기 프로세스의 집합이 순한 형태로 자원을 대기 @@ -63,7 +79,17 @@ ### 예방 - 위 4가지 발생 조건 중에, 하나라도 발생하지 않도록 하는 것. -- 예를 들면 상호 배제 조건 의 경우, **여러 프로세스** 들이 해당 자원을 사용할 수 있도록 해주는 것. +- 예를 들면.. + - 상호 배제 조건 의 경우, **여러 프로세스** 들이 해당 자원을 사용할 수 있도록 해주는 것. + - 다만, 배타적으로 사용할 수 밖에 없는 자원도 있기에, 상호 배제 조건을 배제하는건 불가능할듯. + - 점유와 대기 조건의 경우, 자원이 부분할당 되지 않고, 필요한 자원을 모두 할당해 버리는 것. + - 자원의 낭비 발생. 심각하게.. + - 비 선점 조건의 경우, 모든 자원이 선점 가능하도록 해주는 것. + - 즉 어떤 자원을 A 프로세스가 잡고 실행 중에 있는데, B 프로세스 에서 해당 자원을 요청할 경우, A프로세스는 자신이 보유하고 있는 자원을 내놔야함. + - A 프로세스 입장에서는.. 잘 하고 있는 도중 자신의 일의 결과를 모두 뺏길 수 있음 (중단 혹은 다시 시작 가능성 있으므로.) + - 자원 낭비 + - 순환 대기 조건을 배제하는 경우, 자원의 요청 순서를 단 방향으로만 하도록 하는 것일듯. + - 그래도 자원 낭비, 무한 대기는 피해갈 수 없을듯. (모든 경우의 수를 따질 수 없으므로) @@ -71,6 +97,8 @@ > *Safe sequence, Safe state* +- 교착 상태를 피해가게 하는 방법 + - 안전 상태? - 프로세스들이 요청하는 모든 자원을, 교착 상태에 빠지지 않으면서 모두에게 자원을 할당해줄 수 있는 상태 - 안전 순서? @@ -97,13 +125,17 @@ - 왜? - 교착 상태는 안 만들어지는게 좋지만, 교착 상태가 발생할 수 없는 환경을 만들어 버린다면, 할당된 자원을 효율적으로 사용하는 것은 불가능한 일이 됨. - 탐지 + - RAG Resource Allocation Graph + - 자원 할당 그래프. + - 교착 상태 탐지를 위해, 현 시스템의 상황을 나타내는 그래프임. - Allocation, Request, Available - **순환 대기 조건**이 존재하는 지 탐지함 (시스템의 자원 상태를 확인함) - 탐지 알고리즘을 사용..해서 오버헤드 존재 - - 복구 - 순환 대기를 깨서, 교착 상태로 부터 회복하도록 함. - - 순환 대기에 포함된 프로세스의 제어권을 빼고 롤백.. 혹은 순환 대기가 깨질 때까지 프로세스 종료 + - 순환 대기에 포함된 **프로세스의 제어권을 뺏고 롤백**.. 혹은 순환 대기가 깨질 때까지 **프로세스 종료** + - 전자 최소 비용의 프로세스를 고를 수 있지만, 이를 계산하는 데 복잡 + - 후자 프로세스를 종료할 때 마다, 교착 상태가 해결 되었는지 확인해야함 (오버헤드) - 어떤 프로세스를 깰까? - 시스템마다 다른 기준으로 우선 순위 - MySQL의 경우, 트랜잭션의 크기가 가장 작은.. From c1c26fce2936b5dd46bc5604e86cdb81c6108290 Mon Sep 17 00:00:00 2001 From: 102092 Date: Mon, 11 Oct 2021 17:43:30 +0900 Subject: [PATCH 129/142] Add context-switch --- operating-system/context-switch/han/README.md | 98 +++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 operating-system/context-switch/han/README.md diff --git a/operating-system/context-switch/han/README.md b/operating-system/context-switch/han/README.md new file mode 100644 index 0000000..20e41a8 --- /dev/null +++ b/operating-system/context-switch/han/README.md @@ -0,0 +1,98 @@ + + +# Interrupt + +- 프로세스가 하던일을 멈추고, *이미 정해진 코드*에서 요청에 대한 처리를 **수행**하는 것. +- 각 자원들이 능동적으로 자신의 상태 변화를 CPU에게 알리는 방식. + +- `Polling` + - *CPU*가 일정한 시간 간격을 두고, 각 장원들의 상태를 주기적으로 확인하는 방법 + - Interrupt는 자원들이 CPU에게 자신의 상태를 알리는 방법이고.. +- 인터럽트는 하드웨어, 소프트웨어 인터럽트로 나눌수 있을듯. + - 하드웨어는.. 모니터 마우스 등등이고.. + - 소프트웨어는 CPU 자신이 인터럽트를 사용하는 경우 인듯. + + + +- Interrupt가 실행되는 과정 + + ![image](https://user-images.githubusercontent.com/22140570/136755289-4b270209-cbc6-4250-8070-1e76658b5c5d.png) + + - PC ? + - CPU가 실행하는 명령어 + - 레지스터에 있음 + + 2. 장치 (키보드) 의 인터럽트 발생 + + 3. 현재 실행 중인 프로세스 정보 저장 + 1. 어디에? 시스템 스택에. + 2. 어떤 정보? PSW(Program status Word, 현재 상태 정보), PC 레지스터의 값 (CPU가 어떤 명령어를 실행하고 있었는지 ) + + 4. Interrupt Vector에 가서, 요청들어온 인터럽트에 대한 ISR을 찾음. + + 5. 찾은 ISR에 대한 주소를 PC에 넣음 (인터럽트 처리를 위해서..) + + 6. 인터럽트 처리 + + 7. 저장된 프로세스 정보를 가져와서, 이 전 실행 되었던 프로세스 실행으로 돌아감 + +- 참고 키워드 + - Interrupt Service Routine, ISR (Interrupt Handler) + - Interrupt Vector + - 여러가지 인터럽트들을 관리하는 테이블 + + + +# Context switching + +- 위 이미지에서 (3,4,5)번 과정 + +- 하나의 프로세스가 cpu를 사용하는 상태인데, 다른 프로세스가 cpu를 사용하게 하기 위해서... 발생하는 것. + + - 즉 이전 프로세스의 상태를 **보관** 하고, 새롭게 실행된 프로세스의 상태를 **적재하도록 하는 과정**, 작업을 의미. + +- 과정 + + ![image](https://user-images.githubusercontent.com/22140570/136755834-7938b4ae-86bb-408e-8cb4-ee7fc909435a.png) + + - 인터럽트 과정과 같음 + + 1. P0 실행 중.. 그런데 P1 프로세스에서 인터럽트 or 시스템 콜 발생 + 2. P0 프로세스에 대한 정보를 PCB에 저장. 그리고 P1에 대한 정보를 PCB에서 찾아서, 메모리에 올림 + 3. P1 실행 + 4. 위 반복. + + + +- Context Switching이 왜 발생? + - CPU는 한번에 하나의 프로세스만 처리할 수 있기에. + - 여러 프로세스를 실행, 중단 하면서 작동하기에. + - 이 비용이 비싸기에, Mutil Thread 환경이 나오지 않았을까 + + + +- 참고 키워드 + - idle : CPU가 아무일도 하지 않는 상태 + - idle이 겹칠 경우를 오버 헤드라 말함. + - 왜? + - 필요한 정보들을 적재하느라, CPU가 아무일도 하지 않는 상태이기 때문에 (일을 안해서, CPU가 낭비되고 있음) + - 즉 프로세스가 많아지면, 적재과정 때문에 CPU가 안하는 일이 많아져서 오버헤드가 증가할듯. + - PCB (Process Control Block) + - 레지스터에 있고, Queue (LIFO) 구조임. + + - process state : 프로세스 상태 값 (Create, Ready, Runinng..) + + - procuess counter : CPU가 다음 실행할 명령어의 주소 값. + + + ![](https://nesoy.github.io/assets/posts/20181113/1.png) + + + +# 참고 + +- https://www.youtube.com/watch?v=-4HKhwlH3FQ +- http://www.kyobobook.co.kr/product/detailViewKor.laf?mallGb=KOR&ejkGb=KOR&barcode=9788993712476 +- https://nesoy.github.io/articles/2018-11/Context-Switching +- https://jeong-pro.tistory.com/93 + From ffacebfd9ef7b064f22ac2197b59d2b840f028c0 Mon Sep 17 00:00:00 2001 From: 102092 Date: Mon, 11 Oct 2021 17:44:58 +0900 Subject: [PATCH 130/142] Clean up --- operating-system/context-switch/han/README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/operating-system/context-switch/han/README.md b/operating-system/context-switch/han/README.md index 20e41a8..5fac1af 100644 --- a/operating-system/context-switch/han/README.md +++ b/operating-system/context-switch/han/README.md @@ -1,5 +1,3 @@ - - # Interrupt - 프로세스가 하던일을 멈추고, *이미 정해진 코드*에서 요청에 대한 처리를 **수행**하는 것. From c0fb286fa3e14675f94fdf40cf8f8e7f58b9bbda Mon Sep 17 00:00:00 2001 From: Han Date: Tue, 12 Oct 2021 20:18:05 +0900 Subject: [PATCH 131/142] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4cb26af..c05687b 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # lets-cs ## 스터디 규칙 -- 일정 : 09.07 ~ 09.28 +- 일정 : 10.01 ~ 10.26 - 주제 : **운영체제** - 진행 방식 - 2주가 하나의 사이클 From 124d5c8053acd94521346f32bf868b9fa05f9967 Mon Sep 17 00:00:00 2001 From: Jin Hyung Park Date: Sat, 9 Oct 2021 05:38:46 +0900 Subject: [PATCH 132/142] =?UTF-8?q?Context-switching=20=ED=95=99=EC=8A=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../context-switch/sigrid/README.md | 107 ++++++++++++++++++ 1 file changed, 107 insertions(+) create mode 100644 operating-system/context-switch/sigrid/README.md diff --git a/operating-system/context-switch/sigrid/README.md b/operating-system/context-switch/sigrid/README.md new file mode 100644 index 0000000..b9b5881 --- /dev/null +++ b/operating-system/context-switch/sigrid/README.md @@ -0,0 +1,107 @@ +# Context-Switch란 무엇인가? +## 정의 +* Running 상태에 있는 프로세스 또는 쓰레드가 사용하는 Context(각 Task가 사용하는 CPU 레지스터의 값)을 메모리의 특정 영역에 저장한 후, 새롭게 수행할 Task의 Context를 TCB 또는 Stack에서 CPU의 레지스터 영역으로 복사하여 새로운 Task가 수행되도록 하는 일련의 작업을 의미한다. + +## Context란 무엇인가? +* Context: 각 Task가 사용하는 CPU 레지스터의 값이다. +* 만약 프로세스라면? + * 텍스트(Text) 영역 : 프로그램의 코드 부분 + * 데이터(Data) 영역 : 프로그램의 전역 변수 부분 + * 스택(Stack) 영역 : 프로그램의 지역 변수 부분 + * 힙(Heap) 영역 : 프로세스의 동적 메모리 할당 영역 + +* 커널 관리의 프로세스 관련 정보(태스크 구조체, task_struct) + * 중앙 처리기 범용 레지스터의 내용: 일반적 계산을 위해 활용되는 레지스터들의 내용 + * 중앙 처리기 특수 레지스터의 내용: 프로세스의 실행 위치를 나타내는 프로그램 계수기(Program Counter) + * 스택 포인터(Stack Pointer), 중앙 처리기 상태 레지스터, 가상 메모리 페이지 테이블 관련 정보 등 + * 프로세스 및 프로세스 그룹 식별자 + * 사용자 정보, 보안 정보 - 오픈 파일 정보 + * 프로세스 상태 - 시그널(Signal) 정보 + * 우선순위, 정책 등의 스케줄링 정보 + * 부모, 형제, 자식 프로세스 정보 - 타이머(Timer) 정보 + * 메모리 영역 정보 - + * IPC(Inter-process Communication) 관련 정보 + +* Context 구성에서, 프로세스 공간 영역은 메모리에 할당되므로 프로세스 사용자 공간이 유지되면 자동 보존된다. 쓰레드 공간 영역은 같은 프로세스 내 공유하므로 자동 보존된다. 아마 함수 호출의 최소 단위로서 스레드의 정의에 따라 독립적인 실행 흐름을 추가하기 위한 최소 조건으로 독립된 스택을 할당하는 것이다. PCB 레지스터는 쓰레드가 CPU를 할당받았다가 스케쥴러에 의해 다시 선점당하기 때문에 명령어가 연속적으로 수행되지 못하고 어느 부분까지 수행했는지 기억할 필요가 있다. 따라서 쓰레드도 PC 레지스터를 독립적으로 할당받는다. +* 프로세스 정보와 관련된 모든 문맥은 태스크 구조체(PCB, Process Control Block)에 위 표와 같이 보관되는데, 이들 중 프로세스 중단 시점에서 반드시 보존되고 실행 개시 시점에 복원되어야 하는 것은 대부분 중앙 처리기 레지스터들의 내용이다. +* 즉, 레지스터들의 내용은 중앙 처리기를 차지하는 프로세스가 실행되는 동안 모두 변화되기 때문에, 프로세스 중지 시에는 반드시 보존되었다가 수행 속개 시 다시 복원되어야 한다. +* 리눅스에서 커널의 프로세스 관리 정보를 담은 구조체(PCB)를 task_struct라고 한다. 프로세스가 실행 중 또는 준비 상태일 때는 CPU 별로 할당된 스케줄 큐인 runQueues에서 Linkedlist 형태로 저장된다. 대기 상태일 때는 스케줄링 큐에서 제거되어 대기별 큐(sleep queue)에 속한다. + +![](https://i.imgur.com/fkDRqxm.png) +* PCB의 저장 정보는 다음과 같다. + * 프로세스 상태 : 신규, 준비, 수행, 대기, 정지 + * 프로그램 카운터 : 프로세스가 다음에 실행할 명령어 주소 + * 레지스터 : 누산기, 스택, 색인 레지스터 + * 프로세스 번호 + +## 스케줄링 기법 +* Dispatching + * Ready 상태의 프로세스 또는 쓰레드 중에서 우선순위가 가장 높은 프로세스에 CPU 할당 +* Time Quantum + * 특정 프로세스 또는 쓰레드에 할당되는 시간의 단위를 설정하여, 특정 프로세스 또는 쓰레드의 CPU 독점을 방지 +* Preemption + * Time Quantum이 초과하면 인터럽트를 통해 CPU 사용권을 빼앗는 스케줄링 기법 + +## Context-Switch의 진행 과정 +### 진행 시점 +![](https://i.imgur.com/qwaMHjm.png) +* 비자발적 문맥교환 (현 프로세스나 쓰레드가 원치 않은데 커널에 따라 강제로 교환당하는 경우) + * 인터럽트의 처리 및 시스템 호출 완료 직후 사용자 모드로의 복귀 이전에 스케줄러가 수행되며 이 때 우선 순위가 현재 프로세스 보다 높은 프로세스가 있으면 비자발적 문맥 교환(involuntary context switch)이 일어난다. + * 현 프로세스의 타임 슬라이스가 다 소진된 경우도 클럭 인터럽트 처리 과정에서 이러한 사실을 알게 되고, 이때에도 인터럽트 처리를 마치고 사용자 모드로 복귀하는 과정에서 문맥 교환이 발생한다. + * 타임 슬라이스(Time Slice) 소진 시, 인터럽트(Interrupt) 발생 시 +* 자발적 문맥교환 + * 프로세스 자신이 잠들 때(Sleep) + * 프로세스가 Exit 할 때 + * 시스템 호출로부터 사용자 모드로 돌아왔으나 실행될 가장 적당한 프로세스가 아닐 때(wait) + * 커널이 인터럽트 처리를 마치고 프로세스가 사용자 모드로 돌아왔으나 실행될 가장 적당한 프로세스가 아닐 때 (wait) + +### 진행과정 +![](https://i.imgur.com/C2ZcfhF.png) +``` + ① Interrupt나 시스템 호출에 의해 문맥 교환 요구 + + ② 사용자 Mode -> 운영체제 모드 + + ③ 기존 프로세스의 현재 H/W 상태정보를 PCB에 저장 (PCB: Process Control Block) + + ④ 다음에 실행할 프로세스의 상태정보를 PCB에서 복구한 후 다음 프로세스를 실행함 + + ⑤ 운영체제 모드 -> 사용자 Mode로 전환 +``` +* Context-Switching 과정에서 발생하는 오버헤드 + * 1단계: 현 프로세스 + * 2단계: Interrupt 처리 루틴 + * 현재 상태를 PCB에 저장하는 오버헤드 + * 3단계: 프로세스 스케쥴러 + * 다음 실행 프로세스를 준비 Queue에서 선택 + * 4단계: Dispatch + * 다음 Process의 PCB값 복구 + * 5단계: 다음 프로세스 지정 + * 해결 방안: + * Context Switch 자주 발생하지 않도록 다중 프로그래밍의 정도를 낮춤 + * 스택 중심의 장비에서는 Stack 포인터 레지스터를 변경하여 프로세스간 문맥교환 수행 + * Light Weight Process인 스레드를 이용하여 Context Switch 부하를 최소화시킴 + +## 쓰레드 중심의 Context-Switching은 어떨까? +### 의의 +* 스레드는 실행에 필요한 최소한의 정보만을 가지고 자신이 속해 있는 프로세스의 기억장치나 파일과 같은 실행환경을 공유하여 프로세스의 생성과 문맥교환 등의 오버헤드를 줄일 수 있다. +* 병행성 증진: 단일 프로세스에서 다수의 스레드 생성 및 수행 +* 오버헤드 감소: 실행 환경의 공유를 통해 오버헤드 줄임 +### 실행 절차 +![](https://i.imgur.com/SfjYQ12.png) +* CPU 내에 존재하는 레지스터들은 현재 실행 중인 프로세스 관련 데이터들로 채워짐(T0) (실행 중인 프로세스가 변경되면, CPU 내에 존재하는 레지스터들의 값이 변경되어야 함) +* 프로세스 T1이 실행되기 전에, 현재 T0 레지스터들이 지니고 있는 데이터들을 저장 +* 프로세스 T1은 Ready 상태로 바뀌고, 프로세스 T1와 관련된 메모리에 백업된 레지스터 정보를 Restore하여 수행 +* 프로세스 T1은 마지막 실행 이후를 이어서 실행 +* 프로세스 T0 관련 레지스터 정보는 메모리에 저장되고, 프로세스 T1 관련 레지스터 정보는 CPU의 레지스터에 복원 + +### 참고: 언제 Interrupt가 이루어질까? +* I/O request (입출력 요청할 때) +* time slice expired (CPU 사용시간이 만료 되었을 때) +* fork a child (자식 프로세스를 만들 때) +* wait for an interrupt (인터럽트 처리를 기다릴 때) + +### Reference +* http://jidum.com/jidums/view.do?jidumId=442 +* https://jeongchul.tistory.com/94 +* https://jeong-pro.tistory.com/93 From 6d3442c785ee93661691e21833ad9e9d82e78145 Mon Sep 17 00:00:00 2001 From: Jin Hyung Park Date: Tue, 26 Oct 2021 01:45:56 +0900 Subject: [PATCH 133/142] =?UTF-8?q?=EB=8D=B0=EB=93=9C=EB=9D=BD=20=ED=95=99?= =?UTF-8?q?=EC=8A=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- operating-system/deadlock/sigrid/README.md | 83 ++++++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 operating-system/deadlock/sigrid/README.md diff --git a/operating-system/deadlock/sigrid/README.md b/operating-system/deadlock/sigrid/README.md new file mode 100644 index 0000000..b5f04fd --- /dev/null +++ b/operating-system/deadlock/sigrid/README.md @@ -0,0 +1,83 @@ +# 데드락이란 무엇인가 +## 정의 +* 운영체제에서 데드락이란, 시스템 자원에 대한 요구가 엇갈린 상태를 의미한다. +* 둘 이상의 프로세스가 다른 자원의 프로세스를 점유하다보니, 무한 대기(루프) 상태에 빠지게 되는 것을 의미한다. +* 즉, Deadlock은 다른 프로세스 또는 쓰레드가 소유한 자원을 요청한 행위가 서로에게 행해져 모든 프로세스 또는 쓰레드가 block이 되는 상태를 의미한다. +* A lock occurs when multiple processes try to access the same resource at the same time. + * One process loses out and must wait for the other to finish. +* A deadlock occurs when the waiting process is still holding on to another resource that the first needs before it can finish. +## 예시 1 +![](https://i.imgur.com/MEXzKoF.png) +* 쓰레드 T0이 리소스 1에 대한 Lock이 걸려 있는 상태이지만, 해당 쓰레드가 모든 일을 끝마치려면 리소스 2에 대한 자원이 필요한 상태이다. +* 쓰레드 T1이 리소스 2에 대한 Lock이 걸려 있는 상태이지만, 해당 쓰레드가 모든 일을 끝마치려면 리소스 1에 대한 자원이 필요한 상태이다. +## 예시 2 +### 서로가 사용하고 있는 Semaphore를 요청하여 Block에 걸리게 되는 경우 +* 다음과 같이 두 개의 코드가 주어졌다고 생각하자. +``` +Process1 +owns lock A +requests lock B +``` +``` +Process2 +owns lock B +requests lock A +``` +* 여기서 프로세스 1은 lock A를 갖고 있는데, 이는 A에 대한 세마포어(semaphore)를 갖고 있다는 뜻이다. 이와 달리, 프로세스 2는 lock B를 갖고 있는데, 이는 B에 대한 세마포어(semaphore)를 갖고 있다는 뜻이다. +* 세마포어는 한 곳에서 사용 중이라면, 다른 프로세스를 차단하는 목적으로 사용된다. 프로세스 1이 lock B를 요청할 경우, lock B는 현재 사용 중이므로 프로세스 1은 lock B가 release되기 전까지 Block 상태에서 대기하게 된다. +* 프로세스 2도 마찬가지이다. lock A를 요청할 경우, 현재 lock A는 사용 중이므로 프로세스 2는 lock A가 release되기 전까지 Block 상태에서 대기하게 된다. +![](https://i.imgur.com/n86eluU.png) +## 예시 3 +### Recursive Lock +* 프로세스 1이 한 semaphore를 갖고 있다. 해당 semaphore는 다른 프로세스가 접근할 수 없게 된다. 이 떄, 프로세스 1은 똑같은 semaphore에 접근을 요청한다. 이러한 경우, 해당 semaphore는 접근할 수 없음으로 데드락에 빠지게 된다. +![](https://i.imgur.com/a6f89wO.png) +## 예시 4 +### 범죄자와 경찰 +![](https://i.imgur.com/lWTXmAi.png) +* Imagine a criminal holds an hostage and against that, a cop also holds an hostage who is a friend of the criminal. In this case, criminal is not going to let the hostage go if cop won't let his friend to let go. Also the cop is not going to let the friend of criminal let go, unless the criminal releases the hostage. This is an endless untrustworthy situation, because both sides are insisting the first step from each other. +* So simply, when two threads needs two different resources and each of them has the lock of the resource that the other need, it is a deadlock. + +## Deadlock의 상태 +* 일반적으로 프로세스는 리소스를 사용하기 위해서는 사전에 요청을 거쳐야 하고, 다음과 같은 과정을 거친다. + * Request: 리소스 사용을 요청할 때 즉각 받아들여지지 않는다면, 프로세스는 리소스 사용이 가능해질 때까지 대기해야 한다. 주된 함수 연산으로는 ```call(), malloc()``` 등이 있다. + * Use: 쓰레드가 자원을 사용하는 단계이다. 프린터를 사용하고 있거나, 파일을 읽고 있다. + * Release: 프로세스는 리소스 사용을 중지(relinquish)한다. 따라서 해당 자원은 다른 프로세스가 사용 가능해진다. 주된 함수 연산으로는 ```close(), free(), delete()``` 등이 있다. +* 커널이 매니징하느냐? 애플리케이션이 매니징하느냐? 에 따라 차이가 있는데 아무래도 커널이 관리해주는 것이 개발자 입장에서는 불필요한 소요를 줄이는 일이지 않을까 싶다. + * 커널이 매니징한다는 것은, 커널이 어떤 리소스가 free이고 어디에 allocate 되어 있고를 모두 파악한다는 소리다. 현재 process의 queue를 관리해서 어느 프로세스가 다음 리소스의 사용을 원하는 지를 확인한다. + * Application이 매니징한다는 것은, mutex나 wait(), signal() 함수 호출로 인하여 컨트롤 되는 것을 의미한다. + +## Deadlock의 4가지 조건 +* Mutual Exclusion: 최소 한 개의 리소스가 non-sharable한 상태로 특정한 프로세스나 쓰레드에 의해 사용되고 있어야 한다. 만약 다른 프로세스가 해당 리소스 사용 요청을 보내면, 해당 프로세스는 리소스가 사용 가능할 때까지 기다려야 한다. +* Hold and Wait: 프로세스는 동시에 하나의 리소스를 갖고 있으면서 또 다른 프로세스나 쓰레드가 점유하고 있는 리소스 사용을 요청할 수 있다. +* No Preemption: 임의의 프로세스가 리소스를 소유한다고 가정하자. 그렇다면 다른 프로세스나 쓰레드는 해당 프로세스나 쓰레드가 스스로 리소스를 내려 놓기 전까지는 강제로 끌어내릴 수 없다. +* Circular wait: A set of processes { P0, P1, P2, . . ., PN } must exist such that every P[ i ] is waiting for P[ ( i + 1 ) % ( N + 1 ) ]. (해당 조건은 Hold and Wait 조건을 support하는 것 같다) + +## 데드락, 어떻게 해결할 것인가 +## 데드락을 예방 Prevention 하기 +* Not allowing the system to get into a deadlocked state. 위의 4가지 조건을 모두 충족시키지 않으면서 가능하다. +* 자원의 상호 배제 조건 방지 : 한 번에 여러 프로세스가 공유 자원을 사용할 수 있게 한다. 다만, 추후 동기화 문제가 생길 수 있다. +* 점유 대기 조건 방지 : 프로세스 실행에 필요한 모든 자원을 한꺼번에 요구하고 허용할 때까지 작업을 보류해서, 나중에 또다른 자원을 점유하기 위한 대기 조건을 성립하지 않도록 한다. +* 비선점 조건 방지 : 이미 다른 프로세스에게 할당된 자원이 선점권이 없다고 가정할 때, 높은 우선순위의 프로세스가 해당 자원을 선점할 수 있도록 합니다. +* 순환 대기 조건 방지 : 자원을 순환 형태로 대기하지 않도록 일정한 한 쪽 방향으로만 자원을 요구할 수 있도록 합니다. +* 데드락 예방(Prevention)은 시스템의 처리량이나 효율성을 떨어트리는 단점이 있다. + +### 데드락 회피(avoidance) +* 시스템의 프로세스들이 요청하는 모든 자원을, 데드락을 발생시키지 않으면서도 차례로 모두에게 할당해 줄 수 있다면 안정 상태(safe state)에 있다고 한다. +* 그리고 이처럼 특정한 순서로 프로세스들에게 자원을 할당, 실행 및 종료 등의 작업을 할 때 데드락이 발생하지 않는 순서를 찾을 수 있다면, 그것을 안전 순서(safe sequence)라고 부른다. +* 불안정 상태는 안정 상태가 아닌 상황을 말한다. 데드락 발생 가능성이 있는 상황이며, 교착 상태(데드락)는 불안정 상태일 때 발생할 수 있다. +* 회피 알고리즘은 자원을 할당한 후에도 시스템이 항상 Safe state에 있을 수 있도록 할당을 허용하자는 것이 특징이다. +* 은행원 알고리즘: 은행원 알고리즘의 경우, 이처럼 미리 최대 자원 요구량을 알아야 하고, 할당할 수 있는 자원 수가 일정해야 하는 등 사용에 있어 제약조건이 많고, 그에 따른 자원 이용도 하락 등의 문제가 있을 수 있다. + +### 데드락 탐지 및 회복(Detection) +* 탐지 + * Allocation, Request, Available 등으로 시스템에 데드락이 발생했는지 여부를 탐색 + * 현재 시스템의 자원 할당 상태를 파악 +* 회복 + * 순환 대기에서 벗어나 데드락으로부터 회복하기 위한 방법을 사용 + * 단순히 프로세스를 1개 이상 중단시키기: 상태에 빠진 모든 프로세스를 중단하거나, 프로세스를 하나씩 중단 시킬 때마다 탐지 알고리즘으로 데드락을 탐지하면서 회복시키는 방법: 매번 탐지 알고리즘을 호출 및 수행해야 하므로 부담이 되는 작업일 수 있음 + * 자원 선점하기: 프로세스에 할당된 자원을 선점해서, 교착 상태를 해결할 때까지 그 자원을 다른 프로세스에 할당해 주는 방법 + +#### Reference +* 더 알아보기 좋은 자료(영문): https://www.cs.uic.edu/~jbell/CourseNotes/OperatingSystems/7_Deadlocks.html +* https://stackoverflow.com/questions/34512/what-is-a-deadlock +* https://chanhuiseok.github.io/posts/cs-2/ From 437224dee34ccd0cd42c58991e32fe3b35fbdc4e Mon Sep 17 00:00:00 2001 From: 102092 Date: Wed, 3 Nov 2021 20:16:33 +0900 Subject: [PATCH 134/142] Add mutex-semaphore --- .../mutex-semaphore/han/README.md | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 operating-system/mutex-semaphore/han/README.md diff --git a/operating-system/mutex-semaphore/han/README.md b/operating-system/mutex-semaphore/han/README.md new file mode 100644 index 0000000..745cc3a --- /dev/null +++ b/operating-system/mutex-semaphore/han/README.md @@ -0,0 +1,62 @@ +# Mutex +- Mutual (mut) + Exclusion (ex) 의 합성어 +- 상호 배제를 이ㅇ +- 여러 스레드를 실행하는 환경, 자원에 대한 접근을 강제하기 위한 동기화 방식 + +> Mutual Exclusion + +- 하나의 프로세스가 공유 자원을 사용할 때, 다른 프로세스가 해당 자원에 접근하지 못하도록 하는 것. + - 즉 공유 자원에 점유할 수 있는 프로세스, 스레드의 수는 한 개라는 의미..? +- 어떻게 접근하지 못하도록 할까? +- 어떻게 다른 프로세스가 공유 자원이 사용할 수 있는지, 없는지 알 수 있을까? + +> 작동 방식 + +1. Lock + - 공유 자원에는 `Boolean Lock` 변수가 있음 + - Lock = true을 한 스레드만 Lock을 풀 수 있음. + - 그리고 공유자원을 사용하려하고는 스레드들을 위한 **대기큐**가 있음. + - 현재 공유자원을 점유하고 있는 스레드가 있을 경우, 이 자원에 접근하는 스레드들을 `blocking` 시키고, 대기큐에 적재하여 `sleeping` 상태로 변경해둠. + - 공유 자원의 Lock 변수가 false라면, 비어져 있다면, 대기큐에서 하나 깨워서 점유하게 만듬. + +2. SpinLock +- Busy-wating 방식 +- 공유자원에 접근하는 스레드는, 계속 공유 자원에게 자리가 있는지 계속 물어보는 방식 (대기큐가 없다) +- 그럼 비효율적 + - 왜? + - 해당 공유자원을 점유하고 있는 스레드 뿐만 아니라, 물어보는 다른 스레드의 요청까지 처리해줘야 하므로.. +- 그럼 어떤 상황에 위 방식을 사용할까? + - 대기큐를 사용하는 방식보다, 공유자원에게 물어보는 시간이 짦다면.. 굳이 대기큐를 사용하지 않아도 될듯. (컨텍스트 스위칭 시간이 짦으면..) + - 다른 스레드의 질의를 처리할 여유가 있을 때 (멀티 프로세스 일 때) + + +# Semaphore +- 다수의 프로세스, 스레드가 여러 개의 공유자원에 대한 접근을 제한하는 방법 +- Mutex랑은 다르게, 여러 프로세스, 스레드가 공유자원에 접근할 수 있다는 차이점이 있음 (뮤텍스는 하나의 스레드가 공유자원에 접근할 때의 접근을 제어하는 방식을 이야기 하는듯) +- P(wait), V(signal) +- 변수는 정수형 (뮤텍스는 boolean... 변수) + +> 작동 방식 + +1. Sleep - wait +- 대기큐 사용 +- 공유 자원에 자리가 생기면, 대기큐에서 잠자고 있는 스레드를 꺠우는 방식 + +2. SpinLock +- Busy - wating 방식 + +# 정리 + +1. Mutex를 이용하는 환경은, 공유 자원에 하나의 소비자 (프로세스 혹은 스레드) 가 점유가 가능할 때 사용함. +2. 엄밀하게 말하면 Mutex는 locking mechanism임. 즉 공유 자원을 잠그고, 열는 과정에 대한 것인듯. + - 즉 자원에 동기적인 접근이 가능토록 하는 방법 + - 뮤텍스를 통해 공유자원을 잠근 소유자만, 뮤텍스를 통해 공유자원을 릴리즈 할 수 있다 (뮤텍스에 대한 소유권이 존재한다.) + +3. Semaphore를 이용하는 환경은, 공유 자원에 여러 소비자 (여러 프로세스, 혹은 여러 스레드) 가 점유 가능할 때 사용하는 방법 인듯. +4. Semaphore는 signaling mechanism 임 (소비자가 다른 소비자에게 알려주는 방식) + - 어떤 자원을 점유하고 있는 소비자 중 한명이, 자신이 다 끝났으면 다른 대기하는 소비자에게 알려주는 방식인듯 + +# 참고 +- https://www.youtube.com/watch?v=oazGbhBCOfU +- https://en.wikipedia.org/wiki/Semaphore_(programming) +- https://www.geeksforgeeks.org/mutex-vs-semaphore/ \ No newline at end of file From 209dc9bf39addf73650a09c0caa7c9f9d36bac4d Mon Sep 17 00:00:00 2001 From: 102092 Date: Wed, 3 Nov 2021 20:16:58 +0900 Subject: [PATCH 135/142] Add user-kernel-thread --- .../user-kernel-thread/han/README.md | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 operating-system/user-kernel-thread/han/README.md diff --git a/operating-system/user-kernel-thread/han/README.md b/operating-system/user-kernel-thread/han/README.md new file mode 100644 index 0000000..79a5309 --- /dev/null +++ b/operating-system/user-kernel-thread/han/README.md @@ -0,0 +1,65 @@ +# Kernel 이란? +![](https://upload.wikimedia.org/wikipedia/commons/thumb/8/8f/Kernel_Layout.svg/400px-Kernel_Layout.svg.png) + +- OS에 핵심 부분인, 컴퓨터 프로그램을 의미. +- 시스템의 모든 것을 제어할 수 있도록 도와주는 부분. +- 항상 메모리에 상주하고 있으며, 하드웨어와 소프트웨어의 상호작용을 할 수 있도록 도와주는 핵심적인 인터페이스를 의미. + +# Kernel level thread +- 커널이 모든 프로세스, 스레드를 관리하는 방식을 의미 (스케쥴링등.. 모두 커널에서 관리) +- 1개의 Process table, Thread table을 통해서 관리. +- Context swiching이 자주 일어남. + +## Advantages +- 커널이 존재하는 모든 스레드의 정보를 알고 있기 때문에, 스케쥴러에서 적절하게 각 스레드별로 CPU 자원을 배분할 수 있음 +- non-blocking system call이 필요하지 않음. + - 즉 만약 하나의 프로세스에 여러개의 스레드가 있다고 가정 하고 어떤 스레드(프로세스를 잡고 있는)가 Blocking 상태에 들어간다고 하여도, 다른 스레드에 작동에 영향을 주지 않음. + - 커널이 그 프로세스에, 다른 스레드가 runnable한 상태임을 알고 있으므로, 스케쥴러에게 다른 스레드를 실행하라고 이야기 해줄듯. + +## Disadbantages +- 느리고 비율적임. + - 모든 스레드가 커널에 의해 관리되므로 (System call), 이러한 관리는 비용이 큼. +- 복잡도가 높음. + - 커널이 모든 스레드의 정보를 알고 있어야 하므로, + - 이러한 정보는 TCB(Thread Control Block) 에서 관리되는, 이러한 정보를 유지시키는 것이 상당한 오버헤드를 초래함. + +# User level thread +- 커널은 쓰레드의 존재를 알지 못함 (즉 관리하지 않는다.) +- 커널은 단지 프로세스를 관리하는 테이블 (Process table) 만 가지고 있을뿐, 각각의 프로세스들이 스레드를 관리하는 테이블을 가지고 있음 (Thread table) + - 즉 여러개의 스레드는 하나의 프로세스 (Many to One) 관리한다고 보면 됨. +- Context swiching 이 커널 레벨 스레드 보다 적게 일어남. +- 커널에 진입하지 않아도, 라이브러리 지원을 통해 스레드를 사용할 수 있게 함. +- Ex) Jvm with thread + +## Advantages +- 하나의 프로세스가 여러개의 스레드를 관리하는 만큼, 스레드에 수행에 필요한 정보가 해당 프로세스에 모두 저장되어있음. +- 그래서 빠르고 효율적임. (즉 context switching이 적어서) +- 각각의 프로세스가 다른 스케쥴링 알고리즘을 사용하도록 커스텀 할 수 있음. + +## Disadbantages +- 어떤 프로세스에 여러 개의 스레드가 있다고 가정할 때, + - 하나의 스레드가 커널을 호출 한다면 (System call) + - 해당 프로세스 내, 모든 스레드가 중단될 것 (Blocking System) + - 그래서 user level thread를 사용하기 위해서는 non-blocking system call이 필요함. (커널을 호출하더라도, blocking 되지 않도록..?) + +# 정리 +![](https://examradar.com/wp-content/uploads/2019/02/threads-types.png) +- (좌측) User level thread , (우측) Kernel level thread + +- 유저 레벨에서 스레드를 관리하는 것이라는 뜻은, + - 라이브러리등을 통해 하나의 프로세스에서 여러개의 스레드를 사용하게 만드는 것인듯. + - 커널은 어떤 스레드가 있는지 모르고, 프로세스의 존재만 알고 있음. + - 그래서 상대적으로 관리할 비용이 줄어들고 (프로세스만 관리하면 되니), 효율적으로 프로세스-스레드를 관리할 수 있도록 도와주는 측면이 있는듯. + - 다만, 커널이 스레드를 관리하지 않는다는 건, 스레드의 상태를 잘못할 경우, 해당 프로세스는 blocked 상태로 변경되고, 다른 스레드들에 영향이 가는 결과를 초래할 수 있을듯. + +- 커널 레벨에서 스레드를 관리하는 것은.. + - 커널이라는 프로그램이 모든 스레드의 정보를 알고 있어야 함. + - 이 점이 굉장히 비용이 큰 사안일듯. + - 다만, 커널이 관리해주므로, 프로세스가 죽는 block되는 사태는 벌어지지 않을듯. + +# 참고 +- https://en.wikipedia.org/wiki/Kernel_(operating_system) +- https://happy-chipmunk.tistory.com/entry/11-Multithreading2-Thread-%EC%9D%98-%EC%A0%81%EC%9A%A9-Userlevel-Threading-%EA%B3%BC-Kernellevel-Threading +- https://www.geeksforgeeks.org/difference-between-user-level-thread-and-kernel-level-thread/ +- https://examradar.com/os-threads-different-types-thread-questions-answers/ +- https://colinch4.github.io/2020-02-02/%EC%BB%A4%EB%84%90%EB%A0%88%EB%B2%A8%EC%8A%A4%EB%A0%88%EB%93%9C-vs-%EC%9C%A0%EC%A0%80%EB%A0%88%EB%B2%A8%EC%8A%A4%EB%A0%88%EB%93%9C/ \ No newline at end of file From 636ff6a05e5f4f4621ca7d1c32eb3feb893bf1d1 Mon Sep 17 00:00:00 2001 From: Jin Hyung Park Date: Sun, 7 Nov 2021 05:27:15 +0900 Subject: [PATCH 136/142] =?UTF-8?q?=EB=AE=A4=ED=85=8D=EC=8A=A4=EC=99=80=20?= =?UTF-8?q?=EC=84=B8=EB=A7=88=ED=8F=AC=EC=96=B4=20=ED=95=99=EC=8A=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mutex-semaphore/sigrid/README.md | 296 ++++++++++++++++++ 1 file changed, 296 insertions(+) create mode 100644 operating-system/mutex-semaphore/sigrid/README.md diff --git a/operating-system/mutex-semaphore/sigrid/README.md b/operating-system/mutex-semaphore/sigrid/README.md new file mode 100644 index 0000000..2bb8213 --- /dev/null +++ b/operating-system/mutex-semaphore/sigrid/README.md @@ -0,0 +1,296 @@ +# 세마포어와 뮤텍스 +## Process Synchronization vs Thread Synchronization +* 현대 운영체제는 Thread Synchronization 위주로 동작한다. +* Process 1의 Thread A가 실행되고, Process 1의 Thread B가 실행되고 이후 Process 2의 Thread C가 실행되는 형태로 진행된다. 즉, Context Switching의 기준이 현대 OS에는 Thread인 것이다. 각 프로세스 내의 Thread 1, Thread 2… 동일 프로세스 내에서 서로 다른 쓰레드들이 번갈아가며 처리된다. +* Independent Process란 Process 1, Process 2 가 아무런 관계가 없는 독립적인 프로세서인 경우를 의미한다. 이와 달리, Cooperating Processor는 Process 1, Process 2가 서로 영향을 주고 받는 경우를 의미한다. 예를 들면, 프로세스 간 자원공유가 필요한 경우(DB 등)을 꼽아볼 수 있다. +* Cooperating Processor의 경우, 쓰레드 간의 공유자원을 사용하므로 동기화 작업이 필요하다. 공유 자원에 대한 동시 접근(concurrent access)는 데이터 일관성을 깨뜨리므로, cooperating process 간의 순서있는 실행(orderly execution)을 통해 데이터 일관성을 유지해야 한다. +## Example: Bank Account Problem +``` +// Test.java +class Test { + public static void main(String[] args) throws InterruptedException { + BankAccount b = new BankAccount(); + Parent p = new Parent(b); + Child c = new Child(b); + p.start(); // start(): 쓰레드를 실행하는 메서드 + c.start(); + p.join(); // join(): 쓰레드가 끝나기를 기다리는 메서드 + c.join(); + System.out.println("balance = " + b.getBalance()); + } +} + +// 계좌 +class BankAccount { + int balance; + void deposit(int amount) { + int temp = balance + amount; // 임계구역 코드 + System.out.print("+"); // 시간 지연 의도를 위한 코드 + balance = temp; + } + void withdraw(int amount) { + int temp = balance - amount; // 임계구역 코드 + System.out.print("-"); // 시간 지연 의도를 위한 코드 + balance = temp; + } + int getBalance() { + return balance; + } +} + +// 입금 프로세스 +class Parent extends Thread { + BankAccount b; + Parent(BankAccount b) { + this.b = b; + } + public void run() { // run(): 쓰레드가 실제로 동작하는 부분(치환) + for (int i = 0; i < 100; i++) + b.deposit(1000); + } +} + +// 출금 프로세스 +class Child extends Thread { + BankAccount b; + Child(BankAccount b) { + this.b = b; + } + public void run() { + for (int i = 0; i < 100; i++) + b.withdraw(1000); + } +} +``` +* 위 코드에 대한 출력값은 다음과 같다. 만약 시간 지연을 위한 코드(System.out.print 함수 호출)이 없었다면, balance 값은 0이 되었을 것이다. +``` +++++++++++++++++++++++++++++++++++---------------------------------------------- +--------------------------------------------------------------------------++++++ ++++----------------------------------------------+++++++++++++++++++++++++++++++ ++----+++++++-+++++----+++------------------------------------------------------- +-+++++++-++++-+++++++++-------++++++++++++++++++++++++++++++++++++++++++++++++++ +++++++---------------+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ++-++++++++++++-------------------++++++++++++++++++++-++++++++++++++++++++++++++ +++++++-+------------------------------------------------------------------------ +-+++++++++++-+++++++----------------------------------------+-------+----------- +-+------+----------------------------------------------------------------------- +-+------------------------------------------------------------------------------ +-+------------------------------------------------------------------------------ +-------------------+-------+---------------------------------------------------- +------------------------------+------------------------------------------------- +------------------------------------------------------+------------------------- +-+------------------------------------------------------------------------------ +-++---------------------------------------++++++++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +balance = 1000000 +``` +* 간단한 실험을 통해, 우리는 시간 지연이 주어질 때 여러 쓰레드가 하나의 공유 자원을 사용하는 프로그램은 망가진다는 사실을 알 수 있다. 출력되는 결과는 운영체제에서 쓰레드를 스위칭하는 패턴이 매번 다르므로 수행할 때마다 다르다. 이는 공통변수, 즉 계좌의 잔액(common variable)에 대한 동시 업데이트(concurrent update) 가 이루어지기 때문이다. Java와 같이 High-level 언어에서는 한 줄로 족하지만, assembly code로 번역될 때 여러 줄로 바뀌므로 중간에 스위칭이 발생할 수 있다. +* 이를 해결하기 위해서는, 공통변수에 해당하는 임계구역(critical section)을 설정해 임계구역 코드에 접근하는 쓰레드가 단 하나만 존재하도록 해야 한다. +``` +// 해결 코드 +class Test { + static final int MAX = 100; // 입출금 회수 + public static void main(String[] args) throws InterruptedException { + // 은행계좌를 만들고 + BankAccount b = + new BankAccount(); + // 부모 쓰레드와 + Parent p = new Parent(b, MAX); + // 자식 쓰레드를 만든 후 + Child c = new Child(b, MAX); + // 각각 실행시킨다. + p.start(); + c.start(); + p.join();// 부모와 자식 쓰레드가 + c.join();// 각각 종료하기를 기다린다. + System.out.println("Final balance = " + + b.getBalance());// 최종 잔액 출력 + } +} + +class BankAccount { + int balance; + void deposit(int amount) { + balance = balance + amount; + } + void withdraw(int amount) { + balance = balance - amount; + } + int getBalance() { + return balance; + } +} + +class Parent extends Thread { + BankAccount b; + int count; + Parent(BankAccount b, int count) { + this.b = b; + this.count = count; +} + public void run() { + for (int i=0; i 최초 S값은 1임 + while S=0 do wait --> S가 0면 1이 될때까지 기다려야 함 + S := S-1 --> S를 0로 만들어 다른 프로세스가 들어 오지 못하도록 함 +end P + +--- 임계 구역 --- + +procedure V(S) --> 현재상태는 S가 0임 + S := S+1 --> S를 1로 원위치시켜 해제하는 과정 +end V +``` +* 위 코드에서 acquire 함수는 P에 해당하는 것으로서, 쓰레드가 임계구역에 진입하는 경우 value 값을 감소시키는 역할을 한다. 만약 value 값이 0보다 작으면 해당 임계구역에 어느 쓰레드가 존재한다는 뜻이므로, 새로운 쓰레드가 접근하지 못하도록 막아야 한다. +* If the semaphore value is negative, its magnitude is the number of processes waiting on that semaphore. 즉, value의 절댓값 크기만큼 현재 프로세스/쓰레드들이 임계구역 접근 번호표를 뽑은 셈이 된다. 이와 달리, value의 초기값은 1이므로 1일 때는 프로세스가 직접 접근 가능하다는 뜻이며 0이면 현재 누군가가 쓰고 있으니 잠깐만 대기하라는 뜻이다. +* 대기열은 list(Queue)로 구현하되, 원소 추가 이후 block을 걸어준다. +* 위 코드에서 release 함수는 V에 해당하는 것으로서, 쓰레드가 임계구역에 빠져나가는 경우 value 값을 증가시키는 역할을 한다. 만약 value 값이 0보다 크면 임계구역에 진입하려고 대기하는 프로세스가 list(Queue)에 남아있다는 의미이므로 순서대로 상위 프로세스를 임계구역에 접근하도록 해 주어야 한다. +### 예시: 최초 S 값은 1이고, 현재 해당 구역을 수행할 프로세스 A, B가 있다고 가정하자. +* 먼저 도착한 A가 P(S)를 실행하여 S를 0으로 만들고 임계구역에 들어감 +* 그 뒤에 도착한 B가 P(S)를 실행하지만 S가 0이므로 대기 상태 +* A가 임계구역 수행을 마치고 V(S)를 실행하면 S는 다시 1이 됨 +* B는 이제 P(S)에서 while문을 빠져나올 수 있고, 임계구역으로 들어가 수행함 +* Bank Account Problem을 Semaphore를 활용하여 해결하면 다음과 같다. 쓰레드 동기화를 통하여 임계구역 문제를 해결하였고, 이에 따라 +- 출력을 제외하고 balance 값이 0 출력된다. +``` +import java.util.concurrent.Semaphore; +class BankAccount { + int balance; + Semaphore sem; + BankAccount() { + sem = new Semaphore(1);// 초기값 = 1 + } + void deposit(int amount) { // 입금 + try { + sem.acquire(); // 진입 전: acquire() + } catch (InterruptedException e) {} + int temp = balance + amount; + System.out.print("+"); + balance = temp; + sem.release(); // 나온 후: release() + } + void withdraw(int amount) { // 출금 + try { + sem.acquire(); // 진입 전: acquire() + } catch (InterruptedException e) {} + int temp = balance - amount; + System.out.print("-"); + balance = temp; + sem.release(); // 나온 후: release() +} +int getBalance() { + return balance; +} +} +``` +### Ordering +* 세마포어를 사용하는 이유 중 하나는 ordering하기 위함인데, 이는 프로세스의 실행 순서를 원하는 대로 설정하는 것에 있다. +* 예시: 프로세스가 Process 1, Process 2 두 개가 있다고 가정하자. 원하는 순서는 Process 1, Process 2 순으로 실행하기를 원한다. 그러면 아래와 같이 설정해줄 수 있다. + +https://velog.io/@codemcd/%EC%9A%B4%EC%98%81%EC%B2%B4%EC%A0%9COS-8.-%ED%94%84%EB%A1%9C%EC%84%B8%EC%8A%A4-%EB%8F%99%EA%B8%B0%ED%99%94-1 + +* 위의 사진은, Process 1 > Process 2 순서로 프로세스 실행됨이 보장된다. +* P1이 먼저 실행된 경우는 다음과 같다. + * Section 1 이전에 아무런 동작이 없으므로 바로 수행한다. + * sem.release() 를 만나면 value값을 1 증가시키고, 세마포 큐에 있는 프로세스를 깨워주는데 현재에는 큐에 프로세스가 없으므로 아무 동작도 하지 않는다. + * P2가 실행된다. + * P2의 sem.acquire() 를 만나면 현재 value값은 1이고 이를 1감소시키면 0이 된다. value = 0이면 block을 하지 않으므로, 무사히 Section 2가 수행된다. +* P2가 먼저 실행된 경우는 다음과 같다. + * Section 2 이전에 sem.acquire() 가 있으므로 이를 수행하는데, 현재 value값은 0이고 이를 1 감소 시키면 -1 이 된다. value값이 음수면 해당 프로세스를 block 시킨다. 즉, 세마포 큐에 삽입한다. + * P1이 실행되면 Context Switch으로 Section 1이 바로 수행된다. + * sem.release() 를 만나면 value값을 1 증가시키고, 세마포 큐에 있는 P2 프로세스를 깨워준다.(현재 value = 0) + * P2의 Section 2가 수행된다. +* Bank Account Problem을 Ordering으로 해결해보면 다음과 같다. + * 입금(Parent) 또는 출금(Child)가 먼저 실행되는 경우: 상호배타를 위한 sem 세마포어 및 실행순서 조정을 위한 sem2 세마포어 할당. + * 프로그램 시작 시, 부모 쓰레드는 그대로 실행하도록 하고 자식 쓰레드가 실행되는 경우 sem2 세마포어에 의해 일단 block되고 이후 부모 쓰레드를 실행하여 자식 쓰레드가 이후에 블록된 상태에서 벗어나도록 설정. 참고: https://zzsza.github.io/development/2018/07/30/process-synchronization/ + * 구체적으로, 초기값이 0인 sem2 세마포어에 대해 acquire()를 호출하게 하도록 deposit(), withdraw() 메소드를 각각 수정 +``` +class BankAccount { + int balance; + + Semaphore sem, sem2; + BankAccount() { + sem = new Semaphore(1); + sem2 = new Semaphore(0); // Ordeing을 위한 세마포 + } + + void deposit(int amount) { + try { + sem.acquire(); + } catch (InterruptedException e) {} + int temp = balance + amount; + System.out.print("+"); + balance = temp; + sem.release(); + sem2.release(); // block된 출금 프로세스가 있다면 깨워준다. + } + void withdraw(int amount) { + try { + sem2.acquire(); // 출금을 먼저하려고 하면 block한다. + sem.acquire(); + } catch (InterruptedException e) {} + int temp = balance - amount; + System.out.print("-"); + balance = temp; + sem.release(); + } + int getBalance() { + return balance; + } +} +``` +* 입출금이 교대로 이루어지는 경우(Child-Parent-Child-Parent…): 블록된 부모 쓰레드는 자식 쓰레드가 깨워주고, 블록된 자식 쓰레드는 부모 쓰레드가 각각 깨워주도록 한다. + * 상호배타를 위한 sem 세마포어 외에 부모 쓰레드의 블록을 위해 dsem 세마포어를, 자식 쓰레드의 블록을 위해 wsem 세마포어를 각각 사용한다. + * 잔액이 항상 0 이상인 경우: 출금하려는 액수보다 잔액이 작으면 자식 쓰레드가 블록되도록 하며 이후 부모 쓰레드가 깨워주게 한다. + * 상호배타를 위한 sem 세마포어 외에 sem2 세마포어를 사용하여 잔액 부족시 자식 쓰레드가 블록되도록 한다. From c474f246e19672beb024ca4b4574ebeeb8a59a34 Mon Sep 17 00:00:00 2001 From: Jin Hyung Park Date: Sun, 7 Nov 2021 05:28:36 +0900 Subject: [PATCH 137/142] =?UTF-8?q?=EC=82=AC=EC=9A=A9=EC=9E=90=20=EC=88=98?= =?UTF-8?q?=EC=A4=80=20=EC=93=B0=EB=A0=88=EB=93=9C=20=EB=B0=8F=20=EC=BB=A4?= =?UTF-8?q?=EB=84=90=20=EC=88=98=EC=A4=80=20=EC=93=B0=EB=A0=88=EB=93=9C=20?= =?UTF-8?q?=EB=B9=84=EA=B5=90=20=ED=95=99=EC=8A=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../user-kernel-thread/sigrid/README.md | 85 +++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 operating-system/user-kernel-thread/sigrid/README.md diff --git a/operating-system/user-kernel-thread/sigrid/README.md b/operating-system/user-kernel-thread/sigrid/README.md new file mode 100644 index 0000000..423ddf2 --- /dev/null +++ b/operating-system/user-kernel-thread/sigrid/README.md @@ -0,0 +1,85 @@ +# 사용자 수준 쓰레드 vs 커널 수준 쓰레드 +![](https://i.imgur.com/4rFNHLc.png) +## Kernel Thread +* The kernel knows about and manages all threads. +* One process control block (PCP) per process. +* One thread control block (TCB) per thread in the system. +* Provide system calls to create and manage threads from user space. +* 대표적으로 입출력 I/O 작업 등을 꼽아볼 수 있다. +* 스케줄러가 컨텍스트 스위칭 하는 단위는 커널 스레드이고 컨텍스트 스위칭으로 저장되는 정보가 Process Control Block(PCB)이다. +## User level threads +* User level threads are supported above the kernel in user space and are managed without kernel support. +* Threads managed entirely by the run-time system (user-level library). +* Ideally, thread operations should be as fast as a function call. +* The kernel knows nothing about user-level threads and manage them as if they where single-threaded processes. +## Case Study +![](https://i.imgur.com/M9kfk74.png) +* 프로세스에 현재 스레드 4개를 생성하였다. 유저 레벨 스레드이다. +![](https://i.imgur.com/zzKN5Q1.png) +* 프로세스가 CPU 사용을 위해 OS에게 스레드 2개를 달라고 요청한다. +![](https://i.imgur.com/2URJg2V.png) +* 2개의 스레드를 현재 프로세스에서 쓸 수 있도록 할당해준다. 커널 레벨 스레드이다. +* OS의 스케줄러에 의해 현재 프로세스를 보고 있는 커널 레벨 스레드를 CPU에 할당한다. 해당 프로세스를 보고 있는 커널 레벨 스레드가 동작하기 시작한다. 사용자 레벨 스레드에 있는 스레드 중 1개가 커널 레벨 스레드와 연결되어 프로세스에서 작업을 진행할 수 있다. +![](https://i.imgur.com/8iWkBJJ.png) +* 위의 그림은 커널 레벨 스레드는 그대로 컨텍스트 스위칭을 당하지 않았지만 사용자 레벨 스레드는 컨텍스트 스위칭을 당해 작업하는 스레드가 바뀜을 알 수 있다. +![](https://i.imgur.com/luUQZut.png) +* 커널 레벨 스레드가 OS의 스케줄러에 의해 컨텍스트 스위칭을 당하면서 TCB가 저장, 스왑되고 어떤 인터럽트가 들어와서 프로세스 자체가 컨텍스트 스위칭될때 PCB가 저장, 스왑된다. + +**Q: 사용자 스레드 방식이 커널 스레드 방식보다 오버헤드가 적은 이유는?** +* A: 스레드간 전환할 때마다 커널 스케줄러를 호출할 필요가 없기 때문이다. +## Multithreading Model +### N:1 사용자 모델 +![](https://i.imgur.com/pR4M13E.png) +* 프로세스 1개(사용자 스레드 N개) 당 커널 스레드 1개가 할당된다. +* 프로세스 내에 스레드 라이브러리가 있어서 커널의 도움없이 스레드의 스케줄링을 할 수 있다. +* 커널은 프로세스 내의 스레드의 존재를 모른다. +* 스레드 정보(TCB, Thead Control Block)는 프로세스 내에서, 프로세스 정보(PCB, Process Control Block)는 커널에서 관리한다. +* 장점으로는, 스레드의 스케줄링 및 동기화에 시스템콜(커널호출)이 필요없기 때문에 오버헤드가 적다. +* 단점으로는, + * 동작 중인 스레드가 시스템콜을 하면 해당 프로세스 내의 모든 스레드가 멈춘다. (Blocking system call) + * 프로세스 단위로 CPU가 할당되므로, 다중CPU환경에서 한 프로세스 내 스레드들을 동시에 실행할 수 없다. (Hardware Parallelism 지원안함) + * 다중 처리 시스템에서는 사용할 수 없다. + * 커널이 스레드를 관리하지 않아, 프로세스에서 스레드 간 보호를 해줘야 한다. +### 1:1 커널 모델 +![](https://i.imgur.com/iULY4j0.png) + +* 프로세스 내의 사용자 스레드 1개 당 커널 스레드 1개가 할당된다. +* 사용자 스레드를 생성하면 할당할 커널 스레드를 1개 생성한다. +* 프로세스 내에 스레드 라이브러리가 없어서 커널 스레드를 스케줄하여 매핑된 사용자 스레드를 동작시킨다. +* 커널이 전체 TCB와 PCB를 관리한다. +* 장점으로는, + * 동작 중인 스레드가 시스템콜을 해도 해당 프로세스 내의 다른 스레드가 동작할 수 있다. + * 스레드 단위로 커널 스레드가 할당되므로, 다중CPU환경에서 한 프로세스 내 스레드들을 동시에 실행할 수 있다. (즉, 시스템 동시성을 지원한다고 말할 수 있다) +* 단점으로는, + * 스레드 문맥교환할 때도 시스템콜이 필요하고 커널이 모든 TCB와 PCB를 관리하여 오버헤드가 크다. + * CPU, RAM 성능에 따라 생성 가능한 커널 스레드 및 사용자 스레드가 한정되어 있다. + +### 혼합된 스레드 모델 (N:M) +![](https://i.imgur.com/Vh2V3gc.png) +[링크](https://www.geeksforgeeks.org/relationship-between-user-level-thread-and-kernel-level-thread/) +* 커널 스레드 마다 1개씩 경량 프로세스(LWP, Light Weight Process)가 매핑되어 있다. +* LWP는 가상 처리기로써, 1:1 모델처럼 한 프로세스에 여러 개가 할당될 수 있고, 프로세스에 할당된 LWP는 N:1 모델처럼 여러 개의 사용자 스레드를 관리한다. (커널과 프로세스 간의 중간자 역할을 한다.) +* 따라서 프로세스 1개(사용자 스레드 N개)에 M 개의 커널 스레드를 할당할 수 있다. (N ≥ M) +* 장점으로는, + * 사용자 스레드 생성 개수가 제한되지 않는다. (N:1) + * 시스템콜을 해도 해당 프로세스 내 (다른 LWP에 연결된) 스레드는 멈추지 않는다. (1:1) +* 단점으로는, + * LWP가 블록되면 LWP에 연결된 모든 사용자 스레드가 멈춘다. (N:1) + * LWP의 사용자 스레드 문맥교환도 1:1 모델만큼 오버헤드가 크다. (1:1) + * 각 LWP에 한 개의 사용자 스레드가 실행되지 않으면, 1:1 모델에 비해 다중CPU환경에서 효율적이지 않다. (N:1) + +**Q: 디스크 입력의 경우 사용자 수준 쓰레드 모델과 커널 수준 쓰레드 모델 중 어느 것이 유리할까?** +A: Kernel-level Thread 모델이 유리하다. +* User-level Thread 모델에서는 스레드가 디스크 입출력을 할 때마다 해당 프로세스 내의 모든 스레드가 중단된다. 반면에, Kernel-level Thread 모델은 커널 스레드가 사용자 스레드에 1:1로 할당되므로 한 스레드에서 시스템콜을 해도 해당 프로세스의 다른 스레드가 중단되지 않는다. +* 유저 레벨 스레드를 이용하면 컨텍스트 스위칭을 프로세스 내부에서 진행하면 되고, 커널로 진입하지 않아도 되어 비용이 적게 든다. + * 즉, 스레드의 스케줄링 및 동기화에 시스템콜(커널호출)이 필요 없기 때문에 오버헤드가 적다. +* 그리고 커널 레벨 스레드는 커널이 직접 스레드를 관리해주는 것이기 때문에 유저 스레드 1개당 커널 1개가 맡아준다. 따라서 하나의 프로세스에 여러 유저 스레드가 있어도 동시에 실행이 가능하다. +* 하지만 여기서 유저 레벨 스레드에 I/O를 이용하면 치명적인 단점이 존재한다. +* 유저 레벨 스레드를 이용하면 커널은 프로세스 내의 스레드 존재를 모르기 때문에 하나의 유저 레벨 스레드가 I/O를 하면 나머지 모든 스레드가 멈추게 된다. +* 따라서 I/O를 하기 위해서라면 커널 레벨 스레드를 이용하는게 더 유리하다. + + +### Reference +https://www.crocus.co.kr/1404 +http://www.it.uu.se/education/course/homepage/os/vt18/module-4/implementing-threads/ +https://www.geeksforgeeks.org/relationship-between-user-level-thread-and-kernel-level-thread/ From 7faea157341c4730ff5471cc155b991c718ca0b3 Mon Sep 17 00:00:00 2001 From: 102092 Date: Mon, 15 Nov 2021 21:22:17 +0900 Subject: [PATCH 138/142] Fix typo --- operating-system/mutex-semaphore/han/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/operating-system/mutex-semaphore/han/README.md b/operating-system/mutex-semaphore/han/README.md index 745cc3a..20fd13d 100644 --- a/operating-system/mutex-semaphore/han/README.md +++ b/operating-system/mutex-semaphore/han/README.md @@ -1,6 +1,6 @@ # Mutex - Mutual (mut) + Exclusion (ex) 의 합성어 -- 상호 배제를 이ㅇ +- 상호 배제를 의미 - 여러 스레드를 실행하는 환경, 자원에 대한 접근을 강제하기 위한 동기화 방식 > Mutual Exclusion From 0568f5b8c470ca997b097f4af628bb915802eb77 Mon Sep 17 00:00:00 2001 From: Jin Hyung Park Date: Sat, 27 Nov 2021 09:23:38 +0900 Subject: [PATCH 139/142] =?UTF-8?q?=EA=B0=80=EC=83=81=20=EB=A9=94=EB=AA=A8?= =?UTF-8?q?=EB=A6=AC=20=ED=95=99=EC=8A=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../virtual-memory/sigrid/README.md | 131 ++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 operating-system/virtual-memory/sigrid/README.md diff --git a/operating-system/virtual-memory/sigrid/README.md b/operating-system/virtual-memory/sigrid/README.md new file mode 100644 index 0000000..6768ac9 --- /dev/null +++ b/operating-system/virtual-memory/sigrid/README.md @@ -0,0 +1,131 @@ +# 가상 메모리란? +## 개요 +* 가상 메모리는 물리 메모리의 용량 한계를 극복하려는 목적을 지니고 있다. + * 예를 들어, 물리 메모리가 100MB인데 200MB의 소프트웨어를 구동하고자 하는 것이다. +* **당장 필요한 부분만** 메모리에 적재시켜 구동하는 방식을 이용한다. +* 기본적으로 가상 메모리의 용량은 무제한이지만, 실질적으로는 물리 메모리의 용량에 국한된다. 가상 메모리의 용량은 **물리 메모리 + 스왑영역**이다. + +## Demanding Paging +![](https://i.imgur.com/ezgs1jj.png) +* 페이징이란 **논리 메모리 == 가상 주소**를 fixed-size로 분할하는 것을 의미하고, 프레임이란 **물리 메모리**를 fixed-size로 분할하는 것을 의미한다. [참고](https://jhnyang.tistory.com/290) +* 페이징 기법은 **고정 분할 방식**을 이용하는데, 물리 주소 공간을 **같은 크기** 로 분할하는 것을 의미한다. +* 페이지와 프레임은 서로 크기가 같으므로, 1:1 매핑이 가능하다. 매핑 내역은 Page Table에 기록된다. +* 현재 프로세스 실행에 요구되는 페이지만 메모리에 올리는 것을 **Demanding Paging**이라고 한다. +* Page Table에는 Valid bit이 추가되어, 해당 페이지-프레임의 메모리 상 존재 여부를 나타낸다. 만약 현재 페이지가 메모리에 적재되어 있다면 1을, 적재되어 있지 않다면 0을 나타낸다. +* 현재 페이지 2번이 메모리에 적재되어 있지 않고, Valid bit도 0으로 표시되어 있다. 페이지 2번을 메모리에 적재시키는 과정을 한 번 살펴보도록 하자. +![](https://i.imgur.com/aGcbk30.png) +* CPU에서 P1의 2번째 페이지에 접근하는데 valid bit값이 0이다. 그러면 CPU에 인터럽트 신호를 발생시켜서 OS 내부의 ISR로 점프한 후, 디스크 내부에 있는 프로세스 P1에 있는 2번째 페이지를 메모리에 할당하는 작업을 수행한다. **-> 과정 더 알아보기** + +### Page Fault (페이지 실패) +![](https://i.imgur.com/dBh57Ap.png) +* CPU가 접근하려는 페이지가 메모리에 없는 경우이다. 다시 말해서, 페이지 테이블의 valid bit가 0인 경우이다. +* Page Fault가 발생했을 때 처리하는 과정이다. + * 해당 페이지가 메모리에 있는 지 보기 위해 valid bit을 확인한다. + * valid bit이 0이라면, CPU에 인터럽트 신호를 보내어 OS 내부의 해당 ISR로 jump한다. + * 해당 ISR에서 디스크[backing store]를 탐색하여, 해당 프로세스의 페이지를 찾는다. + * 해당 페이지를 비어있는 프레임에 할당한다. + * 페이지 테이블에, 프레임 번호를 설정하고 valid bit이 1로 변경하여 해당 테이블을 갱신한다. + * 다시 명령어로 돌아가서 실행한다. + +### Pure Demanding Paging +* 프로세스가 최초로 실행될 때는 어떤 페이지가 필요한지 알 수 없으므로, 아무 페이지도 올리지 않는다. +* 그러므로 프로그램을 실행하자마자 page fault가 발생한다. 즉, 순수하게 필요한 페이지만 올리는 것을 말한다. +* Pure Demanding Paging의 장점은 메모리를 최대한 효율적으로 사용할 수 있다. 하지만 시작부터 page fault가 발생하므로 속도 면에서 느리다. + +### Pre-paging +* pure demanding paging과 반대 개념이다. +* 프로그램을 실행할 때 필요할 것이라 판단되는 페이지를 미리 올리는 것이다. +* 장점은 page fault가 발생할 확률이 적으므로 속도면에서 빠르지만, 단점으로 미리 올라간 페이지를 사용하지 않는다면 메모리가 낭비된다. + +### Swapping & Demanding Paging +* 공통점은 둘 다 메모리와 backing store 사이를 서로 오고 가는 기능을 수행한다. +* 차이점은 Swapping은 프로세스 단위로 이동하고 Demanding Paging은 페이지 단위로 이동한다. + +### Effective Access Time +* Demanding Paging은 페이지 테이블에 해당 페이지가 없으면 backing store에서 메모리로 가져오는 과정이 있다. 따라서, 페이지 테이블에 해당 페이지가 있을 때와 없을 때 시간 차이가 발생한다. +* 이러한 시간 차이를 고려하여 **평균적으로 어느 정도 소요되는지 계산하는 것을 유효 접근 시간**이라 한다. + +``` +p: 페이지 부재 확률(probability of a page fault = page fault rate) +Tm: 메모리를 읽는 시간 +Tp: Page fault가 발생했을 때 소요되는 시간(대부분 backing store(디스크)를 읽는 시간이 차지한다.) +T = (1-p)Tm + pTp +``` +``` +Tm = 200nsec (DRAM) +Tp = 8msec (seek time + rotational delay + transfer time) +T = (1-p)200 + p(8,000,000) = 200 + 7,999,800 * p +p = 1/1,000 => T = 8.2usec (40배 정도 느림) +p = 1/399,990 => T = 220nsec (10% 정도 느림) +``` +* 페이지 부재의 확률은 극히 낮다. 지역성의 원리(Locality of reference)에 의하기 때문이다. 지역성의 원리는 시간적 지역성, 공간적 지역성이 있다. + * **시간적 지역성**: CPU는 어느 메모리 공간을 읽은 후, 시간이 지나도 그 공간을 다시 읽을 확률이 매우 높다는 것을 의미한다. + * **공간적 지역성**: CPU는 어느 메모리 공간을 읽을 때, 인접한 범위 내에서 읽는다는 것을 의미한다. 특히, 절차적 프로그래밍으로 구현되어 있을 경우 순서대로 읽는 경우가 빈번하다. + +## Page Replacement +* Demanding Paging은 요구되는 페이지만 backing store에서 가져온다. 하지만 프로그램들이 계속 실행함에 따라, 요구 페이지도 계속 늘어나게 된다. 그러다보면, 언젠가는 메모리가 가득 차게 될 것이다. +* 여기서, 다른 프로그램이 새로 실행되거나 실행중인 프로세스가 다른 페이지를 요구한다면, 이미 메모리에 적재되어 있는 backing store로 보내고 -- 이를 **page-out**이라고 한다. +* 한 편으로, 이미 backing store로 page-out이 된 페이지를 **victim page**이라고 한다. + +## Victim Page +![](https://i.imgur.com/vJme440.png) + +* 그러면 어느 페이지를 탈락시켜야 할 것인가? 메모리에 올라가 있는 페이지 중, CPU에 수정(modify)되지 않는 페이지를 골라야 한다. + * 수정되지 않은 페이지는 page-out이 될 때, backing store에 쓰기(write) 연산을 하지 않아도 된다. backing store는 읽기(read) 시간도 느리기 때문에, 쓰기 연산까지 하면 시간이 더욱 느려질 것이다. + * 해당 페이지가 수정되었는 지, 수정되지 않았는지 파악하기 위하여 페이지 테이블에 modified bit(dirty bit)를 추가하여 이를 검사한다. 해당 페이지가 수정되었다면 modified bit을 1로, 수정되지 않았다면 0으로 둔다. + * 만약 수정되지 않은 페이지가 여러 개가 있다면, 랜덤으로 하거나 FIFO로 하는 등 알고리즘을 경우에 따라 선택할 수 있다. + +![](https://i.imgur.com/dl99Unh.png) + +## Other Paremeters in Page Table Entry +* Page base addresses +* Flag bit + * Accessed bit: 접근이 있었나? + * Dirty bit: 내용이 수정된 적이 있나? + * Present bit: 현재 페이지에 할당된 프레임이 있나? + * Read/Write bit: 읽기와 쓰기 권한이 있나? + +## 페이징 기법의 동적 주소 변환 과정 +* 가상 메모리의 스왑 공간에 있는 가상 주소를 물리 메모리의 실제 주소로 변환하는 과정을 **동적 주소 변환** 이라고 한다. +![](https://i.imgur.com/hh38gWH.png) +* 가상 주소를 물리 주소로 변환하는 과정 + 1. 가상 주소 30번지가 어느 페이지에 있는지 찾음 -> 페이지 3의 0번째 위치 + 2. 페이지 테이블의 페이지 3으로 가, 해당 페이지가 프레임 1에 있음을 알아냄 + 3. 물리 메모리 프레임 1의 0번째 위치에 접근 -> 가상 주소 30번지의 물리 주소 +* 가상 주소에 값을 저장할 때의 주소 변환 과정 +![](https://i.imgur.com/QOargpt.jpg) + 1. 가상 주소 18번지가 어느 페이지에 있는지 찾음 -> 페이지 1의 8번째 위치 + 2. 페이지 테이블의 페이지 1로 가, 해당 페이지가 프레임 3에 있음을 알아냄 + 3. 프로세스가 저장하려는 값을 프레임 3의 8번 위치에 저장 +* 부족한 물리 메모리의 크기 == 스왑 영역으로 대체 +* 페이지 테이블 수는 프로세스의 크기와 일치 + +### 페이지 테이블의 매핑 방식 +![](https://i.imgur.com/MauGglv.png) + +#### 직접 매핑 +* 페이지 테이블 전체가 운영체제 영역에 위치하는 경우 +* 특징 + * 모든 페이지 테이블이 물리 주소에 있다. + * 변환속도가 빠르다. + * 메이지 테이블의 시작 주소는 페이지 테이블 기준 레지스터(PTBR)가 가지고 있다. +#### 연관 매핑 +![](https://i.imgur.com/uIeNT7d.png) +* 페이지 테이블 전부가 스왑영역에 위치하는 경우 +* 특징 + * 일부 테이블만 무작위로 선정하여 물리 메모리로 가져온다. +* Translation Lookasider Buffer (TLB) +![](https://i.imgur.com/4xrEkMC.png) + * 가상 메모리 주소를 물리적인 주소를 변환하는 속도를 높이기 위해 사용하는 버퍼 + * 페이지 테이블은 주 기억장치(물리)에 기본적으로 위치하므로, 페이지 테이블에 접근하는 과정 하나와 기억 장치에 필요한 데이터 두 번을 액세스하는 과정이 필요함 + * TLB가 hit일 경우 가상 주소를 물리 주소로 변환하기 위한 페이지 테이블에 접근할 필요가 없음. + * TLB는 메모리가 아닌 프로세서에 내장되어 있기에 훨씬 빠름. + * TLB의 프레임 주소를 토대로 데이터를 불러오기 위한 1번의 메모리 접근만 있으면 됨. +* 탐색 과정 + * TLB를 사용하여 페이지가 물리 메모리(프레임)에 올려져 있는지 확인한다. + +## Reference +* https://velog.io/@codemcd/%EC%9A%B4%EC%98%81%EC%B2%B4%EC%A0%9COS-15.-%EA%B0%80%EC%83%81%EB%A9%94%EB%AA%A8%EB%A6%AC +* https://velog.io/@thalals/OS-8.%EA%B0%80%EC%83%81-%EB%A9%94%EB%AA%A8%EB%A6%AC%EC%9D%98-%EA%B8%B0%EC%B4%88 +* https://velog.io/@kjh3865/%EA%B0%80%EC%83%81-%EB%A9%94%EB%AA%A8%EB%A6%AC-Virtual-Memory +* http://jidum.com/jidums/view.do?jidumId=473 From 702076f192eb85f7294e528e1a6fa8bb2178e658 Mon Sep 17 00:00:00 2001 From: Jin Hyung Park Date: Sat, 27 Nov 2021 09:53:43 +0900 Subject: [PATCH 140/142] =?UTF-8?q?=EB=A9=94=EB=AA=A8=EB=A6=AC=20=EA=B3=84?= =?UTF-8?q?=EC=B8=B5=20=EA=B5=AC=EC=A1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../memory-hierarchy/sigrid/README.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 operating-system/memory-hierarchy/sigrid/README.md diff --git a/operating-system/memory-hierarchy/sigrid/README.md b/operating-system/memory-hierarchy/sigrid/README.md new file mode 100644 index 0000000..cbb46c5 --- /dev/null +++ b/operating-system/memory-hierarchy/sigrid/README.md @@ -0,0 +1,19 @@ +# 메모리 계층 구조 +![](https://i.imgur.com/Ga7efAW.png) +## 개요 +* 메모리 계층 구조는 메모리에 필요에 따라 여러 종류로 나누어 둠으로서, CPU가 메모리에 훨씬 빨리 접근하도록 유도하기 위함이다. + * Registers, Cache: CPU 내부에 존재하므로, 빠르게 접근할 수 있다. + * 캐시 + * ![](https://i.imgur.com/YIk9tLP.png) + * Memory: CPU 외부에 존재하므로, Registers와 Cache보다 느리게 접근할 수 있다. + * RAM: Random Access Memory. RAM은 어느 위치에 저장된 데이터든지 접근(읽기 및 쓰기)하는 데 동일한 시간이 걸리는 메모리이기에 ‘랜덤(Random, 무작위)’이라는 명칭이 주어졌다. + * Hard Disk: 직접 CPU에 접근할 수 없다. CPU가 하드 디스크에 접근하기 위해서는, 하드 디스크의 데이터를 메모리로 이동시킨 후에야 메모리에 접근해야 한다. 따라서 매우 느리다. + +## 특징 +### 비용적 측면 +* 메모리 구조에서 상층으로 갈수록 더 비싸진다. +### 참조의 지역성 (Locality of Reference) +* 자주 쓰이는 데이터는 자주 쓰이고, 그렇지 않은 데이터는 그렇지 않다. CPU는 자동으로 자주 쓰이는 데이터이고, 또는 자주 쓰일 것 같은 데이터를 캐시로 읽어온다. +* 자주 쓰이는 데이터는, 전체 데이터 양에 비해 작은 양이다. 따라서, 캐시는 메모리보다 더 작아도 된다. +### 속도적 측면 +* CPU와 가까이 있는 레지스터가 가장 빠르게 접근 가능하고, 밑으로 내려갈 수록 접근 속도가 느려진다. From 0db2766635a29a74bed3c8c67d95c863fd0231f6 Mon Sep 17 00:00:00 2001 From: 102092 Date: Mon, 29 Nov 2021 21:45:12 +0900 Subject: [PATCH 141/142] Add virtual-memory --- operating-system/virtual-memory/han/README.md | 79 +++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 operating-system/virtual-memory/han/README.md diff --git a/operating-system/virtual-memory/han/README.md b/operating-system/virtual-memory/han/README.md new file mode 100644 index 0000000..55bf8dc --- /dev/null +++ b/operating-system/virtual-memory/han/README.md @@ -0,0 +1,79 @@ +# 가상 메모리란? +- 메모리 관리 기법 +- 실행하고자 하는 프로세스가 모두 메모리에 올라오지 않아도, 실행하도록 하는 기법임. +- 왜 사용할까? + 1. 물리 메모리의 제약에서 벗어남 (즉 정해져있는 메모리보다 더 많이 사용하는 것 처럼 보임) + 2. 각 프로그램이 더 작은 메모리를 통해, 실행 가능 하기 때문에 여러 프로그램이 동시에 실행가능함. + 3. I/O가 적게 일어남. (왜?) + - 필요한 페이지만 올리기에, 페이지 사용하기 전보다 I/O가 적게 일어날 것. + +## 왜 필요할까? +- 현실적으로 실행되어야할 모든 프로세스의 정보를 물리 메모리에 올려 놓을 순 없다. + - 그러면 자주 사용되는 프로그램의 정보만 우선 물리 메모리에 올려 놓으면 어떨까? +- 즉 프로그램 실행에 필요한 메모리가 적재될 때, 연속적으로 저장될 필요 없음 (다른 프로그램의 메모리와 섞여 적재) + - 그러면 메모리를 더 효율적으로 사용할 수 있을듯. + +## 어떻게 필요한 정보만 물리 메모리에 올릴까? +> Demand Paging (요구 페이징 기법) + +![image](https://user-images.githubusercontent.com/22140570/143865107-61ddee97-88af-45c8-9e7d-07c6d4e5621d.png) +- 주소 공간은 페이지로 구성되어 있음 (뭉쳐있음.) +- 필요한 페이지만 물리 메모리에 그때 그때, 물리 메모리에 올리는 방식 + - *유-무효 비트*를 통해, 페이지가 물리메모리에 있는 지 없는지 알 수 있음. + - 만약에 필요한 페이지가 물리 메모리에 없으면? + - Page fault + - 페이지 폴트 발생 시, 보조 저장 장치 (swap area..?) + +> CPU 가 페이지를 찾는 과정 + +![image](https://user-images.githubusercontent.com/22140570/143865553-572ec7f4-c995-44f4-9c11-cbf6cce70525.png) + +1. 논리적 메모리에서 특정 페이지를 찾음 (1) +2. 페이지 테이블 참고 + - Invalied bit (물리 메모리에 해당 페이지가 없다) +3. Page fault + - Swap area에서 참고하여, 물리적 메모리에 올림 +4. 다시 페이지 테이블에 접근하여, 물리 메모리 주소를 찾음. + +- 페이지 테이블을 프로세스당 하나... +- 테이블 접근하기 전에, 찾는 TLB(Translation Lookaside Buffer) 라는 공간도 있음. + - 여기서 찾고자하는 논리 주소의 값이 있으면 바로 물리 주소를 반환. + - 없으면 페이지 테이블로 조회하러 감. + +## CPU의 연산 이란? +![image](https://user-images.githubusercontent.com/22140570/143863331-7a8fc482-7353-4a67-80ae-fca2c413d434.png) +- CPU는 연산할 때, 메모리의 값을 참조한다. + - 참조하는 메모리 값은 보통 레지스터에 있음 (아주 용량이 작은 메모리) + - 레지스터에 원하는 정보가 없으면 Main memeory (보통 Physical Memeory라 부름) 에서 참조하게 됨. + - CPU는 main memory의 값까지만 참조할 수 있게 됨. + + +## 프로그램이 실행되는 것이란? +![image](https://user-images.githubusercontent.com/22140570/143863461-c861d110-e1dd-4c71-bd70-b323744f634a.png) +- 프로그램 실행 이란, 실행에 필요한 정보들을 메모리에 올리는 걸 의미. + +## 주소 바인딩이란? +![image](https://user-images.githubusercontent.com/22140570/143863654-b0247cb0-80cd-481c-987d-7ee3d2b7de0b.png) +- 논리 주소(Logical Address)가 물리 주소(Physical Address)로 맵핑되는 것 +- 논리 주소는 물리 주소와 같을 수도, 다를 수도 +- 물리적 주소가 결정되는 시점에 따라서, 주소 바인딩이 나뉜다. + 1. 컴파일 + 2. 로드 타임 + 3. 실행 시간 + +## MMU 메모리 관리 장치 +![image](https://user-images.githubusercontent.com/22140570/143864193-540a994c-b658-4ac5-bbdd-5ade9ead399f.png) + + +## Swap Area +![image](https://user-images.githubusercontent.com/22140570/143864436-33723399-f0d3-418d-9619-70ef6bf66a3c.png) +- 외부 장치 (I/O 작업 발생!) +- 물리 메모리의 공간이 부족하기 때문에 등장. +- 실행 중인 프로세스의 메모리 주소를 일시적으로 Disk에 저장하는 것. +- 스왑 영역에 저장되는 주소들은, 프로세스가 동작 중에만 즉 **일시적**으로 저장됨. + + +# 참고 +- https://www.youtube.com/watch?v=5pEDL6c--_k +- http://www.kyobobook.co.kr/product/detailViewKor.laf?mallGb=KOR&ejkGb=KOR&barcode=9788993712476 +- https://cyber0946.tistory.com/51 \ No newline at end of file From cdd0714ba2ff774e2419a47afa2906a4b5bd8ea1 Mon Sep 17 00:00:00 2001 From: 102092 Date: Mon, 29 Nov 2021 21:59:11 +0900 Subject: [PATCH 142/142] Add memory hierarachy --- .../memory-hierarchy/han/README.md | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 operating-system/memory-hierarchy/han/README.md diff --git a/operating-system/memory-hierarchy/han/README.md b/operating-system/memory-hierarchy/han/README.md new file mode 100644 index 0000000..44ba23b --- /dev/null +++ b/operating-system/memory-hierarchy/han/README.md @@ -0,0 +1,42 @@ +# 메모리 계층 구조란? +![](https://www.elprocus.com/wp-content/uploads/Memory-Hierarchy.jpg) + +- CPU 접근 속도에 따라 메모리의 계층을 나눠놓은 것. +- 4가지 특징이 있음 + +## Capacity +- 크기 +- 상위 계층일수록 작음 (레지스터가 가지는 크기는 가장 작다는 의미) + +## Access Time +- 접근 시간 +- CPU가 메모리에 read/write 하는 데 걸리는 시간 +- 상위 계층 일수록 빨리 접근할 수 있을듯. + +## Performance +- 수행 능력 +- 얼마나 CPU가 효율적으로 움직이는지 에 대한 이야기 인듯. +- 과거 메모리 계층 구조 없이, 메모리가 구성되었을 때는 메인 메모리든 레지스터든 접근 시간 때문에 수행 능력이 비슷하게 안 좋았음. + - 시스템 수행 능력 강화를 위해, 해당 계층 구조가 등장했다고 보면 될듯. + +## Cost per bit +- 1bit 당 가격을 생각하면, 상위 계층일수록 비쌀 것. + + + +# Primary Memory +- CPU와 가장 접근성이 좋은 내부 메모리 +- 보통 메인, 캐시, 레지스터 를 의미 + +# Secondary Memory +- 외부 메모리 (CPU 외부에 존재하는 듯 ) +- I/O 작업이 필요하다 +- Disk..등이 이에 해당됨. + +# Summary +![](https://media.vlpt.us/images/ogs0518/post/992f6465-cf96-4bd7-8afb-85086bb245fb/Untitled.png) + +# 참고 +- https://ko.wikipedia.org/wiki/%EB%A9%94%EB%AA%A8%EB%A6%AC_%EA%B3%84%EC%B8%B5_%EA%B5%AC%EC%A1%B0 +- https://www.geeksforgeeks.org/memory-hierarchy-design-and-its-characteristics/ +- https://www.elprocus.com/memory-hierarchy-in-computer-architecture/ \ No newline at end of file