Tytuł oryginału: Building Scalable Web Sites Tłumaczenie: Mikołaj Szczepaniak ISBN: 978-83-246-5986-9 © Helion S.A. 2007 Authorized translation of the English edition of Building Scalable Web Sites © 2006 O’Reilly Media, Inc. This translation is published and sold by permission of O’Reilly Media, Inc., the owner of all rights to publish and sell the same. Polish language edition published by Helion S.A. Copyright © 2007 All rights reserved. No part of this book may be reproduced or transmitted in any form or by any means, electronic or mechanical, including photocopying, recording or by any information storage retrieval system, without permission from the Publisher. Wszelkie prawa zastrzeżone. Nieautoryzowane rozpowszechnianie całości lub fragmentu niniejszej publikacji w jakiejkolwiek postaci jest zabronione. Wykonywanie kopii metodą kserograficzną, fotograficzną, a także kopiowanie książki na nośniku filmowym, magnetycznym lub innym powoduje naruszenie praw autorskich niniejszej publikacji. Wszystkie znaki występujące w tekście są zastrzeżonymi znakami firmowymi bądź towarowymi ich właścicieli. Autor oraz Wydawnictwo HELION dołożyli wszelkich starań, by zawarte w tej książce informacje były kompletne i rzetelne. Nie biorą jednak żadnej odpowiedzialności ani za ich wykorzystanie, ani za związane z tym ewentualne naruszenie praw patentowych lub autorskich. Autor oraz Wydawnictwo HELION nie ponoszą również żadnej odpowiedzialności za ewentualne szkody wynikłe z wykorzystania informacji zawartych w książce. Wydawnictwo HELION ul. Kościuszki 1c, 44-100 GLIWICE tel. 032 231 22 19, 032 230 98 63 e-mail: [email protected] WWW: http://helion.pl (księgarnia internetowa, katalog książek) Drogi Czytelniku! Jeżeli chcesz ocenić tę książkę, zajrzyj pod adres http://helion.pl/user/opinie?skalow_ebook Możesz tam wpisać swoje uwagi, spostrzeżenia, recenzję. Printed in Poland. • Poleć książkę na Facebook.com • Księgarnia internetowa • Kup w wersji papierowej • Lubię to! » Nasza społeczność • Oceń książkę Spis treści Przedmowa.....................................................................................................................7 1. Wprowadzenie.............................................................................................................15 Czym jest aplikacja internetowa? 15 Jak budujemy aplikacje internetowe? 16 Czym jest architektura? 17 Od czego należy zacząć? 18 2. Architektura aplikacji internetowej............................................................................21 Wielowarstwowa architektura oprogramowania 21 Technologie wielowarstwowe 24 Projektowanie interfejsów programowych 27 Droga od punktu A do punktu B 29 Podział na oprogramowanie i sprzęt 31 Platformy sprzętowe 31 Rozwój platformy sprzętowej 36 Nadmiarowość sprzętu 39 Sieć 40 Języki, technologie i bazy danych 43 3. Środowiska wytwarzania oprogramowania..............................................................45 Trzy naczelne zasady 45 Kontrola kodu źródłowego 46 Kompilacja w jednym kroku 66 Śledzenie błędów 77 Skalowanie modelu wytwarzania aplikacji 85 Standardy kodowania 86 Testowanie 89 3 4. i18n, L10n i Unicode......................................................................................................93 Umiędzynarodowienie i lokalizacja oprogramowania 94 Unicode w pigułce 98 Schemat kodowania UTF-8 104 Schemat kodowania UTF-8 w aplikacjach internetowych 105 Stosowanie schematu kodowania UTF-8 w języku PHP 107 Stosowanie schematu kodowania UTF-8 w pozostałych językach programowania 108 Stosowanie schematu kodowania UTF-8 w bazach danych MySQL 109 Stosowanie schematu kodowania UTF-8 w wiadomościach poczty elektronicznej 111 Stosowanie schematu kodowania UTF-8 w skryptach języka JavaScript 113 Stosowanie schematu kodowania UTF-8 w interfejsach API 115 5. Integralność danych i bezpieczeństwo......................................................................117 Strategie zapewniania integralności danych 117 Dobre, prawidłowe i nieprawidłowe 119 Filtrowanie sekwencji UTF-8 120 Filtrowanie znaków sterujących 126 Filtrowanie kodu HTML 127 Ataki XSS 131 Wstrzykiwanie kodu języka SQL 140 6. Poczta elektroniczna..................................................................................................147 Otrzymywanie wiadomości poczty elektronicznej 147 Ryzyko wstrzykiwania wiadomości poczty elektronicznej do naszej aplikacji 150 Format MIME 152 Analiza składniowa prostych wiadomości MIME 154 Analiza składniowa załączników zakodowanych w trybie UU 156 Załączniki w formacie TNEF 157 Dlaczego technologie bezprzewodowe nie lubią programistów? 159 Zbiory znaków i schematy kodowania 162 Rozpoznawanie użytkowników 164 Testy jednostkowe 167 7. Usługi zdalne..............................................................................................................169 Klub usług zdalnych 169 Gniazda 170 Stosowanie protokołu HTTP 173 Nadmiarowość usług zdalnych 179 Systemy asynchroniczne 182 Wymiana danych w formacie XML 187 Lekkie protokoły 192 4 | Spis treści 8. Wąskie gardła.............................................................................................................197 Identyfikowanie wąskich gardeł 197 Operacje wejścia-wyjścia 212 Usługi zewnętrzne i czarne skrzynki 225 9. Skalowanie aplikacji internetowych.........................................................................241 Mit skalowania 241 Skalowanie sieci 253 Równoważenie obciążeń 256 Skalowanie bazy danych MySQL 272 Replikacja baz danych MySQL 278 Partycjonowanie bazy danych 287 Skalowanie wielkich baz danych 292 Skalowanie pamięci masowej 294 Pamięć podręczna 302 Skalowanie w pigułce 305 10. Statystyki, monitorowanie i wykrywanie usterek....................................................307 Śledzenie statystyk aplikacji internetowej 307 Monitorowanie aplikacji 318 Alarmowanie 336 11. Interfejsy API..............................................................................................................339 Kanały danych 339 Technologie mobilne 352 Usługi sieciowe 356 Warstwy transportowe interfejsów API 359 Nadużywanie interfejsów API 367 Uwierzytelnianie 371 Przyszłość 375 Skorowidz...................................................................................................................377 Spis treści | 5 6 | Spis treści Przedmowa Swoją pierwszą aplikację internetową nazwałem Terrania. Jej użytkownik odwiedzający strony tej aplikacji mógł tworzyć wirtualne istoty, modyfikować ich parametry i obserwować, jak sobie radzą w wymyślonym przeze mnie wirtualnym świecie. Stworzenia użytkowników mojej aplikacji tułały się po świecie, jadły rośliny (lub pożerały inne stworzenia), staczały bitwy i zaprzyjaźniały się ze stworzeniami pozostałych użytkowników. Każdy użytkownik otrzymywał dwa razy dziennie wiadomość poczty elektronicznej podsumowującą zdarzenia związane z funkcjonowaniem jego przedstawiciela w wirtualnym świecie. Nazywanie tego systemu aplikacją internetową jest pewnym nadużyciem — w tamtym czasie nie przyszłoby mi do głowy zaliczanie mojego dzieła do tej kategorii. Podstawowym elementem mojej gry był program napisany w C++, który pracował na pojedynczym komputerze, odczy- tywał dane gry z pojedynczego pliku tekstowego, przetwarzał te dane w każdym „cyklu” i ponownie zapisywał zmodyfikowane informacje o stanie gry we wspomnianym pliku. Kiedy przystąpiłem do prac nad tym programem, zakładałem, że jego środowisko będzie się składało z komponentu serwera pracującego w tradycyjnej architekturze klient-serwer. Programowanie mechanizmów wymiany danych za pośrednictwem sieci było wówczas dość trudne i wymagało pisania sporej ilości kodu odpowiedzialnego za samo uzgadnianie ustawień pomiędzy serwerem a klientem (w tamtym czasie nikt nie słyszał o takich technologiach jak .NET). Z perspektywy programistów aplikacji strony WWW są doskonałą, gotową do użycia platformą dla danych przesyłanych za pośrednictwem internetu, która eliminuje najtrudniejsze elementy aplikacji klient-serwer. Dopiero strony WWW stworzyły możliwość swobodnego pisania skomplikowanego oprogramowania serwerów odpowiedzialnych za wykonywanie właściwych działań i konstruowania nieporównanie prostszych klientów w formie dokumentów języka HTML. Tradycyjny komponent kliencki systemu Terrania musiał uzyskiwać dostęp do tego samego pliku tekstowego, który był wykorzystywany przez komponent serwera. Nowy model aplikacji internetowych umożliwił stworzenie systemu, w którym działanie „aplikacji klienckich” (czyli po prostu stron internetowych) sprowadzało się do umieszczenia danych w pamięci, przetwarzania informacji o istocie utworzonej przez danego gracza i wyświetleniu ich w formie statycznego kodu języka HTML. Dodanie nowego stworzenia polegało na dołączenie bloku danych na końcu drugiego pliku, którego zawartość była przetwarzana i integrowana z głównym plikiem serwera w każdym cyklu. Za wszystkie operacje związane z właściwym przetwarzaniem danych (włącznie z wysyłaniem wiadomości poczty elektronicznej) odpowiadał komponent serwera. Interfejs kliencki serwera WWW miał postać prostej, kilkusetwierszowej aplikacji C++ CGI przystosowanej do wykonywania analizy składniowej pliku z danymi o stanie gry. 7 System w tej postaci pracował w sposób zadowalający — być może nie zdawałem sobie wówczas sprawy z istniejących ograniczeń, ponieważ moja aplikacja nigdy nie zyskała wystarczającej popularności. Brak zaawansowanych mechanizmów obsługujących interakcję z użytkownikiem (za pośrednictwem interfejsu WWW) nie stanowił większego problemu, ponieważ ten tryb pracy był zgodny z moim oryginalnym projektem. Jedyną operacją zapisu inicjowaną przez gracza było początkowe tworzenie istoty w świecie wirtualnym. Wszystkie pozostałe elementy funkcjo- nalności mojej gry miały postać procesów dostępnych w trybie tylko do odczytu. Innym problemem, z którego w owym czasie nie zdawałem sobie sprawy, było nieprzystosowanie omawianej gry do przetwarzania współbieżnego. Ponieważ system Terrania był w dużej mierze programem oferującym funkcje tylko do odczytu, niemal nieograniczona liczba graczy mogła żądać jednoczesnego generowania stron internetowych. Wszystkie operacje zapisu sprowadzały się do dołączania nowych wierszy do pliku tekstowego, które przebiegało na tyle szybko, że nie zdecydowałem się na zastosowanie żadnego mechanizmu blokowania dostępu. W tamtym czasie liczba graczy była na tyle niewielka, że prawdopodobieństwo jednoczesnego wysłania więcej niż jednego żądania odczytu lub zapisu było minimalne. Minęło kilka lat, zanim stanąłem przed koniecznością opracowania czegoś, co w dużo większym stopniu przypominało dzisiejsze aplikacje internetowe. Kiedy pracowałem w agencji reklamowej, która właśnie rozpoczynała działalność, zostałem poproszony o takie zmodyfikowanie istniejących dokumentów HTML-a, aby przystosować je do współpracy z systemem forum internetowego UBB (Ultimate Bulletin Board firmy Groupee, Inc.). System UBB miał postać aplikacji napisanej w Perlu i pracującej w technologii CGI. Elementy danych naszej aplikacji (w tym konta użytkow- ników i wpisy umieszczane na forum, które były przedmiotem szczególnego zainteresowania z mojej strony) były składowane w zwykłych plikach tekstowych, w jakimś niestandardowym formacie. Niektóre strony tej aplikacji były generowane dynamicznie (na podstawie danych odczytywanych na bieżąco z plików tekstowych); inne miały postać zwykłych dokumentów HTML-a tworzonych i — w razie potrzeby — zapisywanych na dysku przez samą aplikację. Technika zapisywania generowanych stron na dysku nadal jest praktykowana w systemach cechujących się niewielką liczbą operacji zapisu i bardzo dużą częstotliwością wykonywania operacji odczytu, czyli na przykład w aplikacjach obsługujących blogi, gdzie koszt wygenerowa- nia strony przekracza koszt zapisania pliku na dysku (mimo że taki zapis też jest stosunkowo nieefektywną operacją). Największą zaletą systemu UBB był fakt, że napisano go w Perlu, czyli języku skryptowym. Brak konieczności kompilowania kodu źródłowego znacznie skraca cykle wytwarzania oprogramowania i — tym samym — przekłada się na spore oszczędności czasowe. Kod źródło- wy systemu UBB podzielono pomiędzy trzy główne pliki: skrypty punktu końcowego będące właściwym przedmiotem żądań użytkowników oraz dwa pliki bibliotek zawierające niezbędne funkcje pomocnicze (nazwane ubb_library.pl oraz ubb_library2.pl). Po zdobyciu doświadczenia w pracy z systemem UBB i zrealizowaniu projektów dla kilku klientów komercyjnych zaangażowałem się w działalność społeczności „łamiącej” systemy forów internetowych — była to dość osobliwa grupa programistów, którzy poświęcali swój wolny czas na próby rozszerzania funkcjonalności istniejących wówczas platform forów internetowych. Swój udział w tym projekcie rozpocząłem od założenia witryny internetowej, nazwanej UBB Hackers, we współpracy z kolegą, który później został programistą w firmie Infopop, gdzie pracował nad następną wersją systemu UBB. Wczesne wersje systemu UBB oferowały bardzo niewiele w obszarze współbieżności, ponieważ korzystały z nieprzenośnego kodu blokującego dostęp do plików, który nie działał między innymi w systemie operacyjnym Windows (czyli jednej z platform docelowych). Jeśli dwoje 8 | Przedmowa użytkowników jednocześnie wysyłało swoje wypowiedzi w ramach tego samego wątku, mogła nastąpić utrata spójności danych składowanych w pliku właściwym dla tego wątku (polegająca na utracie części informacji). Wraz ze wzrostem liczby użytkowników takiego systemu rosło ryzyko uszkodzenia danych i występowania tzw. sytuacji wyścigów (ang. race conditions). W przypadku najbardziej aktywnych systemów samo zapisywanie na dysku dokumentów HTML prowadziło do powstawania wąskich gardeł dyskowych operacji wejścia-wyjścia. Obecnie nietrudno wskazać kolejny krok rozwoju opisywanego oprogramowania, jednak w tamtym czasie rozwiązywanie podobnych problemów nie było tak oczywiste. Wiele zmian w świecie aplikacji internetowych zostało spowodowanych wydaniem systemu zarządzania bazą danych MySQL3. Przed wydaniem i popularyzacją tego systemu używanie baz danych do utrwalania informacji przetwarzanych przez aplikacje internetowe było dość trudne. Istniejące technologie baz danych były albo bardzo drogie (jak Oracle), albo powolne i trudne w użyciu (jak FileMaker), albo wyjątkowo skomplikowane w konfiguracji i konserwacji (jak PostgreSQL). Dopiero dostępność systemu MySQL3 sprawiła, że sytuacja zaczęła ulegać zmianie. Mniej więcej w tym samym czasie popularność zyskiwał język PHP4 i rozpoczynały się szeroko zakrojone prace nad projektem phpMyAdmin. Projekt phpMyAdmin miał na celu zapewnienie programistom aplikacji internetowych możliwości pracy z bazami danych bez konieczności zapoznawania się z dziwacznymi mechanizmami FileMakera ani zgłębiania arkanów języka SQL i niewygodnych narzędzi obsługiwanych w wierszu poleceń. To, że wciąż nie udało mi się zapamiętać prawidłowej składni wyrażeń tworzących nowe tabele czy przydzielających nowemu użytkownikowi uprawnienia dostępu, nie jest żadną przeszkodą, ponieważ obecnie taka wiedza jest mi zupełnie niepotrzebna. System MySQL wielu programistów wprowadził w świat przetwarzania współbieżnego — nareszcie mogliśmy w tym samym czasie odczytywać i zapisywać dane bez obaw o ich przypadkowe uszkodzenie. Ciągły rozwój samego systemu MySQL zapewniał coraz większe możliwości w zakresie przetwarzania współbieżnego i coraz większą wydajność budowanych aplikacji. Nowe rozwiązania były nieporównanie lepsze od stosowanych wcześniej plików tekstowych i technologii zapisywania gotowych stron na dysku. Wprowadzenie indeksów umożliwiło błyskawiczne odnajdywanie rekordów w ogromnych zbiorach danych (uporząd- kowanych w dowolny sposób) bez konieczności umieszczania całych tabel w pamięci i żmud- nego przeszukiwania złożonych struktur. Okazało się, że nasze możliwości są wręcz nieograni- czone. I tak jest nadal. Programiści aplikacji internetowych nie ustają w wysiłkach nad pokonywaniem kolejnych barier w takich obszarach, jak skala systemów, oferowana funkcjonalność czy współoperatyw- ność. Świat niezliczonych, publicznych interfejsów API stwarza możliwość efektywnego łączenia wielu aplikacji, które doskonale wpisują się w kulturę zorientowaną na usługi. Popularność modelu usług z interfejsami API w sposób oczywisty dowodzi, że można niewielkim kosztem tworzyć architektury gwarantujące zarówno elastyczność, jak i wprost nieograniczoną skalo- walność. Największe i najbardziej popularne obecnie aplikacje internetowe, czyli Flickr, Friendster, MySpace i Wikipedia, wykonują miliardy dziennie zapytań na bazie danych, przetwarzają ogromne zbiory danych i pracują na niezwykle rozbudowanych platformach sprzętowych, złożonych z niezliczonych serwerów i urządzeń sieciowych. Chociaż za przykład wielkich aplikacji internetowych bardzo często podaje się witrynę Google, właśnie wymienione, nieco O czym jest ta książka | 9 mniejsze (ale wciąż ogromne) aplikacje powinny stanowić wzór do naśladowania dla twórców rozwiązań następnej generacji, którym coraz częściej przypisuje się etykietę Web 2.0. Zwiększona częstotliwość wykonywania operacji odczytu i zapisu, zwielokrotnione obciążenie sieci i koniecz- ność udostępniania interfejsów API sprawiają, że procesy wytwarzania i rozwoju aplikacji internetowych nowej generacji zapowiadają się bardzo ciekawie. O czym jest ta książka Niniejsza książka jest poświęcona przede wszystkim problemom związanym z projektowaniem aplikacji internetowych, a konkretnie z projektowaniem oprogramowania i platform sprzętowych dla aplikacji internetowych. Zajmiemy się architekturami aplikacji, dobrymi praktykami procesów wytwarzania, dostępnymi technologiami, standardem Unicode i ogólnymi zadaniami składają- cymi się na budowę niezbędnej infrastruktury. Co ważne, nie pominiemy zagadnień związanych z samym wytwarzaniem aplikacji, w tym z dobrymi praktykami budowy platformy sprzętowej i implementowania zaprojektowanych wcześniej systemów oprogramowania. Znajomość teorii projektowania aplikacji jest oczywiście pożądana (bez niej realizacja całego procesu byłaby wręcz niemożliwa), powinniśmy jednak pamiętać o roli, jaką w skomplikowanej konstrukcji wielkich aplikacji odgrywa implementacja. Świadomość tej roli powinniśmy stale zachowywać w pamięci podczas prac nad projektem. Jeśli zaprojektujemy coś, czego nie będziemy w stanie zbudować, nie będziemy nawet mieli okazji sprawdzić, czy nasz projekt jest właściwy. Niniejsza publikacja nie jest książką o programowaniu, a przynajmniej nie jest typowym podręcznikiem programisty. Zamiast nieustannie analizować fragmenty kodu źródłowego, posługiwać się nazwami funkcji itp., zajmiemy się bardziej ogólnymi technikami i strategiami budowy aplikacji internetowych. Chociaż można w tej książce znaleźć kilka przykładowych fragmentów kodu, ich prezentowanie ma na celu wyłącznie ilustrację omawianych zagadnień. Większość przedstawionych w tej książce przykładowych fragmentów kodu źródłowego może być stosowana wyłącznie w kontekście większej aplikacji lub infrastruktury. Znaczna część problemów poruszanych w tej książce ma ścisły związek z projektowaniem architektury aplikacji i konstruowaniem jej infrastruktury. W świecie aplikacji internetowych mianem infrastruktury określa się zwykle kombinację platformy sprzętowej, platformy progra- mowej, procedur utrzymania i konserwacji oraz praktyk programistycznych. W kolejnych rozdziałach tej książki dokładnie przeanalizujemy wpływ tych elementów na możliwości konstruowania efektywnej infrastruktury dla aplikacji wielkiej skali. Najdłuższy rozdział niniejszej książki (rozdział 9.) poświęcono wyłącznie problematyce skalowa- nia aplikacji internetowych, a więc przede wszystkim metodom projektowania architektur z myślą o przyszłej zmianie skali oraz technologiom i technikom ułatwiającym skalowanie istniejących systemów. Ponieważ przeprowadzenie wyczerpującej analizy wszystkich tych zagadnień w jednym rozdziale byłaby niezwykle trudne (w praktyce omówienie samych podstaw mogłoby zająć całą książkę), zdecydowałem się wybrać kilka najważniejszych i najsku- teczniejszych strategii w kontekście typowych wymagań. Należy oczywiście pamiętać o istnieniu wielu innych koncepcji, które — choć nie zostały przedstawione w tej książce — z pewnością zasługują na uwagę. Czytelników zainteresowanych pogłębieniem wiedzy o świecie skalowalnych infrastruktur zachęcam do sięgnięcia po książkę Performance by Design: Computer Capacity Planning by Example (Prentice Hall). 10 | Przedmowa