<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>숭맹's 기술블로그</title>
        <link>https://velog.io/</link>
        <description>👨🏻‍💻 Backend Developer</description>
        <lastBuildDate>Fri, 25 Apr 2025 00:30:04 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>숭맹's 기술블로그</title>
            <url>https://velog.velcdn.com/images/smpaaark-tech/profile/09442c89-83b6-4b33-8f4b-4e4485bf1af9/image.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. 숭맹's 기술블로그. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/smpaaark-tech" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[Installation of Airflow]]></title>
            <link>https://velog.io/@smpaaark-tech/Installation-of-Airflow</link>
            <guid>https://velog.io/@smpaaark-tech/Installation-of-Airflow</guid>
            <pubDate>Fri, 25 Apr 2025 00:30:04 GMT</pubDate>
            <description><![CDATA[<h2 id="📌-설치-전에-알아야-할-기본-사항">📌 설치 전에 알아야 할 기본 사항</h2>
<p>Airflow 설치 전에 반드시 확인해야 할 사항이 있습니다:</p>
<ul>
<li><strong>지원 버전</strong>: Python, Kubernetes 호환성 확인 필수</li>
<li><strong>필수 조건</strong>: 시스템 패키지, 사용자 권한, 네트워크 설정 등</li>
<li><strong>의존성 관리</strong>: Providers 및 Extras 패키지를 통한 기능 확장</li>
<li><strong>DB 설정</strong>: Metadata DB는 Airflow의 핵심, 업그레이드 시 마이그레이션 필요</li>
</ul>
<hr>
<h2 id="🛠-설치-방식-비교">🛠 설치 방식 비교</h2>
<h3 id="1-공식-소스-코드-설치-from-source">1. <strong>공식 소스 코드 설치 (From Source)</strong></h3>
<ul>
<li><strong>추천 대상</strong>: 소프트웨어 무결성과 커스텀 빌드가 중요한 팀</li>
<li><strong>장점</strong>: ASF 정책에 따라 신뢰성 있는 소스 제공</li>
<li><strong>단점</strong>: 설치 및 유지보수에 드는 시간과 노력 증가</li>
<li><strong>책임</strong>:<ul>
<li>모든 컴포넌트 빌드 및 설치</li>
<li>DB 구성, 자동화 스크립트 작성</li>
<li>리소스 모니터링 및 성능 튜닝 전담</li>
</ul>
</li>
</ul>
<h3 id="2-pypi-설치-pip">2. <strong>PyPI 설치 (pip)</strong></h3>
<ul>
<li><strong>추천 대상</strong>: Python 기반 배포에 익숙한 팀</li>
<li><strong>장점</strong>: 패키지 설치가 간단하고 빠름</li>
<li><strong>단점</strong>: 프로덕션 환경에서의 튜닝은 별도 필요</li>
<li><strong>책임</strong>:<ul>
<li>제약 파일을 사용한 안정적 설치</li>
<li>DB 및 모니터링 설정</li>
<li>커스텀 구성 및 리소스 관리</li>
</ul>
</li>
</ul>
<h3 id="3-공식-docker-이미지">3. <strong>공식 Docker 이미지</strong></h3>
<ul>
<li><strong>추천 대상</strong>: 컨테이너 인프라(Docker, Compose)에 익숙한 팀</li>
<li><strong>장점</strong>: 격리된 환경에서 빠르게 구성 가능</li>
<li><strong>단점</strong>: 커스텀 dependency가 많다면 이미지 재빌드 필요</li>
<li><strong>책임</strong>:<ul>
<li>docker-compose 등으로 multi-container 설정 구성</li>
<li>DB, 모니터링, 업그레이드 전략 수립</li>
</ul>
</li>
</ul>
<h3 id="4-helm-chart-kubernetes-기반">4. <strong>Helm Chart (Kubernetes 기반)</strong></h3>
<ul>
<li><strong>추천 대상</strong>: Kubernetes 클러스터 운영 경험이 있는 팀</li>
<li><strong>장점</strong>:<ul>
<li>커뮤니티에서 관리하는 안정적인 배포 구조</li>
<li>자동화된 컴포넌트 재시작 및 복구</li>
</ul>
</li>
<li><strong>단점</strong>:<ul>
<li>Helm Chart 및 K8s 리소스 커스터마이징 학습 필요</li>
</ul>
</li>
<li><strong>책임</strong>:<ul>
<li>Helm 값 파일 관리</li>
<li>커스텀 이미지 빌드 및 배포 파이프라인 구성</li>
</ul>
</li>
</ul>
<h3 id="5-managed-airflow-services">5. <strong>Managed Airflow Services</strong></h3>
<ul>
<li><strong>추천 대상</strong>: 직접 운영 부담을 줄이고 싶은 팀</li>
<li><strong>장점</strong>:<ul>
<li>설치, 업그레이드, 리소스 조절 모두 위임 가능</li>
</ul>
</li>
<li><strong>단점</strong>:<ul>
<li>비용 증가</li>
<li>커스터마이징 제한</li>
</ul>
</li>
<li><strong>책임</strong>: 대부분 매니지드 서비스에서 처리. 문서 확인 필요</li>
</ul>
<h3 id="6-3rd-party-배포-옵션">6. <strong>3rd-party 배포 옵션</strong></h3>
<ul>
<li><strong>추천 대상</strong>: 기존 레거시 인프라를 유지해야 하는 경우</li>
<li><strong>주의사항</strong>: 공식 지원 없음, 커뮤니티 지원 한계 있음</li>
</ul>
<hr>
<h2 id="⚙️-운영-환경에서-고려할-요소">⚙️ 운영 환경에서 고려할 요소</h2>
<p>Airflow는 복잡한 시스템입니다. 다음과 같은 요소가 성능과 리소스 요구사항에 영향을 줍니다:</p>
<ul>
<li>DAG 개수, 동시 실행 Task 수</li>
<li>DAG의 복잡도 및 외부 시스템 연동 여부</li>
<li>설치 방식에 따른 Infra 요구사항 (Docker vs K8s vs VM)</li>
<li>Scheduler 튜닝 및 리소스(CPU, Memory) 설정</li>
<li>Providers 및 Plugin 사용 범위</li>
</ul>
<p>🧠 <strong>팁:</strong> <code>Fine-tuning Scheduler</code>, <code>Best Practices</code> 문서를 통해 사전 튜닝 전략을 준비하세요.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[History of MySQL]]></title>
            <link>https://velog.io/@smpaaark-tech/History-of-MySQL</link>
            <guid>https://velog.io/@smpaaark-tech/History-of-MySQL</guid>
            <pubDate>Fri, 25 Apr 2025 00:24:32 GMT</pubDate>
            <description><![CDATA[<h2 id="msql에서-출발한-여정">mSQL에서 출발한 여정</h2>
<p>MySQL의 시작은 의외로 <strong>mSQL (Mini SQL)</strong>이라는 또 다른 경량 데이터베이스와 관련이 깊습니다. 당시 MySQL의 개발자들은 빠른 속도를 위해 자체 <strong>ISAM(Indexed Sequential Access Method)</strong> 기반의 로우레벨 스토리지 엔진을 사용하고 있었고, 이를 SQL 인터페이스로 연결하기 위해 mSQL을 고려했습니다.</p>
<p>하지만 mSQL은 테스트 결과 다음과 같은 한계점이 발견되었습니다:</p>
<ul>
<li><strong>성능 부족</strong>: 자체 ISAM 루틴의 속도를 따라가지 못함</li>
<li><strong>유연성 결여</strong>: 복잡한 쿼리와 다양한 요구사항을 충족하기 어려움</li>
</ul>
<p>결국, MySQL 개발자들은 다음과 같은 결정을 내리게 됩니다:</p>
<blockquote>
<p>&quot;mSQL은 우리가 원하는 성능을 제공하지 못하니, <strong>우리가 직접 SQL 인터페이스를 만들자</strong>. 단, mSQL API와 최대한 유사하게 구현해서 기존 코드를 쉽게 이식할 수 있도록 하자.&quot;</p>
</blockquote>
<p>이 결정은 단순한 기능 개발을 넘어, 오픈소스 생태계와의 호환성을 염두에 둔 철학적인 선택이었다고 볼 수 있습니다.</p>
<hr>
<h2 id="mysql이라는-이름의-유래">MySQL이라는 이름의 유래</h2>
<p>MySQL의 이름에서 ‘My’는 단순한 영문 접두사가 아닙니다. <strong>공동 창립자인 Monty Widenius의 딸의 이름</strong>에서 유래한 것입니다. 즉, ‘My’는 개인적인 의미가 담긴 이름이고, ‘SQL’은 우리가 알고 있는 Structured Query Language에서 따온 것입니다.</p>
<p>이런 작명은 단순히 기능 중심이 아닌 <strong>개발자 중심의 철학과 감성</strong>이 녹아 있는 상징적인 예라고 볼 수 있습니다.</p>
<hr>
<h2 id="마스코트-돌고래-sakila의-이야기">마스코트 돌고래, ‘Sakila’의 이야기</h2>
<p>MySQL의 로고를 보면 귀여운 돌고래가 떠오르실 텐데요. 이 돌고래의 이름은 <strong>Sakila</strong>입니다. 재미있는 점은 이 이름이 내부에서 정해진 것이 아니라, 전 세계 사용자들이 참여한 <strong>“Name the Dolphin” 콘테스트</strong>를 통해 탄생했다는 점입니다.</p>
<p>최종 선정된 이름 <strong>Sakila</strong>는 다음과 같은 배경을 가지고 있습니다:</p>
<ul>
<li>제안자: <strong>Ambrose Twebaze</strong>, 에스와티니(구 스와질랜드) 출신 오픈소스 개발자</li>
<li>의미: <strong>SiSwati어에서 유래된 여성 이름</strong>이며, 탄자니아 아루샤 근처에 위치한 마을 이름이기도 함</li>
</ul>
<p>즉, 이 이름은 단순한 마스코트 명칭을 넘어 <strong>글로벌 커뮤니티와의 연결 고리</strong>를 상징하며, 오픈소스 생태계의 가치를 잘 보여주는 사례라고 할 수 있습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Objects In Kubernetes]]></title>
            <link>https://velog.io/@smpaaark-tech/Objects-In-Kubernetes</link>
            <guid>https://velog.io/@smpaaark-tech/Objects-In-Kubernetes</guid>
            <pubDate>Fri, 25 Apr 2025 00:20:26 GMT</pubDate>
            <description><![CDATA[<h2 id="오브젝트란-무엇인가">오브젝트란 무엇인가?</h2>
<p>Kubernetes에서 오브젝트는 <strong>&quot;원하는 상태(desired state)&quot;의 선언</strong>입니다. 이 선언은 다음과 같은 클러스터 상태를 정의합니다:</p>
<ul>
<li>어떤 애플리케이션이 어떤 노드에서 실행 중인지</li>
<li>애플리케이션에 할당된 리소스</li>
<li>재시작 정책, 업그레이드 방식, 장애 허용성과 같은 동작 정책</li>
</ul>
<p>오브젝트는 단순한 리소스 정보 이상의 의미를 가지며, Kubernetes는 이 선언을 기반으로 클러스터를 끊임없이 조율합니다. 이처럼 오브젝트는 &quot;명령&quot;이 아니라 &quot;의도&quot;를 기록하는 방식이라는 점에서, <strong>선언적(declarative)</strong> 접근을 대표합니다.</p>
<hr>
<h2 id="오브젝트의-구조">오브젝트의 구조</h2>
<p>대부분의 Kubernetes 오브젝트는 다음과 같은 공통 필드를 갖습니다:</p>
<pre><code class="language-yaml">apiVersion: &lt;API 버전&gt;
kind: &lt;오브젝트 종류&gt;
metadata:
  name: &lt;오브젝트 이름&gt;
  namespace: &lt;네임스페이스 (선택)&gt;
spec:
  ... 원하는 상태에 대한 정의 ...</code></pre>
<h3 id="필드-설명">필드 설명</h3>
<ul>
<li><code>apiVersion</code>: 해당 오브젝트를 처리할 API의 버전</li>
<li><code>kind</code>: 생성하고자 하는 오브젝트의 종류 (예: Deployment, Pod 등)</li>
<li><code>metadata</code>: 이름, 라벨, 네임스페이스 등 식별자 정보</li>
<li><code>spec</code>: 오브젝트가 어떤 상태를 가져야 하는지 정의</li>
</ul>
<p>또한, Kubernetes는 <code>status</code>라는 필드를 통해 현재 상태(actual state)를 기록합니다. 이는 시스템이 자동으로 업데이트하며, 사용자는 수정하지 않습니다.</p>
<hr>
<h2 id="예제-deployment-오브젝트">예제: Deployment 오브젝트</h2>
<pre><code class="language-yaml">apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.14.2
        ports:
        - containerPort: 80</code></pre>
<p>위 YAML은 <code>nginx</code> 컨테이너를 2개의 복제본으로 실행하는 Deployment를 정의합니다. 중요한 점은 이 설정이 단순히 &quot;2개의 nginx를 실행하라&quot;는 명령이 아니라, <strong>&quot;2개가 항상 존재해야 한다&quot;는 의도를 담고 있다는 것</strong>입니다. Kubernetes는 이 의도를 만족시키기 위해 pod를 생성하고, 실패 시 재시작하며, 롤링 업데이트도 처리합니다.</p>
<p>적용 방법:</p>
<pre><code class="language-bash">kubectl apply -f deployment.yaml</code></pre>
<hr>
<h2 id="오브젝트와-api">오브젝트와 API</h2>
<p>오브젝트는 결국 Kubernetes API를 통해 정의되고 조작됩니다. <code>kubectl</code> CLI는 이러한 API 호출을 추상화해주는 도구일 뿐입니다. 직접 프로그램에서 오브젝트를 생성하거나 조회하고 싶다면, Kubernetes 클라이언트 라이브러리를 사용할 수 있습니다 (Go, Python, Java 등).</p>
<hr>
<h2 id="유효성-검사-validation">유효성 검사 (Validation)</h2>
<p>Kubernetes v1.25부터는 <strong>서버 측 필드 유효성 검사</strong>가 도입되었습니다. 기존에는 <code>kubectl --validate=true</code>를 통해 클라이언트 측에서만 필드 유효성을 검사했지만, 이제는 서버에서 직접 잘못된 필드나 중복된 항목을 검사합니다.</p>
<h3 id="검사-옵션">검사 옵션</h3>
<ul>
<li><code>strict</code>: 유효하지 않으면 에러</li>
<li><code>warn</code>: 유효하지 않아도 경고만 출력</li>
<li><code>ignore</code>: 검사를 수행하지 않음</li>
</ul>
<p>기본값은 <code>strict</code>이며, 이는 CI/CD 환경에서 잘못된 리소스 정의로 인한 장애를 미리 방지하는 데 효과적입니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Quick Start]]></title>
            <link>https://velog.io/@smpaaark-tech/Quick-Start-9ll32kaq</link>
            <guid>https://velog.io/@smpaaark-tech/Quick-Start-9ll32kaq</guid>
            <pubDate>Fri, 25 Apr 2025 00:14:25 GMT</pubDate>
            <description><![CDATA[<h2 id="🧱-step-1-kafka-설치">🧱 Step 1: Kafka 설치</h2>
<p>Kafka를 사용하려면 먼저 최신 릴리스를 다운로드해야 합니다. Scala 버전에 따라 바이너리를 선택해야 하며, 예시는 <code>Scala 2.13</code>과 Kafka <code>4.0.0</code> 기준입니다.</p>
<pre><code class="language-bash">$ tar -xzf kafka_2.13-4.0.0.tgz
$ cd kafka_2.13-4.0.0</code></pre>
<blockquote>
<p>✅ <strong>TIP</strong>: 로컬 실행을 위해 Java 17 이상이 설치되어 있어야 합니다.</p>
</blockquote>
<hr>
<h2 id="🚀-step-2-kafka-서버-실행">🚀 Step 2: Kafka 서버 실행</h2>
<h3 id="🛠-옵션-1-로컬-환경에서-직접-실행">🛠 옵션 1: 로컬 환경에서 직접 실행</h3>
<pre><code class="language-bash"># 클러스터 UUID 생성
$ KAFKA_CLUSTER_ID=&quot;$(bin/kafka-storage.sh random-uuid)&quot;

# 로그 디렉토리 포맷
$ bin/kafka-storage.sh format --standalone -t $KAFKA_CLUSTER_ID -c config/server.properties

# Kafka 서버 실행
$ bin/kafka-server-start.sh config/server.properties</code></pre>
<h3 id="🐳-옵션-2-docker-사용">🐳 옵션 2: Docker 사용</h3>
<h4 id="jvm-기반-이미지">JVM 기반 이미지</h4>
<pre><code class="language-bash">$ docker pull apache/kafka:4.0.0
$ docker run -p 9092:9092 apache/kafka:4.0.0</code></pre>
<h4 id="graalvm-기반-native-이미지">GraalVM 기반 Native 이미지</h4>
<pre><code class="language-bash">$ docker pull apache/kafka-native:4.0.0
$ docker run -p 9092:9092 apache/kafka-native:4.0.0</code></pre>
<blockquote>
<p>✅ <strong>TIP</strong>: 도커로 빠르게 테스트 환경을 만들 수 있지만, 로그 볼륨 마운트 등 설정도 함께 고려하세요.</p>
</blockquote>
<hr>
<h2 id="📁-step-3-토픽-생성">📁 Step 3: 토픽 생성</h2>
<p>Kafka에서 이벤트는 토픽 단위로 저장됩니다. 토픽은 파일 시스템의 폴더와 유사합니다.</p>
<pre><code class="language-bash">$ bin/kafka-topics.sh --create --topic quickstart-events --bootstrap-server localhost:9092</code></pre>
<p>토픽 정보 확인:</p>
<pre><code class="language-bash">$ bin/kafka-topics.sh --describe --topic quickstart-events --bootstrap-server localhost:9092</code></pre>
<hr>
<h2 id="✍️-step-4-이벤트-생산-producer">✍️ Step 4: 이벤트 생산 (Producer)</h2>
<pre><code class="language-bash">$ bin/kafka-console-producer.sh --topic quickstart-events --bootstrap-server localhost:9092
&gt;This is my first event
&gt;This is my second event</code></pre>
<blockquote>
<p>🚀 한 줄 입력마다 개별 이벤트로 저장됩니다.</p>
</blockquote>
<hr>
<h2 id="📥-step-5-이벤트-소비-consumer">📥 Step 5: 이벤트 소비 (Consumer)</h2>
<pre><code class="language-bash">$ bin/kafka-console-consumer.sh --topic quickstart-events --from-beginning --bootstrap-server localhost:9092</code></pre>
<p><code>Ctrl-C</code>로 종료할 수 있으며, 복수의 콘슈머가 동시에 동일 토픽을 소비하는 것도 가능합니다.</p>
<hr>
<h2 id="🔄-step-6-kafka-connect로-외부-연동">🔄 Step 6: Kafka Connect로 외부 연동</h2>
<p>파일 → Kafka 토픽 → 파일 구조의 간단한 파이프라인을 구성할 수 있습니다.</p>
<h3 id="설정-추가">설정 추가</h3>
<pre><code class="language-bash">$ echo &quot;plugin.path=libs/connect-file-4.0.0.jar&quot; &gt;&gt; config/connect-standalone.properties</code></pre>
<h3 id="테스트-데이터-작성">테스트 데이터 작성</h3>
<pre><code class="language-bash">$ echo -e &quot;foo\nbar&quot; &gt; test.txt</code></pre>
<h3 id="커넥트-실행">커넥트 실행</h3>
<pre><code class="language-bash">$ bin/connect-standalone.sh config/connect-standalone.properties config/connect-file-source.properties config/connect-file-sink.properties</code></pre>
<h3 id="결과-확인">결과 확인</h3>
<pre><code class="language-bash">$ more test.sink.txt
foo
bar</code></pre>
<p>Kafka 토픽에서 직접 확인도 가능:</p>
<pre><code class="language-bash">$ bin/kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic connect-test --from-beginning</code></pre>
<hr>
<h2 id="🧠-step-7-kafka-streams로-실시간-처리">🧠 Step 7: Kafka Streams로 실시간 처리</h2>
<p>Kafka Streams는 Kafka 토픽의 데이터를 실시간으로 처리할 수 있는 Java/Scala 클라이언트 라이브러리입니다.</p>
<h3 id="wordcount-예제">WordCount 예제</h3>
<pre><code class="language-java">KStream&lt;String, String&gt; textLines = builder.stream(&quot;quickstart-events&quot;);
KTable&lt;String, Long&gt; wordCounts = textLines
    .flatMapValues(line -&gt; Arrays.asList(line.toLowerCase().split(&quot; &quot;)))
    .groupBy((keyIgnored, word) -&gt; word)
    .count();

wordCounts.toStream().to(&quot;output-topic&quot;, Produced.with(Serdes.String(), Serdes.Long()));</code></pre>
<blockquote>
<p>☑️ 실시간 집계, 윈도우, 조인 등 복잡한 스트림 연산을 처리할 수 있어 실시간 데이터 분석에 적합합니다.</p>
</blockquote>
<hr>
<h2 id="🧹-step-8-환경-정리">🧹 Step 8: 환경 정리</h2>
<pre><code class="language-bash"># Kafka 종료: Ctrl-C
# 로그/데이터 삭제
$ rm -rf /tmp/kafka-logs /tmp/kraft-combined-logs</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[The Domain Language of Batch]]></title>
            <link>https://velog.io/@smpaaark-tech/The-Domain-Language-of-Batch</link>
            <guid>https://velog.io/@smpaaark-tech/The-Domain-Language-of-Batch</guid>
            <pubDate>Fri, 25 Apr 2025 00:02:48 GMT</pubDate>
            <description><![CDATA[<h2 id="🔧-spring-batch-핵심-개념">🔧 Spring Batch 핵심 개념</h2>
<h3 id="job">Job</h3>
<ul>
<li><strong>정의</strong>: 전체 배치 작업을 의미하는 컨테이너</li>
<li><strong>구성</strong>: 하나 이상의 Step으로 구성됨</li>
<li><strong>설정</strong>: Java DSL 또는 XML 설정 가능</li>
</ul>
<pre><code class="language-java">@Bean
public Job sampleJob(JobRepository jobRepository) {
    return new JobBuilder(&quot;sampleJob&quot;, jobRepository)
            .start(step1())
            .next(step2())
            .build();
}</code></pre>
<hr>
<h2 id="🧱-실행-단위와-흐름">🧱 실행 단위와 흐름</h2>
<h3 id="jobinstance">JobInstance</h3>
<ul>
<li>Job 정의 + 식별자(JobParameters)</li>
<li>동일한 Job 정의라도 다른 파라미터로 실행되면 새로운 JobInstance 생성</li>
</ul>
<h3 id="jobparameters">JobParameters</h3>
<ul>
<li>JobInstance를 유일하게 식별하는 파라미터 집합</li>
<li>날짜, 버전, ID 등 비즈니스 키 포함 가능</li>
</ul>
<h3 id="jobexecution">JobExecution</h3>
<ul>
<li>하나의 JobInstance 실행 시도 (성공/실패 관계없이 1회 실행)</li>
<li>재시도 시 새로운 JobExecution 생성됨</li>
</ul>
<h3 id="step">Step</h3>
<ul>
<li>Job을 구성하는 단위 실행 블록</li>
<li>독립적으로 구성 가능</li>
<li>ItemReader, ItemProcessor, ItemWriter를 조합</li>
</ul>
<h3 id="stepexecution">StepExecution</h3>
<ul>
<li>Step의 실행 이력 단위</li>
<li>JobExecution과 매핑됨</li>
</ul>
<h3 id="executioncontext">ExecutionContext</h3>
<ul>
<li>JobExecution 또는 StepExecution에 종속된 상태 저장소</li>
<li>직렬화 가능해야 하며, 재시작 시 상태 복구에 사용됨</li>
</ul>
<pre><code class="language-java">ExecutionContext ec = stepExecution.getExecutionContext();
ec.putLong(&quot;linesRead&quot;, 40321L);</code></pre>
<hr>
<h2 id="📦-처리-구성요소">📦 처리 구성요소</h2>
<h3 id="itemreader">ItemReader</h3>
<ul>
<li>입력 데이터 소스로부터 데이터를 읽는 컴포넌트</li>
<li>null 반환 시 더 이상 읽을 데이터가 없음을 의미</li>
</ul>
<h3 id="itemprocessor">ItemProcessor</h3>
<ul>
<li>비즈니스 로직을 수행하는 처리 컴포넌트</li>
<li>유효하지 않은 데이터는 null 반환으로 필터링 가능</li>
</ul>
<h3 id="itemwriter">ItemWriter</h3>
<ul>
<li>처리된 데이터를 출력하는 컴포넌트</li>
</ul>
<hr>
<h2 id="🗃️-메타데이터-저장-구조">🗃️ 메타데이터 저장 구조</h2>
<p>Spring Batch는 실행 이력을 아래와 같은 테이블에 저장합니다:</p>
<ul>
<li><strong>BATCH_JOB_INSTANCE</strong>: Job 이름 및 파라미터</li>
<li><strong>BATCH_JOB_EXECUTION</strong>: Job 실행 정보 (상태, 시작/종료 시간 등)</li>
<li><strong>BATCH_STEP_EXECUTION</strong>: Step 실행 정보</li>
<li><strong>BATCH_EXECUTION_CONTEXT</strong>: 상태 정보</li>
</ul>
<hr>
<h2 id="🧪-예제-시나리오로-이해하기">🧪 예제 시나리오로 이해하기</h2>
<ol>
<li><code>EndOfDayJob</code>을 01-01에 실행 → 실패</li>
<li>01-01 동일 파라미터로 재실행 → 성공</li>
<li>01-02 파라미터로 실행 → 성공</li>
</ol>
<p>→ JobInstance는 2개, JobExecution은 3개 생성됨</p>
<hr>
<h2 id="⚙️-java-기반-설정-시-참고">⚙️ Java 기반 설정 시 참고</h2>
<pre><code class="language-java">@Configuration
@EnableBatchProcessing
public class BatchConfig {

    @Bean
    public JobLauncher jobLauncher(JobRepository jobRepository) {
        return new SimpleJobLauncher(jobRepository);
    }

    @Bean
    public Step sampleStep() {
        return stepBuilderFactory.get(&quot;sampleStep&quot;)
            .&lt;Input, Output&gt;chunk(10)
            .reader(reader())
            .processor(processor())
            .writer(writer())
            .build();
    }

    // reader(), processor(), writer() 구현 생략
}</code></pre>
<hr>
<h2 id="✅-실무에서-얻는-이점">✅ 실무에서 얻는 이점</h2>
<table>
<thead>
<tr>
<th>장점</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td>책임 분리</td>
<td>각 컴포넌트가 단일 책임을 갖도록 분리되어 있음</td>
</tr>
<tr>
<td>확장성</td>
<td>커스텀 구현이 용이함 (예: 커스텀 ItemReader)</td>
</tr>
<tr>
<td>재시작 가능성</td>
<td>실패한 지점에서의 복구를 자동으로 처리 가능</td>
</tr>
<tr>
<td>표준화</td>
<td>명확한 실행 흐름과 메타데이터 관리로 운영이 수월함</td>
</tr>
</tbody></table>
]]></description>
        </item>
        <item>
            <title><![CDATA[영속성 컨텍스트 2]]></title>
            <link>https://velog.io/@smpaaark-tech/%EC%98%81%EC%86%8D%EC%84%B1-%EC%BB%A8%ED%85%8D%EC%8A%A4%ED%8A%B8-2</link>
            <guid>https://velog.io/@smpaaark-tech/%EC%98%81%EC%86%8D%EC%84%B1-%EC%BB%A8%ED%85%8D%EC%8A%A4%ED%8A%B8-2</guid>
            <pubDate>Thu, 24 Apr 2025 23:49:23 GMT</pubDate>
            <description><![CDATA[<p>김영한님의 자바 ORM 표준 JPA 프로그래밍 - 기본편 정리</p>
<h2 id="🔍-영속성-컨텍스트란">🔍 영속성 컨텍스트란?</h2>
<p><code>EntityManager</code>는 내부적으로 영속성 컨텍스트(Persistence Context)를 유지한다. 쉽게 말해, <strong>JPA가 엔티티를 관리하는 메모리 공간</strong>이다.</p>
<ul>
<li><strong>1차 캐시</strong>: 영속성 컨텍스트 내부에서 가장 핵심적인 역할을 수행.</li>
<li>엔티티의 <strong>PK를 키</strong>, 실제 객체를 값으로 가지는 Map 형태.</li>
</ul>
<pre><code class="language-java">Member member = new Member();
member.setId(&quot;member1&quot;);
member.setUsername(&quot;회원1&quot;);
em.persist(member); // 비로소 영속 상태 진입</code></pre>
<p>이제 <code>member1</code>은 1차 캐시에 저장된다.</p>
<hr>
<h2 id="📌-1차-캐시의-이점">📌 1차 캐시의 이점</h2>
<h3 id="1-조회-최적화">1. 조회 최적화</h3>
<pre><code class="language-java">Member find1 = em.find(Member.class, &quot;member1&quot;); // SELECT 발생
Member find2 = em.find(Member.class, &quot;member1&quot;); // 캐시에서 조회, SELECT 없음</code></pre>
<ul>
<li>같은 트랜잭션 내에서 동일 엔티티 조회 시, <strong>DB가 아닌 1차 캐시에서 가져옴</strong></li>
</ul>
<h3 id="2-동일성-보장-">2. 동일성 보장 (==)</h3>
<pre><code class="language-java">System.out.println(find1 == find2); // true</code></pre>
<ul>
<li>같은 인스턴스를 반환하기 때문에 <code>==</code> 비교도 true</li>
<li>이는 JPA가 제공하는 <strong>REPEATABLE READ 수준의 트랜잭션 일관성</strong>을 보장하는 핵심 기제</li>
</ul>
<hr>
<h2 id="🕐-쓰기-지연-write-behind-buffering">🕐 쓰기 지연 (Write-Behind Buffering)</h2>
<p><code>em.persist()</code> 호출 시, 바로 DB에 INSERT 되지 않는다.</p>
<pre><code class="language-java">em.getTransaction().begin();
em.persist(memberA);
em.persist(memberB);
// 아직 INSERT 없음
em.getTransaction().commit(); // 이 순간 INSERT SQL 실행</code></pre>
<h3 id="➕-이점">➕ 이점</h3>
<ul>
<li>여러 INSERT 쿼리를 <strong>모아서 한 번에 보내 성능 최적화</strong> 가능</li>
<li>Hibernate는 <code>hibernate.jdbc.batch_size</code> 옵션으로 JDBC 배치 처리도 지원</li>
</ul>
<hr>
<h2 id="🧼-변경-감지-dirty-checking">🧼 변경 감지 (Dirty Checking)</h2>
<pre><code class="language-java">Member member = em.find(Member.class, &quot;member1&quot;);
member.setUsername(&quot;변경됨&quot;);
em.getTransaction().commit(); // UPDATE SQL 자동 발생</code></pre>
<ul>
<li><code>em.update()</code> 같은 명시적 호출 필요 없음</li>
<li>JPA는 최초 상태 스냅샷과 비교해 변경이 있으면 UPDATE 쿼리 생성</li>
</ul>
<h3 id="✅-내부-동작-원리">✅ 내부 동작 원리</h3>
<ol>
<li>영속 상태 진입 시 스냅샷 생성</li>
<li>트랜잭션 커밋 시점에 현재 상태와 비교</li>
<li>변경 사항 있으면 UPDATE SQL 생성 후 실행</li>
</ol>
<hr>
<h2 id="🗑️-엔티티-삭제">🗑️ 엔티티 삭제</h2>
<pre><code class="language-java">Member member = em.find(Member.class, &quot;member1&quot;);
em.remove(member);
em.getTransaction().commit(); // DELETE SQL 발생</code></pre>
<ul>
<li>마찬가지로 커밋 시점에 삭제 쿼리 실행</li>
</ul>
<hr>
<h2 id="🔄-플러시-flush">🔄 플러시 (Flush)</h2>
<ul>
<li><strong>영속성 컨텍스트 → DB 반영 작업</strong></li>
<li>커밋 시점 자동 수행 or 수동으로 <code>em.flush()</code> 호출 가능</li>
</ul>
<pre><code class="language-java">em.flush(); // 강제로 DB에 반영</code></pre>
<hr>
<h2 id="💡-실무-팁">💡 실무 팁</h2>
<ul>
<li>트랜잭션 범위 안에서 같은 엔티티 여러 번 조회하면 DB 부하 줄일 수 있음</li>
<li>변경 감지 메커니즘을 이해하면 불필요한 <code>update()</code> 호출 줄일 수 있음</li>
<li>JDBC 배치 설정을 잘 활용하면 대량 INSERT 시 성능 개선 가능</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[MVC와 템플릿 엔진]]></title>
            <link>https://velog.io/@smpaaark-tech/MVC%EC%99%80-%ED%85%9C%ED%94%8C%EB%A6%BF-%EC%97%94%EC%A7%84</link>
            <guid>https://velog.io/@smpaaark-tech/MVC%EC%99%80-%ED%85%9C%ED%94%8C%EB%A6%BF-%EC%97%94%EC%A7%84</guid>
            <pubDate>Thu, 24 Apr 2025 23:35:41 GMT</pubDate>
            <description><![CDATA[<p>김영한님의 스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술 정리</p>
<h2 id="✅-mvc-패턴이란">✅ MVC 패턴이란?</h2>
<p>MVC(Model-View-Controller)는 <strong>소프트웨어 설계의 관심사 분리(Separation of Concerns)</strong>를 위한 대표적인 아키텍처입니다. 웹 개발에서 이 패턴은 특히 유지보수와 확장성을 확보하는 데 강력한 장점을 제공합니다.</p>
<h3 id="🔹-구성-요소">🔹 구성 요소</h3>
<ul>
<li><strong>Model</strong>: 애플리케이션의 데이터 및 비즈니스 로직 담당 (ex. DB 연동, 서비스 로직)</li>
<li><strong>View</strong>: 사용자에게 보여지는 UI (HTML, Thymeleaf 등)</li>
<li><strong>Controller</strong>: 클라이언트 요청을 받고, 적절한 모델을 선택 및 처리 후 뷰로 전달</li>
</ul>
<p>과거에는 JSP 안에 비즈니스 로직, 화면 처리, DB 연동이 한 파일에 몰려있는 <strong>Model 1</strong> 방식이 많았지만, 이는 유지보수 지옥을 불러왔습니다. 현대적 방식인 MVC는 이를 구조적으로 분리합니다.</p>
<hr>
<h2 id="✅-spring-mvc-예제-코드">✅ Spring MVC 예제 코드</h2>
<p>간단한 Hello 예제를 통해 MVC 구조를 설명하겠습니다.</p>
<h3 id="📌-controller">📌 Controller</h3>
<pre><code class="language-java">@Controller
public class HelloController {

    @GetMapping(&quot;hello-mvc&quot;)
    public String helloMvc(@RequestParam(&quot;name&quot;) String name, Model model) {
        model.addAttribute(&quot;name&quot;, name);
        return &quot;hello-template&quot;; // templates/hello-template.html 뷰 반환
    }
}</code></pre>
<h3 id="📌-view-hello-templatehtml">📌 View (<code>hello-template.html</code>)</h3>
<pre><code class="language-html">&lt;html xmlns:th=&quot;http://www.thymeleaf.org&quot;&gt;
&lt;body&gt;
  &lt;p th:text=&quot;&#39;hello &#39; + ${name}&quot;&gt;hello! empty&lt;/p&gt;
&lt;/body&gt;
&lt;/html&gt;</code></pre>
<h3 id="📌-실행-예시">📌 실행 예시</h3>
<pre><code>http://localhost:8080/hello-mvc?name=spring</code></pre><p>➡️ 브라우저 출력: <code>hello spring</code></p>
<hr>
<h2 id="✅-템플릿-엔진---thymeleaf">✅ 템플릿 엔진 - Thymeleaf</h2>
<p>Thymeleaf는 HTML을 그대로 작성하면서, 서버 사이드에서 동적으로 데이터를 바인딩할 수 있는 템플릿 엔진입니다.</p>
<h3 id="장점">장점</h3>
<ul>
<li>정적 HTML로도 열람 가능 → 퍼블리셔 협업 용이</li>
<li>스프링 부트와 자연스럽게 통합</li>
<li>뷰 레이어 로직 최소화 가능</li>
</ul>
<p>템플릿 파일은 <code>resources/templates</code> 경로에 <code>.html</code> 파일로 작성하며, <code>${}</code> 문법으로 모델 값을 치환합니다.</p>
<hr>
<h2 id="✅-전체-흐름-요약-텍스트-기반-순서도">✅ 전체 흐름 요약 (텍스트 기반 순서도)</h2>
<ol>
<li>사용자가 URL 접속: <code>/hello-mvc?name=spring</code></li>
<li>내장 톰캣이 요청을 받고 Spring DispatcherServlet으로 전달</li>
<li><code>HelloController.helloMvc()</code> 메서드 매핑</li>
<li>name 파라미터를 <code>Model</code>에 담고 &quot;hello-template&quot; 리턴</li>
<li>ViewResolver가 템플릿 파일 <code>hello-template.html</code>을 탐색</li>
<li>Thymeleaf가 모델 값을 바인딩하여 HTML 렌더링</li>
<li>최종 HTML을 브라우저에 반환</li>
</ol>
<hr>
<h2 id="✅-실전-개발에서의-적용-포인트">✅ 실전 개발에서의 적용 포인트</h2>
<ul>
<li><strong>Controller는 얇게 유지</strong>: 최대한 비즈니스 로직은 Service 레이어로 위임</li>
<li><strong>Model은 DTO로 깔끔하게 구성</strong>: 불필요한 객체 넘기지 않기</li>
<li><strong>View는 순수 화면 전용</strong>: 로직 없이 화면 구성만 책임지도록</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Kotlin] 변수 시작]]></title>
            <link>https://velog.io/@smpaaark-tech/Kotlin-%EB%B3%80%EC%88%98-%EC%8B%9C%EC%9E%91</link>
            <guid>https://velog.io/@smpaaark-tech/Kotlin-%EB%B3%80%EC%88%98-%EC%8B%9C%EC%9E%91</guid>
            <pubDate>Thu, 24 Apr 2025 23:28:26 GMT</pubDate>
            <description><![CDATA[<p>김영한님의 자바 입문 - 코드로 시작하는 자바 첫걸음 정리</p>
<h2 id="변수란-무엇인가">변수란 무엇인가?</h2>
<p>&quot;변수&quot;는 말 그대로 <strong>변할 수 있는 수(value)</strong>입니다. 프로그래밍에서는 <strong>값을 저장하고, 그 값을 참조할 수 있는 이름이 붙은 메모리 공간</strong>을 의미하죠.</p>
<h2 id="왜-변수가-필요한가">왜 변수가 필요한가?</h2>
<p>아래와 같은 코드를 보겠습니다:</p>
<pre><code class="language-kotlin">fun main() {
    println(10)
    println(10)
    println(10)
}</code></pre>
<p>단순히 <code>10</code>을 3번 출력합니다. 하지만 요구사항이 바뀌어 <code>20</code>으로 바꿔야 한다면?<br>→ 3곳 모두 직접 수정해야 합니다. 이 작업이 100군데면 어떨까요?</p>
<p>이런 상황에서 <strong>변수</strong>를 도입하면 다음과 같이 바뀝니다:</p>
<pre><code class="language-kotlin">fun main() {
    var a = 10
    println(a)
    println(a)
    println(a)
}</code></pre>
<p>이제는 <code>a</code>의 값만 바꾸면 전체 출력 결과가 바뀝니다.</p>
<h2 id="변수-선언과-초기화">변수 선언과 초기화</h2>
<pre><code class="language-kotlin">var a: Int // 변수 선언
a = 10     // 초기화</code></pre>
<p>또는 한 줄로 간단히:</p>
<pre><code class="language-kotlin">var a = 10</code></pre>
<ul>
<li><code>var</code>는 <strong>변할 수 있는 변수</strong>를 선언합니다.</li>
<li><code>val</code>은 <strong>변하지 않는 변수</strong>를 선언할 때 사용합니다 (불변 변수).</li>
<li><code>a</code>는 변수명이고, <code>Int</code>는 정수 타입입니다.</li>
</ul>
<h2 id="변수-사용의-이점">변수 사용의 이점</h2>
<ol>
<li><strong>재사용성</strong>: 여러 곳에서 같은 값을 사용 가능</li>
<li><strong>유지보수 용이성</strong>: 한 번만 값 변경하면 전체 수정</li>
<li><strong>가독성 향상</strong>: 의미 있는 이름을 통해 코드 의도 전달</li>
<li><strong>동적 입력 대응 가능</strong>: 사용자 입력 등 변하는 값 대응</li>
</ol>
<h2 id="실행-흐름-예시">실행 흐름 예시</h2>
<pre><code class="language-kotlin">fun main() {
    var a = 20
    println(a)
    println(a)
    println(a)
}</code></pre>
<p>모든 출력 결과는 <code>20</code>. 변수 하나만 수정했을 뿐인데 전체 출력이 함께 바뀌었습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Java] 변수 시작]]></title>
            <link>https://velog.io/@smpaaark-tech/Java-%EB%B3%80%EC%88%98-%EC%8B%9C%EC%9E%91</link>
            <guid>https://velog.io/@smpaaark-tech/Java-%EB%B3%80%EC%88%98-%EC%8B%9C%EC%9E%91</guid>
            <pubDate>Thu, 24 Apr 2025 23:26:36 GMT</pubDate>
            <description><![CDATA[<p>김영한님의 자바 입문 - 코드로 시작하는 자바 첫걸음 정리</p>
<h2 id="변수란-무엇인가">변수란 무엇인가?</h2>
<p>&quot;변수&quot;는 말 그대로 <strong>변할 수 있는 수(value)</strong>입니다. 프로그래밍에서는 <strong>값을 저장하고, 그 값을 참조할 수 있는 이름이 붙은 메모리 공간</strong>을 의미하죠. 이 공간은 프로그램이 실행되는 동안 필요한 데이터를 저장하고, 다시 사용할 수 있게 해주는 매우 핵심적인 기능입니다.</p>
<h2 id="왜-변수가-필요한가">왜 변수가 필요한가?</h2>
<p>아래와 같은 코드를 보겠습니다:</p>
<pre><code class="language-java">public class Var1 {
    public static void main(String[] args) {
        System.out.println(10);
        System.out.println(10);
        System.out.println(10);
    }
}</code></pre>
<p>위 코드는 단순히 숫자 <code>10</code>을 3번 출력합니다. 만약 요구사항이 바뀌어 <code>20</code>을 출력하라고 한다면, 해당 숫자를 <strong>직접 모두 수정해야</strong> 합니다. 3번이면 괜찮지만, 100군데에 <code>10</code>이 쓰였다면요?</p>
<p>이런 상황에서 변수를 사용하면 다음과 같이 바뀝니다:</p>
<pre><code class="language-java">public class Var2 {
    public static void main(String[] args) {
        int a = 10;
        System.out.println(a);
        System.out.println(a);
        System.out.println(a);
    }
}</code></pre>
<p>이제는 <code>a</code>의 값만 바꾸면 전체 출력 결과가 함께 바뀝니다.</p>
<h2 id="변수의-선언과-초기화">변수의 선언과 초기화</h2>
<pre><code class="language-java">int a; // 변수 선언
a = 10; // 변수 초기화</code></pre>
<p>혹은 한 줄로도 가능합니다:</p>
<pre><code class="language-java">int a = 10;</code></pre>
<ul>
<li><code>int</code>는 정수형 데이터를 저장할 수 있는 타입입니다.</li>
<li><code>a</code>는 변수명으로, 메모리의 주소를 간접적으로 표현합니다.</li>
<li><code>=</code>는 대입 연산자이며, <strong>오른쪽 값을 왼쪽 변수에 저장</strong>합니다.</li>
</ul>
<p><strong>주의</strong>: 자바에서 <code>=</code>는 수학에서의 &quot;같다&quot;가 아니라 <strong>&quot;값을 넣는다&quot;</strong>는 의미입니다.</p>
<h2 id="변수-사용의-이점">변수 사용의 이점</h2>
<ol>
<li><strong>재사용성</strong>: 값을 여러 번 사용할 수 있습니다.</li>
<li><strong>유지보수 용이성</strong>: 한 번에 값 변경이 가능합니다.</li>
<li><strong>가독성 향상</strong>: 의미 있는 이름을 통해 코드의 의도를 표현할 수 있습니다.</li>
<li><strong>사용자 입력 대응</strong>: 사용자의 동적인 입력값을 저장해 처리할 수 있습니다.</li>
</ol>
<h2 id="실행-흐름-요약">실행 흐름 요약</h2>
<pre><code class="language-java">int a = 20; // 변수 선언 및 초기화
System.out.println(a); // 20 출력
System.out.println(a); // 20 출력
System.out.println(a); // 20 출력</code></pre>
<p>모든 출력 결과는 <code>20</code>입니다. 변수 하나만 수정했을 뿐인데 전체 출력이 함께 바뀌었죠. 이는 유지보수가 쉬운 코드를 만드는 핵심입니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Quick Start]]></title>
            <link>https://velog.io/@smpaaark-tech/Quick-Start</link>
            <guid>https://velog.io/@smpaaark-tech/Quick-Start</guid>
            <pubDate>Thu, 24 Apr 2025 04:13:27 GMT</pubDate>
            <description><![CDATA[<h2 id="🚀-왜-uv인가">🚀 왜 <code>uv</code>인가?</h2>
<p>기존에는 <code>pip</code>, <code>venv</code>, <code>pip-tools</code>, <code>poetry</code> 등 다양한 도구를 사용해 Python 패키지를 관리해왔지만, <code>uv</code>는 특히 <strong>속도</strong>, <strong>의존성 해석의 정확성</strong>, 그리고 <strong>단순한 UX</strong>에서 강점을 보입니다. 다음과 같은 장점이 있습니다:</p>
<ul>
<li>Rust로 작성되어 매우 빠릅니다.</li>
<li><code>pip</code>의 제약 파일(<code>constraints.txt</code>)을 그대로 활용 가능</li>
<li>가상 환경 생성부터 패키지 설치까지 일관된 워크플로우 제공</li>
</ul>
<p>Airflow처럼 의존성이 복잡한 패키지 설치에 특히 유리합니다.</p>
<h2 id="📦-설치-전-요구-사항">📦 설치 전 요구 사항</h2>
<ul>
<li>Python 3.9, 3.10, 3.11, 3.12 중 하나 (Airflow 2.7.0 이상 기준)</li>
<li><code>uv</code> 설치 (<a href="https://github.com/astral-sh/uv">설치 가이드</a>)</li>
</ul>
<h2 id="🏡-airflow_home-설정-선택-사항">🏡 AIRFLOW_HOME 설정 (선택 사항)</h2>
<pre><code class="language-bash">export AIRFLOW_HOME=~/airflow  # 기본값은 ~/airflow</code></pre>
<p>설치를 시작하기 전에 환경 변수를 설정하면, 관련 설정 파일이 원하는 디렉토리에 저장됩니다.</p>
<h2 id="📥-airflow-설치">📥 Airflow 설치</h2>
<pre><code class="language-bash">AIRFLOW_VERSION=3.0.0
PYTHON_VERSION=&quot;$(python -c &#39;import sys; print(f&quot;{sys.version_info.major}.{sys.version_info.minor}&quot;)&#39;)&quot;

CONSTRAINT_URL=&quot;https://raw.githubusercontent.com/apache/airflow/constraints-${AIRFLOW_VERSION}/constraints-${PYTHON_VERSION}.txt&quot;

uv pip install &quot;apache-airflow==${AIRFLOW_VERSION}&quot; --constraint &quot;${CONSTRAINT_URL}&quot;</code></pre>
<blockquote>
<p>Python 버전에 따라 URL이 달라지므로 자동 추출하는 방식 추천</p>
</blockquote>
<h2 id="▶️-airflow-standalone-실행">▶️ Airflow Standalone 실행</h2>
<pre><code class="language-bash">airflow standalone</code></pre>
<ul>
<li>웹 UI: <a href="http://localhost:8080">http://localhost:8080</a></li>
<li>관리자 계정 정보는 터미널에 출력됨</li>
<li>예시 DAG(<code>example_bash_operator</code>) 활성화 후 상태 확인 가능</li>
</ul>
<h2 id="🧪-간단한-테스트">🧪 간단한 테스트</h2>
<pre><code class="language-bash"># 개별 태스크 실행
airflow tasks test example_bash_operator runme_0 2015-01-01

# DAG 백필 실행
airflow backfill create --dag-id example_bash_operator \
    --start-date 2015-01-01 \
    --end-date 2015-01-02</code></pre>
<h2 id="⚙️-프로덕션-대비-컴포넌트-개별-실행">⚙️ 프로덕션 대비: 컴포넌트 개별 실행</h2>
<pre><code class="language-bash">airflow db migrate

airflow users create \
    --username admin \
    --firstname Peter \
    --lastname Parker \
    --role Admin \
    --email spiderman@superhero.org

airflow api-server --port 8080
airflow scheduler
airflow dag-processor
airflow triggerer</code></pre>
<blockquote>
<p><code>airflow users</code> 명령은 Flask AppBuilder(FAB) 인증 매니저가 활성화된 경우에만 사용 가능</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[The Main Features of MySQL]]></title>
            <link>https://velog.io/@smpaaark-tech/The-Main-Features-of-MySQL</link>
            <guid>https://velog.io/@smpaaark-tech/The-Main-Features-of-MySQL</guid>
            <pubDate>Thu, 24 Apr 2025 02:54:37 GMT</pubDate>
            <description><![CDATA[<h2 id="🔧-아키텍처-및-이식성-internals--portability">🔧 아키텍처 및 이식성 (Internals &amp; Portability)</h2>
<ul>
<li><strong>멀티스레드 기반 커널 스레드 구조</strong>: CPU 코어를 최대한 활용할 수 있도록 설계되어 병렬 쿼리 처리에 강합니다.</li>
<li><strong>모듈화된 설계</strong>: 스토리지 엔진을 모듈처럼 쉽게 추가할 수 있어, 상황에 맞는 커스터마이징이 가능합니다.</li>
<li><strong>CMake 기반 구성</strong>: 다양한 플랫폼에서 손쉽게 빌드 가능. 실제로 윈도우, 리눅스, macOS 등에서 모두 운영해본 경험상 호환성 문제는 거의 없습니다.</li>
</ul>
<hr>
<h2 id="📦-스토리지-엔진">📦 스토리지 엔진</h2>
<ul>
<li><strong>InnoDB</strong>: 트랜잭션 지원, 외래 키, MVCC, 충돌 복구 기능 포함.</li>
<li><strong>MyISAM</strong>: 빠른 읽기 성능, 풀텍스트 인덱싱 가능. 트랜잭션은 미지원.</li>
<li><strong>기타 엔진</strong>: MEMORY, ARCHIVE 등 필요에 따라 선택 가능.</li>
</ul>
<blockquote>
<p>📌 대규모 트랜잭션 처리나 복잡한 비즈니스 로직이 필요한 경우는 무조건 InnoDB 추천.</p>
</blockquote>
<hr>
<h2 id="📊-데이터-타입-및-표현력">📊 데이터 타입 및 표현력</h2>
<ul>
<li>정수, 부동소수점, 문자열, 날짜/시간, BLOB, TEXT, ENUM, SET 등 다양한 타입 지원.</li>
<li><strong>OpenGIS 공간 데이터 타입</strong>도 제공되어 위치 기반 데이터 저장 가능.</li>
</ul>
<hr>
<h2 id="🧠-sql-기능-및-쿼리-최적화">🧠 SQL 기능 및 쿼리 최적화</h2>
<ul>
<li><strong>GROUP BY, ORDER BY, JOIN, 서브쿼리, 윈도우 함수</strong> 등 거의 모든 SQL 기능 지원.</li>
<li><strong>EXPLAIN으로 쿼리 실행 계획 분석</strong> 가능.</li>
<li><strong>SHOW 및 INFORMATION_SCHEMA</strong>를 통해 내부 상태 점검 및 모니터링 가능.</li>
</ul>
<blockquote>
<p>🧪 실제 운영 중에도 <code>EXPLAIN</code> + <code>ANALYZE</code> 조합은 슬로우 쿼리 튜닝 시 가장 많이 쓰는 방법입니다.</p>
</blockquote>
<hr>
<h2 id="🔐-보안과-접근-제어">🔐 보안과 접근 제어</h2>
<ul>
<li><strong>호스트 기반 인증</strong> 및 <strong>비밀번호 암호화 전송</strong>.</li>
<li>GRANT 문을 통한 <strong>정교한 권한 분리</strong> 가능.</li>
</ul>
<blockquote>
<p>실무에서는 서비스 계정에 최소 권한만 부여하는 것이 중요합니다 (Principle of Least Privilege).</p>
</blockquote>
<hr>
<h2 id="📈-확장성과-성능">📈 확장성과 성능</h2>
<ul>
<li><strong>수천만 ~ 수십억 레코드</strong>도 무리 없이 처리 가능.</li>
<li>테이블당 최대 64개 인덱스, 각 인덱스는 최대 16개 컬럼 포함 가능.</li>
</ul>
<blockquote>
<p>운영 중이던 로그성 테이블에서 20억 행 이상 저장해도 쿼리 튜닝만 잘하면 충분히 쓸 수 있었습니다.</p>
</blockquote>
<hr>
<h2 id="🔌-연결성-및-프로토콜">🔌 연결성 및 프로토콜</h2>
<ul>
<li>TCP/IP, 유닉스 도메인 소켓, Windows Named Pipe 등 다양한 프로토콜 지원.</li>
<li>JDBC, ODBC, .NET, Python, PHP 등 거의 모든 언어에서 연결 가능.</li>
</ul>
<blockquote>
<p>다양한 언어의 API 지원은 마이크로서비스 환경에서 큰 장점입니다.</p>
</blockquote>
<hr>
<h2 id="🌍-로컬라이제이션-및-다국어-지원">🌍 로컬라이제이션 및 다국어 지원</h2>
<ul>
<li>다양한 문자셋 및 정렬(collation) 지원.</li>
<li>서버 및 클라이언트별 타임존 설정 가능.</li>
</ul>
<blockquote>
<p>여러 지역 사용자 데이터를 다룰 때, UTF-8과 타임존 설정은 정말 중요합니다.</p>
</blockquote>
<hr>
<h2 id="🛠️-클라이언트-툴-및-유틸리티">🛠️ 클라이언트 툴 및 유틸리티</h2>
<ul>
<li>CLI 도구: <code>mysql</code>, <code>mysqldump</code>, <code>mysqladmin</code>, <code>mysqlcheck</code>, <code>myisamchk</code></li>
<li>GUI 도구: <strong>MySQL Workbench</strong></li>
</ul>
<blockquote>
<p>스크립트 자동화할 때는 CLI 도구를, ERD 작성이나 시각적 쿼리 작성엔 Workbench를 애용합니다.</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[Kubernetes Components]]></title>
            <link>https://velog.io/@smpaaark-tech/Kubernetes-Components</link>
            <guid>https://velog.io/@smpaaark-tech/Kubernetes-Components</guid>
            <pubDate>Thu, 24 Apr 2025 02:47:01 GMT</pubDate>
            <description><![CDATA[<h2 id="🧭-클러스터-구조-개요">🧭 클러스터 구조 개요</h2>
<p>Kubernetes 클러스터는 크게 두 영역으로 나뉩니다:</p>
<ul>
<li><strong>Control Plane (제어 플레인)</strong>: 클러스터의 브레인 역할</li>
<li><strong>Worker Node (작업 노드)</strong>: 실제 컨테이너가 돌아가는 환경</li>
</ul>
<p>이 두 영역이 상호작용하며 클러스터 전체의 상태를 유지합니다.</p>
<hr>
<h2 id="⚙️-제어-플레인-구성요소-분석">⚙️ 제어 플레인 구성요소 분석</h2>
<h3 id="1-kube-apiserver">1. <code>kube-apiserver</code></h3>
<ul>
<li>클러스터의 진입점으로, 모든 명령은 API Server를 통해 전달됩니다.</li>
<li>인증/인가, 요청 유효성 검사, 상태 저장 등 다양한 역할 수행</li>
<li>실무 팁: <code>kubectl</code> 커맨드는 모두 여기로 향합니다. API latency 모니터링 중요</li>
</ul>
<h3 id="2-etcd">2. <code>etcd</code></h3>
<ul>
<li>클러스터의 상태 정보를 저장하는 분산 키-값 저장소</li>
<li>모든 리소스 상태 (파드, 서비스, 설정 등) 가 저장됨</li>
<li>실무 팁: 고가용성 구성 필수. 백업 전략 반드시 수립해야 함</li>
</ul>
<h3 id="3-kube-scheduler">3. <code>kube-scheduler</code></h3>
<ul>
<li>스케줄링되지 않은 Pod를 찾아 적절한 노드에 할당</li>
<li>리소스 상황, taint/toleration, affinity 등을 고려함</li>
<li>실무 팁: 커스텀 스케줄러를 붙여 특정 워크로드를 별도 노드로 분리 가능</li>
</ul>
<h3 id="4-kube-controller-manager">4. <code>kube-controller-manager</code></h3>
<ul>
<li>컨트롤러 집합체로, Deployment, Node, ReplicaSet 등 관리</li>
<li>선언적 상태 유지의 핵심</li>
<li>실무 팁: 실제 문제의 원인을 트래킹할 때 컨트롤러 로그 확인 필수</li>
</ul>
<h3 id="5-cloud-controller-manager-선택적">5. <code>cloud-controller-manager</code> <em>(선택적)</em></h3>
<ul>
<li>AWS, GCP 등 퍼블릭 클라우드 리소스와의 통합 역할</li>
<li>노드 등록, 로드밸런서 관리 등</li>
<li>실무 팁: 클라우드 환경에서만 사용되며, bare-metal에는 필요 없음</li>
</ul>
<hr>
<h2 id="🖥️-노드-구성요소-분석">🖥️ 노드 구성요소 분석</h2>
<h3 id="1-kubelet">1. <code>kubelet</code></h3>
<ul>
<li>각 노드에 존재하며, 해당 노드의 Pod가 제대로 동작하는지 주기적으로 체크</li>
<li>컨테이너 런타임과 직접 통신</li>
<li>실무 팁: 상태 불량 시 kubelet 로그 (<code>/var/log</code>) 확인이 빠른 진단에 유용</li>
</ul>
<h3 id="2-kube-proxy">2. <code>kube-proxy</code></h3>
<ul>
<li>각 노드의 네트워크 규칙 설정 및 서비스 IP 라우팅 처리</li>
<li>iptables 또는 IPVS 기반으로 동작</li>
<li>실무 팁: 네트워크 이슈 시 가장 먼저 살펴볼 요소</li>
</ul>
<h3 id="3-container-runtime">3. <strong>Container Runtime</strong></h3>
<ul>
<li>컨테이너 실행의 실질적 엔진 (예: containerd, CRI-O)</li>
<li>kubelet이 이 런타임을 통해 컨테이너를 구동</li>
<li>실무 팁: 도커는 deprecated 됨. containerd로 전환하는 것이 표준화 추세</li>
</ul>
<hr>
<h2 id="🧩-addons-클러스터-기능-확장">🧩 Addons (클러스터 기능 확장)</h2>
<h3 id="--coredns">- <strong>CoreDNS</strong></h3>
<ul>
<li>클러스터 내 DNS 서비스 제공</li>
<li>서비스 이름으로 통신이 가능하게 만듦</li>
</ul>
<h3 id="--dashboard">- <strong>Dashboard</strong></h3>
<ul>
<li>웹 UI를 통한 클러스터 시각화 관리</li>
</ul>
<h3 id="--metrics-server--prometheus">- <strong>Metrics Server / Prometheus</strong></h3>
<ul>
<li>자원 사용량 모니터링</li>
</ul>
<h3 id="--efk--loki">- <strong>EFK / Loki</strong></h3>
<ul>
<li>중앙 집중식 로그 수집 및 분석</li>
</ul>
<hr>
<h2 id="⚒️-실무-적용-포인트">⚒️ 실무 적용 포인트</h2>
<ul>
<li><code>kube-apiserver</code> 의 SLA는 전체 클러스터 가용성과 직결됨 → 장애 대응 프로세스 마련</li>
<li><code>etcd</code> 백업/복구 시나리오 정립 → 사고 발생 시 복구 속도에 결정적</li>
<li>노드 단의 kubelet 이슈는 대부분 컨테이너 실행 문제로 이어짐 → 사전 모니터링 중요</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Use Cases]]></title>
            <link>https://velog.io/@smpaaark-tech/Use-Cases</link>
            <guid>https://velog.io/@smpaaark-tech/Use-Cases</guid>
            <pubDate>Thu, 24 Apr 2025 02:40:55 GMT</pubDate>
            <description><![CDATA[<h2 id="1-고성능-메시징-시스템">1. 고성능 메시징 시스템</h2>
<p>Kafka는 전통적인 메시지 브로커(예: RabbitMQ, ActiveMQ)를 대체할 수 있는 강력한 메시징 플랫폼입니다. 내장된 <strong>파티셔닝, 복제, 장애 허용성</strong> 덕분에 대규모 시스템에서도 안정적으로 메시지를 처리할 수 있습니다.</p>
<h3 id="사용-시나리오">사용 시나리오</h3>
<ul>
<li>생산자/소비자 간 완전 비동기 메시지 처리</li>
<li>대용량 데이터 큐 처리</li>
<li>Latency는 낮고, Durability는 높은 환경이 필요한 경우</li>
</ul>
<h2 id="2-웹사이트-사용자-활동-추적">2. 웹사이트 사용자 활동 추적</h2>
<p>Kafka의 초기 목적은 웹사이트에서 발생하는 사용자 활동(페이지 뷰, 검색, 클릭 등)을 실시간으로 수집하고 분석하기 위함이었습니다.</p>
<h3 id="사용-시나리오-1">사용 시나리오</h3>
<ul>
<li><strong>Page view, 클릭 로그</strong> 등을 토픽 단위로 분리해 저장</li>
<li>실시간 대시보드 생성</li>
<li>분석용 DWH(Hadoop, Redshift 등) 적재 파이프라인 구성</li>
</ul>
<h2 id="3-운영-메트릭-및-모니터링-데이터-수집">3. 운영 메트릭 및 모니터링 데이터 수집</h2>
<p>운영 메트릭을 수집하고, 이를 중앙에서 집계 및 시각화하는 데 Kafka가 많이 사용됩니다.</p>
<h3 id="사용-시나리오-2">사용 시나리오</h3>
<ul>
<li>마이크로서비스에서 수집되는 상태 정보 및 성능 지표 수집</li>
<li>Prometheus, Grafana 등과 연계한 실시간 모니터링</li>
</ul>
<h2 id="4-로그-집계log-aggregation">4. 로그 집계(Log Aggregation)</h2>
<p>Kafka는 기존의 로그 수집 시스템(Scribe, Flume 등)을 대체할 수 있으며, 다양한 로그 소스를 하나의 스트림으로 통합할 수 있습니다.</p>
<h3 id="장점">장점</h3>
<ul>
<li><strong>파일 단위가 아닌 이벤트 스트림</strong>으로 처리</li>
<li>다양한 소스/서버에서 들어오는 로그를 하나의 토픽으로 집계</li>
<li>빠른 소비자 확장이 가능</li>
</ul>
<h2 id="5-스트림-처리-stream-processing">5. 스트림 처리 (Stream Processing)</h2>
<p>Kafka를 중심으로 구성된 데이터 파이프라인은 <strong>다단계 실시간 처리</strong>를 위한 훌륭한 기반이 됩니다. <code>Kafka Streams</code>, <code>Apache Storm</code>, <code>Apache Samza</code> 등 다양한 스트림 처리 프레임워크와 연동할 수 있습니다.</p>
<h3 id="예시">예시</h3>
<pre><code class="language-plaintext">RSS 수집기 → Kafka (raw topic)
 → 정제/필터링 → Kafka (clean topic)
 → 개인화 추천 → Kafka (recommend topic)</code></pre>
<h2 id="6-이벤트-소싱-event-sourcing">6. 이벤트 소싱 (Event Sourcing)</h2>
<p>Kafka는 애플리케이션의 상태 변화를 순차적인 이벤트로 저장하는 <strong>Event Sourcing 패턴</strong>의 저장소로 적합합니다.</p>
<h3 id="사용-시나리오-3">사용 시나리오</h3>
<ul>
<li>도메인 객체의 상태 변경 이력을 전체 저장</li>
<li>재현 가능한 시스템 상태 관리</li>
</ul>
<h2 id="7-분산-시스템의-커밋-로그">7. 분산 시스템의 커밋 로그</h2>
<p>Kafka는 분산 시스템의 외부 커밋 로그로 활용되어 데이터 복제 및 장애 복구 시 강력한 도구가 됩니다.</p>
<h3 id="관련-기능">관련 기능</h3>
<ul>
<li><strong>로그 압축(Log Compaction)</strong>: 최신 상태만 유지하면서도 이벤트 로그의 무결성을 보장</li>
<li>Apache BookKeeper와 유사한 사용 방식</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Spring Batch Architecture]]></title>
            <link>https://velog.io/@smpaaark-tech/Spring-Batch-Architecture</link>
            <guid>https://velog.io/@smpaaark-tech/Spring-Batch-Architecture</guid>
            <pubDate>Thu, 24 Apr 2025 02:36:04 GMT</pubDate>
            <description><![CDATA[<h2 id="🧱-spring-batch-아키텍처-이해하기">🧱 Spring Batch 아키텍처 이해하기</h2>
<p>Spring Batch는 대용량 데이터 처리에 특화된 프레임워크로, 다양한 사용자 니즈를 만족시키기 위해 계층화된 구조를 갖습니다. 아래는 핵심 구성 요소입니다.</p>
<h3 id="✅-주요-계층">✅ 주요 계층</h3>
<ul>
<li><strong>Application Layer</strong>: 사용자가 작성하는 Job, Step, 커스텀 리더/라이터 등</li>
<li><strong>Batch Core Layer</strong>: <code>JobLauncher</code>, <code>Job</code>, <code>Step</code> 등의 핵심 런타임 컴포넌트 포함</li>
<li><strong>Infrastructure Layer</strong>: <code>ItemReader</code>, <code>ItemWriter</code>, <code>RetryTemplate</code> 등 공통 유틸리티 제공</li>
</ul>
<p>이러한 구조는 <strong>확장성, 테스트 용이성, 재사용성</strong> 측면에서 유리합니다.</p>
<hr>
<h2 id="📐-배치-시스템-설계-원칙">📐 배치 시스템 설계 원칙</h2>
<h3 id="1-온라인배치-공존-고려">1. 온라인/배치 공존 고려</h3>
<ul>
<li>데이터 공유 및 락 전략을 함께 고려해야 함</li>
<li>커먼 컴포넌트 활용 권장</li>
</ul>
<h3 id="2-io-최소화">2. I/O 최소화</h3>
<ul>
<li>가능하면 메모리 내에서 처리</li>
<li>불필요한 SQL 쿼리 제거 (불필요한 재조회, 테이블 스캔 등)</li>
</ul>
<h3 id="3-데이터-무결성-보장">3. 데이터 무결성 보장</h3>
<ul>
<li>체크섬, 레코드 수, 논리 검증 포함</li>
<li>재처리 방지 (처리 중에 합산 등을 같이 수행)</li>
</ul>
<h3 id="4-스트레스-테스트-및-백업-고려">4. 스트레스 테스트 및 백업 고려</h3>
<ul>
<li>실제 운영량 수준에서 테스트 필요</li>
<li>Flat 파일 기반일 경우, 파일 백업 절차도 중요</li>
</ul>
<hr>
<h2 id="🧩-실무-배치-패턴-및-애플리케이션-유형">🧩 실무 배치 패턴 및 애플리케이션 유형</h2>
<h3 id="💡-애플리케이션-유형">💡 애플리케이션 유형</h3>
<ul>
<li><strong>변환(Conversion)</strong></li>
<li><strong>검증(Validation)</strong></li>
<li><strong>추출/업데이트(Extract/Update)</strong></li>
<li><strong>처리/포맷(Output/Format)</strong></li>
</ul>
<h3 id="🧰-유틸리티-단계">🧰 유틸리티 단계</h3>
<ul>
<li>Sort / Split / Merge 같은 표준 처리 유틸리티 활용</li>
</ul>
<h3 id="📦-입력-소스에-따른-분류">📦 입력 소스에 따른 분류</h3>
<ul>
<li>DB 기반 / 파일 기반 / 메시지 기반</li>
</ul>
<hr>
<h2 id="⚙️-배치-처리-전략">⚙️ 배치 처리 전략</h2>
<h3 id="1-일반-배치-처리">1. 일반 배치 처리</h3>
<ul>
<li>단순 배치 윈도우에서 실행</li>
<li>단일 커밋, 락 고려 필요 없음</li>
</ul>
<h3 id="2-온라인과-동시-처리">2. 온라인과 동시 처리</h3>
<ul>
<li>락을 최소화하는 <strong>Optimistic Locking</strong> 또는 <strong>Pessimistic Locking</strong> 전략 필요</li>
</ul>
<pre><code class="language-java">// Optimistic Locking 예시
UPDATE customer
SET status = &#39;PROCESSED&#39;
WHERE id = ? AND last_updated = ?</code></pre>
<h3 id="3-병렬-처리">3. 병렬 처리</h3>
<ul>
<li>병렬 실행 시, 공유 리소스 락 관리 필요</li>
<li><strong>Control Table</strong> 방식 사용 가능</li>
</ul>
<h3 id="4-파티셔닝-partitioning">4. 파티셔닝 (Partitioning)</h3>
<ul>
<li>대용량 데이터를 여러 인스턴스로 분할 처리</li>
<li>Spring Batch의 <code>PartitionHandler</code> 활용 가능</li>
</ul>
<hr>
<h2 id="🔀-파티셔닝-전략-심층-분석">🔀 파티셔닝 전략 심층 분석</h2>
<h3 id="전략-1-고정-분할">전략 1. 고정 분할</h3>
<ul>
<li>레코드를 일정 수로 나누어 처리 (pre-processing overhead 존재)</li>
</ul>
<h3 id="전략-2-키-컬럼-기반-분할">전략 2. 키 컬럼 기반 분할</h3>
<ul>
<li><code>location_code</code> 등 특정 키 컬럼 기준 분할</li>
</ul>
<h3 id="전략-3-view-기반">전략 3. View 기반</h3>
<ul>
<li>파티션별 뷰 구성 후 뷰 대상으로 배치 수행</li>
</ul>
<h3 id="전략-4-처리-인디케이터-추가">전략 4. 처리 인디케이터 추가</h3>
<ul>
<li>상태 컬럼(예: <code>status</code>) 기반 동시 실행 보장</li>
</ul>
<h3 id="전략-5-테이블-→-flat-file-추출-후-분할">전략 5. 테이블 → Flat File 추출 후 분할</h3>
<ul>
<li>외부 배치 인프라와 연동 시 유용</li>
</ul>
<h3 id="전략-6-hash-컬럼-추가">전략 6. Hash 컬럼 추가</h3>
<ul>
<li><code>hash_key</code> 로 구간 분배, 분산 제어 용이</li>
</ul>
<hr>
<h2 id="🧠-실전-설계-팁">🧠 실전 설계 팁</h2>
<h3 id="✔-중앙-파티션-테이블-설계">✔ 중앙 파티션 테이블 설계</h3>
<pre><code class="language-sql">CREATE TABLE partition_meta (
  program_id VARCHAR(20),
  partition_no INT,
  key_low VARCHAR(100),
  key_high VARCHAR(100),
  PRIMARY KEY (program_id, partition_no)
);</code></pre>
<ul>
<li>유연한 파티셔닝 및 관리 가능</li>
</ul>
<h3 id="✔-데드락-방지">✔ 데드락 방지</h3>
<ul>
<li>테이블 설계 시 인덱싱 전략 주의</li>
<li>핫스팟 테이블(예: log, control, lock table) 신중 설계</li>
</ul>
<h3 id="✔-파라미터-자동-전달-구조-구축">✔ 파라미터 자동 전달 구조 구축</h3>
<ul>
<li>실행 전 파라미터 유효성 검증 포함</li>
<li>파티션 간 격리 및 실패 시 재시도 처리 설계 포함</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[영속성 컨텍스트 1]]></title>
            <link>https://velog.io/@smpaaark-tech/%EC%98%81%EC%86%8D%EC%84%B1-%EC%BB%A8%ED%85%8D%EC%8A%A4%ED%8A%B8-1</link>
            <guid>https://velog.io/@smpaaark-tech/%EC%98%81%EC%86%8D%EC%84%B1-%EC%BB%A8%ED%85%8D%EC%8A%A4%ED%8A%B8-1</guid>
            <pubDate>Thu, 24 Apr 2025 02:28:59 GMT</pubDate>
            <description><![CDATA[<p>김영한님의 자바 ORM 표준 JPA 프로그래밍 - 기본편 정리</p>
<h2 id="💡-영속성-컨텍스트란">💡 영속성 컨텍스트란?</h2>
<p>영속성 컨텍스트는 &quot;엔티티를 영구 저장하는 환경&quot;입니다. 정확히는 다음과 같은 특징을 갖는 <strong>논리적 개념</strong>입니다:</p>
<ul>
<li>엔티티 객체를 관리하는 메모리 내 저장소</li>
<li><code>EntityManager</code>를 통해 접근</li>
<li>눈에 보이지 않지만 <strong>JPA의 거의 모든 동작의 기반</strong></li>
</ul>
<pre><code class="language-java">EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
Member member = new Member(&quot;member1&quot;, &quot;회원1&quot;);
em.persist(member);</code></pre>
<p>위 코드에서 <code>persist()</code> 호출은 DB에 바로 insert하는 것이 아니라, <strong>영속성 컨텍스트에 저장</strong>하는 작업입니다.</p>
<hr>
<h2 id="📦-엔티티-생명주기">📦 엔티티 생명주기</h2>
<p>JPA 엔티티는 아래 네 가지 상태를 가질 수 있습니다:</p>
<table>
<thead>
<tr>
<th>상태</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td>비영속(new)</td>
<td>객체만 생성된 상태. JPA와 전혀 무관</td>
</tr>
<tr>
<td>영속(managed)</td>
<td><code>persist()</code> 후 컨텍스트에 의해 관리되는 상태</td>
</tr>
<tr>
<td>준영속(detached)</td>
<td><code>detach()</code> 등으로 컨텍스트에서 분리된 상태</td>
</tr>
<tr>
<td>삭제(removed)</td>
<td><code>remove()</code> 호출로 삭제 예정 상태</td>
</tr>
</tbody></table>
<pre><code class="language-java">Member member = new Member(); // 비영속
em.persist(member);           // 영속
em.detach(member);            // 준영속
em.remove(member);            // 삭제</code></pre>
<hr>
<h2 id="🚀-언제-db에-반영될까">🚀 언제 DB에 반영될까?</h2>
<p>JPA는 <code>persist()</code> 시점에 DB에 insert 쿼리를 날리지 않습니다. 실제 쿼리는 <strong>트랜잭션 커밋 시점</strong>에 발생합니다.</p>
<pre><code class="language-java">em.getTransaction().commit(); // 이 시점에 insert 쿼리 실행</code></pre>
<p>이러한 방식은 <strong>쓰기 지연(Write-Behind)</strong> 또는 <strong>트랜잭션 단위의 배치 처리</strong>라 부르며, 성능 최적화에 매우 유리합니다.</p>
<hr>
<h2 id="✅-영속성-컨텍스트의-이점">✅ 영속성 컨텍스트의 이점</h2>
<ol>
<li><p><strong>1차 캐시</strong></p>
<ul>
<li>동일 트랜잭션 내에서 <code>find()</code> 시 DB를 다시 조회하지 않음</li>
</ul>
</li>
<li><p><strong>동일성(identity) 보장</strong></p>
<ul>
<li>같은 트랜잭션 내 동일 엔티티 조회 시 동일 객체 반환 (<code>==</code> 비교 가능)</li>
</ul>
</li>
<li><p><strong>쓰기 지연 (Transactional Write-Behind)</strong></p>
<ul>
<li>쿼리 최소화 및 트랜잭션 단위의 처리 가능</li>
</ul>
</li>
<li><p><strong>변경 감지(Dirty Checking)</strong></p>
<ul>
<li>엔티티 값 변경 감지 후 자동 update 쿼리 생성</li>
</ul>
</li>
<li><p><strong>지연 로딩(Lazy Loading)</strong></p>
<ul>
<li>연관 객체는 실제 접근 시점에 쿼리 실행 (필요할 때만 조회)</li>
</ul>
</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[정적 컨텐츠]]></title>
            <link>https://velog.io/@smpaaark-tech/%EC%A0%95%EC%A0%81-%EC%BB%A8%ED%85%90%EC%B8%A0</link>
            <guid>https://velog.io/@smpaaark-tech/%EC%A0%95%EC%A0%81-%EC%BB%A8%ED%85%90%EC%B8%A0</guid>
            <pubDate>Thu, 24 Apr 2025 01:29:13 GMT</pubDate>
            <description><![CDATA[<p>김영한님의 스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술 정리</p>
<h2 id="1-정적-컨텐츠-static-content">1. 정적 컨텐츠 (Static Content)</h2>
<p>정적 컨텐츠는 가장 단순한 형태의 웹 리소스 제공 방식입니다. 서버는 로직 없이 <strong>파일을 있는 그대로 브라우저에 반환</strong>합니다.</p>
<h3 id="🔹-특징">🔹 특징</h3>
<ul>
<li>서버 처리 로직 없음</li>
<li>빠르고 단순</li>
<li>HTML, CSS, JS, 이미지 파일 등</li>
<li>SEO에 유리</li>
</ul>
<h3 id="🔹-spring-boot에서의-처리-방식">🔹 Spring Boot에서의 처리 방식</h3>
<p>Spring Boot는 기본적으로 <code>/resources/static</code> 디렉토리에 위치한 파일들을 정적 컨텐츠로 서빙합니다.</p>
<h4 id="폴더-구조">폴더 구조</h4>
<pre><code>src/main/resources/static/hello-static.html</code></pre><h4 id="예제-html">예제 HTML</h4>
<pre><code class="language-html">&lt;!DOCTYPE HTML&gt;
&lt;html&gt;
&lt;head&gt;
&lt;title&gt;static content&lt;/title&gt;
&lt;meta charset=&quot;UTF-8&quot; /&gt;
&lt;/head&gt;
&lt;body&gt;
정적 컨텐츠 입니다.
&lt;/body&gt;
&lt;/html&gt;</code></pre>
<h4 id="접근-url">접근 URL</h4>
<pre><code>http://localhost:8080/hello-static.html</code></pre><h3 id="🔹-처리-순서">🔹 처리 순서</h3>
<ol>
<li>브라우저가 <code>/hello-static.html</code> 요청</li>
<li>Spring은 해당 URL을 처리할 컨트롤러 존재 여부 확인</li>
<li>없으면 <code>/static</code> 폴더에서 파일 탐색 후 반환</li>
</ol>
<blockquote>
<p>❗ 정적 컨텐츠는 단순하지만 동적 처리(예: 사용자 맞춤형 페이지)가 불가합니다.</p>
</blockquote>
<hr>
<h2 id="2-mvc와-템플릿-엔진">2. MVC와 템플릿 엔진</h2>
<p>전통적인 서버 사이드 렌더링 방식입니다. 컨트롤러가 모델 데이터를 생성하고, 뷰 템플릿(예: Thymeleaf, JSP)을 통해 HTML을 생성합니다.</p>
<h3 id="🔹-구조">🔹 구조</h3>
<ul>
<li><strong>Model</strong>: 비즈니스 데이터</li>
<li><strong>View</strong>: 템플릿 엔진 (JSP, Thymeleaf 등)</li>
<li><strong>Controller</strong>: 요청 처리 및 데이터 전달</li>
</ul>
<h3 id="🔹-장점">🔹 장점</h3>
<ul>
<li>서버 주도형 렌더링으로 복잡한 비즈니스 로직 처리에 적합</li>
<li>SEO 및 초기 로딩 최적화</li>
</ul>
<h3 id="🔹-단점">🔹 단점</h3>
<ul>
<li>클라이언트와 서버 간 결합도가 높음</li>
<li>화면 변경 시 서버 템플릿까지 변경 필요</li>
</ul>
<blockquote>
<p>Spring MVC는 이 구조를 자연스럽게 지원합니다. <code>@Controller</code> + <code>ModelAndView</code> 조합이 일반적입니다.</p>
</blockquote>
<hr>
<h2 id="3-api-방식-json-기반">3. API 방식 (JSON 기반)</h2>
<p>모던 웹/모바일 환경에서는 API 방식이 널리 사용됩니다. 서버는 HTML 대신 <strong>JSON 형식의 데이터만 클라이언트에 전달</strong>하며, UI는 클라이언트(React, Vue, 모바일 앱)가 담당합니다.</p>
<h3 id="🔹-특징-1">🔹 특징</h3>
<ul>
<li>데이터와 UI 완전 분리 (백엔드/프론트엔드 분리)</li>
<li>JSON 포맷 주로 사용</li>
<li>모바일 앱, SPA(React, Vue)와의 통신에 적합</li>
</ul>
<h3 id="🔹-장점-1">🔹 장점</h3>
<ul>
<li>재사용성, 확장성 우수</li>
<li>프론트엔드 독립 개발 가능</li>
<li>서버 간 통신에도 적합 (Microservice)</li>
</ul>
<h3 id="🔹-단점-1">🔹 단점</h3>
<ul>
<li>SEO 대응 어려움</li>
<li>클라이언트 개발 비용 증가</li>
</ul>
<pre><code class="language-java">@RestController
public class HelloApiController {
    @GetMapping(&quot;/api/hello&quot;)
    public Map&lt;String, String&gt; hello() {
        return Map.of(&quot;message&quot;, &quot;Hello, API!&quot;);
    }
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Kotlin] 코틀린이란?]]></title>
            <link>https://velog.io/@smpaaark-tech/Kotlin-%EC%BD%94%ED%8B%80%EB%A6%B0%EC%9D%B4%EB%9E%80</link>
            <guid>https://velog.io/@smpaaark-tech/Kotlin-%EC%BD%94%ED%8B%80%EB%A6%B0%EC%9D%B4%EB%9E%80</guid>
            <pubDate>Thu, 24 Apr 2025 01:21:52 GMT</pubDate>
            <description><![CDATA[<p>김영한님의 자바 입문 - 코드로 시작하는 자바 첫걸음 정리</p>
<h2 id="코틀린도-자바처럼-표준-스펙과-구현체-개념이-있을까">코틀린도 자바처럼 &quot;표준 스펙과 구현체&quot; 개념이 있을까?</h2>
<p>코틀린은 자바처럼 공식적으로 표준 스펙과 다양한 구현체를 나눠 설명하진 않지만, 코틀린 또한 <strong>JVM 기반 언어</strong>로서 자바 생태계를 그대로 활용합니다.</p>
<ul>
<li><p><strong>JetBrains가 주도하는 공식 구현체</strong></p>
<ul>
<li>코틀린은 JetBrains에서 개발하며, 공식 컴파일러 및 툴체인을 제공합니다.</li>
<li>코틀린 컴파일러는 Java 바이트코드를 생성함으로써 JVM에서 실행됩니다.</li>
</ul>
</li>
<li><p><strong>JVM 구현체 활용</strong></p>
<ul>
<li>Oracle OpenJDK, Amazon Corretto, Eclipse Temurin 등 자바 구현체 위에서 실행됩니다.</li>
<li>따라서 다양한 OS에서 실행 가능한 점은 자바와 동일합니다.</li>
</ul>
</li>
</ul>
<hr>
<h2 id="코틀린의-컴파일과-실행-구조">코틀린의 컴파일과 실행 구조</h2>
<p>코틀린의 실행 과정은 자바와 유사하며 다음과 같은 단계로 나뉩니다:</p>
<ol>
<li><p><strong>컴파일 (kotlinc)</strong></p>
<ul>
<li><code>.kt</code> → <code>.class</code> (바이트코드)</li>
<li>자바와 동일하게 문법 검사 및 바이트코드 최적화 수행</li>
</ul>
</li>
<li><p><strong>실행 (java)</strong></p>
<ul>
<li>JVM이 <code>.class</code> 파일을 실행</li>
<li>코틀린은 JVM 위에서 동작하므로 실행 방식은 자바와 동일</li>
</ul>
</li>
</ol>
<blockquote>
<p>실무에서 Kotlin + Spring Boot 조합은 JVM 생태계의 이점을 그대로 누릴 수 있습니다.</p>
</blockquote>
<hr>
<h2 id="intellij-idea에서-코틀린은-어떻게-다를까">IntelliJ IDEA에서 코틀린은 어떻게 다를까?</h2>
<p>IntelliJ IDEA는 코틀린의 본가인 JetBrains에서 만든 IDE이기 때문에 코틀린 개발에 최적화되어 있습니다.</p>
<ul>
<li>Kotlin SDK 설치 및 자동 구성</li>
<li><code>kotlinc</code>, <code>java</code> 명령 자동 실행</li>
<li>컴파일 결과는 자바와 마찬가지로 <code>out/</code> 폴더에 생성됨</li>
<li>코틀린 또한 디컴파일 기능을 통해 바이트코드 분석 가능</li>
</ul>
<p>개발 속도와 학습 효율 모두 자바보다 더 뛰어나다는 평도 많습니다.</p>
<hr>
<h2 id="운영체제-독립성-코틀린도-자바처럼-자유롭다">운영체제 독립성: 코틀린도 자바처럼 자유롭다</h2>
<p>코틀린은 JVM에서 실행되므로 <strong>운영체제 독립성</strong>을 그대로 이어받습니다.</p>
<ul>
<li><code>.class</code> 파일은 OS에 구애받지 않음</li>
<li>JVM만 설치되어 있으면 Windows, macOS, Linux 어디서든 실행 가능</li>
<li>예: 개발은 macOS + Kotlin, 운영은 AWS 리눅스 서버 + Amazon Corretto</li>
</ul>
<p>Kotlin/Native나 Kotlin Multiplatform을 활용하면 이식성을 더 극대화할 수도 있습니다.</p>
<hr>
<h2 id="실무에서의-적용-시나리오">실무에서의 적용 시나리오</h2>
<blockquote>
<p>✅ 실무 TIP: Kotlin 프로젝트의 경우도 자바와 마찬가지로 운영환경과 동일한 JVM 구현체를 맞춰주는 것이 중요합니다.</p>
</blockquote>
<pre><code class="language-bash"># 개발: macOS + Kotlin + Eclipse Temurin
# 운영: AWS EC2 + Kotlin + Amazon Corretto</code></pre>
<ul>
<li>Kotlin으로 개발한 애플리케이션도 <code>.class</code> 파일로 컴파일됨</li>
<li>운영 환경에서는 해당 <code>.class</code> 파일을 그대로 실행</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Java] 자바란?]]></title>
            <link>https://velog.io/@smpaaark-tech/Java-%EC%9E%90%EB%B0%94%EB%9E%80</link>
            <guid>https://velog.io/@smpaaark-tech/Java-%EC%9E%90%EB%B0%94%EB%9E%80</guid>
            <pubDate>Thu, 24 Apr 2025 01:17:37 GMT</pubDate>
            <description><![CDATA[<p>김영한님의 자바 입문 - 코드로 시작하는 자바 첫걸음 정리</p>
<h2 id="자바는-왜-표준-스펙과-구현체로-나눠질까">자바는 왜 &quot;표준 스펙과 구현체&quot;로 나눠질까?</h2>
<p>자바는 단일한 구현체가 아닌, <strong>표준 스펙(Java Specification)</strong>과 이를 따르는 <strong>다양한 구현체(Java Implementation)</strong>의 구조를 가지고 있습니다.</p>
<ul>
<li><p><strong>표준 스펙 (JCP에 의해 관리)</strong></p>
<ul>
<li>자바 언어가 어떤 구조로 만들어져야 하는지 정의한 설계도</li>
<li>예: 컴파일러 동작 방식, JVM 구조, 필수 라이브러리 명세 등</li>
</ul>
</li>
<li><p><strong>구현체</strong></p>
<ul>
<li>다양한 회사들이 스펙을 기반으로 만든 실제 실행 가능한 자바 플랫폼</li>
<li>대표적인 구현체:<ul>
<li>Oracle OpenJDK</li>
<li>Amazon Corretto (AWS에 최적화)</li>
<li>Eclipse Temurin (Adoptium)</li>
</ul>
</li>
</ul>
</li>
</ul>
<p>스펙이 일관되기 때문에 <strong>구현체 간 호환성</strong>이 매우 높습니다. 실무에서 특정 구현체를 바꿔도 대부분 문제가 발생하지 않죠.</p>
<hr>
<h2 id="자바의-컴파일과-실행-구조">자바의 컴파일과 실행 구조</h2>
<p>자바의 실행 과정은 다음 두 단계로 나뉩니다:</p>
<ol>
<li><p><strong>컴파일 (javac)</strong></p>
<ul>
<li><code>.java</code> → <code>.class</code> (바이트코드)</li>
<li>문법 오류 검출 및 바이트코드 최적화 수행</li>
</ul>
</li>
<li><p><strong>실행 (java)</strong></p>
<ul>
<li>JVM이 <code>.class</code> 파일을 읽고 실행</li>
<li>이 과정에서 플랫폼에 맞는 JVM이 역할을 수행</li>
</ul>
</li>
</ol>
<blockquote>
<p>실무에서는 이 구조를 잘 이해하고 있어야 디버깅, 성능 튜닝, 배포 전략 설계에서 실수를 줄일 수 있습니다.</p>
</blockquote>
<hr>
<h2 id="intellij-idea에서-자바는-어떻게-다를까">IntelliJ IDEA에서 자바는 어떻게 다를까?</h2>
<p>현대 개발자에게는 IDE가 곧 생산성입니다. 특히 <strong>IntelliJ IDEA</strong>는 자바 개발에서 필수적인 도구 중 하나입니다.</p>
<ul>
<li>자바 SDK 설치 자동화</li>
<li><code>javac</code>, <code>java</code> 실행 자동화</li>
<li>컴파일 결과는 <code>out/</code> 폴더에서 확인 가능</li>
<li>디컴파일 기능 제공 (단, 주석 등은 복원되지 않음)</li>
</ul>
<p>초보자뿐만 아니라, 프로젝트 설정이 복잡한 엔터프라이즈 환경에서도 매우 유용합니다.</p>
<hr>
<h2 id="운영체제-독립성-자바의-가장-큰-강점-중-하나">운영체제 독립성: 자바의 가장 큰 강점 중 하나</h2>
<p>자바 프로그램은 <strong>어떤 운영체제에서도 실행</strong>될 수 있습니다. 이유는 JVM이 각 OS에 맞는 실행 환경을 제공하기 때문이죠.</p>
<ul>
<li><code>.class</code> 파일은 OS에 구애받지 않음</li>
<li>Windows, macOS, Linux에 맞는 JVM만 있으면 실행 가능</li>
<li>예: 개발은 macOS, 배포는 AWS 리눅스 서버 (Amazon Corretto)</li>
</ul>
<p>이러한 구조 덕분에 <strong>&quot;Write Once, Run Anywhere&quot;</strong>라는 자바의 철학이 실현될 수 있었습니다.</p>
<hr>
<h2 id="실무에서의-적용-시나리오">실무에서의 적용 시나리오</h2>
<blockquote>
<p>✅ 실무 TIP: 운영환경은 대부분 리눅스입니다. 따라서 로컬에서는 Windows나 macOS를 쓰더라도, 서버 환경과 동일한 JDK 버전과 구현체를 맞춰주는 게 좋습니다.</p>
</blockquote>
<pre><code class="language-bash"># 개발: macOS + Eclipse Temurin
# 운영: AWS EC2 + Amazon Corretto</code></pre>
<ul>
<li>개발 중에는 로컬에서 빠른 실행과 디버깅</li>
<li>배포 시에는 운영환경(JVM 최적화된 리눅스)으로 전환</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Overview]]></title>
            <link>https://velog.io/@smpaaark-tech/Overview-wsh2l5dl</link>
            <guid>https://velog.io/@smpaaark-tech/Overview-wsh2l5dl</guid>
            <pubDate>Tue, 22 Apr 2025 05:12:32 GMT</pubDate>
            <description><![CDATA[<h2 id="kubernetes-개요">Kubernetes 개요</h2>
<p>Kubernetes는 컨테이너화된 애플리케이션의 배포, 확장, 관리를 자동화하는 오픈소스 플랫폼입니다. 2014년 Google이 오픈소스로 공개했으며, 이름은 그리스어로 &quot;조타수(helmsman)&quot;를 의미합니다.</p>
<ul>
<li><strong>확장성</strong>: 수천 개의 컨테이너를 관리할 수 있는 구조</li>
<li><strong>이식성</strong>: 온프레미스, 퍼블릭 클라우드, 하이브리드 환경 모두 지원</li>
<li><strong>커뮤니티 중심 발전</strong>: CNCF(Cloud Native Computing Foundation) 주도로 빠르게 발전</li>
</ul>
<h2 id="kubernetes가-필요한-이유">Kubernetes가 필요한 이유</h2>
<p>컨테이너는 애플리케이션을 패키징하고 배포하는 훌륭한 방법이지만, 실제 운영 환경에서는 다음과 같은 문제가 발생합니다.</p>
<ul>
<li>장애 복구(컨테이너가 죽으면 자동 재기동)</li>
<li>서비스 디스커버리 및 로드밸런싱</li>
<li>무중단 배포 및 롤백</li>
<li>리소스 최적화</li>
</ul>
<p>Kubernetes는 이런 운영 이슈를 체계적으로 해결합니다. 복잡한 분산 시스템의 구축과 운영을 프레임워크 수준에서 지원하는 것이죠.</p>
<h2 id="kubernetes-주요-기능">Kubernetes 주요 기능</h2>
<h3 id="1-서비스-디스커버리와-로드밸런싱">1. 서비스 디스커버리와 로드밸런싱</h3>
<ul>
<li>Kubernetes는 DNS 이름 또는 자체 IP를 통해 Pod(컨테이너 집합)에 접근할 수 있게 합니다.</li>
<li>트래픽이 많을 경우 로드밸런서를 통해 네트워크 부하를 분산합니다.</li>
</ul>
<h3 id="2-스토리지-오케스트레이션">2. 스토리지 오케스트레이션</h3>
<ul>
<li>로컬 스토리지, 퍼블릭 클라우드 스토리지(AWS EBS, GCP Persistent Disk 등)를 자동으로 마운트할 수 있습니다.</li>
</ul>
<h3 id="3-자동화된-롤아웃-및-롤백">3. 자동화된 롤아웃 및 롤백</h3>
<ul>
<li>선언적 방식(Declarative Approach)으로 원하는 상태를 정의하면, Kubernetes가 실제 상태를 점진적으로 맞춰갑니다.</li>
</ul>
<h3 id="4-자동-리소스-배치-bin-packing">4. 자동 리소스 배치 (Bin Packing)</h3>
<ul>
<li>컨테이너별 CPU, 메모리 요청량을 기반으로 최적화된 노드에 컨테이너를 배치합니다.</li>
</ul>
<h3 id="5-셀프-힐링self-healing">5. 셀프 힐링(Self-Healing)</h3>
<ul>
<li>실패한 컨테이너를 자동으로 재시작하거나 교체합니다.</li>
<li>상태 확인이 실패한 컨테이너는 외부에 노출하지 않습니다.</li>
</ul>
<h3 id="6-보안-및-설정-관리">6. 보안 및 설정 관리</h3>
<ul>
<li>비밀번호, OAuth 토큰, SSH 키 등 민감한 정보를 안전하게 저장하고 배포할 수 있습니다.</li>
</ul>
<h3 id="7-수평적-확장">7. 수평적 확장</h3>
<ul>
<li>명령어, UI, 또는 CPU 사용량을 기반으로 Pod 수를 자동 확장하거나 축소합니다.</li>
</ul>
<h2 id="kubernetes는-무엇이-아닌가">Kubernetes는 무엇이 아닌가</h2>
<ul>
<li><strong>PaaS</strong>가 아님: 전체 개발 플랫폼을 제공하지 않고, 필요한 기능만 제공합니다.</li>
<li><strong>CI/CD 툴</strong>이 아님: 소스코드 빌드 및 배포는 외부 시스템과 통합해야 합니다.</li>
<li><strong>어플리케이션 서비스 제공자</strong>가 아님: 데이터베이스, 캐시 같은 서비스는 직접 운영하거나 별도 배포해야 합니다.</li>
<li><strong>중앙집중식 오케스트레이터</strong>가 아님: 다양한 컨트롤러들이 비동기적으로 상태를 유지합니다.</li>
</ul>
<h2 id="kubernetes의-역사적-배경">Kubernetes의 역사적 배경</h2>
<h3 id="1-전통적-서버-환경">1. 전통적 서버 환경</h3>
<ul>
<li>물리 서버 위에 여러 앱이 동작 → 리소스 경합 및 비효율 문제</li>
</ul>
<h3 id="2-가상화-시대">2. 가상화 시대</h3>
<ul>
<li>VM 도입 → 자원 격리 및 효율 개선, 하지만 무겁고 느림</li>
</ul>
<h3 id="3-컨테이너-시대">3. 컨테이너 시대</h3>
<ul>
<li>OS 공유 기반 경량화 → 빠른 배포, 높은 이식성, 리소스 최적화</li>
</ul>
<p>컨테이너 기술의 급격한 발전은 복잡한 컨테이너 환경을 운영할 수 있는 관리 시스템(Kubernetes)의 등장을 자연스럽게 이끌었습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Overview]]></title>
            <link>https://velog.io/@smpaaark-tech/Overview</link>
            <guid>https://velog.io/@smpaaark-tech/Overview</guid>
            <pubDate>Tue, 22 Apr 2025 04:43:24 GMT</pubDate>
            <description><![CDATA[<h2 id="airflow란-무엇인가">Airflow란 무엇인가?</h2>
<blockquote>
<p><strong>&quot;워크플로우를 코드로 정의하고, 배치 실행을 체계화하는 플랫폼&quot;</strong></p>
</blockquote>
<p>Airflow는 Python 코드로 워크플로우(DAG: Directed Acyclic Graph)를 정의하고, 주기적으로 실행되도록 스케줄링하며, 실행 상태를 모니터링할 수 있게 해줍니다.</p>
<p>특징은 다음과 같습니다:</p>
<ul>
<li><strong>Workflows as Code</strong>: Python으로 파이프라인을 작성</li>
<li><strong>동적 생성</strong>: 코드로 DAG를 동적으로 만들 수 있음</li>
<li><strong>확장성</strong>: 다양한 오퍼레이터 제공, 필요시 직접 개발 가능</li>
<li><strong>유연성</strong>: Jinja 템플릿을 통한 파라미터화 지원</li>
<li><strong>웹 UI 제공</strong>: DAG와 Task 상태를 시각화 및 관리 가능</li>
</ul>
<hr>
<h2 id="간단한-예제-살펴보기">간단한 예제 살펴보기</h2>
<pre><code class="language-python">from datetime import datetime

from airflow import DAG
from airflow.decorators import task
from airflow.operators.bash import BashOperator

# DAG 정의
with DAG(dag_id=&quot;demo&quot;, start_date=datetime(2022, 1, 1), schedule=&quot;0 0 * * *&quot;) as dag:
    hello = BashOperator(task_id=&quot;hello&quot;, bash_command=&quot;echo hello&quot;)

    @task()
    def airflow():
        print(&quot;airflow&quot;)

    hello &gt;&gt; airflow()</code></pre>
<h3 id="요약">요약</h3>
<ul>
<li><strong>DAG</strong>: &quot;demo&quot;라는 이름으로 매일 자정마다 실행.</li>
<li><strong>Task</strong>: <code>hello</code> (bash 실행) -&gt; <code>airflow</code> (python 실행) 순서로 의존성 설정.</li>
</ul>
<hr>
<h2 id="왜-airflow를-써야-할까">왜 Airflow를 써야 할까?</h2>
<h3 id="1-코드-기반-워크플로우-정의">1. 코드 기반 워크플로우 정의</h3>
<ul>
<li>Git을 통한 버전 관리, 리뷰, 롤백이 가능.</li>
<li>협업 및 테스트 작성이 용이.</li>
</ul>
<h3 id="2-복잡한-파이프라인-스케줄링-가능">2. 복잡한 파이프라인 스케줄링 가능</h3>
<ul>
<li>DAG 안에서 Task 간 의존성을 자유롭게 설정.</li>
<li>Backfill, Catchup 등 과거 데이터에 대한 재처리 지원.</li>
</ul>
<h3 id="3-생태계와-확장성">3. 생태계와 확장성</h3>
<ul>
<li>S3, GCS, Spark, Kubernetes 등 수많은 오퍼레이터 존재.</li>
<li>필요시 커스텀 오퍼레이터 제작 가능.</li>
</ul>
<h3 id="4-운영-편의성">4. 운영 편의성</h3>
<ul>
<li>웹 UI를 통한 상태 모니터링 및 Task 재실행.</li>
<li>각 Task별 로그 확인 가능.</li>
</ul>
<hr>
<h2 id="주의해야-할-점">주의해야 할 점</h2>
<h3 id="배치성-워크플로우에-최적화">배치성 워크플로우에 최적화</h3>
<ul>
<li>Airflow는 유한한 시작과 끝을 가진 배치 파이프라인에 최적화.</li>
<li>Kafka 같은 <strong>스트리밍</strong> 환경에는 부적합.</li>
</ul>
<h3 id="클릭-기반이-아님">&quot;클릭&quot; 기반이 아님</h3>
<ul>
<li>워크플로우를 정의할 때 <strong>반드시 코딩</strong>이 필요.</li>
<li>노코드/로우코드 솔루션을 찾는다면 다른 도구를 고려해야 함.</li>
</ul>
<hr>
<h2 id="실무-적용-팁">실무 적용 팁</h2>
<ul>
<li><strong>초기 세팅</strong>: 로컬에 Docker Compose로 띄워 실험해보기.</li>
<li><strong>구조 설계</strong>: DAG와 Task를 너무 무겁게 만들지 말 것 (단일 책임 원칙 적용).</li>
<li><strong>모듈화</strong>: 공통 기능은 Python 모듈로 분리하여 재사용성 높이기.</li>
<li><strong>모니터링</strong>: SLA 미준수 알림 설정, 실패 Task 알림을 Slack이나 PagerDuty로 연동.</li>
</ul>
]]></description>
        </item>
    </channel>
</rss>