Remote Procedure Calls (RPC) March 14, 2010 Sumário Ideia Implementação Transparência Semântica na presença de avarias Caso de estudo: ONC RPC da Sun
Remote Procedure Call (RPC) A programação baseada em mensagens com as primitivas send()/receive() não é conveniente: depende do protocolo de comunicações usado; requer a especificação dum protocolo de aplicação; assemelha-se a E/S. A invocação de funções (procedimentos) em computadores remotos: é um paradigma familiar; facilita transparência; é particularmente adequada para aplicações cliente-servidor. RPC: a Ideia Locais: Code For Main Program main Code For Procedure A Code For Procedure B Call A Call B Exit Return Return Remotas: Main Program On machine 1 (client) main Procedure A On machine 2 (server) Procedure B On machine 3 (server) call remote proc. A call remote proc. B Exit Respond to caller Respond to caller
Desenvolvimento de Programas com RPC (idealmente) Desenvolver o programa sem considerar distribuição: main proc1 proc2 proc3 proc4 proc5 proc6 proc7 proc8 Fazer a distribuição à posteriori: computer1 computer2 main proc1 proc2 proc3 proc4 proc5 proc6 proc7 proc8 Rotinas de Adaptação (Stub Routines) Asseguram a transparência de RPC: cliente invoca o client stub uma função local, e a função é invocada pelo server stub, uma função local. As rotinas de adaptação comunicam entre si usando mensagens. Computer 1 Computer 2 Proc. A remote procedure call SERVER STUB CLIENT STUB Proc. B
Princípio Semelhante ao de uma Chamada ao Sistema user space user program ordinary call ordinary return C library function trap trap return system call kernel space Arquitectura Típica dum Sistema de RPC rpc call marshaled request client process client program client stub rpc return marshaled return ordinary call marshaled request server process server functions server stub ordinary return marshaled return network services client kernel network services server kernel Obs. RPC assenta na camada de transporte (TCP/UDP).
Processamento no Adaptador Cliente Pedido: constrói a mensagem (parameter marshalling); envia-a (p.ex. usando sendto()) para o servidor; bloqueia à espera da resposta (p.ex. usando recvfrom()). Resposta: recebe a resposta; extrai os resultados (unmarshalling);; retorna-os ao cliente. Processamento no Adaptador Servidor Pedido: recebe mensagem com pedido; extrai argumentos; invoca a função. Resposta: constrói mensagem com resultado da invocação da função; envia mensagem; bloqueia à espera de novo pedido.
RPC: despacho Possibilidade de mais do que um procedimento remoto: Computer 1 Computer 2 PROC. A1 PROC. A2 DISPATCHER CLIENT STUB FOR B2 SERVER STUB FOR B1 SERVER STUB FOR B2 CLIENT STUB FOR B1 PROC. B1 PROC. B2 Identificação do procedimento pelo despacho (dispatcher): (serviço, procedimento) - espaço de nomes hierárquico Transparência: Heterogeneidade do HW Problema: pelo menos dois: diferentes arquitecturas usam diferentes formatos de representação: complemento para 1 vs. complemento para 2; big endian vs. little endian; ASCII vs. EBCDIC; vírgula flutuante: IEEE 754 vs.?? representação de estruturas de dados complexas pode diferir entre compiladores. Solução: essencialmente duas: formato normalizado nos fios + em cada computador, conversão entre 2 formatos só; - (pode ser) ineficiente; receiver-makes-right
Transparência: Endereços como Argumentos Problema: argumentos que são endereços (apontadores de C) só têm significado num processo. Solução: usar o método de passagem de argumentos call-by-copy/restore: + satisfaz na maioria dos casos; complexo: o mesmo endereço pode ser passado em argumentos diferentes. ineficiente: estruturas de dados complexas (p.ex. árvores); Problemas Recorrentes Localização do servidor as soluções habituais: hardcoded inflexível; ficheiro de configuração difícil de manter actualizado; argumentos do programa idem; multicast/broadcast não acomoda crescimento duma forma razoável; servidor de nomes sim, mas não DNS: o servidor regista-se no servidor de nomes; o cliente interroga (lookup) o servidor de nomes. Segurança nomeadamente: autenticação; controlo de acesso.
Transparência na Presença de Avarias Problema: E se alguma coisa corre mal? O cliente não consegue localizar o servidor: RPC retorna um erro (semelhante ao erro numa chamada ao sistema). O pedido perde-se: retransmissão no fim de temporização. A resposta perde-se: necessidade de incluir números de sequência; necessidade de memorizar respostas mais recentes, se pedido não idempotente; O servidor avaria (crashes): a avaria ocorreu antes ou depois de processar o pedido? O cliente avaria: como evitar que o servidor processe um pedido (orfão (orphan)) para um cliente inexistente. Semântica na Presença de Avarias Problema O que é que o cliente pode assumir em relação à execução duma RPC que invocou e assinala uma excepção? Solução Depende da semântica na presença de avarias do sistema de RPC usado: talvez (may-be) fácil de implementar: o adaptador cliente retransmite o pedido um número pré-determinado de vezes, após o que retorna um erro; pelo-menos-uma-vez (at-least-once) o adaptador cliente retransmite o pedido até obter resposta; não-mais-que-uma-vez (at-most-once) - não é trivial de implementar se se usar um transporte não fiável, p.ex. UDP. Se se usar TCP p.ex., RPC pode retornar erro no caso de rotura da conexão. exactamente-uma-vez (exactly-once) nem sempre é possível garantir esta semântica (p.ex., se há acções externas).
Avarias e Semântica Exactamente-Uma-Vez. REQ Server REQ Server REQ Server Receive Receive Receive REP Execute Execute Crash No REP No REP Reply Crash (a) (b) (c) Problema No caso de acções externas, p.ex. impressão dum ficheiro, é virtualmente impossível. Estratégia do Servidor Uma de duas: 1. Enviar ACK depois de imprimir; 2. Enviar ACK antes de imprimir. Estratégia do Cliente Uma de quatro: 1. Nunca reenviar pedido. 2. Reenviar pedido sempre. 3. Reenviar pedido quando recebe ACK; 4. Reenviar pedido quando não recebe ACK; Avaria no Servidor e Semântica Exactamente-Uma-Vez. Cenário: Servidor avaria e recupera a tempo de processar retransmissão do pedido do cliente Cenários de Avaria (ACK->P) 1. A->P->C 2. A->C(->P) 3. C(->A->P) Cenários de Avaria (P->ACK) 1. P->A->C 2. P->C(->A) 3. C(->P->A) Client Server Strategy A P Strategy P A Reissue Strategy APC AC(P) C(AP) PAC PC(A) C(PA) Always Dup OK OK Dup Dup OK Never OK Zero Zero OK OK Zero When Ack Dup OK Zero Dup OK Zero When not Ack OK Zero OK OK Dup OK OK = Text printed once Dup = Text printed twice Zero = Text not printed at all
Implementação de RPCs Problema RPC é um conceito útil, mas a sua implementação requer programação ao nível de rede. Solução Automatizar a geração de código uma parte significativa do código necessário é invariante; outra parte pode ser parametrizável. rpcgen (1/2) É uma ferramenta capaz de gerar: rotinas de adaptação, quer do cliente quer do servidor; esqueletos dos programas cliente e servidor; para a Open Network Computing RPC, especificada pela Sun Microsystems. Requer como entrada uma especificação incluindo: a especificação das funções remotas (i.e., os seus protótipos); a definição de tipos de valores e das constantes passados às ou retornados por essas funções.
rpcgen (2/2) Q_client.c client application Q_clnt.c Q.h C compiler client Q.x rpcgen specification for remote program Q_xdr.c Q_svc.c C compiler server Q_server.c remote procedures Saída de rpcgen -a -C -N date.x date.h header file com os protótipos das funções e a definição de constantes e de tipos. date_clnt.c rotina de adaptação do cliente (de facto, a função de interface à rotina de adaptação. date_svc.c esqueleto do programa servidor, incluindo dispatcher, e rotina de adaptação do servidor. date_xdr.c funções auxiliares para converter estruturas de dados complexas entre o formato nativo e XDR (o formato usado por ONC RPC para enviar dados). date_client.c esqueleto de programa cliente, incluindo invocação de cada uma das funções remotas. date_server.c funções envelope das funções remotas. Obs.- Em princípio, não se deve alterar os 4 primeiros ficheiros.
Desenvolvimento de Aplicações com rpcgen 1. Identificar as funções remotas e definir os seus protótipos. 2. Definir os protótipos das funções remotas, dos tipos e constantes necessárias em RPCL. 3. Executar rpcgen. 4. Escrever as funções remotas (i.e. do servidor), possivelmente a partir das funções em _server.c 5. Compilar a aplicação servidora. 6. Escrever a aplicação cliente, possivelmente a partir das funções em _client.c 7. Compilar a aplicação cliente. RPC Language (RPCL) Linguagem definida pela Sun para especificar as funções remotas: é baseada na linguagem C; não inclui instruções de controlo, p.ex. while; entre outros, suportas os seguintes tipos (comprimento): int (32 bits) unsigned int (32 bits) bool (32 bits) enum (arb.) float (32 bits) double (64 bits) opaque (arb.) string (arb.) fix sized array (arb.) counter array (arb.) structure (arb.) void (0) symbolic constant (arb.) optional constant (arb.) suporta também apontadores.
Declaração de programas em RPCL /* rns.x */ /* RPC declarations for name service */ const MAXNAMESIZE = 64; struct registo { int ipaddr; string name; }; program NAMEPROG { version VERS1 { int INITNS(void) = 1; int INSERTR(struct registo) = 2; int DELETER(struct registo) = 3; int LOOKUPN(string) = 4; } = 1; } = 0x30033003; Declaração de Programas em RPCL: Comentários Por convenção, na declaração de programas usa-se nomes só com maiúsculas: rpcgen gera funções com minúsculas. A numeração das funções começa sempre em 1: rpcgen gera sempre uma função remota com número 0 (correspondente à declaração void NULL(void) = 0;). Um programa pode ter diferentes versões: facilita o teste de novas versões e actualização de um serviço (execução em simultâneo de diferentes versões). Não se pode atribuir os números de programas arbitrariamente: 0x00000000-0x1fffffff 0x20000000-0x3fffffff 0x40000000-0x5fffffff 0x6fffffff-0xffffffff Reservado para a Sun Para utilizador Para uso temporário Reservado
Conversão de Tipos Não-Primitivos O ficheiro rns.h inclui: #define MAXNAMESIZE 64 struct registo { int ipaddr; char *name; }; typedef struct registo registo; extern bool_t xdr_registo(xdr *, registo*); A função xdr_registo() é gerada por rpcgen e está definida em rns_xdr.c: usa funções da biblioteca xdr para empacotar e desempacotar (marshalling and unmarshalling) estruturas de dados de tipo struct registo. XDR (external Data Representation) é o formato especificado pela Sun para transferir os dados entre processos. portmap Problema: Qual é o porto em que o servidor escuta? = número de programas (32 bits) pode exceder o número de portos (16 bits). Solução: Cada máquina que executa servidores deve executar o programa portmap: os servidores registam-se no portmap (o portmap deve iniciar antes de qualquer outro serviço RPC); os clientes interrogam (lookup), no computador onde o servidor executa, o portmap sobre o (serviço, versão): o portmap retorna o porto usado pelo servidor correspondente. IMP.- O portmap é específico da biblioteca RPC da Sun, não faz parte da especificação do protocolo RPC. IMP.- O código de comunicação com o portmap é gerado automaticamente por rpcgen. (Que alívio :)
Port Mapper an RPC program (server) RPC program registers (program,version,proto,port) RPC port mapper (server) RPC client looks up the port for (program,version,proto) an RPC program (client) socket for port currently used by this RPC server socket for well known socket at which the port mapper listens socket for port currently used by this RPC client Port Mapper é um Servidor baseado em RPC Remote Program Number 100000, Version 2 Number Name Description 0 null do nothing 1 set add portmap entry 2 unset remove portmap entry 3 getport return port for remote program 4 dump return all portmap entries 5 callit call remote procedure callit permite invocar uma função em vários servidores usando broadcast.
E o Computador onde Executa o Servidor? Problema: Como é que um cliente sabe qual é o computador onde o servidor executa? Solução: Há algumas alternativas: através dum outro canal de comunicação (p.ex. ficheiro); fazendo broadcast para os port mappers; usando um serviço de directoria: p.ex., o Network Information System (NIS) da Sun, o qual usa um mecanismo próprio para arrancar, e o portmapper (porque os servidores NIS não usam um porto pré-definido). Leitura Adicional Tanenbaum e van Steen, Distributed Systems, 2nd Ed. Secção 4.2 Remote Procedure Call, excepto subsecção 4.2.4 Subsecção 8.3.2 RPC Semantics in the Presence of Failures