[웹 개발자를 위한 대규모 서비스를 지탱하는 기술]Chapter 3

zzarbttoo·2021년 8월 4일
0

이 글은 절판도서 "웹 개발자를 위한 대규모 서비스를 지탱하는 기술" 을 개인적인 용도로 정리한 글입니다. 모든 내용을 정리한 것이 아니라 필요한 부분만 정리했다는 점 양해 부탁드립니다

문제/오류가 있을 시 댓글로 알려주면 감사하겠습니다

OS 캐시와 분산

대규모 데이터를 효율적으로 처리하는 원리


OS캐시로 대규모 데이터를 처리할 수 없을 때 분산을 고려하는 것이 좋다

| OS 캐시의 구조

  • OS는 메모리를 이용해 디스크 액세스를 줄인다 , OS 캐시
  • Linux의 경우 페이지 캐시나 파일 캐시(부적절 단어), 버퍼 캐시라고 하는 캐시 구조를 갖추고 있다
  • 페이징 구조 : 선형 어드레스 -> 페이징 구조를 거쳐 -> 물리 어드레스

| 가상 메모리 구조

  • OS 는 프로세스에서 메모리를 요청받으면 페이지를 1개 이상, 필요한 만큼 페이지를 확보해서 프로세스에 넘기는 작업을 수행한다
  • OS는 메모리를 프로세스에 직접 넘기는 것이 아니라 커널 내에서 메모리를 추상화 한다
  • 메모리에 접근할 때도 디스크와 마찬가지로 1바이트식 엑세스 하는 것이 아니라 4KB 정도 블록으로 확보해 프로세스에 넘긴다
  • 이 때 하나의 블록을 페이지라고 한다

| Linux의 페이지 캐시 원리 (+ 현대의 OS 모두 마찬가지)

  • OS는 확보한 페이지를 메모리상에 계속 확보해두는 기능을 가지고 있다

  • 디스크에서 4KB 크기 블록 읽음 -> 블록을 메모리에 쓴다 -> OS는 메모리 주소(가상 메모리 주소)를 프로세스에 알려준다-> 프로세스가 데이터에 엑세스 -> 데이터를 전부 처리해 불필요하게 됐어도 커널이 한 번 할당된 메모리를 해제하지 않고 남겨놓음 -> 다른 프로세스 남겨둔 페이지를 사용하게 된다(디스크에 또 읽으러 갈 필요가 없다, 페이지 캐시)

  • 페이지 캐시 : 즉 커널이 한 번 할당한 메모리를 해제하지 않고 계속 남겨두는 것

  • 윈도우도 마찬가지인데 그래서 느리다고 재부팅하면 오히려 캐시 메모리가 다 사라져 더 느려질 수 있다고 한다(!실화냐)

| VFS

  • 디스크를 조작하는 디바이스 드라이버(실제 하드웨어 조작)와 OS 사이에는 파일 시스템이 끼어있다
  • 파일 시스템 위에는 VFS(가상 파일 시스템, Virtual File System)이라는 추상화 레이어가 있다
  • 파일 시스템은 다양한 함수를 갖추고 있으며, 인터페이스를 통일하는 것이 VFS의 역할
  • 파일 시스템, 디스크의 종류와 관계 없이 동일한 구조로 캐싱이 이루어진다
  • VFS는 파일 시스템 구현의 추상화와 성능에 관련된 페이지 캐시 부분

| Linux는 페이지 단위로 디스크를 캐싱한다

  • 디스크 상에서 메모리보다 큰 파일을 불러올 때 캐싱을 할 수 없다고 생각할 수 있다
  • 하지만 페이징단위로 캐싱이 되기 때문에 읽어들인 특정 파일의 일부분은 캐싱할 수 있고, 캐싱 단위가 페이지이다
  • 페이징 단위로 캐싱하기 때문에 파일 캐시라는 말은 명확하지 않다
  • LRU로 가장 오래된 것을 파기하고 가장 새로운 것을 남겨좋는 형태로 되었으므로 최근에 읽은 부분이 캐시에 남게 되고 과거에 읽은 부분은 파기 된다 -> DB 도 구동할수록 캐시가 최적화되어 시간이 오래될수록 부하나 I/O 가 내려가는 특성을 보인다
  • 파일을 i 노드, 파일 중 읽을 위치를 오프셋 이렇게 한 쌍 키로 이용해 캐싱을 진행하고, Radix Tree를 이용해 파일이 커져도 캐시 탐색속도가 느려지지 않도록 한다

| 메모리가 비어있으면 캐싱

  • 리눅스는 메모리가 비어있으면 전부 캐싱을 하고, 메모리가 남아있지 않다면 오래된 캐시를 버리고 프로세스에 메모리를 확보하준다
  • sar -r (systat 패키지 하위)를 이용해 1초에 한번 현재 메모리의 상태 출력(메모리 이용률, 캐시 이용률이 높아도 놀라지 말 것)
  • 메모리를 늘려서 IO 부하를 줄일 수 있지만, 쉽지는 않을거다~~~
  • OS 부팅 직후에는 커널이 디스크를 그다지 않으므로 캐시로 데이터가 유입되지 않지만, 특정 파일을 read 하면 이를 쭉 캐싱한다(투과적)
*sar 명령어를 잘 사용하면 각종 지표를 확인할 수 있다 
- sar 1 3 : 1초 간격으로 3회 
- sar -u ->부하분산을 고려하면 user/system/iowait/idle이 중요한 지표가 된다 
- sar -q : 실행 큐에 쌓여있는 프로세스 수, 시스템 상 프로세스 사이즈, load average 등 참조 가능 
- sar -r : 메모리 사용 현황 확인 
- sar -W : 스왑 발생 상황 확인 

| I/O 부하를 줄이는 방법

| 캐시를 전제로 한 I/O 줄이는 방법

  • 데이터 규모에 비해 물리 메모리가 크면 전부 캐싱할 수 있으므로 이 점을 생각할 것(압축 저장 등)
  • 메모리를 늘릴 수 있으면 늘려볼 것(단 경제적인 면을 고려)

| 캐시로 해결될 수 없는 규모의 경우 복수 서버로 확장

  • AP 서버 증설 : CPU 부하를 줄이고 분산시키기 위해서
  • DB 서버를 늘릴 때 : 부하 x, 캐시 용량을 늘리고자 할 때, 효율을 높이고자 할 때 늘림(늘리면 좋다는 말과 맞지 않음)
  • 캐시 용량을 늘리는 것은 대수를 늘린다고 늘어나는 것이 아니다(단순 데이터를 복사해서 대수를 늘리면 부족한 캐시 용량도 같이 복붙됨)

| 국소성(locality)을 살리는 분산

  • 데이터에 대한 액세스 패턴을 고려해서 분산시키는 것이 국소성을 고려한 분산
  • 사용하는 기능에 따라 액세스 패턴이 달라지게 된다

| 파티셔닝

1) 테이블 단위 분할 : 한대였던 DB 서버를 여러 대의 서버로 분할하는 방법을 말한다
ex) 테이블 1,2 | 3,4 로 분할해 각기 다른 서버로 관리(테이블 단위 분할에 의한 파티셔닝)

  • 1, 2는 같이 액세스 하는 경우가 많아 같은 서버에 위치
  • 3, 4는 크기가 크기 때문에 1,2와 함께 같은 서버에 저장하면 전부 캐싱할 수 없고 둘이 있을때만 메모리에 모두 올릴 수 있음
  • 어플리케이션을 필요한 테이블에 따라 다른 서버에 요청할 수 있도록 교체해야함

2) 테이블 데이터 분할
ex) id a~c까지는 1서버, d~f 까지는 2서버 .....

  • 구현상 간단함
  • 분할의 입도를 크거나 작게 조절할 때 데이터를 한번 병합해야 한다는 문제가 있다

| 요청 패턴을 섬으로 분할

ex)HTTP 요청의 User~Agent, Url 을 보고 통상 사용자면 섬1, 일부 API 요청이면 섬3, Google 봇 등이면 섬2 등으로 사용자에 따라 나눈 방식

  • 사람은 광범위하게 액세스/후미진 곳에도 액세스하고, 동일하게 방문하지 않을 경우가 있기 때문에 이럴 때 캐시가 작용하기 어렵다
  • 봇은 빨리 응답을 할 필요는 없다
  • 사람의 대부분은 최상위 페이지, 인기 엔트리등에 액세스가 집중이 되므로 빈번하게 참조되는 부분은 캐싱하기 쉽다
  • 이렇게 캐싱하기 쉬운 요청, 캐싱하기 어려운 요청을 처리하는 섬을 나누게 된다
  • 봇을 나눈 이용은 생각보다 봇에 의한 요청이 많았기 때문

| 페이지 캐시를 고려한 운용의 기본 규칙

  • OS 가동 직후에 서버를 투입하지 않는다(갑자기 배치를 하면 디스크 액세스만 발생해 서버가 내려가는 사태 발생 가능!)
  • 성능 테스트/부하 테스트도 최초의 캐시가 최적화 되어있지 않은 단계와 최적화 된 단계의 속도가 완전 다르다

profile
나는야 누워있는 개발머신

0개의 댓글