CS
운영체제
CPU 캐시
메모리에서 가장 자주 사용되는 위치의 데이터를 갖고 있고, 크기는 작지만 빠른 메모리이다.
대부분의 메모리 접근은 특정한 위치의 근방에서 자주 일어나는 경향이 있기 때문에,
데이터를 크기는 작지만 속도가 빠른 캐시메모리에 복사해 두면 평균 메모리 접근 시간을 아낄 수 있다.
시간 지역성 - 최근 접근한 데이터에 다시 접근하는 경향
공간 지역성 - 최근 접근한 데이터에 주변 공간에 접근하는 경향
프로세서가 메인 메모리를 읽거나 쓰고자 할 때는,
먼저 그 주소에 해당하는 데이터가 캐시에 존재하는지를 살핀다.
만약 그 주소의 데이터가 캐시에 있으면 데이터를 캐시에서 직접 읽고, 그렇지 않으면 메인 메모리에 직접 접근한다.
이때 대부분의 프로세서는 메인 메모리에 직접 접근해서 전송된 데이터를 캐시에 복사해 넣음으로써
다음번에 같은 주소에 프로세서가 접근할 때 캐시에서 직접 읽고 쓸 수 있도록 한다.
한 프로세스 안에도 자주 사용하는 부분과 그렇지 않은 부분이 있기 때문에
운영체제는 프로세스를 페이지(Page)라는 단위로 나눠 관리한다.
주소가 키로 주어졌을 때 그 공간에 즉시 접근할 수 있다는 것은
캐시가 하드웨어로 구현한 해시 테이블(Hash table)과 같다는 의미다.
캐시가 빠른 이유는 자주 사용하는 데이터만을 담아두기 때문이기도 하지만,
해시 테이블의 시간 복잡도가 O(1)정도로 빠르기 때문이기도 하다.
LRU는 사용한지 더 오래된 데이터를 우선적으로 교체하는 정책으로,
운영체제의 프로세스 스케줄링이나 페이지 교체 알고리즘으로도 사용한다.
동기/비동기
호출된 함수가 작업 완료와 관계없이 return하여 제어권을 바로 넘긴다면 Non-Blocking
호출된 함수가 결과를 바로 리턴하지 않고 모든 작업을 완료하고 리턴한다면 Blocking
호출되는 함수의 작업 완료를 호출한 함수가 신경쓴다면 동기
호출되는 함수의 작업 완료를 호출한 함수가 신경쓰지 않는다면 비동기
예를 들면 동기/논블록킹과 비동기/논블록킹을 비교하다면
동기/논블록킹의 경우
논블록킹이기 때문에 호출한 함수가 호출된 함수가 작업이 완료되는 동안 다른 작업을 수행할 수 있습니다.
하지만 동기 방식이기 때문에 호출한 함수는 작업 완료가 이루어졌는지 주기적으로 확인하는 방식으로 작업 완료를 확인해야 합니다.
비동기/논블록킹의 경우
논블록킹이기 때문에 호출한 함수가 호출된 함수가 작업이 완료되는 동안 다른 작업을 수행할 수 있습니다.
비동기 방식이기 때문에 호출한 함수는 작업 완료가 이루어졌는지 확인할 필요가 없고,
호출된 함수에서 callback을 호출해서 작업완료를 알릴 수 있습니다.
callback 함수는 함수가 끝나고 난 뒤 실행되는 함수입니다.
callback 함수를 내부 인터페이스나 클래스로 정의하고
구현체인 callback 객체를 함수 호출시에 파라미터로 같이 넘깁니다.
호출된 함수는 작업 완료시에 callback 객체를 통해 callback 함수를 호출하여
완료시에 수행해야될 작업을 수행할 수 있다.
멀티스레드
특정 작업을 수행하는 소프트웨어를 프로그램이라고 합니다.
이 프로그램이 실제로 실행되어 OS로부터 CPU, 메모리와 같은 자원을 할당받으면 이것을 프로세스라고 합니다.
스레드는 프로세스를 구성하는 하나의 단위라고 할 수 있습니다.
하나의 프로세스에는 여러 스레드가 존재할 수 있습니다.
프로세스는 각각 독립된 (Code, Data, Stack, Heap으로 구성된) 메모리 영역을 할당받아 서로 다른 프로세스끼리는 일반적으로 서로의 영역을 침범할 수 없습니다.
하지만 스레드는 프로세스 내의 주소 공간이나 자원들을 공유하고 있습니다.
(각각 Stack 영역만 따로 할당받습니다.)
같은 자원을 공유할 수 있기 때문에 동시에 같은 자원을 두고 동시성 문제가 발생할 수 있습니다.
지금 당장은 두 가지 방법이 생각나는데,
Lock을 사용하는 방법
불변 객체를 사용하는 방법이 있습니다.
Lock을 사용하면 하나의 자원에 대해서 한 번에 하나의 스레드만 자원에 접근할 수 있도록 할 수 있습니다.
여러 스레드가 동시에 자원에 접근할 수 없으므로 동시성 이슈는 막을 수 있지만 병렬성은 낮아지게 됩니다.
불변 객체는 한 번 생성하면 그 상태가 변하지 않는 객체입니다.
불변 객체의 상태를 바꾸고 싶을 때는 새로운 불변 객체를 생성해야 합니다.
불변객체는 내부적으로 상태가 변하지 않기 때문에 Lock 없이도 동시성 이슈를 해결할 수 있습니다.
프로세스가 어떤 순서로 데이터에 접근하느냐에 따라 결과 값이 달라질 수 있는 상황을 경쟁 상태(race condition)라고 한다.
코드상에서 경쟁 조건이 발생할 수 있는 특정 부분을 critical section이라고 한다.
critical section problem를 해결하기 위해서는 몇가지 조건을 충족해야 한다.
Mutual exclution (상호 배제): 이미 한 프로세스가 critical section에서 작업중일 때 다른 프로세스는 critical section에 진입해서는 안 된다.
Progress (진행): critical section에서 작업중인 프로세스가 없다면 다른 프로세스가 critical section에 진입할 수 있어야 한다.
Bounded waiting (한정 대기): critical section에 진입하려는 프로세스가 무한하게 대기해서는 안 된다.
mutex locks은 여러 스레드가 공통 리소스에 접근하는 것을 제어하는 기법으로,
lock이 하나만 존재할 수 있는 locking 매커니즘을 따른다.
(참고로 'mutex’는 'MUTual EXclusion’을 줄인 말이다.)
이미 하나의 스레드가 critical section에서 작업중인 lock 상태에서 다른 스레드들은 critical section에 진입할 수 없도록 한다.
세마포어(Semaphore)는 여러 개의 프로세스나 스레드가 critical section에 진입할 수 있는 locking 매커니즘이다.
세마포어는 카운터를 이용해 동시에 리소스에 접근할 수 있는 프로세스를 제한한다.
물론 한 프로세스가 값을 변경할 때 다른 프로세스가 동시에 값을 변경하지는 못한다.
세마포어는 공유 자원에 세마포어의 변수만큼의 프로세스(또는 쓰레드)가 접근할 수 있습니다.
반면에 뮤텍스는 오직 1개만의 프로세스(또는 쓰레드)만 접근할 수 있습니다.
현재 수행중인 프로세스가 아닌 다른 프로세스가 세마포어를 해제할 수 있습니다.
하지만 뮤텍스는 락(lock)을 획득한 프로세스가 반드시 그 락을 해제해야 합니다.
트랜잭션을 작업을 한 단위로 커밋하고 롤백하기 위한 수단이고,
Lock은 동시성을 제어하기 위한 수단이다.
병렬 처리 효율이 감소하고 데드락이 발생할 수 있습니다.
데드락은 두 개의 스레드에서 서로가 가지고 있는 lock이 해제되기를 무한히 기다리는 상태를 말합니다.
데드락은 프로세스가 리소스를 점유하고 놓아주지 않거나, 어떠한 프로세스도 리소스를 점유하지 못하는 상태가 되어 프로그램이 멈추는 현상을 말한다.
# Deadlock Prevention
데드락을 방지한다는 것은 데드락 발생 조건 중 하나를 만족시키지 않음으로써 데드락이 발생하지 않도록 하는 것이다.
* 상호배제
* 점유와 대기
* 비선점
* 순환대기
를 모두 충족할 경우 데드락이 발생하게 됩니다.
데드락을 방지하는 것은 장치 효율과 시스템 성능을 떨어트리는 문제가 있다.
# Deadlock Avoidance
데드락을 피하는 것은 데드락이 발생할 것 같을 때는 아예 리소스를 할당하지 않는 것이다.
데드락 가능성은 포인터로 자원 할당 그래프(Resource allocation graph)를 구현해 판단한다.
##Banker’s Algorithm
banker’s algorithm은 Dijkstra가 고안한 데드락 회피 알고리즘이다.
이는 프로세스가 리소스를 요청할 때마다 수행되며, 만약 리소스를 할당했을 때 데드락이 발생하는지 시뮬레이션한다.
# Recovery from Deadlock
만약 시스템이 데드락을 방지하거나 회피하지 못했고, 데드락이 발생했다면 데드락으로부터 복구되어야 한다. 이때는 어떤 프로세스를 종료시킬지 정하는 것이 중요해진다. 여기에는 몇가지 판단 기준이 있다:
1.프로세스의 중요도
2.프로세스가 얼마나 오래 실행됐는가
3.얼마나 많은 리소스를 사용했는가
4.프로세스가 작업을 마치기 위해 얼마나 많은 리소스가 필요한가
5.프로세스가 종료되기 위해 얼마나 많은 리소스가 필요한가
6.프로세스가 batch인가 interactive한가
# Resource Preemption
데드락을 해결하기 위해 리소스 선점(Preemption) 방식을 사용할 때는 다음과 같은 이슈가 있다.
Selecting a victim: 어떤 프로세스를 종료시킬 지 결정한다.
Rollback: 데드락이 발생하기 전 상태로 되돌린다.
Starvation: 계속 같은 프로세스가 victim이 될 수 있다. 이 경우 기아(Starvation) 문제가 발생한다.
네트워크
Application
Presentation
Session
Transport
Network
Datalink
Physical
계층을 나눈 이유는 통신이 일어나는 과정이 단계별로 파악할 수 있기 때문이다.
7단계 중 특정한 곳에 이상이 생기면 다른 단계의 장비 및 소프트웨어를 건들이지 않고도 이상이 생긴 단계만 고칠 수 있기 때문이다.
예를 들면 집에서 PC에서 인터넷 연결을 할 수 없을 때,
모든 PC에서 문제가 생긴 경우, 라우터나 인터넷 공급 회선을 점검하면 되고,
한 장비에만 이상이 있는 경우,
해당 장비만 확인하면 된다.
TCP
3-way handshake 방식으로 클라이언트와 서버간의 연결형 서비스이기 때문에 신뢰성이 높고,
혼잡 제어나 흐름 제어와 같은 기능도 가지고 있습니다.
하지만 연결형이라는 특성과 부가적인 기능 때문에 UDP에 비해서는 느립니다.
UDP
비 연결형 방식이기 때문에 연결을 설정하고 해제하는 과정이 존재하지 않습니다.
따라서 수신여부를 확인할 수 없기 때문에 데이터 전송을 보장할 수 없습니다.
TCP에서 제공하는 흐름 제어나 혼잡제어와 같은 기능도 없지만
그렇기 때문에 TCP보다는 빠릅니다.
HTTP 1.1
* HTTP pipelining
연결 당 기본적으로 하나의 요청만 처리할 수 있는데
두개 이상의 요청을 담아 네트워크 지연을 줄이는 방식
* 브라우저에 도메인 주소를 입력한다.
* 도메인의 ip 주소를 알아야한다, 도메인 네임을 ip 주소로 변경하기 위해 DNS 프로토콜이 사용된다.
* 로컬 DNS 서버 -> 인터넷 제공자의 DNS 서버 -> 루트 DNS 서버
* ARP를 사용
* HTTP 메시지를 보내기 위한 TCP 소켓을 생성
* three-way-handshake를 거쳐 서버와 tcp 연결을 구축해야한다.
* HTTPS 통신이라면 TLS handshake 과정도 거쳐야 한다.
* 클라이언트가 랜덤 문자열을 생성하여 서버로 전송
* 서버는 ssl 인증서와 서버 랜덤 문자열을 클라이언트에 전송
* ssl 인증서를 공인 CA의 공개키로 복호화하여 서버의 공개키를 획득하여 대칭키를 공개키로 암호화하여 전송한다.
* 서버는 서버의 개인키로 대칭키를 얻어, 서버와 클라이언트가 동일한 대칭키를 사용하여 통신한다.
* 클라이언트는 HTTP 메시지를 만들어 URL, HTTP 메소드 등을 담아 서버에 전송한다.
* 서버는 요청에 맞는 로직을 처리하고, 응답할 HTTP 메세지를 생성하고 결과를 body에 담아 클라이언트에 전송한다.
* 응답 값을 브라우저에서 확인한다.