<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>혁신을 이룹니다, 오딘박스</title>
    <link>https://odinbox.tistory.com/</link>
    <description>혁신을 이룹니다, 오딘박스(OdinBOX)</description>
    <language>ko</language>
    <pubDate>Wed, 13 May 2026 19:24:16 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>간지뽕빨리턴님</managingEditor>
    <image>
      <title>혁신을 이룹니다, 오딘박스</title>
      <url>https://tistory1.daumcdn.net/tistory/1569230/attach/0929e04b079a40c6b84b1715fd186fb3</url>
      <link>https://odinbox.tistory.com</link>
    </image>
    <item>
      <title>나는 지금, 새로운 환경에 배포되는 중입니다</title>
      <link>https://odinbox.tistory.com/584</link>
      <description>&lt;div id=&quot;gwangmyeong_post_wrap&quot; class=&quot;gwangmyeong_post_wrap&quot;&gt;
&lt;style&gt;
    .gwangmyeong_post_wrap {
      max-width: 920px;
      margin: 0 auto;
      padding: 28px 18px;
      font-family: -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, &quot;Noto Sans KR&quot;, &quot;Apple SD Gothic Neo&quot;, Arial, sans-serif;
      color: #1f2937;
      line-height: 1.85;
      word-break: keep-all;
      letter-spacing: -0.02em;
      background: #ffffff;
    }

    .gwangmyeong_post_wrap * {
      box-sizing: border-box;
    }

    .gwangmyeong_seo_summary {
      margin: 0 0 22px;
      padding: 18px 20px;
      border-radius: 18px;
      background: #f8fafc;
      border: 1px solid #e5e7eb;
      color: #475569;
      font-size: 15px;
      line-height: 1.75;
    }

    .gwangmyeong_hero {
      position: relative;
      overflow: hidden;
      padding: 54px 34px;
      border-radius: 30px;
      background:
        radial-gradient(circle at 18% 18%, rgba(59, 130, 246, 0.30), transparent 34%),
        radial-gradient(circle at 86% 12%, rgba(14, 165, 233, 0.24), transparent 30%),
        radial-gradient(circle at 50% 100%, rgba(125, 211, 252, 0.14), transparent 42%),
        linear-gradient(135deg, #020617 0%, #0f172a 44%, #1e293b 100%);
      color: #ffffff;
      box-shadow: 0 24px 70px rgba(15, 23, 42, 0.28);
      isolation: isolate;
    }

    .gwangmyeong_hero::before {
      content: &quot;&quot;;
      position: absolute;
      top: -120px;
      left: -120px;
      width: 280px;
      height: 280px;
      border-radius: 50%;
      background: rgba(59, 130, 246, 0.22);
      filter: blur(6px);
      animation: gwangmyeong_softFloat 9s ease-in-out infinite alternate;
      z-index: -1;
    }

    .gwangmyeong_hero::after {
      content: &quot;&quot;;
      position: absolute;
      inset: 0;
      background: linear-gradient(120deg, transparent 0%, rgba(255, 255, 255, 0.08) 42%, transparent 64%);
      transform: translateX(-100%);
      animation: gwangmyeong_lightSweep 6s ease-in-out infinite;
      z-index: -1;
    }

    .gwangmyeong_hero_grid {
      display: grid;
      grid-template-columns: 1.25fr 0.75fr;
      gap: 28px;
      align-items: center;
    }

    .gwangmyeong_hero_badge {
      display: inline-flex;
      align-items: center;
      gap: 8px;
      padding: 8px 14px;
      margin-bottom: 20px;
      border: 1px solid rgba(255, 255, 255, 0.26);
      border-radius: 999px;
      background: rgba(255, 255, 255, 0.10);
      color: #dbeafe;
      font-size: 14px;
      font-weight: 800;
      backdrop-filter: blur(10px);
      animation: gwangmyeong_fadeUp 0.75s ease both;
    }

    .gwangmyeong_visual_title {
      margin: 0;
      color: #ffffff;
      font-size: clamp(32px, 5vw, 50px);
      line-height: 1.23;
      letter-spacing: -0.055em;
      font-weight: 950;
      animation: gwangmyeong_fadeUp 0.85s ease both;
      animation-delay: 0.08s;
    }

    .gwangmyeong_visual_title span {
      display: inline;
      color: #93c5fd;
    }

    .gwangmyeong_hero_subtitle {
      margin: 22px 0 0;
      max-width: 720px;
      color: #dbeafe;
      font-size: 17px;
      line-height: 1.9;
      animation: gwangmyeong_fadeUp 0.9s ease both;
      animation-delay: 0.16s;
    }

    .gwangmyeong_thumbnail_card {
      position: relative;
      padding: 12px;
      border-radius: 28px;
      background: rgba(255, 255, 255, 0.12);
      border: 1px solid rgba(255, 255, 255, 0.20);
      box-shadow: 0 20px 44px rgba(0, 0, 0, 0.22);
      backdrop-filter: blur(12px);
      animation: gwangmyeong_floatImage 4.8s ease-in-out infinite;
    }

    .gwangmyeong_thumbnail_card p {
      margin: 0 !important;
    }

    .gwangmyeong_thumbnail_card img {
      display: block;
      width: 100%;
      height: auto;
      border-radius: 22px;
      box-shadow: 0 16px 36px rgba(15, 23, 42, 0.28);
    }

    .gwangmyeong_thumbnail_caption {
      margin-top: 12px;
      color: #dbeafe;
      font-size: 13px;
      line-height: 1.6;
      text-align: center;
      opacity: 0.9;
    }

    .gwangmyeong_meta_box {
      display: grid;
      grid-template-columns: repeat(3, 1fr);
      gap: 14px;
      margin: 28px 0 0;
      animation: gwangmyeong_fadeUp 0.9s ease both;
      animation-delay: 0.24s;
    }

    .gwangmyeong_meta_item {
      padding: 16px;
      border-radius: 18px;
      background: rgba(255, 255, 255, 0.10);
      border: 1px solid rgba(255, 255, 255, 0.18);
      transition: transform 0.25s ease, background 0.25s ease;
    }

    .gwangmyeong_meta_item:hover {
      transform: translateY(-4px);
      background: rgba(255, 255, 255, 0.15);
    }

    .gwangmyeong_meta_label {
      display: block;
      color: #bfdbfe;
      font-size: 13px;
      font-weight: 800;
      margin-bottom: 4px;
    }

    .gwangmyeong_meta_value {
      display: block;
      color: #ffffff;
      font-size: 16px;
      font-weight: 900;
    }

    .gwangmyeong_section {
      margin-top: 42px;
      padding: 34px;
      border: 1px solid #e5e7eb;
      border-radius: 24px;
      background: #ffffff;
      box-shadow: 0 14px 34px rgba(15, 23, 42, 0.06);
      opacity: 0;
      transform: translateY(22px);
      animation: gwangmyeong_fadeUp 0.85s ease forwards;
    }

    .gwangmyeong_section_title {
      position: relative;
      margin: 0 0 18px;
      padding-left: 16px;
      color: #111827;
      font-size: 26px;
      line-height: 1.35;
      font-weight: 950;
      letter-spacing: -0.04em;
    }

    .gwangmyeong_section_title::before {
      content: &quot;&quot;;
      position: absolute;
      top: 8px;
      left: 0;
      width: 5px;
      height: 26px;
      border-radius: 999px;
      background: linear-gradient(180deg, #2563eb, #38bdf8);
    }

    .gwangmyeong_paragraph {
      margin: 0 0 18px;
      color: #374151;
      font-size: 17px;
    }

    .gwangmyeong_paragraph strong {
      color: #1d4ed8;
      font-weight: 900;
    }

    .gwangmyeong_quote {
      position: relative;
      margin: 28px 0;
      padding: 24px 26px;
      border-left: 6px solid #2563eb;
      border-radius: 18px;
      background: linear-gradient(135deg, #eff6ff 0%, #f8fafc 100%);
      color: #1e3a8a;
      font-size: 18px;
      font-weight: 900;
      line-height: 1.75;
      overflow: hidden;
    }

    .gwangmyeong_quote::after {
      content: &quot;&quot;;
      position: absolute;
      right: -40px;
      bottom: -40px;
      width: 120px;
      height: 120px;
      border-radius: 50%;
      background: rgba(37, 99, 235, 0.08);
    }

    .gwangmyeong_timeline {
      display: grid;
      gap: 16px;
      margin-top: 24px;
    }

    .gwangmyeong_timeline_item {
      display: grid;
      grid-template-columns: 120px 1fr;
      gap: 18px;
      padding: 20px;
      border-radius: 20px;
      background: #f9fafb;
      border: 1px solid #e5e7eb;
      transition: transform 0.25s ease, box-shadow 0.25s ease, border-color 0.25s ease;
    }

    .gwangmyeong_timeline_item:hover {
      transform: translateY(-4px);
      border-color: #bfdbfe;
      box-shadow: 0 14px 30px rgba(37, 99, 235, 0.10);
    }

    .gwangmyeong_timeline_label {
      color: #2563eb;
      font-weight: 950;
      font-size: 15px;
    }

    .gwangmyeong_timeline_text {
      margin: 0;
      color: #374151;
      font-size: 16px;
    }

    .gwangmyeong_code_card {
      position: relative;
      margin-top: 26px;
      padding: 24px;
      border-radius: 22px;
      background: #0f172a;
      color: #dbeafe;
      box-shadow: 0 18px 42px rgba(15, 23, 42, 0.22);
      overflow-x: auto;
    }

    .gwangmyeong_code_card::before {
      content: &quot;odinbox.dev.log&quot;;
      display: block;
      margin-bottom: 12px;
      color: #93c5fd;
      font-size: 13px;
      font-weight: 900;
      letter-spacing: 0.02em;
    }

    .gwangmyeong_code_card pre {
      margin: 0;
      font-size: 15px;
      line-height: 1.8;
      white-space: pre-wrap;
      font-family: &quot;Consolas&quot;, &quot;Monaco&quot;, &quot;Courier New&quot;, monospace;
    }

    .gwangmyeong_final_box {
      position: relative;
      margin-top: 42px;
      padding: 36px;
      border-radius: 28px;
      background:
        linear-gradient(135deg, rgba(37, 99, 235, 0.10), rgba(56, 189, 248, 0.10)),
        #f8fafc;
      border: 1px solid #dbeafe;
      overflow: hidden;
    }

    .gwangmyeong_final_box::before {
      content: &quot;&quot;;
      position: absolute;
      top: -60px;
      right: -60px;
      width: 180px;
      height: 180px;
      border-radius: 50%;
      background: rgba(37, 99, 235, 0.10);
    }

    .gwangmyeong_final_text {
      position: relative;
      margin: 0;
      color: #1f2937;
      font-size: 19px;
      line-height: 1.9;
      font-weight: 800;
      z-index: 1;
    }

    .gwangmyeong_tag_area {
      margin-top: 34px;
      display: flex;
      flex-wrap: wrap;
      gap: 10px;
    }

    .gwangmyeong_tag {
      display: inline-flex;
      padding: 8px 13px;
      border-radius: 999px;
      background: #eff6ff;
      color: #1d4ed8;
      font-size: 14px;
      font-weight: 900;
      border: 1px solid #bfdbfe;
      transition: transform 0.2s ease, background 0.2s ease;
    }

    .gwangmyeong_tag:hover {
      transform: translateY(-2px);
      background: #dbeafe;
    }

    .gwangmyeong_scroll_button {
      position: fixed;
      right: 20px;
      bottom: 22px;
      z-index: 50;
      width: 46px;
      height: 46px;
      border: none;
      border-radius: 50%;
      background: #2563eb;
      color: #ffffff;
      font-size: 18px;
      font-weight: 900;
      cursor: pointer;
      box-shadow: 0 14px 28px rgba(37, 99, 235, 0.34);
      transition: transform 0.2s ease, opacity 0.2s ease;
      display: none;
    }

    .gwangmyeong_scroll_button:hover {
      transform: translateY(-3px);
      opacity: 0.92;
    }

    @keyframes gwangmyeong_fadeUp {
      from {
        opacity: 0;
        transform: translateY(22px);
      }
      to {
        opacity: 1;
        transform: translateY(0);
      }
    }

    @keyframes gwangmyeong_softFloat {
      from {
        transform: translate(0, 0) scale(1);
      }
      to {
        transform: translate(30px, 26px) scale(1.08);
      }
    }

    @keyframes gwangmyeong_lightSweep {
      0% {
        transform: translateX(-100%);
      }
      45% {
        transform: translateX(100%);
      }
      100% {
        transform: translateX(100%);
      }
    }

    @keyframes gwangmyeong_floatImage {
      0%, 100% {
        transform: translateY(0);
      }
      50% {
        transform: translateY(-8px);
      }
    }

    @media (max-width: 720px) {
      .gwangmyeong_post_wrap {
        padding: 18px 12px;
      }

      .gwangmyeong_hero {
        padding: 36px 20px;
        border-radius: 22px;
      }

      .gwangmyeong_hero_grid {
        grid-template-columns: 1fr;
      }

      .gwangmyeong_thumbnail_card {
        max-width: 320px;
        margin: 4px auto 0;
      }

      .gwangmyeong_meta_box {
        grid-template-columns: 1fr;
      }

      .gwangmyeong_section {
        padding: 24px 20px;
        border-radius: 20px;
      }

      .gwangmyeong_section_title {
        font-size: 23px;
      }

      .gwangmyeong_paragraph {
        font-size: 16px;
      }

      .gwangmyeong_timeline_item {
        grid-template-columns: 1fr;
      }

      .gwangmyeong_scroll_button {
        right: 14px;
        bottom: 16px;
      }
    }

    @media (prefers-reduced-motion: reduce) {
      .gwangmyeong_post_wrap *,
      .gwangmyeong_post_wrap *::before,
      .gwangmyeong_post_wrap *::after {
        animation: none !important;
        transition: none !important;
      }
    }
  &lt;/style&gt;
&lt;article class=&quot;gwangmyeong_article&quot;&gt;
&lt;p class=&quot;gwangmyeong_seo_summary&quot; data-ke-size=&quot;size16&quot;&gt;울산에서 광명으로 올라오며, 최영환이라는 개발자가 오딘박스에 남기는 새로운 시작과 성장의 기록입니다.&lt;/p&gt;
&lt;header class=&quot;gwangmyeong_hero&quot;&gt;
&lt;div class=&quot;gwangmyeong_hero_grid&quot;&gt;
&lt;div class=&quot;gwangmyeong_hero_content&quot;&gt;
&lt;div class=&quot;gwangmyeong_hero_badge&quot;&gt;OdinBOX &amp;middot; Developer Journey &amp;middot; Ulsan to Gwangmyeong&lt;/div&gt;
&lt;p class=&quot;gwangmyeong_visual_title&quot; data-ke-size=&quot;size16&quot;&gt;나는 지금,&lt;br /&gt;&lt;span&gt;새로운 환경에 배포되는 중입니다&lt;/span&gt;&lt;/p&gt;
&lt;p class=&quot;gwangmyeong_hero_subtitle&quot; data-ke-size=&quot;size16&quot;&gt;울산에서 쌓아온 시간과 경험을 뒤로하고, 이제는 광명이라는 낯선 도시에서 다시 시작하려 합니다. 개발자 최영환으로서, 그리고 오딘박스라는 이름으로 남기는 이 기록은 설렘과 두려움 사이에서 작성하는 하나의 커밋 메시지 같은 글입니다.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;gwangmyeong_thumbnail_card&quot; aria-label=&quot;대표 이미지&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;글 상단 부분 대표 이미지 (1).png&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/F0lc4/dJMcaiDfQzW/R5KXZ32egvPkHCEqkFeG50/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/F0lc4/dJMcaiDfQzW/R5KXZ32egvPkHCEqkFeG50/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/F0lc4/dJMcaiDfQzW/R5KXZ32egvPkHCEqkFeG50/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FF0lc4%2FdJMcaiDfQzW%2FR5KXZ32egvPkHCEqkFeG50%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;400&quot; data-filename=&quot;글 상단 부분 대표 이미지 (1).png&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;div class=&quot;gwangmyeong_thumbnail_caption&quot;&gt;울산에서 광명으로, 개발자로서 다시 시작하는 기록&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;gwangmyeong_meta_box&quot;&gt;
&lt;div class=&quot;gwangmyeong_meta_item&quot;&gt;&lt;span class=&quot;gwangmyeong_meta_label&quot;&gt;출발점&lt;/span&gt; &lt;span class=&quot;gwangmyeong_meta_value&quot;&gt;울산&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;gwangmyeong_meta_item&quot;&gt;&lt;span class=&quot;gwangmyeong_meta_label&quot;&gt;새로운 환경&lt;/span&gt; &lt;span class=&quot;gwangmyeong_meta_value&quot;&gt;광명&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;gwangmyeong_meta_item&quot;&gt;&lt;span class=&quot;gwangmyeong_meta_label&quot;&gt;기록하는 이름&lt;/span&gt; &lt;span class=&quot;gwangmyeong_meta_value&quot;&gt;최영환 &amp;middot; 오딘박스&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/header&gt;
&lt;section class=&quot;gwangmyeong_section&quot;&gt;
&lt;h2 class=&quot;gwangmyeong_section_title&quot; data-ke-size=&quot;size26&quot;&gt;익숙한 울산을 떠난다는 것&lt;/h2&gt;
&lt;p class=&quot;gwangmyeong_paragraph&quot; data-ke-size=&quot;size16&quot;&gt;오랫동안 울산에서 근무를 하다가, 사무실 위치가 광명으로 이전되면서 저 역시 광명으로 올라오게 되었습니다. 말로는 &amp;ldquo;이전&amp;rdquo;이라는 짧은 단어로 표현할 수 있지만, 제 마음 안에서는 생각보다 많은 감정이 오갔습니다.&lt;/p&gt;
&lt;p class=&quot;gwangmyeong_paragraph&quot; data-ke-size=&quot;size16&quot;&gt;울산은 저에게 익숙한 도시였습니다. 매일 지나던 길, 익숙한 공기, 일하는 방식, 그리고 제가 개발자로서 조금씩 성장해온 시간이 쌓여 있는 곳이었습니다. 최영환이라는 이름으로 일했고, 오딘박스라는 이름으로 기록하며, 저만의 속도로 하루하루를 쌓아왔습니다.&lt;/p&gt;
&lt;p class=&quot;gwangmyeong_paragraph&quot; data-ke-size=&quot;size16&quot;&gt;그런데 이제는 그 익숙함을 잠시 내려놓고, 광명이라는 새로운 환경에서 다시 하루를 시작해야 합니다. 개발자로서 수도권으로 올라오게 되었다는 사실은 솔직히 기쁩니다. 더 많은 기회가 있을 것 같고, 더 넓은 환경에서 성장할 수 있을 것 같고, 지금보다 더 큰 경험을 할 수 있을 것 같다는 기대도 있습니다.&lt;/p&gt;
&lt;div class=&quot;gwangmyeong_quote&quot;&gt;하지만 기대가 크다는 것은, 그만큼 두려움도 함께 따라온다는 뜻이기도 합니다.&lt;/div&gt;
&lt;p class=&quot;gwangmyeong_paragraph&quot; data-ke-size=&quot;size16&quot;&gt;아직 직접 가보지 않은 길입니다. 어떤 사람들이 기다리고 있을지, 어떤 업무가 펼쳐질지, 내가 그 안에서 잘 적응할 수 있을지 아직은 모릅니다. 그래서 설레면서도 한편으로는 겁이 납니다.&lt;/p&gt;
&lt;/section&gt;
&lt;section class=&quot;gwangmyeong_section&quot;&gt;
&lt;h2 class=&quot;gwangmyeong_section_title&quot; data-ke-size=&quot;size26&quot;&gt;개발자의 이동은 단순한 이사가 아니다&lt;/h2&gt;
&lt;p class=&quot;gwangmyeong_paragraph&quot; data-ke-size=&quot;size16&quot;&gt;이번 이동은 단순히 근무지가 바뀌는 일이 아닙니다. 저에게는 개발자로서의 환경이 바뀌고, 시야가 바뀌고, 앞으로의 방향이 조금 더 선명해지는 전환점처럼 느껴집니다.&lt;/p&gt;
&lt;p class=&quot;gwangmyeong_paragraph&quot; data-ke-size=&quot;size16&quot;&gt;개발자는 매일 새로운 문제를 만납니다. 에러 메시지를 보고 원인을 찾고, 복잡한 요구사항을 코드로 풀어내고, 어제는 몰랐던 기술을 오늘은 이해해야 합니다. 어쩌면 광명으로 올라가는 이번 길도 그런 개발 과정과 비슷한 것 같습니다.&lt;/p&gt;
&lt;div class=&quot;gwangmyeong_code_card&quot;&gt;
&lt;pre class=&quot;dts&quot;&gt;&lt;code&gt;const gwangmyeong_developer = {
  name: &quot;최영환&quot;,
  brand: &quot;OdinBOX&quot;,
  from: &quot;Ulsan&quot;,
  to: &quot;Gwangmyeong&quot;,
  role: &quot;Developer&quot;,
  feeling: [&quot;설렘&quot;, &quot;두려움&quot;, &quot;기대&quot;, &quot;책임감&quot;],
  commitMessage: &quot;낯선 환경에서도 멈추지 않고 성장하기&quot;
};&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p class=&quot;gwangmyeong_paragraph&quot; data-ke-size=&quot;size16&quot;&gt;처음부터 완벽하게 아는 개발자는 없습니다. 처음부터 모든 길을 알고 출발하는 사람도 없습니다. 중요한 것은 모르는 것을 인정하고, 부딪히고, 기록하고, 다시 고치는 과정이라고 생각합니다.&lt;/p&gt;
&lt;p class=&quot;gwangmyeong_paragraph&quot; data-ke-size=&quot;size16&quot;&gt;광명이라는 새로운 환경은 저에게 또 다른 운영 서버와도 같습니다. 아직 배포 전이라 어떤 오류가 날지 모르고, 어떤 예외 상황이 생길지 모르지만, 결국 하나씩 로그를 확인하고, 원인을 찾고, 개선해 나가야 합니다.&lt;/p&gt;
&lt;div class=&quot;gwangmyeong_timeline&quot;&gt;
&lt;div class=&quot;gwangmyeong_timeline_item&quot;&gt;
&lt;div class=&quot;gwangmyeong_timeline_label&quot;&gt;울산에서&lt;/div&gt;
&lt;p class=&quot;gwangmyeong_timeline_text&quot; data-ke-size=&quot;size16&quot;&gt;익숙한 환경 속에서 개발자로서의 기본기를 쌓고, 현장의 문제를 마주하며 일하는 법을 배웠습니다.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;gwangmyeong_timeline_item&quot;&gt;
&lt;div class=&quot;gwangmyeong_timeline_label&quot;&gt;오딘박스에&lt;/div&gt;
&lt;p class=&quot;gwangmyeong_timeline_text&quot; data-ke-size=&quot;size16&quot;&gt;최영환이라는 이름으로 경험을 기록하고, 배운 것을 남기며, 개발자로서의 시간을 정리해왔습니다.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;gwangmyeong_timeline_item&quot;&gt;
&lt;div class=&quot;gwangmyeong_timeline_label&quot;&gt;광명으로&lt;/div&gt;
&lt;p class=&quot;gwangmyeong_timeline_text&quot; data-ke-size=&quot;size16&quot;&gt;수도권이라는 더 넓은 무대에서 새로운 사람, 새로운 업무, 새로운 가능성을 만나게 되었습니다.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;gwangmyeong_timeline_item&quot;&gt;
&lt;div class=&quot;gwangmyeong_timeline_label&quot;&gt;앞으로&lt;/div&gt;
&lt;p class=&quot;gwangmyeong_timeline_text&quot; data-ke-size=&quot;size16&quot;&gt;두려움이 없어서 가는 것이 아니라, 두려움이 있어도 개발자로서 더 성장하고 싶기 때문에 나아가려 합니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section class=&quot;gwangmyeong_section&quot;&gt;
&lt;h2 class=&quot;gwangmyeong_section_title&quot; data-ke-size=&quot;size26&quot;&gt;설렘과 두려움 사이에서 남기는 커밋&lt;/h2&gt;
&lt;p class=&quot;gwangmyeong_paragraph&quot; data-ke-size=&quot;size16&quot;&gt;사실 마음이 마냥 가볍지만은 않습니다. 새로운 곳에서 잘할 수 있을지, 내가 기대만큼 성장할 수 있을지, 때로는 지치고 힘든 순간이 오지는 않을지 걱정도 됩니다.&lt;/p&gt;
&lt;p class=&quot;gwangmyeong_paragraph&quot; data-ke-size=&quot;size16&quot;&gt;하지만 그런 마음이 든다는 것은, 그만큼 이번 변화가 저에게 중요하다는 의미이기도 합니다. 아무 의미 없는 일이라면 긴장도 하지 않았을 것입니다. 정말 잘하고 싶기 때문에, 더 나아지고 싶기 때문에, 지금 이 길이 조금은 무겁게 느껴지는 것 같습니다.&lt;/p&gt;
&lt;p class=&quot;gwangmyeong_paragraph&quot; data-ke-size=&quot;size16&quot;&gt;개발자로 일하면서 느낀 것이 있습니다. 어려운 문제일수록 처음에는 막막합니다. 어디서부터 봐야 할지 모르겠고, 해결이 안 될 것 같고, 괜히 내가 부족한 사람처럼 느껴질 때도 있습니다.&lt;/p&gt;
&lt;p class=&quot;gwangmyeong_paragraph&quot; data-ke-size=&quot;size16&quot;&gt;그런데 로그를 하나씩 보고, 코드를 한 줄씩 따라가고, 원인을 조금씩 좁혀가다 보면 결국 실마리가 보입니다. 인생의 변화도 비슷하지 않을까 생각합니다. 광명에서의 시작도 처음에는 낯설겠지만, 하루하루 쌓다 보면 언젠가는 저만의 흐름을 찾게 될 것입니다.&lt;/p&gt;
&lt;div class=&quot;gwangmyeong_quote&quot;&gt;모르는 길이라서 두렵지만, 모르는 길이기 때문에 성장할 수 있다고 믿습니다.&lt;/div&gt;
&lt;/section&gt;
&lt;section class=&quot;gwangmyeong_section&quot;&gt;
&lt;h2 class=&quot;gwangmyeong_section_title&quot; data-ke-size=&quot;size26&quot;&gt;그래도 나는 앞으로 간다&lt;/h2&gt;
&lt;p class=&quot;gwangmyeong_paragraph&quot; data-ke-size=&quot;size16&quot;&gt;울산에서 광명으로. 이 문장 안에는 단순한 지역 이동 이상의 의미가 담겨 있습니다. 저에게는 익숙함에서 벗어나 새로운 가능성으로 향하는 시작이고, 개발자로서 한 단계 더 넓은 환경에 서게 되는 순간입니다.&lt;/p&gt;
&lt;p class=&quot;gwangmyeong_paragraph&quot; data-ke-size=&quot;size16&quot;&gt;물론 앞으로 분명히 힘든 날도 있을 것입니다. 지치는 날도 있을 것이고, 생각보다 잘 풀리지 않는 일도 있을 것입니다. 낯선 도시에서 외로움을 느끼는 순간도 있을지 모릅니다.&lt;/p&gt;
&lt;p class=&quot;gwangmyeong_paragraph&quot; data-ke-size=&quot;size16&quot;&gt;그래도 저는 이 길을 한번 걸어가 보려 합니다. 아직 어떤 길인지 모르지만, 모르기 때문에 더 배우고 싶습니다. 아직 완벽하지 않지만, 완벽하지 않기 때문에 더 성장할 수 있다고 믿습니다.&lt;/p&gt;
&lt;div class=&quot;gwangmyeong_final_box&quot;&gt;
&lt;p class=&quot;gwangmyeong_final_text&quot; data-ke-size=&quot;size16&quot;&gt;울산에서 쌓은 시간은 제 기반이 되었고,&lt;br /&gt;오딘박스에 남긴 기록은 제 방향이 되었으며,&lt;br /&gt;광명에서의 시간은 앞으로의 새로운 실행 환경이 될 것입니다.&lt;br /&gt;&lt;br /&gt;두렵지만 기대됩니다.&lt;br /&gt;낯설지만 설렙니다.&lt;br /&gt;그리고 저는 개발자 최영환으로서,&lt;br /&gt;이 새로운 길 위에서 다시 시작해보려 합니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;div class=&quot;gwangmyeong_tag_area&quot; aria-label=&quot;태그 목록&quot;&gt;&lt;span class=&quot;gwangmyeong_tag&quot;&gt;#최영환&lt;/span&gt; &lt;span class=&quot;gwangmyeong_tag&quot;&gt;#오딘박스&lt;/span&gt; &lt;span class=&quot;gwangmyeong_tag&quot;&gt;#OdinBOX&lt;/span&gt; &lt;span class=&quot;gwangmyeong_tag&quot;&gt;#울산개발자&lt;/span&gt; &lt;span class=&quot;gwangmyeong_tag&quot;&gt;#광명개발자&lt;/span&gt; &lt;span class=&quot;gwangmyeong_tag&quot;&gt;#개발자일상&lt;/span&gt; &lt;span class=&quot;gwangmyeong_tag&quot;&gt;#개발자성장기&lt;/span&gt; &lt;span class=&quot;gwangmyeong_tag&quot;&gt;#수도권개발자&lt;/span&gt; &lt;span class=&quot;gwangmyeong_tag&quot;&gt;#새로운시작&lt;/span&gt; &lt;span class=&quot;gwangmyeong_tag&quot;&gt;#개발자회고&lt;/span&gt;&lt;/div&gt;
&lt;/article&gt;
&lt;button id=&quot;gwangmyeong_scroll_button&quot; class=&quot;gwangmyeong_scroll_button&quot; type=&quot;button&quot; aria-label=&quot;맨 위로 이동&quot;&gt; &amp;uarr; &lt;/button&gt;
&lt;script&gt;
    function gwangmyeong_scrollToTop() {
      window.scrollTo({
        top: 0,
        behavior: &quot;smooth&quot;
      });
    }

    const gwangmyeong_scrollButton = document.getElementById(&quot;gwangmyeong_scroll_button&quot;);

    if (gwangmyeong_scrollButton) {
      gwangmyeong_scrollButton.addEventListener(&quot;click&quot;, gwangmyeong_scrollToTop);
    }

    window.addEventListener(&quot;scroll&quot;, function gwangmyeong_handleScrollButton() {
      if (!gwangmyeong_scrollButton) {
        return;
      }

      if (window.scrollY &gt; 400) {
        gwangmyeong_scrollButton.style.display = &quot;block&quot;;
      } else {
        gwangmyeong_scrollButton.style.display = &quot;none&quot;;
      }
    });
  &lt;/script&gt;
&lt;/div&gt;</description>
      <category>DailyRoutine</category>
      <category>개발자블로그</category>
      <category>개발자성장기</category>
      <category>개발자일상</category>
      <category>개발자회고</category>
      <category>광명개발자</category>
      <category>광명생활</category>
      <category>새로운시작</category>
      <category>수도권개발자</category>
      <category>울산에서광명으로</category>
      <category>직장인이야기</category>
      <author>간지뽕빨리턴님</author>
      <guid isPermaLink="true">https://odinbox.tistory.com/584</guid>
      <comments>https://odinbox.tistory.com/584#entry584comment</comments>
      <pubDate>Sat, 9 May 2026 23:27:01 +0900</pubDate>
    </item>
    <item>
      <title>Claude AI 프롬프트 잘 쓰는 법, 토큰 절약까지 함께 정리</title>
      <link>https://odinbox.tistory.com/583</link>
      <description>&lt;div&gt;
&lt;style&gt;
  .CLAUDETOK_wrap {
    max-width: 920px !important;
    margin: 0 auto !important;
    padding: 24px 18px 52px !important;
    color: #1f2937 !important;
    font-family: -apple-system, BlinkMacSystemFont, &quot;Noto Sans KR&quot;, &quot;Apple SD Gothic Neo&quot;, &quot;Segoe UI&quot;, sans-serif !important;
    line-height: 1.86 !important;
    word-break: keep-all !important;
    background: #ffffff !important;
  }

  .CLAUDETOK_wrap * {
    box-sizing: border-box !important;
  }

  .CLAUDETOK_hero {
    position: relative !important;
    overflow: hidden !important;
    padding: 48px 34px !important;
    border-radius: 28px !important;
    background:
      radial-gradient(circle at 12% 18%, rgba(96, 165, 250, 0.34), transparent 34%),
      radial-gradient(circle at 90% 10%, rgba(167, 139, 250, 0.28), transparent 32%),
      linear-gradient(135deg, #111827 0%, #1e1b4b 48%, #0f172a 100%) !important;
    color: #ffffff !important;
    box-shadow: 0 26px 62px rgba(15, 23, 42, 0.24) !important;
  }

  .CLAUDETOK_badge {
    display: inline-flex !important;
    align-items: center !important;
    padding: 8px 14px !important;
    border: 1px solid rgba(255,255,255,0.35) !important;
    border-radius: 999px !important;
    background: rgba(255,255,255,0.14) !important;
    color: #ffffff !important;
    font-size: 13px !important;
    font-weight: 800 !important;
    letter-spacing: -0.02em !important;
  }

  .CLAUDETOK_h1 {
    margin: 22px 0 18px !important;
    font-size: clamp(31px, 5vw, 48px) !important;
    line-height: 1.22 !important;
    letter-spacing: -0.055em !important;
    font-weight: 900 !important;
    color: #ffffff !important;
    text-shadow: 0 3px 18px rgba(0, 0, 0, 0.34) !important;
  }

  .CLAUDETOK_hero .CLAUDETOK_h1,
  .CLAUDETOK_hero h1 {
    color: #ffffff !important;
  }

  .CLAUDETOK_lead {
    margin: 0 !important;
    max-width: 780px !important;
    color: #f8fafc !important;
    font-size: 17px !important;
    line-height: 1.9 !important;
    font-weight: 500 !important;
  }

  .CLAUDETOK_hero .CLAUDETOK_lead,
  .CLAUDETOK_hero p {
    color: #f8fafc !important;
  }

  .CLAUDETOK_meta {
    display: flex !important;
    flex-wrap: wrap !important;
    gap: 8px !important;
    margin-top: 24px !important;
  }

  .CLAUDETOK_meta span {
    padding: 8px 12px !important;
    border-radius: 999px !important;
    background: rgba(255,255,255,0.16) !important;
    color: #ffffff !important;
    font-size: 13px !important;
    font-weight: 700 !important;
  }

  .CLAUDETOK_thumbnail {
    margin: 30px auto 26px !important;
    padding: 20px !important;
    border: 1px solid #e5e7eb !important;
    border-radius: 26px !important;
    background: linear-gradient(180deg, #ffffff 0%, #f8fafc 100%) !important;
    box-shadow: 0 16px 38px rgba(15, 23, 42, 0.08) !important;
    text-align: center !important;
  }

  .CLAUDETOK_thumbnail p {
    margin: 0 !important;
  }

  .CLAUDETOK_thumbnail img {
    max-width: 100% !important;
    height: auto !important;
    border-radius: 22px !important;
    box-shadow: 0 18px 40px rgba(15, 23, 42, 0.14) !important;
  }

  .CLAUDETOK_thumbnail_caption {
    margin-top: 14px !important;
    color: #475569 !important;
    font-size: 14px !important;
    font-weight: 800 !important;
  }

  .CLAUDETOK_box {
    margin: 30px 0 !important;
    padding: 25px !important;
    border: 1px solid #e5e7eb !important;
    border-radius: 24px !important;
    background: #ffffff !important;
    box-shadow: 0 14px 34px rgba(15, 23, 42, 0.06) !important;
  }

  .CLAUDETOK_box_blue {
    border-color: #bfdbfe !important;
    background: linear-gradient(180deg, #eff6ff 0%, #ffffff 100%) !important;
  }

  .CLAUDETOK_box_yellow {
    border-color: #fde68a !important;
    background: linear-gradient(180deg, #fffbeb 0%, #ffffff 100%) !important;
  }

  .CLAUDETOK_box_dark {
    border-color: #111827 !important;
    background: #0f172a !important;
    color: #f8fafc !important;
  }

  .CLAUDETOK_box_dark p,
  .CLAUDETOK_box_dark h3 {
    color: #f8fafc !important;
  }

  .CLAUDETOK_h2 {
    margin: 50px 0 18px !important;
    padding-left: 14px !important;
    border-left: 6px solid #4f46e5 !important;
    color: #111827 !important;
    font-size: 27px !important;
    line-height: 1.42 !important;
    letter-spacing: -0.04em !important;
    font-weight: 900 !important;
  }

  .CLAUDETOK_h3 {
    margin: 30px 0 14px !important;
    color: #111827 !important;
    font-size: 21px !important;
    line-height: 1.46 !important;
    letter-spacing: -0.035em !important;
    font-weight: 850 !important;
  }

  .CLAUDETOK_p {
    margin: 13px 0 !important;
    color: #263241 !important;
    font-size: 16.5px !important;
    line-height: 1.9 !important;
    font-weight: 500 !important;
  }

  .CLAUDETOK_toc {
    display: grid !important;
    grid-template-columns: repeat(2, minmax(0, 1fr)) !important;
    gap: 12px !important;
    margin-top: 18px !important;
  }

  .CLAUDETOK_toc a {
    display: block !important;
    padding: 15px 16px !important;
    border: 1px solid #dbeafe !important;
    border-radius: 16px !important;
    background: #f8fafc !important;
    color: #1d4ed8 !important;
    text-decoration: none !important;
    font-size: 15px !important;
    font-weight: 850 !important;
    line-height: 1.5 !important;
    transition: transform .2s ease, box-shadow .2s ease, border-color .2s ease !important;
  }

  .CLAUDETOK_toc a:hover {
    transform: translateY(-2px) !important;
    border-color: #93c5fd !important;
    box-shadow: 0 12px 24px rgba(37, 99, 235, 0.12) !important;
  }

  .CLAUDETOK_table {
    width: 100% !important;
    border-collapse: collapse !important;
    margin: 20px 0 !important;
    overflow: hidden !important;
    border-radius: 18px !important;
    box-shadow: 0 0 0 1px #e5e7eb !important;
    font-size: 15px !important;
    background: #ffffff !important;
  }

  .CLAUDETOK_table th,
  .CLAUDETOK_table td {
    padding: 15px 14px !important;
    border-bottom: 1px solid #e5e7eb !important;
    vertical-align: top !important;
    text-align: left !important;
    color: #1f2937 !important;
    line-height: 1.72 !important;
  }

  .CLAUDETOK_table th {
    background: #eef2ff !important;
    color: #111827 !important;
    font-weight: 900 !important;
  }

  .CLAUDETOK_table tr:last-child td {
    border-bottom: 0 !important;
  }

  .CLAUDETOK_code {
    display: block !important;
    margin: 20px 0 !important;
    padding: 20px !important;
    border-radius: 18px !important;
    border: 1px solid #334155 !important;
    background: #0f172a !important;
    color: #f8fafc !important;
    overflow-x: auto !important;
    font-family: &quot;Cascadia Code&quot;, &quot;Consolas&quot;, &quot;Courier New&quot;, monospace !important;
    font-size: 14.5px !important;
    line-height: 1.78 !important;
    white-space: pre-wrap !important;
    word-break: break-word !important;
    box-shadow: 0 14px 32px rgba(15, 23, 42, 0.22) !important;
  }

  .CLAUDETOK_code code,
  pre.CLAUDETOK_code code,
  .CLAUDETOK_wrap pre code {
    color: #f8fafc !important;
    background: transparent !important;
    font-family: &quot;Cascadia Code&quot;, &quot;Consolas&quot;, &quot;Courier New&quot;, monospace !important;
    font-size: 14.5px !important;
    line-height: 1.78 !important;
    opacity: 1 !important;
    text-shadow: none !important;
  }

  .CLAUDETOK_list {
    margin: 16px 0 !important;
    padding: 0 !important;
    list-style: none !important;
  }

  .CLAUDETOK_list li {
    position: relative !important;
    margin: 10px 0 !important;
    padding: 14px 14px 14px 44px !important;
    border: 1px solid #e5e7eb !important;
    border-radius: 16px !important;
    background: #ffffff !important;
    color: #263241 !important;
    font-size: 15.8px !important;
    line-height: 1.72 !important;
    font-weight: 500 !important;
  }

  .CLAUDETOK_list li::before {
    content: &quot;✓&quot; !important;
    position: absolute !important;
    left: 15px !important;
    top: 14px !important;
    width: 21px !important;
    height: 21px !important;
    border-radius: 50% !important;
    background: #4f46e5 !important;
    color: #ffffff !important;
    text-align: center !important;
    line-height: 21px !important;
    font-weight: 900 !important;
    font-size: 12px !important;
  }

  .CLAUDETOK_quote {
    margin: 24px 0 !important;
    padding: 19px 21px !important;
    border-left: 6px solid #0ea5e9 !important;
    border-radius: 16px !important;
    background: #f0f9ff !important;
    color: #0f172a !important;
    font-size: 16px !important;
    line-height: 1.82 !important;
    font-weight: 800 !important;
  }

  .CLAUDETOK_note {
    margin-top: 14px !important;
    padding: 15px 17px !important;
    border-radius: 16px !important;
    background: #fefce8 !important;
    border: 1px solid #fde68a !important;
    color: #713f12 !important;
    font-size: 14.5px !important;
    line-height: 1.72 !important;
    font-weight: 700 !important;
  }

  .CLAUDETOK_tagbox {
    display: flex !important;
    flex-wrap: wrap !important;
    gap: 8px !important;
    margin-top: 14px !important;
  }

  .CLAUDETOK_tagbox span {
    padding: 8px 12px !important;
    border-radius: 999px !important;
    background: #eef2ff !important;
    color: #3730a3 !important;
    font-size: 13px !important;
    font-weight: 850 !important;
  }

  .CLAUDETOK_btnTop {
    position: fixed !important;
    right: 18px !important;
    bottom: 22px !important;
    z-index: 9999 !important;
    display: none;
    padding: 11px 14px !important;
    border: 0 !important;
    border-radius: 999px !important;
    background: #111827 !important;
    color: #ffffff !important;
    font-size: 13px !important;
    font-weight: 800 !important;
    cursor: pointer !important;
    box-shadow: 0 14px 30px rgba(15, 23, 42, 0.22) !important;
  }

  .CLAUDETOK_progress {
    position: fixed !important;
    left: 0 !important;
    top: 0 !important;
    z-index: 99999 !important;
    width: 0;
    height: 4px !important;
    background: linear-gradient(90deg, #4f46e5, #0ea5e9) !important;
  }

  @media (max-width: 760px) {
    .CLAUDETOK_wrap {
      padding: 16px 12px 40px !important;
    }

    .CLAUDETOK_hero {
      padding: 34px 22px !important;
      border-radius: 22px !important;
    }

    .CLAUDETOK_h1 {
      font-size: 30px !important;
      line-height: 1.25 !important;
    }

    .CLAUDETOK_lead {
      font-size: 15.8px !important;
    }

    .CLAUDETOK_toc {
      grid-template-columns: 1fr !important;
    }

    .CLAUDETOK_table {
      display: block !important;
      overflow-x: auto !important;
      white-space: nowrap !important;
    }

    .CLAUDETOK_h2 {
      font-size: 23px !important;
      line-height: 1.42 !important;
    }

    .CLAUDETOK_code {
      font-size: 13.5px !important;
    }
  }
&lt;/style&gt;
&lt;/div&gt;
&lt;div id=&quot;CLAUDETOK_progress&quot; class=&quot;CLAUDETOK_progress&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;article class=&quot;CLAUDETOK_wrap&quot;&gt;
&lt;section class=&quot;CLAUDETOK_hero&quot;&gt;&lt;span class=&quot;CLAUDETOK_badge&quot;&gt;Claude AI 사용량 줄이는 현실적인 방법&lt;/span&gt;
&lt;h1 class=&quot;CLAUDETOK_h1&quot;&gt;Claude AI 토큰, 생각보다 빨리 줄어든다면 이렇게 써보세요&lt;/h1&gt;
&lt;p class=&quot;CLAUDETOK_lead&quot; data-ke-size=&quot;size16&quot;&gt;Claude AI나 Claude Code를 쓰다 보면 &amp;ldquo;분명 별로 안 쓴 것 같은데 왜 벌써 사용량이 줄었지?&amp;rdquo;라는 생각이 들 때가 있습니다. 저도 개발 작업에 Claude를 붙여 쓰면서 가장 많이 신경 쓰게 된 부분이 바로 토큰과 컨텍스트 관리였습니다. 그래서 이번 글에서는 어렵게 설명하기보다, 실제로 바로 적용할 수 있는 방식으로 Claude 토큰을 아끼는 방법을 정리해보려고 합니다.&lt;/p&gt;
&lt;/section&gt;
&lt;section class=&quot;CLAUDETOK_thumbnail&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;글 상단 부분 대표 이미지.png&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/PHkxq/dJMcadaJtxS/XHxTNTjGtYqQw7AOZRZau1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/PHkxq/dJMcadaJtxS/XHxTNTjGtYqQw7AOZRZau1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/PHkxq/dJMcadaJtxS/XHxTNTjGtYqQw7AOZRZau1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FPHkxq%2FdJMcadaJtxS%2FXHxTNTjGtYqQw7AOZRZau1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;400&quot; data-filename=&quot;글 상단 부분 대표 이미지.png&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;div class=&quot;CLAUDETOK_thumbnail_caption&quot;&gt;Claude AI를 더 오래, 더 효율적으로 쓰기 위한 토큰 관리 방법&lt;/div&gt;
&lt;/section&gt;
&lt;section class=&quot;CLAUDETOK_box CLAUDETOK_box_blue&quot;&gt;
&lt;h2 class=&quot;CLAUDETOK_h2&quot; style=&quot;margin-top: 0 !important;&quot; data-ke-size=&quot;size26&quot;&gt;먼저 결론부터 이야기하면&lt;/h2&gt;
&lt;p class=&quot;CLAUDETOK_p&quot; data-ke-size=&quot;size16&quot;&gt;Claude 토큰을 아끼는 가장 좋은 방법은 단순히 질문을 짧게 쓰는 것이 아닙니다. 더 중요한 것은 Claude가 매번 다시 읽어야 하는 내용을 줄이는 것입니다.&lt;/p&gt;
&lt;p class=&quot;CLAUDETOK_p&quot; data-ke-size=&quot;size16&quot;&gt;Claude는 질문 하나만 보는 것이 아니라 이전 대화, 읽은 파일, 명령 실행 결과, 로그, 설정 파일, MCP 도구 정보까지 함께 참고할 수 있습니다. 그래서 대화가 길어지고 파일을 많이 읽을수록 토큰 사용량은 자연스럽게 늘어납니다.&lt;/p&gt;
&lt;div class=&quot;CLAUDETOK_quote&quot;&gt;쉽게 말하면, Claude에게 계속 두꺼운 참고자료를 들고 일하라고 시키면 그만큼 에너지를 더 쓰게 됩니다. 토큰 절약의 핵심은 &amp;ldquo;필요한 자료만 얇고 정확하게 건네주는 것&amp;rdquo;입니다.&lt;/div&gt;
&lt;/section&gt;
&lt;section class=&quot;CLAUDETOK_box&quot;&gt;
&lt;h2 class=&quot;CLAUDETOK_h2&quot; style=&quot;margin-top: 0 !important;&quot; data-ke-size=&quot;size26&quot;&gt;목차&lt;/h2&gt;
&lt;div class=&quot;CLAUDETOK_toc&quot;&gt;&lt;a href=&quot;#CLAUDETOK_sec01&quot;&gt;1. 토큰이 빨리 줄어드는 이유&lt;/a&gt; &lt;a href=&quot;#CLAUDETOK_sec02&quot;&gt;2. Claude Code에서 꼭 쓰면 좋은 명령어&lt;/a&gt; &lt;a href=&quot;#CLAUDETOK_sec03&quot;&gt;3. 질문을 어떻게 써야 토큰을 아낄 수 있을까?&lt;/a&gt; &lt;a href=&quot;#CLAUDETOK_sec04&quot;&gt;4. 모델 선택도 비용 관리다&lt;/a&gt; &lt;a href=&quot;#CLAUDETOK_sec05&quot;&gt;5. CLAUDE.md는 짧고 정확하게&lt;/a&gt; &lt;a href=&quot;#CLAUDETOK_sec06&quot;&gt;6. MCP와 로그는 조심해서 쓰기&lt;/a&gt; &lt;a href=&quot;#CLAUDETOK_sec07&quot;&gt;7. 프롬프트 캐싱은 언제 좋을까?&lt;/a&gt; &lt;a href=&quot;#CLAUDETOK_sec08&quot;&gt;8. 실전 체크리스트&lt;/a&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;CLAUDETOK_sec01&quot;&gt;
&lt;h2 class=&quot;CLAUDETOK_h2&quot; data-ke-size=&quot;size26&quot;&gt;1. Claude 토큰이 빨리 줄어드는 이유&lt;/h2&gt;
&lt;p class=&quot;CLAUDETOK_p&quot; data-ke-size=&quot;size16&quot;&gt;Claude를 사용할 때 토큰은 내가 입력한 질문에만 쓰이는 것이 아닙니다. Claude가 답변을 만들기 위해 참고하는 전체 문맥에 토큰이 사용됩니다.&lt;/p&gt;
&lt;table class=&quot;CLAUDETOK_table&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;구분&lt;/th&gt;
&lt;th&gt;무엇을 의미하나?&lt;/th&gt;
&lt;th&gt;왜 조심해야 하나?&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;질문 내용&lt;/td&gt;
&lt;td&gt;내가 Claude에게 직접 입력한 문장&lt;/td&gt;
&lt;td&gt;모호하게 쓰면 되묻거나 잘못 작업해서 재작업이 생깁니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;이전 대화&lt;/td&gt;
&lt;td&gt;같은 세션에 쌓인 과거 질문과 답변&lt;/td&gt;
&lt;td&gt;새 주제인데도 예전 문맥이 계속 남아 있으면 비효율적입니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;파일 내용&lt;/td&gt;
&lt;td&gt;Claude Code가 읽은 소스코드, 문서, 설정 파일&lt;/td&gt;
&lt;td&gt;전체 프로젝트를 무작정 읽히면 토큰이 빠르게 늘어납니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;터미널 결과&lt;/td&gt;
&lt;td&gt;빌드 로그, 테스트 결과, 에러 로그&lt;/td&gt;
&lt;td&gt;긴 로그를 그대로 붙이면 실제 원인보다 주변 정보가 더 많아집니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MCP 도구 정보&lt;/td&gt;
&lt;td&gt;외부 도구, DB, API 연결 정보&lt;/td&gt;
&lt;td&gt;필요 없는 도구까지 켜두면 컨텍스트 관리가 복잡해질 수 있습니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;div class=&quot;CLAUDETOK_box CLAUDETOK_box_yellow&quot;&gt;
&lt;h3 class=&quot;CLAUDETOK_h3&quot; style=&quot;margin-top: 0 !important;&quot; data-ke-size=&quot;size23&quot;&gt;제가 느낀 가장 큰 낭비 포인트&lt;/h3&gt;
&lt;p class=&quot;CLAUDETOK_p&quot; data-ke-size=&quot;size16&quot;&gt;가장 큰 낭비는 &amp;ldquo;Claude가 뭘 봐야 할지 모르는 상태&amp;rdquo;에서 작업을 시작할 때 생깁니다. 예를 들어 &amp;ldquo;프로젝트 전체 확인해서 오류 고쳐줘&amp;rdquo;라고 하면 Claude는 관련 없는 파일까지 탐색할 가능성이 큽니다. 반대로 &amp;ldquo;이 로그인 오류는 Login.tsx와 authService.ts 쪽 문제 같아. 이 두 파일 중심으로 봐줘&amp;rdquo;라고 하면 훨씬 효율적입니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;CLAUDETOK_sec02&quot;&gt;
&lt;h2 class=&quot;CLAUDETOK_h2&quot; data-ke-size=&quot;size26&quot;&gt;2. Claude Code에서 꼭 쓰면 좋은 명령어&lt;/h2&gt;
&lt;p class=&quot;CLAUDETOK_p&quot; data-ke-size=&quot;size16&quot;&gt;Claude Code를 사용한다면 아래 명령어들은 꼭 알아두는 것이 좋습니다. 특히 개발 작업을 오래 하다 보면 세션이 길어지고, 파일도 많이 읽고, 테스트 로그도 누적되기 때문에 사용량 관리가 중요해집니다.&lt;/p&gt;
&lt;table class=&quot;CLAUDETOK_table&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;명령어&lt;/th&gt;
&lt;th&gt;역할&lt;/th&gt;
&lt;th&gt;이럴 때 사용하면 좋음&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;/usage&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;현재 세션의 사용량과 비용 정보를 확인합니다.&lt;/td&gt;
&lt;td&gt;작업 전후로 사용량이 얼마나 늘었는지 확인할 때 좋습니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;/context&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;현재 컨텍스트 사용량을 시각적으로 보여줍니다.&lt;/td&gt;
&lt;td&gt;무엇 때문에 컨텍스트가 무거워졌는지 보고 싶을 때 좋습니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;/clear&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;비어 있는 새 대화로 시작합니다.&lt;/td&gt;
&lt;td&gt;완전히 다른 작업을 시작할 때 좋습니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;/compact&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;지금까지의 대화를 요약해서 컨텍스트를 확보합니다.&lt;/td&gt;
&lt;td&gt;같은 작업은 이어가야 하는데 세션이 너무 길어졌을 때 좋습니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;/model&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;사용할 Claude 모델을 변경합니다.&lt;/td&gt;
&lt;td&gt;간단한 작업과 복잡한 작업의 모델을 나누고 싶을 때 좋습니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;/effort&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;모델의 추론 강도를 조절합니다.&lt;/td&gt;
&lt;td&gt;간단한 작업에서는 낮추고, 어려운 분석에서는 높일 수 있습니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;/mcp&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;MCP 서버 연결 상태를 관리합니다.&lt;/td&gt;
&lt;td&gt;외부 도구 연결이 많을 때 점검용으로 좋습니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 class=&quot;CLAUDETOK_h3&quot; data-ke-size=&quot;size23&quot;&gt;실제로 이렇게 쓰면 편합니다&lt;/h3&gt;
&lt;pre class=&quot;CLAUDETOK_code jboss-cli&quot;&gt;&lt;code&gt;# 현재 사용량 확인
/usage

# 현재 컨텍스트가 얼마나 찼는지 확인
/context

# 완전히 다른 작업을 시작할 때
/clear

# 같은 작업을 이어가되 문맥을 줄이고 싶을 때
/compact 지금까지 수정한 파일, 남은 작업, 주의할 점 중심으로 요약해줘

# 모델 변경
/model sonnet

# 간단한 작업이면 추론 강도 낮추기
/effort medium&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;CLAUDETOK_note&quot;&gt;개인적으로는 새 기능 개발을 시작하기 전에 /clear, 긴 작업 중간에는 /compact, 사용량이 이상하게 빨리 줄어든다고 느낄 때는 /context를 먼저 확인하는 방식이 가장 편했습니다.&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;CLAUDETOK_sec03&quot;&gt;
&lt;h2 class=&quot;CLAUDETOK_h2&quot; data-ke-size=&quot;size26&quot;&gt;3. 질문을 어떻게 써야 토큰을 아낄 수 있을까?&lt;/h2&gt;
&lt;p class=&quot;CLAUDETOK_p&quot; data-ke-size=&quot;size16&quot;&gt;Claude에게 질문할 때는 짧게 쓰는 것보다 정확하게 쓰는 것이 훨씬 중요합니다. 질문이 짧아도 모호하면 Claude가 여러 방향으로 추측해야 하고, 그 과정에서 파일을 더 많이 읽거나 답변을 여러 번 다시 만들게 됩니다.&lt;/p&gt;
&lt;h3 class=&quot;CLAUDETOK_h3&quot; data-ke-size=&quot;size23&quot;&gt;아쉬운 요청 예시&lt;/h3&gt;
&lt;pre class=&quot;CLAUDETOK_code erlang&quot;&gt;&lt;code&gt;이 프로젝트 전체적으로 오류 좀 고쳐줘.
성능도 개선하고 코드도 정리해줘.&lt;/code&gt;&lt;/pre&gt;
&lt;p class=&quot;CLAUDETOK_p&quot; data-ke-size=&quot;size16&quot;&gt;이런 요청은 사람에게 말해도 범위가 너무 넓습니다. Claude 입장에서도 어디부터 봐야 할지 애매하기 때문에 불필요한 탐색이 늘어날 수 있습니다.&lt;/p&gt;
&lt;h3 class=&quot;CLAUDETOK_h3&quot; data-ke-size=&quot;size23&quot;&gt;좋은 요청 예시&lt;/h3&gt;
&lt;pre class=&quot;CLAUDETOK_code markdown&quot;&gt;&lt;code&gt;목표 : 로그인 화면에서 아이디와 비밀번호를 입력하지 않았을 때 안내 문구를 보여주고 싶어.

확인할 파일 :
- src/pages/Login.tsx
- src/services/authService.ts

조건 :
- API 응답 구조는 바꾸지 말 것
- 기존 디자인 톤은 유지할 것
- 관련 없는 파일은 수정하지 말 것

결과물 :
1. 수정한 코드
2. 수정한 파일 목록
3. 왜 이렇게 바꿨는지 설명
4. 실행해야 할 테스트 명령어&lt;/code&gt;&lt;/pre&gt;
&lt;p class=&quot;CLAUDETOK_p&quot; data-ke-size=&quot;size16&quot;&gt;이렇게 적으면 Claude가 봐야 할 범위가 줄어듭니다. 결국 토큰을 아끼는 질문은 &amp;ldquo;적게 말하는 질문&amp;rdquo;이 아니라 &amp;ldquo;헷갈리지 않게 말하는 질문&amp;rdquo;입니다.&lt;/p&gt;
&lt;h3 class=&quot;CLAUDETOK_h3&quot; data-ke-size=&quot;size23&quot;&gt;프롬프트에 넣으면 좋은 항목&lt;/h3&gt;
&lt;ul class=&quot;CLAUDETOK_list&quot; style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;목표 : &lt;/b&gt; 무엇을 해결하고 싶은지 한 문장으로 적습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;범위 : &lt;/b&gt; 확인해야 할 파일, 폴더, 기능명을 알려줍니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;제외 조건 : &lt;/b&gt; 건드리면 안 되는 파일이나 정책을 적습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;출력 형식 : &lt;/b&gt; 코드, 요약, 표, 체크리스트 등 원하는 형태를 지정합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;검증 방법 : &lt;/b&gt; 테스트 명령어, 기대 결과, 화면 조건을 알려줍니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;section id=&quot;CLAUDETOK_sec04&quot;&gt;
&lt;h2 class=&quot;CLAUDETOK_h2&quot; data-ke-size=&quot;size26&quot;&gt;4. 모델 선택도 비용 관리다&lt;/h2&gt;
&lt;p class=&quot;CLAUDETOK_p&quot; data-ke-size=&quot;size16&quot;&gt;Claude를 쓸 때 무조건 가장 강력한 모델만 쓰는 것이 정답은 아닙니다. 복잡한 설계나 깊은 분석에는 고성능 모델이 좋지만, 단순한 문서 정리나 작은 코드 수정까지 전부 고성능 모델로 처리하면 효율이 떨어질 수 있습니다.&lt;/p&gt;
&lt;table class=&quot;CLAUDETOK_table&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;상황&lt;/th&gt;
&lt;th&gt;추천 방향&lt;/th&gt;
&lt;th&gt;이유&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;짧은 요약, 단순 문장 정리&lt;/td&gt;
&lt;td&gt;가벼운 모델 사용&lt;/td&gt;
&lt;td&gt;복잡한 추론이 필요하지 않기 때문입니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;일반적인 개발 작업&lt;/td&gt;
&lt;td&gt;Sonnet 계열 중심&lt;/td&gt;
&lt;td&gt;속도와 품질의 균형이 좋습니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;복잡한 장애 분석, 구조 설계&lt;/td&gt;
&lt;td&gt;Opus 계열 또는 높은 effort&lt;/td&gt;
&lt;td&gt;깊은 추론이 필요한 작업에 적합합니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;설계와 구현을 나누는 작업&lt;/td&gt;
&lt;td&gt;계획은 강한 모델, 구현은 일반 모델&lt;/td&gt;
&lt;td&gt;비용과 품질을 함께 관리하기 좋습니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;div class=&quot;CLAUDETOK_quote&quot;&gt;제가 추천하는 방식은 처음부터 최고 모델로 끝까지 가는 방식이 아닙니다. 먼저 일반 모델로 범위를 잡고, 진짜 어려운 판단이 필요한 순간에만 강한 모델을 쓰는 방식이 더 현실적입니다.&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;CLAUDETOK_sec05&quot;&gt;
&lt;h2 class=&quot;CLAUDETOK_h2&quot; data-ke-size=&quot;size26&quot;&gt;5. CLAUDE.md는 짧고 정확하게 관리하기&lt;/h2&gt;
&lt;p class=&quot;CLAUDETOK_p&quot; data-ke-size=&quot;size16&quot;&gt;Claude Code를 쓰다 보면 프로젝트 루트에 CLAUDE.md 파일을 만들어 프로젝트 규칙을 적어두는 경우가 많습니다. 이 파일은 굉장히 유용하지만, 너무 길게 쓰면 오히려 매번 Claude가 읽어야 하는 기본 정보가 많아질 수 있습니다.&lt;/p&gt;
&lt;h3 class=&quot;CLAUDETOK_h3&quot; data-ke-size=&quot;size23&quot;&gt;좋은 CLAUDE.md의 기준&lt;/h3&gt;
&lt;ul class=&quot;CLAUDETOK_list&quot; style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프로젝트 전체에 항상 필요한 규칙만 적습니다.&lt;/li&gt;
&lt;li&gt;특정 작업에서만 필요한 설명은 별도 문서로 분리합니다.&lt;/li&gt;
&lt;li&gt;중요한 규칙은 파일 상단에 배치합니다.&lt;/li&gt;
&lt;li&gt;장황한 설명보다 명령어, 경로, 금지사항 중심으로 작성합니다.&lt;/li&gt;
&lt;li&gt;오래된 규칙은 주기적으로 정리합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 class=&quot;CLAUDETOK_h3&quot; data-ke-size=&quot;size23&quot;&gt;CLAUDE.md 예시&lt;/h3&gt;
&lt;pre class=&quot;CLAUDETOK_code markdown&quot;&gt;&lt;code&gt;# Project Guide

## Stack
- Frontend : React + TypeScript
- Backend : Node.js + Express
- Database : PostgreSQL

## Rules
- API 응답 구조는 임의로 변경하지 않는다.
- 기존 class naming 규칙을 유지한다.
- 작업 전 관련 파일을 먼저 확인하고, 최소 범위만 수정한다.
- 수정 후 변경 파일 목록과 테스트 명령어를 설명한다.

## Commands
- npm run lint
- npm run test
- npm run build&lt;/code&gt;&lt;/pre&gt;
&lt;p class=&quot;CLAUDETOK_p&quot; data-ke-size=&quot;size16&quot;&gt;핵심은 간단합니다. Claude가 매번 알아야 하는 정보만 CLAUDE.md에 두고, 나머지는 필요할 때만 불러오는 방식이 좋습니다.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;CLAUDETOK_sec06&quot;&gt;
&lt;h2 class=&quot;CLAUDETOK_h2&quot; data-ke-size=&quot;size26&quot;&gt;6. MCP와 로그는 필요한 만큼만 쓰기&lt;/h2&gt;
&lt;p class=&quot;CLAUDETOK_p&quot; data-ke-size=&quot;size16&quot;&gt;MCP는 Claude Code를 외부 도구, 데이터베이스, API, 이슈 트래커와 연결할 수 있게 해주는 강력한 기능입니다. 하지만 도구를 많이 연결한다고 무조건 좋은 것은 아닙니다. 현재 작업과 관련 없는 도구까지 많이 켜져 있으면 컨텍스트가 복잡해지고, 분석해야 할 정보도 늘어날 수 있습니다.&lt;/p&gt;
&lt;h3 class=&quot;CLAUDETOK_h3&quot; data-ke-size=&quot;size23&quot;&gt;MCP 사용 시 기억할 점&lt;/h3&gt;
&lt;ul class=&quot;CLAUDETOK_list&quot; style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;현재 작업에 필요 없는 MCP 서버는 꺼둡니다.&lt;/li&gt;
&lt;li&gt;DB 전체 스키마보다 관련 테이블만 알려줍니다.&lt;/li&gt;
&lt;li&gt;이슈 전체 목록보다 관련 이슈 번호를 지정합니다.&lt;/li&gt;
&lt;li&gt;도구 결과가 너무 길게 나오지 않도록 제한합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 class=&quot;CLAUDETOK_h3&quot; data-ke-size=&quot;size23&quot;&gt;로그 분석도 똑같습니다&lt;/h3&gt;
&lt;p class=&quot;CLAUDETOK_p&quot; data-ke-size=&quot;size16&quot;&gt;에러를 찾겠다고 서버 로그 전체를 Claude에게 넘기는 것은 비효율적입니다. 대부분은 최근 에러, 실패 구간, 예외 메시지 주변만 봐도 충분한 경우가 많습니다.&lt;/p&gt;
&lt;pre class=&quot;CLAUDETOK_code 1c&quot;&gt;&lt;code&gt;# 비효율적인 방식
전체 app.log 파일을 그대로 붙여넣기

# 조금 더 나은 방식
grep -i &quot;error\|fail\|exception&quot; app.log | tail -100

# 테스트 실패 부분만 보고 싶을 때
npm test 2&amp;gt;&amp;amp;1 | grep -A 5 -E &quot;FAIL|ERROR|Exception&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;CLAUDETOK_note&quot;&gt;로그는 많이 줄수록 좋은 것이 아니라, 원인에 가까운 부분만 주는 것이 좋습니다. Claude도 사람처럼 잡음이 많으면 핵심을 찾는 데 더 많은 비용이 듭니다.&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;CLAUDETOK_sec07&quot;&gt;
&lt;h2 class=&quot;CLAUDETOK_h2&quot; data-ke-size=&quot;size26&quot;&gt;7. 프롬프트 캐싱은 언제 좋을까?&lt;/h2&gt;
&lt;p class=&quot;CLAUDETOK_p&quot; data-ke-size=&quot;size16&quot;&gt;프롬프트 캐싱은 같은 지시문, 같은 문서, 같은 예제, 같은 배경 설명을 반복해서 사용할 때 효과가 있습니다. 특히 API로 Claude를 직접 사용하는 경우라면 캐싱 전략을 잘 설계하는 것만으로도 비용과 응답 속도 면에서 도움이 될 수 있습니다.&lt;/p&gt;
&lt;table class=&quot;CLAUDETOK_table&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;효과적인 경우&lt;/th&gt;
&lt;th&gt;효과가 적은 경우&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;항상 같은 시스템 프롬프트를 사용하는 경우&lt;/td&gt;
&lt;td&gt;매번 완전히 다른 질문을 하는 경우&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;긴 문서나 예제를 반복해서 참고하는 경우&lt;/td&gt;
&lt;td&gt;짧은 일회성 질문만 하는 경우&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;API 기반 자동화 워크플로우를 만드는 경우&lt;/td&gt;
&lt;td&gt;Claude 웹 화면에서 간단히 질문하는 정도인 경우&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;같은 코드베이스 규칙을 계속 주입하는 경우&lt;/td&gt;
&lt;td&gt;매번 다른 프로젝트를 짧게 확인하는 경우&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;div class=&quot;CLAUDETOK_box CLAUDETOK_box_dark&quot;&gt;
&lt;h3 class=&quot;CLAUDETOK_h3&quot; style=&quot;color: #ffffff !important; margin-top: 0 !important;&quot; data-ke-size=&quot;size23&quot;&gt;개발자라면 이렇게 생각하면 쉽습니다&lt;/h3&gt;
&lt;p class=&quot;CLAUDETOK_p&quot; style=&quot;color: #f8fafc !important;&quot; data-ke-size=&quot;size16&quot;&gt;반복되는 긴 입력은 캐싱하고, 단순 작업은 가벼운 모델로 보내고, 긴 로그는 미리 줄이고, 복잡한 판단만 강한 모델에게 맡기는 구조가 좋습니다. AI 사용량 최적화는 결국 &amp;ldquo;입력을 어떻게 설계하느냐&amp;rdquo;의 문제에 가깝습니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;CLAUDETOK_sec08&quot;&gt;
&lt;h2 class=&quot;CLAUDETOK_h2&quot; data-ke-size=&quot;size26&quot;&gt;8. 바로 적용할 수 있는 실전 체크리스트&lt;/h2&gt;
&lt;table class=&quot;CLAUDETOK_table&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;상황&lt;/th&gt;
&lt;th&gt;추천 행동&lt;/th&gt;
&lt;th&gt;사용하면 좋은 방법&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;새로운 작업을 시작할 때&lt;/td&gt;
&lt;td&gt;이전 문맥이 필요 없으면 새로 시작합니다.&lt;/td&gt;
&lt;td&gt;/clear&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;작업이 길어졌을 때&lt;/td&gt;
&lt;td&gt;중요 내용 중심으로 요약합니다.&lt;/td&gt;
&lt;td&gt;/compact&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;사용량이 빨리 줄어드는 느낌이 들 때&lt;/td&gt;
&lt;td&gt;현재 컨텍스트 사용량을 확인합니다.&lt;/td&gt;
&lt;td&gt;/context, /usage&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;간단한 코드 수정&lt;/td&gt;
&lt;td&gt;일반 모델과 낮은 effort를 사용합니다.&lt;/td&gt;
&lt;td&gt;/model, /effort medium&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;복잡한 설계나 장애 분석&lt;/td&gt;
&lt;td&gt;강한 모델을 잠깐 사용합니다.&lt;/td&gt;
&lt;td&gt;Opus 계열 또는 high effort&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;로그 분석&lt;/td&gt;
&lt;td&gt;전체 로그가 아니라 실패 부분만 전달합니다.&lt;/td&gt;
&lt;td&gt;grep, tail, 에러 필터링&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;프로젝트 규칙 관리&lt;/td&gt;
&lt;td&gt;CLAUDE.md를 짧게 유지합니다.&lt;/td&gt;
&lt;td&gt;핵심 규칙만 작성&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MCP 사용&lt;/td&gt;
&lt;td&gt;필요한 MCP만 연결합니다.&lt;/td&gt;
&lt;td&gt;/mcp, /context&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/section&gt;
&lt;section&gt;
&lt;h2 class=&quot;CLAUDETOK_h2&quot; data-ke-size=&quot;size26&quot;&gt;마무리 : Claude를 오래 잘 쓰려면 컨텍스트 관리가 핵심입니다&lt;/h2&gt;
&lt;p class=&quot;CLAUDETOK_p&quot; data-ke-size=&quot;size16&quot;&gt;Claude AI를 잘 쓰는 사람은 질문을 무조건 짧게 쓰는 사람이 아닙니다. Claude가 정확히 필요한 것만 보고 판단할 수 있게 정리해주는 사람입니다.&lt;/p&gt;
&lt;p class=&quot;CLAUDETOK_p&quot; data-ke-size=&quot;size16&quot;&gt;특히 Claude Code를 개발에 사용한다면 /usage, /context, /clear, /compact, /model, /effort 같은 명령어는 꼭 익혀두는 것이 좋습니다. 여기에 CLAUDE.md 정리, 로그 필터링, MCP 최소화, 명확한 프롬프트 작성까지 같이 적용하면 같은 사용량으로 훨씬 더 많은 작업을 처리할 수 있습니다.&lt;/p&gt;
&lt;div class=&quot;CLAUDETOK_quote&quot;&gt;결국 토큰을 아끼는 가장 좋은 방법은 Claude에게 일을 덜 시키는 것이 아니라, Claude가 헤매지 않도록 길을 잘 잡아주는 것입니다.&lt;/div&gt;
&lt;/section&gt;
&lt;section class=&quot;CLAUDETOK_box&quot;&gt;
&lt;h2 class=&quot;CLAUDETOK_h2&quot; style=&quot;margin-top: 0 !important;&quot; data-ke-size=&quot;size26&quot;&gt;참고하면 좋은 공식 문서&lt;/h2&gt;
&lt;p class=&quot;CLAUDETOK_p&quot; data-ke-size=&quot;size16&quot;&gt;아래 문서들은 Claude 사용량 관리와 토큰 최적화를 이해할 때 참고하기 좋습니다. Claude는 모델, 요금, 명령어, 정책이 계속 바뀔 수 있으므로 실제 적용 전 공식 문서를 한 번 더 확인하는 것이 좋습니다.&lt;/p&gt;
&lt;ul class=&quot;CLAUDETOK_list&quot; style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Claude Code Commands : &lt;/b&gt; /clear, /compact, /context, /usage, /model, /effort 등 명령어 확인&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Claude Prompt Caching : &lt;/b&gt; 반복 프롬프트와 긴 컨텍스트 비용 절감 방식 확인&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Claude Pricing : &lt;/b&gt; 모델별 입력 토큰, 출력 토큰, 캐시 비용 확인&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Claude MCP : &lt;/b&gt; 외부 도구, DB, API 연결 방식 확인&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Reddit r/ClaudeCode : &lt;/b&gt; 실제 사용자들의 토큰 사용 경험과 팁 확인&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;section class=&quot;CLAUDETOK_box CLAUDETOK_box_blue&quot;&gt;
&lt;h2 class=&quot;CLAUDETOK_h2&quot; style=&quot;margin-top: 0 !important;&quot; data-ke-size=&quot;size26&quot;&gt;글 제목 추천&lt;/h2&gt;
&lt;p class=&quot;CLAUDETOK_p&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1안 : &lt;/b&gt; Claude AI 토큰 아끼는 법 : Claude Code 사용량 줄이는 현실적인 방법&lt;/p&gt;
&lt;p class=&quot;CLAUDETOK_p&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2안 : &lt;/b&gt; Claude Code 토큰이 빨리 줄어든다면? 사용량 줄이는 설정과 팁 정리&lt;/p&gt;
&lt;p class=&quot;CLAUDETOK_p&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3안 : &lt;/b&gt; Claude AI를 오래 쓰는 방법 : 토큰 절약과 컨텍스트 관리 실전 가이드&lt;/p&gt;
&lt;h3 class=&quot;CLAUDETOK_h3&quot; data-ke-size=&quot;size23&quot;&gt;SEO 설명 문구&lt;/h3&gt;
&lt;p class=&quot;CLAUDETOK_p&quot; data-ke-size=&quot;size16&quot;&gt;Claude AI와 Claude Code를 사용할 때 토큰을 효율적으로 아끼는 방법을 정리했습니다. /usage, /context, /clear, /compact, /model, /effort 명령어 사용법부터 CLAUDE.md 관리, MCP 최적화, 프롬프트 캐싱까지 실전 중심으로 설명합니다.&lt;/p&gt;
&lt;/section&gt;
&lt;section class=&quot;CLAUDETOK_box&quot;&gt;
&lt;h2 class=&quot;CLAUDETOK_h2&quot; data-ke-size=&quot;size26&quot;&gt;이 글의 핵심 키워드&lt;/h2&gt;
&lt;div class=&quot;CLAUDETOK_tagbox&quot;&gt;&lt;span&gt;Claude AI 토큰 절약 방법&lt;/span&gt; &lt;span&gt;Claude Code 사용량 줄이기&lt;/span&gt; &lt;span&gt;Claude Code context 관리&lt;/span&gt; &lt;span&gt;Claude Code clear compact 사용법&lt;/span&gt; &lt;span&gt;Claude 프롬프트 캐싱&lt;/span&gt; &lt;span&gt;Claude Code MCP 토큰&lt;/span&gt; &lt;span&gt;CLAUDE.md 작성법&lt;/span&gt; &lt;span&gt;Claude Code 모델 선택&lt;/span&gt; &lt;span&gt;AI 코딩 도구 비용 절감&lt;/span&gt; &lt;span&gt;Claude Code 토큰 최적화&lt;/span&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;/article&gt;
&lt;p&gt;&lt;button id=&quot;CLAUDETOK_btnTop&quot; class=&quot;CLAUDETOK_btnTop&quot; type=&quot;button&quot;&gt;위로&lt;/button&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;
&lt;script&gt;
  (function () {
    const CLAUDETOK_btnTop = document.getElementById(&quot;CLAUDETOK_btnTop&quot;);
    const CLAUDETOK_progress = document.getElementById(&quot;CLAUDETOK_progress&quot;);

    function CLAUDETOK_onScroll() {
      const CLAUDETOK_scrollTop = window.scrollY || document.documentElement.scrollTop;
      const CLAUDETOK_docHeight = document.documentElement.scrollHeight - window.innerHeight;
      const CLAUDETOK_percent = CLAUDETOK_docHeight &gt; 0 ? (CLAUDETOK_scrollTop / CLAUDETOK_docHeight) * 100 : 0;

      if (CLAUDETOK_progress) {
        CLAUDETOK_progress.style.width = CLAUDETOK_percent + &quot;%&quot;;
      }

      if (CLAUDETOK_btnTop) {
        CLAUDETOK_btnTop.style.display = CLAUDETOK_scrollTop &gt; 500 ? &quot;block&quot; : &quot;none&quot;;
      }
    }

    if (CLAUDETOK_btnTop) {
      CLAUDETOK_btnTop.addEventListener(&quot;click&quot;, function () {
        window.scrollTo({ top: 0, behavior: &quot;smooth&quot; });
      });
    }

    window.addEventListener(&quot;scroll&quot;, CLAUDETOK_onScroll);
    CLAUDETOK_onScroll();
  })();
&lt;/script&gt;
&lt;/p&gt;</description>
      <category>DEVELOPMENT</category>
      <category>ai개발도구</category>
      <category>AI토큰절약</category>
      <category>anthropic claude</category>
      <category>claudeai</category>
      <category>claudecode</category>
      <category>Claude사용법</category>
      <category>Claude토큰</category>
      <category>개발자생산성</category>
      <category>클로드코드</category>
      <category>프롬프트엔지니어링</category>
      <author>간지뽕빨리턴님</author>
      <guid isPermaLink="true">https://odinbox.tistory.com/583</guid>
      <comments>https://odinbox.tistory.com/583#entry583comment</comments>
      <pubDate>Fri, 1 May 2026 09:44:17 +0900</pubDate>
    </item>
    <item>
      <title>Sentry 완벽 가이드, 에러 추적부터 성능 모니터링까지</title>
      <link>https://odinbox.tistory.com/582</link>
      <description>&lt;div id=&quot;SENTRY_docsRoot&quot; class=&quot;SENTRY_docsRoot&quot;&gt;
&lt;div id=&quot;SENTRY_readProgress&quot; class=&quot;SENTRY_readProgress&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;section id=&quot;SENTRY_docsHero&quot; class=&quot;SENTRY_docsHero&quot;&gt;
&lt;div class=&quot;SENTRY_docsHeroGrid&quot;&gt;
&lt;div class=&quot;SENTRY_docsHeroContent&quot;&gt;
&lt;div class=&quot;SENTRY_docsEyebrow&quot;&gt;SENTRY OBSERVABILITY GUIDE&lt;/div&gt;
&lt;h1 class=&quot;SENTRY_docsHeroTitle&quot;&gt;Sentry 완벽 가이드:&lt;br /&gt;에러 추적부터 성능 모니터링까지&lt;/h1&gt;
&lt;p class=&quot;SENTRY_docsHeroText&quot; data-ke-size=&quot;size16&quot;&gt;React, ASP.NET Core, API 서버 환경에서 Sentry를 활용해 운영 장애, 성능 병목, 사용자 오류 흐름, Source Map, Session Replay, 샘플링 전략까지 정리한 실무 중심 가이드입니다.&lt;/p&gt;
&lt;div class=&quot;SENTRY_docsHeroMeta&quot;&gt;
&lt;div&gt;&lt;span&gt;대상&lt;/span&gt; &lt;b&gt;Frontend &amp;middot; Backend&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;핵심&lt;/span&gt; &lt;b&gt;Error &amp;middot; Tracing &amp;middot; Replay&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;운영&lt;/span&gt; &lt;b&gt;Release &amp;middot; Sampling &amp;middot; Security&lt;/b&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;SENTRY_docsThumbPanel&quot;&gt;
&lt;div class=&quot;SENTRY_docsThumbCard&quot;&gt;
&lt;div class=&quot;SENTRY_docsThumbTop&quot;&gt;&lt;span&gt;Official Docs Style&lt;/span&gt; &lt;b&gt;Sentry&lt;/b&gt;&lt;/div&gt;
&lt;div class=&quot;SENTRY_docsThumbImage&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;글 상단 부분 대표 이미지 (2).png&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cN7e2M/dJMcaaSDkfq/GE7IsNd1nwTXOQGm4GZdHk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cN7e2M/dJMcaaSDkfq/GE7IsNd1nwTXOQGm4GZdHk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cN7e2M/dJMcaaSDkfq/GE7IsNd1nwTXOQGm4GZdHk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcN7e2M%2FdJMcaaSDkfq%2FGE7IsNd1nwTXOQGm4GZdHk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;400&quot; data-filename=&quot;글 상단 부분 대표 이미지 (2).png&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;div class=&quot;SENTRY_docsThumbBottom&quot;&gt;&lt;b&gt;Observability&lt;/b&gt; &lt;span&gt;Error Monitoring &amp;middot; Performance &amp;middot; Source Map &amp;middot; Replay&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;main class=&quot;SENTRY_docsMain&quot;&gt;
&lt;section id=&quot;SENTRY_sectionIntro&quot; class=&quot;SENTRY_docsSection&quot;&gt;
&lt;div class=&quot;SENTRY_docsLabel&quot;&gt;Introduction&lt;/div&gt;
&lt;h2 class=&quot;SENTRY_docsTitle&quot; data-ke-size=&quot;size26&quot;&gt;1. Sentry는 무엇인가&lt;/h2&gt;
&lt;p class=&quot;SENTRY_docsParagraph&quot; data-ke-size=&quot;size16&quot;&gt;Sentry는 애플리케이션에서 발생하는 오류와 성능 문제를 개발자가 빠르게 분석할 수 있도록 도와주는 관측성 플랫폼입니다. 단순히 로그를 저장하는 수준이 아니라, 어떤 사용자에게, 어떤 화면에서, 어떤 릴리스 이후, 어떤 코드 라인에서 문제가 발생했는지 추적할 수 있습니다.&lt;/p&gt;
&lt;p class=&quot;SENTRY_docsParagraph&quot; data-ke-size=&quot;size16&quot;&gt;전통적인 서버 모니터링이 CPU, 메모리, 디스크, 네트워크 같은 인프라 상태를 보는 데 집중했다면, Sentry는 실제 애플리케이션 코드와 사용자 경험에 더 가깝습니다. 프론트엔드 런타임 오류, API 실패, 느린 요청, 소스맵 기반 원본 코드 추적, 세션 리플레이 등을 통해 운영 장애 대응 속도를 높일 수 있습니다.&lt;/p&gt;
&lt;div class=&quot;SENTRY_docsInfoGrid&quot;&gt;
&lt;div class=&quot;SENTRY_docsInfoCard&quot;&gt;&lt;span&gt;01&lt;/span&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;에러 추적&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Unhandled Exception, API 실패, 런타임 오류를 자동 수집합니다.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;SENTRY_docsInfoCard&quot;&gt;&lt;span&gt;02&lt;/span&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;성능 분석&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;트랜잭션, 스팬, 느린 API, DB 병목을 추적합니다.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;SENTRY_docsInfoCard&quot;&gt;&lt;span&gt;03&lt;/span&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;릴리스 관리&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특정 배포 이후 오류가 증가했는지 확인할 수 있습니다.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;SENTRY_docsInfoCard&quot;&gt;&lt;span&gt;04&lt;/span&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;사용자 경험&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;세션 리플레이로 실제 사용자가 겪은 흐름을 재현합니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;SENTRY_sectionArchitecture&quot; class=&quot;SENTRY_docsSection&quot;&gt;
&lt;div class=&quot;SENTRY_docsLabel&quot;&gt;Architecture&lt;/div&gt;
&lt;h2 class=&quot;SENTRY_docsTitle&quot; data-ke-size=&quot;size26&quot;&gt;2. Sentry 내부 아키텍처 흐름&lt;/h2&gt;
&lt;p class=&quot;SENTRY_docsParagraph&quot; data-ke-size=&quot;size16&quot;&gt;Sentry는 SDK에서 전송된 이벤트를 바로 저장하지 않고 여러 처리 단계를 거칩니다. 대표적으로 SDK, Relay, Kafka, Ingest Consumer, Symbolicator, Snuba, ClickHouse가 이벤트 수집과 분석 과정에 관여합니다.&lt;/p&gt;
&lt;div class=&quot;SENTRY_docsFlow&quot;&gt;
&lt;div&gt;&lt;b&gt;SDK&lt;/b&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;브라우저, 모바일, 서버 런타임에서 에러와 성능 이벤트를 수집합니다.&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;&lt;b&gt;Relay&lt;/b&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DSN 검증, 할당량 체크, 샘플링, 이벤트 필터링을 수행합니다.&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;&lt;b&gt;Kafka&lt;/b&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대량 이벤트를 비동기 스트리밍 방식으로 안정적으로 전달합니다.&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;&lt;b&gt;Symbolicator&lt;/b&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;난독화된 스택 트레이스를 원본 소스 코드 라인으로 복원합니다.&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;&lt;b&gt;Snuba / ClickHouse&lt;/b&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이벤트 검색, 집계, 대시보드 분석을 위한 데이터를 저장합니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;SENTRY_docsCallout&quot;&gt;&lt;b&gt;실무 핵심&lt;/b&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Sentry는 인프라 전체를 보는 도구라기보다 애플리케이션 코드와 사용자 경험 중심의 모니터링 도구입니다. 서버 자원 모니터링은 Prometheus, Grafana, Datadog 등과 함께 구성하는 방식이 안정적입니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;SENTRY_sectionFrontend&quot; class=&quot;SENTRY_docsSection&quot;&gt;
&lt;div class=&quot;SENTRY_docsLabel&quot;&gt;Frontend&lt;/div&gt;
&lt;h2 class=&quot;SENTRY_docsTitle&quot; data-ke-size=&quot;size26&quot;&gt;3. React 프론트엔드 적용 방법&lt;/h2&gt;
&lt;p class=&quot;SENTRY_docsParagraph&quot; data-ke-size=&quot;size16&quot;&gt;React에서는 애플리케이션 진입점에서 Sentry를 초기화하고, Error Boundary, Browser Tracing, Session Replay를 함께 구성하는 방식이 일반적입니다. 운영 환경에서는 성능 트레이스 수집 비율을 낮게 설정하여 비용과 노이즈를 줄여야 합니다.&lt;/p&gt;
&lt;div class=&quot;SENTRY_codeBox&quot;&gt;
&lt;div class=&quot;SENTRY_codeHeader&quot;&gt;&lt;span&gt;React / Vite 기본 적용 예시&lt;/span&gt; &lt;button type=&quot;button&quot;&gt;복사&lt;/button&gt;&lt;/div&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;import * as Sentry from &quot;@sentry/react&quot;;

Sentry.init({
  dsn: import.meta.env.VITE_SENTRY_DSN,
  environment: import.meta.env.MODE,
  release: `frontend@${import.meta.env.VITE_APP_VERSION}`,

  integrations: [
    Sentry.browserTracingIntegration(),
    Sentry.replayIntegration()
  ],

  sampleRate: 1.0,
  tracesSampleRate: import.meta.env.MODE === &quot;production&quot; ? 0.05 : 1.0,

  replaysSessionSampleRate: 0.0,
  replaysOnErrorSampleRate: 1.0,

  beforeSend(SENTRY_event) {
    if (SENTRY_event.user) {
      delete SENTRY_event.user.email;
      delete SENTRY_event.user.ip_address;
    }

    if (SENTRY_event.request &amp;amp;&amp;amp; SENTRY_event.request.headers) {
      delete SENTRY_event.request.headers.authorization;
      delete SENTRY_event.request.headers.cookie;
    }

    return SENTRY_event;
  }
});&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h3 class=&quot;SENTRY_docsSubTitle&quot; data-ke-size=&quot;size23&quot;&gt;API 오류 수집 전략&lt;/h3&gt;
&lt;p class=&quot;SENTRY_docsParagraph&quot; data-ke-size=&quot;size16&quot;&gt;프론트엔드에서 API 오류를 단순히 콘솔에만 출력하면 운영 환경에서 원인 파악이 어렵습니다. Axios 인터셉터를 사용하면 API 실패 정보를 일관된 방식으로 Sentry에 전송할 수 있습니다.&lt;/p&gt;
&lt;div class=&quot;SENTRY_codeBox&quot;&gt;
&lt;div class=&quot;SENTRY_codeHeader&quot;&gt;&lt;span&gt;Axios Interceptor 예시&lt;/span&gt; &lt;button type=&quot;button&quot;&gt;복사&lt;/button&gt;&lt;/div&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;import axios from &quot;axios&quot;;
import * as Sentry from &quot;@sentry/react&quot;;

const SENTRY_apiClient = axios.create({
  baseURL: &quot;/api&quot;,
  timeout: 10000
});

SENTRY_apiClient.interceptors.response.use(
  function SENTRY_onSuccess(SENTRY_response) {
    return SENTRY_response;
  },
  function SENTRY_onError(SENTRY_error) {
    const SENTRY_status = SENTRY_error.response?.status || &quot;NETWORK&quot;;
    const SENTRY_method = SENTRY_error.config?.method || &quot;UNKNOWN&quot;;
    const SENTRY_url = SENTRY_error.config?.url || &quot;UNKNOWN&quot;;

    Sentry.withScope(function SENTRY_scopeHandler(SENTRY_scope) {
      SENTRY_scope.setTag(&quot;api.status&quot;, String(SENTRY_status));
      SENTRY_scope.setTag(&quot;api.method&quot;, SENTRY_method.toUpperCase());
      SENTRY_scope.setTag(&quot;api.url&quot;, SENTRY_url);

      SENTRY_scope.setFingerprint([
        &quot;api-error&quot;,
        SENTRY_method,
        String(SENTRY_status),
        SENTRY_url
      ]);

      Sentry.captureException(SENTRY_error);
    });

    return Promise.reject(SENTRY_error);
  }
);

export default SENTRY_apiClient;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;SENTRY_sectionBackend&quot; class=&quot;SENTRY_docsSection&quot;&gt;
&lt;div class=&quot;SENTRY_docsLabel&quot;&gt;Backend&lt;/div&gt;
&lt;h2 class=&quot;SENTRY_docsTitle&quot; data-ke-size=&quot;size26&quot;&gt;4. ASP.NET Core 백엔드 적용 방법&lt;/h2&gt;
&lt;p class=&quot;SENTRY_docsParagraph&quot; data-ke-size=&quot;size16&quot;&gt;백엔드에서는 Unhandled Exception, 요청 처리 시간, 외부 API 호출 실패, DB 쿼리 병목을 함께 추적하는 것이 중요합니다. 특히 운영 서버에서는 개인정보 전송 여부와 샘플링 비율을 명확하게 통제해야 합니다.&lt;/p&gt;
&lt;div class=&quot;SENTRY_codeBox&quot;&gt;
&lt;div class=&quot;SENTRY_codeHeader&quot;&gt;&lt;span&gt;ASP.NET Core Program.cs 예시&lt;/span&gt; &lt;button type=&quot;button&quot;&gt;복사&lt;/button&gt;&lt;/div&gt;
&lt;pre class=&quot;nix&quot;&gt;&lt;code&gt;var SENTRY_builder = WebApplication.CreateBuilder(args);

SENTRY_builder.WebHost.UseSentry(SENTRY_options =&amp;gt;
{
    SENTRY_options.Dsn = SENTRY_builder.Configuration[&quot;Sentry:Dsn&quot;];
    SENTRY_options.Environment = SENTRY_builder.Environment.EnvironmentName;
    SENTRY_options.Release = &quot;backend@1.0.0&quot;;

    SENTRY_options.TracesSampleRate =
        SENTRY_builder.Environment.IsProduction() ? 0.05 : 1.0;

    SENTRY_options.SendDefaultPii = false;

    SENTRY_options.BeforeSend = SENTRY_event =&amp;gt;
    {
        if (SENTRY_event.User != null)
        {
            SENTRY_event.User.Email = null;
            SENTRY_event.User.IpAddress = null;
        }

        return SENTRY_event;
    };
});

var SENTRY_app = SENTRY_builder.Build();

SENTRY_app.MapGet(&quot;/&quot;, () =&amp;gt; &quot;Sentry backend monitoring ready.&quot;);

SENTRY_app.Run();&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;SENTRY_sectionOptions&quot; class=&quot;SENTRY_docsSection&quot;&gt;
&lt;div class=&quot;SENTRY_docsLabel&quot;&gt;SDK Options&lt;/div&gt;
&lt;h2 class=&quot;SENTRY_docsTitle&quot; data-ke-size=&quot;size26&quot;&gt;5. Sentry 주요 옵션과 편리 기능 정리&lt;/h2&gt;
&lt;p class=&quot;SENTRY_docsParagraph&quot; data-ke-size=&quot;size16&quot;&gt;Sentry를 단순히 설치만 하면 운영 환경에서 원하는 수준의 관측성을 얻기 어렵습니다. 실제 서비스에서는 어떤 데이터를 수집할지, 얼마나 수집할지, 어떤 정보는 제거할지, 어떤 오류는 무시할지를 명확하게 설정해야 합니다.&lt;/p&gt;
&lt;h3 class=&quot;SENTRY_docsSubTitle&quot; data-ke-size=&quot;size23&quot;&gt;5-1. 기본 식별 옵션&lt;/h3&gt;
&lt;div class=&quot;SENTRY_docsTableWrap&quot;&gt;
&lt;table class=&quot;SENTRY_docsTable&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;옵션&lt;/th&gt;
&lt;th&gt;역할&lt;/th&gt;
&lt;th&gt;실무 권장값&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;dsn&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Sentry 프로젝트로 이벤트를 전송하기 위한 고유 주소입니다.&lt;/td&gt;
&lt;td&gt;환경변수로 관리하고 코드에 직접 하드코딩하지 않는 것이 좋습니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;environment&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;production, staging, development 같은 실행 환경을 구분합니다.&lt;/td&gt;
&lt;td&gt;운영, 테스트, 개발 환경을 반드시 분리합니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;release&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;어떤 버전에서 오류가 발생했는지 추적합니다.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;frontend@1.0.0&lt;/code&gt;, &lt;code&gt;backend@2026.04.26&lt;/code&gt;처럼 명확히 지정합니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;dist&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;같은 release 안에서 빌드 산출물을 더 세분화합니다.&lt;/td&gt;
&lt;td&gt;모바일 빌드 번호, 웹 빌드 번호, CDN 배포 번호 구분에 사용합니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class=&quot;SENTRY_docsTip&quot;&gt;&lt;b&gt;실무 팁&lt;/b&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;release 값을 지정하지 않으면 이번 배포 이후 오류가 늘었는지 추적하기 어렵습니다. 운영 배포 자동화에서는 Git Commit SHA, Git Tag, 빌드 번호 중 하나를 release 값으로 넣는 것이 좋습니다.&lt;/p&gt;
&lt;/div&gt;
&lt;h3 class=&quot;SENTRY_docsSubTitle&quot; data-ke-size=&quot;size23&quot;&gt;5-2. 에러 수집과 필터링 옵션&lt;/h3&gt;
&lt;div class=&quot;SENTRY_docsTableWrap&quot;&gt;
&lt;table class=&quot;SENTRY_docsTable&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;옵션&lt;/th&gt;
&lt;th&gt;역할&lt;/th&gt;
&lt;th&gt;주의사항&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sampleRate&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;에러 이벤트를 몇 % 수집할지 결정합니다.&lt;/td&gt;
&lt;td&gt;운영 초기에는 &lt;code&gt;1.0&lt;/code&gt;을 권장합니다. 너무 낮추면 중요한 장애를 놓칠 수 있습니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ignoreErrors&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;특정 에러 메시지를 무시합니다.&lt;/td&gt;
&lt;td&gt;브라우저 확장 프로그램 오류, 외부 스크립트 오류 제외에 유용합니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;denyUrls&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;특정 URL에서 발생한 오류를 무시합니다.&lt;/td&gt;
&lt;td&gt;광고 스크립트, 브라우저 플러그인, 외부 위젯 오류 제외에 사용합니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;allowUrls&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;허용한 URL에서 발생한 오류만 수집합니다.&lt;/td&gt;
&lt;td&gt;자사 도메인 오류만 보고 싶을 때 사용합니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;beforeSend&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;이벤트 전송 직전에 데이터를 수정하거나 폐기합니다.&lt;/td&gt;
&lt;td&gt;개인정보 제거, 특정 오류 무시, 토큰 삭제에 가장 많이 사용됩니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class=&quot;SENTRY_codeBox&quot;&gt;
&lt;div class=&quot;SENTRY_codeHeader&quot;&gt;&lt;span&gt;에러 필터링 옵션 예시&lt;/span&gt; &lt;button type=&quot;button&quot;&gt;복사&lt;/button&gt;&lt;/div&gt;
&lt;pre class=&quot;typescript&quot;&gt;&lt;code&gt;Sentry.init({
  dsn: import.meta.env.VITE_SENTRY_DSN,
  environment: import.meta.env.MODE,
  release: `frontend@${import.meta.env.VITE_APP_VERSION}`,

  sampleRate: 1.0,

  ignoreErrors: [
    &quot;ResizeObserver loop limit exceeded&quot;,
    &quot;Non-Error promise rejection captured&quot;,
    &quot;Network Error&quot;
  ],

  denyUrls: [
    /extensions\//i,
    /^chrome:\/\//i,
    /^moz-extension:\/\//i,
    /googleads/i,
    /doubleclick/i
  ],

  beforeSend(SENTRY_event, SENTRY_hint) {
    if (SENTRY_event.user) {
      delete SENTRY_event.user.email;
      delete SENTRY_event.user.ip_address;
    }

    if (SENTRY_event.request &amp;amp;&amp;amp; SENTRY_event.request.headers) {
      delete SENTRY_event.request.headers.authorization;
      delete SENTRY_event.request.headers.cookie;
      delete SENTRY_event.request.headers[&quot;x-api-key&quot;];
    }

    const SENTRY_errorMessage = SENTRY_hint.originalException?.message || &quot;&quot;;

    if (SENTRY_errorMessage.includes(&quot;사용자가 직접 취소한 요청&quot;)) {
      return null;
    }

    return SENTRY_event;
  }
});&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h3 class=&quot;SENTRY_docsSubTitle&quot; data-ke-size=&quot;size23&quot;&gt;5-3. 성능 모니터링 옵션&lt;/h3&gt;
&lt;p class=&quot;SENTRY_docsParagraph&quot; data-ke-size=&quot;size16&quot;&gt;Sentry의 성능 모니터링은 트랜잭션과 스팬을 통해 화면 로딩, API 요청, DB 처리, 외부 서비스 호출 시간을 추적합니다. 단, 모든 트랜잭션을 100% 수집하면 비용과 노이즈가 빠르게 증가할 수 있으므로 운영 환경에서는 샘플링 전략이 중요합니다.&lt;/p&gt;
&lt;div class=&quot;SENTRY_docsTableWrap&quot;&gt;
&lt;table class=&quot;SENTRY_docsTable&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;옵션&lt;/th&gt;
&lt;th&gt;역할&lt;/th&gt;
&lt;th&gt;권장 사용 방식&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;tracesSampleRate&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;성능 트랜잭션 수집 비율을 설정합니다.&lt;/td&gt;
&lt;td&gt;운영 환경에서는 &lt;code&gt;0.05&lt;/code&gt; ~ &lt;code&gt;0.1&lt;/code&gt;부터 시작합니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;tracesSampler&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;요청 조건에 따라 동적으로 수집 비율을 결정합니다.&lt;/td&gt;
&lt;td&gt;결제, 로그인, 주문 같은 핵심 기능은 높게 수집하고 일반 페이지는 낮게 수집합니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;beforeSendTransaction&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;트랜잭션 전송 직전에 데이터를 수정하거나 폐기합니다.&lt;/td&gt;
&lt;td&gt;health check, static resource 요청을 제외할 때 유용합니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class=&quot;SENTRY_codeBox&quot;&gt;
&lt;div class=&quot;SENTRY_codeHeader&quot;&gt;&lt;span&gt;동적 트레이싱 샘플링 예시&lt;/span&gt; &lt;button type=&quot;button&quot;&gt;복사&lt;/button&gt;&lt;/div&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;Sentry.init({
  dsn: import.meta.env.VITE_SENTRY_DSN,

  integrations: [
    Sentry.browserTracingIntegration()
  ],

  tracesSampler(SENTRY_samplingContext) {
    const SENTRY_transactionName = SENTRY_samplingContext.name || &quot;&quot;;

    if (
      SENTRY_transactionName.includes(&quot;/payment&quot;) ||
      SENTRY_transactionName.includes(&quot;/login&quot;) ||
      SENTRY_transactionName.includes(&quot;/order&quot;)
    ) {
      return 0.5;
    }

    if (SENTRY_transactionName.includes(&quot;/admin&quot;)) {
      return 0.2;
    }

    return 0.05;
  },

  beforeSendTransaction(SENTRY_transaction) {
    if (
      SENTRY_transaction.transaction === &quot;/health&quot; ||
      SENTRY_transaction.transaction === &quot;/ping&quot;
    ) {
      return null;
    }

    return SENTRY_transaction;
  }
});&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div class=&quot;SENTRY_docsWarning&quot;&gt;&lt;b&gt;주의&lt;/b&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;tracesSampleRate: 1.0&lt;/code&gt;은 모든 성능 이벤트를 수집한다는 의미입니다. 트래픽이 많은 서비스에서 무심코 1.0으로 배포하면 사용량과 비용이 빠르게 증가할 수 있습니다.&lt;/p&gt;
&lt;/div&gt;
&lt;h3 class=&quot;SENTRY_docsSubTitle&quot; data-ke-size=&quot;size23&quot;&gt;5-4. Session Replay 옵션&lt;/h3&gt;
&lt;p class=&quot;SENTRY_docsParagraph&quot; data-ke-size=&quot;size16&quot;&gt;Session Replay는 사용자가 오류를 만나기 전후에 어떤 화면을 보고, 어떤 버튼을 누르고, 어떤 네트워크 요청이 실패했는지 재현하는 기능입니다. 텍스트 로그만으로 재현하기 어려운 UI 오류를 분석할 때 매우 유용합니다.&lt;/p&gt;
&lt;div class=&quot;SENTRY_docsTableWrap&quot;&gt;
&lt;table class=&quot;SENTRY_docsTable&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;옵션&lt;/th&gt;
&lt;th&gt;역할&lt;/th&gt;
&lt;th&gt;권장값&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;replaysSessionSampleRate&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;일반 사용자 세션을 몇 % 녹화할지 결정합니다.&lt;/td&gt;
&lt;td&gt;운영에서는 &lt;code&gt;0.01&lt;/code&gt; ~ &lt;code&gt;0.05&lt;/code&gt; 또는 &lt;code&gt;0.0&lt;/code&gt;부터 시작합니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;replaysOnErrorSampleRate&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;오류가 발생한 세션을 몇 % 보관할지 결정합니다.&lt;/td&gt;
&lt;td&gt;오류 분석 목적이라면 &lt;code&gt;1.0&lt;/code&gt; 권장&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;maskAllText&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;화면의 모든 텍스트를 마스킹합니다.&lt;/td&gt;
&lt;td&gt;개인정보가 많은 서비스라면 활성화 권장&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;blockAllMedia&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;이미지, 영상 같은 미디어 노출을 차단합니다.&lt;/td&gt;
&lt;td&gt;사용자 이미지나 민감 자료가 있다면 활성화 권장&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class=&quot;SENTRY_codeBox&quot;&gt;
&lt;div class=&quot;SENTRY_codeHeader&quot;&gt;&lt;span&gt;Session Replay 개인정보 보호 예시&lt;/span&gt; &lt;button type=&quot;button&quot;&gt;복사&lt;/button&gt;&lt;/div&gt;
&lt;pre class=&quot;css&quot;&gt;&lt;code&gt;Sentry.init({
  dsn: import.meta.env.VITE_SENTRY_DSN,

  integrations: [
    Sentry.replayIntegration({
      maskAllText: true,
      blockAllMedia: true,

      mask: [
        &quot;.password&quot;,
        &quot;.token&quot;,
        &quot;.phone&quot;,
        &quot;.email&quot;,
        &quot;[data-private='true']&quot;
      ],

      block: [
        &quot;.payment-card-area&quot;,
        &quot;.resident-number-area&quot;,
        &quot;.secret-document-area&quot;
      ]
    })
  ],

  replaysSessionSampleRate: 0.0,
  replaysOnErrorSampleRate: 1.0
});&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h3 class=&quot;SENTRY_docsSubTitle&quot; data-ke-size=&quot;size23&quot;&gt;5-5. Breadcrumb 활용&lt;/h3&gt;
&lt;p class=&quot;SENTRY_docsParagraph&quot; data-ke-size=&quot;size16&quot;&gt;Breadcrumb는 오류가 발생하기 전 사용자가 어떤 행동을 했는지 남기는 작은 로그입니다. 페이지 이동, 버튼 클릭, 콘솔 로그, 네트워크 요청, 사용자 지정 이벤트를 순서대로 확인할 수 있습니다.&lt;/p&gt;
&lt;div class=&quot;SENTRY_codeBox&quot;&gt;
&lt;div class=&quot;SENTRY_codeHeader&quot;&gt;&lt;span&gt;Breadcrumb 활용 예시&lt;/span&gt; &lt;button type=&quot;button&quot;&gt;복사&lt;/button&gt;&lt;/div&gt;
&lt;pre class=&quot;kotlin&quot;&gt;&lt;code&gt;Sentry.init({
  dsn: import.meta.env.VITE_SENTRY_DSN,

  maxBreadcrumbs: 80,

  beforeBreadcrumb(SENTRY_breadcrumb) {
    if (
      SENTRY_breadcrumb.category === &quot;fetch&quot; ||
      SENTRY_breadcrumb.category === &quot;xhr&quot;
    ) {
      const SENTRY_url = SENTRY_breadcrumb.data?.url || &quot;&quot;;

      if (SENTRY_url.includes(&quot;/auth/token&quot;)) {
        return null;
      }
    }

    return SENTRY_breadcrumb;
  }
});

function SENTRY_onClickOrderButton(SENTRY_orderId) {
  Sentry.addBreadcrumb({
    category: &quot;order&quot;,
    message: &quot;사용자가 주문 버튼을 클릭했습니다.&quot;,
    level: &quot;info&quot;,
    data: {
      orderId: SENTRY_orderId
    }
  });
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h3 class=&quot;SENTRY_docsSubTitle&quot; data-ke-size=&quot;size23&quot;&gt;5-6. Tags, Context, User 활용&lt;/h3&gt;
&lt;p class=&quot;SENTRY_docsParagraph&quot; data-ke-size=&quot;size16&quot;&gt;Sentry에서 장애를 빠르게 찾으려면 이벤트에 부가 정보를 잘 넣어야 합니다. tag는 검색과 필터링에 좋고, context는 상세 분석에 좋으며, user는 영향받은 사용자 범위를 파악할 때 유용합니다.&lt;/p&gt;
&lt;div class=&quot;SENTRY_docsTableWrap&quot;&gt;
&lt;table class=&quot;SENTRY_docsTable&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;기능&lt;/th&gt;
&lt;th&gt;용도&lt;/th&gt;
&lt;th&gt;추천 데이터&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;setTag&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;검색과 필터링에 사용할 짧은 값&lt;/td&gt;
&lt;td&gt;화면명, API명, 고객사코드, 기능구분, 배포채널&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;setContext&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;상세 분석용 객체 데이터&lt;/td&gt;
&lt;td&gt;주문 상태, 장바구니 상태, 서버 응답 요약&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;setUser&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;영향받은 사용자 식별&lt;/td&gt;
&lt;td&gt;내부 사용자 ID. 이메일, 전화번호는 신중히 처리&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;setExtra&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;추가 디버깅 데이터&lt;/td&gt;
&lt;td&gt;임시 상태값, 계산 결과, 조건 분기 정보&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class=&quot;SENTRY_codeBox&quot;&gt;
&lt;div class=&quot;SENTRY_codeHeader&quot;&gt;&lt;span&gt;Tags / Context / User 예시&lt;/span&gt; &lt;button type=&quot;button&quot;&gt;복사&lt;/button&gt;&lt;/div&gt;
&lt;pre class=&quot;less&quot;&gt;&lt;code&gt;function SENTRY_setMonitoringContext(SENTRY_loginUser) {
  Sentry.setUser({
    id: SENTRY_loginUser.userId,
    username: SENTRY_loginUser.userName
  });

  Sentry.setTag(&quot;company.code&quot;, SENTRY_loginUser.companyCode);
  Sentry.setTag(&quot;system.name&quot;, &quot;IAMZ-BIZ&quot;);
  Sentry.setTag(&quot;screen.name&quot;, &quot;OrderCreatePage&quot;);

  Sentry.setContext(&quot;business&quot;, {
    module: &quot;order&quot;,
    feature: &quot;create-order&quot;,
    permission: SENTRY_loginUser.permissionName
  });
}

function SENTRY_captureOrderError(SENTRY_error, SENTRY_order) {
  Sentry.withScope(function (SENTRY_scope) {
    SENTRY_scope.setTag(&quot;order.status&quot;, SENTRY_order.status);
    SENTRY_scope.setContext(&quot;order&quot;, {
      orderId: SENTRY_order.orderId,
      itemCount: SENTRY_order.items.length,
      totalAmount: SENTRY_order.totalAmount
    });

    Sentry.captureException(SENTRY_error);
  });
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h3 class=&quot;SENTRY_docsSubTitle&quot; data-ke-size=&quot;size23&quot;&gt;5-7. 수동 캡처 편리 함수&lt;/h3&gt;
&lt;p class=&quot;SENTRY_docsParagraph&quot; data-ke-size=&quot;size16&quot;&gt;Sentry는 자동 오류 수집뿐 아니라 개발자가 원하는 시점에 직접 메시지, 예외, 트랜잭션 정보를 보낼 수 있습니다. 운영 중 특정 비즈니스 조건이 비정상일 때 수동 캡처를 넣어두면 장애를 더 빨리 찾을 수 있습니다.&lt;/p&gt;
&lt;div class=&quot;SENTRY_codeBox&quot;&gt;
&lt;div class=&quot;SENTRY_codeHeader&quot;&gt;&lt;span&gt;수동 캡처 함수 예시&lt;/span&gt; &lt;button type=&quot;button&quot;&gt;복사&lt;/button&gt;&lt;/div&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;function SENTRY_validateBusinessRule(SENTRY_payload) {
  if (!SENTRY_payload.customerCode) {
    Sentry.withScope(function (SENTRY_scope) {
      SENTRY_scope.setLevel(&quot;warning&quot;);
      SENTRY_scope.setTag(&quot;validation.type&quot;, &quot;missing-customer-code&quot;);
      SENTRY_scope.setContext(&quot;payload&quot;, {
        screen: &quot;OrderCreatePage&quot;,
        hasItems: SENTRY_payload.items?.length &amp;gt; 0
      });

      Sentry.captureMessage(&quot;주문 생성 요청에 고객사 코드가 없습니다.&quot;);
    });

    return false;
  }

  return true;
}

async function SENTRY_saveOrder(SENTRY_order) {
  try {
    const SENTRY_response = await fetch(&quot;/api/orders&quot;, {
      method: &quot;POST&quot;,
      body: JSON.stringify(SENTRY_order)
    });

    if (!SENTRY_response.ok) {
      throw new Error(&quot;주문 저장 API 실패&quot;);
    }
  } catch (SENTRY_error) {
    Sentry.withScope(function (SENTRY_scope) {
      SENTRY_scope.setTag(&quot;api.name&quot;, &quot;save-order&quot;);
      SENTRY_scope.setTag(&quot;order.status&quot;, SENTRY_order.status);
      SENTRY_scope.setLevel(&quot;error&quot;);

      Sentry.captureException(SENTRY_error);
    });

    throw SENTRY_error;
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h3 class=&quot;SENTRY_docsSubTitle&quot; data-ke-size=&quot;size23&quot;&gt;5-8. 운영 환경 추천 설정 조합&lt;/h3&gt;
&lt;div class=&quot;SENTRY_docsTableWrap&quot;&gt;
&lt;table class=&quot;SENTRY_docsTable&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;서비스 규모&lt;/th&gt;
&lt;th&gt;에러 수집&lt;/th&gt;
&lt;th&gt;트레이싱&lt;/th&gt;
&lt;th&gt;리플레이&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;사내 시스템 / 트래픽 낮음&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sampleRate: 1.0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;tracesSampleRate: 0.2 ~ 1.0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;replaysOnErrorSampleRate: 1.0&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;일반 B2B 서비스&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sampleRate: 1.0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;tracesSampleRate: 0.05 ~ 0.2&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;일반 세션 낮게, 오류 세션 높게&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;대규모 B2C 서비스&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sampleRate: 0.5 ~ 1.0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;tracesSampler&lt;/code&gt;로 동적 제어&lt;/td&gt;
&lt;td&gt;핵심 화면 위주로 제한&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;개인정보 민감 서비스&lt;/td&gt;
&lt;td&gt;필수 오류만 수집&lt;/td&gt;
&lt;td&gt;낮은 비율부터 시작&lt;/td&gt;
&lt;td&gt;마스킹, 블록 처리 필수&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class=&quot;SENTRY_docsFinal&quot;&gt;&lt;b&gt;실무 결론&lt;/b&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Sentry 옵션 설정의 핵심은 많이 수집하는 것이 아니라 장애 대응에 필요한 데이터를 안전하게 수집하는 것입니다. 운영 환경에서는 에러는 놓치지 않되, 트레이싱과 리플레이는 비용&amp;middot;보안&amp;middot;노이즈를 고려해 점진적으로 확대하는 전략이 좋습니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;SENTRY_sectionSourcemap&quot; class=&quot;SENTRY_docsSection&quot;&gt;
&lt;div class=&quot;SENTRY_docsLabel&quot;&gt;Source Maps&lt;/div&gt;
&lt;h2 class=&quot;SENTRY_docsTitle&quot; data-ke-size=&quot;size26&quot;&gt;6. 소스맵과 릴리스 관리&lt;/h2&gt;
&lt;p class=&quot;SENTRY_docsParagraph&quot; data-ke-size=&quot;size16&quot;&gt;프론트엔드 코드는 운영 배포 시 압축되고 난독화됩니다. 이 상태에서 오류가 발생하면 스택 트레이스가 실제 원본 코드와 다르게 보일 수 있습니다. 이를 해결하려면 빌드 시점에 Source Map을 생성하고 Sentry에 업로드해야 합니다.&lt;/p&gt;
&lt;div class=&quot;SENTRY_docsWarning&quot;&gt;&lt;b&gt;보안 주의&lt;/b&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Source Map은 원본 코드 구조를 노출할 수 있으므로 운영 서버 public 경로에 그대로 남기지 않는 것이 좋습니다. Sentry에 업로드한 뒤 삭제하거나 .map 파일 접근을 차단해야 합니다.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;SENTRY_codeBox&quot;&gt;
&lt;div class=&quot;SENTRY_codeHeader&quot;&gt;&lt;span&gt;Vite Source Map 업로드 예시&lt;/span&gt; &lt;button type=&quot;button&quot;&gt;복사&lt;/button&gt;&lt;/div&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;import { defineConfig } from &quot;vite&quot;;
import react from &quot;@vitejs/plugin-react&quot;;
import { sentryVitePlugin } from &quot;@sentry/vite-plugin&quot;;

export default defineConfig({
  build: {
    sourcemap: &quot;hidden&quot;
  },
  plugins: [
    react(),

    sentryVitePlugin({
      org: &quot;YOUR_ORG_SLUG&quot;,
      project: &quot;YOUR_PROJECT_SLUG&quot;,
      authToken: process.env.SENTRY_AUTH_TOKEN,

      sourcemaps: {
        filesToDeleteAfterUpload: [
          &quot;./dist/**/*.map&quot;
        ]
      }
    })
  ]
});&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div class=&quot;SENTRY_docsChecklist&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;릴리스 관리 체크리스트&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프론트엔드와 백엔드 release 값을 명확히 지정합니다.&lt;/li&gt;
&lt;li&gt;production, staging, development environment 값을 분리합니다.&lt;/li&gt;
&lt;li&gt;CI/CD의 SENTRY_AUTH_TOKEN은 Secret으로 관리합니다.&lt;/li&gt;
&lt;li&gt;Source Map은 Sentry 업로드 후 public 배포 경로에서 제거합니다.&lt;/li&gt;
&lt;li&gt;배포 직후 Release 화면에서 신규 오류 증가 여부를 확인합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;SENTRY_sectionTracing&quot; class=&quot;SENTRY_docsSection&quot;&gt;
&lt;div class=&quot;SENTRY_docsLabel&quot;&gt;Tracing&lt;/div&gt;
&lt;h2 class=&quot;SENTRY_docsTitle&quot; data-ke-size=&quot;size26&quot;&gt;7. 분산 트레이싱과 성능 모니터링&lt;/h2&gt;
&lt;p class=&quot;SENTRY_docsParagraph&quot; data-ke-size=&quot;size16&quot;&gt;Sentry의 성능 모니터링은 요청 하나를 Transaction으로 보고, 그 안에서 발생하는 API 호출, DB 쿼리, 외부 서비스 호출, 렌더링 작업을 Span 단위로 분석합니다.&lt;/p&gt;
&lt;div class=&quot;SENTRY_docsTableWrap&quot;&gt;
&lt;table class=&quot;SENTRY_docsTable&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;지표&lt;/th&gt;
&lt;th&gt;의미&lt;/th&gt;
&lt;th&gt;실무 활용&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Apdex&lt;/td&gt;
&lt;td&gt;사용자 만족도를 0~1 점수로 표현&lt;/td&gt;
&lt;td&gt;서비스 전체 체감 품질 판단&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;p95 / p99&lt;/td&gt;
&lt;td&gt;상위 5% 또는 1% 사용자가 겪는 느린 응답&lt;/td&gt;
&lt;td&gt;일부 사용자만 겪는 병목 추적&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Throughput&lt;/td&gt;
&lt;td&gt;분당 또는 초당 요청 처리량&lt;/td&gt;
&lt;td&gt;트래픽 급증과 장애 상관관계 분석&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Error Rate&lt;/td&gt;
&lt;td&gt;전체 요청 중 실패 비율&lt;/td&gt;
&lt;td&gt;배포 후 장애 증가 여부 확인&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;SENTRY_sectionSecurity&quot; class=&quot;SENTRY_docsSection&quot;&gt;
&lt;div class=&quot;SENTRY_docsLabel&quot;&gt;Security &amp;amp; Cost&lt;/div&gt;
&lt;h2 class=&quot;SENTRY_docsTitle&quot; data-ke-size=&quot;size26&quot;&gt;8. 도입 시 주의사항: 보안, 비용, 알림&lt;/h2&gt;
&lt;h3 class=&quot;SENTRY_docsSubTitle&quot; data-ke-size=&quot;size23&quot;&gt;개인정보와 민감정보 제거&lt;/h3&gt;
&lt;p class=&quot;SENTRY_docsParagraph&quot; data-ke-size=&quot;size16&quot;&gt;Sentry 이벤트에는 요청 정보, 사용자 정보, 브라우저 정보, 서버 컨텍스트가 포함될 수 있습니다. 이메일, IP, 인증 토큰, 쿠키, 비밀번호, 결제 정보는 전송 전 또는 저장 전 단계에서 반드시 제거해야 합니다.&lt;/p&gt;
&lt;div class=&quot;SENTRY_docsInfoGrid SENTRY_docsInfoGridThree&quot;&gt;
&lt;div class=&quot;SENTRY_docsInfoCard&quot;&gt;&lt;span&gt;Client&lt;/span&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;beforeSend&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전송 전 user, request, headers, extra 데이터를 정리합니다.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;SENTRY_docsInfoCard&quot;&gt;&lt;span&gt;Server&lt;/span&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Data Scrubbing&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Sentry 프로젝트 설정에서 저장 전 마스킹 규칙을 적용합니다.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;SENTRY_docsInfoCard&quot;&gt;&lt;span&gt;Alert&lt;/span&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Allowlist&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Slack, Email, Webhook에는 필요한 최소 정보만 전달합니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 class=&quot;SENTRY_docsSubTitle&quot; data-ke-size=&quot;size23&quot;&gt;샘플링 전략&lt;/h3&gt;
&lt;p class=&quot;SENTRY_docsParagraph&quot; data-ke-size=&quot;size16&quot;&gt;모든 성능 데이터를 100% 수집하면 비용과 노이즈가 빠르게 증가할 수 있습니다. 일반적으로 에러 이벤트는 최대한 놓치지 않도록 유지하고, 성능 트랜잭션과 세션 리플레이는 낮은 비율부터 시작하는 것이 안전합니다.&lt;/p&gt;
&lt;div class=&quot;SENTRY_docsSampling&quot;&gt;
&lt;div&gt;&lt;span&gt;에러 이벤트&lt;/span&gt; &lt;b&gt;sampleRate: 1.0&lt;/b&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;운영 초기에는 중요 장애를 놓치지 않도록 100% 수집 권장&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;&lt;span&gt;성능 트레이스&lt;/span&gt; &lt;b&gt;tracesSampleRate: 0.05 ~ 0.1&lt;/b&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;트래픽이 많은 서비스는 낮은 비율부터 시작&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;&lt;span&gt;세션 리플레이&lt;/span&gt; &lt;b&gt;replaysOnErrorSampleRate: 1.0&lt;/b&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반 세션은 낮게, 오류 발생 세션은 높게 설정&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;SENTRY_sectionFaq&quot; class=&quot;SENTRY_docsSection&quot;&gt;
&lt;div class=&quot;SENTRY_docsLabel&quot;&gt;FAQ&lt;/div&gt;
&lt;h2 class=&quot;SENTRY_docsTitle&quot; data-ke-size=&quot;size26&quot;&gt;9. 자주 묻는 질문&lt;/h2&gt;
&lt;div class=&quot;SENTRY_docsFaq&quot;&gt;&lt;details&gt;
&lt;summary&gt;Sentry는 로그 수집 도구와 무엇이 다른가요?&lt;/summary&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반 로그 수집 도구는 서버나 애플리케이션 로그를 저장하고 검색하는 데 강점이 있습니다. Sentry는 오류 이벤트를 코드 라인, 릴리스, 사용자 영향도, 성능 트랜잭션과 연결해 분석하는 데 강점이 있습니다.&lt;/p&gt;
&lt;/details&gt;&lt;details&gt;
&lt;summary&gt;운영 환경에서 tracesSampleRate를 1.0으로 설정해도 되나요?&lt;/summary&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;트래픽이 적은 내부 시스템이라면 가능하지만, 대규모 서비스에서는 비용과 노이즈가 빠르게 증가할 수 있습니다. 운영 환경에서는 0.05~0.1부터 시작하고, 핵심 기능만 tracesSampler로 높이는 방식을 권장합니다.&lt;/p&gt;
&lt;/details&gt;&lt;details&gt;
&lt;summary&gt;Source Map 파일은 서버에 배포해도 되나요?&lt;/summary&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Source Map은 원본 코드 구조를 노출할 수 있으므로 public 경로에 그대로 두는 것은 권장하지 않습니다. Sentry에 업로드한 후 삭제하거나, 웹 서버에서 .map 파일 접근을 차단하는 방식이 안전합니다.&lt;/p&gt;
&lt;/details&gt;&lt;details&gt;
&lt;summary&gt;Session Replay는 개인정보 문제가 없나요?&lt;/summary&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설정에 따라 화면 텍스트, 입력값, 미디어가 포함될 수 있으므로 개인정보 보호 설정이 필수입니다. maskAllText, blockAllMedia, block, mask 옵션을 활용해 민감 영역을 반드시 보호해야 합니다.&lt;/p&gt;
&lt;/details&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;SENTRY_sectionFinish&quot; class=&quot;SENTRY_docsSection&quot;&gt;
&lt;div class=&quot;SENTRY_docsLabel&quot;&gt;Conclusion&lt;/div&gt;
&lt;h2 class=&quot;SENTRY_docsTitle&quot; data-ke-size=&quot;size26&quot;&gt;10. 마무리&lt;/h2&gt;
&lt;p class=&quot;SENTRY_docsParagraph&quot; data-ke-size=&quot;size16&quot;&gt;Sentry를 잘 도입하면 장애 대응 방식이 바뀝니다. 사용자가 오류를 제보한 뒤 로그를 뒤지는 방식에서, 어떤 사용자에게 어떤 화면에서 어떤 배포 이후 어떤 코드가 문제였는지 먼저 확인하고 대응하는 방식으로 전환할 수 있습니다.&lt;/p&gt;
&lt;p class=&quot;SENTRY_docsParagraph&quot; data-ke-size=&quot;size16&quot;&gt;다만 Sentry는 설치만으로 끝나는 도구가 아닙니다. 릴리스 관리, Source Map 자동화, 개인정보 제거, 샘플링 정책, 알림 라우팅, 담당자 지정까지 함께 설계해야 운영 환경에서 진짜 가치가 나옵니다.&lt;/p&gt;
&lt;div class=&quot;SENTRY_docsFinal&quot;&gt;&lt;b&gt;최종 정리&lt;/b&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Sentry는 장애가 발생한 뒤 보는 로그 도구가 아니라, 장애가 사용자 경험에 미치는 영향을 코드와 배포 단위로 연결해주는 관측성 플랫폼입니다.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;SENTRY_docsTags&quot;&gt;&lt;span&gt;Sentry&lt;/span&gt; &lt;span&gt;에러모니터링&lt;/span&gt; &lt;span&gt;성능모니터링&lt;/span&gt; &lt;span&gt;APM&lt;/span&gt; &lt;span&gt;Observability&lt;/span&gt; &lt;span&gt;프론트엔드&lt;/span&gt; &lt;span&gt;백엔드&lt;/span&gt; &lt;span&gt;React&lt;/span&gt; &lt;span&gt;ASP.NETCore&lt;/span&gt; &lt;span&gt;SourceMap&lt;/span&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;SENTRY_sectionReferences&quot; class=&quot;SENTRY_docsSection SENTRY_docsReferenceSection&quot;&gt;
&lt;div class=&quot;SENTRY_docsLabel&quot;&gt;References&lt;/div&gt;
&lt;h2 class=&quot;SENTRY_docsTitle&quot; data-ke-size=&quot;size26&quot;&gt;공식 문서 참고 링크&lt;/h2&gt;
&lt;ul class=&quot;SENTRY_docsReferenceList&quot; style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.sentry.io/platforms/javascript/configuration/options/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Sentry JavaScript SDK Options&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.sentry.io/platforms/javascript/session-replay/configuration/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Sentry Session Replay Configuration&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.sentry.io/platforms/javascript/sourcemaps/uploading/vite/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Sentry Vite Source Map Upload&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.sentry.io/platforms/dotnet/guides/aspnetcore/configuration/options/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Sentry ASP.NET Core Options&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;/main&gt;&lt;/div&gt;
&lt;div&gt;
&lt;style&gt;
  #SENTRY_docsRoot,
  #SENTRY_docsRoot * {
    box-sizing: border-box !important;
  }

  #SENTRY_docsRoot {
    --SENTRY_primary: #5f4bb6;
    --SENTRY_primaryDark: #251d46;
    --SENTRY_primarySoft: #f3f0ff;
    --SENTRY_text: #111827;
    --SENTRY_muted: #5b6472;
    --SENTRY_border: #e3e7ef;
    --SENTRY_bg: #ffffff;
    --SENTRY_panel: #f8fafc;
    --SENTRY_codeBg: #0f172a;
    --SENTRY_codeHeader: #111827;
    --SENTRY_codeText: #e5e7eb;

    max-width: 1040px !important;
    margin: 0 auto !important;
    padding: 28px 16px 70px !important;
    color: var(--SENTRY_text) !important;
    font-family: &quot;Pretendard&quot;, &quot;Noto Sans KR&quot;, -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, sans-serif !important;
    line-height: 1.75 !important;
    word-break: keep-all !important;
    background: #ffffff !important;
    overflow-x: hidden !important;
  }

  #SENTRY_readProgress {
    position: fixed !important;
    top: 0 !important;
    left: 0 !important;
    z-index: 99999 !important;
    width: 0;
    height: 4px !important;
    background: linear-gradient(90deg, #5f4bb6, #8b7cf6, #38bdf8) !important;
  }

  .SENTRY_docsHero {
    overflow: hidden !important;
    position: relative !important;
    border-radius: 30px !important;
    background:
      radial-gradient(circle at 86% 12%, rgba(255,255,255,0.22), transparent 18%),
      radial-gradient(circle at 0% 100%, rgba(255,255,255,0.11), transparent 24%),
      linear-gradient(135deg, #21183e 0%, #382c66 48%, #6c5fc7 100%) !important;
    box-shadow: 0 30px 80px rgba(37, 29, 70, 0.30) !important;
  }

  .SENTRY_docsHeroGrid {
    display: grid !important;
    grid-template-columns: minmax(0, 1.45fr) minmax(300px, 0.75fr) !important;
    gap: 34px !important;
    align-items: center !important;
    padding: 58px 46px !important;
  }

  .SENTRY_docsHeroContent {
    position: relative !important;
    z-index: 2 !important;
    min-width: 0 !important;
  }

  .SENTRY_docsEyebrow {
    display: inline-flex !important;
    align-items: center !important;
    margin-bottom: 24px !important;
    padding: 8px 15px !important;
    border-radius: 999px !important;
    border: 1px solid rgba(255,255,255,0.35) !important;
    background: rgba(255,255,255,0.12) !important;
    color: #ffffff !important;
    font-size: 13px !important;
    font-weight: 900 !important;
    letter-spacing: 0.06em !important;
  }

  .SENTRY_docsHeroTitle {
    margin: 0 !important;
    max-width: 780px !important;
    color: #ffffff !important;
    font-size: clamp(34px, 5vw, 56px) !important;
    line-height: 1.14 !important;
    letter-spacing: -0.055em !important;
    font-weight: 900 !important;
  }

  .SENTRY_docsHeroText {
    max-width: 820px !important;
    margin: 24px 0 0 !important;
    color: rgba(255,255,255,0.91) !important;
    font-size: 18px !important;
    line-height: 1.8 !important;
    font-weight: 500 !important;
  }

  .SENTRY_docsHeroMeta {
    display: grid !important;
    grid-template-columns: repeat(3, minmax(0, 1fr)) !important;
    gap: 14px !important;
    margin-top: 34px !important;
  }

  .SENTRY_docsHeroMeta div {
    min-height: 106px !important;
    padding: 19px !important;
    border-radius: 20px !important;
    border: 1px solid rgba(255,255,255,0.24) !important;
    background: rgba(255,255,255,0.12) !important;
    backdrop-filter: blur(10px) !important;
  }

  .SENTRY_docsHeroMeta span {
    display: block !important;
    margin-bottom: 9px !important;
    color: rgba(255,255,255,0.72) !important;
    font-size: 13px !important;
    font-weight: 800 !important;
  }

  .SENTRY_docsHeroMeta strong {
    display: block !important;
    color: #ffffff !important;
    font-size: 16px !important;
    line-height: 1.45 !important;
    font-weight: 900 !important;
  }

  .SENTRY_docsThumbPanel {
    position: relative !important;
    z-index: 2 !important;
    min-width: 0 !important;
  }

  .SENTRY_docsThumbCard {
    position: relative !important;
    overflow: hidden !important;
    border-radius: 28px !important;
    border: 1px solid rgba(255,255,255,0.24) !important;
    background: rgba(255,255,255,0.12) !important;
    box-shadow: 0 30px 60px rgba(15, 23, 42, 0.26) !important;
    backdrop-filter: blur(12px) !important;
  }

  .SENTRY_docsThumbCard::before {
    content: &quot;&quot; !important;
    position: absolute !important;
    inset: 14px !important;
    border-radius: 22px !important;
    border: 1px solid rgba(255,255,255,0.16) !important;
    pointer-events: none !important;
  }

  .SENTRY_docsThumbTop {
    display: flex !important;
    align-items: center !important;
    justify-content: space-between !important;
    padding: 20px 22px 12px !important;
    color: #ffffff !important;
  }

  .SENTRY_docsThumbTop span {
    color: rgba(255,255,255,0.72) !important;
    font-size: 12px !important;
    font-weight: 800 !important;
    letter-spacing: 0.05em !important;
    text-transform: uppercase !important;
  }

  .SENTRY_docsThumbTop b {
    color: #ffffff !important;
    font-size: 18px !important;
    font-weight: 900 !important;
  }

  .SENTRY_docsThumbImage {
    margin: 0 auto !important;
    padding: 10px 28px 18px !important;
    text-align: center !important;
  }

  .SENTRY_docsThumbImage p {
    margin: 0 !important;
  }

  .SENTRY_docsThumbImage img,
  .SENTRY_docsThumbImage figure,
  .SENTRY_docsThumbImage .imageblock,
  .SENTRY_docsThumbImage .imageblock img {
    max-width: 100% !important;
    height: auto !important;
    margin: 0 auto !important;
    border-radius: 24px !important;
    display: block !important;
    box-shadow: 0 22px 45px rgba(0,0,0,0.24) !important;
  }

  .SENTRY_docsThumbBottom {
    padding: 0 22px 24px !important;
    text-align: left !important;
  }

  .SENTRY_docsThumbBottom strong {
    display: block !important;
    color: #ffffff !important;
    font-size: 22px !important;
    font-weight: 900 !important;
    line-height: 1.3 !important;
  }

  .SENTRY_docsThumbBottom span {
    display: block !important;
    margin-top: 6px !important;
    color: rgba(255,255,255,0.72) !important;
    font-size: 13px !important;
    line-height: 1.5 !important;
  }

  .SENTRY_docsMain {
    max-width: 860px !important;
    margin: 30px auto 0 !important;
    min-width: 0 !important;
  }

  .SENTRY_docsSection {
    margin-bottom: 26px !important;
    padding: 42px !important;
    border-radius: 28px !important;
    border: 1px solid var(--SENTRY_border) !important;
    background: #ffffff !important;
    box-shadow: 0 16px 46px rgba(15, 23, 42, 0.06) !important;
    overflow: hidden !important;
  }

  .SENTRY_docsLabel {
    display: inline-flex !important;
    margin-bottom: 14px !important;
    padding: 6px 12px !important;
    border-radius: 999px !important;
    background: var(--SENTRY_primarySoft) !important;
    color: var(--SENTRY_primary) !important;
    font-size: 12px !important;
    font-weight: 900 !important;
    letter-spacing: 0.08em !important;
    text-transform: uppercase !important;
  }

  .SENTRY_docsTitle {
    margin: 0 0 20px !important;
    padding-bottom: 14px !important;
    border-bottom: 1px solid var(--SENTRY_border) !important;
    color: #111827 !important;
    font-size: clamp(27px, 3vw, 38px) !important;
    line-height: 1.32 !important;
    letter-spacing: -0.045em !important;
    font-weight: 900 !important;
  }

  .SENTRY_docsSubTitle {
    margin: 38px 0 14px !important;
    color: var(--SENTRY_primaryDark) !important;
    font-size: 23px !important;
    line-height: 1.42 !important;
    letter-spacing: -0.035em !important;
    font-weight: 900 !important;
  }

  .SENTRY_docsParagraph {
    margin: 0 0 17px !important;
    color: #374151 !important;
    font-size: 16px !important;
    line-height: 1.95 !important;
  }

  .SENTRY_docsInfoGrid {
    display: grid !important;
    grid-template-columns: repeat(2, minmax(0, 1fr)) !important;
    gap: 16px !important;
    margin-top: 30px !important;
  }

  .SENTRY_docsInfoGridThree {
    grid-template-columns: repeat(3, minmax(0, 1fr)) !important;
  }

  .SENTRY_docsInfoCard {
    padding: 24px !important;
    border-radius: 24px !important;
    border: 1px solid #e7e3ff !important;
    background: linear-gradient(180deg, #ffffff 0%, #faf9ff 100%) !important;
    min-width: 0 !important;
  }

  .SENTRY_docsInfoCard span {
    display: inline-flex !important;
    margin-bottom: 14px !important;
    padding: 6px 10px !important;
    border-radius: 12px !important;
    background: var(--SENTRY_primary) !important;
    color: #ffffff !important;
    font-size: 12px !important;
    font-weight: 900 !important;
  }

  .SENTRY_docsInfoCard h3 {
    margin: 0 0 8px !important;
    color: #111827 !important;
    font-size: 20px !important;
    font-weight: 900 !important;
  }

  .SENTRY_docsInfoCard p {
    margin: 0 !important;
    color: var(--SENTRY_muted) !important;
    font-size: 14px !important;
    line-height: 1.75 !important;
  }

  .SENTRY_docsFlow {
    display: grid !important;
    grid-template-columns: repeat(2, minmax(0, 1fr)) !important;
    gap: 14px !important;
    margin: 30px 0 !important;
  }

  .SENTRY_docsFlow div {
    padding: 22px !important;
    border-radius: 22px !important;
    border: 1px solid var(--SENTRY_border) !important;
    background: var(--SENTRY_panel) !important;
    min-width: 0 !important;
  }

  .SENTRY_docsFlow strong {
    display: block !important;
    margin-bottom: 8px !important;
    color: var(--SENTRY_primaryDark) !important;
    font-size: 17px !important;
    font-weight: 900 !important;
  }

  .SENTRY_docsFlow p {
    margin: 0 !important;
    color: #4b5563 !important;
    font-size: 14px !important;
    line-height: 1.75 !important;
  }

  .SENTRY_docsCallout,
  .SENTRY_docsWarning,
  .SENTRY_docsFinal,
  .SENTRY_docsTip {
    margin-top: 24px !important;
    padding: 22px 24px !important;
    border-radius: 20px !important;
    border: 1px solid #d8d2ff !important;
    border-left: 6px solid var(--SENTRY_primary) !important;
    background: #fbfaff !important;
  }

  .SENTRY_docsTip {
    border-color: #bfdbfe !important;
    border-left-color: #2563eb !important;
    background: #eff6ff !important;
  }

  .SENTRY_docsWarning {
    border-color: #fed7aa !important;
    border-left-color: #f97316 !important;
    background: #fff7ed !important;
  }

  .SENTRY_docsFinal {
    border-color: #bbf7d0 !important;
    border-left-color: #16a34a !important;
    background: #f0fdf4 !important;
  }

  .SENTRY_docsCallout strong,
  .SENTRY_docsWarning strong,
  .SENTRY_docsFinal strong,
  .SENTRY_docsTip strong {
    display: block !important;
    margin-bottom: 8px !important;
    color: #111827 !important;
    font-size: 17px !important;
    font-weight: 900 !important;
  }

  .SENTRY_docsCallout p,
  .SENTRY_docsWarning p,
  .SENTRY_docsFinal p,
  .SENTRY_docsTip p {
    margin: 0 !important;
    color: #374151 !important;
    font-size: 15px !important;
    line-height: 1.8 !important;
  }

  .SENTRY_codeBox {
    overflow: hidden !important;
    margin: 26px 0 34px !important;
    border-radius: 20px !important;
    border: 1px solid #1f2937 !important;
    background: var(--SENTRY_codeBg) !important;
    box-shadow: 0 18px 42px rgba(15, 23, 42, 0.22) !important;
  }

  .SENTRY_codeHeader {
    display: flex !important;
    align-items: center !important;
    justify-content: space-between !important;
    gap: 12px !important;
    padding: 14px 18px !important;
    background: var(--SENTRY_codeHeader) !important;
    border-bottom: 1px solid rgba(255,255,255,0.08) !important;
  }

  .SENTRY_codeHeader span {
    color: #f9fafb !important;
    font-size: 14px !important;
    font-weight: 900 !important;
  }

  .SENTRY_codeHeader button {
    min-width: 62px !important;
    padding: 7px 13px !important;
    border-radius: 999px !important;
    border: 1px solid rgba(196,181,253,0.6) !important;
    background: rgba(139, 92, 246, 0.18) !important;
    color: #ddd6fe !important;
    font-size: 12px !important;
    font-weight: 900 !important;
    cursor: pointer !important;
  }

  .SENTRY_codeHeader button:hover {
    background: #7c3aed !important;
    color: #ffffff !important;
  }

  .SENTRY_codeBox pre {
    margin: 0 !important;
    padding: 24px !important;
    overflow-x: auto !important;
    background: var(--SENTRY_codeBg) !important;
    color: var(--SENTRY_codeText) !important;
    font-size: 14px !important;
    line-height: 1.75 !important;
    tab-size: 2 !important;
    white-space: pre !important;
  }

  .SENTRY_codeBox code {
    display: block !important;
    margin: 0 !important;
    padding: 0 !important;
    background: transparent !important;
    color: #e5e7eb !important;
    font-family: &quot;D2Coding&quot;, &quot;Fira Code&quot;, Consolas, Monaco, monospace !important;
    font-size: 14px !important;
    line-height: 1.75 !important;
    text-shadow: none !important;
  }

  .SENTRY_docsTableWrap {
    overflow-x: auto !important;
    margin-top: 24px !important;
    border-radius: 18px !important;
    border: 1px solid var(--SENTRY_border) !important;
  }

  .SENTRY_docsTable {
    width: 100% !important;
    min-width: 720px !important;
    border-collapse: collapse !important;
    background: #ffffff !important;
  }

  .SENTRY_docsTable th {
    padding: 16px !important;
    background: var(--SENTRY_primaryDark) !important;
    color: #ffffff !important;
    font-size: 14px !important;
    text-align: left !important;
    font-weight: 900 !important;
  }

  .SENTRY_docsTable td {
    padding: 16px !important;
    border-top: 1px solid var(--SENTRY_border) !important;
    color: #374151 !important;
    font-size: 14px !important;
    line-height: 1.7 !important;
    vertical-align: top !important;
  }

  .SENTRY_docsTable code {
    display: inline-flex !important;
    align-items: center !important;
    padding: 2px 7px !important;
    border-radius: 7px !important;
    background: #f3f4f6 !important;
    color: #4c1d95 !important;
    font-family: &quot;D2Coding&quot;, &quot;Fira Code&quot;, Consolas, Monaco, monospace !important;
    font-size: 13px !important;
    font-weight: 800 !important;
    white-space: nowrap !important;
  }

  .SENTRY_docsChecklist {
    margin-top: 24px !important;
    padding: 24px !important;
    border-radius: 20px !important;
    border: 1px solid var(--SENTRY_border) !important;
    background: var(--SENTRY_panel) !important;
  }

  .SENTRY_docsChecklist h3 {
    margin: 0 0 12px !important;
    color: #111827 !important;
    font-size: 19px !important;
    font-weight: 900 !important;
  }

  .SENTRY_docsChecklist ul,
  .SENTRY_docsReferenceList {
    margin: 0 !important;
    padding-left: 22px !important;
  }

  .SENTRY_docsChecklist li,
  .SENTRY_docsReferenceList li {
    margin: 8px 0 !important;
    color: #374151 !important;
    font-size: 15px !important;
    line-height: 1.7 !important;
  }

  .SENTRY_docsReferenceList a {
    color: var(--SENTRY_primary) !important;
    font-weight: 900 !important;
    text-decoration: none !important;
  }

  .SENTRY_docsReferenceList a:hover {
    text-decoration: underline !important;
  }

  .SENTRY_docsSampling {
    display: grid !important;
    grid-template-columns: repeat(3, minmax(0, 1fr)) !important;
    gap: 14px !important;
    margin-top: 22px !important;
  }

  .SENTRY_docsSampling div {
    padding: 22px !important;
    border-radius: 20px !important;
    border: 1px solid var(--SENTRY_border) !important;
    background: #ffffff !important;
    box-shadow: 0 10px 28px rgba(15,23,42,0.05) !important;
    min-width: 0 !important;
  }

  .SENTRY_docsSampling span {
    display: inline-flex !important;
    margin-bottom: 10px !important;
    padding: 5px 10px !important;
    border-radius: 999px !important;
    background: var(--SENTRY_primarySoft) !important;
    color: var(--SENTRY_primary) !important;
    font-size: 12px !important;
    font-weight: 900 !important;
  }

  .SENTRY_docsSampling strong {
    display: block !important;
    margin-bottom: 8px !important;
    color: var(--SENTRY_primaryDark) !important;
    font-size: 17px !important;
    font-weight: 900 !important;
  }

  .SENTRY_docsSampling p {
    margin: 0 !important;
    color: #4b5563 !important;
    font-size: 14px !important;
    line-height: 1.7 !important;
  }

  .SENTRY_docsFaq {
    display: grid !important;
    gap: 12px !important;
    margin-top: 24px !important;
  }

  .SENTRY_docsFaq details {
    border: 1px solid var(--SENTRY_border) !important;
    border-radius: 18px !important;
    background: #ffffff !important;
    overflow: hidden !important;
  }

  .SENTRY_docsFaq summary {
    cursor: pointer !important;
    padding: 18px 20px !important;
    color: #111827 !important;
    font-size: 16px !important;
    font-weight: 900 !important;
    background: #f8fafc !important;
  }

  .SENTRY_docsFaq p {
    margin: 0 !important;
    padding: 18px 20px !important;
    color: #374151 !important;
    font-size: 15px !important;
    line-height: 1.8 !important;
  }

  .SENTRY_docsTags {
    display: flex !important;
    flex-wrap: wrap !important;
    gap: 9px !important;
    margin-top: 28px !important;
  }

  .SENTRY_docsTags span {
    display: inline-flex !important;
    padding: 8px 13px !important;
    border-radius: 999px !important;
    background: var(--SENTRY_primarySoft) !important;
    color: var(--SENTRY_primary) !important;
    font-size: 13px !important;
    font-weight: 900 !important;
  }

  @media (max-width: 900px) {
    .SENTRY_docsHeroGrid {
      grid-template-columns: 1fr !important;
    }

    .SENTRY_docsThumbPanel {
      max-width: 420px !important;
      margin: 0 auto !important;
      width: 100% !important;
    }

    .SENTRY_docsHeroMeta,
    .SENTRY_docsInfoGrid,
    .SENTRY_docsInfoGridThree,
    .SENTRY_docsFlow,
    .SENTRY_docsSampling {
      grid-template-columns: 1fr !important;
    }
  }

  @media (max-width: 560px) {
    #SENTRY_docsRoot {
      padding: 16px 10px 50px !important;
    }

    .SENTRY_docsHeroGrid {
      padding: 40px 22px !important;
    }

    .SENTRY_docsHeroTitle {
      font-size: 32px !important;
    }

    .SENTRY_docsHeroText {
      font-size: 15px !important;
    }

    .SENTRY_docsMain {
      margin-top: 22px !important;
    }

    .SENTRY_docsSection {
      padding: 26px 18px !important;
      border-radius: 22px !important;
    }

    .SENTRY_docsParagraph {
      font-size: 15px !important;
    }

    .SENTRY_codeBox pre,
    .SENTRY_codeBox code {
      font-size: 13px !important;
    }
  }
&lt;/style&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;
&lt;script&gt;
  function SENTRY_copyCode(SENTRY_codeId) {
    var SENTRY_codeElement = document.getElementById(SENTRY_codeId);

    if (!SENTRY_codeElement) {
      alert(&quot;복사할 코드 영역을 찾지 못했습니다.&quot;);
      return;
    }

    var SENTRY_codeText = SENTRY_codeElement.innerText;

    if (navigator.clipboard &amp;&amp; window.isSecureContext) {
      navigator.clipboard.writeText(SENTRY_codeText)
        .then(function () {
          SENTRY_showCopySuccess(SENTRY_codeId);
        })
        .catch(function () {
          SENTRY_fallbackCopy(SENTRY_codeText, SENTRY_codeId);
        });
    } else {
      SENTRY_fallbackCopy(SENTRY_codeText, SENTRY_codeId);
    }
  }

  function SENTRY_fallbackCopy(SENTRY_codeText, SENTRY_codeId) {
    var SENTRY_textarea = document.createElement(&quot;textarea&quot;);

    SENTRY_textarea.value = SENTRY_codeText;
    SENTRY_textarea.setAttribute(&quot;readonly&quot;, &quot;&quot;);
    SENTRY_textarea.style.position = &quot;fixed&quot;;
    SENTRY_textarea.style.top = &quot;-9999px&quot;;
    SENTRY_textarea.style.left = &quot;-9999px&quot;;

    document.body.appendChild(SENTRY_textarea);
    SENTRY_textarea.select();

    try {
      document.execCommand(&quot;copy&quot;);
      SENTRY_showCopySuccess(SENTRY_codeId);
    } catch (SENTRY_error) {
      alert(&quot;브라우저 정책으로 인해 복사에 실패했습니다.&quot;);
    }

    document.body.removeChild(SENTRY_textarea);
  }

  function SENTRY_showCopySuccess(SENTRY_codeId) {
    var SENTRY_buttons = document.querySelectorAll(&quot;.SENTRY_codeHeader button&quot;);

    SENTRY_buttons.forEach(function (SENTRY_button) {
      var SENTRY_onclickValue = SENTRY_button.getAttribute(&quot;onclick&quot;) || &quot;&quot;;

      if (SENTRY_onclickValue.indexOf(SENTRY_codeId) !== -1) {
        var SENTRY_originalText = SENTRY_button.innerText;

        SENTRY_button.innerText = &quot;완료&quot;;
        SENTRY_button.style.background = &quot;#16a34a&quot;;
        SENTRY_button.style.borderColor = &quot;#16a34a&quot;;
        SENTRY_button.style.color = &quot;#ffffff&quot;;

        setTimeout(function () {
          SENTRY_button.innerText = SENTRY_originalText;
          SENTRY_button.style.background = &quot;rgba(139, 92, 246, 0.18)&quot;;
          SENTRY_button.style.borderColor = &quot;rgba(196,181,253,0.6)&quot;;
          SENTRY_button.style.color = &quot;#ddd6fe&quot;;
        }, 1600);
      }
    });
  }

  function SENTRY_updateReadProgress() {
    var SENTRY_progress = document.getElementById(&quot;SENTRY_readProgress&quot;);

    if (!SENTRY_progress) {
      return;
    }

    var SENTRY_scrollTop = window.scrollY || document.documentElement.scrollTop;
    var SENTRY_docHeight = document.documentElement.scrollHeight - window.innerHeight;
    var SENTRY_progressRate = SENTRY_docHeight &gt; 0 ? (SENTRY_scrollTop / SENTRY_docHeight) * 100 : 0;

    SENTRY_progress.style.width = SENTRY_progressRate + &quot;%&quot;;
  }

  document.addEventListener(&quot;scroll&quot;, SENTRY_updateReadProgress);
  document.addEventListener(&quot;DOMContentLoaded&quot;, SENTRY_updateReadProgress);
&lt;/script&gt;
&lt;script type=&quot;application/ld+json&quot;&gt;
{
  &quot;@context&quot;: &quot;https://schema.org&quot;,
  &quot;@type&quot;: &quot;TechArticle&quot;,
  &quot;headline&quot;: &quot;Sentry 완벽 가이드: 에러 추적부터 성능 모니터링까지&quot;,
  &quot;description&quot;: &quot;React, ASP.NET Core, API 서버 환경에서 Sentry를 활용해 에러 모니터링, 성능 트레이싱, Source Map, Session Replay, 샘플링 전략을 정리한 실무 가이드입니다.&quot;,
  &quot;keywords&quot;: [
    &quot;Sentry&quot;,
    &quot;에러모니터링&quot;,
    &quot;성능모니터링&quot;,
    &quot;APM&quot;,
    &quot;Observability&quot;,
    &quot;React&quot;,
    &quot;ASP.NET Core&quot;,
    &quot;Source Map&quot;,
    &quot;Session Replay&quot;,
    &quot;분산 트레이싱&quot;
  ],
  &quot;inLanguage&quot;: &quot;ko-KR&quot;,
  &quot;author&quot;: {
    &quot;@type&quot;: &quot;Person&quot;,
    &quot;name&quot;: &quot;OdinBOX&quot;
  },
  &quot;publisher&quot;: {
    &quot;@type&quot;: &quot;Organization&quot;,
    &quot;name&quot;: &quot;OdinBOX&quot;
  }
}
&lt;/script&gt;
&lt;script type=&quot;application/ld+json&quot;&gt;
{
  &quot;@context&quot;: &quot;https://schema.org&quot;,
  &quot;@type&quot;: &quot;FAQPage&quot;,
  &quot;mainEntity&quot;: [
    {
      &quot;@type&quot;: &quot;Question&quot;,
      &quot;name&quot;: &quot;Sentry는 로그 수집 도구와 무엇이 다른가요?&quot;,
      &quot;acceptedAnswer&quot;: {
        &quot;@type&quot;: &quot;Answer&quot;,
        &quot;text&quot;: &quot;일반 로그 수집 도구는 서버나 애플리케이션 로그를 저장하고 검색하는 데 강점이 있습니다. Sentry는 오류 이벤트를 코드 라인, 릴리스, 사용자 영향도, 성능 트랜잭션과 연결해 분석하는 데 강점이 있습니다.&quot;
      }
    },
    {
      &quot;@type&quot;: &quot;Question&quot;,
      &quot;name&quot;: &quot;운영 환경에서 tracesSampleRate를 1.0으로 설정해도 되나요?&quot;,
      &quot;acceptedAnswer&quot;: {
        &quot;@type&quot;: &quot;Answer&quot;,
        &quot;text&quot;: &quot;트래픽이 적은 내부 시스템이라면 가능하지만, 대규모 서비스에서는 비용과 노이즈가 빠르게 증가할 수 있습니다. 운영 환경에서는 0.05~0.1부터 시작하고, 핵심 기능만 tracesSampler로 높이는 방식을 권장합니다.&quot;
      }
    },
    {
      &quot;@type&quot;: &quot;Question&quot;,
      &quot;name&quot;: &quot;Source Map 파일은 서버에 배포해도 되나요?&quot;,
      &quot;acceptedAnswer&quot;: {
        &quot;@type&quot;: &quot;Answer&quot;,
        &quot;text&quot;: &quot;Source Map은 원본 코드 구조를 노출할 수 있으므로 public 경로에 그대로 두는 것은 권장하지 않습니다. Sentry에 업로드한 후 삭제하거나, 웹 서버에서 .map 파일 접근을 차단하는 방식이 안전합니다.&quot;
      }
    },
    {
      &quot;@type&quot;: &quot;Question&quot;,
      &quot;name&quot;: &quot;Session Replay는 개인정보 문제가 없나요?&quot;,
      &quot;acceptedAnswer&quot;: {
        &quot;@type&quot;: &quot;Answer&quot;,
        &quot;text&quot;: &quot;설정에 따라 화면 텍스트, 입력값, 미디어가 포함될 수 있으므로 개인정보 보호 설정이 필수입니다. maskAllText, blockAllMedia, block, mask 옵션을 활용해 민감 영역을 반드시 보호해야 합니다.&quot;
      }
    }
  ]
}
&lt;/script&gt;
&lt;/p&gt;</description>
      <category>DEVELOPMENT</category>
      <category>APM</category>
      <category>asp.netcore</category>
      <category>Observability</category>
      <category>React</category>
      <category>Sentry</category>
      <category>SourceMAP</category>
      <category>백엔드</category>
      <category>성능모니터링</category>
      <category>에러모니터링</category>
      <category>프론트엔드</category>
      <author>간지뽕빨리턴님</author>
      <guid isPermaLink="true">https://odinbox.tistory.com/582</guid>
      <comments>https://odinbox.tistory.com/582#entry582comment</comments>
      <pubDate>Sun, 26 Apr 2026 20:01:02 +0900</pubDate>
    </item>
    <item>
      <title>웹 서비스 API 문서화의 표준 [Swagger와 OpenAPI]</title>
      <link>https://odinbox.tistory.com/581</link>
      <description>&lt;div&gt;
&lt;style&gt;
  :root {
    --wsinfo_bg: #f5f7fb;
    --wsinfo_surface: #ffffff;
    --wsinfo_surface_soft: #f8fbff;
    --wsinfo_text: #1a2330;
    --wsinfo_text_soft: #586577;
    --wsinfo_line: #dde6f0;
    --wsinfo_line_strong: #c8d5e4;
    --wsinfo_primary: #173b73;
    --wsinfo_primary_soft: #eef4ff;
    --wsinfo_secondary: #0f766e;
    --wsinfo_warn_bg: #fff8e8;
    --wsinfo_warn_line: #efd38c;
    --wsinfo_shadow: 0 18px 40px rgba(15, 23, 42, 0.08);
    --wsinfo_radius_xl: 28px;
    --wsinfo_radius_lg: 22px;
    --wsinfo_radius_md: 16px;
    --wsinfo_maxw: 980px;
  }

  .wsinfo_wrap,
  .wsinfo_wrap * {
    box-sizing: border-box;
  }

  .wsinfo_wrap {
    max-width: var(--wsinfo_maxw);
    margin: 0 auto;
    padding: 8px 0 42px;
    color: var(--wsinfo_text);
    font-family: -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, &quot;Apple SD Gothic Neo&quot;, &quot;Noto Sans KR&quot;, &quot;Malgun Gothic&quot;, sans-serif;
    line-height: 1.82;
    word-break: keep-all;
  }

  .wsinfo_wrap img {
    max-width: 100%;
    height: auto;
    border: 0;
  }

  .wsinfo_wrap a {
    color: var(--wsinfo_primary);
    text-decoration: none;
    border-bottom: 1px solid rgba(23, 59, 115, 0.18);
  }

  .wsinfo_hero {
    position: relative;
    overflow: hidden;
    padding: 24px 26px 30px;
    border: 1px solid var(--wsinfo_line);
    border-radius: var(--wsinfo_radius_xl);
    background:
      radial-gradient(circle at top right, rgba(23, 59, 115, 0.12), transparent 30%),
      linear-gradient(135deg, #ffffff 0%, #f7faff 58%, #eef4fb 100%);
    box-shadow: var(--wsinfo_shadow);
  }

  .wsinfo_thumb {
    margin: 0 0 18px;
    padding: 0;
    text-align: center;
  }

  .wsinfo_eyebrow {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    margin: 0 0 14px;
    padding: 7px 12px;
    border: 1px solid #cfdaea;
    border-radius: 999px;
    background: rgba(255, 255, 255, 0.88);
    color: var(--wsinfo_primary);
    font-size: 12px;
    font-weight: 800;
    letter-spacing: 0.08em;
    text-transform: uppercase;
  }

  .wsinfo_title {
    margin: 0;
    font-size: 35px;
    line-height: 1.28;
    letter-spacing: -0.03em;
    color: #0f1b2d;
  }

  .wsinfo_lead {
    margin: 16px 0 0;
    font-size: 17px;
    color: var(--wsinfo_text_soft);
  }

  .wsinfo_meta {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    margin-top: 20px;
  }

  .wsinfo_meta_item {
    display: inline-flex;
    align-items: center;
    min-height: 36px;
    padding: 8px 12px;
    border: 1px solid var(--wsinfo_line);
    border-radius: 999px;
    background: rgba(255, 255, 255, 0.84);
    color: var(--wsinfo_text_soft);
    font-size: 13px;
    font-weight: 700;
  }

  .wsinfo_notice {
    margin-top: 16px;
    padding: 14px 16px;
    border: 1px solid var(--wsinfo_warn_line);
    border-radius: var(--wsinfo_radius_md);
    background: var(--wsinfo_warn_bg);
    color: #6b5618;
    font-size: 14px;
  }

  .wsinfo_section {
    margin-top: 28px;
    padding: 28px 26px;
    border: 1px solid var(--wsinfo_line);
    border-radius: var(--wsinfo_radius_lg);
    background: var(--wsinfo_surface);
    box-shadow: 0 10px 30px rgba(15, 23, 42, 0.04);
  }

  .wsinfo_section_title {
    margin: 0 0 16px;
    font-size: 28px;
    line-height: 1.35;
    letter-spacing: -0.025em;
    color: #11223a;
  }

  .wsinfo_section_subtitle {
    margin: 0 0 16px;
    color: var(--wsinfo_text_soft);
    font-size: 15px;
  }

  .wsinfo_section p {
    margin: 0 0 14px;
    font-size: 16px;
  }

  .wsinfo_section p:last-child,
  .wsinfo_cards_item p:last-child,
  .wsinfo_steps_item p:last-child,
  .wsinfo_list li:last-child,
  .wsinfo_checklist li:last-child,
  .wsinfo_timeline_item p:last-child,
  .wsinfo_matrix_item p:last-child {
    margin-bottom: 0;
  }

  .wsinfo_point {
    color: var(--wsinfo_primary);
    font-weight: 800;
  }

  .wsinfo_divider {
    height: 1px;
    margin: 24px 0;
    background: linear-gradient(to right, transparent, #d8e3ef, transparent);
  }

  .wsinfo_grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 16px;
    margin-top: 18px;
  }

  .wsinfo_cards_item {
    padding: 18px 18px 16px;
    border: 1px solid var(--wsinfo_line);
    border-radius: var(--wsinfo_radius_md);
    background: var(--wsinfo_surface_soft);
  }

  .wsinfo_cards_kicker {
    margin: 0 0 8px;
    color: var(--wsinfo_primary);
    font-size: 12px;
    font-weight: 800;
    letter-spacing: 0.08em;
    text-transform: uppercase;
  }

  .wsinfo_cards_title {
    margin: 0 0 8px;
    font-size: 19px;
    line-height: 1.45;
    color: #12253f;
  }

  .wsinfo_cards_item p {
    margin: 0 0 10px;
    color: var(--wsinfo_text_soft);
    font-size: 15px;
  }

  .wsinfo_quote {
    margin-top: 18px;
    padding: 18px 20px;
    border-left: 4px solid var(--wsinfo_primary);
    border-radius: 0 var(--wsinfo_radius_md) var(--wsinfo_radius_md) 0;
    background: #f3f7fe;
  }

  .wsinfo_quote p {
    margin: 0;
    font-size: 16px;
    color: #1d304c;
  }

  .wsinfo_timeline {
    position: relative;
    margin: 18px 0 0;
    padding: 0;
    list-style: none;
  }

  .wsinfo_timeline::before {
    content: &quot;&quot;;
    position: absolute;
    top: 8px;
    bottom: 8px;
    left: 15px;
    width: 2px;
    background: linear-gradient(to bottom, #b8cade, #dce7f2);
  }

  .wsinfo_timeline_item {
    position: relative;
    margin: 0 0 16px;
    padding-left: 46px;
  }

  .wsinfo_timeline_item:last-child {
    margin-bottom: 0;
  }

  .wsinfo_timeline_item::before {
    content: &quot;&quot;;
    position: absolute;
    top: 8px;
    left: 8px;
    width: 16px;
    height: 16px;
    border: 3px solid #ffffff;
    border-radius: 50%;
    background: var(--wsinfo_primary);
    box-shadow: 0 0 0 1px #c0d1e2;
  }

  .wsinfo_timeline_badge {
    display: inline-block;
    margin-bottom: 4px;
    color: var(--wsinfo_primary);
    font-size: 13px;
    font-weight: 800;
  }

  .wsinfo_timeline_item p {
    margin: 0;
    font-size: 15px;
    color: var(--wsinfo_text_soft);
  }

  .wsinfo_steps {
    display: grid;
    gap: 14px;
    margin-top: 18px;
  }

  .wsinfo_steps_item {
    display: grid;
    grid-template-columns: 58px 1fr;
    gap: 14px;
    align-items: start;
    padding: 16px;
    border: 1px solid var(--wsinfo_line);
    border-radius: var(--wsinfo_radius_md);
    background: #ffffff;
  }

  .wsinfo_steps_no {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 58px;
    height: 58px;
    border-radius: 18px;
    background: var(--wsinfo_primary_soft);
    color: var(--wsinfo_primary);
    font-size: 20px;
    font-weight: 900;
  }

  .wsinfo_steps_title {
    margin: 2px 0 6px;
    font-size: 18px;
    color: #132743;
  }

  .wsinfo_steps_item p {
    margin: 0;
    font-size: 15px;
    color: var(--wsinfo_text_soft);
  }

  .wsinfo_list,
  .wsinfo_checklist {
    margin: 16px 0 0;
    padding: 0;
    list-style: none;
  }

  .wsinfo_list li,
  .wsinfo_checklist li {
    position: relative;
    margin: 0 0 12px;
    padding-left: 18px;
    color: var(--wsinfo_text_soft);
    font-size: 15px;
  }

  .wsinfo_list li::before {
    content: &quot;&quot;;
    position: absolute;
    top: 12px;
    left: 0;
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: var(--wsinfo_primary);
  }

  .wsinfo_checklist li::before {
    content: &quot;✓&quot;;
    position: absolute;
    top: 0;
    left: 0;
    color: var(--wsinfo_secondary);
    font-weight: 900;
  }

  .wsinfo_matrix {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 14px;
    margin-top: 18px;
  }

  .wsinfo_matrix_item {
    padding: 18px;
    border: 1px solid var(--wsinfo_line);
    border-radius: var(--wsinfo_radius_md);
    background: linear-gradient(180deg, #ffffff 0%, #f8fbff 100%);
  }

  .wsinfo_matrix_item h4 {
    margin: 0 0 10px;
    font-size: 18px;
    line-height: 1.4;
    color: #132743;
  }

  .wsinfo_matrix_item p {
    margin: 0;
    color: var(--wsinfo_text_soft);
    font-size: 15px;
  }

  .wsinfo_table_wrap {
    margin-top: 18px;
    overflow-x: auto;
    border: 1px solid var(--wsinfo_line);
    border-radius: var(--wsinfo_radius_md);
    background: #ffffff;
  }

  .wsinfo_table {
    width: 100%;
    min-width: 720px;
    border-collapse: collapse;
  }

  .wsinfo_table th,
  .wsinfo_table td {
    padding: 14px 14px;
    border-bottom: 1px solid var(--wsinfo_line);
    vertical-align: top;
    text-align: left;
    font-size: 14px;
    line-height: 1.7;
  }

  .wsinfo_table th {
    background: #f4f8fd;
    color: #15335f;
    font-weight: 800;
  }

  .wsinfo_table tr:last-child td {
    border-bottom: 0;
  }

  .wsinfo_footer {
    margin-top: 24px;
    padding: 18px 20px;
    border: 1px solid var(--wsinfo_line);
    border-radius: var(--wsinfo_radius_lg);
    background: #f7fbff;
    color: var(--wsinfo_text_soft);
    font-size: 14px;
  }

  @media (max-width: 860px) {
    .wsinfo_title {
      font-size: 28px;
    }

    .wsinfo_grid,
    .wsinfo_matrix {
      grid-template-columns: 1fr;
    }
  }

  @media (max-width: 560px) {
    .wsinfo_wrap {
      padding: 0 0 30px;
    }

    .wsinfo_hero,
    .wsinfo_section,
    .wsinfo_footer {
      padding-left: 18px;
      padding-right: 18px;
    }

    .wsinfo_title {
      font-size: 24px;
    }

    .wsinfo_lead,
    .wsinfo_section p {
      font-size: 15px;
    }

    .wsinfo_steps_item {
      grid-template-columns: 1fr;
    }

    .wsinfo_steps_no {
      width: 48px;
      height: 48px;
      border-radius: 14px;
      font-size: 18px;
    }
  }
&lt;/style&gt;
&lt;/div&gt;
&lt;div class=&quot;wsinfo_wrap&quot;&gt;
&lt;section class=&quot;wsinfo_hero&quot;&gt;
&lt;div class=&quot;wsinfo_thumb&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;글 상단 부분 대표 이미지 (1).png&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Rev11/dJMcagSKyWx/0kpokS7n0UpXKrjiVqqrB0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Rev11/dJMcagSKyWx/0kpokS7n0UpXKrjiVqqrB0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Rev11/dJMcagSKyWx/0kpokS7n0UpXKrjiVqqrB0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FRev11%2FdJMcagSKyWx%2F0kpokS7n0UpXKrjiVqqrB0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;400&quot; data-filename=&quot;글 상단 부분 대표 이미지 (1).png&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;div class=&quot;wsinfo_eyebrow&quot;&gt;Web Service Documentation Strategy&lt;/div&gt;
&lt;p class=&quot;wsinfo_lead&quot; data-ke-size=&quot;size16&quot;&gt;API는 이제 단순한 데이터 전달 통로가 아닙니다. 프론트엔드와 백엔드, 내부 시스템과 외부 고객사, 운영 환경과 개발 생태계를 하나로 연결하는 핵심 계약입니다. 그래서 API 문서는 부가 자료가 아니라 &lt;span class=&quot;wsinfo_point&quot;&gt;서비스 품질과 협업 수준을 드러내는 기술 자산&lt;/span&gt;이 되어야 합니다.&lt;/p&gt;
&lt;div class=&quot;wsinfo_notice&quot;&gt;수동 문서화는 빠르게 낡습니다. 실무에서는 코드와 문서가 함께 움직이는 살아있는 문서 체계가 필요합니다.&lt;/div&gt;
&lt;/section&gt;
&lt;section class=&quot;wsinfo_section&quot;&gt;
&lt;h2 class=&quot;wsinfo_section_title&quot; data-ke-size=&quot;size26&quot;&gt;왜 지금 Swagger와 OpenAPI를 다시 봐야 하는가&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현대의 웹 서비스는 단일 애플리케이션 중심에서 벗어나 다수의 서비스가 연결되는 구조로 빠르게 이동했습니다. 마이크로서비스, 외부 연동, 고객사 API 제공, 모바일 앱, 관리자 시스템, 파트너 시스템이 동시에 연결되면서 &lt;span class=&quot;wsinfo_point&quot;&gt;정확한 인터페이스 정의와 신뢰 가능한 문서&lt;/span&gt;가 없으면 개발 속도보다 장애 속도가 더 빨라집니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;과거에는 워드, 위키, 엑셀 같은 수동 방식으로 API 명세를 관리하는 경우가 많았습니다. 하지만 이 방식은 코드 변경과 문서 갱신이 분리되어 결국 죽은 문서를 양산합니다. 프론트엔드 개발자와 외부 고객사는 오래된 문서를 보고 연동하다가 오류를 만나고, 내부 개발팀은 소스와 문서를 오가며 불필요한 맥락 전환 비용을 치르게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바로 이 지점을 해결하기 위해 등장한 것이 &lt;span class=&quot;wsinfo_point&quot;&gt;OpenAPI 사양과 Swagger 생태계&lt;/span&gt;입니다. 기계와 사람이 모두 읽을 수 있는 문서를 기준으로, 문서화&amp;middot;테스트&amp;middot;모킹&amp;middot;코드 생성&amp;middot;배포 자동화까지 연결하는 방식입니다.&lt;/p&gt;
&lt;div class=&quot;wsinfo_quote&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;좋은 API 문서는 개발 결과를 설명하는 부속물이 아니라, 개발과 운영 전체를 움직이는 기준점입니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section class=&quot;wsinfo_section&quot;&gt;
&lt;h2 class=&quot;wsinfo_section_title&quot; data-ke-size=&quot;size26&quot;&gt;Swagger와 OpenAPI는 무엇이 다를까&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현업에서는 두 용어를 자주 섞어 쓰지만, 정확히 구분하면 설계와 운영 수준이 달라집니다. &lt;span class=&quot;wsinfo_point&quot;&gt;OpenAPI는 API를 기술하는 표준 사양&lt;/span&gt;이고, &lt;span class=&quot;wsinfo_point&quot;&gt;Swagger는 그 사양을 시각화하고 활용하는 도구 모음&lt;/span&gt;에 가깝습니다.&lt;/p&gt;
&lt;div class=&quot;wsinfo_grid&quot;&gt;
&lt;div class=&quot;wsinfo_cards_item&quot;&gt;
&lt;div class=&quot;wsinfo_cards_kicker&quot;&gt;OpenAPI Specification&lt;/div&gt;
&lt;h3 class=&quot;wsinfo_cards_title&quot; data-ke-size=&quot;size23&quot;&gt;API를 정의하는 공식 계약 문서&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;YAML 또는 JSON 포맷으로 작성되며, 엔드포인트, 요청 본문, 응답 스키마, 인증 방식, 서버 정보, 버전 같은 요소를 표준 형식으로 기술합니다.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;wsinfo_cards_item&quot;&gt;
&lt;div class=&quot;wsinfo_cards_kicker&quot;&gt;Swagger Tooling&lt;/div&gt;
&lt;h3 class=&quot;wsinfo_cards_title&quot; data-ke-size=&quot;size23&quot;&gt;문서를 보여주고 테스트하고 생성하는 실행 도구&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Swagger UI, Swagger Editor, Codegen 같은 도구들이 여기에 포함됩니다. 즉, 문서의 형식이 OpenAPI라면 그것을 실제 개발 경험으로 연결해 주는 계층이 Swagger입니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;wsinfo_divider&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;OpenAPI 문서의 구조는 생각보다 명확합니다. &lt;b&gt;openapi&lt;/b&gt;로 사양 버전을 명시하고, &lt;b&gt;info&lt;/b&gt;에 서비스 정보를 넣고, &lt;b&gt;servers&lt;/b&gt;에 환경별 베이스 URL을 정의하며, &lt;b&gt;paths&lt;/b&gt;에서 실제 API 경로와 메서드를 설명합니다. 그리고 &lt;b&gt;components&lt;/b&gt;에서 공통 스키마와 인증 정의를 재사용하는 구조로 설계됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실무에서 특히 중요한 부분은 components와 $ref입니다. 요청/응답 모델을 매번 반복 작성하지 않고 재사용할 수 있기 때문에, 대규모 프로젝트일수록 문서 품질과 유지보수성이 눈에 띄게 좋아집니다.&lt;/p&gt;
&lt;/section&gt;
&lt;section class=&quot;wsinfo_section&quot;&gt;
&lt;h2 class=&quot;wsinfo_section_title&quot; data-ke-size=&quot;size26&quot;&gt;Node.js와 Express에서 Swagger를 적용하는 방법&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Node.js 기반 Express 프로젝트에서는 런타임에 주석을 파싱해 명세를 만드는 방식이 일반적입니다. 실무에서 가장 많이 쓰는 조합은 &lt;span class=&quot;wsinfo_point&quot;&gt;swagger-jsdoc + swagger-ui-express&lt;/span&gt;입니다.&lt;/p&gt;
&lt;div class=&quot;wsinfo_steps&quot;&gt;
&lt;div class=&quot;wsinfo_steps_item&quot;&gt;
&lt;div class=&quot;wsinfo_steps_no&quot;&gt;01&lt;/div&gt;
&lt;div&gt;
&lt;h3 class=&quot;wsinfo_steps_title&quot; data-ke-size=&quot;size23&quot;&gt;swagger-jsdoc으로 명세 생성&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JSDoc 주석에 작성한 OpenAPI 정보를 읽어 JSON 스펙 객체로 변환합니다. openapi, info, servers, apis 경로를 설정해 문서의 뼈대를 만듭니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;wsinfo_steps_item&quot;&gt;
&lt;div class=&quot;wsinfo_steps_no&quot;&gt;02&lt;/div&gt;
&lt;div&gt;
&lt;h3 class=&quot;wsinfo_steps_title&quot; data-ke-size=&quot;size23&quot;&gt;swagger-ui-express로 UI 바인딩&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생성된 스펙을 /api-docs 같은 경로에 연결해 브라우저에서 시각적으로 확인할 수 있게 합니다. 테스트까지 가능한 인터랙티브 문서가 즉시 구성됩니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;wsinfo_steps_item&quot;&gt;
&lt;div class=&quot;wsinfo_steps_no&quot;&gt;03&lt;/div&gt;
&lt;div&gt;
&lt;h3 class=&quot;wsinfo_steps_title&quot; data-ke-size=&quot;size23&quot;&gt;라우트별 주석으로 상세 명세 작성&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 API 핸들러 상단에 @openapi 또는 @swagger 블록을 작성해 summary, tags, parameters, requestBody, responses를 기술합니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;wsinfo_steps_item&quot;&gt;
&lt;div class=&quot;wsinfo_steps_no&quot;&gt;04&lt;/div&gt;
&lt;div&gt;
&lt;h3 class=&quot;wsinfo_steps_title&quot; data-ke-size=&quot;size23&quot;&gt;복잡한 모델은 components로 분리&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;공통 응답 구조, 에러 포맷, 페이징 모델, 인증 스키마는 components에 두고 $ref로 참조하면 문서가 훨씬 읽기 쉬워지고 중복 관리도 줄어듭니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul class=&quot;wsinfo_list&quot; style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Node.js 쪽은 유연하고 빠르지만, 주석 규칙이 흐트러지면 문서 일관성이 무너지기 쉽습니다.&lt;/li&gt;
&lt;li&gt;프로젝트 초기에 tags 규칙, 응답 포맷 규칙, 에러 포맷 규칙을 먼저 통일하는 것이 좋습니다.&lt;/li&gt;
&lt;li&gt;문서 경로와 소스 경로 분리는 배포 전에 꼭 점검해야 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;section class=&quot;wsinfo_section&quot;&gt;
&lt;h2 class=&quot;wsinfo_section_title&quot; data-ke-size=&quot;size26&quot;&gt;Spring Boot 3에서는 무엇이 핵심인가&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Spring Boot 진영에서는 예전의 Springfox보다 &lt;span class=&quot;wsinfo_point&quot;&gt;springdoc-openapi&lt;/span&gt;가 사실상 표준입니다. 특히 Spring Boot 3부터는 jakarta 전환 이슈 때문에 호환성 관점에서도 springdoc-openapi 쪽이 훨씬 안정적입니다.&lt;/p&gt;
&lt;div class=&quot;wsinfo_grid&quot;&gt;
&lt;div class=&quot;wsinfo_cards_item&quot;&gt;
&lt;div class=&quot;wsinfo_cards_kicker&quot;&gt;Starter&lt;/div&gt;
&lt;h3 class=&quot;wsinfo_cards_title&quot; data-ke-size=&quot;size23&quot;&gt;의존성 추가만으로 기본 구조 활성화&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;springdoc-openapi-starter-webmvc-ui 의존성을 추가하면 별도의 복잡한 설정 없이 OpenAPI JSON과 Swagger UI 엔드포인트를 빠르게 열 수 있습니다.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;wsinfo_cards_item&quot;&gt;
&lt;div class=&quot;wsinfo_cards_kicker&quot;&gt;Annotation&lt;/div&gt;
&lt;h3 class=&quot;wsinfo_cards_title&quot; data-ke-size=&quot;size23&quot;&gt;어노테이션 기반 명세 고도화&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;@Tag, @Operation, @Schema, @SecurityRequirement 등을 활용하면 컨트롤러와 DTO 레벨에서 풍부한 설명과 예시를 체계적으로 문서화할 수 있습니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;wsinfo_divider&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제로 품질을 가르는 지점은 자동 생성 자체가 아닙니다. &lt;span class=&quot;wsinfo_point&quot;&gt;도메인 단위 그룹화, DTO 예시 데이터, 인증 요구사항, 응답 표준화&lt;/span&gt;가 얼마나 잘 정리됐는지가 중요합니다. 같은 Swagger라도 여기가 정리돼 있으면 고객사가 바로 이해할 수 있고, 정리돼 있지 않으면 내부 팀도 다시 물어보게 됩니다.&lt;/p&gt;
&lt;/section&gt;
&lt;section class=&quot;wsinfo_section&quot;&gt;
&lt;h2 class=&quot;wsinfo_section_title&quot; data-ke-size=&quot;size26&quot;&gt;.NET과 ASP.NET Core에서는 어떻게 접근해야 하나&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웹 서비스 문서화를 닷넷 관점에서 보면 버전 구분이 꽤 중요합니다. 예전에는 &lt;span class=&quot;wsinfo_point&quot;&gt;Swashbuckle.AspNetCore&lt;/span&gt;가 사실상 기본 선택지처럼 쓰였지만, 최신 ASP.NET Core에서는 &lt;span class=&quot;wsinfo_point&quot;&gt;기본 제공 OpenAPI 지원&lt;/span&gt;을 중심으로 보는 편이 더 자연스럽습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히 실무에서는 &amp;ldquo;Swagger를 붙였다&amp;rdquo;보다 &lt;span class=&quot;wsinfo_point&quot;&gt;문서 생성 계층과 UI 계층을 분리해서 이해하는 것&lt;/span&gt;이 중요합니다. 문서 생성은 ASP.NET Core의 OpenAPI 기능이 담당하고, 브라우저에서 탐색하고 테스트하는 화면은 Swagger UI, Scalar, ReDoc 같은 별도 UI 도구가 담당하는 구조로 보는 것이 맞습니다.&lt;/p&gt;
&lt;div class=&quot;wsinfo_grid&quot;&gt;
&lt;div class=&quot;wsinfo_cards_item&quot;&gt;
&lt;div class=&quot;wsinfo_cards_kicker&quot;&gt;.NET 8 이하에서 익숙한 방식&lt;/div&gt;
&lt;h3 class=&quot;wsinfo_cards_title&quot; data-ke-size=&quot;size23&quot;&gt;Swashbuckle 중심 구성&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존 ASP.NET Core 프로젝트에서는 AddSwaggerGen, UseSwagger, UseSwaggerUI 흐름이 가장 널리 쓰였습니다. 빠르게 문서를 띄우고 로컬 테스트를 붙이는 데 강점이 있어 여전히 많은 현업 프로젝트에서 사용됩니다.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;wsinfo_cards_item&quot;&gt;
&lt;div class=&quot;wsinfo_cards_kicker&quot;&gt;.NET 9 이상 최신 흐름&lt;/div&gt;
&lt;h3 class=&quot;wsinfo_cards_title&quot; data-ke-size=&quot;size23&quot;&gt;기본 제공 OpenAPI + 별도 UI&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최신 ASP.NET Core는 OpenAPI 문서 생성을 기본 제공하며, Swagger UI는 기본 내장이 아닙니다. 즉 문서 생성은 플랫폼 기본 기능으로 가져가고, UI는 필요에 따라 Swagger UI나 Scalar를 추가하는 방식이 더 깔끔합니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;wsinfo_divider&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;닷넷 관점에서 이 변화가 의미하는 바는 분명합니다. 이제는 단순히 Swagger 패키지를 붙이는 수준이 아니라, &lt;span class=&quot;wsinfo_point&quot;&gt;API 설명 메타데이터, 문서 생성, 문서 UI, 빌드 산출물, 클라이언트 코드 생성&lt;/span&gt;을 서로 분리해서 설계해야 한다는 뜻입니다.&lt;/p&gt;
&lt;/section&gt;
&lt;section class=&quot;wsinfo_section&quot;&gt;
&lt;h2 class=&quot;wsinfo_section_title&quot; data-ke-size=&quot;size26&quot;&gt;ASP.NET Core 실무에서 꼭 넣어야 할 OpenAPI 구성 요소&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;닷넷 프로젝트에서 Swagger/OpenAPI를 진짜 실무형으로 쓰려면 단순 활성화만으로는 부족합니다. 아래 항목들이 들어가야 고객사 문서, 사내 개발 문서, 운영 배포 문서가 각각 제 역할을 하게 됩니다.&lt;/p&gt;
&lt;div class=&quot;wsinfo_steps&quot;&gt;
&lt;div class=&quot;wsinfo_steps_item&quot;&gt;
&lt;div class=&quot;wsinfo_steps_no&quot;&gt;01&lt;/div&gt;
&lt;div&gt;
&lt;h3 class=&quot;wsinfo_steps_title&quot; data-ke-size=&quot;size23&quot;&gt;런타임 문서와 빌드 산출물 분리&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개발 환경에서는 런타임 OpenAPI 엔드포인트로 빠르게 확인하고, 배포 파이프라인에서는 빌드 시점에 JSON 또는 YAML 산출물을 생성해 아티팩트처럼 관리하는 구성이 좋습니다. 이렇게 해야 고객사용 정적 문서 배포나 계약 테스트 자동화가 쉬워집니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;wsinfo_steps_item&quot;&gt;
&lt;div class=&quot;wsinfo_steps_no&quot;&gt;02&lt;/div&gt;
&lt;div&gt;
&lt;h3 class=&quot;wsinfo_steps_title&quot; data-ke-size=&quot;size23&quot;&gt;XML 주석 기반 설명 강화&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;C#은 XML 문서 주석을 활용할 수 있다는 장점이 큽니다. summary, remarks, param, response, example 같은 정보를 코드에 남기면 OpenAPI 문서에 자연스럽게 녹아들고, 코드와 문서의 동기화 수준도 높아집니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;wsinfo_steps_item&quot;&gt;
&lt;div class=&quot;wsinfo_steps_no&quot;&gt;03&lt;/div&gt;
&lt;div&gt;
&lt;h3 class=&quot;wsinfo_steps_title&quot; data-ke-size=&quot;size23&quot;&gt;문서 변환기 기반 공통 규칙 적용&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최신 ASP.NET Core의 OpenAPI 기능은 문서 전체, 개별 작업, 스키마 단위로 문서를 변형할 수 있는 transformer 구조를 제공합니다. 이걸 이용하면 공통 헤더 설명, 전역 보안 요구사항, 공통 응답 설명 같은 규칙을 일괄 적용하기 좋습니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;wsinfo_steps_item&quot;&gt;
&lt;div class=&quot;wsinfo_steps_no&quot;&gt;04&lt;/div&gt;
&lt;div&gt;
&lt;h3 class=&quot;wsinfo_steps_title&quot; data-ke-size=&quot;size23&quot;&gt;UI 도구 선택 기준 분리&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Swagger UI는 테스트 중심, ReDoc은 읽기 중심, Scalar는 최신형 문서 경험에 가깝습니다. 내부 개발팀 문서와 외부 고객사 문서를 같은 UI로 고정하지 말고, 사용 목적에 따라 UI 전략을 분리하는 편이 더 실무적입니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;wsinfo_steps_item&quot;&gt;
&lt;div class=&quot;wsinfo_steps_no&quot;&gt;05&lt;/div&gt;
&lt;div&gt;
&lt;h3 class=&quot;wsinfo_steps_title&quot; data-ke-size=&quot;size23&quot;&gt;NSwag 활용 범위 검토&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;닷넷 생태계에서는 NSwag도 여전히 강력합니다. 문서 생성뿐 아니라 C# 클라이언트 코드 생성, ReDoc 제공, 외부 스펙 기반 소비자 코드 생성까지 연결할 수 있어 고객사 SDK나 내부 연동 클라이언트를 빠르게 만들 때 특히 유리합니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section class=&quot;wsinfo_section&quot;&gt;
&lt;h2 class=&quot;wsinfo_section_title&quot; data-ke-size=&quot;size26&quot;&gt;닷넷 프로젝트에서 특히 주의해야 할 포인트&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ASP.NET Core는 문서 생성 기능이 좋아진 대신, 버전별 접근 방식 차이를 이해하지 못하면 오히려 설정이 혼란스러워질 수 있습니다. 예를 들어 오래된 Swashbuckle 중심 예제를 그대로 최신 프로젝트에 복사하면 구조가 뒤섞일 수 있고, 반대로 최신 기본 제공 OpenAPI만 믿고 UI 전략을 안 세우면 고객사 전달 문서가 빈약해질 수 있습니다.&lt;/p&gt;
&lt;ul class=&quot;wsinfo_checklist&quot; style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;기존 프로젝트는 Swashbuckle 중심, 신규 최신 프로젝트는 기본 OpenAPI 중심으로 판단하는 것이 안전합니다.&lt;/li&gt;
&lt;li&gt;문서 생성과 UI는 분리해서 생각해야 운영 구조가 깔끔해집니다.&lt;/li&gt;
&lt;li&gt;빌드 시 문서 산출물을 남겨야 CI/CD와 계약 테스트 자동화가 쉬워집니다.&lt;/li&gt;
&lt;li&gt;XML 문서 주석을 적극 활용하면 닷넷 프로젝트의 문서 완성도가 확 올라갑니다.&lt;/li&gt;
&lt;li&gt;고객사 제공 문서는 public 전용 문서로 따로 생성하는 것이 가장 안전합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;wsinfo_quote&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;닷넷에서 Swagger/OpenAPI를 잘 쓴다는 것은 패키지 하나 설치하는 문제가 아니라, &lt;b&gt;플랫폼 기본 기능, UI 선택, 문서 산출물, 코드 주석, 고객사 전달 체계&lt;/b&gt;를 함께 설계하는 일에 가깝습니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section class=&quot;wsinfo_section&quot;&gt;
&lt;h2 class=&quot;wsinfo_section_title&quot; data-ke-size=&quot;size26&quot;&gt;대규모 엔터프라이즈 환경에서는 무엇을 더 고려해야 하나&lt;/h2&gt;
&lt;p class=&quot;wsinfo_section_subtitle&quot; data-ke-size=&quot;size16&quot;&gt;엔드포인트 수가 많아질수록 문서는 단순히 예쁘게 보이는 것보다 잘 나뉘고 빨리 열리고 쉽게 찾을 수 있어야 합니다.&lt;/p&gt;
&lt;div class=&quot;wsinfo_matrix&quot;&gt;
&lt;div class=&quot;wsinfo_matrix_item&quot;&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;그룹화 전략&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;tags만으로도 1차 분류는 가능하지만, admin&amp;middot;user&amp;middot;operation처럼 URL 또는 역할 기반으로 물리적으로 분리하는 편이 훨씬 강력합니다.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;wsinfo_matrix_item&quot;&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;브랜드 반영&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;외부 고객사에게 보여줄 문서는 회사의 기술 완성도를 대변합니다. 로고, 상단 색상, 파비콘, 제목까지 브랜드 일관성을 맞추는 것이 좋습니다.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;wsinfo_matrix_item&quot;&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;렌더링 성능&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문서 크기가 커지면 브라우저 프리즈가 발생할 수 있습니다. 부가 기능을 끄고 확장 깊이를 조절하는 튜닝이 필요합니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;wsinfo_table_wrap&quot;&gt;
&lt;table class=&quot;wsinfo_table&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;최적화 항목&lt;/th&gt;
&lt;th&gt;권장 방향&lt;/th&gt;
&lt;th&gt;실무 효과&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;syntaxHighlight&lt;/td&gt;
&lt;td&gt;false&lt;/td&gt;
&lt;td&gt;대형 JSON 예시 렌더링 시 브라우저 부담을 줄여 응답성을 높입니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DocExpansion&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;초기 로드 시 모든 항목이 펼쳐지는 것을 막아 첫 화면 속도를 안정화합니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DefaultModelExpandDepth&lt;/td&gt;
&lt;td&gt;낮게 유지&lt;/td&gt;
&lt;td&gt;깊은 중첩 모델이 한 번에 펼쳐지는 문제를 방지합니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;문서 분리&lt;/td&gt;
&lt;td&gt;도메인/권한별 분리&lt;/td&gt;
&lt;td&gt;고객사와 내부 사용자가 각자 필요한 문서만 빠르게 볼 수 있습니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section class=&quot;wsinfo_section&quot;&gt;
&lt;h2 class=&quot;wsinfo_section_title&quot; data-ke-size=&quot;size26&quot;&gt;Code-First와 Design-First, 무엇이 더 좋은가&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 질문은 단순 취향 문제가 아닙니다. 프로젝트 운영 방식과 협업 구조를 결정하는 문제입니다.&lt;/p&gt;
&lt;div class=&quot;wsinfo_grid&quot;&gt;
&lt;div class=&quot;wsinfo_cards_item&quot;&gt;
&lt;div class=&quot;wsinfo_cards_kicker&quot;&gt;Code-First&lt;/div&gt;
&lt;h3 class=&quot;wsinfo_cards_title&quot; data-ke-size=&quot;size23&quot;&gt;개발 속도는 빠르지만 계약 통제가 약해질 수 있습니다&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드를 먼저 만들고 문서를 따라오게 하는 방식입니다. 초기 개발 속도와 프로토타이핑에는 유리하지만, 고객사나 프론트엔드와 협업할 때는 합의된 계약이 늦게 생긴다는 단점이 있습니다.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;wsinfo_cards_item&quot;&gt;
&lt;div class=&quot;wsinfo_cards_kicker&quot;&gt;Design-First&lt;/div&gt;
&lt;h3 class=&quot;wsinfo_cards_title&quot; data-ke-size=&quot;size23&quot;&gt;초기 조율 비용은 들지만 장기적으로 훨씬 강합니다&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드를 쓰기 전에 OpenAPI 사양을 먼저 합의하는 방식입니다. 이 경우 문서가 곧 계약이 되므로 프론트엔드와 백엔드가 병렬로 움직일 수 있습니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;wsinfo_divider&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히 신규 서비스나 외부 고객사 연동이 많은 프로젝트라면 Design-First가 훨씬 유리합니다. 사양이 먼저 확정되면 Prism, Stoplight, ReadyAPI 같은 도구로 모킹 서버를 띄워 프론트엔드 개발을 즉시 시작할 수 있고, 백엔드는 Codegen이나 서버 스텁을 활용해 실제 구현에 집중할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반대로 Code-First로 시작한 뒤 나중에 계약 중심 구조로 옮기려 하면 이미 의존성이 얽혀 있어 리팩토링 비용이 크게 증가합니다. 그래서 서비스 초기일수록 설계 우선의 가치가 더 큽니다.&lt;/p&gt;
&lt;/section&gt;
&lt;section class=&quot;wsinfo_section&quot;&gt;
&lt;h2 class=&quot;wsinfo_section_title&quot; data-ke-size=&quot;size26&quot;&gt;고객사 적용 단계에서 반드시 봐야 하는 것들&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내부 개발용 Swagger를 열어두는 것과, 외부 고객사에게 연동 문서로 제공하는 것은 완전히 다른 문제입니다. 여기서부터는 문서 품질이 아니라 &lt;span class=&quot;wsinfo_point&quot;&gt;보안, 버전 관리, 문서 분리, 운영 자동화&lt;/span&gt;가 핵심이 됩니다.&lt;/p&gt;
&lt;div class=&quot;wsinfo_steps&quot;&gt;
&lt;div class=&quot;wsinfo_steps_item&quot;&gt;
&lt;div class=&quot;wsinfo_steps_no&quot;&gt;01&lt;/div&gt;
&lt;div&gt;
&lt;h3 class=&quot;wsinfo_steps_title&quot; data-ke-size=&quot;size23&quot;&gt;프로덕션 노출 통제&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Swagger UI와 api-docs를 운영 환경에 그대로 노출하면 공격자에게 시스템 구조를 제공하는 꼴이 됩니다. 운영에서는 비활성화하거나, 최소한 인증과 화이트리스트 기반 통제로 막아야 합니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;wsinfo_steps_item&quot;&gt;
&lt;div class=&quot;wsinfo_steps_no&quot;&gt;02&lt;/div&gt;
&lt;div&gt;
&lt;h3 class=&quot;wsinfo_steps_title&quot; data-ke-size=&quot;size23&quot;&gt;예시 데이터 마스킹&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문서 안의 example 데이터에 실제 이름, 전화번호, 이메일, 키 값이 들어가면 그 자체로 사고가 됩니다. 고객사 제공 문서는 샘플 데이터까지 별도 검증이 필요합니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;wsinfo_steps_item&quot;&gt;
&lt;div class=&quot;wsinfo_steps_no&quot;&gt;03&lt;/div&gt;
&lt;div&gt;
&lt;h3 class=&quot;wsinfo_steps_title&quot; data-ke-size=&quot;size23&quot;&gt;버전 관리 전략 수립&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존 고객사가 이미 연동 중이라면 작은 변경도 장애가 됩니다. URI 버전, Header 버전, 미디어 타입 버전 등 전략을 정하고, Deprecated 플래그와 마이그레이션 가이드를 함께 제공해야 합니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;wsinfo_steps_item&quot;&gt;
&lt;div class=&quot;wsinfo_steps_no&quot;&gt;04&lt;/div&gt;
&lt;div&gt;
&lt;h3 class=&quot;wsinfo_steps_title&quot; data-ke-size=&quot;size23&quot;&gt;내부용과 외부용 문서 분리&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;admin, internal, operation API를 외부 고객 문서에 같이 노출하면 안 됩니다. 라우팅 기반으로 public 문서만 따로 생성하거나, 빌드 파이프라인에서 필터링된 스펙을 별도 배포해야 합니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul class=&quot;wsinfo_checklist&quot; style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;운영 환경에서는 Swagger UI를 기본적으로 닫아두는 것이 원칙입니다.&lt;/li&gt;
&lt;li&gt;열어야 한다면 인증, 접근 제어, IP 제한을 같이 걸어야 합니다.&lt;/li&gt;
&lt;li&gt;예시 데이터, 에러 응답, 샘플 토큰까지 전부 검토해야 합니다.&lt;/li&gt;
&lt;li&gt;구버전 폐기는 삭제보다 먼저 Deprecated와 유예 기간 안내가 필요합니다.&lt;/li&gt;
&lt;li&gt;고객사 문서는 Public API만 별도 분리해 제공하는 것이 가장 안전합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;section class=&quot;wsinfo_section&quot;&gt;
&lt;h2 class=&quot;wsinfo_section_title&quot; data-ke-size=&quot;size26&quot;&gt;이제는 Swagger 링크가 아니라 개발자 포털을 생각해야 한다&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;B2B 고객사에게 API를 인도할 때 단순히 Swagger 주소만 보내는 방식은 점점 한계를 드러냅니다. 실제 고객사는 문서만 필요한 것이 아니라, 연동 순서, 인증 절차, 샘플 시나리오, 버전 변경 이력, 앱 등록 방법까지 함께 이해해야 하기 때문입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 성숙한 조직은 Swagger UI를 종착점이 아니라 &lt;span class=&quot;wsinfo_point&quot;&gt;개발자 포털의 데이터 소스&lt;/span&gt;로 활용합니다. Redocly, Backstage, ReadMe 같은 포털 도구와 연동하면 API 참조 문서와 가이드 문서를 함께 제공할 수 있고, API Gateway와 결합하면 앱 등록과 키 발급까지 셀프서비스 형태로 연결할 수 있습니다.&lt;/p&gt;
&lt;div class=&quot;wsinfo_grid&quot;&gt;
&lt;div class=&quot;wsinfo_cards_item&quot;&gt;
&lt;div class=&quot;wsinfo_cards_kicker&quot;&gt;Portal Strategy&lt;/div&gt;
&lt;h3 class=&quot;wsinfo_cards_title&quot; data-ke-size=&quot;size23&quot;&gt;문서를 서비스처럼 제공&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기술 문서를 링크 하나로 끝내지 않고, 고객사가 실제로 연동을 성공할 수 있도록 온보딩 경험 자체를 설계해야 합니다.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;wsinfo_cards_item&quot;&gt;
&lt;div class=&quot;wsinfo_cards_kicker&quot;&gt;CI/CD Automation&lt;/div&gt;
&lt;h3 class=&quot;wsinfo_cards_title&quot; data-ke-size=&quot;size23&quot;&gt;문서 무결성은 자동으로 검증&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Dredd, Schemathesis 같은 계약 테스트 도구를 파이프라인에 넣으면, 스펙과 실제 응답이 어긋나는 순간 빌드를 실패시켜 문서 신뢰도를 지킬 수 있습니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section class=&quot;wsinfo_section&quot;&gt;
&lt;h2 class=&quot;wsinfo_section_title&quot; data-ke-size=&quot;size26&quot;&gt;결국 핵심은 문서를 얼마나 잘 쓰느냐가 아니라, 얼마나 잘 운영하느냐입니다&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Swagger와 OpenAPI를 도입했다고 해서 바로 문서화가 잘되는 것은 아닙니다. 진짜 차이는 그다음부터 발생합니다. 문서를 코드와 함께 관리하는지, 고객사 관점으로 분리해 주는지, 보안과 버전 전략이 붙어 있는지, 그리고 CI/CD를 통해 자동 검증되는지에 따라 결과가 완전히 달라집니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실무에서 좋은 API 문서는 세 가지를 동시에 만족해야 합니다. &lt;span class=&quot;wsinfo_point&quot;&gt;개발자는 빠르게 이해할 수 있어야 하고, 운영팀은 안전하게 통제할 수 있어야 하며, 고객사는 불안 없이 연동할 수 있어야 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 기준으로 보면 Swagger와 OpenAPI는 단순 문서화 도구가 아니라, 서비스 신뢰도와 기술 성숙도를 드러내는 핵심 인프라라고 보는 편이 더 정확합니다.&lt;/p&gt;
&lt;/section&gt;
&lt;div class=&quot;wsinfo_footer&quot;&gt;태그 추천: #Swagger #OpenAPI #웹서비스 #API문서화 #Springdoc #Nodejs #API보안 #버전관리 #CICD #개발자포털&lt;/div&gt;
&lt;/div&gt;</description>
      <category>DEVELOPMENT</category>
      <category>api문서화</category>
      <category>api보안</category>
      <category>Nodejs</category>
      <category>OpenAPI</category>
      <category>springboot</category>
      <category>springdoc</category>
      <category>swagger</category>
      <category>개발자포털</category>
      <category>버전관리</category>
      <category>웹서비스개발</category>
      <author>간지뽕빨리턴님</author>
      <guid isPermaLink="true">https://odinbox.tistory.com/581</guid>
      <comments>https://odinbox.tistory.com/581#entry581comment</comments>
      <pubDate>Sat, 18 Apr 2026 23:04:07 +0900</pubDate>
    </item>
    <item>
      <title>대규모 트래픽 처리를 위한 로드밸런싱과 DB 분산 전략</title>
      <link>https://odinbox.tistory.com/580</link>
      <description>&lt;div&gt;
&lt;style&gt;
  .balancing_wrap { font-family: 'Pretendard', 'Apple SD Gothic Neo', -apple-system, sans-serif; color: #1a1a1a; line-height: 1.85; max-width: 780px; margin: 0 auto; font-size: 16.5px; word-break: keep-all; }
  .balancing_wrap h2 { font-size: 26px; font-weight: 800; margin: 56px 0 18px; padding-bottom: 12px; border-bottom: 3px solid #1a1a1a; letter-spacing: -0.02em; }
  .balancing_wrap h3 { font-size: 21px; font-weight: 700; margin: 44px 0 14px; color: #1a1a1a; }
  .balancing_wrap h4 { font-size: 17.5px; font-weight: 700; margin: 32px 0 10px; color: #2d2d2d; }
  .balancing_wrap p { margin: 0 0 16px; }
  .balancing_wrap strong { color: #0d6efd; font-weight: 700; }
  .balancing_wrap hr { border: none; border-top: 1px solid #e0e0e0; margin: 48px 0; }
  .balancing_wrap code { background: #f1f3f5; padding: 2px 6px; border-radius: 4px; font-family: 'JetBrains Mono', 'D2Coding', monospace; font-size: 14px; }

  .balancing_thumbnail { width: 100%; max-height: 420px; object-fit: cover; border-radius: 12px; margin: 0 0 36px; display: block; }

  .balancing_intro { background: linear-gradient(135deg, #f0f4ff 0%, #e8f0fe 100%); border-left: 5px solid #1a73e8; border-radius: 0 12px 12px 0; padding: 28px 32px; margin: 0 0 36px; font-size: 15.5px; color: #303030; }
  .balancing_intro p:last-child { margin-bottom: 0; }

  .balancing_code { background: #1e1e2e; color: #cdd6f4; border-radius: 10px; padding: 22px 26px; margin: 18px 0 24px; overflow-x: auto; font-family: 'JetBrains Mono', 'D2Coding', 'Fira Code', monospace; font-size: 13.8px; line-height: 1.7; white-space: pre; }
  .balancing_code .balancing_cm { color: #6c7086; }
  .balancing_code .balancing_kw { color: #cba6f7; }
  .balancing_code .balancing_st { color: #a6e3a1; }
  .balancing_code .balancing_an { color: #f9e2af; }
  .balancing_code .balancing_tp { color: #89b4fa; }
  .balancing_code .balancing_nm { color: #fab387; }

  .balancing_diagram { background: #f8f9fa; border: 1px solid #dee2e6; border-radius: 10px; padding: 24px 28px; margin: 18px 0 24px; font-family: 'JetBrains Mono', 'D2Coding', monospace; font-size: 13.5px; line-height: 1.65; color: #495057; white-space: pre; overflow-x: auto; text-align: center; }

  .balancing_tbl { overflow-x: auto; margin: 18px 0 24px; border-radius: 10px; border: 1px solid #dee2e6; }
  .balancing_tbl table { width: 100%; border-collapse: collapse; font-size: 14.5px; }
  .balancing_tbl thead { background: #1a73e8; color: #fff; }
  .balancing_tbl th { padding: 13px 16px; text-align: left; font-weight: 600; white-space: nowrap; }
  .balancing_tbl td { padding: 12px 16px; border-top: 1px solid #e9ecef; }
  .balancing_tbl tbody tr:hover { background: #f0f4ff; }
  .balancing_tbl tbody tr:nth-child(even) { background: #f8f9fa; }
  .balancing_tbl tbody tr:nth-child(even):hover { background: #e8f0fe; }

  .balancing_note { background: #fff8e1; border-left: 5px solid #ffc107; border-radius: 0 10px 10px 0; padding: 18px 22px; margin: 18px 0 24px; font-size: 15px; }
  .balancing_warn { background: #fce4ec; border-left: 5px solid #e53935; border-radius: 0 10px 10px 0; padding: 18px 22px; margin: 18px 0 24px; font-size: 15px; }

  .balancing_checklist { margin: 14px 0 24px; padding: 0; list-style: none; }
  .balancing_checklist li { padding: 8px 0 8px 30px; position: relative; font-size: 15px; }
  .balancing_checklist li::before { content: '\25B6'; position: absolute; left: 6px; color: #1a73e8; font-size: 10px; top: 12px; }

  .balancing_summary { background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%); color: #e0e0e0; border-radius: 12px; padding: 30px 34px; margin: 24px 0; }
  .balancing_summary h4 { color: #82b1ff; margin-top: 0; font-size: 18px; }
  .balancing_summary ol { padding-left: 20px; margin: 0; }
  .balancing_summary li { margin-bottom: 10px; line-height: 1.7; }
  .balancing_summary strong { color: #64ffda; }

  .balancing_badge { display: inline-block; background: #1a73e8; color: #fff; width: 32px; height: 32px; line-height: 32px; text-align: center; border-radius: 50%; font-size: 15px; font-weight: 700; margin-right: 10px; vertical-align: middle; }

  .balancing_ref { background: #f8f9fa; border: 1px solid #dee2e6; border-radius: 10px; padding: 24px 28px; margin: 24px 0; }
  .balancing_ref h4 { margin-top: 0; color: #1a73e8; }
  .balancing_ref ul { padding-left: 20px; margin: 0; }
  .balancing_ref li { margin-bottom: 8px; font-size: 14.5px; line-height: 1.6; }
  .balancing_ref a { color: #1a73e8; text-decoration: none; }
  .balancing_ref a:hover { text-decoration: underline; }

  .balancing_tags { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 32px; }
  .balancing_tags span { background: #e8f0fe; color: #1a73e8; padding: 6px 14px; border-radius: 20px; font-size: 13px; font-weight: 600; }
&lt;/style&gt;
&lt;/div&gt;
&lt;div class=&quot;balancing_wrap&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;글 상단 부분 대표 이미지.png&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oEmLP/dJMcaaLGiP3/MUklHYY2KoR2kTHKSvdIAk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oEmLP/dJMcaaLGiP3/MUklHYY2KoR2kTHKSvdIAk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oEmLP/dJMcaaLGiP3/MUklHYY2KoR2kTHKSvdIAk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoEmLP%2FdJMcaaLGiP3%2FMUklHYY2KoR2kTHKSvdIAk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;400&quot; data-filename=&quot;글 상단 부분 대표 이미지.png&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;div class=&quot;balancing_intro&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서비스를 개발하다 보면 처음에는 단일 서버 하나로도 충분합니다. 하지만 사용자가 늘고, 동시 접속이 수백에서 수천 단위를 넘어가기 시작하면 &quot;서버가 버틸 수 있을까?&quot;라는 고민이 현실로 다가옵니다.&lt;/p&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제로 업무를 하면서 규모 있는 서비스를 만들다 보면, 단순히 기능 구현에만 집중할 수 없습니다. 동시 접속자가 몰릴 때 응답 지연이 발생하고, DB 커넥션이 부족해져 장애로 이어지는 상황을 한두 번 겪고 나면 &lt;b&gt;트래픽 분산&lt;/b&gt;과 &lt;b&gt;DB 처리 전략&lt;/b&gt;이 아키텍처 설계의 핵심이라는 걸 체감하게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 글에서는 로드밸런싱의 기본 개념부터 DB 커넥션 관리, 읽기/쓰기 분리, 캐싱 전략까지 실무에서 활용할 수 있는 기술들을 정리해 보겠습니다. 이론에 그치지 않고 &lt;b&gt;왜 이 기술이 필요한지&lt;/b&gt;, 그리고 &lt;b&gt;어떤 상황에서 어떤 선택을 해야 하는지&lt;/b&gt; 판단 기준을 함께 다루겠습니다. 또한 IIS/ASP.NET Core 환경과 Node.js 환경에서의 실제 구현 방법도 함께 정리하였습니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span class=&quot;balancing_badge&quot;&gt;1&lt;/span&gt;로드밸런싱(Load Balancing)이란&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로드밸런싱은 다수의 서버에 클라이언트 요청을 분산하여 특정 서버에 부하가 집중되는 것을 방지하는 기술입니다. 단일 서버 구성에서는 해당 서버가 다운되면 서비스 전체가 중단되지만, 로드밸런서를 도입하면 &lt;b&gt;고가용성(High Availability)&lt;/b&gt;과 &lt;b&gt;수평 확장(Scale-Out)&lt;/b&gt;이 가능해집니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;로드밸런서의 동작 위치&lt;/h4&gt;
&lt;div class=&quot;balancing_diagram&quot;&gt;[클라이언트] | v [로드밸런서] -- L4(TCP/UDP) 또는 L7(HTTP/HTTPS) 계층 | +--+--+ v v v [WAS1][WAS2][WAS3] -- 동일 애플리케이션 서버 그룹&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;L4 로드밸런싱&lt;/b&gt;은 IP 주소와 포트 기반으로 분배하며, 처리 속도가 빠르고 단순합니다. AWS NLB, HAProxy(TCP 모드)가 대표적입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;L7 로드밸런싱&lt;/b&gt;은 HTTP 헤더, URL 경로, 쿠키 등 애플리케이션 계층 정보를 기반으로 분배합니다. URL 패턴별로 다른 서버 그룹에 라우팅 할 수 있으며, AWS ALB, Nginx가 대표적입니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;주요 분배 알고리즘&lt;/h4&gt;
&lt;div class=&quot;balancing_tbl&quot;&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;알고리즘&lt;/th&gt;
&lt;th&gt;설명&lt;/th&gt;
&lt;th&gt;적합한 상황&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Round Robin&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;서버에 순서대로 요청을 분배합니다&lt;/td&gt;
&lt;td&gt;서버 스펙이 동일할 때&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Weighted Round Robin&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;서버별 가중치를 부여하여 분배합니다&lt;/td&gt;
&lt;td&gt;서버 스펙이 다를 때&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Least Connections&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;현재 연결 수가 가장 적은 서버로 분배합니다&lt;/td&gt;
&lt;td&gt;요청 처리 시간이 불균등할 때&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;IP Hash&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;클라이언트 IP 기반 해시로 고정 서버를 할당합니다&lt;/td&gt;
&lt;td&gt;세션 유지가 필요할 때&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Least Response Time&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;응답 시간이 가장 빠른 서버로 분배합니다&lt;/td&gt;
&lt;td&gt;서버 성능이 동적으로 변하는 환경&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;세션 관리 문제&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로드밸런싱 환경에서 가장 먼저 부딪히는 문제가 &lt;b&gt;세션 관리&lt;/b&gt;입니다. 사용자가 WAS1에서 로그인했는데 다음 요청이 WAS2로 가면 세션이 없어 로그인이 풀리게 됩니다. 해결 방법은 크게 세 가지입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Sticky Session&lt;/b&gt; &amp;mdash; 로드밸런서가 특정 사용자를 동일 서버에 고정하는 방식입니다. 구현이 간단하지만, 특정 서버에 부하가 몰릴 수 있고 해당 서버가 다운되면 세션이 유실됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Session Clustering&lt;/b&gt; &amp;mdash; WAS 간 세션 데이터를 복제하고 공유하는 방식입니다. Tomcat의 경우 DeltaManager를 활용할 수 있지만, 서버 수가 늘어나면 동기화 오버헤드가 기하급수적으로 증가합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;External Session Store&lt;/b&gt; &amp;mdash; Redis나 Memcached 같은 외부 저장소에 세션을 저장하는 방식입니다. 가장 널리 사용되며, WAS가 어디로 라우팅되든 동일한 세션 데이터를 조회할 수 있습니다.&lt;/p&gt;
&lt;div class=&quot;balancing_diagram&quot;&gt;[WAS1] --+ [WAS2] --+--&amp;gt; [Redis Cluster] -- 세션 저장소 [WAS3] --+&lt;/div&gt;
&lt;div class=&quot;balancing_note&quot;&gt;&lt;b&gt;참고&lt;/b&gt; - 실무에서는 JWT 토큰 기반 인증으로 아예 서버 측 세션을 없애는 Stateless 구조를 채택하는 경우도 많습니다. 세션 저장소 자체가 불필요해지므로 구조가 단순해집니다. 다만 토큰 탈취 시 즉시 무효화가 어렵다는 트레이드오프가 있어, Refresh Token 전략이나 Token Blacklist 등 보완 설계가 필요합니다.&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span class=&quot;balancing_badge&quot;&gt;2&lt;/span&gt;IIS + ASP.NET Core 환경에서의 로드밸런싱&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Windows Server 기반의 IIS 환경에서는 &lt;b&gt;ARR(Application Request Routing)&lt;/b&gt; 모듈을 통해 L7 로드밸런싱을 구성할 수 있습니다. ARR은 IIS의 확장 모듈로, 리버스 프록시 및 로드밸런서 역할을 수행합니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;IIS ARR 기반 서버 팜 구성&lt;/h4&gt;
&lt;div class=&quot;balancing_diagram&quot;&gt;[클라이언트] | v [IIS + ARR] -- 로드밸런서 역할 | +--+--+ v v v [IIS Node1][IIS Node2][IIS Node3] ASP.NET ASP.NET ASP.NET Core App Core App Core App&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ARR에서 서버 팜(Server Farm)을 생성하고, 각 백엔드 서버를 등록하면 자동으로 Health Check와 함께 요청을 분배합니다. 분배 알고리즘은 Weighted Round Robin, Least Current Request 등을 IIS 관리자에서 선택할 수 있습니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;ASP.NET Core 분산 세션 구성 (Redis)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ASP.NET Core에서는 &lt;b&gt;Microsoft.Extensions.Caching.StackExchangeRedis&lt;/b&gt; 패키지를 통해 분산 세션을 구성합니다.&lt;/p&gt;
&lt;div class=&quot;balancing_code&quot;&gt;// Program.cs builder.Services.&lt;span class=&quot;balancing_kw&quot;&gt;AddStackExchangeRedisCache&lt;/span&gt;(options =&amp;gt; { options.&lt;span class=&quot;balancing_tp&quot;&gt;Configuration&lt;/span&gt; = &lt;span class=&quot;balancing_st&quot;&gt;&quot;redis-server:6379&quot;&lt;/span&gt;; options.&lt;span class=&quot;balancing_tp&quot;&gt;InstanceName&lt;/span&gt; = &lt;span class=&quot;balancing_st&quot;&gt;&quot;MyApp_&quot;&lt;/span&gt;; }); builder.Services.&lt;span class=&quot;balancing_kw&quot;&gt;AddSession&lt;/span&gt;(options =&amp;gt; { options.&lt;span class=&quot;balancing_tp&quot;&gt;IdleTimeout&lt;/span&gt; = &lt;span class=&quot;balancing_tp&quot;&gt;TimeSpan&lt;/span&gt;.&lt;span class=&quot;balancing_kw&quot;&gt;FromMinutes&lt;/span&gt;(&lt;span class=&quot;balancing_nm&quot;&gt;30&lt;/span&gt;); options.&lt;span class=&quot;balancing_tp&quot;&gt;Cookie&lt;/span&gt;.&lt;span class=&quot;balancing_tp&quot;&gt;HttpOnly&lt;/span&gt; = &lt;span class=&quot;balancing_kw&quot;&gt;true&lt;/span&gt;; options.&lt;span class=&quot;balancing_tp&quot;&gt;Cookie&lt;/span&gt;.&lt;span class=&quot;balancing_tp&quot;&gt;IsEssential&lt;/span&gt; = &lt;span class=&quot;balancing_kw&quot;&gt;true&lt;/span&gt;; }); app.&lt;span class=&quot;balancing_kw&quot;&gt;UseSession&lt;/span&gt;();&lt;/div&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;ASP.NET Core Data Protection Key 공유&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로드밸런싱 환경에서 ASP.NET Core를 운영할 때 반드시 설정해야 하는 것이 &lt;b&gt;Data Protection Key 공유&lt;/b&gt;입니다. 각 인스턴스가 서로 다른 키를 사용하면 인증 쿠키를 복호화할 수 없어 세션이 풀리게 됩니다.&lt;/p&gt;
&lt;div class=&quot;balancing_code&quot;&gt;builder.Services.&lt;span class=&quot;balancing_kw&quot;&gt;AddDataProtection&lt;/span&gt;() .&lt;span class=&quot;balancing_kw&quot;&gt;PersistKeysToStackExchangeRedis&lt;/span&gt;( &lt;span class=&quot;balancing_tp&quot;&gt;ConnectionMultiplexer&lt;/span&gt;.&lt;span class=&quot;balancing_kw&quot;&gt;Connect&lt;/span&gt;(&lt;span class=&quot;balancing_st&quot;&gt;&quot;redis-server:6379&quot;&lt;/span&gt;), &lt;span class=&quot;balancing_st&quot;&gt;&quot;DataProtection-Keys&quot;&lt;/span&gt; ) .&lt;span class=&quot;balancing_kw&quot;&gt;SetApplicationName&lt;/span&gt;(&lt;span class=&quot;balancing_st&quot;&gt;&quot;MyApp&quot;&lt;/span&gt;);&lt;/div&gt;
&lt;div class=&quot;balancing_warn&quot;&gt;&lt;b&gt;주의&lt;/b&gt; &amp;mdash; Data Protection Key를 공유하지 않으면 IIS ARR 환경에서 Sticky Session 없이 운영할 때 로그인이 반복적으로 풀리는 현상이 발생합니다. 이 문제는 실무에서 매우 자주 발생하므로 반드시 확인해야 합니다.&lt;/div&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;IIS 환경에서의 Health Check 설정&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ASP.NET Core에는 내장 Health Check 미들웨어가 있으며, ARR의 URL Test 기능과 연동할 수 있습니다.&lt;/p&gt;
&lt;div class=&quot;balancing_code&quot;&gt;builder.Services.&lt;span class=&quot;balancing_kw&quot;&gt;AddHealthChecks&lt;/span&gt;() .&lt;span class=&quot;balancing_kw&quot;&gt;AddSqlServer&lt;/span&gt;(connectionString, name: &lt;span class=&quot;balancing_st&quot;&gt;&quot;sqldb&quot;&lt;/span&gt;) .&lt;span class=&quot;balancing_kw&quot;&gt;AddRedis&lt;/span&gt;(&lt;span class=&quot;balancing_st&quot;&gt;&quot;redis-server:6379&quot;&lt;/span&gt;, name: &lt;span class=&quot;balancing_st&quot;&gt;&quot;redis&quot;&lt;/span&gt;); app.&lt;span class=&quot;balancing_kw&quot;&gt;MapHealthChecks&lt;/span&gt;(&lt;span class=&quot;balancing_st&quot;&gt;&quot;/health&quot;&lt;/span&gt;);&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ARR 서버 팜의 Health Test 설정에서 URL을 &lt;code&gt;/health&lt;/code&gt;로 지정하면, 장애가 발생한 노드를 자동으로 분배 대상에서 제외합니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span class=&quot;balancing_badge&quot;&gt;3&lt;/span&gt;Node.js 환경에서의 로드밸런싱&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Node.js는 싱글 스레드 이벤트 루프 기반으로 동작하기 때문에, 멀티 코어 CPU를 활용하려면 별도의 분산 처리가 필요합니다. 대표적인 방법은 &lt;b&gt;Cluster 모듈&lt;/b&gt;과 &lt;b&gt;PM2&lt;/b&gt;, 그리고 앞단에 &lt;b&gt;Nginx 리버스 프록시&lt;/b&gt;를 두는 구성입니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Node.js Cluster 모듈&lt;/h4&gt;
&lt;div class=&quot;balancing_code&quot;&gt;&lt;span class=&quot;balancing_kw&quot;&gt;const&lt;/span&gt; cluster = &lt;span class=&quot;balancing_kw&quot;&gt;require&lt;/span&gt;(&lt;span class=&quot;balancing_st&quot;&gt;'cluster'&lt;/span&gt;); &lt;span class=&quot;balancing_kw&quot;&gt;const&lt;/span&gt; os = &lt;span class=&quot;balancing_kw&quot;&gt;require&lt;/span&gt;(&lt;span class=&quot;balancing_st&quot;&gt;'os'&lt;/span&gt;); &lt;span class=&quot;balancing_kw&quot;&gt;const&lt;/span&gt; express = &lt;span class=&quot;balancing_kw&quot;&gt;require&lt;/span&gt;(&lt;span class=&quot;balancing_st&quot;&gt;'express'&lt;/span&gt;); &lt;span class=&quot;balancing_kw&quot;&gt;if&lt;/span&gt; (cluster.&lt;span class=&quot;balancing_tp&quot;&gt;isPrimary&lt;/span&gt;) { &lt;span class=&quot;balancing_kw&quot;&gt;const&lt;/span&gt; cpuCount = os.&lt;span class=&quot;balancing_kw&quot;&gt;cpus&lt;/span&gt;().&lt;span class=&quot;balancing_tp&quot;&gt;length&lt;/span&gt;; console.&lt;span class=&quot;balancing_kw&quot;&gt;log&lt;/span&gt;(&lt;span class=&quot;balancing_st&quot;&gt;`Primary ${process.pid} &amp;mdash; forking ${cpuCount} workers`&lt;/span&gt;); &lt;span class=&quot;balancing_kw&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;balancing_kw&quot;&gt;let&lt;/span&gt; i = &lt;span class=&quot;balancing_nm&quot;&gt;0&lt;/span&gt;; i &amp;lt; cpuCount; i++) { cluster.&lt;span class=&quot;balancing_kw&quot;&gt;fork&lt;/span&gt;(); } cluster.&lt;span class=&quot;balancing_kw&quot;&gt;on&lt;/span&gt;(&lt;span class=&quot;balancing_st&quot;&gt;'exit'&lt;/span&gt;, (worker) =&amp;gt; { console.&lt;span class=&quot;balancing_kw&quot;&gt;log&lt;/span&gt;(&lt;span class=&quot;balancing_st&quot;&gt;`Worker ${worker.process.pid} exited. Restarting...`&lt;/span&gt;); cluster.&lt;span class=&quot;balancing_kw&quot;&gt;fork&lt;/span&gt;(); }); } &lt;span class=&quot;balancing_kw&quot;&gt;else&lt;/span&gt; { &lt;span class=&quot;balancing_kw&quot;&gt;const&lt;/span&gt; app = &lt;span class=&quot;balancing_kw&quot;&gt;express&lt;/span&gt;(); app.&lt;span class=&quot;balancing_kw&quot;&gt;get&lt;/span&gt;(&lt;span class=&quot;balancing_st&quot;&gt;'/'&lt;/span&gt;, (req, res) =&amp;gt; { res.&lt;span class=&quot;balancing_kw&quot;&gt;send&lt;/span&gt;(&lt;span class=&quot;balancing_st&quot;&gt;`Handled by worker ${process.pid}`&lt;/span&gt;); }); app.&lt;span class=&quot;balancing_kw&quot;&gt;listen&lt;/span&gt;(&lt;span class=&quot;balancing_nm&quot;&gt;3000&lt;/span&gt;); }&lt;/div&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;PM2를 활용한 클러스터 모드&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PM2는 Node.js 프로세스 매니저로, 클러스터 모드를 간편하게 설정할 수 있습니다.&lt;/p&gt;
&lt;div class=&quot;balancing_code&quot;&gt;module.exports = { apps: [{ &lt;span class=&quot;balancing_tp&quot;&gt;name&lt;/span&gt;: &lt;span class=&quot;balancing_st&quot;&gt;&quot;my-app&quot;&lt;/span&gt;, &lt;span class=&quot;balancing_tp&quot;&gt;script&lt;/span&gt;: &lt;span class=&quot;balancing_st&quot;&gt;&quot;./app.js&quot;&lt;/span&gt;, &lt;span class=&quot;balancing_tp&quot;&gt;instances&lt;/span&gt;: &lt;span class=&quot;balancing_st&quot;&gt;&quot;max&quot;&lt;/span&gt;, &lt;span class=&quot;balancing_tp&quot;&gt;exec_mode&lt;/span&gt;: &lt;span class=&quot;balancing_st&quot;&gt;&quot;cluster&quot;&lt;/span&gt;, &lt;span class=&quot;balancing_tp&quot;&gt;max_memory_restart&lt;/span&gt;: &lt;span class=&quot;balancing_st&quot;&gt;&quot;500M&quot;&lt;/span&gt;, &lt;span class=&quot;balancing_tp&quot;&gt;env&lt;/span&gt;: { &lt;span class=&quot;balancing_tp&quot;&gt;NODE_ENV&lt;/span&gt;: &lt;span class=&quot;balancing_st&quot;&gt;&quot;production&quot;&lt;/span&gt;, &lt;span class=&quot;balancing_tp&quot;&gt;PORT&lt;/span&gt;: &lt;span class=&quot;balancing_nm&quot;&gt;3000&lt;/span&gt; } }] };&lt;/div&gt;
&lt;div class=&quot;balancing_code&quot;&gt;$ pm2 start ecosystem.config.js $ pm2 monit $ pm2 reload my-app&lt;/div&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Nginx 리버스 프록시 + Node.js 다중 인스턴스&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로덕션 환경에서는 Nginx를 앞단에 두고 여러 Node.js 인스턴스(또는 서버)로 요청을 분배하는 것이 일반적입니다.&lt;/p&gt;
&lt;div class=&quot;balancing_code&quot;&gt;&lt;span class=&quot;balancing_kw&quot;&gt;upstream&lt;/span&gt; nodejs_backend { &lt;span class=&quot;balancing_kw&quot;&gt;least_conn&lt;/span&gt;; &lt;span class=&quot;balancing_kw&quot;&gt;server&lt;/span&gt; &lt;span class=&quot;balancing_nm&quot;&gt;127.0.0.1&lt;/span&gt;:&lt;span class=&quot;balancing_nm&quot;&gt;3001&lt;/span&gt;; &lt;span class=&quot;balancing_kw&quot;&gt;server&lt;/span&gt; &lt;span class=&quot;balancing_nm&quot;&gt;127.0.0.1&lt;/span&gt;:&lt;span class=&quot;balancing_nm&quot;&gt;3002&lt;/span&gt;; &lt;span class=&quot;balancing_kw&quot;&gt;server&lt;/span&gt; &lt;span class=&quot;balancing_nm&quot;&gt;127.0.0.1&lt;/span&gt;:&lt;span class=&quot;balancing_nm&quot;&gt;3003&lt;/span&gt;; &lt;span class=&quot;balancing_kw&quot;&gt;server&lt;/span&gt; &lt;span class=&quot;balancing_nm&quot;&gt;127.0.0.1&lt;/span&gt;:&lt;span class=&quot;balancing_nm&quot;&gt;3004&lt;/span&gt;; } &lt;span class=&quot;balancing_kw&quot;&gt;server&lt;/span&gt; { &lt;span class=&quot;balancing_kw&quot;&gt;listen&lt;/span&gt; &lt;span class=&quot;balancing_nm&quot;&gt;80&lt;/span&gt;; &lt;span class=&quot;balancing_tp&quot;&gt;server_name&lt;/span&gt; example.com; &lt;span class=&quot;balancing_kw&quot;&gt;location&lt;/span&gt; / { &lt;span class=&quot;balancing_kw&quot;&gt;proxy_pass&lt;/span&gt; http://nodejs_backend; &lt;span class=&quot;balancing_tp&quot;&gt;proxy_http_version&lt;/span&gt; &lt;span class=&quot;balancing_nm&quot;&gt;1.1&lt;/span&gt;; &lt;span class=&quot;balancing_tp&quot;&gt;proxy_set_header&lt;/span&gt; Upgrade $http_upgrade; &lt;span class=&quot;balancing_tp&quot;&gt;proxy_set_header&lt;/span&gt; Connection &lt;span class=&quot;balancing_st&quot;&gt;'upgrade'&lt;/span&gt;; &lt;span class=&quot;balancing_tp&quot;&gt;proxy_set_header&lt;/span&gt; Host $host; &lt;span class=&quot;balancing_tp&quot;&gt;proxy_cache_bypass&lt;/span&gt; $http_upgrade; } }&lt;/div&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Node.js 분산 세션 관리 (express-session + Redis)&lt;/h4&gt;
&lt;div class=&quot;balancing_code&quot;&gt;&lt;span class=&quot;balancing_kw&quot;&gt;const&lt;/span&gt; session = &lt;span class=&quot;balancing_kw&quot;&gt;require&lt;/span&gt;(&lt;span class=&quot;balancing_st&quot;&gt;'express-session'&lt;/span&gt;); &lt;span class=&quot;balancing_kw&quot;&gt;const&lt;/span&gt; RedisStore = &lt;span class=&quot;balancing_kw&quot;&gt;require&lt;/span&gt;(&lt;span class=&quot;balancing_st&quot;&gt;'connect-redis'&lt;/span&gt;).default; &lt;span class=&quot;balancing_kw&quot;&gt;const&lt;/span&gt; { &lt;span class=&quot;balancing_tp&quot;&gt;createClient&lt;/span&gt; } = &lt;span class=&quot;balancing_kw&quot;&gt;require&lt;/span&gt;(&lt;span class=&quot;balancing_st&quot;&gt;'redis'&lt;/span&gt;); &lt;span class=&quot;balancing_kw&quot;&gt;const&lt;/span&gt; redisClient = &lt;span class=&quot;balancing_kw&quot;&gt;createClient&lt;/span&gt;({ &lt;span class=&quot;balancing_tp&quot;&gt;url&lt;/span&gt;: &lt;span class=&quot;balancing_st&quot;&gt;'redis://redis-server:6379'&lt;/span&gt; }); &lt;span class=&quot;balancing_kw&quot;&gt;await&lt;/span&gt; redisClient.&lt;span class=&quot;balancing_kw&quot;&gt;connect&lt;/span&gt;(); app.&lt;span class=&quot;balancing_kw&quot;&gt;use&lt;/span&gt;(&lt;span class=&quot;balancing_kw&quot;&gt;session&lt;/span&gt;({ &lt;span class=&quot;balancing_tp&quot;&gt;store&lt;/span&gt;: &lt;span class=&quot;balancing_kw&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;balancing_tp&quot;&gt;RedisStore&lt;/span&gt;({ &lt;span class=&quot;balancing_tp&quot;&gt;client&lt;/span&gt;: redisClient }), &lt;span class=&quot;balancing_tp&quot;&gt;secret&lt;/span&gt;: &lt;span class=&quot;balancing_st&quot;&gt;'your-secret-key'&lt;/span&gt;, &lt;span class=&quot;balancing_tp&quot;&gt;resave&lt;/span&gt;: &lt;span class=&quot;balancing_kw&quot;&gt;false&lt;/span&gt;, &lt;span class=&quot;balancing_tp&quot;&gt;saveUninitialized&lt;/span&gt;: &lt;span class=&quot;balancing_kw&quot;&gt;false&lt;/span&gt;, &lt;span class=&quot;balancing_tp&quot;&gt;cookie&lt;/span&gt;: { &lt;span class=&quot;balancing_tp&quot;&gt;secure&lt;/span&gt;: &lt;span class=&quot;balancing_kw&quot;&gt;true&lt;/span&gt;, &lt;span class=&quot;balancing_tp&quot;&gt;maxAge&lt;/span&gt;: &lt;span class=&quot;balancing_nm&quot;&gt;1800000&lt;/span&gt; } }));&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span class=&quot;balancing_badge&quot;&gt;4&lt;/span&gt;DB 커넥션 관리 &amp;mdash; Connection Pool의 중요성&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;트래픽이 증가하면 WAS보다 &lt;b&gt;DB가 먼저 병목&lt;/b&gt;이 되는 경우가 많습니다. DB 커넥션은 생성 비용이 높은 자원입니다. TCP 3-way Handshake, 인증, 세션 초기화 과정을 매 요청마다 반복하면 성능이 급격히 저하됩니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Connection Pool 기본 구조&lt;/h4&gt;
&lt;div class=&quot;balancing_diagram&quot;&gt;[Application Thread 1] --+ [Application Thread 2] --+--&amp;gt; [Connection Pool] --&amp;gt; [DB] [Application Thread 3] --+ (미리 생성된 커넥션 N개를 재사용)&lt;/div&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;HikariCP 설정 예시 (Spring Boot / Java)&lt;/h4&gt;
&lt;div class=&quot;balancing_code&quot;&gt;&lt;span class=&quot;balancing_kw&quot;&gt;spring&lt;/span&gt;: &lt;span class=&quot;balancing_kw&quot;&gt;datasource&lt;/span&gt;: &lt;span class=&quot;balancing_kw&quot;&gt;hikari&lt;/span&gt;: &lt;span class=&quot;balancing_tp&quot;&gt;minimum-idle&lt;/span&gt;: &lt;span class=&quot;balancing_nm&quot;&gt;10&lt;/span&gt; &lt;span class=&quot;balancing_tp&quot;&gt;maximum-pool-size&lt;/span&gt;: &lt;span class=&quot;balancing_nm&quot;&gt;30&lt;/span&gt; &lt;span class=&quot;balancing_tp&quot;&gt;connection-timeout&lt;/span&gt;: &lt;span class=&quot;balancing_nm&quot;&gt;3000&lt;/span&gt; &lt;span class=&quot;balancing_tp&quot;&gt;idle-timeout&lt;/span&gt;: &lt;span class=&quot;balancing_nm&quot;&gt;600000&lt;/span&gt; &lt;span class=&quot;balancing_tp&quot;&gt;max-lifetime&lt;/span&gt;: &lt;span class=&quot;balancing_nm&quot;&gt;1800000&lt;/span&gt; &lt;span class=&quot;balancing_tp&quot;&gt;leak-detection-threshold&lt;/span&gt;: &lt;span class=&quot;balancing_nm&quot;&gt;5000&lt;/span&gt;&lt;/div&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;ASP.NET Core 커넥션 풀 설정&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ASP.NET Core에서 SQL Server를 사용하는 경우, 커넥션 풀은 &lt;b&gt;연결 문자열&lt;/b&gt;에서 설정합니다. ADO.NET이 내부적으로 커넥션 풀을 관리합니다.&lt;/p&gt;
&lt;div class=&quot;balancing_code&quot;&gt;{ &lt;span class=&quot;balancing_st&quot;&gt;&quot;ConnectionStrings&quot;&lt;/span&gt;: { &lt;span class=&quot;balancing_st&quot;&gt;&quot;Default&quot;&lt;/span&gt;: &lt;span class=&quot;balancing_st&quot;&gt;&quot;Server=db-server;Database=MyDb;User Id=sa;Password=***;Min Pool Size=10;Max Pool Size=100;Connection Timeout=15;Connection Lifetime=300;&quot;&lt;/span&gt; } }&lt;/div&gt;
&lt;div class=&quot;balancing_code&quot;&gt;builder.Services.&lt;span class=&quot;balancing_kw&quot;&gt;AddDbContext&lt;/span&gt;&amp;lt;&lt;span class=&quot;balancing_tp&quot;&gt;AppDbContext&lt;/span&gt;&amp;gt;(options =&amp;gt; options.&lt;span class=&quot;balancing_kw&quot;&gt;UseSqlServer&lt;/span&gt;( builder.Configuration.&lt;span class=&quot;balancing_kw&quot;&gt;GetConnectionString&lt;/span&gt;(&lt;span class=&quot;balancing_st&quot;&gt;&quot;Default&quot;&lt;/span&gt;), sqlOptions =&amp;gt; sqlOptions.&lt;span class=&quot;balancing_kw&quot;&gt;EnableRetryOnFailure&lt;/span&gt;( maxRetryCount: &lt;span class=&quot;balancing_nm&quot;&gt;3&lt;/span&gt;, maxRetryDelay: &lt;span class=&quot;balancing_tp&quot;&gt;TimeSpan&lt;/span&gt;.&lt;span class=&quot;balancing_kw&quot;&gt;FromSeconds&lt;/span&gt;(&lt;span class=&quot;balancing_nm&quot;&gt;5&lt;/span&gt;), errorNumbersToAdd: &lt;span class=&quot;balancing_kw&quot;&gt;null&lt;/span&gt; ) ) );&lt;/div&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Node.js 커넥션 풀 설정 (PostgreSQL)&lt;/h4&gt;
&lt;div class=&quot;balancing_code&quot;&gt;&lt;span class=&quot;balancing_kw&quot;&gt;const&lt;/span&gt; { &lt;span class=&quot;balancing_tp&quot;&gt;Pool&lt;/span&gt; } = &lt;span class=&quot;balancing_kw&quot;&gt;require&lt;/span&gt;(&lt;span class=&quot;balancing_st&quot;&gt;'pg'&lt;/span&gt;); &lt;span class=&quot;balancing_kw&quot;&gt;const&lt;/span&gt; pool = &lt;span class=&quot;balancing_kw&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;balancing_tp&quot;&gt;Pool&lt;/span&gt;({ &lt;span class=&quot;balancing_tp&quot;&gt;host&lt;/span&gt;: &lt;span class=&quot;balancing_st&quot;&gt;'db-server'&lt;/span&gt;, &lt;span class=&quot;balancing_tp&quot;&gt;port&lt;/span&gt;: &lt;span class=&quot;balancing_nm&quot;&gt;5432&lt;/span&gt;, &lt;span class=&quot;balancing_tp&quot;&gt;database&lt;/span&gt;: &lt;span class=&quot;balancing_st&quot;&gt;'mydb'&lt;/span&gt;, &lt;span class=&quot;balancing_tp&quot;&gt;user&lt;/span&gt;: &lt;span class=&quot;balancing_st&quot;&gt;'admin'&lt;/span&gt;, &lt;span class=&quot;balancing_tp&quot;&gt;password&lt;/span&gt;: &lt;span class=&quot;balancing_st&quot;&gt;'***'&lt;/span&gt;, &lt;span class=&quot;balancing_tp&quot;&gt;min&lt;/span&gt;: &lt;span class=&quot;balancing_nm&quot;&gt;5&lt;/span&gt;, &lt;span class=&quot;balancing_tp&quot;&gt;max&lt;/span&gt;: &lt;span class=&quot;balancing_nm&quot;&gt;30&lt;/span&gt;, &lt;span class=&quot;balancing_tp&quot;&gt;idleTimeoutMillis&lt;/span&gt;: &lt;span class=&quot;balancing_nm&quot;&gt;30000&lt;/span&gt;, &lt;span class=&quot;balancing_tp&quot;&gt;connectionTimeoutMillis&lt;/span&gt;: &lt;span class=&quot;balancing_nm&quot;&gt;5000&lt;/span&gt;, }); &lt;span class=&quot;balancing_kw&quot;&gt;const&lt;/span&gt; client = &lt;span class=&quot;balancing_kw&quot;&gt;await&lt;/span&gt; pool.&lt;span class=&quot;balancing_kw&quot;&gt;connect&lt;/span&gt;(); &lt;span class=&quot;balancing_kw&quot;&gt;try&lt;/span&gt; { &lt;span class=&quot;balancing_kw&quot;&gt;const&lt;/span&gt; result = &lt;span class=&quot;balancing_kw&quot;&gt;await&lt;/span&gt; client.&lt;span class=&quot;balancing_kw&quot;&gt;query&lt;/span&gt;( &lt;span class=&quot;balancing_st&quot;&gt;'SELECT * FROM products WHERE id = $1'&lt;/span&gt;, [id] ); &lt;span class=&quot;balancing_kw&quot;&gt;return&lt;/span&gt; result.rows[&lt;span class=&quot;balancing_nm&quot;&gt;0&lt;/span&gt;]; } &lt;span class=&quot;balancing_kw&quot;&gt;finally&lt;/span&gt; { client.&lt;span class=&quot;balancing_kw&quot;&gt;release&lt;/span&gt;(); }&lt;/div&gt;
&lt;div class=&quot;balancing_note&quot;&gt;&lt;b&gt;참고&lt;/b&gt; &amp;mdash; maximum-pool-size 설정은 단순히 크게 잡는 것이 능사가 아닙니다. DB 서버의 max_connections 값과 애플리케이션 인스턴스 수를 함께 고려해야 합니다. 예를 들어 DB max_connections가 200이고 인스턴스가 5대라면, 인스턴스당 풀 크기는 200 / 5 = 40, 여유분을 감안하면 30~35 수준이 적절합니다.&lt;/div&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;커넥션 누수(Connection Leak) 방지&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실무에서 자주 발생하는 장애 원인 중 하나가 &lt;b&gt;커넥션 누수&lt;/b&gt;입니다. 트랜잭션을 열어놓고 예외 발생 시 커넥션을 반환하지 않으면, 풀의 커넥션이 하나씩 고갈되다가 결국 전체 서비스가 멈추게 됩니다.&lt;/p&gt;
&lt;div class=&quot;balancing_code&quot;&gt;&lt;span class=&quot;balancing_cm&quot;&gt;// [C#] 잘못된 예 &amp;mdash; 예외 발생 시 커넥션 미반환&lt;/span&gt; &lt;span class=&quot;balancing_kw&quot;&gt;var&lt;/span&gt; conn = &lt;span class=&quot;balancing_kw&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;balancing_tp&quot;&gt;SqlConnection&lt;/span&gt;(connString); conn.&lt;span class=&quot;balancing_kw&quot;&gt;Open&lt;/span&gt;(); &lt;span class=&quot;balancing_kw&quot;&gt;var&lt;/span&gt; cmd = conn.&lt;span class=&quot;balancing_kw&quot;&gt;CreateCommand&lt;/span&gt;(); cmd.&lt;span class=&quot;balancing_tp&quot;&gt;CommandText&lt;/span&gt; = &lt;span class=&quot;balancing_st&quot;&gt;&quot;SELECT ...&quot;&lt;/span&gt;; cmd.&lt;span class=&quot;balancing_kw&quot;&gt;ExecuteReader&lt;/span&gt;(); &lt;span class=&quot;balancing_cm&quot;&gt;// [C#] 올바른 예 &amp;mdash; using 문 사용&lt;/span&gt; &lt;span class=&quot;balancing_kw&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;balancing_kw&quot;&gt;var&lt;/span&gt; conn = &lt;span class=&quot;balancing_kw&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;balancing_tp&quot;&gt;SqlConnection&lt;/span&gt;(connString); &lt;span class=&quot;balancing_kw&quot;&gt;await&lt;/span&gt; conn.&lt;span class=&quot;balancing_kw&quot;&gt;OpenAsync&lt;/span&gt;(); &lt;span class=&quot;balancing_kw&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;balancing_kw&quot;&gt;var&lt;/span&gt; cmd = conn.&lt;span class=&quot;balancing_kw&quot;&gt;CreateCommand&lt;/span&gt;(); cmd.&lt;span class=&quot;balancing_tp&quot;&gt;CommandText&lt;/span&gt; = &lt;span class=&quot;balancing_st&quot;&gt;&quot;SELECT ...&quot;&lt;/span&gt;; &lt;span class=&quot;balancing_kw&quot;&gt;await&lt;/span&gt; cmd.&lt;span class=&quot;balancing_kw&quot;&gt;ExecuteReaderAsync&lt;/span&gt;();&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span class=&quot;balancing_badge&quot;&gt;5&lt;/span&gt;DB 분산 전략 &amp;mdash; 읽기/쓰기 분리 (Read Replica)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반적인 웹 서비스에서 DB 요청의 &lt;b&gt;70~80%는 읽기(SELECT)&lt;/b&gt; 작업입니다. 이 읽기 부하를 별도의 복제본(Replica)으로 분리하면 Master DB의 부하를 크게 줄일 수 있습니다.&lt;/p&gt;
&lt;div class=&quot;balancing_diagram&quot;&gt;+--- [쓰기 요청] --&amp;gt; [Master DB] [Application] | | (비동기 복제) +--- [읽기 요청] --&amp;gt; [Replica DB 1] [Replica DB 2]&lt;/div&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;ASP.NET Core에서의 읽기/쓰기 분리&lt;/h4&gt;
&lt;div class=&quot;balancing_code&quot;&gt;builder.Services.&lt;span class=&quot;balancing_kw&quot;&gt;AddDbContext&lt;/span&gt;&amp;lt;&lt;span class=&quot;balancing_tp&quot;&gt;WriteDbContext&lt;/span&gt;&amp;gt;(options =&amp;gt; options.&lt;span class=&quot;balancing_kw&quot;&gt;UseSqlServer&lt;/span&gt;(&lt;span class=&quot;balancing_st&quot;&gt;&quot;Server=master-db;...&quot;&lt;/span&gt;)); builder.Services.&lt;span class=&quot;balancing_kw&quot;&gt;AddDbContext&lt;/span&gt;&amp;lt;&lt;span class=&quot;balancing_tp&quot;&gt;ReadDbContext&lt;/span&gt;&amp;gt;(options =&amp;gt; options.&lt;span class=&quot;balancing_kw&quot;&gt;UseSqlServer&lt;/span&gt;(&lt;span class=&quot;balancing_st&quot;&gt;&quot;Server=replica-db;...&quot;&lt;/span&gt;) .&lt;span class=&quot;balancing_kw&quot;&gt;UseQueryTrackingBehavior&lt;/span&gt;( &lt;span class=&quot;balancing_tp&quot;&gt;QueryTrackingBehavior&lt;/span&gt;.NoTracking ));&lt;/div&gt;
&lt;div class=&quot;balancing_code&quot;&gt;&lt;span class=&quot;balancing_kw&quot;&gt;public class&lt;/span&gt; &lt;span class=&quot;balancing_tp&quot;&gt;OrderService&lt;/span&gt; { &lt;span class=&quot;balancing_kw&quot;&gt;private readonly&lt;/span&gt; &lt;span class=&quot;balancing_tp&quot;&gt;WriteDbContext&lt;/span&gt; _writeDb; &lt;span class=&quot;balancing_kw&quot;&gt;private readonly&lt;/span&gt; &lt;span class=&quot;balancing_tp&quot;&gt;ReadDbContext&lt;/span&gt; _readDb; &lt;span class=&quot;balancing_cm&quot;&gt;// 읽기 -- Replica로 라우팅&lt;/span&gt; &lt;span class=&quot;balancing_kw&quot;&gt;public async&lt;/span&gt; &lt;span class=&quot;balancing_tp&quot;&gt;Task&lt;/span&gt;&amp;lt;&lt;span class=&quot;balancing_tp&quot;&gt;List&lt;/span&gt;&amp;lt;&lt;span class=&quot;balancing_tp&quot;&gt;Order&lt;/span&gt;&amp;gt;&amp;gt; &lt;span class=&quot;balancing_kw&quot;&gt;GetOrders&lt;/span&gt;(&lt;span class=&quot;balancing_tp&quot;&gt;long&lt;/span&gt; userId) =&amp;gt; &lt;span class=&quot;balancing_kw&quot;&gt;await&lt;/span&gt; _readDb.Orders .&lt;span class=&quot;balancing_kw&quot;&gt;Where&lt;/span&gt;(o =&amp;gt; o.UserId == userId) .&lt;span class=&quot;balancing_kw&quot;&gt;ToListAsync&lt;/span&gt;(); &lt;span class=&quot;balancing_cm&quot;&gt;// 쓰기 -- Master로 라우팅&lt;/span&gt; &lt;span class=&quot;balancing_kw&quot;&gt;public async&lt;/span&gt; &lt;span class=&quot;balancing_tp&quot;&gt;Task&lt;/span&gt; &lt;span class=&quot;balancing_kw&quot;&gt;CreateOrder&lt;/span&gt;(&lt;span class=&quot;balancing_tp&quot;&gt;Order&lt;/span&gt; order) { _writeDb.Orders.&lt;span class=&quot;balancing_kw&quot;&gt;Add&lt;/span&gt;(order); &lt;span class=&quot;balancing_kw&quot;&gt;await&lt;/span&gt; _writeDb.&lt;span class=&quot;balancing_kw&quot;&gt;SaveChangesAsync&lt;/span&gt;(); } }&lt;/div&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Node.js에서의 읽기/쓰기 분리 (Sequelize)&lt;/h4&gt;
&lt;div class=&quot;balancing_code&quot;&gt;&lt;span class=&quot;balancing_kw&quot;&gt;const&lt;/span&gt; { &lt;span class=&quot;balancing_tp&quot;&gt;Sequelize&lt;/span&gt; } = &lt;span class=&quot;balancing_kw&quot;&gt;require&lt;/span&gt;(&lt;span class=&quot;balancing_st&quot;&gt;'sequelize'&lt;/span&gt;); &lt;span class=&quot;balancing_kw&quot;&gt;const&lt;/span&gt; sequelize = &lt;span class=&quot;balancing_kw&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;balancing_tp&quot;&gt;Sequelize&lt;/span&gt;(&lt;span class=&quot;balancing_st&quot;&gt;'mydb'&lt;/span&gt;, &lt;span class=&quot;balancing_kw&quot;&gt;null&lt;/span&gt;, &lt;span class=&quot;balancing_kw&quot;&gt;null&lt;/span&gt;, { &lt;span class=&quot;balancing_tp&quot;&gt;replication&lt;/span&gt;: { &lt;span class=&quot;balancing_tp&quot;&gt;read&lt;/span&gt;: [ { &lt;span class=&quot;balancing_tp&quot;&gt;host&lt;/span&gt;: &lt;span class=&quot;balancing_st&quot;&gt;'replica-1'&lt;/span&gt;, &lt;span class=&quot;balancing_tp&quot;&gt;username&lt;/span&gt;: &lt;span class=&quot;balancing_st&quot;&gt;'reader'&lt;/span&gt;, &lt;span class=&quot;balancing_tp&quot;&gt;password&lt;/span&gt;: &lt;span class=&quot;balancing_st&quot;&gt;'***'&lt;/span&gt; }, { &lt;span class=&quot;balancing_tp&quot;&gt;host&lt;/span&gt;: &lt;span class=&quot;balancing_st&quot;&gt;'replica-2'&lt;/span&gt;, &lt;span class=&quot;balancing_tp&quot;&gt;username&lt;/span&gt;: &lt;span class=&quot;balancing_st&quot;&gt;'reader'&lt;/span&gt;, &lt;span class=&quot;balancing_tp&quot;&gt;password&lt;/span&gt;: &lt;span class=&quot;balancing_st&quot;&gt;'***'&lt;/span&gt; } ], &lt;span class=&quot;balancing_tp&quot;&gt;write&lt;/span&gt;: { &lt;span class=&quot;balancing_tp&quot;&gt;host&lt;/span&gt;: &lt;span class=&quot;balancing_st&quot;&gt;'master-db'&lt;/span&gt;, &lt;span class=&quot;balancing_tp&quot;&gt;username&lt;/span&gt;: &lt;span class=&quot;balancing_st&quot;&gt;'writer'&lt;/span&gt;, &lt;span class=&quot;balancing_tp&quot;&gt;password&lt;/span&gt;: &lt;span class=&quot;balancing_st&quot;&gt;'***'&lt;/span&gt; } }, &lt;span class=&quot;balancing_tp&quot;&gt;dialect&lt;/span&gt;: &lt;span class=&quot;balancing_st&quot;&gt;'postgres'&lt;/span&gt;, &lt;span class=&quot;balancing_tp&quot;&gt;pool&lt;/span&gt;: { &lt;span class=&quot;balancing_tp&quot;&gt;max&lt;/span&gt;: &lt;span class=&quot;balancing_nm&quot;&gt;30&lt;/span&gt;, &lt;span class=&quot;balancing_tp&quot;&gt;min&lt;/span&gt;: &lt;span class=&quot;balancing_nm&quot;&gt;5&lt;/span&gt;, &lt;span class=&quot;balancing_tp&quot;&gt;idle&lt;/span&gt;: &lt;span class=&quot;balancing_nm&quot;&gt;10000&lt;/span&gt; } });&lt;/div&gt;
&lt;div class=&quot;balancing_warn&quot;&gt;&lt;b&gt;주의 &amp;mdash; 복제 지연(Replication Lag)&lt;/b&gt; &amp;mdash; Master에서 Replica로의 데이터 복제는 비동기로 이루어지므로 수 밀리초에서 수 초의 지연이 발생할 수 있습니다. 사용자가 게시글을 작성한 직후 목록을 조회하면 방금 작성한 글이 보이지 않는 문제가 생길 수 있습니다. 쓰기 직후 읽기(Read-after-Write) 시에는 강제로 Master에서 조회하도록 처리해야 합니다.&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span class=&quot;balancing_badge&quot;&gt;6&lt;/span&gt;캐싱 전략 &amp;mdash; DB 부하를 줄이는 가장 효과적인 방법&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아무리 DB를 분산해도 동일한 데이터를 반복 조회하는 요청은 &lt;b&gt;캐시로 처리하는 것이 가장 효율적&lt;/b&gt;입니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;캐시 적용 계층&lt;/h4&gt;
&lt;div class=&quot;balancing_diagram&quot;&gt;[클라이언트] --&amp;gt; [CDN 캐시] --&amp;gt; [애플리케이션 캐시] --&amp;gt; [DB 캐시] --&amp;gt; [DB] (정적 자원) (Redis / Local) (Query Cache)&lt;/div&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;ASP.NET Core &amp;mdash; IDistributedCache 기반 Look-Aside 패턴&lt;/h4&gt;
&lt;div class=&quot;balancing_code&quot;&gt;&lt;span class=&quot;balancing_kw&quot;&gt;public class&lt;/span&gt; &lt;span class=&quot;balancing_tp&quot;&gt;ProductService&lt;/span&gt; { &lt;span class=&quot;balancing_kw&quot;&gt;private readonly&lt;/span&gt; &lt;span class=&quot;balancing_tp&quot;&gt;IDistributedCache&lt;/span&gt; _cache; &lt;span class=&quot;balancing_kw&quot;&gt;private readonly&lt;/span&gt; &lt;span class=&quot;balancing_tp&quot;&gt;ReadDbContext&lt;/span&gt; _db; &lt;span class=&quot;balancing_kw&quot;&gt;public async&lt;/span&gt; &lt;span class=&quot;balancing_tp&quot;&gt;Task&lt;/span&gt;&amp;lt;&lt;span class=&quot;balancing_tp&quot;&gt;Product&lt;/span&gt;&amp;gt; &lt;span class=&quot;balancing_kw&quot;&gt;GetProduct&lt;/span&gt;(&lt;span class=&quot;balancing_tp&quot;&gt;long&lt;/span&gt; id) { &lt;span class=&quot;balancing_kw&quot;&gt;var&lt;/span&gt; key = &lt;span class=&quot;balancing_st&quot;&gt;$&quot;product:{id}&quot;&lt;/span&gt;; &lt;span class=&quot;balancing_kw&quot;&gt;var&lt;/span&gt; cached = &lt;span class=&quot;balancing_kw&quot;&gt;await&lt;/span&gt; _cache.&lt;span class=&quot;balancing_kw&quot;&gt;GetStringAsync&lt;/span&gt;(key); &lt;span class=&quot;balancing_kw&quot;&gt;if&lt;/span&gt; (cached != &lt;span class=&quot;balancing_kw&quot;&gt;null&lt;/span&gt;) &lt;span class=&quot;balancing_kw&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;balancing_tp&quot;&gt;JsonSerializer&lt;/span&gt;.&lt;span class=&quot;balancing_kw&quot;&gt;Deserialize&lt;/span&gt;&amp;lt;&lt;span class=&quot;balancing_tp&quot;&gt;Product&lt;/span&gt;&amp;gt;(cached); &lt;span class=&quot;balancing_kw&quot;&gt;var&lt;/span&gt; product = &lt;span class=&quot;balancing_kw&quot;&gt;await&lt;/span&gt; _db.Products.&lt;span class=&quot;balancing_kw&quot;&gt;FindAsync&lt;/span&gt;(id); &lt;span class=&quot;balancing_kw&quot;&gt;await&lt;/span&gt; _cache.&lt;span class=&quot;balancing_kw&quot;&gt;SetStringAsync&lt;/span&gt;(key, &lt;span class=&quot;balancing_tp&quot;&gt;JsonSerializer&lt;/span&gt;.&lt;span class=&quot;balancing_kw&quot;&gt;Serialize&lt;/span&gt;(product), &lt;span class=&quot;balancing_kw&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;balancing_tp&quot;&gt;DistributedCacheEntryOptions&lt;/span&gt; { &lt;span class=&quot;balancing_tp&quot;&gt;AbsoluteExpirationRelativeToNow&lt;/span&gt; = &lt;span class=&quot;balancing_tp&quot;&gt;TimeSpan&lt;/span&gt;.&lt;span class=&quot;balancing_kw&quot;&gt;FromMinutes&lt;/span&gt;(&lt;span class=&quot;balancing_nm&quot;&gt;30&lt;/span&gt;) }); &lt;span class=&quot;balancing_kw&quot;&gt;return&lt;/span&gt; product; } }&lt;/div&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Node.js &amp;mdash; ioredis 기반 캐시 유틸리티&lt;/h4&gt;
&lt;div class=&quot;balancing_code&quot;&gt;&lt;span class=&quot;balancing_kw&quot;&gt;const&lt;/span&gt; Redis = &lt;span class=&quot;balancing_kw&quot;&gt;require&lt;/span&gt;(&lt;span class=&quot;balancing_st&quot;&gt;'ioredis'&lt;/span&gt;); &lt;span class=&quot;balancing_kw&quot;&gt;const&lt;/span&gt; redis = &lt;span class=&quot;balancing_kw&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;balancing_tp&quot;&gt;Redis&lt;/span&gt;(&lt;span class=&quot;balancing_st&quot;&gt;'redis://redis-server:6379'&lt;/span&gt;); &lt;span class=&quot;balancing_kw&quot;&gt;async function&lt;/span&gt; &lt;span class=&quot;balancing_kw&quot;&gt;getProduct&lt;/span&gt;(id) { &lt;span class=&quot;balancing_kw&quot;&gt;const&lt;/span&gt; key = &lt;span class=&quot;balancing_st&quot;&gt;`product:${id}`&lt;/span&gt;; &lt;span class=&quot;balancing_kw&quot;&gt;const&lt;/span&gt; cached = &lt;span class=&quot;balancing_kw&quot;&gt;await&lt;/span&gt; redis.&lt;span class=&quot;balancing_kw&quot;&gt;get&lt;/span&gt;(key); &lt;span class=&quot;balancing_kw&quot;&gt;if&lt;/span&gt; (cached) &lt;span class=&quot;balancing_kw&quot;&gt;return&lt;/span&gt; JSON.&lt;span class=&quot;balancing_kw&quot;&gt;parse&lt;/span&gt;(cached); &lt;span class=&quot;balancing_kw&quot;&gt;const&lt;/span&gt; product = &lt;span class=&quot;balancing_kw&quot;&gt;await&lt;/span&gt; db.&lt;span class=&quot;balancing_kw&quot;&gt;query&lt;/span&gt;( &lt;span class=&quot;balancing_st&quot;&gt;'SELECT * FROM products WHERE id = $1'&lt;/span&gt;, [id] ); &lt;span class=&quot;balancing_kw&quot;&gt;await&lt;/span&gt; redis.&lt;span class=&quot;balancing_kw&quot;&gt;setex&lt;/span&gt;(key, &lt;span class=&quot;balancing_nm&quot;&gt;1800&lt;/span&gt;, JSON.&lt;span class=&quot;balancing_kw&quot;&gt;stringify&lt;/span&gt;(product.rows[&lt;span class=&quot;balancing_nm&quot;&gt;0&lt;/span&gt;]) ); &lt;span class=&quot;balancing_kw&quot;&gt;return&lt;/span&gt; product.rows[&lt;span class=&quot;balancing_nm&quot;&gt;0&lt;/span&gt;]; }&lt;/div&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;캐시 무효화(Invalidation) 전략 비교&lt;/h4&gt;
&lt;div class=&quot;balancing_tbl&quot;&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;전략&lt;/th&gt;
&lt;th&gt;설명&lt;/th&gt;
&lt;th&gt;장점&lt;/th&gt;
&lt;th&gt;단점&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;TTL 기반&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;일정 시간 후 자동 만료&lt;/td&gt;
&lt;td&gt;구현이 단순합니다&lt;/td&gt;
&lt;td&gt;만료 전까지 오래된 데이터를 제공할 수 있습니다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Write-Through&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;데이터 변경 시 캐시도 즉시 갱신&lt;/td&gt;
&lt;td&gt;데이터 일관성이 높습니다&lt;/td&gt;
&lt;td&gt;쓰기 성능이 저하됩니다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Write-Behind&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;캐시에 먼저 쓰고 일정 주기로 DB에 반영&lt;/td&gt;
&lt;td&gt;쓰기 성능이 우수합니다&lt;/td&gt;
&lt;td&gt;데이터 유실 위험이 있습니다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;이벤트 기반&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;데이터 변경 이벤트 발행 시 캐시 갱신&lt;/td&gt;
&lt;td&gt;시스템 간 결합도가 낮습니다&lt;/td&gt;
&lt;td&gt;이벤트 유실 처리가 필요합니다&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span class=&quot;balancing_badge&quot;&gt;7&lt;/span&gt;대용량 트래픽 대응 &amp;mdash; 실무 체크리스트&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제 서비스에서 대규모 트래픽에 대비할 때 점검해야 할 항목을 계층별로 정리하면 다음과 같습니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;WAS 계층&lt;/h4&gt;
&lt;ul class=&quot;balancing_checklist&quot; style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;로드밸런서 구성 (L4/L7 선택, IIS ARR 또는 Nginx)&lt;/li&gt;
&lt;li&gt;Auto Scaling 정책 수립 (CPU, 메모리, 요청 수 기준)&lt;/li&gt;
&lt;li&gt;Stateless 설계 (세션 외부 저장소 또는 JWT)&lt;/li&gt;
&lt;li&gt;서킷 브레이커(Circuit Breaker) 적용 &amp;mdash; 외부 서비스 장애 전파 방지&lt;/li&gt;
&lt;li&gt;Rate Limiting / Throttling &amp;mdash; 비정상 트래픽 차단&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;DB 계층&lt;/h4&gt;
&lt;ul class=&quot;balancing_checklist&quot; style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Connection Pool 적정 사이즈 산정&lt;/li&gt;
&lt;li&gt;읽기/쓰기 분리 (Read Replica)&lt;/li&gt;
&lt;li&gt;쿼리 최적화 및 인덱스 점검&lt;/li&gt;
&lt;li&gt;Slow Query 모니터링&lt;/li&gt;
&lt;li&gt;필요 시 샤딩(Sharding) 검토&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;캐시 계층&lt;/h4&gt;
&lt;ul class=&quot;balancing_checklist&quot; style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Redis/Memcached 클러스터 구성&lt;/li&gt;
&lt;li&gt;캐시 히트율 모니터링 (목표: 80% 이상)&lt;/li&gt;
&lt;li&gt;캐시 스탬피드(Cache Stampede) 방지 &amp;mdash; 동시 만료 시 DB 폭주 대비&lt;/li&gt;
&lt;li&gt;Hot Key 분산 처리&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;인프라 / 모니터링&lt;/h4&gt;
&lt;ul class=&quot;balancing_checklist&quot; style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;CDN 적용 (정적 자원)&lt;/li&gt;
&lt;li&gt;메시지 큐(Kafka, RabbitMQ) 도입 &amp;mdash; 비동기 처리로 피크 부하 완화&lt;/li&gt;
&lt;li&gt;APM 도구(Datadog, Grafana, Pinpoint 등) 연동&lt;/li&gt;
&lt;li&gt;부하 테스트(nGrinder, k6, JMeter) 정기 수행&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div class=&quot;balancing_ref&quot;&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;참고 자료 및 공식 문서&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Microsoft &amp;mdash; IIS Application Request Routing&lt;/b&gt;&lt;br /&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/iis/extensions/planning-for-arr/application-request-routing-version-2-overview&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://learn.microsoft.com/en-us/iis/extensions/planning-for-arr&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Microsoft &amp;mdash; ASP.NET Core 분산 캐싱&lt;/b&gt;&lt;br /&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/aspnet/core/performance/caching/distributed&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://learn.microsoft.com/en-us/aspnet/core/performance/caching/distributed&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Microsoft &amp;mdash; ASP.NET Core Data Protection 키 저장소&lt;/b&gt;&lt;br /&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/aspnet/core/security/data-protection/implementation/key-storage-providers&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://learn.microsoft.com/en-us/aspnet/core/security/data-protection/implementation/key-storage-providers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Microsoft &amp;mdash; ASP.NET Core Health Checks&lt;/b&gt;&lt;br /&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/aspnet/core/host-and-deploy/health-checks&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://learn.microsoft.com/en-us/aspnet/core/host-and-deploy/health-checks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Microsoft &amp;mdash; SqlConnection 커넥션 풀링&lt;/b&gt;&lt;br /&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/framework/data/adonet/sql-server-connection-pooling&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://learn.microsoft.com/en-us/dotnet/framework/data/adonet/sql-server-connection-pooling&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Nginx &amp;mdash; HTTP Load Balancing&lt;/b&gt;&lt;br /&gt;&lt;a href=&quot;https://docs.nginx.com/nginx/admin-guide/load-balancer/http-load-balancer/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://docs.nginx.com/nginx/admin-guide/load-balancer/http-load-balancer/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Node.js &amp;mdash; Cluster 모듈 공식 문서&lt;/b&gt;&lt;br /&gt;&lt;a href=&quot;https://nodejs.org/api/cluster.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://nodejs.org/api/cluster.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;PM2 &amp;mdash; Cluster Mode 공식 문서&lt;/b&gt;&lt;br /&gt;&lt;a href=&quot;https://pm2.keymetrics.io/docs/usage/cluster-mode/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://pm2.keymetrics.io/docs/usage/cluster-mode/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;HikariCP &amp;mdash; GitHub (Connection Pool)&lt;/b&gt;&lt;br /&gt;&lt;a href=&quot;https://github.com/brettwooldridge/HikariCP&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/brettwooldridge/HikariCP&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;node-postgres (pg) &amp;mdash; Connection Pool&lt;/b&gt;&lt;br /&gt;&lt;a href=&quot;https://node-postgres.com/features/pooling&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://node-postgres.com/features/pooling&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Sequelize &amp;mdash; Read Replication&lt;/b&gt;&lt;br /&gt;&lt;a href=&quot;https://sequelize.org/docs/v6/other-topics/read-replication/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://sequelize.org/docs/v6/other-topics/read-replication/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Redis &amp;mdash; 공식 문서&lt;/b&gt;&lt;br /&gt;&lt;a href=&quot;https://redis.io/docs/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://redis.io/docs/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;마무리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로드밸런싱과 DB 분산 전략은 서비스가 성장할수록 반드시 마주하게 되는 과제입니다. 처음부터 완벽한 아키텍처를 설계할 필요는 없지만, 각 기술이 &lt;b&gt;어떤 문제를 해결하는지&lt;/b&gt;, 그리고 &lt;b&gt;어떤 트레이드오프가 있는지&lt;/b&gt; 이해하고 있으면 장애 상황에서 훨씬 빠르게 대응할 수 있습니다.&lt;/p&gt;
&lt;div class=&quot;balancing_summary&quot;&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;핵심 정리!&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;WAS는 Stateless하게&lt;/b&gt; 설계하고 로드밸런서로 수평 확장합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;DB는 커넥션 풀 관리와 읽기/쓰기 분리&lt;/b&gt;로 병목을 줄입니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;캐시를 적극 활용&lt;/b&gt;하여 불필요한 DB 접근을 줄입니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;작은 규모의 서비스라도 이런 구조를 머릿속에 그려두시면, 나중에 트래픽이 증가했을 때 당황하지 않고 단계적으로 확장할 수 있을 것입니다.&lt;/p&gt;
&lt;div class=&quot;balancing_tags&quot;&gt;&lt;span&gt;#로드밸런싱&lt;/span&gt; &lt;span&gt;#LoadBalancing&lt;/span&gt; &lt;span&gt;#DB분산처리&lt;/span&gt; &lt;span&gt;#ConnectionPool&lt;/span&gt; &lt;span&gt;#ReadReplica&lt;/span&gt; &lt;span&gt;#캐싱전략&lt;/span&gt; &lt;span&gt;#대용량트래픽&lt;/span&gt; &lt;span&gt;#서버아키텍처&lt;/span&gt; &lt;span&gt;#ASPNETCore&lt;/span&gt; &lt;span&gt;#NodeJS&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;</description>
      <category>DEVELOPMENT</category>
      <category>ASP.NET Core 분산 세션</category>
      <category>connection pool</category>
      <category>DB 커넥션 풀</category>
      <category>IIS ARR 서버팜</category>
      <category>load balancing</category>
      <category>Node.js 클러스터</category>
      <category>read replica</category>
      <category>Redis 캐싱 전략</category>
      <category>대용량 트래픽 처리</category>
      <category>로드밸런싱</category>
      <author>간지뽕빨리턴님</author>
      <guid isPermaLink="true">https://odinbox.tistory.com/580</guid>
      <comments>https://odinbox.tistory.com/580#entry580comment</comments>
      <pubDate>Sun, 12 Apr 2026 00:04:57 +0900</pubDate>
    </item>
    <item>
      <title>Claude Code 소스 유출 사건 총정리, 유출 경위, 타임라인, 취약점, 그리고 개발자가 반드시 봐야 할 핵심</title>
      <link>https://odinbox.tistory.com/579</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oWyG5/dJMcaflPuPV/yKbaevNG5nL6iiWvol4Jwk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oWyG5/dJMcaflPuPV/yKbaevNG5nL6iiWvol4Jwk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oWyG5/dJMcaflPuPV/yKbaevNG5nL6iiWvol4Jwk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoWyG5%2FdJMcaflPuPV%2FyKbaevNG5nL6iiWvol4Jwk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;400&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;div&gt;
&lt;style&gt;
  .caludecodehack_wrap{
    --caludecodehack_bg:#f7f9fc;
    --caludecodehack_card:#ffffff;
    --caludecodehack_line:#e5eaf2;
    --caludecodehack_line2:#d9e2ef;
    --caludecodehack_text:#18212f;
    --caludecodehack_sub:#556070;
    --caludecodehack_muted:#6b7788;
    --caludecodehack_point:#1f5fae;
    --caludecodehack_point_dark:#123d73;
    --caludecodehack_point_soft:#eef5ff;
    --caludecodehack_dark:#0b1220;
    --caludecodehack_dark2:#111a2b;
    --caludecodehack_warn:#a03a12;
    --caludecodehack_warn_soft:#fff5ef;
    --caludecodehack_ok:#0f6b46;
    --caludecodehack_ok_soft:#eefbf4;
    --caludecodehack_shadow:0 10px 30px rgba(15,23,42,0.06);
    --caludecodehack_radius:22px;
    max-width:1080px;
    margin:0 auto;
    padding:16px 20px 80px;
    color:var(--caludecodehack_text);
    font-family:&quot;Pretendard&quot;,&quot;Noto Sans KR&quot;,&quot;Malgun Gothic&quot;,sans-serif;
    line-height:1.82;
    word-break:keep-all;
  }
  .caludecodehack_wrap *{
    box-sizing:border-box;
  }
  .caludecodehack_wrap a{
    color:var(--caludecodehack_point);
    text-decoration:none;
  }

  .caludecodehack_doc_header{
    background:linear-gradient(180deg,#fbfdff 0%, #f3f7fc 100%);
    border:1px solid var(--caludecodehack_line);
    border-radius:28px;
    padding:30px 28px;
    box-shadow:var(--caludecodehack_shadow);
    margin:0 0 22px;
  }
  .caludecodehack_doc_kicker{
    display:inline-flex;
    align-items:center;
    gap:8px;
    border:1px solid var(--caludecodehack_line2);
    background:#fff;
    color:var(--caludecodehack_point_dark);
    border-radius:999px;
    padding:8px 12px;
    font-size:13px;
    font-weight:800;
    margin-bottom:14px;
  }
  .caludecodehack_doc_title{
    margin:0 0 14px;
    font-size:clamp(30px,4vw,42px);
    line-height:1.3;
    font-weight:900;
    letter-spacing:-0.03em;
    color:#0f172a;
  }
  .caludecodehack_doc_desc{
    margin:0 0 18px;
    font-size:17px;
    color:var(--caludecodehack_sub);
  }
  .caludecodehack_doc_meta{
    display:grid;
    grid-template-columns:repeat(3,minmax(0,1fr));
    gap:12px;
    margin-top:16px;
  }
  .caludecodehack_doc_meta_item{
    border:1px solid var(--caludecodehack_line);
    background:#fff;
    border-radius:18px;
    padding:14px 14px;
  }
  .caludecodehack_doc_meta_item strong{
    display:block;
    margin-bottom:6px;
    font-size:12px;
    font-weight:900;
    color:var(--caludecodehack_muted);
    text-transform:uppercase;
    letter-spacing:.04em;
  }
  .caludecodehack_doc_meta_item span{
    display:block;
    font-size:15px;
    font-weight:800;
    color:#111827;
    line-height:1.5;
  }

  .caludecodehack_toc{
    background:var(--caludecodehack_card);
    border:1px solid var(--caludecodehack_line);
    border-radius:var(--caludecodehack_radius);
    box-shadow:var(--caludecodehack_shadow);
    padding:24px 24px;
    margin:0 0 22px;
  }
  .caludecodehack_toc h2{
    margin:0 0 12px;
    font-size:22px;
    font-weight:900;
    color:#0f172a;
  }
  .caludecodehack_toc ul{
    list-style:none;
    margin:0;
    padding:0;
    display:grid;
    gap:9px;
  }
  .caludecodehack_toc li{
    margin:0;
    padding:0;
  }
  .caludecodehack_toc a{
    display:block;
    padding:10px 12px;
    border-radius:12px;
    color:var(--caludecodehack_point_dark);
    font-weight:800;
    background:#f8fbff;
    border:1px solid #edf3fb;
  }

  .caludecodehack_section{
    background:var(--caludecodehack_card);
    border:1px solid var(--caludecodehack_line);
    border-radius:var(--caludecodehack_radius);
    box-shadow:var(--caludecodehack_shadow);
    padding:30px 24px;
    margin:0 0 22px;
  }
  .caludecodehack_section h2{
    margin:0 0 18px;
    padding-bottom:12px;
    border-bottom:2px solid #edf2f7;
    font-size:30px;
    line-height:1.35;
    font-weight:900;
    letter-spacing:-0.02em;
    color:#0f172a;
  }
  .caludecodehack_section h3{
    margin:28px 0 12px;
    font-size:23px;
    line-height:1.45;
    font-weight:900;
    letter-spacing:-0.02em;
    color:#111827;
  }
  .caludecodehack_section h4{
    margin:22px 0 10px;
    font-size:18px;
    line-height:1.5;
    font-weight:800;
    color:#111827;
  }
  .caludecodehack_section p{
    margin:0 0 16px;
    font-size:17px;
    color:var(--caludecodehack_text);
  }
  .caludecodehack_lead{
    font-size:18px;
    font-weight:700;
    color:#233247;
  }

  .caludecodehack_note,
  .caludecodehack_warn,
  .caludecodehack_ok{
    border-radius:18px;
    padding:18px 18px;
    margin:18px 0;
    border:1px solid transparent;
  }
  .caludecodehack_note{
    background:var(--caludecodehack_point_soft);
    border-color:#d8e7ff;
  }
  .caludecodehack_warn{
    background:var(--caludecodehack_warn_soft);
    border-color:#f3d1c2;
  }
  .caludecodehack_ok{
    background:var(--caludecodehack_ok_soft);
    border-color:#ccead9;
  }

  .caludecodehack_quote{
    margin:18px 0;
    padding:18px 20px;
    background:#f8fbff;
    border:1px solid #e5efff;
    border-left:4px solid var(--caludecodehack_point);
    border-radius:0 16px 16px 0;
    font-size:18px;
    font-weight:800;
    color:#10233f;
  }

  .caludecodehack_list{
    list-style:none;
    margin:16px 0;
    padding:0;
  }
  .caludecodehack_list li{
    position:relative;
    padding-left:18px;
    margin:0 0 12px;
    color:var(--caludecodehack_text);
  }
  .caludecodehack_list li::before{
    content:&quot;&quot;;
    position:absolute;
    left:0;
    top:12px;
    width:7px;
    height:7px;
    border-radius:50%;
    background:var(--caludecodehack_point);
  }
  .caludecodehack_label{
    font-weight:900;
    color:#0f172a;
  }

  .caludecodehack_grid{
    display:grid;
    grid-template-columns:repeat(2,minmax(0,1fr));
    gap:16px;
    margin:18px 0;
  }
  .caludecodehack_card_mini{
    border:1px solid var(--caludecodehack_line);
    background:#fbfcfe;
    border-radius:18px;
    padding:18px;
  }
  .caludecodehack_card_mini h4{
    margin:0 0 8px;
    font-size:18px;
    font-weight:900;
  }
  .caludecodehack_card_mini p{
    margin:0;
    font-size:15px;
    color:var(--caludecodehack_sub);
  }

  .caludecodehack_table{
    width:100%;
    border-collapse:collapse;
    margin:18px 0;
    font-size:15px;
  }
  .caludecodehack_table th,
  .caludecodehack_table td{
    border:1px solid var(--caludecodehack_line);
    padding:14px 12px;
    text-align:left;
    vertical-align:top;
  }
  .caludecodehack_table th{
    background:#f8fbff;
    font-weight:900;
    color:#111827;
  }

  .caludecodehack_timeline{
    position:relative;
    margin:16px 0 0;
    padding-left:22px;
    border-left:2px solid #d9e4f3;
  }
  .caludecodehack_timeline_item{
    position:relative;
    padding:0 0 20px 14px;
  }
  .caludecodehack_timeline_item::before{
    content:&quot;&quot;;
    position:absolute;
    left:-29px;
    top:8px;
    width:12px;
    height:12px;
    border-radius:50%;
    background:var(--caludecodehack_point);
    box-shadow:0 0 0 4px #edf4ff;
  }
  .caludecodehack_time{
    display:inline-block;
    margin-bottom:8px;
    padding:6px 10px;
    background:#eef5ff;
    color:var(--caludecodehack_point_dark);
    border-radius:999px;
    font-size:13px;
    font-weight:900;
  }

  .caludecodehack_codewrap{
    margin:16px 0 18px;
    border:1px solid #1f2b42;
    border-radius:18px;
    overflow:hidden;
    background:var(--caludecodehack_dark);
    box-shadow:inset 0 1px 0 rgba(255,255,255,0.03);
  }
  .caludecodehack_codehead{
    display:flex;
    align-items:center;
    justify-content:space-between;
    gap:10px;
    padding:10px 14px;
    background:var(--caludecodehack_dark2);
    border-bottom:1px solid rgba(255,255,255,0.06);
  }
  .caludecodehack_codehead strong{
    font-size:13px;
    font-weight:900;
    color:#d7e3ff;
    letter-spacing:.02em;
  }
  .caludecodehack_codehead span{
    font-size:12px;
    color:#8ea3c7;
  }
  .caludecodehack_codeblock{
    margin:0;
    padding:18px 18px 20px;
    overflow:auto;
    font-size:15px;
    line-height:1.75;
    color:#f4f7ff;
    font-family:Consolas, &quot;SFMono-Regular&quot;, Menlo, Monaco, &quot;Liberation Mono&quot;, monospace;
    white-space:pre;
  }

  .caludecodehack_faq{
    display:grid;
    gap:14px;
    margin-top:18px;
  }
  .caludecodehack_faq details{
    border:1px solid var(--caludecodehack_line);
    background:#fff;
    border-radius:18px;
    padding:16px 18px;
  }
  .caludecodehack_faq summary{
    cursor:pointer;
    font-weight:900;
    color:#111827;
  }
  .caludecodehack_faq p{
    margin:12px 0 0;
    color:var(--caludecodehack_sub);
  }

  .caludecodehack_tags{
    display:flex;
    flex-wrap:wrap;
    gap:10px;
    margin-top:18px;
  }
  .caludecodehack_tags span{
    display:inline-block;
    padding:9px 12px;
    border-radius:999px;
    border:1px solid var(--caludecodehack_line);
    background:#fff;
    font-size:13px;
    font-weight:800;
    color:#22324a;
  }

  .caludecodehack_refs{
    list-style:none;
    margin:0;
    padding:0;
  }
  .caludecodehack_refs li{
    margin:0 0 10px;
    padding-left:16px;
    position:relative;
    color:var(--caludecodehack_sub);
    font-size:15px;
  }
  .caludecodehack_refs li::before{
    content:&quot;&quot;;
    position:absolute;
    left:0;
    top:11px;
    width:6px;
    height:6px;
    border-radius:50%;
    background:var(--caludecodehack_point);
  }

  .caludecodehack_cta{
    background:linear-gradient(180deg,#103c73 0%, #1b56a0 100%);
    color:#fff;
    border-radius:24px;
    padding:30px 24px;
    box-shadow:var(--caludecodehack_shadow);
    margin-top:28px;
  }
  .caludecodehack_cta h2{
    margin:0 0 14px;
    font-size:28px;
    line-height:1.4;
    font-weight:900;
  }
  .caludecodehack_cta p{
    margin:0 0 10px;
    color:rgba(255,255,255,0.96);
  }

  @media (max-width:920px){
    .caludecodehack_doc_meta,
    .caludecodehack_grid{
      grid-template-columns:1fr;
    }
    .caludecodehack_wrap{
      padding:14px 14px 60px;
    }
    .caludecodehack_doc_header,
    .caludecodehack_toc,
    .caludecodehack_section,
    .caludecodehack_cta{
      padding:22px 18px;
      border-radius:20px;
    }
    .caludecodehack_doc_title{
      font-size:28px;
    }
    .caludecodehack_section h2{
      font-size:24px;
    }
    .caludecodehack_section h3{
      font-size:20px;
    }
    .caludecodehack_codeblock{
      font-size:14px;
    }
  }
&lt;/style&gt;
&lt;/div&gt;
&lt;div class=&quot;caludecodehack_wrap&quot;&gt;
&lt;section class=&quot;caludecodehack_doc_header&quot;&gt;
&lt;div class=&quot;caludecodehack_doc_kicker&quot;&gt;Security Analysis &amp;middot; Claude Code Leak &amp;middot; Developer Notes&lt;/div&gt;
&lt;h1 class=&quot;caludecodehack_doc_title&quot;&gt;Claude Code 소스 유출 사건 총정리 : 유출 경위, 타임라인, 취약점, 그리고 개발자가 반드시 봐야 할 핵심&lt;/h1&gt;
&lt;p class=&quot;caludecodehack_doc_desc&quot; data-ke-size=&quot;size16&quot;&gt;이번 Claude Code 소스 유출 사건은 단순한 코드 공개 이슈가 아닙니다. AI 코딩 도구의 배포 구조, 권한 제어, 샌드박스 모델, 설정 파일 신뢰 경계, DevSecOps 수준의 릴리즈 관리까지 한 번에 드러난 사건이었습니다. 이 글에서는 사건의 흐름부터 기술적 의미, 실무자가 당장 점검해야 할 포인트까지 개발자 관점으로 정리합니다.&lt;/p&gt;
&lt;div class=&quot;caludecodehack_doc_meta&quot;&gt;
&lt;div class=&quot;caludecodehack_doc_meta_item&quot;&gt;&lt;b&gt;Topic&lt;/b&gt; &lt;span&gt;Claude Code source leak&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;caludecodehack_doc_meta_item&quot;&gt;&lt;b&gt;Focus&lt;/b&gt; &lt;span&gt;보안 구조 &amp;middot; 에이전트 실행 &amp;middot; 공급망 리스크&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;caludecodehack_doc_meta_item&quot;&gt;&lt;b&gt;Audience&lt;/b&gt; &lt;span&gt;개발자 &amp;middot; 보안 담당자 &amp;middot; DevSecOps 실무자&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section class=&quot;caludecodehack_toc&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;목차&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;#caludecodehack_sec1&quot;&gt;1. Claude Code 유출 사건이 왜 큰 문제였나&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#caludecodehack_sec2&quot;&gt;2. 유출 경위와 주요 타임라인&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#caludecodehack_sec3&quot;&gt;3. 유출된 것과 유출되지 않은 것&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#caludecodehack_sec4&quot;&gt;4. Claude Code 내부 구조와 기술 포인트&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#caludecodehack_sec4a&quot;&gt;4-1. 유출된 소스에서 드러난 핵심 코드 패턴&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#caludecodehack_sec5&quot;&gt;5. 취약점, 보안 결함, 실제 위험성&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#caludecodehack_sec6&quot;&gt;6. 개발자와 조직이 지금 점검해야 할 대응책&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#caludecodehack_sec7&quot;&gt;7. 마무리 : 이번 사건이 남긴 진짜 교훈&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#caludecodehack_sec8&quot;&gt;8. 자주 묻는 질문 Q&amp;amp;A&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#caludecodehack_sec9&quot;&gt;9. 참고 자료&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;section id=&quot;caludecodehack_sec1&quot; class=&quot;caludecodehack_section&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. Claude Code 유출 사건이 왜 큰 문제였나&lt;/h2&gt;
&lt;p class=&quot;caludecodehack_lead&quot; data-ke-size=&quot;size16&quot;&gt;결론부터 말하면, 이번 사건은 단순히 코드가 노출됐다는 수준을 넘어서, AI 에이전트형 개발 도구가 실제로 어떤 방식으로 동작하는지 운영 구조가 바깥으로 드러났다는 점에서 매우 민감했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히 이번 사건은 모델 가중치나 고객 데이터가 통째로 빠져나간 형태와는 다르게, Claude Code의 에이전트 런타임 구조, 권한 정책, 도구 실행 흐름, 샌드박스 설계, 설정 파일 처리 방식 같은 핵심 구현 디테일이 외부 분석 대상이 되었다는 점이 중요합니다.&lt;/p&gt;
&lt;div class=&quot;caludecodehack_note&quot;&gt;&lt;b&gt;핵심 요약&lt;/b&gt;&lt;br /&gt;이번 유출은 모델 유출이라기보다 AI 코딩 도구 운영 구조 노출에 가깝습니다. 그래서 공격자 입장에서는 취약점을 더 빨리 찾을 수 있고, 개발자 입장에서는 제품의 신뢰 경계가 어디서 무너질 수 있는지 더 선명하게 보이게 됩니다.&lt;/div&gt;
&lt;ul class=&quot;caludecodehack_list&quot; style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span class=&quot;caludecodehack_label&quot;&gt;사건의 본질 : &lt;/span&gt;코드 몇 줄이 새어나간 문제가 아니라 배포 거버넌스 실패 문제였습니다.&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;caludecodehack_label&quot;&gt;보안적 의미 : &lt;/span&gt;권한 모델과 샌드박스 설계의 약한 부분을 외부가 빠르게 검토할 수 있게 됐습니다.&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;caludecodehack_label&quot;&gt;개발자 관점 : &lt;/span&gt;소스맵, 디버그 파일, 패키징 파일 경계가 얼마나 중요한지 다시 보여준 사례였습니다.&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;caludecodehack_label&quot;&gt;콘텐츠 가치 : &lt;/span&gt;AI 보안, DevSecOps, 공급망 보안이라는 검색 키워드를 동시에 잡을 수 있는 주제입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;caludecodehack_quote&quot;&gt;이번 사건의 진짜 무게는 AI가 아니라 배포 과정에서 터졌다는 데 있습니다.&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;caludecodehack_sec2&quot; class=&quot;caludecodehack_section&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 유출 경위와 주요 타임라인&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;공개된 분석들을 보면, Claude Code 배포 과정에서 디버깅용 source map 파일이 공개 패키지에 함께 포함되면서 내부 TypeScript 코드가 대규모로 복원 가능한 상태가 된 것이 사건의 출발점으로 정리됩니다.&lt;/p&gt;
&lt;div class=&quot;caludecodehack_warn&quot;&gt;&lt;b&gt;중요 포인트&lt;/b&gt;&lt;br /&gt;이번 이슈는 흔히 떠올리는 외부 침입형 해킹과는 성격이 다릅니다. 공개되면 안 되는 배포 아티팩트가 릴리즈 과정에서 노출된 사고에 더 가깝습니다.&lt;/div&gt;
&lt;div class=&quot;caludecodehack_timeline&quot;&gt;
&lt;div class=&quot;caludecodehack_timeline_item&quot;&gt;
&lt;div class=&quot;caludecodehack_time&quot;&gt;2026-03-31&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span class=&quot;caludecodehack_label&quot;&gt;초기 유출 정황 : &lt;/span&gt;업데이트 배포물에 source map 파일이 포함되며 내부 코드 복원이 가능해졌다는 분석이 확산되었습니다.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;caludecodehack_timeline_item&quot;&gt;
&lt;div class=&quot;caludecodehack_time&quot;&gt;2026-03-31&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span class=&quot;caludecodehack_label&quot;&gt;커뮤니티 반응 : &lt;/span&gt;개발자와 연구자들이 온라인에서 유출 정황과 구조 분석을 빠르게 공유하기 시작했습니다.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;caludecodehack_timeline_item&quot;&gt;
&lt;div class=&quot;caludecodehack_time&quot;&gt;2026-04-01&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span class=&quot;caludecodehack_label&quot;&gt;삭제 요청 확대 : &lt;/span&gt;복제 저장소에 대한 대량 삭제 요청과 함께 과잉 대응 논란도 이어졌습니다.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;caludecodehack_timeline_item&quot;&gt;
&lt;div class=&quot;caludecodehack_time&quot;&gt;2026-04-01 ~ 2026-04-02&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span class=&quot;caludecodehack_label&quot;&gt;취약점 재조명 : &lt;/span&gt;deny rule 우회, 설정 기반 신뢰 경계 문제 등 기존 보안 이슈가 다시 주목받기 시작했습니다.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;caludecodehack_timeline_item&quot;&gt;
&lt;div class=&quot;caludecodehack_time&quot;&gt;이후&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span class=&quot;caludecodehack_label&quot;&gt;2차 피해 우려 : &lt;/span&gt;유출 소스를 사칭한 저장소나 설치 파일이 악성코드 유포에 악용될 수 있다는 경고가 뒤따랐습니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;caludecodehack_sec3&quot; class=&quot;caludecodehack_section&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 유출된 것과 유출되지 않은 것&lt;/h2&gt;
&lt;div class=&quot;caludecodehack_grid&quot;&gt;
&lt;div class=&quot;caludecodehack_card_mini&quot;&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;유출된 것&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;에이전트 런타임 구조, 권한 처리 흐름, 도구 호출 방식, 샌드박스 설계, 훅 및 설정 파일 관련 구현 정보&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;caludecodehack_card_mini&quot;&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;유출되지 않은 것&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모델 가중치 전체, 고객 데이터 전체, 전형적인 대규모 계정 탈취형 정보 유출로 보기는 어려운 요소들&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 점이 중요한 이유는 단순한 코드 노출과 제품 내부 구조 노출이 완전히 다른 파장을 만들기 때문입니다. 전자는 저작권이나 경쟁 이슈에 그칠 수 있지만, 후자는 보안 경계와 우회 포인트를 함께 노출시킵니다.&lt;/p&gt;
&lt;ul class=&quot;caludecodehack_list&quot; style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span class=&quot;caludecodehack_label&quot;&gt;핵심 구분 : &lt;/span&gt;모델이 털렸다기보다 제품이 어떻게 움직이는지가 드러났다는 쪽에 가깝습니다.&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;caludecodehack_label&quot;&gt;실제 위험 : &lt;/span&gt;공격자는 권한 정책과 샌드박스의 빈틈을 더 효율적으로 찾을 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;caludecodehack_label&quot;&gt;산업적 함의 : &lt;/span&gt;AI 에이전트 도구의 경쟁 우위와 내부 설계 철학이 함께 노출될 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;section id=&quot;caludecodehack_sec4&quot; class=&quot;caludecodehack_section&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. Claude Code 내부 구조와 기술 포인트&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;공개된 분석 흐름을 종합하면 Claude Code는 단순한 채팅형 AI가 아니라, 터미널 환경에서 파일을 읽고, 수정하고, Bash 명령을 실행하고, 외부 도구와 연계하는 에이전트 런타임에 가깝습니다.&lt;/p&gt;
&lt;table class=&quot;caludecodehack_table&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;구성 요소&lt;/th&gt;
&lt;th&gt;설명&lt;/th&gt;
&lt;th&gt;개발자 관점 포인트&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;도구 실행 계층&lt;/td&gt;
&lt;td&gt;파일 수정, Bash, WebFetch, MCP 연동 등 실제 행동 수행&lt;/td&gt;
&lt;td&gt;LLM이 단순 답변이 아니라 작업을 실행하는 핵심 계층&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;권한 모델&lt;/td&gt;
&lt;td&gt;deny, ask, allow 규칙과 모드 조합으로 위험 행동 제어&lt;/td&gt;
&lt;td&gt;정책 설계가 흐트러지면 에이전트는 쉽게 위험 행동으로 확장됨&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;훅 확장 구조&lt;/td&gt;
&lt;td&gt;도구 실행 전후로 추가 정책과 검사를 연결 가능&lt;/td&gt;
&lt;td&gt;유연하지만 설정 파일이 공격 표면으로 바뀔 수 있음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;샌드박스 계층&lt;/td&gt;
&lt;td&gt;OS 수준 격리를 통해 파일과 네트워크 접근 제한&lt;/td&gt;
&lt;td&gt;권한 규칙이 실패해도 피해를 줄이는 마지막 방어선&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;div class=&quot;caludecodehack_note&quot;&gt;&lt;b&gt;개발자 해석&lt;/b&gt;&lt;br /&gt;에이전트형 AI 도구의 위험은 모델 성능보다 무엇을 할 수 있는지, 어떤 조건에서 허용되는지, 막히지 않으면 어디까지 실행되는지에 달려 있습니다.&lt;/div&gt;
&lt;div class=&quot;caludecodehack_quote&quot;&gt;에이전트형 AI 제품의 보안은 답변 품질이 아니라 경계 조건 설계로 결정됩니다.&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;caludecodehack_sec4a&quot; class=&quot;caludecodehack_section&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4-1. 유출된 소스에서 드러난 핵심 코드 패턴&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 예시는 유출 원문을 그대로 옮긴 것이 아니라, 공개 분석에서 공통적으로 확인된 구조를 바탕으로 재구성한 축약 예시입니다. 실제로 어떤 부분이 핵심이었는지 개발자가 빠르게 이해할 수 있도록 정리했습니다.&lt;/p&gt;
&lt;div class=&quot;caludecodehack_note&quot;&gt;&lt;b&gt;왜 이 섹션이 중요한가&lt;/b&gt;&lt;br /&gt;단순히 코드가 유출됐다고만 쓰면 글의 전문성이 약해집니다. 반대로 에이전트 루프, 도구 등록, 권한 판정, 보안 경계 같은 구조를 코드 패턴으로 보여주면 개발자 독자의 체류시간과 신뢰도가 더 높아집니다.&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;예시 1. 에이전트의 심장부 역할을 하는 반복 루프&lt;/h3&gt;
&lt;div class=&quot;caludecodehack_codewrap&quot;&gt;
&lt;div class=&quot;caludecodehack_codehead&quot;&gt;&lt;b&gt;Agent Loop Example&lt;/b&gt; &lt;span&gt;reconstructed for explanation&lt;/span&gt;&lt;/div&gt;
&lt;pre class=&quot;caludecodehack_codeblock cs&quot;&gt;&lt;code&gt;while (true) {
  const modelEvents = callModel(systemPrompt, messages, toolContext)

  for await (const event of modelEvents) {
    if (event.type === 'assistant_message') appendMessage(event)
    if (event.type === 'tool_call') queueTool(event)
  }

  if (queuedTools.length &amp;gt; 0) {
    const toolResults = await runTools(queuedTools)
    messages.push(...toolResults)
    continue
  }

  break
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;ul class=&quot;caludecodehack_list&quot; style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span class=&quot;caludecodehack_label&quot;&gt;설명 : &lt;/span&gt;사용자 요청 &amp;rarr; 모델 응답 &amp;rarr; 도구 호출 &amp;rarr; 결과 반영 &amp;rarr; 다음 턴 반복이라는 에이전트형 실행 구조를 보여줍니다.&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;caludecodehack_label&quot;&gt;핵심 포인트 : &lt;/span&gt;이 구조 때문에 Claude Code는 단순 채팅이 아니라 실제로 파일을 고치고 명령을 실행하는 작업형 도구가 됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;예시 2. 도구를 등록하고 기능 플래그로 제어하는 패턴&lt;/h3&gt;
&lt;div class=&quot;caludecodehack_codewrap&quot;&gt;
&lt;div class=&quot;caludecodehack_codehead&quot;&gt;&lt;b&gt;Tool Registration Example&lt;/b&gt; &lt;span&gt;feature flag pattern&lt;/span&gt;&lt;/div&gt;
&lt;pre class=&quot;caludecodehack_codeblock javascript&quot;&gt;&lt;code&gt;const WebBrowserTool =
  feature('WEB_BROWSER_TOOL')
    ? require('./tools/WebBrowserTool').WebBrowserTool
    : null

const tools = [
  ReadTool,
  EditTool,
  BashTool,
  ...(isToolSearchEnabledOptimistic() ? [ToolSearchTool] : [])
]&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;ul class=&quot;caludecodehack_list&quot; style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span class=&quot;caludecodehack_label&quot;&gt;설명 : &lt;/span&gt;도구 자체를 켜고 끄는 구조와, 필요 시에만 도구를 등록하거나 지연 로딩하는 패턴이 보입니다.&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;caludecodehack_label&quot;&gt;핵심 포인트 : &lt;/span&gt;이런 구조는 성능 최적화와 내부 기능 숨김에 유리하지만, source map 노출 시 어떤 도구가 실제 제품에 들어가는지도 그대로 드러날 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;예시 3. 권한 모델과 샌드박스가 분리된 구조&lt;/h3&gt;
&lt;div class=&quot;caludecodehack_codewrap&quot;&gt;
&lt;div class=&quot;caludecodehack_codehead&quot;&gt;&lt;b&gt;Permission Decision Example&lt;/b&gt; &lt;span&gt;policy + sandbox separation&lt;/span&gt;&lt;/div&gt;
&lt;pre class=&quot;caludecodehack_codeblock reasonml&quot;&gt;&lt;code&gt;function decidePermission(toolCall, rules) {
  if (matchesDeny(toolCall, rules.deny)) return 'deny'
  if (matchesAllow(toolCall, rules.allow)) return 'allow'
  return 'ask'
}

const result = decidePermission(bashCall, permissionRules)

if (result === 'allow') {
  return runInSandbox(bashCall, sandboxPolicy)
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;ul class=&quot;caludecodehack_list&quot; style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span class=&quot;caludecodehack_label&quot;&gt;설명 : &lt;/span&gt;권한 판정과 실제 OS 수준 샌드박스 실행이 다른 층으로 나뉘는 전형적인 구조입니다.&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;caludecodehack_label&quot;&gt;핵심 포인트 : &lt;/span&gt;정책이 한번 틀어져도 샌드박스가 막아줄 수 있어야 하고, 반대로 샌드박스가 없으면 권한 규칙 하나가 곧 전체 위험이 됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;예시 4. 이번 논란과 직접 연결된 deny rule 우회 구조&lt;/h3&gt;
&lt;div class=&quot;caludecodehack_codewrap&quot;&gt;
&lt;div class=&quot;caludecodehack_codehead&quot;&gt;&lt;b&gt;Bash Guard Example&lt;/b&gt; &lt;span&gt;threshold-based security path&lt;/span&gt;&lt;/div&gt;
&lt;pre class=&quot;caludecodehack_codeblock actionscript&quot;&gt;&lt;code&gt;const MAX_SUBCOMMANDS_FOR_SECURITY_CHECK = 50

function evaluateBash(command, rules) {
  const subcommands = splitCompoundCommand(command)

  if (subcommands.length &amp;gt; MAX_SUBCOMMANDS_FOR_SECURITY_CHECK) {
    return { decision: 'ask', reason: 'too_many_subcommands' }
  }

  for (const item of subcommands) {
    if (matchesDeny(item, rules.deny)) {
      return { decision: 'deny' }
    }
  }

  return { decision: 'allow' }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;ul class=&quot;caludecodehack_list&quot; style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span class=&quot;caludecodehack_label&quot;&gt;설명 : &lt;/span&gt;길이가 긴 복합 명령에서 보안 검사를 단순화하면 deny 규칙이 기대만큼 강하게 작동하지 않을 수 있다는 문제를 대준 예시입니다.&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;caludecodehack_label&quot;&gt;핵심 포인트 : &lt;/span&gt;AI 에이전트는 사람이 직접 타이핑하지 않을 정도로 긴 명령 체인도 쉽게 생성하므로, 이런 임계치 기반 예외 처리는 위험해질 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;caludecodehack_warn&quot;&gt;&lt;b&gt;주의&lt;/b&gt;&lt;br /&gt;위 코드는 유출 원문을 그대로 복제한 것이 아니라, 공개적으로 알려진 구조를 이해하기 쉽게 블로그용으로 재구성한 축약 예시입니다.&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;caludecodehack_sec5&quot; class=&quot;caludecodehack_section&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. 취약점, 보안 결함, 실제 위험성&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 사건 이후 특히 많이 언급된 부분은 deny rule 우회 가능성, 파서 불일치, 그리고 설정 기반 신뢰 경계 문제였습니다. 공개 분석을 보면 단순 버그 한 개가 아니라, 에이전트형 AI 도구에서 성능 최적화와 보안 정책이 충돌할 때 어떤 식으로 위험이 생기는지가 그대로 드러났습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5-1. deny rule 우회 문제&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;공개 분석에 따르면, 서브커맨드가 지나치게 길어질 경우 보안 검사를 단순화하는 경로가 존재할 수 있고, 이때 deny 규칙이 기대만큼 강하게 작동하지 않는 구조가 논란이 되었습니다.&lt;/p&gt;
&lt;ul class=&quot;caludecodehack_list&quot; style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span class=&quot;caludecodehack_label&quot;&gt;문제의 본질 : &lt;/span&gt;성능 최적화를 위해 만든 제한이 보안 정책을 밀어낸 구조적 문제&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;caludecodehack_label&quot;&gt;왜 위험한가 : &lt;/span&gt;AI 에이전트는 사람보다 훨씬 긴 명령 체인을 자연스럽게 생성할 수 있음&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;caludecodehack_label&quot;&gt;실무 교훈 : &lt;/span&gt;분석이 어려운 경우 기본 동작은 ask보다 deny가 더 안전함&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5-2. 파서 불일치 문제&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보안 검증기가 해석한 명령과 실제 셸이 해석한 명령이 다르면, 검증은 존재해도 무력화될 수 있습니다. 이것은 웹 보안에서 입력 검증 로직과 실제 실행 로직이 다른 경우와 매우 유사합니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5-3. 신뢰 경계와 설정 파일 문제&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;repo 내부 설정이나 로컬 설정이 trust prompt 이전 동작에 영향을 줄 수 있다면, 사용자는 신뢰 여부를 결정하기도 전에 민감한 동작에 노출될 수 있습니다. 이 부분은 AI 에이전트 보안에서 계속 반복적으로 등장하는 핵심 리스크입니다.&lt;/p&gt;
&lt;div class=&quot;caludecodehack_warn&quot;&gt;&lt;b&gt;정리&lt;/b&gt;&lt;br /&gt;설정 파일, 권한 룰, 샌드박스, 승인 흐름이 서로 다른 기준으로 움직이면 반드시 틈이 생깁니다.&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;caludecodehack_sec6&quot; class=&quot;caludecodehack_section&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;6. 개발자와 조직이 지금 점검해야 할 대응책&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;개발사 입장에서 가장 중요한 것&lt;/h3&gt;
&lt;ul class=&quot;caludecodehack_list&quot; style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span class=&quot;caludecodehack_label&quot;&gt;배포 파일 경계 관리 : &lt;/span&gt;deny 방식보다 allowlist 방식으로 패키지 포함 파일을 강하게 통제해야 합니다.&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;caludecodehack_label&quot;&gt;아티팩트 검사 자동화 : &lt;/span&gt;배포 직전 source map, 디버그 파일, 대용량 파일 포함 여부를 CI 단계에서 자동 차단해야 합니다.&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;caludecodehack_label&quot;&gt;크기 이상 탐지 : &lt;/span&gt;평소보다 패키지 용량이 급증하면 배포를 막는 장치가 필요합니다.&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;caludecodehack_label&quot;&gt;수동 배포 최소화 : &lt;/span&gt;사람 손을 타는 릴리즈 프로세스는 바쁜 상황에서 반드시 누락이 생깁니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;일반 개발팀이 당장 할 수 있는 것&lt;/h3&gt;
&lt;ul class=&quot;caludecodehack_list&quot; style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span class=&quot;caludecodehack_label&quot;&gt;의심 저장소 실행 금지 : &lt;/span&gt;유출 소스를 사칭하는 저장소, ZIP, 실행 파일은 절대 바로 실행하지 말아야 합니다.&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;caludecodehack_label&quot;&gt;격리 환경 우선 : &lt;/span&gt;신뢰되지 않은 repo에서는 devcontainer, VM, 샌드박스 환경을 우선 사용해야 합니다.&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;caludecodehack_label&quot;&gt;방어 심층화 : &lt;/span&gt;deny rule만 믿지 말고 샌드박스와 훅, 네트워크 제한을 함께 걸어야 합니다.&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;caludecodehack_label&quot;&gt;보안 버전 유지 : &lt;/span&gt;관련 보안 권고가 나온 버전은 가능한 빨리 최신 버전으로 끌어올려야 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;caludecodehack_ok&quot;&gt;&lt;b&gt;실무 한 줄 조언&lt;/b&gt;&lt;br /&gt;AI 에이전트 도구는 무엇을 할 수 있는가보다 무엇을 절대 못 하게 막을 것인가를 먼저 정해야 안전합니다.&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;caludecodehack_sec7&quot; class=&quot;caludecodehack_section&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;7. 마무리, 이번 사건이 남긴 진짜 교훈&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Claude Code 소스 유출 사건은 AI 시대의 보안 문제가 더 이상 모델 자체에만 머물지 않는다는 점을 강하게 보여줬습니다. 실제로 더 위험한 것은 배포 자동화, 패키징 위생, 권한 정책, 샌드박스, 설정 파일 신뢰 경계처럼 제품 외곽을 이루는 운영 구조일 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개인적으로 이번 사건에서 가장 크게 느껴지는 지점은 이것입니다. 좋은 AI 제품은 단지 똑똑한 모델로 만들어지는 것이 아니라, 실수할 수밖에 없는 배포 과정을 얼마나 견고하게 감싸고 있느냐로 완성됩니다.&lt;/p&gt;
&lt;div class=&quot;caludecodehack_quote&quot;&gt;AI 제품을 무너뜨리는 가장 현실적인 원인은, 종종 AI가 아니라 사람이 만든 배포 절차입니다.&lt;/div&gt;
&lt;div class=&quot;caludecodehack_tags&quot;&gt;&lt;span&gt;#ClaudeCode&lt;/span&gt; &lt;span&gt;#소스유출&lt;/span&gt; &lt;span&gt;#AI보안&lt;/span&gt; &lt;span&gt;#DevSecOps&lt;/span&gt; &lt;span&gt;#공급망보안&lt;/span&gt; &lt;span&gt;#소스맵&lt;/span&gt; &lt;span&gt;#에이전트보안&lt;/span&gt; &lt;span&gt;#샌드박스&lt;/span&gt; &lt;span&gt;#개발자분석&lt;/span&gt; &lt;span&gt;#보안사고&lt;/span&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;caludecodehack_sec8&quot; class=&quot;caludecodehack_section&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;8. 자주 묻는 질문 Q&amp;amp;A&lt;/h2&gt;
&lt;div class=&quot;caludecodehack_faq&quot;&gt;&lt;details open=&quot;&quot;&gt;
&lt;summary&gt;Q. 이번 사건은 모델 자체 유출이라고 봐야 하나요?&lt;/summary&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;A. 공개된 흐름 기준으로는 모델 가중치 전체 유출보다는 Claude Code 운영 구조와 구현 디테일이 외부 분석 대상이 된 사건으로 보는 편이 더 정확합니다.&lt;/p&gt;
&lt;/details&gt;&lt;details&gt;
&lt;summary&gt;Q. 일반 개발자에게도 실제 위험이 있나요?&lt;/summary&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;A. 있습니다. 유출 소스를 사칭한 저장소, 악성 설치 파일, 취약한 설정을 가진 프로젝트를 통해 2차 피해가 이어질 수 있기 때문입니다.&lt;/p&gt;
&lt;/details&gt;&lt;details&gt;
&lt;summary&gt;Q. 가장 현실적인 대응은 무엇인가요?&lt;/summary&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;A. 신뢰되지 않은 저장소는 격리 환경에서만 다루고, AI 에이전트 도구의 권한 정책과 샌드박스 규칙을 기본 차단형으로 운영하는 것이 가장 현실적입니다.&lt;/p&gt;
&lt;/details&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;caludecodehack_sec9&quot; class=&quot;caludecodehack_section&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;9. 참고 자료&lt;/h2&gt;
&lt;ul class=&quot;caludecodehack_refs&quot; style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://www.theverge.com/ai-artificial-intelligence/904776/anthropic-claude-source-code-leak&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;The Verge - Claude Code leak 관련 보도&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.anthropic.com/engineering/claude-code-auto-mode&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Anthropic Engineering - Claude Code Auto Mode&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://code.claude.com/docs/en/permissions&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Claude Code Docs - Permissions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://code.claude.com/docs/en/sandboxing&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Claude Code Docs - Sandboxing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/advisories/GHSA-jh7p-qr78-84p7&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;GitHub Security Advisory - GHSA-jh7p-qr78-84p7&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://nvd.nist.gov/vuln/detail/CVE-2026-21852&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;NVD - CVE-2026-21852&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://adversa.ai/claude-code-security-bypass-deny-rules-disabled/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Adversa - deny rule bypass 분석&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;/div&gt;</description>
      <category>DEVELOPMENT</category>
      <category>AnthropicAI보안</category>
      <category>claudecode</category>
      <category>DevSecOps</category>
      <category>SourceMAP</category>
      <category>개발자분석</category>
      <category>공급망보안</category>
      <category>샌드박스</category>
      <category>소스유출</category>
      <category>에이전트보안</category>
      <category>클로드코드소스유출</category>
      <author>간지뽕빨리턴님</author>
      <guid isPermaLink="true">https://odinbox.tistory.com/579</guid>
      <comments>https://odinbox.tistory.com/579#entry579comment</comments>
      <pubDate>Sat, 4 Apr 2026 17:07:31 +0900</pubDate>
    </item>
    <item>
      <title>99% 어셈블리어로 만든 전설, 롤러코스터 타이쿤의 최적화 비밀</title>
      <link>https://odinbox.tistory.com/578</link>
      <description>&lt;div&gt;
&lt;style&gt;
  .assemblylang_wrap {
    --assemblylang_bg: #ffffff;
    --assemblylang_text: #1f2937;
    --assemblylang_muted: #6b7280;
    --assemblylang_line: #e5e7eb;
    --assemblylang_soft: #f8fafc;
    --assemblylang_soft2: #f3f4f6;
    --assemblylang_point: #0f172a;
    --assemblylang_point2: #2563eb;
    --assemblylang_point3: #111827;
    --assemblylang_quote: #eff6ff;
    --assemblylang_warn: #fff7ed;
    --assemblylang_green: #ecfdf5;
    --assemblylang_green_line: #a7f3d0;
    --assemblylang_code_bg: #0b1220;
    --assemblylang_code_head: #111827;
    --assemblylang_code_text: #e5eefc;
    --assemblylang_radius: 18px;
    --assemblylang_shadow: 0 14px 32px rgba(15, 23, 42, 0.08);
    max-width: 860px;
    margin: 0 auto;
    color: var(--assemblylang_text);
    font-family: -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, &quot;Pretendard&quot;, &quot;Apple SD Gothic Neo&quot;, &quot;Noto Sans KR&quot;, sans-serif;
    line-height: 1.85;
    word-break: keep-all;
    overflow-wrap: break-word;
  }

  .assemblylang_wrap * {
    box-sizing: border-box;
  }

  .assemblylang_wrap a {
    color: var(--assemblylang_point2);
    text-decoration: none;
  }

  .assemblylang_wrap img {
    max-width: 100%;
    height: auto;
    border-radius: 14px;
  }

  .assemblylang_kicker {
    display: inline-block;
    margin: 8px 0 14px;
    padding: 6px 12px;
    border-radius: 999px;
    background: var(--assemblylang_soft2);
    color: var(--assemblylang_point3);
    font-size: 13px;
    font-weight: 700;
    letter-spacing: 0.02em;
  }

  .assemblylang_title {
    margin: 0 0 14px;
    font-size: 36px;
    line-height: 1.35;
    color: var(--assemblylang_point);
    font-weight: 800;
    letter-spacing: -0.03em;
  }

  .assemblylang_subtitle {
    margin: 0 0 18px;
    font-size: 18px;
    line-height: 1.72;
    color: var(--assemblylang_muted);
  }

  .assemblylang_meta {
    margin: 0 0 26px;
    padding-bottom: 18px;
    border-bottom: 1px solid var(--assemblylang_line);
    color: var(--assemblylang_muted);
    font-size: 14px;
  }

  .assemblylang_card,
  .assemblylang_leadbox,
  .assemblylang_toc,
  .assemblylang_infobox,
  .assemblylang_quotebox,
  .assemblylang_sourcebox,
  .assemblylang_tagbox,
  .assemblylang_warnbox,
  .assemblylang_greenbox {
    margin: 24px 0;
    padding: 24px;
    border: 1px solid var(--assemblylang_line);
    border-radius: var(--assemblylang_radius);
    background: var(--assemblylang_bg);
    box-shadow: var(--assemblylang_shadow);
  }

  .assemblylang_leadbox {
    background: linear-gradient(180deg, #ffffff 0%, #f8fbff 100%);
  }

  .assemblylang_infobox {
    background: var(--assemblylang_soft);
  }

  .assemblylang_quotebox {
    background: var(--assemblylang_quote);
    border-color: #bfdbfe;
  }

  .assemblylang_warnbox {
    background: var(--assemblylang_warn);
    border-color: #fed7aa;
  }

  .assemblylang_greenbox {
    background: var(--assemblylang_green);
    border-color: var(--assemblylang_green_line);
  }

  .assemblylang_box_title {
    margin: 0 0 14px;
    font-size: 18px;
    font-weight: 800;
    color: var(--assemblylang_point);
  }

  .assemblylang_summary_list,
  .assemblylang_plain_list {
    margin: 0;
    padding-left: 20px;
  }

  .assemblylang_summary_list li,
  .assemblylang_plain_list li {
    margin: 10px 0;
  }

  .assemblylang_toc {
    background: var(--assemblylang_soft);
  }

  .assemblylang_toc_title {
    margin: 0 0 12px;
    font-size: 17px;
    font-weight: 800;
    color: var(--assemblylang_point);
  }

  .assemblylang_toc ol {
    margin: 0;
    padding-left: 20px;
  }

  .assemblylang_toc li {
    margin: 8px 0;
  }

  .assemblylang_section {
    margin: 48px 0 0;
  }

  .assemblylang_section h2 {
    margin: 0 0 16px;
    font-size: 30px;
    line-height: 1.42;
    color: var(--assemblylang_point);
    font-weight: 800;
    letter-spacing: -0.02em;
  }

  .assemblylang_section h3 {
    margin: 28px 0 12px;
    font-size: 22px;
    line-height: 1.5;
    color: var(--assemblylang_point3);
    font-weight: 800;
    letter-spacing: -0.02em;
  }

  .assemblylang_section p {
    margin: 0 0 16px;
    font-size: 17px;
  }

  .assemblylang_emphasis {
    color: var(--assemblylang_point);
    font-weight: 800;
  }

  .assemblylang_compare {
    width: 100%;
    border-collapse: collapse;
    margin: 18px 0 8px;
    overflow: hidden;
    border-radius: 14px;
  }

  .assemblylang_compare th,
  .assemblylang_compare td {
    border: 1px solid var(--assemblylang_line);
    padding: 14px 12px;
    vertical-align: top;
    text-align: left;
    font-size: 15px;
  }

  .assemblylang_compare thead th {
    background: #f8fafc;
    color: var(--assemblylang_point);
    font-weight: 800;
  }

  .assemblylang_code_wrap {
    margin: 18px 0;
    border-radius: 16px;
    overflow: hidden;
    background: var(--assemblylang_code_bg) !important;
    border: 1px solid #1e293b;
    box-shadow: 0 12px 24px rgba(2, 6, 23, 0.18);
  }

  .assemblylang_code_head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 10px 14px;
    background: var(--assemblylang_code_head) !important;
    color: #e5e7eb !important;
    font-size: 13px;
    font-weight: 700;
    border-bottom: 1px solid #1f2937;
  }

  .assemblylang_code_wrap pre {
    margin: 0 !important;
    padding: 18px !important;
    overflow-x: auto;
    overflow-y: hidden;
    background: var(--assemblylang_code_bg) !important;
    color: var(--assemblylang_code_text) !important;
    font-size: 14px;
    line-height: 1.72;
    font-family: Consolas, &quot;Fira Code&quot;, &quot;D2Coding&quot;, monospace !important;
    white-space: pre !important;
    word-break: normal !important;
    overflow-wrap: normal !important;
    tab-size: 4;
    -webkit-text-fill-color: var(--assemblylang_code_text) !important;
  }

  .assemblylang_code_wrap code {
    display: block;
    background: var(--assemblylang_code_bg) !important;
    color: var(--assemblylang_code_text) !important;
    font-size: 14px;
    line-height: 1.72;
    font-family: Consolas, &quot;Fira Code&quot;, &quot;D2Coding&quot;, monospace !important;
    white-space: pre !important;
    word-break: normal !important;
    overflow-wrap: normal !important;
    -webkit-text-fill-color: var(--assemblylang_code_text) !important;
  }

  .assemblylang_code_wrap pre *,
  .assemblylang_code_wrap code * {
    color: inherit !important;
    -webkit-text-fill-color: inherit !important;
  }

  .assemblylang_code_wrap .hljs,
  .assemblylang_code_wrap .hljs-subst {
    background: var(--assemblylang_code_bg) !important;
    color: var(--assemblylang_code_text) !important;
  }

  .assemblylang_code_wrap .hljs-comment,
  .assemblylang_code_wrap .hljs-quote {
    color: #94a3b8 !important;
  }

  .assemblylang_code_wrap .hljs-keyword,
  .assemblylang_code_wrap .hljs-selector-tag,
  .assemblylang_code_wrap .hljs-built_in,
  .assemblylang_code_wrap .hljs-name,
  .assemblylang_code_wrap .hljs-tag {
    color: #93c5fd !important;
  }

  .assemblylang_code_wrap .hljs-string,
  .assemblylang_code_wrap .hljs-attr,
  .assemblylang_code_wrap .hljs-doctag,
  .assemblylang_code_wrap .hljs-template-tag,
  .assemblylang_code_wrap .hljs-template-variable {
    color: #86efac !important;
  }

  .assemblylang_code_wrap .hljs-number,
  .assemblylang_code_wrap .hljs-literal,
  .assemblylang_code_wrap .hljs-symbol,
  .assemblylang_code_wrap .hljs-bullet {
    color: #fbbf24 !important;
  }

  .assemblylang_code_wrap .hljs-title,
  .assemblylang_code_wrap .hljs-section,
  .assemblylang_code_wrap .hljs-function {
    color: #c4b5fd !important;
  }

  .assemblylang_code_wrap .hljs-variable,
  .assemblylang_code_wrap .hljs-regexp,
  .assemblylang_code_wrap .hljs-link {
    color: #fca5a5 !important;
  }

  .assemblylang_keyword {
    display: inline-block;
    margin: 6px 8px 0 0;
    padding: 7px 12px;
    border-radius: 999px;
    background: var(--assemblylang_soft2);
    color: var(--assemblylang_point3);
    font-size: 13px;
    font-weight: 700;
  }

  .assemblylang_conclusion {
    margin-top: 44px;
    padding: 28px;
    border-radius: 22px;
    background: linear-gradient(135deg, #111827 0%, #1e293b 100%);
    color: #ffffff;
  }

  .assemblylang_conclusion h2 {
    margin: 0 0 14px;
    font-size: 28px;
    line-height: 1.4;
    color: #ffffff;
  }

  .assemblylang_conclusion p {
    margin: 0 0 12px;
    font-size: 17px;
    color: rgba(255,255,255,0.92);
  }

  .assemblylang_source_list {
    margin: 12px 0 0;
    padding-left: 20px;
  }

  .assemblylang_source_list li {
    margin: 8px 0;
    font-size: 15px;
    color: var(--assemblylang_muted);
  }

  @media (max-width: 768px) {
    .assemblylang_title {
      font-size: 28px;
    }

    .assemblylang_subtitle {
      font-size: 16px;
    }

    .assemblylang_section h2 {
      font-size: 25px;
    }

    .assemblylang_section h3 {
      font-size: 20px;
    }

    .assemblylang_card,
    .assemblylang_leadbox,
    .assemblylang_toc,
    .assemblylang_infobox,
    .assemblylang_quotebox,
    .assemblylang_sourcebox,
    .assemblylang_tagbox,
    .assemblylang_warnbox,
    .assemblylang_greenbox,
    .assemblylang_conclusion {
      padding: 18px;
      border-radius: 16px;
    }

    .assemblylang_compare th,
    .assemblylang_compare td {
      font-size: 14px;
      padding: 12px 10px;
    }

    .assemblylang_code_head {
      flex-direction: column;
      align-items: flex-start;
    }
  }
&lt;/style&gt;
&lt;/div&gt;
&lt;!--
assemblylang_seo_title: 전설이 된 코드, 롤러코스터 타이쿤과 어셈블리어가 만든 최적화의 기적
assemblylang_seo_description: 롤러코스터 타이쿤은 왜 지금도 최적화의 전설로 불릴까. 크리스 소이어의 1인 개발, 99% x86 어셈블리, 데이터 레이아웃, 비트시프트, OpenRCT2, 예시 어셈블리 코드까지 한 번에 정리합니다.
assemblylang_seo_keywords: 롤러코스터타이쿤, 어셈블리어, 크리스소이어, x86 assembly, game optimization, OpenRCT2, 데이터 레이아웃, 비트시프트, 1인 개발, 소프트웨어 공학
--&gt;
&lt;div class=&quot;assemblylang_wrap&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;글 상단 부분 대표 이미지.png&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nWgYI/dJMcaaxYNqY/87gsL0brY4hh873vWq1N61/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nWgYI/dJMcaaxYNqY/87gsL0brY4hh873vWq1N61/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nWgYI/dJMcaaxYNqY/87gsL0brY4hh873vWq1N61/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnWgYI%2FdJMcaaxYNqY%2F87gsL0brY4hh873vWq1N61%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;400&quot; data-filename=&quot;글 상단 부분 대표 이미지.png&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;div class=&quot;assemblylang_kicker&quot;&gt;게임개발 &amp;middot; 어셈블리어 &amp;middot; 최적화 &amp;middot; 소프트웨어공학&lt;/div&gt;
&lt;h1 class=&quot;assemblylang_title&quot;&gt;전설이 된 코드&lt;/h1&gt;
&lt;h1 class=&quot;assemblylang_title&quot;&gt;롤러코스터 타이쿤과 어셈블리어가 만든 최적화의 기적&lt;/h1&gt;
&lt;p class=&quot;assemblylang_subtitle&quot; data-ke-size=&quot;size16&quot;&gt;1999년의 PC에서 수천 명의 손님과 수십 개의 놀이기구를 동시에 굴린 게임. 그리고 그 중심에는 지금 봐도 믿기 어려운 선택, 거의 전부를 저수준 코드로 밀어붙인 개발 방식이 있었습니다. &lt;b&gt;롤러코스터 타이쿤&lt;/b&gt;은 단순한 명작 게임이 아니라, 지금도 개발자들이 최적화와 시스템 설계를 이야기할 때 빠지지 않는 사례입니다.&lt;/p&gt;
&lt;p class=&quot;assemblylang_meta&quot; data-ke-size=&quot;size16&quot;&gt;롤러코스터 타이쿤 &amp;middot; 크리스 소이어 &amp;middot; 어셈블리어 &amp;middot; x86 &amp;middot; 게임 최적화 &amp;middot; OpenRCT2 &amp;middot; 데이터 레이아웃 &amp;middot; 비트시프트 &amp;middot; 1인 개발&lt;/p&gt;
&lt;div class=&quot;assemblylang_leadbox&quot;&gt;
&lt;p class=&quot;assemblylang_box_title&quot; data-ke-size=&quot;size16&quot;&gt;핵심만 먼저 보면&lt;/p&gt;
&lt;ul class=&quot;assemblylang_summary_list&quot; style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;롤러코스터 타이쿤은 단순한 추억의 게임이 아니라 &lt;b&gt;최적화 설계의 대표 사례&lt;/b&gt;로 자주 언급됩니다.&lt;/li&gt;
&lt;li&gt;크리스 소이어는 당시 하드웨어 한계 속에서 원하는 시뮬레이션을 구현하기 위해 &lt;b&gt;매우 낮은 수준의 제어&lt;/b&gt;를 선택했습니다.&lt;/li&gt;
&lt;li&gt;이 게임의 강점은 &amp;ldquo;어셈블리어를 썼다&amp;rdquo;에서 끝나지 않습니다. &lt;b&gt;데이터 구조, 수식, 길찾기, 군중 처리까지 전부 성능 중심으로 설계&lt;/b&gt;됐다는 점이 핵심입니다.&lt;/li&gt;
&lt;li&gt;반대로 이런 방식은 훗날 이식성과 유지보수성에서 큰 대가를 남겼고, 그래서 OpenRCT2 같은 재구현 프로젝트가 더욱 의미를 가지게 됐습니다.&lt;/li&gt;
&lt;li&gt;결국 이 사례가 남기는 질문은 하나입니다. &lt;b&gt;우리는 추상화 아래에서 실제 비용 구조를 얼마나 이해하고 있는가&lt;/b&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;assemblylang_toc&quot;&gt;
&lt;p class=&quot;assemblylang_toc_title&quot; data-ke-size=&quot;size16&quot;&gt;목차&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;a href=&quot;#assemblylang_section1&quot;&gt;왜 롤러코스터 타이쿤은 아직도 전설인가&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#assemblylang_section2&quot;&gt;어셈블리어란 무엇인가&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#assemblylang_section3&quot;&gt;1990년대 하드웨어가 만든 선택&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#assemblylang_section4&quot;&gt;크리스 소이어의 1인 개발 방식&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#assemblylang_section5&quot;&gt;최적화의 황금 표준으로 불리는 이유&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#assemblylang_section6&quot;&gt;예시 어셈블리 소스가 왜 도움이 되는가&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#assemblylang_section7&quot;&gt;성능을 위해 게임 디자인까지 바꾼 사례&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#assemblylang_section8&quot;&gt;어셈블리어의 대가와 OpenRCT2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#assemblylang_section9&quot;&gt;현대 개발자가 얻을 수 있는 교훈&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div id=&quot;assemblylang_section1&quot; class=&quot;assemblylang_section&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;왜 롤러코스터 타이쿤은 아직도 전설인가&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;롤러코스터 타이쿤은 단순히 재미있는 테마파크 경영 게임이 아닙니다. 이 게임은 거대한 공원을 보여주면서도 손님들의 이동, 기구의 상태, 수익과 동선, 만족도와 혼잡도 같은 여러 시스템을 동시에 굴립니다. 그런데 놀라운 점은 이 복잡한 구조가 1999년의 PC 환경에서도 상당히 부드럽게 돌아갔다는 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금처럼 강력한 CPU와 대용량 메모리, 정교한 컴파일러가 보편적이지 않던 시절에 이 정도 규모의 시뮬레이션을 구현했다는 것만으로도 이미 대단하지만, 이 작품이 더 특별한 이유는 그 구현 방식에 있습니다. 롤러코스터 타이쿤은 &amp;ldquo;고수준 언어와 대규모 팀&amp;rdquo;이라는 현대적 방식과는 다른 길을 택했고, 그 결과 지금도 개발자 사이에서 &lt;span class=&quot;assemblylang_emphasis&quot;&gt;최적화의 전설&lt;/span&gt;로 불립니다.&lt;/p&gt;
&lt;div class=&quot;assemblylang_quotebox&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;롤러코스터 타이쿤의 진짜 무게감은 단순히 &amp;ldquo;혼자 만들었다&amp;rdquo;가 아닙니다. &lt;b&gt;제약이 심한 시대에, 성능과 설계를 같은 손으로 끝까지 밀어붙였다&lt;/b&gt;는 데 있습니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;assemblylang_section2&quot; class=&quot;assemblylang_section&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;어셈블리어란 무엇인가&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CPU는 본질적으로 0과 1로 이뤄진 기계어만 이해합니다. 어셈블리어는 그 기계어를 사람이 그나마 읽을 수 있도록 바꿔놓은 가장 낮은 단계의 프로그래밍 언어입니다. 우리가 흔히 사용하는 C, C++, Java, C#, Python 같은 언어가 &amp;ldquo;무엇을 할지&amp;rdquo;를 상대적으로 높은 수준에서 표현한다면, 어셈블리어는 &lt;b&gt;어느 레지스터에 무엇을 넣고, 어떤 메모리를 읽고, 어떤 순서로 연산할지&lt;/b&gt;까지 매우 세밀하게 지시합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쉽게 비유하면 고수준 언어는 이미 만들어진 블록을 조립하는 방식에 가깝고, 어셈블리어는 그 블록의 모양과 내부 구조까지 직접 깎는 일에 가깝습니다. 그래서 성능은 강력하지만, 생산성과 유지보수성은 매우 낮습니다.&lt;/p&gt;
&lt;div class=&quot;assemblylang_infobox&quot;&gt;
&lt;p class=&quot;assemblylang_box_title&quot; data-ke-size=&quot;size16&quot;&gt;어셈블리어를 이해할 때 핵심&lt;/p&gt;
&lt;ul class=&quot;assemblylang_plain_list&quot; style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;추상화가 적기 때문에 시스템 비용이 그대로 보입니다.&lt;/li&gt;
&lt;li&gt;메모리 사용량과 연산 단위에 민감한 최적화가 가능합니다.&lt;/li&gt;
&lt;li&gt;반면 코드 가독성, 재사용성, 협업 효율은 크게 떨어집니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;assemblylang_section3&quot; class=&quot;assemblylang_section&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1990년대 하드웨어가 만든 선택&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금 기준으로는 &amp;ldquo;왜 굳이 그렇게까지?&amp;rdquo;라는 질문이 자연스럽습니다. 하지만 1990년대 후반 PC 환경은 지금과 완전히 달랐습니다. CPU 성능은 훨씬 낮았고, 메모리도 넉넉하지 않았으며, 오늘날처럼 컴파일러가 광범위한 최적화를 대신해 주는 시대도 아니었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 환경에서 수천 명의 손님, 복잡한 기구 상태, 대규모 공원 화면을 동시에 유지하려면 단순히 코드를 잘 짜는 수준을 넘어 &lt;b&gt;무엇을 어떤 형태로 저장하고 계산할지&lt;/b&gt;까지 매우 집요하게 설계해야 했습니다. 당시 크리스 소이어에게 저수준 제어는 취향의 문제가 아니라, 원하는 수준의 결과를 내기 위한 현실적인 선택에 가까웠습니다.&lt;/p&gt;
&lt;table class=&quot;assemblylang_compare&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;구분&lt;/th&gt;
&lt;th&gt;고수준 언어 중심 개발&lt;/th&gt;
&lt;th&gt;저수준 어셈블리 중심 개발&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;개발 속도&lt;/td&gt;
&lt;td&gt;상대적으로 빠름&lt;/td&gt;
&lt;td&gt;매우 느림&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;성능 통제력&lt;/td&gt;
&lt;td&gt;컴파일러 의존&lt;/td&gt;
&lt;td&gt;개발자가 직접 제어&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;메모리 제어&lt;/td&gt;
&lt;td&gt;추상화 계층 존재&lt;/td&gt;
&lt;td&gt;바이트 단위 설계 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;이식성&lt;/td&gt;
&lt;td&gt;상대적으로 유리&lt;/td&gt;
&lt;td&gt;특정 아키텍처에 종속&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;유지보수성&lt;/td&gt;
&lt;td&gt;상대적으로 쉬움&lt;/td&gt;
&lt;td&gt;매우 어려움&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div id=&quot;assemblylang_section4&quot; class=&quot;assemblylang_section&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;크리스 소이어의 1인 개발 방식&lt;/h2&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;737&quot; data-origin-height=&quot;416&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dirYxB/dJMcahw6FHC/pKGFdCwiQwN48lFFcVZB71/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dirYxB/dJMcahw6FHC/pKGFdCwiQwN48lFFcVZB71/img.webp&quot; data-alt=&quot;크리스소이&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dirYxB/dJMcahw6FHC/pKGFdCwiQwN48lFFcVZB71/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdirYxB%2FdJMcahw6FHC%2FpKGFdCwiQwN48lFFcVZB71%2Fimg.webp&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;737&quot; height=&quot;416&quot; data-origin-width=&quot;737&quot; data-origin-height=&quot;416&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;크리스소이&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;롤러코스터 타이쿤의 가치가 더 크게 느껴지는 이유는, 이 게임이 단지 특정 언어를 썼기 때문만은 아니라는 점입니다. 크리스 소이어는 게임 디자이너이면서 동시에 핵심 프로그래머 역할을 함께 수행했고, 그래서 &amp;ldquo;게임이 어떻게 느껴져야 하는가&amp;rdquo;와 &amp;ldquo;그걸 어떤 비용으로 구현할 것인가&amp;rdquo;를 같은 머리에서 통합해 판단할 수 있었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;710&quot; data-origin-height=&quot;399&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ccQhq5/dJMcaaSicu1/zBzYMkMpec7vO6v5KTS6c1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ccQhq5/dJMcaaSicu1/zBzYMkMpec7vO6v5KTS6c1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ccQhq5/dJMcaaSicu1/zBzYMkMpec7vO6v5KTS6c1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FccQhq5%2FdJMcaaSicu1%2FzBzYMkMpec7vO6v5KTS6c1%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;335&quot; height=&quot;188&quot; data-origin-width=&quot;710&quot; data-origin-height=&quot;399&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;현대의 대규모 개발이 역할 분업과 문서 중심으로 흘러간다면, 그의 방식은 작동하는 구조를 먼저 만들고 그 위에 쌓아 올리는 바텀업 접근에 가까웠습니다. 이 방식은 위험하지만, 성능 최적화와 시스템 일관성을 동시에 잡는 데는 매우 강력합니다.&lt;/p&gt;
&lt;div class=&quot;assemblylang_greenbox&quot;&gt;
&lt;p class=&quot;assemblylang_box_title&quot; data-ke-size=&quot;size16&quot;&gt;이 방식이 강력했던 이유&lt;/p&gt;
&lt;ul class=&quot;assemblylang_plain_list&quot; style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;게임 디자인과 기술 판단이 분리되지 않았습니다.&lt;/li&gt;
&lt;li&gt;성능 문제를 발견하면 구조를 즉시 바꿀 수 있었습니다.&lt;/li&gt;
&lt;li&gt;결국 &amp;ldquo;재미&amp;rdquo;와 &amp;ldquo;속도&amp;rdquo;를 같은 관점에서 설계할 수 있었습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;assemblylang_section5&quot; class=&quot;assemblylang_section&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;최적화의 황금 표준으로 불리는 이유&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 값의 크기에 따라 자료형을 더 잘게 나눴다&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최신 개발에서는 그냥 넉넉한 자료형을 쓰는 일이 흔하지만, 롤러코스터 타이쿤은 값의 범위에 맞춰 필요한 크기만 사용하는 식의 세밀한 선택이 보입니다. 전체 공원 가치처럼 큰 값은 더 크게, 매점 가격처럼 범위가 작은 값은 더 작게 다루는 식입니다. 이런 선택은 지금 보면 소소해 보일 수 있지만, 수많은 값이 동시에 움직이는 시뮬레이션에서는 누적 효과가 분명합니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 곱셈과 나눗셈을 비트시프트 친화적으로 설계했다&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2, 4, 8 같은 값은 비트시프트로 빠르게 계산할 수 있습니다. 더 흥미로운 점은 단순히 코드 레벨에서만 그런 최적화를 한 것이 아니라, 아예 게임 안의 수식이 이런 계산 방식과 잘 맞도록 설계된 흔적이 보인다는 것입니다. 이건 &amp;ldquo;코드를 빨리 짰다&amp;rdquo;가 아니라 &lt;b&gt;설계 자체가 CPU 친화적이었다&lt;/b&gt;는 뜻에 가깝습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. 데이터 레이아웃 자체가 성능의 핵심이었다&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;진짜 무서운 부분은 명령어 하나하나보다 데이터 구조입니다. 무엇을 어떻게 저장하고, 어떤 순서로 읽고, 얼마나 자주 접근할지 자체가 성능을 좌우합니다. 롤러코스터 타이쿤이 전설이 된 이유는 단지 저수준 언어를 썼기 때문이 아니라, &lt;b&gt;데이터를 CPU가 좋아하는 방식으로 최대한 빽빽하게 설계했다&lt;/b&gt;는 데 있습니다.&lt;/p&gt;
&lt;div class=&quot;assemblylang_quotebox&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;좋은 최적화는 &amp;ldquo;코드 몇 줄을 빨리 돌게 만드는 것&amp;rdquo;보다, &lt;b&gt;애초에 어떤 데이터와 규칙을 어떤 구조로 배치할지를 잘 정하는 것&lt;/b&gt;에서 시작됩니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;assemblylang_section6&quot; class=&quot;assemblylang_section&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;예시 어셈블리 소스가 왜 도움이 되는가&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 글에서 예시 어셈블리 소스를 넣는 것은 분명 도움이 됩니다. 다만 중요한 점은, 이 예시가 실제 Chris Sawyer의 원본 소스가 아니라 &lt;b&gt;본문에서 설명한 최적화 감각을 이해하기 위한 개념 예시&lt;/b&gt;라는 점을 분명히 해야 한다는 것입니다.&lt;/p&gt;
&lt;div class=&quot;assemblylang_warnbox&quot;&gt;
&lt;p class=&quot;assemblylang_box_title&quot; data-ke-size=&quot;size16&quot;&gt;주의&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 코드는 &lt;b&gt;원본 RollerCoaster Tycoon 소스가 아닙니다.&lt;/b&gt;&lt;br /&gt;비트시프트, 플래그 검사, 짧은 분기, 단순 상태 갱신이 어떤 느낌인지 보여주기 위한 &lt;b&gt;이해용 x86 스타일 예시&lt;/b&gt;입니다.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;assemblylang_code_wrap&quot;&gt;
&lt;div class=&quot;assemblylang_code_head&quot;&gt;&lt;span&gt;assemblylang_example_x86.asm&lt;/span&gt; &lt;span&gt;개념 이해용 예시&lt;/span&gt;&lt;/div&gt;
&lt;pre class=&quot;x86asm&quot;&gt;&lt;code&gt;; -----------------------------------------
; 이해용 예시: 손님의 상태 일부를 매우 저수준으로 갱신하는 느낌
; 실제 RCT 원본 소스 아님
; -----------------------------------------

section .data
assemblylang_guest_hunger      db 48      ; 0~255 범위
assemblylang_guest_flags       db 00000101b
assemblylang_guest_happiness   db 120

section .text
global assemblylang_update_guest_state

assemblylang_update_guest_state:
    ; eax, ebx 사용 예시
    xor eax, eax
    xor ebx, ebx

    ; hunger 값을 읽음
    mov al, [assemblylang_guest_hunger]

    ; /8 대신 &amp;gt;&amp;gt; 3 사용
    shr al, 3

    ; 배고픔 단계가 6 이상이면 행복도 감소
    cmp al, 6
    jl assemblylang_check_flags

    mov bl, [assemblylang_guest_happiness]
    sub bl, 2
    mov [assemblylang_guest_happiness], bl

assemblylang_check_flags:
    ; bit 2 = 지도 보유
    mov al, [assemblylang_guest_flags]
    test al, 00000100b
    jz assemblylang_done

    nop

assemblylang_done:
    ret&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 예시에서 중요한 포인트는 문법 자체보다도 감각입니다. &lt;b&gt;작은 자료형, 비트 단위 플래그, 짧은 분기, 곱셈/나눗셈 대신 시프트 활용&lt;/b&gt; 같은 요소가 저수준 최적화의 분위기를 보여줍니다. 본문에 이런 예시가 들어가면 독자는 &amp;ldquo;어셈블리어로 작성됐다&amp;rdquo;는 문장을 더 구체적으로 이해하게 됩니다.&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&quot;assemblylang_section7&quot; class=&quot;assemblylang_section&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;성능을 위해 게임 디자인까지 바꾼 사례&lt;/h2&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;640&quot; data-origin-height=&quot;365&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cYpS6t/dJMcagLJNOo/XcH8z1s9o5tubdDghM1plK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cYpS6t/dJMcagLJNOo/XcH8z1s9o5tubdDghM1plK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cYpS6t/dJMcagLJNOo/XcH8z1s9o5tubdDghM1plK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcYpS6t%2FdJMcagLJNOo%2FXcH8z1s9o5tubdDghM1plK%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;640&quot; height=&quot;365&quot; data-origin-width=&quot;640&quot; data-origin-height=&quot;365&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;h3 data-ke-size=&quot;size23&quot;&gt;손님은 항상 똑똑하게 목적지를 찾지 않는다&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;공원 경영 게임이라면 손님이 가고 싶은 놀이기구를 정하고, 그곳까지 효율적으로 길을 찾을 것 같지만, 이런 구조는 수천 명이 동시에 움직일 때 계산 비용이 너무 큽니다. 롤러코스터 타이쿤은 여기서 정면돌파 대신 우회를 택했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;손님은 늘 완전한 목적지 기반 탐색을 하지 않고, 길을 따라다니다가 흥미로운 시설을 발견하는 식으로 움직입니다. 플레이어 입장에서는 다소 단순해 보일 수 있어도, 엔진 입장에서는 프레임을 지키는 매우 현실적인 선택이었습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;정말 중요한 경우에만 더 비싼 길찾기를 쓴다&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론 모든 상황을 그렇게 처리한 것은 아닙니다. 정비공이 고장 난 기구로 이동하거나, 손님이 출구를 찾아야 하는 경우처럼 중요한 순간에는 더 전통적인 길 찾기가 필요합니다. 다만 여기서도 탐색 깊이에 제한을 둬서, 하나의 길 찾기 요청이 프레임 전체를 무너뜨리지 않게 했다는 점이 중요합니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;군중은 서로 부딪히지 않는다&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현실적인 군중 시뮬레이션을 하려면 사람끼리 충돌과 회피를 계산해야 합니다. 하지만 그건 엄청난 비용을 부릅니다. 롤러코스터 타이쿤은 이 문제도 정면으로 풀지 않았습니다. 손님은 서로 물리적으로 막지 않고, 대신 너무 붐비면 불만이 쌓이도록 해 플레이 경험은 유지하면서 계산량은 줄였습니다.&lt;/p&gt;
&lt;div class=&quot;assemblylang_infobox&quot;&gt;
&lt;p class=&quot;assemblylang_box_title&quot; data-ke-size=&quot;size16&quot;&gt;이 지점이 특히 중요한 이유&lt;/p&gt;
&lt;ul class=&quot;assemblylang_plain_list&quot; style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;모든 문제를 복잡한 알고리즘으로 풀지 않았습니다.&lt;/li&gt;
&lt;li&gt;게임 경험을 해치지 않는 선에서 계산량을 과감하게 줄였습니다.&lt;/li&gt;
&lt;li&gt;즉, 최적화가 코드 레벨이 아니라 게임 디자인 레벨까지 내려가 있었습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;assemblylang_section8&quot; class=&quot;assemblylang_section&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;어셈블리어의 대가와 OpenRCT2&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 방식은 당시 최고의 성능을 끌어내는 데는 강력했지만, 시간이 지나 플랫폼이 달라질수록 큰 약점이 되기도 합니다. 특정 아키텍처에 강하게 종속된 저수준 코드는 새로운 환경으로 옮길 때 그대로 재사용하기가 매우 어렵습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 훗날 원작의 구조를 현대 환경으로 이어가기 위해 팬과 개발자들이 큰 역할을 하게 되었고, 그 대표적인 사례가 바로 &lt;b&gt;OpenRCT2&lt;/b&gt;입니다. 이 프로젝트는 단순한 모드가 아니라, 원작 계열 게임의 동작을 분석하고 현대 환경에서 더 편하게 즐길 수 있도록 이어주는 재구현 프로젝트라는 점에서 의미가 큽니다.&lt;/p&gt;
&lt;div class=&quot;assemblylang_quotebox&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;성능을 위해 가장 낮은 수준까지 내려간 선택은 훗날 유지보수성을 희생시켰지만, 역으로 그 덕분에 OpenRCT2 같은 집요한 재구현 프로젝트가 더 큰 기술적 가치를 갖게 되었습니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;assemblylang_section9&quot; class=&quot;assemblylang_section&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;현대 개발자가 얻을 수 있는 교훈&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 사례를 보고 &amp;ldquo;역시 어셈블리어가 정답이다&amp;rdquo;라고 결론 내리면 오해입니다. 오늘날 대부분의 소프트웨어는 고수준 언어와 성숙한 툴체인 위에서 개발하는 편이 훨씬 합리적입니다. 생산성, 유지보수성, 협업성, 이식성을 무시할 수 없기 때문입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 롤러코스터 타이쿤이 지금도 강하게 남는 이유는 따로 있습니다. &lt;b&gt;성능 문제는 마지막에 튜닝 몇 번 해서 해결되는 것이 아니라, 처음에 데이터와 규칙을 어떻게 설계하느냐에서 이미 절반 이상 결정된다&lt;/b&gt;는 점을 분명하게 보여주기 때문입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 한 가지 더 있습니다. 좋은 개발자는 단순히 프레임워크를 잘 쓰는 사람이 아니라, 그 아래에서 실제로 어떤 비용이 발생하는지 상상할 수 있는 사람에 가깝습니다. 결국 롤러코스터 타이쿤이 남긴 가장 큰 유산은 &amp;ldquo;낮은 수준을 무조건 쓰라&amp;rdquo;가 아니라, &lt;b&gt;하드웨어와 런타임 비용을 이해하는 감각을 잃지 말라&lt;/b&gt;는 말에 더 가깝습니다.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;assemblylang_conclusion&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;마무리, 전설은 언어보다 설계에서 나온다&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;롤러코스터 타이쿤은 오래된 명작 게임이면서 동시에, 제약이 심한 시대에 얼마나 집요한 설계와 최적화가 가능한지를 보여주는 작품입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 이 게임은 지금도 개발자에게 질문을 던집니다. &lt;b&gt;당신은 코드만 보고 있는가, 아니면 그 아래의 비용 구조까지 보고 있는가&lt;/b&gt;. 이 질문이야말로 롤러코스터 타이쿤이 아직도 전설로 남아 있는 진짜 이유일 것입니다.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;assemblylang_sourcebox&quot;&gt;
&lt;p class=&quot;assemblylang_box_title&quot; data-ke-size=&quot;size16&quot;&gt;참고 및 출처&lt;/p&gt;
&lt;ul class=&quot;assemblylang_source_list&quot; style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Chris Sawyer 공식 FAQ 기준으로 RollerCoaster Tycoon은 99% x86 assembler/machine code와 소량의 C로 작성되었다고 소개됩니다.&lt;/li&gt;
&lt;li&gt;Lars Tofus, &lt;i&gt;The gold standard of optimization: A look under the hood of RollerCoaster Tycoon&lt;/i&gt;&lt;/li&gt;
&lt;li&gt;OpenRCT2 프로젝트 및 재구현/역분석 관련 공개 자료&lt;/li&gt;
&lt;li&gt;업로드한 원고 내용을 바탕으로 전체 흐름과 표현을 재구성했습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;assemblylang_tagbox&quot;&gt;
&lt;p class=&quot;assemblylang_box_title&quot; data-ke-size=&quot;size16&quot;&gt;태그&lt;/p&gt;
&lt;span class=&quot;assemblylang_keyword&quot;&gt;#롤러코스터타이쿤&lt;/span&gt; &lt;span class=&quot;assemblylang_keyword&quot;&gt;#어셈블리어&lt;/span&gt; &lt;span class=&quot;assemblylang_keyword&quot;&gt;#크리스소이어&lt;/span&gt; &lt;span class=&quot;assemblylang_keyword&quot;&gt;#x86&lt;/span&gt; &lt;span class=&quot;assemblylang_keyword&quot;&gt;#게임개발&lt;/span&gt; &lt;span class=&quot;assemblylang_keyword&quot;&gt;#게임최적화&lt;/span&gt; &lt;span class=&quot;assemblylang_keyword&quot;&gt;#데이터레이아웃&lt;/span&gt; &lt;span class=&quot;assemblylang_keyword&quot;&gt;#비트시프트&lt;/span&gt; &lt;span class=&quot;assemblylang_keyword&quot;&gt;#OpenRCT2&lt;/span&gt; &lt;span class=&quot;assemblylang_keyword&quot;&gt;#소프트웨어공학&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;</description>
      <category>DEVELOPMENT</category>
      <category>OpenRCT2</category>
      <category>x86어셈블리</category>
      <category>게임개발</category>
      <category>게임최적화</category>
      <category>데이터레이아웃</category>
      <category>롤러코스터타이쿤</category>
      <category>소프트웨어공학</category>
      <category>어셈블리어</category>
      <category>저수준언어</category>
      <category>크리스소이어</category>
      <author>간지뽕빨리턴님</author>
      <guid isPermaLink="true">https://odinbox.tistory.com/578</guid>
      <comments>https://odinbox.tistory.com/578#entry578comment</comments>
      <pubDate>Sun, 29 Mar 2026 13:07:10 +0900</pubDate>
    </item>
    <item>
      <title>울산 공공주택 유홈</title>
      <link>https://odinbox.tistory.com/577</link>
      <description>&lt;div&gt;
&lt;style&gt;
  :root {
    --ulsanhome_color_bg: #f4f7fb;
    --ulsanhome_color_surface: #ffffff;
    --ulsanhome_color_text: #1f2937;
    --ulsanhome_color_muted: #5b6472;
    --ulsanhome_color_line: #dbe4ee;
    --ulsanhome_color_primary: #0f4c81;
    --ulsanhome_color_primary_soft: #eaf3fb;
    --ulsanhome_color_accent: #0f766e;
    --ulsanhome_color_accent_soft: #ecfdf5;
    --ulsanhome_color_warn: #9a3412;
    --ulsanhome_color_warn_soft: #fff7ed;
    --ulsanhome_color_navy: #16324f;
    --ulsanhome_shadow_sm: 0 8px 22px rgba(15, 76, 129, 0.07);
    --ulsanhome_shadow_md: 0 18px 42px rgba(15, 76, 129, 0.12);
    --ulsanhome_radius_sm: 12px;
    --ulsanhome_radius_md: 18px;
    --ulsanhome_radius_lg: 26px;
    --ulsanhome_width: 980px;
    --ulsanhome_font: &quot;Pretendard&quot;, &quot;Noto Sans KR&quot;, &quot;Apple SD Gothic Neo&quot;, sans-serif;
  }

  .ulsanhome_wrap,
  .ulsanhome_wrap * {
    box-sizing: border-box;
  }

  .ulsanhome_wrap {
    max-width: var(--ulsanhome_width);
    margin: 0 auto;
    padding: 18px 0 56px;
    font-family: var(--ulsanhome_font);
    color: var(--ulsanhome_color_text);
    line-height: 1.9;
    word-break: keep-all;
  }

  .ulsanhome_hero {
    padding: 36px 28px;
    border-radius: var(--ulsanhome_radius_lg);
    background: linear-gradient(135deg, #0f4c81 0%, #1c6aa3 55%, #1f7a8c 100%);
    color: #ffffff;
    box-shadow: var(--ulsanhome_shadow_md);
    margin-bottom: 22px;
  }

  .ulsanhome_eyebrow {
    display: inline-block;
    padding: 6px 11px;
    border-radius: 999px;
    background: rgba(255, 255, 255, 0.16);
    font-size: 13px;
    font-weight: 700;
    letter-spacing: 0.02em;
    margin-bottom: 14px;
  }

  .ulsanhome_title {
    margin: 0 0 10px;
    font-size: 34px;
    line-height: 1.34;
    font-weight: 800;
  }

  .ulsanhome_desc {
    margin: 0;
    font-size: 16px;
    color: rgba(255, 255, 255, 0.94);
  }

  .ulsanhome_visual {
    margin: 18px 0 28px;
    padding: 14px;
    background: #ffffff;
    border: 1px solid var(--ulsanhome_color_line);
    border-radius: var(--ulsanhome_radius_lg);
    box-shadow: var(--ulsanhome_shadow_sm);
  }

  .ulsanhome_visual p {
    margin: 0;
  }

  .ulsanhome_section {
    margin-top: 26px;
    background: var(--ulsanhome_color_surface);
    border: 1px solid var(--ulsanhome_color_line);
    border-radius: var(--ulsanhome_radius_md);
    box-shadow: var(--ulsanhome_shadow_sm);
    padding: 28px 22px;
  }

  .ulsanhome_section h2 {
    margin: 0 0 14px;
    font-size: 27px;
    line-height: 1.42;
    color: var(--ulsanhome_color_primary);
  }

  .ulsanhome_section h3 {
    margin: 26px 0 12px;
    font-size: 21px;
    line-height: 1.5;
    color: var(--ulsanhome_color_navy);
  }

  .ulsanhome_section p {
    margin: 0 0 14px;
    font-size: 16px;
  }

  .ulsanhome_info {
    margin: 18px 0;
    padding: 16px 18px;
    border-radius: var(--ulsanhome_radius_md);
    border: 1px solid transparent;
  }

  .ulsanhome_info--primary {
    background: var(--ulsanhome_color_primary_soft);
    border-color: #d3e5f5;
  }

  .ulsanhome_info--accent {
    background: var(--ulsanhome_color_accent_soft);
    border-color: #cdeee7;
  }

  .ulsanhome_info--warn {
    background: var(--ulsanhome_color_warn_soft);
    border-color: #ffd9c2;
  }

  .ulsanhome_toc {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 10px;
    margin-top: 18px;
  }

  .ulsanhome_toc a {
    display: block;
    padding: 12px 14px;
    border-radius: 14px;
    text-decoration: none;
    color: var(--ulsanhome_color_primary);
    background: #f7fbff;
    border: 1px solid #d8e7f5;
    font-weight: 700;
    transition: all 0.2s ease;
  }

  .ulsanhome_toc a:hover {
    transform: translateY(-1px);
    background: #eef6fd;
  }

  .ulsanhome_grid {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 14px;
    margin-top: 18px;
  }

  .ulsanhome_card {
    background: var(--ulsanhome_color_bg);
    border: 1px solid var(--ulsanhome_color_line);
    border-radius: var(--ulsanhome_radius_md);
    padding: 18px 16px;
  }

  .ulsanhome_card strong {
    display: block;
    margin-bottom: 8px;
    color: var(--ulsanhome_color_primary);
    font-size: 15px;
  }

  .ulsanhome_card p {
    margin: 0;
    font-size: 15px;
    color: var(--ulsanhome_color_muted);
  }

  .ulsanhome_list {
    margin: 10px 0 0;
    padding-left: 20px;
  }

  .ulsanhome_list li {
    margin-bottom: 8px;
  }

  .ulsanhome_table_wrap {
    overflow-x: auto;
    margin-top: 18px;
    border: 1px solid var(--ulsanhome_color_line);
    border-radius: var(--ulsanhome_radius_md);
  }

  .ulsanhome_table {
    width: 100%;
    min-width: 760px;
    border-collapse: collapse;
    background: #ffffff;
  }

  .ulsanhome_table th,
  .ulsanhome_table td {
    padding: 14px 12px;
    border-bottom: 1px solid var(--ulsanhome_color_line);
    text-align: left;
    vertical-align: top;
    font-size: 15px;
  }

  .ulsanhome_table th {
    background: #f1f6fb;
    color: var(--ulsanhome_color_primary);
    font-weight: 700;
  }

  .ulsanhome_table tr:last-child td {
    border-bottom: 0;
  }

  .ulsanhome_quote {
    margin-top: 18px;
    padding: 18px 20px;
    border-left: 5px solid var(--ulsanhome_color_primary);
    background: #f8fbfe;
    border-radius: 0 16px 16px 0;
    color: #24415c;
    font-size: 16px;
  }

  .ulsanhome_linkbox {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 14px;
    margin-top: 18px;
  }

  .ulsanhome_linkcard {
    display: block;
    text-decoration: none;
    color: inherit;
    padding: 18px 16px;
    border-radius: var(--ulsanhome_radius_md);
    border: 1px solid var(--ulsanhome_color_line);
    background: #fbfdff;
    transition: all 0.2s ease;
  }

  .ulsanhome_linkcard:hover {
    transform: translateY(-2px);
    box-shadow: var(--ulsanhome_shadow_sm);
  }

  .ulsanhome_linkcard strong {
    display: block;
    margin-bottom: 6px;
    color: var(--ulsanhome_color_primary);
  }

  .ulsanhome_faq_item {
    padding: 16px 0;
    border-bottom: 1px dashed var(--ulsanhome_color_line);
  }

  .ulsanhome_faq_item:last-child {
    border-bottom: 0;
    padding-bottom: 0;
  }

  .ulsanhome_badges {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-top: 18px;
  }

  .ulsanhome_badge {
    display: inline-flex;
    align-items: center;
    padding: 8px 12px;
    border-radius: 999px;
    background: var(--ulsanhome_color_primary_soft);
    color: var(--ulsanhome_color_primary);
    border: 1px solid #d6e6f5;
    font-size: 13px;
    font-weight: 700;
  }

  .ulsanhome_hr {
    border: 0;
    border-top: 1px dashed var(--ulsanhome_color_line);
    margin: 24px 0;
  }

  .ulsanhome_small {
    font-size: 14px;
    color: var(--ulsanhome_color_muted);
  }

  .ulsanhome_em {
    color: var(--ulsanhome_color_primary);
    font-weight: 800;
  }

  @media (max-width: 768px) {
    .ulsanhome_wrap {
      padding: 10px 0 40px;
    }

    .ulsanhome_hero {
      padding: 26px 18px;
    }

    .ulsanhome_title {
      font-size: 28px;
    }

    .ulsanhome_section {
      padding: 20px 16px;
    }

    .ulsanhome_section h2 {
      font-size: 24px;
    }

    .ulsanhome_section h3 {
      font-size: 19px;
    }

    .ulsanhome_grid,
    .ulsanhome_toc,
    .ulsanhome_linkbox {
      grid-template-columns: 1fr;
    }
  }
&lt;/style&gt;
&lt;/div&gt;
&lt;div class=&quot;ulsanhome_wrap&quot;&gt;
&lt;div class=&quot;ulsanhome_visual&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;글 상단 부분 대표 이미지 (1).png&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bzjfve/dJMcagdNnZy/0vAw3Ta2KKLAhPpkpAgkI0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bzjfve/dJMcagdNnZy/0vAw3Ta2KKLAhPpkpAgkI0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bzjfve/dJMcagdNnZy/0vAw3Ta2KKLAhPpkpAgkI0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbzjfve%2FdJMcagdNnZy%2F0vAw3Ta2KKLAhPpkpAgkI0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;400&quot; data-filename=&quot;글 상단 부분 대표 이미지 (1).png&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;section class=&quot;ulsanhome_section&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;울산 유홈 성안매입 정보를 다시 차분하게 정리해 보았습니다&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최근 울산에서 주거 정보를 찾다 보면 &lt;span class=&quot;ulsanhome_em&quot;&gt;유홈 성안매입&lt;/span&gt;, &lt;span class=&quot;ulsanhome_em&quot;&gt;울산도시공사 임대공고&lt;/span&gt;, 그리고 &lt;span class=&quot;ulsanhome_em&quot;&gt;울산청년정책플랫폼 U-PAGE&lt;/span&gt;를 자주 보게 됩니다. 다만 실제로 검색을 해보면 정보가 여기저기 흩어져 있고, 유홈이 정확히 어떤 브랜드인지, 이번 성안매입 공고는 어떤 성격인지, 발표는 언제쯤 나오는지 한 번에 정리된 글은 생각보다 많지 않았습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 이번 글은 제가 직접 공고를 확인하고, 직접 신청도 해보면서 느낀 점까지 담아 정리해 보았습니다. 결론부터 말씀드리면, &lt;b&gt;유홈 전체 브랜드와 이번 성안매입 개별 공고는 구분해서 보는 것이 가장 정확합니다.&lt;/b&gt; 브랜드 전체는 더 넓은 범위를 담고 있고, 이번 성안매입 모집은 현재 공고 기준으로 별도의 청년임대 공고로 이해하는 편이 자연스럽습니다.&lt;/p&gt;
&lt;div class=&quot;ulsanhome_info ulsanhome_info--primary&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저도 최근 유홈 성안매입에 직접 신청하고 왔습니다. 현장에서 생각보다 많은 분들이 기다리고 계셔서 꽤 놀랐고, 결과는 아직 발표되지 않아 저 역시 계속 기다리고 있는 중입니다.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulsanhome_toc&quot;&gt;&lt;a href=&quot;#ulsanhome_summary&quot;&gt;핵심 요약 먼저 보기&lt;/a&gt; &lt;a href=&quot;#ulsanhome_brand&quot;&gt;유홈 브랜드 성격 보기&lt;/a&gt; &lt;a href=&quot;#ulsanhome_sungan&quot;&gt;성안매입 공고와 발표 시기 보기&lt;/a&gt; &lt;a href=&quot;#ulsanhome_story&quot;&gt;직접 신청하고 느낀 점 보기&lt;/a&gt; &lt;a href=&quot;#ulsanhome_upage&quot;&gt;U-PAGE 활용법 보기&lt;/a&gt; &lt;a href=&quot;#ulsanhome_faq&quot;&gt;FAQ 보기&lt;/a&gt; &lt;a href=&quot;#ulsanhome_links&quot;&gt;공식 링크 바로가기&lt;/a&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;ulsanhome_summary&quot; class=&quot;ulsanhome_section&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;한눈에 보는 핵심 요약&lt;/h2&gt;
&lt;div class=&quot;ulsanhome_grid&quot;&gt;
&lt;div class=&quot;ulsanhome_card&quot;&gt;&lt;b&gt;유홈 브랜드&lt;/b&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;유홈은 울산시와 울산도시공사가 공급하는 공공주택 브랜드로 보는 편이 맞습니다. 그래서 유홈 전체를 곧바로 청년 전용 브랜드라고 단정하는 표현은 조금 조심하는 편이 좋습니다.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulsanhome_card&quot;&gt;&lt;b&gt;성안매입 공고&lt;/b&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 성안매입 모집은 공식 공고 기준으로 청년임대로 올라와 있습니다. 그래서 브랜드 전체 설명과 개별 모집 공고 설명은 나눠서 보는 것이 정확합니다.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulsanhome_card&quot;&gt;&lt;b&gt;발표와 확인 경로&lt;/b&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;공개자료상 자격 검증 뒤 5~6월 중 최종 입주자 확정 흐름으로 안내되어 있습니다. 실제 확인은 울산도시공사 임대공고와 U-PAGE를 같이 보는 방식이 가장 효율적입니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;ulsanhome_quote&quot;&gt;이번 내용을 정리하면서 가장 중요하다고 느낀 점은 하나였습니다. 유홈이라는 이름만 보고 단정하기보다, 브랜드 전체와 개별 공고를 분리해서 이해해야 정보가 훨씬 선명해진다는 점입니다.&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;ulsanhome_brand&quot; class=&quot;ulsanhome_section&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;유홈은 청년만의 브랜드라고 단정하기보다 더 넓게 보는 편이 맞습니다&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 부분은 검색하면서 가장 헷갈리기 쉬운 지점입니다. 많은 분들이 유홈을 보면 자연스럽게 청년주택을 먼저 떠올리실 수 있지만, 실제로는 &lt;b&gt;유홈 전체 브랜드 설명&lt;/b&gt;과 &lt;b&gt;이번 성안매입 개별 모집 공고&lt;/b&gt;를 구분해서 보는 것이 더 정확합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;브랜드 차원에서 유홈은 울산시와 울산도시공사가 공급하는 공공주택의 새로운 이름으로 자리 잡아가는 흐름에 가깝습니다. 그래서 글을 쓸 때도 &amp;ldquo;유홈은 무조건 청년만을 위한 브랜드입니다&amp;rdquo;라고 단정하기보다는, &amp;ldquo;유홈은 울산 공공주택 브랜드이고, 이번 성안매입 공고는 현재 청년임대로 분류되어 있습니다&amp;rdquo;라고 설명하는 편이 훨씬 깔끔합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;최근 유홈 사례를 보면 이런 방향이 더 잘 보입니다&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최근 준공된 유홈 백합 사례를 보면 단순히 저렴한 집 한 칸을 공급하는 방식보다, 공유주방과 헬스장 같은 커뮤니티 요소를 함께 갖춘 형태로 소개되고 있습니다. 이런 흐름을 보면 유홈은 단지 임대료만 이야기하는 브랜드라기보다, 실제 거주 만족도와 생활 편의까지 함께 고려하려는 방향으로 읽히기도 합니다.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;ulsanhome_sungan&quot; class=&quot;ulsanhome_section&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;울산 유홈 성안매입 공고와 발표 시기는 이렇게 이해하시면 됩니다&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;성안매입은 최근 울산에서 관심이 높았던 공고 중 하나였습니다. 공개된 자료를 기준으로 보면 성안동 유홈은 총 48호 규모로 공급되며, 서류 신청 이후 자격 검증을 거쳐 최종 입주자를 확정하는 흐름으로 안내되고 있습니다.&lt;/p&gt;
&lt;div class=&quot;ulsanhome_table_wrap&quot;&gt;
&lt;table class=&quot;ulsanhome_table&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;항목&lt;/th&gt;
&lt;th&gt;정리 내용&lt;/th&gt;
&lt;th&gt;체크 포인트&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;공고 게시&lt;/td&gt;
&lt;td&gt;2026년 2월 20일&lt;/td&gt;
&lt;td&gt;울산도시공사 임대공고에서 공식 확인 가능합니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;주택 유형&lt;/td&gt;
&lt;td&gt;청년임대&lt;/td&gt;
&lt;td&gt;이번 성안매입 공고 자체는 현재 청년임대로 분류되어 있습니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;공급 규모&lt;/td&gt;
&lt;td&gt;48호&lt;/td&gt;
&lt;td&gt;전용 19㎡형과 20㎡형 중심으로 안내됩니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;입주 예정&lt;/td&gt;
&lt;td&gt;2026년 6월&lt;/td&gt;
&lt;td&gt;자격 검증과 확정 절차 이후 입주 흐름으로 보시면 됩니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;최종 확정 시기&lt;/td&gt;
&lt;td&gt;5~6월 중&lt;/td&gt;
&lt;td&gt;그래서 현장에서 들으신 5월 전후 발표 이야기와도 큰 틀에서는 맞닿아 있습니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;많은 분들이 가장 궁금해하시는 부분이 바로 발표 시기일 텐데, 현재 공개자료 기준으로는 &lt;b&gt;자격 검증을 거쳐 5~6월 중 최종 입주자를 확정&lt;/b&gt;하는 흐름으로 이해하는 것이 맞습니다. 그래서 아직 결과가 나오지 않은 지금 시점에서는 &amp;ldquo;발표 전&amp;rdquo;이라고 보는 것이 자연스럽고, 조금 더 기다리면서 공식 공고를 계속 확인하는 것이 가장 정확한 방법입니다.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;ulsanhome_story&quot; class=&quot;ulsanhome_section&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;저도 직접 신청해 보니 관심이 큰 이유를 조금 알 것 같았습니다&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저도 최근 유홈 성안매입에 직접 신청하고 왔습니다. 막연히 공고 하나가 올라왔겠거니 생각하고 갔는데, 실제로는 생각보다 많은 분들이 관심을 가지고 기다리고 계셔서 꽤 놀랐습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 분위기를 보면서 느낀 점은 단순했습니다. 울산에서도 &lt;b&gt;위치가 괜찮고, 현실적으로 접근 가능한 공공임대&lt;/b&gt;에 대한 관심이 분명히 크다는 점입니다. 집은 단순히 월세 숫자만의 문제가 아니라 출근과 생활, 이동 동선, 그리고 앞으로의 안정감까지 연결되기 때문에 이런 공고 하나의 의미가 생각보다 훨씬 크게 다가오는 것 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저 역시 아직 결과를 기다리고 있는 입장이라 더 조심스럽지만, 개인적으로는 꼭 좋은 결과가 있었으면 좋겠다는 마음입니다. 그리고 이 글을 보시는 분들께도 실제로 도움이 되는 정리였으면 좋겠습니다.&lt;/p&gt;
&lt;div class=&quot;ulsanhome_quote&quot;&gt;신청해보니 더 선명하게 느껴졌습니다. 유홈 성안매입은 단순히 한 번 스쳐 지나가는 공고가 아니라, 많은 분들이 실제로 기다리고 있던 기회에 가까웠습니다.&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;ulsanhome_upage&quot; class=&quot;ulsanhome_section&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;울산청년정책플랫폼 U-PAGE는 꼭 같이 보시는 것이 좋습니다&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;유홈 성안매입처럼 개별 공고를 볼 때 가장 먼저 확인해야 하는 곳은 물론 울산도시공사 임대공고입니다. 다만 거기서 끝내지 않고 &lt;b&gt;울산청년정책플랫폼 U-PAGE&lt;/b&gt;까지 같이 보면, 훨씬 넓은 흐름을 이해하기 쉬워집니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;U-PAGE에서 좋은 점&lt;/h3&gt;
&lt;ul class=&quot;ulsanhome_list&quot; style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;정책유형에서 주거를 따로 선택해서 볼 수 있습니다.&lt;/li&gt;
&lt;li&gt;지역, 학력 등 조건별로 정책을 나눠서 볼 수 있습니다.&lt;/li&gt;
&lt;li&gt;주거뿐 아니라 취업지원, 창업지원, 교육, 복지&amp;middot;문화, 참여&amp;middot;권리까지 함께 확인할 수 있습니다.&lt;/li&gt;
&lt;li&gt;공고 한 건만 보는 것이 아니라 울산 정책 흐름을 넓게 파악하기 좋습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;ulsanhome_info ulsanhome_info--primary&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제 기준에서는 &lt;b&gt;실제 모집 공고와 결과 확인은 울산도시공사&lt;/b&gt;에서, &lt;b&gt;추가로 챙길 수 있는 정책과 연관 지원은 U-PAGE&lt;/b&gt;에서 확인하는 방식이 가장 효율적으로 느껴졌습니다.&lt;/p&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히 울산에 살면서 주거뿐 아니라 취업, 교육, 복지까지 함께 챙기고 싶다면 U-PAGE는 한 번쯤 꼭 들어가 볼 만한 플랫폼입니다. 한 건의 공고만 보는 것보다 정보 폭이 훨씬 넓어집니다.&lt;/p&gt;
&lt;/section&gt;
&lt;section class=&quot;ulsanhome_section&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;울산 유홈과 공공임대 정보를 볼 때 이렇게 접근하시면 더 편합니다&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 공고 원문은 울산도시공사에서 먼저 확인합니다&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제 모집 공고, 결과 공고, 첨부서류, 공고문 원문은 울산도시공사 임대공고가 기준이 됩니다. 성안매입처럼 관심이 큰 공고일수록 첨부파일까지 함께 확인해 두시는 것이 좋습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. U-PAGE로 정책 흐름을 넓게 봅니다&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 건의 공고만 보면 지금 열려 있는 기회만 보게 됩니다. 반면 U-PAGE는 울산 정책 안에서 주거를 포함한 다양한 지원을 같이 볼 수 있어 놓치고 있던 정보까지 챙기기에 좋습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. 유홈 전체와 개별 공고를 구분해서 이해합니다&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 성안매입은 청년임대 공고이지만, 유홈 전체 브랜드 설명은 그것보다 더 넓습니다. 그래서 검색할 때도 유홈, 성안매입, 울산도시공사 임대공고, U-PAGE를 함께 보는 편이 훨씬 정확합니다.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;ulsanhome_faq&quot; class=&quot;ulsanhome_section&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;울산 유홈 성안매입 관련 자주 묻는 질문&lt;/h2&gt;
&lt;div class=&quot;ulsanhome_faq_item&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;유홈은 청년만 가능한가요?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;유홈 전체 브랜드를 무조건 청년 전용이라고 단정하는 표현은 조금 조심하는 편이 좋습니다. 다만 이번 성안매입 개별 공고는 현재 공식 분류상 청년임대로 올라와 있으므로, 실제 신청 여부는 개별 공고 기준으로 판단하시는 것이 맞습니다.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulsanhome_faq_item&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;성안매입 발표는 언제쯤으로 보면 될까요?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 공개자료 기준으로는 자격 검증을 거쳐 5~6월 중 최종 입주자를 확정하는 흐름으로 안내되어 있습니다. 그래서 5월 전후 발표 이야기가 나오는 것도 큰 틀에서는 자연스럽게 이해할 수 있습니다.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulsanhome_faq_item&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;결과는 어디서 확인하면 되나요?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 먼저 보셔야 할 곳은 울산도시공사 임대공고입니다. 제가 글을 정리하는 시점에는 성안매입 결과 공고는 아직 보이지 않았기 때문에, 공식 게시판을 주기적으로 확인하시는 것이 가장 정확합니다.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulsanhome_faq_item&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;U-PAGE는 왜 같이 봐야 하나요?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;유홈 공고 하나만 보는 것이 아니라 울산의 주거, 취업, 교육, 복지 정책을 함께 볼 수 있기 때문입니다. 실제로는 이런 플랫폼을 같이 보는 편이 훨씬 실용적입니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;ulsanhome_links&quot; class=&quot;ulsanhome_section&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;공식 사이트 바로가기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 링크는 실제로 확인해 두면 좋은 공식 사이트입니다. 울산 유홈 성안매입 공고, 울산도시공사 임대공고, 울산청년정책플랫폼 U-PAGE를 같이 보시면 공고와 정책 흐름을 더 쉽게 연결해서 볼 수 있습니다.&lt;/p&gt;
&lt;div class=&quot;ulsanhome_linkbox&quot;&gt;&lt;a class=&quot;ulsanhome_linkcard&quot; href=&quot;https://www.umca.co.kr/umca/bbs/view.do?bbsId=BBS_0000000000000004&amp;amp;mId=001001004000000000&amp;amp;dataId=4241&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt; &lt;b&gt;유홈 성안매입 입주자 모집 공고 바로가기&lt;/b&gt; &lt;span&gt;성안매입 공고문과 첨부자료를 직접 확인할 수 있습니다.&lt;/span&gt; &lt;/a&gt; &lt;a class=&quot;ulsanhome_linkcard&quot; href=&quot;https://www.umca.co.kr/umca/bbs/list.do?bbsId=BBS_0000000000000004&amp;amp;mId=001001004000000000&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt; &lt;b&gt;울산도시공사 임대공고 바로가기&lt;/b&gt; &lt;span&gt;유홈과 공공임대의 최신 모집 공고, 결과 공고 흐름을 확인할 수 있습니다.&lt;/span&gt; &lt;/a&gt; &lt;a class=&quot;ulsanhome_linkcard&quot; href=&quot;https://www.ulsan.go.kr/s/ulsanyouth/main.ulsan&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt; &lt;b&gt;울산청년정책플랫폼 U-PAGE 바로가기&lt;/b&gt; &lt;span&gt;주거를 포함한 울산 정책을 조건별로 검색할 수 있습니다.&lt;/span&gt; &lt;/a&gt; &lt;a class=&quot;ulsanhome_linkcard&quot; href=&quot;https://www.ulsan.go.kr/u/rep/bbs/view.ulsan?bbsId=BBS_0000000000000027&amp;amp;dataId=179102&amp;amp;mId=001004003001000000&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt; &lt;b&gt;울산시 성안동 유홈 보도자료 바로가기&lt;/b&gt; &lt;span&gt;서류 접수와 입주 예정 시기, 최종 확정 흐름을 확인할 수 있습니다.&lt;/span&gt; &lt;/a&gt;&lt;/div&gt;
&lt;div class=&quot;ulsanhome_badges&quot;&gt;&lt;span class=&quot;ulsanhome_badge&quot;&gt;#울산유홈&lt;/span&gt; &lt;span class=&quot;ulsanhome_badge&quot;&gt;#유홈성안매입&lt;/span&gt; &lt;span class=&quot;ulsanhome_badge&quot;&gt;#울산공공임대&lt;/span&gt; &lt;span class=&quot;ulsanhome_badge&quot;&gt;#울산도시공사&lt;/span&gt; &lt;span class=&quot;ulsanhome_badge&quot;&gt;#울산청년정책플랫폼&lt;/span&gt; &lt;span class=&quot;ulsanhome_badge&quot;&gt;#U_PAGE&lt;/span&gt; &lt;span class=&quot;ulsanhome_badge&quot;&gt;#울산주거정보&lt;/span&gt; &lt;span class=&quot;ulsanhome_badge&quot;&gt;#울산성안동&lt;/span&gt;&lt;/div&gt;
&lt;hr class=&quot;ulsanhome_hr&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p class=&quot;ulsanhome_small&quot; data-ke-size=&quot;size16&quot;&gt;본 글은 작성 시점 기준 공개된 공식 자료를 바탕으로 정리한 정보성 글입니다. 실제 신청 자격과 최종 발표 일정은 공식 공고문과 최신 공지를 다시 확인하시기 바랍니다.&lt;/p&gt;
&lt;/section&gt;
&lt;/div&gt;</description>
      <category>DailyRoutine/Ulsan</category>
      <category>U-PAGE</category>
      <category>울산공공임대</category>
      <category>울산도시공사</category>
      <category>울산유홈</category>
      <category>울산주거정책</category>
      <category>울산청년플랫폼</category>
      <category>임대주택</category>
      <category>주거지원</category>
      <category>청년</category>
      <category>청년지원</category>
      <author>간지뽕빨리턴님</author>
      <guid isPermaLink="true">https://odinbox.tistory.com/577</guid>
      <comments>https://odinbox.tistory.com/577#entry577comment</comments>
      <pubDate>Sun, 22 Mar 2026 11:17:43 +0900</pubDate>
    </item>
    <item>
      <title>PostgreSQL, Oracle DB 모니터링</title>
      <link>https://odinbox.tistory.com/576</link>
      <description>&lt;div&gt;
&lt;style&gt;
.pgocmonitoring_wrap{
  max-width:860px;
  margin:0 auto;
  padding:32px 18px 70px;
  font-family:&quot;Pretendard&quot;,&quot;Noto Sans KR&quot;,&quot;Apple SD Gothic Neo&quot;,&quot;Malgun Gothic&quot;,sans-serif;
  color:#1f2937;
  line-height:1.9;
  word-break:keep-all;
}

.pgocmonitoring_wrap *{
  box-sizing:border-box;
}

.pgocmonitoring_hero{
  padding:36px 30px;
  border:1px solid #e5e7eb;
  border-radius:24px;
  background:linear-gradient(135deg,#f8fbff 0%,#ffffff 58%,#f3f7fb 100%);
  box-shadow:0 14px 36px rgba(15,23,42,0.05);
  margin-bottom:24px;
}

.pgocmonitoring_kicker{
  display:inline-block;
  margin-bottom:14px;
  padding:6px 12px;
  border-radius:999px;
  background:#eff6ff;
  color:#1d4ed8;
  font-size:12px;
  font-weight:700;
  letter-spacing:0.04em;
}

.pgocmonitoring_title{
  margin:0;
  font-size:34px;
  line-height:1.35;
  letter-spacing:-0.03em;
  color:#111827;
  font-weight:800;
}

.pgocmonitoring_subtitle{
  margin:16px 0 0;
  font-size:17px;
  color:#4b5563;
}

.pgocmonitoring_thumb{
  margin:18px 0 30px;
  text-align:center;
}

.pgocmonitoring_thumb p{
  margin:0;
}

.pgocmonitoring_box{
  margin:24px 0;
  padding:24px;
  border:1px solid #e5e7eb;
  border-radius:20px;
  background:#ffffff;
  box-shadow:0 8px 24px rgba(15,23,42,0.04);
}

.pgocmonitoring_section{
  margin-top:56px;
}

.pgocmonitoring_h2{
  margin:0 0 18px;
  font-size:28px;
  line-height:1.42;
  letter-spacing:-0.02em;
  color:#111827;
  font-weight:800;
}

.pgocmonitoring_h3{
  margin:34px 0 14px;
  font-size:22px;
  line-height:1.48;
  letter-spacing:-0.02em;
  color:#1f2937;
  font-weight:750;
}

.pgocmonitoring_p{
  margin:0 0 18px;
  font-size:17px;
  color:#374151;
}

.pgocmonitoring_toc{
  list-style:none;
  margin:0;
  padding:0;
}

.pgocmonitoring_toc li{
  margin:10px 0;
  padding-left:0;
  font-size:16px;
  color:#374151;
}

.pgocmonitoring_toc a{
  color:#1f2937;
  text-decoration:none;
  border-bottom:1px solid rgba(31,41,55,0.15);
}

.pgocmonitoring_toc a:hover{
  color:#1d4ed8;
  border-bottom-color:rgba(29,78,216,0.3);
}

.pgocmonitoring_list{
  margin:0 0 20px;
  padding-left:22px;
}

.pgocmonitoring_list li{
  margin:10px 0;
  font-size:16px;
  color:#374151;
}

.pgocmonitoring_note{
  margin:18px 0;
  padding:16px 18px;
  border-left:4px solid #2563eb;
  border-radius:12px;
  background:#eff6ff;
  color:#1e3a8a;
  font-size:15px;
}

.pgocmonitoring_warn{
  margin:18px 0;
  padding:16px 18px;
  border-left:4px solid #dc2626;
  border-radius:12px;
  background:#fef2f2;
  color:#991b1b;
  font-size:15px;
}

.pgocmonitoring_codewrap{
  margin:20px 0 24px;
  border:1px solid #0f172a;
  border-radius:18px;
  overflow:hidden;
  background:#0b1220;
  box-shadow:0 16px 32px rgba(2,6,23,0.18);
}

.pgocmonitoring_codelabel{
  padding:13px 18px;
  background:#0f172a;
  color:#dbeafe;
  font-size:13px;
  font-weight:700;
  border-bottom:1px solid rgba(255,255,255,0.08);
}

.pgocmonitoring_code{
  margin:0;
  padding:20px 22px;
  overflow-x:auto;
  background:#0b1220;
  color:#f8fafc;
  font-size:14px;
  line-height:1.8;
  font-family:&quot;D2Coding&quot;,&quot;Consolas&quot;,&quot;Courier New&quot;,monospace;
  white-space:pre;
  tab-size:4;
}

.pgocmonitoring_tablewrap{
  overflow-x:auto;
  margin:20px 0 26px;
}

.pgocmonitoring_table{
  width:100%;
  min-width:640px;
  border-collapse:collapse;
  background:#ffffff;
  border:1px solid #e5e7eb;
  border-radius:16px;
  overflow:hidden;
}

.pgocmonitoring_table th,
.pgocmonitoring_table td{
  padding:14px 16px;
  border-bottom:1px solid #e5e7eb;
  text-align:left;
  vertical-align:top;
  font-size:15px;
  color:#374151;
}

.pgocmonitoring_table th{
  background:#f9fafb;
  color:#111827;
  font-weight:800;
}

.pgocmonitoring_table tr:last-child td{
  border-bottom:none;
}

.pgocmonitoring_divider{
  height:1px;
  margin:46px 0;
  background:linear-gradient(90deg,rgba(203,213,225,0) 0%,rgba(203,213,225,1) 50%,rgba(203,213,225,0) 100%);
}

.pgocmonitoring_tags{
  display:flex;
  flex-wrap:wrap;
  gap:10px;
  margin-top:16px;
}

.pgocmonitoring_tag{
  display:inline-flex;
  align-items:center;
  padding:8px 13px;
  border:1px solid #dbeafe;
  border-radius:999px;
  background:#f8fbff;
  color:#1d4ed8;
  font-size:13px;
  font-weight:600;
}

@media (max-width:768px){
  .pgocmonitoring_wrap{
    padding:18px 14px 44px;
  }

  .pgocmonitoring_hero,
  .pgocmonitoring_box{
    padding:22px 18px;
    border-radius:18px;
  }

  .pgocmonitoring_title{
    font-size:28px;
  }

  .pgocmonitoring_h2{
    font-size:24px;
  }

  .pgocmonitoring_h3{
    font-size:20px;
  }

  .pgocmonitoring_p,
  .pgocmonitoring_list li,
  .pgocmonitoring_toc li{
    font-size:16px;
  }

  .pgocmonitoring_code{
    font-size:13px;
    padding:18px 16px;
  }
}
&lt;/style&gt;
&lt;/div&gt;
&lt;div class=&quot;pgocmonitoring_wrap&quot;&gt;
&lt;section class=&quot;pgocmonitoring_hero&quot;&gt;
&lt;div class=&quot;pgocmonitoring_kicker&quot;&gt;POSTGRESQL &amp;middot; ORACLE &amp;middot; DB MONITORING&lt;/div&gt;
&lt;p class=&quot;pgocmonitoring_subtitle&quot; data-ke-size=&quot;size16&quot;&gt;운영 중인 시스템에서 저장 버튼이 눌렸는데 반응이 없거나, 특정 화면만 유독 느려지고, 배치 작업이 끝나지 않은 것처럼 보이는 상황을 한 번쯤은 겪게 됩니다. 이런 문제는 애플리케이션 코드만의 문제가 아니라 데이터베이스 세션 대기, 장시간 실행 쿼리, Commit 누락, Lock 충돌 때문에 발생하는 경우가 많습니다. 이번 글에서는 PostgreSQL과 Oracle 환경에서 어떤 기준으로 DB를 모니터링해야 하는지, 현재 Lock 상태를 어떻게 확인해야 하는지, 문제가 되는 세션은 어떤 방식으로 해제해야 하는지를 실무 흐름 중심으로 정리하겠습니다.&lt;/p&gt;
&lt;/section&gt;
&lt;div class=&quot;pgocmonitoring_thumb&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;글 상단 부분 대표 이미지.png&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/crNTCr/dJMcahKssYv/S3RBQCjnoeaxoZseFmkTrK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/crNTCr/dJMcahKssYv/S3RBQCjnoeaxoZseFmkTrK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/crNTCr/dJMcahKssYv/S3RBQCjnoeaxoZseFmkTrK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcrNTCr%2FdJMcahKssYv%2FS3RBQCjnoeaxoZseFmkTrK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;400&quot; data-filename=&quot;글 상단 부분 대표 이미지.png&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;section class=&quot;pgocmonitoring_box&quot;&gt;
&lt;h2 class=&quot;pgocmonitoring_h3&quot; style=&quot;margin-top: 0;&quot; data-ke-size=&quot;size26&quot;&gt;목차&lt;/h2&gt;
&lt;ul class=&quot;pgocmonitoring_toc&quot; style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;#pgocmonitoring_sec1&quot;&gt;DB 모니터링이 왜 중요한가&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#pgocmonitoring_sec2&quot;&gt;PostgreSQL에서 확인해야 하는 모니터링 포인트&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#pgocmonitoring_sec3&quot;&gt;Oracle에서 확인해야 하는 모니터링 포인트&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#pgocmonitoring_sec4&quot;&gt;PostgreSQL에서 Lock 확인과 해제 방법&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#pgocmonitoring_sec5&quot;&gt;Oracle에서 Lock 확인과 해제 방법&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#pgocmonitoring_sec6&quot;&gt;운영 중 조치할 때 주의할 점&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;section id=&quot;pgocmonitoring_sec1&quot; class=&quot;pgocmonitoring_section&quot;&gt;
&lt;h2 class=&quot;pgocmonitoring_h2&quot; data-ke-size=&quot;size26&quot;&gt;DB 모니터링이 왜 중요한가&lt;/h2&gt;
&lt;p class=&quot;pgocmonitoring_p&quot; data-ke-size=&quot;size16&quot;&gt;데이터베이스는 서비스의 가장 안쪽에서 실제 데이터를 처리하는 핵심 계층입니다. 사용자는 웹 화면이나 프로그램 화면에서 단순히 저장, 조회, 삭제만 수행하는 것처럼 보이지만, 그 뒤에서는 세션 연결, 트랜잭션 시작, SQL 실행, Lock 획득, Commit 또는 Rollback과 같은 과정이 순차적으로 이뤄지고 있습니다.&lt;/p&gt;
&lt;p class=&quot;pgocmonitoring_p&quot; data-ke-size=&quot;size16&quot;&gt;따라서 화면이 느려지는 현상이나 저장이 멈춘 것처럼 보이는 증상은 실제로는 DB 내부에서 누군가가 자원을 오래 점유하고 있거나, 특정 세션이 다른 세션들을 대기시키고 있는 경우가 많습니다. 이런 상황을 빠르게 파악하려면 평소부터 모니터링 기준을 정리해 두고, 이상 징후가 발생했을 때 어디부터 확인할지를 알고 있어야 합니다.&lt;/p&gt;
&lt;div class=&quot;pgocmonitoring_note&quot;&gt;운영 장애는 대부분 갑자기 발생한 것처럼 보이지만, 실제로는 이미 세션 증가, 장시간 실행 쿼리, idle in transaction, Lock 대기 같은 징후가 누적되고 있었던 경우가 많습니다.&lt;/div&gt;
&lt;p class=&quot;pgocmonitoring_p&quot; data-ke-size=&quot;size16&quot;&gt;실무에서 자주 보는 대표적인 징후는 아래와 같습니다.&lt;/p&gt;
&lt;ul class=&quot;pgocmonitoring_list&quot; style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;특정 사용자만 저장이 안 되는 것이 아니라 여러 사용자가 동시에 느리다고 말하는 경우&lt;/li&gt;
&lt;li&gt;같은 화면에서만 반복적으로 응답 지연이 발생하는 경우&lt;/li&gt;
&lt;li&gt;배치 시간대와 온라인 업무 시간이 겹칠 때 성능 저하가 심해지는 경우&lt;/li&gt;
&lt;li&gt;트랜잭션이 끝나지 않은 세션이 오랫동안 살아 있는 경우&lt;/li&gt;
&lt;li&gt;한 세션이 잡은 Lock 때문에 다른 작업들이 연쇄적으로 대기하는 경우&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;pgocmonitoring_p&quot; data-ke-size=&quot;size16&quot;&gt;결국 DB 모니터링은 단순히 수치를 보는 것이 아니라, 현재 서비스 흐름이 정상적으로 돌고 있는지 확인하는 운영 기술이라고 볼 수 있습니다.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;pgocmonitoring_sec2&quot; class=&quot;pgocmonitoring_section&quot;&gt;
&lt;h2 class=&quot;pgocmonitoring_h2&quot; data-ke-size=&quot;size26&quot;&gt;PostgreSQL에서 확인해야 하는 모니터링 포인트&lt;/h2&gt;
&lt;p class=&quot;pgocmonitoring_p&quot; data-ke-size=&quot;size16&quot;&gt;PostgreSQL에서는 기본적으로 제공되는 시스템 뷰만 잘 활용해도 많은 문제를 추적할 수 있습니다. 가장 대표적인 대상은 pg_stat_activity와 pg_locks입니다. pg_stat_activity는 현재 살아 있는 세션과 실행 중인 쿼리 상태를 보여주고, pg_locks는 어떤 Lock이 어떤 세션에 의해 점유되고 있는지를 보여줍니다.&lt;/p&gt;
&lt;h3 class=&quot;pgocmonitoring_h3&quot; data-ke-size=&quot;size23&quot;&gt;현재 실행 중인 세션과 SQL 확인&lt;/h3&gt;
&lt;p class=&quot;pgocmonitoring_p&quot; data-ke-size=&quot;size16&quot;&gt;문제 상황이 발생하면 가장 먼저 현재 어떤 세션이 살아 있는지를 확인해야 합니다. 특히 state가 idle이 아닌 세션, query_start 이후 오래 실행되고 있는 세션, wait_event가 표시되는 세션은 우선적으로 볼 필요가 있습니다.&lt;/p&gt;
&lt;div class=&quot;pgocmonitoring_codewrap&quot;&gt;
&lt;div class=&quot;pgocmonitoring_codelabel&quot;&gt;PostgreSQL &amp;middot; active session 확인&lt;/div&gt;
&lt;pre class=&quot;pgocmonitoring_code pgsql&quot;&gt;&lt;code&gt;SELECT
    pid,
    usename,
    application_name,
    client_addr,
    state,
    wait_event_type,
    wait_event,
    now() - query_start AS duration,
    query
FROM pg_stat_activity
WHERE state &amp;lt;&amp;gt; 'idle'
ORDER BY query_start;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;p class=&quot;pgocmonitoring_p&quot; data-ke-size=&quot;size16&quot;&gt;위 결과에서 특히 확인할 것은 아래와 같습니다.&lt;/p&gt;
&lt;ul class=&quot;pgocmonitoring_list&quot; style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;duration 값이 비정상적으로 긴 세션이 있는지&lt;/li&gt;
&lt;li&gt;state가 active인지, idle in transaction인지&lt;/li&gt;
&lt;li&gt;wait_event_type과 wait_event가 무엇인지&lt;/li&gt;
&lt;li&gt;어떤 application_name으로 접속했는지&lt;/li&gt;
&lt;li&gt;어떤 SQL이 반복적으로 오래 수행되고 있는지&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 class=&quot;pgocmonitoring_h3&quot; data-ke-size=&quot;size23&quot;&gt;Lock 상태 상세 확인&lt;/h3&gt;
&lt;p class=&quot;pgocmonitoring_p&quot; data-ke-size=&quot;size16&quot;&gt;세션 상태만 보는 것으로 부족할 때는 pg_locks와 pg_stat_activity를 같이 조회하여 어떤 Lock 타입이 걸려 있는지, 실제로 granted 상태인지, 기다리는 중인지까지 확인할 수 있습니다.&lt;/p&gt;
&lt;div class=&quot;pgocmonitoring_codewrap&quot;&gt;
&lt;div class=&quot;pgocmonitoring_codelabel&quot;&gt;PostgreSQL &amp;middot; lock 상세 조회&lt;/div&gt;
&lt;pre class=&quot;pgocmonitoring_code pgsql&quot;&gt;&lt;code&gt;SELECT
    a.pid,
    a.usename,
    a.application_name,
    a.state,
    a.wait_event_type,
    a.wait_event,
    l.locktype,
    l.mode,
    l.granted,
    a.query
FROM pg_locks l
JOIN pg_stat_activity a
  ON l.pid = a.pid
ORDER BY a.pid, l.granted, l.locktype;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p class=&quot;pgocmonitoring_p&quot; data-ke-size=&quot;size16&quot;&gt;granted 값이 false인 경우는 해당 Lock을 아직 획득하지 못하고 대기 중이라는 의미입니다. 이 결과를 통해 단순히 느린 쿼리인지, 아니면 자원 대기 때문인지 구분하는 데 도움이 됩니다.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;pgocmonitoring_sec3&quot; class=&quot;pgocmonitoring_section&quot;&gt;
&lt;h2 class=&quot;pgocmonitoring_h2&quot; data-ke-size=&quot;size26&quot;&gt;Oracle에서 확인해야 하는 모니터링 포인트&lt;/h2&gt;
&lt;p class=&quot;pgocmonitoring_p&quot; data-ke-size=&quot;size16&quot;&gt;Oracle은 PostgreSQL과 유사한 문제를 다른 뷰를 통해 확인합니다. 대표적으로 V$SESSION, V$SQL, V$LOCK가 자주 사용됩니다. 현재 어떤 세션이 살아 있는지, 어떤 SQL을 수행 중인지, 어떤 세션이 다른 세션을 막고 있는지를 순서대로 보는 것이 일반적입니다.&lt;/p&gt;
&lt;h3 class=&quot;pgocmonitoring_h3&quot; data-ke-size=&quot;size23&quot;&gt;현재 세션과 실행 SQL 확인&lt;/h3&gt;
&lt;p class=&quot;pgocmonitoring_p&quot; data-ke-size=&quot;size16&quot;&gt;Oracle에서는 현재 접속 세션, 프로그램 이름, 접속 장비, SQL_ID 등을 함께 보는 것이 좋습니다. 이 정보가 있어야 실제 사용자 작업인지, 특정 인터페이스 프로그램인지, 배치 작업인지 구분할 수 있습니다.&lt;/p&gt;
&lt;div class=&quot;pgocmonitoring_codewrap&quot;&gt;
&lt;div class=&quot;pgocmonitoring_codelabel&quot;&gt;Oracle &amp;middot; session 및 SQL 확인&lt;/div&gt;
&lt;pre class=&quot;pgocmonitoring_code sql&quot;&gt;&lt;code&gt;SELECT
    s.sid,
    s.serial#,
    s.username,
    s.status,
    s.machine,
    s.program,
    s.sql_id,
    q.sql_text
FROM v$session s
LEFT JOIN v$sql q
  ON s.sql_id = q.sql_id
WHERE s.username IS NOT NULL
ORDER BY s.logon_time DESC;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p class=&quot;pgocmonitoring_p&quot; data-ke-size=&quot;size16&quot;&gt;결과를 볼 때는 아래 항목을 같이 확인하면 좋습니다.&lt;/p&gt;
&lt;ul class=&quot;pgocmonitoring_list&quot; style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;동일 machine 또는 program에서 세션이 과도하게 많은지&lt;/li&gt;
&lt;li&gt;같은 SQL_ID가 반복적으로 오래 남아 있는지&lt;/li&gt;
&lt;li&gt;특정 사용자나 특정 인터페이스에서만 문제가 집중되는지&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 class=&quot;pgocmonitoring_h3&quot; data-ke-size=&quot;size23&quot;&gt;대기 세션과 blocking session 확인&lt;/h3&gt;
&lt;p class=&quot;pgocmonitoring_p&quot; data-ke-size=&quot;size16&quot;&gt;Oracle에서는 blocking_session 컬럼을 통해 현재 어떤 세션이 다른 세션을 막고 있는지 확인할 수 있습니다. seconds_in_wait가 길다면 이미 사용자는 저장 지연이나 화면 멈춤을 체감하고 있을 가능성이 큽니다.&lt;/p&gt;
&lt;div class=&quot;pgocmonitoring_codewrap&quot;&gt;
&lt;div class=&quot;pgocmonitoring_codelabel&quot;&gt;Oracle &amp;middot; blocking session 확인&lt;/div&gt;
&lt;pre class=&quot;pgocmonitoring_code sql&quot;&gt;&lt;code&gt;SELECT
    sid,
    serial#,
    username,
    blocking_session,
    event,
    wait_class,
    seconds_in_wait
FROM v$session
WHERE blocking_session IS NOT NULL
ORDER BY seconds_in_wait DESC;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;pgocmonitoring_sec4&quot; class=&quot;pgocmonitoring_section&quot;&gt;
&lt;h2 class=&quot;pgocmonitoring_h2&quot; data-ke-size=&quot;size26&quot;&gt;PostgreSQL에서 Lock 확인과 해제 방법&lt;/h2&gt;
&lt;p class=&quot;pgocmonitoring_p&quot; data-ke-size=&quot;size16&quot;&gt;PostgreSQL에서 Lock 문제를 볼 때 핵심은 누가 기다리고 있는지가 아니라, 실제로 누가 Lock을 잡고 있는지를 찾는 것입니다. blocked 세션보다 blocking 세션이 원인인 경우가 대부분이기 때문입니다.&lt;/p&gt;
&lt;h3 class=&quot;pgocmonitoring_h3&quot; data-ke-size=&quot;size23&quot;&gt;현재 막히고 있는 세션 확인&lt;/h3&gt;
&lt;p class=&quot;pgocmonitoring_p&quot; data-ke-size=&quot;size16&quot;&gt;pg_blocking_pids() 함수는 특정 세션을 막고 있는 PID 목록을 반환합니다. 이를 이용하면 현재 대기 상태에 있는 세션을 빠르게 골라낼 수 있습니다.&lt;/p&gt;
&lt;div class=&quot;pgocmonitoring_codewrap&quot;&gt;
&lt;div class=&quot;pgocmonitoring_codelabel&quot;&gt;PostgreSQL &amp;middot; blocking PID 확인&lt;/div&gt;
&lt;pre class=&quot;pgocmonitoring_code pgsql&quot;&gt;&lt;code&gt;SELECT
    pid,
    usename,
    application_name,
    wait_event_type,
    wait_event,
    pg_blocking_pids(pid) AS blocking_pids,
    query
FROM pg_stat_activity
WHERE cardinality(pg_blocking_pids(pid)) &amp;gt; 0;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h3 class=&quot;pgocmonitoring_h3&quot; data-ke-size=&quot;size23&quot;&gt;blocked 세션과 blocking 세션을 함께 확인&lt;/h3&gt;
&lt;p class=&quot;pgocmonitoring_p&quot; data-ke-size=&quot;size16&quot;&gt;운영에서는 단순히 PID 하나만 보는 것보다, 누가 대기 중이고 누가 막고 있는지를 한 화면에서 같이 보는 것이 훨씬 편합니다. 아래 쿼리는 blocked 세션과 blocking 세션을 함께 보여주는 예시입니다.&lt;/p&gt;
&lt;div class=&quot;pgocmonitoring_codewrap&quot;&gt;
&lt;div class=&quot;pgocmonitoring_codelabel&quot;&gt;PostgreSQL &amp;middot; blocked / blocking 관계 확인&lt;/div&gt;
&lt;pre class=&quot;pgocmonitoring_code pgsql&quot;&gt;&lt;code&gt;SELECT
    blocked.pid AS blocked_pid,
    blocked.usename AS blocked_user,
    blocked.query AS blocked_query,
    blocking.pid AS blocking_pid,
    blocking.usename AS blocking_user,
    blocking.query AS blocking_query
FROM pg_stat_activity blocked
JOIN pg_stat_activity blocking
  ON blocking.pid = ANY(pg_blocking_pids(blocked.pid));&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p class=&quot;pgocmonitoring_p&quot; data-ke-size=&quot;size16&quot;&gt;이 결과를 보면 실제 원인이 되는 세션이 어떤 SQL을 수행 중인지 비교적 쉽게 파악할 수 있습니다. 저장 버튼이 안 눌리는 사용자 쪽 세션보다, 먼저 Lock을 잡고 오래 유지한 세션이 더 중요합니다.&lt;/p&gt;
&lt;h3 class=&quot;pgocmonitoring_h3&quot; data-ke-size=&quot;size23&quot;&gt;먼저 쿼리만 취소하는 방법&lt;/h3&gt;
&lt;p class=&quot;pgocmonitoring_p&quot; data-ke-size=&quot;size16&quot;&gt;PostgreSQL에서는 바로 세션을 죽이기 전에 현재 실행 중인 쿼리만 취소할 수 있습니다. 장시간 조회 SQL이나 단순히 오래 걸리는 작업이라면 이 방법을 먼저 검토하는 편이 안전합니다.&lt;/p&gt;
&lt;div class=&quot;pgocmonitoring_codewrap&quot;&gt;
&lt;div class=&quot;pgocmonitoring_codelabel&quot;&gt;PostgreSQL &amp;middot; 쿼리 취소&lt;/div&gt;
&lt;pre class=&quot;pgocmonitoring_code pgsql&quot;&gt;&lt;code&gt;SELECT pg_cancel_backend(12345);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p class=&quot;pgocmonitoring_p&quot; data-ke-size=&quot;size16&quot;&gt;위 예시에서 12345는 종료 대상 PID입니다. 이 방법은 현재 실행 중인 SQL만 취소하고 세션 자체는 유지합니다.&lt;/p&gt;
&lt;h3 class=&quot;pgocmonitoring_h3&quot; data-ke-size=&quot;size23&quot;&gt;세션 자체를 종료하는 방법&lt;/h3&gt;
&lt;p class=&quot;pgocmonitoring_p&quot; data-ke-size=&quot;size16&quot;&gt;Commit 누락, idle in transaction 상태 장기 유지, 비정상 세션 유지처럼 명확히 문제를 일으키는 세션이라면 세션 종료를 검토할 수 있습니다.&lt;/p&gt;
&lt;div class=&quot;pgocmonitoring_codewrap&quot;&gt;
&lt;div class=&quot;pgocmonitoring_codelabel&quot;&gt;PostgreSQL &amp;middot; 세션 종료&lt;/div&gt;
&lt;pre class=&quot;pgocmonitoring_code pgsql&quot;&gt;&lt;code&gt;SELECT pg_terminate_backend(12345);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div class=&quot;pgocmonitoring_tablewrap&quot;&gt;
&lt;table class=&quot;pgocmonitoring_table&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;조치 방법&lt;/th&gt;
&lt;th&gt;설명&lt;/th&gt;
&lt;th&gt;권장 상황&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;pg_cancel_backend&lt;/td&gt;
&lt;td&gt;실행 중인 쿼리만 취소합니다.&lt;/td&gt;
&lt;td&gt;장시간 조회, 일시적 지연, 취소 가능한 SQL&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;pg_terminate_backend&lt;/td&gt;
&lt;td&gt;세션 자체를 강제로 종료합니다.&lt;/td&gt;
&lt;td&gt;Commit 누락, 장기 Lock 점유, 비정상 세션&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class=&quot;pgocmonitoring_warn&quot;&gt;운영 환경에서는 세션 종료 전에 반드시 해당 세션이 어떤 사용자 작업인지, 어떤 프로그램에서 발생한 것인지, 종료했을 때 다른 후속 작업에 영향은 없는지 확인하는 것이 좋습니다.&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;pgocmonitoring_sec5&quot; class=&quot;pgocmonitoring_section&quot;&gt;
&lt;h2 class=&quot;pgocmonitoring_h2&quot; data-ke-size=&quot;size26&quot;&gt;Oracle에서 Lock 확인과 해제 방법&lt;/h2&gt;
&lt;p class=&quot;pgocmonitoring_p&quot; data-ke-size=&quot;size16&quot;&gt;Oracle에서도 접근 방식은 같습니다. 기다리는 세션보다 막고 있는 세션을 찾고, 해당 세션이 실제로 어떤 작업을 수행 중인지 확인한 뒤, 필요할 경우 세션 종료를 검토합니다.&lt;/p&gt;
&lt;h3 class=&quot;pgocmonitoring_h3&quot; data-ke-size=&quot;size23&quot;&gt;Lock 대기 세션 확인&lt;/h3&gt;
&lt;p class=&quot;pgocmonitoring_p&quot; data-ke-size=&quot;size16&quot;&gt;먼저 현재 대기 중인 세션을 확인합니다. blocking_session 값이 있다는 것은 현재 다른 세션 때문에 기다리고 있다는 의미입니다.&lt;/p&gt;
&lt;div class=&quot;pgocmonitoring_codewrap&quot;&gt;
&lt;div class=&quot;pgocmonitoring_codelabel&quot;&gt;Oracle &amp;middot; lock 대기 세션 확인&lt;/div&gt;
&lt;pre class=&quot;pgocmonitoring_code sql&quot;&gt;&lt;code&gt;SELECT
    sid,
    serial#,
    username,
    blocking_session,
    event,
    wait_class,
    seconds_in_wait
FROM v$session
WHERE blocking_session IS NOT NULL
ORDER BY seconds_in_wait DESC;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h3 class=&quot;pgocmonitoring_h3&quot; data-ke-size=&quot;size23&quot;&gt;Lock 보유 세션 상세 확인&lt;/h3&gt;
&lt;p class=&quot;pgocmonitoring_p&quot; data-ke-size=&quot;size16&quot;&gt;더 자세하게 보고 싶다면 V$LOCK와 V$SESSION을 조합하여 어떤 세션이 어떤 형태의 Lock을 오래 유지하고 있는지 확인할 수 있습니다. 이 단계에서는 단순히 기다리는 쪽이 아니라 실제 Lock을 보유한 쪽의 지속 시간과 상태를 확인하는 것이 중요합니다.&lt;/p&gt;
&lt;div class=&quot;pgocmonitoring_codewrap&quot;&gt;
&lt;div class=&quot;pgocmonitoring_codelabel&quot;&gt;Oracle &amp;middot; lock 보유 세션 상세 조회&lt;/div&gt;
&lt;pre class=&quot;pgocmonitoring_code pgsql&quot;&gt;&lt;code&gt;SELECT
    s.sid,
    s.serial#,
    s.username,
    l.type,
    l.id1,
    l.id2,
    l.lmode,
    l.request,
    l.ctime
FROM v$lock l
JOIN v$session s
  ON l.sid = s.sid
ORDER BY l.ctime DESC;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p class=&quot;pgocmonitoring_p&quot; data-ke-size=&quot;size16&quot;&gt;ctime 값은 해당 Lock이 얼마나 오래 유지되고 있는지 확인하는 데 도움이 됩니다. 동일 사용자나 동일 프로그램에서 지속적으로 오래 잡히는 패턴이 있다면 트랜잭션 구조 자체를 다시 점검할 필요가 있습니다.&lt;/p&gt;
&lt;h3 class=&quot;pgocmonitoring_h3&quot; data-ke-size=&quot;size23&quot;&gt;문제 세션 종료 방법&lt;/h3&gt;
&lt;p class=&quot;pgocmonitoring_p&quot; data-ke-size=&quot;size16&quot;&gt;Oracle에서는 일반적으로 문제 세션을 확인한 뒤 ALTER SYSTEM KILL SESSION 명령으로 종료를 수행합니다. 이때는 SID와 SERIAL 값을 함께 사용해야 합니다.&lt;/p&gt;
&lt;div class=&quot;pgocmonitoring_codewrap&quot;&gt;
&lt;div class=&quot;pgocmonitoring_codelabel&quot;&gt;Oracle &amp;middot; 세션 종료&lt;/div&gt;
&lt;pre class=&quot;pgocmonitoring_code routeros&quot;&gt;&lt;code&gt;ALTER SYSTEM KILL SESSION '123,4567';&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p class=&quot;pgocmonitoring_p&quot; data-ke-size=&quot;size16&quot;&gt;여기서 123은 SID이고 4567은 SERIAL 값입니다. 보통 V$SESSION 조회 결과를 바탕으로 실제 종료 대상을 결정합니다.&lt;/p&gt;
&lt;div class=&quot;pgocmonitoring_note&quot;&gt;Oracle은 kill 명령을 내려도 세션이 즉시 완전히 사라지지 않을 수 있습니다. 롤백이 진행 중이거나 내부 정리 작업이 남아 있는 경우에는 KILLED 상태로 일정 시간 유지될 수 있습니다.&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;pgocmonitoring_sec6&quot; class=&quot;pgocmonitoring_section&quot;&gt;
&lt;h2 class=&quot;pgocmonitoring_h2&quot; data-ke-size=&quot;size26&quot;&gt;운영 중 조치할 때 주의할 점&lt;/h2&gt;
&lt;p class=&quot;pgocmonitoring_p&quot; data-ke-size=&quot;size16&quot;&gt;Lock 문제를 푸는 것은 단순히 세션을 끊는 작업이 아닙니다. 왜 그 세션이 오래 살아 있었는지, 왜 Commit이 되지 않았는지, 왜 같은 시간대에 반복되는지를 함께 봐야 재발을 줄일 수 있습니다.&lt;/p&gt;
&lt;p class=&quot;pgocmonitoring_p&quot; data-ke-size=&quot;size16&quot;&gt;특히 운영 환경에서는 사용자의 실제 업무가 진행 중일 수 있고, 배치나 인터페이스와 연결된 세션일 수도 있기 때문에 조치 순서를 명확히 가져가는 것이 중요합니다.&lt;/p&gt;
&lt;ul class=&quot;pgocmonitoring_list&quot; style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;먼저 blocked 세션보다 blocking 세션을 정확히 찾습니다.&lt;/li&gt;
&lt;li&gt;해당 세션이 화면 작업인지, 배치인지, 인터페이스인지 구분합니다.&lt;/li&gt;
&lt;li&gt;PostgreSQL은 가능하면 cancel부터 검토하고, 필요 시 terminate로 넘어갑니다.&lt;/li&gt;
&lt;li&gt;Oracle은 kill 이후에도 롤백 및 정리 시간이 필요할 수 있다는 점을 고려합니다.&lt;/li&gt;
&lt;li&gt;반복되는 경우 SQL 구조, 인덱스, 트랜잭션 범위, Commit 시점을 점검해야 합니다.&lt;/li&gt;
&lt;li&gt;idle in transaction 상태가 자주 발생한다면 애플리케이션 예외 처리 흐름도 함께 확인해야 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;pgocmonitoring_warn&quot;&gt;가장 위험한 조치는 원인 파악 없이 세션을 무조건 종료하는 것입니다. 일시적으로 증상이 사라질 수는 있지만, 데이터 정합성 문제나 후속 장애를 더 크게 만들 수 있습니다.&lt;/div&gt;
&lt;h3 class=&quot;pgocmonitoring_h3&quot; data-ke-size=&quot;size23&quot;&gt;마무리&lt;/h3&gt;
&lt;p class=&quot;pgocmonitoring_p&quot; data-ke-size=&quot;size16&quot;&gt;PostgreSQL과 Oracle 모두 기본 제공 시스템 뷰만 잘 활용해도 현재 세션 상태, 장시간 실행 쿼리, Lock 대기 관계를 충분히 파악할 수 있습니다. 운영 환경에서는 장애가 발생한 뒤 당황해서 하나씩 찾기보다, 평소에 자주 보는 조회 SQL과 판단 기준을 정리해 두는 것이 훨씬 중요합니다.&lt;/p&gt;
&lt;p class=&quot;pgocmonitoring_p&quot; data-ke-size=&quot;size16&quot;&gt;결국 핵심은 단순합니다. 누가 살아 있는지 보고, 누가 막고 있는지 찾고, 어떤 조치가 가장 안전한지 판단하는 흐름을 익혀두는 것입니다. 이 흐름이 정리되어 있으면 DB 장애 대응 속도와 정확도는 확실히 달라집니다.&lt;/p&gt;
&lt;div class=&quot;pgocmonitoring_divider&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;h3 class=&quot;pgocmonitoring_h3&quot; data-ke-size=&quot;size23&quot;&gt;태그&lt;/h3&gt;
&lt;div class=&quot;pgocmonitoring_tags&quot;&gt;&lt;span class=&quot;pgocmonitoring_tag&quot;&gt;PostgreSQL&lt;/span&gt; &lt;span class=&quot;pgocmonitoring_tag&quot;&gt;Oracle&lt;/span&gt; &lt;span class=&quot;pgocmonitoring_tag&quot;&gt;DB모니터링&lt;/span&gt; &lt;span class=&quot;pgocmonitoring_tag&quot;&gt;DB Lock&lt;/span&gt; &lt;span class=&quot;pgocmonitoring_tag&quot;&gt;트랜잭션&lt;/span&gt; &lt;span class=&quot;pgocmonitoring_tag&quot;&gt;세션관리&lt;/span&gt; &lt;span class=&quot;pgocmonitoring_tag&quot;&gt;운영장애&lt;/span&gt; &lt;span class=&quot;pgocmonitoring_tag&quot;&gt;SQL운영&lt;/span&gt; &lt;span class=&quot;pgocmonitoring_tag&quot;&gt;개발자실무&lt;/span&gt; &lt;span class=&quot;pgocmonitoring_tag&quot;&gt;데이터베이스&lt;/span&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;/div&gt;</description>
      <category>DEVELOPMENT</category>
      <category>Database</category>
      <category>DB</category>
      <category>DBLOCK</category>
      <category>DB모니터링</category>
      <category>Oracle</category>
      <category>PostgreSQL</category>
      <category>개발</category>
      <category>데이터베이스모니터링</category>
      <category>데이터베이스운영</category>
      <category>트랜잭션관리</category>
      <author>간지뽕빨리턴님</author>
      <guid isPermaLink="true">https://odinbox.tistory.com/576</guid>
      <comments>https://odinbox.tistory.com/576#entry576comment</comments>
      <pubDate>Sun, 15 Mar 2026 19:09:09 +0900</pubDate>
    </item>
    <item>
      <title>갤럭시 버즈4 프로 리뷰, Hi-Fi 사운드, 초광대역 통화, Galaxy AI까지 직접 써본 후기</title>
      <link>https://odinbox.tistory.com/575</link>
      <description>&lt;div&gt;
&lt;style&gt;
:root{
  --samsungbuds_bg:#f5f8fc;
  --samsungbuds_surface:#ffffff;
  --samsungbuds_surface_alt:#f8fbff;
  --samsungbuds_text:#111827;
  --samsungbuds_text_soft:#4b5563;
  --samsungbuds_text_muted:#6b7280;
  --samsungbuds_line:#dbe5f0;
  --samsungbuds_line_soft:#e9eff7;
  --samsungbuds_brand:#0f172a;
  --samsungbuds_accent:#3559d8;
  --samsungbuds_accent_soft:#edf3ff;
  --samsungbuds_shadow:0 18px 40px rgba(15,23,42,.08);
  --samsungbuds_shadow_soft:0 10px 24px rgba(15,23,42,.05);
  --samsungbuds_radius_xl:30px;
  --samsungbuds_radius_lg:22px;
  --samsungbuds_radius_md:16px;
  --samsungbuds_radius_sm:12px;
  --samsungbuds_maxw:980px;
  --samsungbuds_font:-apple-system,BlinkMacSystemFont,&quot;Segoe UI&quot;,&quot;Apple SD Gothic Neo&quot;,&quot;Malgun Gothic&quot;,&quot;Noto Sans KR&quot;,sans-serif;
}

.samsungbuds_wrap,
.samsungbuds_wrap *{
  box-sizing:border-box;
}

.samsungbuds_wrap{
  max-width:var(--samsungbuds_maxw);
  margin:0 auto;
  padding:28px 18px 70px;
  color:var(--samsungbuds_text);
  font-family:var(--samsungbuds_font);
  line-height:1.84;
  word-break:keep-all;
  background:linear-gradient(180deg,#f5f8fc 0%,#ffffff 18%,#f7fafe 100%);
}

.samsungbuds_wrap img{
  display:block;
  max-width:100%;
  height:auto;
  border-radius:18px;
}

.samsungbuds_hero{
  position:relative;
  overflow:hidden;
  margin-bottom:28px;
  padding:34px 26px 30px;
  border:1px solid #d8e3f1;
  border-radius:32px;
  background:
    radial-gradient(circle at top right, rgba(53,89,216,.12) 0, rgba(53,89,216,0) 34%),
    radial-gradient(circle at bottom left, rgba(83,110,255,.08) 0, rgba(83,110,255,0) 28%),
    linear-gradient(135deg,#fbfdff 0%,#ffffff 56%,#eef4ff 100%);
  box-shadow:var(--samsungbuds_shadow);
}

.samsungbuds_hero_badges{
  display:flex;
  flex-wrap:wrap;
  gap:8px;
  margin-bottom:16px;
}

.samsungbuds_badge{
  display:inline-flex;
  align-items:center;
  padding:6px 12px;
  border:1px solid #d9e4f4;
  border-radius:999px;
  background:rgba(255,255,255,.92);
  color:#2641a8;
  font-size:12px;
  font-weight:700;
  letter-spacing:.02em;
}

.samsungbuds_title{
  margin:0 0 14px;
  font-size:34px;
  line-height:1.28;
  letter-spacing:-0.03em;
  color:var(--samsungbuds_brand);
  font-weight:900;
}

.samsungbuds_subtitle{
  margin:0;
  font-size:16px;
  color:var(--samsungbuds_text_soft);
}

.samsungbuds_meta{
  display:flex;
  flex-wrap:wrap;
  gap:10px 18px;
  margin-top:18px;
  padding-top:16px;
  border-top:1px solid rgba(148,163,184,.22);
  color:var(--samsungbuds_text_muted);
  font-size:13px;
}

.samsungbuds_lead{
  margin:0 0 30px;
  padding:22px 22px 24px;
  border:1px solid #dde7f3;
  border-radius:22px;
  background:#fff;
  box-shadow:var(--samsungbuds_shadow_soft);
}

.samsungbuds_lead p{
  margin:0;
  font-size:17px;
  color:#1f2937;
}

.samsungbuds_toc{
  margin:0 0 32px;
  padding:24px;
  border:1px solid var(--samsungbuds_line);
  border-radius:24px;
  background:linear-gradient(180deg,#ffffff 0%,#f8fbff 100%);
}

.samsungbuds_toc_title{
  margin:0 0 14px;
  font-size:16px;
  font-weight:800;
  color:var(--samsungbuds_brand);
}

.samsungbuds_toc_list{
  margin:0;
  padding:0;
  list-style:none;
  display:grid;
  grid-template-columns:repeat(2,minmax(0,1fr));
  gap:10px 14px;
}

.samsungbuds_toc_list li{
  margin:0;
}

.samsungbuds_toc_list a{
  display:block;
  padding:11px 13px;
  border:1px solid #e5edf7;
  border-radius:12px;
  background:#fff;
  text-decoration:none;
  color:#1f2937;
  font-size:14px;
  transition:all .2s ease;
}

.samsungbuds_toc_list a:hover{
  background:#f4f8ff;
  border-color:#cedcf7;
}

.samsungbuds_section{
  margin:0 0 28px;
  padding:28px 24px;
  border:1px solid var(--samsungbuds_line);
  border-radius:26px;
  background:var(--samsungbuds_surface);
  box-shadow:var(--samsungbuds_shadow_soft);
}

.samsungbuds_section_title{
  margin:0 0 18px;
  font-size:28px;
  line-height:1.35;
  letter-spacing:-0.025em;
  color:var(--samsungbuds_brand);
  font-weight:900;
}

.samsungbuds_section p{
  margin:0 0 16px;
  color:#1f2937;
  font-size:16px;
}

.samsungbuds_section p:last-child{
  margin-bottom:0;
}

.samsungbuds_photo_grid{
  display:grid;
  grid-template-columns:repeat(2,minmax(0,1fr));
  gap:16px;
  margin:18px 0 20px;
}

.samsungbuds_photo_item{
  margin:0;
}

.samsungbuds_photo_item p{
  margin:0 !important;
}

.samsungbuds_single_photo{
  margin:18px 0 20px;
}

.samsungbuds_caption{
  margin-top:10px;
  padding:10px 12px;
  border:1px solid var(--samsungbuds_line_soft);
  border-radius:12px;
  background:#f8fafc;
  font-size:13px;
  color:#5b6578;
}

.samsungbuds_quote{
  margin:22px 0;
  padding:22px 22px 22px 24px;
  border-left:5px solid var(--samsungbuds_accent);
  border-radius:18px;
  background:linear-gradient(180deg,#f8fbff 0%,#eef4ff 100%);
}

.samsungbuds_quote p{
  margin:0;
  font-size:18px;
  font-weight:800;
  line-height:1.65;
  color:#0f172a;
}

.samsungbuds_split{
  display:grid;
  grid-template-columns:1.15fr .85fr;
  gap:18px;
  margin:18px 0 8px;
}

.samsungbuds_card{
  padding:20px 18px;
  border:1px solid var(--samsungbuds_line);
  border-radius:18px;
  background:var(--samsungbuds_surface_alt);
}

.samsungbuds_card h4{
  margin:0 0 10px;
  font-size:17px;
  color:var(--samsungbuds_brand);
  font-weight:800;
}

.samsungbuds_card p{
  margin:0;
  font-size:15px;
  color:var(--samsungbuds_text_soft);
}

.samsungbuds_keypoints{
  display:grid;
  gap:10px;
  margin:18px 0 0;
  padding:0;
  list-style:none;
}

.samsungbuds_keypoints li{
  position:relative;
  margin:0;
  padding:12px 14px 12px 40px;
  border:1px solid #e4ebf5;
  border-radius:14px;
  background:#fff;
  color:#1f2937;
  font-size:15px;
}

.samsungbuds_keypoints li:before{
  content:&quot;✓&quot;;
  position:absolute;
  left:14px;
  top:10px;
  display:flex;
  align-items:center;
  justify-content:center;
  width:18px;
  height:18px;
  border-radius:999px;
  background:#e9f1ff;
  color:#1d4ed8;
  font-size:12px;
  font-weight:900;
}

.samsungbuds_table_wrap{
  margin:18px 0 0;
  overflow-x:auto;
  border:1px solid var(--samsungbuds_line);
  border-radius:18px;
  background:#fff;
}

table.samsungbuds_table{
  width:100%;
  min-width:760px;
  border-collapse:collapse;
  font-size:14px;
}

table.samsungbuds_table thead th{
  padding:14px;
  background:#0f172a;
  color:#fff;
  text-align:left;
  font-weight:800;
  vertical-align:top;
  border-right:1px solid rgba(255,255,255,.12);
}

table.samsungbuds_table tbody td{
  padding:14px;
  border-top:1px solid #e5ebf3;
  border-right:1px solid #eef3f8;
  color:#1f2937;
  vertical-align:top;
  line-height:1.7;
}

table.samsungbuds_table tbody tr:nth-child(even){
  background:#f9fbfe;
}

table.samsungbuds_table th:last-child,
table.samsungbuds_table td:last-child{
  border-right:none;
}

.samsungbuds_note{
  margin-top:14px;
  padding:15px 16px;
  border:1px solid #f3dfb4;
  border-radius:14px;
  background:#fff8eb;
  color:#7c5a10;
  font-size:14px;
}

.samsungbuds_summary{
  margin-top:12px;
  padding:24px 22px;
  border:1px solid #d7e4f6;
  border-radius:22px;
  background:
    radial-gradient(circle at right top, rgba(37,99,235,.09) 0, rgba(37,99,235,0) 28%),
    linear-gradient(180deg,#ffffff 0%,#f5f9ff 100%);
}

.samsungbuds_summary h3{
  margin:0 0 12px;
  font-size:22px;
  color:var(--samsungbuds_brand);
  font-weight:900;
}

.samsungbuds_summary p{
  margin:0 0 12px;
}

.samsungbuds_summary p:last-child{
  margin-bottom:0;
}

.samsungbuds_tags{
  margin-top:26px;
  padding:20px 22px;
  border:1px solid var(--samsungbuds_line);
  border-radius:20px;
  background:#fff;
}

.samsungbuds_tags_title{
  margin:0 0 12px;
  font-size:15px;
  font-weight:800;
  color:var(--samsungbuds_brand);
}

.samsungbuds_tag_list{
  display:flex;
  flex-wrap:wrap;
  gap:8px;
}

.samsungbuds_tag{
  display:inline-flex;
  align-items:center;
  padding:8px 12px;
  border:1px solid #dde7f4;
  border-radius:999px;
  background:#f1f5fb;
  color:#334155;
  font-size:13px;
  font-weight:700;
}

.samsungbuds_footer{
  margin-top:28px;
  padding:22px 20px;
  text-align:center;
  color:#64748b;
  font-size:13px;
}

@media (max-width:900px){
  .samsungbuds_split{
    grid-template-columns:1fr;
  }
  .samsungbuds_toc_list,
  .samsungbuds_photo_grid{
    grid-template-columns:1fr;
  }
}

@media (max-width:720px){
  .samsungbuds_wrap{
    padding:18px 12px 54px;
  }
  .samsungbuds_hero{
    padding:24px 18px 20px;
    border-radius:24px;
  }
  .samsungbuds_title{
    font-size:26px;
  }
  .samsungbuds_section{
    padding:22px 16px;
    border-radius:20px;
  }
  .samsungbuds_section_title{
    font-size:22px;
  }
}
&lt;/style&gt;
&lt;/div&gt;
&lt;div id=&quot;samsungbuds_wrap&quot; class=&quot;samsungbuds_wrap&quot;&gt;
&lt;section class=&quot;samsungbuds_hero&quot;&gt;
&lt;div class=&quot;samsungbuds_hero_badges&quot;&gt;&lt;br /&gt;&lt;span class=&quot;samsungbuds_badge&quot;&gt;프리미엄 무선이어폰 리뷰&lt;/span&gt;&lt;/div&gt;
&lt;h1 class=&quot;samsungbuds_title&quot;&gt;갤럭시 버즈4 프로 리뷰 : Hi-Fi 사운드, 초광대역 통화, Galaxy AI까지 직접 써본 후기&lt;/h1&gt;
&lt;p class=&quot;samsungbuds_subtitle&quot; data-ke-size=&quot;size16&quot;&gt;갤럭시 버즈4 프로를 직접 개봉하고 사용해보며 디자인, 음질, 통화 품질, 착용감, Galaxy AI 경험까지 정리한 이벤트 참여형 실사용 리뷰입니다.&lt;/p&gt;
&lt;div class=&quot;samsungbuds_meta&quot;&gt;&lt;span&gt;&lt;br /&gt;&lt;/span&gt; &lt;span&gt;키워드 : 갤럭시 버즈4 프로 리뷰, 음질, 통화 품질, Galaxy AI, 착용감&lt;/span&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;div class=&quot;samsungbuds_single_photo&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;글 상단 부분 대표 이미지.png&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pnkEE/dJMcachZdEJ/ku98SLC61mCfWd7w0vkUX1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pnkEE/dJMcachZdEJ/ku98SLC61mCfWd7w0vkUX1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pnkEE/dJMcachZdEJ/ku98SLC61mCfWd7w0vkUX1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpnkEE%2FdJMcachZdEJ%2Fku98SLC61mCfWd7w0vkUX1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;400&quot; data-filename=&quot;글 상단 부분 대표 이미지.png&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;section class=&quot;samsungbuds_lead&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 포스팅은 삼성전자 갤럭시 버즈4 | 버즈4 프로 리뷰어 이벤트 참여를 계기로 작성한 사용 후기입니다. 무선이어폰은 이제 단순히 음악만 듣는 제품이 아니라, 통화와 이동 중 제어, AI 기능 활용, 장시간 착용감까지 함께 봐야 하는 시대가 되었습니다. 그래서 이번에는 단순 스펙 나열보다 실제로 얼마나 자주 손이 가는지, 그리고 일상 속에서 어떤 부분이 좋게 느껴졌는지를 중심으로 정리해보았습니다. 결론부터 말하면, 보기보다 더 야무진 제품이었습니다.&lt;/p&gt;
&lt;/section&gt;
&lt;section class=&quot;samsungbuds_toc&quot;&gt;
&lt;h3 class=&quot;samsungbuds_toc_title&quot; data-ke-size=&quot;size23&quot;&gt;목차&lt;/h3&gt;
&lt;ul class=&quot;samsungbuds_toc_list&quot; style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;#samsungbuds_intro&quot;&gt;갤럭시 버즈4 프로를 기대한 이유&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#samsungbuds_sec1&quot;&gt;개봉기와 패키지 구성&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#samsungbuds_sec2&quot;&gt;디자인과 외관 디테일&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#samsungbuds_sec3&quot;&gt;케이스 구조와 충전 편의성&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#samsungbuds_sec4&quot;&gt;Hi-Fi 사운드 사용 후기&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#samsungbuds_sec5&quot;&gt;초광대역 통화와 Galaxy AI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#samsungbuds_sec6&quot;&gt;착용감과 이벤트 참여 관점 총평&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#samsungbuds_outro&quot;&gt;추천 포인트 정리&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;section id=&quot;samsungbuds_intro&quot; class=&quot;samsungbuds_section&quot;&gt;
&lt;h2 class=&quot;samsungbuds_section_title&quot; data-ke-size=&quot;size26&quot;&gt;갤럭시 버즈4 프로를 기대한 이유&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;갤럭시 버즈4 프로는 단순히 &amp;ldquo;새로 나온 삼성 무선이어폰&amp;rdquo; 정도로 끝나는 제품이 아니라, 실제 사용 기준에서 음질과 통화 품질, Galaxy AI 활용성, 그리고 착용감까지 두루 기대하게 만드는 제품이었습니다. 특히 이번 리뷰어 미션에서도 Hi-Fi 사운드, 초광대역 통화, AI 기능, 착용감이 핵심 포인트로 제시된 만큼, 단순한 첫인상보다 실사용 중심으로 보는 게 더 중요하다고 생각했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설명 : 무선이어폰은 결국 스펙표보다 &amp;lsquo;하루 동안 몇 번이나 자연스럽게 손이 가는가&amp;rsquo;가 더 중요합니다. 그런 의미에서 갤럭시 버즈4 프로는 꽤 기대를 갖고 보게 되는 제품이었습니다.&lt;/p&gt;
&lt;div class=&quot;samsungbuds_quote&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;ldquo;사진으로 예뻐 보이는 제품&amp;rdquo;과 &amp;ldquo;실제로 자주 쓰게 되는 제품&amp;rdquo;은 다를 때가 많은데, 이번에는 둘 다 어느 정도 챙긴 느낌이었습니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;samsungbuds_sec1&quot; class=&quot;samsungbuds_section&quot;&gt;
&lt;h2 class=&quot;samsungbuds_section_title&quot; data-ke-size=&quot;size26&quot;&gt;개봉기와 패키지 구성&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 개봉 단계에서는 제품 박스부터 구성품, 본체 첫인상까지 차근차근 살펴보았습니다. 패키지는 전체적으로 군더더기 없이 정리된 느낌이었고, 플래그십 라인업답게 깔끔하고 단정한 인상이 강했습니다. 과장된 화려함보다는, 실제 제품 자체에 집중하게 만드는 방향이었습니다.&lt;/p&gt;
&lt;div class=&quot;samsungbuds_photo_grid&quot;&gt;
&lt;div class=&quot;samsungbuds_photo_item&quot;&gt;
&lt;div class=&quot;samsungbuds_caption&quot;&gt;버즈4 프로 개봉 직후 모습 : 처음 상자를 열었을 때 보이는 제품 배치와 전반적인 첫인상을 확인할 수 있습니다.&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;samsungbuds_photo_item&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/HcVfh/dJMcagLsVRv/V61QPF7yoh5xyL1ynSwfh1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/HcVfh/dJMcagLsVRv/V61QPF7yoh5xyL1ynSwfh1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/HcVfh/dJMcagLsVRv/V61QPF7yoh5xyL1ynSwfh1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHcVfh%2FdJMcagLsVRv%2FV61QPF7yoh5xyL1ynSwfh1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;div class=&quot;samsungbuds_caption&quot;&gt;제품 박스 뒷면 : 주요 정보와 패키지 구성을 확인할 수 있는 뒷면 사진입니다.&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;samsungbuds_photo_grid&quot;&gt;
&lt;div class=&quot;samsungbuds_photo_item&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/t1htS/dJMcagSd3wQ/NMbW4VlwcoKPn0auHqs6M1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/t1htS/dJMcagSd3wQ/NMbW4VlwcoKPn0auHqs6M1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/t1htS/dJMcagSd3wQ/NMbW4VlwcoKPn0auHqs6M1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Ft1htS%2FdJMcagSd3wQ%2FNMbW4VlwcoKPn0auHqs6M1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;div class=&quot;samsungbuds_caption&quot;&gt;제품 옆면 1 : 패키지의 측면 구성과 박스 외형을 확인할 수 있습니다.&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;samsungbuds_photo_item&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bLml81/dJMcadVrIJ5/hM4HMUyQKn0951B7ytkGu0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bLml81/dJMcadVrIJ5/hM4HMUyQKn0951B7ytkGu0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bLml81/dJMcadVrIJ5/hM4HMUyQKn0951B7ytkGu0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbLml81%2FdJMcadVrIJ5%2FhM4HMUyQKn0951B7ytkGu0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;div class=&quot;samsungbuds_caption&quot;&gt;제품 옆면 2 : 박스 측면 디테일을 보다 자세히 볼 수 있는 사진입니다.&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;samsungbuds_photo_grid&quot;&gt;
&lt;div class=&quot;samsungbuds_photo_item&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ce4J6L/dJMcagLsVFL/VtcsZFSKJYHi2ji1pNfIiK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ce4J6L/dJMcagLsVFL/VtcsZFSKJYHi2ji1pNfIiK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ce4J6L/dJMcagLsVFL/VtcsZFSKJYHi2ji1pNfIiK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fce4J6L%2FdJMcagLsVFL%2FVtcsZFSKJYHi2ji1pNfIiK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;div class=&quot;samsungbuds_caption&quot;&gt;제품 옆면 3 : 패키지 외형을 마저 확인할 수 있는 마지막 측면 컷입니다.&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;samsungbuds_photo_item&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ZhG1R/dJMcaiibC9h/wTv7R7wqNmzEmgL2cCN9W0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ZhG1R/dJMcaiibC9h/wTv7R7wqNmzEmgL2cCN9W0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ZhG1R/dJMcaiibC9h/wTv7R7wqNmzEmgL2cCN9W0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FZhG1R%2FdJMcaiibC9h%2FwTv7R7wqNmzEmgL2cCN9W0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;div class=&quot;samsungbuds_caption&quot;&gt;구성품 사진 1 : 이어팁, 설명서, 본체까지 전체 구성품을 한눈에 볼 수 있습니다.&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;samsungbuds_single_photo&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b9Wre0/dJMcaiibC9k/8vWm7Pc8QrazhEe2YZNBjK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b9Wre0/dJMcaiibC9k/8vWm7Pc8QrazhEe2YZNBjK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b9Wre0/dJMcaiibC9k/8vWm7Pc8QrazhEe2YZNBjK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb9Wre0%2FdJMcaiibC9k%2F8vWm7Pc8QrazhEe2YZNBjK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;div class=&quot;samsungbuds_caption&quot;&gt;구성품 사진 2 : 이어팁, 설명서, 본체 구성을 다른 각도에서 확인할 수 있는 사진입니다.&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구성품은 필요한 요소만 간결하게 들어 있어 깔끔했습니다. 이어팁과 설명서, 본체 중심으로 정리되어 있었고, 개봉 직후의 인상도 과하게 요란하기보다는 잘 정돈된 느낌이 강했습니다. 솔직히 개봉할 때만큼은 누구나 잠깐 리뷰어가 되는데, 이 제품은 그 순간의 만족감이 꽤 괜찮았습니다.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;samsungbuds_sec2&quot; class=&quot;samsungbuds_section&quot;&gt;
&lt;h2 class=&quot;samsungbuds_section_title&quot; data-ke-size=&quot;size26&quot;&gt;디자인과 외관 디테일&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제품 외관은 실제로 손에 쥐고 봤을 때 더 괜찮게 느껴졌습니다. 특히 케이스와 이어버드 본체의 디테일, 마감, 로고 처리 같은 부분이 사진보다 실물에서 더 자연스럽게 다가왔습니다. 이런 요소는 화려하게 튀지는 않지만, 오래 볼수록 잘 정리되었다는 인상을 남깁니다.&lt;/p&gt;
&lt;div class=&quot;samsungbuds_photo_grid&quot;&gt;
&lt;div class=&quot;samsungbuds_photo_item&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/CrqyH/dJMcagLsVRx/eK7ZzMv5hHqL06Hn6JIhn0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/CrqyH/dJMcagLsVRx/eK7ZzMv5hHqL06Hn6JIhn0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/CrqyH/dJMcagLsVRx/eK7ZzMv5hHqL06Hn6JIhn0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCrqyH%2FdJMcagLsVRx%2FeK7ZzMv5hHqL06Hn6JIhn0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;div class=&quot;samsungbuds_caption&quot;&gt;제품 정면 : 버즈4 프로 케이스의 정면 디자인과 전체적인 인상을 볼 수 있습니다.&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;samsungbuds_photo_item&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1689&quot; data-origin-height=&quot;3000&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bVn6LK/dJMcagLsVFG/wckvhg102Lw7NbZTiSoh5K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bVn6LK/dJMcagLsVFG/wckvhg102Lw7NbZTiSoh5K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bVn6LK/dJMcagLsVFG/wckvhg102Lw7NbZTiSoh5K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbVn6LK%2FdJMcagLsVFG%2Fwckvhg102Lw7NbZTiSoh5K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1689&quot; height=&quot;3000&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1689&quot; data-origin-height=&quot;3000&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;div class=&quot;samsungbuds_caption&quot;&gt;이어폰 자세히 보기 : 이어버드 본체의 형태와 디테일을 가까이서 확인할 수 있는 사진입니다.&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;samsungbuds_photo_grid&quot;&gt;
&lt;div class=&quot;samsungbuds_photo_item&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bdbJKY/dJMcagLsVFH/ODXSy0tVXAgT8O7zzwg4Z0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bdbJKY/dJMcagLsVFH/ODXSy0tVXAgT8O7zzwg4Z0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bdbJKY/dJMcagLsVFH/ODXSy0tVXAgT8O7zzwg4Z0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbdbJKY%2FdJMcagLsVFH%2FODXSy0tVXAgT8O7zzwg4Z0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;div class=&quot;samsungbuds_caption&quot;&gt;충전 타입 사진 : USB-C 타입 포트를 확인할 수 있는 사진입니다.&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;samsungbuds_photo_item&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/6zOsc/dJMcagSd3wJ/ZjzG7MMrRCjaUzIXuKCcLK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/6zOsc/dJMcagSd3wJ/ZjzG7MMrRCjaUzIXuKCcLK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/6zOsc/dJMcagSd3wJ/ZjzG7MMrRCjaUzIXuKCcLK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F6zOsc%2FdJMcagSd3wJ%2FZjzG7MMrRCjaUzIXuKCcLK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;div class=&quot;samsungbuds_caption&quot;&gt;충전 타입 반대편 : 반대편 삼성 로고가 보이는 외관 컷입니다.&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제로 보면서 좋았던 부분은 과한 장식 없이 제품 자체의 디테일로 승부한다는 느낌이 있다는 점이었습니다. 설명 : USB-C 포트 같은 실사용 요소도 깔끔하게 정리되어 있고, 케이스 외관 역시 어느 방향에서 봐도 무난하게 잘 떨어지는 편입니다. 괜히 책상 위에 올려두고 한 번 더 보게 되는 타입이라고 하면 느낌이 좀 전달될 것 같습니다.&lt;/p&gt;
&lt;ul class=&quot;samsungbuds_keypoints&quot; style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;실물 기준으로 깔끔하고 정돈된 디자인 인상&lt;/li&gt;
&lt;li&gt;케이스 정면과 이어버드 디테일이 자연스럽게 잘 드러남&lt;/li&gt;
&lt;li&gt;USB-C 타입 채택으로 충전 편의성 확보&lt;/li&gt;
&lt;li&gt;삼성 로고와 외관 디테일이 과하지 않으면서 깔끔함&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;section id=&quot;samsungbuds_sec3&quot; class=&quot;samsungbuds_section&quot;&gt;
&lt;h2 class=&quot;samsungbuds_section_title&quot; data-ke-size=&quot;size26&quot;&gt;케이스 구조와 충전 편의성&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;케이스를 열고 닫는 흐름, 이어버드를 꺼내고 다시 넣는 과정, 충전 상태를 확인하는 방식은 생각보다 자주 반복되는 동작입니다. 그래서 이런 부분이 불편하면 사소해 보여도 만족도에 꽤 영향을 줍니다. 갤럭시 버즈4 프로는 실제로 케이스를 다루는 과정이 비교적 직관적인 편이었습니다.&lt;/p&gt;
&lt;div class=&quot;samsungbuds_photo_grid&quot;&gt;
&lt;div class=&quot;samsungbuds_photo_item&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cMeiTt/dJMcaiibC9b/hrTcwGPiG06Z7KeeYFFMv1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cMeiTt/dJMcaiibC9b/hrTcwGPiG06Z7KeeYFFMv1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cMeiTt/dJMcaiibC9b/hrTcwGPiG06Z7KeeYFFMv1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcMeiTt%2FdJMcaiibC9b%2FhrTcwGPiG06Z7KeeYFFMv1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;div class=&quot;samsungbuds_caption&quot;&gt;본체에서 이어폰을 모두 꺼낸 뒤 사진 : 케이스 내부 구조를 확인할 수 있는 컷입니다.&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;samsungbuds_photo_item&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Nb7Ma/dJMcagLsVFI/nxGqWlAP7kPgg43f64jWb1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Nb7Ma/dJMcagLsVFI/nxGqWlAP7kPgg43f64jWb1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Nb7Ma/dJMcagLsVFI/nxGqWlAP7kPgg43f64jWb1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNb7Ma%2FdJMcagLsVFI%2FnxGqWlAP7kPgg43f64jWb1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;div class=&quot;samsungbuds_caption&quot;&gt;충전 중인 버즈4 프로 : 이어버드가 케이스 안에서 충전되는 모습을 확인할 수 있습니다.&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설명 : 이런 사진은 실제 리뷰에서 꽤 중요합니다. 왜냐하면 제품을 살 때 사람들은 예쁜 홍보 이미지보다 &amp;ldquo;진짜 손으로 쓰면 어떤 느낌인지&amp;rdquo;가 궁금하기 때문입니다. 케이스 내부 구조나 충전 상태를 보여주는 컷이 있으면 글의 신뢰감도 확실히 올라갑니다.&lt;/p&gt;
&lt;div class=&quot;samsungbuds_quote&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제품 사진을 찍다 보면 어느 순간 &amp;lsquo;내가 지금 리뷰를 쓰는 건지, 제품 사진작가가 된 건지&amp;rsquo; 헷갈릴 때가 있는데, 케이스 내부 컷은 그만큼 실제 사용 느낌을 잘 보여주는 사진입니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;samsungbuds_sec4&quot; class=&quot;samsungbuds_section&quot;&gt;
&lt;h2 class=&quot;samsungbuds_section_title&quot; data-ke-size=&quot;size26&quot;&gt;Hi-Fi 사운드 사용 후기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;갤럭시 버즈4 프로를 사용하면서 가장 먼저 체크한 부분은 역시 음질이었습니다. 다양한 장르의 음악을 들어보니 전반적으로 보컬과 배경 사운드가 비교적 선명하게 분리되어 들렸고, 저음도 과하게 부풀기보다는 안정적으로 받쳐주는 인상이 있었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히 평소 자주 듣던 음악을 다시 틀어보면 작은 차이가 더 잘 느껴집니다. 익숙한 곡일수록 &amp;lsquo;어, 이 부분이 좀 더 또렷하네&amp;rsquo; 같은 순간이 잘 보이는데, 갤럭시 버즈4 프로는 그런 포인트가 은근히 있었습니다. 처음부터 과하게 화려한 소리라기보다는, 들을수록 밸런스가 괜찮다는 쪽에 가까웠습니다.&lt;/p&gt;
&lt;div class=&quot;samsungbuds_split&quot;&gt;
&lt;div class=&quot;samsungbuds_card&quot;&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;실사용 체감&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;출퇴근길이나 실내 집중 시간처럼 비교적 긴 시간 음악을 들을 때 전체 음색이 안정적으로 유지되어 피로감이 덜한 편이었습니다.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;samsungbuds_card&quot;&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;한 줄 정리&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설명 : 하이파이 사운드를 너무 과장하지 않으면서도, 기존보다 더 정리된 느낌이라는 점은 충분히 체감할 수 있었습니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul class=&quot;samsungbuds_keypoints&quot; style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;보컬과 배경 사운드가 비교적 또렷하게 구분되는 인상&lt;/li&gt;
&lt;li&gt;저음이 과도하게 번지지 않고 안정적으로 받쳐주는 편&lt;/li&gt;
&lt;li&gt;오래 들어도 피로감이 심하지 않은 밸런스형 사운드&lt;/li&gt;
&lt;li&gt;갤럭시 버즈4 프로 음질 후기를 쓰기 좋은 분명한 포인트가 있었음&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;section id=&quot;samsungbuds_sec5&quot; class=&quot;samsungbuds_section&quot;&gt;
&lt;h2 class=&quot;samsungbuds_section_title&quot; data-ke-size=&quot;size26&quot;&gt;초광대역 통화와 Galaxy AI&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;무선이어폰은 이제 음악만 듣는 기기가 아니기 때문에, 통화 품질과 보조 기능의 완성도가 점점 더 중요해지고 있습니다. 갤럭시 버즈4 프로는 실제로 실내는 물론 외부 소음이 어느 정도 있는 환경에서도 비교적 안정적인 통화 경험을 보여주었습니다. 상대방 목소리도 답답하지 않았고, 제 목소리 전달 역시 무난하게 이어졌습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 이번에 꽤 흥미로웠던 부분은 Galaxy AI와 연결되는 흐름이었습니다. 이어버드가 단순한 오디오 액세서리를 넘어, 스마트폰과 함께 움직이는 인터페이스처럼 느껴지는 순간들이 있었습니다. 손이 자유롭지 않은 상황에서 빠르게 반응할 수 있다는 점은 실제로 써보면 생각보다 편리합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설명 : 통화 품질은 조용한 방 안보다 바깥에서 더 체감되고, AI 기능은 눌러서 써보기 전보다 익숙해진 뒤가 더 편해지는 법인데, 이번에는 둘 다 실사용에서 꽤 인상이 좋았습니다.&lt;/p&gt;
&lt;div class=&quot;samsungbuds_quote&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상대방이 &amp;ldquo;밖이야?&amp;rdquo;보다 &amp;ldquo;목소리 괜찮네&amp;rdquo;라고 말해주면 그 통화 품질은 일단 합격이라고 생각합니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;samsungbuds_sec6&quot; class=&quot;samsungbuds_section&quot;&gt;
&lt;h2 class=&quot;samsungbuds_section_title&quot; data-ke-size=&quot;size26&quot;&gt;착용감과 이벤트 참여 관점 총평&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아무리 음질과 기능이 좋아도 착용감이 불편하면 결국 자주 쓰지 않게 됩니다. 그래서 개인적으로는 착용 안정감과 귀에 부담이 적은지를 꽤 중요하게 보는데, 갤럭시 버즈4 프로는 장시간 착용했을 때도 비교적 편안한 편이었습니다. 이동 중이나 가벼운 활동 중에도 크게 불안정하다는 느낌 없이 사용할 수 있었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 삼성전자 이벤트 참여 관점에서 봐도 포인트가 분명했습니다. Hi-Fi 사운드는 음악 감상 경험을, 초광대역 통화는 실용성을, Galaxy AI는 차별화 포인트를, 착용감은 실제 만족도를 설명하기에 좋았습니다. 즉, 억지로 포인트를 만들어내지 않아도 리뷰할 요소가 자연스럽게 나온다는 점이 장점이었습니다.&lt;/p&gt;
&lt;div class=&quot;samsungbuds_table_wrap&quot;&gt;
&lt;table class=&quot;samsungbuds_table&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;항목&lt;/th&gt;
&lt;th&gt;체감 포인트&lt;/th&gt;
&lt;th&gt;이벤트 포스팅 활용 포인트&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Hi-Fi 사운드&lt;/td&gt;
&lt;td&gt;익숙한 음악이 더 정리되고 또렷하게 들리는 인상&lt;/td&gt;
&lt;td&gt;음질 후기와 음악 감상 중심 문장에 활용하기 좋음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;초광대역 통화&lt;/td&gt;
&lt;td&gt;실내&amp;middot;실외 모두에서 비교적 안정적인 통화 경험&lt;/td&gt;
&lt;td&gt;일상 통화, 업무 통화 후기와 연결하기 좋음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Galaxy AI&lt;/td&gt;
&lt;td&gt;이어버드가 오디오 기기를 넘어 인터페이스처럼 느껴짐&lt;/td&gt;
&lt;td&gt;차별화 요소와 최신 기능 포인트로 활용 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;착용감&lt;/td&gt;
&lt;td&gt;장시간 착용 시에도 비교적 편안한 편&lt;/td&gt;
&lt;td&gt;실사용 만족도와 구매 포인트 설명에 적합&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class=&quot;samsungbuds_note&quot;&gt;설명 : 이벤트 참여용 글에서는 기능을 나열하기보다, 언제 써봤고 어떤 상황에서 좋았는지를 함께 적어주면 훨씬 자연스럽고 신뢰감 있게 보입니다.&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;samsungbuds_outro&quot; class=&quot;samsungbuds_section&quot;&gt;
&lt;h2 class=&quot;samsungbuds_section_title&quot; data-ke-size=&quot;size26&quot;&gt;마무리! 갤럭시 버즈4 프로 추천 포인트 정리&lt;/h2&gt;
&lt;div class=&quot;samsungbuds_summary&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;총평&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;갤럭시 버즈4 프로는 단순히 신제품이라는 이유만으로 눈길이 가는 무선이어폰이 아니라, 실제 사용 기준에서 음질, 통화 품질, Galaxy AI 활용성, 착용감까지 전체 밸런스가 잘 잡혀 있는 제품으로 느껴졌습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히 이번 리뷰를 작성하면서 인상적이었던 부분은 어떤 기능 하나만 튀기보다 전체 경험이 고르게 정돈되어 있다는 점이었습니다. 그래서 음악 감상용은 물론이고, 통화와 일상 활용성까지 함께 중요하게 보는 분들에게 더 잘 맞는 제품이라고 생각합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이벤트 참여를 계기로 사용해본 결과, &amp;ldquo;사진 찍기 좋은 제품&amp;rdquo;에서 끝나는 것이 아니라 실제로 자주 쓰게 되는 무선이어폰이라는 점에서 만족도가 높았습니다. 괜히 적을 포인트가 많은 제품이 아니었습니다.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;samsungbuds_tags&quot; style=&quot;margin-top: 16px;&quot;&gt;
&lt;h3 class=&quot;samsungbuds_tags_title&quot; data-ke-size=&quot;size23&quot;&gt;태그&lt;/h3&gt;
&lt;div class=&quot;samsungbuds_tag_list&quot;&gt;&lt;span class=&quot;samsungbuds_tag&quot;&gt;갤럭시 버즈4 프로 리뷰&lt;/span&gt; &lt;span class=&quot;samsungbuds_tag&quot;&gt;갤럭시 버즈4 프로 후기&lt;/span&gt; &lt;span class=&quot;samsungbuds_tag&quot;&gt;갤럭시 버즈4 프로 음질&lt;/span&gt; &lt;span class=&quot;samsungbuds_tag&quot;&gt;갤럭시 버즈4 프로 통화 품질&lt;/span&gt; &lt;span class=&quot;samsungbuds_tag&quot;&gt;갤럭시 버즈4 프로 착용감&lt;/span&gt; &lt;span class=&quot;samsungbuds_tag&quot;&gt;갤럭시 버즈4 프로 Galaxy AI&lt;/span&gt; &lt;span class=&quot;samsungbuds_tag&quot;&gt;갤럭시 버즈4 프로 이벤트&lt;/span&gt; &lt;span class=&quot;samsungbuds_tag&quot;&gt;갤럭시 버즈4 프로 리뷰어 미션&lt;/span&gt; &lt;span class=&quot;samsungbuds_tag&quot;&gt;버즈4 프로 하이파이 사운드&lt;/span&gt; &lt;span class=&quot;samsungbuds_tag&quot;&gt;버즈4 프로 초광대역 통화&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;div class=&quot;samsungbuds_footer&quot;&gt;이벤트 참여형 전문 리뷰 템플릿 &amp;middot; 티스토리 최적화 &amp;middot; SEO 키워드 자연 반영&lt;/div&gt;
&lt;/div&gt;</description>
      <category>IT/Product</category>
      <category>galaxyai</category>
      <category>GalaxyBuds4</category>
      <category>GalaxyBuds4Pro</category>
      <category>갤럭시버즈4ForU리뷰어</category>
      <category>갤럭시버즈4프로</category>
      <category>갤럭시버즈4프로리뷰</category>
      <category>삼성전자이벤트</category>
      <category>초광대역통화</category>
      <category>편안한착용감</category>
      <category>하이파이사운드</category>
      <author>간지뽕빨리턴님</author>
      <guid isPermaLink="true">https://odinbox.tistory.com/575</guid>
      <comments>https://odinbox.tistory.com/575#entry575comment</comments>
      <pubDate>Mon, 9 Mar 2026 07:02:34 +0900</pubDate>
    </item>
    <item>
      <title>센과 치히로의 행방불명 오리지널 내한 공연 관람 후기</title>
      <link>https://odinbox.tistory.com/574</link>
      <description>&lt;div&gt;
&lt;style&gt;
    @import url('https://fonts.googleapis.com/css2?family=Noto+Sans+KR:wght@300;400;500;700&amp;family=Noto+Serif+KR:wght@400;700;900&amp;display=swap');

    #magazine_post_wrapper {
        font-family: 'Noto Sans KR', 'Malgun Gothic', sans-serif;
        line-height: 1.8;
        color: #2c2c2c;
        max-width: 900px;
        margin: 0 auto;
        padding: 50px 20px;
        word-break: keep-all;
        background-color: #ffffff;
    }
    
    .magazine_header {
        text-align: center;
        margin-bottom: 60px;
    }
    
    .magazine_main_title {
        font-family: 'Noto Serif KR', 'Batang', serif;
        font-size: 36px;
        font-weight: 900;
        line-height: 1.45;
        color: #111;
        margin-bottom: 25px;
        letter-spacing: -0.5px;
    }
    
    .magazine_lead {
        font-size: 17px;
        color: #555;
        border-top: 2px solid #222;
        border-bottom: 1px solid #ddd;
        padding: 20px 10px;
        margin-bottom: 35px;
        text-align: justify;
        line-height: 1.7;
    }

    .magazine_sub_title {
        font-family: 'Noto Serif KR', 'Batang', serif;
        font-size: 24px;
        font-weight: 700;
        color: #1a1a1a;
        margin-top: 70px;
        margin-bottom: 25px;
        padding-bottom: 12px;
        border-bottom: 2px solid #222;
        letter-spacing: -0.5px;
    }

    .magazine_content_text {
        font-size: 16px;
        margin-bottom: 25px;
        text-align: justify;
        color: #333;
        font-weight: 400;
    }

    .magazine_info_box {
        margin: 50px 0;
        padding: 35px 30px;
        background-color: #f4f6f8;
        border-radius: 4px;
        border-top: 4px solid #2c3e50;
    }
    
    .magazine_info_title {
        font-family: 'Noto Serif KR', serif;
        font-size: 20px;
        font-weight: 700;
        color: #2c3e50;
        margin-bottom: 15px;
        display: flex;
        align-items: center;
    }
    
    .magazine_info_title::before {
        content: &quot;■&quot;;
        font-size: 14px;
        color: #e74c3c;
        margin-right: 10px;
    }

    .magazine_media_wrap {
        margin: 50px 0;
        text-align: center;
    }
    
    .magazine_media_wrap img, .magazine_media_wrap figure {
        max-width: 100%;
        height: auto;
        margin-bottom: 12px;
        border-radius: 2px;
        box-shadow: 0 4px 12px rgba(0,0,0,0.06);
        transition: transform 0.3s ease;
    }
    
    .magazine_media_wrap img:hover {
        transform: scale(1.01);
    }
    
    .magazine_caption {
        font-size: 13px;
        color: #777;
        margin-top: 10px;
        text-align: center;
        font-weight: 300;
        letter-spacing: 0.5px;
    }

    .magazine_youtube_wrap {
        position: relative;
        width: 100%;
        padding-bottom: 56.25%;
        margin: 45px 0 15px 0;
        background-color: #000;
        border-radius: 4px;
        overflow: hidden;
    }
    
    .magazine_youtube_wrap iframe {
        position: absolute;
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
        border: none;
    }

    .magazine_quote_box {
        margin: 50px 0;
        padding: 35px;
        background-color: #fff;
        border: 1px solid #eaeaea;
        border-left: 5px solid #8b0000;
        font-family: 'Noto Serif KR', 'Batang', serif;
        box-shadow: 0 2px 8px rgba(0,0,0,0.02);
    }
    
    .magazine_quote_jp {
        font-size: 15px;
        color: #888;
        margin-bottom: 12px;
        font-style: italic;
    }
    
    .magazine_quote_kr {
        font-size: 21px;
        font-weight: 700;
        color: #111;
        margin-bottom: 20px;
        line-height: 1.5;
    }
    
    .magazine_quote_speaker {
        font-size: 14px;
        color: #8b0000;
        font-family: 'Noto Sans KR', sans-serif;
        text-align: right;
        font-weight: 700;
    }

    #magazine_tags_section {
        margin-top: 90px;
        padding-top: 35px;
        border-top: 1px solid #eee;
    }
    
    .magazine_tag_header {
        font-size: 13px;
        font-weight: 700;
        color: #aaa;
        margin-bottom: 12px;
        text-transform: uppercase;
        letter-spacing: 2px;
    }
    
    .magazine_tag_content {
        font-size: 14px;
        color: #34495e;
        margin-bottom: 25px;
        line-height: 1.7;
        word-break: keep-all;
    }
&lt;/style&gt;
&lt;/div&gt;
&lt;div id=&quot;magazine_post_wrapper&quot;&gt;
&lt;div class=&quot;magazine_header&quot;&gt;
&lt;h1 class=&quot;magazine_main_title&quot;&gt;지브리의 감동을 무대에서 만나다&lt;br /&gt;연극 '센과 치히로의 행방불명' 오리지널 투어 관람기&lt;/h1&gt;
&lt;div class=&quot;magazine_lead&quot;&gt;세계적인 명작 애니메이션이 토니상 수상 연출가 존 케어드(John Caird)의 손을 거쳐 무대 위 아날로그 예술로 재탄생했다. 울산에서 서울 예술의전당까지, 스크린 속 신들의 세계를 실물로 마주한 2026년 2월의 기록을 심층적으로 분석한다.&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;magazine_media_wrap&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;750&quot; data-origin-height=&quot;1000&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dmvisF/dJMcagLoRWw/NHoQf4EhqPt0O4Df0FkoTk/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dmvisF/dJMcagLoRWw/NHoQf4EhqPt0O4Df0FkoTk/img.gif&quot; data-alt=&quot;뮤지컬 공식 포스터&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dmvisF/dJMcagLoRWw/NHoQf4EhqPt0O4Df0FkoTk/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/dmvisF/dJMcagLoRWw/NHoQf4EhqPt0O4Df0FkoTk/img.gif&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;750&quot; height=&quot;1000&quot; data-origin-width=&quot;750&quot; data-origin-height=&quot;1000&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;뮤지컬 공식 포스터&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;div class=&quot;magazine_caption&quot;&gt;센과 치히로의 행방불명 오리지널 투어 공식 포스터&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;magazine_media_wrap&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;썸네일.png&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rbepn/dJMcagLoNoH/NK7YouVxywxtZizL9BNmx1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rbepn/dJMcagLoNoH/NK7YouVxywxtZizL9BNmx1/img.png&quot; data-alt=&quot;썸네일 이미지&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rbepn/dJMcagLoNoH/NK7YouVxywxtZizL9BNmx1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Frbepn%2FdJMcagLoNoH%2FNK7YouVxywxtZizL9BNmx1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; alt=&quot;썸네일 이미지&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;400&quot; data-filename=&quot;썸네일.png&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;썸네일 이미지&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;h2 class=&quot;magazine_sub_title&quot; data-ke-size=&quot;size26&quot;&gt;새벽 KTX를 타고 마주한 지브리의 세계&lt;/h2&gt;
&lt;p class=&quot;magazine_content_text&quot; data-ke-size=&quot;size16&quot;&gt;지브리 스튜디오의 애니메이션 중에서도 전 세계적으로 가장 높은 평가를 받는 명작, '센과 치히로의 행방불명'이 오리지널 투어로 내한한다는 소식을 듣고 울산에서 서울까지 긴 여정을 계획했다. 2026년 2월 28일 토요일 오후 2시 공연 관람을 위해 아침 일찍부터 서둘렀던 그날의 동선과 현장 분위기를 상세히 서술한다.&lt;/p&gt;
&lt;div class=&quot;magazine_youtube_wrap&quot;&gt;&lt;iframe src=&quot;https://www.youtube-nocookie.com/embed/ajabjhn2k7c?si=B8lNhZRyTBd_hREU&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;
&lt;div class=&quot;magazine_caption&quot;&gt;▲ 센과 치히로의 행방불명 오리지널 투어 SPOT 영상&lt;/div&gt;
&lt;p class=&quot;magazine_content_text&quot; data-ke-size=&quot;size16&quot;&gt;아침 6시 30분 울산역에서 출발하는 KTX에 탑승하여 서울역에 도착하니 오전 9시가 조금 넘은 시각이었다. 지체 없이 택시를 이용하여 예술의전당으로 이동했다. 공연 시간까지 충분한 여유가 있었으므로, 전당 내부 구조를 살펴보고 카페에서 휴식을 취하며 관람을 준비했다. 오페라극장 홀 입장은 공연 시작 1시간 30분 전부터 허용되며, 12시 30분이 되자마자 1층 예매처에서 첫 번째로 티켓을 수령할 수 있었다.&lt;/p&gt;
&lt;div class=&quot;magazine_media_wrap&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/KnlDl/dJMcad18Bwb/kMbMtW4ISeL1pwih8wkKB1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/KnlDl/dJMcad18Bwb/kMbMtW4ISeL1pwih8wkKB1/img.png&quot; data-alt=&quot;출발 전 찍은 울산역 고래 조형물&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/KnlDl/dJMcad18Bwb/kMbMtW4ISeL1pwih8wkKB1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKnlDl%2FdJMcad18Bwb%2FkMbMtW4ISeL1pwih8wkKB1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; alt=&quot;출발 전 찍은 울산역 고래 조형물&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출발 전 찍은 울산역 고래 조형물&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/srKON/dJMcaf6LDgE/aKK2Dp1KmteS1XKt7llfDk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/srKON/dJMcaf6LDgE/aKK2Dp1KmteS1XKt7llfDk/img.png&quot; data-alt=&quot;출발전 찍은 울산역 전경&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/srKON/dJMcaf6LDgE/aKK2Dp1KmteS1XKt7llfDk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FsrKON%2FdJMcaf6LDgE%2FaKK2Dp1KmteS1XKt7llfDk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; alt=&quot;출발전 찍은 울산역 전경&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출발전 찍은 울산역 전경&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kzuhS/dJMcad18Bv6/35tDIJWkHB3HUhBk1H5RW0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kzuhS/dJMcad18Bv6/35tDIJWkHB3HUhBk1H5RW0/img.png&quot; data-alt=&quot;에술의전당 입구&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kzuhS/dJMcad18Bv6/35tDIJWkHB3HUhBk1H5RW0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkzuhS%2FdJMcad18Bv6%2F35tDIJWkHB3HUhBk1H5RW0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; alt=&quot;에술의전당 입구&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;에술의전당 입구&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1689&quot; data-origin-height=&quot;3000&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bgpdiu/dJMcad18Bv9/CQoduNDLJm4udT7nugXJD0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bgpdiu/dJMcad18Bv9/CQoduNDLJm4udT7nugXJD0/img.png&quot; data-alt=&quot;예술의극장 지하 1층 조형물&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bgpdiu/dJMcad18Bv9/CQoduNDLJm4udT7nugXJD0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbgpdiu%2FdJMcad18Bv9%2FCQoduNDLJm4udT7nugXJD0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; alt=&quot;예술의극장 지하 1층 조형물&quot; loading=&quot;lazy&quot; width=&quot;1689&quot; height=&quot;3000&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1689&quot; data-origin-height=&quot;3000&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;예술의극장 지하 1층 조형물&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bElhPp/dJMb996y4md/9PQfSrv7hvh9WItiQXfpAK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bElhPp/dJMb996y4md/9PQfSrv7hvh9WItiQXfpAK/img.png&quot; data-alt=&quot;예술의극장 지하1층 모습&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bElhPp/dJMb996y4md/9PQfSrv7hvh9WItiQXfpAK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbElhPp%2FdJMb996y4md%2F9PQfSrv7hvh9WItiQXfpAK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; alt=&quot;예술의극장 지하1층 모습&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;예술의극장 지하1층 모습&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;div class=&quot;magazine_quote_box&quot;&gt;
&lt;div class=&quot;magazine_quote_jp&quot;&gt;名前を奪われると、帰り道が分からなくなるんだよ。&lt;/div&gt;
&lt;div class=&quot;magazine_quote_kr&quot;&gt;&quot;이름을 빼앗기면 돌아가는 길을 알 수 없게 돼.&quot;&lt;/div&gt;
&lt;div class=&quot;magazine_quote_speaker&quot;&gt;- 하쿠 (ハク)&lt;/div&gt;
&lt;/div&gt;
&lt;h2 class=&quot;magazine_sub_title&quot; data-ke-size=&quot;size26&quot;&gt;공연장 인프라, 굿즈 수령과 포토존 활용&lt;/h2&gt;
&lt;p class=&quot;magazine_content_text&quot; data-ke-size=&quot;size16&quot;&gt;이번 내한 공연의 MD(굿즈) 부스는 예매 티켓 소지자에 한해 이용이 제한되었다. 이미 품절된 품목이 다수 존재했으나, 티켓을 조기 수령한 덕분에 사전에 계획했던 프로그램북, OST CD, 기념 뱃지를 원활하게 확보할 수 있었다.&lt;/p&gt;
&lt;p class=&quot;magazine_content_text&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;magazine_content_text&quot; data-ke-size=&quot;size16&quot;&gt;1층에는 하쿠의 특성을 시각화한 메인 포토존이 설치되어 있다. 조명을 활용한 연출이 돋보이며 시각적 완성도가 높다. 관람객의 분산을 위해 2층과 3층에도 각각 독립된 포토존이 운영되었다.&lt;/p&gt;
&lt;iframe mapdata=&quot;addr=%EC%84%9C%EC%9A%B8%20%EC%84%9C%EC%B4%88%EA%B5%AC%20%EC%84%9C%EC%B4%88%EB%8F%99%20700&amp;amp;addtype=1&amp;amp;confirmid=17344023&amp;amp;docid=&amp;amp;idx=1&amp;amp;ifrH=362px&amp;amp;ifrW=490px&amp;amp;mapHeight=362&amp;amp;mapInfo=%7B%22version%22%3A2%2C%22mapWidth%22%3A490%2C%22mapHeight%22%3A362%2C%22mapCenterX%22%3A503040%2C%22mapCenterY%22%3A1105553%2C%22mapLevel%22%3A4%2C%22coordinate%22%3A%22wcongnamul%22%2C%22markInfo%22%3A%5B%7B%22markerType%22%3A%22standPlace%22%2C%22coordinate%22%3A%22wcongnamul%22%2C%22x%22%3A503041%2C%22y%22%3A1105558%2C%22clickable%22%3Atrue%2C%22draggable%22%3Atrue%2C%22icon%22%3A%7B%22width%22%3A35%2C%22height%22%3A56%2C%22offsetX%22%3A17%2C%22offsetY%22%3A56%2C%22src%22%3A%22%2F%2Ft1.daumcdn.net%2Flocalimg%2Flocalimages%2F07%2F2012%2Fattach%2Fpc_img%2Fico_marker2_150331.png%22%7D%2C%22content%22%3A%22%EC%98%88%EC%88%A0%EC%9D%98%EC%A0%84%EB%8B%B9%22%2C%22confirmid%22%3A17344023%7D%5D%2C%22graphicInfo%22%3A%5B%5D%2C%22roadviewInfo%22%3A%5B%5D%7D&amp;amp;mapWidth=490&amp;amp;mapX=503040&amp;amp;mapY=1105553&amp;amp;map_hybrid=false&amp;amp;map_level=4&amp;amp;map_type=TYPE_MAP&amp;amp;rcode=1165053000&amp;amp;tel=1668-1352&amp;amp;title=%EC%98%88%EC%88%A0%EC%9D%98%EC%A0%84%EB%8B%B9&quot; src=&quot;/proxy/plusmapViewer.php?id=maps_1772384805392&quot; id=&quot;maps_1772384805392&quot; width=&quot;540px&quot; height=&quot;350px&quot; frameborder=&quot;0&quot; scrolling=&quot;no&quot; data-ke-type=&quot;map&quot; data-maps-data=&quot;addr=%EC%84%9C%EC%9A%B8%20%EC%84%9C%EC%B4%88%EA%B5%AC%20%EC%84%9C%EC%B4%88%EB%8F%99%20700&amp;amp;addtype=1&amp;amp;confirmid=17344023&amp;amp;docid=&amp;amp;idx=1&amp;amp;ifrH=362px&amp;amp;ifrW=490px&amp;amp;mapHeight=362&amp;amp;mapInfo=%7B%22version%22%3A2%2C%22mapWidth%22%3A490%2C%22mapHeight%22%3A362%2C%22mapCenterX%22%3A503040%2C%22mapCenterY%22%3A1105553%2C%22mapLevel%22%3A4%2C%22coordinate%22%3A%22wcongnamul%22%2C%22markInfo%22%3A%5B%7B%22markerType%22%3A%22standPlace%22%2C%22coordinate%22%3A%22wcongnamul%22%2C%22x%22%3A503041%2C%22y%22%3A1105558%2C%22clickable%22%3Atrue%2C%22draggable%22%3Atrue%2C%22icon%22%3A%7B%22width%22%3A35%2C%22height%22%3A56%2C%22offsetX%22%3A17%2C%22offsetY%22%3A56%2C%22src%22%3A%22%2F%2Ft1.daumcdn.net%2Flocalimg%2Flocalimages%2F07%2F2012%2Fattach%2Fpc_img%2Fico_marker2_150331.png%22%7D%2C%22content%22%3A%22%EC%98%88%EC%88%A0%EC%9D%98%EC%A0%84%EB%8B%B9%22%2C%22confirmid%22%3A17344023%7D%5D%2C%22graphicInfo%22%3A%5B%5D%2C%22roadviewInfo%22%3A%5B%5D%7D&amp;amp;mapWidth=490&amp;amp;mapX=503040&amp;amp;mapY=1105553&amp;amp;map_hybrid=false&amp;amp;map_level=4&amp;amp;map_type=TYPE_MAP&amp;amp;rcode=1165053000&amp;amp;tel=1668-1352&amp;amp;title=%EC%98%88%EC%88%A0%EC%9D%98%EC%A0%84%EB%8B%B9&quot; data-maps-thumbnail=&quot;https://ssl.daumcdn.net/map3/staticmap/image?center=503040%2C1105553&amp;amp;lv=4&amp;amp;size=540x350&amp;amp;srs=WCONGNAMUL&amp;amp;markers=symbol%3Asc_marker%7Clocation%3A503041%2C1105558&quot;&gt;&lt;/iframe&gt;
&lt;div class=&quot;magazine_media_wrap&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ctdxm3/dJMcaa5tbBf/XXupOYnGgzJ2K9o33YHkdK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ctdxm3/dJMcaa5tbBf/XXupOYnGgzJ2K9o33YHkdK/img.png&quot; data-alt=&quot;1층 오페라극장 들어가기전 입구 (1시간 30분전부터입장가능)&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ctdxm3/dJMcaa5tbBf/XXupOYnGgzJ2K9o33YHkdK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fctdxm3%2FdJMcaa5tbBf%2FXXupOYnGgzJ2K9o33YHkdK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; alt=&quot;1층 오페라극장 들어가기전 입구 (1시간 30분전부터입장가능)&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;1층 오페라극장 들어가기전 입구 (1시간 30분전부터입장가능)&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/JUSHS/dJMb996y4mc/RqCGBaF7weiCoMx4tBr58K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/JUSHS/dJMb996y4mc/RqCGBaF7weiCoMx4tBr58K/img.png&quot; data-alt=&quot;1층 입구 모습(오페라극장)&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/JUSHS/dJMb996y4mc/RqCGBaF7weiCoMx4tBr58K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJUSHS%2FdJMb996y4mc%2FRqCGBaF7weiCoMx4tBr58K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; alt=&quot;1층 입구 모습(오페라극장)&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;1층 입구 모습(오페라극장)&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oxC8x/dJMcad18BvR/wJn7B2mdh5biHyI5L5Sbr1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oxC8x/dJMcad18BvR/wJn7B2mdh5biHyI5L5Sbr1/img.png&quot; data-alt=&quot;오페라극장 바로 앞모습&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oxC8x/dJMcad18BvR/wJn7B2mdh5biHyI5L5Sbr1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoxC8x%2FdJMcad18BvR%2FwJn7B2mdh5biHyI5L5Sbr1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; alt=&quot;오페라극장 바로 앞모습&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;오페라극장 바로 앞모습&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/AJhH9/dJMcad18BvX/wOBHiWcpqWp8fQiq2ROko1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/AJhH9/dJMcad18BvX/wOBHiWcpqWp8fQiq2ROko1/img.png&quot; data-alt=&quot;오페라극장 건물외부&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/AJhH9/dJMcad18BvX/wOBHiWcpqWp8fQiq2ROko1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FAJhH9%2FdJMcad18BvX%2FwOBHiWcpqWp8fQiq2ROko1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; alt=&quot;오페라극장 건물외부&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;오페라극장 건물외부&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bf7uWI/dJMcaca9f4s/lVMoQQTd4XyAeNhEAREnyK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bf7uWI/dJMcaca9f4s/lVMoQQTd4XyAeNhEAREnyK/img.png&quot; data-alt=&quot;1층 옆에 걸려있는 포스터들 모음&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bf7uWI/dJMcaca9f4s/lVMoQQTd4XyAeNhEAREnyK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbf7uWI%2FdJMcaca9f4s%2FlVMoQQTd4XyAeNhEAREnyK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; alt=&quot;1층 옆에 걸려있는 포스터들 모음&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;1층 옆에 걸려있는 포스터들 모음&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/T6xXb/dJMb996y4mb/u8GG9tEHptVbvTsKzqoNiK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/T6xXb/dJMb996y4mb/u8GG9tEHptVbvTsKzqoNiK/img.png&quot; data-alt=&quot;1층 포토존 모습&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/T6xXb/dJMb996y4mb/u8GG9tEHptVbvTsKzqoNiK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FT6xXb%2FdJMb996y4mb%2Fu8GG9tEHptVbvTsKzqoNiK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; alt=&quot;1층 포토존 모습&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;1층 포토존 모습&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/UXT5L/dJMcaa5tbBh/KaNLeAPeMvcR2fXC97hYT1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/UXT5L/dJMcaa5tbBh/KaNLeAPeMvcR2fXC97hYT1/img.png&quot; data-alt=&quot;시작 전인 1층 모습(불꺼져있음)&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/UXT5L/dJMcaa5tbBh/KaNLeAPeMvcR2fXC97hYT1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FUXT5L%2FdJMcaa5tbBh%2FKaNLeAPeMvcR2fXC97hYT1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; alt=&quot;시작 전인 1층 모습(불꺼져있음)&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;시작 전인 1층 모습(불꺼져있음)&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/L440A/dJMcad18Bv8/FqMWodsfRT63jSBB2JzVrk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/L440A/dJMcad18Bv8/FqMWodsfRT63jSBB2JzVrk/img.png&quot; data-alt=&quot;영화포스터대형현수막&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/L440A/dJMcad18Bv8/FqMWodsfRT63jSBB2JzVrk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FL440A%2FdJMcad18Bv8%2FFqMWodsfRT63jSBB2JzVrk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; alt=&quot;영화포스터대형현수막&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;영화포스터대형현수막&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/yLSKU/dJMcaca9f4o/VnKJmN46ISM0gkS6KQZ3l0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/yLSKU/dJMcaca9f4o/VnKJmN46ISM0gkS6KQZ3l0/img.png&quot; data-alt=&quot;공연장 입장전찍은모습&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/yLSKU/dJMcaca9f4o/VnKJmN46ISM0gkS6KQZ3l0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FyLSKU%2FdJMcaca9f4o%2FVnKJmN46ISM0gkS6KQZ3l0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; alt=&quot;공연장 입장전찍은모습&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;공연장 입장전찍은모습&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/AKOrn/dJMcaadleHd/Su7H6tAkNK46SqfiXknWlk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/AKOrn/dJMcaadleHd/Su7H6tAkNK46SqfiXknWlk/img.png&quot; data-alt=&quot;1층 포토존 모습 위에서 바라봄&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/AKOrn/dJMcaadleHd/Su7H6tAkNK46SqfiXknWlk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FAKOrn%2FdJMcaadleHd%2FSu7H6tAkNK46SqfiXknWlk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; alt=&quot;1층 포토존 모습 위에서 바라봄&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;1층 포토존 모습 위에서 바라봄&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cPH2Cf/dJMcaca9f4t/Mk0RyUhwDcaQrkNVMUYfv0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cPH2Cf/dJMcaca9f4t/Mk0RyUhwDcaQrkNVMUYfv0/img.png&quot; data-alt=&quot;1층 티켓수령장소 바로 앞&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cPH2Cf/dJMcaca9f4t/Mk0RyUhwDcaQrkNVMUYfv0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcPH2Cf%2FdJMcaca9f4t%2FMk0RyUhwDcaQrkNVMUYfv0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; alt=&quot;1층 티켓수령장소 바로 앞&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;1층 티켓수령장소 바로 앞&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1689&quot; data-origin-height=&quot;3000&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bF1bFY/dJMcad18BvE/pC2ONjvl6l2PjmLKqdEL01/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bF1bFY/dJMcad18BvE/pC2ONjvl6l2PjmLKqdEL01/img.png&quot; data-alt=&quot;기념품 가오나시 뱃지&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bF1bFY/dJMcad18BvE/pC2ONjvl6l2PjmLKqdEL01/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbF1bFY%2FdJMcad18BvE%2FpC2ONjvl6l2PjmLKqdEL01%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; alt=&quot;기념품 가오나시 뱃지&quot; loading=&quot;lazy&quot; width=&quot;1689&quot; height=&quot;3000&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1689&quot; data-origin-height=&quot;3000&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;기념품 가오나시 뱃지&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1689&quot; data-origin-height=&quot;3000&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cfJi1k/dJMb996y4xc/4h8WLFK7CMMSn4qTciy9Kk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cfJi1k/dJMb996y4xc/4h8WLFK7CMMSn4qTciy9Kk/img.png&quot; data-alt=&quot;입장권&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cfJi1k/dJMb996y4xc/4h8WLFK7CMMSn4qTciy9Kk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcfJi1k%2FdJMb996y4xc%2F4h8WLFK7CMMSn4qTciy9Kk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; alt=&quot;입장권&quot; loading=&quot;lazy&quot; width=&quot;1689&quot; height=&quot;3000&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1689&quot; data-origin-height=&quot;3000&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;입장권&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1689&quot; data-origin-height=&quot;3000&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dpmytM/dJMcad18BvM/6vq5yltedSA5aFlOBnpgx1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dpmytM/dJMcad18BvM/6vq5yltedSA5aFlOBnpgx1/img.png&quot; data-alt=&quot;1층 기둥 포스 터&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dpmytM/dJMcad18BvM/6vq5yltedSA5aFlOBnpgx1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdpmytM%2FdJMcad18BvM%2F6vq5yltedSA5aFlOBnpgx1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; alt=&quot;1층 기둥 포스 터&quot; loading=&quot;lazy&quot; width=&quot;1689&quot; height=&quot;3000&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1689&quot; data-origin-height=&quot;3000&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;1층 기둥 포스 터&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1689&quot; data-origin-height=&quot;3000&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/VRtE6/dJMcad18BvO/4w1bU3BjVSHXklDJZVyBCk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/VRtE6/dJMcad18BvO/4w1bU3BjVSHXklDJZVyBCk/img.png&quot; data-alt=&quot;1층 디지털 포스터&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/VRtE6/dJMcad18BvO/4w1bU3BjVSHXklDJZVyBCk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FVRtE6%2FdJMcad18BvO%2F4w1bU3BjVSHXklDJZVyBCk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; alt=&quot;1층 디지털 포스터&quot; loading=&quot;lazy&quot; width=&quot;1689&quot; height=&quot;3000&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1689&quot; data-origin-height=&quot;3000&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;1층 디지털 포스터&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1689&quot; data-origin-height=&quot;3000&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cmtgjt/dJMcaca9f4l/9TwY2xLfEzooIeUQg2TJIK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cmtgjt/dJMcaca9f4l/9TwY2xLfEzooIeUQg2TJIK/img.png&quot; data-alt=&quot;1층 포스트 기둥&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cmtgjt/dJMcaca9f4l/9TwY2xLfEzooIeUQg2TJIK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcmtgjt%2FdJMcaca9f4l%2F9TwY2xLfEzooIeUQg2TJIK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; alt=&quot;1층 포스트 기둥&quot; loading=&quot;lazy&quot; width=&quot;1689&quot; height=&quot;3000&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1689&quot; data-origin-height=&quot;3000&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;1층 포스트 기둥&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1689&quot; data-origin-height=&quot;3000&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cC3wSF/dJMcaadleHa/Wi2cF10UdtkJdqxlg9LEo1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cC3wSF/dJMcaadleHa/Wi2cF10UdtkJdqxlg9LEo1/img.png&quot; data-alt=&quot;1층 포토존 뒤에 가오나시 그림&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cC3wSF/dJMcaadleHa/Wi2cF10UdtkJdqxlg9LEo1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcC3wSF%2FdJMcaadleHa%2FWi2cF10UdtkJdqxlg9LEo1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; alt=&quot;1층 포토존 뒤에 가오나시 그림&quot; loading=&quot;lazy&quot; width=&quot;1689&quot; height=&quot;3000&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1689&quot; data-origin-height=&quot;3000&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;1층 포토존 뒤에 가오나시 그림&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;p class=&quot;magazine_content_text&quot; data-ke-size=&quot;size16&quot;&gt;3층에 마련된 '신들의 온천장'은 사전 예약 굿즈의 수령처인 동시에 전시 기능을 겸하고 있다. 더불어 소원나무 트리와 무료 엽서 배포 공간이 마련되어 있으며, 치히로가 바닷가에서 신발을 들고 있는 명장면을 재현한 포토존은 관람객들에게 높은 호응을 얻었다.&lt;/p&gt;
&lt;div class=&quot;magazine_media_wrap&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1689&quot; data-origin-height=&quot;3000&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/9ZwVR/dJMcaca9f4n/khe4GCxKkpFICgh00FI0K1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/9ZwVR/dJMcaca9f4n/khe4GCxKkpFICgh00FI0K1/img.png&quot; data-alt=&quot;신들의온천장 근처에 있는 포토존 1&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/9ZwVR/dJMcaca9f4n/khe4GCxKkpFICgh00FI0K1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F9ZwVR%2FdJMcaca9f4n%2Fkhe4GCxKkpFICgh00FI0K1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; alt=&quot;신들의온천장 근처에 있는 포토존 1&quot; loading=&quot;lazy&quot; width=&quot;1689&quot; height=&quot;3000&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1689&quot; data-origin-height=&quot;3000&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;신들의온천장 근처에 있는 포토존 1&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1689&quot; data-origin-height=&quot;3000&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cJBaCy/dJMcad18BvU/2qVM5JANBFvdFQ9fzCzT31/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cJBaCy/dJMcad18BvU/2qVM5JANBFvdFQ9fzCzT31/img.png&quot; data-alt=&quot;신들의온천장 근처에 있는 포토존2&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cJBaCy/dJMcad18BvU/2qVM5JANBFvdFQ9fzCzT31/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcJBaCy%2FdJMcad18BvU%2F2qVM5JANBFvdFQ9fzCzT31%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; alt=&quot;신들의온천장 근처에 있는 포토존2&quot; loading=&quot;lazy&quot; width=&quot;1689&quot; height=&quot;3000&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1689&quot; data-origin-height=&quot;3000&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;신들의온천장 근처에 있는 포토존2&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bOwkDn/dJMcaca9f4p/o0KBaLMjGQ5RzwdkHJ0ae0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bOwkDn/dJMcaca9f4p/o0KBaLMjGQ5RzwdkHJ0ae0/img.png&quot; data-alt=&quot;신들의 온천장 근처에 있는 포토존 두개&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bOwkDn/dJMcaca9f4p/o0KBaLMjGQ5RzwdkHJ0ae0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbOwkDn%2FdJMcaca9f4p%2Fo0KBaLMjGQ5RzwdkHJ0ae0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; alt=&quot;신들의 온천장 근처에 있는 포토존 두개&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;신들의 온천장 근처에 있는 포토존 두개&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;h2 class=&quot;magazine_sub_title&quot; data-ke-size=&quot;size26&quot;&gt;무대 연출 및 좌석 시야 분석&lt;/h2&gt;
&lt;p class=&quot;magazine_content_text&quot; data-ke-size=&quot;size16&quot;&gt;공연은 1부 85분, 인터미션 20분, 2부 75분 등 총 3시간에 걸쳐 진행되었다. 예매한 좌석은 1층 C열 21번 3번이었다. 예매 전 해당 구역의 시야 확보에 대한 우려가 있었으나, 실제 착석 결과 무대 전체의 미장센을 조망하는 데 큰 무리가 없었다.&lt;/p&gt;
&lt;div class=&quot;magazine_media_wrap&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1689&quot; data-origin-height=&quot;3000&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lHS8e/dJMcaadleHb/YEzvR40lgOxxWKCaZIvNr0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lHS8e/dJMcaadleHb/YEzvR40lgOxxWKCaZIvNr0/img.png&quot; data-alt=&quot;1층 좌석배치도&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lHS8e/dJMcaadleHb/YEzvR40lgOxxWKCaZIvNr0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlHS8e%2FdJMcaadleHb%2FYEzvR40lgOxxWKCaZIvNr0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; alt=&quot;1층 좌석배치도&quot; loading=&quot;lazy&quot; width=&quot;1689&quot; height=&quot;3000&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1689&quot; data-origin-height=&quot;3000&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;1층 좌석배치도&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/k4Lq6/dJMcaf6LDgF/8lbohwbVPqEeELh0F5TFIk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/k4Lq6/dJMcaf6LDgF/8lbohwbVPqEeELh0F5TFIk/img.png&quot; data-alt=&quot;공연장 안 모습&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/k4Lq6/dJMcaf6LDgF/8lbohwbVPqEeELh0F5TFIk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fk4Lq6%2FdJMcaf6LDgF%2F8lbohwbVPqEeELh0F5TFIk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; alt=&quot;공연장 안 모습&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;공연장 안 모습&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bqgLoU/dJMcaca9f4k/XmlftX4aUDdSYDkvQQeaWK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bqgLoU/dJMcaca9f4k/XmlftX4aUDdSYDkvQQeaWK/img.png&quot; data-alt=&quot;공연장 안 모습&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bqgLoU/dJMcaca9f4k/XmlftX4aUDdSYDkvQQeaWK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbqgLoU%2FdJMcaca9f4k%2FXmlftX4aUDdSYDkvQQeaWK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; alt=&quot;공연장 안 모습&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;공연장 안 모습&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;p class=&quot;magazine_content_text&quot; data-ke-size=&quot;size16&quot;&gt;다만, 배우들의 세밀한 표정 연기를 관찰하기 위해서는 오페라글라스 지참을 권장한다. 본 공연은 일본어 원어로 진행되며 한국어 자막이 제공된다. 따라서 자막기의 위치와 좌석의 시야각을 종합적으로 고려하여 예매하는 것이 원활한 관람의 핵심이다. (공연 중 휴대전화 전원 차단 및 커튼콜을 포함한 전 구간 촬영 금지 규정이 엄격히 적용된다.)&lt;/p&gt;
&lt;div class=&quot;magazine_quote_box&quot;&gt;
&lt;div class=&quot;magazine_quote_jp&quot;&gt;ここで働かせてください！&lt;/div&gt;
&lt;div class=&quot;magazine_quote_kr&quot;&gt;&quot;여기서 일하게 해주세요!&quot;&lt;/div&gt;
&lt;div class=&quot;magazine_quote_speaker&quot;&gt;- 치히로 (千尋)&lt;/div&gt;
&lt;/div&gt;
&lt;h2 class=&quot;magazine_sub_title&quot; data-ke-size=&quot;size26&quot;&gt;아날로그 예술의 극치, 무대와 배우들의 열연&lt;/h2&gt;
&lt;p class=&quot;magazine_content_text&quot; data-ke-size=&quot;size16&quot;&gt;이번 연극이 전 세계적인 호평을 받는 이유는 원작의 판타지적 요소를 CG가 아닌 철저한 '아날로그 무대 장치'와 '퍼핏(인형)' 기술로 구현했다는 점에 있다. 영국의 저명한 퍼핏 디자이너 토비 올리에(Toby Oli&amp;eacute;)의 기술력이 더해져, 스크린 속 정령들과 요괴들이 인간의 신체 움직임과 결합하여 물리적인 무대 위에서 생동감 있게 살아 움직인다.&lt;/p&gt;
&lt;div class=&quot;magazine_youtube_wrap&quot;&gt;&lt;iframe src=&quot;https://www.youtube-nocookie.com/embed/6WkHf8jlkVQ?si=OLDNwglzy6TgAWQd&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;
&lt;div class=&quot;magazine_caption&quot;&gt;▲ 센과 치히로의 행방불명 오리지널 투어 무대 셋업 타임랩스&lt;/div&gt;
&lt;p class=&quot;magazine_content_text&quot; data-ke-size=&quot;size16&quot;&gt;관람 회차의 캐스팅 역시 원작과의 높은 싱크로율을 입증했다. 치히로 역의 카와에이 리나는 두려움에 떨던 소녀가 주체적인 인물로 성장해 가는 궤적을 에너제틱하게 소화해 냈다. 하쿠 역의 아쿠츠 니치카는 절도 있는 동선 처리로 캐릭터 특유의 신비로움을 유지했다.&lt;/p&gt;
&lt;p class=&quot;magazine_content_text&quot; data-ke-size=&quot;size16&quot;&gt;특히 유바바와 제니바 1인 2역을 맡은 타카하시 히토미는 베테랑 배우의 관록을 증명하듯, 탐욕과 포용력이라는 양극단의 감정을 완벽하게 분리하여 연기했다. 사와무라 료(가오나시 역)의 섬세한 안무적 표현, 만타니 노리히데(가마 할아범 역)의 안정적인 조력자 연기 또한 무대의 입체감을 더하는 데 크게 기여했다.&lt;/p&gt;
&lt;div class=&quot;magazine_media_wrap&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oi3sV/dJMcad18BHP/wkozYmFFc8lh52nsO5Tdnk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oi3sV/dJMcad18BHP/wkozYmFFc8lh52nsO5Tdnk/img.png&quot; data-alt=&quot;예술의 전당 앞 모습&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oi3sV/dJMcad18BHP/wkozYmFFc8lh52nsO5Tdnk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Foi3sV%2FdJMcad18BHP%2FwkozYmFFc8lh52nsO5Tdnk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; alt=&quot;예술의 전당 앞 모습&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;예술의 전당 앞 모습&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oi3sV/dJMcad18BHP/wkozYmFFc8lh52nsO5Tdnk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oi3sV/dJMcad18BHP/wkozYmFFc8lh52nsO5Tdnk/img.png&quot; data-alt=&quot;예술의 전당 앞 모습&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oi3sV/dJMcad18BHP/wkozYmFFc8lh52nsO5Tdnk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Foi3sV%2FdJMcad18BHP%2FwkozYmFFc8lh52nsO5Tdnk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; alt=&quot;예술의 전당 앞 모습&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;예술의 전당 앞 모습&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1689&quot; data-origin-height=&quot;3000&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/E7mdm/dJMcad18BvW/lm42ZEUuT2AEEgoaR9TbKk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/E7mdm/dJMcad18BvW/lm42ZEUuT2AEEgoaR9TbKk/img.png&quot; data-alt=&quot;예술의 전당 가로등에 걸린 뮤지컬포스터 홍보&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/E7mdm/dJMcad18BvW/lm42ZEUuT2AEEgoaR9TbKk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FE7mdm%2FdJMcad18BvW%2Flm42ZEUuT2AEEgoaR9TbKk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; alt=&quot;예술의 전당 가로등에 걸린 뮤지컬포스터 홍보&quot; loading=&quot;lazy&quot; width=&quot;1689&quot; height=&quot;3000&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1689&quot; data-origin-height=&quot;3000&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;예술의 전당 가로등에 걸린 뮤지컬포스터 홍보&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/YdmI4/dJMcad18Bwe/Y8iEESRgf3k2MlaTBuq7Kk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/YdmI4/dJMcad18Bwe/Y8iEESRgf3k2MlaTBuq7Kk/img.png&quot; data-alt=&quot;예술의전당 벽에 걸린 뮤지컬 홍보 포스터&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/YdmI4/dJMcad18Bwe/Y8iEESRgf3k2MlaTBuq7Kk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FYdmI4%2FdJMcad18Bwe%2FY8iEESRgf3k2MlaTBuq7Kk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; alt=&quot;예술의전당 벽에 걸린 뮤지컬 홍보 포스터&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;예술의전당 벽에 걸린 뮤지컬 홍보 포스터&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;301&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/BzRGl/dJMcahXPd99/jIoUempfQRVHi1eQv6E1Rk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/BzRGl/dJMcahXPd99/jIoUempfQRVHi1eQv6E1Rk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/BzRGl/dJMcahXPd99/jIoUempfQRVHi1eQv6E1Rk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FBzRGl%2FdJMcahXPd99%2FjIoUempfQRVHi1eQv6E1Rk%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;700&quot; height=&quot;301&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;301&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;div class=&quot;magazine_caption&quot;&gt;Photo by Johan Persson, 공연 中&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;magazine_quote_box&quot;&gt;
&lt;div class=&quot;magazine_quote_jp&quot;&gt;一度あったことは忘れないものさ。思い出せないだけで。&lt;/div&gt;
&lt;div class=&quot;magazine_quote_kr&quot;&gt;&quot;한 번 만난 인연은 잊히는 것이 아니라, 잊고 있을 뿐이란다.&quot;&lt;/div&gt;
&lt;div class=&quot;magazine_quote_speaker&quot;&gt;- 제니바 (銭婆)&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;magazine_info_box&quot;&gt;
&lt;div class=&quot;magazine_info_title&quot;&gt;FACT CHECK : 뮤지컬인가, 연극인가?&lt;/div&gt;
&lt;p class=&quot;magazine_content_text&quot; style=&quot;margin-bottom: 10px; font-size: 15px;&quot; data-ke-size=&quot;size16&quot;&gt;압도적인 무대 스케일과 라이브 오케스트라의 존재로 인해 관람객들조차 이 작품을 '뮤지컬'로 오해하는 경우가 빈번하다. 인터파크 등 국내 주요 예매처 역시 마케팅 효과와 대극장 공연 시스템 분류의 편의를 위해 '뮤지컬' 카테고리에서 티켓을 판매하고 있다. &lt;b&gt;하지만 제작사가 명시한 이 작품의 공식 장르는 '연극(Play)'이다.&lt;/b&gt;&lt;/p&gt;
&lt;p class=&quot;magazine_content_text&quot; style=&quot;margin-bottom: 0; font-size: 15px;&quot; data-ke-size=&quot;size16&quot;&gt;뮤지컬은 극의 서사와 인물의 감정을 배우의 '가창(넘버)'을 통해 전개하는 것이 핵심이다. 반면, 본 공연은 철저하게 배우들의 대사와 신체 연기, 퍼핏 조종으로 서사를 이끌어간다. 11인조 오케스트라가 연주하는 히사이시 조의 명곡은 가창을 위한 반주가 아닌, 극의 분위기를 극대화하는 오리지널 사운드트랙(BGM)의 역할을 수행한다. 즉, 예매처의 분류와 대중적 인식은 '뮤지컬'일지라도, 작품의 본질적인 예술 형태는 음악이 가미된 &lt;b&gt;'대극장 연극'&lt;/b&gt;으로 이해하는 것이 정확하다.&lt;/p&gt;
&lt;/div&gt;
&lt;h2 class=&quot;magazine_sub_title&quot; data-ke-size=&quot;size26&quot;&gt;커튼콜의 여운과 복귀 여정&lt;/h2&gt;
&lt;p class=&quot;magazine_content_text&quot; data-ke-size=&quot;size16&quot;&gt;공연의 피날레를 장식한 커튼콜은 본 관람의 하이라이트라 할 수 있다. 무대 아래 가려져 있던 11인조 라이브 오케스트라 피트가 공개되고, 히사이시 조의 대표 명곡인 '또다시(Reprise)'가 웅장한 라이브 연주로 울려 퍼졌다. 19만 원이라는 티켓 가격은 결코 적은 금액이 아니나, 무대 메커니즘의 완성도와 오케스트라 라이브가 주는 공간감을 고려할 때 그 가치는 충분히 입증되었다.&lt;/p&gt;
&lt;div class=&quot;magazine_youtube_wrap&quot;&gt;&lt;iframe src=&quot;https://www.youtube-nocookie.com/embed/brHencVS5y4?si=2r3f_2XX6pj9mZi3&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;
&lt;div class=&quot;magazine_caption&quot;&gt;▲ 센과 치히로의 행방불명 OST (또다시 Reprise)&lt;/div&gt;
&lt;p class=&quot;magazine_content_text&quot; data-ke-size=&quot;size16&quot;&gt;오후 5시경 예술의전당을 나서 서울역으로 이동했다. 기차 탑승 전 인근 식당에서 매운 낙지비빔국수로 저녁 식사를 해결하며 공연의 여운을 정리했다. 밤 8시 58분에 서울역을 출발한 KTX는 11시 23분 울산역에 도착했다. 주차장에 대기해 둔 차량을 이용하여 자택으로 복귀함으로써 당일치기 문화 기행이 마무리되었다. 물리적인 피로는 수반되었으나, 무대 위에서 완벽하게 재현된 지브리의 세계는 오랫동안 잊지 못할 예술적 경험으로 남을 것이다.&lt;/p&gt;
&lt;div class=&quot;magazine_media_wrap&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/SkQyI/dJMcaca9f4j/MZtScaTNwlEtXAPQdGUoD1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/SkQyI/dJMcaca9f4j/MZtScaTNwlEtXAPQdGUoD1/img.png&quot; data-alt=&quot;신세계본점 대형 입체디스플레이&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/SkQyI/dJMcaca9f4j/MZtScaTNwlEtXAPQdGUoD1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FSkQyI%2FdJMcaca9f4j%2FMZtScaTNwlEtXAPQdGUoD1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; alt=&quot;신세계본점 대형 입체디스플레이&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;신세계본점 대형 입체디스플레이&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bfsF3B/dJMcabi1SDH/85VfNOWSViCVHM87X3ayCk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bfsF3B/dJMcabi1SDH/85VfNOWSViCVHM87X3ayCk/img.png&quot; data-alt=&quot;신세계본점 대형디스플레이 사진 찍으려는 사람들 모습&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bfsF3B/dJMcabi1SDH/85VfNOWSViCVHM87X3ayCk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbfsF3B%2FdJMcabi1SDH%2F85VfNOWSViCVHM87X3ayCk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; alt=&quot;신세계본점 대형디스플레이 사진 찍으려는 사람들 모습&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;신세계본점 대형디스플레이 사진 찍으려는 사람들 모습&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cqKAR5/dJMcaadleG9/hFcRvrxJl3R1KjYWoRd8E1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cqKAR5/dJMcaadleG9/hFcRvrxJl3R1KjYWoRd8E1/img.png&quot; data-alt=&quot;서울역 앞에 있는 건물 (드라마 미생에 나옴) 야경1&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cqKAR5/dJMcaadleG9/hFcRvrxJl3R1KjYWoRd8E1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcqKAR5%2FdJMcaadleG9%2FhFcRvrxJl3R1KjYWoRd8E1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; alt=&quot;서울역 앞에 있는 건물 (드라마 미생에 나옴) 야경1&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;서울역 앞에 있는 건물 (드라마 미생에 나옴) 야경1&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kzybx/dJMcaadleG8/GNelmyK8IwYscXsMmelMjk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kzybx/dJMcaadleG8/GNelmyK8IwYscXsMmelMjk/img.png&quot; data-alt=&quot;서울역 앞에 있는 건물(드라마 미생에 나왔던 곳)&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kzybx/dJMcaadleG8/GNelmyK8IwYscXsMmelMjk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fkzybx%2FdJMcaadleG8%2FGNelmyK8IwYscXsMmelMjk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; alt=&quot;서울역 앞에 있는 건물(드라마 미생에 나왔던 곳)&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;서울역 앞에 있는 건물(드라마 미생에 나왔던 곳)&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cxrODK/dJMcahDu70s/vEAeJr8u6nkTBglksDkcI0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cxrODK/dJMcahDu70s/vEAeJr8u6nkTBglksDkcI0/img.png&quot; data-alt=&quot;울산으로 출발하는 KTX 타기 전 서울역 플랫폼&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cxrODK/dJMcahDu70s/vEAeJr8u6nkTBglksDkcI0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcxrODK%2FdJMcahDu70s%2FvEAeJr8u6nkTBglksDkcI0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; alt=&quot;울산으로 출발하는 KTX 타기 전 서울역 플랫폼&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;울산으로 출발하는 KTX 타기 전 서울역 플랫폼&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1689&quot; data-origin-height=&quot;3000&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/X5mFz/dJMcad18BHN/xJDR2lxVcQf6S4pK0IpAAK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/X5mFz/dJMcad18BHN/xJDR2lxVcQf6S4pK0IpAAK/img.png&quot; data-alt=&quot;서울역에서 울산출발 전 KTX찍은 모습&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/X5mFz/dJMcad18BHN/xJDR2lxVcQf6S4pK0IpAAK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FX5mFz%2FdJMcad18BHN%2FxJDR2lxVcQf6S4pK0IpAAK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; alt=&quot;서울역에서 울산출발 전 KTX찍은 모습&quot; loading=&quot;lazy&quot; width=&quot;1689&quot; height=&quot;3000&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1689&quot; data-origin-height=&quot;3000&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;서울역에서 울산출발 전 KTX찍은 모습&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ddnVQS/dJMcahDu70q/DcVeRoH4eln9bQlk05dlE1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ddnVQS/dJMcahDu70q/DcVeRoH4eln9bQlk05dlE1/img.png&quot; data-alt=&quot;울산 도착하고 집가다가 찍은 소나타 모습&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ddnVQS/dJMcahDu70q/DcVeRoH4eln9bQlk05dlE1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FddnVQS%2FdJMcahDu70q%2FDcVeRoH4eln9bQlk05dlE1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; alt=&quot;울산 도착하고 집가다가 찍은 소나타 모습&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;울산 도착하고 집가다가 찍은 소나타 모습&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;div id=&quot;magazine_tags_section&quot;&gt;
&lt;div class=&quot;magazine_tag_header&quot;&gt;태그&lt;/div&gt;
&lt;div class=&quot;magazine_tag_content&quot;&gt;#센과치히로의행방불명 #예술의전당 #오리지널투어 #공연후기 #카와에이리나 #아쿠츠니치카 #타카하시히토미 #지브리공연 #존케어드연출 #내한공연&lt;/div&gt;
&lt;div class=&quot;magazine_tag_content&quot;&gt;뮤지컬센과치히로, 센과치히로연극후기, 예술의전당오페라극장, 센과치히로굿즈, 하쿠명대사, 치히로명대사, 지브리내한공연, 서울역낙지비빔국수, 울산출발서울공연, 센과치히로캐스팅&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</description>
      <category>DailyRoutine</category>
      <category>내한공연</category>
      <category>뮤지컬</category>
      <category>센과치히로의행방불명</category>
      <category>애니메이션</category>
      <category>연극</category>
      <category>예술의전당</category>
      <category>오케스트라공연</category>
      <category>지브리내한공연</category>
      <category>지브리스튜디오</category>
      <category>히사히시조</category>
      <author>간지뽕빨리턴님</author>
      <guid isPermaLink="true">https://odinbox.tistory.com/574</guid>
      <comments>https://odinbox.tistory.com/574#entry574comment</comments>
      <pubDate>Mon, 2 Mar 2026 01:59:51 +0900</pubDate>
    </item>
    <item>
      <title>애플 맥 개발환경  설정방법</title>
      <link>https://odinbox.tistory.com/573</link>
      <description>&lt;div id=&quot;macsettings_post_wrap&quot; class=&quot;macsettings_post_wrap&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;글 상단 부분 대표 이미지.png&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/efdu68/dJMcacoATZu/WK0Oa6z7ahiFX3Wy85QB2K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/efdu68/dJMcacoATZu/WK0Oa6z7ahiFX3Wy85QB2K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/efdu68/dJMcacoATZu/WK0Oa6z7ahiFX3Wy85QB2K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fefdu68%2FdJMcacoATZu%2FWK0Oa6z7ahiFX3Wy85QB2K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;400&quot; data-filename=&quot;글 상단 부분 대표 이미지.png&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;style&gt;
    .macsettings_post_wrap{
      max-width: 960px;
      margin: 0 auto;
      padding: 20px 16px 48px;
      font-family: &quot;Pretendard&quot;,&quot;Noto Sans KR&quot;,&quot;Apple SD Gothic Neo&quot;,&quot;Malgun Gothic&quot;,sans-serif;
      color: #111827;
      line-height: 1.85;
      word-break: keep-all;
    }
    .macsettings_post_wrap *{ box-sizing: border-box; }

    .macsettings_hero{
      border: 1px solid #e5e7eb;
      border-radius: 18px;
      background: linear-gradient(135deg, #f8fbff 0%, #ffffff 45%, #f4f7fb 100%);
      padding: 22px 18px;
      margin-bottom: 18px;
    }
    .macsettings_badges{
      display:flex;
      flex-wrap:wrap;
      gap:8px;
      margin-bottom:10px;
    }
    .macsettings_badge{
      display:inline-flex;
      align-items:center;
      padding:5px 10px;
      border-radius:999px;
      border:1px solid #e5e7eb;
      background:#fff;
      color:#374151;
      font-size:12px;
      font-weight:600;
    }
    .macsettings_title{
      margin:0 0 8px 0;
      font-size:1.85rem;
      line-height:1.35;
      letter-spacing:-0.02em;
      color:#0f172a;
    }
    .macsettings_subtitle{
      margin:0;
      color:#4b5563;
      font-size:0.98rem;
    }

    .macsettings_section{
      margin-top:30px;
    }
    .macsettings_section h2{
      margin:0 0 12px;
      font-size:1.33rem;
      line-height:1.4;
      color:#0f172a;
      border-left:5px solid #2563eb;
      padding-left:10px;
      letter-spacing:-0.01em;
    }
    .macsettings_section h3{
      margin:18px 0 8px;
      font-size:1.03rem;
      color:#1f2937;
    }
    .macsettings_section p{
      margin:10px 0;
      color:#1f2937;
    }
    .macsettings_section ul{
      margin:8px 0 12px;
      padding-left:20px;
    }
    .macsettings_section li{
      margin:4px 0;
    }

    .macsettings_callout{
      margin:14px 0;
      padding:12px 14px;
      border-radius:12px;
      border:1px solid #dbeafe;
      background:#eff6ff;
      color:#1e3a8a;
      font-size:0.95rem;
    }
    .macsettings_callout_warn{
      border-color:#fde68a;
      background:#fffbeb;
      color:#92400e;
    }
    .macsettings_callout_ok{
      border-color:#bbf7d0;
      background:#f0fdf4;
      color:#166534;
    }

    .macsettings_table_wrap{
      overflow-x:auto;
      margin:12px 0 16px;
      border:1px solid #e5e7eb;
      border-radius:12px;
      background:#fff;
    }
    .macsettings_table{
      width:100%;
      min-width:640px;
      border-collapse:collapse;
      font-size:0.93rem;
    }
    .macsettings_table th,
    .macsettings_table td{
      padding:10px 12px;
      border-bottom:1px solid #f1f5f9;
      text-align:left;
      vertical-align:top;
    }
    .macsettings_table th{
      background:#f8fafc;
      color:#0f172a;
      font-weight:700;
    }

    .macsettings_code{
      margin:12px 0;
      border:1px solid #e5e7eb;
      border-radius:12px;
      background:#0f172a;
      color:#e5e7eb;
      padding:12px 14px;
      overflow-x:auto;
      font-family:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, &quot;Liberation Mono&quot;, monospace;
      font-size:0.9rem;
      line-height:1.6;
    }
    .macsettings_code pre{
      margin:0;
      white-space:pre;
    }

    .macsettings_checklist{
      margin:12px 0;
      padding:12px 14px;
      border:1px solid #e5e7eb;
      border-radius:12px;
      background:#fff;
    }
    .macsettings_checklist_title{
      margin:0 0 8px 0;
      font-weight:700;
      color:#111827;
      font-size:0.95rem;
    }
    .macsettings_checklist ul{
      margin:0;
      padding-left:18px;
    }

    .macsettings_kpi_grid{
      display:grid;
      grid-template-columns:repeat(2, minmax(0,1fr));
      gap:10px;
      margin:14px 0 6px;
    }
    .macsettings_kpi_card{
      border:1px solid #e5e7eb;
      border-radius:12px;
      padding:12px;
      background:#fff;
    }
    .macsettings_kpi_label{
      font-size:0.82rem;
      color:#6b7280;
      margin-bottom:4px;
    }
    .macsettings_kpi_value{
      font-size:1rem;
      font-weight:700;
      color:#111827;
      line-height:1.4;
    }

    .macsettings_reference{
      margin-top:30px;
      padding-top:16px;
      border-top:1px dashed #d1d5db;
    }
    .macsettings_reference h2{
      border-left-color:#64748b;
    }
    .macsettings_reference ul{
      margin:8px 0 0;
      padding-left:18px;
    }
    .macsettings_reference li{
      margin:6px 0;
      color:#374151;
    }

    .macsettings_tags{
      margin-top:24px;
      display:flex;
      flex-wrap:wrap;
      gap:8px;
    }
    .macsettings_tag{
      display:inline-flex;
      align-items:center;
      border:1px solid #dbeafe;
      background:#eff6ff;
      color:#1d4ed8;
      border-radius:999px;
      padding:6px 10px;
      font-size:0.86rem;
      font-weight:600;
    }

    .macsettings_footer_note{
      margin-top:20px;
      color:#6b7280;
      font-size:0.9rem;
    }

    .macsettings_terminal_cards_wrap{
      margin: 14px 0 8px;
    }
    .macsettings_terminal_grid{
      display:grid;
      grid-template-columns: repeat(3, minmax(0,1fr));
      gap:12px;
      margin-top:12px;
    }
    .macsettings_terminal_card{
      border:1px solid #e5e7eb;
      border-radius:14px;
      background:#fff;
      overflow:hidden;
      box-shadow: 0 1px 2px rgba(15,23,42,0.04);
    }
    .macsettings_terminal_card_head{
      padding:12px 14px;
      border-bottom:1px solid #eef2f7;
      background:#f8fafc;
    }
    .macsettings_terminal_card_title{
      margin:0;
      font-size:1rem;
      font-weight:800;
      color:#0f172a;
      letter-spacing:-0.01em;
    }
    .macsettings_terminal_card_sub{
      margin:4px 0 0;
      font-size:0.85rem;
      color:#64748b;
    }
    .macsettings_terminal_card_body{
      padding:12px 14px;
    }
    .macsettings_terminal_metric{
      display:flex;
      justify-content:space-between;
      align-items:flex-start;
      gap:8px;
      padding:8px 0;
      border-bottom:1px dashed #eef2f7;
    }
    .macsettings_terminal_metric:last-child{
      border-bottom:none;
      padding-bottom:0;
    }
    .macsettings_terminal_metric_key{
      font-size:0.88rem;
      color:#475569;
      min-width:100px;
      flex:0 0 100px;
    }
    .macsettings_terminal_metric_val{
      font-size:0.9rem;
      color:#111827;
      font-weight:600;
      text-align:right;
      line-height:1.4;
    }
    .macsettings_terminal_badges{
      display:flex;
      flex-wrap:wrap;
      gap:6px;
      margin-top:12px;
    }
    .macsettings_terminal_badge{
      display:inline-flex;
      align-items:center;
      padding:4px 8px;
      border-radius:999px;
      font-size:0.78rem;
      font-weight:700;
      border:1px solid #e5e7eb;
      background:#fff;
      color:#334155;
    }
    .macsettings_terminal_bestfor{
      margin-top:12px;
      padding:10px 11px;
      border-radius:10px;
      border:1px solid #e5e7eb;
      background:#fafafa;
      font-size:0.86rem;
      color:#334155;
      line-height:1.5;
    }
    .macsettings_terminal_bestfor strong{
      color:#111827;
    }
    .macsettings_terminal_compare_note{
      margin-top:12px;
      padding:12px 14px;
      border-radius:12px;
      border:1px solid #dbeafe;
      background:#eff6ff;
      color:#1e3a8a;
      font-size:0.93rem;
    }
    .macsettings_terminal_benchmark_box{
      margin-top:14px;
      border:1px solid #e5e7eb;
      border-radius:12px;
      background:#fff;
      padding:12px 14px;
    }
    .macsettings_terminal_benchmark_box h4{
      margin:0 0 8px;
      font-size:0.96rem;
      color:#0f172a;
    }
    .macsettings_terminal_benchmark_box ul{
      margin:0;
      padding-left:18px;
    }
    .macsettings_terminal_benchmark_box li{
      margin:4px 0;
      font-size:0.92rem;
      color:#334155;
    }

    @media (max-width: 980px){
      .macsettings_terminal_grid{
        grid-template-columns:1fr;
      }
      .macsettings_terminal_metric_key{
        flex:0 0 88px;
        min-width:88px;
      }
    }

    @media (max-width: 768px){
      .macsettings_title{ font-size:1.5rem; }
      .macsettings_kpi_grid{ grid-template-columns:1fr; }
      .macsettings_post_wrap{ padding:14px 12px 36px; }
    }
  &lt;/style&gt;
&lt;div class=&quot;macsettings_hero&quot;&gt;
&lt;div class=&quot;macsettings_badges&quot;&gt;&lt;span class=&quot;macsettings_badge&quot;&gt;2026 맥 개발환경&lt;/span&gt; &lt;span class=&quot;macsettings_badge&quot;&gt;Apple Silicon&lt;/span&gt; &lt;span class=&quot;macsettings_badge&quot;&gt;실사용 후기형 정리&lt;/span&gt; &lt;span class=&quot;macsettings_badge&quot;&gt;AI Agent Workflow&lt;/span&gt;&lt;/div&gt;
&lt;p class=&quot;macsettings_subtitle&quot; data-ke-size=&quot;size16&quot;&gt;최근 맥북을 새로 구매하고 처음 세팅하면서 직접 겪은 시행착오를 바탕으로, 개발자가 실제로 바로 적용할 수 있는 기준으로 정리한 실전 가이드입니다.&lt;/p&gt;
&lt;/div&gt;
&lt;section id=&quot;macsettings_intro&quot; class=&quot;macsettings_section&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;맥북 사고 세팅하면서 제일 많이 헤맸던 부분들&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;맥북을 최근에 새로 샀습니다. 처음에는 금방 끝날 줄 알았는데, 막상 세팅해보니 생각보다 시간이 많이 걸렸습니다. 정보는 많은데, 인텔 맥 기준 글과 Apple Silicon 기준 글이 섞여 있고, 도구 추천은 많은데 왜 그 조합이 좋은지 설명이 부족한 경우가 많았습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히 처음 세팅할 때 막혔던 포인트는 비슷했습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Homebrew 설치 경로와 PATH 설정&lt;/li&gt;
&lt;li&gt;터미널 선택 (Ghostty / iTerm2 / Warp)&lt;/li&gt;
&lt;li&gt;VSCode + 터미널 + AI 도구 조합 정리&lt;/li&gt;
&lt;li&gt;프로젝트별 런타임 버전 관리(asdf / direnv)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 이 글은 단순히 &amp;ldquo;좋은 앱 모음&amp;rdquo;이 아니라, &lt;b&gt;처음부터 다시 깔끔하게 잡는 맥 개발환경 기준&lt;/b&gt;을 성능 / 생산성 / 유지보수성 관점에서 한 번에 정리한 글입니다.&lt;/p&gt;
&lt;div class=&quot;macsettings_callout&quot;&gt;이 글의 목표는 &amp;ldquo;많이 설치하는 것&amp;rdquo;이 아니라 &amp;ldquo;덜 꼬이고 오래 쓰는 개발환경&amp;rdquo;입니다.&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;macsettings_body_1&quot; class=&quot;macsettings_section&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 개발하기 전에 먼저 바꾼 macOS 기본 설정들&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;타이핑/커서 이동이 답답해서 가장 먼저 손본 설정&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개발자는 하루에 타이핑과 커서 이동을 정말 많이 합니다. 그래서 macOS 기본값보다 키 반복 속도와 반복 지연 시간을 개발자 기준으로 조정해두는 게 체감 차이가 큽니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;키 반복 속도 : 빠르게&lt;/li&gt;
&lt;li&gt;반복 지연 시간 : 짧게&lt;/li&gt;
&lt;li&gt;자동 수정 / 자동 대문자 / 인라인 텍스트 예측 : 비활성화 권장&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;코딩할 때 방해되는 자동 보정 기능 끄기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반 문서 작성에는 유용한 기능이지만, 코드에서는 예약어/기호 입력을 깨뜨리는 경우가 있습니다. 특히 특수문자, 영문 약어, 변수명 입력이 많은 환경에서는 오히려 노이즈가 됩니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;트랙패드/창 관리 세팅 : 오래 작업해도 덜 피곤하게&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;세 손가락 드래그 활성화 (접근성 설정)&lt;/li&gt;
&lt;li&gt;Dock 자동 숨김&lt;/li&gt;
&lt;li&gt;창 전환/배치 습관화 (Raycast와 같이 쓰면 더 좋음)&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;macsettings_callout macsettings_callout_ok&quot;&gt;먼저 이 기본 설정을 잡아두면 이후 도구 세팅보다 먼저 &amp;ldquo;작업 감각&amp;rdquo;이 좋아집니다.&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;macsettings_body_2&quot; class=&quot;macsettings_section&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 애플 실리콘 맥에서 Homebrew부터 제대로 잡아야 하는 이유&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Apple Silicon 맥에서는 개발환경의 시작점이 거의 Homebrew라고 봐도 됩니다. 여기서 경로/PATH를 잘못 잡으면 이후 설치되는 도구들도 연쇄적으로 꼬일 수 있습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;필수 선행 : Xcode Command Line Tools 설치&lt;/h3&gt;
&lt;div class=&quot;macsettings_code&quot;&gt;
&lt;pre class=&quot;ada&quot;&gt;&lt;code&gt;xcode-select --install&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Apple Silicon 기준 Homebrew 경로 체크&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인텔 맥 시절 글과 달리, Apple Silicon 기준 Homebrew 기본 경로는 &lt;code&gt;/opt/homebrew&lt;/code&gt; 입니다. 예전 글 그대로 따라가면 여기서 헷갈리기 쉽습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;PATH 설정 (처음 세팅할 때 가장 자주 놓치는 부분)&lt;/h3&gt;
&lt;div class=&quot;macsettings_code&quot;&gt;
&lt;pre class=&quot;bash&quot;&gt;&lt;code&gt;eval &quot;$(/opt/homebrew/bin/brew shellenv)&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div class=&quot;macsettings_table_wrap&quot;&gt;
&lt;table class=&quot;macsettings_table&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;항목&lt;/th&gt;
&lt;th&gt;상세 내용&lt;/th&gt;
&lt;th&gt;실무 체크 포인트&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;설치 경로&lt;/td&gt;
&lt;td&gt;/opt/homebrew&lt;/td&gt;
&lt;td&gt;Apple Silicon 기준 경로 확인&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;선행 도구&lt;/td&gt;
&lt;td&gt;Xcode Command Line Tools&lt;/td&gt;
&lt;td&gt;brew 설치 전 선행 권장&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;환경 변수&lt;/td&gt;
&lt;td&gt;brew shellenv 등록&lt;/td&gt;
&lt;td&gt;.zprofile 반영 후 새 셸 재실행&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;정상 확인&lt;/td&gt;
&lt;td&gt;brew --version / which brew&lt;/td&gt;
&lt;td&gt;경로가 /opt/homebrew인지 확인&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class=&quot;macsettings_callout macsettings_callout_warn&quot;&gt;처음부터 패키지를 많이 깔기보다, brew 경로 인식과 PATH부터 정상인지 확인하고 진행하는 게 안전합니다.&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;macsettings_body_3&quot; class=&quot;macsettings_section&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 터미널 뭘 써야 할지 고민될 때, Ghostty vs iTerm2 vs Warp&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 세팅에서 가장 오래 고민한 부분 중 하나가 터미널이었습니다. 예전에는 iTerm2를 기본처럼 썼는데, 요즘은 Ghostty/Warp처럼 성격이 확실히 다른 선택지가 생겨서 &amp;ldquo;무엇을 기준으로 고를지&amp;rdquo;부터 다시 정리할 필요가 있었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제가 비교할 때 본 기준은 기능 개수보다 아래 항목들이었습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;입력 반응성 (타이핑 지연 체감)&lt;/li&gt;
&lt;li&gt;대용량 로그 출력/스크롤 안정성&lt;/li&gt;
&lt;li&gt;다중 탭/분할창 사용 시 부하&lt;/li&gt;
&lt;li&gt;tmux 사용 비중&lt;/li&gt;
&lt;li&gt;AI 기능 통합 필요 여부&lt;/li&gt;
&lt;li&gt;설정 방식 취향 (GUI vs 설정파일)&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;macsettings_terminal_cards_wrap&quot;&gt;
&lt;div class=&quot;macsettings_terminal_grid&quot;&gt;
&lt;article class=&quot;macsettings_terminal_card&quot;&gt;
&lt;div class=&quot;macsettings_terminal_card_head&quot;&gt;
&lt;h3 class=&quot;macsettings_terminal_card_title&quot; data-ke-size=&quot;size23&quot;&gt;Ghostty&lt;/h3&gt;
&lt;p class=&quot;macsettings_terminal_card_sub&quot; data-ke-size=&quot;size16&quot;&gt;고성능 &amp;middot; 저지연 &amp;middot; 미니멀 지향&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;macsettings_terminal_card_body&quot;&gt;
&lt;div class=&quot;macsettings_terminal_metric&quot;&gt;
&lt;div class=&quot;macsettings_terminal_metric_key&quot;&gt;핵심 포지션&lt;/div&gt;
&lt;div class=&quot;macsettings_terminal_metric_val&quot;&gt;성능/반응성 중심 터미널&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;macsettings_terminal_metric&quot;&gt;
&lt;div class=&quot;macsettings_terminal_metric_key&quot;&gt;입력 반응성&lt;/div&gt;
&lt;div class=&quot;macsettings_terminal_metric_val&quot;&gt;매우 빠름 (체감 우수)&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;macsettings_terminal_metric&quot;&gt;
&lt;div class=&quot;macsettings_terminal_metric_key&quot;&gt;로그 처리&lt;/div&gt;
&lt;div class=&quot;macsettings_terminal_metric_val&quot;&gt;대용량 출력/스크롤에 강점&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;macsettings_terminal_metric&quot;&gt;
&lt;div class=&quot;macsettings_terminal_metric_key&quot;&gt;설정 방식&lt;/div&gt;
&lt;div class=&quot;macsettings_terminal_metric_val&quot;&gt;설정 파일 기반&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;macsettings_terminal_metric&quot;&gt;
&lt;div class=&quot;macsettings_terminal_metric_key&quot;&gt;AI 관점&lt;/div&gt;
&lt;div class=&quot;macsettings_terminal_metric_val&quot;&gt;외부 도구 연동 중심&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;macsettings_terminal_badges&quot;&gt;&lt;span class=&quot;macsettings_terminal_badge&quot;&gt;성능 우선&lt;/span&gt; &lt;span class=&quot;macsettings_terminal_badge&quot;&gt;로그 작업&lt;/span&gt; &lt;span class=&quot;macsettings_terminal_badge&quot;&gt;미니멀&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;macsettings_terminal_bestfor&quot;&gt;&lt;b&gt;추천 시나리오 :&lt;/b&gt; 빌드 로그 / 스트리밍 로그를 오래 보고, 입력 반응성과 스크롤 부드러움을 중요하게 보는 개발자&lt;/div&gt;
&lt;/div&gt;
&lt;/article&gt;
&lt;article class=&quot;macsettings_terminal_card&quot;&gt;
&lt;div class=&quot;macsettings_terminal_card_head&quot;&gt;
&lt;h3 class=&quot;macsettings_terminal_card_title&quot; data-ke-size=&quot;size23&quot;&gt;iTerm2&lt;/h3&gt;
&lt;p class=&quot;macsettings_terminal_card_sub&quot; data-ke-size=&quot;size16&quot;&gt;기능 풍부 &amp;middot; 검증된 워크플로우 &amp;middot; 안정성&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;macsettings_terminal_card_body&quot;&gt;
&lt;div class=&quot;macsettings_terminal_metric&quot;&gt;
&lt;div class=&quot;macsettings_terminal_metric_key&quot;&gt;핵심 포지션&lt;/div&gt;
&lt;div class=&quot;macsettings_terminal_metric_val&quot;&gt;전통 강자 / 기능 중심&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;macsettings_terminal_metric&quot;&gt;
&lt;div class=&quot;macsettings_terminal_metric_key&quot;&gt;입력 반응성&lt;/div&gt;
&lt;div class=&quot;macsettings_terminal_metric_val&quot;&gt;안정적 (검증된 사용감)&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;macsettings_terminal_metric&quot;&gt;
&lt;div class=&quot;macsettings_terminal_metric_key&quot;&gt;로그 처리&lt;/div&gt;
&lt;div class=&quot;macsettings_terminal_metric_val&quot;&gt;무난~좋음 (설정 영향 큼)&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;macsettings_terminal_metric&quot;&gt;
&lt;div class=&quot;macsettings_terminal_metric_key&quot;&gt;설정 방식&lt;/div&gt;
&lt;div class=&quot;macsettings_terminal_metric_val&quot;&gt;GUI 기반 (세부 설정 강함)&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;macsettings_terminal_metric&quot;&gt;
&lt;div class=&quot;macsettings_terminal_metric_key&quot;&gt;AI 관점&lt;/div&gt;
&lt;div class=&quot;macsettings_terminal_metric_val&quot;&gt;외부 도구 연동 중심&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;macsettings_terminal_badges&quot;&gt;&lt;span class=&quot;macsettings_terminal_badge&quot;&gt;안정성&lt;/span&gt; &lt;span class=&quot;macsettings_terminal_badge&quot;&gt;GUI 설정&lt;/span&gt; &lt;span class=&quot;macsettings_terminal_badge&quot;&gt;tmux 친화&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;macsettings_terminal_bestfor&quot;&gt;&lt;b&gt;추천 시나리오 :&lt;/b&gt; tmux/서버 운영 비중이 높고, 기능 많은 터미널에 익숙한 파워 유저&lt;/div&gt;
&lt;/div&gt;
&lt;/article&gt;
&lt;article class=&quot;macsettings_terminal_card&quot;&gt;
&lt;div class=&quot;macsettings_terminal_card_head&quot;&gt;
&lt;h3 class=&quot;macsettings_terminal_card_title&quot; data-ke-size=&quot;size23&quot;&gt;Warp&lt;/h3&gt;
&lt;p class=&quot;macsettings_terminal_card_sub&quot; data-ke-size=&quot;size16&quot;&gt;AI 중심 &amp;middot; 앱형 UX &amp;middot; 생산성 워크플로우&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;macsettings_terminal_card_body&quot;&gt;
&lt;div class=&quot;macsettings_terminal_metric&quot;&gt;
&lt;div class=&quot;macsettings_terminal_metric_key&quot;&gt;핵심 포지션&lt;/div&gt;
&lt;div class=&quot;macsettings_terminal_metric_val&quot;&gt;AI 중심 생산성 터미널&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;macsettings_terminal_metric&quot;&gt;
&lt;div class=&quot;macsettings_terminal_metric_key&quot;&gt;입력 반응성&lt;/div&gt;
&lt;div class=&quot;macsettings_terminal_metric_val&quot;&gt;빠른 편 (기능 레이어 영향 가능)&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;macsettings_terminal_metric&quot;&gt;
&lt;div class=&quot;macsettings_terminal_metric_key&quot;&gt;로그 처리&lt;/div&gt;
&lt;div class=&quot;macsettings_terminal_metric_val&quot;&gt;무난 (환경/설정 의존)&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;macsettings_terminal_metric&quot;&gt;
&lt;div class=&quot;macsettings_terminal_metric_key&quot;&gt;설정 방식&lt;/div&gt;
&lt;div class=&quot;macsettings_terminal_metric_val&quot;&gt;앱형 UI / 입문 쉬움&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;macsettings_terminal_metric&quot;&gt;
&lt;div class=&quot;macsettings_terminal_metric_key&quot;&gt;AI 관점&lt;/div&gt;
&lt;div class=&quot;macsettings_terminal_metric_val&quot;&gt;내장형 경험 강점&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;macsettings_terminal_badges&quot;&gt;&lt;span class=&quot;macsettings_terminal_badge&quot;&gt;AI 보조&lt;/span&gt; &lt;span class=&quot;macsettings_terminal_badge&quot;&gt;생산성 UX&lt;/span&gt; &lt;span class=&quot;macsettings_terminal_badge&quot;&gt;입문 쉬움&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;macsettings_terminal_bestfor&quot;&gt;&lt;b&gt;추천 시나리오 :&lt;/b&gt; 명령어 탐색/실행과 AI 보조를 함께 쓰고, 터미널을 생산성 앱처럼 활용하는 워크플로우&lt;/div&gt;
&lt;/div&gt;
&lt;/article&gt;
&lt;/div&gt;
&lt;div class=&quot;macsettings_terminal_compare_note&quot;&gt;제 기준 결론 : &lt;b&gt;Ghostty는 성능/반응성&lt;/b&gt;, &lt;b&gt;iTerm2는 기능/안정성&lt;/b&gt;, &lt;b&gt;Warp는 AI 중심 UX&lt;/b&gt;가 확실히 다르게 느껴졌습니다. 무조건 하나가 최고라기보다, 내 작업 비중(로그/운영/AI보조)에 따라 선택하는 게 맞았습니다.&lt;/div&gt;
&lt;div class=&quot;macsettings_terminal_benchmark_box&quot;&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;실사용 벤치마크 체크리스트 (직접 비교 추천)&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;빠른 타이핑 시 입력 지연 체감 여부&lt;/li&gt;
&lt;li&gt;&lt;code&gt;docker logs -f&lt;/code&gt;, &lt;code&gt;kubectl logs -f&lt;/code&gt; 스트리밍 시 스크롤 끊김 여부&lt;/li&gt;
&lt;li&gt;탭 10개 이상 + 분할창 사용 시 부하/전환 속도&lt;/li&gt;
&lt;li&gt;tmux 사용 시 단축키 충돌/워크플로우 적합성&lt;/li&gt;
&lt;li&gt;장시간 실행 시 안정성 및 메모리 증가 체감&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;macsettings_body_4&quot; class=&quot;macsettings_section&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. zsh 꾸미기보다 먼저 한 생산성 자동화 설정&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;zsh 설정은 예쁘게 꾸미는 것보다 먼저, 반복 작업을 줄이는 방향으로 잡는 게 체감이 큽니다. 저는 프롬프트/플러그인을 최소화하고 alias/함수 위주로 먼저 정리했습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;추천 구성 (과하지 않게)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Oh-My-Zsh (기반)&lt;/li&gt;
&lt;li&gt;Powerlevel10k (프롬프트 정보 가시성)&lt;/li&gt;
&lt;li&gt;fzf (탐색 속도 개선)&lt;/li&gt;
&lt;li&gt;zsh-autosuggestions (명령어 오타/반복 입력 감소)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;실제로 자주 쓰게 된 alias / 함수 예시&lt;/h3&gt;
&lt;div class=&quot;macsettings_code&quot;&gt;
&lt;pre class=&quot;maxima&quot;&gt;&lt;code&gt;alias p=&quot;pnpm&quot;
alias s=&quot;source ~/.zshrc&quot;
alias cz=&quot;code ~/.zshrc&quot;
alias e=&quot;exit&quot;

killport() {
  lsof -i tcp:&quot;$1&quot; | awk 'NR!=1 {print $2}' | xargs kill -9
}

gfm() {
  git fetch origin main &amp;amp;&amp;amp; git merge origin/main
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div class=&quot;macsettings_callout&quot;&gt;포인트는 &amp;ldquo;멋있는 셸&amp;rdquo;이 아니라 &amp;ldquo;자주 반복하는 명령어를 줄이는 셸&amp;rdquo;입니다.&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;macsettings_body_5&quot; class=&quot;macsettings_section&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. 요즘 맥 개발환경에서 AI 도구를 붙이면 달라지는 점&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예전에는 AI 도구가 코드 자동완성 중심이었다면, 요즘은 작업 흐름 자체를 도와주는 쪽으로 많이 바뀌었습니다. 특히 터미널/에디터와 연결되는 에이전트형 도구를 붙이면 반복 작업이나 탐색 비용이 줄어드는 체감이 있습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Kiro CLI를 좁은 범위부터 붙이면 좋았던 이유&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;리팩토링 후보 찾기&lt;/li&gt;
&lt;li&gt;에러 원인 추적 보조&lt;/li&gt;
&lt;li&gt;테스트/스크립트 초안 생성&lt;/li&gt;
&lt;li&gt;대규모 코드베이스 탐색 보조&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;설치 예시&lt;/h3&gt;
&lt;div class=&quot;macsettings_code&quot;&gt;
&lt;pre class=&quot;groovy&quot;&gt;&lt;code&gt;curl -fsSL https://cli.kiro.dev/install | bash&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div class=&quot;macsettings_callout macsettings_callout_warn&quot;&gt;처음부터 모든 작업을 AI에게 맡기기보다, &amp;ldquo;탐색/초안/반복작업&amp;rdquo;처럼 검증 가능한 영역부터 붙이는 방식이 실무에서 더 안전합니다.&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;macsettings_body_6&quot; class=&quot;macsettings_section&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;6. VSCode + Raycast 조합이 생각보다 큰 차이를 만든 이유&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;VSCode : 확장보다 먼저 정리할 것&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;안 쓰는 확장 제거&lt;/li&gt;
&lt;li&gt;Settings Sync로 환경 재현성 확보&lt;/li&gt;
&lt;li&gt;&lt;code&gt;code .&lt;/code&gt; 실행 가능한 PATH 구성&lt;/li&gt;
&lt;li&gt;macOS 단축키 충돌 점검&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Raycast : 단순 실행기보다 작업 허브로 사용&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Window Management&lt;/li&gt;
&lt;li&gt;Clipboard History&lt;/li&gt;
&lt;li&gt;비밀번호 관리자 연동(Bitwarden / 1Password)&lt;/li&gt;
&lt;li&gt;단축키 중심 앱 전환&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;macsettings_kpi_grid&quot;&gt;
&lt;div class=&quot;macsettings_kpi_card&quot;&gt;
&lt;div class=&quot;macsettings_kpi_label&quot;&gt;체감 포인트 1&lt;/div&gt;
&lt;div class=&quot;macsettings_kpi_value&quot;&gt;도구 전환 시간 감소&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;macsettings_kpi_card&quot;&gt;
&lt;div class=&quot;macsettings_kpi_label&quot;&gt;체감 포인트 2&lt;/div&gt;
&lt;div class=&quot;macsettings_kpi_value&quot;&gt;마우스 의존도 감소&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;macsettings_kpi_card&quot;&gt;
&lt;div class=&quot;macsettings_kpi_label&quot;&gt;체감 포인트 3&lt;/div&gt;
&lt;div class=&quot;macsettings_kpi_value&quot;&gt;반복 작업 흐름 고정&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;macsettings_kpi_card&quot;&gt;
&lt;div class=&quot;macsettings_kpi_label&quot;&gt;체감 포인트 4&lt;/div&gt;
&lt;div class=&quot;macsettings_kpi_value&quot;&gt;맥락 전환 비용 감소&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;macsettings_body_7&quot; class=&quot;macsettings_section&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;7. 프로젝트마다 버전 달라서 꼬일 때 해결한 방식 (asdf + direnv)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로젝트마다 Node/Python/Java/.NET SDK 버전이 다르면 환경이 쉽게 꼬입니다. 이때 asdf + direnv 조합은 &amp;ldquo;내 PC에서는 되는데?&amp;rdquo; 문제를 줄이는 데 꽤 도움이 됩니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;asdf : 런타임 버전 통합 관리&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;여러 언어 버전 관리 도구를 하나로 통합&lt;/li&gt;
&lt;li&gt;&lt;code&gt;.tool-versions&lt;/code&gt; 파일로 팀 공유 가능&lt;/li&gt;
&lt;li&gt;프로젝트별 버전 고정에 유리&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;direnv : 프로젝트별 환경 변수 자동 로드&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;디렉토리 진입 시 &lt;code&gt;.envrc&lt;/code&gt; 자동 로드&lt;/li&gt;
&lt;li&gt;쉘 이탈 시 자동 언로드&lt;/li&gt;
&lt;li&gt;프로젝트별 API 키/DB 정보 분리에 유리&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;macsettings_callout&quot;&gt;버전 관리(asdf) + 환경 변수 관리(direnv)를 분리하면 유지보수성이 좋아지고, 프로젝트 이동도 훨씬 편해집니다.&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;macsettings_body_8&quot; class=&quot;macsettings_section&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;8. 맥에서 .NET 개발할 때 버전/패치를 더 자주 봐야 하는 이유&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;맥 기반 .NET 개발자는 로컬 SDK/런타임 상태를 주기적으로 점검하는 습관이 중요합니다. 특히 팀/서버 환경과 버전 차이가 나면, 로컬에서는 잘 되는데 배포 후 문제 나는 경우가 생기기 쉽습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2026년 기준 체크 포인트 (운영 관점)&lt;/h3&gt;
&lt;div class=&quot;macsettings_table_wrap&quot;&gt;
&lt;table class=&quot;macsettings_table&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;버전&lt;/th&gt;
&lt;th&gt;상태&lt;/th&gt;
&lt;th&gt;패치 예시 (2026-02 기준)&lt;/th&gt;
&lt;th&gt;실무 포인트&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;.NET 10&lt;/td&gt;
&lt;td&gt;LTS (Active)&lt;/td&gt;
&lt;td&gt;10.0.3&lt;/td&gt;
&lt;td&gt;신규/장기 운영 검토&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;.NET 9&lt;/td&gt;
&lt;td&gt;STS (Active)&lt;/td&gt;
&lt;td&gt;9.0.13&lt;/td&gt;
&lt;td&gt;기능 활용 + 정기 패치 필수&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;.NET 8&lt;/td&gt;
&lt;td&gt;LTS (Active)&lt;/td&gt;
&lt;td&gt;8.0.24&lt;/td&gt;
&lt;td&gt;안정 운영 환경에 적합&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class=&quot;macsettings_checklist&quot;&gt;
&lt;p class=&quot;macsettings_checklist_title&quot; data-ke-size=&quot;size16&quot;&gt;실무에서 바로 적용하기 좋은 운영 습관&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;global.json으로 SDK 버전 고정&lt;/li&gt;
&lt;li&gt;월 1회 이상 SDK/런타임 점검&lt;/li&gt;
&lt;li&gt;로컬/CI/서버 버전 차이 확인 루틴 만들기&lt;/li&gt;
&lt;li&gt;보안 패치 포함 릴리스 노트 확인&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;macsettings_outro&quot; class=&quot;macsettings_section&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;마무리 - 이번 세팅하면서 느낀 점 (도구보다 순서가 중요했다)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번에 맥북을 새로 세팅하면서 가장 크게 느낀 점은, 좋은 도구를 많이 설치하는 것보다 &lt;b&gt;어떤 순서로 환경을 잡는지&lt;/b&gt;가 훨씬 중요하다는 점이었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정리하면 제 기준 핵심은 이 세 가지였습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;반응성 최적화&lt;/b&gt; : 입력 지연과 창 전환 비용 줄이기&lt;/li&gt;
&lt;li&gt;&lt;b&gt;관리 가능한 환경&lt;/b&gt; : Homebrew + asdf + direnv로 일관성 확보&lt;/li&gt;
&lt;li&gt;&lt;b&gt;지능형 워크플로우&lt;/b&gt; : Ghostty + AI 도구 + VSCode/Raycast 조합&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음 맥 개발환경을 세팅하는 분들에게는 기본 틀로, 이미 사용 중인 분들에게는 환경 점검 체크리스트로 도움이 되었으면 좋겠습니다. 저도 이후에는 실제로 쓰는 dotfiles와 프로젝트 템플릿 기준으로 더 구체적인 세팅 글을 이어서 정리해볼 생각입니다.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;macsettings_refs&quot; class=&quot;macsettings_section macsettings_reference&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;참고자료&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Homebrew 공식 설치/설정 문서 (Apple Silicon 경로 및 shellenv 기준 확인)&lt;/li&gt;
&lt;li&gt;Ghostty 공식 문서 (macOS 기능 및 렌더링 관련 내용 확인)&lt;/li&gt;
&lt;li&gt;Kiro CLI 공식 사이트/CLI 설치 문서&lt;/li&gt;
&lt;li&gt;.NET 공식 다운로드 / 릴리스 정보 (8/9/10 버전 및 패치 확인)&lt;/li&gt;
&lt;li&gt;Raycast 공식 문서 (확장/단축키 운영 참고)&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;macsettings_footer_note&quot; data-ke-size=&quot;size16&quot;&gt;버전/설치 명령/패치 정보는 시점에 따라 변동될 수 있으므로, 실제 적용 전 공식 문서를 기준으로 최종 확인하는 것을 권장합니다.&lt;/p&gt;
&lt;/section&gt;
&lt;div class=&quot;macsettings_tags&quot; aria-label=&quot;태그&quot;&gt;&lt;span class=&quot;macsettings_tag&quot;&gt;#맥북개발환경&lt;/span&gt; &lt;span class=&quot;macsettings_tag&quot;&gt;#AppleSilicon&lt;/span&gt; &lt;span class=&quot;macsettings_tag&quot;&gt;#MacOS최적화&lt;/span&gt; &lt;span class=&quot;macsettings_tag&quot;&gt;#Homebrew&lt;/span&gt; &lt;span class=&quot;macsettings_tag&quot;&gt;#Ghostty&lt;/span&gt; &lt;span class=&quot;macsettings_tag&quot;&gt;#iTerm2&lt;/span&gt; &lt;span class=&quot;macsettings_tag&quot;&gt;#Warp&lt;/span&gt; &lt;span class=&quot;macsettings_tag&quot;&gt;#KiroCLI&lt;/span&gt; &lt;span class=&quot;macsettings_tag&quot;&gt;#VSCode세팅&lt;/span&gt; &lt;span class=&quot;macsettings_tag&quot;&gt;#닷넷개발환경&lt;/span&gt;&lt;/div&gt;
&lt;script type=&quot;application/ld+json&quot;&gt;
  {
    &quot;@context&quot;:&quot;https://schema.org&quot;,
    &quot;@type&quot;:&quot;BlogPosting&quot;,
    &quot;headline&quot;:&quot;2026년형 애플 실리콘 맥 개발환경 세팅 완전정리 : Homebrew·Ghostty·Kiro CLI·VSCode·.NET 최적화 전략&quot;,
    &quot;description&quot;:&quot;최근 맥북을 새로 구매하고 처음 세팅하면서 겪은 시행착오를 바탕으로, Apple Silicon 맥 개발환경을 성능·생산성·유지보수성 기준으로 정리한 실전 가이드.&quot;,
    &quot;keywords&quot;:[&quot;맥북 개발환경&quot;,&quot;Apple Silicon&quot;,&quot;Homebrew&quot;,&quot;Ghostty&quot;,&quot;iTerm2&quot;,&quot;Warp&quot;,&quot;Kiro CLI&quot;,&quot;VSCode&quot;,&quot;.NET&quot;,&quot;asdf&quot;,&quot;direnv&quot;],
    &quot;inLanguage&quot;:&quot;ko-KR&quot;
  }
  &lt;/script&gt;
&lt;/div&gt;</description>
      <category>DEVELOPMENT</category>
      <category>homebrew</category>
      <category>MacOS</category>
      <category>개발자</category>
      <category>개발환경</category>
      <category>맥북</category>
      <category>설정방법</category>
      <category>애플</category>
      <category>윈도우</category>
      <category>초보</category>
      <category>터미널</category>
      <author>간지뽕빨리턴님</author>
      <guid isPermaLink="true">https://odinbox.tistory.com/573</guid>
      <comments>https://odinbox.tistory.com/573#entry573comment</comments>
      <pubDate>Sun, 1 Mar 2026 10:20:41 +0900</pubDate>
    </item>
    <item>
      <title>카카오맵 + OSRM 연동 경로 탐색 및 폴리라인 구현 방법</title>
      <link>https://odinbox.tistory.com/572</link>
      <description>&lt;div&gt;
&lt;style&gt;
  .osrm-post{
    max-width:980px;
    margin:0 auto;
    padding:8px 4px 28px;
    color:#111827;
    font-family:&quot;Pretendard&quot;,&quot;Noto Sans KR&quot;,&quot;Apple SD Gothic Neo&quot;,&quot;Malgun Gothic&quot;,sans-serif;
    line-height:1.85;
    word-break:keep-all;
  }
  .osrm-post *{box-sizing:border-box;}
  .osrm-post .hero{
    border:1px solid #e5e7eb;
    background:linear-gradient(135deg,#eff6ff 0%, #ffffff 55%, #f8fafc 100%);
    border-radius:16px;
    padding:20px 18px;
    margin:4px 0 14px;
  }
  .osrm-post .badge-wrap{display:flex;flex-wrap:wrap;gap:8px;margin-bottom:10px;}
  .osrm-post .badge{
    display:inline-flex;align-items:center;
    padding:5px 10px;border-radius:999px;border:1px solid #e5e7eb;
    background:#fff;color:#4b5563;font-size:12px;
  }
  .osrm-post h1{
    margin:0 0 10px;
    font-size:26px;line-height:1.35;letter-spacing:-0.02em;
    color:#0f172a;
  }
  .osrm-post .lead{
    margin:0;
    color:#374151;
    font-size:15px;
  }
  .osrm-post .meta{
    margin-top:10px;
    display:flex;flex-wrap:wrap;gap:8px 12px;
    color:#6b7280;font-size:13px;
  }

  .osrm-post .hero-thumb{
    margin:0 0 18px;
    padding:10px;
    border:1px solid #e5e7eb;
    border-radius:16px;
    background:#fff;
    box-shadow:0 6px 20px rgba(15,23,42,.04);
  }
  .osrm-post .hero-thumb &gt; p{
    margin:0 !important;
    text-align:center;
  }
  .osrm-post .hero-thumb img{
    display:block;
    margin:0 auto;
    max-width:100%;
    height:auto;
    border-radius:12px;
  }

  .osrm-post h2{
    margin:34px 0 12px;
    padding-bottom:8px;
    border-bottom:2px solid #eef2f7;
    font-size:20px;
    line-height:1.45;
    letter-spacing:-0.01em;
    color:#111827;
  }
  .osrm-post h3{
    margin:22px 0 10px;
    font-size:16px;
    line-height:1.5;
    letter-spacing:-0.01em;
    color:#111827;
  }

  .osrm-post p{margin:10px 0 12px;}
  .osrm-post ul{margin:8px 0 12px;padding-left:20px;}
  .osrm-post li{margin:6px 0;}
  .osrm-post strong{color:#111827;}

  .osrm-post .inline-code{
    display:inline-block;
    background:#f3f4f6;
    border:1px solid #e5e7eb;
    border-radius:6px;
    padding:0 6px;
    font-family:Consolas,&quot;D2Coding&quot;,monospace;
    font-size:.94em;
    line-height:1.6;
  }

  .osrm-post .card{
    border:1px solid #e5e7eb;
    background:#f9fafb;
    border-radius:14px;
    padding:14px;
    margin:14px 0;
  }
  .osrm-post .callout{
    border:1px solid #bfdbfe;
    background:#eef5ff;
    border-radius:12px;
    padding:12px 14px;
    margin:14px 0;
  }
  .osrm-post .warn{
    border:1px solid #fdba74;
    background:#fff7ed;
    border-radius:12px;
    padding:12px 14px;
    margin:14px 0;
  }
  .osrm-post .good{
    border:1px solid #86efac;
    background:#f0fdf4;
    border-radius:12px;
    padding:12px 14px;
    margin:14px 0;
  }

  .osrm-post .grid-2{
    display:grid;
    grid-template-columns:1fr 1fr;
    gap:12px;
    margin:10px 0 14px;
  }
  .osrm-post .grid-2 &gt; div{
    border:1px solid #e5e7eb;
    background:#fff;
    border-radius:12px;
    padding:12px;
  }
  .osrm-post .grid-2 h4{
    margin:0 0 6px;
    font-size:14px;
    color:#111827;
  }

  .osrm-post .table-wrap{
    overflow-x:auto;
    border:1px solid #e5e7eb;
    border-radius:12px;
    background:#fff;
    margin:12px 0 14px;
  }
  .osrm-post table{
    width:100%;
    min-width:720px;
    border-collapse:collapse;
    font-size:14px;
  }
  .osrm-post th, .osrm-post td{
    text-align:left;
    vertical-align:top;
    padding:10px 10px;
    border-bottom:1px solid #e5e7eb;
  }
  .osrm-post th{
    background:#f8fafc;
    font-weight:700;
  }

  .osrm-post hr{
    border:0;
    border-top:1px solid #e5e7eb;
    margin:28px 0;
  }

  .osrm-post details.faq{
    border:1px solid #e5e7eb;
    border-radius:12px;
    background:#fff;
    margin:10px 0;
    overflow:hidden;
  }
  .osrm-post details.faq summary{
    cursor:pointer;
    list-style:none;
    padding:12px 14px;
    font-weight:700;
    background:#f9fafb;
    border-bottom:1px solid #e5e7eb;
  }
  .osrm-post details.faq summary::-webkit-details-marker{display:none;}
  .osrm-post details.faq .faq-body{padding:12px 14px;}

  .osrm-post .foot{
    border:1px solid #e5e7eb;
    border-radius:14px;
    background:linear-gradient(180deg,#fff,#f8fafc);
    padding:14px;
    margin-top:16px;
  }
  .osrm-post .kv{
    display:grid;
    grid-template-columns:120px 1fr;
    gap:6px 10px;
    font-size:14px;
  }
  .osrm-post .kv div:nth-child(odd){
    color:#6b7280;
    font-weight:600;
  }

  @media (max-width:768px){
    .osrm-post{padding:6px 2px 18px;line-height:1.75;}
    .osrm-post h1{font-size:20px;}
    .osrm-post h2{font-size:18px;}
    .osrm-post .grid-2{grid-template-columns:1fr;}
    .osrm-post .kv{grid-template-columns:1fr;}
    .osrm-post .hero-thumb{padding:8px;border-radius:14px;}
  }
&lt;/style&gt;
&lt;/div&gt;
&lt;article class=&quot;osrm-post&quot;&gt;&lt;header class=&quot;hero&quot;&gt;
&lt;div class=&quot;badge-wrap&quot;&gt;&lt;span class=&quot;badge&quot;&gt;카카오맵 API&lt;/span&gt; &lt;span class=&quot;badge&quot;&gt;OSRM&lt;/span&gt; &lt;span class=&quot;badge&quot;&gt;경로탐색&lt;/span&gt; &lt;span class=&quot;badge&quot;&gt;Polyline&lt;/span&gt; &lt;span class=&quot;badge&quot;&gt;Docker&lt;/span&gt; &lt;span class=&quot;badge&quot;&gt;추적관리 시스템&lt;/span&gt;&lt;/div&gt;
&lt;p class=&quot;lead&quot; data-ke-size=&quot;size16&quot;&gt;실무에서 추적관리(관제) 프로그램을 개발하면서 지도 위에 자산/차량의 이동 경로를 안정적으로 표시하고, 반복적으로 경로를 계산해야 하는 요구사항이 생겼습니다. 이 과정에서 상용 길찾기 API의 비용 구조와 호출 제한, 운영 환경에서의 확장성 문제를 직접 마주했고, 그 대안으로 &lt;b&gt;카카오맵 + OSRM 조합&lt;/b&gt;을 적용했습니다.&lt;/p&gt;
&lt;div class=&quot;meta&quot;&gt;&lt;span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;핵심 포인트 : 좌표 순서 변환 + 렌더링 관리&lt;/span&gt;&lt;/span&gt; &lt;span&gt;실전 코드 : Kakao Polyline + OSRM Route API&lt;/span&gt;&lt;/div&gt;
&lt;/header&gt;&lt;!-- 상단 대표 이미지 (사용자 제공 티스토리 이미지 태그) --&gt;
&lt;div class=&quot;hero-thumb&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;글 상단 부분 대표 이미지.png&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rkbC7/dJMcaf6Gduy/PA0eQm607ErN3aF7IpBA3k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rkbC7/dJMcaf6Gduy/PA0eQm607ErN3aF7IpBA3k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rkbC7/dJMcaf6Gduy/PA0eQm607ErN3aF7IpBA3k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrkbC7%2FdJMcaf6Gduy%2FPA0eQm607ErN3aF7IpBA3k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;400&quot; data-filename=&quot;글 상단 부분 대표 이미지.png&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;div class=&quot;card&quot;&gt;&lt;b&gt;작성 배경&lt;/b&gt;&lt;br /&gt;실제 추적관리 프로그램(위치/이동 이력 관제 성격의 시스템)을 개발하던 중, 지도 렌더링은 카카오맵으로 처리하면서 경로 계산은 비용 효율적으로 운영할 수 있는 구조가 필요했습니다. 단순 데모가 아니라 재조회, 실시간 갱신, 다회 렌더링, 운영 안정성까지 고려해야 했기 때문에 OSRM을 연동하는 방식으로 설계했고, 적용 후 구조가 안정적으로 정리되었습니다.&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;왜 카카오맵 + OSRM 조합을 선택했는가&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위치 기반 서비스(LBS), 물류, 관제, 자산 추적 시스템에서는 &lt;b&gt;출발지~목적지 경로 계산&lt;/b&gt;과 &lt;b&gt;지도 위 경로 시각화&lt;/b&gt;가 핵심 기능입니다. 하지만 상용 길 찾기 API는 호출량이 늘어날수록 비용 부담이 커지고, 대규모 트래픽 환경에서는 비용 예측이 어려워질 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실무에서 추적관리 프로그램을 개발하다 보면 단순 1회 경로 계산이 아니라, 경로 재계산, 다중 자산 모니터링, 반복 조회, 화면 갱신 등의 요구가 계속 발생합니다. 이런 환경에서는 &lt;b&gt;지도 UI와 경로 계산 엔진을 분리&lt;/b&gt;하는 설계가 운영 비용과 유지보수 측면에서 매우 유리합니다.&lt;/p&gt;
&lt;div class=&quot;callout&quot;&gt;&lt;b&gt;핵심 아키텍처 분리 전략&lt;/b&gt;&lt;br /&gt;&lt;span class=&quot;inline-code&quot;&gt;카카오맵&lt;/span&gt;은 사용자에게 친숙한 국내 지도 UI/POI/오버레이 렌더링을 담당하고, &lt;span class=&quot;inline-code&quot;&gt;OSRM&lt;/span&gt;은 경로 계산(거리/시간/최적 경로) 전담 엔진으로 사용합니다. 이렇게 분리하면 실무에서 비용, 성능, 확장성 모두 잡기 쉬워집니다.&lt;/div&gt;
&lt;div class=&quot;grid-2&quot;&gt;
&lt;div&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;카카오맵이 좋은 이유&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;국내 사용자에게 익숙한 지도 UX&lt;/li&gt;
&lt;li&gt;마커/폴리라인/오버레이 렌더링 편의성&lt;/li&gt;
&lt;li&gt;국내 서비스에 적합한 POI 표현&lt;/li&gt;
&lt;li&gt;프론트엔드 구현 속도가 빠름&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;OSRM이 좋은 이유&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;오픈소스 기반으로 비용 부담 완화&lt;/li&gt;
&lt;li&gt;고성능 라우팅 엔진 (대규모 도로망 대응)&lt;/li&gt;
&lt;li&gt;자체 서버 운영 가능 (온프레미스/클라우드)&lt;/li&gt;
&lt;li&gt;프로파일/Lua 커스터마이징 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;가장 중요한 포인트 : 좌표 순서가 다르다&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;카카오맵과 OSRM을 연동할 때 가장 많이 실수하는 부분은 &lt;b&gt;좌표 순서&lt;/b&gt;입니다. 이 부분만 정확히 이해해도 경로가 엉뚱한 위치에 찍히는 문제를 대부분 방지할 수 있습니다.&lt;/p&gt;
&lt;div class=&quot;warn&quot;&gt;&lt;b&gt;좌표 순서 규칙&lt;/b&gt;&lt;br /&gt;OSRM 입력/응답 좌표 : &lt;span class=&quot;inline-code&quot;&gt;[경도, 위도] = [lng, lat]&lt;/span&gt;&lt;br /&gt;카카오맵 LatLng 생성자 : &lt;span class=&quot;inline-code&quot;&gt;new kakao.maps.LatLng(lat, lng)&lt;/span&gt;&lt;br /&gt;즉, OSRM 좌표를 카카오맵에 넣기 전에 &lt;b&gt;순서를 뒤집어야&lt;/b&gt; 합니다.&lt;/div&gt;
&lt;div class=&quot;card&quot;&gt;&lt;b&gt;실무 팁&lt;/b&gt;&lt;br /&gt;팀 내 공통 유틸 함수(예 : &lt;span class=&quot;inline-code&quot;&gt;toKakaoLatLng(osrmCoord)&lt;/span&gt;)를 만들어두면 좌표 순서 실수를 크게 줄일 수 있습니다.&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;OSRM Route API 요청 구조와 필수 옵션&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반적인 Route API 호출 구조는 아래와 같습니다. 실무에서는 &lt;span class=&quot;inline-code&quot;&gt;overview&lt;/span&gt;와 &lt;span class=&quot;inline-code&quot;&gt;geometries&lt;/span&gt; 선택이 특히 중요합니다.&lt;/p&gt;
&lt;pre class=&quot;codeblock awk&quot; data-ke-language=&quot;text&quot;&gt;&lt;code&gt;GET http://{osrm-server}:{port}/route/v1/driving/{lng,lat;lng,lat}?overview=full&amp;amp;geometries=geojson&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;table-wrap&quot;&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;옵션&lt;/th&gt;
&lt;th&gt;권장값&lt;/th&gt;
&lt;th&gt;설명&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;overview&lt;/td&gt;
&lt;td&gt;full&lt;/td&gt;
&lt;td&gt;도로 굴곡까지 자연스럽게 폴리라인을 그리려면 full 권장&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;geometries&lt;/td&gt;
&lt;td&gt;geojson / polyline&lt;/td&gt;
&lt;td&gt;개발 편의성은 geojson, 네트워크 최적화는 polyline 유리&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;steps&lt;/td&gt;
&lt;td&gt;false (기본)&lt;/td&gt;
&lt;td&gt;턴바이턴 안내가 필요할 때만 true 사용&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;alternatives&lt;/td&gt;
&lt;td&gt;false (기본)&lt;/td&gt;
&lt;td&gt;대체 경로가 필요한 경우에만 true 설정&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;annotations&lt;/td&gt;
&lt;td&gt;필요 시만&lt;/td&gt;
&lt;td&gt;세그먼트별 거리/시간/속도 분석이 필요할 때 사용&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;GeoJSON vs Polyline 선택 기준 (실무 의사결정 포인트)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;경로 geometry 응답은 &lt;span class=&quot;inline-code&quot;&gt;geometries=geojson&lt;/span&gt; 또는 &lt;span class=&quot;inline-code&quot;&gt;geometries=polyline&lt;/span&gt; 중 하나를 선택하게 됩니다. 프로젝트 단계(초기 개발/운영 확장)에 따라 선택 전략이 달라집니다.&lt;/p&gt;
&lt;div class=&quot;grid-2&quot;&gt;
&lt;div&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;GeoJSON 추천 상황&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;PoC, 초기 구현, 빠른 검증&lt;/li&gt;
&lt;li&gt;브라우저 파싱 직관성이 중요할 때&lt;/li&gt;
&lt;li&gt;팀 내 온보딩 속도를 높이고 싶을 때&lt;/li&gt;
&lt;li&gt;내부망/트래픽 부담이 상대적으로 낮을 때&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Polyline 추천 상황&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;모바일/대규모 트래픽 운영&lt;/li&gt;
&lt;li&gt;응답 페이로드 크기 최적화가 중요할 때&lt;/li&gt;
&lt;li&gt;OSRM 호출량이 많은 서비스&lt;/li&gt;
&lt;li&gt;클라이언트 디코딩 비용을 감수할 수 있을 때&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;good&quot;&gt;&lt;b&gt;실무 추천 전략&lt;/b&gt;&lt;br /&gt;초기엔 &lt;span class=&quot;inline-code&quot;&gt;GeoJSON&lt;/span&gt;으로 빠르게 구현하고, 운영 트래픽이 커지면 &lt;span class=&quot;inline-code&quot;&gt;Polyline&lt;/span&gt;으로 전환하는 단계적 접근이 가장 현실적입니다.&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;카카오맵 + OSRM 연동 실전 예제 (GeoJSON 기준)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 예제는 카카오맵에 OSRM 경로를 폴리라인으로 그리는 기본 구조이면서, 실무에서 자주 필요한 &lt;b&gt;재호출 시 이전 폴리라인 제거&lt;/b&gt;, &lt;b&gt;AbortController로 요청 취소&lt;/b&gt;, &lt;b&gt;setBounds 자동 화면 맞춤&lt;/b&gt;까지 포함한 형태입니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1) index.html&lt;/h3&gt;
&lt;pre class=&quot;codeblock xml&quot; data-ke-language=&quot;html&quot;&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html lang=&quot;ko&quot;&amp;gt;
&amp;lt;head&amp;gt;
  &amp;lt;meta charset=&quot;utf-8&quot; /&amp;gt;
  &amp;lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot; /&amp;gt;
  &amp;lt;title&amp;gt;Kakao + OSRM Route Demo&amp;lt;/title&amp;gt;
  &amp;lt;style&amp;gt;
    html, body { margin:0; padding:0; height:100%; }
    #map { width:100%; height:100vh; }
    .panel{
      position:absolute; top:16px; left:16px; z-index:10;
      background:rgba(255,255,255,.96); padding:14px;
      border-radius:10px; box-shadow:0 8px 20px rgba(0,0,0,.12);
      font-family:&quot;Malgun Gothic&quot;, sans-serif;
      width:min(92vw, 380px);
    }
    .panel h3{ margin:0 0 10px; font-size:16px; }
    .panel button{
      border:0; background:#FEE500; color:#222; font-weight:700;
      border-radius:8px; padding:10px 12px; cursor:pointer;
    }
    .panel button:disabled{ opacity:.65; cursor:not-allowed; }
    #meta{ margin-top:10px; font-size:13px; color:#444; line-height:1.5; }
  &amp;lt;/style&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
  &amp;lt;div class=&quot;panel&quot;&amp;gt;
    &amp;lt;h3&amp;gt;OSRM 경로 탐색&amp;lt;/h3&amp;gt;
    &amp;lt;button id=&quot;btnRoute&quot; type=&quot;button&quot; onclick=&quot;calculateAndDrawRoute()&quot;&amp;gt;경로 계산 및 표시&amp;lt;/button&amp;gt;
    &amp;lt;p id=&quot;meta&quot;&amp;gt;버튼을 눌러 경로를 탐색하세요.&amp;lt;/p&amp;gt;
  &amp;lt;/div&amp;gt;

  &amp;lt;div id=&quot;map&quot;&amp;gt;&amp;lt;/div&amp;gt;

  &amp;lt;script src=&quot;//dapi.kakao.com/v2/maps/sdk.js?appkey=YOUR_KAKAO_APP_KEY&quot;&amp;gt;&amp;lt;/script&amp;gt;
  &amp;lt;script src=&quot;./osrm-kakao-integration.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2) osrm-kakao-integration.js&lt;/h3&gt;
&lt;pre class=&quot;codeblock javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;let activePolyline = null;
let startMarker = null;
let endMarker = null;
let currentAbortController = null;

const map = new kakao.maps.Map(document.getElementById('map'), {
  center : new kakao.maps.LatLng(37.382239, 127.121755),
  level : 5
});

const metaEl = document.getElementById('meta');
const btnEl = document.getElementById('btnRoute');

async function calculateAndDrawRoute() {
  // 예시 좌표 (판교역 -&amp;gt; 정자역 부근)
  const origin = { lat : 37.394726, lng : 127.111158 };
  const destination = { lat : 37.367317, lng : 127.108847 };

  // 퍼블릭 OSRM 서버 (데모/테스트용)
  // 실서비스에서는 자체 OSRM 서버 또는 백엔드 프록시 권장
  const osrmBaseUrl = 'https://router.project-osrm.org/route/v1/driving/';

  // OSRM 좌표 순서 : [lng, lat]
  const coordinatesString = `${origin.lng},${origin.lat};${destination.lng},${destination.lat}`;

  // 폴리라인 렌더링에 유리한 전체 경로 + GeoJSON
  const queryParams = '?overview=full&amp;amp;geometries=geojson&amp;amp;alternatives=false&amp;amp;steps=false';
  const requestUrl = osrmBaseUrl + coordinatesString + queryParams;

  // 이전 요청 취소 (연속 클릭/갱신 시 레이스 컨디션 방지)
  if (currentAbortController) currentAbortController.abort();
  currentAbortController = new AbortController();

  btnEl.disabled = true;
  metaEl.innerText = '경로 계산 중입니다...';

  try {
    const res = await fetch(requestUrl, { signal : currentAbortController.signal });
    if (!res.ok) throw new Error(`HTTP ${res.status}`);

    const data = await res.json();

    if (data.code !== 'Ok' || !data.routes || data.routes.length === 0) {
      throw new Error(`OSRM error : ${data.code || 'NoRoute'}`);
    }

    const route = data.routes[0];
    const coords = route.geometry &amp;amp;&amp;amp; route.geometry.coordinates ? route.geometry.coordinates  : [];
    if (coords.length === 0) throw new Error('Empty geometry');

    const distanceKm = (route.distance / 1000).toFixed(2);
    const durationMin = Math.round(route.duration / 60);
    metaEl.innerText = `총 거리 : ${distanceKm}km / 예상 시간 : ${durationMin}분`;

    const linePath = [];
    const bounds = new kakao.maps.LatLngBounds();

    // OSRM [lng, lat] -&amp;gt; Kakao LatLng(lat, lng)
    coords.forEach(([lng, lat]) =&amp;gt; {
      const p = new kakao.maps.LatLng(lat, lng);
      linePath.push(p);
      bounds.extend(p);
    });

    // 기존 오버레이 정리 (누적 렌더링 방지)
    if (activePolyline) activePolyline.setMap(null);
    if (startMarker) startMarker.setMap(null);
    if (endMarker) endMarker.setMap(null);

    activePolyline = new kakao.maps.Polyline({
      path : linePath,
      strokeWeight : 6,
      strokeColor : '#2563EB',
      strokeOpacity : 0.9,
      strokeStyle : 'solid',
      endArrow : true
    });
    activePolyline.setMap(map);

    startMarker = new kakao.maps.Marker({ position : linePath[0], map });
    endMarker = new kakao.maps.Marker({ position : linePath[linePath.length - 1], map });

    // 경로 전체가 보이도록 자동 포커싱
    map.setBounds(bounds);

  } catch (e) {
    if (e.name === 'AbortError') return; // 이전 요청 취소는 정상 흐름
    console.error(e);
    metaEl.innerText = '오류가 발생했습니다. 콘솔 로그를 확인하세요.';
    alert('OSRM 경로 탐색/렌더링 중 오류가 발생했습니다.');
  } finally {
    btnEl.disabled = false;
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;warn&quot;&gt;&lt;b&gt;운영 주의사항&lt;/b&gt;&lt;br /&gt;&lt;span class=&quot;inline-code&quot;&gt;router.project-osrm.org&lt;/span&gt;는 퍼블릭 테스트 서버이므로 상업 서비스에 그대로 사용하는 것은 권장되지 않습니다. 실서비스는 자체 OSRM 서버 또는 백엔드 프록시(BFF) 구조를 권장합니다.&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Docker로 자체 OSRM 서버 구축하기 (실서비스 전환용)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;운영 단계에서는 OSRM 퍼블릭 서버 대신 자체 OSRM 백엔드를 구성하는 것이 안정적입니다. 아래는 대한민국 OSM PBF 데이터를 기준으로 한 기본 구축 예시입니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1) 대한민국 OSM 데이터 다운로드&lt;/h3&gt;
&lt;pre class=&quot;codeblock awk&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;wget http://download.geofabrik.de/asia/south-korea-latest.osm.pbf&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2) OSRM 전처리 (MLD 파이프라인)&lt;/h3&gt;
&lt;pre class=&quot;codeblock dockerfile&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;sudo docker run -t -v &quot;${PWD}:/data&quot; osrm/osrm-backend \
  osrm-extract -p /opt/car.lua /data/south-korea-latest.osm.pbf

sudo docker run -t -v &quot;${PWD}:/data&quot; osrm/osrm-backend \
  osrm-partition /data/south-korea-latest.osrm

sudo docker run -t -v &quot;${PWD}:/data&quot; osrm/osrm-backend \
  osrm-customize /data/south-korea-latest.osrm&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3) OSRM 라우팅 서버 실행&lt;/h3&gt;
&lt;pre class=&quot;codeblock applescript&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;sudo docker run -d -p 5000:5000 --name osrm-routing-server \
  -v &quot;${PWD}:/data&quot; osrm/osrm-backend \
  osrm-routed --algorithm mld /data/south-korea-latest.osrm&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;callout&quot;&gt;&lt;b&gt;실무 추천 운영 구조&lt;/b&gt;&lt;br /&gt;브라우저에서 OSRM을 직접 호출하기보다 &lt;span class=&quot;inline-code&quot;&gt;Frontend &amp;rarr; Backend(BFF/Proxy) &amp;rarr; OSRM&lt;/span&gt; 구조를 권장합니다. CORS, 인증, 로깅, 캐싱, 장애 대응, 요청 제한을 백엔드에서 통합 관리할 수 있기 때문입니다.&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;실무 최적화 체크리스트 (성능/안정성/유지보수)&lt;/h2&gt;
&lt;div class=&quot;card&quot;&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;좌표 변환 규칙 표준화:&lt;/b&gt; OSRM = [lng,lat], Kakao = (lat,lng) 문서화&lt;/li&gt;
&lt;li&gt;&lt;b&gt;오버레이 누적 방지:&lt;/b&gt; 폴리라인/마커 재렌더링 전에 &lt;span class=&quot;inline-code&quot;&gt;setMap(null)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;요청 제어:&lt;/b&gt; AbortController + debounce/throttle 적용&lt;/li&gt;
&lt;li&gt;&lt;b&gt;응답 최적화:&lt;/b&gt; 초기 GeoJSON, 운영 확장 시 Polyline 검토&lt;/li&gt;
&lt;li&gt;&lt;b&gt;캐싱 전략:&lt;/b&gt; 반복 경로는 백엔드 캐싱으로 OSRM 호출 절감&lt;/li&gt;
&lt;li&gt;&lt;b&gt;예외 처리:&lt;/b&gt; NoRoute/Timeout/HTTP 오류 코드별 사용자 메시지 분리&lt;/li&gt;
&lt;li&gt;&lt;b&gt;모니터링:&lt;/b&gt; OSRM 응답시간, 오류율, 메모리 사용량 지표 수집&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;확장 기능 : 단순 경로 표시를 넘어 실무 시스템으로 확장하기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추적관리 프로그램이나 물류/관제 시스템에서는 단순 A&amp;rarr;B 경로 표시를 넘어서, 다양한 라우팅/분석 기능이 필요해집니다. OSRM은 아래 기능들로 확장이 가능합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;table&lt;/b&gt; : 다대다 거리/시간 행렬 계산 (배차/순회 우선순위 계산)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;match&lt;/b&gt; : GPS 궤적 도로 스냅핑 (맵 매칭, 노이즈 보정)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;trip&lt;/b&gt; : 다중 목적지 방문 순서 최적화 (TSP 휴리스틱)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Lua 프로파일&lt;/b&gt; : 차량/이륜차/도보/특수 차량 규칙 커스터마이징&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;callout&quot;&gt;&lt;b&gt;추적관리 실무 관점에서 특히 중요한 기능&lt;/b&gt;&lt;br /&gt;GPS 위치가 흔들리는 환경에서는 &lt;span class=&quot;inline-code&quot;&gt;match&lt;/span&gt; 기반 맵 매칭이 실제 도로를 따라 움직인 것처럼 궤적 품질을 크게 개선해 줍니다.&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;참고 문서 (공식 문서/저장소)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 문서는 실제 구현 및 운영 단계에서 자주 확인하게 되는 공식 문서들입니다. 카카오맵 SDK 사용법, OSRM Route API 옵션, 자체 OSRM 서버 구축/운영 시 기본 레퍼런스로 활용하시면 좋습니다.&lt;/p&gt;
&lt;div class=&quot;table-wrap&quot;&gt;
&lt;table style=&quot;height: 534px;&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr style=&quot;height: 46px;&quot;&gt;
&lt;th style=&quot;width: 22%; height: 46px;&quot;&gt;구분&lt;/th&gt;
&lt;th style=&quot;width: 30%; height: 46px;&quot;&gt;문서명&lt;/th&gt;
&lt;th style=&quot;height: 46px;&quot;&gt;설명 / 활용 포인트&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 76px;&quot;&gt;
&lt;td style=&quot;height: 76px;&quot;&gt;카카오맵&lt;/td&gt;
&lt;td style=&quot;height: 76px;&quot;&gt;&lt;a href=&quot;https://apis.map.kakao.com/web/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt; Kakao 지도 Web API (소개/시작 페이지) &lt;/a&gt;&lt;/td&gt;
&lt;td style=&quot;height: 76px;&quot;&gt;카카오맵 웹 API 소개, 사용 개요, 주요 기능 확인용 시작점. 앱 키 발급 후 빠르게 샘플을 확인할 때 유용합니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 78px;&quot;&gt;
&lt;td style=&quot;height: 78px;&quot;&gt;카카오맵&lt;/td&gt;
&lt;td style=&quot;height: 78px;&quot;&gt;&lt;a href=&quot;https://apis.map.kakao.com/web/documentation/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt; Kakao 지도 Web API 문서 (클래스/메서드) &lt;/a&gt;&lt;/td&gt;
&lt;td style=&quot;height: 78px;&quot;&gt;&lt;span class=&quot;inline-code&quot;&gt;kakao.maps.Map&lt;/span&gt;, &lt;span class=&quot;inline-code&quot;&gt;Polyline&lt;/span&gt;, &lt;span class=&quot;inline-code&quot;&gt;LatLng&lt;/span&gt;, &lt;span class=&quot;inline-code&quot;&gt;LatLngBounds&lt;/span&gt; 등 실제 구현에 필요한 클래스 명세 확인용.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 76px;&quot;&gt;
&lt;td style=&quot;height: 76px;&quot;&gt;카카오 개발자&lt;/td&gt;
&lt;td style=&quot;height: 76px;&quot;&gt;&lt;a href=&quot;https://developers.kakao.com/docs/latest/ko/kakaomap/common&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt; Kakao Developers 지도 API 시작하기 &lt;/a&gt;&lt;/td&gt;
&lt;td style=&quot;height: 76px;&quot;&gt;앱 등록, 플랫폼 설정(도메인 등록), 키 관리, 기본 적용 절차를 정리할 때 참고하기 좋습니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 105px;&quot;&gt;
&lt;td style=&quot;height: 105px;&quot;&gt;OSRM (공식)&lt;/td&gt;
&lt;td style=&quot;height: 105px;&quot;&gt;&lt;a href=&quot;https://project-osrm.org/docs/v5.24.0/api/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt; OSRM API Documentation (v5.x) &lt;/a&gt;&lt;/td&gt;
&lt;td style=&quot;height: 105px;&quot;&gt;&lt;span class=&quot;inline-code&quot;&gt;route&lt;/span&gt;, &lt;span class=&quot;inline-code&quot;&gt;table&lt;/span&gt;, &lt;span class=&quot;inline-code&quot;&gt;match&lt;/span&gt;, &lt;span class=&quot;inline-code&quot;&gt;trip&lt;/span&gt; 엔드포인트 및 &lt;span class=&quot;inline-code&quot;&gt;overview&lt;/span&gt;, &lt;span class=&quot;inline-code&quot;&gt;geometries&lt;/span&gt;, &lt;span class=&quot;inline-code&quot;&gt;annotations&lt;/span&gt; 등 옵션 확인용 핵심 문서.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 76px;&quot;&gt;
&lt;td style=&quot;height: 76px;&quot;&gt;OSRM (공식 저장소)&lt;/td&gt;
&lt;td style=&quot;height: 76px;&quot;&gt;&lt;a href=&quot;https://github.com/Project-OSRM/osrm-backend&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt; Project-OSRM / osrm-backend (GitHub) &lt;/a&gt;&lt;/td&gt;
&lt;td style=&quot;height: 76px;&quot;&gt;Docker 이미지 사용 예시, 빌드/실행 방식, 최신 변경사항 추적, 이슈/토론 확인에 유용합니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 77px;&quot;&gt;
&lt;td style=&quot;height: 77px;&quot;&gt;OSM 데이터&lt;/td&gt;
&lt;td style=&quot;height: 77px;&quot;&gt;&lt;a href=&quot;https://download.geofabrik.de/asia/south-korea.html&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt; Geofabrik - South Korea OSM Extract &lt;/a&gt;&lt;/td&gt;
&lt;td style=&quot;height: 77px;&quot;&gt;대한민국 OSM PBF 다운로드 페이지. 자체 OSRM 서버 구축 시 입력 데이터(&lt;span class=&quot;inline-code&quot;&gt;.osm.pbf&lt;/span&gt;) 확보에 사용합니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class=&quot;card&quot;&gt;&lt;b&gt;참고 문서 활용 순서 (실무 추천)&lt;/b&gt;&lt;br /&gt;1) 카카오맵 Web API 문서로 &lt;span class=&quot;inline-code&quot;&gt;Map / Polyline / Bounds&lt;/span&gt; 사용법 확인&lt;br /&gt;2) OSRM API 문서로 &lt;span class=&quot;inline-code&quot;&gt;route&lt;/span&gt; 옵션(&lt;span class=&quot;inline-code&quot;&gt;overview&lt;/span&gt;, &lt;span class=&quot;inline-code&quot;&gt;geometries&lt;/span&gt;) 정리&lt;br /&gt;3) Geofabrik에서 OSM PBF 확보 후 자체 OSRM 구축&lt;br /&gt;4) 운영 단계에서는 OSRM GitHub 저장소로 버전 변경/이슈 확인&lt;/div&gt;
&lt;div class=&quot;callout&quot;&gt;&lt;b&gt;버전 문서 확인 팁&lt;/b&gt;&lt;br /&gt;OSRM 문서는 버전별 URL이 분리되어 있으므로, 운영 중인 OSRM 버전과 문서 버전을 맞춰 확인하는 것이 좋습니다. (예: &lt;span class=&quot;inline-code&quot;&gt;v5.24.x&lt;/span&gt; 기준 문서 사용)&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;트러블슈팅 FAQ (카카오맵 + OSRM 연동 시 자주 겪는 문제)&lt;/h2&gt;
&lt;details class=&quot;faq&quot; open=&quot;&quot;&gt;
&lt;summary&gt;경로가 바다/해외/엉뚱한 위치에 표시됩니다&lt;/summary&gt;
&lt;div class=&quot;faq-body&quot;&gt;대부분 좌표 순서 문제입니다. OSRM은 &lt;span class=&quot;inline-code&quot;&gt;[lng,lat]&lt;/span&gt;, 카카오맵 LatLng는 &lt;span class=&quot;inline-code&quot;&gt;(lat,lng)&lt;/span&gt;를 사용합니다. 매핑 시 순서를 뒤집는 로직이 누락되었는지 먼저 확인하세요.&lt;/div&gt;
&lt;/details&gt;&lt;details class=&quot;faq&quot;&gt;
&lt;summary&gt;경로를 여러 번 그리면 화면이 느려지고 잔상이 남습니다&lt;/summary&gt;
&lt;div class=&quot;faq-body&quot;&gt;이전 폴리라인/마커 정리가 누락된 경우가 많습니다. 새 경로를 그리기 전에 기존 객체에 &lt;span class=&quot;inline-code&quot;&gt;setMap(null)&lt;/span&gt;을 호출해 제거하세요. 실시간 갱신 화면일수록 이 처리가 중요합니다.&lt;/div&gt;
&lt;/details&gt;&lt;details class=&quot;faq&quot;&gt;
&lt;summary&gt;CORS 오류가 발생합니다&lt;/summary&gt;
&lt;div class=&quot;faq-body&quot;&gt;브라우저에서 OSRM 서버를 직접 호출하면 CORS 이슈가 발생할 수 있습니다. 운영 환경에서는 백엔드 프록시(BFF)를 두고, 프론트는 내부 API만 호출하는 구조가 안정적입니다.&lt;/div&gt;
&lt;/details&gt;&lt;details class=&quot;faq&quot;&gt;
&lt;summary&gt;GeoJSON과 Polyline 중 무엇부터 쓰는 게 좋을까요?&lt;/summary&gt;
&lt;div class=&quot;faq-body&quot;&gt;빠른 개발/검증이 목적이면 GeoJSON부터 시작하고, 운영 트래픽이 늘어나면 Polyline으로 전환하는 전략이 가장 효율적입니다.&lt;/div&gt;
&lt;/details&gt;&lt;details class=&quot;faq&quot;&gt;
&lt;summary&gt;퍼블릭 OSRM 서버를 운영 서비스에 써도 되나요?&lt;/summary&gt;
&lt;div class=&quot;faq-body&quot;&gt;권장하지 않습니다. 퍼블릭 서버는 테스트/데모 용도로 보는 것이 안전합니다. 실서비스는 자체 OSRM 서버 또는 관리 가능한 백엔드 프록시 구조로 운영하는 것이 좋습니다.&lt;/div&gt;
&lt;/details&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;마무리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 정리는 단순한 이론 요약이 아니라, 실제로 추적관리(관제) 프로그램을 개발하면서 필요했던 기능을 구현하고 운영 관점까지 고려해 적용한 내용을 바탕으로 정리한 것입니다. 지도 UI는 카카오맵으로, 경로 연산은 OSRM으로 분리하는 구조는 비용/성능/확장성 측면에서 실무적으로 매우 현실적인 선택이었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히 물류, 자산 추적, 차량 관제, 현장 운영 대시보드처럼 경로 호출이 빈번한 서비스에서는 초기에 아키텍처를 잘 잡아두는 것만으로도 이후 유지보수 난이도와 운영 비용이 크게 달라집니다. 핵심은 &lt;b&gt;좌표 변환 규칙&lt;/b&gt;, &lt;b&gt;렌더링 객체 정리&lt;/b&gt;, &lt;b&gt;백엔드 프록시(BFF) + OSRM 운영 구조&lt;/b&gt;를 처음부터 명확히 설계하는 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저와 비슷하게 실무에서 추적관리/지도 기반 기능을 개발하고 계신 분들이라면, 이 글의 구조와 예제 코드를 출발점으로 삼아도 충분히 도움이 될 것이라고 생각합니다. 시행착오를 줄이고 빠르게 안정화하는 데 분명히 도움이 되길 바랍니다.&lt;/p&gt;
&lt;div class=&quot;callout&quot;&gt;&lt;b&gt;이 글이 특히 도움이 될 분들&lt;/b&gt;&lt;br /&gt;추적관리/관제/물류/운영 대시보드처럼 지도 위에 이동 경로를 표시해야 하는 기능을 개발 중인데, 상용 길찾기 API 비용이나 호출 제한, 운영 확장성 때문에 대안을 찾고 있는 개발자&lt;/div&gt;
&lt;div class=&quot;good&quot;&gt;&lt;b&gt;적용 전 최종 체크 포인트&lt;/b&gt;&lt;br /&gt;좌표 순서 변환 규칙, setBounds 자동 포커싱, 재렌더링 시 오버레이 정리, OSRM 자체 구축 또는 프록시 구조, GeoJSON/Polyline 선택 전략까지 정리하면 시행착오를 크게 줄일 수 있습니다.&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div class=&quot;foot&quot;&gt;
&lt;div class=&quot;kv&quot;&gt;
&lt;div&gt;추천 슬러그&lt;/div&gt;
&lt;div&gt;kakao-map-osrm-route-polyline-guide&lt;/div&gt;
&lt;div&gt;메타 설명&lt;/div&gt;
&lt;div&gt;카카오맵과 OSRM을 연동해 무비용으로 고성능 경로 탐색과 폴리라인 렌더링을 구현하는 실전 가이드. 추적관리 프로그램 실무 적용 경험을 바탕으로 좌표 변환, GeoJSON/Polyline 선택, Docker 기반 OSRM 서버 구축 및 운영 최적화까지 정리.&lt;/div&gt;
&lt;div&gt;핵심 키워드&lt;/div&gt;
&lt;div&gt;카카오맵, Kakaomap, OSRM, 경로탐색, 길찾기API, Polyline, 자바스크립트, Docker, 추적관리 프로그램, 관제 시스템&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/article&gt;</description>
      <category>DEVELOPMENT</category>
      <category>KaKaoMap</category>
      <category>OSRM</category>
      <category>Polyline</category>
      <category>경로탐색</category>
      <category>관제시스템</category>
      <category>길찾기API</category>
      <category>라우팅엔진</category>
      <category>자바스크립트</category>
      <category>추적관리</category>
      <category>카카오맵</category>
      <author>간지뽕빨리턴님</author>
      <guid isPermaLink="true">https://odinbox.tistory.com/572</guid>
      <comments>https://odinbox.tistory.com/572#entry572comment</comments>
      <pubDate>Sun, 22 Feb 2026 01:08:37 +0900</pubDate>
    </item>
    <item>
      <title>부산에서 괌까지, 직장인의 3박 5일 꽉 찬 힐링 여행기</title>
      <link>https://odinbox.tistory.com/571</link>
      <description>&lt;div&gt;
&lt;style&gt;
    /* 오딘박스 블로그 표준 스타일 */
    .odin-container {
        font-family: 'Apple SD Gothic Neo', 'Noto Sans KR', sans-serif;
        line-height: 1.8;
        color: #333;
        font-size: 16px;
        max-width: 820px;
        margin: 0 auto;
        padding: 20px 0;
    }

    /* 제목 스타일 */
    .odin-container h2 {
        font-size: 1.4em;
        font-weight: 700;
        color: #2c3e50;
        border-bottom: 2px solid #2c3e50;
        padding-bottom: 10px;
        margin-top: 50px;
        margin-bottom: 25px;
        letter-spacing: -0.5px;
    }

    .odin-container h3 {
        font-size: 1.2em;
        font-weight: 600;
        color: #0077a3;
        margin-top: 40px;
        margin-bottom: 15px;
        border-left: 4px solid #0077a3;
        padding-left: 12px;
    }

    /* 본문 텍스트 */
    .odin-text {
        margin-bottom: 20px;
        word-break: keep-all;
        text-align: justify;
    }

    /* 강조 박스 (인용구 스타일) */
    .odin-box {
        background-color: #f8f9fa;
        border: 1px solid #e9ecef;
        padding: 20px;
        margin: 30px 0;
        border-radius: 4px;
    }

    .odin-box strong {
        color: #2c3e50;
        font-weight: 700;
    }

    /* 이미지 가이드 박스 (작성 시 참고용, 실제 이미지로 교체 필요) */
    .img-placeholder {
        background-color: #eef2f5;
        border: 2px dashed #cbd5e0;
        color: #5f6c7b;
        padding: 40px 20px;
        margin: 30px 0;
        text-align: center;
        font-size: 0.9em;
        border-radius: 8px;
    }

    .img-placeholder .guide-title {
        display: block;
        font-weight: bold;
        font-size: 1.1em;
        margin-bottom: 10px;
        color: #2d3748;
    }

    .img-placeholder .alt-text {
        display: block;
        font-size: 0.85em;
        color: #718096;
    }

    /* 리스트 스타일 */
    .odin-list {
        margin-bottom: 20px;
        padding-left: 20px;
    }

    .odin-list li {
        margin-bottom: 8px;
    }
&lt;/style&gt;
&lt;/div&gt;
&lt;div class=&quot;odin-container&quot;&gt;
&lt;p class=&quot;odin-text&quot; data-ke-size=&quot;size16&quot;&gt;매일 반복되는 코드와의 씨름, 그리고 뼛속까지 시린 한국의 겨울 추위에 지쳐갈 때쯤이었습니다. 회사에서 괌으로 워크샵을 간다는 소식이 들려왔습니다. 보통 워크샵이라고 하면 짜여진 일정에 몸을 맡기는 수동적인 여행을 떠올리기 쉽지만, 이번 여행의 모토는 조금 달랐습니다. &quot;워크샵이지만 최대한 자유여행처럼.&quot; 개발자로서 효율성을 중시하는 저에게 이보다 더 매력적인 제안은 없었죠. 목요일 저녁 업무를 마치고 부산 김해공항으로 달려가 월요일 아침 바로 출근하는, 꽉 찬 3박 5일간의 기록을 풀어보려 합니다. 단순한 여행기를 넘어 2025년 현재 괌의 물가, 분위기, 그리고 놓치지 말아야 할 포인트들을 아주 상세하게 정리했습니다.&lt;/p&gt;
&lt;div class=&quot;img-placeholder&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;글 상단 부분 대표 이미지 (1).png&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pBHlp/dJMcagYKqxi/Hn8Nduz4bbCudgN0pAK2nK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pBHlp/dJMcagYKqxi/Hn8Nduz4bbCudgN0pAK2nK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pBHlp/dJMcagYKqxi/Hn8Nduz4bbCudgN0pAK2nK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpBHlp%2FdJMcagYKqxi%2FHn8Nduz4bbCudgN0pAK2nK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;400&quot; data-filename=&quot;글 상단 부분 대표 이미지 (1).png&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 왜 지금 괌인가? 데이터로 보는 여행 트렌드&lt;/h2&gt;
&lt;p class=&quot;odin-text&quot; data-ke-size=&quot;size16&quot;&gt;여행을 떠나기 전, 습관처럼 데이터를 좀 찾아봤습니다. 2025년 말 기준으로 괌을 찾는 관광객 통계를 보니 흥미로운 점이 발견되더군요. 12월 한 달 동안 괌을 방문한 한국인이 무려 5만 명이 넘었습니다. 이는 전년 대비 65% 이상 폭증한 수치인데, 전체 괌 방문객의 절반 이상이 한국인이라는 뜻입니다.&lt;/p&gt;
&lt;div class=&quot;odin-box&quot;&gt;&lt;b&gt;Insight&lt;/b&gt;&lt;br /&gt;실제로 현지에 도착해보니 이곳이 미국령 괌인지, 한국의 거제도인지 헷갈릴 정도로 한국어 안내판과 한국인 관광객이 많았습니다. 이는 영어가 낯선 분들에게는 엄청난 심리적 안정감을 주지만, 완벽한 이국적인 고립감을 원하는 분들에게는 조금 아쉬울 수도 있는 부분입니다. 하지만 부산에서 4시간 남짓이면 도착하는 가장 가까운 미국이라는 메리트는 여전히 강력했습니다.&lt;/div&gt;
&lt;div class=&quot;img-placeholder&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cBMUfA/dJMcagLeJ6c/RpboMLXwXsDzBv4MAMqifk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cBMUfA/dJMcagLeJ6c/RpboMLXwXsDzBv4MAMqifk/img.png&quot; data-alt=&quot;부산김해공항 내부 모습&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cBMUfA/dJMcagLeJ6c/RpboMLXwXsDzBv4MAMqifk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcBMUfA%2FdJMcagLeJ6c%2FRpboMLXwXsDzBv4MAMqifk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;부산김해공항 내부 모습&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Hlbun/dJMcagLeJ6b/MK4UhLKDFqRY9pMoZ00W51/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Hlbun/dJMcagLeJ6b/MK4UhLKDFqRY9pMoZ00W51/img.png&quot; data-alt=&quot;부산김해공항에서 먹은 음식(비빔밀면)&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Hlbun/dJMcagLeJ6b/MK4UhLKDFqRY9pMoZ00W51/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHlbun%2FdJMcagLeJ6b%2FMK4UhLKDFqRY9pMoZ00W51%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;부산김해공항에서 먹은 음식(비빔밀면)&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 부산 김해공항 출발, 그리고 괌의 첫인상&lt;/h2&gt;
&lt;p class=&quot;odin-text&quot; data-ke-size=&quot;size16&quot;&gt;목요일 오후 업무를 마치고 김해국제공항으로 향했습니다. 제가 이용한 항공편은 진에어 LJ921편이었습니다. 저녁 늦게 출발해 괌에는 새벽에 도착하는 일정입니다. 직장인에게 연차 소진을 최소화할 수 있는 황금 스케줄이지만, 체력적으로는 꽤 부담이 되는 것이 사실입니다. 비행시간은 약 3시간 50분. 기내식을 먹고 잠깐 눈을 붙이니 금세 착륙 안내 방송이 나왔습니다.&lt;/p&gt;
&lt;p class=&quot;odin-text&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;odin-text&quot; data-ke-size=&quot;size16&quot;&gt;괌 공항에 내리자마자 느껴지는 그 특유의 습하고 따뜻한 공기는 아, 정말 탈출했구나라는 해방감을 주기에 충분했습니다. 입국 심사는 생각보다 까다롭지 않았지만, 새벽 시간대라 피로가 몰려왔습니다. 숙소는 투몬 시내 한복판에 위치한 괌 플라자 리조트로 잡았습니다. 사실 괌의 호텔들은 시설 낙후 대비 가격이 비싼 편이라 가성비를 따지지 않을 수 없는데, 괌 플라자는 위치 하나만큼은 깡패 수준입니다. 렌트카 없이도 T갤러리아나 주요 쇼핑몰을 걸어서 갈 수 있다는 점이 워크샵 단체 행동에서 오는 제약을 많이 상쇄해 주었습니다.&lt;/p&gt;
&lt;div class=&quot;img-placeholder&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/becC0F/dJMcaaxtSl1/TOzG5cpBQk07pJQvbzVY0k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/becC0F/dJMcaaxtSl1/TOzG5cpBQk07pJQvbzVY0k/img.png&quot; data-alt=&quot;안토니오 B. 원 팻 국제공항(Antonio B. Won Pat International Airport)&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/becC0F/dJMcaaxtSl1/TOzG5cpBQk07pJQvbzVY0k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbecC0F%2FdJMcaaxtSl1%2FTOzG5cpBQk07pJQvbzVY0k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;안토니오 B. 원 팻 국제공항(Antonio B. Won Pat International Airport)&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cQRQiU/dJMcafr0cj8/ZSXM1gQeOJWi1wjHtCERz1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cQRQiU/dJMcafr0cj8/ZSXM1gQeOJWi1wjHtCERz1/img.png&quot; data-alt=&quot;렌트카 모습(현대 투싼)&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cQRQiU/dJMcafr0cj8/ZSXM1gQeOJWi1wjHtCERz1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcQRQiU%2FdJMcafr0cj8%2FZSXM1gQeOJWi1wjHtCERz1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;렌트카 모습(현대 투싼)&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2250&quot; data-origin-height=&quot;3000&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bmZGmy/dJMcagYKqK4/iwEpW8PZ2Jc0d3dGHWLbB0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bmZGmy/dJMcagYKqK4/iwEpW8PZ2Jc0d3dGHWLbB0/img.png&quot; data-alt=&quot;투몬 거리 야경모습&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bmZGmy/dJMcagYKqK4/iwEpW8PZ2Jc0d3dGHWLbB0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbmZGmy%2FdJMcagYKqK4%2FiwEpW8PZ2Jc0d3dGHWLbB0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2250&quot; height=&quot;3000&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2250&quot; data-origin-height=&quot;3000&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;투몬 거리 야경모습&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 미식 탐방 : 미국적인 스케일과 섬세한 맛의 조화&lt;/h2&gt;
&lt;p class=&quot;odin-text&quot; data-ke-size=&quot;size16&quot;&gt;여행의 시작은 역시 음식이죠. 렌트카를 인수하자마자 피카스 카페로 향했습니다. 이곳은 관광객뿐만 아니라 현지인들도 줄 서서 먹는 브런치 맛집입니다. 가장 유명한 메뉴인 로코모코를 주문했는데, 이게 정말 물건입니다. 보통 로코모코는 짭조름한 브라운 그레이비소스를 쓰는데, 이곳은 꾸덕꾸덕하고 고소한 크림소스를 베이스로 합니다. 밥과 패티, 그리고 반숙 계란후라이에 크림소스를 듬뿍 적셔 한 입 먹으니 비행의 피로가 싹 씻겨 내려가는 기분이었습니다. 느끼할 것 같지만 의외로 끝맛이 매콤해서 한국인 입맛에 아주 잘 맞았습니다.&lt;/p&gt;
&lt;div class=&quot;img-placeholder&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2691&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FZ5HH/dJMcabC9Mpk/jULCT9wXE7xTWnGWbEef2k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FZ5HH/dJMcabC9Mpk/jULCT9wXE7xTWnGWbEef2k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FZ5HH/dJMcabC9Mpk/jULCT9wXE7xTWnGWbEef2k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFZ5HH%2FdJMcabC9Mpk%2FjULCT9wXE7xTWnGWbEef2k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2691&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2691&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bBgcgY/dJMcai93V3l/LZ8OCh0R82jtgbN3k0J7f1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bBgcgY/dJMcai93V3l/LZ8OCh0R82jtgbN3k0J7f1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bBgcgY/dJMcai93V3l/LZ8OCh0R82jtgbN3k0J7f1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbBgcgY%2FdJMcai93V3l%2FLZ8OCh0R82jtgbN3k0J7f1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cdcV9U/dJMcafle9dC/FQrrhOJ2RToJ3CgTt1Sl7k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cdcV9U/dJMcafle9dC/FQrrhOJ2RToJ3CgTt1Sl7k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cdcV9U/dJMcafle9dC/FQrrhOJ2RToJ3CgTt1Sl7k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcdcV9U%2FdJMcafle9dC%2FFQrrhOJ2RToJ3CgTt1Sl7k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/GvffZ/dJMcafle9dD/PqLSHbpvWkMMZbSfHAV1v1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/GvffZ/dJMcafle9dD/PqLSHbpvWkMMZbSfHAV1v1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GvffZ/dJMcafle9dD/PqLSHbpvWkMMZbSfHAV1v1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGvffZ%2FdJMcafle9dD%2FPqLSHbpvWkMMZbSfHAV1v1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b29Ihb/dJMcah4q0Sp/8lKntoEKgBlzCSU473kOT0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b29Ihb/dJMcah4q0Sp/8lKntoEKgBlzCSU473kOT0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b29Ihb/dJMcah4q0Sp/8lKntoEKgBlzCSU473kOT0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb29Ihb%2FdJMcah4q0Sp%2F8lKntoEKgBlzCSU473kOT0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;압도적인 양(Portion)의 충격과 쇼핑모습&lt;/h3&gt;
&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Ggdm0/dJMcagqUD5U/wkyLwYn7fi19jIdmSHDKJk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Ggdm0/dJMcagqUD5U/wkyLwYn7fi19jIdmSHDKJk/img.png&quot; style=&quot;width: 32.5203%; margin-right: 10px;&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot; data-filename=&quot;blob&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;33.33&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Ggdm0/dJMcagqUD5U/wkyLwYn7fi19jIdmSHDKJk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGgdm0%2FdJMcagqUD5U%2FwkyLwYn7fi19jIdmSHDKJk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/yBlYN/dJMcabb3UQx/FMShNW0BOWvTwRCnoKESC0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/yBlYN/dJMcabb3UQx/FMShNW0BOWvTwRCnoKESC0/img.png&quot; style=&quot;width: 32.5203%; margin-right: 10px;&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot; data-filename=&quot;blob&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;33.33&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/yBlYN/dJMcabb3UQx/FMShNW0BOWvTwRCnoKESC0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FyBlYN%2FdJMcabb3UQx%2FFMShNW0BOWvTwRCnoKESC0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cnhL1F/dJMcafr0cto/ILzDSgbRacKzbJBCKKZ4ak/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cnhL1F/dJMcafr0cto/ILzDSgbRacKzbJBCKKZ4ak/img.png&quot; style=&quot;width: 32.5203%;&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot; data-filename=&quot;blob&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;33.34&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cnhL1F/dJMcafr0cto/ILzDSgbRacKzbJBCKKZ4ak/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcnhL1F%2FdJMcafr0cto%2FILzDSgbRacKzbJBCKKZ4ak%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;케이마트(KMART) 외부모습과 내부모습&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bsIDfv/dJMcahQTBcJ/iwBG1K8tv4sTpkFJDALPV1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bsIDfv/dJMcahQTBcJ/iwBG1K8tv4sTpkFJDALPV1/img.png&quot; style=&quot;width: 23.7746%; margin-right: 10px;&quot; data-origin-width=&quot;1689&quot; data-origin-height=&quot;3000&quot; data-filename=&quot;blob&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;24.07&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bsIDfv/dJMcahQTBcJ/iwBG1K8tv4sTpkFJDALPV1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbsIDfv%2FdJMcahQTBcJ%2FiwBG1K8tv4sTpkFJDALPV1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1689&quot; height=&quot;3000&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/QHkm3/dJMcahJ9n9R/L6hRSgLZ2VjOmNGDgdXUc0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/QHkm3/dJMcahJ9n9R/L6hRSgLZ2VjOmNGDgdXUc0/img.png&quot; style=&quot;width: 75.0059%;&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot; data-filename=&quot;blob&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;75.93&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/QHkm3/dJMcahJ9n9R/L6hRSgLZ2VjOmNGDgdXUc0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQHkm3%2FdJMcahJ9n9R%2FL6hRSgLZ2VjOmNGDgdXUc0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;GPO 아울렛 야경 및 GPO 근처에 있는 로스&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/3sAxW/dJMcahJ9n9S/D0ET8D7rM4q1dan7xQumLK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/3sAxW/dJMcahJ9n9S/D0ET8D7rM4q1dan7xQumLK/img.png&quot; style=&quot;width: 49.3902%; margin-right: 10px;&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot; data-filename=&quot;blob&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/3sAxW/dJMcahJ9n9S/D0ET8D7rM4q1dan7xQumLK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F3sAxW%2FdJMcahJ9n9S%2FD0ET8D7rM4q1dan7xQumLK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bNN7CX/dJMcajgO83B/Nq5yNc0syc2tRkh3kchqT0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bNN7CX/dJMcajgO83B/Nq5yNc0syc2tRkh3kchqT0/img.png&quot; style=&quot;width: 49.3902%;&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot; data-filename=&quot;blob&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bNN7CX/dJMcajgO83B/Nq5yNc0syc2tRkh3kchqT0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbNN7CX%2FdJMcajgO83B%2FNq5yNc0syc2tRkh3kchqT0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;일본라멘가게 외부모습과 일본라멘 모습&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ExKwD/dJMcahQTBcQ/ckI0SAl2Hc51DquJZc4VOK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ExKwD/dJMcahQTBcQ/ckI0SAl2Hc51DquJZc4VOK/img.png&quot; style=&quot;width: 42.1072%; margin-right: 10px;&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot; data-filename=&quot;blob&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;43.16&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ExKwD/dJMcahQTBcQ/ckI0SAl2Hc51DquJZc4VOK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FExKwD%2FdJMcahQTBcQ%2FckI0SAl2Hc51DquJZc4VOK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/MJdBV/dJMcajgO83A/iQ3YfNlKCh3PgtK8k3bj00/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/MJdBV/dJMcajgO83A/iQ3YfNlKCh3PgtK8k3bj00/img.png&quot; style=&quot;width: 13.3467%; margin-right: 10px;&quot; data-origin-width=&quot;1689&quot; data-origin-height=&quot;3000&quot; data-filename=&quot;blob&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;13.68&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/MJdBV/dJMcajgO83A/iQ3YfNlKCh3PgtK8k3bj00/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMJdBV%2FdJMcajgO83A%2FiQ3YfNlKCh3PgtK8k3bj00%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1689&quot; height=&quot;3000&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/LhitR/dJMcahJ9n9T/QGrmk3VA5nGu1zcJRm0Wok/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/LhitR/dJMcahJ9n9T/QGrmk3VA5nGu1zcJRm0Wok/img.png&quot; style=&quot;width: 42.1072%;&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot; data-filename=&quot;blob&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;43.16&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/LhitR/dJMcahJ9n9T/QGrmk3VA5nGu1zcJRm0Wok/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FLhitR%2FdJMcahJ9n9T%2FQGrmk3VA5nGu1zcJRm0Wok%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;하가나쇼핑센터에 있는 로쓰 야경 및 문닫기 전이라 어수선하다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nTbkA/dJMcagqUD5Z/kajTS9xIisnfhLkg0w9FA0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nTbkA/dJMcagqUD5Z/kajTS9xIisnfhLkg0w9FA0/img.png&quot; style=&quot;width: 75.0059%; margin-right: 10px;&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot; data-filename=&quot;blob&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;75.93&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nTbkA/dJMcagqUD5Z/kajTS9xIisnfhLkg0w9FA0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnTbkA%2FdJMcagqUD5Z%2FkajTS9xIisnfhLkg0w9FA0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/909H6/dJMcafr0ctp/4lRjlVKLRTrIOzL2KJxog0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/909H6/dJMcafr0ctp/4lRjlVKLRTrIOzL2KJxog0/img.png&quot; style=&quot;width: 23.7746%;&quot; data-origin-width=&quot;1689&quot; data-origin-height=&quot;3000&quot; data-filename=&quot;blob&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;24.07&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/909H6/dJMcafr0ctp/4lRjlVKLRTrIOzL2KJxog0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F909H6%2FdJMcafr0ctp%2F4lRjlVKLRTrIOzL2KJxog0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1689&quot; height=&quot;3000&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;마트 안 모습 전부 너무 크다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/k1afh/dJMcaaRNGkr/sVPMkdCaSiXkYsYgoiBozK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/k1afh/dJMcaaRNGkr/sVPMkdCaSiXkYsYgoiBozK/img.png&quot; style=&quot;width: 23.7746%; margin-right: 10px;&quot; data-origin-width=&quot;1689&quot; data-origin-height=&quot;3000&quot; data-is-animation=&quot;false&quot; data-filename=&quot;blob&quot; data-widthpercent=&quot;24.07&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/k1afh/dJMcaaRNGkr/sVPMkdCaSiXkYsYgoiBozK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fk1afh%2FdJMcaaRNGkr%2FsVPMkdCaSiXkYsYgoiBozK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1689&quot; height=&quot;3000&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dV72aa/dJMcahQTDsQ/onKpGpHrPLghd1FQRe1Ks0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dV72aa/dJMcahQTDsQ/onKpGpHrPLghd1FQRe1Ks0/img.png&quot; style=&quot;width: 75.0059%;&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot; data-is-animation=&quot;false&quot; data-filename=&quot;blob&quot; data-widthpercent=&quot;75.93&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dV72aa/dJMcahQTDsQ/onKpGpHrPLghd1FQRe1Ks0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdV72aa%2FdJMcahQTDsQ%2FonKpGpHrPLghd1FQRe1Ks0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;마이크로네시아몰, 빨간버스가 셔틀버스같이 괌의 애지간한곳을 다 가는거같다.&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p class=&quot;odin-text&quot; data-ke-size=&quot;size16&quot;&gt;저녁에는 괌의 음식 양에 압도당했습니다. 후지 이찌방 라멘이나 K마트 푸드코트에서 음식을 시켜보면 알게 됩니다. 이걸 혼자 다 먹으라고?라는 말이 절로 나올 정도로 양이 많습니다. 미국의 풍요로움이 식탁 위에 그대로 반영된 느낌이랄까요. 가성비를 따진다면 괌에서의 식사는 꽤 만족스러운 편입니다.&lt;/p&gt;
&lt;p class=&quot;odin-text&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;odin-text&quot; data-ke-size=&quot;size16&quot;&gt;그리고 쇼핑을 통해 다양한 것도 많이 구경을 할 수 있었습니다. 역시 미국답게 모든 물건 용량이 한국과 비교하면 엄청 많이 있었습니다.&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. 쇼핑의 새로운 강자, 빌리지 오브 돈키&lt;/h2&gt;
&lt;p class=&quot;odin-text&quot; data-ke-size=&quot;size16&quot;&gt;2024년에 오픈했다는 빌리지 오브 돈키(돈키호테)는 이번 여행에서 가장 인상 깊은 장소 중 하나였습니다. 일본 여행을 가면 좁은 통로의 돈키호테를 생각하기 마련인데, 괌의 돈키호테는 다릅니다. 미국의 거대한 창고형 마트 스타일에 일본의 디테일한 상품 구성을 섞어놓았습니다. 식료품부터 의약품, 기념품까지 없는 게 없는데, 무엇보다 24시간(혹은 새벽 1시까지) 운영한다는 점이 최고였습니다. 꽉 찬 낮 일정을 보내고 밤에 잠이 안 올 때 슬리퍼 끌고 쇼핑하러 가기에 이만한 곳이 없습니다.&lt;/p&gt;
&lt;div class=&quot;img-placeholder&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bdzjV0/dJMcahchrPa/eUJ0YKrVkKu6K4qEregXlk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bdzjV0/dJMcahchrPa/eUJ0YKrVkKu6K4qEregXlk/img.png&quot; data-alt=&quot;빌리지 오브 돈키 외부전경&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bdzjV0/dJMcahchrPa/eUJ0YKrVkKu6K4qEregXlk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbdzjV0%2FdJMcahchrPa%2FeUJ0YKrVkKu6K4qEregXlk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;빌리지 오브 돈키 외부전경&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/CLFP2/dJMcaf6BYOW/CwD2rJDMgZ06BdSnvfI7E0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/CLFP2/dJMcaf6BYOW/CwD2rJDMgZ06BdSnvfI7E0/img.png&quot; data-alt=&quot;빌리지 오브 돈키 내부 모습&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/CLFP2/dJMcaf6BYOW/CwD2rJDMgZ06BdSnvfI7E0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCLFP2%2FdJMcaf6BYOW%2FCwD2rJDMgZ06BdSnvfI7E0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;빌리지 오브 돈키 내부 모습&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. 괌의 바다, 그리고 날씨라는 변수, 스테이크&lt;/h2&gt;
&lt;p class=&quot;odin-text&quot; data-ke-size=&quot;size16&quot;&gt;둘째 날은 이파오 비치로 향했습니다. 사람들이 북적거리는 투몬 비치보다 훨씬 한적하고 물이 맑았습니다. 스노클링 장비를 챙겨서 물에 들어가니 형형색색의 물고기들이 발치에서 헤엄치는 게 보였습니다.&lt;/p&gt;
&lt;p class=&quot;odin-text&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;odin-text&quot; data-ke-size=&quot;size16&quot;&gt;하지만 괌 여행에서 날씨는 정말 예측할 수 없는 변수입니다. 셋째 날 돌핀 크루즈를 예약해 두었는데, 아침부터 비가 쏟아졌습니다. 배를 타고 나가는 일정은 파도가 높으면 멀미로 고생만 하고 돌고래는 구경도 못 할 확률이 높습니다. 과감하게 일정을 취소하고 대안을 찾았습니다. 비가 올 때는 무리한 야외 활동보다는 쇼핑몰 투어나 맛집 탐방으로 빠르게 태세를 전환하는 유연함이 필요합니다. 날이 조금 개었을 때 에메랄드 밸리를 찾았는데, 물뱀이 지나가는 것도 보일 정도로 투명한 물빛이 인상적이었습니다.&lt;/p&gt;
&lt;p class=&quot;odin-text&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;odin-text&quot; data-ke-size=&quot;size16&quot;&gt;돌핀투어는 살짝 아쉽다고 느낀 것은 타기 전에 찾아본 결과로는 참치회나 이런것도 괜찮아보였는데 실제로 봣을 때 사실 그렇게 좋지 않았습니다. 양도 적었고 어떻게든 작은 배에 많은 사람들을 타게 해야 이익을 남기는 구조일거라 어떻게든 자리를 꽉 채우는 모습이였습니다. 낚시나 물놀이를 일부 할 수 있으나 시간이 그렇게 길지 않으니 냉정하게 물놀이 이런것을 좋아한다면 그냥 그 시간에 해변가서 개인적으로 하시는게 더 좋습니다.&lt;/p&gt;
&lt;p class=&quot;odin-text&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;odin-text&quot; data-ke-size=&quot;size16&quot;&gt;그렇게 돌핀투어를 마치고 숙소에서 샤워하고 옷을 갈아입은 뒤 롱혼스테이크를 먹으러 갔습니다. GPO 근처에 있다고 들어 출발을 했고 그 근처에 애플비즈?라는 곳도 괜찮다고 했는데 롱혼스테이크에서 한번 먹어보려고 했습니다. 저의 경우 립아이를 시켰고 한국에서 먹었던 것보다 더 맛있다고 느껴졌습니다.&lt;/p&gt;
&lt;div class=&quot;img-placeholder&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bklC7G/dJMcabwmF1a/t4VK12EuBIGj1kxr0Nz2Xk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bklC7G/dJMcabwmF1a/t4VK12EuBIGj1kxr0Nz2Xk/img.png&quot; data-alt=&quot;아이러브이파오 조형물&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bklC7G/dJMcabwmF1a/t4VK12EuBIGj1kxr0Nz2Xk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbklC7G%2FdJMcabwmF1a%2Ft4VK12EuBIGj1kxr0Nz2Xk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;아이러브이파오 조형물&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2250&quot; data-origin-height=&quot;3000&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zkFEB/dJMcabwmF1b/F8K37lRG6pzPoMvHyhnvi0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zkFEB/dJMcabwmF1b/F8K37lRG6pzPoMvHyhnvi0/img.png&quot; data-alt=&quot;이파오해변에 있는 아이러브괌&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zkFEB/dJMcabwmF1b/F8K37lRG6pzPoMvHyhnvi0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzkFEB%2FdJMcabwmF1b%2FF8K37lRG6pzPoMvHyhnvi0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2250&quot; height=&quot;3000&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2250&quot; data-origin-height=&quot;3000&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;이파오해변에 있는 아이러브괌&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2250&quot; data-origin-height=&quot;3000&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mRSYf/dJMcabwmF1c/RQdLAORq84T7K2MpsUTBS1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mRSYf/dJMcabwmF1c/RQdLAORq84T7K2MpsUTBS1/img.png&quot; data-alt=&quot;이파오해변 전경&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mRSYf/dJMcabwmF1c/RQdLAORq84T7K2MpsUTBS1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmRSYf%2FdJMcabwmF1c%2FRQdLAORq84T7K2MpsUTBS1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2250&quot; height=&quot;3000&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2250&quot; data-origin-height=&quot;3000&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;이파오해변 전경&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2250&quot; data-origin-height=&quot;3000&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/NSTAH/dJMcaaqHXOV/4fMXKdqCOvGIforeQwyXl0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/NSTAH/dJMcaaqHXOV/4fMXKdqCOvGIforeQwyXl0/img.png&quot; data-alt=&quot;이파오비치 전경&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/NSTAH/dJMcaaqHXOV/4fMXKdqCOvGIforeQwyXl0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNSTAH%2FdJMcaaqHXOV%2F4fMXKdqCOvGIforeQwyXl0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2250&quot; height=&quot;3000&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2250&quot; data-origin-height=&quot;3000&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;이파오비치 전경&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2250&quot; data-origin-height=&quot;3000&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cuVuuA/dJMcaaqHXOW/uSbUCv0ku0wzwxo8sA6exK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cuVuuA/dJMcaaqHXOW/uSbUCv0ku0wzwxo8sA6exK/img.png&quot; data-alt=&quot;이파오해변에서 먹늰 BBQ 준비모습&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cuVuuA/dJMcaaqHXOW/uSbUCv0ku0wzwxo8sA6exK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcuVuuA%2FdJMcaaqHXOW%2FuSbUCv0ku0wzwxo8sA6exK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2250&quot; height=&quot;3000&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2250&quot; data-origin-height=&quot;3000&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;이파오해변에서 먹늰 BBQ 준비모습&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/CiRht/dJMcafr0cHS/fiFAJC72Vl2uhKzh47tjm0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/CiRht/dJMcafr0cHS/fiFAJC72Vl2uhKzh47tjm0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/CiRht/dJMcafr0cHS/fiFAJC72Vl2uhKzh47tjm0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCiRht%2FdJMcafr0cHS%2FfiFAJC72Vl2uhKzh47tjm0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sGXm8/dJMcaaqHXOU/KCueNMFgku7rKSvyUbAuok/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sGXm8/dJMcaaqHXOU/KCueNMFgku7rKSvyUbAuok/img.png&quot; data-alt=&quot;이파오해변 물색상&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sGXm8/dJMcaaqHXOU/KCueNMFgku7rKSvyUbAuok/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FsGXm8%2FdJMcaaqHXOU%2FKCueNMFgku7rKSvyUbAuok%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;이파오해변 물색상&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2250&quot; data-origin-height=&quot;3000&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ckrfiu/dJMcabb3U71/JwwsTZIiofL5UUSmrLAgFK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ckrfiu/dJMcabb3U71/JwwsTZIiofL5UUSmrLAgFK/img.png&quot; data-alt=&quot;이파오해변 길 모습&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ckrfiu/dJMcabb3U71/JwwsTZIiofL5UUSmrLAgFK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fckrfiu%2FdJMcabb3U71%2FJwwsTZIiofL5UUSmrLAgFK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2250&quot; height=&quot;3000&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2250&quot; data-origin-height=&quot;3000&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;이파오해변 길 모습&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sfQ6e/dJMcacWkYlg/CiACkTLBo7wg1oMSlVlDY0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sfQ6e/dJMcacWkYlg/CiACkTLBo7wg1oMSlVlDY0/img.png&quot; data-alt=&quot;에메랄드밸리 모습&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sfQ6e/dJMcacWkYlg/CiACkTLBo7wg1oMSlVlDY0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FsfQ6e%2FdJMcacWkYlg%2FCiACkTLBo7wg1oMSlVlDY0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;에메랄드밸리 모습&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bExNgt/dJMcabb3U7W/8G93Ch3upoeXgBY7MtFI5k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bExNgt/dJMcabb3U7W/8G93Ch3upoeXgBY7MtFI5k/img.png&quot; data-alt=&quot;에메랄드 밸리&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bExNgt/dJMcabb3U7W/8G93Ch3upoeXgBY7MtFI5k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbExNgt%2FdJMcabb3U7W%2F8G93Ch3upoeXgBY7MtFI5k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;에메랄드 밸리&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2250&quot; data-origin-height=&quot;3000&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bIMtjK/dJMcabb3U7Y/tESwmr1YMENATRnpYeNeGK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bIMtjK/dJMcabb3U7Y/tESwmr1YMENATRnpYeNeGK/img.png&quot; data-alt=&quot;에메랄드 밸리&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bIMtjK/dJMcabb3U7Y/tESwmr1YMENATRnpYeNeGK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbIMtjK%2FdJMcabb3U7Y%2FtESwmr1YMENATRnpYeNeGK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2250&quot; height=&quot;3000&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2250&quot; data-origin-height=&quot;3000&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;에메랄드 밸리&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1689&quot; data-origin-height=&quot;3000&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bqtqGh/dJMcag5xnu9/AqxZ5kk4QNapDKzE5L8a4k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bqtqGh/dJMcag5xnu9/AqxZ5kk4QNapDKzE5L8a4k/img.png&quot; data-alt=&quot;돌핀투어 선착장 근처&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bqtqGh/dJMcag5xnu9/AqxZ5kk4QNapDKzE5L8a4k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbqtqGh%2FdJMcag5xnu9%2FAqxZ5kk4QNapDKzE5L8a4k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1689&quot; height=&quot;3000&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1689&quot; data-origin-height=&quot;3000&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;돌핀투어 선착장 근처&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ercKuS/dJMcahwB44T/8Y2et5yGyQxmDQ1wHeEcs1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ercKuS/dJMcahwB44T/8Y2et5yGyQxmDQ1wHeEcs1/img.png&quot; data-alt=&quot;돌핀투어 선착장&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ercKuS/dJMcahwB44T/8Y2et5yGyQxmDQ1wHeEcs1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FercKuS%2FdJMcahwB44T%2F8Y2et5yGyQxmDQ1wHeEcs1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;돌핀투어 선착장&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;2250&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dfGIgg/dJMcag5xnva/evyI9lGk8yVkLKVDDDgI5k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dfGIgg/dJMcag5xnva/evyI9lGk8yVkLKVDDDgI5k/img.png&quot; data-alt=&quot;돌핀투어 선착장 같이 나가는 배 모습&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dfGIgg/dJMcag5xnva/evyI9lGk8yVkLKVDDDgI5k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdfGIgg%2FdJMcag5xnva%2FevyI9lGk8yVkLKVDDDgI5k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;2250&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;2250&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;돌핀투어 선착장 같이 나가는 배 모습&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/IS1g7/dJMcai93Wrr/YzmvvkmcSsMhEpK4HGuPBK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/IS1g7/dJMcai93Wrr/YzmvvkmcSsMhEpK4HGuPBK/img.png&quot; data-alt=&quot;돌핀투어 바닷가 근처모습&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/IS1g7/dJMcai93Wrr/YzmvvkmcSsMhEpK4HGuPBK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FIS1g7%2FdJMcai93Wrr%2FYzmvvkmcSsMhEpK4HGuPBK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;돌핀투어 바닷가 근처모습&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/spEVd/dJMcaibdxyi/hCVxwxC5H2JiIJ60aidylk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/spEVd/dJMcaibdxyi/hCVxwxC5H2JiIJ60aidylk/img.png&quot; data-alt=&quot;롱혼스테이크 앞 거리&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/spEVd/dJMcaibdxyi/hCVxwxC5H2JiIJ60aidylk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FspEVd%2FdJMcaibdxyi%2FhCVxwxC5H2JiIJ60aidylk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;롱혼스테이크 앞 거리&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/8vWi1/dJMcaibdxyj/5FT3vHkS3tnmjbe1Cldcm0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/8vWi1/dJMcaibdxyj/5FT3vHkS3tnmjbe1Cldcm0/img.png&quot; data-alt=&quot;롱혼스테이크 가게 모습&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/8vWi1/dJMcaibdxyj/5FT3vHkS3tnmjbe1Cldcm0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F8vWi1%2FdJMcaibdxyj%2F5FT3vHkS3tnmjbe1Cldcm0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;롱혼스테이크 가게 모습&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1689&quot; data-origin-height=&quot;3000&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/yHX1n/dJMcahi5Bmm/xKpT8hOHcBEca4khFwmO1K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/yHX1n/dJMcahi5Bmm/xKpT8hOHcBEca4khFwmO1K/img.png&quot; data-alt=&quot;롱혼스테이크 메뉴판&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/yHX1n/dJMcahi5Bmm/xKpT8hOHcBEca4khFwmO1K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FyHX1n%2FdJMcahi5Bmm%2FxKpT8hOHcBEca4khFwmO1K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1689&quot; height=&quot;3000&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1689&quot; data-origin-height=&quot;3000&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;롱혼스테이크 메뉴판&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bxuaMp/dJMcagRZ4Zv/Uq5C2ez8DhtBfKmNjdsROk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bxuaMp/dJMcagRZ4Zv/Uq5C2ez8DhtBfKmNjdsROk/img.png&quot; data-alt=&quot;롱혼스테이크 립아이&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bxuaMp/dJMcagRZ4Zv/Uq5C2ez8DhtBfKmNjdsROk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbxuaMp%2FdJMcagRZ4Zv%2FUq5C2ez8DhtBfKmNjdsROk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;롱혼스테이크 립아이&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2250&quot; data-origin-height=&quot;3000&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/68sG2/dJMcahi5Bmo/KSDkLdJhCfRIZzoLnykyP1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/68sG2/dJMcahi5Bmo/KSDkLdJhCfRIZzoLnykyP1/img.png&quot; data-alt=&quot;롱혼스테이크 스테이크 모습&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/68sG2/dJMcahi5Bmo/KSDkLdJhCfRIZzoLnykyP1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F68sG2%2FdJMcahi5Bmo%2FKSDkLdJhCfRIZzoLnykyP1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2250&quot; height=&quot;3000&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2250&quot; data-origin-height=&quot;3000&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;롱혼스테이크 스테이크 모습&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/KqUY5/dJMcaaEfOcJ/GEUZ2vQko4t8HjkXfnqum0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/KqUY5/dJMcaaEfOcJ/GEUZ2vQko4t8HjkXfnqum0/img.png&quot; data-alt=&quot;GPO 안에 있는 카페 모습&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/KqUY5/dJMcaaEfOcJ/GEUZ2vQko4t8HjkXfnqum0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKqUY5%2FdJMcaaEfOcJ%2FGEUZ2vQko4t8HjkXfnqum0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;GPO 안에 있는 카페 모습&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2250&quot; data-origin-height=&quot;3000&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zRRnu/dJMcaibdxyk/wLLk5TpdMC9AGFHfqLV4C1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zRRnu/dJMcaibdxyk/wLLk5TpdMC9AGFHfqLV4C1/img.png&quot; data-alt=&quot;GPO 안에 있는 카페에서 시킨 아메리카노와 건강주스&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zRRnu/dJMcaibdxyk/wLLk5TpdMC9AGFHfqLV4C1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzRRnu%2FdJMcaibdxyk%2FwLLk5TpdMC9AGFHfqLV4C1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2250&quot; height=&quot;3000&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2250&quot; data-origin-height=&quot;3000&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;GPO 안에 있는 카페에서 시킨 아메리카노와 건강주스&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cgVjdf/dJMcaibdxyh/tufDOJAJnShyQ6Dsb3Ew4k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cgVjdf/dJMcaibdxyh/tufDOJAJnShyQ6Dsb3Ew4k/img.png&quot; data-alt=&quot;GPO 안 모습&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cgVjdf/dJMcaibdxyh/tufDOJAJnShyQ6Dsb3Ew4k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcgVjdf%2FdJMcaibdxyh%2FtufDOJAJnShyQ6Dsb3Ew4k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;GPO 안 모습&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Tkf9s/dJMcahi5Bmn/CL8MwV9WDxMMIyauHv9PMk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Tkf9s/dJMcahi5Bmn/CL8MwV9WDxMMIyauHv9PMk/img.png&quot; data-alt=&quot;GPO 앞 도로 모습&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Tkf9s/dJMcahi5Bmn/CL8MwV9WDxMMIyauHv9PMk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FTkf9s%2FdJMcahi5Bmn%2FCL8MwV9WDxMMIyauHv9PMk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;GPO 앞 도로 모습&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1689&quot; data-origin-height=&quot;3000&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/da7M6C/dJMcaaEfOcI/1krfpmcyAUjMt2dPtdPlt0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/da7M6C/dJMcaaEfOcI/1krfpmcyAUjMt2dPtdPlt0/img.png&quot; data-alt=&quot;괌에서 운전하는 모습&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/da7M6C/dJMcaaEfOcI/1krfpmcyAUjMt2dPtdPlt0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fda7M6C%2FdJMcaaEfOcI%2F1krfpmcyAUjMt2dPtdPlt0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1689&quot; height=&quot;3000&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1689&quot; data-origin-height=&quot;3000&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;괌에서 운전하는 모습&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;6. 럭셔리 다이닝의 정점, 츠바키 타워 뷔페&lt;/h2&gt;
&lt;p class=&quot;odin-text&quot; data-ke-size=&quot;size16&quot;&gt;이번 워크샵의 하이라이트는 단연 더 츠바키 타워의 카사 오세아노 뷔페였습니다. 괌에서 가장 비싼 호텔 뷔페답게 입장부터 분위기가 달랐습니다. 해산물 코너에는 신선한 사시미와 스시가 가득했고, 그릴 코너의 스테이크는 굽기가 완벽했습니다. 맥주와 와인이 무제한으로 제공된다는 점도 애주가들에게는 천국 같은 소식이죠. 식사를 하다 보면 창밖으로 분수 쇼가 펼쳐지는데, 라스베이거스만큼 웅장하진 않아도 괌의 밤하늘과 어우러져 꽤 로맨틱한 분위기를 연출합니다. 1인당 가격이 만만치 않지만, 여행 중 한 번쯤은 이런 호사를 누려보는 것도 나쁘지 않다는 생각이 들었습니다.&lt;/p&gt;
&lt;div class=&quot;img-placeholder&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nQ43S/dJMcacWkYLi/XcdxCFNtkZ1LqkkJLUCoA0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nQ43S/dJMcacWkYLi/XcdxCFNtkZ1LqkkJLUCoA0/img.png&quot; data-alt=&quot;입구에 있던 조형물&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nQ43S/dJMcacWkYLi/XcdxCFNtkZ1LqkkJLUCoA0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnQ43S%2FdJMcacWkYLi%2FXcdxCFNtkZ1LqkkJLUCoA0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;입구에 있던 조형물&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bUpPOr/dJMcacWkYLh/0VfYUiokv2wQTBhUnlgMP1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bUpPOr/dJMcacWkYLh/0VfYUiokv2wQTBhUnlgMP1/img.png&quot; data-alt=&quot;뷔폐 모습&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bUpPOr/dJMcacWkYLh/0VfYUiokv2wQTBhUnlgMP1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbUpPOr%2FdJMcacWkYLh%2F0VfYUiokv2wQTBhUnlgMP1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;뷔폐 모습&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2250&quot; data-origin-height=&quot;3000&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bUgd3x/dJMcaiCfb53/Bhwolkd16DPf9awAeqoJUK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bUgd3x/dJMcaiCfb53/Bhwolkd16DPf9awAeqoJUK/img.png&quot; data-alt=&quot;뷔폐 모습&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bUgd3x/dJMcaiCfb53/Bhwolkd16DPf9awAeqoJUK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbUgd3x%2FdJMcaiCfb53%2FBhwolkd16DPf9awAeqoJUK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2250&quot; height=&quot;3000&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2250&quot; data-origin-height=&quot;3000&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;뷔폐 모습&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2250&quot; data-origin-height=&quot;3000&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cu5XUH/dJMcaiCfb52/MjRX4zw2OFtQErJgLdRblk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cu5XUH/dJMcaiCfb52/MjRX4zw2OFtQErJgLdRblk/img.png&quot; data-alt=&quot;뷔폐 모습&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cu5XUH/dJMcaiCfb52/MjRX4zw2OFtQErJgLdRblk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcu5XUH%2FdJMcaiCfb52%2FMjRX4zw2OFtQErJgLdRblk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2250&quot; height=&quot;3000&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2250&quot; data-origin-height=&quot;3000&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;뷔폐 모습&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/7rnuF/dJMcaiCfb51/CibyvpjZD4xQBgvsHwmaV0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/7rnuF/dJMcaiCfb51/CibyvpjZD4xQBgvsHwmaV0/img.png&quot; data-alt=&quot;뷔폐에서 밖을 바라본 야경모습&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/7rnuF/dJMcaiCfb51/CibyvpjZD4xQBgvsHwmaV0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F7rnuF%2FdJMcaiCfb51%2FCibyvpjZD4xQBgvsHwmaV0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;뷔폐에서 밖을 바라본 야경모습&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1689&quot; data-origin-height=&quot;3000&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Q07ql/dJMcacWkYLj/vGhzatMYcvs5ddEWl9FLJk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Q07ql/dJMcacWkYLj/vGhzatMYcvs5ddEWl9FLJk/img.png&quot; data-alt=&quot;분수쇼 모습&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Q07ql/dJMcacWkYLj/vGhzatMYcvs5ddEWl9FLJk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQ07ql%2FdJMcacWkYLj%2FvGhzatMYcvs5ddEWl9FLJk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1689&quot; height=&quot;3000&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1689&quot; data-origin-height=&quot;3000&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;분수쇼 모습&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;7. 남부 투어와 역사적 의미, 그리고 주유소 이용 팁&lt;/h2&gt;
&lt;p class=&quot;odin-text&quot; data-ke-size=&quot;size16&quot;&gt;마지막 날 아침에는 바로 차를 쓸 수 없기도 했고 주위를 둘러 보기로 했습니다. 괌 프라자 근처에 재팬스토어도 있었고 아침에 조식 대신 다른 것을 먹자라는 생각으로 근처에 브런치 먹을 곳을 찾아보니 더 크랙드 에그 (The kracked egg)로 가보기로 했습니다. 이때 저는 치즈버거를 먹었는데 머스타드소스가 정말 맛있었습니다. 한국에서 흔히 먹던 머스타드 소스와는 다른 맛이였습니다. 그렇게 다시 숙소로 돌아가면서 카페에 들러 커피한잔을 했습니다. 밀크티 같은 느낌으로 맛있습니다.&lt;/p&gt;
&lt;p class=&quot;odin-text&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;odin-text&quot; data-ke-size=&quot;size16&quot;&gt;렌트카를 타고 남부로 드라이브를 떠났습니다. 괌의 도로는 운전하기 편하지만, 주유소 이용 방식은 한국과 달라 당황할 수 있습니다. 괌의 쉘(Shell) 주유소는 대부분 셀프인데, 한국처럼 기계에서 바로 결제하는 게 아닙니다. 먼저 주유기 앞에 차를 대고 주유기를 든 다음, 편의점 안으로 들어가 직원에게 3번 주유기, 레귤러 가득(Number 3, Regular Full)이라고 말하고 결제를 해야 기름이 나옵니다. 처음엔 어색했지만 몇 번 해보니 이 아날로그적인 방식도 꽤 재미있더군요.&lt;/p&gt;
&lt;p class=&quot;odin-text&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;odin-text&quot; data-ke-size=&quot;size16&quot;&gt;사랑의 절벽에도 들렀습니다. 탁 트인 바다 전망도 좋았지만, 개인적으로 더 기억에 남는 건 그곳에 있는 9/11 평화 기념비였습니다. 세계 무역 센터를 상징하는 두 기둥을 괌의 전통 가옥 양식인 라떼 스톤이 받치고 있는 형상인데, 괌이 지리적으로는 멀리 떨어져 있어도 엄연한 미국의 영토이며 그 아픔을 함께하고 있다는 연대감을 느낄 수 있었습니다. 그리고 바로 근처에 위치하고 있는 건비치를 가게 되었는데 이파오와 다른 느낌으로 조용하고 야경이 정말 이뻤습니다. 그리고 공항이 바로 근처이다보니 비행기가 왔다갔다 하는 모습과 함께 정말 이쁜 모습이였습니다.&lt;/p&gt;
&lt;div class=&quot;img-placeholder&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/HVHNl/dJMcabiROOE/25fZmDbzdcfmOARwbeer5k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/HVHNl/dJMcabiROOE/25fZmDbzdcfmOARwbeer5k/img.png&quot; data-alt=&quot;브런치 먹으러가는 카페 길거리 모습&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/HVHNl/dJMcabiROOE/25fZmDbzdcfmOARwbeer5k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHVHNl%2FdJMcabiROOE%2F25fZmDbzdcfmOARwbeer5k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;브런치 먹으러가는 카페 길거리 모습&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/TWcjn/dJMcagYKrNC/qWyTzVa8zXr2IT9CKM1I51/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/TWcjn/dJMcagYKrNC/qWyTzVa8zXr2IT9CKM1I51/img.png&quot; data-alt=&quot;가는 길에 건물이 이뻐서 찍었다&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/TWcjn/dJMcagYKrNC/qWyTzVa8zXr2IT9CKM1I51/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FTWcjn%2FdJMcagYKrNC%2FqWyTzVa8zXr2IT9CKM1I51%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;가는 길에 건물이 이뻐서 찍었다&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cddzBd/dJMcadHGvr5/sFunUK1GzGI1ZgPIariDy0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cddzBd/dJMcadHGvr5/sFunUK1GzGI1ZgPIariDy0/img.png&quot; data-alt=&quot;더 크랙드 에그 매장 모습&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cddzBd/dJMcadHGvr5/sFunUK1GzGI1ZgPIariDy0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcddzBd%2FdJMcadHGvr5%2FsFunUK1GzGI1ZgPIariDy0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;더 크랙드 에그 매장 모습&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1689&quot; data-origin-height=&quot;3000&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/k3pmR/dJMcagYKrNB/eqEHsI8pUBQlkTFSAwB94k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/k3pmR/dJMcagYKrNB/eqEHsI8pUBQlkTFSAwB94k/img.png&quot; data-alt=&quot;매장 모습&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/k3pmR/dJMcagYKrNB/eqEHsI8pUBQlkTFSAwB94k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fk3pmR%2FdJMcagYKrNB%2FeqEHsI8pUBQlkTFSAwB94k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1689&quot; height=&quot;3000&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1689&quot; data-origin-height=&quot;3000&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;매장 모습&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/JD8VE/dJMcajgPae2/cNhSkBA8IIzAqRXEy2rR5k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/JD8VE/dJMcajgPae2/cNhSkBA8IIzAqRXEy2rR5k/img.png&quot; data-alt=&quot;치즈버거 세트 모습&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/JD8VE/dJMcajgPae2/cNhSkBA8IIzAqRXEy2rR5k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJD8VE%2FdJMcajgPae2%2FcNhSkBA8IIzAqRXEy2rR5k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;치즈버거 세트 모습&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/3VogP/dJMcacB3K8c/1dcKlxpvg70NsgpUKJCus1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/3VogP/dJMcacB3K8c/1dcKlxpvg70NsgpUKJCus1/img.png&quot; data-alt=&quot;치즈버거 모습&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/3VogP/dJMcacB3K8c/1dcKlxpvg70NsgpUKJCus1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F3VogP%2FdJMcacB3K8c%2F1dcKlxpvg70NsgpUKJCus1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;치즈버거 모습&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1689&quot; data-origin-height=&quot;3000&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bAnzld/dJMcaaRNGrr/IGw83kGwiVPpIerbOgM5Sk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bAnzld/dJMcaaRNGrr/IGw83kGwiVPpIerbOgM5Sk/img.png&quot; data-alt=&quot;돌아가는 길에 본 카페에 바로 들어가본다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bAnzld/dJMcaaRNGrr/IGw83kGwiVPpIerbOgM5Sk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbAnzld%2FdJMcaaRNGrr%2FIGw83kGwiVPpIerbOgM5Sk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1689&quot; height=&quot;3000&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1689&quot; data-origin-height=&quot;3000&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;돌아가는 길에 본 카페에 바로 들어가본다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1689&quot; data-origin-height=&quot;3000&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bYNJ2m/dJMcag5xpFg/Q7Z7k6Uq8cXPp94LONk0jk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bYNJ2m/dJMcag5xpFg/Q7Z7k6Uq8cXPp94LONk0jk/img.png&quot; data-alt=&quot;우유와 아메리카노 이렇게 섞인거였는데 맛있었다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bYNJ2m/dJMcag5xpFg/Q7Z7k6Uq8cXPp94LONk0jk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbYNJ2m%2FdJMcag5xpFg%2FQ7Z7k6Uq8cXPp94LONk0jk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1689&quot; height=&quot;3000&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1689&quot; data-origin-height=&quot;3000&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;우유와 아메리카노 이렇게 섞인거였는데 맛있었다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1689&quot; data-origin-height=&quot;3000&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bSkzXH/dJMcadHGvaV/GWDlvU8wECJMCQQu78lt1k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bSkzXH/dJMcadHGvaV/GWDlvU8wECJMCQQu78lt1k/img.png&quot; data-alt=&quot;주유하는 모습&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bSkzXH/dJMcadHGvaV/GWDlvU8wECJMCQQu78lt1k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbSkzXH%2FdJMcadHGvaV%2FGWDlvU8wECJMCQQu78lt1k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1689&quot; height=&quot;3000&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1689&quot; data-origin-height=&quot;3000&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;주유하는 모습&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rtUT9/dJMcagYKrt8/NnlHxAKRhJ317x6Ufswq7k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rtUT9/dJMcagYKrt8/NnlHxAKRhJ317x6Ufswq7k/img.png&quot; data-alt=&quot;주유소 마트 모습, 우리로 치면 그냥 흔한 편의점 느낌인듯&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rtUT9/dJMcagYKrt8/NnlHxAKRhJ317x6Ufswq7k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrtUT9%2FdJMcagYKrt8%2FNnlHxAKRhJ317x6Ufswq7k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;주유소 마트 모습, 우리로 치면 그냥 흔한 편의점 느낌인듯&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2250&quot; data-origin-height=&quot;3000&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bwyyLr/dJMcahchsiV/aYM8tar3PhHwqm8Uv80n00/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bwyyLr/dJMcahchsiV/aYM8tar3PhHwqm8Uv80n00/img.png&quot; data-alt=&quot;GPO 주유소 근처에서 찍은 무지개 이쁘다&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bwyyLr/dJMcahchsiV/aYM8tar3PhHwqm8Uv80n00/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbwyyLr%2FdJMcahchsiV%2FaYM8tar3PhHwqm8Uv80n00%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2250&quot; height=&quot;3000&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2250&quot; data-origin-height=&quot;3000&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;GPO 주유소 근처에서 찍은 무지개 이쁘다&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1689&quot; data-origin-height=&quot;3000&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/43BVx/dJMcadHGvaU/NgNTAsyKz0HDBhf0rSBByK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/43BVx/dJMcadHGvaU/NgNTAsyKz0HDBhf0rSBByK/img.png&quot; data-alt=&quot;피쉬아이수중전망대 못들어가고 입구를 찍는다..&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/43BVx/dJMcadHGvaU/NgNTAsyKz0HDBhf0rSBByK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F43BVx%2FdJMcadHGvaU%2FNgNTAsyKz0HDBhf0rSBByK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1689&quot; height=&quot;3000&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1689&quot; data-origin-height=&quot;3000&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;피쉬아이수중전망대 못들어가고 입구를 찍는다..&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2250&quot; data-origin-height=&quot;3000&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lfxLE/dJMcagYKrt6/T2rTBxkVSiHUzzGEJ20cEK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lfxLE/dJMcagYKrt6/T2rTBxkVSiHUzzGEJ20cEK/img.png&quot; data-alt=&quot;피쉬아이 수중전망대 (닫혀있어서 아쉽지만 이렇게 찍음)&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lfxLE/dJMcagYKrt6/T2rTBxkVSiHUzzGEJ20cEK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlfxLE%2FdJMcagYKrt6%2FT2rTBxkVSiHUzzGEJ20cEK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2250&quot; height=&quot;3000&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2250&quot; data-origin-height=&quot;3000&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;피쉬아이 수중전망대 (닫혀있어서 아쉽지만 이렇게 찍음)&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2249&quot; data-origin-height=&quot;3000&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/euJLeU/dJMcadHGvaT/C0tkD2YCSh6vLlQuFUhLOk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/euJLeU/dJMcadHGvaT/C0tkD2YCSh6vLlQuFUhLOk/img.png&quot; data-alt=&quot;피쉬아이 수중전망대 근처에서 물놀이 하는 외국인&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/euJLeU/dJMcadHGvaT/C0tkD2YCSh6vLlQuFUhLOk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FeuJLeU%2FdJMcadHGvaT%2FC0tkD2YCSh6vLlQuFUhLOk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2249&quot; height=&quot;3000&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2249&quot; data-origin-height=&quot;3000&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;피쉬아이 수중전망대 근처에서 물놀이 하는 외국인&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1689&quot; data-origin-height=&quot;3000&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/SIlgZ/dJMcahchsiW/8XffHLmWjpaycck8oO9r0K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/SIlgZ/dJMcahchsiW/8XffHLmWjpaycck8oO9r0K/img.png&quot; data-alt=&quot;피쉬아이수중전망대&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/SIlgZ/dJMcahchsiW/8XffHLmWjpaycck8oO9r0K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FSIlgZ%2FdJMcahchsiW%2F8XffHLmWjpaycck8oO9r0K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1689&quot; height=&quot;3000&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1689&quot; data-origin-height=&quot;3000&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;피쉬아이수중전망대&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bgbGvg/dJMcafevX8q/2KbfIzDKfGFct2pAHoSyU0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bgbGvg/dJMcafevX8q/2KbfIzDKfGFct2pAHoSyU0/img.png&quot; data-alt=&quot;파도가 밀려오는 수중전망대 이게 파도라고 해야할지 애매하긴하지만..&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bgbGvg/dJMcafevX8q/2KbfIzDKfGFct2pAHoSyU0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbgbGvg%2FdJMcafevX8q%2F2KbfIzDKfGFct2pAHoSyU0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;파도가 밀려오는 수중전망대 이게 파도라고 해야할지 애매하긴하지만..&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d80v3C/dJMcadHGvaS/w8Ox06tOZnIACXiz04JaFK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d80v3C/dJMcadHGvaS/w8Ox06tOZnIACXiz04JaFK/img.png&quot; data-alt=&quot;피쉬아이수중전망대를 못간 나의 모습&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d80v3C/dJMcadHGvaS/w8Ox06tOZnIACXiz04JaFK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd80v3C%2FdJMcadHGvaS%2Fw8Ox06tOZnIACXiz04JaFK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;피쉬아이수중전망대를 못간 나의 모습&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/YHNXQ/dJMcahchsiX/69UUwrI6OUXGM9HpN8AkxK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/YHNXQ/dJMcahchsiX/69UUwrI6OUXGM9HpN8AkxK/img.png&quot; data-alt=&quot;피쉬아이수중전망대 바로 옆 모습&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/YHNXQ/dJMcahchsiX/69UUwrI6OUXGM9HpN8AkxK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FYHNXQ%2FdJMcahchsiX%2F69UUwrI6OUXGM9HpN8AkxK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;피쉬아이수중전망대 바로 옆 모습&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Sgl7Q/dJMcahchsiY/KHywYeCF2cDuNaZ4uoB011/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Sgl7Q/dJMcahchsiY/KHywYeCF2cDuNaZ4uoB011/img.png&quot; data-alt=&quot;피쉬아이수중전망대근처모습&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Sgl7Q/dJMcahchsiY/KHywYeCF2cDuNaZ4uoB011/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FSgl7Q%2FdJMcahchsiY%2FKHywYeCF2cDuNaZ4uoB011%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;피쉬아이수중전망대근처모습&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/boi3wx/dJMcaaqHYCL/XmWokLokEbOegG8OWSNGQk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/boi3wx/dJMcaaqHYCL/XmWokLokEbOegG8OWSNGQk/img.png&quot; data-alt=&quot;스페인광장 아이러브괌 조형물&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/boi3wx/dJMcaaqHYCL/XmWokLokEbOegG8OWSNGQk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fboi3wx%2FdJMcaaqHYCL%2FXmWokLokEbOegG8OWSNGQk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;스페인광장 아이러브괌 조형물&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1689&quot; data-origin-height=&quot;3000&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/C8F4E/dJMcaaRNETU/CLft6p116JLoglKbeogO7K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/C8F4E/dJMcaaRNETU/CLft6p116JLoglKbeogO7K/img.png&quot; data-alt=&quot;스페인광장 조형물&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/C8F4E/dJMcaaRNETU/CLft6p116JLoglKbeogO7K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FC8F4E%2FdJMcaaRNETU%2FCLft6p116JLoglKbeogO7K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1689&quot; height=&quot;3000&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1689&quot; data-origin-height=&quot;3000&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;스페인광장 조형물&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2250&quot; data-origin-height=&quot;3000&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ZyA2H/dJMcaaRNETV/WLGEE6kqaLIWDpAkqQN5S0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ZyA2H/dJMcaaRNETV/WLGEE6kqaLIWDpAkqQN5S0/img.png&quot; data-alt=&quot;스페인광장 모습 사실 몇분전에 비가 쏟아졌었다&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ZyA2H/dJMcaaRNETV/WLGEE6kqaLIWDpAkqQN5S0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FZyA2H%2FdJMcaaRNETV%2FWLGEE6kqaLIWDpAkqQN5S0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2250&quot; height=&quot;3000&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2250&quot; data-origin-height=&quot;3000&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;스페인광장 모습 사실 몇분전에 비가 쏟아졌었다&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bd3weA/dJMcaaqHYCM/nWoF1TH3xk4odeNxocY1p0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bd3weA/dJMcaaqHYCM/nWoF1TH3xk4odeNxocY1p0/img.png&quot; data-alt=&quot;스페인광장 꽃 모습&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bd3weA/dJMcaaqHYCM/nWoF1TH3xk4odeNxocY1p0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbd3weA%2FdJMcaaqHYCM%2FnWoF1TH3xk4odeNxocY1p0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;스페인광장 꽃 모습&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bYp9Uu/dJMcaaYwUzT/avS4z6nJa6RA6aN54cgpjK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bYp9Uu/dJMcaaYwUzT/avS4z6nJa6RA6aN54cgpjK/img.png&quot; data-alt=&quot;스페인광장 모습&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bYp9Uu/dJMcaaYwUzT/avS4z6nJa6RA6aN54cgpjK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbYp9Uu%2FdJMcaaYwUzT%2FavS4z6nJa6RA6aN54cgpjK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;스페인광장 모습&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vddFA/dJMcaaYwUzU/ZPsiodLYJhGYfSk2uKgGi0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vddFA/dJMcaaYwUzU/ZPsiodLYJhGYfSk2uKgGi0/img.png&quot; data-alt=&quot;스페인광장 바로 근처에 있는 성당&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vddFA/dJMcaaYwUzU/ZPsiodLYJhGYfSk2uKgGi0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvddFA%2FdJMcaaYwUzU%2FZPsiodLYJhGYfSk2uKgGi0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;스페인광장 바로 근처에 있는 성당&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cqv6Vz/dJMcaaYwUzV/mXuXFB5aoNdHnT1kas1zXk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cqv6Vz/dJMcaaYwUzV/mXuXFB5aoNdHnT1kas1zXk/img.png&quot; data-alt=&quot;스페인광장 근처 박물관&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cqv6Vz/dJMcaaYwUzV/mXuXFB5aoNdHnT1kas1zXk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcqv6Vz%2FdJMcaaYwUzV%2FmXuXFB5aoNdHnT1kas1zXk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;스페인광장 근처 박물관&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cCo4tC/dJMcaaYwUzW/B6HwJX798xkBbBljnXuWMk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cCo4tC/dJMcaaYwUzW/B6HwJX798xkBbBljnXuWMk/img.png&quot; data-alt=&quot;스페인광장 모습&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cCo4tC/dJMcaaYwUzW/B6HwJX798xkBbBljnXuWMk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcCo4tC%2FdJMcaaYwUzW%2FB6HwJX798xkBbBljnXuWMk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;스페인광장 모습&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1689&quot; data-origin-height=&quot;3000&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/52aAG/dJMcahi5BNe/iILNl2o6grkJsNiLBeAh0K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/52aAG/dJMcahi5BNe/iILNl2o6grkJsNiLBeAh0K/img.png&quot; data-alt=&quot;스페인광장에서 바라본 성당모습&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/52aAG/dJMcahi5BNe/iILNl2o6grkJsNiLBeAh0K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F52aAG%2FdJMcahi5BNe%2FiILNl2o6grkJsNiLBeAh0K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1689&quot; height=&quot;3000&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1689&quot; data-origin-height=&quot;3000&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;스페인광장에서 바라본 성당모습&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2250&quot; data-origin-height=&quot;3000&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/OMQFw/dJMcahi5Dnk/zQTBh59ebi7C6IyiagxIK1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/OMQFw/dJMcahi5Dnk/zQTBh59ebi7C6IyiagxIK1/img.png&quot; data-alt=&quot;시원하게 펼쳐져있는 사랑의절벽&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/OMQFw/dJMcahi5Dnk/zQTBh59ebi7C6IyiagxIK1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOMQFw%2FdJMcahi5Dnk%2FzQTBh59ebi7C6IyiagxIK1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2250&quot; height=&quot;3000&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2250&quot; data-origin-height=&quot;3000&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;시원하게 펼쳐져있는 사랑의절벽&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1689&quot; data-origin-height=&quot;3000&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bUfmWH/dJMcaaYwVOT/6PxvwzgOzkyd9LizhqJ59k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bUfmWH/dJMcaaYwVOT/6PxvwzgOzkyd9LizhqJ59k/img.png&quot; data-alt=&quot;사랑의절벽에 있는 평화기념비&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bUfmWH/dJMcaaYwVOT/6PxvwzgOzkyd9LizhqJ59k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbUfmWH%2FdJMcaaYwVOT%2F6PxvwzgOzkyd9LizhqJ59k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1689&quot; height=&quot;3000&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1689&quot; data-origin-height=&quot;3000&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;사랑의절벽에 있는 평화기념비&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1689&quot; data-origin-height=&quot;3000&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zjR1R/dJMcagj8Rpt/aImbjm6zMKvja9k5G8yISk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zjR1R/dJMcagj8Rpt/aImbjm6zMKvja9k5G8yISk/img.png&quot; data-alt=&quot;평화기념비의 안내표지판&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zjR1R/dJMcagj8Rpt/aImbjm6zMKvja9k5G8yISk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzjR1R%2FdJMcagj8Rpt%2FaImbjm6zMKvja9k5G8yISk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1689&quot; height=&quot;3000&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1689&quot; data-origin-height=&quot;3000&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;평화기념비의 안내표지판&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;KakaoTalk_20260215_015318574_11.jpg&quot; data-origin-width=&quot;4000&quot; data-origin-height=&quot;2252&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lZFFe/dJMcagdo5Rp/NfKYAfAsbxDfpBRfnBZiX0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lZFFe/dJMcagdo5Rp/NfKYAfAsbxDfpBRfnBZiX0/img.jpg&quot; data-alt=&quot;사랑의 절벽 모습&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lZFFe/dJMcagdo5Rp/NfKYAfAsbxDfpBRfnBZiX0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlZFFe%2FdJMcagdo5Rp%2FNfKYAfAsbxDfpBRfnBZiX0%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;4000&quot; height=&quot;2252&quot; data-filename=&quot;KakaoTalk_20260215_015318574_11.jpg&quot; data-origin-width=&quot;4000&quot; data-origin-height=&quot;2252&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;사랑의 절벽 모습&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1689&quot; data-origin-height=&quot;3000&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cEIYiq/dJMcagj8Rpy/bxKTIHBAcE1u13xrHKPCIk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cEIYiq/dJMcagj8Rpy/bxKTIHBAcE1u13xrHKPCIk/img.png&quot; data-alt=&quot;사랑의절벽 사랑의 종&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cEIYiq/dJMcagj8Rpy/bxKTIHBAcE1u13xrHKPCIk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcEIYiq%2FdJMcagj8Rpy%2FbxKTIHBAcE1u13xrHKPCIk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1689&quot; height=&quot;3000&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1689&quot; data-origin-height=&quot;3000&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;사랑의절벽 사랑의 종&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cgiaMH/dJMcaaYwVOS/6cEMSA0axkb5nn7jRkpT30/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cgiaMH/dJMcaaYwVOS/6cEMSA0axkb5nn7jRkpT30/img.png&quot; data-alt=&quot;사랑의 절벽 일몰&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cgiaMH/dJMcaaYwVOS/6cEMSA0axkb5nn7jRkpT30/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcgiaMH%2FdJMcaaYwVOS%2F6cEMSA0axkb5nn7jRkpT30%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;사랑의 절벽 일몰&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/DnMyx/dJMcaaYwVOV/hy0yXOMMtJ6nhaIafiZrSk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/DnMyx/dJMcaaYwVOV/hy0yXOMMtJ6nhaIafiZrSk/img.png&quot; data-alt=&quot;사랑의 절벽 모습&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/DnMyx/dJMcaaYwVOV/hy0yXOMMtJ6nhaIafiZrSk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDnMyx%2FdJMcaaYwVOV%2Fhy0yXOMMtJ6nhaIafiZrSk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;사랑의 절벽 모습&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1689&quot; data-origin-height=&quot;3000&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/MRDP9/dJMcagj8Rpu/FtSOv9SZoJyYxedEfzrmk0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/MRDP9/dJMcagj8Rpu/FtSOv9SZoJyYxedEfzrmk0/img.png&quot; data-alt=&quot;사랑의절벽 자물쇠&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/MRDP9/dJMcagj8Rpu/FtSOv9SZoJyYxedEfzrmk0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMRDP9%2FdJMcagj8Rpu%2FFtSOv9SZoJyYxedEfzrmk0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1689&quot; height=&quot;3000&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1689&quot; data-origin-height=&quot;3000&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;사랑의절벽 자물쇠&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lXAAO/dJMcaaYwVOR/2Cz4xT4XqY5SJK9RWbJqMk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lXAAO/dJMcaaYwVOR/2Cz4xT4XqY5SJK9RWbJqMk/img.png&quot; data-alt=&quot;사랑의절벽에는 비행기도 다니는것을 볼 수 있다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lXAAO/dJMcaaYwVOR/2Cz4xT4XqY5SJK9RWbJqMk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlXAAO%2FdJMcaaYwVOR%2F2Cz4xT4XqY5SJK9RWbJqMk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;사랑의절벽에는 비행기도 다니는것을 볼 수 있다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bsOexu/dJMcahi5Dnl/z3Fxwi7mxI1w1M5ixFQUD1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bsOexu/dJMcahi5Dnl/z3Fxwi7mxI1w1M5ixFQUD1/img.png&quot; data-alt=&quot;사랑의절벽 해가 지기 시작한다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bsOexu/dJMcahi5Dnl/z3Fxwi7mxI1w1M5ixFQUD1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbsOexu%2FdJMcahi5Dnl%2Fz3Fxwi7mxI1w1M5ixFQUD1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;사랑의절벽 해가 지기 시작한다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bEZKgY/dJMcaaYwVOW/ulBtzVoyg0qww6s0FMGvB1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bEZKgY/dJMcaaYwVOW/ulBtzVoyg0qww6s0FMGvB1/img.png&quot; data-alt=&quot;멍 때리고 보면 좋다&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bEZKgY/dJMcaaYwVOW/ulBtzVoyg0qww6s0FMGvB1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbEZKgY%2FdJMcaaYwVOW%2FulBtzVoyg0qww6s0FMGvB1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;멍 때리고 보면 좋다&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/k06xG/dJMcagj8Rpw/zL0pT0aeOGQedIBeGacuX1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/k06xG/dJMcagj8Rpw/zL0pT0aeOGQedIBeGacuX1/img.png&quot; data-alt=&quot;바로 아래 보면 해변같이 모래도 있다&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/k06xG/dJMcagj8Rpw/zL0pT0aeOGQedIBeGacuX1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fk06xG%2FdJMcagj8Rpw%2FzL0pT0aeOGQedIBeGacuX1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;바로 아래 보면 해변같이 모래도 있다&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1689&quot; data-origin-height=&quot;3000&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bciMLW/dJMcagj8Rpv/7iZA98yMhAXckxYXII29ck/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bciMLW/dJMcagj8Rpv/7iZA98yMhAXckxYXII29ck/img.png&quot; data-alt=&quot;사랑의 절벽 입장권&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bciMLW/dJMcagj8Rpv/7iZA98yMhAXckxYXII29ck/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbciMLW%2FdJMcagj8Rpv%2F7iZA98yMhAXckxYXII29ck%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1689&quot; height=&quot;3000&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1689&quot; data-origin-height=&quot;3000&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;사랑의 절벽 입장권&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kDsSr/dJMcaaYwVOX/OquacE69G9uUK7S2M4PKb1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kDsSr/dJMcaaYwVOX/OquacE69G9uUK7S2M4PKb1/img.png&quot; data-alt=&quot;사랑의 절벽 입구에 있는 하트 조형물&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kDsSr/dJMcaaYwVOX/OquacE69G9uUK7S2M4PKb1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkDsSr%2FdJMcaaYwVOX%2FOquacE69G9uUK7S2M4PKb1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;사랑의 절벽 입구에 있는 하트 조형물&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cdRjXV/dJMcahi5Dnn/4KkhQuyqLgR6sgOTPWlt8K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cdRjXV/dJMcahi5Dnn/4KkhQuyqLgR6sgOTPWlt8K/img.png&quot; data-alt=&quot;사랑의 절벽 건물&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cdRjXV/dJMcahi5Dnn/4KkhQuyqLgR6sgOTPWlt8K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcdRjXV%2FdJMcahi5Dnn%2F4KkhQuyqLgR6sgOTPWlt8K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;사랑의 절벽 건물&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1689&quot; data-origin-height=&quot;3000&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cv8Zft/dJMcahi5Dnm/jSAsK1DSs4PWYzRpXewTL0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cv8Zft/dJMcahi5Dnm/jSAsK1DSs4PWYzRpXewTL0/img.png&quot; data-alt=&quot;사랑의 절벽 우연히 찍었는데 이쁘다&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cv8Zft/dJMcahi5Dnm/jSAsK1DSs4PWYzRpXewTL0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcv8Zft%2FdJMcahi5Dnm%2FjSAsK1DSs4PWYzRpXewTL0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1689&quot; height=&quot;3000&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1689&quot; data-origin-height=&quot;3000&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;사랑의 절벽 우연히 찍었는데 이쁘다&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;KakaoTalk_20260215_015318574_10.jpg&quot; data-origin-width=&quot;4000&quot; data-origin-height=&quot;2252&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/UiVoG/dJMcafr0dq0/MpZIlcIK53yyxQMfF0gIa0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/UiVoG/dJMcafr0dq0/MpZIlcIK53yyxQMfF0gIa0/img.jpg&quot; data-alt=&quot;사랑의절벽&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/UiVoG/dJMcafr0dq0/MpZIlcIK53yyxQMfF0gIa0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FUiVoG%2FdJMcafr0dq0%2FMpZIlcIK53yyxQMfF0gIa0%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;4000&quot; height=&quot;2252&quot; data-filename=&quot;KakaoTalk_20260215_015318574_10.jpg&quot; data-origin-width=&quot;4000&quot; data-origin-height=&quot;2252&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;사랑의절벽&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/CpHxH/dJMcaaRNGgB/bmCooWH6ZaNF7QctjOGjE0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/CpHxH/dJMcaaRNGgB/bmCooWH6ZaNF7QctjOGjE0/img.png&quot; data-alt=&quot;건비치 야경 너무 이쁘다&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/CpHxH/dJMcaaRNGgB/bmCooWH6ZaNF7QctjOGjE0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCpHxH%2FdJMcaaRNGgB%2FbmCooWH6ZaNF7QctjOGjE0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;건비치 야경 너무 이쁘다&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/RAOGO/dJMb99SRhiI/4r4plsY1EvKMh6M5E7aw80/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/RAOGO/dJMb99SRhiI/4r4plsY1EvKMh6M5E7aw80/img.png&quot; data-alt=&quot;건비치에서도 비행기가 지나가는게 보인다&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/RAOGO/dJMb99SRhiI/4r4plsY1EvKMh6M5E7aw80/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FRAOGO%2FdJMb99SRhiI%2F4r4plsY1EvKMh6M5E7aw80%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;건비치에서도 비행기가 지나가는게 보인다&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xOGlc/dJMcaaRNGgD/knLm8E6jINyRiElukUorCK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xOGlc/dJMcaaRNGgD/knLm8E6jINyRiElukUorCK/img.png&quot; data-alt=&quot;건비치에 위치하고 있는 레스토랑&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xOGlc/dJMcaaRNGgD/knLm8E6jINyRiElukUorCK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FxOGlc%2FdJMcaaRNGgD%2FknLm8E6jINyRiElukUorCK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;건비치에 위치하고 있는 레스토랑&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2250&quot; data-origin-height=&quot;3000&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dDBSib/dJMcabQFsBD/JOoKD1OUO6URJ9q1kICfuK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dDBSib/dJMcabQFsBD/JOoKD1OUO6URJ9q1kICfuK/img.png&quot; data-alt=&quot;건비치로 들어가는중&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dDBSib/dJMcabQFsBD/JOoKD1OUO6URJ9q1kICfuK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdDBSib%2FdJMcabQFsBD%2FJOoKD1OUO6URJ9q1kICfuK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2250&quot; height=&quot;3000&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2250&quot; data-origin-height=&quot;3000&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;건비치로 들어가는중&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2249&quot; data-origin-height=&quot;3000&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Kg7Ms/dJMb99SRhiM/Bqyr3b7jyQnZAZHsAPyFH1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Kg7Ms/dJMb99SRhiM/Bqyr3b7jyQnZAZHsAPyFH1/img.png&quot; data-alt=&quot;건비치에서 여유를 즐기며 놀고 있는 사람들 부럽다&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Kg7Ms/dJMb99SRhiM/Bqyr3b7jyQnZAZHsAPyFH1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKg7Ms%2FdJMb99SRhiM%2FBqyr3b7jyQnZAZHsAPyFH1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2249&quot; height=&quot;3000&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2249&quot; data-origin-height=&quot;3000&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;건비치에서 여유를 즐기며 놀고 있는 사람들 부럽다&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2250&quot; data-origin-height=&quot;3000&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bkjM2F/dJMb99SRhiN/P4OFwmKf7WnJeFittgowX0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bkjM2F/dJMb99SRhiN/P4OFwmKf7WnJeFittgowX0/img.png&quot; data-alt=&quot;건비치 야경 진짜 이쁘다&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bkjM2F/dJMb99SRhiN/P4OFwmKf7WnJeFittgowX0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbkjM2F%2FdJMb99SRhiN%2FP4OFwmKf7WnJeFittgowX0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2250&quot; height=&quot;3000&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2250&quot; data-origin-height=&quot;3000&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;건비치 야경 진짜 이쁘다&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2250&quot; data-origin-height=&quot;3000&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mFxdu/dJMcaaEfPKq/82fMUivC7KHKdit8T49qQ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mFxdu/dJMcaaEfPKq/82fMUivC7KHKdit8T49qQ0/img.png&quot; data-alt=&quot;저기서 음식은 맛있게 먹을듯&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mFxdu/dJMcaaEfPKq/82fMUivC7KHKdit8T49qQ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmFxdu%2FdJMcaaEfPKq%2F82fMUivC7KHKdit8T49qQ0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2250&quot; height=&quot;3000&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2250&quot; data-origin-height=&quot;3000&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;저기서 음식은 맛있게 먹을듯&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/1wqH5/dJMcabwmHVj/5ZzSCVspWzAB5kXgmIjrk1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/1wqH5/dJMcabwmHVj/5ZzSCVspWzAB5kXgmIjrk1/img.png&quot; data-alt=&quot;건비치 해변&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/1wqH5/dJMcabwmHVj/5ZzSCVspWzAB5kXgmIjrk1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F1wqH5%2FdJMcabwmHVj%2F5ZzSCVspWzAB5kXgmIjrk1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;건비치 해변&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1689&quot; data-origin-height=&quot;3000&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wcHWv/dJMcaaqHZYU/FLvusZe568drkbi2kViLmK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wcHWv/dJMcaaqHZYU/FLvusZe568drkbi2kViLmK/img.png&quot; data-alt=&quot;괌 리조트 근처에 있는 놀이동산&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wcHWv/dJMcaaqHZYU/FLvusZe568drkbi2kViLmK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwcHWv%2FdJMcaaqHZYU%2FFLvusZe568drkbi2kViLmK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1689&quot; height=&quot;3000&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1689&quot; data-origin-height=&quot;3000&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;괌 리조트 근처에 있는 놀이동산&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wmOTq/dJMcahXFqSQ/dMBOiDTflrsQjTxvoBqui1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wmOTq/dJMcahXFqSQ/dMBOiDTflrsQjTxvoBqui1/img.png&quot; data-alt=&quot;디스코팡팡도 있다&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wmOTq/dJMcahXFqSQ/dMBOiDTflrsQjTxvoBqui1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwmOTq%2FdJMcahXFqSQ%2FdMBOiDTflrsQjTxvoBqui1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;디스코팡팡도 있다&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1689&quot; data-origin-height=&quot;3000&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bMcEnR/dJMcahXFqSP/7QywQUKzDdIKC0NJO9wLD1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bMcEnR/dJMcahXFqSP/7QywQUKzDdIKC0NJO9wLD1/img.png&quot; data-alt=&quot;바이킹 조명 화려함&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bMcEnR/dJMcahXFqSP/7QywQUKzDdIKC0NJO9wLD1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbMcEnR%2FdJMcahXFqSP%2F7QywQUKzDdIKC0NJO9wLD1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1689&quot; height=&quot;3000&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1689&quot; data-origin-height=&quot;3000&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;바이킹 조명 화려함&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bU4CR1/dJMcaaqHZYV/l7FMifD8f0Rdk1TqQNT4o1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bU4CR1/dJMcaaqHZYV/l7FMifD8f0Rdk1TqQNT4o1/img.png&quot; data-alt=&quot;이 날 투몬거리에서 행사를 한다고 경찰이 거리 일부를 통제했다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bU4CR1/dJMcaaqHZYV/l7FMifD8f0Rdk1TqQNT4o1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbU4CR1%2FdJMcaaqHZYV%2Fl7FMifD8f0Rdk1TqQNT4o1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;이 날 투몬거리에서 행사를 한다고 경찰이 거리 일부를 통제했다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dfWElP/dJMcacPBaBr/fC4IGukCZJ9AwrsB9zJ170/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dfWElP/dJMcacPBaBr/fC4IGukCZJ9AwrsB9zJ170/img.png&quot; data-alt=&quot;미국이긴 하다.. 펄럭펄럭 성조기&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dfWElP/dJMcacPBaBr/fC4IGukCZJ9AwrsB9zJ170/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdfWElP%2FdJMcacPBaBr%2FfC4IGukCZJ9AwrsB9zJ170%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;미국이긴 하다.. 펄럭펄럭 성조기&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;8. 여행을 마치며&lt;/h2&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1689&quot; data-origin-height=&quot;3000&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c1kuAL/dJMcadVdHq9/KPcQE1ZHsWji2Vj8D2TIJ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c1kuAL/dJMcadVdHq9/KPcQE1ZHsWji2Vj8D2TIJ1/img.png&quot; data-alt=&quot;한국 거의 다 도착했을 때 비행기에서 찍었다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c1kuAL/dJMcadVdHq9/KPcQE1ZHsWji2Vj8D2TIJ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc1kuAL%2FdJMcadVdHq9%2FKPcQE1ZHsWji2Vj8D2TIJ1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;491&quot; height=&quot;872&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1689&quot; data-origin-height=&quot;3000&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;한국 거의 다 도착했을 때 비행기에서 찍었다.&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p class=&quot;odin-text&quot; data-ke-size=&quot;size16&quot;&gt;월요일 아침, 다시 김해공항에 도착했을 때의 그 쌀쌀한 공기는 현실 복귀를 알리는 신호 같았습니다. 3박 5일이라는 짧은 시간이었지만, 괌은 생각보다 많은 것을 보여주었습니다. 높은 환율과 물가가 부담스럽긴 하지만, 한국에서 가장 편하게 다녀올 수 있는 미국이라는 점, 그리고 렌트카 하나면 어디든 갈 수 있는 자유로움은 여전히 매력적입니다.&lt;/p&gt;
&lt;p class=&quot;odin-text&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;odin-text&quot; data-ke-size=&quot;size16&quot;&gt;혹시 2025년에 괌 여행을 계획하고 계신다면, 너무 빡빡한 일정보다는 날씨에 따라 유동적으로 움직일 수 있는 여유를 두시길 권합니다. 그리고 돈키호테는 꼭 밤늦게 가보세요. 텅 빈 매장을 전세 낸 것처럼 쇼핑하는 재미가 쏠쏠합니다. 이번 워크샵 겸 여행 기록이 여러분의 괌 여행 준비에 조금이나마 도움이 되었기를 바랍니다.&lt;/p&gt;
&lt;/div&gt;</description>
      <category>DailyRoutine</category>
      <category>괌3박5일</category>
      <category>괌돈키호테</category>
      <category>괌렌트카</category>
      <category>괌맛집</category>
      <category>괌쇼핑</category>
      <category>괌여행</category>
      <category>괌자유여행</category>
      <category>부산출발괌</category>
      <category>사랑의절벽</category>
      <category>직장인워크샵</category>
      <author>간지뽕빨리턴님</author>
      <guid isPermaLink="true">https://odinbox.tistory.com/571</guid>
      <comments>https://odinbox.tistory.com/571#entry571comment</comments>
      <pubDate>Sun, 15 Feb 2026 18:49:47 +0900</pubDate>
    </item>
    <item>
      <title>왜 긁어 부스럼을 만드냐고요? 혁신을 위해서입니다.</title>
      <link>https://odinbox.tistory.com/570</link>
      <description>&lt;div&gt;
&lt;style&gt;
    :root {
        --odin-accent : #0056b3;   /* 신뢰감을 주는 딥 블루 */
        --odin-dark : #212529;     /* 본문 기본 색상 */
        --odin-gray : #6c757d;     /* 보조 텍스트 */
        --odin-bg : #ffffff;       /* 배경색 */
        --odin-light-bg : #f8f9fa; /* 카드 배경색 */
        --odin-border : #dee2e6;   /* 테두리 색상 */
    }

    .ODINLIFEISGOOD_container {
        font-family : 'Pretendard', -apple-system, BlinkMacSystemFont, 'Malgun Gothic', sans-serif;
        line-height : 1.75;
        color : var(--odin-dark);
        max-width : 880px;
        margin : 0 auto;
        padding : 30px 20px 50px; /* 상단 패딩 조정 */
        background-color : var(--odin-bg);
        word-break : keep-all; /* 한글 가독성 최적화 */
    }

    /* 썸네일 이미지 스타일 */
    .ODINLIFEISGOOD_thumbnail {
        margin-bottom : 40px;
        text-align : center;
    }
    
    .ODINLIFEISGOOD_thumbnail img {
        max-width : 100%;
        height : auto;
        border-radius : 12px;
        box-shadow : 0 10px 25px rgba(0,0,0,0.1);
    }

    /* 애니메이션 효과 */
    .ODINLIFEISGOOD_fade_in {
        opacity : 0;
        transform : translateY(20px);
        transition : opacity 0.8s ease, transform 0.8s ease;
    }

    .ODINLIFEISGOOD_fade_in.ODINLIFEISGOOD_active {
        opacity : 1;
        transform : translateY(0);
    }

    /* 헤더 스타일 */
    .ODINLIFEISGOOD_header {
        margin-bottom : 60px;
        border-bottom : 2px solid var(--odin-dark);
        padding-bottom : 30px;
        text-align : center;
    }

    .ODINLIFEISGOOD_header h2 { /* 부제 */
        font-size : 1.3rem;
        color : var(--odin-gray);
        font-weight : 600;
        margin-top : 15px;
    }

    /* 섹션 공통 스타일 */
    .ODINLIFEISGOOD_section_title {
        font-size : 1.6rem;
        color : var(--odin-accent);
        margin-top : 80px;
        margin-bottom : 25px;
        font-weight : 700;
        display : flex;
        align-items : center;
    }

    .ODINLIFEISGOOD_section_title::before {
        content : '';
        display : block;
        width : 6px;
        height : 24px;
        background-color : var(--odin-accent);
        margin-right : 12px;
    }

    .ODINLIFEISGOOD_paragraph {
        margin-bottom : 24px;
        text-align : justify;
        font-size : 1.05rem;
        color : #333;
    }

    /* 하이라이트 및 코드박스 */
    .ODINLIFEISGOOD_highlight {
        font-weight : 700;
        color : var(--odin-accent);
        background : rgba(0, 86, 179, 0.05);
        padding : 2px 4px;
        border-radius : 4px;
    }

    .ODINLIFEISGOOD_code_box {
        background-color : #2b3035;
        color : #f8f9fa;
        padding : 25px;
        border-radius : 8px;
        font-family : 'Consolas', monospace;
        font-size : 0.95rem;
        margin : 30px 0;
        border-left : 5px solid var(--odin-accent);
        position : relative;
    }

    .ODINLIFEISGOOD_code_box::after {
        content : 'Dev_Log.cs';
        position : absolute;
        top : 10px;
        right : 15px;
        font-size : 0.8rem;
        color : #6c757d;
        opacity : 0.8;
    }

    /* 아카이브 그리드 스타일 */
    .ODINLIFEISGOOD_archive_grid {
        display : grid;
        grid-template-columns : repeat(auto-fit, minmax(280px, 1fr));
        gap : 20px;
        margin-top : 30px;
    }

    .ODINLIFEISGOOD_archive_card {
        background : var(--odin-light-bg);
        border : 1px solid var(--odin-border);
        padding : 25px;
        border-radius : 12px;
        transition : all 0.3s ease;
    }

    .ODINLIFEISGOOD_archive_card:hover {
        border-color : var(--odin-accent);
        transform : translateY(-5px);
        box-shadow : 0 5px 15px rgba(0,0,0,0.05);
    }

    .ODINLIFEISGOOD_cat_title {
        font-size : 1.2rem;
        font-weight : 800;
        color : #111;
        margin-bottom : 15px;
        display : block;
        border-bottom : 1px solid #ddd;
        padding-bottom : 10px;
    }

    .ODINLIFEISGOOD_sub_cat {
        display : flex;
        flex-wrap : wrap;
        gap : 8px;
        margin-top : 10px;
    }

    .ODINLIFEISGOOD_badge {
        font-size : 0.85rem;
        background : #fff;
        border : 1px solid #ccc;
        padding : 4px 10px;
        border-radius : 4px;
        color : #555;
        font-weight : 500;
    }

    /* 푸터 스타일 */
    .ODINLIFEISGOOD_footer {
        margin-top : 100px;
        padding : 60px 20px;
        background-color : var(--odin-light-bg);
        border-top : 1px solid var(--odin-border);
        text-align : center;
        border-radius : 12px;
    }

    .ODINLIFEISGOOD_footer h3 {
        font-size : 1.8rem;
        color : var(--odin-accent);
        margin-bottom : 15px;
    }

    .ODINLIFEISGOOD_tag_cloud {
        display : flex;
        flex-wrap : wrap;
        justify-content : center;
        gap : 8px;
        margin-top : 25px;
    }

    .ODINLIFEISGOOD_tag {
        font-size : 0.9rem;
        color : #fff;
        background : var(--odin-accent);
        padding : 6px 14px;
        border-radius : 20px;
        opacity : 0.9;
    }
&lt;/style&gt;
&lt;/div&gt;
&lt;article class=&quot;ODINLIFEISGOOD_container&quot;&gt;
&lt;div class=&quot;ODINLIFEISGOOD_thumbnail ODINLIFEISGOOD_fade_in&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;글 상단 부분 대표 이미지.png&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dRwcDP/dJMcajuhecy/6wsfYWwERgeKRaCTB5pmak/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dRwcDP/dJMcajuhecy/6wsfYWwERgeKRaCTB5pmak/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dRwcDP/dJMcajuhecy/6wsfYWwERgeKRaCTB5pmak/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdRwcDP%2FdJMcajuhecy%2F6wsfYWwERgeKRaCTB5pmak%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;400&quot; data-filename=&quot;글 상단 부분 대표 이미지.png&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;header class=&quot;ODINLIFEISGOOD_header ODINLIFEISGOOD_fade_in&quot;&gt;
&lt;p style=&quot;font-weight: bold; color: var(--odin-accent); margin-bottom: 10px;&quot; data-ke-size=&quot;size16&quot;&gt;Developer Retrospective &amp;middot; 2022-2026&lt;/p&gt;

&lt;h2 data-ke-size=&quot;size26&quot;&gt;레거시와 혁신 사이, 울산 토박이 개발자의 4년 성장 로그&lt;/h2&gt;
&lt;/header&gt;
&lt;section class=&quot;ODINLIFEISGOOD_fade_in&quot;&gt;
&lt;div class=&quot;ODINLIFEISGOOD_section_title&quot;&gt;01. Initialize : 절실함이라는 동력&lt;/div&gt;
&lt;p class=&quot;ODINLIFEISGOOD_paragraph&quot; data-ke-size=&quot;size16&quot;&gt;어린 시절 저는 컴퓨터 본체를 분해하고 &lt;span class=&quot;ODINLIFEISGOOD_highlight&quot;&gt;비주얼베이직(Visual Basic)&lt;/span&gt;으로 화면을 그리던 공학도 꿈나무였습니다. &lt;b&gt;울산정보영재&lt;/b&gt;에 합격하며 확신을 얻었지만, 사춘기라는 예기치 못한 버그(Bug)를 만나 학교 밖 청소년이 되는 시련을 겪기도 했습니다.&lt;/p&gt;
&lt;br /&gt;
&lt;p class=&quot;ODINLIFEISGOOD_paragraph&quot; data-ke-size=&quot;size16&quot;&gt;뒤늦은 대학 입학 후에도 현실은 녹록지 않았습니다. 학비를 위해 마트 배달, 철물점, 막노동을 전전해야 했고, 특히 &lt;b&gt;엔진오일 생산 공장&lt;/b&gt;에서 땀 흘리던 시절은 제 인생의 전환점이 되었습니다. &quot;지금 이 루프(Loop)를 끊지 않으면 미래는 없다&quot;는 절박함이 저를 다시 키보드 앞으로 이끌었고, 그 시절의 끈기는 지금 제가 어려운 코드를 마주했을 때 버티는 힘이 되었습니다.&lt;/p&gt;
&lt;/section&gt;
&lt;section class=&quot;ODINLIFEISGOOD_fade_in&quot;&gt;
&lt;div class=&quot;ODINLIFEISGOOD_section_title&quot;&gt;02. Exception Handling : 신입의 생존 전략&lt;/div&gt;
&lt;div class=&quot;ODINLIFEISGOOD_code_box&quot;&gt;// 2022년 입사 초기 상태&lt;br /&gt;try {&lt;br /&gt;&amp;nbsp;&amp;nbsp;LegacySystem.Analyze();&lt;br /&gt;} catch (PanicException e) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;Health.Status = &quot;Critical&quot;; // 3개월간 위장 장애&lt;br /&gt;&amp;nbsp;&amp;nbsp;Strategy = &quot;Reverse_Engineering&quot;; // 코드 역분석으로 돌파&lt;br /&gt;}&lt;/div&gt;
&lt;p class=&quot;ODINLIFEISGOOD_paragraph&quot; data-ke-size=&quot;size16&quot;&gt;2022년 6월 1일, 첫 출근의 설렘은 곧 두려움으로 바뀌었습니다. 학교에서 배우지 못한 &lt;span class=&quot;ODINLIFEISGOOD_highlight&quot;&gt;.NET 레거시 시스템&lt;/span&gt;과 문서화되지 않은 히스토리는 신입에게 거대한 장벽이었습니다. 그리고 말 못한 묘한 정치의 느낌과 함께 입사 초기 3개월은 극심한 압박감에 매일 점심마다 체하기 일쑤였습니다.&lt;/p&gt;
&lt;br /&gt;
&lt;p class=&quot;ODINLIFEISGOOD_paragraph&quot; data-ke-size=&quot;size16&quot;&gt;하지만 저는 도망치지 않았습니다. 남들이 기피하는 레거시 코드를 한 줄 한 줄 역분석하고, 공식 문서를 파고들며 비즈니스 로직을 몸으로 익혔습니다. 그 결과, 점차 팀 내에서 기술적인 신뢰를 쌓으며 그리고 버텼습니다. 그렇게 버티면서 제 자리를 찾아갈 수 있었습니다. 사실 아직까지도 사람과의 관계에서 스트레스가 오긴 하지만 모두가 나를 좋아할 수 없고 이런 일 저런 일이 있다고 생각하며 버티고 있습니다.&lt;/p&gt;
&lt;/section&gt;
&lt;section class=&quot;ODINLIFEISGOOD_fade_in&quot;&gt;
&lt;div class=&quot;ODINLIFEISGOOD_section_title&quot;&gt;03. Core Logic : &quot;왜 긁어 부스럼을 만드냐고요?&quot;&lt;/div&gt;
&lt;p class=&quot;ODINLIFEISGOOD_paragraph&quot; data-ke-size=&quot;size16&quot;&gt;지난 4년간 저는 단순한 코더(Coder)에서 문제를 해결하는 엔지니어(Engineer)로 성장했습니다. 특히 제조 현장의 핵심인 &lt;b&gt;MES, ERP, QMS&lt;/b&gt; 시스템을 구축하며, 보수적인 환경에 새로운 기술을 도입하는 '혁신'을 시도했습니다.&lt;/p&gt;
&lt;br /&gt;
&lt;p class=&quot;ODINLIFEISGOOD_paragraph&quot; data-ke-size=&quot;size16&quot;&gt;&quot;잘 돌아가는 시스템에 왜 긁어 부스럼을 만드냐&quot;는 내부적인 우려도 있었습니다. 하지만 저는 대용량 트랜잭션이 발생하는 환경에서 &lt;span class=&quot;ODINLIFEISGOOD_highlight&quot;&gt;PostgreSQL과 Oracle의 쿼리 최적화(Tuning)&lt;/span&gt;를 통해 시스템 응답 속도를 획기적으로 개선하고 데이터 무결성을 확보함으로써, 기술 혁신이 곧 업무 효율로 이어진다는 것을 증명해냈습니다.&lt;/p&gt;
&lt;br /&gt;
&lt;p class=&quot;ODINLIFEISGOOD_paragraph&quot; data-ke-size=&quot;size16&quot;&gt;최근에는 &lt;b&gt;탄소중립 모니터링&lt;/b&gt; 및 &lt;b&gt;금형 추적 시스템&lt;/b&gt;에 &lt;b&gt;AI 기술&lt;/b&gt;을 접목하는 등, 현재에 안주하지 않고 기술 도메인을 지속적으로 확장하고 있습니다.&lt;/p&gt;
&lt;/section&gt;
&lt;section class=&quot;ODINLIFEISGOOD_fade_in&quot;&gt;
&lt;div class=&quot;ODINLIFEISGOOD_section_title&quot;&gt;04. OdinBOX Archive : 기록이 성장이 되는 공간&lt;/div&gt;
&lt;p class=&quot;ODINLIFEISGOOD_paragraph&quot; data-ke-size=&quot;size16&quot;&gt;지식의 휘발성을 막기 위해 시작한 블로그 &lt;b&gt;OdinBOX&lt;/b&gt;는 이제 제 삶의 일부이자 기술 부채를 상환하는 창구입니다. 개발하며 마주한 문제들의 해결책과 울산에서의 일상을 아래 카테고리에 꾸준히 기록하고 있습니다.&lt;/p&gt;
&lt;div class=&quot;ODINLIFEISGOOD_archive_grid&quot;&gt;
&lt;div class=&quot;ODINLIFEISGOOD_archive_card&quot;&gt;&lt;span class=&quot;ODINLIFEISGOOD_cat_title&quot;&gt;DEVELOPMENT&lt;/span&gt;
&lt;p style=&quot;font-size: 0.95rem; color: #555; margin-bottom: 15px;&quot; data-ke-size=&quot;size16&quot;&gt;. NET, DB 최적화 등 실무에서 부딪히며 배운 기술적 인사이트와 트러블 슈팅 기록과 새로운 기술을 배우는 기록입니다.&lt;/p&gt;
&lt;div class=&quot;ODINLIFEISGOOD_sub_cat&quot;&gt;&lt;span class=&quot;ODINLIFEISGOOD_badge&quot;&gt;Working-level DB&lt;/span&gt; &lt;span class=&quot;ODINLIFEISGOOD_badge&quot;&gt;Server Side&lt;/span&gt; &lt;span class=&quot;ODINLIFEISGOOD_badge&quot;&gt;Clientside&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;ODINLIFEISGOOD_archive_card&quot;&gt;&lt;span class=&quot;ODINLIFEISGOOD_cat_title&quot;&gt;IT &amp;amp; REVIEW&lt;/span&gt;
&lt;p style=&quot;font-size: 0.95rem; color: #555; margin-bottom: 15px;&quot; data-ke-size=&quot;size16&quot;&gt;개발자의 시선으로 분석한 내돈내산 IT 기기 리뷰와 소프트웨어 이야기입니다.&lt;/p&gt;
&lt;div class=&quot;ODINLIFEISGOOD_sub_cat&quot;&gt;&lt;span class=&quot;ODINLIFEISGOOD_badge&quot;&gt;Product Review&lt;/span&gt; &lt;span class=&quot;ODINLIFEISGOOD_badge&quot;&gt;IT Trend&lt;/span&gt; &lt;span class=&quot;ODINLIFEISGOOD_badge&quot;&gt;SW/GAME&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;ODINLIFEISGOOD_archive_card&quot;&gt;&lt;span class=&quot;ODINLIFEISGOOD_cat_title&quot;&gt;DAILY ROUTINE&lt;/span&gt;
&lt;p style=&quot;font-size: 0.95rem; color: #555; margin-bottom: 15px;&quot; data-ke-size=&quot;size16&quot;&gt;울산 토박이의 지역 이야기와 차량 관리 등 소소한 일상의 기록입니다.&lt;/p&gt;
&lt;div class=&quot;ODINLIFEISGOOD_sub_cat&quot;&gt;&lt;span class=&quot;ODINLIFEISGOOD_badge&quot;&gt;Ulsan Life&lt;/span&gt; &lt;span class=&quot;ODINLIFEISGOOD_badge&quot;&gt;Car&lt;/span&gt; &lt;span class=&quot;ODINLIFEISGOOD_badge&quot;&gt;Economy&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;footer class=&quot;ODINLIFEISGOOD_footer ODINLIFEISGOOD_fade_in&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Keep Coding, Keep Innovating&lt;/h3&gt;
&lt;p style=&quot;color: #555; margin-bottom: 25px; font-size: 1.05rem;&quot; data-ke-size=&quot;size16&quot;&gt;울산광역시 블로그 기자단 및 울주군 서포터즈로서 지역 사회와 소통하며,&lt;br /&gt;변화를 두려워하지 않는 '대체 불가능한 개발자'가 되겠습니다.&lt;/p&gt;
&lt;div class=&quot;ODINLIFEISGOOD_tag_cloud&quot;&gt;&lt;span class=&quot;ODINLIFEISGOOD_tag&quot;&gt;#FullStack&lt;/span&gt; &lt;span class=&quot;ODINLIFEISGOOD_tag&quot;&gt;#.NET_Core&lt;/span&gt; &lt;span class=&quot;ODINLIFEISGOOD_tag&quot;&gt;#MES_Expert&lt;/span&gt; &lt;span class=&quot;ODINLIFEISGOOD_tag&quot;&gt;#DB_Tuning&lt;/span&gt; &lt;span class=&quot;ODINLIFEISGOOD_tag&quot;&gt;#Tech_Innovation&lt;/span&gt;&lt;/div&gt;
&lt;p style=&quot;margin-top: 40px; font-size: 0.85rem; color: #999;&quot; data-ke-size=&quot;size16&quot;&gt;Copyright &amp;copy; 2026 OdinBOX. All rights reserved.&lt;/p&gt;
&lt;/footer&gt;&lt;/article&gt;
&lt;script&gt;
    (function() {
        const observer = new IntersectionObserver((entries) =&gt; {
            entries.forEach(entry =&gt; {
                if (entry.isIntersecting) {
                    entry.target.classList.add('ODINLIFEISGOOD_active');
                }
            });
        }, { threshold : 0.1 });

        document.querySelectorAll('.ODINLIFEISGOOD_fade_in').forEach(el =&gt; {
            observer.observe(el);
        });
    })();
&lt;/script&gt;</description>
      <category>DailyRoutine</category>
      <category>dotnet</category>
      <category>개발자회고</category>
      <category>기술혁신</category>
      <category>성장</category>
      <category>성장로그</category>
      <category>솔루션개발</category>
      <category>울산</category>
      <category>울산개발자</category>
      <category>울주군</category>
      <category>최영환</category>
      <author>간지뽕빨리턴님</author>
      <guid isPermaLink="true">https://odinbox.tistory.com/570</guid>
      <comments>https://odinbox.tistory.com/570#entry570comment</comments>
      <pubDate>Sat, 31 Jan 2026 15:58:05 +0900</pubDate>
    </item>
    <item>
      <title>PostgreSQL 논리복제와 FDW로 운영 서버를 두 번 죽여본 개발자의 실시간 데이터 동기화 생존기</title>
      <link>https://odinbox.tistory.com/569</link>
      <description>&lt;div&gt;
&lt;style&gt;
  .pg-article {
    font-family : 'Pretendard', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
    line-height : 1.8;
    color : #333;
    max-width : 100%;
  }
  .pg-article h1 {
    font-size : 1.8em;
    font-weight : 700;
    margin-bottom : 10px;
    color : #1a1a2e;
  }
  .pg-article h2 {
    font-size : 1.5em;
    font-weight : 700;
    margin : 50px 0 25px 0;
    color : #1a1a2e;
  }
  .pg-article h3 {
    font-size : 1.25em;
    font-weight : 600;
    margin : 30px 0 15px 0;
    color : #333;
  }
  .pg-article h4 {
    font-size : 1.1em;
    font-weight : 600;
    margin : 20px 0 12px 0;
    color : #444;
  }
  .pg-subtitle {
    color : #6c757d;
    font-size : 1.1em;
    margin-bottom : 30px;
  }
  .pg-card {
    background : #fff;
    border-radius : 12px;
    padding : 25px;
    margin : 20px 0;
    box-shadow : 0 2px 12px rgba(0,0,0,0.08);
    border : 1px solid #e9ecef;
  }
  .pg-card-danger { border-left : 4px solid #dc3545; }
  .pg-card-warning { border-left : 4px solid #ffc107; }
  .pg-card-success { border-left : 4px solid #28a745; }
  .pg-card-info { border-left : 4px solid #007bff; }
  .pg-card-purple { border-left : 4px solid #6f42c1; }
  .pg-card-teal { border-left : 4px solid #20c997; }
  .pg-card-orange { border-left : 4px solid #fd7e14; }
  .pg-grid-2 {
    display : grid;
    grid-template-columns : repeat(2, 1fr);
    gap : 20px;
    margin : 20px 0;
  }
  @media (max-width : 768px) {
    .pg-grid-2 { grid-template-columns : 1fr; }
  }
  .pg-info-box {
    background : #f8f9fa;
    border-radius : 12px;
    padding : 20px;
  }
  .pg-info-box h4 {
    margin : 0 0 15px 0;
    font-size : 1.1em;
  }
  .pg-alert {
    padding : 20px;
    border-radius : 12px;
    margin : 20px 0;
  }
  .pg-alert-danger {
    background : linear-gradient(135deg, #fff5f5 0%, #ffe3e3 100%);
    border : 1px solid #f5c2c7;
  }
  .pg-alert-danger h4 { color : #dc3545; margin : 0 0 10px 0; }
  .pg-alert-success {
    background : linear-gradient(135deg, #f0fff4 0%, #d3f9d8 100%);
    border : 1px solid #b2f2bb;
  }
  .pg-alert-success h4 { color : #28a745; margin : 0 0 10px 0; }
  .pg-alert-info {
    background : linear-gradient(135deg, #e7f5ff 0%, #d0ebff 100%);
    border : 1px solid #a5d8ff;
  }
  .pg-alert-info h4 { color : #007bff; margin : 0 0 10px 0; }
  .pg-code {
    background : #1e1e1e;
    color : #d4d4d4;
    padding : 20px;
    border-radius : 8px;
    overflow-x : auto;
    font-family : 'Consolas', 'Monaco', 'Courier New', monospace;
    font-size : 0.9em;
    line-height : 1.6;
    margin : 15px 0;
    white-space : pre;
    word-wrap : break-word;
  }
  .pg-code .comment { color : #6a9955; }
  .pg-code .keyword { color : #569cd6; }
  .pg-code .string { color : #ce9178; }
  .pg-code .function { color : #dcdcaa; }
  .pg-code .error { color : #f44747; }
  .pg-code .highlight { color : #4ec9b0; }
  .pg-gauge-container {
    background : #f8f9fa;
    border-radius : 12px;
    padding : 20px;
    text-align : center;
  }
  .pg-gauge-title {
    font-weight : 600;
    margin-bottom : 15px;
    color : #dc3545;
  }
  .pg-gauge-bar {
    height : 20px;
    background : #e9ecef;
    border-radius : 10px;
    overflow : hidden;
    margin-bottom : 15px;
  }
  .pg-gauge-fill {
    height : 100%;
    background : linear-gradient(90deg, #ffc107, #fd7e14, #dc3545);
    border-radius : 10px;
    animation : pulse 2s ease-in-out infinite;
  }
  @keyframes pulse {
    0%, 100% { opacity : 1; }
    50% { opacity : 0.7; }
  }
  .pg-gauge-text {
    font-size : 0.95em;
    color : #6c757d;
    font-style : italic;
  }
  .pg-table {
    width : 100%;
    border-collapse : collapse;
    margin : 20px 0;
    border-radius : 8px;
    overflow : hidden;
    box-shadow : 0 2px 8px rgba(0,0,0,0.1);
  }
  .pg-table th {
    background : #343a40;
    color : white;
    padding : 15px;
    text-align : left;
    font-weight : 600;
  }
  .pg-table td {
    padding : 12px 15px;
    border-bottom : 1px solid #e9ecef;
  }
  .pg-table tr:nth-child(even) { background : #f8f9fa; }
  .pg-table tr:hover { background : #e3f2fd; }
  .pg-list {
    list-style : none;
    padding : 0;
    margin : 0;
  }
  .pg-list li {
    padding : 10px 0;
    display : flex;
    align-items : flex-start;
    gap : 12px;
    border-bottom : 1px solid #f1f3f4;
  }
  .pg-list li:last-child { border-bottom : none; }
  .pg-list-icon {
    flex-shrink : 0;
    width : 24px;
    text-align : center;
    font-weight : bold;
  }
  .pg-diagram {
    background : linear-gradient(135deg, #1a1a2e, #16213e);
    color : #e9ecef;
    padding : 25px;
    border-radius : 12px;
    font-family : 'Consolas', monospace;
    font-size : 0.85em;
    overflow-x : auto;
    line-height : 1.5;
    margin : 20px 0;
    white-space : pre;
    word-wrap : break-word;
  }
  .pg-quote {
    background : linear-gradient(135deg, #f8f9fa, #e9ecef);
    border-left : 4px solid #6c757d;
    padding : 20px 25px;
    margin : 25px 0;
    border-radius : 0 12px 12px 0;
    font-style : italic;
  }
  .pg-quote-author {
    margin-top : 10px;
    font-size : 0.9em;
    color : #6c757d;
    font-style : normal;
  }
  .pg-tags {
    display : flex;
    flex-wrap : wrap;
    gap : 8px;
    margin-top : 30px;
  }
  .pg-tag {
    background : linear-gradient(135deg, #e9ecef, #f8f9fa);
    padding : 6px 14px;
    border-radius : 20px;
    font-size : 0.9em;
    color : #495057;
    border : 1px solid #dee2e6;
  }
  .pg-timeline {
    position : relative;
    padding-left : 35px;
    margin : 20px 0;
  }
  .pg-timeline::before {
    content : '';
    position : absolute;
    left : 10px;
    top : 0;
    bottom : 0;
    width : 3px;
    background : linear-gradient(to bottom, #28a745, #ffc107, #dc3545);
    border-radius : 3px;
  }
  .pg-timeline-item {
    position : relative;
    padding : 12px 0;
  }
  .pg-timeline-item::before {
    content : '';
    position : absolute;
    left : -31px;
    top : 16px;
    width : 14px;
    height : 14px;
    border-radius : 50%;
    background : white;
    border : 3px solid #007bff;
  }
  .pg-timeline-item.success::before { border-color : #28a745; }
  .pg-timeline-item.warning::before { border-color : #ffc107; }
  .pg-timeline-item.danger::before { border-color : #dc3545; }
  .pg-step-number {
    display : inline-flex;
    align-items : center;
    justify-content : center;
    width : 28px;
    height : 28px;
    background : linear-gradient(135deg, #007bff, #0056b3);
    color : white;
    border-radius : 50%;
    font-weight : 600;
    font-size : 0.9em;
    margin-right : 10px;
  }
&lt;/style&gt;
&lt;/div&gt;
&lt;article class=&quot;pg-article&quot;&gt;
&lt;p class=&quot;pg-subtitle&quot; data-ke-size=&quot;size16&quot;&gt;현기증 난단 말이에요... 분산 환경에서 살아남기 위한 처절한 기록&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;글 상단 부분 대표 이미지.png&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bQu24W/dJMcabbVoIF/CSF7yk4rkKAKkSDeGkDatK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bQu24W/dJMcabbVoIF/CSF7yk4rkKAKkSDeGkDatK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bQu24W/dJMcabbVoIF/CSF7yk4rkKAKkSDeGkDatK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbQu24W%2FdJMcabbVoIF%2FCSF7yk4rkKAKkSDeGkDatK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;400&quot; data-filename=&quot;글 상단 부분 대표 이미지.png&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;section id=&quot;intro&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;서론 : 서버가 죽었다, 그것도 두 번이나&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개발자의 심장을 가장 빠르게 뛰게 하는 것은 무엇일까? 연봉 협상? 코드 리뷰? 갑자기 날아오는 기획 변경? 아니다. 단연코 &lt;b&gt;&quot;서버가 죽었습니다&quot;&lt;/b&gt;라는 알림이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나는 최근 이 경험을 &lt;b&gt;두 번&lt;/b&gt;이나 했다. 그것도 같은 목적을 위해 다른 기술을 사용하다가. PostgreSQL의 논리복제(Logical Replication)로 한 번, FDW(Foreign Data Wrapper)로 또 한 번. 같은 실수를 두 번 하면 그건 실수가 아니라 실력이라던데... 그래, 인정한다. 이건 내 실력이다.  &lt;/p&gt;
&lt;div class=&quot;pg-card pg-card-danger&quot;&gt;
&lt;div style=&quot;text-align: center; padding: 10px;&quot;&gt;
&lt;p style=&quot;font-size: 1.15em; margin: 0; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt; &amp;zwj;  &quot;어? 서버 왜 이렇게 느려요?&quot;&lt;br /&gt; &amp;zwj;  &quot;잠깐만... 뭐지?&quot;&lt;br /&gt; ️ &lt;code style=&quot;color: #dc3545; font-weight: bold; font-size: 1.1em;&quot;&gt;Connection refused&lt;/code&gt;&lt;br /&gt; &amp;zwj;  &quot;...&quot;&lt;br /&gt; &amp;zwj;  &quot;...&quot;&lt;br /&gt; &amp;zwj; &amp;zwj;  &lt;b&gt;&quot;현기증 난단 말이에요!!!&quot;&lt;/b&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 글은 화려한 성공 스토리가 아니다. &lt;b&gt;처절한 실패와 현재 진행 중인 도전&lt;/b&gt;, 그리고 앞으로 어떻게 이 문제를 해결해 나갈 것인지에 대한 솔직한 기록이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이전에 논리복제와 FDW에 대한 글을 썼었는데, 막상 실무에서 적용하다 보니 글로 정리한 것과 현실은 꽤나 달랐다. 블로그에 &quot;이렇게 하면 됩니다~&quot;라고 써놓고 정작 내가 그걸로 서버를 죽이다니. 아이러니하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비슷한 고민을 하는 개발자들에게 &quot;아, 나만 삽질하는 게 아니구나&quot;라는 위안과 함께, 실질적인 도움이 되길 바란다. 적어도 나처럼 같은 실수를 두 번 하진 말자.&lt;/p&gt;
&lt;div class=&quot;pg-card&quot;&gt;
&lt;h4 style=&quot;margin: 0 0 15px 0;&quot; data-ke-size=&quot;size20&quot;&gt;  목차&lt;/h4&gt;
&lt;ul style=&quot;margin: 0; padding-left: 20px; line-height: 2;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;#background&quot;&gt;프로젝트 배경 : 왜 실시간 동기화가 필요했나&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#architecture&quot;&gt;시스템 구성 : Tailscale VPN을 활용한 보안 연결&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#attempt1&quot;&gt;첫 번째 시도 : 논리복제(Logical Replication)의 배신&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#attempt2&quot;&gt;두 번째 시도 : FDW + 트리거, 되다가 갑자기 죽는 공포&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#incident&quot;&gt;사건의 전말 : 운영 서버가 죽기까지&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#analysis&quot;&gt;기술적 분석 : 도대체 왜 죽은 걸까&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#solution&quot;&gt;해결을 향한 여정 : 앞으로의 접근 방법&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#conclusion&quot;&gt;마무리 : 실패도 자산이다&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;section id=&quot;background&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;프로젝트 배경 : 왜 실시간 동기화가 필요했나&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;우리가 만들고 있는 것&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 진행 중인 솔루션은 &lt;b&gt;고객 사업장의 계측 데이터를 실시간으로 수집하여 중앙 서버에서 처리하고, 사용자에게 보여주는 시스템&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쉽게 말하면 IoT 데이터 수집 시스템이다. 공장이나 사업장에 설치된 각종 계측기(온도, 습도, 전력량 등)에서 데이터를 모아 중앙에서 모니터링하고 분석하는 것. 간단해 보이지만, 막상 구현하려니 온갖 문제가 터져 나왔다.&lt;/p&gt;
&lt;div class=&quot;pg-grid-2&quot;&gt;
&lt;div class=&quot;pg-info-box&quot;&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;  사업장 A (Gathering PC x2)&lt;/h4&gt;
&lt;p style=&quot;margin: 0; color: #555;&quot; data-ke-size=&quot;size16&quot;&gt;수십 개의 계측기에서 1분 단위로 데이터 생성. 두 대의 게더링 PC가 각각 다른 구역의 계측기를 담당하고 있다. 한 대가 죽어도 다른 구역은 살아있어야 하니까.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;pg-info-box&quot;&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;  사업장 B (Gathering PC x1)&lt;/h4&gt;
&lt;p style=&quot;margin: 0; color: #555;&quot; data-ke-size=&quot;size16&quot;&gt;단일 접점에서 지속적인 트래픽 발생. 규모는 작지만 데이터 발생 빈도는 A 사업장과 비슷하다. 작다고 무시하면 안 된다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;시스템 규모와 요구사항&lt;/h3&gt;
&lt;table class=&quot;pg-table&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;항목&lt;/th&gt;
&lt;th&gt;상세&lt;/th&gt;
&lt;th&gt;체감 난이도&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;연결된 게더링 PC&lt;/td&gt;
&lt;td&gt;3대 (사업장 A : 2대, 사업장 B : 1대)&lt;/td&gt;
&lt;td&gt;⭐⭐&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;총 계측기 수&lt;/td&gt;
&lt;td&gt;약 40~50개&lt;/td&gt;
&lt;td&gt;⭐⭐⭐&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;데이터 생성 주기&lt;/td&gt;
&lt;td&gt;약 1분마다 (계측기당)&lt;/td&gt;
&lt;td&gt;⭐⭐⭐&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;일일 예상 데이터량&lt;/td&gt;
&lt;td&gt;약 60,000~70,000건/일&lt;/td&gt;
&lt;td&gt;⭐⭐⭐⭐&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;background: #fff3cd;&quot;&gt;
&lt;td&gt;&lt;b&gt;핵심 요구사항&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;실시간성 확보 (지연 1분 이내)&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;⭐⭐⭐⭐⭐ (지옥)&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단순히 &quot;3대 PC 연결&quot;이라고 하면 쉬워 보이지만, 각 PC에 연결된 수십 개의 계측기가 1분마다 데이터를 쏟아내고, 이걸 &lt;b&gt;실시간으로 중앙 서버에 전송&lt;/b&gt;해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 &quot;실시간&quot;이라는 단어가 모든 재앙의 시작이었다. 고객은 &quot;실시간으로 보고 싶어요&quot;라고 했고, 나는 &quot;네, 가능합니다&quot;라고 대답했다. 그때의 나를 때리고 싶다.&lt;/p&gt;
&lt;div class=&quot;pg-quote&quot;&gt;
&lt;p style=&quot;margin: 0;&quot; data-ke-size=&quot;size16&quot;&gt;&quot;실시간이요? 그냥 DB 복제하면 되는 거 아니에요?&quot;&lt;/p&gt;
&lt;p class=&quot;pg-quote-author&quot; data-ke-size=&quot;size16&quot;&gt;&amp;mdash; 과거의 순진했던 나 (지금 생각하면 눈물이 난다)&lt;/p&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;section id=&quot;architecture&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;시스템 구성 : Tailscale VPN을 활용한 보안 연결&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;왜 VPN을 사용했나&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사업장의 게더링 PC에서 중앙 서버 DB로 직접 연결하려면 공인 IP가 필요하다. 하지만 보안상 DB 포트(5432)를 인터넷에 직접 노출시키는 건... 음, 그건 좀 아니지 않나?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PostgreSQL 포트를 공개 인터넷에 열어두는 건 해커들에게 &quot;어서 오세요, 환영합니다. 비밀번호는 postgres입니다&quot; 하는 것과 다를 바 없다. (설마 아직도 기본 비밀번호 쓰는 분은 없겠지...?)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 선택한 것이 &lt;b&gt;Tailscale VPN&lt;/b&gt;이다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Tailscale을 선택한 이유&lt;/h3&gt;
&lt;div class=&quot;pg-card pg-card-info&quot;&gt;
&lt;ul class=&quot;pg-list&quot; style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #28a745;&quot; class=&quot;pg-list-icon&quot;&gt;✓&lt;/span&gt;
&lt;div&gt;&lt;b&gt;Zero-config VPN:&lt;/b&gt; 복잡한 설정 없이 쉽게 구축 가능. OpenVPN처럼 인증서 관리하고 config 파일 만들고 할 필요 없다. 설치하고 로그인하면 끝.&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #28a745;&quot; class=&quot;pg-list-icon&quot;&gt;✓&lt;/span&gt;
&lt;div&gt;&lt;b&gt;WireGuard 기반:&lt;/b&gt; 빠르고 안정적인 연결. IPSec보다 코드베이스가 작아서 보안 취약점도 적다. 레이턴시도 낮은 편.&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #28a745;&quot; class=&quot;pg-list-icon&quot;&gt;✓&lt;/span&gt;
&lt;div&gt;&lt;b&gt;NAT 통과:&lt;/b&gt; 사업장 네트워크 환경이 복잡해도 연결 가능. 방화벽 뒤에서도 잘 동작한다. CGNAT도 뚫는다.&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #28a745;&quot; class=&quot;pg-list-icon&quot;&gt;✓&lt;/span&gt;
&lt;div&gt;&lt;b&gt;무료 플랜:&lt;/b&gt; 개인 사용자는 100대까지 무료. 우리처럼 소규모 구성에서는 무료로 충분하다. 이게 제일 중요하다  &lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;전체 네트워크 구성도&lt;/h3&gt;
&lt;pre class=&quot;pg-diagram routeros&quot;&gt;&lt;code&gt;                         [ 인터넷 ]
                              │
             ┌────────────────┴────────────────┐
             │                                 │
             ▼                                 ▼
    ┌─────────────────┐              ┌─────────────────┐
    │   사업장 A       │              │   사업장 B       │
    │   (NAT 환경)    │              │   (NAT 환경)    │
    │                 │              │                 │
    │ ┌─────────────┐ │              │ ┌─────────────┐ │
    │ │게더링 PC 1  │ │              │ │게더링 PC 1  │ │
    │ │ Tailscale   │ │              │ │ Tailscale   │ │
    │ │ 100.x.x.10  │ │              │ │ 100.x.x.30  │ │
    │ │ PostgreSQL  │ │              │ │ PostgreSQL  │ │
    │ └─────────────┘ │              │ └─────────────┘ │
    │ ┌─────────────┐ │              └─────────────────┘
    │ │게더링 PC 2  │ │
    │ │ Tailscale   │ │      Tailscale Mesh Network
    │ │ 100.x.x.20  │ │     ━━━━━━━━━━━━━━━━━━━━━━━
    │ │ PostgreSQL  │ │               │
    │ └─────────────┘ │               │
    └─────────────────┘               │
                                      ▼
                            ┌─────────────────┐
                            │   중앙 서버      │
                            │   Tailscale      │
                            │   100.x.x.1     │
                            │                 │
                            │  ┌───────────┐  │
                            │  │PostgreSQL │  │
                            │  │   :5432   │  │
                            │  └───────────┘  │
                            └─────────────────┘

※ 공인 IP 노출 없이 Tailscale 내부 IP(100.x.x.x)로 안전하게 연결
※ 각 게더링 PC에 로컬 PostgreSQL 설치 (데이터 1차 저장)
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 구성하면 공인 IP 없이도 안전하게 DB에 접근할 수 있다. Tailscale 덕분에 마치 같은 사설 네트워크에 있는 것처럼 연결된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보안 걱정은 덜었다. Tailscale은 믿을 만하다. 문제는... &lt;b&gt;보안이 아니라 완전히 다른 곳에서 터졌다.&lt;/b&gt;&lt;/p&gt;
&lt;/section&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;section id=&quot;attempt1&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;첫 번째 시도 : 논리복제(Logical Replication)의 배신&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;왜 논리복제를 선택했나&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PostgreSQL의 &lt;b&gt;논리복제(Logical Replication)&lt;/b&gt;는 PostgreSQL 10부터 도입된 기능으로, 물리복제와 달리 테이블 단위로 선택적 복제가 가능하다. 전체 DB를 복제할 필요 없이 필요한 테이블만 골라서 복제할 수 있다는 점이 매력적이었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;게다가 Publisher-Subscriber 모델이라 직관적이다. 로컬 DB가 Publisher가 되어 데이터를 발행하고, 중앙 서버가 Subscriber가 되어 구독하면 끝. 심플하지 않은가?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이전에 논리복제에 대해 정리한 글도 있다. (이때까지만 해도 희망에 차 있었다...)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;  &lt;a href=&quot;https://odinbox.co.kr/555&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;PostgreSQL 논리복제 실무 가이드&lt;/a&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;논리복제의 기본 구조&lt;/h3&gt;
&lt;pre class=&quot;pg-code makefile&quot;&gt;&lt;code&gt;-- [로컬 게더링 PC] postgresql.conf 설정
-- 이것부터 해야 논리복제가 가능하다
wal_level = logical
max_replication_slots = 4
max_wal_senders = 4

-- 설정 변경 후 PostgreSQL 재시작 필수!
-- sudo systemctl restart postgresql
&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;pg-code pgsql&quot;&gt;&lt;code&gt;-- [로컬 게더링 PC] Publication 생성
CREATE PUBLICATION measurement_pub 
FOR TABLE measurement_data, sensor_log;

-- 복제용 사용자 생성 (REPLICATION 권한 필요)
CREATE USER repl_user WITH REPLICATION PASSWORD 'secure_password';
GRANT SELECT ON measurement_data, sensor_log TO repl_user;
&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;pg-code pgsql&quot;&gt;&lt;code&gt;-- [중앙 서버] Subscription 생성
-- Tailscale IP(100.x.x.10)로 연결
CREATE SUBSCRIPTION measurement_sub
CONNECTION 'host=100.x.x.10 port=5432 dbname=gathering user=repl_user password=secure_password'
PUBLICATION measurement_pub;

-- 이론상 이렇게 하면 끝...
-- 로컬에 INSERT하면 자동으로 서버에도 INSERT된다
-- 완벽하다! ...이론상은...
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;처음 며칠은 잘 됐다&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설정하고 테스트해보니 진짜 잘 됐다. 로컬 DB에 데이터 넣으면 몇 초 안에 서버에서도 보인다. &quot;오 이거 되는데?&quot; 싶었다. 퇴근길 발걸음이 가벼웠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇게 며칠이 지났다...&lt;/p&gt;
&lt;div class=&quot;pg-alert pg-alert-danger&quot;&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;⚠️ 결과 : 운영 서버 DB 다운&lt;/h4&gt;
&lt;p style=&quot;margin: 0;&quot; data-ke-size=&quot;size16&quot;&gt;어느 날 아침, 서버가 점점 느려지더니 결국 DB가 완전히 멈춰버렸다. 다른 서비스들도 같은 DB를 쓰고 있었는데, 전부 먹통이 됐다. 출근하자마자 전화가 빗발쳤다.&lt;/p&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;논리복제의 함정들&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span class=&quot;pg-step-number&quot;&gt;1&lt;/span&gt;복제 슬롯(Replication Slot)의 저주&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;논리복제는 &lt;code&gt;replication slot&lt;/code&gt;이라는 것을 사용한다. 이게 뭐냐면, Subscriber가 어디까지 데이터를 받았는지 추적하는 북마크 같은 거다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제는 Subscriber가 오프라인 상태가 되면 Publisher가 &quot;언젠간 얘가 돌아오겠지&quot;라며 &lt;b&gt;WAL(Write-Ahead Log) 로그를 무한정 보관&lt;/b&gt;한다는 것이다. Subscriber가 다시 연결되면 그동안 쌓인 변경사항을 보내줘야 하니까.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;근데 사업장 네트워크가 불안정하거나, 게더링 PC가 재부팅되거나, VPN 연결이 끊어지면? Subscriber는 오프라인이 되고, WAL 로그는 계속 쌓인다. 하루, 이틀, 사흘... 디스크가 꽉 차면? &lt;b&gt;DB 사망.&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;pg-code pgsql&quot;&gt;&lt;code&gt;-- 복제 슬롯 상태 확인
-- 이걸 자주 확인했어야 했다...  
SELECT slot_name, 
       pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn)) AS retained_wal,
       active
FROM pg_replication_slots;

-- 실제로 내가 본 결과:
-- slot_name       | retained_wal | active
-- ----------------+--------------+--------
-- measurement_sub | 47 GB        | f
--
-- active가 'f'(false)인데 47GB나 쌓여있었다...
-- 서버 디스크 용량이 100GB였는데 절반을 WAL이 먹고 있었던 것
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span class=&quot;pg-step-number&quot;&gt;2&lt;/span&gt;초기 동기화(Initial Sync)의 공포&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Subscription을 생성하면 기본적으로 &lt;code&gt;copy_data = true&lt;/code&gt; 옵션이 켜져 있다. 이게 뭐냐면, 기존에 테이블에 있던 데이터를 전부 복사해서 보내겠다는 거다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;테스트 환경에서는 데이터가 몇 건 없어서 금방 끝났는데, 운영 환경에서 100만 건 있는 테이블에 이걸 했다가는... 복사하느라 CPU 100%, 네트워크 포화, 다른 쿼리는 전부 대기. 경험담이다.&lt;/p&gt;
&lt;pre class=&quot;pg-code pgsql&quot;&gt;&lt;code&gt;-- 초기 데이터 복사 없이 Subscription 생성하려면
CREATE SUBSCRIPTION measurement_sub
CONNECTION '...'
PUBLICATION measurement_pub
WITH (copy_data = false);  -- 기존 데이터 복사 안 함

-- 단, 이러면 구독 시작 시점 이후의 데이터만 복제됨
-- 기존 데이터는 별도로 마이그레이션 필요
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span class=&quot;pg-step-number&quot;&gt;3&lt;/span&gt;충돌 해결 메커니즘의 부재&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;논리복제는 기본적으로 &lt;b&gt;충돌 해결 메커니즘이 없다&lt;/b&gt;. 예를 들어, 같은 Primary Key로 데이터가 양쪽에 INSERT되면? 에러 나고 복제가 &lt;b&gt;완전히 멈춘다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자동 복구? 그런 거 없다. 사람이 직접 충돌 해결하고, 복제 다시 시작해줘야 한다. 그것도 새벽에 서버 죽으면 새벽에 해야 한다.&lt;/p&gt;
&lt;pre class=&quot;pg-code pgsql&quot;&gt;&lt;code&gt;-- 에러 로그에서 자주 보게 될 메시지
ERROR : duplicate key value violates unique constraint &quot;measurement_data_pkey&quot;
DETAIL : Key (id)=(12345) already exists.
CONTEXT : processing remote data for replication origin &quot;pg_16389&quot; during &quot;INSERT&quot;

-- 이 에러 보면 복제가 멈춘 거다
-- 복제 상태 확인
SELECT * FROM pg_stat_subscription;

-- last_msg_receipt_time이 안 바뀌면 복제가 멈춘 것
-- 야근 확정  
&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;pg-quote&quot;&gt;
&lt;p style=&quot;margin: 0;&quot; data-ke-size=&quot;size16&quot;&gt;&quot;논리복제 쓰면 실시간 동기화 쉽게 되지 않아요?&quot;&lt;/p&gt;
&lt;p class=&quot;pg-quote-author&quot; data-ke-size=&quot;size16&quot;&gt;&amp;mdash; 과거의 나. 지금 보면 참 순진했다.&lt;/p&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;section id=&quot;attempt2&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;두 번째 시도 : FDW + 트리거, 되다가 갑자기 죽는 공포&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;논리복제가 안 되면 FDW다!&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;논리복제의 처참한 실패 후, 좀 더 제어 가능한 방식을 찾았다. PostgreSQL의 &lt;b&gt;FDW(Foreign Data Wrapper)&lt;/b&gt;는 Oracle의 DB Link와 비슷한 개념으로, 외부 데이터베이스를 마치 로컬 테이블처럼 접근할 수 있게 해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Oracle에서 &lt;code&gt;SELECT * FROM remote_table@dblink&lt;/code&gt; 하는 것처럼, PostgreSQL에서도 외부 DB의 테이블을 로컬처럼 쓸 수 있다. 이전에 정리해둔 글이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;  &lt;a href=&quot;https://odinbox.co.kr/568&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;PostgreSQL FDW(Foreign Data Wrapper) 사용법&lt;/a&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;FDW vs Oracle DB Link 비교&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Oracle DB Link 쓰다가 PostgreSQL로 넘어온 분들을 위해 비교표를 만들어봤다.&lt;/p&gt;
&lt;table class=&quot;pg-table&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;구분&lt;/th&gt;
&lt;th&gt;PostgreSQL FDW&lt;/th&gt;
&lt;th&gt;Oracle DB Link&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;설치 방법&lt;/td&gt;
&lt;td&gt;&lt;code&gt;CREATE EXTENSION postgres_fdw&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;내장 기능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;외부 테이블 접근&lt;/td&gt;
&lt;td&gt;FOREIGN TABLE 생성 필요&lt;/td&gt;
&lt;td&gt;&lt;code&gt;테이블명@링크명&lt;/code&gt;으로 바로 접근&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;분산 트랜잭션 (2PC)&lt;/td&gt;
&lt;td&gt;기본 미지원 (별도 설정 필요)&lt;/td&gt;
&lt;td&gt;지원&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;쿼리 푸시다운&lt;/td&gt;
&lt;td&gt;지원 (WHERE 절 등 원격 실행)&lt;/td&gt;
&lt;td&gt;제한적&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;설정 복잡도&lt;/td&gt;
&lt;td&gt;SERVER &amp;rarr; USER MAPPING &amp;rarr; FOREIGN TABLE 순서&lt;/td&gt;
&lt;td&gt;CREATE DATABASE LINK 한 줄&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;체감 난이도&lt;/td&gt;
&lt;td&gt;  생각보다 까다로움&lt;/td&gt;
&lt;td&gt;  그냥저냥&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;FDW + 트리거 조합 아이디어&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아이디어는 이랬다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;로컬 DB에 데이터가 INSERT되면&lt;/li&gt;
&lt;li&gt;AFTER INSERT 트리거 발동&lt;/li&gt;
&lt;li&gt;트리거 함수에서 FDW를 통해 서버 DB에 즉시 전송&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;실시간성 완벽!&lt;/b&gt; 데이터가 들어오는 즉시 서버로 전송되니까. ...라고 생각했다.&lt;/p&gt;
&lt;pre class=&quot;pg-code routeros&quot;&gt;&lt;code&gt;-- 1. FDW 확장 설치
CREATE EXTENSION postgres_fdw;

-- 2. 외부 서버 정의 (Tailscale IP 사용)
CREATE SERVER central_server
FOREIGN DATA WRAPPER postgres_fdw
OPTIONS (host '100.x.x.1', dbname 'production', port '5432');

-- 3. 사용자 매핑 (로컬 사용자 &amp;rarr; 원격 사용자)
CREATE USER MAPPING FOR local_user
SERVER central_server
OPTIONS (user 'sync_user', password '********');

-- 4. 외부 테이블 정의 (서버의 테이블을 로컬에서 접근)
CREATE FOREIGN TABLE remote_measurement (
    id BIGINT,
    sensor_id INTEGER,
    value NUMERIC(10,2),
    measured_at TIMESTAMP,
    created_at TIMESTAMP
) SERVER central_server
OPTIONS (schema_name 'public', table_name 'measurement_data');
&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;pg-code pgsql&quot;&gt;&lt;code&gt;-- 5. 실시간 동기화 트리거 함수
CREATE OR REPLACE FUNCTION sync_to_server()
RETURNS TRIGGER AS $$
BEGIN
    -- 원격 테이블에 INSERT
    INSERT INTO remote_measurement (id, sensor_id, value, measured_at, created_at)
    VALUES (NEW.id, NEW.sensor_id, NEW.value, NEW.measured_at, NEW.created_at);
    
    RETURN NEW;
    
EXCEPTION WHEN OTHERS THEN
    -- 에러 발생해도 로컬 INSERT는 성공하도록
    RAISE WARNING 'Remote sync failed : %', SQLERRM;
    RETURN NEW;
END;
$$ LANGUAGE plpgsql;

-- 6. 트리거 생성
CREATE TRIGGER trg_sync_measurement
AFTER INSERT ON measurement_data
FOR EACH ROW
EXECUTE FUNCTION sync_to_server();
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;처음에는 진짜 잘 됐다&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;테스트해보니 완벽했다. 로컬에 INSERT하면 바로 서버에서 보인다. 논리복제처럼 복잡한 설정도 없고, 복제 슬롯이니 WAL이니 신경 쓸 것도 없다. 트리거로 직접 밀어넣으니까.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;이번엔 진짜 성공인가?&quot; 싶었다. 동료들한테 자랑도 했다. &quot;FDW로 실시간 동기화 구현했어요. 깔끔하죠?&quot; 그렇게 며칠이 지났다...&lt;/p&gt;
&lt;div class=&quot;pg-alert pg-alert-danger&quot;&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;⚠️ 결과 : 또 서버 다운&lt;/h4&gt;
&lt;p style=&quot;margin: 0;&quot; data-ke-size=&quot;size16&quot;&gt;처음에는 잘 됐다. 정말 잘 됐다. 그런데 며칠 지나니까 &lt;b&gt;되다가 갑자기 죽고, 또 되다가 갑자기 죽고&lt;/b&gt;... 패턴도 없이 랜덤하게 죽었다.&lt;/p&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이게 더 미치는 거였다. 논리복제는 그래도 WAL 로그 쌓이는 거 보면서 &quot;아, 이거 위험하겠다&quot; 예측이라도 됐는데, FDW + 트리거 조합은 &lt;b&gt;아무런 전조 증상 없이 갑자기 죽었다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어제까지 멀쩡했는데 오늘 갑자기 서버가 죽어있다. 왜? 모른다. 로그 봐도 뭔가 쌓이다가 갑자기 뻗은 것 같은데, 명확한 원인을 찾기 어려웠다.&lt;/p&gt;
&lt;div class=&quot;pg-grid-2&quot;&gt;
&lt;div class=&quot;pg-card&quot;&gt;
&lt;h4 style=&quot;margin: 0 0 15px 0;&quot; data-ke-size=&quot;size20&quot;&gt;  장애 발생 패턴 (패턴이 없다)&lt;/h4&gt;
&lt;div style=&quot;font-family: monospace; line-height: 2.2;&quot;&gt;Day 1 : ✅ 정상 동작 - &quot;오 잘 되네!&quot;&lt;br /&gt;Day 2 : ✅ 정상 동작 - &quot;역시 FDW 짱&quot;&lt;br /&gt;Day 3 : ✅ 정상 동작 - &quot;이번엔 성공인가?&quot;&lt;br /&gt;Day 4 : ✅ 정상... 어라?&lt;br /&gt;Day 4 : ⚠️ 서버 점점 느려짐&lt;br /&gt;Day 4 : ❌ &lt;span style=&quot;color: #dc3545; font-weight: bold;&quot;&gt;서버 다운&lt;/span&gt;&lt;br /&gt;Day 5 : ✅ 복구 후 정상&lt;br /&gt;Day 6 : ✅ 정상&lt;br /&gt;Day 7 : ❌ &lt;span style=&quot;color: #dc3545; font-weight: bold;&quot;&gt;또 다운&lt;/span&gt; (왜?!)&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;pg-gauge-container&quot;&gt;
&lt;div class=&quot;pg-gauge-title&quot;&gt;현재 나의 멘붕 지수&lt;/div&gt;
&lt;div class=&quot;pg-gauge-bar&quot;&gt;
&lt;div class=&quot;pg-gauge-fill&quot; style=&quot;width: 95%;&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;p class=&quot;pg-gauge-text&quot; data-ke-size=&quot;size16&quot;&gt;&quot;현기증 난단 말이에요...&quot;&lt;/p&gt;
&lt;p style=&quot;margin-top: 15px; font-size: 0.9em; color: #666;&quot; data-ke-size=&quot;size16&quot;&gt;논리복제로 한 번, FDW로 또 한 번...&lt;br /&gt;이쯤 되면 나한테 문제가 있는 거 아닌가?&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;section id=&quot;incident&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;사건의 전말 : 운영 서버가 죽기까지&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그날의 상황을 복기해보자. 나중에 포스트모템(Post-mortem) 자료로도 쓸 수 있으니까. 사실 이 글 자체가 포스트모템이긴 하다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;D-Day 타임라인&lt;/h3&gt;
&lt;div class=&quot;pg-card&quot;&gt;
&lt;div class=&quot;pg-timeline&quot;&gt;
&lt;div class=&quot;pg-timeline-item success&quot;&gt;&lt;b&gt;  14:00&lt;/b&gt; - 평화로운 오후. 커피 한 잔 하면서 다른 작업 중. 오늘따라 날씨도 좋고, 퇴근 후 뭐 먹을지 고민하던 중이었다. 인생 뭐 있나, 평온하다.&lt;/div&gt;
&lt;div class=&quot;pg-timeline-item warning&quot;&gt;&lt;b&gt;  14:23&lt;/b&gt; - 동료 : &lt;i&gt;&quot;어? 시스템 좀 느린 것 같지 않아요?&quot;&lt;/i&gt;&lt;br /&gt;나 : &lt;i&gt;&quot;그래요? 잠깐 볼게요.&quot;&lt;/i&gt; (이때까지만 해도 대수롭지 않게 생각함. 가끔 느릴 때 있으니까.)&lt;/div&gt;
&lt;div class=&quot;pg-timeline-item warning&quot;&gt;&lt;b&gt;  14:28&lt;/b&gt; - 서버 접속. 평소보다 확실히 느리다. 터미널 응답도 늦고, 쿼리도 오래 걸린다. 뭔가 심상치 않은 느낌...&lt;/div&gt;
&lt;div class=&quot;pg-timeline-item danger&quot;&gt;&lt;b&gt;  14:30&lt;/b&gt; - DB 상태 확인 시작. 여기서부터 식은땀이 나기 시작했다.&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;pre class=&quot;pg-code pgsql&quot;&gt;&lt;code&gt;-- 14:30 현재 실행 중인 쿼리 확인
SELECT pid, 
       now() - pg_stat_activity.query_start AS duration, 
       state,
       wait_event_type,
       left(query, 80) AS query_preview
FROM pg_stat_activity
WHERE state != 'idle'
ORDER BY duration DESC
LIMIT 10;

-- 결과 (대략적으로 재현):
-- pid   | duration  | state  | wait_event_type | query_preview
-- ------+-----------+--------+-----------------+---------------------------
-- 12345 | 00:12:34  | active | Client          | INSERT INTO remote_measurement...
-- 12346 | 00:11:22  | active | Client          | INSERT INTO remote_measurement...
-- 12347 | 00:10:15  | active | Client          | INSERT INTO remote_measurement...
-- ... (수십 개가 더 있었다)
--
-- wait_event_type이 'Client' &amp;rarr; 원격 서버 응답 대기 중
-- 10분 넘게 대기 중인 쿼리가 수십 개...  
&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;pg-card&quot;&gt;
&lt;div class=&quot;pg-timeline&quot;&gt;
&lt;div class=&quot;pg-timeline-item danger&quot;&gt;&lt;b&gt;  14:35&lt;/b&gt; - 트리거 실행 상태 점검. FDW를 통한 원격 INSERT들이 타임아웃 없이 &lt;b&gt;무한 대기 상태&lt;/b&gt;. 트리거에 타임아웃 설정을 안 했던 것이다.&lt;/div&gt;
&lt;div class=&quot;pg-timeline-item danger&quot;&gt;&lt;b&gt;  14:38&lt;/b&gt; - 혹시나 해서 논리복제 상태도 확인. (이전에 테스트하다 남겨둔 게 있었다) 여기도 WAL이 수십 GB 쌓여있었다. 설상가상.&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;pre class=&quot;pg-code pgsql&quot;&gt;&lt;code&gt;-- 14:42 커넥션 풀 상태 확인
SELECT 
    count(*) AS current_connections,
    (SELECT setting::int FROM pg_settings WHERE name = 'max_connections') AS max_connections,
    round(count(*) * 100.0 / (SELECT setting::int FROM pg_settings WHERE name = 'max_connections'), 1) AS usage_pct
FROM pg_stat_activity;

-- 결과:
-- current_connections | max_connections | usage_pct
-- --------------------+-----------------+-----------
-- 198                 | 200             | 99.0
--
-- 거의 다 찼다! 새로운 연결이 거의 불가능한 상태
-- 이러니까 다른 서비스도 DB 연결이 안 됐던 것...
&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;pg-card pg-card-danger&quot;&gt;
&lt;div class=&quot;pg-timeline&quot;&gt;
&lt;div class=&quot;pg-timeline-item danger&quot;&gt;&lt;b&gt;  14:45&lt;/b&gt; - 동료들 : &lt;i&gt;&quot;다른 서비스도 안 돼요! 로그인이 안 돼요! 뭐 하신 거예요?!&quot;&lt;/i&gt;&lt;br /&gt;나 : (식은땀 줄줄) &quot;아... 잠깐만요...&quot; 다른 서비스들도 같은 DB를 쓰고 있었는데, 커넥션이 다 차버려서 새 연결이 안 되는 거였다.&lt;/div&gt;
&lt;div class=&quot;pg-timeline-item danger&quot;&gt;&lt;b&gt;  14:50&lt;/b&gt; - &lt;b&gt;결단의 순간.&lt;/b&gt; 더 이상 분석하고 있을 시간이 없다. 일단 불부터 끄자.&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;pre class=&quot;pg-code pgsql&quot;&gt;&lt;code&gt;-- 14:50 응급 처치 시작 (순서대로)

-- 1. 문제가 되는 트리거 즉시 비활성화
ALTER TABLE measurement_data DISABLE TRIGGER trg_sync_measurement;
-- 이제 새로운 INSERT는 원격 전송 시도 안 함

-- 2. 5분 이상 실행 중인 쿼리 강제 종료
SELECT pg_terminate_backend(pid) 
FROM pg_stat_activity 
WHERE now() - query_start &amp;gt; interval '5 minutes'
  AND state != 'idle'
  AND pid != pg_backend_pid();  -- 내 세션은 제외
-- 약 50개 세션 종료됨

-- 3. 복제 슬롯 삭제 (WAL 디스크 해방)
SELECT pg_drop_replication_slot(slot_name)
FROM pg_replication_slots
WHERE active = false;
-- 비활성 슬롯 삭제 &amp;rarr; 수십 GB WAL 해방

-- 4. 오래된 idle 커넥션 정리
SELECT pg_terminate_backend(pid)
FROM pg_stat_activity
WHERE state = 'idle'
  AND state_change &amp;lt; now() - interval '30 minutes';
&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;pg-card pg-card-success&quot;&gt;
&lt;div class=&quot;pg-timeline&quot;&gt;
&lt;div class=&quot;pg-timeline-item success&quot;&gt;&lt;b&gt;  15:10&lt;/b&gt; - 서버 정상화. 커넥션 수 정상 범위로 돌아오고, 다른 서비스들도 복구됨.&lt;br /&gt;하지만 마음의 상처는 회복되지 않았다... 그리고 이제 원인 분석과 재발 방지 대책을 세워야 한다. 야근 확정.&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;pg-alert pg-alert-info&quot;&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;  그날의 교훈&lt;/h4&gt;
&lt;p style=&quot;margin: 0;&quot; data-ke-size=&quot;size16&quot;&gt;&quot;트리거 문제, 논리복제 문제 다 겪어보니 식은땀과 정신이 혼미해지네...&quot;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&quot;현기증 난단 말이에요!!!&quot;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;진짜 현기증 났다. 비유가 아니라.&lt;/p&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;section id=&quot;analysis&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;기술적 분석 : 도대체 왜 죽은 걸까&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사건이 진정된 후, 원인을 철저히 분석했다. 야근하면서. 커피 다섯 잔 마시면서.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결론부터 말하면, 두 가지 방식 모두 &lt;b&gt;동기식 처리의 한계&lt;/b&gt;라는 같은 문제를 안고 있었다.&lt;/p&gt;
&lt;div class=&quot;pg-grid-2&quot;&gt;
&lt;div class=&quot;pg-card pg-card-orange&quot;&gt;
&lt;h4 style=&quot;margin: 0 0 20px 0;&quot; data-ke-size=&quot;size20&quot;&gt;⚡ FDW + Trigger의 한계&lt;/h4&gt;
&lt;ul class=&quot;pg-list&quot; style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #dc3545;&quot; class=&quot;pg-list-icon&quot;&gt;✗&lt;/span&gt;
&lt;div&gt;&lt;b&gt;동기적 처리:&lt;/b&gt; 트리거 안에서 원격 쿼리 실행. 네트워크가 느려지면 SQL 실행 자체가 멈춘다. 원격 쿼리가 끝날 때까지 로컬 트랜잭션도 대기.&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #dc3545;&quot; class=&quot;pg-list-icon&quot;&gt;✗&lt;/span&gt;
&lt;div&gt;&lt;b&gt;VPN 오버헤드:&lt;/b&gt; Tailscale 암호화 터널을 지나는 매 쿼리마다 약간의 지연 발생. 쿼리 한두 개면 모르는데, 1분에 수십 개씩 쌓이면 누적된다.&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #dc3545;&quot; class=&quot;pg-list-icon&quot;&gt;✗&lt;/span&gt;
&lt;div&gt;&lt;b&gt;트리거 락:&lt;/b&gt; AFTER INSERT 트리거가 끝날 때까지 해당 행에 Lock이 유지된다. 트리거가 느리면 다른 INSERT도 대기.&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #dc3545;&quot; class=&quot;pg-list-icon&quot;&gt;✗&lt;/span&gt;
&lt;div&gt;&lt;b&gt;커넥션 고갈:&lt;/b&gt; FDW는 원격 쿼리마다 커넥션을 사용한다. 동시에 여러 트리거가 실행되면 커넥션 풀이 순식간에 소진.&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;pg-card pg-card-purple&quot;&gt;
&lt;h4 style=&quot;margin: 0 0 20px 0;&quot; data-ke-size=&quot;size20&quot;&gt;  논리 복제의 함정&lt;/h4&gt;
&lt;ul class=&quot;pg-list&quot; style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #dc3545;&quot; class=&quot;pg-list-icon&quot;&gt;✗&lt;/span&gt;
&lt;div&gt;&lt;b&gt;WAL 무한 증식:&lt;/b&gt; Subscriber가 오프라인이면 Publisher의 WAL 로그가 계속 쌓인다. 디스크 풀 &amp;rarr; DB 사망 루트.&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #dc3545;&quot; class=&quot;pg-list-icon&quot;&gt;✗&lt;/span&gt;
&lt;div&gt;&lt;b&gt;스키마 민감도:&lt;/b&gt; Publisher와 Subscriber의 테이블 구조가 조금만 달라도 복제 중단. 컬럼 추가하려면 양쪽 다 해야 한다.&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #dc3545;&quot; class=&quot;pg-list-icon&quot;&gt;✗&lt;/span&gt;
&lt;div&gt;&lt;b&gt;충돌 미해결:&lt;/b&gt; PK 충돌 시 복제가 완전히 멈춘다. 자동 해결 없음. 사람이 직접 해결해야 함.&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #dc3545;&quot; class=&quot;pg-list-icon&quot;&gt;✗&lt;/span&gt;
&lt;div&gt;&lt;b&gt;리소스 경합:&lt;/b&gt; 복제 프로세스(wal sender, logical replication worker)가 CPU와 I/O를 꽤 잡아먹는다.&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;핵심 문제 : 동기식 처리의 한계&lt;/h3&gt;
&lt;div class=&quot;pg-alert pg-alert-info&quot;&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;  핵심 깨달음&lt;/h4&gt;
&lt;p style=&quot;margin: 0; font-size: 1.05em;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&quot;원격 작업이 로컬 작업을 블로킹하면 안 된다!&quot;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;실시간이라고 해서 반드시 동기식으로 처리할 필요는 없다. 서버에 문제가 생겨도 &lt;b&gt;로컬 시스템은 정상 동작&lt;/b&gt;해야 한다. 이게 분산 시스템의 기본 원칙인데, 나는 이걸 망각했다.&lt;/p&gt;
&lt;/div&gt;
&lt;pre class=&quot;pg-diagram css&quot;&gt;&lt;code&gt;/* 문제의 흐름 - 동기식 처리의 위험 */

[계측기] &amp;rarr; [로컬 DB INSERT] &amp;rarr; [트리거 발동] &amp;rarr; [FDW 원격 INSERT]
                                                            │
                                                            ▼
                                                    네트워크 지연 발생!
                                                            │
                                                            ▼
                                          로컬 트랜잭션도 대기 상태로 전환
                                                            │
                                                            ▼
                                              다음 INSERT도 대기열에 쌓임
                                                            │
                                                            ▼
                                           커넥션 풀 고갈 &amp;rarr; DB 다운

핵심 : 원격 장애가 로컬 시스템 전체를 멈추게 하면 안 된다!
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사업장의 인터넷이 느려지거나, 중앙 서버가 잠깐 바빠지거나, VPN이 불안정해지면 그 영향이 로컬 시스템까지 전파되는 구조였다. 이건 설계 자체가 잘못된 것이다.&lt;/p&gt;
&lt;/section&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;section id=&quot;solution&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;해결을 향한 여정 : 앞으로의 접근 방법&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;솔직히 고백하면, 아직 완벽한 해결책을 찾지 못했다. 하지만 여러 가지 방법을 조사하고 테스트하면서, 앞으로 이런 방향으로 접근하려고 한다.&lt;/p&gt;
&lt;div class=&quot;pg-alert pg-alert-success&quot;&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;  핵심 원칙&lt;/h4&gt;
&lt;p style=&quot;margin: 0;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&quot;로컬 작업과 원격 동기화를 분리하자&quot;&lt;/b&gt;&lt;br /&gt;원격 서버에 문제가 생겨도 로컬 시스템은 정상 동작해야 한다. 이게 이번 삽질에서 얻은 가장 큰 교훈이다.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;pg-card pg-card-success&quot;&gt;
&lt;h3 style=&quot;margin: 0 0 15px 0;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span class=&quot;pg-step-number&quot;&gt;1&lt;/span&gt;'동기'에서 '비동기'로의 전환&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;트리거에서 즉시 원격 서버로 쏘지 말고, &lt;b&gt;로컬에 임시 테이블(큐)을 두거나 메시지 큐(MQTT, RabbitMQ)를 사용&lt;/b&gt;해 서버가 한가할 때 가져가게 하는 방식이 안전하다.&lt;/p&gt;
&lt;pre class=&quot;pg-code pgsql&quot;&gt;&lt;code&gt;-- 동기화 큐 테이블 생성
CREATE TABLE sync_queue (
    id BIGSERIAL PRIMARY KEY,
    table_name VARCHAR(100) NOT NULL,
    record_id BIGINT NOT NULL,
    operation VARCHAR(10) NOT NULL,
    payload JSONB NOT NULL,
    created_at TIMESTAMP DEFAULT NOW(),
    retry_count INTEGER DEFAULT 0,
    last_error TEXT,
    status VARCHAR(20) DEFAULT 'pending'
);

CREATE INDEX idx_sync_queue_status ON sync_queue(status, created_at);

-- 트리거는 큐에 넣기만 한다 (매우 빠름!)
CREATE OR REPLACE FUNCTION queue_for_sync()
RETURNS TRIGGER AS $$
BEGIN
    INSERT INTO sync_queue (table_name, record_id, operation, payload)
    VALUES (TG_TABLE_NAME, NEW.id, TG_OP, row_to_json(NEW)::jsonb);
    RETURN NEW;
END;
$$ LANGUAGE plpgsql;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 하면 로컬 INSERT는 로컬 테이블에 한 줄 추가하는 것으로 끝난다. 밀리초 단위로 끝난다. 원격 서버가 죽어있든 말든 상관없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;별도의 워커 프로세스가 주기적으로 큐를 확인하고 서버로 전송한다. 실패하면 retry_count 올리고 나중에 다시 시도.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;pg-card pg-card-info&quot;&gt;
&lt;h3 style=&quot;margin: 0 0 15px 0;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span class=&quot;pg-step-number&quot;&gt;2&lt;/span&gt;배치(Batch) 인서트 활용&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터가 1분에 수십 개씩 발생한다면, 건건이 쏘지 말고 &lt;b&gt;5분치 데이터를 모아서 한 번에 서버로 COPY 명령어&lt;/b&gt;를 날리는 것이 훨씬 효율적이다.&lt;/p&gt;
&lt;pre class=&quot;pg-code sql&quot;&gt;&lt;code&gt;-- PostgreSQL COPY는 대량 INSERT보다 훨씬 빠름
-- 100건 INSERT하는 것보다 COPY로 100건 넣는 게 10배는 빠르다

-- 방법 1 : CSV 파일로 내보내고 COPY
COPY (
    SELECT id, sensor_id, value, measured_at 
    FROM sync_queue 
    WHERE status = 'pending'
    LIMIT 1000
) TO '/tmp/batch_data.csv' WITH CSV;

-- 방법 2 : INSERT ... SELECT로 배치 처리 (FDW 사용)
INSERT INTO remote_measurement (id, sensor_id, value, measured_at)
SELECT (payload-&amp;gt;&amp;gt;'id')::bigint,
       (payload-&amp;gt;&amp;gt;'sensor_id')::int,
       (payload-&amp;gt;&amp;gt;'value')::numeric,
       (payload-&amp;gt;&amp;gt;'measured_at')::timestamp
FROM sync_queue 
WHERE status = 'pending'
LIMIT 500;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;네트워크 왕복 횟수가 대폭 줄어든다. 100번 왕복할 거 1번으로 끝. 서버 부하도 분산된다.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;pg-card pg-card-purple&quot;&gt;
&lt;h3 style=&quot;margin: 0 0 15px 0;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span class=&quot;pg-step-number&quot;&gt;3&lt;/span&gt;헬스 체크 및 모니터링 강화&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서버가 느려질 때 바로 알 수 있도록 &lt;b&gt;모니터링 시스템&lt;/b&gt;을 구축해야 한다. 문제가 터지기 전에 감지하는 게 최선이다.&lt;/p&gt;
&lt;pre class=&quot;pg-code pgsql&quot;&gt;&lt;code&gt;-- 모니터링 필수 쿼리들 (크론으로 1분마다 실행)

-- 1. 복제 슬롯 WAL 누적량 (1GB 이상이면 경고)
SELECT slot_name,
       pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn)) AS retained_wal,
       active,
       CASE 
           WHEN pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn) &amp;gt; 1073741824 
           THEN '⚠️ WARNING'
           ELSE '✅ OK'
       END AS status
FROM pg_replication_slots;

-- 2. 커넥션 사용량 (80% 이상이면 경고)
SELECT 
    count(*) AS current_conn,
    (SELECT setting::int FROM pg_settings WHERE name = 'max_connections') AS max_conn,
    round(count(*) * 100.0 / (SELECT setting::int FROM pg_settings WHERE name = 'max_connections'), 1) AS pct
FROM pg_stat_activity;

-- 3. 장시간 실행 쿼리 (5분 이상이면 경고)
SELECT count(*) AS long_running_queries
FROM pg_stat_activity
WHERE state != 'idle' 
  AND now() - query_start &amp;gt; interval '5 minutes';
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Prometheus + Grafana 조합이 좋다. postgres_exporter를 붙이면 PostgreSQL 메트릭을 자동으로 수집해준다. 대시보드도 이쁘게 만들 수 있다.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;pg-card pg-card-teal&quot;&gt;
&lt;h3 style=&quot;margin: 0 0 15px 0;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span class=&quot;pg-step-number&quot;&gt;4&lt;/span&gt;CDC(Change Data Capture) 검토&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Debezium&lt;/b&gt; 같은 CDC 도구를 사용하면 PostgreSQL의 WAL 로그를 직접 읽어서 변경 이벤트를 발행할 수 있다. 논리복제보다 더 유연하고, 트리거보다 안전하다.&lt;/p&gt;
&lt;pre class=&quot;pg-diagram less&quot;&gt;&lt;code&gt;/* CDC 기반 아키텍처 */

[PostgreSQL] ──WAL──▶ [Debezium] ──▶ [Kafka] ──▶ [Consumer] ──▶ [서버 DB]
      │                      │
      │                      └── 변경 이벤트를 JSON으로 발행
      │
      └── 애플리케이션 코드 수정 불필요!
           기존 INSERT/UPDATE/DELETE 그대로 사용
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;장점은 애플리케이션 코드를 전혀 수정하지 않아도 된다는 것. 단점은 인프라가 복잡해진다는 것. Debezium + Kafka + ZooKeeper... 소규모에는 오버스펙일 수 있다.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;pg-card pg-card-warning&quot;&gt;
&lt;h3 style=&quot;margin: 0 0 15px 0;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span class=&quot;pg-step-number&quot;&gt;5&lt;/span&gt;하이브리드 전략&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 데이터를 똑같이 처리할 필요는 없다. &lt;b&gt;데이터 특성에 따라 다른 전략&lt;/b&gt;을 사용하는 것이 현실적이다.&lt;/p&gt;
&lt;pre class=&quot;pg-diagram angelscript&quot;&gt;&lt;code&gt;/* 하이브리드 전략 */

[긴급 알람 데이터] &amp;larr; 온도 이상, 장비 고장 등
  └── REST API 직접 전송 (동기, 하지만 타임아웃 설정)
  └── 실패 시 로컬 큐에 저장 후 재시도
  └── 지연 허용 : 0~5초

[일반 계측 데이터] &amp;larr; 1분마다 쌓이는 센서 데이터
  └── 로컬 DB에 저장
  └── 5분마다 배치로 서버 전송
  └── 지연 허용 : ~5분

[이력/로그 데이터] &amp;larr; 기기 로그, 작업 이력 등
  └── 1시간마다 또는 하루에 한 번 동기화
  └── 실시간성 불필요
  └── 지연 허용 : ~24시간

핵심 질문 : 정말 모든 데이터에 &quot;실시간&quot;이 필요한가?  
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;고객한테 다시 물어봐야 한다. &quot;정말 모든 데이터가 실시간으로 필요하신 건가요? 아니면 알람만 실시간이면 되나요?&quot; 요구사항을 다시 정의하는 것도 방법이다.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;pg-card pg-card-orange&quot;&gt;
&lt;h3 style=&quot;margin: 0 0 15px 0;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span class=&quot;pg-step-number&quot;&gt;6&lt;/span&gt;FDW 개선 (당장 적용 가능)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;당장 구조를 바꾸기 어렵다면, 최소한 &lt;b&gt;타임아웃 설정과 예외 처리 강화&lt;/b&gt;는 해야 한다. 이건 오늘이라도 할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;pg-code routeros&quot;&gt;&lt;code&gt;-- FDW 연결에 타임아웃 설정 (필수!)
ALTER SERVER central_server OPTIONS (
    ADD connect_timeout '10',
    ADD options '-c statement_timeout=30000'
);

-- connect_timeout : 연결 타임아웃 10초
-- statement_timeout : 쿼리 타임아웃 30초 (30000ms)
-- 이 설정 없으면 무한 대기할 수 있다!
&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;pg-code pgsql&quot;&gt;&lt;code&gt;-- 트리거에서 예외 처리 강화 + 실패 로깅
CREATE OR REPLACE FUNCTION sync_to_server_safe()
RETURNS TRIGGER AS $$
BEGIN
    INSERT INTO remote_measurement (id, sensor_id, value, measured_at)
    VALUES (NEW.id, NEW.sensor_id, NEW.value, NEW.measured_at);
    
    RETURN NEW;
    
EXCEPTION WHEN OTHERS THEN
    -- 실패해도 로컬 INSERT는 성공하도록!
    INSERT INTO sync_failure_log (
        table_name, record_id, error_message, created_at
    ) VALUES (
        'measurement_data', NEW.id, SQLERRM, NOW()
    );
    
    RETURN NEW;  -- 에러 나도 RETURN NEW!
END;
$$ LANGUAGE plpgsql;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;  단계별 실행 계획&lt;/h3&gt;
&lt;table class=&quot;pg-table&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;단계&lt;/th&gt;
&lt;th&gt;내용&lt;/th&gt;
&lt;th&gt;예상 기간&lt;/th&gt;
&lt;th&gt;우선순위&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;즉시&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;FDW 타임아웃 설정 + 예외 처리 강화 + 모니터링 쿼리 작성&lt;/td&gt;
&lt;td&gt;1주&lt;/td&gt;
&lt;td style=&quot;color: #dc3545;&quot;&gt;  긴급&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;단기&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;sync_queue 테이블 도입 + 워커 프로세스 개발&lt;/td&gt;
&lt;td&gt;2-3주&lt;/td&gt;
&lt;td style=&quot;color: #fd7e14;&quot;&gt;  높음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;중기&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;RabbitMQ 또는 MQTT 도입 검토 및 테스트&lt;/td&gt;
&lt;td&gt;1-2개월&lt;/td&gt;
&lt;td style=&quot;color: #ffc107;&quot;&gt;  중간&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;장기&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;데이터 특성별 하이브리드 전략 완성 + CDC 검토&lt;/td&gt;
&lt;td&gt;3개월+&lt;/td&gt;
&lt;td style=&quot;color: #28a745;&quot;&gt;  개선&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;div class=&quot;pg-alert pg-alert-success&quot;&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;  현재 상태&lt;/h4&gt;
&lt;p style=&quot;margin: 0;&quot; data-ke-size=&quot;size16&quot;&gt;솔직히 말하면, 여러 가지 방법을 시도 중이고 아직도 삽질하는 중이다. 하지만 &lt;b&gt;반드시 성공할 것이다.&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;이 문제를 해결하면 다시 성공 사례를 공유하겠다. 그때는 &quot;이렇게 하면 됩니다~&quot;라고 자신 있게 말할 수 있을 거다. 아마도.&lt;/p&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;section id=&quot;conclusion&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;마무리 : 실패도 자산이다&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기술 블로그에는 보통 성공 사례만 올라온다. &lt;i&gt;&quot;이렇게 하면 됩니다&quot;&lt;/i&gt;, &lt;i&gt;&quot;이 방법으로 해결했습니다&quot;&lt;/i&gt; 같은 글들이 대부분이다. 나도 그런 글을 썼었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 현실에서는 실패가 훨씬 많다. 10번 시도해서 1번 성공하면 그나마 다행이다. 나머지 9번의 실패는 어디로 갔을까? 블로그에는 안 올라온다. 부끄러우니까.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나는 &lt;b&gt;실패 경험도 중요한 자산&lt;/b&gt;이라고 생각한다. 적어도 이런 효과는 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;다른 개발자들이 같은 실수를 반복하지 않도록 도움&lt;/li&gt;
&lt;li&gt;&quot;나만 이런 거 아니구나&quot;라는 위안 제공&lt;/li&gt;
&lt;li&gt;글로 정리하면서 스스로 원인과 해결책을 명확히 정리&lt;/li&gt;
&lt;li&gt;나중에 비슷한 상황에서 참고 자료로 활용&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;pg-card&quot;&gt;
&lt;h4 style=&quot;margin: 0 0 20px 0;&quot; data-ke-size=&quot;size20&quot;&gt;  이 글의 핵심 요약&lt;/h4&gt;
&lt;ol style=&quot;margin: 0; padding-left: 25px; line-height: 2.2;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;논리복제&lt;/b&gt; : 강력하지만 복제 슬롯 관리 실패하면 WAL이 쌓여서 서버가 죽는다&lt;/li&gt;
&lt;li&gt;&lt;b&gt;FDW + 트리거&lt;/b&gt; : 편리하지만 타임아웃 없으면 되다가 갑자기 죽는다&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Tailscale VPN&lt;/b&gt; : 보안 연결은 완벽했다. 문제는 그 위의 레이어(DB 동기화)였다&lt;/li&gt;
&lt;li&gt;&lt;b&gt;동기식 처리의 한계&lt;/b&gt; : 원격 장애가 로컬 시스템에 영향 주면 안 된다&lt;/li&gt;
&lt;li&gt;&lt;b&gt;비동기 방식&lt;/b&gt; : 메시지 큐, CDC, 애플리케이션 큐 등 대안이 많다&lt;/li&gt;
&lt;li&gt;&lt;b&gt;모니터링&lt;/b&gt; : 문제가 터지기 전에 감지하는 게 최선이다&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&quot;pg-quote&quot;&gt;
&lt;p style=&quot;margin: 0; font-size: 1.1em;&quot; data-ke-size=&quot;size16&quot;&gt;&quot;실패는 성공의 어머니다. 단, 같은 실패를 반복하지 않을 때만.&quot;&lt;/p&gt;
&lt;p class=&quot;pg-quote-author&quot; data-ke-size=&quot;size16&quot;&gt;&amp;mdash; 서버 두 번 죽여본 개발자의 교훈&lt;/p&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 글을 읽는 누군가가 비슷한 상황에서 조금이라도 도움이 되었으면 좋겠다. 그리고 제발, 나처럼 서버를 두 번 죽이진 말자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나중에 이 문제를 해결하면 그때 다시 성공 사례를 공유하겠다. 그때까지는... 삽질 일지를 계속 써나가야겠다. 화이팅.  &lt;/p&gt;
&lt;div class=&quot;pg-card pg-card-warning&quot; style=&quot;text-align: center;&quot;&gt;
&lt;p style=&quot;margin: 0; font-size: 1.15em; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt; &amp;zwj;  트리거 문제, 논리복제 문제 다 겪어보니&lt;br /&gt;식은땀과 정신이 혼미해지네...&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&quot;현기증 난단 말이에요!!!&quot;&lt;/b&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;관련 포스팅&lt;/h3&gt;
&lt;ul style=&quot;line-height: 2;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://odinbox.co.kr/555&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;PostgreSQL 논리복제 실무 가이드&lt;/a&gt; - 논리복제 설정 방법 (이론편)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://odinbox.co.kr/568&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;PostgreSQL FDW(Foreign Data Wrapper) 사용법&lt;/a&gt; - FDW 기본 사용법&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;궁금한 점이나 비슷한 경험이 있다면 댓글로 공유 부탁드립니다. 함께 고민하면 더 좋은 해결책을 찾을 수 있을 것입니다.  &lt;/p&gt;
&lt;/section&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;section&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Tags&lt;/h3&gt;
&lt;div class=&quot;pg-tags&quot;&gt;&lt;span class=&quot;pg-tag&quot;&gt;#PostgreSQL&lt;/span&gt; &lt;span class=&quot;pg-tag&quot;&gt;#논리복제&lt;/span&gt; &lt;span class=&quot;pg-tag&quot;&gt;#LogicalReplication&lt;/span&gt; &lt;span class=&quot;pg-tag&quot;&gt;#FDW&lt;/span&gt; &lt;span class=&quot;pg-tag&quot;&gt;#실시간데이터동기화&lt;/span&gt; &lt;span class=&quot;pg-tag&quot;&gt;#TailscaleVPN&lt;/span&gt; &lt;span class=&quot;pg-tag&quot;&gt;#분산데이터베이스&lt;/span&gt; &lt;span class=&quot;pg-tag&quot;&gt;#데이터베이스장애&lt;/span&gt; &lt;span class=&quot;pg-tag&quot;&gt;#개발삽질기&lt;/span&gt; &lt;span class=&quot;pg-tag&quot;&gt;#IoT데이터수집&lt;/span&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;/article&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;
&lt;script type=&quot;application/ld+json&quot;&gt;
{&quot;@context&quot;:&quot;https://schema.org&quot;,&quot;@type&quot;:&quot;TechArticle&quot;,&quot;headline&quot;:&quot;PostgreSQL 논리복제와 FDW로 운영 서버를 두 번 죽여본 개발자의 실시간 데이터 동기화 생존기&quot;,&quot;alternativeHeadline&quot;:&quot;PostgreSQL Logical Replication과 FDW 실패 경험 및 해결 방안&quot;,&quot;description&quot;:&quot;PostgreSQL 논리복제(Logical Replication)와 FDW(Foreign Data Wrapper)를 사용하다 운영 서버를 다운시킨 실패 경험과 Tailscale VPN 환경에서의 실시간 계측 데이터 동기화 도전기. 복제 슬롯 관리, 트리거 타임아웃, 비동기 처리, 메시지 큐, CDC 등 해결 방안을 상세히 제시합니다.&quot;,&quot;author&quot;:{&quot;@type&quot;:&quot;Person&quot;,&quot;name&quot;:&quot;영환&quot;,&quot;url&quot;:&quot;https://odinbox.co.kr&quot;},&quot;publisher&quot;:{&quot;@type&quot;:&quot;Organization&quot;,&quot;name&quot;:&quot;OdinBOX&quot;,&quot;url&quot;:&quot;https://odinbox.co.kr&quot;},&quot;datePublished&quot;:&quot;2026-01-24&quot;,&quot;dateModified&quot;:&quot;2026-01-24&quot;,&quot;mainEntityOfPage&quot;:{&quot;@type&quot;:&quot;WebPage&quot;,&quot;@id&quot;:&quot;https://odinbox.co.kr/&quot;},&quot;keywords&quot;:[&quot;PostgreSQL&quot;,&quot;논리복제&quot;,&quot;Logical Replication&quot;,&quot;FDW&quot;,&quot;Foreign Data Wrapper&quot;,&quot;Tailscale VPN&quot;,&quot;실시간 데이터 동기화&quot;,&quot;분산 데이터베이스&quot;,&quot;CDC&quot;,&quot;Debezium&quot;,&quot;RabbitMQ&quot;,&quot;메시지 큐&quot;,&quot;복제 슬롯&quot;,&quot;WAL&quot;,&quot;데이터베이스 장애&quot;],&quot;articleSection&quot;:&quot;Database&quot;,&quot;inLanguage&quot;:&quot;ko-KR&quot;}
&lt;/script&gt;
&lt;script type=&quot;application/ld+json&quot;&gt;
{&quot;@context&quot;:&quot;https://schema.org&quot;,&quot;@type&quot;:&quot;FAQPage&quot;,&quot;mainEntity&quot;:[{&quot;@type&quot;:&quot;Question&quot;,&quot;name&quot;:&quot;PostgreSQL 논리복제가 서버를 다운시킬 수 있나요?&quot;,&quot;acceptedAnswer&quot;:{&quot;@type&quot;:&quot;Answer&quot;,&quot;text&quot;:&quot;네, 가능합니다. 특히 복제 슬롯(Replication Slot) 관리를 소홀히 하면 Subscriber가 오프라인일 때 WAL 로그가 무한히 쌓여 디스크가 꽉 차면서 DB가 다운될 수 있습니다. pg_replication_slots 뷰를 주기적으로 모니터링하고, 불필요한 슬롯은 pg_drop_replication_slot()으로 삭제해야 합니다.&quot;}},{&quot;@type&quot;:&quot;Question&quot;,&quot;name&quot;:&quot;PostgreSQL FDW와 트리거를 함께 사용하면 위험한가요?&quot;,&quot;acceptedAnswer&quot;:{&quot;@type&quot;:&quot;Answer&quot;,&quot;text&quot;:&quot;주의가 필요합니다. 트리거 내에서 FDW를 통한 원격 쿼리는 동기식으로 처리되어 네트워크 지연 시 로컬 DB까지 블로킹됩니다. 반드시 connect_timeout과 statement_timeout을 설정하고, 예외 처리를 통해 원격 실패가 로컬 트랜잭션에 영향을 주지 않도록 해야 합니다.&quot;}},{&quot;@type&quot;:&quot;Question&quot;,&quot;name&quot;:&quot;Tailscale VPN으로 PostgreSQL 데이터베이스 연결이 가능한가요?&quot;,&quot;acceptedAnswer&quot;:{&quot;@type&quot;:&quot;Answer&quot;,&quot;text&quot;:&quot;네, 가능합니다. Tailscale VPN은 WireGuard 기반의 Zero-config VPN으로 공인 IP 없이도 안전하게 DB에 접근할 수 있습니다. 다만 암호화 터널을 통과하는 쿼리마다 약간의 오버헤드가 발생하므로, 빈번한 쿼리가 필요한 실시간 동기화에서는 배치 처리나 비동기 방식을 권장합니다.&quot;}},{&quot;@type&quot;:&quot;Question&quot;,&quot;name&quot;:&quot;실시간 데이터 동기화에서 동기식 대신 비동기식이 좋은 이유는?&quot;,&quot;acceptedAnswer&quot;:{&quot;@type&quot;:&quot;Answer&quot;,&quot;text&quot;:&quot;동기식 처리는 원격 서버에 문제가 생기면 로컬 시스템까지 영향을 받습니다. 비동기식은 로컬에서 큐 테이블이나 메시지 큐에 먼저 저장하고, 별도 프로세스가 서버로 전송하므로 원격 장애가 로컬에 영향을 주지 않습니다. RabbitMQ, Kafka, 또는 간단한 sync_queue 테이블 방식을 사용할 수 있습니다.&quot;}},{&quot;@type&quot;:&quot;Question&quot;,&quot;name&quot;:&quot;PostgreSQL 복제 슬롯 WAL 누적을 모니터링하는 방법은?&quot;,&quot;acceptedAnswer&quot;:{&quot;@type&quot;:&quot;Answer&quot;,&quot;text&quot;:&quot;SELECT slot_name, pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn)) AS retained_wal, active FROM pg_replication_slots; 쿼리로 확인할 수 있습니다. retained_wal이 1GB 이상이면 경고, 10GB 이상이면 즉시 조치가 필요합니다.&quot;}},{&quot;@type&quot;:&quot;Question&quot;,&quot;name&quot;:&quot;FDW 연결에 타임아웃을 설정하는 방법은?&quot;,&quot;acceptedAnswer&quot;:{&quot;@type&quot;:&quot;Answer&quot;,&quot;text&quot;:&quot;ALTER SERVER 서버명 OPTIONS (ADD connect_timeout '10', ADD options '-c statement_timeout=30000'); 명령으로 설정합니다. connect_timeout은 연결 타임아웃(초 단위), statement_timeout은 쿼리 타임아웃(밀리초 단위)입니다.&quot;}}]}
&lt;/script&gt;
&lt;script type=&quot;application/ld+json&quot;&gt;
{&quot;@context&quot;:&quot;https://schema.org&quot;,&quot;@type&quot;:&quot;HowTo&quot;,&quot;name&quot;:&quot;PostgreSQL 실시간 데이터 동기화 장애 복구 방법&quot;,&quot;description&quot;:&quot;FDW + 트리거 또는 논리복제로 인한 PostgreSQL 서버 장애 발생 시 응급 복구 절차&quot;,&quot;totalTime&quot;:&quot;PT20M&quot;,&quot;step&quot;:[{&quot;@type&quot;:&quot;HowToStep&quot;,&quot;name&quot;:&quot;문제가 되는 트리거 비활성화&quot;,&quot;text&quot;:&quot;ALTER TABLE 테이블명 DISABLE TRIGGER 트리거명; 명령으로 동기화 트리거를 즉시 비활성화합니다.&quot;,&quot;position&quot;:1},{&quot;@type&quot;:&quot;HowToStep&quot;,&quot;name&quot;:&quot;장시간 실행 쿼리 강제 종료&quot;,&quot;text&quot;:&quot;SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE now() - query_start &gt; interval '5 minutes' AND state != 'idle'; 로 오래 실행 중인 쿼리를 강제 종료합니다.&quot;,&quot;position&quot;:2},{&quot;@type&quot;:&quot;HowToStep&quot;,&quot;name&quot;:&quot;복제 슬롯 삭제로 WAL 해방&quot;,&quot;text&quot;:&quot;SELECT pg_drop_replication_slot('슬롯명'); 으로 WAL을 보관하고 있는 복제 슬롯을 삭제하여 디스크 공간을 확보합니다.&quot;,&quot;position&quot;:3},{&quot;@type&quot;:&quot;HowToStep&quot;,&quot;name&quot;:&quot;커넥션 상태 확인 및 정리&quot;,&quot;text&quot;:&quot;SELECT count(*) FROM pg_stat_activity; 로 현재 커넥션 수를 확인하고, 불필요한 idle 커넥션을 정리합니다.&quot;,&quot;position&quot;:4},{&quot;@type&quot;:&quot;HowToStep&quot;,&quot;name&quot;:&quot;서버 상태 모니터링&quot;,&quot;text&quot;:&quot;CPU, 메모리, 디스크 사용량을 확인하고 정상 범위로 돌아왔는지 확인합니다.&quot;,&quot;position&quot;:5}]}
&lt;/script&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>DEVELOPMENT</category>
      <category>FDW</category>
      <category>IoT수집</category>
      <category>LogicalReplication</category>
      <category>PostgreSQL</category>
      <category>TailscaleVPN</category>
      <category>개발삽질기</category>
      <category>논리복제</category>
      <category>분산데이터베이스</category>
      <category>실시간데이터동기화</category>
      <category>탄소중립(FEMS)</category>
      <author>간지뽕빨리턴님</author>
      <guid isPermaLink="true">https://odinbox.tistory.com/569</guid>
      <comments>https://odinbox.tistory.com/569#entry569comment</comments>
      <pubDate>Sat, 24 Jan 2026 21:49:34 +0900</pubDate>
    </item>
    <item>
      <title>PostgreSQL FDW</title>
      <link>https://odinbox.tistory.com/568</link>
      <description>&lt;article class=&quot;post-fdw&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;글 상단 부분 대표 이미지.png&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bXVWBH/dJMcadgqVHq/UiyGElX1PK4R2FKWCzGSFK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bXVWBH/dJMcadgqVHq/UiyGElX1PK4R2FKWCzGSFK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bXVWBH/dJMcadgqVHq/UiyGElX1PK4R2FKWCzGSFK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbXVWBH%2FdJMcadgqVHq%2FUiyGElX1PK4R2FKWCzGSFK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;400&quot; data-filename=&quot;글 상단 부분 대표 이미지.png&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;header&gt;
&lt;p class=&quot;meta&quot; data-ke-size=&quot;size16&quot;&gt;PostgreSQL 15 &amp;middot; Windows 환경 &amp;middot; FDW 실무 적용 &amp;middot; 이종 DB 연동&lt;/p&gt;
&lt;p class=&quot;lead&quot; data-ke-size=&quot;size16&quot;&gt;PostgreSQL의 Foreign Data Wrapper(FDW)는 외부 데이터베이스를 로컬 테이블처럼 사용할 수 있도록 지원하는 기능입니다. 본 글에서는 PostgreSQL 15 Windows 환경을 기준으로 Postgres 간 연동부터 Oracle, MySQL, SQL Server 등 이종 데이터베이스를 실제 운영 환경에서 연결하고 활용하는 방법을 정리합니다.&lt;/p&gt;
&lt;/header&gt;
&lt;section&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;FDW 개요 및 Oracle DB Link와의 차이&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Foreign Data Wrapper(FDW)는 PostgreSQL에서 외부 데이터 소스를 외부 테이블(Foreign Table) 형태로 정의하여 SELECT, INSERT, UPDATE, DELETE를 수행할 수 있도록 해주는 기능입니다. 별도의 데이터 이관 없이도 실시간으로 외부 데이터베이스를 조회할 수 있어 시스템 통합 및 점진적 마이그레이션에 매우 유용합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Oracle Database 역시 Database Link 기능을 통해 원격 데이터베이스 접근을 지원합니다. 다만 Oracle DB Link는 기본적으로 Oracle 간 연결에 최적화되어 있으며, 이종 데이터베이스 연동을 위해서는 Gateway 또는 별도 미들웨어 구성이 필요합니다. 반면 PostgreSQL FDW는 확장(extension) 기반 구조로 다양한 데이터베이스를 직접 연결할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div class=&quot;box info&quot;&gt;PostgreSQL FDW는 데이터 통합, 병행 운영, 단계적 전환 환경에서 특히 높은 효용을 보입니다.&lt;/div&gt;
&lt;/section&gt;
&lt;section&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Postgres &amp;rarr; Postgres 연결 (postgres_fdw)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PostgreSQL 간 연동은 기본 제공되는 postgres_fdw를 사용합니다. 설정 절차는 다음과 같이 고정된 순서로 진행합니다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Extension 생성&lt;/li&gt;
&lt;li&gt;Foreign Server 등록&lt;/li&gt;
&lt;li&gt;User Mapping 생성&lt;/li&gt;
&lt;li&gt;Foreign Table 생성&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;n1ql&quot;&gt;&lt;code&gt;CREATE EXTENSION IF NOT EXISTS postgres_fdw;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;CREATE SERVER remote_pg_server
FOREIGN DATA WRAPPER postgres_fdw
OPTIONS (host '192.168.0.100', port '5432', dbname 'remote_db');&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;CREATE USER MAPPING FOR CURRENT_USER
SERVER remote_pg_server
OPTIONS (user 'remote_user', password 'remote_password');&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;CREATE FOREIGN TABLE public.remote_orders_ft (
order_id bigint,
customer_id bigint,
total_amt numeric,
created_at timestamp
)
SERVER remote_pg_server
OPTIONS (schema_name 'public', table_name 'orders');&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;SELECT *
FROM public.remote_orders_ft
WHERE created_at &amp;gt; now() - interval '7 days';&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;box warn&quot;&gt;원격 PostgreSQL 접속이 되지 않는 경우 pg_hba.conf 설정, 포트 오픈, 방화벽 설정을 우선 확인합니다.&lt;/div&gt;
&lt;/section&gt;
&lt;section&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Postgres &amp;rarr; Oracle 연결 (oracle_fdw)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Oracle 데이터베이스 연동은 oracle_fdw 확장을 사용합니다. Windows 환경에서는 Oracle Instant Client 설치 여부와 PATH 설정이 정상 동작의 핵심 요소입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Oracle Instant Client 설치 후 PATH 환경변수에 해당 경로를 반드시 포함해야 하며, PostgreSQL 서비스 재시작이 필요합니다.&lt;/p&gt;
&lt;pre class=&quot;n1ql&quot;&gt;&lt;code&gt;CREATE EXTENSION IF NOT EXISTS oracle_fdw;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;CREATE SERVER ora_srv
FOREIGN DATA WRAPPER oracle_fdw
OPTIONS (dbserver '//ora.host.com:1521/XEPDB1');&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;GRANT USAGE ON FOREIGN SERVER ora_srv TO postgres;

CREATE USER MAPPING FOR postgres
SERVER ora_srv
OPTIONS (user 'SCOTT', password 'tiger');&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;CREATE FOREIGN TABLE public.ora_emp_ft (
empno numeric(4,0),
ename varchar(10),
sal numeric(7,2)
)
SERVER ora_srv
OPTIONS (schema 'SCOTT', table 'EMP', key 'EMPNO');&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;n1ql&quot;&gt;&lt;code&gt;SELECT *
FROM public.ora_emp_ft;&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;box warn&quot;&gt;oracle_fdw DLL 로딩 오류는 대부분 Instant Client 경로 미인식 문제입니다. 서비스 계정 기준 PATH 설정까지 반드시 확인합니다.&lt;/div&gt;
&lt;/section&gt;
&lt;section&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;MySQL / SQL Server 등 기타 데이터베이스 연결 전략&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MySQL은 mysql_fdw, SQL Server는 tds_fdw 또는 ODBC FDW를 활용할 수 있습니다. Windows 환경에서는 ODBC 드라이버 기반 접근 방식이 현실적인 선택이 되는 경우가 많습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전용 FDW가 안정적으로 제공되는 경우에는 이를 우선 검토하며, 설치나 유지 관리가 어려운 경우 ODBC 기반 접근 방식을 선택하는 것이 운영 측면에서 유리합니다.&lt;/p&gt;
&lt;/section&gt;
&lt;section&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;성능 설계 및 최적화 전략&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;FDW는 네트워크를 통해 원격 쿼리를 수행하므로 성능 설계가 매우 중요합니다. 무분별한 사용은 오히려 시스템 전체 성능 저하로 이어질 수 있습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;WHERE 조건을 최대한 명확히 작성하여 원격 필터링을 유도합니다.&lt;/li&gt;
&lt;li&gt;필요한 컬럼만 조회하여 데이터 전송량을 최소화합니다.&lt;/li&gt;
&lt;li&gt;외부 테이블에 대해 ANALYZE를 수행하여 실행 계획 품질을 개선합니다.&lt;/li&gt;
&lt;li&gt;대량 집계나 통계 쿼리는 원격 DB에서 View로 정리한 후 연결합니다.&lt;/li&gt;
&lt;li&gt;빈번한 조회 데이터는 주기적 적재 또는 구체화 전략을 병행합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;box info&quot;&gt;FDW는 실시간 조회에 적합하며, 리포트&amp;middot;집계성 데이터는 배치 전략과 병행하는 것이 이상적입니다.&lt;/div&gt;
&lt;/section&gt;
&lt;section&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;보안 설계 시 고려 사항&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;FDW는 외부 데이터베이스 접근 권한을 내부로 확장하는 구조이므로 보안 설계가 필수적입니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;User Mapping 계정은 최소 권한 원칙으로 운영합니다.&lt;/li&gt;
&lt;li&gt;읽기 전용 목적이라면 SELECT 권한만 부여합니다.&lt;/li&gt;
&lt;li&gt;운영 계정과 연동 계정을 분리하여 사용합니다.&lt;/li&gt;
&lt;li&gt;Foreign Server 사용 권한은 필요한 사용자에게만 부여합니다.&lt;/li&gt;
&lt;li&gt;접속 이력 및 쿼리 로그를 통해 접근을 추적합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;section&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;실전 운영 및 장애 대응 전략&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제 운영 환경에서는 외부 데이터베이스 장애가 곧바로 내부 서비스 장애로 전파될 수 있습니다. 이를 방지하기 위한 사전 설계가 중요합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;FDW 쿼리 실패 시 서비스 영향도를 사전에 정의합니다.&lt;/li&gt;
&lt;li&gt;타임아웃 및 재시도 정책을 애플리케이션 레벨에서 고려합니다.&lt;/li&gt;
&lt;li&gt;외부 장애 발생 시 대체 경로 또는 캐시 데이터 활용을 준비합니다.&lt;/li&gt;
&lt;li&gt;중요 배치 작업은 FDW가 아닌 직접 적재 방식으로 분리합니다.&lt;/li&gt;
&lt;li&gt;연결 빈도 및 실패율을 지속적으로 모니터링합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;section&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;마무리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PostgreSQL Foreign Data Wrapper는 단순한 외부 테이블 기능을 넘어 이종 데이터베이스를 유연하게 통합할 수 있는 강력한 도구입니다. 특히 Oracle 중심의 기존 환경에서 PostgreSQL로 점진적 전환을 고려하는 경우, FDW는 매우 현실적인 연결 해법이 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만 FDW는 만능이 아니며 성능, 보안, 장애 전파 측면을 충분히 고려한 설계가 필요합니다. 실시간 조회는 FDW로, 대량 처리와 핵심 리포트는 별도 적재 구조로 분리하는 전략이 장기적으로 안정적인 운영을 가능하게 합니다&lt;/p&gt;
&lt;/section&gt;
&lt;/article&gt;
&lt;div&gt;
&lt;style&gt;
.post-fdw { line-height: 1.8; color: #111; font-size: 15px; }
.post-fdw h1 { font-size: 2.1rem; margin-bottom: 0.8rem; }
.post-fdw h2 { font-size: 1.45rem; margin-top: 2.4rem; }
.post-fdw pre { background: #0b1020; color: #e8eeff; padding: 16px; border-radius: 14px; overflow-x: auto; }
.post-fdw code { font-family: Consolas, monospace; }
.post-fdw .lead { background: rgba(0,0,0,0.04); padding: 16px; border-radius: 14px; }
.post-fdw ul { margin-left: 20px; }
.post-fdw .box { padding: 14px 16px; border-radius: 14px; margin: 18px 0; }
.post-fdw .info { background: rgba(0, 123, 255, 0.08); }
.post-fdw .warn { background: rgba(255, 193, 7, 0.15); }
&lt;/style&gt;
&lt;/div&gt;</description>
      <category>DEVELOPMENT</category>
      <category>DBLink</category>
      <category>FDW</category>
      <category>MYSQL</category>
      <category>ODBC</category>
      <category>Oracle</category>
      <category>oracle_fdw</category>
      <category>PostgreSQL</category>
      <category>PostgreSQL15</category>
      <category>postgres_fdw</category>
      <category>SQLServer</category>
      <author>간지뽕빨리턴님</author>
      <guid isPermaLink="true">https://odinbox.tistory.com/568</guid>
      <comments>https://odinbox.tistory.com/568#entry568comment</comments>
      <pubDate>Sun, 18 Jan 2026 00:37:51 +0900</pubDate>
    </item>
    <item>
      <title>PostgreSQL과 Python의 만남, PL/Python 활용부터 pg_cron 스케줄링까지</title>
      <link>https://odinbox.tistory.com/567</link>
      <description>&lt;div&gt;
&lt;style&gt;
    :root {
        --postgrespy_primary: #336791;
        --postgrespy_secondary: #ffd35c;
        --postgrespy_text: #333333;
        --postgrespy_bg: #ffffff;
        --postgrespy_code_bg: #282c34;
        --postgrespy_code_text: #abb2bf;
        --postgrespy_border: #e1e4e8;
        --postgrespy_accent: #d32f2f;
    }

    .postgrespy_container {
        font-family: -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, Roboto, &quot;Helvetica Neue&quot;, Arial, sans-serif;
        line-height: 1.8;
        color: var(--postgrespy_text);
        max-width: 900px;
        margin: 0 auto;
        padding: 40px 20px;
        background-color: var(--postgrespy_bg);
        overflow-x: hidden;
    }

    .postgrespy_thumbnail {
        text-align: center;
        margin-bottom: 40px;
    }

    .postgrespy_title {
        font-size: 2.5rem;
        font-weight: 800;
        color: #1a1a1a;
        margin-bottom: 10px;
        letter-spacing: -0.05rem;
    }

    .postgrespy_subtitle {
        font-size: 1.1rem;
        color: #666;
        margin-bottom: 50px;
        border-bottom: 2px solid var(--postgrespy_border);
        padding-bottom: 20px;
    }

    .postgrespy_h2 {
        font-size: 1.8rem;
        font-weight: 700;
        color: var(--postgrespy_primary);
        margin-top: 60px;
        margin-bottom: 20px;
        display: flex;
        align-items: center;
    }

    .postgrespy_h2::before {
        content: '';
        display: block;
        width: 8px;
        height: 30px;
        background-color: var(--postgrespy_secondary);
        margin-right: 15px;
        border-radius: 4px;
    }

    .postgrespy_h3 {
        font-size: 1.4rem;
        font-weight: 600;
        margin-top: 40px;
        margin-bottom: 15px;
        color: #2c3e50;
    }

    .postgrespy_p {
        margin-bottom: 20px;
        font-size: 1.05rem;
        word-break: keep-all;
    }

    .postgrespy_code_wrapper {
        position: relative;
        margin: 30px 0;
        border-radius: 8px;
        overflow: hidden;
        box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
        transition: transform 0.3s ease;
    }

    .postgrespy_code_wrapper:hover {
        transform: translateY(-5px);
    }

    .postgrespy_code_header {
        background-color: #21252b;
        color: #fff;
        padding: 8px 15px;
        font-size: 0.85rem;
        font-family: monospace;
        border-bottom: 1px solid #3e4451;
        display: flex;
        justify-content: space-between;
    }

    .postgrespy_code_block {
        background-color: var(--postgrespy_code_bg);
        color: var(--postgrespy_code_text);
        padding: 20px;
        overflow-x: auto;
        font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
        font-size: 0.95rem;
        line-height: 1.6;
        margin: 0;
    }

    .postgrespy_keyword { color: #c678dd; }
    .postgrespy_function { color: #61afef; }
    .postgrespy_string { color: #98c379; }
    .postgrespy_comment { color: #5c6370; font-style: italic; }

    .postgrespy_info_box {
        background-color: #f1f8ff;
        border-left: 5px solid var(--postgrespy_primary);
        padding: 20px;
        margin: 30px 0;
        border-radius: 0 8px 8px 0;
    }

    .postgrespy_warning_box {
        background-color: #fff5f5;
        border-left: 5px solid var(--postgrespy_accent);
        padding: 20px;
        margin: 30px 0;
        border-radius: 0 8px 8px 0;
    }

    .postgrespy_box_title {
        display: block;
        font-weight: 700;
        margin-bottom: 10px;
        font-size: 1.1rem;
    }

    .postgrespy_fade_in {
        opacity: 0;
        transform: translateY(20px);
        transition: opacity 0.8s ease-out, transform 0.8s ease-out;
    }

    .postgrespy_visible {
        opacity: 1;
        transform: translateY(0);
    }

    .postgrespy_list {
        margin-left: 20px;
        margin-bottom: 20px;
    }
    .postgrespy_list li {
        margin-bottom: 10px;
    }

    @media (max-width: 768px) {
        .postgrespy_title { font-size: 2rem; }
        .postgrespy_h2 { font-size: 1.5rem; }
        .postgrespy_code_block { font-size: 0.85rem; }
    }
&lt;/style&gt;
&lt;/div&gt;
&lt;div class=&quot;postgrespy_container&quot;&gt;
&lt;div class=&quot;postgrespy_thumbnail&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;글 상단 부분 대표 이미지.png&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dtTMVG/dJMcac9BOPQ/VA9D833Jo3iMNjs0x7GFYk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dtTMVG/dJMcac9BOPQ/VA9D833Jo3iMNjs0x7GFYk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dtTMVG/dJMcac9BOPQ/VA9D833Jo3iMNjs0x7GFYk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdtTMVG%2FdJMcac9BOPQ%2FVA9D833Jo3iMNjs0x7GFYk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;400&quot; data-filename=&quot;글 상단 부분 대표 이미지.png&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;header&gt;
&lt;p class=&quot;postgrespy_subtitle&quot; data-ke-size=&quot;size16&quot;&gt;단순한 SMTP 전송을 넘어, 데이터 분석부터 오라클 DB Job 대체까지&lt;/p&gt;
&lt;/header&gt;
&lt;section class=&quot;postgrespy_fade_in&quot;&gt;
&lt;p class=&quot;postgrespy_p&quot; data-ke-size=&quot;size16&quot;&gt;이전 포스팅(&lt;a style=&quot;color: var(--postgrespy_primary); text-decoration: underline;&quot; href=&quot;https://odinbox.co.kr/562&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://odinbox.co.kr/562&lt;/a&gt;)에서 우리는 PostgreSQL에서 Python을 연동하여 SMTP 메일을 발송하는 방법을 다루었습니다. 하지만 이것은 PL/Python이 가진 잠재력의 극히 일부에 불과합니다.&lt;/p&gt;
&lt;br /&gt;
&lt;p class=&quot;postgrespy_p&quot; data-ke-size=&quot;size16&quot;&gt;많은 분이 &quot;Python으로 만든 함수의 결과값을 SQL 쿼리 내에서 바로 사용할 수 있는가?&quot;, &quot;외부 API와 통신하여 데이터를 가져와 DB에 넣을 수 있는가?&quot;, 그리고 &quot;오라클의 DB Job처럼 스케줄링이 가능한가?&quot;에 대해 궁금합니다.&lt;/p&gt;
&lt;br /&gt;
&lt;p class=&quot;postgrespy_p&quot; data-ke-size=&quot;size16&quot;&gt;이번 글에서는 PostgreSQL의 확장 기능인 &lt;b&gt;PL/Python&lt;/b&gt;을 활용하여 Python의 방대한 라이브러리 생태계를 DB 내부로 가져오는 방법과, &lt;b&gt;pg_cron&lt;/b&gt;을 이용해 Python 프로시저를 주기적으로 실행하는 스케줄링 구현 방법까지, &lt;b&gt;OdinBOX&lt;/b&gt; 예제 코드를 통해 상세하게 정리해 드립니다.&lt;/p&gt;
&lt;/section&gt;
&lt;section class=&quot;postgrespy_fade_in&quot;&gt;
&lt;h2 class=&quot;postgrespy_h2&quot; data-ke-size=&quot;size26&quot;&gt;1. PL/Python의 이해와 설정 (Trusted vs Untrusted)&lt;/h2&gt;
&lt;p class=&quot;postgrespy_p&quot; data-ke-size=&quot;size16&quot;&gt;PostgreSQL에서 Python을 사용하려면 &lt;code&gt;plpython3u&lt;/code&gt; 확장을 설치해야 합니다. 여기서 뒤에 붙은 'u'는 &lt;b&gt;Untrusted(신뢰할 수 없음)&lt;/b&gt;를 의미합니다. 이는 보안상의 이유로 붙은 이름이지만, 역설적으로 '제약이 없다'는 뜻이기도 합니다.&lt;/p&gt;
&lt;div class=&quot;postgrespy_info_box&quot;&gt;&lt;span style=&quot;color: var(--postgrespy_primary);&quot; class=&quot;postgrespy_box_title&quot;&gt;Trusted vs Untrusted 차이점&lt;/span&gt;
&lt;ul class=&quot;postgrespy_list&quot; style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Trusted (plpgSQL 등) :&lt;/b&gt; DB 내부 데이터만 건드릴 수 있으며, 파일 시스템이나 네트워크 접근이 차단됩니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Untrusted (plpython3u) :&lt;/b&gt; Python이 할 수 있는 모든 것을 할 수 있습니다. OS 파일 읽기/쓰기, 소켓 통신, 외부 API 요청 등이 가능합니다. 즉, &lt;b&gt;슈퍼유저 권한&lt;/b&gt;이 필요합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;p class=&quot;postgrespy_p&quot; data-ke-size=&quot;size16&quot;&gt;먼저 해당 기능을 활성화합니다.&lt;/p&gt;
&lt;div class=&quot;postgrespy_code_wrapper&quot;&gt;
&lt;div class=&quot;postgrespy_code_header&quot;&gt;SQL Command&lt;/div&gt;
&lt;pre class=&quot;postgrespy_code_block n1ql&quot;&gt;&lt;code&gt;CREATE EXTENSION plpython3u;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section class=&quot;postgrespy_fade_in&quot;&gt;
&lt;h2 class=&quot;postgrespy_h2&quot; data-ke-size=&quot;size26&quot;&gt;2. Python 함수 제작 및 결과값 활용&lt;/h2&gt;
&lt;p class=&quot;postgrespy_p&quot; data-ke-size=&quot;size16&quot;&gt;Python으로 로직을 짜고 그 결과값을 SQL 문에서 `SELECT` 하거나 `WHERE` 절 조건으로 즉시 사용할 수 있습니다. 복잡한 텍스트 처리나 정규식 연산은 SQL보다 Python이 훨씬 강력하고 간결합니다.&lt;/p&gt;
&lt;h3 class=&quot;postgrespy_h3&quot; data-ke-size=&quot;size23&quot;&gt;예제 1, OdinBOX 텍스트 분석기&lt;/h3&gt;
&lt;p class=&quot;postgrespy_p&quot; data-ke-size=&quot;size16&quot;&gt;입력받은 텍스트에서 키워드를 추출하여 JSON 형태로 반환하는 함수를 만들어 보겠습니다.&lt;/p&gt;
&lt;div class=&quot;postgrespy_code_wrapper&quot;&gt;
&lt;div class=&quot;postgrespy_code_header&quot;&gt;PostgreSQL Function (PL/Python)&lt;/div&gt;
&lt;pre class=&quot;postgrespy_code_block pgsql&quot;&gt;&lt;code&gt;CREATE OR REPLACE FUNCTION odinbox_analyze_text(input_text text)
RETURNS json
AS $$
    import json
    import re

    words = re.findall(r'\w+', input_text.lower())
    word_count = {}
    
    for word in words:
        if word in word_count:
            word_count[word] += 1
        else:
            word_count[word] = 1
            
    result = {
        &quot;status&quot;: &quot;success&quot;,
        &quot;analyzer&quot;: &quot;OdinBOX_v1&quot;,
        &quot;total_words&quot;: len(words),
        &quot;data&quot;: word_count
    }
    
    return json.dumps(result)
$$ LANGUAGE plpython3u;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p class=&quot;postgrespy_p&quot; data-ke-size=&quot;size16&quot;&gt;이제 이 함수를 일반 SQL처럼 조회할 수 있습니다.&lt;/p&gt;
&lt;div class=&quot;postgrespy_code_wrapper&quot;&gt;
&lt;div class=&quot;postgrespy_code_header&quot;&gt;Usage Example&lt;/div&gt;
&lt;pre class=&quot;postgrespy_code_block reasonml&quot;&gt;&lt;code&gt;SELECT odinbox_analyze_text('OdinBOX is great. OdinBOX uses Postgres.');&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section class=&quot;postgrespy_fade_in&quot;&gt;
&lt;h2 class=&quot;postgrespy_h2&quot; data-ke-size=&quot;size26&quot;&gt;3. 외부 라이브러리 활용 : DB에서 직접 웹 크롤링하기&lt;/h2&gt;
&lt;p class=&quot;postgrespy_p&quot; data-ke-size=&quot;size16&quot;&gt;DB 서버에 &lt;code&gt;requests&lt;/code&gt;나 &lt;code&gt;pandas&lt;/code&gt; 라이브러리가 설치되어 있다면(&lt;code&gt;pip install requests&lt;/code&gt;), DB 함수 내에서 이를 import하여 외부 데이터를 실시간으로 가져올 수 있습니다. 이는 ETL 도구 없이도 외부 데이터를 적재할 수 있음을 의미합니다.&lt;/p&gt;
&lt;div class=&quot;postgrespy_code_wrapper&quot;&gt;
&lt;div class=&quot;postgrespy_code_header&quot;&gt;OdinBOX External Data Fetcher&lt;/div&gt;
&lt;pre class=&quot;postgrespy_code_block sql&quot;&gt;&lt;code&gt;CREATE OR REPLACE FUNCTION odinbox_fetch_currency(currency_code text)
RETURNS numeric
AS $$
    import requests
    
    try:
        url = f&quot;https://api.exchangerate-api.com/v4/latest/{currency_code}&quot;
        response = requests.get(url, timeout=5)
        
        if response.status_code == 200:
            data = response.json()
            return data['rates'].get('KRW', 0)
        else:
            plpy.warning(f&quot;OdinBOX API Error: {response.status_code}&quot;)
            return -1
    except Exception as e:
        plpy.error(f&quot;Network Error: {e}&quot;)
$$ LANGUAGE plpython3u;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section class=&quot;postgrespy_fade_in&quot;&gt;
&lt;h2 class=&quot;postgrespy_h2&quot; data-ke-size=&quot;size26&quot;&gt;4. 오라클 DB Job 대체하기 : pg_cron과 Python의 만남&lt;/h2&gt;
&lt;p class=&quot;postgrespy_p&quot; data-ke-size=&quot;size16&quot;&gt;오라클에는 &lt;code&gt;DBMS_SCHEDULER&lt;/code&gt;나 &lt;code&gt;DBMS_JOB&lt;/code&gt;이 내장되어 있습니다. PostgreSQL은 기본적으로는 스케줄러가 없지만, 표준처럼 사용되는 확장 기능인 &lt;b&gt;pg_cron&lt;/b&gt;을 통해 동일한 기능을 수행할 수 있습니다.&lt;/p&gt;
&lt;p class=&quot;postgrespy_p&quot; data-ke-size=&quot;size16&quot;&gt;이 조합이 강력한 이유는, &lt;b&gt;&quot;Python으로 복잡한 로직을 짜고, pg_cron으로 스케줄링&quot;&lt;/b&gt;할 수 있기 때문입니다.&lt;/p&gt;
&lt;h3 class=&quot;postgrespy_h3&quot; data-ke-size=&quot;size23&quot;&gt;Step 1. pg_cron 설치 및 설정&lt;/h3&gt;
&lt;p class=&quot;postgrespy_p&quot; data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;postgresql.conf&lt;/code&gt; 파일의 &lt;code&gt;shared_preload_libraries&lt;/code&gt;에 &lt;code&gt;pg_cron&lt;/code&gt;을 추가하고 DB를 재시작해야 합니다.&lt;/p&gt;
&lt;div class=&quot;postgrespy_code_wrapper&quot;&gt;
&lt;pre class=&quot;postgrespy_code_block pgsql&quot;&gt;&lt;code&gt;CREATE EXTENSION pg_cron;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h3 class=&quot;postgrespy_h3&quot; data-ke-size=&quot;size23&quot;&gt;Step 2. Python 프로시저 스케줄링 등록&lt;/h3&gt;
&lt;p class=&quot;postgrespy_p&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어, 매일 오전 9시에 위에서 만든 &lt;code&gt;odinbox_fetch_currency&lt;/code&gt; 함수를 실행하여 환율 테이블에 저장하는 작업을 등록해 보겠습니다.&lt;/p&gt;
&lt;div class=&quot;postgrespy_code_wrapper&quot;&gt;
&lt;div class=&quot;postgrespy_code_header&quot;&gt;Schedule Registration&lt;/div&gt;
&lt;pre class=&quot;postgrespy_code_block sql&quot;&gt;&lt;code&gt;CREATE TABLE odinbox_currency_log (
    log_time TIMESTAMP DEFAULT now(),
    usd_rate NUMERIC
);

CREATE OR REPLACE PROCEDURE odinbox_daily_job()
LANGUAGE sql
AS $$
    INSERT INTO odinbox_currency_log (usd_rate)
    SELECT odinbox_fetch_currency('USD');
$$;

SELECT cron.schedule('odinbox_exchange_job', '0 9 * * *', 'CALL odinbox_daily_job()');&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div class=&quot;postgrespy_warning_box&quot;&gt;&lt;span style=&quot;color: var(--postgrespy_accent);&quot; class=&quot;postgrespy_box_title&quot;&gt;주의사항&lt;/span&gt;
&lt;p class=&quot;postgrespy_p&quot; data-ke-size=&quot;size16&quot;&gt;pg_cron은 기본적으로 GMT 기준입니다. 한국 시간(KST)으로 9시에 실행하려면 시간을 -9시간 하여 &lt;code&gt;0 0 * * *&lt;/code&gt;(자정)으로 설정하거나, &lt;code&gt;cron.timezone&lt;/code&gt; 설정을 확인해야 합니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section class=&quot;postgrespy_fade_in&quot;&gt;
&lt;h2 class=&quot;postgrespy_h2&quot; data-ke-size=&quot;size26&quot;&gt;마무리&lt;/h2&gt;
&lt;p class=&quot;postgrespy_p&quot; data-ke-size=&quot;size16&quot;&gt;PostgreSQL의 PL/Python은 단순히 DB 안에서 스크립트를 돌리는 수준을 넘어, 데이터베이스를 &lt;b&gt;지능형 데이터 허브&lt;/b&gt;로 만들어줍니다. Python의 강력한 라이브러리(Pandas, Scikit-learn, Requests 등)를 데이터가 저장된 곳에서 바로 실행함으로써 이동 비용을 줄이고 효율을 극대화할 수 있습니다.&lt;/p&gt;
&lt;p class=&quot;postgrespy_p&quot; data-ke-size=&quot;size16&quot;&gt;또한 &lt;code&gt;pg_cron&lt;/code&gt;과 결합하면 오라클의 DB Job 부럽지 않은 강력한 스케줄링 환경을 구축할 수 있습니다. 오늘 소개한 &lt;b&gt;OdinBOX&lt;/b&gt; 예제들을 응용하여 여러분만의 자동화 시스템을 구축해 보시기 바랍니다.&lt;/p&gt;
&lt;/section&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;
&lt;script&gt;
    document.addEventListener(&quot;DOMContentLoaded&quot;, function() {
        const observerOptions = {
            root: null,
            rootMargin: '0px',
            threshold: 0.1
        };

        const observer = new IntersectionObserver((entries, observer) =&gt; {
            entries.forEach(entry =&gt; {
                if (entry.isIntersecting) {
                    entry.target.classList.add('postgrespy_visible');
                    observer.unobserve(entry.target);
                }
            });
        }, observerOptions);

        const fadeElements = document.querySelectorAll('.postgrespy_fade_in');
        fadeElements.forEach(el =&gt; observer.observe(el));
    });
&lt;/script&gt;
&lt;/p&gt;</description>
      <category>DEVELOPMENT</category>
      <category>DBJOB</category>
      <category>DB튜닝</category>
      <category>pg_cron</category>
      <category>PLPython</category>
      <category>PostgreSQL</category>
      <category>python</category>
      <category>SQL파이썬함수</category>
      <category>데이터베이스</category>
      <category>백엔드</category>
      <category>자동화</category>
      <author>간지뽕빨리턴님</author>
      <guid isPermaLink="true">https://odinbox.tistory.com/567</guid>
      <comments>https://odinbox.tistory.com/567#entry567comment</comments>
      <pubDate>Sun, 11 Jan 2026 11:00:00 +0900</pubDate>
    </item>
    <item>
      <title>AI 에이전트(AI Agent)를 활용한 업무 자동화 및 멀티 에이전트 기반 코드 최적화 전략</title>
      <link>https://odinbox.tistory.com/566</link>
      <description>&lt;div&gt;
&lt;style&gt;
        /* [CSS] 모든 클래스 및 아이디에 aiagentodin_ 접두사 적용 */
        .aiagentodin_container {
            line-height: 1.9;
            color: #1a1a1a;
            max-width: 1000px;
            margin: 0 auto;
            padding: 40px 20px;
            font-family: 'Pretendard', -apple-system, sans-serif;
            background-color: #ffffff;
        }
        #aiagentodin_title_box {
            border-bottom: 4px solid #0056b3;
            padding-bottom: 20px;
            margin-bottom: 50px;
        }
        .aiagentodin_main_h1 {
            font-size: 2.5rem;
            color: #003366;
            margin: 0;
            word-break: keep-all;
        }
        .aiagentodin_section_h2 {
            font-size: 1.8rem;
            color: #004085;
            background-color: #f8f9fa;
            padding: 15px 20px;
            border-left: 10px solid #007bff;
            margin-top: 60px;
            margin-bottom: 25px;
        }
        .aiagentodin_section_h3 {
            font-size: 1.4rem;
            color: #10ac84;
            margin-top: 35px;
            padding-bottom: 5px;
            border-bottom: 1px solid #eee;
        }
        .aiagentodin_paragraph {
            margin-bottom: 20px;
            text-align: justify;
        }
        .aiagentodin_info_panel {
            background-color: #e9ecef;
            border-radius: 8px;
            padding: 25px;
            margin: 30px 0;
            border-left: 5px solid #6c757d;
        }
        /* [코드 블록 스타일 개선] 고대비 색상 적용 */
        .aiagentodin_code_area {
            position: relative;
            background-color: #1e1e1e; /* VS Code Dark 스타일 */
            border-radius: 10px;
            margin: 25px 0;
            box-shadow: 0 4px 12px rgba(0,0,0,0.3);
        }
        .aiagentodin_code_toolbar {
            display: flex;
            justify-content: space-between;
            align-items: center;
            padding: 10px 20px;
            background-color: #333333;
            border-radius: 10px 10px 0 0;
            color: #ffffff;
            font-size: 0.85rem;
        }
        .aiagentodin_copy_button {
            background-color: #007bff;
            color: white;
            border: none;
            padding: 5px 15px;
            border-radius: 4px;
            cursor: pointer;
            font-weight: bold;
            transition: background 0.2s;
        }
        .aiagentodin_copy_button:hover {
            background-color: #0056b3;
        }
        .aiagentodin_pre_tag {
            margin: 0;
            padding: 20px;
            overflow-x: auto;
            color: #d4d4d4;
            font-family: 'Fira Code', 'Consolas', monospace;
            font-size: 0.95rem;
            line-height: 1.5;
        }
        /* 코드 구문 강조 색상 */
        .aiagentodin_code_keyword { color: #569cd6; } /* 파란색 */
        .aiagentodin_code_string { color: #ce9178; }  /* 주황색 */
        .aiagentodin_code_comment { color: #6a9955; } /* 초록색 */
        .aiagentodin_code_func { color: #dcdcaa; }    /* 연노랑 */
        .aiagentodin_code_var { color: #9cdcfe; }     /* 하늘색 */

        .aiagentodin_list {
            margin-bottom: 25px;
            padding-left: 20px;
        }
        .aiagentodin_list_item {
            margin-bottom: 12px;
        }
        .aiagentodin_bold {
            font-weight: bold;
            color: #d63031;
        }
        .aiagentodin_footer_tags {
            margin-top: 80px;
            padding: 30px;
            background-color: #f1f2f6;
            border-radius: 10px;
        }
    &lt;/style&gt;
&lt;/div&gt;
&lt;div class=&quot;aiagentodin_container&quot;&gt;&lt;header id=&quot;aiagentodin_title_box&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;글 상단 부분 대표 이미지 (4).png&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cofej3/dJMcaa41hyp/sCKKfnx0EAPwX2y3wIrFT0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cofej3/dJMcaa41hyp/sCKKfnx0EAPwX2y3wIrFT0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cofej3/dJMcaa41hyp/sCKKfnx0EAPwX2y3wIrFT0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcofej3%2FdJMcaa41hyp%2FsCKKfnx0EAPwX2y3wIrFT0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;400&quot; data-filename=&quot;글 상단 부분 대표 이미지 (4).png&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p class=&quot;aiagentodin_main_h1&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;text-align: justify; color: #1a1a1a; font-size: 16px; letter-spacing: 0px;&quot;&gt;인공지능 기술이 단순한 생성형 언어 모델(LLM)을 넘어, 스스로 사고하고 행동하는 &lt;/span&gt;&lt;b&gt;AI 에이전트(AI Agent)&lt;/b&gt;&lt;span style=&quot;text-align: justify; color: #1a1a1a; font-size: 16px; letter-spacing: 0px;&quot;&gt; 시대로 완벽하게 진입했습니다. 2026년 현재, 에이전틱 워크플로우(Agentic Workflow)는 기업의 생산성을 결정짓는 핵심 요소가 되었습니다. 단순한 질의응답을 넘어 사용자의 목표를 달성하기 위해 계획을 수립하고, 도구를 선택하며, 결과물을 비판적으로 검토하는 자율성이 에이전트의 핵심입니다.&lt;/span&gt;&lt;/p&gt;
&lt;section&gt;
&lt;p class=&quot;aiagentodin_paragraph&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;aiagentodin_paragraph&quot; data-ke-size=&quot;size16&quot;&gt;AI 에이전트의 정의와 작동 원리를 사실에 근거하여 상세히 분석하고, 특히 개발 분야에서 각기 다른 역할을 부여받은 멀티 에이전트들이 어떻게 협업하여 최적의 소스코드를 도출하는지 그 프로세스를 구체적으로 다룹니다. 또한 OpenAI와 Google Gemini를 활용한 실전 구현 방법까지 적었습니다.&lt;/p&gt;
&lt;/section&gt;
&lt;h2 class=&quot;aiagentodin_section_h2&quot; data-ke-size=&quot;size26&quot;&gt;1. AI 에이전트의 논리적 아키텍처와 작동 원리&lt;/h2&gt;
&lt;p class=&quot;aiagentodin_paragraph&quot; data-ke-size=&quot;size16&quot;&gt;AI 에이전트는 거대언어모델(LLM)을 '두뇌'로 삼고, 외부 환경과 상호작용할 수 있는 '도구'와 '메모리'를 결합한 시스템입니다. 학술적으로 에이전트의 자율성은 다음과 같은 4단계 루프에 의해 구현됩니다.&lt;/p&gt;
&lt;div class=&quot;aiagentodin_info_panel&quot;&gt;
&lt;ul class=&quot;aiagentodin_list&quot; style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li class=&quot;aiagentodin_list_item&quot;&gt;&lt;span class=&quot;aiagentodin_bold&quot;&gt;인지(Perception) :&lt;/span&gt; 사용자의 요청과 현재 환경 데이터(파일, 웹 검색 결과 등)를 받아들입니다.&lt;/li&gt;
&lt;li class=&quot;aiagentodin_list_item&quot;&gt;&lt;span class=&quot;aiagentodin_bold&quot;&gt;계획(Planning) :&lt;/span&gt; 목표를 달성하기 위해 필요한 일련의 작업 순서를 논리적으로 분해합니다. (예 : Chain of Thought 기법 활용)&lt;/li&gt;
&lt;li class=&quot;aiagentodin_list_item&quot;&gt;&lt;span class=&quot;aiagentodin_bold&quot;&gt;추론(Reasoning) :&lt;/span&gt; 각 단계에서 어떤 도구(API, 계산기, 코드 실행기)를 사용할지 결정합니다.&lt;/li&gt;
&lt;li class=&quot;aiagentodin_list_item&quot;&gt;&lt;span class=&quot;aiagentodin_bold&quot;&gt;실행 및 성찰(Action &amp;amp; Reflection) :&lt;/span&gt; 도구를 실행한 뒤 그 결과를 관찰하고, 목표에 부합하지 않으면 계획을 수정하여 다시 시도합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;h2 class=&quot;aiagentodin_section_h2&quot; data-ke-size=&quot;size26&quot;&gt;2. 멀티 에이전트를 활용한 코드 제작 및 최적화 방법&lt;/h2&gt;
&lt;p class=&quot;aiagentodin_paragraph&quot; data-ke-size=&quot;size16&quot;&gt;하나의 AI가 모든 코드를 짜는 것보다, 역할이 분산된 여러 에이전트가 상호 검토하는 방식이 코드 품질(신뢰성, 보안성, 효율성) 면에서 압도적으로 우수합니다. 이를 &lt;b&gt;멀티 에이전트 협업 시스템&lt;/b&gt;이라고 합니다.&lt;/p&gt;
&lt;h3 class=&quot;aiagentodin_section_h3&quot; data-ke-size=&quot;size23&quot;&gt;역할 분담 예시 : 코드 최적화 파이프라인&lt;/h3&gt;
&lt;ul class=&quot;aiagentodin_list&quot; style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li class=&quot;aiagentodin_list_item&quot;&gt;&lt;span class=&quot;aiagentodin_bold&quot;&gt;Planner Agent :&lt;/span&gt; 전체적인 아키텍처를 설계하고 필요한 라이브러리와 데이터 구조를 정의합니다.&lt;/li&gt;
&lt;li class=&quot;aiagentodin_list_item&quot;&gt;&lt;span class=&quot;aiagentodin_bold&quot;&gt;Developer Agent :&lt;/span&gt; 설계에 따라 실제 구현 코드를 작성합니다.&lt;/li&gt;
&lt;li class=&quot;aiagentodin_list_item&quot;&gt;&lt;span class=&quot;aiagentodin_bold&quot;&gt;Code Auditor Agent :&lt;/span&gt; 작성된 코드를 비판적으로 검토합니다. 메모리 누수, 시간 복잡도, 보안 취약점을 찾아냅니다.&lt;/li&gt;
&lt;li class=&quot;aiagentodin_list_item&quot;&gt;&lt;span class=&quot;aiagentodin_bold&quot;&gt;Test Engineer Agent :&lt;/span&gt; 단위 테스트 코드를 작성하고 실행하여 예상치 못한 버그를 탐지합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;aiagentodin_paragraph&quot; data-ke-size=&quot;size16&quot;&gt;이들은 서로 메시지를 주고받으며 피드백 루프를 돕니다. 예시 : Auditor가 수정을 요청하면 Developer가 다시 코드를 작성하는 과정을 &quot;최적의 소스코드&quot;가 나올 때까지 반복합니다.&lt;/p&gt;
&lt;h2 class=&quot;aiagentodin_section_h2&quot; data-ke-size=&quot;size26&quot;&gt;3. 에이전트 구현을 위한 환경 설정&lt;/h2&gt;
&lt;p class=&quot;aiagentodin_paragraph&quot; data-ke-size=&quot;size16&quot;&gt;AI 에이전트를 구축하기 위해서는 Python 환경과 주요 라이브러리 설치가 필요합니다. 본 가이드는 2026년 표준인 LangChain(v0.4+)과 CrewAI를 기준으로 설명합니다.&lt;/p&gt;
&lt;div class=&quot;aiagentodin_code_area&quot;&gt;
&lt;div class=&quot;aiagentodin_code_toolbar&quot;&gt;&lt;span&gt;Terminal - Dependencies&lt;/span&gt; &lt;button class=&quot;aiagentodin_copy_button&quot;&gt;복사하기&lt;/button&gt;&lt;/div&gt;
&lt;pre id=&quot;aiagentodin_sh_1&quot; class=&quot;aiagentodin_pre_tag cmake&quot;&gt;&lt;code&gt;# 필수 라이브러리 설치
pip install langchain-openai langchain-google-genai crewai python-dotenv&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h2 class=&quot;aiagentodin_section_h2&quot; data-ke-size=&quot;size26&quot;&gt;4. OpenAI 기반 AI 에이전트 구현 방법&lt;/h2&gt;
&lt;p class=&quot;aiagentodin_paragraph&quot; data-ke-size=&quot;size16&quot;&gt;OpenAI의 모델(GPT-4o 등)은 추론 능력이 뛰어나 에이전트의 두뇌로 적합합니다.&lt;/p&gt;
&lt;div class=&quot;aiagentodin_code_area&quot;&gt;
&lt;div class=&quot;aiagentodin_code_toolbar&quot;&gt;&lt;span&gt;Python - OpenAI Agent&lt;/span&gt; &lt;button class=&quot;aiagentodin_copy_button&quot;&gt;복사하기&lt;/button&gt;&lt;/div&gt;
&lt;pre id=&quot;aiagentodin_py_1&quot; class=&quot;aiagentodin_pre_tag routeros&quot;&gt;&lt;code&gt;import os
from langchain_openai import ChatOpenAI
from crewai import Agent, Task, Crew

# API 키 설정
os.environ[&quot;OPENAI_API_KEY&quot;] = &quot;YOUR_OPENAI_API_KEY&quot;

# OpenAI 기반 에이전트 정의
aiagentodin_openai_llm = ChatOpenAI(model=&quot;gpt-4o&quot;, temperature=0.2)

aiagentodin_coder = Agent(
    role='Senior Python Developer',
    goal='효율적이고 읽기 쉬운 파이썬 코드 작성',
    backstory='당신은 20년 경력의 베테랑 개발자입니다.',
    llm=aiagentodin_openai_llm
)

# 작업 수행
aiagentodin_task = Task(description='정렬 알고리즘 최적화 코드 작성', agent=aiagentodin_coder)
aiagentodin_crew = Crew(agents=[aiagentodin_coder], tasks=[aiagentodin_task])
print(aiagentodin_crew.kickoff())&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h2 class=&quot;aiagentodin_section_h2&quot; data-ke-size=&quot;size26&quot;&gt;5. Google Gemini 기반 AI 에이전트 구현 방법&lt;/h2&gt;
&lt;p class=&quot;aiagentodin_paragraph&quot; data-ke-size=&quot;size16&quot;&gt;Gemini 모델은 방대한 컨텍스트 창과 빠른 처리 속도를 자랑합니다. 멀티모달 능력이 필요한 에이전트에 유리합니다.&lt;/p&gt;
&lt;div class=&quot;aiagentodin_code_area&quot;&gt;
&lt;div class=&quot;aiagentodin_code_toolbar&quot;&gt;&lt;span&gt;Python - Gemini Agent&lt;/span&gt; &lt;button class=&quot;aiagentodin_copy_button&quot;&gt;복사하기&lt;/button&gt;&lt;/div&gt;
&lt;pre id=&quot;aiagentodin_py_2&quot; class=&quot;aiagentodin_pre_tag routeros&quot;&gt;&lt;code&gt;from langchain_google_genai import ChatGoogleGenerativeAI

# Gemini API 키 설정
os.environ[&quot;GOOGLE_API_KEY&quot;] = &quot;YOUR_GEMINI_API_KEY&quot;

# Gemini 기반 에이전트 두뇌 설정
aiagentodin_gemini_llm = ChatGoogleGenerativeAI(
    model=&quot;gemini-1.5-pro&quot;, 
    temperature=0.3,
    convert_system_message_to_human=True
)

aiagentodin_reviewer = Agent(
    role='Code Review Specialist',
    goal='코드의 보안 취약점을 정밀 분석',
    backstory='당신은 글로벌 보안 기업의 화이트해커 출신 리뷰어입니다.',
    llm=aiagentodin_gemini_llm
)

# 이후 Crew 및 Task 구성은 위와 동일하게 연동 가능&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h2 class=&quot;aiagentodin_section_h2&quot; data-ke-size=&quot;size26&quot;&gt;6. AI 에이전트 업무 자동화 구축 프로세스&lt;/h2&gt;
&lt;p class=&quot;aiagentodin_paragraph&quot; data-ke-size=&quot;size16&quot;&gt;에이전트를 통해 업무를 자동화하려면 다음 단계를 준수해야 성공률이 높습니다.&lt;/p&gt;
&lt;ul class=&quot;aiagentodin_list&quot; style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li class=&quot;aiagentodin_list_item&quot;&gt;&lt;span class=&quot;aiagentodin_bold&quot;&gt;단계 1 : 워크플로우 분석 :&lt;/span&gt; 자동화할 업무의 입력을 정의합니다. 예시 : &quot;매일 아침 9시 뉴스 리서치 및 보고서 이메일 발송&quot;.&lt;/li&gt;
&lt;li class=&quot;aiagentodin_list_item&quot;&gt;&lt;span class=&quot;aiagentodin_bold&quot;&gt;단계 2 : 도구(Tools) 바인딩 :&lt;/span&gt; 에이전트가 사용할 도구를 정의합니다. 예시 : SerpApi(검색), Gmail API(메일), Pandas(데이터 분석).&lt;/li&gt;
&lt;li class=&quot;aiagentodin_list_item&quot;&gt;&lt;span class=&quot;aiagentodin_bold&quot;&gt;단계 3 : 에이전트 페르소나 설정 :&lt;/span&gt; 에이전트에게 아주 구체적인 지시사항을 부여합니다.&lt;/li&gt;
&lt;li class=&quot;aiagentodin_list_item&quot;&gt;&lt;span class=&quot;aiagentodin_bold&quot;&gt;단계 4 : 오류 처리 및 성찰 설계 :&lt;/span&gt; 에이전트가 실패했을 때 스스로 원인을 파악하고 재시도하는 로직을 프롬프트에 포함합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 class=&quot;aiagentodin_section_h2&quot; data-ke-size=&quot;size26&quot;&gt;마무리&lt;/h2&gt;
&lt;p class=&quot;aiagentodin_paragraph&quot; data-ke-size=&quot;size16&quot;&gt;AI 에이전트는 단순한 도구를 넘어 인간의 지능적 동반자로 자리 잡았습니다. 특히, 멀티 에이전트 시스템을 통한 코드 최적화는 개발 속도를 획기적으로 높이는 동시에 인적 오류를 최소화하는 강력한 수단입니다. OpenAI와 Gemini 등 각 모델의 특성에 맞춰 에이전트를 설계한다면, 여러분의 업무 환경은 이전과는 전혀 다른 차원의 효율성을 경험하게 될 것입니다.&lt;/p&gt;
&lt;footer class=&quot;aiagentodin_footer_tags&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Tags&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;#AI에이전트 #AIAgent #업무자동화 #OpenAI #Gemini #멀티에이전트 #코드최적화 #LangChain #CrewAI #인공지능프로그래밍&lt;/p&gt;
&lt;/footer&gt;&lt;/header&gt;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;
&lt;script&gt;
    function aiagentodin_copy(aiagentodin_target_id) {
        const aiagentodin_text_content = document.getElementById(aiagentodin_target_id).innerText;
        navigator.clipboard.writeText(aiagentodin_text_content).then(() =&gt; {
            alert(&quot;소스 코드가 성공적으로 클립보드에 복사되었습니다.&quot;);
        }).catch(err =&gt; {
            console.error('복사 중 오류 발생 : ', err);
            alert(&quot;복사에 실패했습니다. 수동으로 복사해 주세요.&quot;);
        });
    }
&lt;/script&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>DEVELOPMENT</category>
      <category>2026 AI 기술 트렌드</category>
      <category>Agent 자동화 가이드</category>
      <category>AI 에이전트 제작 방법</category>
      <category>OpenAI 에이전트</category>
      <category>랭체인 에이전트 사용법</category>
      <category>멀티 에이전트 협업 시스템</category>
      <category>인공지능 에이전트 아키텍처</category>
      <category>제미나이 AI 에이전트 활용</category>
      <category>코드 최적화 AI 솔루션</category>
      <category>파이썬 업무 자동화 코드</category>
      <author>간지뽕빨리턴님</author>
      <guid isPermaLink="true">https://odinbox.tistory.com/566</guid>
      <comments>https://odinbox.tistory.com/566#entry566comment</comments>
      <pubDate>Sat, 3 Jan 2026 10:41:28 +0900</pubDate>
    </item>
    <item>
      <title>원망했던 나의 아버지, 하늘로 보내드리며 적는 편지</title>
      <link>https://odinbox.tistory.com/565</link>
      <description>&lt;div style=&quot;line-height: 2.0; font-family: 'Apple SD Gothic Neo', 'Malgun Gothic', sans-serif; color: #333; max-width: 800px; margin: auto; padding: 40px 20px; word-break: keep-all;&quot;&gt;
&lt;h1 style=&quot;border-bottom: 2px solid #222; padding-bottom: 20px; color: #000; font-size: 1.7em; text-align: center; line-height: 1.4;&quot;&gt;지독했던 원망 끝에 아버지를 보냈습니다.&lt;br /&gt;술 냄새 속에 가려졌던 당신의 진심&lt;/h1&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;ClickERP.png&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;1280&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bsvH0w/dJMcaf6gZZH/DBFxpXOq1e8313dH1BDYJ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bsvH0w/dJMcaf6gZZH/DBFxpXOq1e8313dH1BDYJ0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bsvH0w/dJMcaf6gZZH/DBFxpXOq1e8313dH1BDYJ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbsvH0w%2FdJMcaf6gZZH%2FDBFxpXOq1e8313dH1BDYJ0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1920&quot; height=&quot;1280&quot; data-filename=&quot;ClickERP.png&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;1280&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p style=&quot;text-align: center; color: #999; font-size: 0.9em; margin-bottom: 50px;&quot; data-ke-size=&quot;size16&quot;&gt;2025. 12. 24. 소리 내지 못한 고백&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2025년 12월 7일, 아버지가 세상을 떠나셨습니다. 이틀 뒤인 12월 9일, 입관과 발인을 거쳐 화장까지 마쳤습니다. 경제적인 사정과 여러 이유로 가족들과 고심 끝에 &lt;b&gt;'무빈소 장례'&lt;/b&gt;를 치렀습니다. 빈소도 없이 아버지를 보내드리는 길, 차가운 공기만큼이나 가슴 한구석이 무겁고 씁쓸했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rH49j/dJMb99LKvx5/3TpG01EUxbLmAvHZtrpCL0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rH49j/dJMb99LKvx5/3TpG01EUxbLmAvHZtrpCL0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rH49j/dJMb99LKvx5/3TpG01EUxbLmAvHZtrpCL0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrH49j%2FdJMb99LKvx5%2F3TpG01EUxbLmAvHZtrpCL0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;div style=&quot;margin: 50px 0; padding: 30px; border-left: 4px solid #555; background-color: #fcfcfc;&quot;&gt;
&lt;h2 style=&quot;font-size: 1.3em; color: #222; margin-top: 0;&quot; data-ke-size=&quot;size26&quot;&gt;아버지의 술 냄새, 그리고 나의 상처&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어린 시절 제 기억 속의 아버지는 늘 술에 취해 계셨습니다. 현관문을 열 때부터 풍겨오던 지독한 술 냄새는 어린 저에게 공포였고, 지울 수 없는 상처였습니다. 술에 의지해 삶을 버티던 당신의 모습 때문에 저는 참 많이도 울었고, 아버지를 미워하고 원망하며 자랐습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 상처가 너무나 깊었기에, 저는 어른이 된 지금까지도 술을 입에 대지 않습니다. 아니, 먹지 않는 것이 아니라 &lt;b&gt;'안 먹는 것'&lt;/b&gt;에 가깝습니다. 당신처럼 살고 싶지 않다는 처절한 거부였고, 제 인생만큼은 술 냄새 없는 온전한 것이길 바랐기 때문입니다.&lt;/p&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어린 시절 앓으셨던 열병은 아버지의 삶을 송두리째 앗아갔습니다. 뒤틀린 걸음걸이, 침침해진 눈, 잘 들리지 않던 귀... 그 불편한 몸으로 세상을 살아내는 것이 얼마나 고단하셨을까요. 원망의 뒤편에는 늘 그 가냘픈 뒷모습에 대한 연민이 있었습니다. 상처를 주었지만, 그래도 당신은 제게 단 하나뿐인 아버지였습니다.&lt;/p&gt;
&lt;blockquote style=&quot;background: #f9f9f9; border: 1px solid #eee; padding: 30px; margin: 40px 0; text-align: center;&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p style=&quot;font-size: 1.2em; color: #333; font-weight: bold; margin: 0; line-height: 1.6;&quot; data-ke-size=&quot;size16&quot;&gt;&quot;너는 나처럼 살지 않았으면 좋겠다.&quot;&lt;br /&gt;&quot;어디서든 당당하게 살아라.&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;무뚝뚝하게 내뱉으셨던 그 말씀이 이제는 유언처럼 가슴에 박혔습니다. 당신처럼 술에 기대어 무너지는 삶이 아니라, 고개를 들고 세상 앞에 당당히 서기를 바랐던 그 마음. 당신은 당신의 삶을 통해 제게 '어떻게 살아야 하는지'를 온몸으로 말씀하고 계셨던 것인지도 모르겠습니다.&lt;/p&gt;
&lt;h2 style=&quot;font-size: 1.3em; color: #222; margin-top: 50px;&quot; data-ke-size=&quot;size26&quot;&gt;연말의 빈자리, 익숙해지지 않는 공허함&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;거리에는 벌써 연말 분위기가 가득합니다. 가족들과 웃으며 걷는 사람들을 보면, 당신의 빈자리가 왜 이렇게 시리도록 차갑게 느껴지는지 모르겠습니다. 평생을 이런 외로움과 공허함 속에 살아와서 이제는 익숙해질 법도 한데, 이번 12월은 유독 씁쓸하고 힘이 듭니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;장례 중에도 어머니가 무너질까 봐 일부러 덤덤한 척, 아무렇지도 않은 척 연기를 했습니다. 하지만 마음속으로는 수천 번 되뇌었습니다. &quot;다시 내 아버지로 태어나주신다면, 그때는 당신의 술 냄새조차 사랑으로 안아줄 수 있을 만큼 제가 더 잘하겠노라고...&quot;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bdDnR8/dJMcaiu7qp5/5Cf5YMQbiVsS2NTsHOyMn0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bdDnR8/dJMcaiu7qp5/5Cf5YMQbiVsS2NTsHOyMn0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bdDnR8/dJMcaiu7qp5/5Cf5YMQbiVsS2NTsHOyMn0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbdDnR8%2FdJMcaiu7qp5%2F5Cf5YMQbiVsS2NTsHOyMn0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;center&gt;&lt;iframe src=&quot;https://www.youtube-nocookie.com/embed/cw6f2xxFSmo?si=PZubzG27NKdnB15M&quot; width=&quot;560&quot; height=&quot;315&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;&lt;/center&gt;
&lt;div style=&quot;margin-top: 60px; padding: 30px; border-radius: 10px; background: linear-gradient(to right, #f4f4f4, #fff); border: 1px solid #eee;&quot;&gt;
&lt;p style=&quot;margin: 0; font-size: 1.05em; color: #444;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;아버지, 이제 이곳에서의 모든 미련과 나빴던 기억은 다 털어버리세요.&lt;/b&gt;&lt;br /&gt;술기운 없이 맑은 정신으로, 아프지 않은 다리로 저 하늘을 마음껏 누비시길 바랍니다. 제가 이 공허함을 이겨내고 당당하게 살아가는 것이, 이미 떠난 아버지의 짐을 덜어드리는 길임을 잊지 않겠습니다.&lt;br /&gt;&lt;br /&gt;고생 많으셨습니다. 이제는 부디, 편히 쉬세요.&lt;/p&gt;
&lt;/div&gt;
&lt;p style=&quot;margin-top: 50px; text-align: right; color: #888;&quot; data-ke-size=&quot;size16&quot;&gt;2025년 12월 24일&lt;br /&gt;못다 한 사랑을 담아, 아들이 올림&lt;/p&gt;
&lt;/div&gt;</description>
      <category>DailyRoutine</category>
      <category>무빈소장례</category>
      <category>부모님</category>
      <category>사부곡</category>
      <category>삼가고인의명복을빕니다</category>
      <category>아버지</category>
      <category>아버지의부고</category>
      <category>어린시절기억</category>
      <category>울산</category>
      <category>추모</category>
      <category>추모편지</category>
      <author>간지뽕빨리턴님</author>
      <guid isPermaLink="true">https://odinbox.tistory.com/565</guid>
      <comments>https://odinbox.tistory.com/565#entry565comment</comments>
      <pubDate>Wed, 24 Dec 2025 20:16:59 +0900</pubDate>
    </item>
    <item>
      <title>NVIDIA, 네모트론 엘라스틱(Nemotron Elastic) 분석</title>
      <link>https://odinbox.tistory.com/564</link>
      <description>&lt;div style=&quot;font-family: 'Pretendard', 'Malgun Gothic', sans-serif; line-height: 1.8; color: #333; max-width: 900px; margin: 0 auto; padding: 30px; border: 1px solid #e1e1e1; border-radius: 12px; background-color: #ffffff;&quot;&gt;
&lt;div style=&quot;text-align: center; margin-bottom: 50px;&quot;&gt;
&lt;p style=&quot;color: #0070f3; font-weight: 600; letter-spacing: 1px; margin-bottom: 10px;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;NVIDIA AI RESEARCH DEEP DIVE&lt;/span&gt;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;글 상단 부분 대표 이미지 (3).png&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/clEzTr/dJMcagjMjew/03rqkbyQLH6BhmmZDRilk0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/clEzTr/dJMcagjMjew/03rqkbyQLH6BhmmZDRilk0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/clEzTr/dJMcagjMjew/03rqkbyQLH6BhmmZDRilk0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FclEzTr%2FdJMcagjMjew%2F03rqkbyQLH6BhmmZDRilk0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;400&quot; data-filename=&quot;글 상단 부분 대표 이미지 (3).png&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;div style=&quot;width: 60px; height: 4px; background-color: #0070f3; margin: 25px auto;&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div style=&quot;margin-bottom: 50px;&quot;&gt;
&lt;h2 style=&quot;font-size: 1.6em; color: #222; border-bottom: 2px solid #f0f0f0; padding-bottom: 10px;&quot; data-ke-size=&quot;size26&quot;&gt;번역 및 분석을 통해 본 AI 모델의 미래&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;엔비디아가 최근 공개한 논문 &lt;b&gt;&quot;Nemotron Elastic: Towards Efficient Many-in-One Reasoning LLMs (arXiv:2511.16664)&quot;&lt;/b&gt;를 한국어로 번역하고, 그 핵심 원리를 심층 분석한 결과물입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;기존의 인공지능 개발 방식은 커다란 모델(예: 12B)과 작은 모델(예: 6B)을 만들 때 각각 수조 개의 데이터를 사용해 따로 학습시켜야 했습니다. 이는 비용과 시간 면에서 엄청난 낭비를 초래합니다. 엔비디아의 연구진은 이러한 문제를 해결하기 위해, &lt;b&gt;'단 한 번의 학습으로 여러 크기의 모델을 즉시 추출'&lt;/b&gt;할 수 있는 '엘라스틱(Elastic)' 아키텍처를 제안했습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div style=&quot;margin-bottom: 50px;&quot;&gt;
&lt;h2 style=&quot;font-size: 1.6em; color: #222; border-bottom: 2px solid #f0f0f0; padding-bottom: 10px;&quot; data-ke-size=&quot;size26&quot;&gt;왜 '엘라스틱(Elastic)'인가?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;엘라스틱(Elastic)은 '탄력 있는'이라는 뜻입니다. 이 모델은 필요에 따라 크기를 자유자재로 줄였다 늘렸다 할 수 있습니다. 이를 가능하게 하는 핵심 원리는 &lt;b&gt;가중치 공유(Weight Sharing)&lt;/b&gt;입니다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;padding-left: 20px;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;margin-bottom: 15px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;구조적 유연성:&lt;/b&gt; 부모 모델인 12B 모델의 신경망 중 일부를 선택적으로 사용함으로써 별도의 추가 학습 없이 9B나 6B 모델을 즉시 만들어냅니다.&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;margin-bottom: 15px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;지식 증류 기반 학습:&lt;/b&gt; 학습 과정에서 가장 큰 모델이 스승 역할을 하고, 추출될 작은 모델들이 그 지식을 실시간으로 전수받는 '지식 증류' 기법을 적용하여 작은 모델의 성능 하락을 방어합니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div style=&quot;margin-bottom: 50px;&quot;&gt;
&lt;h2 style=&quot;font-size: 1.6em; color: #222; border-bottom: 2px solid #f0f0f0; padding-bottom: 10px;&quot; data-ke-size=&quot;size26&quot;&gt;네모트론 엘라스틱만의 3가지 핵심 기술&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;1. MSE 기반의 정밀한 레이어 선별&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;단순히 레이어를 무작위로 제거하는 것이 아닙니다. 전체 모델의 결과값과 특정 레이어를 뺐을 때의 오차(Mean Squared Error)를 계산합니다. 오차가 가장 적은, 즉 &lt;b&gt;성능에 영향이 적은 레이어부터 순차적으로 제거&lt;/b&gt;함으로써 작은 모델의 정확도를 극대화했습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;2. 맘바와 어텐션의 하이브리드 설계&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;네모트론 엘라스틱은 문맥 파악이 뛰어난 '어텐션(Attention)'과 연산 효율이 좋은 '맘바(Mamba)' 구조를 섞었습니다. 이 덕분에 긴 문장을 읽을 때 메모리를 적게 쓰면서도 복잡한 논리 문제를 잘 풀 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;3. 2단계 커리큘럼 및 49K 롱컨텍스트 학습&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;모델의 '추론 능력'을 위해 두 단계로 학습합니다. 특히 2단계에서는 &lt;b&gt;49,000개 이상의 토큰(단어 조각)을 한 번에 처리&lt;/b&gt;하는 긴 문맥 학습을 진행하여, AI가 복잡한 수학 문제나 코딩 문제를 끝까지 논리적으로 풀 수 있게 만들었습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div style=&quot;margin-bottom: 50px;&quot;&gt;
&lt;h2 style=&quot;font-size: 1.6em; color: #222; border-bottom: 2px solid #f0f0f0; padding-bottom: 10px;&quot; data-ke-size=&quot;size26&quot;&gt;데이터로 증명된 효율성&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;네모트론 엘라스틱은 경제성과 성능 두 가지 측면에서 혁신적인 수치를 기록했습니다.&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;width: 100%; border-collapse: collapse; margin-top: 20px; border-top: 2px solid #333;&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr style=&quot;background-color: #f9f9f9; text-align: center;&quot;&gt;
&lt;th style=&quot;padding: 15px; border-bottom: 1px solid #ddd;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;지표 항목&lt;/span&gt;&lt;/th&gt;
&lt;th style=&quot;padding: 15px; border-bottom: 1px solid #ddd;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;기존 모델 개발 방식&lt;/span&gt;&lt;/th&gt;
&lt;th style=&quot;padding: 15px; border-bottom: 1px solid #ddd; color: #0070f3;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;네모트론 엘라스틱&lt;/span&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;padding: 15px; border-bottom: 1px solid #ddd; font-weight: bold;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;학습 비용(토큰)&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;padding: 15px; border-bottom: 1px solid #ddd;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;수 조 개의 토큰 소모&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;padding: 15px; border-bottom: 1px solid #ddd;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;단 1,100억 개(110B)로 해결&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;padding: 15px; border-bottom: 1px solid #ddd; font-weight: bold;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;비용 절감율&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;padding: 15px; border-bottom: 1px solid #ddd;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;1.0x (기준)&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;padding: 15px; border-bottom: 1px solid #ddd; font-weight: bold;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;약 360배 절감&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;padding: 15px; border-bottom: 1px solid #ddd; font-weight: bold;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;성능 유지&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;padding: 15px; border-bottom: 1px solid #ddd;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;별도 최적화 필요&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;padding: 15px; border-bottom: 1px solid #ddd;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;기존 독립 모델과 대등한 점수&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div style=&quot;margin-bottom: 50px;&quot;&gt;
&lt;h2 style=&quot;font-size: 1.6em; color: #222; border-bottom: 2px solid #f0f0f0; padding-bottom: 10px;&quot; data-ke-size=&quot;size26&quot;&gt;참고 자료 및 원문 정보&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;상세한 수식과 실험 결과는 아래 공식 논문을 통해 확인하실 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #f0f7ff; padding: 15px; border-radius: 8px;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;원문 논문:&lt;/b&gt; &lt;a style=&quot;color: #0070f3; text-decoration: none;&quot; href=&quot;https://arxiv.org/abs/2511.16664&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Nemotron Elastic: Towards Efficient Many-in-One Reasoning LLMs&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #f0f7ff; padding: 15px; border-radius: 8px;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;참조 모델:&lt;/b&gt; NVIDIA Nemotron Nano V2 12B&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div style=&quot;padding: 35px; background-color: #1a1a1a; border-radius: 12px; color: #efefef;&quot;&gt;
&lt;h2 style=&quot;margin-top: 0; color: #ffffff; font-size: 1.8em;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #ffffff;&quot;&gt;마무리&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #ffffff;&quot;&gt;네모트론 엘라스틱은 인공지능 모델의 '크기'가 더 이상 성능의 유일한 척도가 아님을 보여줍니다. 상황에 따라 모델의 자원을 조절하여 효율적으로 사용하는 이 기술은 클라우드 서버뿐만 아니라 개인용 스마트폰이나 PC에서도 고성능 AI를 원활하게 구동하는 밑거름이 될 것입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;margin-bottom: 0;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #ffffff;&quot;&gt;단 한 번의 학습으로 모든 가능성을 여는 엔비디아의 시도가 AI 상용화에 어떠한 가속도를 붙일지 기대됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;</description>
      <category>IT</category>
      <category>Ai</category>
      <category>LLM</category>
      <category>NVIDIA Nemotron Elastic 분석</category>
      <category>네모트론 엘라스틱 성능</category>
      <category>딥러닝연구</category>
      <category>맘바 아키텍처 원리</category>
      <category>모델 압축 기술 MSE</category>
      <category>엔비디아 AI 신기술</category>
      <category>온디바이스 AI</category>
      <category>인공지능</category>
      <author>간지뽕빨리턴님</author>
      <guid isPermaLink="true">https://odinbox.tistory.com/564</guid>
      <comments>https://odinbox.tistory.com/564#entry564comment</comments>
      <pubDate>Sat, 20 Dec 2025 16:34:04 +0900</pubDate>
    </item>
    <item>
      <title>PostgreSQL 파이썬 연동방법</title>
      <link>https://odinbox.tistory.com/563</link>
      <description>&lt;div&gt;
&lt;style&gt;
    :root {
        --pp-bg-color: #ffffff;
        --pp-text-color: #333333;
        --pp-title-color: #2c3e50;
        --pp-accent-color: #336791;
        --pp-sub-bg: #f8f9fa;
        --pp-border-color: #e9ecef;
        --pp-code-bg: #282c34;
        --pp-code-text: #abb2bf;
        --pp-note-bg: #f0f7fb;
        --pp-note-border: #cce5ff;
        --pp-tag-bg: #f1f3f5;
        --pp-tag-text: #495057;
    }

    @media (prefers-color-scheme: dark) {
        :root {
            --pp-bg-color: #1e1e1e;
            --pp-text-color: #e0e0e0;
            --pp-title-color: #ffffff;
            --pp-accent-color: #61afef;
            --pp-sub-bg: #2d2d2d;
            --pp-border-color: #444444;
            --pp-code-bg: #121212;
            --pp-code-text: #dcdcdc;
            --pp-note-bg: #2a3b4c;
            --pp-note-border: #336791;
            --pp-tag-bg: #333333;
            --pp-tag-text: #cccccc;
        }
    }

    #postgrespython_container {
        font-family: 'Pretendard', 'Noto Sans KR', sans-serif;
        line-height: 1.8;
        color: var(--pp-text-color);
        background-color: var(--pp-bg-color);
        max-width: 860px;
        margin: 0 auto;
        padding: 20px;
        box-sizing: border-box;
        word-break: keep-all;
    }

    @keyframes postgrespython_fadeInUp {
        from { opacity: 0; transform: translateY(20px); }
        to { opacity: 1; transform: translateY(0); }
    }

    .postgrespython_section {
        margin-bottom: 60px;
        opacity: 0;
        animation: postgrespython_fadeInUp 0.6s ease-out forwards;
    }
    .postgrespython_section:nth-child(2) { animation-delay: 0.1s; }
    .postgrespython_section:nth-child(3) { animation-delay: 0.2s; }
    .postgrespython_section:nth-child(4) { animation-delay: 0.3s; }
    .postgrespython_section:nth-child(5) { animation-delay: 0.4s; }

    .postgrespython_title {
        font-size: 2.2rem;
        font-weight: 800;
        color: var(--pp-title-color);
        border-bottom: 3px solid var(--pp-accent-color);
        padding-bottom: 20px;
        margin-bottom: 40px;
        line-height: 1.3;
    }

    .postgrespython_subtitle {
        font-size: 1.5rem;
        font-weight: 700;
        color: var(--pp-accent-color);
        margin-top: 50px;
        margin-bottom: 20px;
        padding-left: 15px;
        border-left: 5px solid var(--pp-accent-color);
    }

    .postgrespython_text {
        font-size: 1.05rem;
        margin-bottom: 20px;
        text-align: justify;
    }

    .postgrespython_note {
        background-color: var(--pp-note-bg);
        border: 1px solid var(--pp-note-border);
        padding: 20px;
        border-radius: 8px;
        margin: 25px 0;
    }
    .postgrespython_note strong {
        color: var(--pp-accent-color);
        display: block;
        margin-bottom: 10px;
        font-size: 1.1rem;
    }

    .postgrespython_code_wrapper {
        position: relative;
        margin: 30px 0;
    }

    .postgrespython_code_block {
        background-color: var(--pp-code-bg);
        color: var(--pp-code-text);
        padding: 20px;
        padding-top: 40px;
        border-radius: 8px;
        font-family: 'Consolas', 'Monaco', monospace;
        font-size: 0.95rem;
        overflow-x: auto;
        line-height: 1.6;
        border: 1px solid var(--pp-border-color);
        white-space: pre;
    }

    .postgrespython_copy_btn {
        position: absolute;
        top: 10px;
        right: 10px;
        background-color: #4a4a4a;
        color: #fff;
        border: none;
        border-radius: 4px;
        padding: 5px 12px;
        font-size: 0.8rem;
        cursor: pointer;
        transition: all 0.2s;
        z-index: 10;
        font-family: sans-serif;
    }
    .postgrespython_copy_btn:hover {
        background-color: var(--pp-accent-color);
    }

    .postgrespython_code_keyword { color: #c678dd; font-weight: bold; }
    .postgrespython_code_func { color: #61afef; }
    .postgrespython_code_string { color: #98c379; }

    .postgrespython_example_label {
        display: inline-block;
        background-color: var(--pp-accent-color);
        color: #fff;
        padding: 6px 16px;
        border-radius: 20px;
        font-weight: bold;
        font-size: 0.95rem;
        margin-bottom: 15px;
        margin-top: 30px;
    }

    .postgrespython_thumbnail_area {
        margin-bottom: 40px;
        text-align: center;
    }
    .postgrespython_thumbnail_area img {
        max-width: 100%;
        height: auto;
        border-radius: 12px;
        box-shadow: 0 4px 12px rgba(0,0,0,0.1);
    }

    .postgrespython_list { margin-left: 20px; margin-bottom: 20px; }
    .postgrespython_list li { margin-bottom: 10px; }

    .postgrespython_tag_container {
        margin-top: 80px;
        padding-top: 30px;
        border-top: 1px solid var(--pp-border-color);
    }
    .postgrespython_tag_item {
        background-color: var(--pp-tag-bg);
        color: var(--pp-tag-text);
        padding: 8px 15px;
        border-radius: 20px;
        font-size: 0.9rem;
        margin-right: 8px;
        margin-bottom: 8px;
        display: inline-block;
        text-decoration: none;
        transition: background-color 0.2s;
    }
    .postgrespython_tag_item:hover {
        background-color: var(--pp-accent-color);
        color: #fff;
    }
    .postgrespython_hidden_tags { display: none; }

    @media (max-width: 768px) {
        #postgrespython_container { padding: 15px; }
        .postgrespython_title { font-size: 1.8rem; }
        .postgrespython_subtitle { font-size: 1.3rem; margin-top: 30px; }
        .postgrespython_code_block { font-size: 0.85rem; padding: 15px; padding-top: 40px; }
    }
&lt;/style&gt;
&lt;/div&gt;
&lt;div id=&quot;postgrespython_container&quot;&gt;
&lt;div class=&quot;postgrespython_section&quot;&gt;
&lt;div class=&quot;postgrespython_thumbnail_area&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;글 상단 부분 대표 이미지 (2).png&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bZUCEi/dJMcaiV6dtf/nVwxSMkS45CZ4t0wXLRRbK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bZUCEi/dJMcaiV6dtf/nVwxSMkS45CZ4t0wXLRRbK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bZUCEi/dJMcaiV6dtf/nVwxSMkS45CZ4t0wXLRRbK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbZUCEi%2FdJMcaiV6dtf%2FnVwxSMkS45CZ4t0wXLRRbK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;400&quot; data-filename=&quot;글 상단 부분 대표 이미지 (2).png&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;postgrespython_section&quot;&gt;
&lt;h2 class=&quot;postgrespython_subtitle&quot; data-ke-size=&quot;size26&quot;&gt;들어가며 : SQL의 한계를 넘어서&lt;/h2&gt;
&lt;p class=&quot;postgrespython_text&quot; data-ke-size=&quot;size16&quot;&gt;PostgreSQL은 강력한 관계형 데이터베이스이지만 순수 SQL만으로는 복잡한 비즈니스 로직이나 문자열 처리를 구현하는 데 한계가 있습니다. 이때 사용할 수 있는 가장 강력한 도구가 바로 PL/Python입니다. 이는 데이터베이스 내부에서 파이썬 언어를 사용하여 함수나 프로시저를 작성할 수 있게 해주는 절차적 언어 핸들러입니다. 본 글에서는 윈도우 운영체제에서 PL/Python을 사용하기 위한 설치 방법과 환경 설정 그리고 실무에서 활용 가능한 예제 코드를 상세하게 정리해 드립니다.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;postgrespython_section&quot;&gt;
&lt;h2 class=&quot;postgrespython_subtitle&quot; data-ke-size=&quot;size26&quot;&gt;윈도우 환경 설치 및 설정 방법&lt;/h2&gt;
&lt;p class=&quot;postgrespython_text&quot; data-ke-size=&quot;size16&quot;&gt;윈도우에서 PostgreSQL과 파이썬을 연동할 때 가장 주의해야 할 점은 버전 호환성입니다. 리눅스 패키지 관리자와 달리 윈도우 인스톨러는 특정 파이썬 버전에 의존적인 DLL 파일을 포함하고 있습니다.&lt;/p&gt;
&lt;div class=&quot;postgrespython_note&quot;&gt;&lt;b&gt;핵심 : 파이썬 버전 일치시키기&lt;/b&gt; 반드시 PostgreSQL 설치 폴더 내의 bin 디렉터리에 있는 plpython3.dll 파일이 요구하는 파이썬 버전을 설치해야 합니다. 버전이 다르면 함수 생성 시 라이브러리를 로드할 수 없다는 오류가 발생합니다.&lt;/div&gt;
&lt;p class=&quot;postgrespython_text&quot; data-ke-size=&quot;size16&quot;&gt;설치 및 설정 단계는 다음과 같습니다.&lt;/p&gt;
&lt;ul class=&quot;postgrespython_list&quot; style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Python 설치 : &lt;/b&gt; PostgreSQL 버전에 맞는 파이썬을 공식 홈페이지에서 다운로드하여 설치합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;환경 변수 설정 : &lt;/b&gt; 제어판의 시스템 환경 변수 설정에서 PYTHONHOME 변수를 새로 만들고 파이썬 설치 경로를 지정해야 합니다. 또한 Path 변수에도 파이썬 실행 경로와 Scripts 경로를 추가합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;서비스 재시작 : &lt;/b&gt; 환경 변수 변경 사항이 PostgreSQL 서비스에 적용되도록 Windows 서비스 관리자에서 서비스를 재시작합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;postgrespython_section&quot;&gt;
&lt;h2 class=&quot;postgrespython_subtitle&quot; data-ke-size=&quot;size26&quot;&gt;PostgreSQL 확장 활성화&lt;/h2&gt;
&lt;p class=&quot;postgrespython_text&quot; data-ke-size=&quot;size16&quot;&gt;환경 설정이 끝났다면 데이터베이스에 접속하여 확장을 생성해야 합니다. plpython3u 확장을 설치하며 여기서 u는 untrusted를 의미하므로 슈퍼유저 권한이 필요합니다.&lt;/p&gt;
&lt;div class=&quot;postgrespython_code_wrapper&quot;&gt;&lt;button class=&quot;postgrespython_copy_btn&quot;&gt;복사&lt;/button&gt;
&lt;pre class=&quot;postgrespython_code_block pgsql&quot;&gt;&lt;code&gt;CREATE EXTENSION plpython3u;

SELECT * FROM pg_extension WHERE extname = 'plpython3u';&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;postgrespython_section&quot;&gt;
&lt;h2 class=&quot;postgrespython_subtitle&quot; data-ke-size=&quot;size26&quot;&gt;PL/Python 함수 활용 예제&lt;/h2&gt;
&lt;p class=&quot;postgrespython_text&quot; data-ke-size=&quot;size16&quot;&gt;파이썬 문법을 그대로 사용하여 DB 함수를 만드는 방법을 예제와 함께 살펴보겠습니다.&lt;/p&gt;
&lt;span class=&quot;postgrespython_example_label&quot;&gt;예제 1 : 두 수 비교 함수&lt;/span&gt;
&lt;p class=&quot;postgrespython_text&quot; data-ke-size=&quot;size16&quot;&gt;가장 기초적인 형태의 함수입니다. 파이썬의 if 조건문을 사용하여 로직을 구현합니다.&lt;/p&gt;
&lt;div class=&quot;postgrespython_code_wrapper&quot;&gt;&lt;button class=&quot;postgrespython_copy_btn&quot;&gt;복사&lt;/button&gt;
&lt;pre class=&quot;postgrespython_code_block pgsql&quot;&gt;&lt;code&gt;CREATE OR REPLACE FUNCTION public.py_max(a integer, b integer)
RETURNS integer
AS $$
  if a &amp;gt; b : 
      return a
  return b
$$ LANGUAGE plpython3u;

SELECT public.py_max(10, 20);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;span class=&quot;postgrespython_example_label&quot;&gt;예제 2 : JSON 데이터 처리&lt;/span&gt;
&lt;p class=&quot;postgrespython_text&quot; data-ke-size=&quot;size16&quot;&gt;파이썬의 내장 모듈인 json을 import하여 딕셔너리 데이터를 손쉽게 JSON 문자열로 변환할 수 있습니다.&lt;/p&gt;
&lt;div class=&quot;postgrespython_code_wrapper&quot;&gt;&lt;button class=&quot;postgrespython_copy_btn&quot;&gt;복사&lt;/button&gt;
&lt;pre class=&quot;postgrespython_code_block sql&quot;&gt;&lt;code&gt;CREATE OR REPLACE FUNCTION public.py_create_json(key text, value text)
RETURNS json
AS $$
  import json
  data = {key :  value}
  return json.dumps(data)
$$ LANGUAGE plpython3u;

SELECT public.py_create_json('result', 'success');&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;span class=&quot;postgrespython_example_label&quot;&gt;예제 3 : 집합 결과 반환 (SETOF)&lt;/span&gt;
&lt;p class=&quot;postgrespython_text&quot; data-ke-size=&quot;size16&quot;&gt;여러 행을 반환해야 하는 경우 파이썬의 yield 키워드를 사용하여 제너레이터 형태로 구현합니다.&lt;/p&gt;
&lt;div class=&quot;postgrespython_code_wrapper&quot;&gt;&lt;button class=&quot;postgrespython_copy_btn&quot;&gt;복사&lt;/button&gt;
&lt;pre class=&quot;postgrespython_code_block pgsql&quot;&gt;&lt;code&gt;CREATE OR REPLACE FUNCTION public.py_sequence(start_val int, end_val int)
RETURNS SETOF integer
AS $$
  for i in range(start_val, end_val + 1) : 
      yield i
$$ LANGUAGE plpython3u;

SELECT * FROM public.py_sequence(1, 5);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;postgrespython_section&quot;&gt;
&lt;h2 class=&quot;postgrespython_subtitle&quot; data-ke-size=&quot;size26&quot;&gt;마무리&lt;/h2&gt;
&lt;p class=&quot;postgrespython_text&quot; data-ke-size=&quot;size16&quot;&gt;이상으로 윈도우 환경에서 PostgreSQL에 파이썬을 연동하고 활용하는 방법에 대해 알아보았습니다. PL/Python을 도입하면 복잡한 연산이나 외부 라이브러리가 필요한 작업을 데이터베이스 계층에서 효율적으로 처리할 수 있습니다. 개발 환경 구축 시 파이썬 버전과 환경 변수 설정만 꼼꼼히 챙기신다면 강력한 백엔드 기능을 구현하실 수 있습니다.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;postgrespython_section postgrespython_tag_container&quot;&gt;
&lt;div&gt;&lt;span class=&quot;postgrespython_tag_item&quot;&gt;#PostgreSQL&lt;/span&gt; &lt;span class=&quot;postgrespython_tag_item&quot;&gt;#Python&lt;/span&gt; &lt;span class=&quot;postgrespython_tag_item&quot;&gt;#PLPython&lt;/span&gt; &lt;span class=&quot;postgrespython_tag_item&quot;&gt;#윈도우설정&lt;/span&gt; &lt;span class=&quot;postgrespython_tag_item&quot;&gt;#데이터베이스&lt;/span&gt; &lt;span class=&quot;postgrespython_tag_item&quot;&gt;#백엔드&lt;/span&gt; &lt;span class=&quot;postgrespython_tag_item&quot;&gt;#DB함수&lt;/span&gt; &lt;span class=&quot;postgrespython_tag_item&quot;&gt;#SQL튜닝&lt;/span&gt; &lt;span class=&quot;postgrespython_tag_item&quot;&gt;#개발자가이드&lt;/span&gt; &lt;span class=&quot;postgrespython_tag_item&quot;&gt;#프로시저&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;postgrespython_hidden_tags&quot;&gt;포스트그레스큐엘 파이썬 연동, plpython3u 설치 방법, 윈도우 Postgres 확장, DB 파이썬 프로시저, PostgreSQL Python Extension, 데이터베이스 튜닝, SQL 파이썬 함수, PostgreSQL 예제, 백엔드 개발 팁, 윈도우 서버 DB 설정&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;
&lt;script&gt;
    function postgrespython_copy(button) {
        var codeBlock = button.nextElementSibling.innerText;
        navigator.clipboard.writeText(codeBlock).then(function() {
            var originalText = button.innerText;
            button.innerText = '완료';
            button.style.backgroundColor = '#2ecc71';
            setTimeout(function() {
                button.innerText = originalText;
                button.style.backgroundColor = ''; 
            }, 2000);
        }).catch(function(err) {
            alert('복사에 실패했습니다.');
        });
    }
&lt;/script&gt;
&lt;/p&gt;</description>
      <category>DEVELOPMENT</category>
      <category>db함수</category>
      <category>PLPython</category>
      <category>PostgreSQL</category>
      <category>python</category>
      <category>SQL튜닝</category>
      <category>개발자가이드</category>
      <category>데이터베이스</category>
      <category>백엔드</category>
      <category>윈도우서버</category>
      <category>저장프로시저</category>
      <author>간지뽕빨리턴님</author>
      <guid isPermaLink="true">https://odinbox.tistory.com/563</guid>
      <comments>https://odinbox.tistory.com/563#entry563comment</comments>
      <pubDate>Wed, 10 Dec 2025 21:03:24 +0900</pubDate>
    </item>
    <item>
      <title>Oracle &amp;amp; PostgreSQL, SMTP 관련 가이드</title>
      <link>https://odinbox.tistory.com/562</link>
      <description>&lt;div&gt;
&lt;style&gt;
    /* 1. 전체 레이아웃 (전문 기술 문서 스타일) */
    #odin_wrap {
        font-family: 'Pretendard', 'Apple SD Gothic Neo', 'Noto Sans KR', sans-serif;
        color: #212529;
        line-height: 1.8;
        max-width: 860px;
        margin: 0 auto;
        word-break: keep-all;
        letter-spacing: -0.02em;
    }

    /* 2. 썸네일 이미지 스타일 */
    .odin_thumb_box {
        text-align: center;
        margin-bottom: 60px;
        border-radius: 8px;
        overflow: hidden;
        border: 1px solid #e0e0e0;
        box-shadow: 0 4px 12px rgba(0,0,0,0.05);
    }
    .odin_thumb_box img {
        max-width: 100%;
        height: auto;
        display: block;
    }

    /* 3. 타이포그래피 (TOC 호환성 고려) */
    .odin_section {
        margin-bottom: 80px;
    }

    /* H1: 글 제목과 유사한 스타일 (본문 내 강조) */
    .odin_title {
        font-size: 2.2rem;
        font-weight: 800;
        color: #111;
        border-bottom: 3px solid #0056b3;
        padding-bottom: 20px;
        margin-bottom: 40px;
    }

    /* H2: 대주제 - 자동 목차 수집 대상 */
    .odin_h2 {
        font-size: 1.7rem;
        font-weight: 700;
        color: #0056b3; /* 신뢰감을 주는 딥 블루 */
        border-left: 5px solid #0056b3;
        padding-left: 15px;
        margin-top: 60px;
        margin-bottom: 25px;
        background-color: #f8f9fa; /* 연한 회색 배경으로 영역 구분 */
        padding-top: 12px;
        padding-bottom: 12px;
    }

    /* H3: 소주제 - 자동 목차 수집 대상 */
    .odin_h3 {
        font-size: 1.35rem;
        font-weight: 600;
        color: #333;
        margin-top: 40px;
        margin-bottom: 15px;
        border-bottom: 1px solid #dee2e6;
        padding-bottom: 10px;
        display: block;
    }

    .odin_p {
        font-size: 1.05rem;
        color: #495057;
        margin-bottom: 15px;
        text-align: justify;
    }

    /* 4. 코드 블록 디자인 (High Contrast Dark Theme) */
    .odin_code_wrap {
        background-color: #1e1e1e; /* 짙은 배경색 */
        border-radius: 6px;
        box-shadow: 0 10px 25px rgba(0,0,0,0.3); /* 깊이감 있는 그림자 */
        margin: 30px 0;
        overflow: hidden;
        border: 1px solid #333;
    }

    .odin_code_header {
        background-color: #252526;
        padding: 8px 15px;
        display: flex;
        justify-content: space-between;
        align-items: center;
        border-bottom: 1px solid #3e3e42;
    }

    .odin_filename {
        color: #cccccc;
        font-size: 0.9rem;
        font-family: 'Consolas', monospace;
        font-weight: 500;
    }

    .odin_copy_btn {
        background-color: #0e639c;
        color: white;
        border: none;
        padding: 5px 12px;
        border-radius: 2px;
        font-size: 0.8rem;
        cursor: pointer;
        font-family: sans-serif;
        transition: background 0.2s;
    }
    .odin_copy_btn:hover { background-color: #1177bb; }
    .odin_copy_btn.copied { background-color: #198754; }

    .odin_pre {
        margin: 0;
        padding: 20px;
        overflow-x: auto;
        font-family: 'Consolas', 'Monaco', 'D2Coding', monospace; /* 가독성 좋은 코딩 폰트 */
        font-size: 0.95rem;
        line-height: 1.6;
        color: #d4d4d4; /* 기본 텍스트 색상 (밝은 회색) */
        background-color: #1e1e1e; /* 코드 영역 배경 (Dark) */
    }

    /* 문법 하이라이팅 (선명한 색상 적용) */
    .kwd { color: #569cd6; font-weight: bold; } /* 키워드 (Blue) */
    .func { color: #dcdcaa; } /* 함수 (Yellow) */
    .str { color: #ce9178; } /* 문자열 (Orange) */
    .num { color: #b5cea8; } /* 숫자 (Light Green) */
    .typ { color: #4ec9b0; } /* 타입 (Teal) */
    .cmt { color: #6a9955; font-style: italic; } /* 주석 (Green) */
    .var { color: #9cdcfe; } /* 변수 (Light Blue) */

    /* 5. 기술 상세 설명 박스 */
    .odin_detail_box {
        background-color: #ffffff;
        border: 1px solid #ced4da;
        border-left: 5px solid #6c757d;
        padding: 20px;
        margin: 20px 0;
    }
    .odin_detail_title {
        font-weight: 700;
        font-size: 1.05rem;
        color: #343a40;
        margin-bottom: 8px;
        display: block;
        text-transform: uppercase;
    }

    /* 6. 문제 해결 (Troubleshooting) 영역 */
    .odin_trouble_wrap {
        background-color: #fff5f5; /* 아주 연한 붉은 배경 */
        border: 1px solid #ffc9c9;
        border-radius: 6px;
        padding: 25px;
        margin-top: 40px;
    }
    .odin_trouble_head {
        font-size: 1.2rem;
        font-weight: 800;
        color: #c92a2a;
        margin-bottom: 20px;
        display: block;
        border-bottom: 2px solid #ffec99;
        padding-bottom: 10px;
    }
    .odin_trouble_item {
        margin-bottom: 20px;
    }
    .odin_err_code {
        display: inline-block;
        background-color: #e03131;
        color: #fff;
        padding: 2px 8px;
        border-radius: 4px;
        font-weight: bold;
        font-size: 0.9rem;
        font-family: monospace;
        margin-right: 8px;
    }
    .odin_err_desc {
        display: block;
        margin-top: 5px;
        color: #495057;
        font-size: 1rem;
    }

&lt;/style&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;
&lt;script&gt;
    function copyOdinCode(elementId, btnId) {
        var codeElement = document.getElementById(elementId);
        var textToCopy = codeElement.innerText;
        var tempTextArea = document.createElement(&quot;textarea&quot;);
        tempTextArea.value = textToCopy;
        document.body.appendChild(tempTextArea);
        tempTextArea.select();
        document.execCommand(&quot;copy&quot;);
        document.body.removeChild(tempTextArea);

        var btn = document.getElementById(btnId);
        var originalText = btn.innerText;
        btn.innerText = &quot;복사됨&quot;;
        btn.classList.add(&quot;copied&quot;);

        setTimeout(function() {
            btn.innerText = originalText;
            btn.classList.remove(&quot;copied&quot;);
        }, 2000);
    }
&lt;/script&gt;
&lt;/p&gt;
&lt;div id=&quot;odin_wrap&quot;&gt;
&lt;div class=&quot;odin_thumb_box&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;글 상단 부분 대표 이미지 (1).png&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bOwtoI/dJMcafykeF3/kebJzeAGcJ4u6lLNZktKz1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bOwtoI/dJMcafykeF3/kebJzeAGcJ4u6lLNZktKz1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bOwtoI/dJMcafykeF3/kebJzeAGcJ4u6lLNZktKz1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbOwtoI%2FdJMcafykeF3%2FkebJzeAGcJ4u6lLNZktKz1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;400&quot; data-filename=&quot;글 상단 부분 대표 이미지 (1).png&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;div class=&quot;odin_section&quot;&gt;
&lt;h1 class=&quot;odin_title&quot;&gt;Oracle vs PostgreSQL 가이드&lt;/h1&gt;
&lt;p class=&quot;odin_p&quot; data-ke-size=&quot;size16&quot;&gt;시스템 운영 환경에서 데이터베이스가 직접 이메일을 발송해야 하는 요구사항은 꾸준히 존재합니다. 배치 작업 결과의 즉각적인 보고나 치명적인 데이터 오류 발생 시 관리자 알림을 위해, WAS(Web Application Server)를 거치지 않고 DB 레벨에서 SMTP 프로토콜을 직접 제어하는 것이 효율적일 때가 많습니다.&lt;/p&gt;
&lt;p class=&quot;odin_p&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;odin_p&quot; data-ke-size=&quot;size16&quot;&gt;본 문서에서는 엔터프라이즈의 표준인 Oracle의 &lt;code&gt;UTL_SMTP&lt;/code&gt; 방식과 오픈소스의 강자 PostgreSQL의 &lt;code&gt;PL/Python&lt;/code&gt; 구현 방식을 비교 분석하고, 실무 적용 시 반드시 마주하게 되는 보안 설정 및 오류 해결 방법까지 상세히 기술합니다.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;odin_section&quot;&gt;
&lt;h2 class=&quot;odin_h2&quot; data-ke-size=&quot;size26&quot;&gt;1. Oracle : UTL_SMTP 패키지 활용 및 ACL 보안&lt;/h2&gt;
&lt;div class=&quot;odin_detail_box&quot;&gt;&lt;span class=&quot;odin_detail_title&quot;&gt;Technical Context&lt;/span&gt;
&lt;p class=&quot;odin_p&quot; style=&quot;margin-bottom: 0;&quot; data-ke-size=&quot;size16&quot;&gt;Oracle 11g R2 버전 이후부터는 데이터베이스의 보안 강화 정책에 따라, 외부 네트워크(TCP/IP)로 나가는 패킷을 엄격히 통제합니다. 따라서 SMTP 서버와 통신하기 위해서는 반드시 &lt;b&gt;ACL(Access Control List)&lt;/b&gt;을 생성하여 특정 유저에게 &lt;code&gt;Resolve&lt;/code&gt; 및 &lt;code&gt;Connect&lt;/code&gt; 권한을 부여해야 합니다.&lt;/p&gt;
&lt;/div&gt;
&lt;h3 class=&quot;odin_h3&quot; data-ke-size=&quot;size23&quot;&gt;Step 1. ACL(Access Control List) 권한 부여 (SYSDBA)&lt;/h3&gt;
&lt;p class=&quot;odin_p&quot; data-ke-size=&quot;size16&quot;&gt;가장 먼저 수행해야 할 작업은 네트워크 통신을 위한 화이트리스트 등록입니다. 이 작업은 SYS 계정에서 수행해야 합니다.&lt;/p&gt;
&lt;div class=&quot;odin_code_wrap&quot;&gt;
&lt;div class=&quot;odin_code_header&quot;&gt;&lt;span class=&quot;odin_filename&quot;&gt;oracle_acl_setup.sql&lt;/span&gt; &lt;button id=&quot;btn_acl&quot; class=&quot;odin_copy_btn&quot;&gt;Code Copy&lt;/button&gt;&lt;/div&gt;
&lt;pre id=&quot;code_acl&quot; class=&quot;odin_pre typescript&quot;&gt;&lt;code&gt;BEGIN
    -- 1. ACL 파일 생성 및 권한 정의
    DBMS_NETWORK_ACL_ADMIN.CREATE_ACL (
        acl          =&amp;gt; 'odinbox_smtp_acl.xml',
        description  =&amp;gt; 'OdinBOX SMTP Access',
        principal    =&amp;gt; 'ODIN_USER', -- 권한을 부여할 DB 스키마(유저)명
        is_grant     =&amp;gt; TRUE,
        privilege    =&amp;gt; 'connect'
    );
    
    -- 2. 도메인 해석을 위한 Resolve 권한 추가
    DBMS_NETWORK_ACL_ADMIN.ADD_PRIVILEGE (
        acl          =&amp;gt; 'odinbox_smtp_acl.xml',
        principal    =&amp;gt; 'ODIN_USER',
        is_grant     =&amp;gt; TRUE,
        privilege    =&amp;gt; 'resolve'
    );

    -- 3. 타겟 호스트 및 포트 매핑 (Gmail 예시)
    DBMS_NETWORK_ACL_ADMIN.ASSIGN_ACL (
        acl          =&amp;gt; 'odinbox_smtp_acl.xml',
        host         =&amp;gt; 'smtp.gmail.com',
        lower_port   =&amp;gt; 587,
        upper_port   =&amp;gt; 587
    );
    COMMIT;
END;
/&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h3 class=&quot;odin_h3&quot; data-ke-size=&quot;size23&quot;&gt;Step 2. 메일 발송 프로시저 구현&lt;/h3&gt;
&lt;p class=&quot;odin_p&quot; data-ke-size=&quot;size16&quot;&gt;ACL 설정이 완료되면, UTL_SMTP 패키지를 사용하여 실제 발송 로직을 구현합니다. 한글 깨짐 방지를 위한 헤더 설정과 Base64 인증 처리가 핵심입니다.&lt;/p&gt;
&lt;div class=&quot;odin_code_wrap&quot;&gt;
&lt;div class=&quot;odin_code_header&quot;&gt;&lt;span class=&quot;odin_filename&quot;&gt;oracle_mail_proc.sql&lt;/span&gt; &lt;button id=&quot;btn_ora&quot; class=&quot;odin_copy_btn&quot;&gt;Code Copy&lt;/button&gt;&lt;/div&gt;
&lt;pre id=&quot;code_ora&quot; class=&quot;odin_pre ada&quot;&gt;&lt;code&gt;CREATE OR REPLACE PROCEDURE sp_send_mail_odinbox (
    p_recipient IN VARCHAR2,
    p_subject   IN VARCHAR2,
    p_body      IN VARCHAR2
) IS
    -- [OdinBOX] 변수 선언
    v_conn      UTL_SMTP.CONNECTION;
    v_host      VARCHAR2(50) := 'smtp.gmail.com';
    v_port      NUMBER       := 587; 
    v_user      VARCHAR2(50) := 'helpodinbox@gmail.com'; 
    v_pass      VARCHAR2(50) := 'app_password_key'; -- 앱 비밀번호 사용
BEGIN
    -- 1. TCP 연결 및 Handshake
    v_conn := UTL_SMTP.OPEN_CONNECTION(v_host, v_port);
    UTL_SMTP.HELO(v_conn, v_host);
    UTL_SMTP.STARTTLS(v_conn); -- TLS 보안 세션 시작

    -- 2. SMTP 인증 (AUTH LOGIN 방식 - Base64 인코딩 필수)
    UTL_SMTP.COMMAND(v_conn, 'AUTH LOGIN');
    UTL_SMTP.COMMAND(v_conn, 
        UTL_RAW.CAST_TO_VARCHAR2(UTL_ENCODE.BASE64_ENCODE(UTL_RAW.CAST_TO_RAW(v_user))));
    UTL_SMTP.COMMAND(v_conn, 
        UTL_RAW.CAST_TO_VARCHAR2(UTL_ENCODE.BASE64_ENCODE(UTL_RAW.CAST_TO_RAW(v_pass))));

    -- 3. 데이터 전송 섹션
    UTL_SMTP.MAIL(v_conn, v_user);
    UTL_SMTP.RCPT(v_conn, p_recipient);
    UTL_SMTP.OPEN_DATA(v_conn);
    
    -- [OdinBOX] MIME 헤더 구성 (Subject 한글 처리 중요)
    UTL_SMTP.WRITE_DATA(v_conn, 'Subject: =?UTF-8?B?' || UTL_RAW.CAST_TO_VARCHAR2(UTL_ENCODE.BASE64_ENCODE(UTL_RAW.CAST_TO_RAW(p_subject))) || '?=' || UTL_TCP.CRLF);
    UTL_SMTP.WRITE_DATA(v_conn, 'To: ' || p_recipient || UTL_TCP.CRLF);
    UTL_SMTP.WRITE_DATA(v_conn, 'Content-Type: text/plain; charset=UTF-8' || UTL_TCP.CRLF);
    UTL_SMTP.WRITE_DATA(v_conn, UTL_TCP.CRLF || p_body);
    
    UTL_SMTP.CLOSE_DATA(v_conn);
    UTL_SMTP.QUIT(v_conn);
EXCEPTION
    WHEN OTHERS THEN
        UTL_SMTP.QUIT(v_conn);
        RAISE;
END;
/&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div class=&quot;odin_trouble_wrap&quot;&gt;&lt;span class=&quot;odin_trouble_head&quot;&gt;Troubleshooting : Oracle Critical Errors&lt;/span&gt;
&lt;div class=&quot;odin_trouble_item&quot;&gt;&lt;span class=&quot;odin_err_code&quot;&gt;ORA-24247&lt;/span&gt; &lt;span class=&quot;odin_err_desc&quot;&gt; &lt;b&gt;네트워크 접근 권한 거부 (Network Access Denied)&lt;/b&gt;&lt;br /&gt;ACL 설정이 누락되었거나, &lt;code&gt;DBMS_NETWORK_ACL_ADMIN&lt;/code&gt;을 통해 부여된 권한이 현재 접속한 유저와 매핑되지 않았을 때 발생합니다. Step 1의 ACL 스크립트를 재점검하십시오. &lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;odin_trouble_item&quot;&gt;&lt;span class=&quot;odin_err_code&quot;&gt;ORA-29024&lt;/span&gt; &lt;span class=&quot;odin_err_desc&quot;&gt; &lt;b&gt;인증서 유효성 검사 실패 (Certificate Validation Failure)&lt;/b&gt;&lt;br /&gt;Oracle Wallet에 메일 서버(Gmail 등)의 Root CA 인증서가 등록되지 않았을 때 발생합니다. UTL_SMTP는 기본적으로 SSL/TLS 핸드쉐이크 시 인증서를 검증합니다. 이를 해결하려면 Wallet을 구성하거나, 내부망에 인증서 검증이 없는 SMTP Relay 서버를 구축하여 경유해야 합니다. &lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;odin_section&quot;&gt;
&lt;h2 class=&quot;odin_h2&quot; data-ke-size=&quot;size26&quot;&gt;2. PostgreSQL : PL/Python 확장과 유연성&lt;/h2&gt;
&lt;div class=&quot;odin_detail_box&quot;&gt;&lt;span class=&quot;odin_detail_title&quot;&gt;Technical Context&lt;/span&gt;
&lt;p class=&quot;odin_p&quot; style=&quot;margin-bottom: 0;&quot; data-ke-size=&quot;size16&quot;&gt;PostgreSQL은 모놀리식 구조를 지양하고 &lt;b&gt;Extension(확장)&lt;/b&gt; 생태계를 권장합니다. &lt;code&gt;plpython3u&lt;/code&gt;(Python 3 Untrusted Language) 확장을 설치하면, DB 내부에서 Python의 표준 라이브러리인 &lt;code&gt;smtplib&lt;/code&gt;을 직접 호출할 수 있습니다. 이를 통해 복잡한 인코딩 로직 없이 매우 간결한 코드로 메일 발송이 가능합니다.&lt;/p&gt;
&lt;/div&gt;
&lt;h3 class=&quot;odin_h3&quot; data-ke-size=&quot;size23&quot;&gt;Step 1. PL/Python 확장 설치&lt;/h3&gt;
&lt;p class=&quot;odin_p&quot; data-ke-size=&quot;size16&quot;&gt;'Untrusted' 언어는 파일 시스템 접근 등 OS 레벨의 제어가 가능하므로, 오직 &lt;b&gt;Superuser(관리자)&lt;/b&gt; 계정만이 해당 확장을 활성화하고 함수를 생성할 수 있습니다.&lt;/p&gt;
&lt;div class=&quot;odin_code_wrap&quot;&gt;
&lt;div class=&quot;odin_code_header&quot;&gt;&lt;span class=&quot;odin_filename&quot;&gt;postgres_ext_setup.sql&lt;/span&gt; &lt;button id=&quot;btn_pg_ext&quot; class=&quot;odin_copy_btn&quot;&gt;Code Copy&lt;/button&gt;&lt;/div&gt;
&lt;pre id=&quot;code_pg_ext&quot; class=&quot;odin_pre pgsql&quot;&gt;&lt;code&gt;-- 사전 조건: DB 서버 OS에 postgresql-contrib 및 python3 패키지가 설치되어 있어야 함
CREATE EXTENSION IF NOT EXISTS plpython3u;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h3 class=&quot;odin_h3&quot; data-ke-size=&quot;size23&quot;&gt;Step 2. Python smtplib 기반 함수 작성&lt;/h3&gt;
&lt;div class=&quot;odin_code_wrap&quot;&gt;
&lt;div class=&quot;odin_code_header&quot;&gt;&lt;span class=&quot;odin_filename&quot;&gt;postgres_mail_func.sql&lt;/span&gt; &lt;button id=&quot;btn_pg&quot; class=&quot;odin_copy_btn&quot;&gt;Code Copy&lt;/button&gt;&lt;/div&gt;
&lt;pre id=&quot;code_pg&quot; class=&quot;odin_pre pgsql&quot;&gt;&lt;code&gt;CREATE OR REPLACE FUNCTION fn_send_mail_odinbox (
    smtp_to text,
    smtp_subject text,
    smtp_content text
)
RETURNS text
AS $$
    import smtplib
    from email.mime.text import MIMEText
    from email.mime.multipart import MIMEMultipart

    # [OdinBOX] SMTP 설정
    smtp_host = &quot;smtp.gmail.com&quot;
    smtp_port = 587
    smtp_user = &quot;helpodinbox@gmail.com&quot;
    smtp_pass = &quot;app_password_key&quot;

    # 메시지 컨테이너 생성
    msg = MIMEMultipart()
    msg['From']    = smtp_user
    msg['To']      = smtp_to
    msg['Subject'] = smtp_subject

    # 본문 내용 UTF-8 인코딩 명시
    msg.attach(MIMEText(smtp_content, 'plain', 'utf-8'))

    try:
        # 서버 연결 및 TLS 승격
        server = smtplib.SMTP(smtp_host, smtp_port)
        server.ehlo()
        server.starttls() # 보안 연결 시작
        server.ehlo()
        
        # 로그인 및 발송
        server.login(smtp_user, smtp_pass)
        server.sendmail(smtp_user, smtp_to, msg.as_string())
        server.quit()
        return &quot;Success: Email Sent via OdinBOX&quot;
    except Exception as e:
        # 상세 에러 메시지 반환
        return f&quot;Error: {str(e)}&quot;
$$ LANGUAGE plpython3u;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div class=&quot;odin_trouble_wrap&quot;&gt;&lt;span class=&quot;odin_trouble_head&quot;&gt;Troubleshooting : PostgreSQL Critical Errors&lt;/span&gt;
&lt;div class=&quot;odin_trouble_item&quot;&gt;&lt;span class=&quot;odin_err_code&quot;&gt;ImportError&lt;/span&gt; &lt;span class=&quot;odin_err_desc&quot;&gt; &lt;b&gt;모듈 미설치 오류 (No module named...)&lt;/b&gt;&lt;br /&gt;PostgreSQL의 PL/Python은 DB 서버 OS의 Python 환경을 공유합니다. 만약 라이브러리가 없다는 에러가 발생하면, DB 서버의 쉘(Shell)에서 &lt;code&gt;pip3 install [모듈명]&lt;/code&gt; 명령어를 통해 필요한 패키지를 설치해야 합니다. &lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;odin_trouble_item&quot;&gt;&lt;span class=&quot;odin_err_code&quot;&gt;SMTPAuthenticationError&lt;/span&gt; &lt;span class=&quot;odin_err_desc&quot;&gt; &lt;b&gt;인증 실패 (Authentication Failed)&lt;/b&gt;&lt;br /&gt;Google 등 최신 메일 서비스는 보안 수준이 낮은 앱에서의 직접 로그인을 차단합니다. 계정의 일반 비밀번호를 사용하면 이 에러가 발생합니다. 반드시 해당 메일 서비스 설정에서 &lt;b&gt;[2단계 인증]&lt;/b&gt;을 활성화한 후, &lt;b&gt;[앱 비밀번호(App Password)]&lt;/b&gt;를 별도로 생성하여 코드 내 &lt;code&gt;smtp_pass&lt;/code&gt; 변수에 적용해야 합니다. &lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;odin_trouble_item&quot;&gt;&lt;span class=&quot;odin_err_code&quot;&gt;Permission Denied&lt;/span&gt; &lt;span class=&quot;odin_err_desc&quot;&gt; &lt;b&gt;권한 부족 (Superuser Required)&lt;/b&gt;&lt;br /&gt;&lt;code&gt;plpython3u&lt;/code&gt; 언어로 작성된 함수를 생성하거나 수정할 때는 반드시 Superuser 권한이 필요합니다. 일반 유저가 사용해야 한다면, 관리자가 함수를 생성한 뒤 &lt;code&gt;GRANT EXECUTE ON FUNCTION...&lt;/code&gt; 명령어로 실행 권한만 부여하는 방식을 사용하십시오. &lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;odin_section&quot;&gt;
&lt;h2 class=&quot;odin_h2&quot; data-ke-size=&quot;size26&quot;&gt;3. 마무리 (Conclusion)&lt;/h2&gt;
&lt;p class=&quot;odin_p&quot; data-ke-size=&quot;size16&quot;&gt;Oracle과 PostgreSQL은 메일 발송이라는 동일한 목적을 달성하기 위해 서로 다른 접근 방식을 취합니다. Oracle은 &lt;code&gt;UTL_SMTP&lt;/code&gt;와 &lt;code&gt;ACL&lt;/code&gt; 설정을 통해 DB 자체의 완결성 있는 기능을 제공하지만, SSL 인증서(Wallet) 관리와 복잡한 인코딩 처리가 진입 장벽이 될 수 있습니다.&lt;/p&gt;
&lt;p class=&quot;odin_p&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;odin_p&quot; data-ke-size=&quot;size16&quot;&gt;반면, PostgreSQL은 Python 생태계를 적극 활용하여 구현 난이도를 대폭 낮추고 코드의 가독성을 높였습니다. 다만, OS 레벨의 패키지 의존성과 Superuser 권한 관리가 필수적이라는 점을 고려해야 합니다. 운영 중인 시스템의 보안 정책과 인프라 환경을 고려하여 가장 적합한 방식을 선택하시기 바랍니다.&lt;/p&gt;
&lt;p class=&quot;odin_p&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;</description>
      <category>IT</category>
      <category>DBMS_NETWORK_ACL_ADMIN</category>
      <category>DB메일발송</category>
      <category>OdinBOX</category>
      <category>PLPython</category>
      <category>PostgreSQL</category>
      <category>SMTP연동</category>
      <category>UTL_SMTP</category>
      <category>데이터베이스</category>
      <category>백엔드개발</category>
      <category>오라클</category>
      <author>간지뽕빨리턴님</author>
      <guid isPermaLink="true">https://odinbox.tistory.com/562</guid>
      <comments>https://odinbox.tistory.com/562#entry562comment</comments>
      <pubDate>Sat, 6 Dec 2025 06:37:09 +0900</pubDate>
    </item>
    <item>
      <title>랜섬웨어(Ransomware)에 대해서 알아보기</title>
      <link>https://odinbox.tistory.com/561</link>
      <description>&lt;div&gt;
&lt;style&gt;
    @import url('https://fonts.googleapis.com/css2?family=Noto+Sans+KR:wght@300;400;500;700;900&amp;display=swap');
    
    * {
        margin: 0;
        padding: 0;
        box-sizing: border-box;
    }
    
    html {
        scroll-behavior: smooth;
    }
    
    .blog-container {
        font-family: 'Noto Sans KR', sans-serif;
        max-width: 1200px;
        margin: 0 auto;
        padding: 40px 20px;
        color: #333;
        line-height: 1.8;
        background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
        animation: backgroundShift 15s ease infinite;
    }
    
    @keyframes backgroundShift {
        0%, 100% { background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%); }
        50% { background: linear-gradient(135deg, #e0c3fc 0%, #8ec5fc 100%); }
    }
    
    /* 다크모드 지원 */
    @media (prefers-color-scheme: dark) {
        .blog-container {
            background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%);
            color: #e0e0e0;
        }
        
        .content-wrapper {
            background: #0f3460 !important;
            color: #e0e0e0;
        }
        
        h1 {
            background: linear-gradient(135deg, #8ec5fc 0%, #e0c3fc 100%) !important;
            -webkit-background-clip: text !important;
            -webkit-text-fill-color: transparent !important;
            background-clip: text !important;
        }
        
        h2 {
            color: #8ec5fc !important;
            border-left-color: #8ec5fc !important;
        }
        
        h3, h4 {
            color: #e0e0e0 !important;
            background: rgba(142, 197, 252, 0.15) !important;
            border-left-color: #8ec5fc !important;
        }
        
        p, li {
            color: #d0d0d0 !important;
        }
        
        .info-box, .warning-box, .intro-box, .reference-box {
            background: rgba(102, 126, 234, 0.2) !important;
            border-left-color: #667eea !important;
        }
        
        .info-box p, .warning-box p, .intro-box p, .reference-box p,
        .info-box li, .warning-box li, .intro-box li, .reference-box li {
            color: #e0e0e0 !important;
        }
        
        .info-box::before, .warning-box::before {
            color: #8ec5fc !important;
        }
        
        .process-step, .prevention-card {
            background: rgba(255, 255, 255, 0.05) !important;
            border-color: #667eea !important;
        }
        
        .process-step h4, .prevention-card h4 {
            color: #8ec5fc !important;
        }
        
        .process-step p, .prevention-card p {
            color: #d0d0d0 !important;
        }
        
        .floating-toc {
            background: rgba(15, 52, 96, 0.95) !important;
            color: #ffffff;
            border: 1px solid rgba(142, 197, 252, 0.3);
        }
        
        .floating-toc h3 {
            color: #8ec5fc !important;
            background: none !important;
            border: none !important;
        }
        
        .floating-toc a {
            color: #b8d4f1 !important;
        }
        
        .floating-toc a:hover {
            background: rgba(142, 197, 252, 0.2) !important;
            color: #8ec5fc !important;
        }
        
        table {
            background: rgba(255, 255, 255, 0.05) !important;
        }
        
        thead {
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%) !important;
        }
        
        tbody tr:hover {
            background: rgba(102, 126, 234, 0.2) !important;
        }
        
        td {
            color: #d0d0d0 !important;
            border-bottom-color: rgba(255, 255, 255, 0.1) !important;
        }
        
        .tag-container {
            background: rgba(255, 255, 255, 0.08) !important;
        }
        
        .tag-title {
            color: #ffffff !important;
        }
        
        .highlight {
            background: rgba(255, 235, 59, 0.3) !important;
            color: #ffeb3b !important;
        }
        
        .meta-info {
            border-bottom-color: rgba(255, 255, 255, 0.1) !important;
        }
        
        .meta-item {
            color: #b0b0b0 !important;
        }
        
        .case-study {
            background: rgba(255, 255, 255, 0.05) !important;
            border-left-color: #f5576c !important;
        }
        
        .case-study h4 {
            color: #f093fb !important;
        }
    }
    
    .content-wrapper {
        background: white;
        padding: 50px;
        border-radius: 20px;
        box-shadow: 0 20px 60px rgba(0,0,0,0.15);
        animation: fadeInUp 1s ease;
        max-width: 900px;
        margin: 0 auto;
    }
    
    @keyframes fadeInUp {
        from {
            opacity: 0;
            transform: translateY(30px);
        }
        to {
            opacity: 1;
            transform: translateY(0);
        }
    }
    
    .read-time {
        display: inline-block;
        background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
        color: white;
        padding: 10px 20px;
        border-radius: 50px;
        font-size: 14px;
        font-weight: 500;
        margin-bottom: 20px;
        animation: pulse 2s ease infinite;
    }
    
    @keyframes pulse {
        0%, 100% { transform: scale(1); }
        50% { transform: scale(1.05); }
    }
    
    h1 {
        font-size: 42px;
        font-weight: 900;
        color: #1a1a2e;
        margin-bottom: 30px;
        line-height: 1.3;
        background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
        -webkit-background-clip: text;
        -webkit-text-fill-color: transparent;
        background-clip: text;
        animation: titleGlow 3s ease infinite;
    }
    
    @keyframes titleGlow {
        0%, 100% { filter: brightness(1); }
        50% { filter: brightness(1.2); }
    }
    
    .meta-info {
        display: flex;
        gap: 20px;
        margin-bottom: 40px;
        padding-bottom: 20px;
        border-bottom: 2px solid #f0f0f0;
        font-size: 14px;
        color: #666;
        flex-wrap: wrap;
    }
    
    .meta-item {
        display: flex;
        align-items: center;
        gap: 8px;
    }
    
    .meta-item::before {
        content: &quot;•&quot;;
        font-size: 16px;
        color: #667eea;
        font-weight: bold;
    }
    
    h2 {
        font-size: 32px;
        font-weight: 700;
        color: #2d3748;
        margin: 50px 0 25px 0;
        padding-left: 20px;
        border-left: 5px solid #667eea;
        animation: slideInLeft 0.8s ease;
        scroll-margin-top: 20px;
    }
    
    @keyframes slideInLeft {
        from {
            opacity: 0;
            transform: translateX(-30px);
        }
        to {
            opacity: 1;
            transform: translateX(0);
        }
    }
    
    h3 {
        font-size: 24px;
        font-weight: 600;
        color: #4a5568;
        margin: 35px 0 20px 0;
        padding: 15px 20px;
        background: linear-gradient(135deg, #f6f8fb 0%, #e9ecf4 100%);
        border-radius: 10px;
        border-left: 4px solid #764ba2;
        transition: all 0.3s ease;
        scroll-margin-top: 20px;
    }
    
    h3:hover {
        transform: translateX(10px);
        box-shadow: 0 5px 15px rgba(0,0,0,0.1);
    }
    
    h4 {
        font-size: 20px;
        font-weight: 700;
        color: #2d3748;
        margin: 25px 0 15px 0;
    }
    
    p {
        font-size: 17px;
        margin-bottom: 20px;
        color: #4a5568;
        text-align: justify;
    }
    
    .intro-box {
        background: linear-gradient(135deg, #ffecd2 0%, #fcb69f 100%);
        padding: 30px;
        border-radius: 15px;
        margin: 30px 0;
        border-left: 6px solid #ff6b6b;
        animation: fadeIn 1.5s ease;
    }
    
    @keyframes fadeIn {
        from { opacity: 0; }
        to { opacity: 1; }
    }
    
    .intro-box p {
        font-weight: 500;
        color: #2d3748;
        margin-bottom: 0;
    }
    
    .warning-box {
        background: linear-gradient(135deg, #ff9a9e 0%, #fecfef 100%);
        padding: 25px;
        border-radius: 12px;
        margin: 25px 0;
        border-left: 6px solid #dc2626;
        animation: shake 0.5s ease;
    }
    
    @keyframes shake {
        0%, 100% { transform: translateX(0); }
        25% { transform: translateX(-5px); }
        75% { transform: translateX(5px); }
    }
    
    .warning-box::before {
        content: &quot;주의&quot;;
        display: block;
        font-size: 18px;
        font-weight: 700;
        color: #dc2626;
        margin-bottom: 10px;
    }
    
    .info-box {
        background: linear-gradient(135deg, #a8edea 0%, #fed6e3 100%);
        padding: 25px;
        border-radius: 12px;
        margin: 25px 0;
        border-left: 6px solid #3b82f6;
        animation: bounceIn 1s ease;
    }
    
    @keyframes bounceIn {
        0% { transform: scale(0.9); opacity: 0; }
        50% { transform: scale(1.05); }
        100% { transform: scale(1); opacity: 1; }
    }
    
    .info-box::before {
        content: &quot;핵심 정보&quot;;
        display: block;
        font-size: 18px;
        font-weight: 700;
        color: #3b82f6;
        margin-bottom: 10px;
    }
    
    ul, ol {
        margin: 20px 0 20px 20px;
        padding-left: 20px;
    }
    
    li {
        margin-bottom: 15px;
        font-size: 17px;
        color: #4a5568;
        line-height: 1.8;
        position: relative;
        padding-left: 10px;
        animation: fadeInList 0.6s ease forwards;
        opacity: 0;
    }
    
    @keyframes fadeInList {
        to { opacity: 1; }
    }
    
    li:nth-child(1) { animation-delay: 0.1s; }
    li:nth-child(2) { animation-delay: 0.2s; }
    li:nth-child(3) { animation-delay: 0.3s; }
    li:nth-child(4) { animation-delay: 0.4s; }
    li:nth-child(5) { animation-delay: 0.5s; }
    li:nth-child(6) { animation-delay: 0.6s; }
    li:nth-child(7) { animation-delay: 0.7s; }
    li:nth-child(8) { animation-delay: 0.8s; }
    
    ul li::before {
        content: &quot;▸&quot;;
        color: #667eea;
        font-weight: bold;
        position: absolute;
        left: -15px;
    }
    
    .highlight {
        background: linear-gradient(135deg, #fff9c4 0%, #ffeb3b 100%);
        padding: 3px 8px;
        border-radius: 5px;
        font-weight: 600;
        color: #1a1a2e;
    }
    
    .stat-grid {
        display: grid;
        grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
        gap: 20px;
        margin: 30px 0;
    }
    
    .stat-card {
        background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
        padding: 25px;
        border-radius: 15px;
        color: white;
        text-align: center;
        box-shadow: 0 10px 30px rgba(102, 126, 234, 0.3);
        transition: all 0.3s ease;
        animation: popIn 0.6s ease;
    }
    
    @keyframes popIn {
        0% { transform: scale(0); opacity: 0; }
        100% { transform: scale(1); opacity: 1; }
    }
    
    .stat-card:hover {
        transform: translateY(-10px) scale(1.05);
        box-shadow: 0 20px 40px rgba(102, 126, 234, 0.5);
    }
    
    .stat-number {
        font-size: 36px;
        font-weight: 900;
        margin-bottom: 10px;
        text-shadow: 2px 2px 4px rgba(0,0,0,0.2);
    }
    
    .stat-label {
        font-size: 16px;
        font-weight: 500;
        opacity: 0.95;
    }
    
    .process-step {
        background: white;
        padding: 25px;
        margin: 20px 0;
        border-radius: 12px;
        border-left: 5px solid #667eea;
        box-shadow: 0 5px 15px rgba(0,0,0,0.08);
        transition: all 0.3s ease;
        animation: slideInRight 0.8s ease;
    }
    
    @keyframes slideInRight {
        from {
            opacity: 0;
            transform: translateX(50px);
        }
        to {
            opacity: 1;
            transform: translateX(0);
        }
    }
    
    .process-step:hover {
        box-shadow: 0 10px 30px rgba(0,0,0,0.15);
        transform: translateX(10px);
    }
    
    .process-step h4 {
        font-size: 20px;
        font-weight: 700;
        color: #667eea;
        margin-bottom: 12px;
    }
    
    .prevention-grid {
        display: grid;
        grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
        gap: 25px;
        margin: 30px 0;
    }
    
    .prevention-card {
        background: linear-gradient(135deg, #f6f8fb 0%, #ffffff 100%);
        padding: 30px;
        border-radius: 15px;
        border: 2px solid #e2e8f0;
        transition: all 0.3s ease;
        animation: zoomIn 0.6s ease;
    }
    
    @keyframes zoomIn {
        from {
            transform: scale(0.8);
            opacity: 0;
        }
        to {
            transform: scale(1);
            opacity: 1;
        }
    }
    
    .prevention-card:hover {
        border-color: #667eea;
        box-shadow: 0 15px 35px rgba(102, 126, 234, 0.2);
        transform: translateY(-5px);
    }
    
    .prevention-card h4 {
        font-size: 20px;
        font-weight: 700;
        color: #2d3748;
        margin-bottom: 15px;
    }
    
    .table-container {
        overflow-x: auto;
        margin: 30px 0;
        border-radius: 12px;
        box-shadow: 0 5px 20px rgba(0,0,0,0.1);
    }
    
    table {
        width: 100%;
        border-collapse: collapse;
        background: white;
    }
    
    thead {
        background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
        color: white;
    }
    
    th {
        padding: 18px;
        text-align: left;
        font-weight: 700;
        font-size: 16px;
        border-bottom: 3px solid #5568d3;
    }
    
    td {
        padding: 16px 18px;
        border-bottom: 1px solid #e2e8f0;
        font-size: 16px;
    }
    
    tbody tr {
        transition: all 0.3s ease;
    }
    
    tbody tr:hover {
        background: linear-gradient(135deg, #f6f8fb 0%, #e9ecf4 100%);
        transform: scale(1.02);
    }
    
    .conclusion-box {
        background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
        color: white;
        padding: 40px;
        border-radius: 15px;
        margin: 40px 0;
        text-align: center;
        box-shadow: 0 15px 40px rgba(102, 126, 234, 0.4);
        animation: fadeInScale 1s ease;
    }
    
    @keyframes fadeInScale {
        from {
            opacity: 0;
            transform: scale(0.9);
        }
        to {
            opacity: 1;
            transform: scale(1);
        }
    }
    
    .conclusion-box h2 {
        color: white;
        border: none;
        padding: 0;
        margin: 0 0 20px 0;
    }
    
    .conclusion-box p {
        color: white;
        font-size: 18px;
        font-weight: 500;
        margin-bottom: 15px;
    }
    
    .tag-container {
        margin: 40px 0 20px 0;
        padding: 25px;
        background: linear-gradient(135deg, #f6f8fb 0%, #e9ecf4 100%);
        border-radius: 12px;
    }
    
    .tag-title {
        font-size: 18px;
        font-weight: 700;
        color: #2d3748;
        margin-bottom: 15px;
    }
    
    .tags {
        display: flex;
        flex-wrap: wrap;
        gap: 12px;
    }
    
    .tag {
        display: inline-block;
        background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
        color: white;
        padding: 8px 18px;
        border-radius: 25px;
        font-size: 14px;
        font-weight: 500;
        transition: all 0.3s ease;
        cursor: pointer;
        animation: tagPop 0.4s ease;
    }
    
    @keyframes tagPop {
        0% { transform: scale(0); }
        50% { transform: scale(1.1); }
        100% { transform: scale(1); }
    }
    
    .tag:hover {
        transform: translateY(-3px) scale(1.1);
        box-shadow: 0 8px 20px rgba(102, 126, 234, 0.4);
    }
    
    .search-tags .tag {
        background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
    }
    
    .reference-box {
        background: linear-gradient(135deg, #e0f7fa 0%, #b2ebf2 100%);
        padding: 25px;
        border-radius: 12px;
        margin: 30px 0;
        border-left: 6px solid #00acc1;
    }
    
    .reference-box h4 {
        font-size: 20px;
        font-weight: 700;
        color: #00838f;
        margin-bottom: 15px;
    }
    
    .reference-box ul {
        margin: 0;
        padding-left: 20px;
    }
    
    .reference-box li {
        color: #00695c;
        font-weight: 500;
    }
    
    .reference-box a {
        color: #00838f;
        text-decoration: none;
        font-weight: 600;
        transition: all 0.3s ease;
    }
    
    .reference-box a:hover {
        color: #00acc1;
        text-decoration: underline;
    }
    
    .case-study {
        background: linear-gradient(135deg, #ffeef8 0%, #ffe8f5 100%);
        padding: 25px;
        border-radius: 12px;
        margin: 25px 0;
        border-left: 6px solid #f5576c;
        animation: fadeIn 1s ease;
    }
    
    .case-study h4 {
        font-size: 20px;
        font-weight: 700;
        color: #d81b60;
        margin-bottom: 15px;
    }
    
    .case-study p {
        color: #4a5568;
        margin-bottom: 12px;
    }
    
    .floating-toc {
        background: white;
        padding: 25px;
        border-radius: 12px;
        box-shadow: 0 5px 20px rgba(0,0,0,0.1);
        animation: slideDown 0.6s ease;
        margin-bottom: 40px;
        border: 2px solid #667eea;
    }
    
    @keyframes slideDown {
        from {
            opacity: 0;
            transform: translateY(-20px);
        }
        to {
            opacity: 1;
            transform: translateY(0);
        }
    }
    
    .floating-toc h3 {
        background: none;
        border: none;
        padding: 0;
        margin: 0 0 15px 0;
        font-size: 20px;
    }
    
    .floating-toc ul {
        margin: 0;
        padding-left: 0;
        list-style: none;
    }
    
    .floating-toc li {
        margin-bottom: 8px;
        padding-left: 0;
        animation: none;
        opacity: 1;
    }
    
    .floating-toc li::before {
        content: none;
    }
    
    .floating-toc a {
        color: #667eea;
        text-decoration: none;
        font-weight: 500;
        transition: all 0.3s ease;
        display: block;
        padding: 8px 12px;
        border-radius: 6px;
        font-size: 15px;
    }
    
    .floating-toc a:hover {
        background: linear-gradient(135deg, #f6f8fb 0%, #e9ecf4 100%);
        transform: translateX(5px);
    }
    
    @media (max-width: 768px) {
        .content-wrapper {
            padding: 30px 20px;
        }
        
        h1 {
            font-size: 32px;
        }
        
        h2 {
            font-size: 26px;
        }
        
        h3 {
            font-size: 20px;
        }
        
        .stat-grid,
        .prevention-grid {
            grid-template-columns: 1fr;
        }
        
        .meta-info {
            flex-direction: column;
            gap: 10px;
        }
    }
  
  .hero-thumbnail {
    width: 100%;
    text-align: center;
    margin-bottom: 40px;
    position: relative;
    animation: fadeIn 1.2s ease;
}

.hero-img-wrapper img {
    width: 60%;
    max-width: 420px;
    border-radius: 20px;
    box-shadow: 0 10px 30px rgba(0,0,0,0.15);
    margin: 0 auto;
}

.hero-caption {
    margin-top: 25px;
}

.hero-title {
    font-size: 38px;
    font-weight: 900;
    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
    -webkit-background-clip: text;
    -webkit-text-fill-color: transparent;
    margin-bottom: 10px;
    animation: titleGlow 3s ease-in-out infinite;
}

.hero-sub {
    font-size: 18px;
    color: #444;
    font-weight: 500;
    opacity: 0.9;
}

/* Dark mode 대응 */
@media (prefers-color-scheme: dark) {
    .hero-sub {
        color: #ddd !important;
    }
}

/* 애니메이션 */
@keyframes fadeIn {
    from { opacity: 0; transform: translateY(20px); }
    to { opacity: 1; transform: translateY(0); }
}
@keyframes titleGlow {
    0%,100% { filter: brightness(1); }
    50% { filter: brightness(1.25); }
}

/* 모바일 최적화 */
@media (max-width: 768px) {
    .hero-img-wrapper img {
        width: 80%;
    }
    .hero-title {
        font-size: 30px;
    }
    .hero-sub {
        font-size: 16px;
    }
}
&lt;/style&gt;
&lt;/div&gt;
&lt;div class=&quot;blog-container&quot;&gt;
&lt;div class=&quot;content-wrapper&quot;&gt;
&lt;div class=&quot;read-time&quot;&gt;예상 읽기 시간 : 약 18분&lt;/div&gt;
&lt;div class=&quot;hero-thumbnail&quot;&gt;
&lt;div class=&quot;hero-img-wrapper&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;글 상단 부분 대표 이미지 (1).png&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bFvTdN/dJMcaiuX1HL/lkLCYKlp0ZwaffR4BVQQy0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bFvTdN/dJMcaiuX1HL/lkLCYKlp0ZwaffR4BVQQy0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bFvTdN/dJMcaiuX1HL/lkLCYKlp0ZwaffR4BVQQy0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbFvTdN%2FdJMcaiuX1HL%2FlkLCYKlp0ZwaffR4BVQQy0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;400&quot; data-filename=&quot;글 상단 부분 대표 이미지 (1).png&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;div class=&quot;hero-caption&quot;&gt;
&lt;h1 class=&quot;hero-title&quot;&gt;랜섬웨어 완벽 가이드&lt;/h1&gt;
&lt;p class=&quot;hero-sub&quot; data-ke-size=&quot;size16&quot;&gt;원리 &amp;middot; 배포 경로 &amp;middot; 예방 &amp;middot; 대응 총정리&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;meta-info&quot;&gt;
&lt;div class=&quot;meta-item&quot;&gt;정보보안&lt;/div&gt;
&lt;div class=&quot;meta-item&quot;&gt;랜섬웨어 대응&lt;/div&gt;
&lt;div class=&quot;meta-item&quot;&gt;2025년 최신 정보&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;floating-toc&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;목차&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;#intro&quot;&gt;왜 지금 랜섬웨어를 알아야 하는가&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#what&quot;&gt;랜섬웨어란 무엇인가&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#principle&quot;&gt;랜섬웨어의 작동 원리&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#distribution&quot;&gt;주요 배포 경로&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#cases&quot;&gt;최근 주요 사례&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#prevention&quot;&gt;예방 방법&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#government&quot;&gt;정부 공식 문서 및 대응 체계&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#recovery&quot;&gt;복구 방법&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#conclusion&quot;&gt;마무리&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;section id=&quot;intro&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;왜 지금 랜섬웨어를 알아야 하는가&lt;/h2&gt;
&lt;div class=&quot;intro-box&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최근 몇 년간 전 세계적으로 랜섬웨어 공격이 급증하면서, 개인부터 대기업, 정부 기관까지 막대한 피해를 입고 있습니다. 단순히 컴퓨터 바이러스의 일종으로 생각했던 랜섬웨어는 이제 조직의 운영을 마비시키고 수십억 원의 금전적 손실을 야기하는 심각한 사이버 위협으로 자리 잡았습니다.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;stat-grid&quot;&gt;
&lt;div class=&quot;stat-card&quot;&gt;
&lt;div class=&quot;stat-number&quot;&gt;493억원&lt;/div&gt;
&lt;div class=&quot;stat-label&quot;&gt;2024년 평균 피해액&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;stat-card&quot;&gt;
&lt;div class=&quot;stat-number&quot;&gt;11초&lt;/div&gt;
&lt;div class=&quot;stat-label&quot;&gt;랜섬웨어 공격 발생 주기&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;stat-card&quot;&gt;
&lt;div class=&quot;stat-number&quot;&gt;72%&lt;/div&gt;
&lt;div class=&quot;stat-label&quot;&gt;중소기업 타겟 비율&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 글에서는 랜섬웨어가 무엇인지, 어떻게 작동하는지, 주요 감염 경로는 무엇인지, 그리고 가장 중요한 예방과 대응 방법까지 실무에서 바로 활용할 수 있는 정보를 전문가와 초보자 모두가 이해할 수 있도록 상세하게 정리했습니다. 정부 공식 문서와 최신 보안 동향을 기반으로 작성되었으니, 끝까지 읽어보시고 소중한 데이터를 안전하게 지키시기 바랍니다.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;what&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;랜섬웨어란 무엇인가&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1.1 랜섬웨어의 정의&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;랜섬웨어(Ransomware)는 &lt;span class=&quot;highlight&quot;&gt;랜섬(Ransom, 몸값)&lt;/span&gt;과 &lt;span class=&quot;highlight&quot;&gt;소프트웨어(Software)&lt;/span&gt;의 합성어로, 사용자의 파일이나 시스템을 암호화하여 사용할 수 없게 만든 뒤, 이를 복구하는 대가로 금전을 요구하는 악성 소프트웨어입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쉽게 말해, 여러분의 중요한 문서, 사진, 데이터베이스 등을 디지털 자물쇠로 잠가버린 후 &quot;열쇠를 원하면 돈을 내라&quot;라고 협박하는 것입니다. 마치 현실 세계에서 인질을 잡고 몸값을 요구하는 것과 동일한 개념이지만, 디지털 환경에서 발생한다는 차이가 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;랜섬웨어의 역사는 1989년 AIDS Trojan까지 거슬러 올라가지만, 본격적으로 위협이 된 것은 2013년 CryptoLocker가 등장하면서부터입니다. 이후 WannaCry(2017), NotPetya(2017), Ryuk(2018), Sodinokibi/REvil(2019), LockBit(2019-현재) 등 점점 더 정교하고 파괴적인 변종들이 등장하고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 랜섬웨어는 단순한 사이버 범죄를 넘어 &lt;b&gt;조직화된 범죄 산업&lt;/b&gt;으로 발전했습니다. 전문 개발자, 협상가, 돈세탁 전문가 등으로 구성된 범죄 조직이 마치 기업처럼 운영되고 있으며, 연간 수조 원의 불법 수익을 올리고 있습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1.2 랜섬웨어의 종류&lt;/h3&gt;
&lt;div class=&quot;table-container&quot;&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;종류&lt;/th&gt;
&lt;th&gt;특징&lt;/th&gt;
&lt;th&gt;대표 사례&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;암호화형&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;파일을 암호화하여 접근 불가능하게 만듦&lt;/td&gt;
&lt;td&gt;WannaCry, Ryuk, LockBit&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;잠금형&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;시스템 자체를 잠가 사용 불가능하게 만듦&lt;/td&gt;
&lt;td&gt;Reveton, WinLocker&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;유출협박형&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;데이터를 탈취하여 공개하겠다고 협박&lt;/td&gt;
&lt;td&gt;Maze, DoppelPaymer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;이중 갈취형&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;암호화 + 데이터 유출 협박 병행&lt;/td&gt;
&lt;td&gt;REvil, Conti, LockBit 3.0&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class=&quot;info-box&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최근에는 단순히 파일을 암호화하는 것을 넘어, 중요한 데이터를 먼저 탈취한 후 암호화하고, 몸값을 지불하지 않으면 데이터를 공개하겠다고 협박하는 &lt;b&gt;이중 갈취(Double Extortion)&lt;/b&gt; 방식이 주류를 이루고 있습니다. 이는 피해자가 백업을 보유하고 있더라도 데이터 유출로 인한 평판 손상과 법적 책임 때문에 몸값을 지불할 수밖에 없게 만드는 전략입니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;principle&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;랜섬웨어의 작동 원리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;랜섬웨어가 어떻게 작동하는지 이해하면 예방과 대응에 큰 도움이 됩니다. 일반적인 랜섬웨어 공격은 다음과 같은 단계로 진행됩니다.&lt;/p&gt;
&lt;div class=&quot;process-step&quot;&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1단계 : 초기 침투 (Initial Access)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;공격자는 피싱 이메일, 취약한 원격 접속 서비스(RDP), 악성 웹사이트, 소프트웨어 취약점 등을 통해 시스템에 최초로 침입합니다. 이 단계에서는 사용자가 악성 첨부파일을 열거나 악성 링크를 클릭하는 등의 행위가 발생하는 경우가 많습니다.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;process-step&quot;&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2단계 : 권한 상승 및 내부 이동 (Privilege Escalation &amp;amp; Lateral Movement)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;초기 침투에 성공한 공격자는 시스템 내에서 관리자 권한을 획득하려 시도합니다. Windows의 경우 취약한 설정이나 패치되지 않은 보안 허점을 이용해 권한을 상승시킵니다. 이후 네트워크 내 다른 시스템으로 이동하여 공격 범위를 확대합니다.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;process-step&quot;&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3단계 : 데이터 탐색 및 탈취 (Data Discovery &amp;amp; Exfiltration)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;공격자는 네트워크 내에서 중요한 데이터(고객 정보, 재무 데이터, 기밀 문서 등)를 찾아냅니다. 최근 랜섬웨어 그룹들은 암호화 전에 이러한 데이터를 외부 서버로 유출시켜 이중 갈취의 수단으로 활용합니다.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;process-step&quot;&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;4단계 : 암호화 실행 (Encryption)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 단계가 랜섬웨어 공격의 핵심입니다. 공격자는 &lt;span class=&quot;highlight&quot;&gt;AES-256, RSA-2048 이상의 강력한 암호화 알고리즘&lt;/span&gt;을 사용하여 파일을 암호화합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;암호화 과정의 기술적 세부사항&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;대칭키 암호화 (AES)&lt;/b&gt; : 각 파일은 고유한 AES-256 키로 암호화됩니다. AES는 암호화와 복호화 속도가 빠르기 때문에 대용량 파일 처리에 적합합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;비대칭키 암호화 (RSA)&lt;/b&gt; : AES로 파일을 암호화한 후, 그 AES 키 자체를 RSA 공개키로 암호화합니다. RSA 개인키는 공격자만 가지고 있으므로, 공격자 없이는 AES 키를 복구할 수 없습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;타겟 파일 선별&lt;/b&gt; : 모든 파일을 암호화하지 않습니다. 문서(.docx, .xlsx, .pdf), 이미지(.jpg, .png), 데이터베이스(.sql, .mdb), 백업 파일(.bak), 압축 파일(.zip, .rar) 등 가치가 높은 확장자만 선별적으로 암호화합니다. 운영체제 핵심 파일은 암호화하지 않아 시스템이 부팅되고 몸값 요구 메시지를 표시할 수 있게 합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;암호화 속도&lt;/b&gt; : 최신 랜섬웨어는 멀티스레딩을 사용하여 여러 파일을 동시에 처리합니다. SSD 기준으로 1GB 파일을 수 초 내에 암호화할 수 있으며, 일반적인 사무용 PC의 모든 문서를 10분 이내에 암호화할 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;원본 파일 삭제&lt;/b&gt; : 암호화된 사본을 만든 후 원본 파일은 안전하게 삭제됩니다. 단순 삭제가 아닌 덮어쓰기(Overwrite) 방식을 사용하여 데이터 복구 도구로도 복원할 수 없게 만듭니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;섀도우 카피 삭제&lt;/b&gt; : Windows의 볼륨 섀도우 카피(Volume Shadow Copy)와 시스템 복원 지점을 삭제하여 Windows 내장 복구 기능을 무력화합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;백업 파일 탐색&lt;/b&gt; : 네트워크 드라이브, 클라우드 동기화 폴더, 외장 하드 등을 탐색하여 백업 파일까지 암호화합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반적으로 문서, 이미지, 데이터베이스, 백업 파일 등 가치가 높은 파일들을 우선적으로 암호화합니다. 암호화 속도는 매우 빠르며, 수 분 내에 수천 개의 파일이 암호화될 수 있습니다. 암호화된 파일은 원본 이름에 특정 확장자(. locked,. encrypted,. crypt 등)가 추가되어 쉽게 식별할 수 있습니다.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;process-step&quot;&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;5단계 : 몸값 요구 (Ransom Demand)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;암호화가 완료되면 바탕화면에 몸값 요구 메시지가 표시됩니다. 일반적으로 비트코인이나 모네로 같은 암호화폐로 일정 금액을 지불하면 복호화 키를 제공하겠다고 약속합니다. 대부분의 경우 72시간 내에 지불하지 않으면 금액이 상승하거나 복호화 키를 영구 삭제하겠다고 협박합니다.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;warning-box&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;랜섬웨어에 사용되는 암호화 알고리즘은 현대 암호학 기술을 기반으로 하며, &lt;b&gt;복호화 키 없이는 사실상 복구가 불가능&lt;/b&gt;합니다. AES-256 암호화의 경우, 전 세계 모든 컴퓨터를 동원해도 수십억 년이 걸려야 해독할 수 있을 정도로 강력합니다. 따라서 예방이 최선의 방어책입니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;distribution&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;랜섬웨어 주요 배포 경로&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;랜섬웨어가 어떻게 유입되는지 알면 감염을 사전에 차단할 수 있습니다. 다음은 실제로 가장 많이 사용되는 배포 경로들입니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3.1 피싱 이메일 (Phishing Email)&lt;/h3&gt;
&lt;div class=&quot;info-box&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;전체 랜섬웨어 감염의 약 45%&lt;/b&gt;가 피싱 이메일을 통해 발생합니다. 공격자는 택배 배송 안내, 세금 고지서, 업무 문서, 청구서, 법원 소환장 등을 가장한 이메일에 악성 첨부파일(주로 .doc, .xls, .pdf, .zip)을 포함시키거나 악성 링크를 삽입합니다.&lt;/p&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;피싱 이메일의 주요 유형과 특징&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;매크로 활성화 유도&lt;/b&gt; : Word나 Excel 파일을 열면 &quot;이 문서는 이전 버전에서 작성되었습니다. 내용을 보려면 매크로를 활성화하세요&quot; 또는 &quot;콘텐츠 사용&quot;을 클릭하라는 메시지가 표시됩니다. 사용자가 매크로를 활성화하면 숨겨진 악성 스크립트가 실행되어 랜섬웨어를 다운로드하고 설치합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;악성 링크 클릭&lt;/b&gt; : &quot;배송 조회하기&quot;, &quot;청구서 확인&quot;, &quot;비밀번호 재설정&quot; 등의 버튼이나 링크를 클릭하면 악성 사이트로 연결됩니다. 이 사이트는 정상 사이트처럼 보이지만, 백그라운드에서 자동으로 랜섬웨어를 다운로드하거나 브라우저 취약점을 악용하여 시스템에 침투합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;스피어 피싱 (Spear Phishing)&lt;/b&gt; : 특정 조직이나 개인을 타겟으로 한 정교한 피싱 공격입니다. 공격자는 SNS, LinkedIn, 회사 웹사이트 등에서 정보를 수집하여 실제 업무 담당자 이름, 프로젝트명, 내부 용어 등을 사용합니다. 예를 들어 &quot;김대리님, 지난번 요청하신 Q4 실적 보고서를 첨부합니다&quot;와 같이 매우 구체적이고 신뢰할 만한 내용으로 작성됩니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;CEO 사칭 공격 (CEO Fraud)&lt;/b&gt; : 대표이사나 임원을 사칭하여 &quot;긴급 건이니 첨부 파일 확인 후 바로 처리해주세요&quot;와 같은 긴박한 톤으로 직원에게 압박을 가합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;피싱 이메일 식별 방법&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;발신자 주소 확인&lt;/b&gt; : @naver.com이 아닌 @naver-com.tk처럼 유사한 도메인을 사용하거나, 알 수 없는 메일 주소에서 발송됩니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;맞춤법과 어색한 표현&lt;/b&gt; : 기계 번역을 사용한 듯한 어색한 한국어, 불필요한 띄어쓰기, 맞춤법 오류가 많습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;긴급성 강조&lt;/b&gt; : &quot;24시간 이내&quot;, &quot;즉시 확인&quot;, &quot;법적 조치&quot; 등 긴박감을 조성하여 신중한 판단을 방해합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;첨부파일 확장자&lt;/b&gt; : .exe, .scr, .bat, .js, .vbs 등 실행 파일이거나, .zip 안에 실행 파일이 들어있는 경우가 많습니다. document.pdf.exe처럼 이중 확장자를 사용하기도 합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;링크 주소 확인&lt;/b&gt; : 링크 위에 마우스를 올려보면(클릭하지 말고) 실제 URL이 표시됩니다. 표시된 텍스트와 실제 URL이 다르면 의심해야 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3.2 원격 데스크톱 프로토콜(RDP) 공격&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;RDP(Remote Desktop Protocol)는 Microsoft가 개발한 프로토콜로, 원격으로 다른 컴퓨터에 접속하여 마치 그 컴퓨터 앞에 앉아 있는 것처럼 사용할 수 있게 해줍니다. 많은 기업들이 재택근무, 원격 관리, IT 지원 등을 위해 RDP를 사용하지만, 보안 설정이 미흡하면 공격자에게 직접적인 침투 경로를 제공하게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;RDP가 위험한 이유&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;직접적인 시스템 접근&lt;/b&gt; : RDP로 로그인하면 공격자는 정상 사용자와 동일한 권한을 가지므로, 별도의 권한 상승 과정 없이 바로 파일 암호화나 데이터 탈취를 수행할 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;인터넷 노출&lt;/b&gt; : Shodan, Censys 같은 검색 엔진을 통해 인터넷에 노출된 RDP 포트(기본 3389)를 쉽게 찾을 수 있습니다. 2024년 기준으로 전 세계에 약 300만 개 이상의 RDP 서비스가 인터넷에 직접 노출되어 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;약한 인증&lt;/b&gt; : 많은 시스템이 여전히 단순한 비밀번호만으로 보호되고 있으며, 다중 인증(MFA)이 설정되지 않은 경우가 많습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;RDP를 통한 공격 방법&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;무차별 대입 공격(Brute Force Attack)&lt;/b&gt; : 공격자는 자동화 도구(Hydra, Medusa 등)를 사용하여 일반적인 비밀번호 조합(admin/admin, administrator/password, user123/password123 등)과 사전 공격(Dictionary Attack)을 수행합니다. 계정 잠금 정책이 없거나 느슨하면 수백만 개의 조합을 시도할 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;자격증명 스터핑(Credential Stuffing)&lt;/b&gt; : 다크웹에서 유출된 수십억 개의 이메일/비밀번호 조합 데이터베이스를 구매하여 RDP 로그인을 시도합니다. 많은 사람들이 여러 서비스에서 동일한 비밀번호를 사용하므로 성공률이 높습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;포트 스캐닝&lt;/b&gt; : Masscan, Nmap 같은 도구로 특정 IP 대역에서 3389 포트가 열려 있는 시스템을 찾아냅니다. 발견된 시스템에 대해 자동으로 로그인 시도를 수행합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;BlueKeep 등 RDP 취약점 악용&lt;/b&gt; : 2019년 발견된 BlueKeep(CVE-2019-0708)처럼 RDP 자체의 보안 취약점을 악용하여 인증 없이 시스템에 침투하는 경우도 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;실제 공격 시나리오&lt;/b&gt; :&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;공격자가 RDP로 로그인에 성공하면, 먼저 시스템을 조사합니다. 네트워크 구조를 파악하고, 백업 위치를 찾으며, 중요 데이터가 어디에 있는지 확인합니다. 그 다음 백신 소프트웨어를 비활성화하고, Windows Defender를 끄고, 방화벽 규칙을 수정합니다. 준비가 완료되면 랜섬웨어를 업로드하여 실행하거나, 네트워크 공유를 통해 다른 시스템으로 전파합니다. 이 모든 과정은 정상적인 관리 작업처럼 보이므로 탐지가 어렵습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3.3 악성 웹사이트 및 드라이브 바이 다운로드&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용자가 악성 코드가 삽입된 웹사이트를 방문하기만 해도 자동으로 랜섬웨어가 다운로드되는 방식입니다. 정상적인 웹사이트가 해킹되어 악성 스크립트가 삽입되는 경우도 많습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;멀버타이징(Malvertising)&lt;/b&gt; : 합법적인 광고 네트워크에 악성 광고를 게재하여, 사용자가 광고를 클릭하거나 광고가 표시된 페이지를 방문하기만 해도 감염됩니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;워터링 홀 공격&lt;/b&gt; : 특정 업계나 조직의 사람들이 자주 방문하는 웹사이트를 해킹하여 악성코드를 심어둡니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3.4 소프트웨어 취약점 악용&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;운영체제나 애플리케이션의 보안 취약점을 이용해 랜섬웨어를 설치합니다. 대표적인 사례가 2017년 전 세계적으로 큰 피해를 입힌 &lt;b&gt;WannaCry&lt;/b&gt;입니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;EternalBlue 취약점&lt;/b&gt; : WannaCry는 Windows SMB 프로토콜의 취약점을 악용하여 네트워크 내에서 자동으로 전파되었습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;제로데이 취약점&lt;/b&gt; : 아직 패치가 나오지 않은 알려지지 않은 취약점을 악용합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;오래된 시스템&lt;/b&gt; : 보안 업데이트가 중단된 구형 운영체제(Windows 7, Windows Server 2008 등)는 특히 취약합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3.5 공급망 공격 (Supply Chain Attack)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;신뢰할 수 있는 소프트웨어 공급업체나 서비스 제공업체를 해킹하여, 그들의 소프트웨어 업데이트나 서비스를 통해 랜섬웨어를 배포하는 방식입니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Kaseya VSA 공격&lt;/b&gt; : 2021년, REvil 랜섬웨어 그룹이 IT 관리 소프트웨어인 Kaseya VSA를 해킹하여 전 세계 수천 개 기업에 랜섬웨어를 배포했습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;소프트웨어 업데이트 변조&lt;/b&gt; : 정상적인 소프트웨어 업데이트에 악성코드를 삽입하여 배포합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3.6 USB 및 이동식 저장장치&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;감염된 USB 드라이브나 외장 하드를 컴퓨터에 연결하면 자동으로 랜섬웨어가 실행되는 경우도 있습니다. 특히 폐쇄망 환경에서는 이러한 물리적 매체가 주요 감염 경로가 됩니다.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;cases&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;최근 주요 랜섬웨어 사례&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제 발생한 대규모 랜섬웨어 공격 사례를 통해 그 심각성과 대응 방법을 배울 수 있습니다. 다음은 전 세계적으로 큰 영향을 미친 주요 사건들입니다.&lt;/p&gt;
&lt;div class=&quot;case-study&quot;&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;WannaCry 글로벌 대란 (2017년 5월)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;공격 그룹&lt;/b&gt; : 북한 연계 해킹 그룹으로 추정 (Lazarus Group)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;피해 규모&lt;/b&gt; : 전 세계 150개국 이상, 약 30만 대의 컴퓨터가 감염되었으며, 총 피해액은 약 40억 달러(약 4조 8천억 원)로 추산됩니다. 영국의 국가보건서비스(NHS)는 81개 병원이 마비되어 수술이 취소되고 응급실이 폐쇄되는 등 심각한 피해를 입었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;공격 방법&lt;/b&gt; : NSA(미국 국가안보국)에서 유출된 EternalBlue 취약점을 악용하여 Windows SMB 프로토콜의 보안 허점을 통해 자동으로 전파되었습니다. 패치되지 않은 Windows 7과 Windows Server 시스템이 주요 타겟이 되었으며, 한 번 감염되면 네트워크 내 모든 취약한 시스템으로 자동 확산되는 웜(Worm) 형태였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;영향 및 교훈&lt;/b&gt; : 이 사건은 전 세계적으로 사이버 보안의 중요성을 일깨웠습니다. 특히 오래된 운영체제의 위험성과 정기적인 보안 패치의 필수성이 부각되었으며, 많은 기업과 기관이 백업 시스템과 재해 복구 계획을 재정비하는 계기가 되었습니다. Microsoft는 이미 지원이 종료된 Windows XP에 대해서도 긴급 보안 패치를 제공했습니다.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;case-study&quot;&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Colonial Pipeline 미국 에너지 인프라 공격 (2021년 5월)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;공격 그룹&lt;/b&gt; : DarkSide (러시아 기반 랜섬웨어 조직)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;피해 규모&lt;/b&gt; : 미국 동부 해안 연료 공급의 45%를 담당하는 송유관 시스템이 6일간 완전히 마비되었으며, 하루 250만 배럴의 연료 운송이 중단되었습니다. Colonial Pipeline은 440만 달러(약 49억 원)의 비트코인 몸값을 지불했으며, 미국 정부는 일부 금액을 추적하여 회수했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;공격 방법&lt;/b&gt; : 공격자들은 다크웹에서 유출된 VPN 계정 정보를 구매하여 Colonial Pipeline의 네트워크에 접근했습니다. 해당 VPN 계정은 다중 인증(MFA)이 설정되지 않았으며, 더 이상 사용하지 않는 계정이었지만 비활성화되지 않은 상태였습니다. 공격자들은 약 90GB의 데이터를 탈취한 후 시스템을 암호화했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;영향 및 교훈&lt;/b&gt; : 미국 동부 지역 주유소에서 대규모 연료 부족 사태가 발생했으며, 일부 지역에서는 주유소의 70% 이상이 연료가 바닥났습니다. 바이든 대통령은 국가 비상사태를 선포했으며, 이 사건 이후 미국은 랜섬웨어를 국가 안보 위협으로 공식 지정했습니다. 중요 인프라 보호를 위한 새로운 사이버 보안 규제가 도입되었으며, 모든 VPN 계정에 대한 MFA 의무화가 권고되었습니다.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;case-study&quot;&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Kaseya VSA 공급망 공격 (2021년 7월)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;공격 그룹&lt;/b&gt; : REvil (Sodinokibi) - 러시아 기반 조직&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;피해 규모&lt;/b&gt; : IT 관리 소프트웨어인 Kaseya VSA를 사용하는 약 60개의 MSP(관리형 서비스 제공업체)와 그들의 고객사 약 1,500개 기업이 동시에 감염되었습니다. 공격자들은 초기에 7,000만 달러(약 800억 원)의 몸값을 요구했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;공격 방법&lt;/b&gt; : 공격자들은 Kaseya VSA의 제로데이 취약점을 발견하고 악용했습니다. 이 소프트웨어는 IT 서비스 제공업체들이 여러 고객사의 시스템을 원격으로 관리하는 데 사용되므로, 하나의 취약점을 통해 수천 개의 기업을 동시에 공격할 수 있었습니다. 공격은 금요일 오후(미국 독립기념일 연휴 직전)에 실행되어 대응 시간을 최소화했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;영향 및 교훈&lt;/b&gt; : 스웨덴의 대형 슈퍼마켓 체인 Coop의 800개 매장이 영업을 중단했으며, POS 시스템과 계산대가 모두 작동을 멈췄습니다. 뉴질랜드의 여러 학교와 유치원도 폐쇄되었습니다. 이 사건은 공급망 공격(Supply Chain Attack)의 위험성을 명확히 보여주었으며, 신뢰할 수 있는 소프트웨어 공급업체라도 보안 취약점이 있을 수 있음을 증명했습니다. 많은 기업들이 제3자 소프트웨어에 대한 보안 평가를 강화하게 되었습니다.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;case-study&quot;&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;JBS Foods 글로벌 육류 공급망 공격 (2021년 6월)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;공격 그룹&lt;/b&gt; : REvil&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;피해 규모&lt;/b&gt; : 세계 최대 육류 가공업체인 JBS의 미국, 캐나다, 호주 전역의 공장이 일시적으로 가동 중단되었습니다. 미국 쇠고기 생산량의 약 20%가 영향을 받았으며, JBS는 1,100만 달러(약 123억 원)의 몸값을 지불했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;공격 방법&lt;/b&gt; : 공격자들은 JBS의 북미 및 호주 IT 시스템을 타겟으로 하여 생산 관리 시스템과 서버를 암호화했습니다. 백업 시스템은 무사했지만, 완전한 복구에는 시간이 필요했고, 식품 공급망 차질을 우려하여 몸값을 지불하기로 결정했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;영향 및 교훈&lt;/b&gt; : 미국 농무부는 육류 가격 급등과 공급 부족을 우려했으며, 백악관이 직접 개입하여 상황을 모니터링했습니다. 이 사건은 식품 공급망의 디지털 의존도와 랜섬웨어가 국가 식량 안보에 미칠 수 있는 영향을 보여주었습니다. 제조업 및 물류 산업에서 운영 기술(OT) 시스템의 보안 강화 필요성이 대두되었습니다.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;case-study&quot;&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;대만 반도체 업체 TSMC 협력업체 공격 (2023년 6월)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;공격 그룹&lt;/b&gt; : LockBit 3.0&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;피해 규모&lt;/b&gt; : 세계 최대 반도체 제조업체 TSMC의 주요 협력업체인 Kinmax Technology가 공격당해 약 7,000만 달러(약 900억 원)의 몸값을 요구받았습니다. 공격자들은 TSMC와 Apple, AMD 등 주요 고객사의 기밀 정보를 탈취했다고 주장했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;공격 방법&lt;/b&gt; : LockBit 3.0은 이중 갈취(Double Extortion) 전략을 사용하여 먼저 약 1.5TB의 데이터를 탈취한 후 시스템을 암호화했습니다. 탈취된 데이터에는 제품 설계도, 고객 정보, 재무 데이터 등이 포함된 것으로 알려졌으며, 몸값을 지불하지 않으면 이를 공개하겠다고 협박했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;영향 및 교훈&lt;/b&gt; : 글로벌 반도체 공급망에 대한 우려가 증가했으며, 특히 중요한 기술 정보가 유출될 가능성에 업계가 긴장했습니다. TSMC는 직접적인 피해는 없었지만 협력업체를 통한 간접적인 데이터 유출 위험을 재평가했습니다. 이 사건 이후 제조업 분야에서 공급망 전체의 사이버 보안 수준을 균일하게 높이는 것의 중요성이 강조되었습니다.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;case-study&quot;&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;한국 주요 기업 및 기관 연쇄 공격 (2023-2024년)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;피해 규모&lt;/b&gt; : 2024년 상반기에만 국내에서 랜섬웨어 관련 신고가 전년 대비 34% 증가했으며, 주요 제조업체(자동차 부품, 반도체 장비), 물류업체, 의료기관, 건설사 등이 연쇄적으로 공격당했습니다. 국내 중견 제조업체의 경우 평균 15억~50억 원의 몸값을 요구받았습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;주요 공격 그룹&lt;/b&gt; : LockBit 3.0, ALPHV/BlackCat, Play 랜섬웨어, Akira 등 다양한 랜섬웨어 조직이 한국 기업을 타겟으로 했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;공격 방법&lt;/b&gt; : 대부분의 공격은 취약한 VPN 또는 RDP를 통한 초기 침투로 시작되었으며, 일부는 공급망 공격이나 스피어 피싱을 활용했습니다. 이중 갈취 방식이 주를 이루었으며, 개인정보보호법 위반에 따른 과징금과 소송 우려를 악용하여 몸값 지불을 압박했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;특징 및 영향&lt;/b&gt; : 한국 기업들은 특히 중소기업의 경우 보안 투자가 부족하여 공격자들의 주요 타겟이 되고 있습니다. 공격자들은 한국 기업의 재무 상황을 사전에 조사하여 지불 능력이 있는 기업을 선별적으로 공격합니다. 또한 한국어로 된 협박 메시지를 사용하고, 한국 시간대에 맞춰 공격을 실행하는 등 점점 더 정교해지고 있습니다. KISA에 따르면 공격당한 기업 중 약 30%가 몸값을 지불했지만, 이 중 15%는 완전한 복구에 실패했습니다.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;info-box&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최근 랜섬웨어 공격의 핵심 트렌드는 다음과 같습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;표적화된 공격 (Targeted Attack)&lt;/b&gt; : 과거의 무차별적 공격에서 벗어나, 공격 대상 기업을 면밀히 조사한 후 재무 상황, 업종, 중요도를 평가하여 선별적으로 공격합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;이중/삼중 갈취&lt;/b&gt; : 단순 암호화를 넘어 데이터 탈취 후 협박, DDoS 공격 병행, 고객/파트너사에 직접 연락하여 압박하는 등 다각도의 압박 전술을 사용합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;공급망 공격 증가&lt;/b&gt; : 보안이 강화된 대기업 대신 상대적으로 취약한 협력업체나 소프트웨어 공급사를 먼저 공격하여 간접적으로 대기업에 침투합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;RaaS 모델 확산&lt;/b&gt; : 랜섬웨어 서비스(Ransomware as a Service) 모델로, 기술이 없는 범죄자도 일정 수수료를 내고 랜섬웨어 플랫폼을 이용할 수 있게 되어 공격 건수가 급증했습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;중요 인프라 타겟팅&lt;/b&gt; : 에너지, 의료, 교통, 금융 등 중요 인프라를 공격하여 사회적 혼란을 야기하고 더 높은 몸값을 받아냅니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;prevention&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;랜섬웨어 예방 방법&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;랜섬웨어는 일단 감염되면 복구가 매우 어렵기 때문에, &lt;span class=&quot;highlight&quot;&gt;예방이 최선의 방어책&lt;/span&gt;입니다. 다음은 개인과 조직이 반드시 실천해야 할 예방 조치들입니다.&lt;/p&gt;
&lt;div class=&quot;prevention-grid&quot;&gt;
&lt;div class=&quot;prevention-card&quot;&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;정기적인 백업&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3-2-1 백업 규칙&lt;/b&gt;을 따르세요. 3개의 복사본을 2개의 서로 다른 매체에 저장하고, 1개는 오프라인(외부 위치)에 보관합니다. 백업은 네트워크에서 분리된 외장 하드나 클라우드(버전 관리 지원)에 저장하며, 자동 백업을 설정하되 복구 테스트도 정기적으로 수행해야 합니다.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;prevention-card&quot;&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;운영체제 및 소프트웨어 업데이트&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Windows Update를 활성화하여 자동 업데이트를 설정하고, 사용하는 모든 소프트웨어(브라우저, PDF 뷰어, Office 등)를 최신 버전으로 유지합니다. 보안 패치는 발표 즉시 적용하는 것이 중요하며, 지원이 종료된 운영체제(Windows 7 등)는 최신 버전으로 교체해야 합니다.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;prevention-card&quot;&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;강력한 보안 솔루션 사용&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;신뢰할 수 있는 백신 소프트웨어를 설치하고 실시간 보호 기능을 활성화합니다. EDR(Endpoint Detection and Response) 솔루션을 도입하면 더욱 효과적입니다. 방화벽을 활성화하고, 안티 랜섬웨어 전용 솔루션도 고려할 수 있습니다.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;prevention-card&quot;&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;이메일 및 링크 주의&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;발신자가 불명확하거나 예상하지 못한 이메일의 첨부파일은 절대 열지 않습니다. 링크를 클릭하기 전에 URL을 확인하고, 의심스러운 경우 발신자에게 별도로 연락하여 확인합니다. 이메일 보안 게이트웨이를 구축하면 피싱 메일을 자동으로 차단할 수 있습니다.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;prevention-card&quot;&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;매크로 비활성화&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Microsoft Office 문서의 매크로는 기본적으로 비활성화하고, 반드시 필요한 경우에만 신뢰할 수 있는 출처의 파일에서만 활성화합니다. Office 보안 센터에서 &quot;모든 매크로 포함 안 함&quot; 설정을 권장합니다.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;prevention-card&quot;&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;RDP 보안 강화&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;RDP를 사용하지 않는다면 완전히 비활성화합니다. 사용이 필요한 경우 복잡한 비밀번호를 설정하고, 다중 인증(MFA)을 반드시 적용합니다. VPN을 통해서만 RDP 접근을 허용하고, 기본 포트(3389)를 변경하며, 로그인 실패 횟수를 제한합니다.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;prevention-card&quot;&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;권한 최소화 원칙&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일상 업무에는 일반 사용자 계정을 사용하고, 관리자 권한은 필요한 경우에만 사용합니다. 각 사용자에게 업무에 필요한 최소한의 권한만 부여하고, 공유 폴더의 쓰기 권한을 제한합니다.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;prevention-card&quot;&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;네트워크 세분화&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;네트워크를 여러 세그먼트로 분리하여 랜섬웨어가 전체 네트워크로 확산되는 것을 방지합니다. 중요한 서버와 일반 사용자 네트워크를 분리하고, 방화벽 규칙을 통해 불필요한 통신을 차단합니다.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;prevention-card&quot;&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;직원 교육 및 인식 제고&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 직원에게 정기적으로 보안 교육을 실시합니다. 피싱 메일 식별법, 안전한 인터넷 사용법, 의심스러운 활동 신고 절차 등을 교육합니다. 모의 피싱 훈련을 통해 실제 상황에 대비합니다.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;prevention-card&quot;&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;파일 확장자 표시 활성화&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Windows 탐색기에서 파일 확장자를 표시하도록 설정하여, document.pdf.exe처럼 확장자를 위장한 악성 파일을 쉽게 식별할 수 있습니다. 이중 확장자를 가진 파일은 매우 의심스럽습니다.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;prevention-card&quot;&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;클라우드 서비스 버전 관리&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;OneDrive, Google Drive 등 클라우드 서비스를 사용하는 경우, 파일 버전 관리 기능을 활성화합니다. 랜섬웨어에 감염되더라도 이전 버전으로 복원할 수 있습니다. 대부분의 클라우드 서비스는 30일 이상의 버전 이력을 제공합니다.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;prevention-card&quot;&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;침입 탐지 시스템(IDS/IPS)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;네트워크 트래픽을 모니터링하여 비정상적인 활동을 탐지하고 차단하는 침입 탐지/방지 시스템을 구축합니다. 랜섬웨어의 C&amp;amp;C(Command and Control) 서버 통신을 차단할 수 있습니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;warning-box&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;백업만으로는 충분하지 않습니다!&lt;/b&gt; 최근 랜섬웨어는 백업 파일도 함께 암호화하거나 삭제합니다. 따라서 백업은 반드시 네트워크에서 분리된 상태로 보관해야 하며, immutable(변경 불가능) 백업 기능을 지원하는 솔루션을 사용하는 것이 좋습니다. 또한 데이터 유출을 막기 위한 DLP(Data Loss Prevention) 솔루션도 함께 고려해야 합니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;government&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;정부 공식 문서 및 대응 체계&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한국 정부는 랜섬웨어 위협에 대응하기 위해 다양한 공식 문서와 지원 체계를 운영하고 있습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;6.1 과학기술정보통신부 및 KISA(한국인터넷진흥원)&lt;/h3&gt;
&lt;div class=&quot;reference-box&quot;&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;주요 공식 문서 및 자료&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;랜섬웨어 대응 가이드&lt;/b&gt; : KISA에서 발간하는 공식 대응 가이드로, 예방부터 대응, 복구까지의 전 과정을 설명합니다. (&lt;a href=&quot;https://www.kisa.or.kr/2060204/form?postSeq=12&amp;amp;lang_type=KO&amp;amp;page=1&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;www.kisa.or.kr&lt;/a&gt;에서 다운로드 가능)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;보안공지 및 주의보&lt;/b&gt; : 새로운 랜섬웨어 변종이 발견되거나 대규모 공격이 예상될 때 발행되는 보안 경보입니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;침해사고 대응 지원&lt;/b&gt; : 랜섬웨어 감염 시 무료 상담 및 기술 지원을 제공합니다. (국번 없이 118)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;보안취약점 정보&lt;/b&gt; : 운영체제 및 주요 소프트웨어의 보안 취약점 정보와 패치 안내를 제공합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;중소기업 정보보호 컨설팅&lt;/b&gt; : 중소기업을 대상으로 무료 보안 컨설팅 및 취약점 점검 서비스를 제공합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;6.2 국가사이버안전센터 (NCSC)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;국가 주요기반시설을 대상으로 한 랜섬웨어 공격에 대응하기 위해 국가사이버안전센터가 운영됩니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;국가 사이버 위협 경보&lt;/b&gt; : 국가 안보에 영향을 미칠 수 있는 대규모 랜섬웨어 공격 시 경보 발령&lt;/li&gt;
&lt;li&gt;&lt;b&gt;주요기반시설 보호&lt;/b&gt; : 전력, 통신, 금융 등 국가 주요기반시설에 대한 사이버 보안 강화&lt;/li&gt;
&lt;li&gt;&lt;b&gt;국제 협력&lt;/b&gt; : Interpol, FBI 등 해외 기관과의 공조를 통한 글로벌 랜섬웨어 조직 추적&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;6.3 금융보안원 (FSS)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;금융권을 대상으로 한 랜섬웨어 공격에 대비하여 금융보안원은 다음과 같은 지원을 제공합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;금융권 랜섬웨어 대응 매뉴얼&lt;/b&gt; : 금융기관 특성에 맞춘 상세한 대응 절차&lt;/li&gt;
&lt;li&gt;&lt;b&gt;금융 ISAC&lt;/b&gt; : 금융권 보안 위협 정보 공유 및 협력 체계&lt;/li&gt;
&lt;li&gt;&lt;b&gt;모의훈련 지원&lt;/b&gt; : 랜섬웨어 공격 대응 모의훈련 시나리오 및 지원&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;6.4 경찰청 사이버안전국&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;랜섬웨어는 범죄 행위이므로, 감염 시 경찰에 신고할 수 있습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;사이버범죄 신고&lt;/b&gt; : 경찰청 사이버안전국 (&lt;a href=&quot;https://ecrm.police.go.kr/minwon/main&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;ecrm.police.go.kr&lt;/a&gt;) 또는 국번 없이 112로 신고 가능&lt;/li&gt;
&lt;li&gt;&lt;b&gt;사이버수사대&lt;/b&gt; : 전국 시도경찰청에 사이버수사대가 설치되어 있으며, 랜섬웨어 범죄 수사 및 피해자 지원을 담당합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;불법 거래 추적&lt;/b&gt; : 암호화폐를 통한 몸값 거래 추적 및 범인 검거&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;6.5 중소벤처기업부 - 중소기업 지원&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;중소기업을 대상으로 랜섬웨어 예방 및 복구 지원 사업을 운영합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;사이버보안 컨설팅 지원&lt;/b&gt; : 중소기업 대상 무료 또는 저렴한 비용으로 보안 컨설팅 제공&lt;/li&gt;
&lt;li&gt;&lt;b&gt;보안 솔루션 지원&lt;/b&gt; : 백신, 방화벽 등 보안 솔루션 구매 비용 일부 지원&lt;/li&gt;
&lt;li&gt;&lt;b&gt;교육 프로그램&lt;/b&gt; : 중소기업 임직원 대상 사이버 보안 교육&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;6.6 주요 정부 문서 및 법령&lt;/h3&gt;
&lt;div class=&quot;reference-box&quot;&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;관련 법령 및 문서&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;정보통신망 이용촉진 및 정보보호 등에 관한 법률&lt;/b&gt; : 정보통신망의 안전성 확보를 위한 기본 법률&lt;/li&gt;
&lt;li&gt;&lt;b&gt;개인정보 보호법&lt;/b&gt; : 개인정보 침해 시 신고 의무 및 보호 조치 규정&lt;/li&gt;
&lt;li&gt;&lt;b&gt;국가사이버안전관리규정&lt;/b&gt; : 국가 차원의 사이버 안전 관리 체계&lt;/li&gt;
&lt;li&gt;&lt;b&gt;사이버보안 진단의 날 운영 지침&lt;/b&gt; : 매월 4째 수요일을 사이버보안 진단의 날로 지정하여 점검 실시&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;info-box&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;랜섬웨어 피해 신고 및 지원 통합 연락처&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;KISA 침해사고 신고 : 국번 없이 &lt;b&gt;118&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;경찰청 사이버범죄 신고 : 국번 없이 &lt;b&gt;112&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;KISA 홈페이지 : &lt;a href=&quot;https://www.kisa.or.kr&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;www.kisa.or.kr&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;보호나라 : &lt;a href=&quot;https://www.boho.or.kr&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;www.boho.or.kr&lt;/a&gt; (보안 관련 종합 정보)&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;recovery&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;랜섬웨어 복구 방법&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;안타깝게도, 말씀하신 대로 &lt;span class=&quot;highlight&quot;&gt;랜섬웨어 감염 후 완벽한 복구는 매우 어렵습니다&lt;/span&gt;. 현대 랜섬웨어가 사용하는 암호화 알고리즘(AES-256, RSA-2048 등)은 복호화 키 없이는 사실상 해독이 불가능합니다. 그러나 상황에 따라 시도해 볼 수 있는 방법들이 있습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;7.1 즉각적인 조치&lt;/h3&gt;
&lt;div class=&quot;process-step&quot;&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1. 즉시 네트워크에서 격리&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;감염된 컴퓨터를 즉시 네트워크에서 분리합니다. 유선 LAN 케이블을 뽑고, Wi-Fi를 끕니다. 이는 랜섬웨어가 네트워크의 다른 시스템으로 확산되는 것을 막기 위함입니다. USB나 외장 하드 등 연결된 모든 저장장치도 분리합니다.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;process-step&quot;&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2. 컴퓨터 종료 여부 판단&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일부 랜섬웨어는 메모리에 복호화 키의 일부를 남겨둘 수 있습니다. 컴퓨터를 종료하면 이 정보가 사라질 수 있으므로, 전문가의 지시가 있을 때까지 전원을 유지합니다. 다만, 암호화가 진행 중이라면 즉시 종료하는 것이 피해를 줄일 수 있습니다.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;process-step&quot;&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3. 증거 보존&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;몸값 요구 메시지, 암호화된 파일의 확장자, 범인이 남긴 연락처 등을 사진으로 촬영하거나 별도로 기록합니다. 이는 경찰 수사와 복구에 도움이 됩니다.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;process-step&quot;&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;4. 전문가에게 연락&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;KISA(118), 경찰청, 또는 전문 보안업체에 즉시 연락하여 지원을 요청합니다. 혼자서 복구를 시도하다가 상황을 악화시킬 수 있습니다.&lt;/p&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;7.2 복구 시도 방법&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;방법 1 : 무료 복호화 도구 사용&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일부 랜섬웨어의 경우, 보안 업체들이 복호화 도구를 개발하여 무료로 제공하고 있습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;No More Ransom Project&lt;/b&gt; : Europol, 네덜란드 경찰, Kaspersky, McAfee 등이 운영하는 프로젝트로, 다양한 랜섬웨어의 무료 복호화 도구를 제공합니다. (&lt;a href=&quot;https://www.nomoreransom.org&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;www.nomoreransom.org&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Avast Free Ransomware Decryption Tools&lt;/b&gt; : Avast에서 제공하는 여러 랜섬웨어 복호화 도구&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Kaspersky Ransomware Decryptor&lt;/b&gt; : Kaspersky에서 제공하는 복호화 도구&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;info-box&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;복호화 도구를 사용하기 전에 반드시 랜섬웨어의 정확한 이름과 버전을 확인해야 합니다. 잘못된 도구를 사용하면 데이터가 영구적으로 손상될 수 있습니다. No More Ransom 웹사이트에는 암호화된 파일을 업로드하면 랜섬웨어 종류를 식별해 주는 기능이 있습니다.&lt;/p&gt;
&lt;/div&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;방법 2 : 백업에서 복원&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사전에 백업을 해두었다면, 이것이 가장 확실한 복구 방법입니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;백업 무결성 확인&lt;/b&gt; : 복원하기 전에 백업 파일이 암호화되지 않았는지 확인합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;완전 포맷 후 복원&lt;/b&gt; : 감염된 시스템을 완전히 포맷하고 운영체제를 재설치한 후 백업을 복원합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;클라우드 버전 복구&lt;/b&gt; : OneDrive, Google Drive 등을 사용했다면 이전 버전으로 복원할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;방법 3 : 섀도우 카피 복원&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Windows의 시스템 복원 기능이 활성화되어 있었다면, 섀도우 카피(Volume Shadow Copy)를 통해 일부 파일을 복구할 수 있습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;ShadowExplorer&lt;/b&gt; : 섀도우 카피를 탐색하고 복원할 수 있는 무료 도구&lt;/li&gt;
&lt;li&gt;&lt;b&gt;한계&lt;/b&gt; : 많은 최신 랜섬웨어는 섀도우 카피도 삭제하므로, 성공 가능성은 낮습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;방법 4 : 데이터 복구 소프트웨어 사용&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;암호화 과정에서 원본 파일이 완전히 삭제되지 않았을 가능성이 있다면, 데이터 복구 소프트웨어를 시도해 볼 수 있습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Recuva, PhotoRec, TestDisk&lt;/b&gt; 등의 복구 도구&lt;/li&gt;
&lt;li&gt;&lt;b&gt;주의사항&lt;/b&gt; : 복구 작업은 별도의 드라이브에 저장해야 하며, 원본 드라이브에 추가 작업을 하면 복구 가능성이 낮아집니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;7.3 몸값 지불에 대한 고려사항&lt;/h3&gt;
&lt;div class=&quot;warning-box&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;몸값 지불은 권장되지 않습니다.&lt;/b&gt; 미국 FBI, 한국 경찰청, 대부분의 보안 전문가들은 다음과 같은 이유로 몸값 지불을 권장하지 않습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;복호화 보장 없음&lt;/b&gt; : 돈을 지불해도 복호화 키를 받지 못하거나, 받더라도 제대로 작동하지 않는 경우가 약 40%에 달합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;재공격 위험&lt;/b&gt; : 돈을 지불한 피해자는 다시 공격받을 확률이 높습니다. 공격자 입장에서는 &quot;돈을 지불할 사람&quot;으로 표시되기 때문입니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;범죄 조직 자금 지원&lt;/b&gt; : 몸값은 범죄 조직의 자금원이 되어 더 많은 공격을 야기합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;법적 문제&lt;/b&gt; : 일부 국가에서는 테러 조직으로 지정된 랜섬웨어 그룹에 돈을 지불하는 것 자체가 불법일 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만, 기업의 경우 사업 연속성, 고객 데이터 보호, 법적 책임 등을 고려하여 불가피하게 몸값 지불을 선택하는 경우도 있습니다. 이런 경우에도 반드시 전문 협상가와 법률 자문을 받아야 합니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;7.4 감염 후 조치&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;복구 여부와 관계없이, 랜섬웨어 감염 후에는 다음 조치를 취해야 합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;전체 시스템 재구축&lt;/b&gt; : 운영체제를 완전히 재설치하고, 모든 소프트웨어를 재설치합니다. 랜섬웨어가 백도어를 설치했을 가능성이 있기 때문입니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;비밀번호 변경&lt;/b&gt; : 모든 계정의 비밀번호를 변경합니다. 특히 이메일, 은행, 주요 서비스 계정은 우선적으로 변경합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;보안 강화&lt;/b&gt; : 앞서 설명한 예방 조치들을 모두 적용합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;사고 보고&lt;/b&gt; : 조직 내부 보안팀, 경영진에 보고하고, 필요시 고객이나 이해관계자에게 통지합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;사후 분석&lt;/b&gt; : 어떻게 감염되었는지 철저히 분석하여 재발을 방지합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;section id=&quot;conclusion&quot;&gt;
&lt;div class=&quot;conclusion-box&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;마무리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;랜섬웨어는 현대 사이버 보안에서 가장 심각한 위협 중 하나입니다. 개인의 소중한 추억부터 기업의 핵심 자산까지 순식간에 인질로 만들 수 있는 무서운 공격입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 이 글에서 설명한 예방 조치들을 철저히 실천한다면, 랜섬웨어로부터 안전하게 시스템과 데이터를 보호할 수 있습니다. 특히 &lt;b&gt;정기적인 백업, 소프트웨어 업데이트, 보안 의식 제고&lt;/b&gt;는 반드시 실천해야 할 핵심 요소입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 불행히도 랜섬웨어에 감염되었다면, 당황하지 말고 즉시 전문가의 도움을 받으시기 바랍니다. 혼자서 해결하려다 상황을 악화시킬 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기억하세요. &lt;b&gt;예방이 최선의 방어&lt;/b&gt;이며, &lt;b&gt;백업이 최후의 보루&lt;/b&gt;입니다. 오늘부터 바로 실천하여 여러분의 소중한 데이터를 지키시기 바랍니다.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;info-box&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;도움이 필요하시면 언제든지 연락하세요&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;KISA 침해사고 신고 : 국번 없이 118&lt;/li&gt;
&lt;li&gt;경찰청 사이버범죄 신고 : 국번 없이 112&lt;/li&gt;
&lt;li&gt;KISA 홈페이지 : &lt;a href=&quot;https://www.kisa.or.kr&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;www.kisa.or.kr&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;div class=&quot;tag-container&quot;&gt;
&lt;div class=&quot;tag-title&quot;&gt;&amp;nbsp;태그&lt;/div&gt;
&lt;div class=&quot;tags&quot;&gt;&lt;span class=&quot;tag&quot;&gt;랜섬웨어&lt;/span&gt; &lt;span class=&quot;tag&quot;&gt;사이버보안&lt;/span&gt; &lt;span class=&quot;tag&quot;&gt;정보보안&lt;/span&gt; &lt;span class=&quot;tag&quot;&gt;악성코드&lt;/span&gt; &lt;span class=&quot;tag&quot;&gt;데이터보호&lt;/span&gt; &lt;span class=&quot;tag&quot;&gt;백업&lt;/span&gt; &lt;span class=&quot;tag&quot;&gt;피싱&lt;/span&gt; &lt;span class=&quot;tag&quot;&gt;보안가이드&lt;/span&gt; &lt;span class=&quot;tag&quot;&gt;KISA&lt;/span&gt; &lt;span class=&quot;tag&quot;&gt;사이버범죄&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</description>
      <category>IT</category>
      <category>기업보안</category>
      <category>데이터 암호화</category>
      <category>랜섬웨어 대응</category>
      <category>랜섬웨어 복구</category>
      <category>랜섬웨어 신고</category>
      <category>랜섬웨어 예방</category>
      <category>랜섬웨어 원리</category>
      <category>보안솔루션</category>
      <category>사이버공격 예방</category>
      <category>중소기업 랜섬웨어</category>
      <author>간지뽕빨리턴님</author>
      <guid isPermaLink="true">https://odinbox.tistory.com/561</guid>
      <comments>https://odinbox.tistory.com/561#entry561comment</comments>
      <pubDate>Sat, 29 Nov 2025 09:44:01 +0900</pubDate>
    </item>
    <item>
      <title>CSS 애니메이션 가이드, CSS로 애니메이션을?</title>
      <link>https://odinbox.tistory.com/560</link>
      <description>&lt;div&gt;
&lt;style&gt;
.csspoststyle_post-wrap {
  max-width: 900px;
  margin: 0 auto;
  padding: 32px 20px 60px;
  font-family: system-ui, -apple-system, BlinkMacSystemFont, &quot;Noto Sans KR&quot;, &quot;Malgun Gothic&quot;, sans-serif;
  color: #222;
  line-height: 1.7;
  box-sizing: border-box;
}
.csspoststyle_post-wrap * {
  box-sizing: border-box;
}
.csspoststyle_title {
  font-size: 2.1rem;
  font-weight: 800;
  letter-spacing: -0.04em;
  margin-bottom: 0.8rem;
}
.csspoststyle_title-highlight {
  position: relative;
  display: inline-block;
}
.csspoststyle_title-highlight::after {
  content: &quot;&quot;;
  position: absolute;
  left: 0;
  bottom: -4px;
  width: 100%;
  height: 10px;
  background: linear-gradient(90deg, #5c6fff, #4ad395);
  opacity: 0.16;
  transform-origin: left center;
  transform: scaleX(0);
  animation: csspoststyle_title-underline 0.8s 0.4s ease-out forwards;
}
@keyframes csspoststyle_title-underline {
  to {
    transform: scaleX(1);
  }
}
.csspoststyle_subtitle {
  font-size: 0.98rem;
  color: #475569;
  margin-bottom: 22px;
}
.csspoststyle_thumbnail {
  position: relative;
  width: 100%;
  padding-top: 46%;
  border-radius: 18px;
  background: radial-gradient(circle at 10% 20%, #f0f4ff 0, #f7fbff 40%, #f8fff7 100%);
  overflow: hidden;
  margin-bottom: 28px;
  box-shadow: 0 12px 30px rgba(15, 23, 42, 0.08);
}
.csspoststyle_thumbnail-inner {
  position: absolute;
  inset: 16px;
  border-radius: 14px;
  border: 1px dashed rgba(15, 23, 42, 0.15);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-direction: column;
  gap: 10px;
  font-size: 0.86rem;
  color: #555;
  text-align: center;
}
.csspoststyle_thumbnail-hint {
  font-size: 0.78rem;
  color: #94a3b8;
}
.csspoststyle_toc {
  margin: 32px 0 36px;
  padding: 18px 18px 16px;
  border-radius: 16px;
  background: linear-gradient(135deg, #f5f7ff, #f7fffb);
  border: 1px solid rgba(148, 163, 184, 0.4);
}
.csspoststyle_toc-title {
  font-size: 1rem;
  font-weight: 700;
  margin-bottom: 8px;
}
.csspoststyle_toc-desc {
  font-size: 0.86rem;
  color: #64748b;
  margin-bottom: 10px;
}
.csspoststyle_toc-list {
  list-style: none;
  padding-left: 0;
  margin: 0;
  display: grid;
  gap: 4px;
}
.csspoststyle_toc-list a {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 0.88rem;
  text-decoration: none;
  color: #111827;
  padding: 4px 0;
}
.csspoststyle_toc-list a::before {
  content: &quot;&quot;;
  display: inline-block;
  width: 7px;
  height: 7px;
  border-radius: 999px;
  background: linear-gradient(135deg, #6366f1, #22c55e);
}
.csspoststyle_post-wrap h2 {
  font-size: 1.4rem;
  margin: 36px 0 14px;
  font-weight: 800;
  letter-spacing: -0.03em;
}
.csspoststyle_post-wrap h3 {
  font-size: 1.1rem;
  margin: 28px 0 12px;
  font-weight: 700;
}
.csspoststyle_post-wrap p {
  margin: 0 0 12px;
  font-size: 0.96rem;
}
.csspoststyle_post-wrap ul {
  margin: 6px 0 16px 18px;
  padding-left: 6px;
  font-size: 0.95rem;
}
.csspoststyle_inline-key {
  display: inline-flex;
  align-items: center;
  padding: 0 7px;
  border-radius: 999px;
  border: 1px solid rgba(148, 163, 184, 0.6);
  font-size: 0.78rem;
  font-weight: 600;
  letter-spacing: 0.03em;
  text-transform: uppercase;
}
.csspoststyle_tip {
  margin: 16px 0 20px;
  padding: 12px 14px;
  border-radius: 14px;
  border: 1px solid rgba(96, 165, 250, 0.4);
  background: linear-gradient(135deg, #f3f7ff, #f5faff);
  font-size: 0.9rem;
  color: #1e293b;
}
.csspoststyle_tip-title {
  font-weight: 700;
  font-size: 0.9rem;
  margin-bottom: 4px;
}
.csspoststyle_section {
  margin: 24px 0 32px;
  padding: 18px 18px 20px;
  border-radius: 16px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.35);
  box-shadow: 0 10px 24px rgba(15, 23, 42, 0.06);
  animation: csspoststyle_section-fade 0.7s ease-out both;
}
.csspoststyle_section:nth-of-type(odd) {
  animation-delay: 0.06s;
}
.csspoststyle_section:nth-of-type(even) {
  animation-delay: 0.12s;
}
@keyframes csspoststyle_section-fade {
  from {
    opacity: 0;
    transform: translateY(12px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}
.csspoststyle_code-block {
  margin: 14px 0 18px;
  border-radius: 14px;
  overflow: hidden;
  background: #020617;
  box-shadow: 0 18px 40px rgba(15, 23, 42, 0.7);
}
.csspoststyle_code-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 9px 12px 8px;
  background: #020617;
  border-bottom: 1px solid rgba(148, 163, 184, 0.35);
}
.csspoststyle_code-label {
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: #e5e7eb;
}
.csspoststyle_code-dots {
  display: flex;
  gap: 4px;
}
.csspoststyle_code-dot {
  width: 8px;
  height: 8px;
  border-radius: 999px;
}
.csspoststyle_code-dot:nth-child(1) {
  background: #f97373;
}
.csspoststyle_code-dot:nth-child(2) {
  background: #facc15;
}
.csspoststyle_code-dot:nth-child(3) {
  background: #22c55e;
}
.csspoststyle_code-copy {
  appearance: none;
  border: none;
  border-radius: 999px;
  padding: 4px 11px;
  font-size: 0.8rem;
  font-weight: 500;
  cursor: pointer;
  background: rgba(15, 23, 42, 0.72);
  color: #e5e7eb;
  backdrop-filter: blur(8px);
  transition: background 0.18s ease, transform 0.18s ease, box-shadow 0.18s ease;
}
.csspoststyle_code-copy:hover {
  background: linear-gradient(135deg, #4f46e5, #16a34a);
  box-shadow: 0 0 0 1px rgba(191, 219, 254, 0.6);
  transform: translateY(-1px);
}
.csspoststyle_code-copy:active {
  transform: translateY(0);
  box-shadow: none;
}
.csspoststyle_code-block pre {
  margin: 0;
  padding: 12px 14px 14px;
  overflow-x: auto;
}
.csspoststyle_code-block code {
  display: block;
  font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, &quot;Liberation Mono&quot;, &quot;Courier New&quot;, monospace;
  font-size: 0.82rem;
  color: #e5e7eb;
  white-space: pre;
}
.csspoststyle_inline-code {
  display: inline-block;
  padding: 0 6px;
  border-radius: 6px;
  background: rgba(148, 163, 184, 0.16);
  font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, &quot;Liberation Mono&quot;, &quot;Courier New&quot;, monospace;
  font-size: 0.85em;
}
.csspoststyle_toast {
  position: fixed;
  left: 50%;
  bottom: 30px;
  transform: translateX(-50%) translateY(16px);
  padding: 9px 16px;
  border-radius: 999px;
  background: #111827;
  color: #f9fafb;
  font-size: 0.82rem;
  box-shadow: 0 18px 35px rgba(15, 23, 42, 0.6);
  opacity: 0;
  pointer-events: none;
  z-index: 9999;
  animation: csspoststyle_toast-in 0.26s ease-out forwards, csspoststyle_toast-out 0.28s ease-in forwards 2.1s;
}
@keyframes csspoststyle_toast-in {
  from {
    opacity: 0;
    transform: translateX(-50%) translateY(18px);
  }
  to {
    opacity: 1;
    transform: translateX(-50%) translateY(0);
  }
}
@keyframes csspoststyle_toast-out {
  to {
    opacity: 0;
    transform: translateX(-50%) translateY(6px);
  }
}
@media (max-width: 720px) {
  .csspoststyle_post-wrap {
    padding: 24px 14px 48px;
  }
  .csspoststyle_title {
    font-size: 1.7rem;
  }
  .csspoststyle_thumbnail-inner {
    font-size: 0.84rem;
  }
}
&lt;/style&gt;
&lt;/div&gt;
&lt;div class=&quot;csspoststyle_post-wrap&quot;&gt;
&lt;h1 class=&quot;csspoststyle_title&quot;&gt;&lt;span class=&quot;csspoststyle_title-highlight&quot;&gt;CSS 애니메이션, 어려우시죠?&lt;/span&gt;&lt;/h1&gt;
&lt;p class=&quot;csspoststyle_subtitle&quot; data-ke-size=&quot;size16&quot;&gt;제가 많이 사용하는 애니메이션과 맨 아래에 참고 CSS 등도 정리를 해서 해봤습니다..&lt;/p&gt;
&lt;div class=&quot;csspoststyle_thumbnail&quot;&gt;
&lt;div class=&quot;csspoststyle_thumbnail-inner&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;글 상단 부분 대표 이미지.png&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cn27dA/dJMcaiVZopR/HxIdkQixqCabPcR3p8IcI1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cn27dA/dJMcaiVZopR/HxIdkQixqCabPcR3p8IcI1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cn27dA/dJMcaiVZopR/HxIdkQixqCabPcR3p8IcI1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcn27dA%2FdJMcaiVZopR%2FHxIdkQixqCabPcR3p8IcI1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;400&quot; data-filename=&quot;글 상단 부분 대표 이미지.png&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;div class=&quot;csspoststyle_thumbnail-hint&quot;&gt;CSS를 이 글 하나로 끝낼 수 있어요!&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현대 웹 디자인에서 애니메이션은 선택이 아니라 기본에 가깝습니다. 적절한 움직임은 사용자의 시선을 끌고, CTA 버튼의 클릭률을 높이며, 브랜드의 인상을 오래 남게 합니다. 특히 개발자와 디자이너에게 CSS 애니메이션은 복잡한 자바스크립트 없이도 인터페이스를 풍부하게 만드는 핵심 도구입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래에서는 실전에서 많이 사용하는 CSS 애니메이션 예제 10가지를 목적별로 정리했습니다. 각 예제는 &lt;span class=&quot;csspoststyle_inline-key&quot;&gt;설명&lt;/span&gt; &amp;rarr; &lt;span class=&quot;csspoststyle_inline-key&quot;&gt;코드&lt;/span&gt; &amp;rarr; &lt;span class=&quot;csspoststyle_inline-key&quot;&gt;실무 팁&lt;/span&gt; 순서로 구성되어 있어 웹 사이트에 바로 가져다 쓸 수 있습니다.&lt;/p&gt;
&lt;div id=&quot;csspoststyle_toc&quot; class=&quot;csspoststyle_toc&quot;&gt;
&lt;div class=&quot;csspoststyle_toc-title&quot;&gt;목차&lt;/div&gt;
&lt;p class=&quot;csspoststyle_toc-desc&quot; data-ke-size=&quot;size16&quot;&gt;각 항목을 클릭하면 해당 애니메이션 예제로 바로 이동합니다.&lt;/p&gt;
&lt;ul class=&quot;csspoststyle_toc-list&quot; style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;#csspoststyle_example1&quot;&gt;1. 자연스러운 페이드인(Fade-in) 효과&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#csspoststyle_example2&quot;&gt;2. 슬라이드 업&amp;middot;다운 등장 효과&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#csspoststyle_example3&quot;&gt;3.버튼&amp;middot;이미지 호버 강조 효과&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#csspoststyle_example4&quot;&gt;4. 3D 카드 플립(Card Flip)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#csspoststyle_example5&quot;&gt;5. 순수 CSS 로딩 스피너&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#csspoststyle_example6&quot;&gt;6. 연속 회전 아이콘 효과&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#csspoststyle_example7&quot;&gt;7. 맥박(Pulse) 강조 애니메이션&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#csspoststyle_example8&quot;&gt;8. 스켈레톤 로딩(Skeleton UI)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#csspoststyle_example9&quot;&gt;9. 흔들림(Shake) 오류 피드백&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#csspoststyle_example10&quot;&gt;10. 배경&amp;middot;텍스트 컬러 애니메이션&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#csspoststyle_consider&quot;&gt;성능&amp;middot;접근성&amp;middot;실무 적용 팁&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#csspoststyle_deeplink&quot;&gt;더 공부할 수 있는 공식 문서 모음&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;CSS 애니메이션 기본 이해, 트랜지션과 키프레임&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 트랜지션과 키프레임 애니메이션의 차이를 정확히 이해하면, 어떤 상황에 어떤 방식을 써야 하는지 빠르게 판단할 수 있습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;트랜지션(transition)&lt;/b&gt;: &lt;span class=&quot;csspoststyle_inline-code&quot;&gt;:hover&lt;/span&gt;, &lt;span class=&quot;csspoststyle_inline-code&quot;&gt;:focus&lt;/span&gt;, 클래스 토글처럼 상태가 변할 때 시작과 끝 사이를 부드럽게 이어 줍니다. 색상 변화, 크기 조정, 그림자 강조 등 단순한 인터랙션에 적합합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;키프레임 애니메이션(animation)&lt;/b&gt;: &lt;span class=&quot;csspoststyle_inline-code&quot;&gt;@keyframes&lt;/span&gt;로 여러 단계의 스타일을 정의하고 반복 재생합니다. 로딩 스피너, 무한 회전, 배경 색상 순환처럼 계속 움직이는 모션에 적합합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실무에서는 &lt;b&gt;상태 한 번 전환 + 짧은 모션은 트랜지션&lt;/b&gt;, &lt;b&gt;지속적&amp;middot;복합적인 움직임은 키프레임&lt;/b&gt;으로 나눠 설계하면 유지보수가 훨씬 편해집니다.&lt;/p&gt;
&lt;div id=&quot;csspoststyle_example1&quot; class=&quot;csspoststyle_section&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 자연스러운 페이드인(Fade-in) 효과&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;페이지 첫 화면에서 타이틀, 대표 이미지를 서서히 등장시키는 가장 기본적인 패턴입니다. 콘텐츠 중심 웹 사이트의 경우, 글 상단 영역에 페이드인을 적용하면 첫인상이 훨씬 부드럽게 느껴집니다.&lt;/p&gt;
&lt;div class=&quot;csspoststyle_code-block&quot;&gt;
&lt;div class=&quot;csspoststyle_code-header&quot;&gt;
&lt;div class=&quot;csspoststyle_code-dots&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;span class=&quot;csspoststyle_code-label&quot;&gt;CSS&lt;/span&gt; &lt;button class=&quot;csspoststyle_code-copy&quot; type=&quot;button&quot;&gt;코드 복사&lt;/button&gt;&lt;/div&gt;
&lt;pre class=&quot;css&quot;&gt;&lt;code&gt;.csspoststyle_fade-in {
  opacity: 0;
  animation: csspoststyle_fade-in-keyframes 1.5s ease-in forwards;
}

@keyframes csspoststyle_fade-in-keyframes {
  to {
    opacity: 1;
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span class=&quot;csspoststyle_inline-code&quot;&gt;forwards&lt;/span&gt; 옵션 덕분에 애니메이션이 끝난 뒤에도 마지막 상태인 &lt;span class=&quot;csspoststyle_inline-code&quot;&gt;opacity: 1&lt;/span&gt;이 유지됩니다. 여러 요소를 순차적으로 등장시키고 싶다면 각각에 &lt;span class=&quot;csspoststyle_inline-code&quot;&gt;animation-delay&lt;/span&gt;를 0.1초씩 다르게 주면 자연스러운 스태거 효과를 만들 수 있습니다.&lt;/p&gt;
&lt;div class=&quot;csspoststyle_tip&quot;&gt;
&lt;div class=&quot;csspoststyle_tip-title&quot;&gt;실무 팁&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스크롤과 함께 등장시키고 싶다면 자바스크립트 &lt;span class=&quot;csspoststyle_inline-code&quot;&gt;IntersectionObserver&lt;/span&gt;로 특정 섹션이 뷰포트에 들어올 때 &lt;span class=&quot;csspoststyle_inline-code&quot;&gt;csspoststyle_fade-in&lt;/span&gt; 클래스를 추가하는 방식으로 확장할 수 있습니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;csspoststyle_example2&quot; class=&quot;csspoststyle_section&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 부드러운 슬라이드 업&amp;middot;다운 효과&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요소가 아래에서 위로 떠오르면서 나타나는 슬라이드 업 효과는 카드형 목록, 알림 바, 모바일 메뉴 등에서 자주 쓰입니다. 단순히 보여 주는 것보다 움직임이 포함되어 더 눈에 잘 들어옵니다.&lt;/p&gt;
&lt;div class=&quot;csspoststyle_code-block&quot;&gt;
&lt;div class=&quot;csspoststyle_code-header&quot;&gt;
&lt;div class=&quot;csspoststyle_code-dots&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;span class=&quot;csspoststyle_code-label&quot;&gt;CSS&lt;/span&gt; &lt;button class=&quot;csspoststyle_code-copy&quot; type=&quot;button&quot;&gt;코드 복사&lt;/button&gt;&lt;/div&gt;
&lt;pre class=&quot;css&quot;&gt;&lt;code&gt;.csspoststyle_slide-up {
  transform: translateY(50px);
  opacity: 0;
  animation: csspoststyle_slide-up-keyframes 0.8s ease-out forwards;
}

@keyframes csspoststyle_slide-up-keyframes {
  to {
    transform: translateY(0);
    opacity: 1;
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위치 이동은 &lt;span class=&quot;csspoststyle_inline-code&quot;&gt;top&lt;/span&gt;이나 &lt;span class=&quot;csspoststyle_inline-code&quot;&gt;margin&lt;/span&gt; 대신 &lt;span class=&quot;csspoststyle_inline-code&quot;&gt;transform&lt;/span&gt;으로 처리했습니다. 브라우저가 GPU 합성 단계에서 처리하기 때문에 레이아웃 재계산이 줄어들어 성능이 더 좋습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반대로 요소를 숨길 때는 시작값과 끝값을 바꿔서 슬라이드 다운 애니메이션을 만들 수 있습니다. 모달, 알림 영역에 등장&amp;middot;퇴장 애니메이션을 모두 붙이고 싶을 때 유용합니다.&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&quot;csspoststyle_example3&quot; class=&quot;csspoststyle_section&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. 호버 시 강조 효과 (버튼&amp;middot;이미지 인터랙션)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마우스를 올렸을 때 살짝 떠오르며 강조되는 효과는 CTA 버튼, 카드, 썸네일 이미지에 거의 필수로 들어가는 패턴입니다. 작은 변화만으로도 &amp;ldquo;클릭 가능한 요소&amp;rdquo;라는 신호를 확실하게 줄 수 있습니다.&lt;/p&gt;
&lt;div class=&quot;csspoststyle_code-block&quot;&gt;
&lt;div class=&quot;csspoststyle_code-header&quot;&gt;
&lt;div class=&quot;csspoststyle_code-dots&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;span class=&quot;csspoststyle_code-label&quot;&gt;CSS&lt;/span&gt; &lt;button class=&quot;csspoststyle_code-copy&quot; type=&quot;button&quot;&gt;코드 복사&lt;/button&gt;&lt;/div&gt;
&lt;pre class=&quot;css&quot;&gt;&lt;code&gt;.csspoststyle_btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 10px 18px;
  border-radius: 999px;
  border: none;
  background: linear-gradient(135deg, #4f46e5, #16a34a);
  color: #ffffff;
  font-weight: 600;
  font-size: 0.9rem;
  cursor: pointer;
  transition: transform 0.2s ease, box-shadow 0.2s ease, filter 0.2s ease;
}

.csspoststyle_btn:hover {
  transform: translateY(-2px) scale(1.04);
  box-shadow: 0 14px 30px rgba(15, 23, 42, 0.3);
  filter: brightness(1.02);
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;글에서 &amp;ldquo;예제 코드 보기&amp;rdquo;, &amp;ldquo;GitHub 바로가기&amp;rdquo; 같은 버튼에 적용해 보면, 사용자가 어떤 요소를 눌러야 할지 직관적으로 이해할 수 있습니다. 카드 레이아웃에서는 카드 전체를 버튼처럼 처리해 동일한 효과를 주면 좋습니다.&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&quot;csspoststyle_example4&quot; class=&quot;csspoststyle_section&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4. 3D 카드 플립(Card Flip) 애니메이션&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;카드 앞면에는 제목과 한 줄 설명, 뒷면에는 세부 설명과 링크를 배치하는 패턴입니다. 포트폴리오, 강의 목록,&amp;nbsp; 진행하는 프로젝트 리스트 등에 활용하기 좋습니다.&lt;/p&gt;
&lt;div class=&quot;csspoststyle_code-block&quot;&gt;
&lt;div class=&quot;csspoststyle_code-header&quot;&gt;
&lt;div class=&quot;csspoststyle_code-dots&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;span class=&quot;csspoststyle_code-label&quot;&gt;HTML + CSS&lt;/span&gt; &lt;button class=&quot;csspoststyle_code-copy&quot; type=&quot;button&quot;&gt;코드 복사&lt;/button&gt;&lt;/div&gt;
&lt;pre class=&quot;dts&quot;&gt;&lt;code&gt;&amp;lt;div class=&quot;csspoststyle_card&quot;&amp;gt;
  &amp;lt;div class=&quot;csspoststyle_card-inner&quot;&amp;gt;
    &amp;lt;div class=&quot;csspoststyle_card-front&quot;&amp;gt;
      OdinBOX 애니메이션 가이드
    &amp;lt;/div&amp;gt;
    &amp;lt;div class=&quot;csspoststyle_card-back&quot;&amp;gt;
      - CSS 애니메이션 핵심 정리&amp;lt;br /&amp;gt;
      - 실전 예제 10가지&amp;lt;br /&amp;gt;
      - GitHub 샘플 프로젝트 링크
    &amp;lt;/div&amp;gt;
  &amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;

.csspoststyle_card {
  perspective: 1000px;
}

.csspoststyle_card-inner {
  position: relative;
  width: 100%;
  max-width: 260px;
  height: 160px;
  margin: 0 auto;
  transition: transform 0.8s;
  transform-style: preserve-3d;
  cursor: pointer;
}

.csspoststyle_card-front,
.csspoststyle_card-back {
  position: absolute;
  inset: 0;
  backface-visibility: hidden;
  border-radius: 16px;
  padding: 16px;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
}

.csspoststyle_card-front {
  background: linear-gradient(135deg, #eef2ff, #e0fbea);
}

.csspoststyle_card-back {
  background: #020617;
  color: #e5e7eb;
  transform: rotateY(180deg);
}

.csspoststyle_card:hover .csspoststyle_card-inner {
  transform: rotateY(180deg);
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;핵심은 &lt;span class=&quot;csspoststyle_inline-code&quot;&gt;perspective&lt;/span&gt;와 &lt;span class=&quot;csspoststyle_inline-code&quot;&gt;transform-style: preserve-3d&lt;/span&gt;입니다. 이 두 가지가 빠지면 앞&amp;middot;뒷면이 평면처럼 겹쳐 보이고, 카드가 진짜 뒤집히는 느낌이 사라집니다.&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&quot;csspoststyle_example5&quot; class=&quot;csspoststyle_section&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5. 순수 CSS 로딩 스피너(Loading Spinner)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;API 응답 대기, 페이지 전환 등에서 &amp;ldquo;지금 처리 중&amp;rdquo;임을 알려 주는 기본 로딩 패턴입니다. 이미지 없이 CSS만으로 구현하면 테마 색상을 변경하기도 쉽고, 해상도 걱정도 없습니다.&lt;/p&gt;
&lt;div class=&quot;csspoststyle_code-block&quot;&gt;
&lt;div class=&quot;csspoststyle_code-header&quot;&gt;
&lt;div class=&quot;csspoststyle_code-dots&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;span class=&quot;csspoststyle_code-label&quot;&gt;CSS&lt;/span&gt; &lt;button class=&quot;csspoststyle_code-copy&quot; type=&quot;button&quot;&gt;코드 복사&lt;/button&gt;&lt;/div&gt;
&lt;pre class=&quot;css&quot;&gt;&lt;code&gt;.csspoststyle_loader {
  width: 40px;
  height: 40px;
  border-radius: 50%;
  border: 4px solid #e5e7eb;
  border-top-color: #4f46e5;
  animation: csspoststyle_spin 1s linear infinite;
}

@keyframes csspoststyle_spin {
  to {
    transform: rotate(360deg);
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;테두리 전체에는 옅은 회색, 윗부분만 강조 색을 주고 회전시키면 심플한 로딩 인디케이터가 됩니다. 웹사이 브랜드 컬러에 맞춰 &lt;span class=&quot;csspoststyle_inline-code&quot;&gt;border-top-color&lt;/span&gt;만 교체해서 사용해 보세요.&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&quot;csspoststyle_example6&quot; class=&quot;csspoststyle_section&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;6. 시선 집중 회전 효과 (뱅글뱅글 아이콘)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;ldquo;지금 확인하기&amp;rdquo;, &amp;ldquo;신규&amp;rdquo; 같은 배지에 회전 애니메이션을 추가하면 사용자의 시선을 자연스럽게 끌어올 수 있습니다. 너무 크지 않은 아이콘에만 적용하는 것이 포인트입니다.&lt;/p&gt;
&lt;div class=&quot;csspoststyle_code-block&quot;&gt;
&lt;div class=&quot;csspoststyle_code-header&quot;&gt;
&lt;div class=&quot;csspoststyle_code-dots&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;span class=&quot;csspoststyle_code-label&quot;&gt;CSS&lt;/span&gt; &lt;button class=&quot;csspoststyle_code-copy&quot; type=&quot;button&quot;&gt;코드 복사&lt;/button&gt;&lt;/div&gt;
&lt;pre class=&quot;css&quot;&gt;&lt;code&gt;.csspoststyle_rotate {
  display: inline-block;
  animation: csspoststyle_rotate360 2s linear infinite;
}

@keyframes csspoststyle_rotate360 {
  to {
    transform: rotate(360deg);
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;속도를 1초 이하로 줄이면 너무 빠르게 느껴질 수 있으니, 2초 전후의 여유 있는 속도가 가장 무난합니다. 필요하다면 &lt;span class=&quot;csspoststyle_inline-code&quot;&gt;:hover&lt;/span&gt; 상태에서만 회전하도록 바꿔 사용해도 좋습니다.&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&quot;csspoststyle_example7&quot; class=&quot;csspoststyle_section&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;7. 맥박(Pulse) 효과로 중요한 요소 강조&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;심장 박동처럼 살짝 커졌다 줄어드는 맥박 효과는 가입 버튼, 알림 뱃지, 새 글 표시 등 &amp;ldquo;계속 눈에 띄어야 하는 요소&amp;rdquo;에 잘 어울립니다. 과하게 사용하지만 않으면 UX를 해치지 않으면서 클릭률을 높일 수 있습니다.&lt;/p&gt;
&lt;div class=&quot;csspoststyle_code-block&quot;&gt;
&lt;div class=&quot;csspoststyle_code-header&quot;&gt;
&lt;div class=&quot;csspoststyle_code-dots&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;span class=&quot;csspoststyle_code-label&quot;&gt;CSS&lt;/span&gt; &lt;button class=&quot;csspoststyle_code-copy&quot; type=&quot;button&quot;&gt;코드 복사&lt;/button&gt;&lt;/div&gt;
&lt;pre class=&quot;css&quot;&gt;&lt;code&gt;.csspoststyle_pulse {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  animation: csspoststyle_pulse-keyframes 1.5s ease-in-out infinite;
}

@keyframes csspoststyle_pulse-keyframes {
  0%,
  100% {
    transform: scale(1);
  }
  50% {
    transform: scale(1.1);
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보통 1.05~1.1배 정도면 충분합니다. 1.2배 이상으로 키우면 강조는 잘 되지만, 화면 전체가 불안정하게 느껴질 수 있으니 주의하세요.&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&quot;csspoststyle_example8&quot; class=&quot;csspoststyle_section&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;8. 스켈레톤 로딩(Skeleton Loading) 효과&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제 콘텐츠가 로딩될 때까지 빈 화면 대신 회색 뼈대 레이아웃을 먼저 보여 주는 패턴입니다. 특히 카드형 목록, 피드, 블로그 글 목록 등에서 &amp;ldquo;곧 내용이 채워질 것&amp;rdquo;이라는 인상을 줄 수 있습니다.&lt;/p&gt;
&lt;div class=&quot;csspoststyle_code-block&quot;&gt;
&lt;div class=&quot;csspoststyle_code-header&quot;&gt;
&lt;div class=&quot;csspoststyle_code-dots&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;span class=&quot;csspoststyle_code-label&quot;&gt;CSS&lt;/span&gt; &lt;button class=&quot;csspoststyle_code-copy&quot; type=&quot;button&quot;&gt;코드 복사&lt;/button&gt;&lt;/div&gt;
&lt;pre class=&quot;css&quot;&gt;&lt;code&gt;.csspoststyle_skeleton {
  border-radius: 10px;
  background: linear-gradient(
    90deg,
    #e5e7eb 25%,
    #d1d5db 50%,
    #e5e7eb 75%
  );
  background-size: 200% 100%;
  animation: csspoststyle_shimmer 1.5s infinite;
}

@keyframes csspoststyle_shimmer {
  0% {
    background-position: -200% 0;
  }
  100% {
    background-position: 200% 0;
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제 카드 레이아웃과 비슷한 크기의 스켈레톤 박스를 여러 개 배치해 두면, 사용자는 로딩 중에도 전체 구조를 미리 파악할 수 있어 이탈률이 줄어듭니다.&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&quot;csspoststyle_example9&quot; class=&quot;csspoststyle_section&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;9. 흔들림(Shake) 애니메이션으로 오류 피드백 제공&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로그인, 회원가입, 댓글 작성 폼 등에서 잘못된 입력이 발생했을 때 입력창을 좌우로 살짝 흔들면, 사용자에게 &amp;ldquo;여기에 문제가 있다&amp;rdquo;는 메시지를 직관적으로 전달할 수 있습니다.&lt;/p&gt;
&lt;div class=&quot;csspoststyle_code-block&quot;&gt;
&lt;div class=&quot;csspoststyle_code-header&quot;&gt;
&lt;div class=&quot;csspoststyle_code-dots&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;span class=&quot;csspoststyle_code-label&quot;&gt;CSS&lt;/span&gt; &lt;button class=&quot;csspoststyle_code-copy&quot; type=&quot;button&quot;&gt;코드 복사&lt;/button&gt;&lt;/div&gt;
&lt;pre class=&quot;css&quot;&gt;&lt;code&gt;.csspoststyle_shake {
  animation: csspoststyle_shake-keyframes 0.5s ease;
}

@keyframes csspoststyle_shake-keyframes {
  0%,
  100% {
    transform: translateX(0);
  }
  20%,
  60% {
    transform: translateX(-10px);
  }
  40%,
  80% {
    transform: translateX(10px);
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보통 오류가 발생했을 때만 자바스크립트로 &lt;span class=&quot;csspoststyle_inline-code&quot;&gt;csspoststyle_shake&lt;/span&gt; 클래스를 잠깐 넣었다가 애니메이션이 끝나면 제거하는 방식으로 사용합니다. 시각적인 피드백과 함께 에러 메시지도 같이 보여 주면 UX가 훨씬 좋아집니다.&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&quot;csspoststyle_example10&quot; class=&quot;csspoststyle_section&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;10. 배경 및 텍스트 컬러 애니메이션&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막으로 분위기를 바꿔 주는 배경&amp;middot;텍스트 색상 애니메이션입니다. 헤더 영역, 히어로 섹션, 사이트 로고 영역 등에 천천히 색이 변하는 효과를 주면, 페이지가 정적인 느낌에서 살아 있는 느낌으로 바뀝니다.&lt;/p&gt;
&lt;div class=&quot;csspoststyle_code-block&quot;&gt;
&lt;div class=&quot;csspoststyle_code-header&quot;&gt;
&lt;div class=&quot;csspoststyle_code-dots&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;span class=&quot;csspoststyle_code-label&quot;&gt;CSS&lt;/span&gt; &lt;button class=&quot;csspoststyle_code-copy&quot; type=&quot;button&quot;&gt;코드 복사&lt;/button&gt;&lt;/div&gt;
&lt;pre class=&quot;css&quot;&gt;&lt;code&gt;.csspoststyle_bg-change {
  animation: csspoststyle_change-bg 5s ease-in-out infinite alternate;
}

@keyframes csspoststyle_change-bg {
  0% {
    background-color: #ff6b6b;
  }
  100% {
    background-color: #feca57;
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span class=&quot;csspoststyle_inline-code&quot;&gt;alternate&lt;/span&gt; 덕분에 색상이 시작색에서 끝색으로 갔다가 다시 시작색으로 자연스럽게 되돌아옵니다. 텍스트에 적용할 때는 &lt;span class=&quot;csspoststyle_inline-code&quot;&gt;background-clip: text&lt;/span&gt;와 그라디언트를 조합해 그라디언트 텍스트 애니메이션을 만들 수 있습니다.&lt;/p&gt;
&lt;/div&gt;
&lt;h2 id=&quot;csspoststyle_consider&quot; data-ke-size=&quot;size26&quot;&gt;CSS 애니메이션 적용 시 꼭 체크해야 할 사항&lt;/h2&gt;
&lt;div class=&quot;csspoststyle_section&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1) 성능 최적화&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;가능하면 &lt;b&gt;transform&lt;/b&gt;과 &lt;b&gt;opacity&lt;/b&gt;만 애니메이션에 사용해 레이아웃 재계산을 줄입니다.&lt;/li&gt;
&lt;li&gt;리스트에 수십 개의 애니메이션을 동시에 돌리기보다는, 시차를 두거나 꼭 필요한 요소만 움직이도록 설계합니다.&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;csspoststyle_inline-code&quot;&gt;will-change&lt;/span&gt; 속성은 정말 성능 이슈가 확인된 요소에만 사용하고, 애니메이션이 끝난 뒤에는 제거해 메모리 사용량을 관리합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;csspoststyle_section&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2) 접근성과 사용자 배려&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;일부 사용자는 강한 모션에 멀미&amp;middot;두통을 느낍니다. 운영체제의 모션 감소 설정을 반영하도록 &lt;span class=&quot;csspoststyle_inline-code&quot;&gt;@media (prefers-reduced-motion: reduce)&lt;/span&gt;를 고려해 보세요.&lt;/li&gt;
&lt;li&gt;이 모드에서는 무한 반복 애니메이션은 꺼 두고, 중요한 전환만 짧은 트랜지션으로 처리하는 식으로 대신할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;csspoststyle_section&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3) CSS 애니메이션과 JS 애니메이션의 역할 분리&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;단순 상태 전환, 반복되는 장식 효과는 CSS 애니메이션이 적합합니다. 선언형 방식이라 브라우저가 최적화하기 쉽습니다.&lt;/li&gt;
&lt;li&gt;스크롤 위치에 따라 변하는 패럴랙스, 드래그에 따라 움직이는 카드, 물리 엔진이 필요한 복잡한 모션은 JS 또는 Web Animations API, GSAP 같은 라이브러리를 고려합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;csspoststyle_section&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4) 사이트에 적용할 때의 실전 팁&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;글 상단: 페이드인과 슬라이드 업을 조합해 타이틀&amp;middot;썸네일을 자연스럽게 등장시키기&lt;/li&gt;
&lt;li&gt;코드 박스: 호버 시 살짝 확대되는 카드 효과로 &amp;ldquo;복사하기 버튼&amp;rdquo;이 더 잘 보이게 만들기&lt;/li&gt;
&lt;li&gt;로딩이 긴 페이지: 로딩 스피너와 스켈레톤 UI를 함께 사용해 사용자의 체감 대기 시간을 줄이기&lt;/li&gt;
&lt;li&gt;신규 기능 배지: 맥박 애니메이션으로 새 기능&amp;middot;이벤트 영역에 시선 집중시키기&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;h2 id=&quot;csspoststyle_deeplink&quot; data-ke-size=&quot;size26&quot;&gt;더 깊이 공부할 수 있는 공식 문서와 추천 글&lt;/h2&gt;
&lt;div class=&quot;csspoststyle_section&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1) 공식 문서&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/CSS/CSS_Animations/Using_CSS_animations&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;MDN Web Docs &amp;ndash; CSS 애니메이션 사용법&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/CSS/transition&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;MDN Web Docs &amp;ndash; CSS transition 속성&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-reduced-motion&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;MDN Web Docs &amp;ndash; prefers-reduced-motion 미디어 쿼리&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;csspoststyle_section&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2) 정리가 잘 된 해외 레퍼런스&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://css-tricks.com/almanac/properties/a/animation/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;CSS-Tricks &amp;ndash; A Complete Guide to CSS Animation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://web.dev/animations-guide/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;web.dev &amp;ndash; Animation Guide for the Web&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 문서들은 최신 브라우저 기준으로 정리되어 있어, 실제 사이트 애니메이션을 설계할 때 큰 도움이 됩니다.&lt;/p&gt;
&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;마무리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;잘 설계된 CSS 애니메이션은 웹사이트의 완성도를 한 단계 끌어올려 주지만, 과도하게 사용하면 오히려 콘텐츠를 방해할 수 있습니다. 이 글에서 정리한 10가지 패턴과 가이드를 기반으로, 자신의 서비스에 맞는 효과만 선택해서 적용해 보세요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히, 사이트에서는, 거창한 모션보다 &amp;ldquo;조금만 잘 움직이는&amp;rdquo; 섬세한 애니메이션이 신뢰감을 높여 줍니다. 애니메이션을 항상 &lt;b&gt;콘텐츠를 돕는 조연&lt;/b&gt;으로 생각한다면, UX&amp;middot;성능&amp;middot;접근성 사이에서 좋은 균형을 잡을 수 있을 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;태그:&lt;/b&gt; CSS, CSS 애니메이션, 웹 디자인, UI/UX, 프론트엔드, 웹 애니메이션, 키프레임, 트랜지션, 인터랙션, 웹 퍼포먼스&lt;/p&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;
&lt;script&gt;
function csspoststyle_initCopyButtons() {
  var csspoststyle_blocks = document.querySelectorAll(&quot;.csspoststyle_code-block&quot;);
  csspoststyle_blocks.forEach(function (csspoststyle_block) {
    var csspoststyle_button = csspoststyle_block.querySelector(&quot;.csspoststyle_code-copy&quot;);
    var csspoststyle_codeElement = csspoststyle_block.querySelector(&quot;pre code&quot;);
    if (!csspoststyle_button || !csspoststyle_codeElement) {
      return;
    }
    csspoststyle_button.addEventListener(&quot;click&quot;, function () {
      var csspoststyle_text = csspoststyle_codeElement.innerText;
      if (navigator.clipboard &amp;&amp; navigator.clipboard.writeText) {
        navigator.clipboard.writeText(csspoststyle_text).then(function () {
          csspoststyle_showToast(&quot;코드를 복사했습니다.&quot;);
        }).catch(function () {
          csspoststyle_fallbackCopy(csspoststyle_text);
        });
      } else {
        csspoststyle_fallbackCopy(csspoststyle_text);
      }
    });
  });
}
function csspoststyle_fallbackCopy(csspoststyle_text) {
  var csspoststyle_textarea = document.createElement(&quot;textarea&quot;);
  csspoststyle_textarea.value = csspoststyle_text;
  csspoststyle_textarea.style.position = &quot;fixed&quot;;
  csspoststyle_textarea.style.left = &quot;-9999px&quot;;
  document.body.appendChild(csspoststyle_textarea);
  csspoststyle_textarea.focus();
  csspoststyle_textarea.select();
  try {
    document.execCommand(&quot;copy&quot;);
    csspoststyle_showToast(&quot;코드를 복사했습니다.&quot;);
  } catch (csspoststyle_error) {
    csspoststyle_showToast(&quot;복사에 실패했습니다. 수동으로 복사해주세요.&quot;);
  }
  document.body.removeChild(csspoststyle_textarea);
}
function csspoststyle_showToast(csspoststyle_message) {
  var csspoststyle_toast = document.createElement(&quot;div&quot;);
  csspoststyle_toast.className = &quot;csspoststyle_toast&quot;;
  csspoststyle_toast.textContent = csspoststyle_message;
  document.body.appendChild(csspoststyle_toast);
  setTimeout(function () {
    if (csspoststyle_toast &amp;&amp; csspoststyle_toast.parentNode) {
      csspoststyle_toast.parentNode.removeChild(csspoststyle_toast);
    }
  }, 2500);
}
document.addEventListener(&quot;DOMContentLoaded&quot;, csspoststyle_initCopyButtons);
&lt;/script&gt;
&lt;/p&gt;</description>
      <category>DEVELOPMENT</category>
      <category>css</category>
      <category>CSS 애니메이션 성능 최적화</category>
      <category>CSS 애니메이션 예제</category>
      <category>CSS 트랜지션</category>
      <category>애니메이션</category>
      <category>웹 애니메이션 접근성</category>
      <category>웹디자인</category>
      <category>웹사이트 모션 효과</category>
      <category>키프레임 애니메이션</category>
      <category>프론트엔드 애니메이션 기법</category>
      <author>간지뽕빨리턴님</author>
      <guid isPermaLink="true">https://odinbox.tistory.com/560</guid>
      <comments>https://odinbox.tistory.com/560#entry560comment</comments>
      <pubDate>Sat, 22 Nov 2025 19:30:19 +0900</pubDate>
    </item>
    <item>
      <title>PFU HHKB Professional HYBRID Type-S</title>
      <link>https://odinbox.tistory.com/559</link>
      <description>&lt;div&gt;
&lt;style&gt;
.hhkb_post-root {
  max-width: 980px;
  margin: 0 auto 40px;
  padding: 24px 20px 40px;
  box-sizing: border-box;
  font-family: system-ui, -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, sans-serif;
  color: #f9fafb;
  background: #020617;
  border-radius: 24px;
  box-shadow: 0 28px 80px rgba(15, 23, 42, 0.85);
}

/* 기본 링크 스타일 */
.hhkb_post-root a {
  color: #38bdf8;
  text-decoration: none;
}
.hhkb_post-root a:hover {
  text-decoration: underline;
}

/* 본문 텍스트 색 강제 (티스토리 기본 스타일 덮어쓰기) */
.hhkb_post-root p,
.hhkb_post-root p *,
.hhkb_post-root li,
.hhkb_post-root li * {
  color: #e5e7eb !important;
}

/* 인라인 코드 색상 */
.hhkb_post-root code {
  padding: 1px 4px;
  border-radius: 4px;
  background: rgba(15, 23, 42, 0.9);
  color: #fb923c !important;
  font-size: 0.9em;
}

/* 제목들 */
.hhkb_post-root h1,
.hhkb_post-root h2,
.hhkb_post-root h3 {
  margin: 0 0 16px;
  font-weight: 700;
  color: #f9fafb;
}
.hhkb_post-root h1 {
  font-size: 2.1rem;
  line-height: 1.3;
}
.hhkb_post-root h2 {
  font-size: 1.5rem;
  margin-top: 40px;
}
.hhkb_post-root h3 {
  font-size: 1.1rem;
  margin-top: 24px;
}

/* 문단 */
.hhkb_post-root p {
  margin: 0 0 14px;
  line-height: 1.7;
  font-size: 0.98rem;
}

/* 리스트 */
.hhkb_post-root ul {
  margin: 4px 0 16px 1.3rem;
  padding: 0;
}
.hhkb_post-root li {
  margin-bottom: 6px;
  font-size: 0.95rem;
}

/* 헤더 카드 */
.hhkb_hero {
  background: radial-gradient(circle at top left, #0b1120 0, #020617 55%, #020617 100%);
  color: #f9fafb;
  border-radius: 22px;
  padding: 22px 20px 20px;
  margin-bottom: 24px;
  box-shadow: 0 24px 50px rgba(15, 23, 42, 0.9);
  position: relative;
  overflow: hidden;
}
.hhkb_hero::before {
  content: &quot;&quot;;
  position: absolute;
  inset: -40%;
  background:
    radial-gradient(circle at 10% 0%, rgba(96, 165, 250, 0.35) 0, transparent 55%),
    radial-gradient(circle at 90% 100%, rgba(248, 250, 252, 0.16) 0, transparent 50%);
  z-index: 0;
}
.hhkb_hero-inner {
  position: relative;
  z-index: 1;
  display: grid;
  grid-template-columns: minmax(0, 3fr) minmax(0, 2.1fr);
  gap: 18px;
  align-items: center;
}
.hhkb_hero-text-main {
  font-size: 0.82rem;
  text-transform: uppercase;
  letter-spacing: 0.18em;
  color: #9ca3af;
  margin-bottom: 10px;
}
.hhkb_hero-title {
  font-size: 1.8rem;
  line-height: 1.35;
  margin-bottom: 10px;
  color: #f9fafb;
}
.hhkb_hero-subtitle {
  font-size: 0.95rem;
  color: #d1d5db;
  margin-bottom: 10px;
}
.hhkb_hero-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 6px;
  font-size: 0.8rem;
  color: #9ca3af;
}
.hhkb_hero-meta-badge {
  border-radius: 999px;
  border: 1px solid rgba(148, 163, 184, 0.55);
  padding: 4px 10px;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  background: rgba(15, 23, 42, 0.96);
  backdrop-filter: blur(10px);
}
.hhkb_hero-badge-dot {
  width: 7px;
  height: 7px;
  border-radius: 999px;
  background: #22c55e;
  box-shadow: 0 0 0 4px rgba(34, 197, 94, 0.35);
}

/* 썸네일 카드 */
.hhkb_hero-thumb {
  border-radius: 16px;
  background: #020617;
  padding: 10px;
  border: 1px solid rgba(148, 163, 184, 0.7);
  position: relative;
  overflow: hidden;
}
.hhkb_hero-thumb-inner {
  border-radius: 10px;
  overflow: hidden;
  background: #020617;
}
.hhkb_hero-thumb-caption {
  font-size: 0.78rem;
  color: #cbd5f5;
  margin-top: 6px;
  text-align: right;
}

/* 상단 해시태그 */
.hhkb_tag-row {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 12px 0 24px;
}
.hhkb_tag-pill {
  font-size: 0.82rem;
  padding: 5px 12px;
  border-radius: 999px;
  background: #020617;
  border: 1px solid #1f2937;
  color: #e5e7eb;
  box-shadow: 0 10px 20px rgba(15, 23, 42, 0.9);
}
.hhkb_tag-pill:hover {
  background: #111827;
}

/* 카드 / 목차 */
.hhkb_main {
  min-width: 0;
}
.hhkb_card {
  background: #020617;
  border-radius: 16px;
  padding: 16px 16px 14px;
  box-shadow: 0 16px 30px rgba(15, 23, 42, 0.9);
  border: 1px solid #1f2937;
  margin-bottom: 20px;
}
.hhkb_card-title {
  font-size: 0.95rem;
  font-weight: 700;
  margin-bottom: 8px;
  color: #f9fafb;
}
.hhkb_card-sub {
  font-size: 0.78rem;
  color: #9ca3af;
  margin-bottom: 8px;
}
.hhkb_toc-list {
  list-style: none;
  padding: 0;
  margin: 0;
  font-size: 0.86rem;
}
.hhkb_toc-list li {
  margin-bottom: 4px;
}
.hhkb_toc-link {
  cursor: pointer;
  color: #e5e7eb;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 6px;
  border-radius: 6px;
  transition: background 0.18s ease, transform 0.18s ease, color 0.18s ease;
}
.hhkb_toc-link-dot {
  width: 5px;
  height: 5px;
  border-radius: 999px;
  background: #6b7280;
}
.hhkb_toc-link:hover {
  background: #111827;
  transform: translateX(2px);
  color: #f9fafb;
}

/* 스펙 테이블 */
.hhkb_spec-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.86rem;
  margin: 6px 0 18px;
  background: #020617;
  border-radius: 12px;
  overflow: hidden;
}
.hhkb_spec-table th,
.hhkb_spec-table td {
  padding: 7px 10px;
  border-bottom: 1px solid #111827;
}
.hhkb_spec-table th {
  width: 26%;
  background: #020617;
  text-align: left;
  font-weight: 600;
  color: #cbd5f5;
}
.hhkb_spec-table td {
  color: #e5e7eb;
}

/* 이미지 블록 */
.hhkb_image-block {
  margin: 18px 0 16px;
  text-align: center;
}
.hhkb_image-inner {
  border-radius: 18px;
  overflow: hidden;
  background: #020617;
  padding: 10px;
  box-shadow: 0 22px 45px rgba(15, 23, 42, 0.95);
  border: 1px solid #0f172a;
}
.hhkb_image-caption {
  font-size: 0.8rem;
  color: #f9fafb;
  margin-top: 6px;
}

/* 하이라이트 박스 */
.hhkb_highlight {
  margin: 18px 0;
  border-radius: 14px;
  padding: 14px 14px 12px;
  background: linear-gradient(135deg, #1e293b, #020617);
  border: 1px solid #334155;
  font-size: 0.9rem;
}
.hhkb_highlight-title {
  font-weight: 700;
  font-size: 0.9rem;
  margin-bottom: 4px;
  color: #bfdbfe;
}

/* 하단 태그 */
.hhkb_tag-footer {
  margin-top: 32px;
  padding-top: 16px;
  border-top: 1px solid #111827;
}
.hhkb_tag-list {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
.hhkb_tag-chip {
  font-size: 0.82rem;
  padding: 5px 12px;
  border-radius: 999px;
  background: #020617;
  border: 1px solid #1f2937;
  color: #e5e7eb;
  box-shadow: 0 10px 22px rgba(15, 23, 42, 0.9);
}
.hhkb_tag-chip:hover {
  background: #111827;
}

/* 버튼 */
.hhkb_button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 7px 14px;
  border-radius: 999px;
  font-size: 0.88rem;
  font-weight: 600;
  border: none;
  outline: none;
  cursor: pointer;
  background: linear-gradient(135deg, #22c55e, #16a34a);
  color: #f9fafb;
  box-shadow: 0 12px 25px rgba(22, 163, 74, 0.6);
  transition: transform 0.15s ease, box-shadow 0.15s ease, filter 0.15s ease;
}
.hhkb_button:hover {
  transform: translateY(-1px);
  box-shadow: 0 16px 35px rgba(22, 163, 74, 0.7);
  filter: brightness(1.03);
}
.hhkb_button span.hhkb_button-icon {
  font-size: 1.05em;
}

/* 공통 호버 애니메이션 */
.hhkb_animate {
  transition: transform 0.45s ease, box-shadow 0.45s ease;
}
.hhkb_animate:hover {
  transform: translateY(-1px);
}

/* 반응형 */
@media (max-width: 900px) {
  .hhkb_hero-inner {
    grid-template-columns: minmax(0, 1.7fr);
  }
}
@media (max-width: 600px) {
  .hhkb_post-root {
    padding: 16px 12px 32px;
  }
  .hhkb_hero {
    padding: 18px 14px 16px;
  }
  .hhkb_hero-title {
    font-size: 1.5rem;
  }
}
&lt;/style&gt;
&lt;/div&gt;
&lt;div class=&quot;hhkb_post-root&quot;&gt;
&lt;section class=&quot;hhkb_hero hhkb_animate&quot; data-hhkb-section=&quot;top&quot;&gt;
&lt;div class=&quot;hhkb_hero-inner&quot;&gt;
&lt;div&gt;
&lt;div class=&quot;hhkb_hero-text-main&quot;&gt;DEVELOPER KEYBOARD REVIEW&lt;/div&gt;
&lt;h1 class=&quot;hhkb_hero-title&quot;&gt;HHKB Hybrid&lt;br /&gt;Professional Type-S&lt;br /&gt;하루 종일 코딩하는 개발자의 실사용 리뷰&lt;/h1&gt;
&lt;p class=&quot;hhkb_hero-subtitle&quot; data-ke-size=&quot;size16&quot;&gt;일본 직구, 첫 제품 불량 교환, 그리고 이제는 메인 키보드가 된 HHKB Type-S. 유선&amp;middot;무선 하이브리드, 무접점 키감, DIP 스위치와 키맵핑까지 한 번에 정리합니다.&lt;/p&gt;
&lt;div class=&quot;hhkb_hero-meta&quot;&gt;
&lt;div class=&quot;hhkb_hero-meta-badge&quot;&gt;&lt;span class=&quot;hhkb_hero-badge-dot&quot;&gt;&lt;/span&gt; &lt;span&gt;하루 대부분을 키보드 위에서 보내는 개발자의 관점&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;hhkb_hero-meta-badge&quot;&gt;&lt;span&gt;무접점 &amp;middot; 하이브리드 &amp;middot; 60% 레이아웃&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;hhkb_hero-thumb&quot;&gt;
&lt;div class=&quot;hhkb_hero-thumb-inner&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;글 상단 부분 대표 이미지.png&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/2csEW/dJMcajtNed4/FFIZxa19AGKp1VZoAf7UJ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/2csEW/dJMcajtNed4/FFIZxa19AGKp1VZoAf7UJ1/img.png&quot; data-alt=&quot;썸네일&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/2csEW/dJMcajtNed4/FFIZxa19AGKp1VZoAf7UJ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F2csEW%2FdJMcajtNed4%2FFFIZxa19AGKp1VZoAf7UJ1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;400&quot; data-filename=&quot;글 상단 부분 대표 이미지.png&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;썸네일&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;div class=&quot;hhkb_hero-thumb-caption&quot;&gt;데스크 한 켠을 책임지는 메인 키보드, HHKB Hybrid Professional Type-S&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;div class=&quot;hhkb_tag-row hhkb_animate&quot;&gt;&lt;span class=&quot;hhkb_tag-pill&quot;&gt;#HHKB&lt;/span&gt; &lt;span class=&quot;hhkb_tag-pill&quot;&gt;#해피해킹&lt;/span&gt; &lt;span class=&quot;hhkb_tag-pill&quot;&gt;#개발자키보드&lt;/span&gt; &lt;span class=&quot;hhkb_tag-pill&quot;&gt;#무접점키보드&lt;/span&gt; &lt;span class=&quot;hhkb_tag-pill&quot;&gt;#HybridTypeS&lt;/span&gt;&lt;/div&gt;
&lt;main class=&quot;hhkb_main&quot;&gt;
&lt;div class=&quot;hhkb_card hhkb_animate&quot;&gt;
&lt;div class=&quot;hhkb_card-title&quot;&gt;목차&lt;/div&gt;
&lt;div class=&quot;hhkb_card-sub&quot;&gt;궁금한 부분부터 바로 읽어보세요. (H2/H3 기준, 티스토리 자동 목차도 함께 생성됩니다.)&lt;/div&gt;
&lt;ul class=&quot;hhkb_toc-list&quot; style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span class=&quot;hhkb_toc-link&quot; data-hhkb-target=&quot;intro&quot;&gt;&lt;span class=&quot;hhkb_toc-link-dot&quot;&gt;&lt;/span&gt; 서론 &amp;ndash; 왜 HHKB인가&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;hhkb_toc-link&quot; data-hhkb-target=&quot;specs&quot;&gt;&lt;span class=&quot;hhkb_toc-link-dot&quot;&gt;&lt;/span&gt; 제품 정보 요약&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;hhkb_toc-link&quot; data-hhkb-target=&quot;unboxing&quot;&gt;&lt;span class=&quot;hhkb_toc-link-dot&quot;&gt;&lt;/span&gt; 개봉기&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;hhkb_toc-link&quot; data-hhkb-target=&quot;design&quot;&gt;&lt;span class=&quot;hhkb_toc-link-dot&quot;&gt;&lt;/span&gt; 디자인 &amp;amp; 구조&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;hhkb_toc-link&quot; data-hhkb-target=&quot;review&quot;&gt;&lt;span class=&quot;hhkb_toc-link-dot&quot;&gt;&lt;/span&gt; 사용 후기&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;hhkb_toc-link&quot; data-hhkb-target=&quot;settings&quot;&gt;&lt;span class=&quot;hhkb_toc-link-dot&quot;&gt;&lt;/span&gt; 설정 팁 (블루투스&amp;middot;DIP&amp;middot;키맵)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;hhkb_toc-link&quot; data-hhkb-target=&quot;conclusion&quot;&gt;&lt;span class=&quot;hhkb_toc-link-dot&quot;&gt;&lt;/span&gt; 마무리 &amp;amp; 추천 대상&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;section id=&quot;hhkb_intro&quot; class=&quot;hhkb_animate&quot; data-hhkb-section=&quot;intro&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;서론 &amp;ndash; 왜 하필 HHKB였을까?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저는 직업상 하루 대부분을 IDE와 터미널 앞에서 보내는 개발자입니다. 그래서 마우스보다 키보드를 더 많이 쓰고, 자연스럽게 키보드에 대한 욕심도 커졌습니다. 체리 스위치 계열의 기계식, 저소음 적축, 펜타그래프까지 여러 종류를 써봤지만 항상 &amp;ldquo;조금만 더 조용했으면&amp;hellip;&amp;rdquo;, &amp;ldquo;손 이동이 조금만 덜했으면&amp;hellip;&amp;rdquo; 하는 아쉬움이 남았습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러다 커뮤니티와 유튜브, 블로그를 돌다 보면 반드시 한 번은 마주치는 이름이 있습니다. 바로 &lt;b&gt;HHKB(Happy Hacking Keyboard)&lt;/b&gt;. 키 개수도 적고, 방향키도 없고, 일반 배열과는 많이 다른데도 많은 개발자들이 &amp;ldquo;결국은 HHKB로 돌아온다&amp;rdquo;라는 말을 남기더군요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;작은 60% 배열이라 처음엔 불편할 것 같았지만, &lt;b&gt;Topre 무접점 스위치 + 하이브리드(유선&amp;middot;무선) + OS 전환 + DIP 스위치&lt;/b&gt;라는 조합이 계속 머릿속에 남았습니다. 결국 일본 직구로 &lt;b&gt;HHKB Hybrid Professional Type-S&lt;/b&gt;를 주문했고, 첫 제품은 안타깝게도 흔들면 이물질 굴러가는 듯한 소리가 나서 교환까지 겪었습니다. 하지만 교환 후 받은 제품은 지금까지 제 메인 키보드로 자리를 완전히 잡았습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 글에서는 처음 도착한 박스부터 실제 설정 및 사용, 그리고 개발자로서 느낀 장단점까지 한 번에 정리해보려고 합니다. HHKB를 고민하는 분들께 기준점이 되었으면 합니다.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;hhkb_specs&quot; class=&quot;hhkb_animate&quot; data-hhkb-section=&quot;specs&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;제품 정보 &amp;ndash; HHKB Hybrid Professional Type-S 한눈에 보기&lt;/h2&gt;
&lt;div class=&quot;hhkb_highlight&quot;&gt;
&lt;div class=&quot;hhkb_highlight-title&quot;&gt;요약&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HHKB Hybrid Professional Type-S는 &lt;b&gt;무접점 토프레 스위치&lt;/b&gt; 기반의 &lt;b&gt;60% 컴팩트 배열&lt;/b&gt; 키보드로, &lt;b&gt;블루투스 4대 멀티 페어링 + USB-C 유선&lt;/b&gt;을 동시에 지원하는 하이브리드 모델입니다. Type-S는 &amp;lsquo;Silent&amp;rsquo; 버전으로, 기본 HHKB보다 타건 소음을 눈에 띄게 줄여줍니다.&lt;/p&gt;
&lt;/div&gt;
&lt;table class=&quot;hhkb_spec-table&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;th&gt;모델명&lt;/th&gt;
&lt;td&gt;HHKB Professional HYBRID Type-S (무접점, 저소음)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;스위치&lt;/th&gt;
&lt;td&gt;정전용량 무접점 Topre, 약 45g, Type-S 저소음 튜닝&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;배열&lt;/th&gt;
&lt;td&gt;60% 컴팩트 배열, HHKB 고유 레이아웃 (Control 홈포지션, 방향키 레이어)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;연결&lt;/th&gt;
&lt;td&gt;Bluetooth 최대 4대 멀티 페어링, USB-C 유선 연결&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;지원 OS&lt;/th&gt;
&lt;td&gt;Windows / macOS / iOS / Android (DIP 스위치로 Mac/Win 모드 전환)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;전원&lt;/th&gt;
&lt;td&gt;AA 건전지 2개 (블루투스), USB-C 연결 시 외부 전원&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;키캡&lt;/th&gt;
&lt;td&gt;PBT 소재, 염료승화 각인, 내구성이 높고 번들거림이 적음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;특징&lt;/th&gt;
&lt;td&gt;키맵핑 소프트웨어 지원, DIP 스위치, 절전 모드, 컨트롤/캡스락 위치 최적화&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/section&gt;
&lt;section id=&quot;hhkb_unboxing&quot; class=&quot;hhkb_animate&quot; data-hhkb-section=&quot;unboxing&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;개봉기 &amp;ndash; 일본에서 온 작은 패키지&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HHKB Hybrid Type-S는 일본 직구로 주문했습니다. 생각보다 작은 택배 박스 안에 또 한 번의 박스, 그리고 그 안에 정갈하게 포장된 키보드가 들어있었습니다. 패키징은 전체적으로 &amp;ldquo;과하지 않게, 딱 필요한 만큼&amp;rdquo;이라는 느낌이 강했습니다.&lt;/p&gt;
&lt;div class=&quot;hhkb_image-block&quot;&gt;
&lt;div class=&quot;hhkb_image-inner&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2274&quot; data-origin-height=&quot;1280&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Y5Dsj/dJMcahpcWLX/MzJrunRGdtO1TKLYkshHcK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Y5Dsj/dJMcahpcWLX/MzJrunRGdtO1TKLYkshHcK/img.png&quot; data-alt=&quot;제품도착직후포장박스&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Y5Dsj/dJMcahpcWLX/MzJrunRGdtO1TKLYkshHcK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FY5Dsj%2FdJMcahpcWLX%2FMzJrunRGdtO1TKLYkshHcK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2274&quot; height=&quot;1280&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2274&quot; data-origin-height=&quot;1280&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;제품도착직후포장박스&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;div class=&quot;hhkb_image-caption&quot;&gt;일본에서 도착한 첫 박스. 예상보다 작고 단단하게 포장되어 있었습니다.&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;hhkb_image-block&quot;&gt;
&lt;div class=&quot;hhkb_image-inner&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2274&quot; data-origin-height=&quot;1280&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bGei0M/dJMcaap474A/5fE23H0kVYx4wl0fLYEjok/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bGei0M/dJMcaap474A/5fE23H0kVYx4wl0fLYEjok/img.png&quot; data-alt=&quot;제품상자&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bGei0M/dJMcaap474A/5fE23H0kVYx4wl0fLYEjok/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbGei0M%2FdJMcaap474A%2F5fE23H0kVYx4wl0fLYEjok%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2274&quot; height=&quot;1280&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2274&quot; data-origin-height=&quot;1280&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;제품상자&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;div class=&quot;hhkb_image-caption&quot;&gt;겉 포장을 벗기면 나오는 HHKB 전용 박스. 군더더기 없는 디자인입니다.&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;hhkb_image-block&quot;&gt;
&lt;div class=&quot;hhkb_image-inner&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2274&quot; data-origin-height=&quot;1280&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bGhb6a/dJMcadUD6mS/vgE29POsMt1YPSdkLKy6q0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bGhb6a/dJMcadUD6mS/vgE29POsMt1YPSdkLKy6q0/img.png&quot; data-alt=&quot;제품온직후배송박스안물품&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bGhb6a/dJMcadUD6mS/vgE29POsMt1YPSdkLKy6q0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbGhb6a%2FdJMcadUD6mS%2FvgE29POsMt1YPSdkLKy6q0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2274&quot; height=&quot;1280&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2274&quot; data-origin-height=&quot;1280&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;제품온직후배송박스안물품&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;div class=&quot;hhkb_image-caption&quot;&gt;배송 박스 속 본품 박스와 보호재. 충격에 대비한 패킹이 잘 되어 있습니다.&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;hhkb_image-block&quot;&gt;
&lt;div class=&quot;hhkb_image-inner&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2274&quot; data-origin-height=&quot;1280&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/1hMvj/dJMcaap474B/V73vMJ8bJEWv1dDSsQnkI1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/1hMvj/dJMcaap474B/V73vMJ8bJEWv1dDSsQnkI1/img.png&quot; data-alt=&quot;제품상자개봉직후모습&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/1hMvj/dJMcaap474B/V73vMJ8bJEWv1dDSsQnkI1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F1hMvj%2FdJMcaap474B%2FV73vMJ8bJEWv1dDSsQnkI1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2274&quot; height=&quot;1280&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2274&quot; data-origin-height=&quot;1280&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;제품상자개봉직후모습&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;div class=&quot;hhkb_image-caption&quot;&gt;박스를 열면 키보드 본체가 안전하게 고정되어 있습니다.&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;hhkb_image-block&quot;&gt;
&lt;div class=&quot;hhkb_image-inner&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2274&quot; data-origin-height=&quot;1280&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cPFlky/dJMcahpcWLY/ziiJpaJIHKaahkSX8R0rs1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cPFlky/dJMcahpcWLY/ziiJpaJIHKaahkSX8R0rs1/img.png&quot; data-alt=&quot;제품구성품&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cPFlky/dJMcahpcWLY/ziiJpaJIHKaahkSX8R0rs1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcPFlky%2FdJMcahpcWLY%2FziiJpaJIHKaahkSX8R0rs1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2274&quot; height=&quot;1280&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2274&quot; data-origin-height=&quot;1280&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;제품구성품&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;div class=&quot;hhkb_image-caption&quot;&gt;구성품: 키보드 본체, AA 배터리, 설명서 등. 심플하지만 필요한 건 다 있습니다.&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;hhkb_image-block&quot;&gt;
&lt;div class=&quot;hhkb_image-inner&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2274&quot; data-origin-height=&quot;1280&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dguSrN/dJMcahpcWLW/VRA5lt9fSMs5LoKvBpIFvk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dguSrN/dJMcahpcWLW/VRA5lt9fSMs5LoKvBpIFvk/img.png&quot; data-alt=&quot;키보드박스뒷면&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dguSrN/dJMcahpcWLW/VRA5lt9fSMs5LoKvBpIFvk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdguSrN%2FdJMcahpcWLW%2FVRA5lt9fSMs5LoKvBpIFvk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2274&quot; height=&quot;1280&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2274&quot; data-origin-height=&quot;1280&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;키보드박스뒷면&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;div class=&quot;hhkb_image-caption&quot;&gt;박스 뒷면에는 간단한 사양과 시리얼이 표기되어 있습니다.&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;hhkb_image-block&quot;&gt;
&lt;div class=&quot;hhkb_image-inner&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2274&quot; data-origin-height=&quot;1280&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Tu6Za/dJMcaacATdG/uX92khLQqn5kHjQkd5krI1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Tu6Za/dJMcaacATdG/uX92khLQqn5kHjQkd5krI1/img.png&quot; data-alt=&quot;키보드박스옆면1&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Tu6Za/dJMcaacATdG/uX92khLQqn5kHjQkd5krI1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FTu6Za%2FdJMcaacATdG%2FuX92khLQqn5kHjQkd5krI1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2274&quot; height=&quot;1280&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2274&quot; data-origin-height=&quot;1280&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;키보드박스옆면1&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;div class=&quot;hhkb_image-caption&quot;&gt;박스 옆면1 &amp;ndash; 모델명과 브랜드 로고.&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;hhkb_image-block&quot;&gt;
&lt;div class=&quot;hhkb_image-inner&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2274&quot; data-origin-height=&quot;1280&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bnWa1G/dJMcabP6FES/aqralvH6mqu4i68ky3TuQ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bnWa1G/dJMcabP6FES/aqralvH6mqu4i68ky3TuQ0/img.png&quot; data-alt=&quot;키보드박스옆면2&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bnWa1G/dJMcabP6FES/aqralvH6mqu4i68ky3TuQ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbnWa1G%2FdJMcabP6FES%2FaqralvH6mqu4i68ky3TuQ0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2274&quot; height=&quot;1280&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2274&quot; data-origin-height=&quot;1280&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;키보드박스옆면2&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;div class=&quot;hhkb_image-caption&quot;&gt;박스 옆면2 &amp;ndash; 하이브리드(Type-S) 모델 표시.&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;hhkb_image-block&quot;&gt;
&lt;div class=&quot;hhkb_image-inner&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2274&quot; data-origin-height=&quot;1280&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/buPSlD/dJMcaeMMMRJ/n9VJkvhEjuQ36F58dgNF8K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/buPSlD/dJMcaeMMMRJ/n9VJkvhEjuQ36F58dgNF8K/img.png&quot; data-alt=&quot;키보드박스옆면3&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/buPSlD/dJMcaeMMMRJ/n9VJkvhEjuQ36F58dgNF8K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbuPSlD%2FdJMcaeMMMRJ%2Fn9VJkvhEjuQ36F58dgNF8K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2274&quot; height=&quot;1280&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2274&quot; data-origin-height=&quot;1280&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;키보드박스옆면3&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;div class=&quot;hhkb_image-caption&quot;&gt;박스 옆면3 &amp;ndash; 간단한 마케팅 문구와 스펙 요약.&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;hhkb_design&quot; class=&quot;hhkb_animate&quot; data-hhkb-section=&quot;design&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;디자인 &amp;ndash; 작은 키보드, 꽉 찬 활용성&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;키보드 본체는 무광스러운 하우징과 PBT 키캡이 조합된, 전형적인 &amp;ldquo;해피해킹&amp;rdquo; 느낌의 디자인입니다. 상단 왼쪽 HHKB 로고, 키캡의 각인, 살짝 높게 솟은 실루엣이 전체적으로 깔끔한 인상을 줍니다.&lt;/p&gt;
&lt;div class=&quot;hhkb_image-block&quot;&gt;
&lt;div class=&quot;hhkb_image-inner&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2274&quot; data-origin-height=&quot;1280&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bPW4is/dJMcaboZqeC/erSl6D2M2aP29jaVpdnBD0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bPW4is/dJMcaboZqeC/erSl6D2M2aP29jaVpdnBD0/img.png&quot; data-alt=&quot;키보드USB-C타입포트&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bPW4is/dJMcaboZqeC/erSl6D2M2aP29jaVpdnBD0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbPW4is%2FdJMcaboZqeC%2FerSl6D2M2aP29jaVpdnBD0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2274&quot; height=&quot;1280&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2274&quot; data-origin-height=&quot;1280&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;키보드USB-C타입포트&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;div class=&quot;hhkb_image-caption&quot;&gt;USB-C 포트 &amp;ndash; 집에서는 유선, 외부에서는 무선으로 사용하기 좋습니다.&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;hhkb_image-block&quot;&gt;
&lt;div class=&quot;hhkb_image-inner&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2274&quot; data-origin-height=&quot;1280&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b34Oue/dJMcaksHrQY/ywiOqYTiylCySa7Ft9NaHK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b34Oue/dJMcaksHrQY/ywiOqYTiylCySa7Ft9NaHK/img.png&quot; data-alt=&quot;DPI설정&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b34Oue/dJMcaksHrQY/ywiOqYTiylCySa7Ft9NaHK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb34Oue%2FdJMcaksHrQY%2FywiOqYTiylCySa7Ft9NaHK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2274&quot; height=&quot;1280&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2274&quot; data-origin-height=&quot;1280&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;DPI설정&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;div class=&quot;hhkb_image-caption&quot;&gt;뒷면 DIP 스위치 &amp;ndash; OS 모드, 키 위치, 절전 모드 등을 하드웨어 수준에서 설정합니다.&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;hhkb_image-block&quot;&gt;
&lt;div class=&quot;hhkb_image-inner&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2274&quot; data-origin-height=&quot;1280&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cRJu2G/dJMcadUD6mU/mtTljLuB9qzM0UYtZEnuBk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cRJu2G/dJMcadUD6mU/mtTljLuB9qzM0UYtZEnuBk/img.png&quot; data-alt=&quot;건전지넣는부분&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cRJu2G/dJMcadUD6mU/mtTljLuB9qzM0UYtZEnuBk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcRJu2G%2FdJMcadUD6mU%2FmtTljLuB9qzM0UYtZEnuBk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2274&quot; height=&quot;1280&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2274&quot; data-origin-height=&quot;1280&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;건전지넣는부분&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;div class=&quot;hhkb_image-caption&quot;&gt;AA 건전지 2개를 넣는 부분. 블루투스 사용 시 전원을 담당합니다.&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;hhkb_image-block&quot;&gt;
&lt;div class=&quot;hhkb_image-inner&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2274&quot; data-origin-height=&quot;1280&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d4WLU2/dJMcaacATdd/2IMf1bi8M8KkrJ8XbA53qK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d4WLU2/dJMcaacATdd/2IMf1bi8M8KkrJ8XbA53qK/img.png&quot; data-alt=&quot;키보드뒷면&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d4WLU2/dJMcaacATdd/2IMf1bi8M8KkrJ8XbA53qK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd4WLU2%2FdJMcaacATdd%2F2IMf1bi8M8KkrJ8XbA53qK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2274&quot; height=&quot;1280&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2274&quot; data-origin-height=&quot;1280&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;키보드뒷면&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;div class=&quot;hhkb_image-caption&quot;&gt;뒷면 전체 모습 &amp;ndash; 미끄럼 방지 패드와 높이 조절 다리가 보입니다.&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;hhkb_image-block&quot;&gt;
&lt;div class=&quot;hhkb_image-inner&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2274&quot; data-origin-height=&quot;1280&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b6tXeY/dJMcaeMMMRI/xjRsyFJo7UdcZftgaPfqz1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b6tXeY/dJMcaeMMMRI/xjRsyFJo7UdcZftgaPfqz1/img.png&quot; data-alt=&quot;키보드모습&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b6tXeY/dJMcaeMMMRI/xjRsyFJo7UdcZftgaPfqz1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb6tXeY%2FdJMcaeMMMRI%2FxjRsyFJo7UdcZftgaPfqz1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2274&quot; height=&quot;1280&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2274&quot; data-origin-height=&quot;1280&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;키보드모습&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;div class=&quot;hhkb_image-caption&quot;&gt;앞쪽에서 바라본 전체 모습. 방향키는 레이어 조합으로 대신합니다.&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;hhkb_image-block&quot;&gt;
&lt;div class=&quot;hhkb_image-inner&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2274&quot; data-origin-height=&quot;1280&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bEshOD/dJMcaeMMMRH/rzO8RfUPskKpmln3PGokGK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bEshOD/dJMcaeMMMRH/rzO8RfUPskKpmln3PGokGK/img.png&quot; data-alt=&quot;키보드상단왼족제품로고&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bEshOD/dJMcaeMMMRH/rzO8RfUPskKpmln3PGokGK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbEshOD%2FdJMcaeMMMRH%2FrzO8RfUPskKpmln3PGokGK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2274&quot; height=&quot;1280&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2274&quot; data-origin-height=&quot;1280&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;키보드상단왼족제품로고&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;div class=&quot;hhkb_image-caption&quot;&gt;왼쪽 상단 제품 로고. 깔끔한 각인이 전체 인상을 결정합니다.&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;hhkb_image-block&quot;&gt;
&lt;div class=&quot;hhkb_image-inner&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2274&quot; data-origin-height=&quot;1280&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bdSvts/dJMcadUD6mW/XYoq3xsDKj3y8otQiYQ7oK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bdSvts/dJMcadUD6mW/XYoq3xsDKj3y8otQiYQ7oK/img.png&quot; data-alt=&quot;키보드옆면&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bdSvts/dJMcadUD6mW/XYoq3xsDKj3y8otQiYQ7oK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbdSvts%2FdJMcadUD6mW%2FXYoq3xsDKj3y8otQiYQ7oK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2274&quot; height=&quot;1280&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2274&quot; data-origin-height=&quot;1280&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;키보드옆면&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;div class=&quot;hhkb_image-caption&quot;&gt;옆에서 본 높이와 각도. 스텝드 스컬쳐 프로파일이라 손목이 편합니다.&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;hhkb_image-block&quot;&gt;
&lt;div class=&quot;hhkb_image-inner&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2274&quot; data-origin-height=&quot;1280&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rHVQn/dJMcadUD6mT/z5RKsNtJbGruNVaEjvHpg0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rHVQn/dJMcadUD6mT/z5RKsNtJbGruNVaEjvHpg0/img.png&quot; data-alt=&quot;키보드전원&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rHVQn/dJMcadUD6mT/z5RKsNtJbGruNVaEjvHpg0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrHVQn%2FdJMcadUD6mT%2Fz5RKsNtJbGruNVaEjvHpg0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2274&quot; height=&quot;1280&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2274&quot; data-origin-height=&quot;1280&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;키보드전원&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;div class=&quot;hhkb_image-caption&quot;&gt;전원 스위치. 물리 스위치라 우발적인 꺼짐/켜짐이 거의 없습니다.&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;hhkb_image-block&quot;&gt;
&lt;div class=&quot;hhkb_image-inner&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2274&quot; data-origin-height=&quot;1280&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/8WP4Z/dJMcaboZqez/FK5a9rbiMWKANX8ZomPamk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/8WP4Z/dJMcaboZqez/FK5a9rbiMWKANX8ZomPamk/img.png&quot; data-alt=&quot;키보드키캡&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/8WP4Z/dJMcaboZqez/FK5a9rbiMWKANX8ZomPamk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F8WP4Z%2FdJMcaboZqez%2FFK5a9rbiMWKANX8ZomPamk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2274&quot; height=&quot;1280&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2274&quot; data-origin-height=&quot;1280&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;키보드키캡&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;div class=&quot;hhkb_image-caption&quot;&gt;키캡 클로즈업. PBT 특유의 보슬한 촉감이 좋고 각인은 또렷합니다.&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;hhkb_review&quot; class=&quot;hhkb_animate&quot; data-hhkb-section=&quot;review&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;사용 후기 &amp;ndash; 하루 종일 써도 손이 편한 키보드&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 먼저 느낀 부분은 &lt;b&gt;타건감과 소음&lt;/b&gt;입니다. 일반 기계식(갈축, 적축, 저소음 적축 등)에 비해 Topre 무접점 스위치는 처음 눌렀을 때 살짝 말캉한 느낌이 있으면서도 확실한 입력감을 줍니다. Type-S는 여기에 저소음 튜닝이 들어가, 야간에도 부담 없이 사용할 수 있을 정도로 조용합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;키가 적기 때문에 손의 이동 범위가 줄어드는 점도 큰 장점입니다. 방향키, Home/End 같은 키들은 Fn 조합으로 대신하지만, &lt;b&gt;코딩할 때 가장 많이 쓰는 키들(Ctrl, Esc, 기호 키들)은 손이 거의 떠나지 않는 위치&lt;/b&gt;에 있습니다. 익숙해지는 데 2~3일 정도만 투자하면 오히려 일반 풀배열보다 효율적인 레이아웃이라는 생각이 듭니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞에서 이야기했듯이, 처음 받은 제품은 안쪽에서 뭔가 굴러다니는 소리가 나서 교환을 진행했습니다. 한 번 교환을 겪고 나니 &amp;ldquo;이 가격에 이런 QC가&amp;hellip;?&amp;rdquo; 라는 실망감도 살짝 들었지만, 교환 후 도착한 제품은 내부 소음 없이 매우 튼튼한 마감 상태를 보여 주었습니다. 이후로는 데일리 메인 키보드로 문제 없이 사용 중입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;장점&lt;/b&gt;을 정리하자면:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;손과 손목이 편한 타건감 (무접점 + 컴팩트 배열)&lt;/li&gt;
&lt;li&gt;Type-S 특유의 정숙함 &amp;ndash; 집/사무실/야간 작업 모두 무난&lt;/li&gt;
&lt;li&gt;Windows / macOS 모두 잘 맞는 OS 전환 및 키맵핑&lt;/li&gt;
&lt;li&gt;4대까지 페어링 되는 블루투스 + USB-C 유선 조합&lt;/li&gt;
&lt;li&gt;책상 위가 정말 깔끔해지는 작은 사이즈&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;단점&lt;/b&gt;은 다음 정도:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;가격 &amp;ndash; &amp;ldquo;키보드에 이렇게까지?&amp;rdquo; 라는 생각이 들 수 있는 수준&lt;/li&gt;
&lt;li&gt;처음 적응까지 2~3일 이상은 투자해야 함 (특히 방향키/Del/Fn 위치)&lt;/li&gt;
&lt;li&gt;정답이 없는 레이아웃이라 사람에 따라 극호/극불호가 갈릴 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;section id=&quot;hhkb_settings&quot; class=&quot;hhkb_animate&quot; data-hhkb-section=&quot;settings&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;설정 팁 &amp;ndash; 블루투스, DIP 스위치, 키맵핑까지&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 블루투스 페어링 &amp;amp; 기기 전환&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;집에서는 데스크톱(유선), 외부에서는 노트북&amp;middot;태블릿(무선) 조합으로 쓰고 있습니다. HHKB Hybrid Type-S는 최대 4대까지 페어링을 지원하기 때문에, 노트북, 태블릿, 스마트폰 등을 모두 등록해두고 필요할 때마다 전환할 수 있습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;전원 켜기: 뒤쪽 전원 스위치를 ON&lt;/li&gt;
&lt;li&gt;페어링 모드: 설명서 기준 조합(예: &lt;code&gt;Fn + Q&lt;/code&gt; 또는 &lt;code&gt;Fn + Ctrl + [숫자]&lt;/code&gt;)으로 진입&lt;/li&gt;
&lt;li&gt;기기 등록: OS에서 블루투스 &amp;rarr; &amp;lsquo;HHKB-Hybrid&amp;rsquo; 선택&lt;/li&gt;
&lt;li&gt;전환: 등록된 기기 간 전환은 &lt;code&gt;Fn + Ctrl + 1~4&lt;/code&gt; 같은 조합으로 변경&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. DIP 스위치 &amp;ndash; OS 모드와 기본 키 위치 바꾸기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HHKB 뒷면의 DIP 스위치에서는 &lt;b&gt;Windows / macOS 모드, Delete/Backspace 위치, Alt/Command 위치, 절전 모드&lt;/b&gt; 등을 설정할 수 있습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;OS 모드&lt;/b&gt;: Mac 위주라면 Mac 모드로 두고, 회사 PC에서는 Windows 모드로 설정&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Delete / Backspace 스왑&lt;/b&gt;: 기존 배열에 익숙하면 Delete 위치를 일반 키보드처럼 맞출 수 있음&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Alt / Command 위치 변경&lt;/b&gt;: macOS 단축키(Cmd+Space, Cmd+Tab 등)에 맞춰 자연스럽게 배치&lt;/li&gt;
&lt;li&gt;&lt;b&gt;절전 스위치&lt;/b&gt;: 몇 분 이상 입력이 없을 때 자동 슬립 &amp;rarr; 배터리 수명 연장&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. 전원&amp;middot;절전 설정 팁&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;집/회사에서 유선으로만 쓸 때는 건전지를 빼두면 누액 걱정을 줄일 수 있습니다.&lt;/li&gt;
&lt;li&gt;블루투스 위주 사용이라면 DIP로 절전 시간을 짧게 설정해두면 배터리가 훨씬 오래갑니다.&lt;/li&gt;
&lt;li&gt;장기간 미사용 예정이라면 전원 스위치를 확실히 OFF로 두는 습관을 들이는 게 좋습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4. 키맵 툴 &amp;ndash; 나만의 HHKB 만들기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HHKB Hybrid Type-S는 &lt;b&gt;전용 키맵핑 소프트웨어&lt;/b&gt;를 제공합니다. USB-C로 PC에 연결한 뒤 아래와 같이 커스터마이징하면 훨씬 편해집니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Caps Lock &amp;rarr; Ctrl, 기존 Ctrl &amp;rarr; Esc: Vim, 터미널 사용할 때 손 이동이 크게 줄어듭니다.&lt;/li&gt;
&lt;li&gt;오른쪽 Command &amp;rarr; 한영 전환 키처럼 사용: macOS / Windows 모두 편하게 전환.&lt;/li&gt;
&lt;li&gt;Fn 조합으로 방향키 / Home / End / PageUp / PageDown을 한 손 안에 배치.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 번 세팅해두면 키보드 내부에 저장되기 때문에, 다른 PC나 OS에 연결해도 같은 키맵을 그대로 사용할 수 있는 게 큰 장점입니다.&lt;/p&gt;
&lt;button class=&quot;hhkb_button&quot; type=&quot;button&quot;&gt; &lt;span class=&quot;hhkb_button-icon&quot;&gt;⬇&lt;/span&gt; HHKB 공식 사이트 / 키맵 툴 안내 &lt;/button&gt;&lt;/section&gt;
&lt;section id=&quot;hhkb_conclusion&quot; class=&quot;hhkb_animate&quot; data-hhkb-section=&quot;conclusion&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;마무리 &amp;ndash; 이런 분들께 추천합니다&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음 HHKB를 봤을 때 느낀 생각은 &amp;ldquo;너무 비싸고, 너무 특이하다&amp;rdquo;였습니다. 그런데 막상 써보니, &lt;b&gt;하루 종일 키보드를 두드리는 사람에게는 합리적인 투자&lt;/b&gt;일 수도 있겠다는 쪽에 가깝습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히 아래와 같은 분들에게는 한 번쯤 진지하게 고려해볼 만한 키보드라고 생각합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;코딩/터미널 작업 비중이 높아 Ctrl, Esc, 기호 키를 많이 쓰는 개발자&lt;/li&gt;
&lt;li&gt;책상 공간을 최대한 효율적으로 쓰고 싶은 분 (작은 사이즈, 깔끔한 레이아웃)&lt;/li&gt;
&lt;li&gt;기계식 키보드의 소음이 부담스럽지만, 키감은 포기하기 싫은 분&lt;/li&gt;
&lt;li&gt;Windows와 macOS를 오가며 작업하는 환경&lt;/li&gt;
&lt;li&gt;키보드를 &amp;ldquo;도구&amp;rdquo;이자 &amp;ldquo;취향&amp;rdquo;으로 즐기고 싶은 사람&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론 HHKB는 절대 저렴한 키보드가 아닙니다. 하지만 하루 수천~수만 번 누르는 입력 장치라는 점, 그리고 손목과 손가락의 피로, 소음, 작업 효율까지 고려해보면 &amp;ldquo;나에게 맞는 키보드에 투자한다&amp;rdquo;는 관점에서 충분히 가치 있는 선택이 될 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 글이 HHKB Hybrid Professional Type-S를 고민하시는 분들께 실제 사용자의 경험과 설정 팁, 그리고 구매 판단에 도움이 되었기를 바랍니다.&lt;/p&gt;
&lt;div class=&quot;hhkb_image-block&quot;&gt;
&lt;div class=&quot;hhkb_image-inner&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2274&quot; data-origin-height=&quot;1280&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cQafob/dJMcaboZqeA/d80FbSWHpSpjc7nfjjF7fk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cQafob/dJMcaboZqeA/d80FbSWHpSpjc7nfjjF7fk/img.png&quot; data-alt=&quot;키보드반품포장&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cQafob/dJMcaboZqeA/d80FbSWHpSpjc7nfjjF7fk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcQafob%2FdJMcaboZqeA%2Fd80FbSWHpSpjc7nfjjF7fk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2274&quot; height=&quot;1280&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2274&quot; data-origin-height=&quot;1280&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;키보드반품포장&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;div class=&quot;hhkb_image-caption&quot;&gt;첫 제품은 안타깝게도 불량으로 반품 포장을 했지만, 교환 후에는 만족스럽게 사용 중입니다.&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;hhkb_image-block&quot;&gt;
&lt;div class=&quot;hhkb_image-inner&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2274&quot; data-origin-height=&quot;1280&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Ac02a/dJMcaaRcqTo/DW7a1qVYXkBXNdF0QmbQn1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Ac02a/dJMcaaRcqTo/DW7a1qVYXkBXNdF0QmbQn1/img.png&quot; data-alt=&quot;제품온직후모습&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Ac02a/dJMcaaRcqTo/DW7a1qVYXkBXNdF0QmbQn1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FAc02a%2FdJMcaaRcqTo%2FDW7a1qVYXkBXNdF0QmbQn1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2274&quot; height=&quot;1280&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2274&quot; data-origin-height=&quot;1280&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;제품온직후모습&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;div class=&quot;hhkb_image-caption&quot;&gt;지금은 이렇게 책상 위 한가운데에서, 하루 종일 코드를 받아내는 메인 키보드가 되었습니다.&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;/main&gt;&lt;footer class=&quot;hhkb_tag-footer hhkb_animate&quot;&gt;
&lt;div class=&quot;hhkb_tag-list&quot;&gt;&lt;span class=&quot;hhkb_tag-chip&quot;&gt;#HHKB&lt;/span&gt; &lt;span class=&quot;hhkb_tag-chip&quot;&gt;#해피해킹키보드&lt;/span&gt; &lt;span class=&quot;hhkb_tag-chip&quot;&gt;#개발자키보드추천&lt;/span&gt; &lt;span class=&quot;hhkb_tag-chip&quot;&gt;#무접점키보드&lt;/span&gt; &lt;span class=&quot;hhkb_tag-chip&quot;&gt;#HybridTypeS&lt;/span&gt; &lt;span class=&quot;hhkb_tag-chip&quot;&gt;#Topre&lt;/span&gt; &lt;span class=&quot;hhkb_tag-chip&quot;&gt;#코딩키보드&lt;/span&gt; &lt;span class=&quot;hhkb_tag-chip&quot;&gt;#블루투스키보드&lt;/span&gt; &lt;span class=&quot;hhkb_tag-chip&quot;&gt;#유선무선하이브리드&lt;/span&gt; &lt;span class=&quot;hhkb_tag-chip&quot;&gt;#키보드리뷰&lt;/span&gt;&lt;/div&gt;
&lt;/footer&gt;&lt;/div&gt;
&lt;script&gt;
(function() {
  var hhkb_links = document.querySelectorAll('.hhkb_toc-link');
  hhkb_links.forEach(function(link) {
    link.addEventListener('click', function() {
      var targetId = link.getAttribute('data-hhkb-target');
      if (!targetId) return;
      var section = document.getElementById('hhkb_' + targetId);
      if (!section) return;
      var rect = section.getBoundingClientRect();
      var offsetTop = window.pageYOffset + rect.top - 70;
      window.scrollTo({
        top: offsetTop,
        behavior: 'smooth'
      });
    });
  });
})();
&lt;/script&gt;</description>
      <category>IT/Product</category>
      <category>HHKB</category>
      <category>hybrid</category>
      <category>topre</category>
      <category>type-s</category>
      <category>개발자키보드추천</category>
      <category>무접점키보드</category>
      <category>블루투스키보드</category>
      <category>유선무선하이브리드</category>
      <category>코딩키보드</category>
      <category>해피해킹키보드</category>
      <author>간지뽕빨리턴님</author>
      <guid isPermaLink="true">https://odinbox.tistory.com/559</guid>
      <comments>https://odinbox.tistory.com/559#entry559comment</comments>
      <pubDate>Sat, 15 Nov 2025 11:15:15 +0900</pubDate>
    </item>
    <item>
      <title>갤럭시스마트태그2, 개봉기 및 사용후기</title>
      <link>https://odinbox.tistory.com/558</link>
      <description>&lt;section id=&quot;gst2x&quot; data-gst2=&quot;v1&quot;&gt;
&lt;div&gt;
&lt;style&gt;
  #gst2x{
    --gst2x-ink:#0f172a;--gst2x-muted:#5b6b86;--gst2x-bg:#fff;--gst2x-line:#e7eef7;
    --gst2x-brand:#1f49c9;--gst2x-accent:#67cfff;--gst2x-chip:#f1f6ff;--gst2x-ok:#2fb673;
    --gst2x-shadow:0 16px 40px rgba(5,25,78,.12);
    font-family:Pretendard,&quot;Noto Sans KR&quot;,ui-sans-serif,system-ui;color:var(--gst2x-ink);
    background:var(--gst2x-bg);max-width:980px;margin:0 auto;padding:0 16px 64px;line-height:1.78
  }
  #gst2x .gst2x-hero{
    position:relative;border-radius:22px;margin:18px 0 22px;overflow:hidden;box-shadow:var(--gst2x-shadow);
    background:linear-gradient(120deg,#0a1324,#0b172c,#0a1324);
    animation:gst2x-heroShift 12s ease-in-out infinite
  }
  @keyframes gst2x-heroShift{0%{background-position:0% 50%}50%{background-position:100% 50%}100%{background-position:0% 50%}}
  #gst2x .gst2x-hero-wrap{position:relative;z-index:1;padding:26px 22px 12px}
  #gst2x .gst2x-summary{color:#bcd7ff;font-size:.95rem;margin:0 0 6px 0;letter-spacing:.1px}
  #gst2x .gst2x-hero-title{margin:0;color:#f4f7ff;font-weight:800;letter-spacing:-.2px;line-height:1.24;font-size:clamp(1.8rem,3.6vw,2.5rem)}
  #gst2x .gst2x-sub{margin:8px 0 14px;color:#d7e6ff;font-size:clamp(.95rem,1.6vw,1.06rem)}
  #gst2x .gst2x-hero-thumb{padding:0 22px 22px}
  #gst2x .gst2x-toc{margin:16px 0 22px;background:#f8fbff;border:1px solid var(--gst2x-line);border-radius:18px;padding:14px 16px}
  #gst2x .gst2x-toc-title{display:block;margin-bottom:8px;color:#183a8a}
  #gst2x .gst2x-toc-list{margin:0;padding:0;display:grid;grid-template-columns:1fr;gap:6px}
  #gst2x .gst2x-toc-item{list-style:none;padding:10px 12px 10px 44px;border:1px solid #dbe9ff;background:#fff;border-radius:14px;position:relative}
  #gst2x .gst2x-toc-item::before{content:&quot;&quot;;position:absolute;left:12px;top:50%;transform:translateY(-50%);width:22px;height:22px;border-radius:999px;background:radial-gradient(circle at 30% 30%,#fff,#b7d7ff 60%,#6aa8ff 100%);box-shadow:0 6px 14px rgba(36,96,196,.28)}
  #gst2x .gst2x-toc-link{text-decoration:none;color:#0b3382}
  #gst2x .gst2x-toc-link:hover{text-decoration:underline}
  #gst2x h2{
    display:inline-block;margin:32px 0 12px;padding:8px 14px;border-radius:18px;
    background:linear-gradient(90deg,#e9f2ff,#f7fbff);
    box-shadow:inset 0 0 0 1px #d9e8ff,0 10px 20px rgba(18,52,128,.06);
    font-size:clamp(1.2rem,2.4vw,1.52rem);color:#0b2b86
  }
  #gst2x h3{margin:18px 0 8px;font-size:1.06rem;color:#18356c}
  #gst2x p{margin:10px 0}
  #gst2x .gst2x-hl{background:linear-gradient(120deg,rgba(31,73,201,.16),rgba(103,207,255,.16));padding:2px 6px;border-radius:6px}
  #gst2x .gst2x-grid2{display:grid;grid-template-columns:1fr 1fr;gap:12px}
  @media(max-width:760px){#gst2x .gst2x-grid2{grid-template-columns:1fr}}
  #gst2x .gst2x-photo{border:1px dashed #cfe2ff;background:linear-gradient(180deg,#fbfdff,#f7fbff);color:var(--gst2x-muted);border-radius:16px;padding:12px;text-align:center;margin:16px 0;font-size:.95rem;box-shadow:0 6px 18px rgba(18,47,90,.05)}
  #gst2x .gst2x-photo img{max-width:100%;border-radius:12px;display:block;margin:6px auto 0}
  #gst2x .gst2x-spec{width:100%;border-collapse:collapse;margin:12px 0;font-size:.98rem}
  #gst2x .gst2x-spec th,#gst2x .gst2x-spec td{border:1px solid var(--gst2x-line);padding:10px 12px}
  #gst2x .gst2x-spec th{background:#f1f6ff;text-align:left;width:28%}
  #gst2x .gst2x-steps{display:grid;grid-template-columns:1fr;gap:10px;margin:10px 0}
  #gst2x .gst2x-step{border:1px solid #dce8ff;background:#fff;border-radius:14px;padding:12px 12px 12px 48px;position:relative}
  #gst2x .gst2x-mark{position:absolute;left:12px;top:12px;width:24px;height:24px;border-radius:999px;background:linear-gradient(135deg,#2b60ff,#67cfff);color:#fff;font-weight:700;font-size:.9rem;display:flex;align-items:center;justify-content:center;box-shadow:0 6px 14px rgba(30,80,190,.25)}
  #gst2x .gst2x-tip{background:#f7fbff;border:1px solid var(--gst2x-line);border-radius:14px;padding:12px;margin:12px 0}
  #gst2x .gst2x-kw-cloud{display:flex;flex-wrap:wrap;gap:12px;margin:14px 0 6px}
  #gst2x .gst2x-kw{display:inline-flex;align-items:center;justify-content:center;padding:10px 16px;border-radius:999px;user-select:none;pointer-events:none;color:#0e318a;font-weight:700;background:radial-gradient(60px 30px at 30% 30%,#fff,#d9ebff 60%,#b8d8ff 100%);box-shadow:0 10px 24px rgba(46,101,214,.18),inset 0 0 0 1px #cfe2ff;transition:transform .35s ease,box-shadow .35s ease,filter .35s ease}
  #gst2x .gst2x-kw:hover{transform:translateY(-5px) scale(1.05);box-shadow:0 18px 32px rgba(46,101,214,.25),inset 0 0 0 1px #b5d3ff;filter:saturate(1.08)}
  #gst2x .gst2x-checklist{display:grid;grid-template-columns:1fr;gap:10px;margin:12px 0}
  #gst2x .gst2x-check{position:relative;border:1px solid #dfe9ff;background:#fff;border-radius:14px;padding:12px 12px 12px 48px}
  #gst2x .gst2x-check::before{content:&quot;&quot;;position:absolute;left:12px;top:12px;width:24px;height:24px;border-radius:8px;background:conic-gradient(from 180deg,var(--gst2x-ok),#44d08c);box-shadow:inset 0 0 0 2px #eafff3}
  #gst2x .gst2x-check::after{content:&quot;&quot;;position:absolute;left:19px;top:18px;width:10px;height:6px;border-left:3px solid #fff;border-bottom:3px solid #fff;transform:rotate(-45deg)}
  #gst2x .gst2x-cta{background:linear-gradient(180deg,#fff,#f8fbff);border:1px solid var(--gst2x-line);border-radius:16px;padding:14px 16px;margin:20px 0}
  #gst2x a{color:#0b3382}
&lt;/style&gt;
&lt;/div&gt;
&lt;header class=&quot;gst2x-hero&quot;&gt;
&lt;div class=&quot;gst2x-hero-wrap&quot;&gt;
&lt;p class=&quot;gst2x-summary&quot; data-ke-size=&quot;size16&quot;&gt;분실과 도난을 예방하고 빠르게 찾아야 한다면 이 조합이 가장 간단합니다.&lt;/p&gt;
&lt;h1 class=&quot;gst2x-hero-title&quot;&gt;갤럭시 스마트태그2(EI_T6600) 개봉기 &amp;middot; 연결 방법 &amp;middot; 스펙/후기 총정리&lt;/h1&gt;
&lt;p class=&quot;gst2x-sub&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;gst2x-hero-thumb&quot;&gt;
&lt;div class=&quot;gst2x-photo&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;글 상단 부분 대표 이미지 (2).png&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dRHB66/dJMb9YccfUs/YekGFlKeic0hJ5digTCBKK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dRHB66/dJMb9YccfUs/YekGFlKeic0hJ5digTCBKK/img.png&quot; data-alt=&quot;대표 썸네일 이미지&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dRHB66/dJMb9YccfUs/YekGFlKeic0hJ5digTCBKK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdRHB66%2FdJMb9YccfUs%2FYekGFlKeic0hJ5digTCBKK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;400&quot; data-filename=&quot;글 상단 부분 대표 이미지 (2).png&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;대표 썸네일 이미지&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/header&gt;&lt;nav class=&quot;gst2x-toc&quot; aria-label=&quot;목차&quot;&gt;&lt;b&gt;목차&lt;/b&gt;
&lt;ul class=&quot;gst2x-toc-list&quot; style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li class=&quot;gst2x-toc-item&quot;&gt;&lt;a class=&quot;gst2x-toc-link&quot; href=&quot;#gst2x-intro&quot;&gt;구매 이유와 변화&lt;/a&gt;&lt;/li&gt;
&lt;li class=&quot;gst2x-toc-item&quot;&gt;&lt;a class=&quot;gst2x-toc-link&quot; href=&quot;#gst2x-unbox&quot;&gt;개봉기와 구성품&lt;/a&gt;&lt;/li&gt;
&lt;li class=&quot;gst2x-toc-item&quot;&gt;&lt;a class=&quot;gst2x-toc-link&quot; href=&quot;#gst2x-desc&quot;&gt;제품 설명&lt;/a&gt;&lt;/li&gt;
&lt;li class=&quot;gst2x-toc-item&quot;&gt;&lt;a class=&quot;gst2x-toc-link&quot; href=&quot;#gst2x-design&quot;&gt;디자인과 착용 예시&lt;/a&gt;&lt;/li&gt;
&lt;li class=&quot;gst2x-toc-item&quot;&gt;&lt;a class=&quot;gst2x-toc-link&quot; href=&quot;#gst2x-connect&quot;&gt;SmartThings 연결 방법&lt;/a&gt;&lt;/li&gt;
&lt;li class=&quot;gst2x-toc-item&quot;&gt;&lt;a class=&quot;gst2x-toc-link&quot; href=&quot;#gst2x-spec&quot;&gt;상세 스펙&lt;/a&gt;&lt;/li&gt;
&lt;li class=&quot;gst2x-toc-item&quot;&gt;&lt;a class=&quot;gst2x-toc-link&quot; href=&quot;#gst2x-tips&quot;&gt;실사용 팁&lt;/a&gt;&lt;/li&gt;
&lt;li class=&quot;gst2x-toc-item&quot;&gt;&lt;a class=&quot;gst2x-toc-link&quot; href=&quot;#gst2x-wrap&quot;&gt;총평과 체크리스트&lt;/a&gt;&lt;/li&gt;
&lt;li class=&quot;gst2x-toc-item&quot;&gt;&lt;a class=&quot;gst2x-toc-link&quot; href=&quot;#gst2x-keywords&quot;&gt;본문 키워드&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/nav&gt;
&lt;section id=&quot;gst2x-intro&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;구매 이유와 변화&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span class=&quot;gst2x-hl&quot;&gt;Galaxy SmartTag2(EI_T6600)&lt;/span&gt;은 분실 우려가 있는 물건을 빠르게 찾기 위해 선택했습니다. 전작 대비 마감과 내구성이 개선되었고, IP67 방수/방진을 지원합니다. 교체형 CR2032 배터리를 사용하여 유지 비용이 낮습니다. &lt;span class=&quot;gst2x-hl&quot;&gt;SmartThings&lt;/span&gt;와의 결합으로 실내&amp;middot;실외 모두에서 위치 파악이 수월합니다. UWB를 지원하는 단말에서는 근거리 정밀 탐색 기능이 동작하여 실내 탐색 효율이 높습니다.&lt;/p&gt;
&lt;div class=&quot;gst2x-photo&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;smarttag2_branded_01.jpg&quot; data-origin-width=&quot;901&quot; data-origin-height=&quot;1600&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bJyQ5Z/dJMb9N9FMZ6/mh06F7STvbnSWqi3QLP4T0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bJyQ5Z/dJMb9N9FMZ6/mh06F7STvbnSWqi3QLP4T0/img.jpg&quot; data-alt=&quot;스마트태그2 제품상자 뒷면&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bJyQ5Z/dJMb9N9FMZ6/mh06F7STvbnSWqi3QLP4T0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbJyQ5Z%2FdJMb9N9FMZ6%2Fmh06F7STvbnSWqi3QLP4T0%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;901&quot; height=&quot;1600&quot; data-filename=&quot;smarttag2_branded_01.jpg&quot; data-origin-width=&quot;901&quot; data-origin-height=&quot;1600&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;스마트태그2 제품상자 뒷면&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;gst2x-unbox&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;개봉기와 구성품&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;포장은 재활용 종이 기반으로 간결하게 설계되었습니다. 기본 구성품은 본체, CR2032 배터리 1개, 간단 사용설명서&amp;middot;보증 안내입니다.&lt;/p&gt;
&lt;div class=&quot;gst2x-grid2&quot;&gt;
&lt;div class=&quot;gst2x-photo&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;smarttag2_branded_02.jpg&quot; data-origin-width=&quot;901&quot; data-origin-height=&quot;1600&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/HTaHy/dJMb9NaK4K7/wYPQaO1y1fFQdF3cBX9fFk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/HTaHy/dJMb9NaK4K7/wYPQaO1y1fFQdF3cBX9fFk/img.jpg&quot; data-alt=&quot;스마트태그2 구성품&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/HTaHy/dJMb9NaK4K7/wYPQaO1y1fFQdF3cBX9fFk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHTaHy%2FdJMb9NaK4K7%2FwYPQaO1y1fFQdF3cBX9fFk%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;901&quot; height=&quot;1600&quot; data-filename=&quot;smarttag2_branded_02.jpg&quot; data-origin-width=&quot;901&quot; data-origin-height=&quot;1600&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;스마트태그2 구성품&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;div class=&quot;gst2x-photo&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;smarttag2_branded_08.jpg&quot; data-origin-width=&quot;901&quot; data-origin-height=&quot;1600&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/buZmgh/dJMb9PGp29f/dojLgDvDyThmv3nIyf8QT1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/buZmgh/dJMb9PGp29f/dojLgDvDyThmv3nIyf8QT1/img.jpg&quot; data-alt=&quot;스마트태그2 제품상자 뒷면&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/buZmgh/dJMb9PGp29f/dojLgDvDyThmv3nIyf8QT1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbuZmgh%2FdJMb9PGp29f%2FdojLgDvDyThmv3nIyf8QT1%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;901&quot; height=&quot;1600&quot; data-filename=&quot;smarttag2_branded_08.jpg&quot; data-origin-width=&quot;901&quot; data-origin-height=&quot;1600&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;스마트태그2 제품상자 뒷면&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;gst2x-desc&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;제품 설명&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;EI_T6600은 블루투스 저전력 통신을 기반으로 위치 정보를 공유합니다. 사용자는 SmartThings 앱에서 장치를 등록하고, 지도를 통해 현재 또는 마지막 확인 위치를 파악할 수 있습니다. 분실 모드에서는 주변의 갤럭시 기기가 태그 신호를 익명으로 감지하여 소유자에게 위치 정보를 전달합니다. 버튼 입력은 단일&amp;middot;길게 누르기 동작을 인식하며, 조명이나 에어컨 같은 스마트홈 장치 제어에 연결할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;본체는 작고 가벼운 고리형 구조로 키링, 가방, 애견 목줄 등 다양한 장착 위치에 어울립니다. 생활 스크래치와 오염에 강한 표면 처리로 관리가 쉽습니다.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;gst2x-design&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;디자인과 착용 예시&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;매끈한 고리형 외형은 시각적으로 단정하며 장착 편의성이 우수합니다. 가방 지퍼 손잡이나 열쇠고리에 연결해도 이질감이 적습니다.&lt;/p&gt;
&lt;div class=&quot;gst2x-grid2&quot;&gt;
&lt;div class=&quot;gst2x-photo&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;smarttag2_branded_03.jpg&quot; data-origin-width=&quot;901&quot; data-origin-height=&quot;1600&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d4MC4i/dJMb9MiCYnQ/BnjnkPR2FEP3FuUFsSuXI0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d4MC4i/dJMb9MiCYnQ/BnjnkPR2FEP3FuUFsSuXI0/img.jpg&quot; data-alt=&quot;스마트태그2 앞면&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d4MC4i/dJMb9MiCYnQ/BnjnkPR2FEP3FuUFsSuXI0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd4MC4i%2FdJMb9MiCYnQ%2FBnjnkPR2FEP3FuUFsSuXI0%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;901&quot; height=&quot;1600&quot; data-filename=&quot;smarttag2_branded_03.jpg&quot; data-origin-width=&quot;901&quot; data-origin-height=&quot;1600&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;스마트태그2 앞면&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;div class=&quot;gst2x-photo&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;smarttag2_branded_04.jpg&quot; data-origin-width=&quot;901&quot; data-origin-height=&quot;1600&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oYA6a/dJMb9OU2xvF/S5tOLouYBRKVy1ABVWqa1k/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oYA6a/dJMb9OU2xvF/S5tOLouYBRKVy1ABVWqa1k/img.jpg&quot; data-alt=&quot;스마트태그2 후면&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oYA6a/dJMb9OU2xvF/S5tOLouYBRKVy1ABVWqa1k/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoYA6a%2FdJMb9OU2xvF%2FS5tOLouYBRKVy1ABVWqa1k%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;901&quot; height=&quot;1600&quot; data-filename=&quot;smarttag2_branded_04.jpg&quot; data-origin-width=&quot;901&quot; data-origin-height=&quot;1600&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;스마트태그2 후면&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;gst2x-connect&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;SmartThings 연결 방법&lt;/h2&gt;
&lt;div class=&quot;gst2x-steps&quot;&gt;
&lt;div class=&quot;gst2x-step&quot;&gt;
&lt;div class=&quot;gst2x-mark&quot;&gt;1&lt;/div&gt;
&lt;b&gt;준비&lt;/b&gt; 블루투스를 켠 갤럭시 스마트폰과 최신 SmartThings 앱을 준비합니다.&lt;/div&gt;
&lt;div class=&quot;gst2x-step&quot;&gt;
&lt;div class=&quot;gst2x-mark&quot;&gt;2&lt;/div&gt;
&lt;b&gt;배터리 장착&lt;/b&gt; 커버를 열고 CR2032를 +면이 위로 오게 넣습니다.&lt;/div&gt;
&lt;div class=&quot;gst2x-step&quot;&gt;
&lt;div class=&quot;gst2x-mark&quot;&gt;3&lt;/div&gt;
&lt;b&gt;페어링&lt;/b&gt; 측면 버튼을 길게 눌러 동작음을 확인합니다.&lt;/div&gt;
&lt;div class=&quot;gst2x-step&quot;&gt;
&lt;div class=&quot;gst2x-mark&quot;&gt;4&lt;/div&gt;
&lt;b&gt;앱에서 추가&lt;/b&gt; SmartThings &amp;rarr; 디바이스 &amp;rarr; + &amp;rarr; 디바이스 추가 &amp;rarr; 주변 검색에서 SmartTag2를 선택합니다.&lt;/div&gt;
&lt;div class=&quot;gst2x-step&quot;&gt;
&lt;div class=&quot;gst2x-mark&quot;&gt;5&lt;/div&gt;
&lt;b&gt;권한 허용&lt;/b&gt; 블루투스&amp;middot;위치&amp;middot;인근 기기 권한을 허용합니다.&lt;/div&gt;
&lt;div class=&quot;gst2x-step&quot;&gt;
&lt;div class=&quot;gst2x-mark&quot;&gt;6&lt;/div&gt;
&lt;b&gt;이름과 아이콘&lt;/b&gt; 열쇠, 백팩 등 구분하기 쉬운 이름과 아이콘을 선택합니다.&lt;/div&gt;
&lt;div class=&quot;gst2x-step&quot;&gt;
&lt;div class=&quot;gst2x-mark&quot;&gt;7&lt;/div&gt;
&lt;b&gt;네트워크 참여&lt;/b&gt; SmartThings Find 네트워크 참여를 켭니다.&lt;/div&gt;
&lt;div class=&quot;gst2x-step&quot;&gt;
&lt;div class=&quot;gst2x-mark&quot;&gt;8&lt;/div&gt;
&lt;b&gt;정밀 탐색&lt;/b&gt; UWB 지원 단말이라면 근거리 정밀 탐색을 활성화합니다.&lt;/div&gt;
&lt;div class=&quot;gst2x-step&quot;&gt;
&lt;div class=&quot;gst2x-mark&quot;&gt;9&lt;/div&gt;
&lt;b&gt;동작 확인&lt;/b&gt; 벨 울리기와 지도 위치가 정상인지 확인합니다.&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;gst2x-tip&quot;&gt;&lt;b&gt;문제 해결&lt;/b&gt; 연결 항목이 보이지 않으면 블루투스를 재시작하고, 태그 버튼을 길게 눌러 페어링을 다시 시도합니다. 그래도 실패하면 앱 캐시를 삭제한 뒤 재검색합니다.&lt;/div&gt;
&lt;div class=&quot;gst2x-grid2&quot;&gt;
&lt;div class=&quot;gst2x-photo&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;smarttag2_branded_05.jpg&quot; data-origin-width=&quot;720&quot; data-origin-height=&quot;1414&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bZfcWL/dJMb9MiCYnP/PobwnUyAZMuUvy3IlZvXk1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bZfcWL/dJMb9MiCYnP/PobwnUyAZMuUvy3IlZvXk1/img.jpg&quot; data-alt=&quot;갤럭시 태그 찾기 &amp;amp;middot; 설정과정 1&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bZfcWL/dJMb9MiCYnP/PobwnUyAZMuUvy3IlZvXk1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbZfcWL%2FdJMb9MiCYnP%2FPobwnUyAZMuUvy3IlZvXk1%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;720&quot; height=&quot;1414&quot; data-filename=&quot;smarttag2_branded_05.jpg&quot; data-origin-width=&quot;720&quot; data-origin-height=&quot;1414&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;갤럭시 태그 찾기 &amp;middot; 설정과정 1&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;div class=&quot;gst2x-photo&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;smarttag2_branded_06.jpg&quot; data-origin-width=&quot;720&quot; data-origin-height=&quot;1414&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wXpzo/dJMb9Ywu4nx/E4xVNYDSYObaksqOIhwHm0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wXpzo/dJMb9Ywu4nx/E4xVNYDSYObaksqOIhwHm0/img.jpg&quot; data-alt=&quot;갤럭시 태그 찾기 &amp;amp;middot; 설정과정 2&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wXpzo/dJMb9Ywu4nx/E4xVNYDSYObaksqOIhwHm0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwXpzo%2FdJMb9Ywu4nx%2FE4xVNYDSYObaksqOIhwHm0%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;720&quot; height=&quot;1414&quot; data-filename=&quot;smarttag2_branded_06.jpg&quot; data-origin-width=&quot;720&quot; data-origin-height=&quot;1414&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;갤럭시 태그 찾기 &amp;middot; 설정과정 2&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;gst2x-photo&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;smarttag2_branded_07.jpg&quot; data-origin-width=&quot;720&quot; data-origin-height=&quot;1414&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cpImqH/dJMb9MbQA0W/JpsZ9FGfUmPM75K3sHIHe0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cpImqH/dJMb9MbQA0W/JpsZ9FGfUmPM75K3sHIHe0/img.jpg&quot; data-alt=&quot;갤럭시 태그 찾기 &amp;amp;middot; 설정과정 3&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cpImqH/dJMb9MbQA0W/JpsZ9FGfUmPM75K3sHIHe0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcpImqH%2FdJMb9MbQA0W%2FJpsZ9FGfUmPM75K3sHIHe0%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;720&quot; height=&quot;1414&quot; data-filename=&quot;smarttag2_branded_07.jpg&quot; data-origin-width=&quot;720&quot; data-origin-height=&quot;1414&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;갤럭시 태그 찾기 &amp;middot; 설정과정 3&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;gst2x-spec&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;상세 스펙&lt;/h2&gt;
&lt;table class=&quot;gst2x-spec&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;th&gt;모델&lt;/th&gt;
&lt;td&gt;Galaxy SmartTag2 (EI_T6600)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;무선&lt;/th&gt;
&lt;td&gt;Bluetooth Low Energy, UWB 정밀 탐색(지원 단말 한정)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;방수/방진&lt;/th&gt;
&lt;td&gt;IP67&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;배터리&lt;/th&gt;
&lt;td&gt;CR2032 교체형&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;알림&lt;/th&gt;
&lt;td&gt;벨 울리기, 마지막 위치 기록, 근접 알림&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;네트워크&lt;/th&gt;
&lt;td&gt;SmartThings Find 익명 크라우드 감지&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;자동화&lt;/th&gt;
&lt;td&gt;버튼 액션으로 스마트홈 장치 제어&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;호환&lt;/th&gt;
&lt;td&gt;갤럭시 스마트폰 + SmartThings 앱&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;크기/무게&lt;/th&gt;
&lt;td&gt;소형 경량 고리형(휴대와 장착 용이)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;사용 환경&lt;/th&gt;
&lt;td&gt;실내&amp;middot;실외, 일반 생활 방수 조건&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p class=&quot;gst2x-cta&quot; data-ke-size=&quot;size16&quot;&gt;배터리 수명과 정밀 탐색 성능은 스마트폰 모델, 펌웨어, 온도, 사용 패턴에 따라 달라질 수 있습니다.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;gst2x-tips&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;실사용 팁&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;분실 모드&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SmartThings에서 디바이스를 선택하여 분실 모드를 켭니다. 연락처 메시지를 저장하면 발견자가 휴대폰으로 확인할 수 있습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;정밀 탐색&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;UWB 지원 단말에서는 화살표 안내로 근거리 탐색이 수월합니다. 실내 환경에서 효과가 큽니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;배터리 관리&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;절전 모드를 사용하고 불필요한 벨 울리기를 줄이면 사용 시간을 늘릴 수 있습니다.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;gst2x-wrap&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;총평과 체크리스트&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;EI_T6600은 갤럭시 사용자에게 실질적인 가치를 주는 분실 방지 액세서리입니다. 실내와 실외 모두에서 위치 파악이 빠르며, IP67과 교체형 배터리로 관리가 쉽습니다. iOS 중심 환경에서는 활용에 제약이 있으므로 갤럭시 생태계에서 사용할 때 만족도가 높습니다.&lt;/p&gt;
&lt;div class=&quot;gst2x-checklist&quot;&gt;
&lt;div class=&quot;gst2x-check&quot;&gt;갤럭시 스마트폰을 사용합니다.&lt;/div&gt;
&lt;div class=&quot;gst2x-check&quot;&gt;항상 들고 다니는 물건이 있습니다.&lt;/div&gt;
&lt;div class=&quot;gst2x-check&quot;&gt;스마트홈 자동화를 활용하고 싶습니다.&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;gst2x-keywords&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;본문 키워드&lt;/h2&gt;
&lt;div class=&quot;gst2x-kw-cloud&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;gst2x-kw&quot;&gt;갤럭시태그2&lt;/span&gt; &lt;span class=&quot;gst2x-kw&quot;&gt;Galaxy SmartTag2&lt;/span&gt; &lt;span class=&quot;gst2x-kw&quot;&gt;EI_T6600&lt;/span&gt; &lt;span class=&quot;gst2x-kw&quot;&gt;스마트싱스&lt;/span&gt; &lt;span class=&quot;gst2x-kw&quot;&gt;SmartThings Find&lt;/span&gt; &lt;span class=&quot;gst2x-kw&quot;&gt;UWB 정밀탐색&lt;/span&gt; &lt;span class=&quot;gst2x-kw&quot;&gt;IP67&lt;/span&gt; &lt;span class=&quot;gst2x-kw&quot;&gt;블루투스 태그&lt;/span&gt; &lt;span class=&quot;gst2x-kw&quot;&gt;분실 모드&lt;/span&gt; &lt;span class=&quot;gst2x-kw&quot;&gt;벨 울리기&lt;/span&gt;&lt;/div&gt;
&lt;p style=&quot;color: var(--gst2x-muted); margin-top: 6px;&quot; data-ke-size=&quot;size16&quot;&gt;키워드는 시각 효과만 제공하며 클릭 기능은 제공하지 않습니다.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;</description>
      <category>IT</category>
      <category>EI_T6600</category>
      <category>GalaxySmartTag2</category>
      <category>IP67</category>
      <category>SmartThings Find</category>
      <category>UWB</category>
      <category>갤럭시태그2</category>
      <category>분실방지</category>
      <category>블루투스태그</category>
      <category>스마트싱스</category>
      <category>위치추적기</category>
      <author>간지뽕빨리턴님</author>
      <guid isPermaLink="true">https://odinbox.tistory.com/558</guid>
      <comments>https://odinbox.tistory.com/558#entry558comment</comments>
      <pubDate>Sat, 8 Nov 2025 09:35:15 +0900</pubDate>
    </item>
    <item>
      <title>자동차 하체 수리 가이드</title>
      <link>https://odinbox.tistory.com/557</link>
      <description>&lt;section id=&quot;lfunderprice_article&quot;&gt;
&lt;div&gt;
&lt;style&gt;
    #lfunderprice_article{
      --hyundai-blue:#002c5f;
      --hyundai-sand:#e4cdc3;
      --hyundai-light-sand:#f6f3f2;
      --hyundai-gold:#a36b4f;
      --active-blue:#00aad2;
      --sky-blue:#aacae6;
      --active-red:#e63312;
      --ink:#0f172a;
      --muted:#5b6b86;
      --line:#e7eef7;
      --brand:var(--hyundai-blue);
      --accent:var(--active-blue);
      --bg:#ffffff;
      --shadow:0 10px 30px rgba(3,22,61,.06);
      --r:18px;
      font-family:Pretendard,&quot;Noto Sans KR&quot;,ui-sans-serif,system-ui,-apple-system,Segoe UI,Roboto,&quot;Apple SD Gothic Neo&quot;,&quot;Malgun Gothic&quot;,sans-serif;
      color:var(--ink)
    }
    .lfunderprice_wrap{max-width:1000px;margin:0 auto;padding:28px 18px}
    .lfunderprice_title{font-size:clamp(24px,3.4vw,36px);font-weight:900;letter-spacing:-.01em;margin:0 0 8px}
    .lfunderprice_sub{color:var(--muted);font-size:14px;margin-bottom:16px}
    .lfunderprice_thumb{border:1px solid var(--line);border-radius:16px;background:#fff;box-shadow:var(--shadow);overflow:hidden;margin-bottom:18px}
    .lfunderprice_thumbcap{padding:10px 12px;background:linear-gradient(90deg,var(--hyundai-light-sand),#fff)}
    .lfunderprice_thumbcap b{color:var(--brand)}
    .lfunderprice_hero{border:1px solid var(--line);background:linear-gradient(160deg,#f7fbff 0%,#ffffff 100%);border-radius:20px;padding:clamp(16px,2.4vw,24px);box-shadow:var(--shadow);margin-bottom:24px}

    .lfunderprice_sec{margin:26px 0 18px}
    .lfunderprice_head{display:flex;align-items:center;gap:12px}
    .lfunderprice_titlebar{position:relative;display:flex;align-items:center;gap:10px;padding:10px 14px;border-radius:14px;border:1px solid var(--line);background:#fff;box-shadow:var(--shadow)}
    .lfunderprice_num{width:32px;height:32px;border-radius:10px;background:linear-gradient(135deg,var(--brand),var(--accent));color:#fff;display:flex;align-items:center;justify-content:center;font-weight:900}
    .lfunderprice_h2{font-size:clamp(18px,2.4vw,22px);font-weight:900;margin:0}
    .lfunderprice_titlebar:after{content:&quot;&quot;;position:absolute;left:14px;right:14px;bottom:-6px;height:6px;border-radius:0 0 10px 10px;background:linear-gradient(90deg,rgba(0,44,95,.18),rgba(0,170,210,.18))}
    .lfunderprice_h3{font-size:clamp(15px,2.2vw,18px);font-weight:800;margin:14px 0 8px}
    .lfunderprice_p{line-height:1.72;margin:8px 0 12px}

    .lfunderprice_gallery{display:grid;gap:14px;grid-template-columns:repeat(12,1fr)}
    .lfunderprice_fig{grid-column:span 12;border:1px solid var(--line);border-radius:16px;background:#fff;box-shadow:var(--shadow);overflow:hidden;transition:transform .2s}
    .lfunderprice_fig:hover{transform:translateY(-2px)}
    .lfunderprice_figcap{padding:10px 12px}
    .lfunderprice_figcap h4{margin:0 0 6px 0;font-weight:800}
    .lfunderprice_figcap p{margin:0;color:var(--muted);font-size:13px}
    @media(min-width:860px){.lfunderprice_fig.col-6{grid-column:span 6}.lfunderprice_fig.col-12{grid-column:span 12}}

    .lfunderprice_cards{display:grid;gap:12px;grid-template-columns:repeat(12,1fr)}
    .lfunderprice_card{grid-column:span 12;border:1px solid var(--line);border-radius:16px;padding:14px;background:#fff;box-shadow:var(--shadow);opacity:0;animation:lfunderprice_fade .55s ease forwards}
    @media(min-width:760px){.lfunderprice_card.sm-6{grid-column:span 6}.lfunderprice_card.sm-4{grid-column:span 4}}
    @keyframes lfunderprice_fade{from{transform:translateY(8px);opacity:0}to{transform:translateY(0);opacity:1}}

    .lfunderprice_list{list-style:none;padding:0;margin:8px 0}
    .lfunderprice_list li{position:relative;padding-left:16px;margin:8px 0}
    .lfunderprice_list li::before{content:&quot;&quot;;position:absolute;left:0;top:.68em;width:8px;height:8px;border-radius:50%;background:linear-gradient(135deg,var(--brand),var(--accent))}

    .lfunderprice_table_wrap{overflow-x:auto;border:1px solid var(--line);border-radius:12px;box-shadow:var(--shadow)}
    .lfunderprice_table{width:100%;border-collapse:collapse;min-width:900px}
    .lfunderprice_table th,.lfunderprice_table td{padding:12px 14px;border-bottom:1px solid var(--line);text-align:left}
    .lfunderprice_table thead th{position:sticky;top:0;background:#f3f7ff;font-weight:800}
    .lfunderprice_table tr:hover td{background:#fafcff}

    .lfunderprice_flag{display:inline-block;padding:2px 8px;border-radius:999px;font-size:12px}
    .lfunderprice_flag.bad{background:rgba(230,51,18,.12);color:#7a1b1b;border:1px solid rgba(230,51,18,.25)}
    .lfunderprice_flag.warn{background:rgba(163,107,79,.12);color:#6b3d2a;border:1px solid rgba(163,107,79,.25)}
    .lfunderprice_flag.ok{background:rgba(18,184,134,.12);color:#0c6b57;border:1px solid rgba(18,184,134,.25)}

    .lfunderprice_links{display:flex;gap:10px;flex-wrap:wrap;margin-top:12px}
    .lfunderprice_link{display:inline-flex;align-items:center;gap:10px;padding:10px 14px;border-radius:12px;border:1px solid var(--line);text-decoration:none;color:var(--ink);background:#fff;box-shadow:var(--shadow);transition:transform .15s,box-shadow .15s}
    .lfunderprice_link:hover{transform:translateY(-2px);box-shadow:0 14px 28px rgba(0,0,0,.08)}

    .lfunderprice_note{border:1px dashed var(--line);background:#fbfdff;border-radius:12px;padding:10px 12px;color:var(--muted);font-size:13px}

    .lfunderprice_modal_mask{position:fixed;inset:0;background:rgba(10,22,40,.45);display:none;z-index:9998}
    .lfunderprice_modal{position:fixed;inset:0;display:none;align-items:center;justify-content:center;z-index:9999}
    .lfunderprice_modal_panel{width:min(980px,94vw);max-height:88vh;overflow:auto;background:#fff;border-radius:16px;border:1px solid var(--line);box-shadow:0 24px 60px rgba(0,0,0,.18);animation:lfunderprice_zoom .18s ease}
    @keyframes lfunderprice_zoom{from{transform:scale(.98);opacity:0}to{transform:scale(1);opacity:1}}
    .lfunderprice_modal_hd{display:flex;align-items:center;justify-content:space-between;padding:16px 18px;border-bottom:1px solid var(--line);background:linear-gradient(90deg,var(--sky-blue),#ffffff)}
    .lfunderprice_modal_tit{font-weight:800}
    .lfunderprice_x{background:#fff;border:1px solid var(--line);border-radius:10px;padding:8px 12px;cursor:pointer}
    .lfunderprice_modal_bd{padding:16px 18px}
    .lfunderprice_grid2{display:grid;gap:12px;grid-template-columns:1fr}
    @media(min-width:880px){.lfunderprice_grid2{grid-template-columns:1.1fr .9fr}}
    .lfunderprice_sectionbox{border:1px solid var(--line);border-radius:12px;padding:12px 14px;background:#fff}
    .lfunderprice_table_small{width:100%;border-collapse:collapse}
    .lfunderprice_table_small th,.lfunderprice_table_small td{border-bottom:1px solid var(--line);padding:8px 10px;font-size:13px;text-align:left}
    .lfunderprice_kw{display:flex;gap:6px;flex-wrap:wrap;margin-top:10px}
    .lfunderprice_kw span{border:1px dashed var(--line);padding:6px 10px;border-radius:999px;font-size:12px;background:#fcfdff}
  &lt;/style&gt;
&lt;/div&gt;
&lt;div class=&quot;lfunderprice_wrap&quot;&gt;
&lt;p class=&quot;lfunderprice_sub&quot; data-ke-size=&quot;size16&quot;&gt;하체 소리에 따라 어떤 부품이 고장인지 그리고, 대략적인 정비비용에 대해서 알 수 있어요!&lt;/p&gt;
&lt;figure class=&quot;lfunderprice_thumb&quot; role=&quot;group&quot; aria-label=&quot;현대 컬러 팔레트 썸네일&quot;&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;글 상단 부분 대표 이미지 (1).png&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bSK9Y0/dJMb9VT4EoG/k8wPEQ6y4kBOk699cPVnak/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bSK9Y0/dJMb9VT4EoG/k8wPEQ6y4kBOk699cPVnak/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bSK9Y0/dJMb9VT4EoG/k8wPEQ6y4kBOk699cPVnak/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbSK9Y0%2FdJMb9VT4EoG%2Fk8wPEQ6y4kBOk699cPVnak%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;400&quot; data-filename=&quot;글 상단 부분 대표 이미지 (1).png&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;figcaption class=&quot;lfunderprice_thumbcap&quot; style=&quot;display: none;&quot;&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;b&gt;자동차 하체에 대해서 알아보도록 하겠습니다.&lt;/b&gt;
&lt;section class=&quot;lfunderprice_hero&quot;&gt;
&lt;p class=&quot;lfunderprice_p&quot; data-ke-size=&quot;size16&quot;&gt;LF소나타(2014~2019)의 하체 소음은 드라이브샤프트, 로워암, 스태빌라이저 링크, 타이로드엔드에서 주로 발생합니다. 먼저 사진으로 구조와 위치를 파악하고, 이어지는 표와 매뉴얼로 증상&amp;rarr;점검&amp;rarr;교체 순서대로 확인하세요.&lt;/p&gt;
&lt;/section&gt;
&lt;div id=&quot;sec-gallery&quot; class=&quot;lfunderprice_sec&quot;&gt;
&lt;div class=&quot;lfunderprice_head&quot;&gt;
&lt;div class=&quot;lfunderprice_titlebar&quot;&gt;
&lt;div class=&quot;lfunderprice_num&quot;&gt;01&lt;/div&gt;
&lt;h2 class=&quot;lfunderprice_h2&quot; data-ke-size=&quot;size26&quot;&gt;부품 구조&amp;middot;위치 갤러리&lt;/h2&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;lfunderprice_gallery&quot; aria-label=&quot;부품 사진 4장&quot;&gt;
&lt;figure class=&quot;lfunderprice_fig col-12&quot;&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;684&quot; data-origin-height=&quot;217&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mtjvI/dJMb9PGpFSW/nEnlX9KlAYGHAihjo5ESY1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mtjvI/dJMb9PGpFSW/nEnlX9KlAYGHAihjo5ESY1/img.jpg&quot; data-alt=&quot;드라이브샤프트 구조 (c) 강주원 자동차 홈&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mtjvI/dJMb9PGpFSW/nEnlX9KlAYGHAihjo5ESY1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmtjvI%2FdJMb9PGpFSW%2FnEnlX9KlAYGHAihjo5ESY1%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;684&quot; height=&quot;217&quot; data-origin-width=&quot;684&quot; data-origin-height=&quot;217&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;드라이브샤프트 구조 (c) 강주원 자동차 홈&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;figcaption class=&quot;lfunderprice_figcap&quot; style=&quot;display: none;&quot;&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;드라이브샤프트&lt;/h4&gt;
&lt;figure class=&quot;lfunderprice_fig col-12&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저속 코너 딱딱 소리와 가속 진동이 대표 신호입니다. 부츠만 손상이면 부츠 교체, 조인트 마모가 진행됐으면 재생 또는 신품 어셈블리를 고려합니다.&lt;/p&gt;
&lt;/figure&gt;
&lt;figure class=&quot;lfunderprice_fig col-6&quot;&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;644&quot; data-origin-height=&quot;483&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nYNMG/dJMb9OncfUS/E0wTyGfKi68wQZqkJkfOiK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nYNMG/dJMb9OncfUS/E0wTyGfKi68wQZqkJkfOiK/img.jpg&quot; data-alt=&quot;로워암 (c) 인터넷 사진 [부품]&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nYNMG/dJMb9OncfUS/E0wTyGfKi68wQZqkJkfOiK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnYNMG%2FdJMb9OncfUS%2FE0wTyGfKi68wQZqkJkfOiK%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;644&quot; height=&quot;483&quot; data-origin-width=&quot;644&quot; data-origin-height=&quot;483&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;로워암 (c) 인터넷 사진 [부품]&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;figcaption class=&quot;lfunderprice_figcap&quot; style=&quot;display: none;&quot;&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;로워암&lt;/h4&gt;
&lt;figure class=&quot;lfunderprice_fig col-6&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제동 시 앞머리가 꿀렁거리거나 직진성이 떨어지면 의심합니다. 부싱 균열과 볼조인트 유격, 부츠 손상을 확인하고 좌우 세트 교체 후 얼라이먼트를 진행합니다.&lt;/p&gt;
&lt;/figure&gt;
&lt;figure class=&quot;lfunderprice_fig col-6&quot;&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1000&quot; data-origin-height=&quot;750&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bjFp4j/dJMb9OAJi69/bpkc8tIwBycBDqZKhY2kLk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bjFp4j/dJMb9OAJi69/bpkc8tIwBycBDqZKhY2kLk/img.jpg&quot; data-alt=&quot;스태빌라이저 (c) 인터넷 사진 [부품]&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bjFp4j/dJMb9OAJi69/bpkc8tIwBycBDqZKhY2kLk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbjFp4j%2FdJMb9OAJi69%2Fbpkc8tIwBycBDqZKhY2kLk%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1000&quot; height=&quot;750&quot; data-origin-width=&quot;1000&quot; data-origin-height=&quot;750&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;스태빌라이저 (c) 인터넷 사진 [부품]&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;figcaption class=&quot;lfunderprice_figcap&quot; style=&quot;display: none;&quot;&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;스태빌라이저 링크&lt;/h4&gt;
&lt;figure class=&quot;lfunderprice_fig col-6&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;방지턱&amp;middot;요철에서 딱딱&amp;middot;덜컹 소리가 나면 우선 확인합니다. 링크 볼조인트 부츠 손상과 유격이 핵심이며, 타이로드엔드와 같은 날 작업하면 공임을 줄일 수 있습니다.&lt;/p&gt;
&lt;/figure&gt;
&lt;figure class=&quot;lfunderprice_fig col-12&quot;&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;272&quot; data-origin-height=&quot;139&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bSzhLp/dJMb9fdXbp7/Ij9ytyTK23tyaWptSJDJmK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bSzhLp/dJMb9fdXbp7/Ij9ytyTK23tyaWptSJDJmK/img.png&quot; data-alt=&quot;타이로드엔드 (c) 인터넷 사진&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bSzhLp/dJMb9fdXbp7/Ij9ytyTK23tyaWptSJDJmK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbSzhLp%2FdJMb9fdXbp7%2FIj9ytyTK23tyaWptSJDJmK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;272&quot; height=&quot;139&quot; data-origin-width=&quot;272&quot; data-origin-height=&quot;139&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;타이로드엔드 (c) 인터넷 사진&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;figcaption class=&quot;lfunderprice_figcap&quot; style=&quot;display: none;&quot;&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;타이로드엔드&lt;/h4&gt;
&lt;figure class=&quot;lfunderprice_fig col-12&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;핸들 유격과 딱딱 소리, 복원력 저하가 나타납니다. 교체 후 토(Toe) 재설정이 중요합니다.&lt;/p&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;sec-parts-manual&quot; class=&quot;lfunderprice_sec&quot;&gt;
&lt;div class=&quot;lfunderprice_head&quot;&gt;
&lt;div class=&quot;lfunderprice_titlebar&quot;&gt;
&lt;div class=&quot;lfunderprice_num&quot;&gt;02&lt;/div&gt;
&lt;h2 class=&quot;lfunderprice_h2&quot; data-ke-size=&quot;size26&quot;&gt;부품별 전문 매뉴얼&lt;/h2&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;lfunderprice_cards&quot;&gt;
&lt;article class=&quot;lfunderprice_card sm-6&quot;&gt;
&lt;h3 class=&quot;lfunderprice_h3&quot; data-ke-size=&quot;size23&quot;&gt;드라이브샤프트&lt;/h3&gt;
&lt;p class=&quot;lfunderprice_p&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span class=&quot;lfunderprice_flag bad&quot;&gt;증상&lt;/span&gt; 저속 코너 딱딱 소리, 가속 진동, 부츠 찢김과 그리스 비산&lt;/p&gt;
&lt;p class=&quot;lfunderprice_p&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span class=&quot;lfunderprice_flag warn&quot;&gt;점검&lt;/span&gt; 내&amp;middot;외측 부츠 균열/누유, 조인트 유격 및 소리&lt;/p&gt;
&lt;ul class=&quot;lfunderprice_list&quot; style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;부품가(개당) 180,000원~400,000원&lt;/li&gt;
&lt;li&gt;공임(개당) 70,000원~120,000원&lt;/li&gt;
&lt;li&gt;대안: 부츠 교체 60,000원~120,000원&lt;/li&gt;
&lt;li&gt;예시 번호 LH 49500-L1400, RH 49501-L0010&lt;/li&gt;
&lt;/ul&gt;
&lt;/article&gt;
&lt;article class=&quot;lfunderprice_card sm-6&quot;&gt;
&lt;h3 class=&quot;lfunderprice_h3&quot; data-ke-size=&quot;size23&quot;&gt;로워암&lt;/h3&gt;
&lt;p class=&quot;lfunderprice_p&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span class=&quot;lfunderprice_flag bad&quot;&gt;증상&lt;/span&gt; 제동 시 앞머리 꿀렁, 덜컹, 직진 불안, 타이어 편마모&lt;/p&gt;
&lt;p class=&quot;lfunderprice_p&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span class=&quot;lfunderprice_flag warn&quot;&gt;점검&lt;/span&gt; 부싱 균열, 볼조인트 유격, 부츠 손상&lt;/p&gt;
&lt;ul class=&quot;lfunderprice_list&quot; style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;부품가(개당) 120,000원~260,000원&lt;/li&gt;
&lt;li&gt;공임(개당) 50,000원~90,000원&lt;/li&gt;
&lt;li&gt;예시 번호 RH 54501-C1000, LH 54500-C1000&lt;/li&gt;
&lt;/ul&gt;
&lt;/article&gt;
&lt;article class=&quot;lfunderprice_card sm-6&quot;&gt;
&lt;h3 class=&quot;lfunderprice_h3&quot; data-ke-size=&quot;size23&quot;&gt;스태빌라이저 링크&lt;/h3&gt;
&lt;p class=&quot;lfunderprice_p&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span class=&quot;lfunderprice_flag bad&quot;&gt;증상&lt;/span&gt; 요철 통과 시 딱딱&amp;middot;덜컹, 롤 억제력 저하&lt;/p&gt;
&lt;p class=&quot;lfunderprice_p&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span class=&quot;lfunderprice_flag warn&quot;&gt;점검&lt;/span&gt; 링크 볼조인트 부츠 손상과 유격, 타격음&lt;/p&gt;
&lt;ul class=&quot;lfunderprice_list&quot; style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;부품가(개당) 30,000원~80,000원&lt;/li&gt;
&lt;li&gt;공임(개당) 20,000원~40,000원&lt;/li&gt;
&lt;li&gt;예시 번호 54840-E6000(RH)&lt;/li&gt;
&lt;/ul&gt;
&lt;/article&gt;
&lt;article class=&quot;lfunderprice_card sm-6&quot;&gt;
&lt;h3 class=&quot;lfunderprice_h3&quot; data-ke-size=&quot;size23&quot;&gt;타이로드엔드&lt;/h3&gt;
&lt;p class=&quot;lfunderprice_p&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span class=&quot;lfunderprice_flag bad&quot;&gt;증상&lt;/span&gt; 핸들 유격과 딱딱 소리, 복원력 저하, 고속 떨림&lt;/p&gt;
&lt;p class=&quot;lfunderprice_p&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span class=&quot;lfunderprice_flag warn&quot;&gt;점검&lt;/span&gt; 조향 링크 유격, 부츠 손상&lt;/p&gt;
&lt;ul class=&quot;lfunderprice_list&quot; style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;부품가(개당) 30,000원~80,000원&lt;/li&gt;
&lt;li&gt;공임(개당) 20,000원~40,000원&lt;/li&gt;
&lt;li&gt;예시 번호 RH 56825-C1090, LH 56820-C1000, 56820-L1000&lt;/li&gt;
&lt;/ul&gt;
&lt;/article&gt;
&lt;/div&gt;
&lt;div class=&quot;lfunderprice_note&quot;&gt;부품번호는 연식&amp;middot;트림&amp;middot;엔진&amp;middot;옵션에 따라 달라질 수 있습니다. 정비 전 VIN 또는 차대번호으로 최종 확인하세요.&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;sec-parts-choice&quot; class=&quot;lfunderprice_sec&quot;&gt;
&lt;div class=&quot;lfunderprice_head&quot;&gt;
&lt;div class=&quot;lfunderprice_titlebar&quot;&gt;
&lt;div class=&quot;lfunderprice_num&quot;&gt;03&lt;/div&gt;
&lt;h2 class=&quot;lfunderprice_h2&quot; data-ke-size=&quot;size26&quot;&gt;부품 선택 기준(순정&amp;middot;재생&amp;middot;대체)&lt;/h2&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;lfunderprice_table_wrap&quot;&gt;
&lt;table class=&quot;lfunderprice_table&quot; aria-label=&quot;부품 선택 가이드&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;구분&lt;/th&gt;
&lt;th&gt;장점&lt;/th&gt;
&lt;th&gt;주의&lt;/th&gt;
&lt;th&gt;가격 경향&lt;/th&gt;
&lt;th&gt;권장 상황&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;순정(블루핸즈&amp;middot;오토큐)&lt;/td&gt;
&lt;td&gt;호환성&amp;middot;품질 안정, 정비 이력&amp;middot;보증 처리 용이&lt;/td&gt;
&lt;td&gt;가격 상단&lt;/td&gt;
&lt;td&gt;상&lt;/td&gt;
&lt;td&gt;소음&amp;middot;진동 민감, 장기 보유&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;대체(OEM&amp;middot;애프터마켓)&lt;/td&gt;
&lt;td&gt;가성비, 브랜드 선택 폭&lt;/td&gt;
&lt;td&gt;제조사별 품질 편차&lt;/td&gt;
&lt;td&gt;중&lt;/td&gt;
&lt;td&gt;일반 주행, 예산 최적화&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;재생(리빌트)&lt;/td&gt;
&lt;td&gt;가격 유리, 친환경&lt;/td&gt;
&lt;td&gt;품질&amp;middot;보증 편차, 코어 반납&lt;/td&gt;
&lt;td&gt;하~중&lt;/td&gt;
&lt;td&gt;샤프트 등 신뢰 업체 사용&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;sec-vin&quot; class=&quot;lfunderprice_sec&quot;&gt;
&lt;div class=&quot;lfunderprice_head&quot;&gt;
&lt;div class=&quot;lfunderprice_titlebar&quot;&gt;
&lt;div class=&quot;lfunderprice_num&quot;&gt;04&lt;/div&gt;
&lt;h2 class=&quot;lfunderprice_h2&quot; data-ke-size=&quot;size26&quot;&gt;VIN으로 내 차 부품번호 정확히 찾기&lt;/h2&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;lfunderprice_cards&quot;&gt;
&lt;div class=&quot;lfunderprice_card&quot;&gt;
&lt;div class=&quot;lfunderprice_h3&quot;&gt;5단계 매뉴얼&lt;/div&gt;
&lt;ul class=&quot;lfunderprice_list&quot; style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;차량번호&amp;middot;VIN 확보: 등록증, 전면 유리 하단, 운전석 하단 플레이트 확인&lt;/li&gt;
&lt;li&gt;공식 EPC 조회: 블루핸즈&amp;middot;오토큐에 VIN 전달 후 부품번호 확인&lt;/li&gt;
&lt;li&gt;리비전 확인: 개선품&amp;middot;연식 변경 여부 점검&lt;/li&gt;
&lt;li&gt;호환 대조: 대체&amp;middot;재생 사용 시 OE 번호 일치, 보증 조건 확인&lt;/li&gt;
&lt;li&gt;작업 전 대조: 실제 박스 번호와 EPC 번호 일치, RH/LH 표기 확인&lt;/li&gt;
&lt;li&gt;* 차대번호로 조회 가능.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;sec-hk-cost&quot; class=&quot;lfunderprice_sec&quot;&gt;
&lt;div class=&quot;lfunderprice_head&quot;&gt;
&lt;div class=&quot;lfunderprice_titlebar&quot;&gt;
&lt;div class=&quot;lfunderprice_num&quot;&gt;05&lt;/div&gt;
&lt;h2 class=&quot;lfunderprice_h2&quot; data-ke-size=&quot;size26&quot;&gt;현대&amp;middot;기아 인기 차종 비용 범위&lt;/h2&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;lfunderprice_table_wrap&quot;&gt;
&lt;table class=&quot;lfunderprice_table&quot; aria-label=&quot;현대&amp;middot;기아 인기 차종 하체 비용(참고)&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;차종(세대)&lt;/th&gt;
&lt;th&gt;링크(좌우)&lt;/th&gt;
&lt;th&gt;로워암(좌우)&lt;/th&gt;
&lt;th&gt;드라이브샤프트(좌우)&lt;/th&gt;
&lt;th&gt;타이로드엔드(좌우)&lt;/th&gt;
&lt;th&gt;얼라이먼트&lt;/th&gt;
&lt;th&gt;참고&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;아반떼 CN7&lt;/td&gt;
&lt;td&gt;90,000원~160,000원&lt;/td&gt;
&lt;td&gt;260,000원~400,000원&lt;/td&gt;
&lt;td&gt;360,000원~560,000원&lt;/td&gt;
&lt;td&gt;80,000원~130,000원&lt;/td&gt;
&lt;td&gt;90,000원~120,000원&lt;/td&gt;
&lt;td&gt;준중형&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;쏘나타 LF/DN8&lt;/td&gt;
&lt;td&gt;120,000원~200,000원&lt;/td&gt;
&lt;td&gt;350,000원~500,000원&lt;/td&gt;
&lt;td&gt;450,000원~700,000원&lt;/td&gt;
&lt;td&gt;100,000원~160,000원&lt;/td&gt;
&lt;td&gt;100,000원~150,000원&lt;/td&gt;
&lt;td&gt;중형 기준&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;그랜저 IG/GN7&lt;/td&gt;
&lt;td&gt;140,000원~220,000원&lt;/td&gt;
&lt;td&gt;420,000원~620,000원&lt;/td&gt;
&lt;td&gt;520,000원~780,000원&lt;/td&gt;
&lt;td&gt;110,000원~170,000원&lt;/td&gt;
&lt;td&gt;110,000원~160,000원&lt;/td&gt;
&lt;td&gt;대형&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;스포티지 NQ5&lt;/td&gt;
&lt;td&gt;130,000원~210,000원&lt;/td&gt;
&lt;td&gt;380,000원~560,000원&lt;/td&gt;
&lt;td&gt;520,000원~780,000원&lt;/td&gt;
&lt;td&gt;110,000원~170,000원&lt;/td&gt;
&lt;td&gt;110,000원~160,000원&lt;/td&gt;
&lt;td&gt;SUV 2WD&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;쏘렌토 MQ4(4WD)&lt;/td&gt;
&lt;td&gt;140,000원~230,000원&lt;/td&gt;
&lt;td&gt;420,000원~620,000원&lt;/td&gt;
&lt;td&gt;560,000원~840,000원&lt;/td&gt;
&lt;td&gt;120,000원~180,000원&lt;/td&gt;
&lt;td&gt;120,000원~170,000원&lt;/td&gt;
&lt;td&gt;SUV 4WD&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class=&quot;lfunderprice_note&quot;&gt;표는 평균 범위이며 지역 공임&amp;middot;부품 브랜드&amp;middot;사양에 따라 달라질 수 있습니다.&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;sec-shop-cost&quot; class=&quot;lfunderprice_sec&quot;&gt;
&lt;div class=&quot;lfunderprice_head&quot;&gt;
&lt;div class=&quot;lfunderprice_titlebar&quot;&gt;
&lt;div class=&quot;lfunderprice_num&quot;&gt;06&lt;/div&gt;
&lt;h2 class=&quot;lfunderprice_h2&quot; data-ke-size=&quot;size26&quot;&gt;정비소 유형별 비용 가이드&lt;/h2&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;lfunderprice_table_wrap&quot;&gt;
&lt;table class=&quot;lfunderprice_table&quot; aria-label=&quot;정비소 유형별 하체 비용 비교&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;유형&lt;/th&gt;
&lt;th&gt;특징&lt;/th&gt;
&lt;th&gt;링크(좌우)&lt;/th&gt;
&lt;th&gt;로워암(좌우)&lt;/th&gt;
&lt;th&gt;드라이브샤프트(좌우)&lt;/th&gt;
&lt;th&gt;타이로드엔드(좌우)&lt;/th&gt;
&lt;th&gt;얼라이먼트&lt;/th&gt;
&lt;th&gt;총액 예시&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;현대 블루핸즈&lt;/td&gt;
&lt;td&gt;순정부품, 기록&amp;middot;AS 용이&lt;/td&gt;
&lt;td&gt;120,000원~200,000원&lt;/td&gt;
&lt;td&gt;350,000원~500,000원&lt;/td&gt;
&lt;td&gt;450,000원~700,000원&lt;/td&gt;
&lt;td&gt;100,000원~160,000원&lt;/td&gt;
&lt;td&gt;100,000원~150,000원&lt;/td&gt;
&lt;td&gt;&lt;b&gt;1,100,000원~1,700,000원&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;기아 오토큐&lt;/td&gt;
&lt;td&gt;순정부품, 지역 공임 편차&lt;/td&gt;
&lt;td&gt;100,000원~180,000원&lt;/td&gt;
&lt;td&gt;320,000원~470,000원&lt;/td&gt;
&lt;td&gt;420,000원~660,000원&lt;/td&gt;
&lt;td&gt;90,000원~150,000원&lt;/td&gt;
&lt;td&gt;90,000원~140,000원&lt;/td&gt;
&lt;td&gt;&lt;b&gt;1,000,000원~1,600,000원&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;일반 카센터&lt;/td&gt;
&lt;td&gt;대체&amp;middot;재생 선택 폭 큼&lt;/td&gt;
&lt;td&gt;80,000원~160,000원&lt;/td&gt;
&lt;td&gt;280,000원~420,000원&lt;/td&gt;
&lt;td&gt;380,000원~600,000원&lt;/td&gt;
&lt;td&gt;80,000원~140,000원&lt;/td&gt;
&lt;td&gt;80,000원~120,000원&lt;/td&gt;
&lt;td&gt;&lt;b&gt;900,000원~1,400,000원&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;sec-guides&quot; class=&quot;lfunderprice_sec&quot;&gt;
&lt;div class=&quot;lfunderprice_head&quot;&gt;
&lt;div class=&quot;lfunderprice_titlebar&quot;&gt;
&lt;div class=&quot;lfunderprice_num&quot;&gt;07&lt;/div&gt;
&lt;h2 class=&quot;lfunderprice_h2&quot; data-ke-size=&quot;size26&quot;&gt;관련 가이드&lt;/h2&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;lfunderprice_links&quot;&gt;&lt;a class=&quot;lfunderprice_link&quot; href=&quot;#&quot; data-modal=&quot;noise&quot;&gt;하체 소음 빠른 진단 체크리스트&lt;/a&gt; &lt;a class=&quot;lfunderprice_link&quot; href=&quot;#&quot; data-modal=&quot;align&quot;&gt;얼라이먼트 판별&amp;middot;세팅 가이드&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;sec-end&quot; class=&quot;lfunderprice_sec&quot;&gt;
&lt;div class=&quot;lfunderprice_head&quot;&gt;
&lt;div class=&quot;lfunderprice_titlebar&quot;&gt;
&lt;div class=&quot;lfunderprice_num&quot;&gt;08&lt;/div&gt;
&lt;h2 class=&quot;lfunderprice_h2&quot; data-ke-size=&quot;size26&quot;&gt;마무리&lt;/h2&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p class=&quot;lfunderprice_p&quot; data-ke-size=&quot;size16&quot;&gt;LF소나타는 링크&amp;middot;타이로드엔드&amp;middot;로워암을 세트로 점검하고, 교체 뒤 얼라이먼트를 진행하면 체감 개선이 큽니다. VIN으로 부품번호를 대조해 과잉 정비 없이 정확히 수리하고, 작업 사진과 측정지를 보관해 사후 관리까지 준비하세요.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;lfunderprice_mask&quot; class=&quot;lfunderprice_modal_mask&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div id=&quot;lfunderprice_modal&quot; class=&quot;lfunderprice_modal&quot;&gt;
&lt;div class=&quot;lfunderprice_modal_panel&quot;&gt;
&lt;div class=&quot;lfunderprice_modal_hd&quot;&gt;
&lt;div id=&quot;lfunderprice_modal_title&quot; class=&quot;lfunderprice_modal_tit&quot;&gt;가이드&lt;/div&gt;
&lt;button id=&quot;lfunderprice_close&quot; class=&quot;lfunderprice_x&quot;&gt;닫기&lt;/button&gt;&lt;/div&gt;
&lt;div id=&quot;lfunderprice_modal_body&quot; class=&quot;lfunderprice_modal_bd&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;script&gt;
    (function(){
      document.querySelectorAll(&quot;.lfunderprice_card&quot;).forEach(function(c,i){setTimeout(function(){c.style.opacity=1},70*i)});

      var el=function(id){return document.getElementById(id)};
      var mask=el(&quot;lfunderprice_mask&quot;),modal=el(&quot;lfunderprice_modal&quot;),title=el(&quot;lfunderprice_modal_title&quot;),body=el(&quot;lfunderprice_modal_body&quot;),close=el(&quot;lfunderprice_close&quot;);

      var guides={
        noise:{
          title:&quot;하체 소음 빠른 진단 체크리스트&quot;,
          overview:&quot;소리 위치·속도·노면 조건으로 의심 부품을 빠르게 좁힙니다.&quot;,
          table:[[&quot;소리/상황&quot;,&quot;의심 부품&quot;,&quot;현장 테스트&quot;],
                 [&quot;요철 덜컹&quot;,&quot;스태빌라이저 링크·로워암 부싱&quot;,&quot;저속 방지턱 반복 통과&quot;],
                 [&quot;코너 딱딱&quot;,&quot;드라이브샤프트&quot;,&quot;좌/우 최대 조향 원주 회전&quot;],
                 [&quot;직진 떨림&quot;,&quot;타이로드엔드·얼라이먼트&quot;,&quot;고속 직진과 급제동 관찰&quot;]],
          steps:[&quot;주행 조건(속도·조향각·노면) 기록&quot;,&quot;부츠·부싱·그리스 시각 점검&quot;,&quot;유격 테스트(바·레버 사용)&quot;,&quot;단품 또는 세트 교체 판단&quot;,&quot;정비 후 동일 조건 재점검&quot;],
          notes:[&quot;점검 공임은 무료~30,000원 범위가 일반적입니다.&quot;],
          keywords:[&quot;LF소나타 하체 소음&quot;,&quot;링크 소리 테스트&quot;,&quot;로워암 부싱 교체 시기&quot;]
        },
        align:{
          title:&quot;얼라이먼트 판별·세팅 가이드&quot;,
          overview:&quot;직진 불안·쏠림·편마모를 수치로 교정하는 절차입니다.&quot;,
          table:[[&quot;증상&quot;,&quot;가능 원인&quot;,&quot;우선 확인&quot;],
                 [&quot;쏠림·직진 불안&quot;,&quot;토·캠버 불량, 타이로드·로워암 유격&quot;,&quot;하체 유격 후 측정지 확인&quot;],
                 [&quot;편마모(안쪽·바깥쪽)&quot;,&quot;캠버·캐스터 불균형, 댐퍼 노후&quot;,&quot;마모 패턴 촬영&quot;],
                 [&quot;고속 떨림&quot;,&quot;언밸런스, 허브/조인트 문제&quot;,&quot;휠 밸런스 후 허브 점검&quot;]],
          steps:[&quot;하체 유격 유무 확인&quot;,&quot;타이어 공기압과 마모 패턴 기록&quot;,&quot;측정지(토·캠버·캐스터) 전/후 값 보관&quot;,&quot;하중이 실린 상태에서 체결 토크 재확인&quot;,&quot;100km 주행 후 재측정 예약&quot;],
          notes:[&quot;블루핸즈 100,000원~150,000원, 오토큐 90,000원~140,000원, 일반 카센터 80,000원~120,000원&quot;],
          keywords:[&quot;LF소나타 얼라이먼트 수치&quot;,&quot;쏘나타 편마모 원인&quot;,&quot;얼라이먼트 각도 해석&quot;]
        }
      };

      function smallTable(rows){
        var h=&quot;&lt;table class='lfunderprice_table_small'&gt;&lt;thead&gt;&lt;tr&gt;&quot;;
        rows[0].forEach(function(th){h+=&quot;&lt;th&gt;&quot;+th+&quot;&lt;/th&gt;&quot;});h+=&quot;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&quot;;
        rows.slice(1).forEach(function(r){h+=&quot;&lt;tr&gt;&quot;+r.map(function(td){return &quot;&lt;td&gt;&quot;+td+&quot;&lt;/td&gt;&quot;}).join(&quot;&quot;)+&quot;&lt;/tr&gt;&quot;});h+=&quot;&lt;/tbody&gt;&lt;/table&gt;&quot;;
        return h;
      }

      function openGuide(key){
        var g=guides[key]; if(!g) return;
        title.textContent=g.title;
        var html=&quot;&lt;div class='lfunderprice_grid2'&gt;&quot;;
        html+=&quot;&lt;div class='lfunderprice_sectionbox'&gt;&lt;div class='lfunderprice_h3'&gt;개요&lt;/div&gt;&lt;div class='lfunderprice_p'&gt;&quot;+g.overview+&quot;&lt;/div&gt;&quot;+smallTable(g.table)+&quot;&lt;/div&gt;&quot;;
        html+=&quot;&lt;div class='lfunderprice_sectionbox'&gt;&lt;div class='lfunderprice_h3'&gt;실행 절차&lt;/div&gt;&lt;ul class='lfunderprice_list'&gt;&quot;+g.steps.map(function(s){return &quot;&lt;li&gt;&quot;+s+&quot;&lt;/li&gt;&quot;}).join(&quot;&quot;)+&quot;&lt;/ul&gt;&lt;div class='lfunderprice_h3'&gt;비용 참고·주의&lt;/div&gt;&lt;ul class='lfunderprice_list'&gt;&quot;+g.notes.map(function(s){return &quot;&lt;li&gt;&quot;+s+&quot;&lt;/li&gt;&quot;}).join(&quot;&quot;)+&quot;&lt;/ul&gt;&lt;div class='lfunderprice_h3'&gt;검색 키워드&lt;/div&gt;&lt;div class='lfunderprice_kw'&gt;&quot;+g.keywords.map(function(k){return &quot;&lt;span&gt;&quot;+k+&quot;&lt;/span&gt;&quot;}).join(&quot;&quot;)+&quot;&lt;/div&gt;&lt;/div&gt;&quot;;
        html+=&quot;&lt;/div&gt;&quot;;
        body.innerHTML=html;
        mask.style.display=&quot;block&quot;; modal.style.display=&quot;flex&quot;; document.body.style.overflow=&quot;hidden&quot;;
      }

      function closeGuide(){mask.style.display=&quot;none&quot;;modal.style.display=&quot;none&quot;;document.body.style.overflow=&quot;&quot;}
      close.addEventListener(&quot;click&quot;,closeGuide);
      mask.addEventListener(&quot;click&quot;,closeGuide);
      document.querySelectorAll(&quot;.lfunderprice_link&quot;).forEach(function(a){a.addEventListener(&quot;click&quot;,function(e){e.preventDefault();openGuide(a.getAttribute(&quot;data-modal&quot;))})});
    })();
  &lt;/script&gt;
&lt;script type=&quot;application/ld+json&quot;&gt;
  {&quot;@context&quot;:&quot;https://schema.org&quot;,&quot;@type&quot;:&quot;FAQPage&quot;,&quot;mainEntity&quot;:[
    {&quot;@type&quot;:&quot;Question&quot;,&quot;name&quot;:&quot;링크/로워암 교체 후 얼라이먼트는 꼭 필요한가요?&quot;,&quot;acceptedAnswer&quot;:{&quot;@type&quot;:&quot;Answer&quot;,&quot;text&quot;:&quot;각도가 변하므로 권장합니다. 직진성과 편마모에 직접적입니다.&quot;}},
    {&quot;@type&quot;:&quot;Question&quot;,&quot;name&quot;:&quot;재생·대체 부품을 써도 되나요?&quot;,&quot;acceptedAnswer&quot;:{&quot;@type&quot;:&quot;Answer&quot;,&quot;text&quot;:&quot;가능합니다. 보증 기간과 품질 편차를 확인하고, NVH에 민감하면 순정이 안전합니다.&quot;}},
    {&quot;@type&quot;:&quot;Question&quot;,&quot;name&quot;:&quot;VIN으로 내 차 부품번호는 어떻게 찾나요?&quot;,&quot;acceptedAnswer&quot;:{&quot;@type&quot;:&quot;Answer&quot;,&quot;text&quot;:&quot;블루핸즈·오토큐에 VIN 또는 차대번호를 전달해 EPC로 조회하고, 작업 전에 실제 박스 번호와 대조합니다.&quot;}}
  ]}
  &lt;/script&gt;
&lt;/section&gt;</description>
      <category>DailyRoutine/Car</category>
      <category>VIN으로 부품번호 조회방법</category>
      <category>드라이브샤프트 교체비용</category>
      <category>로워암 부싱 교체</category>
      <category>블루핸즈 정비비용 비교</category>
      <category>스태빌라이저 링크 증상</category>
      <category>얼라이먼트 필요성</category>
      <category>자동차 소음 진단 가이드</category>
      <category>자동차 하체정비 비용표</category>
      <category>타이로드엔드 유격 점검</category>
      <category>하체소음</category>
      <author>간지뽕빨리턴님</author>
      <guid isPermaLink="true">https://odinbox.tistory.com/557</guid>
      <comments>https://odinbox.tistory.com/557#entry557comment</comments>
      <pubDate>Mon, 27 Oct 2025 14:01:27 +0900</pubDate>
    </item>
    <item>
      <title>SQL 재귀 쿼리 완전 정리</title>
      <link>https://odinbox.tistory.com/556</link>
      <description>&lt;div id=&quot;sg-recursive&quot;&gt;
&lt;style&gt;
  #sg-recursive{
    --ink:#0f172a;--muted:#64748b;--brand:#0b5bd3;--accent:#23c1ff;--line:#e2e8f0;--chip:#f1f5f9;--panel:#ffffff;
    font-family:&quot;Noto Sans KR&quot;,Pretendard,ui-sans-serif,system-ui,sans-serif;color:var(--ink)
  }
  #sg-recursive .sg-wrap{max-width:1000px;margin:0 auto;padding:28px 18px}
  #sg-recursive .sg-hero{padding:22px 18px;border-radius:18px;background:
    linear-gradient(135deg,rgba(11,91,211,.08),rgba(35,193,255,.08));border:1px solid rgba(11,91,211,.18)}
  #sg-recursive h1{font-weight:900;letter-spacing:-.01em;font-size:clamp(1.6rem,3.2vw,2.15rem);color:#0b3a8a;margin:0}
  #sg-recursive .sg-sub{margin-top:8px;color:var(--muted)}
  #sg-recursive .sg-rule{height:3px;width:90px;background:linear-gradient(90deg,var(--brand),var(--accent));border-radius:3px;margin:14px 0}
  #sg-recursive h2{margin:26px 0 10px;font-size:clamp(1.22rem,2.2vw,1.5rem);color:#0b3a8a;font-weight:800}
  #sg-recursive h3{margin:18px 0 8px;font-size:clamp(1.04rem,1.8vw,1.16rem);font-weight:700;color:#0b3a8a}
  #sg-recursive p,#sg-recursive ul,#sg-recursive ol{margin:10px 0}
  #sg-recursive a{color:#0b3a8a;text-decoration:none;border-bottom:1px dashed rgba(11,91,211,.35)}
  #sg-recursive a:hover{text-decoration:underline}
  #sg-recursive .sg-card{background:var(--panel);border:1px solid var(--line);border-radius:14px;padding:14px 16px;box-shadow:0 10px 30px rgba(2,6,23,.06)}
  #sg-recursive .sg-toc{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:12px}
  #sg-recursive .sg-chip{display:inline-block;padding:6px 10px;border-radius:999px;background:var(--chip);border:1px solid var(--line);font-weight:600;font-size:.86rem}
  #sg-recursive .sg-badge{display:inline-block;padding:6px 10px;border-radius:999px;background:linear-gradient(90deg,var(--brand),var(--accent));color:#fff;font-weight:700;font-size:.82rem}
  #sg-recursive pre{background:#0b1220;color:#e8edf7;padding:16px;border-radius:12px;overflow:auto;font-size:.93rem;line-height:1.6;margin-top:8px}
  #sg-recursive code{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace}
  #sg-recursive .sg-ol{list-style:none !important;counter-reset:item;margin:8px 0 4px 0;padding-left:0}
  #sg-recursive .sg-ol li{list-style:none !important;margin:6px 0;padding-left:30px;position:relative;color:#334155}
  #sg-recursive .sg-ol li::before{counter-increment:item;content:counter(item) &quot;.&quot;;position:absolute;left:0;top:0;color:#0b5bd3;font-weight:700}
  #sg-recursive .sg-note{background:#f8fbff;border:1px dashed #c8e6ff;border-radius:10px;padding:12px 14px}
  #sg-recursive .sg-reveal{opacity:0;transform:translateY(12px);transition:opacity .8s ease,transform .8s ease}
  #sg-recursive .sg-reveal.sg-in{opacity:1;transform:none}
  #sg-recursive .sg-org,#sg-recursive .sg-org ul{list-style:none !important;margin:0;padding-left:0 !important}
  #sg-recursive .sg-org li{list-style:none !important;position:relative;padding:6px 0 6px 22px}
  #sg-recursive .sg-org li::before{content:&quot;&quot;;position:absolute;top:0;left:0;border-left:2px solid #d1d5db;height:100%}
  #sg-recursive .sg-org li::after{content:&quot;&quot;;position:absolute;top:16px;left:0;border-top:2px solid #d1d5db;width:20px}
  #sg-recursive .sg-org li:last-child::before{height:16px}
  #sg-recursive .sg-divider{height:1px;background:linear-gradient(90deg,rgba(11,91,211,.25),rgba(35,193,255,.25));margin:22px 0}
  #sg-recursive .sg-small{font-size:.92rem;color:#4b5563}
  #sg-recursive .sg-tiny{font-size:.8rem;color:#6b7280}
  #sg-recursive .sg-footer{margin-top:28px;padding-top:10px;border-top:1px solid var(--line)}
  #sg-recursive .sg-thumb{max-width:960px;margin:14px auto 22px;padding:10px;border-radius:22px;background:linear-gradient(135deg,rgba(11,91,211,.06),rgba(35,193,255,.06));border:1px solid rgba(11,91,211,.18);box-shadow:0 16px 40px rgba(2,6,23,.08)}
  #sg-recursive .sg-thumb .sg-thumb-inner{position:relative;border-radius:16px;overflow:hidden;background:#0b1220}
  #sg-recursive .sg-thumb img{display:block;width:100%;height:auto;aspect-ratio:16/9;object-fit:cover;transform:scale(1.001)}
  #sg-recursive .sg-thumb .sg-glow{position:absolute;inset:0;pointer-events:none;background:radial-gradient(1200px 200px at 50% 0,rgba(35,193,255,.20),transparent 60%)}
  @media (max-width:640px){
    #sg-recursive .sg-wrap{padding:22px 14px}
    #sg-recursive pre{font-size:.9rem}
    #sg-recursive .sg-toc{grid-template-columns:1fr}
    #sg-recursive .sg-thumb{margin:10px auto 18px;padding:8px;border-radius:18px}
    #sg-recursive .sg-thumb .sg-thumb-inner{border-radius:14px}
  }
  &lt;/style&gt;
&lt;div class=&quot;sg-wrap&quot;&gt;
&lt;section class=&quot;sg-hero sg-reveal&quot;&gt;&lt;span class=&quot;sg-badge&quot;&gt;SQL &amp;middot; 계층형 데이터&lt;/span&gt;
&lt;h1&gt;SQL 재귀 쿼리 완전 정리&lt;/h1&gt;
&lt;p class=&quot;sg-sub&quot; data-ke-size=&quot;size16&quot;&gt;PostgreSQL &amp;middot; Oracle &amp;middot; MySQL 8.0 기준으로 재귀 CTE와 CONNECT BY를 조직도 예제로 설명하며 무한 재귀 원인과 방지 전략, 경로&amp;middot;깊이&amp;middot;상하위 탐색 패턴을 자세히 정리합니다.&lt;/p&gt;
&lt;div class=&quot;sg-rule&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;/section&gt;
&lt;section class=&quot;sg-reveal&quot;&gt;
&lt;div class=&quot;sg-thumb&quot;&gt;
&lt;div class=&quot;sg-thumb-inner&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;글 상단 부분 대표 이미지.png&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bygxS8/dJMb9WyF37v/TuQ7pUmxIGnKfRnk7FtChk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bygxS8/dJMb9WyF37v/TuQ7pUmxIGnKfRnk7FtChk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bygxS8/dJMb9WyF37v/TuQ7pUmxIGnKfRnk7FtChk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbygxS8%2FdJMb9WyF37v%2FTuQ7pUmxIGnKfRnk7FtChk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;400&quot; data-filename=&quot;글 상단 부분 대표 이미지.png&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;div class=&quot;sg-glow&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section class=&quot;sg-reveal sg-card&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;목차&lt;/h2&gt;
&lt;div class=&quot;sg-toc&quot;&gt;
&lt;div&gt;&lt;a href=&quot;#sg-top&quot;&gt;재귀 쿼리&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;&lt;a href=&quot;#sg-why&quot;&gt;재귀 쿼리가 필요한 이유&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;&lt;a href=&quot;#sg-model&quot;&gt;재귀 CTE 동작 모델&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;&lt;a href=&quot;#sg-infinite&quot;&gt;무한 재귀 원인과 방지&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;&lt;a href=&quot;#sg-schema&quot;&gt;예제 스키마와 데이터&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;&lt;a href=&quot;#sg-pg&quot;&gt;PostgreSQL 작성법&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;&lt;a href=&quot;#sg-oracle&quot;&gt;Oracle 작성법&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;&lt;a href=&quot;#sg-mysql&quot;&gt;MySQL 8.0 작성법&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;&lt;a href=&quot;#sg-patterns&quot;&gt;실전 패턴 모음&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;&lt;a href=&quot;#sg-end&quot;&gt;마무리&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;&lt;a href=&quot;#sg-refs&quot;&gt;참조 문서&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section class=&quot;sg-reveal&quot;&gt;
&lt;h2 id=&quot;sg-top&quot; data-ke-size=&quot;size26&quot;&gt;재귀 쿼리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;재귀 쿼리는 자기 자신을 참조하여 계층 구조를 단계적으로 확장하는 질의 방식입니다. 반복적인 자기 조인을 줄이고, 깊이가 달라져도 동일 패턴으로 전체 트리를 탐색합니다. 표준 SQL에서는 &lt;code&gt;WITH RECURSIVE&lt;/code&gt; CTE 형태로 제공되며, Oracle은 추가로 &lt;code&gt;CONNECT BY&lt;/code&gt; 구문을 제공합니다.&lt;/p&gt;
&lt;p class=&quot;sg-small&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span class=&quot;sg-chip&quot;&gt;핵심 개념&lt;/span&gt; 앵커(초기 집합), 재귀(자기참조), 종료(새 행이 없을 때) 조합으로 트리를 완성합니다. 데이터가 바뀌어도 쿼리 구조가 유지되므로 재사용성이 높습니다.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;sg-why&quot; class=&quot;sg-reveal&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;재귀 쿼리가 필요한 이유&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;조직도, 제품 BOM, 댓글 트리, 폴더 구조처럼 부모와 자식 관계가 연쇄적으로 이어지는 데이터는 깊이가 일정하지 않습니다. 전통적인 조인은 깊이만큼 FROM/JOIN 절을 늘려야 하며, 깊이가 변하면 쿼리를 다시 작성해야 합니다. 재귀 쿼리는 동일한 템플릿으로 모든 깊이를 순회하므로 유지보수 비용을 안정적으로 낮춥니다.&lt;/p&gt;
&lt;ol class=&quot;sg-ol sg-small&quot; style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;유연성: 깊이를 모를 때도 전체 트리를 안정적으로 순회합니다.&lt;/li&gt;
&lt;li&gt;가독성: 앵커와 재귀 단계가 분리되어 의도가 명확합니다.&lt;/li&gt;
&lt;li&gt;확장성: 경로, 깊이, 루트&amp;middot;말단 여부 등 부가 정보를 쉽게 도출합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
&lt;section id=&quot;sg-model&quot; class=&quot;sg-reveal&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;재귀 CTE 동작 모델&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;재귀 CTE는 &lt;code&gt;WITH RECURSIVE cte AS (앵커 UNION ALL 재귀)&lt;/code&gt; 형태로 작성합니다. 내부 실행은 다음과 같습니다.&lt;/p&gt;
&lt;ol class=&quot;sg-ol&quot; style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;앵커 단계에서 루트 후보를 한 번 조회하여 작업 집합에 적재합니다.&lt;/li&gt;
&lt;li&gt;재귀 단계에서 직전 단계 결과를 입력으로 사용해 자식 행을 찾고 누적합니다.&lt;/li&gt;
&lt;li&gt;새로운 행이 더 이상 생성되지 않으면 반복이 종료되고 누적 결과를 반환합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&quot;sg-note sg-small&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;실무 포인트&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;UNION ALL vs UNION&lt;/b&gt;: ALL은 중복 제거가 없어 빠릅니다. 중복이나 순환 가능성이 있으면 &lt;code&gt;UNION&lt;/code&gt; 또는 별도 차단 로직을 사용합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;정렬&lt;/b&gt;: 출력 순서는 엔진 구현에 좌우됩니다. 사용자 표시용 순서가 필요하면 &lt;code&gt;ORDER BY&lt;/code&gt;를 명시합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;인덱스&lt;/b&gt;: 재귀부 조인 키(&lt;code&gt;manager_id&lt;/code&gt; 등)에 인덱스가 없으면 반복 스캔 비용이 급증합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;깊이 제한&lt;/b&gt;: 오류나 순환으로 인한 증폭을 막기 위해 &lt;code&gt;lvl &amp;lt; N&lt;/code&gt; 같은 제한을 둡니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;sg-infinite&quot; class=&quot;sg-reveal sg-card&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;무한 재귀 원인과 방지&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;원인&lt;/h3&gt;
&lt;ul class=&quot;sg-small&quot; style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;종료 조건이 없어 탐색이 끝나지 않는 경우&lt;/li&gt;
&lt;li&gt;A&amp;rarr;B&amp;rarr;C&amp;rarr;A처럼 동일 노드를 재방문하는 순환 데이터&lt;/li&gt;
&lt;li&gt;동일 노드가 여러 경로에서 반복 추가되는 중복 누적&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;방지 전략&lt;/h3&gt;
&lt;ul class=&quot;sg-small&quot; style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;lvl&lt;/code&gt; 기반 깊이 제한&lt;/li&gt;
&lt;li&gt;경로 문자열 또는 배열에 방문 이력 기록 후 재방문 차단&lt;/li&gt;
&lt;li&gt;&lt;code&gt;UNION&lt;/code&gt;으로 중복 제거 또는 표준 &lt;code&gt;CYCLE&lt;/code&gt; 절 사용(지원 DBMS)&lt;/li&gt;
&lt;li&gt;Oracle &lt;code&gt;CONNECT BY NOCYCLE&lt;/code&gt;, PostgreSQL&amp;middot;Oracle &lt;code&gt;SEARCH&lt;/code&gt;/&lt;code&gt;CYCLE&lt;/code&gt; 활용&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;section id=&quot;sg-schema&quot; class=&quot;sg-reveal&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;예제 스키마와 데이터&lt;/h2&gt;
&lt;div class=&quot;sg-note sg-small&quot;&gt;직원 조직도 예시를 사용합니다. 한 직원은 0명 또는 1명의 상사를 가지며 상사가 없으면 루트입니다.&lt;/div&gt;
&lt;pre class=&quot;sql&quot;&gt;&lt;code&gt;CREATE TABLE employees (
  emp_id     INT PRIMARY KEY,
  name       VARCHAR(50),
  manager_id INT
);

INSERT INTO employees VALUES
  (1,'김하늘',NULL),
  (2,'박준호',1),
  (3,'이서연',1),
  (4,'최민수',2),
  (5,'장예린',2);

CREATE INDEX ix_employees_manager ON employees(manager_id);&lt;/code&gt;&lt;/pre&gt;
&lt;p class=&quot;sg-small&quot; data-ke-size=&quot;size16&quot;&gt;핵심 키는 &lt;code&gt;manager_id&lt;/code&gt;입니다. 이 값으로 부모에서 자식으로 탐색하므로 인덱스를 반드시 생성합니다.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;sg-pg&quot; class=&quot;sg-reveal&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;PostgreSQL 작성법&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;기본 재귀 CTE&lt;/h3&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;WITH RECURSIVE org(emp_id, name, manager_id, lvl) AS (
  SELECT emp_id, name, manager_id, 1
  FROM employees
  WHERE manager_id IS NULL
  UNION ALL
  SELECT e.emp_id, e.name, e.manager_id, o.lvl + 1
  FROM employees e
  JOIN org o ON e.manager_id = o.emp_id
)
SELECT emp_id,name,manager_id,lvl
FROM org
ORDER BY lvl, emp_id;&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;sg-small&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;설명&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;앵커는 루트 직원을 가져옵니다.&lt;/li&gt;
&lt;li&gt;재귀부는 &lt;code&gt;e.manager_id = o.emp_id&lt;/code&gt;로 부모와 자식을 연결합니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;lvl&lt;/code&gt;은 깊이 계산과 깊이 제한 조건에 활용합니다.&lt;/li&gt;
&lt;li&gt;표시 순서가 필요하면 &lt;code&gt;ORDER BY&lt;/code&gt;를 명시합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;경로 누적과 말단 판별&lt;/h3&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;WITH RECURSIVE org(emp_id, name, manager_id, path, lvl) AS (
  SELECT emp_id, name, manager_id, name::text, 1
  FROM employees WHERE manager_id IS NULL
  UNION ALL
  SELECT e.emp_id, e.name, e.manager_id,
         org.path || ' &amp;gt; ' || e.name,
         org.lvl + 1
  FROM employees e
  JOIN org ON e.manager_id = org.emp_id
)
SELECT o.*,
       NOT EXISTS (SELECT 1 FROM employees c WHERE c.manager_id = o.emp_id) AS is_leaf
FROM org o
ORDER BY lvl, emp_id;&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;sg-small&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;설명&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;path&lt;/code&gt;는 루트에서 현재까지의 경로를 문자열로 누적합니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;NOT EXISTS&lt;/code&gt;로 자식이 없는 노드를 말단으로 식별합니다.&lt;/li&gt;
&lt;li&gt;경로 문자열은 트리 렌더링과 브레드크럼 생성에 유용합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;SEARCH/CYCLE 절&lt;/h3&gt;
&lt;pre class=&quot;sql&quot;&gt;&lt;code&gt;WITH RECURSIVE org(emp_id, manager_id) AS (
  SELECT emp_id, manager_id FROM employees WHERE manager_id IS NULL
  UNION ALL
  SELECT e.emp_id, e.manager_id FROM employees e JOIN org o ON e.manager_id = o.emp_id
)
SEARCH BREADTH FIRST BY emp_id SET bfs_ord
CYCLE emp_id SET is_cycle TO TRUE DEFAULT FALSE
SELECT emp_id, manager_id, bfs_ord, is_cycle FROM org;&lt;/code&gt;&lt;/pre&gt;
&lt;p class=&quot;sg-small&quot; data-ke-size=&quot;size16&quot;&gt;탐색 순서를 자동 컬럼으로 부여하고, 순환을 표준 문법으로 탐지할 수 있습니다.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;sg-oracle&quot; class=&quot;sg-reveal&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Oracle 작성법&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;표준 재귀 CTE&lt;/h3&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;WITH org (emp_id, name, manager_id, lvl, path) AS (
  SELECT emp_id, name, manager_id, 1, CAST(name AS VARCHAR2(4000))
  FROM employees
  WHERE manager_id IS NULL
  UNION ALL
  SELECT e.emp_id, e.name, e.manager_id,
         o.lvl + 1,
         o.path || ' &amp;gt; ' || e.name
  FROM employees e
  JOIN org o ON e.manager_id = o.emp_id
)
SELECT emp_id, name, manager_id, lvl, path
FROM org
ORDER BY lvl, emp_id;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;CONNECT BY 계층 쿼리&lt;/h3&gt;
&lt;pre class=&quot;sql&quot;&gt;&lt;code&gt;SELECT
  emp_id, name, manager_id, LEVEL AS lvl,
  SYS_CONNECT_BY_PATH(name, ' &amp;gt; ') AS path,
  CONNECT_BY_ISLEAF AS is_leaf
FROM employees
START WITH manager_id IS NULL
CONNECT BY PRIOR emp_id = manager_id
ORDER SIBLINGS BY emp_id;&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;sg-small&quot;&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;LEVEL&lt;/code&gt;은 깊이를 자동 제공합니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ORDER SIBLINGS BY&lt;/code&gt;로 형제 정렬 기준을 지정합니다.&lt;/li&gt;
&lt;li&gt;순환 데이터는 &lt;code&gt;NOCYCLE&lt;/code&gt;과 &lt;code&gt;CONNECT_BY_ISCYCLE&lt;/code&gt;로 제어합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;sg-mysql&quot; class=&quot;sg-reveal&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;MySQL 8.0 작성법&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;기본 재귀 CTE&lt;/h3&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;WITH RECURSIVE org(emp_id, name, manager_id, lvl) AS (
  SELECT emp_id, name, manager_id, 1
  FROM employees
  WHERE manager_id IS NULL
  UNION ALL
  SELECT e.emp_id, e.name, e.manager_id, o.lvl + 1
  FROM employees e
  JOIN org o ON e.manager_id = o.emp_id
)
SELECT emp_id,name,manager_id,lvl
FROM org
ORDER BY lvl, emp_id;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;문자열 경로 기반 순환 차단&lt;/h3&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;WITH RECURSIVE org(emp_id, name, manager_id, path, lvl) AS (
  SELECT emp_id, name, manager_id, CONCAT('/', emp_id, '/'), 1
  FROM employees WHERE manager_id IS NULL
  UNION ALL
  SELECT e.emp_id, e.name, e.manager_id,
         CONCAT(o.path, e.emp_id, '/'),
         o.lvl + 1
  FROM employees e
  JOIN org o ON e.manager_id = o.emp_id
  WHERE INSTR(o.path, CONCAT('/', e.emp_id, '/')) = 0
)
SELECT emp_id,name,manager_id,lvl FROM org;&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;sg-small&quot;&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;표준 &lt;code&gt;CYCLE&lt;/code&gt; 절이 없으므로 경로 문자열로 재방문을 차단합니다.&lt;/li&gt;
&lt;li&gt;대규모 데이터에서는 JSON 경로와 가상 컬럼 인덱스를 고려할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;sg-patterns&quot; class=&quot;sg-reveal sg-card&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;실전 패턴 모음&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;특정 노드의 전체 하위&lt;/h3&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;WITH RECURSIVE sub(emp_id, name, manager_id, lvl) AS (
  SELECT emp_id, name, manager_id, 0 FROM employees WHERE emp_id = :target_id
  UNION ALL
  SELECT e.emp_id, e.name, e.manager_id, s.lvl + 1
  FROM employees e JOIN sub s ON e.manager_id = s.emp_id
)
SELECT emp_id,name,manager_id,lvl FROM sub;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;현재 노드에서 루트까지 상위 경로&lt;/h3&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;WITH RECURSIVE up(emp_id, name, manager_id, path, lvl) AS (
  SELECT emp_id, name, manager_id, name, 0
  FROM employees WHERE emp_id = :current_id
  UNION ALL
  SELECT e.emp_id, e.name, e.manager_id, CONCAT(e.name,' &amp;gt; ',up.path), up.lvl + 1
  FROM employees e JOIN up ON up.manager_id = e.emp_id
)
SELECT * FROM up;&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;sg-divider&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;조직도 구조 예시&lt;/h3&gt;
&lt;ul class=&quot;sg-org sg-small&quot; style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;김하늘 (1)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;박준호 (2)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;최민수 (3)&lt;/li&gt;
&lt;li&gt;장예린 (3)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;이서연 (2)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;section id=&quot;sg-end&quot; class=&quot;sg-reveal sg-card&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;마무리&lt;/h2&gt;
&lt;p class=&quot;sg-small&quot; data-ke-size=&quot;size16&quot;&gt;재귀 쿼리는 강력하지만 작성 방식과 데이터 특성에 따라 결과와 성능이 크게 달라질 수 있습니다. 이 글은 재귀 쿼리를 이해하는 과정에서 헷갈렸던 개념과 작동 흐름을 정리하기 위해 작성했습니다. 예제는 이해를 돕기 위한 최소 구성으로 제시했으며, 실제 환경에서는 스키마 구조, 데이터량, 인덱스 전략, 순환 규칙에 맞춘 세부 튜닝이 필요합니다. 글에서 부정확한 부분이나 보완해야 할 내용이 있다면 알려 주시면 감사하겠습니다. \의견을 반영하여 내용을 지속적으로 업데이트하겠습니다.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;sg-refs&quot; class=&quot;sg-reveal sg-footer&quot;&gt;
&lt;div class=&quot;sg-tiny&quot;&gt;참조 문서&lt;/div&gt;
&lt;ul class=&quot;sg-tiny&quot; style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://www.postgresql.org/docs/current/queries-with.html#QUERIES-WITH-RECURSIVE&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;PostgreSQL: Recursive Queries&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/Recursive-Subquery-Factoring.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Oracle: Recursive Subquery Factoring&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/Hierarchical-Queries.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Oracle: Hierarchical Queries (CONNECT BY)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/with.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;MySQL 8.0: Common Table Expressions&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;
&lt;script type=&quot;application/ld+json&quot;&gt;
{
  &quot;@context&quot;:&quot;https://schema.org&quot;,
  &quot;@type&quot;:&quot;TechArticle&quot;,
  &quot;headline&quot;:&quot;SQL 재귀 쿼리: 개념·무한 재귀·DBMS별 작성법 완전 정리&quot;,
  &quot;about&quot;:[&quot;SQL 재귀 쿼리&quot;,&quot;WITH RECURSIVE&quot;,&quot;CONNECT BY&quot;,&quot;계층형 데이터&quot;,&quot;PostgreSQL&quot;,&quot;Oracle&quot;,&quot;MySQL&quot;],
  &quot;inLanguage&quot;:&quot;ko&quot;,
  &quot;audience&quot;:{&quot;@type&quot;:&quot;Audience&quot;,&quot;audienceType&quot;:&quot;개발자&quot;},
  &quot;keywords&quot;:&quot;재귀 CTE, WITH RECURSIVE, CONNECT BY, 계층형 데이터, 조직도, 무한 재귀, SEARCH CYCLE&quot;,
  &quot;author&quot;:{&quot;@type&quot;:&quot;Person&quot;,&quot;name&quot;:&quot;작성자&quot;},
  &quot;publisher&quot;:{&quot;@type&quot;:&quot;Organization&quot;,&quot;name&quot;:&quot;블로그&quot;}
}
&lt;/script&gt;
&lt;script&gt;
(function(){
  var root=document.getElementById('sg-recursive'); if(!root)return;
  var els=root.querySelectorAll('.sg-reveal');
  if(!('IntersectionObserver'in window)){els.forEach(function(el){el.classList.add('sg-in')});return;}
  var io=new IntersectionObserver(function(entries){
    entries.forEach(function(e){ if(e.isIntersecting){e.target.classList.add('sg-in');io.unobserve(e.target);} });
  },{threshold:0.12});
  els.forEach(function(el){io.observe(el)});
})();
&lt;/script&gt;
&lt;/p&gt;</description>
      <category>DEVELOPMENT</category>
      <category>CONNNECTBY</category>
      <category>CTE</category>
      <category>MYSQL</category>
      <category>oraclesql</category>
      <category>PostgreSQL</category>
      <category>SQL</category>
      <category>WITHRECURSIVE</category>
      <category>계층형데이터</category>
      <category>데이터베이스</category>
      <category>재귀쿼리</category>
      <author>간지뽕빨리턴님</author>
      <guid isPermaLink="true">https://odinbox.tistory.com/556</guid>
      <comments>https://odinbox.tistory.com/556#entry556comment</comments>
      <pubDate>Sat, 25 Oct 2025 14:40:38 +0900</pubDate>
    </item>
    <item>
      <title>PostgreSQL, 논리복제 실무 가이드</title>
      <link>https://odinbox.tistory.com/555</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;
&lt;script type=&quot;application/ld+json&quot;&gt;
{
  &quot;@context&quot;: &quot;https://schema.org&quot;,
  &quot;@type&quot;: &quot;TechArticle&quot;,
  &quot;headline&quot;: &quot;PostgreSQL 15 논리 복제 실무 가이드&quot;,
  &quot;inLanguage&quot;: &quot;ko&quot;,
  &quot;about&quot;: &quot;PostgreSQL 15 logical replication&quot;,
  &quot;author&quot;: {&quot;@type&quot;:&quot;Person&quot;,&quot;name&quot;:&quot;OdinBOX&quot;},
  &quot;datePublished&quot;: &quot;2025-10-18&quot;
}
&lt;/script&gt;
&lt;/p&gt;
&lt;div&gt;
&lt;style&gt;
:root{
  --fg:#0b1220;--fg2:#2a3140;--muted:#667085;--border:#e6e9f0;--soft:#f6f8fc;
  --accent:#2f6feb;--accent2:#00b894;--accent3:#7c3aed;
  --card:#fff;--codebg:#0b1220;--codebd:#101a33
}
*{box-sizing:border-box}
html,body{margin:0;padding:0;background:#fff;color:var(--fg);font-family:-apple-system,BlinkMacSystemFont,&quot;Noto Sans KR&quot;,Roboto,&quot;Segoe UI&quot;,Helvetica,Arial,sans-serif;line-height:1.85;word-break:keep-all}
.pg15-root{max-width:1100px;margin:auto;padding:clamp(16px,2vw,32px)}
.pg15-title{font-size:clamp(28px,2.6vw,44px);font-weight:900;letter-spacing:-.02em;background:linear-gradient(90deg,var(--accent),var(--accent3),var(--accent2));-webkit-background-clip:text;background-clip:text;color:transparent;text-align:center;margin:0 0 6px;animation:titleShift 7s ease-in-out infinite}
@keyframes titleShift{0%{background-position:0% 50%}50%{background-position:100% 50%}100%{background-position:0% 50%}}
.pg15-sub{text-align:center;color:var(--muted);margin:0 0 18px}
.pg15-imgfx{border-radius:18px;border:1px solid var(--border);overflow:hidden;box-shadow:0 10px 30px rgba(13,35,67,.08);margin:18px auto;max-width:640px;transform:translateY(6px);animation:floatIn .7s cubic-bezier(.22,1,.36,1) both}
.pg15-imgfx img{display:block;width:100%;height:auto}
@keyframes floatIn{from{opacity:0;transform:translateY(16px) scale(.98)}to{opacity:1;transform:translateY(0) scale(1)}}
.pg15-wrap{display:flex;flex-direction:row-reverse;gap:28px}
@media (max-width:1020px){.pg15-wrap{flex-direction:column}}

.pg15-card{background:var(--card);border:1px solid var(--border);border-radius:16px;padding:18px;margin:18px 0;box-shadow:0 8px 24px rgba(16,24,40,.06);animation:fadeUp .55s ease both}
.pg15-card:hover{transform:translateY(-2px);box-shadow:0 16px 36px rgba(16,24,40,.10)}
@keyframes fadeUp{from{opacity:0;transform:translateY(10px)}to{opacity:1;transform:none}}

.pg15-h2{scroll-margin-top:88px;font-size:clamp(20px,1.6rem,28px);font-weight:900;letter-spacing:-.01em;margin:42px 0 14px;position:relative;padding-left:16px}
.pg15-h2:before{content:&quot;&quot;;position:absolute;left:0;top:.55em;width:8px;height:8px;border-radius:2px;background:linear-gradient(135deg,var(--accent),var(--accent2));box-shadow:0 0 0 6px rgba(47,111,235,.10)}
.pg15-h2:after{content:&quot;&quot;;position:absolute;left:16px;right:0;bottom:-6px;height:3px;border-radius:2px;background:linear-gradient(90deg,var(--accent),var(--accent3));transform:scaleX(0);transform-origin:left;animation:underline .8s .25s cubic-bezier(.22,1,.36,1) forwards}
@keyframes underline{to{transform:scaleX(1)}}

.pg15-h3{font-size:clamp(16px,1.08rem,20px);font-weight:800;color:var(--fg2);margin:22px 0 10px;padding-left:14px;position:relative}
.pg15-h3:before{content:&quot;&quot;;position:absolute;left:0;top:.55em;width:6px;height:6px;background:var(--accent2);border-radius:2px}

.pg15-code{background:var(--codebg);color:#e8eaf2;border:1px solid var(--codebd);border-radius:14px;padding:14px;overflow-x:auto;font-family:ui-monospace,Consolas,Monaco,monospace;font-size:.9rem;margin:10px 0}
.pg15-code:hover{box-shadow:0 0 0 2px rgba(124,58,237,.2) inset}

.pg15-table{width:100%;border-collapse:collapse;margin:10px 0;border-radius:12px;overflow:hidden}
.pg15-table th,.pg15-table td{padding:12px;border-bottom:1px solid #eef1f6;text-align:left}
.pg15-table thead th{background:#f6f8ff;font-weight:800}

.pg15-note{border-left:4px solid var(--accent);background:#f7faff;padding:12px 14px;border-radius:10px;margin:12px 0;animation:glow 2.2s ease-in-out infinite alternate}
@keyframes glow{from{box-shadow:0 0 0 rgba(47,111,235,0)}to{box-shadow:0 8px 22px rgba(47,111,235,.12)}}

.pg15-grid{display:grid;gap:18px;grid-template-columns:1fr 1fr}
@media(max-width:820px){.pg15-grid{grid-template-columns:1fr}}

.pg15-toc{position:sticky;top:16px;margin:18px 0}
.pg15-toc .card{background:var(--card);border:1px solid var(--border);border-radius:16px;padding:16px;box-shadow:0 10px 28px rgba(13,35,67,.06)}
.pg15-toc h2{font-size:1.02rem;margin:0 0 8px;color:#0e1a33}
.pg15-toc ul{list-style:none!important;padding:0;margin:0;display:grid;gap:10px}
.pg15-toc li{list-style:none!important}
.pg15-toc li::marker{content:&quot;&quot;}
.pg15-toc [data-ke-list-type]{list-style:none!important}
.pg15-toc a{position:relative;display:block;padding:10px 12px;border:1px solid var(--border);border-radius:12px;text-decoration:none;color:#0b4ee1;font-weight:700;overflow:hidden}
.pg15-toc a:after{content:&quot;&quot;;position:absolute;inset:0;background:linear-gradient(90deg,rgba(47,111,235,.12),rgba(124,58,237,.12));transform:translateX(-100%);transition:transform .45s cubic-bezier(.22,1,.36,1);pointer-events:none}
.pg15-toc a:hover:after{transform:translateX(0)}
.pg15-toc a:hover{border-color:#cfe0ff;box-shadow:0 6px 14px rgba(24,44,90,.08)}

footer{text-align:center;color:#5c6677;font-size:.95rem;margin-top:40px}

.reveal{opacity:0;transform:translateY(14px);animation:reveal .6s ease forwards}
.reveal:nth-of-type(2){animation-delay:.06s}
.reveal:nth-of-type(3){animation-delay:.12s}
@keyframes reveal{to{opacity:1;transform:none}}

@media (prefers-reduced-motion:reduce){
  *{animation:none!important;transition:none!important}
}
&lt;/style&gt;
&lt;/div&gt;
&lt;article class=&quot;pg15-root&quot;&gt;&lt;header&gt;
&lt;h1 class=&quot;pg15-title&quot;&gt;&amp;nbsp;&lt;/h1&gt;
&lt;p class=&quot;pg15-sub&quot; data-ke-size=&quot;size16&quot;&gt;FEMS 사례를 바탕으로 개념을 충분히 풀어 설명하고, 옵션의 의미와 설정 방법, 재동기화, 트리거, 모니터링, Tailscale 네트워크 구성까지 단계별로 정리합니다.&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;글 상단 부분 대표 이미지.png&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bKEUzx/dJMb9Nhuo5x/HzqTe63vV0Bwg0Zh2o7rnk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bKEUzx/dJMb9Nhuo5x/HzqTe63vV0Bwg0Zh2o7rnk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bKEUzx/dJMb9Nhuo5x/HzqTe63vV0Bwg0Zh2o7rnk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbKEUzx%2FdJMb9Nhuo5x%2FHzqTe63vV0Bwg0Zh2o7rnk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;400&quot; data-filename=&quot;글 상단 부분 대표 이미지.png&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;nav class=&quot;pg15-toc pg15-hide-mobile&quot; aria-label=&quot;목차&quot;&gt;&lt;/nav&gt;&lt;nav class=&quot;pg15-toc pg15-show-mobile&quot; aria-label=&quot;목차&quot;&gt;
&lt;div class=&quot;pg15-card&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;빠른 이동&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;#pg15-concept&quot;&gt;개념과 원리&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#pg15-setup&quot;&gt;구성 절차&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#pg15-reset&quot;&gt;재동기화&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#pg15-monitor&quot;&gt;모니터링&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#pg15-checklist&quot;&gt;체크리스트&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/nav&gt;&lt;/header&gt;
&lt;section class=&quot;pg15-wrap&quot;&gt;
&lt;div&gt;
&lt;section id=&quot;pg15-concept&quot; class=&quot;pg15-section pg15-anchor&quot;&gt;
&lt;h2 class=&quot;pg15-h2&quot; data-ke-size=&quot;size26&quot;&gt;1. 개념 심화와 동작 원리&lt;/h2&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;1024&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b63ZeB/dJMb9MXbbPP/YNZrKqlEM2F8rKFLaJjfHk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b63ZeB/dJMb9MXbbPP/YNZrKqlEM2F8rKFLaJjfHk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b63ZeB/dJMb9MXbbPP/YNZrKqlEM2F8rKFLaJjfHk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb63ZeB%2FdJMb9MXbbPP%2FYNZrKqlEM2F8rKFLaJjfHk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1024&quot; height=&quot;1024&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;1024&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;div class=&quot;pg15-card&quot;&gt;
&lt;h3 class=&quot;pg15-h3&quot; data-ke-size=&quot;size23&quot;&gt;1) 비유로 이해합니다&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;논리 복제는 신문 구독과 비슷합니다. 신문사가 오늘자 기사 목록을 만들어 두고, 구독자에게 순서대로 배달합니다. 구독자가 부재중이어도 배달부는 어디까지 전달했는지 기록합니다. PostgreSQL에서는 이 기록이 복제 슬롯입니다.&lt;/p&gt;
&lt;h3 class=&quot;pg15-h3&quot; data-ke-size=&quot;size23&quot;&gt;2) 내부 동작을 단계로 설명합니다&lt;/h3&gt;
&lt;ol class=&quot;pg15-steps&quot; style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li class=&quot;pg15-step&quot;&gt;게시자는 커밋 시 변경을 WAL에 기록합니다.&lt;/li&gt;
&lt;li class=&quot;pg15-step&quot;&gt;논리 디코더가 WAL을 테이블/컬럼/값 이벤트로 변환합니다.&lt;/li&gt;
&lt;li class=&quot;pg15-step&quot;&gt;복제 슬롯이 읽은 위치를 저장해 재시작 시 이어갑니다.&lt;/li&gt;
&lt;li class=&quot;pg15-step&quot;&gt;구독자 워커가 이벤트를 수신해 동일 DML을 실행합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 class=&quot;pg15-h3&quot; data-ke-size=&quot;size23&quot;&gt;3) 보장과 비보장&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;보장&lt;/b&gt;: 트랜잭션 원자성, 내부 순서, 동일 행 변경 순서.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;비보장&lt;/b&gt;: 다중 게시자 전역 순서, DDL 자동 동기화, 시퀀스 동기화.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 class=&quot;pg15-h3&quot; data-ke-size=&quot;size23&quot;&gt;4) 복제 대상&lt;/h3&gt;
&lt;div class=&quot;pg15-table&quot;&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;항목&lt;/th&gt;
&lt;th&gt;상태&lt;/th&gt;
&lt;th&gt;비고&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;DML: INSERT, UPDATE, DELETE, TRUNCATE&lt;/td&gt;
&lt;td&gt;복제됨&lt;/td&gt;
&lt;td&gt;Publication 설정 준수&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DDL: CREATE/ALTER TABLE&lt;/td&gt;
&lt;td&gt;미복제&lt;/td&gt;
&lt;td&gt;양쪽 스키마 별도 배포&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;시퀀스&lt;/td&gt;
&lt;td&gt;미복제&lt;/td&gt;
&lt;td&gt;setval() 보정 필요&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Large Object&lt;/td&gt;
&lt;td&gt;미복제&lt;/td&gt;
&lt;td&gt;별도 전략 필요&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;h3 class=&quot;pg15-h3&quot; data-ke-size=&quot;size23&quot;&gt;5) FEMS 시나리오 적합성&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로컬 DB에 안전 적재 후 연결 회복 시 중앙으로 밀어 올립니다. 슬롯이 진행 위치를 기억해 유실을 줄입니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;pg15-design&quot; class=&quot;pg15-section pg15-anchor&quot;&gt;
&lt;h2 class=&quot;pg15-h2&quot; data-ke-size=&quot;size26&quot;&gt;2. 설계 지침&lt;/h2&gt;
&lt;div class=&quot;pg15-grid&quot;&gt;
&lt;div class=&quot;pg15-card&quot;&gt;
&lt;h3 class=&quot;pg15-h3&quot; data-ke-size=&quot;size23&quot;&gt;1) 키 설계&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;가능하면 기본키 사용.&lt;/li&gt;
&lt;li&gt;불가 시 REPLICA IDENTITY FULL 고려.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;pg15-card&quot;&gt;
&lt;h3 class=&quot;pg15-h3&quot; data-ke-size=&quot;size23&quot;&gt;2) 파티션&amp;middot;인덱스&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;시간 파티셔닝으로 초기 스냅샷&amp;middot;보관 단순화.&lt;/li&gt;
&lt;li&gt;구독자 조회 인덱스 사전 구축.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;pg15-card&quot;&gt;
&lt;h3 class=&quot;pg15-h3&quot; data-ke-size=&quot;size23&quot;&gt;3) 타임스탬프&amp;middot;중복 방지&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;수집 시각과 장비 시각 분리 기록.&lt;/li&gt;
&lt;li&gt;UNIQUE 제약 또는 UPSERT 전략.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;pg15-schema&quot; class=&quot;pg15-section pg15-anchor&quot;&gt;
&lt;h2 class=&quot;pg15-h2&quot; data-ke-size=&quot;size26&quot;&gt;3. 실습 스키마&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;FEMS 전력 계측 예시로 (site_code, log_time) 복합 기본키를 사용합니다.&lt;/p&gt;
&lt;pre class=&quot;pg15-code sql&quot;&gt;&lt;code&gt;CREATE TABLE energy_data (
  site_code     TEXT        NOT NULL,
  usage_kwh     NUMERIC,
  peak_kw       NUMERIC,
  power_factor  NUMERIC,
  log_time      TIMESTAMP   NOT NULL,
  PRIMARY KEY (site_code, log_time)
);&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;pg15-note&quot;&gt;시퀀스는 복제되지 않습니다. 구독자에서 setval()로 보정합니다.&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;pg15-settings&quot; class=&quot;pg15-section pg15-anchor&quot;&gt;
&lt;h2 class=&quot;pg15-h2&quot; data-ke-size=&quot;size26&quot;&gt;4. 설정 옵션 상세&lt;/h2&gt;
&lt;div class=&quot;pg15-grid&quot;&gt;
&lt;div class=&quot;pg15-card&quot;&gt;
&lt;h3 class=&quot;pg15-h3&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span class=&quot;pg15-badge&quot;&gt;게시자&lt;/span&gt; postgresql.conf&lt;/h3&gt;
&lt;div class=&quot;pg15-table&quot;&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;파라미터&lt;/th&gt;
&lt;th&gt;설명&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;wal_level = logical&lt;/td&gt;
&lt;td&gt;논리 디코딩 활성&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;max_wal_senders&lt;/td&gt;
&lt;td&gt;동시 전송 프로세스 수&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;max_replication_slots&lt;/td&gt;
&lt;td&gt;복제 슬롯 상한&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;idle_replication_slot_timeout&lt;/td&gt;
&lt;td&gt;미사용 슬롯 정리&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;listen_addresses&lt;/td&gt;
&lt;td&gt;Tailscale 사용 시 0.0.0.0 또는 TS IP 포함&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class=&quot;pg15-note&quot;&gt;
&lt;pre class=&quot;pg15-code angelscript&quot;&gt;&lt;code&gt;host    replication    replicator    100.64.0.0/10    md5&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;pg15-card&quot;&gt;
&lt;h3 class=&quot;pg15-h3&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span class=&quot;pg15-badge&quot;&gt;구독자&lt;/span&gt; 워커 파라미터&lt;/h3&gt;
&lt;div class=&quot;pg15-table&quot;&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;파라미터&lt;/th&gt;
&lt;th&gt;설명&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;max_logical_replication_workers&lt;/td&gt;
&lt;td&gt;논리 복제 워커 상한&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;max_sync_workers_per_subscription&lt;/td&gt;
&lt;td&gt;초기 스냅샷 병렬 수&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;max_worker_processes&lt;/td&gt;
&lt;td&gt;전체 워커 상한&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;wal_receiver_timeout 등&lt;/td&gt;
&lt;td&gt;불안정 네트워크 보강&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;pg15-card&quot; style=&quot;background: linear-gradient(180deg,#fff,#f8fbff); border: 1px dashed #cfe0ff;&quot;&gt;
&lt;h3 class=&quot;pg15-h3&quot; data-ke-size=&quot;size23&quot;&gt;Subscription 옵션&lt;/h3&gt;
&lt;div class=&quot;pg15-table&quot;&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;옵션&lt;/th&gt;
&lt;th&gt;설명&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;copy_data&lt;/td&gt;
&lt;td&gt;생성 시 스냅샷 복사&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;create_slot&lt;/td&gt;
&lt;td&gt;슬롯 자동 생성&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;enabled&lt;/td&gt;
&lt;td&gt;즉시 시작 여부&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;slot_name&lt;/td&gt;
&lt;td&gt;슬롯 이름 고정&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;synchronous_commit&lt;/td&gt;
&lt;td&gt;커밋 보장 수준&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;binary&lt;/td&gt;
&lt;td&gt;이진 전송 사용&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;streaming&lt;/td&gt;
&lt;td&gt;대용량 트랜잭션 스트리밍&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;origin&lt;/td&gt;
&lt;td&gt;특정 원본만 적용&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;pg15-setup&quot; class=&quot;pg15-section pg15-anchor&quot;&gt;
&lt;h2 class=&quot;pg15-h2&quot; data-ke-size=&quot;size26&quot;&gt;5. 단계별 구성&lt;/h2&gt;
&lt;h3 class=&quot;pg15-h3&quot; data-ke-size=&quot;size23&quot;&gt;5-1 게시자 준비&lt;/h3&gt;
&lt;div class=&quot;pg15-steps&quot;&gt;
&lt;div class=&quot;pg15-step&quot;&gt;&lt;b&gt;복제 계정 생성&lt;/b&gt;
&lt;pre class=&quot;pg15-code pgsql&quot;&gt;&lt;code&gt;CREATE ROLE replicator WITH LOGIN ENCRYPTED PASSWORD '강력한_비밀번호';
GRANT SELECT ON ALL TABLES IN SCHEMA public TO replicator;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div class=&quot;pg15-step&quot;&gt;&lt;b&gt;파라미터 적용&lt;/b&gt;
&lt;pre class=&quot;pg15-code ini&quot;&gt;&lt;code&gt;wal_level = logical
max_wal_senders = 10
max_replication_slots = 10&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div class=&quot;pg15-step&quot;&gt;&lt;b&gt;접속 허용&lt;/b&gt;
&lt;pre class=&quot;pg15-code angelscript&quot;&gt;&lt;code&gt;host replication replicator 100.64.0.0/10 md5&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 class=&quot;pg15-h3&quot; data-ke-size=&quot;size23&quot;&gt;5-2 Publication 생성&lt;/h3&gt;
&lt;pre class=&quot;pg15-code pgsql&quot;&gt;&lt;code&gt;CREATE PUBLICATION fems_pub
  FOR TABLE energy_data
  WITH (publish = 'insert, update, delete, truncate');&lt;/code&gt;&lt;/pre&gt;
&lt;h3 class=&quot;pg15-h3&quot; data-ke-size=&quot;size23&quot;&gt;5-3 구독자 스키마 준비&lt;/h3&gt;
&lt;pre class=&quot;pg15-code sql&quot;&gt;&lt;code&gt;CREATE TABLE energy_data (
  site_code TEXT NOT NULL,
  usage_kwh NUMERIC,
  peak_kw NUMERIC,
  power_factor NUMERIC,
  log_time TIMESTAMP NOT NULL,
  PRIMARY KEY (site_code, log_time)
);&lt;/code&gt;&lt;/pre&gt;
&lt;h3 class=&quot;pg15-h3&quot; data-ke-size=&quot;size23&quot;&gt;5-4 Subscription 생성&lt;/h3&gt;
&lt;pre class=&quot;pg15-code pgsql&quot;&gt;&lt;code&gt;CREATE SUBSCRIPTION fems_sub
  CONNECTION 'host=100.64.0.10 port=5432 dbname=fems user=replicator password=강력한_비밀번호'
  PUBLICATION fems_pub
  WITH (create_slot = true, enabled = true, copy_data = true);&lt;/code&gt;&lt;/pre&gt;
&lt;h3 class=&quot;pg15-h3&quot; data-ke-size=&quot;size23&quot;&gt;5-5 동작 테스트&lt;/h3&gt;
&lt;pre class=&quot;pg15-code sql&quot;&gt;&lt;code&gt;INSERT INTO energy_data(site_code, usage_kwh, peak_kw, power_factor, log_time)
VALUES ('SITE-A', 125.4, 150.0, 0.95, NOW());
SELECT * FROM energy_data ORDER BY log_time DESC;&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;pg15-note&quot;&gt;구독자는 행을 찾지 못하는 UPDATE/DELETE를 건너뜁니다.&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;pg15-filters&quot; class=&quot;pg15-section pg15-anchor&quot;&gt;
&lt;h2 class=&quot;pg15-h2&quot; data-ke-size=&quot;size26&quot;&gt;6. 행과 컬럼 필터&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PostgreSQL 15는 컬럼 목록과 행 조건을 동시에 지정하여 부분 복제를 구성합니다.&lt;/p&gt;
&lt;pre class=&quot;pg15-code pgsql&quot;&gt;&lt;code&gt;CREATE PUBLICATION fems_pub_site_a
  FOR TABLE energy_data (site_code, usage_kwh, peak_kw, power_factor, log_time)
  WHERE (site_code = 'SITE-A');&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;pg15-note&quot;&gt;Publication 변경 후 구독자에서 ALTER SUBSCRIPTION ... REFRESH PUBLICATION을 실행합니다.&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;pg15-initial&quot; class=&quot;pg15-section pg15-anchor&quot;&gt;
&lt;h2 class=&quot;pg15-h2&quot; data-ke-size=&quot;size26&quot;&gt;7. 초기 로딩 전략&lt;/h2&gt;
&lt;div class=&quot;pg15-grid&quot;&gt;
&lt;div class=&quot;pg15-card&quot;&gt;
&lt;h3 class=&quot;pg15-h3&quot; data-ke-size=&quot;size23&quot;&gt;전부 스냅샷&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터 양이 적을 때 적합합니다.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;pg15-card&quot;&gt;
&lt;h3 class=&quot;pg15-h3&quot; data-ke-size=&quot;size23&quot;&gt;덤프 후 copy_data=false&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대량 데이터에 적합합니다.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;pg15-card&quot;&gt;
&lt;h3 class=&quot;pg15-h3&quot; data-ke-size=&quot;size23&quot;&gt;하이브리드&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;덤프로 구독자를 채움&lt;/li&gt;
&lt;li&gt;enabled=false로 생성&lt;/li&gt;
&lt;li&gt;점검 후 ENABLE&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;pg15-reset&quot; class=&quot;pg15-section pg15-anchor&quot;&gt;
&lt;h2 class=&quot;pg15-h2&quot; data-ke-size=&quot;size26&quot;&gt;8. 재동기화와 초기화&lt;/h2&gt;
&lt;div class=&quot;pg15-card&quot;&gt;
&lt;h3 class=&quot;pg15-h3&quot; data-ke-size=&quot;size23&quot;&gt;절차&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;ALTER SUBSCRIPTION fems_sub DISABLE;&lt;/li&gt;
&lt;li&gt;충돌 데이터 정리&lt;/li&gt;
&lt;li&gt;DROP SUBSCRIPTION fems_sub WITH (drop_slot);&lt;/li&gt;
&lt;li&gt;옵션 선택해 재생성&lt;/li&gt;
&lt;li&gt;필요 시 REFRESH PUBLICATION&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&quot;pg15-card&quot;&gt;
&lt;h3 class=&quot;pg15-h3&quot; data-ke-size=&quot;size23&quot;&gt;충돌 유형&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;duplicate key: 충돌 행 정리 후 재시도&lt;/li&gt;
&lt;li&gt;외래 키 실패: 초기 적재 순서 조정 또는 임시 제약 비활성화&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;pg15-triggers&quot; class=&quot;pg15-section pg15-anchor&quot;&gt;
&lt;h2 class=&quot;pg15-h2&quot; data-ke-size=&quot;size26&quot;&gt;9. 트리거 설계&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구독자 적용 워커는 session_replication_role='replica'로 동작합니다. 복제 유입 데이터에 대해 트리거를 실행하려면 ENABLE REPLICA 또는 ENABLE ALWAYS를 사용합니다.&lt;/p&gt;
&lt;pre class=&quot;pg15-code pgsql&quot;&gt;&lt;code&gt;ALTER TABLE energy_data ENABLE REPLICA TRIGGER trg_energy_audit;
ALTER TABLE energy_data ENABLE ALWAYS TRIGGER trg_energy_audit;&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;pg15-note&quot;&gt;복제된 쓰기가 다시 다른 노드로 복제되는 구조는 루프를 유발합니다. 경로를 단방향으로 유지합니다.&lt;/div&gt;
&lt;div class=&quot;pg15-card&quot;&gt;
&lt;pre class=&quot;pg15-code pgsql&quot;&gt;&lt;code&gt;CREATE TABLE energy_audit (
  at_time TIMESTAMP DEFAULT now(),
  op      TEXT,
  site_code TEXT,
  log_time  TIMESTAMP,
  who       TEXT
);
CREATE OR REPLACE FUNCTION fn_energy_audit() RETURNS trigger AS $$
BEGIN
  INSERT INTO energy_audit(op, site_code, log_time, who)
  VALUES (TG_OP, NEW.site_code, NEW.log_time, current_user);
  RETURN NEW;
END; $$ LANGUAGE plpgsql;
CREATE TRIGGER trg_energy_audit
AFTER INSERT OR UPDATE OR DELETE ON energy_data
FOR EACH ROW EXECUTE FUNCTION fn_energy_audit();&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;pg15-perf&quot; class=&quot;pg15-section pg15-anchor&quot;&gt;
&lt;h2 class=&quot;pg15-h2&quot; data-ke-size=&quot;size26&quot;&gt;10. 성능과 용량 계획&lt;/h2&gt;
&lt;div class=&quot;pg15-grid&quot;&gt;
&lt;div class=&quot;pg15-card&quot;&gt;
&lt;h3 class=&quot;pg15-h3&quot; data-ke-size=&quot;size23&quot;&gt;슬롯&amp;middot;WAL&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;비활성 슬롯은 WAL 누적 원인&lt;/li&gt;
&lt;li&gt;장기 중단 시 구독&amp;middot;슬롯 제거 후 재구독&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;pg15-card&quot;&gt;
&lt;h3 class=&quot;pg15-h3&quot; data-ke-size=&quot;size23&quot;&gt;적용 성능&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;구독자 인덱스 사전 구축&lt;/li&gt;
&lt;li&gt;초기 스냅샷 병렬화&lt;/li&gt;
&lt;li&gt;파티셔닝 활용&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;pg15-card&quot;&gt;
&lt;h3 class=&quot;pg15-h3&quot; data-ke-size=&quot;size23&quot;&gt;지연 해석&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;네트워크 지연+적용 시간의 합&lt;/li&gt;
&lt;li&gt;인덱스 부재&amp;middot;제약 충돌&amp;middot;무거운 트리거 점검&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;pg15-monitor&quot; class=&quot;pg15-section pg15-anchor&quot;&gt;
&lt;h2 class=&quot;pg15-h2&quot; data-ke-size=&quot;size26&quot;&gt;11. 모니터링과 장애 대응&lt;/h2&gt;
&lt;div class=&quot;pg15-grid&quot;&gt;
&lt;div class=&quot;pg15-card&quot;&gt;
&lt;h3 class=&quot;pg15-h3&quot; data-ke-size=&quot;size23&quot;&gt;필수 지표&lt;/h3&gt;
&lt;pre class=&quot;pg15-code pgsql&quot;&gt;&lt;code&gt;SELECT subname, status, latest_end_time, last_error FROM pg_stat_subscription;
SELECT slot_name, active, restart_lsn FROM pg_replication_slots;
SELECT application_name, state, sent_lsn, write_lsn, flush_lsn, replay_lsn FROM pg_stat_replication;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div class=&quot;pg15-card&quot;&gt;
&lt;h3 class=&quot;pg15-h3&quot; data-ke-size=&quot;size23&quot;&gt;경보 기준&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;슬롯 비활성 10분 이상&lt;/li&gt;
&lt;li&gt;status 비정상 또는 last_error 존재&lt;/li&gt;
&lt;li&gt;WAL 디스크 사용량 80% 이상&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;pg15-tailscale&quot; class=&quot;pg15-section pg15-anchor&quot;&gt;
&lt;h2 class=&quot;pg15-h2&quot; data-ke-size=&quot;size26&quot;&gt;12. Tailscale 네트워킹&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Tailscale을 사용하면 100 대역 사설 IP로 안전하게 통신합니다.&lt;/p&gt;
&lt;pre class=&quot;pg15-code pgsql&quot;&gt;&lt;code&gt;host    replication    replicator    100.64.0.0/10    md5
CREATE SUBSCRIPTION fems_sub
  CONNECTION 'host=100.64.0.10 port=5432 dbname=fems user=replicator password=***'
  PUBLICATION fems_pub;&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;pg15-note&quot;&gt;ACL과 비밀번호 정책, OS 방화벽을 함께 운영합니다.&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;pg15-security&quot; class=&quot;pg15-section pg15-anchor&quot;&gt;
&lt;h2 class=&quot;pg15-h2&quot; data-ke-size=&quot;size26&quot;&gt;13. 보안 베스트프랙티스&lt;/h2&gt;
&lt;ul class=&quot;pg15-card&quot; style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;복제 전용 사용자 최소 권한&lt;/li&gt;
&lt;li&gt;TLS 적용&lt;/li&gt;
&lt;li&gt;비밀은 환경 변수&amp;middot;비밀 저장소 사용&lt;/li&gt;
&lt;li&gt;로그에 비밀번호 노출 금지&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;section id=&quot;pg15-proscons&quot; class=&quot;pg15-section pg15-anchor&quot;&gt;
&lt;h2 class=&quot;pg15-h2&quot; data-ke-size=&quot;size26&quot;&gt;14. 장단점과 해결책&lt;/h2&gt;
&lt;div class=&quot;pg15-grid&quot; style=&quot;grid-template-columns: 1fr 1fr;&quot;&gt;
&lt;div class=&quot;pg15-card&quot;&gt;
&lt;h3 class=&quot;pg15-h3&quot; data-ke-size=&quot;size23&quot;&gt;장점&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;선택적 복제&lt;/li&gt;
&lt;li&gt;이기종 버전&amp;middot;플랫폼&lt;/li&gt;
&lt;li&gt;다중 게시자 집계&lt;/li&gt;
&lt;li&gt;CDC 파이프라인 입력 적합&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;pg15-card&quot;&gt;
&lt;h3 class=&quot;pg15-h3&quot; data-ke-size=&quot;size23&quot;&gt;단점&amp;middot;대응&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;DDL 미복제 &amp;rarr; 마이그레이션 후 REFRESH&lt;/li&gt;
&lt;li&gt;시퀀스 불일치 &amp;rarr; setval() 보정&lt;/li&gt;
&lt;li&gt;슬롯로 WAL 누적 &amp;rarr; 모니터링&amp;middot;타임아웃&lt;/li&gt;
&lt;li&gt;PK 부재 &amp;rarr; PK 설계 또는 REPLICA IDENTITY FULL&lt;/li&gt;
&lt;li&gt;다중 쓰기 충돌 &amp;rarr; 단일 쓰기 원칙&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;pg15-checklist&quot; class=&quot;pg15-section pg15-anchor&quot;&gt;
&lt;h2 class=&quot;pg15-h2&quot; data-ke-size=&quot;size26&quot;&gt;15. 배포 체크리스트&lt;/h2&gt;
&lt;ul class=&quot;pg15-card&quot; style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span class=&quot;pg15-badge&quot;&gt;스키마&lt;/span&gt; 게시자&amp;middot;구독자 DDL 일치&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;pg15-badge&quot;&gt;계정&lt;/span&gt; 최소 권한&amp;middot;정책&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;pg15-badge&quot;&gt;네트워크&lt;/span&gt; Tailscale/방화벽/pg_hba&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;pg15-badge&quot;&gt;파라미터&lt;/span&gt; senders&amp;middot;slots&amp;middot;workers 확보&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;pg15-badge&quot;&gt;초기화&lt;/span&gt; 데이터 양에 맞는 전략&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;pg15-badge&quot;&gt;모니터링&lt;/span&gt; 상태&amp;middot;슬롯&amp;middot;WAL 알림&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;pg15-badge&quot;&gt;복구&lt;/span&gt; DROP&amp;middot;재구독 절차 문서화&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;section id=&quot;pg15-conclusion&quot; class=&quot;pg15-section pg15-anchor&quot;&gt;
&lt;h2 class=&quot;pg15-h2&quot; data-ke-size=&quot;size26&quot;&gt;16. 마무리&lt;/h2&gt;
&lt;div class=&quot;pg15-card&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;논리 복제는 동기화 기능을 넘어 데이터 흐름 설계입니다. 개념과 옵션, 초기 로딩&amp;middot;재동기화, 트리거&amp;middot;모니터링, 네트워크 구성까지 운영에 필요한 내용을 담았습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현장 문제와 해결 과정을 기록하면 다음 선택이 더 빠르고 안전해집니다. 더 좋은 방법이 있다면 계속 보완하겠습니다.&lt;/p&gt;
&lt;div class=&quot;pg15-note&quot;&gt;설정과 DDL, 스크립트를 버전 관리하고 지연&amp;middot;슬롯 상태 알림을 자동화하세요.&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;footer style=&quot;margin-top: 38px; text-align: center; color: #5c6677; font-size: .95rem;&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;PostgreSQL 논리 복제 실무 가이드&lt;/b&gt; &amp;middot; PostgreSQL 15 기준&lt;/p&gt;
&lt;/footer&gt;&lt;/article&gt;</description>
      <category>DEVELOPMENT</category>
      <category>FEMS</category>
      <category>LogicalReplication</category>
      <category>PostgreSQL</category>
      <category>PostgreSQL실무</category>
      <category>Replication설정</category>
      <category>Tailscale</category>
      <category>공장데이터</category>
      <category>논리복제</category>
      <category>데이터동기화</category>
      <category>실시간게더링</category>
      <author>간지뽕빨리턴님</author>
      <guid isPermaLink="true">https://odinbox.tistory.com/555</guid>
      <comments>https://odinbox.tistory.com/555#entry555comment</comments>
      <pubDate>Sat, 18 Oct 2025 20:32:24 +0900</pubDate>
    </item>
    <item>
      <title>CSS보다 어려운 건 한가위 인사 - 스킨 2.0 완성기</title>
      <link>https://odinbox.tistory.com/554</link>
      <description>&lt;div&gt;
&lt;style&gt;
.tp{--ink:#0f1331;--ink2:#4b5570;--bg:#fcfdff;--card:#fff;--bd:#e7ecff;--g1:#66e3ff;--g2:#a68cff;--acc:#35f0b8;--r:18px;--sh:0 14px 40px rgba(96,120,255,.18);color:var(--ink);background:var(--bg);line-height:1.8;font-size:16px;position:relative;isolation:isolate;z-index:2;margin-bottom:48px;contain:paint}
@media (prefers-color-scheme:dark){.tp{--ink:#eaf0ff;--ink2:#cfd7f0;--bg:#0b0f17;--card:rgba(255,255,255,.06);--bd:rgba(255,255,255,.14);--sh:0 18px 46px rgba(0,0,0,.55)}}
.tp *{box-sizing:border-box}
.tp a{color:#5b72ff;text-decoration:none}
.tp a:hover{opacity:.9}
.tp img{max-width:100%;height:auto;border-radius:14px}
.tp code,.tp pre{font-family:ui-monospace,SFMono-Regular,Consolas,monospace}
.tp .hero{border-radius:24px;margin:0 0 12px;padding:clamp(20px,3vw,36px);background:radial-gradient(900px 520px at -10% -10%,rgba(124,148,255,.26),transparent 60%),radial-gradient(900px 520px at 110% -10%,rgba(166,140,255,.24),transparent 60%),linear-gradient(180deg,#f3f7ff,#ffffff);box-shadow:var(--sh)}
.tp .hero h1{margin:0 0 6px;font-size:clamp(28px,4.6vw,40px);letter-spacing:-.02em}
.tp .subtitle{color:var(--ink2);margin:2px 0 12px}
.tp .meta{display:flex;flex-wrap:wrap;gap:8px;font-size:13px;color:var(--ink2)}
.tp .chip{padding:7px 12px;border:1px solid var(--bd);border-radius:999px;background:#fff}
.tp .toc-top{position:sticky;top:0;z-index:5;background:color-mix(in oklab,var(--bg),#fff 70%);border:1px solid var(--bd);border-radius:16px;margin:12px 0;padding:10px;backdrop-filter:saturate(140%) blur(8px);box-shadow:var(--sh)}
.tp .toc-wrap{display:flex;gap:8px;align-items:center;overflow:auto;scrollbar-width:none;white-space:nowrap}
.tp .toc-wrap::-webkit-scrollbar{display:none}
.tp .toc-link{display:inline-flex;align-items:center;padding:8px 12px;border-radius:12px;border:1px solid var(--bd);background:#fff;color:var(--ink2)}
.tp .toc-link:hover{background:#f2f6ff}
.tp .toc-link.active{background:linear-gradient(90deg,var(--g1),var(--g2));color:#fff;border-color:transparent}
.tp .infobar{display:flex;align-items:center;gap:10px;border:1px solid var(--bd);border-radius:14px;padding:10px 12px;background:#fff;box-shadow:var(--sh);overflow:auto;scrollbar-width:none;white-space:nowrap}
.tp .infobar::-webkit-scrollbar{display:none}
.tp .i-item{display:inline-flex;align-items:center;gap:8px;padding:8px 12px;border:1px solid var(--bd);border-radius:999px;background:#fff;color:var(--ink2)}
.tp .tag{display:inline-flex;align-items:center;gap:6px;padding:7px 10px;border:1px dashed var(--bd);border-radius:999px;background:#fff}
.tp .tag:before{content:&quot;#&quot;;opacity:.7}
.tp .content{display:grid;gap:18px}
.tp .card{background:var(--card);border:1px solid var(--bd);border-radius:var(--r);padding:clamp(16px,2.2vw,22px);box-shadow:var(--sh)}
.tp h2{font-size:clamp(20px,3.2vw,26px);margin:22px 0 10px;scroll-margin-top:88px}
.tp h3{font-size:clamp(18px,2.6vw,22px);margin:18px 0 6px;scroll-margin-top:88px}
.tp p{margin:.2em 0 1em}
.tp .lead{font-size:1.06rem;color:var(--ink2)}
.tp .callout{border-left:4px solid #5b72ff;background:#f4f7ff;padding:14px 16px;border-radius:12px;margin:6px 0}
.tp pre{background:#0a1222;color:#e2e8f0;padding:14px 16px;border-radius:12px;overflow:auto}
.tp table{width:100%;border-collapse:collapse;font-size:.94rem;display:block;overflow:auto}
.tp th,.tp td{border:1px solid var(--bd);padding:10px 12px}
.tp th{text-align:left;background:#f5f7ff}
.tp .grid{display:grid;gap:12px}
.tp .grid.cols-3{grid-template-columns:repeat(3,1fr)}
@media(max-width:780px){.tp .grid.cols-3{grid-template-columns:1fr}}
.tp .yt{position:relative;width:100%;padding-top:56.25%;border-radius:16px;overflow:hidden}
.tp .yt iframe{position:absolute;inset:0;width:100%;height:100%;border:0}
@keyframes up{from{opacity:0;transform:translateY(10px)}to{opacity:1;transform:none}}
.tp [data-reveal]{opacity:0;transform:translateY(10px)}
.tp [data-reveal].on{animation:up .55s ease-out forwards}
.tp .card:last-of-type{margin-bottom:12px}
.tp::after{content:&quot;&quot;;display:block;height:160px}
.tp + *{margin-top:24px !important;clear:both}
.tp ~ .container_postbtn,.tp ~ .another_category,.tp ~ .post_ccl,.tp ~ .postbtn_wrap,.tp ~ .entry-ccl,.tp ~ .tt_more_related,.tp ~ .tags,.tp ~ .post-share,.tp ~ .main_promo,.tp ~ [class*=&quot;donat&quot;],.tp ~ [class*=&quot;sponsor&quot;],.tp ~ [class*=&quot;coffee&quot;]{margin-top:32px !important;clear:both;position:relative;z-index:1}
&lt;/style&gt;
&lt;/div&gt;
&lt;article class=&quot;tp&quot;&gt;
&lt;section class=&quot;hero&quot; data-reveal=&quot;&quot;&gt;
&lt;h1&gt;티스토리 스킨 전면 개편 + 2025 추석 인사&lt;/h1&gt;
&lt;p class=&quot;subtitle&quot; data-ke-size=&quot;size16&quot;&gt;검색 모달&amp;middot;포털형 메인 화면&amp;middot;카테고리&amp;middot;댓글 디자인까지, 블로그 2.0 업데이트 보고서&lt;/p&gt;
&lt;div class=&quot;meta&quot;&gt;&lt;span class=&quot;chip&quot;&gt;작성자: &lt;span&gt;최영환&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;chip&quot;&gt;작성일: &lt;time datetime=&quot;2025-10-08&quot;&gt;2025-10-08&lt;/time&gt;&lt;/span&gt; &lt;span class=&quot;chip&quot;&gt;카테고리: 스킨개편 &amp;middot; 공지&lt;/span&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;!-- 대표 썸네일(히어로 아래) --&gt;
&lt;section class=&quot;card&quot; data-reveal=&quot;&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/JAwoM/btsQ4Wk0IWg/jwd55JM35ckFPy9FiOtlrK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/JAwoM/btsQ4Wk0IWg/jwd55JM35ckFPy9FiOtlrK/img.png&quot; data-alt=&quot;글 상단 부분 대표 이미지&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/JAwoM/btsQ4Wk0IWg/jwd55JM35ckFPy9FiOtlrK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJAwoM%2FbtsQ4Wk0IWg%2Fjwd55JM35ckFPy9FiOtlrK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;400&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;글 상단 부분 대표 이미지&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/section&gt;
&lt;div id=&quot;tpTOC&quot; class=&quot;toc-top&quot;&gt;
&lt;div id=&quot;tpTOCWrap&quot; class=&quot;toc-wrap&quot;&gt;&lt;a class=&quot;toc-link&quot; href=&quot;#intro&quot;&gt;서론&lt;/a&gt; &lt;a class=&quot;toc-link&quot; href=&quot;#search&quot;&gt;검색창 리뉴얼&lt;/a&gt; &lt;a class=&quot;toc-link&quot; href=&quot;#home&quot;&gt;메인 화면 개편&lt;/a&gt; &lt;a class=&quot;toc-link&quot; href=&quot;#category&quot;&gt;카테고리 글 목록&lt;/a&gt; &lt;a class=&quot;toc-link&quot; href=&quot;#comments&quot;&gt;댓글 디자인&lt;/a&gt; &lt;a class=&quot;toc-link&quot; href=&quot;#benefit&quot;&gt;개선 효과&lt;/a&gt; &lt;a class=&quot;toc-link&quot; href=&quot;#outro&quot;&gt;마무리&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;infobar&quot; aria-label=&quot;글 정보 및 태그&quot;&gt;&lt;span class=&quot;i-item&quot;&gt;읽는 시간: 약 3~4분&lt;/span&gt; &lt;span class=&quot;i-item&quot;&gt;업데이트: &lt;time datetime=&quot;2025-10-08&quot;&gt;2025-10-08&lt;/time&gt;&lt;/span&gt; &lt;span class=&quot;tag&quot;&gt;티스토리스킨&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;블로그검색창&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;카테고리글목록&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;포털형메인화면&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;UX개선&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;스킨개편&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;개발자블로그&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;댓글디자인&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;2025추석&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;추석인사&lt;/span&gt;&lt;/div&gt;
&lt;main class=&quot;content&quot;&gt;
&lt;section class=&quot;card&quot; data-reveal=&quot;&quot;&gt;
&lt;h2 id=&quot;intro&quot; data-ke-size=&quot;size26&quot;&gt;서론&lt;/h2&gt;
&lt;p class=&quot;lead&quot; data-ke-size=&quot;size16&quot;&gt;추석 연휴에 블로그의 집안 단장을 마쳤습니다. 개발자 모드로 요약하면 UI/UX 리팩터링, 탐색 플로우 개선, 첫 인상 최적화. 이번 글에서는 티스토리 스킨 개편 핵심 포인트를 빠르게 소개합니다.&lt;/p&gt;
&lt;div class=&quot;callout&quot;&gt;목표: 검색 가시성 강화 &amp;middot; 첫 화면 탐색성 향상 &amp;middot; 카테고리&amp;middot;댓글 가독성 업그레이드&lt;/div&gt;
&lt;/section&gt;
&lt;section class=&quot;card&quot; data-reveal=&quot;&quot;&gt;
&lt;h2 id=&quot;search&quot; data-ke-size=&quot;size26&quot;&gt;검색창 리뉴얼: 상단 우측 버튼 &amp;rarr; 모달&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상단 우측의 검색 버튼을 누르면 중앙에 모달이 열립니다. 모달 내부에는 검색 입력창과 함께 최근 글 목록을 배치해 검색과 최신글 확인을 한 번에 처리합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;클릭 수 최소화로 탐색 동선 단축&lt;/li&gt;
&lt;li&gt;ESC/모달 외 클릭으로 즉시 닫기, 모바일 대응&lt;/li&gt;
&lt;li&gt;라이트&amp;middot;다크 대응, 포커스 유지로 접근성 강화&lt;/li&gt;
&lt;/ul&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1035&quot; data-origin-height=&quot;917&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bamgLR/btsQ3iJv72D/LjnLYgPj3zqkUShTHq7Ggk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bamgLR/btsQ3iJv72D/LjnLYgPj3zqkUShTHq7Ggk/img.png&quot; data-alt=&quot;검색&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bamgLR/btsQ3iJv72D/LjnLYgPj3zqkUShTHq7Ggk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbamgLR%2FbtsQ3iJv72D%2FLjnLYgPj3zqkUShTHq7Ggk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1035&quot; height=&quot;917&quot; data-origin-width=&quot;1035&quot; data-origin-height=&quot;917&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;검색&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/section&gt;
&lt;section class=&quot;card&quot; data-reveal=&quot;&quot;&gt;
&lt;h2 id=&quot;home&quot; data-ke-size=&quot;size26&quot;&gt;메인 화면 개편: 포털형 카드 UI&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;첫 페이지를 카드형 포털 레이아웃으로 재배치했습니다. 썸네일&amp;middot;제목&amp;middot;요약이 보이는 카드들이 섹션별로 구성되어 첫 3초의 인상을 확 끌어올립니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;섹션별 최신&amp;middot;인기&amp;middot;테마 바로 접근&lt;/li&gt;
&lt;li&gt;반응형 그리드로 시선 흐름 안정화&lt;/li&gt;
&lt;li&gt;가벼운 인터랙션으로 체류 시간 개선 기대&lt;/li&gt;
&lt;/ul&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1377&quot; data-origin-height=&quot;1035&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tvNiy/btsQ31G9RkG/8Sz7FinDKeDjTVwCNkx0SK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tvNiy/btsQ31G9RkG/8Sz7FinDKeDjTVwCNkx0SK/img.png&quot; data-alt=&quot;홈화면&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tvNiy/btsQ31G9RkG/8Sz7FinDKeDjTVwCNkx0SK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtvNiy%2FbtsQ31G9RkG%2F8Sz7FinDKeDjTVwCNkx0SK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;580&quot; height=&quot;436&quot; data-origin-width=&quot;1377&quot; data-origin-height=&quot;1035&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;홈화면&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/section&gt;
&lt;section class=&quot;card&quot; data-reveal=&quot;&quot;&gt;
&lt;h2 id=&quot;category&quot; data-ke-size=&quot;size26&quot;&gt;카테고리 글 목록: 썸네일 + 제목 + 간략내용&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제목 나열형에서 벗어나 썸네일, 제목, 한 줄 미리보기로 구성했습니다. 어떤 글을 읽을지 판단이 빨라지고 목록의 시각적 일관성도 좋아졌습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;썸네일 비율 통일로 깔끔한 리스트&lt;/li&gt;
&lt;li&gt;요약문으로 난이도&amp;middot;의도 파악 용이&lt;/li&gt;
&lt;li&gt;뉴스피드처럼 자연스러운 스캐닝 경험&lt;/li&gt;
&lt;/ul&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;761&quot; data-origin-height=&quot;664&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bdprA4/btsQ2jouifo/o2m26FOk6dkYqsEy7w2uDK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bdprA4/btsQ2jouifo/o2m26FOk6dkYqsEy7w2uDK/img.png&quot; data-alt=&quot;카테고리&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bdprA4/btsQ2jouifo/o2m26FOk6dkYqsEy7w2uDK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbdprA4%2FbtsQ2jouifo%2Fo2m26FOk6dkYqsEy7w2uDK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;626&quot; height=&quot;546&quot; data-origin-width=&quot;761&quot; data-origin-height=&quot;664&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;카테고리&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/section&gt;
&lt;section class=&quot;card&quot; data-reveal=&quot;&quot;&gt;
&lt;h2 id=&quot;comments&quot; data-ke-size=&quot;size26&quot;&gt;댓글 디자인: 읽기 쉬운 스레드형으로 리프레시&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;댓글 영역도 새로 손봤습니다. 가독성 중심의 스레드형에 아바타, 작성자명 대비, 시간&amp;middot;버튼 배치를 재정렬했습니다. 답글은 들여쓰기로 레벨을 구분하고, 모바일에서는 버튼을 아이콘으로 축소해 조작을 단순화했습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;가독성 높은 행간과 대비, 아바타로 작성자 식별 쉬움&lt;/li&gt;
&lt;li&gt;답글과 원댓글의 계층 관계가 한눈에 구분&lt;/li&gt;
&lt;li&gt;모바일 최적화로 스크롤&amp;middot;입력 스트레스 감소&lt;/li&gt;
&lt;/ul&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;777&quot; data-origin-height=&quot;195&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dn8Z3i/btsQ4mdfSF9/xifJWYTcKgE0sY3ckudIn1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dn8Z3i/btsQ4mdfSF9/xifJWYTcKgE0sY3ckudIn1/img.png&quot; data-alt=&quot;댓글디자인&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dn8Z3i/btsQ4mdfSF9/xifJWYTcKgE0sY3ckudIn1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdn8Z3i%2FbtsQ4mdfSF9%2FxifJWYTcKgE0sY3ckudIn1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;777&quot; height=&quot;195&quot; data-origin-width=&quot;777&quot; data-origin-height=&quot;195&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;댓글디자인&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/section&gt;
&lt;section class=&quot;card&quot; data-reveal=&quot;&quot;&gt;
&lt;h2 id=&quot;benefit&quot; data-ke-size=&quot;size26&quot;&gt;개선 효과 요약&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;검색성&lt;/b&gt;: 모달 검색으로 접근성&amp;uarr;, 최신글 노출 동시 강화&lt;/li&gt;
&lt;li&gt;&lt;b&gt;발견성&lt;/b&gt;: 포털형 메인으로 다양한 글을 한눈에 탐색&lt;/li&gt;
&lt;li&gt;&lt;b&gt;가독성&lt;/b&gt;: 카테고리&amp;middot;댓글 UI 개선으로 체류&amp;middot;참여도 향상 기대&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;section class=&quot;card&quot; data-reveal=&quot;&quot;&gt;
&lt;h2 id=&quot;outro&quot; data-ke-size=&quot;size26&quot;&gt;마무리 &amp;middot; 2025 추석 인사&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;풍성한 한가위 보내셨나요? 여러분의 행복이 &lt;code&gt;while(true)&lt;/code&gt;처럼 이어지고, 일상의 버그들은 한 번에 &lt;code&gt;fix()&lt;/code&gt; 되길 바랍니다. 새 스킨과 함께 이 블로그는 기술 포스팅, 일상 기록, 커뮤니티 소통을 꾸준히 이어가겠습니다. 방문해 주셔서 감사합니다. 보름달처럼 꽉 찬 한 해 되세요!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;피드백은 언제든 환영입니다. 작은 의견이 다음 릴리즈의 핵심 기능이 될 수 있어요.&lt;/p&gt;
&lt;/section&gt;
&lt;/main&gt;&lt;/article&gt;
&lt;script&gt;
(function(){
  var root=document.currentScript.previousElementSibling;
  if(!(root&amp;&amp;root.classList&amp;&amp;root.classList.contains('tp'))){root=document.querySelector('.tp');}
  if(!root) return;
  var rev=root.querySelectorAll('[data-reveal]');
  var io2=new IntersectionObserver(function(es){es.forEach(function(e){if(e.isIntersecting){e.target.classList.add('on');io2.unobserve(e.target);}})},{threshold:.12});
  rev.forEach(function(el){io2.observe(el)});
  var links=[].slice.call(root.querySelectorAll('#tpTOC .toc-link'));
  var map={}; links.forEach(function(a){var id=(a.getAttribute('href')||'').replace('#',''); if(id) map[id]=a;});
  var heads=[].slice.call(root.querySelectorAll('h2,h3')).filter(function(h){return h.id&amp;&amp;map[h.id];});
  var io=new IntersectionObserver(function(ents){
    ents.forEach(function(ent){
      if(ent.isIntersecting){
        links.forEach(function(l){l.classList.remove('active')});
        var cur=map[ent.target.id]; if(cur) cur.classList.add('active');
      }
    });
  },{rootMargin:'-55% 0px -40% 0px',threshold:0.01});
  heads.forEach(function(h){io.observe(h)});
  document.addEventListener('click',function(e){
    var a=e.target.closest('.toc-link'); if(!a) return;
    var id=a.getAttribute('href'); if(!id||id.charAt(0)!=='#') return;
    var t=root.querySelector(id); if(!t) return;
    e.preventDefault(); t.scrollIntoView({behavior:'smooth',block:'start'});
    history.replaceState(null,'',id);
  });
})();
&lt;/script&gt;</description>
      <category>NOTICE</category>
      <category>UX개선</category>
      <category>개발자블로그</category>
      <category>검색창</category>
      <category>댓글디자인</category>
      <category>명절</category>
      <category>블로그리뉴얼</category>
      <category>스킨</category>
      <category>연휴</category>
      <category>추석인사</category>
      <category>카테고리목록</category>
      <author>간지뽕빨리턴님</author>
      <guid isPermaLink="true">https://odinbox.tistory.com/554</guid>
      <comments>https://odinbox.tistory.com/554#entry554comment</comments>
      <pubDate>Wed, 8 Oct 2025 12:49:25 +0900</pubDate>
    </item>
    <item>
      <title>USB와 Thunderbolt 비교, 진화 과정부터 선택 가이드까지 한 번에 이해하기</title>
      <link>https://odinbox.tistory.com/553</link>
      <description>&lt;article lang=&quot;ko&quot;&gt;&lt;!-- SEO --&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;USB와 Thunderbolt의 세대별 진화, 속도와 전력, 영상 출력, 확장성, 호환성 차이를 한눈에 비교하고, 상황별 선택 가이드까지 정리한 종합 안내서&lt;/span&gt;&lt;/p&gt;
&lt;div class=&quot;txc-textbox&quot; style=&quot;font-weight: normal; position: relative; line-height: 40px; background: #007CBA; border: 1px solid #fff; padding: 10px; color: white; border-radius: 0 10px 0 10px; box-shadow: inset 0 0 5px rgba(53,86,129, 0.5); font-family: 'Muli', sans-serif; border-style: solid; border-width: 0px  0px  1px 15px; border-color: #232323; background-color: #007cba;&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-size: 15pt; color: #ffffff;&quot;&gt;&lt;b&gt;USB와 Thunderbolt :: 이 글 하나면 정리할 수 있습니다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;글 상단 부분 대표 이미지.png&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cJcHjd/btsQ14kv6Zn/WzmH8aSmA4c8j4nFLkOOJk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cJcHjd/btsQ14kv6Zn/WzmH8aSmA4c8j4nFLkOOJk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cJcHjd/btsQ14kv6Zn/WzmH8aSmA4c8j4nFLkOOJk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcJcHjd%2FbtsQ14kv6Zn%2FWzmH8aSmA4c8j4nFLkOOJk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;400&quot; data-filename=&quot;글 상단 부분 대표 이미지.png&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;letter-spacing: 0px; font-family: 'Noto Sans Light';&quot;&gt;스마트폰 충전, 외장 SSD, 4K 또는 8K 모니터, 도킹 스테이션까지 이제는 한 포트로 해결합니다. 그 중심에는 USB와 Thunderbolt 표준의 꾸준한 진화가 있습니다. 이 글은 USB 1.0부터 USB4, Thunderbolt 1부터 4까지의 발전 과정을 하나의 흐름으로 설명하고, 전송속도, 전력, 영상, 확장성, 호환성 관점에서 차이를 분석합니다. 마지막에는 용도별 선택 가이드로 구매와 구축 판단을 돕습니다.&lt;/span&gt;&lt;/p&gt;
&lt;div class=&quot;txc-textbox&quot; style=&quot;border-style: solid; font-weight: bold; border-width: 1px  1px  1px 5px; border-color: #707070; background-color: #fff; padding: 10px;&quot;&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;https://tistory3.daumcdn.net/tistory/1569230/skin/images/jquery.toc.js&quot;&gt;&lt;/script&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;목차&lt;/p&gt;
&lt;ul id=&quot;toc&quot; style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;&lt;/ul&gt;
&lt;script type=&quot;text/javascript&quot;&gt;
$(function(){
	$(&quot;#toc&quot;).toc( {content: &quot;.tt_article_useless_p_margin&quot;, headings: &quot;h1,h2,h3,h4&quot; , top: -90, isBlink : true, blinkColor : '#21B9DE' } ) });
&lt;/script&gt;
&lt;/div&gt;
&lt;!-- 2) 세대별 기술분석 --&gt;
&lt;section id=&quot;generational-analysis&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;USB &amp;amp; 썬더볼트&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;세대별 기술분석&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;USB의 출발점인 USB 1.x는 다양한 직렬, 병렬 포트를 하나로 통합하고 플러그 앤 플레이, 핫스왑을 표준화하려는 요구에서 탄생했습니다. 1.5 Mbps와 12 Mbps 속도, 5V 버스 전원으로 소형 주변기기를 외부 어댑터 없이 구동할 수 있었고, Type-A(호스트), Type-B(장치) 구분이 보급을 이끌었습니다. 1998년 1.1 개정으로 안정성이 올라가며 본격 대중화가 시작됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;대용량 데이터와 휴대기기 확산에 맞춰 USB 2.0은 480 Mbps로 속도를 끌어올렸습니다. 플래시 드라이브와 외장 HDD가 일상화되었고, 5V 0.5A(이후 BC 1.2로 최대 1.5A) 전력 공급이 스마트폰 충전의 표준으로 자리 잡았습니다. 소형 연결은 Mini-USB, 이어서 Micro-USB가 주도하면서 휴대기기 생태계가 USB 중심으로 재편됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;고해상도 멀티미디어와 SSD 등장으로 병목이 커지자 USB 3.0은 5 Gbps SuperSpeed와 전이중 구조로 응답했습니다. 송신과 수신을 동시에 처리하고 UASP로 대용량 파일 처리 효율을 끌어올렸으며, 0.9A 버스 전원으로 버스파워 장치 운용 여지가 커졌습니다. 파란색 인서트 Type-A/B(9핀), Micro-B(SS)가 이 세대의 상징처럼 쓰였습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;USB 3.1은 인코딩 개선으로 10Gbps에 도달했지만, 더 큰 전환점은 USB Type-C였습니다. 위아래 구분 없는 리버서블, 소형, 내구성 높은 설계에 더해, 한 포트에서 데이터, 영상(DisplayPort Alt Mode), 전원(USB Power Delivery)을 통합 처리합니다. 최대 100W 충전이 가능해지며 노트북 충전이 USB-C 중심으로 이동했습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;USB 3.2는 새로운 신호 대신 USB-C 내부의 두 레인을 병렬로 묶어 최대 20 Gbps(Gen2x2)를 달성했습니다. 고성능 외장 NVMe SSD에서 체감 이점이 컸지만, 호스트, 장치, 케이블 모두가 동일 모드를 지원해야 하고 명칭 체계가 복잡해 사용자 혼선도 있었습니다. 그럼에도 USB-C 하나로 더 빠르게, 더 많이 연결한다는 방향은 더욱 공고해졌습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;USB4는 Thunderbolt 3 기술을 흡수해 최대 40 Gbps에서 USB 3.x, PCI Express, DisplayPort를 터널링 합니다. 단일 USB-C 포트로 고속 스토리지, 고해상도 디스플레이, 도킹 확장을 동시에 처리하기 쉬워졌고, 동시대의 USB PD 3.1과 결합하면 최대 240W 전력 전달 생태계가 열렸습니다. 구현에 따라 Thunderbolt 3 호환이 가능한 제품이 많아지며 사실상 경계가 크게 좁혀졌습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Thunderbolt는 전문가 워크플로를 겨냥해 별도의 궤적으로 발전했습니다. Thunderbolt 1은 Mini DisplayPort 형태에 10 Gbps 듀얼 채널(총 20 Gbps)로 PCIe 데이터와 DisplayPort 영상을 한 케이블로 처리했고, 최대 6대 데이지체인을 지원했습니다. Thunderbolt 2는 두 채널을 하나로 묶어 단일 20 Gbps 스트림을 구성, 4K 작업 흐름을 안정화했습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Thunderbolt 3는 USB-C 채택과 함께 40Gbps, PCIe 3.0 x4 + DP 1.2, USB 3.1 호환 모드, PD 최대 100W를 한 포트에 통합했습니다. eGPU, NVMe RAID, 듀얼 4K 또는 단일 5K 구성까지 노트북 한 포트로 실현하면서 사실상 USB-C의 최상위 모드가 되었습니다. Thunderbolt 4는 속도는 동일하지만 듀얼 4K 또는 단일 8K, PCIe 32 Gbps 보장, 정식 Thunderbolt 허브(멀티 포트 분기), 강화된 보안 같은 최소 요구사항을 의무화해 일관성과 안정성을 크게 높였습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt; USB4와의 폭넓은 호환성도 유지됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;/section&gt;
&lt;!-- 3) 핵심 차이 --&gt;
&lt;section id=&quot;differences&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;USB와 Thunderbolt의 핵심 차이(논리적 비교)&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;철학과 목표&lt;/b&gt; : USB는 보급형, 범용, 저비용, 광호환을 지향합니다. Thunderbolt는 고성능, 저지연, 강력한 확장을 지향합니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;프로토콜과 대역폭 활용&lt;/b&gt; : USB는 USB 패킷과 Alt Mode 중심, Thunderbolt는 PCIe와 DisplayPort를 동시 터널링합니다. 동일 40Gbps라도 NVMe, eGPU 같은 작업에서 Thunderbolt가 유리합니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;영상 출력&lt;/b&gt; : USB-C의 DP Alt Mode로 단일 4K는 충분합니다. 듀얼 4K, 8K, 고주사율, 고컬러뎁스 구성은 Thunderbolt가 일관성과 여유가 큽니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;전력 전달&lt;/b&gt; : USB PD는 100W, 일부 240W까지 확장됩니다. Thunderbolt 포트도 USB-C 기반이므로 PD를 활용하며, 인증 기기는 고부하에서도 전력, 대역폭 관리가 일관적인 편입니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;확장 토폴로지&lt;/b&gt; : USB는 허브 중심(스타형), Thunderbolt는 데이지체인에 더해 Thunderbolt 4부터 허브 분기를 지원합니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;케이블과 길이 : 고속일수록 길이에 민감합니다. USB 3.2 Gen2x2, USB4, TB3/4 모두 케이블 인증, 길이, 액티브/패시브 여부가 성능을 좌우합니다. Thunderbolt는 인증 체계가 엄격합니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;비용과 생태계&lt;/b&gt; : USB는 저비용, 광범위 보급입니다. Thunderbolt는 컨트롤러와 독 비용이 높지만, 도킹과 프로 워크플로에서 안정성과 확장성이 뛰어납니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;호환성&lt;/b&gt; : TB3/4 포트는 USB 장치를 수용합니다. 반대로 USB 전용 포트는 TB 장치를 인식하지 못합니다. USB4는 TB3 호환 구현이 많아 경계가 좁혀졌습니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;!-- 4) 한눈에 보는 USB vs Thunderbolt (Styled Table) --&gt;
&lt;section id=&quot;comparison&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;한눈에 보는 USB vs Thunderbolt&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;div class=&quot;meta&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;한눈에 파악할 수 있도록 핵심 포인트를 빠르게 비교하세요.&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;table-wrap&quot; role=&quot;region&quot; aria-label=&quot;USB와 Thunderbolt 비교표&quot;&gt;
&lt;div class=&quot;table-scroll&quot;&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;구분&lt;/span&gt;&lt;/th&gt;
&lt;th&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;USB&lt;/span&gt;&lt;/th&gt;
&lt;th&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Thunderbolt&lt;/span&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;첫 도입, 목표&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;1996, 주변기기 포트 통합, 플러그앤플레이, 핫스왑 표준화&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;2011, 전문가 워크플로(스토리지, 영상)용 초고속 단일 케이블&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;최신 세대&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;USB4, 20/40Gbps, USB-C 전용&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Thunderbolt 4, 40Gbps, USB-C&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;대역폭, 방식&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;480Mbps(2.0) &amp;rarr; 5/10/20Gbps(3.x) &amp;rarr; 20/40Gbps(USB4)&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;20Gbps(TB1/2) &amp;rarr; 40Gbps(TB3/4), PCIe + DisplayPort 동시 터널링&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;영상 출력&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;USB-C의 DP Alt Mode, 구현 의존, 단일 4K 중심&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;DP 터널링 기본, 듀얼 4K 또는 단일 8K까지 안정적 구성&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;전력 공급&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;USB PD 최대 100W, PD 3.1 환경 최대 240W&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;버스전원 10~15W, USB PD 최대 100W(제품 구현)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;확장 토폴로지&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;허브 중심(스타형), 데이지체인 불가&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;데이지체인(최대 6대), TB4 허브 분기 지원&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;호환성&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;세대 간 하위호환 광범위, USB4는 TB3 호환 가능(옵션)&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;TB3/4 포트는 USB 장치 수용, USB 전용 포트는 TB 장치 미지원&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;케이블, 길이&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Gen/레인/길이/인증에 따라 성능 좌우, 특히 Gen2x2, USB4&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;40Gbps 장거리에는 액티브 케이블 요구, 인증 체계 엄격&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;비용, 생태계&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;저비용, 광범위 보급&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;고급형, 전문 생태계, 컨트롤러/독 가격대 높음&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;대표 용도&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;충전, 일반 주변기기, 외장 SSD, 단일 4K 모니터&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;eGPU, 초고속 NVMe RAID, 듀얼 4K 또는 8K, 전문 영상/오디오&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;!-- 5) 기술 진화도(타임라인) --&gt;
&lt;section id=&quot;timeline&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;기술 진화도(타임라인)&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;time datetime=&quot;1996&quot;&gt;1996&lt;/time&gt; USB 1.0, 1.5/12Mbps&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;time datetime=&quot;1998&quot;&gt;1998&lt;/time&gt; USB 1.1, 대중화&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;time datetime=&quot;2000&quot;&gt;2000&lt;/time&gt; USB 2.0, 480Mbps, Mini/Micro-USB 확산&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;time datetime=&quot;2008&quot;&gt;2008&lt;/time&gt; USB 3.0, 5Gbps, 전이중, UASP&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;time datetime=&quot;2011&quot;&gt;2011&lt;/time&gt; Thunderbolt 1, 20Gbps, Mini DP, 데이지체인&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;time datetime=&quot;2013&quot;&gt;2013&lt;/time&gt; USB 3.1, 10Gbps, USB-C, DP Alt Mode, USB PD, Thunderbolt 2, 20Gbps&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;time datetime=&quot;2015&quot;&gt;2015&lt;/time&gt; Thunderbolt 3, 40Gbps, USB-C, PCIe 3.0 x4 + DP 1.2, PD 100W&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;time datetime=&quot;2017&quot;&gt;2017&lt;/time&gt; USB 3.2, 최대 20Gbps, 멀티레인 Gen2x2&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;time datetime=&quot;2019&quot;&gt;2019&lt;/time&gt; USB4, 20/40Gbps, TB3 기술 통합, 다중 프로토콜 터널링&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;time datetime=&quot;2020&quot;&gt;2020&lt;/time&gt; Thunderbolt 4, 40Gbps, 듀얼 4K 또는 8K, TB 허브, 강화된 최소요건&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;!-- 6) 상황별 선택 가이드 --&gt;
&lt;section id=&quot;guide&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;상황별 선택 가이드&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;일반 사용&lt;/b&gt; : 스마트폰 충전, 백업, 주변기기 연결, 단일 4K 모니터는 USB-C(USB 3.1/3.2 이상)와 PD 충전기로 충분합니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;대용량/고속 저장&lt;/b&gt; : 외장 NVMe SSD는 10Gbps 이상 권장, USB 3.2 Gen2x2(20Gbps) 또는 Thunderbolt 3/4(40Gbps) 고려.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;멀티 디스플레이&lt;/b&gt; : 단일 4K는 USB-C DP Alt Mode로 무난, 듀얼 4K 또는 8K, 고주사율은 Thunderbolt 3/4 또는 USB4가 안정적.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;eGPU, 전문 영상/오디오&lt;/b&gt; : PCIe급 대역폭이 필요한 워크플로는 Thunderbolt 3/4가 사실상 표준입니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;노트북/모니터 전원&lt;/b&gt; : 65~100W는 USB PD로 충분, 고출력 장비는 PD 3.1(최대 240W) 지원 여부 확인.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;케이블 체크&lt;/b&gt; : 표기 대역(20/40Gbps), 길이, 액티브/패시브, PD 등급을 반드시 확인, 인증 케이블 사용이 성능과 안정성을 좌우합니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;!-- 7) 마무리 --&gt;
&lt;section id=&quot;outro&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;마무리&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;USB는 범용성과 저비용, 광호환을 무기로 일상 연결의 표준이 되었고, Thunderbolt는 PCIe와 DisplayPort 터널링, 엄격한 인증을 바탕으로 고성능, 저지연 확장을 책임져 왔습니다. USB4가 TB3 기술을 흡수하면서 두 세계는 USB-C라는 단자 아래 사실상 수렴 중입니다. 일반 용도는 USB로 충분하며, 고성능, 멀티 디스플레이, 전문 워크플로는 Thunderbolt 3/4 또는 USB4가 해답입니다. 앞으로도 USB-C 한 포트로 데이터, 영상, 전원, 확장을 아우르는 흐름은 더 강화될 것입니다.&lt;/span&gt;&lt;/p&gt;
&lt;/section&gt;
&lt;/article&gt;
&lt;div&gt;
&lt;style&gt;
    /* Readability-first table styles */
     :root {
      --bg : #ffffff;
      --text : #111827;
      --muted : #6b7280;
      --primary : #0ea5e9;
      --border : #e5e7eb;
      --row : #f9fafb;
      --row2 : #ffffff;
      --shadow : 0 1px 2px rgba(0,0,0,0.05);
      --radius : 12px;
    }
    body, table { color : var(--text); }
    section { margin : 1.25rem 0 1.75rem; }
    p { line-height : 1.7; margin : 0.6rem 0; }
    h1, h2 { line-height : 1.35; }
    h1 { font-size : 1.85rem; margin : 0 0 1rem; }
    h2 { font-size : 1.35rem; margin : 1.2rem 0 0.6rem; }
    ul { padding-left : 1.1rem; }
    ul li { margin : 0.35rem 0; }

    .table-wrap {
      margin-top : 0.8rem;
      background : var(--bg);
      border : 1px solid var(--border);
      border-radius : var(--radius);
      overflow : hidden;
      box-shadow : var(--shadow);
    }
    .table-scroll {
      overflow-x : auto;
      -webkit-overflow-scrolling : touch;
    }
    table {
      width : 100%;
      border-collapse : separate;
      border-spacing : 0;
      min-width : 760px;
    }
    thead th {
      position : sticky;
      top : 0;
      background : #f1f5f9;
      text-align : left;
      padding : 12px 14px;
      font-weight : 600;
      border-bottom : 1px solid var(--border);
      white-space : nowrap;
    }
    tbody td {
      padding : 12px 14px;
      vertical-align : top;
      border-bottom : 1px solid var(--border);
    }
    tbody tr :nth-child(odd) { background : var(--row); }
    tbody tr :nth-child(even) { background : var(--row2); }
    tbody tr :hover { background : #eef6ff; }
    .meta {
      color : var(--muted);
      font-size : 0.95rem;
      margin-top : -0.35rem;
      margin-bottom : 0.4rem;
    }
    .tag {
      display : inline-block;
      font-size : .8rem;
      color : #0369a1;
      background : #e0f2fe;
      border : 1px solid #bae6fd;
      padding : 2px 8px;
      border-radius : 999px;
      margin-right : 6px;
      margin-bottom : 6px;
    }
  &lt;/style&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>IT</category>
      <category>thunderbolt</category>
      <category>usb</category>
      <category>usb-c</category>
      <category>usb4</category>
      <category>고속충전</category>
      <category>도킹스테이션</category>
      <category>모니터출력</category>
      <category>외장SSD</category>
      <category>전송속도</category>
      <category>하드웨어가이드</category>
      <author>간지뽕빨리턴님</author>
      <guid isPermaLink="true">https://odinbox.tistory.com/553</guid>
      <comments>https://odinbox.tistory.com/553#entry553comment</comments>
      <pubDate>Sat, 4 Oct 2025 10:34:36 +0900</pubDate>
    </item>
    <item>
      <title>카카오 if(kakao)25 후기</title>
      <link>https://odinbox.tistory.com/552</link>
      <description>&lt;div&gt;
&lt;style&gt;
  :root{
    --ink:#0f172a;           
    --ink-2:#334155;         
    --bg:#ffffff;            
    --accent:#007CBA;        
    --accent-2:#0ea5e9;      
    --line:#e9eef3;          
    --muted:#64748b;         
    --radius:14px;           
    --radius-sm:10px;
    --shadow:0 16px 38px rgba(2,14,40,.10);
    --shadow-sm:0 6px 20px rgba(2,14,40,.08);
    --shadow-hover:0 22px 48px rgba(2,14,40,.16);
    --maxw:980px;            
  }

  .devconf-article{max-width:var(--maxw);margin:0 auto;padding:8px 16px;color:var(--ink);line-height:1.75;word-break:keep-all}
  .devconf-article p{margin:1rem 0}
  .devconf-article h1,.devconf-article h2,.devconf-article h3,.devconf-article h4{
    font-family:&quot;Nanum Gothic&quot;,&quot;Noto Sans KR&quot;,system-ui,AppleSDGothicNeo,&quot;Segoe UI&quot;,sans-serif;
    color:var(--ink); 
  }
  .devconf-article h2{font-size:1.65rem;font-weight:800;margin:2.2rem 0 1rem;display:flex;align-items:center;gap:.6rem}
  .devconf-article h2::before{content:&quot;&quot;;display:inline-block;width:10px;height:10px;border-radius:3px;background:var(--accent);box-shadow:0 0 0 6px rgba(0,124,186,.12)}
  .devconf-article h3{font-size:1.35rem;font-weight:800;margin:1.6rem 0 .6rem}
  .devconf-article h4{font-size:1.12rem;font-weight:700;margin:1.2rem 0 .4rem;color:#0b3c59}

  .devconf-hero p[data-ke-size]{margin:.25rem 0}
  .devconf-hero .txc-textbox{
    position:relative;border:0;background:linear-gradient(135deg,var(--accent),#0097d1);
    color:#fff;border-radius:0 14px 0 14px;padding:16px 18px;box-shadow:inset 0 0 6px rgba(0,0,0,.15), var(--shadow-sm);
  }
  .devconf-hero .txc-textbox b{letter-spacing:.2px}
  .devconf-hero .txc-textbox::after{
    content:&quot;Developer Conference&quot;;position:absolute;right:10px;bottom:8px;font-size:.75rem;opacity:.6
  }

  .dev-card{background:var(--bg);border:1px solid var(--line);border-radius:var(--radius);box-shadow:var(--shadow-sm);padding:18px 18px;margin:16px 0}
  .dev-card:hover{box-shadow:var(--shadow-hover);transition:box-shadow .25s ease}

  .devconf-article .txc-textbox:not(.devconf-hero .txc-textbox){
    border:1px solid var(--line)!important;background:#fbfdff!important;border-left:6px solid var(--accent)!important;
    border-radius:12px!important;box-shadow:var(--shadow-sm)!important;padding:14px 16px!important
  }

  .dev-toc{position:relative;background:#fff;border:1px solid var(--line);border-radius:var(--radius);padding:14px 16px;box-shadow:var(--shadow);margin:18px 0 28px}
  .dev-toc p{margin:.2rem 0 .6rem;color:var(--muted);font-weight:700}
  .dev-toc ul#toc{list-style:none;padding:0;margin:0;display:grid;gap:.35rem}
  .dev-toc ul#toc li a{display:block;text-decoration:none;color:var(--ink-2);padding:.28rem .4rem;border-radius:10px}
  .dev-toc ul#toc li a:hover{background:#f0f9ff;color:#075985}

  .devconf-article img{max-width:100%;height:auto;border-radius:12px;box-shadow:var(--shadow-sm)}
  .devconf-article p:has([id^=&quot;_Image&quot;],[id^=&quot;_ImageGrid&quot;]){margin:1rem 0}
  .img-grid{display:grid;gap:10px}
  .devconf-article .alignCenter{display:block;margin-inline:auto}

  .dev-file{display:flex;align-items:center;gap:10px;background:#f8fbff;border:1px solid var(--line);border-radius:12px;padding:10px 12px;margin:10px 0}
  .dev-file .dev-file-ic{width:28px;height:28px;flex:0 0 28px;border-radius:6px;background:#e0f2fe;display:inline-flex;align-items:center;justify-content:center;font-weight:800;color:#0369a1}
  .dev-file a{text-decoration:none;color:#075985}
  .dev-file small{color:var(--muted)}

  .media-wrap{position:relative;width:100%;aspect-ratio:16/9;border-radius:14px;overflow:hidden;box-shadow:var(--shadow);margin:10px 0}
  .media-wrap iframe{position:absolute;inset:0;width:100%;height:100%}

  .devconf-article table{width:100%;border-collapse:collapse;border:1px solid var(--line);border-radius:12px;overflow:hidden;box-shadow:var(--shadow-sm);margin:14px 0}
  .devconf-article th,.devconf-article td{padding:.7rem .8rem;border-bottom:1px solid var(--line)}
  .devconf-article thead th{background:#f8fbff;text-align:left}
  pre,code{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace}
  pre{overflow:auto;background:#0b1220;color:#e5e7eb;border-radius:12px;padding:12px 14px;box-shadow:var(--shadow-sm)}

  .dev-meta{display:flex;gap:10px;flex-wrap:wrap;color:var(--muted);font-size:.9rem;margin:.5rem 0 1.2rem}
  .dev-badge{display:inline-flex;align-items:center;gap:.4rem;background:#ecfeff;color:#0e7490;border:1px solid #99f6e4;padding:.18rem .55rem;border-radius:999px;font-size:.78rem}
  .dev-note{font-size:.95rem;color:#0b3c59;background:#f0f9ff;border:1px dashed #bae6fd;border-radius:10px;padding:10px 12px;margin:.8rem 0}

  @media (max-width: 768px){
    .devconf-article{padding:4px 12px}
    .devconf-article h2{font-size:1.4rem}
    .devconf-article h3{font-size:1.18rem}
  }

  .dev-anchor{opacity:.18;margin-left:.35rem;font-weight:600;text-decoration:none}
  .dev-anchor:hover{opacity:.5}
&lt;/style&gt;
&lt;/div&gt;
&lt;script type=&quot;application/ld+json&quot;&gt;
{
  &quot;@context&quot;:&quot;https://schema.org&quot;,
  &quot;@type&quot;:&quot;BlogPosting&quot;,
  &quot;inLanguage&quot;:&quot;ko-KR&quot;,
  &quot;headline&quot;:&quot;가능성이 일상이 될 때, if(kakao)25에서 본 AI&quot;,
  &quot;about&quot;:[&quot;if(kakao)25&quot;,&quot;Developer Conference&quot;,&quot;AI&quot;,&quot;Agent&quot;,&quot;On-device&quot;,&quot;Long Context&quot;,&quot;Multimodal&quot;],
  &quot;keywords&quot;:&quot;if(kakao)25, 카카오, 개발자 컨퍼런스, AI, 에이전트, 온디바이스, 롱컨텍스트, 멀티모달, Kanana&quot;,
  &quot;isAccessibleForFree&quot;: &quot;true&quot;,
  &quot;mainEntityOfPage&quot;:{&quot;@type&quot;:&quot;WebPage&quot;,&quot;@id&quot;:document.location.href}
}
&lt;/script&gt;
&lt;div id=&quot;devconf-article&quot; class=&quot;devconf-article&quot;&gt;
&lt;section class=&quot;devconf-hero&quot;&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;개발자와 일반인 모두 즐길 수 있었던 행사&lt;/span&gt;&lt;/p&gt;
&lt;div class=&quot;txc-textbox&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-size: 15pt; color: #ffffff;&quot;&gt;&lt;b&gt;가능성이 일상이 될 때, if(kakao)25에서 본 AI&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nciXR/btsQR87Lz2j/qndAc5zp37gsYKi6VuxPQk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nciXR/btsQR87Lz2j/qndAc5zp37gsYKi6VuxPQk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nciXR/btsQR87Lz2j/qndAc5zp37gsYKi6VuxPQk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnciXR%2FbtsQR87Lz2j%2FqndAc5zp37gsYKi6VuxPQk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;400&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/section&gt;
&lt;div class=&quot;dev-meta&quot;&gt;&lt;span class=&quot;dev-badge&quot;&gt;if(kakao)25 현장기&lt;/span&gt; &lt;span&gt;AI &amp;middot; 에이전트 &amp;middot; 온디바이스 &amp;middot; 롱컨텍스트 &amp;middot; 멀티모달&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;dev-toc dev-card&quot;&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;https://tistory3.daumcdn.net/tistory/1569230/skin/images/jquery.toc.js&quot;&gt;&lt;/script&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;목차&lt;/p&gt;
&lt;ul id=&quot;toc&quot; style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;&lt;/ul&gt;
&lt;script&gt;
      (function(){
        if (window.jQuery){
          jQuery(function(){
            jQuery(&quot;#toc&quot;).toc({
              content: &quot;.tt_article_useless_p_margin&quot;,
              headings: &quot;h1,h2,h3,h4&quot;,
              top: -90,
              isBlink : true,
              blinkColor : '#21B9DE'
            });
          });
        }
      })();
    &lt;/script&gt;
&lt;/div&gt;
&lt;div class=&quot;tt_article_useless_p_margin&quot;&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;지난 9월 24일, 경기도 용인시에 위치한 카카오 AI캠퍼스에서 개최된 if(kakao)25 컨퍼런스에 다녀왔습니다. 올해로 7회를 맞이한 이프카카오는 카카오 그룹의 기술 비전과 성과를 공유하는 연례행사입니다. 가능성, 일상이 되다라는 슬로건 아래 인공지능 기술의 대중화를 목표로 다양한 세션과 발표가 진행되었습니다. 개발자뿐 아니라 다양한 업계 관계자들이 한자리에 모여 카카오의 AI 신기술과 서비스를 직접 체험할 수 있었던 자리였습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;이번 글에서는 지방에서 참가한 저의 이동 여정부터 현장 분위기, 그리고 각 세션에서 다뤄진 주요 기술 내용을 정리해 공유드립니다. 특히 카카오의 차세대 AI 모델인 카나나 시리즈, 에이전트, 온디바이스 AI최적화 등 개발자분들이 관심 가질만한 부분을 중심으로 보완설명을 덧붙였습니다.&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;if(KAKAO)25&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;울산에서 서울로&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;행사가 평일 이른 아침 시작이라 전날 퇴근 후 곧바로 울산에서 서울로 이동을 했습니다. 9월 23일 퇴근 후 울산역에서 SRT를 타고 수서역에 도착 수인분당선과 2호선을 환승해 강남역 인근 숙소에 도착을 하여 다음 날 컨퍼런스에 대한 기대감을 갖고 잠에 들었습니다.&lt;/span&gt;&lt;/p&gt;
&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ykfza/btsQSju1EIG/Wcta6871fhsdEVC8ImmAgK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ykfza/btsQSju1EIG/Wcta6871fhsdEVC8ImmAgK/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot; data-filename=&quot;blob&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ykfza/btsQSju1EIG/Wcta6871fhsdEVC8ImmAgK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fykfza%2FbtsQSju1EIG%2FWcta6871fhsdEVC8ImmAgK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bDdFOz/btsQSipfnKx/IXQdANDpciTTmujT4NB3u1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bDdFOz/btsQSipfnKx/IXQdANDpciTTmujT4NB3u1/img.png&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot; data-is-animation=&quot;false&quot; data-filename=&quot;blob&quot; data-widthpercent=&quot;50&quot; style=&quot;width: 49.4186%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bDdFOz/btsQSipfnKx/IXQdANDpciTTmujT4NB3u1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbDdFOz%2FbtsQSipfnKx%2FIXQdANDpciTTmujT4NB3u1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cce07c/btsQTSJAA4C/3moK3IItPplq1U9oN4eDC0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cce07c/btsQTSJAA4C/3moK3IItPplq1U9oN4eDC0/img.png&quot; data-origin-width=&quot;1689&quot; data-origin-height=&quot;3000&quot; data-is-animation=&quot;false&quot; data-filename=&quot;blob&quot; data-widthpercent=&quot;13.68&quot; style=&quot;width: 13.3622%; margin-right: 10px; margin-top: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cce07c/btsQTSJAA4C/3moK3IItPplq1U9oN4eDC0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcce07c%2FbtsQTSJAA4C%2F3moK3IItPplq1U9oN4eDC0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1689&quot; height=&quot;3000&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bQIAbd/btsQRzLBjiy/xlH52ySfOGBbWQnspGuqJ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bQIAbd/btsQRzLBjiy/xlH52ySfOGBbWQnspGuqJ1/img.png&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot; data-is-animation=&quot;false&quot; data-filename=&quot;blob&quot; style=&quot;width: 42.1561%; margin-right: 10px; margin-top: 10px;&quot; data-widthpercent=&quot;43.16&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bQIAbd/btsQRzLBjiy/xlH52ySfOGBbWQnspGuqJ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbQIAbd%2FbtsQRzLBjiy%2FxlH52ySfOGBbWQnspGuqJ1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/botiPK/btsQR9MivsU/WkgJbuH62n9cC9RcbXkU5k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/botiPK/btsQR9MivsU/WkgJbuH62n9cC9RcbXkU5k/img.png&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot; data-is-animation=&quot;false&quot; data-filename=&quot;blob&quot; style=&quot;width: 42.1561%; margin-top: 10px;&quot; data-widthpercent=&quot;43.16&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/botiPK/btsQR9MivsU/WkgJbuH62n9cC9RcbXkU5k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbotiPK%2FbtsQR9MivsU%2FWkgJbuH62n9cC9RcbXkU5k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;당일 아침, 셔틀 탑승과 입장&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;9월 24일 아침 7시에 일어나 준비를 마쳤고 8시 10분쯤 강남역 5번 출구에 도착을 했습니다. 셔틀 탑스안내 피켓을 든 진행요원을 따라 QR코드로 탑승 확인을 했고 8시 30분 정시에 셔틀이 출발했습니다. 약 한 시간 후 용인 수지구에 위치한 카카오 AI캠퍼스에 도착을 했고 간단히 초대권 확인을 마치고 웰컴 키트를 수령했습니다. 본 행사장으로 이동을 하니 직원분들의 박수 환대가 이어졌고 극I였던 저로써는 잠시동안 공포의 시간이였고 일찍 도착하여 거의 맨 앞줄에 착석을 할 수 있었습니다. 그 이후 참가하는 분들도 많이 들어왔습니다.&lt;/span&gt;&lt;/p&gt;
&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/5RHRM/btsQTrlaInc/W2jXAqQHrRaBZLg2CjjOwK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/5RHRM/btsQTrlaInc/W2jXAqQHrRaBZLg2CjjOwK/img.png&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot; data-is-animation=&quot;false&quot; data-filename=&quot;blob&quot; data-widthpercent=&quot;75.93&quot; style=&quot;width: 75.049%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/5RHRM/btsQTrlaInc/W2jXAqQHrRaBZLg2CjjOwK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F5RHRM%2FbtsQTrlaInc%2FW2jXAqQHrRaBZLg2CjjOwK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/VvZKO/btsQTUm9mhv/IyQrlCy9KQktyJyeY7bQvk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/VvZKO/btsQTUm9mhv/IyQrlCy9KQktyJyeY7bQvk/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;1689&quot; data-origin-height=&quot;3000&quot; data-filename=&quot;blob&quot; style=&quot;width: 23.7882%;&quot; data-widthpercent=&quot;24.07&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/VvZKO/btsQTUm9mhv/IyQrlCy9KQktyJyeY7bQvk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FVvZKO%2FbtsQTUm9mhv%2FIyQrlCy9KQktyJyeY7bQvk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1689&quot; height=&quot;3000&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/OTw32/btsQR03wvoV/j74LI2Ye6peHRuLGDYc5mK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/OTw32/btsQR03wvoV/j74LI2Ye6peHRuLGDYc5mK/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot; data-filename=&quot;blob&quot; data-widthpercent=&quot;50&quot; style=&quot;width: 49.4186%; margin-right: 10px; margin-top: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/OTw32/btsQR03wvoV/j74LI2Ye6peHRuLGDYc5mK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOTw32%2FbtsQR03wvoV%2Fj74LI2Ye6peHRuLGDYc5mK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/v6zHh/btsQQYrj6OT/cmRTSilYXXoaIfEnJIFzak/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/v6zHh/btsQQYrj6OT/cmRTSilYXXoaIfEnJIFzak/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot; data-filename=&quot;blob&quot; style=&quot;width: 49.4186%; margin-top: 10px;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/v6zHh/btsQQYrj6OT/cmRTSilYXXoaIfEnJIFzak/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fv6zHh%2FbtsQQYrj6OT%2FcmRTSilYXXoaIfEnJIFzak%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mEC5n/btsQRzkwpnH/q1akIe5YwIbtVQ4hxJN4Ck/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mEC5n/btsQRzkwpnH/q1akIe5YwIbtVQ4hxJN4Ck/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mEC5n/btsQRzkwpnH/q1akIe5YwIbtVQ4hxJN4Ck/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmEC5n%2FbtsQRzkwpnH%2Fq1akIe5YwIbtVQ4hxJN4Ck%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;오전 키노트 세션&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;오전에는 공통 키노트가 진행되었습니다, 기술적 핵심만 간단히 정리합니다.&lt;/span&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;PlayMCP - AI 서비스 생태계의 출발점&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qtWNB/btsQR9Miz7b/pkeUAJbV4BMNYbfn821km0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qtWNB/btsQR9Miz7b/pkeUAJbV4BMNYbfn821km0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qtWNB/btsQR9Miz7b/pkeUAJbV4BMNYbfn821km0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqtWNB%2FbtsQR9Miz7b%2FpkeUAJbV4BMNYbfn821km0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;모델과 서비스, 즉 에이전트가 외부 기능을 안전하게 호출하도록 연결하는 표준 프로토콜과 마켓&amp;middot;플레이그라운드 개념이 소개되었습니다. 세부적으로는 툴 등록과 권한 범위 선언, 컨텍스트 교환 형식, 호출 정책, 실행 기록 추적 같은 운영 포인트가 강조되었습니다. 개발자 관점에서 느낀 핵심은 두 가지였습니다. 첫째, 에이전트가 호출할 수 있는 기능을 능력 단위로 캡슐화해 상호 운용성을 높였다는 점. 둘째, 인증&amp;middot;과금&amp;middot;레이트리밋 같은 운영 레일이 프로토콜 레벨에서 고려되어 실서비스로 전환하기 쉽다는 점입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;Agentic AI를 향한 카나나 모델의 진화&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/5rDlH/btsQSw1zmL9/qxqdNYMEIHvKANjT3NBcDK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/5rDlH/btsQSw1zmL9/qxqdNYMEIHvKANjT3NBcDK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/5rDlH/btsQSw1zmL9/qxqdNYMEIHvKANjT3NBcDK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F5rDlH%2FbtsQSw1zmL9%2FqxqdNYMEIHvKANjT3NBcDK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;단순 응답형을 넘어 관찰(멀티모달 인지)-계획(체인&amp;middot;그래프 기반 플래닝)-행동(툴 실행) 루프를 붙이는 방향이 제시되었습니다. 프롬프트 기반 플래너와 경량 정책 모듈을 조합해 시나리오별 플로우를 안정적으로 재현하는 전략이 인상적이었습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;안전한 AI를 위한 카카오의 노력&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d9Iqi2/btsQSqtOXRW/aCxGYWk9PHYRInJqNxcBb0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d9Iqi2/btsQSqtOXRW/aCxGYWk9PHYRInJqNxcBb0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d9Iqi2/btsQSqtOXRW/aCxGYWk9PHYRInJqNxcBb0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd9Iqi2%2FbtsQSqtOXRW%2FaCxGYWk9PHYRInJqNxcBb0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;안전&amp;middot;품질 조직이 독립적으로 가드레일을 설계하고, 금칙행동 정의, PII 필터링, 심리&amp;middot;정치&amp;middot;의학 등 고위험 도메인에서의 방어 정책, 레드팀 라운드(모의 공격)와 휴리스틱&amp;middot;규칙&amp;middot;모델 앙상블을 결합한 검증 파이프라인을 운영한다는 점이 공유되었습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Kakao Re-engineering: AI-Native 전환&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bfsVmz/btsQR80Ze1j/5OBelsNX4CtwklryokW1KK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bfsVmz/btsQR80Ze1j/5OBelsNX4CtwklryokW1KK/img.png&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot; data-filename=&quot;blob&quot; data-is-animation=&quot;false&quot; style=&quot;width: 32.5581%; margin-right: 10px;&quot; data-widthpercent=&quot;33.33&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bfsVmz/btsQR80Ze1j/5OBelsNX4CtwklryokW1KK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbfsVmz%2FbtsQR80Ze1j%2F5OBelsNX4CtwklryokW1KK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bxSSB8/btsQSrfaonm/sKYgEXYXKwAedXeHkQDIOK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bxSSB8/btsQSrfaonm/sKYgEXYXKwAedXeHkQDIOK/img.png&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot; data-filename=&quot;blob&quot; data-is-animation=&quot;false&quot; style=&quot;width: 32.5581%; margin-right: 10px;&quot; data-widthpercent=&quot;33.33&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bxSSB8/btsQSrfaonm/sKYgEXYXKwAedXeHkQDIOK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbxSSB8%2FbtsQSrfaonm%2FsKYgEXYXKwAedXeHkQDIOK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/OAVn5/btsQQVH8G1A/7T5q5IahT8CMewEjwuudf0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/OAVn5/btsQQVH8G1A/7T5q5IahT8CMewEjwuudf0/img.png&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot; data-filename=&quot;blob&quot; data-is-animation=&quot;false&quot; style=&quot;width: 32.5581%;&quot; data-widthpercent=&quot;33.34&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/OAVn5/btsQQVH8G1A/7T5q5IahT8CMewEjwuudf0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOAVn5%2FbtsQQVH8G1A%2F7T5q5IahT8CMewEjwuudf0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;

&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;데이터 플랫폼-모델 플랫폼-서빙 플랫폼을 수평 결합하고, 릴리즈&amp;middot;모니터링&amp;middot;세이프티 리뷰를 ML 파이프라인에 통합하는 전사 아키텍처 전환이 소개되었습니다. 특히 실험 관리와 재현성, 피드백 루프 자동화가 강조되었습니다.&lt;/span&gt;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;[오전 세션 전체 : 다시보기]&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;center&gt;&lt;iframe src=&quot;https://www.youtube-nocookie.com/embed/UING73fPHiU?si=rKAYT_IihP0tT52r&quot; width=&quot;560&quot; height=&quot;315&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;&lt;/center&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;점심과 체험존&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/EeBV7/btsQTq0RRIr/MGiLfHEg43JczxzoqiSKs0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/EeBV7/btsQTq0RRIr/MGiLfHEg43JczxzoqiSKs0/img.png&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot; data-filename=&quot;blob&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/EeBV7/btsQTq0RRIr/MGiLfHEg43JczxzoqiSKs0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEeBV7%2FbtsQTq0RRIr%2FMGiLfHEg43JczxzoqiSKs0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/5kk9Z/btsQRJtGN1J/8S9C8zIwLMapHj3Hr7FfeK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/5kk9Z/btsQRJtGN1J/8S9C8zIwLMapHj3Hr7FfeK/img.png&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot; data-filename=&quot;blob&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.4186%;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/5kk9Z/btsQRJtGN1J/8S9C8zIwLMapHj3Hr7FfeK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F5kk9Z%2FbtsQRJtGN1J%2F8S9C8zIwLMapHj3Hr7FfeK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bGyi2V/btsQSs5XyNB/4qPlkhnIxzZNEWjVmKPi3K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bGyi2V/btsQSs5XyNB/4qPlkhnIxzZNEWjVmKPi3K/img.png&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot; data-filename=&quot;blob&quot; data-is-animation=&quot;false&quot; style=&quot;width: 42.0491%; margin-right: 10px;&quot; data-widthpercent=&quot;43.05&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bGyi2V/btsQSs5XyNB/4qPlkhnIxzZNEWjVmKPi3K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbGyi2V%2FbtsQSs5XyNB%2F4qPlkhnIxzZNEWjVmKPi3K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bbJOQo/btsQQUoRaeo/oLQ9CoqGYqsTSauAUt9EN1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bbJOQo/btsQQUoRaeo/oLQ9CoqGYqsTSauAUt9EN1/img.png&quot; data-origin-width=&quot;761&quot; data-origin-height=&quot;1327&quot; data-filename=&quot;blob&quot; data-is-animation=&quot;false&quot; style=&quot;width: 13.5762%; margin-right: 10px;&quot; data-widthpercent=&quot;13.9&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bbJOQo/btsQQUoRaeo/oLQ9CoqGYqsTSauAUt9EN1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbbJOQo%2FbtsQQUoRaeo%2FoLQ9CoqGYqsTSauAUt9EN1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;761&quot; height=&quot;1327&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c2fVrQ/btsQRFyAHv4/K6hcqvBgwuBBLcX8ymqhMk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c2fVrQ/btsQRFyAHv4/K6hcqvBgwuBBLcX8ymqhMk/img.png&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot; data-filename=&quot;blob&quot; data-is-animation=&quot;false&quot; style=&quot;width: 42.0491%;&quot; data-widthpercent=&quot;43.05&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c2fVrQ/btsQRFyAHv4/K6hcqvBgwuBBLcX8ymqhMk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc2fVrQ%2FbtsQRFyAHv4%2FK6hcqvBgwuBBLcX8ymqhMk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;

&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;점심 도시락은 치킨, 유부초밥, 과일로 구성이 되어있었고 스타벅스 음료와 생수가 넉넉했습니다. 체험존에서는 카나나 계열 모델과 다양한 데모를 직접 사용을 할 수 있었고 스티커를 모아 럭키드로우에 응모하는 이벤트가 진행되었습니다. 즐겁게 돌아다녔지만 아쉽게 경품은 뱃지와 체험권을 받아 조금은 실망은 했지만 체험은 재미있었습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;오후 기술 세션&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;LLM은 있지만 다시 학습하고 싶어 - Kanana-2 개발기 &lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;center&gt;&lt;iframe src=&quot;https://www.youtube-nocookie.com/embed/B7sc-OlnkCE?si=1pQNkan-53rcoBj7&quot; width=&quot;560&quot; height=&quot;315&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;&lt;/center&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Kanana-2는 프리트레이닝 스케일과 데이터 구성을 재설계해 범용성과 실서비스 적합성을 동시에 노립니다. 코드와 수학 비중을 크게 늘렸고, 데이터 중복 제거&amp;middot;라이선스 정합성&amp;middot;오류 주입 방지 규칙을 고도화해 텍스트 품질을 개선했습니다. 모델 구조는 Mixture of Experts로 전환해 토큰당 활성화되는 이 전문가 수를 조절하며 연산 효율을 높였습니다. 라우터 손실과 부하균형 패널티로 전문가 쏠림을 방지하고, 토큰 라우팅 로그를 분석해 비정상 라우팅을 조기에 탐지하는 운영 팁도 공유되었습니다. 컨텍스트 확장은 MLA류 기법과 RoPE 스케일 전략을 병행했고, 사후 정렬 단계에서는 지시 따르기, 함의&amp;middot;추론, 함수호출, 안전 정책 따르기 등 다축 학습을 별도로 돌린 뒤 점진적으로 합치는 하이브리드 레시피가 소개되었습니다. 중요한 메시지는 성능 숫자만이 아니라 회귀 방지와 안정 추론, 호환성 같은 사용자 체감 지표를 동등하게 관리하는 개발 문화였습니다.&lt;/span&gt;&lt;/p&gt;
&lt;figure class=&quot;fileblock&quot; data-ke-align=&quot;alignCenter&quot;&gt;&lt;a href=&quot;https://blog.kakaocdn.net/dn/EQTSy/dJMb9MbJp2q/QOK6AkJNCkPNkt16nVBkBK/01.LLM%EC%9D%80%20%EC%9E%88%EC%A7%80%EB%A7%8C%20%EB%8B%A4%EC%8B%9C%20%ED%95%99%EC%8A%B5%ED%95%98%EA%B3%A0%20%EC%8B%B6%EC%96%B4%20%26ndash%3B%20Kanana-2%20%EA%B0%9C%EB%B0%9C%EA%B8%B0%28%7Eing%29_.pdf?attach=1&amp;amp;knm=tfile.pdf&quot; class=&quot;&quot;&gt;
    &lt;div class=&quot;image&quot;&gt;&lt;/div&gt;
    &lt;div class=&quot;desc&quot;&gt;&lt;div class=&quot;filename&quot;&gt;&lt;span class=&quot;name&quot;&gt;01.LLM은 있지만 다시 학습하고 싶어 &amp;amp;ndash; Kanana-2 개발기(~ing)_.pdf&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;size&quot;&gt;4.55MB&lt;/div&gt;
&lt;/div&gt;
  &lt;/a&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;데이터는 없지만 LLM은 학습하고 싶어 - Code/Math 데이터 개발기 &lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;center&gt;&lt;iframe src=&quot;https://www.youtube-nocookie.com/embed/cL_UjE38_8Q?si=Og9JTkusnmRTpCNC&quot; width=&quot;560&quot; height=&quot;315&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;&lt;/center&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;대규모 고품질 데이터의 병목을 해결한 방법이 인상적이었습니다. 코드 쪽은 리포지토리 건강도 지표(스타, 최근 커밋, CI 상태), 라이선스, 중복률, 실행 성공률로 필터링하고, 파서 기반 토큰화&amp;middot;AST 정규화&amp;middot;주석 노이즈 처리로 학습 친화도를 올렸습니다. 수학 쪽은 OCR 파이프라인에 수식 렌더 복구, 표 구조 복원, 레이아웃 프롬프트 힌트 삽입을 추가해 망가진 수식을 되살렸습니다. 약지도(weak supervision)는 규칙&amp;middot;LLM 보조 라벨러&amp;middot;휴리스틱을 섞어 품질을 끌어올렸고, 샘플 난이도 스코어로 커리큘럼을 구성해 초반에는 기초, 후반에는 복합 추론&amp;middot;증명류를 강화했습니다. 이런 데이터 공학 덕분에 코드 생성&amp;middot;테스트 통과율, 수학 태스크의 연쇄추론 안정성이 체감적으로 향상되었다는 점이 설득력 있었습니다. &lt;/span&gt;&lt;/p&gt;
&lt;figure class=&quot;fileblock&quot; data-ke-align=&quot;alignCenter&quot;&gt;&lt;a href=&quot;https://blog.kakaocdn.net/dn/cIBQ1j/dJMb9Om5hTv/say6lrppuDigcC9Ku34mL1/02.%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%8A%94%20%EC%97%86%EC%A7%80%EB%A7%8C%20LLM%EC%9D%80%20%ED%95%99%EC%8A%B5%ED%95%98%EA%B3%A0%20%EC%8B%B6%EC%96%B4%20-%20Code%2C%20Math%20%EB%8D%B0%EC%9D%B4%ED%84%B0%20%EA%B0%9C%EB%B0%9C%EA%B8%B0.pdf?attach=1&amp;amp;knm=tfile.pdf&quot; class=&quot;&quot;&gt;
    &lt;div class=&quot;image&quot;&gt;&lt;/div&gt;
    &lt;div class=&quot;desc&quot;&gt;&lt;div class=&quot;filename&quot;&gt;&lt;span class=&quot;name&quot;&gt;02.데이터는 없지만 LLM은 학습하고 싶어 - Code, Math 데이터 개발기.pdf&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;size&quot;&gt;3.07MB&lt;/div&gt;
&lt;/div&gt;
  &lt;/a&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;LLM은 있지만 컨텍스트가 짧아 - Long Context 실전 적용기 &lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;center&gt;&lt;iframe src=&quot;https://www.youtube-nocookie.com/embed/mFHjPLa_d-4?si=eSCzdDaxHLiDuwoU&quot; width=&quot;560&quot; height=&quot;315&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;&lt;/center&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;여기서는 윈도 크기 숫자보다 운영 노하우가 핵심이었습니다. 포지셔널 임베딩은 RoPE 스케일링, YaRN/LongRoPE 계열 변형을 태스크별로 A/B했고, 긴 맥락에서 앞&amp;middot;뒤 정보 편향을 줄이기 위해 섹션 앵커 토큰과 헤더 힌트를 넣어 검색 부담을 낮췄습니다. 모델을 건드리지 않는 방법으로는 검색 강화(RAG)와 계층 요약을 조합해 비용을 통제했고, 생성 단계에서는 plan-then-answer 전략과 끊김 없는 스트리밍을 적용했습니다. 평가도 단순 F1이 아니라 위치 민감도(정답 위치 오프셋), 기억 지속성, 긴 대화 drift 여부, 실사용 로그 재현률까지 포함해 다면적으로 봤다는 점이 좋았습니다. 결론은 롱컨은 모델&amp;middot;프롬프트&amp;middot;인덱싱&amp;middot;평가를 하나의 세트로 운영해야 실무에 녹아든다는 것이었습니다. &lt;/span&gt;&lt;/p&gt;
&lt;figure class=&quot;fileblock&quot; data-ke-align=&quot;alignCenter&quot;&gt;&lt;a href=&quot;https://blog.kakaocdn.net/dn/bWrBUM/dJMb9MbJp2s/kZAtSiPHd9uKNN5RB3tIH1/03.LLM%EC%9D%80%20%EC%9E%88%EC%A7%80%EB%A7%8C%20%EC%BB%A8%ED%85%8D%EC%8A%A4%ED%8A%B8%EA%B0%80%20%EC%A7%A7%EC%95%84%20-%20Long%20Context%20%EC%8B%A4%EC%A0%84%20%EC%A0%81%EC%9A%A9%EA%B8%B0.pdf?attach=1&amp;amp;knm=tfile.pdf&quot; class=&quot;&quot;&gt;
    &lt;div class=&quot;image&quot;&gt;&lt;/div&gt;
    &lt;div class=&quot;desc&quot;&gt;&lt;div class=&quot;filename&quot;&gt;&lt;span class=&quot;name&quot;&gt;03.LLM은 있지만 컨텍스트가 짧아 - Long Context 실전 적용기.pdf&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;size&quot;&gt;5.46MB&lt;/div&gt;
&lt;/div&gt;
  &lt;/a&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;눈으로 보고, 귀로 듣고, 입으로 말하는 AI - 통합 멀티모달 언어모델 Kanana-o &lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;center&gt;&lt;iframe src=&quot;https://www.youtube-nocookie.com/embed/S4CMtHfscis?si=1zoop8yz1V-3j27d&quot; width=&quot;560&quot; height=&quot;315&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;&lt;/center&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Kanana-o는 비전 인코더와 오디오 인코더를 언어모델에 적절한 어댑터를 통해 연결한 후, 멀티모달 지시튜닝과 선호정렬을 거쳐 완성된 통합 모델입니다. 이미지 쪽은 문서&amp;middot;UI&amp;middot;차트 같은 구조화 시각물에 강점이 보였고, 오디오 쪽은 스트리밍 ASR과 감정 포함 TTS, 턴테이킹 제어(VAD/바이브 모니터링)로 대화 자연스러움을 끌어올렸습니다. 데모에서 감정 음성 합성, 팟캐스트 스타일 대화 생성, 실시간 통역이 매끄럽게 돌아갔고, 한국어 멀티모달 태스크에서 강한 모습을 보였습니다. 실무 관점의 포인트는 입력 동기화와 지연 관리였습니다. 프레임 드롭 시 보수적 응답으로 전환, 비동기 모달의 타임스탬프 정합, 오디오-텍스트 상호검증으로 오류 전파를 줄이는 운영 팁이 유용했습니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;화면을 이해하고 행동하는 AI - GUI Agent 개발기 &lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;center&gt;&lt;iframe src=&quot;https://www.youtube-nocookie.com/embed/k-8CFgBhhu4?si=w_ZYDF4FzOBtZgBv&quot; width=&quot;560&quot; height=&quot;315&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;&lt;/center&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;GUI Agent는 스크린샷&amp;middot;태스크 목표&amp;middot;액션 히스토리를 입력으로 받아, VLM이 UI 요소를 인지하고, 액션 파서가 click/type/drag/submit 같은 원자 행위를 생성하며, 실행기가 실제 브라우저나 앱을 조작하는 구조였습니다. 한국어 웹 데이터 부족을 자동 생성과 수작업 로그 수집으로 메웠고, 좌표 체계는 해상도 의존을 줄이기 위해 상대 좌표와 텍스트 앵커 바인딩을 병행했습니다. Heatmap 기반 손실로 정답 주변 허용 오차를 주어 실제 클릭 성공률을 끌어올린 점, 실패 로그를 원인별로 분류해 데이터 재주입 루프를 돌린 점이 눈에 띄었습니다. 벤치마크 시나리오는 예약&amp;middot;결제&amp;middot;민원&amp;middot;검색 중심으로 구성되어 현실성이 있었고, 프롬프트와 정책의 결합으로 계획 오류를 줄이는 방식이 효과적이었습니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;카카오톡 AI 에이전트를 위한 온디바이스 모델 최적화 및 적용 &lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;center&gt;&lt;iframe src=&quot;https://www.youtube-nocookie.com/embed/8ggESRKrfZ4?si=IkL41oe8U-k8RayJ&quot; width=&quot;560&quot; height=&quot;315&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;&lt;/center&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;온디바이스는 개인정보 보호, 지연&amp;middot;비용 절감을 위해 필연적인 선택이었습니다. 모델은 1-3B급 소형 모델을 기본으로 하고, 4/8비트 양자화로 메모리 발자국을 줄였습니다. iOS에서는 MLX와 CoreML을 혼용하고, GPU와 ANE를 태스크 특성에 따라 스위칭했습니다. 초기 컴파일 지연을 줄이기 위한 캐시 전략, KV 캐시 조각화 방지, 토크나이저 병렬화와 스트리밍 출력이 실사용 체감에 크게 기여했습니다. 전력&amp;middot;발열 대응으로는 토큰 초당 목표치에 맞춘 다이내믹 디코딩(탑K/탑P/온도)을 적용했고, 휴면 복귀 시 빠른 컨텍스트 재주입을 위한 메모리 맵핑을 사용했습니다. 중요한 교훈은 큰 모델의 과도한 압축보다 설계 단계에서 작은 모델을 제대로 선택&amp;middot;튜닝하는 쪽이 최적의 사용자 경험을 준다는 점이었습니다.&lt;/span&gt;&lt;/p&gt;
&lt;figure class=&quot;fileblock&quot; data-ke-align=&quot;alignCenter&quot;&gt;&lt;a href=&quot;https://blog.kakaocdn.net/dn/bqYmYz/dJMb9Om5hUX/m78LWt6O0NbtpwKTxdw3J1/06.%EC%B9%B4%EC%B9%B4%EC%98%A4%ED%86%A1%20AI%20%EC%97%90%EC%9D%B4%EC%A0%84%ED%8A%B8%EB%A5%BC%20%EC%9C%84%ED%95%9C%20%EC%98%A8%EB%94%94%EB%B0%94%EC%9D%B4%EC%8A%A4%20%EB%AA%A8%EB%8D%B8%20%EC%B5%9C%EC%A0%81%ED%99%94%20%EB%B0%8F%20%EC%A0%81%EC%9A%A9.pdf?attach=1&amp;amp;knm=tfile.pdf&quot; class=&quot;&quot;&gt;
    &lt;div class=&quot;image&quot;&gt;&lt;/div&gt;
    &lt;div class=&quot;desc&quot;&gt;&lt;div class=&quot;filename&quot;&gt;&lt;span class=&quot;name&quot;&gt;06.카카오톡 AI 에이전트를 위한 온디바이스 모델 최적화 및 적용.pdf&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;size&quot;&gt;2.23MB&lt;/div&gt;
&lt;/div&gt;
  &lt;/a&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;행사종료 및 귀경&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;모든 일정이 끝난 뒤 오전 하차 지점에서 강남역행 셔틀을 탔습니다. 퇴근 시간 정체로 오전보다 두배 이상 걸렸고 비도 내려 근처 국수집에서 간단히 저녁을 해결했습니다. 이 후 2호선과 수인분당선으로 환승해 수서역으로 이동했고 SRT를 탑승하여 울산을 내려와 하루를 마무리했습니다. 장거리 일정이라 피곤했지만 머릿 속은 새로운 아이디어로 가득했습니다.&lt;/span&gt;&lt;/p&gt;
&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/0W8xa/btsQQ1VWIQg/bA7kzJjpEtk11bKQFxcKRk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/0W8xa/btsQQ1VWIQg/bA7kzJjpEtk11bKQFxcKRk/img.png&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot; data-filename=&quot;blob&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/0W8xa/btsQQ1VWIQg/bA7kzJjpEtk11bKQFxcKRk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F0W8xa%2FbtsQQ1VWIQg%2FbA7kzJjpEtk11bKQFxcKRk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b9nHyJ/btsQUjtpqjX/Ctj240bZzRsAkzLWZgeeZ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b9nHyJ/btsQUjtpqjX/Ctj240bZzRsAkzLWZgeeZ1/img.png&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot; data-filename=&quot;blob&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.4186%;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b9nHyJ/btsQUjtpqjX/Ctj240bZzRsAkzLWZgeeZ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb9nHyJ%2FbtsQUjtpqjX%2FCtj240bZzRsAkzLWZgeeZ1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/erktmK/btsQSOAT6Ku/xUPficBGx7JBHGoi8BC4Q0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/erktmK/btsQSOAT6Ku/xUPficBGx7JBHGoi8BC4Q0/img.png&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot; data-filename=&quot;blob&quot; data-is-animation=&quot;false&quot; style=&quot;width: 42.1561%; margin-right: 10px; margin-top: 10px;&quot; data-widthpercent=&quot;43.16&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/erktmK/btsQSOAT6Ku/xUPficBGx7JBHGoi8BC4Q0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FerktmK%2FbtsQSOAT6Ku%2FxUPficBGx7JBHGoi8BC4Q0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/SMXrE/btsQTRqnCSF/3nItK9MbeEgnsSthP23PK1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/SMXrE/btsQTRqnCSF/3nItK9MbeEgnsSthP23PK1/img.png&quot; data-origin-width=&quot;1689&quot; data-origin-height=&quot;3000&quot; data-filename=&quot;blob&quot; data-is-animation=&quot;false&quot; style=&quot;width: 13.3622%; margin-right: 10px; margin-top: 10px;&quot; data-widthpercent=&quot;13.68&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/SMXrE/btsQTRqnCSF/3nItK9MbeEgnsSthP23PK1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FSMXrE%2FbtsQTRqnCSF%2F3nItK9MbeEgnsSthP23PK1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1689&quot; height=&quot;3000&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/doKaS7/btsQQVBoeed/Bmf76s3PCZdIMZNGzYPtVk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/doKaS7/btsQQVBoeed/Bmf76s3PCZdIMZNGzYPtVk/img.png&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot; data-filename=&quot;blob&quot; data-is-animation=&quot;false&quot; style=&quot;width: 42.1561%; margin-top: 10px;&quot; data-widthpercent=&quot;43.16&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/doKaS7/btsQQVBoeed/Bmf76s3PCZdIMZNGzYPtVk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdoKaS7%2FbtsQQVBoeed%2FBmf76s3PCZdIMZNGzYPtVk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;

&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;마무리&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;if(kakao)25는 기술 쇼케이스를 넘어 실서비스에 AI를 녹여내는 운영 지혜를 배울 수 있는 자리였습니다. 데이터 엔지니어링, 모델 구조, 정렬, 롱컨 운영, 멀티모달 통합, GUI 에이전트, 온디바이스 최적화까지 전 과정을 한번에 조망할 수 있었습니다. 무엇보다도 각 팀이 성능 수치만이 아닌 회귀 방지, 안정성, 지연 비용, 안전같은 현실 지표를 동등하게 관리한다는 점이 크게 와 닿았습니다. 개발자로써 현업에 바로 가져다 쓸 수 있는 힌트를 많이 얻었습니다. 내년에도 기회가 된다면 다시 참여하고 싶습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;s&gt;(카카오톡 업데이트로 많은 이야기가 있어서 업데이트를 일부러 해봤습니다. 아직 적응이 안된 것때문에 불편한 것인지.. UI가 메신저가 아닌 인스타그램화 되어있는 것이 불편하고 왜 숏폼을 메신저에서 봐야하는지 이해도 안되는데... 여러분은 사용하실만한가요?)&lt;/s&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;script&gt;

(function(){
  document.querySelectorAll('iframe').forEach(function(f){
    var src = (f.getAttribute('src')||'').toLowerCase();
    var isYT = src.includes('youtube.com') || src.includes('youtu.be');
    var isMap = src.includes('maps.google') || src.includes('map.kakao') || src.includes('vworld');
    if(!(isYT||isMap)) return;
    if(f.closest('.media-wrap')) return;
    var wrap = document.createElement('div');
    wrap.className='media-wrap';
    f.parentNode.insertBefore(wrap, f);
    wrap.appendChild(f);
    f.setAttribute('loading','lazy');
    f.setAttribute('referrerpolicy','strict-origin-when-cross-origin');
    f.setAttribute('title', f.getAttribute('title') || (isYT ? 'YouTube video' : 'Map'));
    if(isYT &amp;&amp; !src.includes('mute=1')){
      var url = new URL(f.src);
      url.searchParams.set('mute','1');
      f.src = url.toString();
    }
  });

  document.querySelectorAll('.devconf-article a[href^=&quot;http&quot;]').forEach(function(a){
    a.rel = 'noopener noreferrer';
    if(!a.target) a.target = '_blank';
  });

  var heads = document.querySelectorAll(&quot;.tt_article_useless_p_margin h2, .tt_article_useless_p_margin h3&quot;);
  heads.forEach(function(h){
    if(!h.id){
      h.id = &quot;h-&quot; + h.textContent.trim().replace(/\s+/g,&quot;-&quot;).replace(/[^\w\-가-힣]/g,&quot;&quot;).toLowerCase();
    }
    if(!h.querySelector('.dev-anchor')){
      var a = document.createElement('a');
      a.href = &quot;#&quot;+h.id; a.className=&quot;dev-anchor&quot;; a.title=&quot;이 제목 링크&quot;;
      a.textContent = &quot;#&quot;;
      h.appendChild(a);
    }
  });

  document.querySelectorAll('.tt_article_useless_p_margin').forEach(function(scope){
    var html = scope.innerHTML;
    scope.innerHTML = html.replace(/\[##_File\|([^\|]+)\|([^\|]+)\|_##\]/g, function(_, url, meta){
      // meta 예: filename=&quot;xxx.pdf&quot; size=&quot;4.55MB&quot; data-ke-align=&quot;alignCenter&quot;
      var filename = (meta.match(/filename=&quot;([^&quot;]+)&quot;/)||[])[1] || 'attachment';
      var size = (meta.match(/size=&quot;([^&quot;]+)&quot;/)||[])[1] || '';
      var align = (meta.match(/data-ke-align=&quot;([^&quot;]+)&quot;/)||[])[1] || '';
      var alignCls = align==='alignCenter' ? ' style=&quot;justify-content:center&quot;' : '';
      return '&lt;div class=&quot;dev-file&quot;'+alignCls+'&gt;' +
             '&lt;span class=&quot;dev-file-ic&quot;&gt;PDF&lt;/span&gt;' +
             '&lt;div&gt;&lt;a href=&quot;'+url+'&quot; download&gt;'+filename+'&lt;/a&gt;&lt;br&gt;&lt;small&gt;'+ (size ? size : '') +'&lt;/small&gt;&lt;/div&gt;' +
             '&lt;/div&gt;';
    });
  });
})();
&lt;/script&gt;
&lt;script&gt;
(function(){
  var toc = document.querySelector('.dev-toc');
  if(!toc) return;

  var last = window.scrollY;
  var checkSticky = function(){
    var rect = toc.getBoundingClientRect();
    var shouldFix = rect.top &lt; 0 &amp;&amp; window.innerWidth &gt; 1024;
    toc.classList.toggle('is-fixed', shouldFix);
  };
  window.addEventListener('scroll', checkSticky, {passive:true});
  window.addEventListener('resize', checkSticky);
  checkSticky();
})();
&lt;/script&gt;
&lt;script&gt;
(function(){
  var scope = document.querySelector('.tt_article_useless_p_margin');
  if(!scope) return;

  scope.querySelectorAll('h1,h2,h3,h4').forEach(function(h){
    var txt = (h.textContent || &quot;&quot;).replace(/\u00a0/g,' ').trim(); // nbsp 제거
    if(!txt){ h.remove(); }
  });

  scope.querySelectorAll('h2,h3').forEach(function(h){
    if(!h.id){
      h.id = &quot;h-&quot; + h.textContent.trim().replace(/\s+/g,&quot;-&quot;).replace(/[^\w\-가-힣]/g,&quot;&quot;).toLowerCase();
    }
    if(!h.querySelector('.dev-anchor')){
      var a = document.createElement('a');
      a.href = &quot;#&quot;+h.id; a.className=&quot;dev-anchor&quot;; a.title=&quot;이 제목 링크&quot;;
      a.textContent = &quot;#&quot;;
      h.appendChild(a);
    }
  });

  if (window.jQuery &amp;&amp; jQuery.fn.toc){
    jQuery(&quot;#toc&quot;).empty().toc({
      content: &quot;.tt_article_useless_p_margin&quot;,
      headings: &quot;h1,h2,h3,h4&quot;,
      top: -90,
      isBlink : true,
      blinkColor : '#21B9DE'
    });
  }
})();
&lt;/script&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;</description>
      <category>IT</category>
      <category>aiagent</category>
      <category>AI컨퍼런스</category>
      <category>IF카카오25</category>
      <category>LLM</category>
      <category>개발자</category>
      <category>온디바이스AI</category>
      <category>이프카카오25</category>
      <category>참가후</category>
      <category>카카오</category>
      <category>카카오ai</category>
      <author>간지뽕빨리턴님</author>
      <guid isPermaLink="true">https://odinbox.tistory.com/552</guid>
      <comments>https://odinbox.tistory.com/552#entry552comment</comments>
      <pubDate>Sun, 28 Sep 2025 07:05:50 +0900</pubDate>
    </item>
    <item>
      <title>SQL JOIN문법, 데이터베이스(DB) 테이블 결합의 모든 것</title>
      <link>https://odinbox.tistory.com/551</link>
      <description>&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;JOIN 종류 이해, 개념의 차이를 정리해 봅니다.&lt;/span&gt;&lt;/p&gt;
&lt;div class=&quot;txc-textbox&quot; style=&quot;font-weight: normal; position: relative; line-height: 40px; background: #007CBA; border: 1px solid #fff; padding: 10px; color: white; border-radius: 0 10px 0 10px; box-shadow: inset 0 0 5px rgba(53,86,129, 0.5); font-family: 'Muli', sans-serif; border-style: solid; border-width: 0px  0px  1px 15px; border-color: #232323; background-color: #007cba;&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-size: 15pt; color: #ffffff;&quot;&gt;&lt;b&gt;헷갈리는 JOIN 한번 정리해 봅시다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;글 상단 부분 대표 이미지.png&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bIELNc/btsQI4XQ0IJ/XFD7IMo1BhjSDma8K7KeZK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bIELNc/btsQI4XQ0IJ/XFD7IMo1BhjSDma8K7KeZK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bIELNc/btsQI4XQ0IJ/XFD7IMo1BhjSDma8K7KeZK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbIELNc%2FbtsQI4XQ0IJ%2FXFD7IMo1BhjSDma8K7KeZK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;400&quot; data-filename=&quot;글 상단 부분 대표 이미지.png&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;관계형 데이터베이스에서는 정보가 여러 테이블로 정규화되어 나눠어 저장됩니다. 예를 들어 직원 정보와 부서 정보를 별도 테이블에 분리해 두는 경우 필요한 데이터를 한 곳에서 조회하려면 테이블을 조인해야 합니다. JOIN은 데이터베이스 내 여러 테이블의 레코드를 조합하여 하나의 결과 집합으로 표현해 주는 SQL 구문으로 두 테이블 간 공통 필드의 값을 기준으로 행들을 연결합니다. 이를 통해 마치 하나의 테이블에 있던 것처럼 데이터를 결합하여 활용할 수 있습니다. SQL 표준에 따르면 JOIN에는 여러 종류가 있지만 주로 사용하는 것은 INNER JOIN, LEFT JOIN, FULL OUTER JOIN 네 가지입니다. 각 JOIN은 포함하는 데이터 범위에 차이가 있으므로 용도에 맞게 올바른 JOIN을 선택하는 것이 중요합니다.&lt;/span&gt;&lt;/p&gt;
&lt;div class=&quot;txc-textbox&quot; style=&quot;border-style: solid; font-weight: bold; border-width: 1px  1px  1px 5px; border-color: #707070; background-color: #fff; padding: 10px;&quot;&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;https://tistory3.daumcdn.net/tistory/1569230/skin/images/jquery.toc.js&quot;&gt;&lt;/script&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;목차&lt;/p&gt;
&lt;ul id=&quot;toc&quot; style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;&lt;/ul&gt;
&lt;script type=&quot;text/javascript&quot;&gt;
$(function(){
	$(&quot;#toc&quot;).toc( {content: &quot;.tt_article_useless_p_margin&quot;, headings: &quot;h1,h2,h3,h4&quot; , top: -90, isBlink : true, blinkColor : '#21B9DE' } ) });
&lt;/script&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;SQL JOIN&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span&gt;예시(테이블 생성)&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1758389169773&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 직원 테이블 생성
CREATE TABLE Employee (
    EmpID INT PRIMARY KEY,
    EmpName VARCHAR(50),
    BirthYear INT,
    DeptID INT
);

-- 부서 테이블 생성
CREATE TABLE Department (
    DeptID INT PRIMARY KEY,
    DeptName VARCHAR(50)
);

-- 직원 데이터 입력
INSERT INTO Employee (EmpID, EmpName, BirthYear, DeptID) VALUES
(1, '최영환', 1994, 30),
(2, '홍길동', 1950, 20),
(3, '신형만', 1983, 15);

-- 부서 데이터 입력
INSERT INTO Department (DeptID, DeptName) VALUES
(30, '솔루션개발'),
(20, '경영지원'),
(15, 'DX사업부'),
(40, '스마트팩토리'); -- 직원 없는 부서&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;INNER JOIN(내부 조인) - 교집합 조회&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1212&quot; data-origin-height=&quot;733&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cPUq6T/btsQGrmM5V7/EXOHWVGoak6fRKNMk0dEbK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cPUq6T/btsQGrmM5V7/EXOHWVGoak6fRKNMk0dEbK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cPUq6T/btsQGrmM5V7/EXOHWVGoak6fRKNMk0dEbK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcPUq6T%2FbtsQGrmM5V7%2FEXOHWVGoak6fRKNMk0dEbK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1212&quot; height=&quot;733&quot; data-origin-width=&quot;1212&quot; data-origin-height=&quot;733&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;INNER JOIN은 두 테이블에서 공통으로 일치하는 레코드만 결합하여 반환합니다. 조건에 양쪽 모두 존재하는 데이터만 결과에 포함되기 때문에, 어느 한쪽에만 존재하는 데이터는 빠지게 됩니다. 일반적으로 JOIN 키워드만 사용한 경우 기본적으로 INNER JOIN으로 동작하며, 가장 흔히 사용되는 조인 방식입니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;예를 들어 직원(Employee) 테이블과 부서(Department) 테이블을 Employee.DepartmentID와 Department.DepartmentID를 기준으로 INNER JOIN 하면, 부서가 할당된 직원들만 조회됩니다. 부서가 없는 직원이나, 직원이 한 명도 없는 부서는 결과에 포함되지 않습니다. 즉, 양측 모두에 존재하는 교집합 데이터만 얻을 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;예시&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1758389227627&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT e.EmpName, e.BirthYear, d.DeptName
FROM Employee e
INNER JOIN Department d
    ON e.DeptID = d.DeptID;

-- 결과 : 모든 직원이 실제 부서와 연결되므로 3명 전부 표시됨, 직원이 없는 스마트팩토리는 제외됨.&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;LEFT JOIN (좌측 조인) &amp;ndash; 왼쪽 테이블 모두 포함&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1212&quot; data-origin-height=&quot;733&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/luYWf/btsQIKyxCzF/VKt5Jy2zKNRdZ9fvrjFcqK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/luYWf/btsQIKyxCzF/VKt5Jy2zKNRdZ9fvrjFcqK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/luYWf/btsQIKyxCzF/VKt5Jy2zKNRdZ9fvrjFcqK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FluYWf%2FbtsQIKyxCzF%2FVKt5Jy2zKNRdZ9fvrjFcqK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1212&quot; height=&quot;733&quot; data-origin-width=&quot;1212&quot; data-origin-height=&quot;733&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;LEFT JOIN은 왼쪽 테이블의 모든 행을 결과에 유지하면서, 오른쪽 테이블에서 일치하는 행을 결합합니다. 만약 오른쪽에 대응되는 값이 없다면 해당 부분은 NULL로 채워진 채 결과에 포함됩니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;직원(Employee) 테이블을 왼쪽으로 두고 부서(Department) 테이블과 LEFT JOIN 하면, 모든 직원이 결과에 나타납니다. 부서가 있는 직원은 부서명이 표시되고, 부서가 없는 직원도 결과에 나오지만 부서명이 NULL로 표시됩니다. 반대로 직원이 없는 부서는 결과에 나타나지 않습니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;LEFT JOIN은 주요 데이터 세트(왼쪽)의 손실 없이 부가 정보를 합칠 때 많이 사용됩니다. 또한 NULL을 활용해 &quot;어느 쪽에는 있지만 다른 쪽에는 없는 데이터&quot;를 쉽게 찾을 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;예시&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1758389289186&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT e.EmpName, e.BirthYear, d.DeptName
FROM Employee e
LEFT JOIN Department d
    ON e.DeptID = d.DeptID;

-- 결과 : 모든 직원 표시, 부서 없는 직원이 있었다면, NULL로 나옴, 하지만 현재는 다 매칭됨.&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;RIGHT JOIN (우측 조인) &amp;ndash; 오른쪽 테이블 모두 포함&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1213&quot; data-origin-height=&quot;733&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xgOVW/btsQHTP9MaZ/rInr9AURJlQNhbyzUj6WU1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xgOVW/btsQHTP9MaZ/rInr9AURJlQNhbyzUj6WU1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xgOVW/btsQHTP9MaZ/rInr9AURJlQNhbyzUj6WU1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FxgOVW%2FbtsQHTP9MaZ%2FrInr9AURJlQNhbyzUj6WU1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1213&quot; height=&quot;733&quot; data-origin-width=&quot;1213&quot; data-origin-height=&quot;733&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;RIGHT JOIN은 LEFT JOIN과 반대로 오른쪽 테이블의 모든 행을 유지하면서, 왼쪽 테이블에서 일치하는 행을 결합합니다. 왼쪽에 대응되는 값이 없는 경우 NULL로 표시됩니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;부서(Department) 테이블을 오른쪽으로 두고 직원(Employee) 테이블과 RIGHT JOIN 하면, 모든 부서가 결과에 나타납니다. 직원이 없는 부서는 부서명이 표시되지만 직원 칼럼은 NULL로 나타납니다. 반대로 부서가 없는 직원은 결과에서 제외됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;RIGHT JOIN은 LEFT JOIN과 기능이 대칭적이지만, 대부분의 경우 LEFT JOIN으로 같은 결과를 얻을 수 있기 때문에 실무에서는 자주 쓰이지 않습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;예시&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1758389358448&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT e.EmpName, e.BirthYear, d.DeptName
FROM Employee e
RIGHT JOIN Department d
    ON e.DeptID = d.DeptID;

-- 결과 : 모든 부서 표시, 직원이 없는 스마트팩토리는 EmpName/BirthYear가 NULL로 나옴.&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;FULL OUTER JOIN (풀 아우터 조인) &amp;ndash; 전체 합집합 조회&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1214&quot; data-origin-height=&quot;733&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dBEnDA/btsQIWlf5BM/UbLULBFT2c6fkeKdNxuFe1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dBEnDA/btsQIWlf5BM/UbLULBFT2c6fkeKdNxuFe1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dBEnDA/btsQIWlf5BM/UbLULBFT2c6fkeKdNxuFe1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdBEnDA%2FbtsQIWlf5BM%2FUbLULBFT2c6fkeKdNxuFe1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1214&quot; height=&quot;733&quot; data-origin-width=&quot;1214&quot; data-origin-height=&quot;733&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;FULL OUTER JOIN은 왼쪽과 오른쪽 테이블의 모든 행을 모두 포함하여 결합하는 방식입니다. 교집합뿐 아니라 양쪽에만 존재하는 데이터까지 합쳐 보여줍니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;직원(Employee)과 부서(Department) 테이블을 FULL OUTER JOIN 하면, 모든 직원과 모든 부서가 결과에 포함됩니다. 부서가 없는 직원은 부서 칼럼이 NULL로, 직원이 없는 부서는 직원 컬럼이 NULL로 표시됩니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;단, 일부 DBMS(MySQL 등)는 FULL JOIN을 지원하지 않습니다. 이 경우 LEFT JOIN 결과와 RIGHT JOIN 결과를 UNION으로 합쳐서 동일한 효과를 낼 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;예시&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1758389440780&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT e.EmpName, e.BirthYear, d.DeptName
FROM Employee e
FULL OUTER JOIN Department d
    ON e.DeptID = d.DeptID;

-- 결과 : 직원 3명 + 부서 4개 모두 표시됨, 스마트팩토리는 직원 없음 그러므로 직원 컬럼 NULL
-- 만약 부서 없는 직원이 추가 되면 그 직원도 DeptName이 NULL로 나옴.&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;마무리&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;네 가지 JOIN을 간단히 요약하면 다음과 같습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;INNER JOIN&lt;/b&gt; &amp;ndash; 교집합. 양쪽에 모두 존재하는 데이터만 조회. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;LEFT JOIN&lt;/b&gt; &amp;ndash; 왼쪽 기준. 왼쪽 데이터는 모두 유지, 오른쪽에 없는 값은 NULL. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;RIGHT JOIN&lt;/b&gt; &amp;ndash; 오른쪽 기준. 오른쪽 데이터는 모두 유지, 왼쪽에 없는 값은 NULL. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;FULL OUTER JOIN&lt;/b&gt; &amp;ndash; 합집합. 양쪽 모든 데이터를 다 보여줌.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;추가 팁&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;조인 칼럼에 인덱스를 걸면 성능이 크게 향상됩니다. &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;너무 많은 테이블을 한 번에 조인하면 복잡해지고 성능 저하가 발생할 수 있으므로, 필요한 경우 뷰나 서브쿼리로 나누는 것이 좋습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;JOIN의 기본 원리를 이해하면 원하는 데이터를 빠뜨리지 않고 정확하게 조회할 수 있습니다. 상황에 맞는 JOIN을 선택하여 효율적인 데이터 결합을 해보세요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>DEVELOPMENT</category>
      <category>Full Outer Join</category>
      <category>INNER JOIN</category>
      <category>LEFT JOIN</category>
      <category>RIGHT JOIN</category>
      <category>SQL</category>
      <category>sql문법</category>
      <category>관계형데이터베이스</category>
      <category>데이터분석</category>
      <category>조인</category>
      <category>쿼리</category>
      <author>간지뽕빨리턴님</author>
      <guid isPermaLink="true">https://odinbox.tistory.com/551</guid>
      <comments>https://odinbox.tistory.com/551#entry551comment</comments>
      <pubDate>Sun, 21 Sep 2025 02:54:45 +0900</pubDate>
    </item>
    <item>
      <title>KT 소액결제 해킹 사건으로 본 펨토셀 유령 기지국의 위험</title>
      <link>https://odinbox.tistory.com/550</link>
      <description>&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;통신사 해킹, 개인정보는 언제 개인정보가 될 수 있는 건가요?&lt;/span&gt;&lt;/p&gt;
&lt;div class=&quot;txc-textbox&quot; style=&quot;font-weight: normal; position: relative; line-height: 40px; background: #007CBA; border: 1px solid #fff; padding: 10px; color: white; border-radius: 0 10px 0 10px; box-shadow: inset 0 0 5px rgba(53,86,129, 0.5); font-family: 'Muli', sans-serif; border-style: solid; border-width: 0px  0px  1px 15px; border-color: #232323; background-color: #007cba;&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-size: 15pt; color: #ffffff;&quot;&gt;&lt;b&gt;보이지 않는 위협, 유령기지국의 위험&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;글 상단 부분 대표 이미지 (1).png&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lVwzF/btsQzKLEIRn/w1BrMWBD6ZUevLlYZepRo0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lVwzF/btsQzKLEIRn/w1BrMWBD6ZUevLlYZepRo0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lVwzF/btsQzKLEIRn/w1BrMWBD6ZUevLlYZepRo0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlVwzF%2FbtsQzKLEIRn%2Fw1BrMWBD6ZUevLlYZepRo0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;400&quot; data-filename=&quot;글 상단 부분 대표 이미지 (1).png&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;지난 9월 KT 통신망 이용자들을 대상으로 한 대규모 무단 소액결제 해킹 사건이 발생하여 사회적으로 큰 파장을 일으켰습니다. 특히 이번 사건에서는 일반인에게 생소한 펨토셀(FEMTOCELL) 일명 초소형 기지국이 해킹 도구로 악용되었다는 점에서 주목받고 있습니다. 펨토셀은 원래 실내나 음영 지역의 통신 품질을 높이기 위해 사용하는 손바닥 크기의 소형 기지국 장치인데요 이번 사건에서는 이러한 펨토셀이 유령기지국(불법 가짜 기지국)의 형태로 이용되어 다수 피해자의 휴대폰이 속아 접속하도록 만들고 이를 통해 소액결제 인증 절차를 가로챈 정황이 드러났습니다.&lt;/p&gt;
&lt;div class=&quot;txc-textbox&quot; style=&quot;border-style: solid; font-weight: bold; border-width: 1px  1px  1px 5px; border-color: #707070; background-color: #fff; padding: 10px;&quot;&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;https://tistory3.daumcdn.net/tistory/1569230/skin/images/jquery.toc.js&quot;&gt;&lt;/script&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;목차&lt;/p&gt;
&lt;ul id=&quot;toc&quot; style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;&lt;/ul&gt;
&lt;script type=&quot;text/javascript&quot;&gt;
$(function(){
	$(&quot;#toc&quot;).toc( {content: &quot;.tt_article_useless_p_margin&quot;, headings: &quot;h1,h2,h3,h4&quot; , top: -90, isBlink : true, blinkColor : '#21B9DE' } ) });
&lt;/script&gt;
&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;KT 해킹(FEMTOCELL)&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;펨토셀(Femtocell)이란?&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;펨토셀은 이동통신사의 초소형 기지국 장비를 의미합니다. 일반 기지국보다 훨씬 소형이며 반경 수십 미터 이내의 좁은 범위에 이동통신 신호를 제공합니다. 주로 가정이나 소규모 사무실처럼 신호가 약한 장소의 음영지역 해소 및 트래픽 분산 목적으로 설치됩니다. 예컨대 지하나 건물 내부에서 휴대전화 신호가 약할 때 통신사가 제공한 펨토셀을 인터넷망에 연결해 두면 그 주변에서 휴대폰이 강한 신호로 통화와 데이터를 사용할 수 있게 해주는 것입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;펨토셀은 단순한 중계기(repeater)와 달리 자체적으로 이동통신 신호를 생성하여 인터넷을 통해 통신사의 코어망(core network)에 직접 연결되는 것이 특징입니다. 즉, 펨토셀에 접속한 휴대전화의 통화나 데이터는 펨토셀 -&amp;gt; 가정용 인터넷망 -&amp;gt; 통신사 코어망으로 전달되어 처리됩니다. 이렇게 하면 통신사는 대형 기지국을 늘리지 않고도 실내 커버리지를 개선하고 메인 망의 부하를 줄일 수 있는 장점이 있습니다. 원래 통신품질 향상을 위한 편리한 장치인 펨토셀이지만 보안이 취약할 경우 승인되지 않은 장비가 통신망에 접속하여 악용될 소지가 있다는 점이 이번 사건으로 드러났습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;사건 개요, KT 유령 기지국 소액결제 해킹&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;center&gt;&lt;iframe src=&quot;https://www.youtube-nocookie.com/embed/9MOhwpz2AsQ?si=9CNqKsE9MT9SaoAr&quot; width=&quot;560&quot; height=&quot;315&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;&lt;/center&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;2025년 8월 말부터 9월 초 사이 KT 통신망을 사용하는 일부 휴대폰 가입자들이 자신도 모르는 사이에 무단으로 소액결제가 이루어지는 피해가 발생했습니다. 예를 들어 모바일 상품권 구매나 선불 교통카드 충전 등의 소액결제가 본인 승인 없이 이뤄져 경찰에 신고된 것입니다. 첫 피해신고는 8월 27일경 접수되었으며 주로 서울 금천구, 영등포구, 경기 광명시 일대 등 특정지역에서 피해 사례가 집중됐습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;KT 내부 족사에 따르면 9월 11일까지 파악된 피해만 최소 278건에 약 1억 7천만 원의 금액이 본인 모르게 결제된 것으로 집계되었습니다. 이 사건은 오직 KT 망 이용자들에게서만 발생했으며 SKT나 LG U+ 등 다른 통신사 가입자 피해는 보고되지 않았습니다. KT는 9월 5일 새벽 자체 모니터링으로 이상 징후를 감지하고 해당 결제 트래픽을 차단했지만 초기에 이를 단순 스미싱 악성앱 감염으로 오인하여 사고 대응이 늦어졌습니다. 이후 9월 8일 네트워크 상에서 등록되지 않은 정체불명의 기지국 신호를 발견하고 나서야 비로소 해킹 정황을 인지 KISA(한국인터넷진흥원)에 사고를 공식 신고하게 되었습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;조사 결과 피해자들의 휴대폰이 한때 접속했던 특정 기지국 ID가 KT망에 등록된 적 없는 불법 기지국으로 확인되었습니다. 쉽게 말해 해커들이 합법적인 KT기지국인 척 위장한 유령 기지국을 운용하여 피해자 휴대폰을 자기 장비로 끌어들였던 것입니다. 해당 기지국 ID는 KT 네트워크 상에 존재하지 않는 번호였기에 의심을 샀고 KT는 이를 즉시 차단했습니다. 이러한 불법 초소형 기지국을 이용한 해킹 사건은 국내 최초로 기록되었으며 수법의 특이성과 치밀한 때문에 수사 당국과 보안 업계의 이목이 집중되었습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;펨토셀 해킹 수법, 어떻게 결제를 가로챘나?&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;그렇다면 해커들은 어떻게 펨토셀을 통해 남의 휴대폰 결제를 몰래 진행할 수 있었을까요? 현재까지 드러난 바를 종합했습니다.&lt;/span&gt;&lt;/p&gt;
&lt;center&gt;&lt;iframe src=&quot;https://www.youtube-nocookie.com/embed/9wMrHOVmpJo?si=eHRhUXucvmsMKnsy&quot; width=&quot;560&quot; height=&quot;315&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;&lt;/center&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;- IMSI 탈취 - 가입자 식별정보 가로채기&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;펨토셀에 접속한 휴대전화는 통신망에 등록하기 위해 단말 고유식별번호를 기지국에 전송합니다. LTE망의 경우 단말 전원을 껐다 켜거나 할 때 IMSI(International Mobile Subscribar Identity, 국제이동가입자식별번호)를 보내면, 네트워크가 이를 확인하고 임시 id인 GUTI를 발급하여 통신을 진행합니다. IMSI는 유심(USIM)에 내장된 가입자 고유 번호로 이동통신사가 가입자를 인식하는 데&amp;nbsp; 사용되는 중요한 개인정보입니다. 이번 사건에서 해커의 불법 기지국에 일단 휴대폰이 접속되면 IMSI 등의 가입자 정보가 해커 장비로 유출되는 상황이 발생했습니다. 실제로 약 1만 9천 명의 KT 고객이 한 때 이 유령 기지국 신호를 잡았고 이 중 5,561명은 IMSI가 유출되었을 가능성이 있다고 확인되었습니다. IMSI가 유출될 경우 해커는 그 정보를 이용해 통신 트래픽을 중간에서 가로채거나 사용자를 가장할 수 있기 때문에 매우 위험합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;한편 5G의 경우 보안을 강화하여 IMSI 대신 암호화된 식별자를 사용하기 때문에 이러한 공격에 비교적 안전하지만 이번 사고는 LTE망을 노렸기에 IMSI 노출이 이루어진 것으로 분석됩니다. IMSI를 탈취한 해커는 곧이어 해당 가입자 명의로 소액결제를 시도한 것으로 보입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1536&quot; data-origin-height=&quot;1024&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bdNdv3/btsQzwNsXKf/MihL4rqV6HIyweEQf9b04k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bdNdv3/btsQzwNsXKf/MihL4rqV6HIyweEQf9b04k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bdNdv3/btsQzwNsXKf/MihL4rqV6HIyweEQf9b04k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbdNdv3%2FbtsQzwNsXKf%2FMihL4rqV6HIyweEQf9b04k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;636&quot; height=&quot;424&quot; data-origin-width=&quot;1536&quot; data-origin-height=&quot;1024&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;- 가짜 기지국을 통한 인증 가로채기&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;모바일 소액결제를 진행하려면 보통 본인확인 절차로 휴대폰 명의자의 이름, 생년월일, 주민등록번호 일부 등을 입력하고 ARS 전화 인증 또는 SMS 인증을 거쳐야 합니다. 일반적인 상황에서는 사용자의 휴대폰으로 통신사 인증번호가 문자로 오거나 ARS 전화가 와서 본인이 직접 이를 확인/승인해야 결제가 완료됩니다. 그런데 해커는 유령기지국에 연결된 피해자 폰의 통신을 통제함으로써 인증 요청 전화나 문자를 가로채고 대신 승인 절차를 진행한 것으로 추정됩니다. 즉, 통신사망 입장에선 해당 휴대폰이 정상적으로 ARS 인증을 완료한 것처럼 보이게 만들어 결제를 승인시켰다는 시나리오입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;아직 구체적으로 해커가 ARS 인증을 어떤 방식으로 우회 했는지 명확히 밝혀지지 않았으며 수사 중인 부분입니다. ARS 인증 시 요구되는 개인정보(예 : 주민번호 등)는 펨토셀만으로는 알아낼 수 없기 때문에 해커가 사전에 유출된 개인정보 DB를 입수하여 사용했거나 내부 협조자가 있었는지 등의 가능성이 제기되고 있습니다. KT측도 &quot;미등록 장비가 코어망에 어떻게 접속했는지 또 소액결제가 어떤 메커니즘으로 이뤄졌는지 추가 조사를 필요하다&quot;라고 밝혔습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;- 통신장비 악용 - KT 기지국 장비 도용 의혹&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;한편 이번 사건의 유령 기지국 장비는 고가에 KT에서 실제 사용되던 펨토셀 장비가 유출되어 악용된 정황이 제기되었습니다. KT는 기자 브리핑에서 &quot;해당 불법 기지국이 기존에 KT망에 연결된 적이 있는 장비로 추정된다.&quot;라고 밝혔습니다. 현재 실물이 확보되지 않아 단정할 수 없지만 만약 과거에 쓰다 철거한 펨토셀 기기를 해커가 입수해 ID를 위조/도용했다면 통신망 인증을 쉽게 통과했을 가능성이 있습니다. 실제로 KT는 &quot;관리 시스템에 없는 장비는 개통되지 않도록 조치하고 있는데 이번 발견된 장비는 아마 철거 과정에서 ID가 삭제된 장비가 도용된 것 같다&quot;라고 설명했습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;다시 말해 해커가 통신사 관리망 바깥에 있는 펨토셀을 불법 개통시킨 것이 아니라 원래 KT망에 등록되었던 장비를 어떤 방식으로 다시 불법 활용했을 가능성이 높다는 것입니다. 이는 통신장비 관리의 허점을 노린 것으로 볼 수 있어 향후 유사 수법에 대한 대비의 필요성을 시사합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;드러난 피해와 보안상 문제점&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;이번 해킹을 통해 드러난 피해 규모와 보안 문제점은 다음과 같습니다.&lt;/span&gt;&lt;/p&gt;
&lt;center&gt;&lt;iframe src=&quot;https://www.youtube-nocookie.com/embed/x3nMzIL0oS8?si=U_rveP11WZ9CDmHl&quot; width=&quot;560&quot; height=&quot;315&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;&lt;/center&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;* 무단 소액결제 피해&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;앞서 언급했듯이 확인된 무단 결제 건수만 수백 건에 달합니다. 피해자들은 자신이 결제한 적 없는 상품권 구매 내역등을 통신요금 청구서나 결제 알림을 통해 뒤늦게 인지한 경우가 많았습니다. 다행히 KT는 피해금액 전액을 고객에게 청구하지 않기로 결정하여 피해자 부담은 없도록 조치했습니다. 그러나 해커들은 이 과정에서 실제 금전적인 이득을 취했을 가능성이 높습니다. 예를 들어 구매된 상품권이나 충전금은 해커가 되팔았을 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;* 개인정보(IMSI) 유출&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;5천여 명의 고객 IMSI가 노출되었을 가능성이 확인됨에 따라 이는 잠재적인 2차 피해 위협으로 이어집니다. IMSI 등 유심 정보가 유출되면 향후 동일 수법으로 통신 도청이나 추가 사기가 발생할 수 있으므로 해당 고객들은 유심 교체 및 보호서비스가 권고되고 있습니다. KT는 IMSI 노출 가능성이 있는 고객 전원에게 개별 안내를 보내어 희망 시 무상 유심 교체와 USIM 보안서비스를 제공하고 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;* 통신 인프라 보안 허점 노출&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;통신사들은 공식 승인된 기지국 장비만 자사 망에 접속되도록 관리해 왔지만 이번 사건으로 그 관리 체계의 허점이 드러났습니다. 폐기되었거나 권한이 말소된 장비가 다시 이용될 수 있었던 점, 그리고 일정기간 동안 통신사 내부에서 이를 탐지하지 못한 점은 보안적 개선이 필요한 부분입니다. 또한 기지국 인증과 통신 프로토콜 측면에서의 취약점도 지적됩니다. 예를 들어 휴대폰이 기지국을 선택할 때 신호 세기가 강하면 일단 접속하도록 설계된 구조상 해커는 합법 기지국 신호를 교란하거나 더 강한 신호로 유인하여 쉽게 단말을 가로챌 수 있었습니다. 더구나 4G LTE에서는 IMSI가 평문으로 노출되는 과정이 있었는데 이는 이전부터 IMSI 캐처(Stingray)등으로 악용 가능성이 제기되어 온 부분입니다. 실제로 2013년 Black Hat 해커 컨퍼런스에서도 연구자들이 해킹된 펨토셀을 사용해 인근 휴대폰의 음성통화, 문자, 인터넷 트래픽을 모두 도청 및 기록해 보이는 시연을 한 바 있습니다. 이처럼 가짜 기지국 공격은 해외에서는 이미 알려진 기법이며 우리나라에서도 현실화된 첫 사례가 발생한 것입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;대응 조치 및 재발 방지 대책&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;사고 발생 후 정부와 KT를 비릇한 통신업계는 급히 대응 조치에 나섰습니다. 우선 과학기술정보통신부는 해당 사안을 중대한 통신망 침해사고로 보고 민, 관 합동조사단을 구성하였습니다. 또한 타 통신사들에게도 자사망에 유령 기지국이 존재하는지 긴급점검하도록 지시했고, SKT와 LG유플러스는 자체 점검 결과 이상이 없음을 보고했습니다. 고가기정통부는 만일 유사 피해가 발생할 경우 통신사가 피해금액을&amp;nbsp; 고객에게 청구하지 않도록 사전에 조치하라고 요청하였고 모든 통신사가 이를 수용한 상태입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;KT는 고객 대상 사과와 함께 다양한 보호 대책을 발표했습니다. 우선 이상 패턴의 소액결제 시도를 실시간 감지하여 자동 차단하고 결제 시 추가 본인확인(예 : ARS 비밀번호, 생체인증)을 거치도록 2차 인증을 강화했다고 밝혔습니다. 또한 피해 고객에 대한 전액 보상은 물론, 원인규명과 재발 방지를 위한 투자와 보안 인력 확충에 힘쓰겠다고 발표했습니다. 피해 공지가 부족했다는 지적에 따라 마이KT 앱과 웹사이트에 공지사항을 게시하고 고객이 직접 본인의 IMSI 유출 여부를 조회할 수 있는 기능도 제공했습니다.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;초소형 기지국 관리 강화도 중요한 과제로 떠올랐습니다. 정부는 통신 3사에 일시적으로 신규 펨토셀 장비의 망접속을 전면 제한하도록 지시하며 추가적인 의심기기 접속을 차단했습니다. 향후 소형 기지국 보안 기준을 재정립하고 불법 기지국의 망 접속 시도를 실시간 탐지, 차단하는 기술적 대책도 마련할 계획입니다. 더불어 개인정보보호위원회는 이번 사태를 계기로 개인정보 안전관리 강화 방안을 발표하여 보안투자를 소홀히 한 기업에 대한 제재 강화와 위반 기업에 대한 과징금으로 피해자 구제 등에 나서겠다고 밝혔습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;무엇보다 통신사들은 유사 사건 재발 방지를 위한 자사 관리 하에 운영되다 철거된 펨토셀 등 장비의 반출 및 폐기 절차를 엄격히 점검할 필요가 있습니다. 아울러 기지국 인증 시스템 상에서 사용 종료된 장치의 ID가 재사용되지 않도록 하고 비인가 기지국 탐지 시스템을 고도화해야 할 것입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;일반 이용자들을 위한 조언&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1536&quot; data-origin-height=&quot;1024&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/GtaEa/btsQymLBLYX/JU5ELRBTKLUfa6XRf556z0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/GtaEa/btsQymLBLYX/JU5ELRBTKLUfa6XRf556z0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GtaEa/btsQymLBLYX/JU5ELRBTKLUfa6XRf556z0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGtaEa%2FbtsQymLBLYX%2FJU5ELRBTKLUfa6XRf556z0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;400&quot; data-origin-width=&quot;1536&quot; data-origin-height=&quot;1024&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;이번 사건은 상당히 정교한 수법으로 진행되었기 때문에 일반 사용자가 개별적으로 예방하기는 어려운 측면이 있습니다. 그럼에도 불구하고 몇 가지 참고할만한 안전조치가 있습니다. 첫 번째는 휴대전화 소액결제를 평소 거의 사용하지 않는다면 통신사 고객센터나 앱을 통해 소액결제 한도를 0원으로 설정하거나 소액결제 차단/허용을 관리할 수 있도록 안내하고 있습니다. 실제로 KT는 이번 사고 이후 마이 KT앱에서 간편하게 소액결제 차단/허용을 관리할 수 있도록 안내하고 있습니다. 결제 수단을 원천봉인해 두면 설령 해커가 접근하더라도 결제를 시도할 수 없게 되므로 안심할 수 있습니다. 둘째,&amp;nbsp; 휴대폰에 갑자기 뜨는 이상한 기지국 명칭(평소와 다른 번호나 이름)이 확인되거나 평소 쓰던 4G/5G 데이터가 불통되고 2G로 표시되는 등 평소와 다른 통신 상태를 발견하면 주의가 필요합니다. 일본 사례에서는 해커의 차량이 나타나면 주변 휴대폰이 갑자기 2G로 전환되고 통신 장애가 발생했다고 합니다. 이러한 징후는 유령 기지국 개입 가능성을 의심해 볼 수 있으므로 반복된다면 통신사에 문의하거나 해당지역을 벗어나는 편이 안전할 수 있습니다. 셋째 본인 명의와 관련된 각종 개인정보 유출사고 소식에 관심을 가지고 주요 정보(주민번호, 통신가입정보 등)가 유출되었다는 소식을 들으면 필요한 경우 명의 도용 방지서비스나 신용정보 모니터링을 신청해 두는 것이 도움이 됩니다. 해커는 여러 경로로 얻은 정보들을 조합하여 범죄에 악용하기 때문에 내 정보가 유출된 적이 있는지 수시로 확인하는 습관이 중요합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;마무리&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;이번 KT 펨토셀 유령기지국 해킹사건은 첨단 통신 인프라의 허점을 노린 신종 수법으로서 우리에게 두 가지 교훈을 주었습니다. 하나는 편의를 위한 기술도 보안이 담보되지 않으면 양날의 검이 될 수 있다는 점입니다. 집 안 신호 개선을 위해 보급된 펨토셀이 오히려 해커의 수중에서 통신망을 장악하는 도구가 될 수 있었듯이 모든 ICT 기술에는 보안 강화는 필수적입니다. 둘째는 통신사와 정부의 신속한 대응체계 구축입니다. 이번 사건을 통해 관계 기관들은 비로소 유령기지국 공격이라는 현실화된 위협에 눈뜨게 되었습니다. 다행히 추가 피해를 막기 위한 조치들이 빠르게 취해졌고 피해보상과 재발 방지책이 마련되고 있지만 사후 대응보다 사전 예방과 상시 모니터링 강화가 더욱 중요할 것입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;일반 사용자 입장에서는 눈에 보이지 않는 통신망 해킹이 막연하고 두려울 수 있습니다. 그러나 한편으로는 이러한 사건을 계기로 통신사들의 보안 의식 높아지고 시스템이 개선되는 효과도 기대할 수 있습니다. 우리는 개인차원에서 보안수칙을 잘 지키고 이상 징후에 주의를 기울이는 한편 더 큰 틀에서는 통신 인프라 전반의 보안 수준 재고를 꾸준히 요구해야겠습니다. 유령기지국의 침입을 막아낼 탄탄한 망 보안 체계 구축이 이루어질 때 비로소 안심하고 편리한 통신서비스를 누릴 수 있을 것입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>IT</category>
      <category>ars인증</category>
      <category>IMSI</category>
      <category>소액결제</category>
      <category>유령기지국</category>
      <category>정보유출</category>
      <category>초소형기지국</category>
      <category>통신보안</category>
      <category>통신해킹</category>
      <category>펨토셀</category>
      <category>해킹사고</category>
      <author>간지뽕빨리턴님</author>
      <guid isPermaLink="true">https://odinbox.tistory.com/550</guid>
      <comments>https://odinbox.tistory.com/550#entry550comment</comments>
      <pubDate>Sat, 13 Sep 2025 20:23:58 +0900</pubDate>
    </item>
    <item>
      <title>개발자들의 웃픈 일상, 코드 짜며 웃고 우는 이야기</title>
      <link>https://odinbox.tistory.com/549</link>
      <description>&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&amp;ldquo;저는 HTML로 코딩하는 걸 제일 좋아합니다!&amp;rdquo;&lt;/span&gt;&lt;/p&gt;
&lt;div class=&quot;txc-textbox&quot; style=&quot;font-weight: normal; position: relative; line-height: 40px; background: #007CBA; border: 1px solid #fff; padding: 10px; color: white; border-radius: 0 10px 0 10px; box-shadow: inset 0 0 5px rgba(53,86,129, 0.5); font-family: 'Muli', sans-serif; border-style: solid; border-width: 0px  0px  1px 15px; border-color: #232323; background-color: #007cba;&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-size: 15pt; color: #ffffff;&quot;&gt;&lt;b&gt;개발자는 커피로 코딩한다, 웃픈 밈 모음 ZIP&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;글 상단 부분 대표 이미지.png&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bd4vhp/btsQfDM3vq9/c3iFZPIL8fLEvY4RNK3290/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bd4vhp/btsQfDM3vq9/c3iFZPIL8fLEvY4RNK3290/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bd4vhp/btsQfDM3vq9/c3iFZPIL8fLEvY4RNK3290/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbd4vhp%2FbtsQfDM3vq9%2Fc3iFZPIL8fLEvY4RNK3290%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;400&quot; data-filename=&quot;글 상단 부분 대표 이미지.png&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;개발자들은 왜 모니터 앞에서 혼자 피식피식 웃고 있을까요? 알고 보면 그 뒤엔 개발자만의 유머와 밈이 숨어 있습니다. 어려운 코드를 붙들고 씨름하다 보면, 어느새 웃픈 상황들이 펼쳐지죠. 이 글에서는 개발자들의 현실에서 탄생한 유머, 밈, 은어들을 한데 모아 소개합니다. IT나 스타트업 문화를 잘 모르는 분들도 함께 웃을 수 있도록, 하나하나 쉽고 재미있게 풀어 볼게요!&lt;/span&gt;&lt;/p&gt;
&lt;div class=&quot;txc-textbox&quot; style=&quot;border-style: solid; font-weight: bold; border-width: 1px  1px  1px 5px; border-color: #707070; background-color: #fff; padding: 10px;&quot;&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;https://tistory3.daumcdn.net/tistory/1569230/skin/images/jquery.toc.js&quot;&gt;&lt;/script&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;목차&lt;/p&gt;
&lt;ul id=&quot;toc&quot; style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;&lt;/ul&gt;
&lt;script type=&quot;text/javascript&quot;&gt;
$(function(){
	$(&quot;#toc&quot;).toc( {content: &quot;.tt_article_useless_p_margin&quot;, headings: &quot;h1,h2,h3,h4&quot; , top: -90, isBlink : true, blinkColor : '#21B9DE' } ) });
&lt;/script&gt;
&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;개발자밈&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;개발자 유머와 밈 : 용어부터 변명까지&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;개발자들에겐 일반인에겐 낯선 용어와 드립이 있습니다. 예를 들어 프로그램을 설치할 땐 &amp;ldquo;깔았다&amp;rdquo;, 지울 땐 &amp;ldquo;밀었다&amp;rdquo;라고도 하고, 프로세스를 종료시킬 땐 과격하게 &amp;ldquo;죽인다&amp;rdquo;, 다시 실행하면 &amp;ldquo;살린다&amp;rdquo;는 표현을 씁니다. 복사해서 붙여넣기는 &amp;ldquo;갖다 붙이기&amp;rdquo;, 콘솔에 메시지를 출력하는 건 &amp;ldquo;뿌리기&amp;rdquo;처럼 말이죠. 이렇게 독특한 개발자 용어부터 벌써 웃음이 솔솔 나오나요?&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;개발자들의 대표적인 변명 밈도 빼놓을 수 없습니다. 그중 하나가 &amp;ldquo;버그가 아니라 기능입니다&amp;rdquo;라는 말인데요. 원래 프로그램에서 예&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;상치 못한 이상 행동이 나타나면 보통 버그라고 부르지만, 개발자들은 농담 삼아 &amp;ldquo;그거 버그 아니고 원래 그런 기능이에요!&amp;rdquo; 하고 둘러대곤 합니다. 의도하지 않은 오류도 마치 계획된 기능인 척 우기는 이 유머는 전 세계 개발자들이 공감하는 관용구가 되었죠. 사용자나 상사가 &amp;ldquo;이거 왜 이래요?&amp;rdquo; 물을 때 &amp;ldquo;원래 그런 기능&amp;rdquo;이라고 뻔뻔하게 답하는 모습, 상상만 해도 웃프죠?&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;또 하나, 개발자들의 단골 레퍼토리 변명 : &amp;ldquo;내 컴퓨터에서는 잘 되는데요?&amp;rdquo;입니다. 이 말도 세계 공용 개발자 밈으로 악명 높아요. 어디선가 프로그램이 에러가 났다 하면, 담당 개발자가 &amp;ldquo;이상하네요, 제 PC에선 문제없이 돌아갔는데요???&amp;rdquo; 하고 답하는 장면이 떠오릅니다. 사실 이 멘트의 속뜻은 대개 &amp;ldquo;다른 환경에서 왜 안 되는지 더 알아봐야겠네요&amp;rdquo;라는 의미지만, 듣는 사람 입장에선 &amp;ldquo;네 컴퓨터 말고 내 컴퓨터에서 돌아가야지!&amp;rdquo; 하고 속 터질 노릇이죠. 그래서 이 &amp;ldquo;Works on my machine&amp;rdquo; 변명은 아이가 입 주위에 초콜릿 잔뜩 묻히고 &amp;ldquo;전 안 먹었어요&amp;rdquo; 하는 격이라는 우스갯소리도 있습니다. 한마디로 &amp;ldquo;내 잘못 아냐~ 나는 문제없어&amp;rdquo;라는 개발자판 무죄 주장인 셈이죠.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;1024&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c7UBlI/btsQf9LMP3Y/BefDsSptJLdDWVK3kTktlk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c7UBlI/btsQf9LMP3Y/BefDsSptJLdDWVK3kTktlk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c7UBlI/btsQf9LMP3Y/BefDsSptJLdDWVK3kTktlk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc7UBlI%2FbtsQf9LMP3Y%2FBefDsSptJLdDWVK3kTktlk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;536&quot; height=&quot;536&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;1024&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;그리고 &amp;ldquo;이게 안 되네&amp;hellip; 어, 이게 되네?&amp;rdquo;라는 유명한 밈도 있습니다. 처음엔 코드가 안 돌아가서 절망하다가, 갑자기 뚝딱 돼버리면 개발자는 어리둥절한 기쁨을 느끼는데요. 그 순간을 묘사한 유행어가 바로 &amp;ldquo;이게 안 되네? 이게 되네&amp;hellip;?&amp;rdquo;랍니다. 원래는 한 모바일 게임 캐릭터의 대사에서 유래했는데, 이제는 &amp;ldquo;엉망인 코드가 이상하게도 의도한 대로 동작할 때&amp;rdquo;나 &amp;ldquo;새내기 개발자가 어설프게 짠 코드가 돌아갈 때&amp;rdquo; 쓰이는 대표 밈이 되었죠. 한 번쯤 그런 황당한 경험, 모든 개발자가 해봤을 거예요!&lt;/span&gt;&lt;/p&gt;
&lt;center&gt;&lt;iframe src=&quot;https://www.youtube-nocookie.com/embed/zLZBunxh80U?si=ds1tTZzSuVMLC_R1&quot; width=&quot;560&quot; height=&quot;315&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;&lt;/center&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;코딩하는 일상, 커피와 버그로 밤새는 개발자&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&amp;ldquo;프로그래머는 커피를 코드로 변환하는 기계&amp;rdquo;라는 말이 있을 정도로, 커피와 개발자는 떼려야 뗄 수 없습니다. 실제로 많은 개발자들이 진한 카페인에 의존해 코딩을 이어 가곤 하죠. 밤샘 코딩이나 촉박한 마감일(데드라인)에 쫓길 때, 개발자의 책상에는 식은 커피 컵이 여러 개 쌓여있는 진풍경이 펼쳐집니다. 카페인=연료, 코드=산출물 공식이 성립하는 순간이죠.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;1024&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Kjidj/btsQfzRubOV/tZMS6KzGQHu3k66m9vWPa0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Kjidj/btsQfzRubOV/tZMS6KzGQHu3k66m9vWPa0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Kjidj/btsQfzRubOV/tZMS6KzGQHu3k66m9vWPa0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKjidj%2FbtsQfzRubOV%2FtZMS6KzGQHu3k66m9vWPa0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;499&quot; height=&quot;499&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;1024&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;야근과 버그와의 싸움도 개발자 일상의 일부입니다. &amp;ldquo;하루에 버그 하나씩 잡다 보면 언젠간 끝나겠지&amp;rdquo; 하면서도, 잡은 버그가 도망가면 또 잡고&amp;hellip; 마치 두더지 잡기 게임 같은 날들이 이어지죠. 그래서 탄생한 밈&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;이 &amp;ldquo;99 little bugs in the code, fix one bug, 127 little bugs in the code&amp;hellip;&amp;rdquo; 같은 개발자 노래(?)입니다. 버그 하나 고치면 새로운 버그 둘이 생겨나는 웃픈 상황을 노래 가사 패러디로 만든 거예요. 문제를 해결했나 싶으면 또 다른 에러 로그가 빨간 글씨로 뜨고&amp;hellip; 이런 순간에 개발자들은 웃프면서도 공감의 탄식을 내뱉습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;디버깅도 개발자의 숙명인데요. 혹시 개발자가 책상에 노란 고무 오리를 올려두고 중얼거리는 모습을 본다면 놀라지 마세요. 이것은 유명한 &amp;ldquo;러버덕 디버깅&amp;rdquo; 기법입니다. 고무 오리에게 문제를 설명하듯 하나하나 코드를 말로 풀다 보면 머릿속이 정리되어 버그를 찾게 된다는 원리죠. 실제로 많은 개발자가 인형에게 코드 설명하기로 막힌 문제를 풀곤 합니다. 남들이 보면 웃긴 장면이지만, 당사자에겐 꽤 효과적인 진지한 방법이니 이해해 주세요!&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;1024&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/8WmeV/btsQgubfiqy/p5TyJKGCEtZOgnDknbMKk1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/8WmeV/btsQgubfiqy/p5TyJKGCEtZOgnDknbMKk1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/8WmeV/btsQgubfiqy/p5TyJKGCEtZOgnDknbMKk1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F8WmeV%2FbtsQgubfiqy%2Fp5TyJKGCEtZOgnDknbMKk1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;571&quot; height=&quot;571&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;1024&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;밤을 새워 코딩하다 보면 다크서클은 내려오고, 눈은 빨개지고&amp;hellip; 그러다 아침에 결국 에러 원인을 찾았을 때의 희열은 말로 못 합니다. 개발자 문화에서는 이런 야근 영웅담도 자주 공유되죠. 하지만 현실에선 건강이 최우선! 농담처럼 &amp;ldquo;야근이 죄는 아니잖아, 버그가 죄지&amp;rdquo;라고들 하지만, 버그 잡느라 자기 건강 버그나 만들지 말자고요.??&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;회의보다 이메일 : 개발자들의 소통법&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;개발자 유머 중엔 회의에 대한 쓴소리(?)도 있습니다. 그 대표적인 말이 &amp;ldquo;이 회의는 이메일 한 통으로 충분했는데&amp;rdquo;일 거예요. 필요한 정보 몇 줄 주고받으면 될 일을 굳이 모두 불러 모아 긴 회의를 할 때, 개발자들은 속으로 이렇게 외칩니다 : &amp;ldquo;차라리 그 시간에 코딩 몇 줄 더 치겠다!&amp;rdquo; 공감 가시나요?&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;1024&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/exSmWF/btsQemZw3YO/TIe1SnlYeeBw8jgTkxGJi1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/exSmWF/btsQemZw3YO/TIe1SnlYeeBw8jgTkxGJi1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/exSmWF/btsQemZw3YO/TIe1SnlYeeBw8jgTkxGJi1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FexSmWF%2FbtsQemZw3YO%2FTIe1SnlYeeBw8jgTkxGJi1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;475&quot; height=&quot;475&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;1024&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt; &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;특히 긴 회의나 불필요한 보고 시간은 개발자들이 가장 답답해하는 순간 중 하나입니다. 하루에도 수십 번 머릿속으로 코드 구조를 그려보는 사람들이라, 불필요하게 느껴지는 회의에서는 딴생각&amp;hellip; 예컨대 버그 해결 방안이나 다음에 짤 밈 생각에 빠지기 일쑤죠. 그래서 생긴 밈이 회의 시간에 노트북으로 코딩하는 만화라든가, 회의 중 졸려하는 개발자 짤방 등입니다. 물론 모든 회의가 나쁜 건 아니지만, 개발자들은 효율과 집중을 중시하기 때문에 쓸데없이 긴 회의는 유머의 대상이 되곤 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;개발자들의 소통은 때로 비대면이나 텍스트에 강한 경향도 있습니다. 이메일이나 슬랙(Slack) 같은 협업툴로 요점을 공유하고 바로 코딩으로 돌입하는 걸 선호하죠. 그래서 팀 메신저 대화방엔 업무 얘기 옆에 귀여운 밈 GIF들이 종종 올라옵니다. 예컨대 누가 밤새 버그를 잡았다면 동료가 &amp;lsquo;슈퍼히어로 밈 GIF&amp;rsquo;를 올려주거나, 금요일 오후 배포를 강행한다고 하면 &amp;lsquo;멈춰!&amp;rsquo; 밈 이미지로 말리는 식이죠. 이런 짤 문화 덕에 딱딱한 개발 업무도 한결 인간미 넘치고 웃음이 오갑니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;한편 개발자들은 데일리 스탠드업 미팅(매일 아침 짧게 진행 상황 공유하는 회의)도 하는데, 여기에 얽힌 농담도 있어요. 일부 개발자는 어제 한 일을 그대로 복붙 해서 오늘도 했다고 보고하거나, &amp;ldquo;어제도 버그 잡았고 오늘도 버그 잡을 예정입니다. 이상입니다.&amp;rdquo;처럼 짧게 끝내죠. 이런 모습을 두고 &amp;ldquo;역시 코드를 줄이는 사람들답게 보고도 최소화!&amp;rdquo;라며 농담합니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;개발자 문화와 밈 : 함께 웃는 커뮤니티&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;전 세계 개발자들은 커뮤니티를 통해 밈을 공유하며 하나의 문화를 이뤘습니다. 특히 레딧(Reddit)의 ProgrammerHumor 게시판이나 트위터(X)의 개발자 계정들, 깃허브 저장소 등에는 개발자 밈의 원천이 넘쳐납니다. 예를 들어, 흔히들 &amp;ldquo;스택 오버플로우 없인 코딩을 못 해&amp;rdquo;라고들 하는데, 스택 오버플로우(Stack Overflow)는 개발 Q&amp;amp;ampA 커뮤니티죠. 여기서 답변 코드를 복사해다 붙이는 일이 워낙 흔해지다 보니, 스스로를 &amp;ldquo;풀스택 개발자&amp;rdquo; 대신 &amp;ldquo;풀-스택오버플로우 개발자&amp;rdquo;라고 자조하는 농담까지 생겼습니다. 즉 모든 걸 다 할 줄 아는 척하지만 사실 모르면 커뮤니티에 물어봐서 해결한다는 웃픈 고백이죠.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;또 다른 밈 전쟁의 역사로 &amp;ldquo;탭 vs 스페이스&amp;rdquo; 논쟁이 있어요. 코드를 들여 쓰기 할 때 탭(tab)을 쓰느냐 스페이스(space) 4번을 쓰느냐는 개발자들 사이 오랜 holy war(성전)인데요, 사실 결과는 똑같으면서도 누구도 양보 못 하는 우스운 싸움이죠. 심지어 이걸 주제로 한 코미디 단편 영화까지 있을 정도예요 (개발자 두 명이 취조실에서 &amp;ldquo;당신 탭 썼지? 자백해!&amp;rdquo; 뭐 이런 내용의??). 물론 실제로는 각자 취향 차이지만, 이런 사소한 것으로 친목 겸 드립을 치는 문화가 재밌는 겁니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;다크 모드 사랑도 개발자 문화의 밈 중 하나입니다. 많은 개발자가 IDE나 에디터 화면을 검은 배경(다크 모드)으로 쓰는데, 이유를 묻는 농담에 이렇게 답하곤 하죠 : &amp;ldquo;프로그래머들이 다크 모드를 선호하는 이유? 밝은 화면은 벌레(버그)를 끌어당기니까!&amp;rdquo;??(영어로 bug는 벌레라는 뜻도 있으니까요). 밝은 화면 쓰면 버그 생긴다는 억지 같지만 그만큼 어둠을 사랑하는 개발자들의 심정을 유머러스하게 표현한 겁니다. 실제로 &amp;ldquo;라이트 모드(흰 화면) 쓰는 개발자는 사이코패스&amp;rdquo;라는 농담이 있을 정도로, 다크 모드 선호는 절&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;대적이죠. (짤 : 눈이 부신 하얀 화면을 보고 경악하는 개발자 표정의 밈) &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;개발자들은 자신을 놀리는 밈에도 꽤 관대합니다. 왜냐하면 요즘 개발자는 사회적으로 인기 있고 대접받는 직종이라서, 밈으로 희화화되어도 약자에 대한 비하처럼 느끼지 않기 때문이라는 분석도 있어요. 실제 한 개발자 블로거는 &amp;ldquo;개발자가 다른 직군에 비해 취약계층이 아니기 때문에, 개발자 밈을 보며 여유롭게 웃을 수 있는 것&amp;rdquo;이라고 하더군요. 쉽게 말해, 연봉도 높고 대우도 좋으니 밈 소재가 돼도 마음 편하다는 거죠. 그래서 자기 비하 개그도 즐기고, 동료끼리 &amp;ldquo;우리 다 같이 정신 나갔지 헤헤&amp;rdquo; 하며 웃어넘기는 문화가 형성되었습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;마지막으로, 개발자 문화의 꽃인 밈 공유는 공감과 위로의 역할도 합니다. 프로젝트 폭망 이야기를 밈으로 만들면 &amp;ldquo;우리만 그런 게 아니구나&amp;rdquo; 안심이 되고, 신기술에 쫓겨 허덕이는 일상을 웹툰으로 보면 서로 킥킥대며 스트레스를 날려버리죠. GitHub 잔디밭(커밋 기록) 자랑이나, 배포 후 서버 터졌을 때의 심정 등을 다룬 짤방들도 웃음을 줍니다. 심지어 개발자 전용 이모티콘이나 밈 스티커도 등장해서, 메신저에서 &amp;ldquo;버그 발견!&amp;rdquo; 하면 귀여운 벌레 캐릭터 이모티콘을 쓰고, &amp;ldquo;퇴근 언제?&amp;rdquo;에는 팬더가 눈물 흘리는 짤을 보내기도 해요. 이렇듯 개발자들의 유머는 그들만의 문화이자 하루를 버티게 해주는 활력소가 되고 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;마무리&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;여기까지 살펴본 개발자들의 유머 코드, 재미있으셨나요??? 비 개발자라도 이해할 수 있도록 풀어낸다고 했지만, 혹시 &amp;ldquo;무슨 소리야?&amp;rdquo; 싶은 부분도 있었을지 모르겠습니다. 그래도 한 가지 분명한 건, 개발자들도 우리와 똑같이 웃고 운다는 것이에요. 버그 앞에서 속상해하다가도 밈 하나에 허탈한 웃음을 짓고, 야근으로 녹초가 되어도 동료의 농담 한 방에 피식 힘을 얻고&amp;hellip; 이렇게 웃픈 순간들을 나누며 같이 성장하는게&amp;nbsp;개발자 문화의 매력 아닐까요?&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;개발자는 늘 새로운 문제를 마주하지만, 그럴 때마다 유머 감각을 장착하고 &amp;ldquo;버그 따위 우습지!&amp;rdquo; 넘길 줄 아는 멋진 사람들입니다. 오늘 소개한 밈들과 이야기들로 잠시나마 웃음을 드렸길 바라면서, 글을 마칩니다. 코드를 짤 땐 진지하게, 그러나 웃음 버튼도 곁에 장&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;착한 모든 개발자분 파이팅!&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;1024&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bubaVQ/btsQggKTHPc/xmlPcnoK0dYMOtUYUwVQdK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bubaVQ/btsQggKTHPc/xmlPcnoK0dYMOtUYUwVQdK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bubaVQ/btsQggKTHPc/xmlPcnoK0dYMOtUYUwVQdK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbubaVQ%2FbtsQggKTHPc%2FxmlPcnoK0dYMOtUYUwVQdK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;377&quot; height=&quot;377&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;1024&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;AI가 이미지까지 척척 만들어주니까, 이제 제 생각은 단순합니다. &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&amp;ldquo;AI야, 코드도 대신 짜줄래?&amp;rdquo; &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;... 네, 맞습니다. 오늘도 회사 일 하기 싫다는 뜻입니다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>IT</category>
      <category>IT유머</category>
      <category>개발자</category>
      <category>개발자문화</category>
      <category>개발자밈</category>
      <category>버그</category>
      <category>스타트업</category>
      <category>야근</category>
      <category>엔지니어</category>
      <category>코딩</category>
      <category>프로그래밍</category>
      <author>간지뽕빨리턴님</author>
      <guid isPermaLink="true">https://odinbox.tistory.com/549</guid>
      <comments>https://odinbox.tistory.com/549#entry549comment</comments>
      <pubDate>Sat, 6 Sep 2025 08:04:00 +0900</pubDate>
    </item>
    <item>
      <title>개발자와 직장인을 위한 효과적인 시간 관리 전략</title>
      <link>https://odinbox.tistory.com/548</link>
      <description>&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이렇게 하면 좋지 않을까라는 생각으로 적어본 글&lt;/span&gt;&lt;/p&gt;
&lt;div class=&quot;txc-textbox&quot; style=&quot;font-weight: normal; position: relative; line-height: 40px; background: #007CBA; border: 1px solid #fff; padding: 10px; color: white; border-radius: 0 10px 0 10px; box-shadow: inset 0 0 5px rgba(53,86,129, 0.5); font-family: 'Muli', sans-serif; border-style: solid; border-width: 0px  0px  1px 15px; border-color: #232323; background-color: #007cba;&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-size: 15pt; color: #ffffff;&quot;&gt;&lt;b&gt;개발자(직장인)의 시간은 어떻게 관리되어야 하는가, 생산성을 높이는 집중 및 우선순위&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;글 상단 부분 대표 이미지 (8).png&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/eCZ6TF/btsQfAJqp9v/022kGMEk2qGPwaYAumAbyK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/eCZ6TF/btsQfAJqp9v/022kGMEk2qGPwaYAumAbyK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/eCZ6TF/btsQfAJqp9v/022kGMEk2qGPwaYAumAbyK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FeCZ6TF%2FbtsQfAJqp9v%2F022kGMEk2qGPwaYAumAbyK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;400&quot; data-filename=&quot;글 상단 부분 대표 이미지 (8).png&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;실무&amp;nbsp;현장에서&amp;nbsp;우리는&amp;nbsp;언제나&amp;nbsp;한정된&amp;nbsp;시간&amp;nbsp;안에&amp;nbsp;무수한&amp;nbsp;일을&amp;nbsp;처리해야&amp;nbsp;하는&amp;nbsp;압박감&amp;nbsp;속에&amp;nbsp;살아갑니다.&amp;nbsp;하루는&amp;nbsp;고작&amp;nbsp;24시간뿐인데,&amp;nbsp;회의와&amp;nbsp;보고,&amp;nbsp;개발과&amp;nbsp;버그&amp;nbsp;수정,&amp;nbsp;팀&amp;nbsp;소통과&amp;nbsp;개인&amp;nbsp;업무까지&amp;nbsp;동시에&amp;nbsp;몰려옵니다.&amp;nbsp;그러다&amp;nbsp;보면&amp;nbsp;정말&amp;nbsp;중요한&amp;nbsp;일에&amp;nbsp;집중하기보다는&amp;nbsp;눈앞의&amp;nbsp;급한&amp;nbsp;일만&amp;nbsp;처리하다&amp;nbsp;하루가&amp;nbsp;끝나버리기&amp;nbsp;일쑤입니다.&amp;nbsp;저&amp;nbsp;역시&amp;nbsp;개발&amp;nbsp;업무를&amp;nbsp;하면서&amp;nbsp;&amp;ldquo;어떻게&amp;nbsp;하면&amp;nbsp;제한된&amp;nbsp;시간을&amp;nbsp;좀&amp;nbsp;더&amp;nbsp;효율적으로&amp;nbsp;활용할&amp;nbsp;수&amp;nbsp;있을까?&amp;rdquo;라는&amp;nbsp;고민을&amp;nbsp;끊임없이&amp;nbsp;해왔습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;이런&amp;nbsp;고민&amp;nbsp;속에서&amp;nbsp;발견한&amp;nbsp;몇&amp;nbsp;가지&amp;nbsp;실질적인&amp;nbsp;방법이&amp;nbsp;있습니다.&amp;nbsp;대표적으로는&amp;nbsp;Eisenhower&amp;nbsp;매트릭스를&amp;nbsp;활용한&amp;nbsp;우선순위&amp;nbsp;설정,&amp;nbsp;Cal&amp;nbsp;Newport가&amp;nbsp;제안한&amp;nbsp;시간&amp;nbsp;블록&amp;nbsp;관리(Time&amp;nbsp;Blocking)&amp;nbsp;기법,&amp;nbsp;그리고&amp;nbsp;다중작업을&amp;nbsp;줄이고&amp;nbsp;단일작업(싱글태스킹)에&amp;nbsp;집중하는&amp;nbsp;습관입니다.&amp;nbsp;이&amp;nbsp;세&amp;nbsp;가지는&amp;nbsp;단순한&amp;nbsp;이론이&amp;nbsp;아니라,&amp;nbsp;실제로&amp;nbsp;바쁜&amp;nbsp;개발자나&amp;nbsp;직장인들이&amp;nbsp;분주한&amp;nbsp;일상&amp;nbsp;속에서도&amp;nbsp;본질적인&amp;nbsp;업무에&amp;nbsp;몰입할&amp;nbsp;수&amp;nbsp;있도록&amp;nbsp;돕는&amp;nbsp;매우&amp;nbsp;강력한&amp;nbsp;도구입니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;결국&amp;nbsp;제가&amp;nbsp;정리하고&amp;nbsp;싶은&amp;nbsp;고민의&amp;nbsp;핵심은&amp;nbsp;이것입니다.&amp;nbsp;&amp;ldquo;수많은&amp;nbsp;업무와&amp;nbsp;방해&amp;nbsp;요인&amp;nbsp;속에서&amp;nbsp;어떻게&amp;nbsp;하면&amp;nbsp;내가&amp;nbsp;진짜&amp;nbsp;중요한&amp;nbsp;일에&amp;nbsp;시간을&amp;nbsp;쓸&amp;nbsp;수&amp;nbsp;있을까?&amp;rdquo;&amp;nbsp;이&amp;nbsp;질문에&amp;nbsp;답을&amp;nbsp;찾는&amp;nbsp;과정에서&amp;nbsp;배운&amp;nbsp;원칙들을&amp;nbsp;이번&amp;nbsp;글에서&amp;nbsp;풀어내고자&amp;nbsp;합니다.&lt;/span&gt;&lt;/p&gt;
&lt;div class=&quot;txc-textbox&quot; style=&quot;border-style: solid; font-weight: bold; border-width: 1px  1px  1px 5px; border-color: #707070; background-color: #fff; padding: 10px;&quot;&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;https://tistory3.daumcdn.net/tistory/1569230/skin/images/jquery.toc.js&quot;&gt;&lt;/script&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;목차&lt;/p&gt;
&lt;ul id=&quot;toc&quot; style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;&lt;/ul&gt;
&lt;script type=&quot;text/javascript&quot;&gt;
$(function(){
	$(&quot;#toc&quot;).toc( {content: &quot;.tt_article_useless_p_margin&quot;, headings: &quot;h1,h2,h3,h4&quot; , top: -90, isBlink : true, blinkColor : '#21B9DE' } ) });
&lt;/script&gt;
&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;시간관리&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;들어가기 전&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;아침에 업무를 시작하며 가장 중요한 프로젝트를 머릿속에 그려보지만 컴퓨터를 켜는 순간 이메일과 메신저 알림이 쏟아집니다. 급하게 온 요청들을 처리하고 나니 곧 회의 시간입니다. 회의 도중에도 추가 업무 지시와 긴급 문의가 이어지고 정작 오늘 꼭 진척을 내야 할 중요한 작업은 손도 대지 못한 채 하루가 끝나버립니다. 이러한 경험은 많은 개발자와 직장인들에겐 낯설지 않을 겁니다. 실제로 스티븐 코비는 &quot;대부분의 사람들은 긴급한 일에 쫓기느라 정작 중요한 일에는 충분한 시간을 들이지 못한다&quot;라고 지적했습니다. 현대 사회에서 시간 관리는 개인의 생산성과 삶의 질을 결정하는 핵심 역량이며 우리가 한정된 시간의 주인이 되지 못하면 일에 끌려다니는 삶을 벗어나기 어렵습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;최근 IT 리더 Mike Fisher[&lt;a title=&quot;Mike Fisher&quot; href=&quot;https://mikefisher.substack.com/p/time-management&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;#&lt;/a&gt;]님이 올리셨던 글을 참고하여 &quot;10 Ways to Take Ownership of Your Time&quot;에서 이러한 시간 관리 문제를 해결하기 위한 10가지 기법을 소개했습니다. 그 핵심은 시간의 주도권을 되찾아 중요한 목표에 우리의 시간을 투자하는 것입니다. 시간관리에 대해서 어떤 유용한 원칙들이 있는지 살펴보고 이야기해보려고 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;긴급함에 쫓기지 말고, 중요한 일에 집중하기&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1648&quot; data-origin-height=&quot;1139&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/OtLtn/btsQfflhUiF/mOATzuk0lDpokmm22KfHj1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/OtLtn/btsQfflhUiF/mOATzuk0lDpokmm22KfHj1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/OtLtn/btsQfflhUiF/mOATzuk0lDpokmm22KfHj1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOtLtn%2FbtsQfflhUiF%2FmOATzuk0lDpokmm22KfHj1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1648&quot; height=&quot;1139&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1648&quot; data-origin-height=&quot;1139&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;업무를 하다 보면 눈앞의 긴급한 일들이 끊임없이 나타나 우리를 몰아붙입니다. 그러나 긴급한 일이 항상 중요한 일은 아닙니다. 폭풍처럼 밀려드는 요청에 일일이 대응하다 보면 정작 장기적으로 큰 가치와 성과를 내는 중요한 일은 뒤로 밀리기 쉽습니다. 이를 극복하기 위해 아이젠하워 중요-긴급 매트릭스(EisenhowerMatrix)가 유용합니다. 아이젠하워 매트릭스는 해야 할 업무를 중요도와 긴급도 축으로 분류하여 4개 사분면에 배치하는 도구로서 긴급성과 중요성을 하눈에 평가하도록 돕습니다. 이를 통해 우리는 업무의 우선순위를 재정립하고 무턱대고 모든 일에 쫓기는 악순환에서 벗어날 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;예를 들어 팀 리드로 일한다고 하면 갑작스러운 버그 수정 요청이나 사소한 문의(긴급하지만 중요다가 낮은 일)에 즉각 매달리기보다 하루 중 우선 중요하고 긴급한 일(예를 들어 마감 임박한 핵심 기능 구현)부터 처리하려고 노력하는 등 긴급하지는 않지만 성장과 목표 달성에 중요한 일(예를 들어 기술 부채 개선이나 전력 기획 등)은 별도로 시간을 확보해 수행 일정에 넣었습니다. 반면 긴급해 보이나 팀의 목표와 관련이 적은 업무는 과감히 위임하거나 일정을 재조정했고 중요도도 낮고 긴급하지 않은 일들은 생략하거나 최소화했습니다. 이렇게 업무를 분류하고 나니 하루가 끝날 때 정말로 가치 있는&amp;nbsp; 성과가 남는 날이 점저 늘어날 수 있는 상황이 늘어납니다. 실제 하버드대 커리어 전문가 Gorickng도 이 매트릭스를 활용하면 일의 홍수 속에서 무엇을 먼저 해야 할지 구분할 수 있고 정기적으로 이 분류를 재점검하면 자신의 목표와 가치에 가장 의미 있는 곳에서 시간을 쓸 수 있게 된다고 합니다. 결국 긴급함에 휘둘리지 않고 중요한 일을 우선하는 원칙이 시간 관리의 출발점이라 할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;하루를 설계하는 시간 블록 관리 전략&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;1024&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dyUK8i/btsQfwG4Xs1/lqPVeh065llV4CsIpDOaUK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dyUK8i/btsQfwG4Xs1/lqPVeh065llV4CsIpDOaUK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dyUK8i/btsQfwG4Xs1/lqPVeh065llV4CsIpDOaUK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdyUK8i%2FbtsQfwG4Xs1%2FlqPVeh065llV4CsIpDOaUK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;498&quot; height=&quot;498&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;1024&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;개발자들은&amp;nbsp;회의,&amp;nbsp;코딩,&amp;nbsp;코드&amp;nbsp;리뷰,&amp;nbsp;버그&amp;nbsp;대응&amp;nbsp;등&amp;nbsp;다양한&amp;nbsp;작업&amp;nbsp;유형을&amp;nbsp;하루&amp;nbsp;동안&amp;nbsp;수행합니다.&amp;nbsp;이때&amp;nbsp;시간&amp;nbsp;블록&amp;nbsp;관리(Time&amp;nbsp;Blocking)&amp;nbsp;기법을&amp;nbsp;활용하면&amp;nbsp;산만한&amp;nbsp;일정을&amp;nbsp;체계적으로&amp;nbsp;조직할&amp;nbsp;수&amp;nbsp;있습니다.&amp;nbsp;시간&amp;nbsp;블록&amp;nbsp;관리란&amp;nbsp;말&amp;nbsp;그대로&amp;nbsp;하루를&amp;nbsp;여러&amp;nbsp;블록으로&amp;nbsp;나누고&amp;nbsp;각&amp;nbsp;블록에&amp;nbsp;특정&amp;nbsp;업무를&amp;nbsp;할당하는&amp;nbsp;방식입니다.&amp;nbsp;예를&amp;nbsp;들어&amp;nbsp;필자는&amp;nbsp;오전&amp;nbsp;시간을&amp;nbsp;2~3시간짜리&amp;nbsp;코딩&amp;nbsp;집중&amp;nbsp;블록으로&amp;nbsp;정해두고,&amp;nbsp;이&amp;nbsp;시간만큼은&amp;nbsp;다른&amp;nbsp;회의나&amp;nbsp;메신저&amp;nbsp;확인을&amp;nbsp;최대한&amp;nbsp;배제합니다.&amp;nbsp;점심&amp;nbsp;이후&amp;nbsp;한두&amp;nbsp;시간은&amp;nbsp;동료와&amp;nbsp;토론하거나&amp;nbsp;코드&amp;nbsp;리뷰를&amp;nbsp;하는&amp;nbsp;커뮤니케이션&amp;nbsp;블록으로&amp;nbsp;사용하고,&amp;nbsp;남은&amp;nbsp;시간은&amp;nbsp;이메일&amp;nbsp;정리나&amp;nbsp;잡무를&amp;nbsp;처리하는&amp;nbsp;시간으로&amp;nbsp;배분합니다.&amp;nbsp;이렇게&amp;nbsp;일정을&amp;nbsp;설계해&amp;nbsp;두면&amp;nbsp;예기치&amp;nbsp;못한&amp;nbsp;일이&amp;nbsp;생겨도&amp;nbsp;큰&amp;nbsp;틀에서&amp;nbsp;우선순위&amp;nbsp;있는&amp;nbsp;업무에&amp;nbsp;충분한&amp;nbsp;시간을&amp;nbsp;확보할&amp;nbsp;수&amp;nbsp;있습니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;시간&amp;nbsp;블로킹&amp;nbsp;기법을&amp;nbsp;대중화한&amp;nbsp;Cal&amp;nbsp;Newport는&amp;nbsp;일정표를&amp;nbsp;빈&amp;nbsp;달력이&amp;nbsp;아니라&amp;nbsp;해야&amp;nbsp;할&amp;nbsp;일을&amp;nbsp;담는&amp;nbsp;시간&amp;nbsp;예산서로&amp;nbsp;활용하라고&amp;nbsp;조언합니다.&amp;nbsp;위&amp;nbsp;그림처럼&amp;nbsp;하루를&amp;nbsp;미리&amp;nbsp;설계해 두면&amp;nbsp;마치&amp;nbsp;회의&amp;nbsp;일정을&amp;nbsp;지키듯&amp;nbsp;자신과의&amp;nbsp;약속을&amp;nbsp;지키게&amp;nbsp;되어,&amp;nbsp;중요한&amp;nbsp;업무를&amp;nbsp;몰입할&amp;nbsp;시간을&amp;nbsp;확보하게&amp;nbsp;됩니다.&amp;nbsp;업무&amp;nbsp;특성상&amp;nbsp;하루가&amp;nbsp;예측&amp;nbsp;불가능하게&amp;nbsp;흐를&amp;nbsp;수밖에&amp;nbsp;없는&amp;nbsp;경우에도,&amp;nbsp;최소한&amp;nbsp;필요한&amp;nbsp;만큼의&amp;nbsp;블록은&amp;nbsp;사수하려고&amp;nbsp;노력하는&amp;nbsp;것과&amp;nbsp;전혀&amp;nbsp;계획&amp;nbsp;없이&amp;nbsp;임기응변으로&amp;nbsp;임하는&amp;nbsp;것에는&amp;nbsp;큰&amp;nbsp;차이가&amp;nbsp;있음을&amp;nbsp;느꼈습니다.&amp;nbsp;한&amp;nbsp;개발팀에서는&amp;nbsp;아예&amp;nbsp;팀&amp;nbsp;공용&amp;nbsp;달력에&amp;nbsp;코딩&amp;nbsp;타임을&amp;nbsp;블록으로&amp;nbsp;설정해&amp;nbsp;두고&amp;nbsp;그&amp;nbsp;시간엔&amp;nbsp;회의를&amp;nbsp;잡지&amp;nbsp;않기로&amp;nbsp;합의하기도&amp;nbsp;했습니다.&amp;nbsp;이렇게&amp;nbsp;하면&amp;nbsp;개발자&amp;nbsp;개인뿐&amp;nbsp;아니라&amp;nbsp;팀&amp;nbsp;전체가&amp;nbsp;중요한&amp;nbsp;개발&amp;nbsp;작업에&amp;nbsp;필요한&amp;nbsp;시간을&amp;nbsp;보호할&amp;nbsp;수&amp;nbsp;있습니다.&amp;nbsp;이처럼&amp;nbsp;시간&amp;nbsp;블록&amp;nbsp;관리로&amp;nbsp;하루를&amp;nbsp;능동적으로&amp;nbsp;설계하면,&amp;nbsp;주어진&amp;nbsp;시간&amp;nbsp;내에&amp;nbsp;가장&amp;nbsp;의미&amp;nbsp;있는&amp;nbsp;일을&amp;nbsp;완료할&amp;nbsp;가능성이&amp;nbsp;훨씬&amp;nbsp;높아집니다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;멀티태스킹의 함정과 한 가지 일에 집중하는 힘&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;1024&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ctot38/btsQdxOkebw/k7hILaUYGK1N1z2cKqYCT1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ctot38/btsQdxOkebw/k7hILaUYGK1N1z2cKqYCT1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ctot38/btsQdxOkebw/k7hILaUYGK1N1z2cKqYCT1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fctot38%2FbtsQdxOkebw%2Fk7hILaUYGK1N1z2cKqYCT1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;515&quot; height=&quot;515&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;1024&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;업무 효율을 높이려고 여러 가지 일을 동시에 처리(멀티태스킹)하는 사람들이 많지만, 아이러니하게도 이는 생산성을 떨어뜨리는 주범입니다. 한 연구에 따르면 멀티태스킹을 많이 하는 사람들은 한 번에 하나씩 차례로 처리하는 사람들보다 업무 효율이 낮고, 일단 작업 흐름이 끊기면 다시 집중력을 되찾는 데 평균 23분 15초가 걸린다고 합니다. 결국 동시에 여러 일을 해내려는 욕심이 오히려 시간을 낭비시키고 두뇌의 에너지만 소모하는 셈입니다. 필자 역시 한때는 IDE로 코드를 작성하면서 옆 화면으로 이메일 알림을 수시로 확인하고, 전화 통화까지 하며 다중작업을 자처했던 적이 있습니다. 그러나 결과를 돌이켜보면 그런 날은 잦은 문맥 전환 때문에 정말 중요한 코드 한 줄 제대로 작성하지 못한 채 피로감만 누적되곤 했습니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;그&amp;nbsp;이후로&amp;nbsp;업무&amp;nbsp;방식에&amp;nbsp;큰&amp;nbsp;변화를&amp;nbsp;주었습니다.&amp;nbsp;이제는&amp;nbsp;한&amp;nbsp;번에&amp;nbsp;한&amp;nbsp;가지&amp;nbsp;업무에만&amp;nbsp;몰입하려고&amp;nbsp;의식적으로&amp;nbsp;노력합니다.&amp;nbsp;코딩할&amp;nbsp;때는&amp;nbsp;메신저와&amp;nbsp;이메일&amp;nbsp;알림을&amp;nbsp;잠시&amp;nbsp;꺼두고,&amp;nbsp;면밀한&amp;nbsp;사고가&amp;nbsp;필요한&amp;nbsp;설계&amp;nbsp;작업&amp;nbsp;시간엔&amp;nbsp;아예&amp;nbsp;사무실&amp;nbsp;메시지도&amp;nbsp;뒤로&amp;nbsp;미룹니다.&amp;nbsp;이러한&amp;nbsp;싱글태스킹&amp;nbsp;원칙을&amp;nbsp;지키면서&amp;nbsp;제&amp;nbsp;업무&amp;nbsp;완성도와&amp;nbsp;속도가&amp;nbsp;크게&amp;nbsp;향상되었습니다.&amp;nbsp;역사적으로도&amp;nbsp;위대한&amp;nbsp;성과를&amp;nbsp;낸&amp;nbsp;이들은&amp;nbsp;몰입의&amp;nbsp;가치를&amp;nbsp;강조해 왔습니다.&amp;nbsp;모차르트는&amp;nbsp;&amp;ldquo;여러&amp;nbsp;일을&amp;nbsp;빨리해 내는&amp;nbsp;지름길은&amp;nbsp;한&amp;nbsp;번에&amp;nbsp;한&amp;nbsp;가지&amp;nbsp;일만&amp;nbsp;하는&amp;nbsp;것&amp;rdquo;이라고&amp;nbsp;말했으며,&amp;nbsp;실제로&amp;nbsp;하나의&amp;nbsp;작업에&amp;nbsp;깊이&amp;nbsp;몰입할&amp;nbsp;때&amp;nbsp;창의성과&amp;nbsp;문제&amp;nbsp;해결&amp;nbsp;능력이&amp;nbsp;최고조에&amp;nbsp;달하는&amp;nbsp;것을&amp;nbsp;느낍니다.&amp;nbsp;개발&amp;nbsp;현장에서도&amp;nbsp;집중의&amp;nbsp;힘을&amp;nbsp;높이기&amp;nbsp;위해&amp;nbsp;포모도로&amp;nbsp;기법을&amp;nbsp;활용하는&amp;nbsp;동료가&amp;nbsp;많은데,&amp;nbsp;25분간&amp;nbsp;한&amp;nbsp;가지&amp;nbsp;일에만&amp;nbsp;집중하고&amp;nbsp;5분&amp;nbsp;휴식하는&amp;nbsp;사이클을&amp;nbsp;반복하는&amp;nbsp;이&amp;nbsp;방법은&amp;nbsp;뇌가&amp;nbsp;산만해지기&amp;nbsp;전에&amp;nbsp;짧은&amp;nbsp;집중을&amp;nbsp;누적시키는&amp;nbsp;데&amp;nbsp;효과적입니다.&amp;nbsp;예컨대&amp;nbsp;저도&amp;nbsp;오전에&amp;nbsp;2~3회&amp;nbsp;포모도로를&amp;nbsp;실행하며&amp;nbsp;코딩에&amp;nbsp;몰두한&amp;nbsp;뒤,&amp;nbsp;오후에는&amp;nbsp;짧은&amp;nbsp;휴식&amp;nbsp;후&amp;nbsp;다른&amp;nbsp;업무로&amp;nbsp;전환하는&amp;nbsp;식으로&amp;nbsp;리듬을&amp;nbsp;관리하고&amp;nbsp;있습니다.&amp;nbsp;처음에는&amp;nbsp;한&amp;nbsp;가지&amp;nbsp;일에만&amp;nbsp;집중하기가&amp;nbsp;힘들지만,&amp;nbsp;연습을&amp;nbsp;통해&amp;nbsp;집중근육을&amp;nbsp;단련하면&amp;nbsp;어느새&amp;nbsp;짧은&amp;nbsp;시간에도&amp;nbsp;깊은&amp;nbsp;성과를&amp;nbsp;내는&amp;nbsp;자신을&amp;nbsp;발견하게&amp;nbsp;됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;시간을 지배하는 법, 목표에 맞게 일하기&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;1024&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/MpWYW/btsQgelSRZ1/zmdfKrDCFBit6tZGXuFmx1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/MpWYW/btsQgelSRZ1/zmdfKrDCFBit6tZGXuFmx1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/MpWYW/btsQgelSRZ1/zmdfKrDCFBit6tZGXuFmx1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMpWYW%2FbtsQgelSRZ1%2FzmdfKrDCFBit6tZGXuFmx1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;508&quot; height=&quot;508&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;1024&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;한정된&amp;nbsp;시간&amp;nbsp;자원을&amp;nbsp;제대로&amp;nbsp;활용하려면&amp;nbsp;바쁘게&amp;nbsp;일하는&amp;nbsp;것과&amp;nbsp;잘&amp;nbsp;일하는&amp;nbsp;것을&amp;nbsp;구분해야&amp;nbsp;합니다.&amp;nbsp;앞서&amp;nbsp;살펴본&amp;nbsp;원칙들을&amp;nbsp;종합하면,&amp;nbsp;효과적인&amp;nbsp;시간&amp;nbsp;관리란&amp;nbsp;더&amp;nbsp;많은&amp;nbsp;일을&amp;nbsp;억지로&amp;nbsp;끼워&amp;nbsp;넣는&amp;nbsp;것이&amp;nbsp;아니라&amp;nbsp;스마트하게&amp;nbsp;일하는&amp;nbsp;것입니다.&amp;nbsp;스마트하게&amp;nbsp;일한다는&amp;nbsp;것은&amp;nbsp;자신의&amp;nbsp;핵심&amp;nbsp;목표에&amp;nbsp;맞춰&amp;nbsp;시간과&amp;nbsp;에너지를&amp;nbsp;배분하는&amp;nbsp;일입니다.&amp;nbsp;개발자라면&amp;nbsp;제품의&amp;nbsp;품질&amp;nbsp;향상이나&amp;nbsp;중요한&amp;nbsp;기능&amp;nbsp;개발&amp;nbsp;같은&amp;nbsp;장기적&amp;nbsp;가치를&amp;nbsp;최우선&amp;nbsp;순위에&amp;nbsp;두고&amp;nbsp;시간을&amp;nbsp;투자해야&amp;nbsp;합니다.&amp;nbsp;창업자나&amp;nbsp;팀&amp;nbsp;리더라면&amp;nbsp;방향성을&amp;nbsp;잡는&amp;nbsp;기획과&amp;nbsp;의사결정에&amp;nbsp;충분한&amp;nbsp;시간을&amp;nbsp;할애해야&amp;nbsp;할&amp;nbsp;것입니다.&amp;nbsp;일과를&amp;nbsp;설계할&amp;nbsp;때&amp;nbsp;늘&amp;nbsp;&amp;ldquo;이&amp;nbsp;활동이&amp;nbsp;나나&amp;nbsp;우리&amp;nbsp;조직의&amp;nbsp;목표에&amp;nbsp;얼마나&amp;nbsp;이바지하는가?&amp;rdquo;를&amp;nbsp;자문해&amp;nbsp;보면,&amp;nbsp;우선순위에서&amp;nbsp;밀려나야&amp;nbsp;할&amp;nbsp;일과&amp;nbsp;집중해야&amp;nbsp;할&amp;nbsp;일이&amp;nbsp;보입니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;또한&amp;nbsp;자신의&amp;nbsp;업무&amp;nbsp;스타일을&amp;nbsp;돌아보고&amp;nbsp;생산성을&amp;nbsp;높여주는&amp;nbsp;작은&amp;nbsp;습관들도&amp;nbsp;활용하면&amp;nbsp;좋습니다.&amp;nbsp;예를&amp;nbsp;들어&amp;nbsp;GTD와&amp;nbsp;같은&amp;nbsp;생산성&amp;nbsp;구조에서는&amp;nbsp;모든&amp;nbsp;할&amp;nbsp;일을&amp;nbsp;머릿속이&amp;nbsp;아니라&amp;nbsp;신뢰할&amp;nbsp;수&amp;nbsp;있는&amp;nbsp;시스템에&amp;nbsp;적어두고&amp;nbsp;처리&amp;nbsp;순서를&amp;nbsp;정하라고&amp;nbsp;권합니다.&amp;nbsp;저도&amp;nbsp;업무용&amp;nbsp;노트&amp;nbsp;앱에&amp;nbsp;해야&amp;nbsp;할&amp;nbsp;일들을&amp;nbsp;프로젝트별로&amp;nbsp;기록하고,&amp;nbsp;매일&amp;nbsp;아침&amp;nbsp;최우선으로&amp;nbsp;처리할&amp;nbsp;상위&amp;nbsp;3~5개&amp;nbsp;업무를&amp;nbsp;골라냅니다.&amp;nbsp;이렇게&amp;nbsp;적어두면&amp;nbsp;업무량이&amp;nbsp;많아도&amp;nbsp;머릿속이&amp;nbsp;맑게&amp;nbsp;유지되고&amp;nbsp;지금&amp;nbsp;할&amp;nbsp;일에만&amp;nbsp;전념하기&amp;nbsp;쉬워집니다.&amp;nbsp;사소한&amp;nbsp;일들이&amp;nbsp;쌓여&amp;nbsp;큰&amp;nbsp;부담이&amp;nbsp;되는&amp;nbsp;것을&amp;nbsp;막기&amp;nbsp;위해,&amp;nbsp;2분&amp;nbsp;안에&amp;nbsp;끝낼&amp;nbsp;수&amp;nbsp;있는&amp;nbsp;작업은&amp;nbsp;바로&amp;nbsp;처리하는&amp;nbsp;&amp;ldquo;2분&amp;nbsp;규칙&amp;rdquo;도&amp;nbsp;유용합니다.&amp;nbsp;이메일&amp;nbsp;회신이나&amp;nbsp;간단한&amp;nbsp;보고처럼&amp;nbsp;짧은&amp;nbsp;업무는&amp;nbsp;곧바로&amp;nbsp;처리해 버림으로써&amp;nbsp;작업&amp;nbsp;목록을&amp;nbsp;정리하고&amp;nbsp;정신적&amp;nbsp;부담을&amp;nbsp;줄일&amp;nbsp;수&amp;nbsp;있었습니다.&amp;nbsp;반대로&amp;nbsp;오래&amp;nbsp;걸리지만&amp;nbsp;중요한&amp;nbsp;작업은&amp;nbsp;아침의&amp;nbsp;높은&amp;nbsp;에너지&amp;nbsp;시간대에&amp;nbsp;먼저&amp;nbsp;수행하는&amp;nbsp;것이&amp;nbsp;효과적입니다.&amp;nbsp;이른바&amp;nbsp;&amp;ldquo;개구리를&amp;nbsp;먼저&amp;nbsp;먹어라&amp;rdquo;라는&amp;nbsp;생산성&amp;nbsp;격언이&amp;nbsp;있는데,&amp;nbsp;가장&amp;nbsp;힘든&amp;nbsp;일을&amp;nbsp;미루지&amp;nbsp;말고&amp;nbsp;하루의&amp;nbsp;첫&amp;nbsp;번째&amp;nbsp;작업으로&amp;nbsp;처리하라는&amp;nbsp;뜻입니다.&amp;nbsp;필자도&amp;nbsp;심리적으로&amp;nbsp;부담되는&amp;nbsp;코딩&amp;nbsp;작업이나&amp;nbsp;까다로운&amp;nbsp;문제&amp;nbsp;해결을&amp;nbsp;오전&amp;nbsp;일찍&amp;nbsp;착수해&amp;nbsp;끝내놓으면,&amp;nbsp;그날&amp;nbsp;나머지&amp;nbsp;시간이&amp;nbsp;훨씬&amp;nbsp;가볍고&amp;nbsp;생산적으로&amp;nbsp;느껴졌습니다.&amp;nbsp;결국,&amp;nbsp;자기&amp;nbsp;시간을&amp;nbsp;지배한다는&amp;nbsp;것은&amp;nbsp;무엇에&amp;nbsp;시간을&amp;nbsp;투자하고&amp;nbsp;무엇을&amp;nbsp;과감히&amp;nbsp;버릴지&amp;nbsp;스스로&amp;nbsp;결정하는&amp;nbsp;일입니다.&amp;nbsp;업무상&amp;nbsp;불가피하게&amp;nbsp;해야&amp;nbsp;하는&amp;nbsp;일이라도&amp;nbsp;내가&amp;nbsp;주도권을&amp;nbsp;갖고&amp;nbsp;선택한&amp;nbsp;것처럼&amp;nbsp;인식하는&amp;nbsp;순간&amp;nbsp;몰입도와&amp;nbsp;만족도가&amp;nbsp;달라집니다.&amp;nbsp;시간&amp;nbsp;관리의&amp;nbsp;궁극적인&amp;nbsp;목표는&amp;nbsp;시간의&amp;nbsp;주인이&amp;nbsp;되어&amp;nbsp;삶과&amp;nbsp;업무&amp;nbsp;전반에서&amp;nbsp;더&amp;nbsp;큰&amp;nbsp;성취와&amp;nbsp;균형을&amp;nbsp;이루는&amp;nbsp;데&amp;nbsp;있다는&amp;nbsp;것을&amp;nbsp;기억해야&amp;nbsp;합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;마무리, 우선순위를 지키는 습관이 경쟁력이다&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;1024&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Ktyn6/btsQdSkpkwl/iTlKLrkd9DfLoA0kIKKDAK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Ktyn6/btsQdSkpkwl/iTlKLrkd9DfLoA0kIKKDAK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Ktyn6/btsQdSkpkwl/iTlKLrkd9DfLoA0kIKKDAK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKtyn6%2FbtsQdSkpkwl%2FiTlKLrkd9DfLoA0kIKKDAK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;486&quot; height=&quot;486&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;1024&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;중요-긴급 매트릭스 활용&lt;/b&gt; : 오늘 해야 할 일을 네 가지 범주(중요&amp;middot;긴급 등)로 분류해 보세요. 긴급하지 않지만 중요한 일에 꾸준히 시간을 투자하는 계기가 됩니다. &lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;시간 블록킹 시도 : 내일 일정표에 중요한 업무를 위한 집중 블록 시간을 미리 확보하세요. 그 시간만큼은 방해를 차단하고 몰입해 봅니다. &lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;업무 중 한 가지에만 몰두&lt;/b&gt; : 작업할 때 방해가 되는 알림을 끄고 하나의 업무에만 집중하세요. 멀티태스킹을 줄이면 오히려 처리 속도가 빨라집니다. &lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;2분 규칙 적용&lt;/b&gt; : 2분 이내에 끝낼 수 있는 이메일 답장이나 관리 업무가 있다면 바로바로 처리하여 작업 목록을 가볍게 유지하세요. &lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;하루의 첫 임무로 어려운 일 수행&lt;/b&gt; : 미루기 쉬운 까다로운 작업을 아침 첫 작업으로 완료해 보세요(&amp;ldquo;개구리&amp;rdquo;부터 먹기). 남은 시간에 대한 자신감이 생깁니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;소프트웨어&amp;nbsp;개발자를&amp;nbsp;비롯한&amp;nbsp;현대의&amp;nbsp;지식&amp;nbsp;노동자에게&amp;nbsp;시간&amp;nbsp;관리는&amp;nbsp;곧&amp;nbsp;자기&amp;nbsp;관리이며&amp;nbsp;경쟁력의&amp;nbsp;핵심입니다.&amp;nbsp;우리는&amp;nbsp;모두&amp;nbsp;같이&amp;nbsp;24시간을&amp;nbsp;받지만,&amp;nbsp;어떻게&amp;nbsp;사용하느냐에&amp;nbsp;따라&amp;nbsp;성과와&amp;nbsp;삶의&amp;nbsp;질은&amp;nbsp;극적으로&amp;nbsp;달라집니다.&amp;nbsp;급한&amp;nbsp;불을&amp;nbsp;끄느라&amp;nbsp;하루를&amp;nbsp;보낼&amp;nbsp;수도&amp;nbsp;있고,&amp;nbsp;장기적으로&amp;nbsp;가치&amp;nbsp;있는&amp;nbsp;일에&amp;nbsp;투자하여&amp;nbsp;미래를&amp;nbsp;준비할&amp;nbsp;수도&amp;nbsp;있습니다.&amp;nbsp;중요한&amp;nbsp;일에&amp;nbsp;우선순위를&amp;nbsp;두고,&amp;nbsp;하루를&amp;nbsp;계획적으로&amp;nbsp;설계하며,&amp;nbsp;한&amp;nbsp;번에&amp;nbsp;한&amp;nbsp;가지&amp;nbsp;일에&amp;nbsp;집중하는&amp;nbsp;습관은&amp;nbsp;쉽게&amp;nbsp;길러지지&amp;nbsp;않지만,&amp;nbsp;꾸준히&amp;nbsp;실천하면&amp;nbsp;분명히&amp;nbsp;삶을&amp;nbsp;바꿔놓습니다.&amp;nbsp;이제&amp;nbsp;소개한&amp;nbsp;원칙들을&amp;nbsp;바탕으로&amp;nbsp;작은&amp;nbsp;변화부터&amp;nbsp;시작해 보세요.&amp;nbsp;여러분의&amp;nbsp;시간&amp;nbsp;사용&amp;nbsp;방식이&amp;nbsp;서서히&amp;nbsp;달라지고,&amp;nbsp;바쁜&amp;nbsp;일정&amp;nbsp;속에서도&amp;nbsp;정말&amp;nbsp;중요한&amp;nbsp;목표들을&amp;nbsp;차근차근&amp;nbsp;달성해 나가는&amp;nbsp;자신을&amp;nbsp;발견할&amp;nbsp;수&amp;nbsp;있을&amp;nbsp;것입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>DailyRoutine</category>
      <category>개발자</category>
      <category>생산성</category>
      <category>시간관리</category>
      <category>업무</category>
      <category>업무순위</category>
      <category>업무효율</category>
      <category>우선순위</category>
      <category>자기관리</category>
      <category>직장생활</category>
      <category>집중</category>
      <author>간지뽕빨리턴님</author>
      <guid isPermaLink="true">https://odinbox.tistory.com/548</guid>
      <comments>https://odinbox.tistory.com/548#entry548comment</comments>
      <pubDate>Sat, 30 Aug 2025 17:14:05 +0900</pubDate>
    </item>
    <item>
      <title>오라클 DBLINK 사용방법</title>
      <link>https://odinbox.tistory.com/547</link>
      <description>&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;DBLINK의 개념과 필요성 이해하기&lt;/span&gt;&lt;/p&gt;
&lt;div class=&quot;txc-textbox&quot; style=&quot;font-weight: normal; position: relative; line-height: 40px; background: #007CBA; border: 1px solid #fff; padding: 10px; color: white; border-radius: 0 10px 0 10px; box-shadow: inset 0 0 5px rgba(53,86,129, 0.5); font-family: 'Muli', sans-serif; border-style: solid; border-width: 0px  0px  1px 15px; border-color: #232323; background-color: #007cba;&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-size: 15pt; color: #ffffff;&quot;&gt;&lt;b&gt;오라클 DBLINK에 대해서 알아봅시다!&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;글 상단 부분 대표 이미지 (7).png&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bEDFxM/btsP5EZpnVM/1Ln9fC6uFV6NSOpJ3YOelk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bEDFxM/btsP5EZpnVM/1Ln9fC6uFV6NSOpJ3YOelk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bEDFxM/btsP5EZpnVM/1Ln9fC6uFV6NSOpJ3YOelk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbEDFxM%2FbtsP5EZpnVM%2F1Ln9fC6uFV6NSOpJ3YOelk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;400&quot; data-filename=&quot;글 상단 부분 대표 이미지 (7).png&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;실무에서 단일 오라클 데이터베이스만 사용하는 경우보다 여러 종류의 DBMS(ORACLE, MYSQL, POSTGRESQL 등)을 함께 사용하는 경우가 많습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;예를 들어, 현재 시스템에서 타 시스템과 연계하여 자료를 보여주어야 하는 경우가 흔히 많이 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;이때 DBLINK(Database Link)기능과 게이트웨이(Database Gateway, ODBC 연동)을 활용하면 서로 다른 DB간에도 데이터를 연계할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;이번에는 오라클 DBLINK 개념과 설정 방법을 설명한 후 연결하는 방법등을 알아보려고 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;div class=&quot;txc-textbox&quot; style=&quot;border-style: solid; font-weight: bold; border-width: 1px  1px  1px 5px; border-color: #707070; background-color: #fff; padding: 10px;&quot;&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;https://tistory3.daumcdn.net/tistory/1569230/skin/images/jquery.toc.js&quot;&gt;&lt;/script&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;목차&lt;/p&gt;
&lt;ul id=&quot;toc&quot; style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;&lt;/ul&gt;
&lt;script type=&quot;text/javascript&quot;&gt;
$(function(){
	$(&quot;#toc&quot;).toc( {content: &quot;.tt_article_useless_p_margin&quot;, headings: &quot;h1,h2,h3,h4&quot; , top: -90, isBlink : true, blinkColor : '#21B9DE' } ) });
&lt;/script&gt;
&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;DBLINK&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;DBLINK란?&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;오라클 DB에서 원격 DB(SQL 실행대상)에 접근할 수 있게 해주는 객체입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;용도의 경우 원격 DB 테이블 조회 및 조작, 분산 트랜잭션 처리, 이기종 DB 통합 등의 용도가 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;오라클에서 오라클 DBLINK&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1755916205260&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;--생성 방법 1
CREATE DATABASE LINK remote_link
CONNECT TO remote_user IDENTIFIED BY password
USING 'tns_alias'; -- tnsnames.ora에 있는 이름과 맞춰야 함.

-- 생성 방법 2
CREATE DATABASE LINK remote_link
  CONNECT TO TEST
  IDENTIFIED BY &quot;비밀이다&quot;
  USING '(DESCRIPTION=
            (ADDRESS=(PROTOCOL=TCP)(HOST=127.0.0.1)(PORT=1521))
            (CONNECT_DATA=(SERVICE_NAME=TEST))
         )';

--확인 및 삭제
SELECT * FROM user_db_links;
DROP DATABASE LINK remote_link;&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;&quot;&gt;&lt;b&gt;PUBLIC DBLINK vs PRIVATE DBLINK&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Private DBLINK : 생성한 사용자만 사용가능&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Public DBLINK : 모든 사용자가 사용 가능 (보안 위협증가)&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;오라클에서 MYSQL DBLINK&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;오라클은 MYSQL과 직접 DBLINK라는 것을 지원하지 않습니다. 대신 Oracle Database Gateway for ODBC(DG4ODBC) 또는 hsodbc를 이용합니다.&lt;/span&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;1. ODBC 드라이버 설치&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;MYSQL ODBC 드라이버(Connector/ODBC) 설치&lt;/span&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;2. odbc.ini 등록 (Linux)&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1755916381700&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[mysql_dsn]
Driver=/usr/lib/libmyodbc5.so
Description=MySQL ODBC Driver
Server=127.0.0.1
Port=3306
Database=testdb
User=testuser
Password=testpwd&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;3. tnsnames.ora 등록&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1755916406743&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;MYSQL_DBLINK =
  (DESCRIPTION =
    (ADDRESS = (PROTOCOL=TCP)(HOST=127.0.0.1)(PORT=1521))
    (CONNECT_DATA = (SID=dg4odbc))
    (HS=OK)
  )&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;4. DBLINK 생성&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1755916421761&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;CREATE DATABASE LINK mysql_link
CONNECT TO &quot;testuser&quot; IDENTIFIED BY &quot;testpwd&quot;
USING 'MYSQL_DBLINK';&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;5. 조회 &amp;amp; 삭제&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1755917217519&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 조회
SELECT * FROM dba_db_links;
SELECT * FROM user_db_links;

-- 삭제
DROP DATABASE LINK remote_link;&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;6. 사용예시&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1755916441327&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT * FROM customers@mysql_link;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;오라클에서 PostgreSQL 연결&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;PostgreSQL도 동일하게 DG4ODBC또는 Oracle Gateway for ODBC를 활용합니다.&lt;/span&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;1. PostgreSQL ODBC 드라이버 설치&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;psqlODBC 설치&lt;/span&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;2. odbc.ini 등록&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1755916584630&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[pg_dsn]
Driver=/usr/lib/psqlodbcw.so
Description=PostgreSQL ODBC
Servername=127.0.0.1
Port=5432
Database=pgdb
Username=pguser
Password=pgpwd&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;3. tnsnames.ora 등록&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1755916595710&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;POSTGRES_DBLINK =
  (DESCRIPTION =
    (ADDRESS = (PROTOCOL=TCP)(HOST=127.0.0.1)(PORT=1521))
    (CONNECT_DATA = (SID=dg4odbc))
    (HS=OK)
  )&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;4. DBLINK 생성&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1755916610139&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;CREATE DATABASE LINK pg_link
CONNECT TO &quot;pguser&quot; IDENTIFIED BY &quot;pgpwd&quot;
USING 'POSTGRES_DBLINK';&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;5. 사용예시&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1755916622625&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT * FROM orders@pg_link;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;실제 운영 환경 문제&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;성능저하&lt;/b&gt; : 이기종 DB는 변환 오버헤드가 크므로 대량 데이터 전송 시 ETL 권장&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;문자셋 문자&lt;/b&gt; : MYSQL, POSTGRESQL에서 ORACLE 간 UTF-8에서 AL32UTF8 변환 오류 가능 -&amp;gt; HS_LANGUAGE 설정&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;트랜잭션 문제&lt;/b&gt; : 분산 트랜잭션은 안전성이 떨어지므로 단일 조회 용도로만 DBLINK 권장&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;DBLINK 사용 시 주의사항&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;성능 이슈&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;- 네트워크 지연 발생 가능&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;- 대량 데이터 전송 시 성능 저하&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;- JOIN 시 원격 DB에서 실행계획 차이 발생&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;보안 고려사항&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;- PUBLIC DBLINK 사용 최소화&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;- 비밀번호 암호화 문제 (12c 이후부터는 암호화 저장 지원)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;- 권한 분리 원칙 적용&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;대안 기술&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;- ORACLE GOLDENGATE - 실시간 복제&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;- ORACLE DATA GUARD - 고가용성 환경&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;- ETL 도구 - 대용량 데이터 이동&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;DBLINK 대안 기술&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;Oracle GoldenGate&lt;/b&gt; : 실시간 복제 (이기종 DB 지원)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;ETL 도구(Informatica, ODI 등)&lt;/b&gt; : 대용량 데이터 이동&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;Kafka + CDC&lt;/b&gt; : 실시간 데이터 스트리밍&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;마무리&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;DBLINK는 오라클간 연결뿐 아니라 MYSQL, POSTGRESQL 같은 이기종 DB 연결에도 활용 가능합니다. 하지만 이기종 DB 연결은 성능 저하, 문자셋, 트랜잭션 제약이 있으므로 소규모 조회, 연계 용도에 적합합니다. 운영환경에서는 DBLINK를 남용하기보다 데이터복제-ETL-CDC 같은 전문 솔루션과 함께 고려하는 것이 바람직합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>DEVELOPMENT</category>
      <category>DBLink</category>
      <category>DB연동</category>
      <category>MYSQL</category>
      <category>ODBC</category>
      <category>Oracle</category>
      <category>PostgreSQL</category>
      <category>분산트랜잭션</category>
      <category>성능최적화</category>
      <category>이기종DB</category>
      <category>인터페이스</category>
      <author>간지뽕빨리턴님</author>
      <guid isPermaLink="true">https://odinbox.tistory.com/547</guid>
      <comments>https://odinbox.tistory.com/547#entry547comment</comments>
      <pubDate>Sat, 23 Aug 2025 11:56:14 +0900</pubDate>
    </item>
    <item>
      <title>코닥 미니 3 레트로 P300R 알아보자!</title>
      <link>https://odinbox.tistory.com/546</link>
      <description>&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;스마트폰에서 찍은 사진을 레트로 감성으로 인쇄하는 P300R&lt;/span&gt;&lt;/p&gt;
&lt;div class=&quot;txc-textbox&quot; style=&quot;font-weight: normal; position: relative; line-height: 40px; background: #007CBA; border: 1px solid #fff; padding: 10px; color: white; border-radius: 0 10px 0 10px; box-shadow: inset 0 0 5px rgba(53,86,129, 0.5); font-family: 'Muli', sans-serif; border-style: solid; border-width: 0px  0px  1px 15px; border-color: #232323; background-color: #007cba;&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-size: 15pt; color: #ffffff;&quot;&gt;&lt;b&gt;휴대용 포토프린터 코닥 미니 3 레트로 P300R을 알아보자!&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;글 상단 부분 대표 이미지 (6).png&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kxs23/btsPWjOD5g7/bRkjUuyAV1HNTZGtMKGxWK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kxs23/btsPWjOD5g7/bRkjUuyAV1HNTZGtMKGxWK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kxs23/btsPWjOD5g7/bRkjUuyAV1HNTZGtMKGxWK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fkxs23%2FbtsPWjOD5g7%2FbRkjUuyAV1HNTZGtMKGxWK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;400&quot; data-filename=&quot;글 상단 부분 대표 이미지 (6).png&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;사진 찍는 것을 좋아하다 보니 수많은 사진을 찍는 것도 좋지만 정작 인쇄해서 보관하는 경우는 많지 않습니다. 어릴 때는 필름카메라로 촬영하고 사진관에서 인쇄를 하고 보관했었는데 스마트폰으로 저장을 하니 이젠 그런 경우가 많진 않은 듯합니다. 그래서 사진으로 보관도 하고 싶다는 생각으로 포토프린터를 알아보다가 레트로 감성이 물씬 나는 코닥 미니 3 레트로 P300R을 구매했습니다. 이 제품은 (3x3 인치) 정사각형 사진을 블루투스로 인쇄할 수 있고 코닥만의 4PASS 염료승화 방식으로 선명한 색감을 구현한다는 점이 인상적입니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;div class=&quot;txc-textbox&quot; style=&quot;border-style: solid; font-weight: bold; border-width: 1px  1px  1px 5px; border-color: #707070; background-color: #fff; padding: 10px;&quot;&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;https://tistory3.daumcdn.net/tistory/1569230/skin/images/jquery.toc.js&quot;&gt;&lt;/script&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;목차&lt;/p&gt;
&lt;ul id=&quot;toc&quot; style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;&lt;/ul&gt;
&lt;script type=&quot;text/javascript&quot;&gt;
$(function(){
	$(&quot;#toc&quot;).toc( {content: &quot;.tt_article_useless_p_margin&quot;, headings: &quot;h1,h2,h3,h4&quot; , top: -90, isBlink : true, blinkColor : '#21B9DE' } ) });
&lt;/script&gt;
&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;코닥미니3레트로P300R&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;패키지 구성&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/brbl1k/btsPTL7d94D/ERkCljwTKOI3rygX9IKMqK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/brbl1k/btsPTL7d94D/ERkCljwTKOI3rygX9IKMqK/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot; data-filename=&quot;blob&quot; style=&quot;width: 32.5581%; margin-right: 10px;&quot; data-widthpercent=&quot;33.33&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/brbl1k/btsPTL7d94D/ERkCljwTKOI3rygX9IKMqK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbrbl1k%2FbtsPTL7d94D%2FERkCljwTKOI3rygX9IKMqK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lrvq3/btsPUgSYeyq/MSRAl0aJ8OoyKivxDRFIgK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lrvq3/btsPUgSYeyq/MSRAl0aJ8OoyKivxDRFIgK/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot; data-filename=&quot;blob&quot; style=&quot;width: 32.5581%; margin-right: 10px;&quot; data-widthpercent=&quot;33.33&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lrvq3/btsPUgSYeyq/MSRAl0aJ8OoyKivxDRFIgK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Flrvq3%2FbtsPUgSYeyq%2FMSRAl0aJ8OoyKivxDRFIgK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FdwGQ/btsPUIPtfXM/iaDRtpVKccmEfBrgBcRkd0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FdwGQ/btsPUIPtfXM/iaDRtpVKccmEfBrgBcRkd0/img.png&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot; data-is-animation=&quot;false&quot; data-filename=&quot;blob&quot; style=&quot;width: 32.5581%;&quot; data-widthpercent=&quot;33.34&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FdwGQ/btsPUIPtfXM/iaDRtpVKccmEfBrgBcRkd0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFdwGQ%2FbtsPUIPtfXM%2FiaDRtpVKccmEfBrgBcRkd0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;제품이 들어가 있는 박스 사진&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/KJIdM/btsPTW8wn28/1lKe2SkuXIp8XNlMVfZsN0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/KJIdM/btsPTW8wn28/1lKe2SkuXIp8XNlMVfZsN0/img.png&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot; data-is-animation=&quot;false&quot; data-filename=&quot;blob&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/KJIdM/btsPTW8wn28/1lKe2SkuXIp8XNlMVfZsN0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKJIdM%2FbtsPTW8wn28%2F1lKe2SkuXIp8XNlMVfZsN0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bRXFO8/btsPSPaYmn4/BWKwRN34pZdlV2Lzsp61M0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bRXFO8/btsPSPaYmn4/BWKwRN34pZdlV2Lzsp61M0/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot; data-filename=&quot;blob&quot; style=&quot;width: 49.4186%;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bRXFO8/btsPSPaYmn4/BWKwRN34pZdlV2Lzsp61M0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbRXFO8%2FbtsPSPaYmn4%2FBWKwRN34pZdlV2Lzsp61M0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/TrNSE/btsPTFTgTiO/ctHI39wylvUWIihmo6BBKK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/TrNSE/btsPTFTgTiO/ctHI39wylvUWIihmo6BBKK/img.png&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot; data-is-animation=&quot;false&quot; data-filename=&quot;blob&quot; style=&quot;width: 32.5581%; margin-right: 10px; margin-top: 10px;&quot; data-widthpercent=&quot;33.33&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/TrNSE/btsPTFTgTiO/ctHI39wylvUWIihmo6BBKK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FTrNSE%2FbtsPTFTgTiO%2FctHI39wylvUWIihmo6BBKK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cEOKMM/btsPTbx3hDi/112TmQxi7OQHBk9NNw8JN0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cEOKMM/btsPTbx3hDi/112TmQxi7OQHBk9NNw8JN0/img.png&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot; data-is-animation=&quot;false&quot; data-filename=&quot;blob&quot; style=&quot;width: 32.5581%; margin-right: 10px; margin-top: 10px;&quot; data-widthpercent=&quot;33.33&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cEOKMM/btsPTbx3hDi/112TmQxi7OQHBk9NNw8JN0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcEOKMM%2FbtsPTbx3hDi%2F112TmQxi7OQHBk9NNw8JN0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cI6FcJ/btsPViCEuZX/5lKJe4SW5remtTVNCpUV1k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cI6FcJ/btsPViCEuZX/5lKJe4SW5remtTVNCpUV1k/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot; data-filename=&quot;blob&quot; style=&quot;width: 32.5581%; margin-top: 10px;&quot; data-widthpercent=&quot;33.34&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cI6FcJ/btsPViCEuZX/5lKJe4SW5remtTVNCpUV1k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcI6FcJ%2FbtsPViCEuZX%2F5lKJe4SW5remtTVNCpUV1k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;제품 박스 모습&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bL4j7A/btsPWgxCgw8/12pJ9K46imY9sP7QRKsse0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bL4j7A/btsPWgxCgw8/12pJ9K46imY9sP7QRKsse0/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot; data-filename=&quot;blob&quot; style=&quot;width: 32.5581%; margin-right: 10px;&quot; data-widthpercent=&quot;33.33&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bL4j7A/btsPWgxCgw8/12pJ9K46imY9sP7QRKsse0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbL4j7A%2FbtsPWgxCgw8%2F12pJ9K46imY9sP7QRKsse0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oI4uG/btsPUnrhqPq/EIRs9lmo8323Tx3EKkTly1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oI4uG/btsPUnrhqPq/EIRs9lmo8323Tx3EKkTly1/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot; data-filename=&quot;blob&quot; style=&quot;width: 32.5581%; margin-right: 10px;&quot; data-widthpercent=&quot;33.33&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oI4uG/btsPUnrhqPq/EIRs9lmo8323Tx3EKkTly1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoI4uG%2FbtsPUnrhqPq%2FEIRs9lmo8323Tx3EKkTly1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dYumSu/btsPUDUUkyD/HPpr459EBajCV5QH0pAFKK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dYumSu/btsPUDUUkyD/HPpr459EBajCV5QH0pAFKK/img.png&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot; data-is-animation=&quot;false&quot; data-filename=&quot;blob&quot; style=&quot;width: 32.5581%;&quot; data-widthpercent=&quot;33.34&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dYumSu/btsPUDUUkyD/HPpr459EBajCV5QH0pAFKK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdYumSu%2FbtsPUDUUkyD%2FHPpr459EBajCV5QH0pAFKK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;구성품 및 포토프린터 본체 모습&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;먼저 박스를 살펴보면 깔끔한 상자로 되어 있고 제품 이미지와 주요 특징이 있습니다. 상자를 열면 포토프린터 본체, 사용 설명서가 포함되어 있습니다. 모든 구성품이 깔끔하게 포장되어 있어 선물용으로도 좋습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;디자인 및 휴대성&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/NQ3TG/btsPVhcEOjc/qcPDC8M6ZDoyTK1k2daOoK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/NQ3TG/btsPVhcEOjc/qcPDC8M6ZDoyTK1k2daOoK/img.png&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot; data-is-animation=&quot;false&quot; data-filename=&quot;blob&quot; style=&quot;width: 32.5581%; margin-right: 10px;&quot; data-widthpercent=&quot;33.33&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/NQ3TG/btsPVhcEOjc/qcPDC8M6ZDoyTK1k2daOoK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNQ3TG%2FbtsPVhcEOjc%2FqcPDC8M6ZDoyTK1k2daOoK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/daC1Py/btsPURk0KEE/nyEQmI0HDZP43EtgKT8ln1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/daC1Py/btsPURk0KEE/nyEQmI0HDZP43EtgKT8ln1/img.png&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot; data-is-animation=&quot;false&quot; data-filename=&quot;blob&quot; style=&quot;width: 32.5581%; margin-right: 10px;&quot; data-widthpercent=&quot;33.33&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/daC1Py/btsPURk0KEE/nyEQmI0HDZP43EtgKT8ln1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdaC1Py%2FbtsPURk0KEE%2FnyEQmI0HDZP43EtgKT8ln1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/btmqWa/btsPUV8QIzs/rlfCz5NknquD43JC5uJYP0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/btmqWa/btsPUV8QIzs/rlfCz5NknquD43JC5uJYP0/img.png&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot; data-is-animation=&quot;false&quot; data-filename=&quot;blob&quot; style=&quot;width: 32.5581%;&quot; data-widthpercent=&quot;33.34&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/btmqWa/btsPUV8QIzs/rlfCz5NknquD43JC5uJYP0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbtmqWa%2FbtsPUV8QIzs%2FrlfCz5NknquD43JC5uJYP0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/PTVxA/btsPWpVAwX7/C1D3VBvSpIfex0cogVyXK1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/PTVxA/btsPWpVAwX7/C1D3VBvSpIfex0cogVyXK1/img.png&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot; data-is-animation=&quot;false&quot; data-filename=&quot;blob&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/PTVxA/btsPWpVAwX7/C1D3VBvSpIfex0cogVyXK1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FPTVxA%2FbtsPWpVAwX7%2FC1D3VBvSpIfex0cogVyXK1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/clM0a7/btsPVfeR4Zw/t0kgBDBQ45qb9XrhlfqXtk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/clM0a7/btsPVfeR4Zw/t0kgBDBQ45qb9XrhlfqXtk/img.png&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot; data-is-animation=&quot;false&quot; data-filename=&quot;blob&quot; style=&quot;width: 49.4186%;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/clM0a7/btsPVfeR4Zw/t0kgBDBQ45qb9XrhlfqXtk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FclM0a7%2FbtsPVfeR4Zw%2Ft0kgBDBQ45qb9XrhlfqXtk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;P300R 본체는 화이트, 옐로우, 블랙 총 세가지 색상으로 출시되며 저는 클래식한 옐로우 색상을 선택을 했습니다. 크기는 약 134 104 x 30mm, 무게는 370g으로 한 손에 잡히는 크기라 가방이나 파우치에 쏙 들어갑니다. 상단엔 전원 버튼과 상태 LED가 측면에 충전 포트와 카트리지 삽입구가 있어 조작이 간단합니다. 내부에는 충전 가능한 리튬이온배터리가 탑재되어 있으며 90분 충전으로 약 20장 사진을 출력할 수 있다는 점도 매력적입니다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;연결 및 사용방법&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bxLNTz/btsPUf7ymsO/1a9qTlFQbN0k1XX0j7L3ak/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bxLNTz/btsPUf7ymsO/1a9qTlFQbN0k1XX0j7L3ak/img.png&quot; data-origin-width=&quot;1007&quot; data-origin-height=&quot;1454&quot; data-is-animation=&quot;false&quot; data-filename=&quot;blob&quot; style=&quot;width: 56.9594%; margin-right: 10px;&quot; data-widthpercent=&quot;57.63&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bxLNTz/btsPUf7ymsO/1a9qTlFQbN0k1XX0j7L3ak/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbxLNTz%2FbtsPUf7ymsO%2F1a9qTlFQbN0k1XX0j7L3ak%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1007&quot; height=&quot;1454&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ccL8Mz/btsPUV8QPGH/3EnU6Shs6G6Qrg9VQFrpcK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ccL8Mz/btsPUV8QPGH/3EnU6Shs6G6Qrg9VQFrpcK/img.png&quot; data-origin-width=&quot;720&quot; data-origin-height=&quot;1414&quot; data-is-animation=&quot;false&quot; data-filename=&quot;blob&quot; style=&quot;width: 41.8778%;&quot; data-widthpercent=&quot;42.37&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ccL8Mz/btsPUV8QPGH/3EnU6Shs6G6Qrg9VQFrpcK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FccL8Mz%2FbtsPUV8QPGH%2F3EnU6Shs6G6Qrg9VQFrpcK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;720&quot; height=&quot;1414&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dRGu9T/btsPS8g1cj5/iaXBfH8kHnAheyy6a364W0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dRGu9T/btsPS8g1cj5/iaXBfH8kHnAheyy6a364W0/img.png&quot; data-origin-width=&quot;720&quot; data-origin-height=&quot;1414&quot; data-is-animation=&quot;false&quot; data-filename=&quot;blob&quot; style=&quot;width: 49.4186%; margin-right: 10px; margin-top: 10px;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dRGu9T/btsPS8g1cj5/iaXBfH8kHnAheyy6a364W0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdRGu9T%2FbtsPS8g1cj5%2FiaXBfH8kHnAheyy6a364W0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;720&quot; height=&quot;1414&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Rlsan/btsPVWzoOUQ/4lUTeWxBNkZR2Wp8EMQfVk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Rlsan/btsPVWzoOUQ/4lUTeWxBNkZR2Wp8EMQfVk/img.png&quot; data-origin-width=&quot;720&quot; data-origin-height=&quot;1414&quot; data-is-animation=&quot;false&quot; data-filename=&quot;blob&quot; style=&quot;width: 49.4186%; margin-top: 10px;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Rlsan/btsPVWzoOUQ/4lUTeWxBNkZR2Wp8EMQfVk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FRlsan%2FbtsPVWzoOUQ%2F4lUTeWxBNkZR2Wp8EMQfVk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;720&quot; height=&quot;1414&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;전원을 켜고 스마트폰에서 KODAK PHOTO PRINTER 앱을 설치합니다. 앱에서 블루투스를 통해 P300R을 선택을 하면 연결이 완료됩니다. 사진을 불러와 간단한 편집 기능(필터, 프레임, 스티커 등)을 적용한 뒤 인쇄 버튼을 누르면 즉시 출력이 됩니다. 4PASS 염료승화 방식은 CMYK 네 번의 전사 과정을 거쳐 색을 쌓아 올린 후 마지막에 보호 라미네이션을 입히는데 덕분에 사진이 번지거나 물에 젖는 것을 방지해 줍니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;출력 과정은 약 1분 정도 걸리며 사진이 카트리지에 네번 왕복하며 서서히 완성되는 모습이 재미있습니다. 앱과 연동이 직관적이라 누구나 쉽게 사용할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;인쇄 품질&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;P300R은 291x300 dpi 해상도로 3x3인치 사진을 인쇄합니다. 출력된 사진은 색감이 깊고 선명하며 라미네이션 처리 덕분에 지문이 묻지 않고 오래 보존을 할 수 있습니다. 종이 표면은 일반 포토 페이퍼처럼 매끈하면서도 적당한 두께감을 제공합니다. 또한 사진 뒷면에 접착제가 없는 비접착식 용지를 사용하기 때문에 스크랩북이나 앨범에 끼우기 좋습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d53PzQ/btsPTaFWLTc/4yc2gayuZcK4X04LZh8ahK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d53PzQ/btsPTaFWLTc/4yc2gayuZcK4X04LZh8ahK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d53PzQ/btsPTaFWLTc/4yc2gayuZcK4X04LZh8ahK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd53PzQ%2FbtsPTaFWLTc%2F4yc2gayuZcK4X04LZh8ahK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;제품 스펙 및 특징&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;출력 : 코닥 4PASS 염료승화 방식&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;해상도/출력 크기 : 291 * 300dpi / 3 * 3 인치&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;호환 OS 및 연결 : iOS, Android 스마트폰과 블루투스 연결&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;사진 용지 : 단면, 비접착식 포토페이퍼&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;크기 / 무게 : 약 134 * 104 * 30mm / 370g&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;배터리 : 리튬이온내장, 완충까지 약 90분 / 한번 충전으로 약 20장 출력&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;전용 앱 : KODAK PHOTO PRINTER 앱을 통해 간단한 편집 및 인쇄 관리 가능&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;이 제품을 사용하면서 느낀 가장 큰 장점은 휴대성과 출력 품질의 균형입니다. 여행이나 행사에서 사진을 바로 뽑아 나눠주면 분위기가 더 좋아지고 폴라로이드 감성의 네모난 사진이 소장 가치를 높여 줍니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;마무리&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;코닥 미니 3 레트로 P300R은 스마트폰에 저장된 추억을 실물로 만들어 주는 훌륭한 도구였습니다. 간편한 블루투스 연결과 감성적인 3*3인치 사진, 4PASS 염료승화 방식의 높은 품질 덕분에 출력물이 오래도록 깨끗하게 보존됩니다. 다만 정사각형 전용이라 사진 비율에 제약이 있고, 4PASS 방식 특성상 인쇄 시간이 약간 길게 느껴질 수 있습니다. 그럼에도 불구하고 핸드폰 속 사진을 실물로 간직하고 싶은 분들에게는 강력히 추천할 만한 포토프린터입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>IT/Product</category>
      <category>4PASS</category>
      <category>P300R</category>
      <category>레트로감성</category>
      <category>사진인화</category>
      <category>스마트폰프린터</category>
      <category>언박싱</category>
      <category>코닥미니3레트로</category>
      <category>코닥포토프린터</category>
      <category>포트프린터추천</category>
      <category>휴대용프린터</category>
      <author>간지뽕빨리턴님</author>
      <guid isPermaLink="true">https://odinbox.tistory.com/546</guid>
      <comments>https://odinbox.tistory.com/546#entry546comment</comments>
      <pubDate>Sat, 16 Aug 2025 10:07:02 +0900</pubDate>
    </item>
    <item>
      <title>양자컴퓨팅과 엣지컴퓨팅, 암호화/신약 개발/자율주행스마트팩토리를 뒤흔드는 두 축의 기술</title>
      <link>https://odinbox.tistory.com/545</link>
      <description>&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;암호화/신약 개발/자율주행,스마트팩토리를 바꾸는 차세대 컴퓨팅 패러다임&lt;/span&gt;&lt;/p&gt;
&lt;div class=&quot;txc-textbox&quot; style=&quot;font-weight: normal; position: relative; line-height: 40px; background: #007CBA; border: 1px solid #fff; padding: 10px; color: white; border-radius: 0 10px 0 10px; box-shadow: inset 0 0 5px rgba(53,86,129, 0.5); font-family: 'Muli', sans-serif; border-style: solid; border-width: 0px  0px  1px 15px; border-color: #232323; background-color: #007cba;&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-size: 15pt; color: #ffffff;&quot;&gt;&lt;b&gt;양자컴퓨팅/엣지컴퓨팅, 미래 산업 혁신의 두 축&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;글 상단 부분 대표 이미지 (5).png&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c88wcd/btsPMVagHAt/VglAThLGEguPAjk6J29V81/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c88wcd/btsPMVagHAt/VglAThLGEguPAjk6J29V81/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c88wcd/btsPMVagHAt/VglAThLGEguPAjk6J29V81/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc88wcd%2FbtsPMVagHAt%2FVglAThLGEguPAjk6J29V81%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;400&quot; data-filename=&quot;글 상단 부분 대표 이미지 (5).png&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;인공지능, 5G, IoT 등 다양한 기술이 쏟아지고 있는 가운데 양자컴퓨팅과 엣지컴퓨팅은 2025년을 대표하는 키워드로 꼽힙니다. 양자컴퓨터는 양자역학의 특성을 활용하여 기존 컴퓨터가 수백 년 걸릴 문제를 해결할 잠재력을 지니고 있으며 엣지컴퓨팅은 데이터 처리 위치를 사용자와 장치 가까이로 옮겨 실시간 반응을 가능하게 합니다. 이번에 알아볼 것은 이 두 기술의 원리와 실제 적용 사례를 살펴보고 앞으로 가능성 등을 알아보려고 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;div class=&quot;txc-textbox&quot; style=&quot;border-style: solid; font-weight: bold; border-width: 1px  1px  1px 5px; border-color: #707070; background-color: #fff; padding: 10px;&quot;&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;https://tistory3.daumcdn.net/tistory/1569230/skin/images/jquery.toc.js&quot;&gt;&lt;/script&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;목차&lt;/p&gt;
&lt;ul id=&quot;toc&quot; style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;&lt;/ul&gt;
&lt;script type=&quot;text/javascript&quot;&gt;
$(function(){
	$(&quot;#toc&quot;).toc( {content: &quot;.tt_article_useless_p_margin&quot;, headings: &quot;h1,h2,h3,h4&quot; , top: -90, isBlink : true, blinkColor : '#21B9DE' } ) });
&lt;/script&gt;
&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;양자컴퓨팅과 엣지컴퓨팅&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;양자컴퓨팅의 원리, 비트에서 큐비트로&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;360&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/biw7OU/btsPL4lfWA5/fVFkPjPQNEsFBE9tbfVQy0/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/biw7OU/btsPL4lfWA5/fVFkPjPQNEsFBE9tbfVQy0/img.webp&quot; data-alt=&quot;(C) 최초 양자컴퓨팅 IBM&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/biw7OU/btsPL4lfWA5/fVFkPjPQNEsFBE9tbfVQy0/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbiw7OU%2FbtsPL4lfWA5%2FfVFkPjPQNEsFBE9tbfVQy0%2Fimg.webp&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;800&quot; height=&quot;360&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;360&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;(C) 최초 양자컴퓨팅 IBM&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;center&gt;&lt;iframe src=&quot;https://www.youtube-nocookie.com/embed/7XU_S-ZhyNA?si=SAnQzx1d64MtkrMD&quot; width=&quot;560&quot; height=&quot;315&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;&lt;/center&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;비트 vs 규비트&lt;/b&gt; : 전통적인 컴퓨터는 0 또는 1을 표현하는 비트(bit)로 데이터를 처리합니다. 반면 양자컴퓨터는 큐비트(qubit)라는 단위를 사용합니다. 큐비트는 중첩 상태에 있어 0과 1을 동시에 표현할 수 있고 여러 큐비트가 서로 얽힘을 통해 연결되면 데이터를 기하급수적으로 병렬 처리할 수 있습니다. 이는 동시에 여러 계산 경로를 탐색할 수 있다는 의미이며 복잡한 문제를 빠르게 해결할 잠재력을 제공합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;양자컴퓨터의 강점과 한계&lt;/b&gt; : 양자컴퓨터는 기후 모델링, 물질과학, 금융 시뮬레이션과 같이 변수 수가 많은 문제를 빠르게 해결할 수 있습니다. 그러나 현재의 양자컴퓨터는 물리적 오차율이 높고 큐비트 수가 제한적이며 초저온 등 특수한 환경이 필요합니다. 따라서 양자컴퓨팅과 고전 컴퓨팅의 협력이 중요하며 향후 몇 년간 두 시스템이 병행되어 사용될 가능성이 큽니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;양자컴퓨팅과 암호화, 보안 생태계의 도전과 변화&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;RSA와 소인수분해&lt;/b&gt; : 인터넷 보안의 핵심은 두 소수의 곱으로 이루어진 큰 수를 소인수분해하기 어렵다는 사실에 기반합니다. 양자컴퓨터는 쇼어(Shor) 알고리즘을 사용해 이러한 대형 수를 빠르게 소인수분해할 수 있어 현존 암호 체계를 위협할 잠재력을 지니고 있습니다. 양자컴퓨터가 실용적 규모에 도달하면 기존의 공개키 암호(RSA, ECC 등)가 무력화될 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;포스트 양자 암호와 양자통신&lt;/b&gt; : 이 위협에 대비해 포스트 양자 암호(PQC)가 연구되고 있으며 양자컴퓨터로도 풀기 어려운 새로운 수학적 문제를 기반으로 한 암호 방식이 개발 중입니다. 또한 양자통신(QComm)은 양자얽힘을 이용해 정보를 전달하는 기술로 도청이 불가능한 완벽한 암호화 채널을 제공할 수 있어 큰 주목을 받고 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;보안 생태계의 변화&lt;/b&gt; : 현재는 양자컴퓨터가 암호화 체계를 완전히 무너뜨릴 정도의 성능을 갖추지 못했습니다. 하지만 전문가들은 2020년대 후반부터 2030년대 초반쯤 그런 수준에 도달할 수 있다고 전망하여 정부와 기업들은 데이터와 시스템을 보호하기 위해 준비하고 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;약물 개발과 양자 시뮬레이션, 분자를 이해하는 새로운 방법&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;분자 구조 시뮬레이션의 한계 : 신약 개발에서 핵심은 약물 후보 물질이 생체 환경에서 어떻게 작용할지 예측하는 것입니다. 기존 컴퓨터는 각 원자의 상호작용을 모두 시뮬레이션하기 어렵기 때문에 계산에 막대한 시간과 비용이 듭니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;양자 시뮬레이션의 가능성 : 양자컴퓨터는 복잡한 분자 구조를 직접 모사할 수 있어 분자의 에너지 상태와 상호작용을 정확히 계산할 잠재력을 갖고 있습니다. 맥킨지 보고서는 양자컴퓨팅이 복잡한 분자 모델링을 가능하게 함으로써 신약 개발 속도를 빠르게 하고 기존에 찾기 어려웠던 치료법을 발견하는데 동무을 줄 수 있다고 분석합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;의료 외 응용 : 양자컴퓨팅은 배터리 소재 개발, 금융 포트폴리오 최적화 등 다른 분야에서도 활용 가능성이 큽니다. 아직 초기 단계이지만 실용적인 애플리케이션이 등장할 경우 산업 전반에 파급력을 미칠 것입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;엣지 컴퓨팅, 자율주행과 스마트팩토리를 이끄는 실시간 처리의 힘&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;center&gt;&lt;iframe src=&quot;https://www.youtube-nocookie.com/embed/SxDLDKs5zLA?si=nplb1bU1sPO5H8CC&quot; width=&quot;560&quot; height=&quot;315&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;&lt;/center&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;820&quot; data-origin-height=&quot;350&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/OVhU9/btsPOqAwQFJ/YoVOhmKVr57k5U3kNlhvXk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/OVhU9/btsPOqAwQFJ/YoVOhmKVr57k5U3kNlhvXk/img.jpg&quot; data-alt=&quot;(C) 아마존(Amazone) 클라우드와 엣지 관련 개념도&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/OVhU9/btsPOqAwQFJ/YoVOhmKVr57k5U3kNlhvXk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOVhU9%2FbtsPOqAwQFJ%2FYoVOhmKVr57k5U3kNlhvXk%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;820&quot; height=&quot;350&quot; data-origin-width=&quot;820&quot; data-origin-height=&quot;350&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;(C) 아마존(Amazone) 클라우드와 엣지 관련 개념도&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;엣지컴퓨팅의 개념&lt;/b&gt; : 기존 클라우드 컴퓨팅이 중앙 데이터센터에서 대량의 데이터를 처리하는 것과 달리 엣지 컴퓨팅은 데이터를 생성하는 곳 근처에서 처리합니다. 이 방식은 지연을 줄이고 대역폭을 아낄 수 있어 실시간 의사결정이 필요한 분야에서 매우 중요합니다.&lt;/span&gt;&lt;/p&gt;
&lt;center&gt;&lt;iframe src=&quot;https://www.youtube-nocookie.com/embed/k3Ox5GEax6w?si=rJNkuOl-d_ZswX7A&quot; width=&quot;560&quot; height=&quot;315&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;&lt;/center&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;자율주행차의 핵심 인프라&lt;/b&gt; : 자율주행 차량 한 대는 하루에 30TB 이상 데이터를 생성합니다. 이 데이터를 클라우드로 모두 전송하면 지연이 발생하여 안전에 치명적입니다. 엣지 컴퓨팅은 차량 자체에서 데이터 분석과 의사결정을 수행하여 도로상황, 날씨, 교통정보 등을 실시간으로 처리하고 다른 차량과 정보를 교환하여 사고를 예방합니다. 0.1초의 지연이 생명과 직결될 수 있는 환경에서 엣지컴퓨팅은 필수적입니다.&lt;/span&gt;&lt;/p&gt;
&lt;center&gt;&lt;iframe src=&quot;https://www.youtube-nocookie.com/embed/oIaZYfRdRyw?si=_iMgZtrjRuXuVQbF&quot; width=&quot;560&quot; height=&quot;315&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;&lt;/center&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;스마트팩토리와 산업 IoT&lt;/b&gt; : 제조업에서 엣지컴퓨팅은 로봇 제어, 품질검사, 예측 유지보수 등에 사용됩니다. 이 기술을 통해 공장 내부의 다양한 센서와 기계가 발생시키는 데이터를 즉시 분석해 불량품을 잡아내고 기계 이상 징후를 초기에 감지할 수 있습니다. 분산된 생산 설비가 각자 데이터를 처리하면서도 네트워크를 통해 서로 동기화되기 때문에 생사라인을 더욱 유연하고 효율적으로 운영할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;center&gt;&lt;iframe src=&quot;https://www.youtube-nocookie.com/embed/e2wbyUY7AdU?si=Jimpcstj7qKvla0v&quot; width=&quot;560&quot; height=&quot;315&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;&lt;/center&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;5G와 AI의 시너지&lt;/b&gt; : 5G 네트워크의 확산과 IoT 기기의 증가로 기업 데이터의 75%가 엣지에서 처리될 것으로 예측됩니다. 엣지 단에서 AI 모델을 실행하면 위협 탐지나 예측 분석을 실시간으로 수행할 수 있어 스마트 헬스케어, 도시 인프라, 에너지 관리 등 다양한 분야에서도 활용도가 높습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;마무리&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;양자컴퓨팅과 엣지컴퓨팅은 각각 다른 방향에서 컴퓨팅 패러다임의 혁신을 이끌고 있습니다. 양자컴퓨터는 현재의 한계를 뛰어넘어 암호화, 최적화, 과학연구를 근본적으로 바꿀 가능성을 지니고 있으며 엣지컴퓨팅은 데이터 처리 위치를 이동시켜 자율주행, 스마트팩토리, IoT 등 실시간 의사결정이 필요한 영역을 활성화하고 있습니다. 두 기술은 아직 완전한 상용화 단계에 이르지는 않았지만 관련 인프라와 보안 체계의 변화가 빠르게 진행되고 있습니다. 개발자와 기술 기업들은 포스트 양자 암호, 엣지 보안, 적절한 데이터 분산 전략을 고만하며 이러한 변화에 대비하고 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;미래에는 양자컴퓨팅과 엣지컴퓨팅이 서로 보완되어 새로운 서비스를 창출할 가능성도 있습니다. 예를 들어 양자컴퓨터에서 생성한 대규모 모델을 엣지에서 빠르게 활용하거나 엣지 기기에서 수집한 데이터를 양자 알고리즘으로 분석할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>IT</category>
      <category>5G</category>
      <category>IOT</category>
      <category>기술트렌드</category>
      <category>보안</category>
      <category>스마트팩토리</category>
      <category>신약개발</category>
      <category>양자컴퓨팅</category>
      <category>엣지컴퓨팅</category>
      <category>자율주행</category>
      <category>포스트양자암호</category>
      <author>간지뽕빨리턴님</author>
      <guid isPermaLink="true">https://odinbox.tistory.com/545</guid>
      <comments>https://odinbox.tistory.com/545#entry545comment</comments>
      <pubDate>Sat, 9 Aug 2025 21:50:18 +0900</pubDate>
    </item>
    <item>
      <title>울산&amp;rarr;임진각&amp;rarr;고성&amp;rarr;울산, 분단을 마주한 뜨거운 여름여행</title>
      <link>https://odinbox.tistory.com/544</link>
      <description>&lt;!-- ===================== SAFE &amp; RESPONSIVE (TinyMCE/Tistory OK) — No JS / No JSON ===================== --&gt;
&lt;div&gt;
&lt;style&gt;
/* 본문 전용 스코프 */
.t-post{color:#0f172a;line-height:1.85;font-size:16.5px}
.t-post *{box-sizing:border-box}
.t-post h1{font-size:clamp(26px,3.2vw,34px);font-weight:800;margin:8px 0 12px;letter-spacing:-.2px}
.t-post h2{font-size:clamp(20px,2.5vw,26px);font-weight:800;margin:32px 0 12px}
.t-post h3{font-size:clamp(18px,2.1vw,22px);font-weight:700;margin:24px 0 10px}
.t-post p{margin:14px 0;word-break:keep-all}
.t-post img{max-width:100%;height:auto;border-radius:12px}
.t-post .lead{color:#475569;font-size:15px;margin-top:-4px}
.t-post .callout{border-left:6px solid #232323;background:#007cba;color:#fff;padding:14px 18px;border-radius:12px;margin:18px 0}
.t-post .toc{border:1px solid #e5e7eb;border-left:5px solid #0ea5e9;border-radius:10px;padding:12px 16px;background:#f8fafc;margin:18px 0}
.t-post .toc h4{margin:0 0 6px;font-size:16px;font-weight:800}
.t-post .toc a{color:#0ea5e9;text-decoration:none}
.t-post .toc a:hover{text-decoration:underline}
/* 반응형 임베드(유튜브/지도) — iframe 내용은 절대 수정 안 함 */
.t-embed{position:relative;width:100%;padding-top:56.25%;border-radius:14px;overflow:hidden;box-shadow:0 10px 30px rgba(2,14,40,.08);margin:16px 0}
.t-embed &gt; iframe{position:absolute;inset:0;width:100%;height:100%;border:0}
/* 토큰 그리드 간격 정리 */
.t-post [data-widthpercent]{vertical-align:top;margin-bottom:10px}
.t-post [style*=&quot;margin-right: 10px&quot;]{margin-right:10px}
/* 인용/구분선 */
.t-post blockquote{margin:20px 0;padding:14px 18px;background:#f0f9ff;border-left:4px solid #007cba;border-radius:10px;color:#0369a1}
.t-post hr{border:0;border-top:1px dashed #e5e7eb;margin:26px 0}
/* 다크모드 */
@media(prefers-color-scheme:dark){
  .t-post{color:#e5e7eb}
  .t-post .lead{color:#9aa3ad}
  .t-post .toc{background:#0f172a;border-color:#1f2937}
  .t-post .callout{background:#0b6aa5}
}
&lt;/style&gt;
&lt;/div&gt;
&lt;article class=&quot;t-post tt_article_useless_p_margin&quot;&gt;
&lt;h1&gt;울산 &amp;rarr; 파주 &amp;rarr; 고성 : 땅굴과 분단 현실을 마주한 감성여행&lt;/h1&gt;
&lt;p class=&quot;lead&quot; data-ke-size=&quot;size16&quot;&gt;무박 2일 &amp;middot; 총 1,300km &amp;middot; DMZ 제3땅굴 &amp;middot; 도라전망대 &amp;middot; 명파해변 &amp;mdash; 지도&amp;middot;이미지&amp;middot;영상 그대로 유지&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;2025년 여름, 울산에서 파주와 고성까지! 땅굴과 분단 현실을 마주한 감성여행&lt;/span&gt;&lt;/p&gt;
&lt;div class=&quot;callout&quot;&gt;&lt;b&gt;뜨거웠던 여름 그들은 보이지 않는 곳에서 우리를 지켰다.&lt;/b&gt;&lt;/div&gt;
&lt;!-- 대표 이미지 토큰: 원문 그대로 --&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;글 상단 부분 대표 이미지 (4).png&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/1Rona/btsPFBo2evq/9qKgOsE8FtTCJLmVcGzmuK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/1Rona/btsPFBo2evq/9qKgOsE8FtTCJLmVcGzmuK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/1Rona/btsPFBo2evq/9qKgOsE8FtTCJLmVcGzmuK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F1Rona%2FbtsPFBo2evq%2F9qKgOsE8FtTCJLmVcGzmuK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;400&quot; data-filename=&quot;글 상단 부분 대표 이미지 (4).png&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;올여름휴가에는 또 한 번 장거리 여행을 도전했습니다. 7월 30일 아침 일찍 울산을 떠나 경기도 파주 임진각과 DMZ 관광, 그리고 강원도 고성까지 다녀오는 1박 2일 일정이었죠. 사실 1박 2일이라기보단 무박 2일이라고 봐야겠죠? 왕복 1300km에 달하는 거리를 자동차를 타고 달린다는 생각을 하니 설레고 두근거림이 가득했습니다. 무더운 한여름 날씨였지만 맑은 하늘 아래 시원한 바람을 맞으며 긴 여정을 시작했습니다.&lt;/span&gt;&lt;/p&gt;
&lt;!-- 유튜브 (iframe 원문 그대로, 래퍼만 추가) --&gt;
&lt;div class=&quot;t-embed&quot;&gt;&lt;iframe src=&quot;https://www.youtube-nocookie.com/embed/vbOaNr2D6dY?si=Zw-bFofTZ4C3UOTt&quot; width=&quot;560&quot; height=&quot;315&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;span&gt;&quot;가난하고 힘없던 나라였던 대한민국의 자유를 지키기 위해 달려왔던 그들에게 감사와 존경을&quot;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;div class=&quot;t-embed&quot;&gt;&lt;iframe src=&quot;https://www.youtube-nocookie.com/embed/FJ8iOX7ahok?si=MIGg0R70iQJaTMyB&quot; width=&quot;560&quot; height=&quot;315&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span&gt;위 노래와 함께 글을 읽어보시는 것을 추천드립니다.&lt;/span&gt;&lt;/p&gt;
&lt;!-- 정적 목차 --&gt;
&lt;div class=&quot;toc&quot;&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;목차&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;#sec-start&quot;&gt;여행, 설레는 출발과 끝&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#sec-dmz&quot;&gt;파주 임진각과 DMZ 땅굴 투어 도전&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#sec-goseong&quot;&gt;밤을 달려 도착한 강원도 고성, 명파해변의 새벽&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#sec-end&quot;&gt;마무리&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;h2 id=&quot;sec-start&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;여행, 설레는 출발과 끝&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;h3 id=&quot;sec-dmz&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;파주 임진각과 DMZ 땅굴 투어 도전&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/naRFN/btsPE4yrbRV/y4VB6nFY9ifE2GINKkDoBK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/naRFN/btsPE4yrbRV/y4VB6nFY9ifE2GINKkDoBK/img.png&quot; data-alt=&quot;올라가던 중 사고 난 것을 알려주는 것이 뜨길래 신기해서 찍음.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/naRFN/btsPE4yrbRV/y4VB6nFY9ifE2GINKkDoBK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnaRFN%2FbtsPE4yrbRV%2Fy4VB6nFY9ifE2GINKkDoBK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;565&quot; height=&quot;318&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;올라가던 중 사고 난 것을 알려주는 것이 뜨길래 신기해서 찍음.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ctL9Y0/btsPFiXwKuu/zEIURROjsM2thU1vj4KQZK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ctL9Y0/btsPFiXwKuu/zEIURROjsM2thU1vj4KQZK/img.png&quot; data-alt=&quot;이천 졸음쉼터에서 차에서 누워서 찍었던걸로 기억&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ctL9Y0/btsPFiXwKuu/zEIURROjsM2thU1vj4KQZK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FctL9Y0%2FbtsPFiXwKuu%2FzEIURROjsM2thU1vj4KQZK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;625&quot; height=&quot;352&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;이천 졸음쉼터에서 차에서 누워서 찍었던걸로 기억&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;!-- 지도 #1 — 원문 그대로, 래퍼만 추가 --&gt;
&lt;div class=&quot;t-embed&quot;&gt;&lt;iframe mapdata=&quot;addr=%EA%B2%BD%EA%B8%B0%20%ED%8C%8C%EC%A3%BC%EC%8B%9C%20%EB%AC%B8%EC%82%B0%EC%9D%8D%20%EB%A7%88%EC%A0%95%EB%A6%AC%201325-2&amp;amp;addtype=1&amp;amp;confirmid=8055098&amp;amp;docid=&amp;amp;idx=1&amp;amp;ifrH=362px&amp;amp;ifrW=490px&amp;amp;mapHeight=362&amp;amp;mapInfo=%7B%22version%22%3A2%2C%22mapWidth%22%3A490%2C%22mapHeight%22%3A362%2C%22mapCenterX%22%3A442940%2C%22mapCenterY%22%3A1219558%2C%22mapLevel%22%3A4%2C%22coordinate%22%3A%22wcongnamul%22%2C%22markInfo%22%3A%5B%7B%22markerType%22%3A%22standPlace%22%2C%22coordinate%22%3A%22wcongnamul%22%2C%22x%22%3A442943%2C%22y%22%3A1219563%2C%22clickable%22%3Atrue%2C%22draggable%22%3Atrue%2C%22icon%22%3A%7B%22width%22%3A35%2C%22height%22%3A56%2C%22offsetX%22%3A17%2C%22offsetY%22%3A56%2C%22src%22%3A%22%2F%2Ft1.daumcdn.net%2Flocalimg%2Flocalimages%2F07%2F2012%2Fattach%2Fpc_img%2Fico_marker2_150331.png%22%7D%2C%22content%22%3A%22%EC%9E%84%EC%A7%84%EA%B0%81%EA%B4%91%EC%A7%80%22%2C%22confirmid%22%3A8055098%7D%5D%2C%22graphicInfo%22%3A%5B%5D%2C%22roadviewInfo%22%3A%5B%5D%7D&amp;amp;mapWidth=490&amp;amp;mapX=442940&amp;amp;mapY=1219558&amp;amp;map_hybrid=false&amp;amp;map_level=4&amp;amp;map_type=TYPE_MAP&amp;amp;rcode=4148025000&amp;amp;tel=031-953-4744&amp;amp;title=%EC%9E%84%EC%A7%84%EA%B0%81%EA%B4%91%EC%A7%80&quot; src=&quot;/proxy/plusmapViewer.php?id=maps_1754121332632&quot; id=&quot;maps_1754121332632&quot; width=&quot;540px&quot; height=&quot;350px&quot; frameborder=&quot;0&quot; scrolling=&quot;no&quot; data-ke-type=&quot;map&quot; data-maps-data=&quot;addr=%EA%B2%BD%EA%B8%B0%20%ED%8C%8C%EC%A3%BC%EC%8B%9C%20%EB%AC%B8%EC%82%B0%EC%9D%8D%20%EB%A7%88%EC%A0%95%EB%A6%AC%201325-2&amp;amp;addtype=1&amp;amp;confirmid=8055098&amp;amp;docid=&amp;amp;idx=1&amp;amp;ifrH=362px&amp;amp;ifrW=490px&amp;amp;mapHeight=362&amp;amp;mapInfo=%7B%22version%22%3A2%2C%22mapWidth%22%3A490%2C%22mapHeight%22%3A362%2C%22mapCenterX%22%3A442940%2C%22mapCenterY%22%3A1219558%2C%22mapLevel%22%3A4%2C%22coordinate%22%3A%22wcongnamul%22%2C%22markInfo%22%3A%5B%7B%22markerType%22%3A%22standPlace%22%2C%22coordinate%22%3A%22wcongnamul%22%2C%22x%22%3A442943%2C%22y%22%3A1219563%2C%22clickable%22%3Atrue%2C%22draggable%22%3Atrue%2C%22icon%22%3A%7B%22width%22%3A35%2C%22height%22%3A56%2C%22offsetX%22%3A17%2C%22offsetY%22%3A56%2C%22src%22%3A%22%2F%2Ft1.daumcdn.net%2Flocalimg%2Flocalimages%2F07%2F2012%2Fattach%2Fpc_img%2Fico_marker2_150331.png%22%7D%2C%22content%22%3A%22%EC%9E%84%EC%A7%84%EA%B0%81%EA%B4%91%EC%A7%80%22%2C%22confirmid%22%3A8055098%7D%5D%2C%22graphicInfo%22%3A%5B%5D%2C%22roadviewInfo%22%3A%5B%5D%7D&amp;amp;mapWidth=490&amp;amp;mapX=442940&amp;amp;mapY=1219558&amp;amp;map_hybrid=false&amp;amp;map_level=4&amp;amp;map_type=TYPE_MAP&amp;amp;rcode=4148025000&amp;amp;tel=031-953-4744&amp;amp;title=%EC%9E%84%EC%A7%84%EA%B0%81%EA%B4%91%EC%A7%80&quot; data-maps-thumbnail=&quot;https://ssl.daumcdn.net/map3/staticmap/image?center=442940%2C1219558&amp;amp;lv=4&amp;amp;size=540x350&amp;amp;srs=WCONGNAMUL&amp;amp;markers=symbol%3Asc_marker%7Clocation%3A442943%2C1219563&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uAMO3/btsPGqtPU3h/A9w5ETeKFLWiBvSdLcXDxK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uAMO3/btsPGqtPU3h/A9w5ETeKFLWiBvSdLcXDxK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uAMO3/btsPGqtPU3h/A9w5ETeKFLWiBvSdLcXDxK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FuAMO3%2FbtsPGqtPU3h%2FA9w5ETeKFLWiBvSdLcXDxK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FJnru/btsPFEeXN37/0e34JGnRfO0P2aCmJ561y1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FJnru/btsPFEeXN37/0e34JGnRfO0P2aCmJ561y1/img.png&quot; data-origin-width=&quot;1689&quot; data-origin-height=&quot;3000&quot; data-is-animation=&quot;false&quot; data-filename=&quot;blob&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FJnru/btsPFEeXN37/0e34JGnRfO0P2aCmJ561y1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFJnru%2FbtsPFEeXN37%2F0e34JGnRfO0P2aCmJ561y1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1689&quot; height=&quot;3000&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bNDivT/btsPFCBro6q/cdtBDFDrDFjzgkKcoYyII1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bNDivT/btsPFCBro6q/cdtBDFDrDFjzgkKcoYyII1/img.png&quot; data-origin-width=&quot;1689&quot; data-origin-height=&quot;3000&quot; data-is-animation=&quot;false&quot; data-filename=&quot;blob&quot; style=&quot;width: 49.4186%;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bNDivT/btsPFCBro6q/cdtBDFDrDFjzgkKcoYyII1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbNDivT%2FbtsPFCBro6q%2FcdtBDFDrDFjzgkKcoYyII1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1689&quot; height=&quot;3000&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;투어 관련해서 신분증이 무조건 필요함, 개인적 이동은 불가 무조건 버스로 같이 이동 해야 함.&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;임진각에서 신분 확인과 출입 신고 절차를 거친 후 DMZ 투어 셔틀버스에 올랐습니다. 버스는 군 검문소를 통과 해 민간인통제구역(CCZ)으로 들어갔고, 따로 안내원은 없어 버스기사님이 마이크로 현재 어디를 지나고 있고 이런 것을 알려주십니다. 가는 길에 도라산역과 남북출입사무소를 볼 수 있었습니다. 그렇게 첫 번째 목적지인 제 3땅굴로 향했습니다. 제 3땅굴은 1978년 대한민국이 발견한 북한의 남침용 땅굴로 휴전선 남쪽 435M 지점까지 파여 있었습니다. 전체 길이 약 1.6km 지하 깊이 약 73m에 달하는 이 땅굴은 높이 2미터 남짓의 규모로 한 시간에 무려 3만 명의 군인을 대한민국으로 이동시킬 수 있을 만큼 대규모였다고 합니다. 발견 당시 북한은 자신들이 판 것이 아니라고 부인하다가 나중에는 석단을 캐던 굴이라고 우겼지만 실제 내부 벽은 화강암 지대로 탄광과는 거리가 멀었다고 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bOvfz5/btsPE8Odd23/Qv1JXejHyHYG1IVkhnuxh0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bOvfz5/btsPE8Odd23/Qv1JXejHyHYG1IVkhnuxh0/img.png&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot; data-is-animation=&quot;false&quot; data-filename=&quot;blob&quot; style=&quot;width: 32.9647%; margin-right: 10px;&quot; data-widthpercent=&quot;33.75&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bOvfz5/btsPE8Odd23/Qv1JXejHyHYG1IVkhnuxh0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbOvfz5%2FbtsPE8Odd23%2FQv1JXejHyHYG1IVkhnuxh0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bkrLD8/btsPFC2uCbO/dOKqv1vwMVWrBHDV322DQK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bkrLD8/btsPFC2uCbO/dOKqv1vwMVWrBHDV322DQK/img.png&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot; data-is-animation=&quot;false&quot; data-filename=&quot;blob&quot; style=&quot;width: 32.9647%; margin-right: 10px;&quot; data-widthpercent=&quot;33.75&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bkrLD8/btsPFC2uCbO/dOKqv1vwMVWrBHDV322DQK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbkrLD8%2FbtsPFC2uCbO%2FdOKqv1vwMVWrBHDV322DQK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/0vQxa/btsPEp38W10/QUtkK5IShYH5fj74NVgdfK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/0vQxa/btsPEp38W10/QUtkK5IShYH5fj74NVgdfK/img.png&quot; data-origin-width=&quot;2889&quot; data-origin-height=&quot;1689&quot; data-is-animation=&quot;false&quot; data-filename=&quot;blob&quot; style=&quot;width: 31.745%;&quot; data-widthpercent=&quot;32.5&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/0vQxa/btsPEp38W10/QUtkK5IShYH5fj74NVgdfK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F0vQxa%2FbtsPEp38W10%2FQUtkK5IShYH5fj74NVgdfK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2889&quot; height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;날씨가 생각보다 괜찮았다 (물론 덥고 습하긴 했지만 여름이닌깐)&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;div class=&quot;t-embed&quot;&gt;&lt;iframe src=&quot;https://www.youtube-nocookie.com/embed/jmOdwt6oeoo?si=f9OyRs5Qox7SdOtC&quot; width=&quot;560&quot; height=&quot;315&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;제 3땅굴을 내려가기 위해 소지품을 별도로 보관을 하고 내려갑니다. 내부는 2미터 남짓의 높이가 있어 들어갈 때 헬멧을 착용하고 들어가게 되는데 모노레일도 있긴 한데 방문 당시 모노레일 자체는 운영하지 않았고 도보로만 이용을 할 수 있었습니다. 땅굴에 들어가면 첫 느낌은 엄청 시원합니다. 한참을 내려가야 땅굴이 나올 정도로 규모가 생각보다 있었습니다. 그렇게 땅굴을 구경하고 올라올 때 숨이 찰 정도로 힘들었습니다. 사실 이때 다 올라오고 다리가 후들거리긴 했습니다(부끄러워 괜찮은 척 걷긴 했습니다.) 땅굴의 끝은 더 이상 접근하지 못하게 경고방송이 나오는데 생각보다 규모가 꽤 커서 놀랬습니다. 분단의 현실이 실제로 눈앞에 다가오니 묘한 느낌이 들었습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;(땅굴 투어 전 동영상 시청을 하는데 생각보다 볼만했습니다. 동영상 시청 후 땅굴 투어하는 것을 추천해드립니다.)&lt;/span&gt;&lt;/p&gt;
&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/brvspI/btsPF8fNMMW/gfQfiwS6XasMpEN6xETLjk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/brvspI/btsPF8fNMMW/gfQfiwS6XasMpEN6xETLjk/img.png&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot; data-is-animation=&quot;false&quot; data-filename=&quot;blob&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/brvspI/btsPF8fNMMW/gfQfiwS6XasMpEN6xETLjk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbrvspI%2FbtsPF8fNMMW%2FgfQfiwS6XasMpEN6xETLjk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/diFZXh/btsPEM5PrjG/jT8YaQRWQJNVq2k4FmihI1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/diFZXh/btsPEM5PrjG/jT8YaQRWQJNVq2k4FmihI1/img.png&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot; data-is-animation=&quot;false&quot; data-filename=&quot;blob&quot; style=&quot;width: 49.4186%;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/diFZXh/btsPEM5PrjG/jT8YaQRWQJNVq2k4FmihI1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdiFZXh%2FbtsPEM5PrjG%2FjT8YaQRWQJNVq2k4FmihI1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;왼쪽 : 신 도라전망대, 오른쪽 : 구 도라전망대 -&amp;gt; 현재 사용 할 수 없게 막아둔 모습&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;div class=&quot;t-embed&quot;&gt;&lt;iframe src=&quot;https://www.youtube-nocookie.com/embed/T5GRFdG-mIc?si=M-MXJb0XvTiYrzWI&quot; width=&quot;560&quot; height=&quot;315&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;땅굴을 둘러본 후 버스를 타고 도라전망대를 향했습니다. 도라전망대는 서부전선 DMZ 일대를 조망 할 수 있는 전망대로 1987년 처음 일반에 공개되었다가 노후화로 2018년 관람이 중단된 바 있습니다. 최근에는 기존 위치보다 12M 높은 곳에 신축된 도라전망대 건물이 개장하여 더 넓은 시야로 북한 땅을 바라볼 수 있게 되었습니다. 2024년 문을 연 새 전망대는 3층 규모로 실내에는 교육장과 카페, 편의시설까지 갖춘 건물이었습니다. 제가 방문을 했을 때는 군인 분들도 정말 많이 계셨습니다. 맨 꼭대기 층은 갈 수 없었고 2층에서 통유리로 된 위치에서 북한 쪽을 볼 수 있었습니다. 강원도 고성 통일전망대에서 보던 것과 다른 느낌이었습니다. 이곳에선 북한 개성과 선전마을 등이 보였고 제가 갔을 때 생각보다 날씨가 좋아 뚜렷이 보였습니다. 이곳은 엄연히 촬영금지가 된 곳으로써 눈으로만 모습을 담고 왔습니다. 전 세계 유일의 분단 현장을 이렇게 보니 감회가 남달랐습니다.&lt;/span&gt;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1671&quot; data-origin-height=&quot;1482&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/v5aNm/btsPGFYMaO8/nrn4fXTOuhofgi2dPYw0k1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/v5aNm/btsPGFYMaO8/nrn4fXTOuhofgi2dPYw0k1/img.png&quot; data-alt=&quot;통일촌 주위 모습, 일반 시골이랑 비슷하지만 DMZ(민통선)이라는 단어에서 볼 수 있듯이 북한과 인접한것을 알 수 있다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/v5aNm/btsPGFYMaO8/nrn4fXTOuhofgi2dPYw0k1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fv5aNm%2FbtsPGFYMaO8%2Fnrn4fXTOuhofgi2dPYw0k1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1671&quot; height=&quot;1482&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1671&quot; data-origin-height=&quot;1482&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;통일촌 주위 모습, 일반 시골이랑 비슷하지만 DMZ(민통선)이라는 단어에서 볼 수 있듯이 북한과 인접한것을 알 수 있다.&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;이어서 버스는 통일촌이라 불리는 작은 마을로 우리를 데려갔습니다. 통일촌은 민통선 내에 위치한 파주시 장단면 백연리의 주민 마을인데 일반인이 개인 차량으로는 출입을 할 수 없어 이렇게 투어 코스로만 방문이 가능합니다. 특이하게도 마을 입구에 흔한 대문이나 큰 간판조차 없었는데 외부인의 자유로운 접근이 어렵기 때문이겠죠? 통일촌은 오래전부터 장단콩과 개성인삼 산지로 유명한 곳으로 임금님께 진상되던 '장단 3백(쌀,콩,인삼)'의 생산지이기도 합니다. 지금도 매년 11월이면 장단콩 축제가 열릴 만큼 콩으로 유명한데 통일촌 직판장에서 다양한 것을 살 수 있습니다. 또 신기했던 것은 막걸리 분말 가루가 눈에 띄었는데 물에 타 마시는 즉석 막걸리라니 신기하면서도 DMZ를 떠날 때 기념품으로 하나 사 올 걸 그랬나 아쉬움이 남았습니다.&lt;/span&gt;&lt;/p&gt;
&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bY0TrN/btsPGIBbvrV/ENCcPdrhJ9RWkIqtO0qlak/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bY0TrN/btsPGIBbvrV/ENCcPdrhJ9RWkIqtO0qlak/img.png&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot; data-is-animation=&quot;false&quot; data-filename=&quot;blob&quot; style=&quot;width: 32.5581%; margin-right: 10px;&quot; data-widthpercent=&quot;33.33&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bY0TrN/btsPGIBbvrV/ENCcPdrhJ9RWkIqtO0qlak/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbY0TrN%2FbtsPGIBbvrV%2FENCcPdrhJ9RWkIqtO0qlak%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vJhcj/btsPFEsu8MF/gIZ1it75Qzcrmr8hfICte0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vJhcj/btsPFEsu8MF/gIZ1it75Qzcrmr8hfICte0/img.png&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot; data-is-animation=&quot;false&quot; data-filename=&quot;blob&quot; style=&quot;width: 32.5581%; margin-right: 10px;&quot; data-widthpercent=&quot;33.33&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vJhcj/btsPFEsu8MF/gIZ1it75Qzcrmr8hfICte0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvJhcj%2FbtsPFEsu8MF%2FgIZ1it75Qzcrmr8hfICte0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cA5nkL/btsPE4ZtL3N/JKhbkGACyJATdX8uDEo0wK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cA5nkL/btsPE4ZtL3N/JKhbkGACyJATdX8uDEo0wK/img.png&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot; data-is-animation=&quot;false&quot; data-filename=&quot;blob&quot; style=&quot;width: 32.5581%;&quot; data-widthpercent=&quot;33.34&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cA5nkL/btsPE4ZtL3N/JKhbkGACyJATdX8uDEo0wK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcA5nkL%2FbtsPE4ZtL3N%2FJKhbkGACyJATdX8uDEo0wK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;임진각 평화누리 모습&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FkmWt/btsPD2OKykK/75oHzy0luBBibRSO411tVk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FkmWt/btsPD2OKykK/75oHzy0luBBibRSO411tVk/img.png&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot; data-is-animation=&quot;false&quot; data-filename=&quot;blob&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FkmWt/btsPD2OKykK/75oHzy0luBBibRSO411tVk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFkmWt%2FbtsPD2OKykK%2F75oHzy0luBBibRSO411tVk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/RE9Nu/btsPDpqezZT/V6wJD5Mf1e1kRspOGpFnkK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/RE9Nu/btsPDpqezZT/V6wJD5Mf1e1kRspOGpFnkK/img.png&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot; data-is-animation=&quot;false&quot; data-filename=&quot;blob&quot; style=&quot;width: 49.4186%;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/RE9Nu/btsPDpqezZT/V6wJD5Mf1e1kRspOGpFnkK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FRE9Nu%2FbtsPDpqezZT%2FV6wJD5Mf1e1kRspOGpFnkK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;

&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;통일촌을 둘러본 뒤 3시간 남짓의 투어 일정은 모두 마쳤습니다. 버스는 다시 임진각으로 우리를 데려다 주었고 저는 뜨거운 여름 태양 아래 먼 길 달려온 차를 세차를 하기 위해 파주 근처 실내세차장으로 향했습니다. 세차를 하고 잠시 쉬고&amp;nbsp; 다음 목적지로 향했습니다. 임진강 근처를 이동하는 동안 마주친 미군 모습이 인상적이었습니다. 낯선 이국땅에서 대한민국의 자유를 지키기 위해 헌신하는 모습에 숙연해지면서도 한국전쟁 당시 피 흘리며 함께 싸워준 그들에게 새삼 감사한 마음이 들었습니다.&lt;/span&gt;&lt;/p&gt;
&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/4dXa0/btsPFCIgBrA/yG8YF9RL9kfG4UdY8tegeK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/4dXa0/btsPFCIgBrA/yG8YF9RL9kfG4UdY8tegeK/img.png&quot; data-origin-width=&quot;1689&quot; data-origin-height=&quot;3000&quot; data-is-animation=&quot;false&quot; data-filename=&quot;blob&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/4dXa0/btsPFCIgBrA/yG8YF9RL9kfG4UdY8tegeK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F4dXa0%2FbtsPFCIgBrA%2FyG8YF9RL9kfG4UdY8tegeK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1689&quot; height=&quot;3000&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/v3WjW/btsPGHoJ2AA/JoDsYoBAOOYkRO2pjl6Yok/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/v3WjW/btsPGHoJ2AA/JoDsYoBAOOYkRO2pjl6Yok/img.png&quot; data-origin-width=&quot;1689&quot; data-origin-height=&quot;3000&quot; data-is-animation=&quot;false&quot; data-filename=&quot;blob&quot; style=&quot;width: 49.4186%;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/v3WjW/btsPGHoJ2AA/JoDsYoBAOOYkRO2pjl6Yok/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fv3WjW%2FbtsPGHoJ2AA%2FJoDsYoBAOOYkRO2pjl6Yok%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1689&quot; height=&quot;3000&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;우연히 주위를 보다가 철조망에 사이 좋게 있던 참새(?)를 보게 되었다 너흰 자유롭게 다니는데 난 허가를 받고 다녀야 하구나&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;한편, 도라전망대와 땅굴 등에서 외국인 관광객들이 특히 많았던 것이 기억에 남습니다. 그들은 분단 상황을 그저 흥미로운 관광거리로 소비하는 듯 보였지만 정작 우리에겐 아픈 역사이기에 마음 한켠이 씁쓸해지기도 했습니다. 한반도 분단 현실을 외국인과 함께 마치 박제된 전시물처럼 바라보고 있다는 생각에 묘한 슬픔이 밀려왔지만 언젠가 통일이 되어 이런 관광 자체가 필요 없어지길 바라보았습니다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;sec-goseong&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;밤을 달려 도착한 강원도 고성, 명파해변의 새벽&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bDSNg4/btsPDX7Oq2m/Bo3QHozVxfs0fJ3C6ZWS6K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bDSNg4/btsPDX7Oq2m/Bo3QHozVxfs0fJ3C6ZWS6K/img.png&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot; data-is-animation=&quot;false&quot; data-filename=&quot;blob&quot; style=&quot;width: 32.5581%; margin-right: 10px;&quot; data-widthpercent=&quot;33.33&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bDSNg4/btsPDX7Oq2m/Bo3QHozVxfs0fJ3C6ZWS6K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbDSNg4%2FbtsPDX7Oq2m%2FBo3QHozVxfs0fJ3C6ZWS6K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/2dtz5/btsPDD2SXcZ/6bskLaprKxgdJmyyeOMKuk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/2dtz5/btsPDD2SXcZ/6bskLaprKxgdJmyyeOMKuk/img.png&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot; data-is-animation=&quot;false&quot; data-filename=&quot;blob&quot; style=&quot;width: 32.5581%; margin-right: 10px;&quot; data-widthpercent=&quot;33.33&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/2dtz5/btsPDD2SXcZ/6bskLaprKxgdJmyyeOMKuk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F2dtz5%2FbtsPDD2SXcZ%2F6bskLaprKxgdJmyyeOMKuk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vq0jG/btsPF7nFVMw/DSnkkgq3Uik7YpfGFs1RG0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vq0jG/btsPF7nFVMw/DSnkkgq3Uik7YpfGFs1RG0/img.png&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot; data-is-animation=&quot;false&quot; data-filename=&quot;blob&quot; style=&quot;width: 32.5581%;&quot; data-widthpercent=&quot;33.34&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vq0jG/btsPF7nFVMw/DSnkkgq3Uik7YpfGFs1RG0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fvq0jG%2FbtsPF7nFVMw%2FDSnkkgq3Uik7YpfGFs1RG0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;

&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;투어를 마치고 시계를 보니 어느덧 저녁 무렵이 되었지만 저는 곧바로 강원도 고성으로 향하기로 했습니다. 하루를 그냥 보내기 아쉬워 휴식을 포기하고 야간 드라이브에 나선 겁니다. 파주에서 동해안 최북단의 고성까지는 지도상 거리만 약 240km이며 운전으로 3~4시간 정도는 걸리는 여정입니다. 서쪽 끝에서 동쪽 끝을 가로지르는 길 혼자 운전하며 창밖으로 어두워진 풍경과 드문드문 보이는 불빛을 벗 삼아 달렸습니다. 피로가 몰려왔지만 이왕 나온 길 가볼 수 있을 때까지 가보고 싶었습니다.&lt;/span&gt;&lt;/p&gt;
&lt;!-- 지도 #2 — 원문 그대로, 래퍼만 추가 --&gt;
&lt;div class=&quot;t-embed&quot;&gt;&lt;iframe mapdata=&quot;addr=%EA%B0%95%EC%9B%90%ED%8A%B9%EB%B3%84%EC%9E%90%EC%B9%98%EB%8F%84%20%EA%B3%A0%EC%84%B1%EA%B5%B0%20%ED%98%84%EB%82%B4%EB%A9%B4%20%EB%AA%85%ED%8C%8C%EB%A6%AC%20230-29&amp;amp;addtype=1&amp;amp;confirmid=7866724&amp;amp;docid=&amp;amp;idx=1&amp;amp;ifrH=362px&amp;amp;ifrW=490px&amp;amp;mapHeight=362&amp;amp;mapInfo=%7B%22version%22%3A2%2C%22mapWidth%22%3A490%2C%22mapHeight%22%3A362%2C%22mapCenterX%22%3A806350%2C%22mapCenterY%22%3A1403228%2C%22mapLevel%22%3A4%2C%22coordinate%22%3A%22wcongnamul%22%2C%22markInfo%22%3A%5B%7B%22markerType%22%3A%22standPlace%22%2C%22coordinate%22%3A%22wcongnamul%22%2C%22x%22%3A806352%2C%22y%22%3A1403233%2C%22clickable%22%3Atrue%2C%22draggable%22%3Atrue%2C%22icon%22%3A%7B%22width%22%3A35%2C%22height%22%3A56%2C%22offsetX%22%3A17%2C%22offsetY%22%3A56%2C%22src%22%3A%22%2F%2Ft1.daumcdn.net%2Flocalimg%2Flocalimages%2F07%2F2012%2Fattach%2Fpc_img%2Fico_marker2_150331.png%22%7D%2C%22content%22%3A%22%EB%AA%85%ED%8C%8C%ED%95%B4%EB%B3%80%22%2C%22confirmid%22%3A7866724%7D%5D%2C%22graphicInfo%22%3A%5B%5D%2C%22roadviewInfo%22%3A%5B%5D%7D&amp;amp;mapWidth=490&amp;amp;mapX=806350&amp;amp;mapY=1403228&amp;amp;map_hybrid=false&amp;amp;map_level=4&amp;amp;map_type=TYPE_MAP&amp;amp;rcode=5182031000&amp;amp;tel=&amp;amp;title=%EB%AA%85%ED%8C%8A%ED%95%B4%EB%B3%80&quot; src=&quot;/proxy/plusmapViewer.php?id=maps_1754121351091&quot; id=&quot;maps_1754121351091&quot; width=&quot;540px&quot; height=&quot;350px&quot; frameborder=&quot;0&quot; scrolling=&quot;no&quot; data-ke-type=&quot;map&quot; data-maps-data=&quot;addr=%EA%B0%95%EC%9B%90%ED%8A%B9%EB%B3%84%EC%9E%90%EC%B9%98%EB%8F%84%20%EA%B3%A0%EC%84%B1%EA%B5%B0%20%ED%98%84%EB%82%B4%EB%A9%B4%20%EB%AA%85%ED%8C%8C%EB%A6%AC%20230-29&amp;amp;addtype=1&amp;amp;confirmid=7866724&amp;amp;docid=&amp;amp;idx=1&amp;amp;ifrH=362px&amp;amp;ifrW=490px&amp;amp;mapHeight=362&amp;amp;mapInfo=%7B%22version%22%3A2%2C%22mapWidth%22%3A490%2C%22mapHeight%22%3A362%2C%22mapCenterX%22%3A806350%2C%22mapCenterY%22%3A1403228%2C%22mapLevel%22%3A4%2C%22coordinate%22%3A%22wcongnamul%22%2C%22markInfo%22%3A%5B%7B%22markerType%22%3A%22standPlace%22%2C%22coordinate%22%3A%22wcongnamul%22%2C%22x%22%3A806352%2C%22y%22%3A1403233%2C%22clickable%22%3Atrue%2C%22draggable%22%3Atrue%2C%22icon%22%3A%7B%22width%22%3A35%2C%22height%22%3A56%2C%22offsetX%22%3A17%2C%22offsetY%22%3A56%2C%22src%22%3A%22%2F%2Ft1.daumcdn.net%2Flocalimg%2Flocalimages%2F07%2F2012%2Fattach%2Fpc_img%2Fico_marker2_150331.png%22%7D%2C%22content%22%3A%22%EB%AA%85%ED%8C%8C%ED%95%B4%EB%B3%80%22%2C%22confirmid%22%3A7866724%7D%5D%2C%22graphicInfo%22%3A%5B%5D%2C%22roadviewInfo%22%3A%5B%5D%7D&amp;amp;mapWidth=490&amp;amp;mapX=806350&amp;amp;mapY=1403228&amp;amp;map_hybrid=false&amp;amp;map_level=4&amp;amp;map_type=TYPE_MAP&amp;amp;rcode=5182031000&amp;amp;tel=&amp;amp;title=%EB%AA%85%ED%8C%8A%ED%95%B4%EB%B3%80&quot; data-maps-thumbnail=&quot;https://ssl.daumcdn.net/map3/staticmap/image?center=806350%2C1403228&amp;amp;lv=4&amp;amp;size=540x350&amp;amp;srs=WCONGNAMUL&amp;amp;markers=symbol%3Asc_marker%7Clocation%3A806352%2C1403233&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;
&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dozQAr/btsPDICX4Kf/husr8wHinZymSeCNzFTJBk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dozQAr/btsPDICX4Kf/husr8wHinZymSeCNzFTJBk/img.png&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot; data-is-animation=&quot;false&quot; data-filename=&quot;blob&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dozQAr/btsPDICX4Kf/husr8wHinZymSeCNzFTJBk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdozQAr%2FbtsPDICX4Kf%2Fhusr8wHinZymSeCNzFTJBk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bYmbma/btsPDYyTNOL/CADtL95zfHkpbgYWmshvQK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bYmbma/btsPDYyTNOL/CADtL95zfHkpbgYWmshvQK/img.png&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot; data-is-animation=&quot;false&quot; data-filename=&quot;blob&quot; style=&quot;width: 49.4186%;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bYmbma/btsPDYyTNOL/CADtL95zfHkpbgYWmshvQK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbYmbma%2FbtsPDYyTNOL%2FCADtL95zfHkpbgYWmshvQK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;이때 많이 피곤하긴 했나보다 사진 초점을 맞추질 않았다 (캠핑하는 사람들이 많았다)&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bcNP0v/btsPDmNP4YZ/XgBjeFBbKIAJ1VnR3zKAW1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bcNP0v/btsPDmNP4YZ/XgBjeFBbKIAJ1VnR3zKAW1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bcNP0v/btsPDmNP4YZ/XgBjeFBbKIAJ1VnR3zKAW1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbcNP0v%2FbtsPDmNP4YZ%2FXgBjeFBbKIAJ1VnR3zKAW1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/T2JIi/btsPDmG3rjY/vPwk3rAlCncnxIVSTDcXek/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/T2JIi/btsPDmG3rjY/vPwk3rAlCncnxIVSTDcXek/img.png&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot; data-is-animation=&quot;false&quot; data-filename=&quot;blob&quot; style=&quot;width: 32.5581%; margin-right: 10px;&quot; data-widthpercent=&quot;33.33&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/T2JIi/btsPDmG3rjY/vPwk3rAlCncnxIVSTDcXek/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FT2JIi%2FbtsPDmG3rjY%2FvPwk3rAlCncnxIVSTDcXek%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/biwQf4/btsPDKngGBa/JxqwDBPmDLtvxw3HejNmeK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/biwQf4/btsPDKngGBa/JxqwDBPmDLtvxw3HejNmeK/img.png&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot; data-is-animation=&quot;false&quot; data-filename=&quot;blob&quot; style=&quot;width: 32.5581%; margin-right: 10px;&quot; data-widthpercent=&quot;33.33&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/biwQf4/btsPDKngGBa/JxqwDBPmDLtvxw3HejNmeK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbiwQf4%2FbtsPDKngGBa%2FJxqwDBPmDLtvxw3HejNmeK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/QUKXX/btsPEsT1aOH/GkQQ3QgLvahMoZ8fKtFce0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/QUKXX/btsPEsT1aOH/GkQQ3QgLvahMoZ8fKtFce0/img.png&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot; data-is-animation=&quot;false&quot; data-filename=&quot;blob&quot; style=&quot;width: 32.5581%;&quot; data-widthpercent=&quot;33.34&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/QUKXX/btsPEsT1aOH/GkQQ3QgLvahMoZ8fKtFce0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQUKXX%2FbtsPEsT1aOH%2FGkQQ3QgLvahMoZ8fKtFce0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;

&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;새벽 0시쯤 되자 차 안에서 슬슬 졸음이 피어났습니다. 창문을 열어 시원한 바람을 쐬고(사실 여름이라 그리 시원하진 않았습니다.) 음악 소리도 높여 보았지만 한계가 왔습니다. 그래도 바깥바람을 적당히 느끼면서 오니 새벽 2시경 명파해변에 도착을 했습니다. 이곳은 대한민국 동해안 가장 북쪽에 위치한 해수욕장입니다. DMZ에 매우 가까운 탓에 해변 가장자리에 철조망이 둘러 쳐져 있고 군부대의 출입 통제도 이루어지는 곳입니다. 덕분에 이곳은 일반적인 해수욕장이라기보단&amp;nbsp; 캠핑장으로 더 알려져 있습니다. 저 역시 도착하니 백사장 앞쪽에 캠핑 사이트와 관리소 등이 눈에 띄었고 바닷가로 나가지 못하도록 울타리가 쳐져 있었습니다. 깊은 밤이라 해변 출입이 통제된 터라 파도 소리를 멀찍이 들으며 휴식을 취할 수밖에 없었습니다. 비록 모래사장을 직접 밟아보지는 못했지만 뒤편으로 보이는 에메랄드빛 동해 바다의 고요한 밤하늘의 별들은 충분히 아름다웠습니다. 적막한 해변에 서서 북쪽을 바라보니 불과 수 km 너머에 금강산과 북한 땅이 있다는 사실이 실감 나 묘한 기분이 들었습니다.&lt;/span&gt;&lt;/p&gt;
&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vqn5B/btsPELeLslP/EqWIuMWXRID7B18vyd9J3k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vqn5B/btsPELeLslP/EqWIuMWXRID7B18vyd9J3k/img.png&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot; data-is-animation=&quot;false&quot; data-filename=&quot;blob&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vqn5B/btsPELeLslP/EqWIuMWXRID7B18vyd9J3k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fvqn5B%2FbtsPELeLslP%2FEqWIuMWXRID7B18vyd9J3k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/R4OlH/btsPDn6XII3/FFDoCjnSwnHcEaPPHeVY21/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/R4OlH/btsPDn6XII3/FFDoCjnSwnHcEaPPHeVY21/img.png&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot; data-is-animation=&quot;false&quot; data-filename=&quot;blob&quot; style=&quot;width: 49.4186%;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/R4OlH/btsPDn6XII3/FFDoCjnSwnHcEaPPHeVY21/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FR4OlH%2FbtsPDn6XII3%2FFFDoCjnSwnHcEaPPHeVY21%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/blNQ2m/btsPEpC4Nro/3ToGutXmXIj8RfvFfWNfhk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/blNQ2m/btsPEpC4Nro/3ToGutXmXIj8RfvFfWNfhk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/blNQ2m/btsPEpC4Nro/3ToGutXmXIj8RfvFfWNfhk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FblNQ2m%2FbtsPEpC4Nro%2F3ToGutXmXIj8RfvFfWNfhk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1689&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1689&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;잠시나마 바닷바람을 쐬고 피로를 달랜 후 다시 운전대를 잡고 고성을 떠나 귀향 길을 올랐습니다. 동틀 무렵 동해 고속도로를 남쪽으로 내려오면서 희미한 여명이 바다를 밝히는 광경은 오래 기억에 남을 듯합니다. 중간중간 졸음이 몰려올 때마다 휴게소에 들러 스트레칭도 하고 커피도 마시며 스스로를 깨우며 왔습니다. 그렇게 달려 7월 31일 아침 무사히 다시 울산 집 앞에 도착했습니다. 주행 기록계를 보니 총 운행 거리가 약 1300km를 달려왔습니다. 스스로도 믿기지 않을 만큼 긴 거리를 달렸지만 큰 사고 없이 여행을 마쳤다는 안도감에 피곤함도 잊혔습니다.&lt;/span&gt;&lt;/p&gt;
&lt;h2 id=&quot;sec-end&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;마무리&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;/h2&gt;
&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bhCDT6/btsPE6Qpju3/si9bchD3xBJykqCOakTKrk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bhCDT6/btsPE6Qpju3/si9bchD3xBJykqCOakTKrk/img.png&quot; data-origin-width=&quot;737&quot; data-origin-height=&quot;831&quot; data-is-animation=&quot;false&quot; data-filename=&quot;blob&quot; style=&quot;width: 52.7677%; margin-right: 10px;&quot; data-widthpercent=&quot;53.39&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bhCDT6/btsPE6Qpju3/si9bchD3xBJykqCOakTKrk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbhCDT6%2FbtsPE6Qpju3%2Fsi9bchD3xBJykqCOakTKrk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;737&quot; height=&quot;831&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ce0h46/btsPEP2nYWs/mrX0Uc8Kve3CRcVxq0Ckpk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ce0h46/btsPEP2nYWs/mrX0Uc8Kve3CRcVxq0Ckpk/img.png&quot; data-origin-width=&quot;669&quot; data-origin-height=&quot;864&quot; data-is-animation=&quot;false&quot; data-filename=&quot;blob&quot; data-widthpercent=&quot;46.61&quot; style=&quot;width: 46.0695%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ce0h46/btsPEP2nYWs/mrX0Uc8Kve3CRcVxq0Ckpk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fce0h46%2FbtsPEP2nYWs%2FmrX0Uc8Kve3CRcVxq0Ckpk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;669&quot; height=&quot;864&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;이동경로&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;이번 여름휴가 여행을 통해 나와의 약속을 또 하나 지켰다는 뿌듯함을 느낍니다. 바쁜 일상 속에서 미뤄두었던 여행을 실행에 옮기고 스스로 계획한 길을 끝까지 완주해냈으닌깐 이 기쁨과 성취감 또한 큽니다. 혼자 긴 거리를 운전하며 많은 생각이 오갔습니다. 특히 최전방 DMZ에서 마주한 분단의 현실을 볼 때마다 마음을 아프게 합니다. 휴전선 철조망과 땅굴 깊숙한 곳에서 느낀 정체 모를 공기는 제가 누리고 있는 일상의 소중함과 평화의 가치를 다시금 일깨워주었습니다.&lt;/span&gt;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1689&quot; data-origin-height=&quot;1015&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/LjvTA/btsPFhdeY8C/9rmyVmmuu9qzBK17exqLok/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/LjvTA/btsPFhdeY8C/9rmyVmmuu9qzBK17exqLok/img.png&quot; data-alt=&quot;미군들이 탑승했던 차량들 (스타렉스랑 맨앞에 호송차가 같이 다니는걸확인...)&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/LjvTA/btsPFhdeY8C/9rmyVmmuu9qzBK17exqLok/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FLjvTA%2FbtsPFhdeY8C%2F9rmyVmmuu9qzBK17exqLok%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1689&quot; height=&quot;1015&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1689&quot; data-origin-height=&quot;1015&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;미군들이 탑승했던 차량들 (스타렉스랑 맨앞에 호송차가 같이 다니는걸확인...)&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;960&quot; data-origin-height=&quot;444&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bitx4W/btsPEpiJydv/aUn7mQeSZZVoCYctkwW8ck/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bitx4W/btsPEpiJydv/aUn7mQeSZZVoCYctkwW8ck/img.jpg&quot; data-alt=&quot;(C) 한미연합 도하훈련 - 대한민국 국군&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bitx4W/btsPEpiJydv/aUn7mQeSZZVoCYctkwW8ck/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbitx4W%2FbtsPEpiJydv%2FaUn7mQeSZZVoCYctkwW8ck%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;752&quot; height=&quot;348&quot; data-origin-width=&quot;960&quot; data-origin-height=&quot;444&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;(C) 한미연합 도하훈련 - 대한민국 국군&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;또한 고속도로에서 마주친 미군, 그리고 지금 이 순간에도 대한민국을 지키기 위한 군인 분들에게 깊은 감사와 존경을 보냅니다. 그들의 희생과 헌신 덕분에 우리가 자유로운 삶을 영위할 수 있다는 사실을 잊지 말아야겠죠.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;끝으로 이번 여행에서 절실히 깨달은 것도 있습니다. 바로 졸음운전의 위험입니다. 물론 뉴스, 자료 등을 많이 접하긴 하지만 또 그냥 조금만 더라는 생각으로 출발하는 경우도 있습니다. 누구에게나 피로가 찾아오기 마련입니다. 이럴 땐 저처럼 중간중간 졸음쉼터에서 쉬어가는 용기(?)를 내는 것이 중요합니다. 안전이 최우선이니깐요. 무리하게 달리는 것보다 잠깐이라도 휴식을 취한 덕분에 저는 소중한 일상을 지킬 수 있었습니다. 앞으로도 여행을 떠날 때는 설렘만큼이나 안전수칙과 자기 자신과의 약속을 지키며 두 눈에 담은 풍경과 가슴으로 느낀 감동을 오래도록 간직하고자 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/article&gt;</description>
      <category>DailyRoutine</category>
      <category>DMZ여행</category>
      <category>LF소나타</category>
      <category>도라전망대</category>
      <category>명파해변</category>
      <category>분단국가</category>
      <category>여름휴가</category>
      <category>임진각</category>
      <category>장거리운전</category>
      <category>제3땅굴</category>
      <category>통일촌</category>
      <author>간지뽕빨리턴님</author>
      <guid isPermaLink="true">https://odinbox.tistory.com/544</guid>
      <comments>https://odinbox.tistory.com/544#entry544comment</comments>
      <pubDate>Sat, 2 Aug 2025 16:38:28 +0900</pubDate>
    </item>
    <item>
      <title>Oracle vs PostgreSQL, STRING_AGG(LISTAGG) 가이드</title>
      <link>https://odinbox.tistory.com/543</link>
      <description>&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Oracle과 PostgreSQL에서 문자열 집계를 손쉽게 처리하는 STRING_AGG(LISTAGG) 함수의 개념과 활용법&lt;/span&gt;&lt;/p&gt;
&lt;div class=&quot;txc-textbox&quot; style=&quot;font-weight: normal; position: relative; line-height: 40px; background: #007CBA; border: 1px solid #fff; padding: 10px; color: white; border-radius: 0 10px 0 10px; box-shadow: inset 0 0 5px rgba(53,86,129, 0.5); font-family: 'Muli', sans-serif; border-style: solid; border-width: 0px  0px  1px 15px; border-color: #232323; background-color: #007cba;&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-size: 15pt; color: #ffffff;&quot;&gt;&lt;b&gt;STRING_AGG(LISTAGG) 이 글 하나면 끝!&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;글 상단 부분 대표 이미지 (3).png&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c87K4n/btsPCnRkfsB/KJweTviMvy1fYs3GCNTuo0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c87K4n/btsPCnRkfsB/KJweTviMvy1fYs3GCNTuo0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c87K4n/btsPCnRkfsB/KJweTviMvy1fYs3GCNTuo0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc87K4n%2FbtsPCnRkfsB%2FKJweTviMvy1fYs3GCNTuo0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;400&quot; data-filename=&quot;글 상단 부분 대표 이미지 (3).png&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-end=&quot;117&quot; data-start=&quot;9&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;SQL을 쓰다 보면 여러 행의 값을 한 줄로 모아야 할 때가 많습니다. 예를 들어, 한 부서의 직원 이름을 콤마로 연결하거나, 여러 제품 코드를 한 칸에 모아 보여주고 싶을 때가 그렇습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-end=&quot;117&quot; data-start=&quot;9&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;248&quot; data-start=&quot;119&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;이럴 때 유용한 함수가 Oracle의 LISTAGG와 PostgreSQL의 STRING_AGG입니다. 두 함수 모두 여러 행의 문자열을 하나로 합쳐주는 집계 함수로, 보고서 작성이나 데이터 요약에 자주 활용됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;div class=&quot;txc-textbox&quot; style=&quot;border-style: solid; font-weight: bold; border-width: 1px  1px  1px 5px; border-color: #707070; background-color: #fff; padding: 10px;&quot;&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;https://tistory3.daumcdn.net/tistory/1569230/skin/images/jquery.toc.js&quot;&gt;&lt;/script&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;목차&lt;/p&gt;
&lt;ul id=&quot;toc&quot; style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;&lt;/ul&gt;
&lt;script type=&quot;text/javascript&quot;&gt;
$(function(){
	$(&quot;#toc&quot;).toc( {content: &quot;.tt_article_useless_p_margin&quot;, headings: &quot;h1,h2,h3,h4&quot; , top: -90, isBlink : true, blinkColor : '#21B9DE' } ) });
&lt;/script&gt;
&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;SQL - STRING_AGG&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;소개&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;STRING_AGG는 여러 행의 문자열 값을 하나의 문자열로 결합해 주는 집계 함수로, Oracle과 PostgreSQL에서 모두 비슷한 기능을 제공합니다. Oracle 데이터베이스에서는 동일한 기능을 LISTAGG라는 이름의 함수로 제공하며 PostgreSQL에서는 STRING_AGG 함수로 구현되어 있습니다. 이 함수들을 사용하면 다중 행의 데이터를 단일 행의 구분된 문자열로 변환할 수 있기 때문에, 데이터베이스에서 데이터를 요약하거나 보고용으로 표시할 때 매우 유용합니다. 예를 들어, 여러 사람의 이름을 콤마로 구분된 하나의 문자열로 만들거나 여러 제품 코드를 한 줄에 모아 표시할 때 이 함수를 사용할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;문법 및 사용방법&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;Oracle - LISTAGG&lt;/b&gt; : Oracle에서는 LISTAGG(값_표현식, 구분자) WITHIN GROUP (ORDER BY 정렬열) 문법을 사용합니다. WITHIN GROUP (ORDER BY ...) 절에는 문자열을 연결하기 전에 정렬할 기준 열을 지정하며, 구분자는 각 값 사이에 넣을 문자열(예: '', '' 콤마와 스페이스)입니다. 이 함수를 GROUP BY와 함께 사용하면 각 그룹별로 문자열을 모아주고, GROUP BY 없이 단독 집계로 쓰면 전체 결과를 하나의 문자열로 반환합니다. Oracle의 LISTAGG는 NULL 값을 무시하며, 구분자를 생략하면 기본으로 아무 구분자 없이 연결합니다.&lt;/span&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;Oracle 사용방법 예시&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1753567604574&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT deptno,
 LISTAGG(ename, ', ') WITHIN GROUP (ORDER BY ename) AS employees_list
FROM emp
GROUP BY deptno;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;PostgreSQL - STRING_AGG : PostgreSQL에서는 'STRING_AGG(값_표현식, 구분자 [ORDER BY 정렬열])' 형식으로 사용하며, Oracle과 달리 함수 인자 내부에서 'ORDER BY' 절을 바로 지정할 수 있습니다. 구분자와 정렬 기준을 제외한 기본 동작은 Oracle의 LISTAGG와 동일하게, 여러 행을 모아 하나의 문자열로 반환합니다. PostgreSQL의 STRING_AGG 역시 NULL 값은 무시하고, 구분자를 'NULL'로 지정하면 결과 문자열 사이에 아무 문자도 넣지 않고 연결합니다.&lt;/span&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;PostgreSQL 사용방법 예시&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1753567813220&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT deptno,
 STRING_AGG(ename, ', ' ORDER BY ename) AS employees_list
FROM emp
GROUP BY deptno;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;구현 및 성능 차이&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;두&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt; 함수는 기능적으로 유사하지만 구현상의 세부 사항과 지원 기능에 차이가 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;함수명과 제공 버전&lt;/b&gt; : Oracle에서는 11g R2 버전부터 LISTAGG 함수를 제공하며, PostgreSQL에서는 9.x 버전부터 STRING_AGG 함수를 지원해 왔습니다. SQL 표준에서는 LISTAGG라는 이름으로 정의되어 있어, Oracle뿐 아니라 SQL Server 등 일부 DB에서는 LISTAGG 또는 STRING_AGG를 표준에 맞게 구현하고 있습니다. Oracle과 PostgreSQL에서는 이름만 다를 뿐 기본 동작은 동일합니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;결과 길이 제한&lt;/b&gt; : Oracle의 LISTAGG는 반환 타입이 VARCHAR2로 고정되어 있어서, 연결 결과 문자열 길이가 SQL VARCHAR2의 한계(일반적으로 4000바이트)를 넘을 경우 ORA-01489: result of string concatenation is too long 오류가 발생할 수 있습니다. 이를 대비해 Oracle 12c R2부터는 ON OVERFLOW 절을 도입하여, 결과 문자열이 너무 길 때 오류 대신 잘라내거나 특정 표시(&amp;hellip;)를 추가하는 옵션을 제공했습니다. 반면 PostgreSQL의 STRING_AGG는 반환 타입이 TEXT이며 가변 길이이므로 매우 큰 문자열도 그대로 반환할 수 있고, 별도의 오버플로 제어 옵션은 없습니다. 따라서 PostgreSQL에서는 이론적으로 메모리가 허용하는 한 상당히 긴 문자열까지도 결과로 얻을 수 있지만, 너무 큰 결과를 다루는 것은 성능에 영향을 줄 수 있으므로 주의가 필요합니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;중복 제거(DISTINCT) 지원&lt;/b&gt; : Oracle은 19c 버전부터 LISTAGG 함수에 DISTINCT 키워드를 지원하여 집계 과정에서 중복 값을 제거할 수 있게 되었습니다. 예를 들어 LISTAGG(DISTINCT 컬럼, ',') WITHIN GROUP (...) 형태로 사용하면 중복된 값은 한 번만 나타납니다. 반면 PostgreSQL의 STRING_AGG는 함수 자체로 DISTINCT 옵션을 제공하지는 않지만, 일반 집계 함수와 동일하게 STRING_AGG(DISTINCT 컬럼, ', ')와 같이 쿼리 수준에서 DISTINCT 키워드를 적용하는 방법으로 중복을 제거할 수 있습니다. 또는 하위쿼리에서 미리 DISTINCT 결과를 만든 후 STRING_AGG로 연결하는 방식으로도 처리합니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;정렬 및 실행 계획&lt;/b&gt; : Oracle의 LISTAGG는 WITHIN GROUP (ORDER BY ...)절이 필수적으로 포함되는 경우가 많은데 Oracle 옵티마이저는 LISTAGG 수행 시 SORT 연산을 수행하는 실행 계획을 선택합니다. 이는 그룹 내 데이터 정렬이 필요한 경우 불가피하지만, 대량의 데이터를 집계할 때 쿼리 성능에 부담이 될 수 있습니다. PostgreSQL의 STRING_AGG에서도 ORDER BY를 지정하면 마찬가지로 정렬 오버헤드가 발생합니다. 특별히 정렬이 필요 없는 경우 ORDER BY를 생략할 수도 있지만, 이때 결과 문자열의 요소 순서는 정의되지 않을 수 있으므로(테이블의 저장 순서 등에 따름) 일반적으로는 명시적으로 정렬하는 것이 좋습니다. 양쪽 DB 모두 대량의 문자열을 집계하면 메모리 사용량 증가 및 처리 시간 증가가 발생할 수 있으므로, 필요에 따라 적절한 인덱스 활용이나 데이터 필터링으로 성능을 튜닝해야 합니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;성능 비교&lt;/b&gt; : 일반적으로 STRING_AGG/LISTAGG 함수 자체의 성능은 다른 집계 함수들과 비슷한 수준이며, DB 엔진 레벨에서 최적화되어 있습니다. Oracle에서는 LISTAGG 도입 전 사용자 정의 함수로 구현하던 문자열 집계보다 LISTAGG가 성능 면에서 우수한 것으로 보고되었습니다. PostgreSQL에서도 배열 집계('ARRAY_AGG') 후 문자 변환을 하는 방법보다 전용 함수인 STRING_AGG를 사용하는 것이 성능상 유리합니다. 예컨대, PostgreSQL에서 ARRAY_AGG()으로 모은 후 ARRAY_TO_STRING()을 호출하는 방식은 큰 집합을 처리할 때 약간의 오버헤드가 있으므로, 가능하면 한 번에 처리하는 STRING_AGG를 사용하는 것이 효율적입니다. 요약하면, 두 DB 모두 해당 함수 사용 자체는 비교적 빠르지만, 정렬이나 매우 큰 결과 처리 시에는 부하를 유발할 수 있으므로 이러한 점을 감안해야 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;활용 예시&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1753568002442&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Dept | Employee
-------------
10 | CHOEYEONGHWAN
20 | ODINBOX
10 | ULSAN
20 | BUSAN&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;Oracle(LISTAGG 사용)&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1753568061156&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 부서 번호별로 직원 이름을 취합하여 콤마로 구분된 하나의 문자열로 만들 수 있습니다.
SELECT deptno,
 LISTAGG(ename, ', ') WITHIN GROUP (ORDER BY ename) AS employees_list
FROM employees
GROUP BY deptno;&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;PostgreSQL(STRING_AGG 사용)&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1753568120990&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 부서 번호별로 직원 이름을 취합하여 콤마로 구분된 하나의 문자열로 만들 수 있습니다.
SELECT deptno,
 STRING_AGG(ename, ', ' ORDER BY ename) AS employees_list
FROM employees
GROUP BY deptno;&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;결과&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1753568167026&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Dept | Employees
-------------------------
10 | CHOEYEONGHWAN,ULSAN
20 | ODINBOX,BUSAN&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;사용 사례 및 활용범위&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;보고서 데이터 요약&lt;/b&gt; : 여러 행의 상세 데이터를 한 줄로 요약하여 보고할 때 유용합니다. 예를 들어 영업 보고서에서 지역별 판매 상품 목록을 콤마로 구분된 문자열로 표시하거나, 과목별 학생 명단을 하나의 칸에 넣어 보여주는 식으로 사용할 수 있습니다. 이러한 데이터 비정규화(denormalization) 된 표현은 사람에게 읽기 편한 요약 정보를 제공합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;CSV 또는 목록 문자열 생성 &lt;/b&gt;: 애플리케이션에 데이터를 전달할 때, 다수의 값을 하나의 문자열 (예: CSV 형식)로 묶어서 전달해야 하는 경우가 있습니다. 예를 들어 여러 태그(tag) 값을 하나의 문자열로 결합하여 API로 보내거나, 로그 메시지에 여러 이벤트를 한 줄로 기록할 때 사용할 수 있습니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;동적 쿼리 구성&lt;/b&gt; : SQL문을 동적으로 생성해야 할 때, 특정 컬럼 값들을 콤마로 이어 붙여 인자 목록을 만드는 경우가 있습니다. 이때 STRING_AGG로 컬럼들을 한 줄로 만들고 그 결과를 서브쿼리 등으로 활용하면 편리합니다. (예: ''IN (' || LISTAGG(id, ',') || ')'' 형태로 ID 목록을 쿼리에 삽입 등). &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;XML/JSON 등과 결합 &lt;/b&gt;: 문자열로 합친 값을 further 가공하여 XML 혹은 JSON 문자열을 생성할 수도 있습니다. PostgreSQL의 경우 STRING_AGG 결과를 JSON 함수와 함께 사용해 여러 키를 한꺼번에 표현하거나, ARRAY_AGG 및 JSON_AGG와 조합하여 복잡한 구조의 문자열을 만들기도 합니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;ETL 및 데이터 마이그레이션 &lt;/b&gt;: 데이터 마이그레이션 과정에서 다대일(여러 행 -&amp;gt; 한 행) 관계를 처리할 때 임시로 문자열로 합쳐서 이동한 후, 대상 시스템에서 파싱하는 전략을 쓰기도 합니다. 이런 경우 간단히 문자열로 합치기 위해 해당 함수를 사용할 수 있습니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;STRING_AGG/LISTAGG는 데이터베이스 레벨에서 목록을 만들어야 할 때 두루 쓰일 수 있는 범용 도구입니다. 다만, 너무 많은 데이터를 한 번에 연결하면 결과 문자열이 과도하게 길어질 수 있으므로, 실제로 표시하거나 활용할 목적에 맞게 적절한 규모로 사용하는 것이 좋습니다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;같이 사용하였던 부분 확인&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;GROUP BY 절&lt;/b&gt; : 대부분 STRING_AGG/LISTAGG는 GROUP BY와 함께 사용됩니다. 그룹화된 각 그룹마다 별도의 문자열 집계 결과를 얻어낼 수 있기 때문입니다. 예를 들어 부서별, 카테고리별 등의 그룹을 지정하여 각 그룹 내 값들을 연결하면 그룹별 요약정보를 손쉽게 생성할 수 있습니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;ORDER BY 절&lt;/b&gt; : 연결되는 문자열 내부의 값 순서를 제어하기 위해 정렬 기능을 사용합니다. Oracle의 경우 WITHIN GROUP (ORDER BY ...) 절에, PostgreSQL의 경우 함수 인자 내부에 ORDER BY를 넣어서 원하는 순서로 값들을 나열할 수 있습니다. 이를 통해 결과 문자열을 의미 있게 정렬할 수 있습니다 (예: 이름순, 날짜순 등). 정렬 기준을 명시하지 않으면 시스템은 임의의 순서로 값을 연결하므로, 결과의 재현성을 위해서는 가급적 정렬 조건을 지정하는 것이 좋습니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;FILTER 절 (PostgreSQL)&lt;/b&gt; : PostgreSQL에서는 집계 함수에 FILTER (WHERE 조건) 절을 추가하여 특정 조건을 만족하는 행만을 집계할 수 있습니다. STRING_AGG에도 응용하면, 예를 들어 STRING_AGG(value, ', ') FILTER (WHERE condition) 형태로 특정 조건에 부합하는 값들만 선택적으로 연결 가능합니다. Oracle의 LISTAGG에는 직접적인 FILTER 절이 없지만, 대신 CASE WHEN ... THEN value END와 같은 표현식을 사용하여 조건에 따라 값이 'NULL'이 되도록 함으로써 비슷한 효과를 낼 수 있습니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;DISTINCT 및 중복 처리&lt;/b&gt; : 앞서 언급한 대로 Oracle 19c의 LISTAGG DISTINCT 기능은 중복 제거된 값들의 목록을 만드는데 편리합니다. PostgreSQL에서도 SELECT 구문에서 DISTINCT를 사용하거나 서브쿼리를 통해 중복을 제거한 후 STRING_AGG로 연결하면 동일한 목적을 달성할 수 있습니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;윈도우 함수로 사용&lt;/b&gt; : 두 DB의 문자열 집계 함수는 윈도우 함수로도 활용 가능합니다. Oracle의 LISTAGG는 OVER (PARTITION BY ...) 절과 함께 사용하여 각 파티션별 결과를 모든 행에 반복 표시하는 식으로 쓸 수 있고, PostgreSQL의 STRING_AGG도 OVER (PARTITION BY ... ORDER BY ...) 구문을 통해 비슷한 작업을 할 수 있습니다. 이를 활용하면 별도의 그룹핑 없이도 원본 행에 집계 결과를 추가적으로 표시할 수 있어, 일부 분석 쿼리에서 유용합니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;기타 함수와 조합&lt;/b&gt; : 경우에 따라 다른 문자열 함수나 집계 함수와 함께 사용하면 좋습니다. 예를 들어 Oracle에서 LISTAGG 결과가 4000자를 초과할 수 있을 때는 DBMS_LOB.SUBSTR 등을 사용해 자르거나, PostgreSQL에서 STRING_AGG 결과를 LEFT()나 SUBSTRING()으로 잘라서 표시할 수도 있습니다. 또한, Oracle에서는 LISTAGG 결과에 접두어나 접미어를 붙이기 위해 'CONCAT' 함수를 함께 쓰거나, PostgreSQL에서는 STRING_AGG 결과를 다른 문자열과 결합하여 문장을 만들 수도 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;마무리&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;STRING_AGG (Oracle의 LISTAGG) 함수는 SQL 레벨에서 손쉽게 문자열 리스트를 만드는 강력한 도구입니다. 여러 행의 데이터를 하나의 요약 문자열로 표현해야 할 때 이 함수를 사용하면 별도의 코딩 없이 한 줄의 SQL로 결과를 얻을 수 있습니다. Oracle과 PostgreSQL 모두 이 기능을 제공하므로 사용하는 데이터베이스에 맞는 구문만 선택하면 됩니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>DEVELOPMENT</category>
      <category>listagg</category>
      <category>PostgreSQL</category>
      <category>SQL</category>
      <category>SQL함수</category>
      <category>STRING_AGG</category>
      <category>데이터베이스</category>
      <category>문자열집계</category>
      <category>실무</category>
      <category>오라클</category>
      <category>쿼리성능</category>
      <author>간지뽕빨리턴님</author>
      <guid isPermaLink="true">https://odinbox.tistory.com/543</guid>
      <comments>https://odinbox.tistory.com/543#entry543comment</comments>
      <pubDate>Sun, 27 Jul 2025 07:29:02 +0900</pubDate>
    </item>
    <item>
      <title>주요 LLM 성능 비교, GPT‑4o, Claude 4, Gemini 2.5, Grok 3, DeepSeek까지 총정리</title>
      <link>https://odinbox.tistory.com/542</link>
      <description>&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;대형 LLM 전쟁의 현주소, 2025년 성능&amp;middot;코딩&amp;middot;멀티모달 능력 비교 정리&lt;/span&gt;&lt;/p&gt;
&lt;div class=&quot;txc-textbox&quot; style=&quot;font-weight: normal; position: relative; line-height: 40px; background: #007CBA; border: 1px solid #fff; padding: 10px; color: white; border-radius: 0 10px 0 10px; box-shadow: inset 0 0 5px rgba(53,86,129, 0.5); font-family: 'Muli', sans-serif; border-style: solid; border-width: 0px  0px  1px 15px; border-color: #232323; background-color: #007cba;&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-size: 15pt; color: #ffffff;&quot;&gt;&lt;b&gt;대형 언어모델(LLM) 성능 비교: 자연어처리, 코딩, 멀티모달까지 전방위 분석&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;글 상단 부분 대표 이미지 (2).png&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/03FQ2/btsPrLEOGVS/abCOiLAh64UhkLrYQOaxl1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/03FQ2/btsPrLEOGVS/abCOiLAh64UhkLrYQOaxl1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/03FQ2/btsPrLEOGVS/abCOiLAh64UhkLrYQOaxl1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F03FQ2%2FbtsPrLEOGVS%2FabCOiLAh64UhkLrYQOaxl1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;400&quot; data-filename=&quot;글 상단 부분 대표 이미지 (2).png&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;2025년, 인공지능 언어모델 시장은 초거대 모델의 경쟁 구도가 본격화되며 혁신의 정점을 향해 달려가고 있습니다. OpenAI의 GPT?4o, Google의 Gemini 2.5 Pro, Anthropic의 Claude 4, xAI의 Grok 3, 그리고 Meta, Mistral, DeepSeek, Moonshot AI 등 다수의 오픈소스 모델까지, 전 세계 주요 기업들이 AI 기술력을 쏟아붓고 있습니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;2025년 5월부터 7월 기준으로 공개된 성능 평가 및 벤치마크를 기반으로, 최신 AI 모델들을 자연어 처리, 코드 생성, 추론, 멀티모달, 컨텍스트 처리, 비용 효율성 등 다양한 측면에서 종합 비교한 결과를 정리합니다. 특히 실사용에 도움이 되도록 각 모델의 특화된 용도, 추천 활용 시나리오, 그리고 기업 및 개발자 관점에서의 선택 기준까지 폭넓게 다룹니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;누가 어떤 모델을 선택해야 할까? 2025년 현재 최고의 AI는 어떤것일까요?&lt;/span&gt;&lt;/p&gt;
&lt;center&gt;&lt;iframe src=&quot;https://www.youtube-nocookie.com/embed/HnvitMTkXro?si=Lnaze2HuN7AbkOvE&quot; width=&quot;560&quot; height=&quot;315&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;&lt;/center&gt;
&lt;div class=&quot;txc-textbox&quot; style=&quot;border-style: solid; font-weight: bold; border-width: 1px  1px  1px 5px; border-color: #707070; background-color: #fff; padding: 10px;&quot;&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;https://tistory3.daumcdn.net/tistory/1569230/skin/images/jquery.toc.js&quot;&gt;&lt;/script&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;목차&lt;/p&gt;
&lt;ul id=&quot;toc&quot; style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;&lt;/ul&gt;
&lt;script type=&quot;text/javascript&quot;&gt;
$(function(){
	$(&quot;#toc&quot;).toc( {content: &quot;.tt_article_useless_p_margin&quot;, headings: &quot;h1,h2,h3,h4&quot; , top: -90, isBlink : true, blinkColor : '#21B9DE' } ) });
&lt;/script&gt;
&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;LLM성능비교&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1536&quot; data-origin-height=&quot;1024&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/P1kqT/btsPqFZPYU9/adUkv5j2cHemzb8M2KR7p0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/P1kqT/btsPqFZPYU9/adUkv5j2cHemzb8M2KR7p0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/P1kqT/btsPqFZPYU9/adUkv5j2cHemzb8M2KR7p0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FP1kqT%2FbtsPqFZPYU9%2FadUkv5j2cHemzb8M2KR7p0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;681&quot; height=&quot;454&quot; data-origin-width=&quot;1536&quot; data-origin-height=&quot;1024&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;자연어 처리 능력 (이해와 생성) &lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;GPT-4o/4.5 (OpenAI)는 전반적인 지식수준과 대화 품질 면에서 가장 앞선 모델로 평가됩니다. 예컨대 학술&amp;middot;상식 분야 57개 과목을 다루는 MMLU 벤치마크에서 GPT-4.5 모델(o3)은 약 90.2%의 정답률을 기록하여, Anthropic&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;의 Claude 4(약 85~86%)나 Google DeepMind의 Gemini 2.5 Pro(약 85.8%)보다 소폭 높았습니다. 이는 역사, 법률, 과학 등 다양한 분야에서 GPT-4 계열이 보다 정확하고 자신감 있는 답변을 산출했음을 의미합니다. 또한, GPT-4.5는 대화의 자연스러움과 맥락 이해 면에서도 두각을 나타내어, OpenAI CEO인 Sam Altman이 &amp;ldquo;사려 깊은 사람과 대화하는 느낌&amp;rdquo;이라고 표현할 정도로 유창하고 감정까지 파악하는 응대를 보여줍니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Claude 4 (Anthropic) 역시 인간에 가까운 친근하고 상세한 응답을 제공하며, 맥락 유지에 뛰어난 모습을 보입니다. Claude 4의 지식응답 정확도(MMLU 약 85~86%)는 상위권 모델들과 비슷한 수준이지만, 특유의 따뜻하고 협력적인 어조와 장문 입력 처리 능력 덕분에 긴 대화나 문서 요약 작업에서 사용자 선호도가 높습니다. 또한, 지식수준과 대화에서의 문맥 파악 능력이 좋아 사용자가 길게 설명해도 일관성을 유지하며 답변하는 강점을 보입니다. 한편 Gemini 2.5 Pro (Google)는 뛰어난 논리적 일관성과 체계적인 응답으로 주목받는데, 체인-지식수준과-생각(chain-of-thought) 추론 방식을 기본적으로 활용하여 복잡한 질문에도 구조화된 논리로 답변하는 경향이 있습니다. 다만 어조는 비교적 중립적이고 연구조에 가까워, GPT나 Claude에 비해 다소 건조하게 느껴질 수 있다는 평가도 있습니다. 그럼에도 다국어 처리 능력에서 Gemini 2.5는 두각을 나타내며, 최신 벤치마크에서 다중언어 과제 수행에 높은 점수를 보여주었습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;오픈소스 지식수준과 이 시기 크게 발전하여, Meta의 지식수준과 3 (예 : 지식수준과 매개변수 버전) 같은 초거대 공개 모델은 상식 평가에서 상용 모델에 근접한 성능을 냈습니다. 예를 들어 LLaMA 3.1 405B 모델은 일부 지식시험에서 OpenAI GPT-4o와 비슷한 수준까지 도달하며, 최첨단 성능을 보였습니다 지식수준과 Yi 모델(01.ai 개발)은 영어와 중국어 이중언어 환경에 특화되어, 영중 번역이나 다문화 질의응답에서 강점을 보입니다. 종합적으로 2025년 중반의 최상위 언어 모델들은 광범위한 지식과 자연스러운 문장 생성 능력을 갖추고 있으며, 대부분 대학 졸업 수준의 상식 문제를 인간 이상의 정확도로 풀어내는 단계에 이르렀습니다. 다만 각 모델별로 대화 스타일과 세부 강점에 차이가 있어, 용도에 맞는 모델을 선택하는 것이 중요합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;코드 생성 및 프로그래밍 능력&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;최신 LLM들은 코드 생성 능력에서도 과거보다 월등히 향상되었습니다. Claude 4는 특히 프로그래밍 작업에서 선두로 꼽히는데, 실제 개발 업무를 모사한 SWE-Bench 평가에서 62~70% 수준의 정답률로 1위를 차지했습니다. Claude는 추론 과정을 설명하며 코드 작성을 하는 &amp;ldquo;확장된 사고&amp;rdquo; 모드 덕분에 어려운 문제도 단계별로 풀고, 디버깅이나 리팩토링까지 능숙하게 수행합니다. 개발자들은 Claude 4가 대규모 코드베이스를 이해하고 수정하는 능력이 뛰어나며, IDE 플러그인으로도 연계해 사용하면서 생산성이 크게 향상되었다고 평가합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Gemini 2.5 Pro는 코드 편집 및 멀티모달 코딩 시나리오에서 두각을 나타냅니다. 예를 들어 코드 편집 능력을 보는 Aider 벤치마크에서 Gemini는 73%의 높은 점수를 받아, 코드 개선 작업에 특히 강함을 보였습니다. 또한 이미지나 UI 시안을 입력받아 해당 기능을 구현하는 엔드투엔드 코딩에도 능하여, 디자인 목업을 입력하면 바로 웹앱을 생성하는 등 Google 생태계와 연계된 개발 작업에 적합합니다. OpenAI의 GPT-4.5 역시 여전히 안정적이고 범용적인 코딩 비서로 평가됩니다. GPT-4.5는 SWE-Bench에서 약 54.6%의 정확도를 보여 Claude나 Gemini보다는 약간 뒤졌지만, 깔끔하고 형식이 잘 갖춰진 코드를 생성하는 신뢰도 면에서는 높게 평가받습니다. 특히 명료한 지시를 주면 요구 사항에 맞는 코드를 한결같이 뽑아내고, 다수의 IDE와 개발자 도구에 통합되어 있어 실무 활용성이 뛰어납니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;흥미롭게도, Human과 같은 전통적 코딩 테스트에서는 Anthropic의 Claude 최신 모델이 최고 성적을 거두기도 했습니다. Claude 3.5 Sonnet 버전은 Human에서 92.0%의 문제 해결률을 기록하여, OpenAI GPT-4o의 90.2%보다 약간 높았습니다. 이는 Claude 모델이 정교한 코드 생성과 함수 구현에 매우 능숙함을 보여주는 지표입니다. 한편 Google의 Gemini도 일부 실시간 코딩 대회 벤치마크(예 : LiveCodeBench)에서는 Claude를 앞서는 등, 코드 생성 분야에서 상위 모델들 간 경쟁이 치열합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;오픈소스 진영에서도, StarCoder2와 같은 전문 코드 모델은 150억 규모 파라미터로도 훨씬 큰 모델에 맞먹는 성능을 내며 개발자들에게 활용되고 있습니다. 또한, 중국의 Moonshot AI가 공개한 Kimi K2 모델은 소프트웨어 개발 작업에 최적화되어, 회사 주장으로는 OpenAI GPT-4.1과 Anthropic Claude Opus 4를 코딩 분야에서 능가한다고 합니다. 이러한 최신 공개 모델의 등장은 상용 모델 위주의 코딩 지원 시장에 변화를 주고 있으며, 특히 Kimi K2는 무료 공개와 더불어 누구나 활용할 수 있도록 해 개발자 커뮤니티의 이목을 끌고 있습니다. 종합적으로, 2025년 최신 LLM들은 다수의 프로그래밍 언어에 정통하고, 함수 생성부터 버그 수정까지 광범위한 코딩 작업을 자동화해 줄 정도로 발전했습니다. 기업과 개발자는 각 모델의 장단점을 고려해, 장기간 복잡한 프로젝트에는 Claude 4, 멀티모달 프로토타이핑에는 Gemini, 일반적 코딩 도우미로는 GPT-4.5와 같이 적재적소에 활용하고 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;수학 및 논리 추론 능력&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;LLM들이 단순한 지식 응답을 넘어 수학 문제 해결과 논리 추론에서도 인간 수준에 도전하고 있습니다. 특히 Google DeepMind의 Gemini 2.5 Pro는 고차원 수리 추론에 강점을 보여, 미국 수학 경시대회(AIME 2025) 문제를 86.7%나 도구 없이 풀어냈습니다. 또한, 최신 난이도의 올림피아드 스타일 난제 모음인 MathArena 벤치마크에서는 Gemini가 24.4%의 점수를 획득해, 다른 모든 모델이 5% 미만에 그친 것과 큰 격차를 보였습니다. 이는 Gemini 모델이 내부적인 논리 사고 능력 면에서 독보적임을 시사하며, 단순히 공식을 암기하기보다 문제를 스스로 풀어나가는 과정이 뛰어나다는 평가입니다. 반면 OpenAI의 GPT-4.5 (o3) 모델은 외부 도구를 활용할 경우 거의 98~99%에 달하는 수학 정답률을 보여줍니다. 예를 들어 ChatGPT o3 모델은 파이썬 코드를 실행하는 도구 사용을 스스로 결정하여 계산이 필요한 수학 문제를 전산으로 풀어내는데, 이러한 자율적 도구 사용 능력을 통해 인간을 뛰어넘는 정밀도를 달성할 수 있습니다. 다만 도구 없이 순수 사고만으로는 GPT-4.5도 Gemini만큼의 성능은 내지 못해, 내재적 추론력은 Gemini가 한 발 앞선다는 분석이 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Anthropic의 Claude 4 역시 논리 퍼즐이나 추론 질문에서 우수한 성능을 보입니다. Claude는 긴 사고 체인을 유지하며 스스로 생각을 확장하는 특성이 있어, 복잡한 퍼즐이나 논증 과제를 풀 때 친절한 설명과 함께 결론에 도달하는 모습을 보입니다. 비록 순수 정답률 면에서는 최고치는 아니지만, 과정 설명이 풍부하고 사고력이 돋보인다는 점에서 교육용으로 유용하다는 평가입니다. 또한, Claude에는 &amp;ldquo;Extended Thinking(확장 사고)&amp;rdquo; 모드가 있어, 답을 내기 전에 문제를 깊이 숙고하고 단계별 검증을 거치는 전략으로 논리 오류를 줄이고 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;이 밖에도 주목해야 할 것은 DeepSeek-R1 같은 오픈소스 모델의 추론 혁신입니다. DeepSeek-R1은 강화학습을 통해 스스로 추론 능력을 향상한 연구로, 사전 지도 없이 RL만으로도 강력한 연쇄 추론과 자기 검증 능력이 나타날 수 있음을 보였습니다. 그 결과 탄생한 DeepSeek-R1 모델은 수학, 코드, 논증 과제에서 OpenAI의 최신 모델(OpenAI-o1)에 필적하는 성능을 달성했으며, 핵심 추론력을 작은 모델들에 지식 distillation하여 전수하는 데도 성공했습니다. 이는 연구 커뮤니티에 큰 반향을 일으켰고, 합리적인 비용으로도 최첨단 추론 AI를 구축할 수 있다는 가능성을 보여주었습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;현재 ARC (경합형 상식 추론)이나 GSM8K (초등 산수 응용) 같은 벤치마크는 최상위 모델들에게 거의 풀린 문제가 되었습니다. 예를 들어 GPT-4 계열은 ARC-Challenge에서 70~80% 이상의 높은 정확도를 기록하여 인간 상위권과 비슷한 성능을 냈고, GSM8K(초등학교 수준 계산 문제)는 chain-of-thought 기법을 활용해 대부분 해결하고 있는 수준입니다. 이에 따라 연구자들은 이제 더 어려운 경시대회 수준의 문제나 추론 퍼즐로 눈을 돌리고 있으며, 앞서 언급한 AIME, MathArena, Humanity&amp;rsquo;s Last Exam 등 새로운 고난도 평가에서 모델들의 한계를 시험하고 있습니다. 종합하면 2025년 현재. 또한, GPT-4 단순 지식 응답을 넘어 복잡한 문제를 스스로 풀어내는 사고력을 점차 갖춰가고 있습니다. 물론 아직 인간의 최고 전문가 수준에 완전히 도달한 것은 아니지만, 도구의 도움 여부를 떠나 논리적 일관성과 문제 해결력 측면에서 비약적 발전을 이뤘습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;멀티모달 처리 능력 (텍스트+이미지+음성 등)&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;멀티모달 AI란 텍스트뿐 아니라 이미지, 음성, 영상 등 다양한 형태의 입력을 동시에 이해하는 능력을 말하며, 2025년 최신. 또한, GPT-4 이 영역에서도 경쟁하고 있습니다. Google의 Gemini 2.5 Pro는 이 비교에 참여한 모델 중 유일하게 모든 주요 모달리티(텍스트, 이미지, 오디오, 비디오)를 네이티브로 처리할 수 있습니다. 사용자가 차트 이미지, 사진, 짧은 동영상 클립과 텍스트 설명을 함께 제공하면, Gemini는 이들을 한꺼번에 해석하여 통합된 답변을 만들어낼 수 있습니다. 이를 통해 미디어 요약, 학술 연구(논문+그래프 분석), 멀티모달 에이전트 개발 등에서 탁월한 성능을 보이며, 여러 형태의 데이터를 동시에 다루는 현실 세계 응용에 적합합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;OpenAI의 GPT-4o/4.5와 Anthropic의 Claude 4는 텍스트+이미지 입력을 지원하는 공통점이 있습니다. 두 모델 모두 사용자로부터 사진이나 스크린샷을 업로드 받아 그 내용을 분석하고 설명하거나, 이미지 속 글자를 읽어주는 등의 작업을 수행할 수 있습니다. GPT-4.5는 시각적 분석 능력이 정확하고 섬세하기로 정평이 나 있어, 밈(meme) 해석이나 복잡한 차트 읽기 등에 강점을 보입니다. Claude 4는 이미지에 대해 보다 대화체로 해석하여 설명해주는 경향이 있어, 사용자가 그림을 올리면 친절하게 묘사하거나 유추하는 식의 응답을 합니다. 그러나 이들 모델은 음성이나 영상 입력을 바로 받아들이는 기능은 아직 없으며(별도 음성 API나 외부 연동 필요), 이미지 생성 또한 내장되지 않고 기존의 DALL-E나 Stable Diffusion 같은 도구를 연계하는 방식으로 제공합니다. 그럼에도 일상적 멀티모달 요구?예를 들어 사진 속 표 읽기, 스크린샷 내용을 요약? 정도는 GPT-4나 Claude로도 충분히 소화하고 있어, 일반 사용자들에게 유용한 기능으로 자리 잡았습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;한편 xAI의 Grok 3는 특이하게도 이미지 생성 능력을 갖춘 모델입니다. 사용자가 원하는 장면을 묘사하면 Grok이 자체적으로 그림을 그려내거나 예술작품 수준의 이미지를 생성해 줍니다. 다만 Grok 3는 이미지를 입력받아 이해하는 기능은 지원하지 않아, 다른 모델들과 달리 멀티모달 입력 분석보다는 창작형 멀티모달 출력에 초점이 맞춰져 있습니다. 이를 통해 Grok은 밈 생성이나 간단한 디자인 시안 출력 등 창의적 용도에서 사랑받고 있지만, 분석적 멀티모달 작업에서는 경쟁 모델들에 뒤처집니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;오픈소스 생태계에서도 멀티모달 지원 모델이 속속 등장하고 있습니다. Meta의 LLaMA 3는 몇몇 변종에서 텍스트+이미지 기반 추론을 통합하여, 공개 모델로서 시각-언어 복합 과제에서 유용하게 쓰이고 있습니다. 또한 Yi-VL (Vision-Language) 모델은 중국 01.ai의 Yi 시리즈에 시각 정보를 접목한 연구로, 이미지와 텍스트를 함께 이해하도록 훈련되었습니다. Alibaba의 Qwen 2.5 역시 코더 버전과 수학 특화 버전 외에, 시각 이해를 강화한 모델을 포함하고 있어 멀티모달 활용도를 높이고 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;요약하면, 2025년의 주요. 또한, 텍스트를 넘어선 다양한 데이터 형태를 다루는 능력이 크게 향상되었습니다. Gemini 2.5 Pro처럼 모든 입력을 통합 처리하는 모델이 등장했고, GPT-4o/Claude 4처럼 이미지+텍스트 분야는 상용 서비스에도 활용되는 단계입니다. 아직 모든 모델이 음성이나 영상까지 완벽히 다루는 것은 아니지만, 이러한 멀티모달 처리 능력의 발전은 창작, 교육, 연구 등 분야에서 AI 활용 범위를 급격히 넓히고 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;컨텍스트 윈도우 및 효율성, 비용 대비 성능&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;컨텍스트 윈도우란 모델이 한 번에 받아들일 수 있는 입력 토큰의 길이를 말하며, 긴 문서나 많은 대화 이력을 처리하려면 이 윈도우 크기가 중요합니다. 2025년 최신 모델들은 컨텍스트 길이 경쟁도 본격화되어, Google Gemini 2.5 Pro는 무려 100만 토큰에 달하는 맥락을 한꺼번에 처리할 수 있습니다. 이는 수백 페이지에 달하는 책 여러 권 분량의 정보를 한 번에 넣을 수 있는 수준으로, Gemini는 그렇게 방대한 입력에서도 내용을 일관성 있게 파악하고 요약할 수 있음을 보여주었습니다. Anthropic Claude 4는 약 20만 토큰 컨텍스트로 . 또한, 깁니다. 20만 토큰은 대략 15만 단어 (500쪽 분량 문서)에 해당하는 용량으로, Claude는 이 덕분에 장문의 보고서나 복잡한 코드베이스도 한 번에 통째로 분석해 주는 용도로 주목받고 있습니다. OpenAI GPT-4.5 (ChatGPT o3)는 128천 토큰(약 책 한 권 분량)까지 지원하여 이전 GPT-4(8천수십만 토큰 수준 추정), Cohere Command R+나 Meta LLaMA 3 등의 오픈 모델들도 최대 128k 토큰 이상을 처리하도록 최적화되고 있어 상용 모델을 따라잡고 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;처리 효율성과 비용 측면에서는 모델의 크기와 아키텍처 최적화가 핵심 이슈입니다. OpenAI, Anthropic 등의 최상위 모델들은 수천억~수조 개의 매개변수를 갖추고 있어 그 자체로는 추론 비용이 매우 비쌉니다. 예컨대 Meta의 지식수준과 3 (70B) 모델을 풀사이즈로 활용하려면 멀티 GPU 서버가 필요하고, OpenAI GPT-4 계열 역시 대형 클러스터 상에서만 실시간 응답이 가능합니다. 그러나 Mistral 7B와 같은 소형 모델들은 가벼운 하드웨어에서도 동작하도록 특화되어, 품질 대비 추론 속도와 비용 효율이 뛰어난 경량 모델로 주목받고 있습니다. 실제로 프랑스 스타트업이 공개한 Mistral 7B 모델은 단일 GPU(예 : 지식수준과 4090)로도 구동 가능하며, 그룹화된 쿼리 어텐션 등 아키텍처 개선으로 효율을 극대화하여 파라미터당 성능이 매우 우수한 것으로 평가됩니다. 한편 DeepSeek-R1은 Mixture-of-Experts(MoE) 구조를 채택해 총 6,710억 개의 파라미터 중 매 질의마다 370억 정도만 활성화되는 방식으로 거대한 모델을 비교적 효율적으로 운용합니다. 이러한 MoE 접근법과 다중 헤드 잠재 지식수준과(지식수준과) 기법 덕분에 지식수준과 모델 규모와 비교하면 추론 속도가 빠르고 비용이 절감되는 혁신을 보여주었습니다. 지식수준과 up, 기업 입장에서는 꼭 초거대 모델 하나만 쓰기보다는, 작업 종류에 따라 경량 모델과 대형 모델을 혼용하여 성능과 비용의 균형을 잡는 전략이 대두되고 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;API 사용 비용도 실무에서 중요한 고려 사항입니다. 상용 지식수준과 API 호출에 따른 토큰 비용이 발생하는데, 최근 공개된 지식수준과 Anthropic Claude Opus 4는 백만 토큰당 입력 $15, 출력 $75 정도의 요금을 책정하고 있습니다. OpenAI GPT-4.1(GPT-4 개선판) API도 입력 $2, 출력 $8 per 1M tokens 수준으로 절대 저렴하진 않습니다. 이에 비해 중국 Moonshot AI의 Kimi K2와 같은 개방형 모델은 입력 100만 토큰당 $0.15, 출력 $2.50로 책정되어 있어, 미국계 모델 대비 수십 배 이상 저렴한 비용을 내세우고 있습니다. 더욱이 Kimi K2는 자체 웹앱을 통해 일반 사용자에 무료 제공되기도 하여 개발자들 사이에서 크게 주목받았습니다. 이런 저비용 전략은 대규모 배치가 필요한 서비스나 예산이 한정된 스타트업에 매력적으로 다가오며, 실제로 &amp;ldquo;대용량 또는 예산 제한이 있는 배포에 적합하다&amp;rdquo;는 평가를 받았습니다. 이처럼 토큰당 비용 경쟁은 향후 LLM 시장의 중요 변수가 되고 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;마지막으로, 자체 호스팅 vs 클라우드 활용 관점에서 비용을 보면, 오픈소스 모델을 직접 서버에 올려 쓰면 API 비용은 들지 않지만 GPU 인프라 비용과 관리 부담이 발생합니다. LLaMA 3 70B 같은 모델은 여러 장비가 필요해 중소기업엔 벅찰 수 있지만, LLaMA 3 8B나 Mistral 7B는 비교적 저렴한 장비로도 구동 가능하여 온프레미스 활용 사례가 늘고 있습니다. 또한 Command R+ 등 일부 오픈모델은 기업용으로 최적화되어 툴 사용 및 장문 RAG(Retri-Augmented Generation) 작업에 특화된 설계로 제공되므로, 특정 도메인에서는 공개 모델이 더 높은 비용 효율을 보이기도 합니다. 결국 성능 대비 비용 측면에서는, OpenAI&amp;middot;Anthropic 등 최고 성능 모델이 높은 비용을 정당화할 만큼의 가치를 주는지 vs 약간 성능을 양보하더라도 오픈 모델로 큰 비용 절감을 이룰지를 사용처에 맞게 판단해야 할 것입니다. 2025년 현재 시장에는 이러한 다양한 선택지가 존재하며, 기업들은 요구사항에 따라 성능과 비용의 최적 균형을 모색하고 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;결론 및 모델별 활용 추천 시나리오&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;2025년 중반 기준으로 볼 때, 지식수준과 &amp;ldquo;최고의 LLM&amp;rdquo; 하나를 고르는 것은 의미가 없을 정도로 여러 모델이 저마다 뛰어난 역량을 선보이고 있습니다. 따라서 사용 목적에 따라 적합한 모델을 선택하는 것이 중요합니다. 주요 모델들의 추천 활용 시나리오를 정리하면 다음과 같습니다&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;코딩 및 소프트웨어 개발 중심이라면 Claude 4 (Claude 3.7 Sonnet)이 적합합니다. 이 모델은 긴 코드도 한 번에 이해하고, 디버깅이나 코드리뷰처럼 심층적인 사고를 필요로 하는 프로그래밍 작업에서 탁월한 성능을 보여줍니다. 협업하듯 단계별로 설명해 주는 스타일은 큰 프로젝트의 설계 논의나 문제 해결에도 도움을 줍니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;깊은 논리적 분석, 과학 연구 및 방대한 데이터 문맥을 다룰 때는 Gemini 2.5 Pro를 추천합니다. 수백 페이지에 달하는 문서를 통합 분석하거나, 여러 이미지/데이터세트를 한꺼번에 처리하는 등 초대용량 컨텍스트와 멀티모달리티가 필요한 작업에선 Gemini의 능력을 따라올 모델이 없습니다. 복잡한 연구 리포트 작성, 데이터 사이언스 분야에서 특히 유용합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;일반적인 지식 QA, 일상 대화 및 다목적 활용에는 OpenAI 지식수준과 (GPT-4.5)가 여전히 만능형으로서 뛰어납니다. 세계 지식에 두루 정통하고 지식수준과 스타일 맞춤이 자유로워, 컨텐츠 생성, 요약, 번역, 비서 업무 등 광범위한 용도로 안정적입니다. 또한, API와 생태계 통합이 잘 되어있어 다양한 애플리케이션에 쉽게 붙일 수 있는 장점이 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;실시간 정보 접근, 트렌드 모니터링이나 유머러스한 톤이 필요하다면 지식수준과 Grok 3가 독특한 선택이 될 수 있습니다. Grok은 소셜미디어(X, 구 트위터)와 연결되어 최신 데이터를 바로 검색하기 때문에, 시시각각 변하는 뉴스나 온라인 유행을 따라잡아 답변해 줄 수 있습니다. 또한, 가벼운 농담이나 인터넷 지식수준과 능하고 약간 비꼬는 듯한 개성 있는 어조도 구사 가능하여, 다른 모델보다 지식수준과 친근한 대화 경험을 줍니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;데이터 프라이버시가 중요하거나 비용 효율을 최우선으로 할 경우 오픈소스 LLM을 고려해 볼 만합니다. 예를 들어 Meta의 LLaMA 3 (8B 등)은 자체 서버에 모델을 올려 사내 데이터로 학습시킬 수 있고, 경량화된 버전은 온프레미스 환경에서 빠르게 동작합니다. Mistral 7B는 소규모이지만 특화 작업에 충분한 성능을 내면서도 인프라 비용을 크게 절감할 수 있습니다. 또한 DeepSeek-R1은 최신 연구 수준의 추론력을 공개모델로 활용할 수 있어, 사고력 중심의 작업(예 : 어려운 퍼즐 풀이)을 자체 솔루션에 통합하려는 경우 적합합니다. Moonshot의 Kimi K2는 코딩 업무에 특화된 동시에 토큰 비용이 파격적으로 저렴하여, 예산이 한정된 스타트업이 대안으로 활용하기에 매력적입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;이처럼 한 가지 모델이 모든 면에서 최고가 아닌 시대에서는, 필요에 따라 여러 모델을 조합해 쓰는 전략도 부상하고 있습니다. 실제로 일부 워크플로우 도구는 GPT-4, Claude, Gemini, Grok 등을 상황별로 자동 호출하여 최상의 결과를 얻기도 합니다. 2025년 현재 전세계 AI 언어 모델 경쟁은 전에 없이 치열하며, 각기 다른 강점을 지닌 모델들이 공존함으로써 사용자와 기업에게는 더 넓은 선택지와 혁신의 기회가 열리고 있습니다. 앞으로도 새로운 모델의 등장과 기존 모델의 개선이 이어질 것이며, 신중한 평가와 신뢰할 만한 자료에 기반한 활용 전략이 그 어느 때보다 중요해질 것입니다. 항상 최신 동향을 주시하면서, 목적에 가장 부합하는 맞춤형 LLM 활용으로 최대의 성과를 거둘 수 있기를 기대합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&lt;span&gt;마무리&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;span&gt;2025년 중반에 이르러, 대형 언어모델(LLM)은 단순한 챗봇의 수준을 넘어 논리 추론, 코딩, 멀티모달 처리, 지식 요약 등 다양한 전문 영역에서 사람과 비슷하거나 그 이상의 능력을 보이고 있습니다. 특히 GPT‑4o, Claude 4, Gemini 2.5, Grok 3 등은 각기 다른 방향으로 발전하며, &amp;ldquo;누가 최고인가&amp;rdquo;보다 &amp;ldquo;누가 어디에 가장 적합한가&amp;rdquo;를 고민해야 할 시점이 되었습니다. &lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;span&gt;기업, 개발자, 콘텐츠 제작자, 연구자 등 각 분야의 수요에 따라 최적의 모델은 달라집니다. 정밀한 코드 작성에는 Claude, 멀티모달 통합과 분석에는 Gemini, 범용성과 안정성에는 GPT‑4o, 실시간성과 개성엔 Grok, 그리고 비용 대비 성능을 고려한 오픈소스 LLM까지. 선택지는 넓어졌고, 그만큼 판단 기준도 세분화되고 있습니다. &lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;span&gt;빠르게 진화하는 AI 생태계 속에서 중요한 것은, 단순한 성능 수치 그 이상으로, 자신이 속한 분야와 목표에 맞는 '실용적 선택'을 하는 것입니다. 앞으로도 계속해서 변화할 AI 모델들의 흐름을 주의 깊게 살피고, 기술을 목적에 맞게 활용하는 현명함이 필요한 시점입니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>IT</category>
      <category>2025최신ai</category>
      <category>ai모델성능비교</category>
      <category>ai벤치마크</category>
      <category>claude4</category>
      <category>gemini2.5pro</category>
      <category>gpt4o</category>
      <category>grok3</category>
      <category>LLM</category>
      <category>llm성능분석</category>
      <category>멀티모달ai</category>
      <author>간지뽕빨리턴님</author>
      <guid isPermaLink="true">https://odinbox.tistory.com/542</guid>
      <comments>https://odinbox.tistory.com/542#entry542comment</comments>
      <pubDate>Sun, 20 Jul 2025 05:51:09 +0900</pubDate>
    </item>
    <item>
      <title>에러 하나에 멘붕 왔던 개발자, 이렇게 극복했다.</title>
      <link>https://odinbox.tistory.com/541</link>
      <description>&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&quot;버그와 맞짱 뜨는 법&quot; - 개발자의 문제 해결 기술 공개&lt;/span&gt;&lt;/p&gt;
&lt;div class=&quot;txc-textbox&quot; style=&quot;font-weight: normal; position: relative; line-height: 40px; background: #007CBA; border: 1px solid #fff; padding: 10px; color: white; border-radius: 0 10px 0 10px; box-shadow: inset 0 0 5px rgba(53,86,129, 0.5); font-family: 'Muli', sans-serif; border-style: solid; border-width: 0px  0px  1px 15px; border-color: #232323; background-color: #007cba;&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-size: 15pt; color: #ffffff;&quot;&gt;&lt;b&gt;성장하기 - 모든 버그는 나를 강하게 만든다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;글 상단 부분 대표 이미지 (1).png&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dNHVwr/btsPf0pzPcL/aXxwq28Ylg56DgjKId4JPK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dNHVwr/btsPf0pzPcL/aXxwq28Ylg56DgjKId4JPK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dNHVwr/btsPf0pzPcL/aXxwq28Ylg56DgjKId4JPK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdNHVwr%2FbtsPf0pzPcL%2FaXxwq28Ylg56DgjKId4JPK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;400&quot; data-filename=&quot;글 상단 부분 대표 이미지 (1).png&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;코딩을 처음 시작한 신입 개발자부터 다년차 현업 개발자, 그리고 비전공자나 일반인까지 누구나 컴퓨터 프로그램 에러 앞에서는 머리를 긁적입니다. &quot;개발자들은 도대체 이런 문제를 어떻게 해결할까?&quot; 궁금하시다면 잘 오셨습니다. 이 글에서는 개발자의 문제 해결 접근 방식과 그 과정을 쉽고 유쾌하게 풀어보겠습니다. 기술적인 내용도 다루지만 어려운 용어는 비유와 예시로 설명할 테니 걱정하지 않으셔도 됩니다. 자, 그럼 버그와의 한판 승부 현장으로 함께 들어가 볼까요?&lt;/span&gt;&lt;/p&gt;
&lt;div class=&quot;txc-textbox&quot; style=&quot;border-style: solid; font-weight: bold; border-width: 1px  1px  1px 5px; border-color: #707070; background-color: #fff; padding: 10px;&quot;&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;https://tistory3.daumcdn.net/tistory/1569230/skin/images/jquery.toc.js&quot;&gt;&lt;/script&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;목차&lt;/p&gt;
&lt;ul id=&quot;toc&quot; style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;&lt;/ul&gt;
&lt;script type=&quot;text/javascript&quot;&gt;
$(function(){
	$(&quot;#toc&quot;).toc( {content: &quot;.tt_article_useless_p_margin&quot;, headings: &quot;h1,h2,h3,h4&quot; , top: -90, isBlink : true, blinkColor : '#21B9DE' } ) });
&lt;/script&gt;
&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;디버깅부터성찰까지&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;문제 이해하기 - 당황하지 말고 원인파악&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1536&quot; data-origin-height=&quot;1024&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/btmavA/btsPfJPbCdO/EkRUFsXUkOSBlG6bW5MFJ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/btmavA/btsPfJPbCdO/EkRUFsXUkOSBlG6bW5MFJ1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/btmavA/btsPfJPbCdO/EkRUFsXUkOSBlG6bW5MFJ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbtmavA%2FbtsPfJPbCdO%2FEkRUFsXUkOSBlG6bW5MFJ1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;486&quot; height=&quot;324&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1536&quot; data-origin-height=&quot;1024&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;문제가 발생하면 일단 심호흡부터 해봅시다. 초보든 고수든 문제를 정확히 이해하는 게 첫걸음입니다. 무엇이 기대한 대로 안되고 있나요? 에러메시지나 증상을 천천히 살펴보세요. 마치 의사가 환자 증상을 듣듯 프로그램의 증상과 상황을 꼼꼼하게 수집합니다. 예를 들어 &quot;버튼을 눌렀는데 앱이 꺼진다&quot;면 언제 어떤 버튼을 눌렀을 때 꺼지는지, 에러 메시지는 무엇인지 등을 확인하는 거죠&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;이해한 문제를 종이 위에 적어보거나 다른 사람에게 설명해 보는 것도 좋은 방법입니다. 문제를 글로 써보거나 아니면 컴퓨터를 모르는 친구에게라도 쉽지만 자세히 설명해 보세요. 말로 설명하는 과정에서 문제를 명확히 파악할 수 있습니다. 실제로 &quot;이러이러해서 이런 문제가 생겼어&quot;하고 말하다 보면 스스로 상황을 정리하게 되고 어디가 이상한지 감이 잡히기도 합니다. (개발자들이 고무 오리 인형에게 문제 설명하기도 하는데, 이 이야기는 뒤에서 조금 더 다뤄볼게요!) 아무튼 이 단계에서는 &quot;문제의 정체가 무엇인지&quot; 밝혀내는 데 집중해야 합니다. 원인을 정확히 알아야 제대로 된 해결책을 찾을 수 있으닌깐요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;전력 세우기 - 큰 문제를 작은 문제로 쪼개기&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1536&quot; data-origin-height=&quot;1024&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qhWz7/btsPeROcwR8/o89By6kv66TkZi7hALNLaK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qhWz7/btsPeROcwR8/o89By6kv66TkZi7hALNLaK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qhWz7/btsPeROcwR8/o89By6kv66TkZi7hALNLaK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqhWz7%2FbtsPeROcwR8%2Fo89By6kv66TkZi7hALNLaK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;507&quot; height=&quot;338&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1536&quot; data-origin-height=&quot;1024&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;이제 문제가 무엇인지 알았다면 당장 코딩하기보다는 해결 전략을 세워보세요 한꺼번에 모든 걸 해결하려고 하면 산처럼 막막하지만 작게 쪼개면 길이 보입니다. 많은 초보자들이 큰 문제를 한 번에 해결하려고 하는데 그러다 오히려 미궁에 빠지는 경우가 많습니다. 복잡한 문제는 더 작고 해결하기 쉬운 하위 문제로 분해해서 하나씩 해결하는 것이 훨씬 나은 접근입니다. 예를 들어 로그인 기능이 안 된다면 &quot;서버 연결 문제인지? 인증 로직 문제인지? UI 입력 문제인지?&quot; 나눠서 원인별로 살펴보는 식이죠.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;문제를 쪼겠다면 각 부분을 어떻게 풀지 계획을 세워봅니다. 코드를 바로 작성하기보다 먼저 의사 결정을 하는 단계입니다. 필요한 경우 간단히 의사코드(pseudocode)나 순서도를 그려볼 수 있습니다. 예컨대 1) 입력값 검증 2) 서버에 요청 3) 응답 처리하여 화면 표시와 같이 큰 흐름을 적어보는 거죠. 이렇게 하면 머릿속 복잡한 생각들이 정리되고 놓치기 쉬운 부분도 눈에 띕니다. 정리된 계획을 가지고 있으면 이제 본격적인 해결 과정에서도 길을 잃지 않고 차근차근 나아갈 수 있습니다. 개발자 세계에서는 &quot;코끼리를 먹을 때 한 입에 먹지 말고 한 조각씩 천천히 먹어라&quot;는 우스갯소리가 있는데, 큰 프로그램 문제를 다룰 때 꼭 기억해 볼 만한 조언입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;도구 활용하기 - 구글링부터 고무 오리까지&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;1024&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bd5A6N/btsPgfNAFri/AtzuKkGPUg3iJaf9FQvdg0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bd5A6N/btsPgfNAFri/AtzuKkGPUg3iJaf9FQvdg0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bd5A6N/btsPgfNAFri/AtzuKkGPUg3iJaf9FQvdg0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbd5A6N%2FbtsPgfNAFri%2FAtzuKkGPUg3iJaf9FQvdg0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;537&quot; height=&quot;537&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;1024&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;개발자는 때로 고무 오리에게 코드를 설명하며 디버깅한다. 문제가 어디에 있는지 오리에게 설명하다 보면 스스로 답을 깨닫기도 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;cfb6474f-5f82-40bb-abaa-983076ae1421.png&quot; data-origin-width=&quot;1000&quot; data-origin-height=&quot;1000&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vj00t/btsPfGx6Lma/myuuOuDgBCZvCnr5kB8Rd1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vj00t/btsPfGx6Lma/myuuOuDgBCZvCnr5kB8Rd1/img.png&quot; data-alt=&quot;인터넷에 올라가 있는 짤&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vj00t/btsPfGx6Lma/myuuOuDgBCZvCnr5kB8Rd1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fvj00t%2FbtsPfGx6Lma%2FmyuuOuDgBCZvCnr5kB8Rd1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;233&quot; height=&quot;233&quot; data-filename=&quot;cfb6474f-5f82-40bb-abaa-983076ae1421.png&quot; data-origin-width=&quot;1000&quot; data-origin-height=&quot;1000&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;인터넷에 올라가 있는 짤&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;개발자는 문제 해결을 위해 다양한 도구와 리소스를 총동원합니다. 가장 흔한 비밀무기는 역시 검색 엔진입니다. 흔히 &quot;구글신의 가호&quot;라고 농담할 정도로 에러 메시지나 궁금한 점을 구글에 검색하면 전 세계 개발자들의 Q&amp;amp;A 저장소인 Stack Overflow나 기술블로그 글이 답을 줄 때가 많습니다. 이미 누군가 비슷한 문제를 물어봤다면 해결책이 인터넷 어딘가에 있는 것이죠. 단, 무작정 복사-붙여넣기보다는 자신의 상황에 맞는지 꼭 확인해야 합니다. 검색으로 해결책을 찾으면 왜 그런지 이해하고 노력해 보세요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;다음으로 디버깅 도구들을 적극 활용합니다. 코드에 종지점(브레이크포이늩)을 걸어 한 줄씩 실행해 보거나 변수 값을 출력해 보는 식이죠. 이렇게 하면 코드가 실제로 어떻게 동작하는지 추적할 수 있습니다. 문제가 발생하는 지점을 찾았다면 그 부분을 집중적으로 뜯어볼 수 있어요. 그리고 앞서 언급한 고무 오리 디버깅은 많은 개발자들이 애용하는 기법입니다. 말 그대로 책상 옆에 둔 고무 오리에게 코드 동작을 하나하나 설명하는 거예요, 이 우스운 방법이 의외로 효과적인데 실제로 오리 인형에게 코드를 설명하면서 문제를 찾는 개발자의 일화에서 유래했습니다. 코드를 설명하다 보면 &quot;내 코드가 해야 하는 일과 실제 동작 사이의 불일치&quot;를 깨닫게 되어 스스로 해답을 얻는다는 원리죠, 꼭 오리 인형이 아니어도 좋습니다. 종이든, 식물이든, 혹은 동료나 친구에게 문제를 설명해 보세요. 정리가 안된 머릿속 생각이 말로 풀어내는 순간 명확해집니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;마지막으로 동료 개발자나 선배의 도움도 큰 자원입니다. 혼자 오래 끙끙대는 것보다 옆 사람에게 간단히 의견을 구하면 금방 해결되는 경우도 있습니다. 물론 질문할 때 문제 상황과 내가 시도한 것들을 정리해서 물어보는 게 예의입니다. 회사라면 코드 리뷰를 통해 또는 메신저로 '어디가 문제인지 잘 모르겠어요'하고 도움을 청할 수 있습니다. 친절한 선배라면 해결책뿐 아니라 접근 방법까지 배울 수 있습니다. (한 편으로 잔소리 폭격을 받을 수도 있습니다.) 개발 커뮤니티와 Q&amp;amp;A사이트에 익명으로 질문을 올려보는 것이 개발자의 일상입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;시행착오와 디버깅 - 끈질기게 파고들기&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1536&quot; data-origin-height=&quot;1024&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/opctt/btsPe6qQkCb/l7Wsz4vEY6spJoL7Xc5480/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/opctt/btsPe6qQkCb/l7Wsz4vEY6spJoL7Xc5480/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/opctt/btsPe6qQkCb/l7Wsz4vEY6spJoL7Xc5480/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fopctt%2FbtsPe6qQkCb%2Fl7Wsz4vEY6spJoL7Xc5480%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;522&quot; height=&quot;348&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1536&quot; data-origin-height=&quot;1024&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;이제 계획한 대로 하나씩 구현해 보면 문제 해결에 착수합니다. 그러나 현실은 만만치 않죠. 코드를 고치거나 새로운 시도를 하면 원하는 대로 딱 해결되면 좋지만 종종 또 다른 에러가 나타나거나 예상과 다른 결과가 나옵니다. 여기서 중요한 것은 포기하지 않고 여러 시도를 해보는 것입니다. 개발자는 시행착오(trial and error)를 통해 학습한다고 해도 과언이 아닙니다. 코드를 수정했다가 안되면 원상 복구하고 다른 원인을 의심해 보고 또 안 되면 로그를 더 찍어보고 이런 식으로 끈질기게 파고들어야 합니다. 마치 탐정이 단서를 찾기 위해 샅샅이 뒤지는 것처럼 개발자는 코드를 이리저리 살펴보며 문제의 원인을 추적합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;디버깅 과정에서 논리적인 가설 세우기가 도움이 됩니다. &quot;혹시 입력 값이 잘못 들어와서 그런가? 그렇다면 로그를 찍어서 입력을 해보자.&quot; 이런 식으로 문제의 원인을 몇 가지 가설로 세운 뒤 하나씩 검증해 보는 거죠. 이렇게 체계적으로 접근할 수 있고 무엇을 했는지 기록도 남으니 나중에 헷갈리지 않습니다. 반대로 생각 없이 코드를 여기저기 막 바꾸기 시작하면 무엇이 문제를 해결했고 무엇이 새로운 문제를 일으켰는지 혼란에 빠질 수 있습니다. 그러니 한 번에 한 가지씩 바꿔보고 확인하는 과학 실험 같은 방식을 추천합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;가끔은 황당한 해결책이 나오기도 합니다. &quot;컴퓨터를 껐다 켜니 되더라&quot;라든가 &quot;괄호 하나 고쳤더니 말끔히 해결됐다&quot;처럼요. 문제 원인이 정말 사소한 실수나 오타인 경우도 많습니다. 그래서 기본기를 점검하는 것도 잊지 마세요. 예를 들어 경로가 틀리지 않았나 변수 철자가 틀리지 않았나 서비스 재시작이 필요하지 않은가 등등 기본적인 체크리스트를 만들어 두면 좋습니다. 많은 버그들이 알고 보면 사람이라면 하기 마련인 실수에서 옵니다.&amp;nbsp; 그러니 자신을 너무 자책할 필요도 없습니다. 대신 실수를 발견하면 &quot;다음엔 이런 실수를 하지 말아야지&quot;하고 한 단계 성장하면 됩니다. 결국 디버깅은 끈기와 꼼꼼함, 그리고 약간의 유머 감각으로 버티는 과정일지 모릅니다. (예를 들어, &quot;버그가 도망 못 가게 커피 한 잔 더 하자!&quot;와 같은 농담을 스스로에게 건네보세요, 조금은 기운이 날지도 모릅니다!)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;성장하기 - 모든 버그를 나를 강하게 만든다&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;1024&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bOAIFd/btsPfuEGefD/oeqX6eT1CY7wpsGjWSKXG0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bOAIFd/btsPfuEGefD/oeqX6eT1CY7wpsGjWSKXG0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bOAIFd/btsPfuEGefD/oeqX6eT1CY7wpsGjWSKXG0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbOAIFd%2FbtsPfuEGefD%2FoeqX6eT1CY7wpsGjWSKXG0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;381&quot; height=&quot;381&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;1024&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;문제를 하나 해결했다면 스스로를 칭찬해 주세요. 개발자는 이렇게 하루에도 몇 번씩 성장합니다. 처음엔 사소한 오류 하나 고치는데 하루 종일 걸렸다면 나중엔 비슷한 문제를 금세 해결하는 자신을 발견하게 될 겁니다. 왜냐하면 한 번 부딪쳤던 문제는 경험치가 되어 다시 나타나도 두렵지 않거든요. 문제 해결 능력은 연습을 통해 향상됩니다. 심지어 실패도 괜찮습니다. 개발에서는 실패를 통해 배울 점이 많고, 다행히도 코드를 망가뜨린다고 해서 세상이 무너지지 않으닌깐요. 오히려 이런 시행착오를 통해 더 나은 방법을 찾게 되는 경우가 많습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;또한 혼자 겪는 어려움이라도 공유하면 보물이 됩니다. 회사 동료들과 해결 과정을 공유하거나 블로그에 정리해 보세요. 내가 삽질하며 찾은 해결책이 누군가에겐 소중한 정보가 될 수 있습니다. 동시에 글로 정리하는 과정에서 내가 완전히 이해하지 못했던 부분을 깨닫게 되기도 합니다. 이렇게 지식과 경험을 나누는 개발자들이 모여 커뮤니티도 발전하고 모두의 실력이 한층 올라가곤 합니다. 그리고 무엇보다 문제를 해결해 낸 성취감이야말로 개발자의 큰 보람입니다. 어렵게 잡은 버그일수록 &quot;해냈다!&quot;라는 쾌감이 크죠. 이 맛에 밤새 코딩하면서도 개발을 계속할 수 있는 거 아닐까요?&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;마지막으로 기억하세요! 모든 고수도 처음엔 초보였다는 사실을요. 지금 막막한 문제를 마주하고 있다면 과거의 어떤 개발자도 비슷한 고민을 했을 겁니다. 당장 답이 안 보이더라도 앞서 소개한 5단계를 하나씩 밟아 보세요. 문제를 이해하고, 작게 나누고, 도구를 쓰고, 시행착오를 거치며, 결국엔 성장하게 될 겁니다. 언젠가 당신도 누군가에게 &quot;개발자 선배&quot;로서 문제 해결 노하우를 전수해 주는 날이 올지 모릅니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;마무리&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1536&quot; data-origin-height=&quot;1024&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qAbg4/btsPeSzyzAf/315FsSnDpJKqHVWEHIEsVk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qAbg4/btsPeSzyzAf/315FsSnDpJKqHVWEHIEsVk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qAbg4/btsPeSzyzAf/315FsSnDpJKqHVWEHIEsVk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqAbg4%2FbtsPeSzyzAf%2F315FsSnDpJKqHVWEHIEsVk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;516&quot; height=&quot;344&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1536&quot; data-origin-height=&quot;1024&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;개발자의 문제 해결 과정을 알고 보면 논리적이면서도 창의적인 모험입니다. 처음에는 복잡한 오류가 우리를 좌절시키지만 차근차근 원인을 찾고 해결책을 모색하는 과정을 거치면 결국에는 컴퓨터에게 &quot;굿바이, 버그!&quot;라고 외칠 수 있게 되죠. 이번 글에서 소개한 접근 방식은 신입 개발자뿐만 아니라 비전공자나 일반인도 일상 속 문제 해결에 응용할 수 있는 팁이기도 합니다. 중요한 건 문제를 를 두려워하지 않고 도전하는 태도입니다. 개발자는 끊임없이 문제를 만나지만 그럴 때마다 한걸음 더 상장하게 됩니다. 그러니 다음엔 버그를 마주치면 당황하지 말고 앞서 말씀드린 대로 해결을 위한 도전을 해보세요! &quot;버그 잡는 건 참 힘들지만 재밌는 게임과 같으니까&quot;라는 마음으로요!&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;마지막으로 해당 내용을 통해 마인드셋에 도움이 되셨으면 좋겠습니다. 호기심과 끈기로 무장하면 어떤 문제든 정복할 수 있습니다. 이제 여러분도 개발자의 무기를 손에 넣었으니 코등 여정에 조금 더 자신감이 붙으셨으면 좋겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;다들 즐거운 코딩되세요! 또 본인이 생각을 하실 때 방법이 있다면 댓글을 통해 알려주세요!&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>DEVELOPMENT</category>
      <category>개발자</category>
      <category>디버깅</category>
      <category>문제점해결방식</category>
      <category>문제해결</category>
      <category>버그</category>
      <category>에러</category>
      <category>온보딩</category>
      <category>코드</category>
      <category>프로그래밍</category>
      <category>해결방법</category>
      <author>간지뽕빨리턴님</author>
      <guid isPermaLink="true">https://odinbox.tistory.com/541</guid>
      <comments>https://odinbox.tistory.com/541#entry541comment</comments>
      <pubDate>Sat, 12 Jul 2025 09:39:51 +0900</pubDate>
    </item>
    <item>
      <title>Google Gemini CLI,  사용방법</title>
      <link>https://odinbox.tistory.com/540</link>
      <description>&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;윈도우&amp;nbsp;기준으로&amp;nbsp;Node.js를&amp;nbsp;설치하고&amp;nbsp;Google의&amp;nbsp;최신&amp;nbsp;AI&amp;nbsp;터미널&amp;nbsp;도구인&amp;nbsp;Gemini&amp;nbsp;CLI를&amp;nbsp;사용하는&amp;nbsp;방법&lt;/span&gt;&lt;/p&gt;
&lt;div class=&quot;txc-textbox&quot; style=&quot;font-weight: normal; position: relative; line-height: 40px; background: #007CBA; border: 1px solid #fff; padding: 10px; color: white; border-radius: 0 10px 0 10px; box-shadow: inset 0 0 5px rgba(53,86,129, 0.5); font-family: 'Muli', sans-serif; border-style: solid; border-width: 0px  0px  1px 15px; border-color: #232323; background-color: #007cba;&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-size: 15pt; color: #ffffff;&quot;&gt;&lt;b&gt;윈도우에서&amp;nbsp;Node.js&amp;nbsp;설치부터&amp;nbsp;Gemini&amp;nbsp;CLI&amp;nbsp;설정까지&amp;nbsp;한 번에!&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;글 상단 부분 대표 이미지 (1).png&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bUeVxy/btsO6qa6jns/FHjpKKSqvkwYUMM3ycBtLK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bUeVxy/btsO6qa6jns/FHjpKKSqvkwYUMM3ycBtLK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bUeVxy/btsO6qa6jns/FHjpKKSqvkwYUMM3ycBtLK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbUeVxy%2FbtsO6qa6jns%2FFHjpKKSqvkwYUMM3ycBtLK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;400&quot; data-filename=&quot;글 상단 부분 대표 이미지 (1).png&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;개발 입문 자라면 AI 도구를 활용해 개발 생산성을 높이고 싶을 때가 있습니다. 구글이 공개한 Gemini CLI는 터미널에서 바로 AI 도움을 받을 수 있는 오픈소스 도구로 개인 Google 계정만 있으면 무료로 구글 AI 모델인 Gemini 2.5 Pro의 기능을 사용할 수 있습니다. 이 글에서는 윈도우(Windows) 운영체제 기준으로 NodeJS 설치부터 Google Gemini CLI 설치 및 초기 설정, 그리고 기본 사용방법까지 단계별로 정리를 해보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1096&quot; data-origin-height=&quot;617&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/blSimL/btsO6cc5Pxh/JC9qU1TlrHFP2wuiaFlmv1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/blSimL/btsO6cc5Pxh/JC9qU1TlrHFP2wuiaFlmv1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/blSimL/btsO6cc5Pxh/JC9qU1TlrHFP2wuiaFlmv1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FblSimL%2FbtsO6cc5Pxh%2FJC9qU1TlrHFP2wuiaFlmv1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1096&quot; height=&quot;617&quot; data-origin-width=&quot;1096&quot; data-origin-height=&quot;617&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;div class=&quot;txc-textbox&quot; style=&quot;border-style: solid; font-weight: bold; border-width: 1px  1px  1px 5px; border-color: #707070; background-color: #fff; padding: 10px;&quot;&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;https://tistory3.daumcdn.net/tistory/1569230/skin/images/jquery.toc.js&quot;&gt;&lt;/script&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;목차&lt;/p&gt;
&lt;ul id=&quot;toc&quot; style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;&lt;/ul&gt;
&lt;script type=&quot;text/javascript&quot;&gt;
$(function(){
	$(&quot;#toc&quot;).toc( {content: &quot;.tt_article_useless_p_margin&quot;, headings: &quot;h1,h2,h3,h4&quot; , top: -90, isBlink : true, blinkColor : '#21B9DE' } ) });
&lt;/script&gt;
&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;Google Gemini CLI&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;NodeJS 설치방법&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1689&quot; data-origin-height=&quot;900&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cU2qBY/btsO6ObuJcy/SN3nKOAjPrOcdglYULANr1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cU2qBY/btsO6ObuJcy/SN3nKOAjPrOcdglYULANr1/img.png&quot; data-alt=&quot;Install Node.JS를 선택해도 되고, 상단 다운로드를 선택하고 설치를 하셔도 됩니다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cU2qBY/btsO6ObuJcy/SN3nKOAjPrOcdglYULANr1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcU2qBY%2FbtsO6ObuJcy%2FSN3nKOAjPrOcdglYULANr1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1689&quot; height=&quot;900&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1689&quot; data-origin-height=&quot;900&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Install Node.JS를 선택해도 되고, 상단 다운로드를 선택하고 설치를 하셔도 됩니다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Gemini CLI는 NodeJS로 구현되어 있으므로 먼저 노드 JS를 먼저 설치를 해야 합니다. 사이트[&lt;a title=&quot;NodeJS&quot; href=&quot;https://nodejs.org/ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;#&lt;/a&gt;]에 접속을 하여 LTS 버전 설치 프로그램을 다운로드하면 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;183&quot; data-origin-height=&quot;643&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bNCylB/btsO7fs9GVd/D9B082KyJHAWI838AXAqYK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bNCylB/btsO7fs9GVd/D9B082KyJHAWI838AXAqYK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bNCylB/btsO7fs9GVd/D9B082KyJHAWI838AXAqYK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbNCylB%2FbtsO7fs9GVd%2FD9B082KyJHAWI838AXAqYK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;183&quot; height=&quot;643&quot; data-origin-width=&quot;183&quot; data-origin-height=&quot;643&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;설치를 하기 전 NodeJS가 설치되어 있는지 확인을 해보도록 하겠습니다, 하단 윈도우 로고에서 오른쪽 마우스 클릭하면 메뉴가 뜨는데 해당 메뉴에서 터미널(관리자)을 선택하고 아래의 명령어를 입력하면 됩니다. (설치를 다 하고 확인을 반드시 해주시길 바랍니다.)&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1751776693439&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;node -v # Node.JS 버전 확인(정상 설치 시 버전 번호 출력)
npm -v # npm 버전 확인(정상 설치 시 버전 번호 출력)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;정상적으로 설치가 되었다면 숫자로 된 글자 등이 출력이 될 것이고 만약 제대로 설치가 되질 않았다면 'node'은(는) 내부 또는 외부 명령... 인식되지 않습니다. 등의 에러 메시지가 나옵니다. 이때는 삭제하고 재설치하는 것을 추천해 드립니다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cgwwNW/btsO51pbz8y/OFLJp6A8vO76pBlqGkEkr1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cgwwNW/btsO51pbz8y/OFLJp6A8vO76pBlqGkEkr1/img.png&quot; data-origin-width=&quot;491&quot; data-origin-height=&quot;379&quot; data-is-animation=&quot;false&quot; data-filename=&quot;blob&quot; style=&quot;width: 49.7284%; margin-right: 10px;&quot; data-widthpercent=&quot;50.31&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cgwwNW/btsO51pbz8y/OFLJp6A8vO76pBlqGkEkr1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcgwwNW%2FbtsO51pbz8y%2FOFLJp6A8vO76pBlqGkEkr1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;491&quot; height=&quot;379&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/2cL3Z/btsO7eOyFGm/uCDaFTrNpQcEXChYyraKxK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/2cL3Z/btsO7eOyFGm/uCDaFTrNpQcEXChYyraKxK/img.png&quot; data-origin-width=&quot;490&quot; data-origin-height=&quot;383&quot; data-is-animation=&quot;false&quot; data-filename=&quot;blob&quot; style=&quot;width: 49.1088%;&quot; data-widthpercent=&quot;49.69&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/2cL3Z/btsO7eOyFGm/uCDaFTrNpQcEXChYyraKxK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F2cL3Z%2FbtsO7eOyFGm%2FuCDaFTrNpQcEXChYyraKxK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;490&quot; height=&quot;383&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cXqiG6/btsO6oj3Fy2/J7YPTb0mnBK7Ma2I8AX361/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cXqiG6/btsO6oj3Fy2/J7YPTb0mnBK7Ma2I8AX361/img.png&quot; data-origin-width=&quot;494&quot; data-origin-height=&quot;386&quot; data-is-animation=&quot;false&quot; data-filename=&quot;blob&quot; style=&quot;width: 32.313%; margin-right: 10px; margin-top: 10px;&quot; data-widthpercent=&quot;33.08&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cXqiG6/btsO6oj3Fy2/J7YPTb0mnBK7Ma2I8AX361/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcXqiG6%2FbtsO6oj3Fy2%2FJ7YPTb0mnBK7Ma2I8AX361%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;494&quot; height=&quot;386&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cgJiJv/btsO7NpouIz/Jmzwpay3SjOkAR5motVdI1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cgJiJv/btsO7NpouIz/Jmzwpay3SjOkAR5motVdI1/img.png&quot; data-origin-width=&quot;494&quot; data-origin-height=&quot;380&quot; data-is-animation=&quot;false&quot; data-filename=&quot;blob&quot; style=&quot;width: 32.8232%; margin-right: 10px; margin-top: 10px;&quot; data-widthpercent=&quot;33.6&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cgJiJv/btsO7NpouIz/Jmzwpay3SjOkAR5motVdI1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcgJiJv%2FbtsO7NpouIz%2FJmzwpay3SjOkAR5motVdI1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;494&quot; height=&quot;380&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wGXDH/btsO7HbFMrJ/satolqHeNec8cueakH8rfK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wGXDH/btsO7HbFMrJ/satolqHeNec8cueakH8rfK/img.png&quot; data-origin-width=&quot;491&quot; data-origin-height=&quot;381&quot; data-is-animation=&quot;false&quot; data-filename=&quot;blob&quot; style=&quot;width: 32.5382%; margin-top: 10px;&quot; data-widthpercent=&quot;33.32&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wGXDH/btsO7HbFMrJ/satolqHeNec8cueakH8rfK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwGXDH%2FbtsO7HbFMrJ%2FsatolqHeNec8cueakH8rfK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;491&quot; height=&quot;381&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cpeyjh/btsO6rA3W6v/m40ytN6tcyTR5pUki3Av21/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cpeyjh/btsO6rA3W6v/m40ytN6tcyTR5pUki3Av21/img.png&quot; data-origin-width=&quot;492&quot; data-origin-height=&quot;384&quot; data-is-animation=&quot;false&quot; data-filename=&quot;blob&quot; style=&quot;width: 32.3113%; margin-right: 10px; margin-top: 10px;&quot; data-widthpercent=&quot;33.08&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cpeyjh/btsO6rA3W6v/m40ytN6tcyTR5pUki3Av21/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcpeyjh%2FbtsO6rA3W6v%2Fm40ytN6tcyTR5pUki3Av21%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;492&quot; height=&quot;384&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bVfnue/btsO7wBoUsK/A410XpWFesNvEKZj3BZLpk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bVfnue/btsO7wBoUsK/A410XpWFesNvEKZj3BZLpk/img.png&quot; data-origin-width=&quot;490&quot; data-origin-height=&quot;380&quot; data-is-animation=&quot;false&quot; data-filename=&quot;blob&quot; style=&quot;width: 32.5187%; margin-right: 10px; margin-top: 10px;&quot; data-widthpercent=&quot;33.29&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bVfnue/btsO7wBoUsK/A410XpWFesNvEKZj3BZLpk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbVfnue%2FbtsO7wBoUsK%2FA410XpWFesNvEKZj3BZLpk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;490&quot; height=&quot;380&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bYqLmL/btsO6yz1iz5/bJ5KZHtErrLnl8aRSc1lw0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bYqLmL/btsO6yz1iz5/bJ5KZHtErrLnl8aRSc1lw0/img.png&quot; data-origin-width=&quot;491&quot; data-origin-height=&quot;377&quot; data-is-animation=&quot;false&quot; data-filename=&quot;blob&quot; style=&quot;width: 32.8444%; margin-top: 10px;&quot; data-widthpercent=&quot;33.63&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bYqLmL/btsO6yz1iz5/bJ5KZHtErrLnl8aRSc1lw0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbYqLmL%2FbtsO6yz1iz5%2FbJ5KZHtErrLnl8aRSc1lw0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;491&quot; height=&quot;377&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;사실상 설치를 할 때 특별하게 설정할 것이 없어 그냥 다음만 눌러도 잘 설치가 됩니다. 반드시 설치하고 명령프롬프트에 설치가 잘되었는지 확인하는 것을 권장해 드립니다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;Google Gemini GLI 설치방법(npm)&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;환경 세팅은 완료가 되었습니다. Gemini CLI는 npm 패키지로 배포되어 있어 한 줄의 명령어로 설치가 가능합니다. 명령프롬프트(또는 PowerShell)에서 아래 명령어를 실행하시면 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1113&quot; data-origin-height=&quot;620&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d1KRr1/btsO60bS0GR/4vNI7h8qkaJRBey9iBMpyK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d1KRr1/btsO60bS0GR/4vNI7h8qkaJRBey9iBMpyK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d1KRr1/btsO60bS0GR/4vNI7h8qkaJRBey9iBMpyK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd1KRr1%2FbtsO60bS0GR%2F4vNI7h8qkaJRBey9iBMpyK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1113&quot; height=&quot;620&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1113&quot; data-origin-height=&quot;620&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1751777289361&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm install -g @google/gemini-cli&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qfWtO/btsO6fABMU4/o0ltXzm7XgSpua8zRxmd91/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qfWtO/btsO6fABMU4/o0ltXzm7XgSpua8zRxmd91/img.png&quot; data-origin-width=&quot;1109&quot; data-origin-height=&quot;620&quot; data-is-animation=&quot;false&quot; data-filename=&quot;blob&quot; style=&quot;width: 49.8086%; margin-right: 10px;&quot; data-widthpercent=&quot;50.39&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qfWtO/btsO6fABMU4/o0ltXzm7XgSpua8zRxmd91/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqfWtO%2FbtsO6fABMU4%2Fo0ltXzm7XgSpua8zRxmd91%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1109&quot; height=&quot;620&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kBKZM/btsO5AFAnBW/SSQxybvflztt1g1uXzLIRK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kBKZM/btsO5AFAnBW/SSQxybvflztt1g1uXzLIRK/img.png&quot; data-origin-width=&quot;1111&quot; data-origin-height=&quot;631&quot; data-is-animation=&quot;false&quot; data-filename=&quot;blob&quot; style=&quot;width: 49.0286%;&quot; data-widthpercent=&quot;49.61&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kBKZM/btsO5AFAnBW/SSQxybvflztt1g1uXzLIRK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkBKZM%2FbtsO5AFAnBW%2FSSQxybvflztt1g1uXzLIRK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1111&quot; height=&quot;631&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;위 명령은 전역(-g) 옵션으로 Gemini CLI를 설치합니다. 설치 과정에서 인터넷을 통해 패키지를 내려받으므로 약간의 시간이 소모될 수 있습니다. 설치 완료 후 오류 없이 명령프롬프트로 돌아오게 되었다면 성공입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;* 전역 패키지 설치 시 권한 오류가 발생하는 경우 관리자 권한으로 명령 프롬프트를 실행하거나 Mac/Linux의 경우 sudo를 붙여 시도를 하면 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;Google Gemini CLI 초기 설정 및 Google 계정 인증&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;848&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nojqw/btsO54F8Y8I/haAMmkxz8OcwJF72jTTCvK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nojqw/btsO54F8Y8I/haAMmkxz8OcwJF72jTTCvK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nojqw/btsO54F8Y8I/haAMmkxz8OcwJF72jTTCvK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fnojqw%2FbtsO54F8Y8I%2FhaAMmkxz8OcwJF72jTTCvK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;848&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;848&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;이제 설치는 다 완료가 되었습니다. 터미널에서 Gemini 명령을 입력하면 실행을 할 수 있습니다. 처음 실행 시 CLI가 몇 가지 초기 설정을 필요로 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;테마 선택 : 터미널 화면에 텍스트 테마를 선택하는 메뉴가 나타나면 화살표 키로 마음에 드는 테마를 선택하고 Enter 키를 누릅니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;인증방법 선택 : Login With Google 구글 계정으로 로그인 옵션을 선택합니다. 개인 구글 계정으로 로그인하면 분당 60회 하루 1000회의 요청을 무료로 사용할 수 있는 자격이 주어집니다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;729&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/SUGFB/btsO6zr6rcQ/4Eb7YPo2MfnnJDPdLKyegK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/SUGFB/btsO6zr6rcQ/4Eb7YPo2MfnnJDPdLKyegK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/SUGFB/btsO6zr6rcQ/4Eb7YPo2MfnnJDPdLKyegK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FSUGFB%2FbtsO6zr6rcQ%2F4Eb7YPo2MfnnJDPdLKyegK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;729&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;729&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;구글 로그인 또는 제미나이 API Key를 사용을 하거나 Vertex AI 등을 선택을 할 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1125&quot; data-origin-height=&quot;447&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/urKLi/btsO5oSXTTY/50pcFvlNIKTSYCTkdERgb1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/urKLi/btsO5oSXTTY/50pcFvlNIKTSYCTkdERgb1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/urKLi/btsO5oSXTTY/50pcFvlNIKTSYCTkdERgb1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FurKLi%2FbtsO5oSXTTY%2F50pcFvlNIKTSYCTkdERgb1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1125&quot; height=&quot;447&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1125&quot; data-origin-height=&quot;447&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;678&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ds37Bo/btsO5Lz1dJw/Kms9SVA8hsGEnUPK7qVuN1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ds37Bo/btsO5Lz1dJw/Kms9SVA8hsGEnUPK7qVuN1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ds37Bo/btsO5Lz1dJw/Kms9SVA8hsGEnUPK7qVuN1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fds37Bo%2FbtsO5Lz1dJw%2FKms9SVA8hsGEnUPK7qVuN1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;678&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;678&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;설치부터 설정까지 모두 완료가 되었습니다. 간단하게 명령프롬프트에서 여러분이 원하는 것을 AI에 질문을 할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;무료 사용량 및 크레딧 확인방법&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;개인 계정으로 사용하는 한 완전히 무료로 사용을 할 수 있고 사용 한도도 일반적인 개발 작업량을 훨씬 웃돌 정도로 여유롭게 사용할 수 있습니다. 구글에 따르면 대부분의 개발자가 이 한도에 도달하지 않을 것이라고 한만큼 넉넉한 무료 사용량(분당 60회, 일 1000회 요청)을 제공을 하고 있습니다. 따라서 개인 프로젝트나 학습 용도로는 사실상 제한 없이 사용할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;무료 사용량 내에서는 별도의 크레딧을 충전을 할 필요가 없으며 크레딧 잔액을 신경 쓸 필요 없이 마음껏 AI 기능을 활용하면 됩니다. 그러나 만약에 기업 환경이나 이런 곳에서 여러 개발자가 동시에 사용을 한다면 구글 클라우드의 Vertext&amp;nbsp; AI API키를 사용해 확장할 수 있습니다. 구글 AI Studio에서 제미나이 키를 받급하여 유료로 사용을 하거나 할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;724&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c38Rro/btsO6n6u2dw/W6xmlgf5pkJxxpV3HdAVCk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c38Rro/btsO6n6u2dw/W6xmlgf5pkJxxpV3HdAVCk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c38Rro/btsO6n6u2dw/W6xmlgf5pkJxxpV3HdAVCk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc38Rro%2FbtsO6n6u2dw%2FW6xmlgf5pkJxxpV3HdAVCk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;724&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;724&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;현재 사용량이 궁금하다면 Gemini CLI 상에서 /help 명령을 입력하여 확인을 할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;MacOS/Linux 사용자를 위한 설치방법&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Mac은 아까 설치했던 NodeJS 공식홈페이지에서 설치를 진행을 하고 Linux 사용자의 경우 apt, dnf 등의 패키지 관리자 또는 NodeSource의 설치 스크립트를 사용할 수 있습니다. 어느 경우든 Node18 버전이상을 서치를 해야 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;그리고, npm install -g @google/gemini-cli를 입력하여 설치를 할 수 있습니다. 만약 에러가 난다면 앞에 sudo를 입력하시면 됩니다. 그리고 난 뒤 동일하게 초기 설정을 진행을 하고 설정하면 사용을 할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;마무리&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;이제 터미널에서 AI 활용하는 첫걸음을 떼신 것을 환영합니다. 처음에는 다소 생소할 수 있지만 사용하다 보면 자연어로 코딩을 돕고 문제를 해결해 주는 AI비서가 주는 편리함도 있을 겁니다. 특히 초보 개발자들에게 막막한 문제 해결을 하거나 예시코드를 얻는데 큰 도움이 될 수 있으니 적극적으로 활용해 보세요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;물론, 해당 제미나이 CLI가 완벽한 것은 아닙니다. 생성된 코드나 주고받은 내용들이 AI 학습을 위해 활용을 할 수 있다고 하니 유념해서 사용을 하시는 것을 추천해 드립니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;직접 여러분이 터미널에서 Gemini CLI를 실행하고 AI와 함께 코딩 경험을 즐겨보고 다양한 아이디어로 현실에서 만드는 속도가 빨라지고 개발 과정이 한층 수월해질 겁니다!&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;(+ 다음엔 이걸 활용하여 MCP를 구축하여 한번 만들어보도록 하겠습니다.)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>DEVELOPMENT</category>
      <category>geminicli</category>
      <category>mcp</category>
      <category>Nodejs</category>
      <category>개발툴</category>
      <category>명령프롬프트</category>
      <category>무료AI</category>
      <category>윈도우개발</category>
      <category>인공지능</category>
      <category>챗봇</category>
      <category>터미널</category>
      <author>간지뽕빨리턴님</author>
      <guid isPermaLink="true">https://odinbox.tistory.com/540</guid>
      <comments>https://odinbox.tistory.com/540#entry540comment</comments>
      <pubDate>Sun, 6 Jul 2025 14:21:46 +0900</pubDate>
    </item>
  </channel>
</rss>