Bevezetés a Hystrixbe

1. Áttekintés

Egy tipikus elosztott rendszer sok szolgáltatás együttes együttműködéséből áll.

Ezek a szolgáltatások hajlamosak a meghibásodásokra vagy a késleltetett válaszokra. Ha egy szolgáltatás meghiúsul, az hatással lehet más szolgáltatásokra, amelyek befolyásolják a teljesítményt, és esetleg elérhetetlenné tehetik az alkalmazás más részeit, vagy a legrosszabb esetben lebontják az egész alkalmazást.

Természetesen vannak olyan megoldások, amelyek elősegítik az alkalmazások rugalmasságát és hibatűrését - az egyik ilyen keret a Hystrix.

A Hystrix keretrendszer segíti a szolgáltatások közötti kölcsönhatás ellenőrzését azáltal, hogy hibatűrést és késleltetési toleranciát biztosít. Javítja a rendszer általános ellenálló képességét azáltal, hogy elszigeteli a meghibásodott szolgáltatásokat és megállítja a hibák lépcsőzetes hatását.

Ebben a bejegyzéssorozatban azzal kezdjük, hogy megvizsgáljuk, hogyan jut Hystrix segítségre, ha egy szolgáltatás vagy rendszer meghibásodik, és mit tud elérni a Hystrix ilyen körülmények között.

2. Egyszerű példa

A Hystrix hiba- és késleltetési toleranciáját a távoli szolgáltatások hívásainak elkülönítése és lezárása jelenti.

Ebben az egyszerű példában egy hívást csomagolunk a fuss() módszere HystrixCommand:

class CommandHelloWorld kiterjeszti a HystrixCommand {private String name; CommandHelloWorld (karakterlánc neve) {super (HystrixCommandGroupKey.Factory.asKey ("ExampleGroup")); ez.név = név; } @Orride protected String run () {return "Hello" + név + "!"; }}

és a hívást a következőképpen hajtjuk végre:

@Test public void givenInputBobAndDefaultSettings_whenCommandExecuted_thenReturnHelloBob () {assertThat (new CommandHelloWorld ("Bob"). Execute (), equTo ("Hello Bob!")); }

3. Maven Setup

Ahhoz, hogy a Hystrix-et egy Maven projektben felhasználhassuk, meg kell hisztrix-mag és rxjava-mag függ a Netflix-től a projektben pom.xml:

 com.netflix.hystrix hystrix-core 1.5.4 

A legfrissebb verzió mindig itt található.

 com.netflix.rxjava rxjava-core 0.20.7 

A könyvtár legújabb verziója mindig itt található.

4. Távoli szolgáltatás beállítása

Kezdjük egy valós példa szimulálásával.

Az alábbi példában, osztály RemoteServiceTestSimulator egy távoli szerveren található szolgáltatást jelent. Van egy módszere, amely a megadott idő elteltével üzenettel válaszol. Elképzelhetjük, hogy ez a várakozás a távoli rendszer időigényes folyamatának szimulációja, amely késleltetett választ eredményez a hívó szolgáltatásra:

class RemoteServiceTestSimulator {privát hosszú várakozás; A RemoteServiceTestSimulator (hosszú várakozás) dobja az InterruptedException {this.wait = wait; } String execute () dobja az InterruptedException {Thread.sleep (wait); return "siker"; }}

És itt van a minta kliensünk hogy hívja a RemoteServiceTestSimulator.

A szolgáltatáshoz intézett hívás elkülönül, és be van csomagolva a fuss() módszer a HystrixCommand. Ez a csomagolás biztosítja a rugalmasságot, amelyet fentebb érintettünk:

class RemoteServiceTestCommand kiterjeszti a HystrixCommand {private RemoteServiceTestSimulator remoteService; RemoteServiceTestCommand (Setter config, RemoteServiceTestSimulator remoteService) {super (config); this.remoteService = remoteService; } @Orride protected String run () dobja a Kivételt {return remoteService.execute (); }}

A hívást a. Hívásával hajtják végre végrehajtani () metódus a RemoteServiceTestCommand tárgy.

A következő teszt bemutatja, hogyan történik ez:

A @Test public void givenSvcTimeoutOf100AndDefaultSettings_whenRemoteSvcExecuted_thenReturnSuccess () dobja a InterruptedException {HystrixCommand.Setter config = HystrixCommand .Setter .withGroupKey "HystrixCeyGroupKerviceService2 assertThat (új RemoteServiceTestCommand (config, új RemoteServiceTestSimulator (100)). execute (), equalTo ("Siker")); }

Eddig láttuk, hogyan lehet csomagolni a távoli szolgáltatási hívásokat a HystrixCommand tárgy. Az alábbi szakaszban nézzük meg, hogyan kell kezelni egy olyan helyzetet, amikor a távoli szolgáltatás romlani kezd.

5. Munka a távoli szolgáltatással és a védekező programozással

5.1. Védekező programozás időtúllépéssel

Általános programozási gyakorlat az időkorlátok beállítása a távoli szolgáltatásokra irányuló hívásokhoz.

Kezdjük azzal, hogy megvizsgáljuk, hogyan állíthatjuk be az időkorlátot HystrixCommand és hogyan segít rövidzárlattal:

@Test public void givenSvcTimeoutOf5000AndExecTimeoutOf10000_whenRemoteSvcExecuted_thenReturnSuccess () dobja az InterruptedException {HystrixCommand.Setter config = HystrixCommand .Setter .withGroupKeyGame (HystrixCommGey) HystrixCommandProperties.Setter commandProperties = HystrixCommandProperties.Setter (); commandProperties.withExecutionTimeoutInMilliseconds (10_000); config.andCommandPropertiesDefaults (commandProperties); assertThat (új RemoteServiceTestCommand (config, új RemoteServiceTestSimulator (500)). execute (), equalTo ("Siker")); }

A fenti tesztben késleltetjük a szolgáltatás válaszát azzal, hogy 500 ms-ra állítjuk az időtúllépést. Beállítjuk a végrehajtás időkorlátját is HystrixCommand 10 000 ms legyen, így elegendő időt hagyva a távoli szolgáltatás reagálására.

Most nézzük meg, mi történik, ha a végrehajtás időkorlátja kevesebb, mint a szolgáltatás időkorlátja:

@Test (várható = HystrixRuntimeException.class) public void givenSvcTimeoutOf15000AndExecTimeoutOf5000_whenRemoteSvcExecuted_thenExpectHre () dobja az InterruptedException {HystrixCommand.Setter config = HystrixComm. HystrixCommag. HystrixCommandProperties.Setter commandProperties = HystrixCommandProperties.Setter (); commandProperties.withExecutionTimeoutInMilliseconds (5_000); config.andCommandPropertiesDefaults (commandProperties); új RemoteServiceTestCommand (config, új RemoteServiceTestSimulator (15_000)). execute (); }

Figyelje meg, hogyan csökkentettük a sávot, és 5000 ms-ra állítottuk a végrehajtás időkorlátját.

Arra számítunk, hogy a szolgáltatás 5000 ms-on belül válaszol, míg a szolgáltatást 15 000 ms után válaszoltuk. Ha észreveszi, amikor végrehajtja a tesztet, akkor a teszt 5000 ms után kilép, ahelyett, hogy 15 000 ms-ot várna, és egy HystrixRuntimeException.

Ez azt mutatja, hogy a Hystrix nem vár tovább a válaszra a beállított időtúllépésnél. Ez segít a Hystrix által védett rendszer gyorsabb reagálásában.

Az alábbi szakaszokban megvizsgáljuk a szálkészlet méretének beállítását, amely megakadályozza a szálak kimerülését, és megvitatjuk annak előnyeit.

5.2. Védekező programozás korlátozott szálkészlettel

A szervizhívás időkorlátjának beállítása nem oldja meg a távoli szolgáltatásokkal kapcsolatos összes kérdést.

Amikor egy távoli szolgáltatás lassan reagálni kezd, egy tipikus alkalmazás továbbra is felhívja az adott távoli szolgáltatást.

Az alkalmazás nem tudja, hogy a távoli szolgáltatás egészséges-e vagy sem, és minden egyes kérelem érkezésekor új szálak jönnek létre. Ez egy már küzdő szerveren lévő szálak használatát fogja eredményezni.

Nem akarjuk, hogy ez megtörténjen, mivel ezekre a szálakra szükségünk van a szerverünkön futó többi távoli híváshoz vagy folyamathoz, és azt is szeretnénk elkerülni, hogy a CPU kihasználtsága megugrjon.

Nézzük meg, hogyan lehet beállítani a szálkészlet méretét HystrixCommand:

@Test public void givenSvcTimeoutOf500AndExecTimeoutOf10000AndThreadPool_whenRemoteSvcExecuted _thenReturnSuccess () dobja megszakítottException {HystrixCommand.Setter config = HystrixCommand.Setter config = HystrixCommand .Setter konfigurációs HystrixCommand. HystrixCommandProperties.Setter commandProperties = HystrixCommandProperties.Setter (); commandProperties.withExecutionTimeoutInMilliseconds (10_000); config.andCommandPropertiesDefaults (commandProperties); config.andThreadPoolPropertiesDefaults (HystrixThreadPoolProperties.Setter () .withMaxQueueSize (10) .withCoreSize (3) .withQueueSizeRejectionThreshold (10)); assertThat (új RemoteServiceTestCommand (config, új RemoteServiceTestSimulator (500)). execute (), equalTo ("Siker")); }

A fenti tesztben beállítjuk a maximális sorméretet, az alapsor méretét és a sor elutasítási méretét. Hystrix akkor kezdi elutasítani a kéréseket, amikor a maximális szálak száma eléri a 10-et, és a feladatsor eléri a 10-es méretet.

A magméret az a szálak száma, amelyek mindig életben maradnak a szálkészletben.

5.3. Védekező programozás rövidzárlat-megszakító mintával

Azonban még mindig van egy javulás, amelyet a távoli szervizhívásokkal kapcsolatban megtehetünk.

Vegyük figyelembe azt az esetet, amikor a távoli szolgáltatás meghibásodni kezdett.

Nem akarjuk folyamatosan elkérni a kérelmeket és pazarolni az erőforrásokat. Ideális esetben azt szeretnénk, ha egy bizonyos időre leállítanánk a kérelmek benyújtását, annak érdekében, hogy a szolgáltatás ideje legyen a helyreállításra, mielőtt a kéréseket folytatnánk. Ezt hívják Rövidzárlat-megszakító minta.

Lássuk, hogyan hajtja végre Hystrix ezt a mintát:

A @Test public void givenCircuitBreakerSetup_whenRemoteSvcCmdExecuted_thenReturnSuccess () dobja az InterruptedException {HystrixCommand.Setter config = HystrixCommand .Setter .withGroupKey (HystrixCommandGroupServiceGroupService.Factory) HystrixCommandProperties.Setter tulajdonságok = HystrixCommandProperties.Setter (); tulajdonságok.WithExecutionTimeoutInMilliseconds (1000); properties.withCircuitBreakerSleepWindowInMilliseconds (4000); tulajdonságok.WithExecutionIsolationStrategy (HystrixCommandProperties.ExecutionIsolationStrategy.THREAD); properties.withCircuitBreakerEnabled (true); properties.withCircuitBreakerRequestVolumeThreshold (1); config.andCommandPropertiesDefaults (tulajdonságok); config.andThreadPoolPropertiesDefaults (HystrixThreadPoolProperties.Setter () .withMaxQueueSize (1) .withCoreSize (1) .withQueueSizeRejectionThreshold (1)); assertThat (this.invokeRemoteService (config, 10_000), equalTo (null)); assertThat (this.invokeRemoteService (config, 10_000), equalTo (null)); assertThat (this.invokeRemoteService (config, 10_000), equalTo (null)); Szál.alszik (5000); assertThat (új RemoteServiceTestCommand (config, új RemoteServiceTestSimulator (500)). execute (), equalTo ("Siker")); assertThat (új RemoteServiceTestCommand (config, új RemoteServiceTestSimulator (500)). execute (), equalTo ("Siker")); assertThat (új RemoteServiceTestCommand (config, új RemoteServiceTestSimulator (500)). execute (), equalTo ("Siker")); }
public String invokeRemoteService (HystrixCommand.Setter config, int timeout) dobja az InterruptedException {String response = null; próbáld ki a (z) {response = new RemoteServiceTestCommand (config, new RemoteServiceTestSimulator (timeout)) parancsot. execute (); } catch (HystrixRuntimeException ex) {System.out.println ("ex =" + ex); } visszatérési válasz; }

A fenti tesztben különböző megszakító tulajdonságokat állítottunk be. A legfontosabbak:

  • A CircuitBreakerSleepWindow amely 4000 ms-ra van állítva. Ez konfigurálja a megszakító ablakát, és meghatározza azt az időintervallumot, amely után a távoli szolgáltatás iránti kérés folytatódik
  • A CircuitBreakerRequestVolumeThreshold amely 1-re van állítva, és meghatározza a meghibásodási arány mérlegeléséhez szükséges minimális kérelmek számát

A fenti beállítások meglétével a HystrixCommand két sikertelen kérés után most kiold. A harmadik kérés még a távoli szolgáltatást sem éri el, pedig a szolgáltatás késleltetését 500 ms-ra állítottuk, Hystrix rövidzárlatot okoz, és a módszerünk visszatér nulla válaszként.

Ezt követően hozzáadjuk a Thread.sleep (5000) annak érdekében, hogy átlépjük az alvási ablak általunk beállított határt. Ez okozni fog Hystrix az áramkör bezárásához, és az azt követő kérések sikeresen át fognak áramlani.

6. Következtetés

Összefoglalva, a Hystrix célja:

  1. Biztosítson védelmet és ellenőrzést a hibák és késleltetés felett a hálózaton keresztül általában elérhető szolgáltatásoktól
  2. Állítsa le a szolgáltatások egy részének leállása miatt bekövetkező hibák lépcsőzését
  3. Gyorsan és gyorsan felépülni
  4. Degradálódjon kecsesen, ahol lehetséges
  5. Valós idejű figyelés és riasztás a parancsnoki központnál a hibákról

A következő bejegyzésben megtudhatjuk, hogyan lehet kombinálni a Hystrix előnyeit a tavaszi kerettel.

A teljes projektkód és az összes példa megtalálható a github projektben.