Jump to content

[Resolvido] Balanceamento de Carga Delphi Mysql (Saas)


CrominhO
 Share

Recommended Posts

Pessoal é assim,

na minha lamentável ignorância eu pensava Balanceamento de Carga em Software era só mesmo para quem não tinha mais nada para fazer 😛 lol pensava que era um "Add On" de luxo que não me tocava à porta, pois enganei-me e bem.

Preciso de fazer...

Então no inicio há-de ser algo do genero,

Red1.png

E o que prentendo(na falta de melhor) há-de ser isto,

scaleout.png

Agora no Código, no ADO é tão simples que chega a ser embaraçoso, mas não funciona... no AdoConnection temos a opção de "OnWillExecute", por lá passam todas as Instruções SQL, era só separar "Selects" pa um lado, e "Inserts", "Updates" e "Deletes" pa outro. E consegui meter a funcionar, mas por algum motivo, o "Onwillexecute" já efectuou o pedido à BD e não deixa cancelar, ou seja consegui separar as instruções mas elas já foram enviadas à BD.

No Zeos, consegui também consegui meter a funcionar com o ZUpdateSql, chega ao ponto de estar a trabalhar numa DBgrid e ele estar a ler de um servidor e a gravar/alterar noutro, dentro do mesmo componente. Só que para isto acontecer é necessário que todas as Instruções SQL estejam dentro dos respectivos componentes, nada em Runtime. Coisa que a mim não me ajuda muito, alterar 2 milhões de linhas para fazer isto 😞

Alguma sugestão??? Nesta altura toda a ajuda é bem vinda 😞

Edited by CrominhO

As mentes humanas são realmente um local estranho!

Link to comment
Share on other sites

Se bem percebi, queres mudar o servidor a que acedes, consoante a operação que vais fazer...

Assim numa "cuidada análise" durante o pequeno almoço, que te parece:

1. Duas ligações SQL:

dbReads, dbWrites: TZConnection;

Cada uma ligada ao respectivo servidor, ambas activas em simultâneo, é claro.

Depois, pegando na minha função RunSql, mas extendendo-a para isto:

function THZQuery.RunSQL(SQL:String;Escrita:Boolean=False):boolean;
begin
    Result:=True;

    if Escrita
       then Self.Connection:=dbWrites
       else Self.Connection:=dbReads;

    try
       If not (csDestroying in Componentstate)
          then begin
                    Self.SQL.Text:=SQL;
                    Self.Active:=True;
               end;
    except
       Result:=False;
       ShowMessage('Erro de SQL:'#13#13#10+SQL);
    end;
end;

Isto mudaria o servidor a usar mesmo antes de emitires a instrução SQL, consoante a tua indicação (True ou False).

Como imaginas, não testei isto, nem ainda ponderei prós e contras.

Mas assim de repente, pareceu-me fazer sentido.

Que te parece?

  • Vote 1

"A humanidade está a perder os seus génios... Aristóteles morreu, Newton já lá está, Einstein finou-se, e eu hoje não me estou a sentir bem!"

> Não esclareço dúvidas por PM: Indica a tua dúvida no quadro correcto do forum.

Link to comment
Share on other sites

fogo isto de "já antigiu o seu limite de votos positivos hoje" tá-se a tornar repetitivo lol

A tua solução resolvia 90% do problema 🙂 ... eu não consigo explicar muito bem, só testando, ele com o ZUpdateSQL ligado ao Zquery, consegue com o mesmo DataSource fazer as duas coisas, consegue ler num e escrever/alterar noutro sem trocar nada, ou seja o uilizador nem se apercebe de nada... é como se toda a aplicação fosse uma DBlookupcombobox ligada a 2 servidores percebes? 🙂

Edited by CrominhO

As mentes humanas são realmente um local estranho!

Link to comment
Share on other sites

A tua solução resolvia 90% do problema 🙂 ... eu não consigo explicar muito bem, só testando, ele com o ZUpdateSQL ligado ao Zquery, consegue com o mesmo DataSource fazer as duas coisas, consegue ler num e escrever/alterar noutro sem trocar nada, ou seja o uilizador nem se apercebe de nada... é como se toda a aplicação fosse uma DBlookupcombobox ligada a 2 servidores percebes? 🙂

Nuno podes ver só aqui como funciona com o ZQueryUpdate ??

Aqui não tenho código nenhum, ele "processa" tudo automáticamente,

http://portugal-heat.com/nuno.html

Ena, tem video e tudo! 🙂

Pois, como tinha dito, não tinha ainda ponderado todas as situações. Aquilo foi feito durante o pequeno almoço, e ainda não tinha olhado mais para isso.

Creio que para isso teria de se fazer um interceptor ao ZDataset, que fizesse aquela decisão imediantamente antes de executar a query, e não na hora que a activamos.

Não creio que o código necessário seja na conexão, pois esta já está ligada a um servidor, e não vamos andar a desligar de um para ligar a outro constantemente.

É preferível manter as duas ligações, e usar uma ou outra conforme necessário.

O local a usar é que então não será aquele.

Tenho de fazer uns testes a ver se isto é possível.

"A humanidade está a perder os seus génios... Aristóteles morreu, Newton já lá está, Einstein finou-se, e eu hoje não me estou a sentir bem!"

> Não esclareço dúvidas por PM: Indica a tua dúvida no quadro correcto do forum.

Link to comment
Share on other sites

Tava aqui a fazer uns testes...

Tenta fazer um override a estes métodos (tanto quanto sei, podes fazer isto em qualquer descendente do TDataset, uma vez que a declaração (virtual) destes pertencem a essa classe:

TZQuery = Class(ZDataset.TZQuery)
 protected
   procedure DoBeforeInsert; Override;
   procedure DoBeforeEdit; Override;
   procedure DoBeforeDelete; Override;
   procedure DoBeforeScroll; Override;
 End;
.
.
.
procedure TZQuery.DoBeforeInsert;
begin
    Connection:=dbWrites;

    inherited;
end;

procedure TZQuery.DoBeforeEdit;
begin
    Connection:=dbWrites;

    inherited;
end;

procedure TZQuery.DoBeforeDelete;
begin
    Connection:=dbWrites;

    inherited;
end;

procedure TZQuery.DoBeforeScroll;
begin
    Connection:=dbReads;

    inherited;
end;

Vê se isto ajuda...

"A humanidade está a perder os seus génios... Aristóteles morreu, Newton já lá está, Einstein finou-se, e eu hoje não me estou a sentir bem!"

> Não esclareço dúvidas por PM: Indica a tua dúvida no quadro correcto do forum.

Link to comment
Share on other sites

Não é o caso...

O TZQuery é um descendente do TDataset, nativo do Windows.

Este tem muitos métodos abstract, entre eles estes que aqui pus. Regra geral, não servem para nada, mas se os interceptarmos, podemos "brincar" um bocadinho.

"A humanidade está a perder os seus génios... Aristóteles morreu, Newton já lá está, Einstein finou-se, e eu hoje não me estou a sentir bem!"

> Não esclareço dúvidas por PM: Indica a tua dúvida no quadro correcto do forum.

Link to comment
Share on other sites

Tava aqui a fazer uns testes...

Tenta fazer um override a estes métodos (tanto quanto sei, podes fazer isto em qualquer descendente do TDataset, uma vez que a declaração (virtual) destes pertencem a essa classe:

(...)

Nope 😞 de alguma maneira ele segue sempre com a instrução SQL para onde está a "apontar" originalmente 😞 ...

Parece que vou ter mesmo de alterar a aplicação toda para funcionar com o ZupdateSQL ou então rendo-me de vez ao XE5 que já tem mais uma "dezena" de componentes update que provavelmente fazem o trabalhinho todo...

A principal questão é que eu tou a tentar alterar uma aplicação que não foi "pensada" para isso, porque o Zupdate funciona na perfeição, aliás grande parte dos jogos/aplicações, especialmente esses milhares de jogos que utilizam "motor" por trás, lêem no motor e escrevem nos Servidores deles, mas lá está, foram pensados assim...

Bem em todo o caso aqui fica a Solução com Zeos,

Zconnection1 // Ligação ao Slave
Zconnection2 // Ligação ao Master

Zquery1.connection	  :=Zconnection1;
Zquery2.connection	  :=Zconnection2;
Zquery1.updateobject  := ZupdateSQL1;

ZupdateSQL1.BeforeModifySql  := actualiza_zquery2; // Função que faz update no Master
ZupdateSQL1.BeforeDeleteSql := apaga_zquery2;	 // Função que apaga registo no Master
ZupdateSQL1.BeforeInsertSql   := insere_zquery2;	// Função que insere no Master

As simple as that 😞

Tive a ver com o MyDac da Devart, mas é exactamente a mesma coisa,

no entanto fica mais uma solução,

MyQueryUpdate.Connection := MyConnection2; // master
MyQueryDelete.Connection := MyConnection2;
MyQueryInsert.Connection := MyConnection2;
MyQueryLock.Connection := MyConnection2;
MyUpdateSQL.ModifyObject := MyQueryUpdate;
MyUpdateSQL.DeleteObject := MyQueryDelete;
MyUpdateSQL.InsertObject := MyQueryInsert;
MyUpdateSQL.LockObject := MyQueryLock;
MyUpdateSQL.RefreshObject := MyQueryRead;
MyQueryRead.Connection := MyConnection1; // slave
MyQueryRead.UpdateObject := MyUpdateSQL;
MyQueryRead.Open;

XE5 cá vamos nós 😞

Edited by CrominhO

As mentes humanas são realmente um local estranho!

Link to comment
Share on other sites

Ena, tem video e tudo! 🙂

Tava tão perdido com isto tudo que nem vi isto lol 😛 só fiz o filme porque é uma coisa tão simples a funcionar e tão dificil de explicar, mas com o teu código, de certeza absoluta que se eu tivesse mais um dia de "sanidade" que chegava lá 🙂

As mentes humanas são realmente um local estranho!

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

×
×
  • Create New...

Important Information

By using this site you accept our Terms of Use and Privacy Policy. We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.