대메뉴 바로가기 본문 바로가기

데이터 기술 자료

데이터 기술 자료 상세보기
제목 웹 애플리케이션의 구조 확장을 위한 분산 알고리즘
등록일 조회수 4775
첨부파일  

차세대 C/C++인 Go

웹 애플리케이션의 구조 확장을 위한 분산 알고리즘



앞선 1, 2회 연재에서 기본적인 웹 애플리케이션과 그 기능의 확장에 대해 논의하였다면, 이번 연재에서는 최근 화두인 웹 서비스의 분산 처리를 다룬다. 분산 처리의 개념, 기술적인 설명을 위주로 소개한다.


Go의 1회 연재물은 웹에서 Hello World 프로그램을 만들어보고 결과를 확인하는 내용이었다. 어떤 언어로든 Hello World 프로그램을 제작하는 건 첫걸음이라고 보면 된다. 2회에서는 1회에서의 예제를 이용해 웹 애플리케이션을 만들었다. 시나리오와 기능이, 확장되니 기반기술, 프론트엔드, 미들웨어, 데이터베이스 등 인프라가 필요해진다. 이번 3회 연재에서는 웹 애플리케이션을 실제 웹서비스처럼 만들기 위해 적용돼야할 기술을 다루겠다.


페이스북, 아마존, 네이버 등의 웹서비스는 대규모 사용자와 데이터를 처리하는 기술을 보유했다. 특히 서비스 엔진은 사용자들에게 실시간 상태 메시지, 검색어 업데이트 서비스를 제공하기 때문에 지속적으로 트래픽 처리를 해야하기 때문에 관련 기술을 필요로 한다. 이러한 성능과 사용성을 유지하기 위해 다양한 기술과 설계 방식을 적용한다. 분산 처리는 그 중 하나다.


들어가기 전에 생소한 단어들을 짚고자 한다. 멤캐시드(Memcached)를 대체하는 키 값인 그룹캐시(Groupcache), 클라우드와 데이터 센터에 최적화된 플랫폼이라는 슬로건을 내건 코어OS(CoreOS)는 리눅스 커뮤니티에서 최근 주목받는 프로젝트다. ETCD를 주요 라이브러리로 활용해 다수 클라이언트들을 호스팅한다. ETCD는 Go와 ‘래프트 프레임워크’(Raft framework)’를 이용해 작성된 오픈소스 키 값 저장소다. 대규모 서버를 관리할 때 컨테이너(실제 코드와 애플리케이션이 수행되는 블록)를 유기적으로 연동하는 아키텍처를 제공한다.


그룹캐시

그룹캐시를 설명하기 위해선 멤캐시드를 알아야 한다. 웹 애플리케이션에서의 성능을 향상시키기 위해 데이터베이스의 로드를 캐시화하는 기술이다. 그래서 대규모 시스템을 가정하는 시나리오에 적합하다. 멤캐시드는 키-값 스토리지로 구성돼 있고 해싱(Hashing) 알고리즘과 서버 알고리즘을 나뉘어져 있다. 다중 서버를 사용하지만 각 서버가 스스로의 존재를 모르도록 구성돼 있는 것도 특징이다. 멤캐시드의 단점도 있다. 기존 웹 애플리케이션에 라이브러리 형식으로 추가해 쓰기에는 부적합하고 독립적인 데몬(daemon) 형식으로 작동한다. 또 사용자가 데몬을 기존 웹 서비스로 옮기는 비효율적인 작업을 거쳐야 한다.


그룹캐시는 이런 멤캐시드를 대체한다. 오픈소스 라이브러리라 사용자가 API를 호출하는 식으로 예제를 만들고 성능을 바로 확인하면 된다. 그룹캐시가 멤캐시드를 대체할 수 있는 부분은 LRU(Least Recently Used) 캐시 알고리즘이다. 이는 최근 가장 쓰이지 않은 캐시들을 없애는 방식을 의미한다. 데이터들 나이를 계산해 업데이트하고 캐시된 지 오래된 데이터를 지운다.


이 외에도 그룹캐시의 특징 몇 가지를 살펴보겠다. 첫째 그룹캐시는 추가적인 서버 그룹군을 요구하지 않는다. 만일 서버가 대규모고 구성하는 운영체제도 다양하다면 서버 설정, 배포를 일일이 해야하기 때문에 부담이 클 것이다. 하지만 그룹캐시는 클라이언트, 서버를 가리지 않고 어디나 적용 가능하며 스스로 관련있는 부분에만 접속한다. 둘째 이름의 뉘앙스처럼 캐시 관리가 자동적이고 합리적으로 이뤄진다. 멤캐시드는 대규모 클라이언트가 접속하면 예외처리를 하고 데이터베이스에 직접 로드를 부여하는 것이 어렵지만 그룹캐시는 가능하다. 셋째 대규모 서비스를 관리하다 보면 페일오버(Fail-over, 서버가 데이터를 처리중에 예상 밖의 시나리오를 접하게 되어 서버가 갑자기 종료되거나 리부팅되는 것을 의미) 문제에 부딪힌다. 그룹캐시는 페일오버에 대비해 캐시에 중요한 아이템들을 미러링해두고 가장 인기있는 키-값들을 유지한다.


<그림 1> 그룹캐시 의 역할 및 연동


<그림 1>은 기본적인 그룹캐시의 역할을 나타낸다. 다이어그램의 오른쪽 박스가 그룹캐시다. 그룹캐시는 라이브러리 형식으로 배포 되는데 이를 모듈화하여 실제 캐시 서비스처럼 동작하도록 만들 수가 있다. 컨테이너와 연결된 화살표는 모듈간의 관계다. 화살표에 실린 데이터가 무엇이든 그룹캐시가 n개의 컨테이너를 효율적으로 관리하고 운영하도록 간섭하는 역할을 한다는 의미다.


<그림 2> 기존의 서비스와 그룹캐시


<그림 2>처럼 기존의 서비스가 어떤 형태든지 그룹캐시를 추가하여 효율을 높일 수 있다. 그룹캐시 사용은 구현되어있는 라이브러리를 분석하려고 시도하지 않는 이상 마치 C/C++로 Hello World를 작성하는 것처럼 쓰기가 쉽다. 다음과 같이 작성한다.


<리스트 1> 그룹캐시 사용 me := "http://10.0.0.1" peers := 그룹캐시.NewHTTPPool(me) peers.Set("http://10.0.0.1", "http://10.0.0.2", "http://10.0.0.3")


그룹캐시에 대한 더욱 구체적인 설명과 분석, 적용에 대한 예제는 관련 홈페이지나 필자의 블로그를 참조하면 된다.


코어OS

코어OS는 대규모 서비스를 위한 컨테이너 관리 도구다. OS(운영체제)라는 이름을 붙인 이유는 어떠한 운영체제를 사용하는 서버라도 같은 커맨드를 활용하여 용이하게 관리할 수 있게 한다는 의미다. 코어OS를 그림으로 자세히 알아보겠다.


<그림 3>코어OS의 연동다이어그램


<그림 3>은 코어OS 의 구조를 간단하게 보여준다. 코어OS는 실제 OS나 가상머신(VM)을 의미하는 것은 아니며 껍데기 같은 역할을 한다. 코어OS는 리눅스 기반 컨테이너들을 사용하여 서비스를 관리하게 하고 추상화 레벨에서의 유지, 관리, 보수를 지원한다. <그림 3>에는 자세히 나와있지 않지만 코어OS 는 몇 개의 주요 구성요소로 이루어져 있으므로 더욱 효율적으로 각자의 역할에 집중하게 하는 구조를 갖고 있다. 이런 구조에서는 아무래도 컨테이너가 가장 중요하다.


컨테이너는 도커에서 주로 활용하는 요소다. 구글, 페이스북 등이 도커에 관심을 갖고 있다. 도커는 ‘기준 이미지(캐시, 서버 등) 포맷’으로 볼 수 있다.


<그림 4>Dockers와 코어OS


도커 기술은 이미지를 컨테이너에 실어 가상 서버로 옮기는 작업을 시행한다. 우분투, CentOS 등이 고유의 도커 이미지를 가지고 있다.이런 이미지들이 특정 OS에서 작동하는 방식이다. 코어OS는 그 중 하나다. <그림 4>에서 보듯 코어OS는 도커와 ETCD로 이뤄졌다.


ETCD

<그림 3>과 <그림 4>에서 확인했듯이 코어OS의 구성요소 중 하나가 ETCD다. 이름에서 알 수 있듯이 ETCD는 데몬이며 독립적으로 동작하면서 다양한 운영체제들을 연결하는 역할을 한다.


<그림 5>ETCD 의 동작원리


*ETCD의 기능 1. 서비스 탐색 가장 핵심적인 기능이라고 할 수 있는 서비스 탐색 시나리오이다. 코어OS 는 etcd가 역할을 하지 않으면 섬처럼 고립될 것이라고 추측할 수 있다. <그림 3>에서도 확인했듯이 다수의 코어OS가 특정한 서비스들을 실행 (웹서버, 데이터베이스)할 때 원격으로 서비스 탐색이 실행되지 않는다면 해당 서비스를 이용할 수 없다. 2. 컨피규레이션(Configuration) 서버의 특정 컨피규레이션을 읽어오고 작성하는 역할을 한다. 키-값으로 이를 저장하는 기능도 수행한다. 3. 리더 선출 리더 선출은 특히 페일오버를 대비한 중요한 알고리즘이며 주기적으로 서버 상태와 업데이트 설정을 파악해 다수 서버 중에 리더를 선출하는 알고리즘이다. 4. 로그 미리 입력(WAL) WAL는 데이터베이스에 로그를 미리 입력하는 기술이다. 이 기술은 페일오버를 대비해 리더 선출을 가능케 한다. 보통 로그는 문제 발생 후 이유를 추적하는데 대규모 서비스에는 적합하지 않다. 이미 서버가 다운된 뒤 로그 분석을 하면 늦기때문이다. WAL은 페일오버의 기미가 보이면 로그를 미리 발생시키고 적용해 새로운 리더를 선출한다.


<그림 5>는 마스터와 팔로워의 관계를 명시한다. 마스터는 주기적으로 업데이트되고 변한다. 마스터와 함께 속성값들도 업데이트된다. 여기엔 데이터베이스 연결 관계와 일반 정보, 캐시 설정값, 페일오버 여부, 현재 서버의 상태 로그 등이 포함된다. 이 라이브러리들은 모두 Go로 작성됐다. CURL을 활용한 사용예제를 제시한다. ETCD가 작동한다는 가정 아래 <리스트 2>와 같은 요청에 대한 응답은 <리스트 3>이다.


<리스트 2> Etcd 요청 curl -L http://127.0.0.1:4001/v2/keys/_etcd/machines


<리스트 3> ETCD 의 JSON 응답 { "action": "get", "node": { "createdIndex": 1, "dir": true, "key": "/_etcd/machines", "modifiedIndex": 1, "nodes": [ { "createdIndex": 1, "key": "/_etcd/machines/machine1", "modifiedIndex": 1, "value": "raft=http://127.0.0.1:7001&etcd=http://127.0.0.1:4001" }, { "createdIndex": 2, "key": "/_etcd/machines/machine2", "modifiedIndex": 2, "value": "raft=http://127.0.0.1:7002&etcd=http://127.0.0.1:4002" }, { "createdIndex": 3, "key": "/_etcd/machines/machine3", "modifiedIndex": 3, "value": "raft=http://127.0.0.1:7003&etcd=http://127.0.0.1:4003" } ] } }


마지막 연재인 3회에서는 대규모 서비스에 Go의 적용 사례와 기술을 살펴봤다.



출처 : 마이크로소프트웨어 12월호

제공 : 데이터전문가 지식포털 DBguide.net