994 posts
로드 밸런서 정리: 부하 분산 알고리즘부터 운영 포인트까지

로드 밸런서 정리: 부하 분산 알고리즘부터 운영 포인트까지

처음 웹 서버를 돌릴 때는 한 대만 잘 띄워 두면 충분합니다. 그런데 사용자가 늘고 트래픽이 점점 무거워지면, 어느 순간 한 대로는 감당이 안 되는 시점이 옵니다. 사양을 키우는 방법(스케일 업)도 있지만, 한 대를 더 띄워서 일을 나누어 시키는 방법(스케일 아웃)이 더 자연스러운 선택일 때가 많은데요. 이 분산을 책임지는 도구가 로드 밸런서입니다. 이름 그대로 트래픽이라는 부하를 여러 서버에 나눠 주는 장치인데, 막상 들여다보면 "어떤 기준으로 나누느냐", "어느 계층에서 동작하느냐", "한 대가 죽으면 어떻게 알아채느냐"처럼 결

HTTPS란 무엇인가: TLS와 인증서로 HTTP를 보호하는 원리

HTTPS란 무엇인가: TLS와 인증서로 HTTP를 보호하는 원리

브라우저 주소창에 작은 자물쇠 아이콘이 켜져 있으면 우리는 별다른 의심 없이 정보를 입력합니다. 비밀번호를 치고, 카드 번호를 넣고, 메시지를 보내는데요. 이 자물쇠 한 칸이 사실은 HTTP 위에 한 겹의 보호막을 덧씌운 결과인 셈입니다. HTTPS는 이름에서도 짐작되듯 HTTP에 보안(Secure)을 보탠 형태입니다. 정확히 말하면 HTTP를 TLS라는 암호 통신 위에서 흘려보내는 구조인데요. 이번 글에서는 평문 HTTP가 왜 위험한지, TLS가 그 위에 무엇을 더하는지, 그리고 우리가 평소에 보는 인증서와 자물쇠가 어떻게 신뢰를

요청과 응답으로 알아보는 HTTP와 버전 이야기

요청과 응답으로 알아보는 HTTP와 버전 이야기

웹 페이지 하나를 여는 일을 한 줄로 요약하면 "브라우저가 서버한테 뭔가 달라고 부탁하고, 서버가 그걸 보내준다"입니다. 이 단순한 부탁을 둘 사이에서 약속된 모양으로 주고받게 만든 것이 HTTP입니다. 이름이 길어 보이지만 풀어보면 HyperText Transfer Protocol, "문서를 주고받기 위한 약속" 정도로 옮길 수 있죠. 그런데 한 가지 호기심이 생깁니다. 이렇게 단순한 약속이 오랫동안 살아남으면서, 뒷자리 숫자만 1.0에서 1.1, 2, 3까지 바뀌어 왔다는 점이죠. 같은 이름을 달고도 토대를 TCP에서 UDP로

스프링 부트 구동 시점에 특정 코드 실행 시키기 (CommandLineRunner & ApplicationRunner)

스프링 부트 구동 시점에 특정 코드 실행 시키기 (CommandLineRunner & ApplicationRunner)

스프링 부트 애플리케이션 구동 시점에 특정 코드 실행 시키기기 위해서 2가지 인터페이스를 제공하고 있습니다. CommandLineRunner CommandLineRunner 인터페이스는 구동 시점에 실행되는 코드가 자바 문자열 아규먼트 배열에 접근해야 할 필요가 있는 경우에 사용합니다. 다음과 같이 CommandLineRunner 인터페이스를 구현한 클래스에 @Component 어노테이션을 선언해두면 컴포넌트 스캔이되고 구동 시점에 run 메소드의 코드가 실행됩니다. 테스트 jar 파일로 패키징된 애플리케이션을 실행시킬 때 abc와

스프링 부트 내장 서버 설정 (포트, 컨텍스트 패스)

스프링 부트 내장 서버 설정 (포트, 컨텍스트 패스)

본 포스팅에서는 스프링 부트의 내장 서버를 설정하는 방법에 대해서 알아보겠습니다. 애플리케이션 설정 파일 스프링 부트 프로젝트의 src/main/resources 디렉터리를 보시면 application.properties나 applicaiton.yml 파일을 찾으실 수 있으실 겁니다. (없으신 경우 새로운 applicaiton.yml 파일을 만드시면 됩니다.) 포트와 컨텍스트 패스 변경 스프링 부트의 내장 서버는 디플트로 포트는 8080을 사용하고 컨텍스트 패스는 /를 사용하고 있습니다. 포트를 8081로 바꾸고 컨텍스트 패스를 /

스프링 부트 내장 서버 바꾸기

스프링 부트 내장 서버 바꾸기

본 포스팅에서는 스프링 부트의 내장 서버를 바꾸는 방법에 대해서 알아보도록 하겠습니다. 메이븐 설정 파일(pom.xml)만 조금씩 수정해주면 다양한 내장 서버를 사용해볼 수 있습니다. Tomcat 스프링 부트는 디플트 내장 서버로 Tomcat을 사용하고 있습니다. 따라서 특별한 설정없이 Web Starter 의존성만 추가해주면 됩니다. 바로 스프링 부트 애플리케이션을 실행하면 Tocmat 내장 서버가 올라갑니다. Jetty 스프링 부트의 내장 서버로 Tomcat 대신에 Jetty를 사용해보겠습니디. 먼저 Web Starter에 기본

도구 없이 스프링 부트 프로젝트 만들기

도구 없이 스프링 부트 프로젝트 만들기

스프링 부트 프로젝트를 만드는데는 여러 가지 자동화된 방법이 있습니다. Eclipse나 IntelliJ와 같은 코드 에디터에서 제공하는 프로젝트 생성 마법사를 이용할 수 있고, SPRING INITIALIZR 웹사이트에서 생성해준 프로젝트의 압축 파일을 다운로드 받을 수도 있으며, Spring CLI 도구를 이용하여 터미널에서 커맨드 한 줄을 날릴 수도 있습니다. 하지만 스프링 부트를 본격적으로 시작할 분이 아니라면 이런 도구를 설치하는 게 부담스럽거나 번거롭게 느껴질 수 있습니다. 본 포스팅에서는 이러한 도구의 도움없이 아무 것도

SLI, SLO, SLA 정리: 측정하고, 목표를 세우고, 약속하기

SLI, SLO, SLA 정리: 측정하고, 목표를 세우고, 약속하기

온콜 정리의 끝에서 남겨 둔 질문이 있었죠. 오류율 알림의 임계값을 5%로 할지 1%로 할지를 놓고 팀 안에서 의견이 갈리는 상황이요. 개발 쪽은 "1%는 너무 빡빡해서 배포할 때마다 울린다"고 하고, 운영 쪽은 "5%면 사용자 스무 명 중 한 명이 실패하는 건데 그걸 그냥 둘 거냐"고 합니다. 둘 다 틀린 말은 아닌데 대화가 끝나지 않아요. 🤔 이 논쟁이 안 끝나는 이유는 "우리 서비스가 얼마나 실패해도 괜찮은가"를 먼저 정하지 않았기 때문입니다. 그 기준을 세우는 도구가 SLI, SLO, SLA인데요. 비슷하게 생긴 세 약어가

localhost와 127.0.0.1: 같은 듯 다른 둘의 정체

localhost와 127.0.0.1: 같은 듯 다른 둘의 정체

개발 서버를 띄우면 터미널에 항상 비슷한 메시지가 뜨죠. 별생각 없이 클릭해서 들어가지만, 막상 localhost가 정확히 무엇인지, 127.0.0.1과 어떻게 다른지, 그리고 0.0.0.0은 또 뭔지 물으면 순간 헷갈리는 분이 의외로 많습니다. 이번 포스팅에서는 매일 쓰는 localhost를 둘러싼 이름, 주소, 바인딩의 관계를 정리하고, 자주 만나는 함정 몇 가지도 함께 짚어보겠습니다. localhost는 이름, 127.0.0.1은 주소 먼저 가장 기본적인 구분부터 짚고 가요. localhost는 이름이고 127.0.0.1은 주

TCP와 UDP, 어떤 차이가 있을까?

TCP와 UDP, 어떤 차이가 있을까?

웹 서비스를 만들거나 게임 서버를 짜다 보면 "통신은 그냥 되는 거지" 정도로 넘어가게 되는 부분이 있습니다. 정작 소켓을 직접 열어 데이터를 주고받아야 할 때면, 만들 수 있는 소켓이 한 종류가 아니라는 사실과 마주치게 됩니다. 하나는 SOCK_STREAM, 다른 하나는 SOCK_DGRAM이라고 부르는데, 이 두 가지가 각각 TCP와 UDP에 해당합니다. 왜 굳이 두 종류로 나뉘어 있을까요? 🤔 같은 인터넷 위에서 데이터를 주고받는 일인데도, TCP와 UDP는 만들어진 목적이 꽤 다릅니다. 이번 글에서는 두 프로토콜이 어떤 점에

사설 IP와 RFC 1918: 192.168과 10.0이 특별한 이유

사설 IP와 RFC 1918: 192.168과 10.0이 특별한 이유

집에서 공유기 관리자 페이지에 들어가려고 IP를 쳐본 적 있으시죠? 대부분 192.168.0.1이나 192.168.1.1 같은 주소일 겁니다. 회사 사내망에 들어가 보면 10.0.0.5 같은 주소를 받고요. 그런데 인터넷의 평범한 사이트들 IP는 또 52.x.x.x나 203.0.113.x처럼 전혀 다른 모양이에요. 왜 어떤 IP는 집 안에서만 보이고, 어떤 IP는 전 세계에서 보일까요? 이 구분을 만들어 준 게 바로 RFC 1918이라는 표준 문서입니다. 이번 포스팅에서는 사설 IP 주소가 왜 필요했는지, 어떤 대역이 정해져 있는지

[자바] 알아두면 유용한 Lombok 어노테이션

[자바] 알아두면 유용한 Lombok 어노테이션

이번 포스팅에서는 많이 알려지지는 않았지만 알아두면 유용한 Lombok 어노테이션에 대해서 알아보겠습니다. 빌더 자동 생성 다수의 필드를 가지는 복잡한 클래스의 경우, 생성자 대신에 빌더를 사용하는 경우가 많은데요. 빌더 패턴을 직접 작성해보면 코딩량이 의외로 상당함을 깨닫게 됩니다. 이 때, @Builder 어노테이션을 사용하면 자동으로 해당 클래스에 빌더를 추가해주기 때문에 매우 편리합니다. 컬렉션으로 된 필드에는 @Singular 어노테이션을 선언해주면 모든 원소를 한 번에 넘기지 않고 원소를 하나씩 추가할 수 있습니다. 로거

[자바] 자주 사용되는 Lombok 어노테이션

[자바] 자주 사용되는 Lombok 어노테이션

Lombok 라이브러리에서 제공하는 어노테이션 중에서 자주 사용되는 어노테이션 위주로 살펴보도록 하겠습니다. 접근자/설정자 자동 생성 제일 먼저 살펴볼 어노테이션은 @Getter와 @Setter 입니다. 아마 Lombok에서 가장 많이 사용되는 어노테이션일 텐데요. 예를 들어, xxx라는 필드에 선언하면 자동으로 getXxx()(boolean 타입인 경우, isXxx())와 setXxx() 메소드를 생성해줍니다. 위와 같이 특정 필드에 어노테이션을 붙여주면, 다음과 같이 자동으로 생성된 접근자와 설정자 메소드를 사용할 수 있어서 매

UDP 뜯어보기: 데이터그램 경계부터 MTU까지

UDP 뜯어보기: 데이터그램 경계부터 MTU까지

UDP를 설명하는 문장은 대개 비슷하게 시작합니다. "TCP에서 신뢰성을 뺀 프로토콜"이라는 식이죠. 틀린 말은 아닙니다. 그런데 이 설명만 들고 있으면 막상 UDP로 뭔가를 만들어야 할 때 손이 잘 안 떨어집니다. 무엇이 빠졌는지는 알겠는데, 그래서 무엇을 직접 챙겨야 하는지는 여전히 흐릿하거든요. 🤔 TCP와 UDP의 차이는 예전에 나란히 놓고 비교한 적이 있는데요. 이번에는 비교를 잠시 접어두고 UDP 하나만 들여다보려고 합니다. 헤더 8바이트 안에 무엇이 들어 있는지, 왜 데이터그램에는 경계가 있는지, 한 번에 얼마나 보낼

[자바] 리스트를 순회하는 방법

[자바] 리스트를 순회하는 방법

자바에서 리스트를 순회하는 4가지 방법에 대해서 알아봅시다. 다음와 같이 5가지 과일 문자열을 담고 있는 리스트를 순회하면서 원소를 하나씩 출력해보겠습니다. 전통적인 For 루프 그냥 평범한 For 루프문을 사용하여 마치 배열을 순회하는 것과 동일한 방식으로 순회할 수 있습니다. 하지만 이 방법은 E get(int index) 메소드를 가지는 List 타입의 객체 대상으로만 사용할 수 있습니다. 상위 타입인 Collection이나 Set과 같은 이종 타입의 객체 대상으로는 사용이 불가한 방법입니다. Iterator 위의 대안 중 하

TCP는 어떻게 신뢰성을 지킬까: 핸드셰이크부터 혼잡 제어까지

TCP는 어떻게 신뢰성을 지킬까: 핸드셰이크부터 혼잡 제어까지

TCP를 한 단어로 요약하라면 대개 "신뢰성"이 나옵니다. 보낸 데이터가 순서대로, 빠짐없이 도착한다는 뜻이죠. 그런데 인터넷의 아래층인 IP는 아무것도 보장하지 않습니다. 패킷을 버려도 되고, 순서를 바꿔도 되고, 같은 것을 두 번 보내도 규칙 위반이 아닙니다. 그 위에서 TCP는 어떻게 "빠짐없이 순서대로"를 만들어낼까요? 🤔 TCP와 UDP의 차이에서 두 프로토콜의 성격을 견줘봤고, UDP는 따로 파고들었으니 이번에는 TCP 차례입니다. 신뢰성이라는 결과가 아니라 그것을 만드는 장치를 하나씩 뜯어보겠습니다. 스트림에는 경계가

ConcurrentModificationException 없이 자바 컬렉션에서 원소 삭제하기

ConcurrentModificationException 없이 자바 컬렉션에서 원소 삭제하기

리스트를 순회하면서 특정 원소를 삭제하고 싶을 때가 있습니다. 예를 들어, 다음과 같이 알파벳과 숫자가 섞여있는 리스트가 있다고 가정해봅시다. 저는 이 리스트에서 숫자인 원소들은 모두 삭제하고 싶습니다. ConcurrentModificationException 발생 가장 먼저 떠오르는 방법은 boolean remove(Object o) 메소드를 사용하는 것입니다. for 루프를 돌면서 해당 원소가 숫자인지 체크 후에 숫자이면 remove 메소드를 호출합니다. 하지만 위 코드는 다음과 같은 ConcurrentModificationEx

[자바] NavigableSet 사용법

[자바] NavigableSet 사용법

자바6에서 추가된 NavigableSet에 대해서 알아보도록 하겠습니다. NavigableSet은 SortedSet을 확장한 인터페이스입니다. 따라서 기존 SortedSet 대비 추가된 기능 위주로 살펴보는 게 좋을 것 같습니다. 객체 생성 자바에서 제공하는 NavigableSet 인터페이스의 대표적인 구현 클래스는 TreeSet 입니다. 따라서 TreeSet 객체를 생성 후에, NavigableSet 타입 변수에 할당하기면 하면 됩니다. 역순 접근: descendingIterator, descendingSet SortedSet을

[자바] SortedSet 사용법

[자바] SortedSet 사용법

SortedSet 사용법에 대해서 알아보록 하겠습니다. SortedSet은 원소들이 정렬되어 있는 Set입니다. 따라서 SortedSet 하여금 객체 간 대소 비교가 가능한 상황을 만들어줘야 합니다. 여기서 "객체 간 대소 비교가 가능한 상황"이란 다음 2가지로 생각해볼 수 있습니다. Comparable 인터페이스를 구현하고 있는 클래스의 객체를 원소로 사용 Comparator 인터페이스를 구현한 대소 판단을 위한 로직을 SortedSet 객체 생성 시에 넘김 본 포스팅에서는 Comparable 인터페이스를 구현하고 있는 Strin

자바스크립트의 btoa와 atob로 Base64 다루기

자바스크립트의 btoa와 atob로 Base64 다루기

자바스크립트로 Base64 인코딩을 다뤄야 할 일이 생기면 가장 먼저 마주치게 되는 함수가 btoa()와 atob()인데요. 이름이 워낙 짧고 비대칭적이라 어느 쪽이 인코딩이고 어느 쪽이 디코딩인지 헷갈리기 십상입니다. 이번 포스팅에서는 두 함수가 무엇이고 어디에 자주 쓰이는지부터 짚어보겠습니다. 그리고 한글이 들어갈 때의 함정과 현대적인 대안도 함께 살펴보겠습니다. btoa와 atob는 무엇일까요? btoa()와 atob()는 자바스크립트에 내장된 Base64 인코딩과 디코딩 함수입니다. 이름의 의미를 풀어서 외워두면 헷갈리지 않

Discord