<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Monitoring on</title><link>https://taetaetae.github.io/tags/monitoring/</link><description>Recent content in Monitoring on</description><generator>Hugo</generator><language>en</language><lastBuildDate>Sun, 04 Oct 2020 15:39:15 +0000</lastBuildDate><atom:link href="https://taetaetae.github.io/tags/monitoring/index.xml" rel="self" type="application/rss+xml"/><item><title>그런 개발자로 괜찮은가 - '로그 &amp; 모니터링' 편</title><link>https://taetaetae.github.io/2020/10/04/a-good-developer-in-terms-of-log-and-monitoring/</link><pubDate>Sun, 04 Oct 2020 15:39:15 +0000</pubDate><guid>https://taetaetae.github.io/2020/10/04/a-good-developer-in-terms-of-log-and-monitoring/</guid><description>&lt;p>　캐릭터를 육성하며 게임하는 경우를 생각해 보자. 더 좋은 아이템을 얻거나 퀘스트를 달성하기 위해 당신은 다양한 방법을 통해 캐릭터를 성장시킨다. 사냥을 하다 체력이 떨어지게 되면 물약을 먹고, &lt;!--more -->캐릭터의 능력 중 부족한 부분이 있으면 훈련을 더 하거나 그에 맞는 아이템을 장착하게 된다. 이렇게 캐릭터의 &amp;lsquo;상태&amp;rsquo;를 적절한 UI를 통해 사용자에게 알려주기 때문에 &amp;lsquo;확인&amp;rsquo;이 가능하고 &amp;lsquo;대응&amp;rsquo;이 가능하게 된다.&lt;/p>
&lt;p>　우리가 만드는 애플리케이션 또한 위에서 이야기 한 게임상의 캐릭터가 아닐까 싶다. 복잡한 스펙을 다양한 테스트 케이스를 만들며 로직 동작에는 이상이 없음을 확인했다면 그걸로 만족할 수 있을까? 개발자의 &amp;lsquo;레벨&amp;rsquo;은 이 부분에서 차이가 난다고 생각한다. 운영환경에 출시한 애플리케이션에 에러가 나는지, 트래픽이 얼마나 들어오고 있고 트래픽의 유형은 또 어떠한지, 요청에 대한 응답속도는 어떻고 서버의 시스템 지표에는 문제가 없는지 등등. 애플리케이션의 유형에 따라 다양하겠지만 적절한 로그를 이용하여 애플리케이션의 &amp;lsquo;상태&amp;rsquo;를 확인하고 문제가 있다면 &amp;lsquo;대응&amp;rsquo;하는 게 꼭 필요하다고 생각한다.&lt;/p>
&lt;p>　이번 포스팅에서는 크게 로깅과 모니터링에 대해 알아보고자 한다. 이를 통해 애플리케이션의 &amp;lsquo;개발&amp;rsquo;에만 집중하고 있던 관점을 보다 더 높은 곳에서 바라보며 애플리케이션의 &amp;lsquo;운영&amp;rsquo; 측면에서도 고민해 보는 기회가 되었으면 한다.&lt;/p>
&lt;blockquote>
&lt;p>필자는 서버 개발자이다 보니 글의 내용이 다소 서버 개발자의 시선에서 작성하게 되었다. 하지만 &amp;lsquo;개발자&amp;rsquo;라면 유형만 다르지 대부분 비슷하기 때문에 크게 다르지 않다고 생각한다.&lt;/p>&lt;/blockquote>
&lt;h2 id="로그는-어떤걸-어떻게-남겨야-할까">로그는 어떤걸, 어떻게 남겨야 할까?&lt;/h2>
&lt;p>　﻿로그가 왜 필요한지에 대한 내용은 다루지 않겠다. (굳이 말하지 않아도 그만큼 중요하다는 표현이 더 어울릴 수도 있겠다.) 그렇다면 우선 어떤 로그를 남겨야 할까?&lt;/p>
&lt;figure>&lt;a class="lightgallery" href="https://taetaetae.github.io/images/a-good-developer-in-terms-of-Log-and-Monitoring/talk.jpg" title="/images/a-good-developer-in-terms-of-Log-and-Monitoring/talk.jpg" data-thumbnail="/images/a-good-developer-in-terms-of-Log-and-Monitoring/talk.jpg" data-sub-html="&lt;h2>필자가 꿈나무 시절때 나누었던 조직장님과의 대화 내용&lt;/h2>">
 &lt;img
 class="lazyload"
 src="https://taetaetae.github.io/svg/loading.min.svg"
 data-src="https://taetaetae.github.io/images/a-good-developer-in-terms-of-Log-and-Monitoring/talk.jpg"
 data-srcset="https://taetaetae.github.io/images/a-good-developer-in-terms-of-Log-and-Monitoring/talk.jpg, https://taetaetae.github.io/images/a-good-developer-in-terms-of-Log-and-Monitoring/talk.jpg 1.5x, https://taetaetae.github.io/images/a-good-developer-in-terms-of-Log-and-Monitoring/talk.jpg 2x"
 data-sizes="auto"
 alt="/images/a-good-developer-in-terms-of-Log-and-Monitoring/talk.jpg" width="40%" />
 &lt;/a>&lt;figcaption class="image-caption">필자가 꿈나무 시절때 나누었던 조직장님과의 대화 내용&lt;/figcaption>
 &lt;/figure>
&lt;p>　﻿아직까지도 기억에 남아있는 예전 조직 장님과의 대화. 일단 로그는 최대한 많이 (과하게) 남겨야 한다고 생각한다. 그다음 불필요한 로그들은 제거하거나 레벨을 낮추는 등 상황에 맞도록 커스터마이징이 필요하다. 경험을 해보면 알겠지만 운영환경에 애플리케이션을 배포하고 서비스를 운영하다 보면 개발 환경에서 만나기 어렵거나 경험해보지 못한 상황이 발생하곤 한다. 이럴 때 상황에 맞는 로그들이 있다면 미리 남겨둔 로그를 통해 더 효과적으로 상황을 파악할 수 있다. 트래픽의 정보(request url, parameter, UA, remote ip 등)를 남겨서 외부에서 호출하는 형태를 분석하는데 활용할 수도 있고, 애플리케이션에서 외부로 호출을 하고 난 뒤에 받는 응답에 대해서 로그를 남겨두면 외부 통신의 오류를 파악하는 데 도움이 될 수 있다. 어떤 로그를 남겨야 하는가에 대한 고민은 운영하는 애플리케이션이 어떤 행동을 하는가에 관점을 두고 고민해보면 좀 더 쉽게 찾을 수 있을 것이라 생각한다.&lt;/p>
&lt;p>　로그를 남기는 방법 또한 다양하다. 시스템 로컬에 파일로 남기거나 특정 로그 서버를 설정하여 여러 대의 서버 로그를 한곳에서 볼 수도 있다. 다만 로그를 &amp;lsquo;남기는&amp;rsquo; 것 또한 하나의 비용에 포함되기 때문에 애플리케이션의 기능에 최대한 영향이 가지 않도록 최대한 빠른 시간 내에 처리가 되도록 해야 한다. (혹은 비동기로 남기거나 등)&lt;/p>
&lt;p>　로그를 남기는 이유 중 가장 큰 이유는 &amp;lsquo;나중에 보기 위해서&amp;rsquo;이다. 그만큼 한번 로그를 남길 때에도 보기 좋게 남겨야 한다. 예컨대, 아래에 적어놓은 로그 방식의 경우 작은 차이지만 나중에 볼 때 꽤 큰 차이를 유발한다.
﻿&lt;/p>
&lt;ul>
&lt;li>안좋은 예&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="k">try&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">	&lt;/span>&lt;span class="p">...&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">catch&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">Exception&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">e&lt;/span>&lt;span class="p">){&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">	&lt;/span>&lt;span class="n">log&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">Error&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">e&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c1">// 어떤 상황이지..?&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ul>
&lt;li>보다 조금 더 좋은 예&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="k">try&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">	&lt;/span>&lt;span class="p">...&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">catch&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">Exception&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">e&lt;/span>&lt;span class="p">){&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">	&lt;/span>&lt;span class="n">log&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">Error&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;url : &amp;#34;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">+&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">url&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">+&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s">&amp;#34;, parameter : &amp;#34;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">+&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">parameter&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">+&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s">&amp;#34;, remote ip : &amp;#34;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">+&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">remoteIp&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">e&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c1">// 로그는 가급적 자세하게 !&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="로그가-가져다-주는-또-다른-세상">로그가 가져다 주는 또 다른 세상&lt;/h2>
&lt;p>　로그는 또 다른 데이터가 될 수 있다. 글 목록을 보여주는 웹페이지가 있다고 가정해보자. 이때 사용자들이 어떤 글을 더 많이 읽는지 &amp;lsquo;클릭 지표&amp;rsquo;에 대한 로그를 남겨 둔다면 &amp;lsquo;인기글&amp;rsquo; 같은 또 다른 웹 페이지가 나올 수 있을 것 같다. 만약 그 페이지가 회원만 읽을 수 있는 페이지라면 &amp;lsquo;20대 남성이 월요일 오후에 많이 읽는 글&amp;rsquo; 같이 회원의 정보를 조합하여 새로운 데이터를 만들 수 있게 된다. 이러한 데이터들은 보다 더 좋은 서비스를 할 수 있게 도와줄 수 있는 밑거름이 되고 그 바탕은 로그라는 걸 명심하자.&lt;/p></description></item><item><title>자바, 성능, 모니터링 테크세미나 정리 및 후기 (by 우아한 형제들)</title><link>https://taetaetae.github.io/2019/05/12/got-of-java-seminar/</link><pubDate>Sun, 12 May 2019 20:04:01 +0000</pubDate><guid>https://taetaetae.github.io/2019/05/12/got-of-java-seminar/</guid><description>&lt;p>실무에서 자바 기반으로 개발을 하고 서비스를 운영을 하다보면 처음엔 아무런 문제가 없다가 사용자가 몰리는 등 이벤트성으로 트래픽이 많아질 경우 꼭 문제가 생기기 마련이다. 그럴때면 뒤늦게 부랴부랴 원인을 찾고 개선하기 바빠지게 된다. &lt;!-- more --> (아마 윗분들에게 혼나면서?ㅠㅠ)
평소에 이런 성능문제를 개선하고 미리 모니터링 할수있는 부분에 대해 관심을 갖고 있었던 찰나, 우아한 형제들에서 &lt;a href="https://www.facebook.com/woowahanTech/photos/a.1925530564354206/2280664485507477" target="_blank" rel="noopener noreffer ">5월 우아한 테크 세미나&lt;/a>를 한다기에 부랴부랴 장문의 글로 신청을 하였고 운이 좋아 당첨이 되었다.
한창 회사에서 새로운 서비스 출시, 그리고 잠을 줄여가며 별도로 진행하고 있던 토이프로젝트 등 여러가지로 바쁜 시기였지만 특히 예전부터 뵙고싶던 이상민님께서 직접 강의를 해주신다기에 피곤한 심신을 이끌고 세미나에 참석하였고 그 후기를 적어보고자 한다.&lt;/p>
&lt;blockquote>
&lt;p>두레이로 만드신 발표자료를 공유해 주셨지만 저작권 문제도 있고 해서 필자기준에서 이해한 부분에 대해서만 공유하고자 한다. 더불어 그냥 듣고 앵무새처럼 발표내용 그대로를 공유하는건 의미가 없다고 생각되어&amp;hellip;&lt;/p>&lt;/blockquote>
&lt;figure>&lt;a class="lightgallery" href="https://taetaetae.github.io/images/got-of-java-seminar/1.jpg" title="/images/got-of-java-seminar/1.jpg" data-thumbnail="/images/got-of-java-seminar/1.jpg" data-sub-html="&lt;h2>포스터만 봐도 벌써부터 가슴이 뛴다(?).&lt;/h2>">
 &lt;img
 class="lazyload"
 src="https://taetaetae.github.io/svg/loading.min.svg"
 data-src="https://taetaetae.github.io/images/got-of-java-seminar/1.jpg"
 data-srcset="https://taetaetae.github.io/images/got-of-java-seminar/1.jpg, https://taetaetae.github.io/images/got-of-java-seminar/1.jpg 1.5x, https://taetaetae.github.io/images/got-of-java-seminar/1.jpg 2x"
 data-sizes="auto"
 alt="/images/got-of-java-seminar/1.jpg" width="80%" />
 &lt;/a>&lt;figcaption class="image-caption">포스터만 봐도 벌써부터 가슴이 뛴다(?).&lt;/figcaption>
 &lt;/figure>
&lt;h2 id="성능">성능&lt;/h2>
&lt;p>구글에서 작성한 &lt;a href="https://developers.google.com/web/fundamentals/performance/why-performance-matters/" target="_blank" rel="noopener noreffer ">성능이 중요한 이유&lt;/a> 라는 아티클을 공유해 주셨다. (시간이 된다면 한번 읽어보길 강추, 무려 한글!) 어플리케이션에서 성능은 사용자의 증가, 이탈율, 응답속도에 영향이 있고 이는 결국 추구하는 가치(이를 테면 수익)에 직면한다고 한다.
사용자는 어느 관점에서 바라보는가에 따라 달라지고 각 관점에 따라 성능을 챙겨야 하는 부분이 달라진다. 수강신청을 하는 시점에서의 사용자와 뉴스 페이지를 읽는 시점에서의 사용자는 각 성격이 엄연히 다른것처럼.&lt;/p>
&lt;ul>
&lt;li>시스템 관리자
&lt;ul>
&lt;li>등록된 / 등록되지 않은 사용자&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>서버 관점
&lt;ul>
&lt;li>로그인된 / 로그인 하지 않은 사용자&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>성능 테스터 관점
&lt;ul>
&lt;li>Active User
&lt;ul>
&lt;li>서버에 부하를 주는 사용자&lt;/li>
&lt;li>메뉴나 링크를 누르고 결과가 나오기를 기다리는 사용자&lt;/li>
&lt;li>성능테스트시 Vuser와 거의 동일 ( Vuser : 가상사용자(virtual user) )&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>Concurrent user
&lt;ul>
&lt;li>서버에 부하를 주고 있거나, 줄 가능성이 매우높은 서비스에 접속중인 사용자&lt;/li>
&lt;li>웹 페이지를 띄워놓은 사용자&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;p>TPS(Transaction Per Seconds)는 초당 얼마나 많은 요청을 처리할수 있는지에 대한 시스템의 절대적인 수치로 볼수있다. (개발자는 어느상황에서든지 대충 감으로 이야기 하지말고 정확한 수치로 이야기 해야한다는 뼈를 때리는 조언과 함께&amp;hellip;) TPS는 Scale out/up을 통해 증가시킬수 있지만 Response Time 은 불가능하다. 물론 어플리케이션을 튜닝하면 두 수치 모두 개선이 가능하다. 이러한 TPS와 Response Time의 최대치는 출시전에 반드시 테스트를 통해 알고 있어야 이슈발생시 대응하는데 유용하다.
Bottleneck 즉 병목은 장비, 어플리케이션, 저장소, 설정 등 다양한 상황에서 발생할수 있다. 그중에 &amp;ldquo;아주 일반적&amp;quot;으로 가장 병목이 많이 발생하는 구간은 DB이고 그 다음으로 클라이언트(Web page, App), Network이 있을 수 있다.
결론은 &lt;strong>Performance engineering is &amp;ldquo;Composite Art&amp;rdquo; of IT&lt;/strong> 라는 하나의 문장으로 정리를 해주셨다. 아무리 이쁜 디자인과 어렵고 복잡한 기능이 있을지라도 성능이 뒷받침 안된다면 대용량 트래픽 상황에서는 무의미해지기 때문이라고 생각한다.&lt;/p>
&lt;h2 id="자바">자바&lt;/h2>
&lt;p>자바의 역사에 대해 설명해 주셨다. ( 역사에 대한 보다 자세한 설명은 &lt;a href="https://www.whatap.io/blog/12/" target="_blank" rel="noopener noreffer ">https://www.whatap.io/blog/12/&lt;/a> 참고 ) 언제부터인가 JDK 라이센스 이슈가 많았었는데 실무에서 개발하는 입장에서는 java 8 에서는 문제가 안되고 java 11부터 라이센스 문제가 복잡하게 생길수 있다고 한다. 이부분은 공식문서(?)를 찾아보는게 좋을듯 하다. (개인 또는 회사에서 사용할 경우 상황에 따라 법적 이슈가 생길수도, 안생길수도 있는 복잡한 문제가 있어보여서&amp;hellip; 필자도 제대로 이해하지는 못했다ㅠ)&lt;/p>
&lt;p>그리고 각 자바 버전에서 발표한 새로운 기능에 대해 설명해주셨다.&lt;/p>
&lt;ul>
&lt;li>Java 8
&lt;ul>
&lt;li>lambda, stream, default method, LocalDate / LocalTime 추가&lt;/li>
&lt;li>stream 과 foreach 의 성능은 거의 차이 없음 (오히려 가독성이 나빠질수도 있다.)&lt;/li>
&lt;li>ParallelStream 은 해당 장비의 cpu 개수만큼 스레드 풀을 만들어 사용 (오히려 독이 될수 있으니 잘 알아보고 사용할것)&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>Java 9
&lt;ul>
&lt;li>Compact Strings : char[] &amp;gt; byte[]&lt;/li>
&lt;li>G1 default GC : &lt;a href="https://www.oracle.com/technetwork/tutorials/tutorials-1876574.html" target="_blank" rel="noopener noreffer ">https://www.oracle.com/technetwork/tutorials/tutorials-1876574.html&lt;/a>&lt;/li>
&lt;li>Collections of (불변) : List.of, Set.of, Map.of&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>Java 10
&lt;ul>
&lt;li>var 의 등장&lt;/li>
&lt;li>Application Class-Data Sharing(AppCDS)&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>Java 11
&lt;ul>
&lt;li>Oracle JDK의 유료화&lt;/li>
&lt;li>Http Client. 기본 설정값들을 제대로 알고 써야한다. ( &lt;a href="https://golb.hplar.ch/2019/01/java-11-http-client.html" target="_blank" rel="noopener noreffer ">https://golb.hplar.ch/2019/01/java-11-http-client.html&lt;/a> )&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>Java 12
&lt;ul>
&lt;li>Switch expressions&lt;/li>
&lt;li>Shenandoah : &lt;a href="https://www.youtube.com/watch?v=E1M3hNlhQCg" target="_blank" rel="noopener noreffer ">https://www.youtube.com/watch?v=E1M3hNlhQCg&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h2 id="모니터링">모니터링&lt;/h2>
&lt;p>유명한 상용 APM들을 설명해 주셨다. 각각의 장점에 대해 설명해 주셨는데 정말 회사에 요청해 구매할수만 있다면 사서 해보고 싶을정도로 신기한 기능이 많았다. 그중 dynatrace 는 에이전트만 설치해두면 별도의 설정 필요없이 알아서 해준다고&amp;hellip;&lt;/p></description></item></channel></rss>