Προς το περιεχόμενο

Προτεινόμενες αναρτήσεις

Δημοσ.

Αν και τη δουλεύω εδώ και μερικά χρόνια, βρίσκω την αφεντιά μου αρχάρια στην Javascript.

 

Έχω μια Javascript εφαρμογή, η οποία χρησιμοποιεί το OpenLayers. Προβάλλω διάφορα συμβάντα στο χάρτη, που ενημερώνονται από μια περίπλοκη Βάση Δεδομένων γραμμένη σε MySQL. Ο χρήστης μπαίνει σε έναν web server που συνδέεται με τη ΒΔ και φυσικά λαμβάνει μια ιστοσελίδα που συμπεριλαμβάνει Javascript, η οποία κάνει όλη την ωφέλιμη δουλειά.

 

Αυτή η εφαρμογή, μέσω AJAX (για την ακρίβεια, με το OpenLayers API που χρησιμοποιεί AJAX) διαβάζω ένα αρχείο .PHP από έναν web server. Το PHP αρχείο περιέχει μέσα του ένα έτοιμο MySQL query, οπότε αυτό που επιστρέφεται πίσω είναι το αποτέλεσμα του query, οργανωμένο σε JSON μορφή (με γεωγραφικά και θεματικά δεδομένα που το OpenLayers απεικονίζει natively).

 

Πρώτα δηλαδή γίνεται το τρέξιμο της PHP και του query, μόλις το query δώσει αποτελέσματα, τα μορφοποιεί η PHP σε JSON και κατόπιν το JSON σερβίρεται πίσω σαν απόκριση στην κλήση AJAX από την Javascript του κάθε χρήστη. 

 

Το κωδικάκι μου σε Javascript παίρνει το περιεχόμενο του JSON και φτιάχνει τα δικά του, δηλ. απεικονίζει τη γεωγραφική κατανομή της πληροφορίας που πήρε από την ΒΔ. Η ανανέωση που ζητά το AJAX είναι σχετικά συχνή, περίπου ανά λεπτό.

 

Αυτή η διαδικασία είναι πολύ βολική, διότι το σκεπτικό είναι να έχω όσο το δυνατόν real-time εμφάνιση συμβάντων πάνω στο χάρτη. Με το που γινόταν ένα συμβάν π.χ. στην Αττική, η ΒΔ κάνει update μέσα σε λίγα λεπτά το πολύ. Οπότε με το να έχω ανά λεπτό κλήσεις από το Javascript/AJAX, ο χρήστης πληροφορείται με μικρή καθυστέρηση το συμβάν. Επίσης, πολλοί χρήστες υποβάλλουν τιμές σε μεταβλητές PHP (π.χ. συντεταγμένες) κι έτσι το κάθε query αποκτά μικρές παραλλαγές.

 

Ωστόσο το MySQL query τελικά έχει γίνει αρκετά εκτεταμένο (SELECT με INNER JOIN ανάμεσα σε 8-10 πίνακες που σχηματίζονται από subqueries), ενώ και η βάση δεδομένων έχει γίνει αρκετά μεγάλη σε εγγραφές. Κάθε query κρατάει Tquery ~ 35-40 δευτερόλεπτα. Έτσι η ιστοσελίδα "παγώνει" για λίγο και υστερεί και σε λειτουργικότητα, διότι θα πρέπει να ολοκληρωθεί το query για να σχηματιστεί η απόκριση. Φυσικά θέλω αυτό το "πάγωμα" να εξαφανιστεί.

 

Έχω για αυτό μερικές ιδέες:

 

(1) Μια λύση προφανής είναι η χρονική βελτιστοποίηση του query. Αυτή, ας πούμε, εξαντλήθηκε.

 

(2) Μια άλλη λύση που σκέφτηκα είναι το AJAX να κάνει κλήση όχι σε ένα PHP αρχείο, όπως τώρα, αλλά σε ένα plain JSON αρχείο, το οποίο θα ανανεώνει η ΒΔ με δικό της χρονοπρογραμματισμό.

 

Δηλαδή, να έχω ένα crontab στο Λ/Σ ή event scheduler στην ΒΔ (είχα ανοίξει και σχετικό θέμα) που να κάνει μόνο του το μακροσκελές query ανά τακτά διαστήματα ((ΔΤ)ΒΔ~1 ή 2 λεπτά) και να γράφει το αποτέλεσμα σε ένα κανονικό αρχείο .json, ενώ παράλληλα η Javascript να κάνει κλήσεις μέσω AJAX στο αρχείο αυτό όπως πριν, π.χ. ανά λεπτό ((Δτ)AJAX~1 λεπτό). Κατ' αυτή τη διαδικασία, αν και το καθεαυτό query μπορεί να κάνει μερικά λεπτά (Tquery), το αποτέλεσμά του θα είναι διαθέσιμο πολύ γρήγορα (ΔΤ)ΒΔ από όλους τους χρήστες.

 

Ο κύριος προβληματισμός μου είναι αν μπορεί να συμβεί κάποιο conflict. Σίγουρα η εγγραφή ενός αρχείου (400-500 KB ως 1-2 MB) με αποτελέσματα ενός query από την MySQL είναι πιο γρήγορη από την εκτέλεση του PHP κώδικα που δίνει το ίδιο αποτέλεσμα του query. Ωστόσο δεν ξέρω αν τη στιγμή της εγγραφής πάει το Javascript/AJAX και ζητήσει το μισογραμμένο - εκείνη τη στιγμή - αρχείο. Τι γίνεται τότε; Πώς ασφαλίζω το «υπό κατασκευή» αρχείο;

 

Επίσης με προβληματίζει μήπως την ώρα που ολοκληρώνεται ένα event, πέσω επάνω στην έναρξη του επόμενου event. Δηλαδή, ένα query να κρατήσει τόσο, ώστε πριν βγάλει αποτελέσματα, να έχει ξεκινήσει ήδη το επόμενο. Είναι πολύ δύσκολο, ειδικά αν τηρήσω βέλτιστη χρονική απόσταση μεταξύ των event, το δεύτερο query να καπελώσει το πρώτο, αλλά δεν ξέρω πώς να το χειριστώ σε μια απίθανη τέτοια εκδοχή.

 

Και τέλος, όπως φαίνεται, θυσιάζω κάποια στοιχεία customization του query.

 

Θέλω τα σχόλιά σας πάνω στους προβληματισμούς μου αλλά και γενικά πάνω στη στρατηγική που μεταχειρίζομαι πάνω στο πρόβλημα.

Δημοσ.

Πρώτα απ' όλα συγχαρητήρια που έκατσες και έγραψες τόσο κατατοπιστικό post.
 

(1) Μια λύση προφανής είναι η χρονική βελτιστοποίηση του query. Αυτή, ας πούμε, εξαντλήθηκε.


Δυσκολεύομαι πάρα μα πάρα πολύ να το πιστέψω, 35-40 δευτερόλεπτα είναι άπειρος χρόνος. Δεδομένου ότι αυτή η βελτιστοποίηση είναι ο ευκολότερος τρόπος να πάρεις πρακτικό αποτέλεσμα πιστεύω πως πρέπει να το ψάξεις περισσότερο σε επίπεδο db.
 

Ο κύριος προβληματισμός μου είναι αν μπορεί να συμβεί κάποιο conflict. Σίγουρα η εγγραφή ενός αρχείου (400-500 KB ως 1-2 MB) με αποτελέσματα ενός query από την MySQL είναι πιο γρήγορη από την εκτέλεση του PHP κώδικα που δίνει το ίδιο αποτέλεσμα του query. Ωστόσο δεν ξέρω αν τη στιγμή της εγγραφής πάει το Javascript/AJAX και ζητήσει το μισογραμμένο - εκείνη τη στιγμή - αρχείο. Τι γίνεται τότε; Πώς ασφαλίζω το «υπό κατασκευή» αρχείο;


Δεν υπάρχει κανένα πρόβλημα, το γράφεις π.χ. με file_put_contents και δίνεις LOCK_EX για την τρίτη παράμετρο.
 

Επίσης με προβληματίζει μήπως την ώρα που ολοκληρώνεται ένα event, πέσω επάνω στην έναρξη του επόμενου event. Δηλαδή, ένα query να κρατήσει τόσο, ώστε πριν βγάλει αποτελέσματα, να έχει ξεκινήσει ήδη το επόμενο. Είναι πολύ δύσκολο, ειδικά αν τηρήσω βέλτιστη χρονική απόσταση μεταξύ των event, το δεύτερο query να καπελώσει το πρώτο, αλλά δεν ξέρω πώς να το χειριστώ σε μια απίθανη τέτοια εκδοχή.


Εξαρτάται από το πώς γίνεται το AJAX ακριβώς. Γενικά είτε θα κάνεις abort τυχόν προηγούμενο request (κάπου θα σημειώνεις το "τρεχον" όταν ξεκινάει και θα το ξεχνάς όταν ολοκληρωθεί) πριν ξεκινήσεις το επόμενο, ή response versioning.
 

Μια άλλη τεχνική που αξίζει να σκεφτείς για να μειώσεις το φόρτο είναι το ενδεχόμενο (δεν ξέρω αν γίνεται στην περίπτωσή σου) να παράγεις κάθε κάποιο μεγαλύτερο χρονικό διάστημα ένα dataset (π.χ. κάθε 1 ώρα) και να εξυπηρετείς τα queries παίρνοντας αποτελέσματα από το dataset αυτό συν (κάπως παντρεύοντάς το κατάλληλα) με ένα μικρότερο dataset που προκύπτει από τα δεδομένα μόνο της τελευταίας ώρας. Δε μπορώ να γίνω πιο συγκεκριμένος αλλά είναι μια ιδέα.

 

Τέλος, αυτό που λες με το JSON cache είναι το λεγόμενο memcached του φτωχού. Ίσως σ' ενδιαφέρει να δεις το κανονικό memcached.

Δημοσ.

@mad-proffessor:

Δεν έχω υλοποιήσει τη δεύτερη λύση ακόμη, αλλά προτείνεις να κάνει η php την δημιουργία του json αρχείου;

 

Να διευκρινίσω ότι αυτή τη στιγμή, το AJAX κάνει κλήση σε ένα αρχείο .PHP και το response λαμβάνει JSON.

var protocol= new OpenLayers.Protocol.HTTP({
                            url: "http://web.server.my/getmydata.PHP",
                            async: true,
                            handleResponse: function(r) {
                                var x=r.priv.responseText;
                                var j=new OpenLayers.Format.JSON(...);
                                layer.addFeatures(j.read(x)); }
});


Τέλος, αυτό που λες με το JSON cache είναι το λεγόμενο memcached του φτωχού. Ίσως σ' ενδιαφέρει να δεις το κανονικό memcached.

 

Ευχαριστώ για τα καλά λόγια. Δεν είναι ότι δεν ξέρω προγραμματισμό, δεν ξέρω - ας το πω έτσι - τεχνικές, το πώς να ενσωματώνω καινούργια στοιχεία.

Έτσι, αυτό που αναφέρεις "memcached του φτωχού" δεν το είχα καν υπόψη, ούτε συνειδητοποιούσα ότι κάνω caching. Αν το memcache δουλεύει από την μεριά του server, ασφαλώς και είναι πολύ ενδιαφέρον. 

 

(Στην βελτιστοποίηση της ΒΔ, μπορώ να ανοίξω άλλη τόση συζήτηση, αλλά καλύτερα ένα-ένα κι από λίγο τα ζητήματα. Με ενδιαφέρει να παίρνω ιδέες και να μαθαίνω λεπτομέρειες, τεχνικές κλπ. και νομίζω ότι αυτό μπορώ να το κάνω εδώ στο φόρουμ. Το να αραδιάσω όλα τα προβλήματά μου και να ζητάω από τους άλλους εμμέσως να μου κάνουν τη δουλειά, ενώ μου είναι μεγάλος πειρασμός, δεν θα βρει προφανώς ανταπόκριση).

Δημοσ.

Ποιος άλλος θα τη κάνει;

Για γεωγραφικά δεδομένα η postgres είναι καλύτερη(πάντως σίγουρα είναι πιο ασφαλής) απο mysql που είναι σαφώς πιο απλή και εύκολη. Τώρα αμα κάνεις ερωτημα σε τόσους πίνακες  σίγουρα ή πρέπει να κάνεις βελτιστοποίηση ή αλλαγη στο σχήμα.

 Πάντως αξίζει αυτο που σου λέει ο defacer παραπάνω

 

 

Μια άλλη τεχνική που αξίζει να σκεφτείς για να μειώσεις το φόρτο είναι το ενδεχόμενο (δεν ξέρω αν γίνεται στην περίπτωσή σου) να παράγεις κάθε κάποιο μεγαλύτερο χρονικό διάστημα ένα dataset (π.χ. κάθε 1 ώρα) και να εξυπηρετείς τα queries παίρνοντας αποτελέσματα από το dataset αυτό συν (κάπως παντρεύοντάς το κατάλληλα) με ένα μικρότερο dataset που προκύπτει από τα δεδομένα μόνο της τελευταίας ώρας. Δε μπορώ να γίνω πιο συγκεκριμένος αλλά είναι μια ιδέα.

 

ή να κάνεις cache στη βάση

Δημοσ.

Στη ΒΔ υπάρχουν κάποιες ιδιαιτερότητες, π.χ. δεν μπορώ να ξεφύγω από mysql. Αυτή τη στιγμή έχω έναν μικρότερο πίνακα που χρησιμοποιώ σαν cache με ξένα κλειδιά στους μεγάλους, οπότε αν έχω π.χ. 100 πρόσφατα συμβάντα θα γίνει query πρώτα στο μικρό πίνακα και μετά στον μεγάλο. Τα μεσοδιαστήματα λήψεως μπορούν να αλλάξουν ακόμη και σε 2-3 λεπτά, αλλά το ιδανικό είναι το ASAP.

 

Η λύση με τα delta των datasets είναι η καλύτερη δυνατή, αλλά πρέπει να βρω έναν τρόπο να "θυμάμαι" τι έχω ήδη στείλει στον κάθε χρήστη, οπότε και να αποκρίνεται μόνο με ό,τι όντως άλλαξε και να μην ξαναστέλνει όλο το dataset σαν απόκριση. Δηλαδή πρέπει να αποθηκεύω καταστάσεις από κάθε χρήστη, ή ώρα τελευταίας ενημέρωσης και τελευταίας γεωγραφικής περιοχής.

 

Επίσης, αυτό πρέπει αυτό να περάσει στα OpenLayers μεταβάλλοντας μόνο το ένα feature που πρέπει.

 

Αν βρω κάτι αριστοτεχνικό, θα το εφαρμόσω αναμφισβήτητα.

Δημιουργήστε ένα λογαριασμό ή συνδεθείτε για να σχολιάσετε

Πρέπει να είστε μέλος για να αφήσετε σχόλιο

Δημιουργία λογαριασμού

Εγγραφείτε με νέο λογαριασμό στην κοινότητα μας. Είναι πανεύκολο!

Δημιουργία νέου λογαριασμού

Σύνδεση

Έχετε ήδη λογαριασμό; Συνδεθείτε εδώ.

Συνδεθείτε τώρα
  • Δημιουργία νέου...