web-dev-qa-db-fra.com

Spring Boot + Eureka Server + Hystrix with Turbine: turbine vide.stream

J'essaie d'exécuter Spring Boot (avec Spring Cloud) + Eureka Server + Hystrix Dashboard and Turbine stream, mais je rencontre un problème que je n'ai trouvé aucune solution jusqu'à présent. J'utilise Spring Boot 1.2.1.RELEASE et Spring Cloud 1.0.0.RC2 . Voici ce que j'ai:

La première instance exécute le serveur Eureka et le tableau de bord Hystrix:

@Configuration
@EnableAutoConfiguration
@EnableEurekaServer
@EnableHystrixDashboard
@EnableDiscoveryClient
class Application {

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

Ici vous pouvez trouver build.gradle pour cette instance - https://Gist.github.com/wololock/570272ad7cf2d14a4d3c

Le serveur Eureka fonctionne bien, je peux voir les instances enregistrées sur le tableau de bord du serveur eureka, je peux également utiliser LoadBalancer pour obtenir l'URL de l'instance enregistrée en utilisant son identifiant. Jusqu'à présent, tout va bien.

J'ai quelques instances exécutées avec @EnableHystrix annotation et utilisation @HystrixCommand pour définir quelles méthodes doivent être contrôlées par Hystrix. Lorsque je transmets l'URL à hystrix.stream d'une seule instance au tableau de bord Hystrix, je peux le voir fonctionner sans problème.

J'ai également un serveur Turbine séparé, pas compliqué:

@EnableAutoConfiguration
@EnableTurbine
@Configuration
@EnableDiscoveryClient
class Application {

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

Ici vous pouvez trouver build.gradle pour l'instance de serveur Turbine - https://Gist.github.com/wololock/ff0d855b8a890232851e

Il utilise une configuration très simple, basée principalement sur celle fournie par l'exemple d'application de turbine - 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/

Après avoir exécuté ces instances dans l'ordre:

  1. serveur eureka
  2. serveur de turbine
  3. découvrir l'instance client,

J'ai une deuxième et une troisième instance enregistrées sur le serveur eureka, indique le journal du serveur de turbine, qu'il y a une instance en place:

[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

L'appel de hystrix.stream à partir d'une seule instance fonctionne, par exemple curl http://localhost:8885/hystrix.stream Retour:

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}

Mais quand j'attache turbine.stream au tableau de bord hystrix, je ne reçois rien. Les journaux disent:

[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 je fais curl http://localhost:8989/turbine.stream Je reçois seulement:

: 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}

Ma question est: ai-je raté quelque chose lors de sa configuration et de son fonctionnement? Auparavant, j'essayais de gérer cela en ayant eureka et turbine server en une seule instance, mais dans ce cas, turbine ne pouvait même pas trouver l'application enregistrée dans eureka en utilisant le nom d'application approprié. J'ai fait des progrès après avoir divisé eureka et turbine, mais cela ne fonctionne toujours pas correctement.

Je serai reconnaissant pour toute suggestion. Si vous avez besoin de plus d'informations, faites le moi savoir, je pourrais manquer quelque chose d'important.

MISE À JOUR 20150209

Suite à la suggestion de Dave, j'ai appliqué de petits changements dans application.yml fichier de turbine-server. Maintenant, le fichier ne contient que:

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/

Mais cela ne fait pas fonctionner turbine.stream. Une fois que turbine-server a eu connaissance d'un client enregistré sur le serveur eureka, il échoue avec une exception donnée:

[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)

J'ai essayé d'écrire 'default' ainsi que default, mais le résultat est malheureusement le même.

Solution

Merci à Dave Syer d'avoir trouvé la bonne solution. Fondamentalement, ce qui a fait l'affaire était d'ajouter:

turbine:
    clusterNameExpression: new String("default")

à application.yml fichier dans l'instance d'application du serveur turbine. Cela peut sembler bizarre, je ne pensais pas que cela fonctionnerait, mais c'est le cas. Maintenant, lorsque j'appelle mon application client hystrix, j'obtiens les informations appropriées dans hystrix.stream qui est desservi par cette application et dans turbine.stream du serveur Turbine également. Mon actuel application.yml dans le serveur de turbine se présente comme suit:

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 contient les informations sur les clients hystrix (par leur ID). Pour ajouter un autre client à votre serveur turbine, vous devrez simplement mettre un autre identifiant d'instance, séparé par le coma du précédent. Et c'est tout le monde :)

21
Szymon Stepniak

Cela fonctionne pour moi si j'ajoute une configuration pour le cluster, par exemple.

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

Turbine doit savoir comment construire le nom du "cluster" (une clé d'agrégation pour des ensembles d'applications). La valeur par défaut est d'utiliser le nom de l'application, donc si vous ne définissez pas le clusterNameExpression, vous devez utiliser un paramètre de requête dans l'URL du flux, par exemple /turbine.stream?cluster=CUSTOMERS (nom d'application en majuscule).

11
Dave Syer

Dans mon cas, j'avais: 7979/mock.stream comme client pour tester l'application turbine. La turbine vérifie l'heure de l'événement (timeOfEvent) afin de n'afficher que les événements de date et d'heure actuels.

Il peut être désactivé à l'aide de

turbine.InstanceMonitor.eventStream.skipLineLogic.enabled = false

1
kadkaz