<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>dev_yong.log</title>
        <link>https://velog.io/</link>
        <description>반갑습니다!</description>
        <lastBuildDate>Tue, 07 May 2024 09:37:02 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>dev_yong.log</title>
            <url>https://images.velog.io/images/dev_yong/profile/d57ce1ec-ec38-442f-849b-4c84ea414999/social.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. dev_yong.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/dev_yong" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[Java] Exception 한줄로 처리하기]]></title>
            <link>https://velog.io/@dev_yong/Java-Exception-%ED%95%9C%EC%A4%84%EB%A1%9C-%EC%B2%98%EB%A6%AC%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@dev_yong/Java-Exception-%ED%95%9C%EC%A4%84%EB%A1%9C-%EC%B2%98%EB%A6%AC%ED%95%98%EA%B8%B0</guid>
            <pubDate>Tue, 07 May 2024 09:37:02 GMT</pubDate>
            <description><![CDATA[<h1 id="이슈">이슈</h1>
<p>업무 환경에서 DataDog을 사용하고 있는데, DataDog에서 오류로그를 line별로 요금을 받고 있어 라인 수가 많은 Exception 로그를 줄일 수 있는지에 대한 인프라 조직 요청이 있었다.</p>
<h1 id="해결방법">해결방법</h1>
<p>오류 로그가 긴 Exception을 한줄로 처리했다.
모든 Exception을 적용하지는 않고 자주 발생하고, 유독 긴 오류에 대해서만 작업을 진행했다.</p>
<h2 id="exception-오류-로그를-한줄로-만들어주는-utiljava">Exception 오류 로그를 한줄로 만들어주는 Util.java</h2>
<pre><code class="language-java">@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class ExceptionUtils {

    public static String toOneLineExceptionDetailLog(Throwable throwable, String lineSeparator) {
        var stackTraces = throwable.getStackTrace();
        StringBuilder builder = new StringBuilder();
        builder.append(throwable.toString());
        for (StackTraceElement element : stackTraces) {
            builder.append(lineSeparator).append(&quot;\tat &quot;).append(element);
        }
        return builder.toString();
    }

    public static String toOneLineExceptionDetailLog(Throwable throwable) {
        return toOneLineExceptionDetailLog(throwable, &quot;&lt;br&gt;&quot;);
    }
}</code></pre>
<h2 id="사용-예시">사용 예시</h2>
<pre><code class="language-java">try {
    occurException(testValue);
} catch (NumberFormatException e) {
    log.debug(&quot;[Test: one line stack trace = {}&quot;, ExceptionUtils.toOneLineExceptionDetailLog(e));
}
</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Spring] FeignClient timeout 별도 설정하기]]></title>
            <link>https://velog.io/@dev_yong/FeignClient-timeout-%EB%B3%84%EB%8F%84-%EC%84%A4%EC%A0%95%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@dev_yong/FeignClient-timeout-%EB%B3%84%EB%8F%84-%EC%84%A4%EC%A0%95%ED%95%98%EA%B8%B0</guid>
            <pubDate>Fri, 03 May 2024 06:37:53 GMT</pubDate>
            <description><![CDATA[<h1 id="feignclient-timeout-별도-설정하기">FeignClient timeout 별도 설정하기</h1>
<p>feignClient를 사용하다보면 외부 API를 호출해야하는 상황이 생기는데, timeout정책을 default정책과 다르게 별도로 설정할 수 있다.</p>
<p>외부 API를 호출하는 feignClient를 아래 코드와 같이 작성한다고 가정한다.
feignClient의 name은 <code>example-client</code>이다.</p>
<pre><code class="language-java">@FeignClient(name = &quot;example-client&quot;, url = &quot;${example.url}&quot;)
public interface ExampleClient {
    @PostMapping(value = &quot;/test&quot;)
    CompletableFuture&lt;Void&gt; test();
}</code></pre>
<h1 id="applicationyml파일-수정">application.yml파일 수정</h1>
<p><code>application.yml</code>에 별도 설정할 feignClient 이름으로 설정할 수 있다.
위 코드에서 외부 호출 feignClient name으로 지정한 <code>example-client</code>를 <code>config</code>하위로 작성하고, <code>connectionTimeout</code>과 <code>readTimeout</code> 시간을 지정하면 된다.</p>
<pre><code class="language-yml">feign:
  client:
    config:
      default:
        connectTimeout: 30000
        readTimeout: 30000
      example-client:
        connectTimeout: 5000
        readTimeout: 5000</code></pre>
<h1 id="주의사항">주의사항</h1>
<p>별도로 설정한 timeout시간이 default timeout시간까지 변경되지는 않았는지 테스트를 꼭 해보는게 좋다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Spring] ObjectMapper LocalDateTime 역직렬화 오류]]></title>
            <link>https://velog.io/@dev_yong/Spring-ObjectMapper-LocalDateTime-%EC%97%AD%EC%A7%81%EB%A0%AC%ED%99%94-%EC%98%A4%EB%A5%98</link>
            <guid>https://velog.io/@dev_yong/Spring-ObjectMapper-LocalDateTime-%EC%97%AD%EC%A7%81%EB%A0%AC%ED%99%94-%EC%98%A4%EB%A5%98</guid>
            <pubDate>Thu, 28 Mar 2024 08:22:18 GMT</pubDate>
            <description><![CDATA[<h1 id="오류내용">오류내용</h1>
<p>Spring에서 ObjectMapper로 객체를 JsonString으로 변환하는 도중 오류가 발생했다.</p>
<pre><code>com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Java 8 date/time type `java.time.LocalDateTime` not supported by default: add Module &quot;com.fasterxml.jackson.datatype:jackson-datatype-jsr310&quot; to enable handling (through reference chain: ...)</code></pre><p>해당 오류는 Java8에 추가된 LocalDateTime, DateTime과 같은 날짜/시간 타입이 Jackson library에 지원되지 않아 발생하는 오류이다.</p>
<h1 id="해결방법">해결방법</h1>
<p><code>build.gradle</code>파일에  <a href="https://mvnrepository.com/artifact/com.fasterxml.jackson.datatype/jackson-datatype-jsr310"><code>jackson-datatype-jsr310</code></a> 의존성을 추가해야 한다.
(스프링 부트 2.0부터는 기본으로 포함되어 있기 때문에 스프링 부트 2.0 이상을 사용하고 있다면 추가하지 않아도 된다.)</p>
<pre><code>dependencies {
    implementation &#39;com.fasterxml.jackson.datatype:jackson-datatype-jsr310&#39;
...</code></pre><p>아래 코드와 같이 <code>JavaTimeModule</code>이 포함된 <code>ObjectMapper</code>를 Bean으로 등록하고 사용하면 된다.</p>
<pre><code>@Configuration
public class ModuleConfig {

    @Bean
    public ObjectMapper objectMapper() {
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.registerModule(new JavaTimeModule());
        return objectMapper;
    }
}</code></pre><p>그런데 LocalDateTime을 String으로 파싱했을 때 모양이 영 마음에 들지 않는다.</p>
<pre><code>...&quot;createDateTime&quot;:[2024,3,13,11,6,17,755809000]}</code></pre><p>아래와 같이 JavaTimeModule을 수정하면 원하는 포멧으로 사용할 수 있다.</p>
<pre><code>    MAPPER.registerModule(getJavaTimeModule());


    private static final String DEFAULT_DATE_TIME_FORMAT = &quot;yyyy-MM-dd HH:mm:ss.SSSSSS&quot;;

    private static final String DEFAULT_DATE_FORMAT = &quot;yyyy-MM-dd&quot;;

    private static final String DEFAULT_TIME_FORMAT = &quot;HH:mm:ss&quot;;

    /**
     * Could not read JSON: Java 8 date/time type `java.time.LocalDate` not supported by default: add
     * Module &quot;com.fasterxml.jackson.datatype:jackson-datatype-jsr310&quot; to enable handling 관련 오류 대응
     */
    private static JavaTimeModule getJavaTimeModule() {
        var module = new JavaTimeModule();
        module.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(
                DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT)));
        module.addSerializer(LocalDate.class,
                new LocalDateSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT)));
        module.addSerializer(LocalTime.class,
                new LocalTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)));
        module.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(
                DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT)));
        module.addDeserializer(LocalDate.class,
                new LocalDateDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT)));
        module.addDeserializer(LocalTime.class,
                new LocalTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)));
        return module;
    }</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[Spring devtools classLoader 오류]]></title>
            <link>https://velog.io/@dev_yong/Spring-devtools-classLoader-%EC%98%A4%EB%A5%98</link>
            <guid>https://velog.io/@dev_yong/Spring-devtools-classLoader-%EC%98%A4%EB%A5%98</guid>
            <pubDate>Thu, 23 Nov 2023 01:49:52 GMT</pubDate>
            <description><![CDATA[<h1 id="현상">현상</h1>
<p>Local에서 Spring Project API호출시 다음와 같은 오류가 발생했다.</p>
<pre><code class="language-json">{
    &quot;timestamp&quot;: 1696997788477,
    &quot;status&quot;: 500,
    &quot;error&quot;: &quot;Internal Server Error&quot;,
    &quot;message&quot;: &quot;loader constraint violation: when resolving method &#39;***.***.***.***.request.SignInRequest$SignInRequestBuilder ***.***.***.signin.request.SignInRequest$SignInRequestBuilder.snsType(***.***.***.enums.SnsType)&#39; the class loader org.springframework.boot.devtools.restart.classloader.RestartClassLoader @30c4828b of the current class, ***/***/***/login/mapper/LoginMapperImpl, and the class loader &#39;app&#39; for the method&#39;s defining class, ***/***/***/signin/request/SignInRequest$SignInRequestBuilder, have different Class objects for the type ***/***/***/enums/SnsType used in the signature (***.****.***.login.mapper.LoginMapperImpl is in unnamed module of loader org.springframework.boot.devtools.restart.classloader.RestartClassLoader @30c4828b, parent loader &#39;app&#39;; ***.***.***.signin.request.SignInRequest$SignInRequestBuilder is in unnamed module of loader &#39;app&#39;)&quot;,
    &quot;path&quot;: &quot;/member/login&quot;
}</code></pre>
<hr>
<h1 id="원인">원인</h1>
<pre><code class="language-json">loader constraint violation: when resolving method &#39;***.***.***.signin.request.SignInRequest$SignInRequestBuilder ***.***.***.signin.request.SignInRequest$SignInRequestBuilder.snsType(***.***.common.enums.SnsType)&#39; the class loader org.springframework.boot.devtools.restart.classloader.RestartClassLoader @30c4828b of the current class, ***/***/***/login/mapper/LoginMapperImpl, and the class loader &#39;app&#39; for the method&#39;s defining class, ***/***/***/signin/request/SignInRequest$SignInRequestBuilder, have different Class objects for the type ***/***/common/enums/SnsType used in the signature (***.***.***.login.mapper.LoginMapperImpl is in unnamed module of loader org.springframework.boot.devtools.restart.classloader.RestartClassLoader @30c4828b, parent loader &#39;app&#39;; ***.***.***.signin.request.SignInRequest$SignInRequestBuilder is in unnamed module of loader &#39;app&#39;)&quot;
</code></pre>
<p>devtools에서 base class loader와 restart class loader 2개의 클래스 로더가 있고 application에서 개발된 클래스는 restart class loader를 사용한다.</p>
<p>기본적으로 IDE에서 open한 프로젝트는 restart loader가 load하고 .jar class들은 class loader가 로드한다.</p>
<p>멀티모듈 프로젝트이거나 해당 프로젝트의 모든 모듈이 IDE에서 open한게 아니라면 수정이 필요할 수 있다.</p>
<hr>
<h1 id="해결방법">해결방법</h1>
<p>아래 방법 중에서 선택하여 해결할 수 있다.</p>
<ol>
<li>devtools을 제거<pre><code># build.gradle
</code></pre></li>
</ol>
<p>dependencies {
    // developmentOnly &#39;org.springframework.boot:spring-boot-devtools&#39;
}</p>
<pre><code>
2. `META-INF/spring-devtools.properties` 파일을 생성하여 restart class loader 설정
```bash
restart:
  exclude:
    companycommonlibs: &quot;/mycorp-common-[\\w\\d-\\.]+\\.jar&quot;
  include:
    projectcommon: &quot;/mycorp-myproj-[\\w\\d-\\.]+\\.jar&quot;</code></pre><ol start="3">
<li>devtools Restart 비활성화</li>
</ol>
<pre><code class="language-java">@SpringBootApplication
public class MyApplication {
    public static void main(String[] args) {
        System.setProperty(&quot;spring.devtools.restart.enabled&quot;, &quot;false&quot;);
        SpringApplication.run(MyApplication.class, args);
    }
}</code></pre>
<hr>
<h1 id="주의사항">주의사항</h1>
<ul>
<li>DevTools는 기본적으로 개발시에만 사용되며, prod환경에서는 사용되지 않는다.</li>
<li>VM 옵션에 -Dspring.devtools.restart.enabled=true를 줘서 프로덕션 레벨에서도 켤 수 있다.</li>
<li>프로덕션 레벨에서 spring-boot-devtools를 켜면 보안상의 취약점이 생길 수 있음으로 켜지 않는 것을 권장</li>
<li>-Dspring.devtools.restart.enabled=false로 확실히 끌 수 있다.</li>
</ul>
<hr>
<h3 id="참고문서">참고문서</h3>
<p><a href="https://docs.spring.io/spring-boot/docs/current/reference/html/using.html#using.devtools.restart.customizing-the-classload">https://docs.spring.io/spring-boot/docs/current/reference/html/using.html#using.devtools.restart.customizing-the-classload</a></p>
<p><a href="https://docs.spring.io/spring-boot/docs/1.5.16.RELEASE/reference/html/using-boot-devtools.html">https://docs.spring.io/spring-boot/docs/1.5.16.RELEASE/reference/html/using-boot-devtools.html</a></p>
<p><a href="https://jake-seo-dev.tistory.com/60#Restart-%EF%BF%BD%-E%EF%BF%BD%EF%BF%BD%-B%-C%EF%BF%BD%-E%---%--%EF%BF%BD%B-%--%EF%BF%BD%--%-C%EF%BF%BD%--%B-%EF%BF%BD%--%--%EF%BF%BD%--%--%EF%BF%BD%B-%B-">https://jake-seo-dev.tistory.com/60#Restart-�%-E��%-B%-C�%-E%---%--�%B-%--�%--%-C�%--%B-�%--%--�%--%--�%B-%B-</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[PKIX path building failed]]></title>
            <link>https://velog.io/@dev_yong/PKIX-path-building-failed</link>
            <guid>https://velog.io/@dev_yong/PKIX-path-building-failed</guid>
            <pubDate>Fri, 17 Mar 2023 02:08:21 GMT</pubDate>
            <description><![CDATA[<p>SpringBoot에서 feignClient를 사용해 외부 API를 호출하니 아래와 같은 오류가 발생했다.</p>
<pre><code>https Error - PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException</code></pre><h2 id="원인">원인</h2>
<p>대부분의 원인은 연결하려는 site의 인증서가 JVM의 신뢰하는 인증서 목록에 없는 경우이다.</p>
<hr>
<h2 id="해결방법">해결방법</h2>
<p>문제되는 사이트의 SSL인증서를 추출해서 등록하면 해결된다.</p>
<h4 id="1-installcertjava-다운로드">1. InstallCert.java 다운로드</h4>
<p><a href="https://github.com/lesstif">lesstif</a>님의 gist에서 다운로드 받았고 다른 경로에서 다운로드 받아도 된다.</p>
<pre><code class="language-bash">curl -O https://gist.githubusercontent.com/lesstif/cd26f57b7cfd2cd55241b20e05b5cd93/raw/InstallCert.java</code></pre>
<h4 id="2-다운로드-받은-코드를-컴파일">2. 다운로드 받은 코드를 컴파일</h4>
<pre><code class="language-bash">javac InstallCert.java</code></pre>
<h4 id="3-연결하려는-사이트-도메인을-포함하여-실행">3. 연결하려는 사이트 도메인을 포함하여 실행</h4>
<pre><code class="language-bash">java -cp ./ InstallCert test.com</code></pre>
<pre><code class="language-bash">Loading KeyStore jssecacerts...
Opening connection to test.com:443...
Starting SSL handshake...

javax.net.ssl.SSLHandshakeException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
    at java.base/sun.security.ssl.Alert.createSSLException(Alert.java:131)
    at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:353)
    at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:296)
    at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:291)
    at java.base/sun.security.ssl.CertificateMessage$T13CertificateConsumer.checkServerCerts(CertificateMessage.java:1357)
    at java.base/sun.security.ssl.CertificateMessage$T13CertificateConsumer.onConsumeCertificate(CertificateMessage.java:1232)
    at java.base/sun.security.ssl.CertificateMessage$T13CertificateConsumer.consume(CertificateMessage.java:1175)
    at java.base/sun.security.ssl.SSLHandshake.consume(SSLHandshake.java:392)
    at java.base/sun.security.ssl.HandshakeContext.dispatch(HandshakeContext.java:443)
    at java.base/sun.security.ssl.HandshakeContext.dispatch(HandshakeContext.java:421)
    at java.base/sun.security.ssl.TransportContext.dispatch(TransportContext.java:183)
    at java.base/sun.security.ssl.SSLTransport.decode(SSLTransport.java:172)
    at java.base/sun.security.ssl.SSLSocketImpl.decode(SSLSocketImpl.java:1506)
    at java.base/sun.security.ssl.SSLSocketImpl.readHandshakeRecord(SSLSocketImpl.java:1416)
    at java.base/sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:456)
    at java.base/sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:427)
    at InstallCert.main(InstallCert.java:116)
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
    at java.base/sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:439)
    at java.base/sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:306)
    at java.base/sun.security.validator.Validator.validate(Validator.java:264)
    at java.base/sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:313)
    at java.base/sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:233)
    at java.base/sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:110)
    at InstallCert$SavingTrustManager.checkServerTrusted(InstallCert.java:199)
    at java.base/sun.security.ssl.AbstractTrustManagerWrapper.checkServerTrusted(SSLContextImpl.java:1510)
    at java.base/sun.security.ssl.CertificateMessage$T13CertificateConsumer.checkServerCerts(CertificateMessage.java:1341)
    ... 12 more
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
    at java.base/sun.security.provider.certpath.SunCertPathBuilder.build(SunCertPathBuilder.java:141)
    at java.base/sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:126)
    at java.base/java.security.cert.CertPathBuilder.build(CertPathBuilder.java:297)
    at java.base/sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:434)
    ... 20 more

Server sent 2 certificate(s):

 1 Subject CN=*.test.com
   Issuer  CN=Symantec CA, O=***, L=Seoul, ST=Seoul, C=KR
   sha1    50 40 9c e4 8d ae 8e 51 a2 16 96 f8 cb bd 61 55 04 4a 13 2a
   md5     52 99 43 a8 1b a8 5e 6c 3e ae ba 4f 57 bc ed 43

 2 Subject CN=Symantec CA, O=***, L=Seoul, ST=Seoul, C=KR
   Issuer  CN=Symantec CA, O=***, L=Seoul, ST=Seoul, C=KR
   sha1    97 fe 03 0c 78 ce 02 c9 a8 e3 c8 4b e8 76 f6 fd 85 b1 a9 63
   md5     bc 40 06 6d ff 9c c4 3f 24 8c bf ca cc f6 f7 e6

Enter certificate to add to trusted keystore or &#39;q&#39; to quit: [1]</code></pre>
<h4 id="4-2개의-인증서-중-두번째-인증서를-선택하여-저장한다">4. 2개의 인증서 중 두번째 인증서를 선택하여 저장한다.</h4>
<pre><code class="language-bash">Enter certificate to add to trusted keystore or &#39;q&#39; to quit: [1]
2</code></pre>
<h4 id="5-아래와-같은-메세지가-출력되는데-keystorejssecacerts값과--aliastestcom-2를-기억하거나-저장한다">5. 아래와 같은 메세지가 출력되는데 <code>keystore</code>(jssecacerts)값과  <code>alias</code>(test.com-2)를 기억하거나 저장한다.</h4>
<pre><code class="language-bash">Added certificate to keystore &#39;jssecacerts&#39; using alias &#39;test.com-2&#39;</code></pre>
<h4 id="6-keystore파일-jssecacerts에-있는-인증서를-outputcert라는-파일로-저장">6. keystore파일 jssecacerts에 있는 인증서를 output.cert라는 파일로 저장</h4>
<pre><code>keytool -exportcert -keystore jssecacerts -storepass changeit -file output.cert -alias test.com-2</code></pre><h4 id="7-jvm의-keystore에-인증서를-추가">7. jvm의 keystore에 인증서를 추가</h4>
<pre><code>sudo  keytool -importcert -keystore ${JAVA_HOME}/lib/security/cacerts -storepass changeit -file output.cert -alias letsencrypt</code></pre><pre><code>소유자: CN=*.test.com
발행자: CN=Symantec CA, O=*****, L=Seoul, ST=Seoul, C=KR
일련 번호: 9d0ff9bc92058720082601b3fc857587
적합한 시작 날짜: Mon Oct 24 01:42:17 KST 2022 종료 날짜: Sat Nov 25 01:42:16 KST 2023
인증서 지문:
     SHA1: 50:40:9C:E4:8D:AE:8E:51:A2:16:96:F8:CB:BD:61:55:04:4A:13:2A
     SHA256: 60:FE:80:32:76:A0:22:D9:A3:80:80:78:8C:E4:48:3E:C3:AE:D9:8B:67:84:9A:58:07:C6:1C:13:C8:B0:D4:38
서명 알고리즘 이름: SHA256withRSA
주체 공용 키 알고리즘: 2048비트 RSA 키
버전: 3

확장:

#1: ObjectId: 2.5.29.17 Criticality=false
SubjectAlternativeName [
  DNSName: *.test.com
]

이 인증서를 신뢰합니까? [아니오]:  y
인증서가 키 저장소에 추가되었습니다.</code></pre><p>인증서 키가 저장되고 서버 restart를 하면 정상적으로 실행된다.</p>
<h2 id="ref">Ref</h2>
<p><a href="https://github.com/lesstif">https://github.com/lesstif</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[.gitignore가 적용되지 않을 때(git 캐시 삭제하기)]]></title>
            <link>https://velog.io/@dev_yong/.gitignore%EA%B0%80-%EC%A0%81%EC%9A%A9%EB%90%98%EC%A7%80-%EC%95%8A%EC%9D%84-%EB%95%8Cgit-%EC%BA%90%EC%8B%9C-%EC%82%AD%EC%A0%9C%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@dev_yong/.gitignore%EA%B0%80-%EC%A0%81%EC%9A%A9%EB%90%98%EC%A7%80-%EC%95%8A%EC%9D%84-%EB%95%8Cgit-%EC%BA%90%EC%8B%9C-%EC%82%AD%EC%A0%9C%ED%95%98%EA%B8%B0</guid>
            <pubDate>Tue, 12 Apr 2022 06:59:49 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/dev_yong/post/a7d089d0-30c8-417e-96e9-392e70ff9851/image.png" alt=""></p>
<h1 id="gitignore">.gitignore</h1>
<p>프로젝트를 깃허브 public저장소에 커밋할 때 각종 인증 키값이나 서버정보, DB정보를 입력한 파일들은 커밋하면 안된다.</p>
<p>public에 커밋하게되면 내 서버가 어느새 누군가의 비트코인 채굴기가 되어 다음 달 AWS로부터 어마무시한 과금 청구서가 날아올 수 있다.</p>
<p>중요한 정보가 담긴 파일은 <code>.gitignore</code>에 등록하여 커밋되지 않도록 설정한다.</p>
<h1 id="그래서-gitignore에-등록했는데-왜-커밋목록에-올라오는거지">그래서 .gitignore에 등록했는데 왜 커밋목록에 올라오는거지?</h1>
<p><code>.gitignore</code>에 파일을 추가했는데 추가한 파일이 계속 커밋목록에 있는 경우가 있다.</p>
<p><code>.gitignore</code>에 파일을 추가하기 전에 stage에 올라간 파일들은 캐시가 남아 있어 커밋목록에 자꾸 뜨는 것이다.</p>
<h3 id="캐시를-제거하기-위해서는-해당-디렉토리로-이동-후-아래와-같이-명령어를-입력해주면-된다">캐시를 제거하기 위해서는 해당 디렉토리로 이동 후 아래와 같이 명령어를 입력해주면 된다.</h3>
<pre><code class="language-bash">// 캐시를 모두 삭제
git rm -r --cached .

// .gitignore에 입력된 파일 목록을 제외한 다른 모든 파일을 다시 트래킹
git add .

// 커밋
git commit -m &quot;clear git cache&quot;</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[배포전략]]></title>
            <link>https://velog.io/@dev_yong/%EB%B0%B0%ED%8F%AC%EC%A0%84%EB%9E%B5</link>
            <guid>https://velog.io/@dev_yong/%EB%B0%B0%ED%8F%AC%EC%A0%84%EB%9E%B5</guid>
            <pubDate>Wed, 06 Apr 2022 16:07:12 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/cloudflare/dev_yong/629a78c4-adf1-4d04-ba16-c318f6e26d06/img1.daumcdn-3.png" alt=""></p>
<h1 id="배포전략">배포전략</h1>
<p>과거에는 배포라는 작업이 아주 큰 이벤트였다. 하지만 최근에는 유연한 아케텍쳐 설계로 이전보다 더 자주 배포를 하게된다. 이러한 과정에서 배포전략들이 다양하게 발전해왔는데 가장 대표적인 배포전략 몇가지만 소개해보겠다.</p>
<hr>
<h1 id="recreate">Recreate</h1>
<p><img src="https://velog.velcdn.com/cloudflare/dev_yong/fb811048-fc77-4067-aa13-ca373a77e78f/img1.daumcdn-4.png" alt="">
모든 서버를 중지하고 새로운 버전으로 배포한 후 다시 서비스를 올리는 방법이다.
다운타임이 발생하는 배포전략이기 때문에 테스트서버 및 서비스가 중단되어도 문제가 없는 서버등에서 사용한다.
일반적으로 사용되는 배포전략은 아니다.</p>
<hr>
<h1 id="rolling">Rolling</h1>
<p><img src="https://velog.velcdn.com/cloudflare/dev_yong/19c8aa2e-f155-4d22-b46f-229eb2b621df/img1.daumcdn-5.png" alt="">
가장 일반적이며, 많이 사용하는 배포 방법이다.
여러대의 서버가 있을 때 새로운 버전의 서비스를 서버마다 순차적으로 배포한다.</p>
<h2 id="장점">장점</h2>
<ul>
<li>서버를 점차적으로 배포하는 방식으로, 서버 자원이 한정적인 경우 유리하다.(서버자원이 2배가 필요한 <code>Blue/Green</code> 배포방식에 비해 유리하다.)</li>
<li>배포관리가 다른 전략에 비해 비교적 간단하다.</li>
<li>Downtime이 없다.</li>
</ul>
<h2 id="단점-및-주의해야-할-점">단점 및 주의해야 할 점</h2>
<ul>
<li>배포중에는 구버전과 신버전이 공존하게 됨으로, 두 버전이 공존해도 문제가 생기지 않도록 주의하여 개발해야한다. (예를들어 DB에 대한 수정이 있을 경우)</li>
<li>배포중인 서버는 서비스가 중단된 상태이다. 그러므로 서버 부하량을 체크하면서 배포를 진행해야한다. 예를 들어 특가 및 이벤트 진행으로 서버의 부하량이 늘어난 상태에서 배포를 시작하게 되면 나머지 자원에 부하량이 늘어나 서비스가 마비될 수 있다.</li>
</ul>
<hr>
<h1 id="bluegreen">Blue/Green</h1>
<p><img src="https://velog.velcdn.com/cloudflare/dev_yong/5e36fc1d-508a-4580-8413-4a334f6c6278/img1.daumcdn-6.png" alt="">
<code>blue</code>는 구버전 <code>green</code>은 신버전을 의미하여 붙여진 이름이다.</p>
<p>새로운 버전을 모두 배포한 뒤에 <code>L4</code>에서 모두 새로운 버전의 서버로 유입되도록 하는 배포전략이다.</p>
<h2 id="장점-1">장점</h2>
<ul>
<li>Downtime 최소화 가능하다.</li>
<li>신규 버전에 문제 발생시 빠른 rollback이 가능하다. 문제가 발생되면 이전버전의 서버로 유입되도록 변경하여 빠르게 이전버전으로 서비스를 돌릴 수 있다.</li>
</ul>
<h2 id="단점-및-주의해야-할-점-1">단점 및 주의해야 할 점</h2>
<ul>
<li>구버전 신버전을 모두 갖추어야함으로 서버 리소스가 2배로 필요하다.</li>
<li>배포할 떄 구버전 서버에서 트랜잭션이 긴 처리와 같은 기능이 있다면 신서버로 전환되는 경우를 어떻게 처리해야할지 고려해야한다.</li>
<li>기존 운영되고 있는 서버에서 <code>Long-term 트랜잭션</code>이 수행중이었다면 전환시 어떤 방식으로 처리할 지 충분한 고려가 필요하다.</li>
<li>두 서버 환경간 migration이 배포때 마다 필요하며, Rollback 수행시에도 고려해야 한다</li>
</ul>
<hr>
<h1 id="canary">Canary</h1>
<p><img src="https://velog.velcdn.com/cloudflare/dev_yong/8e564651-d0db-45c6-8a7d-b995c9e29769/img1.daumcdn-7.png" alt="">
빠르게 위험을 감지할 수 있는 배포전략이다.
특정 서버에만 선 배포를 진행하여 오류 여부를 확인하고 문제가 없다고 판단되면 모든 서버에 새로운 버전으로 배포하는 방식이다.</p>
<p>디즈니의 트위티로 많이들 알고 있는 카나리라는 새는 유독가스에 취약하다고 한다.
그래서 옛날 광부들은 광산에서 유독가스가 나오는 것을 알기 위해 카나리를 광산 안에서 키웠다고 한다. 카나리가 세상을 떠나면 유독가스나 나오는것으로 보고 대피를 했다고 하는데, 이 개념에서 카나리 배포 전략이라는 이름이 붙여졌다.</p>
<h2 id="장점-2">장점</h2>
<ul>
<li><code>A/B 테스트</code>가 가능하다</li>
<li>오류를 감지하는데 효과적이다. (특정 서버에만 배포하기 떄문에 문제 발생시 리스크가 적다.)</li>
<li>문제 발생시 선배포한 서버만 롤백하면 됨으로 롤백이 비교적 간단하다.</li>
</ul>
<h2 id="단점-및-주의해야-할-점-2">단점 및 주의해야 할 점</h2>
<ul>
<li>두가지 버전을 동시에 관리해야한다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[반복되는 코드작업을 해결해주는 코드 다이어터 Lombok
]]></title>
            <link>https://velog.io/@dev_yong/%EB%B0%98%EB%B3%B5%EB%90%98%EB%8A%94-%EC%BD%94%EB%93%9C%EC%9E%91%EC%97%85%EC%9D%84-%ED%95%B4%EA%B2%B0%ED%95%B4%EC%A3%BC%EB%8A%94-%EC%BD%94%EB%93%9C-%EB%8B%A4%EC%9D%B4%EC%96%B4%ED%84%B0-Lombok</link>
            <guid>https://velog.io/@dev_yong/%EB%B0%98%EB%B3%B5%EB%90%98%EB%8A%94-%EC%BD%94%EB%93%9C%EC%9E%91%EC%97%85%EC%9D%84-%ED%95%B4%EA%B2%B0%ED%95%B4%EC%A3%BC%EB%8A%94-%EC%BD%94%EB%93%9C-%EB%8B%A4%EC%9D%B4%EC%96%B4%ED%84%B0-Lombok</guid>
            <pubDate>Wed, 06 Apr 2022 15:48:56 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/cloudflare/dev_yong/16d58c5f-c351-4431-ac81-cadbdcb567e3/img1.daumcdn.png" alt=""></p>
<h1 id="lombok으로-코드-다이어트-하기">Lombok으로 코드 다이어트 하기</h1>
<p>Lombok은 Java기반에서 <code>VO</code>, <code>DTO</code>, <code>Entity</code>클래스를 생성할 때 반복적으로 작성하는 <code>getter</code>, <code>setter</code>, <code>toString</code>과 같은 작업들을 어노테이션을 사용하여 보다 더 간편하게 개발할 수 있게 도와주는 라이브러리이다.</p>
<h2 id="lombok의-장점">Lombok의 장점</h2>
<ol>
<li>반복되는 코드를 줄여줌으로 코드의 가독성이 좋아진다.</li>
<li>반복되는 코드를 줌여줌으로 생산성이 증가한다.</li>
<li><code>JPA</code>를 사용하고 있는 경우 <code>JPA</code>환경과 일관화됨으로 가독성이 좋은 코드를 작성할 수 있다.</li>
</ol>
<h2 id="lombok의-단점">Lombok의 단점</h2>
<ol>
<li>모든 협업 인원이 Lombok의 설치해야한다.</li>
<li>@Data @ToString어노테이션으로 자동 생성되는 toString()메서드의 순환참조, 재귀호출 문제로 스택오버플로우가 발생할 수 있다. (자세한 내용은 <a href="https://kwonnam.pe.kr/wiki/java/lombok/pitfall" target="_blank">권남님의 블로그 참고</a>)</li>
</ol>
<hr>
<h1 id="설치방법">설치방법</h1>
<p>다양한 IDE를 지원하지만 가장 많이 사용하는 <code>Eclipse</code>와 <code>IntelliJ</code> 두 IDE의 설치방법에 대해 알아보겠다. (사실 내가 이 두가지 IDE를 사용한다.)</p>
<p>다른 IDE의 설치방법을 알고싶다면 <a href="https://projectlombok.org/" target="_blank" >공식홈페이지</a>의 [Install] 탭에 자세하게 설명되어있다.</p>
<h2 id="eclipse">Eclipse</h2>
<p><a href="https://projectlombok.org/setup/eclipse" target="_blank">롬복 공식사이트</a>에서 파일을 다운받고 실행시키면 아래와 같은 화면이 나오고 내 PC에 설치되있는 IDE를 선택하고 &quot;install/Update&quot;버튼을 눌러 설치를 하면 된다.
(<code>Eclipse</code> 실행한 상태에서 설치를 했다면 재시작을 해야한다.)
<img src="https://velog.velcdn.com/cloudflare/dev_yong/12c2c408-217a-47c0-8fce-248789491ee1/img1.daumcdn-2.png" alt=""></p>
<h2 id="intellij">IntelliJ</h2>
<p><code>IntelliJ</code> Lombok은 설치방법은 비교적 간단하다.
Preferences &gt; Plugins &gt; Browse repositories.. &gt; Lombok 검색 &gt; Install &gt; restart
<img src="https://velog.velcdn.com/cloudflare/dev_yong/40208a19-f409-40c1-b9b9-1d4487646575/img1.daumcdn-1.png" alt=""></p>
<hr>
<h1 id="build">Build</h1>
<p>설치를 마친 후에 프로젝트에 적용되어 있는 빌드 방식에 따라 lombok을 추가해준다.</p>
<h2 id="maven">Maven</h2>
<pre><code class="language-xml">&lt;dependency&gt;
    &lt;groupId&gt;org.projectlombok&lt;/groupId&gt;
    &lt;artifactId&gt;lombok&lt;/artifactId&gt;
    &lt;version&gt;1.18.12&lt;/version&gt;
    &lt;scope&gt;provided&lt;/scope&gt;
&lt;/dependency&gt;</code></pre>
<h2 id="gradle">Gradle</h2>
<pre><code class="language-gradle">repositories {
    mavenCentral()
}

dependencies {
    compileOnly &#39;org.projectlombok:lombok:1.18.12&#39;
    annotationProcessor &#39;org.projectlombok:lombok:1.18.12&#39;

    testCompileOnly &#39;org.projectlombok:lombok:1.18.12&#39;
    testAnnotationProcessor &#39;org.projectlombok:lombok:1.18.12&#39;
}</code></pre>
<hr>
<h1 id="사용방법">사용방법</h1>
<p><code>VO</code>, <code>DTO</code>클래스를 생성할 때 보통 아래와 같이 생성자, <code>getter</code>, <code>setter</code>, <code>toString</code>이 포함되어있는 코드를 작성하게 된다. IDE에서 Generate해주는 편리한 기능이 있지만 인자가 많아질 수록 코드의 양은 늘어나고 가독성 또한 떨어진다.</p>
<h2 id="lombok을-적용하지-않은-코드">Lombok을 적용하지 않은 코드</h2>
<pre><code class="language-java">public class TestVO {
    private long id;
    private String name;
    private String nickName;
    private double weight;
    private double height;

    public TestVO() {}

    public TestVO(long id, String name, String nickName, double weight, double height) {
        this.id = id;
        this.name = name;
        this.nickName = nickName;
        this.weight = weight;
        this.height = height;
    }

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getNickName() {
        return nickName;
    }

    public void setNickName(String nickName) {
        this.nickName = nickName;
    }

    public double getWeight() {
        return weight;
    }

    public void setWeight(double weight) {
        this.weight = weight;
    }

    public double getHeight() {
        return height;
    }

    public void setHeight(double height) {
        this.height = height;
    }

    @Override
    public String toString() {
        return &quot;TestVO{&quot; +
                &quot;id=&quot; + id +
                &quot;, name=&#39;&quot; + name + &#39;\&#39;&#39; +
                &quot;, nickName=&#39;&quot; + nickName + &#39;\&#39;&#39; +
                &quot;, weight=&quot; + weight +
                &quot;, height=&quot; + height +
                &#39;}&#39;;
    }
}</code></pre>
<h2 id="lombok을-적용한-코드">Lombok을 적용한 코드</h2>
<p><code>@Getter</code> <code>@Setter</code> <code>@ToString</code> <code>@NoArgsConstructor</code> <code>@AllArgsConstructor</code> 다섯가지 어노테이션을 사용함으로 코드의 양을 줄일 수 있을 뿐만 아니라 가독성 또한 좋아진다.</p>
<pre><code class="language-java">import lombok.*;

@Getter
@Setter
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class TestVO {
    private long id;
    private String name;
    private String nickName;
    private double weight;
    private double height;
}</code></pre>
<p>위 다섯가지의 어노테이션을 모두 사용할 경우에는 <code>@Data</code> 어노테이션 하나면 더 깔끔하게 적용할 수 있다.
하지만 <code>@Data</code>어노테이션은 가급적 지양하도록 한다.(<a href="https://kwonnam.pe.kr/wiki/java/lombok/pitfall" target="_blank">lombok 사용 시 주의해야 할 점</a>)</p>
<pre><code class="language-java">import lombok.*;

@Data
public class TestVO {
    private long id;
    private String name;
    private String nickName;
    private double weight;
    private double height;
}</code></pre>
<p>이렇게 lombok을 적용하게 되면 작업성과 코드의 가독성 두 가지 이점을 얻을 수 있다.</p>
<hr>
<h1 id="자주-사용되는-어노테이션">자주 사용되는 어노테이션</h1>
<p>lombok에서 자주 사용되는 어노테이션을 정리해본다.</p>
<h2 id="접근자--설정자-자동-생성-관련-annotation">접근자 / 설정자 자동 생성 관련 Annotation</h2>
<h3 id="getter와-setter">@Getter와 @Setter</h3>
<p><code>@Getter</code>는 모든 필드에 대해서 <code>getter</code>메서드를 생성해주며, <code>@Setter</code>는 모든 non-final 필드의 <code>setter</code>메서드를 생성해준다.</p>
<h4 id="setter사용시-유의해야-할-점"><code>@Setter</code>사용시 유의해야 할 점</h4>
<p>무분별한 @Setter어노테이션의 사용은 지양한다. Setter는 객체를 언제든지 변경할 수 있는 상태가 되어서 변경되지 않아야할 필드에 @Setter를 적용하는 경우에는 객체의 안전성이 보장받을 수 없다.</p>
<pre><code class="language-java">import lombok.*;

@Getter
@Setter
public class TestVO {
    private long id;
    private String name;
    private String nickName;
    private double weight;
    private double height;
}</code></pre>
<h2 id="생성자-관련-어노테이션">생성자 관련 어노테이션</h2>
<h3 id="noargsconstructor">@NoArgsConstructor</h3>
<p>파라미터가 없는 생성자를 만들어주는 어노테이션이다.</p>
<h3 id="allargsconstructor">@AllArgsConstructor</h3>
<p>모든 필드값을 파라미터로 받는 생성자를 만들어주는 어노테이션이다.</p>
<h3 id="requiredargsconstructor">@RequiredArgsConstructor</h3>
<p>접근제어자 <code>final</code>이나 <code>notNull</code>인 필드값만 받아 생성자를 만들어 주는 어노테이션이다.</p>
<pre><code class="language-java">import lombok.*;

import javax.validation.constraints.NotNull;

@NoArgsConstructor
@AllArgsConstructor
@RequiredArgsConstructor
public class TestVO {
    @NotNull
    private long id;
    private String name;
    private String nickName;
    private double weight;
    private double height;
}</code></pre>
<h2 id="기타">기타</h2>
<h3 id="notnull">@NotNull</h3>
<p><code>@Notnull</code>어노테이션은 <code>Class</code>위에서는 사용이 되지 않는다. <code>Class</code>내 필드값에 직접 사용한다. (위 코드 참고)</p>
<h3 id="builder">@Builder</h3>
<p>클래의 다수의 필드값이 있는 경우 생성자를 만들 때 필드값이 많고 순서 또한 맞춰서 파라미터값을 입력해야 하기 때문에 코딩할 때 불편한 경우가 있다.</p>
<p><code>@Builder</code>어노테이션을 사용하게 되면 자동으로 빌더패턴을 생성해줌으로 작업하는데 많은 도움을 준다.</p>
<pre><code class="language-java">import lombok.*;

import javax.validation.constraints.NotNull;

@Builder
public class TestVO {
    @NotNull
    private long id;
    @NotNull
    private String name;
    private String nickName;
    private double weight;
    private double height;

    // @Builder 적용 예시
    public class BuilderExClass {
        TestVO testVO = TestVO.builder()
                .id(1L)
                .nickName(&quot;nickName&quot;)
                .name(&quot;green&quot;)
                .height(80)
                .height(180)
                .build();
    }
}</code></pre>
<hr>
<p>lombok을 사용하면서 자주 사용되는 어노테이션이 있으면 추가로 작성할 예정이다.</p>
<p>이렇게 lombok어노테이션을 잘 활용하면 작업성과 가독성의 두 마리 토끼를 잡을 수 있게 된다. 하지만 사용할 때 <code>JPA</code>와 같은 <code>ORM</code>등과 같이 사용할 때 발생할 수 있는 오류들에 대해 염두해두고 사용해야한다.</p>
<p>공식 문서도 잘 설명되어 있는 편이라서 참고해보면 좋다.</p>
<blockquote>
<p><a href="https://objectcomputing.com/resources/publications/sett/january-2010-reducing-boilerplate-code-with-project-lombok" target="_blank">Lombok 공식 문서</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[간편하게 ssh접속하기]]></title>
            <link>https://velog.io/@dev_yong/%EA%B0%84%ED%8E%B8%ED%95%98%EA%B2%8C-ssh%EC%A0%91%EC%86%8D%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@dev_yong/%EA%B0%84%ED%8E%B8%ED%95%98%EA%B2%8C-ssh%EC%A0%91%EC%86%8D%ED%95%98%EA%B8%B0</guid>
            <pubDate>Thu, 31 Mar 2022 02:07:23 GMT</pubDate>
            <description><![CDATA[<h1 id="귀찮은-ssh접속">귀찮은 SSH접속</h1>
<p>AWS나 네이버클라우드에서 설치한 클라우드 서버에 ssh접속할 때 아래와 같은 과정을 거친다.</p>
<blockquote>
<p><em>콘솔창 켜고 - 메모장 열고 - 아이피, user-name복사하고 - 콘솔창에 붙여넣고 - 접속</em></p>
</blockquote>
<p>AWS가이드에도 ssh접속방법이 아래와 같이 나와있는데 pem파일 이름 user-name dns또는 ip까지 입력해야한다.</p>
<pre><code># public dns로 접속 
$ ssh -i /path/my-key-pair.pem my-instance-user-name@my-instance-public-dns-name 

# IPv6 주소로 접속 
$ ssh -i /path/my-key-pair.pem my-instance-user-name@my-instance-IPv6-address</code></pre><p><a href="https://docs.aws.amazon.com/ko_kr/AWSEC2/latest/UserGuide/AccessingInstancesLinux.html" target="_blank">[AWS] SSH 클라이언트를 사용하여 Linux 인스턴스에 연결</a></p>
<h1 id="ssh접속-간편하게-하기">SSH접속 간편하게 하기</h1>
<p>아래 방법대로 설정 한번만 해주면 위와 같이 귀찮은 과정을 거치지 않고 간편하게 ssh접속이 가능하다</p>
<pre><code>$ ssh 이름</code></pre><blockquote>
<p>⚠ MAC OS 기준 설정방법입니다.</p>
</blockquote>
<p>.ssh 폴더로 들어가면 <code>known_hosts</code> 파일만 존재한다.</p>
<pre><code class="language-shell">$ cd ~/.ssh
$ ls
known_hosts</code></pre>
<p><code>config</code> 라는 파일이 없다면 파일을 생성해주자</p>
<pre><code class="language-shell">$ touch config
$ vim config</code></pre>
<p>아래 항목을 각각 입력해준다.</p>
<ul>
<li><code>Host</code> : ssh접속시 사용할 이름</li>
<li><code>User</code> : 계정이름</li>
<li><code>IdentityFile</code> : pem또는 private 키</li>
</ul>
<pre><code class="language-shell"># Example 
Host example
    HostName 123.123.123.1 
    User example-user 
    IdentityFile ~/file-path</code></pre>
<p>설정을 완료했다면 아래 간단한 명령어만으로 ssh접속을 할 수 있다.</p>
<pre><code class="language-shell">$ ssh example</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[간단하게 AWS용어들을 정리해보자]]></title>
            <link>https://velog.io/@dev_yong/%EA%B0%84%EB%8B%A8%ED%95%98%EA%B2%8C-AWS%EC%9A%A9%EC%96%B4%EB%93%A4%EC%9D%84-%EC%A0%95%EB%A6%AC%ED%95%B4%EB%B3%B4%EC%9E%90</link>
            <guid>https://velog.io/@dev_yong/%EA%B0%84%EB%8B%A8%ED%95%98%EA%B2%8C-AWS%EC%9A%A9%EC%96%B4%EB%93%A4%EC%9D%84-%EC%A0%95%EB%A6%AC%ED%95%B4%EB%B3%B4%EC%9E%90</guid>
            <pubDate>Mon, 28 Mar 2022 13:54:20 GMT</pubDate>
            <description><![CDATA[<p><img src="https://images.velog.io/images/dev_yong/post/84226ea4-0dc7-4cf4-8bcd-eddef394454d/%EB%8B%A4%EC%9A%B4%EB%A1%9C%EB%93%9C.png" alt=""></p>
<h1 id="기본개념">기본개념</h1>
<h2 id="리전region">리전(Region)</h2>
<ul>
<li>리전은 AWS의 물리적 장소가 있는 지역</li>
<li>한국에도 16년 1월에 서울 리전을 공개했다. (서울리전 코드 : ap-northeast-2)</li>
<li>AWS에서는 지역별 대륙별로 리전들의 <a href="https://status.aws.amazon.com" target="_blank">리소스 상태를 볼 수 있는 링크</a>를 제공한다.</li>
</ul>
<h2 id="가용영역availability-zone">가용영역(Availability Zone)</h2>
<ul>
<li>한개의 리전에는 다수의 가용영역이 있다.</li>
<li>IDC와 같은 개념이다.</li>
<li>한개 리전에 2개 이상의 가용영역이 존재한다.</li>
<li>정전, 자연재해 등 외부 영향이 발생했을 때 한개의 가용영역이 불능상태가 되어도 다른 가용영역을 사용할 수 있다.</li>
<li>L4장비(ELB)로 두개의 가용영역을 로드밸런싱 하면 한개의 가용영역이 불능상태가 되어도 서비스를 유지할 수 있다.</li>
</ul>
<h2 id="엣지-로케이션">엣지 로케이션</h2>
<ul>
<li>리전과 가용영역과는 별개로 AWS에서 서비스하는 캐시서버이다.</li>
<li>CDN(CloudFront),  DNS(Route 53) 서비스가 있다.</li>
</ul>
<hr>
<h1 id="컴퓨팅">컴퓨팅</h1>
<h2 id="ec2elastic-compute-cloud">EC2(Elastic Compute Cloud)</h2>
<ul>
<li>EC2는 인터넷에 연결된 가상서버이다.</li>
<li>간단한 클릭 몇번으로 생성, 삭제가 가능하다.</li>
<li>다양한 운영체제를 지원한다. (Windows, Linux 등)</li>
<li>가상서버임으로 원격으로 접속한다. (ssh)</li>
</ul>
<h2 id="elastic-beanstalk">Elastic Beanstalk</h2>
<ul>
<li>어플리케이션을 코드만으로 빠르고 쉽게 배포하고 서비스할 수 있다.</li>
<li>인프라 지식이 부족해도 서버 설정을 할 수 있다는 장점이 있다.</li>
<li>프로비저닝, 오토스캐일링, 로드밸런싱, 모니터링등을 자동으로 설정해준다.</li>
<li>Go, Java, .NET, Node.js, PHP, Python등의 어플리케이션을 지원한다.</li>
</ul>
<hr>
<h2 id="데이터베이스">데이터베이스</h2>
<h2 id="rdsrelation-database-service">RDS(Relation Database Service)</h2>
<ul>
<li>관계형 데이터베스를 제공하는 서비스이다.</li>
<li>Mysql, Oracle, SQL Server 등 다양한 관계형 데이터베이스를 제공한다.</li>
</ul>
<h2 id="dynamo-db">Dynamo DB</h2>
<ul>
<li>NoSQL DB</li>
<li>아마존에서 개발한 NoSQL 데이터베이스</li>
<li>성능과 가용성을 위해 3곳의 AZ(가용영역)에 복제하여 저장</li>
<li>Dynamo DB의 데이터는 SSD에 저장됨, 읽고쓰기가 빠름</li>
</ul>
<h2 id="elasticache">ElastiCache</h2>
<ul>
<li>인 메모리 데이터 스토어 서비스</li>
</ul>
<hr>
<h1 id="보안-자격-증명-및-규정-준수">보안, 자격 증명 및 규정 준수</h1>
<h2 id="iam">IAM</h2>
<ul>
<li>Identity and Access Management, 식별 및 접근관리</li>
<li>AWS리소르에 대한 접근을 안전하게 제어할 수 있게 하는 서비스</li>
<li>관리 및 보안설정</li>
</ul>
<hr>
<h1 id="관리-및-거버넌스">관리 및 거버넌스</h1>
<h2 id="auto-scaling">Auto Scaling</h2>
<ul>
<li>자동으로 EC2서버를 증설해주는 서비스</li>
<li>클라우드의 가장 큰 장점 중 하나</li>
<li>트래픽이 급격하게 늘어나면 자동으로 EC2서버를 증설하여 서비스 확장</li>
<li>반대로 트래픽이 적을떄는 EC2인스턴스를 줄일 수 있음</li>
<li>프로모션이나 이벤트시에 사용</li>
<li>ELB서비스를 사용함</li>
<li>Cloud Watch(모니터링)과 연동하여 인스턴스의 증설,삭제를 설정</li>
</ul>
<h2 id="cloudformation">CloudFormation</h2>
<ul>
<li>AWS리소스를 자동으로 생성해주는 서비스</li>
<li>AWS 리소스를 템플릿 파일로 작성하면, CloudFormation이 이를 분석해서 AWS 리소스를 생성</li>
<li>템플릿은 JSON, YAML로 만들 수 있다.</li>
<li>서비스확장에 이점이 있음</li>
<li>실서버, 스테이지, 개발서버를 비슷한 환경으로 운영하기 용이함</li>
<li>별도의 요금은 부과되지 않음</li>
</ul>
<h2 id="cloudwatch">CloudWatch</h2>
<ul>
<li>AWS의 리소스 상태를 모니터링 하는 서비스</li>
<li>Auto Scaling에 사용됨</li>
<li>프리티어에서 사용 가능</li>
</ul>
<h2 id="opsworks">OpsWorks</h2>
<ul>
<li>모든 어플리케이션의 구성과 배포를 자동화해주는 서비스</li>
<li>Beanstalk보다는 자유도가 높음(세세한 설정 가능)</li>
<li>CloudFormation보다는 자동화 되어 있음</li>
<li>별도의 요금은 없음</li>
</ul>
<hr>
<h1 id="네트워킹-및-콘텐츠-전송">네트워킹 및 콘텐츠 전송</h1>
<h2 id="cloud-front">Cloud Front</h2>
<ul>
<li>CDN 서비스</li>
<li>html, css, js, 이미지 파일과 같은 정작 및 동적 콘텐츠를 빠르게 배포하는 서비스</li>
<li>엣지로케이션이라고 하는 전세계 네트워크를 통해 제공</li>
<li>프리티어에서 사용 가능</li>
</ul>
<h2 id="elbelastic-load-balancing">ELB(Elastic Load Balancing)</h2>
<ul>
<li>L4장비</li>
<li>부하 분산 서비스</li>
<li>고가의 L4장비를 저렴하게 사용 가능</li>
<li>라운드로빈 알고리즘을 사용함(우선순위를 두지 않고 분배)</li>
<li>헬스체크 기능, EC2인스턴스가 중단되면 트래픽 분배에서 제외</li>
<li>Auto Scaling을 구축할 때 사용됨</li>
</ul>
<h2 id="route-53">Route 53</h2>
<ul>
<li>DNS서비스</li>
<li>도메인 구입 가능</li>
</ul>
<h2 id="vpc">VPC</h2>
<ul>
<li>AWS의 가상 네트워크(네트워크 계층)</li>
<li>AWS가입시 자동으로 생성됨</li>
<li>공개 서브넷, 사설서브넷(VPN)을 구축할 수 있음</li>
<li>VPN은 별도의 비용 부과됨</li>
</ul>
<h2 id="security-group">Security Group</h2>
<ul>
<li>방화벽 서비스</li>
<li>EC2에 적용하는 방화벽 서비스</li>
<li>인바운드, 아웃바운드 설정</li>
</ul>
<hr>
<h1 id="미디어-서비스">미디어 서비스</h1>
<h2 id="elastic-transcoder">Elastic Transcoder</h2>
<ul>
<li>동영상 인코딩 서비스</li>
<li>재생 디바이스에 필요한 형식의 미디어 파일로 변환가능</li>
<li>모바일 장치, 태블릿, 웹 브라우저 및 연결된 TV에서 재생할 수 있는 형식으로 변환</li>
</ul>
<hr>
<h1 id="프런트-엔드-웹-및-모바일">프런트 엔드 웹 및 모바일</h1>
<h2 id="sns">SNS</h2>
<ul>
<li>Simple Notification Service</li>
<li>애플리케이션 간(A2A) 및 애플리케이션과 사용자 간(A2P) 통신 모두를 위한 완전관리형 메시징 서비스</li>
<li>SMS, 모바일 푸시 및 이메일을 통해 대규모로 사용자에게 메시지를 전송가능</li>
</ul>
<hr>
<h1 id="분석">분석</h1>
<h2 id="cloudsearch">CloudSearch</h2>
<ul>
<li>AWS 검색엔진 솔루션</li>
<li>34개 언어 지원</li>
</ul>
<hr>
<h1 id="애플리케이션-통합">애플리케이션 통합</h1>
<h2 id="sns-1">SNS</h2>
<ul>
<li>Simple Notification Service </li>
<li>애플리케이션 간(A2A) 및 애플리케이션과 사용자 간(A2P) 통신 모두를 위한 완전관리형 메시징 서비스 </li>
<li>SMS, 모바일 푸시 및 이메일을 통해 대규모로 사용자에게 메시지를 전송가능</li>
</ul>
<h2 id="sqs">SQS</h2>
<ul>
<li>Simple Queue Service</li>
<li>메시지 대기열 서비스</li>
<li>해야 할 일을 나중에 처리하거나, 다른 시스템이 처리 할 수 있도록 하기 위한 비동기 메시징 서비스</li>
</ul>
<hr>
<h1 id="비즈니스-애플리케이션">비즈니스 애플리케이션</h1>
<h2 id="ses">SES</h2>
<ul>
<li>Simple Email Service</li>
<li>대량 이메일 전송 서비스</li>
<li>메일서버 구축 및 스팸차단에 자유로움</li>
</ul>
<h3 id="참고">참고</h3>
<blockquote>
<p><a href="https://docs.aws.amazon.com/ko_kr/">https://docs.aws.amazon.com/ko_kr/</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[CRLF와 LF차이의 이해]]></title>
            <link>https://velog.io/@dev_yong/CRLF%EC%99%80-LF%EC%B0%A8%EC%9D%B4%EC%9D%98-%EC%9D%B4%ED%95%B4</link>
            <guid>https://velog.io/@dev_yong/CRLF%EC%99%80-LF%EC%B0%A8%EC%9D%B4%EC%9D%98-%EC%9D%B4%ED%95%B4</guid>
            <pubDate>Mon, 28 Mar 2022 13:34:43 GMT</pubDate>
            <description><![CDATA[<p><img src="https://images.velog.io/images/dev_yong/post/d9284e96-ba01-404b-8753-c0c4d8a19491/typewriter-g04e98173e_1920.jpg" alt=""></p>
<h1 id="왜-lf를-사용하라고-하는가">왜 LF를 사용하라고 하는가?</h1>
<p>개발을 하면서 협업을 할 때 Code Convention을 맞추기 위해 Check Style을 사용한다.
Check Style파일을 열어보면 줄바꿈 타입을 체크하는 부분이 있고, 줄바꿈 시 CRLF는 금지하고 LF는 허용하도록 설정되어있다.
아래는 네이버에서 제공하는 <code>check style</code> xml파일이다. </p>
<pre><code>&lt;module name = &quot;Checker&quot;&gt;
    &lt;property name=&quot;severity&quot; value=&quot;warning&quot;/&gt;
    &lt;property name=&quot;fileExtensions&quot; value=&quot;java&quot;/&gt;

    &lt;!-- [newline-lf] --&gt;
    &lt;module name=&quot;RegexpMultiline&quot;&gt;
        &lt;property name=&quot;format&quot; value=&quot;\r\n&quot;/&gt;
        &lt;property name=&quot;message&quot; value=&quot;[newline-lf] Line must end with LF, not CRLF&quot;/&gt;
    &lt;/module&gt;</code></pre><h1 id="cr-lf란">CR, LF란?</h1>
<p>CR, LF는 타자기에서 유래된 단어이다.
타자기로 문서를 작성할 때 한 줄에 글자를 다 입력했으면 아래 줄로 이동시켜줘야한다.
아래 줄로 이동 하는 것이 <code>Line Feed(LF)</code>이고, 왼쪽 끝으로 밀어 주는 것이 <code>Carrige Return(CR)</code>이다.</p>
<h2 id="사전적-의미">사전적 의미</h2>
<h3 id="crcarrige-return">CR(Carrige Return)</h3>
<blockquote>
<p>Carrige 캐리지
(타자기 등의 기계에서 다른 부분을 이동시키는 부분)
<a href="https://en.dict.naver.com/#/search?query=carriage%20return">네이버 사전</a></p>
</blockquote>
<h3 id="lfline-feed">LF(Line Feed)</h3>
<blockquote>
<p>Line Feed 라인피드
모니터의 커서 위치나 프린터의 인쇄 위치를 한 줄 아래로 내리는 일.
<a href="https://en.dict.naver.com/#/search?query=line%20feed">네아버 사전</a></p>
</blockquote>
<h3 id="crlfcr--lf">CRLF(CR + LF)</h3>
<blockquote>
<p>crlf
1.명사 컴퓨터속어 복귀와 개행(改行)
2.자동사 컴퓨터속어 개행하다
<a href="https://en.dict.naver.com/#/search?query=CRLF">네이버 사전</a></p>
</blockquote>
<h2 id="os별-줄바꿈">OS별 줄바꿈</h2>
<p>CR, LF는 위의 내용과 같이 타자기의 디지털 잔해(?)이며, 컴퓨터 OS별로 다른 줄바꿈 타입을 사용한다.</p>
<h3 id="linux유닉스-계열">Linux(유닉스 계열)</h3>
<p>리눅스에서는 줄바꿈을 <code>LF</code>가 기본값이다. (\n)</p>
<h3 id="windows">Windows</h3>
<p>Windows에서는 줄바꿈을 <code>CRLF</code>이 기본값이다.(\r\n)</p>
<h1 id="lf를-사용해야-하는-이유">LF를 사용해야 하는 이유</h1>
<p>다양한 코딩컨벤션 규칙과 개발자들에게 일관적인 코딩 스타일을 유지할 수 있게 도와주는 툴인 <code>Prettier</code>에서는 <code>CRLF</code>대신 <code>LF</code>사용을 권고하고 있다.</p>
<p>LF를 사용하는 이유는 협업때문인데 <code>CRLF</code>와 <code>LF</code>의 바이트 코드가 다르기 때문에 형상관리 툴에서 다른 코드로 인식함으로 Commit할 때 줄바꿈 타입이 다른 경우 변경하지 않은 파일에 대해서도 변경된 것으로 인식하기 때문에 <code>LF</code>로 통일하는 것이다.</p>
<h3 id="참고">참고</h3>
<blockquote>
<p><a href="https://github.com/naver/hackday-conventions-java">네이버 코딩 컨벤션</a>
<a href="https://prettier.io/docs/en/options.html#end-of-line">Prettier</a></p>
</blockquote>
]]></description>
        </item>
    </channel>
</rss>