사용자 활동 추적 사례, 특정 시간에 특정 사용자에게 느렸던 이유는?
사용자 활동 추적은 느리다고 한 사용자를 로그인 ID로 찾고, 그 사용자가 거쳐 간 화면에서 가장 느린 요청의 SQL까지 한 흐름으로 내려가는 일입니다. 58초 영상과 제품 화면 캡처 7장으로 그 과정을 정리했습니다.
영상으로 먼저 보기: 58초에 담은 사용자 활동 추적 과정
느리다고 한 사용자 한 명에서 원인 SQL 한 줄까지, AI Insight에 물어 가며 찾는 사용자 활동 추적 과정을 58초로 담은 영상입니다.
영상에서 다루는 순서는 다음과 같습니다.
이 영상이 답하는 7가지 질문 정리
영상이 보여 주는 사용자 활동 추적을 질문으로 바꾸면 일곱 가지이고, 아래 일곱 개 절이 이 순서대로 답합니다.
- 느리다는 문의를 받으면 어디에서 조사를 시작하는가?
- 지금 접속한 사용자가 몇 명인지는 어떻게 아는가?
- 그 가운데 느리다고 한 사용자는 무엇으로 찾는가?
- 그 사용자가 무엇을 하다가 느렸는지는 어떻게 확인하는가?
- 가장 느렸던 요청은 어느 구간에서 시간을 썼는가?
- 그 구간에서 실행된 SQL은 무엇이었는가?
- 원인이 SQL이라는 판단은 어떤 수치로 받쳐지는가?
느리다는 문의를 대시보드 안의 질문으로 바꾸는 방식
조사는 대시보드를 떠나지 않고 시작합니다. 영상은 OPENMARU APM의 실시간 WAS 대시보드 오른쪽에 AI 패널을 열고, 지금 접속한 사용자가 몇 명인지부터 묻습니다. 나레이션은 “한 사용자가 느리다고 합니다. 누가, 무엇을 하다가였을까요?”라는 물음으로 시작합니다.
WAS(Web Application Server, 웹 애플리케이션 서버)는 업무 프로그램이 실제로 실행되는 서버입니다. 화면의 대시보드는 shopping이라는 애플리케이션 그룹에 속한 인스턴스 다섯 개를 한 화면에 놓고, 처리 중인 요청과 활성 사용자, TPS(Transactions Per Second, 초당 처리 건수), 평균 응답 시간을 그래프로 그립니다. 이 그래프들은 시스템 전체의 상태를 말해 줍니다. 그러나 문의를 넣은 그 한 사람이 어떤 화면에서 얼마나 기다렸는지는 그래프에 따로 표시되지 않습니다.

▲ 대시보드를 떠나지 않고 AI 패널에 질문을 입력한다 (영상 0:11)
캡처 오른쪽 아래의 파란 말풍선이 질문입니다. 패널은 대시보드를 덮지 않고 옆에 열리므로 운영자는 평소 보던 그래프를 그대로 둔 채 묻습니다. 질문을 보내면 패널에 “생각하고 있습니다”라는 표시가 뜨고 잠시 뒤 같은 자리에 답이 채워집니다. 평균값만 보면 한 사람의 불편은 묻힙니다. 그래서 사용자 활동 추적은 전체 그래프가 아니라 한 사람을 가리키는 질문에서 출발합니다. 영상의 표현으로는 “그대로 물어보세요”입니다.
접속 사용자 100명이라는 답이 사용자 활동 추적의 범위를 정하는 이유
첫 질문의 답은 100명입니다. AI 패널은 “현재 접속된 사용자는 100명입니다”라고 답하고, 목록에 들어 있는 로그인 ID 하나가 사용자 한 명을 뜻한다고 덧붙입니다.
이 답은 두 가지를 알려 줍니다. 하나는 조사 대상의 크기입니다. 느리다고 한 사용자는 이 100명 가운데 한 명이므로 찾아야 할 범위가 정해집니다. 다른 하나는 세는 단위입니다. 접속 수를 IP 주소나 세션이 아니라 로그인 ID로 셌다는 점이 중요합니다. 문의를 넣은 사람은 자신을 IP 주소로 말하지 않고 아이디로 말하기 때문입니다.

▲ 현재 접속된 사용자는 100명 (영상 0:15)
질문은 “현재 접속된 사용자 수는?”이라는 짧은 문장 하나였습니다. 조회 조건을 고르거나 메뉴를 찾아 들어가지 않았습니다. 답의 위쪽에는 AI가 답을 만들며 거친 생각을 펼쳐 볼 수 있는 줄이 있어, 답이 어떤 데이터에서 나왔는지 확인할 수 있습니다. 영상 설명란은 화면의 수치가 데모 환경에서 측정한 값이라고 밝힙니다. 사용자 활동 추적에서는 100명이라는 숫자 자체보다, 접속 수를 로그인 ID 단위로 바로 얻는다는 점을 봐야 합니다.
대시보드에 늘 떠 있는 활성 사용자 수도 같은 기준으로 셉니다. OPENMARU APM의 기술 백서에 따르면 이 값은 최근 5분 동안 한 번이라도 요청을 보낸 사용자 수이고, 에이전트에 설정한 사용자 식별 값을 기준으로 중복 없이 집계합니다. 집계 방식의 자세한 설명은 대규모 환경에서도 신뢰할 수 있는 APM 사용자 수 집계 전략 글에서 읽을 수 있습니다.
로그인 ID 목록으로 그 사용자를 찾는 사용자 활동 추적의 기준
사용자는 로그인 ID로 찾습니다. 영상은 두 번째 질문으로 최근 접속한 사용자 목록을 요청하고, AI 패널은 로그인 ID 100개를 표로 답합니다. 나레이션은 “접속한 100명 가운데, 느리다고 한 그 사용자를 찾습니다”라고 말합니다.
표의 열은 순번, 로그인 ID, 요청 수 세 가지입니다. 제목 줄에는 집계 구간이 적혀 있는데 2026년 6월 25일 09시 37분 11초부터 09시 42분 11초까지 5분입니다. 첫 줄이 openmaru라는 로그인 ID이고 요청 수는 657건입니다. 그 아래로 요청 수 649건, 648건, 643건인 사용자가 이어집니다.

▲ 로그인 ID 와 요청 수로 정리된 접속 사용자 목록 (영상 0:19)
이 목록이 가능하려면 APM이 요청마다 누가 보냈는지를 함께 기록하고 있어야 합니다. 응답 시간과 URL만 모으는 도구에서는 느린 요청을 찾을 수는 있어도 그 요청을 보낸 사람까지 거슬러 올라가지 못합니다. 영상의 목록은 반대 방향의 조사를 가능하게 합니다. 느린 요청에서 사람을 찾는 것이 아니라, 사람에서 출발해 그 사람의 요청을 찾습니다. 헬프데스크에 들어온 문의에는 보통 아이디가 붙어 있으므로, 사용자 활동 추적은 이 방향이 실무의 순서와 맞습니다.
한 사용자가 거쳐 간 화면 5건으로 보는 사용자 활동 추적 과정
무엇을 하다가 느렸는지는 그 사용자의 요청 목록이 답합니다. 영상의 세 번째 질문은 “오늘 09시부터 10시까지 openmaru 사용자의 활동 내역을 알려줘”입니다. AI 패널은 그 한 시간 동안 openmaru 사용자가 호출한 트랜잭션 다섯 건을 표로 돌려줍니다. 나레이션은 “그 사용자가 한 시간 동안 거쳐 간 화면이, 순서대로 나옵니다”라고 설명합니다.

▲ 한 사용자가 한 시간 동안 거쳐 간 화면 5건 (영상 0:29)
표에 담긴 값을 옮기면 다음과 같습니다.
| 순번 | 호출한 화면(URL) | 지속 시간 | 상태 코드 |
|---|---|---|---|
| 1 | /home | 418ms | 200 |
| 2 | /cart/items | 272ms | 200 |
| 3 | /products/detail | 3,200ms | 200 |
| 4 | /orders | 334ms | 200 |
| 5 | /payments | 495ms | 200 |
다섯 건을 나란히 놓으면 한 줄만 다릅니다. 홈, 장바구니, 주문, 결제는 모두 0.5초 안에 끝났는데 상품 상세 화면만 3,200ms, 곧 3.2초가 걸렸습니다. 다른 요청의 여섯 배가 넘는 시간입니다. 상태 코드는 다섯 건 모두 정상을 뜻하는 200입니다. 오류는 없었습니다. 그래서 이 문의는 오류 로그나 알람으로는 잡히지 않습니다. 사용자는 실패한 화면을 본 것이 아니라 늦게 뜬 화면을 본 것입니다.
이 표는 “무엇을 하다가”에 대한 답입니다. openmaru 사용자는 상품 상세를 열다가 느려졌습니다. 답의 아래쪽에는 트랜잭션 상세 조회로 넘어가는 링크가 붙어 있고, 표의 URL도 눌러서 열 수 있는 형태입니다. 사용자 활동 추적은 여기서 끝나지 않고 다음 단계의 입구를 같은 답 안에 둡니다.
가장 느린 요청의 호출 흐름이 시간을 구간으로 나누는 구조
사용자 활동 추적의 다음 단계는 호출 흐름입니다. 영상은 표에서 /products/detail을 누르고, 그 요청의 호출 흐름 화면을 띄웁니다. 나레이션은 “가장 느렸던 화면을 누르면, 그 화면의 호출 흐름이 열립니다”라고 말합니다.
호출 흐름은 요청 한 건이 처리되는 동안 거친 메서드 호출을 시간 막대로 늘어놓은 화면입니다. 위쪽 목록에는 방금 본 다섯 건이 응답 시간 순으로 다시 나오고, 응답 시간 옆에 SQL 시간이 따로 적혀 있습니다. 상품 상세 요청은 응답 시간 3,200ms에 SQL 시간 3,000ms입니다.

▲ /products/detail 호출 흐름 — 응답 3.20초, SQL 3.00초 (영상 0:37)
캡처 아래쪽의 막대를 위에서부터 읽으면 세 가지가 보입니다. 맨 위 막대는 요청 전체로 3.20초, 100%입니다. 그 아래 커넥션 풀에서 데이터베이스 접속을 얻는 호출은 0ms로, 접속을 기다리느라 늦은 것이 아닙니다. 마지막으로 SQL을 실행하는 호출이 3.00초, 전체의 93.8%를 차지합니다. 요약 줄에는 응답 시간 3.20s, CPU 960ms, SQL 3.00s가 나란히 적혀 있습니다.
막대 세 줄이 원인 후보를 좁혀 줍니다. 애플리케이션 코드가 오래 계산한 것도 아니고, 커넥션을 기다린 것도 아니고, 데이터베이스에 보낸 질의 하나가 시간을 썼습니다. 같은 3초 지연이라도 커넥션 대기가 원인이면 풀 설정을 보아야 하고, SQL 실행이 원인이면 쿼리를 보아야 합니다. 호출 흐름은 이 갈림길에서 방향을 정해 줍니다.
제품의 트랜잭션 분석 안내서는 이 구분을 따로 짚습니다. 커넥션 풀에서 접속을 빌리기까지 오래 걸린 요청은 사용자 눈에는 SQL이 느린 것처럼 보이지만, 실제로는 데이터베이스가 한가하고 애플리케이션이 접속을 얻으려 줄을 선 상태입니다. 영상의 요청은 커넥션을 얻는 호출이 0ms이므로 이 경우가 아닙니다. 요청 한 건을 코드 수준까지 따라가는 기술의 원리는 트랜잭션 추적이란 글이 설명합니다.
원인 SQL 한 줄을 쿼리 본문으로 확인하는 과정
호출 흐름의 SQL 막대를 열면 실행된 SQL 문이 그대로 나옵니다. 화면은 DB 연결 정보, SQL 쿼리, 파라미터, 파라미터가 채워진 쿼리, FETCH 정보를 차례로 보여 줍니다.

▲ 느렸던 SQL 문과 바인딩된 파라미터 (영상 0:40)
쿼리는 상품 테이블에서 상품 코드가 일치하는 한 건을 조회합니다. 조회하는 열 가운데 두 개가 서브쿼리입니다. 하나는 상품 리뷰 테이블에서 그 상품의 평점 평균을 구하고, 다른 하나는 주문 항목 테이블에서 그 상품이 팔린 건수를 셉니다. 파라미터 칸에는 상품 코드 값이 적혀 있는데, 앞 절의 활동 내역 표에서 본 URL의 상품 코드와 같은 값입니다. 사용자가 연 화면과 데이터베이스에 도착한 질의가 한 요청으로 이어져 있다는 증거입니다.
사용자 활동 추적이 SQL까지 닿으면 운영자가 얻는 것은 개발팀에 넘길 수 있는 근거입니다. “상품 상세가 느리다”는 말은 재현부터 다시 해야 하지만, “이 SQL이 이 파라미터로 3초 걸렸다”는 말은 바로 실행 계획을 확인할 수 있습니다. 화면에는 쿼리를 AI에게 진단시키는 버튼도 함께 놓여 있습니다. 영상은 이 버튼을 누르지 않고 다음 화면으로 넘어갑니다.
제품 사용 안내서에 따르면 이 버튼은 호출 흐름에서 연 SQL을 AI 쿼리 진단으로 넘겨 실행 계획과 인덱스까지 분석하게 합니다. 느린 SQL을 찾는 일과 그 SQL이 느린 까닭을 찾는 일이 같은 화면에서 이어지는 셈입니다.
SQL 시간 점유 93.8%가 결론을 받치는 기준
결론은 수치 하나로 정리됩니다. 성능 분석 화면의 시간 분석 항목은 SQL 시간 점유를 93.8%, SQL 시간을 3.00초로 표시하고 붉은 ‘위험’ 딱지를 붙입니다. 나레이션은 “응답 시간의 94%는, SQL 한 줄이었습니다”라고 말합니다. 나레이션의 94%는 화면의 93.8%를 반올림한 값입니다.

▲ SQL 시간 점유 93.8% · 3.00초 (영상 0:43)
화면 위쪽의 ‘문제 감지’ 항목은 이 요청에서 느린 SQL 쿼리를 찾아 목록으로 보여 줍니다. 실행 시간 3.00초, 점유율 93.8%라는 값과 함께 SQL 본문, 접속한 데이터베이스 주소, DB 사용자가 적혀 있습니다. 그 아래 ‘누적 핫스팟’은 같은 쿼리가 한 번 호출됐고 평균 3.00초였다고 표시합니다. 이 점이 중요합니다. 짧은 쿼리가 수백 번 반복돼 느려지는 경우와 달리, 이 요청은 쿼리 한 번이 통째로 느린 경우입니다.
제품 사용 안내서는 이 ‘문제 감지’를 시스템이 먼저 짚어 주는 카드라고 설명합니다. 느린 SQL뿐 아니라 SQL 오류, 외부 호출 지연, 오류 패턴도 같은 자리에 표시되므로, 운영자는 호출 흐름의 막대를 하나씩 읽기 전에 이 카드로 의심할 곳을 먼저 정할 수 있습니다. 사용자 한 명이 아니라 느린 요청 전체의 분포에서 출발하고 싶을 때는 APM 에서 트랜잭션 분석 챠트 활용하기 : T-MAP 글의 방법이 맞습니다.
아래쪽 시간 분석 카드는 네 칸입니다.
| 항목 | 값 | 화면 표시 |
|---|---|---|
| CPU 시간 | 960ms | 30.0% |
| SQL 시간 | 3.00초 | 93.8%, 위험 |
| 외부 호출 시간 | 0ms | 0.0% |
| FETCH | 0ms | 0건 |
외부 호출 시간이 0이므로 다른 시스템을 부르다 늦은 것이 아닙니다. FETCH 시간도 0이어서 결과를 많이 읽어 오느라 늦은 것도 아닙니다. 남는 것은 SQL 실행 시간뿐입니다. 3.20초 가운데 3.00초라는 계산이 93.8%라는 숫자가 됩니다. 영상은 이 장면 뒤에 “사용자 한 명에서, SQL 한 줄까지”라는 문장으로 사용자 활동 추적 전체를 요약합니다.
영상 밖의 보충: 서브쿼리 두 개가 든 SQL을 점검하는 기준
화면에 나온 쿼리처럼 바깥 쿼리의 값을 참조하는 서브쿼리를 상관 서브쿼리라고 부릅니다. MySQL 참조 설명서의 상관 서브쿼리 항목은 이런 서브쿼리가 바깥 쿼리의 행마다 다시 평가된다고 설명합니다. 영상의 쿼리는 바깥에서 상품 한 건만 고르므로 서브쿼리도 각각 한 번씩 실행됩니다. 그런데도 3초가 걸렸다면 서브쿼리가 읽는 테이블에서 조건에 맞는 행을 찾는 방식부터 확인해야 합니다.
확인 수단은 실행 계획입니다. MySQL의 EXPLAIN 설명에 따르면 EXPLAIN은 옵티마이저가 각 테이블을 어떤 순서로, 어떤 인덱스로 읽는지 보여 줍니다. 리뷰 테이블과 주문 항목 테이블에서 조건으로 쓰인 열에 인덱스가 있는지, 있다면 실제로 쓰이는지가 첫 점검 항목입니다. 영상은 이 쿼리가 왜 느린지까지는 다루지 않습니다. 사용자 활동 추적으로 얻은 SQL 문과 파라미터가 있으면 이 점검을 바로 시작할 수 있습니다. 같은 화면을 여는 다른 사용자도 같은 지연을 겪는지는 실행 계획과 함께 점검해야 합니다.
핵심 정리: 한 표로 보는 사용자 활동 추적의 흐름
사용자 활동 추적은 사람에서 출발해 SQL에서 끝나는 조사입니다. 영상의 흐름을 단계로 나누면 다음과 같습니다.
| 단계 | 화면에서 일어난 일 | 운영자가 얻는 것 | 영상 시각 |
|---|---|---|---|
| 질문 | 대시보드 옆 AI 패널에 문장으로 질문 | 화면을 떠나지 않는 조사 시작 | 0:11 |
| 범위 | 현재 접속된 사용자 100명 | 조사 대상의 크기와 세는 단위 | 0:15 |
| 사람 | 로그인 ID 100개와 요청 수 목록 | 느리다고 한 그 사용자 | 0:19 |
| 활동 | 한 시간 동안 거쳐 간 화면 5건 | 무엇을 하다가 느렸는지 | 0:29 |
| 구간 | /products/detail 호출 흐름 3.20초 | 시간이 쓰인 구간 | 0:37 |
| 질의 | 서브쿼리 두 개가 든 SQL 문 | 개발팀에 넘길 근거 | 0:40 |
| 수치 | SQL 시간 점유 93.8%, 3.00초 | 원인이 SQL이라는 판단 | 0:43 |
영상의 마지막 문장은 “묻는 만큼 보입니다”입니다. 질문 세 번과 클릭 몇 번으로 사용자 한 명의 불편이 SQL 한 줄로 좁혀졌고, 그 사이에 운영자는 대시보드를 한 번도 떠나지 않았습니다.
자주 묻는 질문
사용자 활동 추적은 무엇을 하는 일인가요?
사용자 활동 추적은 특정 사용자가 어떤 화면을 어떤 순서로 호출했고 각 요청이 얼마나 걸렸는지를 로그인 ID 기준으로 따라가는 일입니다. 영상에서는 openmaru 사용자가 한 시간 동안 호출한 화면 다섯 건을 시간순으로 뽑고, 그 가운데 3.2초가 걸린 상품 상세 요청을 찾았습니다. 전체 평균 그래프에서는 보이지 않는 한 사람의 경험을 확인하는 방법입니다.
AI Insight에는 어떤 질문을 했나요?
영상의 사용자 활동 추적은 질문 세 가지로 진행됐습니다. 현재 접속된 사용자 수, 최근 접속한 사용자 목록, 그리고 오늘 09시부터 10시까지 openmaru 사용자의 활동 내역입니다. 세 질문 모두 평소 쓰는 문장으로 입력했고, 조회 조건을 고르거나 메뉴를 찾아 들어가지 않았습니다. 답은 대시보드 옆 패널에 숫자와 표로 채워졌습니다.
느리다고 한 사용자는 무엇으로 찾나요?
사용자 활동 추적의 기준은 로그인 ID입니다. AI Insight는 현재 접속된 사용자를 로그인 ID 단위로 세어 100명이라고 답했고, 이어서 로그인 ID와 요청 수가 적힌 목록을 보여 주었습니다. 문의를 넣은 사람은 보통 자신의 아이디를 알려 주므로, IP 주소나 세션 값이 아니라 아이디로 찾을 수 있어야 문의와 기록을 바로 맞출 수 있습니다.
영상에서 가장 느렸던 요청은 무엇인가요?
상품 상세 화면인 /products/detail 요청입니다. 지속 시간이 3,200ms로, 같은 사용자의 다른 네 요청이 272ms에서 495ms 사이였던 것과 크게 달랐습니다. 다섯 건 모두 상태 코드는 200이어서 오류는 없었습니다. 실패가 아니라 지연이었기 때문에 오류 알람으로는 드러나지 않는 사례입니다.
응답 시간의 94%가 SQL이라는 것은 어떻게 알았나요?
호출 흐름과 성능 분석 화면에 수치로 표시됩니다. 요청 전체 응답 시간이 3.20초인데 SQL 실행 구간이 3.00초였고, 화면은 이를 SQL 시간 점유 93.8%로 표시했습니다. 나레이션의 94%는 이 값을 반올림한 것입니다. 커넥션을 얻는 호출은 0ms, 외부 호출 시간도 0ms여서 다른 원인 후보는 화면에서 함께 제외됩니다.
원인이 된 SQL은 어떤 쿼리였나요?
상품 한 건을 조회하면서 평점 평균과 판매 건수를 서브쿼리 두 개로 계산하는 쿼리였습니다. 화면에는 SQL 본문과 함께 바인딩된 상품 코드 파라미터가 표시됩니다. 누적 핫스팟 항목에 호출 수 1, 평균 3.00초로 적혀 있어, 짧은 쿼리가 여러 번 반복된 경우가 아니라 쿼리 한 번이 느렸던 경우임을 알 수 있습니다.
화면의 수치는 실제 운영 환경에서 나온 값인가요?
아닙니다. 영상 설명란은 화면의 수치가 데모 환경에서 측정한 값이라고 밝힙니다. 접속 사용자 100명, 응답 시간 3.20초, SQL 시간 3.00초는 모두 데모용 쇼핑몰 애플리케이션에서 나온 값입니다. 운영 환경에서는 수치가 달라지지만, 사용자 활동 추적이 사용자에서 화면으로, 화면에서 SQL로 내려가는 순서는 그대로 적용됩니다.
참고 리소스
사용자 활동 추적과 느린 SQL 분석을 더 살펴볼 때 볼 원 영상과 이어서 읽을 글, 인용한 문서를 모았습니다.
- APM이란? 서버 모니터링으로 못 잡는 장애, 개념부터 도입까지
- APM AI Insight 사례, 장애 알람에서 근본 원인까지 30초
- APM 핵심 지표 읽는 법
- 프롬프트로 WAS 장애 분석 — OPENMARU APM AI Agent 데모
- 범인은 무심코 짠 SQL 이었다: AI가 찾아낸 OOM과 DB 커넥션 풀 고갈의 연결고리
- 분산 추적으로 WAS 병목 찾기
- WAS 모니터링 가이드 — JVM 힙·스레드·커넥션 풀 관측 포인트
- AIOps란? 안정적인 IT 운영을 위한 특급 비법
- 누가, 무엇을 하다가 느려졌는지 찾을 수 있나요? — 클라우드네이티브TV — 이 글이 정리한 원 영상
- MySQL 8.4 Reference Manual: Correlated Subqueries — 상관 서브쿼리의 평가 방식
- MySQL 8.4 Reference Manual: Optimizing Queries with EXPLAIN — 실행 계획 읽는 법
- OpenTelemetry: Traces — 요청 한 건을 구간으로 나누어 보는 추적의 개념
- Google SRE Book: Monitoring Distributed Systems — 증상과 원인을 구분하는 모니터링 원칙



JBoss Data Grid PostgreSQL Cache Store 사용하기
/카테고리: JBoss/작성자: OM marketing룰 엔진으로 선언적 프로그래밍 – Drools 6.0
/카테고리: JBoss/작성자: OM marketingJBoss EAP 6 – 거침없이 배우는 JBoss
/카테고리: JBoss/작성자: OM marketing