ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Large-scale cluster management at Google with Borg 정리
    Cloud 2015. 9. 21. 09:00
    반응형

    Large-scale cluster management at Google with Borg 정리

    구글은 Borg 시스템으로 수십만개의 job을 돌리고 있음.

    1. 도입
    Borg는 구글이 운영하는 애플리케이션을 스케쥴, 시작, 재시작, 모니터하는 클러스터 관리 시스템.
    크게 3가지 장점이 있음.
    (1) 사용자는 자원 관리와 장애 처리에 신경쓰지 않고 애플리케이션 개발에만 집중하면됨.
    (2) 애플리케이션을 안정적이고 가용성이 높게 운영할 수 있게 해줌.
    (3) 수만대 규모의 장비에서 작동하는 작업부하를 효율적으로 관리.
    이런 이슈를 해결하기위한 시스템이 Borg만 있는건 아니지만 이정도 규모를 이렇게 잘 처리하는건 별로 없음.
    구글은 Borg를 production 환경에서 십년넘게 사용해 오고 있음.

    2. 사용자 관점
    job : 사용자가 Borg에서 실행하려는 작업
    task : 각 job들은 하나 이상의 task로 구성되어 있음.
    cell : 여러개의 장비들을 하나로 묶은 단위. job 1개는 Borg cell 한군데에서만 돌아간다.

    2.1 워크로드(workload)
    cell에서는 여러가지 작업이 돌아가는데 크게 2가지로 분류한다.
    long-running 서비스(prod)
     - "절대(never)" 죽으면 안되는 서비스.
     - 빠른 응답(수 μs에서 수백 ms)이 필요한 서비스.
     - 보통 엔드유저가 사용하는 서비스(웹검색, gmail, 구글닥스등)거나 내부 인프라 서비스(빅테이블)

    batch 작업(non-prod)
     - 완료되는데 몇초에서 몇일까지 걸림.
     - 그다지 민감하지 않은 작업.

    Borg는 이런 다양한 작업들을 잘 처리해야 한다.
    지난 몇년동안 구글의 MapReduce 시스템, FlumeJava, Millwhell, Pregel, GFS, Bigtable, Megastore등이 Borg위에서 돌아가게 됐음.
    prod job은 cell의 CPU자원중 70% 정도를 할당받고 전체 CPU 사용률중 60%를 사용한다. 전체 메모리 자원중 55%를 할당받고 전체 메모리 사용량의 85%를 사용한다. 할당량과 사용량간의 차이가 왜 발생하는지는 5.5절에서 다룸.

    2.2 클러스터와 셀(cell)
    셀안에 있는 장비들은 하나의 클러스터에 속하게 된다.
    클러스터는 단일 데이터센터내에서 서로 네트워크가 연결된 장비들을 의미한다.
    클러스터는 보통 한개의 큰 셀을 제공하거나 테스트용이나 특수 목적용으로 여러개의 작은 셀들을 가지고 있다.
    구글에서는 중간크기의 셀은 1만개의 장비들로 이뤄져 있다.
    셀안에 장비들의 사용은 다 제각각이다. 사용자들은 장비 사양에 신경쓰지 않게 borg가 다 관리해줌.

    2.3 잡(job)과 태스크(task)
    잡(job)의 속성 : 이름, 소유주, 가지고 있는 태스크의 개수
    잡은 특정 속성(attributes)을 가진 장비에서만 태스크들이 수행할 수 있게 제약(constraints)을 설정할 수 있다.
    프로세서 아키텍처, OS 버전, 외부 IP 주소등을 지정할 수 있다.
    잡은 단일 셀안에서만 실행된다.

    태스크들은 컨테이너에서 실행되는 리눅스 프로세스들에 대응된다.
    가상화 때문에 발생하는 성능저하를 막기위해서 VM을 안쓴다.
    그리고, borg를 첨 설계할때 하드웨어가 가상화를 지원하지 않았음.

    태스크는 자원 요구사항(CPU 코어, RAM, 디스크 용량, 디스크 접근빈도,TCP 포트등), 잡에서의 태스크 인덱스등의 속성을 가지고 있다.
    잡에서 대부분의 태스크는 같은 속성을 가지고 있지만 오버라이드 가능함.
    borg 프로그램들은 바이너리와 데이터 파일로 패키지(packages)되어 있음.
    사용자가 borg에서 잡(job)을 운영하는건 CLI를 통해서 RPC를 호출해서 하고. 잡(job)설정은 BCL이라는 설정 언어를 이용한다.


    2.4 alloc
    borg의 alloc은 장비의 자원들중에서 미리 할당해둔 자원들이다. alloc은 하나 이상의 태스크들을 실행할 수 있다.
    alloc은 나중에 있을 태스크를 위해 설정될 수 있다. 태스크가 멈췄다가 다시 시작되는 사이에 자원을 유지하거나 같은 장비에 다른 잡의 태스크를 넣기위해 사용된다. 예를들어, 웹서버 인스턴스와 로컬의 웹서버 로그를 원격지의 분산파일 시스템으로 보내는 로그처리 작업을 하나의 머신에 두는 것등이 있다.
    alloc의 자원은 장비의 자원과 동일하게 취급되고, 여러개의 태스크들이 그 자원을 공유함.
    alloc이 다른 장비로 재할당되면 그 alloc에 대한 태스크들도 같이 스케쥴링이 변경된다.
    alloc set : 잡이랑 비슷한 개념. 여러대의 장비에 자원을 예약해두는 alloc의 그룹.
    일반적으로 태스크는 alloc을 참조하고, job은 alloc set을 참조함.


    2.5 Priority , 쿼터, admission control
    처리가능한 양보다 많은 작업이 할당될때는 priority, 쿼터로 해결.
    모든 job에 priority가 있다. priority는 양수.
    용도에 따른 priority band가 있음.
    우선순위가 높은 순으로 monitoring, production, batch, best effort(testing, free) 등이 있음.
    여기서 prod job은 monitoring과 production 밴드에 속함.
    priority가 높은 태스크가 들어오게 되면 그것 먼저 할당되고 연쇄적으로 그 다음으로 priority가 낮은 태스크들이 재할당되게 된다. 이렇게 안되게 하려고 production priority band에 속한 태스크는 기존에 돌고 있는 다른  production priority band에 속한 태스크는 건드리지 못한다.
    priority는 셀내에서 실행 또는 대기중인 잡의 상대적 중요도를 나타낸다.
    쿼터(quota)는 어떤 잡이 스케줄링 가능한지 결정한다. 자원들의 양을 나타내는 벡터(CPU, RAM, 디스크 등)로 표현.
    쿼터에 설정된 값은 잡에서 사용할 자원의 최대치를 나타냄.
    쿼터를 확인하는건 스케쥴링이 아니라 admission control의 일부임. 잡에 쿼터가 충분치 않으면 바로 거절됨.
    같은 쿼터라 하더라도 데이터센터마다 쿼터에 대한 비용이나 가용성이 다 다르기 때문에 쿼터 할당은 borg 외부에서 관리됨.
    관리자 권한은 별도의 권한으로 처리됨.

    2.6 네이밍, 모니터링
    BNS : Borg name service
    BNS는 각 태스크마다 셀 이름, 잡 이름, 테스크 번호등을 가지고 있음. 태스크를 찾고 새 장비에 재할당할때 필요.
    borg는 chubby에 bns 이름과 태스크의 호스트이름, 포트(장비에 IP가 하나라서 포트로 태스크들을 구분함.)등을 저장함. 
    BNS는 태스크의 기본 DNS 이름을 구성하는 정보가 됨.
    잡 크기, 태스크 상태등도 chubby에 저장해서 이런 정보가 변경됐을때 로드밸런서가 요청을 어디다 분배할지 결정하는데 이용.

    잡 등록, 태스크 이벤트, 태스크당 상세한 인프라자원 사용량등을 Dremel에 저장함.
    이 데이터를 이용해서 사용량 기반 과금, 잡&시스템 장애 디버깅, 장기적인 장비 수급 계획등에 사용함.
    이런 데이터를 이용해서 구글 개발자들은 자기 업무용으로 일인당 수만대의 장비를 관리할 수 있음.


    3. borg 아키텍처
    borg의 셀은 여러대의 장비로 구성되어 있고, 논리적으로는 Borgmaster라는 컨트롤러를 이용해서 각 장비에 Borglet이라는 에이전트 프로세스를 띄우고 관리한다. 전부 C++ 로 개발됨.

    3.1 Borgmaster
    Borgmaster는 메인 borgmaster 프로세스와 스케쥴러 2개의 프로세스로 구성된다.
    메인 Borgmaster 프로세스 역할
     - 클라이언트 RPC를 처리.
     - 시스템내부의 모든 객체(장비, 태스크, alloc등)의 상태를 관리.
     - Borglet와 통신
     - 웹 UI제공
    Borgmaster는 논리적으로는 단일 프로세스지만 실제로는 5개의 사본이 있음.
    각 사본들은 셀의 상태를 메모리에 복제해서 관리함. 이중 하나가 Paxos에 의해 마스터로 선출되서
    cell내의 상태를 변경하는 잡 제출, 장비에서 태스크 종료등의 운영을 하게된다.
    마스터에 문제가 생기면 새로 마스터를 선출하고 failover하는데 10초 정도 걸리지만, cell이 크면 메모리 상태를 재구성하느라 1분정도 걸리기도 함.
    사본이 복구되면 다른 paxos 사본에 있는 최신정보를 가져와서 업데이트 됨.
    Borgmaster의 특정 시점에서의 상태는 checkpoint라고 하고, 기간별 스냅샷에 변경 로그를 더해서 paxos 저장소에 보관한다.

    3.2 스케쥴링
    잡이 제출되면 Borgmaster는 그걸 paxos 저장소에 저장하고 잡의 태스크를 pending 큐에 추가한다.
    스케쥴러(scheduler)가 이걸 비동기적으로 확인해서 잡에 설정된 자원조건에 맞는 자원을 가진 적당한 장비에 태스크를 할당한다.
    스케쥴러는 주로 태스크를 관리하지 잡을 관리하는게 아니다. 이때 높은 우선순위를 가진 태스크 먼저 스케쥴링된다.

    스케쥴링 알고리즘은 2가지 로 구성
      - feasibility checking : 태스크를 실행할 수 있는 장비가 있는지 찾음. 태스크의 제약에 맞으면서 "이용가능한" 자원이 있는 장비를 찾음. 이때 "이용가능한" 이라는 의미에는 현재 태스크보다 priority가 낮아서 쫓아 낼수 있는 태스크가 사용하는 자원도 포함된다.
      - scoring : 적절한 장비중에서 하나를 고름. 사용자가 설정한 선호조건이 있으면 거기에 맞는 장비를 선택하지만 보통은 기본 설정(사용중인 태스크의 개수와 priority를 줄이는 방향)에 따라 선택된다. 태스크의 패키지를 가지고 있는 장비를 선택,  한 장비에 priority가 높고 낮은 태스크들을 적당히 섞어서 넣기등.

    Borg에서 태스크들을 적절히 분해하기 위해서는 가능한 장비에 태스크들을 꽉꽉 채워 넣어야 한다.
    그런데 태스크에서 필요한 자원을 사용자나 borg가 잘못 예측하면 로드가 몰렸을때 애플리케이션에 영향을 주게 된다. 특히 CPU를 조금 사용하는 배치 잡에 안 좋은 영향을 주게 된다. 그래서 큰 태스크들은 가능한 사용하지 않고 있는 자원에 할당하도록 되어 있다.
    non-prod 태스크의 20%정도는 0.1 보다 작은 양의 CPU 코어만 있으면 된다.

    borg의 scoring 모델은 장비의 자원들이 다 할당되서 사용할수 없게 되는 경우를 줄이도록 되어 있다.
    이렇게 하는게 100% 다 채워넣는 것보다  3~5%정도 더 효율적이다.
    scoring이 선택한 장비에 가용한 자원이 모자라면 borg는 자원을 확보하기위해 priority가 낮은 태스크들 부터 죽인다.
    이 때 죽은 태스크들은 다른 곳으로 옮겨지는게 아니라 스케쥴러의 pending 큐에 들어간다.

    태스크가 처음 제출되고 시작되기 까지는 보통 25초 정도 걸림. 이중 패키지 설치하는데 80% 정도의 시간이 걸림. 디스크 쓰는데 시간이 많이 걸려서 그렇다. 그래서 시작 시간을 줄이기 위해서 스케쥴러는 가능하면 필요한 패키지들이 설치되어 있는 장비에 태스크를 할당하려 한다. 추가로 borg는 패키지를 배포할때 토렌트 같은 프로토콜을 사용해서 병렬로 여러 장비들에 배포한다.

    3.3 Borglet
    borglet : 셀내의 모든 장비들에서 돌아가는 Borg 에이전트.
     - 태스크의 시작/정지. 실패했을때 재시작등을 담당.
     - OS 커널 세팅을 조정해서 로컬자원 관리
     - 디버그 로그 롤링
     - borgmaster나 모니터링 시스템에 장비 상태 보고

    borgmaster에서 몇 초 간격으로 borglet에서 장비의 상태를 요청함.
    borgmaster에 요청이 몰리는걸 막기 위해서임.
    선출된 마스터가 borglet에 보낼 메세지를 준비하고 응답을 받아서 셀의 상태를 업데이트 한다. 
    성능 향상을 위해서 borgmaster의 사본은 borglet와 통신하기 위해 상태가 없는 link shard를 실행한다.
    파티셔닝은 borgmaster가 선출됐을때 일어난다. 
    borglet는 항상 전체 상태를 보고하지만, 마스터의 부하를 줄이기위해서 link shard는 차이점만 수집하고 압축해서 보낸다. 
    borglet가 몇번 메세지에 응답을 하지 않으면 down 상태로 처리되고 거기서 실행되고 있던 태스크들은 다른 장비로 재할당된다. borgmaster와의 통신이 복구되면 borgmaster는 중복을 피하기 위해 그 borglet에 있는 태스크들중 다른 장비로 할당된 태스크를 죽이라고 한다.
    borglet은 borgmaster와의 연결이 끊어져도 정상작동하기 때문에, borgmaster가 죽더라도 현재 실행중인 태스크와 서비스들은 유지된다.

    3.4 Scalability
    하나의 borgmaster는 셀내의 수천개의 장비를 관리할 수 있음.
    몇몇 셀들은 분당 만개의 태스크를 처리하고 있음.
    많이 사용되는 borgmaster는 10~14 CPU 코어, 50GB ram을 사용함.
    대규모 셀을 관리하기 위해서 borgmaster는 스케쥴러와 다른 기능들이 분리되어 있음.
    응답시간을 개선하기위해서 borglet과 통신하는 스레드와 읽기전용 RPC에 대해 응답하는 스레드가 분리되어 있음.
    성능을 끌어올리기 위해서 이런 기능들을 다섯개의 borgmaster 사본에 분배해 놨음.
    이렇게 해서 UI응답의 99%는 1초 미만이고, borglet 풀링 간격의 95%는 10초 미만이 됐음.

    borg 스케쥴러의 성능을 끌어 올리는 것들.
    score caching : 장비의 feasibility, scoring을 평가하는 비용이 비싸기 때문에 장비의 속성이나 태스크가 변경되기 전에는 score를 캐시하고 있음.
    equivalence classes : borg job의 태스크들은 보통은 동일한 요구사항과 제약을 가지고 있다. 그래서 borg는 동일한 요구사항을 가진 equivalence class당 하나의 태스크에 대해서만 feasibility, scoring를 수행한다.
    relaxed randomization : 대규모 셀에서 모든 장비에 대해 feasibility, score를 계산하는건 낭비가 심하다. 스케쥴러는 score하기 충분히 feasible한 장비를 찾을때까지 랜덤으로 장비를 평가해서 선택한다. 

    셀의 전체 작업부하를 처음부터 끝까지 스케쥴링하는데 수백초 정도가 걸리는데, 위의 테크닉들을 사용하지 않았을 경우에는 3일이 지나도 끝나지 않기도 한다. 일반적으로 온라인 상태에서 pending 큐를 처리하는데는 1초 미만으로 끝난다.


    4. 가용성
    * 정지된 태스크가 자동으로 리스케쥴 되는 이벤트
    * 잡의 태스크들을 분산해서 장비, 랙, 파워같은 장애가 미치는 영향을 감소시킴
    * OS나 장비 업그레이드등의 유지보수 작업을 하는 동안 중단될수 있는 태스크의 수를 제한.
    * 멱등성을 가지게 작업을 처리해서 장애난 클라이언트에 작업을 다시 실행해도 문제가 없게 처리.
    * 태스크나 장비가 깨진 태스크-장비를 연결하는 작업을 반복하지 않음.
    * logsaver 태스크를 재실행해서 로컬 디스크에 있는 critical 중간 데이터를 복구함.

    borg의 메인 설계 의도는 기존에 실행중인 태스크들은 borgmaster나 borglet이 죽더라도 계속해서 실행되고 있도록 하는 것.
    실제 운영중인 borgmaster의 가용성은 99.99% 정도.
    장애가 연계되어 전파되는걸 방지하기 위해서 각 셀들은 다른 셀과는 독립적임.


    5. utilization
    borg의 주요 목적중 하나는 장비들의 utilization을 올리는 일.
    구글 스케일에서는 utilization을 약간만 올려도 수백만 달러를 절약할 수 있음.


    5.1 평가 방법
    "average utilization"으로는 다양한 환경에서의 utilization을 측정할 수 없어서 다른 지표를 선택함.
    cell compaction : 주어진 작업부하를 얼마나 작은 규모의 셀로 처리할 수 있는가.

    테스트 조건
    2014년 10월 1일 14:00 PDT의 실제 체크포인트 데이터를 가지고 시뮬레이션 했음.
    15개의 셀을 선택. 특수목적, 테스트, 작은 규모(5000개 미만의 장비)의 셀은 제외.
    각 실험은 11번 반복했음.
    좋은 스케쥴링 정책은 적은 수의 장비로 같은 량의 작업부하를 처리할 수 있기 때문에 cell compaction이 스케쥴링 정책을 비교하는데 좋은 방법이다.
    long-running 서비스들이 있기 때문에 전통적인 time-to-completion 방식보다는 point in time에 작업을 스케쥴링하는데 중점을 뒀음.
    테스트 한번 돌리는데 20만 개의 CPU 코어를 사용하는데 구글 스케일에서도 테스트할때 이정도를 사용하는건 부담이 되는 숫자다.

    5.2 Cell sharing
    공유되는 borg 셀중 98%의 장비, borg가 관리하는 전체 장비의 83% 정도는 prod, non-prod 태스크를 같이 수행함.
    일부 셀은 특수 목적으로 별도로 사용함.
    보통 다른 회사에서는 사용자 서비스와 배치 작업을 별도의 클러스터로 분리해서 사용함.
    그렇게 prod와 non-prod를 분리운영하는 방식을 테스트 했을때는 20~30% 정도의 장비가 더 필요했음.
    보통 prod 잡(job)들은 가끔 있는 작업부하 스파이크를 처리하려고 자원을 실제 평소에 사용하는 것보다 많이 예약해두고 쓰는데, 이렇게 예약해놓은 버퍼들은 실제로는 거의 사용하지 않는다.
    borg는 이런 사용하지 않는 자원을 이용해서 대부분의 non-prod 작업을 처리하기 때문에 사용되는 장비수를 줄일 수 있다.

    위 그림에서 왼쪽막대가 작업부하를 함께 썼을 때의 원본 셀이고, 오른쪽 막대가 작업 성격을 분리해서 운영했을때의 셀 크기.


    보통 수천명의 사용자가 하나의 borg 셀을 공유해서 사용한다. 
    아래 그림을 보면 사용자를 분리하면 장비가 더 많이 필요해진다는걸 알 수 있다.


    성격이 다른 여러 작업이 하나의 장비에서 실행될때 CPU 간섭이 발생하지는 않는지에 대한 테스트.
    CPI(cycles per instruction, 명령어당 사이클)가 어떻게 변경되는지 관찰해 봄.
    CPI가 2배가 되면 CPU에서 실행중인 프로그램의 실행시간도 2배가 되기 때문에 지표로 사용하기 좋다.
    데이터는 일주일간 실행된 태스크중 12000개를 무작위로 뽑았음. 5분동안의 사이클과 명령어 개수를 셌음.
    (1) CPI는 장비의 전체 CPU 사용량과 태스크의 개수와 연관관계가 있다.
        장비에 태스크를 추가하면 다른 태스크의 CPI가 0.3%정도 증가하고, CPU 사용량이 10% 증가하면 CPI는 2%미만으로 증가한다. 
       이런 상관관계가 영향을 미치기는 하지만 CPI를 측정했을 때 분산의 5% 정도만 이걸로 설명가능하다.
       애플리케이션의 특성이나 특정 간섭 패턴[24, 83]등의 다른 요소가 더 큰 영향을 미친다.
    (2) 비슷한 애플리케이션들에 대한 공유 셀과 전용 셀간의 CPI를 비교해 봤을때 공유 셀의 CPI는 1.58(σ = 0.35)이고 전용 셀의 CPI는 1.53(σ = 0.32) 정도.
         즉, 공유셀의 CPU 성능이 3% 정도 더 나쁘다.
    (3) 각 셀의 작업부하가 다양한걸(실제론 CPU 간섭에 민감한 프로그램들은 이미 전용셀로 들어가 있음 ) 무시하고 CPI를 측정해보면 전용셀의 CPI는 1.20 (σ = 0.29) 공유셀의 CPI는 1.43 (σ = 0.45) 이다. 전용셀이 1.19배 정도 빠르다. 

    여기서 보면 성능비교는 어떻게 하느냐에 따라 다양하니 warehouse 스케일에서는 무의미 하다.
    프로그램 실행 비용이 엄청나게 증가하는 일이 없으니 공유해서 사용하는게 좋다. 
    CPU가 느려지는 것보다는 장비수가 줄어드는게 더 효율이 좋으니 공유해서 쓰는게 좋다.
    CPU뿐만 아니라 메모리, 디스크에 대해서도 마찬가지다.


    5.3 Large cells
    구글은 자원 단편화를 줄이기 위해서 셀의 단위를 크게 가져간다.
    아래 그림을 보면 작은 셀로 나눴을때 동일한 작업을 처리하기 위해 필요한 장비수가 큰 셀 하나로 처리할때보다 훨씬 많이 필요한 걸 알 수 있다.



    5.4 Fine-grained resource requests
    borg 사용자는 CPU를 밀리코어(milli-core)단위, 메모리와 디스크를 바이트 단위로 요청.
    코어는 장비 타입별로 성능을 표준화한 프로세서를 의미함.
    아래 그림을 보면 다양한 사양을 고르게 사용하고 있는걸 알 수 있음.


    고정된 크기의 컨테이너나 VM을 제공하는게 IaaS에서는 일반적이지만 borg에서는 맞지 않음.
    CPU 코어나 메모리 자원을 특정 단위(CPU 0.5 코어, RAM 1GB)로 잘라서 테스트 해보면 중간크기의 셀(10000대 규모)인 경우 아래 그림처럼 30~50% 정도의 추가 자원이 필요함.



    5.5 Resource reclamation
    잡(job)은 자원 limit을 둘수 있다.
    이런 limit은 사용자가 잡을 사용하기에 충분한 쿼터를 가지고 있는지 확인하고 어떤 장비가 잡을 돌릴만한 여유자원을 가지고 있는지 확인하는데 사용한다.
    시스템을 운영하다 보면 필요한것 보다 많은 쿼터를 가지고 있고, 실제 사용할 자원보다 많은 자원을 요청하는 사용자가 꼭 있다.
    그래서, borg가 요청한 것보다 많은 ram이나 디스크를 사용하는 태스크를 죽이고, CPU 사용량을 조절한다.
    일부 태스크들은 요청한 자원을 모두 사용하기도 하지만 대부분은 안 그런다.
    resource reclamation : 태스크가 얼마만큼의 자원이 필요한지 예측하고 배치 작업같이 작은 자원으로도 충분한 작업을 나머지 부분에 채워 넣는 작업.
    이런 예측을 태스크의 reservation이라고 하고 borgmaster가 몇초 간격으로 실행한다. 계산에 필요한 실제 사용량(usage, resource consumption)은 borglet에서 가져온다.
    최초의 reservation은 요청과 동일하게 설정된다. 300초후부터 천천히 실제 사용량에 맞게 감소시켜 나간다. 사용량이 늘어나면 reservation도 증가한다.
    borg 스케쥴러는 prod 태스크의 feasibility를 계산하기위해 limt을 사용한다. 그래서 reclaimed resource하고는 상관없다.
    non-prod 태스크의 경우, 기존 태스크의 reservation을 이용한다. 그래서 새 태스크는 reclaimed resources에 할당될 수 있다.
    혹시나 reservation이 잘못되서 장비에서 자원을 많이 사용하게 되면 non-prod 태스크를 죽인다. prod 태스크는 건드리지 않음.
    아래 그래프를 보면 resource reclamation을 사용하지 않았을때 더 많은 장비가 필요하다는걸 보여준다.



    아래 그림은 reservation과 사용 limit간의 비율을 보여준다. 자원이 필요할때는 우선순위 고려없이 메모리 제한을 넘어서 사용중인 태스크가 먼저 중지된다. 그래서, 실제로 태스크가 메모리 제한을 넘어서 사용되고 있는 경우는 거의 없다. 반대로 CPU는 읽기 제한을 통해서 짧은 순간의 스파이크는 무리없이 감당할 수 있다.


    figure11에서의 resource reclamation은 불필요하게 보수적이기 때문에 이걸 조정하면서 테스트 해봄.
    자원 예측 알고리즘을 여분 자원을 줄여서 aggressive하게 세팅해서 한주정도 돌려보고, 기본과 aggressive사이로 medium으로 세팅해서 한주정도 돌려보고, 다시 기본 세팅으로 돌려봤음.
    결과는 아래 그림.
    2째주와 3째주를 보면 OOM(out-of-memory)이 늘어난걸 확인할 수 있음. 
    대신 기본 설정(baseline)보다 추가 태스크를 수용할 수 있는 capacity도 늘어났음.
    구글에서는 이 테스트를 바탕으로 자원예측 알고리즘을 medium으로 세팅해서 사용함.



    6. Isolation
    50% 정도의 장비는 9개 이상의 태스크를 돌리고 있음.
    90% 정도의 장비는 25개의 태스크를 돌리고 있고 4500개의 스레드를 돌리고 있음.
    장비를 공유하는게 이용률을 높여주기는 하지만 태스크간의 간섭을 막기위한 보안과 성능상의 자원 격리가 필요함.

    6.1 Security isolation
    리눅스 chroot, cgroup를 사용함.
    원격 디버깅을 위해서 ssh 키를 자동으로 배포함. 이 키를 이용해서 사용자는 자신의 태스크에만 접근 가능함.
    사용자들은 borgssh라는 명령어를 사용.
    앱엔진과 GCE(Google Compute Engine)에서는 KVM으로 VM을 사용.

    6.2 Performance isolation
    초기 버전에서는 borglet이 CPU 사이클, 메모리/디스크 사용량 등을 모니터링하면서 너무 많은 자원을 사용하는 태스크 죽이면서 관리를 하긴 했지만 완벽하지는 않았다.
    그래서 대부분의 사용량이 많은 서비스의 경우에, 사용자들은 자기 작업이 다른 작업에 영향받지 않게 전용 장비나 셀을 요청했었다.
    지금은 borg는 태스크를 리눅스 cgroup 기반 컨테이너에서 실행하고 borglet이 컨테이너 세팅을 관리한다.
    OS 커널에서 관리할 수 있게되서 운영하기 좋아졌다.
    그래도 여전히 메모리 bandwidth나 L3 캐시 오염같은 저수준에서의 자원 간섭은 발생한다.

    borg 태스크에는 appclass가 있음.
    appclass는 주로 latency-sensitive(LS)와 batch로 구분됨.
    LS 태스크들은 사용자가 직접 사용하는 애플리케이션이거나 공유해서 사용하는 인프라 서비스들이라 빠른 응답이 필요한 것들.

    compressible 자원과 non-compressible 자원으로도 구분함.
    compressible 자원 : CPU 사이클, 디스크 I/O bandwith등이 해당. 비율 기반의 자원들이고 서비스를 죽이지 않고 자원 재할당이 가능함.
    non-compressible 자원 : 메모리, 디스크 용량등. 태스크를 죽이지 않고 재할당하는 것이 힘든 것들.
    장비가 non-compressible자원을 초과하면 borglet이 우선순위가 낮은거에서 높은 순으로 태스크들을 즉시 죽여서 자원을 확보.
    compressible 자원을 초과하면 borglet이 태스크를 죽이지 않고 사용량을 줄여서 짧은 스파이크는 처리할수 있게함.
    그래도 개선되지 않으면 borgmaster가 해당 장비에서 태스크들을 제거함.

    LS 태스크는  전체 물리 CPU 코어를 예약할 수 있음.
    batch 태스크는 아무 코어에서나 실행될수 있는데, LS태스크와 공유해서 꼽사리 껴서 사용.
    borglet이 LS 태스크 위주로 동적으로 자원을 사용하지만 batch 태스크를 분단위로 지연시키지는 않음.

    리눅스 CPU scheduler(CFS)를 튜닝해서 사용. LS 태스크들을 우선해서 처리하게 함. 결과는 아래와 같음.
    LS가 왼쪽, batch가 오른쪽. 전체 스레드중 1ms 이상 CPU를 기다리는 경우가 얼마나 자주 발생하는지를 보여줌.


    7. Related work
    Apache Mesos : 자원 및 배치. offer 기반 구조(Borg는 request 기반 구조)
    YARN : 하둡 클러스터 매니저
    페이스북 Tupperware
    트위터 Aurora : mesos위에서 돔.
    마이크로소프트 Autopilot
    Quincy
    Cosmos : 배치 프로세싱 중심.
    마이크로소프트 Apollo 시스템.
    알리바바 Fuxi : 데이터 분석용.
    Omega
    Kubernetes : borg 만들었던 엔지니어들이 만들고 있음.

    HPC쪽은 Maui, Moab, Platform LSF등이 있는데 성격이 좀 다름. utilization쪽에 초점이 맞춰져 있음.


    8. Lessons and future work
    Borg를 십년 넘게 운영해 오면서 배운 노하우를 어떻게 Kubernetes에 녹여 냈는지에 관한 이야기

    8.1 단점에서 배운 것

    * 잡이 태스크를 그룹화 하는 용으로만 제한된다.
    borg에는 멀티 잡을 하나로 처리하거나 서비스에 관련된 인스턴스들을 참조할 수 있는 방법이 없다.
    사용자들이 잡 이름에 관련 정보를 넣어서 짓고, 이 이름들을 파싱해서 처리하는 도구들을 만들어서 사용해 왔음.
    잡의 특정 하위집합만 묶어서 처리할 수 없어서 롤링 업데이트나 잡 크기변경등을 못한다.
    이런걸 해결하려고 Kubernetes는 label을 이용해서 pods들을 스케쥴링한다.
    사용자가 시스템의 모든 객체에 label을 붙일 수 있다.
    borg 잡처럼 사용하려면 job:jobname에 대한 label을 pods에 붙여서 사용할 수 있다.
    서비스, 티어, 릴리즈 타입(production, staging, test)같은 정보도 붙일 수 있다.
    Kubernetes에서는 label을 통해서 작업할 대상을 정한다.

    * 장비당 하나의 IP 주소만 있어서 처리하기가 복잡하다.
    borg에서는 장비에 IP가 하나밖에 없다. 그래서 각 태스크들이 장비의 포트를 구분해서 사용했다.
    borg가 포트를 자원으로 간주하고 관리하는게 어려웠음.
    태스크가 얼마나 많은 포트를 사용할지 미리 지정해 놔야 함.
    Kubernetes에서는 모든 pod와 서비스들이 각각의 IP주소를 가짐. 포트를 관리할 필요가 없어짐.

    * 파워유저를 위한 최적화옵션이 많아서 복잡했다.
    borg는 파워유저를 위해서 많은 옵션을 줬다. BCL에는 230여개의 파라메터들이 있음.
    초기에는 구글에서 대량 자원이 필요하고 성능극대화가 필요한 사용자들을 위해서 이렇게 디자인 됐음.
    일반 유저에게는 이게 오히려 복잡하고 어렵게 느껴짐.
    그래서 그동안의 경험을 바탕으로 이런 옵션들을 자동설정하는걸 borg에 탑재했음.


    8.2 장점에서 배운 것

    * alloc은 유용하다. 
    로그 저장 패턴에 많이 쓰임.
    웹서버가 사용하는 데이터를 주기적으로 업데이트하는 등의 간단한 작업.
    alloc을 이용해서 이런 부가 서비스들을 별도의 팀에서 개발하는게 가능해 졌음.
    Kubernetes에서는 pod가 alloc와 비슷하다.
    alloc 대신에 같은 pod내에 헬퍼 컨테이너를 사용할 수 있다.

    * 클러스터 관리라는게 태스크 관리만 하는건 아니다.
    borg의 주요 역할은 태스크와 장비의 생명주기를 관리하는 것이지만, borg에서 돌아가는 애플리케이션은 네이밍, 로드밸런싱등의 클러스터 서비스에서 얻는 장점이 많다.
    Kubernetes는 service를 이용해서 네이밍과 로드밸런싱을 지원한다.
    서비스는 이름을 가지고 있고 label selector를 통해서 pod를 동적으로 정의할 수 있다.
    클러스터내의 모든 컨테이너들은 서비스 이름을 통해서 서비스에 연결할 수 있다. 
    Kubernetes는 자동으로 서비스에 대한 커넥션들을 pod에 로드밸런싱한다.

    * Introspection이 중요하다.
    Borg가 대부분은 잘 작동하지만, 먼가 잘못되면 원인을 찾기가 힘들다.
    Borg는 디버깅 정보를 모든 사용자가 볼 수 있다. 
    Borg는 수천명의 사용자를 가지고 있고 디버깅을 직접하는걸 권하고 있다.

    대용량 데이터를 처리하기위해서 여러 단계의 UI와 디버깅 도구들을 제공해서 사용자들이 빨리 비정상적인 이벤트를 감지해서 애플리케이션에 쌓는 상세한 이벤트나 에러로그를 줄일 수 있다.

    Kubernetes는 borg의 introspection 테크닉을 많이 가져왔다.
    자원 모니터링을 위해 cAdvisor를 사용하고, Elasticsearch/Kibana/Fluentd 를 이용해 로그를 수집한다.
    마스터는 객체의 상태에 대한 스냅샷을 요청할 수 있다.
    모든 구성요소들이 사용할 수 있는 이벤트(pod가 스케쥴되었는지, 컨테이너가 장애인지등)를 기록하는 표준화된 구조를 가지고 있고, 이걸 클라이언트가 이용할 수 있다.

    * 마스터는 분산 시스템의 커널이다.
    Borgmaster는 처음에는 단일 프로세스로 시작했지만, 시간이 흐르면서 스케쥴러나 UI 그외 기능등을 별도의 프로세스로 분리해 내면서 스케일업하기에 좋은 구조로 발전해 나갔다.
    Kubernetes는 여기서 한발 더 나아가서 API 서버를 가지고 있다.
    클러스터 관리에 필요한 기능들을 마이크로 서비스로 만들어서 API 서버의 클라이언트가 되게 만들었다.

    8.3 결론
    구글의 모든 클러스터 작업은 Borg를 사용하도록 변경됐다.
    구글에서는 그걸 개속 발전시켜나갈거고 거기서 익힌 노하우를 Kubernetes에 적용시킬 거다.



    반응형

    'Cloud' 카테고리의 다른 글

    Openstack glance 설치하기  (0) 2016.02.19
    openstack keystone 설치해보기  (0) 2016.02.17
    kubernetes 기본 개념  (0) 2015.09.14
    etcd 기본사용  (0) 2015.09.11
    libvirt 사용하기  (0) 2015.03.25

    댓글

Designed by Tistory.