Zasady były proste. Każdy użytkownik mógł wybrać jeden z 16 kolorów i pomalować nim jeden piksel w dowolnym miejscu na płótnie. Możesz pomalować dowolną liczbę pikseli i na dowolne kolory, ale aby przemalować kolejny piksel, trzeba było poczekać 5 minut.
To prawda, że zasady mówiły: „Współpracując z innymi, możesz stworzyć znacznie więcej niż tylko działanie w pojedynkę”.
To, co wydarzyło się w ciągu następnych 72 godzin, wprawiło organizatorów w szok. To pojawiło się na pustym płótnie:
Każdy piksel na płótnie został umieszczony ręcznie. Każda ikona, każda flaga, każdy mem został pieczołowicie stworzony przez setki tysięcy ludzi, których nie łączyło nic poza połączeniem internetowym. Tak czy inaczej to, co wydarzyło się na Reddicie, można słusznie uznać za narodziny sztuki.
Jak to wszystko się stało
Nie da się tego opisać w kilku słowach. Na płótnie rozgrywały się niezliczone dramaty – walki, bitwy i wojny, czasem nawet z nieznanych przyczyn. Prowadzono je na małych forach, w prywatnych rozmowach, było ich tak dużo i wszystkie działy się na raz, że nie sposób było wszystkiego śledzić. Ogólnie płótno pokazało wieczna historia o trzech siłach niezbędnych do stworzenia ludzkości.
Twórcy
Twórcy byli pierwsi. Byli to artyści, dla których czyste płótno ma nieodparty urok.
Twórcy zaczęli losowo zmieniać kolor pikseli, aby zobaczyć, co mogą zrobić. Dlatego pierwsze rysunki wyglądały bardziej podobnie sztuka naskalna– artyści dopiero zaczynali rozwijać skrzydła.
Dość szybko zdali sobie sprawę, że pracując w pojedynkę i umieszczając tylko jeden piksel co 5-10 minut, nie da się stworzyć niczego znaczącego. Ktoś na pewno zrujnuje ich pracę. Aby stworzyć coś większego, muszą współpracować.
A potem ktoś zasugerował narysowanie siatki, która wyraźnie wskazywałaby, gdzie należy namalować kolejny piksel, aby uzyskać spójny obraz. Tak w lewym dolnym rogu płótna pojawił się Dickbutt – słynny internetowy mem, owoc nastoletniego poczucia humoru. Stało się to pierwszym wspólnym dziełem.
Ale twórcy na tym nie poprzestali. Zaczęli dodawać różne elementy do Dickbutta, malować go na różne kolory, a nawet próbowali przekształcić go w Dickbutterfly. Za tym głupim pomysłem kryła się aluzja do zbliżającego się twórczego tsunami.
Nie stało się to jednak natychmiast. Twórcy byli odurzeni swoją mocą. Pokemon Charmander pojawił się obok Dickbutta i zamiast łapy zaczął rosnąć penis, a potem jeszcze dwa.
To już nie był projekt. Niektórzy twórcy desperacko próbowali usunąć prowokacyjne dodatki, nawołując do „czystej” sztuki, inni natomiast kontynuowali swoje. Ale tego tam nie było.
Stało się jasne, że zbyt duża wolność prowadzi do chaosu. Kreatywność potrzebuje ograniczeń tak samo jak wolności. Skoro ktoś może umieścić dowolny piksel w dowolnym miejscu, jak może to nie doprowadzić do chaosu?
Strażnicy
Problem ten został bardzo szybko rozwiązany przez innego typu użytkowników – opiekunów. Przybyli z jednym celem – podbić cały świat.
Tworząc frakcje według koloru, zaczęli podbijać przestrzeń, malując ją na określony kolor. Jedną z pierwszych i największych frakcji była frakcja Niebieskiego Zakątka. Pojawiając się w prawym dolnym rogu, rozprzestrzenił się jak zaraza. Jej zwolennicy głosili, że w ten sposób należy pokryć całą przestrzeń płótna. Piksel po pikselu zaczęli przekładać swój pomysł na rzeczywistość, wkrótce zajmując ogromne obszary.
Blue Corner nie był w swoich dążeniach odosobniony. Po drugiej stronie płótna pojawiła się kolejna grupa - Czerwony Narożnik (czerwony róg). Jej uczestnicy deklarowali, że są zwolennikami lewicy. poglądy polityczne. Inna grupa - Green Lattice (zielona krata) - zaczęła wszędzie przeplatać zielone i białe piksele. Wykazała się dużą wydajnością, gdyż musiała pomalować o połowę mniej pikseli niż inne frakcje.
Strażnicy przypuścili frontalny atak na twórców. Charmander stał się pierwszą lokacją bitwy. Po odkryciu, że Blue Corner zaczął wypełniać Pokemony niebieskimi pikselami, twórcy zdali sobie sprawę z zagrożenia i powstrzymali wewnętrzne wojny.
Walczyli, zastępując każdy niebieski piksel swoim własnym. Ale siły nie były równe. Dzięki swojej determinacji Blue Corner zgromadził znacznie większą armię niż jej twórcy. A jedyne, co twórcy mogli w takiej sytuacji zrobić, to błagać o życie.
I w jakiś sposób to odwróciło losy. Blue Corner rozpoczął debatę na temat swojej roli w proces twórczy. Jeden z uczestników zapytał: „Skoro nasza fala nieuchronnie całkowicie zawładnie światem, czy powinniśmy okazywać miłosierdzie innym formom sztuki, które spotykamy?”
To było pytanie, które prędzej czy później pojawiło się przed każdą frakcją. Co mieli zrobić ze sztuką, która stanęła im na drodze, mimo całej ich ekspansjonistycznej gorliwości?
To stało się punkt zwrotny. Bezmyślne frakcje stały się obrońcami.
Ale to jeszcze nie był koniec
W świecie pełnym drapieżnych kolorów twórcy mogli wrócić do swoich dzieł. Dodając jeden element po drugim, zaczęli je komplikować. Używając czcionek trzypikselowych, zaczęliśmy pisać teksty. Jednym z najbardziej znanych dzieł był prequel Gwiezdnych Wojen.
Twórcy zjednoczyli się w grupach pracujących nad wspólnym projektem. Dzielili się między sobą strategiami i wzorcami. Jednym z najbardziej udanych była grupa, która stworzyła panel Windows 95 z przyciskiem Start w rogu.
Inni stworzyli blok serc, taki jak te ze starych gier wideo, takich jak Zelda. Tylko kilka osób rozpoczęło ten projekt, ale szybko dołączyli do nich inni i ostatecznie serca, pomalowane w kolorach różnych flag, rozciągnęły się na połowie płótna.
Inna grupa odtworzyła „Gwiaździstą noc” Van Gogha.
Jednak nie wszystko poszło gładko. Zwolennicy, którzy niegdyś celebrowali tworzenie dzieł sztuki, stali się tyranami dyktującymi modę. Zaczęto wskazywać, co można stworzyć, a czego nie. Zaczęło się na krótko przed tym, jak twórcy zaczęli tworzyć według własnych zasad.
Frakcje zwróciły na siebie spojrzenia, żądając, aby ich wyznawcy stanęli po którejś stronie w epickich bitwach. Nie mieli czasu zwracać uwagi na żałosne prośby twórców pragnących aprobaty dla idei nowej sztuki.
Walki pomiędzy obrońcami zaostrzyły się. Transmisje na żywo na Twitchu zachęcały swoich obserwujących do atakowania Blue Corner i Purple. Powstały plany bitwy. Odwoływał się do emocji.
Zdarzały się nawet fałszywe ataki, podczas których wyznawcy tego samego koloru umieszczali piksele przeciwników w swoich, aby mogli złożyć skargę dotyczącą naruszenia i odpowiedzieć atakiem.
Największym problemem była jednak sztywna zasada – płótna nie można powiększać. Zarówno walczące frakcje, jak i twórcy zaczęli zdawać sobie sprawę, że po prostu nie będzie już miejsca na nową sztukę.
Od samego początku na płótnie pojawiły się flagi różne kraje. Rosły i wpadały na siebie. Pomiędzy flagami Niemiec i Francji wybuchła prawdziwa epicka bitwa. Stało się jasne, że do zagospodarowania nowych przestrzeni potrzebny jest pośrednik.
Nagle świat, który na początku uniknął prymitywnych najazdów, był gotowy na wojnę totalną. Desperackie próby dyplomatycznego rozwiązania problemu prowadziły donikąd. Spotykając się na czacie przywódcy twórców i obrońcy tylko obwiniali się nawzajem.
Potrzebna była łasica, z którą każdy mógł się dogadać.
Niszczyciele
Serwis internetowy 4chan zwrócił uwagę na to, co działo się na Reddicie. I nie mogli przejść obok. Ich użytkownicy wybrali kolor najbliższy ich sercu – czerń. Stali się Pustką.
Gdy łza powoli rozlewa się po powierzchni, na środku płótna zaczęły pojawiać się czarne piksele, niszcząc wszystko na swojej drodze.
Początkowo inne frakcje próbowały zawrzeć z nimi sojusz, naiwnie wierząc, że dyplomacja zadziała. Ale im się to nie udało, ponieważ Pustka była inna.
Pustka nie była obrońcą. W przeciwieństwie do innych frakcji nie okazała żadnej lojalności wobec sztuki. Zwolennicy Pustki wyznawali destrukcyjny egalitaryzm pod hasłem „Próżnia wszystko pochłonie”. Nie nawiązali kontaktu z innymi. Chcieli po prostu pomalować cały świat na czarno.
I to było dokładnie to, czego wymagano. Znajdując się na skraju wyginięcia, wszyscy uczestnicy projektu zjednoczyli się, aby walczyć z Pustką, aby zachować swoją sztukę.
Ale Pustkę nie było tak łatwo pokonać, bo była potrzebna. Trzeba było wszystko zniszczyć, aby z popiołów odrodziła się nowa, najlepsza sztuka. A bez Pustki było to niemożliwe.
Zatem Pustka stała się katalizatorem stworzenia największe dzieło sztuka.
Od samego początku toczyła się zacięta walka o środkową część płótna. Twórcy zajęli to terytorium dla swoich dzieł. Początkowo próbowano to zrobić za pomocą ikon. Następnie w skoordynowanej próbie stworzenia pryzmatu takiego jak ten na okładce album Różowy Floyda tylna strona Księżyc."
Ale Pustka zjadła wszystko. Jedno dzieło za drugim tylko podsycało jej żarłoczny apetyt na chaos.
A jednak właśnie tego było potrzeba. Po zniszczeniu grafiki Void zmusił użytkowników do wymyślenia czegoś lepszego. Wiedzieli, że mogą pokonać czarnego potwora. Potrzebują tylko pomysłu z dobrym potencjałem, który przyciągnie wystarczającą liczbę zwolenników.
I ten pomysł stał się amerykańską flagą.
Ostatniego dnia projektu wszyscy zebrali się, aby raz na zawsze przegonić pustkę. Utworzono koalicję z ludzi, którzy w innej sytuacji rozerwaliby się nawzajem – ze zwolenników i przeciwników Trumpa, z Demokratów i Republikanów, z Amerykanów i Europejczyków.
Połączyli siły, aby stworzyć coś razem w tym małym zakątku Internetu, udowadniając, że w czasach, gdy taka współpraca wydaje się niemożliwa, nadal mogą to robić.
Starożytni mieli rację
Niedługo potem eksperyment na Reddicie dobiegł końca. Dziś towarzyszy mu wiele historii opowiadanych na dziesiątkach czatów. Na każde dzieło powstałe w ramach projektu nałożono setki nowych, z których na ostatecznym płótnie pozostało zaledwie kilka.
Ale chyba najbardziej zaskakujące jest to, że pomimo anonimowości i braku zakazów, na ostatecznym płótnie nie było żadnych symboli rasistowskich ani mizantropijnych. To był piękny cykl sztuki, życia i śmierci. I nie był pierwszy w naszej historii.
Wiele tysiącleci temu, kiedy ludzkość (prawdziwa, nie tylko ta na Reddicie) była jeszcze w powijakach, filozofowie hinduscy snuli teorię, że niebiosa składają się z trzech konkurujących ze sobą, ale niezbędnych bóstw: Brahmy Stwórcy, Wisznu Opiekuna i Śiwa Niszczyciel.
Nawet bez jednego z nich Wszechświat nie byłby w stanie funkcjonować. Aby było światło, konieczna jest ciemność. Aby życie mogło istnieć, konieczna jest śmierć. Dla stworzenia i sztuki musi nastąpić zniszczenie.
Kilka dni trwania projektu pokazało, że takie podejście okazało się prorocze. W najbardziej niesamowity sposób Reddit udowodnił, że tworzenie wymaga wszystkich trzech elementów.
Ostateczne malowanie
Świergot
Kieszeń
komunikator fb
Nie można powiedzieć, że 100% żartów korporacyjnych z okazji Dnia Humoru będzie udanych i wciągających. W tym roku administracja Reddita uruchomiła Place, czyli interaktywne płótno graficzne o wymiarach 1000 na 1000 pikseli i dedykowaną mu sekcję. Założono, że członkowie społeczności będą wspólnie malować to płótno, jak im się podoba. W efekcie przekształciło się to w walkę o Miejsce, czasem przeradzającą się w konfrontację filozoficzną. Zwykłe ćwiczenie rysunkowe zamieniło się w ekscytujący eksperyment społeczny. Historia została udokumentowana od początku do końca na blogu Sudoscript.
Zasady Miejsca były proste. Każdy uczestnik mógł wybrać jeden piksel spośród 16 kolorów i umieścić go w dowolnym miejscu na płótnie. Można było umieścić dowolną liczbę pikseli, ale pomiędzy kolejnymi miejscami trzeba było odczekać 5 minut. Po 72 godzinach te bardzo proste zasady doprowadziły do stworzenia niesamowitego zbiorowego płótna:
Każdy z widocznych powyżej pikseli został umieszczony ręcznie. Każda ikona, każda flaga, każdy mem został starannie stworzony przez tysiące ludzi, których nie łączyło nic poza połączeniem internetowym.
W czasie jego tworzenia doszło do niezliczonych dramatów, pomysłów, walk, a nawet wojen. Ale w ogóle historia Miejsca to odwieczny dramat o trzech siłach niezbędnych ludzkości do tworzenia, tworzenia i rozwijania technologii.
Twórcy
Najpierw byli twórcy. Byli to artyści, dla których puste płótno wydawało się nieodpartą szansą. Pierwsi artyści umieszczali piksele losowo, żeby zobaczyć, co mogą zrobić. Już w pierwszych minutach pojawiły się pierwsze szkice. Szorstkie i niedojrzałe, przypominały malowidła jaskiniowe przedstawiające jaskiniowców.
Twórcy od razu zobaczyli, jaką moc i potencjał kryją piksele. Ale pracując samodzielnie, mogliby umieszczać jeden piksel co 5 lub 10 minut. Stworzenie znaczącego rysunku zajęłoby całą wieczność. Aby coś narysować, musieli współpracować.
Wtedy ktoś wpadł na genialny pomysł, aby do rysowania wykorzystać siatkę, która będzie nałożona na rysunek i wskazywała, gdzie powinny znajdować się kolejne piksele. Pierwszym, który przeszedł ten eksperyment, był słynny mem anglojęzycznego Internetu Dickbutt. I mieszkańcy Place zabrali się do pracy: Dickbutt zmaterializował się dosłownie w ciągu kilku minut w lewym dolnym rogu płótna. Na Stronie pojawiło się pierwsze dzieło zbiorowej kreatywności.
Następnie, gdy twórcy nieco odurzyli się możliwościami, pojawił się Pokémon Charmander, który wkrótce zamiast nogi miał penisa. I zaczął się pierwszy konflikt: niektórzy twórcy pilnie starali się oczyścić obraźliwe rysunki, inni zaś uporczywie dodawali wulgaryzmy.
Twórcy stanęli przed zasadniczym zadaniem problem filozoficzny: Zbyt duża wolność prowadzi do chaosu. Kreatywność potrzebuje ograniczeń tak samo jak wolności.
Obrońcy
W Miejscu pojawił się inny typ użytkownika, który musiał zmierzyć się właśnie z tym problemem. Ale zaczęli od bardziej prymitywnych celów: podboju świata. Podzieleni na frakcje według koloru, próbowali zdobyć Miejsce. Jednym z pierwszych był Niebieski Zakątek. Zaczęło się w prawym dolnym rogu i rozprzestrzeniło się jak zaraza.
Inna grupa założyła Czerwony Zakątek po przeciwnej stronie płótna, skłaniając się ku lewicy politycznej. Inna grupa o nazwie Green Grid malowała płótno za pomocą pikseli – zielonych komórek przeplatanych białymi. Ponieważ musieli pomalować tylko połowę pikseli, byli bardziej wydajni niż inne frakcje.
Nie minęło dużo czasu, zanim frakcje starły się z twórcami. Charmander stał się jednym z pierwszych celów bitwy. Niebieski róg zaczął rysować Pokemony niebieskimi pikselami, a Twórcy przeszli z „wojen fallicznych” (którzy potrafią przyciągnąć najwięcej kutasów) na poważniejsze zagrożenie. Podjęli walkę, malując każdy niebieski piksel swoim własnym. Jednak przewaga ilościowa nie była na ich korzyść.
Twórcy poddali się więc łasce zwycięzcy i w jakiś sposób zraniło to uczucia Bluesa. Wśród nich znaleźli się tacy, którzy wątpili w swoją rolę w świecie Miejsca. „Nasza fala nieuchronnie obejmie cały świat, od końca do końca, jeśli okażemy miłosierdzie innej sztuce, którą spotkamy” – zapytał jeden z uczestników.
Każda frakcja stanęła przed tym pytaniem. I wszyscy postanowili zapisać inne rysunki. I tak fale koloru zaczęły opływać rysunki, nie malując ich.
To był punkt zwrotny. Bezmyślne kolorowe frakcje stały się użytecznymi Obrońcami.
Ale to jeszcze nie jest happy end
Wreszcie nienasycone fale koloru zostały zatrzymane, a Twórcy mogli wrócić do kreatywności. Rysunki stawały się coraz bardziej złożone. Pojawiły się teksty zapisane w pikselach.
Twórcy zjednoczyli się małe grupy, tworząc subreddity na Reddicie, gdzie można omawiać projekty rysunków i strategię. Jeden z najbardziej udane grupy Narysowałem pasek zadań w stylu Windows 95. Inny naszkicował Miejsce z sercami.
Potem pojawił się Van Gogh.
Ale to nie było takie proste. Obrońcy zamienili się w tyranów, dyktując styl rysunków. Decydowali, co można narysować, a czego nie. Frakcje zaczęły dzielić użytkowników między sobą, wzywając strony, podczas gdy Twórcy czekali na akceptację nowych pomysłów.
Walki pomiędzy Obrońcami stawały się coraz bardziej zacięte. Jeden ze streamerów na Twitchu namawiał swoich zwolenników do ataku na Blue. Opracowano strategie walki. Doszło nawet do prowokacji: fani tego samego koloru sami malowali na swoim terytorium piksele w kolorze wroga, aby mieć pretekst do odwetowego ataku. Podczas gdy frakcje walczyły między sobą, Twórcy odkryli, że nie ma już miejsca na nowe rysunki.
Zaczęły pojawiać się flagi różne kraje– gdy dorastali, nieuchronnie wpadali na siebie. Na przykład flagi Niemiec i Francji zderzyły się na „ziemi niczyjej”.
Wydawało się, że ten mały świat był na krawędzi wojny. Wszystkie strony próbowały rozwiązać konflikt dyplomatycznie. Przywódcy Twórców i Obrońców porozumiewali się na czacie, ale zazwyczaj kończyło się to wzajemnymi oskarżeniami.
To miejsce potrzebowało złoczyńcy, przeciwko któremu wszyscy mogliby się zjednoczyć.
Niszczyciele
Nadeszła pustka.
Zaczęło się od 4chan, najsłynniejszej tablicy graficznej na świecie. Zamieszkujący go dowcipnisie zauważyli, co dzieje się na Reddicie i nie mogli tego zignorować. Stali się Pustką.
Na środku Miejsca zaczęła rosnąć plama czarnych pikseli. Początkowo frakcje próbowały zawrzeć pakt z Pustką za pomocą dyplomacji. Ale im się nie udało, Pustka zachowała się inaczej. Nie należała do Obrońców, nie chroniła sztuki. Jej wyznawcy głosili, że Pustka pożre wszystko. Nie utworzyli żadnej strony, chcieli po prostu pomalować cały świat na czarno.
To był dokładnie kopniak w tyłek, jakiego potrzebowało Miejsce. W obliczu wspólnego zagrożenia Twórcy i Obrońcy ponownie zjednoczyli się, by ratować sztukę. Ale celem Pustki nie było tylko zniszczenie, w jakiś sposób dała początek nowej, lepszej sztuce.
Przykładowo pozycja w centrum była jedną z najbardziej kontrowersyjnych wśród twórców. A kiedy zrobiło się ciemno, Obrońcy zdali sobie sprawę, że będą musieli wymyślić lepszy pomysł, który przyciągnie wystarczającą liczbę zwolenników do walki z czarnym potworem. Jednym z takich pomysłów była flaga USA.
Ostatniego dnia istnienia Miejsca powstała w nim najbardziej niesamowita koalicja, mająca na celu walkę z Pustką - byli fani Trumpa i przeciwnicy Trumpa, Republikanie i Demokraci, Amerykanie i Europejczycy.
Eksperyment na Reddicie wkrótce się zakończył. Na ostatecznym płótnie nie było ani jednego rasistowskiego rysunku, ani jednego symbolu nienawiści.
Świergot
Kieszeń
komunikator fb
Na początek niezwykle ważne było określenie wymagań dla projektu Prima Aprilis, ponieważ musiał on zostać uruchomiony bez „podkręcania”, aby wszyscy użytkownicy Reddita mogli od razu uzyskać do niego dostęp. Gdyby od samego początku nie działało idealnie, raczej nie przyciągnęłoby uwagi wielu osób.
- Należy zapewnić elastyczną konfigurację na wypadek wystąpienia nieoczekiwanych wąskich gardeł lub awarii. Oznacza to, że musisz mieć możliwość dostosowania rozmiaru planszy i dozwolonej częstotliwości rysowania na bieżąco, jeśli ilość danych jest zbyt duża lub częstotliwość aktualizacji jest zbyt wysoka.
„Tablica” powinna mieć wymiary 1000x1000 płytek, aby wyglądała na bardzo dużą.
Wszyscy klienci powinni być zsynchronizowani i wyświetlać ten sam stan karty. W końcu, jeśli mają to różni użytkownicy różne wersje, będzie im trudno nawiązać kontakt.
Musisz obsługiwać co najmniej 100 000 jednoczesnych użytkowników.
Użytkownicy mogą umieszczać jedną płytkę co pięć minut. Dlatego konieczne jest utrzymanie średniej szybkości aktualizacji na poziomie 100 000 płytek na pięć minut (333 aktualizacji na sekundę).
Projekt nie powinien negatywnie wpływać na funkcjonowanie pozostałych części i funkcji obiektu (nawet w przypadku dużego ruchu na r/Place).
Zaplecze
Rozwiązania wdrożeniowe
Główną trudnością przy tworzeniu backendu była synchronizacja wyświetlania statusu tablicy dla wszystkich klientów. Zdecydowano, aby klienci nasłuchiwali w czasie rzeczywistym zdarzeń związanych z rozmieszczeniem płytek i natychmiast sprawdzali stan całej płytki. Posiadanie nieco przestarzałego pełnego stanu jest dopuszczalne, jeśli subskrybujesz aktualizacje przed wygenerowaniem pełnego stanu. Gdy klient otrzyma pełny stan, wyświetla wszystkie otrzymane kafelki w oczekiwaniu; wszystkie kolejne płytki muszą pojawić się na planszy natychmiast po ich otrzymaniu.
Aby ten schemat zadziałał, prośba stan pełny tablice należy ukończyć możliwie najszybciej. Na początku chcieliśmy przechowywać całą tablicę w jednym wierszu w Cassandrze i aby każde żądanie po prostu czytało ten wiersz. Format każdej kolumny w tym wierszu był następujący:
(x, y): („znacznik czasu”: epoki, „autor”: nazwa_użytkownika, „kolor”: kolor)
Ale ponieważ plansza zawiera milion płytek, musieliśmy przeczytać milion kolumn. W naszym klastrze produkcyjnym trwało to do 30 sekund, co było niedopuszczalne i mogło skutkować nadmiernym obciążeniem Cassandry.
Następnie postanowiliśmy przechowywać całą płytkę w Redisie. Wzięliśmy pole bitowe miliona czterobitowych liczb, z których każda mogła zakodować czterobitowy kolor, a współrzędne x i y zostały określone przez przesunięcie (offset = x + 1000y) w polu bitowym. Aby uzyskać pełny stan płytki, należało odczytać całe pole bitowe.
Możliwa była aktualizacja płytek poprzez aktualizację wartości w określonych przesunięciach (nie trzeba blokować ani przeprowadzać całej procedury odczytu/aktualizacji/zapisu). Jednak wszystkie szczegóły nadal muszą być przechowywane w Cassandrze, aby użytkownicy mogli dowiedzieć się, kto i kiedy umieścił poszczególne kafelki. Planowaliśmy również użyć Cassandry do przywrócenia planszy po awarii Redis. Odczytanie z niego całej płytki zajęło niecałe 100 ms, czyli było dość szybko.
Oto jak przechowywaliśmy kolory w Redis na przykładzie tablicy 2x2:
Martwiliśmy się, że możemy napotkać przepustowość odczytu w Redis. Jeśli wielu klientów podłączyło się lub zaktualizowało w tym samym czasie, wszyscy jednocześnie wysyłaliby żądania pełnego stanu tablicy. Ponieważ tablica reprezentowała współdzielony stan globalny, oczywistym rozwiązaniem było użycie buforowania. Zdecydowaliśmy się na buforowanie na poziomie CDN (Fastly), ponieważ było to łatwiejsze w implementacji, a pamięć podręczną uzyskiwano najbliżej klientów, co skracało czas otrzymania odpowiedzi.
Żądania dotyczące stanu pełnego wyżywienia były buforowane przez Fastly z limitem czasu wynoszącym sekundę. Aby zapobiec przekroczeniu limitu czasu dla dużej liczby żądań, użyliśmy nagłówka „stale-while-revalidate”. Fastly obsługuje około 33 punktów POP, które niezależnie buforują się nawzajem, dlatego spodziewaliśmy się otrzymać do 33 żądań stanu pełnego wyżywienie na sekundę.
Aby opublikować aktualizacje dla wszystkich klientów, skorzystaliśmy z naszej usługi websocket. Wcześniej z powodzeniem używaliśmy go do obsługi Reddit.Live z ponad 100 000 jednoczesnymi użytkownikami w celu otrzymywania powiadomień o prywatnych wiadomościach na żywo i innych funkcji. Obsługa również była kamień węgielny nasze poprzednie primaaprilisowe projekty - The Button i Robin. W przypadku r/Place klienci obsługiwali połączenia za pośrednictwem protokołu internetowego, aby otrzymywać w czasie rzeczywistym aktualizacje dotyczące rozmieszczenia kafelków.
API
Uzyskanie stanu pełnego wyżywienia
Początkowo prośby kierowano do Fastly. Gdyby miał ważny egzemplarz płytki, natychmiast by ją zwrócił, bez konieczności kontaktowania się z serwerami aplikacji Reddita. Jeśli nie lub kopia jest zbyt stara, aplikacja Reddit odczyta całą planszę z Redis i zwróci ją do Fastly w celu zapisania w pamięci podręcznej i zwrócenia klientowi.
Należy pamiętać, że liczba żądań nigdy nie osiągnęła 33 na sekundę, co oznacza, że buforowanie w Fastly było bardzo duże Skuteczne środki Ochrona aplikacji Reddit przed większością żądań.
A kiedy żądania dotarły do aplikacji, Redis zareagował bardzo szybko.
Rysowanie płytki
Etapy rysowania płytki:
- Znacznik czasu ostatniego umieszczenia kafelka przez użytkownika jest odczytywany z Cassandry. Jeżeli było to mniej niż pięć minut temu, to nic nie robimy i do użytkownika zwracany jest błąd.
- Szczegóły kafelka są zapisywane Redisowi i Cassandrze.
- Aktualny czas jest rejestrowany w Cassandrze jako ostatni moment ułożenia płytki przez użytkownika.
- Usługa websocket wysyła wiadomość do wszystkich podłączonych klientów o nowym kafelku.
Aby zachować ścisłą spójność, wszystkie zapisy i odczyty w Cassandrze zostały wykonane przy użyciu warstwy spójności QUORUM.
W rzeczywistości mieliśmy tutaj wyścig, w którym użytkownicy mogli umieszczać wiele płytek na raz. W etapach 1–3 nie było blokowania, więc jednoczesne próby losowania płytek mogły przejść kontrolę w pierwszym etapie i zostać wylosowane w drugim. Wygląda na to, że niektórzy użytkownicy odkryli ten błąd (lub użyli botów, które zignorowały ograniczenie częstotliwości żądań) – w rezultacie przy jego użyciu ułożono około 15 000 płytek (~0,09% całości).
Wskaźniki żądań i czasy odpowiedzi mierzone przez aplikację Reddit:
Szczytowa szybkość umieszczania płytek wynosiła prawie 200 na sekundę. To mniej niż nasz szacunkowy limit 333 płytek na sekundę (średnia przy założeniu, że 100 000 użytkowników umieszcza płytki co pięć minut).
Uzyskiwanie szczegółów dotyczących konkretnego kafelka
Przy żądaniu konkretnych płytek dane były odczytywane bezpośrednio z Cassandry.
Wskaźniki żądań i czasy odpowiedzi mierzone przez aplikację Reddit:
Ta prośba okazała się bardzo popularna. Oprócz zwykłych próśb klientów, ludzie napisali skrypty pobierające całą tablicę, po jednym kafelku na raz. Ponieważ to żądanie nie zostało zapisane w pamięci podręcznej w CDN, wszystkie żądania zostały obsłużone przez aplikację Reddit.
Czas reakcji na te prośby był dość krótki i utrzymywał się na tym samym poziomie przez cały okres trwania projektu.
Gniazda internetowe
Nie mamy indywidualnych wskaźników pokazujących, jak r/Place wpłynął na usługę websocket. Ale możemy oszacować wartości, porównując dane przed rozpoczęciem projektu i po jego zakończeniu.
Całkowita liczba połączeń z usługą websocket:
Podstawowe obciążenie przed uruchomieniem r/Place wynosiło około 20 000 połączeń, szczytowe 100 000 połączeń. Zatem w szczytowym okresie prawdopodobnie do r/Place podłączonych było jednocześnie około 80 000 użytkowników.
Przepustowość usługi Websocket:
W szczytowym momencie obciążenia r/Place usługa websocket przesyłała ponad 4 Gb/s (150 Mb/s na instancję, łącznie 24 instancje).
Frontend: klienci webowi i mobilni
W procesie tworzenia frontendu dla Place musieliśmy rozwiązać wiele skomplikowanych problemów związanych z rozwojem międzyplatformowym. Chcieliśmy, aby projekt działał tak samo na wszystkich głównych platformach, w tym na komputerach stacjonarnych i urządzeniach mobilnych z systemami iOS i Android.
Interfejs użytkownika musiał spełniać trzy ważne funkcje:
- Wyświetlaj status tablicy w czasie rzeczywistym.
- Pozwól użytkownikom na interakcję z tablicą.
- Pracuj na wszystkich platformach, w tym w aplikacjach mobilnych.
Głównym obiektem interfejsu był canvas, a API Canvas nadawało się do tego idealnie. Wykorzystaliśmy element
Rysowanie płótna
Płótno musiało odzwierciedlać stan tablicy w czasie rzeczywistym. Konieczne było narysowanie całej planszy po załadowaniu strony i dokończenie rysowania aktualizacji przychodzących przez websockety. Element canvas korzystający z interfejsu CanvasRenderingContext2D można zaktualizować na trzy sposoby:
- Narysuj istniejący obraz na płótnie za pomocą funkcji DrawImage() .
- Rysuj kształty, korzystając z różnych technik rysowania kształtów. Na przykład fillRect() wypełnia prostokąt kolorem.
- Skonstruuj obiekt ImageData i narysuj go na płótnie za pomocą putImageData() .
Pierwsza opcja nam nie odpowiadała, gdyż nie mieliśmy planszy w postaci gotowego obrazu. Pozostały opcje 2 i 3. Najprostszym sposobem była aktualizacja poszczególnych kafelków za pomocą fillRect(): kiedy aktualizacja nadchodzi przez websocket, po prostu rysujemy prostokąt 1x1 w pozycji (x, y). Ogólnie metoda działała, ale nie była zbyt wygodna do renderowania stan początkowy deski. Metoda putImageData() była znacznie lepsza: mogliśmy określić kolor każdego piksela w pojedynczym obiekcie ImageData i narysować od razu całe płótno.
Rysowanie stanu początkowego płytki
Użycie metody putImageData() wymaga zdefiniowania stanu płytki jako Uint8ClampedArray , gdzie każda wartość jest ośmiobitową liczbą bez znaku z zakresu od 0 do 255. Każda wartość reprezentuje kanał koloru (czerwony, zielony, niebieski, alfa), a każda piksel wymaga czterech elementów w tablicy. Płótno 2x2 wymaga 16-bajtowej tablicy, w której pierwsze cztery bajty reprezentują lewy górny piksel płótna, a ostatnie cztery reprezentują prawy dolny piksel.
Oto jak piksele canvas są powiązane z ich reprezentacjami Uint8ClampedArray:
Na kanwę naszego projektu potrzebowaliśmy tablicy czterech milionów bajtów - 4 MB.
W backendzie stan płytki jest przechowywany jako czterobitowe pole bitowe. Każdy kolor jest reprezentowany przez liczbę od 0 do 15, co pozwoliło nam upakować dwa piksele w każdym bajcie. Aby użyć tego na urządzeniu klienckim, musisz wykonać trzy rzeczy:
- Prześlij dane binarne z naszego API do klienta.
- Rozpakuj dane.
- Konwertuj kolory czterobitowe na 32-bitowe.
Do przesyłania danych binarnych wykorzystaliśmy Fetch API w przeglądarkach, które je obsługują. A w tych, które nie obsługują, używaliśmy Żądanie XMLHttp z typem odpowiedzi ustawionym na „arraybuffer”.
Dane binarne otrzymane z interfejsu API zawierają dwa piksele w każdym bajcie. Najmniejszy konstruktor TypedArray, jaki mieliśmy, pozwala na pracę z danymi binarnymi w postaci jednostek jednobajtowych. Trudno jest jednak z nich korzystać na urządzeniach klienckich, dlatego rozpakowaliśmy dane, aby ułatwić pracę z nimi. Proces jest prosty: iterowaliśmy po spakowanych danych, wyciągaliśmy bity wyższego i niższego rzędu, a następnie kopiowaliśmy je do pojedynczych bajtów do innej tablicy.
Wreszcie kolory czterobitowe musiały zostać przekonwertowane na kolory 32-bitowe.
Wymaga tego struktura ImageData, której potrzebowaliśmy do użycia metody putImageData(). ostateczny wynik miał postać tablicy Uint8ClampedArray z bajtami kodującymi kanały kolorów w kolejności RGBA. Oznacza to, że musieliśmy przeprowadzić kolejną dekompresję, dzieląc każdy kolor na bajty kanału składowego i umieszczając je we właściwym indeksie. Wykonywanie czterech zapisów na piksel nie jest zbyt wygodne. Ale na szczęście była inna opcja.
Obiekty TypedArray są zasadniczo reprezentacjami tablicowymi ArrayBuffer. Jest tu jedno zastrzeżenie: wiele instancji TypedArray może czytać i zapisywać w tej samej instancji ArrayBuffer. Zamiast nagrywać cztery wartości w tablicy ośmiobitowej możemy zapisać jedną wartość w 32-bitowej! Używając Uint32Array do zapisu, mogliśmy łatwo aktualizować kolory kafelków, po prostu aktualizując jeden indeks tablicy. Musieliśmy jednak przechowywać naszą paletę kolorów w kolejności dużych bajtów (ABGR), aby bajty automatycznie trafiały we właściwe miejsca podczas odczytu za pomocą Uint8ClampedArray .
Przetwarzanie aktualizacji otrzymanych przez websocket
Metoda remisRect() była dobra do rysowania aktualizacji poszczególnych pikseli w miarę ich otrzymywania, ale miała jedną wadę: duże partie aktualizacji przychodzących jednocześnie mogły prowadzić do spowolnienia przeglądarek. Rozumieliśmy też, że aktualizacje statusu tablicy mogą pojawiać się bardzo często, więc problem musiał zostać w jakiś sposób rozwiązany.
Zamiast natychmiastowo przerysowywać płótno za każdym razem, gdy aktualizacja jest odbierana przez websocket, zdecydowaliśmy się zrobić to tak, aby aktualizacje websocket, które docierają w tym samym czasie, mogły być grupowane i renderowane masowo. Aby to osiągnąć, wprowadzono dwie zmiany:
- Przestań używać funkcji DrawRect() - znaleźliśmy wygodnym sposobem aktualizuj wiele pikseli na raz za pomocą putImageData() .
- Przesyłanie renderowania płótna do pętli requestAnimationFrame.
Przenosząc renderowanie do pętli animacji, mogliśmy natychmiast zapisać aktualizacje protokołu internetowego w buforze ArrayBuffer, odraczając jednocześnie faktyczne renderowanie. Wszystkie aktualizacje protokołu websocket docierające pomiędzy ramkami (około 16 ms) zostały wsadowe i renderowane jednocześnie. Dzięki zastosowaniu requestAnimationFrame, jeśli renderowanie trwałoby zbyt długo (ponad 16 ms), wpłynęłoby to jedynie na częstotliwość odświeżania canvasu (a nie pogorszyłoby wydajność całej przeglądarki).
Interakcja z płótnem
Warto zaznaczyć, że canvas był potrzebny, aby ułatwić użytkownikom interakcję z systemem. Głównym scenariuszem interakcji jest rozmieszczenie płytek na płótnie.
Jednak dokładne renderowanie każdego piksela w skali 1:1 byłoby niezwykle trudne i nie uniknęlibyśmy błędów. Potrzebowaliśmy więc (dużego!) zoomu. Dodatkowo użytkownicy musieli mieć możliwość łatwego poruszania się po obszarze roboczym, ponieważ był on zbyt duży dla większości ekranów (szczególnie przy korzystaniu z zoomu).
Powiększenie
Ponieważ użytkownicy mogli umieszczać płytki raz na pięć minut, błędy w ich umieszczaniu byłyby dla nich szczególnie frustrujące. Należało zastosować powiększenie o takim współczynniku, aby płytka była odpowiednio duża i można było ją łatwo włożyć Właściwe miejsce. Było to szczególnie ważne w przypadku urządzeń z ekranem dotykowym.
Zaimplementowaliśmy zoom 40x, czyli każda płytka miała rozmiar 40x40. Okleiliśmy element