Obsługa aktualizacji otrzymanych przez websocket. Tworzenie czegoś więcej

12.03.2019

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żna było pomalować dowolną liczbę pikseli i dowolnymi kolorami, ale aby ponownie pokolorować następny piksel, trzeba było czekać 5 minut.

To prawda, że ​​zasady mówią: „Dzięki koordynacji z innymi możesz stworzyć znacznie więcej niż działając w pojedynkę”.

To, co wydarzyło się w ciągu następnych 72 godzin, zszokowało organizatorów. 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ły pieczołowicie stworzone przez setki tysięcy ludzi, którzy nie mieli ze sobą nic wspólnego poza połączeniem internetowym. Tak czy inaczej, ale 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 rozegrały się niezliczone dramaty - walki, bitwy i wojny, czasem nawet nie wiadomo, z jakiego powodu. Prowadzone były na małych forach, na prywatnych czatach, było ich tak dużo i wszystkie naraz, że nie sposób było wszystkiego śledzić. Ogólnie rzecz biorąc, płótno zostało prześledzone wieczna historia o trzech siłach niezbędnych ludzkości do stworzenia.

Twórcy

Twórcy byli pierwsi. Byli artystami, dla których czyste płótno ma nieodparty urok.

Twórcy zaczęli losowo ponownie kolorować piksele, żeby zobaczyć, co mogą zrobić. Dlatego pierwsze rysunki wyglądały bardziej 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ś musi zrujnować ich pracę. Aby stworzyć coś więcej, muszą ze sobą współpracować.

A potem ktoś zasugerował narysowanie siatki, która wyraźnie pokazałaby, gdzie trzeba narysować następny piksel, aby uzyskać spójny obraz. Tak więc w lewej dolnej części 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 Dickbutt, malować go na różne kolory, a nawet próbowali przekształcić go w Dickbutterfly. Za tym głupim pomysłem kryła się nuta zbliżającego się twórczego tsunami.

Nie stało się to jednak od razu. Twórcy byli odurzeni ich mocą. Obok Dickbutta pojawił się Pokemon Charmander, w którym zamiast łapy zaczął rosnąć członek, a potem jeszcze dwa.

To już nie był projekt. Niektórzy twórcy desperacko próbowali usunąć prowokacyjne dodatki, wzywając do „czystej” sztuki, ale inni nie ustąpili. Ale go tam nie było.

Stało się jasne, że nadmiar wolności prowadzi do chaosu. Kreatywność potrzebuje ograniczeń tak samo, jak potrzebuje wolności. Kiedy ktoś może umieścić dowolny piksel w dowolnym miejscu, jak może to nie doprowadzić do chaosu?

Strażnicy

Ten problem został bardzo szybko rozwiązany przez innego rodzaju użytkowników - opiekunów. Przybyli w jednym celu - 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 była frakcja Blue Corner. Pojawiając się w prawym dolnym rogu, rozprzestrzeniał się jak zaraza. Jej zwolennicy głosili, że w ten sposób powinni zawijać całą przestrzeń płótna. Piksel po pikselu zaczęli przekładać swój pomysł na rzeczywistość, wkrótce rejestrując ogromne obszary.

Blue Corner nie był sam w swoich staraniach. Po drugiej stronie płótna pojawiła się kolejna grupa - Red Corner (czerwony róg). Jego uczestnicy powiedzieli, że są zwolennikami lewicy poglądy polityczne. Kolejna grupa – Green Lattice (zielona krata) – zajęła się wszechobecnym przeplataniem zielonych i białych pikseli. Okazała się bardzo wydajna, ponieważ musiała malować o połowę mniej pikseli niż inne frakcje.

Strażnicy udali się do twórców frontalnym atakiem. Charmander stał się pierwszym miejscem bitwy. Po odkryciu, że Blue Corner zaczął zabijać Pokémony niebieskimi pikselami, twórcy zdali sobie sprawę z zagrożenia i zakończyli wewnętrzne wojny.

Walczyli, zastępując każdy niebieski piksel swoim własnym. Ale siły nie były równe. Dzięki jego determinacji Blue Corner zgromadził znacznie większą armię niż twórcy. I jedyne, co pozostało twórcom w takiej sytuacji, to błaganie o życie.

I jakoś to się odwróciło. W Blue Corner rozpoczęła się debata na temat ich roli w proces twórczy. Jeden z uczestników zadał pytanie: „Skoro nasza fala nieuchronnie całkowicie przejmuje kontrolę nad światem, czy powinniśmy okazywać miłosierdzie innym formom sztuki, z którymi się spotykamy?”

To pytanie prędzej czy później stanęło przed każdą frakcją. Przy całej swojej ekspansjonistycznej gorliwości, co mieli zrobić ze sztuką, która stała im na drodze?

To był punkt zwrotny. Bezmyślne frakcje zamieniły się w obrońców.

Ale to jeszcze nie koniec

W świecie wypełnionym drapieżnymi kolorami twórcy mogli powrócić do swoich dzieł. Dodając jeden element po drugim, zaczęli je komplikować. Używając czcionek trzypikselowych, zaczęli pisać teksty. Jednym z najbardziej znanych dzieł był prequel Gwiezdnych Wojen.

Twórcy połączyli się w grupy pracujące nad wspólnym projektem. Dzielili między sobą strategie i wzorce. Jednym z najbardziej udanych była grupa, która stworzyła panel Windows 95 z przyciskiem Start w rogu.

Inni stworzyli blok serc, jak w starych grach wideo, takich jak Zelda. Niewielu zaczęło ten projekt, ale szybko dołączyli do nich inni, w wyniku czego serca pomalowane w kolory różnych flag rozciągnęły się do połowy płótna.

Inna grupa odtworzyła Gwiaździstą noc Van Gogha.

Jednak nie wszystko poszło gładko. Obrońcy, którzy kiedyś witali z radością tworzenie dzieł sztuki, stali się modowymi tyranami. Zaczęli precyzować, co można tworzyć, a co nie. Zaczęło się na krótko przed tym, zanim twórcy zaczęli tworzyć według własnych zasad.

Frakcje zwróciły na siebie spojrzenia, żądając, by ich wyznawcy stanęli po którejś ze stron w epickich bitwach. Nie mieli czasu słuchać żałosnych próśb twórców, którzy chcieli zyskać aprobatę dla idei nowej sztuki.

Walki między obrońcami zaostrzyły się poważnie. Transmisje na żywo na Twitchu zachęcały swoich obserwujących do atakowania Blue Corner i Purple. Sporządzano plany bitew. Wzywali do emocji.

Zdarzały się nawet ataki zwodnicze, w których wyznawcy tego samego koloru umieszczali piksele przeciwnika wewnątrz swoich, aby mogli narzekać na naruszenie i atakować.

Największym problemem była jednak surowa zasada – płótna nie można powiększyć. Zarówno walczące frakcje, jak i twórcy zaczęli zdawać sobie sprawę, że po prostu nie będzie w nich miejsca na nową sztukę.

Od samego początku na płótnie pojawiały się flagi różne kraje. Rosły i wpadały na siebie. Między flagami Niemiec i Francji wybuchła prawdziwa epicka bitwa. Stało się jasne, że do stworzenia nowych przestrzeni potrzebny jest pośrednik.

Nagle świat, który na początku uniknął prymitywnych najazdów, stał się gotowy do wojny na pełną skalę. Desperackie próby rozwiązania problemu drogą dyplomatyczną spełzły na niczym. Spotykając się na czatach, liderzy twórców i obrońcy tylko obwiniali się nawzajem.

Potrzebowaliśmy sprytnego, z którym wszyscy mogliby się zgodzić.

Niszczyciele

Na stronie internetowej 4chan zwrócił uwagę na to, co dzieje się na Reddicie. I nie mogli się przebić. Ich użytkownicy wybrali kolor najbliższy ich sercu - czarny. Stali się Pustką.

Gdy łza powoli rozlewa się po powierzchni, czarne piksele zaczęły pojawiać się na środku płótna, 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ę nie udało, ponieważ Pustka była inna.

Pustka nie była obrońcą. W przeciwieństwie do innych frakcji nie wykazywała żadnej lojalności wobec sztuki. Wyznawcy Pustki praktykowali destrukcyjny egalitaryzm pod hasłem „Pustka wszystko połknie”. Nie nawiązywali kontaktu z innymi. Chcieli po prostu pomalować cały świat na czarno.

I tego właśnie wymagano. Na skraju wyginięcia wszyscy członkowie projektu połączyli siły, by walczyć z Pustką, aby ocalić swoją sztukę.

Ale Pustka nie była tak łatwa do pokonania, ponieważ była potrzebna. Trzeba było wszystko zniszczyć, aby z popiołów odrodziła się nowa sztuka, najlepsza. A bez Pustki było to niemożliwe.

Tak więc Pustka stała się katalizatorem powstania największego dzieła sztuki.

Od samego początku trwała uparta walka o centralną część płótna. Twórcy zajęli to terytorium dla swoich dzieł. Początkowo próbowali to zrobić za pomocą ikon. Następnie w skoordynowanej próbie stworzenia pryzmatu jak na okładce Album różowy Floyd tylna strona Księżyc."

Ale Pustka zjadła wszystko. Tworzone kreacje jedna po drugiej tylko rozpalały jej drapieżny apetyt na chaos.

A jednak to było dokładnie to, co było potrzebne. Niszcząc grafikę, The Void zmusiło 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ę obserwujących.

A tym pomysłem była amerykańska flaga.

Ostatniego dnia projektu wszyscy zebrali się, aby raz na zawsze przepędzić pustkę. Koalicja powstała z ludzi, którzy inaczej by się rozerwali – od zwolenników i przeciwników Trumpa, od Demokratów i Republikanów, od 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, w których taka współpraca wydaje się niemożliwa, nadal mogą to robić.

Starożytni mieli rację

Wkrótce potem eksperyment Reddita dobiegł końca. Dziś towarzyszy mu wiele historii opowiadanych na dziesiątkach czatów. Każde dzieło sztuki powstałe w ramach projektu zostało pokryte setkami nowych, z których tylko kilka pozostało na ostatecznym płótnie.

Ale chyba najbardziej zaskakujące jest to, że pomimo anonimowości i braku zakazów na ostatecznym płótnie nie było żadnych rasistowskich ani mizantropijnych symboli. To był piękny obieg sztuki, życia i śmierci. I nie był pierwszym w naszej historii.

Wiele tysiącleci temu, kiedy ludzkość (ta prawdziwa, nie tylko ta z Reddita) była jeszcze w powijakach, hinduscy filozofowie sugerowali, że niebo składa się z trzech konkurujących ze sobą, ale niezbędnych bóstw: Brahmy Stwórcy, Wisznu Obrońcy, i Shiva- Niszczyciel.

Nawet bez jednego z nich wszechświat nie mógłby funkcjonować. Aby było światło, musi być ciemność. Aby istniało życie, potrzebna jest śmierć. Dla stworzenia i sztuki musi nastąpić zniszczenie.

Kilka dni trwania projektu pokazało, że takie podejście okazało się prorocze. Reddit w najbardziej niewiarygodny sposób udowodnił, że tworzenie wymaga obecności wszystkich trzech komponentów.

Ostateczne płótno

Facebook

Świergot

Kieszeń

Linkedin

komunikator fb

Nie można powiedzieć, że 100% żartów korporacyjnych z okazji Dnia Humoru jest udanych i wciągających. W tym roku administracja Reddita uruchomiła Place, interaktywne płótno graficzne o wymiarach 1000 na 1000 pikseli, oraz sekcję mu poświęconą. Założono, że członkowie społeczności będą wspólnie malować to płótno według własnego uznania. Ale w rezultacie przeradzało się to w walkę o Miejsce, czasem w filozoficzną konfrontację. Zwykłe ćwiczenie rysunkowe zamieniło się w ekscytujący eksperyment społeczny. Historia od początku do końca została udokumentowana na blogu Sudoscript.

Zasady Miejsca były proste. Każdy uczestnik mógł wybrać jeden piksel z 16 kolorów i umieścić go w dowolnym miejscu na płótnie. Możesz umieścić tyle pikseli, ile chcesz, ale musisz odczekać 5 minut między każdym umieszczeniem. Po 72 godzinach te bardzo proste zasady doprowadziły do ​​powstania niesamowitego kolektywnego płótna:

Każdy z widocznych powyżej pikseli został umieszczony ręcznie. Każda ikona, każda flaga, każdy mem zostały pieczołowicie stworzone przez tysiące ludzi, których nie łączyło nic prócz połączenia internetowego.

Podczas tworzenia było niezliczone dramaty, idee, walki, a nawet wojny. Ale ogólnie historia Miejsca jest odwiecznym dramatem o trzech siłach, których ludzkość potrzebuje do tworzenia i 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, aby zobaczyć, co można zrobić. W pierwszych minutach pojawiły się pierwsze szkice. Szorstkie i niedojrzałe, przypominały malowidła naskalne jaskiniowców.

Twórcy od razu dostrzegli, jaką moc i potencjał skrywają piksele. Ale pracując samodzielnie, mogli umieszczać jeden piksel co 5 lub 10 minut. kreacja sensowny rysunek zajęłoby wieczność. Aby coś narysować, musieli ze sobą współpracować.

Wtedy ktoś wpadł na genialny pomysł wykorzystania siatki do rysowania, która nakładałaby rysunek i pokazywała, gdzie powinny znajdować się kolejne piksele. Pierwszym, który przeszedł przez ten eksperyment, był dobrze znany mem anglojęzycznego internetowego Dickbutta. I mieszkańcy Miejsca zabrali się do pracy: Dickbutt zmaterializował się w ciągu kilku minut w lewym dolnym rogu płótna. Na Miejscu pojawiła się pierwsza kreacja twórczości zbiorowej.

Potem, gdy twórcy trochę upili się możliwościami, pojawił się Pokemon Charmander, w którym dość szybko pojawił się członek zamiast nogi. I zaczął się pierwszy konflikt: niektórzy twórcy sumiennie starali się oczyścić obraźliwe rysunki, ale inni uporczywie dodawali nieprzyzwoite rzeczy.

Twórcy stają przed fundamentalnym filozoficznym problemem: zbyt duża swoboda prowadzi do chaosu. Kreatywność potrzebuje ogranicznika, tak jak potrzebuje wolności.

Obrońcy

Miejsce miało inny typ użytkownika, który miał do czynienia właśnie z tym problemem. Ale zaczęli od bardziej prymitywnych celów: podboju świata. Dzieląc się na frakcje według koloru, próbowali zdobyć Miejsce. Jednym z pierwszych był Blue Corner. Pochodzi z prawego dolnego rogu i rozprzestrzenia się jak zaraza.

Inna grupa założyła Czerwony Kącik po przeciwnej stronie płótna, skłaniała się ku politycznej lewicy. Inna grupa o nazwie Green Grid malowała płótno przez piksel - zielone komórki przeplatane bielą. Ponieważ musieli pomalować tylko połowę pikseli, byli bardziej wydajni niż inne frakcje.

Nie trwało długo, zanim frakcje starły się z twórcami. Charmander stał się jednym z pierwszych obiektów bitwy. Niebieski róg zaczął malować Pokémona niebieskimi pikselami, a Twórcy przeszli z „wojen fallicznych” (która przyciąga więcej członków) do poważniejszego zagrożenia. Podjęli walkę, malując każdy niebieski piksel swoim własnym. Ale przewaga ilościowa nie była na ich korzyść.

Twórcy poddali się więc łasce zwycięzcy, co w jakiś sposób zraniło uczucia Bluesa. Wśród nich pojawili się powątpiewający w swoją rolę w świecie Miejsca. „Nasza fala nieuchronnie pokryje cały świat, od krawędzi do krawędzi, jeśli okażemy litość innej sztuce, z którą się spotykamy” – powiedział jeden z członków grupy.

Z tym problemem borykała się każda z frakcji. I wszyscy postanowili zapisać inne rysunki. Tak więc kolorowe fale zaczęły przepływać wokół rysunków, nie zamalowując ich.

To był punkt zwrotny. Bezmyślne kolorowe frakcje stały się użytecznymi obrońcami.

Ale to nie jest szczęśliwe zakończenie

W końcu nienasycone fale kolorów zostały zatrzymane, a Twórcy mogli wrócić do twórczości. Rysunki stawały się coraz trudniejsze. Pojawiły się teksty zapisane w pikselach.

Twórcy zebrali się w małe grupy, tworząc na Reddicie podsekcje, w których mogli dyskutować o rysunkach roboczych i strategii. Jedna z najbardziej udanych grup narysowała pasek zadań w stylu Windows 95. Kolejne naszkicowane Miejsce z sercami.

Potem pojawił się Van Gogh.

Ale wszystko nie było takie proste. Obrońcy zamienili się w tyranów, dyktujących styl rysunków. Decydują, co można narysować, a co nie. Frakcje zaczęły dzielić użytkowników między sobą, zwołując partie, tymczasem Twórcy czekali na akceptację nowych pomysłów.

Walki między obrońcami stawały się coraz ostrzejsze. Jeden ze streamerów na Twitchu wezwał swoich zwolenników do ataku na BLU. Opracowano strategie bojowe. Zdarzały się nawet prowokacje: fani tego samego koloru sami rysowali na swoim terytorium piksele w kolorze przeciwnika, aby mieć pretekst do odwetowego ataku. Podczas gdy frakcje walczyły między sobą, Twórcy stwierdzili, że nie ma miejsca na nowe rysunki.

Flagi zaczęły się podnosić różnych krajów Gdy dorastają, nieuchronnie wpadają na siebie. Na przykład flagi Niemiec i Francji zderzyły się na terytorium „niczyim”.

Wydawało się, że świat stanął na krawędzi wojny. Wszystkie strony próbowały rozwiązać konflikt na drodze dyplomacji. Przywódcy Twórców i Obrońców rozmawiali, ale zwykle kończyło się to wzajemnymi oskarżeniami.

To miejsce potrzebowało złoczyńcy, przeciwko któremu wszyscy inni mogliby się zjednoczyć.

Niszczyciele

Pustka nadeszła.

Zaczęło się od 4chan, najsłynniejszej tablicy z obrazkami na świecie. Zamieszkujący go dowcipnisiowie zauważyli, co dzieje się na Reddicie i nie mogli przejść obojętnie. Stali się Pustką.

Na środku Miejsca zaczęła rosnąć plamka czarnych pikseli. Początkowo frakcje próbowały zawrzeć pakt z Pustką na drodze dyplomacji. Ale im się nie udało, Pustka działała inaczej. Nie była Obrończynią, nie stała na straży sztuki. Jej wyznawcy głosili, że Pustka pochłonie wszystko. Nie tworzyli stron, chcieli po prostu pomalować cały świat na czarno.

Właśnie tego kopniaka w dupę brakowało Place. W obliczu wspólnego zagrożenia Twórcy i Obrońcy po raz kolejny zjednoczyli się, by ratować sztukę. Ale znaczenie Pustki nie było tylko zniszczeniem, w jakiś sposób dało początek nowej, lepszej sztuce.

Na przykład lokalizacja 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 obejmowałby wystarczającą liczbę zwolenników do walki z czarnym potworem. Jednym z takich pomysłów była flaga USA.

Ostatniego dnia Miejsca powstała najbardziej niesamowita koalicja do walki z Pustką — fani i przeciwnicy Trumpa, Republikanie i Demokraci, Amerykanie i Europejczycy.

Wkrótce eksperyment Reddita dobiegł końca. Na ostatecznym płótnie nie było ani jednego rasistowskiego rysunku, ani jednego symbolu nienawiści.

Świergot

Kieszeń

Linkedin

komunikator fb

Reddit otworzył stronę autoekspresji na cześć Prima Aprilis, ale projekt, stworzony jako żart, stał się swoistym murem dla zbiorowych graffiti uczestników z całego świata, pokazujących, jaki ślad chcą pozostawić w historii.

1 kwietnia Reddit uruchomił projekt Place, czyli stronę z pustym płótnem, na którym każdy użytkownik forum mógł narysować dowolny obrazek. Artyści mieli ograniczenia: mogli narysować tylko jeden piksel jednego z 16 kolorów co pięć minut, a rozmiar płótna był również ograniczony. Na narysowanych pikselach możesz narysować inne (a wtedy pierwszy autor może ponownie narysować swój własny piksel na pikselu przeciwnika), dlatego autorzy obrazów są a priori w konflikcie. Jak wskazano w opisie płótna, projekt przeznaczony jest do wspólnej twórczości - „Każdy z Was może stworzyć coś indywidualnego. Razem możesz stworzyć coś więcej.”

Na początku projektu wszyscy dosłownie rzucili się na płótno - każdy piksel na nim był wypełniony. Na początku użytkownicy po prostu wbijali kolor w wolne piksele, ale potem zaczęły tworzyć się zespoły, które zaczęły rysować jeden z najprostszych możliwych pomysłów, jakie znajdują podobnie myślący ludzie - flagi państwowe. Im więcej użytkowników pracowało na płótnie, tym bardziej interesujące i złożone pomysły przyszło im do głowy. A „The Place” ewoluowało od primaaprilisowego projektu do miejsca, w którym użytkownicy z całego świata spotykają się w prawdziwych społecznościach, aby pokazać coś światu i wesprzeć ich tworzenie od grup najeźdźców, którzy tak naprawdę chcą po prostu narysować jakiś rodzaj własnego rysunku.

Miejsce w pierwszych godzinach pracy

„Miejsce” stało się internetową tablicą z naklejkami, ale każdą z nich tworzy się z wielkim trudem. Na przykład, aby narysować logo Linuksa o wymiarach 48 x 68 pikseli i chronić je przed dzikimi lokatorami, potrzeba 3264 osób do rysowania w tym samym czasie.

Użytkownicy jednoczą się, aby realizować pomysły, które są mniejsze i prostsze, ale nadal bardzo zorientowane na zespół, jak ten rząd serc z flagami różnych krajów (i nie tylko): każdy jest odpowiedzialny za „swoje” serce, ale wszyscy razem ludzie nieświadomie tworzą jedno zespół.

A inni piszą całe płótna tekstu, jak na przykład ta grupa fanów ” Gwiezdne Wojny”, który napisał i utrzymuje słynny monolog Najwyższego Kanclerza Palpatine'a o Sith Darth Plagueis z trzeciego odcinka kosmicznej sagi.

Jednak niektórzy użytkownicy skarżyli się, że uczestnicy projektu „podłożyli” zamiast siebie boty, które co pięć minut automatycznie aktualizują piksel zajmowany przez autora. Pomimo tego, że podczas rysowania każdego piksela użytkownik musi powtórzyć zestaw czynności (np. wybrać określony kolor), niektórym udało się ominąć mechanizm ochronny i stworzyć boty, które rysują dla nich obrazki.

Są jednak tacy, którzy wciąż tworzą specjalne wątki, próbując wezwać podobnie myślących ludzi, którzy pomogą narysować i zostawić dla przyszłych pokoleń coś w rodzaju… rzygnięcia Ricka Sancheza z kreskówki Rick and Morty. Poważnie? Czy oni naprawdę nie są botami?

Po 72 godzinach pracy projekt został zamknięty. Administracja zasobu podziękowała wszystkim za udział i za to, że ludzie zjednoczyli się „by stworzyć coś więcej”.

Reddit często staje się miejscem dla różnych działania społeczne. Na przykład ostatnio smutni użytkownicy zasobu postanowili zapytać, jak to jest budzić się każdego dnia z uśmiechem. A wcześniej czytelnicy Reddita dzielili się ze sobą historiami o dziewczynach. Na popularnym zasobie siedzą nie tylko anonimowi ludzie: ostatnio aktor przez kilka godzin odpowiadał na pytania użytkowników dotyczące filmu „Trainspotting”.

Na początek niezwykle ważne było określenie wymagań dla primaaprilisowego projektu, ponieważ musiał on zostać uruchomiony bez „podkręcania”, aby wszyscy użytkownicy Reddita mieli od razu do niego dostęp. Gdyby nie działał idealnie od samego początku, z trudem przyciągnąłby uwagę dużej liczby osób.

    „Tablica” musi mieć wymiary 1000 x 1000 płytek, aby wyglądała na bardzo dużą.

    Wszyscy klienci muszą być zsynchronizowani i wyświetlać ten sam stan tablicy. W końcu, jeśli różni użytkownicy mają różne wersje, trudno będzie im wchodzić w interakcje.

    Musisz obsługiwać co najmniej 100 000 użytkowników w tym samym czasie.

    Użytkownicy mogą umieszczać jedną płytkę co pięć minut. Dlatego konieczne jest utrzymanie średniej szybkości aktualizacji na poziomie 100 000 kafelków na pięć minut (333 aktualizacje na sekundę).

    Projekt nie powinien negatywnie wpływać na pracę innych części i funkcji serwisu (nawet jeśli na r/Place panuje duży ruch).

  • W przypadku nieoczekiwanych wąskich gardeł lub awarii należy zapewnić elastyczną konfigurację. Oznacza to, że musisz mieć możliwość dostosowania rozmiaru tablicy i dozwolonej częstotliwości rysowania w locie, jeśli ilość danych jest zbyt duża lub częstotliwość odświeżania jest zbyt wysoka.

Zaplecze

Decyzje wykonawcze

Główną trudnością w tworzeniu backendu była synchronizacja wyświetlania stanu tablicy dla wszystkich klientów. Zdecydowano, aby klienci nasłuchiwali zdarzeń umieszczenia kafelków w czasie rzeczywistym i natychmiast pytali o stan całej planszy. Dopuszczalne jest posiadanie nieco przestarzałego pełnego stanu, jeśli subskrybujesz aktualizacje przed wygenerowaniem pełnego stanu. Kiedy klient otrzymuje pełny stan, wyświetla wszystkie otrzymane kafelki podczas oczekiwania; wszystkie kolejne żetony muszą być wyłożone na planszę zaraz po ich otrzymaniu.


Aby ten schemat zadziałał, request stan pełny tablice powinny działać tak szybko, jak to możliwe. Na początku chcieliśmy przechowywać całą tablicę w jednym wierszu w Cassandrze i aby każde żądanie odczytywało tylko ten wiersz. Format każdej kolumny w tym wierszu był następujący:


(x, y): ('znacznik czasu': epoki, 'autor': nazwa_użytkownika, 'kolor': kolor)

Ponieważ jednak plansza zawiera milion kafelków, musieliśmy przeczytać milion kolumn. W naszym klastrze produkcyjnym trwało to do 30 sekund, co było niedopuszczalne i mogło prowadzić do nadmiernego obciążenia Cassandry.


Następnie zdecydowaliśmy się na przechowywanie całej planszy w Redis. Wzięliśmy pole bitowe składające się z 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 (przesunięcie = x + 1000y) w polu bitowym. Aby uzyskać pełny stan płytki, konieczne było odczytanie całego pola bitowego.


Kafelki można aktualizować, aktualizując wartości w określonych przesunięciach (nie trzeba blokować ani wykonywać całej procedury odczytu/aktualizacji/zapisu). Ale wszystkie szczegóły nadal muszą być przechowywane w Cassandrze, aby użytkownicy mogli dowiedzieć się, kto opublikował każdy z kafelków i kiedy. Planowaliśmy również użyć Cassandry do przywrócenia tablicy po awarii Redis. Odczytanie z niej całej tablicy zajęło mniej niż 100 ms, czyli 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 łączyło się lub aktualizowało w tym samym czasie, wszyscy jednocześnie wysyłali żądania uzyskania pełnego stanu tablicy. Ponieważ tablica była wspólnym stanem globalnym, oczywistym rozwiązaniem było użycie buforowania. Zdecydowaliśmy się na cache na poziomie CDN (Fastly), ponieważ był łatwiejszy do wdrożenia, a cache znajdował się najbliżej klientów, co skróciło czas odpowiedzi.


Żądania stanu pełnej tablicy były buforowane przez Fastly z limitem czasu na sekundę. Aby zapobiec duża liczbażądań, gdy upłynie limit czasu, użyliśmy nagłówka nieaktualnego podczas ponownej walidacji. Fastly obsługuje około 33 POP, które są niezależnie buforowane, więc spodziewaliśmy się otrzymywać do 33 żądań stanu pełnej płyty 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 zasilania Reddit.Live z ponad 100 000 jednoczesnych użytkowników w zakresie powiadomień o prywatnych wiadomościach na żywo i innych funkcji. Obsługa też była kamień węgielny nasze poprzednie prima aprilisowe projekty - The Button i Robin. W przypadku r/Place klienci obsługiwali połączenia websocket, aby otrzymywać aktualizacje w czasie rzeczywistym dotyczące rozmieszczenia kafelków.

API

Uzyskanie pełnego stanu tablicy


Na pierwsze prośby trafiały do ​​Fastly. Jeśli posiadał ważny egzemplarz płytki, to od razu zwracał go bez kontaktowania się z serwerami aplikacyjnymi Reddita. Jeśli nie, lub kopia była za stara, wówczas aplikacja Reddit odczytała pełną tablicę z Redis i zwróciła ją do Fastly, aby została zbuforowana i zwrócona klientowi.




Należy pamiętać, że częstotliwość żądań nigdy nie osiągnęła 33 na sekundę, tj. buforowanie z Fastly było bardzo skuteczne narzędzie ochrona aplikacji Reddit przed większością żądań.



A kiedy żądania docierały do ​​aplikacji, Redis reagował bardzo szybko.

Rysunek kafelkowy


Etapy rysowania płytki:

  1. Znacznik czasu ostatniego kafelka umieszczonego przez użytkownika jest odczytywany z Cassandry. Jeśli było to mniej niż pięć minut temu, nic nie robimy, a użytkownikowi zwracany jest błąd.
  2. Szczegóły kafelków są zapisywane do Redisa i Cassandry.
  3. Bieżący czas jest rejestrowany w Cassandrze jako ostatni moment, w którym użytkownik umieścił kafelek.
  4. Usługa websocket wysyła wiadomość o nowym kafelku do wszystkich podłączonych klientów.

Aby zachować ścisłą spójność, wszystkie zapisy i odczyty w Cassandrze były wykonywane przy użyciu spójnego poziomu KWORUM .


W rzeczywistości mieliśmy tutaj wyścig, w którym użytkownicy mogli umieszczać wiele płytek jednocześnie. W etapach 1-3 nie było blokowania, więc jednoczesne próby losowania płytek mogły zdać test w pierwszym etapie i zostać wylosowane w drugim. Wygląda na to, że niektórzy użytkownicy wykryli ten błąd (lub korzystali z botów, które ignorowały ograniczenie częstotliwości wysyłania żądań) - w rezultacie za jego pomocą umieszczono około 15 000 kafelków (~0,09% całości).


Częstotliwość żądań i czas odpowiedzi mierzony przez aplikację Reddit:



Szczytowa szybkość umieszczania kafelków wynosiła prawie 200 na sekundę. To poniżej naszego obliczonego limitu 333 kafelków/s (średnia przy założeniu, że 100 000 użytkowników umieszcza swoje kafelki co pięć minut).


Uzyskiwanie szczegółowych informacji na temat konkretnego kafelka


W przypadku żądania określonych kafelków dane były odczytywane bezpośrednio z Cassandry.


Częstotliwość żądań i czas odpowiedzi mierzony przez aplikację Reddit:



Prośba ta okazała się bardzo popularna. Oprócz zwykłych próśb klientów, ludzie napisali skrypty, aby pobierać całą planszę po jednym kafelku na raz. Ponieważ to żądanie nie było buforowane w CDN, wszystkie żądania były obsługiwane przez aplikację Reddit.



Czas odpowiedzi na te prośby był dość krótki i utrzymywał się na tym samym poziomie przez cały okres trwania projektu.

Gniazda sieciowe

Nie mamy oddzielnych metryk pokazujących, jak r/Place wpłynęło na wydajność usługi 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:



Bazowe obciążenie przed uruchomieniem r/Place wynosiło około 20 000 połączeń, w szczycie 100 000 połączeń. Tak więc w szczytowym momencie mieliśmy prawdopodobnie około 80 000 użytkowników podłączonych do r/Place w tym samym czasie.


Przepustowość usługi websocket:



Podczas szczytowego obciążenia w r/Place usługa websocket transmitowała z prędkością ponad 4 Gb/s (150 Mb/s na instancję, łącznie 24 instancje).

Frontend: klienci sieciowi i mobilni

W procesie tworzenia front-endu dla Place musieliśmy rozwiązać wiele skomplikowanych zadań 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 miał spełniać trzy ważne funkcje:

  1. Wyświetlaj status tablicy w czasie rzeczywistym.
  2. Zezwól użytkownikom na interakcję z tablicą.
  3. Pracuj na wszystkich platformach, w tym na aplikacjach mobilnych.

Głównym obiektem interfejsu było płótno, a API kanwy było do tego idealne. Użyliśmy elementu 1000x1000, a każdy kafelek został narysowany jako pojedynczy piksel.

Rysunek na płótnie

Płótno miało odzwierciedlać stan tablicy w czasie rzeczywistym. Konieczne było narysowanie całej planszy podczas ładowania strony i zakończenie aktualizacji rysunków przechodzących przez gniazda sieciowe. Element canvas korzystający z interfejsu CanvasRenderingContext2D można aktualizować na trzy sposoby:

  1. Narysuj istniejący obraz na kanwie za pomocą funkcji drawImage() .
  2. Rysuj formularze przy użyciu różnych metod rysowania formularzy. Na przykład fillRect() wypełnia prostokąt jakimś kolorem.
  3. Skonstruuj obiekt ImageData i narysuj go na kanwie za pomocą metody putImageData() .

Pierwsza opcja nam nie odpowiadała, ponieważ nie mieliśmy planszy w postaci gotowego obrazu. Były opcje 2 i 3. Najłatwiej było zaktualizować poszczególne kafelki za pomocą fillRect() : kiedy aktualizacja przychodzi przez websocket, po prostu narysuj prostokąt 1x1 na pozycji (x, y). Ogólnie rzecz biorąc, metoda działała, ale nie była zbyt wygodna do rysowania stan początkowy deski. Metoda putImageData() była znacznie lepsza: mogliśmy określić kolor każdego piksela w pojedynczym obiekcie ImageData i narysować całe płótno naraz.

Narysowanie stanu początkowego planszy

Użycie metody putImageData() wymaga zdefiniowania stanu płytki jako Uint8ClampedArray , gdzie każda wartość jest ośmiobitową liczbą bez znaku z przedziału od 0 do 255. Każda wartość reprezentuje jakiś kanał koloru (czerwony, zielony, niebieski, alfa), a każdy piksel potrzebuje cztery elementy 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 bajty reprezentują prawy dolny piksel.


Oto jak piksele płótna są powiązane z ich reprezentacjami Uint8ClampedArray:



Na płótno naszego projektu potrzebowaliśmy tablicy o wielkości czterech milionów bajtów - 4 MB.


W zapleczu 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 czynności:

  1. Przekaż dane binarne z naszego API do klienta.
  2. Rozpakuj dane.
  3. Konwertuj 4-bitowe kolory na 32-bitowe.

Aby przesyłać dane binarne, użyliśmy interfejsu Fetch API w tych przeglądarkach, które go obsługują. A w tych, które nie obsługują, używane XMLHttpRequest z responseType ustawionym na „arraybuffer” .


Dane binarne otrzymane z API zawierają dwa piksele w każdym bajcie. Najmniejszy konstruktor TypedArray, jaki mieliśmy, pozwala nam pracować z danymi binarnymi w postaci jednostek jednobajtowych. Są one jednak niewygodne w użyciu na urządzeniach klienckich, więc rozpakowaliśmy dane, aby ułatwić pracę. Proces jest prosty: iterujemy spakowane dane, wyciągamy wysokie i niskie bity, a następnie kopiujemy je do oddzielnych bajtów w innej tablicy.


Wreszcie czterobitowe kolory musiały zostać przekonwertowane na 32-bitowe.



Wymaga tego struktura ImageData, której potrzebowaliśmy do użycia funkcji putImageData(). ostateczny wynik miał postać Uint8ClampedArray z bajtami kodującymi kanały kolorów w kolejności RGBA. Oznacza to, że musieliśmy wykonać jeszcze jedno rozpakowanie, dzieląc każdy kolor na bajty kanału składowego i umieszczając je we właściwym indeksie. Wykonanie czterech zapisów na piksel nie jest zbyt wygodne. Na szczęście była inna opcja.


Obiekty TypedArray są zasadniczo tablicowymi reprezentacjami ArrayBuffer. Jest tu jedno zastrzeżenie: wiele instancji TypedArray może odczytywać i zapisywać do tej samej instancji ArrayBuffer. Zamiast pisać cztery wartości w tablicy ośmiobitowej możemy zapisać jedną wartość w tablicy 32-bitowej! Używając Uint32Array do zapisu, byliśmy w stanie łatwo zaktualizować kolory kafelków, po prostu aktualizując jeden indeks tablicy. To prawda, że ​​musieliśmy przechowywać naszą paletę kolorów w odwróconej kolejności bajtów (ABGR), aby bajty automatycznie trafiały we właściwe miejsca podczas odczytu za pomocą Uint8ClampedArray .


Obsługa aktualizacji otrzymanych przez websocket

Metoda drawRect() dobrze nadawała się do rysowania aktualizacji piksel po pikselu w miarę ich odbierania, ale miała jedną słabość: duże porcje aktualizacji napływających w tym samym czasie mogły powodować zacinanie się w przeglądarkach. Zrozumieliśmy, że aktualizacje stanu tablicy mogą pojawiać się bardzo często, więc problem trzeba było jakoś rozwiązać.


Zamiast natychmiastowego ponownego renderowania płótna za każdym razem, gdy otrzymujemy aktualizację websocket, zdecydowaliśmy się zrobić to tak, aby aktualizacje websocket, które docierają w tym samym czasie, mogły być grupowane i renderowane zbiorczo. Aby to osiągnąć, wprowadzono dwie zmiany:

  1. Przestań używać funkcji drawRect() — znaleźliśmy wygodnym sposobem aktualizuj wiele pikseli jednocześnie za pomocą putImageData() .
  2. Przenoszenie renderowania płótna do pętli requestAnimationFrame.

Zawijając renderowanie w pętlę animacji, byliśmy w stanie natychmiast zapisać aktualizacje websocket do ArrayBuffer, odraczając rzeczywiste renderowanie. Wszystkie aktualizacje websocket przychodzące między ramkami (około 16 ms) były łączone i renderowane w tym samym czasie. Dzięki zastosowaniu requestAnimationFrame , gdyby renderowanie trwało zbyt długo (dłużej niż 16ms), wpłynęłoby to tylko na częstotliwość odświeżania płótna (a nie na obniżenie wydajności całej przeglądarki).

Interakcja z płótnem

Należy zauważyć, że płótno było potrzebne, aby ułatwić użytkownikom interakcję z systemem. Główny scenariusz interakcji to układanie kafelków 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 zoomu (dużego!). Ponadto użytkownicy musieli mieć możliwość łatwego poruszania się po obszarze roboczym, ponieważ był on zbyt duży dla większości ekranów (zwłaszcza podczas korzystania z powiększenia).

Powiększenie

Ponieważ użytkownicy mogliby umieszczać kafelki raz na pięć minut, błędy w umieszczaniu byłyby dla nich szczególnie frustrujące. Konieczne było wykonanie powiększenia o takiej krotności, aby kafelek był wystarczająco duży i można go było łatwo umieścić w Właściwe miejsce. Było to szczególnie ważne w przypadku urządzeń z ekranem dotykowym.


Zaimplementowaliśmy zoom 40x, czyli każdy kafelek miał rozmiar 40x40. Owinęliśmy element w

, do którego zastosowano CSS transform: scale(40, 40). To było świetne rozwiązanie do układania kafelków, ale utrudniało zobaczenie planszy (zwłaszcza na małych ekranach), więc powiększyliśmy o dwa stopnie: 40x do rysowania kafelków, 4x do przeglądania planszy.


Wykorzystanie CSS do skalowania płótna ułatwiło oddzielenie kodu odpowiedzialnego za rysowanie planszy od kodu odpowiedzialnego za skalowanie. Ale to podejście ma kilka wad. Podczas skalowania obrazu (płótna) przeglądarki domyślnie stosują algorytmy wygładzania obrazu. W niektórych przypadkach nie powoduje to niedogodności, ale po prostu niszczy grafikę pikselową, zamieniając ją w mydlaną owsiankę. Dobrą wiadomością jest to, że istnieje właściwość CSS renderowania obrazu, która pozwala nam „poprosić” przeglądarki, aby nie stosowały wygładzania. Zła wiadomość jest taka, że ​​nie wszystkie przeglądarki w pełni obsługują tę właściwość.


Rozmycie w powiększeniu:



Dla takich przeglądarek trzeba było znaleźć inny sposób skalowania. Wspomniałem powyżej, że istnieją trzy sposoby rysowania na płótnie. Pierwsza, drawImage() , obsługuje rysowanie istniejącego obrazu lub innego płótna. Obsługuje również skalowanie obrazu podczas renderowania (zwiększanie lub zmniejszanie). Chociaż powiększanie ma te same problemy z rozmyciem, co powyższy CSS, można je rozwiązać w bardziej ogólny sposób pod względem obsługi przeglądarki, usuwając flagę CanvasRenderingContext2D.imageSmoothingEnabled.


Rozwiązaliśmy więc problem rozmytego płótna, dodając kolejny krok do procesu renderowania. W tym celu wykonaliśmy jeszcze jeden element , który ma taki sam rozmiar i położenie jak element kontenera (czyli widoczny obszar planszy). Po przerysowaniu płótna za pomocą funkcji drawImage() jego widoczna część jest rysowana na nowym kanwie w żądanej skali. Ponieważ ten dodatkowy krok nieznacznie zwiększa koszty renderowania, użyliśmy go tylko w przeglądarkach, które nie obsługują właściwości CSS renderowania obrazu.

Poruszanie się po płótnie

Płótno jest ładne duży obraz, zwłaszcza po powiększeniu, więc musieliśmy mieć możliwość poruszania się po nim. Aby dostosować położenie płótna na ekranie, zastosowaliśmy to samo podejście, co w przypadku skalowania: zawinęliśmy element do innej

, do którego zastosowano CSS transform: translate(x, y). Dzięki oddzielnemu divowi mogliśmy łatwo kontrolować kolejność nakładania transformacji na płótno, co było konieczne, aby zapobiec przesuwaniu się „kamery” podczas zmiany zoomu.


W rezultacie zapewniliśmy wsparcie różne sposoby ustawienia pozycji kamery:

  • „Kliknij i przeciągnij” (kliknij i przeciągnij lub dotknij, aby przeciągnąć);
  • „Kliknij, aby przenieść” (kliknij, aby przenieść);
  • nawigacja za pomocą klawiatury.

Każda z tych metod jest realizowana w inny sposób.

"Kliknij i przeciągnij"

Jest to podstawowy sposób nawigacji. Zapisaliśmy współrzędne x i y zdarzenia mousedown. Dla każdego z tych zdarzeń znaleźliśmy przesunięcie pozycji kursora myszy względem pozycji początkowej, a następnie dodaliśmy to przesunięcie do istniejącego przesunięcia płótna. Pozycja kamery została natychmiast zaktualizowana, więc nawigacja była bardzo responsywna.

„Naciśnij, aby przenieść”

Kiedy klikniesz na kafelek, zostanie on umieszczony na środku ekranu. Aby wdrożyć ten mechanizm, musieliśmy śledzić odległość między zdarzeniami mousedown i mouseup, aby oddzielić „kliknięcia” od „ruchów”. Jeśli odległość, na jaką przesunęła się mysz, nie była wystarczająca, aby można ją było uznać za „ruch”, pozycja „kamery” była zmieniana na podstawie różnicy między pozycją myszy a punktem na środku ekranu. W przeciwieństwie do poprzedniej metody nawigacji, pozycja „kamery” została zaktualizowana za pomocą funkcji łagodzenia. Zamiast od razu wyznaczać nową pozycję, zapisaliśmy ją jako „cel”. Wewnątrz pętli animacji (tej samej, której użyto do przerysowania płótna) bieżąca pozycja „kamery” została przesunięta bliżej celu za pomocą funkcji wygładzania. Pozwoliło to pozbyć się efektu zbyt gwałtownego ruchu.

Nawigacja za pomocą klawiatury

Można było poruszać się po płótnie za pomocą strzałek na klawiaturze lub WASD. Te klawisze sterowały wewnętrznym wektorem ruchu. Jeśli żaden z klawiszy nie został wciśnięty, to domyślny wektor miał współrzędne (0, 0). Naciśnięcie dowolnego klawisza nawigacyjnego dodaje 1 do x lub y. Na przykład, jeśli naciśniesz „w prawo” i „w górę”, współrzędne wektora będą wynosić (1, -1). Ten wektor został następnie użyty w pętli animacji do przesunięcia „kamery”.


Podczas animacji obliczano prędkość poruszania się w zależności od stopnia powiększenia za pomocą następującego wzoru:


motionSpeed ​​​​= maxZoom / currentZoom * speedMultiplier

Kiedy zoom był wyłączony, przyciski działały szybciej i bardziej naturalnie.


Następnie wektor ruchu został znormalizowany, pomnożony przez prędkość ruchu i zastosowany do aktualnej pozycji „kamery”. Zastosowano normalizację w celu dopasowania prędkości ruchów ukośnych i ortogonalnych. Na koniec zastosowaliśmy funkcję łagodzenia do zmian samego wektora ruchu. To wygładziło zmiany kierunku i prędkości ruchu, dzięki czemu „kamera” dużo się poruszała gładszy.

Wsparcie aplikacji mobilnych

Podczas osadzania płótna w aplikacjach na iOS i Androida napotkaliśmy pewne trudności. Najpierw musieliśmy uwierzytelnić użytkownika, aby mógł umieszczać kafelki. W przeciwieństwie do wersji internetowej, w której uwierzytelnianie odbywa się na podstawie sesji, w aplikacje mobilne użyliśmy OAuth: w tym przypadku aplikacje powinny udostępniać zalogowanemu użytkownikowi WebView z tokenem dostępu. Najbezpieczniejszym sposobem wdrożenia tego jest wstrzyknięcie nagłówków autoryzacji OAuth za pośrednictwem wywołania JS z aplikacji do WebView. To pozwoliłoby nam dostosować inne nagłówki, jeśli to konieczne. Następnie wystarczyło przeanalizować nagłówki autoryzacji przy każdym wywołaniu API:


r.place.injectHeaders(('Autoryzacja': 'Nośnik ’});

W wersji na iOS dodatkowo zaimplementowaliśmy obsługę powiadomień, gdy kafelek użytkownika był gotowy do umieszczenia na kanwie. Ponieważ umieszczenie odbywało się w całości w WebView, musieliśmy zaimplementować natywne wywołanie zwrotne aplikacji. Na szczęście w iOS 8 i nowszych można to zrobić za pomocą prostego wywołania JS:


webkit.messageHandlers.tilePlacedHandler.postMessage(this.cooldown / 1000);

Metoda delegata w aplikacji wysyłała następnie powiadomienia na podstawie przekazanego do niej licznika czasu ładowania.


Czego się nauczyliśmy

Zawsze czegoś brakuje

Wszystko idealnie zaplanowaliśmy. Wiedzieliśmy, kiedy nastąpi premiera. Wszystko musiało pójść jak w zegarku. Testowaliśmy front-end i back-end pod obciążeniem. My, ludzie, po prostu nie mogliśmy popełnić więcej błędów. Dobrze?


Uruchomienie przebiegło naprawdę sprawnie. Rano, wraz ze wzrostem popularności r/Place, wzrosła liczba połączeń i ruch do instancji WebSocket:




Przewidzieliśmy to. I przygotowywaliśmy się na to, że w efekcie sieć stanie się wąskim gardłem w naszym systemie. Okazało się jednak, że mamy duży zapas. Jednak patrząc na użycie procesora, zobaczyliśmy zupełnie inny obraz:



To maszyny ośmiordzeniowe, więc było oczywiste, że osiągnęły swój limit. Dlaczego te „pudełka” zachowywały się tak nieoczekiwanie? Uznaliśmy, że obciążenie generowane przez Place ma bardzo różny charakter od tego, co było wcześniej. Ponadto użyto dużej liczby bardzo małych wiadomości, podczas gdy zwykle wysyłamy większe wiadomości, takie jak aktualizacje wątków na żywo i powiadomienia. Ponadto zwykle nie mamy tak wielu użytkowników otrzymujących tę samą wiadomość. Warunki pracy były więc bardzo różne od zwykłych.


Uznaliśmy, że nic strasznego się nie dzieje: zwiększamy skalę i już. Odpowiedzialny pracownik po prostu podwoił liczbę przypadków i poszedł do lekarza bez grama ekscytacji.


A potem stało się to:



Na pierwszy rzut oka nic specjalnego. Gdyby nie fakt, że była to nasza instancja produkcyjna RabbitMQ, która obsługuje nie tylko komunikaty websocket, ale wszystko, od czego zależy reddit.com. I nie było dobrze. Wcale nie dobrze.


Po licznych dochodzeniach, załamywaniu rąk i aktualizacjach instancji zawęziliśmy źródło problemu do interfejsu zarządzania. Zawsze wydawało się to powolne i zdecydowaliśmy, że regularnie prosi o to nasz kolekcjoner Rabbit Diamond. Sądziliśmy, że dodatkowa wymiana danych związana z uruchamianiem nowych instancji websocket, w połączeniu z masą otrzymywanych w związku z tą wymianą komunikatów, doprowadziła do przeciążenia Królika, który starał się śledzić realizację żądań do Panel administratora. Więc po prostu go wyłączyliśmy - i sytuacja się poprawiła.


Ale nie lubimy przebywać w ciemności i tak dalej pochopnie spartaczył prowizoryczny skrypt monitorujący:


$ cat s****y_diamond.sh #!/bin/bash /usr/sbin/rabbitmqctl list_queues | /usr/bin/awk "$2~//(print "servers.foo.bar.rabbit.rabbitmq.queues." $1 ".messages " $2 " " systime())" | /bin/grep -v "amq.gen" | /bin/nc 10.1.2.3 2013

Jeśli zastanawiasz się, dlaczego ciągle dostosowywaliśmy limity czasu rozmieszczenia pikseli, odpowiedź jest taka, że ​​staraliśmy się zmniejszyć obciążenie całego projektu. Z tego samego powodu od pewnego czasu niektóre piksele nie były wyświetlane na planszy przez długi czas.


Niestety mimo takich komunikatów:



Wspomniane tutaj zmiany czasu odnowienia były czysto przyczyny techniczne. Chociaż po nich ciekawie było obejrzeć r/place/new branch:



Być może była to część motywacji użytkowników.

Boty pozostaną botami

Na końcowym etapie projektu napotkaliśmy kolejne zawirowania. Regularnie mamy problemy z niewłaściwymi zachowaniami klientów w zakresie ponawiania prób. Wielu klientów napotyka błędy i po prostu ponownie przesyła żądania. I jeszcze raz. I jeszcze raz. Oznacza to, że gdy na stronie pojawia się jakiś problem, prowadzi to do fali powtarzających się próśb klientów, którzy nie wiedzą, co to jest fragment.


Kiedy wyłączyliśmy miejsce, punkty końcowe, do których dostęp miało wiele botów, zaczęły zwracać błędy inne niż 200. Ten kod nie był zbyt udany. Na szczęście wszystkie te powtarzające się połączenia były łatwo blokowane na poziomie Fastly.

Tworzenie czegoś więcej

r/Place nie odniósłby takiego sukcesu, gdyby nie dobra koordynacja Praca w zespole. Chcielibyśmy podziękować u/gooeyblob, u/egonkasper, u/eggplanticarus, u/spladug, u/thephilthe, u/d3fect i wszystkim innym, którzy pomogli urzeczywistnić ten prima aprilisowy eksperyment.



Podobne artykuły