<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>즐겁게 살고 싶은 개발자</title>
    <link>https://2dongdong.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Tue, 14 Apr 2026 21:18:03 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>평범한 개발자...</managingEditor>
    <item>
      <title>[Spring boot] HTTP API 만들기 -  Hello World!</title>
      <link>https://2dongdong.tistory.com/77</link>
      <description>&lt;p&gt;Spring boot로 HTTP API를 만들기 전에, MVC 구조로 웹 애플리케이션이 어떠한 원리로 만들어지고 동작하는지 이해가 필요합니다.&lt;/p&gt;
&lt;p&gt;이번 글에서는 간단한 API 1개와 웹페이지 1개를 만들어보고, 그 차이와 원리에 대해서 설명해보겠습니다.&lt;/p&gt;
&lt;h1&gt;1. 프로젝트 생성&lt;/h1&gt;
&lt;p&gt;인텔리제이를 기준으로 진행합니다.&lt;/p&gt;
&lt;p&gt;[프로젝트 환경]&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Gradle&lt;/li&gt;
&lt;li&gt;Java 1.8&lt;/li&gt;
&lt;li&gt;Spring Boot 2.5.5&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;[Dependencies]&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Spring Boot DevTools&lt;ul&gt;
&lt;li&gt;자동 재시작 기능 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Spring Web&lt;ul&gt;
&lt;li&gt;내장 톰캣, 웹, MVC, RESTful 등 대다수 기능 포함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Thymeleaf&lt;ul&gt;
&lt;li&gt;웹 개발을 위한 서버사이드 자바 템플릿 엔진&lt;/li&gt;
&lt;li&gt;API를 개발하는데 필요하지 않지만, 원리를 설명하고 비교하기 위함.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;인텔리제이 얼티메이트 버전을 사용하시는 분들은 툴에 내장된 Spring Initalizr를 이용하여 프로젝트를 생성하면 되고,&lt;br&gt;&lt;img src=&quot;https://images.velog.io/images/lehdqlsl/post/7a7e29df-54be-4c91-bdc5-c428704466aa/image.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;커뮤니케이션 버전을 사용하시는 분들은, &lt;a href=&quot;https://start.spring.io&quot;&gt;https://start.spring.io&lt;/a&gt; 에 접속하셔서 아래와 같이 설정 후, 프로젝트를 다운받아 압축해제하여 인텔리제이로 Import하면 됩니다.&lt;br&gt;&lt;img src=&quot;https://images.velog.io/images/lehdqlsl/post/d1151692-da13-45ae-b8a3-3cd2555032c3/image.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h1&gt;2. Controller 생성&lt;/h1&gt;
&lt;p&gt;하위에 controller 패키지를 생성 하고 APIController.java, WebController.java 파일을 만듭니다.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://images.velog.io/images/lehdqlsl/post/106ac7a2-5175-4a97-9f05-4c6cbf22c99d/image.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2&gt;APIController.java 작성&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;@Controller
public class APIController {

    @ResponseBody
    @GetMapping(&amp;quot;/api/hello&amp;quot;)
    public String api(){
        return &amp;quot;Hello World!&amp;quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;WebController.java 작성&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;@Controller
public class WebController {

    @GetMapping(&amp;quot;/web/hello&amp;quot;)
    public String web(Model model){
        model.addAttribute(&amp;quot;msg&amp;quot;,&amp;quot;Hello World!&amp;quot;);
        return &amp;quot;/hello&amp;quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;프로젝트 resources/templates 폴더에 hello.html 파일을 하나 생성합니다.&lt;br&gt;&lt;img src=&quot;https://images.velog.io/images/lehdqlsl/post/f6b405a1-c2f9-46ae-bcb1-329da88660d1/image.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;hello.html 작성&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html lang=&amp;quot;en&amp;quot;&amp;gt;
&amp;lt;head&amp;gt;
    &amp;lt;meta charset=&amp;quot;UTF-8&amp;quot;&amp;gt;
    &amp;lt;title&amp;gt;Title&amp;lt;/title&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
[[ ${msg} ]]
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;h1&gt;3. 실행&lt;/h1&gt;
&lt;p&gt;실행 후 크롬창을 열고 아래 각각 URL에 접속해봅니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;localhost:8080/api/hello&lt;br&gt;&lt;img src=&quot;https://images.velog.io/images/lehdqlsl/post/94db0f6b-4e26-42bc-84dd-12c41178da31/image.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;localhost:8080/web/hello&lt;br&gt;&lt;img src=&quot;https://images.velog.io/images/lehdqlsl/post/d67b5da7-42ec-4776-84a9-1022dad110a5/image.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;크롬 개발자 도구 확인&lt;/h2&gt;
&lt;p&gt;F12을 눌러 개발자 도구를 연다음 Network 탭으로 들어갑니다.&lt;br&gt;그 다음 새로고침을 눌러서 한번 더 요청해봅니다. 해당 요청의 Response 탭으로 이동하면 서버로 부터 어떤 응답을 받았는지 확인할 수 있습니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;localhost:8080/api/hello&lt;br&gt;&lt;img src=&quot;https://images.velog.io/images/lehdqlsl/post/a7b78c4f-aa46-488f-bb65-b7ee6a26a86c/image.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;localhost:8080/web/hello&lt;br&gt;&lt;img src=&quot;https://images.velog.io/images/lehdqlsl/post/2de1791c-832a-40b3-92a7-de0a2740823f/image.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;차이점 및 원리&lt;/h2&gt;
&lt;p&gt;코드상의 공통점은&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;둘 다 @Controller 어노테이션을 사용하였고&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;차이점은&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;/api/hello의 경우 @ResponseBody 어노테이션이 붙어있고 &lt;code&gt;Hello World!&lt;/code&gt; 문자열을 반환합니다.&lt;/li&gt;
&lt;li&gt;/web/hello의 경우 &lt;code&gt;Hello World!&lt;/code&gt; 값을 Model 속성에 넣고, /hello 경로를 반환합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Spring Boot를 Thymeleaf와 같은 템플릿 엔진을 이용하여 웹 애플리케이션을 개발하는 경우, 후자와 같이 컨트롤러 요청이 왔을 때, 템플릿 경로를 반환하게 됩니다.&lt;/p&gt;
&lt;p&gt;그러면 ViewResolver를 통해 해당 템플릿을 찾아가서 문법을 해석하고 값을 바인딩 한 뒤, 최종적으로 html 코드 형태로 응답합니다.&lt;/p&gt;
&lt;p&gt;반대로 뷰 페이지가 아닌 특정 값을 반환하려면 전자와 같이 @ResponseBody 어노테이션을 이용합니다. 이 경우에는 보통 ajax 요청에 대한 처리를 위해 사용합니다.&lt;/p&gt;
&lt;h3&gt;Spring MVC 구조 및 ViewResolver 와 HttpMessageConverters&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://images.velog.io/images/lehdqlsl/post/68594fe1-d020-411f-94d2-d08abe5107a8/image.png&quot; alt=&quot;&quot;&gt; &lt;/p&gt;
&lt;center&gt;출처: https://www.javatpoint.com/spring-mvc-tutorial&lt;/center&gt;

&lt;p&gt;Spring MVC 대략적인 흐름입니다. 해당 글에서 자세히 살펴볼 부분은 5번에 해당합니다.&lt;br&gt;앞서 말씀드렸다 싶이, 컨트롤러 요청이 오면 ViewResolver를 통해 템플릿을 해석한 후 view를 반환해 줍니다.&lt;/p&gt;
&lt;p&gt;하지만, @ResponseBody를 사용하게 되면 어떻게 동작할까요?&lt;/p&gt;
&lt;p&gt;Spring에서는 @ResponseBody 어노테이션을 사용하면 ViewResolver가 아닌 HttpMessageConverters에 뷰랜더링을 위임합니다.&lt;/p&gt;
&lt;p&gt;HttpMessageConverters는 다양한 포맷의 데이터를 http 메시지에 알맞게 변환시켜주는 역할을 합니다. Spring에서는 컨버터를 데이터 종류에 따라서 자동으로 선택합니다.&lt;/p&gt;
&lt;p&gt;대표적인 HttpMessageConverters 중 하나는 &lt;code&gt;MappingJackson2HttpMessageConverter&lt;/code&gt; 이고, 자바 및 HashMap 객체를 Json으로 변환하거나 Json 데이터를 자바,HashMap 객체로 변환시켜줍니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;request =&amp;gt; json 데이터를 자바 객체로 변환 (json read)&lt;/li&gt;
&lt;li&gt;response =&amp;gt; 자바 객체 데이터를 json 데이터로 변환 (json write)&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;[번외]&lt;br&gt;@RestController  라는 어노테이션이 있습니다.&lt;br&gt;@Controller + @ResponseBody를 합친 어노테이션이며, 해당 컨트롤러로 들어오는 요청에 대한 응답에 대해 @ResponseBody 가 적용됩니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;HttpMessageConverters 종류&lt;/h4&gt;
&lt;p&gt;HttpMessageConverters을 상속받아서 구현된 컨버터는 아래 문서에서 확인할 수 있습니다.&lt;br&gt;&lt;a href=&quot;https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/http/converter/HttpMessageConverter.html&quot;&gt;https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/http/converter/HttpMessageConverter.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;종류가 굉장히 많은데, 이름만 읽어도 대략 어떤역할을 하는 컨버터인지 알수있습니다. 해당 컨버터로 이동하면 아래와 같이 간략한 설명이 있으니, 참고하시면 되겠습니다.&lt;img src=&quot;https://images.velog.io/images/lehdqlsl/post/a299f501-28c7-4efb-bb06-c1a28124b3ad/image.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h1&gt;결론&lt;/h1&gt;
&lt;p&gt;&lt;code&gt;Hello World!&lt;/code&gt; 문자열을 반환하는 API 1개와 &lt;code&gt;Hello World!&lt;/code&gt;가 적혀있는 웹페이지 1개를 만들어보았습니다.&lt;/p&gt;
&lt;p&gt;API는 @ReponseBody 어노테이션을 이용하여 HttpMessageConverters를 통해 String 형태의 문자열을 반환하였고, 웹페이지는 Thymeleaf라는 템플릿 엔진을 이용하여 ViewResolver를 통해 html이 반환되었습니다.&lt;/p&gt;
&lt;p&gt;다음 글에서는 Content-type을 다루도록 하겠습니다.&lt;/p&gt;</description>
      <category>Java/Spring</category>
      <author>평범한 개발자...</author>
      <guid isPermaLink="true">https://2dongdong.tistory.com/77</guid>
      <comments>https://2dongdong.tistory.com/77#entry77comment</comments>
      <pubDate>Thu, 7 Oct 2021 16:44:09 +0900</pubDate>
    </item>
    <item>
      <title>REST, RESTful, REST API에 대한 오해와 진실</title>
      <link>https://2dongdong.tistory.com/76</link>
      <description>&lt;h1&gt;서론&lt;/h1&gt;
&lt;p&gt;백엔들 개발자라면 누구나 한 번쯤은 본 유명한 발표자료입니다.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://slides.com/eungjun/rest&quot;&gt;그런 REST API로 괜찮은가&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;발표에서의 핵심내용은 아래와 같습니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;오늘날 대부분의 &amp;quot;REST API&amp;quot;는 사실 REST를 따르지 않고 있다.&lt;br&gt;REST의 제약조건을 만족하지 않고 있기 때문이다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;해당 발표로, 우리가 잘못 알고있는 상식들을 바로잡는데 크게 기여했다고 생각합니다.&lt;/p&gt;
&lt;p&gt;그러나 아직까지도 각종 블로그 포스팅글에 REST, RESTful, REST API, RESTful API 등의 용어들이 마치 &lt;code&gt;웹 서비스용 API&lt;/code&gt; 라는 하나의 뜻으로 정의되어 남용 및 혼용되는 경우를 많이 봅니다. &lt;/p&gt;
&lt;p&gt;뭐, 대충 뜻만 통하면 되는거 아닌가...? 라고 생각이 들다가도, &lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://images.velog.io/images/lehdqlsl/post/77561943-ec73-4107-8b49-21edcf08543e/image.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;REST의 창시자인 Roy Fielding이 개인 블로그를 통해, REST API라 불리는 것들이 REST 규약을 위반하고 있으니, 규약을 지키거나 다른 단어를 선택하라고 말합니다.&lt;/p&gt;
&lt;p&gt;고로 창시자의 뜻을 이어받아, 우리가 알고있는 REST에 대한 잘못된 상식 이를 바로 잡기위한 글을 써보려고 합니다.&lt;/p&gt;
&lt;p&gt;레츠고!&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://thumbs.gfycat.com/ObeseThisBarasinga-size_restricted.gif&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h1&gt;대표적인 오해 6가지&lt;/h1&gt;
&lt;h2&gt;1. REST는 웹 서비스 API 정의를 위한 아키텍처이다.&lt;/h2&gt;
&lt;p&gt;REST는 웹 서비스 API를 정의할 때 &lt;code&gt;이해하기 쉽고 사용하기 쉬운 URL을 만드는 규칙&lt;/code&gt;이 아닙니다.&lt;/p&gt;
&lt;p&gt;놀랍게도 REST의 개념이 처음 등장한 Roy Fielding의 &lt;a href=&quot;https://www.ics.uci.edu/~fielding/pubs/dissertation/fielding_dissertation_2up.pdf&quot;&gt;논문&lt;/a&gt;은 2000년에 출간되었고, 이 시대에는 우리가 흔히 알고있는 웹 서비스 API가 존재하지 않았습니다.&lt;/p&gt;
&lt;p&gt;Roy Fielding은 HTTP/1.0 (1991&lt;del&gt;1995), HTTP/1.1 (1995&lt;/del&gt;1999)의 주요 저자 중 한명이고,&lt;br&gt;수십 년의 변화를 견딜 수 있고, 독립적으로 진화하는 시스템을 만들기 위해 REST를 설계했다고 합니다.&lt;/p&gt;
&lt;p&gt;자세한 내용은 &lt;a href=&quot;https://www.infoq.com/articles/roy-fielding-on-versioning/&quot;&gt;인터뷰&lt;/a&gt;를 통해 확인할 수 있습니다.&lt;/p&gt;
&lt;p&gt;REST의 정확한 정의는 &lt;code&gt;분산형 하이퍼미디어 시스템을 위한 아키텍처 스타일&lt;/code&gt;이라고 논문에 나와있습니다. REST 아키텍처가 잘 적용된 대표적인 예시는, 우리 모두가 잘 알고있는 &lt;code&gt;웹사이트&lt;/code&gt; 입니다.&lt;/p&gt;
&lt;h2&gt;2. REST는 HTTP 표준을 기반으로 구현한다.&lt;/h2&gt;
&lt;p&gt;REST는 어떤 구현체가 아니라, 아키텍처 스타일입니다. 그리고 REST는 특정 네트워크 프로토콜에 국한되지 않습니다. &lt;/p&gt;
&lt;p&gt;물론 REST가 HTTP 문제점을 해결하기 위해 만든 아키텍처이고, 실제로 REST의 규약들은 웹 환경에 최적화 되어있습니다. 그러나 웹은 REST 스타일 아키텍처가 잘 적용된 하나의 예시이고, 핵심은 분산 하이퍼 미디어 시스템에 있다고 논문 일부에 설명되어있습니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The modern Web is one instance of a REST-style architecture. Although Web-based&lt;br&gt;applications can include access to other styles of interaction, the central focus of its&lt;br&gt;protocol and performance concerns is distributed hypermedia&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;3. REST는 HTTP 프로토콜을 활용하는 아키텍처이다.&lt;/h2&gt;
&lt;p&gt;2번과 비슷한 내용입니다. REST는 프로토콜과 관련이 없는 아키텍처이지만, 제약조건 때문에 헷갈릴 수 있습니다.&lt;/p&gt;
&lt;p&gt;REST의 제약조건을 살펴보면 아래와 같습니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Client–server architecture&lt;/li&gt;
&lt;li&gt;Statelessness&lt;/li&gt;
&lt;li&gt;Cacheability&lt;/li&gt;
&lt;li&gt;Layered system&lt;/li&gt;
&lt;li&gt;Code on demand (optional)&lt;/li&gt;
&lt;li&gt;Uniform interface&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;제약조건의 자세한 내용은 &lt;a href=&quot;https://en.wikipedia.org/wiki/Representational_state_transfer&quot;&gt;위키피디아&lt;/a&gt;나 &lt;a href=&quot;https://www.ics.uci.edu/~fielding/pubs/dissertation/fielding_dissertation_2up.pdf&quot;&gt;논문&lt;/a&gt; 챕터 5.1부터 확인할 수 있습니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;HTTP에 대해 공부를 하신 분들이라면 &lt;code&gt;이거 HTTP에 대한 내용이 아닌가?&lt;/code&gt; 라는 생각이 드실텐데, 그 이유가 바로 HTTP는 REST 아키텍처 스타일이 반영된 프로토콜이기 때문입니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt; REST는 HTTP/1.0 → HTTP/1.1로 넘어오면서 반영됐습니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;HTTP와 REST의 관계?&lt;/h3&gt;
&lt;p&gt;그렇다고해서 HTTP가 REST라는 이야기가 아닙니다. HTTP는 REST 아키텍처 스타일이 반영되었기 때문에, HTTP를 이용하여 REST 제약조건이 잘 지켜진 RESTful 시스템을 쉽게 만들 수 있다는 것이 핵심입니다.&lt;/p&gt;
&lt;p&gt;다른 네트워크 프로토콜을 이용하여 REST 아키텍처를 따르는 시스템을 만든다면 그 또한 RESTful 시스템입니다.&lt;/p&gt;
&lt;h2&gt;4. REST와 RESTful은 같은 말이다.&lt;/h2&gt;
&lt;p&gt;RESTful은 공식적인 단어도, REST의 창시자가 만든 단어도 아닙니다. (논문에 RESTful이란 단어는 등장하지 않습니다.)&lt;/p&gt;
&lt;p&gt;다만, REST의 제약조건을 모두 따르는 시스템을 RESTful, 혹은 RESTful 시스템이라고 전 세계적으로 무언의 약속을 한 것같습니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;앞에서도 언급한 &lt;code&gt;웹사이트&lt;/code&gt; 는 REST의 제약조건을 모두 따르기 때문에 RESTful 이라 할 수 있습니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;5. REST API는 HTTP 메서드를 사용하여 검색, 생성, 업데이트, 삭제한다.&lt;/h2&gt;
&lt;p&gt;반복하지만 REST는 특정 네트워크 프로토콜에 국한되는 개념이 아닙니다.&lt;/p&gt;
&lt;p&gt;REST API는 &lt;code&gt;REST의 제약조건을 따르는 API 이다.&lt;/code&gt; 정도로 나타낼 수 있고, &lt;code&gt;HTTP 메서드를 사용하여 검색, 생성, 업데이트, 삭제한다.&lt;/code&gt; 라는 내용은 단순히 &lt;a href=&quot;https://datatracker.ietf.org/doc/html/rfc7231&quot;&gt;HTTP RPC&lt;/a&gt;의 일부입니다.&lt;/p&gt;
&lt;h2&gt;6. /customer 또는 /cusrtomer/1과 같은 리소스에 대해 알기쉬운 URL를 정의하는 것이 REST 제약 조건에 해당하며 RESTful API라 부른다.&lt;/h2&gt;
&lt;p&gt;REST와 관련이 없는 내용입니다. 아마 이런 내용이 널리 퍼지게된 이유 중 하나가 &lt;a href=&quot;https://github.com/microsoft/api-guidelines/blob/vNext/Guidelines.md&quot;&gt;마이크로소프트 REST API 가이드 라인&lt;/a&gt; 때문이지 않을까 싶네요.&lt;/p&gt;
&lt;p&gt;7장에 아래와 같은 내용이 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://images.velog.io/images/lehdqlsl/post/c5758d59-75ec-4216-9b7b-904de524e303/image.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;인간은 URL을 쉽게 읽고 구성할 수 있어야 한다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;REST 가이드 라인에 이런 내용이 있으니, 해당 내용이 REST의 제약 조건이라고 착각하게 만들었나봅니다.&lt;/p&gt;
&lt;h1&gt;REST를 이해하기 어려운 이유&lt;/h1&gt;
&lt;h2&gt;1. REST라는 단어가 남용되고 있다.&lt;/h2&gt;
&lt;p&gt;우리가 처음 접하게 되는 REST API, RESTful API라는 용어는 대부분 &lt;code&gt;웹 서비스 API 정의를 위한 아키텍처&lt;/code&gt; 정도로 생각합니다.&lt;/p&gt;
&lt;p&gt;수 많은 블로그에 나와있는 내용들을 보면서, REST는 HTTP 메소드와 알기 쉬운 URL을 통해 쉽고 편하게 사용할 수 있는 사용자 API를 만들기 위한 아키텍처 혹은 제약사항 정도로 이해하게 됩니다.&lt;/p&gt;
&lt;h2&gt;2. REST라는 단어를 직역하여 이해하려고 한다.&lt;/h2&gt;
&lt;p&gt;REST는 Representational state transfer의 줄임말이며, 번역기나 사전을 통해 직역하면 &lt;code&gt;대표 상태 이전&lt;/code&gt; 혹은 &lt;code&gt;표현 상태 이전&lt;/code&gt; 인데, REST의 제약사항을 보았을때 &lt;code&gt;표현 상태 전송&lt;/code&gt;이 더 어울리는것 같습니다.&lt;/p&gt;
&lt;p&gt;REST를 &lt;code&gt;웹 서비스 API 정의를 위한 아키텍처&lt;/code&gt;로 알고있는 상태에서 REST의 풀네임의 직역 및 정의를 읽게되다면 서로 매칭이 안되니까, 무슨 말인지 이해못하는게 당연하지 않나 생각됩니다.&lt;/p&gt;
&lt;h1&gt;REST는 왜 만들어졌는가?&lt;/h1&gt;
&lt;p&gt;REST를 왜 만들었는지 그 의도와 해결하기 위한 고민을 알게되면 이해하기 쉽습니다.&lt;/p&gt;
&lt;p&gt;Roy Fielding은 수십 년의 변화를 견딜 수 있는 시스템을 만들고 싶어 하였고, 그 시스템을 만들기 위해 끊임없는 질문과 고민을 하였습니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;웹을 손상시키지 않고 HTTP를 어떻게 발전시킬 수 있을까?&lt;/li&gt;
&lt;li&gt;시대가 바뀌면서 확장성 및 일관성 문제는 어떻게 해결할 수 있을까?&lt;/li&gt;
&lt;li&gt;Web과 같은 분산 하이퍼미디어 시스템이 생겨난다면 서로 어떻게 연결해야 할까?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;이런 고민끝에 만들어진게 REST이고, REST가 반영된 프로토콜이 HTTP이며, 이 HTTP를 이용하여 웹이 서로 통신합니다. 그래서 우리는 여전히 최신 웹브라우저를 통해 80~90년대에 만들어진 웹사이트에 접속할 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://thoughtcatalog.com/jeremy-london/2018/09/oldest-websites-on-the-internet/&quot;&gt;인터넷에서 가장 오래된 웹사이트 15개&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;REST를 꼭 알아야할까?&lt;/h1&gt;
&lt;p&gt;Roy Fielding의 PPT &lt;a href=&quot;https://www.slideshare.net/AEMHub2014/rest-in-aem-by-roy-fielding&quot;&gt;발표&lt;/a&gt; 자료 마지막에 나와있습니다.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://images.velog.io/images/lehdqlsl/post/7fc13e04-b5d6-4bab-9e17-eed8bedb3c9b/image.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;시스템 전체를 제어할 수 있다고 생각하거나, 진화에 관심이 없다면, REST에 대해 논쟁하는 데 시간을 낭비하지 마세요.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;라고 합니다.&lt;/p&gt;
&lt;h1&gt;진정한 REST API에 대해 알고싶다.&lt;/h1&gt;
&lt;p&gt;Roy Fielding 개인 블로그 글 (&lt;a href=&quot;https://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven&quot;&gt;REST API는 하이퍼텍스트 기반이어야 합니다.&lt;/a&gt;)&lt;br&gt;을 통해 사람들이 자주 위반하는 룰 6가지 정도를 설명합니다.&lt;/p&gt;
&lt;p&gt;그리고 REST, REST API, RESTful API에 관한 사람들의 질문에 대한 답글 또한 최대한 길게 풀어서 설명합니다.&lt;/p&gt;
&lt;p&gt;제가 설명하는것 보단, 해당 글을 번역해서 쭉 읽는게 훨씬 더 도움이 될 것 같습니다.&lt;/p&gt;
&lt;h1&gt;결론&lt;/h1&gt;
&lt;p&gt;공부하면서 REST가 무엇인지 정확하게 알게되었습니다. &lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://images.velog.io/images/lehdqlsl/post/7ee28080-d447-40b8-a21a-bf3d6242c038/image.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;API를 개발하는 백엔드 개발자로써, REST는 저랑 상관 없는 단어라는 것을 알게되었습니다.&lt;/p&gt;
&lt;p&gt;그리고 수 십년을 내다본 Roy Fielding이란 인물을 매우 존경하게 되었습니다.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;[참고]&lt;br&gt;&lt;a href=&quot;https://www.infoq.com/articles/roy-fielding-on-versioning/&quot;&gt;https://www.infoq.com/articles/roy-fielding-on-versioning/&lt;/a&gt;&lt;br&gt;&lt;a href=&quot;https://deview.kr/2017/schedule/212&quot;&gt;https://deview.kr/2017/schedule/212&lt;/a&gt;&lt;br&gt;&lt;a href=&quot;http://slides.com/eungjun/rest#/69&quot;&gt;http://slides.com/eungjun/rest#/69&lt;/a&gt;&lt;br&gt;&lt;a href=&quot;https://twobithistory.org/2020/06/28/rest.html#fnref:6&quot;&gt;https://twobithistory.org/2020/06/28/rest.html#fnref:6&lt;/a&gt;&lt;br&gt;&lt;a href=&quot;https://www.ics.uci.edu/~fielding/pubs/dissertation/fielding_dissertation_2up.pdf&quot;&gt;https://www.ics.uci.edu/~fielding/pubs/dissertation/fielding_dissertation_2up.pdf&lt;/a&gt;&lt;br&gt;&lt;a href=&quot;https://stackoverflow.com/questions/2190836/what-is-the-difference-between-http-and-rest&quot;&gt;https://stackoverflow.com/questions/2190836/what-is-the-difference-between-http-and-rest&lt;/a&gt;&lt;br&gt;&lt;a href=&quot;https://news.ycombinator.com/item?id=7201871&quot;&gt;https://news.ycombinator.com/item?id=7201871&lt;/a&gt;&lt;br&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Representational_state_transfer&quot;&gt;https://en.wikipedia.org/wiki/Representational_state_transfer&lt;/a&gt;&lt;br&gt;&lt;a href=&quot;https://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven&quot;&gt;https://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven&lt;/a&gt;&lt;br&gt;&lt;a href=&quot;https://shoark7.github.io/programming/knowledge/what-is-rest&quot;&gt;https://shoark7.github.io/programming/knowledge/what-is-rest&lt;/a&gt;&lt;/p&gt;</description>
      <category>Server</category>
      <author>평범한 개발자...</author>
      <guid isPermaLink="true">https://2dongdong.tistory.com/76</guid>
      <comments>https://2dongdong.tistory.com/76#entry76comment</comments>
      <pubDate>Tue, 5 Oct 2021 10:38:28 +0900</pubDate>
    </item>
    <item>
      <title>GitLab CI/CD + SSH 공개키를 이용한 자동배포</title>
      <link>https://2dongdong.tistory.com/75</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;Start&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Gitlab + AWS 연동에 관한 글을 참 많지만.. 저처럼 IDC 서버를 사용하는 사람들에겐 해당하지 않는 내용이라..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자료도 많지 않고, 설명이 부실한 글들이 많아서 직접 정리해봅니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;무작정 따라하는것 보다, 공개키를 이용한 SSH 접속의 전체적인 흐름을 이해하고 읽는 것이 훨씬 더 도움됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://velog.io/@lehdqlsl/SSH-%EA%B3%B5%EA%B0%9C%ED%82%A4-%EC%95%94%ED%98%B8%ED%99%94-%EB%B0%A9%EC%8B%9D-%EC%A0%91%EC%86%8D-%EC%9B%90%EB%A6%AC-i7rrv4de&quot;&gt;SSH 공개키 인증을 사용하여 접속하기&lt;/a&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Process&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;클라이언트 키쌍 생성 (공개키-비밀키)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;패스워드 입력 없이 SSH 접속하기 위함.&lt;/li&gt;
&lt;li&gt;패스워드 대신 공개키 및 비밀키 사용.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Gitlab Variables 등록
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;배포할 서버의 IP 혹은 도메인 주소 (노출돼도 상관없으면 스크립트에 직접 넣어도 됩니다.)&lt;/li&gt;
&lt;li&gt;SSH 비밀키 (생성한 키의 비밀키)&lt;/li&gt;
&lt;li&gt;(옵션) 배포 서버의 SSH 공개키 (주의: 생성한 키의 공개키가 아님)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;known_hosts로 등록하기 위함&lt;/li&gt;
&lt;li&gt;서버의 SSH 공개키는 &lt;code&gt;/etc/ssh&lt;/code&gt; 경로에 있으며, ssh 설치 시 생성됨&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;배포 서버에 공개키 등록 (생성한 키의 공개키)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;~.ssh/authorized_keys 파일에 등록.&lt;/li&gt;
&lt;li&gt;SSH 클라이언트 접속 시, 등록되어있는 공개키의 해당하는 비밀키를 가지고 있다면 접속을 허용해줍니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Gitlab 스크립트 작성&lt;/li&gt;
&lt;li&gt;자동 배포 확인&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 클라이언트 키쌍 생성&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ssh-keygen 명령어를 이용하여 키쌍을 생성합니다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Windows 10이나 대부분 리눅스는 기본적으로 설치가 되어있는데, 없으면 설치하면 됩니다.&lt;/li&gt;
&lt;li&gt;cmd 창에 &lt;code&gt;ssh-keygen&lt;/code&gt; 명령어를 입력하고, 엔터를 쭉쭉 눌러주면 C:Users\계정\.ssh\ 경로에 키쌍이 생성됩니다.&lt;/li&gt;
&lt;li&gt;ssh-keygen 명령어의 기본 값은 아래와 같습니다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;RSA 3072 비트 (SHA256)&lt;/li&gt;
&lt;li&gt;키 생성 경로: ~.ssh\
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;윈도우, 리눅스 동일&lt;/li&gt;
&lt;li&gt;비밀키 (id_rsa)&lt;/li&gt;
&lt;li&gt;공개키 (id_rsa.pub)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;키에 패스워드를 지정하지 않음.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;https://images.velog.io/images/lehdqlsl/post/2b084e1d-e78b-49a8-966d-09888ee35ad5/image-20210913171744638.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. Gitlab Variables 등록&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Settings -&amp;gt; CI/CI -&amp;gt; Variables -&amp;gt; Add variable&lt;/li&gt;
&lt;li&gt;저는 이미 변수를 등록해놓은 상태입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;https://images.velog.io/images/lehdqlsl/post/a2a3923a-79ce-401e-8a37-87d029fef82f/image-20210913172658544.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;비밀키 등록
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Key
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;스크립트에서 사용할 변수명&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Value
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;아까 생성한 비밀키(id_rsa)를 붙여넣습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Type
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;File로 변경&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;https://images.velog.io/images/lehdqlsl/post/811be768-1d06-43fd-be59-76b9aa86781e/image-20210913172819444.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; start=&quot;2&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;서버 IP or 도메인 등록&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;https://images.velog.io/images/lehdqlsl/post/d18f3e92-e9a5-4649-8584-c78750332f84/image-20210913173439368.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; start=&quot;3&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;(Option) 배포 서버의 SSH 공개키 등록&lt;/li&gt;
&lt;/ol&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;서버에 접속하여, /etc/ssh/ssh_host_*.pub 파일들을 확인합니다.&lt;/li&gt;
&lt;li&gt;보통 ssh-server를 설치하면 3개의 키쌍이 생성되는데, 이 중 아무 공개키를 사용해도 무관합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;https://images.velog.io/images/lehdqlsl/post/b30aa5dc-4eb8-477c-bfa0-bade89a206c2/image.png&quot; alt=&quot;&quot; /&gt;&lt;img src=&quot;https://images.velog.io/images/lehdqlsl/post/3d4eb8e9-aa47-443f-b2b1-8b0e77c09e76/image.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;아래와 같이 변수로 등록해줍니다. (서버 IP주소 입력 후 한칸 띄어야 합니다.)&lt;/li&gt;
&lt;li&gt;만약 포트가 22번이 아니라면 &lt;code&gt;[IP주소]:포트&lt;/code&gt; 형태로 입력합니다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ex) [111.111.111.111]:2243 ssh-ed25519 AAAA.........JJJ&lt;br /&gt;&lt;img src=&quot;https://images.velog.io/images/lehdqlsl/post/65938299-b54e-4d1c-9948-f88ce503ca6c/image.png&quot; alt=&quot;&quot; /&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;이 과정은 하지 않아도 되지만, 하는 이유와 하지않으면 어떤 문제가 있는지 설명합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;키를 등록하는 이유&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;서버에 처음 SSH 접속 시 아래와 같은 메시지를 많이 보셨을겁니다.&lt;br /&gt;&lt;img src=&quot;https://images.velog.io/images/lehdqlsl/post/2fb8fa28-58df-45b6-9367-ee621566b56a/image.png&quot; alt=&quot;&quot; /&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;https://images.velog.io/images/lehdqlsl/post/1b51adb1-c5b1-4d5d-9430-6cc376cd8bd5/image.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;로컬에 서버의 키가 등록 되어있지 않은데, 이 서버를 신뢰할 수 있다면 로컬에 서버키를 추가 후 SSH 접속을 하고, 그렇지 않다면 접속하지 않습니다.&lt;/li&gt;
&lt;li&gt;키를 추가하게 되면 다음부터 이 서버에 접속할 때 마다, 서버에 대한 인증을 위해 로컬에 저장되어있는 키를 이용하여 인증하는 과정을 거칩니다.&lt;/li&gt;
&lt;li&gt;이런 과정을 통해 중간자 공격을 예방하여 안전하게 SSH 접속이 가능합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Gitlab 변수로 등록하는 이유&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;SSH 클라이언트를 사용하는 우리 입장에서는, 엔터를 치거나 마우스 클릭으로 등록을 하면 됩니다.&lt;/li&gt;
&lt;li&gt;그러나, 빌드 할 때마다 매번 새로운 도커 이미지가 생성되고 콘솔에서 조작이 불가능한 Gitlab에서는 스크립트를 통해 서버키를 미리 등록함으로써 해당 과정을 생략할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;이 과정을 하지 않으면?&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;공개키 등록 대신에, ssh 설정으로 이 서버키 등록 과정을 생략하고 SSH 접속을 할 수 있습니다.&lt;/li&gt;
&lt;li&gt;바로 Host Key Checking을 비활성화 하는 것인데요,&lt;/li&gt;
&lt;li&gt;이 옵션을 추가하게 되면, 처음 접속할 때 공개키 등록 없이 바로 SSH 접속이 가능하게 되지만, 중간자 공격에 취약할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. 배포 서버에 공개키 등록&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;키쌍으로 생성한 공개키를 서버의 ~/.ssh/authorized_keys 파일에 등록합니다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;많이 실수하는 부분인데, SSH로 접속할 계정의 홈디렉토리/.ssh 폴더입니다.&lt;/li&gt;
&lt;li&gt;일반 유저계정으로 SSH 접속할건데, /root/.ssh/authorized_keys 파일을 수정하면 안됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;공개키 등록 방법
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;직접 등록
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;vi와 같은 편집기를 통해 공개키 복사 및 붙여넣기 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;ssh-copy-id 명령어 이용
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;윈도우
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;윈도우는 ssh-copy-id 명령어가 없기 때문에, 다른 명령어로 대체합니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;type $env:공개키위치 | ssh 계정@IP &quot;cat &amp;gt;&amp;gt; .ssh/authorized_keys&quot;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;만약 Windows에서 키쌍을 생성했다면 공개키의 경로는 &lt;code&gt;C:\Users\계정\.ssh\id_rsa.pub&lt;/code&gt; 입니다.&lt;/li&gt;
&lt;li&gt;위 명령어를 수행하면 공개키값을 변수에 담아서 SSH 접속 후, .ssh/authorized_keys에 붙여 넣게됩니다.&lt;/li&gt;
&lt;li&gt;서버에 접속 후 authorized_keys을 확인해보면 공개키값이 잘 들어가있는 것을 확인 할수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;리눅스계열
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;리눅스는 간단합니다. &lt;code&gt;ssh-copy-id 계정@IP&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;해당 명령어를 입력하면 ~/.ssh 폴더에 있는 공개키를 해당 서버에 등록합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4. 스크립트 작성&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프로젝트 최상위 폴더에 .gitlab-ci.yml 파일을 생성합니다.&lt;/li&gt;
&lt;li&gt;아래 스크립트 내용 붙여넣습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;stages:
    - build
    - deploy

image: java:8-jdk # jdk8 도커 이미지 사용 (배포환경에 따라 변경할 것)

cache:
    paths: # .gradle 캐시 적용
        - .gradle/wrapper
        - .gradle/caches

build:
    stage: build
    before_script:
        - chmod +x ./gradlew # gradlew 실행권한 부여 (초기 권한 666 [-rw-rw-rw-])
    script:
        - ./gradlew build
    artifacts: 
        paths:
            - build/libs/*.jar    # build의 결과물인 jar파일을 artifacts로 지정. 
        expire_in: 1 week    # 1주일 동안 보관

deploy-to-server:
    stage: deploy
    before_script:
        - mkdir -p ~/.ssh
        - eval $(ssh-agent -s) # ssh-agent 백그라운드 실행

        ###############################################
        # 공개키 등록을 안했다면 Host Key Checking 비활성화 옵션 추가 (중간자 공격 위험)       
        # - '[[ -f /.dockerenv ]] &amp;amp;&amp;amp; echo -e &quot;Host *\n\tStrictHostKeyChecking no\n\n&quot; &amp;gt;&amp;gt; ~/.ssh/config'    

        # 공개키 등록을 했다면 known_hosts 등록 및 권한 변경
        # - echo &quot;$SSH_KNOWN_HOSTS&quot; &amp;gt;&amp;gt; ~/.ssh/known_hosts
        # - chmod 644 ~/.ssh/known_hosts
        ###############################################

        - chmod 600 &quot;$SSH_KEY&quot; # 개인키 파일 권한변경 
        - ssh-add &quot;$SSH_KEY&quot;   # SSH 개인키 추가
    script:
        # SSH를 이용한 원격 파일 업로드
        - scp build/libs/*.jar 계정명@&quot;$DEPLOY_SERVER_IP&quot;:~/BUILD_PATH/build.jar
        # 원격 스크립트 실행
        - ssh 계정명@&quot;$DEPLOY_SERVER_IP&quot; /BUILD_PATH/start.sh&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;아래는 서버에서 실행 할 원격 스크립트 파일 내용입니다.&lt;/li&gt;
&lt;li&gt;단순히 기존 프로세스가 있으면 kill 후 재실행, 없으면 그냥 실행합니다.
&lt;pre class=&quot;bash&quot;&gt;&lt;code&gt;#!/bin/sh
cd ~/BUILD_PATH
PID=$(ps -ef|grep build.jar|grep -v grep|awk '{print $2}')
if [ &quot;$PID&quot; == &quot;&quot; ]; then
  echo &quot;no process exist&quot;
else
  echo &quot;process id (${PID}) killed&quot;
  kill -9 ${PID}
fi
echo &quot;Program Start&quot;
nohup java -jar build.jar 1 &amp;gt; /dev/null 2&amp;gt;&amp;amp;1 &amp;amp;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5. 자동 배포 확인&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Gitlab으로 Push 하여 CI/CD를 동작시킵니다.&lt;br /&gt;&lt;img src=&quot;https://images.velog.io/images/lehdqlsl/post/b0718633-7e5a-4ca0-a4c4-db6e75fc00d3/image.png&quot; alt=&quot;&quot; /&gt;&lt;/li&gt;
&lt;li&gt;별다른 문제 없이 성공하였다면, 서버에 접속하여 프로세스가 동작하는지 확인합니다.&lt;br /&gt;&lt;img src=&quot;https://images.velog.io/images/lehdqlsl/post/866bae04-ff79-4bbb-ac29-fd9fc1654628/image.png&quot; alt=&quot;&quot; /&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Server</category>
      <author>평범한 개발자...</author>
      <guid isPermaLink="true">https://2dongdong.tistory.com/75</guid>
      <comments>https://2dongdong.tistory.com/75#entry75comment</comments>
      <pubDate>Tue, 14 Sep 2021 15:20:47 +0900</pubDate>
    </item>
    <item>
      <title>MariaDB에는 'innodb buffer pool instances' 변수 설정이 없다...?</title>
      <link>https://2dongdong.tistory.com/74</link>
      <description>&lt;p&gt;최근 innodb buffer pool 설정 관련해서 찾아보다가 알게된 사실입니다.&lt;/p&gt;
&lt;p&gt;MriaDB 10.5 변경사항에 innoDB 성능 항샹 내용 중 &lt;code&gt;Multiple buffer pool Remove&lt;/code&gt;가 있습니다.&lt;br&gt;상식적으로 생각해봤을때 멀티로 동작하는게 무조건 성능이 좋다고 생각이 드는데, 지운 이유가 무엇일까요? 궁금해서 조금 찾아봤습니다.&lt;br&gt;&lt;img src=&quot;https://images.velog.io/images/lehdqlsl/post/09ad5be3-b798-45f7-88d3-2cd4fd809855/image.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;innodb_buffer_pool_instances 변수 설명을 확인해보니, 10.5.1부터 해당 변수의 값이 비활성화되고 10.6.0부터 제거되었습니다.&lt;br&gt;제거된 이유는 단 한줄로 표시하였네요.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;버퍼 풀을 분할하는 본래의 이유가 사라졌다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src=&quot;https://images.velog.io/images/lehdqlsl/post/8cf54fa5-b15e-4732-9e79-5036e39be230/image.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;왜인지 이유는 자세하게 설명을 안해주네요.. 궁금하게 참...&lt;br&gt;먼저 multiple buffer pool을 사용하는 이유 부터 알아보면&lt;/p&gt;
&lt;h3&gt;multiple buffer pool을 사용 이유&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;MySQL 공식 홈페이지에 잘 설명되어있습니다. (&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/innodb-parameters.html#sysvar_innodb_buffer_pool_instances&quot;&gt;원문&lt;/a&gt;)&lt;br&gt;&lt;img src=&quot;https://images.velog.io/images/lehdqlsl/post/a8ab24f2-392d-4034-8519-ecbebf249b86/image.png&quot; alt=&quot;&quot;&gt;&lt;/li&gt;
&lt;li&gt;*&lt;em&gt;다른 스레드가 캐시된 페이지를 읽고 쓸 때 경합을 줄임으로써 동시성을 향상시킬 수 있다. *&lt;/em&gt;가 핵심.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;이유만 들어보면 엄청난 성능 향상이 있을것 같은데... 왜 없앴을까요??&lt;/p&gt;
&lt;h3&gt;지라 이슈 제기&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;지라 이슈 제기: &lt;a href=&quot;https://jira.mariadb.org/browse/MDEV-15058&quot;&gt;Remove multiple InnoDB buffer pool instances&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;요약&lt;ul&gt;
&lt;li&gt;MySQL 5.5.5 버전부터 multiple buffer pools 도입 이후 &lt;a href=&quot;https://github.com/mysql/mysql-server/commit/ce6109ebfdedfdf185e391a0c97dc6d33867ed78&quot;&gt;뮤텍스 대신 rw-locks를 사용하도록 MySQL 5.6.2에 수정&lt;/a&gt; 과 같은 버퍼 풀간 뮤텍스 경합을 줄이기 위해 다수의 수정이 있었음&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://jira.mariadb.org/browse/MDEV-15016&quot;&gt;multiple page cleaner threads use a lot of CPU on idle server&lt;/a&gt; 문제 검토 중 multiple buffer pools이 정말 성능향상에 도움이 되는지 궁금 &lt;/li&gt;
&lt;li&gt;그리고 뮤텍스 관련 &lt;a href=&quot;https://jira.mariadb.org/browse/MDEV-15053%5D&quot;&gt;MySQL 8.0.0 기능 추가&lt;/a&gt;되면서 MariaDB도  비슷한 작업을 수행해야한다고 이슈 제기.&lt;ul&gt;
&lt;li&gt;그러나 multiple buffer pools 과 page cleaners를 지원하기 위해 모든 코드를 지우는 것을 고려해야 한다 생각하고,&lt;/li&gt;
&lt;li&gt;향후 multiple buffer pools이 필요할 경우, 처음부터 잘 설계해야된다고 함.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;결론은 single instance buffer pools과 multiple buffer pools의 성능을 비교해서, 단일 인스턴스 버퍼 풀이어도 성능 저하가 없다면 코드를 단순화 해야된다고 주장&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;다시 한번 정리 (뇌피셜로 분석한 제 생각입니다...)&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;multiple buffer pools 도입 이후 버퍼 풀간 뮤텍스 경합을 줄이기 위해 다수의 수정으로 코드가 복잡해져있는 상태에서&lt;/li&gt;
&lt;li&gt;MySQL의 Mutex 분할 기능을 도입하기엔  설계 문제로 불가능하고 판단,&lt;/li&gt;
&lt;li&gt;multiple buffer pools로 인해 생기는 성능 이슈도 있으니&lt;/li&gt;
&lt;li&gt;single buffer pools과 multi buffer pools의 성능의 큰 차이가 없다면 기존 코드를 제거하여 single buffer pools로 가자!&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;2년간 이어진 기나긴 테스트...&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;지라 댓글 히스토리를 쭉 보니까, 거의 2년에 걸쳐서 테스트는 진행되었고 그 과정이 쉽지 않았다는게 느껴집니다.&lt;/li&gt;
&lt;li&gt;single buffer pools 에서 생기는 병목현상을 다른 방향으로 해결하기 위해 여러 수정이 있었고,&lt;/li&gt;
&lt;li&gt;결국 single buffer pools으로도 multiple 만큼 성능을 발휘하도록 만들었다고 하네요.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;https://images.velog.io/images/lehdqlsl/post/575715ec-503b-4f2c-b493-413e98d24a01/image-20210831141408538.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h3&gt;MySQL의 innodb buffer pool instances는?&lt;/h3&gt;
&lt;p&gt;percona의 CTO가 innodb buffer pool instances 관련 테스트 글을 작성하였습니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://www.percona.com/blog/2020/08/13/how-many-innodb_buffer_pool_instances-do-you-need-in-mysql-8&quot;&gt;How Many innodb_buffer_pool_instances Do You Need in MySQL 8?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.percona.com/blog/2020/08/14/part-two-how-many-innodb_buffer_pool_instances-do-you-need-in-mysql-8-with-a-cpu-bound-workload/&quot;&gt;Part Two: How Many innodb_buffer_pool_instances Do You Need in MySQL 8 With a CPU-Bound Workload?&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;innodb_buffer_pool_instances 라는 매개변수가 어떤 값으로 설정해야 좋은지 나쁜지 애매모호하여 다양한 시나리오에서 테스트를 진행했다고 합니다.&lt;ul&gt;
&lt;li&gt;서버 사양은 cpu core 80개, 메모리 188GB&lt;/li&gt;
&lt;li&gt;innodb_buffer_pool_instances를 1, 2, 4, 8, 16, 32, 64 로 설정하여 테스트 진행&lt;/li&gt;
&lt;li&gt;첫 테스트는 innodb_buffer_pool_size를 25GB로, 두번째 테스트는 140GB로 설정&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;해당글의 결론은 아래와 같습니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;높은 처리량과 적은 변동성을 고려하였을 때 64가 최선의 선택이지만, 그렇다고 무작정 이 값을 추천할 수 없다. (하드웨어 및 부하량에 따라 다름)&lt;/li&gt;
&lt;li&gt;1-4는 처리량에 대한 변동성이 크기 때문에 8부터 테스트를 진행하여 최적의 값을 찾는걸 추천.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;나의 생각&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;설정 값에 대한 정답은 없다. 하드웨어 사양 및 환경에 따라 다 다르고, 다양한 설정값으로 밴치마크를 하여 직접 비교해보는 것이 정답인듯 합니다.&lt;/li&gt;
&lt;li&gt;시간이 된다면 MariaDB 10.6 vs MySQL8의 innodb_buffer_pool_instances 관련 성능 비교글을 작성해보고 싶네요.&lt;/li&gt;
&lt;/ol&gt;</description>
      <category>Server/Database</category>
      <author>평범한 개발자...</author>
      <guid isPermaLink="true">https://2dongdong.tistory.com/74</guid>
      <comments>https://2dongdong.tistory.com/74#entry74comment</comments>
      <pubDate>Mon, 13 Sep 2021 09:15:53 +0900</pubDate>
    </item>
    <item>
      <title>SSH 공개키 인증을 사용하여 접속하기</title>
      <link>https://2dongdong.tistory.com/73</link>
      <description>&lt;h1&gt;1. 공개키 암호화란?&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;공개 키 암호 방식은 암호 방식의 한 종류로 사전에 비밀 키를 나눠가지지 않은 사용자들이 안전하게 통신할 수 있도록 한다.&lt;br&gt;공개 키 암호 방식에서는 공개 키와 비밀 키가 존재하며, 공개 키는 누구나 알 수 있지만 그에 대응하는 비밀 키는 키의 소유자만이 알 수 있어야 한다.&lt;br&gt;공개 키는 보안 타협 없이 공개적으로 배포가 가능하다.&lt;br&gt;공개 키 암호를 구성하는 알고리즘은 대칭 키 암호 방식과 비교하여 비대칭 암호라고 부르기도 한다.&lt;br&gt;&lt;a href=&quot;https://ko.wikipedia.org/wiki/%EA%B3%B5%EA%B0%9C_%ED%82%A4_%EC%95%94%ED%98%B8_%EB%B0%A9%EC%8B%9D&quot;&gt;위키백과&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;공개키-개인키(비밀키)가 한 쌍으로 이루어져 있는 키 쌍이라 합니다.&lt;br&gt;공개키는 누구나 가질 수 있고, 개인키는 개인이나 중요한 사람만이 가지고 있습니다.&lt;/p&gt;
&lt;p&gt;이런 특성을 이용하여 공개키 방식으로 암호화 및 인증에 사용됩니다.&lt;/p&gt;
&lt;p&gt;메시지를 공개키로 암호화하면 개인키를 가지고 있는 사람만이 메시지를 복호화하여 메시지를 확인 할 수 있습니다. 개인키를 탈취당하지 않는 이상, 암호화된 메시지가 유출되어도 다른 사람이 절대 읽을 수 없습니다.&lt;/p&gt;
&lt;h1&gt;2. SSH 공개키 접속&lt;/h1&gt;
&lt;p&gt;SSH는 기본적으로 사전에 설정된 패스워드를 입력하여 접속하지만, 공개키 암호화에 사용되는 &lt;strong&gt;키 쌍&lt;/strong&gt;을 가지고 접속할 수 있는 기능을 제공합니다.&lt;/p&gt;
&lt;p&gt;사전에 자신의 공개키를 서버에 나눠주고, SSH 접속 시 개인키를 이용하여 사용자를 증명하는 원리로 로그인하게 됩니다.&lt;/p&gt;
&lt;p&gt;아래는 ssh 접속 과정을 나타낸 시퀀스 다이어그램 입니다.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://images.velog.io/images/lehdqlsl/post/e3c60ea2-9716-452b-8b7f-1bbbed626347/%EA%B7%B8%EB%A6%BC1.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h1&gt;3. SSH 공개키 접속 방법&lt;/h1&gt;
&lt;p&gt;3.1 및 3.2는 공개키를 이용한 SSH 접속 방법을 설명하기 앞서 기본적으로 알아야할 사전지식입니다.&lt;/p&gt;
&lt;h2&gt;3.1 SSH 클라이언트 (사용자)&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;클라이언트 키 쌍&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;ssh-keygen&lt;/strong&gt; 명령어를 이용하여 공개키 및 개인키 생성&lt;/li&gt;
&lt;li&gt;키 쌍을 생성하게 되면 기본적으로 아래 경로에 생성됨&lt;ul&gt;
&lt;li&gt;~/.ssh/&lt;strong&gt;id_rsa&lt;/strong&gt; (개인키)&lt;/li&gt;
&lt;li&gt;~/.ssh/&lt;strong&gt;id_ras.pub&lt;/strong&gt; (공개키)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;서버의 authorized_keys 파일에 생성된 사용자 공개키를 제공해야 함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;~/.ssh/&lt;strong&gt;known_hosts&lt;/strong&gt; 파일&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;사용자가 처음 서버에 로그인 할 때, 연결을 진행하면 서버의 공개키가 해당 파일에 기록됨&lt;h2&gt;3.2 SSH 서버 (호스트)&lt;/h2&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;서버 키 쌍&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;서버에서 openssh-server를 설치하는 과정에 자동 생성&lt;br&gt;&lt;img src=&quot;https://images.velog.io/images/lehdqlsl/post/a24c9fd1-46a1-440e-adeb-0a817432e951/image.png&quot; alt=&quot;&quot;&gt; &lt;ul&gt;
&lt;li&gt;/etc/ssh/&lt;strong&gt;ssh_host_ras_key&lt;/strong&gt; (개인키)&lt;/li&gt;
&lt;li&gt;/etc/ssh/&lt;strong&gt;ssh_host_ras_key.pub&lt;/strong&gt; (공개키)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;클라이언트가 서버에 처음 연결 시도 시 해당 공개키를 클라이언트에게 제공. 클라이언트는 &lt;strong&gt;known_hosts&lt;/strong&gt; 파일에 서버의 공개키를 저장&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;~/.ssh/&lt;strong&gt;authorized_keys&lt;/strong&gt; 파일&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;해당 파일에 로그인할 클라이언트의 공개키가 기록되어있어야 함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;3.3 SSH 공개키 접속&lt;/h2&gt;
&lt;h3&gt;3.3.1 클라이언트 키 쌍 생성&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;아래 명령어를 이용하여 RSA 알고리즘 키 쌍 생성&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;$ ssh-keygen -t rsa&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;별 다른 설정이 필요하지 않으므로, 엔터를 계속 누르면 현재 로그인되어있는 사용자의 홈디렉토리 .ssh 폴더 밑에 키 쌍이 생성 됨&lt;br&gt;&lt;img src=&quot;https://images.velog.io/images/lehdqlsl/post/a1081ead-cac1-451b-8611-4bda700d39b2/image.png&quot; alt=&quot;&quot;&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;3.3.2 공개키 전송&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;리눅스계열에서는 공개키를 복사하는 명령어 &lt;strong&gt;ssh-copy-id&lt;/strong&gt; 를 사용&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;$ ssh-copy-id USER@remote-host&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;예) $ ssh-copy-id &lt;a href=&quot;mailto:lee@192.168.0.15&quot;&gt;lee@192.168.0.15&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;-i 옵션을 사용하지 않으면, 현재 로그인 되어있는 계정의 .ssh/id_rsa.pub 파일을 전송 (기본값)&lt;/li&gt;
&lt;li&gt;공개키 파일이 다른 경로에 있다면 -i 옵션을 이용하여 별도의 경로를 지정해야 함&lt;ul&gt;
&lt;li&gt;$ ssh-copy-id -i /home/test/key/key.pub &lt;a href=&quot;mailto:lee@192.168.0.15&quot;&gt;lee@192.168.0.15&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;윈도우에서는 &lt;strong&gt;ssh&lt;/strong&gt;와 &lt;strong&gt;cat&lt;/strong&gt;을 이용한 명령어 조합을 이용 &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;type $env:공개키경로 | ssh USER@remote-host &amp;quot;cat &amp;gt;&amp;gt; .ssh/authorized_keys&amp;quot;&lt;/li&gt;
&lt;li&gt;예) type $env:C:\Users\LDB.ssh\id_rsa.pub | ssh &lt;a href=&quot;mailto:lee@192.168.0.15&quot;&gt;lee@192.168.0.15&lt;/a&gt;  &amp;quot;cat &amp;gt;&amp;gt; .ssh/authorized_keys&amp;quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;3.3.3 로그인&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;공개키 방식으로 SSH 접속 시 -i 옵션 생략 시, 아래 경로에 있는 개인키로 접속을 시도&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;윈도우: USER_NAME\.ssh\id_rsa&lt;/li&gt;
&lt;li&gt;리눅스: USER_NAME/.ssh/id_rsa&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;만약 개인키의 위치가 다르거나 AWS의 pem 파일인 경우 -i 옵션 이용&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;$ssh -i KEY_PATH\key.pem USER@remote-host&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;$ssh -i KEY_PATH\id_rsa USER@remote-host&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;3.3.4 키 파일 권한 문제 (Permissions are too open)&lt;/h3&gt;
&lt;p&gt;개인키를 windows &amp;lt;-&amp;gt; linux간 FTP로 복사하다가 발생하는 권한 문제입니다.&lt;br&gt;ssh에 사용되는 각 종 파일들 (설정파일,공개키,개인키 등)은 보안적인 이슈로 인해 아래 사진과 같이 권한이 정해져있습니다.&lt;br&gt;&lt;img src=&quot;https://images.velog.io/images/lehdqlsl/post/dd201cdb-817e-48ee-aa7a-bafe974b8dd4/image.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;위 사진을 보면 Mandatory Permission 이라고 정해진 권한이 있는데, 개인키 파일과 설정파일은 꼭 600으로 설정이 되어있어야 한다는 뜻입니다. (600은 소유자만 읽고 쓸 수 있는 권한)&lt;br&gt;만약 600이 아니라면 chmod 명령어를 통해 권한을 수정하면 됩니다.&lt;/p&gt;
&lt;p&gt;만약 윈도우에서 발생했다면 해당 파일에 대한 상속 권한을 비활성화 시키고, 현재 윈도우 계정만 개인키 파일에 접근할 수 있도록 설정을 변경해줍니다. &lt;/p&gt;
&lt;p&gt;자세한 방법은 &lt;a href=&quot;https://techsoda.net/windows10-pem-file-permission-settings/&quot;&gt;윈도우10 SSH 접속시 PEM 파일 퍼미션 에러 해결방법&lt;/a&gt;  글을 참고하시면 됩니다.&lt;/p&gt;
&lt;p&gt;[참고]&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://serverfault.com/questions/935666/ssh-authentication-sequence-and-key-files-explain&quot;&gt;https://serverfault.com/questions/935666/ssh-authentication-sequence-and-key-files-explain&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://superuser.com/questions/215504/permissions-on-private-key-in-ssh-folder&quot;&gt;https://superuser.com/questions/215504/permissions-on-private-key-in-ssh-folder&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;</description>
      <category>Server</category>
      <author>평범한 개발자...</author>
      <guid isPermaLink="true">https://2dongdong.tistory.com/73</guid>
      <comments>https://2dongdong.tistory.com/73#entry73comment</comments>
      <pubDate>Mon, 13 Sep 2021 09:14:47 +0900</pubDate>
    </item>
    <item>
      <title>[Mysql/MariaDB] 밀리세컨드 저장이 안되는 문제</title>
      <link>https://2dongdong.tistory.com/71</link>
      <description>&lt;p&gt;밀리세컨드 저장이 안되는 근본적인 이유는 하나입니다.&amp;nbsp;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;&quot;데이터베이스 버전 문제&quot;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #000000;&quot;&gt;MySQL은 5.6.4부터,&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #000000;&quot;&gt;MariaDB는 5.3부터 &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #000000;&quot;&gt;밀리세컨드/마이크로세컨드 단위를 지원합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;MariaDB의 경우, 호환성을 위해 10.1.2 버전부터 MySQL과 동일한 포맷 및 변수를 사용합니다.&lt;b&gt;&lt;br /&gt;&lt;a href=&quot;https://mariadb.com/kb/en/server-system-variables/#mysql56_temporal_format&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;mariadb.com/kb/en/server-system-variables/#mysql56_temporal_format&lt;/a&gt;&lt;/b&gt;&lt;/blockquote&gt;
&lt;p&gt;그러나, 버전이 지원함에도 불구하고 Spring boot 설정 문제로 인하여 밀리세컨드 저장이 안되는 경우가 있습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;이 경우에는, DB에 직접 쿼리를 실행하면 밀리세컨드가 저장 되지만,&lt;/p&gt;
&lt;p&gt;JDBC를 통해서 저장하게되면 밀리세컨드가 저장되지 않는 아주 난감한 상황게 빠지게 되죠.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;저장이 안되는 이유는 크게 2가지 입니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. Dialect 설정 문제&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p&gt;잘못된 Dialect 설정으로 해당 기능을 사용하지 못하는 경우입니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;예를들어, 데이터베이스 버전이 MySQL 8.0인데,&lt;/p&gt;
&lt;p&gt;아래와 같이 MySQL5(5.5)로 설정하게되면 ORM에서 MySQL 5.5 버전을 기준으로 쿼리를 작성하게 됩니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1616903279500&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;5.5버전에서는&amp;nbsp;&lt;span style=&quot;color: #000000;&quot;&gt;마이크로세컨드&lt;/span&gt;를 지원하지 않으니 당연히 저장이 안되겠죠&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;자세한 내용은 아래 글을 참고하시면 됩니다.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://2dongdong.tistory.com/66&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;span&gt;[Spring boot] JPA Dialect(방언) 설정에 관하여&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. Connector 문제&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p&gt;데이터베이스는 MariaDB인데 MySQL Connector 사용하는 경우입니다.&lt;/p&gt;
&lt;p&gt;(&lt;span style=&quot;color: #333333;&quot;&gt;MySQL을 사용하는데 MariaDB Connector를 사용하는 경우는 아마 없겠죠..?)&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;MySQL과 MariaDB는 서로 호환이 되기 때문에 Connector를 크게 신경쓰지 않는 분들이 계실텐데요.&lt;/p&gt;
&lt;p&gt;실제로 동작시켜보면 MySQL Connector를 사용할 경우, &lt;span&gt;MariaDB 10.4.7을 MySQL 5.5.5로 감지하게 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lf0FJ/btq09kkZCQ4/e1wmXsh5gy7cR3mxG1kzNk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lf0FJ/btq09kkZCQ4/e1wmXsh5gy7cR3mxG1kzNk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lf0FJ/btq09kkZCQ4/e1wmXsh5gy7cR3mxG1kzNk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Flf0FJ%2Fbtq09kkZCQ4%2Fe1wmXsh5gy7cR3mxG1kzNk%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;3. 결론&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p&gt;초급 혹은 신입개발자가 혼자서 초기 프로젝트를 구성하다보면,&lt;/p&gt;
&lt;p&gt;Spring boot 설정파일이나 pom 또는 gradle 코드를 구글링하여 그대로 쓰는 경우가 있습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;설정이나 라이브러리는 하나하나 공부해서 직접 설정하는것이 실력향상에 도움도되고&lt;/p&gt;
&lt;p&gt;오류가 발생했을때 원인을 찾는것이 훨씬 쉬워질 것입니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;[참고]&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://issues.alfresco.com/jira/browse/MNT-17613&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;issues.alfresco.com/jira/browse/MNT-17613&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://mariadb.com/kb/en/changes-improvements-in-mariadb-53/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;mariadb.com/kb/en/changes-improvements-in-mariadb-53/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://mariadb.com/kb/en/microseconds-in-mariadb/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;mariadb.com/kb/en/microseconds-in-mariadb/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Server/Database</category>
      <author>평범한 개발자...</author>
      <guid isPermaLink="true">https://2dongdong.tistory.com/71</guid>
      <comments>https://2dongdong.tistory.com/71#entry71comment</comments>
      <pubDate>Sun, 28 Mar 2021 13:11:29 +0900</pubDate>
    </item>
    <item>
      <title>2020년 회고</title>
      <link>https://2dongdong.tistory.com/70</link>
      <description>&lt;p&gt;&lt;a href=&quot;https://2dongdong.tistory.com/14?category=730705&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2dongdong.tistory.com/14?category=730705&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1610267445801&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;article&quot; data-og-title=&quot;2020년 목표&quot; data-og-description=&quot;훈련소 다녀오고 여행갔다가 한 주 보내니 벌써 1월의 절반이 지나갔네요. 2020년도 목표를&amp;nbsp;따로&amp;nbsp;다이어리에 적긴 했지만, 블로그를 제대로 운영해보고자 글을 남겨봅니다. 남들 처럼 이쁘게 꾸&quot; data-og-host=&quot;2dongdong.tistory.com&quot; data-og-source-url=&quot;https://2dongdong.tistory.com/14?category=730705&quot; data-og-url=&quot;https://2dongdong.tistory.com/14&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bwpka3/hyIS7Ilsf4/56L8mIDymirafjrkLomrl0/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/bqIAj5/hyISZDxonN/NVqKekS4BoAkgnSdTtYtjK/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800&quot;&gt;&lt;a href=&quot;https://2dongdong.tistory.com/14?category=730705&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://2dongdong.tistory.com/14?category=730705&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bwpka3/hyIS7Ilsf4/56L8mIDymirafjrkLomrl0/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/bqIAj5/hyISZDxonN/NVqKekS4BoAkgnSdTtYtjK/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;2020년 목표&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;훈련소 다녀오고 여행갔다가 한 주 보내니 벌써 1월의 절반이 지나갔네요. 2020년도 목표를&amp;nbsp;따로&amp;nbsp;다이어리에 적긴 했지만, 블로그를 제대로 운영해보고자 글을 남겨봅니다. 남들 처럼 이쁘게 꾸&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;2dongdong.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;1. 운동&lt;/b&gt;&lt;/h4&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주 3회를 목표로 하였으며, 코로나 때문에 중간중간 끊기긴 했지만 지금 까지 꾸준히 진행 중이다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;320&quot; data-origin-height=&quot;711&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/74Det/btqSZydqltb/67Puylgd3KJ7eTPjKOgep1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/74Det/btqSZydqltb/67Puylgd3KJ7eTPjKOgep1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/74Det/btqSZydqltb/67Puylgd3KJ7eTPjKOgep1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F74Det%2FbtqSZydqltb%2F67Puylgd3KJ7eTPjKOgep1%2Fimg.png&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;320&quot; data-origin-height=&quot;711&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;재작년 12월 훈련소를 다녀온 이후,&amp;nbsp;&lt;/p&gt;
&lt;p&gt;골격근량 3.7kg 증가, 체지방량 4.7kg 감소했다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;되돌아보면 몸이 정말 많이 바뀌었다. 왜소했던게 큰 컴플랙스 였는데, 덩치가 많이 커져서 뿌듯하다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;2. 공부&lt;/b&gt;&lt;/h4&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 영어회화는 완전한 실패로 끝났다. 처음 한, 두달 열심히 했지만 동기부여가 생기지 않아 깔끔하게 포기!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 책읽기는 정말 자기전 하루에 한 장 읽는 것을 목표로 해도, 실천하지 못했다. 자기전에 자꾸 유튜브를 보게된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정말 유튜브를 삭제해야하나 싶다! 아으~~!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 카메라 공부는 틈틈히 했다. 책을 사서 참고 해보기도 하고, 인터넷 글도 많이 읽었다. 2019년도에는 카메라 공부, 2020년도는 사진찍는법에 대해 많이 배웠다. 연말에는 영상찍는법을 벼락치기로 배워서 여자친구 언니 결혼식 영상을 찍고 편집하여 하나의 작품을 만들었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 개발공부는 대략적으로 정리하면 아래와 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; . Vue.js 입문책: 완독&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; . 스프링부트와 AWS로 혼자 구현하는 웹 서비스: 완독&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; . RealMySQL: 필요한 부분만 읽는 중. index, partitioning을 주로 읽은 듯&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; . 마이크로서비스 아키텍처 구축: 완독&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; . 디자인패턴 책 3권: 1권으로는 이해가안가서 3권을 돌려보는 중, 대부분 읽긴 했지만 정리가 필요함..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 공부를 통해 얻은 것.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. Vue.js로 만든 간단한 웹서비스 (Front 보단 Back에 더 집중..)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;. gitlab+ aws S3 + CodeDeploy를 연동해서 테스트 자동화, 배포 자동화 시스템을 구현했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;. 도메인을 적용(무료)하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 테이블 만들 때, 쿼리를 작성할 때 인덱스부터 고민한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 대용량처리를 어떻게 하는지 구체적으로 알고 싶었는데, 가려운 부분이 해소됐다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; . 실제로 구축해보고 싶은데, 마땅한 자원이 없다... 로컬로 가상머신으로 해야하나?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. 처음부터 디자인패턴을 설계해서 코드 짜는 레벨은 아니지만, 코드를 짜다가 반복되는 부분이 생기거나, 나중에 기능이 추가되거나 유지보수를 고려해서 기존코드의 수정을 최소화 시키는 방법 또는 아에 독립적으로 분리시켜서 어떻게 패턴화 할지 많이 고민하게 된다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;3. 경험한 것 혹은 이룬 것&lt;/b&gt;&lt;/h4&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 꾸준히 운동하기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 공부하기 (꾸준히는 안함)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 눈썹 문신 (진작 했어야함)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. 국내여행 (전주,공주,삼남길,청주,춘천,소요산)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5. 아울렛 쇼핑에 눈을 떴다. (다신 백화점 안간다...)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;6. 턱걸이 최대 10개 가능&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;7. 커플링을 맞췄다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;8. 다양한 데이트 (사격, 스포츠몬스터, 출사, 비건데이트, 커플여행)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;9. 결혼식 영상 찍기+편집 (뜻깊은 선물을 줘서 기분이 좋다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;10. 카러플 레전드 티어 달성?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;11. 후지필름 카메라를 사고 인생샷을 많이 찍은 것.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;4. 시원하게! 플랙스하게 지른 것&lt;/b&gt;&lt;/h4&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 후지필름 카메라: 2020년 한 해의 추억을 이 카메라로 담았다. 너무 잘 샀다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 자브라 75T: QCY시리즈 쓰다가 큰맘먹고 지른 것. 정말 잘 쓰고있음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 갤럭시S20: 말도안되는 스팩에 정말 잘 만든 핸드폰...&amp;nbsp; 많이 안팔려서 안타까울 뿐&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. 지오지아 롱패딩: 따뜻하고 옷 자체는 좋은데, 백화점에서 산게 가장 큰 실수. 너무 비싸게주고 샀다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5. 아울렛 가서 산것들: 정장, 코트, 바지, 셔츠.. 등등 눈돌아가서 막 산거같다. 합해서 100만원 나온듯.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;6. 2070 Super + 32인치 144hz QHD 모니터: 게임하는데 몰입감이 한 층 더해졌다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;7. 마샬 스탠모어2 스피커: &lt;span style=&quot;color: #333333;&quot;&gt;음질 좋고 파워 빵빵한 스피커. &lt;span style=&quot;color: #333333;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;직구로 싸게 샀다.&amp;nbsp; &lt;/span&gt;&lt;/span&gt;음악감상 + 인테리어용&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나름 &lt;span style=&quot;color: #333333;&quot;&gt;평소에&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;알뜰하게 살고있다고 생각했는데, 되돌아보니 전혀 아니네&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래도 딱 필요한 거 샀다고 생각한다...&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;5. 결론&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바쁘게 산 날도 있고, 무기력하게 보낸 날도 많았다. 무기력하게 보낸 날은 시간을 그냥 흘려보낸거같아 많이 후회했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래도 되돌아보니 열심히 살았었구나 생각한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만, 블로그에 글을 많이 못쓴게 흠이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메모장에 써야할 글과 주제를 수십개 적어놨는데, 줄지않고 늘어나기만한다. 마이너스 요소임..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2020년을 점수로 평가하자면 10점 만점에 7점!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2021년도를 완벽하게 보낼거라 생각하지 않는다. 딱 1점만 올려서 8점의 해를 보내보자.&lt;/p&gt;</description>
      <category>Life/일상</category>
      <author>평범한 개발자...</author>
      <guid isPermaLink="true">https://2dongdong.tistory.com/70</guid>
      <comments>https://2dongdong.tistory.com/70#entry70comment</comments>
      <pubDate>Sun, 10 Jan 2021 18:53:55 +0900</pubDate>
    </item>
    <item>
      <title>[Vue.js] - HTML5 WebSocket(웹 소켓) 소스코드 및 데모 사이트</title>
      <link>https://2dongdong.tistory.com/67</link>
      <description>&lt;p&gt;웹소켓 클라이언트가 필요해서 bootstrap+vuejs로 간단하게 만들어봤습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;jQuery에서 vuejs로 넘어오면서 익숙하지 않은게 힘들었는데, 조금씩 익숙해지니 개발하는데 훨씬 편리함을 느끼네요.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;웹소켓 또한 이벤트핸들러와 메소드로 간단히 만들 수 있습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;핵심 부분은 아래가 전부입니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1605253082027&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;  ...
  //소켓 연결
  this.socket = new WebSocket(this.address)
  ...
  this.socket.onopen = 소켓 연결 이벤트 헨들러
  ...
  this.socket.onerror = 소켓 에러 이벤트 헨들러
  ...
  this.socket.onmessage = 데이터 수신 이벤트 헨들러
  ...
  this.socket.onclose = 소켓 해제 이벤트 헨들러
  ...
  // 소켓 데이터 전송
  this.socket.send(&quot;메시지&quot;) 
  ...
  // 소켓 종료
  this.socket.close()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;아래는 자바 스크립트 전체 소스코드 입니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1605250709003&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;  methods: {
    connect () {
      if (this.socket === undefined || this.socket.readyState === 3) {
        this.socket = new WebSocket(this.address)
        this.socket.onopen = () =&amp;gt; {
          this.logs.push({ type: 'INFO', msg: 'CONNECTED' })
          this.disabled = false
        }
        this.socket.onerror = () =&amp;gt; {
          this.logs.push({ type: 'ERROR', msg: 'ERROR:' })
        }
        this.socket.onmessage = ({ data }) =&amp;gt; {
          this.logs.push({ type: 'RECV', msg: 'RECV:' + data })
        }
        this.socket.onclose = (msg) =&amp;gt; {
          this.logs.push({ type: 'ERROR', msg: 'Closed (Code: ' + msg.code + ', Message: ' + msg.reason + ')' })
        }
      }
    },
    sendMessage () {
      if (this.selected === 'plain') {
        this.logs.push({ type: 'SENT', msg: 'SENT:' + this.message })
        this.socket.send(this.message)
      } else if (this.selected === 'json') {
        this.logs.push({ type: 'SENT', msg: 'SENT:' + JSON.stringify(this.json) })
        this.socket.send(JSON.stringify(this.json))
      }
    },
    disconnect () {
      if (this.socket.readyState === 1) {
        this.socket.close()
        this.logs.push({ type: 'INFO', msg: 'DISCONNECTED' })
        this.disabled = true
      }
    }
  }&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Vue를 포함한 모든 소스 코드는 깃허브에 있습니다.&lt;/p&gt;
&lt;p&gt;깃허브 주소:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://github.com/lehdqlsl/vue-websocket-client&quot;&gt;github.com/lehdqlsl/vue-websocket-client&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ceqPCY/btqNoRO2w3w/kfxrwn5pDeM7k5mP56jXLK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ceqPCY/btqNoRO2w3w/kfxrwn5pDeM7k5mP56jXLK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ceqPCY/btqNoRO2w3w/kfxrwn5pDeM7k5mP56jXLK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FceqPCY%2FbtqNoRO2w3w%2Fkfxrwn5pDeM7k5mP56jXLK%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;실제 서버에 올려서 구동시킨 데모 화면입니다. 아래 URL에 누르면 해당 웹페이지로 접속 가능합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;접속주소:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;http://vue-websocket.ga/&quot;&gt;vue-websocket.ga/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;그리고 Location 부분에 아래 에코서버에 연결하여 간단하게 테스트해 볼 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://echo.websocket.org&quot;&gt;wss://echo.websocket.org&lt;/a&gt;&lt;/p&gt;</description>
      <category>Web/Vue.js</category>
      <author>평범한 개발자...</author>
      <guid isPermaLink="true">https://2dongdong.tistory.com/67</guid>
      <comments>https://2dongdong.tistory.com/67#entry67comment</comments>
      <pubDate>Fri, 13 Nov 2020 16:43:03 +0900</pubDate>
    </item>
    <item>
      <title>[Spring boot] JPA Dialect(방언) 설정에 관하여</title>
      <link>https://2dongdong.tistory.com/66</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;결론만 말하면&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;&quot;Dialect 설정은 하지 않아도 된다.&quot;&amp;nbsp;&lt;/b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;1. Dialect 란?&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ORM의 큰 특징중 하나는 객체 맵핑을 통해 자동으로 쿼리를 작성해주는 것입니다. 하지만 수 많은 DBMS 종류가 있고 각 종류마다 쿼리가 조금씩 다르기 때문에, 이를 알릴 수 있도록 데이터베이스 유형을 지정하도록 하는 것이 &lt;b&gt;Dialect&lt;/b&gt; 설정 입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 Dialect 설정은 연결되는 Springboot 실행 시, 연결되어있는 데이터베이스에 알맞게 자동으로 지정이 되므로, &lt;span style=&quot;color: #333333;&quot;&gt;특별한 이유가 존재하지 않는 이상 수동으로 설정할 필요가 없습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;여러가지 데이터베이스를 하나씩 연결하여 확인해보면 아래 로그와 같이 연결되는 DB에 알맞게 Dialect 설정이 되는 것을 확인할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;535&quot; data-origin-height=&quot;125&quot; width=&quot;603&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Pj5U6/btqM4Au1bIr/l1yI0UGpDOPx9E0VCkGd1k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Pj5U6/btqM4Au1bIr/l1yI0UGpDOPx9E0VCkGd1k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Pj5U6/btqM4Au1bIr/l1yI0UGpDOPx9E0VCkGd1k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FPj5U6%2FbtqM4Au1bIr%2Fl1yI0UGpDOPx9E0VCkGd1k%2Fimg.png&quot; data-origin-width=&quot;535&quot; data-origin-height=&quot;125&quot; width=&quot;603&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;저 처럼 인터넷에 떠돌아다니는 JPA properties 값을 복사/붙여넣기 하여,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;잘 모르는 상태에서 &lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;spring.jpa.properties.hibernate.dialect 설정값을 그대로 가져다가 쓰시는 분이 계시다면 해당 부분은 지우시는걸 권장드립니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;그렇지 않으면 현재 사용하는 데이터베이스와 다르게 Dialect가 설정되어 큰 고생을 하게 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2. 무엇이 문제가 되는가?&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론 오라클 DB를 사용하는데, MySQL Dialect로 설정하거나, MySQL DB를 사용하는데 오라클 Dialect로 설정하신 분들은 없으실 겁니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만, MySQL과 MariaDB가 서로 호환되는 사실에, 둘이 혼용하거나 버전에 맞지않은 Dialect 설정을 하는 것이 문제 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저의 경우, MariaDB 10.4 버전을 사용하는데, Dialect 설정값 &lt;b&gt;&lt;span&gt;MySQL5Dialect&lt;/span&gt;&lt;/b&gt;&lt;span&gt;을 사용했습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;(&lt;span&gt;MySQL5Dialect 은 MysQL 5.5 이전 버전을 뜻합니다.)&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1605052611616&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런식으로 말이죠..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이미&amp;nbsp;MySQL&amp;nbsp;버전의&amp;nbsp;차이에&amp;nbsp;대해&amp;nbsp;잘&amp;nbsp;알고계신&amp;nbsp;분들은&amp;nbsp;눈치&amp;nbsp;채셨을겁니다. &lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저렇게 설정을 한다고해서 에러가 발생하다거나 JPA가 동작을 안하지는 않습니다. 다만 Hibernate에서 SQL 쿼리로 변환하는 과정에서 MySQL 5.x 버전(5.5이전) 기준으로 변환 될 뿐이죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저는 이렇게 설정을 하면서 2가지 문제를 겪었습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2-1 트랜잭션 동작 안함&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MySQL 5.5 이전 버전의 기본 스토리지 엔진은 &lt;b&gt;InnoDB&lt;/b&gt;가 아닌&amp;nbsp;&lt;b&gt;MyISAM 입니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;MySQL &lt;/span&gt;5.5부터 기본 스토리지 엔진이 InnoDB로 채택됩니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 스토리지 엔진의 가장 큰 차이점은 트랙잭션 기능 유무입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Dialect를 &lt;span&gt;MySQL5Dialect으로 설정했던 탓에 MyISAM 엔진이 기본으로 선택되어 트랜잭션이 동작하지 않았습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;373&quot; data-origin-height=&quot;297&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/VQD6E/btqNaFnTfH4/kksSI6S4fHIzRMY7wd4Ex0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/VQD6E/btqNaFnTfH4/kksSI6S4fHIzRMY7wd4Ex0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/VQD6E/btqNaFnTfH4/kksSI6S4fHIzRMY7wd4Ex0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FVQD6E%2FbtqNaFnTfH4%2FkksSI6S4fHIzRMY7wd4Ex0%2Fimg.png&quot; data-origin-width=&quot;373&quot; data-origin-height=&quot;297&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;테이블이 생성 될 때 쿼리를 확인해보면 MyISAM으로 생성되는 것을 확인할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span&gt;MySQL5Dialect&lt;/span&gt;&lt;/b&gt;&lt;span&gt;의 부모클래스인 &lt;b&gt;&lt;span&gt;MySQLDialect &lt;/span&gt;&lt;/b&gt;&lt;span&gt;클래스 생성자의 &lt;span style=&quot;color: #333333;&quot;&gt;소스코드를 살펴보면 해당 내용이 있습니다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img style=&quot;text-align: center; caret-color: transparent; letter-spacing: 0px;&quot; src=&quot;https://blog.kakaocdn.net/dn/dSdNNz/btqNcFOST9t/zMKzxpIRx5EImKKk9RigH0/img.png&quot; data-image-src=&quot;https://blog.kakaocdn.net/dn/dSdNNz/btqNcFOST9t/zMKzxpIRx5EImKKk9RigH0/img.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; /&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스토리지 엔진을 별도로 지정하지 않으면 getDefaultMySQLStorageEngine 메소드를 호출하는데,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;520&quot; data-origin-height=&quot;84&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bMRauS/btqNeIYVLEf/B65OWEypjjnCPtyyjn1OT0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bMRauS/btqNeIYVLEf/B65OWEypjjnCPtyyjn1OT0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bMRauS/btqNeIYVLEf/B65OWEypjjnCPtyyjn1OT0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbMRauS%2FbtqNeIYVLEf%2FB65OWEypjjnCPtyyjn1OT0%2Fimg.png&quot; data-origin-width=&quot;520&quot; data-origin-height=&quot;84&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본 스토리지 엔진이 MyISAM으로 되어있는것을 확인할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추가적으로,&amp;nbsp; InnoDB가 기본적으로 채택되는 MySQL 5.5 버전에 해당하는 &lt;span&gt;MySQL55Dialect를 살펴보면,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;865&quot; data-origin-height=&quot;134&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bivbtF/btqM9OMG4Yr/dLP9Ru184zUniSD4ueq3Sk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bivbtF/btqM9OMG4Yr/dLP9Ru184zUniSD4ueq3Sk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bivbtF/btqM9OMG4Yr/dLP9Ru184zUniSD4ueq3Sk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbivbtF%2FbtqM9OMG4Yr%2FdLP9Ru184zUniSD4ueq3Sk%2Fimg.png&quot; data-origin-width=&quot;865&quot; data-origin-height=&quot;134&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;MySQL5Dialect 클래스를 상속받아 getDefaultMySQLStorageEngine() 메소드가 InnoDB로 재정의 되어있는 것을 볼 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2-2 datetime 밀리세컨드 단위 저장 안됨&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저의 경우, 데이터베이스는 당연히 최신이니 직접 쿼리를 할 땐 밀리세컨드까지 저장이 잘 되었으나,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JPA를 통해 저장이 될 때는 밀리센컨드 단위가 잘려서 저장되었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;datetime 타입에서 밀리세컨드를 정식으로 지원하는 MySQL 버전은 5.6.4 입니다. (MariaDB는 5.3 부터 지원)&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MySQL 최신버전을 사용하는데 밀리세컨드 저장이 안된다면 Dialect 설정을 확인하면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;(밀리세컨드를 지원하는 Dialect는 MySQL57Dialect 이상입니다)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;MySQL57Dialect 클래스의 소스코드를 확인해보면 관련 내용에 대해 상세한 설명이 되어있는 것을 볼 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;757&quot; data-origin-height=&quot;347&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/QW5MD/btqNaEwjf33/k5ZeHj9stMJ4lUoQ2LKSXK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/QW5MD/btqNaEwjf33/k5ZeHj9stMJ4lUoQ2LKSXK/img.png&quot; data-alt=&quot;MySQL57Dialect 클래스 일부&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/QW5MD/btqNaEwjf33/k5ZeHj9stMJ4lUoQ2LKSXK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQW5MD%2FbtqNaEwjf33%2Fk5ZeHj9stMJ4lUoQ2LKSXK%2Fimg.png&quot; data-origin-width=&quot;757&quot; data-origin-height=&quot;347&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;MySQL57Dialect 클래스 일부&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MariaDB를 사용하는데 밀리세컨드 저장이 안된다면 커넥터를 MriaDB 커넥터로 바꾸시길 바랍니다.&lt;span style=&quot;color: #333333;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;3. Dialect 클래스 정리&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Hibernate 5.4 기준으로 작성한 MySQL &amp;amp; MariaDB Dialect 클래스 구조입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;새로운 DB 버전이 릴리즈 될 때, 하위버전 Dialect 클래스를 상속받아 추가된 기능을 재정의 하는 방식으로 Dialect 클래스가 추가되고 있습니다. 디자인패턴을 배우고나니 프레임워크의 구조를 뜯어보게 되네요.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;351&quot; data-origin-height=&quot;642&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/59dRT/btqNeHTikj7/UnUuaPu50hTShbBujQxKxk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/59dRT/btqNeHTikj7/UnUuaPu50hTShbBujQxKxk/img.png&quot; data-alt=&quot;MySQL &amp;amp;amp;amp; MariaDB Dialect 구조&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/59dRT/btqNeHTikj7/UnUuaPu50hTShbBujQxKxk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F59dRT%2FbtqNeHTikj7%2FUnUuaPu50hTShbBujQxKxk%2Fimg.png&quot; data-origin-width=&quot;351&quot; data-origin-height=&quot;642&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;MySQL &amp;amp; MariaDB Dialect 구조&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;4. Deprecated Dialect 설정 값&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JPA Properties 관련해서 구글링 하다보면 간혹 &lt;span style=&quot;color: #333333;&quot;&gt;예제로&lt;/span&gt; Deprecated 된 설정값으로 되어있는 경우가 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;MySQL57InnoDBDialect&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;MySQL5InnoDBDialect&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;MySQLInnoDBDialect등&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;등등.. 이 존재하는데, 자세한건 Hibernate 공식문서에서 확인할 수 있습니다.&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;(&lt;a href=&quot;https://docs.jboss.org/hibernate/orm/5.4/javadocs/org/hibernate/dialect/package-summary.html&quot;&gt;https://docs.jboss.org/hibernate/orm/5.4/javadocs/org/hibernate/dialect/package-summary.html&lt;/a&gt;)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;잘 모르고 설정했다가는 문제가 발생할 수 있으니, 수동으로 설정을 하게 된다면 잘 알고 하는게 좋고&lt;br /&gt;그렇지&amp;nbsp;않으면&amp;nbsp;따로&amp;nbsp;Dialect&amp;nbsp;설정을&amp;nbsp;할&amp;nbsp;필요가&amp;nbsp;없겠습니다.&lt;/p&gt;</description>
      <category>Java/JPA</category>
      <author>평범한 개발자...</author>
      <guid isPermaLink="true">https://2dongdong.tistory.com/66</guid>
      <comments>https://2dongdong.tistory.com/66#entry66comment</comments>
      <pubDate>Wed, 11 Nov 2020 00:07:07 +0900</pubDate>
    </item>
    <item>
      <title>갤럭시 S20 울트라 이미지 센서 크기 (+ 카메라 이미지 센서 크기 비교)</title>
      <link>https://2dongdong.tistory.com/65</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;1억만 화소의 카메라 모듈이 장착되는 휴대폰인 &lt;b&gt;갤럭시 S20 울트라&lt;/b&gt;와 &lt;b&gt;갤럭시 노트20 울트라&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 휴대폰들의 이미지 센서크기가 DSLR에 들어가는 이미지 센서와 비교했을 때, 어느정도의 차이가 날까요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바로 비교 들어가보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 120px;&quot; border=&quot;1&quot; data-ke-style=&quot;style4&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 40px;&quot;&gt;
&lt;td style=&quot;text-align: center; height: 40px; width: 12.4419%;&quot;&gt;Type&lt;/td&gt;
&lt;td style=&quot;text-align: center; height: 40px; width: 12.4419%;&quot;&gt;1/2.55 인치&lt;/td&gt;
&lt;td style=&quot;text-align: center; height: 40px; width: 12.4419%;&quot;&gt;1/1.72 인치&lt;/td&gt;
&lt;td style=&quot;text-align: center; height: 40px; width: 12.4419%;&quot;&gt;1/1.33 인치&lt;/td&gt;
&lt;td style=&quot;text-align: center; width: 12.4419%; height: 40px;&quot;&gt;1인치&lt;/td&gt;
&lt;td style=&quot;text-align: center; height: 40px; width: 12.5581%;&quot;&gt;Four Thirds&lt;/td&gt;
&lt;td style=&quot;text-align: center; height: 40px; width: 12.5581%;&quot;&gt;APS-C&lt;br /&gt;(크롭바디)&lt;/td&gt;
&lt;td style=&quot;text-align: center; height: 40px; width: 12.5581%;&quot;&gt;35mm&lt;br /&gt;(풀프레임)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 40px;&quot;&gt;
&lt;td style=&quot;text-align: center; height: 40px; width: 12.4419%;&quot;&gt;대표기종&lt;/td&gt;
&lt;td style=&quot;text-align: center; height: 40px; width: 12.4419%;&quot;&gt;대부분의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;스마트폰&lt;/td&gt;
&lt;td style=&quot;text-align: center; height: 40px; width: 12.4419%;&quot;&gt;갤럭시 S20,&lt;br /&gt;갤럭시 S20+&lt;/td&gt;
&lt;td style=&quot;text-align: center; height: 40px; width: 12.4419%;&quot;&gt;노트 20 울트라,&lt;br /&gt;S20 울트라&lt;/td&gt;
&lt;td style=&quot;text-align: center; width: 12.4419%; height: 40px;&quot;&gt;G9X, RX100&lt;/td&gt;
&lt;td style=&quot;text-align: center; height: 40px; width: 12.5581%;&quot;&gt;LX100&lt;/td&gt;
&lt;td style=&quot;text-align: center; height: 40px; width: 12.5581%;&quot;&gt;EOS M 시리즈&lt;br /&gt;A6400&lt;/td&gt;
&lt;td style=&quot;text-align: center; height: 40px; width: 12.5581%;&quot;&gt;EOS R&lt;br /&gt;A7 시리즈&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;text-align: center; height: 20px; width: 12.4419%;&quot;&gt;대각선 (mm)&lt;/td&gt;
&lt;td style=&quot;text-align: center; height: 20px; width: 12.4419%;&quot;&gt;7.06&lt;/td&gt;
&lt;td style=&quot;text-align: center; height: 20px; width: 12.4419%;&quot;&gt;9.216&lt;/td&gt;
&lt;td style=&quot;text-align: center; height: 20px; width: 12.4419%;&quot;&gt;12.03&lt;/td&gt;
&lt;td style=&quot;text-align: center; width: 12.4419%; height: 20px;&quot;&gt;16&lt;/td&gt;
&lt;td style=&quot;text-align: center; height: 20px; width: 12.5581%;&quot;&gt;21.6&lt;/td&gt;
&lt;td style=&quot;text-align: center; height: 20px; width: 12.5581%;&quot;&gt;26.7~28.2&lt;/td&gt;
&lt;td style=&quot;text-align: center; height: 20px; width: 12.5581%;&quot;&gt;43.26&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;text-align: center; height: 20px; width: 12.4419%;&quot;&gt;크롭팩터&lt;/td&gt;
&lt;td style=&quot;text-align: center; height: 20px; width: 12.4419%;&quot;&gt;6.12&lt;/td&gt;
&lt;td style=&quot;text-align: center; height: 20px; width: 12.4419%;&quot;&gt;4.69&lt;/td&gt;
&lt;td style=&quot;text-align: center; height: 20px; width: 12.4419%;&quot;&gt;3.59&lt;/td&gt;
&lt;td style=&quot;text-align: center; width: 12.4419%; height: 20px;&quot;&gt;2.7&lt;/td&gt;
&lt;td style=&quot;text-align: center; height: 20px; width: 12.5581%;&quot;&gt;2.0&lt;/td&gt;
&lt;td style=&quot;text-align: center; height: 20px; width: 12.5581%;&quot;&gt;1.5~1.6&lt;/td&gt;
&lt;td style=&quot;text-align: center; height: 20px; width: 12.5581%;&quot;&gt;1.0&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;그림1.png&quot; data-origin-width=&quot;807&quot; data-origin-height=&quot;548&quot; width=&quot;591&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cLNfs4/btqK2rSQ80k/tFlR5WLtUkKX6CMnAPwZI1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cLNfs4/btqK2rSQ80k/tFlR5WLtUkKX6CMnAPwZI1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cLNfs4/btqK2rSQ80k/tFlR5WLtUkKX6CMnAPwZI1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcLNfs4%2FbtqK2rSQ80k%2FtFlR5WLtUkKX6CMnAPwZI1%2Fimg.png&quot; data-filename=&quot;그림1.png&quot; data-origin-width=&quot;807&quot; data-origin-height=&quot;548&quot; width=&quot;591&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 사진을 보면, 1/1.33인치(&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;파란색&lt;/b&gt;)&lt;/span&gt;에 해당하는 부분이 1억만 화소의 이미지 모듈 센서입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;크롭 미러리스(APS-C)&lt;/b&gt;나 &lt;b&gt;풀프레임&lt;/b&gt; 센서에 비하면 울트라 1억만 화소 1/1.33 인치의 크기는 한참 작습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;엄청난 체급차이로 인해 안타깝게도 이는 비교대상이 아닙니다...&amp;nbsp;당연히 해상력 및 화질에 엄청난 차이를 보일겁니다. 사진을 첨부하여 그 차이를 직접 눈으로 소개시켜 드리고 싶으나, 마땅히 장비가 없어서 보여드리진 못하네요.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;그렇다면 울트라 1억만 화소 센서는 어느 카메라와 비빌 수 있을까요?&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;센서 크기를 보면 소형 디카(똑딱이)에 탑재되는 &lt;b&gt;1인치 &lt;/b&gt;이미지센서와 &lt;b&gt;1/1.33인치&lt;/b&gt; 센서를 비교해봤을 때,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;크기가 비슷한것을 볼 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선, 35mm 풀프레임 센서와 크롭바디 센서의 면적 차이가 2.25~2.56배 입니다. (1.5배 or 1.6배 크롭)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;빛이 매우 어두운 환경과 같이 아주 극단적인 상황을 제외하면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;채광력이 풍부한 환경에서는 풀프레임과 크롭의 화질 차이를 구분하기 어렵습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마찬가지로, 1인치 센서와 1/1.33인치 센서의 면적이 약 1.7배 정도 차이가 나는것으로 볼때, 이 둘의 화질 차이가 그리 크지 않을 것으로 예상해봅니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만 이 것은, 어디까지나 렌즈가 동일하다는 가정입니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;렌즈의 중요성 (조리개 및 유효구경)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1억만화소 센서가 과연 어디까지 비빌 수 있을지 구체적으로 알기위해 이론적인 계산이 필요합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 갑분수.. (갑자기 분위기 수학)가 될 것같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아무튼, 화질을 결정하는 가장 중요한 요소 중 하나가 렌즈이기 때문에 렌즈 이야기를 빼놓을 수 없네요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이미지 센서가 아무리 커도 빛을 모아주는 렌즈의 크기가 작다면, 충분한 빛을 받지 못해서 좋은 화질을 기대할 수 없겠죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;F1.4, F2.0, F2.8와 같이 조리개 값은 빛을 받아들이는 양을 뜻합니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;더 많은 빛을 모으기 위해서는 렌즈가 더 커져야 하겠지요? 그래서 조리개가 값이 낮은 렌즈일수록 더 크고 가격이 비쌉니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 조리개 값은 렌즈의 유효직경과 초점거리에 의해 결정됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;렌즈의 유효직경, 초점거리, 조리개 값은 서로 연관관계가 있는데, 이런 연관관계는 아래와 같은 간단한 공식으로 나타낼 수 있습니다.&lt;/p&gt;
&lt;h2 style=&quot;text-align: center;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;유효직경 = 초점거리/조리개&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 공식에 따르면, 아래 사진 처럼 같은 조리개 값이라도 초점거리에 따라서 유효직경이 달라지게 됩니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;434&quot; data-origin-height=&quot;434&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Ai8AY/btrfQEHVMo0/NISoxe0ci2V3tNCdMpmWb0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Ai8AY/btrfQEHVMo0/NISoxe0ci2V3tNCdMpmWb0/img.png&quot; data-alt=&quot;출처:&amp;amp;amp;nbsp;https://www.sony.co.kr/electronics/what-is-aperture-depth-of-field&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Ai8AY/btrfQEHVMo0/NISoxe0ci2V3tNCdMpmWb0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FAi8AY%2FbtrfQEHVMo0%2FNISoxe0ci2V3tNCdMpmWb0%2Fimg.png&quot; data-origin-width=&quot;434&quot; data-origin-height=&quot;434&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처:&amp;nbsp;https://www.sony.co.kr/electronics/what-is-aperture-depth-of-field&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 원리를 이용하여 35mm 풀프레임과 포서드의 차이를 예로 들어보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;포서드의 크롭팩터는 약 2이며, 면적 차이는 4배 입니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(면적 차이가 4배라는 의미는 단순히 빛을 4배 덜 받는다 라고 생각하면 됩니다. [조리개 2스탑])&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 50mm F4.0 단렌즈가 있다고 가정하고, 이 렌즈로 각각 풀프레임와 포서드에 장착시킨 후&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;초점을 특정 배경 정중앙에 맞춰서 찍으면 어떻게될까요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;880&quot; data-origin-height=&quot;305&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dzY4cJ/btrfU3NRITn/jG4prMZEZs7RcRBaCwvKQk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dzY4cJ/btrfU3NRITn/jG4prMZEZs7RcRBaCwvKQk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dzY4cJ/btrfU3NRITn/jG4prMZEZs7RcRBaCwvKQk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdzY4cJ%2FbtrfU3NRITn%2FjG4prMZEZs7RcRBaCwvKQk%2Fimg.png&quot; data-origin-width=&quot;880&quot; data-origin-height=&quot;305&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(비교하기 쉽게, 이미지 센서를 정사각형으로 그렸습니다. 파란색이 풀프레임 크기면 초록색은 포서드입니다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;포서드 이미지 센서가 더 작기때문에 그 차이만큼 잘리게 됩니다. 이걸 크롭이라 표현하죠. 그리고 얼만큼 크롭이 됐는지 판단하는 그 척도를 크롭팩터라고 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;포서드는 앞서 말씀드렸다 싶이, 크롭팩터가 2입니다. (대각선 길이 비율) 그래서 2배 확대된것처럼 보입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 풀프레임 기준으로는 초점거리 50mm 렌즈이지만, 포서드 기준으로는 50mm * 2(크롭팩터) 계산을 통해, 환산화각 100mm 렌즈가 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런식으로 풀프레임 렌즈가 아닌 렌즈들은 크롭팩터로 환산화각을 계산합니다.&amp;nbsp; 그러면 포서드로 환산화각 50mm로 만들려면 어떻게 할까요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;25mm 렌즈를 끼면됩니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇다면 이제 두번째 예시입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;풀프레임에는 F4.0 50mm, 포서드는 F4.0 25mm를 장착해서 찍으면, 둘 다 동일한 화각의 결과물을 얻을 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(단순히 화각만 같습니다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;과연 화질은 어떨까요?? 여기서 위의 공식을 적용해서 렌즈의 유효 직경을 계산해보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;F4.0 50mm 렌즈의 유효직경은 12.5mm&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;F4.0 25mm 렌즈의 유효직경은 6.25m&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;F4.0 25mm 렌즈가 훨씬 직경이 짧다는것을 알 수 있습니다. 위의 스펙으로 실제 렌즈가 만들어진다면 렌즈 크기가 훨씬 작을겁니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국 화각은 같더라도 결국 이미지 센서 면적 차이가 4배이기 때문에 빛을 4배만큼 덜 받게 되고, 화질에 영향을 주게됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 포서드가 풀프레임에 비빌려면 어떻게 해야하느냐?? 이미지 센서가 작으면, &lt;b&gt;밝은 렌즈&lt;/b&gt;를 끼면 됩니다. 4배 작으니, 4배 밝은 렌즈를 끼는겁니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[조리개값 1스탑은 제곱근이며, 면적으론 2배 밝아집니다. 자세한 설명은 검색을 통해..]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉 F4.0보다 4배 밝은 조리개 값은 F2.0 입니다. 포서드에 25mm F2.0 렌즈를 낀다면 풀프레임 50mm F4.0과 비빌 수 있을것입니다. (F2.0 25mm 렌즈의 유효직경은 12.5mm 입니다. F4.0 50mm 렌즈의 유효직경과 같다는 것을 알수있습니다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자, 예시는 끝났습니다. 이제 같은 원리를 이용하여, 갤럭시 S20 울트라와 1인치 똑딱이 G9X Mark2를 이론적으로 비교해보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;울트라 1억만 화소 센서에 장착되는 렌즈는 환산화각 &lt;b&gt;25mm&lt;/b&gt;의 고정 조리개 &lt;b&gt;F1.8 렌즈&lt;/b&gt;로, 굉장히 밝은 렌즈입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반면 캐논의 1인치 카메라 G9X Mark2에 장착되는 렌즈는 환산화각 &lt;b&gt;28-84mm&lt;/b&gt;, 가변조리개 &lt;b&gt;F2.0~F4.9&lt;/b&gt; 입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보기쉽게 계산 결과를 표로 나타내면,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 100px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;갤럭시 S20 울트라&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;G9X Mark2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;환산화각&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;25mm&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;28 ~ 84mm&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;실제 초점거리&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;6.9mm&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;10.2 ~ 30.6 mm&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;렌즈 유효 직경&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;3.8mm&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;5.1mm (F2.0 기준)&lt;br /&gt;6.2mm (F4.9 기준)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;조리개&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;F1.8&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;F2.0 ~ F 4.9&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;크롭팩터&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;3.59&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;2.74&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;차이가 느껴지시나요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;G9X Mark2 카메라가 이미지 센서도 조금 더 크고, 렌즈도 더 좋습니다. 렌즈 유효직경이 약 1.4~1.5배 정도 차이가 있네요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국 스마트폰에 장착되는 이미지 센서가 더 좋아지고 커져도, 카메라를 이기려면 센서에 장착되는 렌즈도 좋아야합니다. 물론 렌즈 또한 옛날 스마트폰에 비해 유효직경이 더 커지고 좋아지긴 했지만,&amp;nbsp; 1인치 똑딱이 카메라보다도 못한게 현실입니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국 스마트폰이 똑딱이라도 따라 잡으려면 더 큰 센서와 렌즈를 장착시켜야 할겁니다. 아래 라이츠 폰 처럼요..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;590&quot; data-origin-height=&quot;442&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mZkVP/btrfPXuU8s3/fNmF12w9wkpavZXI8xeS11/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mZkVP/btrfPXuU8s3/fNmF12w9wkpavZXI8xeS11/img.jpg&quot; data-alt=&quot;출처&amp;amp;amp;nbsp;https://www.dpreview.com/news/7121498839/leica-s-first-smartphone-the-leitz-phone-1-hits-the-japanese-market&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mZkVP/btrfPXuU8s3/fNmF12w9wkpavZXI8xeS11/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmZkVP%2FbtrfPXuU8s3%2FfNmF12w9wkpavZXI8xeS11%2Fimg.jpg&quot; data-origin-width=&quot;590&quot; data-origin-height=&quot;442&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처&amp;nbsp;https://www.dpreview.com/news/7121498839/leica-s-first-smartphone-the-leitz-phone-1-hits-the-japanese-market&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;라이츠 폰은 1인치 이미지 센서가 장착되었고, 19mm(환산화각 52mm) 의 F1.9 밝기 렌즈가 장착되어있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이정도 스펙이면, 그냥 똑딱이 카메라가 스마트폰에 내장되었다고 생각하면 될것같네요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;그 외 다른 사항들&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단순히 이미지 센서 크기와 렌즈를 떠나서 카메라만이 가지고 있는 기능들이 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. (줌렌즈의 경우) 다양한 화각&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론 울트라도 줌 렌즈 지원은 되지만, 이는 1억만 화소 센서가 아닌 1200만화소 1/3.6인치 센서의 F3.0 조리개를 가진 망원 카메라 입니다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;퀄리티는 당연히 매우 떨어지겠죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 반셔터&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 카메라에 있어서 반셔터의 역할은 매우 큰데요. 반셔터를 통해 초점과 구도를 쉽게 조절할 수 있고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;역광사진을 찍기 위해 노출(광량)을 고정하는 등 멋진 사진을 편하게 찍는 역할을 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. AF&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;캐논, 소니 등 카메라 전문 기업들은 각자 자신만의 영상처리 엔진 기술로 빠르고 정확한 AF를 제공합니다. 더 비싼 모델이나 최신의 경우 AF 추적까지 하는 기능이 있죠. 반면 스마트폰의 AF는 썩 만족스럽지 않습니다. 포커스가 안맞을때가 자주 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;결론&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;갤럭시 S20 울트라와 G9X Mark2 의 결과를 직접 비교해보고 싶지만, 우선 이론적으로 봤을 때 어느정도 차이가 날것으로 예상됩니다.&amp;nbsp; 게다가 카메라로 찍었을 때, 더 멋있고 다양한 사진을 찍을 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반대로 울트라는 별도의 카메라를 사지 않아도 혹은 들고다니지 않아도 기존 스마트폰 보다 더 뛰어난&amp;nbsp;해상력의 사진을 찍을 수 있다는 점이 가장 큰 장점이겠죠. (물론 해상력이 높다고해서 멋있는 사진이 나오는건 아닙니다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;갤럭시 울트라로 찍었을 때 딱히 만족할 만한 사진이 안나온다면 디지털카메라를 사는게 맞고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;아니다, 이걸로면 충분하고도 남는다&quot; 라는 생각이 든다면 디지털카메라는 필요하지 않을겁니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모바일용 이미지 센서가 발달하면서 마치 &quot;1억만 화소의 스마트폰 카메라가 디지털 카메라를 위협하고 있다.&quot; 라는 주제의 기사를 많이 보게됩니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 기사가 널리 퍼질 수록 카메라에 대해 잘 모르는 사람이 &lt;b&gt;&amp;nbsp;&quot;1억만 화소&quot;&lt;/b&gt; 라는 단어에서 오는 느낌은 마치 2000~3000만 화소 밖에 안되는 풀프레임 카메라보다 훨씬 더 뛰어나다는 착각을 하게 만듭니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스마트폰에 적용되는 카메라와 센서가 아무리 발전해도 동시대에 출시되는 풀프레임 카메라는 &lt;b&gt;절대 비교 불가&lt;/b&gt;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;당연히 10~20년 전의 풀프레임 카메라 보단 더 낫겠으나, 제 기준에선 &lt;b&gt;&quot;이제는 스마트폰으로도 충분히 멋진 사진을 찍을 수 있다.&quot; &lt;/b&gt;가 될 것 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 글을 읽는 여러분들의 생각은 어떠한지요?&lt;/p&gt;</description>
      <category>Life/카메라</category>
      <author>평범한 개발자...</author>
      <guid isPermaLink="true">https://2dongdong.tistory.com/65</guid>
      <comments>https://2dongdong.tistory.com/65#entry65comment</comments>
      <pubDate>Thu, 15 Oct 2020 23:11:45 +0900</pubDate>
    </item>
  </channel>
</rss>