| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | ||
| 6 | 7 | 8 | 9 | 10 | 11 | 12 |
| 13 | 14 | 15 | 16 | 17 | 18 | 19 |
| 20 | 21 | 22 | 23 | 24 | 25 | 26 |
| 27 | 28 | 29 | 30 |
- java
- Nodejs
- waterfall
- Spring
- Service Worker
- 테스트코드
- Node.js
- Long Polling
- emit
- 코딩 컨벤션
- TDD
- 노드
- EventEmitter
- callback
- Polling
- undefined
- null
- DB
- 코드관리
- 생성자
- 통신방식
- jest
- node js
- JavaScript
- Web push
- 티스토리챌린지
- BDD
- kotlin
- 오블완
- 모델링
- Today
- Total
목록전체 글 (100)
Will Of Rough
개요Java 에서 우리가 만드는 모든 것은 결국 힙 위의 객체다. 처음에 new Integer(1) 은 int 가 4바이트니까 객체도 4바이트 언저리겠지 싶었지만, JOL 로 실제 크기를 찍어보니 16바이트가 나왔다. 사실 몇 바이트 차이가 뭐 대수인가 싶었다, 어차피 GC 가 알아서 치워주는데 헤더가 몇 바이트인지까지 개발자가 알아야하나 싶기도 했고 힙이 모자라면 Xmx 를 올리면 되는거 아닌가 싶었다. 하지만 힙을 채우고 있는 객체 대부분이 이런 손톱만한 객체고, 헤더는 필드 크기가 아니라 — 객체 개수에 비례해서 걷히는 고정비 — 라는걸 알게되었다. 가끔씩 Java 25 의 Compact Object Headers 를 소개하는 글을 보면 "헤더가 12바이트에서 8바이트로 줄어든다" 하고 끝~인 경우..
개요MSA 로 서비스를 쪼개고 나면 내 코드의 절반은 남의 서버를 호출하는 코드가 된다. 사실 원격 호출 실패는 try-catch 로 잡아서 몇 번 다시 돌리면 되는거 아닌가? 싶었고, 서킷 브레이커라는 단어도 Netflix Hystrix 이야기에 늘 따라붙길래 트래픽 큰 회사들이나 쓰는 유행어 정도로만 이해하고 있었다. 그런데 외부 API 하나가 죽은 것도 아니고 그저 느려졌을 뿐인데 멀쩡하던 서버 전체가 응답 불능으로 끌려 들어가는 과정을 따라가보니, 이 도구들은 장애를 없애는 장치가 아니라 장애가 번지는 길목을 하나씩 끊는 장치 라는걸 알게되었다. 가끔씩 Resilience4j 정리 글을 보면 어노테이션 붙이는 법과 yml 설정값을 나열하고 끝~인 경우가 많아, 그 숫자 하나하나가 어떤 장애 시나리..
개요WHERE 절에 자주 걸리는 컬럼에는 인덱스를 걸어라, 백엔드 개발자라면 신입 때부터 귀에 못이 박히게 듣는 문장이다. 사실 나도 오랫동안 인덱스를 "걸면 빨라지는 스위치" 정도로 이해하고, CREATE INDEX 한 줄이면 튜닝이 끝났다고 생각했었다. 그런데 분명 인덱스를 걸어둔 컬럼인데 실행 계획을 떠보면 풀 스캔이 찍혀 있질 않나, 조회 좀 빠르게 해보겠다고 인덱스를 추가했더니 이번엔 배치 INSERT 가 눈에 띄게 느려지질 않나, 도대체 무엇을 기준으로 빨라지고 무엇을 기준으로 느려지는건지 감이 안 잡히는 순간이 오면서 인덱스는 결국 — 디스크에서 16KB 페이지를 몇 장 읽어오느냐의 문제이고, 읽기가 아낀 페이지는 쓰기가 대신 갚는 구조 — 라는걸 알게되었다. 가끔씩 인덱스 관련 글을 보면 ..
개요서비스에서 오늘 접속한 유니크 사용자 수(DAU) 를 세는 건 너무 흔한 요구사항이라, 지금까지는 별 고민 없이 Set 에 밀어넣고 크기를 세면 끝이라고 생각했다.사실 중복을 제거하고 센다는 게 그것 말고 다른 방법이 있긴 한가? 싶었고, Redis 에 HyperLogLog 라는게 있다는 건 알고 있었지만 이름부터 어려워 보이는데다 정확하지도 않은 카운트를 굳이 써야하나 싶기도 했고.그런데 사용자가 수억 규모가 되면 "세기 위해 전부 기억하는" Set 방식은 카운트 하나에 기가바이트를 지불하게 되고, HyperLogLog 는 — 원소를 기억하는 대신 가장 희귀한 기록 하나로 전체 규모를 역산한다 — 는 발상으로 이걸 12KB 에 해결한다는걸 알게되었다.가끔씩 HyperLogLog 를 설명하는 글을 보..
개요실시간 알림이나 채팅 기능을 만든다고 하면 다들 반사적으로 WebSocket 부터 꺼낸다.사실 나도 실시간이면 무조건 WebSocket 아닌가? 싶었고, SSE 는 이름만 들어봤지 폴링보다 조금 나은 반쪽짜리 기술 정도로 이해하고 있었다, 어차피 양방향이 되는 WebSocket 이 있는데 굳이 단방향밖에 안 되는 기술을 배워야하나 싶기도 했고.그런데 막상 서버에서 클라이언트로 내려주기만 하면 되는 기능을 구현하려고 찾아보니, 실시간이라는 요구사항은 하나가 아니라 — 데이터가 흐르는 방향이 프로토콜을 결정한다 — 는걸 알게되었다.가끔씩 SSE 와 WebSocket 을 비교하는 글을 보면 표 하나 그려두고 채팅이면 WebSocket, 알림이면 SSE 하고 끝~인 경우가 많아, 왜 그렇게 갈리는지 그 밑바..
개요선착순 쿠폰이나 타임세일처럼 순간적으로 트래픽이 몰리는 기능에서, 재고 차감은 UPDATE 문 한 줄이면 되는 단순한 작업처럼 보인다.처음에는 @Transactional 안에서 재고를 조회하고 차감하면 끝 아닌가? 싶었지만, 수만 명이 같은 상품 하나를 동시에 노리는 순간 모든 트랜잭션이 그 상품 row 하나의 락 앞에 줄을 서고, 락 대기가 길어지면 커넥션 풀이 마르고, 커넥션 풀이 마르면 재고와 상관없는 다른 API 까지 같이 죽는걸 보고 나서야 이게 쿼리의 문제가 아니라 구조의 문제라는 생각이 들었다.파보니 답은 차감을 DB 밖으로 꺼내는 것이었는데 — 차감은 Redis 가 메모리에서 원자적으로 받아내고, DB 반영은 뒤로 미루고, 그 사이에 벌어진 어긋남은 정산으로 갚는 구조 — 라는걸 알게되..
개요2편에서 메시지가 지나가는 길과 Ack, prefetch 까지 구조를 훑었다.처음에는 구조를 알았으니 쓰는 데는 문제 없다고 생각했었다, 그런데 브로커에 맡긴 메시지가 정말 한 번은 도착하냐고 물으면 대답이 막혔고, 실패한 메시지는 어디서 몇 번을 재시도해야 하는건가? 싶기도 했고 브로커 노드가 통째로 죽으면 큐에 있던 메시지는 어떻게 되는건가 싶었다.파보니 이 질문들의 답은 하나로 이어져 있었는데 — 유실을 막는 장치들은 유실을 중복으로 바꿀 뿐이고, 그 중복까지 삼키는 것이 설계의 완성 — 이라는걸 알게되었다.가끔씩 전달 보장 글을 보면 confirm 켜라, durable 켜라 나열하고 끝~인 경우가 많아, 그 장치들이 정확히 어느 시점에 무엇까지 보장하는지와 켜고 난 뒤에 남는 중복·순서·재시도..
개요1편에서 RabbitMQ 는 소비하면 지우는, 브로커가 메시지별 장부를 적는 쪽의 메시지 큐라고 정리했다.처음에는 Exchange 니 Binding 이니 하는 용어가 그냥 큐에 붙는 옵션 정도인 줄 알았고, 코드로도 큐 이름 하나 적어서 보내면 되는거 아닌가? 싶었는데 왜 예제마다 굳이 Exchange 를 선언하고 바인딩을 거는건가 싶기도 했고 Connection 을 놔두고 Channel 은 또 왜 따로 있는건가 싶었다.파보니 이 등장인물들은 전부 — Producer 와 Consumer 가 서로를 몰라도 되게 만드는 간접층이고, 층마다 자기만의 함정을 하나씩 갖고 있는 것 — 이라는걸 알게되었다.가끔씩 RabbitMQ 구조 글을 보면 Exchange 타입 네 가지 그림만 나열하고 끝~인 경우가 많아,..