Ubuntu에서 Lotion 설치해보기 Week6. curl과 Git을 설치한 뒤에도 앱이 열리지 않았던 기록 Ubuntu로 한 학기 살아보기 프로젝트를 하면서, 평소에 쓰던 Notion도 계속 사용하고 싶어졌다. Linux에서 사용할 방법을 찾다가 Lotion 이라는 프로젝트를 알게 됐다. 설치 중에는 curl 과 git 이 없어 두 번 막혔다. 필요한 도구를 설치하고 다시 진행했지만, 마지막에는 아이콘을 눌러도 앱이 열리지 않았다. 이번 글은 그 과정과 끝내 확인하지 못한 부분을 함께 정리한 기록이다. 앞부분의 명령은 당시 실습 기록이다. 현재 설치를 권하는 절차로 읽지 않도록 주의하자. 명령의 역할과 점검 방법은 설명을 보탰고, 지금도 설치 파일이 배포되는지는 마지막 절에서 따로 확인했다. 1. Lotion은 어떤 프로그램이었나 Lotion은 Notion을 Linux 데스크톱에서 사용할 수 있게 만든 비공식 클라이언트 다. 현재 프로젝트도 Electron 기반이라고 소개하며, Notion이 제작하거나 지원하는 앱이 아니라고 명시한다. Lotion 프로젝트 당시 보고서의 Lotion 로고. 아래쪽에도 UNOFFICIAL이라고 적혀 있다. 원래 보고서에서는 이를 “Notion native”라고 적었다. 하지만 그 표현만으로 Notion의 공식 Linux 앱이 설치됐다고 볼 수는 없다. 아래 명령 끝의 native 역시 당시 설치 스크립트에 넘겼던 인자다. 이 글에서는 실제 사용한 프로젝트 이름인 Lotion으로 구분한다. 2. 먼저 압축 도구를 준비했다 당시 안내를 따라 7-Zip 관련 패키지부터 설치했다. 아래 세 줄은 보고서에 남아 있는 명령을 그대로 옮겼다. sudo add-apt-repository universe Ubuntu의 패키지 저장소 구성 요소인 universe 를 활성화한다. 프로그램을 받는 출처를 설정하는 단계다. sudo 는 이 명령을 관리자 권한으로 실행한다. 저장소 추가 명령 sudo apt update 등록된 저장소에서 설치 가능한 패키지 정보 를 새로 받는다. 이 단계에서 설치된 프로그램 전체가 업그레이드되는 것은 아니다. APT 설명 sudo apt install p7zip-full p7zip-rar 7-Zip 도구와 RAR 형식 지원을 위한 패키지를 설치한다. 여기까지는 Lotion 자체를 설치한 것이 아니라 당시 안내에서 요구한 압축 도구를 준비한 것이다. 지금도 같은 패키지 이름과 순서가 필요한지는 현재 배포 방식에 맞춰 확인해야 한다. 7-Zip 패키지 설명 3. 설치 파일을 받으려는데 curl이 없었다 다음으로 GitHub에 있던 설치 스크립트를 내려받으려고 했다. setup.sh 는 설치 명령들이 담긴 셸 스크립트 파일이다. curl https://raw.githubusercontent.com/puneetsl/lotion/master/setup.sh > setup.sh curl 은 URL을 통해 데이터를 주고받는 도구다. 여기서는 해당 주소의 내용을 받아 출력한다. 뒤의 > setup.sh 는 그 출력을 현재 폴더의 파일에 저장한다. 이 한 줄의 역할은 스크립트 다운로드까지다. 스크립트를 실행하는 명령은 뒤에 따로 나온다. curl 설명 · Bash 출력 저장 > 는 같은 이름의 파일이 있으면 일반적인 설정에서 기존 내용을 비우고 새로 쓴다. 파일이 생겼다는 사실만으로 다운로드가 정상적으로 끝났다고 판단해서는 안 된다. 오류 출력과 실제 파일 내용을 함께 봐야 한다. 첫 시도에서는 아래 메시지가 나왔다. 원본 화면의 메시지: Command 'curl' not found, but can be installed with: Lotion의 다운로드 주소에 접속하기 전에, 내 환경에서 curl 명령을 찾지 못한 것이다. 당시에는 다음 명령으로 curl을 설치했다. sudo apt install curl APT를 통해 curl 패키지를 설치한다. 설치한 뒤 같은 다운로드 명령을 다시 실행했다. 당시 보고서의 후속 화면에는 전송 진행률과 2,952바이트를 받은 기록이 표시됐다. 다운로드 명령은 실행됐지만, 받은 파일의 내용이나 안전성을 검증한 기록은 없다. 4. 이번에는 설치 스크립트가 Git을 요구했다 다운로드 이후에는 아래 두 명령을 실행했다. 외부에서 받은 스크립트를 관리자 권한으로 실행한 당시 기록 이므로 그대로 따라 하기 전에 출처와 파일 내용을 확인해야 한다. 스크립트가 실행되면 시스템 파일이나 설정을 바꿀 수 있다. chmod +x setup.sh chmod 는 파일 권한을 바꾸는 명령이고, +x 는 실행 권한을 더한다. 이 명령 자체로 스크립트가 실행되지는 않는다. 실행 권한 설명 sudo ./setup.sh native 현재 폴더를 뜻하는 ./ 를 붙여 setup.sh 를 실행하고, native 라는 인자를 전달한다. sudo 가 있으므로 관리자 권한으로 실행된다. 파일을 내려받는 단계와 그 안의 명령을 실제로 수행하는 단계는 이렇게 나뉜다. 여기서 다음 메시지가 나왔다. 아래 문장은 당시 터미널 화면에서 그대로 옮겼다. Command git is required to run this script 이번에는 설치 스크립트가 실행되다가 필요한 git 명령을 확인하는 단계에서 막혔다. 앞의 curl 오류와 달리, 내려받은 스크립트가 자체적으로 요구한 도구가 부족했던 것이다. sudo apt install git Git을 설치하는 명령이다. curl은 이 과정에서 스크립트 파일을 받아오는 데 쓰였고, Git은 프로젝트의 저장소와 변경 이력을 다루는 도구다. 예를 들어 git clone 은 저장소를 로컬로 복제한다. 원본 화면으로 확인되는 것은 이 설치 스크립트가 Git을 필수로 요구했다는 데까지다. 실제로 어떤 저장소를 복제했는지는 별도 로그가 남아 있지 않다. Git 저장소 복제 설명 당시에는 Git을 설치한 뒤 설치 명령을 다시 실행했다. 보고서에는 설치가 완료됐다고 적었지만, 설치 완료 로그나 설치된 버전을 확인한 화면은 남겨 두지 못했다. 5. 아이콘이 생겨도 실행 확인은 남아 있었다 설치 후 아이콘을 눌렀을 때 오류 메시지가 나타났고, 앱이 열리지 않았다. 몇 번을 다시 눌러보고 시간이 지난 뒤에도 시도했지만 결과는 같았다. 결국 앱 실행에는 실패했고, 원인은 확인하지 못했다. 마지막 오류의 정확한 문구나 화면도 남아 있지 않다. 앞에서 해결한 curl·Git 문제를 마지막 실행 실패의 원인으로 연결할 근거는 없다. 당시에는 GitHub 안내가 오래돼 그사이에 다른 오류가 생긴 것 아닐까 생각했다. 가능성을 떠올린 정도였고, 버전이나 실행 로그를 비교해 확인하지는 못했다. 지금 기록을 보완한다면 확인할 것 아래는 당시 실행한 해결 과정이 아니라, 원인을 좁히기 위해 덧붙인 점검 순서다. 실패한 단계와 오류 전문 : 다운로드, 설치 스크립트, 앱 실행 중 어느 단계인지 나누고 오류 문장을 그대로 남긴다. 환경과 버전 : Ubuntu 버전, CPU 아키텍처, 설치 파일 이름과 Lotion 버전을 기록한다. 같은 증상처럼 보여도 실행 환경이 다를 수 있다. 아이콘과 실행 파일 : 아이콘에 연결된 실행 경로와 파일이 실제로 있는지 확인한다. 앱 실행 로그를 확보한 뒤 해당 버전의 알려진 문제와 비교한다. 6. 지금도 설치할 수 있을까 2026년 10월 7일 확인 기준, 같은 Lotion 프로젝트에서 Linux용 설치 파일을 배포하고 있다. 릴리스 목록에는 2026년 5월 26일 공개된 v1.6.0이 표시된다. 배포 파일에는 Ubuntu·Debian용 amd64·arm64 .deb 패키지, Linux용 x64·arm64 압축 파일, Fedora 계열용 RPM이 있다. Lotion 릴리스 · 전체 배포 파일 현재 README의 Ubuntu 안내는 .deb 파일을 받은 뒤 APT로 설치하는 방식이다. 예시 명령은 다음과 같다. 이 명령은 현재 문서의 안내를 소개한 것이며, 이번 글을 정리하면서 직접 실행한 결과는 아니다. sudo apt install ./lotion_1.6.0_amd64.deb 현재 폴더에 내려받은 .deb 파일을 APT로 설치한다. 파일명의 amd64 는 x86-64 계열용이라는 뜻이다. ARM64용 패키지는 lotion_1.6.0_arm64.deb 로 별도 배포된다. 프로젝트는 APT가 필요한 의존성을 처리한다고 안내한다. 다만 Ubuntu 버전별 검증표는 확인하지 못했고, 내 당시 환경에서 이 버전이 정상 실행되는지도 시험하지 않았다. README 따라서 지금 확인할 수 있는 답은 “현재 설치 파일과 설치 안내가 제공된다” 까지다. 과거의 setup.sh 절차를 그대로 재사용하거나, 당시 실행 실패가 최신 버전에서 해결됐다고 단정할 수는 없다. 비공식 앱의 코드는 로그인 세션과 화면을 다루므로, 사용 전에는 배포 출처와 변경 내역, 필요한 권한도 살펴봐야 한다. Notion은 왜 Linux를 공식 지원하지 않을까 실습을 하면서 이 점도 궁금했다. 당시에는 기술적인 부담이나 수익성 때문일 수 있다고 추측했지만, 이를 뒷받침하는 공식 근거를 확인한 것은 아니었다. 현재 Notion 도움말에서 확인되는 내용은 Linux 앱을 제공하지 않으며 브라우저에서 사용할 수 있다 는 안내다. 구체적인 사업적 이유까지는 이 문서로 알 수 없다. Notion의 Linux 지원 안내 마치며 이번 실습은 앱 실행 문제를 해결하지 못한 채 끝났다. 그래도 기록을 다시 나눠 보니 curl 오류는 파일을 받기 전, Git 오류는 설치 스크립트 실행 중, 마지막 문제는 앱을 열 때 발생했다는 차이가 보였다. 설치 명령을 끝까지 입력한 것과 실제로 사용할 수 있는 상태가 된 것은 각각 확인이 필요했다. 실패한 단계와 정확한 메시지를 남기는 일도 설치 과정만큼 중요하다는 점이 이번 기록에 남았다. 이어서 읽기 이전 글: Install R-Ubuntu
26.10.07 개인프로젝트 6일차 - 정답지 재검토 및 재채점 평가셋 정답지 재검토 및 재채점 앞선 실험에서는 RAG의 검색과 답변 생성을 개선하면서 여러 단계의 성능을 측정했다. 그런데 실험 결과를 다시 살펴보면서 한 가지 의문이 생겼다. 정말 모델이 틀린 것인지, 아니면 내가 만든 정답지와 채점 기준이 잘못된 것인지 구분할 필요가 있었다. 특히 일부 문항에서는 챗봇이 질문에 필요한 내용을 어느 정도 답했는데도, 정답지에서 질문에 직접 요구되지 않은 내용을 필수 조건으로 설정해 놓아 부분정답이나 오답으로 처리되는 경우가 있었다. 따라서 이번에는 모델을 추가로 개선하기 전에 평가셋 자체를 다시 검토 했다. 1. 정답지 검토 기준 문제가 있는 문항을 다음 세 가지로 나누어 검토했다. 1 정답지가 잘못된 경우 질문과 실제 공고 원문을 기준으로 봤을 때 기존 정답 기준이 질문보다 과하거나, 원문과 맞지 않는 경우이다. → 정답지를 수정한다. 2 정답지에는 문제가 없는 경우 질문이 요구하는 내용과 정답 기준이 적절한데, 챗봇이 필요한 내용을 제대로 답하지 못한 경우이다. → 모델의 검색 또는 답변 생성을 개선한다. 3 애매한 경우 질문의 표현이나 의도에 따라 답변 범위가 달라질 수 있는 경우이다. → 질문과 정답 기준을 다시 검토한다. 여기서 가장 중요한 원칙은 챗봇의 답변을 보고 정답지를 수정하지 않는 것 이다. 정답지는 질문과 실제 공고 원문을 기준으로 판단하고, 챗봇의 답변은 그 이후에 평가한다. 2. 문제가 발견된 문항 검토 과정에서 주요하게 확인한 문항은 A03, A04, A05, A09, A14, A16 이었다. A03. 쿤텍 신입은 무슨 언어 할 줄 알아? 기존 정답 기준에는 시스템 프로그래밍 이 포함되어 있었다. 하지만 질문은 "무슨 언어를 할 줄 알아야 하는가" 를 묻고 있었다. 따라서 질문에서 직접 요구하지 않은 시스템 프로그래밍 까지 반드시 언급해야 정답으로 인정하는 것은 질문의 범위를 넘어선다고 판단했다. 판단: 1 정답지 수정 수정 후에는 질문에서 요구하는 언어 관련 정보가 정확하게 답변되었는지 를 중심으로 평가한다. A04. 아인잡 프론트엔드 연봉 기존 평가에서는 연봉 질문에 스톡옵션 정보 를 필수 옵션으로 추가했었다. 하지만 연봉과 스톡옵션은 서로 다른 보상 항목이고, 질문에서 직접 요구한 것은 연봉이었다. 따라서 연봉 질문에 스톡옵션까지 필수적으로 요구하는 기존 기준은 적절하지 않다고 판단했다. 판단: 1 정답지 수정 기존: 연봉 + 스톡옵션을 함께 언급해야 함 수정: 연봉 정보를 정확하게 안내했는지를 평가 스톡옵션은 별도의 보상 정보로 분리한다. A05. Spring만 해 봤는데 지원해도 돼? 기존 기준에서는 Spring 경험을 바탕으로 Java/Kotlin까지 연결해서 판단하도록 요구하고 있었다. 하지만 질문 자체는 "Spring만 해 봤는데 지원해도 돼?" 라는 질문이다. 따라서 Java/Kotlin까지 반드시 언급해야 하는지는 질문의 해석에 따라 달라질 수 있었다. 판단: 3 애매한 경우 질문 자체가 어느 범위까지 답변을 요구하는지 먼저 검토할 필요가 있다고 판단했다. A09. 들어가면 무슨 일 해? 기존 정답 기준에는 EMR·CRM 백엔드 API 설계 및 비즈니스 로직 구현 이라는 표현이 사용되어 있었다. 이 때문에 답변에서 CRM이 따로 언급되지 않으면 일부 내용이 빠졌다고 판단했다. 하지만 챗봇의 답이 정답 내용이 맞는데 정답 기준에서 특정 표현을 묶어서 필수적으로 요구했기 때문에 틀리다고 나온 것을 확인할 수 있었다. 판단: 1 정답지 수정 수정 후에는 질문의 의도에 맞춰 공고에 실제로 명시된 주요 업무를 정확하게 설명했는지 를 중심으로 평가한다. A14. 재택·유연근무 되는 곳 있어? A14는 정답지보다는 채점 과정에서 문제가 발생한 경우 였다. 챗봇은 재택·유연근무가 가능한 6곳을 찾아냈지만, LLM 채점 과정에서 특정 공고를 경력 공고라고 잘못 판단하면서 오답으로 처리된 문제가 있었다. 즉, 답변이 틀린 것이 아니라 채점 과정에서 잘못 판단한 경우 였다. 판단: 1 정답지/채점 기준 수정 실제 공고 원문을 기준으로 판단하고, 채점자가 근거 없이 공고의 경력 여부를 추측하지 않도록 채점 기준을 수정했다. A16. 신입 백엔드 공고에서 공통으로 요구하는 게 뭐야? A16은 가장 복잡한 문항이었다. 모델은 여러 공고를 검색했지만 일부 공고만 중심적으로 비교하는 문제가 있었다. 반면 기존 정답지는 특정 공고들을 묶어 공통 요구사항을 분석하고, 다른 공고들은 성격이 다르기 때문에 제외하는 과정을 요구하고 있었다. 따라서 다음 두 가지를 나누어 볼 필요가 있었다. 정말 모델이 여러 공고를 제대로 종합하지 못한 것인가? 아니면 정답지가 질문보다 지나치게 복잡한 분석을 요구하고 있는가? 판단: 3 애매한 경우 질문과 원문을 기준으로 정답지가 요구하는 범위가 적절한지 먼저 검토하기로 했다. 3. 정답지 수정 후 기존 실험 전체 재채점 정답지가 수정되었다면 최근 실험만 다시 채점해서는 안 된다. 예를 들어 A04의 정답 기준이 변경되었다면, 기준선 ↓ 공고 전체 투입 ↓ 기술 동의어 ↓ 조건 코드 필터 ↓ 분류-본문 차이 ↓ 지시문 개선 ↓ 공고별 균등 검색 ↓ 최종 설정 각 실험 결과를 새로운 정답지 기준으로 다시 채점해야 한다. 그래야 정답지 변경으로 인한 점수 변화와 실제 모델 개선으로 인한 점수 변화를 구분할 수 있다. 4. 답변 정확도 v2 → v4 기존 채점 기준을 v2, 수정된 채점 기준을 v4로 두고 기존 실험 결과를 다시 채점했다. 실행 v2 v4 변화 0 기준선 (A) 64.0% 70.0% +6%p 0 기준선 (B) 66.0% 72.0% +6%p 1 공고 전체 투입 70.0% 78.0% +8%p 2 기술 동의어 76.0% 76.0% 0%p 3 조건 코드 필터 82.0% 86.0% +4%p 4-v1 분류-본문 82.0% 88.0% +6%p 4-v2 82.0% 88.0% +6%p 5-a 지시문 v2 88.0% 92.0% +4%p 5-b 80.0% 92.0% +12%p 6-a 공고별 균등 검색 84.0% 96.0% +12%p 6-b 86.0% 90.0% +4%p top_k=10 순수 검색 a 78.0% 82.0% +4%p top_k=10 순수 검색 b 68.0% 76.0% +8%p top_k=10 최종 a 82.0% 90.0% +8%p top_k=10 최종 b 86.0% 96.0% +10%p 이번 결과에서 가장 중요한 점은 위의 변화가 코드 수정으로 인한 성능 향상이 아니라는 것이다. 동일한 기존 실험 결과를 대상으로 수정된 정답지 기준으로 다시 채점했기 때문에 발생한 변화이다. 따라서 예를 들어 최종 설정이 86%에서 96%가 되었다고 해서 "모델 성능이 10%p 향상되었다." 라고 해석하면 안 된다. 이번 변화는 평가 기준을 바로잡은 결과이다. 5. 최종 설정의 재채점 결과 최종 설정의 경우 다음과 같이 변경되었다. 실행 기존 v2 수정 v4 6-a 공고별 균등 검색 84% 96% 6-b 86% 90% 동일 설정을 2회 실행한 결과의 평균을 비교하면, 기존 v2 평균: 85% 수정된 v4 평균: 93% 이다. 즉, 평가 기준을 수정한 뒤 동일한 결과를 다시 채점했을 때 평균 점수가 8%p 높아졌다. 하지만 이 8%p를 모델의 성능 향상으로 해석하지는 않았다. 이는 정답지 및 채점 기준의 수정으로 인한 평가 결과 변화이기 때문이다. 6. 문서에 없음 정확도 문서에 없음 유형에서도 일부 결과가 달라졌다. 실행 v2 v4 5-a 지시문 v2 80% 100% 6-a 공고별 균등 검색 80% 100% top_k=10 순수 검색 b 100% 80% 나머지 실행은 모두 100% → 100% 로 동일했다. 이번 변화 역시 모델의 성능 변화가 아니라 N01·N02 의 재채점 결과가 달라진 것으로 확인했다. 따라서 이 지표도 정답지 수정에 따른 변화와 실제 모델 개선을 구분해서 해석했다. 7. 정답지 수정과 관계없는 지표 이번 정답지 수정으로 다음 지표에는 변화가 없었다. 최신성 출처 정확도 근거 표시 정확도 검색 적중률 즉, 이번 작업은 검색 시스템 자체를 개선한 실험이 아니었다. 기존 실험 결과를 새로운 정답 기준으로 다시 평가하여 평가셋의 신뢰도를 높이는 과정이었다. 8. 이번 작업에서 알게 된 점 이번 검토를 통해 모든 오답을 단순히 "RAG가 검색을 못했다." 라고 판단하면 안 된다는 것을 확인했다. 평가 결과가 낮은 이유는 크게 다음과 같이 나눌 수 있었다. 평가 결과가 낮음 │ ├── 검색 문제 │ ├── 답변 생성 문제 │ ├── 정답지/채점 기준 문제 │ └── 질문 자체가 애매한 문제 특히 A03, A04, A09처럼 질문보다 정답 기준이 과했던 경우에는 모델을 개선하는 것만으로는 평가의 문제를 해결할 수 없다. 반대로 정답 기준이 적절한 문항에서 답변이 부족하다면 그때는 모델의 검색이나 답변 생성 방식을 개선해야 한다. 9. 이후 평가 기준은 고정 이번 검토를 통해 수정된 정답지를 확정하고, 이후 실험에서는 새로운 정답 기준을 고정해서 사용하기로 했다. 앞으로 성능을 높이기 위해 결과에 맞춰 정답지를 다시 변경하지 않고, 동일한 기준으로 평가한다. 최종 측정은 다음 순서로 진행한다. 평가셋 정답지 검토 ↓ 정답지 수정 ↓ 기존 실험 전체 재채점 ↓ 수정된 결과 확정 ↓ 평가 기준 고정 ↓ 코드 동결 ↓ 새로운 홀드아웃 문항 준비 ↓ 최종 측정 특히 최종 홀드아웃에서는 고치는 동안 한 번도 보지 않은 새로운 문항을 사용하고, 결과가 마음에 들지 않는다고 다시 고치거나 문항을 바꾸지 않고 그대로 실패 사례로 기록할 예정이다. 마무리 이번 작업의 목적은 단순히 정확도 숫자를 높이는 것이 아니었다. 오히려 기존 평가 결과를 다시 살펴보면서, 모델이 틀린 것인지, 정답지가 틀린 것인지, 아니면 질문 자체가 애매한 것인지를 구분하는 것이 목적이었다. 실제로 정답지를 다시 검토한 결과, 일부 문항에서는 질문에서 직접 요구하지 않은 내용을 정답 조건으로 포함하고 있거나 채점 과정에서 잘못 판단하는 문제가 있었다. 따라서 해당 문항을 수정하고 기존 실험 전체를 새로운 기준으로 다시 채점했다. 그 결과 최종 설정의 평균 점수도 기존 85%에서 93% 로 변경되었다. 하지만 이 변화는 모델을 개선해서 얻은 성능 향상이 아니라 평가 기준을 수정한 뒤 동일한 결과를 다시 채점하면서 발생한 변화이다. 이번 과정을 통해 RAG 프로젝트에서는 검색과 생성 모델을 개선하는 것뿐만 아니라, 무엇을 정답으로 볼 것인지에 대한 평가 기준을 제대로 설계하는 것도 중요하다는 것을 확인했다. 이제 수정된 정답지를 고정하고, 이후에는 평가 기준을 변경하지 않은 상태에서 코드 동결 → 홀드아웃 측정 → 최종 성능 평가를 진행할 예정이다.
28일 신고가 돌파 직후 10일간의 횡보, 그리고 -13% 8월 저점 대비 70% 오른 자리에서 들어간 돌파 매수가 단 하루의 급락으로 끝난 날의 기록. 요약 항목 값 총 거래 1건 승 / 패 0 / 1 총 P&L -7.07 USDT 총 수수료 -0.08 USDT 평균 P&L -7.07 USDT 승률 0% 포트폴리오 현황 항목 값 USDT 잔고 261.79 활성 포지션 AVAX(158), SHIB(0), APT(61), PEPE(0), ETHFI(42), MUBARAK(161), BROCCOLI714(53) 미실현 P&L +113.52 USDT 총 포트폴리오 736.96 USDT 거래 상세 1. DOTUSDT — SL (-) 항목 값 진입 2026-09-26 15:55:08 @ 1.287 청산 2026-10-07 02:01:17 @ 1.12 수량 41.91000000 매수 금액 53.94 USDT 매도 금액 46.94 USDT 수수료 -0.0757 USDT P&L -7.07 USDT (-13.12%) 보유 기간 10일 청산 유형 SL 진입 근거: 9월 7일 고점(약 1.29)으로 형성된 28일 Upper Channel을 9월 26일 상향 돌파, 시스템 룰에 따른 정상 진입. 8월 18일 저점 0.75 이후 MA7 > MA28 > MA90 정배열이 유지되던 구간으로, 추세 방향 자체는 상승과 일치. 다만 돌파 당일 볼륨은 9월 초 급등 때 대비 평범한 수준이었고, 돌파 폭도 직전 고점을 간신히 넘는 marginal break였음. 잘한 점 / 아쉬운 점: 잘한 점: 진입 다음 날부터 가격이 1.15~1.25 박스에 갇혀 10일간 재돌파 실패했음에도 SL 도달 전까지 임의 청산하지 않고 시스템을 신뢰함. 잘한 점: 10월 7일 장대 음봉이 SL 라인을 관통했지만 1.12 SL 가격에 체결되어 슬리피지 없이 손실을 제한함. 손실 금액은 포트폴리오의 약 1%로 2% 룰 내. 아쉬운 점: 저점 대비 70% 상승 후의 돌파였고, 직전 고점(9/7) 돌파 실패 이력이 있는 구간이라 Upper Channel이 저항으로 작동한 double-top 형태로 마무리됨. 아쉬운 점: 진입 후 한 번도 의미 있는 추가 상승이 없어 피라미딩 기회 자체가 없었음. 돌파 후 즉시 되밀리는 패턴은 추세 추종 관점에서 가장 비용이 큰 유형. 코인 소개: DOT 마켓 순위: #54 (CoinGecko) 카테고리: Smart Contract Platform, Polkadot Ecosystem, Proof of Stake (PoS), Layer 0 (L0), Pantera Capital Portfolio, GMCI 30 Index, GMCI Index, Made in USA, Coinbase 50 Index, Governance, Base Native Polkadot은 여러 체인(parachain)을 하나의 보안 계층 아래 연결하는 Layer 0 인터체인 플랫폼으로, 2026년 현재 Polkadot 2.0의 Agile Coretime 체제가 가동 중이며 Relay Chain을 대체하는 차세대 프로토콜 JAM(Join-Accumulate Machine)이 핵심 로드맵 네러티브. 2026년 3월 거버넌스를 통해 총 공급량 21억 개 hard cap과 인플레이션 53.6% 감축이 통과되어 토크노믹스가 크게 바뀐 점이 최근 가격 관심의 주요 배경. 시스템 업데이트 (해당 날짜 변경 없음) 일일 회고 오늘의 교훈 28일 신고가 돌파라도 직전 고점을 간신히 넘는 marginal break는 저항 재확인(double top)으로 끝날 확률이 높다. 돌파 폭과 볼륨은 시그널 강도의 핵심 변수. 돌파 후 10일간 진입가를 회복하지 못하는 포지션은 "추세가 아직 안 왔다"는 신호다. 이런 거래의 손실은 시스템이 당연히 지불해야 하는 비용이며, 터틀 방식에서 승률 0%인 날은 통계적으로 정상 범위. 잘한 점 SL 체결가가 설정가와 일치하여 급락장에서도 리스크 통제가 계획대로 작동함. 1회 손실이 포트폴리오의 약 1%로 2% 한도 내에 머물렀고, 미실현 +113 USDT의 다른 포지션들이 손실을 충분히 상쇄 중. 아쉬운 점 8월 저점 대비 70% 상승 후의 늦은 진입이었음에도 포지션 사이즈를 줄이는 장치가 없어 평범한 비중으로 늘어난 구간에 올라탐. 누적 P&L이 -393.5 USDT로 여전히 우하향 추세. 소액 승리는 잦지만 손실을 덮을 홈런급 거래가 부족한 구조가 이어지고 있음. 다음에 적용할 점 돌파 시그널의 품질 지표(직전 고점 대비 돌파 폭, 돌파 봉 볼륨 비율)를 백테스트로 검증하고, 유의미하면 진입 필터가 아닌 사이즈 조절 변수로 반영 검토. 보유 중인 7개 포지션의 미실현 수익을 TS로 끝까지 끌고 가는 데 집중. 손절은 계획대로 작동했으니 이제 수익을 길게 가져가는 쪽에서 기대값을 회복해야 함.
이번 실습에서는 ROS 2의 실행 인자 프로그래밍(Python)을 진행했다. argparse 를 이용해 실행 인자를 설정하고, checker 노드 실행 시 목표 합계값을 직접 전달하는 과정을 실습했다. 1. 실행 인자란? 실행 인자는 프로그램을 실행할 때 명령어와 함께 전달하는 값이다. 이전에 checker 노드를 실행하면서 다음과 같은 명령어를 사용했었다. ros2 run topic_service_action_rclpy_example checker -g 100 여기서 -g 100 이 실행 인자다. ros2 run ↓ checker 실행 ↓ -g 100 ↓ goal_total_sum = 100 PPT에서는 Parameter는 매개 변수, Argument는 실행 인자로 구분해서 설명하고 있다. 2. Python에서 실행 인자 처리 Python에서는 argparse 모듈을 이용해 실행 인자를 처리한다. 실행 인자를 처리하는 과정은 다음과 같다. 1. parser 만들기 ↓ 2. 인자 추가하기 ↓ 3. 인자 파싱하기 ↓ 4. args.xxx로 사용하기 checker/main.py 에서는 sys.argv[1:] 를 이용해 실행 인자를 전달받도록 작성되어 있다. def main(argv=sys.argv[1:]): 그리고 ArgumentParser 를 생성한다. parser = argparse.ArgumentParser( formatter_class=argparse.ArgumentDefaultsHelpFormatter) 3. 실행 인자 추가하기 -g 와 --goal_total_sum 을 실행 인자로 등록했다. parser.add_argument( '-g', '--goal_total_sum', type=int, default=50, help='Target goal value of total sum') 여기서 -g : 짧은 형태 --goal_total_sum : 긴 형태 type=int : 정수형으로 처리 default=50 : 기본값 50 help : 도움말에 표시할 설명 으로 설정되어 있다. 4. 실행 인자 파싱 등록한 실행 인자는 parse_args() 를 통해 분석한다. args = parser.parse_args() 그다음 args.goal_total_sum 을 이용해 실제 값을 사용할 수 있다. checker.send_goal_total_sum(args.goal_total_sum) 즉 실행 인자로 입력한 값이 Checker 의 Goal 값으로 전달된다. 전체적인 흐름은 다음과 같다. 실행 인자 입력 ↓ argparse ↓ parse_args() ↓ args.goal_total_sum ↓ send_goal_total_sum() 5. 기본값으로 실행 먼저 실행 인자를 입력하지 않고 checker 를 실행했다. ros2 run topic_service_action_rclpy_example checker 이 경우 별도의 -g 값을 입력하지 않았기 때문에 goal_total_sum 의 기본값인 50 이 사용된다. 6. -g 를 이용해 실행 이번에는 목표값을 100 으로 지정해서 실행했다. ros2 run topic_service_action_rclpy_example checker -g 100 -g 100 이 실행 인자로 전달되는 것을 확인했다. 즉, -g 100 ↓ args.goal_total_sum = 100 의 형태로 값이 전달된다. 7. -h 로 도움말 확인 실행 인자의 사용 방법을 확인하기 위해 -h 옵션도 사용했다. ros2 run topic_service_action_rclpy_example checker -h 실행 결과: usage: checker [-h] [-g GOAL_TOTAL_SUM] ... positional arguments: argv Pass arbitrary arguments to the executable options: -h, --help show this help message and exit -g GOAL_TOTAL_SUM, --goal_total_sum GOAL_TOTAL_SUM Target goal value of total sum (default: 50) -g 와 --goal_total_sum 을 사용할 수 있고, 기본값이 50 이라는 것을 확인할 수 있었다. 8. 긴 형태의 실행 인자 사용 짧은 형태인 -g 뿐만 아니라 긴 형태인 --goal_total_sum 도 사용할 수 있는지 확인했다. ros2 run topic_service_action_rclpy_example checker --goal_total_sum 100 실행 결과에서 Arithmetic action server is not available. 경고가 출력됐지만, 이는 실행 인자 오류가 아니라 당시 calculator 의 Action Server가 실행되고 있지 않았기 때문에 발생한 메시지였다. 실행 인자 자체는 정상적으로 인식되는 것을 확인했다. 9. 실행 인자가 실제로 사용되는 부분 확인 마지막으로 args.goal_total_sum 이 실제 코드에서 어디에 사용되는지 확인했다. checker.send_goal_total_sum(args.goal_total_sum) 즉 argparse 로 분석한 실행 인자를 send_goal_total_sum() 에 전달하고, 해당 값이 Action의 Goal 값으로 사용되는 구조다. 마무리 이번 실습을 통해 ROS 2 Python에서 실행 인자를 처리하는 방법을 확인했다. sys.argv[1:] 로 실행 인자 전달 argparse.ArgumentParser() 로 parser 생성 add_argument() 로 실행 인자 등록 parse_args() 로 실행 인자 분석 args.goal_total_sum 으로 값 사용 -g 100 으로 실행 인자 전달 --goal_total_sum 100 으로 긴 형태의 실행 인자 전달 -h 를 이용한 실행 인자 도움말 확인
『Real MySQL 8.0』 7장을 읽고, 핵심 개념을 쉽게 이해할 수 있도록 제 방식대로 정리한 글입니다. 📌 들어가기 전에 왜 데이터를 암호화할까? 개인정보, 결제 정보 같은 민감한 데이터 를 보호하기 위해서입니다. 서버의 디스크나 백업 파일이 유출되더라도, 암호화 키가 없으면 내용을 읽을 수 없게 만드는 것이 목적입니다. MySQL 8.0 암호화 대상 한눈에 보기 암호화 대상 설정 다루는 절 테이블(데이터 파일) ENCRYPTION = 'Y' 7.3 언두 로그 / 리두 로그 innodb_undo_log_encrypt , innodb_redo_log_encrypt 7.4 바이너리 로그 / 릴레이 로그 binlog_encryption 7.5 💡 테이블만 암호화하고 로그를 암호화하지 않으면, 로그 파일에 데이터가 평문으로 남을 수 있습니다. 그래서 실제로는 세 가지를 함께 고려해야 합니다. 7.1 MySQL 서버의 데이터 암호화 TDE (Transparent Data Encryption) MySQL의 데이터 암호화는 디스크에 쓰고 읽는 시점 에 동작합니다. [쓰기] 버퍼 풀 (평문) ──암호화──▶ 디스크 (암호문) [읽기] 디스크 (암호문) ──복호화──▶ 버퍼 풀 (평문) MySQL 서버의 다른 부분(쿼리 처리 등)은 데이터가 암호화됐는지 전혀 신경 쓰지 않습니다. 사용자 입장에서도 일반 테이블과 똑같이 사용합니다. 그래서 이 방식을 투명한 데이터 암호화(TDE, Transparent Data Encryption) 라고 부릅니다. 디스크에 저장된 상태의 데이터를 보호한다는 의미로 Data at Rest Encryption 이라고도 합니다. 에디션별 키 관리 방식 (키링 플러그인) 암호화 키는 키링(Keyring) 플러그인 을 통해 관리합니다. 에디션 사용 가능한 키링 커뮤니티 keyring_file (마스터 키를 디스크 파일 에 저장) 엔터프라이즈 keyring_file , keyring_encrypted_file , keyring_okv , keyring_aws 등 (외부 키 관리 서버 연동 가능) 7.1.1 2단계 키 관리 MySQL은 키를 두 단계 로 나눠서 관리합니다. ┌──────────── 키링 (외부 파일 / 키 관리 서버) ────────────┐ │ 🔑 마스터 키 (Master Key) │ └───────────────────────┬──────────────────────────┘ │ 테이블스페이스 키를 암호화 ▼ ┌──────────── 각 테이블 데이터 파일 헤더 ─────────────────┐ │ 🔐 테이블스페이스 키 (Tablespace Key) │ │ (마스터 키로 암호화된 상태로 저장) │ └───────────────────────┬──────────────────────────┘ │ 실제 데이터를 암호화 ▼ ┌──────────── 데이터 파일 ─────────────────────────────┐ │ 📄 암호화된 데이터 │ └──────────────────────────────────────────────────┘ 키 저장 위치 역할 마스터 키 키링(외부 파일 또는 키 관리 서버) 테이블스페이스 키를 암호화 테이블스페이스 키 각 테이블 데이터 파일의 헤더 (마스터 키로 암호화된 상태) 실제 데이터를 암호화 🧩 비유 테이블스페이스 키 = 각 방(테이블)의 문을 여는 열쇠 마스터 키 = 그 방 열쇠들을 넣어둔 금고의 열쇠 금고 열쇠(마스터 키)는 건물 밖(키링)에 따로 보관 왜 2단계로 나눌까? → 마스터 키 변경이 빠르다 보안 정책상 키는 주기적으로 변경 해야 합니다. ALTER INSTANCE ROTATE INNODB MASTER KEY; 마스터 키 변경 시 1. 새로운 마스터 키 발급 2. 모든 테이블스페이스 키를 기존 마스터 키로 복호화 3. 새 마스터 키로 다시 암호화해서 데이터 파일 헤더에 저장 → 데이터 파일 전체를 다시 암호화할 필요 없음 ✅ 키를 하나만 쓴다면 2단계 키를 쓴다면 키를 바꿀 때마다 모든 데이터 파일을 다시 암호화 → 매우 오래 걸림 테이블스페이스 키만 다시 암호화 → 빠름 💡 테이블스페이스 키는 MySQL 서버 외부로 노출되지 않기 때문에 따로 변경할 필요가 없습니다. 암호화 알고리즘 대상 알고리즘 테이블스페이스 키 암호화 AES 256비트 (ECB 모드) 실제 데이터 암호화 AES 256비트 (CBC 모드) 7.1.2 암호화와 성능 언제 암호화·복호화가 일어날까? 작업 시점 사용자 응답에 영향 복호화 디스크에서 읽어 버퍼 풀에 올릴 때 한 번 디스크에서 읽어야 하는 경우 약간 느려짐 암호화 더티 페이지를 디스크에 기록할 때 백그라운드 스레드가 처리하므로 거의 없음 버퍼 풀에 이미 있는 데이터 → 이미 복호화된 상태 → 추가 비용 없음 ✅ 버퍼 풀에 없는 데이터 → 디스크에서 읽으며 복호화 → 약간의 지연 💡 데이터 대부분이 버퍼 풀에 올라와 있는 서버라면, 암호화로 인한 성능 영향은 크지 않습니다. 책의 테스트에서도 페이지 하나를 읽고 쓰는 시간은 몇 배 늘어났지만, 마이크로초 단위 라 체감은 크지 않은 수준이었습니다. 암호화 + 압축을 함께 쓴다면? 1 압축 먼저 → 2 그 다음 암호화 이유 설명 압축 효율 암호화된 데이터는 랜덤한 바이트처럼 보여서 거의 압축되지 않음 → 압축을 먼저 해야 효과가 있음 버퍼 풀 활용 버퍼 풀에는 압축만 된(암호화되지 않은) 페이지 가 올라오므로, 버퍼 풀 안에서는 복호화가 필요 없음 7.1.3 암호화와 복제 소스 서버와 레플리카는 각자의 마스터 키를 가진다 ┌─── 소스 서버 ───┐ ┌─── 레플리카 ───┐ │ 🔑 마스터 키 A │ ──복제──▶ │ 🔑 마스터 키 B │ │ 데이터: 동일 │ │ 데이터: 동일 │ │ 파일 내용: 다름 │ │ 파일 내용: 다름 │ └───────────────┘ └───────────────┘ 복제 소스와 레플리카는 서로 다른 마스터 키 를 사용합니다. 그래서 데이터 내용은 같아도, 암호화된 데이터 파일 내용은 서로 다릅니다. ALTER INSTANCE ROTATE INNODB MASTER KEY 명령이 레플리카로 복제되더라도, 레플리카는 자기만의 새로운 마스터 키 를 생성합니다. ⚠️ 백업 시 주의 주의점 설명 키링 파일도 백업 키링 파일이 없으면 백업한 데이터를 복구할 수 없음 분리 보관 키링 파일을 데이터 백업과 같은 곳에 두면 암호화한 의미가 없음 → 별도로 안전하게 보관 💡 TDE를 사용한다면, 데이터 백업 + 키링 파일 백업 을 함께 관리해야 합니다. 7.2 keyring_file 플러그인 설치 keyring_file 플러그인이란? MySQL 커뮤니티 에디션에서 사용할 수 있는 키링 플러그인입니다. 마스터 키를 디스크의 파일 에 저장합니다. ⚠️ 마스터 키가 평문 파일 로 저장되기 때문에, 파일이 유출되면 암호화가 무의미해집니다. 파일 위치와 접근 권한을 철저히 관리해야 합니다. 설치 방법 키링 플러그인은 다른 플러그인보다 먼저 초기화되어야 하므로, early-plugin-load 옵션으로 설정합니다. # my.cnf [mysqld] early-plugin-load = keyring_file.so keyring_file_data = /very/secure/directory/tde_master.key 설정 설명 early-plugin-load MySQL 서버가 시작될 때 가장 먼저 로드할 플러그인 keyring_file_data 마스터 키를 저장할 파일 경로 💡 하나의 MySQL 서버에서 여러 인스턴스를 실행한다면, 인스턴스마다 다른 키링 파일 경로 를 지정해야 합니다. 설치 확인 SELECT PLUGIN_NAME, PLUGIN_STATUS FROM INFORMATION_SCHEMA.PLUGINS WHERE PLUGIN_NAME LIKE 'keyring%'; +--------------+---------------+ | PLUGIN_NAME | PLUGIN_STATUS | +--------------+---------------+ | keyring_file | ACTIVE | +--------------+---------------+ 서버를 시작하면 키링 파일이 빈 파일 로 생성됩니다. 실제 마스터 키는 암호화된 테이블을 처음 생성하거나 마스터 키를 로테이션할 때 만들어집니다. 💡 참고로 MySQL 8.0.24부터는 키링 플러그인 대신 컴포넌트 ( component_keyring_file ) 사용이 권장됩니다. 7.3 테이블 암호화 7.3.1 테이블 생성 암호화 테이블 생성 CREATE TABLE tab_encrypted ( id INT, data VARCHAR(100), PRIMARY KEY (id) ) ENCRYPTION = 'Y'; INSERT INTO tab_encrypted VALUES (1, 'test_data'); SELECT * FROM tab_encrypted; -- 일반 테이블과 똑같이 조회됨 💡 사용자 입장에서는 ENCRYPTION = 'Y' 옵션만 추가하면 되고, 사용 방법은 일반 테이블과 같습니다. 암호화된 테이블 확인 SELECT table_schema, table_name, create_options FROM information_schema.tables WHERE create_options LIKE '%ENCRYPTION="Y"%'; 모든 테이블을 기본으로 암호화하려면? SET GLOBAL default_table_encryption = ON; 이 설정을 켜면 ENCRYPTION 옵션을 지정하지 않아도 새로 생성하는 테이블이 자동으로 암호화 됩니다. 7.3.2 응용 프로그램 암호화와의 비교 암호화는 MySQL(TDE)에서 할 수도 있고, 애플리케이션에서 직접 할 수도 있습니다. [응용 프로그램 암호화] 애플리케이션: '1990' ──암호화──▶ 'xK9#mQ2...' ──저장──▶ MySQL → MySQL은 'xK9#mQ2...'가 무슨 값인지 모름 [TDE] 애플리케이션: '1990' ──저장──▶ MySQL ──디스크 기록 시 암호화──▶ 디스크 → MySQL 내부에서는 '1990'으로 인식 응용 프로그램 암호화의 문제점 애플리케이션에서 암호화한 값은 MySQL 입장에서 의미 없는 문자열 이기 때문에 이런 쿼리를 쓸 수 없습니다. -- birth_year 컬럼을 애플리케이션에서 암호화했다면 -- ❌ 범위 검색 불가 SELECT * FROM app_user WHERE birth_year BETWEEN 2000 AND 2010; -- ❌ 정렬 불가 SELECT * FROM app_user ORDER BY birth_year LIMIT 10; 문제 설명 범위 검색 불가 암호화된 값은 크기 비교가 의미 없음 정렬 불가 암호문 순서 ≠ 원래 값 순서 인덱스 활용 제한 범위 조건이나 정렬에 인덱스를 쓸 수 없음 비교 항목 응용 프로그램 암호화 TDE (MySQL 암호화) 암호화 위치 애플리케이션 MySQL 서버 (디스크 I/O 시점) 범위 검색 / 정렬 ❌ ✅ 인덱스 활용 제한적 일반 테이블과 동일 SQL로 조회 시 암호문 으로 보임 (DB 관리자도 내용을 모름) 평문 으로 보임 ✅ 정리 검색·정렬이 필요한 컬럼 → TDE DB 관리자에게도 노출되면 안 되는 민감한 컬럼(주민번호, 카드번호 등) → 응용 프로그램 암호화 보안 요구사항에 따라 두 가지를 함께 적용 할 수도 있습니다. 7.3.3 테이블스페이스 이동 테이블스페이스 이동이란? 테이블 데이터를 덤프해서 다시 넣는 대신, 데이터 파일( .ibd ) 자체를 복사 해서 다른 서버로 옮기는 기능입니다. 💡 데이터가 많을 때 mysqldump 로 덤프·적재하는 것보다 훨씬 빠릅니다. 일반 테이블 이동 과정 -- [원본 서버] FLUSH TABLES source_table FOR EXPORT; -- → source_table.cfg 파일 생성 (테이블 구조 정보) -- → .ibd, .cfg 파일 복사 UNLOCK TABLES; 암호화된 테이블이라면? 암호화된 테이블은 원본 서버의 마스터 키 로 테이블스페이스 키가 암호화되어 있습니다. 다른 서버는 그 마스터 키를 모르기 때문에, 파일만 복사하면 복호화할 수 없습니다. 그래서 FLUSH TABLES ... FOR EXPORT 실행 시 파일이 하나 더 생성됩니다. 파일 내용 .ibd 실제 데이터 파일 .cfg 테이블 구조 정보 .cfp 임시 마스터 키 로 암호화한 테이블스페이스 키 [원본 서버] FLUSH TABLES source_table FOR EXPORT; → 임시 마스터 키 생성 → 테이블스페이스 키를 임시 마스터 키로 암호화해서 .cfp 파일에 저장 → .ibd, .cfg, .cfp 파일 복사 UNLOCK TABLES; [대상 서버] ALTER TABLE target_table DISCARD TABLESPACE; → 복사한 .ibd, .cfg, .cfp 파일을 데이터 디렉터리에 배치 ALTER TABLE target_table IMPORT TABLESPACE; → .cfp 파일로 테이블스페이스 키를 복호화 → 대상 서버의 마스터 키로 다시 암호화해서 저장 ✅ ⚠️ .cfp 파일을 빠뜨리면 복구할 수 없습니다. 암호화된 테이블을 이동할 때는 반드시 .cfp 파일까지 함께 복사해야 합니다. 7.4 언두 로그 및 리두 로그 암호화 문제: 테이블만 암호화하면 로그는 평문 테이블 데이터 파일 → 암호화 ✅ 리두 로그 / 언두 로그 → 평문 ❌ ← 여기에 데이터 변경 내용이 그대로 남음 테이블을 암호화해도, 리두 로그와 언두 로그 에는 데이터 변경 내용이 평문으로 기록될 수 있습니다. MySQL 8.0.16부터 리두 로그와 언두 로그도 암호화할 수 있습니다. 설정 SET GLOBAL innodb_undo_log_encrypt = ON; SET GLOBAL innodb_redo_log_encrypt = ON; -- 설정 확인 SHOW GLOBAL VARIABLES LIKE 'innodb_%_log_encrypt'; 동작 방식 상황 결과 암호화를 켜면 켠 시점 이후 에 기록되는 로그만 암호화. 이전 로그는 평문 그대로 암호화를 끄면 이후 로그는 평문. 이미 암호화된 로그는 암호화된 상태 그대로 유지 ⚠️ 암호화를 껐더라도 이전에 암호화된 로그가 남아 있다면, 복구할 때 암호화 키가 여전히 필요 합니다. 키 관리 🔑 마스터 키 └─ 🔐 리두 로그 / 언두 로그 전용 프라이빗 키 (로그 파일 헤더에 암호화되어 저장) └─ 📄 리두 로그 / 언두 로그 데이터 암호화 리두 로그와 언두 로그는 테이블스페이스 키가 아니라, 각각의 프라이빗 키 로 암호화됩니다. 이 프라이빗 키는 마스터 키로 암호화 되어 로그 파일의 헤더 에 저장됩니다. 7.5 바이너리 로그 암호화 문제: 바이너리 로그도 평문 바이너리 로그에는 데이터 변경 내용이 그대로 기록됩니다. 바이너리 로그는 복제나 시점 복구(PITR)를 위해 오랫동안 보관 하는 경우가 많아서, 유출 위험도 큽니다. MySQL 8.0.14부터 바이너리 로그를 암호화할 수 있습니다. SET GLOBAL binlog_encryption = ON; 💡 바이너리 로그뿐 아니라 레플리카의 릴레이 로그 도 함께 암호화됩니다. 7.5.1 바이너리 로그 암호화 키 관리 바이너리 로그도 2단계 키 관리 방식을 사용합니다. ┌──────────── 키링 ────────────────────────────┐ │ 🔑 바이너리 로그 암호화 키 │ ← 테이블 암호화의 "마스터 키" 역할 └───────────────────┬─────────────────────────┘ │ 파일 키를 암호화 ▼ ┌──────────── 각 바이너리 로그 / 릴레이 로그 파일 헤더 ──┐ │ 🔐 파일 키 (File Key) │ ← 파일마다 하나씩 └───────────────────┬─────────────────────────┘ │ 실제 로그 데이터를 암호화 ▼ 📄 암호화된 바이너리 로그 키 비교 대상 역할 바이너리 로그 암호화 키 테이블 암호화의 마스터 키 파일 키를 암호화 파일 키 테이블 암호화의 테이블스페이스 키 바이너리 로그 파일마다 하나씩 생성되어 로그 데이터를 암호화 7.5.2 바이너리 로그 암호화 키 변경 ALTER INSTANCE ROTATE BINLOG MASTER KEY; 키 변경 과정 1. 새로운 바이너리 로그 암호화 키를 발급해서 키링 파일에 저장 2. 바이너리 로그 파일과 릴레이 로그 파일을 새 파일로 전환(로테이션) 3. 새로 생성되는 로그 파일의 파일 키는 새 암호화 키로 암호화 4. 기존 바이너리 로그·릴레이 로그 파일의 파일 키를 읽어서 새 암호화 키로 다시 암호화 (암호화되지 않은 로그 파일은 무시) 5. 모든 파일의 변환이 끝나면, 기존 바이너리 로그 암호화 키를 키링 파일에서 삭제 ⚠️ 4번은 보관 중인 바이너리 로그 파일이 많으면 시간이 오래 걸릴 수 있습니다. 대신 로그 데이터 전체가 아니라 파일 키만 다시 암호화 하므로, 2단계 키 관리 덕분에 그나마 빠르게 처리됩니다. 암호화 여부 확인 SHOW BINARY LOGS; +------------------+-----------+-----------+ | Log_name | File_size | Encrypted | +------------------+-----------+-----------+ | mysql-bin.000010 | 3047 | No | | mysql-bin.000011 | 512 | Yes | +------------------+-----------+-----------+ 7.5.3 mysqlbinlog 도구 활용 문제: 암호화된 바이너리 로그는 직접 열 수 없다 mysqlbinlog 는 바이너리 로그 내용을 확인하거나 시점 복구(PITR)를 할 때 많이 쓰는 도구입니다. 그런데 암호화된 바이너리 로그 파일을 직접 열면 에러가 발생 합니다. mysqlbinlog -vvv mysql-bin.000011 # → 파일이 암호화되어 있어서 읽을 수 없다는 에러 발생 ❌ 바이너리 로그 암호화 키는 MySQL 서버만 키링을 통해 접근할 수 있기 때문입니다. mysqlbinlog 는 키링에 직접 접근할 수 없습니다. 해결: MySQL 서버를 통해 읽기 mysqlbinlog -uroot -p -vvv --read-from-remote-server mysql-bin.000011 옵션 설명 --read-from-remote-server 파일을 직접 읽지 않고, MySQL 서버에 접속해서 바이너리 로그를 받아옴 mysqlbinlog ──요청──▶ MySQL 서버 (키링 접근 가능) │ 복호화 mysqlbinlog ◀──평문── MySQL 서버 💡 MySQL 서버가 바이너리 로그를 복호화해서 전달 하기 때문에 내용을 확인할 수 있습니다. ⚠️ 백업·복구 시 주의 백업해둔 암호화된 바이너리 로그를 나중에 사용하려면, 해당 키를 가진 MySQL 서버를 거쳐야 합니다. 그래서 바이너리 로그를 백업할 때는 키링 파일도 함께 백업 해야 합니다. ✍️ 마무리 정리 7.1 MySQL 서버의 데이터 암호화 TDE : 디스크에 쓸 때 암호화, 읽을 때 복호화. 사용자는 일반 테이블처럼 사용 2단계 키 관리 : 마스터 키(키링) → 테이블스페이스 키(데이터 파일 헤더) → 데이터 마스터 키 변경 시 테이블스페이스 키만 다시 암호화 하므로 빠름 버퍼 풀에 올라온 데이터는 복호화 상태 → 성능 영향은 크지 않음 압축과 함께 쓰면 압축 먼저, 암호화 나중 복제 소스와 레플리카는 각자의 마스터 키 사용, 키링 파일은 별도 백업 7.2 keyring_file 플러그인 설치 커뮤니티 에디션용, 마스터 키를 평문 파일 에 저장 → 파일 관리 주의 early-plugin-load 로 가장 먼저 로드 7.3 테이블 암호화 ENCRYPTION = 'Y' 로 생성, default_table_encryption 으로 기본값 설정 가능 응용 프로그램 암호화는 범위 검색·정렬 불가 , TDE는 제약 없음 암호화 테이블 이동 시 .cfp 파일 필수 7.4 언두 로그 및 리두 로그 암호화 innodb_undo_log_encrypt , innodb_redo_log_encrypt (8.0.16+) 켠 이후의 로그만 암호화, 끄더라도 기존 암호화 로그는 그대로 7.5 바이너리 로그 암호화 binlog_encryption (8.0.14+), 릴레이 로그도 함께 암호화 바이너리 로그 암호화 키 → 파일 키 → 로그 데이터 2단계
Warriors vs Northern Cape previews the 28th T20 match of the CSA T20 Challenge 2026, with both teams looking to strengthen their position in the competition. Warriors will aim to make the most of their batting depth and home conditions, while Northern Cape will look to counter with disciplined bowling and key contributions from their experienced players. With the match expected to feature an exciting contest between bat and ball, this Warriors vs Northern Cape Match Prediction covers the teams’ recent form, pitch conditions, predicted playing XIs and key players to watch before assessing who has the stronger chance of winning today’s match. Warriors vs Northern Cape, Match Details: Location: St George’s Park, Gqeberha, South Africa Venue: St George’s Park, Port Elizabeth Date & Time: 8th Oct/ 09:00 PM PST LOCAL Time Streaming: FanCode Establish: 1889 Capacity: 19,000 Owner: N/A Home Team: Sunrisers Eastern Cape End Name: Duckpond End & Park Drive End Flood Light: Yes Warriors vs Northern Cape Head-to-Head: Total Match: 0 Warriors: 0 Northern Cape: 0 No Result: 0 Tie: 0 Warriors vs Northern Cape Team Form: Warriors: NR, W, L, W, A Northern Cape: A, L, A, A, L Warriors vs Northern Cape Last Five Head-to-Head Matches: The teams haven’t faced each other till now. Warriors vs Northern Cape Weather Report: Temperature: 21° Humidity: 70% Wind Speed: 23 km/hr Cloud Cover: 5% Warriors vs Northern Cape Pitch Report: St George’s Park in Gqeberha generally offers a balanced T20 surface, with the new ball providing some assistance to pace bowlers while batters can score freely once they settle. Recent T20 data at the venue shows an average first-innings score of around 158, while the last five matches have produced an average of approximately 164, indicating that scoring conditions can improve for batters. Pacers have taken a larger share of wickets at the ground, although spinners can also play an important role as the innings progresses. Warriors vs Northern Cape Match Performance: Total Matches Played: 10 1st Batting Team Won: 4 2nd Batting Team Won: 6 No Result: 0 Average Batting Score: 134 Highest Score: 180/7 Lowest Score: 0/0 Pitch Report: Bowling Pitch Warriors Playing XI: Jean du Plessis, Jordan Hermann, Sibonelo Makhanya, Matthew De Villiers (C), Jp King, Patrick Kruger, Andile Mokgakane, Thomas Kaber, Beuran Hendricks, Wesley Bedja, Kerwin Mungroo Northern Cape Playing XI: Gerhardus Maree (C), Nonelela Yikha, Kyle Jacobs, Blake Simpson, Tahir Isaacs, Jordan Neill, Romano Terblanche, Ruan van Rooyen, Tshepo Ntuli, Johannes van Dyk, Odirile Modimokoane Injury and Availability: We will add any updates here. Warriors vs Northern Cape Match Prediction Tips: Who Will Win the Toss: Northern Cape Match Winner: Warriors Total Boundaries: 20+ Player Of The Match: Jordan Hermann 1st Innings Total: 180+ Most Wicket Taker: Matthew De Villiers Warriors vs Northern Cape Match Prediction: Warriors will win this match.
(출처: arXiv:2609.32993, Figure 2) X-Tree: Tokenizing Reusable Experience for Efficient Agent Generalization 저자 : Sitao Cheng, Xunjian Yin, Zhiyuan Sun, Yuxuan Li, Ruiwen Zhou, Xiangru Jian, Victor Zhong 소속 : University of Waterloo, Duke University, National University of Singapore 공개일 : 2026년 9월 26일 (arXiv v1, cs.AI) arXiv : https://arxiv.org/abs/2609.32993 코드 : https://github.com/sitaocheng/X-Tree · 프로젝트 페이지 : https://sitaocheng.github.io/xtree 분류 : LLM Agent / Reinforcement Learning / Skill Discovery / Experience Reuse 🔖 TL;DR (한눈에) 멀티스텝 에이전트 학습은 궤적(trajectory)을 평평한 액션 스트림 으로 소비한다. SFT와 RLVR은 모든 토큰에 같은 가중치를 주기 때문에, 과제마다 반복되는 하위 절차(sub-procedure)의 계층 구조를 전혀 활용하지 못한다 . 기존 에이전트 하네스는 이 구조를 쓰긴 하지만 LLM이 글로 써낸 스킬을 프롬프트에 넣는 방식 이라, 효과가 "검색해서 끼워넣기" 범위를 넘지 못하고 가중치에는 남지 않는다 . X-Tree는 LLM 호출 0회 로, 텍스트 토크나이저가 빈도만 세어 어휘를 만드는 것과 같은 방식으로 궤적에서 계층을 캐낸다. 액션을 verb⟨role⟩ 형태로 정규화한 뒤 재사용성 점수(X-Score) 로 인접 쌍을 BPE처럼 병합해 트리를 만든다. 각 노드는 "자주 등장하고 성공과 결부된 스킬이 하위 스킬로 어떻게 조립되는가"를 담고, 이를 데이터(오프라인 RL) · 보상(온라인 RLVR) · 컨텍스트(OPSD) 세 경로로 학습에 투입한다. WebArena·ScienceWorld·WebShop 3개 환경, 1.5B/3B/7B 3개 스케일에서 동일 데이터·동일 예산 조건으로 기존 레시피를 앞섰다(WebArena +4.5 SR, ScienceWorld +5.8 SR, WebShop +4.1 success). 특히 무작위 트리(17.9 SR)가 트리를 아예 안 쓴 경우(19.9 SR)보다 나빴다 — 성능이 "쪼개기" 자체가 아니라 구조의 질 에서 나온다는 증거. 한 줄 요약 : 에이전트 궤적 속에 암묵적으로 깔려 있던 "재사용 가능한 절차"를, LLM 없이 통계적 병합만으로 명시적 스킬 트리로 뽑아내고, 그 트리를 데이터·보상·컨텍스트 세 방향에서 모델 가중치에 심는 방법. 📄 초록(Abstract) 완역 멀티스텝 에이전트는 평평한 액션 스트림 위에서 학습된다. SFT와 RLVR은 모든 토큰에 균일한 가중치를 부여하며, 과제들에 걸쳐 반복적으로 나타나는 하위 절차들 — 즉 사람이 재사용 가능한 루틴으로부터 하향식(top-down)으로 계획을 세울 수 있게 해주는 그 계층 구조 — 을 무시한다. 이 구조는 쓰이지 않은 채 방치되고, 평평한 학습은 각각의 희소한 궤적을 그 내용이 허용하는 수준보다 덜 활용한다. 최근의 에이전트들은 그 구조를 실제로 사용하기는 하지만, 오직 LLM이 작성한 스킬을 컨텍스트에 넣는 형태로만 사용하며 가중치에는 결코 반영하지 않기 때문에, 그 이득이 검색(retrieval)의 범위를 넘어 일반화되지 않는다. 우리는 대신 이 계층 구조를 데이터 자체로부터 복원하여 그 위에서 학습하며, 이때 LLM 호출은 전혀 사용하지 않는다. 오직 세는 것만으로 어휘를 구축하는 텍스트 토크나이저를 따라, 우리는 액션 구간(span)들을 재사용성 기준으로 점수화하고 정규화된 액션들을 병합하여 재사용 가능한 경험 트리(reusable eXperience tree, X-Tree)를 만든다. 각 X-Tree 노드는 자주 등장하며 성공을 담지하는(success-bearing) 스킬이 하위 스킬들로부터 어떻게 구성되는지를 포착하여, 효율적인 일반화를 유도한다. 우리는 X-Tree를 세 가지 학습 설정에 통합한다: 각 노드를 하나의 학습 인스턴스로 쓰는 오프라인 RL, 적응적 스킬 보너스를 쓰는 온라인 RLVR, 그리고 X-Tree를 자기-교사(self-teacher)의 특권적 컨텍스트로 쓰는 온-폴리시 자기증류(on-policy self-distillation). WebArena, ScienceWorld, WebShop에서 세 가지 모델 스케일에 걸쳐, X-Tree는 동일한 데이터와 예산 조건에서 표준 레시피를 최대 WebArena 4.5% SR, ScienceWorld 5.8% SR, WebShop 4.1% success만큼 개선한다. 대조 분석들은 그 이득이 X-Tree의 구조와 세 가지 통합 방식에서 비롯됨을 보여준다. 요약 정리 : 저자들의 진단은 "데이터가 부족한 게 아니라, 있는 데이터를 평평하게 소비해서 덜 뽑아먹고 있다"는 것이다. 해법은 궤적에서 반복·성공 패턴을 통계적으로 병합해 스킬 계층(X-Tree)을 만드는 것. 핵심 차별점은 두 가지로, (1) 스킬 추출에 LLM을 쓰지 않아 결정론적이고 감사(audit) 가능하며, (2) 스킬을 프롬프트에 끼워넣는 데 그치지 않고 데이터·보상·컨텍스트 세 경로로 가중치에 학습시킨다 는 점이다. 🧩 왜 이 문제가 중요한가 (배경) 에이전트를 학습시킬 때 가장 비싼 자원은 GPU가 아니라 궤적 이다. 웹 환경에서 성공한 멀티스텝 궤적 하나를 얻으려면 긴 롤아웃과 검증이 필요하고, 사람이 라벨링하면 더 비싸다. 그런데 이 귀한 궤적을 학습에 넣는 방식은 지금까지 거의 한 가지였다. 액션을 토큰 시퀀스로 늘어놓고 SFT로 따라 하게 하거나, 에피소드 끝의 성공/실패 하나로 RLVR을 돌리는 것이다. 문제는 이 두 방식 모두 궤적을 구조 없는 긴 끈 으로 취급한다는 데 있다. 웹 에이전트가 쇼핑 사이트에서 "검색창에 질의를 입력하고 → 결과에서 상품을 고르고 → 옵션을 선택하고 → 구매"를 수행했다면, 이 네 단계는 과제가 바뀌어도 거의 그대로 재등장하는 덩어리 다. 사람은 이런 덩어리를 "루틴"으로 묶어 기억하고, 새 과제를 만나면 루틴 단위로 하향식 계획을 세운다. 반면 평평한 학습은 click 이라는 토큰 하나하나에 같은 무게를 둘 뿐, "이 네 개가 하나의 단위다"라는 사실을 모델에 알려주지 않는다. 이 지점이 바로 암묵지(tacit knowledge)의 데이터화 문제와 맞닿는다. 성공한 궤적 안에는 "이 환경에서 무엇이 통하는 절차인가"라는 지식이 이미 들어 있지만, 그것은 액션 나열 속에 암묵적으로 흩어져 있다. 명시적으로 꺼내 쓰려면 누군가 구조화해야 한다. 최근 연구들(AWM, Voyager, SkillWeaver 등)의 답은 "LLM에게 궤적을 읽히고 스킬을 글로 쓰게 하라"였다. 이 방식은 작동하지만 세 가지 비용을 치른다. 첫째, 스킬 추출 단계마다 LLM 호출 비용 이 든다. 둘째, LLM이 써낸 스킬 설명은 비결정론적이고 검증하기 어렵다 . 셋째, 그리고 가장 중요하게, 그 스킬은 추론 시점에 프롬프트로 검색해 넣어야만 효과가 있다. 모델 가중치는 스킬을 배우지 못했으므로, 검색이 실패하거나 컨텍스트에서 빠지면 이득도 사라진다. X-Tree는 이 세 비용을 동시에 공격한다. "LLM에게 요약을 시키지 말고, 토크나이저처럼 세기만 하라"는 것이 출발점이다. BPE가 코퍼스에서 자주 붙어 나오는 문자 쌍을 병합해 서브워드 어휘를 만드는 것처럼, 자주 붙어 나오고 성공과 결부된 액션 쌍을 병합해 스킬 어휘를 만든다. 그리고 그 어휘를 프롬프트가 아니라 학습 신호 로 쓴다. 🔬 방법론 X-Tree는 크게 두 부분이다. 궤적 풀에서 트리를 캐내는 마이닝 단계 , 그리고 그 트리를 학습에 투입하는 세 가지 통합 방식 이다. (출처: arXiv:2609.32993, Figure 1) 1단계: 액션 정규화 (Canonicalization) 원시 액션을 그대로 세면 아무것도 반복되지 않는다. click(element_id=4821) 과 click(element_id=7733) 은 문자열로는 다른 액션이지만, 추상 수준에서는 둘 다 "링크를 클릭했다"다. 그래서 각 액션을 verb⟨role⟩ 형태의 타입 토큰으로 바꾼다. verb : 액션의 함수 이름에서 가져온다. role : 그 verb가 작용하는 대상의 클래스. WebArena에서는 접근성 트리(accessibility tree)의 role을, ScienceWorld에서는 9개 객체 클래스 어휘(door, instrument, paint, container, device, plant, animal, substance, location)를 쓴다. slot : element ID, 입력한 텍스트, 옵션 값 같은 구체적 값은 심볼에서 제거하되 따로 저장한다 . 그래서 마이닝이 끝난 뒤에도 원래 값을 복원할 수 있다. 에이전트의 thought는 아예 제외한다. 예를 들어 WebArena에서 fill 과 type 은 모두 type 으로, goto / go_back / go_forward 는 모두 navigate 로 접힌다. 중요한 점은 이 매핑이 환경별로 액션 스페이스를 보고 한 번 작성하는 고정 템플릿 이라는 것이다. 학습도, LLM 호출도 없다. 2단계: X-Score로 병합 (Eq. 1) 인접한 두 심볼 u, v (각각 원시 액션이거나 이전 병합으로 만들어진 노드)에 대해 병합 후보 uv 의 점수를 이렇게 매긴다. X(u, v) = f_uv · (l_u + l_v)^{p_l} · (succ(uv) + ε)^{p_s} 세 항의 직관은 각각 반복성 · 길이 · 성공 이다. f_uv : 코퍼스 전체에서 (u,v) 가 인접해 등장한 횟수 → 자주 쓰이는 쌍일수록 높다. l_u + l_v : 후보가 펼쳐지는 원시 액션 개수(원시 액션은 l=1) → 긴 덩어리를 선호한다. succ(uv) : 그 f_uv 번의 등장 중 성공한 에피소드에 속한 비율 → 성공과 결부된 패턴을 선호한다. p_l , p_s : 길이와 성공의 가중 지수. 주요 3개 환경에서 p_l = 1, p_s = 1 , MiniWoB++에서는 p_s = 1.5 . ε = 0.001 . 이 공식의 효과는 명확하다. 길고 믿을 만하며 반복되는 쌍이, 자주 나오지만 짧거나 실패와 얽힌 쌍을 이긴다. 단순 빈도 기반 BPE와 결정적으로 다른 지점이 바로 succ 항이다. 여기에 압축 제약 이 붙는다. f_uv − 1 > η · (l_u + l_v) 병합은 코퍼스에서 f_uv − 1 개의 심볼 등장을 없애는 대신 길이 l_u + l_v 의 어휘 항목 하나를 추가한다. η 는 그 항목의 비용을 정한다. 이 제약이 없으면 코퍼스가 소수의 거대한 심볼로 붕괴한다. 3단계: 트리 구축 초기화 — 각 궤적을 정규화된 원시 액션 시퀀스로 두고, 원시 액션을 리프로 삼는다. 카운트 — 현재 코퍼스에서 모든 인접 쌍의 f_uv , 길이, succ 를 센다. 필터 — 압축 제약과 함께 빈도( f_min ), 길이( L_max ), 성공률( s_min ), 과제 유형 수( T_min ) 필터를 통과한 후보만 남긴다. 선택 — X-Score가 가장 높은 후보를 고른다. 병합 — 노드 v = uv 를 만들고 자식을 (u, v) 로 기록한 뒤, 코퍼스의 해당 인접 등장들을 v 로 치환한다. 노드는 길이 l_v , 깊이 d_v , 등장 횟수, 성공률을 함께 들고 있다. 후보가 없거나 스킬 상한 K 에 도달하면 멈춘다. 그렇지 않으면 2번으로. 깊이는 조립 트리의 높이 다. 리프는 d=0 이고, 내부 노드는 d_v = 1 + max(자식들의 깊이) . 트리를 궤적에 적용할 때는 가장 큰 노드로 궤적을 타일링(tiling) 하고, 어떤 스킬에도 덮이지 않은 위치는 원시 토큰으로 남긴다. 이 타일링이 세 가지 통합 방식 모두가 쓰는 단위다. 환경별 마이닝 하이퍼파라미터는 다음과 같다. 기호 의미 WebArena ScienceWorld WebShop η 압축 비용 0.3 0.5 0.5 K 스킬 상한 256 80 60 L_max 최대 스킬 길이(액션) 12 8 8 f_min 최소 쌍 빈도 4 5 5 s_min 최소 스킬 성공률 0 0.9 0 T_min 스킬당 최소 과제 유형 수 1 2 1 실제로 캐낸 트리의 규모는 이렇다. 벤치마크 마이닝 궤적 수 원시 액션 타입 수 캐낸 스킬 수 WebArena 7,974 139 256 (상한 도달) ScienceWorld 1,673 84 80 (상한 도달) WebShop 1,824 17 48 (압축 제약에 걸림) WebArena 학습에 쓰인 노드 집합은 총 5,148개 로, 깊이 1이 약 3.5k, 깊이 2가 1.2k, 깊이 3이 0.4k다. ScienceWorld에서는 깊이 6까지 나타난다. (출처: arXiv:2609.32993, Figure 5) 위 그림이 이 방법의 정체를 가장 잘 보여준다. ScienceWorld의 "침실에서 미지의 물질 B의 온도를 측정해 50도 이상이면 초록 상자, 미만이면 파란 상자에 넣어라"라는 과제에서, 18개 액션이 4개의 X-Tree 노드와 2개의 원시 액션, 즉 6개 토큰으로 압축된다. 그중 S2(보라색)는 서로 다른 두 토큰 안에 중첩되어 재등장한다. 통합 1: 오프라인 RL (데이터로서의 X-Tree) 궤적의 위치 t 에 있는 각 X-Tree 노드 v 가 하나의 RL 인스턴스 가 된다. 정책은 정답 접두사 s_<t 를 조건으로 받아 최대 l_v 스텝을 생성한다. 각 스텝 j 에서 정답 액션과 대상 요소를 모두 맞추면 match_j = 1 이고, 첫 불일치에서 롤아웃을 중단 한다. 맞춘 스텝에 대해서는 기록된 정답 관측(observation)을 붙여준다 — 그래서 롤아웃이 존재하지 않는 관측을 상상하지 않는다(오프라인 안전성). 보상은 c_v = ∏_j match_j (모든 스텝을 맞췄을 때만 1)로 두고, r = (1 − α) · (1/l_v) Σ_j match_j + α · (1 + γ·d_v) · c_v α = 0.3 , γ = 0.5 . 첫 항은 정답 경로를 따라가는 데 주는 조밀한 크레딧 , 둘째 항은 깊이 d_v 에 비례하는 완주 보너스 다. 깊은 노드를 끝까지 맞추는 것이 더 큰 보상을 받는다는 점이 "계층적 보상"의 실체다. 통합 2: 온라인 RLVR (보상으로서의 X-Tree) 그룹 g 안의 롤아웃 τ_i 에 대해, r_i = R_out(τ_i) + λ_g · Σ_{v ∈ matched(τ_i)} b_v λ_g = λ0 · clip(1 − w_g / w_ref, 0, 1) w_g 는 그룹에서 성공한 롤아웃의 비율이다. 이 설계의 핵심은 스스로 사라지는(self-fading) 보너스 라는 점이다. 아무 롤아웃도 성공하지 못했을 때 보너스는 최대 강도 λ0 이고, 그룹 성공률이 w_ref 에 도달하면 0으로 떨어진다. 즉 검증자의 결과 신호가 쓸모 있어지는 순간 정확히 그 시점에 shaping 항이 사라진다 . 시간 기반 스케줄이 아니라 성공률 기반이라는 점이 중요하다. 실제로 측정된 후반 학습 노출도는 n=2에서 0.50, n=16에서 0.18~0.26으로 떨어진다. 노드 보너스 b_v 는 ScienceWorld에서 1 + 0.5·d_v (에피소드당 1회), WebShop에서 10 · s_v · k_v / T 다. 중첩 매치에서는 외부 노드가 자신의 b_v 에서 내부에 이미 지급된 최대 보너스를 뺀 값 을 받아, 스킬과 하위 스킬의 이중 계산을 막는다. 통합 3: 온-폴리시 자기증류 OPSD (컨텍스트로서의 X-Tree) 학생과 교사가 같은 가중치 다. 차이는 프롬프트뿐으로, 교사는 검색된 X-Tree 스킬이 앞에 붙은 특권적 컨텍스트 를 본다. 둘이 같은 샘플 응답 y 를 채점하므로 로그확률이 위치별로 정렬된다. δ_t = log π_θ̄(y_t | s^tea) − log π_θ(y_t | s^stu) g_t = σ(β · δ_t) L = L_GRPO(R_out) + c · (1/|y|) Σ_t g_t (log π_θ̄(y_t | s^tea) − log π_θ(y_t | s^stu)) 게이트 g_t 는 교사가 더 확신하는 토큰에서 1에 가깝고, 학생이 이미 잘 아는 토큰에서 0에 가깝다. c = 0.01 , ScienceWorld는 β = 5 , WebShop은 β = 0 (게이트가 상수 0.5, 즉 균일 증류). 이 설정이 영리한 이유는 완전히 공정한 비교 를 가능하게 하기 때문이다. 자기-교사가 읽는 스킬 뱅크만 바꾼다. LLM이 쓴 뱅크(ScienceWorld는 gpt-oss-120b, WebShop은 GPT-o3)냐, 렌더링된 X-Tree냐. 다른 모든 것은 동일하다. 📊 실험 결과 WebArena: 오프라인 RL (Qwen2.5-7B, 694개 결정론적 과제, 30스텝 상한, 3패스 평균) Method gitlab (187) shopping (158) admin (156) reddit (112) map (67) wiki (14) All (694) Qwen2.5-7B-Instruct (base) 6.4 7.8 7.7 2.4 9.0 2.4 6.5 Go-Browse (SFT-Full, 2 epochs) 16.8 21.7 22.9 16.4 10.4 7.1 18.4 SFT-Full, 4 epochs (compute 매칭) 17.5 19.4 24.4 16.1 13.4 11.9 18.8 Offline RL w/ Outcome reward 15.5 23.4 23.1 15.2 7.5 14.3 18.2 Offline RL w/ Random span 18.4 20.9 26.6 14.7 11.9 14.3 19.5 X-Tree, Plain mixing (all depths) 16.1 24.5 25.4 19.9 14.4 23.8 20.7 X-Tree, Curriculum (d=1→2) 17.8 21.5 28.6 20.8 12.4 23.8 21.2 X-Tree Full 22.0 26.6 29.3 18.8 10.4 14.3 22.9 전체 SR 22.9는 SFT-Full(2 epochs) 18.4 대비 +4.5 다. 사이트별로 보면 gitlab(16.8→22.0)과 admin(22.9→29.3)처럼 양식 입력과 메뉴 탐색이 반복되는 곳에서 이득이 크고, map(10.4→10.4)과 wiki(7.1→14.3, 다만 과제가 14개뿐)처럼 반복 구조가 약한 곳에서는 이득이 없거나 노이즈 수준이다. 재사용 가능한 절차가 실제로 존재하는 사이트에서만 작동한다 는 해석이 자연스럽다. 어블레이션: 이득은 어디서 오는가 Method SR Δ X-Tree Full 22.9 – 트리 구조 검증 Whole trajectory (트리 없음) 19.9 −3.0 Random span 19.5 −3.4 Random tree 17.9 −5.0 오프라인 RL 설계 검증 X-Tree Plain mixing 20.7 −2.2 X-Tree Curriculum (d=1→2) 21.2 −1.7 Binary outcome reward 18.2 −4.7 SFT-Full, 2 epochs 18.4 −4.5 SFT-Full, 4 epochs 18.8 −4.1 이 표에서 가장 의미 있는 숫자는 Random tree 17.9 다. 무작위로 만든 트리는 트리를 아예 쓰지 않은 경우(19.9)보다도 2.0 포인트 나쁘다 . 궤적을 잘게 쪼개 학습 인스턴스 수를 늘리는 것 자체는 효과가 없고, 오히려 해로울 수 있다는 뜻이다. 성능은 X-Score가 고른 구조의 질 에서 나온다. 참고로 무작위 트리는 노드의 88%가 길이 2인 반면, 캐낸 트리는 43%만 길이 2다. 온라인 RLVR: 롤아웃 수에 따른 스케일링 (ScienceWorld, 1.5B) n Setting G0 (seen) G1 (unseen variation) G2 (unseen task) 2 outcome-only 12.9 13.7 11.8 2 + X-Tree bonus 14.6 15.5 13.0 4 outcome-only 24.2 23.9 12.1 4 + X-Tree bonus 28.0 27.5 16.5 8 outcome-only 38.6 36.2 22.8 8 + X-Tree bonus 39.8 39.5 25.6 16 outcome-only 47.5 49.0 26.6 16 + X-Tr
시스템 보안 · 취약점 › G. 내부 확장 · 측면 이동 징후 · 49/50편 (전체 349/450) 학습 단계: 실전 시나리오·종합 실습 표기: 이 글의 명령어·출력·로그는 로컬 VMware 테스트 VM(Rocky Linux 9 / Ubuntu 22.04) 기준의 「실습 예시」 이며, IP·계정·호스트명은 가상의 값입니다. 선행 학습 348. 내부 확장·측면 이동 — 내부 확장·측면 이동 탐지 규칙 모음 340. 침투→확장→목표 연계 분석 1. 개념 G영역에서 배운 탐지·분석·대응을 하나의 실전 시나리오 로 종합합니다. 외부 웹 침투부터 내부 확산, 핵심 자산(DB 마스터) 장악, 유출 시도까지의 전 과정을 SOC 관점에서 탐지·조사·차단하는 흐름을 연습합니다. 실전 시나리오: 침투 → 핵심 자산 장악 1. 침투: 웹 취약점으로 web01 장악 2. 정찰: 내부 스캔·열거(G29·G30) 3. 인증 이동: SSH 키 재사용으로 db01(G10) 4. 상승·수집: 권한 상승·자격 수집(G36·G32) 5. 확산: db01→app01→dbmaster(G33·G35) 6. 목표: dbmaster 데이터 수집·유출(G37) ← 각 단계에서 탐지·차단 기회 이 시나리오는 가상의 예시이며, 각 단계마다 어떤 신호가 발생하고 어떻게 탐지·대응하는지를 종합합니다. 2. 왜 중요한가 실전 시나리오는 개별 탐지 지식을 하나의 사건 흐름으로 통합합니다. 각 단계마다 탐지·차단 기회가 있어, 다층 방어의 가치를 보여줍니다. 조기 단계(정찰·초기 이동) 탐지가 피해를 최소화함을 확인합니다. 3. 핵심 명령어 / 설정 단계 신호 탐지 룰 침투 웹 이상·웹셸 웹 로그 정찰 스캔·열거 106280·106290 인증 이동 키 재사용 106080 상승·수집 sudo·자격 수집 106350·106310 목표 핵심 자산·유출 106330·106360 4. 실습 (실습 예시) # 실전 시나리오 탐지 흐름 (분석 방법) # 단계별 신호를 시간순 종합 조회(타임라인) sudo ausearch -k lateral,recon,privesc,exfil -i --start recent 2>/dev/null | grep -E 'nmap|id_rsa|sudo|dbmaster|mysqldump' | sort # 확산 경로·허브 식별 sudo ausearch -k lateral -i --start recent 2>/dev/null | grep -oE 'srcip=10\.[0-9.]+.*addr=10\.[0-9.]+' | sort | uniq -c 5. 정상 상태 $ (단계별 신호) (평시 — 각 단계 신호 없음, 정상 운영) 평시에는 정찰·이동·상승·유출 신호가 없고, 단계가 연쇄되지 않는 정상 운영 상태입니다. 6. 이상 상태 $ (단계별 신호 — 시나리오 진행) 09:00 web01 웹셸(침투) 09:05 web01 nmap(정찰, 106280) 09:12 web01→db01 SSH 키 재사용(이동, 106080) 09:15 db01 sudo 상승(106350) + id_rsa 수집(106310) 09:20 db01→app01→dbmaster(확산, 106340) 09:25 dbmaster mysqldump → 외부 유출(106360) → 각 단계 탐지 룰 발동, 상관으로 캠페인 경보(106430) 각 공격 단계가 대응 탐지 룰을 발동 → 다층 탐지 상관 룰(106430)이 캠페인으로 묶어 경보 조기 단계(정찰·초기 이동) 차단 시 핵심 자산 보호 가능 7. 로그 분석 (분석 방법) 실전 시나리오 탐지·대응 흐름입니다(가상의 예시). [침투] web01 웹셸 ↓ 탐지: 웹 로그 이상 [정찰] nmap 스캔(106280) ← 차단 기회 1 ↓ [이동] SSH 키 재사용 db01(106080) ← 차단 기회 2 ↓ [상승·수집] sudo(106350)+키 수집(106310) ← 차단 기회 3 ↓ [확산] db01→app01→dbmaster(106340) ← 차단 기회 4 ↓ [목표] mysqldump→유출(106360) ← 마지막 기회 ↓ 상관 캠페인 경보(106430) → 대응 플레이북(G47) = 다층 탐지로 어느 단계든 차단 가능 차단 기회 효과 정찰 단계 피해 없음 이동 단계 확산 전 차단 확산 단계 핵심 자산 보호 목표 단계 유출 저지 조기 단계 탐지일수록 피해가 작음을 보여줍니다. 8. SOC 관제 포인트 실전 시나리오는 침투→정찰→이동→상승·수집→확산→목표 의 전 과정을 종합합니다. 각 단계마다 탐지 룰이 발동하고 상관으로 캠페인 경보가 나는 다층 방어를 확인합니다. 조기 단계(정찰·초기 이동) 탐지가 핵심 자산 보호와 피해 최소화의 열쇠입니다. 9. 탐지 규칙 <!-- 실습 예시 룰: 적용 전 wazuh-logtest 및 테스트 환경 검증 필요 --> <group name="local,syssec_g,lateral,scenario,"> <rule id="106480" level="15" frequency="4" timeframe="1800"> <if_matched_group>lateral</if_matched_group> <same_field>audit.srcip</same_field> <description>침투-정찰-이동-확산-목표 전 단계 연쇄(실전 캠페인)</description> <mitre><id>T1190</id><id>T1021</id><id>T1041</id></mitre> </rule> </group> 단계별 룰과 상관 룰을 종합해 전 과정을 추적합니다. 조기 단계 경보에 신속 대응하면 핵심 자산 도달 전에 차단할 수 있습니다. 10. 대응 방법 초기 확인 — 단계별 신호를 시간순 종합(타임라인)해 시나리오를 재구성합니다. 범위 확인 — 각 단계 탐지 룰 발동·상관 경보·차단 기회를 확인합니다. 증거 확보 — 전 과정 타임라인·경로·증거를 보존합니다. 차단/조치 — 가장 이른 탐지 단계에서 확산 차단·자산 보호 대응을 진행합니다. 재발 방지 — 실전 시나리오 기반 측면 이동 탐지·대응을 연습·운영합니다. 11. 핵심 정리 단계 탐지 룰 침투 웹 로그 정찰 106280·106290 인증 이동 106080 목표 106330·106360 면접 포인트 "실전은 다층 탐지 — 조기 단계(정찰·이동) 차단이 핵심 자산을 지킴" 12. 다음 편 예고 다음 편 350. 내부 확장·측면 이동 — 내부 확장·측면 이동 징후 종합 정리 에서는 내부 확장·측면 이동 징후 전체를 종합하는 내부 확장·측면 이동 징후 종합 정리 를 다룹니다. 이전 편: 348. 내부 확장·측면 이동 — 내부 확장·측면 이동 탐지 규칙 모음 📚 시리즈 전체 보기: 시스템 보안 · 취약점
시스템 보안 · 취약점 › G. 내부 확장 · 측면 이동 징후 · 48/50편 (전체 348/450) 학습 단계: SOC 탐지 연계 실습 표기: 이 글의 명령어·출력·로그는 로컬 VMware 테스트 VM(Rocky Linux 9 / Ubuntu 22.04) 기준의 「실습 예시」 이며, IP·계정·호스트명은 가상의 값입니다. 선행 학습 347. 내부 확장·측면 이동 — 측면 이동 Alert 대응 절차 344. Wazuh 기반 측면 이동 탐지 1. 개념 G영역에서 설계한 측면 이동 탐지 규칙을 공격 단계별로 분류한 카탈로그 로 정리합니다. 정찰→인증 이동→원격 실행→확산→목표의 단계마다 핵심 룰을 매핑해, 다층 방어(defense in depth) 관점에서 운영합니다. 측면 이동 탐지 규칙 카탈로그(단계별) [정찰] 스캔·열거·디렉터리 [인증 이동] SSH·키 재사용·자격 재사용·PtH [원격 실행] 명령·스케줄러·SMB·DB·웹·터널 [확산] 경로·홉·자격 수집 [목표] 핵심 자산·상승 연계·유출 연계 [상관] 캠페인·부채꼴·체인 = 단계별 다층 탐지 카탈로그의 목적은 "어느 단계든 하나는 걸리게" 하는 다층 방어입니다. 단계별 룰을 모두 운영해 탐지 사각을 줄입니다. 2. 왜 중요한가 측면 이동은 여러 단계를 거치므로, 단계별 다층 룰이 탐지 확률을 높입니다. 어느 단계든 탐지하면 조기 차단 기회이므로 전 단계 커버가 중요합니다. 카탈로그로 룰을 체계화하면 누락 점검·튜닝·갱신이 쉬워집니다. 3. 핵심 명령어 / 설정 단계 핵심 룰 MITRE 정찰 106280·106290·106300 T1046·T1087 인증 이동 106080·106110·106130 T1021·T1550 원격 실행 106170·106200·106230 T1210·T1059 확산 106310·106320·106340 T1552·T1090 목표·상관 106330·106360·106430 T1041·T1078 4. 실습 (실습 예시) # 측면 이동 탐지 규칙 운영 점검 (분석 방법) # 적재된 G영역 룰 목록·레벨 확인 sudo grep -rE 'id="10(6)[0-9]{3}"' /var/ossec/etc/rules/ 2>/dev/null | grep -oE 'id="[0-9]+" level="[0-9]+"' | sort # 단계별 룰 커버리지 점검(누락 단계 확인) echo "정찰·인증이동·원격실행·확산·목표·상관 각 단계 룰 존재 여부 점검" # 전체 룰 문법 검증 sudo /var/ossec/bin/wazuh-logtest 5. 정상 상태 $ (룰 목록) (정찰~상관 전 단계 룰 적재·검증 통과) 정찰부터 상관까지 전 단계 룰이 적재되고 문법 검증을 통과해, 단계별 커버리지에 누락이 없는 상태가 정상입니다. 6. 이상 상태 운영 이슈 예: · 특정 단계 룰 누락 → 그 단계 탐지 사각 · 과도한 레벨·광범위 조건 → 오탐 폭증 · 기준선 예외 미설정 → 정상 관리 오탐 · 룰 미갱신 → 새 이동 기법 미탐 → 카탈로그로 누락·튜닝·갱신 점검 단계 누락 → 탐지 사각 → 전 단계 커버 확인 필요 광범위 조건·기준선 미설정 → 오탐 → 조건 정밀화·예외 설정 카탈로그 기반 정기 점검으로 사각·오탐·미탐 관리 7. 로그 분석 (분석 방법) 측면 이동 탐지 규칙 카탈로그 구조입니다(가상의 예시). 공격 단계 → 탐지 룰(다층) [정찰] ────── 106280(스캔)·106290(열거)·106300(디렉터리) [인증 이동] ── 106080(키 재사용)·106110(자격 재사용)·106130(계정 전환) [원격 실행] ── 106170(명령)·106200(SMB)·106230(DB)·106260(터널) [확산] ────── 106310(수집)·106320(경로)·106340(홉) [목표] ────── 106330(핵심 자산)·106360(유출 연계) [상관] ────── 106430(캠페인)·106450(흐름 연계) = 어느 단계든 하나는 걸리는 다층 방어 관점 운영 단계별 다층 커버 레벨 우선순위 기준선 오탐 제거 갱신 신규 기법 단계별 다층 커버 + 지속 튜닝이 카탈로그 운영의 핵심입니다. 8. SOC 관제 포인트 G영역 탐지 규칙을 공격 단계별 카탈로그 로 정리해 다층 방어를 운영합니다. 정찰→인증 이동→원격 실행→확산→목표→상관 전 단계를 커버해 사각을 줄입니다. 카탈로그로 누락 점검·오탐 튜닝·신규 기법 갱신을 체계적으로 관리합니다. 9. 탐지 규칙 <!-- 실습 예시 룰: 적용 전 wazuh-logtest 및 테스트 환경 검증 필요 --> <group name="local,syssec_g,lateral,catalog,"> <!-- 단계별 룰은 각 편(106080~106450)을 참조, 베이스로 묶음 관리 --> <rule id="106470" level="3"> <if_group>lateral</if_group> <description>측면 이동 탐지 카탈로그(단계별 룰 묶음 관리)</description> <mitre><id>T1021</id></mitre> </rule> </group> lateral 그룹으로 전 단계 룰을 묶어 관리하고, 레벨·기준선 예외를 일괄 튜닝합니다. 정기적으로 커버리지·오탐·신규 기법을 점검·갱신합니다. 10. 대응 방법 초기 확인 — 단계별(정찰~상관) 룰 적재·커버리지·문법을 점검합니다. 범위 확인 — 레벨·조건·기준선 예외의 오탐·미탐 균형을 확인합니다. 증거 확보 — 룰 카탈로그·커버리지 맵·튜닝 이력을 문서화·보존합니다. 차단/조치 — 누락 단계는 룰 추가, 오탐은 예외·조건 정밀화로 지속 튜닝합니다. 재발 방지 — 측면 이동 탐지 규칙 카탈로그를 운영·갱신합니다. 11. 핵심 정리 단계 핵심 룰 정찰 106280·106290·106300 인증 이동 106080·106110·106130 원격 실행 106170·106200·106230 목표·상관 106330·106360·106430 면접 포인트 "단계별 다층 룰로 어느 단계든 탐지 — 카탈로그로 사각·오탐·갱신 관리" 12. 다음 편 예고 다음 편 349. 내부 확장·측면 이동 — 실전 시나리오 — 침투부터 핵심 자산 장악까지 에서는 침투부터 핵심 자산 장악까지의 실전 시나리오를 다루는 실전 시나리오 — 침투부터 핵심 자산 장악까지 를 다룹니다. 이전 편: 347. 내부 확장·측면 이동 — 측면 이동 Alert 대응 절차 📚 시리즈 전체 보기: 시스템 보안 · 취약점
『Real MySQL 8.0』 6장을 읽고, 핵심 개념을 쉽게 이해할 수 있도록 제 방식대로 정리한 글입니다. 📌 들어가기 전에 왜 데이터를 압축할까? 디스크에 저장된 데이터 파일이 커지면 여러 가지 문제가 생깁니다. 문제 설명 쿼리 성능 읽어야 할 데이터가 많아져 디스크 I/O 증가 백업·복구 시간 파일이 클수록 백업과 복구가 오래 걸림 저장 공간 비용 디스크 용량이 많이 필요함 그래서 MySQL은 데이터를 압축해서 저장 하는 방법을 제공합니다. MySQL의 두 가지 압축 방식 방식 다른 이름 한 줄 설명 페이지 압축 Transparent Page Compression 디스크에 쓸 때 압축 , 읽을 때 해제. OS의 펀치 홀 기능에 의존 테이블 압축 - 압축된 페이지를 정해진 크기(KEY_BLOCK_SIZE) 에 맞춰 저장 6.1 페이지 압축 페이지 압축이란? 데이터 페이지를 디스크에 저장하는 순간 압축 하고, 디스크에서 읽어올 때 압축을 해제 합니다. 그래서 버퍼 풀에는 압축이 해제된 상태 로 데이터가 올라옵니다. [쓰기] 버퍼 풀 (16KB, 원본) ──압축──▶ 디스크 (압축된 상태) [읽기] 디스크 (압축된 상태) ──해제──▶ 버퍼 풀 (16KB, 원본) 💡 MySQL 서버 내부에서는 데이터가 압축됐는지 신경 쓰지 않고 똑같이 처리합니다. 그래서 "투명한(Transparent)" 페이지 압축이라고 부릅니다. 문제: 압축 결과의 크기를 예측할 수 없다 16KB 페이지를 압축하면 결과가 7KB가 될지, 10KB가 될지 미리 알 수 없습니다. 그런데 하나의 테이블은 모든 페이지가 같은 크기 여야 관리할 수 있습니다. 페이지 A 압축 → 7KB 페이지 B 압축 → 11KB 페이지 C 압축 → 5KB → 크기가 제각각이면 파일 안에서 페이지 위치를 계산할 수 없음 😵 해결: 펀치 홀 (Punch Hole) 운영체제의 펀치 홀 기능을 이용해 이 문제를 해결합니다. 1 16KB 페이지를 압축 → 결과 7KB 2 디스크에 16KB 크기 그대로 기록 [압축 데이터 7KB][빈 공간 9KB] 3 뒤쪽 빈 공간 9KB에 펀치 홀을 뚫음 [압축 데이터 7KB][🕳️ 9KB] → 파일 시스템은 9KB를 운영체제에 반납 관점 크기 실제 디스크 사용량 7KB MySQL·운영체제가 보는 파일 크기 16KB (압축 데이터 + 펀치 홀 공간) 🧩 비유: 16칸짜리 주차 구역을 그대로 유지하되, 실제로 차를 7칸에만 세우고 나머지 9칸은 "여기는 비어 있음" 이라고 표시해서 다른 사람이 쓰게 돌려주는 것 페이지 압축의 한계 한계 설명 지원 환경 제약 펀치 홀은 운영체제뿐 아니라 하드웨어(파일 시스템) 도 지원해야 함 파일 복사 시 문제 일반적인 파일 복사 명령어는 펀치 홀을 지원하지 않아서, 복사하면 원래 크기(16KB)로 되돌아감 백업 도구 문제 XtraBackup 같은 백업 도구로 백업·복구할 때도 같은 문제가 생길 수 있음 ⚠️ 이런 이유로 페이지 압축은 실무에서 많이 사용되지 않습니다. 사용 방법 -- 테이블 생성 시 페이지 압축 적용 CREATE TABLE t1 (c1 INT) COMPRESSION = 'zlib'; -- 기존 테이블에 페이지 압축 적용 ALTER TABLE t1 COMPRESSION = 'zlib'; OPTIMIZE TABLE t1; -- 기존 데이터에도 압축을 적용하려면 테이블 재구성 필요 COMPRESSION 값 의미 zlib zlib 알고리즘으로 압축 lz4 lz4 알고리즘으로 압축 none 압축하지 않음 6.2 테이블 압축 테이블 압축이란? 운영체제나 하드웨어 제약 없이 사용할 수 있는 압축 방식입니다. 그래서 페이지 압축보다 활용도가 높습니다. 단점도 있다 단점 설명 버퍼 풀 공간 활용률 낮음 버퍼 풀에 압축된 페이지와 해제된 페이지를 둘 다 보관 쿼리 처리 성능 낮음 압축·해제 과정에서 CPU 사용 잦은 변경 시 압축률 저하 데이터가 자주 바뀌면 압축 효율이 떨어짐 6.2.1 압축 테이블 생성 사전 조건 압축 테이블은 별도의 테이블스페이스 를 사용해야 합니다. SHOW GLOBAL VARIABLES LIKE 'innodb_file_per_table'; -- ON 이어야 함 생성 방법 CREATE TABLE compressed_table ( c1 INT PRIMARY KEY ) ROW_FORMAT = COMPRESSED KEY_BLOCK_SIZE = 8; 옵션 설명 ROW_FORMAT = COMPRESSED 압축 테이블로 생성 (생략하면 KEY_BLOCK_SIZE 만 지정해도 자동으로 COMPRESSED 적용) KEY_BLOCK_SIZE 압축된 페이지가 저장될 목표 크기 (KB 단위) 💡 KEY_BLOCK_SIZE 는 1, 2, 4, 8, 16(KB) 중에서 정하며, 기본 페이지 크기(16KB) 기준으로 보통 4KB 또는 8KB 를 사용합니다. InnoDB 페이지 크기가 32KB, 64KB라면 테이블 압축을 사용할 수 없습니다. 압축 과정 (KEY_BLOCK_SIZE = 8KB 예시) 1 16KB 데이터 페이지를 압축 │ ├─ 압축 결과 ≤ 8KB → 그대로 디스크에 저장 ✅ (압축 완료) │ └─ 압축 결과 > 8KB → 원본 페이지를 둘로 나눔 (페이지 스플릿) [8KB] [8KB] │ │ ▼ ▼ 나뉜 페이지 각각에 대해 1부터 다시 반복 ⚠️ 압축 결과가 목표 크기(KEY_BLOCK_SIZE)보다 작아야 저장할 수 있습니다. 목표 크기를 넘으면 페이지 스플릿 이 일어나고, 이게 반복되면 성능이 떨어집니다. 6.2.2 KEY_BLOCK_SIZE 결정 KEY_BLOCK_SIZE 를 너무 작게 잡으면 압축 실패 → 페이지 스플릿 이 자주 발생합니다. 그래서 실제 적용 전에 샘플 데이터로 테스트 해보는 것이 중요합니다. 테스트 방법 -- 1) 인덱스별 압축 통계 수집 활성화 SET GLOBAL innodb_cmp_per_index_enabled = ON; -- 2) KEY_BLOCK_SIZE를 바꿔가며 테스트 테이블 생성 CREATE TABLE employees_comp4k ( emp_no INT NOT NULL, first_name VARCHAR(14) NOT NULL, hire_date DATE NOT NULL, PRIMARY KEY (emp_no), KEY ix_firstname (first_name), KEY ix_hiredate (hire_date) ) ROW_FORMAT = COMPRESSED KEY_BLOCK_SIZE = 4; -- 3) 실제 데이터 일부를 넣어봄 INSERT INTO employees_comp4k SELECT emp_no, first_name, hire_date FROM employees; -- 4) 인덱스별 압축 성공/실패 횟수 확인 SELECT table_name, index_name, compress_ops, compress_ops_ok, (compress_ops - compress_ops_ok) / compress_ops * 100 AS compression_failure_pct FROM information_schema.INNODB_CMP_PER_INDEX; 컬럼 의미 compress_ops 전체 압축 시도 횟수 compress_ops_ok 압축 성공 횟수 compression_failure_pct 압축 실패율 판단 기준 압축 실패율 = (compress_ops - compress_ops_ok) / compress_ops × 100 💡 일반적으로 압축 실패율이 3~5% 미만 이 되도록 KEY_BLOCK_SIZE 를 선택합니다. 예를 들어 4KB에서 실패율이 높고 8KB에서 낮다면, 8KB 를 선택하는 것이 좋습니다. 그런데 실패율이 전부는 아니다 상황 판단 INSERT만 하는 로그성 테이블 한 번 압축되면 다시 변경되지 않으므로, 실패율이 조금 높아도 압축률이 좋다면 사용 고려 변경이 잦은 테이블 실패율이 낮더라도 압축·해제가 반복되어 CPU 부담 → 압축을 다시 고민 ✅ 압축·해제는 CPU를 사용하는 작업 이라는 점을 함께 고려해야 합니다. 6.2.3 압축된 페이지의 버퍼 풀 적재 및 사용 버퍼 풀에 두 가지 버전을 함께 보관 압축 테이블의 페이지는 버퍼 풀에 이렇게 올라옵니다. ┌─────────────── InnoDB 버퍼 풀 ───────────────┐ │ │ │ [압축된 페이지 8KB] ──해제──▶ [해제된 페이지 16KB] │ │ ▲ ▲ │ │ LRU 리스트 Unzip_LRU 리스트 │ └─────────────────────────────────────────────┘ 리스트 관리 대상 LRU 리스트 압축된 페이지 + 압축 해제된 페이지 모두 Unzip_LRU 리스트 압축 해제된 페이지만 디스크에서 읽어온 압축된 페이지 를 그대로 보관하고, 실제로 데이터를 읽거나 변경하려면 압축을 해제한 페이지 가 필요하기 때문에 둘 다 가지고 있습니다. 이로 인한 문제 문제 설명 메모리 낭비 같은 데이터를 두 가지 형태로 들고 있어서 버퍼 풀 공간을 더 많이 씀 CPU 소모 압축 해제된 페이지를 버렸다가 다시 필요해지면, 또 압축 해제 를 해야 함 InnoDB의 해결 방법: Unzip_LRU 리스트 관리 상황 InnoDB의 동작 버퍼 풀 공간이 부족할 때 압축된 원본은 남기고, Unzip_LRU에서 압축 해제된 버전을 제거 압축된 페이지가 자주 사용될 때 Unzip_LRU에 해제된 페이지를 계속 유지 → 압축·해제 작업 최소화 압축된 페이지가 사용되지 않아 LRU에서 제거될 때 Unzip_LRU에서도 함께 제거 어댑티브(적응형) 알고리즘 InnoDB는 서버 상황을 보고 Unzip_LRU의 비율을 자동으로 조절 합니다. 서버 상황 동작 이유 CPU 사용량이 높음 Unzip_LRU 비율을 높게 유지 압축 해제를 덜 하도록 해서 CPU 절약 디스크 I/O 사용량이 높음 Unzip_LRU 비율을 낮게 유지 버퍼 풀 공간을 더 확보해서 디스크 읽기 감소 🧩 비유 CPU가 바쁠 때: "포장 다시 뜯기 힘드니까, 뜯어놓은 거 그냥 둬" 디스크가 바쁠 때: "창고 공간이 부족하니까, 뜯어놓은 건 치우고 포장된 것만 보관해" 6.2.4 테이블 압축 관련 설정 1 innodb_cmp_per_index_enabled innodb_cmp_per_index_enabled = ON 값 수집되는 통계 ON 인덱스별 압축 성공·실패 횟수 → INNODB_CMP_PER_INDEX OFF 테이블 단위 압축 통계만 수집 → INNODB_CMP 2 innodb_compression_level innodb_compression_level = 6 -- 0 ~ 9, 기본값 6 InnoDB 테이블 압축은 zlib 알고리즘 을 사용하며, 이 값으로 압축률을 정합니다. 값 압축 속도 압축률(저장 공간) CPU 낮을수록 빠름 낮음 (공간 더 사용) 적게 사용 높을수록 느림 높음 (공간 절약) 많이 사용 3 innodb_compression_failure_threshold_pct & innodb_compression_pad_pct_max innodb_compression_failure_threshold_pct = 5 -- 기본값 5(%) innodb_compression_pad_pct_max = 50 -- 기본값 50(%) 동작 방식 테이블 단위 압축 실패율 > innodb_compression_failure_threshold_pct → 압축하기 전에 원본 페이지 끝에 일부러 빈 공간(패딩)을 추가 → 빈 공간은 압축이 매우 잘 되므로 전체 압축률이 올라감 → 압축 결과가 KEY_BLOCK_SIZE보다 작아질 확률 증가 ✅ 설정 의미 innodb_compression_failure_threshold_pct 압축 실패율이 이 값을 넘으면 패딩 추가 시작 innodb_compression_pad_pct_max 패딩 공간은 실패율이 높을수록 늘어나며, 최대 이 비율(%)까지 커질 수 있음 💡 압축 실패로 인한 페이지 스플릿을 줄이기 위해, InnoDB가 스스로 압축 성공률을 높이는 장치 입니다. 4 innodb_log_compressed_pages innodb_log_compressed_pages = ON -- 기본값 ON 서버가 비정상 종료된 뒤 재시작할 때, 압축 알고리즘(zlib)의 버전이 바뀌었더라도 복구가 실패하지 않도록 압축된 데이터 페이지를 그대로 리두 로그에 기록 하는 옵션입니다. 장점 단점 압축 알고리즘을 업그레이드할 때 안전한 복구 보장 데이터 페이지를 통째로 기록하므로 리두 로그 증가량이 커짐 ⚠️ 압축 테이블을 사용 중이라면 리두 로그 공간이 얼마나 빨리 차는지 모니터링해야 합니다. 버퍼 풀에서 더티 페이지가 한꺼번에 많이 기록되는 패턴이라면, 이 옵션을 OFF 로 바꾼 뒤 모니터링해보는 것을 고려할 수 있습니다. ✍️ 마무리 정리 페이지 압축 vs 테이블 압축 항목 페이지 압축 테이블 압축 압축 시점 디스크에 쓸 때 정해진 크기에 맞춰 저장 버퍼 풀 상태 해제된 상태 만 보관 압축 + 해제 둘 다 보관 의존성 OS·하드웨어의 펀치 홀 지원 필요 제약 없음 설정 COMPRESSION = 'zlib' ROW_FORMAT = COMPRESSED , KEY_BLOCK_SIZE 실무 활용 낮음 (파일 복사·백업 문제) 상대적으로 높음 핵심 포인트 6.1 페이지 압축 디스크에 쓸 때 압축하고, 남는 공간은 펀치 홀 로 운영체제에 반납한다. 파일 복사·백업 시 펀치 홀이 사라지는 문제로 잘 쓰이지 않는다. 6.2.1 압축 테이블 생성 innodb_file_per_table = ON 필요 압축 결과가 KEY_BLOCK_SIZE 보다 크면 페이지 스플릿 발생 6.2.2 KEY_BLOCK_SIZE 결정 샘플 데이터로 테스트 후 INNODB_CMP_PER_INDEX 에서 압축 실패율 확인 실패율 3~5% 미만이 기준이지만, 테이블의 변경 빈도도 함께 고려 6.2.3 버퍼 풀 적재 압축 페이지(LRU)와 해제 페이지(Unzip_LRU)를 함께 보관 CPU가 바쁘면 해제 페이지를 유지하고, 디스크가 바쁘면 해제 페이지를 줄이는 적응형 알고리즘 6.2.4 관련 설정 압축 통계( innodb_cmp_per_index_enabled ), 압축률( innodb_compression_level ) 실패율이 높으면 패딩을 추가 해 압축 성공률을 높임 innodb_log_compressed_pages 는 리두 로그 증가량을 함께 모니터링 📚 참고 백은빈, 이성욱, 『Real MySQL 8.0 1권』, 위키북스 MySQL 8.0 Reference Manual - InnoDB Page Compression MySQL 8.0 Reference Manual - InnoDB Table Compression