<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Batch on</title><link>https://taetaetae.github.io/tags/batch/</link><description>Recent content in Batch on</description><generator>Hugo</generator><language>en</language><lastBuildDate>Sun, 13 Oct 2019 15:46:12 +0000</lastBuildDate><atom:link href="https://taetaetae.github.io/tags/batch/index.xml" rel="self" type="application/rss+xml"/><item><title>더이상 기다리지 않아도 되는 배치 무중단 배포</title><link>https://taetaetae.github.io/2019/10/13/batch-nondisruptive-deploy/</link><pubDate>Sun, 13 Oct 2019 15:46:12 +0000</pubDate><guid>https://taetaetae.github.io/2019/10/13/batch-nondisruptive-deploy/</guid><description>&lt;p>&lt;a href="https://taetaetae.github.io/2019/09/29/woowabros-spring-batch/" target="_blank" rel="noopener noreffer ">지난 포스팅&lt;/a>, 그러니까 우아한 형제들에서 초대를 받아 Spring batch 에 대한 테크세미나에 다녀 왔다. 그 중 가장 인상깊었던 부분이 바로 &lt;code>무중단 배포&lt;/code>. 차일피일 미루다 필자가 속한 팀에서도 배포때마다 가장 불편을 느끼고 있었던 부분이었기도 했고&lt;!--more -->, &lt;code>그런가보다&lt;/code> 하며 개념만 알고 넘어가기엔 무언가 양심에 찔려 직접 무중단 배포를 할 수 있도록 구성을 해보고 테스트까지 해보고자 한다.&lt;/p>
&lt;h2 id="상황-및-문제점">상황 및 문제점&lt;/h2>
&lt;p>리눅스 서버에 Jenkins가 설치되어 있고, Spring batch 모듈을 실행시키고 있다. 수동으로 실행을 하거나, Jenkins RestApi를 이용해서 실행을 할 수 있지만 주로 정해진 시간 즉, 스케쥴링에 의해 실행되곤 한다. 스케쥴링의 가장 작은 단위는 1분단위 배치도 있기 때문에 24시간 멈추지 않고 실행되고 있다고 무방하다. 하지만 배치 모듈이 수정되고, 배포를 하기 위해서는 다음과 같은 시나리오로 진행이 된다.&lt;/p>
&lt;ol>
&lt;li>Jenkins 설정의 &lt;code>끄기전 준비&lt;/code> 를 실행하여 더이상 Jenkins에 의해 Spring batch 모듈(이하 Job)이 실행되지 않도록 한다.&lt;/li>
&lt;li>새로운 Job은 더이상 실행되지 않지만 이미 실행중이였던 Job 은 강제로 중단을 하거나 Job 이 끝날때까지 기다린다.&lt;/li>
&lt;li>실행중인 Job이 없을 경우 이제 배포를 진행한다.&lt;/li>
&lt;li>배포가 완료되면 Jenkins 설정의 &lt;code>끄기전 준비&lt;/code>를 해제한다.&lt;/li>
&lt;/ol>
&lt;figure>&lt;a class="lightgallery" href="https://taetaetae.github.io/images/batch-nondisruptive-deploy/wait.jpg" title="/images/batch-nondisruptive-deploy/wait.jpg" data-thumbnail="/images/batch-nondisruptive-deploy/wait.jpg" data-sub-html="&lt;h2>실행중인 Job이 안끝나면 마냥 기다릴텐가? 출처 : https://m.post.naver.com/viewer/postView.nhn?volumeNo=14100660&amp;memberNo=2032633&lt;/h2>">
 &lt;img
 class="lazyload"
 src="https://taetaetae.github.io/svg/loading.min.svg"
 data-src="https://taetaetae.github.io/images/batch-nondisruptive-deploy/wait.jpg"
 data-srcset="https://taetaetae.github.io/images/batch-nondisruptive-deploy/wait.jpg, https://taetaetae.github.io/images/batch-nondisruptive-deploy/wait.jpg 1.5x, https://taetaetae.github.io/images/batch-nondisruptive-deploy/wait.jpg 2x"
 data-sizes="auto"
 alt="/images/batch-nondisruptive-deploy/wait.jpg" width="80%" />
 &lt;/a>&lt;figcaption class="image-caption">실행중인 Job이 안끝나면 마냥 기다릴텐가? &lt;br>출처 : &lt;a href="https://m.post.naver.com/viewer/postView.nhn?volumeNo=14100660&amp;amp;memberNo=2032633" target="_blank" rel="noopener noreffer ">https://m.post.naver.com/viewer/postView.nhn?volumeNo=14100660&amp;memberNo=2032633&lt;/a>&lt;/figcaption>
 &lt;/figure>
&lt;p>실행되는 Job을 중단하지 못하는 상황 즉, 실행중에 중단하면 트랜잭션이 깨져 무조건 기다려야만 하는 상황이라면 배포 또한 계속 지연될 수 밖에 없는 상황인 것이다. Spring boot에 java config 를 활용하고 딱 &lt;code>jar&lt;/code> 파일 하나를 실행하는 방식이라면 &lt;code>jar&lt;/code>파일을 바꿔치기 하는 식으로 고민을 해볼수도 있을것 같다. 하지만 Legacy 코드가 아직 존재하여 일반 Spring 에 xml 로 config 하는 방식으로 운영중이라 &lt;code>jar&lt;/code>파일 하나만 바꿔치기 하기엔 무리가 있는 상황.&lt;/p>
&lt;p>은총알처럼 어디에서나 사용이 가능한 만병통치약 같은 방법은 없다. 언제나 그랬듯 현재 시스템(xml config 방식)에 가장 최적화된 방법, 그리고 java config 방식에서도 사용이 가능할것 같은 방법을 생각해 보았다.&lt;/p>
&lt;h2 id="무중단-배포를-가능케-하는-3가지-핵심">무중단 배포를 가능케 하는 3가지 핵심&lt;/h2>
&lt;p>&lt;strong>1. 배포를 매번 새로운 경로에 배포한다.&lt;/strong>
각 회사마다, 그리고 서비스마다 정말 다양한 배포 시스템이 있다. 그들의 공통점은 원격서버의 &lt;code>특정 경로&lt;/code>에 빌드된 파일들을 밀어 넣어준다는 것. 시나리오는 다음과 같다.&lt;/p>
&lt;ol>
&lt;li>배포할때마다 별도의 디렉토리를 생성한뒤 심볼릭 링크를 연결해준다.&lt;/li>
&lt;li>배포는 &lt;code>1&lt;/code>에서 연결한 심볼릭 링크에 배포되도록 설정, 결국 매번 만들어지는 디렉토리에 배포가 되게 된다.&lt;/li>
&lt;/ol>
&lt;p>여기서 중요한점은 &amp;ldquo;배포할 때마다 새로운 디렉토리에 배포가 된다&amp;rdquo; 와 배포시에는 항상 심볼릭 링크에만 배포를 하면 되기 때문에 &amp;ldquo;배포시스템이 새로 만들어지는 디렉토리의 경로를 몰라도 무방하다&amp;quot;는 점이다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#!/bin/sh
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&lt;/span>&lt;span class="nb">cd&lt;/span> /~~~/deploy/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 임시 디렉토리&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">DIRECTORY_NAME&lt;/span>&lt;span class="o">=&lt;/span>batch_&lt;span class="k">$(&lt;/span>/bin/date +%Y%m%d%H%M%S&lt;span class="k">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">mkdir &lt;span class="nv">$DIRECTORY_NAME&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>위 쉘 스크립트를 실행하면 batch_20191012205218 와 같은 디렉토리가 생성이 된다. 심볼릭 링크 관련해서는 바로 아래 이어서 설명하겠다.&lt;/p>
&lt;p>&lt;strong>2. 심볼릭 링크의 원래 링크를 즉시 변경&lt;/strong>
보통 심볼릭 링크 (즉, 바로가기) 의 경로를 변경하기 위해서는 아래처럼 지웠다가 삭제하는 식으로 했었는데&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">$ mkdir directory_a
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">$ mkdir directory_b
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">$ ln -s directory_a asdf
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">$ ll
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">asdf -&amp;gt; directory_a
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">directory_a
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">directory_b
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># directory_a 에서 directory_b 로 바꾸는 경우 (심볼릭 링크 자체를 삭제하고 다시 심볼릭 링크 생성)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">$ rm asdf
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">$ ln -s directory_b asdf
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">$ ll
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">asdf -&amp;gt; directory_b
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">directory_a
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">directory_b
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>이렇게 되면 삭제하고 ~ 다시 만들어지는 타이밍에 배포가 되거나 실행이 되는 즉, 해당 경로에 엑세스 하는 경우 이전의 경로를 바라본다거나 의도했던 방식으로 실행이 되지 않는 상황이 발생한다. (찰나의 타이밍 이지만 필자는 이러한 문제로 이전의 경로를 바라보는 문제가 발생했었다.) 그래서 ln 의 옵션중인 &lt;code>-Tfs&lt;/code>옵션으로 즉시 변경을 해주도록 하자. (&lt;a href="https://linux.die.net/man/1/ln" target="_blank" rel="noopener noreffer ">ln man 참고&lt;/a>)&lt;/p></description></item><item><title>우아한 스프링 배치 테크세미나 정리 및 후기 (by 우아한 형제들)</title><link>https://taetaetae.github.io/2019/09/29/woowabros-spring-batch/</link><pubDate>Sun, 29 Sep 2019 17:55:50 +0000</pubDate><guid>https://taetaetae.github.io/2019/09/29/woowabros-spring-batch/</guid><description>&lt;p>지난주 우아한 형제들에서 진행하였던 &amp;ldquo;9월 우아한 테크 세미나 - 우아한 스프링 배치&amp;rdquo; 에 다녀왔다. 필자에게 이번 9월은 정신이 어디에 있는지 모를만큼 바쁘고 힘들었지만 예전부터 궁금하기도 했고 &lt;!--more -->요즘들어 관심을 갖던 &amp;ldquo;배치 어플리케이션&amp;quot;을 어떻게 하면 &amp;ldquo;우아한 방법&amp;quot;으로 사용할 수 있을지에 대해 여러 생각들이 있었기에 큰 기대를 가지고 지옥철을 견디며 잠실 근처에 있는 우아한 형제들 작은집으로 가게 되었다.
어떤 내용을 발표하였는지에 대해 &lt;code>기억잘하는 똑똑한 앵무새&lt;/code>가 되어 정리하기 보다 주요 포인트에 대한 생각과 함께 참여를 못한 분들 위해서라기 보다 내 스스로 정리를 하기 위해 포스팅을 작성해 보고자 한다.
(이번에도 불러주셔서 감사합니다 ^=^)&lt;/p>
&lt;h2 id="인트로">인트로&lt;/h2>
&lt;p>연사자 분은 워낙에 유명하신 분이라 별도의 설명이 필요 없이 운영하시는 &lt;a href="https://jojoldu.tistory.com" target="_blank" rel="noopener noreffer ">블로그 주소&lt;/a>로 대체를 해본다. 이번 행사에 초대되신 분들은 한번이라도 스프링 배치를 써분 분들을 대상으로 진행하게 되었다고 했는데 마침 필자도 팀 내에서 운영하고 있는 배치 어플리케이션을 보다 효율적이고 우아하게 바꿔보고자 하는 니즈가 있었기에 아마 초대된게 아닐까 싶다.&lt;/p>
&lt;figure>&lt;a class="lightgallery" href="https://taetaetae.github.io/images/woowabros-spring-batch/small_house.jpg" title="/images/woowabros-spring-batch/small_house.jpg" data-thumbnail="/images/woowabros-spring-batch/small_house.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/woowabros-spring-batch/small_house.jpg"
 data-srcset="https://taetaetae.github.io/images/woowabros-spring-batch/small_house.jpg, https://taetaetae.github.io/images/woowabros-spring-batch/small_house.jpg 1.5x, https://taetaetae.github.io/images/woowabros-spring-batch/small_house.jpg 2x"
 data-sizes="auto"
 alt="/images/woowabros-spring-batch/small_house.jpg" width="50%" />
 &lt;/a>&lt;figcaption class="image-caption">아기자기한 우아한 형제들 건물 내부&lt;/figcaption>
 &lt;/figure>
&lt;p>더불어 발표전에 간략히 회사가 원하는 인재에 대하여 언급해주셨는데 그게 어찌나 공감이 가던지. 역시 생각이 남다른 회사구나 하고 다시한번 생각을.&lt;/p>
&lt;blockquote>
&lt;p>자기보다 경험이 &amp;ldquo;적은&amp;rdquo; 사람에게 &amp;ldquo;설득을 당할 수&amp;rdquo; 있어야 하고, 자기보다 경험이 &amp;ldquo;많은 사람을 설득&amp;rdquo; 시킬 수 있어야 한다.&lt;/p>&lt;/blockquote>
&lt;h2 id="기본편">기본편&lt;/h2>
&lt;p>배치 어플리케이션이란 컴퓨터에서 사람와 상호작용없이 이어지는 프로그램(작업)들의 실행이라고 &lt;a href="https://ko.wikipedia.org/wiki/%EC%9D%BC%EA%B4%84_%EC%B2%98%EB%A6%AC" target="_blank" rel="noopener noreffer ">위키피디아&lt;/a>에 간결&amp;amp;명료하게 정리되어 있다. 그만큼 일반적인 웹 어플리케이션과의 차이가 있는데 웹 어플리케이션은 실시간 처리가 기본이고 요청에 대한 응답을 제공해야 하니 아무래도 속도가 상대적이며 QA시 편한 부분이 있다. 그에 반해 배치 어플리케이션은 웹 어플리케이션에서 말하는 요청이라는 개념보다 후속처리에 가깝고, 속도 또한 절대적이며 QA가 복잡하다는게 특징이다. 따라서 테스트코드는 웹 어플리케이션 보다 배치 어플리케이션이 더 필요하다고 볼 수 있다.
배치 어플리케이션이 필요한 상황은 크게 두가지로 나눠 볼 수가 있다고 한다.&lt;/p>
&lt;ul>
&lt;li>일정 주기로 실행 되어야 할 때&lt;/li>
&lt;li>실시간 처리가 어려운 대량의 데이터를 처리 할때&lt;/li>
&lt;/ul>
&lt;p>평소 첫번째 상황만 생각하고 배치 어플리케이션을 작성하곤 했었는데 두번재 상황에 대해 생각에 생각을 더 해보니 스프링 배치를 간단하게만 (Tasklet) 사용하고 있는건 아닌가 하는 반성을 해보곤 했다. (Reader, Processor, Writer 등 다양한 레이어가 있는데도&amp;hellip;)&lt;/p>
&lt;p>특히 스프링 배치에서는 기본적으로 모든 데이터를 메모리에 쌓지 않는 조회방식라고 한다. (DB기준) Paging 혹은 Cursor로 pageSize만큼만 읽어오고 chunkSize만큼만 commit 하는 형태. 이러한 각 레이어별 size를 잘 조정하기만 해도 적은 노력으로 큰 성능을 얻을 수 있는 부분이 프레임워크를 사용하는 이유 아닐까 라고 생각해본다.&lt;/p>
&lt;p>또한 &lt;code>@JobScope&lt;/code> 나 &lt;code>@StepScope&lt;/code>는 Late Binding 즉 배치 어플리케이션이 실행되는 시점이 아니라 Job 이 실행될때 생성이 되기 때문에 이를 활용하여 동적으로 reader / processor / wirter 레이어를 만들 수 있다고 한다.&lt;/p>
&lt;h2 id="활용편">활용편&lt;/h2>
&lt;p>스프링 배치를 이용한 배치 어플리케이션이 있고 이를 스케쥴링 등 관리를 해주는 도구들에 이야기를 해주셨다.&lt;/p>
&lt;ul>
&lt;li>Cron
&lt;ul>
&lt;li>리눅스를 어느정도 사용해봤다면 알만한 리눅스 기본 스케쥴링 프로그램인 Cron.&lt;/li>
&lt;li>필자도 Cron 으로 주기적으로 실행하도록 설정해보기도 하였지만 배치 어플리케이션의 특성상 로그 및 실행/종료 등 제한사항이 많은 건 사실인것 같다.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>Spring MVC + API Call
&lt;ul>
&lt;li>주변에서 사용하고 있다고 하던 방식. 이 방식의 장점은 항상 떠있기 때문에 어플리케이션 구동시간이 별도로 필요 없다는 장점이 있지만 전반적인 관리가 어려운 단점이 있는것 같다.&lt;/li>
&lt;li>물론 울며 겨자먹기 식으로 단점을 극복할 방법은 여러가지가 있겠지만 모든건 항상 Trade off&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>Spring Batch Admin (Deprecated)
&lt;ul>
&lt;li>예전 팀분이 알려주셔서 잠깐 봤던 부분이긴 한데 어느사이에 Deprecated 되었다고 한다.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>Quertz + Admin
&lt;ul>
&lt;li>&lt;a href="http://www.quartz-scheduler.org/" target="_blank" rel="noopener noreffer ">http://www.quartz-scheduler.org/&lt;/a>&lt;/li>
&lt;li>아주 오래전에 써본 기억이 있지만 배보다 배꼽이 더 큰 상황같았던 힘들었던 기억들만 남아있는 구현방법인것 같다. 여러 레이어를 혼용해서 쓰다보면 각 레이어간의 상호 연결성의 위배되는 경우가 많기에&amp;hellip;&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>CI Tools (Jenkins / Teamcity 등)
&lt;ul>
&lt;li>아무래도 가장 추천할만한게 CI Tool 인것 같다. 그중에 필자도 Jenkins라는 툴을 너무 좋아하고.&lt;/li>
&lt;li>유료 툴 중에 Teamcity 를 잠깐 언급해주셨는데 찾아보니 한번즈음 써보고 싶을만한 기능들이 있어보였다.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;p>Jenkins 의 장점은 &lt;del>말해뭐해&lt;/del> 정도로 배치 어플리케이션과 궁합이 너무 잘 맞는 툴인것 같다. (물론 다른 툴들도 있겠지만 필자&lt;code>개취&lt;/code>라 넘어가도록 하자.) 특히 실행시 필요한 플러그인들이 다양하게 많이 있고, 실행방법 또한 수동/스케쥴링 으로 다양하게 할 수가 있으며 RestAPI 지원과 보안, 실행이력관리, 로그 등 최적화 되어있다고 해도 과언이 아닐정도로 다양한 장점들이 있는것 같다.&lt;/p></description></item></channel></rss>