50
Chamada Remota de Procedimento (RPC)

Chamada Remota de Procedimento (RPC)noemi/sd-10/rpc.pdf · – CORBA, RMI, J2EE, … • SOAP . exemplo SR • linguagem criada especificamente para aprender ... exemplo de uso em

  • Upload
    buinhan

  • View
    222

  • Download
    0

Embed Size (px)

Citation preview

Chamada Remota de Procedimento (RPC)

padrão cliente-servidor

A (cliente) B (servidor)

send (B, pedido) receive(B, &resp)

receive (A, …) processa pedido send(A, …)

•  repetição de padrão de comunicação •  encapsulação em abstração de mais alto nível

–  transparência

chamada remota

A (cliente) B (servidor)

send (B, pedido) receive(B, &resp)

receive (A, …) processa pedido send(A, …)

•  transformação em chamada de procedimento –  transparência para comunicação e suporte a passagem de parâmetros

chamadas locais

main

proc1

proc5

proc2 proc3 proc4

proc6 proc8 proc7

•  programa convencional organizado e entendido em como uma sequência de chamadas a procedimentos

chamada remota

main

proc1

proc5

proc2 proc3 proc4

proc6 proc8 proc7

Computador 1 Computador 2

•  protocolo permite chamada de procedimento remoto •  chamada remota pode ficar mais ou menos •  ênfase em estruturação do programa

–  bastante associado ao modelo cliente-servidor

chamadas remotas

•  possibilidade de estruturas mais complexas –  mais comum em sistemas de objetos distribuídos

main

proc1

proc5

proc2 proc3 proc4

proc6 proc8

proc7

RPC: modelo de execução

•  processo cliente permanece bloqueado durante execução de chamada remota

A (cliente) B (servidor)

resp = foo(a1, a2, …)

function foo (arg1, arg2,…) … return resposta end

•  stubs são responsáveis por intermediar a comunicação entre quem faz a chamada (caller) e quem é chamado (callee)

RPC: modelo de execução

cliente

stub cliente

servidor

stub servidor

RPC - papel dos stubs

processo chamador processo chamado

cham local

stub cliente stub servidor

runtime RPC runtime RPC

camadas envolvidas

•  supondo uso de TCP –  protocolo sobre TCP –  conversão de dados –  conversão de chamada remota em protocolo TCP

ferramenta

stubs cli e srv

prg cliente

protocolo tcp

conversão entre formatos de repres.

ferramentas/ geração de stubs

•  linguagens que incorporam conceito de RPC –  compilador gera diferentes partes do programa e stubs

•  bibliotecas + ferramentas –  possivelmente com interoperabilidade entre linguagens

servidor

stub servidor

cliente

stub cliente

descrição interface

stub servidor

stub cliente gerador de stubs

compilador

programa fonte

conversão de dados

•  marshalling/unmarshalling –  empacotamento e desempacotamento

•  problemas –  representações diferentes para inteiros –  alinhamento de dados –  estruturas com ponteiros

soluções

•  representação em XML (web services)

•  XDR (external data representation)

•  rotinas de conversão escritas pelo programador

RPC

•  Birrell e Nelson: 1984 –  PARC –  implementação em linguagens como CCLU

•  Sun RPC •  objetos distribuídos:

–  CORBA, RMI, J2EE, …

•  SOAP

exemplo SR

•  linguagem criada especificamente para aprender/usar distribuição e concorrência

•  aplicação é um mundo fechado: não há como processos lançados indepentemente se comunicarem

•  ver exemplo

exemplo SOAP RPC

•  SOAP – padrão de comunicação em serviços web –  messaging ou RPC

•  mensagens SOAP baseadas em XML •  bibliotecas (Java, C++, ...) oferecem

facilidades de manipulação dessas

Copyright© 2000 Kenn Scribner and Mark C. Stiver

requisição SOAP

<SOAP-ENV:Envelope

xmlns:SOAP-ENV=“http://schemas.xmlsoap.org/soap/envelope/” SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/”>

<SOAP-ENV:Header>

<t:transId xmlns:t=“http://a.com/trans”>1234</t:transId>

</SOAP-ENV:Header> <SOAP-ENV:Body>

<m:Add xmlns:m=“http://a.com/Calculator”>

<a xsi:type=“integer”>3</a>

<b xsi:type=“integer”>4</b>

</m:Add>

</SOAP-ENV:Body>

</SOAP-ENV:Envelope>

Copyright© 2000 Kenn Scribner and Mark C. Stiver

Resposta SOAP

<SOAP-ENV:Envelope

xmlns:SOAP-ENV=“http://schemas.xmlsoap.org/soap/envelope/”

SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/”>

<SOAP-ENV:Header>

<t:transId xmlns:t=“http://a.com/trans”>1234</t:transId>

</SOAP-ENV:Header>

<SOAP-ENV:Body>

<m:AddResponse xmlns:m=“http://a.com/Calculator”>

<c xsi:type=“integer”>7</c>

</m:AddResponse>

</SOAP-ENV:Body>

</SOAP-ENV:Envelope>

exemplo de uso em Java

•  ver exemplo

Um exemplo histórico de RPC: Sun-RPC

•  sistema originalmente criado para máquinas Sun. –  oferecido depois por diversos sistemas operacionais!

•  arquitetura definida inclui: –  uma linguagem para definição das interfaces (cabeçalhos de

procedimentos, etc); –  a ferramenta RPCGEN, que gera os stubs cliente e servidor

automaticamente; –  uma biblioteca RPC, que pode ser usada diretamente na

construção de programas que não usem o RPCGEN; –  o protocolo de comunicação entre os stubs.

•  utiliza TCP ou UDP

Sun-RPC - Tradução de dados

•  tradução entre formatos de dados: utilização de uma representação padrão, XDR (eXternal Data Representation Standard).

•  conversão é especificada para um conjunto pré-definido de tipos de dados.

formato origem

formato padrão

formato destino

rpcgen - funcionamento

prog.x rpcgen biblioteca RPC

cc

cc rprog.c

prog_proc.c

prog_clnt.c

prog.h

prog_svc.c

rprog

prog_svc procedimentos servidores

cliente

especificação RPC

stub servidor

stub cliente

programa servidor

programa cliente

rpcgen

•  Exemplo

aplicação

insere

remove

busca

inicializar main

proxima

Banco de

Dados

Chamadas a Procedimentos Remotos

Cliente Programa Remoto

criar uma especificação rpcgen

/* rbd.x especificação rpc para um programa de banco de dados que oferece os procedimentos INSERE, REMOVE e BUSCA */

struct example { /* estrutura não usada, declarada para ilustrar como rpcgen */ int exfield1; /* constrói rotinas XDR para converter estruturas */ char exfield2;

};

program RBDPROG{ /* nome do programa remoto */ version RDBVERS{ /* declaração da versão */ int INICIALIZAR(void) = 1; /* primeiro procedimento deste programa */ int INSERE(string) = 2; /* segundo procedimento deste programa */

int REMOVE(string) = 3; /* terceiro procedimento deste programa */ int BUSCA(string) = 4; /* quarto procedimento deste programa */

} = 1; /* definição da versão do programa */ } = 0x30090949; /* número do programa remoto (deve ser único) */

rodar o rpcgen

•  rpcgen rbd.x

rpcgen

rdb_clnt.c

rdb.h

rdb_svc.c

rdb_xdr.c

rpcgen arquivo .h

/* rbd.h */

struct example { int exfield1; char exfield2;

};

typedef sruct example example; bool_t xdr_example();

#define RBDPROG (u_long) 0x30090949) #define RDBVERS ((u_long) 1) #define INICIALIZAR ((u_long) 1) extern int *inicializar_1(); #define INSERE ((u_long) 2) extern int *insere_1(); #define REMOVE ((u_long) 3) extern int *remove_1(); #define BUSCA ((u_long) 4) extern int *busca_1();

rpcgen arquivo de conversão XDR

/* rbd_xdr.c */ #include <rpc/rpc.h> #include “rbd.h”

bool_t xdr_example(xdrs, objp)

XDR *xdrs; example *objp;

{ if (!xdr_int(xdrs, &objp->exfield1)) { return(FALSE); } if (!xdr_char(xdrs, &objp->exfield2) { return(FALSE); } return(TRUE);

}

rpcgen stub do cliente

/* rbd_clnt.c */ #include <rpc/rpc.h> #include “rbd.h”

int * inicializar_1(argp, clnt) void *argp; CLIENT *clnt; { static int res;

bzero((char *)&res, sizeof(res)); if (clnt_call(clnt, INICIALIZAR, xdr_void, argp, xdr_int, &res, TIMEOUT) != RPC_SUCCESS)

return (NULL); return (&res); }

int *insere_1(argp, clnt) char **argp; CLIENT *clnt; { static int res; bzero((char *)&res, sizeof(res)); if (clnt_call(clnt, INSERE, xdr_wrapstring, argp, xdr_int, &res, TIMEOUT) != RPC_SUCCESS)

return (NULL); return (&res); }

int * remove_1(argp, clnt) char **argp; CLIENT *clnt; { static int res;

bzero((char *)&res, sizeof(res)); if (clnt_call(clnt, REMOVE, xdr_wrapstring, argp, xdr_int, &res, TIMEOUT) != RPC_SUCCESS)

return (NULL); return (&res); }

int *busca_1(argp, clnt) char **argp; CLIENT *clnt; { static int res; bzero((char *)&res, sizeof(res)); if (clnt_call(clnt, BUSCA, xdr_wrapstring, argp, xdr_int, &res, TIMEOUT) != RPC_SUCCESS)

return (NULL); return (&res); }

rpcgen stub do servidor

/* rbd_svc.c */ #include <rpc/rpc.h> #include “rbd.h”

static void rbdprog_1();

main() { SVCXPRT *transp; (void)pmap_unset(RBDPROG, RBDVERS);

transp = svcudp_create(RPC_ANYSOCK); if (transp == NULL) { (void) fprintf(“Não pode criar serviço udp\n”); exit(1); } if (!svc_register(transp, RBCPROG, RBDVERS, rbdprog_1, IPPROTO_UDP)) { (void) fprintf(“Não pode registrar tal prog.\n”); exit(1); } transp = svctcp_create(RPC_ANYSOCK, 0, 0); if (transp == NULL) { (void) fprintf(“Não pode criar serviço TCP\n”); exit(1); } if (!svc_register(transp, RBCPROG, RBDVERS, rbdprog_1, IPPROTO_TCP)) { (void) fprintf(“Não pode registrar tal prog.\n”); exit(1); }

svc_run(); (void)fprintf(“SVC_RUn retornado \n”); exit(1); }

static void rbdprog_1(rqstp, transp) struct svc_req *rqstp; SVCXPRT *transp; { union {

char *insere_1_arg; char *remove_1_arg; char *busca_1_arg;

} argument; char *result; bool_t (*xdr_argument) (), (*xdr_result)(); char *(*local)();

switch (rqstp->rq_proc) { case NULLPROC: ( void)svc_sendreply(transp, xdr_void,(char *) NULL); return; case INICIALIZAR: xdr_argument = xdr_void; xdr_result = xdr_int; local = (char *(*)())inicializar_1; break; case INSERE: xdr_argument = xdr_wrapstring; xdr_result = xdr_int; local = (char *(*)()) insere_1; break;

rpcgen continuação stub do servidor

case REMOVE: xdr_argument = xdr_wrapstring; xdr_result = xdr_int; local = (char *(*)())remove_1; break; case BUSCA: xdr_argument = xdr_wrapstring; xdr_result = xdr_int; local = (char *(*)()) busca_1; break; default: svcerr_noproc(transp); return; } bzero((char*)&argument, sizeof(argument)); if (!svc_getargs(transp, xdr_argument, &argument)) { svcerr_decode(transp); return; } result = (*local)(&argument, rqstp); if (result != NULL && !svc_sendreply(transp, xdr_result, result )) {

svcerr_systemerr(transp); } if (!svc_freeargs(transp, xdr_argument, &argument)) { (void)fprintf(“Problema nos argumentos\n”); exit(1); } }

escrever procedimentos de interface com o stub

/* rbd_cif.c - inicializar, insere, remove, busca */ #include <rpc/rpc.h> #include “rbd.h” extern CLIENT *handle; /* handle para procedimento

remoto */

int inicializar() {

return *inicializar_1(handle); } int insere(item) char *item; {

char **arg; arg = &item; return *insere_1(arg, handle);

}

•  Rotinas de Interface do Cliente int remove(item) char *item; {

char **arg; arg = &item; return *remove_1(arg, handle);

} int busca(item) char *item; {

char **arg; arg = &item; return *busca_1(arg, handle);

}

rotinas de interface do servidor

/* rbd_sif.c - inicializar_1, insere_1, remove_1, busca_1 */ #include <rpc/rpc.h> #include “rbd.h” static int retcode;

int *inicializar_1() {

retcode = inicializar(); return &retcode;

} int *insere_1(i) char **i; {

retcode = insere(*i); return &retcode;

}

int *remove_1(i) char **i; { retcode = remove(*i);

return &retcode; } int *busca_1(i) char **i; {

retcode = busca(*i); return &retcode;

}

/* rbd_srp.c - inicializar, insere, remove, busca*/ #include <rpc/rpc.h> #include “rbd.h”

/* Procedimentos remotos do servidor e dados globais */

char bd[BDSIZE][MAXWORD+1] /* armazena o dicionário de palavras */ int npalavras = 0; /* número de palavras no dicionário */

int inicializar() {

npalavras = 0; return 1;

}

int insere(palavra) char *palavra; {

strcpy(bd[npalavras], palavra); npalavras++; return npalavras;

}

int remove(palavra) char *palavra; {

int i; for (i=0; i<npalavras; i++) if (strcmp(palavra, bd[i]) == 0) { npalavras--; strcpy(bd[i], bd[npalavras]); return 1; } return 0;

}

int busca(palavra) char *palavra; {

int i; for (i=0; i<npalavras; i++) if (strcmp(palavra, bd[i]) == 0 ) return 1; return 0;

}

Programa Servidor

semântica de chamadas

•  pelo menos uma vez •  no máximo uma vez •  exatamente uma vez

•  relação com protocolo subjacente •  falhas e reinicializações de servidores

–  funções idempotentes

binding

•  amarração entre cliente e servidor reedita problema de localização de destinatário –  solução portmapper no Sun RPC

•  em geral: chamada a servidor que detém: –  nome –  localização (IP, porta) –  estado

•  e se… –  nenhum servidor for localizado –  vários servidores forem localizados

críticas

•  sincronismo •  modelo um a um •  dificuldades de tratamento de falhas

•  dinamismo

sincronismo

•  processo que faz a chamada permanece bloqueado –  falta de interatividade local –  desperdício de uso da CPU

•  processamento •  outras operações de comunicação

RPC e multithreading (cliente)

•  combinação de RPC com multithreading –  sobreposição de computação

e comunicação –  disparo de várias chamadas

•  trocas de contexto preemptivas –  custo –  necessidade de sincronização

A1 B A2 C

alternativas

•  cliente pode disparar threads apenas no momento de fazer chamadas remotas

•  uso de mecanismos como co-rotinas •  chamadas assíncronas

tratamento de chamadas

•  concorrência no servidor B S A

como tratar???

concorrência no servidor

•  opções análogas às vistas para servidores em geral

RPC assíncrona

•  controle retorna imediatamente

function funcb(v) globalVal = v end obtemNovoVal(args, funcb);

•  em alguns casos, função de callback pode ser chamada qdo chamada se completa

registravalor(novoval);

programa como máquina de estado

function collect(val) acc = acc + val repl = repl + 1 if (repl==expected) then print ("Current Value: ", acc/repl) end end function askvals (peers) repl = 0; expected = 0; acc = 0 for p in pairs (peers) do expected = expected + 1 p:currValue{callback=collect} end end

problema de perda de locais

exemplo luarpc

function request(peers) local acc, repl = 0, 0 local expected = table.getn(peers) function avrg (val) repl = repl+1 acc = acc + val if (repl==expected) then print ("Current Value: ", acc/repl) end end for _,p in ipairs (peers) do rpc.async(p, "currValue", avrg)() end end

CLOSURE

variantes RPC assíncrona

comunicação um a um

•  como pensar em canais ou mailboxes onde processos espalhados por várias máquinas podem recolher chamadas?

•  no caso de tolerância a falhas: às vezes desejável que os diversos processos recebam a mesma chamada –  replicação –  comunicação em grupo

tratamento de falhas

•  como retornar informações sobre falhas no modelo de chamada remota? –  callbacks –  exceções

dinamismo…

•  modelo apresentado exige conhecimento sobre interfaces antes da geração do programa cliente –  geração estática de stubs –  suficiente para maior parte das situações

•  adaptação dinâmica –  servidores com diferentes otimizações

•  cache –  otimização dependendo do estilo de uso do cliente

•  chamada dentro de loop –  descoberta dinâmica de servidores

•  relação com serviços de binding mais complexos