Artikel "Frühlingswolken"
Transcription
Artikel "Frühlingswolken"
Java Mag REST und SPAs – immer die beste Lösung? 62 6.2016 magazin Java • Architekturen • Web • Agile www.javamagazin.de Multilingual React Native Scala in AWS Groovy-Code in Java-Applikationen 30 Native Apps mit JavaScript 70 Schritt für Schritt in die Cloud 78 e h c i l k c glüJava-Entwickler Der © iStockphoto.com/thorbjorn66 Wenn das Hobby zum Beruf wird Spring Boot: Eine frühlingshafte Lösung für Microservices 56 Java 8: API- Design mit Lambdas 12 Spring Cloud und Netflix OSS: Cloud-native Anwen dungen bauen 87 Sonderdruck Agile Teil 2: Cloud-native Anwendungen bauen mit Spring Cloud und Netflix OSS Frühlingswolken Cloud-native Anwendungen skalieren fast beliebig, reagieren elastisch auf Last und sind bis an die Schmerzgrenze fehlertolerant. So etwas sicherzustellen ist komplex. Es braucht neue Frameworks und Infrastruktur, die den Anwendungsentwickler vor dieser Komplexität schützen. Genau das leistet Spring Cloud: Es bietet ein Framework zur Entwicklung von Cloud-nativen Anwendungen als Microservices und integriert die quelloffene Cloud-Infrastruktur von Netflix und Co. von Dr. Josef Adersberger und Mario-Leander Reimer Die Entwicklung und der Betrieb von Cloud-nativen Anwendungen sollte so einfach sein wie bei traditionellen Java-EE-Anwendungen. Dennoch bringt der hohe Verteilungsgrad viel Komplexität mit sich. Das SpringCloud-Projekt [1] verspricht hier Abhilfe: Es setzt auf Spring Boot als Container für Microservices, integriert vielerlei Cloud-Infrastruktur und vereinfacht in gewohnter Spring-Manier die Programmierung. Spring Cloud ist ein Schirmprojekt über derzeit fünfzehn Bausteinprojekte. Es ist Ende 2014 gestartet und unserer Meinung nach die tragfähigste Basis, um Cloud-native Anwendungen mit Java zu entwickeln. Spring Cloud bietet alle Bausteine eines MicroserviceFrameworks, wie sie im Vorgängerartikel beschrieben wurden [2]. Abbildung 1 zeigt, wie sich Spring-CloudBausteine auf die typischen Bausteine eines Microservice-Frameworks abbilden. Die momentan grundlegendsten Bausteine von Spring Cloud sind Netflix Eureka, Spring Cloud Config, Netflix Hystrix, Netflix Ribbon, Netflix Feign, Netflix Zuul, Hystrix Dashboard und Netflix Turbine. Netflix Eureka zur Service Discovery, die Registratur für Serviceendpunkte: Microservices können ihre Endpunkte bei Eureka registrieren und nach vorhandenen Endpunkten suchen. Ferner überwacht Eureka kontinuierlich die Verfügbarkeit der Endpunkte. Es besteht aus einer hochskalierbaren und ausfallsicheren Serverkomponente sowie aus clientseitigen Komponenten. Artikelserie Teil 1: Der Cloud-Native-Stack Teil 2: Cloud-native Anwendungen bauen mit Spring Cloud und Netflix OSS Teil 3: Clusterorchestrierung mit Kubernetes Teil 4: Mesos: Das Betriebssystem der Cloud 2 javamagazin 6 | 2016 Spring Cloud Config zur Service Configuration übernimmt die zentrale Verwaltung von Konfigurationsparametern der Anwendungen über alle Umgebungen und Stages hinweg. Es stellt dabei die Konsistenz der Konfigurationsstände sicher und ermöglicht es, Konfigurationsparameter zur Laufzeit zu aktualisieren. Net flix Hystrix als Circuit Breaker im Serviceclient sorgt für die nötige Resilienz von Serviceclients [3], [4] und sammelt Statistiken zu Fehlerquoten und Antwortzeiten. Bei Ribbon handelt es sich um einen clientseitigen Load Balancer zur Lastverteilung zwischen mehreren Serviceinstanzen. Diese erfragt er bei Eureka. Netflix Feign, zum einfachen Aufruf von REST-Schnittstellen im Serviceclient, verfolgt einen deklarativen Ansatz; der übliche Boilerplate-Code bei Nutzung von Jersey oder Spring RestTemplate entfällt. Feign macht aus einem normalen Java-Interface plus speziellen Annotationen einen Serviceclient, der bereits mit Hystrix, Ribbon und Eureka integriert ist. Netflix Zuul – als Edge-Server – ist das Zugangstor zu den Endpunkten von außen. Er routet Anfragen zum richtigen Endpunkt und sorgt dabei für Load Balancing. Zuul holt sich die dafür notwendigen Informationen aus Eureka und verwendet Ribbon und Hystrix für das Dispatching der Aufrufe. Das Hystrix Dashboard zeigt die Statistiken der Hystrix Circuit Breaker grafisch an, Netflix Turbine ist verantwortlich, die dafür notwendigen Daten von allen Knoten einzusammeln und zu aggregieren. Eine vertiefende Beschreibung dieser und weiterer Bausteine von Spring Cloud kann der Dokumentation [5] entnommen werden. Da diese teilweise sehr knapp gehalten ist, raten wir zusätzlich zu einem Blick in die Spring-Cloud-Beispielanwendungen [6] und, gerade wenn es um Konfigurationsparameter geht, in den Quellcode selbst. Spring Cloud wird in Release Trains versioniert, ähnlich dem Entwicklungsmodell von Eclipse. Damit wird die Entwicklung in den verschiedenen Bausteinprojekten synchronisiert. Die Namen der Release Trains sind © Software & Support Media GmbH www.JAXenter.de Sonderdruck Agile Abb. 1: Spring-Cloud-Bausteine auf typische Bausteine eines Microservice-Frameworks abbilden Stationen der Londoner Metro: Das aktuelle Release ist Angel, momentan in Entwicklung ist Brixton. Beim Bau einer Cloud-nativen Anwendung muss beachtet werden, dass die Releases von Spring Boot und Spring Cloud kompatibel sind. So läuft Angel noch mit Spring Boot 1.2.x, wohingegen Brixton nur noch mit Spring Boot 1.3.x kompatibel ist. Für das schnelle Erstellen von Cloud-nativen Anwendungen bietet sich Spring Initializr [7] an. Über eine Weboberfläche können die gewünschten Bausteine ausgewählt und ein Projektgrundgerüst mit Build-Skripten und Spring-Boot-Hauptklasse generiert werden. Der Zwitscher-Showcase Nun wollen wir am Beispiel von Zwitscher, unserer Cloud-nativen Beispielanwendung, zeigen, wie Spring Cloud genutzt werden kann. Zwitscher ist eine Webanwendung, die Meldungen aus mehreren Internetquellen aggregiert. Abbildung 2 zeigt den schematischen Aufbau von Zwitscher und welche Bausteine von Spring Cloud dabei verwendet werden. Zwitscher besteht aus zwei Microservices: Der Zwitscher-Service ruft Tweets und Quotes bei entsprechenden Onlinediensten ab und stellt sie über ein REST-API zur Verfügung. Das Zwitscher Dashboard ist ein Web- Abb. 2: Aufbau Zwitscher-Showcase www.JAXenter.de © Software & Support Media GmbH javamagazin 6 | 2016 3 Sonderdruck Agile Abb. 3: Eureka-Serviceübersicht UI, mit dem Tweets und Quotes angezeigt und durchsucht werden können. Es nutzt dafür das REST-API des Zwitscher-Service. Um diese beiden anwendungsspezifischen Microservices herum läuft die Infrastruktur des Microservice-Frameworks – natürlich ebenso als Microservice. Der komplette Sourcecode der Beispielanwendung steht auf GitHub [8] zur Verfügung. Service Discovery mit Netflix Eureka Im ersten Schritt realisieren wir die Service Discovery auf Basis von Netflix Eureka. Für das schnelle ProjektSet-up verwenden wir Spring Initializr, wählen den Baustein Eureka Server aus und lassen uns die Projekthülle generieren. Um die generierte Applikation in einen lauffähigen Eureka-Server zu verwandeln, muss man lediglich die @EnableEurekaServer-Annotation zur Spring-Boot-Hauptklasse hinzufügen. Danach ist Listing 1 eureka: client: registerWithEureka: false fetchRegistry: false Listing 2 eureka: client: serviceUrl: defaultZone: http://localhost:8761/eureka/ 4 javamagazin 6 | 2016 der Eureka-Server bereits lauffähig, das UI kann unter http://localhost:8761 aufgerufen werden (Abb. 3). Serviceübersicht in Eureka Eureka ist auf Hochverfügbarkeit ausgelegt. Unser Server erwartet eine zweite Eureka-Serverinstanz, mit der die Registry-Informationen repliziert werden können. Für ein einfaches lokales Set-up ist dieses Verhalten jedoch nicht erforderlich, weshalb wir Eureka vorerst im Standalone-Modus betreiben. Listing 1 zeigt die hierfür notwendige Konfiguration in der Datei application.yml. Jeder Eureka-Server ist gleichzeitig auch ein EurekaClient, da er seine Dienste über Endpunkte zur Verfügung stellt. Die obigen Parameter bringen den Client im Server dazu, den Service nicht zu registrieren und sich den kompletten Registry-Inhalt nicht anfänglich herunterzuladen. Damit ist sein Wunsch nach einem zweiten Eureka-Server abgekappt. Um später einen Service am Eureka-Server zu regis trieren, muss dem Projekt die spring-cloud-starter-eureka BuildDependency hinzugefügt und die Hauptklasse mit der @EnableDiscoveryClient-Annotation versehen werden. Daraufhin registriert sich die Anwendung unter dem Namen, der als Property spring.application.name in der Datei bootstrap.yml hinterlegt ist. Damit der Eureka-Client den Server findet, definieren wir den Eureka-ServiceURL in der application.yml (Listing 2). Der Parameter defaultZone erlaubt, dass man kommasepariert auf eine oder mehrere Eureka-Serverinstanzen verweist. Service Configuration mit Spring Cloud Config Die Konfigurationen der einzelnen Services können über Spring Cloud Config zentral über einen Config-Server © Software & Support Media GmbH www.JAXenter.de Sonderdruck Agile verwaltet werden. Eine Anwendung sucht beim Start den Configuration Service per Service Discovery und ruft anschließend die jeweiligen Konfigurationswerte ab. Für Zwitscher erzeugen wir per Spring Initializr einen neuen Config-Server. Die Hauptklasse wird anschließend mit der @EnableConfigServer-Annotation versehen, um den Config-Server in die Spring-BootApplikation einzubetten. Zusätzlich annotieren wir die Applikation mit @EnableDiscoveryClient, damit der Config-Server später per Service Discovery gefunden wird. Der Server stellt die Konfigurationen über eine REST-Schnittstelle bereit. Es gibt verschiedene Möglichkeiten zur Ablage der Konfigurationsdateien: in einem Git oder Subversion Repository oder nativ im Klassenpfad des Config-Servers. Letztere Option ist speziell zu Beginn der Entwicklung praktisch. Listing 3 zeigt die entsprechende Konfiguration des Config-Servers. Alle Konfigurationsdateien werden direkt im Verzeichnis src/main/resources/config im Config-ServerProjekt abgelegt und folgen dem Namensmuster {application}-{profile}.yml. Zu jedem Microservice können also noch verschiedene Konfigurationsvarianten (Profile) hinterlegt werden. Dies kann man z. B. nutzen, um unterschiedliche Parameter für die lokale Ausführung und die Ausführung in der Cloud zu hinterlegen. Es ist natürlich nicht ratsam, sensible Daten wie Passwörter oder API Keys im Klartext in den Konfigurationsdateien zu hinterlegen. Darum bietet Spring Cloud Config die Möglichkeit, Konfigurationswerte symmetrisch oder asymmetrisch zu verschlüsseln. Vor Auslieferung der Konfigurationsparameter an die Anwendung werden die Werte entschlüsselt. Mehr Sicherheit bietet nur noch ein Baustein wie Vault [9], der aber noch nicht in Spring Cloud integriert ist. Damit nun Anwendungen beim Start ihre Konfiguration beim Config-Server abrufen können, muss der URL Listing 3 spring: profiles: native cloud: config: server: native: searchLocations: classpath:/config Listing 4 spring: cloud: config: enabled: true discovery: enabled: true serviceId: ZWITSCHER-CONFIG www.JAXenter.de des Config-Endpunkts per Service Discovery ermittelt werden. Listing 4 zeigt die dafür notwendige Konfiguration. Der Parameter ZWITSCHER-CONFIG ist dabei der Servicename des Config-Servers in Eureka. Serviceclients mit Feign, Ribbon und Hystrix Es liegt in der Natur von Cloud-nativen Anwendungen, dass sie viel Remote kommunizieren. Es braucht also Unterstützung dabei, schnell Serviceclients von hoher Qualität entwickeln zu können. Die NetflixBausteine Feign, Ribbon und Hystrix, integriert mit Spring Cloud, bieten hier eine elegante Lösung. Feign ist ein deklarativer Web-Service-Client: Die Serviceschnittstelle wird über ein annotiertes Java-Interface beschrieben (Listing 5). Das Interface wird mit @ FeignClient annotiert und dabei der Servicename des Endpunkts in Eureka angegeben. Zusätzlich kann ein Fallback Handler angegeben werden, der alle Anfragen im Fehlerfall beantwortet. Feign kümmert sich selbstständig um die Service Discovery, und alle Anfragen an den Endpunkt werden automatisch über einen Ribbon Load Balancer abgesetzt und mit einem Hystrix Circuit Breaker versehen. Will man den Serviceclient nun nutzen, muss man zunächst in der Spring-Boot-Hauptklasse ein paar Annotationen ergänzen (Listing 6). Zusätzlich dazu kann auch noch die Annotation @RibbonClient verwendet werden, um das Load-Balancing-Verhalten von Ribbon zu konfigurieren. Nun steht der Serviceclient fertig initialisiert per Spring Dependency Injection zur Verfügung. Der Ribbon Loader Balancer kann auch ohne Feign im Zusammenspiel mit einem RestTemplate verwendet werden (Listing 7). Beim Injizieren wird lediglich die @ LoadBalanced-Annotation zusätzlich angegeben. Die Nutzung der Instanz erfolgt wie gewohnt, mit der Ausnahme, dass der URL anstatt eines Hostnamens einen Eureka-Servicenamen enthalten muss. Listing 5 @FeignClient(name = "zwitscher-service", fallback = Quote.Fallback.class) public interface QuoteRepository { @RequestMapping(method = RequestMethod.GET, value = "/quote") Quote getNextQuote(); } Listing 6 @EnableDiscoveryClient @EnableCircuitBreaker @EnableFeignClients public class ZwitscherBoardApplication { //... } © Software & Support Media GmbH javamagazin 6 | 2016 5 Sonderdruck Agile Abb. 4: Das Zwitscher Hystrix Dashboard Edge-Server mit Netflix Zuul Ein Zuul-Edge-Server bildet das Zugangstor zu Zwitscher. Sowohl das Zwitscher-Service-REST-API als auch das Zwitscher Dashboard werden als Endpunkte von Zuul exportiert und sind unter einem gemeinsamen Basis-URL erreichbar. Auch hier nutzen wir wieder den Spring Initializr für einen schnelle Start und wählen dabei die folgenden Bausteine aus: Config Client, Eureka Discovery und Zuul. Um die generierte Spring-Boot-Applikation zu einem Zuul Proxy zu machen, muss lediglich die @ EnableZuulProxy-Annotation zur Hauptklasse hinzugefügt werden. Diese Annotation aktiviert neben Listing 7 @Autowired @LoadBalanced private RestTemplate restTemplate; final String tweetsRibbonUrl = "http://zwitscher-service/tweets?q={q}"; Zwitscher[] tweets = restTemplate.getForObject(tweetsRibbonUrl, Zwitscher[].class, q); Listing 8 zuul: ignoredPatterns: /**/admin/** routes: api: path: /api/** serviceId: zwitscher-service stripPrefix: true zwitscher-board: /** 6 javamagazin 6 | 2016 der Zuul-Konfiguration auch einen Eureka-DiscoveryClient und den Hystrix Circuit Breaker. Netflix Ribbon sorgt für die Lastverteilung aller weitergeleiteten Anfragen und Hystrix für deren Resilienz. Das Herzstück unseres Edge-Servers besteht aus der Konfiguration von Routen. Jede Route definiert, welches URL-Pattern an welchen in Eureka registrierten Service weitergeleitet wird. In Listing 8 sind zwei Beispiele für Routendefinitionen zu sehen. So leitet die api-Route alle Aufrufe unterhalb des Pfads /api/ an den Service mit dem Namen zwitscher-service weiter. Das Präfix (api) wird dabei abgeschnitten. Die zweite Route verwendet die kurze Notation; hiermit werden die Anfragen an den Service mit dem Namen zwitscherboard weitergeleitet. Präfix und Servicename sind hier gleich. Über das zuul.ignoredPatterns Property werden Patterns definiert, die ignoriert und nicht weitergeleitet werden sollen. Alle administrativen URLs wollen wir natürlich nicht über den Edge-Server zugänglich machen. Monitoring mit Hystrix und Turbine Im letzten Schritt statten wir die Anwendung mit einem Monitoring aus. Wir wollen den Zustand der Circuit Breaker über alle Services hinweg überwachen. Genau die Circuit Breaker sitzen an den neuralgischen Stellen eines Microservice-Systems. Die aufrufenden Microservices können am besten beurteilen, wie es einem aufgerufenen Microservice geht – ob er zu viele Fehler produziert, abgestürzt ist oder zu langsam antwortet. Den Zustand der Hystrix Circuit Breaker aller Services sammeln wir über Turbine zusammen und stellen sie per Hystrix Dashboard zur Verfügung (Abb. 4). Wie schon in den vorherigen Schritten erzeugen wir ein neues Projekt per Spring Initialzr und wählen dabei © Software & Support Media GmbH www.JAXenter.de Sonderdruck Agile die folgenden Bausteine: Discovery Client, Config Client, Hystrix Dashboard und Turbine. Die Hauptklasse der Monitoringanwendung wird danach mit den @EnableHystrixDashboard- und @EnableTurbine-Annotationen versehen. Zusätzlich definieren wir noch ein Request Mapping, um Anfragen auf oder direkt an das Hystrix Dashboard weiterzuleiten (Listing 9). Um den aggregierten Zustand der Circuit Break über mehrere Applikationen hinweg anzeigen zu können, muss Turbine konfiguriert werden. Wie üblich passiert dies direkt in der Anwendungskonfiguration (Listing 10). Über das turbine.appConfig Property wird die Liste an Eureka-Servicenamen konfiguriert, deren HystrixZustandsdaten aggregiert werden sollen. Nach dem Start der Applikation kann das Hystrix Dashboard direkt unter dem per server.port Property konfigurierten Port aufgerufen werden. Fazit und Ausblick Der Zwitscher-Showcase zeigt, dass mit Spring Cloud einfache Cloud-native Anwendungen schnell umgesetzt werden können. Der Programmierstil ist in gewohnter Spring-Manier und geht einfach von der Hand. Alle Bausteine der Infrastruktur sind Microservices. Eine vollständige Umgebung ist deshalb mit wenigen Kommandos schnell gestartet. Spring Cloud macht einen reifen und runden Eindruck, wird sich aber durch die hohe Dynamik im Bereich der Cloud-nativen Anwendungen stärker verändern, als man dies bei anderen Frameworks gewohnt ist. So gibt es ständig neue „Treiber“-Bausteine für aufkommende Cloud-Infrastruktur. Momentan wird z. B. gerade intensiv an einer tieferen Integration von Spring Cloud mit Kubernetes gearbeitet. Ferner deutet sich aktuell an, dass die Bedeutung von Consul bei der Service Discovery und der Service Configuration zunimmt. Die hohe Dynamik merkt man der Dokumentation an. Hier liefert ein Blick in die Beispielapplikationen oder in den Quellcode von Spring Cloud selbst oft die besseren Antworten für Fragen abseits des normalen Trampelpfads. Im nächsten Artikel dieser Serie werden wir Zwitscher auf einem Kubernetes-Cluster zum Laufen bringen. Dr. Josef Adersberger ist technischer Geschäftsführer der QAware GmbH, einem IT-Projekthaus mit Schwerpunkt auf Cloud-native Anwendungen und Softwaresanierung. Er hält seit mehr als zehn Jahren Vorlesungen und publiziert zu Themen des Software-Engineerings, aktuell insbesondere zu Cloud Computing. Mario-Leander Reimer ist Cheftechnologe bei der QAware. Er ist Spezialist für den Entwurf und die Umsetzung von komplexen System- und Softwarearchitekturen auf Basis von Open-Source-Technologien. Als Mitglied im Java Community Process (JCP) ist sein Ziel, die Java-Plattform weiter zu verbessern und praxistaugliche Spezifikationen zu entwickeln. Links & Literatur [1] Spring-Cloud-Projekt: http://projects.spring.io/spring-cloud [2] Dr. Adersberger, Josef; Reimer, Mario-Leander; Zitzelsberger, Andreas: „Über den Wolken“, in: Java Magazin 4.2016 [3] Wolff, Eberhard: „Resilience mit Spring Cloud“, in: Java Magazin 5.2015 Listing 9 [4] Brehmer, Gerrit: „Hystrix in Action“, in: Java Magazin 12.2015 @SpringBootApplication @EnableDiscoveryClient @EnableTurbine @EnableHystrixDashboard @Controller public class ZwitscherMonitorApplication { [5] Spring Cloud Reference Documentation: http://projects.spring.io/springcloud/spring-cloud.html [6] Spring Cloud Samples: https://github.com/spring-cloud-samples [7] Spring Initializr: https://start.spring.io [8] Cloud Native Zwitscher Showcase: https://github.com/qaware/cloudnative-zwitscher @RequestMapping(path = "/", method = RequestMethod.GET) public String index() { return "forward:/hystrix"; } [9] HashiCorp Vault: https://www.vaultproject.io [10] Spring Cloud Config: http://cloud.spring.io/spring-cloud-config [11] Spring Cloud Netflix: http://cloud.spring.io/spring-cloud-netflix public static void main(String[] args) { // ... } } Listing 10 turbine: appConfig: zwitscher-service,zwitscher-board,zwitscher-edge instanceUrlSuffix: /admin/hystrix.stream instanceInsertPort: true aggregator: clusterConfig: ZWITSCHER www.JAXenter.de QAware GmbH [email protected] Aschauer Str. 32 81549 München Tel.: +49 (0) 89 23 23 15 - 0 Rheinstr. 4D 55116 Mainz Tel.: +49 (0) 6131 215 69 - 0 © Software & Support Media GmbH javamagazin 6 | 2016 7