OpenAI

2 Νοεμβρίου 2026

Μηχανική

Κλιμακώνοντας το Git στην OpenAI

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

Από τους Aaron Friel, Taylor Blau και Ted Nyman, μέλη του τεχνικού προσωπικού

Φόρτωση…

Τον τελευταίο χρόνο, το μέγεθος του ενιαίου αποθετηρίου μας και οι απαιτήσεις από αυτό έχουν αυξηθεί με εντυπωσιακό ρυθμό. Ήταν σαφές ότι έπρεπε να ανασχεδιάσουμε το σύστημα ελέγχου εκδόσεων κώδικα, ώστε να ανταποκρίνεται στην κλίμακα ταυτόχρονης εργασίας που καθιστά δυνατή το Codex.

Δημιουργήσαμε το Pando, ένα νέο backend για αποθετήρια Git, χωρίς να διακόψουμε καμία εργασία ανάπτυξης ή να αλλάξουμε τον τρόπο με τον οποίο η ομάδα μας χρησιμοποιεί το Git. Το Pando υποστηρίζει πλέον όλη την ανάπτυξη στο ενιαίο αποθετήριο της OpenAI. Το Pando σχεδιάστηκε για να πετύχει δύο φιλόδοξους στόχους: πρώτον, οριζόντια κλιμακούμενες εγγραφές, βελτιστοποιημένες για ταυτόχρονα push σε πολλούς κλάδους. Και δεύτερον, μέγιστη ρυθμαπόδοση ανάγνωσης, ώστε οι πελάτες να κατεβάζουν δεδομένα αρκετά γρήγορα για να αξιοποιούν πλήρως το διαθέσιμο εύρος ζώνης του δικτύου τους.

Πετύχαμε αυτούς τους στόχους διατηρώντας τη συμβατότητα με το πρωτόκολλο και τον πελάτη Git, επιτρέποντας στους μηχανικούς και τους πράκτορές μας να ενσωματώσουν ομαλά το Pando στις υπάρχουσες ροές εργασίας τους. Στο περιβάλλον παραγωγής, το Pando μείωσε τη διάμεση καθυστέρηση των push σχεδόν στο ένα πέμπτο. Πλέον διανέμει σχεδόν ένα petabyte δεδομένων Git την ημέρα.

Εδώ θα παρουσιάσουμε τους λόγους που μας οδήγησαν να δημιουργήσουμε ένα νέο σύστημα ελέγχου εκδόσεων κώδικα και να διατηρήσουμε τη συμβατότητα με το Git. Θα συγκρίνουμε το σύστημά μας με συνήθεις προσεγγίσεις κλιμάκωσης του Git, εξηγώντας γιατί το Pando είναι μοναδικά κατάλληλο να καλύψει τις ανάγκες κλιμάκωσης της OpenAI. Θα συζητήσουμε επίσης τα επόμενα βήματα και πώς θα συνεχίσουμε να συνεισφέρουμε στο Git, ώστε να υποστηρίζει εργασία στην κλίμακα των πρακτόρων.

Γιατί χρειαζόμασταν νέο σύστημα ελέγχου εκδόσεων κώδικα

Το Codex έχει αλλάξει την κλίμακα και τον ρυθμό ανάπτυξης στην OpenAI, επιτρέποντας στους μηχανικούς να εκτελούν πολύ περισσότερες εργασίες παράλληλα. Αυτό σημαίνει περισσότερους κλάδους και push, περισσότερες συγχωνεύσεις και περισσότερα fetch και clone από περιβάλλοντα ανάπτυξης, ερευνητικές εργασίες και συστήματα συνεχούς ενσωμάτωσης (CI).

Αυτές οι απαιτήσεις πολλαπλασιάζονται. Ένας μηχανικός έχει πλέον πολλές αλλαγές έτοιμες για CI ταυτόχρονα και κάθε push μπορεί να ενεργοποιεί πολλές εργασίες που ανακτούν το ίδιο commit.

Από τα τέλη περίπου του περασμένου έτους, τα συστήματα που υποστήριζαν το ενιαίο αποθετήριό μας δυσκολεύονταν να ανταποκριθούν. Αντιμετωπίζαμε αργά fetch και push, καθώς και αποτυχημένες συγχωνεύσεις, με την αξιοπιστία να πέφτει κατά διαστήματα κάτω από το 90%. Είχαμε φτάσει στα όρια του ίδιου του Git ή του τρόπου με τον οποίο εξυπηρετούσαμε το ενιαίο αποθετήριό μας; Το Git γεννήθηκε μέσα από μια κοινότητα που αντάλλασσε μέσω email ενημερώσεις κώδικα για τον πυρήνα. Για περισσότερες από δύο δεκαετίες, οι προγραμματιστές προσαρμόζουν τα εργαλεία τους γύρω από το Git, καθώς αλλάζει ο τρόπος με τον οποίο αναπτύσσουν λογισμικό. Όταν άρχισαν να εμφανίζονται δυσκολίες στο δικό μας ενιαίο αποθετήριο, ήταν σημαντικό για εμάς να συνεχίσουμε να βασιζόμαστε σε αυτή τη δουλειά.

Είδαμε έναν τρόπο να διατηρήσουμε αυτή τη γνώριμη ροή εργασίας, ανασχεδιάζοντας το backend ώστε να χειρίζεται παράλληλα push σε διαφορετικούς κλάδους και να παρέχει το ίδιο ιστορικό ταυτόχρονα σε πολλούς πελάτες ανάγνωσης. Με το Git ως βάση της ροής εργασίας μας για τον έλεγχο εκδόσεων κώδικα, οι βελτιώσεις στον πελάτη θα μπορούσαν να είναι χρήσιμες και εκτός OpenAI. Θέλαμε να συνεισφέρουμε αυτές τις βελτιώσεις από το δικό μας αντίγραφο του Git⁠(ανοίγει σε νέο παράθυρο) στο κύριο έργο, μοιράζοντάς τες με την ευρύτερη κοινότητα.

Σχεδιάζοντας το Git για μεγάλη κλίμακα

Η κλιμάκωση ενός συστήματος ελέγχου εκδόσεων κώδικα έχει δύο βασικές διαστάσεις: πολλούς πελάτες εγγραφής που κάνουν push σε διαφορετικούς κλάδους και πολλούς πελάτες ανάγνωσης που ανακτούν το ίδιο ιστορικό. Το Pando βελτιστοποιεί και τις δύο.

Πρώτον, το Pando συντονίζει ανεξάρτητα τις ενημερώσεις κάθε κλάδου. Οι ενημερώσεις σε ανεξάρτητους κλάδους μπορούν να προχωρούν παράλληλα και ένας πελάτης που ανακτά έναν κλάδο λαμβάνει το ιστορικό που χρειάζεται για τη συγκεκριμένη έκδοση. Ο συμβιβασμός είναι ότι ένας πελάτης που διαβάζει πολλούς κλάδους μπορεί να τους δει σε διαφορετικές χρονικές στιγμές.

Δεύτερον, το Pando επαναχρησιμοποιεί packfile (τη μορφή του Git για τη συμπίεση πολλών αντικειμένων μαζί) μεταξύ διαφορετικών fetch, αντί να δημιουργεί ξεχωριστό packfile για κάθε πελάτη. Ένας πελάτης μπορεί να κατεβάσει ορισμένα αντικείμενα που ήδη έχει, αλλά ο διακομιστής μπορεί να παρέχει τα ίδια byte σε πολλούς πελάτες με ελάχιστους υπολογισμούς.

Αυτές οι επιλογές μάς επιτρέπουν να κλιμακώνουμε τις εγγραφές σε πολλούς κλάδους και να εξυπηρετούμε αναγνώσεις από κρυφές μνήμες. Για να δούμε πώς συνδυάζονται, ας ξεκινήσουμε από τον τρόπο με τον οποίο το Git αποθηκεύει και μεταφέρει το ιστορικό.

Εισαγωγή στην αποθήκευση αντικειμένων του Git

Το Git πρέπει να διατηρεί συγχρονισμένα δύο μέρη ενός αποθετηρίου: τα αντικείμενα και τις αναφορές.

Ένα αποθετήριο Git καταγράφει στιγμιότυπα αρχείων και το ιστορικό που τα συνδέει ως γράφο αντικειμένων. Ένα αντικείμενο μπορεί να είναι blob, δέντρο, commit ή ετικέτα. Τα blob περιέχουν το περιεχόμενο ενός μεμονωμένου αρχείου, ενώ τα δέντρα αντιστοιχίζουν ονόματα σε blob ή άλλα δέντρα, σχηματίζοντας μια δομή καταλόγων. Τα commit δείχνουν σε ένα ριζικό δέντρο και σε μηδέν ή περισσότερα γονικά commit, σχηματίζοντας το ιστορικό του αποθετηρίου σας.

Τα αντικείμενα ταυτοποιούνται από μια τιμή κατακερματισμού του τύπου και του περιεχομένου τους. Τα αντικείμενα είναι επίσης αμετάβλητα: η καταγραφή ενός τροποποιημένου αρχείου δημιουργεί νέο blob, ενώ τα αμετάβλητα αρχεία και οι κατάλογοι μπορούν να επαναχρησιμοποιούν υπάρχοντα αντικείμενα.

Οι κλάδοι και οι ετικέτες είναι αναφορές, ή «refs», που δείχνουν σε commit. Η εκτέλεση commit σε έναν κλάδο δημιουργεί νέο commit και ενημερώνει την αναφορά του κλάδου ώστε να δείχνει σε αυτό.

Ο κλάδος refs/heads/main δείχνει στο commit C2, του οποίου γονέας είναι το C1. Το C1 δείχνει στο ριζικό δέντρο T1, όπου το parser.py παραπέμπει στο blob B1. Το C2 δείχνει στο ριζικό δέντρο T2, όπου το parser.py παραπέμπει στο blob B2. Και στα δύο ριζικά δέντρα, το docs/ παραπέμπει στο ίδιο δέντρο, το T3. Η καταχώρισή του README.md δείχνει στο blob B3 και η usage.md στο blob B4.

Τα αντικείμενα Git παραπέμπουν το ένα στο άλλο μέσω του αναγνωριστικού τους: τα commit σε δέντρα και τα δέντρα σε άλλα δέντρα και blob. Ο κλάδος refs/heads/main δείχνει στο commit C2, του οποίου γονέας είναι το C1. Το C1 δείχνει στο ριζικό δέντρο T1, όπου το parser.py παραπέμπει στο blob B1. Το C2 δείχνει στο ριζικό δέντρο T2, όπου το parser.py παραπέμπει στο blob B2. Και στα δύο ριζικά δέντρα, το docs/ παραπέμπει στο ίδιο δέντρο, το T3. Η καταχώρισή του README.md δείχνει στο blob B3 και η usage.md στο blob B4.

Το Git αποθηκεύει τα αντικείμενα είτε «μεμονωμένα» είτε «συσκευασμένα». Τα μεμονωμένα αντικείμενα αποθηκεύονται σε ξεχωριστά αρχεία που ταυτοποιούνται από το αναγνωριστικό του αντικειμένου τους. Τα συσκευασμένα αντικείμενα αποθηκεύονται μαζί σε ένα packfile, επιτρέποντας την αποθήκευση παρόμοιων αντικειμένων ως διαφορών μεταξύ τους.

Δύο εκδόσεις του parser.py εμφανίζονται κάτω από το $GIT_DIR/objects . Ως μεμονωμένα αντικείμενα, το blob A περιέχει τη parse() και το blob B περιέχει τις parse() και parse_file(). Το packfile αποθηκεύει ολόκληρο το A και αναπαριστά το B ως οδηγίες αντιγραφής ολόκληρου του A και προσθήκης της parse_file(). Το συνοδευτικό αρχείο *.idx εντοπίζει και τα δύο blob στο packfile με βάση το αναγνωριστικό αντικειμένου.

Το Git μπορεί να αποθηκεύει τα blob ως ξεχωριστά αρχεία ή να τα συσκευάζει μαζί, κωδικοποιώντας ένα blob ως διαφορά σε σχέση με ένα άλλο.

Στο Git, ένα αντικείμενο είναι προσβάσιμο από ένα commit αν το Git μπορεί να το βρει ακολουθώντας συνδέσμους από αυτό το commit μέσω των γονικών commit, των δέντρων και των blob. Κατά το fetch, ο πελάτης δηλώνει στον διακομιστή ποια commit θέλει και ποια ήδη έχει. Ο διακομιστής βρίσκει τα αντικείμενα που είναι προσβάσιμα από τα ζητούμενα commit, εξαιρεί όσα γνωρίζει ότι ο πελάτης ήδη έχει και στέλνει τα υπόλοιπα ως packfile, στην ίδια μορφή που χρησιμοποιεί το Git στον δίσκο. Ένα πλήρες clone ξεκινά χωρίς κανένα αντικείμενο, οπότε χρειάζεται όλα τα αντικείμενα που είναι προσβάσιμα από το ιστορικό που κλωνοποιείται.

Το push μεταφέρει αντικείμενα προς την αντίθετη κατεύθυνση, ζητώντας από τον διακομιστή να ενημερώσει μία ή περισσότερες αναφορές. Ο πελάτης χρησιμοποιεί το σύνολο των αναφορών που ανακοινώνει ο διακομιστής για να αποφύγει την αποστολή αντικειμένων που ο διακομιστής ήδη διαθέτει. Το πακέτο που αποστέλλεται μπορεί επομένως να εξαρτάται από υπάρχοντα αντικείμενα: η λήψη του πακέτου από μόνη της δεν αρκεί για την ανασύνθεση του νέου ιστορικού.

Η δημιουργία αντιγράφων ενός αποθετηρίου Git σημαίνει ότι διατηρούνται διαθέσιμα τόσο τα αντικείμενα όσο και οι αναφορές σε πολλούς διακομιστές. Πριν ένα αντίγραφο μπορέσει να εξυπηρετήσει τη νέα τιμή μιας αναφοράς, πρέπει να μπορεί να παρέχει τα αντικείμενα που είναι προσβάσιμα από αυτή την τιμή. Η υπηρεσία πρέπει επίσης να συντονίζει ανταγωνιστικές ενημερώσεις αναφορών, δηλαδή push που προσπαθούν να μετακινήσουν τον ίδιο κλάδο από την ίδια παλιά κορυφή σε διαφορετικά νέα commit. Τα συστήματα που επιβάλλουν μία κοινή σειρά σε όλες τις εγγραφές ενός αποθετηρίου μπορεί να αναγκάζουν τα push σε ανεξάρτητους κλάδους να περιμένουν το ένα το άλλο.

Υπάρχοντα πρότυπα κατανεμημένων υπηρεσιών Git

Κατά τον σχεδιασμό του Pando, αξιολογήσαμε συμβατικές προσεγγίσεις κλιμάκωσης του ελέγχου εκδόσεων κώδικα με το Git: μία που συντονίζει τις ενημερώσεις αναφορών μεταξύ αντιγράφων του αποθετηρίου μέσω οριστικοποίησης τριών φάσεων (3PC, πρωτόκολλο συντονισμού μιας οριστικοποίησης σε πολλούς κόμβους) και μία που διατάσσει τις ενημερώσεις μέσω ενός κοινού αρχείου καταγραφής προεγγραφής (WAL, καταγραφή αλλαγών πριν εφαρμοστούν) σε χώρο αποθήκευσης blob.

Οριστικοποίηση τριών φάσεων (3PC)

Στον σχεδιασμό οριστικοποίησης τριών φάσεων που μοντελοποιήσαμε, η υπηρεσία Git διατηρεί πλήρες αντίγραφο του αποθετηρίου σε πολλούς κόμβους αντιγράφων. Όταν οποιοσδήποτε διακομιστής λαμβάνει ένα push, το εισερχόμενο packfile αντιγράφεται και αποστέλλεται παράλληλα σε όλα τα αντίγραφα. Για να δημοσιευτεί το push, η πλειονότητα των αντιγράφων πρέπει να αποδεχτεί την ενημέρωση της αναφοράς. Ο διακομιστής που διαχειρίζεται αυτή τη διαδικασία είναι ο συντονιστής και απαιτούνται πολλοί γύροι επικοινωνίας μεταξύ αυτού και κάθε άλλου αντιγράφου.

Για να αποδεχτεί μια ενημέρωση αναφοράς, κάθε αντίγραφο κλειδώνει το δικό του αντίγραφο της αναφοράς και ελέγχει ότι εξακολουθεί να δείχνει στο commit που αναμένει ο πελάτης. Ο συντονιστής στέλνει έπειτα ένα μήνυμα προ-οριστικοποίησης στα αντίγραφα που αποδέχονται την ενημέρωση. Μόλις η πλειονότητα επιβεβαιώσει το μήνυμα προ-οριστικοποίησης, ο συντονιστής δίνει εντολή να εκτελέσουν την ενημέρωση. Στη συνέχεια, οποιοδήποτε ενημερωμένο αντίγραφο μπορεί να ανακοινώσει τη νέα κορυφή του κλάδου από το τοπικό του αντίγραφο του αποθετηρίου.

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

Η αναμονή για απαρτία καθιστά την απόδοση των δίσκων των αντιγράφων και την καθυστέρηση επικοινωνίας μέρος της κρίσιμης διαδρομής του push. Καθώς αυξάνεται ο όγκος εγγραφών, τα αντίγραφα πρέπει να ανταποκρίνονται τόσο στα εισερχόμενα πακέτα όσο και στην κίνηση ανάγνωσης.

Αρχείο καταγραφής προεγγραφής (WAL)

Στον σχεδιασμό με βάση το WAL που μοντελοποιήσαμε, η υπηρεσία Git χρησιμοποιεί ένα κοινό manifest σε χώρο αποθήκευσης blob για να ορίζει τη σειρά των ενημερώσεων σε όλο το αποθετήριο. Για να δημοσιεύσει το push, προσθέτει στο κοινό manifest του χώρου αποθήκευσης blob μια καταχώριση που καταγράφει την ενημέρωση της αναφοράς και δείχνει στο packfile. Ο διακομιστής Git ενημερώνει έπειτα το manifest με μια λειτουργία σύγκρισης και ανταλλαγής. Αυτή είτε αντικαθιστά ατομικά το manifest είτε απορρίπτει την αλλαγή. Αν ένας άλλος πελάτης εγγραφής την έχει ενημερώσει στο μεταξύ, ο διακομιστής διαβάζει τις ενδιάμεσες καταχωρίσεις, ελέγχει ότι η ενημέρωση της αναφοράς του παραμένει έγκυρη και επαναλαμβάνει την προσπάθεια με το packfile που έχει ήδη ανεβάσει.

Οι πελάτες εγγραφής μπορούν να ανεβάζουν παράλληλα τα packfile τους, αλλά ακόμη και τα push σε ανεξάρτητους κλάδους απαιτούν ενημέρωση του ίδιου manifest. Ο χρόνος πλήρους κύκλου μιας επιτυχούς σύγκρισης και ανταλλαγής περιορίζει τη συχνότητα με την οποία το αποθετήριο μπορεί να δημοσιεύει νέο manifest. Η ομαδοποίηση επιτρέπει σε ένα manifest να ενημερώνει πολλές αναφορές ταυτόχρονα, με τίμημα την αναμονή των ενημερώσεων σε ουρά και την αύξηση της καθυστέρησης.

Ο χώρος αποθήκευσης blob μπορεί να λαμβάνει packfile παράλληλα, αλλά οι ενημερώσεις του κοινού manifest εξακολουθούν να ανταγωνίζονται μεταξύ τους. Η αύξηση της δυναμικότητας του χώρου αποθήκευσης blob από μόνη της δεν εξαλείφει αυτό το σημείο συμφόρησης. Κάθε αντίγραφο πρέπει και πάλι να διαβάσει τα πακέτα από τον χώρο αποθήκευσης blob και να δημιουργήσει ευρετήρια, προτού μπορέσει να τα παρέχει τοπικά. Αν οι εισερχόμενες εγγραφές ξεπερνούν τον ρυθμό αυτής της εργασίας, τα αντίγραφα μένουν πίσω και οι πελάτες περιμένουν περισσότερο για να ανακτήσουν commit που μόλις ανέβηκαν.

Η αρχιτεκτονική του Pando

Και εδώ ερχόμαστε στο Pando. Το Pando είναι μια νέα αρχιτεκτονική εξυπηρέτησης αποθετηρίων Git, με στόχο την κλιμάκωση σε πολλούς πελάτες που κάνουν push ταυτόχρονα. Δείτε πώς λειτουργεί:

Επανεξετάζοντας τους περιορισμούς

Πριν αναπτύξουμε το Pando, πιστεύαμε ότι μπορούσαμε να καλύψουμε τις απαιτήσεις μας χωρίς συμβιβασμούς ως προς το Git. Χρειάστηκε όμως να κάνουμε υποχωρήσεις σε ορισμένα στοιχεία που τα περισσότερα συστήματα Git θεωρούν απαραίτητα:

  • Συνέπεια σε όλο το αποθετήριο: Η παροχή ενός συνεπούς στιγμιότυπου όλων των αναφορών για μια συγκεκριμένη χρονική στιγμή απαιτεί συντονισμό σε όλο το αποθετήριο. Σε ένα σύστημα που διατάσσει όλες τις ενημερώσεις αναφορών σε κοινή σειρά, τα push σε ανεξάρτητους κλάδους ανταγωνίζονται για ένα μοναδικό σημείο συντονισμού.

  • Ξεχωριστά packfile για κάθε πελάτη: Αν δύο πελάτες με διαφορετικό τοπικό ιστορικό ανακτήσουν τον ίδιο κλάδο, ο διακομιστής ίσως χρειαστεί να δημιουργήσει διαφορετικό πακέτο για τον καθένα, ώστε να μη στείλει αντικείμενα που ήδη έχουν. Η δημιουργία αυτών των αποκρίσεων καταναλώνει CPU και πόρους εισόδου/εξόδου δίσκου, δυσκολεύοντας την κλιμάκωση σε μεγάλο αριθμό πελατών ανάγνωσης.

Αντί γι’ αυτό, το Pando παρέχει ένα χαλαρότερο μοντέλο συνέπειας (αιτιώδη συνέπεια) για την κλιμάκωση των εγγραφών και επαναχρησιμοποιεί packfile για την κλιμάκωση των αναγνώσεων.

Αιτιώδης συνέπεια (CC)

Όταν ένας πελάτης κάνει push σε έναν κλάδο, το Pando αποθηκεύει το εισερχόμενο packfile ως αμετάβλητο blob σε έναν χώρο αποθήκευσης blob. Κάθε φορά που αλλάζει η κορυφή του κλάδου, το Pando καταγράφει σε έναν χώρο αποθήκευσης μεταδεδομένων μια έκδοση αναφοράς που περιέχει τη νέα κορυφή, το πακέτο που την παρείχε και τυχόν προηγούμενες εκδόσεις αναφορών από τις οποίες εξαρτάται το πακέτο. Τόσο ο χώρος αποθήκευσης blob όσο και ο χώρος αποθήκευσης μεταδεδομένων μπορούν να κλιμακωθούν οριζόντια.

Η ανάκτηση ενός commit ή μιας αναφοράς από το Pando απαιτεί την αποστολή στον πελάτη ενός συνόλου εκδόσεων αναφορών (packfile), ανασυνθέτοντας την κατάσταση του πελάτη που δημιούργησε την έκδοση αναφοράς που ανακτάται. Έτσι παρέχεται μια ασθενέστερη μορφή συνέπειας σε ολόκληρο το αποθετήριο, ενώ εξασφαλίζεται σειριοποιησιμότητα για τις ενημερώσεις μεμονωμένων αναφορών. Συγκρούσεις μεταξύ πελατών προκύπτουν μόνο όταν κάνουν ταυτόχρονα push στην ίδια αναφορά. Ένας πελάτης που διαβάζει πολλούς κλάδους δεν μπορεί να θεωρεί ότι αυτές οι αναγνώσεις αποτυπώνουν την ίδια χρονική στιγμή σε όλο το αποθετήριο.

Αριστερά, τρία διαδοχικά πακέτα του trunk περιέχουν τα commit A, B και C, D και E, και F. Δεξιά, οι trunk και topic αποκλίνουν στο C. Ο trunk προχωρά στο G, ενώ ο topic προχωρά μέσω των D, E και F. Το τελευταίο πακέτο του topic περιέχει τα D, E και F. Ένα διακεκομμένο περίγραμμα δείχνει ότι τα D και E υπάρχουν και στο προηγούμενο πακέτο του topic. Το μπλε βέλος δείχνει την εξάρτηση του νέου πακέτου από τον trunk στο G. Ο γονέας του F στο Git είναι το E.

Ένα push στον trunk προσθέτει ένα πακέτο μόνο με τις νέες αλλαγές, που περιέχει ένα ή περισσότερα commit. Κάθε push σε έναν δευτερεύοντα κλάδο περιλαμβάνει ξανά τα προηγούμενα commit του, ώστε ένας πελάτης με την ανακοινωμένη έκδοση του trunk να μπορεί να ανακτήσει τον κλάδο με ένα μόνο πακέτο.

Πρόκειται για μια μορφή αιτιώδους συνέπειας. Για να ανακτήσει μια αναφορά, ο πελάτης ανάγνωσης βλέπει το ιστορικό του πελάτη εγγραφής που τη δημιούργησε. Κατά το push, το Pando ελέγχει σε ποιο κοινό ιστορικό συμφωνούν πελάτης και διακομιστής, διασφαλίζοντας ότι οι πελάτες δημιουργούν packfile που μπορούν να χρησιμοποιηθούν ευκολότερα από κοινού.

Κατά συνέπεια, το Pando δεν παρέχει την κατάσταση όλων των αναφορών σε μία συγκεκριμένη χρονική στιγμή κατά τις λειτουργίες Git, ούτε μια καθολική σειρά ενημερώσεων αναφορών στο πλαίσιο ενός clone ή fetch. Συγκεκριμένα, ας υποθέσουμε ότι οι κλάδοι foo και bar ενημερώνονται και οι δύο κατά τη διαπραγμάτευση ενός πλήρους clone. Κατά τη διαπραγμάτευση, ένας πελάτης μπορεί να δει τον foo στην έκδοση 1 και τον bar στην έκδοση 2, ενώ ένας άλλος βλέπει τον foo στην έκδοση 2 και τον bar στην έκδοση 1. Στην πράξη, οι χρήστες και οι πράκτορες δεν εξαρτώνται από την καθολική σειρά ενημέρωσης των αναφορών, αλλά από τη σειρά ενημερώσεων μιας μεμονωμένης αναφοράς.

Σύγκριση προσεγγίσεων

Σε αυτή την προσομοίωση των τριών μοντέλων συνέπειας, ρυθμίζουμε 1.000 πελάτες ώστε ο καθένας να επιλέγει διαφορετικό κλάδο και να κάνει επανειλημμένα push, κάθε φορά με μοναδικά commit, μετρώντας τον συνολικό πραγματικό χρόνο εκτέλεσης και την καθυστέρηση από το push έως το fetch. Η δεύτερη μέτρηση είναι σημαντική για τους φόρτους εργασίας, καθώς μετρά τον χρόνο πλήρους κύκλου που χρειάζονται οι χρήστες και οι πράκτορες για να συνεργαστούν ή να χρησιμοποιήσουν άλλα συστήματα που βασίζονται στον έλεγχο εκδόσεων. Η προσομοίωση μοντελοποιεί υποδομές από τυπικές έως υψηλών προδιαγραφών, με εικονικές μηχανές και συστήματα αποθήκευσης blob. Σε αυτή την προσομοίωση, έχουμε χαλαρώσει την απαίτηση συνέπειας σε όλο το αποθετήριο για την οριστικοποίηση τριών φάσεων.

Simulating Git Server Implementations

Follow each writer through repeated pushes, and separately measure when an independent reader can check out each commit.

Three-phase commit

Ready
Simulated time
0 s
Mean push to fetch
—
Writers done
0 / 1,000

Each square represents one writer. All selected architectures run the same workload. Squares lighten as pushes are acknowledged and turn blue when a writer finishes. The chart shows writers finished over simulated time; independent readers can continue fetching afterward. Use arrow keys to select a writer, Home or End to jump, and Escape to clear.

0 / 10,000 pushes acknowledged · 0 fetched

Select a square to inspect that writer.

Object-store WAL

Ready
Simulated time
0 s
Mean push to fetch
—
Writers done
0 / 1,000

Each square represents one writer. All selected architectures run the same workload. Squares lighten as pushes are acknowledged and turn blue when a writer finishes. The chart shows writers finished over simulated time; independent readers can continue fetching afterward. Use arrow keys to select a writer, Home or End to jump, and Escape to clear.

0 / 10,000 pushes acknowledged · 0 fetched

Select a square to inspect that writer.

Pando

Ready
Simulated time
0 s
Mean push to fetch
—
Writers done
0 / 1,000

Each square represents one writer. All selected architectures run the same workload. Squares lighten as pushes are acknowledged and turn blue when a writer finishes. The chart shows writers finished over simulated time; independent readers can continue fetching afterward. Use arrow keys to select a writer, Home or End to jump, and Escape to clear.

0 / 10,000 pushes acknowledged · 0 fetched

Select a square to inspect that writer.

Writer progress through verified fetches

  • Three-phase commit
  • Object-store WAL
  • Pando
05001,00000 s
  • Waiting
  • Pushing
  • All pushes acknowledged
0 sLater

Synthetic teaching models, not production benchmarks. Mean push to fetch covers topic pushes, from the first attempt through retries until an independent reader verifies that commit. It includes waiting for a reader slot and excludes builds and tests. With merges enabled, writer completion includes the required fetches and trunk merge.

Experiment settings

Preparing simulation…

Results

Play the comparison to see the recorded results.

Synthetic teaching models, not production benchmarks. Mean push to fetch covers topic pushes, from the first attempt through retries until an independent reader verifies that commit. It includes waiting for a reader slot and excludes builds and tests. With merges enabled, writer completion includes the required fetches and trunk merge.

Εκτελέστε αυτή την προσομοίωση που συγκρίνει το Pando με δύο άλλες προσεγγίσεις. Επιλέξτε υποδομή από τυπικό υλικό έως υλικό υψηλών προδιαγραφών, αριθμό πελατών και άλλες ρυθμίσεις για να δείτε πώς συγκρίνονται.

Το μοντελοποιημένο σύστημα οριστικοποίησης τριών φάσεων εμφανίζει σημαντικά μεγαλύτερη καθυστέρηση εγγραφής υπό φορτίο, καθώς οι δίσκοι του φτάνουν σε κορεσμό. Αντίστοιχα, τα συστήματα με αρχείο καταγραφής προεγγραφής εμφανίζουν σημαντικά μεγαλύτερη καθυστέρηση ανάγνωσης για τον ίδιο λόγο, καθώς οι διακομιστές δυσκολεύονται να διαβάζουν το αρχείο καταγραφής με τον απαιτούμενο ρυθμό. Τόσο στις δοκιμές σε πραγματικές συνθήκες στο ενιαίο αποθετήριό μας όσο και σε αυτή την προσομοίωση, το Pando υποστηρίζει πολλές χιλιάδες πελάτες που μπορούν να κάνουν push ταυτόχρονα, χωρίς να επηρεάζονται οι επιδόσεις υπό φορτίο.

Κατά την επεξεργασία ενός push, το Pando επικυρώνει το εισερχόμενο packfile ενώ το μεταφέρει με ροή στον χώρο αποθήκευσης blob, χωρίς να το αποσυσκευάζει σε τοπικό αποθετήριο. Όταν ένας πελάτης ξεκινά ένα fetch, το Pando επιλέγει τα αποθηκευμένα πακέτα που χρειάζεται και ο πελάτης τα κατεβάζει. Κανένας διακομιστής δεν χρειάζεται να εφαρμόσει packfile σε τοπικό αποθετήριο ή να εκτελέσει δαπανηρές εργασίες αποσυσκευασίας και συσκευασίας. Επειδή εκτελούν κυρίως διαπραγμάτευση και επιλογή packfile, οι διακομιστές Pando μπορούν να λειτουργούν σε τυπικό υλικό.

Έτσι, το Pando μπορεί να κλιμακώνεται μέχρι τα όρια των πελατών, του δικτύου μεταξύ πελατών και Pando και της υπηρεσίας αποθήκευσης blob. Με επαρκή δυναμικότητα, οι πελάτες που εργάζονται σε ανεξάρτητους κλάδους μπορούν να μεταφέρουν πακέτα όσο γρήγορα επιτρέπει η σύνδεσή τους. Για να εξυπηρετήσουμε περισσότερους πελάτες με αυτόν τον ρυθμό, μπορούμε να προσθέσουμε διακομιστές Pando και να κλιμακώσουμε παράλληλα τους χώρους αποθήκευσης μεταδεδομένων και blob.

Pushing and Fetching a Branch in Pando

Pando stores the writer’s packfile in blob storage and records the ref version in metadata service. On fetch, Pando selects the packs the reader needs, and Express serves them.

Stream the push

  • Packfile bytes
  • Metadata
  • Request / acknowledgment
  • Packfile URIs

Ένας πράκτορας επεξεργάζεται αρχεία, δημιουργεί ένα commit τοπικά και εκτελεί git push, το οποίο δημιουργεί ένα packfile με αυτές τις αλλαγές για να ενημερώσει έναν κλάδο. Το Pando λαμβάνει το πακέτο και το μεταφέρει με ροή στον χώρο αποθήκευσης blob. Αφού επικυρώσει το εισερχόμενο push με αποκωδικοποίηση ενός περάσματος, το Pando χρησιμοποιεί μια συναλλαγή πολλαπλών κλειδιών για να καταγράψει μια έκδοση αναφοράς στον χώρο αποθήκευσης μεταδεδομένων μας και να ενημερώσει ατομικά τον δείκτη της αναφοράς. Έτσι, το Pando μπορεί να παρέχει συνέπεια τύπου «διαβάζεις ό,τι έγραψες». Ολόκληρη αυτή η λειτουργία εγγραφής απαιτεί O(1)O(1) αναγνώσεις και εγγραφές μεταδεδομένων.

Όταν ένας άλλος πελάτης ανακτά τον κλάδο, το Pando επιλέγει ένα σύνολο αποθηκευμένων πακέτων με βάση το ιστορικό που ήδη διαθέτει ο πελάτης. Αυτή η λειτουργία απαιτεί O(log⁡Δ)O(\log \Delta) αναγνώσεις μεταδεδομένων, όπου Δ\Delta είναι η μικρότερη απόσταση, σε εκδόσεις αναφορών, ανάμεσα σε όσα έχει και σε όσα ζητά ο πελάτης. Ο διακομιστής επιστρέφει URI των packfile και ο πελάτης τα κατεβάζει μέσω της υπηρεσίας Express, η οποία αποθηκεύει packfile σε περιφερειακές κρυφές μνήμες.

Αυτός ο σχεδιασμός βασίζεται στις τρεις κεντρικές υπηρεσίες της αρχιτεκτονικής του Pando: push, fetch και συμπύκνωση.

Κλιμάκωση των push

Όταν ένας πελάτης κάνει push, ένας συμβατικός διακομιστής Git μοιάζει με παίκτη πόκερ που ανοίγει όλα του τα χαρτιά: αποκαλύπτει στον πελάτη κάθε κλάδο που διαθέτει. Ο πελάτης συγκεντρώνει έπειτα τα commit, τα δέντρα και τα blob για να δημιουργήσει ένα packfile που εξαιρεί τα αντικείμενα που γνωρίζει ότι ο διακομιστής ήδη διαθέτει.

Η ανακοίνωση περισσότερων αναφορών μπορεί να μειώσει το μέγεθος του push. Μπορεί όμως να δυσκολέψει και την επαναχρησιμοποίηση του πακέτου, επειδή από έναν άλλο πελάτη ίσως λείπουν αντικείμενα που παρέλειψε ο πελάτης εγγραφής.

Το Pando ακολουθεί διαφορετική προσέγγιση. Αντί να ανοίγει όλα του τα χαρτιά, ανακοινώνει στον πελάτη μόνο ένα επιλεγμένο σύνολο κλάδων. Αυτό γίνεται για δύο λόγους:

  1. Η παροχή μιας συνεπούς εικόνας όλων των αναφορών είναι δαπανηρή. Με εκατομμύρια κλάδους, μόνο η ανακοίνωση των αναφορών μπορεί να ξεπεράσει τα 100 MiB. Αυτό απαιτεί από κάθε διακομιστή είτε να διατηρεί μια ενημερωμένη αντιστοίχιση, με σημαντικό κόστος συντονισμού, είτε να εκτελεί ένα ερώτημα βάσης δεδομένων του οποίου το κόστος αυξάνεται με τον αριθμό των αναφορών.

  2. Παρέχοντας στον πελάτη μόνο ένα υποσύνολο των αναφορών, εξασφαλίζουμε ότι θα δημιουργήσει ένα πακέτο που εξαρτάται μόνο από όσα ο διακομιστής τού επιτρέπει ρητά να εξαιρέσει. Η παρακολούθηση των εξαρτήσεων επιτρέπει στο Pando να επαναχρησιμοποιεί το packfile που δημιουργεί ένας πελάτης σε ένα push, παρέχοντάς το ως απόκριση σε μεταγενέστερο fetch.

Όσο περισσότερες αναφορές ανακοινώνει ένας διακομιστής Git, τόσο περισσότερες πηγές έχουν οι πελάτες που κάνουν push για να εξαιρούν αντικείμενα, δημιουργώντας μικρότερα πακέτα. Ωστόσο, για να επαναχρησιμοποιηθούν αυτά τα packfile, ο διακομιστής πρέπει να μπορεί να αποδείξει ότι οι πελάτες που κάνουν fetch διαθέτουν όλες τις εξαρτήσεις. Διαφορετικά, το packfile μπορεί να παραλείπει αντικείμενα που χρειάζεται ο πελάτης.

Από την άλλη, αν ένας διακομιστής Git δεν ανακοινώνει καμία αναφορά, ο πελάτης θα δημιουργήσει ένα packfile που περιέχει ολόκληρο το ιστορικό του αποθετηρίου. Αυτό το packfile μπορεί να χρησιμοποιηθεί από οποιονδήποτε άλλο πελάτη, αλλά με σημαντικό κόστος: η ανάκτηση οποιουδήποτε κλάδου ισοδυναμεί ουσιαστικά με πλήρες clone.

Καμπύλη που δείχνει πώς οι ανακοινωμένες αναφορές επηρεάζουν το μέγεθος του packfile: από το πλήρες ιστορικό όταν δεν ανακοινώνεται καμία, στην ανακοίνωση του trunk, έως μόνο τα νέα αντικείμενα όταν ανακοινώνονται όλες.

Η ανακοίνωση περισσότερων αναφορών οδηγεί σε μικρότερα packfile. Το μεγαλύτερο μέρος της μείωσης του μεγέθους μπορεί να προκύψει από την ανακοίνωση μίας μόνο αναφοράς.

Από προεπιλογή, όταν ένας πελάτης κάνει push έναν νέο κλάδο ανάπτυξης λειτουργίας, το Pando ανακοινώνει ως βάση μόνο έναν καθορισμένο κύριο κλάδο, τον trunk. Έτσι, το μέγεθος της ανακοίνωσης παραμένει σταθερό όσο αυξάνονται οι κλάδοι του αποθετηρίου, αλλά υπάρχουν συμβιβασμοί. Όταν ένας μηχανικός κάνει πολλά push στον ίδιο κλάδο ή δημιουργεί έναν κλάδο ανάπτυξης λειτουργίας πάνω σε άλλον, ο πελάτης πρέπει να ξαναστείλει όλα όσα βρίσκονται εκτός trunk.

Έτσι, τα διαδοχικά push στον κλάδο είναι μεγαλύτερα, περιέχουν ενδεχομένως πλεονάζοντα αντικείμενα και καταναλώνουν επιπλέον εύρος ζώνης του πελάτη. Στο ενιαίο αποθετήριό μας, το διάμεσο μέγεθος των packfile που δημιουργούνταν έτσι ήταν κάτω από 20 KiB και το 99ο εκατοστημόριο κάτω από 3 MiB. Για εμάς, αυτός ήταν ένας εύλογος συμβιβασμός, επειδή ένας πελάτης ανάγνωσης που έχει ήδη το ανακοινωμένο ιστορικό του trunk μπορεί να ανακτήσει τον κλάδο με αυτό το ένα packfile.

Αφού επιλέξει το σύνολο αναφορών που θα ανακοινώσει στον πελάτη, το Pando δέχεται το push και ενημερώνει τον χώρο αποθήκευσης μεταδεδομένων του. Το Pando χωρίζει την ενημέρωση μεταδεδομένων σε σύγχρονο και ασύγχρονο μέρος. Η σύγχρονη ενημέρωση μεταδεδομένων διασφαλίζει ότι οι πελάτες μπορούν να ανακτήσουν αμέσως το νέο commit. Αυτή καταγράφει μια νέα έκδοση αναφοράς και ενημερώνει την αντιστοίχιση του δείκτη αναφοράς στη νέα έκδοση, αποθηκεύοντας τη νέα κορυφή, τις εξαρτήσεις που χρησιμοποιήθηκαν στη διαπραγμάτευση του packfile και έναν σύνδεσμο προς το packfile του push.

Παράλληλα, στην ίδια συναλλαγή καταγράφονται ασύγχρονες εργασίες, όπως ο προγραμματισμός συμπύκνωσης. Για πολύ μεγάλα push, μόνο ένα υποσύνολο των commit καταγράφεται σύγχρονα. Έτσι, απαιτείται μόνο σταθερός αριθμός αναγνώσεων και εγγραφών στον χώρο αποθήκευσης μεταδεδομένων, ανεξάρτητα από το μέγεθος του push.

Το σημαντικό είναι ότι οι διακομιστές Pando μπορούν να δέχονται ανεξάρτητα push σε άσχετες μεταξύ τους αναφορές. Το μόνο κλειδί για το οποίο υπάρχει ανταγωνισμός είναι ο δείκτης αναφοράς, τον οποίο προστατεύουμε με μια ατομική λειτουργία τύπου σύγκρισης και ανταλλαγής. Μπορούμε να αυξήσουμε τη ρυθμαπόδοση εγγραφής προσθέτοντας διακομιστές Pando, μονάδες κλιμάκωσης του χώρου αποθήκευσης μεταδεδομένων ή χώρους αποθήκευσης blob.

Επιδόσεις fetch και clone στη μέγιστη ταχύτητα της σύνδεσης

Όταν ένας πελάτης εκτελεί fetch, παρέχει στον διακομιστή δύο σύνολα αναγνωριστικών commit, γνωστά στο πρωτόκολλο ως have και want. Σε έναν συμβατικό διακομιστή Git, ο διακομιστής υπολογίζει τη διαφορά μεταξύ των συνόλων αντικειμένων που είναι προσβάσιμα από τα have και από τα want, συμπιέζει τα αντικείμενα που προκύπτουν και στέλνει το αποτέλεσμα στον πελάτη. Παρότι ο διακομιστής Git ανοιχτού κώδικα διαθέτει διάφορα τοπικά ευρετήρια για να επιταχύνει αυτή τη λειτουργία, η δημιουργία αυτών των packfile μπορεί να είναι δαπανηρή και γενικά δεν προσφέρονται για αποθήκευση σε κρυφή μνήμη.

Αντί γι’ αυτό, το Pando χρησιμοποιεί τις αντιστοιχίσεις commit που καταγράφονται κατά τα push για να αναζητήσει τα have και want του πελάτη και να τα αντιστοιχίσει σε ένα σύνολο εκδόσεων αναφορών που περιέχουν αυτά τα commit. Κάθε μία από αυτές τις εκδόσεις αναφορών συνδέεται με ένα packfile που έχει λάβει προηγουμένως το Pando. Ο διακομιστής χρησιμοποιεί αυτή την πληροφορία για να προσδιορίσει τι χρειάζεται ο πελάτης, επιλέγοντας τα packfile που καλύπτουν το απαιτούμενο σύνολο αντικειμένων.

Planning fetches in Pando

Pando compares what a client has with what it wants, then selects the stored packfiles needed—including any missing branch dependencies.

Already heldFetchMissing branch dependency

Fetch 27 trunk packs.

Select a branch to include its trunk dependencies.

Το Pando αντιστοιχίζει τα have και want του πρωτοκόλλου Git σε μια ακολουθία εκδόσεων αναφορών. Ένα αίτημα για δευτερεύοντα κλάδο περιλαμβάνει και το ιστορικό μέχρι τις εξαρτήσεις του στον trunk.

Το πρωτόκολλο Git επιτρέπει την αποστολή μόνο ενός packfile στην απόκριση HTTP ενός clone ή fetch. Ωστόσο, μια λιγότερο γνωστή δυνατότητα του πρωτοκόλλου Git, το packfile-uri, επιτρέπει στον διακομιστή να επιστρέφει συνδέσμους για ξεχωριστή λήψη επιπλέον πακέτων. Το Pando χρησιμοποιεί αποκλειστικά αυτή τη δυνατότητα και στέλνει ένα κενό packfile μέσα στην απόκριση. Για να υποστηρίξει αυτή τη δυνατότητα, η OpenAI συνεισέφερε αρκετές βελτιώσεις στο packfile-uri στο κύριο έργο του Git.

Τα συστήματα της OpenAI λειτουργούν σε πολλές γεωγραφικές περιοχές, γι’ αυτό διατηρούμε συστοιχίες Pando με τοπικές κρυφές μνήμες σε καθεμία. Μια υπηρεσία διανομής πακέτων, η Express, παρέχει κρυφή μνήμη για τον χώρο αποθήκευσης blob, ενώ μια ξεχωριστή υπηρεσία παρέχει κρυφή μνήμη για τον χώρο αποθήκευσης μεταδεδομένων. Αυτές οι κρυφές μνήμες επιτρέπουν στο Pando να εξυπηρετεί αιτήματα για ένα αναγνωριστικό commit ή ειδική ανάγνωση μιας αναφοράς εξ ολοκλήρου από την αποθηκευμένη κατάσταση της συγκεκριμένης συστοιχίας. Χρησιμοποιούμε συνεπή κατακερματισμό για να δρομολογούμε αιτήματα για packfile στους διακομιστές Express, με ποσοστά επιτυχούς εύρεσης στην κρυφή μνήμη άνω του 99%.

Αυτό το σύστημα κρυφών μνημών παρέχει εξαιρετικά υψηλή ρυθμαπόδοση, ικανή να αξιοποιήσει πλήρως τη χωρητικότητα του δικτύου μεταξύ πελατών και Pando. Με αυτά τα URI των packfile και τις τοπικές κρυφές μνήμες, επιβεβαιώσαμε ότι, χρησιμοποιώντας μόνο τυπικές εικονικές μηχανές παρόχων cloud, οι λειτουργίες clone και fetch αξιοποιούν πλήρως συνδέσεις δικτύου 10 Gbps.

Συμπύκνωση και χρόνος έως το πρώτο byte

Στους περισσότερους διακομιστές Git, η επανασυσκευασία και η συλλογή απορριμμάτων είναι απαραίτητες για τη διατήρηση των επιδόσεων ενός αποθετηρίου που μεγαλώνει. Και οι δύο εργασίες απελευθερώνουν χώρο, αλλά απαιτούν πολλούς υπολογιστικούς πόρους και λειτουργίες εισόδου/εξόδου.

Σε ένα αποθετήριο που αλλάζει γρήγορα, όπως το ενιαίο αποθετήριο της OpenAI, δεν είναι πρακτικό να στέλνεται ξεχωριστό URI packfile για κάθε push που έχει γίνει από το τελευταίο fetch. Κάθε μέρα, ένας πελάτης θα έπρεπε να κατεβάζει δεκάδες χιλιάδες packfile για να ενημερώνει τον trunk του.

Αντί γι’ αυτό, το Pando συνδυάζει πακέτα στο παρασκήνιο για να μειώνει αυτό το κόστος, υιοθετώντας σχεδιασμό παρόμοιο με τη συμπύκνωση σε δέντρα συγχώνευσης με δομή καταγραφής (LSM). Κάθε push δημιουργεί αυτό που το Pando ονομάζει packfile «L0», τη μικρότερη μονάδα δεδομένων που μπορεί να μεταδώσει. Με την πάροδο του χρόνου, διεργασίες παρασκηνίου συγκεντρώνουν αυτά τα packfile σε ομάδες κάλυψης που καλύπτουν μια ακολουθία εκδόσεων αναφορών και αυξάνονται γεωμετρικά από το L0. Σήμερα, το ενιαίο αποθετήριό μας χρησιμοποιεί ομάδες κάλυψης packfile έως το επίπεδο L4.

Αυτές οι ομάδες κάλυψης εξυπηρετούν διπλό σκοπό. Όταν μια ομάδα κάλυψης γεμίσει αρκετά, μια διεργασία συμπύκνωσης την αναλαμβάνει και δημιουργεί ένα ενιαίο packfile. Έτσι βελτιώνεται ο λόγος συμπίεσης, με την αναδιοργάνωση των αντικειμένων μέσα στο packfile. Παράλληλα, βελτιώνονται οι επιδόσεις της διαπραγμάτευσης fetch, καθώς η ομάδα κάλυψης λειτουργεί ως λίστα παράκαμψης πάνω στις εκδόσεις αναφορών. Σαρώνοντας ταυτόχρονα τα ευρετήρια κάθε επιπέδου, το Pando μπορεί να επιλέγει σε λογαριθμικό χρόνο ένα σύνολο πακέτων για αποστολή σε έναν πελάτη. Αυτές οι ομάδες κάλυψης packfile, είτε έχουν επανασυσκευαστεί είτε όχι, επιτρέπουν αποδοτικότερο σχεδιασμό των fetch, μειώνοντας τις απαιτήσεις τόσο ως προς τη ρυθμαπόδοση όσο και ως προς την καθυστέρηση για το Pando.

Compaction in Pando

Small packfiles are grouped into larger covers across levels, improving compression and speeding up fetches.

Compaction in progressPublished cover

Η συμπύκνωση συνδυάζει στο παρασκήνιο packfile από πολλές εκδόσεις αναφορών, επιτρέποντας αποδοτικότερα fetch με λιγότερα αρχεία.

Σε αντίθεση με πολλούς διακομιστές Git, τα packfile διατηρούνται σε κάθε επίπεδο και δεν απορρίπτονται ούτε αφαιρούνται μέσω συλλογής απορριμμάτων. Πακέτα από κάθε επίπεδο χρησιμοποιούνται συνεχώς για την εξυπηρέτηση πελατών, με βάση τα have και want που δηλώνουν σε ένα fetch. Και για τους πελάτες που χρησιμοποιούν το Pando ως API, η ανάγνωση ενός αυθαίρετου αντικειμένου από packfile συνήθως απαιτεί λιγότερα δεδομένα από ένα L0 παρά από ένα L4, επειδή είναι λιγότερο πιθανό να είναι συμπιεσμένο.

Η συμπύκνωση στο Pando μειώνει σημαντικά τον συνολικό όγκο δεδομένων που μεταφέρονται στους πελάτες και επιτρέπει στον σχεδιασμό πακέτων να κλιμακώνεται υπογραμμικά ως προς το πόσο πίσω έχει μείνει ο πελάτης. Αυτό είναι ιδιαίτερα σημαντικό για μεγάλα αποθετήρια που αλλάζουν γρήγορα, τα οποία αναμένουμε ότι θα αποτελέσουν τη νέα κανονικότητα στην ανάπτυξη λογισμικού.

Η δημιουργία του Pando

Δημιουργήσαμε το Pando με το Codex, περνώντας από την έναρξη του έργου στην παραγωγή σε μόλις 10 εβδομάδες. Ο πυρήνας του Pando σχεδιάστηκε από έναν μόνο μηχανικό, υλοποιήθηκε από ομάδες πρακτόρων και τέθηκε σε λειτουργία από μια μικρή ομάδα μηχανικών. Το Pando άρχισε να εξυπηρετεί κίνηση παραγωγής τον Απρίλιο του τρέχοντος έτους και αποτελεί μέρος ενός ευρύτερου συστήματος εργαλείων διαχείρισης εκδόσεων κώδικα που χρησιμοποιούνται στην OpenAI.

Χρησιμοποιήσαμε πολλές διαφορετικές προσεγγίσεις για την επικύρωση του σχεδιασμού του Pando. Εφαρμόσαμε τις αρχές μας για τη δημιουργία ασφαλέστερων θεμελίων λογισμικού⁠. Καθώς ξεκινούσαμε από το μηδέν, επιλέξαμε να υλοποιήσουμε το Pando σε Rust και χωρίς εξαρτήσεις από παλαιότερα συστήματα. Γράψαμε μια σουίτα δοκιμών συμμόρφωσης, ώστε οι πράκτορες να μπορούν να ελέγχουν τις αλλαγές τους ως προς την τυπική συμπεριφορά του Git. Αναπτύξαμε επίσης μηχανισμούς δοκιμών με ντετερμινιστική προσομοίωση, ώστε να ελέγχουμε αναλλοίωτες συνθήκες και ιδιότητες του συστήματος. Έτσι εντοπίσαμε και περιορίσαμε δυσδιάκριτες συνθήκες ανταγωνισμού και παλινδρομήσεις στη διαπραγμάτευση και στον σχεδιασμό πακέτων.

Πολλά μοντέλα συνέβαλαν σε αυτό το σύστημα. Καθώς γίνονταν διαθέσιμα νέα μοντέλα, τα χρησιμοποιούσαμε για να βελτιώσουμε τις επιδόσεις και την αξιοπιστία του Pando. Χρησιμοποιώντας το GPT‑6 Astra, πράκτορες έγραψαν κώδικα σε Lean και TLA+ για να διατυπώσουν τυπικά μια «θεωρία του Pando», την οποία χρησιμοποιήσαμε για να εντοπίσουμε και να διορθώσουμε σφάλματα στην υλοποίηση και να αποδείξουμε ιδιότητες του συστήματος. Πολλές συνεχείς συνεδρίες εκτελούνταν για εκατοντάδες ώρες, εντοπίζοντας και διορθώνοντας οριακές περιπτώσεις στο Pando. Εκτελούμε επίσης πράκτορες όλο το εικοσιτετράωρο για επιθετικούς ελέγχους ασφαλείας στο Git και το Pando, με μοντέλα που διαθέτουν δυνατότητες Daybreak.

Η θέση του Pando σε λειτουργία

Αρχικά θέσαμε το Pando σε λειτουργία ως διαμεσολαβητή που προωθούσε αναγνώσεις και εγγραφές στο υπάρχον σύστημα ελέγχου εκδόσεων κώδικα. Έτσι διατηρούσαμε συγχρονισμένα το Pando και το προηγούμενο σύστημα, ώστε να μεταφέρουμε με ασφάλεια την κίνηση στο Pando χωρίς διακοπή λειτουργίας.

Στο πλαίσιο του σχεδιασμού της κρυφής μνήμης του, το Pando μπορεί επίσης να εξαλείφει διπλότυπα και να συνδυάζει αιτήματα πριν τα προωθήσει. Αυτό μας επέτρεψε να διατηρούμε την ομαλή λειτουργία των υπαρχόντων εργαλείων μας, καθώς μεταφέραμε τα συστήματα στο Pando ένα προς ένα. Καθώς μεταφέραμε περισσότερους φόρτους εργασίας στο Pando, τα push τους γέμιζαν την κρυφή μνήμη του και βελτίωναν την αξιοπιστία του προηγούμενου backend μας.

Για να βελτιστοποιήσουμε τις επιδόσεις κατά τη χρήση του Pando, αρχίσαμε να διαθέτουμε τη δημόσια διανομή μας του Git στους υπολογιστές των προγραμματιστών και μέσα στην εφαρμογή ChatGPT για υπολογιστές. Για τη σταδιακή μετάβαση των πελατών στο Pando, χρησιμοποιήσαμε ένα εσωτερικό εργαλείο που περιβάλλει το CLI του Git. Δημιουργήσαμε πολλά ακόμη εργαλεία για τη διαχείριση αιτημάτων αλλαγών και την ανασκόπηση κώδικα, καθώς και API για αυτοματισμούς. Μαζί με την κίνηση Git, μεταφέραμε εκατοντάδες ενσωματώσεις που εξαρτώνταν από παλαιότερα API, webhook και λήψεις αποθετηρίων.

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

Η μετάβαση στο Pando βελτίωσε την αξιοπιστία των συγχωνεύσεων και μείωσε τη διάμεση καθυστέρηση των push κατά σχεδόν 80%.

Το Pando μπορεί να διανέμει ένα petabyte δεδομένων Git την ημέρα με ελάχιστους πυρήνες CPU. Το Pando έχει διανείμει περισσότερα από 57 terabyte πακέτων Git σε μία μόνο ώρα, με πάνω από το 99% αυτών των byte να προέρχεται από την τοπική κρυφή μνήμη δίσκου.

Η επαναχρησιμοποίηση πακέτων επιτρέπει σε πολλούς πελάτες να κατεβάζουν το ίδιο ιστορικό αποθετηρίου με ελάχιστους υπολογισμούς στους κόμβους εξυπηρέτησης. Αυτό το παράδειγμα αφορά ένα μόνο αποθετήριο, αλλά το Pando έχει σχεδιαστεί για να υποστηρίζει πολύ περισσότερα. Καθώς αυξάνεται η ζήτηση, μπορούμε να κλιμακώνουμε ανεξάρτητα τη διανομή δεδομένων και τη διαπραγμάτευση Git.

Συνεισφορά στο έργο του Git

Η ανάπτυξη του Pando πάνω στο πρωτόκολλο και τον πελάτη Git μάς βοήθησε να εντοπίσουμε σφάλματα και ευκαιρίες βελτίωσης των επιδόσεων του ίδιου του Git.

Για παράδειγμα, το Pando παρέχει επαναχρησιμοποιήσιμα πακέτα απευθείας στους πελάτες. Έτσι, η λήψη και η δημιουργία ευρετηρίων για αυτά τα πακέτα έγιναν κεντρικό στοιχείο για την ταχύτητα και την αξιοπιστία του συστήματος. Αυτή η δουλειά ανέδειξε οριακές περιπτώσεις στις ταυτόχρονες λήψεις, στον καθαρισμό μετά από διακοπείσες μεταφορές και στη συνέχιση λήψεων που είχαν ήδη ολοκληρωθεί. Διορθώσαμε αυτές τις διαδρομές εκτέλεσης, προσθέσαμε ελέγχους επικύρωσης κατά την αποδοχή υπάρχοντος πακέτου για fetch και συνεισφέραμε αυτή τη δουλειά στο κύριο έργο του Git.

Χρειαζόταν επίσης να δούμε πού καταναλώνονταν χρόνος και εύρος ζώνης. Προσθέσαμε λοιπόν ιχνηλάτηση για τις λήψεις packfile-uri και μετρήσεις byte για τη δημιουργία πακέτων, ώστε να διαπιστώνουμε ευκολότερα αν ένα αργό fetch καθυστερεί στη δημιουργία των πακέτων ή στη μεταφορά τους.

Στην έκδοση του Git της OpenAI⁠(ανοίγει σε νέο παράθυρο), ο πελάτης μπορεί να κατεβάζει και να δημιουργεί ευρετήρια για ανεξάρτητα πακέτα παράλληλα. Προσθέσαμε την έννοια των «ρητών have», ώστε ένας διακομιστής να μπορεί να ανακοινώνει την τρέχουσα κορυφή ενός κλάδου ξεχωριστά από το ιστορικό που μπορεί να παραλείψει από το πακέτο του ένας πελάτης που κάνει push. Στο Pando, αυτό επιτρέπει στους πελάτες να χρησιμοποιούν το --force-with-lease για να ελέγχουν ότι δεν έχει αλλάξει η κορυφή ενός κλάδου ανάπτυξης λειτουργίας και να δημιουργούν το πακέτο του με βάση μόνο τον trunk. Στη συνέχεια, οποιοσδήποτε διαθέτει αυτό το ιστορικό του trunk μπορεί να ανακτήσει τον κλάδο χρησιμοποιώντας το ίδιο πακέτο.

Αρκετές από αυτές τις βελτιώσεις έχουν ήδη ενσωματωθεί στο κύριο έργο του Git και πολλές άλλες βρίσκονται στο δημόσιο αποθετήριό μας. Συνεχίζουμε να συνεργαζόμαστε με την κοινότητα του Git, ώστε αυτές οι βελτιώσεις να είναι χρήσιμες και πέρα από το Pando. Μπορείτε να παρακολουθείτε αυτή τη δουλειά στο δημόσιο σύστημα παρακολούθησης ενημερώσεων κώδικά μας⁠(ανοίγει σε νέο παράθυρο).

Τα επόμενα βήματα

Επανεξετάζοντας τις καθιερωμένες αντιλήψεις για την κλιμάκωση των αποθετηρίων Git, το Pando μάς επιτρέπει να κλιμακώνουμε το ενιαίο αποθετήριό μας χωρίς να αλλάζουμε τις ροές εργασίας Git που ήδη χρησιμοποιούν οι μηχανικοί και οι πράκτορές μας. Στο ενιαίο αποθετήριό μας, το Pando έχει επιτρέψει μεγαλύτερο βαθμό παραλληλισμού, έχει βελτιώσει την αξιοπιστία των συγχωνεύσεων και έχει μειώσει τον χρόνο δημοσίευσης αλλαγών κώδικα. Πέρα από το ενιαίο αποθετήριό μας, διερευνούμε και άλλες χρήσεις του Pando στην OpenAI, όπως φόρτους εργασίας όπου μεγάλος αριθμός πρακτόρων χρειάζεται να συνεργάζεται σε ένα κοινό αποθετήριο Git.

Καθώς οι μηχανικοί και οι πράκτορες παράγουν περισσότερο λογισμικό, όλο και περισσότερες ομάδες εκτός OpenAI θα συναντούν τα όρια που αντιμετωπίσαμε στον έλεγχο εκδόσεων κώδικα. Αυτή την περίοδο διερευνούμε τρόπους να μοιραστούμε με τους χρήστες μας την τεχνολογία στην οποία βασίζεται το Pando.

Το Pando αξιοποιεί δύο δεκαετίες εμπειρίας χρηστών και διαχειριστών αποθετηρίων Git. Θα συνεχίσουμε να αναπτύσσουμε το Pando, συνεργαζόμενοι με την κοινότητα ανοιχτού κώδικα του Git για να μοιραζόμαστε βελτιώσεις που ωφελούν ευρύτερα τους χρήστες του Git.

Συντάκτης

OpenAI