| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 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 |
- 생성자
- 티스토리챌린지
- Spring
- 모델링
- null
- undefined
- Service Worker
- callback
- Web push
- 코드관리
- 테스트코드
- Nodejs
- jest
- 노드
- 오블완
- waterfall
- JavaScript
- DB
- TDD
- Node.js
- EventEmitter
- node js
- Polling
- kotlin
- 코딩 컨벤션
- emit
- 통신방식
- Long Polling
- java
- BDD
- Today
- Total
목록전체 글 (106)
Will Of Rough
개요운영 서버를 컨테이너로 옮긴 다음 날, 주문 시각이 전부 9시간씩 밀려 있었다. 처음엔 DB 가 이상한가? 싶었지만 코드도 DB 도 그대로였고, 바뀐 건 서버가 보는 시계 하나였다는걸 알게되었다 — 시간은 하나인데 그걸 읽는 시계가 셋(프로그램·통역사·서랍) 이라는 얘기였다. 가끔씩 시간대 글을 보면 설정 한 줄 넣고 끝~인 경우가 많아, 왜 밀리는지는 늘 아쉬운 부분이었다. 그렇기에 이번글은 시각과 시계를 구분하는 것부터 시작해서, 시간 값이 프로그램에서 DB 까지 가는 길을 따라가보려고한다.시각과 벽시계 — 순간은 하나, 시계는 도시마다 다르다런던으로 출장 간 동료가 "내일 3시에 통화하자" 고 메시지를 보냈다. 서울의 3시인지 런던의 3시인지 묻지 않으면 둘 중 하나는 빈 전화기 앞에 앉아 있게..
개요서버가 느려졌다는 말을 들으면 보통 로그를 먼저 뒤지고, 그걸로 안 되면 스레드 덤프를 몇 장 뜬다. 사실 프로파일러라는건 로컬에서 IntelliJ 에 붙여서 돌려보는 개발용 도구 정도로만 이해하고 있었다, 운영 서버에 붙이면 느려질게 뻔하고 어차피 장애는 재현이 안 되는데 뭘 재냐 싶기도 했고 스레드 덤프를 시간차로 몇 장 뜨면 어디서 멈춰있는지 대충 보이니까 그걸로 충분하다 싶었다. 하지만 JDK 안에는 이미 상시로 켜 두라고 만든 기록 장치가 들어있고, 그 기록의 절반은 "지금 어느 코드가 돌고 있는지 주기적으로 찍은 사진" 이며 — 그 사진을 어떤 시계로 언제 찍느냐가 답을 바꾼다 — 는걸 알게되었다. 가끔씩 JFR 글을 보면 옵션 나열하고 JMC(JDK Mission Control, JFR ..
개요Spring Boot 4 로 올리고 나서 IDE 에 노란 밑줄이 갑자기 늘었다. 처음에는 Spring 이 자기네 @Nullable 을 JSpecify 라는 걸로 갈아탄 것 정도로만 이해하고, import 만 바꿔주면 끝 아닌가? 싶었지만, Object @Nullable [] 처럼 대괄호 앞에 붙은 어노테이션을 보고 나서야 이게 단순한 라이브러리 교체가 아니라 — null 을 값이 아니라 타입의 일부로 취급하기 시작했다 — 라는걸 알게되었다. 사실 자바를 오래 쓰면서 null 체크는 습관의 문제 정도로 생각했고, 어노테이션은 컴파일러가 봐주지도 않는 문서 대용인데 굳이 붙일 이유가 있나 싶었다, 그런데 Spring 팀이 프레임워크 전체 코드에 이걸 붙이고 빌드에서 검사까지 돌린다는 걸 보니 뭔가 내가 ..
개요쿠버네티스 위에서는 서버가 죽는 일이 특별한 이벤트가 아니다, 롤링 배포·오토스케일링·노드 교체로 파드는 하루에도 몇 번씩 죽고 다시 태어난다. 그런데 배포할 때마다 모니터링에 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 설정값을 나열하고 끝~인 경우가 많아, 그 숫자 하나하나가 어떤 장애 시나리..
