Καλώς ορίσατε στο dotNETZone.gr - Σύνδεση | Εγγραφή | Βοήθεια
σε

 

Αρχική σελίδα Ιστολόγια Συζητήσεις Εκθέσεις Φωτογραφιών Αρχειοθήκες

Διαχωρισμός database reads από database writes

Îåêßíçóå áðü ôï ìÝëïò cap. Τελευταία δημοσίευση από το μέλος than10 στις 13-07-2005, 13:29. Υπάρχουν 8 απαντήσεις.
Ταξινόμηση Δημοσιεύσεων: Προηγούμενο Επόμενο
  •  07-06-2005, 01:51 2530

    Διαχωρισμός database reads από database writes

    Μια και συζητάμε για transactions στα serviced components, να ρωτήσω κάτι που έχω ακούσει και παλαιότερα:

    Ακουω οτι είθισται, ειδικά σε components που εκτελούν database operations να διαχωρίζονται τα objects που κάνουν read από αυτά που κάνουν write στη database. Και εξηγούμαι:

    Αν κάτι κάνει read το οποίο ΔΕΝ προηγείται κάποιου insert/update/delete, π.χ. "δειξε μου τις τελευταίες 10 εγγραφές από τον πίνακα μπλαμπλα", τότε καλό ειναι να μπαίνει σε δικό του object, με TransactionOption.NotSupported ή Disabled.

    Ο,τι κάνει update/delete/insert να μπαίνει σε διαφορετικό object με TransactionOption.Supported ή Required ή RequiresNew.

    Αυτό για να μην "μπλέκονται" σε transactions πράγματα τα οποία δεν απαιτούν. Με αυτή τη λογική δεν μπορεί να έχει κανείς mapped ΕΝΑ object σε μια ονότητα που κάνει τη δουλειά, αλλά τουλάχιστον δύο. Ενα για read, ενα για write.

    Ισχύει; Αποτελεί δοκιμασμένη πρακτική (υπο προυποθέσεις; ) Ειναι κουταμάρα;

    Σωτήρης Φιλιππίδης

    DotSee Web Services

    View Sotiris Filippidis's profile on LinkedIn

    DotNetNuke them!
  •  07-06-2005, 02:58 2531 σε απάντηση της 2530

    Re: Διαχωρισμός database reads από database writes

    Έστω ότι έχεις ένα parent component που καλεί μία σειρά από άλλα components.  Κάποια είναι wirters και κάποια readers.

    To parent component έχει (ας πούμε) Required ή RequiresNew, οπότε με το καλημέρα ξεκινάει ένα transaction.  Και ας πούμε ότι οι wirters έχουν Supported ενώ οι readers έχουν NotSupported.  Όλα τα components είναι stateless, και όπου κάνεις access την βάση ανοίγεις ένα νέο connection (που στο δίνει από το pool), κάνεις αυτά που θες, και το κλείνεις όσο πιο γρήγορα μπορείς.

    Με το παραπάνω "setup" μπορεί να αντιμετωπίσεις τα εξής 2 προβλήματα:

    Πρόβλημα 1:

    [Ισως να το έχεις ήδη σκεφτεί, διότι μιλάς για reads που ΔΕΝ προηγούνται κάποιου insert/update.delete.]

    Γενικός κανόνας: αν μέσα σε ένα transaction χρησιμοποιείς πληροφορίες που παίρνεις από select (είτε για να παίρνεις αποφάσεις, είτε για να τις γράψεις σε άλλους πίνακες) τα select αυτά πρέπει να συμμετέχουν στο transaction, ούτως ώστε να διαβάζεις consistent πληροφορίες (τα λεγόμενα repeatable reads), και για να μην κάνεις τα data αχταρμά!  Για παράδειγμα:

    - Ξεκινάς το transaction "πώληση προϊόντος"
    - Διαβάζεις το πεδίο "stock" εκτός transaction: 10 τεμάχια
    - Κάνεις ότι κάνεις, και πας να κάνεις update στο stock με 9 (αφού πούλησες 1)
    - Κάποιος άλλος έχει ήδη πουλήσει άλλα 2, οπότε στην βάση έχει 8.
    - Εσύ γράφεις 9
    - Γεια σας!

    Αν όμως ο reader συμμετείχε στο transaction, με το που θα έκανε select, δεν θα μπορούσε κανείς να πειράξει αυτή την εγγραφή μέχρι να τελείωνε το transaction, οπότε και αν την ξαναδιάβαζες (πιο κάτω στον κώδικά σου) θα έβρισκες πάλι την τιμή 10, αλλά και αν πήγαινες να κάνεις update, δεν θα έσκιζες το consistency της βάσης σου.

    Πρόβλημα 2 (πιο ωραίο!):

    Το parent component καλεί τα εξής: writer1, reader1, writer2 και τελειώνει.  Ο writer1 κάνει update μία εγγραφή (έστω πάλι το stock), οπότε την κλειδώνει μέχρι να τελειώσει το transaction.  Έρχεται ο reader1 (που είναι εκτός transaction), πάει να την διαβάσει και... την βρίσκει κλειδωμένη!  Γεια σας!  Έκανες το μαγικό deadlock με τον εαυτό σου!

    Γενικά, λοιπόν, μου ακούγεται πολύ επικίνδυνο, άσε που δεν μπορώ να φανταστώ γιατί είναι χρήσιμο...  Βέβαια, είναι και 3 το πρωί, οπότε το μυαλό μου δεν είναι και στα φόρτε του... Smile

    Patrick
  •  07-06-2005, 11:15 2539 σε απάντηση της 2531

    Re: Διαχωρισμός database reads από database writes

    Πολύ δομημένη απάντηση. Εθιξες και άλλα θέματα, τα οποία είχα στο μυαλό μου, αλλα δεν μπήκα στη διαδικασία να ρωτήσω σε αυτό το στάδιο. Ευχαριστω!

    Ακριβώς αυτά τα προβλήματα είχα στο μυαλό μου όταν έλεγα "reads που ΔΕΝ συμμετέχουν σε οποιαδήποτε διαδικασία write". Μιλούσα μόνο για τα reads τα οποία είναι αυτόνομα και δεν συμμετέχουν σε λήψη αποφάσεων ούτε για να παρέχουν δεδομένα σε write operations. Σε αυτή την περίπτωση, από ο,τι καταλαβαίνω, έχει κάποιο νόημα να έχεις ξεχωριστά reader components.

    Π.χ. έχεις κάπου ένα query που κοιτάει την ημ/νία και την ώρα τελευταίας εγγραφής σε ένα πίνακα και ο σκοπός της ζωής του είναι να παρέχει στατιστικά στοιχεία στο UI. Ας πούμε οτι αυτό ΔΕΝ καλείται από πουθενά και από τίποτα άλλο παρά μονο για την παροχή των στατιστικών. Ακόμα και αν έχεις κάπου υλοποιημένο ένα object (ας πούμε - τελείως υποθετικά - οτι είναι κάποιος πίνακας μελών/πελατών/προσώπων που λέγεται "members"), καλό είναι να το "σπάσεις" σε δύο objects, οπου το ένα θα διαθέτει την μέθοδο getlastmember() ενώ το άλλο τις InsertMember(), UpdateMember() κλπ.

    Πολλοί, από ο,τι έχω δει, θα έβαζαν τη μέθοδο GetLastMember() εντός του ιδίου object με τις άλλες μεθόδους με αποτέλεσμα να συμμετέχει σε ενδεχόμενα transactions χωρίς να χρειάζεται.


    Σωτήρης Φιλιππίδης

    DotSee Web Services

    View Sotiris Filippidis's profile on LinkedIn

    DotNetNuke them!
  •  07-06-2005, 17:54 2556 σε απάντηση της 2539

    Re: Διαχωρισμός database reads από database writes

    Το LastChangeDate είναι στοιχείο ενός Object που φέρνει λίστες αντικειμένων και εκεί πρέπει να μπει. Πχ. CategoryListProvider. Μήπως όμως το χρησιμοποιείς για να χειριστείς το caching; οπότε είνα κάτι που πρέπει να το χειρίζονται εσωτερικά τα αντικείμενα;
    Για τα transactions όμως γιατί τα μπλέκεις τα πράγματα; έχει νόημα το object να ξέρει τι παέι να πει transaction; για δώσε παράδειγμα του object σου γιατί δεν πάει το μυαλό μου.
    Πες ότι έχεις object Payment το οποίο έχει πάνω του μια λίστα με PaymentDetails. Όταν πεις Payment.Create, θα πάρει τα δεδομένα η ρουτινούλα που υπάρχει από κάτω και θα ανοίξει εκείνη transaction για να τα βάλει όλα μαζί. [^o)]


    Χρήστος Γεωργακόπουλος
  •  08-06-2005, 00:00 2562 σε απάντηση της 2556

    Re: Διαχωρισμός database reads από database writes

    Ναι, όλα αυτά που ειπώθηκαν είναι σωστά. Αλλά, όταν μιλάμε για το ACID (Ατομικότητα, Συνέπεια, Απομόνωση & Διάρκεια) ενός transaction, θα πρέπει να λαμβάνουμε υπόψη μας ότι δεν μπορούμε να κάνουμε SELECT ή άλλα operations, database related ή μη, κατά την διάρκεια του. Τα resource managers και τα transactions monitors του COM+, δεν παρακολουθούν μόνο τα database operations, αν και πολύ θα τα θέλαμε.

    Το πρόβλημα μάλλον είναι, όχι να χωρίσουμε τα reader από τα writer operations, αλλά να εξασφαλίσουμε ότι τα transactions είναι απομονωμένα. Παραδείγματος χάρη, ένα serviced component που έχει μία μέθοδο, txExecuteSQL(sSQL, οConnection) και Requires Transaction, είναι μια πολύ καλή κλάση για να συμμετάσχει σε ένα transaction. Αν τώρα έχουμε ένα component που διαβάζει/γράφει από το δίσκο, διαβάζει από βάση, στέλνει email και μέσα σε όλα συμμετάσχει σε ένα transaction, μάλλον το μέγεθος του transaction δεν είναι αυτό που φανταζόμαστε, αλλά το μέγεθός του και το εύρος του έχει γίνει μεγάλο σαν ένα διήγημα επιστημονικής φαντασίας.

    George J.


    George J. Capnias: Χειροπρακτικός Υπολογιστών, Ύψιστος Γκουράρχης της Κουμπουτερολογίας
    w: capnias.org, t: @gcapnias, l: gr.linkedin.com/in/gcapnias
    dotNETZone.gr News
  •  16-06-2005, 12:12 2862 σε απάντηση της 2539

    Re: Διαχωρισμός database reads από database writes

     cap wrote:
    Ακριβώς αυτά τα προβλήματα είχα στο μυαλό μου όταν έλεγα "reads που ΔΕΝ συμμετέχουν σε οποιαδήποτε διαδικασία write". Μιλούσα μόνο για τα reads τα οποία είναι αυτόνομα και δεν συμμετέχουν σε λήψη αποφάσεων ούτε για να παρέχουν δεδομένα σε write operations. Σε αυτή την περίπτωση, από ο,τι καταλαβαίνω, έχει κάποιο νόημα να έχεις ξεχωριστά reader components.


    Hello ανύσηχοι ...
    Αυτά τα components πχ που κάνουν Reads για πχ reporting έχει νόημα να υλοποιηθούν σαν serviced components;
    Πάνος Αβραμίδης
  •  16-06-2005, 13:19 2864 σε απάντηση της 2862

    Re: Διαχωρισμός database reads από database writes

    Δεν φτιάχνουμε serviced components μόνο για το support των transactions.

    Υπάρχει το resource management. Ή αν ένα component χρειάζεται elevated privileges (administrator account) είναι πολύ πιο σωστό να γίνει serviced component για την προστασία του προγράμματος. Μην ξεχνάμε ότι τα component services είναι μέρος του application server του λειτουργικού συστήματος.


    George J.


    George J. Capnias: Χειροπρακτικός Υπολογιστών, Ύψιστος Γκουράρχης της Κουμπουτερολογίας
    w: capnias.org, t: @gcapnias, l: gr.linkedin.com/in/gcapnias
    dotNETZone.gr News
  •  16-06-2005, 15:17 2870 σε απάντηση της 2530

    Re: Διαχωρισμός database reads από database writes

    Thank you δάσκαλε με κάλυψες !!!


    Πάνος Αβραμίδης
  •  13-07-2005, 13:29 3455 σε απάντηση της 2530

    Re: Διαχωρισμός database reads από database writes

    Η καλύτερη λύση είναι να χωρίσουμε τα components σε read και write, βάζοντας τα read σε support transaction mode, και τα write σε requires ή require new. Αυτό θα έχει σαν αποτέλεσμα αν ενα read component κληθεί μόνο του να μην βρει κάποιο transaction (και να μην φτιάξει δικό του) οπότε να δουλεύει εκτός transaction, ενω αν κληθεί από ένα write να βρεί ένα έτοιμο transaction και να συμετέχει. Για τις περιπτώσεις write,read,write θα πρέπει να υπάρχει ένα top (write με require transaction) που θα ελέγχει την διαδικασία και θα έχει όλα τα βήματα υπό την σκέπη του δικού του transaction.

    Το μόνο πρόβλημα είναι ότι θέλεις δυο objects, ενα read, ενα write. Μπορείς όμως να χρησιμοποιείς το read σαν κύριο, και με την σειρά του να περνά τις αιτήσεις στο write όταν χρειάζεται.

    Παράδειγμα:
    το readobj object έχει τις μεθόδους και support transaction mode
     readrec
     dojob
    το writeobj object έχει τις μεθόδους και required transaction mode
     dojob
     update1
     update2

    Όπου η dojob κάνει update1, readrec, update2

    Η εφαρμογή βλέπει μόνο το readobj.
    Όταν καλέσει την μέθοδο readrec τοτέ εκτελειται χωρίς transaction.
    Όταν καλέσει την μέθοδο dojob, το readobj την περνά αυτούσια στο writeobj που δημιουργεί ένα transaction. Στην συνέχεια η dojob καλέι την update1, την readrec από ένα νέο readobj (που συμετέχει ποια στο transaction), και την update2.

    Αυτή η μέθοδος έχει το μειονέκτημα ότι απαιτεί την δημιουργία ένος ή δύο παραπάνω objects, αλλά το COM+ υποτίθεται ότι κάνει αυτή την διαδικασία γρήγορη.

Προβολή Τροφοδοσίας RSS με μορφή XML
Με χρήση του Community Server (Commercial Edition), από την Telligent Systems