<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>____.log</title>
        <link>https://velog.io/</link>
        <description></description>
        <lastBuildDate>Thu, 24 Jul 2025 02:18:06 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>____.log</title>
            <url>https://velog.velcdn.com/images/seon___/profile/0366be1d-6a17-4c79-97a0-87019c3f0301/image.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. ____.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/seon___" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[2]replicaset, deployment, namespace ]]></title>
            <link>https://velog.io/@seon___/2replicaset-deployment-namespace-hrrz11ln</link>
            <guid>https://velog.io/@seon___/2replicaset-deployment-namespace-hrrz11ln</guid>
            <pubDate>Thu, 24 Jul 2025 02:18:06 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/seon___/post/638b5cb9-bdf1-4a7a-b804-74320abaade1/image.png" alt=""></p>
<hr>
<ol>
<li>replicaset, replicacontroller</li>
<li>deployment</li>
<li>namespace</li>
</ol>
<hr>
<h1 id="1-kubernetes-controller">1. Kubernetes controller</h1>
<h2 id="replicationcontroller왜-필요할까">ReplicationController왜 필요할까?</h2>
<ol>
<li>고가용성</li>
</ol>
<p>어플리케이션이 죽을때, 최소로 돌아가는 어플리케이션을 유지할 수 있도록 해준다.</p>
<ul>
<li>단일 파드여도 replication contrller를 사용할수있다.</li>
<li>명시한 개수의 컨테이너가 돌아가도록 보장하는것.</li>
</ul>
<ol start="2">
<li>로드밸런싱 &amp; 스케일링</li>
</ol>
<ul>
<li>파드간의 로드밸런싱을 해준다.</li>
<li>트래픽이 올라갈때 스케일링을 해준다.</li>
</ul>
<h3 id="replicaset-vs-replicacontroller">Replicaset vs ReplicaController</h3>
<p>Replicaset은 새로 나온 권장되는 기능이다.
이제는 replicaset이 보편적으로 사용되고, 더 이상 controller는 사용되지않는다.
그러나 여기에서는 둘다 다룬다.</p>
<h2 id="replicacontroller">ReplicaController</h2>
<pre><code class="language-yaml">//replica-definition.yml
apiVersion: v1
kind: ReplicationController
metadata:
  name: myapp-rc // user-define
  labels:
      app: myapp
      type: front-end
spec:
  template:
  //여기부터는 pod-definition.yml
    metadata:
      name: myapp-pod
      labels:
          app: myapp
          type: front-end
    spec:
      containers:
      - name: nginx-container
        image: nginx
  //여기까지
  //몇개의 파드를 유지하고 싶은지 명시.
  replicas: 3</code></pre>
<pre><code class="language-yaml">kubectl get replicationcontroller</code></pre>
<h2 id="replicaset">Replicaset</h2>
<pre><code class="language-yaml">apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: myapp-replicaset
  labels:
      app: myapp
      type: front-end
spec:
  template:
  //여기부터 pod의 metadata 기재
    metadata:
      name: myapp-pod
      labels:
          app: myapp
          type: front-end
    spec:
      containers:
      - name: nginx-container
        image: nginx
  replicas: 3
  selector: 
    matchLabels:
      type: front-end</code></pre>
<ul>
<li>selector는 replicaset에 있는 옵션으로 이제는 필수적으로 명시해야된다.</li>
</ul>
<pre><code class="language-yaml">kubectl get replicaset</code></pre>
<h2 id="labels-and-selectors">Labels and Selectors</h2>
<p>모니터링할 타켓 리소스을 구분할 수 있게해줌</p>
<h3 id="replicas-값을-수정하고싶을때">replicas 값을 수정하고싶을때</h3>
<pre><code class="language-yaml">kubectl replace -f replicaset-definition.yml(filename.yml)
#or
kubectl scale --replicas=6 -f filename.yml
#or
kubectl scale --replicas=6 replicaset(type) myapp-replicaset(name)</code></pre>
<hr>
<h1 id="2-kubernetes-deployments">2. Kubernetes Deployments</h1>
<p>도커 인스턴스들을 중단없이 매끄럽게 업그레이드 </p>
<ul>
<li><p><strong>Rolling update:</strong></p>
<p>  한번에 업그레이드하고 싶지않고, 하나씩 점진적으로 업그레이드하고싶을때 사용되는 기법.</p>
<blockquote>
<p><strong><code>Rolling Update</code></strong>: 새로운 버전의 애플리케이션 컨테이너를 하나씩 점진적으로 배포하면서, 동시에 구버전 컨테이너를 하나씩 제거하는 방식입니다. 이 덕분에 전체 서비스가 중단되는 순간이 없습니다.</p>
</blockquote>
</li>
<li><p>최근 업데이트에 오류가 발생해서 roll back 하고싶거나</p>
</li>
</ul>
<pre><code class="language-yaml">#deployment-definition.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp-deployment
  labels:
      app: myapp
      type: front-end
spec:
  template:
    metadata:
      name: myapp-pod
      labels:
          app: myapp
          type: front-end
    spec:
      containers:
      - name: nginx-container
        image: nginx
  replicas: 3
  selector: //옵셔널
    matchLabels:
      type: front-end</code></pre>
<pre><code class="language-yaml">kubectl create -f deployment-definition.yml
kubectl get deployments
kubectl get replicaset
kubectl get pods
# etc
kubectl get all</code></pre>
<h2 id="deployment의-특징">deployment의 특징</h2>
<ul>
<li>선언형 업데이트</li>
<li>replicaSet 관리 -&gt; 롤링 업데이트,버저닝,롤백 지원</li>
<li>스케일링</li>
</ul>
<h3 id="kind를-deployment로-설정-vs-replicaset로-설정의-차이가-뭐지">kind를 deployment로 설정 vs replicaset로 설정의 차이가 뭐지?</h3>
<ol>
<li><p>deployment이라는 객체를 따로 생성.</p>
<p> —&gt; 다른 차이점들을 다음 강의에 알려주시기로…  음..</p>
</li>
</ol>
<ul>
<li><p>Baeldung을 통해 알아본 차이점.</p>
<ul>
<li><p><a href="https://www.baeldung.com/ops/kubernetes-deployment-vs-replicaset">https://www.baeldung.com/ops/kubernetes-deployment-vs-replicaset</a></p>
<table>
<thead>
<tr>
<th>Deployments</th>
<th>ReplicaSet</th>
</tr>
</thead>
<tbody><tr>
<td>rolling updates, rollbacks, versioning등 추가기능들을 지원하는 고수준의 추상화 기술</td>
<td>명시된 개수의 파드replicaset을 관리하는 저수준의 추상화 기술.</td>
</tr>
<tr>
<td>(기본 스케일링과 self-healing 지원)</td>
<td></td>
</tr>
<tr>
<td>파드 template을 관리함.</td>
<td></td>
</tr>
<tr>
<td>replicaset을 이용해서, 특정 개수 파드 replica를 유지하도록 함.</td>
<td>명시된 개수의 파드 replicas만 관리.</td>
</tr>
<tr>
<td>자동 롤링 업데이트, 롤백을 통해서,</td>
<td></td>
</tr>
<tr>
<td>다운타임 최소화해준다</td>
<td>수동으로 업데이트 / 롤백 필요</td>
</tr>
<tr>
<td>버저닝 지원 → 롤백이 쉽다.</td>
<td>버저닝 지원 x</td>
</tr>
</tbody></table>
</li>
</ul>
</li>
</ul>
<h3 id="deployment의-옵션에는">deployment의 옵션에는</h3>
<p>strategy라는 옵션이 있다.
이 옵션을 통해
recreate, 혹은 rolling update를 설정할수있고,
rolling update의 상세사항인, maxsurge등을 설정할수있다.</p>
<hr>
<h1 id="3-namespace">3. Namespace</h1>
<p>클러스터 생성시 자동생성되는 3가지 네임스페이스가있다.</p>
<ol>
<li>Default</li>
<li>kube-system</li>
<li>kube-public</li>
</ol>
<p>같은 클러스터를 사용하고 싶지만, 리소스를 구분하고싶을때. namespace를 구분할수있다.</p>
<p>Q. 네임스페이스는 클러스터간에도 같은 네임스페이스를 넣을수있는건지.?</p>
<pre><code class="language-bash"># automatically add DNS service name
mysql.connect(&quot;db-service.dev.svc.cluster.local&quot;)
#             &quot;servicename.namespace.service.domain(=cluster.local)&quot;</code></pre>
<pre><code class="language-yaml"># namespace를 지정하고싶을때. pod-definition.yml
apiVersion: v1
kind: Pod

metadata:
  name: myapp-pod
  **namespace: dev # namespace를 지정할수있음**
  labels:
    app: myapp
    type: front-end
spec:
    containers:
    - name: nginx-container
      image: nginx</code></pre>
<h3 id="create-namespace">create namespace</h3>
<ol>
<li>yaml로 생성하는 방법</li>
</ol>
<pre><code class="language-yaml">apiVersion: v1
kind: Namespace
metadata:
    name: dev</code></pre>
<ol>
<li>cmd로 생성하는 방법</li>
</ol>
<pre><code class="language-yaml">kubectl create namespace dev</code></pre>
<p>get pods를 통해 정보 조회 시, 원하는 namespace를 지정하지않으면 default namespace가 조회된다.</p>
<ul>
<li><p>만약, default namespace를 다른 것(ex. dev)으로 변경하고싶을때?</p>
<pre><code class="language-bash">  kubectl config set-context $(kubectl config current-context) --namespace=dev</code></pre>
</li>
</ul>
<pre><code class="language-bash">#모든 네임스페이스의 파드 조회
kubectl get pods --all-namespaces</code></pre>
<h3 id="create-quota">create quota</h3>
<p>네임스페이스의 쿼타를 yml를 통해 지정가능.</p>
<pre><code class="language-bash">apiVersion: v1
kind: ResourceQuota
metadata:
  name: compute-quota
  namespace: dev
spec:
  hard:
    pods: &quot;10&quot;
    requests.cpu: &quot;4&quot;
    requests.memory: 5Gi
    limits.cpu: &quot;10&quot;
    limits.memory: 10Gi. </code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[1]Cluster Architecture,Pods]]></title>
            <link>https://velog.io/@seon___/1Cluster-ArchitecturePods</link>
            <guid>https://velog.io/@seon___/1Cluster-ArchitecturePods</guid>
            <pubDate>Thu, 24 Jul 2025 01:36:30 GMT</pubDate>
            <description><![CDATA[<hr>
<ol>
<li><a href="https://www.notion.so/1-Cluster-Architecture-Pods-2319ba00fe5680a3a048e2f875896614?pvs=21">전체적인 쿠버네티스의 구조</a></li>
<li><a href="https://www.notion.so/1-Cluster-Architecture-Pods-2319ba00fe5680a3a048e2f875896614?pvs=21">파드</a></li>
</ol>
<hr>
<h1 id="1-kubernetes-architecture">1. Kubernetes Architecture</h1>
<h2 id="구성요소">구성요소</h2>
<h3 id="1-node--worker-machine-minions">1. Node : worker machine, minions</h3>
<ul>
<li>need more than one mode.(if one failed, others are accessible)</li>
</ul>
<h3 id="2-cluster--set-of-nodes">2. Cluster : set of nodes.</h3>
<ul>
<li>if one node fail, still accessible</li>
<li>group nodes sharing loads</li>
</ul>
<h3 id="3-master--watch-worker-nodes">3. Master : watch worker nodes</h3>
<ul>
<li>orchestration nodes</li>
</ul>
<h2 id="쿠버네티스를-설치하면-실제로-구성되어있는-요소들">쿠버네티스를 설치하면, 실제로 구성되어있는 요소들</h2>
<h3 id="1-api-server">[1] API server</h3>
<p>front end of Kubernetes</p>
<h3 id="2-etcd">[2] etcd</h3>
<p>keystore for all data used to manage the cluster</p>
<ul>
<li>etcd stores all info on all the nodes in the cluster in a distributed manner.</li>
<li>is responsible for implementing locks within the cluster to ensure no conflict with master</li>
</ul>
<h3 id="3-kubelet">[3] kubelet</h3>
<p>the agent that runs on each node in the cluster.</p>
<ul>
<li>agent : 예상된 노드에 컨테이너가 잘 돌아가는지 확인/수행.</li>
</ul>
<h3 id="4-container-runtime">[4] Container Runtime</h3>
<p>use to run containers = docker.</p>
<h3 id="5-controller">[5] Controller</h3>
<p>brain </p>
<ul>
<li>noticing and responding when nodes, containers or endpoints goes down.</li>
<li>decide to bring up new containers</li>
</ul>
<h3 id="6-scheduler">[6] Scheduler</h3>
<p>distributing work or containers across mutliple nodes.</p>
<p>look for new created containers and assign them to nodes.</p>
<h2 id="어떻게-master-worker는-다르게-이루어져있는가">어떻게 master, worker는 다르게 이루어져있는가?</h2>
<p><img src="https://velog.velcdn.com/images/seon___/post/6d1d1a89-ed3c-46f6-a444-33e41c000500/image.png" alt=""></p>
<h1 id="docker-vs-containerd-차이">Docker vs ContainerD 차이</h1>
<ul>
<li><strong>히스토리</strong></li>
</ul>
<pre><code>쿠버네티스 - 도커 런타임만 호환됬었음.


이후, 쿠베 인기급상승.


타 런타임과의 호환을 위해, CRI도입 (OCI 표준으로 구현 시 CRI 를 사용해서 쿠버네티스와 호환해서 사용할수있게됨)</code></pre><p>   <del>dockershim 으로 계속 도커를 CRI없이도 지원가능하도록 함.</del>(deprecated)</p>
<pre><code>dockershim이 deprecated 되면서 containerD가 나옴.</code></pre><h3 id="도커의-구성요소">도커의 구성요소</h3>
<p><img src="https://velog.velcdn.com/images/seon___/post/14fbb05d-7034-4945-a5cc-591a1cb95713/image.png" alt=""></p>
<p>Run C : Container Run time.</p>
<p>Container D : daemon managing run C. / can working directly with Kubernetes 도커외의 런타임과 직접 사용가능 / CRI Compatible.</p>
<p>dockershim 이제 지원 X</p>
<ul>
<li>도커의 다른 기능이 필요없는 경우, containerD만 설치가능<ul>
<li>ctr : cmd tools, not user friendly</li>
<li>nerdctr : docker-like cli for containerD / new feature not in docker</li>
<li>crictr : not for create container , for debug. (pull image, list images, list containers, view logs, <strong>also can aware of pods</strong>)</li>
</ul>
</li>
</ul>
<table>
<thead>
<tr>
<th></th>
<th>ctr</th>
<th>nerdctl</th>
<th>crictl</th>
</tr>
</thead>
<tbody><tr>
<td>purpose</td>
<td>Debugging</td>
<td>General Purpose</td>
<td>Debugging</td>
</tr>
<tr>
<td>community</td>
<td>ContainerD</td>
<td>ContainerD</td>
<td>Kubernetes</td>
</tr>
<tr>
<td>Works With</td>
<td>ContainerD</td>
<td>ContainerD</td>
<td>All CRI Compatible Runtimes</td>
</tr>
</tbody></table>
<hr>
<h1 id="2-pods">2. Pods</h1>
<h2 id="일반적인-파드와-컨테이너-노드의-관계">일반적인 파드와 컨테이너, 노드의 관계</h2>
<ul>
<li>파드: 컨테이너는 1:1이 일반적임.</li>
<li>유저 증가로 인해, scale해야할때, 컨테이너를 추가하지 않는다.<ul>
<li>대신, 노드안에 Pod를 추가한다 → 더 증가 시, 노드 전체를 추가하기도함.</li>
<li>scale up : 파드를 추가 / scale down : 파드를 제거</li>
</ul>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/seon___/post/b5e9e5d1-c100-41b4-9a85-d2ea1bdfdf63/image.png" alt=""></p>
<h2 id="파드안에-두-개의-컨테이너가-있는-경우">파드안에 두 개의 컨테이너가 있는 경우</h2>
<ul>
<li>Helper Containers 이다.<ul>
<li>helper container는 application container가 생성되면 같이 생성/ 제거 시 같이 제거 된다. (같은 파드이기 때문)</li>
<li>같은 network, storage를 공유한다.</li>
</ul>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/seon___/post/d38369de-0989-40e0-996f-011224edf793/image.png" alt=""></p>
<h2 id="kubernetes-에서의-pods">Kubernetes 에서의 pods.</h2>
<p>pod가 없고 도커만으로 컨테이너를 런하는경우, 연관된 helper container 관리, scale한 전체 컨테이너의 관리를 직접해줘야한다.</p>
<ul>
<li>pod를 통해, 컨테이너 상태 모니터링 할 수 있고, 그에 따른 조치가 가능함.</li>
<li>같은 pod에 대해서 같은 네트워크와 스토리지, 생명주기를 부여할수있음.</li>
</ul>
<pre><code class="language-jsx">kubectl run nginx --image [image-name] </code></pre>
<p>→ pods를 우선 생성하고 nginx image 를 deploy 한다.</p>
<pre><code class="language-jsx">kubectl get pods</code></pre>
<h1 id="yaml">YAML</h1>
<p><img src="https://velog.velcdn.com/images/seon___/post/a0ca1ea8-7b34-495d-9d84-9569b9c4ba27/image.png" alt=""></p>
<p>기본 yaml.</p>
<ul>
<li>apiVersion</li>
<li>kind</li>
<li>metadata</li>
<li>spec</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[영속성 전이(cascade)]]></title>
            <link>https://velog.io/@seon___/%EC%98%81%EC%86%8D%EC%84%B1-%EC%A0%84%EC%9D%B4cascade-ehkc5umr</link>
            <guid>https://velog.io/@seon___/%EC%98%81%EC%86%8D%EC%84%B1-%EC%A0%84%EC%9D%B4cascade-ehkc5umr</guid>
            <pubDate>Wed, 19 Feb 2025 01:50:21 GMT</pubDate>
            <description><![CDATA[<ul>
<li>부모엔티티저장할때 자식엔티티도 함께 저장하고 싶을때 사용한다.</li>
</ul>
<h1 id="영속성이란">영속성이란?</h1>
<p>→ <strong>데이터를 생성한 프로그램의 실행이 종료되더라도 사라지지않는 데이터의 특성</strong></p>
<p>부모를 persist할때 그 밑의 자식객체들도 persist되는것</p>
<p>연관관계매핑과는 전혀무관!</p>
<p>그저 편리함제공일뿐</p>
<h3 id="property-종류">PROPERTY 종류</h3>
<ul>
<li>ALL:모두적용</li>
<li>PERSIST:영속 만 적용</li>
</ul>
<aside>
💡 주의할 점!
하나의 부모가 여러 자식들을 관리할때는 의미가있다
BUT, 하나의 자식이 여러부모와 연관있고, 여러 부모가 관리할때는 쓰면안된다.

</aside>

<h3 id="고아객체">고아객체</h3>
<p>부모엔티티와 연관관계가 끊어진 자식엔티티를 자동으로 삭제한다.</p>
<p>자식엔티티가 삭제되었을때, persist없어도 삭제쿼리가 나간다.</p>
<p>컬랙션에서 나간 객체는 삭제된다.</p>
<aside>
💡 주의할 점!
참조하는곳이 하나일때만 사용
완전히 종속관계일때 사용

</aside>]]></description>
        </item>
        <item>
            <title><![CDATA[머지소트, 퀵소트]]></title>
            <link>https://velog.io/@seon___/%EB%A8%B8%EC%A7%80%EC%86%8C%ED%8A%B8-%ED%80%B5%EC%86%8C%ED%8A%B8</link>
            <guid>https://velog.io/@seon___/%EB%A8%B8%EC%A7%80%EC%86%8C%ED%8A%B8-%ED%80%B5%EC%86%8C%ED%8A%B8</guid>
            <pubDate>Tue, 18 Feb 2025 01:44:20 GMT</pubDate>
            <description><![CDATA[<pre><code>
💡 &lt;Java에서의 정렬알고리즘&gt;
Primitive Type → QuickSort [nlogn]
Object Type → MergeSort [nlogn]</code></pre><h1 id="mergesort">MergeSort</h1>
<ul>
<li><strong>시간복잡도: O(nlogn)</strong></li>
<li>크게 split단계와 merge단계로 나눌 수 있다.</li>
<li>재귀를 사용한다.</li>
<li>merge단계에서는 두개의 리스트의 각각 A[0]과 B[0]을 비교해서 작은 값을 앞으로 보내고, 작은값이 포함되어있던 리스트의 피벗? 비교대상인덱스? 를 다음으로 넘긴다.<ul>
<li>ex. A[0]과 B[0]중 B가 더 작으면, B[0]을 앞으로 보내고, 다음에는 A[0]과 B[1]을 비교한다.</li>
</ul>
</li>
</ul>
<h1 id="quicksort">QuickSort</h1>
<ul>
<li><strong>시간복잡도: O(nlogn)</strong></li>
<li>피벗을 사용함</li>
<li>재귀를 사용한다.</li>
<li>맨 앞을 피벗으로 설정해서 작은데이터를 왼쪽, 큰 데이터를 오른쪽으로 넘긴다. 이를 반복한다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/seon___/post/92b55af8-2f0d-4430-a3fc-50490d8a8f0d/image.png" alt=""></p>
<p><strong>정렬알고리즘</strong> <strong>코드 예시</strong></p>
<ul>
<li><a href="https://github.com/seoeunbae/Algorithm_2022/tree/main/Algorithm/src/sort">https://github.com/seoeunbae/Algorithm_2022/tree/main/Algorithm/src/sort</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[B+Tree ]]></title>
            <link>https://velog.io/@seon___/BTree</link>
            <guid>https://velog.io/@seon___/BTree</guid>
            <pubDate>Sun, 16 Feb 2025 06:24:10 GMT</pubDate>
            <description><![CDATA[<ul>
<li>[참고자료]:<a href="https://rebro.kr/167#:~:text=%EC%9D%B8%EB%8D%B1%EC%8A%A4(Index)%EB%8A%94%20%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B2%A0%EC%9D%B4%EC%8A%A4%EC%9D%98,%EC%A3%BC%EC%86%8C%EC%99%80%20%ED%95%A8%EA%BB%98%20%EC%A0%80%EC%9E%A5%EB%90%9C%EB%8B%A4">https://rebro.kr/167#:~:text=인덱스(Index)는 데이터베이스의,주소와 함께 저장된다</a>.</li>
</ul>
<hr>
<h1 id="인덱스에서-b-tree-보다-btree를-주로-사용하는-이유">인덱스에서 B-Tree 보다 B+Tree를 주로 사용하는 이유?</h1>
<p>→ <strong>인덱스 컬럼은 부등호를 이용한 순차 검색 연산이 자주 발생할 수 있다.</strong> 따라서 B+Tree의 Linked list를 이용하면 순차 검색을 효율적으로 할 수 있게 된다.</p>
<ul>
<li>B+Tree의 검색 과정은 B-Tree와 동일하다. 반면 B+Tree의 삽입과 삭제 과정은 약간의 차이가 있다. 기본적으로 B+Tree의 삽입과 삭제는 항상 leaf node에서 일어난다.</li>
</ul>
<h1 id="btree-구조">B+Tree 구조</h1>
<p>B+Tree는 <strong>오직 leaf node에만 데이터를 저장하고 leaf node가 아닌 node에서는 자식 포인터만 저장한다.</strong></p>
<p>그리고 <strong>leaf node끼리는 Linked list로 연결되어있다.</strong></p>
<p>또, B+Tree에서는 반드시 leaf node에만 데이터가 저장되기 때문에 중간 node에서 key를 올바르게 찾아가기 위해서 key가 중복될 수 있다.</p>
<p><img src="https://velog.velcdn.com/images/seon___/post/52f4ce06-31a8-4b97-a6b8-161f24f77634/image.png" alt=""></p>
<h2 id="장">장</h2>
<ol>
<li>Leaf node를 제외하고 데이터를 저장하지 않기 때문에 메모리를 더 확보할 수 있다. → 하나의 node에 더 많은 포인터를 가질 수 있기 때문에 트리의 높이가 더 낮아짐 → 검색 속도 향상</li>
<li>Full Scan 을 하는 경우, leaf node에만 데이터가 저장되있고,  leaf node끼리 linkedlist로 연결되어있어서 선형 시간이 소모된다. 
↔ B-Tree는 모든 노드를 확인해야함!</li>
</ol>
<h2 id="단">단</h2>
<ol>
<li>B-Tree의 경우, 최상의 경우 특정 key를 root node에서 찾을 수 있지만 
↔ <strong>B+Tree의 경우 반드시 특정 key에 접근하기 위해서 leaf node까지 가야 함</strong></li>
</ol>
<h1 id="삽입">삽입</h1>
<h2 id="1-key-의-수가-최대키수-보다-적은-리프노드에-삽입하는-경우">1) key 의 수가 최대키수 보다 적은 리프노드에 삽입하는 경우</h2>
<p><img src="https://velog.velcdn.com/images/seon___/post/7328354a-4a94-4775-9db5-7ac2499a3152/image.png" alt=""></p>
<p>해당 node의 가장 앞이 아닌 곳에 삽입되는 경우는 단순히 삽입해 주면 된다.</p>
<p>→ 하지만, leaf node의 가장 앞에 삽입되는 경우는, 해당 node를 가리키는 부모 node의 포인터의 오른쪽에 위치한 key를 K(삽입되는 애)로 바꿔준다. 그리고 leaf node끼리 Linked list로 이어줘야 하므로 삽입된 key에 Linked list로 연결한다.</p>
<h2 id="2-key-의-수가-최대인-리프노드에-삽입하는-경우">2) key 의 수가 최대인 리프노드에 삽입하는 경우</h2>
<p><img src="https://velog.velcdn.com/images/seon___/post/6b644a16-a6ae-4bc4-89e7-0fae2e1f9c37/image.png" alt=""></p>
<p>key의 수가 최대이므로 삽입하는 경우 <strong>분할</strong>을 해주어야 한다. 만약 중간 node에서 분할이 일어나는 경우는 B-Tree와 동일하게 해주면 된다.</p>
<p>leaf node에서 분할이 일어나는 경우는 중간 key를 부모 node로 올려주는데 이때, 오른쪽 node에 중간 key를 붙여 분할한다. 그리고 분할된 두 node를 Linked List로 연결해준다.</p>
<h1 id="삭제">삭제</h1>
<h2 id="1-삭제할-key가-리프노드의-가장-앞에-있지-않는-경우">1) 삭제할 key가 리프노드의 가장 앞에 있지 않는 경우</h2>
<p>B-Tree와 동일한 방법으로 삭제된다.</p>
<h2 id="2-삭제할-key가-리프노드의-가장-앞에-위치한-경우">2) 삭제할 key가 리프노드의 가장 앞에 위치한 경우</h2>
<p>이 경우는 leaf node가 아닌 node에 key가 중복해서 존재한다.
 → 따라서 해당 key를 노드보다 오른쪽에 있으면서 가장 작은 값으로 바꿔주어야 한다.</p>
<p><img src="https://velog.velcdn.com/images/seon___/post/eba7e8b1-2efc-4241-9b31-e3d1afd8937a/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[OSIV]]></title>
            <link>https://velog.io/@seon___/OSIV</link>
            <guid>https://velog.io/@seon___/OSIV</guid>
            <pubDate>Tue, 11 Feb 2025 03:06:57 GMT</pubDate>
            <description><![CDATA[<p>Open Session In View</p>
<p>뷰에서도 영속성컨텍스트를 열어놓겠다.</p>
<p>즉, 뷰에서도 지연로딩을 열어놓는다는 뜻이다.</p>
<h2 id="과거osiv요청당-트랜잭션">과거OSIV:요청당 트랜잭션</h2>
<blockquote>
<p>클라에서 요청이 들어오자마자 서블릿필터나 스프링인터셉터에서 트랜잭션을 시작하고 요청이 끝날 때 트랜잭션도 끝내는 것이다.</p>
</blockquote>
<p>뷰에서도 지연로딩을 할 수 있게되면서 퍼사드계층없이도 뷰에 독립적인 서비스 계층을 유지할 수 있다.</p>
<h2 id="요청당-트랜잭션의-문제점">요청당 트랜잭션의 문제점</h2>
<blockquote>
<p>(컨트롤러, 뷰)프리젠테이션 계층이 엔티티를 변경할 수 있다.</p>
</blockquote>
<h2 id="해결방안">해결방안</h2>
<ol>
<li>엔티티를 read-only 인터페이스로.</li>
<li>엔티티 래핑하기</li>
</ol>
<p>엔티티의 getter(읽기전용메소드)만 있는 래퍼클래스를 만든다.</p>
<pre><code class="language-java">class MemberWrapper{
    private Member member;

    public MemberWrapper(member){
        this.member = member;
    }

    public String getName(){
        member.getName();    
    }
}</code></pre>
<ol>
<li>DTO만 반환하기</li>
</ol>
<p>전통적인 방법.</p>
<p>→ BUT, 엔티티를 거의 복사한듯 DTO를 하나더 만들어야함.</p>
<h2 id="현재-스프링osiv-비즈니즈계층에서만-트랜잭션유지">현재 스프링OSIV: 비즈니즈계층에서만 트랜잭션유지</h2>
<p>spring-orm.jar 에서 다양한 osiv클래스를 제공.</p>
<p><img src="https://velog.velcdn.com/images/seon___/post/c8dd6771-4ba7-40a5-9722-9796582fc0f0/image.png" alt=""></p>
<ol>
<li>클라이언트 요청이 들어오면 서블릿 필터 혹은 스프링 인터셉터에서 영속성 컨텍스트를 생성한다. 단 이때 <strong>트랜잭션은 시작하지 않는다.</strong></li>
<li><strong>서비스 계층</strong>에서 @Transactional로 <strong>트랜잭션을 시작할 때</strong> 1번에서 미리 생성해둔 <strong>영속성 컨텍스트를 찾아와서 트랜잭션을 시작</strong>한다.</li>
<li>서비스 계층이 끝나면 트랜잭션을 커밋하고 영속성 컨텍스트를 플러시한다. 이때 <strong>트랜잭션은 끝내지만 영속성 컨텍스트는 종료하지 않는다.</strong></li>
<li><strong>컨트롤러와 뷰까지 영속성 컨텍스트가 유지되므로 조회한 엔티티는 영속 상태를 유지한다.</strong></li>
<li><strong>서블릿 필터나 스프링 인터셉터로 요청이 돌아오면 영속성 컨텍스트를 종료한다. 단 이때 플러시를 호출하지 않고 바로 종료한다.</strong></li>
</ol>
<ul>
<li>영속성 컨텍스트는 트랜잭션없이(범위 밖에서) 엔티티를 조회만 할 수 있다. 이것을 NonTransactional reads라고한다.</li>
</ul>
<h3 id="서비스에서-컨트롤러로-요청이-넘어간뒤-변경감지더티체킹이-안되는-이유">서비스에서 컨트롤러로 요청이 넘어간뒤 변경감지(더티체킹)이 안되는 이유</h3>
<ul>
<li>영속성 컨텍스트의 변경 내용을 데이터베이스에 반영하려면 영속성 컨텍스트를 플러쉬해야한다. 하지만 트랜잭션을 사용하는 서비스 계층이 끝날 때 트랜잭션이 커밋되면서 이미 플러시해버렸다. 그리고 <strong>스프링이 제공하는 osiv 서블릿필터나 osiv스프링인터셉터는 요청이 끝나면 플러시를 호출하지 않고 em.close()로 영속성 컨텍스트만 종료해버리므로 플러시가 일어나지 않는다.</strong></li>
</ul>
<h2 id="스프링osiv주의사항">스프링OSIV주의사항</h2>
<ol>
<li>memberService의 getMember를 통해 찾아온 Member를 영속성 컨텍스트에 저장한다. (트랜잭션은 시작하지 않았지만 영속성 컨텍스트는 존재하기 때문에 가능하다.)</li>
<li>찾아온 member의 이름을 XXX로 바꿨다.</li>
<li>logic() 메소드를 호출하여 <strong>트랜잭션이 있는</strong> 비즈니스 로직을 실행하였다.</li>
<li>트랜잭션 AOP가 동작하면서 영속성 컨텍스트에 트랜잭션을 시작한다. 그리고 logic() 메소드를 실행한다.</li>
<li>logic()메소드가 끝나면 트랜잭션 AOP는 트랜잭션을 커밋하고 영속성 컨텍스트를 플러시한다. 이때 <strong>변경 감지가 동작하면서 회원 엔티티의 수정 사항을 데이터베이스에 반영한다.</strong></li>
<li>트랜잭션이 있는 비즈니스로직을 모두 호출하고 나서 엔티티를 변경하면 된다.</li>
</ol>
<h1 id="단점">단점</h1>
<ul>
<li>영속성 컨텍스트와 db커넥션은 1:1로 물고있는 관계이기 때문에 프레젠테이션 로직까지 디비커넥션 리소스를 낭비하게됨.→ 장애로 이어진다.</li>
<li>osiv를 적용하면 같은 영속성 컨텍스트를 여러 트랜잭션이 공유하기 될 수 있다.</li>
<li>프레젠테이션 에서 엔티티를 수정하고 비즈니스 로직수행하면 엔티티가 수정될 수 있다.</li>
<li>프레젠테이션 계층에서 렌더링 과정에서 지연 로딩에 의해 SQL이 실행되므로, 성능 튜닝시에 확인해야 할 범위가 넓어진다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[IP와 서브넷마스크]]></title>
            <link>https://velog.io/@seon___/IP%EC%99%80-%EC%84%9C%EB%B8%8C%EB%84%B7%EB%A7%88%EC%8A%A4%ED%81%AC</link>
            <guid>https://velog.io/@seon___/IP%EC%99%80-%EC%84%9C%EB%B8%8C%EB%84%B7%EB%A7%88%EC%8A%A4%ED%81%AC</guid>
            <pubDate>Tue, 11 Feb 2025 03:03:33 GMT</pubDate>
            <description><![CDATA[<hr>
<ol>
<li>사설 IP과 공인 IP</li>
<li>유동 IP와 고정 IP</li>
<li>서브넷마스크와 CIDR</li>
</ol>
<p>[IP와서브넷마스크] : <a href="https://www.youtube.com/watch?v=gOMljj6K2V0">https://www.youtube.com/watch?v=gOMljj6K2V0</a></p>
<p>[얄팍한코딩사전-IP종류] : <a href="https://www.youtube.com/watch?v=GK3h936Co-k">https://www.youtube.com/watch?v=GK3h936Co-k</a> </p>
<hr>
<p>IPv4 : 46억개 / 32비트(주소길이)</p>
<p>IPv6 : 2의 128승개 / 128bit </p>
<blockquote>
<p>**사설 IP 대역</p>
</blockquote>
<ul>
<li>10.0.0.0 ~ 10.255.255.255</li>
<li>172.16.0.0 ~ 172.31.255.255</li>
<li>192.168.0.0 ~ 192.168.255.255**<blockquote>
</blockquote>
</li>
</ul>
<p>사설 IP 컴 → 공인 IP 컴으로는 접근가능</p>
<p>공인 IP → 사설 IP 로는 접근 불가능</p>
<p><strong>즉, 웹 서비스 는 공인ip여야한다.!</strong></p>
<h3 id="사설-ip-로-웹-서비스를-사용하는-법">사설 ip 로 웹 서비스를 사용하는 법</h3>
<h3 id="1-내부-ip를-포트로-연결하는-방법도-있다">1. <strong>내부 ip를 포트로 연결하는 방법도 있다.</strong></h3>
<p>공인ip에 포트들을 개방해서 내부 사설 ip 마다 포트 하나씩 연결할 수 있다.</p>
<p>그러면 , 외부에서 접근할떄는⇒ 공인ip:포트번호</p>
<h3 id="2-dmz">2. <strong>DMZ</strong></h3>
<p>공인 ip의 모든 포트를 내부 사설 ip하나에 몰아주기</p>
<ul>
<li>보안상 위험함 , 권장X</li>
</ul>
<hr>
<h1 id="고정-ip">고정 IP</h1>
<p>서버에 사용 / 비쌈</p>
<h1 id="유동-ip">유동 IP</h1>
<p>일반 가정, 기기 에 사용 / 저렴</p>
<ul>
<li>DDNS 라는 조치를 취해서 가정에서도<ul>
<li>동적DNS : 유동 ip를 감지해서 고정된 도메인에 연결하는 것</li>
</ul>
</li>
</ul>
<hr>
<h1 id="서브넷-마스크">서브넷 마스크</h1>
<p>네트워크 host ip 의 길이를 알려주기.</p>
<p>앞에서부터 네트워크id의 범위를 알려준다.</p>
<p>ex. 172.100.99.1/24 </p>
<p>이면 앞에서부터 24자리수인, 172.100.99까지가 네트워크id이다.</p>
<p>남은 8자리수가 호스트id이다. ex.1</p>
<h2 id="서브넷-마스크-계산-예시">서브넷 마스크 계산 예시</h2>
<p>ip : 172.100.99.1</p>
<p>서브넷 : 255.255.255.0</p>
<p>→ ip : 10101100.1100100.1100011.1</p>
<p>→ subnet : 11111111.11111111.11111111.00000000</p>
<p><strong>두개를 AND 연산하면 나오는 값 (⇒ 네트워크 아이디)</strong></p>
<p><strong>→ 172.100.99.0 (⇒ 네트워크 아이디)</strong></p>
<p><strong>서브넷의 1자리 개수 만큼이 네트워크 주소의 범위이다.</strong></p>
<p><strong>즉, 남은 8개만이 호스트 개수이다.</strong></p>
<h1 id="cidr">CIDR</h1>
<p>ip주소/네트워크범위인 비트자리수</p>
<h3 id="예시">예시</h3>
<p><strong>위의 서브넷마스크계산 예시와 동일한 환경인 경우, ?? 에 오는 숫자 값은?</strong></p>
<p>→ 172.100.99.1/??</p>
<p><strong>답</strong> : 24</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[패키지매니저]]></title>
            <link>https://velog.io/@seon___/%ED%8C%A8%ED%82%A4%EC%A7%80%EB%A7%A4%EB%8B%88%EC%A0%80</link>
            <guid>https://velog.io/@seon___/%ED%8C%A8%ED%82%A4%EC%A7%80%EB%A7%A4%EB%8B%88%EC%A0%80</guid>
            <pubDate>Tue, 11 Feb 2025 03:02:16 GMT</pubDate>
            <description><![CDATA[<hr>
<ol>
<li>패키지 매니저 존재하는 이유</li>
<li>데비안계열의 패키지매니저</li>
<li>레드햇계열의 패키지매니저</li>
</ol>
<hr>
<ul>
<li><a href="https://minhan2.tistory.com/entry/%EB%A6%AC%EB%88%85%EC%8A%A4-%ED%8C%A8%ED%82%A4%EC%A7%80-%EB%B9%84%EA%B5%90aptdpkgyumrpm">https://minhan2.tistory.com/entry/리눅스-패키지-비교aptdpkgyumrpm</a></li>
</ul>
<h1 id="패키지매니저의-존재-이유">패키지매니저의 존재 이유</h1>
<p><img src="https://velog.velcdn.com/images/seon___/post/e0256511-52fc-4a3d-9760-e4555075b729/image.png" alt=""></p>
<ul>
<li><strong>복잡한 패키지들간의 의존관계</strong></li>
</ul>
<p><img src="https://velog.velcdn.com/images/seon___/post/75b4e034-252d-4c6b-904f-0f6ac0a360f8/image.png" alt=""></p>
<ul>
<li>즉, 수동업데이트와 수동설치를 하는 과정에 나타나는 의존관계 충돌을 근절하기 위해 나타났다.</li>
</ul>
<h1 id="aptapt-get">APT/APT-GET</h1>
<blockquote>
<p>데비안계열에서 주로 사용
<strong>(Ubuntu,…)</strong></p>
</blockquote>
<p><strong>dpkg라는 패키지매니저도 존재한다.</strong></p>
<p>dpkg는 해당 패키지만 설치를 진행하고 해당 패키지에 종속되서 설치되야하는 프로그램을 같이 설치해주지는 않는다.</p>
<p> 이를 해결하기 위해 나온것이 <strong>apt-get</strong>이다.</p>
<h3 id="apt-get">apt-get</h3>
<p>dpkg와 달리 종속된 프로그램이 만약 작업환경에 미설치되어있다면 추가 수동설치 필요없이 자동으로 설치해준다.</p>
<blockquote>
<p>apt와 apt-get의 차이 (apt, apt-get은 데비안계열에서 사용)</p>
<p>APT는 Advanced Packaging Tool의 약자이다.</p>
<p>apt 와 apt-get는 내부적인 동작 차이는 거의 없기에, 뭘사용해도 상관이 없다.</p>
<p>다만, 좀 더 가독성이 좋고, 메세지 안내가 나오거나(apt),</p>
<p>좀더 세부적인 옵션과 스크립트 작성을 할때 유리한것(apt-get)</p>
</blockquote>
<blockquote>
<p>script 파일, 예를들어 Dockerfile 등에서 apt를 사용하면,</p>
<p><strong><em>WARNING: apt does not have a stable CLI interface. Use with caution in scripts.</em></strong></p>
<p>이라는 경고문구가 나온다.</p>
<p>apt 명령어는 사용자와의 상호작용에 중점을 둔 CLI고, script내에서는 사용하기에는 주의가 필요하다는 것이므로, apt-get을 이용해서 사용하면 된다.</p>
</blockquote>
<h1 id="yum과-rpm">YUM과 RPM</h1>
<blockquote>
<p>레드햇 계열에서 주로 사용
<strong>(Centos, Fedora,…)</strong></p>
</blockquote>
<h2 id="rpm">RPM</h2>
<p>기존 수동설치의 방식으로는 (직접 tar,gzip로 묶여있는 패키지 소스파일을 컴파일한 후에 수동 설치) 너무 많은 시간이 들었기 때문에,  레드햇에서 패키지관리프로그램을 개발.</p>
<ul>
<li><strong>RPM 패키지는 컴파일되어 설치한 실행파일, 설정파일, 라이브러리 등을 하나로 묶어놓은 파일을 말한다.</strong></li>
</ul>
<h3 id="단점">단점</h3>
<ul>
<li>패키지 사이에 의존하고 있는 패키지까지 자동설치되지는 않는다.</li>
<li>인터넷이 연결되어있지않아도 설치가 가능하지만, rpm 확장자로 된 패키지 프로그램이 필요하다.</li>
</ul>
<h3 id="기본-사용-명령어">기본 사용 명령어</h3>
<ul>
<li>설치: rpm -Uvh [패키지명]</li>
<li>삭제: rpm -e [패키지명]</li>
<li>설치확인: rpm -qa [패키지명]</li>
<li>상세정보: rpm -qi [패키지명]</li>
</ul>
<h2 id="yum">YUM</h2>
<p>YUM은 RPM 기반의 시스템을 위한 자동 업데이터 및 패키지 설치, 제거 프로그램이다.</p>
<p>RPM과 다르게 인터넷 사용이 필수이기 때문에 패키지간 의존성 문제를 해결할 수 있다. 예를들어 A 패키지를 설치하기전에 필요한 B 패키지까지 모두 한번에 설치가 가능하며, 의존도를 자동으로 찾고 알아서 설치해준다.</p>
<ul>
<li>인터넷에서 바로 설치가 가능하기 때문에 패키지 프로그램이 따로 필요없다.</li>
<li>패키지 사이에 의존하고 있는 패키지까지 자동으로 설치가 가능하다</li>
</ul>
<h3 id="기본-사용-명령어-1">기본 사용 명령어</h3>
<ul>
<li>설치: yum install [패키지명]</li>
<li>삭제: yum remove [패키지명]</li>
<li>업그레이드: yum update [패키지명]</li>
<li>목록: yum list [패키지명]</li>
<li>yum 데이터베이스 동기화 업데이트: yum update</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[샤딩과 파티셔닝이란]]></title>
            <link>https://velog.io/@seon___/%EC%83%A4%EB%94%A9%EA%B3%BC-%ED%8C%8C%ED%8B%B0%EC%85%94%EB%8B%9D%EC%9D%B4%EB%9E%80</link>
            <guid>https://velog.io/@seon___/%EC%83%A4%EB%94%A9%EA%B3%BC-%ED%8C%8C%ED%8B%B0%EC%85%94%EB%8B%9D%EC%9D%B4%EB%9E%80</guid>
            <pubDate>Tue, 11 Feb 2025 02:57:27 GMT</pubDate>
            <description><![CDATA[<h1 id="paritioning">Paritioning</h1>
<ul>
<li>파티셔닝(Partitioning)</li>
</ul>
<p>큰 테이블이나 인덱스를 관리하기 쉬운 크기로 분리하는 방법</p>
<ul>
<li>단점: 파티션 제약이있다.= 테이블과 인덱스를 별도로 파티션 할 수 없다.</li>
</ul>
<h2 id="1-horizontal-partitioning">1. Horizontal Partitioning</h2>
<ul>
<li>데이터 개수를 기준으로 나누어 partitioning 하는 방법이다. sharding이 horizontal partitioning 과 관련있다. <strong>같은 테이블 스키마를 가진 데이터를 데이터베이스 여러개에 분산하여 저장하는 방법을 일컫는 용어이기 때문이다.</strong> 때문에 Sharding을 Horizontal Partition`이라고 볼 수도 있다.</li>
</ul>
<h2 id="2-vertical-partitioning">2. Vertical Partitioning</h2>
<ul>
<li>테이블의 칼럼을 기준으로 데이터를 나눈다.</li>
<li>이미 정규화된 데이터를 분리하는 과정으로 생각해야한다.</li>
<li>자주 사용하는 칼럼을 분리하여 성능향상을 얻을 수 있다.</li>
</ul>
<h2 id="3-sharding">3. Sharding</h2>
<ul>
<li>DBMS 한 개로 처리할 수 있는 데는 한계가 있으므로 <strong><em>데이터베이스 여러 개를 사용*</em></strong>하는 방식으로 데이터 조회 한계를 극복해야 한다. 이를 위해 분산 환경을 고려해 만들어진 데이터베이스를 이용하는 방법도 있지만 범위 검색에 취약하거나 JOIN 연산을 사용할 수 없는 등 기능에 제약이 많다. <strong><em>따라서 상대적으로 풍부한 기능을 사용하면서 데이터 확장을 꾀할 수 있는 방법은 RDBMS를 샤딩(sharding)하여 사용하는 것이다.*</em></strong>계속 증가하는 데이터에 장애 없이 효과적으로 대응할 수 있어야 하고 서비스마다 다른 데이터 특성과 모델에 어떻게 대처할 것인가가 샤딩 플랫폼의 핵심이다.</li>
</ul>
<h1 id="궁금증">궁금증</h1>
<ol>
<li><p>서로 다른 데이터베이스에 있는 테이블들을 join 할 수 있다고...?? → 같은 데이터베이스엔진이면 가능</p>
</li>
<li><p>내가 찾는 데이터가 몇번샤드에 있는지 찾는거..는..? → 알고리즘에 따라 다르다</p>
</li>
<li><p>샤딩과 horizontal partitioning 의 비교</p>
</li>
</ol>
<p>수평 분할(Horizontal Partitioning)이란 스키마가 같은 데이터를 두 개 이상의 테이블에 나누어 저장하는 디자인을 말한다. 가령 같은 주민 데이터를 처리하기 위해 스키마가 같은 ‘서현동주민 테이블&#39;과 ‘정자동주민 테이블&#39;을 사용하는 것을 말한다. 인덱스의 크기를 줄이고, 작업 동시성을 늘리기 위한 것이다. 보통 수평 분할을 한다고 했을 때는 하나의 데이터베이스 안에서 이루어지는 경우를 지칭한다.</p>
<p>이에 비해, 샤딩은 물리적으로 다른 데이터베이스에 데이터를 수평 분할 방식으로 분산 저장하고 조회하는 방법을 말한다. ‘주민’ 테이블이 여러 DB에 있을 때 서현동 주민에 대한 정보는 A DB에, 정자동 주민에 대한 정보는 DB에 저장되도록 하는 방식이다. 여러 데이터베이스를 대상으로 작업해야 하기 때문에 경우에 따라서는 <strong>(JOIN 등) 기능에 제약이 있을 수 있고</strong> 일관성(consistency)과 복제(replication) 등에서 불리한 점이 많다. 예전의 샤딩은 애플리케이션 서버 레벨에서 구현하는 경우가 많았지만 최근에는 이를 플랫폼 차원에서 제공한다.</p>
<ol start="4">
<li>샤딩의 한계</li>
</ol>
<ul>
<li><strong>두 개 이상의 샤드에 대한 JOIN 연산을 할 수 없다.</strong></li>
<li>auto increment 등은 샤드 별로 달라질 수 있다.</li>
<li>last_insert_id() 값은 유효하지 않다.</li>
<li>shard key column 값은 update하면 안된다.</li>
<li>하나의 트랜잭션에서 두 개 이상의 샤드에 접근할 수 없다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[트랜잭션의 격리수준]]></title>
            <link>https://velog.io/@seon___/%ED%8A%B8%EB%9E%9C%EC%9E%AD%EC%85%98%EC%9D%98-%EA%B2%A9%EB%A6%AC%EC%88%98%EC%A4%80</link>
            <guid>https://velog.io/@seon___/%ED%8A%B8%EB%9E%9C%EC%9E%AD%EC%85%98%EC%9D%98-%EA%B2%A9%EB%A6%AC%EC%88%98%EC%A4%80</guid>
            <pubDate>Tue, 11 Feb 2025 02:39:54 GMT</pubDate>
            <description><![CDATA[<ul>
<li>[참고자료] : <a href="https://nesoy.github.io/articles/2019-05/Database-Transaction-isolation">https://nesoy.github.io/articles/2019-05/Database-Transaction-isolation</a></li>
</ul>
<hr>
<h1 id="트랜잭션의-격리-수준-이란">트랜잭션의 격리 수준 이란?</h1>
<ul>
<li>트랜잭션이 병렬 처리될 때<ul>
<li>특정 트랜잭션이 다른 트랜잭션에서 변경하거나 조회하는 데이터를 볼 수 있도록 허용할지 말지 범위를 결정하는 것.</li>
</ul>
</li>
</ul>
<h1 id="격리수준의-종류">격리수준의 종류</h1>
<ul>
<li>READ UNCOMMITTED</li>
<li>READ COMMITTED</li>
<li>REPEATABLE READ</li>
<li>SERIALIZABLE</li>
</ul>
<h2 id="read-uncommitted">READ UNCOMMITTED</h2>
<ul>
<li>각 트랜잭션에서의 변경 내용이 <code>COMMIT</code>이나 <code>ROLLBACK</code> 여부에 상관 없이 다른 트랜잭션에서 값을 읽을 수 있다.</li>
<li>정합성에 문제가 많은 격리 수준이기 때문에 사용하지 않는 것을 권장한다.</li>
<li>아래의 그림과 같이 <code>Commit</code>이 되지 않는 상태지만 <code>Update</code>된 값을 다른 트랜잭션에서 읽을 수 있다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/seon___/post/4b03e7f5-7b38-453a-abc6-ae78a29dfc46/image.png" alt=""></p>
<h2 id="그렇다면-read-uncommitted는-문제가-없을까"><strong>그렇다면 READ UNCOMMITTED는 문제가 없을까?</strong></h2>
<ul>
<li><code>DIRTY READ</code>현상 발생<ul>
<li>트랜잭션이 작업이 완료되지 않았는데도 다른 트랜잭션에서 볼 수 있게 되는 현상</li>
</ul>
</li>
</ul>
<hr>
<h1 id="read-committed">READ COMMITTED</h1>
<ul>
<li><p>RDB에서 대부분 기본적으로 사용되고 있는 격리 수준이다.</p>
</li>
<li><p>Dirty Read 와 같은 현상은 발생하지 않는다.</p>
</li>
<li><p>실제 테이블 값을 가져오는 것이 아니라 <strong>Undo영역</strong>에 백업된 레코드에서 값을 가져온다.</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/seon___/post/ce5176fc-afb9-421c-b0a9-0bd4ff5ad5d2/image.png" alt=""></p>
<h2 id="그렇다면-read-committed는-문제가-없을까">그렇다면 READ COMMITTED는 문제가 없을까?</h2>
<p><img src="https://velog.velcdn.com/images/seon___/post/44b829e5-9dcb-4380-83aa-34744139c773/image.png" alt=""></p>
<ul>
<li><code>트랜잭션-1</code>이 Commit한 이후 아직 끝나지 않는 <code>트랜잭션-2</code>가 다시 테이블 값을 읽으면 값이 변경됨을 알 수 있다.</li>
<li>하나의 트랜잭션내에서 똑같은 SELECT 쿼리를 실행했을 때는 항상 같은 결과를 가져와야 하는 <code>REPEATABLE READ</code>의 정합성에 어긋난다.</li>
<li>이러한 문제는 주로 입금, 출금 처리가 진행되는 금전적인 처리에서 주로 발생한다.<ul>
<li>데이터의 정합성은 깨지고, 버그는 찾기 어려워 진다.</li>
</ul>
</li>
</ul>
<h1 id="repeatable-read"><strong>REPEATABLE READ</strong></h1>
<ul>
<li>MySQL에서는 트랜잭션마다 트랜잭션 ID를 부여하여 트랜잭션 ID보다 작은 트랜잭션 번호에서 변경한 것만 읽게 된다.</li>
<li>Undo 공간에 백업해두고 실제 레코드 값을 변경한다.<ul>
<li>백업된 데이터는 불필요하다고 판단하는 시점에 주기적으로 삭제한다.</li>
<li>Undo에 백업된 레코드가 많아지면 MySQL 서버의 처리 성능이 떨어질 수 있다.</li>
</ul>
</li>
<li>이러한 변경방식은 <a href="https://en.wikipedia.org/wiki/Multiversion_concurrency_control">MVCC(Multi Version Concurrency Control</a>)라고 부른다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/seon___/post/a68d2ba4-0e49-4cd0-92d3-8fb8ac15b4c8/image.png" alt=""></p>
<h2 id="그렇다면-repeatable-read는-문제가-없을까"><strong>그렇다면 REPEATABLE READ는 문제가 없을까?</strong></h2>
<ul>
<li>PHANTOM READ<ul>
<li>다른 트랜잭션에서 수행한 변경 작업에 의해 레코드가 보였다가 안 보였다가 하는 현상</li>
<li><strong>이를 방지하기 위해서는 쓰기 잠금을 걸어야 한다.</strong></li>
</ul>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/seon___/post/02f2a327-e99e-4bff-9d7e-424f251291e9/image.png" alt=""></p>
<h1 id="serializable"><strong>SERIALIZABLE</strong></h1>
<ul>
<li>가장 단순한 격리 수준이지만 가장 엄격한 격리 수준</li>
<li>성능 측면에서는 동시 처리성능이 가장 낮다.</li>
<li><code>SERIALIZABLE</code>에서는 <code>PHANTOM READ</code>가 발생하지 않는다.
하지만.. 데이터베이스에서 거의 사용되지 않는다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[커넥션 풀이란?]]></title>
            <link>https://velog.io/@seon___/%EC%BB%A4%EB%84%A5%EC%85%98-%ED%92%80%EC%9D%B4%EB%9E%80-2y4c5y02</link>
            <guid>https://velog.io/@seon___/%EC%BB%A4%EB%84%A5%EC%85%98-%ED%92%80%EC%9D%B4%EB%9E%80-2y4c5y02</guid>
            <pubDate>Tue, 11 Feb 2025 02:10:53 GMT</pubDate>
            <description><![CDATA[<p>[참고 아티클] : <a href="https://hyuntaeknote.tistory.com/12">https://hyuntaeknote.tistory.com/12</a></p>
<h1 id="배경">배경</h1>
<p>MySQL 8.0을 기준으로 INSERT 문을 수행할 때 필요한 비용의 비율은 다음과 같다. 괄호 안의 숫자가 비율을 의미</p>
<p><strong>1. Connecting (3)</strong></p>
<ol start="2">
<li><p>Sending query to server (2)</p>
</li>
<li><p>Parsing query (2)</p>
</li>
<li><p>Inserting row (1)</p>
</li>
<li><p>Inserting index(1)</p>
</li>
<li><p>Closing (1)</p>
</li>
</ol>
<p>즉, 서버가 DB에 연결하기 위한 Connecting 비용이 가장 큰 비율을 차지한다. 이처럼 Connection을 생성하는 작업은 비용이 많이 드는 작업이다. 이를 <strong>보완</strong>할 수 있는 방법이 바로 <strong>Connection Pool이다.</strong></p>
<h1 id="커넥션-풀connection-pool이란">커넥션 풀(Connection Pool)이란?</h1>
<p><img src="https://velog.velcdn.com/images/seon___/post/8d04f524-773f-42c0-8fd9-2650c7fba7b8/image.png" alt=""></p>
<p>커넥션 풀은 데이터베이스와 연결된 커넥션을 미리 만들어 놓고 이를 pool로 관리하는 것이다. 즉, <strong>필요할 때마다 커넥션 풀의 커넥션을 이용하고 반환</strong>하는 기법이다. 이처럼 <strong><em>미리 만들어 놓은</em></strong> 커넥션을 이용하면 Connection에 필요한 비용을 줄일 수 있다. 따라서 DB에 빠르게 접속할 수 있다.</p>
<p>또한 커넥션 풀을 사용하면 커넥션 수를 제한할 수 있어서 과도한 접속으로 인한 서버 자원 고갈을 방지할 수 있으며 DB 접속 모듈을 공통화해 DB 서버의 환경이 바뀔 경우 유지보수를 쉽게 할 수 있다.</p>
<h1 id="hikaricp란">HikariCP란?</h1>
<ul>
<li><p>가벼운 용량과 빠른 속도를 가지는 JDBC의 커넥션 풀 프레임워크</p>
</li>
<li><p>SpringBoot는 커넥션 풀 관리를 위해 HikariCP를 사용한다.</p>
<h1 id="hikaricp-동작방식">HikariCP 동작방식</h1>
<h2 id="유휴-스레드-존재">유휴 스레드 존재</h2>
<p><img src="https://velog.velcdn.com/images/seon___/post/dd090f3c-b54b-4d24-ab66-f5865d576d1f/image.png" alt=""></p>
</li>
</ul>
<pre><code>위 같이 Thread가 커넥션을 요청했을 때 유휴 커넥션이 존재한다면 해당 커넥션을 반환해준다.

## 유휴 스레드 부재
![](https://velog.velcdn.com/images/seon___/post/c2d043db-fd9c-4cbd-bbca-c7e4477379a7/image.png)

![](https://velog.velcdn.com/images/seon___/post/a871df29-7903-424e-baac-cc7d1a5338ae/image.png)



만약 유휴 커넥션이 존재하지 않는다면, HandOffQueue를 Polling 하면서 다른 Thread가 커넥션을 반납하기를 기다린다.

다른 Thread가 커넥션 풀에 커넥션을 반납하면 커넥션 풀은 HandOffQueue에 반납된 커넥션을 삽입하고 HandOffQueue를 Polling 하던 Thread는 커넥션을 획득하게 된다.

만약 커넥션 풀의 크기가 너무 작다면, 커넥션을 획득하기 위해 대기하고 있는 Thread가 많아지게 될 것이다. 이러한 문제는 커넥션 풀의 크기를 늘려주면 해결할 수 있다. 그렇다면 커넥션 풀의 크기는 어느 정도인 게 좋을까?</code></pre><h1 id="커넥션-풀의-크기와-성능">커넥션 풀의 크기와 성능</h1>
<h3 id="커넥션풀이-너무-크면">커넥션풀이 너무 크면</h3>
<ul>
<li><p>커넥션 사용 주체인 Thread의 개수 &lt; 커넥션 풀의 크기</p>
<p>  → 유휴 커넥션이 많아, 메모리의 낭비가 발생한다.</p>
</li>
</ul>
<h3 id="mysql-공식-레퍼런스-피셜">Mysql 공식 레퍼런스 피셜</h3>
<p> <strong>600여 명의 유저를 대응에 15~20개의 커넥션 풀만으로도 충분하다.</strong>
 MySQL은 최대 연결 수(== 커넥션 수)를 <strong>무제한</strong>으로 설정한 뒤 부하 테스트를 진행하면서 최적화된 값을 찾는 것을 추천한다.</p>
<h3 id="우아한-형제들-블로그-피셜">우아한 형제들 블로그 피셜</h3>
<ul>
<li>Tn = 전체 Thread의 개수</li>
<li>Cm = 하나의 Task에서 동시에 필요한 Connection 수</li>
<li>Pool size = 커넥션 풀의 크기</li>
</ul>
<p><img src="https://velog.velcdn.com/images/seon___/post/6fe419e0-14b3-40ba-a94d-5e8b79d88eff/image.png" alt=""></p>
<p>DB와 WAS의 Context Switching 역시 한계가 있기 때문에 <strong>Thread Pool의 크기</strong>는 <strong>Conncetion Pool의 크기를 결정하는데 매우 중요</strong>하다.</p>
<ul>
<li>→ <a href="https://wiki.postgresql.org/wiki/Number_Of_Database_Connections">https://wiki.postgresql.org/wiki/Number_Of_Database_Connections</a></li>
</ul>
<p><img src="https://velog.velcdn.com/images/seon___/post/cd31eec9-8ef6-4691-8f80-729dd8e86ecb/image.png" alt=""></p>
<ul>
<li>위 레퍼런스에서는 유휴 커넥션을 제외하고 계산하고서도 여분의 용량을 추가한 만큼의 커넥션을 마련해야한다고 한다.</li>
<li>위키에서는 나와있는 공식이 조정이 필요하다고 함</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[트랜잭션이 필요한 이유,  원칙을 보장하는 방식]]></title>
            <link>https://velog.io/@seon___/%ED%8A%B8%EB%9E%9C%EC%9E%AD%EC%85%98%EC%9D%B4-%ED%95%84%EC%9A%94%ED%95%9C-%EC%9D%B4%EC%9C%A0-%EC%9B%90%EC%B9%99%EC%9D%84-%EB%B3%B4%EC%9E%A5%ED%95%98%EB%8A%94-%EB%B0%A9%EC%8B%9D</link>
            <guid>https://velog.io/@seon___/%ED%8A%B8%EB%9E%9C%EC%9E%AD%EC%85%98%EC%9D%B4-%ED%95%84%EC%9A%94%ED%95%9C-%EC%9D%B4%EC%9C%A0-%EC%9B%90%EC%B9%99%EC%9D%84-%EB%B3%B4%EC%9E%A5%ED%95%98%EB%8A%94-%EB%B0%A9%EC%8B%9D</guid>
            <pubDate>Tue, 11 Feb 2025 02:06:15 GMT</pubDate>
            <description><![CDATA[<ul>
<li>[참고자료] : <a href="https://victorydntmd.tistory.com/129">https://victorydntmd.tistory.com/129</a></li>
</ul>
<h1 id="트랜잭션이란">트랜잭션이란?</h1>
<p> [1] : 작업 수행의 논리적 단위
 [2] : 원자성을 지켜야하는 동기화되는 하나의 논리블록(ex. 스크립트)의 단위</p>
<h1 id="트랜잭션-필요한-이유">트랜잭션 필요한 이유</h1>
<p>→ 트랜잭션은 DB 서버에 여러 개의 클라이언트가 동시에 엑세스 하거나 응용프로그램이 갱신을 처리하는 과정에서 중단될 수 있는 경우 등, 데이터 부정합을 방지하고자 할 때 사용합니다.</p>
<p>→ 부정합이 발생하지 않으려면, 프로세스를 병렬로 처리하지 않도록 하여 한 번에 하나의 프로세스만 처리하도록 하면 되는데, 이는 효율이 너무 떨어집니다.</p>
<p>→ 즉 , 병렬로 처리할 수 밖에 없는 현실적인 상황으로 인해 부정합을 방지하고자 트랜잭션을 사용한다.</p>
<p><strong>→ 트랜잭션에서 중요한 점 ⇒ 스케줄 관리!!!</strong></p>
<p>→ 스케줄을 잘못 짜면, <strong>데드락</strong>에 빠지게 되는데, 이와 연관된 것이 <strong>2PL</strong>이다.</p>
<h1 id="특성">특성</h1>
<ol>
<li>Atomicity (원자성)<ol>
<li>All or Nothing, 작업 단위를 일부분만 실행하지 않는다는 것 의미</li>
</ol>
</li>
<li>Consistency (일관성)<ol>
<li>트랜잭션이 성공완료되면, 일관적인 DB 상태를 유지</li>
<li>EX) 송금 전후 모두 금액의 데이터타입은 정수형이여야 한다.</li>
</ol>
</li>
<li>Isolatioin (격리성)<ol>
<li>트랜잭션끼리 서로 끼어들지 못한다.</li>
</ol>
</li>
<li>Durability (지속성)<ol>
<li>커밋하면 현재 상태는 영원히 보장된다.</li>
</ol>
</li>
</ol>
<h2 id="1-원자성-보장">1. 원자성 보장</h2>
<ul>
<li><p>[ 트랜잭션의 원자성 보장 방법 ]</p>
<p>  <strong>수행하고 있는 트랜잭션에 의해 변경된 내역을 유지하면서, 이전에 commit된 상태를 임시 영역에 따로 저장함</strong>으로써 보장</p>
<p>  → EX) 현재 수행하고 있는 트랜잭션에서 오류가 발생하면 현재 내역을 날려버리고 <strong>임시 영역</strong>에 저장했던 상태로 rollback 합니다.</p>
</li>
<li><p><strong>Rollback Segment</strong> : 이전 데이터들이 임시로 저장되는 영역</p>
</li>
<li><p>데이터베이스 테이블 : 현재 수행하고 있는 트랜잭션에 의해 새롭게 변경되는 내역</p>
</li>
<li><p>[ save point ]</p>
<p>  트랜잭션의 길이가 긴 경우, 오류가 나면 확실하게 진행된 부분도 다시 작업 수행해야함.</p>
<p>  → 확실한 부분에 대해서는 rollback이 되지 않도록 중간 저장 지점인 <strong>save point</strong>를 지정할 수 있습니다.</p>
<p>  <strong>save point를 지정하면 rollback 할 때 save point 이전은 확실하다 간주하고 그 이후부터 진행하게 됩니다.</strong></p>
</li>
</ul>
<h2 id="2-일관성-보장">2. 일관성 보장</h2>
<ul>
<li><p>[ 일관성이란? ]</p>
<p>  트랜잭션에서 일관성은 <strong>트랜잭션 수행 전, 후에 데이터 모델의 모든 제약 조건(기본키, 외래키, 도메인, 도메인 제약조건 등)을 만족하는 것을 통해 보장</strong></p>
</li>
<li><p>한 쪽의 테이블에만 데이터 변경사항이 이루어지면 안되는 것</p>
</li>
<li><p><strong>[ 트랜잭션의 일관성 보장 방법 ]</strong></p>
<p>  → 어떤 <strong>이벤트</strong>와 <strong>조건</strong>이 <strong>*<em>발생했을 때, *</em>트리거( Trigger )</strong> 를 통해 보장</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/seon___/post/ad1695f5-7328-4200-b888-cb79b2ba4a8a/image.png" alt=""></p>
<p>위 코드는, 트리거가 호출되면, 수행할 질의들을 트리거로 생성해서 작성한 코드.</p>
<p>after는 트리거가 실행되기 위한 event를 나타냅니다.</p>
<h2 id="3-격리성-보장">3. 격리성 보장</h2>
<h3 id="1-병행-처리--concurrent-processing-">1) 병행 처리 ( concurrent processing )</h3>
<p>CPU가 여러 프로세스를 처리하는 것처럼, 트랜잭션에 정해진 시간을 할당해서 작업을 하다가 부여된 시간이 끝나면 다른 트랜잭션을 실행하는 이런 방식으로 트랜잭션들을 조금씩 처리하는 것을 말합니다.</p>
<p>그런데 이렇게 되면 많은 트랜잭션들이 조금씩 처리되는 과정에서 공통된 데이터를 조작하게 되는데, 이 경우 데이터가 혼란스러워 질 수 있습니다.</p>
<pre><code>&lt;aside&gt;
❗ A 트랜잭션에서 x라는 데이터를 100으로 설정한 후 시간이 만료되어 B 트랜잭션으로 넘어갔다고 가정해보겠습니다. 
B 트랜잭션에서는 x 데이터에 -50 연산을 해서 저장을 했을때, 시간이 만료되어 다시 A 트랜잭션이 실행될 경우 x 데이터의 값은 50이 됩니다.

&lt;/aside&gt;</code></pre><p>이렇게 트랜잭션이 조금씩 수행될 때, 공통된 데이터가 다른 트랜잭션에 의해 방해되면 안됩니다.</p>
<p>이와 같이 트랜잭션의 간섭이 일어날 경우 <strong>갱신분실, 오손판독, 반복불가능, 팬텀문제</strong> 등 여러 문제점들이 발생합니다.</p>
<h3 id="2-트랜잭션의-격리성-보장-방법">2) <strong>트랜잭션의 격리성 보장 방법</strong></h3>
<ol>
<li><strong>Lock &amp; Excute unlock</strong><ul>
<li>즉, 데이터를 읽거나 쓸 때는 문을 잠궈서 다른 트랜잭션이 접근하지 못하도록 고립성을 보장하고, 수행을 마치면 unlock을 통해 데이터를 다른 트랜잭션이 접근할 수 있도록 허용하는 방식입니다.</li>
<li>트랜잭션에서는 데이터를 읽을 때, 여러 트랜잭션이 읽을 수는 있도록 허용하는 <strong>shared_lock</strong>을 합니다.</li>
<li>즉, shared_lock은 데이터 쓰기를 허용하지 않고 오직 읽기만 허용합니다.</li>
<li>또한 데이터를 쓸 때는 다른 트랜잭션이 읽을 수도 쓸 수도 없도록 하는 <strong>exclusive_lock</strong>을 사용합니다.</li>
<li>그리고 읽기, 쓰기 작업이 끝나면 <strong>unlock</strong>을 통해 다른 트랜잭션이 lock을 할 수 있도록 데이터에 대한 잠금(lock)을 풀어줍니다.</li>
</ul>
</li>
</ol>
<p>→ 잘못 사용하면 <strong>데드락(DEADLOCK)상태</strong>에 빠질 수 있다.</p>
<hr>
<ol>
<li><p><strong>2PL 프로토콜 ( 2 Phase Locking Protocol )</strong></p>
<p> <strong>: 데드락 방지를 위해 특정 규칙에 의해서 고립성을 보장해야한다는 프로토콜</strong></p>
<p> : 여러 트랜잭션이 공유하고 있는 데이터에 동시에 접근할 수 없도록 하기위한 목적을 가진 프로토콜</p>
<ul>
<li><p>이름 그대로 2가지 단계의 locking이 존재하는데, 1) <strong>growing phase,</strong> 2) <strong>shrinking phase</strong>입니다.</p>
</li>
<li><p>상승 단계란 read_lock , write_lock을 의미하고, 하강 단계란 unlock를 의미합니다.</p>
</li>
<li><p>2PL 프로토콜은 상승 단계와 하강 단계와 <strong>섞이면 안된다는 것</strong>을 의미합니다.</p>
</li>
<li><p>즉, lock과 unlock이 번갈아 수행되지 않고 <strong>lock이 쭉 수행된 후에 unlock이 쭉 수행되어야 한다</strong>는 것이 이 프로토콜입니다.</p>
<blockquote>
<p>정리하면 성<strong>능을 위해 병행처리를 해야하는데, 트랜잭션의 고립성을 보장하기 위해서는 2PL을 사용해야 한다는 것입니다.</strong> ( Serializable Schedule )</p>
</blockquote>
</li>
<li><p><strong>[ Locking 하는 두가지 방법 ]</strong></p>
<ul>
<li>보수적 Locking ( conservative locking )<ul>
<li>트랜잭션이 시작되면 모든 lock을 얻는 방식으로서, 데드락이 발생하지 않지만 병행성이 좋지 못함</li>
</ul>
</li>
<li><strong>엄격한 Locking ( strict locking )</strong><ul>
<li><strong>트랜잭션이 commit을 만날 때까지 lock을 갖고 있다가 commit을 만날때 unlock을 하는 방식</strong>으로 데드락이 발생하지만 병행성이 좋음</li>
<li>일반적으로 병행성이 좋은 strict 방식을 사용합니다.</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ol>
<h3 id="rdb는-일반적으로-잠금-스케줄러를-사용">RDB는 일반적으로 잠금 스케줄러를 사용</h3>
]]></description>
        </item>
        <item>
            <title><![CDATA[인덱싱하는 이유, 자료구조와 유형]]></title>
            <link>https://velog.io/@seon___/%EC%9D%B8%EB%8D%B1%EC%8B%B1%ED%95%98%EB%8A%94-%EC%9D%B4%EC%9C%A0-%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0%EC%99%80-%EC%9C%A0%ED%98%95</link>
            <guid>https://velog.io/@seon___/%EC%9D%B8%EB%8D%B1%EC%8B%B1%ED%95%98%EB%8A%94-%EC%9D%B4%EC%9C%A0-%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0%EC%99%80-%EC%9C%A0%ED%98%95</guid>
            <pubDate>Tue, 11 Feb 2025 02:01:40 GMT</pubDate>
            <description><![CDATA[<ul>
<li>[참고자료]: <a href="https://rebro.kr/167#:~:text=%EC%9D%B8%EB%8D%B1%EC%8A%A4(Index)%EB%8A%94%20%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B2%A0%EC%9D%B4%EC%8A%A4%EC%9D%98,%EC%A3%BC%EC%86%8C%EC%99%80%20%ED%95%A8%EA%BB%98%20%EC%A0%80%EC%9E%A5%EB%90%9C%EB%8B%A4">https://rebro.kr/167#:~:text=인덱스(Index)는 데이터베이스의,주소와 함께 저장된다</a>.</li>
<li>[읽어볼 것] :<a href="https://inpa.tistory.com/entry/MYSQL-%F0%9F%93%9A-%EC%9D%B8%EB%8D%B1%EC%8A%A4index-%ED%95%B5%EC%8B%AC-%EC%84%A4%EA%B3%84-%EC%82%AC%EC%9A%A9-%EB%AC%B8%EB%B2%95-%F0%9F%92%AF-%EC%B4%9D%EC%A0%95%EB%A6%AC">https://inpa.tistory.com/entry/MYSQL-📚-인덱스index-핵심-설계-사용-문법-💯-총정리</a></li>
</ul>
<hr>
<p>인덱스에 대해 얘기하기전에...</p>
<h2 id="페이지page란"><strong>페이지(Page)란?</strong></h2>
<p>책이 페이지로 구성되어 있는 것처럼 SQL 서버도 여러 Page로 구성되어 있으며 크기는 8KB입니다. SQL 서버의 가장 기본적인 단위로 실제로 SQL 서버에 데이터의 접근 시에는 Page 단위로 접근합니다. Page는 대부분 Data로 구성되어 있지만 일부 페이지는 인덱스(데이터 위치), 텍스트/이미지 등등으로도 구성되어 있습니다. 각 페이지는 96바이트의 헤더로 구성되어 있으며, 헤더는 페이지에 대한 시스템 정보를 저장합니다. 추가로 정리해보면 다음과 같습니다.</p>
<ul>
<li>데이터 파일을 구성하는 논리 단위</li>
<li>SQL Server의 기본 데이터 저장 단위 ( 8KB )</li>
<li>데이터를 쓸 때 행이 페이지에 기록됨</li>
<li>데이터를 읽을 때 페이지 내의 모든 행이 읽어짐</li>
<li>페이지 내의 행이 많을 수록 I/O 효율 증가</li>
<li>페이지 번호는 0~n 사이의 순차적인 번호가 존재</li>
</ul>
<p>데이터를 Insert하게 된다면 페이지에 들어가게 되고, 테이블에 쿼리를 날려 조회하는 것이 아니라 페이지에서 SELECT하는 것으로 생각하면 됩니다.</p>
<hr>
<h1 id="인덱스란">인덱스란?</h1>
<p>인덱스는 데이터베이스의 테이블에 대한 검색 속도를 향상시켜주는 자료구조이다. 데이터베이스와 마찬가지로 인덱스도 디스크 공간에 저장된다.</p>
<p>(DB크기의 10%정도의 추가 공간 필요)</p>
<p>테이블의 특정 칼럼에 인덱스를 생성하면, 해당 칼럼의 데이터를 정렬한 후 별도의 메모리 공간에 데이터의 물리적주소와 함께 저장된다.</p>
<p>인덱스는 책에서의 <strong>목차 혹은 색인</strong> 이라고 생각하면 된다.</p>
<p>그러므로,</p>
<p><strong>데이터 = 책의 내용</strong></p>
<p><strong>인덱스 = 책의 목차</strong></p>
<p><strong>물리적주소 = 책의 페이지 번호</strong></p>
<p>라고 생각할 수 있다.</p>
<p><img src="https://velog.velcdn.com/images/seon___/post/e3f150b5-b00c-42cd-bd65-434f03af74cc/image.png" alt=""></p>
<h1 id="인덱스의-장단점">인덱스의 장단점</h1>
<h2 id="장">장</h2>
<ul>
<li>테이블 검색 속도와 성능이 향상</li>
<li>인덱스에 의해 데이터들이 정렬된 형태를 갖는다<ul>
<li>where 문의 경우, 테이블전체를 조건과 비교해야하는 풀 테이블 스캔 작업</li>
<li>ORDER BY 나 MIN/MAX 같은 경우, 이미 정렬되어있는 상태여서 빠르게 수행가능</li>
</ul>
</li>
</ul>
<h2 id="단">단</h2>
<ol>
<li><strong>인덱스 관리하기 위한 추가작업이 필요</strong><ol>
<li><strong>INSERT : 새로운 데이터에 대한 인덱스 추가하는 작업 필요</strong></li>
<li><strong>DELETE : 삭제하는 데이터의 인덱스를 “사용하지 않음” 처리 작업 수행 이루어짐</strong></li>
<li><strong>UPDATE : 기존의 인덱스를 “사용하지 않음” 처리, 갱신된 데이터에 대한 인덱스 추가하는 작업 이루어짐</strong></li>
</ol>
</li>
<li><strong>추가 저장 공간이 필요</strong><ol>
<li>수정의 경우, <strong>데이터의 인덱스를 제거하는 게 아니라, “사용하지않음” 처리</strong>하고 남겨두기 때문에 <strong>실제 데이터에 비해 인덱스가 과도하게 커지는 문제점</strong>이 발생 할 수 있고, 별도의 메모리 공간에 저장되기 때문에 , <strong>추가저장공간이 많이 필요</strong>하게된다.</li>
</ol>
</li>
<li><em><strong>전체데이터의 10~15% 이상의 데이터</strong>를 처리 하거나 , 데이터의 형식(<strong>나이,성별과 같이 값의 range가 적은 컬럼인 경우</strong>)에 따라 오히려 성능이 낮아질 수 있다.</em></li>
</ol>
<h1 id="인덱스-사용하기-좋은-경우">인덱스 사용하기 좋은 경우</h1>
<ol>
<li><strong>규모가 큰 테이블</strong></li>
<li><strong>데이터의 range가 넓고, 중복이 적은 칼럼</strong></li>
<li><strong>삽입, 수정, 삭제 작업이 자주 발생하지 않는 칼럼</strong></li>
<li><strong>WHERE 나 ORDER BY, JOIN 등이 자주 사용되는 칼럼</strong></li>
<li><strong>데이터의 중복도 낮은 칼럼</strong></li>
</ol>
<h1 id="인덱스의-자료구조">인덱스의 자료구조</h1>
<ol>
<li><p><strong>해쉬테이블</strong></p>
<p> → 해시 테이블을 이용한다면 인덱스는 <strong>(key, value) = (컬럼의 값, 데이터의 위치)</strong>로 구현하는데, 해시 테이블은 실제로 인덱스에서 잘 사용되지 않는다.</p>
<p> 그 이유는, <strong>해시 테이블은 등호(=) 연산에 최적화되어있기 때문이다.</strong> 데이터베이스에선 부등호(&lt;, &gt;) 연산이 자주 사용되는데, 해시 테이블 내의 데이터들은 정렬되어 있지 않으므로 특정 기준보다 크거나 작은 값을 빠른 시간 내에 찾을 수가 없다.</p>
</li>
<li><p>B+Tree</p>
<p> →  <a href="https://www.notion.so/B-Tree-74e36a4dd26147819cecd238492daedb?pvs=21">B+Tree 자료구조</a></p>
<ul>
<li>기존의 B-Tree는 어느 한 데이터의 검색은 효율적이지만, 모든 데이터를 한 번 순회하는 데에는 트리의 모든 노드를 방문해야 하므로 비효율적이다. 이러한 B-Tree의 단점을 개선시킨 자료구조가 B+Tree이다.</li>
<li><strong>인덱스 칼럼은 부등호를 이용한 순차 검색연산이 자주 발생</strong>할 수 있는데, B+Tree의 LinkedList를 이용하면 순차검색을 효율적으로 할 수 있게 된다.</li>
</ul>
</li>
</ol>
<h1 id="인덱스의-종류">인덱스의 종류</h1>
<h3 id="클러스터형-인덱스-logn">클러스터형 인덱스 (logN)</h3>
<ul>
<li>데이터가 재정렬</li>
<li>보조 인덱스보다 검색 속도는 더 빠르다. (단, 입력/수정/삭제 는 더 느림.)</li>
<li>인덱싱 처리한 column이 수정될때마다(데이터 하나마다) 재정렬된다.</li>
<li>pk에 자동적용된다.</li>
</ul>
<h3 id="보조-인덱스-non-clustered-index-2logn">보조 인덱스 (non-clustered index) (2logN)</h3>
<ul>
<li><p>데이터 페이지는 그냥 둔 상태에서 별도의 페이지에서 인덱스를 구성
 → (자동정렬 되지 않음 EX.책의 색인)</p>
</li>
<li><p>클러스터형 인덱스가 더 빠른 이유? / <del>자료구조가 다른가..?</del></p>
<ul>
<li>클러스터는 데이터에 직접 접근 → 원본데이터가 정렬된다.</li>
<li>보조는 별도의 페이지로 접근</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[스레드풀] ExecutorService]]></title>
            <link>https://velog.io/@seon___/%EC%8A%A4%EB%A0%88%EB%93%9C%ED%92%80-ExecutorService</link>
            <guid>https://velog.io/@seon___/%EC%8A%A4%EB%A0%88%EB%93%9C%ED%92%80-ExecutorService</guid>
            <pubDate>Thu, 24 Oct 2024 08:00:45 GMT</pubDate>
            <description><![CDATA[<p>비동기스레드를 생성하는 CompletableFuture를 사용하기 위해,
스레드풀 인터페이스를 찾아보려함.</p>
<hr>
<p>CompletableFuture사용 시, 별다른 스레드풀을 명시하지 않으면,
ForkJoinPool를 사용한다고 한다.</p>
<h3 id="forkjoinpool-이란">ForkJoinPool 이란?</h3>
<blockquote>
<ul>
<li>Task를 fork를 통해서 Subtask로 나누고 하나의 스레드에서 모든 것을 처| 리하지 않고 sub로 나눈다.</li>
</ul>
</blockquote>
<ul>
<li>Thread pool에서 steal work 알고리즘을 이용해서 균등하게 처리해서</li>
<li>join을 통해 결과를 생성</li>
</ul>
<p>그림으로 보면 다음과 같음</p>
<p><img src="https://velog.velcdn.com/images/seon___/post/76bca6a4-60c4-4288-b710-b8f3dfb5e7ba/image.png" alt=""></p>
<hr>
<h2 id="다양한-스레드풀-환경설정들">다양한 스레드풀 환경설정들</h2>
<pre><code class="language-java">public class Executors {
    // 단일 쓰레드로 구성된 스레드 풀을 생성. 한번에 하나의 작업만 실행
    public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue&lt;Runnable&gt;(),
                                    threadFactory));
    }
    // 고정된 크기의 쓰레드풀을 생성
    public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue&lt;Runnable&gt;());
    }
      // 사용 가능한 쓰레드가 없다면 새로 생성해서 작업을 처리하고, 있다면 재사용. 쓰레드가 일정 시간 사용되지 않으면 회수
    public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue&lt;Runnable&gt;());
    }
    // 스케줄링 기능을 갖춘 고정 크기의 쓰레드 풀을 생성. 주기적이거나 지연이 발생하는 작업을 실행
    public static ScheduledExecutorService newScheduledThreadPool(
            int corePoolSize, ThreadFactory threadFactory) {
        return new ScheduledThreadPoolExecutor(corePoolSize, threadFactory);
    }
    // work steal 알고리즘을 사용하는 ForkJoinPool을 생성
    public static ExecutorService newWorkStealingPool(int parallelism) {
        return new ForkJoinPool
            (parallelism,
             ForkJoinPool.defaultForkJoinWorkerThreadFactory,
             null, true);
    }
}</code></pre>
<h2 id="스레드풀-환경설정요인-상세보기">스레드풀 환경설정요인 상세보기</h2>
<p><img src="https://velog.velcdn.com/images/seon___/post/07562e78-4a3e-4c73-88d7-efa218b76fec/image.png" alt=""></p>
<p>스레드풀을 어떻게 하면 적합하게 설정을 해줄 수 있는지가 궁금해서 스레드풀executor를 더 알아보고 싶었음.</p>
<p>ThreadPoolExecutor 라이브러리를 타고들어가면 자세한 설명이 있다.</p>
<ol>
<li>corePoolSize : 풀안에서 유지하는 스레드 개수 </li>
<li>maxiumPoolsize: 가능한 최대 스레드 개수</li>
<li>keepAliveTime : 코어보다 스레드수가 많을때, 작업대기시간. 해당 시간동안 놀게되면 종료됨.</li>
<li>unit (TimeUnit) : keepAliveTime의 단위. ex.Milliseconds.</li>
<li>workQueue (BlockingQueue) : 모든 스레드가 작업 중일때 task를 보관할 큐.</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[토스의 Gateway]]></title>
            <link>https://velog.io/@seon___/%ED%86%A0%EC%8A%A4%EC%9D%98-Gateway-iimdzskr</link>
            <guid>https://velog.io/@seon___/%ED%86%A0%EC%8A%A4%EC%9D%98-Gateway-iimdzskr</guid>
            <pubDate>Fri, 06 Sep 2024 06:41:43 GMT</pubDate>
            <description><![CDATA[<p>참고자료
[토스는 Gateway이렇게 씁니다] (<a href="https://youtube.com/watch?v=Zs3jVelp0L8&amp;t=235s">https://youtube.com/watch?v=Zs3jVelp0L8&amp;t=235s</a>)</p>
<h1 id="gateway-패턴-변천사">Gateway 패턴 변천사</h1>
<h3 id="1-monolitic-gateway방식">#1 Monolitic Gateway방식</h3>
<p><img src="https://velog.velcdn.com/images/seon___/post/16b2ef5d-b833-4699-82c9-cea1f87c460e/image.png" alt=""></p>
<p>다른 로직에서 같은 게이트웨이 사용
웹에서 필요한 로직과 앱에서 필요한 로직이 다르지만, 게이트웨이는 모두 가지고 있어야 포워딩이 된다.</p>
<p>이를 해결하기 위해, Backend For Frontend 패턴이 나옴</p>
<h3 id="2-bff-패턴-backend-for-frontend">#2 BFF 패턴 (Backend For Frontend)</h3>
<p><img src="https://velog.velcdn.com/images/seon___/post/3e382681-e389-4e0b-9abc-21ee19ec2420/image.png" alt=""></p>
<p>관심사의 분리</p>
<p>web용 App용 게이트웨이를 분리.</p>
<h3 id="3-ingressegress-패턴">#3 Ingress/Egress 패턴</h3>
<p>요청방향에 맞게 분리하는 패턴.</p>
<p>클러스터에 들어오는 요청 처리 : Ingress Gateway</p>
<p>클러스터에서 나가는 요청 처리 : Egress Gateway</p>
<p><img src="https://velog.velcdn.com/images/seon___/post/05c2722a-e4eb-4f41-b14b-eceaf5d8a5c1/image.png" alt=""></p>
<hr>
<h3 id="위-패턴들을-활용한-토스의-아키텍쳐">위 패턴들을 활용한 토스의 아키텍쳐</h3>
<p><img src="https://velog.velcdn.com/images/seon___/post/44a96b87-8b28-44ef-a011-090a41fef69b/image.png" alt=""></p>
<p>서비스 개발자는 Client목적에 맞는 GW를 사용하여 라우트를 추가해주고, 해당 라우트에 필요한 로직을 넣어 서비스 로의 요청을 완성한다.</p>
<p>mTLS : (보안)인증서 관련 요청</p>
<p>망분리 : 사내</p>
<p>SSR : 서버 사이드 렌더링 관련 요청</p>
<p>Egress GW 로 외부 요청 보냄</p>
<hr>
<h3 id="위-아키텍쳐-구현에-토스에서-사용한-스택">[위 아키텍쳐 구현에 토스에서 사용한 스택]</h3>
<p><strong>Spring cloud Gateway</strong> (Springwebflux, Reactor-Netty ) 사용</p>
<p><strong>Filter 개발</strong>에 Kotlin Coroutine사용</p>
<p>Istio의 Ingress/Egress, Envoy필터 사용</p>
<hr>
<h3 id="gateway-에서-사용되는-공통-로직의-종류">Gateway 에서 사용되는 공통 로직의 종류</h3>
<p>Request 처리</p>
<p>유저</p>
<p>보안</p>
<p>서비스 안정화</p>
<h1 id="1-request-처리">1. Request 처리</h1>
<p><img src="https://velog.velcdn.com/images/seon___/post/d818875f-226f-4f35-9663-20e6d0cb6429/image.png" alt=""></p>
<p>게이트웨이에서 처음으로 해줘야하는 일은 데이터 Sanitize이다.</p>
<p>Sanitize란? :클라이언트로부터 올바르지 않은 요청이 올 경우, 이를 지워주거나 올바른 값으로 바꿔주는 것.</p>
<p>(ex. 악의적인 요청이 와도 GW에서 이를 올바른 값으로 변경후 서비스로 넘긴다.)</p>
<p><img src="https://velog.velcdn.com/images/seon___/post/20044692-1429-4044-93d1-26b51147f8ef/image.png" alt=""></p>
<h3 id="1-trace-id-생성">#1 Trace ID 생성</h3>
<p>GW는 서비스의 진입점이라서, MSA내 트랜잭션을 구분할수있는 trace ID을 부여함.</p>
<p>이렇게 생성된 Trace id는 각자의 서비스에서 MDC 컨텍스트에 저장되고,</p>
<p>로그를 남길때 이를 같이 남긴다.</p>
<p>그림같이 트랜잭션별 로그 구분가능</p>
<h3 id="2-하나의-트랜잭션안에-여러-서비스에서-공통으로-필요한-정보가-있는-경우">#2 하나의 트랜잭션안에 여러 서비스에서 공통으로 필요한 정보가 있는 경우</h3>
<p><strong>[기존방식]</strong></p>
<p>모든 서비스가 공통 API 요청</p>
<p><img src="https://velog.velcdn.com/images/seon___/post/13f51568-75a4-4ecc-8414-5f38c4600389/image.png" alt=""></p>
<p><strong>[GW사용후]</strong></p>
<p>GW단에서 internal Header에 필요공통정보를 넣어서 전파한다.</p>
<h3 id="유저-정보">유저 정보</h3>
<p><strong>[기존방식]</strong></p>
<p>유저 정보가 필요할때마다 유저정보조회API사용</p>
<p><strong>[개선 후]</strong> </p>
<p><strong>&lt;넷플릭스의 Passport 구조 참고함&gt;</strong></p>
<p>유저 인증시, Passport라는 ID 토큰을 트랜잭션내로 전파함.</p>
<p>passport란?  사용자 기기 정보와 유저 정보를 담은 하나의 토큰이다.</p>
<p> <img src="https://velog.velcdn.com/images/seon___/post/1f04a1dc-edc6-44ca-bd4a-fe5ca8021931/image.png" alt=""></p>
<ul>
<li><p>인증 과정이 GW에 붙어있음</p>
</li>
<li><p>passport 토큰을 응답하면, 이를 Serialize해서 서비스에 전파한다.</p>
</li>
</ul>
<hr>
<h3 id="보안">보안</h3>
<h3 id="1-다양한-인증방식-사용">1. 다양한 인증방식 사용</h3>
<p>종단간 암호화를 통해 패킷 분석의 허들을 높여 안전하게 통신한다.</p>
<p>암호화가 애매한 SSR요청을 위해서 JWT인증방식도 사용한다.</p>
<p><img src="https://velog.velcdn.com/images/seon___/post/6c321d10-ddd1-484e-af0e-8ce26557e7f0/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/seon___/post/7c41b10c-0425-4b88-b658-8b2fa9c85a4f/image.png" alt=""></p>
<p>위 두 그림은 OAuth / JWT방식또한 인증할때 사용한다는 말.. 특별히 다른 점은 없다  </p>
<h3 id="2-위변조-여부-검증">2. 위변조 여부 검증</h3>
<p>각 요청이 실제로 위변조 되지않은 토스앱에서 만들어진 요청인지도 검증한다.</p>
<p><img src="https://velog.velcdn.com/images/seon___/post/1d3c62cf-df22-4275-99df-3accd30a5250/image.png" alt=""></p>
<p> 요청당 아주짧은유효기간을 가진 키값 + 토스앱에서만 알수있는 정보 </p>
<p>를 가지고 요청을 서명하고 이를 GW에 보낸다.</p>
<p>토큰 위변조 감지시, FDS(Fraud Detection System)를 통해 계정을 비활성화하여 사용자 보호함</p>
<p>FDS에 대한 추후 연구 필요</p>
<p>FDS는 유저 행위 분석 기반으로 다양한 룰베이스로 수상한 행동 감지한다.</p>
<p>감지하는 경우 GW로 정보보내, IPS로 차단. → 특정 유저 , 특정 디바이스가 특정 API를 이용하지 못하게 함</p>
<h3 id="3-인증서-mtls-인증">3. 인증서 mTLS 인증</h3>
<p><img src="https://velog.velcdn.com/images/seon___/post/66e046ca-f3bc-4d33-ba33-078494a4cdeb/image.png" alt=""></p>
<p> Istio 에서 제공하는 mTLS flow위에 레이어를 하나 얹어 사용함</p>
<p>그냥 써도 되지만 코드베이스인 경우에 Auditing, 카나리배포방식사용 등에서 이점이 있다함.</p>
<p><img src="https://velog.velcdn.com/images/seon___/post/1203458b-ca3a-4101-ba45-57bc2aa59812/image.png" alt=""></p>
<h3 id="4-oidc">4. OIDC</h3>
<p><img src="https://velog.velcdn.com/images/seon___/post/bc93eac8-d629-4b58-ab18-0cabd503d8d4/image.png" alt=""></p>
<h3 id="5-서킷브레이킹">5. 서킷브레이킹</h3>
<p><img src="https://velog.velcdn.com/images/seon___/post/00a44314-1a7b-440e-8464-9719969a6bc3/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[리액티브에 대해]]></title>
            <link>https://velog.io/@seon___/%EC%9E%91%EC%84%B1%EC%A4%91%EB%A6%AC%EC%95%A1%ED%8B%B0%EB%B8%8C%EC%97%90-%EB%8C%80%ED%95%B4</link>
            <guid>https://velog.io/@seon___/%EC%9E%91%EC%84%B1%EC%A4%91%EB%A6%AC%EC%95%A1%ED%8B%B0%EB%B8%8C%EC%97%90-%EB%8C%80%ED%95%B4</guid>
            <pubDate>Fri, 16 Aug 2024 06:22:30 GMT</pubDate>
            <description><![CDATA[<h1 id="리액티브-리액티브시스템-리액티브프로그래밍-리액티브스트림즈">리액티브 ,리액티브시스템, 리액티브프로그래밍, 리액티브스트림즈</h1>
<h2 id="1-리액티브란">1. 리액티브란?</h2>
<p>| 리액티브란? 즉각적으로 변화하는 데이터에 대해 반응하는 프로그래밍 모델.
-&gt; 이 개념은 비동기성과 반응성을 통해 더욱 효율적이고 유연한 애플리케이션을 구축하는 혁신적인 방법 .. 이라고 한다.</p>
<h2 id="2-리액티브-시스템">2. 리액티브 시스템</h2>
<p><img src="https://velog.velcdn.com/images/seon___/post/89a3a6b0-5d35-4cc8-a602-32e4f6a94ee0/image.png" alt=""></p>
<p>위는 리액티브 선언문에 나오는 그림이다.</p>
<hr>
<p><strong>리액티브는 4가지 설계원칙</strong>이 있는하는데
다음과 같다.</p>
<ol>
<li>Responsive (응답성)</li>
</ol>
<ul>
<li>가능한 한 즉각적으로 응답하는 것을 말합니다. 사용자의 입장에서 가장 중요한 항목이 되겠지요. 소프트웨어는 당연히 사용자가 필요로 할 때 빠르게 응답해야 합니다. 응답성은 Reactive Manifesto의 4가지 속성 중 가장 중요하고, 나머지 아래 3가지 요소는 응답성을 위하여 존재하는 하위 요소입니다.</li>
</ul>
<ol start="2">
<li>Resilient (탄력성)</li>
</ol>
<ul>
<li>시스템이 장애에 직면하더라도 응답성을 유지하는 것입니다. Fault Tolerence(장애 허용)와 밀접한 개념이기도 합니다. 부분적인 장애나 고장이 시스템 전체를 망가뜨리지 않습니다. 시스템 고장을 예외가 아닌 시스템 기능의 일부로 받아들입니다.</li>
</ul>
<ol start="3">
<li>Elastic (유연성)</li>
</ol>
<ul>
<li>시스템의 작업량이 변하더라도 응답성을 유지하는 것입니다. 리액티브 시스템은 트래픽에 따라 Scale Up과 Scala Down이 쉬워야 합니다. 리액티브 선언의 초기 버전에는 Scalable 이라는 말을 썼지만, 이것은 Scale Up에 해당하는 용어라, Scale Up과 Down을 동시에 표현하는 Elastic 이라는 용어로 바뀌었습니다.</li>
</ul>
<ol start="4">
<li>Message Driven (메시지 구동)</li>
</ol>
<ul>
<li>소프트웨어 내부에서 의사소통을 하는 방식이 메시지를 전달하는 방식으로 구성되어 있습니다. 소프트웨어를 구성하는 각 부분들은 비동기적으로 메시지를 주고받습니다. 메시지를 주고받을 때는 보내고 잊는(fire-and-forget) 방식을 이용합니다.</li>
</ul>
<h2 id="3-리액티브-프로그래밍">3. 리액티브 프로그래밍</h2>
<p>  In computing, reactive programming is a declarative programming paradigm concerned with data streams and the propagation of change.</p>
<p>변화의 전파와 데이터 흐름과 관련된 선언적 프로그래밍 패러다임이다.</p>
<hr>
<p>변화의 전파와 데이터 흐름 : 데이터가 변경 될 때마다 이벤트를 발생시켜서 데이터를 계속적으로 전달
선언적 프로그래밍 : 실행할 동작을 구체적으로 명시하는 명령형 프로그래밍과 달리 선언형 프로그래밍은 단순히 목표를 선언</p>
<hr>
<h3 id="리액티브-프로그래밍을-사용하는-이유">리액티브 프로그래밍을 사용하는 이유</h3>
<p><strong>비동기적인 이벤트 처리</strong>
리액티브 프로그래밍에서는 이벤트를 비동기적으로 처리하기 때문에, 이벤트가 발생하는 즉시 처리할 수 있습니다. 이는 일반적으로 스레드와 락에 의존하는 전통적인 동기적인 프로그래밍 방식보다 훨씬 효율적이며, 대규모 시스템에서 높은 성능을 보장합니다.</p>
<p><strong>데이터 스트림 처리</strong>
리액티브 프로그래밍에서는 데이터 스트림을 다룰 수 있습니다. 이러한 데이터 스트림은 무한하거나 큰 양일 수 있으며, 이벤트가 발생할 때마다 해당 이벤트를 처리하는 콜백 함수를 등록합니다. 이러한 방식은 대규모 데이터 처리에 적합합니다.</p>
<p><strong>반응형 시스템 구현</strong>
리액티브 프로그래밍은 반응형 시스템을 구현하는 데 적합합니다. 이는 시스템이 외부 요청에 신속하게 반응하고, 빠른 응답 시간을 제공할 수 있도록 하는 기능입니다.</p>
<hr>
<h3 id="옵저버-패턴">옵저버 패턴</h3>
<p>리액티브 프로그래밍은 옵저버 패턴에 많은 영감을 받았다고 합니다.
옵저버 패턴이란 GoF가 소개한 디자인 패턴 중 하나로 
관찰 대상이 되는 객체가 변경되면 대상 객체를 관찰하고 있는 옵저버(Observer)에게 변경사항을 <strong>통지(notify)</strong> 하는 디자인 패턴을 말합니다.
리액티브 프로그래밍은 옵저버 패턴의 서브젝트와 옵저버의 개념과 유사한 <strong>발행자와 구독자</strong>를 사용해 데이터를 통지하고 처리합니다. 데이터를 제공하는 측에서 데이터를 소비하는 측으로 통지하는 방식(ex.데이터가 있음을 알리는 방식-지속적으로 확인X)을 일반적으로 푸시 기반 (Push-Based)이라고 부릅니다.</p>
<hr>
<h3 id="리액티브-개념의-적용-예시">리액티브 개념의 적용 예시</h3>
<p><strong>Push 방식</strong> : 데이터의 변화가 발생했을 때 변경이 발행한 곳에서 데이터를 보내주는 방식</p>
<ul>
<li>RTC (Real Time Communication)</li>
<li>Socket</li>
<li>Push message 등</li>
</ul>
<p><strong>&lt;-&gt;</strong></p>
<p><strong>Pull 방식</strong> : 변경된 데이터가 있는지 요청을 보내 질의하고 변경된 데이터를 가져오는 방식</p>
<ul>
<li>클라이언트 요청 - 서버 응답 방식의 어플리케이션</li>
<li>Java와 같은 절차지향형 프로그래밍 언어 등</li>
<li>Long polling</li>
</ul>
<h2 id="4-리액티브-스트림즈">4. 리액티브 스트림즈</h2>
<p>[배경]
리액티브 프로그래밍을 구현한 라이브러리들이 정해진 표준없이 구현되기 시작했습니다. 이에 하나의 규칙을 정해서, 여러 리액티브 프로그래밍 구현체들이 상호 변환 가능하도록 만들자는 목소리가 나오기 시작했습니다.</p>
<p>그렇게 만들어진 규칙이 리액티브 스트림즈입니다.</p>
<p>[예시]
리액티브 스트림은 non-blocking(넌블럭킹), backPressure(역압)을 이용하여 리액티브 프로그래밍을 할 때 비동기 데이터 처리의 표준이 되는 스펙입니다.</p>
<p>대표적인 리액티브 스트림즈 표준을 따르는 구현체들은<strong>_ RxJava, Reactor, Akka _</strong> 등이 있습니다.</p>
<hr>
<h3 id="backpressure">backPressure</h3>
<p>백프레셔는 리액티브 스트림에서 발생하는 <strong>데이터 처리 속도 조절</strong>과 관련된 문제를 해결하기 위한 메커니즘입니다. </p>
<p>과부하 상태의 컴포넌트에서 치명적인 장애가 발생하거나 제어 없이 처리 중인 메시지를 유실해서는 안 됩니다. 
컴포넌트는 장애가 발생해선 안 되기 때문에 상위 컴포넌트에 자신이 과부하 상태라는 것을 알려 부하를 줄이도록 해야 합니다.</p>
<p><strong>데이터 생산자와 소비자 간의 처리 속도 차이로 인해 데이터 처리 과정에서 발생하는 문제를 방지하기 위해 사용됩니다.</strong></p>
<p>[백프레셔에 대한 비유]
현실세계의 화장실에서 우리는 물을 사용하기 위해 수도꼭지를 적정량만 틀어 사용합니다. 물이 적절하게 나와야 우리는 그 물들을 받아 처리(사용)할 수 있습니다. 물이 과도하게 나오면 우리의 처리량이 이를 받쳐주지 못하고 나머지 물은 모두 유실될 것입니다. 소프트웨어 세계에서는 이는 곧 장애입니다. 백프레셔는 이런 수도꼭지같은 역할을 수행합니다.</p>
<p><strong>백프레셔는 주로 pull 방식을 채택합니다.</strong> 즉, 소비자가 데이터를 필요로 할 때마다 데이터를 요청하여 가져오는 방식입니다. 이를 통해 소비자가 처리할 수 있는 만큼의 데이터만 가져오면서 문제를 방지할 수 있습니다.</p>
<hr>
<h3 id="비동기데이터흐름에는-push방식을-사용하지만-수송신-데이-터-처리속도조절에는-pull방식을-사용한다">비동기데이터흐름에는 push방식을 사용하지만, 수송신 데이 터 처리속도조절에는 pull방식을 사용한다.</h3>
<p>🙋🏻 위에서 리액티브 프로그래밍은 Push 방식이라고 하지 않았나요?
리액티브 스트림은 push 방식을 따릅니다. 즉, 데이터 생산자가 데이터를 생성하고 변경되는 즉시 데이터를 소비자에게 푸시(push)하여 전달하는 방식입니다.</p>
<p>리액티브 프로그래밍과 백프레셔는 서로 다른 측면에서 동작하며, 리액티브 스트림은 비동기 데이터 흐름을 기술하고, <strong>백프레셔는 송신자와 수신자 사이의 데이터 처리 속도 조절에 초점을 둡니다.</strong></p>
<hr>
<h3 id="백프레셔가-없으면-발생하는-일">백프레셔가 없으면 발생하는 일</h3>
<p>Subscriber가 처리하는 속도보다 Publisher가 발행하는 속도가 빠른경우, 대기 중인 데이터가 지속적으로 쌓이면서 오버플로가 발생하거나 최악의 경우에는 시스템이 다운되는 사태가 발생할 수 있습니다.</p>
<p>이러한 문제를 해결하기 위해 백프레셔가 필요합니다.</p>
<p><img src="https://velog.velcdn.com/images/seon___/post/625dbbcf-ec29-46a4-b1f2-c034c76291ad/image.png" alt=""></p>
<p>|
 예상. publisher가 subscriber의 처리완료여부를 체크 + 완료된 경우,
     새로운 처리를 발생시킴.</p>
<hr>
<h3 id="리액티브-스트림즈의-인터페이스들">리액티브 스트림즈의 인터페이스들</h3>
<ul>
<li>Publisher : 데이터를 생성하고 통지</li>
<li>Subscriber : 통지된 데이터를 전달받아서 처리</li>
<li>Subscription : 전달받을 데이터의 갯수를 요청하고 구독을 해지</li>
<li>Processor : Publisher와 Subscriber의 기능이 모두 있음</li>
</ul>
<p><img src="https://velog.velcdn.com/images/seon___/post/c8856511-c4c7-4fa8-9acb-d6235fb3cd4d/image.png" alt=""></p>
<hr>
<h3 id="리액티브-스트림즈-컴포넌트">리액티브 스트림즈 컴포넌트</h3>
<p>리액티브 스트림즈는 4개의 인터페이스인 <strong>Publisher(발행자), Subscriber(구독자), Subscription(구독), Processor(프로세서)</strong>로 요약이 가능합니다.</p>
<p>발행자(Publisher)는 데이터를 생성하고 통지(발행, 게시, 방출)합니다.</p>
<p>구독자(Subscriber)는 Subscription를 통해 Publisher에게 자신이 처리할 수 있는 만큼의 데이터를 요청하고 처리합니다.</p>
<p>Subscription은 Publisher에 요청할 데이터의 개수를 지정하고 데이터의 구독을 취소하는 역할을 합니다.</p>
<p>Processor 인터페이스는 Subscriber, Publisher 인터페이스를 결합한 것라고 보면 됩니다. 즉 Subscriber로서 다른 Publisher를 구독할 수 있고, Publisher로서 다른 Subscriber가 구독할 수 있습니다.</p>
<p>이때 발행자가 제공할 수 있는 데이터의 양은 무한(unbounded) 하고 오퍼레이션에 따라 순차적(sequential) 처리를 보장합니다.</p>
<hr>
<h1 id="reactor란">Reactor란?</h1>
<p>스프링 프레임워크는 자바를 기반으로 할 경우 리액티브 스트림즈 구현체인 Reactor를 사용</p>
<hr>
<h1 id="rxjava">RxJava</h1>
]]></description>
        </item>
        <item>
            <title><![CDATA[Sync/Async vs Block/Non-Block]]></title>
            <link>https://velog.io/@seon___/SyncAsync-vs-BlockNon-Block</link>
            <guid>https://velog.io/@seon___/SyncAsync-vs-BlockNon-Block</guid>
            <pubDate>Fri, 16 Aug 2024 02:24:01 GMT</pubDate>
            <description><![CDATA[<h3 id="block-vs-non-block--제어권에-초점">Block vs Non-Block (= 제어권에 초점)</h3>
<ul>
<li><p><strong>Block</strong></p>
<p>  호출된 함수가 자신이 할 일을 모두 마칠 때까지 제어권을 계속 가지고서 호출한 함수에게 바로 제어권을 리턴하지않는다.
  (호출된 함수가 수행을 마칠동안 블록된다.)</p>
</li>
<li><p><strong>Non-Block</strong></p>
</li>
</ul>
<pre><code>호출된 함수가 자신이 할 일을 마치지 않았더라도 바로 제어권을 리턴하여 호출한 함수가 다른일을 진행할 수 있도록한다.
(수행을 마치든 아니든 블록되지 않는다.)</code></pre><p>| 정리해보면서 블로킹/논블로킹은 <strong>제어권을 리턴하느냐</strong>와 관련있다고 느낌!</p>
<h3 id="sync-vs-async--동기-vs-비동기--작업의-완료에-초점">Sync vs Async ( 동기 vs 비동기) (= 작업의 완료에 초점)</h3>
<ul>
<li><strong>Synchronous</strong>
Synchronous : 동시적인 
즉, 호출와 종료의 시점이 동시이다.
  <strong>[특징]</strong><pre><code>1. 호출된 함수의 수행결과 및 종료를 
호출된 함수와 호출한 함수도 함께 신경쓴다.  
→ 이말은, Callback개념이 없다. / 폴링으로 계속 완료 확인을 해줘야한다.</code></pre></li>
</ul>
<ul>
<li><strong>Asynchronous</strong>
호출과 종료의 시점이 동시가 아니어도 됨.
즉, 함수종료시점과 무관하게 호출이 가능.
  <strong>[특징]</strong><ol>
<li>호출된 함수의 수행결과 및 종료를 호출된 함수에서 알린다.
→ 완료되면 Callback수행해서 완료를 알린다.</li>
</ol>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/seon___/post/92bdc7dc-5169-4d04-b0c8-528b9caf241b/image.png" alt=""></p>
<h3 id="관심사의-차이">관심사의 차이</h3>
<p>두 가지 개념의 차이는 관심사 측 어디에 초점을 두느냐의 차이.</p>
<p><strong>동기(Synchronous)와 비동기(Asynchronous)는 작업의 완료에 초점을 두고 있다.</strong></p>
<p>하나의 쓰레드가 다른 쓰레드의 작업 종료일 경우에 작업 시작하면 동기
하나의 쓰레드가 작업이 완료 되던지 말던지 신경쓰지 않고 다른 쓰레드에서 작업 시작을 할 수 있으면 비동기</p>
<p><strong>반면에 블로킹(Blocking)과 논블로킹(NonBlocking)은 호출되는 제어권 리턴되는 시점에 초점을 두고 있다.</strong></p>
<p>호출된 함수가 바로 리턴하지 않고, 제어권을 가지고 있으면서 해당 함수가 종료될 때 제어권을 넘긴다면 블로킹
호출된 함수가 완료되지 않아도 제어권을 바로 호출한 함수에게 넘긴다면 논블로킹</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[행위패턴]커맨드패턴-자바Runnable,웹onClick()]]></title>
            <link>https://velog.io/@seon___/%ED%96%89%EC%9C%84%ED%8C%A8%ED%84%B4%EC%BB%A4%EB%A7%A8%EB%93%9C%ED%8C%A8%ED%84%B4</link>
            <guid>https://velog.io/@seon___/%ED%96%89%EC%9C%84%ED%8C%A8%ED%84%B4%EC%BB%A4%EB%A7%A8%EB%93%9C%ED%8C%A8%ED%84%B4</guid>
            <pubDate>Tue, 13 Aug 2024 00:34:26 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/seon___/post/bd9c0624-8d39-4c6d-b2d5-bc9f5f42fca8/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/seon___/post/036de74b-c046-4f8f-a1c9-9f66d1395de3/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/seon___/post/f6d85e74-6bd1-4b45-842f-3580df4752ac/image.png" alt=""></p>
<h1 id="패턴-코드">패턴 코드</h1>
<pre><code class="language-java">// 기초 커맨드 클래스는 모든 구상 커맨드에 대한 공통 인터페이스를 정의합니다.
abstract class Command is
    protected field app: Application
    protected field editor: Editor
    protected field backup: text

    constructor Command(app: Application, editor: Editor) is
        this.app = app
        this.editor = editor

    // 편집기의 상태에 대한 백업을 만드세요.
    method saveBackup() is
        backup = editor.text

    // 편집기의 상태를 복원하세요.
    method undo() is
        editor.text = backup

    // 실행 메서드는 모든 구상 커맨드들이 자체 구현을 제공하도록 강제하기 위해
    // 추상으로 선언됩니다. 이 메서드는 커맨드가 편집기의 상태를 변경하는지에 따라
    // 진실 또는 거짓을 반환해야 합니다.
    abstract method execute()


// 구상 커맨드들은 여기에 배치됩니다.
class CopyCommand extends Command is
    // 복사 커맨드는 편집기의 상태를 변경하지 않으므로 기록에 저장되지 않습니다.
    method execute() is
        app.clipboard = editor.getSelection()
        return false

class CutCommand extends Command is
    // cut 커맨드는 편집기의 상태를 변경하므로 기록에 반드시 저장되어야 하며,
    // 메서드가 true를 반환하는 한 저장됩니다.
    method execute() is
        saveBackup()
        app.clipboard = editor.getSelection()
        editor.deleteSelection()
        return true

class PasteCommand extends Command is
    method execute() is
        saveBackup()
        editor.replaceSelection(app.clipboard)
        return true

// 실행취소 작업도 커맨드입니다.
class UndoCommand extends Command is
    method execute() is
        app.undo()
        return false


// 글로벌 커맨드 기록도 스택일 뿐입니다.
class CommandHistory is
    private field history: array of Command

    // 후입 …
    method push(c: Command) is
        // 커맨드를 기록 배열의 끝으로 푸시하세요.

    // … 선출
    method pop():Command is
        // 기록에서 가장 최근 명령을 가져오세요.


// 편집기 클래스에는 실제 텍스트 편집 기능이 있습니다. 이는 수신기의 역할을
// 합니다. 모든 커맨드들은 결국 편집기의 메서드들에 실행을 위임합니다.
class Editor is
    field text: string

    method getSelection() is
        // 선택된 텍스트를 반환하세요.

    method deleteSelection() is
        // 선택된 텍스트를 삭제하세요.

    method replaceSelection(text) is
        // 현재 위치에 클립보드의 내용을 삽입하세요.


// 앱 클래스는 객체 관계들을 설정하며 발신자 역할을 합니다. 이것은 무언가를
// 수행해야 할 때 커맨드 객체를 만들고 실행합니다.
class Application is
    field clipboard: string
    field editors: array of Editors
    field activeEditor: Editor
    field history: CommandHistory

    // 사용자 인터페이스 객체들에 커맨드들을 할당하는 코드는 다음과 같을 수
    // 있습니다.
    method createUI() is
        // …
        copy = function() { executeCommand(
            new CopyCommand(this, activeEditor)) }
        copyButton.setCommand(copy)
        shortcuts.onKeyPress(&quot;Ctrl+C&quot;, copy)

        cut = function() { executeCommand(
            new CutCommand(this, activeEditor)) }
        cutButton.setCommand(cut)
        shortcuts.onKeyPress(&quot;Ctrl+X&quot;, cut)

        paste = function() { executeCommand(
            new PasteCommand(this, activeEditor)) }
        pasteButton.setCommand(paste)
        shortcuts.onKeyPress(&quot;Ctrl+V&quot;, paste)

        undo = function() { executeCommand(
            new UndoCommand(this, activeEditor)) }
        undoButton.setCommand(undo)
        shortcuts.onKeyPress(&quot;Ctrl+Z&quot;, undo)

    // 커맨드를 실행하여 기록에 추가해야 하는지 확인하세요.
    method executeCommand(command) is
        if (command.execute())
            history.push(command)

    // 기록에서 가장 최근의 커맨드를 가져와서 그의 실행 취소 메서드를 실행하세요.
    // 참고로 우리는 이 커맨드의 클래스를 알지 못한다는 사실에 유념하세요.
    // 하지만 몰라도 상관없는데, 그 이유는 커맨드가 자신의 작업을 실행 취소하는
    // 법을 알기 때문입니다.
    method undo() is
        command = history.pop()
        if (command != null)
            command.undo()</code></pre>
<h1 id="실제-사례">실제 사례</h1>
<ul>
<li><strong>스프링의 <code>Command</code></strong></li>
</ul>
<p>스프링의 <code>Command</code>는 컨트롤러의 요청을 처리하는 역할을 합니다. <code>Command</code> 인터페이스를 구현한 클래스는 다양한 요청을 처리할 수 있습니다. 예를 들어, <code>SaveUserCommand</code> 클래스는 사용자를 저장하는 요청을 처리하고, <code>DeleteUserCommand</code> 클래스는 사용자를 삭제하는 요청을 처리합니다.</p>
<p><code>Command</code>는 명령 패턴을 사용하여 구현되었습니다. <code>Command</code> 인터페이스는 요청을 처리하는 알고리즘을 정의하는 추상 메서드 <code>execute()</code>를 제공합니다. 각 <code>Command</code> 구현체는 <code>execute()</code> 메서드를 구현하여 특정 요청을 처리하는 알고리즘을 제공합니다.</p>
<ul>
<li><strong>자바의 <code>Runnable</code></strong></li>
</ul>
<p>자바의 <code>Runnable</code> 인터페이스는 스레드를 실행하는 역할을 합니다. <code>Runnable</code> 인터페이스를 구현한 클래스는 스레드에서 실행할 작업을 정의할 수 있습니다. 예를 들어, <code>PrintMessageRunnable</code> 클래스는 콘솔에 메시지를 출력하는 작업을 정의합니다.</p>
<p><code>Runnable</code>은 명령 패턴을 사용하여 구현되었습니다. <code>Runnable</code> 인터페이스는 스레드에서 실행할 작업을 정의하는 추상 메서드 <code>run()</code>를 제공합니다. 각 <code>Runnable</code> 구현체는 <code>run()</code> 메서드를 구현하여 스레드에서 실행할 작업을 정의합니다.</p>
<ul>
<li><strong>웹 브라우저의 <code>Button</code></strong></li>
</ul>
<p>웹 브라우저의 <code>Button</code>은 사용자의 클릭을 처리하는 역할을 합니다. <code>Button</code>은 클릭 이벤트를 발생시킬 때, <code>Command</code> 객체를 전달할 수 있습니다. <code>Command</code> 객체는 클릭 이벤트를 처리하는 역할을 합니다.</p>
<p>웹 브라우저의 <code>Button</code>은 명령 패턴을 사용하여 구현되었습니다. <code>Command</code> 객체는 클릭 이벤트를 처리하는 알고리즘을 정의합니다.</p>
<p>명령 패턴은 다음과 같은 장점이 있습니다.</p>
<ul>
<li><strong>요청을 일관되게 처리할 수 있다.</strong></li>
<li><strong>요청을 전달하고 처리하는 방식을 추상화할 수 있다.</strong></li>
<li><strong>코드의 재사용성을 높일 수 있다.</strong></li>
</ul>
<p>명령 패턴은 다양한 프레임워크에서 적용되어, 애플리케이션의 개발과 유지보수를 보다 쉽고 효율적으로 만들어 줍니다.</p>
<p>다음은 명령 패턴이 적용된 프레임워크의 서비스의 예입니다.</p>
<ul>
<li><strong>스프링의 <code>CommandController</code></strong></li>
</ul>
<p>스프링의 <code>CommandController</code>는 <code>Command</code> 객체를 사용하여 요청을 처리하는 컨트롤러입니다. <code>CommandController</code>는 <code>Command</code> 객체의 <code>execute()</code> 메서드를 호출하여 요청을 처리합니다.</p>
<ul>
<li><strong>자바의 <code>ExecutorService</code></strong></li>
</ul>
<p>자바의 <code>ExecutorService</code>는 스레드를 실행하는 서비스입니다. <code>ExecutorService</code>는 <code>Runnable</code> 객체를 사용하여 스레드를 실행합니다.</p>
<ul>
<li><strong>웹 브라우저의 <code>onClick()</code> 이벤트</strong></li>
</ul>
<p>웹 브라우저의 <code>Button</code>은 <code>onClick()</code> 이벤트를 발생시킬 수 있습니다. <code>onClick()</code> 이벤트는 <code>Button</code>이 클릭되었을 때 발생합니다. <code>onClick()</code> 이벤트의 핸들러는 <code>Command</code> 객체를 전달받을 수 있습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[행위패턴]스트레티지패턴 - 자바Comparator, 스프링Logback]]></title>
            <link>https://velog.io/@seon___/%ED%96%89%EC%9C%84%ED%8C%A8%ED%84%B4%EC%8A%A4%ED%8A%B8%EB%A0%88%ED%8B%B0%EC%A7%80%ED%8C%A8%ED%84%B4-%EC%9E%90%EB%B0%94Comparator-%EC%8A%A4%ED%94%84%EB%A7%81Logback</link>
            <guid>https://velog.io/@seon___/%ED%96%89%EC%9C%84%ED%8C%A8%ED%84%B4%EC%8A%A4%ED%8A%B8%EB%A0%88%ED%8B%B0%EC%A7%80%ED%8C%A8%ED%84%B4-%EC%9E%90%EB%B0%94Comparator-%EC%8A%A4%ED%94%84%EB%A7%81Logback</guid>
            <pubDate>Tue, 13 Aug 2024 00:33:44 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/seon___/post/d4a5c444-5ab9-4894-a88a-739e878e3ca4/image.png" alt=""></p>
<ul>
<li><p>필드로 부모스트레지를 갖는다.</p>
</li>
<li><p>세터로 받는 메소드가있다.</p>
</li>
<li><p>행위메소드에서 스트레지클래스에 위임한다.</p>
</li>
</ul>
<h1 id="실제-사례">실제 사례</h1>
<p>전략 패턴은 알고리즘을 객체로 분리하여 구현하는 디자인 패턴입니다. 이를 통해 애플리케이션의 핵심 기능과 알고리즘을 분리하여, 알고리즘을 변경하거나 확장하기 쉽도록 합니다.</p>
<p>전략 패턴은 다양한 프레임워크에서 적용되고 있습니다. 대표적인 예로는 다음과 같은 것들이 있습니다.</p>
<ul>
<li><strong>스프링의 <code>MessageConverter</code></strong></li>
</ul>
<p>스프링의 <code>MessageConverter</code>는 HTTP 요청/응답의 메시지 바디를 변환하는 역할을 합니다. <code>MessageConverter</code> 인터페이스를 구현한 클래스는 다양한 메시지 포맷을 지원합니다. 예를 들어, <code>Jackson2HttpMessageConverter</code> 클래스는 JSON 포맷을 지원하고, <code>XmlHttpMessageConverter</code> 클래스는 XML 포맷을 지원합니다.</p>
<p><code>MessageConverter</code>는 전략 패턴을 사용하여 구현되었습니다. <code>MessageConverter</code> 인터페이스는 알고리즘을 정의하는 추상 메서드 <code>convert()</code>를 제공합니다. 각 <code>MessageConverter</code> 구현체는 <code>convert()</code> 메서드를 구현하여 특정 메시지 포맷을 변환하는 알고리즘을 제공합니다.</p>
<ul>
<li><strong>스프링의 <code>Logback</code></strong></li>
</ul>
<p>스프링의 <code>Logback</code>은 로그를 기록하는 프레임워크입니다. <code>Logback</code>은 다양한 로그 기록 방식을 지원합니다. 예를 들어, <code>ConsoleAppender</code> 클래스는 콘솔에 로그를 기록하고, <code>FileAppender</code> 클래스는 파일에 로그를 기록합니다.</p>
<p><code>Logback</code>은 전략 패턴을 사용하여 구현되었습니다. <code>Appender</code> 인터페이스는 알고리즘을 정의하는 추상 메서드 <code>append()</code>를 제공합니다. 각 <code>Appender</code> 구현체는 <code>append()</code> 메서드를 구현하여 특정 로그 기록 방식을 구현합니다.</p>
<ul>
<li><strong>자바의 <code>Comparator</code></strong></li>
</ul>
<p>자바의 <code>Comparator</code> 인터페이스는 객체를 비교하는 알고리즘을 제공합니다. <code>Comparator</code> 인터페이스를 구현한 클래스는 다양한 기준으로 객체를 비교할 수 있습니다. 예를 들어, <code>NaturalOrderComparator</code> 클래스는 객체의 문자열 표현을 기준으로 비교합니다.</p>
<p><code>Comparator</code>은 전략 패턴을 사용하여 구현되었습니다. <code>Comparator</code> 인터페이스는 알고리즘을 정의하는 추상 메서드 <code>compare()</code>를 제공합니다. 각 <code>Comparator</code> 구현체는 <code>compare()</code> 메서드를 구현하여 특정 기준으로 객체를 비교하는 알고리즘을 제공합니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[구조패턴]프록시패턴-스프링]]></title>
            <link>https://velog.io/@seon___/%EA%B5%AC%EC%A1%B0%ED%8C%A8%ED%84%B4%ED%94%84%EB%A1%9D%EC%8B%9C%ED%8C%A8%ED%84%B4</link>
            <guid>https://velog.io/@seon___/%EA%B5%AC%EC%A1%B0%ED%8C%A8%ED%84%B4%ED%94%84%EB%A1%9D%EC%8B%9C%ED%8C%A8%ED%84%B4</guid>
            <pubDate>Tue, 13 Aug 2024 00:28:06 GMT</pubDate>
            <description><![CDATA[<p><strong>프록시</strong>는 다른 객체에 대한 대체 또는 자리표시자를 제공할 수 있는 구조 디자인 패턴입니다. 프록시는 원래 객체에 대한 접근을 제어하므로, 당신의 요청이 원래 객체에 전달되기 전 또는 후에 무언가를 수행할 수 있도록 한다.</p>
<p><img src="https://velog.velcdn.com/images/seon___/post/0d8556e2-543e-4446-93be-7c590290d5c9/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/seon___/post/3ca719df-b8aa-4a68-97b6-966e664ccec3/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/seon___/post/d478a0e0-42c3-498e-951b-c57cee9a5889/image.png" alt=""></p>
<p>프록시 클래스는 원래 다운로더와 같은 인터페이스를 구현하고 이 다운로더에 모든 작업을 위임하나, 앱이 같은 비디오를 두 번 이상 요청하면 이미 다운로드한 파일을 추적한 후 캐시 된 결과를 반환한다.</p>
<h3 id="실제사례">실제사례</h3>
<p>제일 유명한 스프링AOP!</p>
]]></description>
        </item>
    </channel>
</rss>