 Jestem Tomek i pracuję w Allegro, który jest platformą e-commerce, który jest w centralnym Europie, Polskim. Dzisiaj chcę zrozumieć nasz journey z preformacją Maratą i problemów, które przyjeżdżamy na naszą drodę do nowej solucji. Zaczniemy z Maratą z Maratą i Messosem w 2015 roku. Wreszcie zaczęłem zrozumieć z Maratą w 2015 roku. To jest mój pierwszy komit, kiedy zaczęłem zrozumieć z Maratą i produkcją. Uwiedziłem mi, i to jest to, jak zaczęło. Więc, z powrotem, mówimy o preformacjach. Pierwsza projekcja dla mnie jest na to, jak zrozumieć wszystko. Maratą ma metrykę. Wreszcie wyszło w 0,13 wersji, i od początku mamy głębą w środku co się dzieje w Maratą. Zobaczmy metryki z aktorami, z namiotami, z zukipami, z targami, z aplikacją, z metryką. Myślę, że musimy zobaczyć, co się dzieje, i porozumieć o preformacjach. Maratą opuści wszystkie metryki lub datastarów, jak grafite, które użyjemy, datadoks, studsd. To jest suport dla promytusów, ale żeby użyć, musisz mieć aktywną adaptorę, który jest dostępny na github, bo Maratą prezentuje metrykę w formatach jazdy i promytusy wymagające w formatach flatnych, jak CSV. Więc, jak umożliwiać metrykę, jeśli nie zrobiłeś to? Musisz włożyć konfiguracyjną opcją z raportem w tym przykładu, jest grafite. Protokol, który chciałeś użyć, jak DCP lub UDP, gdzie umożliwiać metrykę, to jest opcjonalne, jeśli nie wywołaścisz, to nie jest w porządku. I interwał, który jest też opcjonalny do opcji 10. Więc, zobaczmy, co się dzieje, jak umożliwiać metrykę. Jesteście familiari z grafami, dla tych, którzy wiemy, grafami są generowane z profilerań, kiedy profilujemy Maratą, widzieliśmy coś takiego. X-axis, to jest cpu time. Smalne bloky są funkcjonalne, które są w porządku i są w porządku. To znaczy, że ta funkcjonalna jest w porządku. Kolory są w rady i w ciele, więc to powinno wyglądać jak graf. Niestety Maratą jest w rytmach, więc to jest w porządku ale co jest ważne, to jest metryka. Kiedy mamy metrykę interwał na 10 sekund, metrykę, w górze metrykę ma prawie 20% cpu. Więc to nie jest dobrze na porządku, więc jeśli chcesz używać metrykę, używaj twice, to ma sensibilny interwał. Szczerze 10 sekund, który był 55 sekund, ulepszył metrykę cpu do mniej niż 3% i to było okej. I to był pierwszy wielki udział na porządku w przypadku Maratą. Kiedy mamy graf tutaj, nie możesz powiedzieć coś z tego, ale tutaj jest jeden ważny punkt. Mam nadzieję, że widzisz to jeszcze raz. To jest na porządku na porządku. Jeśli ten blok jest większy, to nie jest prawdopodobnie regresja w porządku na porządku na porządku i trzeba ulepszyć. Ale to nie stało do nas. Są kiedy mówimy o metryce, musimy powiedzieć coś o librze, które używają na porządku na porządku na porządku. To loga jest Drop Wizard. Maratą używa Drop Wizard na porządku na porządku na porządku i integracji z grafami i datadogu. Z wersji 1.4 Maratą ulepszy do Kamonu, który jest na porządku na porządku na porządku na porządku. I dlaczego to jest ważne? Jeśli używasz systemu powinnaś się zrozumieć najlepszy poziom odpoczywania. Ulepszy problem z metryką i to zazwyczaj problem był najnowszy i zazwyczaj wersja Drop Wizards. Musimy to ulepszyć i wszystko zostało zazwyczaj. Mam nadzieję, że widzisz te wersja z zazwyczajem JVM na porządku na porządku. Mam nadzieję, że widziałem to dwa lata wcześniej kiedy mój zazwyczaj było manualnie zrobiony. Tak, ale kiedy zaczęliśmy wersję o JVM powinniście myśleć o garpach. Java jest znawna po prostu zbyt silna ponieważ nie wgrywa się w GCD. i to nie jest to, co powinno się wydarzyć. To znaczy, że gc konfiguracja jest walińsza. Jak się zauważyć GARBAGE-kollekcję? Niebezpieczna optymizacja. Po prostu pójdę ten smalny snipet w konfigurację JVM na Marathon. To będzie tworzyć gc-log w viral-logmarathon.gc.log z wsparciem informacji, które są potrzebne, żeby wyobrazić, co się dzieje z FEDA-HIP i jak gc-log pracuje. W tym przykładzie mamy 15Mg gc rotatorowe w dwóch filich. Jak wyobrażamy ten filo, możemy używać tool, jak Chansum, stworzone przez J-Clarity. Chciałbym powiedzieć, co się stało z formą gc-logu czy innego java aplikacji. To jest screen shot, które stworzyłem wczoraj od latach z gc-logu, które mamy na produkcji. Jak widać, 50Mg jest około 12 dni. Chansum daje ci jakieś indikacje, co się stworzyło, a nawet możesz kliknąć na to, a to powoduje, co konflikt powinien się zmienić. Niestety, nie daje żadnych walory, ale jest dobrze zacząć. W tym przykładzie mamy gc-log, więc powinniśmy wyobrazić XMX. To jest problematyczna, kiedy maraton pracuje i ma wiele obcięs, ale są w porządku przez wszystkie generacje z gc-logu i to, co mamy na gc-logu. Kolejny tool, który mi się podoba, jest gc-easy. Jest to web-tul, gdzie wyobrażasz gc-log. To jest lepsze, tylko ma fajny UI i bardzo informatywne diagramy. To jest same gc-log, i na zdjęciu są jakieś gc-logy, które odbierają więcej niż sekund, a wreszcie są 4 sekund. To jest dźwięk gc-logu. Nie wiem, czy jesteście znowu, jak gc-loga jest pracować. Bądź gc-loga ma dwa rodzaje pamięci, więc gc-log jest sprzedał do 2. To jest dźwięk generacji i dźwięk gc-logu. Gc-logu wydaje się, że jeśli jakiś obcięz obserwuje dźwięk generacji, więc to jest dźwięk dźwięk generacji, to będzie dźwięk dźwięk. I dźwięk gc-logu rzuca się, kiedy nie ma dźwięk generacji. Problemy zaczynają, kiedy większość obcięzów jest zbudowany do dźwięków, a potem jest zbudowany. To znaczy, że to jest problem. Chcę pokazać ci, że powinniście zmienić parametrów, które powinniście utrudnić JVM, bo to naprawdę spowoduje o twojej używanej, a co te funkcje z Marathonu użyjesz? Tak, druga rzecz w Marathonu jest akka. Akka to aktajka dla skala. Wreszcie, to jest implementacja w JVM. Niestety, JVM ma pewien model memory i pewien filmik, który jest nie najlepszy dla aktorów, ale akka próbuje pracować na tym. Akka ma ciekawą opcją, np. obcięzów. W porządku, chcemy mieć obcięzów, ale obcięzów w akce i jakieś opcją będzie otworzone przez aktorów na obcięzów i pracować na obcięzów To znaczy, jeśli zauważymy jedną opcją i pracować na obcięzów i obcięzów można używać CPU. Ale dla realnych aplikacji ten approaches nie jest najlepszy, dlatego, że cieszy są inwaliowane i w kontekstach, ponieważ akka każda time aktorów ma się zmienić, akka ma się założyć na obcięzów. Marathon używa wpływ 5. Zauważyliśmy, że określenie tej akcji do 20 da się lepszy wreszcie. Ale to naprawdę w porządku na używaniu. Jesteśmy używania eventów i w tej chwili używaliśmy Marathon Healthchecks. Więc są też Marathon feature, które są wpływane na obcięzów. Więc kiedy wycieczysz to, pamiętaj, żeby sprawdzić, czy to naprawdę pomaga. Ok. ZUKIPER Marathon używa ZUKIPER od początku, jako stary stary nie tylko dla lekarzów, ale cały stary aplikacji z Marathonu używa płatny layout, jak wszystko było w jednym branczu. I od 1.4 wycieczą do stary stary stary z podróżującym branczu na ulicy, obcięzów, obcięzów i grupy. ZUKIPER jest mocna konsystencja. To znaczy, że to może uratować datoń, ale kiedy datoń jest za wielka, to będzie ciężko, żeby procesować. Jeśli widzisz ten bag to znaczy, że masz chyba ponad 300 aplikacji w twoim klasyce. To był problem. Kiedy chcesz dołączyć bardzo ważną aplikacją do produkcji, to zauważy. Ponieważ obcięzów w Marathonu do 1.4 i po wycieczku to znaczy, że z 100 aplikacji wycieczkowali dwie liczby w Marathonu. To może być kompresowe, ale czasami wycieczkowali 1 megabyte defaultu dla ZUKIPER. Więc zrobimy to, że zmienimy max note size. Udaję to do 2 megabytes. Ale dokumentacja też powiedziała nam sprawdzić dokumentację ZUKIPER. I zwłaszcza, że aby wycieczkać ZUKIPER size musisz też wycieczkać max buffer dla ZUKIPER. I jeśli wycieczkowali, musisz to zrobić na wszystkich ZUKIPER masters i klienci. I ważną note nie jest jak megabytes data. To jest w porządku, żeby wycieczkać kilobytes w jednej note, bo ZUKIPER klaser może mieć gigabytes data. Jak powiedziałem, z 1.4 Marathonu wycieczkowali dwie layouty z ZUKIPER data. Co to znaczy? Wycieczkać z jednej note wycieczkała, ale wycieczkę się zamiarować. Przed wycieczkałem ciemna objaźna i wszystko wytrzał w tego objaźnia w ZUKIPER. W 1.4 Marathonu wycieczkała dwie objaźnie wycieczki z ZUKIPER, które miały referencje do objaźnia, które są osiągnięte ZUKIPER jest znacznie znaczeniem, bez transakcji, a gdybyśmy tworzyli referencje, zresztą robiliśmy relacje bez transakcji. I to może zauważyć czasami, kiedy są wystarczające od ZUKIPER, jak zniszczenie jest zbrojone, kiedy stwierdziłem jakieś data, czy to się skończyło, i Marathon nie chce się skończyć. To nie jest regresja, to się dzieje w 1.3 i below 2, ale w 1.4 może zdarzyć więcej. Więc co musisz zrobić, kiedy jesteś wystarczający przez ten bag, tylko jedna rzecz, jest, że możesz to zrobić, kiedy masz zniszczenie do ZUKIPER i zniszczenie problematycznego node. Pierwsza rzecz, zniszczenie z ZUKIPER, jest naprawdę zniszczenie do latenia między node, więc jeżeli jesteś zniszczenie z ZUKIPER przez te dwa zniszczenie, to będą problemy z replikacją i stąd. Co więcej, jeśli jesteś zniszczenie z ZUKIPER na samą node, jak Marathon, i przez zniszczenie z Marathon jest to same, jak z ZUKIPER, to zniszczenie z ZUKIPER will increase, a ZUKIPER i Marathon will fight for their resources as a CPU and memory. Best we can do, put ZUKIPER on the dedicated host near to each other, but if you need to replicate to another DC, just make a read-only copies in this another DC. Masters should be only in one DC close to each other. The fourth tip is to update to 1.314. It is the last release on the 1.3 branch. And there is a little star, I will tell about this later. Why? Marathon is written in AKKA, it tries to utilize all CPU that you have. So it spawns many system threads. In Marathon code there is configuration that was not touched for ages that creates a thread pool for actors for 64 threads. There is another pool this time 100 threads for IO operation. So in theory Marathon should spawn only 64 plus 100 threads. And our experience is that it's equal to two thousands. And we have three different environments for Marathon and we observe that number of threads was correlated with the number of tasks. In fact it was because from the number of tasks. Why does it happens? Because whenever blocking request is called by the actor wait for the result of some other operation the thread is spawned. And in general this is good. This is how AKKA work. It's created to prevent actors from be blocked by one operation in one actor. But when there are code that it's not written in a reactive way this is what's happened. So this is the diagram of our threads on one of our cluster. So as you can see there are about two thousand threads and after deployment of 1.3.7 when the back was fixed the thread count is less than 200. And that's okay because AKKA spawns 164 threads. There are still some places where there are blocking operation in actors. But we need to count also the JVM threads like GC threads. So 200 is much better than 2000. Next optimization in a marathon that you can do only in 1.3 0.13 and 1.4 and 1.5 is no optimization. This thread from Jonathan could be rephrased into the fastest operation you can possibly perform is no operation at all. What does it mean? You should delegate the operation you want to perform or marathon was doing somewhere else. Then it has time for doing its job like deploying applications. And the first thing that works for us are health checks. Marathon has health checks from the very beginning. It supports HTTP, TCP and command health checks. And command health checks are performed by messes while Marathon, HTTP and TCP health checks were performed by a single master. And it works. You've got the six tasks, two of them are unhealthy Marathon query or healthy no or healthy yes. And this is working as long as you have only six tasks but when you have more it's not scaling. The single Marathon instance can handle more than 2,000 tasks for HTTP health checks. So what we can do we can delegate that job to messes why not and make use of this that these tasks are not run in a void. They are run by messes agent. All this block is a messes agent. And tasks are run by executors and executor gets a feature of making TCP and HTTP health checks from 1.1 from messes 1.1. It's an experimental feature in 1.2 it's stable. So messes executor is health checking tasks and when the task becomes healthy or change its health state it updates messes agent when messes agent got the update it updates messes master and then finally Marathon is notified with a task status a task status message from messes that the task is healthy or unhealthy. This means Marathon has much less work to do. It only handle the passing state and failures. In the worst case scenario when all tasks are unhealthy Marathon will have as many job as it previously because every task needs to report that it's unhealthy but in a real world usually the task becomes healthy and its state usually don't change. As I said Marathon can handle limited numbers of tasks for TCP health checks it's 4000 and for HTTP health checks it's nearly 2000. The numbers are taken from the brilliant blog post written by Gaston this year and I can confirm them we experienced the problems with Marathon health checks starting with 50 hundred tasks the problem is when Marathon has problem with health checks it will show you that there is a problem with health checks because it's time out due to time seconds time out and we were debugging problems on the network layer while it was the problem on Marathon itself. So it looks for us we are using 1.3 as you can see this is the Marathon response times measured from one of our systems called Marathon console it's query Marathon 4 some additional metadata about the tasks then we deployed 1.4 it was completely disaster somewhere here we rolled back to 1.3 and implemented back ported methods health checks from Marathon 1.4 and as you can see this line is the Marathon response time reduced nearly 2 times comparing to this 1.3 where we run 3000 tasks without methods health checks Another thing is why we are still using Marathon 1.3 is the deployment degradation in case of performance in 1.4.2 fortunately yesterday I talked with Johannes from Mesosphere and he showed me that version 1.4.7 fixes this problem and it's the degradation was reduced in fact there is no degradation and in fact version 1.5 that was released a week ago fixes the problem with the threads in the deployments so you have 3 options one you can use methods 1.3 with methods health checks it require merging our patch for Marathon that will enable methods health checks update to 1.4.7 or 1.5 5 tip do not use event bus we are using event bus for task registration in console because the console is our service discovery solution we've got a little program that is written in Go that consumes events in Marathon and register tasks based on that event in Marathon there are 2 options of registering for events callbacks and server sent events the callbacks were implemented as a first option you register for an event and then Marathon post that event in a request body to your endpoint this was good but the problem starts once you got the bigger cluster because there is no filtering for these events and some events are really big especially deployments events for our installation it was almost over 10 megabytes and it's 10 megabytes of data that needs to be serialized on Marathon site and for us they are not interesting so it was serialized and put into void so we switched to server sent events which support filtering from 1.3.7 so only events that need to be serialized are serialized still some events are big but we can filter them and the performance increased as you can see this is the Marathon events delay when using Marathon callbacks measured as a time difference between timestamp in the events and local timestamp as you can see 7 minutes of delay for service discovery solution it's like eternity we've got an outages because of this this approach so we quickly switched to server sent events and everything is fine this is a millisecond so it's huge improvement also the heap is not used that much because we do not have this huge jason that needs to be serialized the GCE works less there is no havoc in the heap it's just better but I said you should not you should not use events at all why some operations that you think or you want to make happens synchronically are not best for events as you can see on previous slide we've got a 20 milliseconds delay so what we are using doing now we are creating a custom executor that instead of sending events act on some events that happen on executor site so when tasks become healthy now executor register it in a discovery service not some other marathon instance so this is like solution for this gap of this 30 milliseconds and marathon do not sense event at all so it do even less seventh tip is when we started using marathon the compliance guy comes to my room and ask me for access locks and we don't have them so we implemented LDAP filter for marathon then it becomes marathon plugin for authentication and how it's working user creates request and on marathon site each application for example user want to query to get all application running on the cluster on marathon site marathon is checking if each application can be shown to the user then download data from the zookeeper and then prepare a response this is not best solution we create a facade before marathon so the user query our facade downloads all data from marathon and then remove the sensitive data that shouldn't be presented to that particular user this is simple optimization but it works for us and the last last tip is sharding so once you hit a roof and you can do anything more like you bought the bare metal machine to run marathon tune JVM, reduce operations don't buy marathon switch to messes health checks the last thing you can do is sharding and currently we implemented sharding and started using it our sharding key is marathon app ID and how it's how it's working we started from the facade so it's easy to just put multiple backends from the facade so when the user want to deploy application A we use consistent hash to find which of marathon should it be deployed to all marathon shares one messes cluster but the performance problems disappear because now each of these instance has less than 500 apps so to sum up monitor, tune JVM optimize zookeeper tune zookeeper JVM because it's running written in java update to latest stable version that is working for you if it's 1.3.15 good 1.4.7 or 1.5 do not event bars if you have some synchronical some events that should happen if it's running use custom executor prefer batching and if all above does not help shard your marathon that's all thank you how much of applications not tasks but applications if it is not we have three environments on our production over I think it's less than over 500 apps with 3000 tasks and this is the production on the development environment we have we used to have 3000 applications and 3000 tasks because usually developers deploy application in one tasks to just check if it's communicate correctly and small workload but now we are sharding it so this is environments are less than 500 apps how much zookeeper nodes are you using 305 we are using five zookeeper nodes on production and they are replicated in second dc with zookeeper observer so they are in observer mode when one dc goes down you can switch the flag and then the second dc should be operating but right now we are sharding marathon so we for some environments we've got only three zookeeper three zookeeper master located in one dc last question will you open source your custom executor? I hope I submitted a talk for a messes.com Prague where I will describe our solution it's based on messes.go created by James J.Def from Mesosphere there one custom part of this that we can't open source but I think the whole solution will be open source next month thank you very much thank you