dzone-rc234-microservicesinjava

Please download to get full document.

View again

of 6
407 views
PDF
All materials on our website are shared by users. If you have any questions about copyright issues, please report us to resolve them. We are always happy to assist you.
Document Description
java
Document Share
Documents Related
Document Tags
Document Transcript
  SURVIVAL IS NOT MANDATORY It is not necessary to change. Survival is not mandatory.   -W. Edwards Deming  It’s not controversial to suggest that startups iterate and innovate faster than larger organizations, but what about the larger organizations — the Netflixes, the Alibabas, the Amazons, etc.? How do they innovate so quickly? The secret to their agility lays in the size of their teams. These organizations deploy small teams that in turn build small, singly focused, independently deployable, microservices. Microservices are easier to build because the implementation choices don’t bleed over to other functionality, they minimize the scope and impact of a given change, they are easier to test; and they are easier to scale. Microservices give us a lot of benefits, but they also introduce complexities related to incepting new services and addressing the dynamics of distribution. MOVING BEYOND THE WIKI PAGE: “500 EASY STEPS TO PRODUCTION”  Microservices are APIs. How quickly can you stand up a new service? Microframeworks like Spring Boot, Grails (which builds on Spring Boot), JHipster (which builds on Spring Boot), DropWizard, Lagom, and WildFly Swarm are, at a minimum, optimized for quickly standing up REST services with a minimum of fuss. Some of these options go further and address all production requirements including security, observability and monitoring. Cloud computing technologies like Cloud Foundry, OpenShift, Heroku, and Google App Engine provide higher-level abstractions for managing the lifecycle of software. At both layers, stronger opinions result in consistency which results in velocity. These technologies let organizations move beyond the burdensome internal Wiki page, “500 Easy Steps to Production.” SURVIVAL IS NOT MANDATORY  One thing is common across all organizations, no matter what their technology stack: when the pager goes off,  somebody   is roused and sat in front of a computer in order to stop the system’s bleeding. Root cause analysis will come later; the priority is to restore service. The more we can do upfront to support remediation in those waning and critical seconds, minutes, and hours after a production outage, the better.Services should expose their own health endpoints, metadata about the service itself, logs, threadumps, configuration and environment information, and whatever else could be operationally useful. Services should also track the progression of both business and operational metrics. Metrics can be overwhelming, and so it makes sense to publish collected metrics to time-series databases that support analytics and visualization. There are many time-series databases like Graphite, Atlas, InfluxDB, and OpenTSDB. Metrics are keys and values over time. Spring Boot suppots the collection of metrics, and can delegate to projects like Dropwizard Metrics and Micrometer.io to publish them. @SpringBootApplicationpublic class DemoApplication { public static void main(String args[]) { SpringApplication.run(DemoApplication.class, args); } @Bean  GraphiteReporter graphite(@Value(“${graphite.prex}”) String prex, @Value(“${graphite.url}”) URL url, @Value(“${graphite.port}”) int port,  MetricRegistry registry) { GraphiteReporter reporter = GraphiteReporter.forRegistry(registry)  .prexedWith(prex)  .build(new Graphite(url.getHost(), port));  reporter.start(1, TimeUnit.SECONDS);  return reporter; }} @RestControllerclass FulllmentRestController {  @Autowired  private CounterService ok, well, as long as shes able to get a taxi or a bte tocounterService; @RequestMapping(“/customers/{customerId}/fulllment”) Fulllment fulll(@PathVariable long customerId) {  // ..  counterService.increment(“meter.customers-fullled”);  // .. }} 234   Survival Is Not Mandatory   Moving Beyond the Wiki Page: “500 Easy Steps to Production”   You Can’t Fix What You Can’t Measure   Centralized Configuration   Service Registration and Discovery CONTENTS DZONE.COM  |  © DZONE, INC.VISIT DZONE.COM/REFCARDZ FOR MORE! Microservices in Java  Compared to Amazon Web Services, Oracle Cloud is ... FSTER FSTER LOWER COST Transactions Analytics Compute 35x 105x �33% Better than Better than Less than Amazon Aurora Amazon Redshif Amazon EC2 Experience a superior solution with $300 in free Oracle Cloud credits. Start Today for Free  Log multiplexers like Logstash or Cloud Foundry’s Loggregator funnel the logs from application instances and ship them to downstream log analysis tools like ElasticSearch, Splunk, or PaperTrail. CENTRALIZED CONFIGURATION  The Twelve-Factor App methodology provides a set of guidelines for building applications with good, clean cloud hygiene. One tenet is that environment-specific configuration should live external to the application itself. It might live in environment variables, -D  arguments, externalized .properties , .yml  files, or any other place, so long as the application code itself need not be recompiled. DropWizard, Spring Boot, Apache Commons Configuration, and others support this foundational requirement. However, this approach fails a few key use cases: how do you change configuration centrally and propagate those changes? How do you support symmetric encryption and decryption of things like connection credentials? How do you support feature flags which toggle configuration values at runtime, without restarting the process?Spring Cloud provides the Spring Cloud Config Server (and a client) which stands up a REST API in front of a version-controlled repository of configuration files, and Spring Cloud provides support for using Apache Zookeeper and HashiCorp Consul as configuration sources. Spring Cloud provides various clients for all of these so that all properties—whether they come from the Config Server, Consul, a -D argument, or an environment variable—work the same way for a Spring client. Netflix provides a solution called Archaius that acts as a client to a pollable configuration source. This is a bit too low- level for many organizations and lacks a supported, open-source configuration source counterpart, but Spring Cloud bridges the Archaius properties with Spring’s, too. THE CONFIG SERVER # application.properties spring.cloud.cong.server.git.uri=https://github.com/joshlong/my-cong.git server.port=8888 @EnableCongServer @SpringBootApplication public class CongServiceApplication {  public static void main(String[] args) {  SpringApplication.run(CongServiceApplication. class, args); }} THE CONFIG CLIENT # application.properties spring.cloud.cong.uri=http://localhost:8888 spring.application.name=message-client # will read https://github.com/joshlong/my-cong/message- client.properties@SpringBootApplication public class CongClientApplication {  public static void main(String[] args) {  SpringApplication.run(CongClientApplication. class, args); }} // supports dynamic re-conguration:// curl -d{} http://localhost:8000/refresh@RestController   @RefreshScope class MessageRestController { @Value(“${message}”)  private String message;  @RequestMapping(“/message”)  String read() { return this.message; }} SERVICE REGISTRATION AND DISCOVERY   DNS is sometimes a poor fit for intra-service communication. DNS benefits from layers of caching and time-to-liveness that work against services in a dynamic cloud environment. In most cloud environments, DNS resolution requires a trip out of the platform to the router and then back again, introducing latency. DNS doesn’t provide a way to answer the question: is the service I am trying to call still alive and responding? It can only tell us where something is supposed to be. A request to such a fallen service will block until the service responds, unless the client specifies a timeout (which it should!). DNS is often paired with load balancers, but third-party load balancers are not sophisticated things: they may support round-robin load balancing, or even availability zone-aware load balancing, but may not be able to accomodate business-logic-specific routing, like routing a request with an OAuth token to a specific node, or routing requests to nodes collocated with data, etc. It’s important to decouple the client from the location of the service, but DNS might be a poor fit. A little bit of indirection is required. A service registry provides that indirection.A service registry is a phonebook, letting clients look up services by their logical names. There are many such service registries out there. Netflix’s Eureka, Apache Zookeeper, and HashiCorp Consul are three good examples. Spring Cloud’s DiscoveryClient abstraction provides a convenient client-side API for working with service registries. Here, we inject the DiscoveryClient to interrogate the registered services: @Autowired public void enumerateServiceInstances(DiscoveryClient client){  client.getInstances(“reservation-service”) .forEach( si -> System.out.println( si.getHost() + “:” + si.getPort() )); } CLIENT-SIDE LOAD BALANCING A big benefit of using a service registry is client-side load balancing. Client-side load balancing lets the client pick from among the registered instances of a given service—if there are 10 or a thousand they’re all discovered through the registry—and then choose from among the candidate instances which one to route requests to. The client can programmatically decide based on whatever criteria it likes—capacity, least-recently used, cloud-provider availability-zone awareness, multi-tenancy, etc.—to which node a request should be sent. Netflix provides a great client-side load balancer called Ribbon that Spring Cloud integrates with. Ribbon is automatically in play at all layers of the framework, whether you’re using the RestTemplate , the reactive WebFlux WebClient , declarative REST clients powered by Netflix’s Feign, the Zuul microproxy or Spring Cloud Gateway. 3 DZONE.COM  |  © DZONE, INC. MICROSERVICES IN JAVA Code Continued on following column  @EnableDiscoveryClient @SpringBootApplication public class ReservationClientApplication {  @Bean  @LoadBalanced // lets us use service registry service IDs as hosts RestTemplate restTemplate() { return new RestTemplate(); } public static void main(String[] args) { SpringApplication. run(ReservationClientApplication.class, args);  }} @RestControllerclass ApiClientRestController {  @Autowired private RestTemplate restTemplate;  @RequestMapping(method = RequestMethod.GET, value = “/reservations/names”) public Collection<String> names() { ResponseEntity<JsonNode> responseEntity = restTemplate.exchange(“http://reservation-service/reservations”, HttpMethod.GET, null, JsonNode.class);  // ... }} EDGE SERVICES: API GATEWAYS AND API ADAPTERS  Client-side load-balancing works for intra-service communication, usually behind a firewall. External clients—iPhones, HTML5 clients, Android clients, etc.—will need DNS and will have client-specific security, payload, and protocol requirements. An edge service is the first port of call for requests coming from these external clients. You address client-specific concerns at the edge service and then forward the requests to downstream services. An API gateway (sometimes called a backend for a frontend) supports declarative, cross-cutting concerns like rate limiting, authentication, compression, and routing. API adapters have more insight into the semantics of the downstream services; they might expose a synthetic view of the responses of downstream services, combining, filtering, or enriching them.There are many API gateways, some hosted and some not, like Apigee, WS02, Nginx, Kong, Netflix Zuul, and Spring Cloud Gateway. I like to think of Netflix Zuul and Spring Cloud Gateway as microproxies. They’re small and embeddable. API Gateways need to be as fast as possible and able to absorb as much incoming traffic as possible. Here, non-blocking, reactive APIs (using technologies like Netflix’s RXJava 2, Spring WebFlux, RedHat’s Vert.x and Lightbend’s Akka Streams) are a very good choice. @EnableDiscoveryClient @SpringBootApplication public class EdgeServiceApplication { // congure reactive, Ribbon aware `WebClient`  @Bean  WebClient client(LoadBalancerExchangeFilterFunction lb) {  return WebClient.builder().lter(lb).build();  }  // API Adapter using reactive Spring WebFlux WebClient @Bean  RouterFunction<?> endpoints(WebClient client) { List<String> badCars = Arrays.asList(“Pinto”, “Gremlin”); return route(GET(“/good-cars”), req -> { Publisher<Car> beers = client  .get() .uri(“http://car-catalog-service/cars”)  .retrieve()  .bodyToFlux(Car.class) .lter(x -> badCars.contains(x.getName())); Publisher<Car> circuit = HystrixCommands  .from(beers)  .commandName(“beers”) .fallback(Flux.empty())  .eager() .build();  return ServerResponse.ok().body(circuit, Car. class); }); }  // API gateway with Spring Cloud Gateway  @Bean  RouteLocator gateway() {  return Routes.locator() // custom paths to a load-balanced service  .route(“path_route”) .predicate(path(“/edge-results”)) .uri(“lb://my-service/actual-results”)  // rewrites  .route(“rewrite_route”) .predicate(host(“*.rewrite.org”)) .lter(rewritePath(“/foo/(?<segment>.*)”, “/${segment}”)) .uri(“http://httpbin.org:80”) // circuit breaker .route(“hystrix_route”) .predicate(host(“*.hystrix.org”)) .lter(hystrix(“slowcmd”)) .uri(“http://httpbin.org:80”)  .build(); } public static void main(String[] args) {  SpringApplication.run(EdgeServiceApplication. class, args); }} CLUSTERING PRIMITIVES  In a complex distributed system, there are many actors with many roles to play. Cluster coordination and cluster consensus is one of the most difficult problems to solve. How do you handle leadership election, active/passive handoff, or global locks? Thankfully, many technologies provide the primitives required to support this sort of coordination, including Apache Zookeeper, Redis, and Hazelcast. Spring Integration supports a clean integration with these kinds of technologies. In the following example, we’ve configured a component to change its state whenever OnGrantedEvent  or an OnRevokedEvent  is emitted, which it will do when the underlying coordination technology promotes and demotes a leader node. @Componentclass LeadershipApplicationListener { @EventListener(OnGrantedEvent.class) public void leadershipGranted(OnGrantedEvent evt){  // .. }  @EventListener(OnRevokedEvent.class) public void leadershipRevoked(OnRevokedEvent evt){  // .. }} MESSAGING, CQRS, AND STREAM PROCESSING  When you move into the world of microservices, state synchronization 4 DZONE.COM  |  © DZONE, INC. MICROSERVICES IN JAVA Code Continued on following column
We Need Your Support
Thank you for visiting our website and your interest in our free products and services. We are nonprofit website to share and download documents. To the running of this website, we need your help to support us.

Thanks to everyone for your continued support.

No, Thanks