Ευρετήριο ημερολογίουDockup / σημείωση πεδίου
Note / unexpected-egress-charges

Απρόσμενες χρεώσεις egress: Από πού προέρχονται οι λογαριασμοί bandwidth

Οι απρόσμενες χρεώσεις egress συνήθως οφείλονται σε τέσσερις συνήθειες: σερβίρισμα media από την εφαρμογή, απουσία cache headers, chatty APIs και traffic μεταξύ regions. Εντόπισε την πηγή και μείωσε τον λογαριασμό χωρίς να αλλάξεις provider.

Ο λογαριασμός έρχεται και είναι τέσσερις φορές υψηλότερος από όσο περίμενες. Η χρέωση για compute είναι περίπου αυτή που είχες υπολογίσει. Η χρέωση που ξεφεύγει είναι το egress — τα bytes που φεύγουν από την υποδομή σου — και υπάρχει μεγάλη πιθανότητα να μην το είχες σκεφτεί ποτέ.

Οι απρόσμενες χρεώσεις egress είναι η συνηθέστερη έκπληξη στους λογαριασμούς για application hosting, και ο λόγος είναι δομικός: τίποτα στη διαδικασία ανάπτυξής σου δεν μετράει bytes. Το laptop σου δεν σε χρεώνει γι’ αυτά. Το staging δεν έχει users. Η πρώτη φορά που το bandwidth γίνεται ορατό είναι σε ένα invoice, και μέχρι τότε έχεις ήδη κυκλοφορήσει τη συνήθεια που το προκάλεσε.

Από εδώ προέρχεται στην πράξη, με σειρά ανάλογη με το πόσο συχνά είναι η σωστή απάντηση.

1. Σερβίρισμα media από την εφαρμογή

Αυτό ξεπερνά κατά πολύ τα υπόλοιπα και σχεδόν πάντα συμβαίνει κατά λάθος.

Βάζεις ένα video στο /public για να κάνεις demo κάτι. Λειτουργεί, οπότε παραμένει εκεί. Τώρα κάθε page view κάνει stream αυτό το αρχείο από το container σου. Ένα video 40 MB σε μια σελίδα με χίλιους visitors τον μήνα σημαίνει 40 GB — από ένα αρχείο που θεωρούσες απλώς προσωρινό.

Το ίδιο ισχύει για product images, PDFs, user uploads και font files. Όταν τα προσθέτεις, κανένα από αυτά δεν μοιάζει με απόφαση υποδομής.

Η λύση δεν απαιτεί κάτι περίπλοκο: τα static media ανήκουν σε object storage πίσω από CDN, όχι στο filesystem της εφαρμογής σου. Η εφαρμογή σου πρέπει να σερβίρει HTML και JSON. Από τη στιγμή που σερβίρει μια hero image 4 MB σε κάθε visitor, κάνει τη δουλειά ενός CDN χωρίς κανένα από τα οικονομικά οφέλη ενός CDN.

2. Απουσία cache headers

Αν οι responses σου δεν έχουν cache headers, κάθε visitor κατεβάζει κάθε asset σε κάθε page load. Οι visitors που επιστρέφουν τα κατεβάζουν όλα ξανά. Ένα crawler τα κατεβάζει δεκάδες φορές την ημέρα.

# Fingerprinted build assets never change — cache them for a year
Cache-Control: public, max-age=31536000, immutable

# HTML changes — revalidate but allow a short window
Cache-Control: public, max-age=0, must-revalidate

# Anything user-specific
Cache-Control: private, no-store

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

3. APIs που επιστρέφουν περισσότερα από όσα χρησιμοποιεί ο client

Ένα list endpoint που επιστρέφει ολόκληρα objects ενώ το UI εμφανίζει τρία fields στέλνει τη διαφορά σε κάθε request, για πάντα. Δεν εμφανίζεται ποτέ στο profiling επειδή είναι γρήγορο — είναι απλώς μεγάλο.

Έλεγξε δύο πράγματα στα endpoints με τη μεγαλύτερη κίνηση:

  • Είναι ενεργοποιημένο το compression; Το Content-Encoding: gzip ή br στο JSON συνήθως το μειώνει κατά 70–80%. Είναι μία γραμμή middleware και συχνά λείπει.
  • Στέλνεις fields που δεν διαβάζει κανείς; Το να κάνεις serialize ολόκληρη τη row επειδή το ORM το έκανε εύκολο είναι η προεπιλεγμένη συμπεριφορά των περισσότερων codebases.

Ένας polling client κάνει και τα δύο χειρότερα, ανάλογα με το πόσες φορές το λεπτό κάνει polling.

4. Traffic μεταξύ regions και services

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

Η κίνηση μεταξύ των δικών σου services μπορεί επίσης να θεωρηθεί egress αν βγει από το private network και επιστρέψει μέσω public hostname. Δύο services στο ίδιο workspace που επικοινωνούν μέσω των public URLs τους πληρώνουν δύο φορές για μια συνομιλία που δεν χρειαζόταν ποτέ να βγει εκτός δικτύου.

Στο Dockup αυτό το συγκεκριμένο λάθος είναι δύσκολο να γίνει, επειδή τα services επικοινωνούν μεταξύ τους μέσω internal name. Ένα service προσεγγίζει το main-db.internal:5432 και ένα άλλο service μέσω του alias <slug>.internal — η κίνηση που παραμένει μέσα στο workspace network δεν περνά ποτέ από public listener. Αυτός είναι επίσης ο λόγος για τον οποίο η database δεν έχει public hostname by default: δεν υπάρχει κάτι που θα μπορούσε να δρομολογηθεί κατά λάθος μέσω αυτού.

Εντόπισέ το αντί να μαντεύεις

Το να μαντεύεις ποια από τις τέσσερις αιτίες ισχύει σπαταλά έναν billing cycle. Κάνε μετρήσεις:

Διάβασε το access log με βάση τα bytes, όχι το πλήθος. Ταξινόμησε τα κορυφαία responses με βάση τα συνολικά bytes που σερβίρονται και όχι με βάση το πλήθος των requests. Το endpoint που στέλνει τα περισσότερα δεδομένα σπάνια είναι αυτό που καλείται συχνότερα.

Έλεγξε τα μεγαλύτερα static assets. Αν οτιδήποτε πάνω από ένα megabyte σερβίρεται από την εφαρμογή σου, αυτό είναι το πρώτο πράγμα που πρέπει να μεταφέρεις.

# What is the service actually doing right now
dockup metrics my-project/my-api --json

# And what is it logging
dockup logs my-project/my-api -n 1000

Παρακολούθησε τα crawlers. Ένα bot που συμπεριφέρεται λανθασμένα και κατεβάζει επανειλημμένα μεγάλα αρχεία μπορεί να ευθύνεται για το μεγαλύτερο μέρος του μηνιαίου egress σε ένα site με μέτρια κίνηση από ανθρώπους. Το robots.txt και ένα noindex στα preview environments είναι οικονομικές λύσεις.

Τα environments που κανείς δεν υπολογίζει

Δύο συνήθειες δημιουργούν egress που δεν εμφανίζεται ποτέ στο mental model κανενός:

Preview environments. Ένα preview ανά pull request είναι πραγματικά χρήσιμο και αυξάνει αθόρυβα το footprint σου. Πέντε ανοιχτά PRs σημαίνουν πέντε αντίγραφα του stack σου, το καθένα με τη δική του κίνηση — συχνά από τα ίδια crawlers, επειδή τα preview URLs γίνονται indexed αν δεν τα σταματήσεις.

Long-lived staging. Το staging που λειτουργεί εδώ και οκτώ μήνες, χωρίς να το επισκέπτεται κανείς, συνεχίζει να κατεβάζει images, να δέχεται crawlers και να εκτελεί τα cron jobs του.

Κανένα από τα δύο δεν είναι λόγος να σταματήσεις να τα χρησιμοποιείς. Είναι όμως λόγος να τους βάλεις όρια: κάνε expire τα previews όταν κλείνει το PR και δήλωσέ τα ως noindex, ώστε οι search engines να σταματήσουν να τα κατεβάζουν για λογαριασμό σου.

dockup noindex my-project/my-api --on

Πώς μοιάζει ένα σωστό billing setup

Πρέπει να μπορείς να απαντήσεις σε τρεις ερωτήσεις πριν φτάσει το invoice:

  1. Τι εκτελείται αυτή τη στιγμή; Συμπεριλαμβανομένων όσων έχεις ξεχάσει.
  2. Τι κατανάλωσε το καθένα; Χωριστά σε compute και transfer, όχι ως έναν ενιαίο αριθμό.
  3. Τι συμβαίνει αν υπάρξει spike; Ένα cap που σταματά services είναι δυσάρεστο. Ένα cap που δεν υπάρχει είναι χειρότερο.

Το Dockup μετρά την υποδομή ξεχωριστά από το plan, επομένως το plan fee δεν κρύβει τη χρήση — και το credit των $20 του Pro plan εφαρμόζεται στη χρήση αντί να αποτελεί έκπτωση στο fee. Το σημαντικό είναι ότι βλέπεις καθαρά ποιο είναι το ένα και ποιο το άλλο.

Η σύντομη εκδοχή

Μετέφερε τα media σε object storage. Ρύθμισε cache headers. Ενεργοποίησε το compression. Κράτησε τα services και τις databases τους στο ίδιο region και άφησέ τα να επικοινωνούν μέσω του private network αντί για το public internet. Κάνε expire τα preview environments και κράτησέ τα εκτός των search results.

Αυτές οι πέντε συνήθειες αντιμετωπίζουν σχεδόν κάθε απρόσμενο λογαριασμό bandwidth και καμία δεν απαιτεί να αλλάξεις το σημείο όπου κάνεις hosting.

Συχνές ερωτήσεις

Τι είναι το egress; Δεδομένα που φεύγουν από την υποδομή σου προς το internet. Responses προς users, αρχεία που κατεβαίνουν, API payloads. Το inbound traffic συνήθως είναι δωρεάν· το outbound συνήθως όχι.

Γιατί ο λογαριασμός egress είναι υψηλότερος από τον λογαριασμό compute; Σχεδόν πάντα επειδή η εφαρμογή σερβίρει αρχεία που ανήκουν σε CDN. Ένα μεμονωμένο μεγάλο asset σε μια δημοφιλή σελίδα μπορεί να ξεπεράσει εβδομάδες request handling.

Μειώνει πράγματι το κόστος ένα CDN; Ναι, όταν κάνει cache. Το origin σερβίρει το αρχείο μία φορά ανά edge αντί για μία φορά ανά visitor, ενώ η τιμή του CDN ανά gigabyte είναι συνήθως ένα κλάσμα της τιμής μιας application platform.

Κοστίζουν τα preview environments όσο και το production; Κοστίζουν ανάλογα με την κατανάλωσή τους, η οποία συχνά είναι μεγαλύτερη από το αναμενόμενο, επειδή το καθένα είναι ένα πλήρες αντίγραφο και τα preview URLs γίνονται crawled αν δεν το αποτρέψεις.