/images/profile.png

Spring์—์„œ Request๋ฅผ ์šฐ์•„ํ•˜๊ฒŒ ๋กœ๊น…ํ•˜๊ธฐ

์Šคํ”„๋ง ๊ธฐ๋ฐ˜์˜ ์›น ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๋งŒ๋“ค๋‹ค ๋ณด๋ฉด ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜๋Š”๋ฐ ๋งจ ์ฒ˜์Œ์— ์œ„์น˜ํ•˜๊ณ  ์žˆ๋Š” Controller(์ดํ•˜ ์ปจํŠธ๋กค๋Ÿฌ)๋ผ๋Š” ๋ ˆ์ด์–ด๋ฅผ ๋งŒ๋“ค๊ฒŒ ๋œ๋‹ค. ๊ทธ๋Ÿด๋•Œ๋ฉด ์‚ฌ์šฉ์ž๊ฐ€ ์–ด๋–ค ์š”์ฒญ(Request)์„ ํ•˜์˜€๋Š”์ง€์— ๋Œ€ํ•ด ํ™•์ธ์ด ํ•„์š”ํ•  ์ˆ˜ ์žˆ๋‹ค. ๋ฌผ๋ก  ํ™•์ธ์„ ์•ˆํ•ด๋„ ๋ฌด๋ฐฉํ•˜์ง€๋งŒ ๊ฐ€๊ธ‰์  ๋กœ๊น…์€ ์‹œ์Šคํ…œ ๋กœ์ง์— ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š๋Š” ๋ฒ”์œ„์—์„œ ์ตœ๋Œ€ํ•œ ๋‹ค์–‘ํ•˜๊ฒŒ ๋ฏธ๋ฆฌ ํ•ด๋‘๋Š”๊ฒŒ ๋‚˜์ค‘์— ์œ ์ง€๋ณด์ˆ˜์‹œ ํŽธํ•  ์ˆ˜ ์žˆ๋‹ค. (์˜ˆ์ „ ์กฐ์ง์žฅ๋‹˜๊ป˜์„œ ๋ง์”€ํ•˜์‹ ๊ฒŒ ์•„์ง๋„ ๋จธ๋ฆฟ์†์— ๊ฝ‰ ์ž๋ฆฌ์žก๊ณ  ์žˆ๋‹ค…) ์•„~์ฃผ ์ผ๋ฐ˜์ ์œผ๋กœ, ์ปจํŠธ๋กค๋Ÿฌ์—์„œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋ฉ”์†Œ๋“œ ๋‹จ์œ„๋กœ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์ง์ ‘ ๋กœ๊น…ํ•˜๊ฒŒ ๋œ๋‹ค.

@Slf4j
@RestController
public class SampleController {

	@GetMapping("/test1")
	public String test1(@RequestParam String id) {
		log.info("id : {}", id);
		return "length : " + id.length();
	}
}

์ด๋ ‡๊ฒŒ ๋˜๋ฉด ์‚ฌ์šฉ์ž๊ฐ€ GET /test1 ์ด๋ผ๋Š” ์š”์ฒญ์„ ๋ณด๋‚ผ๋•Œ ์–ด๋–ค ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ํ˜ธ์ถœํ•˜์˜€๋Š”์ง€์— ๋Œ€ํ•ด ๋กœ๊น…์ด ๋‚จ๊ฒŒ ๋˜๋Š”๋ฐ ํ•ญ์ƒ log.info("id : {}", id); ๊ณผ ๊ฐ™์ด ์ˆ˜๋™์œผ๋กœ ๋กœ๊น…์„ ๋‚จ๊ฒจ์•ผ ํ•˜๋Š” ๋ถˆํŽธํ•จ์ด ์ƒ๊ธด๋‹ค. ๋ฌผ๋ก  ๊ผผ๊ผผํ•˜๊ฒŒ ๋ฉ”์†Œ๋“œ๋งˆ๋‹ค ๋กœ๊น…์„ ์ ์–ด์ฃผ๋ฉด ์ „ํ˜€ ๋ฌธ์ œ๋ ๊ฒŒ ์—†์ง€๋งŒ ์ด๋Ÿฌํ•œ ์ปจํŠธ๋กค๋Ÿฌ ~ ๋ฉ”์†Œ๋“œ๊ฐ€ ํ•œ๋‘๊ฐœ๊ฐ€ ์•„๋‹Œ ์ˆ˜์‹ญ ๋˜๋Š” ์ˆ˜๋ฐฑ๊ฐœ์ผ ๊ฒฝ์šฐ์—” ๊ทธ๋•Œ๋งˆ๋‹ค ๋กœ๊น…์„ ์ ์–ด์ค˜์•ผ ํ•˜๋Š” ๋ถˆํŽธํ•จ์ด ์žˆ์„ ์ˆ˜ ์žˆ๋‹ค. ๋˜ํ•œ ์ž์นซ ๊นœ๋ฐ•ํ•˜๊ณ  ๋กœ๊น…์„ ๋นผ๋จน๊ณ  ๋ฐฐํฌ๋ฅผ ํ•˜๊ฒŒ ๋œ ๊ฒฝ์šฐ ๋ชจ๋‹ˆํ„ฐ๋ง์‹œ ๋กœ๊น…์„ ํ•˜์ง€ ์•Š์•„์„œ ๋‹ค์‹œ ๋กœ๊น…ํ•˜๊ณ  ๋ฐฐํฌ๋ฅผ ํ•˜๋Š”, ๋ณ„๊ฒƒ๋„ ์•„๋‹Œ๋ฐ(?) “์ •๋ง ๋ถˆํŽธํ•œ” ์ƒํ™ฉ์ด ์žˆ์„ ์ˆ˜ ์žˆ๋‹ค. ์ด๋ฒˆ ํฌ์ŠคํŒ…์—์„œ๋Š” ์‚ฌ์šฉ์ž์˜ ์š”์ฒญ์„ ๋ชจ๋‹ˆํ„ฐ๋ง ํ•˜๊ธฐ ์œ„ํ•ด ์ปจํŠธ๋กค๋Ÿฌ๋งˆ๋‹ค ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•ด๊ฐ€๋ฉฐ ๋กœ๊น…์„ ํ•˜๋Š”๊ฒƒ์ด ์•„๋‹ˆ๋ผ HttpServletRequestWrapper ๋ผ๋Š” ๊ฒƒ๊ณผ Filter, AOP๋ฅผ ์ด์šฉํ•˜์—ฌ Request์˜ ์ •๋ณด๋ฅผ ํ•œ๊ณณ์—์„œ ์šฐ์•„ํ•˜๊ฒŒ ๋กœ๊น…ํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ์•Œ์•„๋ณด๊ณ ์ž ํ•œ๋‹ค.

์š”๊ตฌ์‚ฌํ•ญ

/images/controller-common-logging/bull_fighting.gif
์™€ ๊ฐœ๋ฐœํ•˜์ž์•„!
์ถœ์ฒ˜ : https://gfycat.com/ko/brightevilaoudad

ํˆฌ์šฐ์‚ฌ๊ฐ€ ํ”๋“œ๋Š” ๋นจ๊ฐ„ ์ฒœ์„ ๋ณด๋ฉฐ ๋Œ์ง„ํ•˜๋Š” ํ™ฉ์†Œ์ฒ˜๋Ÿผ (์“ฐ๊ณ ๋ณด๋‹ˆ ๋„ˆ๋ฌด TMI ๊ฐ™๋‹ค….) ๋‹น์žฅ ์ฝ”๋”ฉ์„ ์‹œ์ž‘ํ•˜๋ฉฐ ๊ฐœ๋ฐœ์„ ํ•  ์ˆ˜๋„ ์žˆ์ง€๋งŒ ์ •์ž‘ ์›ํ•˜๋Š” ๊ธฐ๋Šฅ์ด ๋ฌด์—‡์ธ์ง€ ์ฒœ์ฒœํžˆ ์ •๋ฆฌํ•˜๊ณ  ๋„˜์–ด๊ฐˆ ํ•„์š”๊ฐ€ ์žˆ๋Š” ๊ฒƒ ๊ฐ™๋‹ค. (์–ด์ฉ”๋• ์˜คํžˆ๋ ค ํ›„์ž๊ฐ€ ๋” ๋น ๋ฅธ ๊ฐœ๋ฐœ์„ ํ•˜๊ฒŒ ๋˜๋Š”๊ฒƒ ๊ฐ™๋‹ค.)

  1. GET, POST ๋“ฑ ๋‹ค์–‘ํ•œ http method ๋กœ ๊ตฌํ˜„๋œ ๋ชจ๋“  ์ปจํŠธ๋กค๋Ÿฌ์˜ ํŒŒ๋ผ๋ฏธํ„ฐ์™€ ๊ธฐํƒ€ Request ์ •๋ณด๊ฐ€ ๋กœ๊น…์ด ๋˜์•ผ ํ•œ๋‹ค.
  2. ์ปจํŠธ๋กค๋Ÿฌ, ๋ฉ”์†Œ๋“œ๊ฐ€ ๋Š˜์–ด๋‚ ๋•Œ๋งˆ๋‹ค ๋ณ„๋„์˜ ์ฝ”๋“œ ์ถ”๊ฐ€ ์—†์ด ํ•œ๊ณณ์—์„œ ๊ณตํ†ต์ ์œผ๋กœ ๋กœ๊น…์ด ๋˜์•ผ ํ•œ๋‹ค.
  3. URL ์ค‘ ํŠน์ • ํŒจํ„ด์œผ๋กœ ๋“ค์–ด์˜ค๋Š” ์š”์ฒญ์€ ๋‹ค๋ฅธ ๋ฐฉ์‹์œผ๋กœ ๋กœ๊น…์„ ํ•˜๊ฑฐ๋‚˜, ๋กœ๊น…์—์„œ ์ œ์™ธํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•œ๋‹ค.
  4. ์•ž์„œ ๋งํ–ˆ๋“ฏ ๋‹ค๋ฅธ ๋น„์ง€๋‹ˆ์Šค ๋กœ์ง์— ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š์•„์•ผ ํ•œ๋‹ค.

๊ตฌํ˜„ํ•˜๊ธฐ - Request ์˜ ํŒŒ๋ผ๋ฏธํ„ฐ ์ •๋ฆฌ

Request ์˜ ๋ชจ๋“  ๋กœ๊น…์„ ํ•œ๊ณณ์—์„œ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด์„œ filter(ํ•„ํ„ฐ)๋ฅผ ํ™œ์šฉํ•˜์˜€๋‹ค. ํ•„ํ„ฐ๋Š” Dispatcher servlet์˜ ์•ž๋‹จ์— ์œ„์น˜ํ•˜๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๋ชจ๋“  ์ •๋ณด๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ ์šฉ์ดํ•˜๋‹ค. ๋ฌผ๋ก  ์ธํ„ฐ์…‰ํ„ฐ๋ฅผ ํ™œ์šฉํ•ด์„œ๋„ ๋ฐฉ๋ฒ•์ด ์žˆ๊ฒ ์ง€๋งŒ ๋ณธ ํฌ์ŠคํŒ… ์—์„œ๋Š” ํ•„ํ„ฐ๋ฅผ ํ™œ์šฉํ•ด์„œ ๊ตฌํ˜„ํ•˜๋Š”๊ฒƒ์„ ๋ชฉ์ ์œผ๋กœ ํ•œ๋‹ค. (์‚ฌ์‹ค ์ธํ„ฐ์…‰ํ„ฐ๋กœ ๋ช‡๋ฒˆ ์‹œ๋„ํ•ด๋ณด๋‹ค๊ฐ€ ์‹คํŒจํ•ด์„œ…์œ ์œ  )

/images/controller-common-logging/spring-request-lifecycle.jpg
Spring MVC Request Life Cycle
์ถœ์ฒ˜ : https://justforchangesake.wordpress.com/2014/05/07/spring-mvc-request-life-cycle/

Filter๋ฅผ ๋งŒ๋“ค๊ธฐ ์ „์— Filter์—์„œ ์‚ฌ์šฉํ•  ์ฃผ์š” ํ•ต์‹ฌ(?) ํด๋ž˜์Šค๊ฐ€ ํ•„์š”ํ•œ๋ฐ HttpServletRequest ๋ฅผ Wrapping ํ•ด์„œ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด HttpServletRequestWrapper๋ฅผ ์ƒ์†๋ฐ›๋Š” ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค์ž. Request ์— ๋‹ด๊ฒจ์žˆ๋Š” param ๊ณผ body๋กœ ์š”์ฒญ์ด ๋“ค์–ด์˜ฌ ๊ฒฝ์šฐ body์— ์žˆ๋Š” ๋‚ด์šฉ์„ param ์— ๋‹ด๋Š” ๋กœ์ง์ด๋‹ค. ์ฃผ์š” ์„ค๋ช…์€ ์ฝ”๋“œ ์•ˆ์—์„œ ์ฃผ์„์œผ๋กœ ์„ค๋ช…ํ•˜๊ฒ ๋‹ค.

public class ReadableRequestWrapper extends HttpServletRequestWrapper { // ์ƒ์†
	private final Charset encoding;
	private byte[] rawData;
	private Map<String, String[]> params = new HashMap<>();

	public ReadableRequestWrapper(HttpServletRequest request) {
		super(request);
		this.params.putAll(request.getParameterMap()); // ์›๋ž˜์˜ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์ €์žฅ

		String charEncoding = request.getCharacterEncoding(); // ์ธ์ฝ”๋”ฉ ์„ค์ •
		this.encoding = StringUtils.isBlank(charEncoding) ? StandardCharsets.UTF_8 : Charset.forName(charEncoding);

		try {
			InputStream is = request.getInputStream();
			this.rawData = IOUtils.toByteArray(is); // InputStream ์„ ๋ณ„๋„๋กœ ์ €์žฅํ•œ ๋‹ค์Œ getReader() ์—์„œ ์ƒˆ ์ŠคํŠธ๋ฆผ์œผ๋กœ ์ƒ์„ฑ

			// body ํŒŒ์‹ฑ
			String collect = this.getReader().lines().collect(Collectors.joining(System.lineSeparator()));
			if (StringUtils.isEmpty(collect)) { // body ๊ฐ€ ์—†์„๊ฒฝ์šฐ ๋กœ๊น… ์ œ์™ธ
				return;
			}
			if (request.getContentType() != null && request.getContentType().contains(
				ContentType.MULTIPART_FORM_DATA.getMimeType())) { // ํŒŒ์ผ ์—…๋กœ๋“œ์‹œ ๋กœ๊น…์ œ์™ธ
				return;
			}
			JSONParser jsonParser = new JSONParser();
			Object parse = jsonParser.parse(collect);
			if (parse instanceof JSONArray) {
				JSONArray jsonArray = (JSONArray)jsonParser.parse(collect);
				setParameter("requestBody", jsonArray.toJSONString());
			} else {
				JSONObject jsonObject = (JSONObject)jsonParser.parse(collect);
				Iterator iterator = jsonObject.keySet().iterator();
				while (iterator.hasNext()) {
					String key = (String)iterator.next();
					setParameter(key, jsonObject.get(key).toString().replace("\"", "\\\""));
				}
			}
		} catch (Exception e) {
			log.error("ReadableRequestWrapper init error", e);
		}
	}

	@Override
	public String getParameter(String name) {
		String[] paramArray = getParameterValues(name);
		if (paramArray != null && paramArray.length > 0) {
			return paramArray[0];
		} else {
			return null;
		}
	}

	@Override
	public Map<String, String[]> getParameterMap() {
		return Collections.unmodifiableMap(params);
	}

	@Override
	public Enumeration<String> getParameterNames() {
		return Collections.enumeration(params.keySet());
	}

	@Override
	public String[] getParameterValues(String name) {
		String[] result = null;
		String[] dummyParamValue = params.get(name);

		if (dummyParamValue != null) {
			result = new String[dummyParamValue.length];
			System.arraycopy(dummyParamValue, 0, result, 0, dummyParamValue.length);
		}
		return result;
	}

	public void setParameter(String name, String value) {
		String[] param = {value};
		setParameter(name, param);
	}

	public void setParameter(String name, String[] values) {
		params.put(name, values);
	}

	@Override
	public ServletInputStream getInputStream() {
		final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(this.rawData);

		return new ServletInputStream() {
			@Override
			public boolean isFinished() {
				return false;
			}

			@Override
			public boolean isReady() {
				return false;
			}

			@Override
			public void setReadListener(ReadListener readListener) {
				// Do nothing
			}

			public int read() {
				return byteArrayInputStream.read();
			}
		};
	}

	@Override
	public BufferedReader getReader() {
		return new BufferedReader(new InputStreamReader(this.getInputStream(), this.encoding));
	}
}

๊ฐ€์žฅ ์ค‘์š”ํ•œ ๋ถ€๋ถ„์€ IOUtils.toByteArray(is) ์š” ๋ถ€๋ถ„์ธ๋ฐ, InputStream์€ ํ•œ๋ฒˆ๋ฐ–์— ์ฝ์„ ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์— ์ด ํ•„ํ„ฐ์—์„œ ์ŠคํŠธ๋ฆผ์„ ์ฝ๋Š” ๋Œ€์‹ , ๋ž˜ํผ ๊ตฌํ˜„์œผ๋กœ ์ƒˆ ์ŠคํŠธ๋ฆผ ์ƒ์„ฑํ•˜๋„๋ก ์ž‘์—…์„ ํ•˜์˜€๋‹ค. ์ž์นซ ์ž˜๋ชปํ•˜๋‹ค๊ฐ„ body์˜ ๋‚ด์šฉ์ด ์œ ์‹ค๋  ์ˆ˜๋„ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ์ฐธ์กฐ : http://stackoverflow.com/questions/10210645/http-servlet-request-lose-params-from-post-body-after-read-it-once http://stackoverflow.com/questions/3769259/why-is-the-parameter-value-an-object-hash-code-for-request-getparametermap-ge

D.light ํˆฌ๊ฒŒ๋”ํ†ค ์ฐธ๊ฐ€ํ›„๊ธฐ

ํšŒ์‚ฌ์ผ์„ ํ•˜๋‹ค ๋ณด๋ฉด ์‹œํ‚ค๋Š” ๋Œ€๋กœ ํ˜น์€ ํŒ€์˜ ๋ชฉํ‘œ์— ๋ถ€ํ•ฉํ•˜๊ธฐ ์œ„ํ•ด ์–ด์ฉ” ์ˆ˜ ์—†์ด ํ•ด์•ผ ํ•˜๋Š” ์ผ์„ ํ•˜๊ฒŒ ๋œ๋‹ค. ๊ทธ๋Ÿฌํ•œ ์ผ์ด ์žฌ๋ฏธ์žˆ๊ณ  ๊ฒฐ๊ณผ๋ฌผ์— ๋Œ€ํ•œ ๋งŒ์กฑ๋„๊ฐ€ 100% ๋ผ๋ฉด ๋‹คํ–‰์ด์ง€๋งŒ ๊ฐ„ํ˜น ์žฌ๋ฏธ๋„ ์—†๊ณ  ์‹œ์ผœ์„œ ํ•˜๋Š” ์ผ์€ ๋ฐค์„ ๊ผฌ๋ฐ• ์ƒˆ ๊ฐ€๋ฉด์„œ ์™„์„ฑ์„ ํ•ด๋„ ์ฉ ๊ทธ๋ ‡๊ฒŒ ๋งŒ์กฑ์Šค๋Ÿฝ์ง€ ๋ชปํ•œ ๊ฒฝ์šฐ๊ฐ€ ๋Œ€๋ถ€๋ถ„์ธ ๊ฒƒ ๊ฐ™๋‹ค. (๋ฌผ๋ก  ํšŒ์‚ฌ์ผ์—์„œ ์ž์‹ ๋งŒ์˜ ์ธ์‚ฌ์ดํŠธ๋ฅผ ์ฐพ๋Š”๋‹ค๋ฉด ๊ธˆ์ƒ์ฒจํ™”๊ฒ ์ง€๋งŒ… + ๋งค๋ฒˆ ํšŒ์‚ฌ์ผ์ด ์žฌ๋ฏธ์—†๊ณ  ํ•˜๊ธฐ ์‹ซ์€๊ฑด ์•„๋‹˜) ์–ธ์ œ๋ถ€ํ„ฐ์ธ์ง€ ํ•„์ž๋„ ์ด๋Ÿฌํ•œ ๋ถ€๋ถ„์— ๊ฐˆ์ฆ์„ ๋А๋ผ๋ฉฐ ํšŒ์‚ฌ์™€๋Š” ๋ณ„๋„๋กœ ๋ฌด์–ธ๊ฐ€๋ฅผ ๋งŒ๋“ค์–ด ๋ณด๊ณ  ์‹ถ์€ ๋งˆ์Œ์ด ๋ฌด๋Ÿญ๋ฌด๋Ÿญ ์ƒ๊ฒจ๋‚  ์ฆˆ์Œ facebook ํƒ€์ž„๋ผ์ธ์—์„œ ๊ฐœ๋ฐœ์ž์™€ ๋””์ž์ด๋„ˆ๊ฐ€ ์•ฝ 7์ฃผ๊ฐ„ ํ”„๋กœ์ ํŠธ๋ฅผ ์ง„ํ–‰ํ•˜๋Š” D.light ํˆฌ๊ฒŒ๋”ํ†ค ์ด๋ผ๋Š” ํ–‰์‚ฌ๊ฐ€ ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ๋ฐœ๊ฒฌํ•˜๊ณ  ๋‚˜๋ฆ„ ์ •์„ฑ์Šค๋ ˆ ์ง€์›์„œ๋ฅผ ์ž‘์„ฑ ํ›„ ํ•ฉ๊ฒฉ ๋ฉ”์ผ์„ ๋ฐ›๊ฒŒ ๋œ๋‹ค. (GDG Facebook ํ•ด๋‹น ๊ฒŒ์‹œ๊ธ€) ์ด๋ฒˆ ํฌ์ŠคํŒ…์—์„œ๋Š” ํ•ด์ปคํ†ค๊ณผ๋Š” ์‚ด์ง ์„ฑ๊ฒฉ์ด ๋‹ค๋ฅธ D.light ํˆฌ๊ฒŒ๋”ํ†ค์„ ์ง„ํ–‰ํ•˜๋ฉด์„œ ๋А๊ผˆ๋˜ ๋ถ€๋ถ„๋“ค๊ณผ ์ง„ํ–‰ํ•œ ๊ฒฐ๊ณผ๋ฌผ์— ๋Œ€ํ•ด ๊ฐ„๋žตํžˆ ๋ฆฌ๋ทฐ๋ฅผ ํ•ด๋ณด๋ฉฐ ์ •๋ง ๊ธ‰ํ–‰์ฒ˜๋Ÿผ ์ง€๋‚˜๊ฐ„ ์•ฝ 7์ฃผ๊ฐ„์„ ๋Œ์ด์ผœ ๋ณด๋Š” ์‹œ๊ฐ„์„ ๊ฐ–๊ณ ์ž ํ•œ๋‹ค.

ํŒ€ ๋นŒ๋”ฉ

/images/d-light-togetherthon-2019/team_build.jpg
๋ˆˆ๋„ ๋ชป๋งˆ์ฃผ์น  ์ •๋„๋กœ ์–ด์ƒ‰ํ•œ ์ฒซ๋‚ 
Team. ๊ทธํŒฝ

์ด 6๊ฐœ ํŒ€ ์ค‘์— ํ•„์ž๋Š” ์—ฌ์ž ๋””์ž์ด๋„ˆ ๋‘ ๋ถ„, ๋‚จ์ž ์•ˆ๋“œ๋กœ์ด๋“œ ๊ฐœ๋ฐœ์ž ๋‘ ๋ถ„์„ ํฌํ•จํ•œ ํŒ€์— ์†ํ•˜๊ฒŒ ๋˜์—ˆ๋‹ค. 5๋ช… ์ค‘ ํ•ด์ปคํ†ค ์ฐธ์—ฌ ๊ฒฝํ—˜์ด ์žˆ๋‹ค๋Š” ์ด์œ ๋งŒ์œผ๋กœ ์—ฌ์ž ๋””์ž์ด๋„ˆ ๋ถ„๊ป˜์„œ ํŒ€์žฅ์ด ๋˜์‹œ๊ณ , 7์ฃผ๋ผ๋Š” ์‹œ๊ฐ„์ด ์ •๋ง ๊ธ‰ํ•˜๊ฒŒ ์ง€๋‚˜๊ฐˆ ๊ฒƒ ๊ฐ™๋‹ค๋Š” ์–ต์ง€(?) ์ด์œ ๋ฅผ ๋“ค๋จน์—ฌ ๊ทธํŒฝ์ด๋ผ๋Š” ํŒ€ ์ด๋ฆ„์ด ์ •ํ•ด์กŒ๋‹ค. ๊ทธ๋ ‡๊ฒŒ “์šฐ๋ฆฌ๊ฐ€ ์ •๋ง ๋ฌด์—‡์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ์„๊นŒ?” ํ•˜๋Š” ์˜๊ตฌ์‹ฌ ์†์— ํ”„๋กœ์ ํŠธ๊ฐ€ ์‹œ์ž‘์ด ๋˜์—ˆ๋‹ค.

ํ”„๋กœ์ ํŠธ ์ง„ํ–‰ ์ „๋ฐ˜

์‹ ๊ธฐํ•˜๊ฒŒ๋„ ์šฐ๋ฆฌ 5๋ช…์€ ๊ฐ๊ฐ ์‚ฌ๋Š” ์ง€์—ญ์ด ์ „๋ถ€ ๋‹ฌ๋ž๋‹ค. (์‹ฌ์ง€์–ด ํ•œ ๋ถ„์€ ๋งค์ฃผ ์ € ๋ฉ€๋ฆฌ ์ถฉ์ฒญ๋‚จ๋„ ์ฒœ์•ˆ์—์„œ ์˜ฌ๋ผ์˜ค์…”์•ผ ํ•˜๋Š” ์ˆ˜๊ณ ๋ฅผ ใ… ใ… ) ๋งค ์ฃผ๋ง๋งˆ๋‹ค ์˜คํ”„๋ผ์ธ์œผ๋กœ ๋งŒ๋‚˜์„œ ํšŒ์˜๋ฅผ ์ง„ํ–‰ํ–ˆ๋‹ค. ๊ทธ๋ž˜์•ผ ๊ธธ๋‹ค๋ฉด ๊ธธ๊ณ  ์งง๋‹ค๋ฉด ์งง์€ 7์ฃผ ์•ˆ์— ์™„์„ฑ๋„ ๋†’์€ ๊ฒฐ๊ณผ๋ฌผ์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ์„ ๊ฒƒ ๊ฐ™์•„์„œ์˜€๋‹ค. ํ”„๋กœ์ ํŠธ์˜ ์ฃผ์ œ๋ฅผ ์ •ํ•˜๋Š” ์•„์ด๋””์–ด ํšŒ์˜์—์„œ ์ •ํ•ด์ง„ ์šฐ๋ฆฌ์˜ ๋ชฉํ‘œ๋Š” “๋™๋„ค ๋งˆํŠธ ํ• ์ธ ์ •๋ณด๋ฅผ ์•Œ๋ ค์ฃผ๋Š” ์•ฑ"์„ ๋งŒ๋“ค๊ธฐ๋กœ ํ•˜์˜€๋‹ค.

/images/d-light-togetherthon-2019/diagram.jpg
์‹œ๊ฐ„๊ฐ€๋Š”์ค„ ๋ชฐ๋ž๋˜ ์•„์ด๋ฐ์ด์…˜ ํšŒ์˜

ํŒ€์›Œํฌ๊ฐ€ ์ค‘์š”ํ•œ ํˆฌ๊ฒŒ๋”ํ†ค ์ž„์—๋„ ๋ถˆ๊ตฌํ•˜๊ณ  ์—ฌ๋А ์ฒœ์žฌ ๋””์ž์ด๋„ˆ, ์ฒœ์žฌ ๊ฐœ๋ฐœ์ž์ฒ˜๋Ÿผ ์ผ๋‹น๋ฐฑ ์Šคํƒ€์ผ๋กœ ๋š๋”ฑ ๋งŒ๋“œ๋Š” ๊ทธ๋Ÿฐ ํ”„๋กœ์ ํŠธ์˜ ์ง„ํ–‰ ๋ฐฉ์‹์€ ํ”ผํ•˜๋ ค๊ณ  ์šฐ๋ฆฌ ๋ชจ๋‘๊ฐ€ ๋…ธ๋ ฅํ•˜์˜€๋‹ค. ๋˜๋„๋ก์ด๋ฉด ์ด๋ ‡๊ฒŒ ๋ชจ์ธ ๋‹ค์„ฏ ๋ช…์ด ํ•œ๋งˆ์Œ ํ•œ๋œป์œผ๋กœ ๊ฐ์ž๊ฐ€ ์ƒ๊ฐํ•˜๋Š” ํฌ๊ธฐ์™€ ์–‘์€ ๋‹ค๋ฅด๊ฒ ์ง€๋งŒ ์ด ํ”„๋กœ์ ํŠธ๋ฅผ ํ†ตํ•ด ๋ฌด์—‡์ด๋ผ๋„ ๋ฐฐ์šธ ์ˆ˜ ์žˆ์—ˆ์œผ๋ฉด ํ–ˆ๋‹ค. ๋””์ž์ด๋„ˆ ๋ถ„๋“ค์€ ์„œ๋กœ ๋””์ž์ธํ•˜์‹  ์‹œ์•ˆ์— ๋Œ€ํ•ด ๊ณต์œ ๋ฅผ ํ•˜๋ฉด์„œ ๊ฐœ์„ ํ•ด ๋‚˜๊ฐ€๋Š” ๋ชจ์Šต๊ณผ, ์•ˆ๋“œ๋กœ์ด๋“œ ๊ฐœ๋ฐœ์ž ๋‘๋ถ„์€ (๊ฑฐ์˜ ๋งค์ผ) ๋ฐค๋งˆ๋‹ค ์„œ๋กœ ์Šฌ๋ž™์—์„œ ๊ฐœ๋ฐœ ๋ฐฉ๋ฒ•๋ก ์— ๋Œ€ํ•ด ์Šคํ„ฐ๋””๋ฅผ ํ•˜๋Š” ๋ชจ์Šต์ด ๋ณด๊ธฐ ๋„ˆ๋ฌด ๋ณด๊ธฐ ์ข‹์•˜๋‹ค. ๋ฌผ๋ก  ํ•„์ž๋„ ์•„๋ฌด๊ฒƒ๋„ ์—†๋Š” ํ™˜๊ฒฝ์—์„œ ๋ฐฑ์—”๋“œ ์„œ๋ฒ„๋ฅผ ๊ตฌ์ถ•ํ•˜๊ณ  API๋ฅผ ๋งŒ๋“œ๋Š” ๊ณผ์ • ์†์—์„œ ์ •๋ง ๋งŽ์€๊ฒƒ์„ ๋ฐฐ์šธ ์ˆ˜ ์žˆ์—ˆ๋‹ค. ๊ทธ๋ ‡๊ฒŒ ์‹œ๊ฐ„์ด ํ˜๋Ÿฌ ๋งˆ์ง€๋ง‰ ๋ฐœํ‘œํ•˜๋Š” ์ „๋‚ ์—” ํŒ€์› ๋ช‡ ๋ถ„๊ณผ ํ•จ๊ป˜ ๊ผฌ๋ฐ• ๋ฐค์„ ์ƒˆ์šฐ๋ฉฐ ํ”„๋กœ์ ํŠธ ๊ฒฐ๊ณผ๋ฌผ์˜ ์™„์„ฑ๋„๋ฅผ ๋†’์ด๋Š”๋ฐ ๋…ธ๋ ฅํ•˜์˜€๊ณ  ํ•„์ž ๊ฐœ์ธ์ ์œผ๋กœ ์•„์ฃผ ์„ฑ๊ณต์ ์œผ๋กœ ํ”„๋กœ์ ํŠธ๋ฅผ ๋งˆ๋ฌด๋ฆฌํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค.

๊ฐœ๋ฐœ ์ง„ํ–‰

์•ˆ๋“œ๋กœ์ด๋“œ ๊ฐœ๋ฐœ์ž๋ถ„๋“ค์€ ์ฝ”ํ‹€๋ฆฐ ๊ธฐ๋ฐ˜์œผ๋กœ ๊ฐœ๋ฐœ์„ ํ•˜์˜€๋‹ค. ์—ฌ๋Ÿฌ ๋””์ž์ธ ํŒจํ„ด๊ณผ ๋‹ค์–‘ํ•œ ๊ธฐ์ˆ ๋“ค์„ ์‚ฌ์šฉํ•˜์˜€๋‹ค๊ณ  ๋“ค์—ˆ๋Š”๋ฐ ํ•„์ž๋Š” ์•„์‰ฝ๊ฒŒ๋„ ๋ฐฑ์—”๋“œ ๊ฐœ๋ฐœ์„ ํ•˜๋‹ค ๋ณด๋‹ˆ ์ „๋ถ€๋ฅผ ์ดํ•ดํ•˜์ง€๋Š” ๋ชปํ•˜์˜€๋‹ค. ์˜ˆ์ „์— ํ† ์ด ํ”„๋กœ์ ํŠธ๋ฅผ ํŒŒ์ด์ฌ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•ด๋ณธ ๊ฒฝํ—˜์ด ์žˆ์–ด์„œ Flask ๋˜๋Š” Django ๊ธฐ๋ฐ˜์œผ๋กœ API ์„œ๋ฒ„๋ฅผ ๊ตฌ์ถ•ํ•ด๋ณผ๊นŒ ํ•˜๊ณ  ๊ณ ๋ฏผํ•˜์˜€๋‹ค. ํ•˜์ง€๋งŒ (Spring Boot ๊ธฐ๋ฐ˜์œผ๋กœ๋„ ํ•ด๋ณด๊ณ  ์‹ถ์—ˆ๊ณ ) ํŒŒ์ด์ฌ๋ณด๋‹ค๋Š” ์ž๋ฐ” ๊ธฐ๋ฐ˜์œผ๋กœ ๋‹ค์–‘ํ•œ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์š”๊ตฌ ์‚ฌํ•ญ์„ ๊ฐœ๋ฐœํ•˜๋Š”๋ฐ ์กฐ๊ธˆ ๋” ๋Šฅ์ˆ™ํ•  ๊ฒƒ ๊ฐ™์•„์„œ Spring Boot ๊ธฐ๋ฐ˜์œผ๋กœ ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์„ ๊ตฌ์„ฑํ•˜์˜€๋‹ค. ์„œ๋ฒ„๋Š” AWS ํ”„๋ฆฌํ‹ฐ์–ด์˜ EC2๋ฅผ ๋ฐœ๊ธ‰๋ฐ›๊ณ  DB ๋˜ํ•œ AWS์—์„œ ์ œ๊ณตํ•ด์ฃผ๋Š” RDS(mysql)์„ ๋ฐœ๊ธ‰๋ฐ›์•„ ๊ตฌ์„ฑํ•˜์˜€๋‹ค. ๊ทธ๋ฆฌ๊ณ  DNS๋Š” ์˜ˆ์ „์— ๋ฌด๋ฃŒ ๋„๋ฉ”์ธ์„ ์ฐพ๋‹ค๊ฐ€ ์•Œ๊ฒŒ ๋œ http://mooo.com/ ๋ผ๋Š” ์„œ๋น„์Šค์—์„œ ๋ฐœ๊ธ‰๋ฐ›์•„ ์—ฐ๊ฒฐํ•˜์˜€๊ณ , ํ”„๋กœ์ ํŠธ ๊ธฐ๋Šฅ ์ค‘์— ์„œ๋ฒ„์—์„œ ์•ฑ์œผ๋กœ ํ‘ธ์‹œ๋ฅผ ํ•˜๋Š” ๊ธฐ๋Šฅ์ด ์žˆ์—ˆ๋Š”๋ฐ Firebase๋ฅผ ํ™œ์šฉํ•ด์„œ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค.

์ž๋ฐ”, ์„ฑ๋Šฅ, ๋ชจ๋‹ˆํ„ฐ๋ง ํ…Œํฌ์„ธ๋ฏธ๋‚˜ ์ •๋ฆฌ ๋ฐ ํ›„๊ธฐ (by ์šฐ์•„ํ•œ ํ˜•์ œ๋“ค)

์‹ค๋ฌด์—์„œ ์ž๋ฐ” ๊ธฐ๋ฐ˜์œผ๋กœ ๊ฐœ๋ฐœ์„ ํ•˜๊ณ  ์„œ๋น„์Šค๋ฅผ ์šด์˜์„ ํ•˜๋‹ค๋ณด๋ฉด ์ฒ˜์Œ์—” ์•„๋ฌด๋Ÿฐ ๋ฌธ์ œ๊ฐ€ ์—†๋‹ค๊ฐ€ ์‚ฌ์šฉ์ž๊ฐ€ ๋ชฐ๋ฆฌ๋Š” ๋“ฑ ์ด๋ฒคํŠธ์„ฑ์œผ๋กœ ํŠธ๋ž˜ํ”ฝ์ด ๋งŽ์•„์งˆ ๊ฒฝ์šฐ ๊ผญ ๋ฌธ์ œ๊ฐ€ ์ƒ๊ธฐ๊ธฐ ๋งˆ๋ จ์ด๋‹ค. ๊ทธ๋Ÿด๋•Œ๋ฉด ๋’ค๋Šฆ๊ฒŒ ๋ถ€๋žด๋ถ€๋žด ์›์ธ์„ ์ฐพ๊ณ  ๊ฐœ์„ ํ•˜๊ธฐ ๋ฐ”๋น ์ง€๊ฒŒ ๋œ๋‹ค. (์•„๋งˆ ์œ—๋ถ„๋“ค์—๊ฒŒ ํ˜ผ๋‚˜๋ฉด์„œ?ใ… ใ… ) ํ‰์†Œ์— ์ด๋Ÿฐ ์„ฑ๋Šฅ๋ฌธ์ œ๋ฅผ ๊ฐœ์„ ํ•˜๊ณ  ๋ฏธ๋ฆฌ ๋ชจ๋‹ˆํ„ฐ๋ง ํ• ์ˆ˜์žˆ๋Š” ๋ถ€๋ถ„์— ๋Œ€ํ•ด ๊ด€์‹ฌ์„ ๊ฐ–๊ณ  ์žˆ์—ˆ๋˜ ์ฐฐ๋‚˜, ์šฐ์•„ํ•œ ํ˜•์ œ๋“ค์—์„œ 5์›” ์šฐ์•„ํ•œ ํ…Œํฌ ์„ธ๋ฏธ๋‚˜๋ฅผ ํ•œ๋‹ค๊ธฐ์— ๋ถ€๋žด๋ถ€๋žด ์žฅ๋ฌธ์˜ ๊ธ€๋กœ ์‹ ์ฒญ์„ ํ•˜์˜€๊ณ  ์šด์ด ์ข‹์•„ ๋‹น์ฒจ์ด ๋˜์—ˆ๋‹ค. ํ•œ์ฐฝ ํšŒ์‚ฌ์—์„œ ์ƒˆ๋กœ์šด ์„œ๋น„์Šค ์ถœ์‹œ, ๊ทธ๋ฆฌ๊ณ  ์ž ์„ ์ค„์—ฌ๊ฐ€๋ฉฐ ๋ณ„๋„๋กœ ์ง„ํ–‰ํ•˜๊ณ  ์žˆ๋˜ ํ† ์ดํ”„๋กœ์ ํŠธ ๋“ฑ ์—ฌ๋Ÿฌ๊ฐ€์ง€๋กœ ๋ฐ”์œ ์‹œ๊ธฐ์˜€์ง€๋งŒ ํŠนํžˆ ์˜ˆ์ „๋ถ€ํ„ฐ ๋ต™๊ณ ์‹ถ๋˜ ์ด์ƒ๋ฏผ๋‹˜๊ป˜์„œ ์ง์ ‘ ๊ฐ•์˜๋ฅผ ํ•ด์ฃผ์‹ ๋‹ค๊ธฐ์— ํ”ผ๊ณคํ•œ ์‹ฌ์‹ ์„ ์ด๋Œ๊ณ  ์„ธ๋ฏธ๋‚˜์— ์ฐธ์„ํ•˜์˜€๊ณ  ๊ทธ ํ›„๊ธฐ๋ฅผ ์ ์–ด๋ณด๊ณ ์ž ํ•œ๋‹ค.

๋‘๋ ˆ์ด๋กœ ๋งŒ๋“œ์‹  ๋ฐœํ‘œ์ž๋ฃŒ๋ฅผ ๊ณต์œ ํ•ด ์ฃผ์…จ์ง€๋งŒ ์ €์ž‘๊ถŒ ๋ฌธ์ œ๋„ ์žˆ๊ณ  ํ•ด์„œ ํ•„์ž๊ธฐ์ค€์—์„œ ์ดํ•ดํ•œ ๋ถ€๋ถ„์— ๋Œ€ํ•ด์„œ๋งŒ ๊ณต์œ ํ•˜๊ณ ์ž ํ•œ๋‹ค. ๋”๋ถˆ์–ด ๊ทธ๋ƒฅ ๋“ฃ๊ณ  ์•ต๋ฌด์ƒˆ์ฒ˜๋Ÿผ ๋ฐœํ‘œ๋‚ด์šฉ ๊ทธ๋Œ€๋กœ๋ฅผ ๊ณต์œ ํ•˜๋Š”๊ฑด ์˜๋ฏธ๊ฐ€ ์—†๋‹ค๊ณ  ์ƒ๊ฐ๋˜์–ด…

/images/got-of-java-seminar/1.jpg
ํฌ์Šคํ„ฐ๋งŒ ๋ด๋„ ๋ฒŒ์จ๋ถ€ํ„ฐ ๊ฐ€์Šด์ด ๋›ด๋‹ค(?).

์„ฑ๋Šฅ

๊ตฌ๊ธ€์—์„œ ์ž‘์„ฑํ•œ ์„ฑ๋Šฅ์ด ์ค‘์š”ํ•œ ์ด์œ  ๋ผ๋Š” ์•„ํ‹ฐํด์„ ๊ณต์œ ํ•ด ์ฃผ์…จ๋‹ค. (์‹œ๊ฐ„์ด ๋œ๋‹ค๋ฉด ํ•œ๋ฒˆ ์ฝ์–ด๋ณด๊ธธ ๊ฐ•์ถ”, ๋ฌด๋ ค ํ•œ๊ธ€!) ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ์„ฑ๋Šฅ์€ ์‚ฌ์šฉ์ž์˜ ์ฆ๊ฐ€, ์ดํƒˆ์œจ, ์‘๋‹ต์†๋„์— ์˜ํ–ฅ์ด ์žˆ๊ณ  ์ด๋Š” ๊ฒฐ๊ตญ ์ถ”๊ตฌํ•˜๋Š” ๊ฐ€์น˜(์ด๋ฅผ ํ…Œ๋ฉด ์ˆ˜์ต)์— ์ง๋ฉดํ•œ๋‹ค๊ณ  ํ•œ๋‹ค. ์‚ฌ์šฉ์ž๋Š” ์–ด๋А ๊ด€์ ์—์„œ ๋ฐ”๋ผ๋ณด๋Š”๊ฐ€์— ๋”ฐ๋ผ ๋‹ฌ๋ผ์ง€๊ณ  ๊ฐ ๊ด€์ ์— ๋”ฐ๋ผ ์„ฑ๋Šฅ์„ ์ฑ™๊ฒจ์•ผ ํ•˜๋Š” ๋ถ€๋ถ„์ด ๋‹ฌ๋ผ์ง„๋‹ค. ์ˆ˜๊ฐ•์‹ ์ฒญ์„ ํ•˜๋Š” ์‹œ์ ์—์„œ์˜ ์‚ฌ์šฉ์ž์™€ ๋‰ด์Šค ํŽ˜์ด์ง€๋ฅผ ์ฝ๋Š” ์‹œ์ ์—์„œ์˜ ์‚ฌ์šฉ์ž๋Š” ๊ฐ ์„ฑ๊ฒฉ์ด ์—„์—ฐํžˆ ๋‹ค๋ฅธ๊ฒƒ์ฒ˜๋Ÿผ.

  • ์‹œ์Šคํ…œ ๊ด€๋ฆฌ์ž
    • ๋“ฑ๋ก๋œ / ๋“ฑ๋ก๋˜์ง€ ์•Š์€ ์‚ฌ์šฉ์ž
  • ์„œ๋ฒ„ ๊ด€์ 
    • ๋กœ๊ทธ์ธ๋œ / ๋กœ๊ทธ์ธ ํ•˜์ง€ ์•Š์€ ์‚ฌ์šฉ์ž
  • ์„ฑ๋Šฅ ํ…Œ์Šคํ„ฐ ๊ด€์ 
    • Active User
      • ์„œ๋ฒ„์— ๋ถ€ํ•˜๋ฅผ ์ฃผ๋Š” ์‚ฌ์šฉ์ž
      • ๋ฉ”๋‰ด๋‚˜ ๋งํฌ๋ฅผ ๋ˆ„๋ฅด๊ณ  ๊ฒฐ๊ณผ๊ฐ€ ๋‚˜์˜ค๊ธฐ๋ฅผ ๊ธฐ๋‹ค๋ฆฌ๋Š” ์‚ฌ์šฉ์ž
      • ์„ฑ๋Šฅํ…Œ์ŠคํŠธ์‹œ Vuser์™€ ๊ฑฐ์˜ ๋™์ผ ( Vuser : ๊ฐ€์ƒ์‚ฌ์šฉ์ž(virtual user) )
    • Concurrent user
      • ์„œ๋ฒ„์— ๋ถ€ํ•˜๋ฅผ ์ฃผ๊ณ  ์žˆ๊ฑฐ๋‚˜, ์ค„ ๊ฐ€๋Šฅ์„ฑ์ด ๋งค์šฐ๋†’์€ ์„œ๋น„์Šค์— ์ ‘์†์ค‘์ธ ์‚ฌ์šฉ์ž
      • ์›น ํŽ˜์ด์ง€๋ฅผ ๋„์›Œ๋†“์€ ์‚ฌ์šฉ์ž

TPS(Transaction Per Seconds)๋Š” ์ดˆ๋‹น ์–ผ๋งˆ๋‚˜ ๋งŽ์€ ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ• ์ˆ˜ ์žˆ๋Š”์ง€์— ๋Œ€ํ•œ ์‹œ์Šคํ…œ์˜ ์ ˆ๋Œ€์ ์ธ ์ˆ˜์น˜๋กœ ๋ณผ์ˆ˜์žˆ๋‹ค. (๊ฐœ๋ฐœ์ž๋Š” ์–ด๋А์ƒํ™ฉ์—์„œ๋“ ์ง€ ๋Œ€์ถฉ ๊ฐ์œผ๋กœ ์ด์•ผ๊ธฐ ํ•˜์ง€๋ง๊ณ  ์ •ํ™•ํ•œ ์ˆ˜์น˜๋กœ ์ด์•ผ๊ธฐ ํ•ด์•ผํ•œ๋‹ค๋Š” ๋ผˆ๋ฅผ ๋•Œ๋ฆฌ๋Š” ์กฐ์–ธ๊ณผ ํ•จ๊ป˜…) TPS๋Š” Scale out/up์„ ํ†ตํ•ด ์ฆ๊ฐ€์‹œํ‚ฌ์ˆ˜ ์žˆ์ง€๋งŒ Response Time ์€ ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค. ๋ฌผ๋ก  ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ํŠœ๋‹ํ•˜๋ฉด ๋‘ ์ˆ˜์น˜ ๋ชจ๋‘ ๊ฐœ์„ ์ด ๊ฐ€๋Šฅํ•˜๋‹ค. ์ด๋Ÿฌํ•œ TPS์™€ Response Time์˜ ์ตœ๋Œ€์น˜๋Š” ์ถœ์‹œ์ „์— ๋ฐ˜๋“œ์‹œ ํ…Œ์ŠคํŠธ๋ฅผ ํ†ตํ•ด ์•Œ๊ณ  ์žˆ์–ด์•ผ ์ด์Šˆ๋ฐœ์ƒ์‹œ ๋Œ€์‘ํ•˜๋Š”๋ฐ ์œ ์šฉํ•˜๋‹ค. Bottleneck ์ฆ‰ ๋ณ‘๋ชฉ์€ ์žฅ๋น„, ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜, ์ €์žฅ์†Œ, ์„ค์ • ๋“ฑ ๋‹ค์–‘ํ•œ ์ƒํ™ฉ์—์„œ ๋ฐœ์ƒํ• ์ˆ˜ ์žˆ๋‹ค. ๊ทธ์ค‘์— “์•„์ฃผ ์ผ๋ฐ˜์ "์œผ๋กœ ๊ฐ€์žฅ ๋ณ‘๋ชฉ์ด ๋งŽ์ด ๋ฐœ์ƒํ•˜๋Š” ๊ตฌ๊ฐ„์€ DB์ด๊ณ  ๊ทธ ๋‹ค์Œ์œผ๋กœ ํด๋ผ์ด์–ธํŠธ(Web page, App), Network์ด ์žˆ์„ ์ˆ˜ ์žˆ๋‹ค. ๊ฒฐ๋ก ์€ Performance engineering is “Composite Art” of IT ๋ผ๋Š” ํ•˜๋‚˜์˜ ๋ฌธ์žฅ์œผ๋กœ ์ •๋ฆฌ๋ฅผ ํ•ด์ฃผ์…จ๋‹ค. ์•„๋ฌด๋ฆฌ ์ด์œ ๋””์ž์ธ๊ณผ ์–ด๋ ต๊ณ  ๋ณต์žกํ•œ ๊ธฐ๋Šฅ์ด ์žˆ์„์ง€๋ผ๋„ ์„ฑ๋Šฅ์ด ๋’ท๋ฐ›์นจ ์•ˆ๋œ๋‹ค๋ฉด ๋Œ€์šฉ๋Ÿ‰ ํŠธ๋ž˜ํ”ฝ ์ƒํ™ฉ์—์„œ๋Š” ๋ฌด์˜๋ฏธํ•ด์ง€๊ธฐ ๋•Œ๋ฌธ์ด๋ผ๊ณ  ์ƒ๊ฐํ•œ๋‹ค.

์ž๋ฐ”

์ž๋ฐ”์˜ ์—ญ์‚ฌ์— ๋Œ€ํ•ด ์„ค๋ช…ํ•ด ์ฃผ์…จ๋‹ค. ( ์—ญ์‚ฌ์— ๋Œ€ํ•œ ๋ณด๋‹ค ์ž์„ธํ•œ ์„ค๋ช…์€ https://www.whatap.io/blog/12/ ์ฐธ๊ณ  ) ์–ธ์ œ๋ถ€ํ„ฐ์ธ๊ฐ€ JDK ๋ผ์ด์„ผ์Šค ์ด์Šˆ๊ฐ€ ๋งŽ์•˜์—ˆ๋Š”๋ฐ ์‹ค๋ฌด์—์„œ ๊ฐœ๋ฐœํ•˜๋Š” ์ž…์žฅ์—์„œ๋Š” java 8 ์—์„œ๋Š” ๋ฌธ์ œ๊ฐ€ ์•ˆ๋˜๊ณ  java 11๋ถ€ํ„ฐ ๋ผ์ด์„ผ์Šค ๋ฌธ์ œ๊ฐ€ ๋ณต์žกํ•˜๊ฒŒ ์ƒ๊ธธ์ˆ˜ ์žˆ๋‹ค๊ณ  ํ•œ๋‹ค. ์ด๋ถ€๋ถ„์€ ๊ณต์‹๋ฌธ์„œ(?)๋ฅผ ์ฐพ์•„๋ณด๋Š”๊ฒŒ ์ข‹์„๋“ฏ ํ•˜๋‹ค. (๊ฐœ์ธ ๋˜๋Š” ํšŒ์‚ฌ์—์„œ ์‚ฌ์šฉํ•  ๊ฒฝ์šฐ ์ƒํ™ฉ์— ๋”ฐ๋ผ ๋ฒ•์  ์ด์Šˆ๊ฐ€ ์ƒ๊ธธ์ˆ˜๋„, ์•ˆ์ƒ๊ธธ์ˆ˜๋„ ์žˆ๋Š” ๋ณต์žกํ•œ ๋ฌธ์ œ๊ฐ€ ์žˆ์–ด๋ณด์—ฌ์„œ… ํ•„์ž๋„ ์ œ๋Œ€๋กœ ์ดํ•ดํ•˜์ง€๋Š” ๋ชปํ–ˆ๋‹คใ… )

๊ทธ๋ฆฌ๊ณ  ๊ฐ ์ž๋ฐ” ๋ฒ„์ „์—์„œ ๋ฐœํ‘œํ•œ ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์— ๋Œ€ํ•ด ์„ค๋ช…ํ•ด์ฃผ์…จ๋‹ค.

  • Java 8
    • lambda, stream, default method, LocalDate / LocalTime ์ถ”๊ฐ€
    • stream ๊ณผ foreach ์˜ ์„ฑ๋Šฅ์€ ๊ฑฐ์˜ ์ฐจ์ด ์—†์Œ (์˜คํžˆ๋ ค ๊ฐ€๋…์„ฑ์ด ๋‚˜๋น ์งˆ์ˆ˜๋„ ์žˆ๋‹ค.)
    • ParallelStream ์€ ํ•ด๋‹น ์žฅ๋น„์˜ cpu ๊ฐœ์ˆ˜๋งŒํผ ์Šค๋ ˆ๋“œ ํ’€์„ ๋งŒ๋“ค์–ด ์‚ฌ์šฉ (์˜คํžˆ๋ ค ๋…์ด ๋ ์ˆ˜ ์žˆ์œผ๋‹ˆ ์ž˜ ์•Œ์•„๋ณด๊ณ  ์‚ฌ์šฉํ• ๊ฒƒ)
  • Java 9
  • Java 10
    • var ์˜ ๋“ฑ์žฅ
    • Application Class-Data Sharing(AppCDS)
  • Java 11
  • Java 12

๋ชจ๋‹ˆํ„ฐ๋ง

์œ ๋ช…ํ•œ ์ƒ์šฉ APM๋“ค์„ ์„ค๋ช…ํ•ด ์ฃผ์…จ๋‹ค. ๊ฐ๊ฐ์˜ ์žฅ์ ์— ๋Œ€ํ•ด ์„ค๋ช…ํ•ด ์ฃผ์…จ๋Š”๋ฐ ์ •๋ง ํšŒ์‚ฌ์— ์š”์ฒญํ•ด ๊ตฌ๋งคํ• ์ˆ˜๋งŒ ์žˆ๋‹ค๋ฉด ์‚ฌ์„œ ํ•ด๋ณด๊ณ  ์‹ถ์„์ •๋„๋กœ ์‹ ๊ธฐํ•œ ๊ธฐ๋Šฅ์ด ๋งŽ์•˜๋‹ค. ๊ทธ์ค‘ dynatrace ๋Š” ์—์ด์ „ํŠธ๋งŒ ์„ค์น˜ํ•ด๋‘๋ฉด ๋ณ„๋„์˜ ์„ค์ • ํ•„์š”์—†์ด ์•Œ์•„์„œ ํ•ด์ค€๋‹ค๊ณ …

spring-boot์—์„œ mybatis๋กœ mysql ์—ฐ๋™ํ•˜๊ธฐ

์‹ค๋ฌด์—์„œ ๊ฐœ๋ฐœ์„ ํ•˜๋‹ค๋ณด๋ฉด ๊ณผ๊ฑฐ ๋ˆ„๊ตฐ๊ฐ€ ์ž˜ ๊ตฌ์„ฑํ•ด ๋†“์€ ๋ฐฅ์ƒ(legacy)์— ์ˆŸ๊ฐ€๋ฝ๋งŒ ์–น๋Š” ๋А๋‚Œ์œผ๋กœ ๋กœ์ง ๊ตฌํ˜„๋งŒ ํ• ๋•Œ๊ฐ€ ์žˆ๋‹ค. ๊ทธ๋Ÿฌ๋‹ค๋ณด๋ฉด ๊ฐ์ข… ๋ ˆ์ด์–ด๊ฐ€ ์–ด๋–ป๊ฒŒ ๊ตฌ์„ฑ(์„ค์ •)๋˜์–ด์žˆ๋Š”์ง€๋„ ๋ชจ๋ฅด๊ณ  ๊ฐ„ํ˜น ์„ค์ •์—์„œ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด “์•„ ๋‚ด๊ฐ€ ์ด๊ฒƒ๋„ ๋ชจ๋ฅด๊ณ  ์ด์ œ๊นŒ์ง€ ๊ฐœ๋ฐœ์„ ํ•ด์™”๋‚˜” ํ•˜๋Š” ์ž๊ดด๊ฐ์ด ๋“ค๋ฉฐ ๋ช‡์‹œ๊ฐ„์„ ์‚ฝ์งˆํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ๋‹ค. ๊ทธ๊ฒŒ ์ง€๊ธˆ์˜ ํ•„์ž์ธ๊ฒƒ ๊ฐ™๋‹ค. (๋ˆ™๋ฌผ…)

/images/spring-boot-mybatis-mysql-xml/mung.jpg
์ถœ์ฒ˜ : http://blog.naver.com/PostView.nhn?blogId=ondo_h&logNo=221437452142

์‚ฌ์ด๋“œ ํ”„๋กœ์ ํŠธ ์ดˆ๊ธฐ์…‹ํŒ…์„ ํ•˜๋ฉฐ ํ˜ธ๊ธฐ๋กญ๊ฒŒ spring boot ์ตœ์‹ ๋ฒ„์ „์—์„œ db๋ฅผ ์—ฐ๋™ํ•˜๋ ค ํ–ˆ๋Š”๋ฐ ๋ง‰์ƒ ์™„์ „ ๋ฐ”๋‹ฅ๋ถ€ํ„ฐ ํ•ด๋ณธ ๊ฒฝํ—˜์ด ์ ๋‹ค๋ณด๋‹ˆ (spring boot 2 ๋ฒ„์ „์—์„œ๋Š” ๋”์šฑ๋”…) ์–ด๋””์„œ๋ถ€ํ„ฐ ๋ญ˜ ์„ค์ •์„ ํ•ด์•ผํ• ์ง€… ๊ทธ๋ฆฌ๊ณ  ์ด๋Ÿด๋•Œ ๋ณด๋Š” ๋„ํ๋จผํŠธ๋ฅผ ๋ด๋„ ์ž˜ ์ดํ•ด๊ฐ€ ์•ˆ๋˜์–ด ์‚ฝ์งˆ์„ ํ•ด๊ฐ€๋ฉฐ ๋‹นํ™ฉํ•˜๊ธฐ ์ผ์‘ค์˜€๋‹ค. ์ด๋ฒˆ ํฌ์ŠคํŒ…์—์„œ๋Š” ์•„๋ž˜์™€ ๊ฐ™์€ ๊ตฌ์„ฑ์„ ํ•˜๋Š”๋ฐ ๋ชฉํ‘œ๋ฅผ ๋‘๊ณ ์ž ํ•œ๋‹ค.

  • Spring Boot 2 ํ”„๋กœ์ ํŠธ๋ฅผ ์ฒ˜์Œ ๋งŒ๋“ค๊ณ 
  • mybatis ๋ฅผ ์‚ฌ์šฉํ•ด์„œ
  • mysql ์„ ์—ฐ๋™ํ•˜๋Š”๊ฒƒ (AWS ์˜ RDS๋ฅผ ์‚ฌ์šฉ, ์ถ”ํ›„ RDS์‚ฌ์šฉ๋ฒ•์— ๋Œ€ํ•ด ๋ธ”๋กœ๊น… ์˜ˆ์ •)

์œ„์™€ ๊ฐ™์€ ์ƒํ™ฉ์„ ์ฒ˜์Œ ์ ‘ํ•˜๋Š” ๋ถ„๋“ค๊ป˜ ๋„์›€์ด ๋˜์—ˆ์œผ๋ฉด ํ•˜๋Š” ๋ฐ”๋žจ์œผ๋กœ ์งง๊ฒŒ๋‚˜๋งˆ ํ•„์ž์˜ ์‚ฝ์งˆ๊ธฐ๋ฅผ ์—ฌํ–‰ํ•ด๋ณด์ž.

Spring boot 2 ํ”„๋กœ์ ํŠธ ๋งŒ๋“ค๊ธฐ

ํ•„์ž๋Š” IntelliJ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์–ด์„œ ์ƒˆ๋กœ ํ”„๋กœ์ ํŠธ๋ฅผ ๋งŒ๋“ค๋ ค๊ณ  ํ• ๋•Œ ํด๋ฆญ ๋ช‡๋ฒˆ๋งŒ์œผ๋กœ dependency ์„ค์ •๊นŒ์ง€ ๋‹ค ํ•ด์ฃผ๊ธฐ ๋•Œ๋ฌธ์— ํŽธํ•˜๊ณ  ์ข‹์•˜๋‹ค. ํ˜น ์ดํด๋ฆฝ์Šค๋‚˜ ๋‹ค๋ฅธ IDE๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋‹ค๋ฉด https://start.spring.io/ ์„ ์ฐธ๊ณ ํ•˜๋ฉด ๋„์›€์ด ๋ ๊ฒƒ๊ฐ™๋‹ค. ์—ฌ๊ธฐ์„œ๋„ ํด๋ฆญ ๋ช‡๋ฒˆ์œผ๋กœ IntelliJ ์—์„œ ํ•ด์ฃผ๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋‚ด๊ฐ€ ์‚ฌ์šฉํ•  ๋ชจ๋“ˆ์„ ์„ ํƒํ•˜๊ณ  generate ๋ฅผ ๋ˆ„๋ฅด๋ฉด ํ”„๋กœ์ ํŠธ๊ฐ€ ์ƒ์„ฑ๋˜์–ด ๋‹ค์šด๋กœ๋“œ ๋ฐ›์•„์ง„๋‹ค. (์ฐธ ์ข‹์€ ์„ธ์ƒ…) ์šฐ์„  File โ†’ New โ†’ Project ๋ฅผ ๋ˆŒ๋Ÿฌ์„œ ์•„๋ž˜ ์ฐฝ์„ ์—ด์–ด๋ณด์ž. ๊ทธ๋ฆฌ๊ณ  ๋ญ”๊ฐ€ ๋‹ค ํ•ด์ค„๊ฒƒ ๊ฐ™์€ (๊ฐœ๋ฐœ๋„ ํ•ด์ฃผ๋ฉด ์•ˆ๋˜๋‚˜…) Spring Initializr์„ ์„ ํƒํ›„ ์•„๋ž˜์™€ ๊ฐ™์€ ์„ค์ •์„ ์ ์–ด์ค€ ๋’ค ๋‹ค์Œ์„ ๋ˆŒ๋Ÿฌ์ค€๋‹ค.

/images/spring-boot-mybatis-mysql-xml/1.jpg

์‚ฌ์šฉํ•  ๋ชจ๋“ˆ์„ ์„ ํƒํ•ด์ฃผ์ž. ํ•„์ž๋Š” ์ด๊ฒƒ์ €๊ฒƒ(?)์„ ๋„์™€์ฃผ๋Š” lombok๊ณผ Mybatis, MySQL์„ ์„ ํƒํ•˜๊ณ  ํ”„๋กœ์ ํŠธ๋ฅผ ์ƒ์„ฑํ•˜์˜€๋‹ค. ๊ทธ๋Ÿฌ๋ฉด ์ด์œ(?) pom.xml ๊ณผ ํ•จ๊ป˜ ๋‹น์žฅ ๊ฐœ๋ฐœ์„ ์‹œ์ž‘ํ•  ์ˆ˜ ์žˆ๋Š” ํ™˜๊ฒฝ์ด ์ œ๊ณต๋œ๋‹ค.

<dependencies>
	<dependency>
		<groupId>org.mybatis.spring.boot</groupId>
		<artifactId>mybatis-spring-boot-starter</artifactId>
		<version>2.0.1</version>
	</dependency>
	<dependency>
		<groupId>mysql</groupId>
		<artifactId>mysql-connector-java</artifactId>
	</dependency>	
	<dependency>
		<groupId>org.projectlombok</groupId>
		<artifactId>lombok</artifactId>
		<optional>true</optional>
	</dependency>
</dependencies>
/images/spring-boot-mybatis-mysql-xml/2.jpg

์šฐ์„  ์—ฌ๊ธฐ๊นŒ์ง€ ์ž˜ ๋˜์—ˆ๋Š”์ œ ํ™•์ธํ•ด๋ณด๊ธฐ ์œ„ํ•ด Controller ์— ํ˜„์žฌ์‹œ๊ฐ„์„ ์ถœ๋ ฅํ•˜๋Š”๊ฑธ ๋งŒ๋“ค์–ด ๋ณด๊ณ 

@RestController
public class ApiController {

	@GetMapping(path = "/helloWorld")
	public String helloWorld() {
		return LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME);
	}
}

ํ†ฐ์ผ“์„ ์‹คํ–‰ํ•ด๋ณด๋ฉด ์ •์ƒ์ ์œผ๋กœ ์ ‘์†๊ณผ ์ถœ๋ ฅ์ด ๋˜๋Š”๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

/images/spring-boot-mybatis-mysql-xml/3.jpg

MySQL ์—ฐ๋™ํ•˜๊ธฐ

ํ•„์ž๊ฐ€ ํ—ˆ๋‘ฅ์ง€๋‘ฅ ํ–ˆ๋˜์  ์ค‘ ํ•˜๋‚˜๋Š” MyBatis์™€ MySQL์„ ๋™์‹œ์— ์—ฐ๋™ํ•˜๋ ค๊ณ  ํ•˜๋‹ค๋ณด๋‹ˆ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•ด๋„ ์–ด๋””์„œ์˜ ๋ฌธ์ œ์ธ์ง€๋ฅผ ์ œ๋Œ€๋กœ ํŒŒ์•…ํ•˜์ง€ ๋ชปํ•˜๊ณ  ์‚ฝ์งˆํ–ˆ๋‹ค๋Š” ์ ์ด๋‹ค. ์—ฌ๊ธฐ์„œ ์ •ํ™•ํžˆ ์งš๊ณ  ๋„˜์–ด๊ฐ€๋ฉด ์šฐ์„  ๋ฐ์ดํ„ฐ๋ฅผ ์—ฐ๊ฒฐํ•ด์ฃผ๋Š” ORM์ธ MyBatis๋ฅผ ์…‹ํŒ…ํ•ด์ค€ ๋‹ค์Œ MySQL์„ ์—ฐ๋™ํ•ด์ฃผ๋Š” ์‹์œผ๋กœ ๋ถ„๋ฆฌํ•ด์„œ ์„ค์ •์„ ํ•˜๋ฉด ํ–‡๊ฐˆ๋ฆฌ์ง€ ์•Š๊ณ  (๋Œ์•„๊ฐ€์ง€ ์•Š๊ณ ) ๋ณด๋‹ค ๋น ๋ฅด๊ฒŒ ์„ค์ •์ด ๊ฐ€๋Šฅํ• ๊ฒƒ ๊ฐ™๋‹ค. (์—ฌ๊ธฐ์„œ ์ˆœ์„œ๋Š” ์ค‘์š”ํ•˜์ง€ ์•Š๊ณ  ๋ณ„๋„๋กœ ์„ค์ •ํ•ด์•ผ ํ•œ๋‹ค๋Š” ๊ด€์ ์ด ์ค‘์š”ํ•œ๊ฒƒ ๊ฐ™๋‹ค.) ์šฐ์„  src/main/resourcesํด๋”์— ์žˆ๋Š” application.properties ์— ๋‹ค์Œ์ฒ˜๋Ÿผ ์ž‘์„ฑํ•ด์ฃผ์ž.

spring.datasource.hikari.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.hikari.jdbc-url=jdbc:mysql://{url}:{port}/{db}
spring.datasource.hikari.username={id}
spring.datasource.hikari.password={password}

์œ„์˜ jdbc-url ํ•ญ๋ชฉ์—์„œ AWS์—์„œ ์ œ๊ณตํ•˜๋Š” RDS๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ RDS์—์„œ ์ œ๊ณตํ•ด์ฃผ๋Š” ์—”๋“œํฌ์ธํŠธ์™€ ํฌํŠธ๋ฅผ ์ ์–ด์ฃผ๋ฉด ๋œ๋‹ค. (์ถ”ํ›„ AWS - RDS์— ๋Œ€ํ•ด ๋ธ”๋กœ๊น… ์˜ˆ์ •์ด๋‹ค.) Spring Boot 2.0 ์ดํ›„๋ถ€ํ„ฐ ๊ธฐ๋ณธ์ ์œผ๋กœ ์‚ฌ์šฉ๋˜๋Š” ์ปค๋„ฅ์…˜ ํ’€์ด HikariCP๋กœ ๋ณ€๊ฒฝ๋˜์—ˆ๋‹ค๊ณ  ํ•œ๋‹ค. (๋งํฌ) ์ปค๋„ฅ์…˜ ํ’€ ์ข…๋ฅ˜์ค‘ ์„ฑ๋Šฅ์ด ์ข‹๋‹ค๊ณ  ํ•˜๋Š”๋ฐ ๋งํฌ๋ฅผ ๊ฐ€๋ณด๋ฉด ๋‹ค๋ฅธ ์ปค๋„ฅ์…˜ ํ’€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์™€ ์„ฑ๋Šฅ์„ ๋น„๊ตํ•œ ๋ฒค์น˜๋งˆํฌ ๊ฒฐ๊ณผ๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค. ์œ„์ฒ˜๋Ÿผ spring.datasource.hikari ๊ฐ€ prefix๋กœ ๋ถ™๊ณ  ๊ฐ์ข… ์ •๋ณด๋“ค์„ ์ ์–ด์ฃผ์–ด config ์—์„œ ์ธ์‹๋ ์ˆ˜ ์žˆ๋„๋ก ํ•ด์ฃผ์ž. ๊ทธ ๋‹ค์Œ DataSource ์„ค์ •์„ ํ•ด์ค€๋‹ค.

@Slf4j
@Configuration
@PropertySource("classpath:/application.properties")
public class DatabaseConfiguration {
	@Bean
	@ConfigurationProperties(prefix = "spring.datasource.hikari")
	public HikariConfig hikariConfig() {
		return new HikariConfig();
	}

	@Bean
	public DataSource dataSource() {
		DataSource dataSource = new HikariDataSource(hikariConfig());
		log.info("datasource : {}", dataSource);
		return dataSource;
	}
}

์œ„ ๋‚ด์šฉ์€ DataSource ๋ฅผ hikariConfig์—์„œ ์„ค์ •ํ•œ ์ •๋ณด๋กœ ๋งŒ๋“ค์–ด ์ค€๋‹ค๋Š” ์˜๋ฏธ์ด๋‹ค. ์ด๋ ‡๊ฒŒ๋งŒ ํ•˜๊ณ  ํ”„๋กœ์ ํŠธ๋ฅผ ๋‹ค์‹œ ์‹คํ–‰์‹œ์ผœ๋ณด๋ฉด logger ์— ์˜ํ•ด datasource ์˜ ์ •๋ณด๋ฅผ ๋ณผ์ˆ˜๊ฐ€ ์žˆ๋‹ค.

AWS ํ”„๋ฆฌํ‹ฐ์–ด ๋ฐœ๊ธ‰๋ถ€ํ„ฐ EC2 ์ ‘์†๊นŒ์ง€

IT ์ชฝ์— ์ผ์„ ํ•˜๊ณ  ์žˆ๊ฑฐ๋‚˜ ๊ด€์‹ฌ์„ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ์‚ฌ๋žŒ์ด๋ผ๋ฉด ํ•œ๋ฒˆ์ฏค์„ ๋“ค์–ด๋ดค์„ AWS(Amazon Web Services). ์ด๋ฆ„์—์„œ๋„ ์•Œ์ˆ˜์žˆ๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ์•„๋งˆ์กด์—์„œ ์ œ๊ณตํ•˜๋Š” ๊ฐ์ข… ์›๊ฒฉ ์ปดํ“จํŒ… ์›น์„œ๋น„์Šค์ด๋‹ค. ์•„๋งˆ์กด์€ ์ด๋Ÿฌํ•œ ์„œ๋น„์Šค๋ฅผ ๋ˆ„๊ตฌ๋‚˜ ์‰ฝ๊ฒŒ ์ ‘๊ทผํ•ด๋ณผ์ˆ˜ ์žˆ๋„๋ก AWS ํ”„๋ฆฌํ‹ฐ์–ด๋ฅผ ์ œ๊ณตํ•ด ์ฃผ๋Š”๋ฐ ์ด ํ”„๋ฆฌํ‹ฐ์–ด ๋งŒ์œผ๋กœ๋„ ๊ณผ๊ธˆ์—†์ด (๋˜๋Š” ์ตœ์†Œํ™” ํ•˜์—ฌ) ์›น์„œ๋น„์Šค๋ฅผ ๊ตฌ์„ฑํ• ์ˆ˜ ์žˆ๋‹ค. ํ•„์ž๊ฐ€ ์šด์˜ํ•˜๊ณ  ์žˆ๋Š” ๊ธฐ์ˆ ๋ธ”๋กœ๊ทธ ๊ตฌ๋…์„œ๋น„์Šค๋˜ํ•œ AWS ํ”„๋ฆฌํ‹ฐ์–ด๋กœ ์šด์˜๋˜๊ณ  ์žˆ๋‹ค. ์ตœ๊ทผ GDG Seoul, P-typer, Sketch Seoul ์—์„œ ์ฃผ์ตœํ•œ D.light 345 ํˆฌ๊ฒŒ๋”ํ†ค์— ์ฐธ๊ฐ€ํ•˜๋ฉฐ ์‚ฌ์ด๋“œ ํ”„๋กœ์ ํŠธ๋ฅผ ํ•˜๊ณ  ์žˆ๋Š”๋ฐ ๋งˆ์นจ AWS๋ฅผ ์‚ฌ์šฉํ•˜๊ฒŒ ๋˜์—ˆ๋‹ค. ์˜ˆ์ „์— ์‚ฌ์šฉํ–ˆ์„๋•Œ๋Š” ์žฅ๋‹˜ ์ฝ”๋ผ๋ฆฌ ๋งŒ์ง€๋“ฏ์ด ์„ค์ •์„ ํ–ˆ์—ˆ๋Š”๋ฐ ์ด๋ฒˆ๊ธฐํšŒ๋ฅผ ํ†ตํ•ด ๋‹ค์‹œํ•œ๋ฒˆ ์ •๋ฆฌ๋ฅผ ํ•ด๋ณธ๋‹ค. ๋ณธ ํฌ์ŠคํŒ…์—์„œ๋Š” AWS ๊ณ„์ •์„ ๋ฐœ๊ธ‰๋ฐ›๊ณ  ์‹ ์šฉ์นด๋“œ ํ™•์ธ๊นŒ์ง€ ๋œ ๊ณ„์ •์—์„œ EC2 ์„œ๋ฒ„๋ฅผ ๋ฐœ๊ธ‰๋ฐ›๊ณ  putty๋ฅผ ํ™œ์šฉํ•˜์—ฌ ์„œ๋ฒ„์— ์ ‘๊ทผ์„ ํ•ด๋ณด๋Š”๊ฒƒ์„ ๋ชฉํ‘œ๋กœ ๋‘”๋‹ค.

(์‚ฌ์ด๋“œ ํ”„๋กœ์ ํŠธ๋ฅผ ํ•˜๋ฉด์„œ) ์•„๋งˆ๋„ ์›น์„œ๋น„์Šค๋ฅผ ๊ฐœ๋ฐœํ•˜๋ฉด์„œ AWS๋ฅผ ํ™œ์šฉํ•˜๋Š” ๋ถ€๋ถ„์— ๋Œ€ํ•ด ์‹œ๋ฆฌ์ฆˆ๋ฌผ๋กœ ํฌ์ŠคํŒ…์„ ํ•˜๊ฒŒ ๋ ๊ฒƒ ๊ฐ™๋‹ค. ์‚ฌ์‹ค ๋„ˆ๋ฌด ๊ฐ„๋‹จํ•ด์„œ ์ด๋Ÿฐ๊ฑธ ๊ธ€๋กœ ์“ฐ๋‚˜? ๋ผ๊ณ  ํ• ์ˆ˜๋„ ์žˆ์ง€๋งŒ ๋ˆˆ์œผ๋กœ๋งŒ ๋ณด๋Š”๊ฒƒ๊ณผ ์ง์ ‘ ํ•ด๋ณด๋Š” ๊ฒƒ์ด ๋‹ค๋ฅด๊ณ , ์ด๊ฑธ ๋‹ค์‹œ ๊ธ€๋กœ์จ ์ •๋ฆฌ๋ฅผ ํ•˜๋Š”๊ฒƒ ๋˜ํ•œ ์™„์ „ ๋‹ค๋ฅธ ๋ถ€๋ถ„์ด๊ธฐ ๋•Œ๋ฌธ์— ํฌ์ŠคํŒ…์„ ํ•ด๋ณธ๋‹ค.

EC2 ์ƒ์„ฑํ•˜๊ธฐ

EC2? Amazon Elastic Compute Cloud์˜ ์•ฝ์ž๋กœ ๋ฌผ๋ฆฌ์„œ๋ฒ„๊ฐ€ ์•„๋‹Œ ํด๋ผ์šฐ๋“œ ์„œ๋ฒ„๋ฅผ ์ œ๊ณตํ•˜๊ณ  ์žˆ๋‹ค. EC2์˜ ์žฅ์ ์€ ์„œ๋ฒ„์˜ ์ŠคํŽ™์„ ์‰ฝ๊ณ  ์ž์œ ๋กญ๊ฒŒ ์กฐ์ •ํ•  ์ˆ˜ ์žˆ๋Š”์ ์ด ๊ฐ€์žฅ ๋งค๋ ฅ์žˆ๊ฒŒ ์ƒ๊ฐํ•œ๋‹ค. ์šฐ์„  ์ฝ˜์†”์— ๋“ค์–ด๊ฐ€ EC2๋ฅผ ๊ฒ€์ƒ‰ํ›„ ์ ‘์†์„ ํ•˜๊ณ  ์ธ์Šคํ„ด์Šค ์‹œ์ž‘์„ ๋ˆŒ๋Ÿฌ์„œ ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ ํ™”๋ฉด์œผ๋กœ ๋“ค์–ด๊ฐ„๋‹ค.

/images/aws-freetier-create-and-ssh-access/ec2-1.jpg

AMI ์ฆ‰ ์ƒ์„ฑํ•  ์ด๋ฏธ์ง€๋ฅผ ์„ ํƒํ•˜๋Š” ๋ถ€๋ถ„์ธ๋ฐ ์—ฌ๊ธฐ์„œ ์ฃผ์˜ํ• ์ ์€ ์ž˜๋ชป์„ ํƒ ํ–ˆ๋‹ค๊ฐ„ ๊ณ„์ • ๋งŒ๋“ค์—ˆ์„๋•Œ์˜ ์นด๋“œ๋กœ ์ƒ๊ฐ์ง€๋„ ๋ชปํ•  ๊ธˆ์•ก์ด ๊ฒฐ์ œ๊ฐ€ ๋˜๋ฒ„๋ฆด์ˆ˜๋„ ์žˆ๋‹ค. (์‹ค์ œ๋กœ ํ•„์ž๋„ AWS๋ฅผ ์ฒ˜์Œ ๋งŒ์ ธ๋ณผ๋•Œ ์•„๋ฌด์ƒ๊ฐ์—†์ด ์ข‹์•„๋ณด์ด๋Š”๊ฑธ๋กœ ํ–ˆ๋‹ค๊ฐ€ ํ•œ 30๋‹ฌ๋Ÿฌ ์ •๋„๋ฅผ ์ง€๋ถˆํ–ˆ์–ด์•ผ๋งŒ ํ–ˆ๋‹ค…) ์ขŒ์ธก์— ๋ณด๋ฉด ํ”„๋ฆฌ ํ‹ฐ์–ด๋งŒ์ด๋ผ๋Š” ์ฒดํฌ๋ฐ•์Šค๋ฅผ ์ฒดํฌํ•˜๊ณ  ์ž์‹ ์ด ์›ํ•˜๋Š” ์ด๋ฏธ์ง€๋ฅผ ์„ ํƒํ•˜์ž. ์ผ๋ฐ˜์ ์ธ ๋ฆฌ๋ˆ…์Šค ์„œ๋ฒ„๋ฅผ ๋ฐœ๊ธ‰๋ฐ›๊ณ  ์‹ถ๊ธฐ ๋•Œ๋ฌธ์— ๋นจ๊ฐ„ ์˜์—ญ์˜ ์ด๋ฏธ์ง€๋ฅผ ์„ ํƒํ•˜๊ณ  ์„ ํƒํ•œ ์ด๋ฏธ์ง€์˜ ์ŠคํŒฉ์„ ๋‹ค์‹œํ•œ๋ฒˆ ํ™•์ธํ•˜์ž. (cpu 1๊ฐœ์— ๋ฉ”๋ชจ๋ฆฌ๋„ 1๊ธฐ๊ฐ€… ๋„ˆ๋ฌด ์งœ์ง€๋งŒ ๋ฌด๋ฃŒ๋‹ˆ๊นŒ…)

/images/aws-freetier-create-and-ssh-access/ec2-2.jpg

๋งˆ์ง€๋ง‰์œผ๋กœ ์‹œ์ž‘ํ•˜๊ธฐ ๋ฅผ ๋ˆ„๋ฅด๋ฉด ํ‚ค ํŽ˜์–ด๋ฅผ ์„ ํƒ ๋˜๋Š” ์ƒ์„ฑํ•˜๋„๋ก ์•ˆ๋‚ด๊ฐ€ ๋‚˜์˜ค๋Š”๋ฐ ๋‹น์—ฐํžˆ ์•„๋ฌด๊ฒƒ๋„ ์•ˆํ•œ ์ƒํƒœ๋ผ ์ƒˆ ํ‚ค ํŽ˜์–ด ์ƒ์„ฑ์„ ์„ ํƒํ•ด ์ฃผ๊ณ  ์ด๋ฆ„์„ ์ง€์ •ํ•œ๋’ค ํ‚ค ํŒŒ์ผ์„ ๋ฐ›์•„์ค€๋‹ค. ์ด ๋ถ€๋ถ„์—์„œ๋„ ์กฐ์‹ฌํ•ด์•ผํ•  ์ ์ด ํ‚ค ํŽ˜์–ด๋ฅผ ํ•œ๋ฒˆ ๋‹ค์šด ๋ฐ›์œผ๋ฉด ๋‹ค์‹œ ๋™์ผํ•œ ํ‚ค ํŽ˜์–ด๋ฅผ ๋‹ค์šด๋ฐ›์„์ˆ˜๊ฐ€ ์—†๊ฒŒ ๋œ๋‹ค. (๋‚˜์ค‘์— ๋‹ค์‹œ ๋ฐœ๊ธ‰์„ ๋ฐ›์•„์•ผ ํ•˜๋Š” ๋ฒˆ๊ฑฐ๋กœ์šด ๋ฌธ์ œ๊ฐ€…) ๋‹ค์šด์„ ๋ฐ›๊ณ  ์žŠ์–ด๋ฒ„๋ฆฌ์ง€ ์•Š๋„๋ก ์ž˜ ๋ณด๊ด€ํ•ด๋‘์ž.

/images/aws-freetier-create-and-ssh-access/ec2-3.jpg

ํ‚ค ํŽ˜์–ด๋ฅผ ๋‹ค์šด ๋ฐ›์œผ๋ฉด ์ƒ์„ฑ์ค‘์ด๋ผ๋Š” ๋ฉ”์„ธ์ง€์™€ ํ•จ๊ป˜ ๊ฒฐ๊ณผํ™”๋ฉด์ด ๋‚˜์˜จ๋‹ค. ์—ฌ๊ธฐ์„œ๋„ ์ค‘์š”ํ•œ ๋ถ€๋ถ„! ํ”„๋ฆฌํ‹ฐ์–ด๋ผ๋Š” ๋‹ฌ์ฝคํ•œ ํ‚ค์›Œ๋“œ ๋•Œ๋ฌธ์— ๋“ค๋œฌ ๋งˆ์Œ์œผ๋กœ ์„ฑ๊ธ‰ํ•˜๊ฒŒ ๋นจ๋ฆฌ ์„œ๋ฒ„๋ฅผ ๋ฐ›์•„๋ณด๊ณ  ์‹ถ๋‹ค๊ณ  ๋‹ค์Œ๋‹ค์Œ ์‹ ๊ณต์„ ํ•˜๋‹ค๋ณด๋ฉด ์ž์นซ ๊ฐ„๊ณผํ• ์ˆ˜๊ฐ€ ์žˆ๋Š”๋ฐ ํ™”๋ฉด์„ ๋ณด๋ฉด ๊ฒฐ์ œ ์•Œ๋ฆผ ์ƒ์„ฑ์ด๋ผ๋Š” ๋‹คํ–‰์Šค๋Ÿฌ์šด ๊ธฐ๋Šฅ์ด ์žˆ๋‹ค. ๋ณ„ ์–ด๋ ค์šด ์„ค์ •์ด ์•„๋‹ˆ๋‹ˆ ๊ผญ ์„ค์ •์„ ํ•ด์„œ ํ•„์ž๊ฐ™์ด ๊ธฐ๋ถ€(?)๋ฅผ ํ•˜๋Š” ์ผ์ด ๋ฐœ์ƒํ•˜์ง€ ์•Š์•˜์œผ๋ฉด ํ•œ๋‹ค…

/images/aws-freetier-create-and-ssh-access/ec2-4.jpg

EC2 ์ธ์Šคํ„ด์Šค๊ฐ€ ์ƒ์„ฑ์ด ๋˜์—ˆ๋‹ค. ์ธ์Šคํ„ด์Šค์˜ ๊ฐ์ข… ์ •๋ณด๋ฅผ ํ™•์ธํ• ์ˆ˜๊ฐ€ ์žˆ๋Š”๋ฐ public IP, public DNS ๊นŒ์ง€ ์ œ๊ณต๋˜๋Š”๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค. (์ถ”ํ›„ DNS๋ฅผ ๊ตฌ์ž…ํ•˜๊ฒŒ ๋˜๋‹ค๋ฉด ์ด IP์— ์—ฐ๊ฒฐ์„ ์‹œ์ผœ ๋„๋ฉ”์ธ์œผ๋กœ ํ•ด๋‹น ์„œ๋ฒ„์— ์ ‘์†์„ ํ• ์ˆ˜๊ฐ€ ์žˆ๊ฒŒ ๋œ๋‹ค.)

/images/aws-freetier-create-and-ssh-access/ec2-5.jpg

putty ๋กœ ๋ฐœ๊ธ‰๋ฐ›์€ EC2 ์ธ์Šคํ„ด์Šค์— ์ ‘์†์„ ํ•ด๋ณด์ž.

์ด์ œ ๋ฐœ๊ธ‰๋ฐ›์€ EC2 ์ธ์Šคํ„ด์Šค์— ์ ‘์†์„ ํ•ด๋ณผ ์ฐจ๋ก€์ด๋‹ค. ๋‹ค์–‘ํ•œ ์„œ๋ฒ„ ์ ‘์†ํˆด์ด ์žˆ์ง€๋งŒ ํ•„์ž๋Š” putty๋ฅผ ๊ฐ€์žฅ ์„ ํ˜ธํ•œ๋‹ค. ๋””์ž์ธ์€ ๊ตฌ๋‹ฅ๋‹ค๋ฆฌ์ฒ˜๋Ÿผ ๋ณด์ผ์ง€ ๋ชจ๋ฅด๊ฒ ์ง€๋งŒ ๊ฐœ์ธ์ ์œผ๋กœ ์ง๊ด€์ ์ธ UI์— ๊ฐ€๋ฒผ์šด ํ”„๋กœ๊ทธ๋žจ์ด๋ผ ์ƒ๊ฐ์ด ๋“ ๋‹ค. ์šฐ์„  putty๋ฅผ ๋‹ค์šด ๋ฐ›๊ณ  putty.exe๋ฅผ ์‹คํ–‰์‹œํ‚จ๋’ค์— ๋ฐ”๋กœ ssh ์ ‘์†์„ ํ•˜๋ฉด ๋„ˆ๋ฌด ๊ฐ„๋‹จํ•˜๊ฒŒ ์„œ๋ฒ„ ์ ‘์†์— ์„ฑ๊ณต์„ ํ• ์ˆ˜ ์žˆ์ง€๋งŒ ์œ„์—์„œ ๋ฐ›์€ ํ‚ค ํŽ˜์–ด ํŒŒ์ผ์„ ๋‹ค์‹œ private key ๋กœ ์ „ํ™˜ํ•ด์•ผ ํ•˜๋Š”๋ฐ putty๋ฅผ ๋‹ค์šด๋ฐ›์œผ๋ฉด ๋™์ผํ•œ ํด๋”์— puttygen.exe๋ผ๋Š” ํŒŒ์ผ์„ ์‹คํ–‰์‹œ์ผœ์ฃผ์ž. ๊ทธ๋‹ค์Œ pemํŒŒ์ผ์„ ๋ถˆ๋Ÿฌ์™€์„œ ๋งˆ์šฐ์Šค๋ฅผ ์›€์ง์—ฌ์„œ ๊ฒŒ์ด์ง€(?)๋ฅผ ๋‹ค ์ฑ„์šฐ๊ณ  save private key๋ฅผ ์ค„๋Ÿฌ ์ €์žฅ์„ ํ•˜๋Š”๋ฐ ์—ฌ๊ธฐ์„œ ์ฃผ์˜ํ• ์ ์€ ppkํŒŒ์ผ๋ช…์„ pemํŒŒ์ผ๋ช…๊ณผ ๋™์ผํ•˜๊ฒŒ ์ €์žฅํ•ด์•ผ ํ•œ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค. (์•ˆ๊ทธ๋Ÿฌ๋ฉด ์„œ๋ฒ„ ์ ‘์†์‹œ ์‹คํŒจ๊ฐ€ ๋‚จ… ์‚ฝ์งˆ…)

KafkaKRU(Kafka ํ•œ๊ตญ์‚ฌ์šฉ์ž ๋ชจ์ž„) ๋ฐ‹์—… ํ›„๊ธฐ

ํ•„์ž๋Š” ElasticStack์„ ์‚ฌ์šฉํ•˜๋ฉด์„œ ์ฒ˜์Œ ์นดํ”„์นด๋ฅผ ์ ‘ํ•˜๊ฒŒ ๋˜์—ˆ๋‹ค. ๋ฉ”์„ธ์ง• ํ ๋ผ๋Š” ๊ฐœ๋…๋„ ์ „ํ˜€ ๋ชจ๋ฅด๋Š” ์ƒํƒœ์—์„œ ์„ค์น˜๋ถ€ํ„ฐ ElasticStack ์—ฐ๋™๊นŒ์ง€ ์‚ฌ์šฉํ•˜๋ฉฐ ์ •๋ง ๊ฐ•์ œ๋กœ ์นดํ”„์นด์— ๋Œ€ํ•ด ๊ณต๋ถ€๋ฅผ ํ•˜๊ฒŒ ๋˜์—ˆ๋‹ค. ์นดํ”„์นด๋ฅผ ์ž์ฃผ ๋‹ค๋ฃจ๊ณ  ๋ฉ”์ปค๋‹ˆ์ฆ˜์— ๋Œ€ํ•ด ์ž์„ธํžˆ ์‚ดํŽด๋ณด๋‹ค ์ž ๊น ํ•ด์ดํ•ด์งˆ ๋ฌด๋ ต ์นดํ”„์นด ํ•œ๊ตญ ์‚ฌ์šฉ์ž ๋ชจ์ž„์—์„œ ๋ฐ‹์—…์„ ํ•œ๋‹ค๊ณ  ํ•˜๊ธธ๋ž˜ ๋น›์˜ ์†๋„๋กœ ์‹ ์ฒญ, ์•„๋งˆ๋„ 1๋“ฑ์œผ๋กœ ์‹ ์ฒญํ–ˆ์ง€ ์•Š์•˜์„๊นŒ ์‹ถ๋‹ค. ์‚ฌ์‹ค ์ž‘๋…„ ์นดํ”„์นด ๋ฐ‹์—…์„ ๋ชป๊ฐ„๊ฒŒ ๋„ˆ๋ฌด ํ•œ(?)์ด ๋˜์–ด ์ด๋ฒˆ์—” ํšŒ์‚ฌ ์—…๋ฌด ๋“ฑ ์—ฌ๋Ÿฌ๊ฐ€์ง€๋กœ ํ•œ์ฐฝ ๋ฐ”์˜์ง€๋งŒ “์ง€๊ธˆ์ด ์•„๋‹ˆ๋ฉด ์•ˆ๋ผ” ๋ผ๋Š” ์ƒ๊ฐ์œผ๋กœ ๋ฐ‹์—…์„ ๋‹ค๋…€์™”๊ณ , ์งง์ง€๋งŒ ํ›„๊ธฐ๋ฅผ ์ž‘์„ฑํ•ด ๋ณด๊ณ ์ž ํ•œ๋‹ค.

(์š”์ฆ˜ ์™œ ์ด๋ ‡๊ฒŒ ๋ฐ”์œ์ง€ ๋ชจ๋ฅด๊ฒ ์ง€๋งŒ… ์‹ ๊ธฐํ•˜๊ฒŒ๋„ ๊ทธ ๋ฐ”์œ ์ผ์ •๋“ค์ด ํ•˜๋‚˜๋„ ๊ฒน์น˜์ง€ ์•Š๋Š”๊ฒŒ ๋” ์‹ ๊ธฐํ•˜๋‹ค… )

/images/kafka-meetup-2019/first.jpg
์‚ผ์„ฑ SDS ๊ฑด๋ฌผ์—์„œ ์ง„ํ–‰๋œ ์นดํ”„์นด ๋ฐ‹์—…

์ฐธ๊ณ ๋กœ ํ•„์ž๋Š” ์นดํ”„์นด์— ๋Œ€ํ•ด ์•„์ฃผ ์กฐ๊ธˆ ๊ฑด๋“œ๋ ค๋ณธ ์ˆ˜์ค€์ด๋ผ ๋ฐœํ‘œํ•˜์‹œ๋Š” ๋ถ„๋“ค์˜ ์ „๋ถ€๋ฅผ ์Šต๋“ํ•˜๊ธฐ์—” ๋‹ค์†Œ ๊ทธ๋ฆ‡์ด ์ž‘์•„์„œ ์ผ๋ถ€ ์„ธ์…˜์€ ๊ฑฐ์˜ “๊ทธ๋Ÿฐ๊ฐ€๋ณด๋‹ค~” ํ•˜๊ณ  ๋“ค์„ ์ˆ˜ ๋ฐ–์— ์—†์—ˆ๋‹ค. ํ›„๊ธฐ๋„ ์•„๋งˆ ๊ทธ๋Ÿฐ ๋งฅ๋ฝ์œผ๋กœ ์ž‘์„ฑํ• ๋“ฏ ์‹ถ๋‹ค.

์นดํ”„์นด๋ฅผ ํ™œ์šฉํ•œ ์บ์‹œ ๋กœ๊ทธ ์ฒ˜๋ฆฌ - ๊น€ํ˜„์ค€(์นด์นด์˜ค)

  • ์ด๋ฏธ์ง€ ๋“ฑ ์บ์‹œ์„œ๋ฒ„์˜ ๋กœ๊ทธ๋ฅผ ๋ถ„์„ํ•˜๊ธฐ ์œ„ํ•œ ์‹œ์Šคํ…œ์„ ๊ตฌ์ถ•ํ•˜๋Š”๋ฐ ElasticStack ์„ ํ™œ์šฉ
  • Elasticsearch ๋กœ ๋Šฆ๊ฒŒ ๋“ค์–ด์™€์„œ ์‚ฌ๋ก€๋ฅผ ์ฐพ์•„๋ณด๋‹ˆ ๋Œ€์šฉ๋Ÿ‰ ๋กœ๊น… ์ฒ˜๋ฆฌ์‹œ ์•ž๋‹จ์— ๋ฉ”์„ธ์ง• ํ๋ฅผ ๋‘ฌ์•ผ ํ•œ๋‹ค๊ณ  ํ–ˆ๊ณ  ๊ทธ๊ฒŒ ์นดํ”„์นด
  • ์นดํ”„์นด ๋ชจ๋‹ˆํ„ฐ๋ง์€ ๊ทธ๋ผํŒŒ๋‚˜๋กœ ํ™œ์šฉ
  • lag์ด ์ž๊พธ ์ƒ๊น€
    • ํŒŒํ‹ฐ์…˜์„ ์ชผ๊ฐœ๊ฑฐ๋‚˜, ์ปจ์Šˆ๋จธ๋ฅผ ๋Š˜๋ฆฌ๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ์Œ
    • auto.commit.interval.ms ์™€ enable.auto.commit=true ๋กœ ์กฐ์ •
    • interval์„ ์ค„์ด๋‹ˆ lag์ด ์ค„์–ด๋“ฌ
  • ํ˜„์žฌ๋Š” ์ˆ˜๋ฐฑ๋Œ€ ์บ์‹œ์„œ๋ฒ„์˜ ๋กœ๊ทธ๋ฅผ ์ดˆ๋‹น 15๋งŒ๊ฑด ์ด์ƒ ์ฒ˜๋ฆฌ์ค‘

์งˆ๋ฌธ์„ ํ–ˆ๋‹ค. ํ•„์ž๋„ lag์ด ๋†’์•„์ง€๋ฉด ์–ด์ฉŒ์ง€ ํ•˜๋Š” ๋ถˆ์•ˆ๊ฐ๊ณผ ๋†’์•„์ง€๋ฉด ์ปจ์Šˆ๋จธ๋ฅผ ๋Š˜๋ฆฌ๋ฉด ๋˜๊ฒ ์ง€ ํ•˜๋Š” ๋ง‰์—ฐํ•จ์ด ์žˆ์—ˆ๋Š”๋ฐ commit interval์„ ์ค„์ด๋ฉด lag์ด ์ค„์–ด๋“ ๋‹ค๊ณ  ํ•ด์„œ ๋ฌด์กฐ๊ฑด ์ค„์ด๋ฉด ์ข‹์€๊ฐ€์— ๋‹ต๋ณ€์€ ์นดํ”„์นด๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ์ฃผํ‚คํผ์ชฝ์— ๋ฌด๋ฆฌ๊ฐ€ ๊ฐ„๋‹ค๊ณ  ์„ค๋ช…ํ•ด ์ฃผ์…จ๋‹ค. ์—ญ์‹œ ๋งŒ๋ณ‘ํ†ต์น˜์•ฝ์€ ์—†๊ณ  ์ƒํ™ฉ์— ๋”ฐ๋ผ ์ ์ ˆํ•˜๊ฒŒ ์‹œ์Šคํ…œ ๊ด€๋ฆฌ์ž๊ฐ€ ์กฐ์ •ํ•ด๊ฐ€๋ฉฐ ์šด์˜ํ•ด์•ผ ํ•˜๋Š”์ ์„ ๋А๊ผˆ๋‹ค.

์นดํ”„์นด๋ฅผ ํ™œ์šฉํ•œ ์—˜๋ผ์Šคํ‹ฑ์„œ์น˜ ์‹ค๋ฌดํ”„๋กœ์ ํŠธ ์†Œ๊ฐœ - ์ด์€ํ•™(๋ฉ”๊ฐ€์กด)

  • ์นด๋“œ์‚ฌ์˜ ํ”„๋กœ์ ํŠธ๋ฅผ ์•ฝ 3๊ฐœ์›”๊ฐ„ ๊ฐœ๋ฐœํ•˜์˜€๊ณ  ์ „์ฒด ์•„ํ‚คํ…์ณ ์ค‘์— ์ผ๋ถ€๋ถ„์„ kakfa๋ฅผ ํ™œ์šฉ
  • Elasticsearch ๋ฐ์ดํ„ฐ๋ฅผ hadoop์— ๋ฐฑ์—… ํ˜•ํƒœ๋กœ ์˜ฎ๊ธฐ๋ฉฐ ๊ด€๋ฆฌ
  • filebeat > kafka > spark streaming ์„ ํ™œ์šฉํ•˜์—ฌ ๋ฐ์ดํ„ฐ์˜ ๊ฒ€์ฆ์ฒ˜๋ฆฌ๊ฐ€ ๊ฐ€๋Šฅ (ํŠน์ • ์ƒํ™ฉ์—์„œ์˜ ๊ด€๋ฆฌ์ž์—๊ฒŒ ์•Œ๋ฆผ ๋“ฑ)
  • logstash ์˜ ruby ํ•„ํ„ฐ๋ฅผ ํ™œ์šฉํ•˜์—ฌ ์ผ์ •์˜ ์ž‘์—…์„ ํ•ด์ฃผ๋Š” ๋ฐ์ดํ„ฐ ํŒŒ์ดํ”„๋ผ์ธ ๊ตฌ์„ฑ ๊ฐ€๋Šฅ (๊ฐœ์ธ์ •๋ณด ์‹๋ณ„ ๋“ฑ)
  • logstash ๋Š” cronํ˜•ํƒœ์˜ ๋ฐฐ์น˜๋กœ๋„ ๊ฐ€๋Šฅ

๋˜ ์งˆ๋ฌธ์„ ํ•˜์˜€๋‹ค. (์นดํ”„์นด ๋ฐ‹์—…๊ณผ๋Š” ๋ฌด๊ด€ํ–ˆ์ง€๋งŒ…) logastsh ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด์„œ ํ•„ํ„ฐ์ชฝ์— ๋กœ์ง์ด ๋“ค์–ด๊ฐ€๋ฉด ์„ฑ๋Šฅ์ƒ ๊ดœ์ฐฎ๋ƒ๋Š” ์งˆ๋ฌธ์— ํ•˜๋ฃจ์— 15์–ต๊ฑด์„ ์ฒ˜๋ฆฌํ•˜๊ณ ์žˆ๊ณ  ๋ฌธ์ œ๊ฐ€ ์—†์—ˆ๋‹ค๊ณ  ํ•œ๋‹ค. ํ•„์ž๋Š” ์•„ํŒŒ์น˜ ์—‘์„ธ์Šค ๋กœ๊ทธ๋ฅผ logstash๋กœ ์ฒ˜๋ฆฌํ•˜๋ฉด์„œ ๊ฐ„ํ˜น ๋ป—๊ฑฐ๋‚˜ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ–ˆ๋Š”๋ฐ ์•„๋งˆ ํŒŒ์ผ์„ logstash๊ฐ€ ์ง์ ‘ ๋ฐ”๋ผ๋ณด๊ณ  ์ฒ˜๋ฆฌ๋„ ํ•˜๊ฒŒํ•ด์„œ ๊ทธ๋Ÿฐ๊ฒƒ ๊ฐ™๋‹ค. (์ง€๊ธˆ์€ filebeat๊ฐ€ shipper ์—ญํ™œ์„ ์ˆ˜ํ–‰ํ•˜๊ณ  ์žˆ๊ณ  ํฐ ๋ฌด๋ฆฌ ์—†์ด ์šด์˜์ค‘)

์นดํ”„์นด๋ฅผ ํ™œ์šฉํ•œ rabbitMQ ๋กœ๊ทธ์ฒ˜๋ฆฌ - ์ •์›๋นˆ (์นด์นด์˜ค)

  • ๋ ˆ๋น—์— ํ๋Š” erlang์œผ๋กœ ๊ตฌํ˜„๋œ AMQP ๋ฉ”์‹œ์ง€ ๋ธŒ๋กœ์ปค์ด๊ณ  TCP๊ธฐ๋ฐ˜์œผ๋กœ ๊ตฌ์„ฑ
  • Kafka ๋Š” ๊ฒŒ์œผ๋ฅด์ง€๋งŒ ๋ฉ”์šฐ ํšจ์œจ์„ฑ์ด ๋›ฐ์–ด๋‚จ, ๋ฐ˜๋ฉด RabbitMQ ๋Š” ๋˜‘๋˜‘ํ•˜์ง€๋งŒ ๋ณด๋‹ค ๋А๋ฆผ
  • Kafka ์—์„œ Elasticsearch ๋กœ์˜ ingset ๋Š” NIFI๋ฅผ ํ™œ์šฉ
  • ๋ ˆ๋น—์— ํ์™€ ์นดํ”„์นด์˜ ์ฐจ์ด
    KafkaRabbitMQ
    ์ปจ์Šˆ๋จธ ์ถ”๊ฐ€์—ฌ๋Ÿฌ ์ปจ์Šˆ๋จธ๊ฐ€ ํ•˜๋‚˜์˜ ๋ฉ”์„ธ์ง€๋ฅผ ๋™์‹œ์— ํ• ์ˆ˜ ์žˆ์–ด ํ™•์žฅ์— ์šฉ์ดํ•จํ™•์žฅํ• ๋•Œ๋งˆ๋‹ค ํ๋ฅผ ์ถ”๊ฐ€ ์ƒ์„ฑํ•ด์•ผํ•จ
    ๋ฉ”์„ธ์ง€ ์ €์žฅ๋กœ๊ทธ๊ธฐ๋ฐ˜์œผ๋กœ ๋””์Šคํฌ์— ์ €์žฅ, ๋ฆฌํ…์…˜ ์ดํ›„ ์‚ญ์ œํ ๊ธฐ๋ฐ˜์œผ๋กœ ๋ฉ”๋ชจ๋ฆฌ์— ์ €์žฅ ์ปจ์Šˆ๋จธ๊ฐ€ ๋ฉ”์„ธ์ง€ ์ˆ˜์‹ ์‹œ ์ฆ‰์‹œ ์‚ญ์ œ
    ๋ฉ”์„ธ์ง€ ์ฒ˜๋ฆฌ๋ฐœ์†กํ™•์ธ ๊ฐ€๋Šฅ / ์ˆ˜์‹ ํ™•์ธ ๋ถˆ๊ฐ€๋Šฅ๋ฐœ์†กํ™•์ธ/์ˆ˜์‹ ํ™•์ธ ๊ฐ€๋Šฅ

์นดํ”„์นด๋ฅผ ๋งˆ์ดํฌ๋กœ์„œ๋น„์Šค ์•„ํ‚คํ…์ณ์— ํ™œ์šฉํ•˜๊ธฐ - ์ด๋™์ง„ (์•„ํŒŒ์น˜ ์†Œํ”„ํŠธ์›จ์–ด ํŒŒ์šด๋ฐ์ด์…˜)

  • ์นดํ”„์นด ์ŠคํŠธ๋ฆผ์ฆˆ ์†Œ๊ฐœ (Interactive Query)
  • ์นดํ”„์นด๋ฅผ ํ™œ์šฉํ•˜์—ฌ ๋งˆ์ดํฌ๋กœ์„œ๋น„์Šค์—์„œ ์‚ฌ์šฉํ•˜๋ ค๋ฉด ๋ฐ์ดํ„ฐ๋ฅผ ์ž„์‹œ ๊ณต๊ฐ„์— ๋„ฃ์–ด๋‘๊ณ  (redis ๊ฐ™์€?) ๋นผ์„œ ์‚ฌ์šฉํ•˜๋Š” ํ˜•ํƒœ๊ฐ€ ์•„๋‹ˆ๋ผ Interactive Query ๋˜๋Š” Queryable Store ๋กœ ํ™œ์šฉ ๊ฐ€๋Šฅ

์‚ฌ์‹ค ์ด๋ถ€๋ถ„์€ ํ•„์ž๊ฐ€ ์ œ๋Œ€๋กœ ๋ชป๋”ฐ๋ผ๊ฐ„ ์„ธ์…˜์ค‘์— ํ•˜๋‚˜์ด๋‹ค. ์šฉ์–ด๋‚˜ ๋ฉ”์ปค๋‹ˆ์ฆ˜๋„ ๋‹ค์†Œ ์ƒ์†Œํ–ˆ๊ณ  ๋Œ€๋žต ์–ด๋–ค ๋ถ€๋ถ„์„ ๋ฐœํ‘œํ•ด์ฃผ์‹œ๋Š”์ง€ ๋А๋‚Œ์€ ์žˆ์—ˆ์œผ๋‚˜ ์ œ๋Œ€๋กœ ์ดํ•ด๋ฅผ ๋ชปํ•ด์„œ … ๋ถ€๋„๋Ÿฝ์ง€๋งŒ ์นดํ”„์นด ์ŠคํŠธ๋ฆผ์ฆˆ์˜ ๊ณต์‹๋งํฌ๋กœ ๋Œ€์ฒดํ•œ๋‹ค.