개발 팁
프로젝트와 상관없이 다시 쓸 수 있는 요령을 문제·원인·해법·코드 예시로 짧게 적습니다.
- 애플리케이션 keepalive는 클라이언트 타임아웃보다 짧게 보낸다 →클라이언트 라이브러리가 「아무것도 못 받으면 재접속」하는 시간을 확인하고, 그보다 자주 상태를 바꾸지 않는 메시지를 보낸다.
- Django async(웹소켓) 서버 성능 점검 목록 →DB 연결 수명, thread_sensitive, 전달 경로에서 저장 떼기, 채널 용량, 코어 수만큼 프로세스. 부하 때 지연이 튀면 이 다섯 곳부터 본다.
- CRDT(Yjs) 문서는 평평한 키로, 큰 숫자 열은 바이너리 하나로 둔다 →동시에 생길 수 있는 구조는 합쳐지는 단위로 나누고, 통째로 쓰고 잘 안 바뀌는 데이터는 압축해 한 값으로 둔다.
- channels_redis에서 직접 만드는 채널도 new_channel()로 만든다 →RedisChannelLayer는 프로세스당 받기 잠금이 하나라, 접두어가 다른 채널이 잠금을 쥐면 다른 채널의 메시지가 멈춘다.
- 같은 상태를 보는 연결은 한 프로세스로 모으고, 휘발성 이벤트는 묶어 보낸다 →스티키 라우팅으로 같은 문서의 연결을 한 프로세스에 모으고, 프로세스 안에서는 메모리로 나눠 주고, 커서처럼 마지막 값만 중요한 이벤트는 모아 보낸다.
- 연결 정리는 finally에서 「어떻게 끝나든 정확히 한 번」 →프레임워크의 disconnect 콜백은 예외로 끝나면 불리지 않을 수 있다. 진입점을 try/finally로 감싸고 두 번 정리하지 않게 표시를 둔다.
- E2E는 폴링·고정 대기 대신 이벤트로만 기다린다 →expect.poll·waitForTimeout·toPass 대신 MutationObserver와 스트림 메시지 리스너로 화면이 바뀔 때마다 한 번씩만 다시 본다. 전체 E2E 6분(실패 10개)이 CI 45초(110개 통과)가 됐다.
- SSE 동시 접속 한도는 CPU보다 파일 서술자 한도에서 먼저 막힌다 →스트림 하나가 소켓 하나와 Redis 구독 하나, 서술자 2개를 쓴다. 컨테이너 기본 soft 한도 1024면 약 500명에서 Too many open files가 난다.
- Django ASGI에서 DB 연결은 풀로 쓰고, 오래 열린 요청은 바로 돌려준다 →ASGI에서는 CONN_MAX_AGE를 올려도 연결이 재사용되지 않는다. psycopg 풀을 켜고, SSE·롱폴링은 DB를 쓴 직후 연결을 풀에 돌려준다.