tutorial spring-boot groovy spring-cloud hystrix turbine

spring-boot - spring cloud netflix tutorial



Spring Boot+Eureka Server+Hystrix con turbina: vaciar turbine.stream (2)

Estoy intentando ejecutar Spring Boot (con Spring Cloud) + Eureka Server + Hystrix Dashboard y Turbine stream, pero tengo un problema que no pude encontrar ninguna solución hasta ahora. Yo uso Spring Boot 1.2.1.RELEASE y Spring Cloud 1.0.0.RC2 . Esto es lo que tengo:

La primera instancia es ejecutar el servidor Eureka y el panel de control de Hystrix:

@Configuration @EnableAutoConfiguration @EnableEurekaServer @EnableHystrixDashboard @EnableDiscoveryClient class Application { public static void main(String[] args) { SpringApplication.run Application, args } }

Aquí puede encontrar build.gradle para esa instancia: https://gist.github.com/wololock/570272ad7cf2d14a4d3c

El servidor Eureka se está ejecutando bien, puedo ver las instancias registradas en el panel de control del servidor eureka, también puedo usar LoadBalancer para obtener la URL de la instancia registrada utilizando su ID. Hasta ahora todo está bien.

Tengo algunas instancias que se ejecutan con la anotación @EnableHystrix y uso @HystrixCommand para definir qué métodos deben ser monitoreados por Hystrix. Cuando paso la URL a hystrix.stream de una sola instancia al panel de control de Hystrix, puedo ver que se ejecuta sin problemas.

También tengo servidor de turbina separado, no complicado:

@EnableAutoConfiguration @EnableTurbine @Configuration @EnableDiscoveryClient class Application { public static void main(String[] args) { SpringApplication.run Application, args } }

Aquí puede encontrar build.gradle para la instancia del servidor Turbine - https://gist.github.com/wololock/ff0d855b8a890232851e

Utiliza una configuración muy simple, basada principalmente en la proporcionada por la aplicación de ejemplo de turbina: https://github.com/spring-cloud-samples/turbine

info: component: Turbine endpoints: restart: enabled: true shutdown: enabled: true turbine: appConfig: pdf-creator-service InstanceDiscovery: impl: io.spring.platform.netflix.turbine.EurekaInstanceDiscovery server: port: 8989 management: port: 8990 eureka: instance: leaseRenewalIntervalInSeconds: 10 client: serviceUrl: defaultZone: ${vcap.services.${PREFIX:}eureka.credentials.uri:http://user:password@localhost:8761}/eureka/

Después de ejecutar esas instancias en orden:

  1. servidor eureka
  2. servidor de turbina
  3. descubrir la instancia del cliente,

Tengo la segunda y la tercera instancia registradas en el servidor eureka, el registro del servidor de turbina dice que hay una instancia arriba:

[2015-02-06 12:35:04.162] boot - 20495 INFO [Timer-0] --- EurekaInstanceDiscovery: Fetching instance list for apps: [pdf-creator-service] [2015-02-06 12:35:04.162] boot - 20495 INFO [Timer-0] --- EurekaInstanceDiscovery: Fetching instances for app: pdf-creator-service [2015-02-06 12:35:04.162] boot - 20495 INFO [Timer-0] --- EurekaInstanceDiscovery: Received instance list for app: pdf-creator-service = 1 [2015-02-06 12:35:04.162] boot - 20495 INFO [Timer-0] --- InstanceObservable: Retrieved hosts from InstanceDiscovery: 1 [2015-02-06 12:35:04.162] boot - 20495 INFO [Timer-0] --- InstanceObservable: Found hosts that have been previously terminated: 0 [2015-02-06 12:35:04.162] boot - 20495 INFO [Timer-0] --- InstanceObservable: Hosts up:1, hosts down: 0 [2015-02-06 12:36:04.162] boot - 20495 INFO [Timer-0] --- EurekaInstanceDiscovery: Fetching instance list for apps: [pdf-creator-service] [2015-02-06 12:36:04.162] boot - 20495 INFO [Timer-0] --- EurekaInstanceDiscovery: Fetching instances for app: pdf-creator-service [2015-02-06 12:36:04.162] boot - 20495 INFO [Timer-0] --- EurekaInstanceDiscovery: Received instance list for app: pdf-creator-service = 1 [2015-02-06 12:36:04.162] boot - 20495 INFO [Timer-0] --- InstanceObservable: Retrieved hosts from InstanceDiscovery: 1 [2015-02-06 12:36:04.162] boot - 20495 INFO [Timer-0] --- InstanceObservable: Found hosts that have been previously terminated: 0 [2015-02-06 12:36:04.162] boot - 20495 INFO [Timer-0] --- InstanceObservable: Hosts up:1, hosts down: 0

Llamar a hystrix.stream desde una sola instancia funciona, por ejemplo, curl http://localhost:8885/hystrix.stream devuelve:

data: {"type":"HystrixCommand","name":"post","group":"PdfController","currentTime":1423223614259,"isCircuitBreakerOpen":false,"errorPercentage":0,"errorCount":0,"requestCount":0,"rollingCountCollapsedRequests":0,"rollingCountExceptionsThrown":0,"rollingCountFailure":0,"rollingCountFallbackFailure":0,"rollingCountFallbackRejection":0,"rollingCountFallbackSuccess":0,"rollingCountResponsesFromCache":0,"rollingCountSemaphoreRejected":0,"rollingCountShortCircuited":0,"rollingCountSuccess":0,"rollingCountThreadPoolRejected":0,"rollingCountTimeout":0,"currentConcurrentExecutionCount":0,"latencyExecute_mean":0,"latencyExecute":{"0":0,"25":0,"50":0,"75":0,"90":0,"95":0,"99":0,"99.5":0,"100":0},"latencyTotal_mean":0,"latencyTotal":{"0":0,"25":0,"50":0,"75":0,"90":0,"95":0,"99":0,"99.5":0,"100":0},"propertyValue_circuitBreakerRequestVolumeThreshold":20,"propertyValue_circuitBreakerSleepWindowInMilliseconds":5000,"propertyValue_circuitBreakerErrorThresholdPercentage":50,"propertyValue_circuitBreakerForceOpen":false,"propertyValue_circuitBreakerForceClosed":false,"propertyValue_circuitBreakerEnabled":true,"propertyValue_executionIsolationStrategy":"THREAD","propertyValue_executionIsolationThreadTimeoutInMilliseconds":8000,"propertyValue_executionIsolationThreadInterruptOnTimeout":true,"propertyValue_executionIsolationThreadPoolKeyOverride":null,"propertyValue_executionIsolationSemaphoreMaxConcurrentRequests":10,"propertyValue_fallbackIsolationSemaphoreMaxConcurrentRequests":10,"propertyValue_metricsRollingStatisticalWindowInMilliseconds":10000,"propertyValue_requestCacheEnabled":true,"propertyValue_requestLogEnabled":true,"reportingHosts":1} data: {"type":"HystrixCommand","name":"generate","group":"WkHtmlToPdfGenerator","currentTime":1423223614259,"isCircuitBreakerOpen":false,"errorPercentage":0,"errorCount":0,"requestCount":0,"rollingCountCollapsedRequests":0,"rollingCountExceptionsThrown":0,"rollingCountFailure":0,"rollingCountFallbackFailure":0,"rollingCountFallbackRejection":0,"rollingCountFallbackSuccess":0,"rollingCountResponsesFromCache":0,"rollingCountSemaphoreRejected":0,"rollingCountShortCircuited":0,"rollingCountSuccess":0,"rollingCountThreadPoolRejected":0,"rollingCountTimeout":0,"currentConcurrentExecutionCount":0,"latencyExecute_mean":0,"latencyExecute":{"0":0,"25":0,"50":0,"75":0,"90":0,"95":0,"99":0,"99.5":0,"100":0},"latencyTotal_mean":0,"latencyTotal":{"0":0,"25":0,"50":0,"75":0,"90":0,"95":0,"99":0,"99.5":0,"100":0},"propertyValue_circuitBreakerRequestVolumeThreshold":20,"propertyValue_circuitBreakerSleepWindowInMilliseconds":5000,"propertyValue_circuitBreakerErrorThresholdPercentage":50,"propertyValue_circuitBreakerForceOpen":false,"propertyValue_circuitBreakerForceClosed":false,"propertyValue_circuitBreakerEnabled":true,"propertyValue_executionIsolationStrategy":"THREAD","propertyValue_executionIsolationThreadTimeoutInMilliseconds":8000,"propertyValue_executionIsolationThreadInterruptOnTimeout":true,"propertyValue_executionIsolationThreadPoolKeyOverride":null,"propertyValue_executionIsolationSemaphoreMaxConcurrentRequests":10,"propertyValue_fallbackIsolationSemaphoreMaxConcurrentRequests":10,"propertyValue_metricsRollingStatisticalWindowInMilliseconds":10000,"propertyValue_requestCacheEnabled":true,"propertyValue_requestLogEnabled":true,"reportingHosts":1} data: {"type":"HystrixThreadPool","name":"PdfController","currentTime":1423223614259,"currentActiveCount":0,"currentCompletedTaskCount":4,"currentCorePoolSize":10,"currentLargestPoolSize":4,"currentMaximumPoolSize":10,"currentPoolSize":4,"currentQueueSize":0,"currentTaskCount":4,"rollingCountThreadsExecuted":0,"rollingMaxActiveThreads":0,"propertyValue_queueSizeRejectionThreshold":5,"propertyValue_metricsRollingStatisticalWindowInMilliseconds":10000,"reportingHosts":1}

Pero cuando conecto turbine.stream al tablero de instrumentos de hystrix, no obtengo nada. Los registros dicen:

[2015-02-06 12:42:48.922] boot - 24816 INFO [Timer-0] --- EurekaInstanceDiscovery: Received instance list for app: pdf-creator-service = 1 [2015-02-06 12:42:48.922] boot - 24816 INFO [Timer-0] --- InstanceObservable: Retrieved hosts from InstanceDiscovery: 1 [2015-02-06 12:42:48.922] boot - 24816 INFO [Timer-0] --- InstanceObservable: Found hosts that have been previously terminated: 0 [2015-02-06 12:42:48.922] boot - 24816 INFO [Timer-0] --- InstanceObservable: Hosts up:1, hosts down: 0 [2015-02-06 12:43:26.237] boot - 24816 INFO [XNIO-2 task-4] --- TurbineStreamServlet: FilterCriteria: [] [2015-02-06 12:43:26.237] boot - 24816 INFO [XNIO-2 task-4] --- TurbineStreamServlet: StatsType filters: [] [2015-02-06 12:43:26.237] boot - 24816 INFO [XNIO-2 task-4] --- TurbineStreamingConnection: Relevance config: [] [2015-02-06 12:43:26.237] boot - 24816 INFO [XNIO-2 task-4] --- TurbineStreamingConnection: Relevance metrics config: {} [2015-02-06 12:43:26.237] boot - 24816 INFO [XNIO-2 task-4] --- ClusterMonitor: Registering event handler for cluster monitor: StreamingHandler_f1308dda-58c5-47a5-b1e2-5a0bea32226b [2015-02-06 12:43:26.237] boot - 24816 INFO [XNIO-2 task-4] --- TurbineDataDispatcher: Just added and starting handler tuple: StreamingHandler_f1308dda-58c5-47a5-b1e2-5a0bea32226b [2015-02-06 12:43:26.238] boot - 24816 INFO [XNIO-2 task-4] --- AggDataFromCluster: Per handler dispacher started for: StreamingHandler_f1308dda-58c5-47a5-b1e2-5a0bea32226b [2015-02-06 12:43:26.238] boot - 24816 INFO [XNIO-2 task-4] --- ClusterMonitor: All event handlers for cluster monitor: [StreamingHandler_637572ab-acda-4bf4-81cd-6a658adb73eb, StreamingHandler_f1308dda-58c5-47a5-b1e2-5a0bea32226b, StaticListener_For_Aggregator, StreamingHandler_5ec12ee8-3fcd-4a6f-9006-d2a6ecc309d0, StreamingHandler_72d7b9e2-ad98-42a0-9ac3-abe4aa57cc7a] [2015-02-06 12:43:26.238] boot - 24816 INFO [XNIO-2 task-4] --- ClusterMonitor: Starting up the cluster monitor for default_agg

Si hago curl http://localhost:8989/turbine.stream solo obtengo:

: ping data: {"reportingHostsLast10Seconds":0,"name":"meta","type":"meta","timestamp":1423223006935} : ping data: {"reportingHostsLast10Seconds":0,"name":"meta","type":"meta","timestamp":1423223010935} : ping data: {"reportingHostsLast10Seconds":0,"name":"meta","type":"meta","timestamp":1423223013936} : ping data: {"reportingHostsLast10Seconds":0,"name":"meta","type":"meta","timestamp":1423223017936} : ping data: {"reportingHostsLast10Seconds":0,"name":"meta","type":"meta","timestamp":1423223020937} : ping : ping data: {"reportingHostsLast10Seconds":0,"name":"meta","type":"meta","timestamp":1423223024937} : ping data: {"reportingHostsLast10Seconds":0,"name":"meta","type":"meta","timestamp":1423223028938} : ping data: {"reportingHostsLast10Seconds":0,"name":"meta","type":"meta","timestamp":1423223032938} : ping : ping data: {"reportingHostsLast10Seconds":0,"name":"meta","type":"meta","timestamp":1423223036938} : ping data: {"reportingHostsLast10Seconds":0,"name":"meta","type":"meta","timestamp":1423223039939} : ping data: {"reportingHostsLast10Seconds":0,"name":"meta","type":"meta","timestamp":1423223043939} : ping data: {"reportingHostsLast10Seconds":0,"name":"meta","type":"meta","timestamp":1423223046940} : ping data: {"reportingHostsLast10Seconds":0,"name":"meta","type":"meta","timestamp":1423223050940} : ping : ping data: {"reportingHostsLast10Seconds":0,"name":"meta","type":"meta","timestamp":1423223054941}

Mi pregunta es: ¿me perdí algo al configurarlo y ejecutarlo? Anteriormente intenté gestionar esto teniendo un servidor de eureka y turbina en una sola instancia, pero en ese caso, la turbina ni siquiera podía encontrar la aplicación registrada en eureka con el nombre correcto de la aplicación. Hice un progreso después de dividir el eureka y la turbina, pero todavía no funciona correctamente.

Estaré agradecido por cualquier sugerencia. Si necesita más información, hágamelo saber, es posible que me pierda algo importante.

Actualización 20150209

Siguiendo la sugerencia de Dave, apliqué pequeños cambios en el archivo application.yml de turbine-server . Ahora el archivo contiene solo:

info: component: Turbine turbine: appConfig: pdf-creator-service clusterNameExpression: ''default'' server: port: 8989 management: port: 8990 eureka: instance: leaseRenewalIntervalInSeconds: 10 client: serviceUrl: defaultZone: ${vcap.services.${PREFIX:}eureka.credentials.uri:http://user:password@localhost:8761}/eureka/

Pero no hace funcionar la turbina. Después de que turbine-server se da cuenta del cliente registrado en el servidor de eureka, falla con la excepción dada:

[2015-02-09 21:25:03.516] boot - 4808 INFO [Timer-0] --- EurekaInstanceDiscovery: Fetching instance list for apps: [pdf-creator-service] [2015-02-09 21:25:03.516] boot - 4808 INFO [Timer-0] --- EurekaInstanceDiscovery: Fetching instances for app: pdf-creator-service [2015-02-09 21:25:03.516] boot - 4808 INFO [Timer-0] --- EurekaInstanceDiscovery: Received instance list for app: pdf-creator-service = 1 [2015-02-09 21:25:03.520] boot - 4808 ERROR [Timer-0] --- EurekaInstanceDiscovery: Failed to fetch instances for app: pdf-creator-service, retrying once more org.springframework.expression.spel.SpelEvaluationException: EL1008E:(pos 0): Property or field ''default'' cannot be found on object of type ''com.netflix.appinfo.InstanceInfo'' - maybe not public? at org.springframework.expression.spel.ast.PropertyOrFieldReference.readProperty(PropertyOrFieldReference.java:226) at org.springframework.expression.spel.ast.PropertyOrFieldReference.getValueInternal(PropertyOrFieldReference.java:93) at org.springframework.expression.spel.ast.PropertyOrFieldReference.getValueInternal(PropertyOrFieldReference.java:81) at org.springframework.expression.spel.ast.SpelNodeImpl.getValue(SpelNodeImpl.java:120) at org.springframework.expression.spel.standard.SpelExpression.getValue(SpelExpression.java:242) at org.springframework.cloud.netflix.turbine.EurekaInstanceDiscovery.getClusterName(EurekaInstanceDiscovery.java:183) at org.springframework.cloud.netflix.turbine.EurekaInstanceDiscovery.marshallInstanceInfo(EurekaInstanceDiscovery.java:141) at org.springframework.cloud.netflix.turbine.EurekaInstanceDiscovery.getInstancesForApp(EurekaInstanceDiscovery.java:123) at org.springframework.cloud.netflix.turbine.EurekaInstanceDiscovery.getInstanceList(EurekaInstanceDiscovery.java:88) at com.netflix.turbine.discovery.InstanceObservable.getInstanceList(InstanceObservable.java:327) at com.netflix.turbine.discovery.InstanceObservable.access$500(InstanceObservable.java:66) at com.netflix.turbine.discovery.InstanceObservable$1.run(InstanceObservable.java:258) at java.util.TimerThread.mainLoop(Timer.java:555) at java.util.TimerThread.run(Timer.java:505)

Intenté escribir ''default'' así como default , pero desafortunadamente el resultado es el mismo.

Solución

Gracias Dave Syer por encontrar la solución adecuada. Básicamente lo que hizo el truco fue agregando:

turbine: clusterNameExpression: new String("default")

al archivo application.yml en la instancia de la aplicación del servidor de turbina. Puede parecer extraño, no creía que funcionara, pero lo hace. Ahora, cuando llamo a mi aplicación cliente de hystrix, obtengo la información correcta en hystrix.stream que sirve esta aplicación y también en turbine.stream del servidor de turbinas. Mi actual application.yml en el servidor de turbina tiene el siguiente aspecto:

info: component: Turbine turbine: clusterNameExpression: new String("default") appConfig: pdf-creator-service server: port: 8989 management: port: 8990 eureka: instance: leaseRenewalIntervalInSeconds: 10 client: serviceUrl: defaultZone: ${vcap.services.${PREFIX:}eureka.credentials.uri:http://user:password@localhost:8761}/eureka/

turbine.appConfig contiene la información sobre los clientes de hystrix (por sus ID). Para agregar otro cliente a su servidor de turbina, tendrá que simplemente colocar otra identificación de instancia, coma separada por la anterior. Y eso es todo gente :)


En mi caso tuve: 7979 / mock.stream como cliente para probar la aplicación de turbina. La turbina comprueba la hora del evento (timeOfEvent) para que muestre solo la fecha actual y los eventos.

Se puede apagar usando

turbine.InstanceMonitor.eventStream.skipLineLogic.enabled = false


Funciona para mí si agrego alguna configuración para el clúster, por ejemplo

turbine: appConfig: customers,stores clusterNameExpression: new String(''default'')

La turbina debe saber cómo construir el nombre del "clúster" (una clave de agregación para conjuntos de aplicaciones). El valor predeterminado es usar el nombre de la aplicación, por lo que si no configura la clusterNameExpression , debe usar un parámetro de consulta en la URL de la secuencia, por ejemplo, /turbine.stream?cluster=CUSTOMERS (nombre de aplicación en mayúsculas)