IBM Korea Skip to main content
       IBM 홈    |  제품 & 서비스  |  고객지원 & 다운로드  |  회원가입  

P2P 상호 운용성 확보하기 : JXTA 시스템 개발하기
목 차:
분산된 데이터 수집 문제 해결하기
초기 분석
솔루션
오류 회복성
JXTA 서비스와 JXTA 클라이언트 설계하기
집중 장치
수집기
실행중인 JXTA
매력적인 애플리케이션 패턴
TCP/IP를 넘어선 네트워킹
참고 자료
필자 소개
기사에 대한 평가
관련 dW 링크:
Making P2P interoperable: The JXTA story
Making P2P interoperable: The JXTA command shell
The practice of peer-to-peer computing column archive
developerWorks newsletter 구독하기
US 원문 읽기
Also in the Web services zone:
튜토리얼
툴 및 제품
코드 및 컴포넌트
기사
기존의 네트워크 경계를 넘어 확장되는 P2P 시스템 설계


Sing Li
작가, Wrox Press
2002년 4월

모바일 컴퓨팅의 인기가 높아지고 네트워크에 연결 가능한 내장 마이크로프로세서가 널리 적용됨에 따라 TCP/IP 프로토콜이 마침내 그 노후성을 드러내고 있다. JXTA는 현재의 TCP/IP 기반 네트워크의 한계를 넘어 인터넷의 범위를 확대하려는 의도에서 설계되었다. JXTA에 대한 developerWorks의 시리즈 중 최종회에서 Sing Li는 이러한 확장을 보여 주고 실질적인 문제를 해결하는 시스템을 설명한다. 여러분은 JXTA가 클라이언트-서버 네트워크의 일반적인 제약 사항에 구속되지 않음을 보게 될 것이다.

지금까지 이 시리즈에서 우리는 자바 참조 구현을 가진 새로운 P2P 플랫폼인 JXTA가 어떻게 작동하는지에 대해 기본적인 사항들을 살펴보았다. 첫회에서는 상호 운용 가능한 JXTA의 기능들을 살펴보았다. 상호 운용 가능한 프로토콜 세트로 정의되는 JXTA는 여러 하드웨어 플랫폼, 운영 체제, 프로그래밍 언어들에서 구현될 수 있다. 우리는 또한 JXTA의 운영 모델과 피어, 피어 그룹, 서비스 및 파이프와 같은 중요한 개념들도 다루었다. 2회에서 우리의 포커스는 JXTA를 구동시켜 실행시키는데 맞추어졌다. 우리는 한 JXTA 애플리케이션 -JXTA 셀-을 검토하여 파이프를 만들고 한 피어에서 다른 피어로 메시지를 보내는 시나리오를 실행하였다. 우리는 또한 JXTA 셀 확장자를 작성하여 JXTA API에 대한 첫번째 프로그래밍 경험을 얻었다. 이렇게 지금까지 우리의 JXTA 접근 방식은 상향식이었다. 시스템 프로그래밍과 엔지니어링 배경을 가진 우리에게는 이것이 가장 자연스러운 방식이다.

3회이자 마지막 회인 이번 글에서 우리는 접근 방식을 하향식으로 바꾸어 보겠다. 이 글은 애플리케이션 레벨 설계와 아키텍처에 관해 작업하는 사람들의 견해를 취하여 JXTA에 대해 하향식으로 접근한다. 우리는 하나의 특정 예제 문제를 가지고 시작하여 그 문제에 대한 솔루션을 분석하고 설계하며 JXTA가 그 문제를 어떻게 자연스럽게 해결하는지를 보여 주겠다.

우리는 JXTA가 병치 (juxtaposition)를 이용하여 네트워킹 경관을 어떻게 변화시키는지를 밝히고 JXTA 서비스와 클라이언트의 설계와 코드도 제시하겠다.

분산 데이터 수집 문제 해결하기

우리가 대단위 기상 데이터 수집 및 분석 시스템을 개발해야 한다고 상상해 보자. 이 시스템에서 우리는 수백개의 기상 데이터 수집 지점을 가지고 있다. 이들 각각에는 현재 온도 (그리고 다른 대기 상태들)를 한 세트의 데이터 집중 장치에 제공하는 모형 기상 관측소가 설치되어 있다. 수집기들은 전 세계에 흩어져 있고, 이들 모두가 인터넷에 직접 연결되어 있는 것은 아니며 새로운 데이터 수집기는 때때로 연결이 끊기기도 한다. 이 프로젝트에 참여하는 수집기의 정한 숫자는 계속 바뀐다. 데이터 분석과 처리는 지역별 평균에 기초한다.

출발할 때는 단지 10개의 집중 장치가 있었다. 각 집중 장치는 많은 수집기들이 보내는 데이터를 모니터링하고 이 데이터는 실시간으로 관계형 데이터베이스에 전달된다. 그 후에 관계형 데이터베이스의 데이터는 기상 분석과 예측을 위한 시뮬레이션 모델을 운용하는 수퍼 컴퓨터에 전달되고 여기에서 처리된다. 집중 장치의 수와 위치는 다양할 수 있지만, 행동은 덜 변화한다. 일단 설치되면 시스템 장애가 없는 한 계속 운영된다.

우리가 해결해야 하는 문제는 어떻게 우리 시스템이 지속적으로 작동하게 하고 전체 성능에 영향을 미치지 않으면서 수집기와 집중 장치를 동적으로 추가하고 제거할 수 있도록 하는가이다.

초기 분석 : 임시 네트워크의 복잡성

시스템 내의 일부 수집기는 직접적인 인터넷 연결을 가지고 있지만, 일부는 무선 전송 기술로 연결되어 있고 거친 외부 환경 속에 있다. 사실 이들 무선 전신 기반 수집기 중 많은 것이 전력을 보존함으로써 배터리 수명을 절약하도록 설계되어 있다. 이들은 가장 가까운 수집기나 기지에 접속할만큼의 범위만 가지고 있다. 이 중 많은 수집기들이 TCP/IP를 지원하지 않으며 대신 미숙한 패킷 무선 기술을 사용한다. 몇 개의 좀 더 고립된 수집기들은 전력을 오직 태양 전지판에서 얻으며 위성 전송을 사용하여 통신한다. 그러나 또다른 그룹은 표준 셀룰러 폰과 연결되어 있고 SMS (short message service) 메시징을 사용하여 메시지를 전송한다.

사용 가능한 수집기의 수는 프로젝트 과정 동안 변동적일 것이다. 프로젝트를 시작할 때 우리는 미래의 수집기에 구축될 연결성의 유형과 이들이 사용할 기술을 예측하지 못했다. 예를 들어, 프로젝트의 한 단계에서는 소프트웨어 시뮬레이션을 사용하여 많은 수집기들을 내부적으로 시뮬레이션하기 위해 수퍼 컴퓨터 클러스터가 사용되었다. 우리의 솔루션은 실제의 그리고 시뮬레이션된, 현재와 미래의 모든 수집기에 적용될 수 있어야 한다.

솔루션 : 병치
그림 1은 이 문제를 해결하기 위한 상위 레벨 설계를 보여 준다.

그림 1. 데이터 수집 문제 해결하기
Solving the data collection problem

네트워크의 다양한 상황을 수용하기 위해 병치된 P2P 네트워크를 사용하는 한편 집중 장치는 데이터베이스 서버와 수퍼 컴퓨터가 있는 기존의 클라이언트/서버 네트워크와 P2P 네트워크에 대한 연결을 제공하고 있다는 사실에 주의한다. 집중 장치들은 두 네트워크간의 교량 역할을 하는데, P2P 네트워크의 동적인 특성과 클라이언트/서버 네트워크의 정적인 특성을 모두 가지고 있다.

이 아키텍처는 juxtaposition (병치 : JXTA라는 이름이 만들어진 바로 그 단어)를 이용해 기존 시스템들을 보완하고 이들에게 부가된 가치를 제공하는 JXTA의 역량을 나타낸다.

우리는 별로 독특할 것이 없는 클라이언트/서버 네트워크의 상세 사항은 다루지 않을 것이다. 우리는 VPN 기술을 사용해 이를 인터넷 상에서도 실행시킬 수 있다. 흥미를 끄는 부분이 P2P 네트워크이다. 그림 2는 그 구성을 보여주는데, 앞으로 변화하기 싶다. 관련된 기술들의 다양성에 주목하기 바란다.

그림 2. 데이터 수집기 네트워크 구성
Data collector network composition

엔드포인트 프로토콜 지원

JXTA의 자바 참조 구현은 우리가 기상 네트워크 예제에서 설명할 비 TCP/IP 네트워크에 대한 엔드포인트 프로토콜을 가지고 있지 않다. 그러나 JXTA 설계가 지닌 고유한 계층 기능 덕분에 수집기가 JXTA의 어떤 기존 구현이라도 운영할 수 있는 경우 여러분은 이러한 프로토콜을 지원하도록 코딩할 수 있다.

P2P 네트워크를 구현할 때 우리는 JXTA를 사용하여 다음과 같은 이점을 얻을 수 있다.

  • JXTA의 통일된 비집중식 주소 체계에 의한 새로운 수집기나 집중 장치의 손쉬운 추가와 삭제

  • JXTA의 네트워크 가상화에 의한 설계의 간편성

  • JXTA의 오류 회복 기능에 의한 지속적인 운영

  • JXTA의 동적이고 자기 조직적인 네트워크 지원에 의한 메인터넌스가 필요 없는 운영

  • 많은 하드웨어 플랫폼과 프로그래밍 언어에 걸친 다양한 구현에 대한 지원과 사용되는 다양한 통신 프로토콜에 대한 지원

이들 중 몇 개를 좀 더 상세히 살펴보고 JXTA가 우리 아키텍처의 각 측면에 어떻게 기여하는지를 알아 보자.

통일된 비집중식 주소 체계
통일된 비집중식 주소 체계란 피어가 현재의 DNS에서 거쳐야 하는 어떠한 등록 담당자나 중앙 기관을 거치지 않고도 스스로 ID를 생성할 수 있고 네트워크에 즉시 참여할 수 있다는 의미이다. 이 기능은 우리가 언제라도 네트워크에 수집기와 집중장치를 추가할 수 있음을 의미한다.

이 글에서 제공하는 코드 패키지(참고 자료에서 다운로드받을 수 있다)에서 우리는 새로운 JXTA 서비스와 파이프에 대한 주소를 생성하는데 사용되는 mdidgen이라는 유틸리티를 제공하였다 (mdidgen에 대한 추가 정보는 보조자료 mdidgen 유틸리티를 참조한다). 피어, 피어 그룹, 서비스 및 파이프와 같은 JXTA 객체에 대해 체계적으로 주소를 지정하기 위해 JXTA가 어떻게 사용되는지에 관한 상세 사항은 이 시리즈의 첫회를 읽기 바란다.

JXTA 네트워크의 피어는 개별적인 물리적인 존재를 가지고 있을 필요가 없다는 점에 주의한다. 우리의 예에서 우리는 각자 자체적인 통일된 주소를 가지고 있는 수많은 수집기들을 모방하는 수퍼 컴퓨터 클러스터를 사용하였다. 이 시뮬레이션된 수집기들 각각은 실제로 존재하는 피어들과 구별이 불가능한 피어로써 P2P 네트워크의 나머지 부분에서 열람된다.

네트워크 가상화

비집중화된 주소 체계에 의해 네트워크에서 유일한 ID를 받은 후에 모든 수집기와 집중 장치들은 즉각적으로 네트워크에서 피어가 될 수 있고 서로 통신을 시작할 수 있다. 이들은 무수한 상이한 메시징 메커니즘을 통해 서로에게 도달하지만, 그림 3에서 보여지듯이 JXTA 레벨에서는 모드 가상의 망사형 네트워크에 있는 노드일 뿐이다.

그림 3. 네트워크 가상화
Network virtualization

수집기와 피어를 실제로 상호 연결하는 모든 상이한 전송 및 주소 스키마들이 가상화되며, 모든 피어가 다른 모든 피어에 연결되는 망사형 네트워크만 남게 된다. JXTA는 통일된 주소 스키마와 매우 느린 바인딩을 사용해 복수의 엔드포인트 프로토콜 상에 지능적인 메시지 라우팅 계층을 추가함으로써 이를 수행한다. 본질적으로, 각 엔드포인트 프로토콜이나 전송 스택은 가상화된 JXTA 네트워크의 추진자가 되며 가상화된 네트워크를 실제 네트워크로 매핑시킨다. 그림 4에 이 설정이 나와 있다.

그림 4. 엔드포인트 프로토콜
Endpoint protocols as drivers

엔드포인트 프로토콜에 적합한 통신 프로토콜이 되려면 두 개의 물리적 노드 간에 XML 메시지를 주고 받을 수 있기만 하면 된다. 전송의 신뢰성이나 메시지 방송에 대한 지원이 필요 없다. 이리하여 가장 간단한 패킷 무선 프로토콜이 TCP/IP와 같은 복잡한 다계층 프로토콜과 나란히 엔드포인트 프로토콜로 사용될 수 있다. 이것은 왜 실제로는 아주 다른 레벨에 존재하는 HTTP와 TCP/IP가 JXTA 스택의 동일한 레벨에 있는 엔드포인트 프로토콜인지를 설명해준다. HTTP는 한 피어에서 다른 피어로 전달되는 메시지를 얻기 위해 필요한 많은 파이어월들을 통과할 수 있는 능력 때문에 지원되는 엔드포인트 프로토콜이다.

JXTA 네트워크의 각 피어는 동시에 여러 개의 엔드포인트 프로토콜을 지원할 수 있고, JXTA 가상 네트워크 메커니즘은 가상화된 통일된 네트워크 주소를 실제 네트워크 주소 (JXTA에서는 네트워크 엔드포인트라고 불림)를 가능한한 느리게 매핑시킬 것이다. 본질적으로 한 피어는 물리적인 엔드포인트들의 집합에 대응되며, 이들 각각은 완전히 다른 물리적 통신 프로토콜에서 구현될 수 있다. 상위 레벨 가상화와 라우팅 서비스는 이들을 보이지 않게 유지할 것이다. 많은 사람들이 오늘날의 인터넷을 현실로 만든 장비와 동일한 멀티프로토콜 라우터의 아주 발전된 형식으로 이를 인식할 것이다. 이 개념의 발전이 보다 널리 확산되는 인터넷 버전으로 우리를 이끌 것은 아주 자연스러운 일이다.

그림 5에서 우리 예제를 좀 더 자세히 살펴보자. 피어 A는 우리 네트워크의 한 수집기로써, 일련의 중개 수집기(피어 B,C,D)를 통해 집중장치 (피어 E)에게 데이터를 보내려고 시도한다. 그림의 각 피어 아래에는 피어가 지원하는 프로토콜의 목록이 나와 있다.

그림 5. JXTA 라우팅 예제
JXTA routing example

피어 A는 피어 E에 직접 연결되어 있지 않기 대문에 그 메시지는 중개 피어인 B,C,D에 라우팅되어야 한다. JXTA는 메시지를 자동으로 라우팅할 것이다.

  • TCP/IP를 사용하여 피어 A에서 피어 B로

  • 패킷 라디오를 사용하여 피어 B에서 피어 C로

  • SMS를 사용하여 피어 C에서 피어 D로

  • HTTP를 사용하여 피어 D에서 피어 E로

피어 E는 자신이 생성한 파이프 상에서 피어 A로부터 메시지를 받을 것이며, JXTA가 대신 수행한 복잡한 작업들을 전혀 알지 못할 것이다. 피어 C에서 피어 D로의 경로는 비대칭적이라는 데 주의한다. JXTA는 그러한 상황을 처리하도록 구체적으로 설계되었다. 메시지가 피어 E에서 피어 A로 재전송되면 JXTA는 자동적으로 피어 D에서 피어 C로 다이얼업 모뎀 PPP 라우팅을 사용할 것이다.

오류 회복성

위에서 설명한 라우팅 기능만으로도 이미 아주 놀랍지만, JXTA는 P2P 네트워크의 변화하는 위상에 부응하기 위해 훨씬 더 많은 것을 수행할 수 있어야 한다. 특히 메시지 라우팅 에이전트로 작동할 때 P2P 피어의 비신뢰성을 다룰 수 있어야 한다. 우리의 경우에 메시지를 라우팅하기 위해 다른 수집기에 의존하는 수집기는 중계 수집기가 사용할 수 없게 되면 통신을 할 수 없을 것이다.

JXTA는 피어가 네트워크에 들어오고 나가는 순간에 메시지를 재라우팅하는 기능을 가지고 있어야 한다. 그림 5의 라우팅 예제를 다시 고려해보자. 어떤 이유로 피어 A가 메시지를 보낸 직후에 (현재 전송 중임), 그리고 메시지가 피어 C에 도착하기 전에 C와 D간의 위성 링크가 다운되었다고 가정해 보자. JXTA는 대체 경로를 통해 피어 E에게 메시지를 동적으로 재전송할 수 있어야 한다 (다른 중계 노드 세트를 통해). 이러한 동적인 라우팅은 최선의 노력에 따라 수행된다. 때때로 어떤 라우팅도 가능하지 않을 경우 메시지를 잃어버리기도 한다. 이러한 라우팅은 피어 E (예를 들어, HTTP에서 TCP/IP로)에 도착하기 위해 사용되는 실제 엔드포인트 프로토콜을 변경할 수 있기 때문에, 피어를 물리적 엔드포인트에 바인딩시키는 일은 경로의 마지막 지점까지 발생하지 않을 수도 있다. 이것이 JXTA의 매우 느린 바인딩의 본질이다.

피어 그룹 레벨 (피어 그룹에 대한 상세 사항은 이 시리즈의 첫회를 참조한다.)에서 JXTA는 피어 그룹 내에서 항상 사용 가능해야 하는 중복적으로 구현된 서비스인 피어 그룹 서비스를 지원함으로써 오류 회복 기능을 지원한다.

동적이고 자기 조직적인 네트워크

통일된 가상 네트워크 ID를 가진 피어는 JXTA 네트워크에 삽입될 때 다음과 같이 자신을 부트스트랩해야 한다.

  • 로컬 피어의 위치를 찾고 기능을 검색한다.

  • 사용 가능한 피어 그룹을 검색하고 여기에 참여한다.

  • 피어 그룹에서 사용할 수 있는 서비스를 검색하고 이들을 이용하기 시작한다.

우리는 2회에서 이 작업이 advertisement라고 불리는 다른 유형의 메시지를 공개하고 중계하며 즉각적으로 캐시에 저장하고 검색함으로써 메시지 레벨에서 수행된다고 배웠다. JXTA의 자바 참조 구현은 이러한 공개-캐시-검색 프로세스를 용이하게 하는 해결자와 집결 서비스 계층을 가지고 있다.

JXTA의 피어 그룹은 네트워크 분할 메커니즘으로 작용하는데, advertisement가 이들을 사용할 수 있는 그룹 멤버들에게만 중계되도록 보증한다. 다른 피어 그룹들은 다르게 혼합된 피어와 피어 그룹 서비스를 가지고 있고, 기능을 제공하기 위한 번들링으로 활동한다. 피어 그룹은 또한 특정 애플리케이션에 대한 인증 도메인 역할도 한다.

mdidgen 유틸리티

유틸리티 클래스 com.ibm.jxta.mdidgen은 JXTA 객체에 대한 통일된 주소를 비집중식 방식으로 생성하는데 사용된다. 이 유틸리티는 새로운 ModuleClassID, 대응하는 ModuleSpecID 및 그룹 (구동시 읽혀지는 설정 파일에 지정되어 있음)과 연관된 새로운 PipeID를 생성한다. 생성된 이들 ID는 자바 선언 형식을 사용할 준비가 되어 있고, 여러분 코드에 바로 삽입될 수 있다. 이것이 ModuleSpecAdvertisement와 집중 장치 서비스 파이프의 ID를 생성하는 방식이다.

JXTA 서비스와 JXTA 클라이언트 설계하기
우리의 기상 관측소 예로 돌아가 보자. 개념적으로, 집중 장치는 다음과 같은 것을 수행해야 한다.

  1. 집중장치에게 어떤 JXTA 그룹에 참여할지 알려주는 적절한 설정 파일을 읽고 처리한다. (우리 예제에 대한 설정 파일이 샘플 코드 패키지에 들어 있다.)

  2. JXTA를 구동시킨다.

  3. 설정 파일에 지정된 그룹에 참여한다.

  4. 집중 장치에 대한 서비스 advertisement가 제공되어 있는지 검색한다. 제공되어 있지 않으면 하나를 만들고 이를 공개한다.

  5. 서비스에 대응하는 입력 파이프를 생성한다.

  6. 수집기로부터 도착하는 메시지를 위해 파이프에서 대기한다.

  7. 메시지가 도착하면 이를 처리하여 RDBMS에 저장한다.

  8. 6단계로 돌아간다.

이 로직은 com.ibm.jxta.Concentrator 클래스에서 구현된다. 여러분은 이 클래스와 이 글에 나온 다른 모든 코드를 참고자료에서 다운로드받을 수 있다.

수집기는 다음을 구현해야 한다.

  1. 설정 파일을 읽고 처리한다.

  2. JXTA를 구동시킨다.

  3. 설정 파일에 지정된 그룹에 참여한다.

  4. 집중장치 서비스에 대한 서비스 advertisement를 검색한다. 이것이 사용가능하지 않으면 계속 진행할 수 없다.

  5. 서비스 advertisement에서 파이프 정보를 추출한다.

  6. 정기적인 간격으로 데이터를 수집한다.

  7. 수집기의 위치와 데이터를 포함하고 있는 메시지를 생성한다.

  8. 파이프를 통해 집중장치 서비스에게 메시지를 보낸다.

  9. 6단계로 돌아간다.

위의 로직은 com.ibm.jxta.Collector 클래스에서 구현된다.

DwJxtaPeer 수퍼 클래스로 일반 작업 factoring하기

수집기와 집중 장치의 역할에 공통되는 많은 작업들이 있다. 코드의 불필요한 중복을 없애고 향후 유지보수 작업을 간편하게 하기 위해 이 공통 작업들을 com.ibm.jxta.DWJxtaPeer라는 수퍼 클래스로 factoring해보자.

이 공통 작업들 중 하나는 ModuleSpecAdvertisement에 대한 검색을 수행하는 것이다. (advertisement에 대한 상세 사항은 JXTA에서의 서비스 Advertisements를 참조한다.) 이것은 Listing 1의 findModuleSpecAdv() 메소드에 의해 수행된다.

Listing 1. findModuleSpecAdv()

protected ModuleSpecAdvertisement findModuleSpecAdv()  {
   return (ModuleSpecAdvertisement) findAdv("ModuleSpecAdvertisement",
      "Name",ModuleSpecName,  new ModuleSpecAdvValidator(), false );
}

findModuleSpecAdv()findAdv()라는 또다른 일반 메소드를 호출한다는데 주의한다. 우리는 advertisement를 검색하기 위해 이 메소드를 사용한다. findAdv()의 인자는 다음과 같다.

인자 설명
AdvType advertisement의 유형을 문자열로 기술 -- 예 : PipeAdvertisement
Attr advertisement를 검색할 때 매치되는 태그 -- 예 : Name
Value 지정된 속성과 일치되는 값
Validator FindValidate 인터페이스를 구현하는 객체, 이 객체는 checkAdv()라는 하나의 메소드를 가지고 있는데, 발견된 advertisement를 긍정적으로 확인하는데 사용된다
LocalOnly 검색이 로컬로만, 혹은 네트워크 상에서 원격으로만 수행되어야 할 때 이를 나타내는 boolean 태그

Listing 2에 나와 있는 것처럼, 메소드의 첫번째 부분은 그룹의 검색 서비스의 getLocalAdvertisement() 메소드를 사용하여 로컬 advertisement 캐시에 있는 advertisement만 검색한다. 발견된 advertisement를 확인하기 위해 validator.checkAdv()를 호출하는데 주의한다.

Listing 2. findAdv(), Part 1

  protected  Advertisement findAdv(String advType, String attr, String val,
       FindValidate validator, boolean localOnly) {
        Enumeration enum = null;
        System.out.println("Looking for " + advType + ", please wait...");
        // First look in the local storage
         try {
            enum = discovery.getLocalAdvertisements(DiscoveryService.ADV,
           attr, val);

          } catch (Exception e) {
          }



         if ((enum != null) && (enum.hasMoreElements())) {
                Advertisement adv = null;
                while (enum.hasMoreElements()) {
                    try {
                        adv = (Advertisement) enum.nextElement();
                        if( validator.checkAdv(adv))
                                return adv;
                        } catch(Exception e) {
                        continue;
                           }
                       } // while
              } // if

검색이 로컬에서 수행되어야 하면 로직은 여기에서 멈춘다. 그렇지 않다면 네트워크에 조회를 보내어 원격 검색을 수행한다. 발견된 advertisement는 검색 서비스에 의해 로컬 캐시에 저장될 것이다. 우리는 원격 검색이 수행되도록 얼마간의 시간을 주기만 하면 된다. Listing 3에서 우리는 약 5초 정도 루프를 돌린다.

Listing 3. findAdv(), Part 2

        if (localOnly)
           return null;

        System.out.println("   cannot find it locally, trying remote");
        // Now, search remote
        discovery.getRemoteAdvertisements(null, DiscoveryService.ADV,
                attr, val, 2, null);

        // Wait a bit in order to get an answer.
         int i=0;
         while (true) {
         try {
               if (i>MAXRETRIES){
                System.out.print(".");
                break;
            }
            Thread.sleep(WaitingTime);
            i++;
        } catch (Exception e) {
        }
        System.out.println("");

이 지점에서는 발견된 어떤 advertisement라도 로컬 캐시에서 사용 가능해야 한다. Listing 4에서 우리는 로컬 체크를 다시 수행한다.

Listing 4. findadv(), Part 3

      // Look in the local storage again
        try {
            enum = discovery.getLocalAdvertisements(DiscoveryService.ADV,
                    attr, val);

            if ((enum != null) && (enum.hasMoreElements())) {
                Advertisement adv = null;

                while (enum.hasMoreElements()) {
                    try {
                        adv = (Advertisement) enum.nextElement();
                          if( validator.checkAdv(adv))
                                return adv;
                        } catch(Exception e) {
                        continue;
                    }
                } // while
            }
        } catch (Exception e) {
        }
       }
        return null;
    }

T이 수퍼 클래스에 있는 다른 두개의 공통 메소드가 아래 표에 설명되어 있다. 여러분은 연습 삼아 이들을 분석해 볼 수 있다.

메소드 설명
PublishModuleSpecAdv() 검색 프로세스가 서비스에 대한 기존 ModuleSpecAdvertsiement를 발견하지 못한 경우 집중 장치에 의해 호출된다. 이 메소드는 서비스를 생성할 것이다 (우리가 생성한 고정된 서비스 ID에 기반하여). 이 advertisement는 로컬과 원격으로 공개될 것이다. advertisement 생성은 집중 장치가 구동될 때, 설정이 바뀔 때, 혹은 로컬 매시가 변경되었을 때만 필요하다.
JoinGroupIfExists() 집중 장치와 수집기 양자에 의해 호출된다. 이 메소드는 포괄적인 NetPeerGroup (모든 피어가 속한 기본 그룹)의 자식인 지정된 하위 그룹에 참여하려고 시도한다.

Listing 5에서 DwJxtaPeer 클래스의 상수 선언 섹션의 일부분을 살펴보자

Listing 5. Module ID definitions

public static final String ClassID = 
"urn:jxta:uuid-EE99266A1DE84E3DB34D9CC842EC889105";
public static final String SpecID = 
"urn:jxta:uuid-EE99266A1DE84E3DB34D9CC842EC8891B9EB13ECA6FE44DDA112B5F5E357763006";

Service advertisements in JXTA

서비스 advertisement 개념은 서로 관련된 세 advertisement 세트로 나누어진다.


ModuleClassAdvertiseent
ModuleSpecAdvertisement
MdouleImplAdvertisement

이것은 시스템상에서 이동하는 advertisement의 크기를 줄이고, 서비스의 일반 클래스 (즉 banking)와 그 클래스에 대한 특정 사양 (예금과 출금 API) 및 서비스 구현 (즉 API의 자바 기반 구현)간의 관계를 표준화하는데 필요하다.

애플리케이션, 즉 JXTA 서비스는 이 advertisement들을 모두 사용하지 않아도 되고, 필요한 것만 사용하면 된다. 우리 시스템에서 우리는 ModuleSpecAdvertisement만 필요한데, 서비스를 파이프에 결합시키고 advertisement가 원격으로 검색될 수 있도록 하는데 이를 사용한다.

이들은 mdidgen 유틸리티를 사용하여 생성된 ModuleClassIDModuleSpecID 이다. 이들은 집중 장치 서비스의 ID에 대응한다. 이 서비스의 ID는 모든 수집기에 알려지고, 일단 생성되면 동일하게 유지된다. 따라서 그룹내의 수집기들은 집중장치 서비스를 신뢰성 있게 검색할 수 있다. ModuleClassIDModuleSpecID를 생성할 때 필요하기 때문에 여기에 존재한다. 이 ID들을 쉽게 생성하기 위해 우리는 W.R. Bauer(vasha@jxta.org)가 개발한 jxta-wire라는 JXTA 프로젝트의 일부인 AdvCooker 라이브러리를 사용한다.

네트워크에서 작동하고 있는 집중 장치들의 모든 인스턴스들은 동일한 집중장치 피어 그룹 서비스 (동일한 ModuleSpecID를 사용하고전파 파이프의 동일한 논리적 인스턴스를 듣는)에 응답할 것이다 . 이러한 중복 구현은 집중 장치 서비스가 피어 그룹에서 항상 사용 가능하도록 보장할 것이다.

집중장치 : JXTA 피어 그룹 서비스

com.ibm.jxta.Concentrator 구현을 살펴 보자. 우리가 언급했듯이, 이 구현은 DwJxtaPeer 클래스에서 상속된다 (그리고 이를 확장한다.) 다음은 Concentrator를 메소드별로 서명한 것이다.

메소드 설명
init()

클래스에 호출되는 첫번째 메소드일 것이다. private jxtaInit() 메소드를 호출하고 출력 집중장치 서비스 파이프의 인스턴스를 만들어낸다.

process() 이 메소드는 무한 루프로 간다. 수집기 데이터가 들어오는지 보기 위해 입력 집중장치 서비스 파이프를 듣는다. 들어오는 각 데이터에 대해 processData()를 호출하여 데이터를 처리한다.
findPipeAdv() 서비스 파이프 advertisement에 대해 로컬 검색을 수행한다. (즉 로컬 캐시만 체크한다)
jxtaInit() 이 메소드는 우선 설정 파일을 읽고 우리가 참가할 그룹을 지정한다. 그리고 JXTA와 NetPeerGroup을 구동시킨 후 수퍼 클래스의 joinGroupIfExist()를 호출하여 지정된 그룹에 참가한다. 그리고 가능한 경우, 로컬 캐시에서 서비스 파이프 advertisement를 검색한다. 검색되지 않으면 새로운 것을 생성할 것이다 (createInputPipeAdvIfNotExist()를 사용하여). 마지막으로 이 메소드는 ModuleSpecAdvertisement가 발견될 수 있는지를 보기 위해 검색을 수행한다. 없으면 새로운 것을 만들고 공개한다.
processData() 이 메소드는 플레이스홀더이다. 실제 프로젝트에서 이 메소드는 수집된 데이터를 (아마도 JDBC를 이용해) RDBMS에 제출하기 위해 백엔드 클라이언트/서버 네트워크를 사용할 것이다.
createInputPipeAdvIfNotExist() 이 헬퍼 메소드는 서비스 파이프 advertisement가 이용가능한지 보기 위해 먼저 캐시를 체크한다. 이용할 수 없으면 advertisement를 생성하여 이를 캐시에 저장한다. 어느 경우이든 모두 올바른 advertisement가 반환된다.

정적인 유형 정의에는 다음과 같은 것이 포함된다.


public static String servicePipeID = 
"urn:jxta:uuid-969610EE8945417CA56F9771197EE3965207E4C303154E7EB5878751AE22761804";

이것은 mdidgen 유틸리티에 의해 생성된 파이프 ID로써, 모든 집중 장치에 의해 사용되는 서비스 파이프에 대한 통일된 주소이다. 이것은 전파 파이프이며 따라서 메시지를 듣는 모든 집중장치는 수집기로부터 이 메시지들을 받아야 한다. 수집기는 ModuleSpecAdvertisement의 부분인 파이프 advertisement에서 이 파이프 ID를 얻는다. 그리고 검색 절차를 통해 이 advertisement를 발견한다.

수집기 : JXTA 클라이언트 로직 코딩하기

마지막으로, com.ibm.jxta.Collector 클래스에 한정된 메소드들을 살펴보자.

메소드 설명
init() 클래스로부터 호출되는 첫번째 메소드일 것이다. private jxtaInit()를 호출한 후 수집된 데이터를 집중 장치 서비스에 보내기 위해 사용되는 출력 파이프를 생성한다.
process() 이 메소드는 우선 측정된 데이터를 얻기 위해 collectData()를 호출한 후 JXTA 메시지를 생성하고 집중 장치 서비스를 통해 이 메시지를 대기하고 있는 집중 장치에 보내는 무한 루프를 가지고 있다. 각 샘플링은 루프 내의 정해진 시간까지 지연된다.
jxtaInit() 이 메소드는 우선 설정 파일을 읽고 우리가 참여해야 하는 그룹을 설정한 후 수집기의 위치를 결정한다. 그리고 JXTA와 NetPeerGroup을 구동시키고 수퍼 클래스의 joinGroupIfExist()를 호출하여 지정된 그룹에 참여한다. 그 다음 검색을 수행하여 잘 알려진 집중장치 서비스에 대응하는 ModuleSpecAdvertisement가 발견되는지 본다. 발견되지 않으면 종료될 것이다. ModuleSpecAdvertisment가 발견되면 이 메소드는 집중장치 서비스 파이프 advertisement를 추출하여 출력 파이프 생성을 준비할 것이다.
collectData() 이 메소드는 실제 데이터 집합을 위한 플레이스홀더이다. 실제 프로젝트에서 이 메소드는 다양한 데이터 입력 채널에 접근하고 (아마도 입력/출력 포트나 원시 모드를 사용하여) 수집된 데이터를 호출자에게 반환한 것이다.

작동중인 JXTA : 여러분의 머신에서 동적인 네트워크 테스트하기
이 글과 함께 제공되는 소스 코드 패키지는 실험을 용이하게 해줄 데이터 구조를 가지고 있다. 다음 디렉토리들이 코드 하위 디렉토리 아래에 있다.

디렉토리 설명
lib JXTA core의 최신 안정 구축판의 모든 jar 파일, JXTA 셀의 모든 jar 파일 및 jxta-wire 프로젝트의 jxta-wire.jar 파일을 여기에 둔다. (JXTA 셀과 jxta-wire에 대한 상세 사항은 참고 자료를 참조한다.)
src 우리 시스템의 소스 코드를 가지고 있다.
classes 우리 시스템의 컴파일된 클래스 파일들을 가지고 있다.
shell1 처음 실행된 디렉토리. 우리는 이 디렉토리에 있는 집중 장치 뒤에 셀을 생성할 것이다.
shell2 네트워크에 두번째 피어로 구축한다. 이것은 다른 집중장치를 실행시킬 것이다.
shell3 네트워크에 세번째 피어로 구축한다. 이것은 수집기를 실행시킬 것이다.

코드를 컴파일하려면 JDK 1.3 이상이 설치되어 있어야 한다. 코드 디렉토리에서 MAKEIT.BAT 배치 파일을 실행시킨다. 그러면 코드가 컴파일되어 클래스 디렉토리에 클래스 파일을 생성할 것이다.

다음에 MAKEJAR.BAT 배치 파일을 실행시킨다. 그러면 우리의 모든 코드를 포함하고 있는 dwjxta.jar 파일이 생성될 것이다. 이 파일을 lib에 둔다. 그러면 실험한 준비가 갖추어졌다.

이제 세 개의 다른 명령 창을 구동시킨다. 이들의 디렉토리를 각각 shell1, shell2, shell3으로 바꾼다.

shell1 디렉토리에서 runshell.bat 파일을 편집하여 설정 단계에서 보안을 구축하기 위해 사용할 사용자 ID와 패스워드를 지정한다. (패스워드는 적어도 8자 길이여야 한다.) runconc.bat and mdidgen.bat 파일에도 이 사용자 ID와 패스워드를 지정한다.

runshell.bat을 사용하여 셀을 실행시키고 이 피어를 다음과 같이 구성한다.

피어 명: 노드1
전송:

TCP/IP지원, HTTP 비활성화, act as rendezvous 체크, no relay

사용되는 TCP 포트: 9701
보안 사용자명과 패스워드: 배치 파일에 정의된대로

우리 시스템은 작업을 위한 그룹이 이미 만들어졌다고 가정하기 때문에, 이 그룹을 셀에 생성해야 한다. 셀에서 다음 명령어를 사용하여 dwtest 그룹을 생성한다.


Jxta> myadv = mkadv -g dwtest
Jxta> mygrp = mkpgrp -d myadv dwtest

그러면 우리가 사용할 dwtest 그룹이 만들어진다. 여러분은 이 그룹의 생성을 다음과 같이 확정할 수 있다.


Jxta>groups
group0: name = dwtest

이제 셀에서 빠져 나올 수 있다.

이제 mdidgen.bat 파일을 사용하여 통일된 주소(ID)의 비집중식 생성을 시도해 보자. 이를 실행시키면 다음과 유사한 출력을 얻게 될 것이다.

Listing 6. mdidgen.bat 출력

remote group discovery message sent
group joined successfully
public static final String ClassID = 
"urn:jxta:uuid-DCDD418FCC194040AA13A52A334B967105";
public static final String SpecID = 
"urn:jxta:uuid-DCDD418FCC194040AA13A52A334B96716C515B975C2941AD9FBC90178B6918A806";
public static final String PipeID = 
"urn:jxta:uuid-2184CACA259B42E0A866AEA788A923054C519D304E07415195B0917C81238FD004";

ModuleClassID, ModuleSpecIDPipeID가 생성되었다. 이것이 우리가 집중장치 서비스에서 사용되는 ID를 얻는 방법이다.

runconc.bat 파일을 실행시켜 집중장치를 구동시키자. 이 파일은 dwConfig 파일을 읽고, 집중장치에게 어떤 dwtest 그룹에게 참가할지를 말해준다. 여러분은 다음과 유사한 출력을 얻을 수 있을 것이다.

Listing 7. Concentrator #1 (runconc.bat) 출력

Starting Jxta...
Joining default NetPeerGroup...
Attempting to join group: dwtest
remote group discovery message sent
group joined successfully
group dwtest joined successfully
Look for previously created Pipe Adv, create one if not exist
Looking for PipeAdvertisement, please wait...
Previously published pipe advertisement not found, creating a new one.
Locally caching the new pipe advertisement...
Checking to see if MSA previously published...
Looking for ModuleSpecAdvertisement, please wait...
   cannot find it locally, trying remote
... MSA not found, need to create it
Creating new MSA
Locally and remotely publish the MSA
Creating pipe for data collection...
pipe created successfully
Waiting for data from collector...

이 지점에서, 집중 장치 인스턴스가 구축되고 수집기에서 오는 데이터를 받을 준비가 되었다.

이제 shell2 명령 창으로 가서 runconc.bat 파일에 여러분의 보안 사용자 ID와 패스워드를 입력한다. 그리고 나서 runconc.bat 파일을 사용하여 집중장치 인스턴스를 실행시킨다. 구성 절차에서는 다음과 같은 매개 변수를 설정한다.

피어명: 노드 2
전송: TCP/IP지원, HTTP 비활성화, no rendezvous, no relays
사용되는 TCP 포트 : 9702
보안 사용자명과 패스워드: 배치 파일에 정의된대로

모든 것이 올바로 작동한다면 여러분은 다음과 유사한 출력을 보게 될 것이다.

Listing 8. Concentrator #2 (runconc.bat output from Shell2)

Starting Jxta...
Joining default NetPeerGroup...
Attempting to join group: dwtest
remote group discovery message sent
group joined successfully
group dwtest joined successfully
Look for previously created Pipe Adv, create one if not exist
Looking for PipeAdvertisement, please wait...
Checking to see if MSA previously published...
Looking for ModuleSpecAdvertisement, please wait...
.. found previously published MSA
Creating pipe for data collection...
pipe created successfully
Waiting for data from collector...

중장치의 ModuleSpecAdvertisement가 발견되었음에 주의한다. 따라서 이 집중장치 인스턴스는 다른 것을 생성하지 않아도 된다. 이제 이 인스턴스 역시 수집기로부터 입력이 들어오는지 대기한다.

마지막으로, shell3 명령창으로 가서 runcoll.bat 파일에 여러분의 보안 사용자 ID와 패스워드를 입력한다. 다음에 runcoll.bat 파일을 사용하여 수집기 인스턴스를 실행시킨다. 이 인스턴스는 디렉토리 내의 dwColConfig 파일을 사용할 것인데, 이 파일은 수집기에게 어떤 dwtest 그룹에 참여해야 하는지 알려주고 그 위치가 "Timbuktu North"임을 알려준다. 구성 절차에서는 다음과 같은 매개 변수를 설정한다.

피어명: 노드 3
전송: TCP/IP지원, HTTP 비활성화, no rendezvous, no relays
사용되는 TCP 포트: 9703
보안 사용자명과 패스워드: 배치 파일에 정의된대로

수집기 인스턴스는 ModuleSpecAdvertisement를 찾기 시작할 것이고, 이를 찾아야 한다. 그리고 나서 이미 실행중인 집중장치와 통신하기 위한 파이프를 생성할 것이다. 여러분은 다음과 유사한 출력을 보게 된다.

Listing 9. Collector (runcoll.bat output from Shell3)

Reading config file, dwColConfig, and processing...
   group to join will be dwtest
   collector location is  Timbuktu North
Starting Jxta...
Joining default NetPeerGroup...
Attempting to join group: dwtest
remote group discovery message sent
group joined successfully
group dwtest joined successfully
Searching for collector's MSA...
Looking for ModuleSpecAdvertisement, please wait...
   cannot find it locally, trying remote
.. found collector's MSA
Extracting pipe adv from MSA...
Connecting to concentrator network...
pipe created successfully
... collecting data....
... data collected, sending to concentrator
waiting until next sample...
... collecting data....
... data collected, sending to concentrator
waiting until next sample...

데이터가 수집되어 정기적으로 집중장치 서비스에 전송된다. 데이터는 P2P 네트워크상을 이동하여 두 집중장치에게 보내져 처리된다.

매력적인 애플리케이션 패턴

우리의 기상 데이터 수집 예제는 일반적인 P2P 응용 시스템과 특히 JXTA에 널리 퍼져있는 애플리케이션 패턴을 보여준다. 이것은 두 개의 아주 느슨하게 결합된 요소를 포함하고 있는데, 소비자생산자가 그것이다. 소비자는 생산자가 만들어낸 제품을 원하는 반면 특정 생산자에게 강하게 묶이는 것은 원하지 않는다. 이러한 태도에는 실세계의 몇 가지 동기가 있을 수 있다. 소비자들은 다음을 원할 수 있다.

  • 주어진 시간에 이용할 수 있는 최상의 생산자를 선택할 수 있는 선택권을 가진다.

  • 한 생산자의 성공이나 실패에 의존하는 위험을 줄인다.

  • 규모와 토폴리지를 물리적으로 관리할 수 없는 매우 동적이고 규모가 큰 커뮤니티에서 선택한다.

현재 사용 가능한 인기 있는 전세계적인 파일 공유 시스템의 예와 같이 소비자와 생산자가 겹쳐질 때 패턴은 아주 흥미롭게 된다. P2P 시스템은 처음부터 기존의 네트워킹 기술과는 달리 이러한 애플리케이션 패턴을 수용하도록 설계되어 왔다. 특히 JXTA는 기존의 클라이언트/서버 기술을 설계할 때 제공해야 하는 복잡한 솔루션과 달리 이러한 시스템을 직접적이고 쉽게 개발할 수 있도록 한다.

TCP/IP를 넘어서는 네트워킹

JXTA가 추가하는 가치를 실질적으로 강조하기 위해 나는 전세계적인 기상 정보 수집 시스템을 예로 선택하였다. 그러나 문제와 솔루션은 몇 개만 나열하자면 모바일 영업팀 자동화, 상품 거래, 컨텐트 배포 및 비즈니스간 전자 상거래등과 같은 많은 비즈니스 시나리오에서 전형적인 특징들을 가지고 있다. 현재의 정적인 경계를 넘어 잘 확장되는 새로운 네트워크 솔루션을 구축하기 위해 기존의 클라이언트/서버 네트워크와 P2P 네트워크를 나란히 놓을 수 있다. 오픈 소스 JXTA 플랫폼은 이러한 신규 솔루션을 위한 수단이 될 것이다. 나는 이 시리즈가 JXTA가 제공하는 가능성을 탐사하도록 여러분을 고무시켰기를 바란다.

참고 자료

  • 이 글에 설명된 예제의 소스 코드

  • JXTA에 대해 더 많이 배우고 싶다면, Sing Li의 Early Adopter JXTA (Wrox Press, 2002)를 참조한다.

  • 이 시리즈의 1회인 "The JXTA story" (developerWorks, August 2001) : 프로젝트 JXTA의 개요와 이 신기술이 어떻게 P2P 애플리케이션을 간단하게 구성하도록 하고 원할하게 하는지를 설명한다.

  • 이 시리즈의 2회인, "The JXTA command shell" (developerWorks, September 2001) : JXTA 셀에 관해 자세히 설명한다. 여러분은 그 명령문 세트를 익히고 자바 프로그래밍 언어를 사용해 여러분 자신이 정의한 명령어를 사용하여 그 기능을 확장할 것이다.

  • Jxta.org, 공식 JXTA 커뮤니티 사이트 : 최신 사양, 문서, 소스 및 바이너리 파일들이 들어 있다.

  • Jxta.org의 jxta-wire 프로젝트 : 여러분은 이 글에 나온 예제를 실행시키기 위해 이 프로젝트의 코드가 필요할 수 있다.

  • 오픈 소스인 Voice over P2P Network 프로젝트에서 Sing Li와 전 세계의 엔지니어들과 함께 기존의 메가 스위치와 중앙 사무실에 의존하지 않는 혁신적인 P2P 음성 네트워크의 설계에 참여하라.

  • Todd Sundsted의 P2P 컴퓨팅의 실제 컬럼 (developerWorks) : P2P기반 기술의 모든 측면을 설명한다.

  • 대체 오픈 소스 P2P 시스템을 보려면 Freenet를 참조한다.

  • Advanced Peer-to-Peer Networking (APPN)는 확장성과 가용성이 높고 안전한 네트워크 솔루션을 제공한다.

  • Magstar Peer-to-Peer Virtual Tape Server는 데이터 가용성을 높이고 여러분의 재난 복구 인프라를 향상시키기 위해 설계되었다.

  • developerWorks Java technology zone. 자바 관련 수많은 자료들

필자소개
Photo of Sing LiSSing Li는 Wrox Press가 발간한 수많은 다른 책 뿐 아니라 Early Adopter JXTA Professional Jini의 저작자이다. 그는 기술 잡지에 정기적으로 기고하고 있고, P2P 애플리케이션의 적극적인 전도사이다. Sing은 컨설턴트 겸 프리랜서 작가이다.



이 기사에 대하여 어떻게 생각하십니까?

정말 좋다 (5) 좋다 (4) 그저그렇다 (3) 수정보완이 필요하다(2) 형편없다 (1)

  회사소개  |  개인보호정책  |  법률  |  문의