<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>All of the life</title>
    <link>https://mari-laveau.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Fri, 17 Jul 2026 10:24:51 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>쿨쿨.</managingEditor>
    <image>
      <title>All of the life</title>
      <url>https://tistory1.daumcdn.net/tistory/5318083/attach/93ff7e51fc3b464d9a00c0f0bfee9079</url>
      <link>https://mari-laveau.tistory.com</link>
    </image>
    <item>
      <title>[ByteByteGo] Database Indexing Strategies(데이터 베이스 인덱스 전략)</title>
      <link>https://mari-laveau.tistory.com/284</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;도입부&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;인덱스(index)&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;인덱스는 책 뒷면에 있는 색인과 마찬가지로 데이터 검색 작업의 속도를 높여주는 자료구조이다. 색인이 정보를 빠르게 찾을 수 있도록 키워드와 페이지 번호를 함께 나열하는 것처럼 데이터베이스 인덱스도 테이블의 모든 행을 스캔할 필요 없이 데이터 검색 속도를 높여주는 유사한 역할을 한다.&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-origin-width=&quot;1216&quot; data-origin-height=&quot;1644&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zHvCv/dJMcaic0FNs/uCc0SvunN4yNkYKzFvCB1K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zHvCv/dJMcaic0FNs/uCc0SvunN4yNkYKzFvCB1K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zHvCv/dJMcaic0FNs/uCc0SvunN4yNkYKzFvCB1K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzHvCv%2FdJMcaic0FNs%2FuCc0SvunN4yNkYKzFvCB1K%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;1216&quot; height=&quot;1644&quot; data-origin-width=&quot;1216&quot; data-origin-height=&quot;1644&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;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;데이터베이스 인덱스의 구조는 &lt;span style=&quot;color: #ee2323;&quot;&gt;정렬된 값의 리스트&lt;/span&gt;를 포함하며 각 값은 해당 값이 존재하는 &lt;span style=&quot;color: #009a87;&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;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;여기서 말하는 특정 테이블은 Index Segment라는 테이블로 저장이되며 인덱스로 지정된 컬럼 값 + 실제 데이터가 있는 주소&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;인덱스를 구현하기 위해 B-트리, 비트맵, 해시 맵과 같은 다양한 자료 구조를 사용할 수 있다 하지만 관계형 데이터베이스에서 인덱스는 B-트리의 변형인&amp;nbsp;B+트리 구조로 저장된다. 이러한 구조로 데이터베이스는 관련된 행을 효율적으로 찾을 수 있다.&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: 'Noto Sans Demilight', 'Noto Sans KR';&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;B-트리(B- Tree)&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;B-트리는 정렬된 데이터를 유지하고 효율적인 삽입, 삭제, 검색 작업을 가능하게 하는 자가 균형 트리 자료 구조로&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;모든 리프(leaf) 노드가 동일 레벨에 존재하며 이러한 요소가 트리를 균형 잡힌(balanced) 상태로 만들 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;모든 노드에는 키(key) + 해당 키에 대한 데이터 값(value)를 가지고 있다.&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: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;루트 노드를 제외한 모든 노드는 d(트리의 최소 차수)에서 2d 사이의 개수의 자식 노드를 가질 수 있으며 루트 노드는 최소 2개의 자식을 가진다.&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: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;자식이 k개인 비리프(non-leaf) 노드는 k-1개의 키를 포함한다&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;만약 [70, 80]의 키가 존재한다면 70보다 작은 값들은 왼쪽 자식 노드 70과 80사이의 값들은 중간 자식 노드 80보다 큰 값들은 오른쪽 자식 노드에 삽입할 수 있다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;B-트리는 디스크 액세스 횟수를 최소화하도록 설계되었기 때문에 메인 메모리에 수용할 수 없을 정도로 큰 데이터를 저장하는데 탁월한 자료 구조이다.&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;B트리는 여러개의 자식 노드(차수)를 가질 수 있기 때문에 트리의 높이를 적게 가져갈 수 있어 디스크 액세스를 낮출 수 있다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;또한 트리가 균형을 이루고 &lt;span style=&quot;color: #ee2323;&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;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1512&quot; data-origin-height=&quot;578&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/chHyHu/dJMcabx4WdU/YEr2yV6r35QKkqKaKIo0IK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/chHyHu/dJMcabx4WdU/YEr2yV6r35QKkqKaKIo0IK/img.png&quot; data-alt=&quot;B-Tree 기본 구조&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/chHyHu/dJMcabx4WdU/YEr2yV6r35QKkqKaKIo0IK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FchHyHu%2FdJMcabx4WdU%2FYEr2yV6r35QKkqKaKIo0IK%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;1512&quot; height=&quot;578&quot; data-origin-width=&quot;1512&quot; data-origin-height=&quot;578&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;B-Tree 기본 구조&lt;/figcaption&gt;
&lt;/figure&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;B+트리(B+tree)&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;B-트리의 변형으로 데이터 포인터(실제 레코드에 대한 포인터)는 오직 리프 노드에만 저장이되며 내부 노드는 오직 키와 다른 노드에 대한 포인터만 포함된다&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;모든 리프노드는 연결리스트로 함께 연결되어 있으며 이로 인해 범위 쿼리가 효율적이다&amp;nbsp;&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;B+트리에서 모든 키는 내부 노드에 한번, 리프 노드에 한번으로 총 두 번 나타나며 내부 노드의 키는 찾고자 하는 값이 어느 서브트리에 있을지 결정하는 기준점 역할을 한다.&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: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이러한 특징으로 B+트리는 메인 메모리에 다 담을 수 없을 정도로 방대한 양의 데이터를 가진 시스템에 잘 맞으며 데이터는 오직 리프 노드에서만 접근할 수 있기 때문에, 모든 조회의 경우 루트에서 리프까지의 경로 탐색을 거쳐야 하기에 모든 데이터 접근 작업은 일관된 시간이 소요된다.&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;B-Tree는 노드의 위치에 따라 엄청 빠르거나 엄청 느리거나 평균일 것이다 하지만 B+Tree는 데이터가 무조건 리프 노드에 위치해 있기에 동일한 시간이 걸린다.&lt;/span&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;1520&quot; data-origin-height=&quot;546&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dhfoHE/dJMcabSnLhr/1p1iq4dy72xf59jVL6HDXk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dhfoHE/dJMcabSnLhr/1p1iq4dy72xf59jVL6HDXk/img.png&quot; data-alt=&quot;B+Tree 기본 구조&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dhfoHE/dJMcabSnLhr/1p1iq4dy72xf59jVL6HDXk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdhfoHE%2FdJMcabSnLhr%2F1p1iq4dy72xf59jVL6HDXk%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;1520&quot; height=&quot;546&quot; data-origin-width=&quot;1520&quot; data-origin-height=&quot;546&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;B+Tree 기본 구조&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 14.6124%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;속성(Attribute)&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 37.7519%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;B-트리(B-Tree)&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 47.6356%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;B+트리(B+Tree)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 14.6124%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;구조&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 37.7519%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;리프 노드와 내부 노드 모두 키와 데이터를 저장한다.&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 47.6356%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;오직 리프 노드만 데이터, 데이터포인터를 저장하고 내부 노드는 키만 저장한다.&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 14.6124%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;데이터 접근성&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 37.7519%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;리프 노드와 내부 노드 모두에서 데이터에 직접 접근할 수 있다.&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 47.6356%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;데이터는 오직 리프 노드까지 탐색해 내려가야 접근이 가능하다.&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 14.6124%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;효율성&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 37.7519%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;데이터가 모든 노드에 분산되어 있어 범위 쿼리(Range Query)시 효율성이 떨어질 수 있다.&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 47.6356%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;모든 데이터가 리프 노드에 모여있고 리프 노드끼리 연결되어 있어 범위 쿼리에 훨씬 효율적이다.&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 14.6124%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;삽입 및 삭제&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 37.7519%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;데이터가 모든 노드에 분산되어 있어 작업이 다소 복잡할 수 있다.&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 47.6356%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;데이터가 리프 노드에만 존재하므로 잦은 재정렬 필요성이 줄어들어 약간 더 효율적이다.&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 14.6124%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;공간 활용도&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 37.7519%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;모든 노드가 데이터를 저장하므로 인덱스 공간 활용 효율이 떨어질 수 있다.&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 47.6356%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;데이터가 리프 노드에만 저장되므로 내부 노드의 공간 활용도가 더 높다.&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 14.6124%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;주요 용도&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 37.7519%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;데이터 검색이 주로 특정 키를 타깃으로 하는 데이터베이스 시스템에 유용하다.&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 47.6356%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;범위 쿼리가 더 빈번하게 발생하는 데이터베이스 및 파일 시스템에서 더 흔히 사용된다.&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;클러스터형 인덱스(Clustered Index)&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;클러스터형 인덱스는 테이블의 레코드가 물리적으로 저장되는 방식을 정렬하며 행을 무작위로 저장하거나 데이터가 삽입된 순서대로 두지 않는다.&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 style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;대신 인덱스 순서에 맞춰 행들을 물리적으로 모아서 정렬하며&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이 순서를 정하는 데 사용되는 특정 컬럼 또는 컬럼 집합을 클러스터형 키(clustered key)라고 부른다. 이러한 정렬 방식이 디스크 상에 데이터가 저장되는 실제 &lt;span style=&quot;color: #ee2323;&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;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;1550&quot; data-origin-height=&quot;568&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cdWKx2/dJMcaftJGMO/B0JQiVWoXjqXbYx9J5Cevk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cdWKx2/dJMcaftJGMO/B0JQiVWoXjqXbYx9J5Cevk/img.png&quot; data-alt=&quot;클러스터형 인덱스&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cdWKx2/dJMcaftJGMO/B0JQiVWoXjqXbYx9J5Cevk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcdWKx2%2FdJMcaftJGMO%2FB0JQiVWoXjqXbYx9J5Cevk%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;1550&quot; height=&quot;568&quot; data-origin-width=&quot;1550&quot; data-origin-height=&quot;568&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;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;예외로 PostgreSQL은 클러스터형 인덱스나 다른 인덱스를 기준으로 정렬되지 않고 기본적으로 삽입된 순서대로 저장된다. 다만 테이블의 물리적 데이터를 특정 인덱스와 일치하도록 재정렬하는 CLUSTER 명령어를 제공한다.&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: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;하지만 데이터가 삽입되거나 업데이트될 때 물리적 정렬이 자동으로 유지되지 않으며 CLUSTER 명령어를 주기적으로 실행해야 순서가 유지된다.&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;비클러스터형 인덱스(Non-clustered Index)&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이러한 분리 구조 때문에 비클러스터형 인덱스로 데이터에 접근할 때는 최소 두 번의 디스크 읽기 작업(인덱스 조회에 한 번, 실제 데이터 조회에 한번)이 필요하며 총 2번 조회를 한다.&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: 'Noto Sans Demilight', 'Noto Sans KR';&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;클러스터형 인덱스에 포함되지 않는 컬럼을 조건으로 사용하는 쿼리에 유용(클러스터형 키를 사용하는 쿼리는 굳이 비클러스터형 인덱스를 사용할 필요 x)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;넓은 범위의 데이터가 스캔할 필요가 없는 쿼리의 성능을 향상시킴(range 쿼리의 경우 여러번 참조해야함)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;단점&lt;/span&gt;&lt;br /&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;읽기 작업의 속도를 높이지만, 테이블의 데이터가 수정될 때마다 관련된 모든 인덱스를 함께 업데이트해야 하므로 쓰기 작업 속도를 떨어뜨릴 수 있다.&lt;/span&gt;&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;1642&quot; data-origin-height=&quot;1010&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cze0YA/dJMcacqjkHC/j3cuH2j0Ewe5ttFFjhIsDK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cze0YA/dJMcacqjkHC/j3cuH2j0Ewe5ttFFjhIsDK/img.png&quot; data-alt=&quot;비클러스터링 인덱스의 구조&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cze0YA/dJMcacqjkHC/j3cuH2j0Ewe5ttFFjhIsDK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcze0YA%2FdJMcacqjkHC%2Fj3cuH2j0Ewe5ttFFjhIsDK%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;1642&quot; height=&quot;1010&quot; data-origin-width=&quot;1642&quot; data-origin-height=&quot;1010&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;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;여러가지 인덱스 유형&lt;/span&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;기본 인덱스(Primary Index)&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;데이터베이스 기본 인덱스는 대부분 데이터에 접근하는 수단으로 테이블을 생성할때 기본 키(Primary Key)는 흔히 클러스터형 인덱스의 역할도 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;덕분에 &lt;span style=&quot;color: #ee2323;&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;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;But 키가 순차적이지 않다면(무작위 값등) 정렬 순서를 유지하기위해 페이지 병합, 분할등 작업을 하기에 재정렬 작업을 할 수 있으며 이러한 이유로 쓰기 효율성을 저하시킨다.&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-origin-width=&quot;1466&quot; data-origin-height=&quot;1236&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bg4193/dJMcacRhdR1/ar8xa7Sj48nYu85Hg9Scr0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bg4193/dJMcacRhdR1/ar8xa7Sj48nYu85Hg9Scr0/img.png&quot; data-alt=&quot;기본 인덱스 구조&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bg4193/dJMcacRhdR1/ar8xa7Sj48nYu85Hg9Scr0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbg4193%2FdJMcacRhdR1%2Far8xa7Sj48nYu85Hg9Scr0%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;1466&quot; height=&quot;1236&quot; data-origin-width=&quot;1466&quot; data-origin-height=&quot;1236&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;보조 인덱스(Secondary Index)&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;데이터가 새로 쓰이거나 갱신되는 경우 해당 데이터를 바라보는 모든 인덱스 구조를 함께 갱신하기 때문&lt;/span&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;1556&quot; data-origin-height=&quot;938&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/793S6/dJMcabZfgIm/39KJJ63aXxFlzJ4g939wkk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/793S6/dJMcabZfgIm/39KJJ63aXxFlzJ4g939wkk/img.png&quot; data-alt=&quot;보조 인덱스 구조&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/793S6/dJMcabZfgIm/39KJJ63aXxFlzJ4g939wkk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F793S6%2FdJMcabZfgIm%2F39KJJ63aXxFlzJ4g939wkk%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;1556&quot; height=&quot;938&quot; data-origin-width=&quot;1556&quot; data-origin-height=&quot;938&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;복합 인덱스(Composite Index)&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;예를 들어 where 조건문으로 이름과 나이를 사용한 검색 쿼리를 자주 실행한다고 했을때 이름과 나이에 각각 별도의 인덱스를 2개를 만드는 것보다 두 컬럼을 하나로 묶은 단일 복합 인덱스를 만드는 것이 더 좋다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;But 많은 컬럼을 묶을수록 복합 인덱스의 크기가 비대해져 더 많은 저장 공간을 차지하게 된다.&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-origin-width=&quot;1536&quot; data-origin-height=&quot;944&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oFA2t/dJMcabLJ8Js/PThH6aQKQwdTzfivgk39Sk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oFA2t/dJMcabLJ8Js/PThH6aQKQwdTzfivgk39Sk/img.png&quot; data-alt=&quot;복합 키 인덱스 구조&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oFA2t/dJMcabLJ8Js/PThH6aQKQwdTzfivgk39Sk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoFA2t%2FdJMcabLJ8Js%2FPThH6aQKQwdTzfivgk39Sk%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;1536&quot; height=&quot;944&quot; data-origin-width=&quot;1536&quot; data-origin-height=&quot;944&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;커버링 인덱스(Covering Index)&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;테이블 접근 단계를 생략하고 인덱스만으로 쿼리를 조회할 수 있으므로 디스크I/O 작업이 줄어들어 특정 쿼리의 속도가 향상된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1528&quot; data-origin-height=&quot;804&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/meCyV/dJMcaglRE2r/Bud1gWTROP6SdsbrPkJmq0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/meCyV/dJMcaglRE2r/Bud1gWTROP6SdsbrPkJmq0/img.png&quot; data-alt=&quot;커버링 인덱스 구조&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/meCyV/dJMcaglRE2r/Bud1gWTROP6SdsbrPkJmq0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmeCyV%2FdJMcaglRE2r%2FBud1gWTROP6SdsbrPkJmq0%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;1528&quot; height=&quot;804&quot; data-origin-width=&quot;1528&quot; data-origin-height=&quot;804&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;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;유니크 인덱스(Unique Index)&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;유니크 인덱스는 인덱스로 지정된 키 값들이 데이터베이스 내에서 유일함을 보장한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1476&quot; data-origin-height=&quot;788&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bzNmzw/dJMcaastSjy/YL0TeGXK7BJXZukdqYpJxK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bzNmzw/dJMcaastSjy/YL0TeGXK7BJXZukdqYpJxK/img.png&quot; data-alt=&quot;이메일 컬럼에 유니크 인덱스를 설정했을때 중복 데이터를 삽입을 하려는 경우 실패한다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bzNmzw/dJMcaastSjy/YL0TeGXK7BJXZukdqYpJxK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbzNmzw%2FdJMcaastSjy%2FYL0TeGXK7BJXZukdqYpJxK%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;1476&quot; height=&quot;788&quot; data-origin-width=&quot;1476&quot; data-origin-height=&quot;788&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;필터링 인덱스(Filtered Index)&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;예시로 회원 테이블의 데이터가 1000개가 있고 950개가 탈퇴한 회원이고 나머지 50개가 실제 사용하는 유저라고 가정했을때 회원테이블에 접근하기 위해서 인덱스를 생성한다고 가정했을때 &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;기본키로 인덱스를 잡으면 실제 사용하는 사람이 50명밖에 안되지만 나머지 950명에 대해서 인덱스 정보가 낭비가 되는 꼴이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;따라서 status = &quot;Active&quot;로 인덱스를 설정해서 활성화된 사용자들만 빠르게 찾을 수 있도록 설정할 수 있다.&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: 'Noto Sans Demilight', 'Noto Sans KR';&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;필터링 인덱스는 관계형 데이터베이스 중 MicrosoftSQL, PostgreSQL은 필터링된 인덱스를 지원하지만 MySQL은 지원하지 않는다.&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-origin-width=&quot;1470&quot; data-origin-height=&quot;912&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b0IAr2/dJMcac4Ql0c/DQYGKnsKL2T2fdTlblKuKk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b0IAr2/dJMcac4Ql0c/DQYGKnsKL2T2fdTlblKuKk/img.png&quot; data-alt=&quot;Country 컬럼이 대부분 US 값으로 구성되어 있는경우 필터링 인덱스를 Country = &amp;quot;US&amp;quot;로 설정할 수 있다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b0IAr2/dJMcac4Ql0c/DQYGKnsKL2T2fdTlblKuKk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb0IAr2%2FdJMcac4Ql0c%2FDQYGKnsKL2T2fdTlblKuKk%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;1470&quot; height=&quot;912&quot; data-origin-width=&quot;1470&quot; data-origin-height=&quot;912&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Country 컬럼이 대부분 US 값으로 구성되어 있는경우 필터링 인덱스를 Country = &quot;US&quot;로 설정할 수 있다.&lt;/figcaption&gt;
&lt;/figure&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;특수 인덱스(Specialized Indexes)&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;모든 DBMS에서 다 지원하지 않지만 알맞은 상황을 만나면 좋은 효율을 발휘할 수 있으며 대부분 일반적인 B+tree 인덱스를 사용하지 않는다.&lt;/span&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;비트맵 인덱스(Bitmap Index)&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;비트맵 인덱스는 0과 1로 이루어진 비트 배열(비트맵)을 사용하는 특수한 데이터베이스 인덱스이다.&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 style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;성별, 예/아니요 처럼 Enum이나 플래그 컬럼이 좋은 대상이다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;비트맵 인덱스에서는 컬럼의 고유 값마다 각각 하나의 비트맵이 할당되며 비트맵 내부의 비트 개수는 테이블의 총 행(row)수와 같다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;해당 행의 컬럼 값이 일치하면 비트를 1로, 일치하지 않으면 0으로 세팅하는 방식이다&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: 'Noto Sans Demilight', 'Noto Sans KR';&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;BUT 읽기 작업은 매우 빠르지만 쓰기(업데이트) 작업 시에는 비트맵 내부의 비트들을 일일히 찾아서 뒤집어야 하기에 성능이 떨어질 수 있다.&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: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;따라서 데이터 변화가 거의 없는 정적인 테이블이나 읽기 전용인 데이터 웨어하우스(DW) 환경에 적합하다.&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-origin-width=&quot;1472&quot; data-origin-height=&quot;768&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/O40J1/dJMcagsEFSZ/DBiG72KKkojFndFjp2RT6K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/O40J1/dJMcagsEFSZ/DBiG72KKkojFndFjp2RT6K/img.png&quot; data-alt=&quot;비트맵 인덱스를 사용하여 읽기 최적화&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/O40J1/dJMcagsEFSZ/DBiG72KKkojFndFjp2RT6K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FO40J1%2FdJMcagsEFSZ%2FDBiG72KKkojFndFjp2RT6K%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;1472&quot; height=&quot;768&quot; data-origin-width=&quot;1472&quot; data-origin-height=&quot;768&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;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;대표적으로 Oracle, IBM Db2, SQL Server 등이 비트맵 인덱스를 지원하는 시스템이며 MySQL과 PostgreSQL은 비트맵 인덱스를 지원하지 않는다.&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;공간 인덱스(Spatial Index)&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;공간 인덱스는 지리적 좌표, 다각형(폴리곤), 3차원 입체와 같은 다차원 객체 데이터를 인덱싱하기 위해 만들어진 특수 인덱스로 해당 인덱스는 가장 가까운 이웃 위치 찾기, 반경 내 지역 검색 같은 공간 쿼리의 속도를 내기 위해 고안되었다.&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: 'Noto Sans Demilight', 'Noto Sans KR';&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;B-tree 같은 기존 인덱스 방식은 일차원적인 선형 데이터(숫자, 문자열 등)을 다루도록 설계되었기에 면적과 다차원을 다루는 공간 데이터 처리에는 한계가 있다.&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: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이러한 한계를 극복하기 위해 공간 데이터를 효율적으로 저장하고 찾기 위해 최적화된 R-tree나 쿼드트리 등의 알고리즘을 사용한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;R-tree&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;R-tree의 R은 Rectangle로 최소 경계 사각형(Minimum Bounding Rectangle)로 공간을 분리한다.&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: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;모든 노드는 자식 노드들에 포함된 모든 공간 객체를 감싸는 MBR로 MBR끼리 겹칠 수도 있고 부모 MBR은 자식 MBR을 포함하는 트리 구조로 이룬다.&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-origin-width=&quot;600&quot; data-origin-height=&quot;514&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cfkYl8/dJMcabkD5di/fa9GQtbkFoXUkg2sBJeffK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cfkYl8/dJMcabkD5di/fa9GQtbkFoXUkg2sBJeffK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cfkYl8/dJMcabkD5di/fa9GQtbkFoXUkg2sBJeffK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcfkYl8%2FdJMcabkD5di%2Ffa9GQtbkFoXUkg2sBJeffK%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;600&quot; height=&quot;514&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;514&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;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;위치 검색 쿼리가 들어오면 R-트리는 검색 영역과 전혀 교차하지 않는 바운딩 박스들을 단번에 걸러내어 불필요한 많은 행들을 탐색 대상에서 제외한다.&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: 'Noto Sans Demilight', 'Noto Sans KR';&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;예시로 특정 좌표 중심의 반경 Nkm 이내 맛집 찾기, 현재 위치에서 가장 가까운 지하철역 조회 기능이 핵심인 지도 앱 데이터베이스에서 R-트리 인덱스는 효과적으로 기능을 사용할 수 있다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;또한 우리가 하려는 택시 동승 프로젝트에서도 사용자 기반의 위치(출발점)과 도착점을 기준으로 0 ~ 200m 반경의 클러스터를 생성하여 출발점과 도착점 클러스터와 겹치는 승객이 있을경우 자동으로 매칭을 해서 위치를 기준으로 중간지점을 산출하여 동승할 수 있도록 서비스를 구성하면 어떨까 생각했다.&lt;/span&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;2372&quot; data-origin-height=&quot;1508&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cjj6rb/dJMcacKDwnj/9zqnnRhnecNnJLtus6kMKk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cjj6rb/dJMcacKDwnj/9zqnnRhnecNnJLtus6kMKk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cjj6rb/dJMcacKDwnj/9zqnnRhnecNnJLtus6kMKk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcjj6rb%2FdJMcacKDwnj%2F9zqnnRhnecNnJLtus6kMKk%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;2372&quot; height=&quot;1508&quot; data-origin-width=&quot;2372&quot; data-origin-height=&quot;1508&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;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;공간 인덱스는 많은 관계형 데이터베이스에서 지원하며 MySQL, PostgreSQL(PostGIS 사용), Oracle, SQL Server 등 모두 공간 인덱싱 기능을 지원한다.&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-origin-width=&quot;1232&quot; data-origin-height=&quot;482&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/91rwK/dJMcaaeW7qc/eIV9RUcNc9rNKgu3TykKAk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/91rwK/dJMcaaeW7qc/eIV9RUcNc9rNKgu3TykKAk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/91rwK/dJMcaaeW7qc/eIV9RUcNc9rNKgu3TykKAk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F91rwK%2FdJMcaaeW7qc%2FeIV9RUcNc9rNKgu3TykKAk%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;1232&quot; height=&quot;482&quot; data-origin-width=&quot;1232&quot; data-origin-height=&quot;482&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;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;전체 텍스트 인덱스(full-text Index)&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;텍스트의 중간 단어 검색이나 부분일치 검색을 시도할 때 B-트리 인덱스는 정확히 일치하거나 범위 정렬된 구조에만 맞춰져 있기에 제 성능을 못낸다.&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;뉴스 기사, 도서 본문, 수많은 단어가 뒤섞인 긴 장문의 자유 형식 텍스트 뭉치에서 원하는 단어를 찾을 때 빠르게 찾을 수 있다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;또한 우리 프로젝트에서도 지도에서 사용자가 도착지 검색을 하는 경우 작성한 글자에 따라서 일치하는 장소를 드랍다운 할 수 있도록 적용할 수 있을것 같다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;전체 텍스트 인덱스는 컬럼 내 텍스트를 형태소나 단위별 단어(토큰)으로 잘개 쪼갠 후 이 토큰들을 기반으로 인덱스를 새로 빌드한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;전체 텍스트 인덱스 구현에서 가장 흔히 쓰이는 기술이 역인덱스 구조이며&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 style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;역 인덱스는 단어나 숫자 같은 실제 contents를 키로 삼아, 그것이 포함된 문서 번호와 위치 목록을 거꾸로 찾아 들어가는 구조를 가진 자료구조이다.&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: 'Noto Sans Demilight', 'Noto Sans KR';&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;MySQL, PostgreSQL, SQL Server 같은 전통적인 관계형 데이터베이스 계열에서도 지원된다.&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: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;하지만 데이터가 커지고 검색이 주요 기능이라고 한다면 DB에는 저장, 삭제, 갱신만을 사용하고 조회할때만 ElasticSearch를 사용해서 오버헤드를 빠르게 접근할 수 있다.&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: 'Noto Sans Demilight', 'Noto Sans KR';&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;ElasticSearch&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;ElasticSearch는 강력한 텍스트 검색 라이브러리인 Apache Lucene를 뼈대로 삼으며, 실시간 애플리케이션의 대규모 확장이 가능하도록 분산 시스템 기능을 얹어 성능을 극대화한 제품이다.&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;해시 인덱스(Hash Index)&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;탐색시 데이터베이스가 검색 키의 해시 값을 계산하여 레코드 위치로 단번에 접근하므로, 순차 스캔이나 B-트리의 노드 경로를 타고 내려가는 복잡한 과정 없이 즉각적인 조회가 가능하여 O(log N)에서 O(1)로 조회할 수 있다.&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 style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;하지만 해시 인덱스는 내부 데이터를 정렬된 순서로 보관하지 않기에 키의 대소 관계나 위치에 의존하는 부등호(&amp;lt;, &amp;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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;PostgreSQL은 해시 인덱스를 정식한다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>Review</category>
      <category>데이터베이스 인덱스 전략</category>
      <author>쿨쿨.</author>
      <guid isPermaLink="true">https://mari-laveau.tistory.com/284</guid>
      <comments>https://mari-laveau.tistory.com/284#entry284comment</comments>
      <pubDate>Sun, 12 Jul 2026 21:22:22 +0900</pubDate>
    </item>
    <item>
      <title>Ject 2차 회고록</title>
      <link>https://mari-laveau.tistory.com/283</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;ject_logo_white.png&quot; data-origin-width=&quot;701&quot; data-origin-height=&quot;160&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/QPaj8/dJMcac4BPzo/512OHxRJYOSIVyHEf2X3oK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/QPaj8/dJMcac4BPzo/512OHxRJYOSIVyHEf2X3oK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/QPaj8/dJMcac4BPzo/512OHxRJYOSIVyHEf2X3oK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQPaj8%2FdJMcac4BPzo%2F512OHxRJYOSIVyHEf2X3oK%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;701&quot; height=&quot;160&quot; data-filename=&quot;ject_logo_white.png&quot; data-origin-width=&quot;701&quot; data-origin-height=&quot;160&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;이 활동은 젝트에서 진행한 프로젝트입니다.&lt;/b&gt;&lt;br /&gt;젝트 공식 홈페이지   &lt;a href=&quot;https://ject.kr&quot;&gt;https://ject.kr&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-sourcepos=&quot;3:1-3:8;36-43&quot; data-ke-size=&quot;size26&quot;&gt;들어가며&lt;/h2&gt;
&lt;p data-sourcepos=&quot;5:1-5:32;45-76&quot; data-ke-size=&quot;size16&quot;&gt;솔직히 말하면, 이번 회고가 1차보다 쓰기 훨씬 어렵다.&lt;/p&gt;
&lt;p data-sourcepos=&quot;7:1-10:19;78-253&quot; data-ke-size=&quot;size16&quot;&gt;1차 회고 말미에 &quot;데모데이까지 남은 기간엔 더 욕심을 내보려 한다&quot;고 썼다.&lt;br /&gt;그런데 그 약속을 제대로 지키지 못했다. 소프트웨어 마에스트로(소마) 일정이 본격화되면서,&lt;br /&gt;젝트에 쓸 수 있는 시간이 눈에 띄게 줄었다. 데모데이 같은 핵심 행사에도 온전히 함께하지 못했다.&lt;br /&gt;팀원들한테 많이 미안한 2차였다.&lt;/p&gt;
&lt;p data-sourcepos=&quot;12:1-12:58;255-312&quot; data-ke-size=&quot;size16&quot;&gt;그래도 회고는 해야 한다. 작게나마 만든 것들, 그리고 그 안에서 배운 것들을 담담하게 적어보려 한다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-sourcepos=&quot;16:1-16:13;319-331&quot; data-ke-size=&quot;size26&quot;&gt;이번에 만든 것들&lt;/h2&gt;
&lt;h3 data-sourcepos=&quot;18:1-18:33;333-365&quot; data-ke-size=&quot;size23&quot;&gt;필터를 더 단단하게 &amp;mdash; 대소문자를 모르는 욕설 탐지&lt;/h3&gt;
&lt;p data-sourcepos=&quot;20:1-21:72;367-478&quot; data-ke-size=&quot;size16&quot;&gt;1차에서 KMP 알고리즘으로 욕설 필터를 구현하고 나름 뿌듯해했다.&lt;br /&gt;그런데 얼마 지나지 않아 허점이 보였다. &quot;shit&quot; 은 걸러내지만 &quot;Shit&quot; 이나 &quot;SHIT&quot; 은 그냥 통과했다.&lt;/p&gt;
&lt;p data-sourcepos=&quot;23:1-23:15;480-494&quot; data-ke-size=&quot;size16&quot;&gt;수정 자체는 한 줄이었다.&lt;/p&gt;
&lt;div data-sourcepos=&quot;25:1-31:4;496-622&quot;&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;java&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;reasonml&quot; style=&quot;color: #14181f;&quot;&gt;&lt;code&gt;// Before
char[] text = input.toCharArray();

// After
char[] text = input.toLowerCase(Locale.ROOT).toCharArray();&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-sourcepos=&quot;33:1-36:59;624-815&quot; data-ke-size=&quot;size16&quot;&gt;KMP에 넘기기 전에 입력을 소문자로 정규화한 것이다.&lt;br /&gt;Locale.ROOT를 선택한 건 이유가 있었다. 터키어 같은 일부 언어에서는 'i' &amp;rarr; 'İ' 처럼&lt;br /&gt;일반적인 대소문자 변환 규칙과 다르게 동작하는 케이스가 있다.&lt;br /&gt;특정 로케일 환경에서 필터가 예상 밖으로 흔들리는 걸 막으려면 로케일에 독립적인 ROOT가 안전하다.&lt;/p&gt;
&lt;p data-sourcepos=&quot;38:1-40:44;817-967&quot; data-ke-size=&quot;size16&quot;&gt;한 줄짜리 수정이었지만, 알고리즘을 맞게 짜는 것과 현실의 입력을 안전하게 처리하는 건&lt;br /&gt;별개의 문제라는 걸 다시 한번 확인했다. 1차에서 KMP를 직접 구현한 게 &quot;알고리즘&quot;이었다면,&lt;br /&gt;이번엔 그 알고리즘이 실제로 믿을 수 있으려면 무엇이 필요한지를 배운 셈이다.&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-sourcepos=&quot;44:1-44:29;974-1002&quot; data-ke-size=&quot;size23&quot;&gt;닉네임 데이터셋 리뉴얼 &amp;mdash; 코드 바깥의 고민&lt;/h3&gt;
&lt;p data-sourcepos=&quot;46:1-47:61;1004-1106&quot; data-ke-size=&quot;size16&quot;&gt;1차에서 만든 닉네임 추천 시스템은 &lt;b&gt;형용사 + 명사&lt;/b&gt; 조합이었다.&lt;br /&gt;직접 써보니 &quot;효율적인회의&quot;, &quot;유연한책상&quot; 같은 닉네임들이 나왔다. 말은 되지만 서비스와 어울리지 않았다.&lt;/p&gt;
&lt;p data-sourcepos=&quot;49:1-49:11;1108-1118&quot; data-ke-size=&quot;size16&quot;&gt;두 가지를 바꿨다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-sourcepos=&quot;51:1-52:51;1120-1221&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-sourcepos=&quot;51:1-51:51;1120-1170&quot;&gt;&lt;b&gt;형용사 셋&lt;/b&gt;: 중립적인 단어들을 걷어내고, 밝고 긍정적인 느낌의 단어들만 추렸다.&lt;/li&gt;
&lt;li data-sourcepos=&quot;52:1-52:51;1171-1221&quot;&gt;&lt;b&gt;명사 셋&lt;/b&gt;: 일반 명사 대신 친숙하고 귀여운 동물 이름(2자)으로 전부 교체했다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-sourcepos=&quot;54:1-57:44;1223-1399&quot; data-ke-size=&quot;size16&quot;&gt;커밋 기록을 보면 데이터를 다듬는 커밋이 기능 코드보다 많다.&lt;br /&gt;&quot;이 단어는 너무 딱딱하다&quot;, &quot;동물 종류도 차가운 느낌을 주는 &quot;를 하나씩 걸러내면서,&lt;br /&gt;코드 바깥의 &lt;b&gt;감각적인 판단&lt;/b&gt;이 결과물에 얼마나 영향을 주는지 실감했다.&lt;br /&gt;처음엔 &quot;데이터셋이야 그냥 채우면 되지&quot;라고 생각했는데, 전혀 그렇지 않았다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-sourcepos=&quot;61:1-61:11;1406-1416&quot; data-ke-size=&quot;size26&quot;&gt;부족했던 것들&lt;/h2&gt;
&lt;p data-sourcepos=&quot;63:1-63:28;1418-1445&quot; data-ke-size=&quot;size16&quot;&gt;기여 자체가 적었다. 이건 돌려서 쓸 말이 없다.&lt;/p&gt;
&lt;p data-sourcepos=&quot;65:1-67:27;1447-1581&quot; data-ke-size=&quot;size16&quot;&gt;소마 일정이 겹치면서 젝트에 온전히 몰입하지 못했고, 팀원들이 데모데이를 준비하고 마무리하는 동안&lt;br /&gt;내가 함께 있지 못한 순간들이 생겼다. 두 가지를 동시에 잘 하고 싶었지만, 결과적으로&lt;br /&gt;어느 한쪽에도 온전히 집중하지 못한 기간이었다.&lt;/p&gt;
&lt;p data-sourcepos=&quot;69:1-71:72;1583-1746&quot; data-ke-size=&quot;size16&quot;&gt;1차에서 &quot;시간에 쫓기다 보니 테스트 코드를 제대로 작성하지 못했다&quot;고 썼는데,&lt;br /&gt;2차엔 그보다 더 근본적인 문제가 있었다. 시간 배분 자체가 무너진 것이다.&lt;br /&gt;다음에 비슷한 상황이 생긴다면, 처음부터 한쪽에 집중하거나 아니면 각각의 기대치를 팀원들과 미리 맞추는 게 낫겠다는 걸 배웠다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-sourcepos=&quot;75:1-75:7;1753-1759&quot; data-ke-size=&quot;size26&quot;&gt;마치며&lt;/h2&gt;
&lt;p data-sourcepos=&quot;77:1-77:43;1761-1803&quot; data-ke-size=&quot;size16&quot;&gt;숫자로 보면 2차 기간의 기여는 초라하다. 그걸 부풀려서 쓰고 싶지 않았다.&lt;/p&gt;
&lt;p data-sourcepos=&quot;79:1-81:33;1805-1921&quot; data-ke-size=&quot;size16&quot;&gt;다만 적게 만든 것들 안에서도 배움은 있었다.&lt;br /&gt;한 줄의 정규화가 알고리즘의 허점을 막고, 데이터 한 줄의 뉘앙스가 사용자 경험을 바꾼다는 것.&lt;br /&gt;그리고 개발자가 '코드 바깥'의 감각도 길러야 한다는 것.&lt;/p&gt;
&lt;p data-sourcepos=&quot;83:1-83:55;1923-1977&quot; data-ke-size=&quot;size16&quot;&gt;팀원들한테는 미안함이 크다. 그 미안함을 소마에서의 성장으로 갚는 수밖에 없겠다고 생각하고 있다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;이 활동은 젝트에서 진행한 프로젝트입니다.&lt;/b&gt;&lt;br /&gt;젝트 공식 홈페이지   &lt;a href=&quot;https://ject.kr&quot;&gt;https://ject.kr&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;</description>
      <category>Review</category>
      <author>쿨쿨.</author>
      <guid isPermaLink="true">https://mari-laveau.tistory.com/283</guid>
      <comments>https://mari-laveau.tistory.com/283#entry283comment</comments>
      <pubDate>Thu, 9 Jul 2026 18:04:02 +0900</pubDate>
    </item>
    <item>
      <title>[Real MySQL 8.0] 4장 리뷰</title>
      <link>https://mari-laveau.tistory.com/282</link>
      <description>&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;449&quot; data-origin-height=&quot;445&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b5sSzf/dJMcahryFjn/kQulpNb5eckVKaHNHsRyYk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b5sSzf/dJMcahryFjn/kQulpNb5eckVKaHNHsRyYk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b5sSzf/dJMcahryFjn/kQulpNb5eckVKaHNHsRyYk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb5sSzf%2FdJMcahryFjn%2FkQulpNb5eckVKaHNHsRyYk%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;449&quot; height=&quot;445&quot; data-origin-width=&quot;449&quot; data-origin-height=&quot;445&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;MySQL 서버는 크게 MySQL 엔진과 스토리지 엔진으로 구분할 수 있다.&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;MySQL 엔진&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;커넥션 핸들러&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;SQL 파서, 전처리기&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;옵티마이저&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;쿼리 실행기&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;요청된 SQL 문장을 분석하거나 최적화 하는 등 DBMS의 뇌에 해당하는 처리를 수행한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;대표적인 예시로 InnoDB, MyISAM이 있다.&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;핸들러 요청 : MySQL 엔진의 쿼리 실행기에서 데이터를 쓰거나 읽어야할 때 스토리지 엔진에 쓰기 또는 읽기를 요청하는것이다.&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Foreground thread, Background thread&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;MySQL 서버는 프로세스 기반이 아닌 스레드 기반으로 작동하며 포그라운드 스레드와 백그라운드 스레드로 구분한다.&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Foreground thread&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;MySQL 서버에 접속된 클라이언트 수만큼 존재하며 주로 각 클라이언트 사용자가 요청하는 쿼리 문장을 처리한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;스레드 캐시에 존재할 수 있는 최대 스레드 개수는 thread_cache_size로 할당할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;대부분 읽기 작업(Select)에서 포그라운드 스레드가 사용이된다.&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Background thread&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;대표적으로 스토리지 엔진을 사용하는 InnoDB의 경우 5가지 사항이 백그라운드로 처리된다.&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;인서트 버퍼를 병합하는 스레드&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;로그를 디스크로 기록하는 스레드&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;InnoDB 버퍼 풀의 데이터를 디스크에 기록하는 스레드&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;데이터를 버퍼로 읽어 오는 스레드&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;잠금이나 데드락을 모니터링하는 스레드&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;데이터를 쓰는 작업(Update, Insert)에서 대부분 백그라운드 스레드가 사용된다.&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;메모리 영역&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;MySQL에서 사용하는 메모리 공간은 크게 글로벌 메모리 영역, 로컬 메모리 영역으로 나누어 진다.&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;MySQL서버가 시작되면서 운영체제로부터 할당되며 종료될때 해제된다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;클라이언트 스레드의 수와 무관하게 하나의 메모리 공간만 할당된다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;MySQL 서버 내부의 모든 스레드가 공유한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;ex) InnoDB 버퍼 풀, 테이블 캐시, 로그 버퍼 등&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;MySQL 서버상에 존재하는 클라이언트 스레드가 쿼리를 처리하는데 사용된다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;각 클라이언트 스레드가 독립적으로 할당되며 공유하지 않는다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;클라이언트 스레드가 쿼리를 실행할때 필요에 따라 할당이 된다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;ex) 정렬 버퍼, 조인 버퍼, 바이너리 로그 캐시 등&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;플러그인, 컴포넌트&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;기존 MySQL은 플러그인 방식을 사용하였다. 하지만 8.0버전부터 플러그인 단점으로 인해 컴포넌트 방식을 사용하게 된다.&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: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;플러그인의 단점으로는 오직 MySQL 엔진과 직접 연결할 수 밖에 없고 플러그인끼리는 통신이 불가하였다. 따라서 2개의 플러그인을 동시에 같이 사용하려고 해도 통신이 안되 직접 엔진 소스 코드를 수정할 수 밖에 없었다.&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: 'Noto Sans Demilight', 'Noto Sans KR';&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;쿼리 실행 구조&lt;/span&gt;&lt;/h3&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;999&quot; data-origin-height=&quot;710&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/EN6cW/dJMcaf8fmua/hvxmVJSxJjM89vWhYcKxk0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/EN6cW/dJMcaf8fmua/hvxmVJSxJjM89vWhYcKxk0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/EN6cW/dJMcaf8fmua/hvxmVJSxJjM89vWhYcKxk0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEN6cW%2FdJMcaf8fmua%2FhvxmVJSxJjM89vWhYcKxk0%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;999&quot; height=&quot;710&quot; data-origin-width=&quot;999&quot; data-origin-height=&quot;710&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;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;MySQL은 위 사진과 같이 쿼리를 실행할때 해당 구조로 동작한다.&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;쿼리 파서&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;전처리기&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;옵티마이저&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;실행 엔진&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;핸들러(InnoDB 스토리지 엔진, MyISAM)에 명령을 내리고 그에 대한 결과를 받아서 조합하는 역할을 한다. -&amp;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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;핸들러(스토리지 엔진)&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;MySQL 실헹 엔진의 요청에 따라 데이터를 디스크로 저장하고 읽어오는 역할을 담당한다. 즉 핸들러는 스토리지 엔진이며 사용하는 엔진에 따라 핸들러도 달라진다.&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;쿼리 캐시&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;SQL의 실행 결과를 메모리에 캐시하고 동일 SQL 쿼리가 실행되면 테이블을 읽지 않고 즉시 결과를 반환하기에 매우 좋은 성능을 가진다 하지만 테이블의 데이터가 변경, 삭제되는 경우 그에 대한 캐시값도 삭제되어야 하며 이는 심각한 동시 처리 성능 저하를 유발한다. 이후&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;8.0으로 올라오며 기능이 완전히 삭제되었다.&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;스레드 풀&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;기존 OS 관점에서 보면 사용자가 요청을 날리면 서버는 새로운 스레드를 생성하고 결과를 반환하고 요청이 없으면 스레드를 삭제한다 이때 OS는 스레드를 생성하고 삭제하는 비용이 엄청나게 커진다 따라서 스레드 풀을 도입하여 미리 생성한 풀에 사용자의 요청에 응답한 후 스레드를 제거하지 않고 풀에 계속 대기하는 방식이다.&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: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;그렇다고 스레드 풀이 많으면 좋은가? 그건 아니다 왜냐하면 스레드도 마찬가지로 컨텍스트 스위칭(cpu가 스레드를 점유하는데 하나씩 점유)이 자주 발생하면 스레드 전환하는데만 오랜 시간을 쏟는다.&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: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Percona Server의 스레드 풀 기능은 선순위 후순위 큐를 사용하여 쿼리를 우선적으로 처리할 수 있는 기능을 제공한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;-&amp;gt; 트랜잭션내에 속한 SQL을 빨리 처라히면 트랜잭션 잠금이 빨리 해제되고 경합을 낮춰 전체적인 처리 성능이 높아진다.&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: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;InnoDB는 유일하게 레코드 기반의 잠금을 제공하며 그 때문에 높은 동시성 처리가 가능하다.&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Primary Key에 의한 클러스터링&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;InnoDB의 모든 테이블은 프라이머리키를 기준으로 클러스터링되어 저장된다. 즉 pk 값 순서대로 디스크에 저장된다. 모든 세컨더리 인덱스는 레코드 주소 대신 pk의 값을 논리적 주소로 사용한다.&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: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;BUT&lt;/span&gt; MyISAM 스토리지 엔진에서는 클러스터링 키를 지원하지 않는다.&lt;span style=&quot;color: #000000;&quot;&gt; MyISAM 테이블의 PK키를 포함한 모든 인덱스는 물리적 레코드 주소 값(rowID)를 가진다. 또한 외래키는 서버 운영에 불편함이 있어서 사용되지 않는다.&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;외래키는 innoDB에서 지원하는 기능으로 MyISAM memory 테이블에서는 사용하지 않는다. InnoDB에서 외래키는 부모테이블과 자식테이블 모두 해당 컬럼에 인덱스 생성이 필요하다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;MVCC(Multi-Version Concurrency Control) 다중 버전 동시성 제어&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;레코드 레벨의 트랜잭션을 동시에 지원하는 DBMS가 제공하는 기능으로 MVCC는 잠금을 사용하지 않는 일관된 읽기를 제공한다. InnoDB는 언두 로그를 사용해 구현한다.&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: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;InnoDB는 MVCC 기술을 이요해 잠금을 걸지 않고 읽기 작업을 수행한다. 잠금을 걸지 않기에 읽기 작업을 다른 트랜잭션이 가지는 잠금을 기다리지 않고 읽기 작업이 가능하다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;즉 다른 사용자가 레코드를 변경하고 아직 커밋을 하지 않았다 하더라도 변경 트랜잭션이 다른 사용자의 select 작업을 방해하지 않는다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&amp;rarr; 변경되기 전 언두 로그를 읽어온다.&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;자동 데드락 감지&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;InnoDB 스토리지 엔진은 잠금이 교착 상태에 빠지진 않았는지 체크하기 위해 잠금 대기 목록을 그래프 형태로 관리한다. 또한 데드락 감지 스레드가 있어 주기적으로 대기 그래프를 검사해 트랜잭션을 종료한다.&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;자동화된 장애 복구&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;InnoDB에는 손실이나 장애로부터 데이터를 보호하기 위한 여러가지 메커니즘이 탑재되어 있다.&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;버퍼 풀&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;디스크 데이터 파일이나 인덱스 정보를 메모리에 캐시해두는 공간이다 또한 쓰기 작업을 지연시켜 일괄 작업으로 처리도 해준다. Insert, Update, Delete 처럼 데이터를 변경하는 쿼리는 파일의 분산되어있는 레코드를 변경하기에 랜덤한 디스크 작업을 발생시킴&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;버퍼풀 구조&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;InnoDB 스토리지 엔진은 버퍼 풀이라는 공간을 거대한 메모리 공간을 페이지 크기의 조각으로 쪼개어 InnoDB 스토리지 엔진이 데이터를 필요로 할때 해당 데이터 페이지를 읽어 각 조각에 저장한다.&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;LRU 리스트 : 한쪽은 MRU(최근 사용), 한쪽은 LRU(사용하지 않은) 자주 쓰는 데이터는 남기고 최근에 안쓴 데이터부터 메모리에서 삭제한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;플러시 리스트 : 디스크와 내용이 달라진 페이지를 모아서 순서대로 저장한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;버퍼 풀과 리두 로그&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;InnoDB 버퍼 풀은 데이터베이스 성능 향상을 위해 데이터 캐시, 쓰기 버퍼링이라는 용도가 있어 버퍼풀의 메모리 공간만 늘리면 캐시 기능만 향상된다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&amp;rarr; 단순히 버퍼 풀만 늘린다고 버퍼풀 쓰기 기능은 향상 되지 않고 읽기 기능만 향상된다.&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;클린 페이지 : 디스크에서 읽고 전혀 변경 되지 않는 페이지&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;더티 페이지 : 페이지는 디스크와 메모리(버퍼 풀)의 데이터 상태가 다르기 때문에 언젠가는 디스크로 기록되어야 하는 페이지&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;리두 로그 : 리두 로그 파일에서 재사용 불가능한 공간이다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;InnoDB 스토리지 엔진에서 리두 로그는 1개 이상의 고정 크기 파일을 연결해 순환고리로 사용한다&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&amp;rarr; 하나의 로그파일을 끝까지 다 사용해도 처음부터 덮어씌워 로그 엔트리(단순한 데이터 변경만 있지 않고 서버가 꺼져도 복구 가능한 데이터를 포함)로 다시 작성한다.&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;LSN : 리두 로그 파일은 기록될 때마다 로그 포지션이 제일 중요하다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;스토리지 엔진은 주기적으로 체크포인트를 발생시켜 리두 로그와 버퍼풀의 더티페이지를 디스크로 동기화한다. 이때 시작점은 최근 체크포인트점의 LSN이 되며 끝점은 리두 로그 엔트리로 값이 계속 증가한다.&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: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이때 체크포인트 에이지는 마지막 리두 로그 엔트리 LSN 값에서 최근 체크포인트 LSN을 빼면 현재 활성 리두 로그의 정도를 알 수 있다.&lt;/span&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;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;버퍼 풀 플러시&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;더티 페이지들은 어떤 방식으로 디스크에 반영하는지에 대한 내용이며 이때 2가지 방법을 사용해서 반영한다.&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;플러시 리스트 플러시&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;LRU 리스트 플러시&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;새로운 데이터를 읽어올 빈 메모리 공간을 확보하기 위해 LRU 플러시 함수가 사용된다. LRU 리스트의 끝부분부터 시작해서 페이지를 스캔하며 더티 페이지는 디스크에 동기화하게 하며 클린 페이지는 프리페이지로 옮긴다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>Dev Book Review/Real MySQL</category>
      <author>쿨쿨.</author>
      <guid isPermaLink="true">https://mari-laveau.tistory.com/282</guid>
      <comments>https://mari-laveau.tistory.com/282#entry282comment</comments>
      <pubDate>Tue, 7 Jul 2026 00:59:58 +0900</pubDate>
    </item>
    <item>
      <title>[AWS] 네트워크 기초 (VPC, Subnet, NAT)</title>
      <link>https://mari-laveau.tistory.com/281</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;aws 글로벌 인프라는 어떻게 생겼을까??&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: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;제일 먼저 핵심 개념 3가지에 대해 알아보자&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Region(리전)&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;지리적으로 분리된 독립 단위 현재 30개 이상 있다.&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;ex) ap-northeast-2&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Availability Zone(가용 영역)&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Region 안에 물리적으로 격리된 단위로 각각 별도 데이터 센터가 존재한다.&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;ex) ap-northeast-2a / 2b / 2c&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Data Center(데이터 센터)&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Availability Zone을 구성하는 건물로 수만대의 서버가 존재한다.&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;ex) 사용자에게는 보이지 않는다.&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&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: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Region 안에는 반드시 둘 이상의 Availability Zone이 있고 AZ 사이에는 저지연 전용선이 깔려 있다.&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: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;또한 흥미로운 사실은 AWS에서 신규 서비스들을 출시할때 먼저 미국 내 버지니아 북부 등 먼저 사용가능하도록 되어 있고 이후 점차 안정성이 뛰어나면 다른 리전으로 확장이 된다.&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: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;만약 서비스를 사용화한다면 EC2를 서로 다른 2개의 zone을 사용해야한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;▶ ex) 2개의 서버 모두 같은 zone에 위치해 있고 해당 데이터 센터가 고장이나서 복구하는 도중 실제 서비스를 이용할 수 없기 때문&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;AWS VPC, Subnet 구조&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1570&quot; data-origin-height=&quot;1130&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/BhdZf/dJMcahZinDN/er9KE9cHGtNtD2ex8KPbQ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/BhdZf/dJMcahZinDN/er9KE9cHGtNtD2ex8KPbQ1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/BhdZf/dJMcahZinDN/er9KE9cHGtNtD2ex8KPbQ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FBhdZf%2FdJMcahZinDN%2Fer9KE9cHGtNtD2ex8KPbQ1%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;1570&quot; height=&quot;1130&quot; data-origin-width=&quot;1570&quot; data-origin-height=&quot;1130&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;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;VPC는 IP 대역을 논리적으로 확보하고 그 안에 subnet 개념으로 쪼개서 사용한다. 또한 VPC는 Region에 종속이 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;+ IP 대역 10.x.x.x, 172.x.x.x, 192.x.x.x, 3개의 IP대역은 private IP이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;서브넷 종류&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;설명&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Public subnet&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;외부에서 들어오고 나가는 트래픽이 모두 가능한 공간으로&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;웹 서버, 로드밸런서, Bastion이 여기에 들어온다.&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;DMZ subnet&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;NAT를 연결하여 외부와 통신하는 구간이다.&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Private Subnet&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;외부에서 들어오는 트래픽이 차단된 공간으로&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;앱 서버, DB, 내부 API가 여기에 들어온다.&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Route Table&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;서브넷과 1 : 1로 매핑되는 구조이며 기본적으로 Route Table은 VPC 대역을 기본적으로 가지고 있다.&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 style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;서브넷 테이블은 다음과 같이 구성되어 있다.&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;순서&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;목적지 범위&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;실제 매핑되는 요소&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;1&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;10.0.0.0/16&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;vpc&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;2&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;0.0.0.0/24&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;internet-gateway&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;3&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;10.0.1.0/24&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;subnet&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;또한 매핑 규칙으로는 같은 범위 안에 포함되어 있어도 가장 구체적인 즉 일치하는 항목을 선택해서 보낸다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;ex) 10.0.1.5인 패킷이 들어오고 2 -&amp;gt; 1 -&amp;gt; 3 순서로 찾는다고 했을때 모든 범위에 포함된다 이때 가장 좁은 범위 즉 3번 은 10.0.1.0 ~ 10.0.1.255의 범위의 ip를 포함하는 가장 일치하는 구간이기에 해당구간으로 패킷을 보낸다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Internet Gateway&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;VPC(가상 네트워크)와 외부 인터넷을 연결해 주는 관문이다.&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: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;만약 VPC에 Internet Gateway가 달려있고 여러개의 서브넷을 나눴을때 해당 서브넷에 연결되어 있는 라우팅 테이블에 IGW가 존재하면 public subnet이며 아닌 경우 private Subnet이다.&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: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;public subnet에서는 공인 ip를 할당할 수 있다. 이때 EC2에 공개된 IP를 사용하기에 클라이언트와 소통이 가능하다.&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-origin-width=&quot;1346&quot; data-origin-height=&quot;808&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bzcSqy/dJMcaglMWkO/6kUPHDqlaKIs9kp5kz6Rqk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bzcSqy/dJMcaglMWkO/6kUPHDqlaKIs9kp5kz6Rqk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bzcSqy/dJMcaglMWkO/6kUPHDqlaKIs9kp5kz6Rqk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbzcSqy%2FdJMcaglMWkO%2F6kUPHDqlaKIs9kp5kz6Rqk%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;1346&quot; height=&quot;808&quot; data-origin-width=&quot;1346&quot; data-origin-height=&quot;808&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;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;위의 사진에서 ec2는 10.0.1.7이라는 ip를 가지고 해당 서브넷은 10.0.1.0 ~ 10.0.1.255 대역의 IP 주소를 할당받을 수 있다 VPC는 internet-gateway에 연결되어 있다 이때 ec2는 인터넷 게이트웨이를 통해서 외부와 통신할 수 있을까??&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: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;정답은 아니다 &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;ec2가 private ip(10.0.1.7)을 가지고 있다고 해서 외부에 요청을 보내도 외부에서는 해당 ip를 인식할 수 없기에 internet-gateway에서 private ip주소를 public ip 주소로 변환하지 못해서 igw에서 차단된다.&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: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;만약에 나간다해도 목적지 서버가 다시 요청 서버에 패킷을 보내야 하는데 private ip를 찾을 수 없기에 응답을 할 수 없다.&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: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;그렇다면 방법은 EC2에 public IP를 할당하는 방법밖에 없을까? 여기서 나오는 개념이 NAT(Network-address-Translation)이다.&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;NAT(Network-Address-Translation)&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;private subnet에 있는 서버들의 패킷을 받아 외부 인터넷으로 연결해주는 것으로 NAT는 외부 IP를 가진다.&amp;nbsp;&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-origin-width=&quot;1836&quot; data-origin-height=&quot;1096&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/boV18D/dJMcahrxJC9/uMULZrqAZ2q2Akp94iFCqK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/boV18D/dJMcahrxJC9/uMULZrqAZ2q2Akp94iFCqK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/boV18D/dJMcahrxJC9/uMULZrqAZ2q2Akp94iFCqK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FboV18D%2FdJMcahrxJC9%2FuMULZrqAZ2q2Akp94iFCqK%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;1836&quot; height=&quot;1096&quot; data-origin-width=&quot;1836&quot; data-origin-height=&quot;1096&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;1번 상황을 보자 EC2는 private ip주소만 가지고 있고 해당 서브넷에 routing table에 NAT주소도 포함되기에 외부 서버에 요청을 보내면 NAT서버에서 ip주소를 NAT 주소로 변환후 IGW에 요청하여 응답을 받을 수 있다.&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: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;2번째 상황은 약간 다르다. private subnet 안에서 routing table은 해당 vpc 주소만 매핑되어 있다 즉 private subnet은 외부에 요청을 보낼 수 없다고 생각할 수 있지만 routing table에는 vpc 주소와 nat주소가 매핑되어 있기에 해당 EC2도 외부와 통신을 할 수 있게 된다.&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: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;추가적으로 nat는 public subnet에만 추가할 수 있다.&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-origin-width=&quot;837&quot; data-origin-height=&quot;415&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mPKfj/dJMcajv5zjX/ki6iTKXIGkkiD5UfuDEVok/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mPKfj/dJMcajv5zjX/ki6iTKXIGkkiD5UfuDEVok/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mPKfj/dJMcajv5zjX/ki6iTKXIGkkiD5UfuDEVok/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmPKfj%2FdJMcajv5zjX%2Fki6iTKXIGkkiD5UfuDEVok%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;837&quot; height=&quot;415&quot; data-origin-width=&quot;837&quot; data-origin-height=&quot;415&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;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;또한 실무에서는 위 사진처럼 ALB에서 사용자의 요청을 받고 DB와 EC2는 따로 private subnet으로 배치해서 접근할 수 없도록 설정한다고 한다.&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: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;외부 클라이언트가 ALB에 요청을 하면 EC2는 그에 관한 응답을 RDS나 내부적으로 처리하여 NAT에 요청을 해서 해당 클라이언트에게 응답할 수 있도록 구성한다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>AWS</category>
      <category>AWS</category>
      <category>igw</category>
      <category>NAT</category>
      <category>subnet</category>
      <author>쿨쿨.</author>
      <guid isPermaLink="true">https://mari-laveau.tistory.com/281</guid>
      <comments>https://mari-laveau.tistory.com/281#entry281comment</comments>
      <pubDate>Sun, 5 Jul 2026 20:22:08 +0900</pubDate>
    </item>
    <item>
      <title>[AWS] 계정과 권한 IAM</title>
      <link>https://mari-laveau.tistory.com/280</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;aws 계정은 운영 경계이며&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;개발계정(Dev) : 개발자들이 자유롭게 코드를 테스트하고 실행할 수 있는 환경&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;검증계정(Stage/QA) : 운영 환경과 동일하게 맞추고, 배포 전 최종 기능 및 성능을 테스트 하는 환경&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;운영계정(Prod) : 실제 유저들이 사용중인 서비스가 돌아가는 보호 구역&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Root(루트) 계정은 회원가입 시 사용한 이메일로 로그인하는 계정의 소유자로 계정 내 모든 서비스와 리소스에 접근이 가능하다.&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: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;루트 계정은 너무나도 권한이 많기에 IAM으로 권한을 낮추어 대체해서 사용하는 경우가 많다.&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: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;IAM은 사람과 시스템에 필요한 만큼의 권한을 부여하기 위한 AWS 권한 관리 서비스이다.&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;구성요소&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;의미&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;특징&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;User(사용자)&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;실제 사람이 사용하는 계정이다.&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;사람 개개인으로 유저를 생성할 수 있다.&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Group(그룹)&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;User들의 권한 집합체이다.&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;백엔드 팀, 인프라 팀 처럼 유저를 묶어서 관리할 수 있다.&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Role(역할)&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;시스템이나 서비스가 임시로 빌려쓰는 권한이다.&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;EC2, Lambda 같은 AWS 리소스가 주체가 된다.&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Policy(정책)&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;구체적인 권한 명세서(Json 형식)이다.&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;S3에서 파일만 읽을 수 있음 과 같은 규칙을 적어둔 문서이다.&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&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: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;IAM을 호출한 주체는 누구인지 또한 작업을 수행할 권한이 있는지 확인한다.&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;주체는 IAM이 실제로 가입된 유저인지(인증) 이후 자격(권한)이 있는지 확인한다(인가)&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;즉 IAM User는 사람이 사용하는 것이며, IAM Role은 시스템이 사용하는 것이다.&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: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;AWS에서 모든 클라우드 리소스는 하나 하나 행동하는데 허락이 필요하다. ec2가 s3에 파일을 쓰기위한(접근할 수 있는 권한이 있어야함) 권한을 부여하기 위해 role을 부여한다.&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Trust Policy : 어떤 리소스가 쓸 수 있는지&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Permission Policy : 어떤 권한을 쓸 수 있는지&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;managed Policy : aws가 기본적으로 제공하는 정책&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;inline Policy : json 형태로 내가 커스텀해서 만드는 정책&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>AWS</category>
      <author>쿨쿨.</author>
      <guid isPermaLink="true">https://mari-laveau.tistory.com/280</guid>
      <comments>https://mari-laveau.tistory.com/280#entry280comment</comments>
      <pubDate>Sun, 5 Jul 2026 17:13:14 +0900</pubDate>
    </item>
    <item>
      <title>[ByteByteGo] Multi-Region Architecture: Going Global Without Going Broke</title>
      <link>https://mari-laveau.tistory.com/279</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;도입부&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;그러나 어플리케이션에 두 번째 리전을 추가하면 오히려 리전이 하나일 때보다 더 느려지고 신뢰성이 떨어질 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;ex)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이제 각 리전은 어느 쪽이 먼저였는지에 대한 공유 기록 없이 서로 다른 버전의 데이터를 보유하게 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;연결이 복구되면 두 버전 중 하나를 다른 버전 대신 선택해야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Foundation(기반 개념)&lt;/span&gt;&lt;/h3&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Region(지역)&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;지리적 영역으로 인프라를 지리적으로 나누어 배포하는 것을 의미한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;사용자의 요청이 리전이 가까울수록 네트워크 지연을 최소화 할 수 있다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;실제 서비스를 사용하는 사용자들과 가장 가까운 리전을 선택해서 해당 인프라를 사용하는것이 적당하다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Availability Zone(가용 영역)&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;리전 내부의 독립된 데이터 센터로 하나의 리전 내부에서 물리적으로 완전히 분리되어 있는 데이터 센터의 집합이다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;모든 가용 영역은 특정 반드시 특정 리전에 속해 있다.&lt;/span&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;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;애플리케이션을 여러 가용 영역에 분산시키면 단일 데이터 센터의 가동 중단으로 서비스를 보호할 수 있다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;메인 리전에서 멀리 떨어진 사용자들의 지연 시간을 줄이기 위해&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;특정 지역 전체가 오프라인 상태가 되더라도 서비스를 계속 운영하기 위해&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;데이터가 물리적으로 저장되는 위치에 대한 법적 요구사항을 충족하기 위해&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;단일 리전 내의 여러 가용 영역에 분산된 시스템은 멀티 리전 배포가 아니다.&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-origin-width=&quot;1334&quot; data-origin-height=&quot;784&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c4xGsA/dJMcadWUELi/ppU7owuaJTadBroz3Ku4zK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c4xGsA/dJMcadWUELi/ppU7owuaJTadBroz3Ku4zK/img.png&quot; data-alt=&quot;왼쪽 US-EAST는 하나의 리전에 3개의 가용영역이 존재하며 현재 AZ3 데이터 센터가 문제가 생겨 다운된 상태이다. 하지만 각 데이터 센터는 격리되어 있기에 전체 서비스는 끊기지 않는다. 오른쪽 EU-WEST는 하나의 리전에 여러 데이터센터가 존재한다 이때 US-EAST에 자연재해가 발생해서 모든 리전 전체가 마비되도 EU-WEST는 영향을 받지 않는다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c4xGsA/dJMcadWUELi/ppU7owuaJTadBroz3Ku4zK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc4xGsA%2FdJMcadWUELi%2FppU7owuaJTadBroz3Ku4zK%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;1334&quot; height=&quot;784&quot; data-origin-width=&quot;1334&quot; data-origin-height=&quot;784&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;왼쪽 US-EAST는 하나의 리전에 3개의 가용영역이 존재하며 현재 AZ3 데이터 센터가 문제가 생겨 다운된 상태이다. 하지만 각 데이터 센터는 격리되어 있기에 전체 서비스는 끊기지 않는다. 오른쪽 EU-WEST는 하나의 리전에 여러 데이터센터가 존재한다 이때 US-EAST에 자연재해가 발생해서 모든 리전 전체가 마비되도 EU-WEST는 영향을 받지 않는다.&lt;/figcaption&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;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;어플리케이션 서버는(WAS ex) Spring Boot)는 상태가 없다.&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: 'Noto Sans Demilight', 'Noto Sans KR';&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;반면 데이터베이스(ex) MySQL, PostgreSQL), 파일 저장소, 사용자 세션은 상태를 유지하며(Stateful), 이는 다른 모든 구성 요소가 의존하는 데이터를 보유하고 있음을 의미한다.&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: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;여기서 어플리케이션 서버와 데이터베이스를 복제하는데에 있어 차이가 있다.&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-origin-width=&quot;1348&quot; data-origin-height=&quot;804&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bMxKNH/dJMcaiX9p8r/23Z7ESUxO46Y5tRHKoTCx1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bMxKNH/dJMcaiX9p8r/23Z7ESUxO46Y5tRHKoTCx1/img.png&quot; data-alt=&quot;Web Servers는 무상태(stateless)하기에 복제하기에 오랜 시간이 소요되지 않는다. 하지만 데이터베이스는 stateful 하기에 복제하는데 많은 시간이 걸린다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bMxKNH/dJMcaiX9p8r/23Z7ESUxO46Y5tRHKoTCx1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbMxKNH%2FdJMcaiX9p8r%2F23Z7ESUxO46Y5tRHKoTCx1%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;1348&quot; height=&quot;804&quot; data-origin-width=&quot;1348&quot; data-origin-height=&quot;804&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Web Servers는 무상태(stateless)하기에 복제하기에 오랜 시간이 소요되지 않는다. 하지만 데이터베이스는 stateful 하기에 복제하는데 많은 시간이 걸린다.&lt;/figcaption&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;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;상태가 없는 어플리케이션 서버는 몇 분 만에 복제할 수 있다(데이터를 동기화할 필요가 없기 때문에 똑같은 소스 코드를 실행하기만 하면됨) 하지만 복제하기 어려운 것은 계정 기록과 장바구니 콘텐츠이다(데이터베이스 -&amp;gt; stateful하며 데이터의 의존관계가 존재함)&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Replication(복제)&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;데이터가 둘 이상의 리전에 존재해야 한다면 그곳으로 데이터를 복사해야 한다. 이 복사 과정을 복제(Replication)이라고 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;복제에는 동기(Synchronous)와 비동기(Asynchronous) 두가지 형태가 존재한다.&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;동기(Synchronous)&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;동기 복제 방식에서는 쓰기 작업이 대기한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;변경 사항이 들어오면 시스템은 이를 다른 리전으로 전송하고, 해당 리전이 복사본을 수신했다고 확인할때까지 쓰기 작업을 완료하지 않고 붙잡아 두며 이후 쓰기 작업이 성공한 것으로 간주한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;장점 : 리전들은 완벽히 동기화된 상태로 유지하므로 어느 곳에서 읽기 작업을 수행하든 동일한 값을 반환한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;단점 : 모든 단일 쓰기 작업에 발생되며 각 쓰기 작업마다 리전 간의 거리를 오가는 왕복비용을 치러야 하기에 느리다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;비동기(Asynchronous)&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;로컬에서 즉시 쓰기가 성공하고, 복사본은 백그라운드에서 다른 리전으로 이동한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;복제가 완료될 때까지 기다릴 필요가 없기 때문에 쓰기 속도가 빠르게 유지된다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;장점 : 복제가 완료될때까지 기다릴 필요가 없기에 쓰기 속도가 빠르다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;단점 : 백그라운드로 동작하기에 아직 반영이 되지 않은 리전이 존재하면 이전(과거)의 값을 응답받을 수 있으며&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;쓰기 작업이 복제되기도 전에 메인 리전에 장애가 발생하면 쓰기 데이터는 유실될 수 있음&lt;/span&gt;&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;1372&quot; data-origin-height=&quot;808&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tYfpH/dJMcajixmnZ/7DTjomkY9kUOBFOm6vfcW1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tYfpH/dJMcajixmnZ/7DTjomkY9kUOBFOm6vfcW1/img.png&quot; data-alt=&quot;Synchronous(동기)와 Asynchronous(비동기)의 차이&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tYfpH/dJMcajixmnZ/7DTjomkY9kUOBFOm6vfcW1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtYfpH%2FdJMcajixmnZ%2F7DTjomkY9kUOBFOm6vfcW1%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;1372&quot; height=&quot;808&quot; data-origin-width=&quot;1372&quot; data-origin-height=&quot;808&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Synchronous(동기)와 Asynchronous(비동기)의 차이&lt;/figcaption&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;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이처럼 동기와 비동기는 서로가 장점과 단점이 확실하게 나눠져 있기에 Tradeoff 관계에 있다.&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: 'Noto Sans Demilight', 'Noto Sans KR';&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Consistency(일관성)&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Strong consistency(강한 일관성)&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;어떤 리전이 응답하든 모든 읽기 작업이 가장 최신의 쓰기 결과를 반환하도록 보장한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;장점 : 읽기 요청을 보낼때마다 가장 최신의 데이터를 가져오기에 신뢰성이 보장된다. (안전하고 직관적)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;단점 : 모든 리전을 최신 상태로 유지하기 위해 리전 간 왕복 통신을 기다려야 한다 (지연 시간 증가)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Eventual consistency(최종 일관성)&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;리전 간의 데이터 합의는 빠르게 이루어지지만 쓰기 직후에 수행된 읽기 작업은 여전히 잠깐동안 과거 값을 반환할 수 있다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;장점 : 읽기와 쓰기 속도가 매우 빠르게 유지된다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;단점 : 쓰기 직후 읽기 작업을 수행할때 과거의 값을 조회할 수 있다.&lt;/span&gt;&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;1342&quot; data-origin-height=&quot;794&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bF1tmg/dJMcaasoEu0/1MojRWqPK0aAxkjI2TLvSk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bF1tmg/dJMcaasoEu0/1MojRWqPK0aAxkjI2TLvSk/img.png&quot; data-alt=&quot;Strong consistency VS Eventual consistency&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bF1tmg/dJMcaasoEu0/1MojRWqPK0aAxkjI2TLvSk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbF1tmg%2FdJMcaasoEu0%2F1MojRWqPK0aAxkjI2TLvSk%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;1342&quot; height=&quot;794&quot; data-origin-width=&quot;1342&quot; data-origin-height=&quot;794&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Strong consistency VS Eventual consistency&lt;/figcaption&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;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&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 style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;예를 들어 SNS 시스템과 금융 시스템이라고 가정하면&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 style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;SNS 시스템은 프로필 소새글이 몇 초 늦게 반영되는 것은 크게 문제가 되지 않는다 따라서 비동기 방식을 사용해서 사용자에게 빠른 응답을 제공하는 것이 적절하다&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 style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Routing(라우팅)&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;사용자가 어느 리전에 도달할지에 대해 결정하는 것도 필요하다. 이러한 역할을 하는 것이 지리적 라우팅(Geo-Routing)이며 이는 고정된 리전이 아니라 가장 가깝고 상태가 정상적인 리전으로 요청을 안내하는 작업을 한다.&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: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Geo-DNS는 사용자 IP 주소를 기반으로 위치를 추정하여 가장 가까운 서버의 IP 주소로 도메인을 변환하는 작업을 수행한다.&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: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;즉 유럽에서 보낸 요청은 유럽 리전에 도달하고, 북미에서 보낸 요청은 북미와 더 가까운 리전에 도달하게 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이는 읽기 요청 처리에 큰 도움이 되며 자주 변하지 않는 캐시된 페이지, 이미지, 기타 콘텐츠를 가까운 리전에서 제공하면 지연 시간이 크게 감소하게 된다.&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-origin-width=&quot;1356&quot; data-origin-height=&quot;902&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/eFl9lp/dJMcajbGqk1/CSO7ak5KzAVKahD7yeYddK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/eFl9lp/dJMcajbGqk1/CSO7ak5KzAVKahD7yeYddK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/eFl9lp/dJMcajbGqk1/CSO7ak5KzAVKahD7yeYddK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FeFl9lp%2FdJMcajbGqk1%2FCSO7ak5KzAVKahD7yeYddK%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;1356&quot; height=&quot;902&quot; data-origin-width=&quot;1356&quot; data-origin-height=&quot;902&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;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Active-Passive(액티브 패시브)&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;하나의 리전(Active)가 모든 쓰기 작업을 독점해서 처리하며 하나 이상의 패시브 리전은 지속적으로 복제 스트림을 전달받는다.&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: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;패시브 리전은 최신 복사본을 보유한 채 아무런 서비스를 제공하지 않거나, 오직 읽기 요청만 처리하며 대기 상태를 유지한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이러한 전환 과정을 장애 조치(failover)이라고 하며 장애 조치에서도 해결해야할 과제들이 존재한다.&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: 'Noto Sans Demilight', 'Noto Sans KR';&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이 공백은 장애를 감지하고, 전환을 결정하고, 트래픽을 재라우팅하는 데 걸리는 시간에 따라 결정된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;장애를 명확하게 감지하는 것이 까다롭고 잠시 동안 네트워크 깜빡임이 리전 전체가 죽은 상태와 똑같이 보일 수 있으며, 오탐에 빨리 반응하면 그 자체로 또 다른 서비스 중단을 초래할 수 있다.&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-origin-width=&quot;1348&quot; data-origin-height=&quot;804&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/o4WvV/dJMcabEMdrJ/wRf7dDwExGoadA4feXlhHk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/o4WvV/dJMcabEMdrJ/wRf7dDwExGoadA4feXlhHk/img.png&quot; data-alt=&quot;왼쪽은 기본 작동, 오른쪽은 장애상황 발생시 리전 B가 승격되어 액티브 상태가되어 읽기,쓰기 작업 수행&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/o4WvV/dJMcabEMdrJ/wRf7dDwExGoadA4feXlhHk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fo4WvV%2FdJMcabEMdrJ%2FwRf7dDwExGoadA4feXlhHk%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;1348&quot; height=&quot;804&quot; data-origin-width=&quot;1348&quot; data-origin-height=&quot;804&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;왼쪽은 기본 작동, 오른쪽은 장애상황 발생시 리전 B가 승격되어 액티브 상태가되어 읽기,쓰기 작업 수행&lt;/figcaption&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;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;공백 기간 동안 쓰기 작업이 일시 중단될 수 있으며, 복제가 아직 완료되지 않은 모든 쓰기 데이터는 유실될 위험에 처할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이러한 과정을 장애 복구(Failback)이라고 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;마지막으로 대기 용량(Standby capacity)도 공짜가 아니다. 패시브 리전은 계속 가동 중이면서 정작 거의 발생하지 않을 수 있는 장애 상황에만 쓰이기 때문이다.&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Active-Active(액티브-액티브)&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;유휴 대기 상태와 장애 조치 시의 공백을 없앤다는 것은 모든 리전이 동시에 쓰기 작업을 수용할 수 있도록 함을 의미하며 이러한 구성을 Active-Active 라고 한다.&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: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이는 모든 리전이 로컬에서 직접 서비스를 제공하고 변경 사항을 접수하며 가장 강력하고 고도화된 구성이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;모든 지역의 사용자가 자신과 가까운 리전에 데이터를 쓰고, 전반적인 지연 시간이 대폭 감소하며, 낭비되는 유휴 용량도 사라진다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이러한 경우 데이터 버전이 2개가 되며 어느쪽 데이터를 최종적으로 선택할지 결정해야 한다. 이러한 결정을 Conflict resolution 이라고 한다.&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: 'Noto Sans Demilight', 'Noto Sans KR';&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;두 변경 사항을 모두 보존하거나 정교하게 병합하는 접근 방식도 존재한다.&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-origin-width=&quot;1338&quot; data-origin-height=&quot;860&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/5kJ9P/dJMcaaMFCRU/pGJhVGjA3MsLHIgBaTMh3k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/5kJ9P/dJMcaaMFCRU/pGJhVGjA3MsLHIgBaTMh3k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/5kJ9P/dJMcaaMFCRU/pGJhVGjA3MsLHIgBaTMh3k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F5kJ9P%2FdJMcaaMFCRU%2FpGJhVGjA3MsLHIgBaTMh3k%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;1338&quot; height=&quot;860&quot; data-origin-width=&quot;1338&quot; data-origin-height=&quot;860&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;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;두 액티브 리전 사이의 네트워크 연결이 끊어지면 양쪽 모두 계속 쓰기를 받아들이는데, 상대방 리전 변경 사항을 전혀 알 수 없다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;1342&quot; data-origin-height=&quot;762&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lZets/dJMcag0me0u/jBvJOc4TehguTxH0UvK4Fk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lZets/dJMcag0me0u/jBvJOc4TehguTxH0UvK4Fk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lZets/dJMcag0me0u/jBvJOc4TehguTxH0UvK4Fk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlZets%2FdJMcag0me0u%2FjBvJOc4TehguTxH0UvK4Fk%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;1342&quot; height=&quot;762&quot; data-origin-width=&quot;1342&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;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Residency(데이터 거주)&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;때로는 규제와 법령이 이러한 방향을 결정하기도 하며&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이것을 data residency라고 하며 이는 아키텍쳐 접근 방식 전체를 바꾸어 놓는다.&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: 'Noto Sans Demilight', 'Noto Sans KR';&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;엄격한 사법권 아래에 있는 수천 명 수준의 소규모 서비스라 할지라도 성능 목적만으로는 전혀 필요 없었을 현지 인프라를 무조건 운영해야 할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Cost(비용)&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이러한 비용은 크게 3가지로 나뉜다.&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;여러 리전에서 운영한다는 것은 각 리전의 용량만큼 비용을 지불해야 한다는 것을 의미한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;액티브-패시브 구성에서는 이 용량의 상당 부분이 올해 안에 일어나지 않을지도 모르는 장애에 대비해 그저 유휴 상태로 대기한다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;데이터 복제는 공짜가 아니며, 리전 간에 끊임없이 흐르는 트래픽은 대개 전송량 기준으로 요금이 부과된다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;규모가 커지면 이 비용이 실제 컴퓨팅 작업을 수행하는 서버 비용보다 더 커질 수 있다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;모든 장애 상황이 여러 리전에 걸쳐 발생하고, 디버깅 시 확인해야 할 곳이 늘어나며, 복제 지연이나 네트워크 단절 현상을 추론하는 작업은 고도의 전문성을 요구하는 까다로운 작업이 된다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이러한 부담은 엔지니어들의 시간적 비용을 크게 증가시킨다.&lt;/span&gt;&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;1356&quot; data-origin-height=&quot;824&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/KX7nQ/dJMcaiqnrrk/KsOeLnnKYcxdftsOlZf8K1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/KX7nQ/dJMcaiqnrrk/KsOeLnnKYcxdftsOlZf8K1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/KX7nQ/dJMcaiqnrrk/KsOeLnnKYcxdftsOlZf8K1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKX7nQ%2FdJMcaiqnrrk%2FKsOeLnnKYcxdftsOlZf8K1%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;1356&quot; height=&quot;824&quot; data-origin-width=&quot;1356&quot; data-origin-height=&quot;824&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;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Summary(정리)&lt;/span&gt;&lt;/h3&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;글로벌화는 단 하나의 스위치를 켜는 것이 아니라 trade-off를 조율해 가는 점진적인 과정이며, 올바른 구성이란 가장 고도화된 기술이 아니라 문제 본연에 부합하는 구성이다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;컴퓨팅 자원은 쉽게 복제되므로, 멀티 리전의 진짜 비용과 난제는 데이터 계층에 존재한다 (DB)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Replication은 일관성을 완벽히 유지하지만 리전 간 왕복 비용을 치르는 '동기 방식'과, 속도는 빠르지만 데이터 반영이 약간 뒤처지는 '비동기 방식' 사이의 선택이다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;강한 일관성은 지연 시간이라는 대가를 치르고 데이터 불일치 기간을 없애는 반면, 최종 일관성은 빠른 속도를 유지하기 위해 잠깐의 불일치 기간을 허용합니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;물리적 거리는 어떠한 엔지니어링 기술로도 제거할 수 없는 지연 시간의 하한선을 설정하며, 이것이 바로 Latency tax 이다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Geo-Routing은 가장 가까운 리전에서 데이터를 제공함으로써 비용 효율적으로 읽기 속도를 높여주지만, 쓰기 작업은 여전히 느려 해결하지 못한 난제이다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Active-Active는 가용성을 확보하는 대신 Failover 공백을 유발하며, 상대적으로 더 어렵고 평소 연습이 부족하기 마련인 FailBack이라는 과제를 안겨준다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Active-Active는 모든 곳에서 로컬 쓰기가 가능하게 해주지만, 충돌 해결 및 네트워크 단절 시 Split-Brain 위험이라는 막중한 대가를 요구한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Data residency는 서비스의 규모나 트래픽과 무관하게 오직 법적인 이유만으로 멀티 리전 설계를 강제할 수 있습니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;</description>
      <category>Review</category>
      <author>쿨쿨.</author>
      <guid isPermaLink="true">https://mari-laveau.tistory.com/279</guid>
      <comments>https://mari-laveau.tistory.com/279#entry279comment</comments>
      <pubDate>Sun, 5 Jul 2026 02:00:14 +0900</pubDate>
    </item>
    <item>
      <title>[ByteByteGo] How AI Agents Manage Memory and Avoid Forgetfulness</title>
      <link>https://mari-laveau.tistory.com/278</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;a href=&quot;https://blog.bytebytego.com/p/how-ai-agents-manage-memory-and-avoid?utm_source=post-email-title&amp;amp;publication_id=817132&amp;amp;post_id=203744632&amp;amp;utm_campaign=email-post-title&amp;amp;isFreemail=true&amp;amp;r=4auvy4&amp;amp;triedRedirect=true&amp;amp;utm_medium=email&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://blog.bytebytego.com/p/how-ai-agents-manage-memory-and-avoid?utm_source=post-email-title&amp;amp;publication_id=817132&amp;amp;post_id=203744632&amp;amp;utm_campaign=email-post-title&amp;amp;isFreemail=true&amp;amp;r=4auvy4&amp;amp;triedRedirect=true&amp;amp;utm_medium=email&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1783083331676&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;How AI Agents Manage Memory and Avoid Forgetfulness&quot; data-og-description=&quot;In this article, we will try to understand how that architecture gets built, from the constraint that forces it to exist all the way to the tradeoffs that follow.&quot; data-og-host=&quot;blog.bytebytego.com&quot; data-og-source-url=&quot;https://blog.bytebytego.com/p/how-ai-agents-manage-memory-and-avoid?utm_source=post-email-title&amp;amp;publication_id=817132&amp;amp;post_id=203744632&amp;amp;utm_campaign=email-post-title&amp;amp;isFreemail=true&amp;amp;r=4auvy4&amp;amp;triedRedirect=true&amp;amp;utm_medium=email&quot; data-og-url=&quot;https://blog.bytebytego.com/p/how-ai-agents-manage-memory-and-avoid&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/kAGDU/dJMb9b325mg/ssXt3vWqT5A9kZfLhXXopK/img.jpg?width=1200&amp;amp;height=675&amp;amp;face=0_0_1200_675,https://scrap.kakaocdn.net/dn/DeAxi/dJMb9aKP9ij/9kaFghsrjVsFl4BeOF1Yjk/img.jpg?width=1600&amp;amp;height=800&amp;amp;face=0_0_1600_800,https://scrap.kakaocdn.net/dn/dhTibA/dJMb85W4xk9/9nvkvu7g4z2FzwkmBrzCO1/img.png?width=1456&amp;amp;height=1115&amp;amp;face=0_0_1456_1115&quot;&gt;&lt;a href=&quot;https://blog.bytebytego.com/p/how-ai-agents-manage-memory-and-avoid?utm_source=post-email-title&amp;amp;publication_id=817132&amp;amp;post_id=203744632&amp;amp;utm_campaign=email-post-title&amp;amp;isFreemail=true&amp;amp;r=4auvy4&amp;amp;triedRedirect=true&amp;amp;utm_medium=email&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://blog.bytebytego.com/p/how-ai-agents-manage-memory-and-avoid?utm_source=post-email-title&amp;amp;publication_id=817132&amp;amp;post_id=203744632&amp;amp;utm_campaign=email-post-title&amp;amp;isFreemail=true&amp;amp;r=4auvy4&amp;amp;triedRedirect=true&amp;amp;utm_medium=email&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/kAGDU/dJMb9b325mg/ssXt3vWqT5A9kZfLhXXopK/img.jpg?width=1200&amp;amp;height=675&amp;amp;face=0_0_1200_675,https://scrap.kakaocdn.net/dn/DeAxi/dJMb9aKP9ij/9kaFghsrjVsFl4BeOF1Yjk/img.jpg?width=1600&amp;amp;height=800&amp;amp;face=0_0_1600_800,https://scrap.kakaocdn.net/dn/dhTibA/dJMb85W4xk9/9nvkvu7g4z2FzwkmBrzCO1/img.png?width=1456&amp;amp;height=1115&amp;amp;face=0_0_1456_1115');&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;How AI Agents Manage Memory and Avoid Forgetfulness&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;In this article, we will try to understand how that architecture gets built, from the constraint that forces it to exist all the way to the tradeoffs that follow.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;blog.bytebytego.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;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;도입부&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;개발 스택에 포함된 정교한 AI 에이전트라고 해도, 매번 메시지를 시작할 때마다 완전한 백지 상태에서 출발하게 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;우리가 클로드나 챗GPT와 대화할 때 느끼는 어떠한 연속성도 사실 주변 플랫폼 시스템이 모델을 대신해서 매 호출마다 적절한 컨텍스트를 다시 주입해 주도록 엔지니어링 한 결과물이다.&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: 'Noto Sans Demilight', 'Noto Sans KR';&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Statelessness(무상태성)&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;LLM을 호출하는 과정은 단순한 패턴을 따르며 시스템이 프롬프트를 보내면 모델이 답변을 반환하고 해당 상호작용은 그 자리에서 끝이난다.&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: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;그 직후 1ms 뒤에 이루어지는 다음 호출이라도 완전히 새로운 백지 상태에서 다시 시작된다. 이것이 모든 상용 LLM의 API 규약이며 트랜스포머 모델이 트래픽을 처리하는 구조적 방식을 반영한 것이다.&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-origin-width=&quot;1280&quot; data-origin-height=&quot;852&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bCNAG8/dJMcagMWGQ6/mfxzvu0ttOxYZT6JLWGwU0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bCNAG8/dJMcagMWGQ6/mfxzvu0ttOxYZT6JLWGwU0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bCNAG8/dJMcagMWGQ6/mfxzvu0ttOxYZT6JLWGwU0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbCNAG8%2FdJMcagMWGQ6%2Fmfxzvu0ttOxYZT6JLWGwU0%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;852&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;852&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;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;즉, 지능은 모델 내부에 존재하지만, 기억(Memory)는 모델을 둘러싸고 있는 외부 백엔드 시스템에 존재하는 구조이다.&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: 'Noto Sans Demilight', 'Noto Sans KR';&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Context(문맥)&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;모든 API 호출에는 컨텍스트 윈도우가 존재하며 이것은 기본적으로 모델이 답변을 생성할 때 읽을 수 있는 제한된 텍스트 조각을 의미한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;모델은 이 컨텍스트 윈도우 내부의 컨텐츠는 완벽하게 볼 수 있지만 윈도우 밖에 있는 것은 아예 다른 장치에 있는 것이나 다름없을 정도로 전혀 인지하지 못한다.&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-origin-width=&quot;1280&quot; data-origin-height=&quot;980&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bDPBZ3/dJMcage2pET/L1BGl2uFKon7b4ku0xmZA0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bDPBZ3/dJMcage2pET/L1BGl2uFKon7b4ku0xmZA0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bDPBZ3/dJMcage2pET/L1BGl2uFKon7b4ku0xmZA0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbDPBZ3%2FdJMcage2pET%2FL1BGl2uFKon7b4ku0xmZA0%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;980&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;980&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;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;메모리 문제를 해결하는 가장 뻔하고 단순한 접근 방식은 매 호출마다 전체 대화 기록을 컨텍스트 윈도우에 밀어 넣는 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;하지만 대화가 길어지면 다음과 같은 3가지 문제가 발생하기 시작한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;비용(Cost)&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;컨텍스트 윈도우 안의 모든 토큰은 호출할 때마다 금전적인 비용과 지연 시간 비용을 모두 지불해야 하므로, 대화가 선형적으로 늘어나면 금액도 똑같이 선형적으로 늘어난다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;대략 80번째 메시지에 도달할 때쯤이면 시스템은 단지 대화의 연속성을 유지하겠다는 이유 하나만으로 매 턴마다 수만 개의 토큰을 반복해서 다시 전송해야 할 수 있다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;지연 시간(Latency)&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;컨텍스트 윈도우가 커질수록 이를 처리하는 데 더 오랜 시간이 걸린다&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;짧은 프롬프트에서는 2초 만에 응답하는 모델이 윈도우를 꽉 채운 프롬프트에서는 응답하는 데 10초 또는 15초까지 걸릴 수 있다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;중간 누락(Lost-in-the-middle)&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;긴 컨텍스트 안에서는 모델의 집중력이 떨어진다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;긴 프롬프트의 중간에 위치한 정보는 처음이나 끝에 위치한 정보보다 모델이 제대로 기억해 낼 확률이 훨씬 낮아진다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이를 Lost-in-the-middle 효과라고 부른다.&lt;/span&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;807&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bpsJcq/dJMcacqdOTI/ZAW4EJWsBPxErOBtAb98sk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bpsJcq/dJMcacqdOTI/ZAW4EJWsBPxErOBtAb98sk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bpsJcq/dJMcacqdOTI/ZAW4EJWsBPxErOBtAb98sk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbpsJcq%2FdJMcacqdOTI%2FZAW4EJWsBPxErOBtAb98sk%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;807&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;807&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;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;최근 트렌드 처럼 컨텍스트 윈도우 크기 자체가 커지면 메모리 문제가 완벽히 해결될 것처럼 느낀다&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;하지만 실제로 정보를 담아두는 공간만 키웠을 뿐, 그 방 안에서 원하는 정보를 찾아내는 탐색 문제는 해결하지 못한채 그대로 남겨두는 꼴이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Hierarchy(계층)&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;컨텍스트 창(Content Window)가 맨 위에 위치하며, 그 아래로 내려갈수록 점차 속도는 느려지지만 용량이 더 크고 비용이 저렴한 저장소들이 배치된다.&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: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이는 운영체제(OS)의 메모리 구조와 매우 비슷하다.&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: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;현대의 에이전트 메모리 시스템은 운영체제가 빠른 RAM과 느린 디스크 사이에서 데이터를 페이징하는 방식에서 많은 영감을 얻었으며, 정보의 관련성이 오르고 내림에 따라 이를 상위 계층으로 승격 시키거나 하위 계층으로 강등시킨다.&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: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;전형적인 4계층 구조는 맨 위의 컨텍스트 창에서부터 시작한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;처리 속도가 매우 빠르고 용량이 제한되어 있으며 대규모로 사용할 때 토큰당 비용이 비싸다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;요약되거나 제거되지 않은 최근의 활동 기록을 보관한다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;영구적인 사실(facts), 임베딩(Embeddings), 그리고 구조화된 요약본들이 여러 세션에 걸쳐 유지된다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;감사나 향후 참조를 위해 보관하는, 거의 접근하지 않는 자료를 저장한다.&lt;/span&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;787&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tPoIl/dJMcabdEZGT/265ARBWpUIQfv9M47NVBo1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tPoIl/dJMcabdEZGT/265ARBWpUIQfv9M47NVBo1/img.png&quot; data-alt=&quot;위로 갈수록 속도는 빨라지고 메모리의 크기는 줄어든다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tPoIl/dJMcabdEZGT/265ARBWpUIQfv9M47NVBo1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtPoIl%2FdJMcabdEZGT%2F265ARBWpUIQfv9M47NVBo1%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;787&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;787&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;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;1280&quot; data-origin-height=&quot;825&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bTqgR2/dJMcah59hl2/r7GOo9jgCuCTEUKQKkRKgK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bTqgR2/dJMcah59hl2/r7GOo9jgCuCTEUKQKkRKgK/img.png&quot; data-alt=&quot;OS 시스템과 마찬가지로 Register가 가장 빠르지만 크기는 작다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bTqgR2/dJMcah59hl2/r7GOo9jgCuCTEUKQKkRKgK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbTqgR2%2FdJMcah59hl2%2Fr7GOo9jgCuCTEUKQKkRKgK%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;825&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;825&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;OS 시스템과 마찬가지로 Register가 가장 빠르지만 크기는 작다.&lt;/figcaption&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;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&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 style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&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 style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;챗GPT의 메모리 기능은 해당 개념의 단순화된 버전을 사용한다.&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 style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;저장된 사용자의 개인 정보(Facts)와 최근 대화의 요약본이 매번 새로운 프롬프트 앞부분에 추가되며 현재 진행중인 세션은 활성화된 작업 계층을 차지하게 된다.&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 style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;챗 GPT 시스템은 읽기 시점의 복잡한 검색 기술보다는, 애초에 어떤 정보를 장기 메모리로 승격시킬지 결정하는 판단 기준에 있다.&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 style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&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 style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&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;h3 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Types(종류)&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이 분야는 cognitive science 개념을 언어 모델 에이전트에 맞게 변형하여, 에이전트 메모리를 크게 4가지 기능적 범주로 정했다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Working memory&lt;/span&gt;&lt;br /&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;현재 수행 중인 작업을 위해 활성화된 컨텍스트 창에 머무르는 모든 정보를 보유한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;ex) 에이전트가 지금 당장 우리가 작성한 함수의 디버깅을 돕고 있다면, 해당 함수의 소스 코드와 최근 주고받은 메시지들이 바로 이 작업 메모리를 차지하게 된다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;그리고 이 작업이 끝나는 순간 작업 메모리는 비워진다.&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Episodic memory&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;시간 순서로 고정된, 과거의 구체적인 상호작용 기록들을 보유한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;ex) 사흘 전, 이 사용자가 신규 엔지니어 온보딩에 대해 물어보았고, 우리는 체크리스트 템플릿에 대해 논의했다와 같은 문장이 일화 메모리의 대표적인 예시이며 특정 사건을 당시 맥락과 함께 그대로 포착한다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Semantic memory&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;특정 상호작용이나 대화 맥락으로 독립적으로 존재하는 순수한 사실과 지식을 저장한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;ex) 아담은 자바스크립트보다 파이썬을 선호한다라거나 그 팀은 CI를 위해 깃허브 액션을 사용한다와 같은 진술이 의미 메모리로 기능한다. 이 기억들은 세선이 바뀌어도 살아남으며, 관련된 맥락이 생기면 어디에서나 적용된다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Procedural memory&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;절차 메모리는 일을 처리하는 과정에 학습된 방식이나 노하우를 포착한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;ex) 에이전트가 이 사용자는 업무 보고를 할 때 3개의 섹션으로 구성된 형식을 선호한다는 점을 파악했다면 그 선호도가 절차 메모리가 된다. 그래서 다음에 사용자가 업무 보고를 요청하면 에이전트는 별도의 지시가 없어도 그 형식을 자동으로 적용한다.&lt;/span&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;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이 4가지 유형은 계층 구조와 서로 독립적이다.&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: 'Noto Sans Demilight', 'Noto Sans KR';&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&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;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Retrieval(검색)&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;사용자 input에 대한 내용을 바탕으로 생성된 정보를 저장하는 것은 쉬운 문제이다. (특정 db에 기록하거나 벡터 저장소에 인덱싱 하는 작업)은 이미 잘 작성된 툴이기 때문이다.&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: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;하지만 어려운 부분은 검색하는 부분이며 대화가 한 턴씩 진행될때마다 모델이 어떤것을 떠올리고 인지해야 하는지 결정하는 것이다.&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-origin-width=&quot;1280&quot; data-origin-height=&quot;614&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dsUhwu/dJMcac4KOZu/X3tkgKAleS5tKhkVK9I0P0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dsUhwu/dJMcac4KOZu/X3tkgKAleS5tKhkVK9I0P0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dsUhwu/dJMcac4KOZu/X3tkgKAleS5tKhkVK9I0P0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdsUhwu%2FdJMcac4KOZu%2FX3tkgKAleS5tKhkVK9I0P0%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;614&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;614&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;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;사용자가 메시지를 보내면 시스템은 keyword search, semantic similarity, recency signals를 종합해서 각 메모리 계층에서 관련 있는 항목들을 검색한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;시스템은 의도적인 순서로 컨텍스트 윈도우를 조립하는데 모델의 집중도가 강력하게 높은 시작 부분과 끝 부분에 가장 중요한 자료를 배치한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;Semantic Similarity
&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;Keyword Search
&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;Recency signals
&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;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: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;검색이 왜 중요한지 알아보기 위해 2가지 상황을 가정하자&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: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;1. 과거에 나눈 모든 상호작용 데이터가 완벽하게 저장된 데이터베이스를 가지고 있지만 이와 쌍을 가진 retrieval 시스템은 엉뚱한 기록을 골라낸다.&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: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;2. 기억 저장소가 완전히 비어 있어서 현재 세션(현재 나누고 있는 대화)에서 사용자가 말해주는 정보에 의존해 작동한다.&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: 'Noto Sans Demilight', 'Noto Sans KR';&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;즉 서비스 환경에서 메모리의 오류는 대부분 retrieval 실패가 메모리 오류인척 위장하고 있는 것이다.&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Tradeoffs&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;메모리 아키텍쳐는 엔지니어링 팀이 신중하게 조율해야 하는 여러 트레이드 오프를 포함한다 그중 4가지를 한번 살펴보자&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;최신성 vs 관련성&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;메모리에서 가장 최근의 항목을 가져와야 할지, 의미론적으로 유사한것을 가져와야할지이다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;대부분 시스템은 두 가지를 모두 수행하며 두 가지 신호를 적절히 섞는 것은 현재 엔지니어링 난제이다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;최신성에 치우치면 에이전트가 과거의 유용한 컨텍스트를 잊어버리게 되고, 반대로 관련성에 치우치면 지난 정보에 집착하게 된다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;요약 vs 충실도&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;오래된 컨텍스트를 압축하면 토큰이 절약되므로 비용이 훨씬 저렴해지고 처리 속도도 빨라진다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;but 이러한 압축은 데이터 손실이 발생하는 손실 압축이며, 손실은 균일하지 않게 발생한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;요약과정에서 이름, 날짜, 구체적인 약속 같은 세부 디테일은 자연스럽게 사라지는 반면 대략적인 핵심 주제나 맥락만 살아남는다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;세부정보가 사라진 후에도 에이전트는 자신감있게 답변을 작성한다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;6개월 전에 진실이였던 사실이, 오늘날에는 오답이 될 수 있다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;ex) 2024년에 에이전트에게 나 채식주의자야라고 말했던 사용자가 2026년인 지금은 다시 육식을 할 수 있다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;메모리 시스템은 세상이 변했다는 것을 추측할 만한 아주 단순하고 무딘 휴리스틱밖에 없기에 과거의 오래된 사실을 여전히 신뢰하며 모델에 계속 제공하게 된다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이처럼 현재 질문과는 관련성이 높지만 이미 오래된 기억을 어떻게 처리할 것인지에 대한 문제는 연구 과제로 남겨졌다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;장기기억은 장기적인 공격 경로가 될 수 있다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;메모리를 유용하게 만드는 특성인 영속성이 저장된 내용이 잘못되었거나 적대적일 때는 오히려 시스템을 위험하게 만들 수 있다.&lt;/span&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;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;메모리 시스템은 에이전트가 여러 세션에 걸쳐 연속성을 유지해야 하거나, 맥락이 겹겹히 쌓이는 장기적인 과제를 수행할때 설계할 가치가 있다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>Review</category>
      <author>쿨쿨.</author>
      <guid isPermaLink="true">https://mari-laveau.tistory.com/278</guid>
      <comments>https://mari-laveau.tistory.com/278#entry278comment</comments>
      <pubDate>Sat, 4 Jul 2026 01:26:52 +0900</pubDate>
    </item>
    <item>
      <title>[Real MySQL 8.0] 1 ~ 3장 리뷰</title>
      <link>https://mari-laveau.tistory.com/277</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;MySQL 서버는 하나의 설정 파일을 사용하며 OS 환경에 따라 my.ini, my.cnf 파일을 사용한다.&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: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;해당 파일에는 MySQL에서 사용되는 시스템 변수등이 기록되어 있으며&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1782915376226&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SHOW GLOBAL VARIABLES&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 style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;436&quot; data-origin-height=&quot;154&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mgnsT/dJMcaiRqxCT/F1JKqxAe59x9FztRsWGj4k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mgnsT/dJMcaiRqxCT/F1JKqxAe59x9FztRsWGj4k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mgnsT/dJMcaiRqxCT/F1JKqxAe59x9FztRsWGj4k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmgnsT%2FdJMcaiRqxCT%2FF1JKqxAe59x9FztRsWGj4k%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;436&quot; height=&quot;154&quot; data-origin-width=&quot;436&quot; data-origin-height=&quot;154&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;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;글로별 변수, 세션 변수&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;MySQL에서는 글로별 변수와 세션 변수가 나뉘어져 있다.&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: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;글로별 변수 : MySQL 서버 전체적으로 영향을 미치는 변수이며 서버 가동 중에 유지가 되며 my.ini 파일 또는 my.cnf 파일을 통해 초기값을 세팅한다.&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: 'Noto Sans Demilight', 'Noto Sans KR';&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;글로벌 변수 확인&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1782915786514&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SHOW GLOBAL VARIABLES ''&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 style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;세션 변수 확인&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1782915758464&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SHOW VARIABLES LIKE ''&lt;/code&gt;&lt;/pre&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;변수값 변경&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;VARIABLES 키워드 앞에 Global 키워드 유무에 따라 세션 글로벌 변수, 세션 변수를 확인할 수 있으며 SET GLOBAL 명령어를 통해 글로벌 변수의 세팅값을 변경할 수 있다. 하지만 해당 명령어를 통해 글로벌 변수를 변경해도 세션 변수는 변경되지 않는다&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;(기존 글로벌 변수의 초기값을 가져와서 사용하기 때문) 변경하고 싶다면 SET SESSION 명령어를 사용해서 변경해야 한다.&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: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;추가적으로 SET GLOBAL 변수를 변경해도 서버를 재시작하면 기존 my.inf 설정파일을 읽어서 변수를 세팅하기 때문에 이전에 변경된게 유지가 되지 않는다&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;해결 방법으로는 my.inf 파일을 변경하거나&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1782916333965&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SET PERSIST&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 style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;정적 변수 vs 동적 변수&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;정적 변수 : 서버가 동작되는 동안 해당 내용을 변경할 수 없다. 변경하기 위해서 my.inf 파일을 변경하고 서버를 재시작해야한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;동적 변수 : 서버가 동작되는 시점에서 SET 명령어를 사용해서 변경할 수 있다.&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;시스템 계정, 일반 계정&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;계정에 System_User 권한이 있는 경우 시스템 계정, 없는 경우 일반계정으로 나뉜다. MySQL 8.0부터 도입되었으며 시스템 계정은 시스템 계정과 일반 계정을 관리할 수 있지만 일반계정은 시스템 계정을 제외하고 일반계정은 관리할 수 있다. 대표적으로 2가지를 할 수 있음&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: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;1. 계정 관리(계정 생성 및 삭제, 계정의 권한 부여 및 제거)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;2. 다른 세션(커넥션) 또는 그 세션에서 실행 중인 쿼리를 강제 종료&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: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;해당 기능이 도입된 이유는 DBA(데이터 베이스 관리자) 계정에서는 SYSTEM_USER 권한을 할당하고 아닌 경우 할당하지 않게 하기 위해서이다.&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;플러그인과 컴포넌트&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;플러그인 : MySQL 서버에 기능을 추가하기 위한 확장 모듈이며 서버 내부에 직접 꽂히는 방식이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1782917801662&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;INSTALL PLUGIN validate_password SONAME 'validate_password.so';&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 style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;위 명령어를 통해 금칙어 패스워드 파일을 다운받아 설정할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;대표적인 플러그인으로 InnoDB 등이 있다.&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: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;컴포넌트 : MySQL 8.0부터 새롭게 도입된 방식으로 서버 내부에 직접 접근하는 대신 서비스 인터페이스를 통해 통신하는 모듈 구조이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1782917903018&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;INSTALL COMPONENT 'file://component_validate_password';&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 style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;권한 (Privilege)&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;MySQL에서 권한도 글로벌 권한과 객체 단위의 권한으로 나뉘어 진다.&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: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;글로벌 권한 : 특정 객체에 종속되지 않은 권한이며 DB나 테이블 같은 대상이 없고 서버 전체에 적용된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1782918152169&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;GRANT SUPER ON *.* TO 'user'@'%';&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 style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;오직 ON *.*으로만 권한을 부여할 수 있다.&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: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;객체 권한 : DB, 테이블, 컬럼 등 특정 객체에 부여하는 권한이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1782918165357&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- DB 단위
GRANT SELECT ON mydb.* TO 'user'@'%';

-- 테이블 단위
GRANT SELECT, INSERT ON mydb.orders TO 'user'@'%';

-- 컬럼 단위
GRANT SELECT(id, name) ON mydb.users TO 'user'@'%';&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 style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;역할(ROLE)&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;권한의 묶음에 이름을 붙인 것으로 MySQL 8.0부터 도입되었다. 만약 계정이 100개이며 계정 마다 따로 권한을 설정해야 한다면 일일히 수작업으로 100개를 입력해서 넣어줘야할 것이다 하지만 해당 권한을 가진 역할을 생성하고 유저에게 할당하기만 하면 쉽게 끝날 것이다.&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: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이때 주의할 점은 MySQL에서 특정 권한을 가진 역할을 생성해서 유저에게 할당해도 해당 유저에 로그인한 후 역할을 활성화해야 해당 역할이 실질적으로 작동할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1782918490097&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 역할 활성화
SET ROLE '역할네임'

-- 활성화된 역할 확인
SELECT CURRENT_ROLE();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Dev Book Review/Real MySQL</category>
      <category>리마큐</category>
      <author>쿨쿨.</author>
      <guid isPermaLink="true">https://mari-laveau.tistory.com/277</guid>
      <comments>https://mari-laveau.tistory.com/277#entry277comment</comments>
      <pubDate>Thu, 2 Jul 2026 00:09:28 +0900</pubDate>
    </item>
    <item>
      <title>[LeetCode] 3020. Find the Maximum Number of Elements in Subset</title>
      <link>https://mari-laveau.tistory.com/276</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;a href=&quot;https://leetcode.com/problems/find-the-maximum-number-of-elements-in-subset/description/?envType=daily-question&amp;amp;envId=2026-06-27&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://leetcode.com/problems/find-the-maximum-number-of-elements-in-subset/description/?envType=daily-question&amp;amp;envId=2026-06-27&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1782569631181&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;Find the Maximum Number of Elements in Subset - LeetCode&quot; data-og-description=&quot;Can you solve this real interview question? Find the Maximum Number of Elements in Subset - You are given an array of positive integers nums. You need to select a subset of nums which satisfies the following condition: * You can place the selected elements&quot; data-og-host=&quot;leetcode.com&quot; data-og-source-url=&quot;https://leetcode.com/problems/find-the-maximum-number-of-elements-in-subset/description/?envType=daily-question&amp;amp;envId=2026-06-27&quot; data-og-url=&quot;https://leetcode.com/problems/find-the-maximum-number-of-elements-in-subset/description&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/b2IfaX/dJMb9iIRa5B/JgC0WzIJEASPBk5cDFkAR0/img.png?width=500&amp;amp;height=260&amp;amp;face=0_0_500_260&quot;&gt;&lt;a href=&quot;https://leetcode.com/problems/find-the-maximum-number-of-elements-in-subset/description/?envType=daily-question&amp;amp;envId=2026-06-27&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://leetcode.com/problems/find-the-maximum-number-of-elements-in-subset/description/?envType=daily-question&amp;amp;envId=2026-06-27&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/b2IfaX/dJMb9iIRa5B/JgC0WzIJEASPBk5cDFkAR0/img.png?width=500&amp;amp;height=260&amp;amp;face=0_0_500_260');&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;Find the Maximum Number of Elements in Subset - LeetCode&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Can you solve this real interview question? Find the Maximum Number of Elements in Subset - You are given an array of positive integers nums. You need to select a subset of nums which satisfies the following condition: * You can place the selected elements&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;leetcode.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;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;문제 정의&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;1. nums라는 양의 정수 배열이 주어진다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;2. 이때 부분집합을 골라서 배열했을때 팰린드롬 모양(대칭)이 되어야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;3. x, x^2, x^4 *** x^4, x^2, x 이런식으로 나와야 한다.&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;문제 접근&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;결국 양쪽 대칭이 되어야 하기 때문에 map을 사용해서 nums 라는 배열중 원소의 개수를 하나씩 다 세줘야 한다. 그 이유는 제일 높은 대칭 탑을 이루기 위해서는 각 원소가 2개 이상씩 있어야 하며 마지막 가장 높은 원소는 1개 이상이 있어야 한다.&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: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;map을 사용해서 개수를 세준 후 map을 순환하여 하나를 잡고 어디까지 올라갈 수 있는지 확인하며 최대 개수를 업데이트 해주었다.&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;작성 코드(C++)&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1782569970433&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Solution {
public:
    int maximumLength(vector&amp;lt;int&amp;gt;&amp;amp; nums) {
        map&amp;lt;int, int&amp;gt; m;

        for(auto &amp;amp;iter : nums) m[iter]++;

        int result = 1;

        for(auto &amp;amp;iter : m) {
            long long val = iter.first;
            int count = iter.second;
            if(val == 1) continue;
            int len = 0;

            while(m.count(val) &amp;amp;&amp;amp; m[val] &amp;gt;= 2) {
                len += 2;
                if(val &amp;gt; 1e9) {
                    val = -1;
                    break;
                }
                val = val * val;
            }

            len += (m.count(val)? 1 : -1);
            result = max(result, len);
        }

        if(m.count(1)) {
            int res = m[1];
            result = max(result, res % 2 == 1? res: res-1);
        }

        return result;
    }
};&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;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;작성코드(Java)&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1782575969401&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Solution {
    public int maximumLength(int[] nums) {
        Map&amp;lt;Long, Integer&amp;gt; m = new HashMap&amp;lt;&amp;gt;();
        int result = 1;

        for(int a : nums) {
            m.put((long)a, m.getOrDefault((long)a, 0) + 1);
        }

        for(long key : m.keySet()) {
            long val = key;
            if(val == 1) continue;
            int count = m.get(key);
            int len = 0;

            while(m.containsKey(val) &amp;amp;&amp;amp; m.get(val) &amp;gt;= 2) {
                len += 2;
                if(val &amp;gt;= Long.MAX_VALUE) {
                    val = -1;
                    break;
                }
                val = val * val;
            }

            result = Math.max(result, m.containsKey(val)? len+1 : len-1);
        }

        if(m.containsKey(1L)) {
            result = Math.max(result, m.get(1L) % 2 == 1? m.get(1L) : m.get(1L)-1);
        }

        return result;
    }
}&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;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;회고록(막힌 부분)&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;처음에 키포인트 대칭이기 때문에 2개 이상인것은 잘 잡아냈지만 해당 부분에서 따로 map을 2개 이상인 요소만 따로 리스트에 저장하여 어떻게 풀려고 했다 하지만 해당 부분에서 최대 길이를 구하기 위해 여러 요소들이 존재했기에 구현을 못했다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>Algorithm/Review</category>
      <author>쿨쿨.</author>
      <guid isPermaLink="true">https://mari-laveau.tistory.com/276</guid>
      <comments>https://mari-laveau.tistory.com/276#entry276comment</comments>
      <pubDate>Sun, 28 Jun 2026 01:00:56 +0900</pubDate>
    </item>
    <item>
      <title>[Algorithm] 이분매칭(Bipartite Matching)</title>
      <link>https://mari-laveau.tistory.com/275</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;N명의 사람이 M개의 일을 해야하는데 각 일에는 한사람만 할당이 가능하다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;해당 문제를 풀기 위해서 완전 탐색등을 사용할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;하지만 N과 M이 커질경우 해당 방식도 기하급수적으로 커진다.&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: 'Noto Sans Demilight', 'Noto Sans KR';&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이분 그래프&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;인접한 정점끼리 서로 다른 색으로 칠해서 모든 정점을 두 가지 색으로만 칠할 수 있는 그래프이며&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;그래프의 모든 정점이 두 그룹으로 나눠지고 서로 다른 그룹의 정점이 간선으로 연결돼 있는 그래프를 의미한다.&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-origin-width=&quot;494&quot; data-origin-height=&quot;247&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FAO0B/dJMcaglDzlQ/a7IDOoCkYTeu0CWqRmjaXk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FAO0B/dJMcaglDzlQ/a7IDOoCkYTeu0CWqRmjaXk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FAO0B/dJMcaglDzlQ/a7IDOoCkYTeu0CWqRmjaXk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFAO0B%2FdJMcaglDzlQ%2Fa7IDOoCkYTeu0CWqRmjaXk%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;494&quot; height=&quot;247&quot; data-origin-width=&quot;494&quot; data-origin-height=&quot;247&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;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이분 매칭&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1106&quot; data-origin-height=&quot;1292&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cEyyHl/dJMcacp4NlJ/XBL7Uf54FrREsaUZOMyPz1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cEyyHl/dJMcacp4NlJ/XBL7Uf54FrREsaUZOMyPz1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cEyyHl/dJMcacp4NlJ/XBL7Uf54FrREsaUZOMyPz1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcEyyHl%2FdJMcacp4NlJ%2FXBL7Uf54FrREsaUZOMyPz1%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;1106&quot; height=&quot;1292&quot; data-origin-width=&quot;1106&quot; data-origin-height=&quot;1292&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;아래와 같이 A, B, C, D, E라는 사원이 있고 1, 2, 3, 4, 5라는 총 5개의 일이 있다고 가정해보자&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: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이때 A라는 사원은 2번과 5번 일을 수행할 수 있고&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;B사원은 2, 3, 4&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;C사원은 1, 5&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;D사원은 1, 2, 5&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;E 사원은 2번 일을 할 수 있다.&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: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이때 가장 많은 일을 하기 위해서 인원 배치를 어떻게 해야할까?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;그리디하게 A 사원부터 살펴보면서 간선을 확인하며 이미 일이 점유된 경우 다음간선을 확인하며 할당해줘야 할까??&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;만약 그렇게 매칭했을경우 최대인것이 보장이 될까?&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-origin-width=&quot;1142&quot; data-origin-height=&quot;846&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bwfS4n/dJMcafG6JFB/dKKeIIKg0JLireqpfhYPrK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bwfS4n/dJMcafG6JFB/dKKeIIKg0JLireqpfhYPrK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bwfS4n/dJMcafG6JFB/dKKeIIKg0JLireqpfhYPrK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbwfS4n%2FdJMcafG6JFB%2FdKKeIIKg0JLireqpfhYPrK%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;1142&quot; height=&quot;846&quot; data-origin-width=&quot;1142&quot; data-origin-height=&quot;846&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;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;해당 그림을 보자 A사원은 3번 일에 매칭이 되었고 B사원는 1에 매칭이 되었다 이때 C사원은 3번밖에 갈 수 없는데 A 사원에 매칭되어있기에 최대 일을 할 수 있는 개수는 2개가된다.&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: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;하지만 A 사원이 1번일을 점유하면 C도 3번 일을 점유할 수 있기에 3개가 가능하다.&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 style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이를 구하기 위해서 dfs(깊이 우선 탐색)을 사용하여 만약 C가 3을 점유할때 이미 점유가 되어 있으면 점유되어 있는 사원한테 물어보는것이다 &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: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&quot;너 다른 일 점유할 수 있어?&quot; 그렇다면 A 사원은 다른 일을 찾을테고 남은 일이 1이므로 1을 점유하고 C는 3을 점유하여 최대의 일을 찾을 수 있다.&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;코드 구현&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1782200411249&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
using namespace std;
typedef pair&amp;lt;int, int&amp;gt; pii;
typedef long long ll;
#define endl &quot;\n&quot;

struct Tree {
    int left, right;
};

const int INF = 1e9;
const int MAX = 100001;
const int D = 2000000;
const int MOD = 10007;
int dx[] = {0, 0, 1, -1};
int dy[] = {1, -1, 0, 0};
int N, M;
vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; v(201);
int job[201];
bool check[201];
int result;

bool dfs(int node) {
    for(int i = 0; i &amp;lt; v[node].size(); i++) {
        int bar = v[node][i];

        if(check[bar]) continue;
        check[bar] = true;

        if(job[bar] == 0 || dfs(job[bar])) {
            job[bar] = node;
            return true;
        }
    }

    return false;
}

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);

    cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; M;

    for(int i = 1; i &amp;lt;= N; i++) {
        int a;
        cin &amp;gt;&amp;gt; a;

        for(int j = 0; j &amp;lt; a; j++) {
            int b;
            cin &amp;gt;&amp;gt; b;
            v[i].push_back(b);
        }
    }

    for(int i = 1; i &amp;lt;= N; i++) {
        memset(check, 0, sizeof(check));
        if(dfs(i)) result++;
    }

    for(int i = 1; i &amp;lt;= N; i++) {
        if(job[i] != 0) {
            cout &amp;lt;&amp;lt; job[i] &amp;lt;&amp;lt; &quot; -&amp;gt; &quot; &amp;lt;&amp;lt; i &amp;lt;&amp;lt; endl;
        }
    }
}&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 style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;자 핵심 부분만 살펴보자&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1782200510368&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; v(201);
int job[201];
bool check[201];
int result;

bool dfs(int node) {
    for(int i = 0; i &amp;lt; v[node].size(); i++) {
        int bar = v[node][i];

        if(check[bar]) continue;
        check[bar] = true;

        if(job[bar] == 0 || dfs(job[bar])) {
            job[bar] = node;
            return true;
        }
    }

    return false;
}&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 style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;먼저 v 변수는 사원과 일에 대한 관계를 나타낸 것이다 A, B, C를 1, 2, 3 사원이라고 하고 일도 1, 2, 3으로 가정했을때 인접리스트에 대한 관계로 나타낼 수 있으며 job 배열은 일에 대한 소유권이 누구인지를 나타내는 배열이며&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: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;check 배열은 다른 일을 부탁할때 해당 일을 방문했는지 체크하는 배열이다 해당 배열이 없는 경우 계속 무한으로 재귀에 빠질 수 있기에 꼭 필요하다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1782200633326&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;        if(job[bar] == 0 || dfs(job[bar])) {
            job[bar] = node;
            return true;
        }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;해당 부분에서 job[bar] == 0인 경우는 일에 점유되지 않는 경우 또는 dfs(job[bar])을 하여 이미 소유된 일인 경우 다시 dfs 탐색을 해서 다른 일을 소유할 수 있는지 확인하는 부분이다.&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: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;만약 다른 일이 소유되지 않았을 경우 job 배열에 기록을 해주고 true를 리턴하여 성공했다고 알려주며 해당 사원에 대해 모든 일을 살펴봤을때 없는 경우 false를 리턴하여 실패했다고 알려준다.&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: 'Noto Sans Demilight', 'Noto Sans KR';&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;792&quot; data-origin-height=&quot;446&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bhRx4V/dJMcai4MMN1/zgznShmERGDi8eIY8Mc9E0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bhRx4V/dJMcai4MMN1/zgznShmERGDi8eIY8Mc9E0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bhRx4V/dJMcai4MMN1/zgznShmERGDi8eIY8Mc9E0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbhRx4V%2FdJMcai4MMN1%2FzgznShmERGDi8eIY8Mc9E0%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;792&quot; height=&quot;446&quot; data-origin-width=&quot;792&quot; data-origin-height=&quot;446&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/2188&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/2188&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1782200864642&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;BOJ 서비스 종료&quot; data-og-description=&quot;BOJ 채점 서비스 준비 중 2010년 3월 19일 - 2026년 4월 28일 그동안 이용해 주셔서 정말 감사합니다. 채점 서비스와 함께 곧 다시 돌아오겠습니다.&quot; data-og-host=&quot;www.acmicpc.net&quot; data-og-source-url=&quot;https://www.acmicpc.net/problem/2188&quot; data-og-url=&quot;https://www.acmicpc.net/problem/2188&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/2188&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.acmicpc.net/problem/2188&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;BOJ 서비스 종료&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;BOJ 채점 서비스 준비 중 2010년 3월 19일 - 2026년 4월 28일 그동안 이용해 주셔서 정말 감사합니다. 채점 서비스와 함께 곧 다시 돌아오겠습니다.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.acmicpc.net&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;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;해당 알고리즘은 이번 문제와 마찬가지로 n명의 사람에게 m명의 일을 할당해야 하는 경우 또는 CS관점에서 N개의 프로세스에 M개의 메모리와 자원을 겹치지 않게 할당하는 경우 처럼 여러 관점에서 유용하게 쓰일 수 있다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>Algorithm</category>
      <category>이분매칭</category>
      <author>쿨쿨.</author>
      <guid isPermaLink="true">https://mari-laveau.tistory.com/275</guid>
      <comments>https://mari-laveau.tistory.com/275#entry275comment</comments>
      <pubDate>Tue, 23 Jun 2026 16:49:31 +0900</pubDate>
    </item>
  </channel>
</rss>