<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>프로그래밍 활용기</title>
        <link>https://velog.io/</link>
        <description></description>
        <lastBuildDate>Thu, 30 Apr 2026 07:15:46 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>프로그래밍 활용기</title>
            <url>https://velog.velcdn.com/images/qkq_butler/profile/ab3c4de7-9348-4651-bbc9-266a920f4bb1/image.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. 프로그래밍 활용기. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/qkq_butler" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[Nginx 는 무엇인가]]></title>
            <link>https://velog.io/@qkq_butler/Nginx-%EB%8A%94-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80</link>
            <guid>https://velog.io/@qkq_butler/Nginx-%EB%8A%94-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80</guid>
            <pubDate>Thu, 30 Apr 2026 07:15:46 GMT</pubDate>
            <description><![CDATA[<h2 id="nginx-란-무엇인가">Nginx 란 무엇인가?</h2>
<p><img src="https://velog.velcdn.com/images/qkq_butler/post/271a390c-a073-4619-9e16-893199fb42ec/image.png" alt=""></p>
<p>Reverse Proxy, Load Balancer, HTTP 캐시 서버 등으로 다양한 네트워크 역할을 수행하는 소프트웨어다!</p>
<p>백엔드 개발에서는 특히, 클라이언트와 Spring Boot 사이 중간 계층 역할로 사용된다</p>
<h2 id="reverse-proxy-란">Reverse Proxy 란?</h2>
<p>클라이언트 요청을 받아 실제 백엔드 서버로 대신 전달하는 서버다!</p>
<p>Client → Nginx → Spring Boot 구조</p>
<h3 id="reverse-proxy를-사용하는-이유">Reverse Proxy를 사용하는 이유</h3>
<ol>
<li>백엔드 서버의 직접 노출을 방지하고, 포트를 숨긴다 (ex. 8080 → 80)</li>
<li>여러 서버로 요청 분산이 가능하다 (로드밸런싱)</li>
<li>정적 파일 처리와 캐싱 가능</li>
<li>HTTPS 설정 간소화 가능</li>
</ol>
<h2 id="nginx-동작-방식">Nginx 동작 방식</h2>
<p>Nginx는 요청이 들어오면 다음과 같은 순서로 처리한다.</p>
<ol>
<li>클라이언트 요청 수신 (80/443 포트)</li>
<li>요청 URL 분석</li>
<li>설정 파일 (nginx.conf)에 따라 처리 방식을 결정</li>
<li>필요 시 백엔드 서버로 전달한다 (proxy_pass)</li>
</ol>
<h2 id="nginx-사용-시-자주-발생하는-문제">Nginx 사용 시 자주 발생하는 문제</h2>
<ol>
<li>502 Bad Gateway</li>
</ol>
<p>: 백엔드 서버가 죽었거나, 포트가 불일치 되는 등의 경우다. </p>
<ol>
<li>404 / 403</li>
</ol>
<p>: location 설정 or root 경로 문제 등의 경우다.</p>
<ol>
<li>정적 파일 안불러와짐</li>
</ol>
<p>: 경로 설정에 오류가 있거나, static 파일 위치의 문제</p>
<ol>
<li>설정 적용 안됨</li>
</ol>
<pre><code class="language-java">sudo nginx -s reload</code></pre>
<p>위 명령어를 실행하지 않으면 설정 반영이 안된다!!</p>
<h2 id="nginx-주요-파일">Nginx 주요 파일</h2>
<ul>
<li>/etc/nginx/nginx.conf → 메인 설정</li>
<li>/etc/nginx/sites-available/ → 설정 파일</li>
<li>/etc/nginx/sites-enabled/ → 활성화된 설정</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Kubernetes 가 무엇인가]]></title>
            <link>https://velog.io/@qkq_butler/Kubernetes-%EA%B0%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80</link>
            <guid>https://velog.io/@qkq_butler/Kubernetes-%EA%B0%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80</guid>
            <pubDate>Thu, 30 Apr 2026 06:35:40 GMT</pubDate>
            <description><![CDATA[<h2 id="k8s란-kubernetes">K8s란? (Kubernetes)</h2>
<p><img src="https://velog.velcdn.com/images/qkq_butler/post/2d00576f-631d-4c65-87fe-71c722a8ed9b/image.png" alt=""></p>
<p>컨테이너화된 애플리케이션을 자동으로 배포, 확장, 관리해주는 오픈소스 플랫폼이다!</p>
<p>즉, Docker 컨데이너를 대규모로 자동 관리해주는 시스템이라 생각하자</p>
<h2 id="왜-사용하는가">왜 사용하는가?</h2>
<p>K8s를 통해서는</p>
<ul>
<li>자동 배포, 자동 확장, 자동 복구, 로드 밸런싱이 가능해진다.</li>
<li>기존에는 서버마다 환경이 다르거나, 장애 발생 시 자동 복구가 어려운 등 문제가 있었다.</li>
</ul>
<h2 id="kubernetes-핵심-구조">Kubernetes 핵심 구조</h2>
<ol>
<li>Cluster 구성</li>
</ol>
<ul>
<li>Control Plane</li>
<li>Worker Node</li>
</ul>
<p>[1] Control Plane</p>
<p>주요 컴포넌트</p>
<ul>
<li>(1) API Server<ul>
<li>모든 요청의 출입구</li>
<li>kubectl 명령이 여기로 들어간다</li>
</ul>
</li>
<li>(2) etcd<ul>
<li>클러스터의 상태를 저장하는 DB</li>
</ul>
</li>
<li>(3) Scheduler<ul>
<li>어떤 노드에 Pod를 배치할지 결정한다</li>
</ul>
</li>
<li>(4) Controller Manager<ul>
<li>시스템 상태를 지속적으로 원하는 상태로 유지한다</li>
</ul>
</li>
</ul>
<p>[2] Worker Node</p>
<p>: 실제로 컨테이너가 실행되는 곳이다</p>
<ul>
<li>(1) Kubelet<ul>
<li>노드에서 Pod 상태를 관리한다</li>
</ul>
</li>
<li>(2) Kube Proxy<ul>
<li>네트워크, 로드밸런싱을 담당한다</li>
</ul>
</li>
<li>(3) Container Runtime<ul>
<li>Docker, containerd 등</li>
</ul>
</li>
</ul>
<h2 id="핵심-개념">핵심 개념</h2>
<ol>
<li>Pod</li>
</ol>
<ul>
<li>K8s의 가장 작은 실행 단위다</li>
<li>하나 이상의 컨테이너를 포함하고 같은 네트워크, 스토리지를 공유한다</li>
</ul>
<ol start="2">
<li>Deployment</li>
</ol>
<ul>
<li>원하는 Pod 개수를 유지</li>
<li>자동 복구와 롤링 업데이트를 지원한다</li>
</ul>
<ol start="3">
<li>Service</li>
</ol>
<ul>
<li>Pod에 접근하기 위한 네트워크 추상화<ul>
<li>Pod는 IP가 계속 바뀌기 때문에 직접 접근이 불가하다.</li>
</ul>
</li>
<li>종류 : ClusterIP, NodePort, LoadBalancer</li>
</ul>
<ol start="4">
<li>Namespace</li>
</ol>
<ul>
<li>클러스터 내 리소스를 논리적으로 분리한다</li>
</ul>
<ol start="5">
<li>ConfigMap, Secret</li>
</ol>
<ul>
<li>ConfigMap : 설정 정보</li>
<li>Secret : 비밀번호, API Key 등 민감 정보</li>
</ul>
<h2 id="kubernetes의-동작-흐름">Kubernetes의 동작 흐름</h2>
<p>상황 예시 : 웹 서버 3개를 띄워보자</p>
<ol>
<li>개발자가 yaml 작성</li>
<li>kubectl로 API Server에 요청</li>
<li>etcd에 상태를 저장</li>
<li>Scheduler가 Pod 배치</li>
<li>Kubelet이 컨테이너 실행</li>
<li>Controller가 상태 유지</li>
</ol>
<p>→ 핵심 : 원하는 상태를 유지</p>
<h2 id="yaml-예시">YAML 예시</h2>
<pre><code class="language-java">apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:latest
        ports:
        - containerPort: 80</code></pre>
<p>뜻 : nginx 컨테이너를 3개 실행하고, 장애 발생 시 자동 복구한다.</p>
<h2 id="kubernetes-핵심-특징">Kubernetes 핵심 특징</h2>
<ol>
<li>Self-Healing</li>
</ol>
<ul>
<li>Pod가 죽으면 자동으로 재생성</li>
</ul>
<ol start="2">
<li>Auto Scaling</li>
</ol>
<ul>
<li>트래픽에 따라 자동으로 확장</li>
</ul>
<ol start="3">
<li>Rolling Update</li>
</ol>
<ul>
<li>무중단 배포가 가능하다</li>
</ul>
<ol start="4">
<li>Declarative 방식</li>
</ol>
<ul>
<li>원하는 상태만 정의한다</li>
</ul>
<h2 id="kubernetes-vs-docker">Kubernetes VS Docker</h2>
<p>그래서 둘의 차이가 무엇인가??</p>
<table>
<thead>
<tr>
<th>구분</th>
<th>Docker</th>
<th>Kubernetes</th>
</tr>
</thead>
<tbody><tr>
<td>역할</td>
<td>컨테이너 실행</td>
<td>컨테이너 관리</td>
</tr>
<tr>
<td>범위</td>
<td>단일 호스트</td>
<td>클러스터</td>
</tr>
<tr>
<td>기능</td>
<td>실행</td>
<td>배포/확장/관리</td>
</tr>
<tr>
<td>- Docker : 컨테이너 실행</td>
<td></td>
<td></td>
</tr>
<tr>
<td>- K8s : 컨테이너 오케스트레이션</td>
<td></td>
<td></td>
</tr>
</tbody></table>
<h2 id="kubernetes를-써야하는-경우는-언제인가">Kubernetes를 써야하는 경우는 언제인가</h2>
<ul>
<li>MSA(마이크로서비스) 구조</li>
<li>트래픽 변동이 큰 서비스</li>
<li>무중단 배포 필요</li>
<li>대규모 서비스</li>
</ul>
<p>위와 같은 상황에서 사용하는 것이 좋다!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[AWS EC2 메모리 부족 현상 해결하기 (Swap Memory)]]></title>
            <link>https://velog.io/@qkq_butler/AWS-EC2-%EB%A9%94%EB%AA%A8%EB%A6%AC-%EB%B6%80%EC%A1%B1-%ED%98%84%EC%83%81-%ED%95%B4%EA%B2%B0%ED%95%98%EA%B8%B0-Swap-Memory</link>
            <guid>https://velog.io/@qkq_butler/AWS-EC2-%EB%A9%94%EB%AA%A8%EB%A6%AC-%EB%B6%80%EC%A1%B1-%ED%98%84%EC%83%81-%ED%95%B4%EA%B2%B0%ED%95%98%EA%B8%B0-Swap-Memory</guid>
            <pubDate>Thu, 23 Apr 2026 05:15:16 GMT</pubDate>
            <description><![CDATA[<h3 id="swap-메모리란">Swap 메모리란</h3>
<p>RAM이 부족할때 디스크 공간을 임시 메모리처럼 사용하는 기술. 속도는 느리지만 OOM이기 때문에 프로세스가 죽는걸 방지할 수 있다</p>
<p>AWS EC2 t2.micro 에서 Spring Boot 프로젝트를 운영하고 있었는데, 자꾸 프로세스가 죽는 일이 생겼다ㅠ</p>
<p>해결 방법을 찾아보던 중, Swap에 대해 접했다.</p>
<h3 id="사용방법">사용방법</h3>
<ol>
<li>Swap 파일 생성</li>
</ol>
<pre><code class="language-java">sudo dd if=/dev/zero of=/swapfile bs=128M count=16</code></pre>
<p>위 명령어를 통해 128MB x 16 의 Swap 파일을 생성할 수 있다.
(필자는 프리티어 1GB 기준이고, 2GB의 파일을 생성한다.)</p>
<ol start="2">
<li>권한 설정</li>
</ol>
<pre><code class="language-java">sudo chmod 600 /swapfile</code></pre>
<p>root만 읽고 쓸 수 있도록 설정한다.</p>
<ol start="3">
<li>영역 설정</li>
</ol>
<pre><code class="language-java">sudo mkswap /swapfile</code></pre>
<p>mkswap 명령어를 통해 swap 영역을 설정한다.</p>
<ol start="4">
<li>파일 적용</li>
</ol>
<pre><code class="language-java">sudo swapon /swapfile</code></pre>
<p>swap 메모리를 활성화시킨다.</p>
<ol start="5">
<li>재부팅 시에도 유지 (선택사항)</li>
</ol>
<pre><code class="language-java">echo &#39;/swapfile none swap sw 0 0&#39; | sudo tee -a /etc/fstab</code></pre>
<p>swapon 명령어만 수행할 경우에는 재부팅될때마다 swap 파일 설정이 비활성화 되기 때문에, 위 명령어를 통해 영구적으로 자동 활성화 시킬 수 있다.</p>
<h3 id="적용-시">적용 시</h3>
<p><img src="https://velog.velcdn.com/images/qkq_butler/post/6a2851c2-127d-4a32-89b9-35e32a2db092/image.png" alt=""></p>
<p>위와 같은 결과를 확인할 수 있다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[토비의 스프링 3.1 2장 (vol.1)]]></title>
            <link>https://velog.io/@qkq_butler/%ED%86%A0%EB%B9%84%EC%9D%98-%EC%8A%A4%ED%94%84%EB%A7%81-3.1-2%EC%9E%A5-vol.1</link>
            <guid>https://velog.io/@qkq_butler/%ED%86%A0%EB%B9%84%EC%9D%98-%EC%8A%A4%ED%94%84%EB%A7%81-3.1-2%EC%9E%A5-vol.1</guid>
            <pubDate>Thu, 16 Apr 2026 03:22:56 GMT</pubDate>
            <description><![CDATA[<h2 id="테스트가-왜-중요하지">테스트가 왜 중요하지?</h2>
<pre><code class="language-java">public void addAndGet() throws Exception{ 
    UserDao dao = new DaoFactory().userDao();

    User user = new User();
    user.setId(&quot;user1&quot;);

    dao.add(user);
    User user2 = dao.get(&quot;user1&quot;);

    assertEquals(user.getId(), user2.getId());
}</code></pre>
<p>작성한 dao가 제대로 동작하는지 확인해야한다.</p>
<p>위 코드처럼 작성하면, add()과 get()을 통해 비교하게 된다.</p>
<h2 id="junit">JUnit</h2>
<p>테스트를 자동화하기 위해 사용한다</p>
<p>대표적인 어노테이션으로 @Test, @Before 가 있다.</p>
<pre><code class="language-java">@Test
public void addAndGet() {
    ...
}</code></pre>
<p>주요 특징을 살펴보면 “자동실행”, “결과 비교(assert)”, “반복가능” 이 있다</p>
<h2 id="di가-테스트에-미치는-영향">DI가 테스트에 미치는 영향</h2>
<p>만약 DI가 없다면,</p>
<pre><code class="language-java">UserDao dao = new UserDao();</code></pre>
<p>내부에서 DB를 직접 생성하기 때문에, 테스트용 DB로 바꾸기가 어렵다</p>
<p>하지만 DI가 있다면?</p>
<pre><code class="language-java">UserDao dao = new UserDao(new TestConnectionMaker());</code></pre>
<p>테스트용 DB로 쉽게 교체가 가능하다!</p>
<h2 id="스프링-컨테이너">스프링 컨테이너</h2>
<p>이제 아래와 같은 기존 코드를</p>
<pre><code class="language-java">UserDao dao = new DaoFactory().userDao();</code></pre>
<p>스프링 방식으로 변화시켜보자</p>
<pre><code class="language-java">ApplicationContext context =
    new AnnotationConfigApplicaionContext(DaoFactory.class);

UserDao dao = context.getBean(&quot;userDao&quot;, UserDao.class);</code></pre>
<p>달라진 점을 살펴보자면, 객체를 직접 만들지 않고 스프링이 대신 만들어준다는 것을 확인할 수 있다!</p>
<p>즉, 스프링 컨테이너는 객체를 대신 만들어주고 관리해주는 시스템이라고 생각하면 된다</p>
<h2 id="bean">Bean</h2>
<p>Bean이 무엇일까? 한마디로 표현하면 스프링 컨테이너가 관리하는 객체다.</p>
<pre><code class="language-java">@Bean
public UserDao userDao() {
    return new UserDao(connectionMaker());
}</code></pre>
<h2 id="applicationcontext">ApplicationContext</h2>
<p>이게 뭘까? </p>
<p>ApplicationContext는 Bean을 저장하고 꺼내주는 창구와 같은 역할을 하는 스프링 컨테이너의 대표 인터페이스다.</p>
<pre><code class="language-java">ApplicationContext context = 
    new AnnotationConfigApplicationContext(DaoFactory.class);

UserDao dao = context.getBean(&quot;userDao&quot;, UserDao.class); </code></pre>
<p>핵심 흐름을 살펴보자면</p>
<ol>
<li>설정 클래스 등록</li>
<li>Bean 생성</li>
<li>DI 수행</li>
<li>필요할때 꺼냄</li>
</ol>
<p>의 과정을 통하는 것을 확인할 수 있다.</p>
<h2 id="singleton">Singleton</h2>
<p>스프링의 기본 전략은 “객체를 하나만 만들어서 공유” 하는것이다.</p>
<p>이럴 위해서 싱글톤을 활용한다</p>
<pre><code class="language-java">UserDao dao1 = new UserDao();
UserDao dao2 = new UserDao();</code></pre>
<p>위와 같은 일반적인 방식으로는 서로 다른 객체 2개가 생성된다.</p>
<pre><code class="language-java">UserDao dao1 = context.getBean(...);
UserDao dao2 = context.getBean(...);</code></pre>
<p>하지만 이러한 방식대로 작성하면, dao1 == dao2 즉 같은 객체가 된다!</p>
<p>주의해야할 점도 있는데, 싱글톤은 상태를 가지면 위험하다.</p>
<p>→ 싱글톤 객체는 상태없는 (Stateless)구조로 만든다.</p>
<h2 id="핵심-개념-관계정리">핵심 개념 관계정리</h2>
<p>각 개념들의 관계를 정리해보자면,</p>
<p>스프링 컨테이너 → ApplicationContext (인터페이스) → Bean (객체) → 싱글톤으로 관리 → JUnit으로 검증</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[토비의 스프링 3.1 1장(vol.1)]]></title>
            <link>https://velog.io/@qkq_butler/%ED%86%A0%EB%B9%84%EC%9D%98-%EC%8A%A4%ED%94%84%EB%A7%81-3.1-1%EC%9E%A5vol.1</link>
            <guid>https://velog.io/@qkq_butler/%ED%86%A0%EB%B9%84%EC%9D%98-%EC%8A%A4%ED%94%84%EB%A7%81-3.1-1%EC%9E%A5vol.1</guid>
            <pubDate>Mon, 13 Apr 2026 04:22:20 GMT</pubDate>
            <description><![CDATA[<h2 id="초난감-코드">초난감 코드</h2>
<pre><code class="language-java">public class UserDao {
    public void add(User user) throws Exception {
        Connection c = DriverManager.getConnection(...);
        PreparedStatement ps = c.prepareStatement(...);
        ps.executeUpdate();
        ps.close();
        c.close();
    }

    public void get(String id) throws Exception {
        Connection c = DriverManager.getConnection(...);
        ...
    }
}</code></pre>
<p>위의 코드는 치명적인 문제점들이 있다.</p>
<ol>
<li>DB에 연결하는 코드 getConnection() 이 반복된다</li>
<li>DB가 바뀌면 모든 DAO를 바꿔야하는 변경에 취약한 문제가 있다</li>
<li>비즈니스 로직과 DB 연결 부분이 섞여있다.</li>
</ol>
<h2 id="관심사의-분리">관심사의 분리</h2>
<p>위와 같은 문제를 해결하기 위해 각 역할을 나눠야한다!</p>
<pre><code class="language-java">public abstract class UserDao {
    protected abstract Connection getConnection();
}</code></pre>
<ul>
<li>DB 연결 부분을 따로 뺐다</li>
</ul>
<pre><code class="language-java">public class NUserDao extends UserDao {
    protected Connection getConnection() {
        return DriverManager.getConnection(...);
    }
}</code></pre>
<ul>
<li>이젠 DB 변경 시 하위 클래스만 수정하면 된다!</li>
<li>하지만 아직 상속에 의존하고 있다</li>
</ul>
<h2 id="템플릿-메소드-패턴">템플릿 메소드 패턴</h2>
<ul>
<li>위의 구조는 템플릿 메소드로 표현할 수 있다<ul>
<li>상위 클래스 : 알고리즘 구조 정의 역할</li>
<li>하위 클래스 : 일부만 구현</li>
</ul>
</li>
<li>템플릿 메소드의 한계<ul>
<li>강한 결합</li>
<li>런타임 변경이 어렵다</li>
</ul>
</li>
</ul>
<h2 id="인터페이스-도입">인터페이스 도입</h2>
<p>그래서 더 좋은 방식을 쓰기 위해 상속 대신 인터페이스를 사용한다!</p>
<pre><code class="language-java">public interface ConnectionMaker {
    Connection makeConenction();
}</code></pre>
<p>인터페이스로 분리하고</p>
<pre><code class="language-java">public class DConnectionMaker implements ConectionMaker {
    public Connection makeConnection() {
        return DriverManager.getConnection(...);
    }
}</code></pre>
<p>위와 같이 구현</p>
<pre><code class="language-java">public class UserDao {
    private ConnectionMaker connectionMaker;

    public UserDao(ConnectionMaker connectionMaker) {
        this.connectionMaker = connectionMaker;
    }
}</code></pre>
<p>→ 이렇게 작성하면 UserDao는 구현이 아닌, 인터페이스에 의존할 수 있게 된다</p>
<h2 id="의존관계-주입-di">의존관계 주입 (DI)</h2>
<p>그런데, ConnectionMaker를 누가 넣어주게 될까?</p>
<pre><code class="language-java">UserDao dao = new UserDao(new DConnectionMaker());</code></pre>
<p>→ 객체가 직접 생성하지 않고, 외부에서 넣어준다</p>
<h2 id="팩토리-도입">팩토리 도입</h2>
<pre><code class="language-java">public class DaoFactory {
    public UserDao userDao() {
        return new UserDao(new DConnectionMaker());
    } 
}</code></pre>
<p>팩토리를 통해 “객체 생성”과 “사용”을 분리시킨다</p>
<h2 id="ioc-제어의-역전">IoC (제어의 역전)</h2>
<p>기존에는 개발자가 직접 객체를 생성했다면,</p>
<p>이제는 팩토리가 대신 생성하게 시킨다. 즉, 객체의 생성/관리 권한이 외부로 넘어간다!</p>
<h2 id="스프링으로-연결">스프링으로 연결</h2>
<p>이러한 개념을 자동으로 해주는게 바로, “스프링 컨테이너”다!</p>
<p>스프링은 “객체 생성”, “의존관계 주입”, “라이프사이클 관리” 의 역할을 수행한다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[하네스 엔지니어링 (Harness Engineering)이 대체 무엇인가?]]></title>
            <link>https://velog.io/@qkq_butler/%ED%95%98%EB%84%A4%EC%8A%A4-%EC%97%94%EC%A7%80%EB%8B%88%EC%96%B4%EB%A7%81-Harness-Engineering%EC%9D%B4-%EB%8C%80%EC%B2%B4-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80</link>
            <guid>https://velog.io/@qkq_butler/%ED%95%98%EB%84%A4%EC%8A%A4-%EC%97%94%EC%A7%80%EB%8B%88%EC%96%B4%EB%A7%81-Harness-Engineering%EC%9D%B4-%EB%8C%80%EC%B2%B4-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80</guid>
            <pubDate>Sun, 12 Apr 2026 06:44:32 GMT</pubDate>
            <description><![CDATA[<p>우연히 주변 개발자분을 통해서 하네스 엔지니어링에 대한 존재를 알게 되었다. 그러다 문득 방치된 블로그가 떠올랐고, 블로그를 다시 손볼 겸 이게 대체 무엇인가에 대한 정리를 해보기로 결심했다!</p>
<p>한 줄로 정의 내리자면 <strong>&quot;AI가 일을 잘하도록 “환경, 도구, 규칙”을 설계하는 엔지니어링 방식&quot;</strong> 이라 표현할 수 있는 듯 하다.</p>
<p>기존 개발 방식이</p>
<ul>
<li>사람이 코드를 작성 &amp; AI는 보조</li>
</ul>
<p>라고 한다면, 최근으로 와서는</p>
<ul>
<li>AI가 코드, 문서, 테스트까지 직접 생성</li>
<li>여기에 버그 수정, 배포까지 수행 가능</li>
</ul>
<p><strong>하지만</strong>
AI는 완벽하지 않다는 점을 간과해서는 안된다.</p>
<p>복잡한 작업일수록 더욱 주의를 필요로 하기 때문에, 등장한 개념이 바로 하네스 엔지니어링이다.</p>
<h3 id="하네스-엔지니어링의-개념">하네스 엔지니어링의 개념</h3>
<h4 id="ai를-도구보다-에이전트로-생각한다">AI를 도구보다 &quot;에이전트&quot;로 생각한다.</h4>
<h4 id="엔지니어의-역할이-바뀐다">엔지니어의 역할이 바뀐다</h4>
<h4 id="하네스harness란">하네스(Harness)란?</h4>
<ul>
<li>Harness : 안전장치 / 제어장치.</li>
</ul>
<p>AI에게 그대로 맡기는 것은 위험하다. 그러므로 제어 시스템을 씌워줘야 한다.
구성 요소 : 시스템 프롬프트, workflow, 도구 연결, 검증 시스템, 제한 규칙</p>
<h4 id="핵심-기술요소-4가지">핵심 기술요소 4가지</h4>
<ol>
<li><strong>AI가 읽고 판단</strong>할 수 있도록 문서, 코드 구조, 규칙 정리 등</li>
<li>작업 분해 : 기능 구현 -&gt; 테스트 -&gt; 검증 -&gt; PR
 <strong>AI는 작은 단위에서 더 잘 작동</strong>한다!</li>
<li>피드백 루프 : 테스트 실행, 실패 시 수정, 다시 테스트하며 <strong>AI가 스스로 검증</strong>할 수 있게 한다!</li>
<li>아키텍처 강제 : <strong>AI가 마음대로 구조를 망치지 못하도록</strong> 레이어 구조를 고정하거나, 의존성을 제한하며 안정성을 확보한다!</li>
</ol>
<h4 id="동작-흐름-예시">동작 흐름 예시</h4>
<p>AI에게 명령하고나면</p>
<ul>
<li>코드 상태 분석 -&gt; 버그 재현 -&gt; 수정 코드 작성 -&gt; 테스트 실행 -&gt; 결과 검증 -&gt; PR 생성 -&gt; 리뷰 반영</li>
</ul>
<p>이 모든 과정을 자동으로 수행 가능하다</p>
<h4 id="정리">정리</h4>
<ul>
<li>하네스 : 자동차 전체 구조</li>
<li>AI : 엔진</li>
</ul>
<p>-&gt; 하네스 엔지니어링 : AI에게 일을 맡기는게 아니라 AI가 스스로 개발 작업을 수행할 수 있도록 환경, 규칙, 도구, 피드백 구조를 설계하는 새로운 소프트웨어 엔지니어링 패러다임</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[GitHub Action이란?]]></title>
            <link>https://velog.io/@qkq_butler/GitHub-Action%EC%9D%B4%EB%9E%80</link>
            <guid>https://velog.io/@qkq_butler/GitHub-Action%EC%9D%B4%EB%9E%80</guid>
            <pubDate>Tue, 30 Sep 2025 08:58:22 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/qkq_butler/post/1b21a056-9511-4d8d-a86c-4e7d78758073/image.png" alt=""></p>
<h2 id="github-action이란">Github Action이란?</h2>
<p>github에서 지원하는 CI/CD 툴. </p>
<h2 id="cicd란">CI/CD란?</h2>
<ul>
<li>CI: 버그 수정 및 코드 변경 사항이 빌드, 테스트를 통해 레포지토리에 merge되는 것</li>
<li>CD: 빌드, 테스트 후 배포를 진행하는 것</li>
</ul>
<h2 id="github-action-요소">Github Action 요소</h2>
<ul>
<li>Workflow: 자동화된 프로세스의 집합, ./github/workflows안에서 YAML로 작성</li>
<li>Event: Workflow를 트리거하는 이벤트 (push, pull request 등)</li>
<li>Job: 여러 Step으로 구성된 작업 단위</li>
<li>Step: Job에서 순차적으로 실행되는 단위. 스크립트 명령어나 정의된 액션으로 구성</li>
<li>Action: Job을 구성하기 위한 Step의 조합으로 구성된 독립적 명령.</li>
</ul>
<h3 id="변수-설정-secrets-and-variables">변수 설정 (Secrets and Variables)</h3>
<ul>
<li>Workflow 파일에서 자주 사용하는 변수, 민감한 정보를 Secrets and Variables 를 통해 관리 가능</li>
</ul>
<p>Repository → Settings → Secrets and Variables → action에서 variable 선택</p>
<ul>
<li>변수명 사용시 {{변수명}} 형태로 참조</li>
</ul>
<h2 id="quick-start">Quick Start</h2>
<p><a href="https://docs.github.com/en/actions/get-started/quickstart">https://docs.github.com/en/actions/get-started/quickstart</a></p>
<p>Github 홈페이지에 Github Action을 간단하게 구성 가능한 안내를 확인할 수 있음.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[객체지향 설계, SOLID]]></title>
            <link>https://velog.io/@qkq_butler/SOLID</link>
            <guid>https://velog.io/@qkq_butler/SOLID</guid>
            <pubDate>Thu, 06 Feb 2025 05:40:58 GMT</pubDate>
            <description><![CDATA[<h1 id="srp-단일-책임-원칙">SRP 단일 책임 원칙</h1>
<p>: 한 클래스는 하나의 책임만 가진다</p>
<ul>
<li>변경 시에 파급효과가 적으면 SRP를 잘 따른 것 (ex. 객체 사용분리, UI변경)</li>
</ul>
<h1 id="ocp-개방-폐쇄-원칙">OCP 개방-폐쇄 원칙</h1>
<p>: 다형성을 활용해 확정에는 열려있고, 변경에는 닫혀있게 한다</p>
<ul>
<li>객체를 생성, 연관관계를 맺는 별도의 설정이 필요함</li>
</ul>
<h1 id="lsp-리스코프-치환-원칙">LSP 리스코프 치환 원칙</h1>
<p>: 객체는 프로그램의 정확성을 깨뜨리지 않으면서 하위 타입의 인스턴스로 바꿀 수 있어야 한다</p>
<ul>
<li>ex. 자동차 interface의 악셀은 앞으로 가는 기능이기 때문에 뒤로 가도록 구현하면 LSP에 위반</li>
</ul>
<h1 id="isp-인터페이스-분리-원칙">ISP 인터페이스 분리 원칙</h1>
<p>: 특정 클라이언트 위한 인터페이스 여러 개가 하나의 범용 인터페이스보다 낫다</p>
<ul>
<li>ex1. 자동차 : 운전, 정비 인터페이스로 분리</li>
<li>ex2. 사용자 : 운전자, 정비사 클라이언트로 분리</li>
</ul>
<h1 id="dip-의존관계-역전-원칙">DIP 의존관계 역전 원칙</h1>
<p>: 구현클래스가 아닌, 인터페이스에 의존해야 한다</p>
<ul>
<li>구현체에 의존하면 변경이 매우 어려워짐</li>
</ul>
<h1 id="요약">요약</h1>
<ol>
<li>객체지향은 다형성이 중요하다</li>
<li>그러나 다형성 만으로는 OCP(개방-폐쇄), DIP(의존관계 역전) 를 지킬 수 없다.</li>
<li>역할, 구현을 분리하는게 좋다.</li>
<li>인터페이스 부여가 좋지만, 기능 확장이 없을때는 구체클래스 선 도입 후 리팩터링을 통해 인터페이스를 도입할 수 있다.</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[Search Trees]]></title>
            <link>https://velog.io/@qkq_butler/Search-Trees</link>
            <guid>https://velog.io/@qkq_butler/Search-Trees</guid>
            <pubDate>Mon, 27 Nov 2023 13:02:00 GMT</pubDate>
            <description><![CDATA[<h2 id="binary-search-trees">Binary Search Trees</h2>
<ul>
<li>Binary Tree
: Map 항목을 저장할 수 있는 우수한 데이터 구조 -&gt; key에 정의된 order relation</li>
<li>Binary Search Tree
: 각 위치 p가 key-value 쌍 (k, v)을 저장하는 이진 트리 T (p의 왼쪽은 k보다 작고, 오른쪽은 k보다 크다)</li>
<li>Sorted Map<ul>
<li>항목은 key에 따라 순서대로 저장됨 -&gt; 가장 가까운 이웃 query 지원 가능</li>
</ul>
</li>
</ul>
<h2 id="navigating-a-binary-search-tree">Navigating a Binary Search Tree</h2>
<ul>
<li><p>Recall
: 이진 검색 트리 순서대로 이동 (왼쪽 서브트리 먼저 방문, 그 후 루트 방문, 그 후에 오른쪽 서브트리 방문)</p>
</li>
<li><p>이진 검색 트리 순서대로 순회하면 키 순서가 증가하는 위치 방문</p>
</li>
<li><p>tree에 저장된 키 특성에 기초한 이진 검색 트리에 대한 추가 네비게이션 방법</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/qkq_butler/post/8caa091f-3d3c-4df1-9cfe-1349b0ce82ae/image.png" alt=""></p>
<h2 id="searches">Searches</h2>
<ul>
<li>이진 검색 트리에서 키 &#39;k&#39;를 찾기 위해 각 위치 p에서 질문함<ul>
<li>&#39;k&#39;는 top.key((p에 저장된 키)와 같음. 검색이 성공적으로 종료</li>
</ul>
</li>
<li>최악의 running time은 O(h), T경로의 위치에서 T(T, p, k)가 루트에서 시작하여 한 단계씩 내려가는 위치에서 트리 검색 (T, p, k)호출
<img src="https://velog.velcdn.com/images/qkq_butler/post/10a96415-c034-4ad8-97dd-34cf11a92d77/image.png" alt=""></li>
</ul>
<h2 id="insertion-mkv">Insertion. M[k]=v</h2>
<p><img src="https://velog.velcdn.com/images/qkq_butler/post/c417be20-a598-4947-b7e9-b1e6fc5c5703/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/qkq_butler/post/a1ba305f-8000-42c5-a76c-285609100926/image.png" alt=""></p>
<h2 id="deletion">Deletion</h2>
<p>: 삭제할 키 &#39;k&#39;로 항목을 저장하는 위치 p를 찾음, 검색 성공 시 노드 삭제</p>
<ul>
<li><p>Leaf Node
<img src="https://velog.velcdn.com/images/qkq_butler/post/7494e48e-2475-492f-907c-d6e5faf4f96b/image.png" alt=""></p>
</li>
<li><p>one child node
<img src="https://velog.velcdn.com/images/qkq_butler/post/ef07a951-0f7c-4f6d-a74e-a36de4ae8efd/image.png" alt=""></p>
</li>
<li><p>two children node
<img src="https://velog.velcdn.com/images/qkq_butler/post/95a227ff-caf9-46da-8a73-e1f0bd1eb4eb/image.png" alt=""></p>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[DB Storage and Access]]></title>
            <link>https://velog.io/@qkq_butler/DB-Storage-and-Access</link>
            <guid>https://velog.io/@qkq_butler/DB-Storage-and-Access</guid>
            <pubDate>Fri, 24 Nov 2023 08:19:04 GMT</pubDate>
            <description><![CDATA[<h1 id="database-저장">Database 저장</h1>
<ul>
<li>database 저장 장치<ul>
<li>데이터 저장하는 방법, 접근에 영향</li>
<li>직접 접근 저장 장치 (DASD)인 disk 사용 (Nonvolatile storage, Online device)</li>
</ul>
</li>
<li>임의 접근 시간<ul>
<li>데이터 접근 시간</li>
<li>헤드가 원하는 트랙에 있는 레코드 찾아 전송하는데 걸리는 시간</li>
<li>탐구시간 + 회전지연시간 + 데이터 전송 시간</li>
<li>접근 시간은 메인 메모리 접근 시간에 비해 느림</li>
<li>실제 데이터 전송 시간은 전체의 10분의 1!!!</li>
<li>대량 전송률 : 연속적인 블록 전송하는 시간</li>
</ul>
</li>
<li>database 성능 향상 초점 : 디스크 접근 횟수 최소화!!!
(디스크에 배치, 저장하는 방법이 중요한 문제)</li>
</ul>
<h2 id="database-접근">Database 접근</h2>
<ul>
<li>Database 접근 과정<ul>
<li>DBMS는 사용자가 요구하는 레코드 결정 (file manager에게 그 저장 레코드 검색 요청)</li>
<li>file manager는 저장 레코드가 들어있는 페이지 결정 (disk manager에게 그 페이지 검색 요청)</li>
<li>disk manager는 그 페이지의 물리적 위치를 결정 (디스크에 I/O 명령 내림)</li>
</ul>
</li>
</ul>
<h2 id="디스크-관리자">디스크 관리자</h2>
<ul>
<li><p>기본 입출력 서비스 지원 모듈</p>
<ul>
<li>모든 물리적 I/O 연산에 대한 책임</li>
<li>물리적 디스크 주소 알고 있음</li>
<li>operating system의 한 구성 요소</li>
</ul>
</li>
<li><p>file manager를 지원</p>
<ul>
<li>file manager가 디스크를 일정 크기의 페이지, 즉 블록으로 구성된 page set로 취급할 수 있도록 지원</li>
<li>page set 중에는 하나의 free space page set가 있음</li>
<li>각 page는 해당 디스크 내에서 유일한 page number 가짐</li>
</ul>
</li>
<li><p>디스크 관리</p>
<ul>
<li>페이지 번호를 물리적 디스크 주소로 mapping</li>
<li><blockquote>
<p>file manager를 장비에서 독립</p>
</blockquote>
</li>
<li>file manager의 요청에 따라 page set에 대한 페이지 할당, 회수 수행</li>
</ul>
</li>
<li><p>disk manager의 페이지 관리 연산</p>
<ul>
<li>file manager가 명령 가능한 연산<ol>
<li>page set S로부터 페이지 P의 검색</li>
<li>S 내에서 P의 교체</li>
<li>S에 새로운 P 첨가</li>
<li>S에서 P 제거</li>
</ol>
-&gt; 3, 4는 자유 공간 다룸 &amp; disk manager 필요에 따른 연산임</li>
</ul>
</li>
</ul>
<h2 id="파일-관리자">파일 관리자</h2>
<ul>
<li>DBMS가 디스크 저장 공간을 저장 화일들의 집합으로 취급할 수 있도록 지원</li>
<li>저장 화일<ul>
<li>한 타입의 저장 레코드 어커런스들의 집합</li>
<li>한 page set는 하나 이상의 저장 화일을 저장</li>
<li>화일 이름 또는 화일 ID로 식별</li>
</ul>
</li>
<li>저장 레코드<ul>
<li>레코드 번호 또는 레코드 ID로 유일하게 식별</li>
<li>전체 디스크 내에서 유일</li>
<li>&lt;페이지 번호, 오프셋(슬롯 번호)&gt;</li>
</ul>
</li>
<li>file manager의 화일 관리 연산<ul>
<li>DBMS가 file manager에게 명령 가능한 연산<ol>
<li>저장 화일 f에서 저장 레코드 r을 검색</li>
<li>f에 있는 저장 레코드 r을 대체</li>
<li>f에 새로운 레코드 첨가하고 새로운 레코드 ID, r을 반환</li>
<li>f에서 저장 레코드 r을 제거</li>
<li>새로운 저장 화일 f를 생성</li>
<li>저장 화일 f를 제거</li>
</ol>
</li>
</ul>
</li>
</ul>
<h2 id="page-set과-화일">Page Set과 화일</h2>
<ul>
<li>disk manager의 페이지 관리
: file manager가 물리적 디스크 I/O가 아닌 논리적인 페이지 I/O를 수행할 수 있게끔 지원하는 disk manager의 기능</li>
<li>대학 데이터베이스 예<ul>
<li>레코드들의 논리적 순서는 그림과 같이 학번, 과목번호, 학번-과목번호 순</li>
<li>저장 순서도 논리적 순서와 같다</li>
<li>저장 화일들은 28개의 페이지로 구성된 page set에 저장</li>
<li>각 레코드들은 하나의 페이지를 차지</li>
</ul>
</li>
</ul>
<h2 id="대학-데이터베이스-예제-연산-과정">대학 데이터베이스 예제 연산 과정</h2>
<p><img src="https://velog.velcdn.com/images/qkq_butler/post/25ab2fe9-7956-4c23-8db4-a51e1754f371/image.png" alt=""></p>
<ul>
<li>빈 디스크 :
하나의 자유 공간 page set만 존재(1~27)
페이지 0 제외 : 디렉터리</li>
<li>file manager : 5개의 학생 화일 레코드를 삽입<ul>
<li>disk manager : 자유 공간 page set의 페이지 1에서 5까지를 학생 page set이라 이름 붙이고 할당</li>
</ul>
</li>
<li>과목과 등록 화일에 대한 page set를 할당<ul>
<li>4개의 page set가 만들어짐</li>
<li>학생(1<del>5), 과목(6</del>10), 등록(11<del>21), 자유공간 page set(22</del>27)</li>
</ul>
</li>
</ul>
<h2 id="대학-데이터베이스의-초기-적재-후-디스크-배치도">대학 데이터베이스의 초기 적재 후 디스크 배치도</h2>
<p><img src="https://velog.velcdn.com/images/qkq_butler/post/9e20f80a-7013-444d-9496-0b0332fd34c6/image.png" alt=""></p>
<ul>
<li>연산 과정<ul>
<li>file manager : 새로운 학생 S6 (학번 600)을 삽입
disk manager : 첫번째 자유 페이지(페이지22)를 자유 공간 page set에서 찾아서 학생 page set에 첨가</li>
<li>file manager : 학생 S2 (학번 200)을 삭제
disk manager : S2가 저장되어 있던 페이지 (페이지 2)를 자유 공간 page set으로 반납</li>
<li>file manager : 새로운 과목 C6 (E 515)를 삽입
disk manager : 자유 공간 page set에서 첫 번째 자유 페이지 (페이지 2)를 찾아서 과목 page set에 첨가</li>
<li>file manager : 학생 S4를 삭제
disk manager : S4가 저장되어 있던 페이지 (페이지 4)를 자유 공간 page set에 반납</li>
</ul>
</li>
</ul>
<h2 id="삽입-삭제-연산-뒤의-디스크-배치도">삽입, 삭제 연산 뒤의 디스크 배치도</h2>
<p><img src="https://velog.velcdn.com/images/qkq_butler/post/5334b921-3b0e-44b1-9296-06d758a720b3/image.png" alt=""></p>
<ul>
<li>일련의 삽입, 삭제 뒤에는 page set들의 물리적 인접성이 없어짐</li>
</ul>
<h2 id="pointer-표현-방법">Pointer 표현 방법</h2>
<ul>
<li>한 page set에서 페이지의 논리적 순서를 물리적 인접으로 표현하기 어려움</li>
<li>페이지 헤드에 제어 정보를 저장<ul>
<li>next page pointer
: 논리적 순서에 따른 next page의 물리적 주소, next page pointer는 disk manager가 관리 (file manager는 무관)</li>
</ul>
</li>
<li>페이지 헤드에 next page pointer가 포함되어 있는 경우의 디스크 배치도
<img src="https://velog.velcdn.com/images/qkq_butler/post/7c956071-6a05-4177-9385-7469e929b624/image.png" alt=""></li>
</ul>
<ul>
<li>disk directory (page set 디렉터리)<ul>
<li>실린더 0, 트랙 0에 위치</li>
<li>디스크에 있는 모든 page set의 리스트와 각 page set의 첫 번째 페이지에 대한 포인터를 저장</li>
</ul>
</li>
<li>disk directory (페이지 0)
<img src="https://velog.velcdn.com/images/qkq_butler/post/c78b0e1c-9199-486b-bacf-155a81d6641a/image.png" alt=""></li>
</ul>
<h2 id="파일-관리자의-기능">파일 관리자의 기능</h2>
<ul>
<li><p>저장 레코드 관리
: DBMS가 페이지 I/O에 대해 알 필요 없이 저장 화일과 저장 레코드로 처리할 수 있도록 지원</p>
</li>
<li><p>예시</p>
<ul>
<li>하나의 페이지에 여러 개의 레코드 저장</li>
<li>학생 레코드에 대한 논리적 순서는 학번 순</li>
</ul>
<ol>
<li><p>페이지 p에 5개의 학생 레코드(S1 ~ S5)가 삽입 되었다고 가정
<img src="https://velog.velcdn.com/images/qkq_butler/post/39ab3223-0469-4eff-b99d-9ae04ea80bc6/image.png" alt=""></p>
<ol start="2">
<li>DBMS : 학생 레코드 S9 (학번 900)의 삽입 요청</li>
</ol>
</li>
</ol>
<p>-&gt; 페이지 p의 학생 레코드 S5 바로 다음에 저장</p>
<ol start="3">
<li>DBMS : 레코드 S2의 삭제 요청</li>
</ol>
<p> -&gt; 페이지 p에 있는 학생 레코드 S2를 삭제하고 뒤에 있는 레코드들을 모두 앞으로 당김</p>
<ol start="4">
<li>DBMS : 레코드 S7 (학번 700)의 삽입 요청</li>
</ol>
<p> -&gt; 학생 레코드 S5 다음에 들어가야 하므로 학생 레코드 S9를 뒤로 옮김
 <img src="https://velog.velcdn.com/images/qkq_butler/post/c74fde2d-b479-4ed8-90c3-05b3c2a27833/image.png" alt=""></p>
</li>
</ul>
<h2 id="rid의-구현">RID의 구현</h2>
<p><img src="https://velog.velcdn.com/images/qkq_butler/post/beb38963-073c-4e75-ab92-e6d04eb53a3b/image.png" alt=""></p>
<ul>
<li>RID = &lt;페이지 번호 p, 오프셋(슬롯번호)&gt;</li>
<li>오프셋 내용 = 페이지 시작에서부터 저장된 레코드의 위치를 저장</li>
<li>레코드 위치 변경 시 RID의 변경 없이 오프셋의 내용만 변경</li>
<li>최악의 경우 두 번의 접근으로 원하는 레코드 검색 가능<ul>
<li>해당 페이지가 overflow 되어 다른 페이지로 저장된 경우 두 번 접근</li>
</ul>
</li>
</ul>
<h2 id="note">Note!</h2>
<ul>
<li>화일에 있는 모든 저장 레코드들의 순차적 접근<ul>
<li>순차적 접근 : page set 내에서는 페이지 순서, 페이지 내에서는 레코드 순서</li>
<li>레코드 순서 : RID의 오름차순</li>
</ul>
</li>
<li>control information<ul>
<li>저장 레코드에 있는 정보 중, 시스템이 필요로 하는 정보<ul>
<li>file ID</li>
<li>record length</li>
<li>deletion flag</li>
</ul>
</li>
<li>레코드 앞에 prefix로 만들어 저장</li>
<li>일반 사용자에게는 무관</li>
</ul>
</li>
<li>user 데이터 필드<ul>
<li>저장 레코드에 있는 정보 중, 사용자가 필요로 하는 정보</li>
<li>DBMS가 이용, file manager와 disk manager는 알 필요 없음
(화일 관리자는 화일을 단순히 바이트 스트링으로 인식)</li>
</ul>
</li>
</ul>
<h1 id="file의-조작-방법">File의 조작 방법</h1>
<ul>
<li>파일 : DBMS에서 관리하는 모든 데이터는 파일 형태로 기록 (같은 타입의 레코드들의 집합)</li>
<li>레코드의 저장과 접근 방법을 결정
<img src="https://velog.velcdn.com/images/qkq_butler/post/e98e258f-0f11-4f48-a508-693640701432/image.png" alt=""></li>
</ul>
<h2 id="순차-방법">순차 방법</h2>
<ul>
<li>레코드들의 논리적 순서가 저장 순서와 동일<ul>
<li>heap 또는 파일 : 엔트리 순차 화일</li>
<li>일반적인 순차 화일 : 키 순차 화일</li>
</ul>
</li>
<li>레코드 접근 - 물리적 순서</li>
<li>화일 복사, 순차적 일괄 처리 응용
<img src="https://velog.velcdn.com/images/qkq_butler/post/07cce29b-ea2f-4ddd-a870-bf2e0ac82d1f/image.png" alt=""></li>
</ul>
<h2 id="인덱스-방법">인덱스 방법</h2>
<ul>
<li>인덱스를 통해 데이터 레코드를 접근</li>
<li>인덱스된 파일의 구성<ul>
<li>인덱스 파일</li>
<li>데이터 화일
<img src="https://velog.velcdn.com/images/qkq_butler/post/7a5b1e6b-b10e-45a7-9225-6907d598e6f9/image.png" alt=""></li>
</ul>
</li>
</ul>
<h2 id="인덱스-된-순차-파일">인덱스 된 순차 파일</h2>
<ul>
<li>하나의 인덱스를 사용</li>
<li>순차 접근과 직접 접근을 지원</li>
<li>순차 데이터 화일<ul>
<li>레코드를 순차적으로 정렬 -&gt; 레코드 집합 전체에 대한 순차 접근 요구를 지원하는데 사용</li>
<li>순차 접근 방법</li>
</ul>
</li>
<li>인덱스<ul>
<li>레코드들에 대한 포인터 -&gt; 개별 레코드들에 대한 임의 접근 요구를 지원하는데 사용</li>
<li>직접 접근 방법</li>
</ul>
</li>
</ul>
<h2 id="다중-키-파일">다중 키 파일</h2>
<ul>
<li>데이터를 중복시키지 않으면서 여러 방법으로 데이터를 접근할 수 있는 경로를 제공</li>
<li>역 화일 -&gt; 각 응용에 적합한 인덱스를 선정해 구축</li>
<li>다중 리스트 화일 -&gt; 하나의 인덱스 값마다 데이터 레코드 리스트를 구축
<img src="https://velog.velcdn.com/images/qkq_butler/post/c8c3a7df-bb2f-48cd-adf0-5cc9397acf0b/image.png" alt=""></li>
</ul>
<h1 id="index-종류">Index 종류</h1>
<ul>
<li>인덱스의 구조<ul>
<li>&lt;레코드 키 값, 포인터(레코드 주소)&gt;</li>
<li>레코드 키 값은 탐색 키 값임</li>
</ul>
</li>
<li>기본 인덱스<ul>
<li>기본 키를 포함한 인덱스</li>
<li>하나의 레코드만 식별</li>
</ul>
</li>
<li>보조 인덱스<ul>
<li>보조 키를 포함</li>
<li>여러 개의 레코드를 식별</li>
</ul>
</li>
<li>집중 인덱스<ul>
<li>탐색 키 값 순서와 데이터 레코드의 물리적 순서가 같도록 구성된 인덱스 -&gt; 기본 인덱스는 집중 인덱스의 특수한 경우</li>
<li>화일에 하나만 존재 가능</li>
<li>동일한 탐색 키 값을 가진 레코드는 물리적으로 집단화 되어 검색이 효율적</li>
</ul>
</li>
<li>비 집중 인덱스<ul>
<li>집중 인덱스가 아닌 인덱스</li>
<li>하나의 데이터 화일에 여러 개 존재 가능</li>
</ul>
</li>
<li>밀집 인덱스<ul>
<li>모든 탐색 키 값에 대해 하나의 인덱스 엔트리가 만들어진 인덱스</li>
<li>역 인덱스는 보통 밀집 인덱스 형태</li>
</ul>
</li>
<li>희소 인덱스<ul>
<li>일부 탐색 키 값에 대해 인덱스 엔트리가 만들어진 인덱스
<img src="https://velog.velcdn.com/images/qkq_butler/post/3a027241-5386-459b-b164-38091c1ca0d0/image.png" alt=""></li>
</ul>
</li>
</ul>
<h2 id="이진-검색-트리">이진 검색 트리</h2>
<ul>
<li>이진검색트리의 각 노드는 키 값을 하나씩 가짐.</li>
<li>최상위 레벨에 루트 노드가 있고, 각 노드는 최대 두 개의 자식 가짐</li>
<li>임의의 노드 키 값은 자신의 왼쪽 자식 노드의 키 값보다 크고, 오른쪽 자식의 키 값보다 작다.
<img src="https://velog.velcdn.com/images/qkq_butler/post/002eb90f-86a9-4115-97bf-f9f617255766/image.png" alt=""></li>
</ul>
<h2 id="b-트리">B-트리</h2>
<ul>
<li>디스크의 접근 단위는 블록</li>
<li>디스크에 한 번 접근하는 시간은 수십만 명령어의 처리 시간과 맞먹는다</li>
<li>검색 트리가 디스크에 저장되어 있다면 트리의 높이를 최소화 하는 것이 유리</li>
<li>B-트리는 다진검색트리가 균형 유지하도록 하여 최악의 경우 디스크 접근 횟수를 줄인 것임</li>
<li>B-트리는 균형잡힌 다진검색트리로 다음의 성질을 만족<ul>
<li>루트 제외한 모든 노드는 적어도 [m/2]-1 개의 키 값 (최대 m개의 서브 트리)를 갖는다</li>
<li>모든 리프 노드는 같은 깊이 가짐</li>
</ul>
</li>
<li>B-트리의 노드 구조
<img src="https://velog.velcdn.com/images/qkq_butler/post/f6bb0cf5-8a5e-471b-b31c-aa1a6f05b005/image.png" alt=""></li>
</ul>
<h2 id="다진-검색-트리">다진 검색 트리</h2>
<p><img src="https://velog.velcdn.com/images/qkq_butler/post/44cc5e93-3134-4478-a8a2-b844791c7203/image.png" alt=""></p>
<h2 id="레코드-접근">레코드 접근</h2>
<ul>
<li>B-트리를 통해 레코드에 접근하는 과정
<img src="https://velog.velcdn.com/images/qkq_butler/post/e0b14428-9e26-4e23-bc75-81718566fcbc/image.png" alt=""></li>
</ul>
<h2 id="3차-b-트리">3차 B-트리</h2>
<p><img src="https://velog.velcdn.com/images/qkq_butler/post/d2420f52-f1d9-4966-ba1e-7953cddf1f1f/image.png" alt=""></p>
<h2 id="연산">연산</h2>
<ul>
<li>B-트리에서의 연산<ul>
<li>직접 탐색 : 키 값에 의한 분기</li>
<li>순차 탐색 : 중위 순회로 가능</li>
<li>삽입, 삭제 : 연산 뒤에 트리의 균형을 유지해야됨</li>
<li>분할 : 노드의 오버플로 발생 시</li>
<li>합병 : 노드의 언더플로 발생 시</li>
</ul>
</li>
<li>삽입<ul>
<li>삽입은 항상 리프 노드에서 수행하게 됨<ul>
<li>빈 공간 있는 경우 : 단순히 빈 공간에 삽입하면 됨</li>
<li>오버플로
1) 두 노드로 분할
2) [m/2] 번째의 키 값 -&gt; 부모 노드에 삽입
3) 나머지는 반씩 왼쪽, 오른쪽 서브트리가 됨</li>
</ul>
</li>
</ul>
</li>
</ul>
<h2 id="삽입-알고리즘">삽입 알고리즘</h2>
<pre><code>BTreeInsert(t,x)
{
    x를 삽입할 리프 노드 r을 찾는다;
    x를 r에 삽입한다;
    if (r에 오버플로우 발생) then clearOverflow(r);
}
clearOverflow(r)
{
    if (r의 형제 노드 중 여유가 있는 노드가 있음) then {
        r의 남는 키를 넘긴다};
    else {
        r을 둘로 분할하고 가운데 키를 부모 노드로 넘긴다;
        if (부모 노드 p에 오버플로우 발생) then clearOverflow(p);</code></pre><h2 id="삽입-예">삽입 예</h2>
<p><img src="https://velog.velcdn.com/images/qkq_butler/post/e60ad121-6b20-45b0-b9ae-26270d4bd633/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/qkq_butler/post/2ad40bab-9fd4-42b2-a0ff-f6995c999609/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/qkq_butler/post/98b16ba5-c8fe-4f97-b441-1ff63c114986/image.png" alt=""></p>
<h2 id="연산-1">연산</h2>
<ul>
<li>삭제<ul>
<li>리프 노드에서는 그대로 삭제</li>
<li>삭제할 키가 리프가 아닌 노드에 존재하는 경우<ul>
<li>후행 키 값과 자리 교환을 하고 리프 노드에서 삭제</li>
</ul>
</li>
<li>키 값의 수 &lt; [m/2]-1이 되어 언더플로가 발생<ol>
<li>재분배 : [m/2] 개 이상의 키를 가지고 있는 형제 노드가 있는 경우에 그 형제 노드로부터 키를 이동</li>
<li>합병 : 재분배 불가능 시 (형제 노드 + 부모 노드의 키 + 언더플로 노드)</li>
</ol>
</li>
</ul>
</li>
</ul>
<h2 id="삭제">삭제</h2>
<p><img src="https://velog.velcdn.com/images/qkq_butler/post/66ff3d65-8b29-46a6-81bd-b6e3659127d5/image.png" alt=""></p>
<h2 id="b-트리-1">B+-트리</h2>
<ul>
<li><p>B+- 트리는 인덱스 세트와 순차 세트로 구성</p>
<ol>
<li>인덱스 세트</li>
</ol>
<ul>
<li>내부 노드로 구성되고 리프 노드에 있는 키들에 대한 경로만 제공</li>
<li>직접 접근을 지원</li>
</ul>
<ol start="2">
<li>순차 세트</li>
</ol>
<ul>
<li>리프 노드로 구성되고 모든 키 값들을 저장</li>
<li>순차 세트는 순차적으로 연결</li>
<li><blockquote>
<p>순차 접근을 지원</p>
</blockquote>
</li>
<li>리프 노드는 내부 노드와 상이한 구조를 가짐</li>
</ul>
</li>
<li><p>m차 B+-트리의 특성</p>
<ul>
<li>노드 구조는 &lt;n, P0, K1, - - ,P n-1 Kn, Pn&gt;<ul>
<li>n : 키 값의 수</li>
<li>P0, - - , Pn : 서브트리에 대한 포인터</li>
<li>K1, - - , Kn : 키 값</li>
</ul>
</li>
<li>루트는 0이거나 2에서 m개 사이의 서브트리를 가짐</li>
<li>리프가 아닌 노드에 있는 키 값의 수는 그 노드의 서브트리 수보다 하나 적음</li>
<li>모든 리프 노드는 같은 레벨</li>
<li>한 노드 안에 있는 키 값들은 오름차순</li>
</ul>
<ul>
<li><p>Pi가 지시하는 서브트리에 있는 노드들의 모든 키 값들은 K i+1보다 작거나 같음</p>
</li>
<li><p>Pn이 지시하는 서브트리에 있는 노드들의 모든 키 값들을 Kn보다 크다</p>
</li>
<li><p>순차 세트를 구성하는 리프 노드는 모두 링크로 연결된 연결 리스트를 구성</p>
</li>
<li><p>리프 노드 구조
&lt;q, &lt;K1, A1&gt;, &lt;K2, A2&gt;, -- &lt;Kq, Aq&gt;, P next&gt;</p>
<ul>
<li>Ai : 키 값 Ki를 가지고 있는 레코드에 대한 주소</li>
<li>q : [m/2]&lt;=q</li>
<li>P next : 다음 리프 노드에 대한 링크</li>
</ul>
</li>
<li><p>B-트리와의 차이점</p>
<ul>
<li>인덱스 세트에 있는 키 값을 찾아가는 경로로만 제공하기 위해 사용</li>
<li><blockquote>
<p>인덱스 세트에 있는 키 값은 모두 순차 세트에 다시 나타남</p>
</blockquote>
</li>
<li>인덱스 세트의 노드와 순차 세트의 노드는 그 내부 구조가 서로 다름<ul>
<li>리프 노드 : 키 값과 이 키 값을 가진 레코드에 대한 주소가 함께 저장</li>
<li>인덱스 세트 노드 : 키 값만 저장</li>
<li>노드에 저장할 수 있는 원소의 수도 서로 다름</li>
</ul>
</li>
<li>순차 세트의 모든 노드가 순차적으로 연결된 연결 리스트<ul>
<li>순차 접근을 효율적으로 지원</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<h2 id="차수가-3인-b-트리">차수가 3인 B+-트리</h2>
<p><img src="https://velog.velcdn.com/images/qkq_butler/post/0bdcd0fd-9eb1-4c60-af19-de40134762d8/image.png" alt=""></p>
<h2 id="b-트리의-연산">B+-트리의 연산</h2>
<ul>
<li>탐색<ul>
<li>B+-트리의 인덱스 세트 : m-원 탐색 트리와 같음</li>
<li>레코드는 리프에서 검색</li>
</ul>
</li>
<li>삽입<ul>
<li>B-트리와 유사</li>
<li>리프가 오버플로가 되면 분할 -&gt; 중간 키 값은 부모 노드로 올라가 저장되지만 분할 노드에도 존재</li>
<li>순차 세트의 연결 리스트의 순차성 유지</li>
</ul>
</li>
<li>삭제<ul>
<li>리프에서만 삭제 (재분배, 합병이 필요 없는 경우)<ul>
<li>인덱스 세트에 있는 키 값은 분리자로 유지 (키 값 탐색하는데 분리 키 값으로 사용)</li>
</ul>
</li>
<li>재분배 : 인덱스 키 값 변화, 트리 구조 유지</li>
<li>합병 : 인덱스의 키 값도 삭제</li>
<li>삭제 예
<img src="https://velog.velcdn.com/images/qkq_butler/post/efb27dac-424f-4e6d-b247-a61835cf5fdf/image.png" alt="">
<img src="https://velog.velcdn.com/images/qkq_butler/post/18d6c02e-26f1-41c1-9f0b-0e92415a99c7/image.png" alt=""></li>
</ul>
</li>
</ul>
<h1 id="해싱-방법">해싱 방법</h1>
<ul>
<li>다른 레코드의 참조 없이 목표 레코드의 접근을 직접 지원 - 직접 화일</li>
<li>키 값과 레코드 주소 사이의 mapping 관계를 함수로 설정</li>
<li>해싱 함수<ul>
<li>키 값으로부터 레코드 주소를 계산</li>
<li>사상 함수 : 키 -&gt; 주소</li>
<li>삽입, 검색에 모두 이용</li>
</ul>
</li>
</ul>
<h2 id="버킷-해싱">버킷 해싱</h2>
<ul>
<li>버킷<ul>
<li>하나의 주소를 가지면서 하나 이상의 레코드를 저장할 수 있는 화일의 한 구역</li>
<li>버킷 크기 : 저장 장치의 물리적 특성과 한번 접근으로 채취 가능한 레코드 수를 고려</li>
</ul>
</li>
<li>버킷 해싱 : 키 -&gt; 버킷 주소</li>
<li>충돌 : 상이한 레코드들을 같은 주소로 변환<ul>
<li>동거자</li>
<li>버킷 만원 - 오버플로 버킷</li>
<li>한번의 I/O가 추가됨</li>
</ul>
</li>
</ul>
<h2 id="충돌-해결">충돌 해결</h2>
<ul>
<li>체이닝<ul>
<li>같은 주소로 해싱되는 원소를 모두 하나의 연결 리스트로 관리</li>
<li>추가적인 연결 리스트 필요</li>
</ul>
</li>
<li>개방주소 방법<ul>
<li>충돌 일어나도 어떻게든 주어진 테이블 공간에서 해결</li>
<li>추가적인 공간 필요하지 않음
<img src="https://velog.velcdn.com/images/qkq_butler/post/6b55ace1-c6b3-4256-a8cd-e1ad16ed15c9/image.png" alt=""></li>
<li>빈자리가 생길 때까지 해시값 계속 만들어낸다</li>
<li>중요한 세가지 방법 : 선형 조사, 이차원 조사, 더블 해싱</li>
</ul>
</li>
</ul>
<h2 id="충돌-해결--선형-조사">충돌 해결 : 선형 조사</h2>
<p>hi (x) = (h(x) + i) mod m
<img src="https://velog.velcdn.com/images/qkq_butler/post/fe615a55-45f8-4503-90a3-0a822cf79db9/image.png" alt=""></p>
<ul>
<li>선형 조사
: 1차 군집에 취약함 (1차군집 : 특정 영역에 원소 몰리는 현상)</li>
</ul>
<h2 id="충돌-해결--이차원-조사">충돌 해결 : 이차원 조사</h2>
<p><img src="https://velog.velcdn.com/images/qkq_butler/post/d9f620f7-760e-4c96-99c0-6d3bc89b708e/image.png" alt=""></p>
<ul>
<li>2차군집 : 여러 개의 원소가 동일한 초기 해시 함수값을 갖는 현상</li>
</ul>
<h2 id="충돌-해결--더블-해싱">충돌 해결 : 더블 해싱</h2>
<p><img src="https://velog.velcdn.com/images/qkq_butler/post/c8075a87-ce42-4f19-a05f-a7995e30d69a/image.png" alt=""></p>
<ul>
<li>충돌 해결 : 개방 주소 방법 시 주의할 점
<img src="https://velog.velcdn.com/images/qkq_butler/post/64e4d742-086d-4dee-bad6-6c1a26144e48/image.png" alt=""></li>
</ul>
<h2 id="확장성-해싱">확장성 해싱</h2>
<ul>
<li>충돌에 대처하기 위해 제안된 기법</li>
<li>레코드 검색은 최대 2번의 디스크 접근만 필요</li>
<li>모조 키<ul>
<li>확장성 해싱 함수 : 키 값 -&gt; 일정 길이의 비트 스트링, pseudokey로 변환</li>
<li>pseudokey의 처음 d 비트를 디렉터리의 인덱스로 사용</li>
</ul>
</li>
<li>디렉터리<ul>
<li>헤더에 현재의 디렉터리 깊이 d를 유지
d : 전역 깊이</li>
<li>2^d개의 버킷들을 지시할 수 있는 포인터 엔트리로 구성</li>
<li>디스크에 저장</li>
</ul>
</li>
<li>버킷<ul>
<li>헤더에 현재의 버킷 깊이 p를 유지, p = 지역 깊이</li>
<li>각 버킷에 저장된 레코드들의 모조 키들은 처음 p비트가 모두 동일
<img src="https://velog.velcdn.com/images/qkq_butler/post/6340e2b7-c650-43fb-a1d2-233ce059695f/image.png" alt=""></li>
</ul>
</li>
</ul>
<h2 id="확장성-해싱의-연산">확장성 해싱의 연산</h2>
<ul>
<li>검색<ul>
<li>모조 키의 처음 d 비트를 디렉터리에 대한 인덱스로 사용</li>
<li>접근된 디렉터리 엔트리는 목표 버킷에 대한 포인터 제공</li>
<li>검색 예
1) 레코드 키 값 k -&gt; 모조키 101000010001
2) 디렉터리 깊이가 3이므로 모조 키의 처음 3비트 사용<ul>
<li>디렉터리의 6번째 (101) 엔트리 접근
3) 엔트리는 4번째 버킷에 대한 포인터</li>
<li>키 값 k를 가지고 있는 레코드가 저장되어있는 버킷</li>
<li>버킷 깊이, p=1 : 모조 키의 공통 비트 수가 1, 즉 이 버킷은 비트 1로 시작하는 레코드들을 저장</li>
</ul>
</li>
</ul>
</li>
<li>저장<ul>
<li>저장할 레코드 모조 키의 처음 d 비트로 디렉터리 접근</li>
<li>엔트리 포인터가 지시하는 버킷에 레코드 저장</li>
<li>버킷의 오버플로 처리<ul>
<li>새로운 버킷 할당</li>
<li>버킷 깊이가 p인 오버플로된 버킷과 새로 할당된 버킷의 깊이를 모두 p+1로 설정</li>
<li>오버플로된 버킷에 있는 레코드들과 새로 저장할 레코드를 모조키의 p+1 번째 값에 따라 기존의 오버플로된 버킷과 새로 할당한 버킷에 분산</li>
<li>이때 d &lt; (p+1) 되면 디렉터리 오버플로가 발생
-&gt; d값을 1 증가시켜 디렉터리 크기를 2배로 확장
-&gt; 2배로 증가된 디렉터리 엔트리 포인터들을 모두 조정</li>
</ul>
</li>
</ul>
</li>
</ul>
<h2 id="버킷-오버플로-예">버킷 오버플로 예</h2>
]]></description>
        </item>
        <item>
            <title><![CDATA[Swapping : Policies]]></title>
            <link>https://velog.io/@qkq_butler/Swapping-Policies</link>
            <guid>https://velog.io/@qkq_butler/Swapping-Policies</guid>
            <pubDate>Fri, 24 Nov 2023 07:13:33 GMT</pubDate>
            <description><![CDATA[<h2 id="beyond-physical-memory--policies">Beyond Physical Memory : Policies</h2>
<ul>
<li>Memory pressure로 인해 OS는 페이지를 페이징하여 활발하게 사용되는 페이지의 공간을 확보해야 함</li>
<li>어떤 페이지를 퇴출할 지 결정하는 것은 OS의 교체 정책 내에서 캡슐화 됨</li>
</ul>
<h2 id="demanding-paging">Demanding Paging</h2>
<ul>
<li>Page Fault Rate (0 &lt;= p &lt;= 1.0)<ul>
<li>p = 0이면 no page fault</li>
<li>p = 1이면 모든 Reference가 fault </li>
</ul>
</li>
<li>Effective Access Time<ul>
<li>EAT = (1 - p) x memory access time + p x page fault service time</li>
<li>Example<ul>
<li>Memory access time = 200ns</li>
<li>Average page fault service = 8ms</li>
<li>EAT = (1 - p) x 200 + p x 8,000,000 = 200 + p x 7,999,800</li>
<li>1000개 중 하나의 access로 인해 page fault가 발생하면 EAT = 8,200ns (40배 정도 둔화된 것)</li>
</ul>
</li>
</ul>
</li>
<li>page fault rate low 낮게 유지하는 게 중요
: 좋은 page replacement 정책이 필요</li>
</ul>
<h2 id="page-replacement">Page Replacement</h2>
<ul>
<li>Page replacement<ul>
<li>실제로 사용하지 않은 page 찾아내 swap out</li>
<li>좋은 page replacement 알고리즘 : page fault 수가 최소화 됨</li>
</ul>
</li>
<li>Locality of reference<ul>
<li>동일한 페이지를 여러 번 메모리에 가져올 수 있음</li>
<li>실제 대부분의 프로그램에서 관찰되는 현상임</li>
<li>일정 시간에 극히 일부 page만 집중적으로 reference 하는 program behavior (Loop)</li>
<li>Paging system이 성능이 좋게 되는 근거</li>
</ul>
</li>
<li>Ideal algorithm : page fault율이 가장 낮음</li>
<li>알고리즘 평가 요소<ul>
<li>메모리 참조의 특정 문자열에서 실행 가능 (참조 문자열)</li>
<li>해당 문자열의 page fault 수 계산</li>
</ul>
</li>
</ul>
<h2 id="the-optimal-replacement-policy">The Optimal Replacement Policy</h2>
<ul>
<li>전체적으로 가장 적은 미스 수로 이어짐<ul>
<li>미래에 가장 멀리 접근할 페이지를 바꿈</li>
<li>cache 누락 가능성이 가장 적음</li>
</ul>
</li>
<li>미래에 가장 멀리 접근할 페이지를 바꿈<ul>
<li>최적 알고리즘이 페이지의 하한을 나타냄</li>
<li>얼마나 근접했는지 알기 위한 비교 정도로만 쓰셈</li>
</ul>
</li>
</ul>
<h2 id="tracing-the-optimal-policy">Tracing the Optimal Policy</h2>
<p><img src="https://velog.velcdn.com/images/qkq_butler/post/fa292cb7-ea25-4237-b91b-0232583cdb1e/image.png" alt=""></p>
<ul>
<li>미래에 가장 나중에 참조될 page를 evict</li>
<li>가장 적은 가능성의 cache miss optimal policy 기준으로 다른 policy</li>
</ul>
<h2 id="a-simple-policy--fifo">A Simple Policy : FIFO</h2>
<ul>
<li>페이지가 시스템에 들어갈 때 대기열에 놓였음</li>
<li>replacement 발생 시, 대기열 끝에 있는 페이지가 삭제 됨(First in page)</li>
</ul>
<h2 id="tracing-the-fifo-policy">Tracing the FIFO Policy</h2>
<p><img src="https://velog.velcdn.com/images/qkq_butler/post/beba599e-416f-4129-aec0-654f393d7dc9/image.png" alt="">
 : replacement가 발생하면 첫번째로 들어온 페이지가 evict 됨</p>
<h2 id="beladys-anomaly">BELADY&#39;S ANOMALY</h2>
<p>: cache size가 커지면 cache hit 비율이 올라갈거라 생각하지만, FIFO 구조에선 worse해질 수 있음 (cache miss가 오히려 늘어남)
<img src="https://velog.velcdn.com/images/qkq_butler/post/5ec23b88-e169-441b-8888-003becbd6f03/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/qkq_butler/post/16ca09b2-97bf-4de1-b52b-34b2f0d94efe/image.png" alt=""></p>
<p>: cache size가 4일 때 cache miss가 더 증가함</p>
<h2 id="another-simple-policy--random">Another Simple Policy : Random</h2>
<ul>
<li>memory pressure로 교체할 random page를 선택<ul>
<li>어떤 블록을 evict할지 너무 고민할 필요 ㄴ</li>
<li>random은 전적으로 얼마나 운이 좋으냐에 따라 달려있음
<img src="https://velog.velcdn.com/images/qkq_butler/post/6f8373c8-7281-4001-a0d7-f2637a5bede5/image.png" alt=""></li>
</ul>
</li>
</ul>
<h2 id="using-history">Using History</h2>
<ul>
<li>이력을 사용 <ul>
<li>recency (최근에 접근한 게 확률 더 ㅇㅇ) : LRU</li>
<li>frequency (자주 접근한 게 확률 더 ㅇㅇ) : LFU</li>
</ul>
</li>
<li>LRU : 마지막으로 사용된 시간이 가장 오래된 page를 쫓아내는 방식
<img src="https://velog.velcdn.com/images/qkq_butler/post/f7b568be-8b0f-4869-a7e4-bb4439961a10/image.png" alt=""><ul>
<li>locality 기반으로 한 알고리즘</li>
<li>Stack 사용한 알고리즘 : Belady&#39;s anomaly 없음</li>
<li>구현 어려움 (page가 언제 접근되었는지 모두 기록하고 있어야 함)</li>
<li>모든 Workload에 유용하지는 않음</li>
</ul>
</li>
</ul>
<h2 id="workload-example">Workload Example</h2>
<ul>
<li>100개의 page에 랜덤으로 접근하는 상황
<img src="https://velog.velcdn.com/images/qkq_butler/post/761d3868-e103-4e52-8c6e-ef18e0eaeaa5/image.png" alt=""></li>
</ul>
<p>: page의 locality가 적용되지 않아 cache size에 비례해서 page hit rate가 높아짐</p>
<ul>
<li>80-20 Workload
<img src="https://velog.velcdn.com/images/qkq_butler/post/d9ff6ea5-f1c9-4154-9851-18f1183b52c0/image.png" alt=""></li>
</ul>
<p>: 80%의 접근 시도가 20개의 페이지에 국한, 20%의 접근 시도가 80개의 페이지에 국한됨
 -&gt; 지역성 기반 알고리즘인 LRU가 FIFO나 RAND 알고리즘 보다 효율적임</p>
<ul>
<li>Looping Sequential
<img src="https://velog.velcdn.com/images/qkq_butler/post/f84a4ba6-9502-430e-a81f-c19c444c153d/image.png" alt=""></li>
</ul>
<p>: 50개의 page가 loop를 돌면서 순차적으로 접근</p>
<ul>
<li>LRU와 FIFO는 크기가 49까지 모두 cache miss 발생 (cache size가 49page 까지 hit ratio=0, 가장 예전에 접근한 page 쫓아내고 50이 들어올때 0이 쫓겨나감)</li>
</ul>
<h2 id="implementing-historical-algorithms">Implementing Historical Algorithms</h2>
<ul>
<li>가장 최근에 사용된 페이지 추적을 위해 시스템은 모든 메모리 참조에 대해 몇 가지 회계 작업을 수행해야 함<ul>
<li>HW 지원도 조금 추가</li>
</ul>
</li>
</ul>
<h2 id="approximating-lru">Approximating LRU</h2>
<ul>
<li>사용 비트 형태의 하드웨어 지원이 필요<ul>
<li>페이지 참조할 때마다 사용 비트는 하드웨어에 의해 1로 설정</li>
<li>하드웨어는 비트를 삭제하지 않음. OS의 책임임</li>
</ul>
</li>
<li>Clock Algorithm<ul>
<li>시스템의 모든 페이지가 원형 목록으로 배열</li>
<li>시계 바늘은 먼저 특정 페이지를 가르킴
<img src="https://velog.velcdn.com/images/qkq_butler/post/0666b36d-da97-451e-be27-018b638cb454/image.png" alt="">
: use bit를 통해서 최근에 접근이 되었는지만 판단 (LRU와 비슷한 동작), page fault 발생 시 손이 가리키는 페이지가 검사됨</li>
</ul>
</li>
</ul>
<h2 id="workload-with-clock-algorithm">Workload with Clock algorithm</h2>
<ul>
<li>Clock algorithm은 완벽한 LRU만큼 잘 작동하지 않음. 이전을 전혀 고려하지 않는 접근이 더 나음
<img src="https://velog.velcdn.com/images/qkq_butler/post/0012e261-20fe-49ef-9261-9f03056cd19f/image.png" alt=""></li>
</ul>
<h2 id="considering-dirty-pages">Considering Dirty Pages</h2>
<ul>
<li>HW엔 수정된 비트 포함<ul>
<li>페이지는 수정되었기 때문에 dirty함. 삭제하려면 디스크에 다시 기록해야 함</li>
<li>페이지 수정되지 않았으면 삭제는 그냥 자유</li>
</ul>
</li>
</ul>
<h2 id="page-selection-policy">Page Selection Policy</h2>
<ul>
<li>OS는 페이지를 메모리에 가져올 시기를 결정해야함</li>
<li>OS에 몇 가지 다른 옵션을 제공</li>
</ul>
<h2 id="prefatching">Prefatching</h2>
<ul>
<li>OS는 페이지가 곧 사용될 것이라고 예측하고, 페이지를 미리 가져옴
<img src="https://velog.velcdn.com/images/qkq_butler/post/5fd4a101-2859-452a-982d-25104775b0e0/image.png" alt=""></li>
</ul>
<h2 id="clustering-grouping">Clustering, Grouping</h2>
<ul>
<li>보류 중인 여러개의 pending writes를 메모리에 함께 모아서 한 번의 쓰기로 기록<ul>
<li>single large write를 many small ones보다 효율적으로 수행</li>
</ul>
</li>
</ul>
<h2 id="thrashing">Thrashing</h2>
<ul>
<li>프로세스에 충분한 page frame이 없는 경우, page fault이 매우 높아짐</li>
<li>Thrashing : 페이지를 주고 받는 중<ul>
<li>발생 이유 : size of locality의 합이 total memory size보다 크기 때문</li>
</ul>
</li>
</ul>
<h2 id="working-set-model">Working-set Model</h2>
<ul>
<li><p>Working-set Model</p>
<ul>
<li><p>locality의 assumption에 기반 두고 있음</p>
</li>
<li><p>working-set window : 고정된 page reference 수</p>
</li>
<li><p>WSS</p>
<ul>
<li>가장 최근 working-set window에서 참조된 총 page 수</li>
<li>w.s.w가 작으면 entire locality를 포함하지 않을 것</li>
<li>w.s.w가 크면 several locality를 아우를 것
<img src="https://velog.velcdn.com/images/qkq_butler/post/762d3c82-5fd9-4c73-8be1-b7266a5d75c8/image.png" alt=""></li>
</ul>
</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Swapping : Mechanisms]]></title>
            <link>https://velog.io/@qkq_butler/Swapping-Mechanisms</link>
            <guid>https://velog.io/@qkq_butler/Swapping-Mechanisms</guid>
            <pubDate>Thu, 23 Nov 2023 06:57:44 GMT</pubDate>
            <description><![CDATA[<h2 id="virtual-memory-concepts">Virtual Memory Concepts</h2>
<ul>
<li>제한된 physical memory size : physical memory의 사용가능한 공간보다 큰 프로그램 실행 불가</li>
<li>일반 program 실행 패턴<ul>
<li>프로그램 전체가 아닌 일부만 실행</li>
<li>프로그램 특정 옵션 및 기능은 거의 안쓰일 수 있음</li>
</ul>
</li>
<li>Virtual memory : memory에 완전히 있지 않은 process도 실행 가능 (program 일부는 memory에 있어야 함)
<img src="https://velog.velcdn.com/images/qkq_butler/post/55c64fc8-5a14-4a5a-8044-78866a5f89d2/image.png" alt=""></li>
</ul>
<p>: logical memory address space와 physical memory address space의 분리,
 logical memory address space는 physical memory address space보다 클 수 있음</p>
<h2 id="demand-paging">Demand Paging</h2>
<ul>
<li>Virtual memory는 demand paging 통해 구현될 수 있음</li>
<li>필요할 때만 page를 memory에 넣음<ul>
<li>적은 I/O, memory 필요</li>
</ul>
</li>
<li>page를 주고받을 수 있어야 함
<img src="https://velog.velcdn.com/images/qkq_butler/post/9f594f2a-c8d8-46d4-9d22-3202ad2e13c9/image.png" alt=""></li>
</ul>
<h2 id="how-to-swap">How to Swap?</h2>
<p>(memory 꽉찼을 때 밀어내는거 : swapping)</p>
<ul>
<li><p>Overlays</p>
<ul>
<li>프로그래머는 필요에 따라 코드나 데이터를 메모리 안팎으로 수동으로 이동시킴</li>
<li>OS에서 지원받을 필요 없음</li>
</ul>
</li>
<li><p>Process-level swapping</p>
<ul>
<li>process는 일시적으로 메모리 부족으로 backing store로 swap된다</li>
<li>나중에 실행되기 위해 memory로 돌아옴</li>
</ul>
</li>
<li><p>Page-level swapping</p>
<ul>
<li>page를 memory에서 backing store로 swap (swap-out)</li>
<li>backing store에서 page를 memory로 swap (swap-in)</li>
</ul>
<h2 id="where-to-swap">Where to Swap?</h2>
<ul>
<li>Swap space<ul>
<li>page를 앞뒤로 이동하기 위해 예약된 디스크 공간 (page 단위로 swap)</li>
<li>swap space의 크기에 따라 사용할 수 있는 최대 메모리 페이지 수가 결정됨</li>
<li>블록 크기는 페이지 크기와 도일함</li>
<li>파일 시스템에서 전용 파티션 또는 파일일 수 있음
<img src="https://velog.velcdn.com/images/qkq_butler/post/4fdcf4a0-a4f1-4c24-b96e-8f9f8d686dd6/image.png" alt=""></li>
</ul>
</li>
</ul>
</li>
</ul>
<h2 id="present-bit">Present Bit</h2>
<ul>
<li>디스크 간에 Page를 swap할 수 있도록 시스템에서 일부 기계를 상위에 추가
: 하드웨어가 page table entry를 검색하면 물리적 메모리에 페이지가 없는 것을 발견 할 수 있음<ul>
<li>Value 1 : page가 physical memory에 있음</li>
<li>Value 0 : page가 memory에는 없지만 disk에 있음</li>
</ul>
</li>
</ul>
<h2 id="the-page-fault">The Page Fault</h2>
<ul>
<li>physical memory에 없는 page에 접근<ul>
<li>페이지가 존재하지 않고 디스크를 swap한 경우 , OS는 페이지 오류 해결하기 위해 페이지를 메모리로 swap 해야 함</li>
<li>page fault handler(페이지 장애 처리기)로 알려진 특정 코드가 실행되고 페이지 장애를 처리해야 함</li>
</ul>
</li>
</ul>
<h2 id="page-fault-handler">Page fault handler</h2>
<ul>
<li>Page fault handling
<img src="https://velog.velcdn.com/images/qkq_butler/post/a21a1448-3504-4782-a44f-5320b474b111/image.png" alt=""></li>
</ul>
<h2 id="memory가-다-찼다면">Memory가 다 찼다면?</h2>
<ul>
<li>OS는 새 페이지를 가져올 공간을 마련하기 위해 페이지를 넘기는 것을 좋아함<ul>
<li>시작하거나 바꿀 페이지를 선택하는 프로세스를함page-replacement (페이지 교체 정책)이라 함</li>
</ul>
</li>
</ul>
<h2 id="page-fault-control-flow---hw">Page Fault control Flow - HW</h2>
<pre><code>VPN = (VirtualAddress &amp; VPN_MASK) &gt;&gt; SHIFT
//  VPN 추출
(Success, TlbEntry) = TLB_Lookup(VPN)
//  추출한 VPN에 대한 주소 변환 정보가 TLB에 있는지 확인
if (Success == True)
//  TLB에 있으면
    if (CanAccess(TlbEntry.ProtectBits) == True)
        Offset = VirtualAddress &amp; OFFSET_MASK
        PhysAddr = (TlbEntry.PFN &lt;&lt; SHIFT) | Offset
        Register = AccessMemory(PhysAddr)
    else RaiseException(PROTECTION_FAULT)
else
//  TLB에 없으면
PTEAddr = PTBR + (VPN * sizeof(PTE))
//  Page Table에 접근해 page위치 알아옴
PTE = AccessMemory(PTEAddr)
if (PTE.Valid == False)
    RaiseException(SEGMENTATION_FAULT)
else
    if (CanAccess(PTE.ProtectBits) == False)
        RaiseException(PROTECTION_FAULT)
    else if (PTE.Present == True)
    //  Present bit가 True라면 (메모리에 page table 존재)
        TLB_Insert(VPN, PTE.PFN, PTE.ProtectBits)
        RetryInstruction()
    else if (PTE.Present == False)
    //  Present Bit가 False라면 (Swap 공간에 page table 존재)
        RaiseException(PAGE_FAULT)
        //  Page Fault 발생</code></pre><h2 id="page-fault-control-flow---sw">Page Fault control Flow - SW</h2>
<pre><code>PFN = FindFreePhysicalPage()
//  Page 가지고 와서 할당할 메모리 공간을 찾음
if (PFN == -1)
    PFN = EvictPage()
    DiskRead(PTE.DiskAddr, PFN)
    //  disk에서 page table 데이터를 가지고 옴
    PTE.present = True
    // Present Bit를 True로 수정
    PTE.PFN = PFN
    RetryInstruction()</code></pre><ul>
<li>OS는 곧 오류가 발생할 페이지의 물리적 프레임을 찾아야 함</li>
<li>해당 페이지가 없는 경우 replace algorithm (교체 알고리즘)이 실행되어 일부 페이지를 메모리에서 꺼낼 때까지 기다림</li>
</ul>
<h2 id="replacement-occur-시">Replacement Occur 시</h2>
<ul>
<li>OS는 메모리가 완전히 채워질 때까지 기다렸다가 다른 페이지의 공간을 만들기 위해 페이지를 바꿈
: 비현실적임. OS가 작은 부분의 메모리를 더 적극적으로 사용할 수 있도록 유지해야 하는 여러 가지 이유가 있음</li>
<li>Swap Daemon, Page Daemon<ul>
<li>사용 가능한 LW page 수가 적으며, 이는 메모리 실행의 자유를 담당하는 백그라운드 스레드임</li>
<li>스레드는 사용 가능한 HW page가 있을 때가지 페이지를 내보냄</li>
</ul>
</li>
</ul>
<h2 id="what-to-swap">What to Swap</h2>
<ul>
<li>low mem에서 각 유형의 page frame에 발생하는 작업<ul>
<li>Kernel code</li>
<li>Kernel data</li>
<li>Page tables for user processes</li>
<li>Kernel stack for user processes § User code pages</li>
<li>User data pages</li>
<li>User heap/stack pages</li>
<li>Files mmap’ed to user processes § Page cache pages
→ Not swapped → Not swapped → Not swapped → Not swapped → Dropped
→ Dropped or swapped
→ Swapped
→ Dropped or go to file system → Dropped or go to file system</li>
</ul>
</li>
<li>Page replacement은 내보낼 페이지 선택</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Advanced Page Tables]]></title>
            <link>https://velog.io/@qkq_butler/Advanced-Page-Tables</link>
            <guid>https://velog.io/@qkq_butler/Advanced-Page-Tables</guid>
            <pubDate>Wed, 22 Nov 2023 17:24:44 GMT</pubDate>
            <description><![CDATA[<h2 id="paging--linear-tables">Paging : Linear Tables</h2>
<p>: 모든 process마다 page table이 하나씩 있음.
 page table : 4byte entry
 -&gt; Page table은 너무 큼</p>
<h2 id="paging--smaller-tables">Paging : Smaller Tables</h2>
<p>: 16KB 페이지와 4byte page table entry가 있다고 가정 (page 하나를 위한 entry하나)
-&gt; Big pages는 internal fragmentation 유발</p>
<h2 id="problem">Problem</h2>
<ul>
<li>process의 entries address space를 위한 single page table
<img src="https://velog.velcdn.com/images/qkq_butler/post/eb692e7f-d936-4587-9713-72297ab6f54b/image.png" alt=""></li>
</ul>
<p>: 대부분의 page table들은 사용되지 않음</p>
<h2 id="hybrid-approach--paging-and-segments">Hybrid Approach : Paging and Segments</h2>
<ul>
<li>Segmentation<ul>
<li>virtual address space를 segments로 나눔</li>
<li>각 segment는 다양한 length 가질 수 있음</li>
</ul>
</li>
<li>Paging<ul>
<li>segment를 고정된 크기의 pages로 나눔</li>
<li>각 segment는 page table 구성</li>
<li>각 segment는 해당 segment에 대한 physical address, limit를 추적함</li>
</ul>
</li>
</ul>
<p>-&gt; page table의 의미없는 공간 줄이기 : Segmentation, Paging</p>
<h2 id="simple-example-of-hybrid-approach">Simple Example of Hybrid Approach</h2>
<ul>
<li>각 process는 3개의 page table이 연결되어 있음
<img src="https://velog.velcdn.com/images/qkq_butler/post/52e67b58-03c0-48ea-bb16-ef6775c82789/image.png" alt=""></li>
</ul>
<p>: VPN에서 상위 두개를 빼서 seg</p>
<h2 id="tlb-miss-on-hybrid-approach">TLB miss on Hybrid Approach</h2>
<ul>
<li>HW는 page table에서 physical address로<ul>
<li>HW는 segment bit(SN)를 사용해 사용할 base and bound 쌍을 결정</li>
<li>HW는 physical address를 가져와 VPN과 결합하고 Page Table Entry의 주소를 형성<pre><code>SN = (VirtualAddress &amp; SEG_MASK) &gt;&gt; SN_SHIFT
VPN = (VirtualAddress &amp; VPN_MASK) &gt;&gt; VPN_SHIFT
AddressOfPTE = Base[SN] + (VPN * sizeof(PTE))</code></pre><h2 id="problem-of-hybrid-approach">Problem of Hybrid Approach</h2>
</li>
</ul>
</li>
<li>크기가 크지만 잘 쓰지 않는 heap이 있으면 page table 낭비 많이 발생 가능</li>
<li><blockquote>
<p>external fragmentation이 다시 발생하는 원인 (할당해놓고 안쓰는게 많음)</p>
</blockquote>
</li>
</ul>
<h2 id="multi-level-page-tables">Multi-level Page Tables</h2>
<ul>
<li>linear page table을 tree와 같은 것으로 바꿈
<img src="https://velog.velcdn.com/images/qkq_butler/post/0443c4c2-d208-4563-a3bd-94c098e0f633/image.png" alt=""></li>
</ul>
<p>: page table을 page-sized units로 쪼갬,</p>
<ul>
<li>모든 page table entries의 page들이 유효하지 않은 경우 page table의 해당 page를 할당하지 않음</li>
<li>page table의 page가 유효한지 여부 보려면 page directory 사용</li>
</ul>
<h2 id="multi-level-page-tables--page-directory">Multi-level Page Tables : Page directory</h2>
<p><img src="https://velog.velcdn.com/images/qkq_butler/post/94666787-e084-485e-900e-a56f7f10b297/image.png" alt=""></p>
<p>: Linear Page Table의 PFN 203 &amp; 203은 invalid하기 때문에 할당되지 않았음 -&gt; page table을 page크기의 단위로 나누고 해당 page table의 page invalid하다면 메모리에 할당하지 않음</p>
<ul>
<li>page directory에는 page table의 page 당 하나의 entry가 포함됨 (page directory entries로 구성됨)</li>
<li>PDE에는 유효한 비트 및 PFN이 있음</li>
</ul>
<h2 id="multi-level-page-tables--advantage--disadvantage">Multi-level Page Tables : Advantage &amp; Disadvantage</h2>
<ul>
<li>Advantage<ul>
<li>사용 중인 address space의 양에 비례해 page table 공간 할당</li>
<li>OS는 page table을 할당하거나 확장해야 할 때 다음 free page를 잡을 수 있음</li>
</ul>
</li>
<li>Disadvantage<ul>
<li>Multi-level table은 time-space trade-off의 예시임</li>
<li>복잡함</li>
</ul>
</li>
</ul>
<h2 id="a-detailed-multi-level-example">A Detailed Multi-level Example</h2>
<p><img src="https://velog.velcdn.com/images/qkq_butler/post/602f5fcf-f944-4018-b083-a414f40954db/image.png" alt=""></p>
<p>: address space가 16KB(2^4, 2^10 -&gt; 14bits), 
 page size가 64bytes(6bit) -&gt; 
 offset도 6bits, VPN = 14-6 = 8bits</p>
<h2 id="a-detailed-multi-level-example--page-directory-idx">A Detailed Multi-level Example : Page Directory Idx</h2>
<p><img src="https://velog.velcdn.com/images/qkq_butler/post/b7a76de1-5019-4d64-9090-1f3f7341292a/image.png" alt="">
 : page directory는 page table의 page마다 하나의 Entry 필요함.
 page directory의 entry가 invalid하면 예외 발생</p>
<p> -&gt; page directory entry가 valid하다면 이 PDE가 가리키는 page table의 page에서 page table entry 가져옴</p>
<p> -&gt; 그때부터 page table index를 그 page table을 가리키는 index로 사용할 수 있음 !!!</p>
<ul>
<li>page directory는 모두 할당되어야 함</li>
</ul>
<h2 id="two-level-page-table-scheme">Two-level Page Table Scheme</h2>
<ul>
<li>32bit Processor의 address translation<ul>
<li>logical address은 20bits(page number), 12bits(page offset)</li>
</ul>
</li>
<li>page table자체가 page이기 때문에 page number가 더 나뉘어져 있음<ul>
<li>10bits(page directory - outer page table), 10bits(page table - inner page table)</li>
</ul>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/qkq_butler/post/5a04a9f0-bb34-432d-9509-0d8bbcaf5e1c/image.png" alt=""></p>
<h2 id="three-level-page-table-scheme">Three-level Page Table Scheme</h2>
<p><img src="https://velog.velcdn.com/images/qkq_butler/post/dc06a39e-0bf3-4fe9-a51f-62ae055c073e/image.png" alt=""></p>
<h2 id="multi-level-page-table-control-flow">Multi-level Page Table Control Flow</h2>
<pre><code>VPN = (VirtualAddress &amp; VPN_MASK) &gt;&gt; SHIFT  // Virtual Page Number를 추출해냄
(Success,TlbEntry) = TLB_Lookup(VPN)  //  TLB가 이 VPN에 대한 translation을 보유하고 있는지 확인
if(Success == True)
    if(CanAccess(TlbEntry.ProtectBits) == True)  
    //  if문 만족 시 해당 TLB 항목에서 page frame number, 원하는 physical address와 access memory를 추출
        Offset = VirtualAddress &amp; OFFSET_MASK
        PhysAddr = (TlbEntry.PFN &lt;&lt; SHIFT) | Offset
        Register = AccessMemory(PhysAddr)
        else RaiseException(PROTECTION_FAULT);
else  // full multi-level lookup 수행 

else  //  Page Directory Index를 추출
        PDIndex = (VPN &amp; PD_MASK) &gt;&gt; PD_SHIFT
        PDEAddr = PDBR + (PDIndex * sizeof(PDE))
        //  Page Directory Entry를 가져옴
        PDE = AccessMemory(PDEAddr)
        if(PDE.Valid == False)
        //  if문 만족 시 : Page Directory Entry의 valid flag를 체크해 true가 되면, page table로 부터 page table entry를 가져옴
            RaiseException(SEGMENTATION_FAULT)
        else  //  PDE가 valid (PTE를 Page table에서 가져옴)</code></pre><h2 id="translation-process--remember-tlb-">Translation Process : Remember TLB !</h2>
<pre><code>PTIndex = (VPN &amp; PT_MASK) &gt;&gt; PT_SHIFT
PTEAddr = (PDE.PFN &lt;&lt; SHIFT) + (PTIndex * sizeof(PTE))
PTE = AccessMemory(PTEAddr)
if(PTE.Valid == False)
    RaiseException(SEGMENTATION_FAULT)
else if(CanAccess(PTE.ProtectBits) == False)
    RaiseException(PROTECTION_FAULT);
else
    TLB_Insert(VPN, PTE.PFN , PTE.ProtectBits)
    RetryInstruction()</code></pre><h2 id="inverted-page-table">Inverted Page Table</h2>
<p><img src="https://velog.velcdn.com/images/qkq_butler/post/0cffde6f-7081-441c-9da7-226a9638d4dd/image.png" alt=""></p>
<p>[page table은 process마다 page table가지고 있어야 함. 사용되지 않는 page가 있어도 page 최대 개수만큼 page table entry가 있어야함]</p>
<p>-&gt; Inverted Page Table 등장</p>
<ul>
<li>page frame마다 page table 하나 (process마다가 아님), page table entry개수가 physical memory의 frame 개수와 동일함</li>
<li>각 page table저장하는데 필요한 memory는 감소하지만 순차 탐색하기 때문에 탐색에 많은 시간이 소요</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[TLB]]></title>
            <link>https://velog.io/@qkq_butler/TLB</link>
            <guid>https://velog.io/@qkq_butler/TLB</guid>
            <pubDate>Wed, 22 Nov 2023 16:22:13 GMT</pubDate>
            <description><![CDATA[<h2 id="paging">Paging</h2>
<ul>
<li>시간적 오버헤드가 크다</li>
<li>Address translation이 너무 느림</li>
<li>목표 : address translation을 빠르게 하는 것</li>
</ul>
<h2 id="tlb-translation-lookaside-buffer">TLB (Translation Lookaside Buffer)</h2>
<ul>
<li><p>CPU -&gt; Logical Address -(TLB Lookup)-&gt; MMU -&gt; TLB Miss시 Page Table, TLB Hit시 Physical Address -&gt; Physical Memory</p>
</li>
<li><p>logical address에서 page number은 process마다 있음</p>
</li>
<li></li>
</ul>
<h2 id="tlb-performance">TLB Performance</h2>
<ul>
<li><p>Effective Access Time With TLB</p>
<ul>
<li>TLB Lookup time : e</li>
<li>Memory Access time : 1</li>
<li>Hit ratio : a (TLB에서의 Percentage)</li>
</ul>
</li>
<li><p>= (1+e)a + (2+3)(1-a)
= 2+e-a</p>
</li>
</ul>
<h2 id="tlb-basic-algorithm">TLB Basic Algorithm</h2>
<pre><code>VPN = (VirtualAddress &amp; VPN_MASK ) &gt;&gt; SHIFT 
(Success , TlbEntry) = TLB_Lookup(VPN)
if(Success == Ture){  // TLB Hit (TLB에 변환 정보 존재할 시)
    if(CanAccess(TlbEntry.ProtectBit) == True ){  // 접근 가능한지 확인 후 TLB 정보로 주소 변환
        offset = VirtualAddress &amp; OFFSET_MASK 
        PhysAddr = (TlbEntry.PFN &lt;&lt; SHIFT) | Offset 
        AccessMemory( PhysAddr )
    } else
        RaiseExceotion(PROTECTION_ERROR)
else  //  TLB에 변환 정보 없을 때
        PTEAddr = PTBR + (VPN * sizeof(PTE)
        PTE = AccessMemory(PTEAddr)
        (--)

        TLB_Insert( VPN , PTE.PFN , PTE.ProtectBits)  //TLB에 변환 정보 저장
        RetryInstruction()
    }
}    </code></pre><ul>
<li>Accessing An Array
<img src="https://velog.velcdn.com/images/qkq_butler/post/5902e9dc-1ec9-4941-bb45-3d95038b2c72/image.png" alt="">
:  첫번째 array[0]에 접근 시 TLB에 아무런 address가 cache 되어있지 않음. 그런데 a[1]에 접근하면 같은 page가 TLB에 cache 되어있어 빠르게 찾기 가능</li>
<li><blockquote>
<p>a[0], a[3], a[7]모두 같은 현상이고 나머지 7번의 접근, 즉 70%에서 TLB Hit 발생 (배열이 연속된 주소공간에 있어 Spatial Locality라 함)</p>
</blockquote>
</li>
</ul>
<h2 id="locality">Locality</h2>
<p>(program간, program 내에서도 Locality 존재)</p>
<ul>
<li>Temporal Locality : 참조했던 걸 다시 참조</li>
<li>Spatial Locality : 주소 x에 접근 시, x의 근처로 접근</li>
</ul>
<h2 id="tlb-entry">TLB entry</h2>
<p>: TLB는 Full Association(결합된) 방법으로 관리됨</p>
<ul>
<li>32 / 64 / 128 entry 가짐</li>
<li>HW에선 원하는 translation 찾기 위해 전체 TLB를 병렬로 검색</li>
<li>Typical TLB : VPN &amp; PFN &amp; other bits</li>
</ul>
<h2 id="tlb-issue--context-switching">TLB Issue : Context Switching</h2>
<p><img src="https://velog.velcdn.com/images/qkq_butler/post/7cd913b6-38b3-4834-9ba9-b5491dbea6be/image.png" alt=""></p>
<p>: process A, B의 VPN가 10으로 동일하지 PFN이 다름 -&gt; TLB에 정보 저장 시 어떤 정보가 어떤 프로세스의 정보인지 알 수 없음</p>
<ul>
<li>해결 방법</li>
</ul>
<ol>
<li>Context Switch 발생 시 기존 process의 주소변환 정보를 flush (모두 지워버림) -&gt; 추가적인 비용 발생</li>
<li>TLB유지 위해 HW의 도움 받음 (TLB구조에 ASID 정보 추가), ASID는 identifier 역할로 process를 구분짓는다</li>
</ol>
<p><img src="https://velog.velcdn.com/images/qkq_butler/post/1348a422-80f3-4bdf-9aef-67fd4a3aebe9/image.png" alt=""></p>
<p>: PFN이 같은 상황(코드 공유)
-&gt; page 공유는 메모리 사용을 줄이기 때문에 메모리 공간 확보 가능</p>
<h2 id="tlb-replacement-policy">TLB Replacement Policy</h2>
<p>: TLB가 꽉차있어서 버려야할때</p>
<ul>
<li>LRU : 가장 오랜 시간 사용되지 않은 process의 정보 제거
<img src="https://velog.velcdn.com/images/qkq_butler/post/cd208996-97dc-4f7b-a376-98d75c61819b/image.png" alt="">
: Total TLB miss : 11</li>
</ul>
<h2 id="a-real-tlb-entry">A Real TLB Entry</h2>
<p><img src="https://velog.velcdn.com/images/qkq_butler/post/253bb00a-edad-4a88-94f3-a76c6c8a0232/image.png" alt=""></p>
<p>[MIPS R4000의 예시 - 32비트 주소공간에 4KB페이지 지원]</p>
<ul>
<li>32비트 주소 공간</li>
<li>4KB페이지
: VPN 19비트, offset 12비트, 남은 1비트는 사용자인지 커널인지 판단</li>
<li>PFN 24비트 할당</li>
<li>PFN(물리 프레임 번호)로 24비트 할당</li>
<li>G(전역 비트) 설정 되어 있으면 ASID무시, 예시에서는 8비트 길이의 ASID 있음 -&gt; 이 부분 보고 주소 공간 구분</li>
<li>Dirty bit는 페이지 갱신 시 세팅</li>
<li>Valid bit는 변환 정보가 존재하는지 나타냄</li>
<li>마지막 64번째 비트는 사용하지 않음</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[모바일프로그래밍_3]]></title>
            <link>https://velog.io/@qkq_butler/%EB%AA%A8%EB%B0%94%EC%9D%BC%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D3</link>
            <guid>https://velog.io/@qkq_butler/%EB%AA%A8%EB%B0%94%EC%9D%BC%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D3</guid>
            <pubDate>Thu, 16 Nov 2023 14:02:02 GMT</pubDate>
            <description><![CDATA[<h2 id="뷰와-뷰-그룹">뷰와 뷰 그룹</h2>
<ul>
<li><p>View 클래스 (Widget)</p>
<ul>
<li>다른 위젯 담을 수 있는 위젯을 레이아웃이라 함</li>
<li>레이아웃은 ViewGroup 클래스 아래 존재</li>
</ul>
</li>
<li><p>View의 상속 받은 클래스 계층도
<img src="https://velog.velcdn.com/images/qkq_butler/post/d1ac7cd5-6204-486e-b12f-dc4cdd7e81c8/image.png" alt=""></p>
</li>
<li><p>Button 속성</p>
<ul>
<li>TextView / View에서 상속받음<h2 id="view-클래스의-xml-속성">View 클래스의 XML 속성</h2>
</li>
<li>XML : 데이터 정의하는 규칙 제공하는 마크업 언어<pre><code class="language-&lt;LinearLayout">xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot; .....</code></pre>
</li>
</ul>
<p>: xml에서의 import 가능,
Button의 id속성을 지정 가능한 것은 android라는 변수에 &quot;<a href="http://schemas.android.com/apk/res/android&quot;">http://schemas.android.com/apk/res/android&quot;</a> 위치에 있는 android 라이브러리를 지정했고, id속성을 가져와서 지정해줬기 때문</p>
</li>
<li><p>id 속성</p>
<ul>
<li>모든 위젯의 아이디 나타냄</li>
<li>Java 코드에서 위젯에 접근할 때 id속성에 지정한 아이디 사용</li>
<li>&quot;@+id/&quot; 형식으로 지정</li>
<li>새로 지정할 id적기 -&gt; 
(위젯형) findViewById(R.id.위젯id);</li>
</ul>
</li>
<li><p>클릭했을 때 동착이 필요한 위젯에만 id속성 지정</p>
</li>
<li><p>layout_width, layout_height 속성</p>
<ul>
<li>match_parent : 레이아웃에 폭이나 높이 맞춤(전체 레이아웃)</li>
<li>wrap_content : 자신의 폭, 높이를 안에 글자가 들어갈 정도로만 설정</li>
</ul>
</li>
<li><p>background 속성</p>
<ul>
<li>RR, GG, BB 위치는 16진수 00~FF 표현</li>
</ul>
</li>
<li><p>padding 속성</p>
<ul>
<li>padding은 위젯 경계선으로부터 위젯 안의 요소가 떨어지도록 설정</li>
</ul>
</li>
<li><p>layout_margin 속성</p>
<ul>
<li>위젯과 위젯 사이 여유 두고 싶을 때 사용</li>
</ul>
</li>
<li><p>visibility 속성</p>
<ul>
<li>위젯 보일건지 여부 결정</li>
<li>invisible : 보이지 않을 뿐더러 원래 자리 계속 유지</li>
<li>gone : 안보이며 자리까지 없어짐</li>
</ul>
</li>
<li><p>enabled, clickable 속성</p>
<ul>
<li>enabled : 위젯 동작 여부</li>
<li>clickable : 클릭/터치 가능하게 함</li>
<li>true / false 지정</li>
<li>XML보다 자바코드에서 주로 사용</li>
</ul>
</li>
<li><p>rotation 속성 : 위젯 회전시켜서 출력 (값은 각도로 지정)</p>
</li>
</ul>
<h2 id="텍스트뷰">텍스트뷰</h2>
<ul>
<li><p>텍스트뷰
java.lang.Object
ㄴ android.view.View
  ㄴ android.widget.TextView</p>
</li>
<li><p>텍스트뷰 속성</p>
<ul>
<li>text : 텍스트뷰에 나타나는 문자열 표현</li>
<li>textColor : 글자 색상 지정</li>
<li>textSize : 글자 크기 지정</li>
<li>typeface : 글자 글꼴 지정</li>
<li>textStyle : 글자 스타일 지정</li>
<li>singleLine : 글 길어서 넘어갈 경우 한 줄만 출력, 문자열 맨 뒤에 ... 표시</li>
</ul>
</li>
</ul>
<h2 id="버튼과-에디트텍스트">버튼과 에디트텍스트</h2>
<ul>
<li><p>버튼과 에디트텍스트</p>
<ul>
<li>사용자에게서 어떤 값 입력받기 위한 가장 기본적인 위젯</li>
<li>View와 TextView 클래스를 상속받으므로 거의 비슷하게 사용 가능</li>
</ul>
</li>
<li><p>버튼
java.lang.Object
ㄴ android.view.View
 ㄴ android.widget.TextView
   ㄴ android.widget.Button</p>
<ul>
<li>일반적인 버튼 XML 코드<pre><code>&lt;Button
android:id=&quot;@+id/button1&quot;
android:text=&quot;확인&quot; /&gt;</code></pre></li>
</ul>
</li>
<li><p>에디트텍스트</p>
<ul>
<li>값 입력받은 후 해당 값을 자바 코드에 가져와서 쓰는 용도로 많이 사용</li>
<li>일반적인 에디트텍스트의 XML 코드</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Query Processing]]></title>
            <link>https://velog.io/@qkq_butler/Query-Processing</link>
            <guid>https://velog.io/@qkq_butler/Query-Processing</guid>
            <pubDate>Tue, 14 Nov 2023 10:52:09 GMT</pubDate>
            <description><![CDATA[<h2 id="query-processing-step">Query Processing Step</h2>
<p> 고급 질의어
-&gt; 검사기 / 파서 (구문분석하는 컴파일러 역할)
-&gt; 내부 형태 질의문 (파이, 시그마 등)
-&gt; 질의어 최적기 (여러 관계대수 문 만들고 제일 빠른 경우 찾음)
-&gt; 질의문 계획
-&gt; 질의문 코드 생성기
-&gt; 질의문 실행 코드
-&gt; 런타임 데이터 베이스 처리
-&gt; 질의어 결과</p>
<h2 id="질의어-최적화">질의어 최적화</h2>
<ul>
<li>최적화 : 더 효율적인 성능</li>
<li>성능측정 : 디스크 I/O 횟수, 중간결과 크기(중간결과 크면 계속 계산해야함), 응답시간(계산시간 빨라야)</li>
<li>질의어 최적화 과정<ol>
<li>질의문 내부 표현</li>
<li>효율적인 내부 형태로 변환 (동등한 내부 표현을 바꿈)</li>
<li>후보 프로시저 선정</li>
<li>질의문 계획 평가 및 결정</li>
</ol>
</li>
</ul>
<h2 id="질의문-내부-표현">질의문 내부 표현</h2>
<ul>
<li>내부 표현<ul>
<li>사용자 질의문을 컴터가 처리하기에 적절한 내부 형태로 변환 (사용자는 sql문이 변함. DBMS가 사용하기에 더 편한 관계대수로 변환)</li>
<li>사용자가 질의</li>
</ul>
</li>
<li>형식론<ul>
<li>시스템의 질의어로 표현할 수 있는 것은 모두 이 형식으로 표현 가능해야함</li>
</ul>
</li>
</ul>
<h2 id="효율적-내부-형태로-변환">효율적 내부 형태로 변환</h2>
<h2 id="후보-프로시저-선정">후보 프로시저 선정</h2>
]]></description>
        </item>
        <item>
            <title><![CDATA[Maps, Hash Tables, and Skip Lists]]></title>
            <link>https://velog.io/@qkq_butler/Maps-Hash-Tables-and-Skip-Lists</link>
            <guid>https://velog.io/@qkq_butler/Maps-Hash-Tables-and-Skip-Lists</guid>
            <pubDate>Sat, 11 Nov 2023 08:35:54 GMT</pubDate>
            <description><![CDATA[<h2 id="map-adt">Map ADT</h2>
<ul>
<li>Map : key-value entry들의 집합
<img src="https://velog.velcdn.com/images/qkq_butler/post/f19d6028-7dcf-496d-b116-b513b997363c/image.png" alt=""></li>
<li>operation
<img src="https://velog.velcdn.com/images/qkq_butler/post/bce8ce60-f94f-42b2-90d2-caef9397148b/image.png" alt=""></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Priority Queues]]></title>
            <link>https://velog.io/@qkq_butler/Priority-Queues</link>
            <guid>https://velog.io/@qkq_butler/Priority-Queues</guid>
            <pubDate>Sat, 11 Nov 2023 08:25:53 GMT</pubDate>
            <description><![CDATA[<h2 id="priority-queue-adt">Priority Queue ADT</h2>
<ul>
<li>Priority Queue : Queue 값들 사이에 우선순위 존재
&amp; minimum key인 요소가 다음에 제거됨<ul>
<li>example
<img src="https://velog.velcdn.com/images/qkq_butler/post/5582a13b-c719-4627-8d98-a6a6e31c9698/image.png" alt=""></li>
</ul>
</li>
</ul>
<h2 id="implementing-priority-queue">Implementing Priority Queue</h2>
<ul>
<li>Unsorted List : 삽입 빠르지만 쿼리, 삭제 속도 느림<ul>
<li>우선순위 높은 O(n) 찾기 (작은 값=높은 우선순위, 높은 값 = 작은 우선순위)</li>
<li>우선순위 높은 item Dequeue! O(1)</li>
<li><blockquote>
<p>item 삭제된 자리가 비어있어 뒤의 item들을 한칸씩 앞으로 shift</p>
</blockquote>
</li>
</ul>
</li>
<li>Sorted List : 쿼리, 삭제는 빠르지만 삽입 느림<ul>
<li>우선순위로 정렬되어 있어 item삭제는 O(1), 삭제된 부분 메꾸기는 O(n)</li>
</ul>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/qkq_butler/post/7b9c15de-8ae8-4768-afcc-f8c9349b95e8/image.png" alt=""></p>
<h2 id="heaps">Heaps</h2>
<p> : Heap은 binary tree [모양, 순서 조건을 만족]</p>
<ul>
<li>Complete Binary Tree (어떤 node가 자식 node를 하나만 가지면 그 노드는 left child에만 존재)</li>
<li>Heap Order<ul>
<li>Max Heap : parent node 값은 child보다 크거나 같아야 함</li>
<li>Min Heap : parent node 값은 child보다 작거나 같아야 함</li>
</ul>
</li>
<li>Implementing Priority Queue with Heap
: Priority Queue 저장하기엔 제일 자연스러운 방식 &amp; 트리 높이 h = [O(nlogn)]</li>
</ul>
<p><img src="https://velog.velcdn.com/images/qkq_butler/post/d0140709-625f-42d3-9724-e36e24214430/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/qkq_butler/post/9ccc7398-5fa4-4172-9357-ca618ba5ed38/image.png" alt=""></p>
<ul>
<li>Bubbling<ul>
<li>up heap bubbling : Min Heap일 경우, 추가된 last node의 entry키가 parent보다 작을때까지 swap 진행</li>
<li>down heap bubbling : Min Heap일 경우, 변경된 root node의 entry키가 parent보다 클때까지 swap 진행</li>
</ul>
</li>
</ul>
<ul>
<li>Array-based Representation of Complete Binary Tree
: 트리를 array에 저장<ul>
<li>p가 root T면, f(p)=0</li>
<li>p가 position q의 left child면 f(p)=2f(q)+1</li>
<li>p가 position q의 right child면 f(p)=2f(p)+2</li>
<li>T의 원소는 범위 [0, n-1]에 있음, </li>
</ul>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/qkq_butler/post/7e7f54ae-fe63-4cc1-93c3-f56fb8f7410b/image.png" alt=""></p>
<ul>
<li>Analysis of Heap-Based Queue<ul>
<li>Heap 기반 구현 통해 insertion, removal 시 실행시간 단축</li>
</ul>
</li>
<li>Python&#39;s heapq Module<ul>
<li>heappush(L,e) : e를 리스트 L에 push, heap order 복구</li>
<li>heappop(L) : L에서 최소값을 pop &amp; return하고 heap order 복구</li>
<li>heappushpop(L,e) : e를 L에 push, 최소값을 pop &amp; return</li>
<li>heapreplace(L,e) : heappushpop과 비슷함</li>
<li>heapify(L) : 순서없는 list를 heap-order property로 변형</li>
<li>nlargest(k, iterable) : 주어진 iterable에서 k개의 최댓값 목록 생성</li>
<li>nsmallest(k, iterable) : k개의 최소값 목록 생성</li>
</ul>
</li>
</ul>
<h2 id="sorting-with-priority-queue">Sorting with Priority Queue</h2>
<ul>
<li><p>Selection-Sort</p>
<ol>
<li>기존 priority queue에 있던 값들을 새로운 sequence에 원래 순서대로 옮김</li>
<li>sequence에서 removeMin을 전체 값의 개수 n만큼 반복, 이 값들을 순서대로 기존 sequence에 옮김
<img src="https://velog.velcdn.com/images/qkq_butler/post/1698df42-1c3e-4b47-8f95-9bd9c6ffa020/image.png" alt=""></li>
</ol>
</li>
<li><p>Insertion-Sort</p>
<ol>
<li>기존 priority queue에 있던 값들을 새로운 sequence로 옮김(새로운 수가 들어올때마다 우선순위대로 해당 위치에 저장)</li>
<li>sequence에 존재하는 값들을 순서대로 기존 sequence에 옮김
<img src="https://velog.velcdn.com/images/qkq_butler/post/291fcf23-4b1f-47b5-b3ce-6040b28b95cd/image.png" alt=""></li>
</ol>
</li>
<li><p>Heap-Sort</p>
<ul>
<li>소요 메모리 양은 O(n)</li>
<li>insert, removeMin()은 O(logn)의 시간 소요</li>
<li>size, empty, min은 O(1)의 시간 소요
ex1)
<img src="https://velog.velcdn.com/images/qkq_butler/post/604f2a12-a06a-42a8-81e7-77a5718ab1da/image.png" alt=""></li>
</ul>
<p>ex2)
<img src="https://velog.velcdn.com/images/qkq_butler/post/a28e2aaf-a058-4021-86f5-80eefe6a21f6/image.png" alt=""></p>
</li>
</ul>
<h2 id="adaptable-priority-queues">Adaptable Priority Queues</h2>
<p><img src="https://velog.velcdn.com/images/qkq_butler/post/0138a4e5-c2a7-4e03-8850-edcd36e3798e/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Data_Modeling]]></title>
            <link>https://velog.io/@qkq_butler/DataModeling</link>
            <guid>https://velog.io/@qkq_butler/DataModeling</guid>
            <pubDate>Tue, 31 Oct 2023 19:21:20 GMT</pubDate>
            <description><![CDATA[<h2 id="데이터-세계">데이터 세계</h2>
<ul>
<li>현실 세계 -&gt; 개념 세계 = 값 사실 -&gt; 개념적 구조 (추상화 개념적 모델링)</li>
<li>개념 세계 -&gt; 컴퓨터 세계 = 개념적 구조 -&gt; 논리적 구조 (데이터 모델)</li>
</ul>
<h2 id="현실-세계-구조적-표현">현실 세계 구조적 표현</h2>
<p> : 데이터베이스 설계</p>
<ol>
<li>개념적 모델링<ul>
<li>현실 세계 -&gt; 추상적 개념, 개체 타입으로 표현</li>
</ul>
</li>
<li>데이터 모델링<ul>
<li>개념적 구조 -&gt; 논리적 개념, 레코드 타입</li>
</ul>
</li>
<li>데이터 구조화<ul>
<li>논리적 구조 -&gt; 물리적 구조</li>
</ul>
</li>
</ol>
<p><img src="https://velog.velcdn.com/images/qkq_butler/post/5d5a07e1-659c-47d3-b6fc-2d28c8b8ae2c/image.png" alt=""></p>
<h2 id="data-modeling">Data Modeling</h2>
<ul>
<li>데이터베이스 설계 과정 일부
: 개념적인 구조와 논리적인 구조를 거쳐 실제 데이터를 저장할 수 있는 물리적 구조로 변환</li>
</ul>
<ol>
<li><p>개념적 데이터 모델링
: 애트리뷰트로 기술된 개체 타입 &amp; 개체 타입 간 관계 이용 ex) E-R Model</p>
</li>
<li><p>논리적 데이터 모델링</p>
<ul>
<li>field로 기술된 record type, 이들 간 관계 이용 ex)relational data model</li>
</ul>
</li>
</ol>
<h2 id="data-model">Data model</h2>
<ul>
<li>데이터 모델 : D = &lt;S, O, C&gt;</li>
<li>S (구조)<ul>
<li>데이터 정적 성질</li>
<li>개체 타입, 관계 명시</li>
</ul>
</li>
<li>O (연산)<ul>
<li>데이터 동적 성질</li>
</ul>
</li>
<li>C (제약 조건)<ul>
<li>데이터 논리적 제약</li>
</ul>
</li>
</ul>
<h2 id="entity-type">Entity Type</h2>
<ul>
<li><p>개체 : 다른 것과 구별되는 객체 (개체=객체)</p>
</li>
<li><p>개체 타입 : 이름, 애트리뷰트로 정의</p>
<ul>
<li>개체 집합 : 개체 인스턴스의 집합</li>
</ul>
</li>
<li><p>애트리뷰트 유형</p>
<ol>
<li>단순 &amp; 복합
(단순 : 더 이상 분해 불가)</li>
<li>단일 &amp; 다중
(단일 : 특정 개체에 대해 하나의 값)</li>
<li>유도 &amp; 저장
(유도 : 가지고 있는 값에서부터 유도됨)</li>
<li>NULL (NULL값 가짐)</li>
</ol>
</li>
</ul>
<h2 id="relationship-type">Relationship Type</h2>
<p>: 개체 집합들 사이의 대응, 즉 사상(Mapping) 의미</p>
<p><img src="https://velog.velcdn.com/images/qkq_butler/post/cbd94ccf-33f5-4272-8e75-3b3b32c87c4d/image.png" alt=""></p>
<ul>
<li>사상 원소 수 : 관계 타입의 원소 수 제약조건<ul>
<li>일대일 ex) marriage : bridegroom ↔ bride</li>
<li>일대다 ex) mothership : mother ← children</li>
<li>다대일 ex) faculty : professor → department</li>
<li>다대다 ex) enrollment : student ↔ course</li>
</ul>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/qkq_butler/post/f7a66abb-96ba-4a8b-a415-54cc77a79b45/image.png" alt=""></p>
<ul>
<li><p>관계 타입의 참여 제약조건</p>
<ul>
<li>전체 참여 : A-B 관계에서 개체 집합 A의 모든 개체가 A-B 관계에 참여</li>
<li>부분 참여 : A-B 관계에서 개체 집합 A의 일부 개체만 A-B 관계에 참여</li>
</ul>
</li>
<li><p>존재 종속 : 어떤 개체 b의 존재가 개체 a의 존재에 종속됨
<img src="https://velog.velcdn.com/images/qkq_butler/post/740c0b75-cba4-4ca7-bbd9-31f186bf0a24/image.png" alt=""></p>
</li>
</ul>
<h2 id="entity-relationship-model-e-r-model">Entity-Relationship Model (E-R Model)</h2>
<ul>
<li><p>개념적 데이터 모델(현실세계의 개념적 표현)</p>
<ul>
<li>개체 집합 : 한 개체 타입에 속하는 모든 개체 인스턴스</li>
<li>관계 집합 : 한 관계 타입에 속하는 모든 관계 인스턴스</li>
</ul>
</li>
<li><p>E-R 모델 그래픽 표현
<img src="https://velog.velcdn.com/images/qkq_butler/post/cf8bd6ff-6283-4e11-ae99-c48903d67629/image.png" alt=""></p>
</li>
</ul>
<h2 id="entity-type--key-attribute">Entity Type &amp; Key Attribute</h2>
<ul>
<li>Key attribute : 개체 집합 내에서 개체마다 상이한 값 갖는 애트리뷰트 / 애트리뷰트 집합<ul>
<li>Key : 개체 타입 내 모든 개체 인스턴스들 유일하게 식별 (동일한 값 갖는 개체 인스턴스는 없다)</li>
</ul>
</li>
</ul>
<h2 id="weak-entity-type">Weak Entity Type</h2>
<ul>
<li>약한 개체 타입 : 애트립뷰트 만으로는 키 명세 불가</li>
<li>구별자 : 약한 개체 집합 내에서만 서로 구별할 수 있는 애트리뷰트</li>
<li>식별 관계 타입 : 약한 개체를 강한 개체에 연관시킴</li>
</ul>
<h2 id="e-r-diagram-표기법">E-R Diagram 표기법</h2>
<p><img src="https://velog.velcdn.com/images/qkq_butler/post/3c1d3cba-9882-4ca8-aa4f-d30d386c15b8/image.png" alt=""></p>
<p>-&gt; example</p>
<p><img src="https://velog.velcdn.com/images/qkq_butler/post/05d3c574-ee6e-4916-b5d5-07696e0d0d3a/image.png" alt=""></p>
<h2 id="logical-data-model">Logical Data Model</h2>
<p>: 개념적 구조를 데이터베이스로 구현하기 위한 중간 단계, 레코드 타입과 관계로 표현</p>
<ul>
<li>개념적 데이터 모델 : 개체-관계 데이터 모델</li>
</ul>
<h2 id="relational-data-model">Relational Data Model</h2>
<ul>
<li>데이터베이스 : 릴레이션 - 테이블의 집합</li>
<li>릴레이션 스키마 : 개체, 관계성을 릴레이션으로 정의</li>
</ul>
<h2 id="data-structure-diagram">Data Structure Diagram</h2>
<p><img src="https://velog.velcdn.com/images/qkq_butler/post/8f4f8018-a334-4ab0-b00b-b742207a53f4/image.png" alt=""></p>
<ul>
<li><p>구성 요소</p>
<ul>
<li>사각형 노드 : 레코드 타입</li>
<li>링크 : 레코드 타입 간 일대다 관계</li>
<li>레이블 : 관계 이름</li>
</ul>
</li>
<li><p>스키마 다이어그램</p>
<ul>
<li>트리 형태 : 계층 데이터 모델</li>
<li>그래프 형태 : 네트워크 데이터 모델</li>
</ul>
</li>
</ul>
<h2 id="network-data-model">Network Data Model</h2>
<ul>
<li>허용되는 레코드 타입, 관계성 명세
<img src="https://velog.velcdn.com/images/qkq_butler/post/d9190940-3d7d-44f1-a4ae-e7f83d1a38eb/image.png" alt=""></li>
</ul>
<h2 id="hierarchical-data-model">Hierarchical Data Model</h2>
<ul>
<li>스키마 다이아그램이 tree</li>
<li>parent-child 관계
<img src="https://velog.velcdn.com/images/qkq_butler/post/28aa6999-a6e4-4ef5-847e-4031aee80f1e/image.png" alt=""></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Normalization ]]></title>
            <link>https://velog.io/@qkq_butler/ch-7</link>
            <guid>https://velog.io/@qkq_butler/ch-7</guid>
            <pubDate>Wed, 18 Oct 2023 20:51:58 GMT</pubDate>
            <description><![CDATA[<h2 id="데이터-논리적-표현">데이터 논리적 표현</h2>
<p> 릴레이션 스키마의 설계</p>
<ul>
<li><ol>
<li>애트리뷰트, entity, 관계성 파악</li>
</ol>
</li>
<li><ol start="2">
<li>관련 애트리뷰트를 릴레이션으로 묶음
(애트리뷰트 간 관계성, 데이터 종속성, 일관성 고려해야)</li>
</ol>
</li>
<li><ol start="3">
<li>변칙적 성질 예방 : 데이터 변경 시의 이상</li>
</ol>
</li>
</ul>
<h2 id="이상-anomaly">이상 (Anomaly)</h2>
<ol>
<li>삭제 이상 : 연쇄 삭제에 의한 정보 손실</li>
<li>삽입 이상 : 원하지 않는 정보의 강제 삽입</li>
<li>갱신 이상 : 중복 데이터 갱신으로 정보의 모순성 발생<ul>
<li>이상 원인 : 한 개체에 속한 애트리뷰트 간 존재하는 여러 개의 종속관계를 하나의 릴레이션으로 표현</li>
<li>이상 해결 : 애트리뷰트 간 여러 종속관계를 분해 (종속성은 릴레이션으로 표현 = 정규화 과정)</li>
</ul>
</li>
</ol>
<h2 id="스키마-설계-변환">스키마 설계, 변환</h2>
<ul>
<li>스키마 설계 : 데이터베이스의 논리적 설계<ol>
<li>애트리뷰트, 제약조건들 수집</li>
<li>수집된 결과를 제약조건에 따라 여러 릴레이션으로 분할 (스키마 변환)</li>
</ol>
</li>
<li>스키마 변환 원리<ol>
<li>정보 표현의 무손실</li>
<li>최소 데이터 중복</li>
<li>분리 원칙 (관계성은 별도 릴레이션으로 분리시켜 표현)</li>
</ol>
</li>
</ul>
<h2 id="함수-종속-fd">함수 종속 (FD)</h2>
<ul>
<li>함수 종속 : 어떤 릴레이션 R에서, 애트리뷰트 X의 값 각각에 대해 애트리뷰트 Y의 값이 최대 하나만 연관된다
(애트리뷰트 Y는 애트리뷰트 X에 함수 종속)<ul>
<li>X는 Y를 결정 (X는 결정자, Y는 종속자)</li>
<li>X나 Y는 각 두 개 이상의 애트리뷰트 집합 될 수 있음</li>
</ul>
</li>
<li>릴레이션 R에서 애트리뷰트 X가 키면, R의 모든 애트리뷰트 Y에 대해 X -&gt; Y 성립</li>
<li>함수 종속 X -&gt; Y의 경우 애트리뷰트 X가 반드시 키라는걸 요건으로 안함 (X의 한 값에 대응되는 Y 값을 갖는 투플이 둘 이상 존재 가능)</li>
</ul>
<h2 id="함수-종속-다이어그램">함수 종속 다이어그램</h2>
<ul>
<li>수강 릴레이션 : 수강(학번, 과목번호, 학년, 성적)</li>
<li>2개 이상 구성된 애트리뷰트 집합 X에 대해 X -&gt; Y가 성립할 때<ul>
<li>완전 함수 종속 : X&#39;가 부분집합이고 X&#39; -&gt; Y가 성립되는 애트리뷰트 X&#39;가 없음</li>
<li>부분 함수 종속 : X&#39;가 부분집합, X&#39; -&gt; Y가 성립되는 애트리뷰트 X&#39; 존재</li>
</ul>
</li>
</ul>
<h2 id="함수-종속의-폐포-closure">함수 종속의 폐포 (Closure)</h2>
<ul>
<li>스키마에 대한 종속의 집합 F가 있으면<ul>
<li>다른 특정 함수 종속도 그 스키마에 성립</li>
<li>추가 존재하는 함수 종속을 논리적으로 함축되었다고 함</li>
<li>F+ : 논리적으로 함축되는 모든 함수 종속의 집합</li>
</ul>
</li>
</ul>
]]></description>
        </item>
    </channel>
</rss>