/images/profile.png

더이상 기닀리지 μ•Šμ•„λ„ λ˜λŠ” 배치 무쀑단 배포

μ§€λ‚œ ν¬μŠ€νŒ…, κ·ΈλŸ¬λ‹ˆκΉŒ μš°μ•„ν•œ ν˜•μ œλ“€μ—μ„œ μ΄ˆλŒ€λ₯Ό λ°›μ•„ Spring batch 에 λŒ€ν•œ ν…Œν¬μ„Έλ―Έλ‚˜μ— λ‹€λ…€ μ™”λ‹€. κ·Έ 쀑 κ°€μž₯ μΈμƒκΉŠμ—ˆλ˜ 뢀뢄이 λ°”λ‘œ 무쀑단 배포. 차일피일 미루닀 ν•„μžκ°€ μ†ν•œ νŒ€μ—μ„œλ„ λ°°ν¬λ•Œλ§ˆλ‹€ κ°€μž₯ λΆˆνŽΈμ„ 느끼고 μžˆμ—ˆλ˜ λΆ€λΆ„μ΄μ—ˆκΈ°λ„ ν–ˆκ³ , κ·ΈλŸ°κ°€λ³΄λ‹€ ν•˜λ©° κ°œλ…λ§Œ μ•Œκ³  λ„˜μ–΄κ°€κΈ°μ—” 무언가 양심에 μ°”λ € 직접 무쀑단 배포λ₯Ό ν•  수 μžˆλ„λ‘ ꡬ성을 해보고 ν…ŒμŠ€νŠΈκΉŒμ§€ ν•΄λ³΄κ³ μž ν•œλ‹€.

상황 및 문제점

λ¦¬λˆ…μŠ€ μ„œλ²„μ— Jenkinsκ°€ μ„€μΉ˜λ˜μ–΄ 있고, Spring batch λͺ¨λ“ˆμ„ μ‹€ν–‰μ‹œν‚€κ³  μžˆλ‹€. μˆ˜λ™μœΌλ‘œ 싀행을 ν•˜κ±°λ‚˜, Jenkins RestApiλ₯Ό μ΄μš©ν•΄μ„œ 싀행을 ν•  수 μžˆμ§€λ§Œ 주둜 μ •ν•΄μ§„ μ‹œκ°„ 즉, μŠ€μΌ€μ₯΄λ§μ— μ˜ν•΄ μ‹€ν–‰λ˜κ³€ ν•œλ‹€. μŠ€μΌ€μ₯΄λ§μ˜ κ°€μž₯ μž‘μ€ λ‹¨μœ„λŠ” 1λΆ„λ‹¨μœ„ λ°°μΉ˜λ„ 있기 λ•Œλ¬Έμ— 24μ‹œκ°„ λ©ˆμΆ”μ§€ μ•Šκ³  μ‹€ν–‰λ˜κ³  μžˆλ‹€κ³  λ¬΄λ°©ν•˜λ‹€. ν•˜μ§€λ§Œ 배치 λͺ¨λ“ˆμ΄ μˆ˜μ •λ˜κ³ , 배포λ₯Ό ν•˜κΈ° μœ„ν•΄μ„œλŠ” λ‹€μŒκ³Ό 같은 μ‹œλ‚˜λ¦¬μ˜€λ‘œ 진행이 λœλ‹€.

  1. Jenkins μ„€μ •μ˜ 끄기전 μ€€λΉ„ λ₯Ό μ‹€ν–‰ν•˜μ—¬ 더이상 Jenkins에 μ˜ν•΄ Spring batch λͺ¨λ“ˆ(μ΄ν•˜ Job)이 μ‹€ν–‰λ˜μ§€ μ•Šλ„λ‘ ν•œλ‹€.
  2. μƒˆλ‘œμš΄ Job은 더이상 μ‹€ν–‰λ˜μ§€ μ•Šμ§€λ§Œ 이미 μ‹€ν–‰μ€‘μ΄μ˜€λ˜ Job 은 κ°•μ œλ‘œ 쀑단을 ν•˜κ±°λ‚˜ Job 이 λλ‚ λ•ŒκΉŒμ§€ κΈ°λ‹€λ¦°λ‹€.
  3. 싀행쀑인 Job이 없을 경우 이제 배포λ₯Ό μ§„ν–‰ν•œλ‹€.
  4. 배포가 μ™„λ£Œλ˜λ©΄ Jenkins μ„€μ •μ˜ 끄기전 μ€€λΉ„λ₯Ό ν•΄μ œν•œλ‹€.
/images/batch-nondisruptive-deploy/wait.jpg
싀행쀑인 Job이 μ•ˆλλ‚˜λ©΄ 마λƒ₯ 기닀릴텐가?
좜처 : https://m.post.naver.com/viewer/postView.nhn?volumeNo=14100660&memberNo=2032633

μ‹€ν–‰λ˜λŠ” Job을 μ€‘λ‹¨ν•˜μ§€ λͺ»ν•˜λŠ” 상황 즉, 싀행쀑에 μ€‘λ‹¨ν•˜λ©΄ νŠΈλžœμž­μ…˜μ΄ κΉ¨μ Έ 무쑰건 κΈ°λ‹€λ €μ•Όλ§Œ ν•˜λŠ” 상황이라면 배포 λ˜ν•œ 계속 지연될 수 밖에 μ—†λŠ” 상황인 것이닀. Spring boot에 java config λ₯Ό ν™œμš©ν•˜κ³  λ”± jar 파일 ν•˜λ‚˜λ₯Ό μ‹€ν–‰ν•˜λŠ” 방식이라면 jarνŒŒμΌμ„ λ°”κΏ”μΉ˜κΈ° ν•˜λŠ” μ‹μœΌλ‘œ 고민을 ν•΄λ³Όμˆ˜λ„ μžˆμ„κ²ƒ κ°™λ‹€. ν•˜μ§€λ§Œ Legacy μ½”λ“œκ°€ 아직 μ‘΄μž¬ν•˜μ—¬ 일반 Spring 에 xml 둜 config ν•˜λŠ” λ°©μ‹μœΌλ‘œ μš΄μ˜μ€‘μ΄λΌ jar파일 ν•˜λ‚˜λ§Œ λ°”κΏ”μΉ˜κΈ° ν•˜κΈ°μ—” 무리가 μžˆλŠ” 상황.

μ€μ΄μ•Œμ²˜λŸΌ μ–΄λ””μ—μ„œλ‚˜ μ‚¬μš©μ΄ κ°€λŠ₯ν•œ λ§Œλ³‘ν†΅μΉ˜μ•½ 같은 방법은 μ—†λ‹€. μ–Έμ œλ‚˜ κ·Έλž¬λ“― ν˜„μž¬ μ‹œμŠ€ν…œ(xml config 방식)에 κ°€μž₯ μ΅œμ ν™”λœ 방법, 그리고 java config λ°©μ‹μ—μ„œλ„ μ‚¬μš©μ΄ κ°€λŠ₯할것 같은 방법을 생각해 λ³΄μ•˜λ‹€.

무쀑단 배포λ₯Ό κ°€λŠ₯μΌ€ ν•˜λŠ” 3κ°€μ§€ 핡심

1. 배포λ₯Ό 맀번 μƒˆλ‘œμš΄ κ²½λ‘œμ— λ°°ν¬ν•œλ‹€. 각 νšŒμ‚¬λ§ˆλ‹€, 그리고 μ„œλΉ„μŠ€λ§ˆλ‹€ 정말 λ‹€μ–‘ν•œ 배포 μ‹œμŠ€ν…œμ΄ μžˆλ‹€. κ·Έλ“€μ˜ 곡톡점은 μ›κ²©μ„œλ²„μ˜ νŠΉμ • κ²½λ‘œμ— λΉŒλ“œλœ νŒŒμΌλ“€μ„ λ°€μ–΄ λ„£μ–΄μ€€λ‹€λŠ” 것. μ‹œλ‚˜λ¦¬μ˜€λŠ” λ‹€μŒκ³Ό κ°™λ‹€.

  1. λ°°ν¬ν• λ•Œλ§ˆλ‹€ λ³„λ„μ˜ 디렉토리λ₯Ό μƒμ„±ν•œλ’€ 심볼릭 링크λ₯Ό μ—°κ²°ν•΄μ€€λ‹€.
  2. λ°°ν¬λŠ” 1μ—μ„œ μ—°κ²°ν•œ 심볼릭 링크에 λ°°ν¬λ˜λ„λ‘ μ„€μ •, κ²°κ΅­ 맀번 λ§Œλ“€μ–΄μ§€λŠ” 디렉토리에 배포가 되게 λœλ‹€.

μ—¬κΈ°μ„œ μ€‘μš”ν•œμ μ€ “배포할 λ•Œλ§ˆλ‹€ μƒˆλ‘œμš΄ 디렉토리에 배포가 λœλ‹€” 와 λ°°ν¬μ‹œμ—λŠ” 항상 심볼릭 λ§ν¬μ—λ§Œ 배포λ₯Ό ν•˜λ©΄ 되기 λ•Œλ¬Έμ— “λ°°ν¬μ‹œμŠ€ν…œμ΄ μƒˆλ‘œ λ§Œλ“€μ–΄μ§€λŠ” λ””λ ‰ν† λ¦¬μ˜ 경둜λ₯Ό λͺ°λΌλ„ λ¬΄λ°©ν•˜λ‹€"λŠ” 점이닀.

#!/bin/sh
cd /~~~/deploy/

# μž„μ‹œ 디렉토리
DIRECTORY_NAME=batch_$(/bin/date +%Y%m%d%H%M%S)
mkdir $DIRECTORY_NAME

μœ„ μ‰˜ 슀크립트λ₯Ό μ‹€ν–‰ν•˜λ©΄ batch_20191012205218 와 같은 디렉토리가 생성이 λœλ‹€. 심볼릭 링크 κ΄€λ ¨ν•΄μ„œλŠ” λ°”λ‘œ μ•„λž˜ μ΄μ–΄μ„œ μ„€λͺ…ν•˜κ² λ‹€.

2. 심볼릭 링크의 μ›λž˜ 링크λ₯Ό μ¦‰μ‹œ λ³€κ²½ 보톡 심볼릭 링크 (즉, λ°”λ‘œκ°€κΈ°) 의 경둜λ₯Ό λ³€κ²½ν•˜κΈ° μœ„ν•΄μ„œλŠ” μ•„λž˜μ²˜λŸΌ μ§€μ› λ‹€κ°€ μ‚­μ œν•˜λŠ” μ‹μœΌλ‘œ ν–ˆμ—ˆλŠ”λ°

$ mkdir directory_a
$ mkdir directory_b
$ ln -s directory_a asdf
$ ll
asdf -> directory_a
directory_a
directory_b

# directory_a μ—μ„œ directory_b 둜 λ°”κΎΈλŠ” 경우 (심볼릭 링크 자체λ₯Ό μ‚­μ œν•˜κ³  λ‹€μ‹œ 심볼릭 링크 생성)
$ rm asdf
$ ln -s directory_b asdf
$ ll
asdf -> directory_b
directory_a
directory_b

μ΄λ ‡κ²Œ 되면 μ‚­μ œν•˜κ³  ~ λ‹€μ‹œ λ§Œλ“€μ–΄μ§€λŠ” 타이밍에 배포가 λ˜κ±°λ‚˜ 싀행이 λ˜λŠ” 즉, ν•΄λ‹Ή κ²½λ‘œμ— μ—‘μ„ΈμŠ€ ν•˜λŠ” 경우 μ΄μ „μ˜ 경둜λ₯Ό λ°”λΌλ³Έλ‹€κ±°λ‚˜ μ˜λ„ν–ˆλ˜ λ°©μ‹μœΌλ‘œ 싀행이 λ˜μ§€ μ•ŠλŠ” 상황이 λ°œμƒν•œλ‹€. (μ°°λ‚˜μ˜ 타이밍 μ΄μ§€λ§Œ ν•„μžλŠ” μ΄λŸ¬ν•œ 문제둜 μ΄μ „μ˜ 경둜λ₯Ό λ°”λΌλ³΄λŠ” λ¬Έμ œκ°€ λ°œμƒν–ˆμ—ˆλ‹€.) κ·Έλž˜μ„œ ln 의 μ˜΅μ…˜μ€‘μΈ -Tfsμ˜΅μ…˜μœΌλ‘œ μ¦‰μ‹œ 변경을 해주도둝 ν•˜μž. (ln man μ°Έκ³ )

μš°μ•„ν•œ μŠ€ν”„λ§ 배치 ν…Œν¬μ„Έλ―Έλ‚˜ 정리 및 ν›„κΈ° (by μš°μ•„ν•œ ν˜•μ œλ“€)

μ§€λ‚œμ£Ό μš°μ•„ν•œ ν˜•μ œλ“€μ—μ„œ μ§„ν–‰ν•˜μ˜€λ˜ “9μ›” μš°μ•„ν•œ ν…Œν¬ μ„Έλ―Έλ‚˜ - μš°μ•„ν•œ μŠ€ν”„λ§ 배치” 에 λ‹€λ…€μ™”λ‹€. ν•„μžμ—κ²Œ 이번 9월은 정신이 어디에 μžˆλŠ”μ§€ λͺ¨λ₯Όλ§ŒνΌ λ°”μ˜κ³  νž˜λ“€μ—ˆμ§€λ§Œ μ˜ˆμ „λΆ€ν„° κΆκΈˆν•˜κΈ°λ„ ν–ˆκ³  μš”μ¦˜λ“€μ–΄ 관심을 κ°–λ˜ “배치 μ–΄ν”Œλ¦¬μΌ€μ΄μ…˜"을 μ–΄λ–»κ²Œ ν•˜λ©΄ “μš°μ•„ν•œ 방법"으둜 μ‚¬μš©ν•  수 μžˆμ„μ§€μ— λŒ€ν•΄ μ—¬λŸ¬ 생각듀이 μžˆμ—ˆκΈ°μ— 큰 κΈ°λŒ€λ₯Ό κ°€μ§€κ³  μ§€μ˜₯철을 견디며 μž μ‹€ κ·Όμ²˜μ— μžˆλŠ” μš°μ•„ν•œ ν˜•μ œλ“€ μž‘μ€μ§‘μœΌλ‘œ κ°€κ²Œ λ˜μ—ˆλ‹€. μ–΄λ–€ λ‚΄μš©μ„ λ°œν‘œν•˜μ˜€λŠ”μ§€μ— λŒ€ν•΄ κΈ°μ–΅μž˜ν•˜λŠ” λ˜‘λ˜‘ν•œ μ•΅λ¬΄μƒˆκ°€ λ˜μ–΄ μ •λ¦¬ν•˜κΈ° 보닀 μ£Όμš” ν¬μΈνŠΈμ— λŒ€ν•œ 생각과 ν•¨κ»˜ μ°Έμ—¬λ₯Ό λͺ»ν•œ λΆ„λ“€ μœ„ν•΄μ„œλΌκΈ° 보닀 λ‚΄ 슀슀둜 정리λ₯Ό ν•˜κΈ° μœ„ν•΄ ν¬μŠ€νŒ…μ„ μž‘μ„±ν•΄ 보고자 ν•œλ‹€. (μ΄λ²ˆμ—λ„ λΆˆλŸ¬μ£Όμ…”μ„œ κ°μ‚¬ν•©λ‹ˆλ‹€ ^=^)

인트둜

μ—°μ‚¬μž 뢄은 μ›Œλ‚™μ— 유λͺ…ν•˜μ‹  뢄이라 λ³„λ„μ˜ μ„€λͺ…이 ν•„μš” 없이 μš΄μ˜ν•˜μ‹œλŠ” λΈ”λ‘œκ·Έ μ£Όμ†Œλ‘œ λŒ€μ²΄λ₯Ό ν•΄λ³Έλ‹€. 이번 행사에 μ΄ˆλŒ€λ˜μ‹  뢄듀은 ν•œλ²ˆμ΄λΌλ„ μŠ€ν”„λ§ 배치λ₯Ό 써뢄 뢄듀을 λŒ€μƒμœΌλ‘œ μ§„ν–‰ν•˜κ²Œ λ˜μ—ˆλ‹€κ³  ν–ˆλŠ”λ° 마침 ν•„μžλ„ νŒ€ λ‚΄μ—μ„œ μš΄μ˜ν•˜κ³  μžˆλŠ” 배치 μ–΄ν”Œλ¦¬μΌ€μ΄μ…˜μ„ 보닀 효율적이고 μš°μ•„ν•˜κ²Œ λ°”κΏ”λ³΄κ³ μž ν•˜λŠ” λ‹ˆμ¦ˆκ°€ μžˆμ—ˆκΈ°μ— μ•„λ§ˆ μ΄ˆλŒ€λœκ²Œ μ•„λ‹κΉŒ μ‹Άλ‹€.

/images/woowabros-spring-batch/small_house.jpg
μ•„κΈ°μžκΈ°ν•œ μš°μ•„ν•œ ν˜•μ œλ“€ 건물 λ‚΄λΆ€

λ”λΆˆμ–΄ λ°œν‘œμ „μ— κ°„λž΅νžˆ νšŒμ‚¬κ°€ μ›ν•˜λŠ” μΈμž¬μ— λŒ€ν•˜μ—¬ μ–ΈκΈ‰ν•΄μ£Όμ…¨λŠ”λ° 그게 μ–΄μ°Œλ‚˜ 곡감이 κ°€λ˜μ§€. μ—­μ‹œ 생각이 남닀λ₯Έ νšŒμ‚¬κ΅¬λ‚˜ ν•˜κ³  λ‹€μ‹œν•œλ²ˆ 생각을.

μžκΈ°λ³΄λ‹€ κ²½ν—˜μ΄ “적은” μ‚¬λžŒμ—κ²Œ “섀득을 λ‹Ήν•  수” μžˆμ–΄μ•Ό ν•˜κ³ , μžκΈ°λ³΄λ‹€ κ²½ν—˜μ΄ “λ§Žμ€ μ‚¬λžŒμ„ 섀득” μ‹œν‚¬ 수 μžˆμ–΄μ•Ό ν•œλ‹€.

기본편

배치 μ–΄ν”Œλ¦¬μΌ€μ΄μ…˜μ΄λž€ μ»΄ν“¨ν„°μ—μ„œ μ‚¬λžŒμ™€ μƒν˜Έμž‘μš©μ—†μ΄ μ΄μ–΄μ§€λŠ” ν”„λ‘œκ·Έλž¨(μž‘μ—…)λ“€μ˜ 싀행이라고 μœ„ν‚€ν”Όλ””μ•„μ— κ°„κ²°&λͺ…λ£Œν•˜κ²Œ μ •λ¦¬λ˜μ–΄ μžˆλ‹€. 그만큼 일반적인 μ›Ή μ–΄ν”Œλ¦¬μΌ€μ΄μ…˜κ³Όμ˜ 차이가 μžˆλŠ”λ° μ›Ή μ–΄ν”Œλ¦¬μΌ€μ΄μ…˜μ€ μ‹€μ‹œκ°„ μ²˜λ¦¬κ°€ 기본이고 μš”μ²­μ— λŒ€ν•œ 응닡을 μ œκ³΅ν•΄μ•Ό ν•˜λ‹ˆ μ•„λ¬΄λž˜λ„ 속도가 μƒλŒ€μ μ΄λ©° QAμ‹œ νŽΈν•œ 뢀뢄이 μžˆλ‹€. 그에 λ°˜ν•΄ 배치 μ–΄ν”Œλ¦¬μΌ€μ΄μ…˜μ€ μ›Ή μ–΄ν”Œλ¦¬μΌ€μ΄μ…˜μ—μ„œ λ§ν•˜λŠ” μš”μ²­μ΄λΌλŠ” κ°œλ…λ³΄λ‹€ ν›„μ†μ²˜λ¦¬μ— 가깝고, 속도 λ˜ν•œ μ ˆλŒ€μ μ΄λ©° QAκ°€ λ³΅μž‘ν•˜λ‹€λŠ”κ²Œ νŠΉμ§•μ΄λ‹€. λ”°λΌμ„œ ν…ŒμŠ€νŠΈμ½”λ“œλŠ” μ›Ή μ–΄ν”Œλ¦¬μΌ€μ΄μ…˜ 보닀 배치 μ–΄ν”Œλ¦¬μΌ€μ΄μ…˜μ΄ 더 ν•„μš”ν•˜λ‹€κ³  λ³Ό 수 μžˆλ‹€. 배치 μ–΄ν”Œλ¦¬μΌ€μ΄μ…˜μ΄ ν•„μš”ν•œ 상황은 크게 λ‘κ°€μ§€λ‘œ λ‚˜λˆ  λ³Ό μˆ˜κ°€ μžˆλ‹€κ³  ν•œλ‹€.

  • 일정 주기둜 μ‹€ν–‰ λ˜μ–΄μ•Ό ν•  λ•Œ
  • μ‹€μ‹œκ°„ μ²˜λ¦¬κ°€ μ–΄λ €μš΄ λŒ€λŸ‰μ˜ 데이터λ₯Ό 처리 ν• λ•Œ

ν‰μ†Œ 첫번째 μƒν™©λ§Œ μƒκ°ν•˜κ³  배치 μ–΄ν”Œλ¦¬μΌ€μ΄μ…˜μ„ μž‘μ„±ν•˜κ³€ ν–ˆμ—ˆλŠ”λ° λ‘λ²ˆμž¬ 상황에 λŒ€ν•΄ 생각에 생각을 더 ν•΄λ³΄λ‹ˆ μŠ€ν”„λ§ 배치λ₯Ό κ°„λ‹¨ν•˜κ²Œλ§Œ (Tasklet) μ‚¬μš©ν•˜κ³  μžˆλŠ”κ±΄ μ•„λ‹Œκ°€ ν•˜λŠ” λ°˜μ„±μ„ 해보곀 ν–ˆλ‹€. (Reader, Processor, Writer λ“± λ‹€μ–‘ν•œ λ ˆμ΄μ–΄κ°€ μžˆλŠ”λ°λ„…)

특히 μŠ€ν”„λ§ λ°°μΉ˜μ—μ„œλŠ” 기본적으둜 λͺ¨λ“  데이터λ₯Ό λ©”λͺ¨λ¦¬μ— μŒ“μ§€ μ•ŠλŠ” μ‘°νšŒλ°©μ‹λΌκ³  ν•œλ‹€. (DBκΈ°μ€€) Paging ν˜Ήμ€ Cursor둜 pageSize만큼만 μ½μ–΄μ˜€κ³  chunkSize만큼만 commit ν•˜λŠ” ν˜•νƒœ. μ΄λŸ¬ν•œ 각 λ ˆμ΄μ–΄λ³„ sizeλ₯Ό 잘 μ‘°μ •ν•˜κΈ°λ§Œ 해도 적은 λ…Έλ ₯으둜 큰 μ„±λŠ₯을 얻을 수 μžˆλŠ” 뢀뢄이 ν”„λ ˆμž„μ›Œν¬λ₯Ό μ‚¬μš©ν•˜λŠ” 이유 μ•„λ‹κΉŒ 라고 생각해본닀.

λ˜ν•œ @JobScope λ‚˜ @StepScopeλŠ” Late Binding 즉 배치 μ–΄ν”Œλ¦¬μΌ€μ΄μ…˜μ΄ μ‹€ν–‰λ˜λŠ” μ‹œμ μ΄ μ•„λ‹ˆλΌ Job 이 μ‹€ν–‰λ λ•Œ 생성이 되기 λ•Œλ¬Έμ— 이λ₯Ό ν™œμš©ν•˜μ—¬ λ™μ μœΌλ‘œ reader / processor / wirter λ ˆμ΄μ–΄λ₯Ό λ§Œλ“€ 수 μžˆλ‹€κ³  ν•œλ‹€.

ν™œμš©νŽΈ

μŠ€ν”„λ§ 배치λ₯Ό μ΄μš©ν•œ 배치 μ–΄ν”Œλ¦¬μΌ€μ΄μ…˜μ΄ 있고 이λ₯Ό μŠ€μΌ€μ₯΄λ§ λ“± 관리λ₯Ό ν•΄μ£ΌλŠ” 도ꡬ듀에 이야기λ₯Ό ν•΄μ£Όμ…¨λ‹€.

  • Cron
    • λ¦¬λˆ…μŠ€λ₯Ό μ–΄λŠμ •λ„ μ‚¬μš©ν•΄λ΄€λ‹€λ©΄ μ•Œλ§Œν•œ λ¦¬λˆ…μŠ€ κΈ°λ³Έ μŠ€μΌ€μ₯΄λ§ ν”„λ‘œκ·Έλž¨μΈ Cron.
    • ν•„μžλ„ Cron 으둜 주기적으둜 μ‹€ν–‰ν•˜λ„λ‘ 섀정해보기도 ν•˜μ˜€μ§€λ§Œ 배치 μ–΄ν”Œλ¦¬μΌ€μ΄μ…˜μ˜ νŠΉμ„±μƒ 둜그 및 μ‹€ν–‰/μ’…λ£Œ λ“± μ œν•œμ‚¬ν•­μ΄ λ§Žμ€ 건 사싀인것 κ°™λ‹€.
  • Spring MVC + API Call
    • μ£Όλ³€μ—μ„œ μ‚¬μš©ν•˜κ³  μžˆλ‹€κ³  ν•˜λ˜ 방식. 이 λ°©μ‹μ˜ μž₯점은 항상 λ– μžˆκΈ° λ•Œλ¬Έμ— μ–΄ν”Œλ¦¬μΌ€μ΄μ…˜ κ΅¬λ™μ‹œκ°„μ΄ λ³„λ„λ‘œ ν•„μš” μ—†λ‹€λŠ” μž₯점이 μžˆμ§€λ§Œ μ „λ°˜μ μΈ 관리가 μ–΄λ €μš΄ 단점이 μžˆλŠ”κ²ƒ κ°™λ‹€.
    • λ¬Όλ‘  울며 겨자먹기 μ‹μœΌλ‘œ 단점을 극볡할 방법은 μ—¬λŸ¬κ°€μ§€κ°€ μžˆκ² μ§€λ§Œ λͺ¨λ“ κ±΄ 항상 Trade off
  • Spring Batch Admin (Deprecated)
    • μ˜ˆμ „ νŒ€λΆ„μ΄ μ•Œλ €μ£Όμ…”μ„œ 잠깐 봀던 뢀뢄이긴 ν•œλ° μ–΄λŠμ‚¬μ΄μ— Deprecated λ˜μ—ˆλ‹€κ³  ν•œλ‹€.
  • Quertz + Admin
    • http://www.quartz-scheduler.org/
    • μ•„μ£Ό μ˜€λž˜μ „μ— 써본 기얡이 μžˆμ§€λ§Œ 배보닀 배꼽이 더 큰 μƒν™©κ°™μ•˜λ˜ νž˜λ“€μ—ˆλ˜ κΈ°μ–΅λ“€λ§Œ λ‚¨μ•„μžˆλŠ” κ΅¬ν˜„λ°©λ²•μΈκ²ƒ κ°™λ‹€. μ—¬λŸ¬ λ ˆμ΄μ–΄λ₯Ό ν˜Όμš©ν•΄μ„œ 쓰닀보면 각 λ ˆμ΄μ–΄κ°„μ˜ μƒν˜Έ μ—°κ²°μ„±μ˜ μœ„λ°°λ˜λŠ” κ²½μš°κ°€ λ§ŽκΈ°μ—…
  • CI Tools (Jenkins / Teamcity λ“±)
    • μ•„λ¬΄λž˜λ„ κ°€μž₯ μΆ”μ²œν• λ§Œν•œκ²Œ CI Tool 인것 κ°™λ‹€. 그쀑에 ν•„μžλ„ JenkinsλΌλŠ” νˆ΄μ„ λ„ˆλ¬΄ μ’‹μ•„ν•˜κ³ .
    • 유료 툴 쀑에 Teamcity λ₯Ό 잠깐 μ–ΈκΈ‰ν•΄μ£Όμ…¨λŠ”λ° μ°Ύμ•„λ³΄λ‹ˆ ν•œλ²ˆμ¦ˆμŒ 써보고 μ‹Άμ„λ§Œν•œ κΈ°λŠ₯듀이 μžˆμ–΄λ³΄μ˜€λ‹€.

Jenkins 의 μž₯점은 말해뭐해 μ •λ„λ‘œ 배치 μ–΄ν”Œλ¦¬μΌ€μ΄μ…˜κ³Ό ꢁ합이 λ„ˆλ¬΄ 잘 λ§žλŠ” νˆ΄μΈκ²ƒ κ°™λ‹€. (λ¬Όλ‘  λ‹€λ₯Έ νˆ΄λ“€λ„ μžˆκ² μ§€λ§Œ ν•„μžκ°œμ·¨λΌ λ„˜μ–΄κ°€λ„λ‘ ν•˜μž.) 특히 μ‹€ν–‰μ‹œ ν•„μš”ν•œ ν”ŒλŸ¬κ·ΈμΈλ“€μ΄ λ‹€μ–‘ν•˜κ²Œ 많이 있고, 싀행방법 λ˜ν•œ μˆ˜λ™/μŠ€μΌ€μ₯΄λ§ 으둜 λ‹€μ–‘ν•˜κ²Œ ν•  μˆ˜κ°€ 있으며 RestAPI 지원과 λ³΄μ•ˆ, 싀행이λ ₯관리, 둜그 λ“± μ΅œμ ν™” λ˜μ–΄μžˆλ‹€κ³  해도 과언이 μ•„λ‹μ •λ„λ‘œ λ‹€μ–‘ν•œ μž₯점듀이 μžˆλŠ”κ²ƒ κ°™λ‹€.

λ„€νŠΈμ›Œν¬ λͺ¨λ‹ˆν„°λ§μ΄ κΆκΈˆν• λ• ? Packetbeat !

λͺ¨λ‹ˆν„°λ§μ€ μ„œλΉ„μŠ€ 둜직 개발 만큼 ν•œλ²ˆμ”© 고민해보고 κ²½ν—˜ν•΄ 봀을 μ€‘μš”ν•œ μ˜μ—­μ΄λΌ ν•  수 μžˆλ‹€. 그쀑 μ›Ήμ„œλ²„μ—μ„œ μ œκ³΅ν•΄μ£ΌλŠ” μ—‘μ„ΈμŠ€ λ‘œκ·ΈλŠ” μš΄μ˜ν•˜κ³  μžˆλŠ” μ›Ήμ„œλΉ„μŠ€μ— λŒ€ν•΄ μ—¬λŸ¬κ°€μ§€ μΈ‘λ©΄μ—μ„œ 뢄석할 수 μžˆλŠ” κ°€μž₯ κ°•λ ₯ν•œ μ•„μ΄ν…œ 쀑에 ν•˜λ‚˜λΌκ³  μƒκ°ν•œλ‹€. 이λ₯Ό 톡해 μ‚¬μš©μžλ“€μ΄ μ–΄λ–€ url을 많이 ν˜ΈμΆœν•˜κ³ , μ–΄λ–€ user-agentν˜•νƒœλ₯Ό μ‚¬μš©ν•˜λŠ”μ§€ μ•Œκ²Œ 되면 그에 따라 μ„œλΉ„μŠ€ μ „λž΅μ„ λ³€κ²½ν• μˆ˜λ„ 있고 μ•…μ˜μ μœΌλ‘œ 곡격적인 μš”μ²­μ— λŒ€ν•΄ μ›Ήμ„œλ²„λ‹¨μ—μ„œ 차단을 ν•  수 있기 λ•Œλ¬Έμ΄λ‹€. μ΄λ ‡κ²Œ inbound νŠΈλž˜ν”½(μ™ΈλΆ€μ—μ„œ λ“€μ–΄μ˜€λŠ” μš”μ²­)에 λŒ€ν•΄μ„œλŠ” μ—‘μ„ΈμŠ€ 둜그λ₯Ό 잘 λΆ„μ„ν•˜λ©΄ 기쑴의 μ›Ή μ–΄ν”Œλ¦¬μΌ€μ΄μ…˜κ³ΌλŠ” μ „ν˜€ λ¬΄κ΄€ν•˜κ²Œ λͺ¨λ‹ˆν„°λ§μ΄ κ°€λŠ₯ν•˜μ§€λ§Œ λ°˜λŒ€λ‘œ outbund νŠΈλž˜ν”½(μ™ΈλΆ€λ‘œ λ‚˜κ°€λŠ” μš”μ²­)에 λŒ€ν•΄μ„œλŠ” μ–΄λ–€μ‹μœΌλ‘œ λͺ¨λ‹ˆν„°λ§μ„ ν•  수 μžˆμ„κΉŒ?

/images/network-monitor-by-packetbeat/passbook.jpg
월급톡μž₯의 inbound νŠΈλž˜ν”½λ³΄λ‹€ outbound νŠΈλž˜ν”½μ΄ λ„ˆλ¬΄ λ§Žμ€ μš”μ¦˜…
이미지 좜처 : https://www.app24moa.com/feedDetail/2/2002

예컨데, 날씨 μ„œλΉ„μŠ€λ₯Ό ν•˜κΈ° μœ„ν•΄ μ™ΈλΆ€μ—μ„œ μ„œμšΈλ‚ μ”¨λΌλŠ” νŽ˜μ΄μ§€λ₯Ό μ‘°νšŒν–ˆμ„ 경우 기상청 APIμ—μ„œ λ„˜κ²¨λ°›μ€ 데이터λ₯Ό κ°€κ³΅ν•˜μ—¬ 보여쀀닀고 κ°€μ •ν•΄λ³΄μž. μ΄λ•Œ κΈ°μƒμ²­μ—μ„œ μ œκ³΅ν•΄μ£ΌλŠ” νŠΉμ • API쀑에 μ–΄λŠ ν•˜λ‚˜κ°€ 늦게 응닡이 μ˜¨λ‹€κ±°λ‚˜, νŠΉμ •μ‹œκ°„λŒ€μ— μ—λŸ¬μ‘λ‹΅μ„ λ°›μ„κ²½μš° κ³Όμ—° 이λ₯Ό μ–΄λ–€μ‹μœΌλ‘œ λͺ¨λ‹ˆν„°λ§ ν• μˆ˜ μžˆμ„κΉŒ? μ–΄ν”Œλ¦¬μΌ€μ΄μ…˜ μ½”λ“œμ— λͺ¨λ‹ˆν„°λ§μ„ μœ„ν•œ μ½”λ“œλ₯Ό μΆ”κ°€ν•  것인가? 혹 ν•˜λ‚˜μ˜ μ„œλ²„μ—μ„œ Aλͺ¨λ“ˆμ€ java둜, Bλͺ¨λ“ˆμ€ python으둜 κ°œλ°œλ˜μ—ˆμ„ 경우 각각 λͺ¨λ“ˆλ§ˆλ‹€ λͺ¨λ‹ˆν„°λ§μ„ μœ„ν•œ μ½”λ“œλ₯Ό μΆ”κ°€ν•˜λŠ” μ‹μœΌλ‘œ ν•˜λ‹€λ³΄λ©΄ λΉ„μ§€λ‹ˆμŠ€ λ‘œμ§μ„ λ°©ν•΄ν•˜κ±°λ‚˜ 였히렀 μΆ”κ°€ν•œ μ½”λ“œ λ˜ν•œ 관리해야 ν•˜λŠ” 배보닀 배꼽이 더 컀져버릴 상황도 μƒκΈΈμˆ˜ μžˆλ‹€. μ–΄ν”Œλ¦¬μΌ€μ΄μ…˜μ˜ λΉ„μ§€λ‹ˆμŠ€ λ‘œμ§κ³ΌλŠ” λ¬΄κ΄€ν•˜κ²Œ μ„œλ²„ μžμ²΄μ—μ„œ μ™ΈλΆ€λ‘œ λ‚˜κ°€λŠ” λ„€νŠΈμ›Œν¬ νŠΈλž˜ν”½μ— λŒ€ν•΄ λͺ¨λ‹ˆν„°λ§μ„ ν•  수 μžˆλŠ” κ°€λ²Όμš°λ©΄μ„œλ„ μ‹¬ν”Œν•œ λͺ¨λ“ˆμ„ μ°Ύκ³  μ‹Άμ—ˆλ‹€. μ–΄ν”Œλ¦¬μΌ€μ΄μ…˜μ˜ κ°œλ°œμ–Έμ–΄κ°€ 무엇이든 상관없이 λ³„λ„μ˜ μ—μ΄μ „νŠΈ ν˜•μ‹μœΌλ‘œ λ„μ›Œλ‘κΈ°λ§Œ ν•˜λ©΄ λ„€νŠΈμ›Œν¬ νŠΈλž˜ν”½μ„ μˆ˜μ§‘ 및 뢄석, λ‚˜μ•„κ°€μ„œλŠ” λͺ¨λ‹ˆν„°λ§κΉŒμ§€ ν• μˆ˜μžˆλŠ”… κ·Έλž˜μ„œ μ°Ύλ‹€λ³΄λ‹ˆ μ—­μ‹œλ‚˜ μ΄λŸ¬ν•œ 고민을 λˆ„κ΅°κ°€λŠ” ν•˜κ³  μžˆμ—ˆκ³  μ˜€ν”ˆμ†ŒμŠ€κΉŒμ§€ λ˜μ–΄μžˆλŠ” Elastic Stack 의 Beat쀑 PacketbeatλΌλŠ” 데이터 μˆ˜μ§‘λͺ¨λ“ˆμ„ μ•Œκ²Œ λ˜μ—ˆλ‹€.

μ—­μ‹œ λ‚΄κ°€ ν•˜κ³ μžˆλŠ” 고민은 이미 λˆ„κ΅°κ°€ ν–ˆλ˜ κ³ λ―Όλ“€… μ΄λŸ¬ν•œ 고민에 λŒ€ν•΄ ν•΄κ²°ν•˜λŠ” 방법을 보닀 빨리 μ°ΎλŠ”κ²Œ 경쟁λ ₯이 될텐데…

이번 ν¬μŠ€νŒ…μ—μ„œλŠ” Packetbeat 에 λŒ€ν•΄ κ°„λ‹¨νžˆ μ•Œμ•„λ³΄κ³  이λ₯Ό ν™œμš©ν•˜μ—¬ outbound νŠΈλž˜ν”½μ— λŒ€ν•΄ λͺ¨λ‹ˆν„°λ§μ„ 해보며 μ–΄λ–€μ‹μœΌλ‘œ ν™œμš©ν•  수 μžˆλŠ”μ§€μ— λŒ€ν•΄ μ•Œμ•„λ³΄κ³ μž ν•œλ‹€.

Packetbeat ?

ElasticStack 쀑에 데이터 μˆ˜μ§‘κΈ° ν”Œλž«νΌμΈ Beats쀑 λ„€νŠΈμ›Œν¬ νŠΈλž˜ν”½ 데이터에 λŒ€ν•΄ μˆ˜μ§‘μ„ ν•  수 μžˆλŠ” 데이터 μˆ˜μ§‘κΈ°λ₯Ό μ œκ³΅ν•˜κ³  μžˆλ‹€. pcap라이브러리λ₯Ό μ΄μš©ν•˜μ—¬ μ„œλ²„μ˜ λ„€νŠΈμ›Œν¬ λ ˆλ²¨μ—μ„œ 데이터λ₯Ό μˆ˜μ§‘ 및 λΆ„μ„ν•œ ν›„ μ™ΈλΆ€λ‘œ(Elasticsearch, Logstash, Kafka λ“±) μ „μ†‘ν•΄μ£ΌλŠ” κ²½λŸ‰ λ„€νŠΈμ›Œν¬ νŒ¨ν‚· 뢄석기라고 곡식 ν™ˆνŽ˜μ΄μ§€μ— μ†Œκ°œλ˜κ³  μžˆλ‹€. λͺ‡λ²ˆ μ‚¬μš©ν•΄λ³΄λ©΄μ„œ λŠλ‚€ μž₯점듀은 λ‹€μŒκ³Ό κ°™λ‹€.

  • μ„€μΉ˜ 및 싀행이 λ„ˆλ¬΄ κ°„λ‹¨ν•˜λ‹€.
  • μ„€μ •κ°’ νŠœλ‹μ„ 톡해 κ°„λ‹¨ν•˜μ§€λ§Œ, κ·ΈλŸ¬ν•œ 간단함에 λΉ„ν•΄μ„œ λ„ˆλ¬΄ κ°•λ ₯ν•œ μˆ˜μ§‘μ΄ κ°€λŠ₯ν•˜λ‹€.
  • μ•žμ„œ 이야기 ν–ˆλ˜ μ–΄ν”Œλ¦¬μΌ€μ΄μ…˜ μ½”λ“œμ™€λŠ” μ „ν˜€ λ¬΄κ΄€ν•˜κ²Œ μž‘λ™ν•œλ‹€.

무엇을 해볼것인가?! (a.k.a. λͺ©ν‘œ)

ν•„μžκ°€ μš΄μ˜ν•˜λŠ” Daily-DevBlog λΌλŠ” μ„œλΉ„μŠ€κ°€ μžˆλ‹€. (κ°‘λΆ„ μ„œλΉ„μŠ€ 홍보) μ—¬λŸ¬ μ‚¬λžŒλ“€μ˜ rssλ₯Ό μ‘°νšŒν•˜κ³  νŒŒμ‹±ν•΄μ„œ 메일을 λ³΄λ‚΄μ£ΌλŠ” μ„œλΉ„μŠ€ 인데, packetbeat μ‚¬μš© μ˜ˆμ‹œλ₯Ό λ“€κΈ°μœ„ν•΄ 쑰금 λ³€ν˜•ν•˜μ—¬ λͺ¨λ“  rssλ₯Ό μ ‘κ·Όν•˜κ³  κ°€μž₯ μ΅œμ‹ κΈ€μ˜ 제λͺ©μ„ 좜λ ₯ν•˜λŠ” μ•„μ£Ό κ°„λ‹¨ν•œ python 슀크립트둜 outbound νŠΈλž˜ν”½μ„ λ°œμƒμ‹œμΌœ 보고자 ν•œλ‹€. 그리고 packetbeat λ₯Ό μ΄μš©ν•˜μ—¬ μ™ΈλΆ€λ‘œ ν˜ΈμΆœλ˜λŠ” νŠΈλž˜ν”½μ„ μˆ˜μ§‘ν•˜κ³  Elasticsearch 둜 인덱싱 ν•˜μ—¬ μ΅œμ’…μ μœΌλ‘œλŠ” μ–΄λŠ rss의 속도가 κ°€μž₯ λŠλ¦°μ§€ μ‹€ν–‰λ˜λŠ” pythonμ½”λ“œμ™€λŠ” μ „ν˜€ 관련없이 λͺ¨λ‹ˆν„°λ§ ν•΄λ³΄κ³ μž ν•œλ‹€. python μ½”λ“œλŠ” λ‹€μŒκ³Ό κ°™λ‹€.

참고둜 ν•„μžλŠ” awesome-devblog의 μš΄μ˜μžλΆ„κ»˜ ν•΄λ‹Ή 데이터 μ‚¬μš©μ— λŒ€ν•΄ ν—ˆλ½μ„ 받은 μƒνƒœμ΄λ‹€.

import requests, yaml, feedparser

blog_info_list_yml_url = 'https://raw.githubusercontent.com/sarojaba/awesome-devblog/master/db.yml'
blog_info_list_yml = requests.get(url=blog_info_list_yml_url).text
blog_info_yaml_parse_list = yaml.load(blog_info_list_yml)

for blog_info in blog_info_yaml_parse_list :
    if 'rss' not in blog_info.keys() or not blog_info['rss']:
        continue
    rss_url = blog_info['rss']
    try :
        parse_feed = feedparser.parse(rss_url)
    except :
        continue

    parse_feed_data =  parse_feed.entries[0]
    print(blog_info['name'], '|', parse_feed_data['title'], '|', parse_feed_data['link'])

μœ„ μ½”λ“œλ₯Ό μ‹€ν–‰ν•˜λ©΄ μ•„λž˜μ²˜λŸΌ μ•„μ£Ό κ°„λ‹¨ν•˜κ²Œ λΈ”λ‘œκ·Έ 주인의 이름과 μ΅œμ‹ κΈ€ 제λͺ©, 링크가 좜λ ₯이 λœλ‹€.

/images/network-monitor-by-packetbeat/rss_python_script.jpg
그러고 λ³΄λ‹ˆ λ„ˆλ¬΄ μ˜€λžœλ§Œμ— κΈ€μ“°λ„€… (μˆ™μ—°)

백문이 λΆˆμ—¬μΌκ²¬? 백견이 λΆˆμ—¬μΌνƒ€!

μ–Έμ œ μ–΄λ””μ„œλΆ€ν„° 유래된 이야기 μΈμ§€λŠ” λͺ¨λ₯΄μ§€λ§Œ “백번 λ“£λŠ”κ²ƒμ΄ ν•œλ²ˆ λ³΄λŠ”κ²ƒλ³΄λ‹€ λͺ»ν•˜κ³ , 백번 λ³΄λŠ”κ²ƒμ΄ ν•œλ²ˆ νƒ€μž μΉ˜λŠ”κ²ƒλ³΄λ‹€ λͺ»ν•˜λ‹€” λΌλŠ” κ°œλ°œλ²„μ „ 속담이 μžˆλ‹€. 자, μœ„μ—μ„œ μ •μ˜ν•œ λͺ©ν‘œλ₯Ό 이루기 μœ„ν•΄ μ‹€μ œλ‘œ 각쒅 λͺ¨λ“ˆμ„ μ„€μΉ˜ν•΄ 보도둝 ν•˜μž! ( ν•„μžκ°€ ν…ŒμŠ€νŠΈ ν–ˆλ˜ μ„œλ²„μ˜ ν™˜κ²½μ€ CentOS 7.4 64Bit μ΄λ‹ˆ μ°Έκ³  )

μ•„νŒŒμΉ˜ λ‘œλ“œλ°ΈλŸ°μ‹±μœΌλ‘œ μ—¬λŸ¬ WAS μš΄μ˜ν•˜κΈ°

μ›Ήμ„œλ²„ ν•˜λ‚˜λ§Œ μ‚¬μš©ν•˜κ±°λ‚˜ WAS ν•˜λ‚˜λ§Œμ„ μ‚¬μš©ν•˜λ©° μ›Ήμ„œλΉ„μŠ€λ₯Ό μš΄μ˜ν•˜λŠ” κ²½μš°λŠ” 극히 λ“œλ¬Όλ‹€. μ›Ήμ„œλ²„μ˜ μž₯점과 WAS의 μž₯점 κ·Έ λ‘λ§ˆλ¦¬μ˜ 토끼λ₯Ό λ‹€ 작기 μœ„ν•΄ 보톡 μ•žλ‹¨μ— μ›Ήμ„œλ²„λ₯Ό 두고 κ·Έ 뒀에 WASλ₯Ό 두며 μ„œλΉ„μŠ€λ₯Ό μš΄μ˜ν•˜κ³€ ν•œλ‹€. ν—Œλ° μš΄μ˜ν•˜λŠ” μ„œλΉ„μŠ€κ°€ 인기가 λ§Žμ•„μ Έ(?) μ‚¬μš©λŸ‰μ΄ λ§Žμ•„μ§€λ‹€λ©΄ 그만큼 응닡이 느렀 (TPS λ“±) μ„œλ²„λ₯Ό λŠ˜λ €μ•Ό ν•˜λŠ” 상황이 생긴닀고 κ°€μ •ν•΄λ³΄μž. (λ¬Όλ‘  μ„œλ²„λ₯Ό λŠ˜λ¦¬λŠ” 것보닀 μΊμ‹œλ₯Ό μ μš©ν•˜κ±°λ‚˜ λ‘œμ§μ„ λ°”κΏ”λ³΄λŠ” λ…Έλ ₯이 μ„ ν–‰λ˜μ•Ό ν•˜κ² μ§€λ§Œ…) λ‹Ήμ—°νžˆ μ„œλ²„λΆ€ν„° κ΅¬λ§€ν•˜λ©° “Scale Out"을 ν•˜λ €κ³  할것이닀. λ§Œμ•½ μ›λž˜ μš΄μ˜ν•˜λ˜ μ„œλ²„κ°€ λ„ˆλ¬΄ μ’‹μ•„μ„œ CPUλ‚˜ λ©”λͺ¨λ¦¬ μ‚¬μš©λ₯ μ΄ 거의 λ°”λ‹₯이여도 μ„œλ²„λ₯Ό ꡬ맀해야 ν• κΉŒ? μ„œλ²„λ₯Ό κ΅¬λ§€ν•˜κ²Œλ˜λ©΄ κ²°κ΅­ λ‘κ°œ μ΄μƒμ˜ μ„œλ²„κ°€ μš΄μ˜λ ν…λ° κ·Έ μ„œλ²„λ“€μ„ μ•žμ—μ„œ λ¬Άμ–΄μ£Όλ©° νŠΈλž˜ν”½μ„ λΆ„μ‚°μ‹œμΌœμ£ΌλŠ” 무언가가 ν•„μš”ν•˜λ‹€. κ·ΈλŸ¬ν•œ κΈ°μˆ μ„ λ°”λ‘œ λ‘œλ“œλ°ΈλŸ°μ‹± 이라고 ν•œλ‹€. 톡상 L4 μŠ€μœ„μΉ˜λ₯Ό ν™œμš©ν•˜μ—¬ μš”μ²­μ„ μ—¬λŸ¬ μ„œλ²„λ“€λ‘œ λΆ„μ‚°μ‹œν‚€λ©° μ‚°μˆ μ μœΌλ‘œλŠ” μ„œλ²„ λŒ€μˆ˜λ§ŒνΌ μ„±λŠ₯이 μ’‹μ•„μ§€λŠ” 효과λ₯Ό λ³Ό 수 μžˆλ‹€. ν•˜μ§€λ§Œ μ•žμ„œ λ§ν–ˆλ“― μ„œλ²„μ˜ μžμ› μ‚¬μš©λ₯ μ΄ λ°”λ‹₯일 μ •λ„λ‘œ 거의 μ‚¬μš©μ„ μ•ˆν• κ²½μš° μ„œλ²„λ₯Ό κ΅¬λ§€ν•˜λŠ”κ±΄ λ„ˆλ¬΄λ‚˜ λΉ„νš¨μœ¨μ μ΄λ‹€. 이번 ν¬μŠ€νŒ…μ—μ„œλŠ” μ„œλ²„λ₯Ό λŠ˜λ¦¬μ§€ μ•ŠμœΌλ©΄μ„œ μ›Ήμ„œλ²„ 쀑 μ•„νŒŒμΉ˜λ₯Ό ν™œμš©ν•˜μ—¬ μ—¬λŸ¬ WASλ₯Ό μš΄μ˜ν•˜λŠ” 방법에 λŒ€ν•΄ μ•Œμ•„λ³΄κ³ μž ν•œλ‹€. μ„œλ²„ λŠ˜λ €μ•Ό ν•˜λŠ” μƒν™©μ—μ„œ μ‚¬μš©ν•΄ λ³Ό 수 μžˆλŠ” λ‚˜λ§Œμ˜ 쒋은 무기(?)κ°€ μƒκΈ΄κ²Œ μ•„λ‹κΉŒ 생각이 λ“ λ‹€.

μ•„νŒŒμΉ˜λŠ” EOL이 λ˜μ—ˆκΈ° λ•Œλ¬Έμ— 2.4λ²„μ „μœΌλ‘œ μ„€μΉ˜ν•˜κ³ , WASλŠ” νŽΈμ˜μƒ ν†°μΌ“ μ΅œμ‹ λ²„μ „μœΌλ‘œ μ„€μΉ˜ν•΄μ„œ λ™μΌν•œ μ„œλ²„μ— μ•„νŒŒμΉ˜ ν•œλŒ€μ™€ ν†°μΌ“ 3λŒ€λ₯Ό μ—°λ™ν•˜λŠ”κ²ƒμ„ λͺ©μ μœΌλ‘œ ν•œλ‹€. λ‘œλ“œλ°ΈλŸ°μ‹±μ΄ μ–΄λ–€μ‹μœΌλ‘œ 이루어 μ§€κ³  ν•˜μœ„μ— μ—°κ²°λœ 톰켓을 컨트둀 ν•˜λŠ” 방법 λ˜ν•œ μ•Œμ•„λ³Ό μ˜ˆμ •μ΄λ‹€.

μ„œλ²„ ν™˜κ²½ 및 μ„€μΉ˜ν•˜κ²Œ 될 각 버전은 λ‹€μŒκ³Ό κ°™λ‹€. μ„œλ²„ : CentOS 7.4 64Bit apache : httpd-2.4.39 tomcat : apache-tomcat-8.5.43 tomcat-connectors(mod_jk) : 1.2.46

Apache 와 Tomcat μ„€μΉ˜

ν•„μžμ˜ ν¬μŠ€νŒ…μ—μ„œ μ’…μ’… λ‚˜μ˜€λŠ” 뢀뢄이기도 ν•˜κ³ , ꡬ글링 해보면 λ°”λ‘œ μ„€μΉ˜ 방법을 μ‰½κ²Œ 찾을 수 μžˆκ² μ§€λ§Œ κ·Έλ ‡λ‹€κ³  언급을 μ•ˆν•˜κ³  λ„˜μ–΄κ°€κΈ°μ—” λ„ˆλ¬΄ λΆˆμΉœμ ˆν•˜λ‹ˆ… μΉ˜νŠΈν‚€μ²˜λŸΌ(?) λΉ λ₯΄κ²Œ μ •λ¦¬ν•΄λ³΄μž.

  • Apache
$ wget http://apache.tt.co.kr//httpd/httpd-2.4.39.tar.gz
$ tar -zxvf httpd-2.4.39.tar.gz
$ ./configure --prefix=/home/~~~/apache
$ make && make install
$ cd /home/~~~/apache/bin
$ sudo chown root:계정λͺ… httpd
$ sudo chmod +s httpd
$ vi /home/~~~/apache/conf/httpd.conf
User 계정λͺ…
Grop 계정λͺ…
$ /home/~~~/apache/bin/apachectl start ← μ‹€ν–‰

μ΄λ ‡κ²Œ μ„€μΉ˜λ₯Ό ν•œλ’€ 싀행을 μ‹œν‚€κ³  μ„œλ²„μ˜ ipλ₯Ό 접속해보면 μ•„λž˜μ™€ 같은 화면을 λ³Ό 수 μžˆλ‹€.

  • Tomcat
$ wget http://mirror.apache-kr.org/tomcat/tomcat-8/v8.5.43/bin/apache-tomcat-8.5.43.tar.gz
$ tar -zxvf apache-tomcat-8.5.43.tar.gz
$ /home/apache-tomcat-8.5.43/bin/start.sh ← μ‹€ν–‰

ν†°μΌ“μ˜ κΈ°λ³Έ http 포트인 8080으둜 접속을 해보면 κ·€μ—¬μš΄ 고양이가 μžˆλŠ” ν†°μΌ“ 기본화면을 λ³Ό 수 μžˆλ‹€.

μ•„νŒŒμΉ˜μ™€ ν†°μΌ“ μ—°λ™ν•˜κΈ°

μ•„νŒŒμΉ˜μ™€ ν†°μΌ“μ˜ 연동은 mod_jk 와 mod_proxy λ“± λ‹€μ–‘ν•œ λͺ¨λ“ˆλ‘œ 연동을 ν•  수 μžˆλŠ”λ° 이번 ν¬μŠ€νŒ…μ—μ„œλŠ” mod_jk λ₯Ό ν™œμš©ν•˜λŠ” 방법에 λŒ€ν•΄ μ•Œμ•„λ³΄κ³ μž ν•œλ‹€. μš°μ„  mod_jk λ₯Ό μ„€μΉ˜ν•˜μž.

κ°„λ‹¨νžˆ mod_jk λŠ” 컴파일, μ„€μ • λ“± λ³΅μž‘ν•˜μ§€λ§Œ ν†°μΌ“ μ „μš© λ°”μ΄λ„ˆλ¦¬ ν”„λ‘œν† μ½œμΈ AJPλ₯Ό μ‚¬μš©ν•˜κΈ° λ•Œλ¬Έμ— 높은 μ„±λŠ₯을 κΈ°λŒ€ν• μˆ˜κ°€ μžˆλ‹€. mod_proxy λŠ” 반면 기본으둜 μ•„νŒŒμΉ˜μ— νƒ‘μž¬λ˜μ–΄μžˆλŠ” λͺ¨λ“ˆμ΄κΈ° λ•Œλ¬Έμ— λ³„λ„μ˜ λͺ¨λ“ˆ μ„€μΉ˜κ°€ ν•„μš” μ—†κ³  섀정도 κ°„λ‹¨ν•˜λ‹€λŠ” μž₯점이 μžˆλ‹€. 각 μ—°λ™λ°©μ‹μ˜ μž₯단점이 있기 λ•Œλ¬Έμ— 본인이 μš΄μ˜ν•˜λŠ” μ„œλ²„ 상황에 λ§žμΆ”μ–΄ 적용 ν•  ν•„μš”κ°€ μžˆλ‹€.

  • mod_jk μ„€μΉ˜
$ wget http://apache.tt.co.kr/tomcat/tomcat-connectors/jk/tomcat-connectors-1.2.46-src.tar.gz
$ tar -zxvf tomcat-connectors-1.2.46-src.tar.gz
$ cd tomcat-connectors-1.2.46-src/native
$ ./configure --with-apxs=/home/~~~/apache/bin/apxs
$ make && make install
$ /home/~~~/apache/modules ν•˜μœ„μ— mod_jk.soκ°€ 생김

mod_jk λ₯Ό ν™œμš©ν•˜λ©΄ AJPλΌλŠ” ν†΅μ‹ μœΌλ‘œ μ•„νŒŒμΉ˜μ™€ 톰켓이 μ—°λ™λ˜λŠ”λ° ν†°μΌ“μ˜ κΈ°λ³Έ AJP ν¬νŠΈλŠ” 8009λ²ˆμž„μ„ μ•Œκ³  λ‹€μŒμ²˜λŸΌ 섀정을 ν•΄μ£Όμž.

  • apache/conf/workers.properties
worker.list=tomcat1
worker.tomcat1.port=8009
worker.tomcat1.host=localhost
worker.tomcat1.type=ajp13
worker.tomcat1.lbfactor=1
  • apache/conf/httpd.conf
LoadModule jk_module modules/mod_jk.so
<IfModule jk_module>
    JkWorkersFile    conf/workers.properties
    JkLogFile        logs/mod_jk.log
    JkLogLevel       info
    JkMount /* 	tomcat1
</IfModule>

μ΄λ ‡κ²Œ ν•˜κ³ μ„œ μ•„νŒŒμΉ˜μ™€ 톰켓을 μž¬μ‹œμž‘ 후에 μ„œλ²„μ˜ ip둜 접속해보면 (λ³„λ„μ˜ port 없이) ν†°μΌ“ μ„€μ •νŽ˜μ΄μ§€λ‘œ λžœλ”©μ΄ λ˜λŠ”κ²ƒμ„ 확인할 수 μžˆλ‹€.

λ‘œλ“œλ°ΈλŸ°μ‹±μ„ μœ„ν•œ μž‘μ—…

μ—¬κΈ°κΉŒμ§€λŠ” λ³Έ ν¬μŠ€νŒ…μ„ μž‘μ„±ν•˜κΈ° μœ„ν•œ 밑거름이라고 말할 수 μžˆλ‹€. 이제 μ‹€μ œλ‘œ λ‘œλ“œλ°ΈλŸ°μ‹±μ„ ν•΄λ³Ό μ°¨λ‘€. μ•žμ„œ ν†°μΌ“ ν•˜λ‚˜λ§Œ μ„€μΉ˜ν–ˆλŠ”λ° νŽΈμ˜μƒ ν†°μΌ“ 3개λ₯Ό μ„€μΉ˜ν•΄λ‘μž. (ν•˜λ‚˜λ₯Ό μ„€μΉ˜ν•˜κ³  cp -r λͺ…λ Ήμ–΄λ₯Ό ν™œμš©ν•˜λŠ”κ²Œ λΉ λ₯΄λ‹€.) κ·Έ λ‹€μŒ 각 ν†°μΌ“μ˜ λͺ¨λ“  포트λ₯Ό μ…‹λ‹€ λ‹€λ₯΄κ²Œ μ„€μ •ν•΄μ•Ό ν•˜λŠ”λ° κ²ΉμΉ˜μ§€ μ•Šλ„λ‘ μ„€μ •ν•΄ 두고 (ν•„μžλŠ” μ•žμžλ¦¬λ₯Ό 1,2,3 μ΄λŸ°μ‹μœΌλ‘œ λ‹€λ₯΄κ²Œ μ„€μ •ν•˜μ˜€λ‹€.) μ›Œμ»€(workers.properties)λ₯Ό μ•„λž˜μ²˜λŸΌ μ„€μ •ν•΄μ£Όμž.

μŠ€ν”„λ§μ„ ν™œμš©ν•œ λŒ€μš©λŸ‰ 파일 μ—…λ‘œλ“œ κ΅¬ν˜„

κ°œλ°œμ„ ν•˜λ‹€λ³΄λ©΄ μ‹€μ œλ‘œ 직접 κ΅¬ν˜„μ„ 해본적은 μ—†μ§€λ§Œ μ—¬κΈ°μ €κΈ°μ„œ λ“€μ–΄λ³Έ 지식과 κ·Έ λ™μ•ˆμ˜ 짬λ°₯(?)으둜 μΆ”μΈ‘ν•΄λ³Όμˆ˜ μžˆλŠ” 뢀뢄듀이 μžˆλ‹€. λ¬Όλ‘  λͺ¨λ“ μΌμ— 정닡은 μ—†κ² μ§€λ§Œ μš”μ¦˜ λŠλΌλŠ”κ±΄ μ±…μ—μ„œ κ³΅λΆ€λ§Œ 해본것과 λ‹€λ₯Έ λΈ”λ‘œκ·Έλ“€μ—μ„œ 눈으둜만 보고 λ„˜μ–΄κ°€λŠ”κ²ƒλ“€ 그리고 직접 손가락을 움직여가며 μ™œ μ—¬κΈ°μ„œλŠ” 이 방법을 μ‚¬μš©ν•˜μ§€ κ³ λ―Όν•˜λ©΄μ„œ κ΅¬ν˜„μ„ ν•΄λ³Έλ‹€λŠ”κ±΄ 정말 μ—„μ²­λ‚˜κ²Œ 큰 차이가 μžˆλŠ”κ²ƒ κ°™λ‹€. μ›Ή μ–΄ν”Œλ¦¬μΌ€μ΄μ…˜μ„ κ°œλ°œν•˜λ‹€λ³΄λ©΄ ν•œλ²ˆ μ―€ λ§Œλ‚˜κ²Œ λ˜λŠ” 파일 μ—…λ‘œλ“œ κΈ°λŠ₯. ν•„μžλ„ λͺ‡λ²ˆ κ΅¬ν˜„μ€ ν•΄λ΄€μ§€λ§Œ κ·Έλƒ₯ λ‹¨μˆœνžˆ κ΅¬ν˜„λ§Œ ν•΄λ³Έ μƒνƒœμ˜€λ‹€κ°€ μ΅œκ·Όμ— κ·Έλƒ₯ 파일 μ—…λ‘œλ“œκ°€ μ•„λ‹Œ λŒ€μš©λŸ‰ 파일 μ—…λ‘œλ“œμ—μ„œμ˜ λ¬Έμ œκ°€ λ°œμƒν•˜μ—¬ μ—¬κΈ°μ €κΈ° μ‚½μ§ˆμ„ ν•˜κ²Œ λ˜μ—ˆκ³  정리도 ν•΄λ³Όκ²Έ μŠ€ν”„λ§μ—μ„œμ˜ λŒ€μš©λŸ‰ 파일 μ—…λ‘œλ“œμ‹œ ν•œλ²ˆμ―€ 고렀해봐야 ν•  뢀뢄에 λŒ€ν•΄ 정리λ₯Ό 해보렀고 ν•œλ‹€.

λ¬Όλ‘  κ΅¬κΈ€μ—μ„œ 검색을 해보면 μ•„λ§ˆ ν•„μžκ°€ 쓴것 보닀 더 μžμ„Έν•˜κ³  쒋은 글듀이 μžˆκ² μ§€λ§Œ ν•„μžλŠ” 보닀 λŒ€μš©λŸ‰μ— μ§‘μ€‘μ—μ„œ μž‘μ„±ν•΄ 보고자 ν•œλ‹€. λͺ…μ‹¬ν•˜μž. “아무리 흐린 μž‰ν¬λΌλ„ 쒋은 κΈ°μ–΅λ ₯보닀 λ‚«λ‹€” λΌλŠ” 말이 μžˆλ“―μ΄

μŠ€ν”„λ§μ„ ν™œμš©ν•œ 파일 μ—…λ‘œλ“œ κ΅¬ν˜„

μš°μ„  μ™„μ „ μ΄ˆκΈ°μƒνƒœμ—μ„œ μ‹œμž‘ν•˜κΈ° μœ„ν•΄ μŠ€ν”„λ§ λΆ€νŠΈ ν”„λ‘œμ νŠΈλ₯Ό λ§Œλ“€κ³  κ°„λ‹¨ν•˜κ²Œ 파일 μ—…λ‘œλ“œλ₯Ό ν•  수 μžˆλŠ” form νŽ˜μ΄μ§€μ™€ μ—…λ‘œλ“œ λ²„νŠΌμ„ λˆŒλ €μ„λ•Œ μž‘λ™ν•˜κ²Œ λ˜λŠ” 컨트둀러λ₯Ό λ§Œλ“€μ–΄ 보자.

import java.io.File;
import java.io.IOException;
import java.io.InputStream;

import org.apache.commons.io.FileUtils;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Controller
public class FileUploadController {

	// λ„ˆλ¬΄ 간단 ...
	@RequestMapping("/form")
	public String form() {
		return "form";
	}

	@RequestMapping(value = "/upload", method = RequestMethod.POST)
	public String upload(@RequestParam("file") MultipartFile multipartFile) {
		log.info("### upload");
		File targetFile = new File("/home1/irteam/" + multipartFile.getOriginalFilename());
		try {
			InputStream fileStream = multipartFile.getInputStream();
			FileUtils.copyInputStreamToFile(fileStream, targetFile);
		} catch (IOException e) {
			FileUtils.deleteQuietly(targetFile);
			e.printStackTrace();
		}
		return "redirect:/form";
	}
}

upload μš”μ²­μ΄ λ“€μ–΄μ˜€λ©΄ fileμ΄λΌλŠ” μ΄λ¦„μ˜ νŒŒλΌλ―Έν„°λ‘œ MultipartFile을 λ°›κ³  파일의 이름을 확인 ν›„ μŠ€νŠΈλ¦Όμ„ 읽어 νŠΉμ • κ²½λ‘œμ— 파일둜 μ €μž₯ν•˜λŠ” λ‘œμ§μ΄λ‹€. κ·Έλ‹€μŒ /form을 μ ‘μ†ν•˜κ²Œ 되면 λ‚˜μ˜€λŠ” 폼 화면을 λ§Œλ“€μž. 이것도 μ•„μ£Ό μ‹¬ν”Œν•˜κ²Œ!

<h1>파일 μ—…λ‘œλ“œ</h1>
<form action="/upload" method="post" enctype="multipart/form-data">
	<input type="file" value="파일 선택" name="file"/>
	<input type="submit" value="μ—…λ‘œλ“œ"/>
</form>

multipart/form-data λΌλŠ” Content-Type 을 λͺ…μ‹œν•΄μ£Όκ³  νŒŒμΌμ„ μ„ νƒν•˜λ©΄ /upload둜 POSTμš”μ²­μ„ ν•˜λ„λ‘ μ„€μ •ν•œλ‹€. μ΄λ ‡κ²Œ 되면 λ„ˆλ¬΄ κ°„λ‹¨ν•˜κ²Œ + 이상없이 파일이 μ—…λ‘œλ“œκ°€ 잘 λ˜λ‹ˆ 이게 이야기 ν•  꺼리인가(?) μ‹Άμ„μ •λ„λ‘œ μ‹¬ν”Œν•˜λ‹€.

그런데 파일 크기가 크닀면?

/images/spring-file-upload/omg.jpg
μ„€λ§ˆ 파일 μ—…λ‘œλ“œ ν•˜λŠ” μš©λŸ‰μ΄ 크겠어?… μ™ μ§€ 파일의 μš©λŸ‰μ΄ 크면 λ¬Έμ œμžˆμ„κ²ƒ 같은데…
좜처 : https://m.blog.naver.com/naibbo0407/30170815180

κ°œλ°œμ„ ν•˜λ‹€λ³΄λ©΄ 항상 생각해야 ν•  뢀뢄쀑에 ν•˜λ‚˜κ°€ λ°”λ‘œ ν™•μž₯성인것 κ°™λ‹€. 이 λΆ€λΆ„μ—μ„œ μ—­μ‹œ λ¬Έμ œκ°€ λ˜μ—ˆλ˜ 것. ν‰μ†Œλ³΄λ‹€ μš©λŸ‰μ΄ 큰 파일이 μ—…λ‘œλ“œκ°€ λ˜λ©΄μ„œ (ν‰μ†Œ 3400MB μ˜€λ‹€κ°€ 34GBμ •λ„μ˜ 파일이 μ—…λ‘œλ“œκ°€ λ˜λŠ” 맀직) μ—…λ‘œλ“œκ°€ μ•ˆλ˜λŠ” 상황이 λ°œμƒν•˜μ˜€λ‹€. λ‹Ήμ—°νžˆ λ¬Έμ œκ°€ λ°œμƒν•˜λ©΄ λˆ„κ΅°κ°€ λ§ν–ˆλ“― λ‘œκ·ΈλΆ€ν„° μ‚΄νŽ΄λ³΄μ•˜λŠ”λ° Apache - (AJP) - Tomcat 으둜 κ΅¬μ„±λœ ν™˜κ²½μ—μ„œ tomcat λ‘œκ·Έμ— ### uploadλΌλŠ” λ‘œκ·Έκ°€ μ—†κ³  μ•„νŒŒμΉ˜ λ‘œκ·Έμ—” 502 μ—λŸ¬κ°€ λ°œμƒν•œ κ²ƒμ΄μ—ˆλ‹€. μ™œ ν†°μΌ“ λ‘œκ·Έλ„ μ•ˆλ‚¨κ³  그전에 μ—λŸ¬κ°€ λ°œμƒν•˜μ˜€μ„κΉŒ? μ΄λ•ŒλΆ€ν„° (κ·Όκ±°μ—†λŠ” 좔츑을 ν•˜λ©°…) κ³ λ‚œκ³Ό μ—­κ²½μ˜ μ‚½μ§ˆμ„ ν•˜κΈ° μ‹œμž‘ν•˜κ²Œ λœλ‹€. ν†°μΌ“ 버전이 문제일까? λ‘œκ·Έκ°€ μ•ˆμ°ν˜”λ‹€λ©΄ λ‹€λ₯Έ ν•„ν„°λ‚˜ μΈν„°μ…‰ν„°μ—μ„œ 무언가λ₯Ό λ¨Ήκ³ (?)μžˆλŠ”κ±΄ μ•„λ‹κΉŒ? 잠깐, 근데 μ›λž˜ λŒ€μš©λŸ‰ μ—…λ‘œλ“œκ°€ 되긴 ν•΄? 파일 μ—…λ‘œλ“œ/λ‹€μš΄λ‘œλ“œ ν•˜λŠ” μ‚¬μ΄νŠΈ 보면 별도 ν”„λ‘œκ·Έλž¨μœΌλ‘œ ν•˜λ˜λ°… 꼬뢈꼬뢈 λ―Έλ‘œμ†μ„ ν—€λ©”λŠ”κ²ƒλ§Œ κ°™μ•˜λ˜ μ‚½μ§ˆμ˜ λ¬Έμ œλŠ” κ²°κ΅­ λ©”λͺ¨λ¦¬μ— μžˆμ—ˆλ‹€. νŒŒμΌμ„ μ—…λ‘œλ“œ ν•˜κ²Œ 되면 ν•΄λ‹Ή λ‚΄μš©μ„ μš°μ„  λ©”λͺ¨λ¦¬μ— λ‹΄κ²Œ 되고 λ‹€ 담은 ν›„ λ©”λͺ¨λ¦¬μ— μžˆλŠ” λ‚΄μš©μ„ was에 μ „λ‹¬ν•œ λ’€ HttpServletRequest 둜 λ„˜μ–΄μ˜€κ²Œ λœλ‹€.(Apache > Tomcat) 그런데 νŒŒμΌμ„ μ—…λ‘œλ“œ ν•˜λ©΄μ„œ λ©”λͺ¨λ¦¬μ— 파일이 써지닀가 λ©”λͺ¨λ¦¬ λΆ€μ‘±μœΌλ‘œ OOM이 λ°œμƒν•˜κ²Œ λ˜λ²„λ¦° κ²ƒμ΄μ—ˆλ‹€. λ˜ν•œ μŠ€ν”„λ§ 파일 μ΅œλŒ€ν¬κΈ°λ₯Ό λ³„λ„λ‘œ μ§€μ •ν•˜μ§€ μ•Šκ³  μžˆμ—ˆκΈ° λ•Œλ¬Έμ— λ©”λͺ¨λ¦¬κ°€ μΆ©λΆ„ν–ˆλ‹€ ν•˜λ”λΌλ„ μ—λŸ¬κ°€ λ°œμƒν–ˆμ„ μƒν™©μ΄μ—ˆλ‹€. ( https://spring.io/guides/gs/uploading-files/ μ°Έμ‘° )

2019 μƒλ°˜κΈ° 리뷰 (feat. κΈ€λ˜)

λˆ„κ΅¬λ‚˜ 어렸을 땐 빨리 μ–΄λ₯Έμ΄ 되고 μ‹Άμ–΄ ν•˜λŠ” 것 κ°™λ‹€. μ‹œκ°„μ΄ 빨리 μ§€λ‚˜κ°€κΈΈ 바라고, 빨리 μ–΄λ₯Έμ΄ 되고 μ‹Άλ‹€λŠ” κ°„μ ˆν•¨μ΄ μžˆμ§€λ§Œ μ΄μƒν•˜κ²Œλ„ 그땐 μ‹œκ°„μ΄ 천천히 κ°€λŠ” κ²ƒμ²˜λŸΌ λŠκ»΄μ‘Œλ‹€. 반면, μ‹œκ°„μ΄ 천천히 κ°”μœΌλ©΄ ν•˜λŠ” λ•Œκ°€ μžˆλ‹€. λ”± μ§€κΈˆ. 남듀은 μ›Œμ–΄μ–΄μ–΄μ–Όν™”μ•„μ•„μˆ˜μš°μš°λͺ¨μ˜₯κΈˆν‡Ό 이라고 λΆ€λ₯΄λ©° μ‹œκ°„μ΄ 느리게 κ°„λ‹€κ³  빨리 주말이 μ™”μœΌλ©΄ μ’‹κ² λ‹€κ³  ν•˜μ§€λ§Œ μš”μ¦˜μ˜ ν•„μžλŠ” μ • λ°˜λŒ€λ‹€. 방금 μΆœκ·Όν•œ 것 같은데 μ–΄λŠμƒŒκ°€ 퇴근인사λ₯Ό μ£Όκ³ λ°›κ³  μžˆλ‹€. 무언가에 홀린 것 κ°™λ‹€. 벌써 μ˜¬ν•΄λ„ 절반이 μ§€λ‚˜κ°€κ³  뜨거운 여름과 ν•¨κ»˜ ν›„λ°˜μ „μ΄ μ‹œμž‘λ˜μ—ˆλ‹€.

/images/review-first-half-2019/speed_time.jpg
κ·Έλž˜μ„œ 빨리 μ§€λ‚˜κ°”λ‚˜…
좜처 : https://m.blog.naver.com/kong6482/220584667861

μ΄μ œκΉŒμ§€λŠ” 12μ›” 말 μ¦ˆμŒμ— ν•œ ν•΄λ₯Ό 바라보고 리뷰λ₯Ό ν–ˆμ—ˆλŠ”λ° κΈ€λ˜λΌλŠ” κΈ€μ“°κΈ° λͺ¨μž„에 κ°€μž…μ„ ν•˜κ²Œ λ˜μ–΄ μƒλ°˜κΈ° 리뷰λ₯Ό 해보렀 ν•œλ‹€. κΈ€λ˜ λͺ¨μž„μ˜ 첫 μˆ™μ œκ°€ μƒλ°˜κΈ° 리뷰 ν¬μŠ€νŒ…μ΄λ‹€. 사싀 리뷰λ₯Ό μƒλ°˜κΈ°μ— ν•˜λ˜ μ—° 말에 ν•œ ν•΄ κΈ°μ€€μœΌλ‘œ ν•˜λ˜ μ •ν•΄μ§„ 건 μ—†μ§€λ§Œ λ‚˜λ₯Ό λ‹€μ‹œ 바라보고 λ‹€μž‘λŠ” μ‹œκ°„μ΄ λ§Žμ„μˆ˜λ‘ 보닀 더 μ•žμœΌλ‘œ κ°€λŠ”λ° 힘이 될 κ±°λΌλŠ” λ°μ—λŠ” 이견이 μ—†λ‹€.

νšŒμ‚¬ μ†μ—μ„œμ˜ λ‚˜

/images/review-first-half-2019/office_work.jpg
νšŒμ‚¬μ—μ„œλŠ” νšŒμ‚¬μΌμ΄ μ΅œμš°μ„ !
좜처 : https://m.blog.naver.com/hwee__/221191852972

μ΅œκ·Όμ— νŒ€μž₯λ‹˜κ³Ό λ©΄λ‹΄ 쀑에 λ‚˜μ˜¨ 이야기닀. μ‹ κΈ°ν•˜κ²Œλ„ κ΅° μ‹œμ ˆ μž₯κΈ°λ₯Ό 꿈꾸던 ν•„μžλ₯Ό μ–΄μ„œ μ „μ—­ν•˜λΌκ³  κΆŒμœ ν•˜μ‹œλ˜ λŒ€λŒ€μž₯λ‹˜κ»˜ 맀일같이 λ“€μ—ˆλ˜ 이야기와 λΉ„μŠ·ν•˜λ‹€.

“μ΄μ œλŠ” λ‹¨μˆœ 개발만 ν•˜κ³  κΈ°λŠ₯κ΅¬ν˜„λ§Œ ν•˜λŠ” 것이 μ•„λ‹ˆλΌ κ·Έ 이상을 ν•΄μ•Ό ν•  μ‹œκΈ°κ°€ λ‹€κ°€μ˜¨λ‹€.” “μ‚¬λžŒλ“€ 관리가 될 μˆ˜λ„ 있고 μ–΄λŠ ν•œ 뢄야에 μ „λ¬Έκ°€κ°€ λ˜μ–΄μ•Ό ν•  μˆ˜λ„ 있고, 선택은 본인의 λͺ«”

사싀 κΈ°λŠ₯ κ΅¬ν˜„μ΄μ•Ό λˆ„κ΅¬λ‚˜ λ‹€ ν•  수 μžˆλ‹€. 단지 κ²½ν—˜μ— λ”°λ₯Έ κ΅¬ν˜„μ˜ μ†λ„λ‚˜ μ•ˆμ •μ„±μ˜ 차이가 μ•„λ‹κΉŒ 생각해본닀. κ·Έλ ‡λ‹€λ©΄ κ·Έ 이상은 μ–΄λ–»κ²Œ ν•΄μ•Ό ν• κΉŒ? 정닡은 μ—†κ² μ§€λ§Œ ν•„μžλŠ” κ·Έ 이상을 해보렀 μš°μ„  νŒ€μ— 도움이 되기 μœ„ν•΄ μ—¬λŸ¬ κ°€μ§€ μžλ™ν™” 툴 듀을 λ§Œλ“  것 κ°™λ‹€. 보닀 κΈ°λŠ₯ κ°œλ°œμ— μ§‘μ€‘ν•˜κ³  λ‹¨μˆœ 반볡적인 μ—…λ¬΄λŠ” μ‹œμŠ€ν…œμ΄ ν•  수 μžˆλ„λ‘. κ·Έλ ‡κ²Œ νˆ΄λ“€μ„ λ§Œλ“€μ–΄ κ°€λ©° μƒκ°ν•˜μ§€ λͺ»ν•œ 뢀뢄듀을 배우게 되고 λ‚˜μ€‘μ— κ·Έκ±Έ 또 μ‚¬μš©ν•˜κ²Œ λ˜λŠ”, 미래의 λ‚˜λ₯Ό μœ„ν•΄ κ°•μ œλ‘œ 배우고 μžˆλŠ”λ“―ν•œ λŠλ‚Œμ΄λž„κΉŒ. μ•„, λ¬Όλ‘  νšŒμ‚¬ λ³Έμ—°μ˜ 업무가 μ΅œμš°μ„ μ΄μ§€λ§Œ 말이닀. μ–΄μ¨Œλ“  μ‹œν‚¨ 일은 μš°μ„  차질 없이 잘 ν•˜κ³  μ‹œν‚€μ§€λ„ μ•Šμ€ 일을 μ°Ύμ•„μ„œ ν•˜λ €κ³  λ…Έλ ₯ν–ˆλ˜ 것 κ°™λ‹€. νŒ€μ„ μœ„ν•΄μ„œ, κ³§ λ‚˜λ₯Ό μœ„ν•΄μ„œ. 적어도 νšŒμ‚¬μ—μ„œ μžˆλŠ” μ‹œκ°„ μ†μ—μ„œλŠ” λ‹€λ₯Έ 곳에 ν•œλˆˆ μ•ˆ νŒ”κ³  νšŒμ‚¬ 업무에 μ „λ…ν•˜λ €κ³  λ…Έλ ₯ν–ˆλ˜ 것 κ°™λ‹€.

μ™ΈλΆ€ ν™œλ™

λΆ€μ‘±ν•œ μ‹œκ°„μ„ μͺΌκ°œλ©΄μ„œ λ°‹μ—…μ΄λ‚˜ μ„Έλ―Έλ‚˜μ— μ°Έμ—¬ν•˜κ³€ ν–ˆμ—ˆλ‹€. 그리고 마λƒ₯ λ“£κ³ λ§Œ μ˜€μ§„ μ•Šμ•˜κ³  “행사에 μ°Έμ—¬ν•˜λ©΄ 무쑰건 질문 ν•˜λ‚˜λŠ” ν•˜μž"λΌλŠ” λ‚˜μ™€μ˜ 약속을 μ§€ν‚€λ©° μ •λ¦¬ν•œ λ‚΄μš©μ„ λΈ”λ‘œκ·Έμ— ν¬μŠ€νŒ…ν•˜κΈ°λ„ ν•˜μ˜€λ‹€.

/images/review-first-half-2019/magarine.jpg
μ˜¬ν•΄ 첫 λ°œν‘œ!

λ””μžμ΄λ„ˆμ™€ κ°œλ°œμžκ°€ ν•¨κ»˜ν•˜λŠ” νˆ¬κ²Œλ”ν†€μ„ μ§„ν–‰ν•˜κΈ°λ„ ν–ˆμ—ˆλ‹€. νˆ¬κ²Œλ”ν†€μ€ μ•½ ν•œ 달 λ™μ•ˆ μ§„ν–‰λ˜λŠ” ν•΄μ»€ν†€μœΌλ‘œ ν•˜λ£¨ λ˜λŠ” 무박 2일 λ™μ•ˆ ν•˜λŠ” κΈ°μ‘΄ 해컀톀과 λ‹€λ₯΄λ‹€. 이 κΈ°κ°„ λ™μ•ˆ νŒ€ λ‚΄μ—μ„œ 자유둭게 일정을 μ‘°μ •ν•  수 μžˆλ‹€. 우리 νŒ€μ€ μ•½ 7주에 걸쳐 “동넀 마트 할인 정보λ₯Ό μ•Œλ €μ£ΌλŠ” μ•±” 을 λ§Œλ“€κ²Œ λ˜μ—ˆλ‹€. ν•„μžλŠ” API μ „λ°˜μ— λŒ€ν•΄ 담당을 ν•˜μ˜€κ³  μž‘μ€ λΆ€λΆ„μ΄μ—ˆμ§€λ§Œ μ›Ήμ‚¬μ΄νŠΈλ„ κ°„λ‹¨ν•˜κ²Œ λ§Œλ“€μ–΄ λ³΄μ•˜λ‹€. 아무것도 μ—†λŠ” λ°±μ§€μƒνƒœμ—μ„œ μ‹œμž‘ν•˜λ €λ‹ˆ λ§‰λ§‰ν–ˆμ§€λ§Œ ν›„κΈ°μ—μ„œλ„ μ μ—ˆλ“―μ΄ λ‹€μ‹œ 해보라고 ν•˜λ©΄ 머릿속에 전체 μ•„ν‚€ν…μ²˜κ°€ 그림으둜 그렀질 만큼 μžμ‹ κ°μ΄ 생겼닀. 특히 정말 쒋은 νŒ€μ›λ“€κ³Ό ν•¨κ»˜ ν˜‘μ—…ν•  수 μžˆμ–΄μ„œ λ„ˆλ¬΄ μ’‹μ•˜λ‹€.

내곡 μ—°λ§ˆ

ν•œ 달에 2개 이상 λΈ”λ‘œκ·Έ 글을 μž‘μ„±ν•˜λŠ” λͺ©ν‘œκ°€ μžˆμ—ˆλ‹€. 그런데 μ§€λ‚œλ‹¬μ— 이사λ₯Ό ν•˜λ‹€ λ³΄λ‹ˆ (핑계…) λͺ©ν‘œλ₯Ό 달성 ν•  μˆ˜κ°€ μ—†μ—ˆλ‹€. ν•˜μ§€λ§Œ λ‚˜λ¦„ 퀄리티가 μžˆλŠ” 글을 μ“°λ €κ³  λ…Έλ ₯ν–ˆκ³  PV도 μž‘λ…„λ³΄λ‹€ μ‘°κΈˆμ”© 였λ₯΄κ³  μžˆλŠ” 것 κ°™μ•„ 내심 기뢄이 μ’‹λ‹€. 그리고 μž‘λ…„ 말뢀터 μ‹œμž‘ν•œ ν•„μžμ˜ 첫 ν† μ΄ν”„λ‘œμ νŠΈ 인 κΈ°μˆ λΈ”λ‘œκ·Έ κ΅¬λ…μ„œλΉ„μŠ€ 에 μ΄λŸ°μ €λŸ° κΈ°λŠ₯을 μΆ”κ°€ν•˜μ˜€λ‹€. μ„€λ§ˆ 1000λͺ…이 λ„˜κ²Œ ꡬ독 ν•˜κ² μ–΄?라고 μƒκ°ν–ˆμ§€λ§Œ 이 글을 μž‘μ„±ν•˜κ³  μžˆλŠ” μ‹œμ μ—μ„œ 1,569λͺ…μ΄λ‚˜ κ΅¬λ…ν–ˆλ‹€. μ„€λ§ˆ 1λ…„ λ„˜κ²Œ λ‚΄κ°€ 이 ν”„λ‘œμ νŠΈλ₯Ό μš΄μ˜ν•˜κ² μ–΄?라고 μƒκ°ν–ˆμ§€λ§Œ λ‹€μŒ μ£Όκ°€ 되면 λ”± 1λ…„μ§Έ. μ‹ κΈ°ν•  따름이닀. 마침 κΈ°νšŒκ°€ λ˜μ–΄ GDG μ£Όκ΄€μœΌλ‘œ ν–‰μ‚¬ν•˜λŠ” λͺ¨λ‘μ˜ TOY STORY: SIDE PROJECT μ–΄λ””κΉŒμ§€ κ°€λ΄€λ‹ˆ?λΌλŠ” μ£Όμ œμ— 첫! 곡식 λ°œν‘œμžλ‘œμ¨ λ°œν‘œλ₯Ό ν•  수 있게 λ˜μ–΄ λ„ˆλ¬΄λ‚˜λ„ μ˜κ΄‘μ΄λ‹€. ν•΄λ‹Ή λ°œν‘œ ν›„κΈ°λŠ” λ‚˜μ€‘μ— μž‘μ„±ν•˜λŠ” κ²ƒμœΌλ‘œ~