Multiplas Contas em uma instancia unica Spring

Galera, bom dia. Sou desenvolvedor Java e estou criando uma App Fullstack utilizando Spring Boot e React. Esta aplicação, falando de arquitetura, irá consistir em um sistema de auto serviço, onde o usuario vai conseguir criar uma conta e acessar o sistema.

Minha duvida é referente a arquitetura do sistema e de dados, onde na minha visão eu tenho 3 opções:

  • Posso rodar uma unica instancia da App, com um unico banco de dados onde os registros de cada cliente ficaram na mesma tabela separados por um identificador unico para cada cliente;

  • Rodar uma instancia do sistema e um banco de dados para cada cliente, essa opção eu não gosto dela devido ao consumo de recurso do servidor, terá clientes que usam mto a app, outros q usa pouco, porem ambos consumirão praticamente o mesmo recurso de servidor, que seria o minimo necessario para rodar o sistema;

  • Utilizar uma unica instancia do servidor com multiplos banco de dados ou multiplos schemas iguais no mesmo banco de dados.

Eu consigo enxergar apenas essas 3 opções, sendo que a mais me agrada é a primeira, porem na minha experiencia com desenvolvimento eu tenho notado que utilizando bancos relacionais, como o postgres (Que é o banco que utilizarei), quando eu faço atualizações ou inserções em massa em uma tabela ele tende a dá um lock nela, então imagine eu tendo umas instancia para 100 clientes, sendo que um resolve fazer alguma coisa mais pesada e acaba dando lock na tabela para os outros 99 clientes… É um desastre.

As outras duas opções eu não sei se é uma opção, já utilizei o recurso de multiplos schemas iguais, mas não foi utilizando spring, e a minha experiencia é: fica uma tremenda gambiarra fazer dessa forma utilizando hibernate, porem funciona e resolve o problema da primeira abordagem.

Eu gostaria de opinião de vocês, sugestão de arquitetura para esse tipo de sistema, pq sei que a hora de fazer a escolha certo é agora, dps de pronto será problema. Mto obrigado.

Já trabalhei com uma arquitetura em que havia uma divisão: clientes de pequeno porte eram gerenciados pelo banco de dados “do sistema” e clientes de grande porte tinham uma estrutura particular de banco de dados.
Dá um trabalho maior, mas não havia problemas com lock e o desempenho era aceitável.

Bom dia Darlan, obrigado pela resposta. Então, isso que vc falou seria a minha primeira opção, obviamente dependendo da quantidade de clientes e até do peso de 1 cliente vc tem q particionar os clientes em instancias diferentes. Agora tu disse q não tinha problemas de lock, que tipo de sistema era? Pq tipo, o lock normalmente acontece quando eu tenho operações em transações de banco de dados extensas, ou seja, que demoram a ser concluídas… Eu sei q o ideal é evitar isso, mas as vezes é inevitável, esse tipo de transação existia nessa aplicação que vc citou?

Sistema de rastreamento de veículos, basicamente, consultas e relatórios.
A estrutura que tínhamos era PG também, com JSF 1.3 (tomahawk) como front e alguns sistemas interagiam com WS SOAP PHP (!!!) e outros utilizavam como ORM o EclipseLink.

O sistema era “inteligente” e criava, para cada cliente, de acordo com o porte (pequeno, médio, grande ou gigante) uma estrutura isolada de tabelas (quase um cluster).
Isso evitava o lock.
Além disso, seria interessante você pensar em um cache de dados, talvez com um banco de dados não relacional.
Nós chegamos a desenvolver um grid dinâmico com atualização via websocket, baseado em um cache MongoDB, porém, foi barrado pela equipe do suporte. Tivemos que apelar para o Coherence do Weblogic 11g.

Eu estou usando cache em memoria com o ehCache, mais até pensei em usar o MongoDB como tipo um cache (Até cogitei utilizar 100% mongodb), mais queria evitar complexidade desnecessária na aplicação.

Mas sua ideia de utilizar um banco como o mongo para cache, e sincronizar com o banco relacional parece uma ideia interessante, isso realmente evitaria o lock em tabelas, podendo utilizar o banco relacional mais para consultas, que é o forte dele de fato, e o ponto fraco dos banco noSql.

Vou estudar essa alternativa, vlw.

Opa bom dia mizael86. eu não possuo muito experiência com isso, mas cheguei a trabalhar um tempinho numa arquitetura multitenancy onde tinha vários schemas de banco para vários clientes no mesmo SGBD.
o backend era feito todo com spring e era utilizando os spring data(hibernate) para a parte de dados e troca de schema, eu mesmo cheguei a fazer um sistema assim somente a nível de conhecimento e até cheguei a gerar uma boa massa de dados e testes para vê a viabilidade.

Fiz com base nesse projeto, realizando algumas alterações é claro.
talvez te ajude em algo.

Vc fala de multi schema ou multi database?
E como que gerencia dessa forma no spring?

Esse daí é multi schema, oque eu trabalhava era trocado por um parametro na url, porém eu peguei o mesmo projeto e fazia a troca de schema pelo login(era um sistema mais simples onde o login era por empresa), quando a pessoa logava eu trocava para o schema correto e jogava um cookie do backend para o front-end(com um hash que identificava cada cliente).

a troca era feito no java por um filter, depois de verificar se o login existia no database, antes de servir a home a request caia num filter que fazia a troca do schema do database(ou baseado na url ou baseado no próprio login ou do jeito que sua lógica demandar) ai fica na sua escolha.

mas basicamente as requests(exeto a de login) passava por um filter pegava o cookie e fazia o direcionamento de troca de esquema.

Para cada empresa cadastrada tinha um schema de mesmo nome e isso era mantido numa tabela aparte em outro schema.
Esse projeto ai da uma ideia(GitHub), porém para amadurecer ele depende doque você precisa.

no geral o projeto tinha dois schemas, um para manter o nome das empresas e seus schemas(afim de relacionar ambos) e outro schema padrão para cada empresa que se cadastrava(só mudava o nome as tabelas eram as mesmas).

existe umas matérias sobre esse assunto no site chamado D-zone, da uma olhada pode esclarecer algo, so procurar no google por ‘mutitenancy D-zone’.

Acho a solução do @Fabioreis1415 bastante complexa.
Aliás, se o temor é lock, suspeito que usar um ORM seja um tiro no pé.

Uma das aplicações que eu utilizei (e desenvolvi), armazenava os dados dos clientes na base de dados, os clientes pequenos utilizavam uma conta genérica e os maiores utilizavam contas específicas, todas READONLY, por razões óbvias.
Quando havia necessidade de conexão ao banco, primeiro abria -se a conexão específica ou genérica, de acordo com o caso e, então, processava-se cada interação necessária.

Isso permite que você tenha N bancos específicos e um genérico.

@darlan_machado, nao eh complexa nao, como dissr, eu ja havia utilizado essa questao de multi schema, so q nao com spring, era em um projeto JSF 1.2, entao era meio q na unha e ficava uma gambi, mas funcionava, e eu conseguia ter uma unica instância da app utilizando varios schemas. E isso evitava o lock de banco pq as tabelas entre schemas nao tinha relacionamento.

Sobre o uso de ORM, cara, eu ate concordo com vc em relação as criticas, mais hj em dia nao usar eh uma perca de produtividade monstruosa, nao vale a pena deixar de lado.

Essa sua ideia ai eu achei bem única e um tanto complexa, mas eh uma alternativa tambem.

Eu desconhecia o multi tenancy do spring, me parece q ficou mto mais facil fazer isso, agora quero ver em termo de uso de memoria, pq qdo fiz na epoca eu tinha q registrar um pool pra cada schema, isso consumia uma memoria danada do servidor, se o spring conseguir gerenciar isso em um unico pool, eh show de bola.

Depende do que você vai achar mais importante: vi pouquíssimos sistemas de média e alta complexidade que conseguem, efetivamente, obter 90% do que qualquer ORM oferece.
A maioria usa o ORM só para construir a conexão e depois soca native query na brincadeira. Ora, se é para fazer isso, use JDBC.

Sobr

Sobre isso, desconheço qualquer multitenancy que seja diferente.

Se está considerando utilizar o Spring Data, sugiro fortemente que considere o MongoDB.
Tirando a curva de aprendizado, eu não enxergo no Mongo qualquer demérito perto de um banco relacional.

Vc fala em criar o próprio ORM de forma mais simples e utilizar query nativa normal? Eu não acho q ah perda de desempenho considerável com ORM, a unica coisa que eu realmente não gosto nele é o fato de nao conseguir de forma facil recuperar apenas dados específicos nas consultas, e principalmente, dá update em campos específicos. Claro q eh possível fazer usando HQL ou query nativa mesmo usando ORM, mas acho que poderia funcionar de forma melhor.

Depende, se vc entende que cada schema contem a mesma estrutura de mapeamento, não ah necessidade de ter varios pool registrados, como na epoca não existia uma forma de fazer isso apenas com Hibernate, eu fiz dessa forma, mas com o spring jpa hoje talvez seja feito da forma mais correta, eh o que vou avaliar. Pra vc ter ideia, eu pegava e registrada cada pool com a propriedade default_schema com o schema q eu queria, era um “brute force” danado, rs.

Pow mano, eu sinceridade considerei isso sim, porem eu não conheço o mongodb na pratica, então fui pesquisar, e o que eu não gostei foi a dificuldade em relacionar registros. Vi que no mongo cada “tabela” é na vdd um json binario, e que não tem relação com outras tabelas. Bom, até ai eu nao vi tantos problema, pq relacionamento é uma questão de dados relacionados apenas, porem me preocupou a parte de pesquisa de dados, com SQL vc faz buscas poderosas, e de certa forma tem uma performance incrível, eu não vi como fazer isso no mongo, exceto pesquisas simples. Estou errado? É possível ter todo o poder de consulta de um banco relacionando usando o mongo? E com performance aceitável?

Não, falo em usar o máximo do que qualquer ORM entrega, sem apelas para coisas que você resolveria com simplicidade se usasse jdbc.

Mas isso não vai, da mesma maneira, obrigar a ter uma informação distinta em memória?

A partir do momento que você deixar de lado o pensamento “relacional” e olhar o mongo como um banco de dados orientado a objetos (que, efetivamente, é o que ele é), você passa a entender que a questão de relacionamentos é a complexidade desnecessária.

Veja, você já tem um ou vários objetos que estão ligados a um ou mais objetos. Por qual razão você quebraria isso tudo, se obrigando a criar PK, FK, tabelas associativas e etc se você pode, apenas, gravar o objeto, como ele é? Melhor, se você, um dia, mudar de front para algum que seja thin client, como o angular, você nem precisa ficar serializando e deserializando tudo, pega do banco e manda pra tela e boa.

Perfeito, vc fala minimizar o uso. Eu já faço isso sempre que preciso de performance extra.

Vê esse artigo, la ele fala q vc tem 2 opções de gerenciamento, uma seria a que eu usei, registrar varios pool, a outra seria um unico pool, e antes de pegar a conexao e por no contexto ele configura o schema.

Ai que entra a bronca, vamos numa situação pratica, que foi exatamente uma postagem que eu vi de alguem que teve problemas com o Mongo em sua app em uma app de rede social:

Você tem Objeto que representa o Usuario, dentro de Usuario você tem uma lista de postagem. Se você salva Usuario, ele salva a lista de postagem. Porem se em determinado momento você precisar referenciar uma postagem, porque essa tem referencia outro usuario, você ai teria um problema, pq vc teria q pegar uma copia da postagem de um usuario e jogar na tela. Se esse cara editar essa postagem, você teria que varrer as copias da mesma para efetuar a mesma alteração, isso porque não é o mesmo registro. Para resolver isso eu teria que ter objetos desacoplados, o que tornaria estranho, pq vc teria o MESMO OBJETO em locais diferentes, conseguiu entender? Se tu pensar no mongo como um banco de memoria, excelente, mas como um banco persistente, cara, eu ainda não consegui enxergar ele como sendo mais poderoso no aspecto produtividade, facilidade e desempenho.

Tu nao me respondeu sobre a questão de pesquisas.

Esta?
Olha, os bancos NoSQL surgiram justamente por isso.
Por mais ninja que uma query seja, ela precisa “sair catando” coisas aqui, ali e acolá.
A ideia de um banco, baseado em documentos, é a de ter tudo em um único local.

Esta questão vai depender, certamente, do teu modelo. Entenda, não é só você, eu e muita gente fomos doutrinados a pensar em tabelas, colunas, constraints e etc, ao mesmo tempo em que tentamos criar sistemas mais OO, ainda inserimos um maldito identificador, cuja única finalidade é quebrar o modelo OO e atender a uma necessidade estruturada.

Aí a gente retorna ao ponto que questionei antes, quanto de um framework ORM consegue-se aproveitar?

Eu fiz várias análises (proof of concept - POC) em diversos bancos de dados não relacionais (como Mongo, Cassandra, Oracle NoSQL), além de trabalhar com as colunas e ferramentas bson do postgres.

Talvez o problema que você propôs precise de uma análise mais detalhada, talvez precise de um afastamento maior do estrutural.
Digo isso por quê, se você fosse manter tudo isso só em memória, com um gigantesco mapa ou coleção, você teria os mesmos problemas, não?
Da mesma maneira, teria que percorrer todos os elementos até encontrar um que satisfaça o que precisa.

De qualquer maneira, faz o teste com o Spring, vê se te atende. Se não, veja as alternativas.

Vc tem razão, mais não é isso que o ORM faz? Ignorar o relacional e transformar em objeto? O que eu estou falando aqui não é nem o COMO é armazenado, isso é problema do banco, se eh em tabelas ou em documentos, tanto faz. Para quem está desenvolvendo a preocupação é: Desempenho, Facilidade e Capacidade de busca. Ainda tenho dificuldade de visualizar o uso do mongo em sistema de dados complexos, se tu puder me indicar alguma coisa para estudo, que possa abrir mais minha mente, eu agradeço :slight_smile:

O ORM (todos, sem exceção e não apenas do Java) estão, ainda, amarrados ao modelo relacional. Não tem como fugir.
Talvez o mai inteligente que eu tenha visto ainda seja o active record, que nasceu no Ruby e foi portado pro PHP (até vi alguma coisa no java, mas…).

O que eu tinha entendido era que você estava preocupado com o modo como o banco de dados iria gerenciar isso tudo (evitar lock, etc), mas, se não e´com o banco, então não esquente com isso.
Até por que o que eu questionei foi quanto, efetivamente, de ORM você vai usar e se, devido a complexidade do sistema, não vai cair em algo como native query.

Na vdd sim, eu estou preocupado com o lock de banco (Seria como ele vai gerenciar), por isso estou vendo como possibilidade o MongoDB, pq sei q ele não tem esse problema. A outra possibilidade eh o multitenant.