Sunucu servisi sağlığı

Katılım
18 Aralık 2018
Mesajlar
9.072
Makaleler
14
Çözümler
128
Yer
Dubai
Bi sunucu yazilimi gelistiriyoruz. Programin bana ulastiktan sonraki tum kisimlari bir thread poolda calisiyor. Bugun bazi worker threadlerimin executionlarini tamamlamadigini ya da cok cok uzun surelerde tamamladiklarini gordum. Bu da threadlerin yeterince erken salinmamasina ve diger tasklarin queueda takili kalmasina sebep olacakti.

Neyin onlari durdugunu anlamak istiyordum ama SSH uzerinden debugging yaptigim icin hem debug sirasinda gereginden fazla bekliyordum gecikme nedeniyle, hem de durdur ilerlet, durdur ilerlet seklinde bir seyleri tespit etmek cok zor olacakti. Bunu cozmek icin calisan tasklarin neler oldugunu ve mumkunse hangi asamada takili kaldigini anlamam gerektigine karar verdim. Bunun sonucunda da sunu urettim;

ScreenRecording2025-04-24at5.22.13PM-ezgif.com-optimize.gif

Gorsel ne kadar anlasiliyor bilmiyorum ama basitce aciklayacak olursam, async worker threadleri kullanan her bir task, bir listeye ekleniyor, isi bittigindeyse bu listeden cikiyor. Programin bana ulastiktan sonraki her kismi da bu worker threadlerde calistigi icin aslinda butun tasklarim buradaki listeye eklenip cikiyor. Ufak bir bottleneck ekleyecek cunku listeden cikartmak bir seyleri O( n ) surede gerceklesiyor ama debugging icin oldukca yararli oldugunu dusunuyorum. Sunucunun /health end pointine istek attigimda call listi goruntuluyebiliyorum. Eger bir task uzun sure calisiyorsa, onun ne oldugunu ve onu kimin cagirdigini da goruntuleyebilirim.

Daha once yapilmis bir seyse benim haberim yok. Ihtiyactan dogan guzel bir fikir oldugunu dusunuyorum. Uzaktan debugging isini kolaylastiriyor benim adima.

Fikri uygulanabilir kilan kod blogu da su;
Java:
    @AllArgsConstructor
    public static class Caller {
        @Getter private List<StackTraceElement> trace;
        @Getter private String name;
        private long startTime;
        public long getRunTime() {
            return System.currentTimeMillis() - startTime;
        }
        public Document toDocument() {
            List<String> traceStrings = trace.stream()
                    .map(StackTraceElement::toString)
                    .toList();
            return new Document("trace", traceStrings)
                    .append("name", name)
                    .append("run_time", getRunTime());
        }
    }

    private static String callerName(StackTraceElement[] traceList) {
        final var element = traceList[4];
        try {
            final var methodClass = Class.forName(element.getClassName());
            if (Action.class.isAssignableFrom(methodClass)) {
                return methodClass.getSimpleName();
            }
        } catch (Exception e) {
            // pass
        }
        return String.format("%s.%s", element.getClassName(), element.getMethodName());
    }

    @Getter private static final List<Caller> callers = new ArrayList<>();
    private static Caller addToCallersList() {
        var traceList = Thread.currentThread().getStackTrace();
        final var caller = new Caller(Arrays.asList(traceList).subList(2,  Thread.currentThread().getStackTrace().length), callerName(traceList), System.currentTimeMillis());
        callers.add(caller);
        return caller;
    }

Array list yerine baska bir sey kullanarak belki darbogazi da azaltabilirim ama su an icin onemi yok.
 
Biz bu tarz isler icin Datadog kullaniyoruz. Task baslamadan once bir gauge metrici olusturup bitince de tamamdandigini gosteren event fire ederek ne kadar surmus, kim cagirmis, su an kac task calisiyor vs hepsi gorulebilir. Metrics Types

Eger mimari degistirmek mumkunse bu isleri MQ ile de yapmak mantikli, hangi queue da ne kadar birikmis takip etmek cok daha rahat olur. Birikme durumunda da consume eden kisim clonelanir.

Ayrica bu tarz yapilarin avantaji kollektif sekilde data takibi sunmasi, mobildeyim goremedim SS i ama eger ilgili server dan 5 tane varda bir cluster icinde hepsine tek tek bakmak gerekecek /health uzerinden.

Ama pragmatik basit bir cozum olarak bence mantikli, muhtemelen yazip devreye almasi 1 gun surmemistir bile.
 
Ama pragmatik basit bir cozum olarak bence mantikli, muhtemelen yazip devreye almasi 1 gun surmemistir bile.
1.5-2 saat civarinda surmustu yazip devreye almasi, test etmesi vs hep beraber. Epey de yardimci oldu durust olmak gerekirse. Iki bottlenecki tespit ettim bu sayede. Fikrin kendisini sekillendirmek koddan daha uzun surdu.
Eger mimari degistirmek mumkunse bu isleri MQ ile de yapmak mantikli, hangi queue da ne kadar birikmis takip etmek cok daha rahat olur. Birikme durumunda da consume eden kisim clonelanir.
Projeyi yayina almaya yakiniz. Yayina aldiktan sonra dusunulebilir aslinda. Suan icin single node olarak calisacagi icin onemi yok ama horizontal scaling kismina geldigimizde cok daha tatli olabilir MQ ile takip etmek.
 
Mevcut duruma yaklaşımınızı çok beğendim, pratik ve iş bitirici cinsten. Ben @bitwise'ın dediği gibi MQ kullanıyorum genelde. Hatta şöyle ki, test ettiğim süreç boyunca .NET ile kendi yazdığım kuyruklama sunucusunu kullanıyorum. Bu sayede hem kuyruktan hem thread'lerden bilgi almak çok kolay oluyor. Size de tavsiye ederim. Gerçi siz benden bir 10-15 kat daha iyi biliyorsunuzdur ama paylaşmak istedim :)
 
Gerçi siz benden bir 10-15 kat daha iyi biliyorsunuzdur ama paylaşmak istedim
Tesekkur ederim guzel sozun icin. MQ o dakika aklima gelmemisti. Zaten websocket kullaniyoruz uygulamada diye ilk yazdigimda aslinda websocket yaniti olarak yazmistim. Bir projede ZeroMQ kullandigimizdan asinayim aslinda sisteme ama dedigim gibi, o dakika aklima gelmemisti. Horizontal scaling asamasina geldigimde tum sunucularin kendi saglik durumlarini bildirdikleri nokta olmasi adina guzel olabilir MQ kullanmak. Post ederler biz de oradan izleriz durumu vs vs. Ama horizontal scalinge var daha vaktimiz. Yoksa olusturdugum her threadin saglik durumunu takip edebiliyorum poollar uzerinden calistigim icin. Yada hic degilse referanslarini bir yerde tutuyorum vs vs.

Bilmiyorum yukarida paylasitigim gorselde ne kadar anlasiliyor ama her pool icin ayri bir info gonderiyor JSON olarak, frontend tarafinda da her birini ayri bir card olarak listeliyorum. HealthWatchdog sinifin adi. Onun da kendi ayri bir poolu var sagligi takip etmek icin kullandigi (cok daha kucuk diger poollara gore, genelde single thread hatta, kendi yanitlarini verebildigi ekstra bir websocket instancei var). Normal de zaten bir thread pool kac tane task tamamladigini, kac taneyi kuyrukta beklettigini vs bildiriyor ama neyi beklettigiyle ilgili bilgi edinemiyorduk, simdi onlarda var artik bu listelere dahil.
 

Technopat Haberler

Yeni konular

Geri
Yukarı