개요 — 무엇을 하나
Service ▸ Sessions(Redis) 는 등록된 Redis 노드의 세션·캐시 저장소 상태를 한 화면에서 관제합니다. Service ▸ 데이터베이스 화면과 동일한 서사를 Redis 로 옮긴 것으로, 두 축을 중심으로 읽습니다.
- 수용 최대한도 + 현재 상태 — 메모리 수용률 링 게이지(
used_memory÷ 수용 상한), 클라이언트 연결(connected / maxclients), 블록된 클라이언트. - 처리량 — 초당 명령 수(
instantaneous_ops_per_sec), 최근 창 적중률(Δhits / Δ(hits+misses)), 네트워크 I/O(in/out kbps).
그리고 접이식 상세에서 메모리 관리 시계열(수용 상한 overlay + 축출 에피소드 핀)과 키스페이스/세션 분석을 제공합니다.
이 화면은 Redis 에 직접 접속하지 않습니다. 내부망 대표 수집기(
scripts/infr_redis_vts_collector.cjs, pm2 cron 매분)가 각 노드에서redis-cli INFO를 떠 중앙 MySQLinfr_redis_metric테이블에 이미 적재한 데이터를 앱이 읽기만 합니다. 앱에는 Redis 크리덴셜도, 상주 데몬도 없습니다(연결 누수·하드코딩 크리덴셜 트랩 회피).
언제 쓰나
- 세션 저장소 용량 관리 — Redis 메모리가 수용 상한에 근접해 세션이 축출(evicted) 로 유실될 위험을 조기에 봅니다.
- 캐시 효율 진단 — 적중률(hit rate)·단편화(fragmentation)·slowlog 로 캐시가 제 역할을 하는지 판단합니다.
- 연결 포화 감지 —
connected_clients가maxclients에 근접하거나rejected_connections가 늘면 신규 연결이 거부되기 전에 조치합니다. - 지속성·복제 이상 — RDB bgsave 실패, AOF rewrite, replica 링크 끊김을 배지로 확인합니다.
- 세션 수명 파악 — 만료(정상 수명)와 축출(메모리 압박)을 구분해 세션 회전량을 읽습니다.
화면 구성
상단 KPI
| KPI | 의미 |
|---|---|
| 노드 수 | 최근 창(30분)에 표본이 있는 Redis 노드 카드 수 |
| 정상 / 주의 / 중단 | up / degraded / down 노드 집계 |
| 총 ops/s | 전 노드 instantaneous_ops_per_sec 합 |
| 총 키 | 전 노드 keyspace_keys 합 |
노드 카드 (2대 지표)
각 노드는 카드 하나입니다. 헤더에 인스턴스 이름/alias·Redis 버전·역할(master/replica), 본문에 위 두 축의 지표가 들어갑니다.
① 수용 · 여유 (좌측 링 게이지) — 중앙값 = used_pct(사용량 ÷ 수용 상한). 아래 지표 스트립:
| 지표 | 필드 | 설명 |
|---|---|---|
| 클라이언트 | connected_clients / maxclients |
연결 수·상한. 상한 근접 시 신규 연결 거부 위험 |
| 블록 | blocked_clients |
BLPOP·BRPOP·WAIT 대기 클라이언트(0 이 정상) |
② 처리량 (우측) — 스파크라인 + 스트립:
| 지표 | 필드 | 설명 |
|---|---|---|
| ops/s | instantaneous_ops_per_sec |
초당 처리 명령 수 |
| 적중률 | Δhits / Δ(hits+misses) | 최근 창 캐시 적중률(표본 부족 시 누적값 폴백) |
| net I/O | instantaneous_input_kbps + output_kbps |
초당 네트워크 입출력 |
효율 점수 (카드 풋)
- 적중률(hit) 등급 — 우수 ≥99% · 양호 ≥95% · 보통 ≥80%.
- 메모리 효율(단편화) 등급 — 우수 0.95~1.4 · 양호 ~1.6 · 보통 ~2.5.
단편화 점수(
frag_score)는used_memory가 64MB 이상일 때만 계산합니다. 작은 인스턴스는 고정 오버헤드가 비율을 지배해 오탐이 나기 때문입니다(그 미만은 점수·상태 판정에서 제외).
세션 수명 흐름 스트립
카드 풋 전체폭에 만료 예정 → 흐름 → 누적 만료 를 표현합니다. 왼쪽 = 지금 TTL 을 가진 키(keyspace_expires, 곧 자연 소멸), 오른쪽 = 가동 이후 만료 누적(expired_keys, 세션 회전량). 채움이 ≈100% 면 순수 세션 저장소입니다.
상세 (펼치기)
접이식으로 두 블록을 엽니다(masonry 가 높이 변화를 자동 재배치).
- 메모리 관리 —
usedvs 수용 상한 시계열 + 수용 상한 100% 절취선 overlay + 축출 에피소드 crit 핀. 카드에 수용 상한(cap)·예상 여유공간(est_free)·총 RAM·DB 점유·OS 예비·피크·RSS·단편화·축출/만료 누적·축출 정책을 표시합니다. - 키스페이스 · 세션 — 총 키·TTL 보유 키·논리 DB(db0/db1…) 분포 막대·세션 DB 강조·평균 TTL·RDB/AOF/replica 지속성 배지.
교육용 popover (edu)
지표 옆 아이콘에 마우스를 올리면 원인·개선법을 설명하는 디자인된 popover 가 뜹니다(자세한 개념은 Redis 튜닝 배우기):
| popover | 내용 |
|---|---|
| SLOWLOG | 느린 명령 누적 원인 7종(O(N) 명령·big key·메모리 압박·fork 지연·Lua·파이프라인·대형 DEL) |
| 적중률 | keyspace hit ratio 근거·향상법(작업셋 상주·TTL 조정·스탬피드 완화) |
| 단편화 | RSS / used 건강 대역(1.0~1.5)·activedefrag·스왑(<1.0) 경고 |
| 논리 DB | Redis 번호 DB(0~15) 개념·용도별 분리·Cluster 이식성 |
| 만료·축출 | 만료(정상 수명) vs 축출(메모리 압박) 구분·읽는 법 |
사용법
- 폴링 — 진입 후
/service/session/live를 30초 주기로 폴링해 KPI·카드를 갱신합니다(서버는 대시보드를 20초 캐시). - 카드 재정렬 — 카드를 드래그해 우선순위대로 배치합니다(SortableJS · 순서 localStorage 영속).
- 상세 펼치기 — 카드의 [펼치기]로 메모리 관리·키스페이스 블록을 엽니다.
- edu 학습 — 각 지표 아이콘 hover 로 원인·개선법 popover 를 봅니다.
- 전체화면 — 헤더 LIVE 옆 전체화면 버튼으로 상단 네비를 숨기고 대시보드 모드로 전환(ESC 해제)합니다.
카드가 하나도 없다면 아직 Redis 노드가 등록·수집되지 않은 것입니다. Administration ▸ Collectors 에서
redis_vts수집기의redis_host노드를 등록하고, 대표 시스템에 수집기를 pm2 로 배치하세요.
데이터 소스
read-model infr_redis_metric
앱은 이 테이블을 읽기 전용 Legacy 스타일 모델(App\Models\Infr\InfrRedisMetric, $timestamps=false)로 매핑합니다. 마이그레이션은 두지 않습니다 — 테이블은 수집기가 CREATE TABLE IF NOT EXISTS 로 자체 프로비저닝하므로 앱이 Schema::create 하면 충돌합니다.
빌더 App\Services\Redis\RedisMetricService::dashboard() 규율:
- 최근 30분 창(
WINDOW_MIN)을 배치 1쿼리로 조회 →node_alias로 그룹(노드별 카드). 창 안에 표본이 없으면(수집 중단) 최근 180행이라도 가져와 노드를stale로 노출합니다. - 시계열은 카드당 최근 60포인트(
SERIES_MAX)로 절단. 누적 카운터(evicted/expired)는 인접 샘플 delta 로 rate 환산하며, 리셋(감소) 시null. - 대시보드 결과는 20초 캐시(
infr:redism:dash:v1).
-- 개념 예시(실제는 Eloquent). 최근 창 배치 조회 → PHP 그룹.
SELECT * FROM infr_redis_metric
WHERE sampled_at >= (NOW() - INTERVAL 30 MINUTE)
ORDER BY sampled_at;
수집기 — scripts/infr_redis_vts_collector.cjs
내부망 대표 시스템 1대가 pm2 cron 으로 주기 실행되며, 여러 노드의 Redis(redis-cli -h {ip} INFO)와 nginx vts 를 1회 순회 수집해 중앙 MySQL 에 직접 적재하고 종료합니다(상주 아님 → 매 실행 새 프로세스, 누수 없음). 설정은 파일 상단 CONFIG 블록만 편집(env·하드코딩 크리덴셜 금지).
# 대표 시스템 배포(매 분 순회 · 상주 아님)
npm i mysql2 # 유일한 npm 의존(적재용). redis-cli 는 OS 패키지로 설치.
pm2 start infr_redis_vts_collector.cjs --name infr-collector \
--no-autorestart --cron-restart "* * * * *"
pm2 save
인스턴스 조인 (alias / int FK)
수집기는 write 시점에 infr_instance 에서 노드 alias→id 를 조회해 instance_id(int) 를 직접 기록합니다. 앱은 metric.instance_id = infr_instance.id 정수 비교를 1차 조인으로 씁니다(collation 무관·PK 인덱스). 미등록/늦게 등록된 인스턴스는 node_alias(소문자) → infr_instance.alias 폴백으로 매칭하며, infr:link-metrics(리더 게이팅, 5분) 백필이 나중에 instance_id 를 채웁니다.
수용 상한(cap) 계산
링 게이지·메모리 차트의 100% 기준은 다음 순서로 정합니다.
| cap 종류 | 조건 | 상한 | 예상 여유(est_free) |
|---|---|---|---|
maxmemory |
maxmemory > 0 |
maxmemory 설정값(하드 상한) | maxmemory − used |
budget |
maxmemory 미설정 | 총 RAM − DB 버퍼풀 − OS 예비 | 예산 − used |
- 총 RAM =
total_system_memory(수집값), 없으면infr_instance.mem_mb폴백. - OS 예비 = 총 RAM ×
redis_reserve_pct(기본 20%). - DB 버퍼풀 = 같은 노드의
access=database수집기 최신infr_db_metric.raw.bp_size(한 노드 다중 DB 는 합산). 이 값을 차감해 Redis 가 현실적으로 쓸 수 있는 예산을 상한으로 삼습니다. - 예산이 현재
used아래로 내려가지 않도록 하한을 걸어 음수·역전을 방지합니다.
상태 판정 & 임계값
statusOf() 는 노드를 up / degraded / down 으로 판정합니다.
| 상태 | 조건 |
|---|---|
down |
수집 실패(ok=0) 또는 stale(마지막 샘플이 redis_stale_min 초과) |
degraded |
아래 사유 중 하나 이상 |
up |
사유 없음 |
degraded 사유와 임계값(Administration ▸ 운영 정책 infr_setting group=ops):
| 사유 | 조건 | 임계 키 | 기본값 |
|---|---|---|---|
| 메모리 수용 임박 | used_pct ≥ |
redis_mem_pct |
85 |
| 메모리 단편화 | frag_score ≥ |
redis_frag_ratio |
1.6 |
| 블록된 클라이언트 | blocked_clients ≥ |
redis_blocked |
1 |
| 복제 링크 끊김 | master_link_status = down |
— | — |
| RDB 저장 실패 | rdb_last_bgsave_status = err |
— | — |
적중률은 상태 축이 아닙니다. 세션 저장소는 신규 로그인·만료·로그아웃마다 miss 가 나 40~60% 적중률이 정상입니다(예: 44.75% 인 멀쩡한 세션 노드). 과거에는
redis_hit_rate_min(기본 50) 미만이면 degraded 로 오탐(false-red)했으나, 지금은 적중률을 카드 KPI·등급 게이지·edu popover 로 표시만 하고 노드를 빨갛게 칠하지 않습니다. 진짜 캐시 문제(메모리 포화·축출·단편화)는mem_saturation/fragmentation이 워크로드와 무관하게 잡습니다.
권한
- 읽기(이 화면) —
user_level ≥ 1(demo=1). Service 역할 영역은 최소 레벨 1 이며, 이 화면은 읽기 전용이라 쓰기·삭제 액션이 없습니다. - 수집기 등록/편집 — Administration ▸ Collectors 는
user_level ≥ 5(staff/admin).redis_vts수집기의redis_host노드와 비밀번호를 등록합니다. - 상태 임계값 변경 — Administration ▸ 운영 정책 은
user_level ≥ 5.
이 화면 자체에는 파괴적 작업이 없어 별도 감사 로그를 남기지 않습니다(수집기·정책 변경은 각 관리자 화면에서 감사).
문제해결 · FAQ
카드가 하나도 없어요("수집된 Redis 노드가 없습니다")
infr_redis_metric 에 최근 표본이 없는 경우입니다. (1) Administration ▸ Collectors 에서 redis_vts 수집기에 redis_host 노드를 등록했는지, (2) 대표 시스템에 infr_redis_vts_collector.cjs 가 pm2 로 돌고 있는지, (3) 대표 시스템에서 각 노드의 Redis 포트에 redis-cli 로 도달 가능한지 확인하세요.
노드가 "중단(stale)" 로 뜹니다
마지막 샘플이 redis_stale_min(기본 5분)보다 오래됐습니다. 대표 수집기 pm2 프로세스가 죽었거나 cron 주기가 멈춘 것입니다. pm2 list / pm2 logs infr-collector 로 점검하세요.
링 게이지 상한이 이상합니다 / 여유공간이 크게 나옵니다
maxmemory 를 설정하지 않은 노드는 가용 예산(budget) 을 상한으로 씁니다(총 RAM − DB 버퍼풀 − OS 예비 20%). 하드 상한을 원하면 Redis 에 maxmemory 를 설정하세요 — 그러면 그 값이 곧 상한이 됩니다.
키스페이스/세션 블록이 비어 있어요
per-db 상세(raw.keyspace)·세션 DB 지표는 확장된 수집기가 채웁니다. 구버전 수집기라면 재배포(total_system_memory·keyspace_keys·per-db raw 컬럼 멱등 추가) 후 표시됩니다. 미수집이면 섹션이 graceful 하게 숨습니다.
적중률이 낮은데 문제인가요?
세션 워크로드라면 아닙니다(위 경고 참조). 순수 캐시 용도인데 적중률이 낮다면 작업셋이 메모리에 상주하지 못하거나 TTL 이 너무 짧은 것일 수 있습니다 — Redis 튜닝 배우기의 적중률 항목을 참고하세요.
단편화 점수가 표시되지 않아요
used_memory 가 64MB 미만이면 단편화 비율이 고정 오버헤드에 지배돼 무의미하므로 점수·상태 판정에서 제외합니다.
관련 항목
- 데이터베이스 (Service ▸ Database) — 같은 서사(수용·처리량·스키마)를 MySQL 로 구현한 자매 화면
- Redis 튜닝 배우기 — slowlog·적중률·단편화·키스페이스·축출 개념 심화
- 수집기 (Administration ▸ Collectors) —
redis_vts수집기·노드 등록 - 운영 정책 (Administration ▸ Operations Policy) — Redis 상태 임계값·예비율 설정
- 서비스 개요 (Service ▸ Overview) — 세션 카드를 우선순위 보드에 배치
