Dzisiaj mamy tematy bezpieczeństwa rodem z USA, kontynuacje (i pewnie już podsumowanie) tematu 1BRC oraz ciekawy case od Netflix
1. Biały Dom rekomenduje używanie języków z bezpiecznym zarządzaniem pamięcią – między innymi Javy
Dzisiaj zaczniemy od bardzo ciekawego ogłoszenia, prosto z Białego Domu.
Administracja prezydenta USA Joe Bidena apeluje bowiem do programistów o stosowanie bezpiecznych pod względem zarządzania pamięcią języków programowania i rezygnację z języków podatnych na ataki, takich jak C i C++. Biuro Dyrektora Narodowego ds. Cyberbezpieczeństwa (ONCD) w wydanym raporcie wzywa deweloperów do zmniejszania ryzyka cyberataków poprzez wykorzystanie języków programowania chroniących przed problemami bezpieczeństwa związanymi z pamięcią, takimi jak przepełnienia bufora, odczyty poza granicami oraz wycieki pamięci. Raport podkreśla, że około 70% wszystkich luk bezpieczeństwa jest spowodowanych przez problemy z bezpieczeństwem pamięci, a zmiana na języki programowania bezpieczne pod względem zarządzania pamięcią może zapobiec wprowadzaniu całych klas podatności do ekosystemu cyfrowego.
Nowy raport ONCD wymienia Javę jako przykład bezpiecznego języka programowania, podczas gdy C i C++ są podane jako przykłady języków z lukami w bezpieczeństwie pamięci. NSA w swojej informacji na temat cyberbezpieczeństwa wymienia również C#, Go, Rusta, Ruby i Swift jako języki uważane za bezpieczne pod względem zarządzania pamięcią. Celem raportu jest przeniesienie odpowiedzialności za cyberbezpieczeństwo z jednostek i małych firm na większe organizacje i rząd USA, które są lepiej przygotowane do zarządzania ciągle ewoluującymi zagrożeniami. Eksperci podkreślają, że przejście z C i C++ na inne języki będzie długim i trudnym procesem, ale istniejące alternatywy, już teraz zyskują na popularności, co może przyspieszyć ewolucję w kierunku bezpieczniejszego kodowania. Ostatnio opublikowane Foreign Function and Memory (FFM) API, choć nie wymienione z nazwy, bardzo dobrze wpisuje się w ten trend.
A jak już się pojawił temat Rusta, to nie mogę sobie odmówić podrzucenia Wam miniaturki Java is becoming more like Rust, and I am here for it!. Rust dla niektórych stał się standardem złota (co dla innych jest pewnie dość kontrowersyjnym stwierdzeniem) ale Java też ewoluuje, o czym chyba nie muszę przekonywać żadnego z czytelników tego newslettera. Z biegiem lat, języki te coraz bardziej zbliżają się do siebie pod wieloma względami Przykładami takich innowacji podawanych przez artykuł są niemutowane Rekordy i Sealed Interfaces, ułatwiające modelowanie złożonych typów danych. Dzięki temu coraz więcej mamy w naszym języku konstruktów z rodziny tak zwanych algebraiczne typy danych, umożliwiających precyzyjne reprezentowanie stanów i zachowań i tak zwany Data-Oriented Programming. Krótki food for thought.
A jeśli chcecie lepiej zrozumieć, o co chodzi z tym całym DOP, polecam podcast Adama Biena i odcinek From Hexagonal Architectures to Data Oriented Programming, w którym gości Jose Paumard i rozpracowują wspólnie ten temat.
Zainstaluj teraz i czytaj tylko dobre teksty!
2. To już pewnie ostatni raz… ale wracamy do tematu 1BRC
Wyzwania Miliarda Wierszy (1BRC), koncentrujące się na optymalizacji kodu Java w celu jak najszybszego przetworzenia 1 miliarda wierszy danych ze stacji meteorologicznej i obliczeniu minimalnej, średniej i maksymalnej temperatury, już dawno za nami. Jednak nie przestaje ono rozpalać wyobraźni społeczności, która wyprodukowała ostatnimi czasy masę artykułów podsumowujących techniki używane w ramach challenge. Dlatego postanowiłem przyglądnąć się kwestii jeszcze jeden raz i podsumować te najciekawsze.
Pierwsza z pozycji to artykuł Marka Topolnika z QuestDB, który szczegółowo opisuje swoją przygodę w ramach wyzwania – dość powiedzieć, że jego „naiwna” wersja rozwiązania oparta o Java Streams początkowo zajmowała 71 sekund na przetworzenie. Lista późniejszy opisywanych optymalizacji zawiera takie sztuczki, jak równoległego przetwarzania I/O czy bezpośrednie parsowanie temperatur do liczb całkowitych, poprzez wykorzystanie niestandardowych struktur danych dla danych (co również „make a difference), aż po niskopoziomowe optymalizacje, takie jak używanie sun.misc.Unsafe
dla dostępu do pamięci i technik SWAR (SIMD Within A Register) do szybkiego przetwarzania danych. Finalne optymalizacje obejmują zaś (z jednej strony) redukcje startu samej aplikacji, z drugiej zaś próby wykorzystania mechanizmów „branch prediction”.
Warto tu wspomnieć, że Mark Topolnik nie opisuje tutaj tylko swoich doświadczeń – całość wyzwania odbywała się w ramach nowych PR-ów na GitHubie, więc usprawnienia poszczególnych uczestników były szybko adaptowane przez resztę społeczności. To właśnie Mark opisał całość jednak w bardzo przystępny, łatwy do zrozumienia sposób. Nie jest on jednak tutaj jedynie kronikarzem – wyzwanie zakończył w pierwszej dziesiątce, na bardzo wysokiej, siódmej pozycji.
W czasie 1BRC zadawano sobie pytanie – czy LLM mają tutaj jakikolwiek start do doświadczonych inżynierów (no bo w końcu mamy 2024, to o czym mamy rozmawiać). Całość sprawdził Antonio Goncalves, który spróbował zrealizować 1BRC wykorzystując GitHub Copilot Chat, by zbadać, jak może on pomóc w w tak specyficznym przypadku optymalizacji wydajności kodu aplikacji. Wykorzystując głównie Copilot Chat do zadawania pytań i otrzymywania odpowiedzi bezpośrednio w środowisku IDE, Antonio skupił się na iteracyjnych poprawkach oryginalnego algorytmu (którego wykonanie zajmowało 4 minuty i 50 sekund). Dzięki poprawkom, które podobnie jak Mark opisuje krok po kroku, Antonio zdołał uruchomić swój kod poniżej minuty na swoim komputerze Mac M1, co jak łatwo policzyć było znaczącym osiągnięciem w porównaniu do bazowego algorytmu. Chociaż autor miał apetyt na więcej, to dalej ocenił GitHub Copilot Chat jako całkiem wartościowe rozwiązanie, gdyż jak twierdzi Narzędzie to nie tylko przyspieszyło rozwój funkcjonalnego algorytmu, ale także ułatwiło jego optymalizację i dostosowanie do środowiska JVM.
Ale 1BRC zdobyło też zainteresowanie osób niezbyt zaawansowanych w Javie (a przynajmniej nie na tyle, by ścigać się o czołowe miejsca), dzięki czemu dostaliśmy kilka innych, ciekawych publikacji. Przykładowo Gerald Venzl i Connor McDonald przeanalizowali, w jaki sposób można efektywnie przechowywać zbiory danych podobne do tego zaprezentowanego w 1BRC. Skupili się oni na wykorzystaniu bazy danych i analizie, jak serwer bazy danych może być skalowany do szybkiego przetwarzania danych. Gerald najpierw w swojej publikacji 1 billion row challenge in SQL and Oracle Database zszedł poniżej 5 sekund (również dokładnie opisując całość krok po kroku), a następnie Connor, wykorzystując technologię In-Memory do przyspieszenia zapytań analitycznych i odpowiednie ustawienia stopnia równoległości, udało mu się przetworzyć miliard wierszy w mniej niż sekundę… na standardowym laptopie z 16 GB RAM (aczkolwiek nie udało mi się dogrzebać, jaki to był model). Szaleństwo.
A na końcu – Go. Ben Hoyt z Canonicala postanowił opisać swoje rozwiązanie w Go i porównać go do Javy, aby rzucić światło na różnice w ekosystemach obu języków, zwłaszcza pod kątem optymalizacji i wydajności. Zaletą tekstu jest też to, że autor (jak jego poprzednicy zresztą) przeprowadza czytelnika przez kolejne iteracje swojego podejścia. Ben skupiał się na wykorzystaniu standardowej biblioteki Go bez uciekania się do niskopoziomowych operacji czy zewnętrznych narzędzi, takich jak pliki mapowane w pamięci. Dzięki iteracyjnym optymalizacjom, autor zdołał zmniejszyć czas przetwarzania z 1 minuty 45 sekund (rozwiązanie naiwne) do zaledwie 3,4 sekundy. Autor konkluduje, że dzięki wykorzystaniu zaawansowanych technik i optymalizacji specyficznych dla JVM (gdzie najszybsze rozwiązanie osiągnęło czas poniżej sekundy), może oferować wyższą wydajność. Go, z jego naciskiem na prostotę i czytelność, dalej zapewnił bardzo szybkie rozwiązanie jest ono nad wyraz zrozumiałe, nawet dla kogoś kto nie programuje na codzień w tym języku.
Zainstaluj teraz i czytaj tylko dobre teksty!
3. Netflix dzieli się doświadczeniami z użycia ZGC
Nie raz spotykam się z pytaniem, kto tak naprawdę używa tych wszystkich nowych funkcjonalności Javy i czy istnieją jakieś casy pokazujące, na ile sprawdzają się one w środowisku produkcyjnym. Dopiero co tydzień temu pisałem, że twórcy JDK powoli myślą o pozbyciu się nie-generacyjnego wariantu ZGC, pozostawiając jedynie dopiero co wprowadzony w JDK 21 wariant generacyjny, ale trudno się dziwić. Patrząc na doświadczenia Netflixa, nowa wersja wyszła im lepiej niż dobrze.
Netflix podzielił się bowiem efektami przeniesienia się z G1 na Generational ZGC. Artykuł Bending pause times to your will with Generational ZGC pokazuje zmiana znacząco podniosła wydajność kluczowych usług do streamingu wideo, z ponad połową z nich działa obecnie na JDK 21 i korzystających z redukcji latencji requestów P99+ (przy skali Netflix nawet dalsze percentyle to wciąż olbrzymi wolumen użytkowników) oraz eliminacji przerw spowodowanych przez garbage collecting. Minimalizując te przerwy, Netflix nie tylko zmniejszył ilość timeoutów, ale także uzyskał jaśniejszy wgląd w rzeczywiste źródła opóźnień, co pozwala im dalej optymalizować wydajność usługi.
Co ciekawe, Danny Thomas, twórca artykułu, wskazuje, że praktycznie nie wiążę się to z żadnymi trade-offami, co jest w software engineeringu jakimś ewenementem. Adopcja Generational ZGC przyniosła bowiem również operacyjną efektywność, a JVM Ecosystem Team Netflixa obserwuje teraz takie samo lub nawet lepszą wykorzystanie CPU dla tego samego obciążenia w porównaniu do G1. Nie występują też oczekiwane kompromisy w przepustowości aplikacji, i to nawet na konfiguracji domyślnej ZGC, który to nie wymagają jawnego dostrojenia i wraz z jego zdolnością do obsługi różnorodnych obciążeń z konsekwentnie dobrą wydajnością. Chociaż uznając, że ZGC może nie nadawać się do wszystkich obciążeń, szczególnie tych zorientowanych na przepustowość z sporadycznymi wskaźnikami alokacji, jest to raczej szukanie dziury w całym. Case Netflixa pokazuje, że twórcy Generational ZGC rzeczywiście wprowadzając ostatnie zmiany zrobili kawał dobrej roboty. Za każdym razem, kiedy macie swoją sesje Binge Watchingu, możecie mieć z tyłu głowy, że Wasze doświadczenie jest nieco lepsze właśnie dzięki ZGC.
And finally something private from me: I had the opportunity along with Frank Delporte to be a technical reviewer of Otavio Santana new book Mastering the Java Virtual Machine – and it’s a very good book, so I’m sharing it with my network.
In his work, Otavio tackles the challenging topic of bringing readers closer to the technological and business horizon associated with the Java Virtual Machine. This is a rather niche subject, which in my opinion, should not be – because the JVM is perhaps the most interesting aspect of the entire Java ecosystem and its family languages – you may have noticed by reading this newsletter that this is my cup of tea.
PS: This is not a paid promotion (shame that it always has to be added on the internet), the topic is simply really interesting, and since I had the opportunity to get acquainted with the whole thing at a very early stage and I was able to add at least tiny bit to the overall experience, I’m sharing the good news further!