Chamada Remota de Procedimento (RPC)noemi/sd-09/aula4.pdf– conversão de dados – conversão de...
Transcript of Chamada Remota de Procedimento (RPC)noemi/sd-09/aula4.pdf– conversão de dados – conversão de...
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
acc = 0 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; 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
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