<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>juna-dev.log</title>
        <link>https://velog.io/</link>
        <description>웹 개발자</description>
        <lastBuildDate>Sat, 30 Oct 2021 13:27:22 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>juna-dev.log</title>
            <url>https://images.velog.io/profiles/juna-dev/thumbnails/1578026666.829.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. juna-dev.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/juna-dev" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[Facebook 접속 장애 사건 분석 (BGP Down)]]></title>
            <link>https://velog.io/@juna-dev/facebook-bgp-down</link>
            <guid>https://velog.io/@juna-dev/facebook-bgp-down</guid>
            <pubDate>Sat, 30 Oct 2021 13:27:22 GMT</pubDate>
            <description><![CDATA[<p>이 글은 전국 KT 네트워크 장애 사건을 이해하는데도 도움이 될 것이라고 생각됩니다.</p>
<ul>
<li><a href="https://www.msit.go.kr/bbs/view.do?sCode=user&amp;mId=113&amp;mPid=112&amp;pageIndex=&amp;bbsSeqNo=94&amp;nttSeqNo=3180886&amp;searchOpt=ALL&amp;searchTxt=">과기부 KT 네트워크 장애 분석 보도자료</a></li>
</ul>
<h1 id="요약">요약</h1>
<ol>
<li>인터넷은 다양한 네트워크들로 구성된 네트워크들이다. 이러한 네트워크들의 라우터는 지속적으로 route를 교환하고 업데이트한다.</li>
<li>&quot;설정 변경 실수&quot;로 페이스북 네트워크는 다른 네트워크에게 BGP advertizing(경로 알리기)을 중단했다.</li>
<li>이제 Facebook 네트워크에 속한 모든 IP 주소를 라우팅할 수 없게 되었다.</li>
</ol>
<p>즉 6시간 동안 페이스북 네트워크가 인터넷 세상에서 단절되어 사라졌습니다.</p>
<br/>

<p>이 글은 위 사건에 대해 학습하는 과정에서 얻은 지식을 총 정리하는 글입니다.</p>
<ul>
<li>빠르게 결론을 파악하고 싶다면 <code>3. AS와 BGP</code> 파트를 추천합니다</li>
<li><a href="https://youtu.be/PsLNQaY5SqE">What really caused the 2021 facebook outage (summary)</a>도 추천(3분20초 요약영상)</li>
</ul>
<h1 id="목차">목차</h1>
<ol>
<li>DNS</li>
<li>라우터</li>
<li>AS(Autonomous System)와 BGP(Border Gateway Protocol)</li>
<li>사건 분석</li>
<li>결론</li>
</ol>
<h1 id="파트1-dns">파트1. DNS</h1>
<blockquote>
<p>DNS는 인터넷에서 사용되는 주소 체계로 .com 또는 .net과 같은 특정 최상위 도메인(TLD)의 모든 도메인 네임 및 해당하는 IP주소, 및 관련 값들을 저장, 관리하는 분산 형 데이터베이스 또는 그에 해당하는 기능을 갖는 물리적인 서버 장치를 지칭합니다 - <a href="http://www.codns.com/b/B05-162">CODNS - DNS란 무엇입니까?</a></p>
</blockquote>
<p>간단히 말하면 DNS는 우리가 브라우저에 주소를 입력하면 실제 IP 주소를 응답하는 서버.</p>
<ul>
<li>즉 <code>www.naver.com</code>(요청) 에 대한 응답으로 <code>125.209.222.141</code> 를 반환</li>
</ul>
<p><img src="https://images.velog.io/images/juna-dev/post/47467619-cedf-43f5-9c4c-a9aab578a240/dns-request-sequence.png" alt=""></p>
<blockquote>
<p><a href="https://www.cloudflare.com/learning/dns/what-is-dns">Cloudflare - What is DNS?</a></p>
</blockquote>
<p>위는 실제 DNS 쿼리 요청 흐름을 간략화한 이미지이다. </p>
<p>위 이미지 속 4개의 DNS 서비스 유형에 대한 설명을 첨부한다.</p>
<Br/>

<p><strong>Recursive Resolver</strong></p>
<ul>
<li>대개 클라이언트는 <code>Authoritative Nameserver</code>에 직접 쿼리를 수행하지 않는다.</li>
<li>대신 <code>Recursive Resolver</code>에 먼저 질의하는 경우가 일반적.</li>
<li>실제 정보를 소유하고 있지 않지만 클라이언트를 대신해서 DNS 정보를 가져올 수 있는 중간자 역할.</li>
<li>보통 ISP가 제공하는 서버를 사용하나, <code>8.8.8.8</code> 등 직접 선택 가능하다.</li>
</ul>
<p><strong>Root Nameserver</strong></p>
<ul>
<li>13개의 루트 네임서버는 모든  <code>Recursive Resolver</code>에 알려져 있으며 이들은 <code>Recursive Resolver</code>가 DNS 레코드를 요청하는 과정의 첫 단계.</li>
<li>루트 네임서버는 도메인 이름을 포함한 <code>Recursive Resolver</code>의 쿼리에 대해, 해당 도메인의 확장자(.com,. net, .org, etc.)에 따라 TLD 네임서버 정보를 포함해 응답.</li>
</ul>
<p><strong>TLD Nameserver</strong></p>
<ul>
<li>TLD 네임서버는 .com, .net 등 도메인 확장자를 공유하는 모든 도메인 이름의 정보를 유지.</li>
<li>.com TLD 네임서버는 <code>.com</code>으로 끝나는 모든 웹사이트의 정보를 갖고 있다.</li>
</ul>
<p><strong>Authoritiative Nameserver</strong></p>
<ul>
<li>Authoritative DNS는 도메인에 대해 <strong>최종 권한</strong>이 있다.</li>
<li><code>Recursive Resolver</code>에 IP 주소 정보가 담긴 답을 제공할 책임이 있다.</li>
</ul>
<Br/>

<h3 id="dns-쿼리-과정">DNS 쿼리 과정</h3>
<p><img src="https://images.velog.io/images/juna-dev/post/264d5094-d2e9-4eaa-ac6b-920df2eef34e/dns-query-aws.png" alt=""></p>
<blockquote>
<p><a href="https://aws.amazon.com/route53/what-is-dns/?nc1=h_ls">AWS - What is DNS?</a>
캐싱 등의 과정이 제외 후, 간략화된 이미지</p>
</blockquote>
<p>(2) 사용자가 <code>www.google.com</code>을 검색하는 경우</p>
<p>(3) <code>Recursive Resolver</code>는 루트 네임서버로부터 응답을 받는다</p>
<p>(4) TLD 네임서버는 해당 도메인의 <code>Authoritative Nameserver</code>에 대한 정보를 응답</p>
<p>(6) <code>Authoritative Nameserver</code>는 최종 결과로 IP를 응답</p>
<br/>

<h3 id="사건-당시-facebookcom을-dns에-요청해보자">사건 당시 facebook.com을 DNS에 요청해보자</h3>
<p><img src="https://images.velog.io/images/juna-dev/post/9d52d118-05ca-4536-854c-b7da8e058a50/dig-google.png" alt=""></p>
<p>구글이 운영하는 <code>8.8.8.8 DNS</code>에 쿼리를 요청하고 <strong>정상 응답</strong>을 받은 것이 확인된다.</p>
<p>참고로 명령어 해석은 아래와 같다.</p>
<pre><code>&gt; dig @dns-server dmain</code></pre><p><img src="https://images.velog.io/images/juna-dev/post/48c8db41-5edc-4f0a-a5b4-0be6d53a6335/dig-facebook.png" alt=""></p>
<p>위 캡쳐는 사건 당시, facebook.com에 대해 쿼리를 날린 결과. </p>
<ul>
<li><code>ANSWER: 0</code> 를 확인 가능하다.</li>
</ul>
<br/>

<h3 id="더-알아보면-재밌는-것들">더 알아보면 재밌는 것들</h3>
<br/>

<p><strong>1. 어째서 전세계 어디에서든 <code>8.8.8.8</code> DNS를 빠르게 이용 가능할까?</strong></p>
<p><img src="https://images.velog.io/images/juna-dev/post/e4b974c3-529a-4f48-ad59-8c35c83b796b/google-dns-on-earth.png" alt=""></p>
<blockquote>
<p>각 대륙별로 8.8.8.8 주소를 가지는 Google DNS 서버를 위치시키십니다. 
<a href="https://www.netmanias.com/ko/post/blog/5357/dns-google-network-protocol/google-dns">Google DNS 소개</a></p>
</blockquote>
<p>댓글에도 나와있지만, DNS를 운용하면 어떠한 장점(수익, 데이터 분석 등)이 있는지 궁금하다.</p>
<br/>

<p><strong>2. 과연 어떤 DNS를 써야 가장 빠르게 이용 가능할까?</strong></p>
<p><img src="https://images.velog.io/images/juna-dev/post/f2c092df-aa01-43c6-83b9-b6facef58a62/namebench.png" alt=""></p>
<blockquote>
<p><a href="http://www.codns.com/b/B05-175">내게 맞는 최적의 DNS 서버주소찾기</a></p>
</blockquote>
<p>DNS는 IP주소를 받아오는 역할을 할 뿐이다. 실제 인터넷 속도를 증가시키지 않는다.</p>
<p>따라서 일반적으로 인터넷을 설치하면 설정되는 통신사 DNS를 사용해도 무관하다.</p>
<ul>
<li>다만 원하는 경우 최적의 DNS를 설정 후 사용 가능하다.</li>
<li><a href="https://hi098123.tistory.com/417">내 인터넷에 맞는 DNS를 결정하는 방법</a> 등의 글도 존재한다.</li>
</ul>
<Br/>

<h1 id="파트2-라우터">파트2. 라우터</h1>
<p>라우터는 이름처럼 경로를 지정해주는 역할을 한다 (3계층에서 동작하는 장비)</p>
<ul>
<li>라우터에 들어오는 패킷의 &quot;목적지 IP 주소&quot;를 확인하고 자신이 가진 &quot;경로 정보&quot;를 이용해 포워딩한다.</li>
</ul>
<Br/>

<h3 id="1-경로-지정">1. 경로 지정</h3>
<p>다양한 방법으로 경로 수집 후, <code>라우팅 테이블</code>에 저장한다. 그 후 최적 경로로 패킷을 보낸다.</p>
<p>경로 수집 방법은 아래와 같다.</p>
<ol>
<li>다이렉트 커넥티드 (인접 네트워크 정보를 얻는 방법)</li>
<li>스태틱 라우팅 (관리자가 직접 입력하는 방법)</li>
<li><strong>다이나믹 라우팅</strong> (서로 경로를 자동 교환하는 방법)</li>
</ol>
<blockquote>
<p>특히 다이나믹 라우팅에 대해서는 아래에서, 자세히 살펴보겠다.</p>
</blockquote>
<h3 id="2-브로드캐스트-컨트롤">2. 브로드캐스트 컨트롤</h3>
<p>패킷의 목적지 주소가 <strong>라우팅 테이블에 없으면 패킷을 버린다.</strong></p>
<ul>
<li>만약 불분명한 패킷을 플러딩하면 인터넷은 쓸모 없는 패킷으로 가득차 통신 불가능 상태가 될 수 있다.(물런 TTL 개념 존재)</li>
</ul>
<h3 id="3-프로토콜-변환">3. 프로토콜 변환</h3>
<ul>
<li>라우터의 또 다른 역할은 서로 다른 프로토콜로 구성된 네트워크를 연결하는 것</li>
<li>현재는 이더넷으로 수렴되어 이 역할이 줄었다.</li>
</ul>
<p>그럼에도 과거나 현재도 LAN에서 사용하는 프로토콜과 WAN에서 사용하는 프로토콜이 전혀 다른 완전히 구분된 공간</p>
<ul>
<li>LAN은 다수 컴퓨터가 함께 통신하는 것에 초점, WAN은 원거리 통신에 중점</li>
</ul>
<h2 id="hop-by-hop">Hop-by-Hop</h2>
<p><img src="https://images.velog.io/images/juna-dev/post/0ac53ef8-2047-4af3-833f-ff43829beb61/hop-by-hop.png" alt=""></p>
<blockquote>
<p><a href="https://catsbi.oopy.io/225439bd-ec84-4e16-aeca-0dfcb9954ea6">IT엔지니어를 위한 네트워크 입문 요약</a></p>
</blockquote>
<p>위 이미지에서 보이듯, 출발점에서 목적지 단말까지 모든 경로를 한번에 이동하지 않는다.</p>
<ul>
<li>또한 각각의 라우터는 패킷이 목적지까지 가는 전체 경로를 파악하지 않고, 최적의 넥스트 홉으로 보낸다.</li>
<li>참고로 위 홉을 하나 지날때마다 TTL 값이 1씩 감소된다.</li>
</ul>
<Br/>

<h2 id="다이나믹-라우팅">다이나믹 라우팅</h2>
<p>이제 위에서 살펴봤던, 경로 수집 방식 중 &#39;다이나믹 라우팅&#39;에 대해 설명하겠다.</p>
<p>다이나믹 라우팅은 라우터끼리 자신이 알고 있는 경로 정보를 교환해 전체 네트워크 정보를 학습하는 경로 수집 방법이다.</p>
<ul>
<li><strong>주기적으로 라우터끼리 경로 정보가 교환된다.</strong></li>
<li>즉 하나의 경로가 장애가 생겨도 이 상황을 인지해 대체 경로로 패킷을 포워딩할 수 있게 된다. </li>
<li>대부분의 네트워크에서 다이나믹 라우팅이 사용된다.</li>
</ul>
<br/>


<p><img src="https://images.velog.io/images/juna-dev/post/4f278238-e5f4-4a32-81f1-dcfa9df20603/dynamic-routing.png" alt=""></p>
<ul>
<li><strong>다이나믹 라우팅에선 자신이 존재한다고 알려줄(<code>Announce</code>) 네트워크를 선언해줘야 한다.</strong></li>
</ul>
<br/>

<p>라우터끼리 정보를 교환해 경로 정보를 최신으로 유지할 수 있는, 다이나믹 라우터는 다양한 프로토콜이 존재한다.</p>
<ul>
<li>최근에는 OSPF와 <code>BGP 프로토콜</code>이 주로 사용된다.</li>
</ul>
<Br/>

<h1 id="파트3-as와-bgp">파트3. AS와 BGP</h1>
<h3 id="autonomous-system">Autonomous System?</h3>
<p>인터넷을 &quot;네트워크의 네트워크&quot;라고 한다. </p>
<ul>
<li>인터넷에서는 개별 네트워크로 구성된 그룹이 다른 대규모 조직에 의해 관리되는 다른 네트워크 그룹과 연결된다. </li>
</ul>
<p>이와 같은 하나의 네트워크 그룹을 자율 시스템(Autonomous System, AS)이라고 한다.</p>
<ul>
<li>즉 인터넷은 이러한 AS들의 네트워크이다</li>
</ul>
<p>SKT, KT, LGU+같은 ISP(Internet Service Provider)가 한 개 이상의 AS를 운영.</p>
<h3 id="bgp">BGP?</h3>
<p>BGP는 다른 AS 라우터간 <strong>최신 라우팅 정보를 교환</strong>하는 데 사용되는 EGP(External Gateway Protocol)</p>
<ul>
<li>쉽게 말해, 서로 다른 AS들끼리 &quot;내가 가진 네트워크 대역은 ...이야&quot;</li>
<li>또한 자동으로 이루어지는 <code>Dynamic Routing Protocol</code></li>
</ul>
<br/>

<p>다시 말해, AS들이 서로 라우팅 경로를 주고 받는 프로토콜이 바로 <code>BGP</code></p>
<ul>
<li>AS내부에서 사용하는 라우팅 프로토콜을 IGP(Interior Gateway Protocol)</li>
<li>AS간 통신에 사용하는 라우팅 프로토콜을 EGP(Exterior Gateway Protocol)</li>
<li><strong>라우터는 이렇게 교환한 라우팅 정보를 이용해 패킷을 포워딩한다.</strong></li>
</ul>
<br/>

<p><img src="https://images.velog.io/images/juna-dev/post/e9a607f8-722d-4910-b4f0-0e7e668f517f/as-bgp.png" alt=""></p>
<blockquote>
<p><a href="https://catsbi.oopy.io/225439bd-ec84-4e16-aeca-0dfcb9954ea6">IT엔지니어를 위한 네트워크 입문 요약</a></p>
</blockquote>
<p>두개의 AS가 BGP에 의해 &quot;라우팅 경로&quot;를 교환하는 모습을 추상화한 이미지</p>
<ul>
<li>하나의 AS안에서는 IGP가 라우팅 경로 교환에 프로토콜로 사용되는 것을 알 수 있다. (<code>IS-IS</code> 등)</li>
</ul>
<blockquote>
<p>참고로 AS는 서로 다른 사업자이고, 무작정 통신을 허용해서는 안된다. 인터넷 사업자 간에도 통신 비용을 지불해야 한다.</p>
</blockquote>
<h1 id="파트4-사건-분석">파트4. 사건 분석</h1>
<p>결국 사건은 네트워크 라우팅의 문제였다.</p>
<p>대부분의 기업은 이러한 문제를 경험할 일이 없지만, 페이스북 등 대규모 데이터센터를 운영하는 기업의 경우 직업 AS로써 인터넷 네트워크에 참여한다.</p>
<ul>
<li>즉 페이스북은 ISP를 통하지 않고 직접 인터넷에 연결하고, 직접 관리</li>
</ul>
<p><img src="https://images.velog.io/images/juna-dev/post/8d266ebc-98d4-4e58-9690-f19816508021/image.png" alt=""></p>
<ul>
<li><a href="https://whois.arin.net/rest/asn/AS32934/pft?s=as32934">https://whois.arin.net/rest/asn/AS32934/pft?s=as32934</a></li>
</ul>
<br/>

<p>AS들의 라우터는 라우팅 테이블은 BGP 프로토콜에 의해 갱신, 유지된다. </p>
<ol>
<li>페이스북 AS는 특정 IP prefix가 자신에게 속한다고 지속적으로 주변 노드에게 <code>Announce</code> 해야 한다.(<code>BGP advertisement</code>)</li>
<li>하지만 &quot;어떠한 이유&quot;로 이러한 <code>Announce</code>를 중단</li>
<li>따라서 AS 네트워크에서 사라졌다 (BGP Down)</li>
</ol>
<pre><code>Due to Facebook stopping announcing their DNS prefix routes through BGP
DNS resolvers had no way to connect to their nameservers.</code></pre><p>다시말해, 페이스북은 인터넷이라는 세상 속에서 단절되어, 사라지게 된 것이다.</p>
<pre><code>Facebook and its sites had effectively disconnected themselves from the Internet.

As a direct consequence of this,
DNS resolvers all over the world stopped resolving their domain names.</code></pre><br/>

<p>그 후, 다시 <code>BGP Announce</code> 를 시작하고 연결이 재개 되었다. (BGP Up)</p>
<ul>
<li>물리적인 통신선이 절단된 것은 아님으로 다시 <code>Announce</code> 후 인터넷에 참여</li>
<li>이때부터, 다른 AS 라우터의 라우팅 테이블에 페이스북이 포함된다. </li>
<li>즉 트래픽을 주고 받을 수 있게 된다.</li>
</ul>
<br/>

<h3 id="만약-누군가dns-facebookcom-ip-주소를-기억하고-있었다면-접속이-가능했을까">만약 누군가(DNS) facebook.com IP 주소를 기억하고 있었다면 접속이 가능했을까?</h3>
<p>결론은 아니다. </p>
<ul>
<li>이 사건은 페이스북 네트워크로 가는 route(경로)가 사라진 것이다.</li>
<li>사라진건 페이스북의 Authoritative Nameserver만이 아니다.</li>
</ul>
<br/>

<h3 id="페이스북-내부에-어떠한-사건이-있었을까">페이스북 내부에 어떠한 사건이 있었을까?</h3>
<blockquote>
<p>configuration changes on the backbone routers that coordinate network traffic between our data centers caused issues that interrupted this communication. </p>
</blockquote>
<blockquote>
<p>더 자세한 정보는 <a href="https://engineering.fb.com/2021/10/05/networking-traffic/outage-details/">Facebook: More details about outage</a></p>
</blockquote>
<p>한마디로 정리하면 &quot;설정 변경 잘못&quot; </p>
<ol>
<li>글로벌 백본(?) 가용성을 평가하기 위한 명령이 오동작</li>
<li>글로벌 데이터센터와 지역 데이터센터와의 연결을 끊음</li>
<li>안정적 운영을 위해서 지역 DC의 DNS는, 상위 글로벌 DC와 연결이 안될 경우 다른 ISP로 <code>BGP Announce</code> 중단</li>
<li>3번 이유로 DNS 서버는 여전히 동작 중이나, 인터넷에서 Facebook이 사라짐</li>
</ol>
<blockquote>
<p>참고로 3번에서 언급하는 DNS는 페이스북의 지역 Authoritative NS라고 추측.</p>
</blockquote>
<br/>

<h3 id="왜-복구에-오래걸렸나">왜 복구에 오래걸렸나?</h3>
<ol>
<li>네트워크가 다운되어 정상적인 수단을 통해 DC에 엑세스 불가</li>
<li>전체 네트워크의 실종으로 모든 내부 툴의 사용 불가 </li>
<li>엔지니어가 데이터센터로 갔으나, 물리적/시스템 보안등으로 지연</li>
</ol>
<br/>

<h1 id="파트5-결론">파트5. 결론</h1>
<blockquote>
<p>인터넷이 수백만 개의 시스템과 프로토콜이 함께 작동하는 매우 복잡하고 상호의존적인 시스템이라는 것을 상기시킨다. 기업 간의 신뢰, 표준화 및 협력이 전 세계 50억 명에 가까운 유저를 위해 작동되도록 한다.
<a href="https://blog.cloudflare.com/october-2021-facebook-outage/?fbclid=IwAR0woPKgVDYbxcuw0z1hI2YoBiFi24WFG84CbUSM9IRpO_mtlIY9M_9sJa4">Cloudflare</a></p>
</blockquote>
<p>하나의 사건을 중심으로, 아래와 같이 학습했습니다.</p>
<ol>
<li>이해안되는 부분 검색 </li>
<li>검색 내용 학습</li>
<li>다시 1번 반복</li>
</ol>
<br/>

<p>아무래도 글의 흐름이 중구난방한 부분이 느껴지실 것 같습니다.</p>
<ul>
<li>학습 내용을 정리하다보니, 이 부분은 양해 부탁드립니다 (_ _)</li>
<li>몇일동안 밤새 학습한 내용을 담았습니다!</li>
</ul>
<br/>

<p>참고로 이 글을 작성 한 이유 KT 네트워크 장애 사건(2021.10.25)이 발생했습니다.</p>
<ul>
<li>이 사건 또한 &quot;라우터간의 통신&quot; 이슈였습니다. (BGP가 아니라 내부 네트워크 프로토콜인 IGP에 의해)</li>
<li><a href="https://www.msit.go.kr/bbs/view.do?sCode=user&amp;mId=113&amp;mPid=112&amp;pageIndex=&amp;bbsSeqNo=94&amp;nttSeqNo=3180886&amp;searchOpt=ALL&amp;searchTxt=">과기부 KT 네트워크 장애 분석 보도자료</a></li>
<li>매우 읽기 쉽게 잘 쓰여진 글입니다. (wow...)</li>
</ul>
<br/>

<p>더 자세한 학습은 아래 참고 부분의 각 링크에서 가능합니다.</p>
<h1 id="참고">참고</h1>
<p>DNS 파트</p>
<ul>
<li><a href="http://www.codns.com/b/B05-162">CODNS - DNS란 무엇입니까?</a></li>
<li><a href="https://www.cloudflare.com/learning/dns/what-is-dns">Cloudflare - What is DNS?</a></li>
<li><a href="https://aws.amazon.com/route53/what-is-dns/?nc1=h_ls">AWS - What is DNS?</a></li>
</ul>
<p>라우터, AS, BGP 파트</p>
<ul>
<li>길벗 &lt;IT 엔지니어를 위한 네트워크 입문&gt;</li>
<li><a href="https://www.itworld.co.kr/t/62078/%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC/181614">&quot;인터넷이 지구 반대편을 연결하는 방법&quot; BGP의 개념과 동작 원리</a></li>
<li><a href="https://www.msit.go.kr/bbs/view.do?sCode=user&amp;mId=113&amp;mPid=112&amp;pageIndex=&amp;bbsSeqNo=94&amp;nttSeqNo=3180886&amp;searchOpt=ALL&amp;searchTxt=">과기부 KT 네트워크 장애 분석 보도자료</a></li>
</ul>
<p>사건 분석 파트</p>
<ul>
<li><a href="https://engineering.fb.com/2021/10/05/networking-traffic/outage-details/">Facebook: More details about outage</a></li>
<li><a href="https://blog.cloudflare.com/october-2021-facebook-outage/?fbclid=IwAR0woPKgVDYbxcuw0z1hI2YoBiFi24WFG84CbUSM9IRpO_mtlIY9M_9sJa4">Cloudflare: Understanding How Facebook Disappeared from the Internet</a></li>
<li><a href="https://youtu.be/9NBv7lKrG1A">Youtube: BGP hijack Explained</a></li>
<li><a href="https://dataportal.kr/14?fbclid=IwAR2zI6PrBfSxMf2kKh1g9qoXZ3nSdBXbsHP_vqDyVYqhTqBbtr-i-lhBU2M">Facebook을 다운 시킨 원인, BGP hijaking</a></li>
<li><a href="https://www.hani.co.kr/arti/society/society_general/525718.html">선관위 접속장애에 대한 기술적 설명</a></li>
<li><a href="https://cafe.naver.com/neteg?iframe_url_utf8=%2FArticleRead.nhn%253Fclubid%3D10344409%2526page%3D1%2526boardtype%3DL%2526articleid%3D237841%2526referrerAllArticles%3Dtrue">네트워크 전문가 따라잡기 카페: 페이스북 장애 업데이트 상세</a></li>
</ul>
<p>또한 전체적인 흐름을 자세히 공부하고 싶다면 <a href="https://www.youtube.com/watch?v=-wMU8vmfaYo">Why was Facebook down for five hours?</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[navigator.mediaDevices undefined 해결]]></title>
            <link>https://velog.io/@juna-dev/navigator.mediaDevices-undefined-%ED%95%B4%EA%B2%B0</link>
            <guid>https://velog.io/@juna-dev/navigator.mediaDevices-undefined-%ED%95%B4%EA%B2%B0</guid>
            <pubDate>Thu, 12 Mar 2020 16:51:59 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p><code>MediaDevices</code> 인터페이스는 카메라, 마이크, 공유 화면 등 현재 연결된 미디어 입력 장치로의 접근 방법을 제공하는 인터페이스입니다. 다르게 말하자면, 미디어 데이터를 제공하는 모든 하드웨어로 접근할 수 있는 방법입니다. - MDN</p>
</blockquote>
<p><a href="https://stackoverflow.com/questions/34165614/navigator-mediadevices-getusermedia-is-not-working-and-neither-does-webkitgetuse">문제 해결법 참고</a></p>
<h2 id="원인">원인</h2>
<p>최신 크롬에선 안전하지 않을경우, 즉 https가 아닐경우
mediaDevices 객체를 제공하지 않는다고 한다.</p>
<h2 id="해결법">해결법</h2>
<p>chrome://flags/#unsafely-treat-insecure-origin-as-secure</p>
<p>위 링크에 들어가, 보안 정책을 무시할려는 주소를 적고 재시작한다</p>
<p>포트가 있을경우, 포트까지 적어준다</p>
<p><code>http://localhost:3000</code> 등...</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[계층형 게시판 구현하기]]></title>
            <link>https://velog.io/@juna-dev/%EA%B3%84%EC%B8%B5%ED%98%95-%EA%B2%8C%EC%8B%9C%ED%8C%90-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0-dfk4xodtk8</link>
            <guid>https://velog.io/@juna-dev/%EA%B3%84%EC%B8%B5%ED%98%95-%EA%B2%8C%EC%8B%9C%ED%8C%90-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0-dfk4xodtk8</guid>
            <pubDate>Fri, 03 Jan 2020 04:46:44 GMT</pubDate>
            <description><![CDATA[<p>이 게시글은 아래와 같은 구조를 구현하기 위한 방법을 알려드립니다</p>
<p>글을 기준으로 알려드리지만
결국 댓글, 카테고리 도 같은 구조로 구현 가능합니다.
이름만 변경하시면 됩니다</p>
<pre><code>글 =&gt; 답글 =&gt; 답답글 =&gt; 답답답글....
댓글 =&gt; 대댓글 =&gt; 대대댓글 =&gt; 대대대댓글....
카테고리 =&gt; 2단계 카테고리 =&gt; 3단계 카테고리....</code></pre><p>원글 : <a href="http://mikehillyer.com/articles/managing-hierarchical-data-in-mysql/">http://mikehillyer.com/articles/managing-hierarchical-data-in-mysql/</a>
구글 번역글 : <a href="http://hmjkor.tistory.com/472">http://hmjkor.tistory.com/472</a>
번역글 : <a href="https://wooriworld2006.tistory.com/417">https://wooriworld2006.tistory.com/417</a></p>
<p>저는 원글과 구글 번역글을 참고해서 이 게시글을 작성했습니다</p>
<h2 id="db-구조">DB 구조</h2>
<p><img src="https://images.velog.io/post-images/juna-dev/eac31120-2de3-11ea-977f-259819423d02/%EA%B3%84%EC%B8%B5%ED%98%95%EA%B2%8C%EC%8B%9C%ED%8C%90.PNG" alt="계층형게시판.PNG"></p>
<h2 id="글-생성">글 생성</h2>
<p>글 생성시 먼저 자신의 <code>lft</code>, <code>rgt</code> 정보가 필요합니다.
다만 <code>lft = rgt - 1</code></p>
<ol>
<li>부모가 없는 원글 생성일때</li>
</ol>
<pre><code class="language-sql">SELECT MAX(rgt) AS max_rgt
FROM post;</code></pre>
<p><code>rgt = max_rgt + 1</code> 입니다
<code>rgt</code>, <code>lft</code>를 가지고 게시글을 생성합니다</p>
<ol start="2">
<li><strong>부모가 있는</strong> 자식글 생성</li>
</ol>
<p>먼저 부모 글을 조회합니다.</p>
<pre><code>SELECT *
FROM post AS parent
WHERE post_id = {parent_id}</code></pre><p><code>rgt = parent.rgt + 2</code> 입니다</p>
<p><strong>생성하기전</strong>에 게시글이 들어갈 자리를 비워야합니다
부모글의 오른쪽 글들을 한칸씩 옮길 필요가 있습니다
<code>Transaction</code>을 이용합니다</p>
<pre><code class="language-sql">UPDATE post
SET lft=lft+2 
WHERE ltf &gt; {parent.rgt}</code></pre>
<pre><code class="language-sql">UPDATE post
SET rgt=rgt+2 
WHERE rgt &gt;= {parent.rgt}</code></pre>
<p><code>rgt</code>, <code>lft</code>를 가지고 게시글을 생성합니다</p>
<h2 id="글-수정">글 수정</h2>
<p>글 제목, 내용 수정시 크게 주의할 사항은 필요하지 않다.
글 수정시 <strong>자식 존재시 수정 불가능</strong> 기능이 필요하시면
자식 글 조회 후 처리하시면 됩니다.</p>
<h2 id="글-삭제">글 삭제</h2>
<p>글 삭제시 <strong>자식글 전체 삭제</strong> 또는 <strong>자식 존재시 삭제 불가능 기능</strong>이 필요하시면
자식 글 조회 후 처리하시면 됩니다.
삭제 글, 오른쪽 글들의 <code>lft</code>, <code>rgt</code>의 변경을 원하신다면 아래를 참고해주세요
(삭제된 post의 오른쪽 글을 왼쪽으로 한칸 옮기는 기능)</p>
<pre><code class="language-sql">UPDATE post
SET rgt = rgt - 
 (CASE 
 WHEN (rgt &gt; {post.rgt}) THEN 2 
 WHEN (lft &gt; {post.lft} AND rgt &lt; {post.rgt}) THEN 1 
 ELSE 0 END)</code></pre>
<pre><code>UPDATE post
SET lft = lft - 
 (CASE 
 WHEN (lft &gt; {post.rgt}) THEN 2
 WHEN (lft &gt; {post.lft - 1} AND rgt &lt; {post.rgt - 1})
 THEN 1 
 ELSE 0 END)</code></pre><h2 id="글-목록-조회">글 목록 조회</h2>
<p><code>MySQL</code>과 <code>Javascript</code>를 기준으로 작성합니다</p>
<p>게시글 정렬시 원글끼리의 정렬방법과 자식끼리의 정렬방법이 다릅니다.
보통 일반적인 게시판은 아래와 같이 정렬됩니다.</p>
<table>
<thead>
<tr>
<th>depth</th>
<th>제목</th>
<th>작성일</th>
</tr>
</thead>
<tbody><tr>
<td>1단계</td>
<td>제목</td>
<td>01/07</td>
</tr>
<tr>
<td>1단계</td>
<td>제목</td>
<td>01/06</td>
</tr>
<tr>
<td>1단계</td>
<td>애국가</td>
<td>01/02</td>
</tr>
<tr>
<td>2단계</td>
<td>[답글]동해물과</td>
<td>01/<strong>03</strong></td>
</tr>
<tr>
<td>2단계</td>
<td>[답글]백두산이</td>
<td>01/<strong>04</strong></td>
</tr>
<tr>
<td>2단계</td>
<td>[답글]마르고</td>
<td>01/<strong>05</strong></td>
</tr>
<tr>
<td>1단계</td>
<td>제목</td>
<td>01/01</td>
</tr>
</tbody></table>
<p>위 예시를 살펴보면</p>
<ol>
<li>1단계(원글)는 <strong>최신글이 앞</strong>으로 정렬</li>
<li>2단계(자식)는 <strong>최신글이 뒤</strong>로 정렬
정렬방법이 서로 다른걸 확인 할 수 있습니다.</li>
</ol>
<pre><code class="language-sql">SELECT *
FROM post
ORDER BY lft DESC;</code></pre>
<p>위와 같은 쿼리는 원글 정렬은 만족하지만 자식 정렬은 만족하지 못합니다
먼저 두가지 값이 필요합니다.
<code>max_depth</code> : 최대 깊이
<code>max_count_per_depth</code> : 단계당 최대 글 개수
두 값 모두 필수이며, 최대 크기 제한이 필요합니다
글 생성시 <code>max_depth</code>와 <code>max_count_per_depth</code> 를 체크해주세요</p>
<p>또한 게시글 전체 조회 기능을 막으시고
<code>page_num</code>(현재 페이지 넘버)와 <code>page_length</code>(한 페이지 당 길이)를 필수값으로 사용해주세요</p>
<p>자식이 영원히 늘어날 수 없으며, 한번에 전체를 조회 할 수 없게 합니다.
위 4가지 값을 통해, 목록 조회시 필요한 <code>offset</code>과 <code>limit</code>을 구합니다 (<code>MySQL</code>기준)</p>
<p>만약 n개의 글이 필요하다면, 조회 방법은 다음과 같습니다.</p>
<ol>
<li>여분의 길이 를 구한다.</li>
<li>n + 여분 길이의 글을 DB에서 가져온다</li>
<li>부모-자식을 정렬 한다</li>
<li>필요없는 여분의 게시글을 제거한다</li>
</ol>
<h3 id="1-여분의-길이를-구한다">1. 여분의 길이를 구한다</h3>
<pre><code class="language-javascript">function getExtraLength(page_num, page_length, max_depth, max_count_per_depth) {
  let start_index = max_depth * max_count_per_depth;
  let offset = (page_num - 1) * page_length;
  let limit = parseInt(limit) + extra_length;

  if (offset &gt; extra_length) {
    start_index = extra_length;
    offset = (offset - front_minus) || 0;
    limit += extra_length;
  }

  return {
    offset,
    limit,
    start_index,
  }
};</code></pre>
<p>여분이 포함된 게시글을 조회합니다</p>
<h3 id="2-select">2. SELECT</h3>
<pre><code>SELECT *
FROM post
ORDER BY lft DESC
LIMIT {limit}
OFFSET {offset};</code></pre><p>결과값을 <code>results</code>라고 부르겠습니다.</p>
<h3 id="3-부모-자식-정렬">3. 부모-자식 정렬</h3>
<p>results를 부모-자식 관계에 맞게 lft와 rgt를 통해 정렬합니다
반복문과 조건문을 사용해주세요</p>
<h3 id="4-여분-제거">4. 여분 제거</h3>
<pre><code class="language-javascript">end_index = (start_index + page_length) - 1</code></pre>
<p><code>results</code>에서 <code>start_index</code> 부터 <code>end_index</code> 까지 게시글을 구합니다.
그 후 여분을 제거한 <code>results</code> 를 반환합니다</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[해시태그 구현하기]]></title>
            <link>https://velog.io/@juna-dev/%ED%95%B4%EC%8B%9C%ED%83%9C%EA%B7%B8-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0-9ak4xocihh</link>
            <guid>https://velog.io/@juna-dev/%ED%95%B4%EC%8B%9C%ED%83%9C%EA%B7%B8-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0-9ak4xocihh</guid>
            <pubDate>Fri, 03 Jan 2020 04:45:31 GMT</pubDate>
            <description><![CDATA[<p>해시태그를 구현하는 2가지 방법에 대해서 소개하고자 합니다.</p>
<h2 id="간단한-방법">간단한 방법</h2>
<p><img src="https://images.velog.io/post-images/juna-dev/c678e7e0-2de3-11ea-977f-259819423d02/%EA%B8%B0%EB%B3%B8.PNG" alt="기본.PNG"></p>
<p>문자열 hashtag 필드를 사용할경우 간단한 추가/수정이 가능합니다</p>
<pre><code class="language-sql">INSERT INTO post (title, content, hashtag) 
VALUES (&#39;제목&#39;, &#39;내용&#39;, &#39;#강아지#고양이&#39;);</code></pre>
<pre><code class="language-sql">UPDATE post SET title = &#39;제목&#39;, content = &#39;수정 내용&#39;, hashtag = &#39;#멍멍이#고양이&#39; 
WHERE (post_id = 1);</code></pre>
<p>다만 단점은 해시태그 조회가 어렵습니다</p>
<ol>
<li>현재 게시글에서 사용중인 해시태그 파악 어렵습니다<ul>
<li>요번주 트렌드 해시태그 목록</li>
<li>등록된 모든 해시태그</li>
</ul>
</li>
<li>특정 해시태그를 통해 글을 찾기 어렵습니다.<ul>
<li><code>#강아지</code> 를 사용하는 글 조회</li>
</ul>
</li>
</ol>
<h2 id="해시태그와-글을-분리하는-방법">해시태그와 글을 분리하는 방법</h2>
<p><img src="https://images.velog.io/post-images/juna-dev/ca05b820-2de3-11ea-977f-259819423d02/%EB%B6%84%EB%A6%AC.PNG" alt="분리.PNG"></p>
<p>위 구조의 장점은 앞서 소개했던 문자열 필드의 단점을 해결할 수 있습니다.
즉 더 많은 기능 구현이 가능합니다
다만 생성,수정,삭제와(태그와 게시글 사이의 관계 관리) 조회가 보다 복잡해집니다</p>
<h3 id="insertupdatedelete">INSERT/UPDATE/DELETE</h3>
<ol>
<li><code>트랜잭션</code>을 이용해야합니다.</li>
<li>만약 글에 등록하고자 하는 태그가 없다면 tag 테이블에 먼저 추가해야합니다</li>
<li><code>post</code>에 글을 추가/수정합니다.<ul>
<li><code>INSERT</code>한 글 <strong>PK</strong>를 구합니다</li>
</ul>
</li>
<li><code>post_id</code>를 통해 <code>post_tag</code> 테이블에 해시태그들을 추가합니다</li>
<li>커밋</li>
</ol>
<p>다만 <strong>글과 해시태그를 수정할때</strong>는
사용하고 있는 해시태그들과 새로 추가,삭제된 해시태그를 잘 살펴주시기 바랍니다</p>
<p><strong>글을 삭제할때</strong>는
<code>post_tag</code> 테이블에 <code>post</code> 테이블과의 관계 설정시 <code>ON DELETE CASCADE</code> 를 사용하시면 됩니다
다만 누구도 참조하지 않는 태그는 삭제하시고 싶으시다면 먼저 체크를 해야합니다</p>
<h3 id="select">SELECT</h3>
<p>등록된 해시태그를 원한다면 <code>tag</code> 테이블을 조회하면 됩니다</p>
<table>
<thead>
<tr>
<th>ID</th>
<th>NAME</th>
</tr>
</thead>
<tbody><tr>
<td>1</td>
<td>강아지</td>
</tr>
<tr>
<td>2</td>
<td>고양이</td>
</tr>
<tr>
<td>3</td>
<td>개</td>
</tr>
</tbody></table>
<p>다만 <strong>트렌드 해시태그기능</strong>을 구현하고자한다면 <code>post_tag</code>에 생성일(태그-글 연결일)을 추가해야합니다</p>
<p><strong>특정 해시태그를 통해 글을 찾는다면</strong></p>
<pre><code class="language-sql">SELECT post.* 
FROM post_tag
JOIN post ON post.post_id = post_tag.post_id
WHERE post_tag.tag_id = 1</code></pre>
<p>위 쿼리는 <code>#강아지</code> 를 사용하는 글을 조회하는 방법입니다.</p>
<p>저는 <code>tag_id</code> 를 사용했지만 <code>tag</code> 테이블에서 문자열을 통해 원하는 태그를 찾고
<code>post_tag</code>와 <code>post</code>를 <code>JOIN</code>하는 방법도 사용해보세요</p>
<p>여러 해시태그를 통해 글을 찾는다면 해시태그 다중 검색이라고 하나요?</p>
<p>예를들어서 #강아지#고양이 이라고 검색창에 입력한다면</p>
<p>강아지와 고양이 태그를 모두 등록한 게시글만 검색되어야 합니다.</p>
<p>방법은 아래와 같습니다</p>
<pre><code class="language-sql">SELECT post.* 
FROM post_tag
JOIN post ON post.post_id = post_tag.post_id
WHERE post_tag.tag_id IN (1,2)
GROUP BY post_tag.post_id
HAVING (COUNT(post_tag.tag_id) = 2);</code></pre>
<p>만약 게시판 페이지네이션 기능을 위해</p>
<p>글 조회시 <code>limit</code>(MySQL) 을 사용하셨다면
<code>limit</code>을 사용하지 않은, 전체 글의 개수를 구해야합니다
아래와 같은 방법으로 전체 글 개수를 구할 수 있습니다</p>
<pre><code>SELECT COUNT(*)
FROM (SELECT post.post_id 
    FROM post_tag 
    INNER JOIN post ON (post.post_id = post_tag.post_id)
    WHERE (post_tag.tag_id IN (1, 2))
    GROUP BY post_tag.post_id 
    HAVING (COUNT(post_tag.tag_id) = 2))</code></pre>]]></description>
        </item>
    </channel>
</rss>