OVH Cloud OVH Cloud

Création de connection synchronisée?

7 réponses
Avatar
p0psy
Bonjour,

Je dois me connecter à plusieurs bases de données pour effectuer
quelques requêtes simples. Il y a un petit millier de bases de données
(MySQL) à interroger (d'un point de vu architecture c'est pas terrible,
c'est un choix qui a été fait il y a longtemps dans ma boîte et la
réduction du nombre de bases de données ne sera pas réalisé avant un
bout de temps).
Donc si je me connecte à chacun de ses bases une à une, j'en ai pour au
moins une heure (vu que DriverManager.getConnection() est l'étape la
plus longue en temps pour mon traitement).
J'ai donc voulu mettre ça en multi-thread pour me connecter
simultanément à plusieurs bases pour réduire le temps... mais
apparemment la méthode getConnection() de DriverManager est synchronisée
(testé avec un vieux driver mysql et un récent (3.1.7)).
Est-ce lié au driver MySQL, au specs Java (apparemment c'est déclaré
synchronisé dans les specs)? Et aurai-je un moyen de résoudre/contourner
ce problème afin d'accélérer mon traitement?
Merci,

Laurent (qui est super content d'avoir gagné une demi-seconde sur un
traitement de plus d'une heure grâce au multi-threads ;-))

7 réponses

Avatar
Trognon Patrice
p0psy wrote:

Bonjour,

Je dois me connecter à plusieurs bases de données pour effectuer
quelques requêtes simples. Il y a un petit millier de bases de données
(MySQL) à interroger (d'un point de vu architecture c'est pas terrible,
c'est un choix qui a été fait il y a longtemps dans ma boîte et la
réduction du nombre de bases de données ne sera pas réalisé avant un
bout de temps).
Donc si je me connecte à chacun de ses bases une à une, j'en ai pour au
moins une heure (vu que DriverManager.getConnection() est l'étape la
plus longue en temps pour mon traitement).
J'ai donc voulu mettre ça en multi-thread pour me connecter
simultanément à plusieurs bases pour réduire le temps... mais
apparemment la méthode getConnection() de DriverManager est synchronisée
(testé avec un vieux driver mysql et un récent (3.1.7)).
Est-ce lié au driver MySQL, au specs Java (apparemment c'est déclaré
synchronisé dans les specs)? Et aurai-je un moyen de résoudre/contourner
ce problème afin d'accélérer mon traitement?
Merci,

Laurent (qui est super content d'avoir gagné une demi-seconde sur un
traitement de plus d'une heure grâce au multi-threads ;-))


interessant et original :)

en effet DriverManager.getConnection() est synchronisé et de plus static
donc en multithread tu as pu constater tu gagnes rien :)

Voici quelques idées en vrac.

Idée 1)
Eclater ton applie en 2 parties, une serveur, l'autre cliente,
l'idée serait que le serveur ouvre tes 1000 connections une fois pour
toute, ensuite a chaque fois que tu as besoin d'utiliser les données
tu lances la partie client qui se connecte a ton server, qui lui est
donc déjà connecté a tes n bases de données.
La communication entre ton client et ton serveur pouvant se faire par
RMI ou par socket.

Idée 2)
Centraliser par réplication MySQL toutes tes bases dans une seule base
de données !
2 possibilité ici !
1) les schémas des n bases sont les mêmes.
tu ne peux pas centraliser toutes tes bases dans une même base,
a voir si dans mysql a partir d'une connection tu peux acceder aux
tables d'un autre schéma, sinon en postgres c'est possible, l'idée
serait alors de synchroniser toutes tes bases mysql dans une base
postgres, chaque base étant dans une base postgres, tu pourras
y acceder au travers d'une seule connection.
Une fois de plus je ne sais pas si mysql gere ca, si oui pas
besoin de postgres.

2) les schémas ne sont pas les mêmes.
Alors pas de problème, sauf que tu vas avoir toutes tes tables
de toutes tes bases dans une même base, ce qui est plutot crade :(

Voila, perso je creuserais la solution Idée 1).

En espérant avoir fait avancer un peu ton smillblick du moins j'aurais
essayé.

PS : c'est quelle boite ou t'as ca ?

--
Cordialement,

Patrice Trognon
http://www.javadevel.com

Avatar
jlp
p0psy wrote:


Bonjour,

Je dois me connecter à plusieurs bases de données pour effectuer
quelques requêtes simples. Il y a un petit millier de bases de données
(MySQL) à interroger (d'un point de vu architecture c'est pas terrible,
c'est un choix qui a été fait il y a longtemps dans ma boîte et la
réduction du nombre de bases de données ne sera pas réalisé avant un
bout de temps).
Donc si je me connecte à chacun de ses bases une à une, j'en ai pour au
moins une heure (vu que DriverManager.getConnection() est l'étape la
plus longue en temps pour mon traitement).
J'ai donc voulu mettre ça en multi-thread pour me connecter
simultanément à plusieurs bases pour réduire le temps... mais
apparemment la méthode getConnection() de DriverManager est synchronisée
(testé avec un vieux driver mysql et un récent (3.1.7)).
Est-ce lié au driver MySQL, au specs Java (apparemment c'est déclaré
synchronisé dans les specs)? Et aurai-je un moyen de résoudre/contourner
ce problème afin d'accélérer mon traitement?
Merci,

Laurent (qui est super content d'avoir gagné une demi-seconde sur un
traitement de plus d'une heure grâce au multi-threads ;-))



interessant et original :)

en effet DriverManager.getConnection() est synchronisé et de plus static
donc en multithread tu as pu constater tu gagnes rien :)

Voici quelques idées en vrac.

Idée 1)
Eclater ton applie en 2 parties, une serveur, l'autre cliente,
l'idée serait que le serveur ouvre tes 1000 connections une fois pour
toute, ensuite a chaque fois que tu as besoin d'utiliser les données
tu lances la partie client qui se connecte a ton server, qui lui est
donc déjà connecté a tes n bases de données.
La communication entre ton client et ton serveur pouvant se faire par
RMI ou par socket.

Idée 2)
Centraliser par réplication MySQL toutes tes bases dans une seule base
de données !
2 possibilité ici !
1) les schémas des n bases sont les mêmes.
tu ne peux pas centraliser toutes tes bases dans une même base,
a voir si dans mysql a partir d'une connection tu peux acceder aux
tables d'un autre schéma, sinon en postgres c'est possible, l'idée
serait alors de synchroniser toutes tes bases mysql dans une base
postgres, chaque base étant dans une base postgres, tu pourras
y acceder au travers d'une seule connection.
Une fois de plus je ne sais pas si mysql gere ca, si oui pas
besoin de postgres.

2) les schémas ne sont pas les mêmes.
Alors pas de problème, sauf que tu vas avoir toutes tes tables
de toutes tes bases dans une même base, ce qui est plutot crade :(

Voila, perso je creuserais la solution Idée 1).

En espérant avoir fait avancer un peu ton smillblick du moins j'aurais
essayé.

PS : c'est quelle boite ou t'as ca ?

Creuser aussi le mécanisme des ThreadLocal :

http://java.sun.com/j2se/1.4.2/docs/api/java/lang/ThreadLocal.html
http://www-128.ibm.com/developerworks/java/library/j-threads3.html


Avatar
Laurent Bossavit
Laurent,

apparemment la méthode getConnection() de DriverManager est synchronisée
(testé avec un vieux driver mysql et un récent (3.1.7)).


La méthode getConnection() de DriverManager est synchronisée, mais pas
la méthode connect() de Driver. Au lieu de l'appel

Connection c = DriverManager.getConnection(url,properties);

tu auras peut-être plus de succès en utilisant la séquence équivalente

Driver driver = DriverManager.getDriver(url);
Connection c = driver.connect(url,properties);

Sans garantie - je n'ai pas essayé, et je ne sais pas à quel gain tu
peux t'attendre même si tout ou partie de tes demandes de connection
s'effectue effectivement en parallèle.

Laurent
http://bossavit.com/

Avatar
p0psy
apparemment la méthode getConnection() de DriverManager est synchronisée
(testé avec un vieux driver mysql et un récent (3.1.7)).
La méthode getConnection() de DriverManager est synchronisée, mais pas

la méthode connect() de Driver. Au lieu de l'appel

Connection c = DriverManager.getConnection(url,properties);

tu auras peut-être plus de succès en utilisant la séquence équivalente

Driver driver = DriverManager.getDriver(url);
Connection c = driver.connect(url,properties);

Sans garantie - je n'ai pas essayé, et je ne sais pas à quel gain tu
peux t'attendre même si tout ou partie de tes demandes de connection
s'effectue effectivement en parallèle.
Pas bête... cependant ce coup-ci c'est getDriver qui est static et

synchronisé.

Donc je retombe dans le même problème. Si je devais lancer moni appli
qu'une fois et après faire plusieurs fois le traitement, je pourrais
certainement y gagner en faisant en premier un getDriver sur toutes les
bases et ensuite faire un connect. Seulement je ne lance mon appli
qu'une fois de temps en temps pour faire quelques vérifications ou bien
quelques calculs/requêtes diverses... donc je ne gagne rien :-(.
Merci quand même.

Laurent.


Avatar
p0psy
en effet DriverManager.getConnection() est synchronisé et de plus static
donc en multithread tu as pu constater tu gagnes rien :)

Voici quelques idées en vrac.

Idée 1)
Eclater ton applie en 2 parties, une serveur, l'autre cliente,
l'idée serait que le serveur ouvre tes 1000 connections une fois pour
toute, ensuite a chaque fois que tu as besoin d'utiliser les données
tu lances la partie client qui se connecte a ton server, qui lui est
donc déjà connecté a tes n bases de données.
La communication entre ton client et ton serveur pouvant se faire par
RMI ou par socket.
Dans nos applis habituelles on a un système un peu dans ce genre (mais

avec un pool de connexions parceque 1000 connexions ouvertes en même
temps ça le fait pas trop).
Mais le pool est dans chaque appli. Ton idée me paraît du coup très
intéressante... mais mon problème c'est qu'en gros on a 3 serveurs de
bases de données, donc en gros 300 bases par serveur, donc 300
connexions par serveur... et là si je fais ça on va me taper sur les
doigts ;-).
Ceci dit je pense que c'est la meilleure solution (pour l'instant).

Idée 2)
Centraliser par réplication MySQL toutes tes bases dans une seule base
de données !
2 possibilité ici !
1) les schémas des n bases sont les mêmes.
tu ne peux pas centraliser toutes tes bases dans une même base,
a voir si dans mysql a partir d'une connection tu peux acceder aux
tables d'un autre schéma, sinon en postgres c'est possible, l'idée
serait alors de synchroniser toutes tes bases mysql dans une base
postgres, chaque base étant dans une base postgres, tu pourras
y acceder au travers d'une seule connection.
Une fois de plus je ne sais pas si mysql gere ca, si oui pas
besoin de postgres.
C'est le cas, en gros toutes les bases sont identiques. Ceci dit je

trouve que ça commence à ressembler à une usine à gaz là (et comme
c'était déjà le cas avant, on va éviter d'en rajhouter une couche).

2) les schémas ne sont pas les mêmes.
Alors pas de problème, sauf que tu vas avoir toutes tes tables
de toutes tes bases dans une même base, ce qui est plutot crade :(
Ce n'est donc pas le cas ;-).


Voila, perso je creuserais la solution Idée 1).

En espérant avoir fait avancer un peu ton smillblick du moins j'aurais
essayé.
Un petit peu oui, merci.

Je vais creuser l'idée du serveur RMI.

Laurent.

Avatar
p0psy
Creuser aussi le mécanisme des ThreadLocal :
http://java.sun.com/j2se/1.4.2/docs/api/java/lang/ThreadLocal.html
http://www-128.ibm.com/developerworks/java/library/j-threads3.html
Hou là... je découvre un nouveau monde là.

Je ne sais pas si ça va m'aider pour mon problème, mais en tout cas,
voilà une fonctionnalité de java que je ne connaissais pas (il y en a
beaucoup d'autres que je ne connais pas c'est vrai).
Merci,

Laurent.

Avatar
Laurent Bossavit
Laurent,

Pas bête... cependant ce coup-ci c'est getDriver qui est static et
synchronisé. Donc je retombe dans le même problème.


Mais non... On a besoin de cet appel une seule fois:

Driver driver = DriverManager.getDriver(url);
for (int i=0; i < 1000; i++) {
Thread t = new Thread() {
public void run() {
Connection c = driver.connect(getUrlFor(i),properties);}
traitement(c);
}};
t.start();
}

Laurent