8 minute read

1. locality

  locality는 temporal locality와 spatial locality가 있다. temporal locality란 어떤 아이템의 일부분이 참조되면, 그부분은 짧은시간내에 재참조될 확률이 높은 성질을 의미한다. spatial locality란 어떤 아이템의 일부분이 참조되면, 그부분의 근처 주소는 짧은시간내에 재참조될 확률이 높은 성질을 의미한다.

2. Memory hirachy

  메모리(저장장치)를 여러 계층으로 구성하는 기법을 말한다. 상위 계층에 어떤 데이터가 존재한다고 가정했을때, 이 데이터는 반드시 하위계층에 존재해야하는 측징을 지닌다.

  만약 상위계층에 원하는 데이터가 이미 존재하는경우 이를 hit 라고하고 hit가 될 확률을 hit-rate라고 한다. 반대로 hit가 되지 않을 확률은 miss rate 라고 한다. 상위계층에 엑세스하고 hit 여부를 판단하는 시간을 hit time 이라 한다. 만약 hit가 아니라면 하위계층으로부터 상위계층으로 데이터를 가지고 와야하는데 이때 걸리는시간을 miss panalty 라고 한다.

  locality 의 성질과, hit rate, hit time, miss panalty를 고려해서 프로세서와 가까워 질수록 엑세스 속도가 빨라지고 저장 공간이 작은 메모리로 구성한다. 이를 통해 엑세스 속도를 높이고 비용을 줄일수 있다.

3. SRAM과 DRAM

  SRAM은 접근속도가 우수하지만 집적도가 낮으며 (6개에서 8개의 트렌지스터) 높은 전력을 필요로 하고 가격이 비싼 단점이 있다. SRAM은 전력이 유지되는한 정보가 유지된다.   DRAM은 집적도가 높고, 저전력, 가격이 저렴하지만 속도가 느리다. DRAM 계열의 메모리의 셀은 행과 열로 구성되어있다. 따라서 메모리의 주소를 지정시 행과 열을 구분해주는 신호가 필요한데 이를 CAS, RAS라고 불린다. CPU가 원하는 주소로 해석하여 RAS를 통해 해당하는 행의 데이터들을 읽어온후에 CAS를 통해 원하는 데이터를 찝어낸다.   DRAM은 여러개의 셀 어레이로 구성되어있는데 하나하나를 뱅크라고 한다. 뱅크들은 독립적인 회로로 구성되어있기 때문에 뱅크수가 많을수록 hit 가능성이 높아진다. DRAM은 SRAM과 다르게 주기적으로 refresh (메모리에 있는 데이터를 읽어서 다시 쓰기) 해줘야 데이터가 보존된다. refresh를 위한 버퍼를 DRAM내에서 이용해서 지연을 최대로 줄인다.   DRAM을 선택하는 가장 중요한 기준은 용량이지만, 서버 구축시에는 내장애성, 성능, 저전력등의 요소들이 고려된다. cpu와 메인보드의 칩셋이 복수의 채널을 지원하면, 같은 종류의 DRAM을 사용해서 데이터폭을 넓히고 성능을 높일수 있다. 각 프로세서의 메모리 구성을 일치시킨다.   DRAM의 대역폭을 계산하는 예로 ddr3-1600이 있을때 다음과 같이 계산할수 있다. ddr3-1600 의 경우 ddr3, 1600mhz로 해석 할수 있고 데이터전송속도 1600mhz * 8byte = 12,800mb = 12.8GB 의 대역폭을 가진다.

4. SDRAM

  SDRAM은 DRAM에다 클럭을 집어넣은것을 말한다. 클럭을 통해 ram과 프로세서간의 싱크를 맞추기위한 타임을 절약할수 있다. 대표적인예로 DDR 이 있다. DDR은 한번에 클럭에 rising edge, falling edge가 발생하여, 대역폭을 2배로 늘릴수 있다.

5. RAM 관련 용어

  슬롯은 메인보드에 있는 메모리 삽입구를 뜻한다.   ECC 메모리란 오류 보정 부호가 추가된 메모리를 말한다. 메모리는 고장이 잘나지 않지만 서버운영댓수가 수백대를 넘어가면 오류를 볼수 있는 확률이 높아진다. ECC 메모리의 경우 오류가 발생하면 비트 반전오류를 스스로 잡는다. 일반 메모리의 경우 운영체제선에서 비정상 종료 된다. 원칙적으로 ECC메모리와 일반 메모리를 섞어 쓸수 없다. 다만 바이오스에서 설정해서 같이 쓸수 있는 경우가 있다.   메모리 컨트롤러가 메모리의 DRAM에서 데이터를 입출력하는 단위를 랭크라고 하며, 싱글랭크, 듀얼랭크, 쿼드랭크가 있다. 랭크가 커질수록 단위가 커져 성능이 향상되긴하지만, 메모리 컨트롤러가 다를수 있는 랭크수가 한정되어있기 때문에 이점을 고려한다.   UDIMM 는 버퍼가 없는 메모리, RDIMM는 클럭과 주소제어를 위한 버퍼회로가 존재하는 메모리고, 엑세스 속도는 떨어지나 안정성이 뛰어나다. LRDIMM는 모든 통신이 버퍼를 이용해서 운용됨, 메인보드에 장착 가능한 모듈수를 늘리고 이에 따라 대용량과 고속전송이 가능한 메모리이다.   LV는 일반메모리보다 전압을 낮추어 저전력을 실현한 메모리이다.

6. 메모리 인터리빙

  서로 다른 메모리 뱅크에 번갈아가며 연속적인 주소를 부여하여, 바로 다음 메모리 주소에 접근할수 있게 하는 성능 향상 기법을 말한다.

EEPROM

  플래시메모리는 EEPROM의 한종류이다. 디스크보다 빠른 속도와 좋은 내구성을 지니며 저전력이고 소형화에 유리하다. 쓰기를 할수록 수명이 닳기 때문에 WEAR-LEVELING을 통해 모든 셀에 대해 균등히 쓰기가 이루어지도록 한다.

  NOR flash는 랜덤엑세스가 가능하며 임베디드시스템에서 rom에 많이 사용된다. NAND flash는 block-at-a-time 접근 방식이라 느리지만 상대적으로 비용이 저렴하여 스토리지, usb에 많이 사용된다.

DISK

  DISK 메모리는 자기장을 활용한 저장장치이다. (쉽게 말해 하드디스크) 디스크는 여러개의 플래터(판)로 구성되어있으며 분당 5400~15000번 회전하며 필요한 데이터를 탐색하거나 저장한다.

각각의 플래터는 수천개의 트랙으로 구성되어있으며 하나의 트랙은 여러개의 섹터로 구분되어있다. 섹터는 512~4096 바이트로 구성할수 있다.

  디스크에서 원하는 데이터를 읽어오기 위해 걸리는시간은 큐 대기, seek, rotational latency, data transfer, controller overhead 에 걸리는 시간의 합니다. 먼저 헤드를 움직여서 원하는 트랙위에 위치시켜야 한다. 이때 걸리는 시간을 seek time이라고 한다. 원하는 트랙에 멈추면 플래터를 돌려서 원하는 섹터를 찾는데 이때 걸리는 시간을 rotational latency라 한다. 마지막으로 disk access, transfer time + overhead를 거쳐서 원하는 데이터를 얻거나 저장한다. 또한 디스크도 seek time과 rotational delay를 최소화하기 위해 캐시를 운용한다.

Average rotational latency

Average rotational latency = 0.5 rotation / x rpm

disk access time

average seek time + rotational latency + transfer time + overhead

종류

  SATA 하드디스크는 하루 8시간정도의 가동 용도로 사용하며 접속 가능수는 1대, 호스트 컨트롤러와 1:1 이다. SAS 하드디스크는 24시간 365일 가동할 용도로 사용한다. 128대 ~ 16만대 (sas 익스펜더 사용시), 까지 접속을 지원하며 다중 링크, SCSI 커맨드, 스타형 토플러지 구조를 가진다.

  FC 하드디스크: 초고속으로 동작한다 엔터프라이즈 용도로 사용한다. 126 ~ 1678만대의 접속을 지원하며, 다중 링크, SCSI 커맨드, 접속 가능수, 루프형 토플러지를 지닌다.

  그밖에 온라인 오프라인으로 오가는 디스크, 장기보존 목적으로 사용되는 니어라인 하드디스크가 있있다. 최근에 가정용 컴퓨터에서 빼노울수 없는 SSD도 있다. 빠르고, 저전력이지만 보증이 약하다. slc (소자하나당 1bit), mlc(소자하나당 2bit)등이 있으며 slc가 수명이 더 좋다.

  엔터프라이즈 플레시 메모리 스토리지 라는 NAND를 활용한 초고속 저장장치도 있다. pci express 로 주로 연결한다.

RAID

  redundent array of inexpensive disk의 약자로 여분의 디스크를 활용해서 성능, 데이터 무결성을 향상시키는 기법이다.

  디스크 용량이 대량으로 필요할때는 RAID5나 RAID10이 주로 사용된다. RAID5는 디스크 용량을 많이 확보할수 있지만 성능이 느리며, RAID10은 용량이 적지만 속도가 빠른 특징을 지닌다. RAID5가 스트라이핑수가 많아 읽기 속도에 있어서는 우위에 슬수 있으나, 패리티 처리 부하때문에 쓰기 속도는 저하될수밖에 없다.

  RAID6는 RAID5와 비교했을때 패리티정보를 하나 더쓰기 때문에 좋다고 볼수 있으나 3개의 디스크 고장시 복구할때 비용이 더 발생하는 단점이 있다.

RAID 0 (스트라이핑)

두개의 디스크에 데이터를 나누어 쓰고 읽는다. 성능은 이론상으로 2배 증가하지만 하나의 디스크가 고장나면 복구할수 없다. 다만 디스크가 2개 고장났을때

RAID 1 (미러링)

하나의 디스크에 정보를 저장할때 똑같은 정보를 다른디스크에 저장한다. 디스크 한개가 고장나더라도 무결성을 지킬수 있다.

RAID 2 , 3, 4

  3개 이상의 디스크를 필요로 한다. 무결성을 위해서 하나의 디스크를 골라 두 디스크에 저장된 데이터의 ECC를 디스크에 저장한다. 2, 3, 4의 차이는 비트, 바이트, 블록 단위의 ECC의 차이가 된다. 2에서 4로 갈수록 하나의 파일을 한번에 읽어올수 있는 확률이 높아 성능이 높다. 패리티디스크 드라이브에 문제 발생시 데이터 복구가 불가능하다. 용량과 스피드는 디스크 갯수 N - 1 에 비례한다.

RAID 5

  RAID 4와 다르게 패리티를 모든 디스크에 기록하는 기법, 어떤 디스크가 고장나더라도 패리티 정보를 이용해 데이터를 복구할수 있다. RAID 0와 비교했을때 쓰기 속도면에서 비슷하나, 읽기 성능이 저하되고 저장공간이 작아지는 단점이 있다.

RAID 6

  RAID 5에서 한단계 더나아가 이중으로 패리티 정보를 저장하는 기법이다. 따라서 2개의 디스크가 고장나도 데이터를 복구할수 있는 장점이 있다. 다만 RAID 5에서 성능과 용량은 더 하락할수 밖에 없다.

RAID 10, 50, 60

  RAID 1, 5, 6 한 친구들을 그대로 스트라이핑 하는 기법이다. RAID 1, 5, 6 각각은 오류복구 기능이 있기 때문에 각각의 디스크에 문제가 발생해도 무결성을 지킬수 있다.

RAID 01

  RAID 0한 친구를 미러링 하는 기법, 속도와 안정성을 모두 지킬수 있으나, 문제가 생기면 RAID한 디스크를 이용해 데이터 복구를 진행하므로 주로 RAID10를 쓴다.

RAID 예제 (1TB 12개를 사용할때)

RAID 0 1TB * 12 = 12TB

RAID 1 1TB * 12 / 2 = 3000GB = 6TB

RAID 5 500 * (12 - 1) = 5500GB = 11TB

RAID 6 500 * (12 - 2) = 5000GB = 10TB

RAID 10 1TB * 12 / 2 = 3000GB = 6TB

RAID 01 1TB * 12 / 2 = 3000GB = 6TB

RAID 50 1TB * ((3 - 1) * 4) = 8TB

1TB * ((4 - 1) * 3) = 9TB 1TB * ((6 - 1) * 2) = 10TB

IOPS

1초당 처리할수 있는 데이터 읽기, 쓰기 성능을 일컬어 말한다.

캐시 메모리

[##_Image kage@bPI083/btqDQcpwDRM/kPH5gbPqadXiXPPtao3TUK/img.png alignCenter data-origin-width=”369” data-origin-height=”359” data-ke-mobilestyle=”widthContent”     _##]

  locality에 의해 낮은 계층의 데이터를 높은 계층의 데이터보다 자주 참조하는 현상을 볼수 있다. 따라서 계층이 낮아질수록 속도가 빨라지고 용량이 작아지는 한편 계층이 높아질수록 용량이 커지고 속도가 느려지게 memory hierachy를 짜는것이 중요하다. i7 프로세서의 경우 예를들면, L1 cache는 32Kib, L2 cache는 256 KiB, L3 cache는 8MiB를 가진다. 캐시메모리를 구현할때는 어떻게 캐시안에 데이터가 있는것을 알아내고, 어떻게 가지고 올것인가를 생각해봐야 한다. 최근 CPU는 locality를 활용한 prediction을 통해 hit rate는 95%에 이른다.

Direct mapped memory

  각각의 메인 메모리 블록의 주소를 활용하여 하나의 캐시의 메모리 블록으로 mapping 되게하는 캐싱 기법이다. 캐시메모리의 index는 다음과 같이 구할수 있다.

        cache index = (block address) modulo (num of blocks in the cache)

  캐시메모리의 공간은 한정적이기때문에 메인메모리의 여러 블록이 하나의 캐시메모리에 매칭되는 상황이 발생한다. 이때 캐시메모리에 들어있는 블록이 어떤 메인메모리의 블록인지 어떻게 알수 있을까? 모든 cache block는 tag라는 메인메모리의 주소의 상위 비트 (캐시에서 index로 사용되지 않고 같은 캐시메모리에 mapping 되는 블록들을 구분할수 있는 비트)들을 저장하는 공간을 가지고 있어서 이를 통해 구별이 가능하다. 이렇게 캐시메모리는 index를 나타내는 비트들, tag를 나타내는 비트들과 data를 구성하는 비트들, 유효성을 검증하기 위한 비트로 구성되어있다.

  예를 들어 32bit 프로세서 환경에서, 용량이 16KiB인 캐시메모리를 4word block으로 direct-mapped cache를 구현하고자 할때 총비트수를 계산해보자. 우선 32bit 환경에서의 4-word = 4 * 32 bit = 2 ^ 7 bit 이다. 캐시메모리의 용량인 16KiB = 2 ^ 17 bit 이다. 이를 통해 캐시메모리의 요구되는 index 수는 2 ^ 10개 임을 알수 있다. 메모리 주소 하나는 1byte에 매칭 된다는 사실을 인지하면서 4-word 로 구축하는것을 생각해보면 1-word로 구축할때 메모리주소가 4씩 증가하는반면에 4-word의 경우 16씩 증가한다. 이를 byte-offset이라 부르며 4-word 환경에서 4bit가 된다. byte-offset과 index에 필요한 비트수를 알고 있으므로 tag에 필요한 비트수는 32 - 10 - 4 = 18 bit 임을 알수 있다.

[##_Image kage@cdAk0v/btqDQsyUuZL/TVlPRiFXQzOCeyOALS17R1/img.jpg alignCenter data-origin-width=”960” data-origin-height=”960” width=”643” height=”643” data-ke-mobilestyle=”widthContent”     _##]

  이를 통해 필요한 캐쉬메모리에 필요한 비트수는 2 ^ 10 * (128 + 18 + 1) = 147 kbit로 계산할수 있다. 이를 공식화해보면 다음과 같다. 

required bits = (data field size + tag field size + valid bits) * num of rows

  한 블록의 크기는 16 byte 이고 64개 block으로 구성되어있을때, 1200번 주소의 블록은 캐시메모리의 몇번째 블록에 속하게 될까. 주소하나하난 1byte이므로 1200번때의 주소가 가리키는 블록은 75번째 블록으로 볼수 있다. 캐시 메모리는 64개 이므로 modulo 연산을 통해 11번째로 들어가게 되는것이다. block의 사이즈가 커질수록 spatial locality가 증가하기 때문에 miss rate가 감소하는 양상을 보인지만 캐시사이즈의 상당한부분 만큼 크기가 커지면 miss rate가 치솟는 경향을 보인다. miss로 인해 발생하는 패널티는 overhead가 작지 않기 때문에 trade-off point를 찾는것이 중요하다.

Handling Cache Misses

  cache miss가 발생하면 hit 상황가 달리 cache 메모리에 메인메모리의 데이터를 가지고 오는 과정등의 절차가 필요하다. cache miss가 발생하면 interrupt가 걸려 현재 레지스터의 상황을 임시로 저장한후 메모리로 부터 해당하는 block을 읽어온후 캐시메모리에 저장하고 valid bit를 1로 바꿔준다. 이후 저장했던 상태를 다시불러온후 작업을 진행하게 된다.

Handling Writes

  만약 캐시메모리에 메인메모리의 블록이 로딩된후, 메인메모리의 블록 내용이 바뀐다면 어떻게 될까 이때 메모리과 캐시메모리는 inconsistent하기 때문에 추가적인 조치가 필요하다. 가장 쉬운 방법은 메인메모리의 블록의 값이 갱신되는순간 캐시메모리의 값도 동시에 갱신하는것이다. 이를 write-through 방식이라고 한다. 하지만 이 과정은 약 100번의 프로세서 사이클이므로 성능저하현상이 심각하다. 이문제에 대한 하나의 해결책은 write buffer 큐를 활용하는것이다.

write-back 방식은 값의 변경 발생시 캐시메모리에 우선 기록하고, 캐시메모리에서 값이 해제될때 하위 계층 방향으로 점진적으로 기록하는 방식이다. write-through 방식에 비해 좋은 성능을 보이지만 구현의 난이도가 높다.

Leave a comment