IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Entity Framework Discussion :

(WCF + EF) + Transaction par synchro = Crash


Sujet :

Entity Framework

  1. #1
    Membre éprouvé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2006
    Messages
    436
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2006
    Messages : 436
    Points : 963
    Points
    963
    Par défaut (WCF + EF) + Transaction par synchro = Crash
    Bonjour à vous ! Je ne sais pas dans quelle catégorie placer ce post. Donc libre à un admin de le déplacer s'il juge que la rubrique n'est pas la bonne (et désolé du désagrément !)

    Je travaille sur un projet qui traite de plusieurs bases de données qui sont synchronisés.

    Nous venons de remarquer que dès qu'on exécute une requête sur une tablequi est verrouillée par un script de synchro entrainait sistématiquement un crash.

    Vous pouvez reproduire ce cas en créant une table sur un petit projet, faites un BEGIN TRAN depuis SQL Management Studio sur cette table, essayé d'exécuter un update via EF sur cette table : cela crash.

    Je voulais savoir si certains avaient déjà réfléchis à ce problème et élaboré des solutions pour profiter de vos pistes et vos recherches. Je ne sais pas encore vers quelle mécanisme me tourner ni comment structurer le tout.

    L'architecture de ce projet est la suivante (en light) : une appli Silverlight, une couche WCF qui permet de faire des appels à des méthodes qui travaillent sur l'EDM.

    Le problème est que la synchro peut durer 1 seconde comme elle peut durer 1 min ou 2. Du coup, notre appli étant utilisé par beaucoup d'utilisateur, il arrive que des dizaines d'utilisateurs tentent de faire une modif pendant ce script de synchro. 10 maintenant mais d'ici 1 an cela sera peut être 100 clients qui feront un update pendant ce petit laps de temps.

    Du coup j'hésite sur les mécanismes à mettre en place :

    Retourner une erreur à Silverlight qui lui fera refaire l'appel WS une nouvelle fois en priant que ça passe (avec possibilité de refaire jusqu'à 3 fois l'appel sinon message "la base est actuellement indisp blablabla) solution la plus simple et rapide à mettre en place mais ...

    Sinon, faire une stack des clients appelants et de la modifs qu'ils souhaitaient faire, et par un event que je ne connais pas encore, au COMMIT (et donc déverrouillage de la base) je parcours la liste, les traites puis fait un genre de push aux clients pour leurs indiquer que c'est bon.

    Faire patienter le client plus longtemps jusqu'à ce que le script de synchro soit passé, puis reprendre la suite (je pensais que c'est ce qu'il se faisait par défaut) mais problème de timeout potentiel de 2 côtés : Silverlight avec WCF et EF qui me dégagerait car cela fait déjà 1 min que la table est verrouillé et qu'il n'a pas que ça à faire

    J'ai plusieurs autres idées mais c'est dans le même genre. Donc je m'en remets à vos connaissances

    Merci d'avance, Nicolas
    "S'adapter, c'est vaincre" - Cellendhyll de Cortavar

  2. #2
    Modérateur
    Avatar de DotNetMatt
    Homme Profil pro
    CTO
    Inscrit en
    Février 2010
    Messages
    3 611
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : CTO
    Secteur : Finance

    Informations forums :
    Inscription : Février 2010
    Messages : 3 611
    Points : 9 743
    Points
    9 743
    Billets dans le blog
    3
    Par défaut
    Une des caractéristiques du monde OLTP (donc des systèmes opérationnels) est qu'on peut avoir énormément de transactions, l'objectif étant qu'elles soient les plus courtes possibles. Ceci faisant opposition au monde OLAP (data warehouses), qui est notamment caractérisé par le fait que les requêtes sont moins nombreuses, mais plus longues à exécuter.

    Dans la mesure du possible il faudra sûrement revoir le mécanisme de synchro, car il n'est pas normal de bloquer une base OLTP pendant plusieurs minutes, quelle qu'en soit la raison. Ton application ne devrait normalement pas avoir à gérer ça.

    Comment marche la synchro ? C'est un ETL ? Un script SQL ? Un batch console ?

    A voir pour référence : OLTP vs. OLAP
    Less Is More
    Pensez à utiliser les boutons , et les balises code
    Desole pour l'absence d'accents, clavier US oblige
    Celui qui pense qu'un professionnel coute cher n'a aucune idee de ce que peut lui couter un incompetent.

  3. #3
    Membre éclairé Avatar de chamamo
    Profil pro
    Inscrit en
    Juin 2006
    Messages
    588
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2006
    Messages : 588
    Points : 735
    Points
    735
    Par défaut
    Avant de traiter le problème des transactions il faut que tu nous donnes plus de détail sur la fréquence des synchronisations et le moment aussi, car dans ton cas il s'agit d'après ce que j'ai compris de l'alimentation d'un Data Warehouse, ça peut peut être sur une semaine un mois un trimestre etc. Ce qu'il faudrait faire c'est avoir un temps considérable entre deux syncho, ça peut être une semaine un mois..., selon le besoin, ça évite de bloquer les données si elles sont utilisées par d'autres applications.

    Le moment est important aussi tu peux par exemple lancer la synchro à minuit ça évitera les accès concurrents.

    Pour les transactions, essaie de fragmenter ta synchronisation, si j'ai X traitements indépendants il est plus raisonnable de créer une transaction par traitement et non une seule pour le tout.

    Depuis ton code si par exemple tu utilises les TransactionScope essaie de jouer avec les niveaux d'isolation.

  4. #4
    Membre éprouvé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2006
    Messages
    436
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2006
    Messages : 436
    Points : 963
    Points
    963
    Par défaut
    Tout d'abord merci de vos réponses. C'est très gentil de votre part.

    Alors, pour poser le contexte et répondre en même temps :

    La société dans laquelle je travaille à fusionnée avec une autre. Chacune ayants ses logiciels et sa base de données. Du coup lorsqu'on a couplé no services, nous avons du synchro nos bases pour récupérer les infos de leurs nouveaux clients et parallèlement, ils doivent recevoir les modifs lorsqu'un de nos utilisateurs modifie depuis notre logiciel, des infos sur le client.

    Du coup, il y a des synchro régulières par script SQL (procédures stockées) qui permettent d'aller faire les modifs dans leurs bases et invérsement. Nos bases de données étant complétement différentes et utilisés par de nombreux logiciels, j'imagine que les admin des serveurs SQL ont préférés faire ça via des scripts.

    Je suppose qu'il y avait sûrement d'autres manières de faire mais c'est celle qui a été mise en place.

    Nous n'avons jamais eu de problème à nos débuts. Mais aujourd'hui, on se rend compte qu'un script peut mettre à jours près de 1000 à 5000 lignes plusieurs fois par jours ou par mois (dépend du nombre de nouveaux clients : 1 clients = 1 réplication de la base type chez nous et 1 chez la société avec laquelle on a fusionné). (Note : c'est sûrement pas exactement ça mais je vous donne une idée du truc). Cette synchro peut donc se produire sur x à y lignes sur n tables. Il n'y a pas forcément des synchro tous les jours parfois aucune pendant 2 semaines. Parfois sur 500 lignes parfois 5000)

    Du coup, si pendant ces 5000 micro transactions, il est possible qu'un utilisateur tente d'accéder à une table bloquée par une de ces dernières.

    La synchro ne peut se faire la nuit. Exemple : une société cliente s'inscrit chez la société A, il a 100 employés qui sont intégrés dans sa DB. Si cela se passe à midi, il faut que rapidement, tout ces inscrits soient répertorié dans notre base pour qu'on puisse utiliser notre logiciel.

    Je ne sais pas si on utilise les TransactionScope. Je demanderai lundi au dév concerné si ça lui dit qq chose ou non ^^

    Je vais consulter le lien de Matt. Je vous en redis plus sur l'aspects technique lundi !

    Merci à vous 2 et bon dimanche !
    "S'adapter, c'est vaincre" - Cellendhyll de Cortavar

  5. #5
    Membre éprouvé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2006
    Messages
    436
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2006
    Messages : 436
    Points : 963
    Points
    963
    Par défaut
    Bonjour, alors je vous confirme que pour ce processus nous n'utilisons pas les TransactionScope mais une procédure stockée.

    Elle ne s'occupe pas de lancer le début et fin de transaction, ils sont géré à l'intérieur de certains Trigger déclencher par les différents update au sein de la procédure stockée.

    En espérant vous avoir éclairer, Nicolas.
    "S'adapter, c'est vaincre" - Cellendhyll de Cortavar

  6. #6
    Modérateur
    Avatar de DotNetMatt
    Homme Profil pro
    CTO
    Inscrit en
    Février 2010
    Messages
    3 611
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : CTO
    Secteur : Finance

    Informations forums :
    Inscription : Février 2010
    Messages : 3 611
    Points : 9 743
    Points
    9 743
    Billets dans le blog
    3
    Par défaut
    Ok dans ce cas, tu as un bon bazar côté base de données ! L'idéal serait d'y mettre de l'ordre.

    En attendant, côté applicatif, tu peux jouer avec le niveau d'isolation de tes requêtes. Attention cependant car il y a quelques risques. Par défaut, lorsqu'une transaction est en cours, il y a donc un lock qui se fait sur les resources impliquées. L'objectif de ce lock est de s'assurer que plusieurs requêtes concurrentes ne viennent pas modifier la valeur en même temps, et que les lectures restent en attente jusqu'au déverrouillage afin de pouvoir ramener des infos à jour au client.

    Ca c'est l'isolation par défaut. En changeant le niveau d'isolation, supposons le scénario suivant :

    On lance une transaction A qui va mettre à jour la table CLIENTS. En même temps, ton application a besoin de lire des infos de cette table qui sont en train d'être mis à jour. Avec un niveau d'isolation plus permissif, ton appli pourra quand même exécuter sa requête, mais elle n'est pas sûre de récupérer les toutes dernières infos, celles qui sont en train d'être écrites par la transaction A.

    Cet exemple peut se produire si tu utilises le niveau Read uncommitted qui est le plus permissif.

    Entre les deux, tu peux utiliser Read Commited, qui dépend aussi du réglage de l'option READ_COMMITED_SNAPSHOT. Je te conseille de commencer avec ça. Ca devrait réduire les cas de lock. Si tu en as toujours trop, alors passe en isolation Read Uncommitted, en tenant compte de l'impact sur la consistance des données.

    Pour activer le Snapshot Isolation (voir aussi ça) :
    Code SQL : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    ALTER DATABASE <NomDeTaDB>
        SET READ_COMMITTED_SNAPSHOT ON;
    Pour activer Read Commited :
    Code SQL : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
    GO
    BEGIN TRANSACTION;
    GO
    SELECT Id, Name FROM Client;
    GO
    COMMIT TRANSACTION;
    GO
    Less Is More
    Pensez à utiliser les boutons , et les balises code
    Desole pour l'absence d'accents, clavier US oblige
    Celui qui pense qu'un professionnel coute cher n'a aucune idee de ce que peut lui couter un incompetent.

  7. #7
    Membre éprouvé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2006
    Messages
    436
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2006
    Messages : 436
    Points : 963
    Points
    963
    Par défaut
    Alors merci beaucoup pour ta réponse. Ca m'a permit de découvrir 2, 3 trucs

    J'ai mené qq investigations et le problème est finalement moins complexe que ce que je pensais.

    Tout d'abord, la procédure stockée de synchro ne dure jamais plus d'une minute.
    Et je crois m'être trompé sur le problème.

    Je vous remet le workflow séquentiel :

    - une modif est faites sur une donnée qu'on retrouve dans différentes bases.
    - un trigger fait une insertion dans une base contenant les infos en cours de synchro qui est contrôlé par un web services,
    - lorsque le webservices tombe sur des données dans la table, il s'occupe de faire un update sur l'autre base de données.

    Notre problème vient du fait que si on fait un update pendant que le script fait également un update, il n'y a pas de mise en attente de la requête d'update (pas celle de la synchro) mais directement un crash.

    Alors que si je fais un select * et non un update, ma requête est bien en attente et dès que je lance un COMMIT, l'application (client) se déverrouille aussi tôt et récupère le résultat de la requête.

    Pourquoi cela crash t il avec un update ? Le système de stack de mise en attente n'est-il pas le même ? Dois je gérer cette liste d'attente à la main ?

    N'hésitez pas à me faire savoir si ma réponse manque de clarté.

    Merci beaucoup !
    "S'adapter, c'est vaincre" - Cellendhyll de Cortavar

  8. #8
    Modérateur
    Avatar de DotNetMatt
    Homme Profil pro
    CTO
    Inscrit en
    Février 2010
    Messages
    3 611
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : CTO
    Secteur : Finance

    Informations forums :
    Inscription : Février 2010
    Messages : 3 611
    Points : 9 743
    Points
    9 743
    Billets dans le blog
    3
    Par défaut
    Difficile de te répondre, je ne suis pas un expert en base de données... Il faudrait déterminer précisément ce qui cause cette situation.

    Ce que tu peux faire c'est essayer de voir quels sont les locks en cours avant que la seconde instruction UPDATE n'arrive. Pour cela, tu peux utiliser SP_LOCK.

    Jette un oeil ici aussi : Locking Hints.

    Regarde aussi comment sont codées les instructions UPDATE et leur exécution. Il y a peut-être quelque chose de pas net à ce niveau.
    Less Is More
    Pensez à utiliser les boutons , et les balises code
    Desole pour l'absence d'accents, clavier US oblige
    Celui qui pense qu'un professionnel coute cher n'a aucune idee de ce que peut lui couter un incompetent.

  9. #9
    Membre éclairé Avatar de chamamo
    Profil pro
    Inscrit en
    Juin 2006
    Messages
    588
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2006
    Messages : 588
    Points : 735
    Points
    735
    Par défaut
    Essaie comme DotNetMatt l'as dit de jouer avec les niveaux d'isolation, j'avais un souci similaire sous Oracle, j'ai du passer de Serialisable à Read committed, mais ça peut être autre chose.

  10. #10
    Membre éprouvé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2006
    Messages
    436
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2006
    Messages : 436
    Points : 963
    Points
    963
    Par défaut
    Oki merci je vais faire avec ça et si je ne trouve pas, je gérerai la file d'attente à la main côté service web.

    Merci à vous deux pour votre aide ! (je marque comme résolu car si jamais j'ai un autre souci par la suite, je ferai un nouveau post)

    encore merci de vos réponses ! C'est très gentil.
    "S'adapter, c'est vaincre" - Cellendhyll de Cortavar

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Activé les transactions par le fournisseur OLE DB "SQLNCLI"
    Par kika10 dans le forum Administration
    Réponses: 4
    Dernier message: 06/01/2014, 16h39
  2. Comment appeler un service WCF en httpget? par url?
    Par 404error dans le forum ASP.NET
    Réponses: 4
    Dernier message: 03/09/2009, 22h54
  3. DLL Borland chargée par Windows: crash
    Par bocher dans le forum C++Builder
    Réponses: 2
    Dernier message: 08/01/2004, 13h09
  4. [Petite requête] Nombre de transactions par jour
    Par Braim dans le forum MS SQL Server
    Réponses: 2
    Dernier message: 15/04/2003, 11h53

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo