<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>어흥</title>
    <link>https://imnotabear.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Mon, 3 Aug 2026 23:54:55 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>라이언납시오</managingEditor>
    <image>
      <title>어흥</title>
      <url>https://tistory1.daumcdn.net/tistory/3754938/attach/e0950c6cd1a746ca8d9da99ac18a1774</url>
      <link>https://imnotabear.tistory.com</link>
    </image>
    <item>
      <title>[LeetCode] Construct Binary Tree from Preorder and Inorder Traversal (C++)</title>
      <link>https://imnotabear.tistory.com/650</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;문제 링크: &lt;a href=&quot;https://leetcode.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/description/?envType=study-plan-v2&amp;amp;envId=top-100-liked&quot;&gt;https://leetcode.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/description/?envType=study-plan-v2&amp;amp;envId=top-100-liked&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1695196557927&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;LeetCode - The World's Leading Online Programming Learning Platform&quot; data-og-description=&quot;Level up your coding skills and quickly land a job. This is the best place to expand your knowledge and get prepared for your next interview.&quot; data-og-host=&quot;leetcode.com&quot; data-og-source-url=&quot;https://leetcode.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/description/?envType=study-plan-v2&amp;amp;envId=top-100-liked&quot; data-og-url=&quot;https://leetcode.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/description/?envId=top-100-liked&amp;amp;envType=study-plan-v2&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/Ry0vc/hyTY7pMMIw/Aqwbmt4O4KupGsnA6nVUdK/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/construct-binary-tree-from-preorder-and-inorder-traversal/description/?envType=study-plan-v2&amp;amp;envId=top-100-liked&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://leetcode.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/description/?envType=study-plan-v2&amp;amp;envId=top-100-liked&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/Ry0vc/hyTY7pMMIw/Aqwbmt4O4KupGsnA6nVUdK/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;LeetCode - The World's Leading Online Programming Learning Platform&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Level up your coding skills and quickly land a job. This is the best place to expand your knowledge and get prepared for your next interview.&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;1. 주의할 점&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 재귀문으로 접근하며, return 조건을 알아야 한다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Inorder와 Preorder의 검사 범위를 따로 둬야 한다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 구현&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Preorder의 첫번째 항은 항상 Root를 것을 이용한다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Inorder에서 Root가 어디에 위치해 있는지 찾는다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Root를 기준으로 왼쪽 Subtree와 오른쪽 Subtree를 각각 완성한다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 분할 정복과 같은 방식으로 Subtree에서도 위와 같은 방법으로 진행한다. 단, Preroder와 Inorder의 검사 범위가 다르므로 서로 다른 변수를 받도록 한다(Preorder: pl~pr, Inorder: il~ir)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1695196743235&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Solution {
public:
    TreeNode* makeTree(vector&amp;lt;int&amp;gt;&amp;amp; preorder, vector&amp;lt;int&amp;gt;&amp;amp; inorder, int pl, int pr, int il, int ir){
        if(pl &amp;gt; pr || il &amp;gt; ir) return nullptr;
        //get rootIdx of inorder;
        int ridx = -1;
        for(int i=il;i&amp;lt;=ir;i++){
            if(inorder[i]==preorder[pl]){
                ridx = i;
                break;
            }
        }
        TreeNode* node = new TreeNode(preorder[pl]);
        int leftLen = ridx-il;
        node-&amp;gt;left = makeTree(preorder, inorder, pl+1, pl+leftLen, il, ridx-1);
        node-&amp;gt;right = makeTree(preorder, inorder, pl+leftLen+1, pr, ridx+1, ir);

        return node;
    }

    TreeNode* buildTree(vector&amp;lt;int&amp;gt;&amp;amp; preorder, vector&amp;lt;int&amp;gt;&amp;amp; inorder) {
        if(preorder.empty()) return nullptr;
        int len = preorder.size();

        return makeTree(preorder, inorder, 0, len-1, 0, len-1);
    }
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>알고리즘/LeetCode</category>
      <category>LeetCode</category>
      <category>순회</category>
      <category>트리</category>
      <author>라이언납시오</author>
      <guid isPermaLink="true">https://imnotabear.tistory.com/650</guid>
      <comments>https://imnotabear.tistory.com/650#entry650comment</comments>
      <pubDate>Wed, 20 Sep 2023 17:00:13 +0900</pubDate>
    </item>
    <item>
      <title>[LeetCode] Find the Duplicate Number (C++)</title>
      <link>https://imnotabear.tistory.com/649</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;문제 링크: &lt;a href=&quot;https://leetcode.com/problems/find-the-duplicate-number/description/?envType=study-plan-v2&amp;amp;envId=top-100-liked&quot;&gt;https://leetcode.com/problems/find-the-duplicate-number/description/?envType=study-plan-v2&amp;amp;envId=top-100-liked&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1693899831666&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 Duplicate Number - LeetCode&quot; data-og-description=&quot;Can you solve this real interview question? Find the Duplicate Number - Given an array of integers nums containing&amp;nbsp;n + 1 integers where each integer is in the range [1, n] inclusive. There is only one repeated number in nums, return this&amp;nbsp;repeated&amp;nbsp;number&quot; data-og-host=&quot;leetcode.com&quot; data-og-source-url=&quot;https://leetcode.com/problems/find-the-duplicate-number/description/?envType=study-plan-v2&amp;amp;envId=top-100-liked&quot; data-og-url=&quot;https://leetcode.com/problems/find-the-duplicate-number/description&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cuOU9H/hyTPzAV9mb/y1e1MfVR2AkKjjqWNWc5k0/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-duplicate-number/description/?envType=study-plan-v2&amp;amp;envId=top-100-liked&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://leetcode.com/problems/find-the-duplicate-number/description/?envType=study-plan-v2&amp;amp;envId=top-100-liked&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cuOU9H/hyTPzAV9mb/y1e1MfVR2AkKjjqWNWc5k0/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 Duplicate Number - 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 Duplicate Number - Given an array of integers nums containing&amp;nbsp;n + 1 integers where each integer is in the range [1, n] inclusive. There is only one repeated number in nums, return this&amp;nbsp;repeated&amp;nbsp;number&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;주의할 점&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 이 문제는 Set 또는 정렬을 사용해서 풀지 않도록 한다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 연결 리스트에서 주기가 시작하는 노드 찾는 방법으로 해결한다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구현&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 1칸씩 이동하는 Turtle과 2칸씩 이동하는 Hare(산토끼) 포인터를 통해 순환하는 링크드 리스트에서 만나는 지점을 찾는다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 배열 처음을 가리키는 포인터 Root를 새로 생성한다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Root와 Turtle을 1칸씩 이동해서 만나는 지점이 주기의 시작점이다&lt;/p&gt;
&lt;pre id=&quot;code_1693900051307&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 findDuplicate(vector&amp;lt;int&amp;gt;&amp;amp; nums) {
        int hare = nums[0];
        int turtle = nums[0];

        while (true) {
            turtle = nums[turtle];
            hare = nums[nums[hare]];
            if (turtle == hare) break;
        }
        
        int root = nums[0];
        while(root != turtle){
            root = nums[root];
            turtle = nums[turtle];
        }
        return root;
    }
};&lt;/code&gt;&lt;/pre&gt;</description>
      <category>알고리즘/LeetCode</category>
      <category>LeetCode</category>
      <category>LinkedList</category>
      <category>two pointer</category>
      <author>라이언납시오</author>
      <guid isPermaLink="true">https://imnotabear.tistory.com/649</guid>
      <comments>https://imnotabear.tistory.com/649#entry649comment</comments>
      <pubDate>Tue, 5 Sep 2023 16:47:51 +0900</pubDate>
    </item>
    <item>
      <title>[프로그래머스] 연속 부분 수열 합의 개수 (C++)</title>
      <link>https://imnotabear.tistory.com/648</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;문제 링크: &lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/131701&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://school.programmers.co.kr/learn/courses/30/lessons/131701&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1693121452134&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;프로그래머스&quot; data-og-description=&quot;코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.&quot; data-og-host=&quot;programmers.co.kr&quot; data-og-source-url=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/131701&quot; data-og-url=&quot;https://programmers.co.kr/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/9AO2J/hyTMhsjott/qiQlVVgRTvWgeKa8MQWyU0/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/bpvtiE/hyTMafFavA/BO2KWwXE9GrNdslh7R4IsK/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/131701&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/131701&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/9AO2J/hyTMhsjott/qiQlVVgRTvWgeKa8MQWyU0/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/bpvtiE/hyTMafFavA/BO2KWwXE9GrNdslh7R4IsK/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630');&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;프로그래머스&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;programmers.co.kr&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 주의할 점&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 어떤 방식으로 1~배열의 길이 만큼의 원소를 더해서 중복을 제거할지 생각한다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 구현&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Set을 통해 중복을 제거하고 Set에는 연속된 부분 수열의 합을 넣는다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- N &amp;lt;= 1000이므로 N^2을 통해 진행해도 1초내에 들어온다고 판단&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Mod 연산을 통해 원형 수열에서 원소를 뽑아오는것 처럼 구현&lt;/p&gt;
&lt;pre id=&quot;code_1693121442434&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;string&amp;gt;
#include &amp;lt;vector&amp;gt;
#include &amp;lt;set&amp;gt;
#include &amp;lt;math.h&amp;gt;
#include &amp;lt;iostream&amp;gt;
using namespace std;

int solution(vector&amp;lt;int&amp;gt; elements) {
    set&amp;lt;int&amp;gt; s;
    int len = elements.size();
    
    for(int i=0;i&amp;lt;len;i++){
        int sum = 0;
        for(int j=i;j&amp;lt;i+len;j++){
            sum+=elements[j%len];
            s.insert(sum);
        }
    }
    
    return s.size();
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>알고리즘/프로그래머스</category>
      <category>MOD</category>
      <category>Set</category>
      <category>연속 부분 수열의 합의 개수</category>
      <category>프로그래머스</category>
      <author>라이언납시오</author>
      <guid isPermaLink="true">https://imnotabear.tistory.com/648</guid>
      <comments>https://imnotabear.tistory.com/648#entry648comment</comments>
      <pubDate>Sun, 27 Aug 2023 16:33:35 +0900</pubDate>
    </item>
    <item>
      <title>[프로그래머스] 부대복귀 (C++)</title>
      <link>https://imnotabear.tistory.com/647</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;문제 링크:&lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/132266&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://school.programmers.co.kr/learn/courses/30/lessons/132266&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1693026948112&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;프로그래머스&quot; data-og-description=&quot;코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.&quot; data-og-host=&quot;programmers.co.kr&quot; data-og-source-url=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/132266&quot; data-og-url=&quot;https://programmers.co.kr/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/dmAoTQ/hyTIRaNaHn/ATwxPjOkkc72vvKqZkG2i0/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/t3XmO/hyTIQJHEwc/3Cu8rdvY1NNEaPkUkixyCK/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/132266&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/132266&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/dmAoTQ/hyTIRaNaHn/ATwxPjOkkc72vvKqZkG2i0/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/t3XmO/hyTIQJHEwc/3Cu8rdvY1NNEaPkUkixyCK/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630');&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;프로그래머스&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;programmers.co.kr&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 주의할 점&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 한 지점부터 다른 지점까지의 최단 거리를 구하는 알고리즘은 대표적으로 &lt;span style=&quot;color: #006dd7;&quot;&gt;다익스트라, 플로이드 와샬, 벨만포드&lt;/span&gt;가 존재&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때 N은 최대 10만이다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;플로이드 와샬은 O(N^3) &amp;rarr; TLE 발생 확률 매우 높아보인다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;벨만포드는 간선에 음수가 있을 때 사용하는 다익스트라의 심화버전이지만 현재는 모든 간선에 1이라는 양수값만 있으므로 Pass&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국, 다익스트라 채택&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Source &amp;rarr; Destination까지 갈 때, 이미 구한 최단 거리는 이용해도 되지 않을까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 구현&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 다익스트라 알고리즘을 통해 각 Source에서 목적지 까지의 거리를 구한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 단, 위에 2번째로 적은 주의할 점과 같이 이미 구한것을 또 구할 필요가 있을까? 발상의 전환을 해보자&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 결국 Source에서 목적지까지 모두 가야한다(못가는 것 제외). 그렇다면 반대로, 목적지에서 각 Source까지 가면 다익스트라 알고리즘 1번에 끝나겠는데?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 각 Source &amp;rarr; 목적지 N번 : N번의 다익스트라. 목적지 &amp;rarr; 각 Source : 1번의 다익스트라&lt;/p&gt;
&lt;pre id=&quot;code_1693026939233&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#define MAXI 987654321
#include &amp;lt;string&amp;gt;
#include &amp;lt;vector&amp;gt;
#include &amp;lt;algorithm&amp;gt;
#include &amp;lt;queue&amp;gt;
using namespace std;
struct info{
    int idx, val;		// Node, Node까지 걸리는 거리
};

vector&amp;lt;int&amp;gt; solution(int n, vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; roads, vector&amp;lt;int&amp;gt; sources, int destination) {
    vector&amp;lt;int&amp;gt; answer;
    vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; node(n+1);   //간선 정보
    vector&amp;lt;int&amp;gt; dist(n+1);           //dest부터 각 source 까지의 거리
    //사전 준비
    for(int i=0;i&amp;lt;roads.size();i++){
        int a = roads[i][0];
        int b = roads[i][1];
        node[a].push_back(b);
        node[b].push_back(a);
    }
    
    for(int i=1;i&amp;lt;=n;i++)
        dist[i] = MAXI;
    
    // 다익스트라 시작
    queue&amp;lt;info&amp;gt; q;
    q.push({destination, 0});
    dist[destination] = 0;
    
    while(!q.empty()){
        info ii = q.front();
        q.pop();
        int cidx = ii.idx;
        int cv = ii.val;
        
        for(int i=0;i&amp;lt;node[cidx].size();i++){
            int next = node[cidx][i];
            if(dist[next] &amp;gt; cv + 1){
                dist[next] = cv + 1;
                q.push({next, cv+1});
            }
        }
    }
    // 다익스트라 끝
    
    for(int i=0;i&amp;lt;sources.size();i++){
        int val = dist[sources[i]] == MAXI ? -1 : dist[sources[i]];
        answer.push_back(val);
    }
    return answer;
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>알고리즘/프로그래머스</category>
      <category>Dijkstra</category>
      <category>다익스트라</category>
      <category>최단거리</category>
      <category>프로그래머스</category>
      <author>라이언납시오</author>
      <guid isPermaLink="true">https://imnotabear.tistory.com/647</guid>
      <comments>https://imnotabear.tistory.com/647#entry647comment</comments>
      <pubDate>Sat, 26 Aug 2023 14:23:29 +0900</pubDate>
    </item>
    <item>
      <title>[프로그래머스] 올바른 괄호 (C++)</title>
      <link>https://imnotabear.tistory.com/646</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;문제 링크: &lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/12909&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://school.programmers.co.kr/learn/courses/30/lessons/12909&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1692930250025&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;프로그래머스&quot; data-og-description=&quot;코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.&quot; data-og-host=&quot;programmers.co.kr&quot; data-og-source-url=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/12909&quot; data-og-url=&quot;https://programmers.co.kr/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cJ9KlG/hyTICLdX9G/8n4YO31veHMd0GiuMlYDIk/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/ctlPcb/hyTIQJsD4a/EBqW2Ofa2YpAnMTbJczHx1/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/12909&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/12909&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cJ9KlG/hyTICLdX9G/8n4YO31veHMd0GiuMlYDIk/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/ctlPcb/hyTIQJsD4a/EBqW2Ofa2YpAnMTbJczHx1/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630');&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;프로그래머스&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;programmers.co.kr&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;1. 주의할 점&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;nbsp; 스택을 이용해서 해결한다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- &quot;(((&quot;와 같은 문자열을 처리할 수 있는 방법을 찾는다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 구현&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 스택을 사용하며, 현재 문자가 '('가라면 스택에 추가한다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 현재 문자가 ')'라면 2가지 경우로 나눈다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 첫째, 스택이 비어있다면 false를 반환한다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 둘째, 스택이 비어있지 않다면 스택의 원소 1개를 pop 한다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 문자열 전체를 조회했다면 이제 스택이 비어있는지 확인해서 괄호가 바르게 짝지었는지 확인한다&lt;/p&gt;
&lt;pre id=&quot;code_1692930241236&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;string&amp;gt;
#include &amp;lt;iostream&amp;gt;
#include &amp;lt;stack&amp;gt;
using namespace std;

bool solution(string str)
{
    stack&amp;lt;char&amp;gt; s;
    
    for(int i=0;i&amp;lt;str.size();i++){
        char c = str[i];
        if(c == '(') s.push(c);
        // ')'
        else{
            if(s.empty()) return false;
            s.pop();
        }
    }
    
    return !s.empty() ? false : true;
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>알고리즘/프로그래머스</category>
      <category>괄호</category>
      <category>문자열</category>
      <category>스택</category>
      <category>프로그래머스</category>
      <author>라이언납시오</author>
      <guid isPermaLink="true">https://imnotabear.tistory.com/646</guid>
      <comments>https://imnotabear.tistory.com/646#entry646comment</comments>
      <pubDate>Fri, 25 Aug 2023 11:26:57 +0900</pubDate>
    </item>
    <item>
      <title>[대규모 시스템 설계] 6. 키-값 저장소 설계 - 3</title>
      <link>https://imnotabear.tistory.com/644</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;장애 처리&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 장애 감지와 장애 해소 전략을 살펴보자&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;장애 감지&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;분산 시스템에선 한 대 서버가 &quot;서버 A 다운&quot;이라고 말해도 서버 A를 장애처리 하지 않는다. 보통 2 대 이상의 서버가 같이 서버 A의 장애를 보고해야 처리한다. 노드간 멀티캐스팅 채널을 구축하는것이 서버 장애를 감지하는 가장 쉬운 방법이지만 서버가 많을때는 비효율적이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-08-17 오후 2.46.31.png&quot; data-origin-width=&quot;1036&quot; data-origin-height=&quot;964&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bA3eCg/btsrsRhYxIM/U4ubAWkXnCPjLR9eAXdTE1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bA3eCg/btsrsRhYxIM/U4ubAWkXnCPjLR9eAXdTE1/img.png&quot; data-alt=&quot;멀티캐스팅 채널 구축&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bA3eCg/btsrsRhYxIM/U4ubAWkXnCPjLR9eAXdTE1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbA3eCg%2FbtsrsRhYxIM%2FU4ubAWkXnCPjLR9eAXdTE1%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;456&quot; height=&quot;424&quot; data-filename=&quot;스크린샷 2023-08-17 오후 2.46.31.png&quot; data-origin-width=&quot;1036&quot; data-origin-height=&quot;964&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;가십 프로토콜(Gossip Protocol) 같은 분산형 장애 감지를 채택하는 것이 나으며 동작원리는 다음과 같다&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-08-17 오후 2.49.24.png&quot; data-origin-width=&quot;1568&quot; data-origin-height=&quot;800&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mVNoQ/btsrgQrBd1y/tpFNWEp2HLo0VIfSwJpTrk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mVNoQ/btsrgQrBd1y/tpFNWEp2HLo0VIfSwJpTrk/img.png&quot; data-alt=&quot;Gossip Protocol&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mVNoQ/btsrgQrBd1y/tpFNWEp2HLo0VIfSwJpTrk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmVNoQ%2FbtsrgQrBd1y%2FtpFNWEp2HLo0VIfSwJpTrk%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;1568&quot; height=&quot;800&quot; data-filename=&quot;스크린샷 2023-08-17 오후 2.49.24.png&quot; data-origin-width=&quot;1568&quot; data-origin-height=&quot;800&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Gossip Protocol&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 각 노드는 멤버십 목록을 유지. 멤버십 목록은 멤버ID와 그 박동 카운터 쌍의 목록&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 각 노드는 주기적으로 자신의 박동 카운터를 증가&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 각 노드는 무작위로 선정된 노드들에게 주기적으로 자기 박동 카운터 목록을 보냄&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 박동 카운터 목록을 받은 노드는 멤버십 목록을 최신 값으로 갱신&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 어떤 멤버의 박동 카운터 값이 일정 시간 동안 갱신되지 않으면 해당 멤버는 장애 상태인것으로 간주&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 사진에서 S0는 S2의 장애를 감지하고 S2 노드를 포함하는 박동 카운터 목록을 무작위로 선택된 다른 노드들에게 전달한다. 그리고 노드 S2의 박동 카운터가 오랫동안 증가되지 않음을 발견한 모든 노드는 해당 노드를 장애 노드로 표시&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;일시적 장애 처리&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가십 프로토콜로 장애를 감지한 시스템은 가용성을 보장하기 위해 조치를 취해야 한다. 엄격한 종족수(strict quorum) 접근법은 데이터 일관성을 지키기 위해 읽기와 쓰기 연산을 금지해야 하기 때문에 &lt;span style=&quot;color: #006dd7;&quot;&gt;느슨한 정족수(sloppy quorum) 접근법&lt;/span&gt;을 취한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 접근법은 조건을 완화하여 가용성을 높인다. 정족수 요구사항을 강제하는 대신, &lt;span style=&quot;color: #006dd7;&quot;&gt;쓰기 연산을 수행항 W개의 건강한 서버&lt;/span&gt;와 &lt;span style=&quot;color: #006dd7;&quot;&gt;읽기 연산을 수행할 R개의 건상한 서버&lt;/span&gt;를 해시 링에서 선택. 이때 장애 상태인 서버는 무시.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;네트워크나 서버 문제로 장애 상태인 서버로 가는 요청은 다른 서버가 잠시 처리 + 그동안 발생한 변경사항은 해당 서버가 복구됐을 때 일괄 반영하여 전달 &amp;rarr; 데이터 일관성 보존&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 위해 임시로 쓰기 연산을 처리한 서버에는 그에 관한 단서를 남기는데 이런 방식을 단서 후 임시 위탁 기법(hinted handoff)이라고 부른다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;영구 장애 처리&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;영구적인 노드의 장애 상태는 반-엔트로피(anti-entropy) 프로토콜을 구현하여 사본들을 동기화한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반 엔트로피 프로토콜은 사본들을 비교하여 최신 버전으로 갱신하는 과정을 포함. 사본 간 일관성이 망가지는 상태를 탐지하고 전송 데이터의 양을 줄이기 위해 머클(Merkle) 트리를 사용. 머클 트리는 각 노드에 그 자식 노드들에 보관된 값의 해시를 레이블로 붙여두는 트리. 해시 트리를 사용하면 대규모 자료 구조의 내용을 효과적이면서 보안상 안전한 방법으로 검증 가능.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-08-17 오후 3.20.33.png&quot; data-origin-width=&quot;1498&quot; data-origin-height=&quot;860&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bUZnys/btsroKKUmcg/AIX5SZrrXLWm7Taz3QrltK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bUZnys/btsroKKUmcg/AIX5SZrrXLWm7Taz3QrltK/img.png&quot; data-alt=&quot;색칠된 부분: 데이터가 망가져서 일관성이 보장되지 않는 해시값&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bUZnys/btsroKKUmcg/AIX5SZrrXLWm7Taz3QrltK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbUZnys%2FbtsroKKUmcg%2FAIX5SZrrXLWm7Taz3QrltK%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;726&quot; height=&quot;417&quot; data-filename=&quot;스크린샷 2023-08-17 오후 3.20.33.png&quot; data-origin-width=&quot;1498&quot; data-origin-height=&quot;860&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;머클 트리의 비교는 루트 노드의 해시값부터 시작해서 자식 노드 해시값을 비교해서 다른 해시값을 가진 버킷을 찾아서 동기화한다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터 센터의 장애는 정전, 네트워크 장애, 자연재해 등 다양한 이유로 발생하는데 이를 대응하기 위해선 데이터를 여러 데이터 센터에 다중화 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;시스템 아키텍처 다이어그램&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-08-17 오후 3.25.54.png&quot; data-origin-width=&quot;1474&quot; data-origin-height=&quot;918&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ACHBi/btsrr1yjvSg/zpiDxV2oDLfghQFg0Mx5k0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ACHBi/btsrr1yjvSg/zpiDxV2oDLfghQFg0Mx5k0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ACHBi/btsrr1yjvSg/zpiDxV2oDLfghQFg0Mx5k0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FACHBi%2Fbtsrr1yjvSg%2FzpiDxV2oDLfghQFg0Mx5k0%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;1474&quot; height=&quot;918&quot; data-filename=&quot;스크린샷 2023-08-17 오후 3.25.54.png&quot; data-origin-width=&quot;1474&quot; data-origin-height=&quot;918&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아키텍처의 주된 기능은 다음과 같다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 클라이언트는 키-값 저장소가 제공하는 2가지 단순한 API, get(k), put(k,v)와 통신&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 중재자는 클라에게 키-값 저장소에 대한 프락시 역할을 하는 노드&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 노드는 안정 해시의 해시 링 위에 분포&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 노드를 자동으로 추가 또는 삭제할 수 있도록, 시스템은 완전히 분산&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 데이터는 여러 노드에 다중화된다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 모든 노드가 같은 책임을 진다 &amp;rarr; SPOF(Singe Poing Of Failure)는 존재X&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;완전히 분산된 설계를 채택했으므로 모든 노드는 아래의 기능을 가져야 한다&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-08-17 오후 3.27.47.png&quot; data-origin-width=&quot;1076&quot; data-origin-height=&quot;1010&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mUenY/btsrsRh2mho/KCiKDFkopNz6lfFG83oVI0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mUenY/btsrsRh2mho/KCiKDFkopNz6lfFG83oVI0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mUenY/btsrsRh2mho/KCiKDFkopNz6lfFG83oVI0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmUenY%2FbtsrsRh2mho%2FKCiKDFkopNz6lfFG83oVI0%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;429&quot; height=&quot;403&quot; data-filename=&quot;스크린샷 2023-08-17 오후 3.27.47.png&quot; data-origin-width=&quot;1076&quot; data-origin-height=&quot;1010&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;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-08-17 오후 3.30.27.png&quot; data-origin-width=&quot;1524&quot; data-origin-height=&quot;902&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kJHWL/btsrkO7UxHq/IkdPge9CLR91s5TKKlKfBK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kJHWL/btsrkO7UxHq/IkdPge9CLR91s5TKKlKfBK/img.png&quot; data-alt=&quot;쓰기 요청이 특정 노드에 전달 될 때, 카산드라(Cassandra) 사례&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kJHWL/btsrkO7UxHq/IkdPge9CLR91s5TKKlKfBK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkJHWL%2FbtsrkO7UxHq%2FIkdPge9CLR91s5TKKlKfBK%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;566&quot; height=&quot;335&quot; data-filename=&quot;스크린샷 2023-08-17 오후 3.30.27.png&quot; data-origin-width=&quot;1524&quot; data-origin-height=&quot;902&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;쓰기 요청이 특정 노드에 전달 될 때, 카산드라(Cassandra) 사례&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 쓰기 요청이 커밋 로그 파일에 기록된다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 데이터가 메모리 캐시에 기록된다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 메모리 캐시가 가득찼거나 사전에 정의된 임계치에 도달하면 데이터는 디스크에 있는 SSTable에 기록된다. SSTable(Sorted-String Table)은 &amp;lt;키,값&amp;gt;의 순서쌍을 정렬된 리스트 형태로 관리하는 테이블&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;읽기 경로&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-08-17 오후 3.34.28.png&quot; data-origin-width=&quot;1578&quot; data-origin-height=&quot;790&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bqPqso/btsrtkqT7Lg/a6ZUOMeKKffKDgMoDshzWk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bqPqso/btsrtkqT7Lg/a6ZUOMeKKffKDgMoDshzWk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bqPqso/btsrtkqT7Lg/a6ZUOMeKKffKDgMoDshzWk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbqPqso%2FbtsrtkqT7Lg%2Fa6ZUOMeKKffKDgMoDshzWk%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;623&quot; height=&quot;312&quot; data-filename=&quot;스크린샷 2023-08-17 오후 3.34.28.png&quot; data-origin-width=&quot;1578&quot; data-origin-height=&quot;790&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 데이터가 메모리 캐시에 있는지 검사. 없으면 2번으로&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 데이터가 메모리에 없으므로 블룸 필터(어느 SSTable에 찾는 키가 있는지 알아낼 효율적인 방법)를 검사&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 블룸 필터를 통해 어떤 SSTable에 키가 보관되어 있는지 확인&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. SSTable에서 데이터를 가져온다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5. 해당 데이터를 클라에게 반환한다&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; data-ke-style=&quot;style13&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 16.6667%;&quot;&gt;목표/문제&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;기술&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 16.6667%;&quot;&gt;대규모 데이터 저장&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;안정 해시를 사용해 서버들에 부하 분산&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 16.6667%;&quot;&gt;읽기 연산에 대한 높은 가용성 보장&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;데이터를 여러 데이터센터에 다중화&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 16.6667%;&quot;&gt;쓰기 연산에 대한 높은 가용성 보장&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;버저닝 및 벡터 시계를 사용한 충돌 해소&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 16.6667%;&quot;&gt;데이터 파티션&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;안정 해시&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 16.6667%;&quot;&gt;점진적 규모 확장성&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;안정 해시&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 16.6667%;&quot;&gt;다양성&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;안정 해시&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 16.6667%;&quot;&gt;조절 가능한 데이터 일관성&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;정족수 합의&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 16.6667%;&quot;&gt;일시적 장애 처리&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;느슨한 정족수 프로토콜과 단서 후 임시 위탁&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 16.6667%;&quot;&gt;영구적 장애 처리&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;머클 트리&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 16.6667%;&quot;&gt;데이터 센터 장애 대응&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&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;/p&gt;</description>
      <category>개발/대규모 시스템 설계</category>
      <category>대규모 시스템 설계</category>
      <category>백엔드</category>
      <author>라이언납시오</author>
      <guid isPermaLink="true">https://imnotabear.tistory.com/644</guid>
      <comments>https://imnotabear.tistory.com/644#entry644comment</comments>
      <pubDate>Thu, 17 Aug 2023 15:40:41 +0900</pubDate>
    </item>
    <item>
      <title>[대규모 시스템 설계] 6. 키-값 저장소 설계 - 2</title>
      <link>https://imnotabear.tistory.com/643</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;시스템 컴포넌트&lt;/h3&gt;
&lt;pre id=&quot;code_1692171925467&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;- 데이터 파티션
- 데이터 다중화
- 일관성
- 일관성 불일치 해소
- 장애 처리
- 시스템 아키텍처 다이어그램
- 쓰기 경로
- 읽기 경로&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;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터를 작은 파티션들로 분할한 다음 여러 대 서버에 저장한다. 데이터를 파티션 단위로 나눌 땐 다음 2가지를 고려한다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 데이터를 여러 서버에 고르게 분산할 수 있는가&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 노드가 추가되거나 삭제될 때 데이터의 이동을 최소화할 수 있는가&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5장에서 다룬 안정 해시를 통해 이런 문제를 해결할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 서버를 해시링에 배치한다. 어떤 키-값 쌍을 어떤 서버에 저장할지 결정하려면 우선 해당 키를 같은 링 위에 배치하고 시계 방향으로 순회하다 만나는 첫 번째 서버에 저장한다. 안정 해시를 사용해서 데이터를 파티션하면 다음과 같은 장점이 있다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 규모 확장 자동화: 시스템 부하에 따라 서버가 자동적으로 추가되거나 삭제되도록 만든다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 다양성: 각 서버의 용량에 맞게 가상 노드의 수를 조정할 수 있다. 고성능 서버는 더 많은 가상 노드를 갖도록 설정한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;데이터 다중화&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;높은 가용성과 안정성을 확보하기 위해선 데이터를&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;N개 서버에 비동기적&lt;/span&gt;으로 다중화한다(N은 튜닝 가능한 값). N개 서버를 선정하는 방법은 특정 키를 해시 링 위에 배치한 후, 그 지점으로부터 시계 방향으로 링을 순회하면서 만나는 첫 N개 서버에 데이터 사본을 보관한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-08-16 오후 4.53.29.png&quot; data-origin-width=&quot;1030&quot; data-origin-height=&quot;966&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/UwkOj/btsrh3XIBqr/1S2KgfRYtpccHoO0s1I111/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/UwkOj/btsrh3XIBqr/1S2KgfRYtpccHoO0s1I111/img.png&quot; data-alt=&quot;데이터 다중화 방법&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/UwkOj/btsrh3XIBqr/1S2KgfRYtpccHoO0s1I111/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FUwkOj%2Fbtsrh3XIBqr%2F1S2KgfRYtpccHoO0s1I111%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;599&quot; height=&quot;562&quot; data-filename=&quot;스크린샷 2023-08-16 오후 4.53.29.png&quot; data-origin-width=&quot;1030&quot; data-origin-height=&quot;966&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;이때 주의사항으론 &lt;span style=&quot;color: #ee2323;&quot;&gt;실제 물리 서버의 개수가 N보다 작은 경우도 존재할 수 있는데, 같은 물리 서버를 중복 선택하지 않도록 해야 한다&lt;/span&gt;. 안정성을 담보하기 위해 데이터의 사본은 다른 센터의 서버에 보관하고, 센터들은 고속 네트워크로 연결한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;데이터 일관성&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러 노드에 다중화된 데이터는 적절히 동기화가 되어야 하며 이때 정족수 합의(Quorom Consensus) 프로토콜을 사용하면 읽기/쓰기 연산 모두에 일관성을 보장할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1692172615089&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;N: 사본 개수
W: 쓰기 연산에 대한 정족수.
쓰기 연산이 성공한 것으로 간주되려면 적어도 W개의 서버로부터 쓰기 연산이 성공했다는 응답을 받아야 한다
R: 읽기 연산에 대한 정족수.
읽기 연산이 성공한 것으로 간주되려면 적어도 W개의 서버로부터 읽기 연산이 성공했다는 응답을 받아야 한다&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-08-16 오후 4.58.04.png&quot; data-origin-width=&quot;792&quot; data-origin-height=&quot;834&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dqU0Fj/btsrf5BX7cZ/89mExI77RgEWCGJxZAska0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dqU0Fj/btsrf5BX7cZ/89mExI77RgEWCGJxZAska0/img.png&quot; data-alt=&quot;N: 3인 경우에 대한 정족수 합의 프로토콜 예시&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dqU0Fj/btsrf5BX7cZ/89mExI77RgEWCGJxZAska0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdqU0Fj%2Fbtsrf5BX7cZ%2F89mExI77RgEWCGJxZAska0%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;506&quot; height=&quot;533&quot; data-filename=&quot;스크린샷 2023-08-16 오후 4.58.04.png&quot; data-origin-width=&quot;792&quot; data-origin-height=&quot;834&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;N: 3인 경우에 대한 정족수 합의 프로토콜 예시&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;W:1 &amp;rarr; 데이터가 1대 서버에만 기록된다(X)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 쓰기 연산이 성공했다고 판단하기 위해 중재자는 최소 한대의 서버로부터 ACK를 받아야 한다(O)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; Ex) 서버 1로부터 성공했다는 ACK를 받았다면, 서버 2와 3의 결과를 기다릴 필요 없다&lt;/p&gt;
&lt;pre id=&quot;code_1692172917344&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;중재자란?
클라이언트와 노드 사이에서 Proxy 역할을 한다&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;W,R,N의 값을 정하는 것은 응답 지연과 데이터 일관성 사이의 타협점을 찾는 전형적인 과정&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;W + R &amp;gt; N인 경우, 일관성을 보증할 최신 데이터를 가진 노드가 최소 하나는 겹치기 때문에 강한 일관성이 보장된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇다면 적절한 구성은? 요구되는 일관성 수준에 따라 아래중 하나로 설정하면 된다&lt;/p&gt;
&lt;pre id=&quot;code_1692248918811&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;1. R = 1, W = N: 빠른 읽기 연산에 최적화된 시스템
2. W = 1, R = N: 빠른 쓰기 연산에 최적화된 시스템
3. W + R &amp;gt; N: 강한 일관성이 보장됨(Ex. N = 3, W = R = 2)
4. W + R &amp;lt;= N: 강한 일관성이 보장되지 않음&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;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일관성 모델은 데이터 일관성의 수준을 결정하며 종류가 다양하다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 강한 일관성: 모든 읽기 연산은 가장 최근에 갱신된 결과를 반환한다. 즉, 클라는 절대로 낡은 데이터를 보지 못한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 약한 일관성: 읽기 연산은 가장 최근에 갱신된 결과를 반환하지 못할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 결과적 일관성: 약한 일관성의 한 형태로, 갱신 결과가 결국에는 모든 사본에 반영된다(동기화)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;강한 일관성 달성 방법: 모든 사본에 현재 쓰기 연산의 결과가 반영될 때까지 해당 데이터에 대한 R/W 금지. 하지만 새로운 요청의 처리가 중단되기 때문에 고가용성 시스템에는 적합하지 않다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다이나모나 카산드라는 결과적 일관성 모델을 사용한다. 이 경우, 쓰기 연산이 병렬적으로 발생하면 시스템에 저장된 값의 일관성이 깨질 수 있는데 이는 클라가 해결해야 한다. 클라에서 버전 정보를 활용해 일관성이 깨진 데이터를 읽지 않도록 해야 한다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;비 일관성 해소 기법: 데이터 버저닝&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터를 다중화하면 가용성은 높아지지만 사본 간 일관성이 깨질 가능성은 높아진다. 버저닝과 벡터 시계는 이 문제를 해결하기 위해 등장한 기술이다. 버저닝은 데이터를 변경할 때마다 해당 데이터의 새로운 버전을 만든다. 따라서 각 버전의 데이터는 변경 불가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;벡터 시계는 [서버, 버전]의 순서쌍을 데이터에 매단것이다. D([S1,v1],[S2,v2],...,[Sn, vn])과 같이 표현한다(D: 데이터, vi: 버전 카운터, Si: 서버 번호).&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만일 데이터 D를 서버 S1에 기록하면, 시스템은 아래 작업 가운데 하나를 수행한다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- [S1,vi]가 있으면 vi+1을 한다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 없다면 새 항목 [S1,1]을 만든다&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-08-17 오후 2.23.23.png&quot; data-origin-width=&quot;846&quot; data-origin-height=&quot;1652&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dpCYNd/btsrv8p2SmC/GxOaQ4OIvLLkETFrpMijg1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dpCYNd/btsrv8p2SmC/GxOaQ4OIvLLkETFrpMijg1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dpCYNd/btsrv8p2SmC/GxOaQ4OIvLLkETFrpMijg1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdpCYNd%2Fbtsrv8p2SmC%2FGxOaQ4OIvLLkETFrpMijg1%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;569&quot; height=&quot;1111&quot; data-filename=&quot;스크린샷 2023-08-17 오후 2.23.23.png&quot; data-origin-width=&quot;846&quot; data-origin-height=&quot;1652&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 클라가 데이터 D1을 시스템에 기록하며 이 쓰기 연산을 처리한 서버는 S1이다 &amp;rarr; D1([S1,1])&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 다른 클라가 데이터 D1을 읽어서 D2로 업데이트하고 기록한다. 이때도 처리 서버는 S1이다 &amp;rarr; D2([S1,2])&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 다른 클라가 데이터 D2를 읽어서 D3로 업데이트하고 기록한다. 이때 처리 서버는 S2다 &amp;rarr; D3([S1,2],[S2,1])&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. 3과 동시에 다른 클라가 D2를 읽어서 D4로 업데이트하고 기록한다. 이때 처리 서버는 S3다 &amp;rarr; D4([S1,2],[S3,1])&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5. 어떤 클라가 D3와 D4를 읽으면 데이터 간 충돌이 있다는 것을 알게 된다. D2를 S2,3가 각각 다른 값으로 바꿨기 때문. 이 충돌은 클라에서 해소하고 서버에 기록한다. 이때 처리 서버는 S1이다 &amp;rarr; D5([S1,3],[S2,1],[S3,1])&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;벡터 시계를 사용하면 버전 X가 버전 Y의 이전 버전인지 쉽게 판단 가능하다. 버전 Y에 포함된 모든 구성요소의 값이 X에 포함된 모든 구성요소 값보다 같거나 큰지만 보면 된다. Ex) D([S0,1],[S1,1])은 D([S0,1],[S1,2])의 이전 버전이다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어떤 버전 X와 Y 사이에 충돌이 있는지 보려면 Y의 벡터 시계 구성요소 가운데 X의 벡터 시계 동일 서버 구성요소보다 작은 값을 갖는 것이 있는지 확인하면 된다(모든 요소가 작다면 이전버전이다). Ex) D([S0,1],[S1,2])와 D([S0,2],[S1,1])은 서로 충돌&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 벡터 시계를 사용해 충돌을 감지하고 해소하는 방법은 2가지 단점이 있다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 충돌 감지 및 해소 로직이 클라에 들어가야하므로, 클라 구현이 복잡해진다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. [서버:버전]의 순서쌍 개수가 굉장히 빨리 늘어난다. 이 문제를 해결하려면 임계치를 정하고 임계치를 넘어서면 오래된 데이터 순으로 지워야 하는데 이렇게 하면 버전 간 선후 관계가 정확하지 않다. 하지만 다이나모 DB 문헌에선 그런 문제가 발생한 적 없다고 한다.&lt;/p&gt;</description>
      <category>개발/대규모 시스템 설계</category>
      <category>대규모 분산 시스템</category>
      <category>백엔드</category>
      <author>라이언납시오</author>
      <guid isPermaLink="true">https://imnotabear.tistory.com/643</guid>
      <comments>https://imnotabear.tistory.com/643#entry643comment</comments>
      <pubDate>Wed, 16 Aug 2023 17:03:21 +0900</pubDate>
    </item>
    <item>
      <title>[대규모 시스템 설계] 6. 키-값 저장소 설계 - 1</title>
      <link>https://imnotabear.tistory.com/642</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;키-값 저장소는 키-값 데이터베이스라고도 불리는 비 관계형 데이터베이스다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 저장소에 저장되는 값은 고유 식별자를 키로 가져야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대표적인 키-값 저장소로 아마존 다이나모, memcached, 레디스가 존재한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;문제 이해 및 설계 범위 확정&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;읽기, 쓰기 그리고 메모리 사용량 사이에 어떤 균형을 갖고, 데이터와의 일관성과 가용성 사이에서 타협적 설계를 해야 한다&lt;/p&gt;
&lt;pre id=&quot;code_1692167434381&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;- 키-값 쌍의 크리는 10KB 이하
- 큰 데이터를 저장할 수 있다
- 높은 가용성을 제공. 시스템은 장애가 있더라도 빨리 응답해야 한다
- 높은 규모 확장성을 제공. 트래픽양에 따라 자동적으로 서버 증설/삭제가 이뤄져야 한다
- 데이터 일관성 수준은 조정이 가능해야 한다
- 응답 지연시간(latency)가 짧아야 한다&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;단일 서버 키-값 저장소는?&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단일 서버 키-값 저장소는 카-값 쌍 전부를 해시 테이블로 저장하는것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;접근법은 빠른 속도를 보장하지만 모든 데이터를 메모리 안에 두는것은 불가능할 수 있다. 이를 해결하기 위해 다음과 같이 할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 데이터 압축&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 자주 쓰이는 데이터만 메모리에 두고 나머지는 디스크에 저장&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 1대 서버로 부족할 때가 찾아오기 때문에 분산 키-값 저장소를 사용한다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;분산 키-값 저장소&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;분산 키-값 저장소는 키-값 쌍을 여러 서버에 분산시키기 때문에 분산 해시 테이블이라고도 불린다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;CAP 정리&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Consistency(일관성): 분산 시스템에 접속하는 모든 클라는 어떤 노드에 접속했느냐에 관계없이 언제나 같은 데이터를 보게 된다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Availability(가용성): 분산 시스템에 접속하는 클라는 일부 노드에 장애가 발생하더라도 항상 응답을 받을 수 있어야 한다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Partitaion Tolerance(파티션 감내): 파티션은 두 노드 사이에 통신 장애가 발생함을 나타낸다. 파티션 감내는 네트워크에 파티션이 생기더라도 시스템은 계속 동작해야 한다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CAP 정리란, 아래 그림과 같이 2가지를 충족하려면 하나는 반드시 희생되어야 한다는 것을 의미&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-08-16 오후 3.43.26.png&quot; data-origin-width=&quot;1100&quot; data-origin-height=&quot;1008&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b2JBob/btsrjsJAABL/lQqINHTmKaj9FUb2rCDkx0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b2JBob/btsrjsJAABL/lQqINHTmKaj9FUb2rCDkx0/img.png&quot; data-alt=&quot;CAP 정리&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b2JBob/btsrjsJAABL/lQqINHTmKaj9FUb2rCDkx0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb2JBob%2FbtsrjsJAABL%2FlQqINHTmKaj9FUb2rCDkx0%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;623&quot; height=&quot;571&quot; data-filename=&quot;스크린샷 2023-08-16 오후 3.43.26.png&quot; data-origin-width=&quot;1100&quot; data-origin-height=&quot;1008&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;CAP 정리&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CP 시스템: 가용성을 희생&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AP 시스템: 데이터 일관성을 희생&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CA 시스템: 파티션 감내를 희생하는 시스템이지만, 통상 네트워크 장애는 피할 수 없는 일로 여겨지므로 실세계에 존재하지 않는다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 사진과 같이 이상적 상태라면 네트워크가 파티션되는 상황은 절대 일어나지 않을것이므로 n1에 기록되는 데이터는 자동적으로 n2와 n3에 복제된다. 가용성과 데이터 일관성도 만족한다&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-08-16 오후 3.46.45.png&quot; data-origin-width=&quot;1070&quot; data-origin-height=&quot;924&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c1EG1E/btsrgQc9fbc/Pa2645FfA56497gpKh0ou0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c1EG1E/btsrgQc9fbc/Pa2645FfA56497gpKh0ou0/img.png&quot; data-alt=&quot;이상적 상태&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c1EG1E/btsrgQc9fbc/Pa2645FfA56497gpKh0ou0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc1EG1E%2FbtsrgQc9fbc%2FPa2645FfA56497gpKh0ou0%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;528&quot; height=&quot;456&quot; data-filename=&quot;스크린샷 2023-08-16 오후 3.46.45.png&quot; data-origin-width=&quot;1070&quot; data-origin-height=&quot;924&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;하지만 실세계는 파티션 문제를 피할 수 없다. 아래 그림은 n3 노드에 장애가 발생하여 n1, n2와 통신할 수 없는 상황을 보여준다. 이때 클라가 n1 또는 n2에 기록한 데이터는 n3에 전달되지 않거나, 반대로 n3에 기록됐으나 n1 및 n2로 전달되지 않는 사태가 발생한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-08-16 오후 3.48.03.png&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;902&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/RbzC3/btsrffYOIfO/j635QOVff4oCgv1QU9DOI0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/RbzC3/btsrffYOIfO/j635QOVff4oCgv1QU9DOI0/img.png&quot; data-alt=&quot;실세계의 분산 시스템&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/RbzC3/btsrffYOIfO/j635QOVff4oCgv1QU9DOI0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FRbzC3%2FbtsrffYOIfO%2Fj635QOVff4oCgv1QU9DOI0%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;547&quot; height=&quot;482&quot; data-filename=&quot;스크린샷 2023-08-16 오후 3.48.03.png&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;902&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;가용성 대신 일관성을 선택한다면(CP 시스템), 3 서버 사이에 생길 수 있는 데이터 불일치 문제를 피하기 위해 n1과 n2에 대해 쓰기 연산을 중단시켜야 하는데, 그렇게 하면 가용성이 깨진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;은행권 시스템은 보통 데이터 일관성을 양보하지 않는다. 계좌 최신 정보를 출력하지 못하는 은행이라고 생각하면 쉽다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;네트워크 파티션 때문에 일관성이 깨질 수 있는 상황이라면 시스템이 해결될 때까지 에러를 반환해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일관성 대신 가용성을 선택한 시스템(AP 시스템)은 낡은 데이터를 반활할 위험이 있어도 계속 읽기 연산을 허용해야 한다. 아울러 n1과 n2는 계속 쓰기 연산을 허용할 것이고, 파티션 문제가 해결된 뒤에 새 데이터를 n3에 전송할 것이다.&lt;/p&gt;</description>
      <category>개발/대규모 시스템 설계</category>
      <category>NoSQL</category>
      <category>대규모 시스템 설계</category>
      <category>키-값 저장소 설계</category>
      <author>라이언납시오</author>
      <guid isPermaLink="true">https://imnotabear.tistory.com/642</guid>
      <comments>https://imnotabear.tistory.com/642#entry642comment</comments>
      <pubDate>Wed, 16 Aug 2023 15:54:01 +0900</pubDate>
    </item>
    <item>
      <title>[Leetcode]Max Number of K-Sum Pairs (C++)</title>
      <link>https://imnotabear.tistory.com/641</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;문제 링크: &lt;a href=&quot;https://leetcode.com/problems/max-number-of-k-sum-pairs/description/?envType=study-plan-v2&amp;amp;envId=leetcode-75&quot;&gt;https://leetcode.com/problems/max-number-of-k-sum-pairs/description/?envType=study-plan-v2&amp;amp;envId=leetcode-75&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1691977889462&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;Max Number of K-Sum Pairs - LeetCode&quot; data-og-description=&quot;Can you solve this real interview question? Max Number of K-Sum Pairs - You are given an integer array nums and an integer k. In one operation, you can pick two numbers from the array whose sum equals k and remove them from the array. Return the maximum nu&quot; data-og-host=&quot;leetcode.com&quot; data-og-source-url=&quot;https://leetcode.com/problems/max-number-of-k-sum-pairs/description/?envType=study-plan-v2&amp;amp;envId=leetcode-75&quot; data-og-url=&quot;https://leetcode.com/problems/max-number-of-k-sum-pairs/description&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/ei4ufg/hyTCy9X9wl/PyYB8roNiCKIQ4mnDPRe31/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/max-number-of-k-sum-pairs/description/?envType=study-plan-v2&amp;amp;envId=leetcode-75&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://leetcode.com/problems/max-number-of-k-sum-pairs/description/?envType=study-plan-v2&amp;amp;envId=leetcode-75&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/ei4ufg/hyTCy9X9wl/PyYB8roNiCKIQ4mnDPRe31/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;Max Number of K-Sum Pairs - 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? Max Number of K-Sum Pairs - You are given an integer array nums and an integer k. In one operation, you can pick two numbers from the array whose sum equals k and remove them from the array. Return the maximum nu&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;p data-ke-size=&quot;size16&quot;&gt;1. 주의할 점&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Map을 활용해도 좋지만, 불필요한 메모리 사용은 지양한다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 구현&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Nums를 오름차순으로 정렬한다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 투 포인터를 이용하여 L은 왼쪽부터 오른쪽으로, R은 오른쪽부터 왼쪽으로 이동하여 둘이 만나기전까지 While문을 수행한다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 둘이 가리키는 합이 K와 같다면 Answer++를 하고 다음 수로 넘어간다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 합이 K보다 작다면 L을 늘려서 합이 커질 수 있도록 한다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 합이 K보다 크다면 R을 줄여 합이 작아질 수 있도록 한다&lt;/p&gt;
&lt;pre id=&quot;code_1691978018919&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 maxOperations(vector&amp;lt;int&amp;gt;&amp;amp; nums, int k) {
        sort(nums.begin(), nums.end());
        int answer = 0;
        int l = 0, r = nums.size()-1;

        while(l &amp;lt; r){
            int sum = nums[l] + nums[r];
            if(sum == k){
                answer++;
                l++;
                r--;
            }
            else if(sum &amp;lt; k) l++;
            else r--;
        }

        return answer;
    }
};&lt;/code&gt;&lt;/pre&gt;</description>
      <category>알고리즘/LeetCode</category>
      <category>LeetCode</category>
      <category>투 포인터</category>
      <author>라이언납시오</author>
      <guid isPermaLink="true">https://imnotabear.tistory.com/641</guid>
      <comments>https://imnotabear.tistory.com/641#entry641comment</comments>
      <pubDate>Mon, 14 Aug 2023 10:53:52 +0900</pubDate>
    </item>
    <item>
      <title>[대규모 시스템 설계] 5. 안정 해시 설계</title>
      <link>https://imnotabear.tistory.com/640</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;수평적 규모 확장성을 달성하기 위해서는 요청 또는 데이터를 서버에 균등하게 나누는것이 중요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇다면 안정 해시 설계는 무엇이고, 무엇을 해결하기 위한 설계인가?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;해시 키 재배치(rehash) 문제&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N개의 캐시 서버가 있다면 이 서버들에 부하를 균등하게 나누기 위해선 다음과 같이 나머지 연산을 통해 서버에 부하를 나눌것이다&lt;/p&gt;
&lt;pre id=&quot;code_1691732124617&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;serverIndex = hash(key) % N (N: 서버 개수)&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;아래는 N이 4로 고정일때의 예시다&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-08-11 오후 2.35.46.png&quot; data-origin-width=&quot;1464&quot; data-origin-height=&quot;736&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d0Qf9f/btsqSHuqsWl/AvWwf4A4e8kKRG5qJaD9UK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d0Qf9f/btsqSHuqsWl/AvWwf4A4e8kKRG5qJaD9UK/img.png&quot; data-alt=&quot;해시가 서버에 나눠지는 방식&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d0Qf9f/btsqSHuqsWl/AvWwf4A4e8kKRG5qJaD9UK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd0Qf9f%2FbtsqSHuqsWl%2FAvWwf4A4e8kKRG5qJaD9UK%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;613&quot; height=&quot;308&quot; data-filename=&quot;스크린샷 2023-08-11 오후 2.35.46.png&quot; data-origin-width=&quot;1464&quot; data-origin-height=&quot;736&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-08-11 오후 2.36.31.png&quot; data-origin-width=&quot;1454&quot; data-origin-height=&quot;682&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/blBEbq/btsqSbCLd7c/kMj09SEkMatLRXgznuCizK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/blBEbq/btsqSbCLd7c/kMj09SEkMatLRXgznuCizK/img.png&quot; data-alt=&quot;나눠진 형태&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/blBEbq/btsqSbCLd7c/kMj09SEkMatLRXgznuCizK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FblBEbq%2FbtsqSbCLd7c%2FkMj09SEkMatLRXgznuCizK%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;670&quot; height=&quot;314&quot; data-filename=&quot;스크린샷 2023-08-11 오후 2.36.31.png&quot; data-origin-width=&quot;1454&quot; data-origin-height=&quot;682&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;하지만 만약 서버가 추가되거나 삭제 혹은 에러가 발생해서 죽는다면?&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-08-14 오후 2.58.30.png&quot; data-origin-width=&quot;1418&quot; data-origin-height=&quot;610&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bcMZdL/btsq5cgxUfY/kwZeLrD9KHEjqZVWZ4wsB0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bcMZdL/btsq5cgxUfY/kwZeLrD9KHEjqZVWZ4wsB0/img.png&quot; data-alt=&quot;1번 서버가 죽은 경우&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bcMZdL/btsq5cgxUfY/kwZeLrD9KHEjqZVWZ4wsB0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbcMZdL%2Fbtsq5cgxUfY%2FkwZeLrD9KHEjqZVWZ4wsB0%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;1418&quot; height=&quot;610&quot; data-filename=&quot;스크린샷 2023-08-14 오후 2.58.30.png&quot; data-origin-width=&quot;1418&quot; data-origin-height=&quot;610&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;1번 서버가 죽은 경우&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 그림처럼 1번 서버가 죽은 경우, Module 연산이 4에서 3으로 변경됨에 따라 대부분의 키 재분배&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 대부분 캐시 클라이언트가 데이터가 없는 엉뚱한 서버에 접속&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 대규모 캐시 미스 발생&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;안정 해시&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해시 테이블의 크기가 조정되면 평균적으로 k/n개의 키만 재배치.(k: Key 개수, n: 슬롯 개수)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SHA-1와 같은 해시 함수를 통해 출력 값의 범위가 x0 ~ xn이라고 가정하고 이를 해시 링 형태로 만들면 아래와 같다&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-08-14 오후 3.03.36.png&quot; data-origin-width=&quot;1416&quot; data-origin-height=&quot;268&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vFr27/btsrgvsinJZ/k3OTqCE0ZQ2MpHrUlAqImK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vFr27/btsrgvsinJZ/k3OTqCE0ZQ2MpHrUlAqImK/img.png&quot; data-alt=&quot;해시 함수의 출력 값&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vFr27/btsrgvsinJZ/k3OTqCE0ZQ2MpHrUlAqImK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvFr27%2FbtsrgvsinJZ%2Fk3OTqCE0ZQ2MpHrUlAqImK%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;623&quot; height=&quot;118&quot; data-filename=&quot;스크린샷 2023-08-14 오후 3.03.36.png&quot; data-origin-width=&quot;1416&quot; data-origin-height=&quot;268&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;해시 함수의 출력 값&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-08-14 오후 3.03.51.png&quot; data-origin-width=&quot;1470&quot; data-origin-height=&quot;1444&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xsPsA/btsq7aW1j8b/nMdtZPLhOstzLeQt6sxtdk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xsPsA/btsq7aW1j8b/nMdtZPLhOstzLeQt6sxtdk/img.png&quot; data-alt=&quot;위의 표를 이어서 만든 해시 링&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xsPsA/btsq7aW1j8b/nMdtZPLhOstzLeQt6sxtdk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FxsPsA%2Fbtsq7aW1j8b%2FnMdtZPLhOstzLeQt6sxtdk%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;576&quot; height=&quot;566&quot; data-filename=&quot;스크린샷 2023-08-14 오후 3.03.51.png&quot; data-origin-width=&quot;1470&quot; data-origin-height=&quot;1444&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;1. (Module 연산을 사용하지 않는) 균등분포 해시 함수 f를 사용하면 서버 IP나 이름을 링 위의 특정 위치와 매칭할 수 있다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 해시할 키 k0, k1, ... 또한 해시 링 위의 특정 위치에 배치할 수 있다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 링위에 배치된 키는 시계 방향에서 만나는 가장 가까운 서버에 저장된다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 3개를 종합하면 아래 그림으로 표현할 수 있다&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-08-14 오후 3.08.49.png&quot; data-origin-width=&quot;1632&quot; data-origin-height=&quot;1076&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dfQtFR/btsrdifXqRr/ZftRk6usSOfBPIYkwk36i0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dfQtFR/btsrdifXqRr/ZftRk6usSOfBPIYkwk36i0/img.png&quot; data-alt=&quot;안정 해시 기본 구현법&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dfQtFR/btsrdifXqRr/ZftRk6usSOfBPIYkwk36i0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdfQtFR%2FbtsrdifXqRr%2FZftRk6usSOfBPIYkwk36i0%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;695&quot; height=&quot;458&quot; data-filename=&quot;스크린샷 2023-08-14 오후 3.08.49.png&quot; data-origin-width=&quot;1632&quot; data-origin-height=&quot;1076&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;서버가 추가되거나 제거가 된다면, 평균적으로 k/n개의 키가 재배치된다(위의 3번에 따라 저장되는 서버 재배치)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본 구현법의 문제점은 2가지가 있다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 추가와 삭제를 한다면 파티션의 크기(인접한 서버 사이의 해시 공간)를 균등하게 유지하지 못한다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 키의 균등 분포를 달성하기 어렵다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-08-14 오후 3.12.22.png&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;817&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bmLkHn/btsq1bWQfsB/xyjFktEaImf7ykmpYrnLFk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bmLkHn/btsq1bWQfsB/xyjFktEaImf7ykmpYrnLFk/img.png&quot; data-alt=&quot;1. 서버 삭제 이후 발생하는 파티션 크기 불균등&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bmLkHn/btsq1bWQfsB/xyjFktEaImf7ykmpYrnLFk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbmLkHn%2Fbtsq1bWQfsB%2FxyjFktEaImf7ykmpYrnLFk%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;833&quot; height=&quot;532&quot; data-filename=&quot;스크린샷 2023-08-14 오후 3.12.22.png&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;817&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;1. 서버 삭제 이후 발생하는 파티션 크기 불균등&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;figure data-ke-type=&quot;image&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; data-ke-style=&quot;alignCenter&quot;&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2번의 예로 아래와 같이 S3에는 아무것도 할당되지 않는 경우가 발생할 수 있다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-08-14 오후 3.17.51.png&quot; data-origin-width=&quot;1646&quot; data-origin-height=&quot;1014&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b52anA/btsq0w70gsf/fOwha9QkY8rHgdqrXuDXlk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b52anA/btsq0w70gsf/fOwha9QkY8rHgdqrXuDXlk/img.png&quot; data-alt=&quot;2. 키의 균등 분포를 달성하지 못한 경우&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b52anA/btsq0w70gsf/fOwha9QkY8rHgdqrXuDXlk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb52anA%2Fbtsq0w70gsf%2FfOwha9QkY8rHgdqrXuDXlk%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;1646&quot; height=&quot;1014&quot; data-filename=&quot;스크린샷 2023-08-14 오후 3.17.51.png&quot; data-origin-width=&quot;1646&quot; data-origin-height=&quot;1014&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;2. 키의 균등 분포를 달성하지 못한 경우&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;h3 data-ke-size=&quot;size23&quot;&gt;가상 노드(Replica, 복제)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 문제를 해결하기 위해 제안된 기법이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하나의 서버는 링 위에 임의의 숫자 K개의 가상 노드를 가질 수 있다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; K가 높을수록 키의 분포는 점점 더 균등해진다. 표준 편자가 작아져서 데이터가 고르게 분포되기 때문&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; K를 약 100~200으로 설정한다면 표준 편차 값은 평균의 10%~5%밖에 되지 않는다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; K값을 더 늘릴수록 표준 편차의 값은 더 작아지지만, 가상 노드 데이터를 저장할 공간이 더 필요해지므로 적절한 trade off가 필요&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-08-14 오후 3.20.24.png&quot; data-origin-width=&quot;1644&quot; data-origin-height=&quot;1028&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vmMlF/btsq5ZOT0qr/WkP0ZKPHtPPW1Ax2PeORDk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vmMlF/btsq5ZOT0qr/WkP0ZKPHtPPW1Ax2PeORDk/img.png&quot; data-alt=&quot;가상 노드 3개씩 가지고 있는 서버0, 1&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vmMlF/btsq5ZOT0qr/WkP0ZKPHtPPW1Ax2PeORDk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvmMlF%2Fbtsq5ZOT0qr%2FWkP0ZKPHtPPW1Ax2PeORDk%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;727&quot; height=&quot;455&quot; data-filename=&quot;스크린샷 2023-08-14 오후 3.20.24.png&quot; data-origin-width=&quot;1644&quot; data-origin-height=&quot;1028&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;가상 노드 3개씩 가지고 있는 서버0, 1&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 서버의 가상 노드 기준으로 반시계 방향에 있는 다른 서버의 가상노드 사이에 있는 키들만 재배치를 하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추가 또한 마찬가지로 추가된 서버부터 반시계 방향에 있는 다른 서버의 가상노드 사이에 있는 키들만 추가된 서버로 재배치하면 된다&lt;/p&gt;</description>
      <category>개발/대규모 시스템 설계</category>
      <author>라이언납시오</author>
      <guid isPermaLink="true">https://imnotabear.tistory.com/640</guid>
      <comments>https://imnotabear.tistory.com/640#entry640comment</comments>
      <pubDate>Mon, 14 Aug 2023 10:50:50 +0900</pubDate>
    </item>
  </channel>
</rss>