Pengantar Spring Cloud Netflix - Eureka

1. Ikhtisar

Dalam tutorial ini, kami akan memperkenalkan penemuan layanan sisi klien melalui " Spring Cloud Netflix Eureka ".

Penemuan layanan sisi klien memungkinkan layanan untuk menemukan dan berkomunikasi satu sama lain tanpa nama host dan port pengkodean keras. Satu-satunya 'titik tetap' dalam arsitektur semacam itu terdiri dari registri layanan yang harus didaftarkan oleh setiap layanan.

Kekurangannya adalah semua klien harus menerapkan logika tertentu untuk berinteraksi dengan titik tetap ini. Ini mengasumsikan perjalanan jaringan tambahan sebelum permintaan sebenarnya.

Dengan Netflix Eureka, setiap klien dapat bertindak sebagai server secara bersamaan, untuk mereplikasi statusnya ke peer yang terhubung. Dengan kata lain, klien mengambil daftar semua peer yang terhubung dari registry layanan dan membuat semua permintaan lebih lanjut ke layanan lain melalui algoritme load-balancing.

Untuk mendapatkan informasi tentang keberadaan klien, mereka harus mengirim sinyal detak jantung ke registri.

Untuk mencapai tujuan artikel ini, kami akan menerapkan tiga layanan mikro :

  • sebuah registri layanan ( Eureka Server ),
  • layanan REST yang mendaftarkan dirinya di registri ( Klien Eureka ) dan
  • aplikasi web, yang menggunakan layanan REST sebagai klien yang peka terhadap registri ( Spring Cloud Netflix Feign Client ).

2. Server Eureka

Menerapkan Server Eureka untuk pendaftaran layanan semudah:

  1. menambahkan spring-cloud-starter-netflix-eureka-server ke dependensi
  2. aktifkan Server Eureka di @SpringBootApplication dengan menganotasinya dengan @EnableEurekaServer
  3. konfigurasikan beberapa properti

Tapi kami akan melakukannya selangkah demi selangkah.

Pertama kita akan membuat proyek Maven baru dan memasukkan dependensi ke dalamnya. Anda harus memperhatikan bahwa kami mengimpor spring-cloud-starter-parent ke semua proyek yang dijelaskan dalam tutorial ini:

 org.springframework.cloud spring-cloud-starter-netflix-eureka-server     org.springframework.cloud spring-cloud-starter-parent Greenwich.RELEASE pom import   

Catatan: kami dapat memeriksa rilis Spring Cloud terbaru di dokumentasi Spring's Projects.

Selanjutnya, kami membuat kelas aplikasi utama:

@SpringBootApplication @EnableEurekaServer public class EurekaServerApplication { public static void main(String[] args) { SpringApplication.run(EurekaServerApplication.class, args); } }

Terakhir, kami mengonfigurasi properti dalam format YAML ; jadi application.yml akan menjadi file konfigurasi kita:

server: port: 8761 eureka: client: registerWithEureka: false fetchRegistry: false

Di sini kami mengonfigurasi port aplikasi - 8761 adalah port default untuk server Eureka . Kami memberi tahu Klien Eureka bawaan untuk tidak mendaftar dengan 'dirinya sendiri' karena aplikasi kami harus bertindak sebagai server.

Sekarang kita akan mengarahkan browser kita ke // localhost: 8761 untuk melihat dasbor Eureka , tempat kita nanti akan memeriksa contoh terdaftar.

Saat ini, kami melihat indikator dasar seperti status dan indikator kesehatan.

3. Klien Eureka

Agar @SpringBootApplication sadar akan penemuan, kami telah menyertakan beberapa Klien Penemuan Musim Semi (misalnya spring-cloud-starter-netflix-eureka-client ) ke dalam classpath kami .

Kemudian kita perlu memberi anotasi pada @Configuration dengan @EnableDiscoveryClient atau @EnableEurekaClient - perhatikan bahwa anotasi ini opsional jika kita memiliki dependensi spring-cloud-starter-netflix-eureka-client di classpath.

Yang terakhir memberi tahu Spring Boot untuk menggunakan Spring Netflix Eureka untuk penemuan layanan secara eksplisit. Untuk mengisi aplikasi klien kita dengan beberapa sample-life, kita juga akan menyertakan paket spring-boot-starter-web di pom.xml dan mengimplementasikan controller REST .

Tapi pertama-tama, kami akan menambahkan dependensi. Sekali lagi, kita dapat menyerahkannya pada dependensi spring-cloud-starter-parent untuk mencari tahu versi artefaknya untuk kita:

 org.springframework.cloud spring-cloud-starter-netflix-eureka-starter   org.springframework.boot spring-boot-starter-web 

Di sini kita akan mengimplementasikan kelas aplikasi utama:

@SpringBootApplication @RestController public class EurekaClientApplication implements GreetingController { @Autowired @Lazy private EurekaClient eurekaClient; @Value("${spring.application.name}") private String appName; public static void main(String[] args) { SpringApplication.run(EurekaClientApplication.class, args); } @Override public String greeting() { return String.format( "Hello from '%s'!", eurekaClient.getApplication(appName).getName()); } }

Dan antarmuka GreetingController :

public interface GreetingController { @RequestMapping("/greeting") String greeting(); }

Di sini, sebagai ganti antarmuka, kami juga dapat dengan mudah mendeklarasikan pemetaan di dalam kelas EurekaClientApplication . Antarmuka dapat berguna jika kita ingin membagikannya antara server dan klien.

Selanjutnya, kita harus menyiapkan application.yml dengan nama aplikasi Spring yang dikonfigurasi untuk mengidentifikasi klien kita secara unik dalam daftar aplikasi terdaftar.

Kita dapat membiarkan Spring Boot memilih port acak untuk kita karena nanti kita mengakses layanan ini dengan namanya.

Terakhir, kami harus memberi tahu klien kami, di mana ia harus menemukan registri:

spring: application: name: spring-cloud-eureka-client server: port: 0 eureka: client: serviceUrl: defaultZone: ${EUREKA_URI://localhost:8761/eureka} instance: preferIpAddress: true

Ketika kami memutuskan untuk menyiapkan Klien Eureka kami dengan cara ini, kami berpikir bahwa layanan semacam ini nantinya akan mudah diskalakan.

Sekarang kita akan menjalankan klien dan mengarahkan browser kita ke // localhost: 8761 lagi, untuk melihat status pendaftarannya di Dasbor Eureka. Dengan menggunakan Dashboard, kita dapat melakukan konfigurasi lebih lanjut, misalnya menghubungkan homepage klien yang terdaftar dengan Dashboard untuk keperluan administratif. Opsi konfigurasi, bagaimanapun, berada di luar cakupan artikel ini.

4. Berpura-pura Klien

Untuk menyelesaikan proyek kami dengan tiga layanan mikro yang bergantung, kami sekarang akan menerapkan aplikasi web yang menggunakan REST menggunakan Spring Netflix Feign Client .

Think of Feign as discovery-aware SpringRestTemplate using interfaces to communicate with endpoints. This interfaces will be automatically implemented at runtime and instead of service-urls, it is using service-names.

Without Feign we would have to autowire an instance of EurekaClient into our controller with which we could receive a service-information by service-name as an Application object.

We would use this Application to get a list of all instances of this service, pick a suitable one and use this InstanceInfo to get hostname and port. With this, we could do a standard request with any http client.

For example:

@Autowired private EurekaClient eurekaClient; public void doRequest() { Application application = eurekaClient.getApplication("spring-cloud-eureka-client"); InstanceInfo instanceInfo = application.getInstances().get(0); String hostname = instanceInfo.getHostName(); int port = instanceInfo.getPort(); // ... }

A RestTemplate can also be used to access Eureka client-services by name, but this topic is beyond this write-up.

To set up our Feign Client project, we're going to add the following four dependencies to its pom.xml:

 org.springframework.cloud spring-cloud-starter-feign   org.springframework.cloud spring-cloud-starter-netflix-eureka-client   org.springframework.boot spring-boot-starter-web   org.springframework.boot spring-boot-starter-thymeleaf 

The Feign Client is located in the spring-cloud-starter-feign package. To enable it, we have to annotate a @Configuration with @EnableFeignClients. To use it, we simply annotate an interface with @FeignClient(“service-name”) and auto-wire it into a controller.

A good method to create such FeignClients is to create interfaces with @RequestMapping annotated methods and put them into a separate module. This way they can be shared between server and client. On server-side, you can implement them as @Controller, and on client-side, they can be extended and annotated as @FeignClient.

Furthermore, the spring-cloud-starter-eureka package needs to be included in the project and enabled by annotating the main application class with @EnableEurekaClient.

The spring-boot-starter-web and spring-boot-starter-thymeleaf dependencies are used to present a view, containing fetched data from our REST service.

This will be our Feign Client interface:

@FeignClient("spring-cloud-eureka-client") public interface GreetingClient { @RequestMapping("/greeting") String greeting(); }

Here we will implement the main application class which simultaneously acts as a controller:

@SpringBootApplication @EnableFeignClients @Controller public class FeignClientApplication { @Autowired private GreetingClient greetingClient; public static void main(String[] args) { SpringApplication.run(FeignClientApplication.class, args); } @RequestMapping("/get-greeting") public String greeting(Model model) { model.addAttribute("greeting", greetingClient.greeting()); return "greeting-view"; } } 

This will be the HTML template for our view:

   Greeting Page   

At least the application.yml configuration file is almost the same as in the previous step:

spring: application: name: spring-cloud-eureka-feign-client server: port: 8080 eureka: client: serviceUrl: defaultZone: ${EUREKA_URI://localhost:8761/eureka}

Now we can build and run this service. Finally, we'll point our browser to //localhost:8080/get-greeting and it should display something like the following:

Hello from SPRING-CLOUD-EUREKA-CLIENT!

5. ‘TransportException: Cannot Execute Request on Any Known Server'

While running Eureka server we often run into exceptions like:

com.netflix.discovery.shared.transport.TransportException: Cannot execute request on any known server

Basically, this happens due to the wrong configuration in application.properties or application.yml. Eureka provides two properties for the client that can be configurable.

  • registerWithEureka: If we make this property as true then while the server starts the inbuilt client will try to register itself with the Eureka server.
  • fetchRegistry: The inbuilt client will try to fetch the Eureka registry if we configure this property as true.

Now when we start up the Eureka server, we don't want to register the inbuilt client to configure itself with the server.

If we mark the above properties as true (or don't configure them as they're true by default) while starting the server, the inbuilt client tries to register itself with the Eureka server and also tries to fetch registry which is not yet available. As a result, we get TransportException.

So we should never configure these properties as true in the Eureka server applications. The correct settings that should be put in application.yml are given below:

eureka: client: registerWithEureka: false fetchRegistry: false

6. Conclusion

As we've seen, we're now able to implement a service registry using Spring Netflix Eureka Server and register some Eureka Clients with it.

Because our Eureka Client from step 3 listens on a randomly chosen port, it doesn't know its location without the information from the registry. With a Feign Client and our registry, we can locate and consume the REST service, even when the location changes.

Akhirnya, kita mendapat gambaran besar tentang penggunaan penemuan layanan dalam arsitektur layanan mikro.

Seperti biasa, Anda akan menemukan source di GitHub, yang juga menyertakan sekumpulan file yang berhubungan dengan Docker untuk digunakan dengan docker-compose untuk membuat container dari proyek kami.