chamada remota de procedimento (rpc)noemi/sd-08/aula4.pdf · 2008. 3. 18. · passo 3: criar uma...
TRANSCRIPT
Chamada Remota de Procedimento (RPC)
padrão cliente-servidor
A (cliente) B (servidor)
send (B, pedido)receive(B, &resp)
receive (A, …)processa pedidosend(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 pedidosend(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 proc8proc7
• programa convencional organizado e entendido emcomo uma sequência de chamadas a procedimentos
chamada remota
main
proc1
proc5
proc2 proc3 proc4
proc6 proc8proc7
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
proc6proc8
proc7
RPC: modelo de execução
• processo cliente permanece bloqueadodurante execução de chamada remota
A (cliente) B (servidor)
resp = foo(a1, a2, …)
function foo (arg1, arg2,…) … return respostaend
• stubs são responsáveis por intermediar acomunicaçã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 RPCruntime 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 clientegerador 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
Um exemplo de RPC: Sun-RPC
• Sistema originalmente criado para máquinas Sun.– oferecido atualmente em diversos sistemas operacionais!
• A 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.
• Pode utilizar TCP ou UDP
Sun-RPC - Tradução de dados
• tradução entre formatos de dados: utilizaçãode uma representação padrão, XDR(eXternal Data Representation Standard).
• conversão é especificada para um conjuntopré-definido de tipos de dados.
formatoorigem
formatopadrão
formatodestino
rpcgen - funcionamento
prog.x rpcgen bibliotecaRPC
cc
ccrprog.c
prog_proc.c
prog_clnt.c
prog.h
prog_svc.c
rprog
prog_svcprocedimentos servidores
cliente
especificação RPC
stub servidor
stub cliente
programa servidor
programa cliente
rpcgen
• Exemplo de arquivo de especificação:
/* date.x especificação de serviços remotos de data e hora */
program DATE_PROG{ version DATE_VERS{ long BIN_DATE(void) = 1; string STR_DATE(long) = 2; } = 1;} = 0x31234567;
passo 1: projetar uma aplicaçao convencional
main
proxima insere remove buscainicializar
passo 2: dividir o programa em duas partes
insere
remove
busca
inicializarmain
proxima
Bancode
Dados
Chamadas aProcedimentos Remotos
Cliente Programa Remoto
passo 3: 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) */
passo 4: rodar o rpcgen
• rpcgen rbd.x
rpcgen
rdb_clnt.c
rdb.h
rdb_svc.c
rdb_xdr.c
rpcgenarquivo .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();
rpcgenarquivo de conversão XDR
/* rbd_xdr.c */#include <rpc/rpc.h>#include “rbd.h”
bool_txdr_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);
}
rpcgenstub 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);}
rpcgenstub 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;
rpcgencontinuaçã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); }}
passo 5: escrever procedimentos de interface com ostub
/* 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 Clienteint 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;
}
passo 6: compilar e linkar o programa cliente
• cc -c rbd_cif.c rbd_cif.o
• cc -c rbd.c rdb.o
• cc -o rbd rbd.o rbd_clnt.o rbd_xdr.o rbd_cif.o
passo 7: compilar e linkar o programa servidor
• cc -c rbd_sif.c rbd_sif.o
• cc -c rbd_srp.c rdb_srp.o
• cc -o rbddaemon rbd_svc.o rbd_xdr.o rbd_sif.orbd_srp.o
/* 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
binding
• amarração entre cliente e servidor reedita problemade 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
dinamismo…
• modelo apresentado exige conhecimento sobreinterfaces 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
críticas
• sincronismo• dificuldades de modelar outras formas de
iteração, como pipes ou multicast• dificuldades de tratamento de falhas
sincronismo
• processo que faz a chamada permanecebloqueado– falta de interatividade local– desperdício de uso da CPU
• processamento• outras operações de comunicação
RPC e multithreading
• combinação de RPC commultithreading– sobreposição de computação
e comunicação– disparo de várias chamadas
• trocas de contextopreemptivas– custo– necessidade de sincronização
A1 BA2C
RPC assíncrona
• controle retorna imediatamente
function funcb(v) globalVal = vendobtemNovoVal(args, funcb);
• em alguns casos, função de callback podeser chamada qdo chamada se completa
registravalor(novoval);
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)() endend
comunicação um a um
• como pensar em canais ou mailboxes ondeprocessos espalhados por várias máquinaspodem recolher chamadas?
• no caso de tolerância a falhas: às vezesdesejável que os diversos processosrecebam a mesma chamada– replicação– comunicação em grupo
tratamento de falhas
• como retornar informações sobre falhas nomodelo de chamada remota?– callbacks– exceções
objetos distribuídos
• invocação remota de métodos– objetos como unidades localizadas, argumentos, etc
or1.mx
processoservidor
or2.my
o.main()
ol1.ma ()
ol1.mb () ol1.mn ()
ol2.mm ()
processocliente
or1.mx(ol1) or2.mz