#!/bin/bash # ============================================================ # GUARDiA SM | search_solr_sm.sh # 대상: Apache Solr (7.x / 8.x / 9.x) # 파라미터: SOLR_HOME=/opt/solr SOLR_HOST=localhost SOLR_PORT=8983 # SOLR_USER=solr SOLR_PASS=SolrRocks # QUERY_TIME_WARN=1000 # ============================================================ set -euo pipefail SOLR_HOME=${SOLR_HOME:-/opt/solr} SOLR_HOST=${SOLR_HOST:-localhost} SOLR_PORT=${SOLR_PORT:-8983} SOLR_USER=${SOLR_USER:-""} SOLR_PASS=${SOLR_PASS:-""} QUERY_TIME_WARN=${QUERY_TIME_WARN:-1000} SOLR_BASE="http://${SOLR_HOST}:${SOLR_PORT}" OK="[OK]"; WARN="[WARN]"; CRIT="[CRIT]" SEP="─────────────────────────────────────────" RESULT=0 _solr() { local URL="$1" local AUTH="" [ -n "$SOLR_USER" ] && AUTH="-u ${SOLR_USER}:${SOLR_PASS}" curl -sk --max-time 10 $AUTH "${SOLR_BASE}${URL}" 2>/dev/null } echo "======================================================" echo " GUARDiA SM 점검 | Apache Solr | $(hostname -s)" echo " 점검 시각: $(date '+%Y-%m-%d %H:%M:%S %Z')" echo "======================================================" # ── 1. 프로세스 ─────────────────────────────────────────── echo; echo "[$SEP] 1. Solr 프로세스" SOLR_PROC=$(pgrep -f "solr\|start.jar" 2>/dev/null | wc -l || echo 0) if [ "$SOLR_PROC" -gt 0 ]; then SOLR_PID=$(pgrep -f "solr" | head -1) echo " ${OK} Solr 실행 중 (PID: ${SOLR_PID})" RSS_MB=$(awk '/VmRSS/{print $2}' /proc/${SOLR_PID}/status 2>/dev/null | \ awk '{printf "%d", $1/1024}' || echo "N/A") echo " RSS 메모리: ${RSS_MB} MB" else echo " ${CRIT} Solr 프로세스 없음" RESULT=2 fi # ── 2. 포트 리스닝 ──────────────────────────────────────── echo; echo "[$SEP] 2. 포트 리스닝" ss -tlnp 2>/dev/null | grep -q ":${SOLR_PORT} " && \ echo " ${OK} 포트 ${SOLR_PORT} LISTEN" || \ { echo " ${CRIT} 포트 ${SOLR_PORT} LISTEN 없음"; RESULT=2; } # ── 3. 시스템 정보 ──────────────────────────────────────── echo; echo "[$SEP] 3. Solr 시스템 정보" if command -v curl &>/dev/null; then SYS=$(_solr "/solr/admin/info/system?wt=json") if [ -n "$SYS" ]; then SOLR_VER=$(echo "$SYS" | python3 -c \ "import sys,json; d=json.load(sys.stdin); print(d.get('lucene',{}).get('solr-spec-version','?'))" 2>/dev/null) UPTIME=$(echo "$SYS" | python3 -c \ "import sys,json; d=json.load(sys.stdin); ms=d.get('jvm',{}).get('jmx',{}).get('upTimeMS',0); \ h=ms//3600000; m=(ms%3600000)//60000; print(f'{h}h {m}m')" 2>/dev/null || echo "N/A") echo " ${OK} Solr 버전: ${SOLR_VER}, 가동 시간: ${UPTIME}" # JVM 힙 HEAP=$(echo "$SYS" | python3 -c \ "import sys,json; d=json.load(sys.stdin); jvm=d.get('jvm',{}).get('memory',{}).get('raw',{}); \ used=jvm.get('used',0)//1048576; max_=jvm.get('max',1)//1048576; \ pct=used*100//max_ if max_>0 else 0; print(f'used={used}MB max={max_}MB ({pct}%)')" 2>/dev/null) echo " JVM 힙: ${HEAP}" if echo "$HEAP" | grep -oP '\d+(?=%)' | awk '{exit !($1>=85)}'; then echo " ${WARN} JVM 힙 사용률 85% 초과" [ $RESULT -lt 1 ] && RESULT=1 fi else echo " ${CRIT} Solr 응답 없음" RESULT=2 fi fi # ── 4. 코어/컬렉션 상태 ───────────────────────────────── echo; echo "[$SEP] 4. 코어/컬렉션 상태" if command -v curl &>/dev/null; then CORES=$(_solr "/solr/admin/cores?wt=json&indexInfo=false") if [ -n "$CORES" ]; then CORE_LIST=$(echo "$CORES" | python3 -c " import sys, json d = json.load(sys.stdin) status = d.get('status', {}) for name, info in status.items(): sz = info.get('index', {}).get('sizeInBytes', 0) // 1048576 docs = info.get('index', {}).get('numDocs', 0) print(f' {name:20s} docs={docs:>10,d} size={sz}MB') " 2>/dev/null || echo " 파싱 실패") echo "$CORE_LIST" CORE_COUNT=$(echo "$CORES" | python3 -c \ "import sys,json; d=json.load(sys.stdin); print(len(d.get('status',{})))" 2>/dev/null) echo " 총 코어 수: ${CORE_COUNT}" fi fi # ── 5. 쿼리 성능 통계 ──────────────────────────────────── echo; echo "[$SEP] 5. 쿼리 성능 통계" if command -v curl &>/dev/null; then # 첫 번째 코어의 성능 지표 FIRST_CORE=$(echo "$CORES" 2>/dev/null | python3 -c \ "import sys,json; d=json.load(sys.stdin); print(list(d.get('status',{}).keys())[0])" 2>/dev/null || echo "") if [ -n "$FIRST_CORE" ]; then METRICS=$(_solr "/solr/${FIRST_CORE}/admin/mbeans?stats=true&cat=QUERYHANDLER&wt=json") AVG_TIME=$(echo "$METRICS" | python3 -c " import sys, json d = json.load(sys.stdin) beans = d.get('solr-mbeans', []) for i in range(0, len(beans), 2): if beans[i] == 'QUERYHANDLER': handlers = beans[i+1] if i+1 < len(beans) else {} for name, stats in handlers.items(): if '/select' in name: qs = stats.get('stats', {}) avg = qs.get('avgTimePerRequest', 0) rpc = qs.get('requests', 0) print(f' /select: requests={rpc} avg={avg:.1f}ms') " 2>/dev/null || echo " 쿼리 통계 없음") echo "$AVG_TIME" fi fi # ── 6. 로그 오류 ───────────────────────────────────────── echo; echo "[$SEP] 6. 로그 오류" for LOGDIR in "${SOLR_HOME}/server/logs" "${SOLR_HOME}/logs" "/var/log/solr"; do if [ -d "$LOGDIR" ]; then LOGFILE=$(ls -t "${LOGDIR}"/solr.log 2>/dev/null | head -1 || echo "") if [ -n "$LOGFILE" ] && [ -r "$LOGFILE" ]; then ERR=$(tail -1000 "$LOGFILE" | grep -cE "ERROR|WARN|Exception" || echo 0) echo " 최근 오류/경고: ${ERR}건 (${LOGFILE})" tail -1000 "$LOGFILE" | grep -E "ERROR|WARN" | tail -5 | sed 's/^/ /' || true fi break fi done # ── 요약 ───────────────────────────────────────────────── echo echo "======================================================" case $RESULT in 0) echo " 최종 결과: ${OK} Solr 정상" ;; 1) echo " 최종 결과: ${WARN} 주의 항목 있음" ;; 2) echo " 최종 결과: ${CRIT} 즉시 조치 필요" ;; esac echo " 점검 완료: $(date '+%Y-%m-%d %H:%M:%S')" echo "======================================================" exit $RESULT