2026-11-10 (화)¶
오늘 요약 - 대시보드 화면·지도·동기화를 다듬으면서 아키텍처 설명을 준비했다. 새로 익힌 것은 BFF, ORM, OLTP·OLAP, H3 부모 셀(h3ToParent), 작업 큐 + 워커. - 가장 오래 헷갈린 것은 "Node가 단일 스레드라 느린가, FastAPI로 바꾸면 해결되나"(3번). 기다리는 일(I/O)과 계산하는 일(CPU)을 섞어 보고 있었다.
🗂️ 오늘의 세션 (2개)¶
| 시간 | 프로젝트 | 무엇을 했나 |
|---|---|---|
| 08:51~13:48 | disaster-dashboard | 어제 작업 이어서 마무리 |
| 09:24~17:39 | disaster-dashboard | 대시보드 동작 파악과 질문 |
🛠️ 오늘 한 작업¶
1. 커밋 정리와 로그인 필수화 (disaster-dashboard · 08:51~09:07)¶
- 배경: 하루 지나서 어디까지 했는지부터 확인했다. 커밋 안 된 작업이 쌓여 있었다.
- 진행:
- 그동안 한 작업을 작업 단위로 커밋 6개로 나눴다. 커밋마다 빌드되는 것을 확인했고, 푸시는 하지 않았다(
feat/auth-poc). - 로컬 로그인 방법을 확인했다. 사내 SSO는
OIDC_*값이 비어 있어 아직 못 쓰고, 이메일·비밀번호로 로그인한다. - "로그인 없이 둘러보기"를 없앴다. 이제 로그인해야만 대시보드를 쓸 수 있고, 로그인하면 원래 가려던 화면으로 돌아간다.
- 결과: 개발 서버에서 확인 완료. 타입 검사와 lint 통과.
2. 디자인 시스템 시안과 적용 (disaster-dashboard · 09:19~09:52)¶
- 배경: 범용적인 대시보드 디자인을 적용하고 싶었다. 다른 레포에 디토닉 디자인 문서가 있던 게 기억났다.
- 진행:
dhub2-portal의DESIGN.md를 찾아서, 이 디자인 시스템으로 시안 5장을 만들었다.- 로그인 화면은 로그인 전 정보를 빼고, 이름을 바꾸고, 재난 관련 인터랙션을 넣었다. 그런데 너무 게임 같고 H3에 쏠려서 시안 B·C·D를 더 받았다.
- "조회·다운로드가 중심이고 지도는 부가 기능"으로 방향을 바로잡았다.
- 과제 문서를 보니 서울 한정이 아니라 전국 확산이 목표이고 서울은 실증 지역이었다. 그래서 이름을 "재난안전 데이터 허브"로 바꿨다.
- E 시안으로 정하고, 나머지 페이지 적용과 다크 모드를 백그라운드 작업으로 맡겼다.
- 결과: 시안 적용과 다크 모드는 백그라운드에서 끝났다(10:10).
3. 대시보드 동작 파악 (disaster-dashboard · 09:24~10:00)¶
- 배경: 대시보드가 어떻게 동작하는지 이해하고 질문하려고, 먼저 코드 전체를 읽혔다.
- 진행:
- PG 메타데이터로 ClickHouse 쿼리를 완성하는 구조인지 확인했다. 맞다. PG는 "어느 표에 어떤 조건을 붙일지"만 정한다.
- 메타데이터만으로 어떻게 조회가 되는지 이해가 안 돼서 다시 물었다.
- hub-dev에 새 데이터가 생기면 자동 동기화가 되는지 물었다. 자동이 아니고, 배포 설정도 아직 없다.
- 전체 아키텍처를 받고, Drizzle과 ORM의 뜻을 물었다.
- 결과: 구조를 큰 그림부터 이해했다. 개념 질문으로 이어졌다(→ 개념 3, 4).
4. hub-dev 데이터 전체 연동 (disaster-dashboard · 09:54~10:12)¶
- 배경: hub-dev 데이터 일부만 연동돼 있어서, 가능한 데이터를 전부 붙이고 싶었다.
- 진행:
- 두 번째 백그라운드 작업자에게 맡겼다. 원천 83개를 조사해서 바로 정규화되는 13개를 추가했다.
- 데이터셋이 7개에서 20개로 늘었다.
- 메타데이터 변경 제안을 승인하면 hub-dev에도 반영되는지, 동기화가 어떻게 되는지 물었다.
- 새
norm_*데이터셋이 생겨도 자동 반영이 아니라 사람이 두 단계를 해야 한다는 걸 확인했다. - 결과: 20개 연동 완료. 커밋은 나중에 했다.
5. 화면 배치와 기능 다듬기 (disaster-dashboard · 10:14~11:20)¶
- 배경: 디자인을 바꾼 뒤 마이페이지·관리자 페이지로 가는 길이 안 보였다. 그 밖에 쓰면서 불편한 점이 계속 나왔다.
- 진행:
- 메뉴 이름을 고쳐 마이페이지·관리자 페이지 길을 살렸다. 마이페이지, 내 수정 제안, 문의를 각각 따로 된 화면으로 나눴다.
- 데이터셋 목록은 10개씩 페이지네이션, 미리보기는 20·50·100행 선택(기본 50)으로 바꿨다. "2022-08 예시" 버튼은 지웠다.
- 상단 카드 4개와 아래 조건·결과 패널의 끝선을 맞췄다. 페이지네이션 버튼은 화살표만 남겼다.
- 관리자 문의를 별도 페이지로 뺐다. 상세 화면에도 기간·지역 필터와 그 조건 그대로 CSV 받기를 넣었다. 필터는 라벨 왼쪽·입력 오른쪽 양식으로 두 번 고쳤다.
- 마이페이지: 최근 본 데이터는 10개까지 저장한다. "최근 받은 데이터"를 뺐다가, 즐겨찾기·최근 본 데이터 아래 전체 폭 패널로 다시 넣었다. DB 표는 바꾸지 않았다(
user_activity하나를action열로 구분). - 관리자 화면: 데이터셋 동기화를 맨 위로 올리고 구분선을 넣었다. 처리된 제안과 변경 이력은 계속 쌓이는 기록이라 페이지네이션과 "자세히 보기"를 넣었다.
- 결과: 테스트 73개 통과, 타입 검사·lint 통과, 캡처로 확인했다.
6. 시니어 보고 연습과 FusionDB 검토 (disaster-dashboard · 10:22~11:05)¶
- 배경: Claude를 신입, 나를 시니어로 두고 아키텍처 보고를 받아 봤다. "FusionDB를 쓰라고 했는데 왜 PG를 썼나"라는 질문이 나왔다.
- 진행:
- 그 지시를 받은 기록도, PG를 고른 이유를 적은 문서도 찾지 못했다.
- FusionDB가 PG를 대신할 수 있는지 검토했다. 그런데 결론의 "조회 경로를 FusionDB로"를 sqlway를 빼자는 뜻으로 오해했다.
- 실제 뜻은 sqlway 뒤의 실행 엔진(ClickHouse)을 FusionDB로 바꿀 수 있는가였다. 대시보드는 이미 sqlway를 거치고 있다는 점도 바로잡았다.
- PG를 대체하기 어려운 이유를 OLTP·OLAP으로 정리했다(→ 개념 5).
- 결과: PG는 FusionDB로 대체하기 어렵다. ClickHouse 대체 검토도 이어서 받았다.
7. 동기화를 정규화 태그 기반으로 바꾸기 (disaster-dashboard · 11:10~13:02)¶
- 배경: 동기화 버튼이 무엇을 기준으로 20개만 가져오는지 궁금했다. 새 데이터셋마다 코드(
sources.ts)를 고쳐야 하는 게 불편했다. - 진행:
- 지금 기준은 "정규화를 거친 데이터셋"을 코드에 적어 둔 목록이었다.
- 자동으로 고르는 기준은
재난:태그가 아니라정규화태그가 맞다고 정했다. - hub-dev에서 정규화 결과에만
정규화태그를 달고, 다른 데이터셋에 붙은 건 지웠다. - 코드 노드가 출력에 태그를 자동으로 붙이는 방법은 지금 hub-dev 기능으로는 깔끔하게 없다.
- 동기화가 태그로 찾도록 바꿨다. 목록을 받아서 우리 서버에서 거르는 방식이다.
- 결과: 실제로 20개를 찾았고, 화면 값도 바꾸기 전과 같았다.
8. 지도 격자와 구 단위 지도 (disaster-dashboard · 11:27~16:57, 두 세션)¶
- 배경: 지도 격자가 잘 안 보였고, 칸이 흩어져 보였다. 구 단위 데이터셋은 지도가 아예 안 그려졌다.
- 진행:
- 격자를 또렷하게 하고, 다크 모드에서 칸을 눌러도 안 나오던 문제를 고쳤다. 칸을 누르면 그 칸의 실제 행이 보이게 했다.
- 칸이 흩어지는 이유는 "행이 있는 칸만 칠하고, 한 행은 점 하나라 칸 하나에만 찍히기 때문"이었다.
- r9로 정규화했어도
h3ToParent로 r7로 묶어 그릴 수 있다는 걸 확인하고 적용했다(테스트 104개 통과). - 20개 중 10개는 위치가 구 단위라
h3_r9가 비어 있었다. 이런 데이터셋은 서울 25개 구 지도로 그리게 했다. - 구 경계가 육각형 톱니인 이유가 hub-dev의
ref_region_cell기준표(H3 셀) 때문이라는 걸 알았다. 그래서 셀을 그대로 그리고 r7로 맞췄다. - H3가 겹치지 않는지, 셀 번호가 전 세계 공통인지 물었다(→ 개념 2).
- 히트맵 그라데이션을 바꿔 봤지만 이전이 나아서 되돌렸다.
- 결과: 지도는 r7 기준으로 맞췄다. 구 단위 지도는 브라우저 확인이 아직 남아 있다.
9. 커밋 정리와 동기화 재시험 계획 (disaster-dashboard · 13:05~13:13)¶
- 배경: 오전 작업이 커밋 안 된 채로 쌓였다.
- 진행:
- 변경 79개 파일을 커밋 4개로 나눠 쌓았다. 푸시는 하지 않았다.
- PG를 지우고 동기화를 다시 돌려 시험하려고 했다. 동기화로 다시 채워지는 표와 사람이 쓴 기록이라 다시 안 채워지는 표가 섞여 있다는 걸 확인했다.
- 결과: 커밋 완료. 재시험은 지울 범위를 나눠서 할 일로 남았다.
10. 아키텍처 설명 준비와 백엔드 기초 (disaster-dashboard · 13:15~13:34)¶
- 배경: 아키텍처를 설명해야 해서 "기능 조사 → ERD → 로컬 PG → Next.js → FusionDB 판단" 흐름으로 초안을 썼다.
- 진행:
- 뼈대는 좋다는 평을 받았다. 다만 "sqlway에 쿼리를 날린다"는 표현은 틀렸다. 실제로는 dhub2-manager를 거친다.
- 설명에 나온 BFF가 무엇인지, Next.js가 BFF인지 물었다(→ 개념 6).
- Next.js로 프론트·백을 둘 다 하는 이유와, 복잡해져도 유지할 수 있는지 물었다(→ 개념 7).
- 큰 CSV에 작업 큐가 필요한 게 단일 스레드 때문인지, CronJob을 더 띄워야 하는지 물었다(→ 개념 1, 8).
- 데이터가 늘면 생길 문제와 FastAPI로 바꾸면 해결되는지 물었다(→ 개념 9, 1).
- 결과: 규모 문제는 프레임워크가 아니라 데이터 다루는 방식에서 생긴다는 걸 이해했다.
11. 주소 텍스트 지오코딩 검토 (disaster-dashboard · 14:27~15:45)¶
- 배경: 원천 데이터에는 주소만 텍스트로 있는 것도 많다. 그런 데이터도 지도에 올리고 싶었다.
- 진행:
- "지오코더 → pyproj → H3" 흐름에서 pyproj → H3는 이미 있다. 새로 필요한 건 주소 → 좌표 파이프라인 하나다.
- 위치가 텍스트 주소인지, 좌표라면 어떤 EPSG인지를 판단해서 자동으로 나누는 방식도 가능하다고 확인했다.
- VWorld 지오코더 가이드에 결과 저장을 금지하는 문구가 실제로 있었다. 숫자만 보고는 출처를 모른다고 해도 그렇게 가는 건 권하지 않는다는 답을 받았다.
- 행안부 주소 DB를 확인했다. 좌표 자료는 신청·심사가 필요하지만, 승인 후에는 공공누리 제1유형이라 저장·가공해서 쓸 수 있다.
- 결과: 지오코딩 원천 후보를 정리했다. 실제 구현은 남았다.
12. 할 일 목록 정리와 대체 열·오버뷰 설계 (disaster-dashboard · 15:59~16:23)¶
- 배경: 작업이 뒤죽박죽이라 할 일을 번호로 정리해 기억시켰다. 정규화 개선, Parquet 받기, 태그 이름 바꾸기 같은 일이다.
- 진행:
- 외부 승인 없이 바로 할 수 있는 일부터 골랐다.
h3_r9가 없으면 대체 열을 쓰는 방식을 정했다.sgg_code·adm_code가 이미 그 역할을 한다.- 시니어 방식(구 안의 셀 목록을 데이터에 넣기)과 비교했다. 화면 동작은 같고, 셀 목록을 어디에 두느냐만 다르다.
- 오버뷰에서 셀 값을 더하면 구 데이터가 중복된다는 문제를 짚었다. 그래서 정확한 칸과 지역 단위를 따로 센다는 메모를 남겼다.
- 결과: 오버뷰 페이지를 만들기 전에 정할 것 두 가지를 확인했다.
13. 날짜 슬라이더와 커밋 (disaster-dashboard · 17:00~17:19)¶
- 배경: 오버뷰 대신 데이터셋마다 날짜 슬라이더를 두는 게 낫겠다고 생각했다.
- 진행:
- 슬라이더를 오버뷰보다 먼저 하기로 했다.
- 그 전에 지도 관련 변경을 커밋 2개로 나눴다. 푸시는 하지 않았다.
- 슬라이더를 구현했다.
- "우와" 소리가 나올 시각화 아이디어를 받았다. 핵심 무기는 모든 데이터가 같은 H3 격자 위에 있다는 점이다. 이건 보류했다.
- 결과: 슬라이더 작업과 시험은 끝났다. 커밋은 아직 안 했다.
14. category 범주 정규화 검토 (disaster-dashboard · 17:20~17:38)¶
- 배경: 남은 할 일 중
use_llm범주 정규화가 무슨 일인지, 왜 시맨틱 레이어 이야기가 나오는지 몰랐다. - 진행:
- hub-dev에 시맨틱 레이어가 있고, 범주 정규화는 그 위에 올리기 위한 준비라는 설명을 들었다.
- 그런데 이 대시보드는 에이전트를 안 쓴다. 그러면 시맨틱 레이어는 꼭 필요하지 않다.
- 그래도 범주 정규화가 필요한 이유는 "종류별로 세고 거르기"다.
- 20개 데이터셋의 열 424개를 확인했다. 자연어 분류가 필요한 곳은 6곳, 코드표로 풀 곳은 2곳이었다.
- LLM이 꼭 필요한지 물었다. 도로굴착 데이터로 재 보니 키워드 규칙 8개로 88.5%가 분류된다.
- 결과: LLM 없이 규칙 기반부터 해 보는 쪽으로 기울었다. 할 일 목록(7번)에 적어 두었다.
🧠 부족했던 개념¶
1. 서버 동시성 모델과 I/O 병목 · 🔁 3번 물음¶
- 어떻게 드러났나: 아키텍처 설명을 준비하면서 물었다(→ 작업 10). 처음에는 "큰 CSV에 작업 큐가 필요한 건 Node가 단일 스레드라서인가"라고 물었다. 이어서 "FastAPI로 바꾸면 해결되나", 마지막에 "백엔드가 부족하니 자세히"까지 세 번 물었다.
- 헷갈린 점: 기다리는 일(I/O)과 계산하는 일(CPU)을 구분하지 못했다. 그래서 느려지는 원인을 언어와 프레임워크 탓으로 봤다.
- 핵심:
- Node는 JS를 실행하는 스레드가 하나다. 하지만 네트워크·DB 응답은 OS와 스레드 풀에 맡기고, 기다리는 동안 다른 요청을 처리한다.
- 단일 스레드가 문제 되는 건 무거운 계산을 한 번에 할 때뿐이다. 예를 들면 100만 행을 한 번에 문자열로 만들 때다. 이런 일은
worker_threads나 별도 서비스로 뺀다. - FastAPI(uvicorn)도 이벤트 루프 하나로 돌고 Python에는 GIL이 있다. 그래서 같은 계열이고, 같은 방식으로 짜면 같은 문제가 난다.
- 요청 하나의 시간은 대부분 외부 쿼리를 기다리는 데 쓴다. 사람이 몰리면 언어와 상관없이 서버를 여러 개 띄운다(수평 확장).
- 👉 서버 동시성 모델과 I/O 병목
2. H3 격자 체계와 해상도 계층 · 🔁 3번 물음¶
- 어떻게 드러났나: 지도를 다듬으면서 물었다(→ 작업 8). "r9로 정규화했는데 r7로 그릴 수 있나"로 시작했다. 이어서 "육각형이 겹쳐 데이터가 겹치지 않나", "셀 번호가 전 세계 공통인가"로 질문을 넓혀 갔다.
- 헷갈린 점: H3 셀 번호를 우리가 정한 임의의 값처럼 생각했다. 그래서 해상도를 바꾸거나 다른 곳에서 그리면 겹치거나 어긋날까 걱정했다.
- 핵심:
- H3는 Uber가 공개한 전 지구 육각형 격자다. 해상도마다 지구 전체가 미리 나뉘어 있다. 그래서 어느 라이브러리에서 계산해도 같은 좌표는 같은 셀 번호가 나온다.
- 같은 해상도의 셀은 겹치지도 비지도 않는다. 좌표 하나는 정확히 한 셀에 들어간다.
- 작은 셀은
h3ToParent로 큰 셀에 묶는다. 자식은 부모가 하나뿐이라 합계가 보존된다(679행 → r7에서도 679행). - 단, 큰 육각형과 작은 육각형 7개는 모양이 딱 포개지지 않는다. 그래서 "기준은 r9, 큰 칸은 항상 r9의 부모로" 규칙을 지킨다. 좌표에서 r7을 따로 계산하면 경계 근처 점의 결과가 엇갈릴 수 있다.
- 👉 H3 격자 체계와 해상도
3. ORM의 개념과 역할 · 🔁 2번 물음¶
- 어떻게 드러났나: 대시보드 아키텍처를 읽다가 물었다(→ 작업 3). Drizzle이 뭔지 묻고, 바로 이어서 "ORM의 정확한 뜻"을 물었다.
- 헷갈린 점: ORM이라는 말을 알았지만 무엇을 무엇에 대응시키는지 몰랐다. Drizzle이 전형적인 ORM과 어떻게 다른지도 몰랐다.
- 핵심:
- ORM(Object-Relational Mapping)은 프로그램의 객체와 DB의 관계형 표를 대응시킨다. 클래스↔표, 객체↔행, 속성↔열, 참조↔외래 키다.
- Hibernate, Django ORM 같은 전형적인 ORM은 변경 추적, 관계 따라가기, 지연 로딩으로 SQL을 감춘다. 대신 반복문에서 질의가 N번 나가는 N+1 문제가 생기기 쉽다.
- Drizzle은 SQL을 감추기보다 "ORM이라 불리는 SQL 빌더"에 가깝다. 표 정의(
schema.ts)에서 TypeScript 타입이 나오고,drizzle-kit으로 마이그레이션을 만든다. - 👉 ORM의 개념과 역할
4. 메타데이터 기반 동적 쿼리 생성¶
- 어떻게 드러났나: 대시보드 동작을 파악하면서 물었다(→ 작업 3). "PG 메타데이터로 ClickHouse 쿼리를 완성하는 것"까지는 맞혔다. 그런데 "DB를 어떻게 메타데이터로만 쓰나, 그 흐름을 모르겠다"고 다시 물었다. 전날(11/09)에도 헷갈린 개념이다.
- 헷갈린 점: 메타데이터 DB가 실제 데이터 없이 어떻게 조회에 쓰이는지 그림이 안 그려졌다.
- 핵심:
- 도서관에 비유하면 PG는 목록 카드함이고, ClickHouse는 서고다. PG에는 데이터셋마다 한 줄씩 "어느 표, 위치 단위, 시간 성격, 보유 기간"이 들어 있다.
- 이게 되는 이유는 정규화 덕분에 모든 표의 열 구조가 같기 때문이다(
t_start,sgg_code,h3_r9…). 그래서 열 이름은 코드에 고정하고, PG 값으로는 SQL 틀의 빈칸만 채운다. - 조건 값은 사용자가 보낸 필터를 검증해서 쓴다.
- 👉 메타데이터 카탈로그 기반 조회
5. OLTP와 OLAP의 차이¶
- 어떻게 드러났나: FusionDB가 PG를 대신할 수 있는지 검토하다가 물었다(→ 작업 6). "PG는 OLTP이고 FusionDB는 OLAP이라 대체가 힘든 건가"라고 확인했다.
- 헷갈린 점: 방향은 맞았다. 하지만 OLTP·OLAP이라는 이름표만 알고, 그 설계 차이 때문에 무엇이 빠지는지는 설명하지 못했다.
- 핵심:
- OLTP는 작은 쓰기를 자주, 동시에 여럿이 한다. 정확성(제약, 잠금, 원자성)이 중요하다. 예는 PostgreSQL, MySQL이다.
- OLAP은 많이 몰아서 적재하고, 수백만 행을 훑어 집계한다. 처리량(열 단위 저장, 병렬 스캔)이 중요하다. 예는 ClickHouse, BigQuery다.
- Delta Lake 같은 파일 기반 OLAP은 행 잠금, 여러 표를 묶는 트랜잭션, PK·UNIQUE 강제가 구조적으로 약하다. 작은 쓰기도 비싸다. 그래서 승인 흐름처럼 잠금·원자성에 기대는 일은 OLTP DB에 둔다.
- 👉 OLTP와 OLAP의 차이
6. BFF(Backend For Frontend) 패턴¶
- 어떻게 드러났나: 아키텍처 설명 초안을 다듬다가 물었다(→ 작업 10). "BFF라는 말이 왜 나왔나, Next.js가 BFF인가"라고 물었다.
- 헷갈린 점: BFF를 프레임워크 이름처럼 받아들였다. 실제로는 역할을 가리키는 말이다.
- 핵심:
- BFF는 특정 화면 하나를 위해 범용 API 앞에 세운 전용 서버다. 범용 백엔드는 그대로 두고, 화면 사정에 맞춘 일은 BFF가 맡는다.
- 하는 일은 이렇다. 토큰을 서버에만 두고 대신 호출하고, SQL을 정해진 틀로 만든다. 앱 전용 기록(즐겨찾기 등)을 저장하고, 로그인·권한을 확인하고, 여러 호출을 화면에 맞는 모양으로 합친다.
- "Next.js가 BFF"가 아니라 "Next.js의 서버 기능으로 BFF를 구현했다"가 정확하다. Express나 FastAPI로 따로 만들 수도 있다.
- 👉 BFF Backend For Frontend 패턴
7. Next.js 풀스택 프레임워크 구조¶
- 어떻게 드러났나: BFF 질문 바로 뒤에 물었다(→ 작업 10). "Next.js로 프론트와 백을 둘 다 할 수 있는 이유"와 "복잡해져도 유지할 수 있나"를 물었다.
- 헷갈린 점: Next.js를 React 화면 도구로만 봤다. 그 자체가 Node.js 서버로 돈다는 점을 몰랐다.
- 핵심:
- 같은 코드베이스가 빌드 때 두 갈래로 나뉜다.
"use client"코드는 브라우저에서, 나머지는 Node 서버에서 돈다. - 서버 쪽에는 Route Handler(
route.ts가 곧 HTTP API)와 Server Component(화면을 그리기 전에 DB를 직접 읽음)가 있다.server-only를 붙인 파일은 브라우저로 새지 않는다. - 화면이 복잡해지는 건 문제없다. 하지만 정기 작업(CronJob), 오래 걸리는 작업(작업 큐), 무거운 계산은 요청-응답 구조와 안 맞아서 떼어 낸다.
- 👉 프론트엔드와 백엔드 서버 구조
8. 작업 큐와 백그라운드 워커¶
- 어떻게 드러났나: 큰 CSV 내보내기 이야기를 하다가 물었다(→ 작업 10). "그럼 CronJob 같은 걸 하나 더 띄워야 하나"라고 물었다.
- 헷갈린 점: 정해진 시간에 도는 CronJob과 요청이 들어오면 바로 처리하는 워커를 같은 것으로 봤다.
- 핵심:
- CronJob은 정해진 시각에 떴다가 끝나면 사라진다. 정기 동기화나 정리 작업에 맞다. 워커(Deployment)는 항상 떠 있다가 큐에 들어온 일을 집어 처리한다.
- 큰 내보내기는 이렇게 흐른다. "요청 → 작업 표에 넣고 바로 응답 → 워커가 만들어 저장소에 올림 → 화면이 상태를 확인하고 받기."
- Redis 없이 PG를 큐로 쓸 수도 있다.
SELECT … FOR UPDATE SKIP LOCKED로 여러 워커가 같은 작업을 집지 않게 한다. - 요청 하나를 몇 분씩 붙잡으면 안 되는 이유가 있다. 프록시 시간 제한(약 60초), 배포 때 연결이 끊김, 이어 받기 불가, 진행률을 못 보여 줌.
- 👉 작업 큐와 백그라운드 워커
9. 데이터 규모 증가와 시스템 확장성¶
- 어떻게 드러났나: 아키텍처 설명을 준비하면서 앞날을 물었다(→ 작업 10). "데이터 종류와 양이 계속 늘면 어떤 문제가 왜 생기고, 어떻게 조치하나"라고 물었다.
- 헷갈린 점: 규모가 커지면 어디서 먼저 깨지는지 병목 지점을 짚는 눈이 없었다.
- 핵심:
- 성장은 종류(데이터셋 수)와 양(행 수) 두 방향으로 나눠 본다.
- 종류가 늘면 차례로 하는 동기화가 길어진다. 조치: CronJob, 바뀐 것만(증분), 몇 개씩 동시 호출.
- 양이 늘면 조회가 느려진다. 조치: 파티션·정렬 키를 조건에 맞추고, 건너뛰기 색인을 둔다.
LIMIT … OFFSET n은 앞의 n행을 매번 읽고 버린다. 그래서 뒤로 갈수록 느려진다. 키셋 페이지네이션(WHERE key > 마지막값)으로 바꾼다.- 👉 데이터 규모 증가와 확장성
10. 시맨틱 레이어의 개념과 용도¶
- 어떻게 드러났나: 남은 할 일을 보다가 물었다(→ 작업 14). "
use_llm범주 정규화가 무슨 작업이고, 왜 시맨틱 레이어 이야기가 나오나"라고 물었다. - 헷갈린 점: 시맨틱 레이어가 무엇을 위한 층인지 몰랐다. 그래서 이 대시보드에 필요한지 판단하지 못했다.
- 핵심:
- 시맨틱 레이어는 데이터 위에 "이 열이 무슨 뜻이고 어떤 값을 가질 수 있는지"를 정의해 두는 층이다. 열, 지표, 필터, 조인, 값 사전(정식값·동의어)으로 이뤄진다.
- 주 용도는 LLM 에이전트다. LLM이 SQL을 직접 쓰지 않고 정의된 지표·필터 중에서 고르게 해서 조용히 틀리는 답을 막는다.
- 에이전트를 쓰지 않으면 꼭 필요하지 않다. 그 준비 작업인 범주 표준화만 따로 쓸모가 있다.
- 👉 시맨틱 레이어의 개념과 용도
11. 범주형 데이터 정규화의 필요성¶
- 어떻게 드러났나: 시맨틱 레이어가 필요 없다는 걸 확인한 뒤 물었다(→ 작업 14). "그럼 category의 자연어를 분류하는 작업이 왜 필요한가"라고 물었다.
- 헷갈린 점: 원문이 남아 있는데 왜 굳이 정해진 값으로 바꿔야 하는지 몰랐다.
- 핵심:
- "종류별로 세고 거르기"를 하려면 값이 정해진 유한한 범주여야 한다. 띄어쓰기 하나만 달라도 다른 값으로 갈려 묶음이 수만 개가 된다.
- 글자 검색으로 대신하면 같은 뜻의 다른 표현은 빠지고, 엉뚱한 행은 섞인다.
- 방법은 사람이 분류하기, 규칙, LLM이 있다. 고유값마다 한 번만 분류하고, 애매하면 보류하고 사람이 검토한다. 실제로는 규칙만으로 대부분 풀리는 경우도 많다.
- 종류별 통계·필터를 쓸 계획이 없으면 하지 않아도 된다.
- 👉 범주형 데이터 정규화
🩹 오늘 드러난 약점¶
- 원인을 도구 탓으로 돌린다 — 근거: "단일 스레드라서?", "FastAPI로 바꾸면?", "OLAP이라서?"처럼 원인을 언어·제품 이름표에서 찾았다(개념 1, 5, 9). → 다음에: 느린 곳이 나오면 먼저 시간이 어디서 쓰이는지(대기·계산·쿼리)를 쪼개 본다.
- 역할과 구현을 섞어 본다 — 근거: "Next.js가 BFF인가", "CronJob을 더 띄우나", Drizzle·ORM 질문(개념 3, 6, 8). → 다음에: 새 용어가 나오면 "패턴·역할인지, 도구인지"부터 구분해서 묻는다.
- 기술의 목적을 모른 채 할 일을 받아들인다 — 근거: 시맨틱 레이어와 LLM 범주 분류를 왜 하는지 세 번 되물은 뒤에야 "우리한텐 필요 없다"는 결론이 나왔다(개념 10, 11). → 다음에: 할 일 목록에 넣기 전에 "이게 없으면 어떤 질문에 답을 못 하나"를 먼저 확인한다.
- 전날 개념이 아직 덜 굳었다 — 근거: 메타데이터 기반 조회를 이틀 연속 물었다(개념 4). → 다음에: 주제 파일을 다시 읽고, 쿼리 하나가 PG→SQL→ClickHouse로 가는 흐름을 직접 그려 본다.
🧪 복습 퀴즈¶
1. Node 서버에서 5만 행 CSV를 1,000행씩 스트리밍으로 받는 동안 다른 사용자가 거의 막히지 않는 이유는? 그래도 작업 큐가 필요한 이유는?
답 보기
시간 대부분이 플랫폼 응답을 **기다리는 I/O**이고, 그동안 이벤트 루프가 다른 요청을 처리하기 때문이다. 작업 큐가 필요한 건 단일 스레드 때문이 아니다. **요청 하나를 몇 분씩 붙잡는 것 자체**가 위험해서다(프록시 시간 제한, 배포 때 끊김, 이어 받기 불가).2. r9로 정규화된 데이터를 r7로 그릴 때, 좌표에서 r7을 바로 계산하지 않고 r9의 부모로 올리는 이유는?
답 보기
H3의 큰 셀과 작은 셀 7개는 모양이 정확히 포개지지 않는다. 그래서 경계 근처 점은 두 방법의 결과가 엇갈릴 수 있다. 부모로 올리면 자식마다 부모가 하나뿐이라 **항상 일관되고 합계가 보존된다**.3. 즐겨찾기·제안 승인 기록을 OLAP 엔진(Delta Lake 기반)에 두기 어려운 이유 두 가지는?