<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>emotional_dev.log</title>
        <link>https://velog.io/</link>
        <description>Emotional Developer</description>
        <lastBuildDate>Thu, 30 Nov 2023 05:12:05 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>emotional_dev.log</title>
            <url>https://velog.velcdn.com/images/emotional_dev/profile/46c80d45-c79d-47f1-9c9c-300b0cdddcb7/image.jpeg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. emotional_dev.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/emotional_dev" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[JPA] Entity Manager & Persistence Context]]></title>
            <link>https://velog.io/@emotional_dev/JPA-%EC%98%81%EC%86%8D%EC%84%B1-%EC%BB%A8%ED%85%8D%EC%8A%A4%ED%8A%B8</link>
            <guid>https://velog.io/@emotional_dev/JPA-%EC%98%81%EC%86%8D%EC%84%B1-%EC%BB%A8%ED%85%8D%EC%8A%A4%ED%8A%B8</guid>
            <pubDate>Thu, 30 Nov 2023 05:12:05 GMT</pubDate>
            <description><![CDATA[<h2 id="entity-manager-factory--entity-manager">Entity Manager Factory &amp; Entity Manager</h2>
<p>Entity Manager는 JPA 에서 매핑한 엔티티를 CRUD 하는 모든 작업을 처리합니다.
Entity Manager Factory는 이러한 Entity Manager를 생성하는 곳이며 일반적으로 연결된 DB당 하나씩 생성합니다.
Factory를 생성하는 비용은 상당히 크기 때문에 생성 후 어플리케이션 전체에서 공유되도록 설계되어 있으며, 반면에 Entity Manager의 생성 비용은 거의 들지 않습니다.
또한 Entity Manager Factory는 Thread-safe하게 설계되어있지만 Entity Manager는 동시 접근 시 문제가 발생할 수 있으므로 공유가 되어서는 안됩니다.
Hibernate를 포함한 JPA 구현체들은 Entity Manager Factory를 생성할 때 Connection Pool을 함께 생성하며, Entity Manager는 생성된 후에 보통 트랜잭션을 시작할 때 해당 커넥션을 획득합니다.</p>
<hr>
<h2 id="persistence-context-영속성-컨텍스트">Persistence Context (영속성 컨텍스트)</h2>
<p>JPA를 이해하는 데 가장 중요한 용어이며 실질적으로 보이지 않아 헷갈릴 수 있지만 &#39;엔티티를 영구 저장하는 논리적인 영역&#39;을 의미합니다.
Entity Manager로 엔티티를 저장, 조회하면 해당 영속성 컨텍스트에 저장합니다.
영속성 컨텍스트 또한 엔티티 매니저가 생성될 때마다 생성이 되며 엔티티 매니저를 통해 영속성 컨텍스트에 접근합니다.
경우에 따라 여러 엔티티 매니저가 동일한 영속성 컨텍스트에 접근 또한 가능합니다.</p>
<hr>
<h2 id="엔티티의-생명주기">엔티티의 생명주기</h2>
<p><img src="https://velog.velcdn.com/images/emotional_dev/post/36d91458-01be-4adf-befd-082fa79ff5ff/image.png" alt=""></p>
<h3 id="비영속-new--transient">비영속 (New / Transient)</h3>
<p>영속성 컨텍스트나 DB와 전혀 관계가 없는 순수한 객체 상태.</p>
<pre><code>Member member = new Member();</code></pre><h3 id="영속-managed">영속 (Managed)</h3>
<p>엔티티 매니저를 통해 엔티티를 영속성 컨텍스트에 저장한 상태.
이제 영속성 컨텍스트에 의해 관리가 되는 상태이며 영속성 컨텍스트의 이점을 적용받게 됩니다.
해당 이점은 아래에 작성하겠습니다.</p>
<pre><code>em.persist(member)</code></pre><h3 id="준영속-detached">준영속 (Detached)</h3>
<p>특정 엔티티를 영속성 컨텍스트에서 제거하거나 (em.detach)
영속성 컨텍스트를 닫거나 (em.close)
영속성 컨텍스트를 초기화 하는 경우 (em.clear)
엔티티가 영속성 컨텍스트에서 분리되어 더 이상 관리되지 않는 상태입니다.
비영속 상태에 가깝지만 영속 상태였기 때문에 식별자의 존재는 보장이 됩니다.
나중에 정리할 지연 로딩 또한 지원이 되지 않습니다.</p>
<pre><code>em.detach(member)
em.close()
em.clear()</code></pre><h3 id="삭제-removed">삭제 (Removed)</h3>
<p>엔티티를 영속성 컨텍스트와 DB에서 삭제한 상태.</p>
<pre><code>em.remove(member)</code></pre><hr>
<h2 id="영속성-컨텍스트-이점">영속성 컨텍스트 이점</h2>
<h3 id="1차-캐시">1차 캐시</h3>
<p><img src="https://velog.velcdn.com/images/emotional_dev/post/c8e2bc10-7e20-47d3-82e2-2e501ff40a16/image.png" alt="">
영속성 컨텍스트는 내부에 캐시를 갖고 있으며 해당 캐시를 1차 캐시라 부르며 영속 상태의 엔티티는 모두 이곳에 저장됩니다.
1차 캐시의 키는 식별자 값이며 테이블의 PK와 매핑되어 있습니다.
em.find()를 통해 엔티티를 조회하면 우선적으로 메모리에 1차 캐시를 조회하며 캐시에 존재하지 않으면 그 때 DB를 통해 조회합니다.
하지만 해당 캐시는 보통 사용자 요청마다 생성이 되는 영속성 컨텍스트 내에 있기 때문에 엄청 복잡한 비즈니스 로직이 아니라면 큰 성능상의 효과는 없는 편입니다.</p>
<h3 id="동일성-보장">동일성 보장</h3>
<p>영속성 컨텍스트는 자바 컬렉션 내의 객체와 같이 식별자가 같다면 반복해서 조회하더라도 동일한 엔티티를 반환합니다.</p>
<pre><code>Member a = em.find(Member.class, &quot;member1&quot;);
Member b = em.find(Member.class, &quot;member1&quot;);
System.out.println(a == b);</code></pre><h3 id="트랜잭션을-지원하는-쓰기-지연">트랜잭션을 지원하는 쓰기 지연</h3>
<p><img src="https://velog.velcdn.com/images/emotional_dev/post/5f35d274-98d9-4dcb-bf5a-f5501ee17a14/image.png" alt=""></p>
<pre><code>em.persist(memberA);
em.persist(memberB);
// 여기 까지는 &#39;쓰기 지연 저장소&#39;에만 저장이 되며 실제 INSERT SQL을 보내지 않음
transaction.commit();
// 트랜잭션 커밋과 동시에 저장소에 모아놓은 쿼리를 한번에 날림</code></pre><h3 id="변경-감지">변경 감지</h3>
<p>기존 SQL 수정 쿼리의 문제점은 테이블의 컬럼이 늘어날 수록 각각에 맞는 수정 쿼리가 많아지는 것은 물론이고 비즈니스 로직을 분석하기 위해 SQL을 계속 확인해야 하기 때문에 직간접적으로 비즈니스 로직이 SQL에 의존하게 된다는 점이 문제점입니다.
이를 보완하기 위해 JPA는 엔티티의 처음 저장할 때 최초 상태를 담은 스냅샷을 함께 저장해둡니다.
그리고 영속성 컨텍스트의 내용을 DB에 반영하는 &#39;Flush&#39;라는 이벤트가 발생하면 1차 캐시에 저장된 스냅샷과 엔티티가 다르다면 수정 쿼리를 작성하여 &#39;쓰기 지연 SQL 저장소&#39;에 저장을 하고 이를 포함하여 저장된 쿼리를 모두 날리게 됩니다.
JPA의 기본 전략은 엔티티의 모든 필드를 업데이트 하는 것이며 이는 하나의 쿼리를 미리 생성하고 재사용할 수 있는 장점이 있습니다.
하지만 데이터 전송량이 부담되는 상황이라면 특정 컬럼만 업데이트할 수 있도록 변경도 가능합니다. (Dynamic Update)</p>
<h3 id="지연-로딩">지연 로딩</h3>
<p>성능 최적화에 중요한 개념이므로 별도로 정리하겠습니다.</p>
<hr>
<h2 id="flush">Flush</h2>
<p>위에서 설명드린 것처럼 영속성 컨텍스트의 변경 내역을 DB에 반영하는 이벤트이며 해당 이벤트가 발생하면 모든 영속 상태의 엔티티를 스냅샷과 비교하여 수정 쿼리를 쓰기 지연 저장소에 등록하고 저장된 쿼리를 DB에 전달합니다.
플러시하는 방법은 아래와 같습니다.</p>
<h3 id="직접-호출">직접 호출</h3>
<p>em.flush()를 통해 강제로 플러시하는 방법이며 테스트할 때 제외하고는 거의 사용하지 않습니다.</p>
<h3 id="트랜잭션-커밋">트랜잭션 커밋</h3>
<p>트랜잭션이 커밋되기 전에 플러시를 통해 DB에 쿼리가 전달이 되어야 데이터 변경이 이루어지기 때문에 JPA는 트랜잭션 커밋 전에 자동으로 플러시를 수행합니다.</p>
<h3 id="jpql-실행">JPQL 실행</h3>
<p>JPQL에서 조회를 할 경우 플러시를 하지 않고 영속 상태일 경우는 JPQL에서 해당 엔티티를 조회하지 못하기 때문에 이를 보완하기 위하여 JPA는 JPQL실행 전 자동으로 플러시를 진행합니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[ELK Stack (2) - 간단한 로그분석 시스템]]></title>
            <link>https://velog.io/@emotional_dev/ELK-Stack-2-%EA%B0%84%EB%8B%A8%ED%95%9C-%EB%A1%9C%EA%B7%B8%EB%B6%84%EC%84%9D-%EC%8B%9C%EC%8A%A4%ED%85%9C</link>
            <guid>https://velog.io/@emotional_dev/ELK-Stack-2-%EA%B0%84%EB%8B%A8%ED%95%9C-%EB%A1%9C%EA%B7%B8%EB%B6%84%EC%84%9D-%EC%8B%9C%EC%8A%A4%ED%85%9C</guid>
            <pubDate>Mon, 27 Nov 2023 03:06:55 GMT</pubDate>
            <description><![CDATA[<h2 id="실습-환경">실습 환경</h2>
<ul>
<li>OS : Cent OS 7</li>
<li>ELK Stack 버전 : 8.11</li>
<li>JDK : 17.0.2</li>
</ul>
<h2 id="시스템-구조">시스템 구조</h2>
<p><img src="https://velog.velcdn.com/images/emotional_dev/post/09146cbe-09ce-4104-8b9a-de3be4ec848e/image.png" alt=""></p>
<h3 id="0-로그-파일-생성">0. 로그 파일 생성</h3>
<p>여러개의 WAS가 동작 중인 상황이고 각 WAS 별로 별개의 로그 파일이 생성되어 파일 시스템에 저장되고 있는 상황을 가정합니다.</p>
<h3 id="1-filebeats">1. Filebeats</h3>
<p>Filebeats를 활용하여 각각의 로그 파일에 접근하여 데이터 수집을 진행합니다.
<img src="https://velog.velcdn.com/images/emotional_dev/post/c3ba2b4b-cd24-4423-a5ff-fcd419fee3a6/image.png" alt="">
multiline 설정을 통해 여러 줄의 로그 내용을 하나의 단위로 수집하도록 설정을 진행합니다.
주석처리된 exclude, include 속성을 활용하여 제외 키워드, 포함 키워드 또한 설정이 가능합니다.</p>
<h3 id="2-filebeats">2. Filebeats</h3>
<p>Filebeats로부터 데이터를 받아 Elasticsearch 적재를 위한 데이터 가공, Elasticsearch 전달을 담당합니다.
<img src="https://velog.velcdn.com/images/emotional_dev/post/faa2c5a3-9fcb-4c42-b169-7aa0cfbbe1de/image.png" alt="">
input 영역에서는 beats를 통해 데이터 수신 설정
filter 영역에서는 데이터 가공 설정을 진행해야 하지만 현재는 별도 가공 없이 전달합니다.
output 영역에서는 전달해야할 elasticsearch 정보 및 index 정보를 설정합니다.</p>
<h3 id="3-elasticsearch">3. Elasticsearch</h3>
<p>Logstash로부터 데이터를 받아 적재하고 인덱싱 처리를 진행합니다.</p>
<p><img src="https://velog.velcdn.com/images/emotional_dev/post/09c1b0b0-f52a-4b44-930a-38a7f750d790/image.png" alt=""></p>
<p>이렇게 전달받은 데이터는 /var/lib/elasticsearch 폴더 내에 인덱싱이 되어 저장됩니다.</p>
<h3 id="4-kibana">4. Kibana</h3>
<p><img src="https://velog.velcdn.com/images/emotional_dev/post/5bb3ad30-38f1-48ee-b862-ef4da792ecf2/image.png" alt="">
데이터 적재 현황을 파악할 수 있는 Kibana Discover 페이지 입니다.
데이터 적재를 위해 WAS에 접속하여 강제로 로그를 생성한 후에 다시 Discover 페이지에 접속합니다.
<img src="https://velog.velcdn.com/images/emotional_dev/post/cc6ca0d1-03bc-4153-8011-24fd15e11513/image.png" alt="">
설정한 기간 내에 몇 건의 데이터가 조회되었는지 카운트와 간단한 차트를 제공하며
아래 테이블에서 Field별로 확인 또한 가능합니다.</p>
<h3 id="5-alert-ms-teams">5. Alert (MS Teams)</h3>
<p>Alert 목표는 각 운영 상황마다 다르겠지만
이번 실습에서는 간단하게 5분 이내에 5회 이상 &#39;ERROR&#39;라는 키워드가 포함된 로그 데이터가 적재되면 지정한 Webhook(MS Teams)을 통해 알림하는 것을 목표로 합니다.</p>
<p><img src="https://velog.velcdn.com/images/emotional_dev/post/a7ee9d68-5d63-4356-97a9-dcbd4a0bba2e/image.png" alt="">
<img src="https://velog.velcdn.com/images/emotional_dev/post/c86821e6-f4b0-4d3b-af39-b215e35b3f5d/image.png" alt="">
Connector 설정을 통해 알림을 보낼 대상을 설정하며
2번째 사진의 Webhook URL에 MS Teams에서 제공받은 Webhook URL을 설정합니다.</p>
<p><img src="https://velog.velcdn.com/images/emotional_dev/post/c3c68123-6a3e-4310-bfc1-6e265bfcfc73/image.png" alt="">
<img src="https://velog.velcdn.com/images/emotional_dev/post/03ecbd14-5509-4bc4-99a8-cc95b2d2e24b/image.png" alt="">
Elastic Search는 루씬기반의 검색엔진이므로 조회를 위해서는 KQL 또는 Lucene 으로 쿼리를 작성해야 합니다.
단순 쿼리로 message 필드의 값 중 &#39;ERROR&#39;라는 키워드가 5분동안 5회 이상 노출되었을 때를 규칙으로 설정합니다.</p>
<p><img src="https://velog.velcdn.com/images/emotional_dev/post/e3c1f2da-c3a5-4ae7-af53-c5a2dba02d6b/image.png" alt="">
현재는 message (로그 메세지) 속성만 사용해서 쿼리를 작성했지만
다른 속성들도 AND/OR로 작성이 가능합니다.</p>
<p><img src="https://velog.velcdn.com/images/emotional_dev/post/bb2d6b55-b622-4b63-8e44-a55af1c9b512/image.png" alt="">
규칙 작성 후에 위에서 설정한 Connector를 연결합니다.</p>
<p><img src="blob:https://velog.io/3417a638-0374-4d52-8ae2-39e3385470e8" alt="업로드중..">
WAS에서 강제로 익셉션을 발생시킨 후 Teams를 보면 KIBANA에서 전달한 Alert가 수신됩니다.
간단한 오류 메세지가 담겨있으며 위에서 알 수 있듯 해당 메세지 또한 활용 가능한 변수들을 조합하여 커스터마이징이 가능합니다.
Link의 값으로 접속하면 해당 내용의 Discover 페이지로 이동합니다.</p>
<hr>
<h2 id="todo">TODO</h2>
<p>이로써 간단한 로그 분석 및 알림 전송 시스템은 실습이 끝났습니다.
나아가서 아래 항목 또한 고려할 필요가 있습니다.</p>
<h3 id="elastic-search-서버-분리">Elastic Search 서버 분리</h3>
<p>Elasticsearch가 비교적 많은 메모리와 저장공간을 차지하며 별도로 Log Rotate를 하지 않는 이상 지속적으로 용량을 차지하기 때문에 적합한 리소스를 갖는 별도의 서버 구축이 필요합니다.
저장한 데이터는 정기적으로 다른 저장소에 전달하는 기능 또한 고려할 수 있습니다.</p>
<h3 id="모니터링-대상-및-규칙-세분화">모니터링 대상 및 규칙 세분화</h3>
<p>실제 운영 환경에 맞는 모니터링 대상 및 알림을 보내는 규칙의 구체화가 필요합니다.</p>
<h3 id="kibana-커스터마이징">Kibana 커스터마이징</h3>
<p>현재는 정말 필요한 기능만 사용했지만 Kibana 는 다양한 기능을 갖고있는 강력한 도구이기 때문에 운영 상황에 맞는 Visualise/Dashboard활용, 알림, 외부 시스템 연동에 대한 고민이 필요합니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[ELK Stack (1) - Stack 설명]]></title>
            <link>https://velog.io/@emotional_dev/ELK-Stack-1-Stack-%EC%84%A4%EB%AA%85</link>
            <guid>https://velog.io/@emotional_dev/ELK-Stack-1-Stack-%EC%84%A4%EB%AA%85</guid>
            <pubDate>Mon, 27 Nov 2023 01:16:39 GMT</pubDate>
            <description><![CDATA[<h2 id="elk-stack">ELK Stack?</h2>
<p>ELK 스택은 E(Elasticsearch), L(Logstash), K(Kibana)라는 데이터 처리 및 활용에 유용한 세가지 오픈소스 프로젝트로 구성된 스택을 의미하는 약어로 시작했으며 2015년 이후 데이터 수집에 유용한 Beats가 Stack에 추가되어 함께 ELK Stack이라고 불립니다.
원래는 별개의 프로젝트였지만 Elastic 측에서 데이터 검색 및 분석 기능에 대한 유연성을 제공하기 위해 스택으로 통합되었으며 이후에 업데이트 또한 함께 버전업이 되어 릴리즈됩니다.
각각의 Stack에 대한 설명은 아래에서 진행하도록 하겠습니다.</p>
<hr>
<h2 id="beats">Beats</h2>
<p>Beats는 로그 스태시와 같이 데이터 전송 역할을 하는 플랫폼입니다.
기존에 수집을 담당하는 Logstash와 다른 점은 FileBeat, MetricBeat와 같이 각 역할에 해당하는 단순한 전송 기능을 수행하는 경량화된 플랫폼이라는 점입니다.
로그 스태시를 사용한다면 데이터 소스의 종류/RDB의 SQL별로 프로세스가 따로 구동되어야 하기 때문에 다양한 데이터 소스를 필요로 하는 시스템에서는 데이터 성격에 맞는 비츠를 구성하여 서비스를 구성하는 것이 더욱 효율적입니다.</p>
<h3 id="filebeats">FileBeats</h3>
<p>File을 수집하는 FileBeats는 다양한 형식의 로그파일을 수집하는 기능을 제공합니다.</p>
<h3 id="metricbeats">MetricBeats</h3>
<p>서버에서 발생하는 다양한 정보를 수집하는 기능을 제공합니다.
CPU 사용률, 메모리 사용률, 네트워크 I/O, 디스크 I/O 등 다양한 정보를 수집하여 엘라스틱 서치로 전송합니다.</p>
<hr>
<h2 id="logstash">Logstash</h2>
<p>자바 기반으로 만들어진 데이터 ETL(Extract, Transform, Load) 제품으로 간단하면서도 다양한 데이터 조회, 변환, 등록 설정을 제공합니다.
하지만 ETL대상마다 Logstash 프로세스를 생성해야하는 단점이 있습니다.</p>
<hr>
<h2 id="elasticsearch">Elasticsearch</h2>
<p>ELK Stack 중 데이터 저장소 역할을 하며 분산 환경으로서 하둡과 같이 자유롭게 Scale out을 지원하며, 데이터 적재 시 수행되는 인덱싱 처리와 메모리 캐싱을 통한 빠른 검색 가능, 사용자 접근이 쉽도록 RESTFUL 방식을 이용한 데이터 접근 등의 특징이 있습니다.</p>
<h3 id="분산처리">분산처리</h3>
<p>Elasticsearch가 빅테이터 플랫폼으로 활용될 수 있는 가장 큰 이유이며 하둡 에코 시스템과 같이 자유롭게 Scaleout이 가능하여 데이터 용량에 제한 없이 필요에 따라 자유로이 스토리지, 자원, 서버등을 확장할 수 있기 때문에 빅데이터의 처리가 가능합니다.</p>
<h3 id="고속-검색을-위한-인덱싱">고속 검색을 위한 인덱싱</h3>
<p>Elasticsearch는 데이터 적재 시 기본적으로 인덱싱하는 과정을 거칩니다.
인덱싱된 데이터는 모두 Document라는 단위의 데이터로 생성되고, 다른 비슷한 인덱싱 프로세스를 가진 솔루션과 달리 이들이 메모리에도 캐싱되어서 고속 검색이 가능합니다.</p>
<h3 id="http-restful-api">HTTP RESTFUL API</h3>
<p>HTTP 프로토콜을 이용한 RESTFUL API 방식으로 데이터 접근이 가능하기 때문에 플랫폼의 제약 없이 데이터 CRUD 작업이 가능하며 Bulk 모드를 통해 대량 건을 한 번에 적재할 수 있는 기능 또한 가능하다.</p>
<h3 id="json-저장-방식">JSON 저장 방식</h3>
<p>Elasticsearch는 데이터 적재 및 관리를 위해 JSON 형식을 사용합니다.
이러한 JSON 타입이 속도 측면에서 빠르다고 할 순 없지만
Key/Value형태인 JSON으로 데이터를 명확하게 관리할 수 있다는 점이 큰 장점이며 
RDB의 NULL 개념과는 달리 필요한 데이터만 Field로 생성하기 때문에 불필요한 영역을 사용하지 않습니다.</p>
<hr>
<h2 id="kibana">Kibana</h2>
<p>ELK Stack에서 시각화를 담당하는 도구입니다.
GUI를 통해 간단하게 데이터 시각화, 차트 구성, 대시보드 생성 등이 가능한 강력한 도구입니다.</p>
<h3 id="discover">Discover</h3>
<p><img src="https://velog.velcdn.com/images/emotional_dev/post/44370777-ddb4-4cb0-a81e-cbe8ed674fb1/image.png" alt=""></p>
<p>Elasticsearch에 적재된 인덱스로 키바나에서 인덱스 패턴 객체를 생성하면 Discover를 통해 데이터 적재 현황을 파악할 수 있습니다.
JSON 필드별로 목록 화면을 조정할 수 있는 기능과 필드별 통계 기능 또한 제공합니다.</p>
<h3 id="visualize">Visualize</h3>
<p><img src="https://velog.velcdn.com/images/emotional_dev/post/540077a1-ac15-4bb0-b458-e820323b50d5/image.png" alt=""></p>
<p>Kibana는 사용자가 직접 데이터를 시각화하고 대시보드를 구성하며 필요에 맞게 분석을 할 수 있는 기능을 제공합니다.
다양한 형식의 차트, 테이블 등을 활용하여 시각화가 가능합니다.</p>
<h3 id="map">Map</h3>
<p><img src="https://velog.velcdn.com/images/emotional_dev/post/9d53dcfb-dcf8-4fb2-9932-68922096b6f9/image.png" alt="">
오픈 스트리트 맵을 비롯한 몇 가지 오픈소스를 활용하여 전세계 지도를 서비스하고, 그 위에 국가, 지역 등을 구분할 수 있는 폴리곤 정보 등을 조합하여 Elastic Maps라는 맵 서비스로 구성하여 서비스하고 있습니다.</p>
<h3 id="dashboard">Dashboard</h3>
<p><img src="https://velog.velcdn.com/images/emotional_dev/post/6b481f93-51a4-484c-9ddc-ff6086c610a4/image.png" alt=""></p>
<p>앞선 Visualize를 통해 생성된 시각화 자료들을 활용하여 하나의 Dashboard로 조합이 가능합니다.
이렇게 생성된 대시보드는 외부에서 확인이 가능하도록 Export가 가능하며 타 시스템에 임베디드가 가능하도록 iframe 형대로도 Export가 가능합니다.</p>
<hr>
<p>다음 게시물에서는 ELK Stack을 활용하여 간단한 로그 분석 시스템 구축과 알림 기능을 하는 시스템을 구축해보겠습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[RestTemplate vs WebClient]]></title>
            <link>https://velog.io/@emotional_dev/RestTemplate-vs-WebClient</link>
            <guid>https://velog.io/@emotional_dev/RestTemplate-vs-WebClient</guid>
            <pubDate>Wed, 23 Aug 2023 08:29:20 GMT</pubDate>
            <description><![CDATA[<h2 id="resttemplate">RestTemplate?</h2>
<p>Spring 3부터 제공되는 전통적인 Blocking HTTP Client입니다.
Apache HttpClient 라이브러리를 활용하여 개발되었으며
HTTP 요청을 생성하기 위해 간단한 API를 제공하며 현재까지도 많은 프로젝트에서 활용되는 HTTP Client입니다.
Java Servlet API를 활용하고 있기 때문에 기본적으로 하나의 스레드당 하나의 요청 방식으로 되어있으며 이는 클라이언트가 응답을 받을 때까지 스레드는 Block 상태이기 때문에 서버 자원과 응답 시간에 영향을 미치는 것을 의미합니다.
또한 많은 요청이 들어오면 이에 비례하여 스레드가 생성되기 때문에 메모리와 스레드풀에 영향을 미치고 잦은 Context Switching으로 인해 효율성이 저하됩니다.</p>
<h2 id="web-client">Web Client?</h2>
<p>Spring 5부터 제공되는 최신 Non-Blocking Reactive HTTP Client입니다.
Non-Blocking을 지원하기 위해 Spring Reactive Framework를 기반으로 개발되었습니다.
Reactive Framework는 Event-Driven 구조를 사용하기 때문에 비동기 로직을 <a href="https://www.baeldung.com/java-9-reactive-streams">Reactive Stream API</a>를 통해 제공하게 됩니다.
이는 RestTemplate와 비교하여 적은 양의 스레드와 시스템 자원만으로 많은 요청을 처리할 수 있음을 의미하기 때문 많은 양의 요청을 병렬로 처리해야하는 경우 적합한 HTTP Client입니다.</p>
<h2 id="resttemplate-vs-web-client-concept">RestTemplate vs Web Client (Concept)</h2>
<p>두 클라이언트간 주요 차이점을 알아보겠습니다.</p>
<h3 id="동기--비동기">동기 / 비동기</h3>
<p>RestTemplate는 요청에 대한 응답이 수신될 때까지 호출한 스레드를 Blocking하는 동기식 클라이언트입니다.
반면에 WebClient는 Non-Blocking 방식이기 때문에 메인 스레드를 차단하지 않고 여러 요청을 동시에 수행이 가능합니다.</p>
<h3 id="반응형--비반응형">반응형 / 비반응형</h3>
<p>RestTemplate은 전통적인 비반응형 클라이언트인 반면, 
WebClient는 반응형 프로그래밍을 지원함으로써 대용량 데이터를 보다 효율적으로 처리할 수 있습니다.</p>
<h3 id="오류-처리">오류 처리</h3>
<p>RestTemplate는 예외를 발생시켜 오류를 처리하는 방식을 사용하고 있습니다.
반면에 WebClient는 반응형 스트림을 사용하여 오류를 전파하기 때문에 오류를 좀 더 쉽게 처리할 수 있습니다.</p>
<h3 id="직렬화--역직렬화">직렬화 / 역직렬화</h3>
<p>RestTemplate는 다른 외부 라이브러리를 통해 객체를 (역)직렬화 하는 반면에
WebClient는 Spring에 내장된 기능을 사용하여 (역)직렬화하기 때문에 별도의 라이브러리가 필요하지 않습니다.</p>
<h2 id="resttemplate-vs-web-client-logic-with-code">RestTemplate vs Web Client (Logic with Code)</h2>
<h3 id="resttemplate-1">RestTemplate</h3>
<pre><code>@GetMapping(&quot;/tweets-blocking&quot;)
public List&lt;Tweet&gt; getTweetsBlocking() {
    log.info(&quot;Starting BLOCKING Controller!&quot;);
    final String uri = getSlowServiceUri();

    RestTemplate restTemplate = new RestTemplate();
    ResponseEntity&lt;List&lt;Tweet&gt;&gt; response = restTemplate.exchange(
      uri, HttpMethod.GET, null,
      new ParameterizedTypeReference&lt;List&lt;Tweet&gt;&gt;(){});

    List&lt;Tweet&gt; result = response.getBody();
    result.forEach(tweet -&gt; log.info(tweet.toString()));
    log.info(&quot;Exiting BLOCKING Controller!&quot;);
    return result;
}</code></pre><p>먼저 RestTemplate 예시 코드입니다.
RestTemplate는 동기적인 특성으로 인해 <code>restTemplate.exchange</code> 응답을 받을 때까지 Blocking 상태일 것이며 이 후의 코드는 Blocking 후에야 실행될 것입니다.</p>
<pre><code>Starting BLOCKING Controller!
Tweet(text=RestTemplate rules, username=@user1)
Tweet(text=WebClient is better, username=@user2)
Tweet(text=OK, both are useful, username=@user1)
Exiting BLOCKING Controller!</code></pre><p>콘솔에 나타난 실행 흐름입니다.</p>
<h3 id="webclient">WebClient</h3>
<pre><code>@GetMapping(value = &quot;/tweets-non-blocking&quot;, 
            produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux&lt;Tweet&gt; getTweetsNonBlocking() {
    log.info(&quot;Starting NON-BLOCKING Controller!&quot;);
    Flux&lt;Tweet&gt; tweetFlux = WebClient.create()
      .get()
      .uri(getSlowServiceUri())
      .retrieve()
      .bodyToFlux(Tweet.class);

    tweetFlux.subscribe(tweet -&gt; log.info(tweet.toString()));
    log.info(&quot;Exiting NON-BLOCKING Controller!&quot;);
    return tweetFlux;
}</code></pre><p>다음은 WebClient 예시 코드입니다.
Web Client가 일련의 데이터 스트림인 Flux 객체를 반환하고 메서드 실행이 완료됩니다. 
<code>/tweets-non-blocking endpoint</code>를 호출하는 클라이언트도 반환된 Flux 개체에 가입됩니다.</p>
<pre><code>Starting NON-BLOCKING Controller!
Exiting NON-BLOCKING Controller!
Tweet(text=RestTemplate rules, username=@user1)
Tweet(text=WebClient is better, username=@user2)
Tweet(text=OK, both are useful, username=@user1)</code></pre><p>콘솔에 나타난 결과 응답과 상관없지 메서드가 종료된 것을 알 수 있습니다.</p>
<h2 id="summary">Summary</h2>
<p>RestTemplate도 현재까지 아직 사용중이지만
위에서 설명드린 특성들로 인해 WebClient가 성능상 이점을 많이 갖고 있기 때문에 HTTP Client를 선택해야할 때 이 점에 대해 인지하고 개발을 하면 좋겠습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Open Source Software (License)]]></title>
            <link>https://velog.io/@emotional_dev/Open-Source-Software-License</link>
            <guid>https://velog.io/@emotional_dev/Open-Source-Software-License</guid>
            <pubDate>Sat, 19 Aug 2023 10:42:41 GMT</pubDate>
            <description><![CDATA[<h2 id="소프트웨어의-등장">소프트웨어의 등장</h2>
<p>소프트웨어는 컴퓨터 등장 이후 하드웨어에 부수적으로 뒤따르는 존재로 등장했지만 소프트웨어가 독립적으로 상품성이 있음에 눈뜨게 된 이후 소프트웨어는 산업으로써의 길을 걷습니다.
오늘날 우리가 구매하는 소프트웨어는 이를 제한적으로 사용할 수 있는 권리를 구매하는 것에 가깝습니다.</p>
<h2 id="ossopen-source-software의-등장">OSS(Open Source Software)의 등장</h2>
<p>IT에서의 지적재산권은 기업의 독점적 지위를 높이기도 하지만 
IT 산업의 전반적인 기술혁신을 가로막는 장애물로 작용하기도 합니다.
소프트웨어가 상업화되어가면서 소스코드 비공개로 전환되는 것에 대한 반발로 자유소프트웨어 운동이 일었는데 리처드 스톨만의 주도로 1983년 &#39;GNU프로젝트&#39;가 시작되었습니다.
&#39;GNU프로젝트&#39;는 컴파일러, 빌드 도구 등 프로그래밍에 필요한 다양한 도구를 개발하면서 진행되다가 실질적인 결실은 <strong>리누스 토발즈의 리눅스 커널과의 결합에 의해 완성</strong>됩니다.
리눅스 커널은 1994년 1.0버전이 출시되면서 상업용 운영체제와 경쟁 가능성을 보이게 됩니다.
OSS는 다수의 사람에 의해 버그를 잡아낼 가능성이 높기 때문에 우수한 개발 모델이라는 주장이 담겨 있습니다.</p>
<h2 id="oss의-정의">OSS의 정의</h2>
<p>정리하자면 OSS는 소프트웨어의 ‘소스코드’를 공개하여 누구나 개량·재배포할 수 있는 소프트웨어입니다. 
처음 듣기엔 소스코드를 공개하는 것에 의문이 들 수 있지만 주로 아래와 같은 이유들이 있습니다.</p>
<ul>
<li>이미 있는 오픈 소스를 포크하여 새 프로젝트가 만들어지는 경우, 아래에서 설명할 라이센스로 인해 공개해야 함.</li>
<li>외부 개발자들이 참여하도록 하면 더 다양한 환경에서 소프트웨어를 시험해보고 품질을 높일 수 있으므로 소프트웨어를 더 좋게 만들기 위함.</li>
<li>사회 공헌의 측면에서 기술의 공유는 물질의 공유보다 상대적으로 희소성이 반감되는 자산으로 다루어질 수 있기 때문.</li>
<li>프로그램의 신뢰성을 보장하는 방법일 수 있음.</li>
</ul>
<h2 id="oss의-장단점">OSS의 장단점</h2>
<ul>
<li>장점<ul>
<li>이용에 비용이 들지 않거나 적다.</li>
<li>각자의 니즈와 호나경에 맞게 변형 가능</li>
<li>외부 개발자들로 인해 보안 취약점이 쉽게 발견된다.
(그러나 오픈 소스가 보안 측면에서 더 우수하다는 것을 의미하지는 않는다.)</li>
<li>누구나 버그를 고칠 수 있고 소프트웨어에 기여할 수 있다.</li>
<li>특정 제조업체인 벤더(vendor)에 의존하지 않아도 된다.</li>
</ul>
</li>
<li>단점<ul>
<li>사용이 편리한 배포판이 아닌 소스 코드를 직접 빌드하여 사용하기에는 비숙련 사용자들은 이용이 어려울 수 있다.</li>
<li>이미 표준적으로 사용되는 소프트웨어가 있는 경우 호환성 문제가 발생.</li>
<li>고객 지원이 상업 소프트웨어에 비해 상대적으로 약함.</li>
<li>잘못된 정보를 가진 소프트웨어일 수 있음.</li>
</ul>
</li>
</ul>
<h2 id="라이센스-목록-및-제약">라이센스 목록 및 제약</h2>
<p>이 글을 작성하게 된 주된 이유입니다.
오픈소스라고 하여 무작정 가져다가 변형하고 배포하였다간 오픈소스에 적용된 제약에 위배되어 법적, 금전적, 신뢰적으로 큰 피해를 입을 수 있으므로 사용하려는 오픈소스의 라이센스의 제약을 명확히 인지하고 사용하는 것이 반드시 필요합니다.</p>
<table>
<thead>
<tr>
<th>라이선스 이름</th>
<th>복제, 배포, 수정의 권한허용</th>
<th>배포시라이선스사본첨부</th>
<th>저작권고지사항또는Attribution고지사항 유지</th>
<th>배포시소스코드제공의무와범위</th>
<th>조합저작물작성 및타 라이선스배포허용</th>
<th>수정내용 고지</th>
<th>명시적특허라이선스의허용</th>
<th>라이선시가특허소송 제기시라이선스종료</th>
<th>이름,상표,상호에 대한사용제한</th>
<th>보증의 부인</th>
<th>책임의 제한</th>
</tr>
</thead>
<tbody><tr>
<td>Academic Free License</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td></td>
<td></td>
</tr>
<tr>
<td>Adaptive Public License</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>모듈 단위</td>
<td>O</td>
<td>O</td>
<td>선택</td>
<td>선택</td>
<td>O</td>
<td>O</td>
<td>O</td>
</tr>
<tr>
<td>Affero GNU General Public License 3.0</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>네트워크서비스 포함 전체 코드</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td></td>
</tr>
<tr>
<td>Apache License 1.1</td>
<td>O</td>
<td>O</td>
<td>조건부</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Apache License 2.0</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td></td>
<td></td>
</tr>
<tr>
<td>Apple Public Source License</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>파일 단위</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
</tr>
<tr>
<td>Artistic License 1.0</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Artistic License 2.0</td>
<td>O</td>
<td>O</td>
<td>O(표준버전)</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td></td>
</tr>
<tr>
<td>Attribution Assurance License</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>조건부</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Boost Software License</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>조건부</td>
<td>O</td>
<td>O</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Common Development and Distribution license</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>파일 단위</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
</tr>
<tr>
<td>Common Public Attribution License 1.0</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>파일 단위</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td></td>
</tr>
<tr>
<td>Common Public License 1.0</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>모듈 단위</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td></td>
</tr>
<tr>
<td>Computer Associates Trusted Open Source License 1.1</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>모듈 단위 2차 저작물</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
</tr>
<tr>
<td>CUA Office Public License Version 1.0</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>파일 단위</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
</tr>
<tr>
<td>Eclipse Public License</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>모듈 단위</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td></td>
</tr>
<tr>
<td>Educational Community License</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>조건부</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Eiffel Forum License 1.0</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>조건부</td>
<td>O</td>
<td>O</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Eiffel Forum License 2.0</td>
<td>O</td>
<td>O</td>
<td>조건부</td>
<td>O</td>
<td>O</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Entessa Public License</td>
<td>O</td>
<td>O</td>
<td>조건부</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>EU DataGrid Software License</td>
<td>O</td>
<td>O</td>
<td>조건부</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Fair License</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Frameworx License</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>GNU General Public License 2.0</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>전체 코드</td>
<td>조건부</td>
<td>O</td>
<td>O</td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>GNU General Public License 3.0</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>전체 코드</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td></td>
<td></td>
</tr>
<tr>
<td>GNU Lesser General Public License 2.0</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>2차 저작물</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>GNU Lesser General Public License 3.0</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>2차 저작물</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td></td>
</tr>
<tr>
<td>Historical Permission Notice and Disclaimer</td>
<td>O</td>
<td>O</td>
<td>조건부</td>
<td>O</td>
<td>O</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>IBM Public License</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>모듈 단위</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td></td>
</tr>
<tr>
<td>Intel Open Source License</td>
<td>O</td>
<td>O</td>
<td>조건부</td>
<td>O</td>
<td>O</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>ISC License</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>조건부</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Jabber Open Source License</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>파일 단위</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
</tr>
<tr>
<td>Lucent Public License(Plan9)</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td></td>
<td></td>
</tr>
<tr>
<td>Lucent Public License 1.02</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td></td>
<td></td>
</tr>
<tr>
<td>Microsoft Public License</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>조건부</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Microsoft Reciprocal License</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>파일 단위</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td></td>
<td></td>
</tr>
<tr>
<td>MirOS License</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>MIT License</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>조건부</td>
<td>O</td>
<td>O</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>MITRE Collaborative Virtual Workspace License</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>조건부</td>
<td>O</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Molosoto Open Source License 0.9.1</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>파일단위</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
</tr>
<tr>
<td>Mozilla Public License 1.0</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>파일 단위</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
</tr>
<tr>
<td>Mozilla Public License 1.1</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>파일 단위</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td></td>
</tr>
<tr>
<td>Multics License</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>NASA Open Source Agreement 1.3</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>2차 저작물</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td></td>
</tr>
<tr>
<td>Naumen Public License</td>
<td>O</td>
<td>O</td>
<td>조건부</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Nethack General Public License</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>New and Simplified BSD License</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>조건부</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Nokia Open Source License</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>파일 단위</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td></td>
</tr>
<tr>
<td>Non-Profit Open Software License 3.0</td>
<td>O</td>
<td>O</td>
<td>2차 저작물</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td></td>
<td></td>
</tr>
<tr>
<td>NTP License</td>
<td>O</td>
<td>O</td>
<td>조건부</td>
<td>O</td>
<td>O</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>OCLC Research Public License 2.0</td>
<td>O</td>
<td>O</td>
<td>파일 단위</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Open Software License</td>
<td>O</td>
<td>O</td>
<td>2차 저작물</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td></td>
<td></td>
</tr>
<tr>
<td>PHP License</td>
<td>O</td>
<td>O</td>
<td>조건부</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Python License</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Python Software Foundation License</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>RealNetworks Public Source License 1.0</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>파일 단위</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
</tr>
<tr>
<td>Reciprocal Public License 1.0</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>파일 단위 2차 저작물</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td></td>
</tr>
<tr>
<td>Reciprocal Public License 1.5</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>파일 단위 2차 저작물</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td></td>
</tr>
<tr>
<td>Ricoh Source Code Public License</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>파일 단위</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
</tr>
<tr>
<td>Simple Public License 2.0</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>2차 저작물</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Sleepycat License</td>
<td>O</td>
<td>O</td>
<td>동봉 SW</td>
<td>O</td>
<td>O</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Sun Industry Standards Source License</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>파일 단위</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td></td>
</tr>
<tr>
<td>Sun Public License</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>파일 단위</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
</tr>
<tr>
<td>Sybase Open Watcom Public License 1.0</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>파일 단위</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
</tr>
<tr>
<td>The Qt Public License</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>University of Illinois/NCSA Open Source License</td>
<td>O</td>
<td>O</td>
<td>조건부</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Vovida Software License 1.0</td>
<td>O</td>
<td>O</td>
<td>조건부</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>W3C License</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>조건부</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>wxWindows Library License</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>2차 저작물</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>The X.Net, Inc. License</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Zlib/Libpng License</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>조건부</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Zope Public License</td>
<td>O</td>
<td>O</td>
<td>조건부</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
</tbody></table>
]]></description>
        </item>
        <item>
            <title><![CDATA[Spring Cache (2) - Provider 비교 및 구현]]></title>
            <link>https://velog.io/@emotional_dev/Spring-Cache-2-Provider-%EB%B9%84%EA%B5%90-%EB%B0%8F-%EA%B5%AC%ED%98%84</link>
            <guid>https://velog.io/@emotional_dev/Spring-Cache-2-Provider-%EB%B9%84%EA%B5%90-%EB%B0%8F-%EA%B5%AC%ED%98%84</guid>
            <pubDate>Thu, 17 Aug 2023 05:10:55 GMT</pubDate>
            <description><![CDATA[<h2 id="cache-evict-전략">Cache Evict 전략</h2>
<p>Cache Provider를 소개하기 앞서 
캐시 저장 공간은 제한적이기 때문에 각 Provider는 서로 다른 기존의 캐시 제거 전략을 갖고 있습니다.
대표적인 전략은 아래 표와 같으며 각 캐시 구현체는 필요에 따라 각 전략을 혼합하고 커스터마이징 하여 캐시를 관리합니다.</p>
<table>
<thead>
<tr>
<th>전략명</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td>LRU (Least Recently Used)</td>
<td>캐시가 적중된 지 가장 오래된 캐시를 제거합니다</td>
</tr>
<tr>
<td>FIFO (First In First Out)</td>
<td>가장 먼저 생성된 캐시를 제거합니다</td>
</tr>
<tr>
<td>FILO (First In Last Out)</td>
<td>가장 최근에 생성된 캐시를 제거합니다</td>
</tr>
<tr>
<td>LFU (Least Frequently Used)</td>
<td>적중 빈도가 가장 낮은 캐시를 제거합니다</td>
</tr>
<tr>
<td>Time Based Eviction</td>
<td>일정시간 적중되지 않은 캐시를 제거합니다</td>
</tr>
</tbody></table>
<h2 id="cache-provider">Cache Provider</h2>
<p>Spring에서 사용 가능한 대표적인 Cache Provider 목록과 상세 정보는 아래 표와 같습니다.</p>
<table>
<thead>
<tr>
<th>이름</th>
<th>캐시저장위치</th>
<th>TTL 여부</th>
<th>비고</th>
</tr>
</thead>
<tbody><tr>
<td>ConcurrentMapCache</td>
<td>Local</td>
<td>O</td>
<td>1.Spring Boot의 기본 캐시 구현체 중 하나<br>2.기본적으로 자바의 ConcurrentHashMap을 사용하여 캐시를 관리</td>
</tr>
<tr>
<td>Caffeine</td>
<td>Local</td>
<td>O</td>
<td>1.캐시 크기를 설정,제한 가능<br>2.애플리케이션 요구 사항에 따라 자동으로 캐시 관리를 해주어 고성능 제공</td>
</tr>
<tr>
<td>Ehcache</td>
<td>Local and Distributed</td>
<td>O</td>
<td>1.기본적으로는 Local 캐시이지만 필요에 따라 분산환경 지원 가능(Terracota)</td>
</tr>
<tr>
<td>Infinispan</td>
<td>Local and Distributed</td>
<td>O</td>
<td>1.여러 노드에 분산하여 저장하고 공유할 수 있는 분산 데이터 그리드를 제공으로 고가용성과 확장성을 달성</td>
</tr>
<tr>
<td>Redis</td>
<td>Local and Distributed</td>
<td>O</td>
<td>1.다양한 데이터 타입을 지원하며, 문자열, 리스트, 해시맵, 집합, 정렬된 집합 등 다양한 데이터 구조를 저장하고 처리할 수 있습니다.<br>2.필요시 분산환경 지원 및 디스크 저장 가능<br>3.ub/Sub(Publish/Subscribe) 메시징 시스템을 내장하고 있어, 메시지 기반 통신을 지원하며, 실시간 이벤트 처리 및 푸시 알림에 유용</td>
</tr>
</tbody></table>
<h2 id="benchmarks">Benchmarks</h2>
<p>캐시 구현체들의 성능 비교입니다. (MacBook Pro i7-4870HQ CPU @ 2.50GHz(4코어) 16GB Yosemite에서 실행)</p>
<h3 id="1-계산">1. 계산</h3>
<p><img src="https://velog.velcdn.com/images/emotional_dev/post/629ba7a3-918f-43a0-86fe-258dbf5cab30/image.png" alt=""></p>
<p>캐시는 제한이 없고 완전히 채워져 있으며 결과는 상수를 반환한다고 가정합니다.
항목이 있을 때 잠금으로 인한 오버헤드를 보여줍니다.</p>
<h3 id="2-읽기100">2. 읽기(100%)</h3>
<p><img src="https://velog.velcdn.com/images/emotional_dev/post/dd2a2115-3fcd-4f4c-8170-e4d1c4083615/image.png" alt=""></p>
<p>최대 크기로 구성된 캐시에서 동시에 8개의 스레드를 읽습니다.</p>
<h3 id="3-읽기75--쓰기25">3. 읽기(75%) / 쓰기(25%)</h3>
<p><img src="https://velog.velcdn.com/images/emotional_dev/post/24fc7ee1-0d58-45f2-ab04-fedd8b203a2b/image.png" alt=""></p>
<p>6개의 스레드는 최대 크기로 구성된 캐시 에서 동시에 읽고 2개의 스레드는 캐시에 씁니다.</p>
<h3 id="4-쓰기100">4. 쓰기(100%)</h3>
<p><img src="https://velog.velcdn.com/images/emotional_dev/post/50e91833-d692-4ff7-a08c-86834363c488/image.png" alt=""></p>
<p>8개의 스레드는 최대 크기로 구성된 캐시에 동시에 씁니다.</p>
<h2 id="spring-configuration-caffeine">Spring Configuration (Caffeine)</h2>
<p>대부분의 벤치마크에서 좋은 성능을 보여주는 Caffeine을 간단히 설정하는 방법을 알아보겠습니다.</p>
<h3 id="의존성">의존성</h3>
<pre><code>&lt;dependency&gt;
      &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
      &lt;artifactId&gt;spring-boot-starter-cache&lt;/artifactId&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
    &lt;groupId&gt;com.github.ben-manes.caffeine&lt;/groupId&gt;
    &lt;artifactId&gt;caffeine&lt;/artifactId&gt;
    &lt;version&gt;3.1.1&lt;/version&gt;
&lt;/dependency&gt;</code></pre><h3 id="configuration">Configuration</h3>
<pre><code> @Bean
public Caffeine&lt;Object, Object&gt; caffeineConfig() {
    return Caffeine.newBuilder()
        .expireAfterWrite(300, TimeUnit.SECONDS)
        .initialCapacity(10);
}

@Bean
public CacheManager cacheManager(Caffeine caffeine) {
    CaffeineCacheManager caffeineCacheManager = new CaffeineCacheManager();
    caffeineCacheManager.setCaffeine(caffeine);
    return caffeineCacheManager;
}</code></pre><p>위와 같은 간단한 설정만으로도 1부에서 설명드린 어노테이션을 사용하며 캐시를 구성할 수 있으며
<code>stats (통계 활성화 여부)</code>, <code>asynchronous (비동기 캐싱)</code>, <code>cache-null-values(null 저장 여부)</code> 등의 프로젝트에 맞는 추가 설정 또한 가능합니다.
자세한 사항은 <a href="https://github.com/ben-manes/caffeine">Github</a> 에서 확인 가능합니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Spring Cache (1) - 개념 및 어노테이션]]></title>
            <link>https://velog.io/@emotional_dev/Spring-Cache</link>
            <guid>https://velog.io/@emotional_dev/Spring-Cache</guid>
            <pubDate>Wed, 16 Aug 2023 14:03:35 GMT</pubDate>
            <description><![CDATA[<h2 id="cache">Cache</h2>
<p>Spring Cache에 앞서 Cache에 대해 정의하자면
CPU가 자주 사용하는 정보, 데이터 및 프로그램을 임시로 저장합니다. 
데이터가 필요할 때 CPU는 더 빠른 데이터 액세스를 위해 자동으로 가장 가깝고 빠른 캐시 메모리에 액세스합니다. 
캐시 메모리에서 데이터가 발견되면 캐시 적중이 발생합니다. 
캐시 적중을 통해 프로세서는 데이터를 빠르게 검색하여 시스템의 전반적인 응답 속도 및 효율성을 높일 수 있습니다.
대신 비교적 저장 공간이 작고 비용이 비싼 단점이 있습니다.</p>
<h2 id="spring-cache">Spring Cache</h2>
<p>이어서 Spring Cache는 스프링 프레임워크에서 제공하는 캐싱 추상화 라이브러리로, 
메서드의 결과나 데이터를 캐시에 저장하여 반복적인 계산이나 데이터베이스 액세스를 피하고 성능을 향상시키는 기능을 제공합니다. 
스프링에서 사용하는 캐시는 대부분 자바 플랫폼에 대한 규격을 기술한 <a href="https://www.jcp.org/en/jsr/detail?id=107">JSR(Java Specification Requests)-107</a> 을 따르고 있으며 이를 따르는 캐시 구현체는 모두 추상화를 지원합니다.
추상화 단계에서는 다중 스레드, 다중 프로세스 환경을 별도로 고려하고 있지는 않으며 이는 각 구현체에서 처리되고 있습니다.
&#39;도중에 변경될 일이 없는 DB 조회 값&#39; 또는 &#39;자주 조회되는 데이터&#39;에 캐시를 적용한다면 성능 향상, DB 접근 및 시스템 부하 감소의 이점을 얻을 수 있습니다.</p>
<h2 id="cache-범위">Cache 범위</h2>
<ul>
<li><p>로컬 캐시
로컬(캐시를 저장한 서버)에서만 사용하는 캐시.
주로 서버의 메인 메모리에 위치하여 외부 시스템과 트랜잭션 비용이 들지 않기 때문에 속도가 빠르다는 장점이 있지만 분산 서버 구조에선 캐시를 공유하기 어려운 단점이 있습니다.</p>
</li>
<li><p>글로벌 캐시
여러 서버에서 접근할 수 있는 캐시 서버를 구축하여 사용하는 방식입니다.
주로 Redis와 같은 별도의 서버로 운영되기 때문에 서버 간 데이터 공유에 용이하지만
네트워크를 통해 접근해야하기 때문에 로컬 캐시에 비해 상대적으로 느린 단점이 있습니다.</p>
</li>
</ul>
<h2 id="annotation">Annotation</h2>
<p>Spring에서는 간단한 어노테이션 만으로 캐시 추상화를 사용할 수 있습니다.</p>
<h3 id="1-cacheable-캐시-생성">1. @Cacheable (캐시 생성)</h3>
<pre><code>@Cacheable(&quot;books&quot;)
public Book findBook(ISBN isbn) {...}</code></pre><p>캐시 생성을 담당하는 어노테이션입니다.
어노테이션을 선언한 후에는 해당 캐시명을 선언해야 합니다.
최초 캐시 생성 시에는 메서드가 정상적으로 실행되나
이후 findBook 메서드가 호출될 때마다 반복할 필요가 없는 지 확인하기 위해 캐시를 확인합니다.
정상적으로 캐시가 조회되면 메서드는 실행되지 않고 저장된 캐시의 값이 반환됩니다.</p>
<h4 id="1-1-기본-키-생성">1-1. 기본 키 생성</h4>
<p>캐시는 본질적으로 key-value 저장소이므로 캐시 조회를 위해선 캐시 액세스에 적합한 키로 변환되어야 합니다.
기본키 생성은 아래의 알고리즘을 사용합니다.</p>
<ul>
<li>메서드에 매개 변수가 없는 경우 : <code>SimpleKey.EMPTY</code> 반환</li>
<li>메서드에 매개 변수가 하나일 경우 : 해당 인스턴스 반환</li>
<li>메서드에 매개 변수가 하나 이상일 경우 : 모든 매개 변수를 포함한 SimpleKey 인스턴스 반환</li>
</ul>
<h4 id="1-2-사용자-지정-키-생성">1-2. 사용자 지정 키 생성</h4>
<pre><code>@Cacheable(&quot;books&quot;)
public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)</code></pre><p>모든 매개변수가 메서드에 영향을 미치지만 캐시에는 쓸모가 없는 경우 &#39;사용자 지정 키 생성&#39; 방식을 고려할 수 있습니다.
아래와 같이 @Cacheable 매개 변수에 key를 명시하여 직접 key를 선언합니다.</p>
<pre><code>@Cacheable(cacheNames=&quot;books&quot;, key=&quot;#isbn&quot;)
public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)

@Cacheable(cacheNames=&quot;books&quot;, key=&quot;#isbn.rawNumber&quot;)
public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)

@Cacheable(cacheNames=&quot;books&quot;, key=&quot;T(someType).hash(#isbn)&quot;)
public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)</code></pre><p> 키 생성을 담당하는 알고리즘이 복잡한 경우 아래 인터페이스를 구현하여 커스텀 키 생성기를 제공합니다.</p>
<pre><code>org.springframework.cache.interceptor.KeyGenerator</code></pre><pre><code>@Cacheable(cacheNames=&quot;books&quot;, keyGenerator=&quot;myKeyGenerator&quot;)
public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)</code></pre><h4 id="1-3-캐싱-동기화">1-3. 캐싱 동기화</h4>
<p>기본적으로 캐시 추상화는 캐시에 대해 락을 걸지 않으며
이는 동일한 값이 여러 번 계산되어 캐싱의 목적을 무산시킬 수 있습니다.
<code>sync</code>옵션을 통해 대상 항목이 캐시에 업데이트될 때 까지 다른 스레드를 차단하는 기능을 제공합니다.</p>
<pre><code>@Cacheable(cacheNames=&quot;foos&quot;, sync=true) 
public Foo executeExpensiveOperation(String id) {...}</code></pre><h4 id="1-4-조건부-캐싱">1-4. 조건부 캐싱</h4>
<pre><code>@Cacheable(cacheNames=&quot;book&quot;, condition=&quot;#name.length() &lt; 32&quot;) 
public Book findBook(String name)</code></pre><p>때로는 매개변수의 특정 조건에서만 캐시 생성할 때가 있습니다.
condition 옵션을 통해 위 예시와 같이 name 변수의 길이가 32보다 작을 경우에만 캐시 생성을 합니다.</p>
<pre><code>@Cacheable(cacheNames=&quot;book&quot;, condition=&quot;#name.length() &lt; 32&quot;, unless=&quot;#result.hardback&quot;) 
public Book findBook(String name)</code></pre><p><code>condition</code>과 달리 <code>unless</code>는 메서드가 호출된 후에 평가되며
위 예시는 메서드의 반환값 (Book)이 hardback이 아닐 경우에만 캐싱을 진행합니다.</p>
<h4 id="1-5-cache-spel">1-5. Cache SpEL</h4>
<p>키 또는 조건부 연산에 사용살 수 있는 표현식은 아래 표와 같습니다.</p>
<table>
<thead>
<tr>
<th>이름</th>
<th>위치</th>
<th>설명</th>
<th>예</th>
</tr>
</thead>
<tbody><tr>
<td>methodName</td>
<td>루트 개체</td>
<td>호출되는 메서드의 이름</td>
<td>#root.methodName</td>
</tr>
<tr>
<td>method</td>
<td>루트 개체</td>
<td>호출되는 메서드</td>
<td>#root.method.name</td>
</tr>
<tr>
<td>target</td>
<td>루트 개체</td>
<td>호출되는 대상 객체</td>
<td>#root.target</td>
</tr>
<tr>
<td>targetClass</td>
<td>루트 개체</td>
<td>호출되는 대상의 클래스</td>
<td>#root.targetClass</td>
</tr>
<tr>
<td>args</td>
<td>루트 개체</td>
<td>대상을 호출하는 데 사용되는 인수 (배열)</td>
<td>#root.args[0]</td>
</tr>
<tr>
<td>caches</td>
<td>루트 개체</td>
<td>현재 메서드가 실행되는 캐시 컬렉션</td>
<td>#root.caches[0].name</td>
</tr>
<tr>
<td>매개변수명</td>
<td>평가식</td>
<td>메서드 매개변수명</td>
<td>#{매개변수명}</td>
</tr>
<tr>
<td>result</td>
<td>평가식</td>
<td>메서드 호출 결과</td>
<td>#result</td>
</tr>
</tbody></table>
<h3 id="2-cacheput-캐시-수정">2. @CachePut (캐시 수정)</h3>
<pre><code>@CachePut(cacheNames=&quot;book&quot;, key=&quot;#isbn&quot;)
public Book updateBook(ISBN isbn, BookDescriptor descriptor)</code></pre><p>메서드 실행을 방해하지 않고 캐시를 업데이트 하고 싶은 경우 <code>@CachePut</code> 어노테이션을 사용합니다.
이 어노테이션은 메서드는 항상 실행이 되며 그 결과는 선언한 옵션에 따라 캐시에 저장됩니다.</p>
<h3 id="3-cacheevict-캐시-제거">3. @CacheEvict (캐시 제거)</h3>
<pre><code>@CacheEvict(cacheNames=&quot;books&quot;, allEntries=true) 
public void loadBooks(InputStream batch)</code></pre><p>캐시에서 자주 사용하지 않는 데이터를 삭제할 경우에는 @CacheEvict를 통해 캐시를 삭제합니다.
위 예제에서는 <code>allEntries</code> 옵션을 통해 <code>books</code>캐시의 모든 엔트리를 삭제하는 작업을 진행합니다.
<code>beforeInvocation=true</code> 옵션을 추가한다면 메서드 실행 전에 항상 실행이 되기 때문에
메서드의 실행 여부, 예외 여부 상관없이 항상 제거를 진행할 수 있습니다.</p>
<h3 id="4-caching-동일-캐시-작업-그룹화">4. @Caching (동일 캐시 작업 그룹화)</h3>
<pre><code>@Caching(evict = { @CacheEvict(&quot;primary&quot;), @CacheEvict(cacheNames=&quot;secondary&quot;, key=&quot;#p0&quot;) })
public Book importBooks(String deposit, Date date)</code></pre><p>경우에 따라 하나의 메서드에 동일한 유형(@CacheEvice or @CachePut)을 여러번 선언해야하는 경우에는 위 예시와 같이 <code>@Caching</code>어노테이션을 통해 어노테이션 그룹화가 가능합니다.</p>
<h2 id="summary">Summary</h2>
<p>지금까지 캐시 추상화가 제공하는 개념 및 어노테이션을 알아봤습니다.
다음에는 이를 구현한 Provider 들을 비교해보고 간단하게 설정해보도록 하겠습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[TLS Handshake]]></title>
            <link>https://velog.io/@emotional_dev/TLS-Handshake</link>
            <guid>https://velog.io/@emotional_dev/TLS-Handshake</guid>
            <pubDate>Wed, 16 Aug 2023 04:38:05 GMT</pubDate>
            <description><![CDATA[<h2 id="tls-handshake">TLS Handshake?</h2>
<p><img src="https://velog.velcdn.com/images/emotional_dev/post/edebe057-0213-4768-8da2-275b57fbff5a/image.png" alt="">
TLS는 안전한 인터넷 통신을 위한 암호화 및 인증 프로토콜입니다.
주요 사용 사례는 클라이언트와 서버 간의 통신을 암호화하여 보호하는 것이지만, 보호되지 않은 네트워크를 통한 이메일, VoIP, 기타 통신을 보호하는 곳에도 사용 가능합니다.
TLS 핸드셰이크는 TLS 암호화를 사용하는 통신 세션을 실행하는 프로세스입니다. 
TLS 핸드셰이크 중에 양측에서는 메시지를 교환하고 서로를 검증하며 사용할 암호화 알고리즘을 구성하고 세션 키에 합의합니다. 
TLS 핸드셰이크는 HTTPS 작동 원리의 근간을 이룹니다.</p>
<h2 id="tls-handshake-발생-시점">TLS Handshake 발생 시점</h2>
<p>TLS Handshake는 위 사진과 같이 일반적으로 알고 있는 TCP 3-way-handshake가 성립된 이후에 진행이 됩니다.
TLS Handshake는 HTTPS를 통해 브라우저가 처음 요청 서버를 쿼리할 때 발생하며 이후에는 생성된 세션을 활용하므로 추가적인 Handshake를 진행하지 않습니다.
API 호출 및 HTTPS를 통한 DNS 쿼리를 포함하는 HTTPS를 사용할 때에도 TLS 핸드셰이크가 발생합니다.</p>
<h2 id="tls-handshake-교환-정보">TLS Handshake 교환 정보</h2>
<ul>
<li>TLS 버전 (1.0, 1.2, 1.3 등)</li>
<li>암호화 알고리즘</li>
<li>SSL인증서 기관의 디지털 서명 및 공개키를 통해 클라이언트 쪽에서의 서버 ID 인증
(기술적으로 모든 웹 사이트 소유자는 자체 SSL인증서 생성 후 자체 서명이 가능하지만 브라우저마다 신뢰하는 인증서 기관 목록이 있기 때문에 신뢰할 수 있는 것으로 간주되지 않습니다.)</li>
<li>Handshake 이후 데이터 대칭 암복호화를 위해 세션 키 생성 및 공유</li>
</ul>
<h2 id="tls-handshake-단계-tls-13-이전---rsa-키-교환-알고리즘">TLS Handshake 단계 (TLS 1.3 이전 - RSA 키 교환 알고리즘)</h2>
<ol>
<li><p>&#39;클라이언트 헬로&#39; 메시지
클라이언트가 서버로 &quot;헬로&quot; 메시지를 전송하면서 핸드셰이크를 개시합니다.
이 과정에서 클라이언트가 지원하는 TLS 버전, 지원되는 암호 제품군, 그리고 &quot;클라이언트 무작위&quot;라고 하는 무작위 바이트 문자열이 포함됩니다.</p>
</li>
<li><p>&#39;서버 헬로&#39; 메시지
클라이언트 헬로 메시지에 대한 응답으로 서버가 
서버의 SSL 인증서, 서버에서 선택한 암호 제품군, 그리고 서버에서 생성한 또 다른 무작위 바이트 문자열인 &quot;서버 무작위&quot;를 포함하는 메시지를 전송합니다.</p>
</li>
<li><p>인증
클라이언트가 서버의 SSL 인증서를 인증서 발행 기관을 통해 검증합니다.
이를 통해 서버가 인증서에 명시된 서버인지, 그리고 클라이언트가 상호작용 중인 서버가 실제 해당 도메인의 소유자인지를 확인합니다.</p>
</li>
<li><p>예비 마스터 암호
클라이언트가 &quot;예비 마스터 암호&quot;라고 하는 무작위 바이트 문자열을 하나 더 전송합니다. 
예비 마스터 암호는 SSL 인증서를 통해 전달 받은 공개 키로 암호화되어 있으며, 서버가 개인 키로만 해독할 수 있습니다. </p>
</li>
<li><p>개인 키 사용
서버가 예비 마스터 암호를 해독합니다.</p>
</li>
<li><p>세션 키 생성
클라이언트와 서버가 모두 클라이언트 무작위, 서버 무작위, 예비 마스터 암호를 이용해 세션 키를 생성합니다. </p>
</li>
</ol>
<p><strong>모두 같은 결과가 나와야 합니다.</strong></p>
<ol start="7">
<li><p>클라이언트 준비 완료
클라이언트가 세션 키로 암호화된 &quot;완료&quot; 메시지를 전송합니다.</p>
</li>
<li><p>서버 준비 완료
서버가 세션 키로 암호화된 &quot;완료&quot; 메시지를 전송합니다.</p>
</li>
<li><p>안전한 대칭 암호화 성공
핸드셰이크가 완료되고, 세션 키를 이용해 통신이 계속 진행됩니다.</p>
</li>
</ol>
<p>세션 키를 생성하는 과정에서 개인키를 사용하는 알고리즘 외에도 Diffie-Hellman 알고리즘을 통해서도 세션키 생성이 가능합니다.</p>
<h2 id="tls-handshake-단계-tls-13">TLS Handshake 단계 (TLS 1.3)</h2>
<p>TLS 1.3은 RSA나 공격에 취약한 기타 알고리즘을 지원하지 않습니다. 
핸드셰이크 과정이 단축되어 더 빠르고 안전해집니다.</p>
<ol>
<li><p>클라이언트 헬로
클라이언트는 프로토콜 버전, 클라이언트 무작위, 암호 모음 목록이 포함된 클라이언트 헬로 메시지를 보냅니다.
클라이언트 헬로에는 예비 마스터 암호를 계산하는 데 사용되는 매개변수도 포함되어 있습니다.
이렇게 하면 핸드셰이크의 전체 길이가 줄어드는데, 이는 TLS 1.3 핸드셰이크와 TLS 1.0, 1.1, 1.2 핸드셰이크의 중요한 차이점 중 하나입니다.</p>
</li>
<li><p>서버가 마스터 암호를 생성
이 시점에서 서버는 클라이언트 무작위, 클라이언트의 매개변수, 암호 그룹을 받았습니다.
서버는 이미 서버 무작위를 자체적으로 생성할 수 있으므로 이미 서버 무작위를 보유하고 있습니다.
따라서 서버는 마스터 암호를 생성할 수 있습니다.</p>
</li>
<li><p>서버 헬로 및 &#39;완료됨&#39;
서버 헬로에는 서버의 인증서, 디지털 서명, 서버 무작위, 선택한 암호 그룹이 포함됩니다.
서버는 이미 마스터 암호를 가지고 있으므로 &quot;완료됨&quot; 메시지도 전송합니다.</p>
</li>
<li><p>마지막 단계 및 클라이언트 &#39;완료됨&#39;
클라이언트가 서명 및 인증서를 확인하고 마스터 암호를 생성한 후 &quot;완료됨&quot; 메시지를 전송합니다.</p>
</li>
<li><p>안전한 대칭 암호화 성공</p>
</li>
</ol>
<h2 id="대칭-암복호화">대칭 암복호화</h2>
<p><img src="https://velog.velcdn.com/images/emotional_dev/post/730fb5d8-befd-4753-930c-dbc6373d51a1/image.svg" alt=""></p>
<p>위 과정을 통해 세션키가 생성이 되면 해당 세션키를 대칭키로 활용하여 요청/응답 데이터 암복호화가 이뤄집니다.
세션키를 통한 대칭키 암복호화가 아닌 매번 비대칭 알고리즘을 통해 데이터를 암복호화 한다면 성능에 영향을 미칠 것이기에 비대칭 알고리즘은 세션키 생성에만 활용됩니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[HTTP Header]]></title>
            <link>https://velog.io/@emotional_dev/HTTP-Header</link>
            <guid>https://velog.io/@emotional_dev/HTTP-Header</guid>
            <pubDate>Mon, 14 Aug 2023 08:09:56 GMT</pubDate>
            <description><![CDATA[<ul>
<li><p><strong>HTTP Header란?</strong><br>
HTTP 프로토콜을 사용하여 웹 클라이언트와 서버간의 통신에서 요청과 응답 본문 외에 해당 요청/응답의 메타 정보를 포함하는 정보입니다.
각 필드는 key/value 형태로 이루어져 있으며 요청과 응답을 처리하는 데 중요한 역할을 합니다.
사용자 지정 전용 헤더는 &#39;X-&#39; 접두사와 함께 사용되어 왔지만 <a href="https://datatracker.ietf.org/doc/html/rfc6648">RFC6648</a> 에서 비표준 필드가 표준이 되었을 때의 발생한 불편함 때문에 2012년 6월에 더 이상 사용하지 않게 됩니다.
각 브라우저와 웹 서버는 몇KB 정도로 헤더를 제한하고 있으며 이를 초과할 시 &#39;<strong>413 Entity Too Large</strong>&#39;가 반환되게 됩니다.
HTTP/2, HTTP/3과 같은 프로토콜은 헤더 압축 및 다중화를 통해 이러한 제약을 완화시키기 위한 방법을 제공합니다.<br><br></p>
</li>
<li><p><strong>Http Header 구조</strong></p>
<ul>
<li>각 헤더는 개행문자로 구분하며 헤더의 KEY/VALUE는 &#39;:&#39;로 구분합니다.<br>
<code>GET /path/to/resource HTTP/1.1</code>
<code>Host: example.com</code>
<code>User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3</code>
<code>Accept: text/html, application/xhtml+xml, application/xml;q=0.9, */*;q=0.8</code><br><br></li>
</ul>
</li>
<li><p><strong>Request Header Field (표준)</strong></p>
</li>
</ul>
<table>
<thead>
<tr>
<th>필드명</th>
<th>설명</th>
<th>예시</th>
</tr>
</thead>
<tbody><tr>
<td>Accept</td>
<td>허용 가능 응답 데이터 유형</td>
<td>Accept: text/html</td>
</tr>
<tr>
<td>Accept-Charset</td>
<td>허용 가능 문자 집합</td>
<td>Accept-Charset: utf-8</td>
</tr>
<tr>
<td>Accept-Datetime</td>
<td>허용 가능 시간 정보.<br>원본 데이터의 과거 시간에 접근할 것임을 나타냄.</td>
<td>Accept-Datetime: Thu, 31 May 2007 20:35:00 GMT</td>
</tr>
<tr>
<td>Accept-Encoding</td>
<td>허용 가능 인코딩 목록</td>
<td>Accept-Encoding: gzip, deflate</td>
</tr>
<tr>
<td>Accept-Language</td>
<td>허용 가능 언어</td>
<td>Accept-Language: en-US</td>
</tr>
<tr>
<td>Accept-Control-Request-Method</td>
<td>CORS 요청 메소드</td>
<td>Access-Control-Request-Method: GET</td>
</tr>
<tr>
<td>Authorization</td>
<td>HTTP 인증 자격 증명</td>
<td>Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==</td>
</tr>
<tr>
<td>Cache-Control</td>
<td>요청,응답 체인을 따라 모든 캐싱 메커니즘이 준수해야하는 지시사항</td>
<td>Cache-Control: no-cache</td>
</tr>
<tr>
<td>Content-Encoding</td>
<td>본문 데이터 인코딩 유형</td>
<td>Content-Encoding: gzip</td>
</tr>
<tr>
<td>Content-Length</td>
<td>요청 본문 길이(Byte)</td>
<td>Content-Length: 348</td>
</tr>
<tr>
<td>Content-Type</td>
<td>요청 본문 데이터 유형(POST,PUT)</td>
<td>Content-Type: application/x-www-form-urlencoded</td>
</tr>
<tr>
<td>Cookie</td>
<td>서버가 설정한 쿠키 목록</td>
<td>Cookie: $Version=1; Skin=new;</td>
</tr>
<tr>
<td>Date</td>
<td>메세지 시작 날짜 및 시간</td>
<td>Date: Tue, 15 Nov 1994 08:12:31 GMT</td>
</tr>
<tr>
<td>Forwarded</td>
<td>HTTP 프록시를 통해 웹서버 연결할 때 클라이언트의 원래 정보</td>
<td>Forwarded: for=192.0.2.60;proto=http;by=203.0.113.43 Forwarded: for=192.0.2.43, for=198.51.100.17</td>
</tr>
<tr>
<td>From</td>
<td>요청자 전자 메일 주소</td>
<td>From: <a href="mailto:user@example.com">user@example.com</a></td>
</tr>
<tr>
<td>Host</td>
<td>서버의 도메인 및 TCP 포트 번호.<br>표준 포트일 경우 생략 가능</td>
<td>Host: en.wikipedia.org:8080</td>
</tr>
<tr>
<td>If-Modified-Since</td>
<td>내용이 수정되지 않은 경우 &#39;304 Not Modified&#39; 허용</td>
<td>If-Modified-Since: Sat, 29 Oct 1994 19:43:31 GMT</td>
</tr>
<tr>
<td>If-None-Match</td>
<td>일치하지 않은 경우 &#39;304 Not Modified&#39; 허용</td>
<td>If-None-Match: &quot;737060cd8c284d8af7ad3082f209582d&quot;</td>
</tr>
<tr>
<td>Origin</td>
<td>CORS 공유 요청</td>
<td>Origin: <a href="http://www.example-social-network.com">http://www.example-social-network.com</a></td>
</tr>
<tr>
<td>Pragma</td>
<td>요청,응답 체인을 따라 다양한 영향을 미칠 수 있는 필드.<br>HTTP/1.1 버전의 Cache-Control 헤더가 생기기 전 그것과 동일한 역할을 하는 대용 헤더로 사용</td>
<td>Prefer: return=representation</td>
</tr>
<tr>
<td>Proxy-Authorization</td>
<td>프록시 연결 인증 자격 증명</td>
<td>Proxy-Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==</td>
</tr>
<tr>
<td>Range</td>
<td>엔티티의 일부 Byte만 요청</td>
<td>Range: bytes=500-999</td>
</tr>
<tr>
<td>Referer</td>
<td>요청한 사이트의 이전 링크</td>
<td>Referer: <a href="http://en.wikipedia.org/wiki/Main_Page">http://en.wikipedia.org/wiki/Main_Page</a></td>
</tr>
<tr>
<td>User-Agent</td>
<td>사용자 에이전트</td>
<td>User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:12.0) Gecko/20100101 Firefox/12.0</td>
</tr>
<tr>
<td>Upgrade</td>
<td>서버에 다른 프로토콜로 업그레이드 하도록 요청</td>
<td>Upgrade: h2c, HTTPS/1.3, IRC/6.9, RTA/x11, websocket</td>
</tr>
</tbody></table>
<ul>
<li><strong>Response Header Field (표준, 공통 필드 제외)</strong></li>
</ul>
<table>
<thead>
<tr>
<th>필드명</th>
<th>설명</th>
<th>예시</th>
</tr>
</thead>
<tbody><tr>
<td>Age</td>
<td>엔티티가 프록시 캐시에 있던 기간(초)</td>
<td>Age: 12</td>
</tr>
<tr>
<td>Allow</td>
<td>지정한 리소스에 유효한 메서드</td>
<td>Allow: GET, HEAD</td>
</tr>
<tr>
<td>Content-Disposition</td>
<td>이진 형식의 MIME 유형에 대해 &#39;파일 다운로드&#39; 대화상자를 열거나 동적 내용에 대한 피일 이름을 제안</td>
<td>Content-Disposition: attachment; filename=&quot;fname.ext&quot;</td>
</tr>
<tr>
<td>Content-Location</td>
<td>반환된 데이터의 대체 위치</td>
<td>Content-Location: /index.htm</td>
</tr>
<tr>
<td>ETAG</td>
<td>리소스의 특정 버전에 대한 식별자</td>
<td>ETag: &quot;737060cd8c284d8af7ad3082f209582d&quot;</td>
</tr>
<tr>
<td>Expires</td>
<td>응답이 오래된 것으로 간주되는 시간 정보 제공</td>
<td>Expires: Thu, 01 Dec 1994 16:00:00 GMT</td>
</tr>
<tr>
<td>Last-Modified</td>
<td>요청된 개체의 마지막 수정 날짜</td>
<td>Last-Modified: Tue, 15 Nov 1994 12:45:26 GMT</td>
</tr>
<tr>
<td>Link</td>
<td>다른 리소스와 유형화된 관계를 표현</td>
<td>Link: </feed>; rel=&quot;alternate&quot;</td>
</tr>
<tr>
<td>Location</td>
<td>리디렉션 또는 새 리소스가 생성된 경우 사용</td>
<td>Location: <a href="http://www.w3.org/pub/WWW/People.html">http://www.w3.org/pub/WWW/People.html</a></td>
</tr>
<tr>
<td>Public-Key-Pins</td>
<td>HTTP 공개키 피닝.웹사이트 인증 TLS 인증서 해시 발표</td>
<td>Public-Key-Pins: max-age=2592000; pin-sha256=&quot;E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=&quot;;</td>
</tr>
<tr>
<td>Retry-After</td>
<td>엔티티를 일시적으로 사용할 수 없는 경우 클라이언트가 나중에 다시 시도하도록 지시.</td>
<td>Retry-After: Fri, 07 Nov 2014 23:59:59 GMT</td>
</tr>
<tr>
<td>Server</td>
<td>서버 이름</td>
<td>Server: Apache/2.4.1 (Unix)</td>
</tr>
<tr>
<td>Set-Cookie</td>
<td>HTTP 쿠키 목록</td>
<td>Set-Cookie: UserID=JohnDoe; Max-Age=3600; Version=1</td>
</tr>
<tr>
<td>Warning</td>
<td>엔티티 본문에서 발생할 수 있는 문제에 대한 일반적인 경고</td>
<td>Warning: 199 Miscellaneous warning</td>
</tr>
<tr>
<td>WWW-Authenticate</td>
<td>요청된 엔티티에 액세스하는데 사용할 인증 체계</td>
<td>WWW-Authenticate: Basic</td>
</tr>
</tbody></table>
]]></description>
        </item>
        <item>
            <title><![CDATA[HTTP(HyperText Transfer Protocol) Version]]></title>
            <link>https://velog.io/@emotional_dev/HTTPHyperText-Transfer-Protocol</link>
            <guid>https://velog.io/@emotional_dev/HTTPHyperText-Transfer-Protocol</guid>
            <pubDate>Mon, 14 Aug 2023 04:59:39 GMT</pubDate>
            <description><![CDATA[<h2 id="http">HTTP?</h2>
<p>월드 와이드 웹(WWW)에서 정보를 주고받기 위해 사용되는 프로토콜 중 하나로,
클라이언트와 서버 간의 데이터 통신을 위한 규칙과 프로토콜을 정의합니다.
HTTP는 본래의 단순함의 대부분을 지키면서 확장성 위에서 많은 수정을 거쳐왔으며
이러한 변화 과정을 알아보고자 합니다.<br><br></p>
<h3 id="http09-원-라인-프로토콜">HTTP/0.9 (원-라인 프로토콜)</h3>
<p>HTTP 초기 버전으로서, 초기에는 버전 번호가 없었지만 이후에 다른 버전과 구별하기 위해 0.9로 불리게 됐습니다.
구조는 극히 단순합니다.
단일 라인으로 구성되며 프로토콜, 서버, 포트는 서버가 연결되고 나면 불필요하기에 리소스에 대한 경로 및 가능한 메서드는 &#39;GET&#39;이 유일했습니다.<br>
<code>GET /mypage.html</code><br>
응답 또한 파일 내용 자체만으로 구성되어 극도로 단순합니다.<br>
<code>&lt;HTML&gt;</code>
<code>A very simple HTML page</code>
<code>&lt;/HTML&gt;</code>
<br>해당 버전은 HTML 파일만 전송될 수 있었기에 헤더가 존재하지 않았으며
문제가 발생한 경우, 사람이 직접 처리할 수 있도록 해당 파일 내부에 문제에 대한 설명과 함께 리턴이 되었기에
상태 혹은 오류 코드도 존재하지 않았습니다.<br><br></p>
<h3 id="http10-확장성-고려">HTTP/1.0 (확장성 고려)</h3>
<ul>
<li>HTTP 버전 정보가 전송되기 시작했습니다. (HTTP/1.0)</li>
<li>상태 코드가 응답의 시작 부분에 붙어 전송되어, 브라우저가 요청에 대해 성공 또는 실패를 알게되었고,
해당 결과에 대한 동작을 설정할 수 있게 되었습니다.</li>
<li>HTTP 헤더의 도입으로 요청/응답에 대한 메타데이터 설정이 가능해지고 HTTP 프로토콜을 유연하고 확장 가능한 프로토콜로 만들어 주었습니다.
또한 헤더의 도움으로 HTML문서 외의 다른 유형의 데이터를 전송할 수 있게 되었습니다.<br>
<code>GET /mypage.html HTTP/1.0</code>
<code>User-Agent: NCSA_Mosaic/2.0 (Windows 3.1)</code><br>
<code>200 OK</code>
<code>Date: Tue, 15 Nov 1994 08:12:31 GMT</code>
<code>Server: CERN/3.0 libwww/2.17</code>
<code>Content-Type: text/html</code>
<code>&lt;HTML&gt;</code>
<code>A page with an image</code>
<code>&lt;IMG SRC=&quot;/myimage.gif&quot;&gt;</code>
<code>&lt;/HTML&gt;</code><br><br></li>
</ul>
<h3 id="http11-표준-프로토콜">HTTP/1.1 (표준 프로토콜)</h3>
<p>HTTP의 첫 번째 표준 버전인 1.1버전은 1.0이 나온 지 몇 달 되지 않은 1997년 1월에 처음 공개되었습니다. (<a href="https://datatracker.ietf.org/doc/html/rfc2068">RFC 2068</a>)
이전 버전에 비해 모호함을 명확하게 하고 많은 개선 사항들을 도입했습니다.</p>
<ul>
<li>커넥션을 재사용할 수 있게 함으로써 문서 내의 리소스들을 다시 접근하기 위해 사용된 커넥션을 다시 열어 시간이 절약되었습니다.</li>
<li>파이프라이닝을 추가하여, 첫번째 요청에 대한 응답이 완전히 전송되기 이전에 두번째 요청 전송을 가능케 하여, 커뮤니케이션 레이턴시를 낮췄습니다.</li>
<li>청크된 응답 지원.</li>
<li>추가적인 캐시 제어 메커니즘이 도입.</li>
<li>언어, 인코딩 혹은 타입을 포함한 컨텐츠 협상이 도입되어, 클라이언트와 서버로 하여금 <strong>교환하려는 가장 적합한 컨텐츠에 대한 동의</strong>를 가능케 했습니다.</li>
<li>Host 헤더 덕분에, 동일 IP 주소에 다른 도메인을 호스트하는 기능이 서버 코로케이션을 가능케 합니다.<br>
<code>GET /ko/docs/Glossary/Simple_header HTTP/1.1</code>
<code>Host: developer.mozilla.org</code>
<code>User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:50.0) Gecko/20100101 Firefox/50.0</code>
<code>Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8</code>
<code>Accept-Language: en-US,en;q=0.5</code>
<code>Accept-Encoding: gzip, deflate, br</code>
<code>Referer: https://developer.mozilla.org/ko/docs/Glossary/Simple_header</code><br>
<code>200 OK</code>
<code>Connection: Keep-Alive</code>
<code>Content-Encoding: gzip</code>
<code>Content-Type: text/html; charset=utf-8</code>
<code>Date: Wed, 20 Jul 2016 10:55:30 GMT</code>
<code>Etag: &quot;547fa7e369ef56031dd3bff2ace9fc0832eb251a&quot;</code>
<code>Keep-Alive: timeout=5, max=1000</code>
<code>Last-Modified: Tue, 19 Jul 2016 00:59:33 GMT</code>
<code>Server: Apache</code>
<code>Transfer-Encoding: chunked</code>
<code>Vary: Cookie, Accept-Encoding</code><br>
<code>(content)</code><br><br><h3 id="http20-더-나은-성능을-위한-프로토콜">HTTP/2.0 (더 나은 성능을 위한 프로토콜)</h3>
몇 년에 걸쳐, 웹 페이지는 매우 복잡해지면서, 하나의 요청에 대한 스크립트의 양과 크기는 점점 더 많이 증가하고 있습니다.
HTTP/1.1 커넥션은 순차적으로 전송되는 요청을 필요로 합니다. 
몇몇 병렬 커넥션이 이론적으로 사용 가능한 경우에도 여전히 많은 양의 오버헤드와 복잡도가 남아 있습니다.
이러한 상황에서 HTTP/2 프로토콜은 HTTP/1.1 버전과 다른 몇가지 근본적인 차이점은 아래와 같습니다.</li>
<li>텍스트 프로토콜 -&gt; 이진 프로토콜. 
이진 프로토콜이기에 더 이상 읽을 수도 없고 수작업을 만들어낼 수 없지만,
이런 결점에 대한 보상으로, 새로운 최적화 기술이 구현될 수 있습니다.</li>
<li>병렬 요청이 동일한 커넥션 상에서 다루어질 수 있는 다중화 프로토콜로, 
순서를 제거해주고 HTTP/1.x 프로토콜의 제약사항을 막아줍니다.</li>
<li>전송된 데이터의 분명한 중복과 그런 데이터로부터 유발된 불필요한 오버헤드를 제거하면서, 
연속된 요청 사이의 매우 유사한 내용으로 존재하는 헤더들을 압축시킵니다.</li>
<li>서버로 하여금 사전에 클라이언트 캐시를 서버 푸쉬라고 불리는 메커니즘에 의해 필요하게 될 데이터로 채워넣도록 허용합니다.<br></li>
</ul>
<p>2015년 5월에 공식적으로 표준화된 HTTP/2는 정보 전송 시 오버헤드 감소로 많은 웹사이트들은 해당 프로토콜을 급속도로 받아들이기 시작했습니다.
이러한 변화는 어느 정도의 제한된 액터 세트만이 필요했고 이외에는 최신의 브라우저, 서버만 있으면 전환이 손쉬웠기에 가능했습니다.<br><br></p>
<h3 id="http3-http-over-quic">HTTP/3 (HTTP over QUIC)</h3>
<p>HTTP의 다음 메이저 버전인 HTTP/3에서는 전송 계층 부분에 
&#39;TCP/TLS&#39; 대신 <strong>&#39;QUIC(Quick UDP Internet Connection)&#39;</strong>가 사용됩니다.
Firefox에서의 구현 상태는 <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1158011">Firefox bug 1158011</a>을 참조해주세요.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Switch] Ether Channel]]></title>
            <link>https://velog.io/@emotional_dev/Switch-Ether-Channel</link>
            <guid>https://velog.io/@emotional_dev/Switch-Ether-Channel</guid>
            <pubDate>Thu, 10 Aug 2023 03:02:57 GMT</pubDate>
            <description><![CDATA[<ul>
<li>Ether Channel?</li>
</ul>
<p><img src="https://t1.daumcdn.net/cfile/tistory/2778B33557C80E0E11" alt=""></p>
<p>Switch Port는 한정되어 무한히 확장할 수 없기 때문에 
물리적 Port확장이 아닌 논리적으로 Port를 확장시키는 방식인 EtherChannel을 사용하게 되는데 
같은 속성을 공유하는 여러개의 Link를 논리적으로 하나의 Link로 묶어 하나의 Logical Link가 생성되므로 더 많은 대역폭을 제공할 수 있으며 물리적인 Port 또한 절약할 수 있고 2계층과 3계층의 Port 모두 EtherChannel 방식을 지원합니다.</p>
<ul>
<li>Ether Channel 종류
EtherChannel을 생성하고 유지하기 위해 필요한 프로토콜에는 아래의 종류가 있습니다.</li>
</ul>
<p>  1.PAgP : Cisco 전용 EtherChannel Protocol이며 EtherChannel 구성에 필요한 협상방식은 아래와 같습니다.
<img src="https://t1.daumcdn.net/cfile/tistory/2777B93957C810420E" alt=""></p>
<ul>
<li>On : 협상없이 Channel Member를 구성하는 Mode</li>
<li>Off : 해당 Interface를 EtherChannel로 구성하지 않는다는 Mode로서 어느 한 쪽이 Off일 시 EtherChannel은 형성되지 않는다.</li>
<li>Auto : 소극적으로 Channel구성을 기다리는 Mode로서 양쪽이 모두 Auto일 때 역시 EtherChannel이 형성되지 않는다.</li>
<li>Desirable : 적극적으로 Channel구성을 협상하는 Mode.</li>
</ul>
<ol start="2">
<li>LACP : IEEE 802.3ad 표준 방식</li>
</ol>
<p><img src="https://t1.daumcdn.net/cfile/tistory/2250803957C810432D" alt=""></p>
<ul>
<li>On : (PAgP와 같음)</li>
<li>Off : (PAgP와 같음)</li>
<li>Passive : Pagp의 Auto와 같은 형태의 Mode</li>
<li>Active : Pagp의 Desirable과 같은 형태의 Mode</li>
</ul>
<ol start="3">
<li>Static : Protocol을 사용하지 않고 Static한 방식으로 EtherChannel을 구성하는 방식.  </li>
</ol>
<p><img src="https://t1.daumcdn.net/cfile/tistory/2620D13557C814A913" alt=""></p>
<p><strong>(L2 Ether Channel)</strong></p>
<ol>
<li>각 Switch에 필요한 VLAN을 지정해주고 PC에 IP와 Gateway를 지정해준다.</li>
<li>EtherChannel을 설정할 Interface범위를 지정하여 해당 Mode로 진입</li>
</ol>
<p>-Switch(config)# interface range Fa0/10-11 (SW01 기준)
3. EtherChannel을 위한 Protocol 지정
-Switch(config-if-range)# channel-protocol lacp
4. EtherChanne Group을 생성하고 해당 Port Group의 Mode를 정한다
-Switch(config-if-range)# channel-group 1(number) mode active (active / on / off / passive )
(같은 Switch내에서의 Group Number는 중복 불가)
5. 지정한 Group의 Interface (int port-channel 1)로 들어가서 Vlan공유를 위한 Trunk 설정 </p>
<p><strong>(L3 Ether Channel)</strong></p>
<ol>
<li>Switch의 Configuration Mode에서 ip routing명령어를 통해 routing을 활성화</li>
<li>L2방식과 동일하게 Ether Channel을 구성</li>
<li>지정한 Group의 Interface로 들어가 swich mode를 해제(no switchport)한 후 ip지정</li>
<li>서로 다른 VLAN통신을 위해 Inter-VLAN지정</li>
<li>EIGRP등의 방식을 사용하여 각 L3 Switch에게 보유 Network광고 </li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Switch] DHCP (Dynamic Host Configuration Protocol)]]></title>
            <link>https://velog.io/@emotional_dev/Switch-DHCP-Dynamic-Host-Configuration-Protocol</link>
            <guid>https://velog.io/@emotional_dev/Switch-DHCP-Dynamic-Host-Configuration-Protocol</guid>
            <pubDate>Thu, 10 Aug 2023 02:46:59 GMT</pubDate>
            <description><![CDATA[<ul>
<li>DHCP란?
과거에는 IP관리대장 등을 사용하여 사람이 직접 IP를 관리 및 분배를 했는데 이로 인해 발생하는 불편을 해소하기 위해 탄생한 것이 바로 DHCP다. 
부팅 시 화면에 나오는 DHCP표시가 이에 해당되는데 지정받은 범위의 IP를 자동으로 할당을 해주는 역할을 담당하며 DHCP같은 서비스로 IP를 받아오지 못했을 경우 169.254.X.X와 같은 자동 개인 IP주소가 부여되어 외부와 통신은 불가하더라도 내부와의 통신 목적과 DHCP로 IP배정이 이루어지지 못했음을 나타내는 정보를 담고 있다.</li>
</ul>
<ul>
<li>IP 설정 방식<ul>
<li>Static IP 설정 : 고정 IP주소를 요구하는 서버에서 사용되며 사용자가 직접 지정할 시 잘못 입력될 가능성이 있어 네트워크가 연결되지 않을 수 있으므로 일반 사용자에게는 비권장되는 방식입니다.</li>
<li>Dynamic IP 설정 : 이 방식이 바로 DHCP서버를 이용하여 자동적으로 IP를 지정해주는 방식이며 사용자는 IP설정에 관해 신경 쓸 필요가 없어지게 되고 잘못된 입력가능성이 줄어들게되고 IP의 효율적 관리와 지정된 IP만 서버에 배정 및 승인하므로 보안적 목적 등의 효과가 있습니다.</li>
</ul>
</li>
</ul>
<p><img src="https://t1.daumcdn.net/cfile/tistory/2673784B57C3FD301D" alt=""></p>
<p>DHCP 서버는 위의 사진처럼 Gateway쪽에 위치할 수도 있으며 같은 Broadcats에서 나와 외부적으로 연결될 수도 있습니다.  </p>
<ul>
<li>IP배정 순서</li>
</ul>
<p><img src="https://t1.daumcdn.net/cfile/tistory/2779A04B57C3FDC919" alt=""></p>
<ol>
<li>Client는 Discover Message를 사용하여 Broadcasting방식으로 DHCP 서버를 탐색하게 된다.</li>
<li>Message를 받은 DHCP 서버는 이에 OFFER라는 응답을 하게 되는데 위에서 소개한 Gateway쪽에 위치한 경우는 Unicast로 외부에 위치한 경우는 Broadcast방식으로 응답을 하게되는데 배정이 가능한 IP를 Client에게 보내주어 최종 요정인 Request Message를 기다리게 된다.</li>
<li>DHCP 서버는 여러개 있을 수 있으므로 가장 먼저 Offer가 온 서버에게 Request Message를 보내 최종적으로 IP지정을 요청하게 된다.</li>
<li>Request 요청을 받은 Server는 IP설정을 완료한다는 Acknowledgement Message를 보내어 최종적으로 IP지정이 완료되게 된다</li>
</ol>
<p>D.O.R.A
D,R (Discover, Requset) : Client 
O,A (Offer, Acknowledgement) : Server</p>
<ul>
<li>DHCP 설정</li>
</ul>
<p><img src="https://t1.daumcdn.net/cfile/tistory/27674C5057C4015D0B" alt=""></p>
<p><strong>[같은 Broadcast위치]</strong></p>
<p><strong>1. POOL 설정 :</strong> 구분이 쉬운 단어로 이름을 지정해준다.</p>
<p><img src="https://t1.daumcdn.net/cfile/tistory/251F9C4C57C4024102" alt=""></p>
<p><img src="https://t1.daumcdn.net/cfile/tistory/21582D4757C402490B" alt=""></p>
<p><strong>2. 해당 대역대 할당</strong></p>
<p><img src="https://t1.daumcdn.net/cfile/tistory/2564B94C57C402433B" alt=""></p>
<p><strong>3. Gateway 및 선택적 요소인 Option 지정 (DNS등 255여개)</strong></p>
<p><img src="https://t1.daumcdn.net/cfile/tistory/256D4E4C57C4024433" alt=""></p>
<p><img src="https://t1.daumcdn.net/cfile/tistory/2370964C57C402442A" alt=""></p>
<p><strong>4. 무제한으로 IP를 제공하지는 않으므로 시간을 한정</strong>
<strong>-&gt;제한 시간의 50~87.5%가 지나면 임대 갱신 필요, 그 이후로는 갱신이 안되고 반환.</strong></p>
<p><img src="https://t1.daumcdn.net/cfile/tistory/257E3F4C57C402461F" alt=""></p>
<p><strong>5. 특정 Service를 제공해야하는 Server나 Gateway의 주소 제외해야 할 IP주소 등을 예외처리한다</strong></p>
<p><img src="https://t1.daumcdn.net/cfile/tistory/2570E24C57C4024730" alt=""></p>
<p><strong>6. 결과 확인</strong></p>
<p><img src="https://t1.daumcdn.net/cfile/tistory/264C394757C4024A17" alt=""></p>
<p><img src="https://t1.daumcdn.net/cfile/tistory/2576534C57C4024829" alt=""></p>
<p>받아간 사용자 정보 확인**</p>
<p><img src="https://t1.daumcdn.net/cfile/tistory/234AFF4757C4024B18" alt=""></p>
<p><img src="https://t1.daumcdn.net/cfile/tistory/220D233757C4034120" alt=""></p>
<p><strong>[Server 외부 위치]</strong>
같은 Broadcast안에 위치하고 있지 않은 경우 IP helper-address라고 하여 해당 Server의 IP주소를 지정 해 주어야 한다.</p>
<p>sw(config)# interface vlan 10
sw(config-if)# ip address 10.1.10.1 255.255.255.0
sw(config-if)# ip helper-address 10.1.100.1</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Route] Routing Table]]></title>
            <link>https://velog.io/@emotional_dev/Route-Routing-Table</link>
            <guid>https://velog.io/@emotional_dev/Route-Routing-Table</guid>
            <pubDate>Thu, 10 Aug 2023 02:37:59 GMT</pubDate>
            <description><![CDATA[<ul>
<li><p>Routing Table?
컴퓨터 네트워크에서 목적지 주소를 목적지에 도달하기 위한 네트워크 노선으로 변환시키는 목적으로 사용된다. 
라우팅 프로토콜의 가장 중요한 목적이 바로 이러한 라우팅 테이블의 구성이다.
네트워크상의 각 라우터에서는 일관된 라우팅 테이블 정보를 가지고 있어야 하며, 그렇지 않을 경우 루프가 발생할 수 있다. 
이는 특히 hop-by-hop 라우팅 방식에서 크게 문제가 되는데, 이는 각 라우터가 올바른 라우팅 테이블을 가지고 있는 것처럼 보여도 서로 패킷을 무한히 주고받게 되기 때문이다. 
라우팅 루프를 피하는 것은 라우팅 프로토콜을 설계할 때 중요한 문제의 하나이다.</p>
</li>
<li><p>Priority
<img src="https://t1.daumcdn.net/cfile/tistory/2523114857D54D1925" alt=""></p>
</li>
</ul>
<p>목적지의 주소가 같을 경우 우선순위를 확인하여 우선순위가 가장 높은 Path를 선택하여 보내게 되는데 우선순위는 아래와 같습니다.</p>
<p><strong>1. Longest Match</strong>
먼저 CIDR(=/24...)을 확인하여 체크해야하는 비트수가 많을수록 정확도가 더 높아지게 되므로 체크 비트수가 높을수록 높은 우선순위를 갖게 됩니다.</p>
<p><strong>2. AD값</strong>
=&gt;Longest Match가 같다면 다음으로는 Administrative Distance라는 관리 거리를 두어 관리자가 라우팅 정보의 신뢰도를 입력하는 정보로 낮을수록 높은 우선순위를 갖게되며, 입력하지 않을 시 Default 값은 1을 갖게 됩니다.</p>
<p><strong>3. Metric값</strong>
=&gt;다음으로는 몇 개의 Router를 거쳐야 목적지에 도착하는지의 정보를 나타내는 Metric값 역시 낮을수록 높은 우선순위를 갖게되며 Metric값은 static으로는 설정이 불가능합니다.</p>
<p><strong>[Floating Static Routing]</strong></p>
<p><img src="https://t1.daumcdn.net/cfile/tistory/274CF34757D550620B" alt="">
Floating Static Routing이란 Routing의 경로에 대해 이중화를 적용하는 개념으로 Static으로 최적의 Path를 설정한 뒤 이 최적경로가 문제가 생길 경우를 대비해 Distance값을 조정하여  Backup Path를 적용할 수 있습니다.</p>
<p><img src="https://t1.daumcdn.net/cfile/tistory/23501C5057D552C612" alt="">
R1 Router에 대해 100.1.3.0 /24 대역대에 대해 Best Path로는 R3방향인 10.1.13.2로
Backup Path로는 R2방향인 10.1.12.2방향을 설정하고 Distance값을 Best Path의 값(default 1)보다 높은 10설정</p>
<p><img src="https://t1.daumcdn.net/cfile/tistory/246F544B57D554041E" alt="">
traceroute를 사용하여 경로를 확인하면 당연히 10.1.13.2를 향해 가는 것을 알 수 있습니다.</p>
<p><img src="https://t1.daumcdn.net/cfile/tistory/2464D14B57D554052B" alt="">
하지만 문제가 생긴 것을 가정하고 s1/1의 연결을 끊고 다시 확인해보면
Backup-Path인 10.1.12.2방향으로 우회하여 목적지로 향하는 것을 알 수 있습니다.
=&gt; 양쪽 경로 모두 best, backup 설정이 되어야 오고가는 정보 모두 원하는 경로로 갈 수 있습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Log]]></title>
            <link>https://velog.io/@emotional_dev/Log</link>
            <guid>https://velog.io/@emotional_dev/Log</guid>
            <pubDate>Thu, 10 Aug 2023 02:14:14 GMT</pubDate>
            <description><![CDATA[<ul>
<li>Log?
시스템의 프로세스 내역, 로그인 내역 등 모든 사용내역을 자동으로 저장하고 볼 수 있는 File.
해킹이나 문제가 발생 시 로그파일을 추적하여 원인을 탐색할 수 있으므로 보호가 필요하며 
자신의 작업 내용들 또한 수동으로 log file을 기록하여 남길 수도 있다.</li>
</ul>
<ul>
<li>종류</li>
<li><em>- /proc :*</em> 현재 동작중인 Program의 정보 저장 (volatility, 휘발성)</li>
<li><em>- /var :*</em> 자주 변경되는 기록 File 저장소 (비휘발성, 누적 기록 File 저장소)
(대부분의 Log들은 /var/log에 저장)</li>
<li><em>- /var/run/utmp :*</em> 현재 접속중인 사용자의 정보를 담은 Log
(단축키 w, who, users 를 통해 접속중인 사용자의 log정보를 출력할 수 있다)</li>
<li><em>- /var/log/wtmp :*</em> 접속을 성공했던 사용자의 Log출력 (단축키 last를 통해서도 확인 가능)</li>
<li><em>- /var/log/btmp :*</em> 접속을 실패했던 사용자의 로그 출력 (단축키 lastb를 통해서도 확인 가능)</li>
<li><em>- /var/log/cron :*</em> 주기적, 예약 작업 Log</li>
<li><em>- /var/log/messages :*</em> 시스템 메세지 Log (Event)</li>
<li><em>- /var/log/secure~ :*</em> 접속 및 인증 관련 Log</li>
<li><em>- /var/log/spooler :*</em> 프린트 연결 Log</li>
<li><em>- /var/log/boot.log :*</em> 부팅 시 시스템 장치 및 데몬 실행 상태 확인 Log</li>
<li><em>- /var/log/xferlog :*</em> 파일 송수신에 관한 Log -&gt; 인증방식 또한 확인할 수 있기 때문에 보안적으로도 좋음</li>
</ul>
<p><img src="https://t1.daumcdn.net/cfile/tistory/2472E84657F603C304" alt=""></p>
<p>-&gt;/etc/loglotate.cont로 들어가서 로그인 정보를 저장하는 파일의 순환주기를 정할 수 있는데
monthly 대신에 weekly , rotate 4 등으로 주면 4주동안 해당 로그를 저장시킬 수 있으며
btmp의 missingok는 로그인이 실패해도 저장된다는 의미입니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[LVM (Logical Volume Manager)]]></title>
            <link>https://velog.io/@emotional_dev/LVM-Logical-Volume-Manager</link>
            <guid>https://velog.io/@emotional_dev/LVM-Logical-Volume-Manager</guid>
            <pubDate>Thu, 10 Aug 2023 02:06:39 GMT</pubDate>
            <description><![CDATA[<ul>
<li>LVM?
LVM은 여러개의 하드를 논리적으로 묶고 원하는 용량만큼 할당하거나 묶은 하드를 다시 나눌수도 있는 동적 하드 스트라이프 기술.
하나 이상의 물리 볼륨(PV 하드디스크 또는 RAID로 생성한 가상 블록장치)을 묶어 볼륨 그룹(VG, Volume Group)을 생성하고
다시 논리 볼륨(LV, Logical Volume)을 생성한 후, 논리 볼륨을 포맷해 사용한다. [PV → VG → LV]</li>
</ul>
<ul>
<li>설정
<img src="https://t1.daumcdn.net/cfile/tistory/2358C23957DD41B225" alt=""></li>
</ul>
<p>LVM에 사용될 장치들을 PV(Physical Volumn)으로 생성</p>
<ul>
<li>LVM 명령어</li>
<li><em>create (생성)
remove (삭제)
scan (검색)
display (확인)
extend(확장)
reduce(축소)
change(속성변경)*</em></li>
</ul>
<p><strong><img src="https://t1.daumcdn.net/cfile/tistory/2755743957DD41B228" alt=""></strong></p>
<p>pvscan으로 확인한 PV설정</p>
<p><strong><img src="https://t1.daumcdn.net/cfile/tistory/2673C53957DD41B309" alt=""></strong></p>
<p>pvdisplay로 확인한 PV설정</p>
<p><strong><img src="https://t1.daumcdn.net/cfile/tistory/2272C83957DD41B30A" alt=""></strong></p>
<p>LVM이라는 VG(Volumn Group)을 생성하여 PV들을 하나로 묶습니다.</p>
<p><strong>EX) vgextend LVM /dev/sde =&gt; 장치 추가가능</strong></p>
<p><strong><img src="https://t1.daumcdn.net/cfile/tistory/21547B3957DD41B428" alt=""></strong></p>
<p>VG를 사용하기위해 LV(Logical Volumn)을 생성하여 각자의 메모리 부여 및 -n(볼륨명)지정</p>
<p>** lvcreate -L [size] -n [볼륨명] [볼륨그룹]**
=&gt; 500M와 같이 고정 용량 또는 100%FREE 등도 사용하여 나머지 용량을 동적으로 할당할 수 있습니다.
<strong>EX)lvreduce -L -1G /dev/LVM/LV1 =&gt; 1G 줄이기</strong></p>
<p><strong><img src="https://t1.daumcdn.net/cfile/tistory/2271403957DD41B40C" alt=""></strong></p>
<p><strong><img src="https://t1.daumcdn.net/cfile/tistory/2260303957DD41B41E" alt=""></strong></p>
<p>LV를 사용하기 위해 포맷 실행</p>
<p><strong><img src="https://t1.daumcdn.net/cfile/tistory/275C693957DD41B521" alt=""></strong></p>
<p>tune2fs -L [라벨명] [LV명]을 사용하여 라벨링이 가능합니다.</p>
<p><strong><img src="https://t1.daumcdn.net/cfile/tistory/2573D03957DD41B609" alt=""></strong></p>
<p>e2label [LV명] [라벨명] 또한 라벨링이 가능하며 해당 LV의 라벨을 확인할 수 있습니다.</p>
<p><strong><img src="https://t1.daumcdn.net/cfile/tistory/2271543957DD41B60C" alt=""></strong></p>
<p>영구 마운트를 위해 fstab수정 및 마운트 확인</p>
<p><strong><img src="https://t1.daumcdn.net/cfile/tistory/2572E53957DD41B70A" alt=""></strong></p>
<p>장치명 공간에 부여한 Label을 입력하고 마운트 정보를 입력합니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[RAID (Redundant Array of Independent Disks)]]></title>
            <link>https://velog.io/@emotional_dev/RAID</link>
            <guid>https://velog.io/@emotional_dev/RAID</guid>
            <pubDate>Thu, 10 Aug 2023 01:57:16 GMT</pubDate>
            <description><![CDATA[<ul>
<li>RAID?
용량이 같은 여러개의 하드 디스크를 하나의 배열로 묶어 데이터를 입출력을 하는 하드디스크의 안정성을 위한 하드 스트라이프 기술.</li>
</ul>
<table>
<thead>
<tr>
<th>레벨</th>
<th>방식</th>
<th>최대 하드 수</th>
<th>용량</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td>0</td>
<td>Stripe 하드 연결</td>
<td>2개 이상</td>
<td>100M+100M = 200M</td>
<td>단순하드연결</td>
</tr>
<tr>
<td>1</td>
<td>Mirroring 동기화</td>
<td>2개 이상</td>
<td>100M+100M = 100M</td>
<td>동기화된 하드 대체 연결 (spair)</td>
</tr>
<tr>
<td>2</td>
<td>백업+DATA 각각 사용</td>
<td>2개 이상</td>
<td>100M+100M = 100M</td>
<td>백업된 내용으로 복구 (사용 안함)</td>
</tr>
<tr>
<td>3</td>
<td>패리티 영역 추가 (byte단위)</td>
<td>3개 이상</td>
<td>100M+100M+100M = 200M</td>
<td>오류 기록 하드영역 1개 추가<br>한 개의 하드 에러 시 복구<br>RAID4보다 속도가 느리고 패리티 영역 손상시 복구 불가</td>
</tr>
<tr>
<td>4</td>
<td>패리티 영역 추가 (block단위)</td>
<td>3개 이상</td>
<td>100M+100M+100M = 200M</td>
<td>오류 기록 하드영역 1개 추가<br>한 개의 하드 에러 시 복구<br>패리티 영역 손상시 복구 불가</td>
</tr>
<tr>
<td>5</td>
<td>각 하드에 분산 패리티 영역 할당 (3개 이상)</td>
<td>3개 이상</td>
<td>100M+100M+100M(p) = 200M</td>
<td>패리티 영역을 각 하드디스크에 분산 시킴<br>랜덤한 하드 1개의 손상에 대한 복구 가능</td>
</tr>
<tr>
<td>6</td>
<td>각 하드에 분산 패리티 영역 할당 (4개 이상)</td>
<td>4개 이상</td>
<td>100M+100M+100M(p)+100M(p) = 200M</td>
<td>패리티 영역을 각 하드디스크에 분산 시킴<br>랜덤한 하드 2개의 손상에 대한 복구 가능</td>
</tr>
</tbody></table>
<ul>
<li><strong>설정 (Level 5)</strong></li>
</ul>
<p><strong><img src="https://t1.daumcdn.net/cfile/tistory/264AB64357DCED401C" alt=""></strong></p>
<p>RAID로 묶을 하드디스크를 추가합니다.
<strong>mdadm  --create(-C) [/dev/md(x)] --level(-l) [0~6] --raid-devices(-n) [sdb(x)]</strong></p>
<p><strong><img src="https://t1.daumcdn.net/cfile/tistory/256A5D4057DCEF5907" alt=""></strong>
RAID생성 명령어를 사용하여 /dev/md5란 이름의 level 5단계로 sdb,sdc,sdd까지 3개의 디바이스를 묶습니다.</p>
<p><strong><img src="https://t1.daumcdn.net/cfile/tistory/2330E84057DCEF5B32" alt=""></strong></p>
<p>마운트를 위한 포맷</p>
<p><strong><img src="https://t1.daumcdn.net/cfile/tistory/2772554057DCEF5B01" alt=""></strong></p>
<p>마운트 및 mount -a로 마운트를 확인합니다.</p>
<p><strong><img src="https://t1.daumcdn.net/cfile/tistory/275A9F4F57DCEFDA1E" alt=""></strong></p>
<p>blkid란 명령어로 추가된 디바이스의 UUID및 구조 확인이 가능합니다.</p>
<p><strong><img src="https://t1.daumcdn.net/cfile/tistory/22519C4F57DCEFDB25" alt=""></strong></p>
<p>/etc/fstab에 추가하여 영구적으로 마운트를 하기위해 awk명령어로 UUID만을 추출하여 redirection으로 추가합니다.</p>
<p><strong><img src="https://t1.daumcdn.net/cfile/tistory/25636C4F57DCEFDD17" alt=""></strong></p>
<p>mdadm -D(Detail)로 확인할 수 있는 생성된 RAID의 구조</p>
<p><strong><img src="https://t1.daumcdn.net/cfile/tistory/265EFA4F57DCEFDE1B" alt=""></strong></p>
<p>정상적으로 추가되는 파일</p>
<p><strong><img src="https://t1.daumcdn.net/cfile/tistory/246FEB4F57DCEFDE10" alt=""></strong></p>
<p>level 5는 각 하드에 분산패리티영역이 생성되기 때문에 랜덤한 하드 1개가 오류가나도 복구가 가능합니다.</p>
<p>-&gt; /dev/sdb를 제거한 상태</p>
<p><strong><img src="https://t1.daumcdn.net/cfile/tistory/25678E4F57DCEFDF14" alt=""></strong></p>
<p>정상적으로 생성되는 파일</p>
<p><strong><img src="https://t1.daumcdn.net/cfile/tistory/254B614F57DCEFDF29" alt=""></strong></p>
<p>하지만 장치를 하나 더 제거할 시 읽기전용 파일 시스템으로 변환되어 파일을 생성할 수 없게됩니다.</p>
<ul>
<li>** RAID 관련 명령어**</li>
<li><em>mdadm /dev/md5  -f (기존 디바이스 비활성)*</em> <strong>-r (기존 디바이스 삭제)</strong> <strong>-a (RAID에 새로운 디바이스 추가)</strong></li>
<li><em>mdadm --stop(-S) /dev/md5 (RAID 비활성)*</em></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[DoS Attack (Scapy, Slowloris attack)]]></title>
            <link>https://velog.io/@emotional_dev/DoS-Attack-Scapy-Slowloris-attack</link>
            <guid>https://velog.io/@emotional_dev/DoS-Attack-Scapy-Slowloris-attack</guid>
            <pubDate>Wed, 09 Aug 2023 08:15:56 GMT</pubDate>
            <description><![CDATA[<p>(간단한 개념 숙지를 위한 과거 포스팅 내용입니다.)</p>
<ul>
<li><p>DoS(Denial Of Service) Attack?
시스템을 악의적으로 공격해 해당 시스템의 리소스를 부족하게 하여 원래 의도된 용도로 사용하지 못하게 하는 공격.
대량의 데이터 패킷을 통신망으로 보내고 특정 서버에 수많은 접속 시도를 하는 등 다른 이용자가 정상적으로 서비스 이용을 하지 못하게 하거나, 서버의 TCP 연결을 바닥내는 등의 공격이 이 범위에 포함된다.</p>
</li>
<li><p>Scapy? : 파이썬으로 작성된 패킷 조작 도구로서, 패킷 디코딩, 패킷전송, 패킷 캡쳐, 패킷 수정 등의 다양한 기능이 있다</p>
</li>
<li><p>실습 환경</p>
<ul>
<li>공격자 : 192.168.1.129</li>
<li>희생자 : 192.168.1.130</li>
</ul>
</li>
</ul>
<p><img src="https://t1.daumcdn.net/cfile/tistory/994ACA335994158F18" alt=""></p>
<p>위와 같이 scapy를 실행하면 파이썬 언어를 인식하는 인터프리터가 다음과 같이 나오며 
필요에 따라 라이브러리를 추가로 설치해야 스크립트가 정상적으로 작동하는 경우가 있습니다.</p>
<p><strong>ls()</strong>와 같이 입력한다면 scapy에서 지원하는 프로토콜들을 보여줍니다.</p>
<p><img src="https://t1.daumcdn.net/cfile/tistory/996AF5335994158F15" alt=""></p>
<p><strong>lrs()</strong>를 입력한다면 scapy에서 사용가능한 기능들을 보여줍니다.</p>
<p><img src="https://t1.daumcdn.net/cfile/tistory/99BD11335994158F25" alt=""></p>
<p>공격을 위해 공격자 PC에서 iptables를 사용하여 TCP 플래그가 RST인 패킷을 DROP시킵니다.</p>
<p><strong>#iptables -A OUTPUT -p tcp --tcp-flags RST RST -J DROP</strong>
<strong>#iptables -L</strong></p>
<p><img src="https://t1.daumcdn.net/cfile/tistory/99C97D335994159025" alt=""></p>
<p>scapy를 실행하여 IP헤더를 확인하는 <strong>IP()</strong>를 입력하여 아직 아무 것도 없는 것을 확인할 수 있으며 
display() 함수를 사용하여 좀 더 자세히 봄으로써 src,dst모두 루프백주소로 되어 있는 것을 확인할 수 있습니다.</p>
<p><img src="https://t1.daumcdn.net/cfile/tistory/992EDC33599415901B" alt=""></p>
<p><strong>IP(dst=&quot;192.168.1.130&quot;).display</strong></p>
<p>를 입력한다면 위와 같이 헤더 내용이 바뀌는 것을 확인할 수 있지만 아직까지는 실제로 변경된 것은 아닙니다.
IP 주소 대신 도메인 주소를 넣어도 무관합니다.</p>
<p><img src="https://t1.daumcdn.net/cfile/tistory/99642D335994159016" alt=""></p>
<p>위와 같이 TCP 또한 같은 방법으로 헤더 내용 확인 및 헤더의 값 변경이 가능합니다.</p>
<p><img src="https://t1.daumcdn.net/cfile/tistory/999838335994159129" alt=""></p>
<p>위의 값들을 실제 변수에 넣기위해</p>
<p><strong>&gt;&gt;&gt;ip=IP(dst=&quot;192.168.1.130&quot;)</strong>
<strong>&gt;&gt;&gt;tcp=TCP(sport=RandNum(1024,65535), dport=80, flags=&#39;S&#39;)</strong>
<strong>&gt;&gt;&gt;syn=ip/tcp</strong>
<strong>&gt;&gt;&gt;syn.display()</strong></p>
<p>를 사용하여 변수 값 변경 및 내용을 확인합니다.
TCP의 sport는 RandNum함수를 사용하여 Well-Known 포트를 제외한
1024-65535포트 중 하나를 선택하며
syn이라는 변수에 /로 구분을 하여 ip,tcp 값을 넣어줍니다.</p>
<p><img src="https://t1.daumcdn.net/cfile/tistory/991B93335994159134" alt=""></p>
<p>실제로 tcp의 three-way-handshaking 과정을 확인하기 위해
three-way-handshake를 맺는 파이썬 스크립트를 위와 같이 작성합니다.
sy1()함수를 사용하여 syn변수에 정의된 패킷을 보내고 그 응답(syn+ack)를 syn_ack에 저장한 후 
ack변수에 응답 값을 설정하여 보냅니다.</p>
<p><img src="https://t1.daumcdn.net/cfile/tistory/999CED33599415911F" alt=""></p>
<p>희생자 PC에서 apache서버를 구동합니다.</p>
<p><img src="https://t1.daumcdn.net/cfile/tistory/996A8B33599415920B" alt=""></p>
<p>공격자 PC에서 작성한 스크립트를 실행하여 패킷을 보냅니다.</p>
<p><img src="https://t1.daumcdn.net/cfile/tistory/99994E335994159207" alt=""></p>
<p>공격자 pc에서 wireshark를 사용하여 패킷을 분석해보면 정상적인 three-way-handshake 과정을 확인할 수 있습니다.</p>
<ul>
<li>TCP SYN Flooding?
3-way-handshake를 맺을 때, 공격자가 희생자의 listen 포트로 연결을 요청하는 SYN패킷을 보낸 후 SYN+ACK를 받게 된다. 
하지만 이 후 최종적으로 ACK패킷을 보내지 않게 된다면 서버는 Half-open상태로 변하며 일정 기간(약 75초) ACK를 기다리며 Backlog Queue 메모리 공간에 SYN정보를 계속 쌓아두게 된다.
이러한 공격이 계속된다면 희생자 서버는 더 이상 SYN을 받을 수 없는 상태가 되며 이를 TCP SYN Flooding공격이라 한다.</li>
</ul>
<p><img src="https://t1.daumcdn.net/cfile/tistory/99B09733599415921D" alt=""></p>
<p>TCP SYN Flooding을 실습하기 위해 공격자 PC에서 위와 같은 파이썬 스크립트를 작성합니다.</p>
<p><img src="https://t1.daumcdn.net/cfile/tistory/995C5B33599415930C" alt=""></p>
<p>희생자 PC에서</p>
<p><strong>#sysctl -a | grep syncookies</strong></p>
<p>를 사용하여 syncookies가 설정되어 있는지 확인합니다.</p>
<ul>
<li>Syncookies?
syncookies가 설정되어 있다면 syn+ack 패킷을 보낼 때 seq num을 쿠키 값으로 설정한다. 
상대방 ack패킷이 쿠키 값+1로 설정되어 있지 않으면 비정상 패킷으로 받아들여 연결을 맺지 않게 된다.</li>
</ul>
<p><img src="https://t1.daumcdn.net/cfile/tistory/992DC6335994159329" alt=""></p>
<p><strong>#sysctl -w net.ipv4.tcp_syncookies=0</strong></p>
<p>을 사용하여 해당 값을 초기화 시킵니다.</p>
<p><img src="https://t1.daumcdn.net/cfile/tistory/99B592335994159334" alt=""></p>
<p>공격자 PC에서 위에서 작성한 스크립트를 
스크립트명, 희생자 IP, 희생자 PORT와 함께 실행한다면
위와 같이 실행되게 됩니다.</p>
<p><img src="https://t1.daumcdn.net/cfile/tistory/999A25335994159307" alt=""></p>
<p>브라우저를 열어 희생자 PC IP로 정상적인 접근을 한다고 하더라도 무한루프가 돌게 되어 접근이 불가능 합니다.</p>
<p><img src="https://t1.daumcdn.net/cfile/tistory/991205335994159414" alt=""></p>
<p>또한 wireshark를 사용하여 syn+ack만을 주고 받는 것을 확인할 수 있습니다.</p>
<p><img src="https://t1.daumcdn.net/cfile/tistory/99AAAB335994159435" alt=""></p>
<p>희생자 pc에서 half-open 상태의 소켓을 확인하는</p>
<p><strong>#netstat -an | grep -i syn_recv</strong></p>
<p>를 사용하여 공격자의 random포트에게 syn를 받은 채 대기중인 상태임을 알 수 있습니다.
이번에는 응용 계층의 http 프로토콜의 취약점을 사용한 slowloris attack를 실습해봅니다.</p>
<ul>
<li>Slowloris attack?
http 헤더가 끝날 때, 개행(carriage return line feed)을 두 번 하게되어 헤더와 데이터를 구분하는데 
slowloris attack은 헤더 마지막 부분에 \r\n\r\n대신 \r\n 한 번만 보내 
아직 헤더가 더 남은 것처럼 서버를 속여 해당 연결을 계속 유지하게 한다.</li>
</ul>
<p><img src="https://t1.daumcdn.net/cfile/tistory/997C90335994159520" alt=""></p>
<p>공격자 pc에서 위와 같이 script를 입력합니다.</p>
<p><img src="https://t1.daumcdn.net/cfile/tistory/99A375335994159506" alt=""></p>
<p>해당 스크립트를 공격자 pc에서 희생자 ip, 연결 횟수와 함께 실행을 시킨 후 희생자 pc의 브라우저에서 
<a href="http://localhost/server-status%EB%A5%BC">http://localhost/server-status를</a> 입력하여 현재 apache의 상태를 확인하면 연결 상태들이 모두 R(읽고 있는 상태)임을 알 수 있습니다.</p>
<p><img src="https://t1.daumcdn.net/cfile/tistory/998FC0335994159638" alt=""></p>
<p>wireshark를 사용하여 해당 패킷을 hex dump모드로 확인하면 개행문자 0d 0a가 한 개 밖에 없는 것을 확인할 수 있습니다.</p>
<p><img src="https://t1.daumcdn.net/cfile/tistory/994CF3335994159601" alt=""></p>
<p>또한 ascii모드로 확인한다면 개행으로 인한 헤더와 데이터 구분 없이 확인을 위한 메세지가 헤더에 이어 작성된 것을 알 수 있습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Nmap Port Scanning]]></title>
            <link>https://velog.io/@emotional_dev/Nmap-Port-Scanning-lqgq97s0</link>
            <guid>https://velog.io/@emotional_dev/Nmap-Port-Scanning-lqgq97s0</guid>
            <pubDate>Wed, 09 Aug 2023 08:03:11 GMT</pubDate>
            <description><![CDATA[<p>(간단한 개념 숙지를 위한 과거 포스팅 내용입니다.)</p>
<ul>
<li>Nmap(Network Map)?
고든 라이온(Gordon Lyon)이 작성한 보안 스캐너. 
컴퓨터와 서비스를 찾을 때 쓰이며, 네트워크 &quot;지도&quot;를 함께 만듭니다. 
다른 간단한 포트 스캐너들처럼, Nmap은 서비스 탐지 프로토콜로 자신을 광고하지 않는 수동적인 서비스들도 찾아낼 수 있습니다. 
게다가 Nmap은 원격 컴퓨터들의 자세한 정보를 알아낼 수 있으며 주요 항목들은 아래와 같습니다.<ul>
<li>운영체제</li>
<li>장치 종류</li>
<li>운영 시간</li>
<li>서비스에 쓰이는 소프트웨어 제품</li>
<li>그 제품의 정확한 버전</li>
<li>방화벽 존재 여부</li>
<li>근거리 네트워크의 네트워크 카드 공급자</li>
<li>네트워크 연결된 호스트들의 IP/OS</li>
<li>서버의 열린 포트</li>
</ul>
</li>
</ul>
<p>이를 통해 공격자는 침투에 필요한 정보를 얻을 수 있으며 방어자는 불필요하게 노출되는 정보를 확인하여 방어를 할 수 있습니다.</p>
<ul>
<li>실습 환경<ul>
<li>공격자 IP : 192.168.1.129</li>
<li>희생자 IP : 192.168.1.130</li>
</ul>
</li>
</ul>
<p><img src="https://t1.daumcdn.net/cfile/tistory/9901A43359818AEE24" alt=""></p>
<p>테스트를 위해 희생자 pc에서 ftp,dns,http서비스를 시작한후 wireshark를 실행합니다.</p>
<p><img src="https://t1.daumcdn.net/cfile/tistory/991BBF3359818AEE33" alt=""></p>
<p>공격자 pc에서 nmap을 사용하여 확인 시 희생자 pc에서 열려있는
21,53,80 포트 번호의 서비스를 확인할 수 있습니다.</p>
<p><img src="https://t1.daumcdn.net/cfile/tistory/996B063359818AEF2E" alt=""></p>
<p>희생자 pc에서 실행한 wireshark로 확인 시 열린 포트들에 대해서는 SYN+ACK를 보내지만 
닫혀진 포트에 대해서는 RST패킷을 전송하여 연결을 종료합니다.
이러한 스캔 방식을 <strong>TCP Half(SYN) Open Scan</strong>이라고 하며 
불완전한 TCP 세션 과정에서 Open된 Port를 확인하며 Log를 남기지 않습니다.
옵션을 주지 않는다면 -sS(TCP Half open scan)과 같은 의미로 스캔합니다.</p>
<p><img src="https://t1.daumcdn.net/cfile/tistory/990DE03359818ED20F" alt=""></p>
<p><img src="https://t1.daumcdn.net/cfile/tistory/9981FB3359818ED308" alt=""></p>
<p><strong>[TCP Half Open Scan]</strong>  </p>
<p><img src="https://t1.daumcdn.net/cfile/tistory/992EEC3359818AEF32" alt=""></p>
<p>로그를 남기기 때문에 많이 쓰이진 않지만</p>
<p><strong>#nmap -sT [IP Address]</strong></p>
<p>를 사용하면 완전한 세션을 맺어 로그를 남기는 TCP Open Scan을 실행합니다.</p>
<p><img src="https://t1.daumcdn.net/cfile/tistory/99155033598191492D" alt=""></p>
<p><strong>[TCP Open Scan]</strong>  </p>
<p>스캔하는 대상에 로그를 남기지 않는 Stelth Scan에는 TCP Half Scan, FIN Scan, Xmas Scan, Null Scan이 있으며 옵션은 다음과 같습니다.</p>
<p><img src="https://t1.daumcdn.net/cfile/tistory/9984743359818AEF2E" alt=""></p>
<p><strong>&lt;FIN Scan&gt;</strong></p>
<p>열린 포트라면 아무 응답이 오지 않으며, 닫힌 포트이면 RST응답이 옵니다.</p>
<p><img src="https://t1.daumcdn.net/cfile/tistory/99231E3359818AF033" alt=""></p>
<p><strong>&lt;X-mas Scan&gt;</strong></p>
<p>공격자는 FIN,PSH,URG 패킷을 보내며 열린 포트이면 아무런 응답이 오지 않고 닫힌 포트이면 RST 응답이 돌아옵니다.</p>
<p><img src="https://t1.daumcdn.net/cfile/tistory/992CCC3359818AF032" alt=""></p>
<p><strong>&lt;Null Scan&gt;</strong></p>
<p>공격자는 Null 패킷을 보내며 열린 포트이면 아무런 응답이 오지 않으며, 닫힌 포트라면 RST 응답이 돌아옵니다.</p>
<p><img src="https://t1.daumcdn.net/cfile/tistory/99C1CC3359818AF104" alt=""></p>
<p>이외에도 포트를 지정하는 옵션 -p와 OS를 판별하는 옵션 -O를 사용하여 추가적인 정보를 얻는 것이 가능합니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[DNS Server & DNS 정보 수집 (BIND, DNSMAP)]]></title>
            <link>https://velog.io/@emotional_dev/DNS-Server-DNS-%EC%A0%95%EB%B3%B4-%EC%88%98%EC%A7%91-BIND-DNSMAP</link>
            <guid>https://velog.io/@emotional_dev/DNS-Server-DNS-%EC%A0%95%EB%B3%B4-%EC%88%98%EC%A7%91-BIND-DNSMAP</guid>
            <pubDate>Wed, 09 Aug 2023 07:26:22 GMT</pubDate>
            <description><![CDATA[<p>(간단한 개념 숙지를 위한 과거 포스팅 내용입니다.)  </p>
<p><img src="https://t1.daumcdn.net/cfile/tistory/260FF233597886291C" alt=""></p>
<p>UNIX/LINUX에서 Name Server를 운용하기위한 패키지인 <strong>BIND(Berkeley Internet Name Domain)</strong>을 설치합니다.
BIND패키지를 사용하면 도메인을 IP로 변환시켜 주는 DNS Server구축이 가능합니다.</p>
<p><img src="https://t1.daumcdn.net/cfile/tistory/26104633597886291C" alt=""></p>
<p>설치 후 패키지내 <strong>/etc/bind</strong>에서 목록을 확인합니다.</p>
<p><img src="https://t1.daumcdn.net/cfile/tistory/2320B8335978862B1B" alt=""></p>
<p>zone 파일의 기본형식인 db.local파일을 복하사여 db.zone파일로 설정합니다.</p>
<ul>
<li>zone file?
도메인 네임과 IP를 매핑한 정보들이 들어 있는 중요한 파일.
DNS 서버는 ZONE파일을 읽어 도메인 주소를 IP주소로 변환한다.</li>
</ul>
<p><img src="https://t1.daumcdn.net/cfile/tistory/2717A1335978862A1B" alt=""></p>
<p>웹서버,ftp서버,메일 서버를 humanist.hum.kr라는 도메인으로 묶어주기 위해 db.zone파일의 정보를 위와 같이 수정합니다.
각 레코드의 정보는 아래와 같습니다.</p>
<ul>
<li>TTL(Time To Live) : DNS 캐시를 저장하는 기간을 초단위로 나타냄. ZONE파일에서 가장 먼저 선언되어야 합니다.</li>
<li>@ : $ORIGIN 지시어라고 하며 도메인 주소 원형을 뜻한다. named.conf.local에 설정해 줄 도메인인데, 여기서는 humanist.hum.kr.로 설정했습니다.</li>
<li>IN : 클래스로서 iNTERNET을 나타낸다.</li>
<li>SOA(Start Of Authority) : zone파일의 시작을 알리며 네임 서버 주소(ns.humanist.hum.kr.)와 관리자 메일 주소(root.humanist.hum.kr.)를 정의하고 소괄호를 이용하여 몇 가지 설정을 해줍니다. 
도메인 끝에 오는 &#39;.&#39;는 최상위 root도메인을 의미합니다. 
브라우저에서는 자동으로 최상위 도메인을 처리하기 때문에 표시하지 않아도 되지만 zone파일에서는 표기해줘야 합니다.</li>
<li>NS : 네임서버의 도메인 주소(localhost.으로 매핑). localhost.는 SOA레코드에서 설정한 ns.humanist.hum.kr.과 같습니다.</li>
<li>MX : 메일 서버의 라우팅 경로. MX 다음의 숫자는 Priority number로서 우선순위를 나타냅니다.</li>
<li>A : 도메인 주소에 IPV4를 매핑합니다.</li>
<li>AAAA :** 도메인 주소에 IPV6를 매핑합니다.</li>
</ul>
<p><img src="https://t1.daumcdn.net/cfile/tistory/24E8C5335978862B1F" alt=""></p>
<p><strong>#vi named.conf.local</strong></p>
<p>위와 같이 zone파일의 형식과 경로를 지정해줍니다.</p>
<p><img src="https://t1.daumcdn.net/cfile/tistory/24589B335978862D2B" alt=""></p>
<p>bind데몬을 재시작한 후</p>
<p><strong>#vi /etc/resolv.conf</strong></p>
<p>에서 </p>
<p>nameserver 192.168.1.130 (서버주소)
nameserver 168.126.63.1 (한국통신 DNS 서버 주소)</p>
<p>를 설정한 후 Ping을 통해 확인합니다.</p>
<p><img src="https://t1.daumcdn.net/cfile/tistory/22EF7F335978862D34" alt=""></p>
<p>네임 서버가 등록된 공격자 PC에서</p>
<p><strong>#dnsmap humanist.hum.kr</strong></p>
<p>을 실행하여 dns정보 수집을 시작합니다.
위 경우는 8개의 도메인 네임과 8개의 ip를 찾았다는 메세지가 출력됩니다.</p>
<p><img src="https://t1.daumcdn.net/cfile/tistory/218760335978862E2C" alt=""></p>
<p>희생자 PC에서 wireshark를 통해 확인합니다.
Filter창에 <strong>dns</strong>를 입력하연 목록 창에 dns관련 패킷만 표시되며</p>
<p><strong>dns.flags.response == 0</strong>이면 DNS조회 목록이
<strong>dns.flags.response == 1</strong>을 입력하면 DNS 응답 목록이 출력됩니다.</p>
<p><img src="https://t1.daumcdn.net/cfile/tistory/265A76335978862F31" alt=""></p>
<p><strong>dns.flags.rcode != 0</strong>을 입력하면 DNS응답 중에 에러만 필터링해서 출력합니다.</p>
<p><img src="https://t1.daumcdn.net/cfile/tistory/2720F8335978862F35" alt=""></p>
<p>위와 같이 <strong>[Analize] &gt; [Display Filter]</strong>에서 필터를 저장하여 사용이 가능합니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[DNS Spoofing (Ettercap)]]></title>
            <link>https://velog.io/@emotional_dev/DNS-Spoofing-Ettercap</link>
            <guid>https://velog.io/@emotional_dev/DNS-Spoofing-Ettercap</guid>
            <pubDate>Wed, 09 Aug 2023 06:44:30 GMT</pubDate>
            <description><![CDATA[<p>(간단한 개념 숙지를 위한 과거 포스팅 내용입니다.)</p>
<ul>
<li><p>DNS Spoofing?
DNS 스푸핑(DNS spoofing) 또는 DNS 캐시 포이즈닝(DNS cache poisoning)은 변질된 DNS 데이터가 DNS resolver의 캐시에 유입되어 네임 서버가 유효하지 않은 결과 레코드(예: IP 주소)를 반환합니다. 이를 통해 공격자의 컴퓨터(또는 다른 컴퓨터)로 공격 우회를 할 수 있습니다.</p>
</li>
<li><p>실습 환경</p>
<ul>
<li>Web Server : Apache2</li>
<li>공격자 IP : 192.168.1.128</li>
<li>희생자 IP : 192.168.1.130</li>
</ul>
</li>
</ul>
<p><img src="https://t1.daumcdn.net/cfile/tistory/2425B15058C52C9C1D" alt=""></p>
<p>먼저 공격자 host 쪽에서 웹서버 데몬인 apache2를 실행합니다.</p>
<p><img src="https://t1.daumcdn.net/cfile/tistory/2778585058C52C9D07" alt=""></p>
<p>이 후 사용할 LAN구간에서 Man-IN-THE-MIDDLE공격을 하기 위한 무료 Opensource dns spoofing 도구인 
<strong>Etter cap</strong>의 host 파일(/etc/ettercp/etter.dns)을 위와 같이 수정하여 
희생자가 naver나 google로 접속할 시 공격자가 지정해놓은 ip로 들어올 수 있도록hosts파일을 수정합니다.
이렇게 한다면 dns server를 직접적으로 공격하지 않아도 hosts file의 변조를 통해 DNS Spoofing 공격을 실행할 수 있습니다.</p>
<p><img src="https://t1.daumcdn.net/cfile/tistory/265BE15058C52C9E18" alt=""></p>
<p>공격자 PC에서 &#39;etthercap -G&#39;을 입력하여
ettercap GUI를 실행한 후 Sniff 탭의 unified sniffing을 선택합니다.</p>
<p><img src="https://t1.daumcdn.net/cfile/tistory/2652245058C52C9F0C" alt=""></p>
<p><img src="https://t1.daumcdn.net/cfile/tistory/2269655058C52C9F09" alt=""></p>
<p>Network interface로 eth0을 선택한 후 scan for hosts를 선택하여
같은 LAN구간에 있는 hosts를 스캔한 후
게이트웨이인 <strong>192.168.1.2</strong>를 <strong>Target 1</strong>로,
희생자 ip인 <strong>192.168.1.130</strong>을 <strong>Target 2</strong>로 지정합니다.</p>
<p><img src="https://t1.daumcdn.net/cfile/tistory/2214FC5058C52CA012" alt=""></p>
<p>Mitm메뉴의 arp posisoning을 선택한 후 Sniff remote connection을 체크하여
이로 인해 공격자가 둘 사이로 들어가 arpspoofing을 할 수 있도록 설정합니다.</p>
<p><img src="https://t1.daumcdn.net/cfile/tistory/2235505058C52CA00F" alt=""></p>
<p>마지막으로 Plugin메뉴의 Manage the plugins를 선택한 후 dns-spoof를 활성화합니다.</p>
<p><img src="https://t1.daumcdn.net/cfile/tistory/2755934958C52CA325" alt=""></p>
<p>이로 인해 희생자 pc에서 위와 같이 <a href="http://www.google.com%EC%9C%BC%EB%A1%9C">www.google.com으로</a> 접속을 시도하면
arp spoofing과 dns spoofing으로 공격자의 web server가 표시되게 됩니다.
이렇게 되면 희생자의 DNS Cache table에서 google과 관련된 cache가 공격자 ip로 바뀌어 있기 때문에 
cache가 유지되어 있는 동안에는 공격자의 web server가 계속 나타나게 됩니다.</p>
<p><strong>C:\&gt;ipconfig /flushdns (windows) , $ sudo /etc/init.d/nscd restart (Unix/Linux)</strong></p>
<p>등의 명령어로 dns cache table을 초기화합니다.
=&gt;DNS Spoofing의 대응방안으로는 앞에서 위조했던 hosts파일의 무결성을 검사하거나 
dns cache의 Poisoning을 보호하는 솔루션을 사용(DNSSEC...) 또는 이전에 다뤄봤던 ARP Spoofing 방지 솔루션을 사용하여 대응할 수 있습니다.</p>
]]></description>
        </item>
    </channel>
</rss>