replicacao de dados no interbase

Upload: sdtecinformatica

Post on 06-Oct-2015

215 views

Category:

Documents


0 download

DESCRIPTION

Replicação de dados no Interbase

TRANSCRIPT

  • Replicao de Dados no InterbasePor Matt Hopkins, Dunstan Thomas(UK) LTD.Borland Developers Conferece1998 - nessa poca ainda no existia o componente IBReplicatorOrigem: http://www.ibphoenix.com/ibp_howto10.htmlTraduo : Marcilio SoaresReviso/adaptao do texto : Carlos Henrique Cantu - http://www.interbase-br.comEste documento descrever a concepo bsica para replicao de dados e como elespodem ser implementados de maneira relativamente simples usando semente recursosdo prprio Interbase.O que Replicao de Dados? a cpia de informaes de um ou mais Banco de dados para outro semelhante,depois das informaes estarem consistentes.H dois tipos bsicos de replicao SNCRONA E ASSNCRONAReplicao Sncrona:

    Todas as cpias ou replicaes de dados sero feitas no instante da sincronizao econsistncia. Se alguma cpia do banco alterada, essa alterao ser imediatamenteaplicada a todos os outros bancos dentro da transao. A Replicao Sncrona apropriada em aplicaes comerciais onde a consistncia exata das informaes deextrema importncia.Replicao Assncrona:

    Armazena e faz a replicao. A cpia de dados fica fora de sincronia entre os BDs. Seum BD alterado, a alterao ser propagada e aplicada para outro BD num segundopasso, dentro de uma transao separada sendo que esta poder ocorrer segundos,minutos, horas ou at dias depois. A cpia poder ficar temporariamente fora desincronia, mas quando a sincronizao ocorrer os dados convergiro para todos oslocais especificados.Este documento trata exclusivamente sobre replicao de dados assncrono.

    Quais componentes so necessrios para a replicao dedados?

    Capturando as alteraes no banco de dados de origem.

  • Toda estratgia de replicao de dados requer um mtodo para capturar as alteraespara um banco de dados de replicao. H dois mecanismos principais Logs deTransao e Triggers.Logs de transao abordam a utilizao de uma tcnica chamada "log Sniffing" a qualreplica uma transao sinalizada para replicao para um plataforma de transmisso.Esta tcnica causa um impacto menor no servidor de Banco de Dados porque requermenor CPU quando da leitura de "Log" na memria e tambm na gravao para odisco. Este mtodo de replicao utilizado tambm por outros fabricantes de Bancoscomo Sybase, Informix e MS SQL/Server.A Segunda tcnica usa triggers no Banco de dados para propagar as alteraes quandoelas ocorrem. Como a Linguagem procedural de Banco de dados pode ser utilizadanesse mtodo, ela prov maior flexibilidade a medida que os dados so replicados.Esta implementao de replicao utilizada pelo Ingres e Oracle, tambm ser atcnica que ns utilizaremos ao trabalharmos com replicao com Interbase.Transmitindo alteraes de um de Banco de Dados para o(s)Banco de dados DestinoPara a transmio das alteraes para o BD destino requerido um Software que l asalteraes e as transmite ao BD Destino situado em algum lugar da rede e grava asalteraes.Este Software conhecido como um gerenciador de replicao e tambm controlaerros e conflito de Updates.

    Como posso fazer Replicao de Dados com oscomponentes do Interbase?Registrando a alterao dos dadosPara criar nosso processo de replicao ns precisaremos criar dois exemplos de Bancode Dados com tabelas idnticas em cada um dos Bancos.CREATE DATABASE "source.gdb" PAGE_SIZE 1024CREATE TABLE TEAMS (TEAM_ID INTEGER NOT NULL,TEAM_NAME VARCHAR(100),TEAM_MGR VARCHAR(40),PRIMARY KEY (TEAM_ID));CREATE TABLE CHANGES (CHANGE_ID INTEGER NOT NULL,CHANGE_TYPE CHAR(1) NOT NULL,SOURCE_KEY_FIELD VARCHAR(31) NOT NULL,SOURCE_KEY INTEGER NOT NULL,

  • SOURCE_TABLE VARCHAR(31),USERNAME VARCHAR(31),PRIMARY KEY (CHANGE_ID));CREATE GENERATOR NEW_TEAM_ID;CREATE GENERATOR NEW_CHANGE_ID;

    Agora criaremos um TRIGGER CHANGES na tabela para obtermos um nico valor doGENERATORCREATE TRIGGER CHANGES_NEWID FOR CHANGESBEFORE INSERTASBEGINNEW.CHANGE_ID = GEN_ID(NEW_CHANGE_ID,1);ENDNOTA: Veja que no adicionaremos um trigger para gerar uma nica ID na tabelaTEAMS. Discutiremos este assunto na prxima sesso.Agora ns precisamos criar um mecanismo para registrar todas as alteraes de nossatabela.Como mencionado anteriormente, ns utilizaremos triggers para registrar as alteraespara nossa tabela de Replicao. O benefcio que os triggers esto disponveis, sofceis de usar, e diferente dos logs de transao, eles possibilitam o uso de uma lgicade programao utilizando a linguagem procedural do Interbase.H trs tipos de alterao que podero ocorrer na tabela Insert, Update e Delete.Ns precisaremos de trs triggers para cada uma das tabelas replicadas./* After an Insert */CREATE TRIGGER TEAMS_REPL_INSERT FOR TEAMSAFTER INSERTASBEGININSERT INTO CHANGES(CHANGE_TYPE, SOURCE_KEY_FIELD,SOURCE_KEY, SOURCE_TABLE,USERNAME)VALUES("I","TEAM_ID",NEW.TEAM_ID,"TEAMS",USER);END;/* After an Update */CREATE TRIGGER TEAMS_REPL_UPDATE FOR TEAMSAFTER UPDATEASBEGIN

  • INSERT INTO CHANGES(CHANGE_TYPE, SOURCE_KEY_FIELD,SOURCE_KEY, SOURCE_TABLE,USERNAME)VALUES("U","TEAM_ID",NEW.TEAM_ID,"TEAMS",USER);END;/* After a Delete */CREATE TRIGGER TEAMS_REPL_DELETE FOR TEAMSAFTER DELETEASBEGININSERT INTO CHANGES(CHANGE_TYPE, SOURCE_KEY_FIELD,SOURCE_KEY, SOURCE_TABLE,USERNAME)VALUES("D","TEAM_ID",OLD.TEAM_ID,"TEAMS",USER);END;Isto tudo que se precisa para registrarmos as alteraes de dados para umareplicao no Interbase.Note que para manter a simplicidade ns requisitamos que todas as tabelas replicadastanha uma Chave Inteira (INTEGER KEY) nica e que este o nico elemento de dadosque ser gravado na tabela CHANGES. Ns poderamos armazenar todos os valoresdos campos que foram alterados, mas como ns vamos replicar um snapshot dosdados armazenando apenas a chave e a ao, ns podemos recuperar os valoresatuais em cada tabela pelo mecanismo de replicao.Mais um passo necessrio antes de irmos para o mecanismo de replicao. Nsprecisaremos criar um Banco de Dados de destino com a mesma Metadata. Isto poderser feito fazendo um backup do BD e restaurando-o com o nome de"DESTINATION.GDB".Replicando os dados alteradosAgora ns vamos criar um Servidor de Replicao usando Delphi.A idia permitir ao usurio pr-defina um tempo determinado para a replicao ouele poder manualmente solicitar a replicao com um boto "Replicar Agora". Umregistro de todas as atividades ser mostrada num Memo e algumas excees queocorram sero exibidas em um Memo de erros.O Banco Replicado e o Banco de Destino da Replicao sero passados em linha decomando atravs de parmetros desta forma:C:\REPLD SOURCEDB TARGETDBPara nos assegurar de que o nosso projeto sempre ter dois parmetros ns faremosassim:

  • if (ParamStr(1) = '') or (ParamStr(2) = '') thenMessageDlg('Usage: "REPLD.EXE SOURCE_ALIAS TARGET_ALIAS"',mtError,[mbOK],0)elsebeginApplication.Initialize;Application.CreateForm(TForm1, Form1);Application.Run;end;

    Toda replicao ser controlada por uma Procedure de replicao desta forma:procedure TForm1.Replicate;varqryChangeList : TQuery;strChangeType : String;beginqryChangeList := TQuery.create(Application);trywith qryChangeList dobeginDatabaseName := 'SourceDB';sql.add('select * from changes');open;while not eof dobeginif (fieldByName('CHANGE_TYPE').asString = 'I') thenbeginstrChangeType := 'Insert';ReplicateInsert(fieldByName('SOURCE_TABLE').asString,fieldByName('SOURCE_KEY_FIELD').asString,fieldByName('SOURCE_KEY').asInteger)endelse if (fieldByName('CHANGE_TYPE').asString = 'U') thenbeginstrChangeType := 'Update';ReplicateUpdate(fieldByName('SOURCE_TABLE').asString,fieldByName('SOURCE_KEY_FIELD').asString,fieldByName('SOURCE_KEY').asInteger)endelse if (fieldByName('CHANGE_TYPE').asString = 'D') thenbeginstrChangeType := 'Delete';ReplicateDelete(fieldByName('SOURCE_TABLE').asString,fieldByName(

  • 'SOURCE_KEY_FIELD').asString,fieldByName('SOURCE_KEY').asInteger)end;memoLog.lines.add( DateTimeToStr(Now)+' '+strChangeType+' '+fieldByName('SOURCE_KEY').asString+' on '+fieldByName('SOURCE_TABLE').asString);DeleteFromChanges(fieldByName('CHANGE_ID').asInteger);next;end;close;end;finallyqryChangeList.free;end;end;E a cada ao(INSERT, DELETE, UPDATE) ser chamada uma Procedure individual,como se segue:Replicate Inserts:procedure TForm1.ReplicateInsert(const strTableName, strKeyField: String; const iKey: Integer);varqrySource, qryTarget : TQuery;i : SmallInt;beginqrySource := TQuery.create(Application);trywith qrySource dobeginDatabaseName := 'SourceDB';with sql dobeginadd('select * from '+strTableName);add(' where ('+strKeyField+' = '+IntToStr(iKey)+');');end;tryopen;while not eof dobeginqryTarget := TQuery.create(Application);trywith qryTarget dobeginDatabaseName := 'TargetDB';with sql do

  • beginadd('insert into '+strTableName);add('(');for i := 0 to qrySource.fieldCount-1 dobeginif (i < qrySource.fieldCount-1) thenadd(' '+qrySource.Fields[i].FieldName+',')elseadd(' '+qrySource.Fields[i].FieldName)end;add(')');add('values');add('(');for i := 0 to qrySource.fieldCount-1 dobeginif (i < qrySource.fieldCount-1) thenadd(' :'+qrySource.Fields[i].FieldName+',')elseadd(' :'+qrySource.Fields[i].FieldName)end;add(')');end;prepare;for i := 0 to qrySource.fieldCount-1 dobeginqryTarget.Params[i].asString := qrySource.Fields[i].asString;end;execSQL;end;finallyqryTarget.free;end;next;end;close;excepton e: Exception domemoErrors.lines.add(DateTimeToStr(Now)+' '+e.message);end;end;finallyqrySource.free;end;end;Replicate Upates:procedure TForm1.ReplicateUpdate(const strTableName, strKeyField: String; const iKey: Integer);

  • varqrySource, qryTarget : TQuery;i : SmallInt;beginqrySource := TQuery.create(Application);trywith qrySource dobeginDatabaseName := 'SourceDB';with sql dobeginadd('select * from '+strTableName);add(' where ('+strKeyField+' = '+IntToStr(iKey)+');');end;tryopen;while not eof dobeginqryTarget := TQuery.create(Application);trywith qryTarget dobeginDatabaseName := 'TargetDB';with sql dobeginadd('update '+strTableName);add('set');for i := 0 to qrySource.fieldCount-1 dobeginif (i < qrySource.fieldCount-1) thenadd(' '+qrySource.Fields[i].FieldName+' = :'+qrySource.Fields[i].FieldName+',')elseadd(' '+qrySource.Fields[i].FieldName+' = :'+qrySource.Fields[i].FieldName)end;add(' where ('+strKeyField+' = '+IntToStr(iKey)+');');end;prepare;for i := 0 to qrySource.fieldCount-1 dobeginqryTarget.Params[i].asString := qrySource.Fields[i].asString;end;execSQL;end;finallyqryTarget.free;end;next;end;

  • close;excepton e: Exception domemoErrors.lines.add(DateTimeToStr(Now)+' '+e.message);end;end;finallyqrySource.free;end;end;Replicate Deletes:procedure TForm1.ReplicateDelete(const strTableName, strKeyField: String; const iKey: Integer);varqrySource : TQuery;i : SmallInt;beginqrySource := TQuery.create(Application);trywith qrySource dobeginDatabaseName := 'TargetDB';sql.add('delete from '+strTableName);sql.add(' where ('+strKeyField+' = '+IntToStr(iKey)+')');execSQL;tryexecSQL;excepton e: Exception domemoErrors.lines.add(DateTimeToStr(Now)+' '+e.message);end;end;finallyqrySource.free;end;end;Nota: Este exemplo no suporta campos do tipo BLOB. Um cdigo adicionalser necessrio para seu uso, mas isso totalmente possvel.Agora atribua o valor do SpinBox ao Timer . Desta forma voc poder ajustar o clicloda replicao:procedure TForm1.SpinEdit1Change(Sender: TObject);

  • beginTimer1.Interval := (SpinEdit1.Value * 1000);end;Execute-o e enquanto REPLD estiver executando, faa alguma alterao na tabelaTEAMS no Banco de dados Origem tendo certeza de adicionar uma chave nica everifique o banco de dados de destino (Depois de um ciclo de replicao) para ver asalteraes replicadas.Replicao Bi-DirecionalCheque a tabela CHANGES no BD destino e voce ver que as alteraes replicadas doBD origem tambm aparecero nessa tabela.O problema que o mecanismo utilizado para logar as alteraes no est distinguindoas alteraes feitas pelo usurio final das alteraes feitas pelo mecanismo dereplicao. Se ns iniciarmos uma replicao bi-direcional utilizando nosso aplicativoREPLD sem especificar um "usurio replicador", correremos o risco de entrar em umloop infinito.Portanto, ns precisaremos definir um "usurio replicador" para esse exemplo ochamaremos de "REPLICATE" em todos os servidores Interbase que estivermosusando, e no efetuaremos o log das alteraes efetuadas por esse "usurio". Issosignifica que precisaremos alterar os triggers para acada tabela replicada da seguinteforma :/* After an Insert */ALTER TRIGGER TEAMS_REPL_INSERT FOR TEAMSAFTER INSERTASBEGINIF (USER "REPLICATE") THENINSERT INTO CHANGES(CHANGE_TYPE, SOURCE_KEY_FIELD,SOURCE_KEY, SOURCE_TABLE,USERNAME)VALUES("I","TEAM_ID",NEW.TEAM_ID,"TEAMS",USER);END;/* After an Update */ALTER TRIGGER TEAMS_REPL_UPDATE FOR TEAMSAFTER UPDATEASBEGINIF (USER "REPLICATE") THENINSERT INTO CHANGES(CHANGE_TYPE, SOURCE_KEY_FIELD,SOURCE_KEY, SOURCE_TABLE,USERNAME)VALUES("U","TEAM_ID",NEW.TEAM_ID,"TEAMS",USER);

  • END;/* After a Delete */ALTER TRIGGER TEAMS_REPL_DELETE FOR TEAMSAFTER DELETEASBEGINIF (USER "REPLICATE") THENINSERT INTO CHANGES(CHANGE_TYPE, SOURCE_KEY_FIELD,SOURCE_KEY, SOURCE_TABLE,USERNAME)VALUES("D","TEAM_ID",OLD.TEAM_ID,"TEAMS",USER);END;Agora ns executaremos duas verses do REPLD:

    C:\REPLD SOURCEDB TARGETDBC:\REPLD TARGETDB SOURCEDBVoce deve notar que quando voce sai de um modelo de replicao mestre-escravo paraum modelo ponto-a-ponto, diversas complexidades aparecem e devem serconsideradas antes de implementar a replicao. Essas complexidades e comotrabalhar com elas sero discutidas na prxima seo.Replicando uma alterao quando ela ocorre (Near-Synchoronous Replication)Se desejarmos replicar as alteraes de uma tabela sem depender do timer, nsprecisamos utilizar o mecanismo de Eventos do Interbase. Ele requer a criao de doispassos: Gerar um evento e responder um evento.Para gerar o evento, precisaremos adicionar um novo TRIGGER CHANGES na tabelaTEAMS:CREATE TRIGGER CHANGES_ALERT FOR TEAMSAFTER INSERTASBEGINPOST_EVENT "NEW_CHANGE";END;Para responder ao evento, precisaremos adicionar um componente do Delphi chamadoIBEventAlerter em nossa aplicao REPLD, registrar nosso interesse no evento"NEW_CHANGE" adicionando-o propriedade Events e ento linkar o eventoOnEventAlert nossa procedure de replicao como se segue:procedure TForm1.IBEventAlerter1EventAlert(Sender: TObject;

  • EventName: string; EventCount: Longint; var CancelAlerts: Boolean);beginReplicate;end;Teste isso.Replicao em tabelas com chaves compostasPara simplicidade, no exemplo anterior ns replicamos tabelas simples com chavesinteiras. A mesma tcnica, um pouco modificada, pode ser usada para replicar tabelascontendo chaves compostas.A principal diferena entre manusear chaves compostas e simples no mtodo que asalteraes so logadas. Ao invs de uma simples tabela CHANGES, no caso de chavescompostas necessrio uma tabela de "log" para cada tabela base que ser replicada.Replicao cruzada em WAN com RAS(Remote AccessServices)O Servio RAS do Windows NT e Dial-up Netwroking do Windows 9x permite acesso viamodem aos servios que s estariam disponveis em uma rede. Isto significa que seprecisssemos replicar informaes em sites remotos atravs do nosso mecanismo dereplicao, ele necessitar suportar o RAS.A maneira mais fcil de implementar no Delphi o RAS usar componentes. H vriosdisponveis em forma de shareware ou freeware na internet. Para esse exemplo nsusaremos o TRas de Daniel Polistchuck que est disponvel no site www.delphi32.com.Como toda a complexidade do RAS est sendo trabalhada pelo componente TRAS, paraacrescentaro RAS nossa replicao necessitar apenas algumas linhas de cdigo.Primeiramente ns precisaremos modificar a procedure Replicate de forma queocorrer uma conexo via RAS sempre que uma alterao dever ser replicada.procedure TForm1.Replicate;beginwith qryChangeList dobeginDatabaseName := 'SourceDB';sql.add('select * from changes');if active then close;open;if (recordCount > 0) thenbeginmemoLog.lines.add(DateTimeToStr(Now)+' Dialing DT');RAS1.EntryName := 'DT';RAS1.Connect;end;

  • end;end;Como voc pode ver, ns adicionamos um teste para verificar se h registros seremenviados e, caso seja verdadeiro criada uma conexo RAS chamada "DT".Nos tambm movemos o resto do que previamente existia nesta procedure para oevento "OnConnect" do componente RAS e fizemos a query de alterao(QryChangeList) global para a form :procedure TForm1.RAS1Connect(Sender: TObject);varstrChangeType : String;beginwith qryChangeList dobeginmemoLog.lines.add(DateTimeToStr(Now)+' Connected to DT');trywhile not eof dobeginif (fieldByName('CHANGE_TYPE').asString = 'I') thenbeginstrChangeType := 'Insert';ReplicateInsert(fieldByName('SOURCE_TABLE').asString,fieldByName('SOURCE_KEY_FIELD').asString,fieldByName('SOURCE_KEY').asInteger)endelse if (fieldByName('CHANGE_TYPE').asString = 'U') thenbeginstrChangeType := 'Update';ReplicateUpdate(fieldByName('SOURCE_TABLE').asString,fieldByName('SOURCE_KEY_FIELD').asString,fieldByName('SOURCE_KEY').asInteger)endelse if (fieldByName('CHANGE_TYPE').asString = 'D') thenbeginstrChangeType := 'Delete';ReplicateDelete(fieldByName('SOURCE_TABLE').asString,fieldByName('SOURCE_KEY_FIELD').asString,fieldByName('SOURCE_KEY').asInteger)end;

  • memoLog.lines.add( DateTimeToStr(Now)+' '+strChangeType+' '+fieldByName('SOURCE_KEY').asString+' on '+fieldByName('SOURCE_TABLE').asString);DeleteFromChanges(fieldByName('CHANGE_ID').asInteger);next;end;close;finallyRAS1.Disconnect;memoLog.lines.add(DateTimeToStr(Now)+' Disconnected from DT');end;end;end;Isto tudo que se precisa para fazer uma conexo remota e replicar as alteraes efazer a desconexo.Isso simples ?No. Com a replicao podem aparecer diversos problemas e por isso necessrio umbom design e planejamento prvio e s vezes um pouco de programao. Abaixo estoalgumas orientaes:Conflitos de UpdateA segurana para replicao Assncrona crtica para quase todas as aplicaes.Porm, o que aconteceria se o mesmo elemento de dados (por exemplo, a mesmacoluna de um mesmo registro) for atualizada em dois locais diferentes ao mesmotempo, ou mais precisamente no mesmo intervalo de replicao?Isto conhecido como conflito de Update. Sendo assim quanto menor for o tempo deatualizao da rplica (ou seja, menor o intervalo(ciclo) de atualizao) menor ser apossibilidade de ocorrer conflitos de atualizao.Alternativamente, os conflitos de atualizaes podem ser evitados limitando o"ownership" ou o direito para atualizar um elemento de dado para um determinadolocal. Na realidade, muitos acreditam que resoluo de conflito uma questo deprocessamento e no uma questo para os desenvolvedores de software. Eliminando apossibilidade de conflitos atravs de design e procedimentos, o software no precisariaresolver conflitos de updates pois os mesmos nunca ocorreriam, na teoria.Essa viso no entanto muito limitada quando os clientes esto exigindo que vriasopes para resoluo de conflitos sejam incorporadas nas ferramentas de replicaode dados.Unique Keys e GeneratorsTipicamente quando se trabalha com chaves nicas inteiras, uma trigger de BEFOREINSERT utilizada adcionar e recuperar um novo valor de um generator. Quando setrabalha com replicao isso pode gerar alguns problemas.

  • O problema est em manter dois ou mais Banco de Dados sincronizados. Veja oexemplo abaixo:Em um BD, o generator contm o valor 5. Quando um novo registro adicionado, atrigger incrementa o valor do generator em 1 e o valor para a chave do novo registropassa ser 6.Este registro replicado para um outro Banco de Dados.Nesse segundo BD, o valor do generator de 100. Quando o registro replicado forinserido no segundo BD, uma trigger sobrepe o valor da chave (6) com o prximovalor do generator (101).A soluo tem duas possibilidades:A primeira confiar que o Cliente ir dar um valor a chave e no usar trigger.A Segunda dar intervalos de valores para cada BD, sendo que cada local possuircertos valores de chave. Como no Interbase um valor do tipo Interger pode chegar a 2bilhes de nmeros, os intervalos de nmeros poderiam ser divididos em partes demilhes se for necessrio. O Generator para cada local poder ser inicializado com umintervalo diferente usando para isso o comando para alterar o valor inicial doGenerator:SET GENERATOR GEN_NAME TO 1000000;InicializaoSe voc replicar uma origem de dados para um destino, ento voc precisar inicializaro destino pois ele estar fora de sincronia com a origem.. Tipicamente, voc poderfazer isto simplesmente implementando uma recarga dos dados da origem para odestino, ou seja do Banco de Dados para sua Replicao.Alteraes na DDLO que acontece quando voc muda o Metadata? Se voc adicionar um campo em umatabela de um lado, esta alterao ter de ser efetuada tambm nos outros BDs.ResumoReplicao de dados um assunto importante nos dias de hoje e est sendo solicitadopor um nmero cada vez maior de clientes em todo mundo. Na realidade, mais decinquenta por cento do projetos iniciados desde dezembro de 1996 por mim (DunstanThomas) era requerido replicao.A Replicao tem o potencial para prover um melhor processamento, respostas maisrpidas, reduo de comunicao, e evitar os gargalos de rede entre usuriosgeograficamente espalhados.Com o Interbase e o Microsoft RAS, a replicao de dados no somente umapossibilidade mas sim uma realidade j disponvel.