ABONAMENTE VIDEO REDACȚIA
RO
EN
Numărul 148 Numărul 147 Numărul 146 Numărul 145 Numărul 144 Numărul 143 Numărul 142 Numărul 141 Numărul 140 Numărul 139 Numărul 138 Numărul 137 Numărul 136 Numărul 135 Numărul 134 Numărul 133 Numărul 132 Numărul 131 Numărul 130 Numărul 129 Numărul 128 Numărul 127 Numărul 126 Numărul 125 Numărul 124 Numărul 123 Numărul 122 Numărul 121 Numărul 120 Numărul 119 Numărul 118 Numărul 117 Numărul 116 Numărul 115 Numărul 114 Numărul 113 Numărul 112 Numărul 111 Numărul 110 Numărul 109 Numărul 108 Numărul 107 Numărul 106 Numărul 105 Numărul 104 Numărul 103 Numărul 102 Numărul 101 Numărul 100 Numărul 99 Numărul 98 Numărul 97 Numărul 96 Numărul 95 Numărul 94 Numărul 93 Numărul 92 Numărul 91 Numărul 90 Numărul 89 Numărul 88 Numărul 87 Numărul 86 Numărul 85 Numărul 84 Numărul 83 Numărul 82 Numărul 81 Numărul 80 Numărul 79 Numărul 78 Numărul 77 Numărul 76 Numărul 75 Numărul 74 Numărul 73 Numărul 72 Numărul 71 Numărul 70 Numărul 69 Numărul 68 Numărul 67 Numărul 66 Numărul 65 Numărul 64 Numărul 63 Numărul 62 Numărul 61 Numărul 60 Numărul 59 Numărul 58 Numărul 57 Numărul 56 Numărul 55 Numărul 54 Numărul 53 Numărul 52 Numărul 51 Numărul 50 Numărul 49 Numărul 48 Numărul 47 Numărul 46 Numărul 45 Numărul 44 Numărul 43 Numărul 42 Numărul 41 Numărul 40 Numărul 39 Numărul 38 Numărul 37 Numărul 36 Numărul 35 Numărul 34 Numărul 33 Numărul 32 Numărul 31 Numărul 30 Numărul 29 Numărul 28 Numărul 27 Numărul 26 Numărul 25 Numărul 24 Numărul 23 Numărul 22 Numărul 21 Numărul 20 Numărul 19 Numărul 18 Numărul 17 Numărul 16 Numărul 15 Numărul 14 Numărul 13 Numărul 12 Numărul 11 Numărul 10 Numărul 9 Numărul 8 Numărul 7 Numărul 6 Numărul 5 Numărul 4 Numărul 3 Numărul 2 Numărul 1
×
▼ LISTĂ EDIȚII ▼
Numărul 34
Abonament PDF

(Micro)Service Discovery cu Netflix Eureka

Adrian Ivan
Software architect @ SDL



PROGRAMARE


Articolul prezintă o soluție tehnică pentru conceptul Descoperirii Serviciilor folosind Netflix Eureka, o tehnologie dezvoltată în Java de către Netflix, expusă open-source în cadrul Netflix Open Source Software (OSS).

Exemplele de cod și configurări prezentate nu folosesc Eureka direct. Folosim Spring Cloud, o inițiativă de la Spring care reunește cele mai bune soluții tehnice pentru a construi un sistem distribuit modern. Spring Cloud este construit peste Spring Boot și are suport pentru integrarea Netflix OSS.

Descoperirea Serviciilor este unul dintre conceptele cheie în construirea sistemelor distribuite orientate pe servicii.

Un Serviciu A pentru a apela un Serviciu B, trebuie să găsească o instanță fizică a Serviciului B.

Configurările statice nu mai sunt o soluție viabilă într-un sistem elastic, dinamic, unde instanțele de servicii sunt pornite și oprite frecvent (planificat și neplanificat) sau unde problemele de rețea pot fi dese (Cloud). Găsirea unei instanțe a Serviciului B nu mai este un lucru banal.

Descoperirea Serviciilor implică un mecanism unde:

Eureka - Prezentare generală

Arhitectura Netflix Eureka constă în două componente, Serverul și Clientul. Serverul este o aplicație de sine stătătoare și este responsabilă de:

Clientul face parte din ecosistemul Serviciului propriu zis și are următoarele responsabilități:

Unități de Descoperire

Eureka lucrează cu Applications și Instances. Căutarea se face după id-ul serviciului, iar rezultatele constau în informații despre instanțele Serviciului care se regăsesc în registru de instanțe.

High Availability

Netflix Eureka este construit pentru High Availability. În termenii teoremei CAP, Eureka favorizează Availability în defavoarea Consistenței.

Accentul e pus pe faptul ca serviciile să se găsească în cazul partiționărilor de rețea sau problemele de Eureka Server.

High Availability este obținut la două niveluri:

Terminologie

Eureka a fost construită pentru a fi funcțională în Cloud-ul Amazon (AWS). În consecință, folosește o terminologie specifică Amazon: regiuni, zone, etc. .Exemplele prezentate în acest articol folosesc setări implicite, regiunea us-east-1 și zona defaultZone.  

Eureka Server

Serverul este ceea ce numim Serviciul de Descoperire într-un sistem SOA.

Începeți prin a clona repo-ul Spring Cloud Eureka de pe github.com.  

Configurare Server standalone

Este simplu de pornit o aplicație Eureka Server folosind Spring Cloud. Orice aplicație Spring Boot devine un Server Eureka folosind adnotarea \@EnableEurekaServer. Folosiți exemplele următoare pentru development pe mediul local.

Exemplu aplicație Java:

@SpringBootApplication
@EnableEurekaServer 
@EnableDiscoveryClient
public class EurekaApplication {

public static void main(String[] args) {
  SpringApplication.run(EurekaApplication.class, args);
    }
}  

Configurare yml:

server:
  port: 8761
security:
  user:
    password: ${eureka.password} 
eureka:   
  password: ${SECURITY_USER_PASSWORD:password}
  server:
    waitTimeInMsWhenSyncEmpty: 0
    enableSelfPreservation: false
  client:    
    preferSameZoneEureka: false 
---
spring:
  profiles: devlocal
eureka:
  instance:
    hostname: localhost
  client:
    registerWithEureka: false
    fetchRegistry: false 
    serviceUrl:
      defaultZone: http://user:${eureka.password:${SECURITY_USER_PASSWORD:password}}@localhost:8761/eureka/

Porniți aplicația folosind comanda: 

mvn spring-boot:run -Drun.jvmArguments="-Dspring.profiles.active=devlocal"

Setările registerWithEureka și fetchRegistry au valoarea false, ceea ce înseamnă ca Serverul nu face parte dintr-un cluster.

Configurare Cluster

Serverele Eureka sunt configurate în mod cluster pentru a asigura disponibilitatea în cazul în care unele instanțe au probleme.

Clienții eureka nu au nevoie de afinitate pentru Server și se pot conecta transparent la oricare Server din Cluster.

Serverele au nevoie de referințe către alte instanțe de Server.

Exista diferite modalități pentru a obține aceste referințe, descrise mai jos.

DNS

Netflix folosește DNS pentru a gestiona lista de referințe Eureka Server într-un mod dinamic. Clienții Eureka nu au nevoie de repornire pentru a obține noile configurări, ci le obțin printr-o nouă interogare DNS.

Aceasta este configurarea recomandată de producție.

Să vedem un exemplu cu un cluster de două servere Eureka, dsc01 și dsc02.

Se poate folosi Bind sau alt server DNS. Aici găsiți instrucțiuni pentru a instala și configura Bind.

  Configurație DNS:

$TTL 604800
@ IN  SOA ns.eureka.local. hostmaster.eureka.local. (
             1024       ; Serial
             604800     ; Refresh
              86400     ; Retry
            2419200     ; Expire
             604800 )   ; Negative Cache TTL
;
@ IN  NS  ns.eureka.local.
ns IN A 10.111.42.10
txt.us-east-1 IN TXT "defaultZone.eureka.local"
txt.defaultZone IN TXT "dsc01" "dsc02"
;

Configurația aplicației:

eureka:
  client:
    registerWithEureka: true
    fetchRegistry: true
    useDnsForFetchingServiceUrls: true
    eurekaServerDNSName: eureka.local
    eurekaServerPort: 8761
    eurekaServerURLContext: eureka

Lista statică de Servere

Configurarea clusterului prezentat anterior:

eureka:
  client:
    registerWithEureka: true
    fetchRegistry: true
    serviceUrl:
      defaultZone: http://dsc01:8761/eureka/,http://dsc02:8762/eureka/ Orice schimbare a listei necesită o repornire a Clientului Eureka pentru a obține lista actualizată.

Instanțe multiple de Server pe aceeași mașină

În cazul în care se dorește pornirea mai multor instanțe de Server pe aceeași mașină, trebuie folosite hostname-uri diferite pentru fiecare instanță. Eureka identifică pe baza combinației hostname și port. Hostname-urile trebuie să rezolve către localhost. în Windows OS se folosește fișierul hosts.

eureka:
instance:
hostname: server1

[Eureka Dashboard] Eureka Dashboard

Interfața grafică

Eureka Server oferă în interfața grafică pentru a observa statusul și detalii despre Instantele înregistrate.

Noi avem un mediu în care evaluăm tehnologii. Inițial am pornit cu exemplele Spring Cloud și le-am modificat pentru nevoile noastre.

Exemplul de mai sus prezintă un Server Eureka din mediul nostru. Sunt prezentate următoarele:

Interfata XML/Text

Această interfața prezintă mai multe detalii, http://dsc02:8761/eureka/apps (copy&paste din browser):

<?xml version="1.0"?>

-<applications>
  <versions__delta>1
  </versions__delta>
  <apps__hashcode>UP_11_
  </apps__hashcode>
   +<application>
   +<application>
   +<application>
   -<application>                   
     <name>BESTPRICES</name>            
     +<instance>            
     -<instance>                
     <hostName>clj-lcpdevsrv10
     </hostName>                
      <app>BESTPRICES</app>                
      <ipAddr>10.111.42.71</ipAddr>                
      <status>UP</status>                
      <overriddenstatus>UNKNOWN
      </overriddenstatus>                     
 <port enabled="true">8000</port>                
<securePort enabled="true">443
</securePort>                
<countryId>1</countryId>                                           
<dataCenterInfo class="com.netflix.appinfo.InstanceInfo$DefaultDataCenterInfo">                
 <name>MyOwn</name>                
 </dataCenterInfo>                                
 -<leaseInfo>                
  <renewalIntervalInSecs>30
  </renewalIntervalInSecs>                

<durationInSecs>90</durationInSecs>                
<registrationTimestamp> 
  1426271956166 
</registrationTimestamp>                
<lastRenewalTimestamp>  
  1427199350993
</lastRenewalTimestamp>                
<evictionTimestamp>0</evictionTimestamp>                
<serviceUpTimestamp>1426157045251
</serviceUpTimestamp>                
</leaseInfo>                

<metadata class="java.util.Collections$EmptyMap"/>                
  <appGroupName> MYSIDECARGROUP</appGroupName>                
  <homePageUrl>http://clj-lcpdevsrv10:8000/
  </homePageUrl>                

<statusPageUrl>http://clj-lcpdevsrv10:8001/info
</statusPageUrl>                
<healthCheckUrl>http://clj-lcpdevsrv10:8001/health
</healthCheckUrl>                
<vipAddress>bestprices</vipAddress>                
<isCoordinatingDiscoveryServer>false
</isCoordinatingDiscoveryServer>                
<lastUpdatedTimestamp>1426271956166
</lastUpdatedTimestamp>                
<lastDirtyTimestamp>1426271939882
</lastDirtyTimestamp>                
<actionType>ADDED</actionType>            
 </instance>        
</application>                
+<application>
+<application>
+<application>
</applications>

Informații despre Instanță

Elementul "instance" prezintă informații complete despre o instanță înregistrată.

Majoritatea detaliilor sunt clare și prezintă informații precum locația fizica a instanței, momentul ultimei înnoiri, etc. .

URL-urile de healthcheck poți fi folosite de către tool-uri externe de monitorizare.

Informații proprii pot fi adăugate cu rolul de metadata.

Eureka Client

Clientul Eureka face parte din ecosistemul unei Instanțe de Serviciu business.

Poate fi folosit în mod embedded sau ca și process atasat (logic).

Netflix sugerează ca modul embedded să fie folosit pentru servicii Java și modul atașat pentru servicii scrise în limbaje non-JVM.

Clientul este configurat cu o listă de Servere Eureka. Configurațiile anterioare din cazul Eureka Server se aplică și la Client.

Orice aplicație Spring Boot devine un Client Eureka folosind adnotarea @EnableDiscoveryClient și având Eureka în Classpath:

@SpringBootApplication
@EnableDiscoveryClient
public class SampleEurekaClientApp extends RepositoryRestMvcConfiguration {

    public static void main(String[] args) {
        SpringApplication.run(CustomerApp.class, args);
    }
}  

Heartbeat-uri

Clientul și Serverul implementează un protocol de heartbeat-uri. Clientul trebuie să trimită mesaje de heartbeat regulat către Server. Serverul așteaptă aceste mesaje pentru a menține instanța de serviciu în registru sau pentru a reînnoi informații despre aceasta. În cazul în care aceste mesaje nu sunt primite, instanța este scoasă din registru.

Mesajele heartbeat pot specifica și un status pentru instanța: UP, DOWN, OUT_OF_SERVICE, cu consecințe imediate pentru rezultatele de descoperire returnate.

Mod protecție Server

Eureka Server are un mod protecție: în cazul în care un anumit număr de instanțe nu mai trimit mesaje heartbeat într-un anumit interval de timp, serverul blochează registrul și nu va șterge automat aceste instanțe. Consideră că a avut loc o partiționare a rețelei fizice și așteaptă ca aceste instanțe să revină când problema fizică se rezolvă. Această capabilitate este utilă în cazul Cloud și poate fi oprită în cazul data center-elor private.

Cache local Client

Una dintre capacitățile speciale ale Eureka este Cach-ul local Client. Clientul obține regulat informații din registru Eureka Server și le stochează local. La un moment dat poate avea aceleași informații ca și Server-ul. În cazul în care toate serverele devin indisponibile sau clientul este izolat de servere printr-o problemă fizică de rețea, acest Client poate funcționa în continuare cu rezultate bune până când acest cache local devine învechit.

Cache-ul local îmbunătățește performanța comunicării între servicii pentru că nu mai este nevoie de a trece peste încă un hop intermediar cu scopul de a face balansarea apelurilor.

Folosire

Clientul Eureka poate fi folosit în mod direct sau cu ajutorul altor librării ce se integrează cu Eureka.

În continuare sunt prezentate două opțiuni de folosire a clientului Eureka pentru a apela un serviciu, în cazul acesta serviciu bestprices din mediul nostru de evaluare:

Direct

 ...
@Autowired
private DiscoveryClient discoveryClient;
...

private BestPrice findBestPriceWithEurekaclient(final String productSku) {

 BestPrice bestPrice = null;
 // get hold of a service instance from Eureka
 ServiceInstance instance = null;
 // "bestprices" is the name of the service in Eureka
 List instances = discoveryClient
    .getInstances("bestprices");
 if (instances != null && instances.size() > 0) {
 instance = instances.get(0); //could be random
 // Invoke server based on host and port. 
 // Example using RestTemplate.    
 URI productUri = URI.create(String
   .format("http://%s:%s/bestprices/" + productSku,
    instance.getHost(), instance.getPort()));

 bestPrice = restTemplate.getForObject(productUri,
    BestPrice.class);            
 }
  return bestPrice;        
}   

Ribbon Load Balancer

Ribbon este un client HTTP și un load balancer software de la Netflix și care se integrează cu Eureka:

... 
@Autowired  
private LoadBalancerClient loadBalancerClient;
...

private BestPrice findBestPriceWithLoadBalancerClient(final String productSku) {
 BestPrice bestPrice = null;

 // "bestprices" is the name of the service in 
 // Eureka, as well as of the Ribbon LoadBalancer 
 // which gets created automatically.

ServiceInstance instance = loadBalancerClient
  .choose("bestprices");

  if (instance != null) {
  // Invoke server, based on host and port. 
  // Example using RestTemplate.
  URI productUri = URI.create(String
    .format("http://%s:%s/bestprices/" + productSku, 
     instance.getHost(), instance.getPort()));

   bestPrice = restTemplate.getForObject(productUri,
   BestPrice.class);
   }

    return bestPrice;
}

Servicii Non-JVM

Acest aspect nu va fi prezentat extensiv în acest articol și poate fi subiectul altuia.

Exista două abordări:

Concluzii

LANSAREA NUMĂRULUI 149

Marți, 26 Octombrie, ora 18:00

sediul Cognizant

Facebook Meetup StreamEvent YouTube

NUMĂRUL 147 - Automotive

Sponsori

  • Accenture
  • BT Code Crafters
  • Accesa
  • Bosch
  • Betfair
  • MHP
  • BoatyardX
  • .msg systems
  • P3 group
  • Ing Hubs
  • Cognizant Softvision
  • Colors in projects