작성자: Tom Preston-Werner([email protected])
Ernie는 Erlang 서버를 사용하여 들어오는 연결을 수락한 다음 모든 언어로 작성할 수 있는 사용자 정의 모듈에 요청을 위임하는 BERT-RPC 서버 구현입니다(현재 Ruby 및 Erlang 지원만 포함됨).
Ruby 또는 Erlang 이외의 언어로 작성된 모듈을 "외부" 모듈이라고 하며 생성해야 하는 각 모듈의 작업자 수를 지정해야 합니다. 이러한 모듈에 대한 요청은 작업자 간에 균형을 이룹니다. Erlang으로 작성된 모듈은 "네이티브" 모듈이라고 하며 Erlang 서버의 런타임 내에서 실행됩니다. 이는 경량 프로세스로 생성되므로 균형 조정이 필요하지 않으며 외부 모듈과 비교할 때 통신 오버헤드가 훨씬 적습니다.
Ernie는 여러 이기종 모듈을 지원합니다. 예를 들어, 10개의 작업자를 실행하는 외부 Ruby 모듈 과 동시에 실행되는 기본 Erlang 모듈을 가질 수 있습니다. Ernie는 적절한 모듈에 대한 요청 전송을 추적합니다. "섀도잉"이라는 기술을 사용하면 네이티브 코드로 특정 외부 모듈 기능을 선택적으로 최적화할 수 있으며 Ernie가 올바른 기능 선택을 처리합니다.
bert-rpc.org에서 전체 BERT-RPC 사양을 확인하세요.
Ernie는 현재 다음 BERT-RPC 기능을 지원합니다.
call
요청cast
요청Ernie는 GitHub용으로 개발되었으며 현재 매일 수백만 건의 RPC 요청을 처리하는 프로덕션 용도로 사용되고 있습니다. 안정성과 성능이 모범적이었습니다.
Ernie는 릴리스 버전 관리를 위해 의미 체계 버전 관리를 따릅니다.
1단계: Erlang(R13B 이상)을 설치합니다.
http://www.erlang.org/download.html
2단계: Ernie 설치:
$ [sudo] gem install ernie
Usage: ernie [command] [options]
-c, --config CONFIG Config file.
-p, --port PORT Port.
-l, --log-level Log level (0-4).
-a, --access-log LOGFILE Access log file.
-d, --detached Run as a daemon.
-P, --pidfile PIDFILE Location to write pid file.
--name NAME Erlang process name.
--sname SNAME Erlang short process name.
-E, --erlang ERLANG_OPTIONS Options passed to Erlang VM.
Commands:
Start an Ernie server.
reload-handlers Gracefully reload all of the external handlers
and use the new code for all subsequent requests.
stats Print a list of connection and handler statistics.
Examples:
ernie -d -p 9999 -c example.cfg
Start the ernie server in the background on port 9999 using the
example.cfg configuration file.
ernie reload-handlers -p 9999
Reload the handlers for the ernie server currently running on
port 9999.
ernie -c example.cfg -E '-run mymodule'
Start the ernie server with an additional erlang module called
'mymodule'
Ernie 구성 파일은 일련의 점으로 구분된 Erlang 용어로 작성됩니다. 각 용어는 모듈에 대한 옵션을 지정하는 2-튜플 목록입니다.
네이티브 모듈의 형식은 다음과 같습니다.
[{module, Module},
{type, native},
{codepaths, CodePaths}].
여기서 Module은 모듈 이름에 해당하는 원자이고 CodePaths는 런타임의 코드 경로에 추가되어야 하는 파일 경로를 나타내는 문자열 목록입니다. 이러한 경로는 코드 경로 앞에 추가되며 네이티브 모듈의 디렉터리와 모든 종속 항목의 디렉터리를 포함해야 합니다.
외부 모듈의 형식은 다음과 같습니다.
[{module, Module},
{type, external},
{command, Command},
{count, Count}].
여기서 Module은 모듈 이름에 해당하는 원자이고 Command는 작업자를 시작하기 위해 실행할 명령을 지정하는 문자열이며 Count는 생성할 작업자 수입니다.
동일한 이름(순서대로)의 네이티브 모듈과 외부 모듈을 지정하면 Ernie는 네이티브 모듈을 검사하여 요청된 함수가 내보냈는지 확인하고 있으면 이를 사용합니다. 그렇지 않으면 외부 모듈로 돌아가게 됩니다. 이는 클라이언트 코드를 수정하지 않고도 모듈의 특정 기능을 선택적으로 최적화하는 데 사용할 수 있습니다.
어떤 상황에서는 인수의 성격에 따라 외부 모듈의 함수를 조건부로 숨기는 것이 좋을 수 있습니다. 예를 들어 X가 10보다 작을 때 math:fib(X)
에 대한 요청이 외부 모듈로 라우팅되지만 X가 10 이상이면 기본 모듈에서 처리되도록 할 수 있습니다. 이는 네이티브 모듈에서 math:fib_pred(X)
함수를 구현하여 수행할 수 있습니다. 일반 함수 이름에 _pred
추가되어 있음을 확인하세요(pred는 술어의 약자입니다). 이와 같은 함수가 있으면 Ernie는 요청된 인수를 사용하여 함수를 호출하고 반환 값이 true
이면 기본 모듈이 사용됩니다. 반환 값이 false
이면 외부 모듈이 사용됩니다.
다음 예제 구성 파일은 Ernie에게 두 개의 모듈을 알려줍니다. 첫 번째 용어는 '/path/to/app/ebin' 디렉터리 아래 nat.beam 파일에 있는 기본 모듈 'nat'을 식별합니다. 두 번째 용어는 'ruby /path/to/app/ernie/ext.rb' 명령으로 시작되는 2개의 워커를 포함하는 외부 모듈 'ext'를 지정합니다.
[{module, nat},
{type, native},
{codepaths, ["/path/to/app/ebin"]}].
[{module, ext},
{type, external},
{command, "ruby /path/to/app/ernie/ext.rb"},
{count, 2}].
-a 또는 --access-log 옵션을 사용하여 액세스 로그를 기록하도록 요청한 경우 모든 요청이 해당 파일에 기록됩니다. 각 요청은 한 줄에 인쇄됩니다. 로그 줄의 요소는 다음과 같습니다(오른쪽에 설명 포함).
ACC type of message [ ACC | ERR ]
[2010-02-20T11:42:25.259750] time the connection was accepted
0.000053 seconds from connection to processing start
0.000237 seconds from processing start to finish
- delimiter
0 size of high queue at connect time
0 size of low queue at connect time
nat type of handler [ nat | ext ]
high priority [ high | low ]
- delimiter
{call,nat,add,[1,2]} message
요청이 완료되면 로그 줄이 기록되므로 연결 시간에 따라 순서가 뒤바뀐 것처럼 보일 수 있습니다. 로그 회전을 용이하게 하기 위해 Ernie는 현재 로그 파일이 이동되거나 삭제되는 경우 새 액세스 로그 파일을 생성합니다.
기본 핸들러는 일반 Erlang 모듈로 작성됩니다. 내보낸 기능은 BERT-RPC 클라이언트에서 사용할 수 있게 됩니다.
-module(nat).
-export([add/2]).
add(A, B) ->
A + B.
-> {call, nat, add, [1, 2]}
<- {reply, 3}
이 gem에는 Ruby에서 Ernie 핸들러를 쉽게 작성할 수 있게 해주는 ernie
라는 라이브러리가 포함되어 있습니다. 여러분이 해야 할 일은 표준 Ruby 모듈을 작성하여 Ernie에게 노출하는 것뿐입니다. 그러면 해당 모듈의 기능을 BERT-RPC 클라이언트에서 사용할 수 있게 됩니다.
Ruby 모듈 및 Ernie.expose 사용:
require 'rubygems'
require 'ernie'
module Ext
def add(a, b)
a + b
end
end
Ernie.expose(:ext, Ext)
-> {call, nat, add, [1, 2]}
<- {reply, 3}
핸들러에 다음 줄을 추가하여 로깅을 파일로 보낼 수 있습니다.
logfile('/var/log/ernie.log')
loglevel(Logger::INFO)
그러면 시작 정보, 요청 및 오류 메시지가 로그에 기록됩니다. Logger::DEBUG를 선택하면 응답이 포함됩니다(이렇게 하면 매우 큰 로그 파일이 생성될 수 있으므로 주의하세요).
일반적으로 Ruby Ernie 핸들러는 파일이 로드된 후에 활성화됩니다. 다음을 설정하여 이 동작을 비활성화할 수 있습니다.
Ernie.auto_start = false
Ernie는 들어오는 연결에 대해 높음 및 낮음 우선순위 대기열을 유지 관리합니다. 높은 우선순위 대기열에 연결이 있으면 항상 먼저 처리됩니다. 높은 우선순위 대기열이 비어 있으면 낮은 우선순위 대기열에서 연결이 처리됩니다. 기본적으로 연결은 높은 우선 순위 대기열로 이동합니다. 대기열을 선택하려면 통화 전에 다음 형식의 정보 BERP를 전송해야 합니다.
-- {info, priority, Priority}
여기서 Priority
는 high
거나 low
원자입니다. 낮은 우선순위 대기열이 선택되는 예시 시퀀스는 다음과 같습니다.
-> {info, priority, low}
-> {call, nat, add, [1, 2]}
<- {reply, 3}
BERTRPC gem을 사용하면 Ruby에서 BERT-RPC 호출을 할 수 있습니다.
require 'bertrpc'
svc = BERTRPC::Service.new('localhost', 8000)
svc.call.ext.add(1, 2)
# => 3
Ernie를 해킹하려면 먼저 GitHub에서 내 저장소를 포크하세요.
http://github.com/mojombo/ernie
모든 종속성을 얻으려면 먼저 gem을 설치하십시오. 소스에서 ernie를 실행하려면 먼저 Erlang 코드를 빌드해야 합니다.
rake ebuild
변경 사항을 다시 코어에 병합하는 가장 좋은 방법은 다음과 같습니다.
rake
실행하여 모든 것이 여전히 통과하는지 확인하세요.저작권 (c) 2009 Tom Preston-Werner. 자세한 내용은 라이센스를 참조하세요.