{"componentChunkName":"component---src-templates-blog-post-js","path":"/Computer-Network/2020-10-02-네트워크-P2P/","result":{"data":{"site":{"siteMetadata":{"title":"Hun's Footsteps 🥷","author":"전여훈","siteUrl":"https://jeonyeohun.netlify.app","comment":{"disqusShortName":"","utterances":"jeonyeohun/jeonyeohun.github.io"},"sponsor":{"buyMeACoffeeId":"jeonyeohun"}}},"markdownRemark":{"id":"d8eac46c-c942-553d-a9c2-20a5ca5a0131","excerpt":"참고도서: 컴퓨터 네트워킹 : 하향식 접근. 7판. James F. Kurose , Keith W.Ross 지음 P2P 개요 P2P는 일반적인 클라인언트-서버 구조와는 달리 서로  라고 부르는 호스트들이 클라이언트도 되고, 서버의 역할을 하기도 한다. 이런 구조는 P2P 네트워크에  를 제공하는데, P2P는 어떤 호스트가 파일을 내려받는 것과 동시에 다른 피어들에게 업로드 하기 때문에 네트워크의 성능을 향상시킬 수 있게된다. 예를 들어, N…","html":"<p><em><strong>참고도서: 컴퓨터 네트워킹 : 하향식 접근. 7판. James F. Kurose , Keith W.Ross 지음</strong></em></p>\n<h2 id=\"p2p-개요\" style=\"position:relative;\"><a href=\"#p2p-%EA%B0%9C%EC%9A%94\" aria-label=\"p2p 개요 permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>P2P 개요</h2>\n<ul>\n<li>P2P는 일반적인 클라인언트-서버 구조와는 달리 서로 <code class=\"language-text\">피어</code> 라고 부르는 호스트들이 클라이언트도 되고, 서버의 역할을 하기도 한다.</li>\n<li>이런 구조는 P2P 네트워크에 <code class=\"language-text\">자가 확장성(Self-Scalability)</code> 를 제공하는데, P2P는 어떤 호스트가 파일을 내려받는 것과 동시에 다른 피어들에게 업로드 하기 때문에 네트워크의 성능을 향상시킬 수 있게된다.</li>\n<li>예를 들어, N개의 피어들이 어떤 파일을 내려받으려고 할 때, 클라이언트-서버 구조의 네트워크에서는 <code class=\"language-text\">NF/서버의 업로드 속도</code> 와 <code class=\"language-text\">피어들 중 가장 다운로드 속도가 느린 피어의 속도</code>에 따라 재분배시간이 결정되지만, P2P 구조에서는 <code class=\"language-text\">NF/서버의 업로드 속도 + 업로드를 하는 모든 피어들의 업로드 속도의 합</code> 과 <code class=\"language-text\">피어들 중 가장 다운로드 속도가 느린 피어의 속도</code> 에 따라 재분배 시간이 결정된다.</li>\n<li>따라서 N이 충분이 커졌을 때, 클라이언트-서버 구조는 선형적으로 재분배시간이 증가하지만, P2P 구조는 분모가 N과 함께 증가하면서 재분배 시간이 느리게 증가하는 것을 알 수 있다.</li>\n<li>하지만 동시에 피어들이 익명으로 참여하기 때문에 피어에 대한 신뢰성과 보안의 문제가 발생한다.</li>\n</ul>\n<h2 id=\"napster\" style=\"position:relative;\"><a href=\"#napster\" aria-label=\"napster permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Napster</h2>\n<ul>\n<li>Napster는 <code class=\"language-text\">중앙집중된 방식을 일부 채택한 P2P 구조</code>이다.</li>\n<li>\n<p>Napster의 운영방식은 대략적으로 다음과 같다.</p>\n<ul>\n<li>어떤 호스트가 피어로 참여하면, Napster에 자신의 IP 주소와 자신이 가진 정보들을 알린다.</li>\n<li>Napster에 참여한 피어가 특정한 정보를 원하면 Napster에게 해당 정보를 가진 피어가 누구인지 질의한다.</li>\n<li>Napster는 자신에게 저장된 IP 주소를 요청피어에게 알려준다.</li>\n<li>피어는 전달받은 IP 주소로 피어를 연결해서 통신을 시작한다.</li>\n</ul>\n</li>\n<li>Napster는 파일과 정보들을 한 곳에 집중시키지는 않지만, 해당 정보들이 <code class=\"language-text\">어디에 위치해있는지</code>에 대한 정보를 집중시켜서 피어들이 원하는 정보를 누가 가지고 있는지 빠르게 파악할 수 있도록 하는 장점이 있다.</li>\n<li>단점은 정보를 얻기 위해서는 항상 Napster를 거쳐야하기 때문에, Napster의 중앙 시스템에 문제가 생기면 P2P 네트워크를 이용할 수 없고, 트래픽이 집중될 때 병목현상이 발생할 수 있다는 점이 있다.</li>\n</ul>\n<h2 id=\"gnutella\" style=\"position:relative;\"><a href=\"#gnutella\" aria-label=\"gnutella permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Gnutella</h2>\n<ul>\n<li>Gnutella 는 <code class=\"language-text\">Query Flooding</code> 이라는 방식을 사용하는 <code class=\"language-text\">완전한 P2P 네트워크</code> 시스템이다. 여기서 완전하다는 것은 중간에 다른 중앙 서버의 도움이 없이 피어끼리 곧바로 통신을 할 수 있다는 것을 의미한다.</li>\n<li>Gnutella 는 네트워크 위에 새로운 네트워크 층을 올려서 특정한 기능을 제공하는 네트워크 노드들이 logical link 를 가질 수 있게 하는 <code class=\"language-text\">Overlay Network</code> 를 사용한다.</li>\n<li>이 overlay network 위에서 각 노드들은 <code class=\"language-text\">flooding</code> 이라고 부르는 질의를 보내고 <code class=\"language-text\">back propagation</code> 이라고 부르는 응답을 주고받는다.</li>\n<li>Gnutella 에 참여하는 피어들을 다른 말로 <code class=\"language-text\">Servents(Server + Client)</code> 라고도 부른다.</li>\n<li>\n<p>Gnutella 는 다음과 같은 과정으로 호스트를 네트워크에 피어로 참여시킨다.</p>\n<ol>\n<li>새롭게 참여할 호스트는 먼저 <code class=\"language-text\">GnuCache</code> 서버에 접속해서 현재 네트워크에 참여 중인 다른 피어들의 리스트를 받아온다.</li>\n<li>응답메세지로 리스트를 받은 호스트는 리스트 중에 있는 하나의 피어 호스트에게 <code class=\"language-text\">Gnutellan Connect</code>요청을 보낸다.</li>\n<li>요청을 받은 피어 호스트는 참여를 허가하는 의미로 <code class=\"language-text\">Gnutella OK</code> 응답을 보낸다.</li>\n<li>이제 새로운 호스트는 Gnutella 의 피어가 되고 처음 요청을 보냈던 피어와 연결되어 있다.</li>\n<li>Gnutella의 피어들은 주기적으로 <code class=\"language-text\">ping</code> 메세지를 이웃 피어들에게 보내는데, 이 메세지를 받은 피어들은 <code class=\"language-text\">pong</code> 메세지로 응답하고, 자신이 받은 ping 메세지를 자신의 이웃 피어들에게 다시 보낸다.</li>\n<li>이렇게 하면 처음에는 하나의 피어와만 연결되어 있던 새로 참여한 호스트는 돌고 돌아서 전달된 ping 메세지를 받게 되고, 이 메세지에서 ping 메세지를 보낸 피어의 IP 주소를 알게된다.</li>\n<li>새로 참여한 호스트는 알아낸 IP 주소와 연결을 설정한다.</li>\n</ol>\n</li>\n<li>\n<p>Gnutella 가 어떤 정보를 피어들로부터 찾을 때는 다음과 같은 과정을 거친다.</p>\n<ol>\n<li>한 피어가 현재 자신과 연결된 모든 피어들에게 쿼리 메세지를 보낸다.</li>\n<li>메세지를 전달받은 피어들은 또 자신과 연결된 모든 피어들에게 쿼리 메세지를 보낸디.</li>\n<li>위 작업을 최초 피어가 전송한 원하는 정보를 얻을 때까지 반복한다.</li>\n</ol>\n</li>\n<li>정보를 찾을 때 쿼리를 계속해서 이웃 노드들에게 전송하기 때문에 이런 방법을 <code class=\"language-text\">Query Flooding</code>이라고 부른다.</li>\n<li>\n<p>Gnutella 는 단순한 구조로 이루어져 있다는 장점이 있지만, <code class=\"language-text\">query flooding</code> 을 계속 반복해야하기 때문에 원하는 정보를 찾는데 시간이 오래 걸릴 가능성이 높다. 또한 원하는 정보를 얻지 못하면 계속해서 쿼리를 전파하기 때문에 잘못하면 <code class=\"language-text\">broadcast storm</code>을 만들어 전체 트래픽에도 큰 영향을 줄 수 있다.</p>\n<ul>\n<li>이 문제를 위해 일정 TTL 이상부터는 query를 더이상 전송하지 않게 하는 <code class=\"language-text\">limited-scope query flooding</code>을 생각할 수도 있지만, 이렇게 하면 피어들을 많이 유지하는 것이 의미가 없어지게 된다.</li>\n</ul>\n</li>\n<li>더불어서 Overlay network는 가상의 네트워크이기 때문에 각 노드들이 요청이 없더라도 항상 서로 TCP 연결을 설정하고 있어야 그 구조가 유지된다는 단점도 있다.</li>\n<li>단점이 참 많은데, 마지막으로 대부분의 Gnutella 피어들은 다른 피어들이 원하는 파일을 가지고 있지 않은 경우가 많다. 대부분의 중요한 파일들을 일부 피어들이 가지고 있게 때문에 네트워크에 기여하는 바가 없이 원하는 것을 얻기만 하는 <code class=\"language-text\">Free Riding</code> 현살이 발생한다.</li>\n</ul>\n<h2 id=\"hierarchical-overlay\" style=\"position:relative;\"><a href=\"#hierarchical-overlay\" aria-label=\"hierarchical overlay permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Hierarchical Overlay</h2>\n<ul>\n<li>Hierarchical Overlay는 피어들을 그룹으로 나누고 그 그룹을 담당하는 <code class=\"language-text\">super-peer</code>를 만들어 운영하는 방식이다.</li>\n<li>실제로 네트워크에 참여하는 것은 <code class=\"language-text\">super-peer</code> 뿐이고 다른 피어들은 super-peer에 TCP 연결로 연결되어 있는 형태이다.</li>\n<li>super-peer 들은 자신의 그룹 안에 있는 피어들이 가지고 있는 파일들의 정보를 모두 알고 있기 때문에 다른 super-peer 로 부터 요청이 들어오면 그룹 내 피어들을 검사해서 응답을 보내주게 되는 구조이다.</li>\n</ul>\n<h2 id=\"bittorrent\" style=\"position:relative;\"><a href=\"#bittorrent\" aria-label=\"bittorrent permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>BitTorrent</h2>\n<ul>\n<li>비트토렌트는 파일 분배에 참여하는 모든 피어들의 그룹을 <code class=\"language-text\">torrent</code> 라고 부르고 <code class=\"language-text\">tracker</code> 라는 리스트를 관리해서 현재 어떤 피어가 네트워크에 참여하고 있는지 기록한다. 그리고 torrent 에 참여하고 있는 피어들은 주기적으로 자신의 활동상태를 tracker에 알려서 해당 리스트에 자신을 유지시킨다.</li>\n<li>비트토렌트 프로토콜에서 모든 파일은 256KB의 조각으로 나뉘어지고 이 조각을 <code class=\"language-text\">chunk</code> 라고 한다.</li>\n<li>각 피어들은 이 chunk 를 다른 피어들에게 업로드하게 된다.</li>\n<li>\n<p>비트토렌트는 다음과 같은 과정으로 피어들과 파일분배를 관리한다.</p>\n<ul>\n<li>새로운 피어가 토렌트에 참여하면, 이 피어는 tracker에 있는 <code class=\"language-text\">50개의 임의의 피어들과 TCP 연결을 설정</code>한다.</li>\n<li>이 피어는 자신과 연결된 다른 피어들에게 <code class=\"language-text\">주기적으로 그들이 가지고 있는 chunk의 리스트를 받아온다.</code></li>\n<li>받아온 리스트에서 현재 <code class=\"language-text\">자신이 가지고 있지 않은 chunk</code>를 가진 피어가 있다면 해당 피어에게 chunk에 대한 요청메세지를 보낸다.</li>\n<li>이떄, 선택되는 chunk는 자신이 가지고 있지 않고 다른 피어들이 드물게 가지고 있는 chunk를 선택하는 <code class=\"language-text\">rarest first</code> 알고리즘을 통해 결정된다. 이 방법을 사용하면, 피어들이 잘 가지고 있지 않은 chunk들이 먼저 분배되기 때문에 chunk의 종류가 피어들에게 균등하게 분배될 수 있다.</li>\n</ul>\n</li>\n<li>\n<p>이웃 피어들로부터 어떤 요청이 들어오면, 피어는 자신에게 가장 빠른 속도로 chunk를 보내는 <code class=\"language-text\">4개의 피어를 선택</code>해서 자신의 파일을 제공한다. 이렇게 선정된 4개의 피어를 <code class=\"language-text\">Unchoked</code> 피어라고 부른다.</p>\n<ul>\n<li>이 상위 4개의 피어는 <code class=\"language-text\">매 10초마다 갱신</code>된다.</li>\n</ul>\n</li>\n<li>\n<p>그리고 매 30초마다 랜덤하게 하나의 피어를 선택해서 chunk를 전송한다. 이렇게 랜덤하게 선정된 피어를 <code class=\"language-text\">Optimistically Unchoked</code> 피어라고 한다.</p>\n<ul>\n<li>토렌트에 처음 참여한 피어는 chunk를 가지고 있지 않기 때문에, 랜덤하게 선택하는 알고리즘이 없다면, 절대 상위 4개의 피어에 등록될 수가 없다.</li>\n</ul>\n</li>\n<li>이렇게 비트토렌트에서 잘 제공해주는 사람에게 좋은 보상을 제공하는 방식을 <code class=\"language-text\">tit-for-tat(TFT)</code> 방식이라고 부른다. 이 방식이 사용되었기 때문에 비트토렌트는 <code class=\"language-text\">Free-Riding</code> 문제를 최소화할 수 있게 된다.</li>\n</ul>\n<h2 id=\"distributed-hash-tabledht\" style=\"position:relative;\"><a href=\"#distributed-hash-tabledht\" aria-label=\"distributed hash tabledht permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Distributed Hash Table(DHT)</h2>\n<ul>\n<li>DHT는 분산된 P2P 데이터베이스이다.</li>\n<li>분산된 데이터베이스이기 때문에 네트워크를 구성하는 각 피어들이 데이터베이스를 구성하는 정보들을 일부씩 나누어서 가지고 있게된다.</li>\n<li>\n<p>문제점은 P2P 네트워크의 피어들은 고정적이지 않고 항상 바뀔 수 있다는 것인데 이를 해결하기 위해서 DHT는 다음과 같은 방법으로 운영된다.</p>\n<ul>\n<li>피어들의 식별자와 데이터들의 식별자를 해쉬함수를 이용해 같은 범위에 있는 숫자로 변환한다.</li>\n<li>변환된 숫자를 가지고 피어와 데이터를 매칭시키는데, 이때 데이터를 데이터의 식별 숫자보다 같거나 큰 숫자를 식별자로 가지는 피어 중 가장 데이터의 식별 숫자에 가까운 피어에 저장시킨다.</li>\n<li>마치 더블리 링크드 리스트처럼 구성되어 있어서 피어가 떠나게 되면 자신이 가지고 있던 데이터를 자신의 이전이나 다음 노드 중 데이터의 식별 숫자와 더 가까운 쪽으로 넘겨주고 네트워크를 떠난다.</li>\n<li>이렇게 하면 피어들이 네트워크를 들어왔다 나갔다 하더라도 데이터의 위치는 큰 변함없이 비슷한 자리를 유지하게 될 것이다.</li>\n</ul>\n</li>\n<li>이렇게 데이터와 피어의 위치를 비슷한 위치로 계속 유지시키는 것을 <code class=\"language-text\">Consistent Hashing</code> 이라고 한다.</li>\n</ul>","frontmatter":{"title":"[네트워크] P2P","date":"October 01, 2020"}}},"pageContext":{"slug":"/Computer-Network/2020-10-02-네트워크-P2P/","previous":{"fields":{"slug":"/Computer-Network/2020-09-29-네트워크-네트워크-어플리케이션의-원리/"},"frontmatter":{"title":"[네트워크] 네트워크 어플리케이션의 원리","category":"Computer-Network","draft":false}},"next":{"fields":{"slug":"/Computer-Network/2020-10-01-네트워크-DNS/"},"frontmatter":{"title":"[네트워크] DNS","category":"Computer-Network","draft":false}}}},"staticQueryHashes":["2486386679","3128451518"]}