연구 노트 - RPC 서버

10593 단어 rpc서버pomelo
POMELO는 다중 프로세스의 구조를 채택하여 게임 서버(프로세스)의 확장성을 잘 실현하고 비교적 많은 온라인 사용자를 지탱하며 서버의 압력을 낮추는 요구를 달성할 수 있다.프로세스 간 통신은 RPC 형식으로 이루어지는데, 포멜로의 RPC는 상당히 정교하게 실현된다.다음과 같은 방식으로 리모트 서버가 제공하는 서비스를 호출할 수 있습니다.
proxies.user.test.service.echo(routeParam, 'hello', function(err, resp) {
    if(err) {
        console.error(err.stack);
        return;
    }
    console.log(resp);
});

위의 RPC 호출은 다음과 같이 이해할 수 있다. namespace 형식은user, 서버 형식은test의 서비스 모듈을 호출하는 echo 인터페이스는 지금 듣기에 약간 까다롭다. 괜찮다. 그리고 내가 천천히 분석하는 것을 들어라.)

서버 원본 분석


pomelo-rpc의 원본 코드는 제가 +debug를 30번 읽었습니다. 다음은 베이스 데이터 교환 모듈에서 상부 업무 논리 분배 처리 방식에 따라 서버와 클라이언트의 원본 코드 구조를 순서대로 소개하겠습니다.

1. 소켓 기반.io 모듈의 데이터 통신 모듈

 socket , :
  • 패키지 문제
  • 가방 분실 및 난서 문제
  • IP 주소 필터링
  • 버퍼 대기열의 실현
  • 상부 모듈과의 상호작용 모드
  •  pomelo-rpc 。nodejs  events 。 :
    
    var Acceptor = function(opts, cb) {
        EventEmitter.call(this);
        this.bufferMsg = opts.bufferMsg;
        this.interval = opts.interval || 300;
        this.whitelist= opts.whitelist;
    
        this._interval = null;
        this.sockets = {};
        this.msgQueues = {};
    
        this.server = null;
        this.notify = cb;
    };
    
    util.inherits(Acceptor, EventEmitter);

    node에 내장된 util이 제공하는 계승 함수를 이용하여 간단한 두 마디로 Acceptor는 이벤트를 계승합니다.nodejs 소스 코드inherits 함수를 펼치는 것도 상당히 간단하다.
    var inherits = function(sub, super) {
        var tmp = function() {}
        tmp.prototype = super.prototype;
        sub.prototype = new tmp();
    }

    이런 기생 조합식의 계승을 통해 부류의 구조 함수를 두 번 호출하는 것을 피할 수 있기 때문에 이곳은 많이 전개되지 않는다.
     Acceptor :
    
    bufferMsg: 버퍼 대기열 설정 여부interval: 시간 데이터 전송 모듈의 간격을 설정합니다. Acceptor가 감청을 켤 때 설정 정보에 따라 타이머를 켤지 여부를 결정합니다. 시간 리셋 버퍼:
        if(this.bufferMsg) {
            this._interval = setInterval(function() {
                flush(self);
            }, this.interval);
        }

    flush 함수는 주로 버퍼링 데이터를 socket을 통과하는 것을 책임집니다.io 인터페이스 쓰기:
    var flush = function(acceptor) {
        var sockets = acceptor.sockets;
        var queues = acceptor.msgQueues;
        var queue, socket;
    
        for(var socketId in queues) {
            socket = sockets[socketId];
            if(!socket) {
                delete queues[socketId];
                continue;
            }
            queue = queues[socketId];
            if(!queue.length) {
                continue;
            }
            socket.emit('message', queue);
            queues[socketId] = [];
        }
    };

    모든 클라이언트 링크는 데이터 버퍼 대기열에 대응하여'메시지'메시지를 보내는 방식으로 데이터를 보냅니다.
    IP 주소 필터링 감청 오픈 후 클라이언트 링크(onconnection 이벤트)가 있으면 첫 번째 일은 IP 주소 필터입니다. IP 주소 화이트리스트도 구조 함수를 통해 주입됩니다.whitelist.IP 주소가 올바르지 않으면 링크를 닫고 경고 메시지를 내보냅니다.
    데이터 처리 모듈 상부 모듈은 설정 정보를 notify 리셋 함수에 주입하고 acceptor 데이터를 감청한 후 먼저 데이터를 상부에 던진다.상부 처리가 끝난 후 버퍼가 필요하면 대기열에 기록합니다. 그렇지 않으면 바로 발송합니다.
     acceptor.notify.call(null, pkg.msg, function() {
            var args = Array.prototype.slice.call(arguments);   
            for(var i = 0, l = args.length; i < l; i++) {
                if(args[i] instanceof Error) {
                    args[i] = cloneError(args[i]);
                }
            }
            var resp = {id: pkg.id, resp: Array.prototype.slice.call(args)};
            if(acceptor.bufferMsg) {
                enqueue(socket, acceptor, resp);
            }
            else {
                socket.emit('message', resp);
            }
        });

    2. 라우팅 요청 배포 모듈


    acceptor 모듈 위에 있는 것은 gateway 모듈로 이 모듈은 주로 acceptor 모듈의 창설과 폐기, 상태 제어를 책임진다.먼저 acceptor 모듈을 만들 때 함수를 전달합니다.
    this.acceptor = this.acceptorFactory.create(opts, function(msg, cb) {
            dispatcher.route(msg, cb);
        });

    공장 방법을 통해acctpor 실례를 구축하면 베이스 데이터 처리 모듈이 통신 프로토콜을 편리하게 교체할 수 있다.여기서 함수를 리셋하는 작업은 배달 함수를 호출하여 구체적인 서비스 제공자에게 요청을 전달하는 것이다.디스패치의 실현을 살펴보자.
    var Dispatcher = function(services) {
        EventEmitter.call('this');
        var self = this;
        this.on('reload', function(services) {
            self.services = services;
        });
        this.services = services;
    };
    util.inherits(Dispatcher, EventEmitter);

    Dispatcher 모듈도 이벤트 트랜시버가 됩니다.동시에 구조기는 services 파라미터를 수신한다.매개 변수가 루트 요청에 협조할 때 전송된 매개 변수에 따라 요청을 구체적인 하위 모듈에 전달할 수 있다.그래서 dispatcher.route(msg, cb); 매개 변수와 일치하여 대응하는 인터페이스를 호출하는 것에 불과하다.구조기가 reload 사건을 감청하는 것을 보면 이 사건은 어떤 작용을 합니까?이것은 사실 포멜로의 RPC 핫플러그 모듈의 실현이다.구현이 간단합니다.
    var watchServices = function(gateway, dispatcher) {
        var paths = gateway.opts.paths;
        var app = gateway.opts.context;
    
        for(var i = 0; i < paths.length; i++) {
            (function(index) {
                fs.watch(paths[index].path, function(event, name) {
                    if(event === 'change') {
                        var res = {};
                        var item = paths[index];
                        var m = Loader.load(item.path, app);
                        if(m) {
                            res[namespace] = res[namespace] || {};
                            for(var s in m) {
                                res[item.namespace][s] = m[s];
                            }
                        }
                        dispatcher.emit('reload', res);
                    }
                });
            })(i);
        }
    };
    gateway 모듈은 시작할 때 설정 정보에 따라 watchServices 감청 모듈의 변화를 호출합니다.데이터 파일이 변경되면 다시 로드services하고 라우팅 배포 모듈에 알립니다.서버와 클라이언트의 정상적인 통신을 확보하기 위해 하부 데이터 형식의 일치를 제외하고 또 하나는 루트 정보의 일치이다.Gateway를 호출하여 전송되는 구성 경로는 다음과 같습니다.
    var paths = [
        {namespace: 'user', path: __dirname + '/remote/test'}
    ];

    현재 디렉터리에 /remote/test/service.js 파일이 있고 파일에는 두 개의 인터페이스 test1/test2 가 포함되어 있다고 가정하십시오.load 이후 반환되는 객체는 다음과 같습니다.
    {
        service: {
            test1: 'function xxx',
            test2: 'function yyy'
        }
    }

    또한 포멜로에서는 시스템 RPC 서비스와 사용자 정의 RPC 서비스가 있습니다. 완전한 루트 정보는 다음과 같습니다.
    services: {
        sys: {
            sys_module1: {
                sys_module1_interface1: 'xxx'
            }
        },
        user: {
            user_module1: {
                user_module1_interface1: 'yyy'
            }
        }
    }

    서비스 측의 다른 것들은 모두 비교적 간단하다. 맥락을 분명히 하기 위해 상기 코드는 삭제를 거친 것이기 때문에 흥미가 있으면 여기에 가서 찾을 수 있다.

    좋은 웹페이지 즐겨찾기