Bevezetés a Dubbo-ba

1. Bemutatkozás

A Dubbo egy nyílt forráskódú RPC és mikroszolgáltatási keretrendszer az Alibaba cégtől.

Többek között elősegíti a szolgáltatások irányításának javítását, és lehetővé teszi a hagyományos monolit alkalmazások zökkenőmentes átalakítását skálázható elosztott architektúrává.

Ebben a cikkben bemutatjuk a Dubbo-t és annak legfontosabb jellemzőit.

2. Építészet

Dubbo megkülönböztet néhány szerepet:

  1. Szolgáltató - ahol a szolgáltatás ki van téve; a szolgáltató nyilvántartásba veszi szolgáltatását
  2. Konténer - ahol a szolgáltatás elindul, betöltődik és fut
  3. Fogyasztó - aki távoli szolgáltatásokat hív fel; a fogyasztó feliratkozik a nyilvántartásban szükséges szolgáltatásra
  4. Nyilvántartás - ahol a szolgáltatást regisztrálják és felfedezik
  5. Monitor - rögzíti a szolgáltatások statisztikáit, például a szolgáltatás meghívásának gyakoriságát egy adott időintervallumban

(forrás: //dubbo.io/images/dubbo-architecture.png)

A szolgáltató, a fogyasztó és a nyilvántartás közötti kapcsolatok tartósak, így amikor a szolgáltató nem működik, a rendszerleíró adatbázis észlelheti a hibát és értesítheti a fogyasztókat.

A nyilvántartás és a monitor nem kötelező. A fogyasztók közvetlenül csatlakozhatnak a szolgáltatókhoz, de ez az egész rendszer stabilitását befolyásolja.

3. Maven-függőség

Mielőtt belevetnénk magunkat, adjuk hozzá a következő függőséget pom.xml:

 com.alibaba dubbo 2.5.7 

A legújabb verzió itt található.

4. Bootstrapping

Most próbáljuk ki a Dubbo alapvető jellemzőit.

Ez egy minimálisan invazív keretrendszer, és számos funkciója a külső konfigurációktól vagy annotációktól függ.

Hivatalosan javasoljuk, hogy XML konfigurációs fájlt használjunk, mert ez egy Spring tárolótól függ (jelenleg a 4.3.10. Tavasz).

A legtöbb funkcióját XML konfigurációval mutatjuk be.

4.1. Multicast Registry - Szolgáltató

Gyors kezdésként csak szolgáltatóra, fogyasztóra és „láthatatlan” nyilvántartásra lesz szükségünk. A nyilvántartás láthatatlan, mert csoportos küldésű hálózatot használunk.

Az alábbi példában a szolgáltató csak „szia” -t mondja el fogyasztóinak:

nyilvános felület GreetingsService {String sayHi (String name); } public class GreetingsServiceImpl implementálja a GreetingsService {@Orride public String sayHi (String name) {return "hi," + name; }}

Távoli eljáráshívás kezdeményezéséhez a fogyasztónak közös interfészt kell megosztania a szolgáltatóval, ezáltal az interfészt GreetingsService meg kell osztani a fogyasztóval.

4.2. Multicast Registry - Szolgáltatás regisztráció

Most regisztráljunk GreetingsService a nyilvántartásba. Nagyon kényelmes módszer a multicast nyilvántartás használata, ha a szolgáltatók és a fogyasztók is ugyanazon a helyi hálózaton vannak:

A fenti babkonfigurációval most kitettük a magunkat GreetingsService alatti URL-re dubbo: //127.0.0.1: 20880 és regisztrálta a szolgáltatást a .

A szolgáltató konfigurációjában deklaráltuk az alkalmazás metaadatait, a közzéteendő felületet és annak megvalósítását is , és .

A dubbo A protokoll a keretrendszer által támogatott számos protokoll egyike. A Java NIO nem blokkoló szolgáltatásának tetejére épül, és ez az alapértelmezett protokoll.

A cikk későbbi részében részletesebben megvitatjuk.

4.3. Multicast Registry - Szolgáltatásfogyasztó

Általában a fogyasztónak meg kell határoznia a meghívandó interfészt és a távoli szolgáltatás címét, és pontosan erre van szükség a fogyasztó számára:

Most minden készen áll, nézzük meg, hogyan működnek működés közben:

public class MulticastRegistryTest {@Before public void initRemote () {ClassPathXmlApplicationContext remoteContext = new ClassPathXmlApplicationContext ("multicast / szolgáltató-app.xml"); remoteContext.start (); } @Test public void givenProvider_whenConsumerSaysHi_thenGotResponse () {ClassPathXmlApplicationContext localContext = new ClassPathXmlApplicationContext ("multicast / consumer-app.xml"); localContext.start (); GreetingsService greetingsService = (GreetingsService) localContext.getBean ("greetingsService"); Karakterlánc hiMessage = greetingsService.sayHi ("baeldung"); assertNotNull (hiMessage); assertEquals ("szia, baeldung", hiMessage); }}

Amikor a szolgáltatóé remoteContext elindul, a Dubbo automatikusan betöltődik GreetingsService és regisztrálja az adott nyilvántartásba. Ebben az esetben egy multicast nyilvántartásról van szó.

A fogyasztó feliratkozik a multicast nyilvántartásra, és létrehoz egy proxyt GreetingsService a kontextusban. Amikor helyi ügyfelünk meghívja a Mondd Szia módszerrel, átláthatóan hívja meg a távoli szolgáltatást.

Megemlítettük, hogy a nyilvántartás nem kötelező, vagyis a fogyasztó közvetlenül kapcsolódhat a szolgáltatóhoz a szabad porton keresztül:

Alapvetően az eljárás hasonló a hagyományos webszolgáltatáshoz, de a Dubbo csak egyszerűvé, egyszerűvé és könnyűvé teszi azt.

4.4. Egyszerű nyilvántartás

Vegye figyelembe, hogy „láthatatlan” csoportos küldésű nyilvántartás használata esetén a rendszerleíró adatbázis-szolgáltatás nem önálló. Ez azonban csak korlátozott helyi hálózatra vonatkozik.

A kezelhető nyilvántartás kifejezett felállításához használhatjuk a SimpleRegistryService.

A következő babkonfiguráció tavaszi környezetbe való betöltése után elindul egy egyszerű rendszerleíró adatbázis-szolgáltatás:

Vegye figyelembe, hogy a SimpleRegistryService osztály nem szerepel a tárgyban, ezért a forráskódot közvetlenül a Github adattárból másoltuk.

Ezután a szolgáltató és a fogyasztó beállításjegyzékét konfiguráljuk:

SimpleRegistryService teszteléskor önálló nyilvántartásként használható, de nem ajánlott a termelési környezetben.

4.5. Java konfiguráció

A konfiguráció Java API-n keresztül, a tulajdonságfájl és a kommentárok is támogatottak. A tulajdonságfájlok és a kommentárok azonban csak akkor alkalmazhatók, ha architektúránk nem túl összetett.

Nézzük meg, hogyan lehet a multicast nyilvántartás korábbi XML-konfigurációit lefordítani API-konfigurációvá. Először a szolgáltatót a következőképpen állítják be:

ApplicationConfig alkalmazás = new ApplicationConfig (); application.setName ("demo-szolgáltató"); application.setVersion ("1.0"); RegistryConfig registryConfig = új RegistryConfig (); registerConfig.setAddress ("multicast: //224.1.1.1: 9090"); ServiceConfig service = new ServiceConfig (); service.setApplication (alkalmazás); service.setRegistry (registryConfig); service.setInterface (GreetingsService.class); service.setRef (new GreetingsServiceImpl ()); szolgáltatás.export ();

Most, hogy a szolgáltatás már ki van szolgáltatva a multicast nyilvántartáson keresztül, fogyasszuk el egy helyi kliensben:

ApplicationConfig alkalmazás = new ApplicationConfig (); application.setName ("demo-consumer"); application.setVersion ("1.0"); RegistryConfig registryConfig = új RegistryConfig (); registerConfig.setAddress ("multicast: //224.1.1.1: 9090"); ReferenceConfig referencia = new ReferenceConfig (); reference.setApplication (alkalmazás); reference.setRegistry (registryConfig); reference.setInterface (GreetingsService.class); GreetingsService greetingsService = referencia.get (); Karakterlánc hiMessage = greetingsService.sayHi ("baeldung");

Bár a fenti kódrészlet varázslatként működik, mint az előző XML-konfigurációs példa, egy kicsit triviálisabb. Egyelőre az XML konfigurációnak kell az első választásnak lennie, ha teljes mértékben ki akarjuk használni a Dubbo alkalmazását.

5. Protokoll támogatás

A keretrendszer több protokollt támogat, beleértve a dubbo, RMI, zsákvászon, HTTP, webes szolgáltatás, takarékosság, memcached és redis. A legtöbb protokoll ismerősnek tűnik, kivéve dubbo. Lássuk, mi új a protokollban.

A dubbo protokoll állandó kapcsolatot tart fenn a szolgáltatók és a fogyasztók között. A hosszú kapcsolat és a nem blokkoló NIO hálózati kommunikáció meglehetősen nagy teljesítményt eredményez, miközben kis méretű adatcsomagokat (<100K) továbbít.

Számos konfigurálható tulajdonság létezik, például port, fogyasztónkénti kapcsolatok száma, maximálisan elfogadott kapcsolatok stb.

A Dubbo emellett támogatja a szolgáltatások egyszerre történő bemutatását különböző protokollokon keresztül:

És igen, a különböző szolgáltatásokat különböző protokollok segítségével tehetjük ki, amint az a fenti részletben látható. Az alapul szolgáló transzporterek, a sorosítási megvalósítások és a hálózathoz kapcsolódó egyéb közös tulajdonságok szintén konfigurálhatók.

6. Eredmény gyorsítótárazás

A távoli eredmények gyorsítótárazása támogatott a forró adatokhoz való hozzáférés felgyorsítása érdekében. Ez olyan egyszerű, mint egy gyorsítótár-attribútum hozzáadása a bab hivatkozáshoz:

Itt konfiguráltunk egy legkevésbé nemrég használt gyorsítótárat. A gyorsítótár-viselkedés ellenőrzéséhez módosítunk egy kicsit az előző szabványos megvalósításban (nevezzük „speciális megvalósításnak”):

public class GreetingsServiceSpecialImpl implementálja a GreetingsService {@Orride public String sayHi (String name) {try {SECONDS.sleep (5); } catch (kivétel figyelmen kívül hagyva) {} return "szia" + név; }}

A szolgáltató beindítása után a fogyasztó oldalán ellenőrizhetjük, hogy az eredmény gyorsítótárazott, ha többször is meghívjuk:

@Test public void givenProvider_whenConsumerSaysHi_thenGotResponse () {ClassPathXmlApplicationContext localContext = new ClassPathXmlApplicationContext ("multicast / consumer-app.xml"); localContext.start (); GreetingsService greetingsService = (GreetingsService) localContext.getBean ("greetingsService"); jóval azelőtt = System.currentTimeMillis (); Karakterlánc hiMessage = greetingsService.sayHi ("baeldung"); long timeElapsed = System.currentTimeMillis () - előtt; assertTrue (timeElapsed> 5000); assertNotNull (hiMessage); assertEquals ("szia, baeldung", hiMessage); előtt = System.currentTimeMillis (); hiMessage = üdvözletService.sayHi ("baeldung"); timeElapsed = System.currentTimeMillis () - előtt; assertTrue (timeElapsed <1000); assertNotNull (hiMessage); assertEquals ("szia, baeldung", hiMessage); }

Itt a fogyasztó a speciális szolgáltatás megvalósítására hivatkozik, így több mint 5 másodpercbe telt, mire a hívás első alkalommal befejeződött. Amikor újra felhívjuk, a Mondd Szia metódus szinte azonnal befejeződik, mivel az eredmény visszatér a gyorsítótárból.

Vegye figyelembe, hogy a thread-local cache és a JCache is támogatott.

7. Klaszter támogatás

A Dubbo teherkiegyenlítő képességével és számos hibatűrési stratégiával segít nekünk szabadon bővíteni szolgáltatásainkat. Tegyük fel, hogy itt a Zookeeper van a rendszerleíró adatbázisunkban a fürt szolgáltatásainak kezelésére. A szolgáltatók a Zookeeper szolgáltatásban így regisztrálhatják szolgáltatásaikat:

Ne feledje, hogy ezekre a további függőségekre szükségünk van a POM:

 org.apache.zookeeper zookeeper 3.4.11 com.101tec zkclient 0.10 

A legújabb verziói állatgondozó függőség és zkclient itt és itt található.

7.1. Terhelés elosztás

Jelenleg a keret néhány terheléselosztási stratégiát támogat:

  • véletlen
  • körbefutó
  • legkevésbé aktív
  • következetes-hash.

Az alábbi példában két szolgáltatási megvalósítás van szolgáltatóként egy fürtben. A kéréseket a körméretes megközelítéssel továbbítják.

Először állítsunk fel szolgáltatókat:

@A nyilvános void előtt initRemote () {ExecutorService executorService = Executors.newFixedThreadPool (2); executorService.submit (() -> {ClassPathXmlApplicationContext remoteContext = új ClassPathXmlApplicationContext ("fürt / szolgáltató-alkalmazás-alapértelmezett.xml"); távoliKontext.start ();}); végrehajtóService.submit (() -> {ClassPathXmlApplicationContext backupRemoteContext = új ClassPathXmlApplicationContext ("fürt / szolgáltató-alkalmazás-speciális.xml"); backupRemoteContext.start ();}); }

Most van egy standard „gyors szolgáltatónk”, amely azonnal reagál, és egy speciális „lassú szolgáltatóval”, aki 5 másodpercig alszik minden kérésre.

Miután 6-szor futott a körmérkőzéses stratégiával, azt várjuk, hogy az átlagos válaszidő legalább 2,5 másodperc lesz:

@Test public void givenProviderCluster_whenConsumerSaysHi_thenResponseBalanced () {ClassPathXmlApplicationContext localContext = new ClassPathXmlApplicationContext ("cluster / consumer-app-lb.xml"); localContext.start (); GreetingsService greetingsService = (GreetingsService) localContext.getBean ("greetingsService"); List elapseList = new ArrayList (6); mert (int i = 0; i e) .átlag (); assertTrue (avgElapse.isPresent ()); assertTrue (avgElapse.getAsDouble ()> 2500,0); }

Ezenkívül dinamikus terheléselosztást alkalmaznak. A következő példa azt mutatja, hogy a körmérkőzéses stratégia alkalmazásával a fogyasztó automatikusan az új szolgáltatót választja jelöltnek, amikor az új szolgáltató online lesz.

A „lassú szolgáltatót” a rendszer indítása után 2 másodperccel később regisztrálják:

@ Nyilvános void előtt initRemote () {ExecutorService executorService = Executors.newFixedThreadPool (2); executorService.submit (() -> {ClassPathXmlApplicationContext remoteContext = új ClassPathXmlApplicationContext ("fürt / szolgáltató-alkalmazás-alapértelmezett.xml"); távoliKontext.start ();}); executorService.submit (() -> {SECONDS.sleep (2); ClassPathXmlApplicationContext backupRemoteContext = new ClassPathXmlApplicationContext ("cluster / szolgáltató-app-special.xml"); backupRemoteContext.start (); return null;}); }

A fogyasztó másodpercenként egyszer hívja meg a távoli szolgáltatást. Hatszoros futás után az átlagos válaszidő 1,6 másodpercnél hosszabbra számítunk:

@Test public void givenProviderCluster_whenConsumerSaysHi_thenResponseBalanced () dobja az InterruptedException {ClassPathXmlApplicationContext localContext = new ClassPathXmlApplicationContext ("cluster / consumer-app-lb.xml"); localContext.start (); GreetingsService greetingsService = (GreetingsService) localContext.getBean ("greetingsService"); List elapseList = new ArrayList (6); mert (int i = 0; i e) .átlag (); assertTrue (avgElapse.isPresent ()); assertTrue (avgElapse.getAsDouble ()> 1666.0); }

Vegye figyelembe, hogy a terheléselosztó mind a fogyasztó, mind a szolgáltató oldalán konfigurálható. Íme egy példa a fogyasztói oldal konfigurálására:

7.2. Hibatűrés

A Dubbo számos hibatűrési stratégiát támogat, többek között:

  • kudarc
  • üzembiztos
  • kudarc
  • kudarc
  • elágazás.

Meghibásodás esetén, ha egy szolgáltató megbukik, a fogyasztó megpróbálkozhat a fürt néhány más szolgáltatójával.

A hibatűrési stratégiák a következőképpen vannak konfigurálva a szolgáltatók számára:

A szolgáltatás sikertelen működésének bemutatásához hozzunk létre egy átviteli megvalósítást GreetingsService:

public class GreetingsFailoverServiceImpl megvalósítja a GreetingsService {@Orride public String sayHi (String name) {return "szia, feladatátvétel" + név; }}

Felidézhetjük, hogy speciális szolgáltatásunk megvalósítása GreetingsServiceSpecialImpl 5 másodpercet alszik minden kérésre.

Ha bármely, 2 másodpercnél tovább tartó válasz a kérelem sikertelenségének tekinthető a fogyasztó számára, fennáll az áthibásodási forgatókönyv:

Két szolgáltató elindítása után a következő kódrészlettel ellenőrizhetjük a hibakezelési viselkedést:

@Test public void whenConsumerSaysHi_thenGotFailoverResponse () {ClassPathXmlApplicationContext localContext = new ClassPathXmlApplicationContext ("cluster / consumer-app-failtest.xml"); localContext.start (); GreetingsService greetingsService = (GreetingsService) localContext.getBean ("greetingsService"); Karakterlánc hiMessage = greetingsService.sayHi ("baeldung"); assertNotNull (hiMessage); assertEquals ("szia, failover baeldung", hiMessage); }

8. Összefoglalás

Ebben az oktatóanyagban vettünk egy kis falatot Dubbo-ból. A legtöbb felhasználót vonzza az egyszerűsége, valamint a gazdag és hatékony funkciók.

Az ebben a cikkben bemutatottaktól eltekintve a keretrendszer számos olyan funkcióval rendelkezik, amelyeket még meg kell vizsgálni, mint például a paraméterek ellenőrzése, értesítés és visszahívás, általános megvalósítás és referencia, távoli eredménycsoportosítás és egyesítés, szolgáltatásfrissítés és visszamenőleges kompatibilitás. néhány.

Mint mindig, a teljes megvalósítás megtalálható a Githubon.