| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 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 |
- BDD
- 코딩 컨벤션
- callback
- 모델링
- Long Polling
- 생성자
- undefined
- 코드관리
- node js
- Service Worker
- Polling
- 테스트코드
- Web push
- EventEmitter
- 노드
- emit
- waterfall
- null
- 티스토리챌린지
- TDD
- 오블완
- 통신방식
- DB
- Spring
- jest
- java
- Nodejs
- JavaScript
- Node.js
- kotlin
- Today
- Total
목록전체 글 (103)
Will Of Rough
개요쿠버네티스 위에서는 서버가 죽는 일이 특별한 이벤트가 아니다, 롤링 배포·오토스케일링·노드 교체로 파드는 하루에도 몇 번씩 죽고 다시 태어난다. 그런데 배포할 때마다 모니터링에 502 가 몇 개씩 찍히는걸 보고, 처음엔 새로 뜨는 파드가 준비되기 전에 트래픽을 받아서 그런가? 싶었지만 readiness probe 를 아무리 조여도 안 없어졌고, 파다 보니 문제는 태어나는 쪽이 아니라 죽는 쪽 — 트래픽 차단이 전파되는 속도와 프로세스가 죽는 속도 사이의 레이스 — 라는걸 알게되었다. 가끔씩 그레이스풀 셧다운 글을 보면 server.shutdown=graceful 한 줄 넣고 끝~인 경우가 많아, 그 설정이 JVM 의 시그널 처리나 쿠버네티스의 종료 순서와 어떻게 맞물리는지는 늘 아쉬운 부분이었다. 그..
개요Spring Boot 로 서버를 띄우면 아무 설정을 하지 않아도 HikariCP 커넥션 풀이 기본으로 붙는다. 처음엔 커넥션 풀이라고 해서 미리 만들어둔 커넥션을 재사용하는 정도로만 이해하고 있었고, 사실 풀 사이즈도 부족하면 늘리면 되는거 아닌가? 싶었다, 왜냐하면 커넥션이 많으면 동시에 처리할 수 있는 쿼리도 많아지는건데 트래픽이 늘면 커넥션도 같이 늘리는게 당연한거 아닌가 싶기도 했고 실제로 DB 쪽이 느려지면 제일 먼저 maximumPoolSize 부터 올리고 보는 경우도 많았다. 하지만 HikariCP 공식 문서의 사이징 자료를 파다 보니 — 커넥션은 늘릴수록 느려지고, 풀은 작게 유지한 채 나머지 요청을 풀 앞에 줄 세우는 쪽이 오히려 빠르다 — 는걸 알게되었다. 가끔씩 커넥션 풀 글을 보..
개요테이블을 설계할 때 PK 컬럼은 늘 있었다. 처음엔 Auto Increment 로 하던지 UUID 로 하던지 그냥 팀 컨벤션 따라가면 되는 문제라고 생각했었다, 사실 ID 라는게 유일하기만 하면 끝 아닌가? 싶기도 했고 성능 이야기가 나와도 8바이트냐 16바이트냐 크기 차이 정도로만 이해하고 있었다. 하지만 인덱스와 B+Tree 를 정리하고 나서 다시 보니, ID 는 생성되는 순간 값의 '모양'이 정해지고 — 그 모양이 B+Tree 의 어느 페이지에 꽂힐지, 즉 쓰기 비용을 미리 결정한다 — 는걸 알게되었다. 가끔씩 UUID vs Auto Increment 글을 보면 "분산 환경이면 UUID, 아니면 Auto Increment" 하고 끝~인 경우가 많아, 도대체 왜 무작위가 인덱스에 비싼지, 그리고 ..
개요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 하고 끝~인 경우가 많아, 왜 그렇게 갈리는지 그 밑바..
