Skip to main content

12 posts tagged with "java"

View All Tags

다중 접속 서버로의 여정

· 29 min read
Haril Song
Owner, Software Engineer at 42dot

banner

Overview

여러 클라이언트의 요청을 동시에 핸들링할 수 있는 서버 애플리케이션을 구현하는 건 이제 너무나 쉽습니다. Spring MVC만 사용해도 뚝딱 만들어낼 수 있으니까요. 하지만, 엔지니어로서, 그 이면의 원리가 너무나 궁금합니다 🤔. 이번 글에서는 당연한 것처럼 느껴지는 것들에 '왜' 라는 질문을 던져보며, 다중 접속 서버를 구현하기 위해 어떤 고민이 있었는지 되짚어보는 여정을 떠나봅니다.

info

예제 코드는 GitHub 에서 확인하실 수 있습니다.

소켓(Socket)

먼저 '소켓' 에서 출발합니다. 네트워크 프로그래밍 관점에서 소켓은, '네트워크상에서 데이터를 주고받기 위해 파일처럼 사용되는 통신 엔드포인트' 입니다. '파일처럼 사용되는' 이라는 설명이 중요한데, 파일 디스크립터(file descriptor, fd) 를 통해 접근되고 파일과 유사한 I/O 연산을 지원하기 때문입니다.

  • 파일과 유사하게 다뤄야 하다 보니 많은 요청을 위해서는 그만큼의 파일을 열 수 있어야 하겠습니다.
  • 예전에는 1개의 프로세스가 열 수 있는 파일 개수가 4096개로 제한되어 있었습니다.
  • ulimit 을 사용하면 이 제한을 확인할 수 있습니다.
  • 요즘은 unlimited 가 기본이라 크게 신경쓸 필요는 없지만, 오래된 리눅스 버전을 사용하는 경우는 주의해야 합니다.
  • Too Many Open Files 라는 에러가 발생하면 이를 확인해보세요.
왜 소켓을 port 가 아닌 fd 로 식별할까요?

자신의 ip, port, 상대방의 ip, port 를 사용하여 소켓을 식별하는 데 사용할 수 있지만 fd 를 사용하는 이유는 연결이 수락되기 전 소켓에는 아무런 정보가 없기 때문이고 ip 와 port 의 조합은 단순한 정수인 fd 보다 많은 데이터가 필요하기 때문입니다.

소켓을 사용하여 서버 애플리케이션을 구현하려면 다음과 같은 과정을 거쳐야 합니다.

Java 에서 Hello World 를 출력하기까지 2

· 14 min read
Haril Song
Owner, Software Engineer at 42dot

이전 글 에 이어서 "Hello World" 를 출력하기 위해 코드가 어떻게 변해가는지 살펴봅니다.

Chapter 2. Compile 과 Disassemble

프로그래밍 언어에는 레벨이 있다.

프로그래밍 언어가 인간의 언어와 가까울수록 고수준 언어(high-level language), 컴퓨터가 이해할 수 있는 언어(=기계어)에 가까울수록 저수준 언어(low-level language)라고 한다. 고수준 언어로 프로그램을 작성하면 인간이 이해하기 쉽기에 높은 생산성을 얻을 수 있지만, 그만큼 기계어와의 괴리가 심해지니 이 간극을 메우기 위한 과정이 필요하다.

고수준 언어가 저수준으로 내려오는 과정, 이걸 컴파일(compile) 이라고 부른다.

Java 또한 저수준 언어는 아니므로, 컴파일 과정이 존재한다. 자바에서는 이 컴파일 과정이 어떻게 동작하는지 살펴보자.

Java 에서 Hello World 를 출력하기까지 1

· 17 min read
Haril Song
Owner, Software Engineer at 42dot

banner

프로그래밍 세계에서는 항상 Hello World 라는 문장을 출력하면서 시작한다. 그게 국룰 암묵적인 규칙이다.

# hello.py
print("Hello World")
python hello.py
// Hello World

Python? 훌륭하다.

// hello.js
console.log("Hello World");
node hello.js
// Hello World

JavaScript? 나쁘지 않다.

public class VerboseLanguage {
public static void main(String[] args) {
System.out.println("Hello World");
}
}
javac VerboseLanguage.java
java VerboseLanguage
// Hello World

그런데 Java 는 마치 다른 세계에서 온 것 같다. class 이름과 파일 이름이 같아야 하는 점은 아직 언급도 안했다.

public 은 무엇이고 class 는 무엇이고, static 은 또 무엇이며, void, main, String[], System.out.println 을 거쳐야 드디어 "Hello World" 라는 문자열에 도달한다. 이제 다른 언어를 배우러 가자.[^fn-nth-1]

단순한 "Hello World" 를 출력하는 것임에도 Java 는 꽤 많은 배경 지식을 요구한다. Java 는 도대체 왜 이리 말 많은(verbose) 과정이 필요할까?

이번 시리즈는 3개의 챕터로 구성되어 있다. 목표는 "Hello World" 라는 2단어를 출력하기 위해 뒤에서는 무슨 일이 일어나는지 자세하게 살펴보는 것이다. 구체적인 챕터의 내용은 아래와 같다.

  • 첫 번째 챕터에서는 의문의 시작이 되는 Hello World 를 살펴보면서 간단하게 이유를 소개한다.
  • 두 번째 챕터에서는 실제로 컴파일된 class 파일을 살펴보며 컴퓨터가 java 코드를 어떻게 해석하고 실행하는지 살펴본다.
  • 마지막으로 public static void mainJVM 이 어떻게 메모리에 어떻게 적재하고 실행할 수 있는지 그 동작 원리에 대해 살펴본다.

3개의 챕터 내용을 조합하면 그제서야 "Hello World" 에 대해 그림이 그려진다. 꽤 긴 여정이니, 호흡을 가다듬고 출발해보자.

Test 의 실행속도를 빠르게, Spring context mocking

· 5 min read
Haril Song
Owner, Software Engineer at 42dot

Overview

모든 프로젝트에서 테스트 코드를 작성하는 것은 이제 일상이 된지 오래다. 프로젝트가 성장해나간다면 필연적으로 테스트의 수도 많아지면서 전체 테스트 수행시간이 점점 길어지게 된다. 특히 Spring framework 을 기반으로 하는 프로젝트의 테스트를 쓰고 있다면 Spring Bean 의 Context loading 에 의해서 테스트 실행이 급격하게 느려지게 되는데, 이 글에서는 이러한 문제를 해결하기 위한 방법을 소개한다.

[Jacoco] 멀티 모듈의 Jacoco report 를 하나로 합치기

· 3 min read
Haril Song
Owner, Software Engineer at 42dot

Overview

gradle 7.4 부터 여러 jacoco test report 를 집계하여 통합적으로 볼 수 있는 기능이 추가되었다. 과거에는 여러 모듈에 걸친 테스트의 결과를 하나의 파일로 확인하기가 무척 어려웠지만, 이제는 매우 편리하게 리포트를 하나로 합칠 수 있게 되었다.

[Java] First collection(일급 컬렉션)을 더욱 Collection 답게 - iterable

· 4 min read
Haril Song
Owner, Software Engineer at 42dot

Overview

// Iterable 을 구현하고 있는 java Collection.
public interface Collection<E> extends Iterable<E>

일급 컬렉션은 객체를 다루는데에 있어서 굉장히 유용한 방법 중 하나다. 하지만 일급 컬렉션이라는 이름이 무색하게도 Collectionfield 로 가지고 있을 뿐 실제 Collection 은 아니기 때문에, Collection 이 제공하는 다양한 method 들을 사용할 수는 없다. 이 글에선 Iterable 을 활용해서 일급 컬렉션을 진짜 Collection 처럼 쓸 수 있는 방법을 소개해본다.

간단한 예제를 작성해보자.

getter/setter 에 대한 사실과 오해

· 6 min read
Haril Song
Owner, Software Engineer at 42dot

구글에 getter/setter 에 대해 검색해보면 정말 많은 게시글이 나온다. 대부분 getter/setter 를 사용하는 이유에 대해서 작성되어 있고 그 이유 중 하나로 캡슐화, 정보 은닉 같은 키워드를 중심으로 설명하고 있다.

필드 변수를 private 로 선언하여 외부에서 접근을 막고 getter/setter 만 공개하여 캡슐화한다는 설명이 90%는 되는 것 같다.

하지만 getter/setter 를 쓰면 진짜로 캡슐화가 될까?

결론부터 말하자면 getter/setter 는 캡슐화를 전혀 달성할 수 없다. 캡슐화를 하고 싶다면 getter, setter 는 쓰지 말아야한다는 것이다. 이걸 이해하기 위해서는 먼저 캡슐화에 대해 정확히 이해할 필요가 있다.

[Spring Batch] KafkaItemReader

· 3 min read
Haril Song
Owner, Software Engineer at 42dot
info

저는 Docker 를 사용하여 Kafka 설치 후 이번 글을 작성했지만 해당 내용은 이번 글에서 다루지 않습니다.

KafkaItemReader..?

Spring batch 에서는 Kafka Topic 의 데이터를 처리하는 경우를 위해서 KafkaItemReader 를 제공하고 있습니다.

간단한 배치를 하나 만들어보겠습니다.

Example

먼저 관련 의존성을 추가해줍니다.