<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>hail2y.log</title>
    <link>https://hail2y.tistory.com/</link>
    <description>just do it! go for it  </description>
    <language>ko</language>
    <pubDate>Fri, 17 Apr 2026 00:16:40 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>hail2y</managingEditor>
    <item>
      <title>운영체제의 이해 10장: 데드락 문제 및 그 해법 (2023.05.28)</title>
      <link>https://hail2y.tistory.com/306</link>
      <description>&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&amp;nbsp;&amp;nbsp;동기화는 공유 데이터의 일관성을 위해 프로세스들 간에 실행 순서를 적절히 유지할 수 있도록 해주는 것이다. 하지만 상호배제의 조건을 만족시켰어도 데드락의 문제가 발생할 수 있다. 데드락은 죽어있는 잠김 상태, 전혀 풀릴 수 없는 잠김 상태를 의미한다. 즉, 프로세스의 관점에서 본다면, 어떤 집합에 속한 프로세스들 모두가 대기 상태로서 존재하는데 이들이 기다리는 이벤트가 이 집합 속의 다른 프로세스에 의해서 발생해야 할 때를 말한다. 예를 들어 신호등이 없는 사거리 상황에서 모두 앞이 막혀 진행하지 못할 때가 그렇다. &lt;br&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;자원의 요청과 할당을 도식화로 표현한 것이 자원 할당 그래프다. 자원은 공유 데이터를 말하는데 그래프에서는 프로세스와 함께 노드로 표현하고 특정 자원에 대해 여러 개의 종류가 존재할 수 있다. 프로세스가 자원을 할당받았을 때는 할당에지로, 아직 할당받진 못했지만 필요로 할 때는 요구에지로 표현한다. 데드락의 발생여부는 이 자원 할당 그래프에서 사이클이 존재하는지의 여부로 판단한다. 사이클에 포함된 자원들이 한 개씩만 존재할 때 사이클이 발생한다면 데드락이 나타나지만 사이클이 있더라도 자원들이 여러 개가 존재할 경우에는 데드락이 아닐 수 있다. &lt;br&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;이러한 데드락 문제를 해결하기 위해 데드락 방지 기법, 데드락 회피 기법, 데드락 탐지 및 복구가 있다. 데드락 방지 기법은 데드락 발생 조건들 중 하나라도 만족시키지 않음으로써 데드락 발생을 방지하는 것이다. 현실적으로 보유 및 대기와 원형 대기 조건만 고려하는데, 보유 및 대기를 피하기 위해서는 필요한 모든 자원들이 사용 가능할 때까지 기다렸다가 일괄적으로 확보하는 방법이 있다. 이것은 당장 사용하지도 않을 자원들까지 미리 확보하므로 자원의 활용률을 저하시키고 또 동시에 사용가능한 상태까지 기다리는 과정에서 기아 문제가 발생할 수 있다는 단점이 있다. 원형 대기를 피하는 방법에는 자원들에 대해 요청 순서를 사이클이 없도록 고정해 놓는 것이다. 이는 자원 간의 대기 그래프에서 단방향으로 표현되므로 사이클이 발생하지 않아 데드락이 발생하지 않는 것이다. &lt;br&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;데드락 회피 기법은 이전 기법보다 자원의 활용률을 높일 수 있는 방식으로서 자원을 필요한 시점에 가서 요청하는데 요청한 자원을 할당할 때 데드락이 발생할 가능성을 고려하여 가능성이 없을 때만 할당하고 있을 때는 할당을 보류하는 방식이다. 데드락 발생 가능성을 따질 때 각 프로세스들이 향후 어떤 순서로 자원을 요청할 건지에 대한 정보가 필요하다. 그에 따라 다익스트라가 제시한, 기존의 그래프에 클레임 에지를 더한 자원 할당 그래프를 이용한다. 데드락 회피 기법은 자원 할당을 요청받을 때마다 데드락 발생 가능성을 검사하기에 오버헤드가 크고 발생 가능성은 있어도 실제로는 안 그럴 수 있으니 여전히 자원의 활용률이 떨어진다. &lt;br&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;데드락 탐지 및 복구는 현재 상태에 대한 정보만 사용하여 요청한 자원이 사용 가능하기만 하면 무조건 할당한다. 자원을 최대로 사용하지만 데드락이 발생할 수 있으므로 데드락이 발생하면 체크포인트로 롤백하거나 데드락과 관련된 프로세스들을 강제 종료시킨다. &lt;/p&gt;</description>
      <category>OS</category>
      <author>hail2y</author>
      <guid isPermaLink="true">https://hail2y.tistory.com/306</guid>
      <comments>https://hail2y.tistory.com/306#entry306comment</comments>
      <pubDate>Fri, 13 Mar 2026 02:38:41 +0900</pubDate>
    </item>
    <item>
      <title>운영체제의 이해 9장: 프로세스 간의 동기화 (2023.05.25)</title>
      <link>https://hail2y.tistory.com/305</link>
      <description>&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt; 공유 메모리나 프로세스들 간 공유하고 있는 데이터 등은 내용이 변경되는 작업이 수시로 이루어진다. 이 과정에서 데이터가 예상치 못한 내용으로 변경되었을 때 공유 데이터의 일관성이 유지되지 못한다고 말한다. 공유 데이터의 일관성을 유지하기 위해 프로세스들 간에 실행순서를 적절히 유지하도록 하는 동기화를 해 준다. 변수의 값을 변경하는 간단한 작업에도 이 문제를 확인할 수 있는데, 이것은 CPU가 하나의 명령어로 처리할 수 없기 때문에 여러 개의 명령어를 사용하면서 문제가 발생한 것이다. 운영체제 커널 내부에서도 문제가 발생하는데, 먼저 시스템 콜 함수의 호출로 커널 데이터를 수정하는데 문맥교환이 되면서 이 프로세스가 같은 시스템 콜 함수를 요청하며 커널 데이터를 수정하는 경우다. 또는 커널 데이터를 수정하는 중에 인터럽트 신호가 오면서 그 인터럽트 처리 루틴에서도 같은 데이터를 변경할 때 발생한다.&lt;br&gt;&amp;nbsp;&amp;nbsp;이처럼 프로그램에서 프로세스들 간의 공유 데이터 코드 부분을 크리티컬 섹션이라고 부른다. 이를 해결하기 위해서는 상호 배제의 조건을 만족시키도록 한다. 이는 크리티컬 섹션 부분을 실행하기 전에 적절한 허가를 받는 과정을 통해 동시에 접근하는 것을 막는다. 구체적으로 실행 전에는 적절한 허가를 받고 또 실행 후에는 허가를 반납한다. 이외에도 크리티컬 섹션을 아무도 사용하지 않는다면 실행할 수 있도록 해주는 진행과, 일정한 시간 내에 크리티컬 섹션을 실행할 기회를 주는 제한된 대기시간이 있다. 이를 위해 인터럽트 금지, 스핀락, 뮤텍스와 세마포 처리, 그리고 프로그래밍 언어 차원에서의 크리티컬 리젼과 모니터 등의 방법이 있다.&lt;br&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;인터럽트 금지를 이용한 방법은 간단하게 구현할 수 있다는 장점이 있지만 멀티 프로세서에서는 이 방식을 적용할 수 없다. 프로세스 간 문맥교환은 시스템 콜 함수나 하드웨어 인터럽트를 통해 이루어지는데 이 둘을 경계해야 한다고 할 때, 무엇보다도 크리티컬 섹션의 실행시간이 길 경우 하드웨어 인터럽트도 제때 처리하지 못하고 문맥교환이 안 된다는 단점이 있다. 이를 다시 말하면 해당 섹션과 전혀 상관없는 프로세스들도 실행될 수 없다는 것이다. 따라서 시스템 모드에서 작동되는 커널 내부의 짧은 크리티컬 섹션을 위해서만 사용된다.&lt;br&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;스핀 락은 lock 변수를 위한 메모리 영역을 확보하고 lock함수와 unlock함수를 호출한다. 비지웨이팅이라는 특정한 조건이 만족될 때까지 기다리는 과정에서 쉬지 않고 조건을 계속 검사하는 과정이 수반된다. 그렇게 되면 CPU의 자원이 낭비될 수 있지만 멀티 프로세서 시스템에서는 내부적으로 짧은 크리티컬 섹션들에 한해 유용하게 사용될 수 있다. &lt;br&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;뮤텍스도 lock, unlock함수를 사용하지만 비지 웨이팅은 적용하지 않는다. 대신 lock함수에서 조건이 만족되지 않는다면 호출한 프로세스를 대기 상태로 전환하고, unlock함수에선 대기 상태의 프로세스들을 모두 깨워 주는 방식을 사용한다. 세마포는 정수값을 가지며 wait, signal의 두 가지 동작만 적용 가능한 객체로 정의된다. 세마포는 크리티컬 섹션 뿐만 아니라 유한버퍼 문제와 같이 여러 가지 동기화 문제에 범용으로 사용된다. &lt;/p&gt;</description>
      <category>OS</category>
      <author>hail2y</author>
      <guid isPermaLink="true">https://hail2y.tistory.com/305</guid>
      <comments>https://hail2y.tistory.com/305#entry305comment</comments>
      <pubDate>Fri, 13 Mar 2026 02:37:24 +0900</pubDate>
    </item>
    <item>
      <title>운영체제의 이해 8장: 저장장치 입출력 및 스케줄링 (2023.05.16)</title>
      <link>https://hail2y.tistory.com/304</link>
      <description>&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;하나의 디스크 드라이버에는 하나 혹은 여러 장의 디스크가 내장되어 있는데, 디스크는 여러 개의 실린더로 이루어져 있다. 실린더는 다시 여러 개의 트랙으로, 하나의 트랙은 여러 개의 섹터로 이루어져 있다. 디스크의 기본 단위는 최소 단위인 섹터들을 일정하게 묶어 놓은 하나의 논리적인 단위인 블록으로 정의한다. 따라서 디스크 용량은 전체 블록 수 x 블록 당 섹터 수 x 섹터 당 바이트 수, 다시 풀어서 정리하면, 전체 실린더 수 x 실린더 당 트랙 수 x 트랙 당 섹터 수 x 섹터 당 바이트 수로 계산할 수 있다. &lt;br&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;OS 내부적으로는 디스크 영역을 관리할 때 논리적 블록 번호만을 사용한다. 따라서 디스크 제어기를 통해 입출력 작업을 실시할 때 이 논리적 블록 번호로부터 물리적 디스크에 대응되는 실린더, 트랙, 섹터 번호들을 계산해야 한다. &lt;br&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;디스크 입출력작업 처리 과정에서 디스크마다 디바이스 큐인 디스크 큐를 사용하는데, 프로세스가 디스크 입출력 작업을 요청하면 OS는 대상이 되는 디스크와 논리적 블록 번호를 결정해 해당 디스크 큐에 프로세스를 넣고 상태를 waiting으로 바꾼다. 이때 스케줄링을 통해 문맥교환을 할 수 있는데 이전 프로세스의 입출력 작업이 완료되면 디스크 인터럽트 처리를 통해 디스크 큐에서 제거되고 상태가 ready로 전환되어 레디 큐에 등록된다. &lt;br&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;디스크 입출력 작업을 실행하는 데 걸리는 시간은 헤드의 이동시간인 접근 시간과 데이터 전송시간으로 나눌 수 있다. 접근 시간은 탐색 시간과 회전지연 시간으로 나뉘는데 헤드의 탐색 시간을 단축시킴으로써 전체 시간을 유의미하게 단축한다. 디스크 큐에 대기 중인 작업들 중 어떤 순서로 처리할지를 정하는 디스크 스케줄링 정책은 FCFS, SSTF, LOOK, C-LOOK, 우선순위 등이 있다. 실제 운영체제에서는 이들을 변형한 N단계 SCAN, 마감시간 스케줄러를 사용한다. 추가적으로 디스크 입출력의 성능개선을 위해 디스크 작업 후 커널 내부의 디스크 캐시 메모리에 내용을 보관하면 이후의 디스크 읽기 작업 횟수를 줄일 수 있다. 또한 지연기록 방식으로 최종 내용에 대해서만 쓰기 작업을 요청함으로써 쓰기 작업 횟수를 줄이고, 하나의 파일에 연속된 블록들이 할당될 수 있도록 클러스터를 사용하거나 디스크 조각모음을 실행하기도 한다.&amp;nbsp;&amp;nbsp;&lt;br&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;플래시 메모리를 저장매체로 사용하는 SSD는 가볍고 속도도 빠르지만 제자리에 덮어쓰기가 안 된다. 그에 반해 HDD는 가능하지만 SSD는 애초에 비어있는 부분에 기록하거나 이미 기록되어 있는 부분의 경우 지우기 절차를 거쳐야 쓰기가 가능하다. 이를 보완하기 위해서 플래시 메모리 특성을 고려한 파일 시스템을 적용하거나 기존 파일 시스템을 사용하되 저장장치로 SSD를 사용하는 방법이 있다. 특히 후자는 그 내부에 플래시 변환 계층인 FTL을 두어 파일 시스템에서 요청한 논리적 위치 정보를 SSD 내부에서 실제로 저장한 위치 정보로 매핑하여 처리한다. SSD는 여러 개의 플래시 메모리 칩들로 구성되는데, 이것은 블록들의 집합으로 정의되며 또, 블록은 페이지들의 집합으로 정의된다. 읽기, 쓰기 작업은 페이지 단위로 처리되며 지우기는 한 블록 단위로 처리된다. &lt;/p&gt;</description>
      <category>OS</category>
      <author>hail2y</author>
      <guid isPermaLink="true">https://hail2y.tistory.com/304</guid>
      <comments>https://hail2y.tistory.com/304#entry304comment</comments>
      <pubDate>Fri, 13 Mar 2026 02:36:06 +0900</pubDate>
    </item>
    <item>
      <title>운영체제의 이해 7장: 파일 관리 (2023.05.10)</title>
      <link>https://hail2y.tistory.com/303</link>
      <description>&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;컴퓨터의 저장매체로는 대표적으로 디스크가 있는데, 이 디스크는 다시 몇 개의 파티션으로 구별하여 사용한다. 하나의 파티션은, 각 파일에 대한 속성을 기록하여 파일들의 목록을 나타내는 파일목록 영역과 각 파일 별 데이터를 기록하는 파일데이터 영역으로 구분된다. 파일 속성이라 하면 파일들의 관리를 위해 이름, 파일종류, 보호, 크기, 데이터블록에 대한 정보를 추가로 기록한 것이다.&lt;br&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;파일은 사용자의 정보를 저장하는 단위이다. 파일과 실제 저장매체에 기록된 부분과의 매핑은 운영체제가 담당하는데 이는 파일시스템으로 구체화된다. 파일시스템은 디스크에 체계적으로 파일들을 기록하고 관리하는 방식을 지칭하는데 하나의 파티션에는 이러한 파일시스템 하나가 적용된다. 파일에 대한 작업은 읽기, 쓰기, 실행 등이 있는데 시스템 콜 함수 형태로 사용자 프로세스가 호출하며 이루어진다. &lt;br&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;유닉스는 파일 보호를 위해 권한을 소유자, 소유 그룹, 기타 이렇게 세 가지로 나누어 구분하였고 권한 수준 별로 각각의 파일 작업의 가능 여부를 나타냈다. 읽기, 쓰기 등의 작업이 사용자가 실행시킨 프로세스에서 요청한 것이기에 접근 권한 검사를 할 때 실행 중인 프로세스의 사용자 번호, 사용자가 소속된 그룹 번호 중 하나가 해당 파일의 소유자 번호 혹은 소유 그룹 번호와 일치하는지를 살핀다. 접근 권한을 표현하는 방법에는 도메인과 객체들에 대해 접근 행렬로써 표현하는 것이 있는데 이를 단순화하여 객체 별 접근목록과 도메인 별 권한목록으로 나눌 수 있다. 유닉스에서는 그 중 객체 별 접근목록을 채택하여 9비트로 도메인 별 권한을 표시한다. &lt;br&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;파일제어블록(FCB)는 파일 별로 속성들을 일괄적으로 정리하여 기록하는 영역으로 각 파티션마다의 파일 목록은 파일제어블록의 집합으로서 파일목록 영역에 배열 형태로 기록된다. 읽기나 쓰기 작업을 수행한다고 하면 파일목록 영역에 있는 PCB의 데이터블록 속성 정보로부터 파일데이터 영역의 블록위치 정보를 확인한 다음 해당 데이터 블록으로 가서 읽거나 기록하는 것이다. &lt;br&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;유닉스를 포함한 대부분의 운영체제에서는 디렉토리 구조로 트리구조를 주로 채택한다. 이는 하나의 파티션에 여러 개의 디렉토리가 존재하는 것으로 이들 간에 트리 구조의 상하관계가 있고 파일 경로를 통해 나타낸다. FCB를 트리구조로 나타낼 때 FCB에는 파일 이름을 포함하지 않고 디렉토리의 데이터 블록에 &amp;lt;이름, 고유번호&amp;gt; 형태의 쌍으로 기록한다. 유닉스는 FCB를 inode로, 파일 목록 영역을 inode 테이블로 정의한다. 그에 따라 이것의 데이터 영역에는 하위파일들의 목록을 &amp;lt;이름, inode 번호&amp;gt;의 쌍으로 기록한다. &lt;br&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;파일 별 데이터 블록을 할당하는 방식은 인덱스 블록 할당, 연속된 블록 할당, 연결된 블록 할당이 있는데 유닉스는 인덱스 블록 할당 방식을 변형하여 파일 크기의 한계를 다단계 인덱스로 보완했다. 윈도즈는 연결된 블록 할당 방식을 쓰는데 임의 위치 접근 향상을 위해 FAT를 사용한다. 이는 파티션의 시작부분에 일정한 크기로 존재하여 블록 간의 연결, 즉 링크에 대한 정보를 따로 모아 관리하는 것이다. FAT의 내용 전체를 메인메모리에 항상 유지하여 시간을 단축시키는 장점이 있다. &lt;/p&gt;</description>
      <category>OS</category>
      <author>hail2y</author>
      <guid isPermaLink="true">https://hail2y.tistory.com/303</guid>
      <comments>https://hail2y.tistory.com/303#entry303comment</comments>
      <pubDate>Fri, 13 Mar 2026 02:34:47 +0900</pubDate>
    </item>
    <item>
      <title>운영체제의 이해 4장: CPU 스케줄링 (2023.04.12)</title>
      <link>https://hail2y.tistory.com/300</link>
      <description>&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;프로세스는 크게 계산 작업과 입출력 작업을 실행하는데, 입출력 작업을 진행하는 동안 대기하므로 그 시간에 계산 위주의 프로세스들을 처리하며 진행된다. 이 과정이 스케줄러에 의한 스케줄링 작업이라 볼 수 있다. 즉 CPU의 활용률을 높이기 위해 ready 상태의 프로세스들 중에서 하나를 선택하는 것이다. 스케줄러는 일반적으로 커널 내에 함수로서 구현되어 있다.&lt;br&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;스케줄러는 실행되는 주기의 길이에 따라 단기, 중기, 장기 스케줄러로 구분할 수 있다. 단기 스케줄러는 일반적인 CPU 스케줄러로서 5ms-100ms 주기로 빈번하게 호출되어 신속히 이루어진다. 이 경우 스케줄링은 현재의 running 프로세스가 다른 상태로 변할 때나 임의의 프로세스가 ready로 변할 때 실행된다. 중기 스케줄러는 메모리 용량이 부족할 때 가상메모리 공간에 프로세스의 영역을 확보하는 스와핑을 해주면서 실행된다. 이 스케줄러는 수백 밀리 초 이상의 주기로 실행된다. 장기 스케줄러는 아직 생성되지 않은 프로세스를 생성할 때 프로세스 유형에 따라 적절한 비율을 유지하면서 실행되고 수십 초 내지 수 분 단위로 실행되는 주기가 아주 길다. &lt;br&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;현재 어떤 프로세스를 실행하고 있을 때 스케줄링을 통해 문맥교환을 할 것인지에 따라 비선점형과 선점형으로 스케줄링을 나누어볼 수 있다. 비선점형 스케줄링은 현재 프로세스가 종료할 때, 스스로 양보할 때, 필요한 작업을 위해 시스템 콜 함수를 호출했을 때와 같이 자발적으로 요청한 경우에 한해서만 스케줄링을 실행해 주는 것을 의미한다. 즉, 실행 중인 프로세스가 계속 실행할 필요가 있으면 다른 프로세스로 문맥교환을 하지 않는 것이다. 이에 반해 선점형 스케줄링은 적절한 스케줄링 작업을 실행해 필요에 따라 다른 프로세스로 문맥교환을 해주는 것을 의미한다. 선점형은 프로세스 중 우선순위 높은 것을 우선하고 비선점형은 실행 중인 프로세스가 완료된 후 우선순위 높은 것을 채택한다.&amp;nbsp;&amp;nbsp;&lt;br&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;스케줄링을 어떻게 하는지에 따른 정책들은 다음과 같다. 레디 큐에 들어온 순서대로 실행되는 FCFS는 현재 프로세스가 종료되거나 대기 상태로 전환되었을 때 1개를 다시 선택하는 방식을 취한다. SJF는 실행할 계산 작업 단위가 가장 짧은 프로세스를 먼저 실행한다. SRTF는 SJF에서 더 나아가 레디 큐에 새로운 프로세스가 추가되는 시점에 지금 실행하던 것의 남은 실행시간과 레디 큐의 것들의 실행시간을 비교하여 가장 작은 값을 갖는 것을 선택한다. 라운드로빈은 레디 큐의 프로세스들을 일정한 할당시간 단위로 돌아가며 실행한다. 우선순위 스케줄링은 각 프로세스마다 부여된 우선순위 중 가장 높은 프로세스를 선택하는 것을 말한다.&lt;/p&gt;</description>
      <category>OS</category>
      <author>hail2y</author>
      <guid isPermaLink="true">https://hail2y.tistory.com/300</guid>
      <comments>https://hail2y.tistory.com/300#entry300comment</comments>
      <pubDate>Fri, 13 Mar 2026 02:30:24 +0900</pubDate>
    </item>
    <item>
      <title>운영체제의 이해 3장: 프로세스 관리 (2023.03.31)</title>
      <link>https://hail2y.tistory.com/299</link>
      <description>&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt; 프로세스는 해당 프로그램에 표현된 내용대로 실제 실행을 하는 능동적인 개체이다. 이는 생성-실행-종료의 순서로 처리되며 생성할 때는 셸이나 GUI를 제공하는 프로세스에서 프로세스 생성을 요청하는 시스템 콜 함수를 통해 이루어진다. 종료 시에도 같다. 필요에 따라 프로세스가 여러 프로세스를 생성할 수 있는데 이때는 부모-자식 관계를 이루는 구조를 갖는다. &lt;br&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;프로세스는 일정한 메모리 영역을 확보한 후에 프로세스가 실행되어야 할 내용이 기록되어야 한다. 메모리에서는 프로세스 영역으로, 기계어 코드가 적힌 코드 영역, 전역변수와 실행 중 메모리 할당 요청 등을 통해 할당받은 메모리들을 포함한 데이터 영역, 함수 호출 과정에서 매개변수나 지역변수를 저장하기 위한 스택 영역이 있다. 프로세스의 상위 개념이라 할 수 있는 프로그램은 디스크에 파일로서 저장되어 있는데 실행 프로그램의 헤더 부분을 통해 필요한 메모리 용량을 결정하여 메모리를 확보한다. 파일의 코드 섹션이 메모리의 코드 영역에, 데이터 섹션이 데이터 영역에 기록된다. 스택 영역은 우선 메모리만 확보한 후에 바닥부터 사용하게 된다. &lt;br&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;여러 프로세스를 실행하는 상태에서 한 프로세스가 입력요청이나 파일 읽기 등 일정 시간이 소요될 때는 CPU가 다른 프로세스를 선택해 실행하도록 해야 한다. 프로세스는 특정 상태를 갖는데 다음과 같다. 현재 실행 중인 상태인 running, 실행 가능 상태인 ready, 입력처럼 특정 조건이 만족될 때까지 대기하는 waiting, 실행이 강제 중지된 suspended 중 하나의 상태를 갖는 것이다. 이때 스케줄링은 ready 상태의 프로세스들 중 하나를 선택해 running을 시키는 것으로 프로세스들의 상태가 바뀔 때나 실행 중인 프로세스에게 할당된 시간이 만료되었을 때 하게 된다. 이때 스케줄러에 의해 선택된 프로세스가 직전에 실행되던 프로세스와 다르면 문맥교환이 일어난다. &lt;br&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;프로세스에는 프로세스 제어블록으로 각 프로세스마다 기록해야 하는 정보를 관리하는 게 있는데 문맥교환 시 저장해야 할 정보도 여기에 들어간다. 문맥교환 할 때는 이전 프로세스의 문맥을 저장하고 다음에 실행할 프로세스의 문맥을 복구하는 과정이 중요하다.&amp;nbsp;&amp;nbsp;&lt;br&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;프로세스를 구성하는 단위인 스레드는 하나의 프로세스에 부여된 작업내용을 소속 스레드들이 나누어서 진행한다. 동일한 목적을 가지지만 스레드도 스택 영역은 스레드 간 독립적으로 구별하고 각각 스레드 제어블록도 가진다. userMain 함수로 시작하는 최초의 스레드에서 필요에 의해 스레드가 생성되고 이들이 문맥교환을 통해 차례로 실행되지만 실제로는 독자적으로 실행되는 것처럼 보인다.&lt;/p&gt;</description>
      <category>OS</category>
      <author>hail2y</author>
      <guid isPermaLink="true">https://hail2y.tistory.com/299</guid>
      <comments>https://hail2y.tistory.com/299#entry299comment</comments>
      <pubDate>Fri, 13 Mar 2026 02:28:56 +0900</pubDate>
    </item>
    <item>
      <title>운영체제의 이해 2장: 컴퓨터 구조와 어셈블리 언어 (2023.03.23)</title>
      <link>https://hail2y.tistory.com/298</link>
      <description>&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;중앙처리장치인 CPU는 메모리에 적재된 명령어를 실행한다. 데이터 입출력 작업을 위해 해당 장치 제어기로 명령을 전달하는데 제어기가 이를 확인하고 작업을 수행한다. CPU가 작업의 결과를 확인하는 방식은 반복적으로 작업 완료 여부를 확인하는 폴링 방식이 아닌, 작업을 수행한 제어기가 작업 완료 시점에 CPU로 인터럽트 신호를 보내는 인터럽트 방식을 주로 채택한다. 제어기가 직접 메모리에 접근하여 읽기, 쓰기 작업을 수행하는 장치를 DMA 제어기라고 한다.&lt;br&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;CPU는 명령어를 실행할 때 OS 부분과 프로세스 부분이 실행될 때를 구분해 권한 차이를 두는데 이는 각각 커널 모드와 유저모드로 설명된다. 전자에서는 시스템 전체의 메모리와 하드웨어에 접근 가능하지만 후자는 일정 메모리 영역에 한해 권한이 제한된다. 특히 전자는 특권 명령으로 상태 레지스터의 모드 부분 변경이나 인터럽트 금지 및 해제 등의 권한을 가진다. 유저 모드에서 커널 모드로 전환할 때는 임의로 비트를 변경하는 것이 안 되기 때문에 인터럽트를 발생하여 전환하고 이후 커널 부분의 인터럽트 처리루틴이 실행된다. 반대의 경우는 인터럽트를 발생할 때 당시 모드 값을 다른 곳에 저장하였다 iret명령어에 통해 복귀한다. 프로세스가 커널 모드에서 실행할 수 있는 시스템 콜 함수를 호출했을 때는 유저 모드에서 인터럽트를 통해 커널 모드로 전환되는데 함수를 처리하는 과정에서 스케줄링을 통해 문맥교환도 가능하다. 이때 현재의 모드와 다음 명령어 주소인 IP 레지스터 값을 스택에 저장한 후 모드를 변경하면 이후 이전 위치로 복귀할 수 있다.&lt;/p&gt;</description>
      <category>OS</category>
      <author>hail2y</author>
      <guid isPermaLink="true">https://hail2y.tistory.com/298</guid>
      <comments>https://hail2y.tistory.com/298#entry298comment</comments>
      <pubDate>Fri, 13 Mar 2026 02:27:41 +0900</pubDate>
    </item>
    <item>
      <title>운영체제의 이해 1장: 운영체제의 이해를 위한 기초 (2023.03.15)</title>
      <link>https://hail2y.tistory.com/297</link>
      <description>&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;운영체제(OS)는 컴퓨터 시스템의 자원들을 효율적으로 사용하기 위해, 또 사용자가 편리하고 안전하게 작업을 할 수 있도록 지원하는 프로그램이다. 즉, 사용자가 원하는 응용 프로그램의 실행을 돕는데, 그 과정에서 하드웨어 제어 등과 같은 기능들을 처리한다. 운영체제를 사용하는 방식은 저마다 다를 수 있는데, 대표적으로 사용자가 직접 키보드 입력을 통해 운영체제에 작업 실행을 요청하는 명령 해석기와 마우스 입력을 통해 작업 실행을 처리하는 그래픽 사용자 인터페이스(GUI) 방식이 있다. 명령 해석기의 예시는 UNIX의 셸이 있다. 운영체제를 구성하는 요소로는 여러 프로세스들 중 어떤 것을 실행할 지 선택하는 스케줄링 등의 프로세스 관리, 프로세스 별 메모리 할당 및 회수를 담당하는 메모리 관리, 컴퓨터 시스템에 장착된 입출력 장치들을 제어하는 입출력 관리 등이 있다. 이 운영체제를 설계하고 구현하는 방법은 크게 모놀리식 커널 구조와 마이크로 커널 구조가 있는데, 의미는 다음과 같다. 먼저 커널은 항상 메모리에 적재된 상태로 실행되는 운영체제의 부분으로서, 좁은 의미의 운영체제로 보면 된다. 모놀리식 커널은 전통적인 방법으로서 운영체제의 모든 기능들을 묶은 하나의 큰 소프트웨어 조각과도 같다. 마이크로 커널은 기본적인 기능만 포함하는 대신 별도의 서버 프로세스들을 두고, 운영체제에 기능 호출할 때는 서버 프로세스와의 메시지 형태로 통신을 한다. 특히 후자는 이식성이 좋고 기능의 추가 및 변경이 용이하다는 장점이 있지만 속도가 느려 전자와 조합한 형태인 하이브리드 커널이 만들어졌다.&lt;/p&gt;</description>
      <category>OS</category>
      <author>hail2y</author>
      <guid isPermaLink="true">https://hail2y.tistory.com/297</guid>
      <comments>https://hail2y.tistory.com/297#entry297comment</comments>
      <pubDate>Fri, 13 Mar 2026 02:26:35 +0900</pubDate>
    </item>
    <item>
      <title>[기타] Ubuntu에서 MySQL 서버 설치하기</title>
      <link>https://hail2y.tistory.com/287</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;1. 한영 전환 키가 작동하지 않을 때&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;키보드 설정에서 입력 소스로 한국어가 있는지 확인하고, 키보드 배치에서 한영 전환키가 명확히 있는 것을 위로 올린다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. MySQL 서버 설치하기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우분투 환경에서 MySQL 서버를 설치할 때 터미널에서 apt를 이용해 설치하는 게 효율적이라고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://jongsky.tistory.com/79&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://jongsky.tistory.com/79&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1763960572670&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;ubuntu mysql 설치 및 초기 세팅&quot; data-og-description=&quot;1. 글을 작성하게 된 계기 처음에는 docker를 이용해서 mysql를 구축을 진행했었다. 하지만 docker를 이용해서 mysql을 구축했을 때의 장단점이 있었다. 해당 내용은 나중에 리포트해보려고 한다. (심플&quot; data-og-host=&quot;jongsky.tistory.com&quot; data-og-source-url=&quot;https://jongsky.tistory.com/79&quot; data-og-url=&quot;https://jongsky.tistory.com/79&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/dlc7Mq/hyZOhuAxXe/BGkNnFAlQPT9DgZpiu2nLK/img.png?width=406&amp;amp;height=191&amp;amp;face=0_0_406_191,https://scrap.kakaocdn.net/dn/odeJG/hyZOaI2nmL/uVLJ21ZeFCcAdDUr5MH5dk/img.png?width=406&amp;amp;height=191&amp;amp;face=0_0_406_191&quot;&gt;&lt;a href=&quot;https://jongsky.tistory.com/79&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://jongsky.tistory.com/79&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/dlc7Mq/hyZOhuAxXe/BGkNnFAlQPT9DgZpiu2nLK/img.png?width=406&amp;amp;height=191&amp;amp;face=0_0_406_191,https://scrap.kakaocdn.net/dn/odeJG/hyZOaI2nmL/uVLJ21ZeFCcAdDUr5MH5dk/img.png?width=406&amp;amp;height=191&amp;amp;face=0_0_406_191');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;ubuntu mysql 설치 및 초기 세팅&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;1. 글을 작성하게 된 계기 처음에는 docker를 이용해서 mysql를 구축을 진행했었다. 하지만 docker를 이용해서 mysql을 구축했을 때의 장단점이 있었다. 해당 내용은 나중에 리포트해보려고 한다. (심플&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;jongsky.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$ sudo apt update&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$ sudo apt install mysql-server&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(선택)&amp;nbsp;$ sudo mysql_secure_installation&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보안 설정을 위해 다음 사항들을 물어본다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 비밀번호 강도 레벨 선택&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- root 계정 원격 접속 허용&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 테스트 DB 제거&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 변경 사항 적용&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$ sudo nano /etc/mysql/mysql.conf.d/mysqld.cnf&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;외부 접속 설정(포트포워딩을 위한 준비)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;bind-address 127.0.0.1 &amp;rarr; 0.0.0.0&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$ sudo ufw allow mysql&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$ sudo systemctl start mysql&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$ sudo ufw status&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$ sudo ufw enable # 방화벽 자체 활성화&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;# mysql 접속하기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$ sudo mysql -u root&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;# root 계정 비밀번호 설정하기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$ alter user 'root'@'localhost' identified by '비밀번호';&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;# 변경된 비밀번호 바로 적용하기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$ flush privileges;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;# 그 이후 포트포워딩 설정 위해 root 계정 이외에 계정 생성하기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$ select user, host from mysql.user;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$ create user '이름'@'%' identified by '비밀번호';&amp;nbsp; &amp;nbsp;# 모든 곳(%)에서 접속할 수 있는 계정 생성&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$ grant all privileges on *.* to '이름'@'%' with grant option;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;# 테스트 위해 데이터베이스도 생성해 주기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$ create databse '이름' default character set utf8mb4 collate utf8mb4_unicode_ci;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$ use '이름';&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;# MySQL 재실행하기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$ sudo systemctl restart mysql&lt;/p&gt;</description>
      <category>문제 및 이론 정리/기타</category>
      <author>hail2y</author>
      <guid isPermaLink="true">https://hail2y.tistory.com/287</guid>
      <comments>https://hail2y.tistory.com/287#entry287comment</comments>
      <pubDate>Mon, 24 Nov 2025 14:37:45 +0900</pubDate>
    </item>
    <item>
      <title>[Modeling] 식별자를 정의할 때 주의하는 경우 (인조식별자)</title>
      <link>https://hail2y.tistory.com/277</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;엔티티를 설계할 때 명확한 본질식별자가 있음에도 불구하고 본능적으로 인조식별자를 PK로 사용해 왔다. 인조식별자를 정의하는 경우는 이론적으로 알고 있었지만 식별자가 한개일 때도 불구하고 인조식별자를 택했기 때문에 올바른 설계법이 궁금했다. 그래서 이번에는 &lt;span style=&quot;color: #ee2323;&quot;&gt;인조식별자를 쓰더라도 추가로 보완해야 할 점&lt;/span&gt;에 대해 정리하고자 한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;1. 식별자 개념&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;원래 존재하는 속성이냐에 따라 본질식별자 / 인조식별자로 구분&lt;/li&gt;
&lt;li&gt;대표성 여부에 따라 주 식별자 / 대체(보조)식별자로 구분&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;엔티티에 원래 존재하는 속성인 사원번호, 주민등록번호 / 업무처리나 이벤트 성격의 데이터의 경우 회원 ID, 계좌번호처럼 ID나 일련번호 등을 부여하여 식별하는 경우 모두 본질식별자를 활용하는 예시다.&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;2. 인조식별자를 정의하는 경우&lt;/span&gt;&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;엔티티를 통합할 때 통합 대상 엔티티 식별자가 서로 다르거나, 데이터 집합 단위가 다른 경우
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;법인(법인등록번호), 개인(주민등록번호, 외국인등록번호 등), 사업자(사업자등록번호) 등 다양한 유형의 데이터 통합&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;복잡한 본질식별자의 상속을 대체하는 경우&lt;/li&gt;
&lt;li&gt;본질식별자가 개인정보 암호화 대상에 해당하는 경우
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;계좌번호, 카드번호는 개인정보 암호화 대상이므로 평문이 아닌 암호화된 데이터를 관리해야 하므로 인조식별자인 계좌관리번호나 카드관리번호 등을 추가하여 주 식별자를 정의하는 것이 일반적&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;본질식별자에 대한 데이터가 들어오지 않은 경우
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;거래처를 등록하여 업무를 처리해야 하는데 본질 식별자에 해당하는 사업자등록번호를 알 수 없을 때 사업자등록번호 대신 인조 식별자인 거래처번호를 주 식별자로 정의&amp;nbsp;&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1764&quot; data-origin-height=&quot;471&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cWHfUz/btsQ3o88tok/30QCXUvOPLbJEyk09tFWkK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cWHfUz/btsQ3o88tok/30QCXUvOPLbJEyk09tFWkK/img.png&quot; data-alt=&quot;핵심 데이터 모델링 p.154 3번 설명&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cWHfUz/btsQ3o88tok/30QCXUvOPLbJEyk09tFWkK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcWHfUz%2FbtsQ3o88tok%2F30QCXUvOPLbJEyk09tFWkK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1764&quot; height=&quot;471&quot; data-origin-width=&quot;1764&quot; data-origin-height=&quot;471&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;핵심 데이터 모델링 p.154 3번 설명&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 책에는 나오지 않았지만 다음의 경우도 적용할 수 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;업무상&lt;/li&gt;
&lt;li&gt;적당한 컬럼이 없는 경우&lt;/li&gt;
&lt;li&gt;컬럼이 너무 많은 경우&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; background-color: #f6e199;&quot;&gt; &amp;zwj;  3. 반드시 참고해야 할 핵심 조언&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1759394754489&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;1. 본질식별자는 엔티티를 대표하거나 변하지 않는 속성을 사용한다.

본질식별자를 주식별자로 하는 경우 주민등록번호보다는 사원번호처럼 엔티티를 대표하거나 변하지 않는 (식별자 특성에 더 적합한) 속성을 우선하는 것이 좋다. 사원번호가 주 식별자가 되는 경우 주민등록번호는 자연스럽게 대체식별자가 된다.

2. 인조식별자 아래 본질식별자를 대체식별자로 지정한다.

인조식별자를 주 식별자로 사용하면서 본질식별자를 식별하지 않은 경우를 종종 볼 수 있다. 결재 상신할 때 상신자가 상신(상신일시) 했을 때 본질식별자는 데이터를 발생하는 규칙을 제공하며 유일하게 데이터를 식별할 수 있는 기준을 제공한다. 본질식별자를 정확하게 정의하지 않았다면 엔티티의 핵심적인 정의가 누락되었다고 볼 수 있으며, 개발자가 데이터 집합을 자의적으로 해석하여 중복 데이터를 발생시킬 수 있는 여지를 주게 된다. 결재번호처럼 인조식별자를 주 식별자로 정의한 경우 ** 본질식별자인 상신자사원번호 + 결재일시를 대체식별자로 지정 **할 수 있다.

3. 본질식별자 또는 인조식별자가 주 식별자 역할이든지 대체식별자 역할이든지 데이터 발생 규칙을 정의하고, 실체무결성(Primary Key, Unique Key) 제약조건을 설계해야 한다.&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;이 내용이 필요했다. 인조식별자를 PK로 사용하는 것은 문제없으나, 본질식별자는 반드시 Unique 제약을 통해 유일성을 보장해야 한다는 설명이다. 상신자사원번호 + 결재일시를 복합 유일키로 설정해야 같은 시각에 결재를 두 번 상신했을 때 문제가 발생하지 않을 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #333333; font-family: 'Nanum Gothic';&quot;&gt;4. 성능&amp;nbsp;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;본질식별자가 단일 속성이라면 인조식별자 없이 그대로 사용해도 된다는 설명이었다. 그리고 복합키일 경우, 인조식별자를 사용한다고 하더라도 본질식별자를 복합 유일키/대체키로 지정하여 데이터 정합성을 지켜야 한다는 말이었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt; 그런데 인조식별자(INT)를 사용하는 것이 문자열보다도 성능이 더 좋을 수 있다는 얘기를 얼핏 들었다. 다시 찾아보니 그 말이 맞았다. 숫자는 컴퓨터 내부적으로 고정된 길이를 갖기 때문에 훨씬 빠르게 비교될 수 있고 메모리 효율성 역시 더 좋다는 이야기였다. 그렇기에 레코드 수가 매우 적은 테이블의 경우 문자열을 사용해도 큰 성능 문제는 없지만, 트랜잭션이 많거나 참조하는 테이블이 많은 경우 숫자형 인조식별자를 사용하는 것이 성능 최적화의 기본이라고 한다.&lt;/span&gt;&lt;span style=&quot;color: #333333; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;5. 결론&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;레코드 수가 적고 PK가 짧은 경우 가독성을 위해 본질식별자를 그대로 쓴다.&lt;/li&gt;
&lt;li&gt;관계 테이블일 경우 복합키를 그대로 써도 좋다. (데이터 유일성 보장이 핵심, 가독성)&lt;/li&gt;
&lt;li&gt;일반적인 경우 인조식별자를 쓰고 본질식별자는 대체키로 관리한다.&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>DB</category>
      <author>hail2y</author>
      <guid isPermaLink="true">https://hail2y.tistory.com/277</guid>
      <comments>https://hail2y.tistory.com/277#entry277comment</comments>
      <pubDate>Thu, 2 Oct 2025 17:58:26 +0900</pubDate>
    </item>
  </channel>
</rss>