Skip to main content

12 posts tagged with "java"

View All Tags

다중 접속 서버로의 여정

· 13 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

· 8 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

· 8 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 main 을 JVM 이 어떻게 메모리에 어떻게 적재하고 실행할 수 있는지 그 동작 원리에 대해 살펴본다.

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

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

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

Overview​

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

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

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

Overview​

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

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

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

Overview​

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

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

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

getter/setter 에 대한 사실과 오해

· 3 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

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

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

KafkaItemReader..?​

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

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

Example​

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