<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>JackCokebb dev blog</title>
    <link>https://jackcokebb.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Sun, 19 Jul 2026 18:14:13 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>JackCokebb</managingEditor>
    <item>
      <title>[MySQL] BNL 조인 제거와 복합 인덱스로 쿼리 성능 개선하기</title>
      <link>https://jackcokebb.tistory.com/24</link>
      <description>&lt;h1&gt;1. 문제 상황 (Problem)&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;슬로우 쿼리에 대한 확인을 해달라는 DB팀으로부터 문의가 들어왔습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러 테이블을 조인하는 복합 쿼리에서 데이터량이 늘어남에 따라 응답 속도가 눈에 띄게 느려지는 현상이 발생했습니다. 특히 4개의 테이블(&lt;code&gt;sme1_0&lt;/code&gt;, &lt;code&gt;gme1_0&lt;/code&gt;, &lt;code&gt;gmmae1_0&lt;/code&gt;, &lt;code&gt;gmmne1_0&lt;/code&gt;)이 얽히면서 MySQL 옵티마이저가 비효율적인 경로를 선택하고 있었습니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;[문제의 쿼리]&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2210&quot; data-origin-height=&quot;526&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/edHmPs/dJMcajnnt5Q/YlpCkKmLuk2k0NcSBtLvk1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/edHmPs/dJMcajnnt5Q/YlpCkKmLuk2k0NcSBtLvk1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/edHmPs/dJMcajnnt5Q/YlpCkKmLuk2k0NcSBtLvk1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FedHmPs%2FdJMcajnnt5Q%2FYlpCkKmLuk2k0NcSBtLvk1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2210&quot; height=&quot;526&quot; data-origin-width=&quot;2210&quot; data-origin-height=&quot;526&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;2. 원인 분석: EXPLAIN을 통한 디버깅&lt;/h1&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2887&quot; data-origin-height=&quot;374&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dmObKG/dJMcaaquvpI/j08wEdh7pw54iaTv15F0sK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dmObKG/dJMcaaquvpI/j08wEdh7pw54iaTv15F0sK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dmObKG/dJMcaaquvpI/j08wEdh7pw54iaTv15F0sK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdmObKG%2FdJMcaaquvpI%2Fj08wEdh7pw54iaTv15F0sK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2887&quot; height=&quot;374&quot; data-origin-width=&quot;2887&quot; data-origin-height=&quot;374&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. &lt;code&gt;EXPLAIN&lt;/code&gt; 결과, 성능 저하의 원인은 인덱스를 활용하지 못해 풀 테이블 스캔이 발생했고, 그 결과 Using join buffer (Block Nested Loop) 기반의 비효율적인 조인이 수행했다는 점입니다.&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;gmmne1_0 테이블의 Full Table Scan&lt;/b&gt; : 조인 조건에 인덱스가 없어 27,796건의 데이터를 매번 풀 스캔하고 있었습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;비효율적인 조인 버퍼 활용&lt;/b&gt; : 인덱스가 없다 보니 MySQL은 데이터를 메모리(Join Buffer)에 쌓아두고 대조하는 차선책을 택했고, 이는 CPU와 I/O에 큰 부하를 주었습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 추가적으로 &lt;code&gt;gmmae1_0&lt;/code&gt; 테이블의 과도한 데이터 탐색이 비효율을 야기 했습니다.&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;인덱스가 조인 조건(group_id, member_no)이나 필터 조건(authority_id, permission)을 모두 커버하지 못해, 일단 많은 양의 데이터를 읽어온 뒤 메모리에서 하나하나 대조하며 버리는 작업을 반복했습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;불필요한 데이터 페이지 접근&lt;/b&gt; : 인덱스에 없는 컬럼(permission 등)을 확인하기 위해 인덱스 페이지에서 실제 데이터가 담긴 테이블 페이지로 이동하는 &lt;b&gt;랜덤 I/O(Random I/O)&lt;/b&gt;가 수만 번 발생했습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;code&gt;gmmae1_0&lt;/code&gt; 테이블의 과도한 데이터 탐색&lt;/b&gt; : 총 35,612행을 읽었지만 실제 조건에 맞는 데이터는 0.19%에 불과했습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;[ 잠깐만!!! ] BNL(Block Nested Loop) 이란?&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1. BNL 조인의 원리&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반적인 &lt;b&gt;Nested Loop Join(NLJ)&lt;/b&gt; 은 드라이빙 테이블(Outer Table)에서 행을 하나 읽을 때마다 드리븐 테이블(Inner Table)의 &lt;b&gt;인덱스&lt;/b&gt;를 타고 데이터를 바로 찾아옵니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 조인 조건에 인덱스가 없다면 어떻게 될까요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최악의 경우, 드라이빙 테이블의 행 수만큼 드리븐 테이블 전체를 풀 스캔해야 합니다. 이를 보완하기 위해 MySQL이 사용하는 방식이 바로&lt;b&gt;BNL&lt;/b&gt;입니다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;Join Buffer 활용:&lt;/b&gt; 드라이빙 테이블의 데이터를 하나씩 처리하는 대신, 메모리 내 &lt;b&gt;Join Buffer&lt;/b&gt;에 가능한 많이 담습니다(Block 단위).&lt;/li&gt;
&lt;li&gt;&lt;b&gt;스캔 횟수 감소:&lt;/b&gt; 버퍼에 데이터를 가득 채운 뒤, 드리븐 테이블을 한 번 풀 스캔하면서 버퍼에 담긴 모든 데이터와 대조합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;반복:&lt;/b&gt; 드라이빙 테이블의 남은 데이터가 있다면 다시 버퍼를 채우고 스캔을 반복합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2. BNL이 성능에 미치는 타격&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비록 풀 스캔하는 것보다는 낫지만, BNL은 인덱스 조인에 비해 압도적으로 비효율적입니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;I/O 폭발:&lt;/b&gt; 인덱스가 있다면 단 몇 페이지만 읽으면 될 것을, BNL은 드리븐 테이블의 모든 데이터 페이지를 반복해서 디스크에서 읽어와야 합니다. 이번 사례의 경우 &lt;b&gt;27,796건을 매 블록마다 풀 스캔&lt;/b&gt;하는 부하가 발생했습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;CPU 과부하:&lt;/b&gt; 인덱스 조인은 '주소'를 찾아가는 방식이지만, BNL은 &lt;b&gt;'버퍼 내 데이터 수 &amp;times; 드리븐 테이블 데이터 수'&lt;/b&gt; 만큼의 모든 조합을 CPU가 일일이 비교 연산 해야 합니다. 데이터가 많아질수록 CPU 점유율이 기하급수적으로 상승합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3. 해결책은 결국 '인덱스'&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 트러블슈팅에서도 확인했듯이, BNL을 해결하는 가장 완벽한 방법은 옵티마이저가 BNL이라는 '차선책'을 택하지 않도록 &lt;b&gt;조인 컬럼에 적절한 인덱스를 제공&lt;/b&gt;하는 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인덱스 추가 후 &lt;code&gt;gmmne1_0&lt;/code&gt; 테이블의 접근 방식이 &lt;code&gt;ALL(BNL)&lt;/code&gt;에서 &lt;code&gt;ref&lt;/code&gt;로 바뀌면서, 수만 번의 비교 연산이 단 &lt;b&gt;3번의 인덱스 탐색&lt;/b&gt;으로 대체되었습니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;3. 해결 방안: 전략적 복합 인덱스 추가&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. gmmae1_0 에 커버링 인덱스 적용&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;조치 전 EXPLAIN 결과를 보면, gmmae1_0 테이블에서 35,612행을 읽었지만 실제 결과로 남은 데이터는 &lt;b&gt;0.19%&lt;/b&gt;에 불과했습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;커버링 인덱스&lt;/b&gt;은 이 문제는 쿼리를 수행하는 데 필요한 모든 컬럼이 인덱스 자체에 포함되어 있는 상태 '커버링 인덱스' 기술로 해결합니다.&lt;/li&gt;
&lt;li&gt;MySQL은 이 인덱스만 읽고도 &lt;b&gt;조인을 수행&lt;/b&gt;하고, 권한(authority_id)을 체크하고, 세부 권한(permission)까지 &lt;b&gt;필터링&lt;/b&gt;할 수 있습니다.&lt;/li&gt;
&lt;li&gt;결과적으로 실제 테이블 데이터(Heap)를 읽으러 디스크에 가지 않아도 되기 때문에 엄청난 속도 향상을 얻게 됩니다. (EXPLAIN 결과의 Using index)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 조인 병목 구간 제거&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;BNL&lt;/b&gt;을 피하기 위해 조인 경로와 필터링 조건을 모두 포함하는 &lt;b&gt;복합 인덱스(Composite Index)&lt;/b&gt;를 설계하여 적용했습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;[적용한 인덱스 DDL]&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1578&quot; data-origin-height=&quot;280&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bOTTuJ/dJMcahiQ5gX/ZrrmpayiUCRuRzk0YK2co0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bOTTuJ/dJMcahiQ5gX/ZrrmpayiUCRuRzk0YK2co0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bOTTuJ/dJMcahiQ5gX/ZrrmpayiUCRuRzk0YK2co0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbOTTuJ%2FdJMcahiQ5gX%2FZrrmpayiUCRuRzk0YK2co0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1578&quot; height=&quot;280&quot; data-origin-width=&quot;1578&quot; data-origin-height=&quot;280&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;4. 개선 결과&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인덱스 적용 후, 실행 계획은 완전히 바뀌었습니다. 비효율적인 스캔이 사라지고 모든 조인이 인덱스를 기반으로 수행됩니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2884&quot; data-origin-height=&quot;361&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cUmAjQ/dJMcahb4vUH/212HsMB1hdweQErR5kZzn1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cUmAjQ/dJMcahb4vUH/212HsMB1hdweQErR5kZzn1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cUmAjQ/dJMcahb4vUH/212HsMB1hdweQErR5kZzn1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcUmAjQ%2FdJMcahb4vUH%2F212HsMB1hdweQErR5kZzn1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2884&quot; height=&quot;361&quot; data-origin-width=&quot;2884&quot; data-origin-height=&quot;361&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;① 실행 시간(Execution Time)의 극적인 단축&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2642&quot; data-origin-height=&quot;1466&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/YV1Hx/dJMcagxs9zh/SMM30rGxxKwLZNZexKErU0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/YV1Hx/dJMcagxs9zh/SMM30rGxxKwLZNZexKErU0/img.png&quot; data-alt=&quot;조치전&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/YV1Hx/dJMcagxs9zh/SMM30rGxxKwLZNZexKErU0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FYV1Hx%2FdJMcagxs9zh%2FSMM30rGxxKwLZNZexKErU0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2642&quot; height=&quot;1466&quot; data-origin-width=&quot;2642&quot; data-origin-height=&quot;1466&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;조치전&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2650&quot; data-origin-height=&quot;1462&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lJmnw/dJMcachxjV8/hpnUlSpCMFNGfl5Xk2T0a1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lJmnw/dJMcachxjV8/hpnUlSpCMFNGfl5Xk2T0a1/img.png&quot; data-alt=&quot;조치후&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lJmnw/dJMcachxjV8/hpnUlSpCMFNGfl5Xk2T0a1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlJmnw%2FdJMcachxjV8%2FhpnUlSpCMFNGfl5Xk2T0a1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2650&quot; height=&quot;1462&quot; data-origin-width=&quot;2650&quot; data-origin-height=&quot;1462&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;조치후&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;[표] 500개의 데이터를 조회했을 때의 성능 변화입니다.&lt;/h3&gt;
&lt;table style=&quot;height: 77px;&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;&lt;b&gt;항목&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;&lt;b&gt;조치 전&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;&lt;b&gt;조치 후&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;&lt;b&gt;개선율&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;순수 실행 시간(Execution)&lt;/td&gt;
&lt;td&gt;70 ms&lt;/td&gt;
&lt;td&gt;17 ms&lt;/td&gt;
&lt;td&gt;&lt;b&gt;약 76% 단축&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;전체 응답 시간(Execution + Fetch)&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;381 ms&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;328 ms&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;-&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Fetching 시간(311ms)은 데이터 전송량에 따른 고정 비용임을 감안할 때, 데이터베이스 엔진이 쿼리를 처리하는 &lt;b&gt;순수 연산 속도를 4배 이상(70ms &amp;rarr; 17ms) 끌어올렸습니다.&lt;/b&gt; 이는 불필요한 연산을 수행하던 CPU의 부하가 그만큼 감소했음을 뜻합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;② 데이터 탐색량 비교 (Full Scan vs Index Lookup)&lt;/h2&gt;
&lt;table style=&quot;height: 98px;&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;&lt;b&gt;테이블&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;&lt;b&gt;개선 전 (Rows)&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;&lt;b&gt;개선 후 (Rows)&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;&lt;b&gt;감소율&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;gmmae1_0&lt;span style=&quot;color: #ffffff; text-align: start;&quot;&gt;&amp;nbsp;&lt;span style=&quot;color: #000000;&quot;&gt;(권한 체크)&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;35,612 건&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;&lt;b&gt;&lt;b&gt;1 건&lt;/b&gt;&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;&lt;b&gt;&lt;b&gt;99.99%&lt;/b&gt;&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;gmmne1_0 (알림 테이블)&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;27,796 건&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;&lt;b&gt;3 건&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;&lt;b&gt;99.98%&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;③ 주요 기술적 변화&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;BNL 조인 완전 제거&lt;/b&gt;: &lt;code&gt;Extra&lt;/code&gt; 항목에서 &lt;code&gt;Block Nested Loop&lt;/code&gt; 문구가 사라지고 &lt;code&gt;ref&lt;/code&gt; 방식의 인덱스 참조로 전환되었습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;커버링 인덱스(Covering Index) 적용&lt;/b&gt;: &lt;code&gt;gmmae1_0&lt;/code&gt; 테이블은 &lt;code&gt;Using index&lt;/code&gt;가 표시되며 실제 테이블 데이터 페이지에 접근하지 않고 인덱스만으로 쿼리를 완료합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;조인 순서 최적화&lt;/b&gt;: 필터링 효율이 좋아지자 옵티마이저가 자동으로 더 최적화된 조인 순서를 선택하여 불필요한 연산을 줄였습니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;5. 마치며&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 최적화를 통해 쿼리 실행 시 탐색해야 할 행의 수가 &lt;b&gt;수만 건에서 단 몇 건 수준으로 줄어들었습니다.&lt;/b&gt; 단순히 인덱스를 거는 것을 넘어, &lt;code&gt;EXPLAIN&lt;/code&gt;을 통해 &lt;b&gt;옵티마이저가 왜 BNL을 선택했는지&lt;/b&gt; 원인을 파악하고, 그에 맞는 복합 인덱스를 설계하는 것이 얼마나 중요한지 다시 한번 깨달을 수 있었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MySQL 환경에서 조인 성능 이슈를 겪고 있다면 반드시 실행 계획에서 &lt;code&gt;Block Nested Loop&lt;/code&gt;나 &lt;code&gt;ALL&lt;/code&gt; 스캔 여부를 먼저 확인해 보시기 바랍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Database</category>
      <category>database</category>
      <category>db</category>
      <category>DB 개선</category>
      <category>MySQL</category>
      <category>개선</category>
      <category>속도 개선</category>
      <author>JackCokebb</author>
      <guid isPermaLink="true">https://jackcokebb.tistory.com/24</guid>
      <comments>https://jackcokebb.tistory.com/24#entry24comment</comments>
      <pubDate>Thu, 15 Jan 2026 00:23:25 +0900</pubDate>
    </item>
    <item>
      <title>Pagination 쿼리, 속도가 너무 느려요 !!!</title>
      <link>https://jackcokebb.tistory.com/23</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;개요&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;최근 프로젝트에서 대용량 테이블 조회 API의 성능 문제를 마주하게 되었습니다. 조회 대상은 약 50만 건에 달하는 데이터였고, 단순한 조회에도 6~7초 정도 걸려렸습니다. 더군다나 FE쪽에서도 Server Side Rendering 방식을 쓰고 있었어서, 이 API 때문에 페이지 자체 랜더링이 지연되는 문제가 생겨버렸습니다,,&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;&lt;hr data-ke-style=&quot;style1&quot; /&gt;&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;문제 상황&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;문제의 쿼리는 소속의 랭킹을 가져오는 API의 쿼리입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;특정 소속에서 진행한 프로젝트의 개수가 많을수록 랭킹이 올라가기 때문에 해당 소속에서 진행한 프로젝트의 개수를 가져오는 것이 조회 API 요구 사항중 하나였습니다. (단, ranking은 따로 계산합니다.)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제가 되는 쿼리는 다음과 같습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1745936515786&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;select
    be1_0.belonging_id,
    be1_0.belonging_type,
    be1_0.name,
    be1_0.current_ranking,
    be1_0.prev_ranking,
    count(distinct pe1_0.project_id) # 프로젝트 개수 count
from
    belonging be1_0
left join                    # 소속의 속한 사람 join
    tb_member me1_0
	on me1_0.belonging_id=be1_0.belonging_id
left join
    participant pe1_0        # 소속의 속한 사람이 참여한 project join
    on pe1_0.member_id=me1_0.member_id
where
    be1_0.belonging_type=?
group by
    be1_0.belonging_id
order by
    case
        when (be1_0.current_ranking) is null
            then 1
        else 0
        end,
    be1_0.current_ranking,
    be1_0.name
limit
    0, 20&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;&lt;hr data-ke-style=&quot;style1&quot; /&gt;&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;문제 원인 분석&lt;/span&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;인덱스 미적용&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 데이터를 쿼리하기 위해 Join도 진행하고 WHERE, ORDER BY를 사용했지만 이를 고려한 인덱스 적용은 전혀 적용되지 않았습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그에 따라 테이블 풀스캔이 일어나고 있었고 &lt;span&gt;JOIN 조건에 사용되는 컬럼들이 인덱스가 없어 모든 row를 스캔하고 있었습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span&gt;대량 데이터 조인 시 row 수 폭발 (N:N&lt;/span&gt;&lt;span&gt;:N&lt;/span&gt;&lt;span&gt; 관계)&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;우선 소속 데이터는 중학교, 고등학교, 기업들에 대한 데이터가 저장되어 있으므로 데이터가 꽤 많은 상태였습니다. (기업 데이터만 50만건)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;거기에다가 해당 소속에 속한 멤버를 left join하고, 해당 멤버가 참여한 프로젝트들에 대한 데이터를 left join 하고 있습니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이는 row수가 기하급수적으로 늘어날 수 있는 문제를 초래할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;&lt;hr data-ke-style=&quot;style1&quot; /&gt;&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;해결 방안 적용&lt;/span&gt;&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span&gt;인덱스 추가&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-spread=&quot;false&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;쿼리 최적화를 위해 다음 복합 인덱스와 조인키 인덱스를 생성했습니다.&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1746961303177&quot; class=&quot;sql&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;sql&quot;&gt;&lt;code&gt;CREATE index belonging_ranking_index ON belonging (belonging_type, current_ranking, name);

CREATE INDEX idx_tb_member_belonging_id ON tb_member(belonging_id);
CREATE INDEX idx_participant_member_id ON participant(member_id);&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-spread=&quot;false&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;이 인덱스를 통해 &lt;/span&gt;&lt;span&gt;WHERE belonging_type = ?&lt;/span&gt;&lt;span&gt; 필터링과 &lt;/span&gt;&lt;span&gt;ORDER BY current_ranking, name&lt;/span&gt;&lt;span&gt; 정렬을 동시에 커버치는 것을 노렸습니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;조인키 에 대한 인덱스를 적용하므로써 모든 row를 스캔하는 것을 막고자 했습니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span&gt;ID 선 조회 후 JOIN 전략 적용&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot; data-spread=&quot;false&quot;&gt;
&lt;li&gt;&lt;span&gt;먼저 조건에 맞는&amp;nbsp;&lt;/span&gt;&lt;span&gt;belonging_id&lt;/span&gt;&lt;span&gt;만 빠르게 조회하였습니다. (페이징 적용을 위해)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;pgsql&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot;&gt;&lt;code&gt;SELECT belonging_id
FROM belonging
WHERE belonging_type = ?
ORDER BY current_ranking, name
LIMIT ?, ?&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot; data-spread=&quot;false&quot;&gt;
&lt;li&gt;&lt;span&gt;이후 해당 ID들을 기반으로 필요한 Join을 수행하여 데이터 조회하였습니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;routeros&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot;&gt;&lt;code&gt;SELECT ...
FROM belonging
LEFT JOIN tb_member ON ...
LEFT JOIN participant ON ...
LEFT JOIN project ON ...
WHERE belonging_id IN (?, ?, ?, ...)
GROUP BY belonging_id&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot; data-spread=&quot;false&quot;&gt;
&lt;li&gt;&lt;span&gt;조인 대상 row 수를 대폭 줄여 성능 개선을 노렸습니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span&gt;Page ➞ Slice로 변경&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot; data-spread=&quot;false&quot;&gt;
&lt;li&gt;&lt;span&gt;Page&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;대신&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;Slice&lt;/span&gt;&lt;span&gt;를 사용하여&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;totalElements&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;계산을 제거했습니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;이에 따라&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;select count(*)&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;쿼리를 없애고, 단순 조회 + next 존재 여부만 판단하도록 변경했습니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;SliceImpl&lt;/span&gt;&lt;span&gt;을 사용해&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;hasNext&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;플래그만 반환하고 무한 스크롤에는 영향이 없도록 하였습니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;&lt;hr data-ke-style=&quot;style1&quot; /&gt;&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;성능 체크&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;쿼리 개선 전 성능을 살펴보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;개선 전 쿼리 성능&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_Screenshot 2025-05-11 at 7.05.24 PM.png&quot; data-origin-width=&quot;1728&quot; data-origin-height=&quot;1514&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bFrh9v/btsNReqhcRH/sy5CLtrDkuldzJEfMQ9l40/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bFrh9v/btsNReqhcRH/sy5CLtrDkuldzJEfMQ9l40/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bFrh9v/btsNReqhcRH/sy5CLtrDkuldzJEfMQ9l40/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbFrh9v%2FbtsNReqhcRH%2Fsy5CLtrDkuldzJEfMQ9l40%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1728&quot; height=&quot;1514&quot; data-filename=&quot;edited_Screenshot 2025-05-11 at 7.05.24 PM.png&quot; data-origin-width=&quot;1728&quot; data-origin-height=&quot;1514&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot 2025-05-11 at 7.09.17 PM.png&quot; data-origin-width=&quot;2852&quot; data-origin-height=&quot;874&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bav2Su/btsNR7qDyxS/CP12ZZSK2BRGcNhqxLtdX0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bav2Su/btsNR7qDyxS/CP12ZZSK2BRGcNhqxLtdX0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bav2Su/btsNR7qDyxS/CP12ZZSK2BRGcNhqxLtdX0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbav2Su%2FbtsNR7qDyxS%2FCP12ZZSK2BRGcNhqxLtdX0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2852&quot; height=&quot;874&quot; data-filename=&quot;Screenshot 2025-05-11 at 7.09.17 PM.png&quot; data-origin-width=&quot;2852&quot; data-origin-height=&quot;874&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쿼리에 explain을 붙혀 실행해보니 위와 같은 결과가 나왔습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;be1_0, me1_0, pe1_0 에 대해서 &lt;b&gt;테이블 풀스캔(type = ALL)&lt;/b&gt;이 일어나고 있었고, be1_0 에 대해서는 인덱스를 통한 정렬이 아닌 별도로 정렬(Extra = Using filesort)이 일어나고 있었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;테이블 풀스캔을 피하기 위해 다음과 같은 조치를 취해보겠습니다.&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;be1_0의 where절과 order by 절을 커버할 수 있는 복합 인덱스 추가&lt;/li&gt;
&lt;li&gt;me1_0, pe1_0의 left join에서 사용하는 조인키를 인덱스로 추가&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span&gt;인덱스 추가 후&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;추가한 인덱스는 다음과 같습니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1746960490771&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;CREATE index belonging_ranking_index ON belonging (belonging_type, current_ranking, name);

CREATE INDEX idx_tb_member_belonging_id ON tb_member(belonging_id);
CREATE INDEX idx_participant_member_id ON participant(member_id);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;쿼리 결과는 다음과 같습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1752&quot; data-origin-height=&quot;1510&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bC6xam/btsNRfvYhJ0/tHcMXNQgGQl1AmVwFckLr0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bC6xam/btsNRfvYhJ0/tHcMXNQgGQl1AmVwFckLr0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bC6xam/btsNRfvYhJ0/tHcMXNQgGQl1AmVwFckLr0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbC6xam%2FbtsNRfvYhJ0%2FtHcMXNQgGQl1AmVwFckLr0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1752&quot; height=&quot;1510&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1752&quot; data-origin-height=&quot;1510&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2888&quot; data-origin-height=&quot;548&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/HLDDv/btsNR8JXMlf/81FNST8Vx3r5KNVakJOMr1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/HLDDv/btsNR8JXMlf/81FNST8Vx3r5KNVakJOMr1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/HLDDv/btsNR8JXMlf/81FNST8Vx3r5KNVakJOMr1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHLDDv%2FbtsNR8JXMlf%2F81FNST8Vx3r5KNVakJOMr1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2888&quot; height=&quot;548&quot; data-origin-width=&quot;2888&quot; data-origin-height=&quot;548&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쿼리 속도도 반토막되고 &lt;b&gt;type&lt;/b&gt;이 &lt;b&gt;range(조건으로 인덱스 일부만 스캔)&lt;/b&gt;, &lt;b&gt;ref (인덱스를 사용해서 매칭되는 row를 탐색)&lt;/b&gt; 로 바뀐 것 보니 인덱스도 잘 적용된 모습을 보입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;be1_0에 대한 filesort 는 여전히 일어나고 있습니다. 이건 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;order by의 case&lt;span&gt; 을 통한&lt;/span&gt;&lt;/span&gt;&amp;nbsp;null 에 대한 처리 때문에 그런것 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(추가 개선에서 다루어 보겠습니다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span&gt;ID 선 조회 후 JOIN 전략 적용&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;다음은 쿼리를 page 처리를 위해 먼저 조건에 맞는 belonging_id만 빠르게 조회하는 방식을 적용한 후 성능 체크를 진행해 보았습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1616&quot; data-origin-height=&quot;762&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/XWIFu/btsNRYOqOnI/kgnMtRJZNLKSBTd8LKqVQ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/XWIFu/btsNRYOqOnI/kgnMtRJZNLKSBTd8LKqVQ0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/XWIFu/btsNRYOqOnI/kgnMtRJZNLKSBTd8LKqVQ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FXWIFu%2FbtsNRYOqOnI%2FkgnMtRJZNLKSBTd8LKqVQ0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1616&quot; height=&quot;762&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1616&quot; data-origin-height=&quot;762&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1600&quot; data-origin-height=&quot;1342&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/E0x7x/btsNRdLJ3gx/WFKSA6DyrQjqkMmssSgYc1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/E0x7x/btsNRdLJ3gx/WFKSA6DyrQjqkMmssSgYc1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/E0x7x/btsNRdLJ3gx/WFKSA6DyrQjqkMmssSgYc1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FE0x7x%2FbtsNRdLJ3gx%2FWFKSA6DyrQjqkMmssSgYc1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1600&quot; height=&quot;1342&quot; data-origin-width=&quot;1600&quot; data-origin-height=&quot;1342&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쿼리가 두개로 쪼개졌지만 둘의 실행 시간을 합쳐도 이전 단일 쿼리보다 훨씬 빠른 모습을 보입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3.530초 -&amp;gt; 0.766초&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span&gt;Page ➞ Slice로 변경&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음은 page에서 slice 형태로 응답값을 바꾸면서 page의 total element 계산 쿼리를 제거하여 쿼리 시간을 단축하고자 했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;slice 방식은, 예를 들어, page size가 20이라면 20 + 1개를 조회해서 실제 조회된 row가 21개가 된다면 다음 페이지가 있다고 판단하고 hasNext flag 값을 true로 반환하는 방식으로 적용했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 total element 계산 쿼리를 제거하였다고 봐도 무방합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제거된 total element 계산 쿼리는 다음과 같습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1610&quot; data-origin-height=&quot;320&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cO4qEh/btsNSb0BJBv/QVlYwBbMgkTTtLfhrDMvOk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cO4qEh/btsNSb0BJBv/QVlYwBbMgkTTtLfhrDMvOk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cO4qEh/btsNSb0BJBv/QVlYwBbMgkTTtLfhrDMvOk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcO4qEh%2FbtsNSb0BJBv%2FQVlYwBbMgkTTtLfhrDMvOk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1610&quot; height=&quot;320&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1610&quot; data-origin-height=&quot;320&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2382&quot; data-origin-height=&quot;272&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Gx0bm/btsNRNeU6B6/e58ZqTrAoLHe9dbOch4ZHk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Gx0bm/btsNRNeU6B6/e58ZqTrAoLHe9dbOch4ZHk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Gx0bm/btsNRNeU6B6/e58ZqTrAoLHe9dbOch4ZHk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGx0bm%2FbtsNRNeU6B6%2Fe58ZqTrAoLHe9dbOch4ZHk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2382&quot; height=&quot;272&quot; data-origin-width=&quot;2382&quot; data-origin-height=&quot;272&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실 위에 인덱스 적용, 쿼리 쪼개기 방식에서 언급은 안했지만 total element를 계산하기 위해 위 쿼리가 추가로 수행되고 있었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 쿼리를 제거한다면 &lt;b&gt;0.193초 정도 단축&lt;/b&gt;하는 효과를 볼 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;되돌아보면 이 total element 계산 때문에 시간이 많이 들것 같다고 생각했는데, 복합 인덱스가 적용되니 &lt;b&gt;type = const (단일 row만 필요할 때 옵티마이저가 상수처럼 다룸)&lt;/b&gt;로 생각보다 짧은 시간이 잡아 먹고 있었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;결론&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이번 경험&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;에서는 &lt;b&gt;ID 선 조회 패턴, &lt;/b&gt;&lt;b&gt;JOIN 최소화, 불필요한 count 제거, 인덱스 적용&lt;/b&gt;으로 쿼리 속도 개선을 진행하였습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;결론적으로 조회 속도가&amp;nbsp;&lt;b&gt;5 ~&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt;7초 ➞ 0.5초 이내 (약 10배)&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;만큼 빨라졌습니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이번 경험은 확실히 쿼리 튜닝에 대해 더 알아갈 수 있었던 좋은 기회였던 것 같습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;블로그 글을 쓰면서 아쉬웠던 점은 쿼리 성능 측정을 할때 더 큰 OFFSET 으로 설정하고 할껄 그랬다는 생각이 듭니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;여유가 된다면 OFFSET을 크게 잡고 개선사항이 더 있을지 뜯어보도록 해보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;또 페이징 성능 개선을 위해 slice 방식 외에도 NO OFFSET 방식이라고 해서 아예 다음으로 조회해야할 Id를 명시하는 방법이 있더라구요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;이 방법도 무한 스크롤이 요구사항일때는 써볼만한 방식인 것 같습니다. 요거는 FE와 합의가 되면 또 써보도록 하겠습니다.&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;감사합니다.&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;h2 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;++ 추가 개선&lt;/h2&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;위에 언급했듯이 인덱스를 적용했음에도 SQL explain을 찍다보니 여전히 filesort가 일어난다는 것을 인지하였습니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;그래서 더 분석해보았습니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;원인&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;order by 문에 case 문이 있어 인덱스를 타지 못하고 별도로 정렬를 하게 됨&lt;/li&gt;
&lt;li&gt;join으로 인해 row 수가 폭발하면서 인덱스를 사용하지 않고 별도로 정렬를 하게 됨 (쿼리 개선전 원인)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;인덱스를 이용해 정렬하려던 계획이 비용 측면에서 비효율로 판단되어 배제됨&lt;/li&gt;
&lt;li&gt;JOIN으로 인해 정렬 기준이 변형됨 -&amp;gt; 인덱스 사용 불가&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;수정&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;row 수 폭발은 id 선 조회로 해소되었습니다.&lt;/li&gt;
&lt;li&gt;case 문을 쓰는 대신 null인 current_ranking이 없도록 임의의 값을 지정하였습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;</description>
      <category>Database</category>
      <category>pagination</category>
      <category>쿼리 성능</category>
      <category>쿼리 성능 개선</category>
      <category>페이지네이션</category>
      <category>페이지네이션 개선</category>
      <category>페이지네이션 성능 개선</category>
      <category>페이징</category>
      <author>JackCokebb</author>
      <guid isPermaLink="true">https://jackcokebb.tistory.com/23</guid>
      <comments>https://jackcokebb.tistory.com/23#entry23comment</comments>
      <pubDate>Wed, 7 May 2025 23:09:44 +0900</pubDate>
    </item>
    <item>
      <title>[Java] Garbage Collector, 왜 Serical GC가 돌아가고 있지???</title>
      <link>https://jackcokebb.tistory.com/22</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;개요&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;최근 새로운 서비스를 배포하면서 예상치 못한 것을 발견하게 되었습니다. 배포 후 이것저것 살펴보던 중, Garbage Collector (이하 GC)가 &lt;/span&gt;&lt;span&gt;SerialGC로&lt;/span&gt;&lt;span&gt; 사용되고 있는 것을 알게 되었습니다. 해당 서비스는 Java 17을 사용중이었고 요즘은 G1GC가 기본 아니었나? 라고 생각했기 때문이죠.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;알고보니 JVM에 할당된 리소스 작을 경우&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&lt;b&gt;Serial GC&lt;/b&gt;&lt;/span&gt;&lt;span&gt;를 기본으로 채택한다는 사실을 알게 되었습니다. 왜 그런지 아무래도 궁금하죠? 저두요~&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span&gt;일단 Serial GC 란??&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;Serial GC&lt;/b&gt;&lt;/span&gt;&lt;span&gt;는 가장 단순한 형태의 가비지 컬렉터로, GC 작업을 &lt;/span&gt;&lt;span&gt;&lt;b&gt;단일 스레드&lt;/b&gt;&lt;/span&gt;&lt;span&gt;로 처리합니다. Stop-the-world 방식으로 모든 애플리케이션 스레드를 멈추고 GC를 수행하며, 구현이 간단하고 오버헤드가 적습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-pm-slice=&quot;1 1 []&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span&gt;JVM은 언제 Serial GC를 선택할까??&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;JVM은 실행 환경에 따라 적절한 GC를 &lt;/span&gt;&lt;span&gt;&lt;b&gt;자동으로 선택&lt;/b&gt;&lt;/span&gt;&lt;span&gt;합니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Java 17 기준으로 일반적으로 G1 GC를 사용하죠. 하지만 1 CPU이거나 가용 가능한 메모리가 &lt;span style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot;&gt;1792MB&lt;/span&gt; 이하일때 HotSpot JVM ergonomics(JVM이 실행 환경과 애플리케이션 특성을 분석하여 성능을 자동으로 최적화하는 메커니즘)에 의해 Serial GC를 쓰도록 설정된다고 합니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;즉, &lt;/span&gt;&lt;span&gt;&lt;b&gt;JVM 힙 메모리가 작거나, 단일 CPU 환경에서 실행될 경우&lt;/b&gt;&lt;/span&gt;&lt;span&gt;, JVM은 자동으로 &lt;/span&gt;&lt;span&gt;SerialGC&lt;/span&gt;&lt;span&gt;를 사용하게 됩니다. 이는 리소스 오버헤드를 최소화하고 빠른 GC 처리를 위해 설계된 전략입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span&gt;왜 JVM은 Serial GC를 선택할까??&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;h4 data-pm-slice=&quot;1 1 []&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span&gt;1. &lt;/span&gt;&lt;span&gt;멀티스레드 GC의 이점이 사라짐&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Parallel GC나 G1 GC는 GC 작업을 병렬 스레드로 처리해 GC 시간을 줄이지만, 단일 CPU 환경에서는 어차피 동시에 실행할 수 없으므로 오히려 오버헤드만 증가할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span&gt;2. &lt;/span&gt;&lt;span&gt;오버헤드 최소화&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;멀티스레드 GC는 동기화, 스레드 생성 및 스케줄링 등의 부가적인 비용이 필요합니다. 단일 스레드로 작동하는 Serial GC는 이러한 오버헤드가 없기 때문에 단순하고 빠르게 GC 작업을 수행할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span&gt;3. &lt;/span&gt;&lt;span&gt;단순한 구조가 안정성 향상&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;개발, 테스트, 경량 컨테이너 환경 등 리소스가 제한된 환경에서는 단순한 GC 동작이 더 예측 가능하고 안정적입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-pm-slice=&quot;1 1 []&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span&gt;결론&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-pm-slice=&quot;1 1 []&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;단일 CPU 환경이나 작은 메모리 환경&lt;/span&gt;&lt;span&gt;에서는 JVM이 자동으로 Serial GC를 선택할 수 있습니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-pm-slice=&quot;1 1 []&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;물론 배포하는 서비스를 이렇게 작은 리소스로 운영할 생각은 없었어서 설정을 바꾸긴 했습니다만,&amp;nbsp;&lt;/span&gt;&lt;span&gt;새로운 서비스를 배포하거나 컨테이너나 리소스가 한정된 환경에서 애플리케이션을 실행할 때는 &lt;/span&gt;&lt;span&gt;&lt;b&gt;어떤 설정으로 서버를 띄웠는지 꼭 확인해보는 습관을 들이는 것&lt;/b&gt;과&lt;b&gt; 상황에 맞는 GC를 선택하는 것&lt;/b&gt;&lt;/span&gt;&lt;span&gt;이 중요하다는 것을 이번 경험을 통해 다시 한번 느꼈습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-pm-slice=&quot;1 1 []&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-pm-slice=&quot;1 1 []&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-pm-slice=&quot;1 1 []&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-pm-slice=&quot;1 1 []&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-pm-slice=&quot;1 1 []&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;참고&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- &lt;a href=&quot;https://inside.java/2022/08/08/sip063/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://inside.java/2022/08/08/sip063/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1743344313406&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;The Serial Garbage Collector - Sip of Java &amp;ndash; Inside.java&quot; data-og-description=&quot;Let's take a look at the Serial Garbage Collector.&quot; data-og-host=&quot;inside.java&quot; data-og-source-url=&quot;https://inside.java/2022/08/08/sip063/&quot; data-og-url=&quot;https://inside.java/2022/08/08/sip063/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/c4p7yM/hyYyGHUisg/8LiRg1ckmJ6rZcOAlTdYzK/img.png?width=500&amp;amp;height=500&amp;amp;face=0_0_500_500,https://scrap.kakaocdn.net/dn/r6viN/hyYvoPDvAH/0f1e5bkyxbx7ZmuixIpRp0/img.jpg?width=600&amp;amp;height=341&amp;amp;face=114_225_182_293&quot;&gt;&lt;a href=&quot;https://inside.java/2022/08/08/sip063/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://inside.java/2022/08/08/sip063/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/c4p7yM/hyYyGHUisg/8LiRg1ckmJ6rZcOAlTdYzK/img.png?width=500&amp;amp;height=500&amp;amp;face=0_0_500_500,https://scrap.kakaocdn.net/dn/r6viN/hyYvoPDvAH/0f1e5bkyxbx7ZmuixIpRp0/img.jpg?width=600&amp;amp;height=341&amp;amp;face=114_225_182_293');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;The Serial Garbage Collector - Sip of Java &amp;ndash; Inside.java&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Let's take a look at the Serial Garbage Collector.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;inside.java&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- &lt;a href=&quot;https://docs.oracle.com/en/java/javase/18/gctuning/available-collectors.html#GUID-9E4A6B11-BB94-424F-90EF-401287A1C333&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://docs.oracle.com/en/java/javase/18/gctuning/available-collectors.html#GUID-9E4A6B11-BB94-424F-90EF-401287A1C333&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1743344319552&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;HotSpot Virtual Machine Garbage Collection Tuning Guide&quot; data-og-description=&quot;The discussion to this point has been about the serial collector. The Java HotSpot VM includes three different types of collectors, each with different performance characteristics.&quot; data-og-host=&quot;docs.oracle.com&quot; data-og-source-url=&quot;https://docs.oracle.com/en/java/javase/18/gctuning/available-collectors.html#GUID-9E4A6B11-BB94-424F-90EF-401287A1C333&quot; data-og-url=&quot;https://docs.oracle.com/en/java/javase/18/gctuning/available-collectors.html#GUID-9E4A6B11-BB94-424F-90EF-401287A1C333&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://docs.oracle.com/en/java/javase/18/gctuning/available-collectors.html#GUID-9E4A6B11-BB94-424F-90EF-401287A1C333&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://docs.oracle.com/en/java/javase/18/gctuning/available-collectors.html#GUID-9E4A6B11-BB94-424F-90EF-401287A1C333&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;HotSpot Virtual Machine Garbage Collection Tuning Guide&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;The discussion to this point has been about the serial collector. The Java HotSpot VM includes three different types of collectors, each with different performance characteristics.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;docs.oracle.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>G1</category>
      <category>garbage collecter</category>
      <category>GC</category>
      <category>Java</category>
      <category>jdk</category>
      <category>jvm</category>
      <category>Serial GC</category>
      <author>JackCokebb</author>
      <guid isPermaLink="true">https://jackcokebb.tistory.com/22</guid>
      <comments>https://jackcokebb.tistory.com/22#entry22comment</comments>
      <pubDate>Sun, 30 Mar 2025 23:24:49 +0900</pubDate>
    </item>
    <item>
      <title>Kubernetes scale-out 중 pod port에 대한 고민</title>
      <link>https://jackcokebb.tistory.com/21</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;개요&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 프로젝트에서 서버를 kubernetes 환경에 배포하여 구축하고 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;부하가 많을 것을 예상하고 scale-out을 고려하고 있었는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;spring boot의 jar 파일로 배포되는 서버는 포트가 기본적으로 8080이고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;포트 번호 8080으로 서버가 scale-out되면 포트가 중복되는 것이 아닌지 고민하게 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다른 사람들과 고민했을 때는 포트가 중복될 수 있기 때문에 랜덤 포트가 지정되도록 설정을 해야된다고 하기도 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 kubernetes 환경에서는 그럴 필요가 없었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;Kubernetes 네트워크&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;service&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;pod는 kubernetes에 올라갈 때 IP가 랜덤하게 지정되고 리스타트 때마다 또 변하기 때문에 엔드포인트를 고정하기 어렵다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;게다가 여러 pod가 같은 애플리케이션으로써 작동할때 이 pod 간의 로드밸런싱도 필요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때 Service가 이러한 문제점을 해결해준다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;784&quot; data-origin-height=&quot;552&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/stVAI/btr6OlQUWuy/KHITFCDi1Ibs61wJpvlLyK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/stVAI/btr6OlQUWuy/KHITFCDi1Ibs61wJpvlLyK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/stVAI/btr6OlQUWuy/KHITFCDi1Ibs61wJpvlLyK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FstVAI%2Fbtr6OlQUWuy%2FKHITFCDi1Ibs61wJpvlLyK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;784&quot; height=&quot;552&quot; data-origin-width=&quot;784&quot; data-origin-height=&quot;552&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;client나 다른 애플리케이션에서 특정 애플리케이션에 접근할 때, 서비스의 주소에 접근하면 로드밸런싱을 통해 하나의 pod로 할당된다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;service type&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서비스는 IP 주소 할당 방식 과 연동 서비스 등에 따라 크게 4가지로 구분된다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;cluster IP&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;디폴트 설정으로 서비스에 클러스터 IP (내부 IP)를 할당한다&lt;/li&gt;
&lt;li&gt;외부 IP를 할당한 것은 아니기 때문에 외부에서 접근이 불가능하다&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Load Balancer&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;클라우드 벤더에서 제공하는 방식&lt;/li&gt;
&lt;li&gt;외부 IP가 있는 로드 밸러서를 할당한다.&lt;/li&gt;
&lt;li&gt;외부에서도 접근 가능하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;NodePort&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;클러스터 IP로만 접근이 가능한 것이 아니라, 모든 노드의 IP와 port를 통해 접근 가능하다.&lt;/li&gt;
&lt;li&gt;예를 들어 nodePort를 30036으로 설정하면 모든 노드의 30036 포트로 서비스에 접근할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;External name&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;외부 서비스를 쿠버네티스 내부에서 호출하고자할 때 사용할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Scale-out은 어떻게 이루어지는가?&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;처음에는 pod 내에 여러 컨테이너가 동적으로 생겨서 같은 ip에 다른 port의 컨테이너가 여러개 생기는 줄 알았음&lt;/li&gt;
&lt;li&gt;찾아보니 하나의 service에 연결된 pod가 동적으로 생성되는 구조였고, pod의 ip가 service 내부 ip처럼 살짝 바뀜&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Untitled.png&quot; data-origin-width=&quot;915&quot; data-origin-height=&quot;678&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b4fJmT/btr6EVzlnHt/OFd3ffVh7jxzhEBkxZGoU1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b4fJmT/btr6EVzlnHt/OFd3ffVh7jxzhEBkxZGoU1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b4fJmT/btr6EVzlnHt/OFd3ffVh7jxzhEBkxZGoU1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb4fJmT%2Fbtr6EVzlnHt%2FOFd3ffVh7jxzhEBkxZGoU1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;504&quot; height=&quot;373&quot; data-filename=&quot;Untitled.png&quot; data-origin-width=&quot;915&quot; data-origin-height=&quot;678&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;따라서 서버의 port는 고정시켜도 괜찮음&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Kubernetes</category>
      <category>Kubernetes</category>
      <category>POD</category>
      <category>pod address</category>
      <category>pod port</category>
      <category>pod 주소</category>
      <category>scale-out</category>
      <category>Service</category>
      <category>네트워크</category>
      <category>스케일 아웃</category>
      <category>쿠버네티스 네트워크</category>
      <author>JackCokebb</author>
      <guid isPermaLink="true">https://jackcokebb.tistory.com/21</guid>
      <comments>https://jackcokebb.tistory.com/21#entry21comment</comments>
      <pubDate>Wed, 29 Mar 2023 16:28:11 +0900</pubDate>
    </item>
    <item>
      <title>[web] 그놈의 CORS와 SOP 란</title>
      <link>https://jackcokebb.tistory.com/20</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;개요&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;139&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tmQEa/btrTRpZGosW/xQcR4JP5jJqRyWoL9V0pXk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tmQEa/btrTRpZGosW/xQcR4JP5jJqRyWoL9V0pXk/img.png&quot; data-alt=&quot;https://blog.container-solutions.com/a-guide-to-solving-those-mystifying-cors-issues&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tmQEa/btrTRpZGosW/xQcR4JP5jJqRyWoL9V0pXk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtmQEa%2FbtrTRpZGosW%2FxQcR4JP5jJqRyWoL9V0pXk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;139&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;139&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://blog.container-solutions.com/a-guide-to-solving-those-mystifying-cors-issues&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최근 여러 프로젝트를 진행하다 CORS 오류를 자주 마주치게 되었다. 사실 CORS가 문제가 아니라 SOP이 문제라는 것도 레퍼런스들을 찾아보다 알게 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CORS는 Cross Origin Resource Sharing의 약자이다. Cross Origin 간의 Resource를 공유할 수 있도록 한다는 것인데 Cross Origin은 뭘까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Cross Origin?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 origin은 출처 즉, URL에서 protocol, hostname, port를 말한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;658&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/OjKC1/btrTPRb5uWb/8s127h3qVdgPtijVksawE0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/OjKC1/btrTPRb5uWb/8s127h3qVdgPtijVksawE0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/OjKC1/btrTPRb5uWb/8s127h3qVdgPtijVksawE0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOjKC1%2FbtrTPRb5uWb%2F8s127h3qVdgPtijVksawE0%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;658&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;658&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 Cross Origin은 protocol, hostname, port가 서로 다른 origin을 말한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;근데 서로 다른 origin끼리 resource를 공유하는 것이 뭐 어쨋다는 말이지??&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실 문제는 SOP 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;SOP (Same Origin Policy)?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;SOP은 동일 출처 정책&lt;/b&gt;이라고도 하며 &lt;b&gt;같은 출처에서만 리소스를 공유할 수 있다는 규칙의&amp;nbsp;정책&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 응답의 출처가 protocol, host, port 중 하나라도 다르면 SOP 오류가 뜨는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;In&amp;nbsp;&lt;a href=&quot;https://en.wikipedia.org/wiki/Computing&quot;&gt;computing&lt;/a&gt;, the&amp;nbsp;same-origin policy&amp;nbsp;(SOP) is an important concept in the web application&amp;nbsp;&lt;a href=&quot;https://en.wikipedia.org/wiki/Computer_security_model&quot;&gt;security model&lt;/a&gt;. Under the policy, a&amp;nbsp;&lt;a href=&quot;https://en.wikipedia.org/wiki/Web_browser_engine&quot;&gt;web browser&lt;/a&gt;&amp;nbsp;permits scripts contained in a first web page to access data in a second web page, but only if both web pages have the same&amp;nbsp;origin. An origin is defined as a combination of&amp;nbsp;&lt;a href=&quot;https://en.wikipedia.org/wiki/Uniform_Resource_Identifier&quot;&gt;URI scheme&lt;/a&gt;,&amp;nbsp;&lt;a href=&quot;https://en.wikipedia.org/wiki/Hostname&quot;&gt;host name&lt;/a&gt;, and&amp;nbsp;&lt;a href=&quot;https://en.wikipedia.org/wiki/Port_(computer_networking)&quot;&gt;port number&lt;/a&gt;. This policy prevents a malicious script on one page from obtaining access to sensitive data on another web page through that page's&amp;nbsp;&lt;a href=&quot;https://en.wikipedia.org/wiki/Document_Object_Model&quot;&gt;Document Object Model&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;i&gt;출처: https://en.wikipedia.org/wiki/Same-origin_policy&lt;/i&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SOP는 웹 애플리케이션 보안 모델에서 중요한 개념이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 정책 하에 웹 브라우저는 어떤 한 웹 페이지에 포함된 스크립트가 다른 페이지에 있는 데이터를 접근하려할 때, 두 페이지의 출처(origin)이 같을 때만 접근을 허용한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 이 정책은 어떤 한 웹 페이지에 있는 악성 스크립트가 다른 웹페이지에 있는 민감 정보를 DOM(Document Object Model)을 통해 접근하는 것을 막을 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;예시&lt;span style=&quot;background-color: #ffffff; color: #292929;&quot;&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #292929;&quot;&gt;SOP는 인증 정보 세션들이 다른 origin에서 사용되는 것을 막는다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #292929;&quot;&gt;만약 SOP 가 없다면??&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #292929;&quot;&gt;한 유저가 은행 업무 사이트에 로그인하고 로그아웃을 안했다고 해보자. 그리고 그 유저가 은행 사이트에 요청을 보내는 악성 스크립트가 있는 사이트를 방문했다고 하자. 유저가 아직 은행 사이트에 로그인 되어있기 때문에 악성 스크립트는 은행 사이트에서 인출, 예금 등 모든 작업을 할 수 있다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #292929;&quot;&gt;은행 사이트 관리자는 일반적인 웹 브라우저가 악성 스크립트가 은행 관련 세션 쿠키나 플랫폼 수준의 권한에 접근하는 것을 원치 않을 것이다. 자바스크립트가 은행 관련 세션 쿠키에 직접적으로 접근 권한이 없다고 하지만, 은행 사이트에 은행 세션 쿠키를 가지고 요청을 보내거나 받을 수 있는 것은 사실이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #292929;&quot;&gt;따라서 SOP는 브라우저가 다른 출처에서 온 응답들이 읽기 권한을 얻는 것을 막는다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #292929;&quot;&gt;CORS (Cross Origin Resource Sharing)&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #292929;&quot;&gt;SOP을 완화(relaxing)시키는 방법 중 하나로,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;CORS는 교차 출처 리소스 공유&lt;/b&gt;라고도 하며 &lt;b&gt;SOP에 의한 접근 제한의 예외 조항&lt;/b&gt;으로, 사전 설정을 통해 리소스에 선택적으로 접근할 수 있도록 브라우저에 알려주는 정책이다. 즉, 브라우저는 SOP에 따라 기본적으로 다른 출처의 리소스 공유를 막지만, CORS를 통해 접근 권한을 얻을 수 있게 되는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이는 Origin 요청 헤더와 Access-Control-Allow-Origin 응답 헤더를 통해 가능하다. 서버가 이 header를 사용해 데이터에 접근할 수 있는 Origin을 명시할 수 있도록 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;어떻게 CORS를 가능하게 할까?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #292929;&quot;&gt;여러 방법 중 하나로 &lt;b&gt;서버에서 특정 도메인에 대해서만 접근을 허용&lt;/b&gt;하면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1400&quot; data-origin-height=&quot;687&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/naedo/btrTQzV2IG4/NgltpXK0XGl0Lz1yR0cIX1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/naedo/btrTQzV2IG4/NgltpXK0XGl0Lz1yR0cIX1/img.png&quot; data-alt=&quot;https://developer.mozilla.org/ko/docs/Web/HTTP/CORS&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/naedo/btrTQzV2IG4/NgltpXK0XGl0Lz1yR0cIX1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fnaedo%2FbtrTQzV2IG4%2FNgltpXK0XGl0Lz1yR0cIX1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1400&quot; height=&quot;687&quot; data-origin-width=&quot;1400&quot; data-origin-height=&quot;687&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://developer.mozilla.org/ko/docs/Web/HTTP/CORS&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span&gt;단순&lt;/span&gt; &lt;span&gt;요청&lt;/span&gt; (Simple Request)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단순 요청은 서버에 바로 본 요청을 보내는 방식이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;브라우저가 예비 요청(preflight)을 보내지 않고, 즉시 실제 HTTP 요청(GET, POST, HEAD 중 하나)을 전송한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서버는 응답 헤더에&amp;nbsp;&lt;b&gt;Access-Control-Allow-Origin&lt;/b&gt;을 포함해 응답하며, 브라우저는 이를 보고 CORS 허용 여부를 결정한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단순 요청이 되려면 아래 조건을 모두 만족해야 한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;요청 메서드가 GET, POST, HEAD 중 하나일 것&lt;/li&gt;
&lt;li&gt;요청&amp;nbsp;헤더가&amp;nbsp;Accept,&amp;nbsp;Accept-Language,&amp;nbsp;Content-Language,&amp;nbsp;Content-Type(특정&amp;nbsp;값만&amp;nbsp;허용),&amp;nbsp;등&amp;nbsp;제한된&amp;nbsp;헤더일&amp;nbsp;것&lt;/li&gt;
&lt;li&gt;Content-Type이&amp;nbsp;application/x-www-form-urlencoded,&amp;nbsp;multipart/form-data,&amp;nbsp;text/plain&amp;nbsp;중&amp;nbsp;하나여야&amp;nbsp;함&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span&gt;사전&lt;/span&gt; &lt;span&gt;요청&lt;/span&gt; (Preflight Request)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사전 요청은 실제 요청을 보내기 전에 브라우저가 먼저 서버에&amp;nbsp;&lt;b&gt;OPTIONS&lt;/b&gt;&amp;nbsp;메서드로 예비 요청을 보내는 방식이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서버가 해당 실제 요청이 안전한지, 허가된 메서드인지 확인한 뒤 승인 응답을 하면 본 요청을 보낸다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 과정은 교차 출처 요청이 사용자 데이터에 영향을 줄 가능성이 있을 때 자동으로 발생한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사전 요청에 포함된 주요 헤더는 아래와 같다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Origin:&amp;nbsp;요청이&amp;nbsp;발생한&amp;nbsp;출처&lt;/li&gt;
&lt;li&gt;Access-Control-Request-Method:&amp;nbsp;실제&amp;nbsp;요청에서&amp;nbsp;사용할&amp;nbsp;HTTP&amp;nbsp;메서드&lt;/li&gt;
&lt;li&gt;Access-Control-Request-Headers:&amp;nbsp;실제&amp;nbsp;요청에&amp;nbsp;포함될&amp;nbsp;헤더&amp;nbsp;목록&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서버는 응답 헤더로&amp;nbsp;&lt;b&gt;Access-Control-Allow-Origin&lt;/b&gt;,&amp;nbsp;&lt;b&gt;Access-Control-Allow-Methods&lt;/b&gt;,&amp;nbsp;&lt;b&gt;Access-Control-Allow-Headers&lt;/b&gt;,&amp;nbsp;&lt;b&gt;Access-Control-Max-Age&lt;/b&gt;&amp;nbsp;등을 보내 허용 범위를 알린다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사전 요청을 통해 서버는 실제 요청 전 안전성 및 CORS 정책 준수 여부를 브라우저에게 알리게 된다.&lt;span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;d50a&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고 및 출처:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy&amp;nbsp;&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1671211274406&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Same-origin policy - Web security | MDN&quot; data-og-description=&quot;The same-origin policy is a critical security mechanism that restricts how a document or script loaded by one origin can interact with a resource from another origin.&quot; data-og-host=&quot;developer.mozilla.org&quot; data-og-source-url=&quot;https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy&quot; data-og-url=&quot;https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cAL4Pt/hyQUU8IM1P/7YlXqt1oLktlmvFuvohXx1/img.png?width=1920&amp;amp;height=1080&amp;amp;face=0_0_1920_1080&quot;&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cAL4Pt/hyQUU8IM1P/7YlXqt1oLktlmvFuvohXx1/img.png?width=1920&amp;amp;height=1080&amp;amp;face=0_0_1920_1080');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Same-origin policy - Web security | MDN&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;The same-origin policy is a critical security mechanism that restricts how a document or script loaded by one origin can interact with a resource from another origin.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;developer.mozilla.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Same-origin_policy&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://en.wikipedia.org/wiki/Same-origin_policy&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1671211270375&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Same-origin policy - Wikipedia&quot; data-og-description=&quot;From Wikipedia, the free encyclopedia Jump to navigation Jump to search Security measure for client-side scripting In computing, the same-origin policy (SOP) is an important concept in the web application security model. Under the policy, a web browser per&quot; data-og-host=&quot;en.wikipedia.org&quot; data-og-source-url=&quot;https://en.wikipedia.org/wiki/Same-origin_policy&quot; data-og-url=&quot;https://en.wikipedia.org/wiki/Same-origin_policy&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/lMKES/hyQU10357U/LOaKrBtNQNQlVDkQQqDH0k/img.png?width=1200&amp;amp;height=642&amp;amp;face=0_0_1200_642,https://scrap.kakaocdn.net/dn/cXrHx2/hyQUXj4XGi/bXPULMIquf0bIr4qrd5oiK/img.png?width=800&amp;amp;height=428&amp;amp;face=0_0_800_428,https://scrap.kakaocdn.net/dn/bVc88h/hyQUY4mB5p/DM8AWywD9qqtLg8OKZuMwk/img.png?width=640&amp;amp;height=342&amp;amp;face=0_0_640_342&quot;&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Same-origin_policy&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://en.wikipedia.org/wiki/Same-origin_policy&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/lMKES/hyQU10357U/LOaKrBtNQNQlVDkQQqDH0k/img.png?width=1200&amp;amp;height=642&amp;amp;face=0_0_1200_642,https://scrap.kakaocdn.net/dn/cXrHx2/hyQUXj4XGi/bXPULMIquf0bIr4qrd5oiK/img.png?width=800&amp;amp;height=428&amp;amp;face=0_0_800_428,https://scrap.kakaocdn.net/dn/bVc88h/hyQUY4mB5p/DM8AWywD9qqtLg8OKZuMwk/img.png?width=640&amp;amp;height=342&amp;amp;face=0_0_640_342');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Same-origin policy - Wikipedia&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;From Wikipedia, the free encyclopedia Jump to navigation Jump to search Security measure for client-side scripting In computing, the same-origin policy (SOP) is an important concept in the web application security model. Under the policy, a web browser per&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;en.wikipedia.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Cross-origin_resource_sharing&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://en.wikipedia.org/wiki/Cross-origin_resource_sharing&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1671211279018&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Cross-origin resource sharing - Wikipedia&quot; data-og-description=&quot;From Wikipedia, the free encyclopedia Jump to navigation Jump to search Mechanism to request restricted resources on a web page from another domain Cross-origin resource sharing (CORS) is a mechanism that allows restricted resources on a web page to be req&quot; data-og-host=&quot;en.wikipedia.org&quot; data-og-source-url=&quot;https://en.wikipedia.org/wiki/Cross-origin_resource_sharing&quot; data-og-url=&quot;https://en.wikipedia.org/wiki/Cross-origin_resource_sharing&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Cross-origin_resource_sharing&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://en.wikipedia.org/wiki/Cross-origin_resource_sharing&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Cross-origin resource sharing - Wikipedia&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;From Wikipedia, the free encyclopedia Jump to navigation Jump to search Mechanism to request restricted resources on a web page from another domain Cross-origin resource sharing (CORS) is a mechanism that allows restricted resources on a web page to be req&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;en.wikipedia.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.geeksforgeeks.org/what-is-same-origin-policy-sop/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.geeksforgeeks.org/what-is-same-origin-policy-sop/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1671211298272&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;What is Same Origin Policy (SOP)? - GeeksforGeeks&quot; data-og-description=&quot;A Computer Science portal for geeks. It contains well written, well thought and well explained computer science and programming articles, quizzes and practice/competitive programming/company interview Questions.&quot; data-og-host=&quot;www.geeksforgeeks.org&quot; data-og-source-url=&quot;https://www.geeksforgeeks.org/what-is-same-origin-policy-sop/&quot; data-og-url=&quot;https://www.geeksforgeeks.org/what-is-same-origin-policy-sop/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/dcCsg9/hyQUTaUR03/jlTk3PthxKILB7iK9RhTp0/img.png?width=200&amp;amp;height=200&amp;amp;face=0_0_200_200&quot;&gt;&lt;a href=&quot;https://www.geeksforgeeks.org/what-is-same-origin-policy-sop/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.geeksforgeeks.org/what-is-same-origin-policy-sop/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/dcCsg9/hyQUTaUR03/jlTk3PthxKILB7iK9RhTp0/img.png?width=200&amp;amp;height=200&amp;amp;face=0_0_200_200');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;What is Same Origin Policy (SOP)? - GeeksforGeeks&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;A Computer Science portal for geeks. It contains well written, well thought and well explained computer science and programming articles, quizzes and practice/competitive programming/company interview Questions.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.geeksforgeeks.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Web</category>
      <category>cors</category>
      <category>CORS policy</category>
      <category>Cross Origin Resource Sharing</category>
      <category>same origin policy</category>
      <category>sop</category>
      <category>web</category>
      <category>교차 출처 리소스 공유</category>
      <category>동일 출처 정책</category>
      <category>웹</category>
      <author>JackCokebb</author>
      <guid isPermaLink="true">https://jackcokebb.tistory.com/20</guid>
      <comments>https://jackcokebb.tistory.com/20#entry20comment</comments>
      <pubDate>Sat, 17 Dec 2022 02:23:19 +0900</pubDate>
    </item>
    <item>
      <title>WSL 외부 접속 설정하기 - ssh, 포트포워딩</title>
      <link>https://jackcokebb.tistory.com/18</link>
      <description>&lt;p data-ke-size=&quot;size14&quot;&gt;노션에 정리하고 옮겼더니 보기가 안좋다...&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;노션으로 보면 더 깔끔할지도...&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;a href=&quot;https://pickle-link-80b.notion.site/wsl-0c5fcaaa8917403f83e7fd8b8a826db8&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://pickle-link-80b.notion.site/wsl-0c5fcaaa8917403f83e7fd8b8a826db8&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1659106596288&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;wsl 외부 접속 설정하기&quot; data-og-description=&quot;개요&quot; data-og-host=&quot;pickle-link-80b.notion.site&quot; data-og-source-url=&quot;https://pickle-link-80b.notion.site/wsl-0c5fcaaa8917403f83e7fd8b8a826db8&quot; data-og-url=&quot;https://pickle-link-80b.notion.site/0c5fcaaa8917403f83e7fd8b8a826db8&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/dLgY4p/hyPgaLp6SX/wBP7iHQKxcjxt67A3c41Ik/img.png?width=820&amp;amp;height=576&amp;amp;face=0_0_820_576,https://scrap.kakaocdn.net/dn/dty63f/hyPgdOTu59/dKVNkJwVoRacfy6Q9EC211/img.png?width=820&amp;amp;height=576&amp;amp;face=0_0_820_576&quot;&gt;&lt;a href=&quot;https://pickle-link-80b.notion.site/wsl-0c5fcaaa8917403f83e7fd8b8a826db8&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://pickle-link-80b.notion.site/wsl-0c5fcaaa8917403f83e7fd8b8a826db8&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/dLgY4p/hyPgaLp6SX/wBP7iHQKxcjxt67A3c41Ik/img.png?width=820&amp;amp;height=576&amp;amp;face=0_0_820_576,https://scrap.kakaocdn.net/dn/dty63f/hyPgdOTu59/dKVNkJwVoRacfy6Q9EC211/img.png?width=820&amp;amp;height=576&amp;amp;face=0_0_820_576');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;wsl 외부 접속 설정하기&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;개요&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;pickle-link-80b.notion.site&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;개요&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;본인은 windows wsl환경에서 개발하고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개발을 하다보면 wsl에 ssh로 접속하거나 디바이스를 서버로써 활용하고 싶을 때가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 공유기 환경에서 사용하다보니 디바이스의 사설 ip가 부팅할 때마다 변경되었고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;wsl 또한 디바이스의 사설 ip와는 별개로, 가상 ip가 주어지는데 이 또한 부팅할 때마다 변경되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;wsl에 접근하기 위해서는&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;외부에 알려진 나의 공인 ip의 특정 포트를 현재 쓰고 있는 기기의 사설 ip와 포트에 포워딩해줘야 하고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그것을 다시 wsl의 ip와 포트에 포워딩 해줘야 하는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;결과적으로,&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리는 디바이스의 사설 ip를 고정해야 하며,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;부팅할 때마다 wsl의 ip를 가지고 포트를 포워딩 해줘야한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;기기의 고정 ip 할당하기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단 공인 ip의 특정 포트로 사용자 또는 request가 접근했을때,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쓰고자 하는 기기의 사설 ip의 특정 포트로 포워딩 되어야한다. 하지만 부팅할 때마다 사설 ip가 변경되면 포트포워딩 룰을 추가해두더라도 다음 부팅 시에는 그 룰이 무용지물이 되어버린다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 일단 사설 ip부터 고정해주자!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 나는 netis 공유기를 사용하고 있지만, 공유기 설정은 다른 회사 공유기더라도 대강 비슷한 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단 공유기 설정에 접근해준다. netis기준 192.168.1.1 로 접속하면 된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;820&quot; data-origin-height=&quot;576&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/DP2sD/btrIyZqglsv/NBv6oYfDwzSQT6K9QBuHq0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/DP2sD/btrIyZqglsv/NBv6oYfDwzSQT6K9QBuHq0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/DP2sD/btrIyZqglsv/NBv6oYfDwzSQT6K9QBuHq0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDP2sD%2FbtrIyZqglsv%2FNBv6oYfDwzSQT6K9QBuHq0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;460&quot; height=&quot;323&quot; data-origin-width=&quot;820&quot; data-origin-height=&quot;576&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로그인 후에 &lt;code&gt;고급설정&lt;/code&gt;에 들어가면, &lt;code&gt;기본 설정&lt;/code&gt;에 &lt;code&gt;고정 ip 주소 등록&lt;/code&gt; 이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;861&quot; data-origin-height=&quot;378&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bczt8X/btrIuXU3KlV/oyNFgNBz0qYTLKuBNgLNdk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bczt8X/btrIuXU3KlV/oyNFgNBz0qYTLKuBNgLNdk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bczt8X/btrIuXU3KlV/oyNFgNBz0qYTLKuBNgLNdk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbczt8X%2FbtrIuXU3KlV%2FoyNFgNBz0qYTLKuBNgLNdk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;630&quot; height=&quot;277&quot; data-origin-width=&quot;861&quot; data-origin-height=&quot;378&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 식으로 본인이 원하는 규칙 이름과 현재 사용 중인 pc의 mac주소, ip를 등록할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;등록하면 재부팅하더라도 이 기기는 등록된 ip로만 ip가 고정된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;포트 포워딩 (public ip:port &amp;rarr; private ip:port)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;공유기 설정에 들어온 김에 포트도 포워딩 해주자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;외부에 노출되는 공인 ip와 포트를 사설 ip와 포트에 포워딩 해주는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그대로 &lt;code&gt;고급설정&lt;/code&gt; 에서 &lt;code&gt;방화벽 설정&lt;/code&gt; 에 &lt;code&gt;포트 포워딩&lt;/code&gt; 이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기에 포워딩하고자 하는 포트를 명시해주자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;850&quot; data-origin-height=&quot;661&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bZKeIq/btrIuXtUOyu/wSJQS8mKnDcMTH1CkDkwf1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bZKeIq/btrIuXtUOyu/wSJQS8mKnDcMTH1CkDkwf1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bZKeIq/btrIuXtUOyu/wSJQS8mKnDcMTH1CkDkwf1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbZKeIq%2FbtrIuXtUOyu%2FwSJQS8mKnDcMTH1CkDkwf1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;570&quot; height=&quot;443&quot; data-origin-width=&quot;850&quot; data-origin-height=&quot;661&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 첫번째 룰은 공인 ip가 201.11.11.111 이라면,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;201.11.11.111의 2222포트로 접근하면 &lt;a href=&quot;http://192.xxx.xxx.xxx&quot;&gt;192.xxx.xxx.xxx&lt;/a&gt; 의 22번 포트로 포워딩하라는 뜻이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나는 wsl에 ssh 로 접속하고, flask 서버도 열기 위해 22번과 5000번을 포워딩했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ssh의 외부 포트를 2222로 한 것은 뻔하게 22번으로 열어두면 공격이 들어올 수 도 있다고해서 2222로 지정했지만, 사실 누가 내 컴퓨터를 공격할까 싶긴 하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;wsl에서 사전 준비&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리는 wsl의 포트 포워딩을 위해 ifconfig라는 명령어를 사용하게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 이는 디폴트로 설치되어있지 않은 것 같다. 따라서 설치해주자&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;sudo apt-get install net-tools&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;만약 ssh로 wsl에 접속하려고 하는 것이라면&amp;hellip;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;openssh-server 재설치&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이곳 저곳 알아본 결과 wsl를 설치할 때 기본으로 설치되는 openssh-server가 문제가 있다는 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;삭제하고 새로 깔아주자&lt;/p&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;sudo apt remove openssh-server
sudo apt update
sudo apt install openssh-server&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;sshd_config 파일 수정&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;sshd_config&lt;/code&gt; 파일은 ssh 설정 파일이다. ssh 서버를 열기 위해 살짝 수정해줘야한다. 수정에는 root 권한이 필요하다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;sudo vi /etc/ssh/sshd_config

Port 22
PasswordAuthentication yes

주석 처리되어 있는
#Port 22 -&amp;gt; 주석해제

PasswordAuthentication no 를 
PasswordAuthentication yes 로 변경&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;#ssh 서버 재시작
sudo service ssh --full-restart&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;ssh 서비스 부팅 시 자동 실행 설정&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;윈도우를 부팅한다고 해서 자동으로 wsl이 실행되는 것은 아니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 wsl의 ssh 서버 또한 자동으로 시작되지 않을 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요것을 자동으로 시작하도록 설정해보자!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메모장을 키고&lt;/p&gt;
&lt;pre class=&quot;coffeescript&quot;&gt;&lt;code&gt;@echo off
&quot;C:\Windows\System32\bash.exe&quot; -c &quot;sudo service ssh start&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요대로 복사한뒤 파일 이름을 &lt;code&gt;sshd.bat&lt;/code&gt;로 저장하자&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;window키 + r&lt;/code&gt; 을 눌러 실행창을 띄우고 &lt;code&gt;shell:startup&lt;/code&gt; 을 실행하여 시작프로그램 폴더를 띄운다. 그리고 이 폴더에 &lt;code&gt;sshd.bat&lt;/code&gt; 을 넣자!&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;ssh service를 sudo 비밀번호 없이 시작하도록 설정&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;service를 멈추거나 시작하려면 권한이 필요해서 비밀번호를 요구하게 된다. (sudo)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자동으로 시작하게 하기 위해 비밀번호를 절차를 없애보자.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;#sudoers 파일 열기
sudo visudo

#열린 파일 가장 밑에  이 구문을 추가하고 저장.
%sudo ALL=NOPASSWD: /usr/sbin/service&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 service를 실행할 때 비밀번호 절차 없이 가능하다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;스크립트 작성&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;재부팅될 때마다 새로 할당되는 wsl의 가상 ip를 부팅할때마다 포워드 해주기 위해 스크립트를 작성해보자&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;포트포워딩 스크립트(기기의 사설ip:port &amp;rarr; wsl의 가상 ip:port)&lt;/h3&gt;
&lt;pre class=&quot;perl&quot;&gt;&lt;code&gt;$remoteport = bash.exe -c &quot;ifconfig eth0 | grep 'inet '&quot;
$found = $remoteport -match '\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}';

if( $found ){
  $remoteport = $matches[0];
} else{
  echo &quot;The Script Exited, the ip address of WSL 2 cannot be found&quot;;
  exit;
}

#[Ports]
#All the ports you want to forward separated by coma
$ports=@(80,443,5000,22);

#[Static ip]
#You can change the addr to your ip config to listen to a specific address
$addr='0.0.0.0';
$ports_a = $ports -join &quot;,&quot;;

#Remove Firewall Exception Rules
iex &quot;Remove-NetFireWallRule -DisplayName 'WSL 2 Firewall Unlock' &quot;;

#adding Exception Rules for inbound and outbound Rules
iex &quot;New-NetFireWallRule -DisplayName 'WSL 2 Firewall Unlock' -Direction Outbound -LocalPort $ports_a -Action Allow -Protocol TCP&quot;;
iex &quot;New-NetFireWallRule -DisplayName 'WSL 2 Firewall Unlock' -Direction Inbound -LocalPort $ports_a -Action Allow -Protocol TCP&quot;;

for( $i = 0; $i -lt $ports.length; $i++ ){
  $port = $ports[$i];
  iex &quot;netsh interface portproxy delete v4tov4 listenport=$port listenaddress=$addr&quot;;
  iex &quot;netsh interface portproxy add v4tov4 listenport=$port listenaddress=$addr connectport=$port connectaddress=$remoteport&quot;;
}
Invoke-Expression &quot;netsh interface portproxy show v4tov4&quot;;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 스크립트를 그대로 메모장에 복사하고, $ports 부분에 열고자하는 port 번호를 넣는다. 본인은 아까 공유기에서 포워딩 해주었던대로 22, 5000을 넣었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저장할 때 &lt;code&gt;.ps1&lt;/code&gt;확장자로 설정해주면 된다. (확장자를 제외한 파일 이름은 자유)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 스크립트는 bash를 실행시키고 ifconfig 명령어를 실행시켜 변경된 ip를 찾고, 이전에 설정한 방화벽 설정을 지우고 변경된 ip를 적용하여 다시 방화벽 설정을 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 열고자 하는 port에 대하여 이전 포워딩 룰을 지우고 새로 등록한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;작업 스케줄러 작성 및 ExcutionPolicy 지정&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 이 스크립트를 부팅할 때마다 실행하도록 설정해 주어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;window키 + r&lt;/code&gt; 을 눌러 실행창을 띄우고 &lt;code&gt;taskschd.msc&lt;/code&gt; 를 실행하여 작업 스케줄러를 열어주자&lt;/p&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;작업 만들기&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;789&quot; data-origin-height=&quot;542&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/W19w1/btrItmAk2gW/aqmgxK7Sx9y54aHTf08II0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/W19w1/btrItmAk2gW/aqmgxK7Sx9y54aHTf08II0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/W19w1/btrItmAk2gW/aqmgxK7Sx9y54aHTf08II0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FW19w1%2FbtrItmAk2gW%2FaqmgxK7Sx9y54aHTf08II0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;515&quot; height=&quot;354&quot; data-origin-width=&quot;789&quot; data-origin-height=&quot;542&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;2. 일반 설정&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;636&quot; data-origin-height=&quot;474&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xnCgf/btrIxwbai4j/rGm5nVVe95E1k60iJreG70/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xnCgf/btrIxwbai4j/rGm5nVVe95E1k60iJreG70/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xnCgf/btrIxwbai4j/rGm5nVVe95E1k60iJreG70/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FxnCgf%2FbtrIxwbai4j%2FrGm5nVVe95E1k60iJreG70%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;530&quot; height=&quot;395&quot; data-origin-width=&quot;636&quot; data-origin-height=&quot;474&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;작업 이름 기억하기 좋은 걸로 설정&lt;/li&gt;
&lt;li&gt;가장 높은 수준의 권한으로 실행 체크&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 트리거 설정&lt;/p&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;631&quot; data-origin-height=&quot;478&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/UOURn/btrIxCii9ZP/nOI9SN13srM2Sbl3xzIsE1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/UOURn/btrIxCii9ZP/nOI9SN13srM2Sbl3xzIsE1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/UOURn/btrIxCii9ZP/nOI9SN13srM2Sbl3xzIsE1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FUOURn%2FbtrIxCii9ZP%2FnOI9SN13srM2Sbl3xzIsE1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;484&quot; height=&quot;367&quot; data-origin-width=&quot;631&quot; data-origin-height=&quot;478&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;589&quot; data-origin-height=&quot;516&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bYatMj/btrIt4UnORO/fDtZRDkFFtA3A2cya0K7j0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bYatMj/btrIt4UnORO/fDtZRDkFFtA3A2cya0K7j0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bYatMj/btrIt4UnORO/fDtZRDkFFtA3A2cya0K7j0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbYatMj%2FbtrIt4UnORO%2FfDtZRDkFFtA3A2cya0K7j0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;473&quot; height=&quot;414&quot; data-origin-width=&quot;589&quot; data-origin-height=&quot;516&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;작업 시작: 로그온할 때&lt;/li&gt;
&lt;li&gt;작업 지연 시간 30초 (ssh 서버 여는 시작프로그램 먼저 실행하기 위해)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. 동작 설정&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;623&quot; data-origin-height=&quot;470&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bA9ZhP/btrIzEsFjBx/75wZRkqaCbqS34ikYpYGyK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bA9ZhP/btrIzEsFjBx/75wZRkqaCbqS34ikYpYGyK/img.png&quot; data-alt=&quot;(본인은 이미 만들어 놔서 있는거임!!)&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bA9ZhP/btrIzEsFjBx/75wZRkqaCbqS34ikYpYGyK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbA9ZhP%2FbtrIzEsFjBx%2F75wZRkqaCbqS34ikYpYGyK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;452&quot; height=&quot;341&quot; data-origin-width=&quot;623&quot; data-origin-height=&quot;470&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;(본인은 이미 만들어 놔서 있는거임!!)&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;448&quot; data-origin-height=&quot;491&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bJgr2e/btrIzFE6ZZc/6mBkVE07eHzZHwRB9M8Lf0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bJgr2e/btrIzFE6ZZc/6mBkVE07eHzZHwRB9M8Lf0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bJgr2e/btrIzFE6ZZc/6mBkVE07eHzZHwRB9M8Lf0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbJgr2e%2FbtrIzFE6ZZc%2F6mBkVE07eHzZHwRB9M8Lf0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;448&quot; height=&quot;491&quot; data-origin-width=&quot;448&quot; data-origin-height=&quot;491&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프로그램/ 스크립트:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe&lt;/li&gt;
&lt;li&gt;powershell 프로그램 경로임&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;인수추가:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;noprofile -executionpolicy bypass -file &lt;i&gt;&amp;lt;아까 만든 .ps1 파일 경로&amp;gt;&lt;/i&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5. 조건 설정&lt;/p&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;617&quot; data-origin-height=&quot;467&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FTKCK/btrIzFd035a/GxcT6ffzKgCbpQwkVycg9K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FTKCK/btrIzFd035a/GxcT6ffzKgCbpQwkVycg9K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FTKCK/btrIzFd035a/GxcT6ffzKgCbpQwkVycg9K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFTKCK%2FbtrIzFd035a%2FGxcT6ffzKgCbpQwkVycg9K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;437&quot; height=&quot;331&quot; data-origin-width=&quot;617&quot; data-origin-height=&quot;467&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;6. 설정 탭 설정&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;632&quot; data-origin-height=&quot;475&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/8hv7R/btrIzEe7r8S/ydfpSLglkglUpi7Yk2MAbK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/8hv7R/btrIzEe7r8S/ydfpSLglkglUpi7Yk2MAbK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/8hv7R/btrIzEe7r8S/ydfpSLglkglUpi7Yk2MAbK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F8hv7R%2FbtrIzEe7r8S%2FydfpSLglkglUpi7Yk2MAbK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;445&quot; height=&quot;334&quot; data-origin-width=&quot;632&quot; data-origin-height=&quot;475&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;7. &lt;code&gt;확인&lt;/code&gt; 눌러서 저장!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 부팅할 때마다 스크립트가 실행되어 포워딩을 해줄 것이다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;스크립트 직접 돌려보기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;powershell&lt;/span&gt; 을 관리자 권한을 열고&lt;/p&gt;
&lt;pre class=&quot;css&quot;&gt;&lt;code&gt;PowerShell.exe -ExecutionPolicy Bypass -File &amp;lt;아까 만든 .ps1 스크립트 경로&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이대로 실행하면 실행 결과를 볼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;ldquo;지정된 파일을 찾을 수 없습니다.&amp;rdquo; 와 같은 오류가 뜨면 한번 더 실행해주자. 그럼 오류 없이 돌아간다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;접속 테스트&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 뭐로 접속해야 될까??&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;공인 ip와 지정한 포트로 접속하면 된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;696&quot; data-origin-height=&quot;277&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qtAsr/btrIpGzn1xR/BBSE6qJwzuzb3mVI8A3Op1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qtAsr/btrIpGzn1xR/BBSE6qJwzuzb3mVI8A3Op1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qtAsr/btrIpGzn1xR/BBSE6qJwzuzb3mVI8A3Op1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqtAsr%2FbtrIpGzn1xR%2FBBSE6qJwzuzb3mVI8A3Op1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;520&quot; height=&quot;207&quot; data-origin-width=&quot;696&quot; data-origin-height=&quot;277&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아이패드에서 터미널(termius 앱)로 테스트&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;889&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/B15dr/btrIvoYKxtv/K0wrMNrVwjZ9B1FRcCXue0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/B15dr/btrIvoYKxtv/K0wrMNrVwjZ9B1FRcCXue0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/B15dr/btrIvoYKxtv/K0wrMNrVwjZ9B1FRcCXue0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FB15dr%2FbtrIvoYKxtv%2FK0wrMNrVwjZ9B1FRcCXue0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;611&quot; height=&quot;424&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;889&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;889&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FXvfN/btrIvSlCrZn/h9m8EAUgzokkjPLjIaEYFk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FXvfN/btrIvSlCrZn/h9m8EAUgzokkjPLjIaEYFk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FXvfN/btrIvSlCrZn/h9m8EAUgzokkjPLjIaEYFk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFXvfN%2FbtrIvSlCrZn%2Fh9m8EAUgzokkjPLjIaEYFk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;622&quot; height=&quot;432&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;889&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고 및 출처&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://webisfree.com/2021-07-14/wsl2-외부-remote-ip-접속-가능하도록-설정하기-방화벽-해제&quot;&gt;https://webisfree.com/2021-07-14/wsl2-외부-remote-ip-접속-가능하도록-설정하기-방화벽-해제&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://m.blog.naver.com/seongjin0526/221778212779&quot;&gt;https://m.blog.naver.com/seongjin0526/221778212779&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://parksb.github.io/article/21.html&quot;&gt;https://parksb.github.io/article/21.html&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>wsl</category>
      <category>ssh</category>
      <category>WSL</category>
      <category>wsl port forwarding</category>
      <category>wsl ssh</category>
      <category>wsl ssh 접속</category>
      <category>wsl 외부접속</category>
      <category>wsl 포트포워딩</category>
      <author>JackCokebb</author>
      <guid isPermaLink="true">https://jackcokebb.tistory.com/18</guid>
      <comments>https://jackcokebb.tistory.com/18#entry18comment</comments>
      <pubDate>Fri, 29 Jul 2022 23:37:02 +0900</pubDate>
    </item>
    <item>
      <title>DB - 트랜잭션 관리</title>
      <link>https://jackcokebb.tistory.com/17</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555;&quot;&gt;데이터베이스는 보통 비휘발성 저장 장치인 디스크에 데이터를 저장하며,&lt;/span&gt;&lt;span style=&quot;color: #555555; letter-spacing: 0px;&quot;&gt;전체 데이터베이스의 일부분을 메인 메모리에 유지한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555;&quot;&gt;DBMS는 데이터를 고정 길이의 페이지(page)로 저장하며, 디스크에서 읽거나 쓸 때에 페이지 단위로 입출력이 이루어진다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555;&quot;&gt;메인 메모리에 유지하는 페이지들을 관리하는 모듈을 보통 페이지 버퍼(page buffer) 관리자 또는 버퍼 관리자라고 부르는데, DBMS의 많은 주요 모듈 중에서 매우 중요한 모듈 중의 하나이다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;438&quot; data-origin-height=&quot;268&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/l3nyN/btrAgo51TCI/keq5eNseZMaxktaniuquEk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/l3nyN/btrAgo51TCI/keq5eNseZMaxktaniuquEk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/l3nyN/btrAgo51TCI/keq5eNseZMaxktaniuquEk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fl3nyN%2FbtrAgo51TCI%2Fkeq5eNseZMaxktaniuquEk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;438&quot; height=&quot;268&quot; data-origin-width=&quot;438&quot; data-origin-height=&quot;268&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555;&quot;&gt; DBMS는 각 제품마다 구조가 다르기는 하지만, 위 그림과 같이 크게 질의 처리기(Query Processor)와 저장 시스템(Storage System)으로 나눠볼 수 있다. MySQL의 경우에는 InnoDB, MyISAM 등과 같이 여러 하부 저장 시스템을 선택할 수 있는데, 이와 같은 모델은 상부의 질의 처리기와 하부의 저장 시스템 간의 명확하게 구분되는 계층(layered) 구조에 해당한다.&lt;/span&gt;&lt;span style=&quot;color: #555555;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555;&quot;&gt;버퍼 관리 정책은 트랜잭션 관리에 매우 중요한 결정을 가진다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #555555;&quot;&gt;Undo???&lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;color: #555555;&quot;&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555;&quot;&gt;오퍼레이션 수행 중에 수정된 페이지들이 버퍼 관리자의 버퍼 교체 알고리즘에 따라서 디스크에 write 되는 경우가 있다. 버퍼 교체는 전적으로 버퍼의 상태에 따라서 결정되며, 일관성 관점에서 봤을 때는 임의의 방식으로 일어나게 된다. 즉 아직 완료되지 않은 트랜잭션이 수정한 페이지들도 디스크에 출력될 수 있으므로, 만약 해당 트랜잭션이 어떤 이유든 정상적으로 종료될 수 없게 되면 트랜잭션이 변경한 페이지들은 원상 복구되어야 한다. 이러한 복구를 &lt;b&gt;UNDO&lt;/b&gt;라고 한다.&lt;/span&gt;&lt;span style=&quot;color: #555555;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555;&quot;&gt; 만약 버퍼 관리자가 트랜잭션 종료 전에는 어떤 경우에도 수정된 페이지들을 디스크에 쓰지 않는다면, UNDO 오퍼레이션은 메모리 버퍼에 대해서만 이루어지면 되는 식으로 매우 간단해질 수 있다. 하지만 이 정책은 매우 큰 크기의 메모리 버퍼가 필요하다는 문제점을 가지고 있다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555;&quot;&gt;수정된 페이지를 디스크에 쓰는 시점을 기준으로 다음과 같은 두 개의 정책으로 나누어 볼 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;steal&lt;/b&gt; : 수정된 페이지를 언제든지 디스크에 쓸 수 있음
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;수정된 페이지가 어떤 시점에도 디스크에 써질 수&amp;nbsp; 있기 때문에 필연적으로 undo 로깅과 복구를 수반함&lt;/li&gt;
&lt;li&gt;거의 모든 DBMS가 채택하는 버퍼 관리 정책&lt;/li&gt;
&lt;li&gt;장점 - &lt;span style=&quot;color: #333333;&quot;&gt;필요에&amp;nbsp;따라&amp;nbsp;commit&amp;nbsp;되지&amp;nbsp;않은&amp;nbsp;buffer들을&amp;nbsp;disk로&amp;nbsp;내보내고&amp;nbsp;빈buffer로&amp;nbsp;만드는것이&amp;nbsp;가능&amp;nbsp;(메모리&amp;nbsp;활용&amp;nbsp;유연)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;no-steal&lt;/b&gt; : 수정된 페이지들을 최소한 트랜잭션 종료 시점까지는 버퍼에 유지함&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #555555;&quot;&gt;Redo???&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555;&quot;&gt;커밋한 트랜잭션의 수정은 어떤 경우에도 유지(durability)되어야 한다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555;&quot;&gt;이미 커밋한 트랜잭션의 수정을 재반영하는 복구 작업을 &lt;b&gt;REDO&lt;/b&gt; 복구라고 하는데, REDO 복구 역시 UNDO 복구와 마찬가지로 버퍼 관리 정책에 영향을 받는다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555;&quot;&gt;트랜잭션이 종료되는 시점에 해당 트랜잭션이 수정한 페이지들을 디스크에도 쓸 것인가 여부로 두 가지 정책이 구분된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;FORCE&lt;/b&gt; : 수정했던 모든 페이지를 트랜잭션 커밋 시점에 디스크에 반영함&lt;/li&gt;
&lt;li&gt;&lt;b&gt;NO-FORCE&lt;/b&gt; : 수정했던 페이지를 트랜잭션 커밋 시점에 디스크에 반영하지 않음
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;거의 모든 DBMS가 채택하는 정책&lt;/li&gt;
&lt;li&gt;장점 - &lt;span style=&quot;color: #333333;&quot;&gt;commit된 후에 바로 block을 없애지 않으면 다른 T가 그 block이 필요할때 다시 읽어들이는 과정이 생략 (I/O cost save)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555;&quot;&gt;FORCE 정책을 따르면 트랜잭션이 커밋되면 수정되었던 페이지들이 이미 디스크 상의 데이터베이스에 반영되었으므로 REDO 복구가 필요 없게 된다. 반면에 NO-FORCE 정책을 따른다면 커밋한 트랜잭션의 내용이 디스크 상의 데이터베이스 상에 반영되어 있지 않을 수 있기 때문에 반드시 REDO 복구가 필요하게 된다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;사실 FORCE 정책을 따르더라도 데이터베이스 백업으로부터의 복구인 미디어(media) 복구 시에는 REDO 복구가 요구된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #555555;&quot;&gt;트랜잭션관리&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555;&quot;&gt;UNDO 복구와 REDO 복구를 위해서 가장 널리 쓰이는 구조는 로그(log)이다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #555555;&quot;&gt;로그(log)&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555;&quot;&gt;로그는 로그 레코드의 연속이며 데이터베이스의 모든 갱신 작업을 기록한다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555;&quot;&gt;로그는 이론적으로는 안정적 저장 매체(stable storage)에 기록된다고 하는데, 안정적 저장 매체는 어떤 경우에도 절대로 손실이 발생하지 않는 실존하기 힘든 이상적인 매체이다. RAID 등 인프라 시스템의 도움 외에도 DBMS 자체적으로 여러 벌의 로그를 유지하는 등 안정적 저장 매체처럼 동작하게 하는 기법을 사용하기도 한다. 하지만 대부분 DBMS는 성능 상의 이유로 하나의 로그를 유지한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555;&quot;&gt;로그는 덧붙이는(append) 방식으로 기록되며, 각 로그 레코드는 고유의 식별자를 가진다. 로그 레코드의 식별자를 LSN(Log Sequence Number) 혹은 LSA(Log Sequence Address)라고 부른다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555;&quot;&gt;로그는 항상 뒤에 덧붙이는 방식으로 쓰이기 때문에, 로그 식별자는 단조 증가하는 성질을 가진다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555;&quot;&gt;로그 데이터는 기록할 오브젝트의 타입에 따라서 물리적/논리적 로깅으로 분류할 수 있고, 데이터베이스의 상태 또는 변화를 야기한 전이(transition)를 기록하느냐에 따라서 분류할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #555555;&quot;&gt;&lt;b&gt;물리적인 상태 로깅(physical state logging)&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;DBMS에서 가장 널리 쓰이는 기본적인 로깅 방법&lt;/li&gt;
&lt;li&gt;갱신 이전 이미지와 이후 이미지를 모두 다 가지고 있으며, UNDO 복구 때에는 이전 이미지로 현재 이미지를 대체하며, REDO 복구 때에는 이후 이미지를 반영하는 방식으로 복구가 이루어짐&lt;/li&gt;
&lt;li&gt;결국 이전 이미지 혹은 이후 이미지로 단순히 대체하는 작업&lt;/li&gt;
&lt;li&gt;예를 들어,
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;UPDATE 문장에 대한 로깅은 수정 이전 이미지(즉, 수정 전 레코드 이미지)와 이후 이미지(새로 갱신하는 레코드 이미지)를 모두 기록하고, UNDO 시에는 수정 이전 이미지로 대체하는 식&lt;/li&gt;
&lt;li&gt;REDO가 필요한 경우에는 수정 이후 이미지를 반영하는 식&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;물리적 상태 로깅은 때로는 페이지 수준(예를 들어, 인덱스나 데이터 파일의 헤더 페이지의 변경 로깅)에서 이루어지기도 하고, 레코드 수준에서 이루어지기도 함&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;물리적인 전이 로깅(physical transition logging)&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #555555;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;페이지 혹은 레코드에 대해서 이전 및 이후 이미지를 모두 기록하기 보다는 XOR 차이점을 기록하는 방식&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #555555;&quot;&gt;복구 시점에서 로그 레코드에 기록된 XOR 이미지와 레코드 이미지를 이용하여 UNDO 복구와 REDO 복구를 수행&lt;/span&gt;&lt;span style=&quot;color: #555555;&quot;&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #555555;&quot;&gt;논리적인 전이 로깅(logical transition logging)&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;오퍼레이션 로깅(operation logging)이라고도 함&lt;/li&gt;
&lt;li&gt;물리적인 로깅이 결과 값을 기록하는 방식이라면 논리적인 로깅은 어떤 일을 했었는가를 기록하는 방식&lt;/li&gt;
&lt;li&gt;예를 들어,
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;a = a + 1과 같은 연산을 로깅할 때 이전 값 0, 이후 값 1을 물리적으로 기록할 수도 있고, a = a + 1 이라는 연산 그 자체를 기록 가능.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;논리적인 로그에 대한 복구 작업은 REDO를 위하여 로그 레코드에 기록된 오퍼레이션을 재수행하거나, UNDO를 위하여 역 오퍼레이션을 수행하는 방식으로 이루어진다.&lt;/li&gt;
&lt;li&gt;로그 레코드의 크기를 크게 줄여준다는 장점&lt;/li&gt;
&lt;li&gt;물리적으로 복구하기 쉽지 않은 자료 구조에 대한 로깅을 쉽게 해줌
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;예를 들어, 인덱스 구조로 많이 사용되는 B+-tree 또는 B-tree 는 split, merge 와 같은 SMO(Structure Modification Operation)를 통해서 레코드의 위치가 계속 변경됨&lt;/li&gt;
&lt;li&gt;따라서 로깅 시점과 복구 시점의 데이터 물리적 위치가 같다는 점이 보장되지 않기 때문에(페이지 내의 위치가 다를 수도 있고, 심지어 다른 페이지에 위치할 수도 있다), 물리적인 로그를 통해서 복구하기가 쉽지 않지만, 논리적인 로그를 통해서 보다 쉽게 복구할 수 있음.&lt;/li&gt;
&lt;li&gt;즉, 인덱스에 키 값 k와 포인터 p가 저장되었다는 논리 로그에 대한 REDO 복구는 인덱스에 (k, p)를 다시 삽입하는 작업이면 충분하고, UNDO 복구는 (k, p)를 인덱스에서 제거하는 작업을 수행하면 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555;&quot;&gt;DBMS 제품들은 위 물리적인 상태 로깅, 물리적인 전이 로깅, 논리적인 전이 로깅 방법 중에 하나만을 선택하여 사용하는 것이 아니라 이들을 적절하게 혼용한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #555555;&quot;&gt;로그가 쓰여지는 방식&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555;&quot;&gt;로그는 로그 타입에 관계없이 다음의 규칙에 따라 써진다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;해당 업데이트가 데이터베이스에 써지기 전에 먼저 관련된 UNDO 정보가 로그에 써져야 한다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이 원칙을 &lt;b&gt;WAL(Write Ahead Logging)&lt;/b&gt;이라고 부름. 어떤 경우에도 UNDO 복구가 되기 위해서는 반드시 WAL 규칙이 준수되어야 함.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;트랜잭션이 정상적으로 종료 처리되기 위해서는 먼저 REDO 정보가 로그에 써져야 한다. 역시 어떤 경우에도 REDO 복구를 할 수 있기 위해서는 REDO 로그가 적어도 커밋 시점에는 써져야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #555555;&quot;&gt;Write Ahead Logging(WAL)&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;모든 수정은 적용하기 전에 먼저 로그에 기록함&lt;/li&gt;
&lt;li&gt;트랜잭션 발생시 로그에 일단 작성하여 기록을 남기고, 데이터가 쌓이면 이를 disk에 data block 형태로 flush 함&lt;/li&gt;
&lt;li&gt;도중에 트랜잭션이 fail되어도 현재까지 이뤄진 작업과 앞으로 해야할 작업을 로그로 분석하여 다시 진행 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DBMS는 로그 레코드를 위한 별도의 버퍼를 유지하는데, 이를 로그 버퍼라고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로그 버퍼 관리는 DBMS마다 서로 다른 방식으로 구현하지만 로그 버퍼를 통해서 로그 파일에 입출력한다는 점은 같다. 성능을 위해서 로그 버퍼에 로그 레코드를 모았다가 블록 단위로 로그 파일에 출력한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;트랜잭션들이 동시에 수행을 하면서 각각의 연산에 대해서 로그 레코드를 생성하게 되는데, 이들은 로그 버퍼에 유지되게 되고 몇몇 시점에 로그 파일에 써지게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로그 버퍼에 유지된 로그 레코드는&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;어떤 트랜잭션이 커밋을 요청한 경우&lt;/li&gt;
&lt;li&gt;WAL을 해야 하는 경우&lt;/li&gt;
&lt;li&gt;로그 버퍼가 다 소진된 경우&lt;/li&gt;
&lt;li&gt;DBMS가 내부적으로 필요로 하는 경우(예를 들어, 체크 포인트(checkpoint) 연산, 로그 관리 연산 등&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 경우에 로그 파일에 출력된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로그 버퍼는 상대적으로 작기 때문에 긴 트랜잭션이 수행 중인 경우에는 로그 버퍼가 소진될 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어떤 트랜잭션이 커밋을 요청하는 경우에는 해당 트랜잭션의 마지막 로그 레코드까지 출력하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;로그로 어떻게 복구???&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555;&quot;&gt;복구에는 두 가지 종류로, &lt;/span&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;사용자의 요청 또는 오류 발생 등으로 인해서 시스템이 트랜잭션을 철회하는 경우&lt;/li&gt;
&lt;li&gt;소프트웨어 문제나 하드웨어 문제 등으로 인해서 장애가 발생하고 데이터베이스 시스템이 재시작 복구(restart recovery)하는 경우&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #555555;&quot;&gt;트랜잭션 철회&lt;/span&gt;&lt;span style=&quot;color: #555555;&quot;&gt;??&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555;&quot;&gt;&lt;span style=&quot;color: #555555;&quot;&gt;트랜잭션을 철회하는 경우는 시스템은 정상적으로 동작하고 있는 중이며 특정 트랜잭션만 철회하는 경우이다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;먼저 로그를 역방향으로 탐색하면서 해당 트랜잭션의 UNDO 복구가 필요한 로그를 찾아서 이에 해당하는 UNDO 연산을 수행
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;역방향으로 로그를 탐색하면서 트랜잭션 수행 순서의 역순으로 UNDO를 수행해야 정확하게 UNDO가 이루어질 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;UNDO를 수행하고 나면 해당 UNDO 작업에 대한 보상 로그 레코드(CLR, Compensation Log Record)라고 하는 REDO 전용 로그를 쓰게 되는데, UNDO를 하고 난 이후에 다시 UNDO를 해서 복구가 잘못 이루어지지 않도록 하기 위함
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;CLR은 이전 로그 레코드 위치를 UNDO 로그의 이전 로그를 가리키도록 하여 이후에는 한 번 UNDO된 로그를 다시 접근하여 재차 UNDO하게 되는 일이 발생되지 않도록 해줌.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;이전 로그를 계속 탐색하면서 해당 트랜잭션의 시작 로그까지 도달하면 해당 트랜잭션의 철회 복구가 완료된 것&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;재시작 복구??&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555;&quot;&gt;장애 발생 이후 데이터베이스가 재시작 복구하는 경우에는 크게 3 단계로 복구가 이루어진다.&lt;/span&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;로그 분석 단계, &lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;마지막 체크포인트(checkpoint) 시점부터 최근 로그(EOL, End of Log)까지 로그를 탐색하면서 어디서부터 시스템이 복구를 시작해야 하는지, 어느 트랜잭션들을 복구해야 하는지 등등을 알아내는 단계&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;REDO 복구 단계,
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;복구를 시작해야 하는 시점부터 장애 발생 직전 시점까지 REDO가 필요한 모든 로그를 REDO 복구를 하는 단계.&lt;/li&gt;
&lt;li&gt;이 단계에서는 심지어 실패한 트랜잭션의 REDO 로그조차도 REDO를 하게 됨
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이렇게 하면 이후의 복구 단계를 매우 간단하게 하는 효과를 가져다 줌.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;이 단계에서는 모든 트랜잭션에 대해서 REDO 복구만 한다는 점이 중요
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이러한 REDO 복구가 완료된 시점의 데이터베이스 상태는 장애 발생 시점의 상태와 같게 됨.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&amp;nbsp;UNDO 복구 단계
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;로그를 최신 시점부터 다시 역방향으로 탐색하면서 UNDO 복구가 필요한 로그들에 대해서 UNDO 복구를 수행.&lt;/li&gt;
&lt;li&gt;여기서 수행하는 UNDO는 결국 위에서 설명한 트랜잭션 철회 시에 수행하는 UNDO와 같은 방식&lt;/li&gt;
&lt;li&gt;repeating history를 통해 데이터베이스 상태를 장애 시점까지 복원해두고 UNDO 복구를 여러 트랜잭션의 철회로 해결할 수 있음.&lt;/li&gt;
&lt;li&gt;한 트랜잭션만 철회시키는 것이 아니라 여러 트랜잭션을 철회시킨다는 차이점만 존재. &lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555;&quot;&gt;참고 및 출처 :&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555;&quot;&gt;&lt;a href=&quot;https://d2.naver.com/helloworld/407507&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://d2.naver.com/helloworld/407507&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;</description>
      <category>Database</category>
      <author>JackCokebb</author>
      <guid isPermaLink="true">https://jackcokebb.tistory.com/17</guid>
      <comments>https://jackcokebb.tistory.com/17#entry17comment</comments>
      <pubDate>Sat, 23 Apr 2022 19:09:02 +0900</pubDate>
    </item>
    <item>
      <title>DB - 동시성 제어와 lock</title>
      <link>https://jackcokebb.tistory.com/16</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Transaction??&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;transaction(트랜잭션)이란 Database Managemet System에서 데이터를 다루는 논리적인 작업의 단위를 나타낸다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터베이스에 삽입, 수정 등의 작업을 할 때, 여러 개의 작업들을 하나의 transaction으로 묶는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어, A 계좌에서 B 계좌로 돈을 전송한다고 할 때, A 계좌에서 돈을 빼는 작업과 B 계좌에 돈을 넣는 작업이 이루어지게 된다. 이 두 가지의 작업(2개의 SQL 문)을 개별적으로 수행하는 것이 아니라 하나의 트랜잭션으로 묶는다. 그리고 묶인 트랜잭션안에 작업들 중 몇 개만 실행되는 상황은 발생하지 않기 때문에 All or nothing이라 하고 트랜잭션의 성질중 Atomicity를 나타낸다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;동시성 제어(concurrency control)&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;동시성 제어란, 여러 사용자가 있는 환경에서 둘 이상의 트랜잭션이 동시에 수행될 때, 데이터의 일관성을 해치지 않도록 하는 제어법이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;동시성 제어의 목적&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;트랜잭션의 직렬성 보장&lt;/li&gt;
&lt;li&gt;공유도 극대화, 응답 시간 최소화, 시스템 활용의 극대화&lt;/li&gt;
&lt;li&gt;데이터의 무결성과 일관성 보장&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;동시성 제어가 없을 경우&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;갱신 손실(lost update)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;하나의 트랜잭션이 갱신한 내용을 다른 트랜잭션이 덮어써서 갱신이 무효화 됨&lt;/li&gt;
&lt;li&gt;두 개 이상의 트랜잭션이 한 개의 데이터를 동시에 갱신할 때 발생함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;현황파악오류(dirty read)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;읽기 작업을 하는 트랜잭션이, 쓰기 작업을 하는 트랜잭션의 중간 데이터를 읽으면 문제가 발생할 수 있음&lt;/li&gt;
&lt;li&gt;작업중인 트랜잭션이 작업을 롤백(rollback)한 경우, 다른 트랜잭션이 무효화된 데이터를 읽게 될 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;모순성(inconsistency)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;어떤 트랜잭션이 데이터를 갱신하는 동안 다른 두 트랜잭션 중 하나는 갱신되기 전의 값을 익고 다른 하나가 갱신된 후의 값을 읽게 되어 불일치하는 경우&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;연쇄복귀(cascading rollback)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;두 트랜잭션이 동일한 데이터 내용을 접근할 때 발생&lt;/li&gt;
&lt;li&gt;한 트랜잭션이 데이터를 갱신하다 실패하여 rollback하는 과정에서 다른 트랜잭션이 갱신과 rollback 연산을 실행하고 있던 데이터를 읽어서 사용하는 경우 문제 발생&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;락(lock)&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;locking이란 트랜잭션들이 같은 데이터에 대해 동시에 접근하지 못하도록 제어하는 것을 말한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어떤 트랜잭션이 데이터에 Read나 Write 연산을 수행하려면 반드시 lock을 해주어야한다. 또 수행이 끝나면 unlock을 해주어야 한다. 이미 lock이 걸려있는 데이터에 대해서는 다시 lock을 걸 수 없고, 당연히 lock을 걸지 않았으면 unlock 할 수 도 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;공유락 (shared lock)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;트랜잭션은 데이터에 대해 읽을 수 있지만 쓸 수는 없다.&lt;/li&gt;
&lt;li&gt;Read는 서로 영향을 주지 않기 때문에 서로 다른 트랜잭션이 같은 데이터에 대해 동시에 shared lock을 설정할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;배타락(exclusive lock)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;한 트랜잭션이 어떤 데이터에 대해 배타락을 건 경우, 그 트랜잭션은 해당 데이터를 읽고 쓸 수 있다.&lt;/li&gt;
&lt;li&gt;단, Write는 다른 트랜잭션에 영향을 주는 작업이기 때문에 다른 트랜잭션은 배타락이 걸린 데이터에 어떤 락도 걸 수 없다.&lt;/li&gt;
&lt;li&gt;트랜잭션이 락을 허용받지 못하면 대기 상태가 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;데드락(Deadlock, 교착 상태)&lt;/b&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Deadlock???&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;교착상태란 두 개 이상의 트랜잭션이 특정 데이터(테이블, 행)에 대해 다른 프로세스가 점유하고 있는 자원을 서로 기다릴 때 무한 대기에 빠지는 상황을 말한다. 즉, 두 트랜잭션이 각각 lock을 설정하고, 서로의 lock에 접근하여 값을 얻어오려고 할 때, 서로의 lock으로 인해 양쪽 트랜잭션이 영원히 처리되지 않는 상태이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;데드락 감지 기법(deadlock detection)&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;wait-for-graph 기법은 교착상태를 감지하는 기법 중에 하나다. 이 기법은 트랜잭션과 lock을 기반으로 그래프를 그린다. 그려진 그래프가 닫힌 루프 형태이거나 사이클을 이루면 교착상태에 빠졌음을 알 수 있다. 작은 데이터베이스에 이 기법이 적합하다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;727&quot; data-origin-height=&quot;345&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/biGrSV/btrzxa3hWCt/yZIDlJQHuIw6zddmc49X81/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/biGrSV/btrzxa3hWCt/yZIDlJQHuIw6zddmc49X81/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/biGrSV/btrzxa3hWCt/yZIDlJQHuIw6zddmc49X81/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbiGrSV%2Fbtrzxa3hWCt%2FyZIDlJQHuIw6zddmc49X81%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;579&quot; height=&quot;275&quot; data-origin-width=&quot;727&quot; data-origin-height=&quot;345&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;데드락 회피 기법&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터베이스가 교착상태에 빠지면, 데이터베이스를 종료하거나 재시작하는 것보다 회피하는 것이 낫다. 이 회피 기법은 사이즈가 작은 데이터베이스에 적합하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;회피 방법 중 하나는 &lt;span style=&quot;background-color: #ffffff; color: #273239;&quot;&gt;application-consistent logic을 사용하는 것이다. 위에 그림을 예시로 봤을때, student와 grade를 접근하는 트랜잭션은 항상 테이블에 같은 순서로 접근하도록 하는 것이다. 그러면 T1은 T2가 grade에 대한 lock을 놓기를 기다렸다가 T2가 놓으면 T1이 트랜잭션을 수행하는 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또 다른 방식은 &lt;span style=&quot;background-color: #ffffff; color: #273239;&quot;&gt;row-level locking mechanism과 &lt;span style=&quot;background-color: #ffffff; color: #273239;&quot;&gt;READ COMMITTED isolation level을 동시에 사용하는 것이다. 하지만 이것은 완벽하게 교착상태를 없앤다고 보장할 수 없다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;&lt;span style=&quot;background-color: #ffffff; color: #273239;&quot;&gt;READ COMMITTED : 읽는 시점의 data가 committed 된 것임을 보장한다. dirty read를 허용하지 않는다는 뜻이다.&amp;nbsp;&lt;/span&gt;&lt;/i&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;데드락 예방 기법&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;wait-die 방식&lt;/b&gt;&amp;nbsp;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;트랜잭션 A가 B에 의해 lock된 데이터를 요청할 때, DBMS는 두 트랜잭션의 timestamp를 확인하여 더 오래된 트랜잭션은 기다리게 해준다. 즉 B에 의해 lock된 데이터를 A가 기다리고 있고 A가 B보다 더 오래됐다면, B는 killed 되지 않고 기다릴 수 있다. 하지만 B가 점유하고 있는 데이터를 A가 기다리고 있고 A가 B보다 오래되지 않았으면 A는 kill된다. 그리고 랜덤한 delay 이후에 동일 timestamp로 재시도한다.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;wound-wait 방식&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;트랜잭션 A가 데이터를 점유하고 있고 B가 그 데이터를 요구하는 시점에서, A보다 B가 더 오래된 트랜잭션이라면 A를 강제로 kill하고 자원을 놓게 한다. 그리고 A는 나중에 동일한 timestamp를 가지고 재시도한다. 반면에 B가 더 최근 트랜잭션이라면 A의 점유가 끝날때까지 기다린다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;928&quot; data-origin-height=&quot;296&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/GS7Yu/btrzAWoYyLM/KySZUgwINom7wuEJfROYO1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/GS7Yu/btrzAWoYyLM/KySZUgwINom7wuEJfROYO1/img.png&quot; data-alt=&quot;출처 - https://www.geeksforgeeks.org/deadlock-in-dbms/&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GS7Yu/btrzAWoYyLM/KySZUgwINom7wuEJfROYO1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGS7Yu%2FbtrzAWoYyLM%2FKySZUgwINom7wuEJfROYO1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;584&quot; height=&quot;186&quot; data-origin-width=&quot;928&quot; data-origin-height=&quot;296&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처 - https://www.geeksforgeeks.org/deadlock-in-dbms/&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Database</category>
      <category>database</category>
      <category>database deadlock</category>
      <category>db</category>
      <category>deadlock</category>
      <category>교착상태</category>
      <category>데드락</category>
      <category>데이터베이스</category>
      <category>데이터베이스 데드락</category>
      <author>JackCokebb</author>
      <guid isPermaLink="true">https://jackcokebb.tistory.com/16</guid>
      <comments>https://jackcokebb.tistory.com/16#entry16comment</comments>
      <pubDate>Sun, 17 Apr 2022 01:43:57 +0900</pubDate>
    </item>
    <item>
      <title>OS - File System(파일시스템)</title>
      <link>https://jackcokebb.tistory.com/15</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;File System???&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;운영체제와 모든 데이터, 프로그램의 저장과 접근을 위한 기법을 제공한다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;사용자의 응용프로그램을 실행하면서 생기는 정보를 &lt;b&gt;파일&lt;/b&gt;이라는 단위로 저장하고 관리하는 운영체제의 서브 시스템이다. &lt;b&gt;파일&lt;/b&gt;은 일반적으로 레코드(record) 혹은 블록(block)단위로 비휘발성 보조기억장치에 저장된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;시스템 내의 모든 파일에 관한 정보를 제공하는 계층적 디렉터리 구조이며, 파일과 파일의 메타데이터, 디렉토리 정보 등을 관리한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;파일 시스템의 목적&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;하드디스크와 메인 메모리 속도 차를 줄일 수 있다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;파일 관리&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;하드디스크 용량을 효율적으로 이용할 수 있다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;메타데이터 :&amp;nbsp;&lt;/b&gt;파일을 관리하기 위해 필요한 정보들을 말한다. 단, 파일 속 내용을 말하는 것은 아니다. 파일 이름, 유형, 저장된 위치, 파일 사이즈, 접근 권한, 소유자, 생성/변경/사용 시간 등 파일에 관련된 전반적인 정보를 말한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;파일 시스템의 기능 및 역할&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;1. 사용자가 파일을 생성, 삭제, 수정 할 수 있게 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;2. 여러 사용자가 파일을 공유할 수 있도록 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;3. 주기억장치와 보조기억장치 간의 파일 전송을 담당한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;4. 파일에 대한 백업과 복구를 할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;5. 각 응용에 적합한 구조로 파일을 구성할 수 있도록 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;6. 접근 방법을 제공한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;파일 디스크립터(File Descriptor)&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;파일을 관리하기 위한 메타데이터를 보관하는 &lt;b&gt;파일제어블록(File Control Block, FCB)&lt;/b&gt;이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;보조기억장치(HDD 등)에 있다가 파일이 오픈되면 주기억장치(RAM&amp;nbsp; 등)로 이동한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;파일시스템이 관리하고 있으며 사용자가 직접 참조할 수 없다. 또한 파일마다 독립적으로 파일 디스크립터를 가지고 있고, 그 내용이 다 다르다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;785&quot; data-origin-height=&quot;522&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/n0YcW/btrxiFKXsm2/LC0R13W42QHWQAeY2y5eu0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/n0YcW/btrxiFKXsm2/LC0R13W42QHWQAeY2y5eu0/img.png&quot; data-alt=&quot;구성 요소&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/n0YcW/btrxiFKXsm2/LC0R13W42QHWQAeY2y5eu0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fn0YcW%2FbtrxiFKXsm2%2FLC0R13W42QHWQAeY2y5eu0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;337&quot; height=&quot;224&quot; data-origin-width=&quot;785&quot; data-origin-height=&quot;522&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;구성 요소&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;파일 시스템의 구조&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;파일 시스템은 디스크에 저장되어 있으며, 여러 레벨로 구성되어 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;1. Logical File System : 메타데이터 정보를 관리한다. 디렉토리 구조를 관히라며 FCB를 가지고 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;2. File-Organization Module : 물리 블럭과 논리 블럭을 알고 있어서 논리 주소를 물리 주소로 변경해 준다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;3. Basic File System : 장치 드라이버에게 물리 블록을 읽고 쓰도록 명령한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;4. I/O Control : device driver와 interrupt handler로 이루어져 있고, 고수준 언어의 명령을 device에 맞는 저수준 언어로 변경해준다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;Access Methods&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;시스템이 제공하는 파일 정보의 접근 방식은 순차접근, 직접 접근, 색인 접근으로 나뉜다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;1. 순차 접근(sequential Access)&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;파일의 정보가 레코드 순서대로 처리된다. 현재 위치에서 읽거나 쓰면 offset이 자동으로 증가하고, 뒤로 돌아가기 위해선 되감기가 필요하다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이 접근 방식은 가장 일반적이고, 편집기나 컴파일러가 사용한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;읽기와 쓰기가 파일 연상의 대부분을 차지하고 있다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;읽기 연산은 파일의 다음 부분부터 읽어 나가며 자동적으로 입출력 위치를 추적하는 파일 포인터를 증가시킨다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;쓰기 연산은 파일의 끝 부분에 내용을 추가하며 새로운 파일의 끝으로 파일 포인터가 이동한다. 오프셋을 시작점이나 마지막 점으로 이동시킬 수 있고, n 정수만큼 건너 뛸 수도 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;831&quot; data-origin-height=&quot;240&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bLzwRY/btrxkKksGFm/sDIur07o05nxKrH9SERLTk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bLzwRY/btrxkKksGFm/sDIur07o05nxKrH9SERLTk/img.png&quot; data-alt=&quot;순차접근&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bLzwRY/btrxkKksGFm/sDIur07o05nxKrH9SERLTk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbLzwRY%2FbtrxkKksGFm%2FsDIur07o05nxKrH9SERLTk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;443&quot; height=&quot;128&quot; data-origin-width=&quot;831&quot; data-origin-height=&quot;240&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;순차접근&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;2. 직접 접근(Random Access)&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;파일의 레코드를 임의의 순서로 접근할 수 있다.&amp;nbsp; 디스크 모델에 기반을 두고 있고, 이는 무작위 파일 블럭에 대한 임의 접근을 허용하기 때문이다. 파일을 번호를 가지고 있는 블록 또는 레코드로 간주한다고 보면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;읽기나 쓰기의 순서와 제약이 없고, 현재 위치(변수 cp)를 유지할 수 있으면 이를 통해 순차 접근 기능도 구현할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;대규모 정보를 즉각적으로 접근하는 데에 유용하기 때문에 데이터베이스에 이용된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;직접 접근 방법을 위해 파일 연산이 블록 번호 매개변수를 포함할 수 있도록 수정되어야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;사용자가 운영체제에 제공하는 블록 번호는 통상적으로 상대 블럭 번호이다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;파일의 시작을 0으로 보고 계산한 레코드의 위치이며, 예를 들어 실제로 첫번째 블럭에 대한 절대적인 디스크의 주소가 12383이고, 두번째 블럭은 42312이더라도 파일의 첫번째 상대 블럭은 0이고 다음 블럭은 1이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이러한 상대적 블럭번호의 사용은 운영체제로 하여금 파일이 어디에 저장되어야 하는지 결정하게 하고, 사용자가 자신의 파일이 아닌 곳에 접근하는 것을 미리 막는다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1424&quot; data-origin-height=&quot;628&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qBlkV/btrxsEqrKID/jBO4dLIKdNVuYEW9YifiE0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qBlkV/btrxsEqrKID/jBO4dLIKdNVuYEW9YifiE0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qBlkV/btrxsEqrKID/jBO4dLIKdNVuYEW9YifiE0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqBlkV%2FbtrxsEqrKID%2FjBO4dLIKdNVuYEW9YifiE0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;531&quot; height=&quot;234&quot; data-origin-width=&quot;1424&quot; data-origin-height=&quot;628&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;3. 색인 접근(Index Access)&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;파일에서 레코드를 찾기 위해 색인을 먼저 찾고 그에 대응되는 포인터를 얻는다. 이 포인터로 파일에 직접 접근하여 원하는 데이터를 얻을 수 있다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;크기가 큰 파일을 입출력 탐색할 수 있게 도와준다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;대용량 파일에 경우 색인 파일 자체도 매우 크고 메모리를 많이 잡아먹게 된다. 이에 대한 해결책으로 색인파일에 대한 또 다른 색인 파일을 생성하는 것이다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1456&quot; data-origin-height=&quot;980&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b53yPx/btrxlqG1YbG/D3Fu8jCIfXGqJmZLmJ5xvK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b53yPx/btrxlqG1YbG/D3Fu8jCIfXGqJmZLmJ5xvK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b53yPx/btrxlqG1YbG/D3Fu8jCIfXGqJmZLmJ5xvK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb53yPx%2FbtrxlqG1YbG%2FD3Fu8jCIfXGqJmZLmJ5xvK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;457&quot; height=&quot;308&quot; data-origin-width=&quot;1456&quot; data-origin-height=&quot;980&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>운영체제</category>
      <category>File System</category>
      <category>filesystem</category>
      <category>Operating System</category>
      <category>OS</category>
      <category>os file system</category>
      <category>운영체제</category>
      <category>운체</category>
      <author>JackCokebb</author>
      <guid isPermaLink="true">https://jackcokebb.tistory.com/15</guid>
      <comments>https://jackcokebb.tistory.com/15#entry15comment</comments>
      <pubDate>Sun, 27 Mar 2022 00:20:00 +0900</pubDate>
    </item>
    <item>
      <title>OS - Context Switching 이론 공부</title>
      <link>https://jackcokebb.tistory.com/14</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Context Switching이란?&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CPU는 한번에 하나의 프로세스만 처리할 수 있다. CPU 자원을 공유해서 여러 프로세스가 쓰기 위해서는 context swtiching 과정이 필요하다.&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러 프로세스를 처리해야 하는 상황에서 현재 진행중인 Task(프로세스, 스레드)의 상태를 PCB(Process Control Block)에 저장하고 다음에 진행할 Task의 상태값을 읽어 적용하는 과정을 context switching이라고 한다. 다른 프로세스에게 CPU 자원을 할당해 작업을 수행하는 과정을 말한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;PCB(Process Control Block)란?&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로세스 제어 블록이란 특정한 프로세스에 대해&amp;nbsp; 관리할 필요가 있는 정보를 포함하고 있는 운영체제 커널의 자료구조이다. kernal space에 유지가 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;운영체제에서 프로세스 스케줄링 하기 위해 프로세스에 대한 정보를 가지고 있는 블럭이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉 운영체제가 프로세스를 표현한 것이라고 할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 프로세스가 생성될 때마다 고유의 PCB가 생성되고, 프로세스가 완료되면 PCB는 제거된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로세스가 context switching이 일어나 CPU의 자원을 다른 프로세스에게 넘겨주어야 할 때, 진행하던 작업을 저장하지 않으면 다음에 다시 CPU를 할당 받았을 때, 어디서부터 작업을 해야할지 모르게 된다. 이때 PCB에 저장해두면 정보를 읽어 계속 작업을 할 수 있게 되는 것이다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;385&quot; data-origin-height=&quot;676&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bqAilS/btrwezxGcwn/K1yVP2jmVbkOqRYKIDvq3K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bqAilS/btrwezxGcwn/K1yVP2jmVbkOqRYKIDvq3K/img.png&quot; data-alt=&quot;PCB의 구조&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bqAilS/btrwezxGcwn/K1yVP2jmVbkOqRYKIDvq3K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbqAilS%2FbtrwezxGcwn%2FK1yVP2jmVbkOqRYKIDvq3K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;244&quot; height=&quot;428&quot; data-origin-width=&quot;385&quot; data-origin-height=&quot;676&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;PCB의 구조&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Notes&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PCB 정보는 각 운영체제마다 다르다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PCB 접근 속도는 전반적인 system performance에 중요하다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;PCB의 정보들&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;PID(Process ID)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Process State(프로세스 상태) :&lt;/b&gt; 생성&lt;span style=&quot;background-color: #ffffff;&quot;&gt;(create),&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;준비&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;(ready),&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;실행&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;(running),&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;대기&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;(waiting),&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;완료&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;(terminated)&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;상태&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;b&gt;Program counter :&lt;/b&gt; 프로세스가 다음에 실행할 명형어의 주소를 가리킴&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;b&gt;CPU registers :&lt;/b&gt; contents of all process-centric registers&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;b&gt;Scheduling information :&lt;/b&gt; 프로세스 우선순위, 스케줄링 매개변수 등.&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;페이지 테이블: 프로세스의 페이지 정보를 저장하고 있는 테이블&lt;/li&gt;
&lt;li&gt;세그먼트 테이블:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;세그먼트: 프로그램과 그와 관련된 데이터들이 나누어지는 단위&lt;/li&gt;
&lt;li&gt;세그먼트 테이블은 이 세그먼트들의 번호, 시작 주소, 크기를 담는다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;b&gt;Memory management information :&lt;/b&gt; Base/limit registers, page tables, segment tables, etc.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;b&gt;Accounting information(프로세스 계정 정보) :&lt;/b&gt; CPU used, clock time elapsed since start, time limits, 소유자, 부모 등&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;b&gt;I/O status information :&lt;/b&gt; 프로세스에 할당된 I/O devices 정보, 열린 파일 목록 etc&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;b&gt;Context save area :&lt;/b&gt; 프로세스의 register context를 저장하는 장소&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;b&gt;Pointer :&lt;/b&gt; 부모 프로세스에 대한 포인터, 자식 프로세스에 대한 포인터, 프로세스가 위치한 메모리 주소에 대한 포인터, 할당된 자원에 대한 포인터 정보 등&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Context Switching은 언제 일어날까?&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;크게 3 케이스로 나뉜다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;멀티태스킹(Multi-Tasking)&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러 프로세스들이 운영체제의 스케줄러의 방식에 따라 번갈아 수행된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때 번갈아 프로세스가 CPU를 할당 받는데, 이를 Context Switching이라고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 이 속도가 무척 빠르기 때문에 사용자는 여러 프로세스가 동시에 처리되는것처럼 느껴진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;인터럽트 핸들링(interrupt handling)&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인터럽트는 시스템에 예외 상황이 발생했을때 CPU에게 알려 처리할 스 있도록 하는 것을 말한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 인터럽트가 발생하면 Context Switching이 일어난다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인터럽트(interrupt) 종류&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;I/O request : 입출력 요청&lt;/li&gt;
&lt;li&gt;Time Slice Expired : CPU 사용시간이 만료&lt;/li&gt;
&lt;li&gt;fork a child : 자식 프로세스 생성&lt;/li&gt;
&lt;li&gt;Wait for an interrupt : 인터럽트 처리 대기&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;사용자와 커널 모드 전환(User and Kernal mode switching)&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;운영체제에는 크게 user mode와 kernal 모드가 있다.&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;user mode : 사용자가 응용프로그램들을 사용하기 위해 접근하는 영역이다. 또한 사용자가 프로그램 내부에 자원들에 접근할 수 없도록 하는 모드이다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;kernal mode : system memory롸 모든 명령어들에 접근이 가능한 실행모드이다. CPU 스케줄링, 메모리 관리, I/O 관리, 파일 시스템 관리 등의 일을 맡고 있다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;user mode와 kernal mode간의 전환에서 context swtiching은 필수가 아니지만 운영체제에 따라 발생할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Context Switching 과정&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;KakaoTalk_20220317_151253012.jpg&quot; data-origin-width=&quot;1384&quot; data-origin-height=&quot;1270&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/V0xSb/btrv7QfVGFR/lrhRWUQzEIjWAiGDBCD2kK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/V0xSb/btrv7QfVGFR/lrhRWUQzEIjWAiGDBCD2kK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/V0xSb/btrv7QfVGFR/lrhRWUQzEIjWAiGDBCD2kK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FV0xSb%2Fbtrv7QfVGFR%2FlrhRWUQzEIjWAiGDBCD2kK%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;651&quot; height=&quot;597&quot; data-filename=&quot;KakaoTalk_20220317_151253012.jpg&quot; data-origin-width=&quot;1384&quot; data-origin-height=&quot;1270&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;요청 발생&lt;/b&gt; &lt;b&gt;:&lt;/b&gt; 인터럽트 또는 트랩에 의한 요청이 발생.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;PCB에 저장&lt;/b&gt; &lt;b&gt;:&lt;/b&gt; 운영체제가 현재 실행중인 프로세스의 정보를 PCB에 저장. Task의 대부분 정보는 Register에 저장되고 PCB로 관리된다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;CPU 할당&lt;/b&gt; &lt;b&gt;:&lt;/b&gt; 운영체제가 다음에 실행된 프로세스의 정보를 PCB에서 가져와 register에 적재하고 CPU 자원을 할당, 이전에 했던 작업을 이어서 진행&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Context Switching Cost&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Context Switching이 발생하게 되면 다음 프로세스를 위해 초기화 하는 등 여러 작업 때문에 큰 cost가 발생한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;cache 초기화&lt;/li&gt;
&lt;li&gt;Memory Mapping 초기화&lt;/li&gt;
&lt;li&gt;Kernel은 메모리 접근을 위해서 항상 실행되어야 함&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;context switching 때, 해당 CPU는 아무 작업을 하지 못하기 때문에&amp;nbsp; context switching 이 자주 일어나면 오버헤드가 많이 발생해서 오히려 효율과 성능이 떨어질 수 있다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Process vs Thread&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;thread는 stack을 제외한 모든 메모리를 공유하기 때문에 context switching이 발생하면 stack 영역만 변경해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 thread의 context switching 비용이 덜 든다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>운영체제</category>
      <category>context</category>
      <category>Context Switching</category>
      <category>Operating System</category>
      <category>OS</category>
      <category>os context switching</category>
      <category>Switching</category>
      <category>운영체제</category>
      <category>콘텍스트 스위칭</category>
      <author>JackCokebb</author>
      <guid isPermaLink="true">https://jackcokebb.tistory.com/14</guid>
      <comments>https://jackcokebb.tistory.com/14#entry14comment</comments>
      <pubDate>Thu, 17 Mar 2022 16:37:00 +0900</pubDate>
    </item>
  </channel>
</rss>