numad 정의

  • NUMA는 Non-Uniformed Memory Access(불균일 기억장치 접근)의 약자
  • CPU 소켓이 하나가 있는 데스크탑이 아니고, 여러개의 CPU 소켓을 가지고 있는 서버에서 메모리에 효과적으로 접근하기 위해서 사용되는 기술
  • 여러개의 CPU 소켓이있는 환경에서, 하나의 프로세서가 전체 메모리에 접근하게 될 경우 메모리 버스를 점유하게 되고 다른 프로세스들은 대기하여야 하는 상황이 발생
  • 위와 같이 메모리 버스를 독점하는 문제를 해결하기 위해서, 각 CPU 마다 지역 전용적으로 사용하는 지역 메모리(Local Memory)으로 할당하고, 지역 메모리를 사용하는 CPU 코어들을 묶어서 하나의 NUMA 노드로 할당
  • numad는 자동 NUMA 친화도 관리 데몬
  • numad는 백그라운드 데몬과 같은 형태로 시스템에 상주
  • 사전 배치 조언 서비스를 통해 여러 작업 관리 시스템 쿼리에 대해 적절한 CPU와 메모리 리소스의 초기 바인딩을 제공 가능
  • numad는 /proc 파일 시스템에서 주기적으로 정보에 액세스하여 각 노드에서 사용 가능한 시스템 리소스를 모니터링
  • 서버의 실제 하드웨어 사진 → 파랑색 : CPU, 빨강색 : CPU와 가까운 메모리 영역

numad의 장점

  • 리눅스에서는 numad를 통해 NUMA 메모리 할당 정책을 직접 설정하지 않고도 메모리 지역성을 높일 수 있는 방법을 제공
  • 시스템의 NUMA 토폴로지 및 리소스 사용량을 모니터링하여 동적으로 NUMA 리소스 할당 및 관리 (즉 시스템 성능)를 향상
  • 시스템 작업량에 따라 numad는 성능 기준의 최대 50% 까지 성능을 개선 가능
  • 일정 수준의 지정된 리소스 사용량을 유지하며 필요에 따라 NUMA 노드 간 프로세스를 이동하여 리소스 할당을 재조정
  • numad는 시스템의 NUMA 노드의 하위 집합에서 중요한 프로세스를 배치 및 격리하여 최적의 NUMA 성능을 구현
  • numad는 주로 상당한 리소스 양을 소비하고 전체 시스템 리소스의 하위 집합에 있는 프로세스에서 장기간 실행 중인 프로세스가 있는 시스템에 이점을 제공
  • 프로세스 A와 B 두개가 동작하고 있는 시스템 가정
    1. default 정책에 따라 메모리 지역성을 높인 상태로 운영 가능
    2. 각 프로세스가 필요로 하는 메모리가 여러 노드에 걸쳐서 존재하는 것 가능
    3. 프로세스가 필요로 하는 메모리가 노드 하나의 메모리 크기보다 메모리의 크기보다 작은 경우 노드 하나의 메모리 크기보다 작기 때문에 충분히 메모리 지역성을 높일 수 있음
    4. 다수의 프로세스를 관리해야 하는 경우 numactl 등을 사용해 수작업으로 실행하기 어려움
    5. numad → 하나의 프로세스가 필요로 하는 메모리를 하나의 노드에서만 할당 받을 수 있도록 설정할 수 있기에 메모리의 지역성을 높이고 성능을 최적화 가능

numad의 단점

  • 여러 NUMA 노드의 리소스를 소비하는 애플리케이션에 유용하지만 시스템 리소스 소비율이 증가하면 numad에서 얻을 수 있는 효과는 감소
  • 프로세스의 실행 시간이 몇 분이거나 많은 리소스를 소비하지 않는 경우 numad는 성능을 개선하지 않을 가능성이 높음
  • 대형 메모리 데이터베이스와 같은 지속적으로 예상치 못한 메모리 액세스 패턴을 갖는 시스템도 numad의 사용으로 혜택을 얻을 가능성이 낮음
  • numad가 대체적으로 좋은 성능을 낼 수 있도록 도와주지만 문제점이 발생할 수 있는 상황 존재
    1. 프로세스 A는 interleaved 정책으로 실행되어 각각의 노드에서 메모리를 순차적으로 할당
    2. 이때 프로세스 B가 실행되고, 프로세스 B는 메모리 요청이 노드 하나의 크기보다 작아서 numad에 의해 한쪽 노드에 바인딩되고 해당 노드로부터 메모리를 할당
    3. 문제는 프로세스 B가 지역성을 높이기 위해 Node 1에서 메모리 할당을 너무 많이 받아서 더 이상 프로세스 A에 할당해 줄 메모리가 없을 때 발생
    4. 프로세스 A는 워크로드에 따라 interleave로 실행되었지만 numad가 지역성을 너무 높인 탓에 메모리 불균형이 발생
    5. numad는 사용자가 신경 쓰지 않아도 메모리 할당 문제를 해결해 주긴 하지만 경우에 따라서는 오히려 성능에 좋지 않은 영향을 미칠 수 있음
    6. 현재 시스템의 워크로드에 따라 numad를 켜는 것이 더 좋을지 아닐지 판단이 필요

NUMA 아키텍처(NUMA Architecture)

1. NUMA

  • Non-Uniform Memory Access의 약자 → 불균형 메모리 접근이라는 뜻
  • 멀티 프로세서 환경에서 적용하는 메모리 접근 방식
  • 로컬 메모리로의 접근이 동시에 이뤄질 수 있음
  • 0번 CPU가 자신의 로컬 메모리에 접근하는 동안 1번 CPU도 자신의 메모리에 접근할 수 있어서 성능 향상
  • 로컬 메모리의 양이 모자라면 다른 CPU에 붙어있는 메모리에 접근이 필요하게 되고, 이때 메모리 접근에 시간이 소요되어 예상치 못한 성능 저하를 경험하게 됨
  • 로컬 메모리에서 얼마나 많이 메모리 접근이 일어나느냐가 성능 향상의 가장 중요한 포인트
  • NUMA 아키텍처에서의 메모리 접근

2. UMA

  • Uniform Memory Access의 약자 → 균형 메모리 접근이라는 뜻
  • NUMA와 반대되는 개념으로 초창기 아키텍처
  • 모든 프로세서가 공용 BUS를 이용해서 메모리에 접근
  • UMA의 문제점은 BUS를 동시에 사용할 수 없는것
  • 0번 소켓에 있는 CPU가 메모리에 접근하는 동안 1번 소켓에 있는 CPU는 메모리에 접근 X
  • UMA 아키텍처에서의 메모리 접근

리눅스에서 NUMA 확인

  • 리눅스에는 NUMA를 활용하기 위한 코드를 구현해 놓았고 명령어를 통해서 현재 시스템의 NUMA 상태를 확인

1. numactl 명령어

  • NUMA와 관련된 정책을 확인하거나 설정할 때 사용

  • --show 명령으로 NUMA 정책을 확인

    # numactl 명령어가 없다면 패키지 install 필요
    $ yum install numactl -y
    
    $ numactl --show
    
    # 기본 정책이 default
    # default는 현재 사용 중인 프로세스가 포함된 노드에서 메모리를 먼저 가져다가 사용하는 방식
    policy: default
    preferred node: current
    physcpubind: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 
    25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 
    51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
    cpubind: 0 1
    nodebind: 0 1
    membind: 0 1  
  • NUMA와 관련된 메모리 할당 정책
    1. default 정책
      • 별도의 설정을 하지 않는 한 모든 프로세스에 적용
      • 현재 실행되고 있는 프로세스가 포함된 노드에서 먼저 메모리를 할당 받아 사용
    2. bind 정책
      • 특정 프로세스를 특정 노드에 바인딩시키는 방식
      • 0번 노드에 할당하면 0번 노드에서만 메모리를 활용 가능
      • 메모리의 지역성이 좋아지기 때문에 메모리 접근 속도가 빨라서 성능이 좋아짐
      • bind에 설정한 노드의 메모리가 부족하면 성능이 급격히 나빠질 수 있음
    3. preferred 정책
      • bind와 비슷하지만 선호하는 노드를 설정
      • bind가 반드시 설정한 노드에서 메모리를 활용 → preferred는 가능한 한 설정한 노드로부터 메모리를 할당 받음
    4. interleaved 정책
      • 다수의 노드에서 거의 동일한 비율로 메모리를 할당
      • Round-Robin 정책에 따라 다수의 노드로부터 한 번씩 돌아가면서 메모리를 할당 받음
  • numactl -H 명령어 설명

    1. available

      • NUMA 노드가 2개로 구성되어 있음
    2. node 숫자 cpus

      • 각각의 노드 0, 1에 해당하는 CPU의 번호와 각 노드에 할당된 메모리의 크기
      • CPU 번호는 시스템마다 조금씩 다를 수 있음
    3. node distances

      • 각 노드의 메모리에 접근하는 데 걸리는 시간

      • 각각의 로컬 메모리에 접근할 때 소요되는 시간이 10

      • 리모트 메모리, 즉 0번 노드에서 1번 노드에 있는 메모리에 접근하거나, 1번 노드에서 0번 노드에 있는 메모리에 접근할 때 소요되는 시간이 21

      • node distances는 절대적인 시간이 아니라 상대적인 값

      • 리모트 메모리에 접근하는 시간이 로컬 메모리에 접근하는 데 필요한 시간의 2.1배

        $ numactl -H
        # NUMA 노드가 2개로 구성
        available: 2 nodes (0-1)
        
        # node 0의 속성
        node 0 cpus: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 36 37 38 39 40 
        41 42 43 44 45 46 47 48 49 50 51 52 53
        node 0 size: 128192 MB
        node 0 free: 126040 MB
        
        # node 1의 속성
        node 1 cpus: 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 54 55 
        56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
        node 1 size: 128993 MB
        node 1 free: 126084 MB
        
        # 각 노드의 메모리에 접근하는 데 걸리는 시간
        node distances:
        node   0   1
        0:  10  21
        1:  21  10



2. numastat 명령어

  • NUMA 환경에서 현재 시스템에 할당된 메모리의 상태를 확인
  • NUMA 아키텍처에서 메모리 불균형 상태를 확인
  • 어느 한쪽 노드의 메모리 사용률이 높으면 메모리 할당 정책에 따라 swap을 사용하는 경우 발생
  • 전체 메모리에는 free 영역이 많이 있는데도 불구하고 메모리 할당 정책에 따라 한쪽 노드에서 메모리 할당이 과하게 일어나면 swap이 사용 → numastat 명령어로 확인 가능
  • numastat -cm 명령어 출력

3. 프로세스가 어떤 메모리 할당 정책으로 실행되었는지 확인

  • /proc//numa_maps은 현재 동작 중인 프로세스의 메모리 할당 정책과 관련된 정보가 기록
    $ cat 21631/numa_maps
    55ca074c5000 default file=/usr/libexec/postfix/pickup mapped=47 N0=47 kernelpagesize_kB=4
    55ca07706000 default file=/usr/libexec/postfix/pickup anon=2 dirty=2 N1=2 kernelpagesize_kB=4
    55ca07708000 default file=/usr/libexec/postfix/pickup anon=1 dirty=1 N1=1 kernelpagesize_kB=4
    55ca07709000 default anon=1 dirty=1 N1=1 kernelpagesize_kB=4
    55ca080ae000 default heap anon=18 dirty=18 N1=18 kernelpagesize_kB=4
    7fdae8bb5000 default file=/usr/lib64/libnss_sss.so.2 mapped=7 mapmax=10 N1=7 kernelpagesize_kB=4
    7fdae8bbd000 default file=/usr/lib64/libnss_sss.so.2
    7fdae8dbc000 default file=/usr/lib64/libnss_sss.so.2 anon=1 dirty=1 N1=1 kernelpagesize_kB=4
    7fdae8dbd000 default file=/usr/lib64/libnss_sss.so.2 anon=1 dirty=1 N1=1 kernelpagesize_kB=4
    7fdae8dbe000 default file=/usr/lib64/libnss_files-2.17.so mapped=9 mapmax=47 N1=9 kernelpagesize_kB=4
    7fdae8dca000 default file=/usr/lib64/libnss_files-2.17.so
    7fdae8fc9000 default file=/usr/lib64/libnss_files-2.17.so anon=1 dirty=1 N1=1 kernelpagesize_kB=4
    7fdae8fca000 default file=/usr/lib64/libnss_files-2.17.so anon=1 dirty=1 N1=1 kernelpagesize_kB=4
    7fdae8fcb000 default

※ 로컬 엑세스(Local Access)

  • 각각의 CPU마다 별도의 메모리가 있는데 이와 같이 메모리에 접근하는 방식

※ 노드(Node)

  • CPU와 메모리를 합쳐서 노드(Node)라고 함

※ 리모트 엑세스(Remote Access)

  • NUMA에서는 자신의 메모리가 아닌 다른 노드에 있는 메모리에도 접근하는 방식
  • VIRT, RES, SHR는 프로세스에서 중요한 요소로, 현재 프로세스가 사용하고 있는 메모리와 관련된 값


VIRT → task가 사용하는 virtual memory의 전체 용량을 의미

  • 프로세스에 할당된 가상 메모리 전체의 크기
  • VIRT는 프로그램이 현재 얼마나 많은 메모리를 접근할 수 있는지를 출력
  • VIRT는 물리 메모리의 사용한 공간을 의미하지는 않음
  • VIRT = SWAP + RES
  • VIRT는 실제로는 할당되지 않은 가상의 공간(swap)이기 때문에 VIRT의 해당 값이 크다고 해도 문제되지는 않음

1. VIRT의 Memory Commit

  • 프로세스가 커널로부터 사용을 예약 받은 메모리 → 프로세스는 malloc()과 같은 시스템 콜로 자신이 필요로 하는 메모리의 영역을 할당해 줄것을 요청
  • 프로세스가 요청한 내용은 커널이 가용할 수 있는 공간이 있다면 성공 메시지와 함께 해당 프로세스가 사용할 수 있도록 가상의 메모리 주소를 전달
  • malloc을 통해 할당 받은 가상 메모리는 물리 메모리에 해당 영역이 할당된 상태는 아님
  • Memory Commit의 참고 URL : memory commit과 vm.overcommit 커널 파라미터

2. VIRT의 malloc 테스트 코드

  • malloc_test.c 파일을 생성

    $ vi malloc_test.c
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    
    # define MEGABYTE 1024*1024
    
    int main(){
       void *myblock = NULL;
       int count = 0;
    
       while(1){
           myblock = (void *) malloc(MEGABYTE);
    
           if(!myblock){
               printf("Error!");
               break;
           }
    
           printf("Currently allocating %d MB\n", (++count)*MEGABYTE);
           sleep(1);
       }
       exit(0);
    }
    
    # malloc_test 파일을 malloc_test 실행 파일로 만듦
    $ gcc -o malloc_test malloc_test.c
    $ ls -al
    -rwxr-xr-x  1 root root 8520 Oct 11 17:53 malloc_test
    -rw-r--r--  1 root root  395 Oct 11 17:47 malloc_test.c

3. VIRT의 malloc 테스트 실행 결과

  • malloc() 으로 메모리 영역을 요청한 후에 아무것도 하지 않음

  • top 명령으로 해당 프로세스의 변화 확인 → 시간이 지나면서 VIRT는 계속해서 높아지지만, RES는 늘어나지 않음

    # 위에서 생성한 malloc_test 실행파일 실행
    $ ./malloc_test
    Currently allocating 1 MB
    Currently allocating 2 MB
    Currently allocating 3 MB
    Currently allocating 4 MB
    Currently allocating 5 MB
    # [...생략...]
    
    # 다른 터미널로 해당 내용 확인
    $ top -b -n 1 | grep -i malloc
    65246 root      20   0   33000    348    276 S   0.0  0.0   0:00.00 malloc_test
    
    $ top -b -n 1 | grep -i malloc
    65246 root      20   0   40196    608    400 S   0.0  0.0   0:00.00 malloc_test
    
    $ top -b -n 1 | grep -i malloc
    65246 root      20   0   47392    608    400 S   0.0  0.0   0:00.00 malloc_test
    
    $ top -b -n 1 | grep -i malloc
    65246 root      20   0   55616    608    400 S   0.0  0.0   0:00.00 malloc_test



RES → task가 사용하고 있는 physical memory의 양을 의미

  • RES는 VIRT가 사용하고 있는 실제 물리 메모리의 크기
  • 일반적으로 RES는 VIRT보다 작은 값을 출력
  • RES는 실제로 메모리를 쓰고 있음
  • RES는 SWAP 값 제외
  • RES는 메모리 점유율이 높은 프로세스를 찾기 위해서는 RES 영역이 높은 프로세스를 찾아야함

1. 프로세스가 VIRT 할당 받은 메모리를 RES에 올려서 사용

  • 프로세스가 할당받은 메모리 영역에 실제로 쓰기 작업을 하면 Page fault가 발생
  • Page fault가 발생하면 커널은 실제 물리 메모리에 프로세스의 가상 메모리 공간을 매핑 → Page Table이라고 불리는 커널의 전역 변수로 관리
  • 물리 메모리에 바인딩된영역이 RES로 계산

2. RES의 malloc 테스트

  • 이전의 malloc_test.c 파일을 수정

    $ vi malloc_test.c
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    
    # define MEGABYTE 1024*1024
    
    int main(){
       void *myblock = NULL;
       int count = 0;
    
       while(1){
           myblock = (void *) malloc(MEGABYTE);
    
           if(!myblock){
               printf("Error!");
               break;
           }
    
           printf("Currently allocating %d MB\n", (++count)*MEGABYTE);
           memset(myblock, 1, MEGABYTE);
           sleep(1);
      }
      exit(0);
    }
    
    # malloc_test 파일을 malloc_test 실행 파일로 만듦
    $ gcc -o malloc_test malloc_test.c
    $ ls -al
    -rwxr-xr-x  1 root root 8568 Oct 11 18:02 malloc_test
    -rw-r--r--  1 root root  433 Oct 11 18:01 malloc_test.c

3. RES의 malloc 테스트 실행 결과

  • malloc()을 단독으로 요청하는 것이 아니라 할당 받은 메모리에 쓰기함 → RES 영역이 VIRT 영역 늘어나는 비율과 비슷하게 늘어남

  • 즉 해당 파일은 메모리 사용과 관련해서 VIRT 뿐만 아니라 실제 메모리를 쓰는 RES를 확인할 수 있음

  • top 명령으로 해당 프로세스의 변화 확인 → 시간이 지나면서 VIRT과 함께 RES가 계속해서 높아짐

    # 위에서 생성한 malloc_test 실행파일 실행
    $ ./malloc_test
    Currently allocating 1 MB
    Currently allocating 2 MB
    Currently allocating 3 MB
    Currently allocating 4 MB
    Currently allocating 5 MB
    # [...생략...]
    
    # 다른 터미널로 해당 내용 확인
    $ top -b -n 1 | grep -i malloc
    66652 root      20   0   21692  17772    400 S   0.0  0.0   0:00.01 malloc_test
    
    $ top -b -n 1 | grep -i malloc
    66652 root      20   0   35056  31236    400 S   0.0  0.0   0:00.04 malloc_test
    
    $ top -b -n 1 | grep -i malloc
    66652 root      20   0   45336  41532    400 S   0.0  0.0   0:00.05 malloc_test
    
    $ top -b -n 1 | grep -i malloc
    66652 root      20   0   57672  53940    400 S   0.0  0.0   0:00.07 malloc_test
    
    $ top -b -n 1 | grep -i malloc
    66652 root      20   0   62812  58956    400 S   0.0  0.0   0:00.08 malloc_test

※ Page Faults

  • 프로그램이 자신의 주소 공간에는 존재하지만 시스템의 RAM에는 현재 없는 데이터나 코드에 접근 시도하였을 경우 발생하는 현상
  • Page Faults 발생하면 운영 체제는 데이터를 메모리로 가져와서 Page Faults가 전혀 발생하지 않은 것처럼 프로그램이 계속적으로 작동하게 해줌

※ Page Table

  • 가상 주소와 물리 메모리 주소의 매핑 테이블
  • 프로세스마다 하나씩 존재하게 되며, 메인 메모리 (RAM)에 상주
  • 많은 프로세스가 구동될 수록, 페이지 테이블로 인한 메인 메모리 사용이 커짐을 의미


SHR → 다른 프로세스와 공유하고 있는 shared memory의 양을 의미

  • SHR는 공유하고 있는 메모리 크기
  • SHR 영역에 대표적으로 등록되는 내용은 라이브러리(library) → 대부분의 리눅스 프로세스는 glibc라는 라이브러리를 참고하기에 해당 라이브러리를 공유 메모리에 올려서 사용
  • 공유메모리에 올려놓고 사용하지 않고, 사용하는 프로세스마다 glibc의 내용을 메모리에 올려서 사용하는 것은 공간 낭비
  • 커널은 공유메모리라는 개념을 도입했고, 다수의 프로세스가 함께 사용하는 라이브러리는 공유메모리 영역에 올려서 함께 사용하도록 구현
  • VIRT는 실제는 할당되지 않는 가상공간이기 때문에 해당 값이 크다고 해도 문제가 되지 않음
  • 실제 사용하고 있는 메모리는 RES 영역이기 때문에 메모리 점유율이 높은 프로세스를 찾기 위해서는 RES 영역이 높은 프로세스를 찾아야함
  • 매핑된 라이브러리 전체는 VIRT와 SHR에 포함되어도, 실제 사용 중인 함수가 있는 일부 메모리만 RES에 포함
  • 커널은 메모리 낭비를 막기위해 공유 메모리라는 개념을 도입했고, 다수의 프로세스가 함께 사용하는 라이브러리는 공유 메모리 영역에 올려서 함께 사용하도록 구현

'OS(운영체제)' 카테고리의 다른 글

NUMAD (메모리 할당 관리)  (0) 2022.06.29
OOM Killer와 OOM Scoring  (0) 2022.06.29
  • OOM Killer는 희생시킬 프로세스를 고르기 위해서 각 프로세스에 점수를 매기는 과정을 진행

  • OOM Killer는 메모리가 부족해졌을 때 프로세스 중 oom_score가 가장 높은 점수를 받은 순서대로 프로세스를 죽임

  • oom_score 점수는 기본적으로 프로세스에게 할당된 메모리의 양으로 점수가 메겨짐 → 해당 프로세스로부터 fork()된 자식 프로세스들의 메모리도 추가됨

  • 오래 돌고 있는 프로세스의 경우 oom_score 점수를 낮춰주고, 프로세스 순위가 낮은 프로세스는 oom_score 점수를 높여서 사용할 필요가 있음

  • 중요하게 취급되어지는 프로세스들(superuser에 의해서 실행되거나, 하드웨어와 직접적인 관련이 있는)은 값을 크게 낮춰줘서 OOM Killer를 통해서 kill되지 않도록 해야함

  • 각 서비스의 oom_score를 확인하는 방식(PID → 프로세스 ID)

    # 기본 형식
    $ cat /proc/<pid>/oom_score
    oom_socre 출력
    
    # 19862 프로세스의 oom_score 확인 
    $ cat /proc/19862/oom_score
    12

※ nice
프로세스의 우선 순위를 낮춰주는 점수를 의미

oom_score_adj, oom_score, oom_adj 커널 파라미터

1. oom_score_adj

  • 앱이 포그라운드(foreground)에 있는지, 백그라운드(background)에 있는지로 결정
  • 정확한 값은 앱이 백그라운드 서비스를 가지고 있는지, 얼마나 오랫동안 포그라운드에 빠져 있는지에 따라 달라짐
  • oom_score_adj 는 -1000 ~ 1000 의 값을 가지며, 낮은 값 일수록 우선순위에서 밀려남
  • 프로세스가 OOM Killer 에 의해 죽지 않길 원한다면 oom_score 를 조정하는게 아니라 oom_score_adj 값을 변경해야함

2. oom_score

  • 기본적으로 프로세스에게 할당된 메모리의 양으로 점수가 메겨짐

3. oom_adj

  • -17 ~ 15 의 값을 가지며, 낮은 값 일수록 우선순위에서 밀려남
  • -17이면 OOM을 완전히 비활성화시킴
    /proc/<pid>/oom_adj
    /proc/<pid>/oom_score
    /proc/<pid>/oom_score_adj


OOM Killer의 대상에서 벗어나기

  • OOM Killer를 끄는 것은 불가능

  • 서비스의 안정성을 위해서 꺼지면 안 될 프로세스도 존재 → 특정한 작업을 하고 있던 worker 프로세스

  • OOM Killer를 직접적으로 끌 수는 없지만, OOM Killer의 scoring를 통해 OOM Killer가 멈추는 대상은 벗어날수 있음

  • /proc//oom_adj 값을 -17로 설정 → -17 값은 OOM_DISABLE의 상수 값

    $ echo -17 > /proc/<pid>/oom_adj
  • /proc/oom_scoring_adj 값을 -1000으로 설정

  • -1000 값으로 지정하는 것은 OOM Scoring을 비활성화한다기보다는 충분히 낮은 값을 주어서 OOM Killer에 벗어남

    $ echo -1000 > /proc/<pid>/oom_adj



메모리 관련해서 리눅스에서 실행(kill) 하는 순서

  1. alloc_pages
  2. out_of_memory
  3. select_bad_process
  4. oom_evaluate_task
  5. oom_badness


OOM Killer 관련 함수

1. select_bad_process 함수

  • bad 프로세스를 선택

  • select_bad_process 함수 내용

    static void select_bad_process(struct oom_control *oc)
    {
    if (is_memcg_oom(oc))
        mem_cgroup_scan_tasks(oc->memcg, oom_evaluate_task, oc);
    else {
        struct task_struct *p;
    
          // RCU: Read-Copy Update
        rcu_read_lock();
    
        for_each_process(p)
            if (oom_evaluate_task(p, oc))
                break;
        rcu_read_unlock();
    }
    
    oc->chosen_points = oc->chosen_points * 1000 / oc->totalpages;
    }

2. oom_evaluate_task 함수

  • oom 선정된 프로세스가 OOM Killer를 통해 멈춰되 되는지 검증

  • oom_evaluate_task 함수 내용

    static int oom_evaluate_task(struct task_struct *task, void *arg)
    {
      struct oom_control *oc = arg;
      unsigned long points;
    
      if (oom_unkillable_task(task, NULL, oc->nodemask))
          goto next;
      /*
       * This task already has access to memory reserves and is being killed.
       * Don't allow any other task to have access to the reserves unless
       * the task has MMF_OOM_SKIP because chances that it would release
       * any memory is quite low.
       */
      if (!is_sysrq_oom(oc) && tsk_is_oom_victim(task)) {
          if (test_bit(MMF_OOM_SKIP, &task->signal->oom_mm->flags))
              goto next;
          goto abort;
      }
    
      /*
       * If task is allocating a lot of memory and has been marked to be
       * killed first if it triggers an oom, then select it.
       */
      if (oom_task_origin(task)) {
          points = ULONG_MAX;
          goto select;
      }
    
      points = oom_badness(task, NULL, oc->nodemask, oc->totalpages);
      if (!points || points < oc->chosen_points)
          goto next;
    
      /* Prefer thread group leaders for display purposes */
      if (points == oc->chosen_points && thread_group_leader(oc->chosen))
          goto next;
    select:
      if (oc->chosen)
          put_task_struct(oc->chosen);
      get_task_struct(task);
      oc->chosen = task;
      oc->chosen_points = points;
    next:
      return 0;
    abort:
      if (oc->chosen)
          put_task_struct(oc->chosen);
      oc->chosen = (void *)-1UL;
      return 1;
    }

3. oom_badness 함수

  • kill 했을 때 가장 높은 메모리를 확보할 수 있는 task 인 경우, 높은 점수를 return 한다는 개념

  • oom_badness() 함수가 리턴해주는 점수가 가장 높은 task가 bad_process로 선정 되어 죽게 됨

  • oom_score_adj 라는 값을 oom_badness 에서 LONG_MIN 을 리턴하기 위해 사용 → LONG_MIN 을 리턴한다는 개념은 낮은 점수를 줘서 kill 하지 못하게 하겠다는 의미

  • RSS (프로세스가 사용하고 있는 물리 메모리) + 프로세스의 스왑 메모리 + (프로세스의 pagetable / page_size) 의 값이 프로세스 (task) 의 점수 (point) 가 됨

  • 해당 코드만 보면 프로세스가 점유하고 있는 메모리가 클 경우 score가 높아진다고 이해 가능

  • oom_badness 함수 내용

    /**
    * oom_badness - heuristic function to determine which candidate task to kill
    * @p: task struct of which task we should calculate
    * @totalpages: total present RAM allowed for page allocation
    *
    * The heuristic for determining which task to kill is made to be as simple and
    * predictable as possible.  The goal is to return the highest value for the
    * task consuming the most memory to avoid subsequent oom failures.
    */
    long oom_badness(struct task_struct *p, unsigned long totalpages)
    {
      long points;
      long adj;
    
      if (oom_unkillable_task(p))
          return LONG_MIN;
    
      p = find_lock_task_mm(p);
      if (!p)
          return LONG_MIN;
    
      /*
       * Do not even consider tasks which are explicitly marked oom
       * unkillable or have been already oom reaped or the are in
       * the middle of vfork
       */
      adj = (long)p->signal->oom_score_adj;
      if (adj == OOM_SCORE_ADJ_MIN ||
              test_bit(MMF_OOM_SKIP, &p->mm->flags) ||
              in_vfork(p)) {
          task_unlock(p);
          return LONG_MIN;
      }
    
      /*
       * The baseline for the badness score is the proportion of RAM that each
       * task's rss, pagetable and swap space use.
       */
      points = get_mm_rss(p->mm) + get_mm_counter(p->mm, MM_SWAPENTS) +
          mm_pgtables_bytes(p->mm) / PAGE_SIZE;
      task_unlock(p);
    
      /* Normalize to oom_score_adj units */
      adj *= totalpages / 1000;
      points += adj;
    
      return points;
    }

4. get_mm_rss 함수

  • get_mm_rss() 함수를 사용하여 여유 메모리(free memory)가 얼마나 되는지 추정
    static inline unsigned long get_mm_rss(struct mm_struct *mm)
    {
      return get_mm_counter(mm, MM_FILEPAGES) +
          get_mm_counter(mm, MM_ANONPAGES) +
          get_mm_counter(mm, MM_SHMEMPAGES);
    }

5. get_mm_counter 함수

  • get_mm_counter 함수를 통해 swap 메모리(swap memory)가 얼마나 되는지 추정

    static inline unsigned long get_mm_counter(struct mm_struct *mm, int member)
    {
      long val = atomic_long_read(&mm->rss_stat.count[member]);
    
      #ifdef SPLIT_RSS_COUNTING
      /*
       * counter is updated in asynchronous manner and may go to minus.
       * But it's never be expected number for users.
       */
      if (val < 0)
          val = 0;
      #endif
      return (unsigned long)val;
    }

  • 리눅스 OS 서버에서 현재 사용 중인 메모리 사용량을 확인하고 캐시 메모리 사용량이 많은 경우 이를 비워서 시스템 효율을 높임
  • /proc/sys/vm/drop을 비움으로써 buff/cache 메모리 항목이 비워지게 됨
  • 캐시는 느린 장치의 데이터를 빠른 장치에 임시 보관해두고 사용함으로써 성능을 높이는 것이 목적 → HIT(적중률)가 낮은 경우엔 캐시를 사용하는 것이 부정적인 영향을 미침
  • 대량의 파일이 관리되는 서버의 파일 cache hit가 낮은데 비해 buffer / cache 메모리 사용량이 높을 경우 해당 cache 기능을 끄거나 주기적으로 비움으로써 성능을 개선 가능
  • 서비스 운영 환경에서는 drop_caches를 하는 것은 위험
  • 기본적으로 memory reclame을 하여 여유 메모리 확보하므로 테스트 등 특별한 경우에만 사용하면됨


/proc/sys/vm/drop_caches에 숫자를 추가하여 리눅스 캐시 메모리 관리

1. pagecache 해제 명령어 (echo 1 > /proc/sys/vm/drop_caches)

$ free -m
              total       used       free     shared    buffers     cached
 Mem:          1999       1983         15        392         90       1490
 -/+ buffers/cache:        402       1596
 Swap:         2047          5       2042

 $ echo 1 > /proc/sys/vm/drop_caches

 $ free -m
             total       used       free     shared    buffers     cached
 Mem:          1999        956       1042        392          8        539
 -/+ buffers/cache:        408       1590
 Swap:         2047          5       2042

2. dentry 및 inode 캐시메모리 해제 명령어 (echo 2 > /proc/sys/vm/drop_caches)

$ echo 2 > /proc/sys/vm/drop_caches

3. pagecache, dentry, inode 캐시메모리 모두 해제 명령어 (echo 3 > /proc/sys/vm/drop_caches)

$ free -m
             total       used       free     shared    buffers     cached
 Mem:          1999       1011        987        392         36        609
 -/+ buffers/cache:        365       1633
 Swap:         2047          5       2042

 $ echo 3 > /proc/sys/vm/drop_caches

 $ free -m
             total       used       free     shared    buffers     cached
 Mem:          1999        875       1123        392         11        511
 -/+ buffers/cache:        352       1646
 Swap:         2047          5       2042



크론탭(crontab)을 사용하여 시스템이 주기적으로 메모리 관리

$ crontab -e 
 # 크론탭 편집 모드에서 아래와 같이 입력
 # 매일 새벽 3시에 시스템이 자동으로 전체 캐시 메모리를 비우는 명령
0 3 * * * sync && echo 3 > /proc/sys/vm/drop_caches



리눅스 캐시 메모리와 연결돤 용어 정리

1. pagecache

  • 리눅스 파일 I/O의 성능 향상을 위해 페이지 캐시라는 메모리 영역을 만들어 사용
  • 상대적으로 느린 디스크로의 접근을 최대한 피하기 위해서 사용하는 영역
  • 파일의 내용을 페이지 캐시 영역에 저장시켰다가 다시 한번 동일한 파일 접근이 일어나면 디스크에서 읽지 않고 페이지 캐시에서 읽어서 제공해 주는 방식
  • pachecache 확인 테스트

    1. 파일을 읽기 전의 메모리 양을 free로 확인 → cached 영역이 78516 KB 확인

    2. 24 KB 정도 되는 파일을 cat 명령어로 읽은 후 메모리 양을 확인 → 24KB 만큼 cached 영역이 늘어남을 확인 가능


2. dentry

  • directory entry의 줄임말로 /usr/share 같은 경로에서 usr과 share를 지칭.
  • Dentry는 해당 디렉토리가 포함하고 있는 디렉토리와 파일정보를 보유하고 있음
  • dentry는 경로명 탐색을 위한 캐시 역할도 수행한다고 알려져 있음
  • 빠른 데이터 접근을 위해 Slab의 자료구조에 추가되어 사용

3. inode

  • 모든 파일이나 디렉토리에는 1개의 inode를 가지고있음(1개의 inode는 64byte로 이루어짐)
  • 각 inode에는 파일의 소유권, 허가권, 파일 종류 등의 정보, 파일의 실제 데이터가 어디에 있는지 위치(=주소) 보유
  • inode가 모여있는 공간이 inode 블록 → (전체 디스크의 1%정도를 차지)
  • 빠른 데이터 접근을 위해 Slab의 자료구조에 추가되어 사용
  • inode 확인 명령어 ( ls- il )

1. 현재 사용중인 커널 버전 확인

$ uname -r

2. 설치 가능한 커널 패키지 확인

$ yum list kernel --shwduplicates

3. 원하는 커널 패키지 업그레이드

  • 가장 최신 커널 패키지 설치가 아닌 경우에 사용
  • 만약 최신 커널 패키지 업그레이드를 원하는 경우에는 yum update -y kernel을 하면 됨
    $ yum install kernel-3.10.0-1160.36.2.el7

4. 현재 설정된 부팅 1순위 확인

$ grub2-editenv list

5. 업데이트된 커널로 부팅할 수 있도록 설정

  • 현재 설정된 부팅 1순위 커널이 부팅될 수 있도록 설정
    $ grub2-set-default 0
    $ grub2-editenv list

6. 업데이트된 커널로 재부팅

$ reboot

7. 업그레이드한 커널으로 부팅되었는지 확인

$ uname -r

8. GRUB Menu에서 Kernel Entry가 어떻게 나올지 확인 (부팅 우선순위 확인)

$ cat /etc/grub2.cfg | grep "menuentry " | awk -F"'" '{print $2}'
CentOS Linux (3.10.0-1160.36.2.el7.x86_64) 7 (Core)                    # Entry 0
CentOS Linux (3.10.0-1160.25.1.el7.x86_64) 7 (Core)                    # Entry 1
CentOS Linux (0-rescue-47e970e504d7415d8539a0173fc7a670) 7 (Core)      # Entry 2

9. 부팅 1순위 변경

  • 커널 업그레이드 이전 버전의 커널로 부팅할 수 있게 변경
    $ grub2-set-default 1
    $ grub2-editenv list

10. 업데이트된 커널로 재부팅

$ reboot

11. 업그레이드한 커널으로 부팅되었는지 확인

$ uname -r

  • openssl 버전이 낮아서 인증서 검증에 실패하거나 보안 이슈가 발생할 수 있기에 업그레이드 필요

1. 기존 Openssl 삭제

  • 아래의 명령어를 입력하여 기존 Openssl를 삭제
    $ yum remove openssl -y
    Loaded plugins: fastestmirror
    Resolving Dependencies
    ...중략...
    Complete!

2. Openssl 1.1.1o 다운로드

  • 아래의 명령어를 입력하여 Openssl 1.1.1o를 다운로드

    $ wget --no-check-certificate https://www.openssl.org/source/openssl-1.1.1o.tar.gz
    --2022-06-28 10:24:33--  https://www.openssl.org/source/openssl-1.1.1o.tar.gz
    Resolving www.openssl.org (www.openssl.org)... 23.65.57.54, 2600:1410:2000:19a::c1e, 2600:1410:2000:19c::c1e
    Connecting to www.openssl.org (www.openssl.org)|23.65.57.54|:443... connected.
    WARNING: cannot verify www.openssl.org's certificate, issued by ‘/C=US/O=Let's Encrypt/CN=R3’:
    Issued certificate has expired.
    HTTP request sent, awaiting response... 200 OK
    Length: 9856386 (9.4M) [application/x-gzip]
    Saving to: ‘openssl-1.1.1o.tar.gz’
    ...중략...
    2022-06-28 10:24:36 (97.8 MB/s) - ‘openssl-1.1.1o.tar.gz’ saved [9856386/9856386]
    
    $ ls -al openssl-1.1.1o.tar.gz
    -rw-r--r--. 1 root root 9856386 May  3 23:02 openssl-1.1.1o.tar.gz

3. Openssl 1.1.1o 압축해제

  • 아래의 명령어를 입력하여 다운받은 Openssl 1.1.1o를 압축 해제

    $ tar -xvfz openssl-1.1.1o.tar.gz

4. Openssl 1.1.1o 폴더로 이동 및 설정

  • 아래의 명령어처럼 입력

    $ cd openssl-1.1.1o
    $ ./config shared zlib
    Configuring OpenSSL version 1.1.1o (0x101010ffL) for linux-x86_64
    Using os-specific seed configuration
    Creating configdata.pm
    Creating Makefile

5. Openssl 1.1.1o 설치

  • 아래의 명령어를 입력하여 Openssl 1.1.1o를 설치

  • 설치에 필요한 패키지 설치

    $ yum install gcc gcc-c++ pcre-devel zlib-devel perl wget -y
  • Openssl 1.1.1o를 컴파일

    $ make && make install

6. Openssl 1.1.1o 정상 동작 확인

  • 아래의 명령어를 입력하여 /usr/local/bin/openssl 경로에 설치한 Openssl 1.1.1o가 정상동작하는지 확인 가능

    $ cp /usr/local/bin/openssl /usr/bin/openssl
    
    $ /usr/local/bin/openssl version
    /bin/openssl: error while loading shared libraries: libssl.so.1.1: cannot open shared object file: No such file or directory
  • openssl: error while loading shared libraries: libssl.so.1.1: cannot open shared object file: No such file or directory 에러 발생
    $ cp /usr/local/lib64/libssl.so.1.1 /usr/lib64/libssl.so.1.1
  • openssl: error while loading shared libraries: libcrypto.so.1.1: cannot open shared object file: No such file or directory 에러 발생
    $ cp /usr/local/lib64/libcrypto.so.1.1 /usr/lib64/libcrypto.so.1.1
  • 에러 해결 후 openssl 버전 재확인
    $ openssl version
    OpenSSL 1.1.1o  3 May 2022

7. Openssl 1.1.1o 설치 정보 등록

  • 아래의 명령어를 입력하여 Openssl 1.1.1o 설치 정보를 등록하여 다른 프로그램이 1.1.1o를 참조하도록 설정
  • 라이브러리 등록

    $ echo "/usr/local/lib64/" >> /etc/ld.so.conf
    $ ldconfig -v
    ldconfig: Path `/opt/dell/srvadmin/lib64' given more than once
    ldconfig: Path `/opt/dell/srvadmin/lib64' given more than once
    ldconfig: Path `/opt/dell/srvadmin/lib64' given more than once
    ldconfig: Path `/opt/dell/srvadmin/lib64' given more than once
    ...생략...
  • Openssl 1.1.1o 환경변수를 작성 → 테스트 필요

    $ cat > /etc/profile.d/openssl.sh << EOF
    export OPENSSL_PATH="/usr/local/bin/openssl"
    export OPENSSL_ROOT_DIR="/usr/local/ssl"
    export OPENSSL_LIBRARIES="/usr/local/lib/"
    export OPENSSL_INCLUDE_DIR="/usr/local/include/openssl/"
    PATH=$PATH:$OPENSSL_PATH
    EOF
  • openssl 1.1.1o 환경변수가 잘 등록되었는지 확인 → 테스트 필요

    $ cat /etc/profile.d/openssl.sh
    export OPENSSL_PATH="/usr/local/bin/openssl"
    export OPENSSL_ROOT_DIR="/usr/local/ssl"
    export OPENSSL_LIBRARIES="/usr/local/lib/"
    export OPENSSL_INCLUDE_DIR="/usr/local/include/openssl/"
    PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin:
  • 환경변수 파일의 실행 권한을 수정

    $ chmod 755 /etc/profile.d/openssl.sh

※ 참고

  • hdparm 명령어는 시스템에 장착된 하드디스크의 속도와 성능을 테스트할 수 있음 → 실무에서 IDE 또는 SCSI 하드디스크의 ACCESS 속도를 측정할 때에 많이 사용
  • hdparm 명령어로 하드디스크의 직접적인 성능에 영향을 줄 수 있는 여러가지 설정이 가능하지만, 극히 위험한 상황을 초래할 수 있으므로 설정의 용도로는 사용하지 않는 것이 좋음
  • hdparm 명령어로 점검하는 하드디스크의 속도는 절대적인 것이 아님 → 동일한 시스템에서 동일한 환경으로 테스트한 결과값도 조금 다르게 나올 수 있음
  • CPU와 메모리, 그리고 시스템 사양에 따라서 hdparm 테스트 결과가 매우 다르게 나올 수 있음 → 대략적인 하드디스크의 읽는 속도를 확인하기 위하여 hdparm 명령어은 매우 유용

hdparm 명령어 설치

$ yum install -y hdparm

명령어위치

$ which hdparm
/sbin/hdparm

하드디스크를 구입 기준

  1. IDE하드디스크인가? 아니면 SCSI하드디스크인가?
  2. 하드디스크의 RPM(디스크의 분당 회전수)은 얼마인가?
  3. 하드디스크의 용량은 얼마인가?
  4. 어느회사에서 생산한 제품인가?
  5. 하드디스크의 안정성은 확보되어있는가?
  6. 하드디스크의 외관


hdparm 명령어 옵션

hdparm 명령어 주로 사용하는 옵션

  • -t : 버퍼되어 있지 않은 데이터를 읽는 속도 체크
  • -T : 버퍼된 데이터를 읽는 속도를 체크


hdparm 명령어로 버퍼링되지 않은 데이터의 디스크 ACCESS 속도 체크하기

  • 시스템에 장착되어 있는 SCSI하드디스크의 속도를 체크
  • -t 옵션을 사용한 것은 버퍼링(buffering)이 전혀 되어있지 않은 데이터를 실제로 디스크에서 얼마나 빠르게 읽을 수 있는가를 확인
  • hdparm명령어는 실제로 2~3회의 테스트를 실시한 후에 출력
  • SCSI 하드디스크가 IDE 하드디스크보다는 데이터의 읽은 속도에 있어서 현저하게 성능이 높음

1.SCSI 하드디스크 테스트 결과

  • 시스템에 장착되어 있는 SCSI 하드디스크의 경우 실제로 디스크에 존재하는 데이터를 읽는 속도가 초당 약64MB

    $ hdparm -t /dev/sda
    
    /dev/sda:
    Timing buffered disk reads:  64 MB in  0.99 seconds = 64.65 MB/sec

2.IDE 하드디스크 테스트 결과

  • 시스템에 장착되어 있는 IDE 디스크의 경우 실제로 디스크에 존재하는 데이터를 읽는 속도가 초당 약26MB

    $ hdparm -t /dev/hda
    
    /dev/hda:
    Timing buffered disk reads:  64 MB in  2.42 seconds = 26.45 MB/sec



hdparm 명령어로 버퍼링 유무 데이터 ACCESS 속도 비교하기

  • 캐쉬(cache)에 버퍼링되어 있는 데이터를 읽는다면 실제 속도는 엄청나게 빨라짐
  • 캐쉬(cache)에 저장된 데이터를 읽는다는 것은 실제로 디스크에서 읽어오는 것이 아니라 캐쉬메모리(cache)에서 읽어오는 것이기 때문임
  • 위에서 설명한 -t 옵션은 디스크에 존재하는 데이터를 읽는 속도를 테스트하는 것이라면, -T 옵션은 캐쉬에 존재하는 데이터를 읽는 속도를 테스트

1. SCSI 디스크의 캐쉬에 버퍼링되어 있는 데이터와 실제 디스크에서 데이터의 읽는 속도 비교

  • 캐쉬메모리가 시스템의 속도에 막대한 영향을 미침을 확인 가능
    1. 캐쉬에 버퍼링되어 있는 데이터(T옵션)를 읽을 때에는 초당 약 220MB
    2. 실제로 디스크에서 데이터(t옵션)를 읽어오는 속도는 초당 약 65MB
      $ hdparm -tT /dev/sda  
      /dev/sda:
      Timing buffer-cache reads:   128 MB in  0.58 seconds =220.69 MB/sec
      Timing buffered disk reads:  64 MB in  0.97 seconds = 65.98 MB/sec

2. IDE 디스크의 캐쉬에 버퍼링되어 있는 데이터와 실제 디스크의 읽는 속도 비교

  • 캐쉬메모리가 시스템의 속도에 막대한 영향을 미침을 확인 가능
    1. 캐쉬에 버퍼링되어 있는 데이터(T옵션)를 읽을 때에는 초당 약 216MB
    2. 실제로 디스크에서 데이터(t옵션)를 읽어오는 속도는 초당 약 25MB
      $ hdparm -tT /dev/hda
      /dev/hda:
      Timing buffer-cache reads:   128 MB in  0.59 seconds =216.95 MB/sec
      Timing buffered disk reads:  64 MB in  2.48 seconds = 25.81 MB/sec


SSD가 Trim 기능 지원여부 확인 → Trim 사용하면 /etc/fstab에 discard를 추가

1. hdparm 명령어에 -I 옵션을 통해 SSD의 Trim 기능 확인

$ hdparm -I /dev/sda

/dev/sda:

ATA device, with non-removable media
        Model Number:       DELLBOSS VD
        Serial Number:      00321258d60c0010
        Firmware Revision:  MV.R00-0
Standards:
        Used: ATA/ATAPI-7 T13 1532D revision 4a
        Supported: 8 7 6 5 & some of 8
Configuration:
        Logical         max     current
        cylinders       16383   16383
        heads           16      16
        sectors/track   63      3
        --
        CHS current addressable sectors:    7864440
        LBA    user addressable sectors:  268435455
        LBA48  user addressable sectors:  468731008
        Logical  Sector size:                   512 bytes
        Physical Sector size:                  4096 bytes
        device size with M = 1024*1024:      228872 MBytes
        device size with M = 1000*1000:      239990 MBytes (239 GB)
        cache/buffer size  = 8192 KBytes (type=DualPortCache)
Capabilities:
        LBA, IORDY(cannot be disabled)
        Queue depth: 32
        Standby timer values: spec'd by Standard, no device specific minimum
        R/W multiple sector transfer: Max = 16  Current = ?
        Recommended acoustic management value: 254, current value: 0
        DMA: mdma0 mdma1 mdma2 udma0 udma1 udma2 udma3 udma4 udma5 udma6 *udma7
             Cycle time: min=120ns recommended=120ns
        PIO: pio0 pio1 pio2 pio3 pio4
             Cycle time: no flow control=120ns
Commands/features:
        Enabled Supported:
           *    Power Management feature set
           *    Write cache
           *    Look-ahead
           *    DOWNLOAD_MICROCODE
           *    48-bit Address feature set
           *    Mandatory FLUSH_CACHE
           *    FLUSH_CACHE_EXT
           *    Gen1 signaling speed (1.5Gb/s)
           *    Gen2 signaling speed (3.0Gb/s)
           *    Gen3 signaling speed (6.0Gb/s)
           *    Native Command Queueing (NCQ)
           *    Data Set Management TRIM supported (limit 1 block)      # 해당 부분 TRIM 표시
Security:
        Master password revision code = 65534
        88min for SECURITY ERASE UNIT. 88min for ENHANCED SECURITY ERASE UNIT.
Checksum: correct

2. lsblk -D가 0이 아니면 TRIM 사용 가능

$ lsblk -D
NAME   DISC-ALN DISC-GRAN DISC-MAX DISC-ZERO
sda           0        4K       2G         0
├─sda1        0        4K       2G         0
├─sda2        0        4K       2G         0
├─sda3        0        4K       2G         0
└─sda4        0        4K       2G         0
sdb           0        0B       0B         0
└─sdb1        0        0B       0B         0
sdc           0        0B       0B         0
└─sdc1        0        0B       0B         0
sdd           0        0B       0B         0
└─sdd1        0        0B       0B         0
sde           0        0B       0B         0
└─sde1        0        0B       0B         0
sdf           0        0B       0B         0
└─sdf1        0        0B       0B         0
sdg           0        0B       0B         0
└─sdg1        0        0B       0B         0
sdh           0        0B       0B         0
└─sdh1        0        0B       0B         0
sdi           0        0B       0B         0
└─sdi1        0        0B       0B         0
sdj           0        0B       0B         0
└─sdj1        0        0B       0B         0
sdk           0        0B       0B         0
└─sdk1        0        0B       0B         0

3. TRIM 최대 사용 bytes 확인 -> TRIM을 사용할 수 없으면 0으로 출력

$ cat /sys/block/sda/queue/discard_max_bytes
2147450880

4. TRIM 지원 Bock size 확인 -> TRIM을 사용할 수 없으면 0으로 출력

$ cat /sys/block/sda/queue/discard_granularity
4096

현재 서버의 Public IP 주소 확인

1. ifconfig.co를 통해 현재 서버의 IP 확인

$ curl ifconfig.co
서버의 IP 출력

2. ifconfig.me를 통해 현재 서버의 IP 확인

$ curl ifconfig.me
서버의 IP 출력

ipinfo.io를 통해 현재 서버의 정보를 json 형식으로 출력

$ curl ipinfo.io
{
  "ip": IP주소,
  "city": 도시,
  "region": 지역,
  "country": 국가,
  "loc": 위치,
  "org": 조직,
  "postal": 우편번호,
  "timezone": 시간대,
  "readme": "https://ipinfo.io/missingauth"
}                                                                                         

+ Recent posts