Zuul集約マイクロサービスの使用

6661 ワード

紹介する
多くのシーンでは、外部リクエストはZuulバックエンドの複数のマイクロサービスをクエリーする必要があります.例えば、映画のチケット販売携帯アプリでは、チケット購入注文ページで「映画マイクロサービス」を検索して映画に関する情報を得るだけでなく、「ユーザーマイクロサービス」を検索して現在のユーザーの情報を得る必要があります.携帯電話側に各マイクロサービス(Zuulで転送しても)を直接要求させると、ネットワークのオーバーヘッド、トラフィックの消費、消費時間が長くて満足できない可能性があります.では、このようなシーンでは、Zuulを使用してマイクロサービスリクエストを集約することができます.携帯電話のアプリはZuulにリクエストを送信するだけです.Zuulはユーザーのマイクロサービスと映画のマイクロサービスを要求し、携帯電話のアプリにデータを整理します.
このようにして、携帯電話側は1回の要求を送信するだけで、クライアント側の開発を簡素化することができる.それだけでなく、Zuul、ユーザマイクロサービス、映画マイクロサービスは一般的に同じローカルエリアネットワークにあるため、速度が非常に速く、効率が非常に高い.
次に、上記のシーンをめぐって、コードを記述します.
この例では、RxJavaとZuulを組み合わせて、マイクロサービス要求の集約を実現する.
二新規プロジェクトmicroservice-gateway-zul-aggregation
三起動クラスの修正
package com.itmuch.cloud.study;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

@SpringBootApplication
@EnableZuulProxy
public class ZuulApplication {
  public static void main(String[] args) {
    SpringApplication.run(ZuulApplication.class, args);
  }

  @Bean
  @LoadBalanced
  public RestTemplate restTemplate() {
    return new RestTemplate();
  }
}

四エンティティクラスの作成
package com.itmuch.cloud.study;
import java.math.BigDecimal;
public class User {
  private Long id;
  private String username;
  private String name;
  private Integer age;
  private BigDecimal balance;
  public Long getId() {
    return id;
  }
  public void setId(Long id) {
    this.id = id;
  }
  public String getUsername() {
    return username;
  }
  public void setUsername(String username) {
    this.username = username;
  }
  public String getName() {
    return name;
  }
  public void setName(String name) {
    this.name = name;
  }
  public Integer getAge() {
    return age;
  }
  public void setAge(Integer age) {
    this.age = age;
  }
  public BigDecimal getBalance() {
    return balance;
  }
  public void setBalance(BigDecimal balance) {
    this.balance = balance;
  }
}

5集約サービスの作成
package com.itmuch.cloud.study;

import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import rx.Observable;

@Service
public class AggregationService {
  @Autowired
  private RestTemplate restTemplate;

  @HystrixCommand(fallbackMethod = "fallback")
  public Observable getUserById(Long id) {
    //         
    return Observable.create(observer -> {
      //         /{id}  
      User user = restTemplate.getForObject("http://microservice-provider-user/{id}", User.class, id);
      observer.onNext(user);
      observer.onCompleted();
    });
  }

  @HystrixCommand(fallbackMethod = "fallback")
  public Observable getMovieUserByUserId(Long id) {
    return Observable.create(observer -> {
      //         /user/{id}  
      User movieUser = restTemplate.getForObject("http://microservice-consumer-movie/user/{id}", User.class, id);
      observer.onNext(movieUser);
      observer.onCompleted();
    });
  }

  public User fallback(Long id) {
    User user = new User();
    user.setId(-1L);
    return user;
  }
}

六コントローラを作成し、コントローラに複数の要求を集約する
package com.itmuch.cloud.study;

import com.google.common.collect.Maps;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.async.DeferredResult;
import rx.Observable;
import rx.Observer;

import java.util.HashMap;

@RestController
public class AggregationController {
  public static final Logger LOGGER = LoggerFactory.getLogger(ZuulApplication.class);

  @Autowired
  private AggregationService aggregationService;

  @GetMapping("/aggregate/{id}")
  public DeferredResult> aggregate(@PathVariable Long id) {
    Observable> result = this.aggregateObservable(id);
    return this.toDeferredResult(result);
  }

  public Observable> aggregateObservable(Long id) {
    //         Observables       ,           
    return Observable.zip(
            this.aggregationService.getUserById(id),
            this.aggregationService.getMovieUserByUserId(id),
            (user, movieUser) -> {
              HashMap map = Maps.newHashMap();
              map.put("user", user);
              map.put("movieUser", movieUser);
              return map;
            }
    );
  }

  public DeferredResult> toDeferredResult(Observable> details) {
    DeferredResult> result = new DeferredResult<>();
    //   
    details.subscribe(new Observer>() {
      @Override
      public void onCompleted() {
        LOGGER.info("  ...");
      }

      @Override
      public void onError(Throwable throwable) {
        LOGGER.error("    ...", throwable);
      }

      @Override
      public void onNext(HashMap movieDetails) {
        result.setResult(movieDetails);
      }
    });
    return result;
  }
}

7マイクロサービス集約テスト
1 eurekaの起動
2 userマイクロサービスの開始
3 movieマイクロサービスの起動
4集約マイクロサービスの開始
5アクセスhttp://localhost:8040/aggregate/1
{"movieUser":{"id":1,"username":"account 1","name":"張三","age":20,"balance":100.00},"user":{"id":1,"username":"account 1","name":"張三","age":20,"balance":100.00}}
ユーザマイクロサービスおよび映画マイクロサービスの集約に成功したRESTful APIについて説明する
8 Hystrixフォールトトレランステスト
1 userマイクロサービスの停止
2 movieマイクロサービスの停止
3アクセスhttp://localhost:8040/aggregate/1
{"movieUser":{"id":-1,"username":null,"name":null,"age":null,"balance":null},"user":{"id":-1,"username":null,"name":null,"age":null,"balance":null}}
fallbackメソッドが正常にトリガーされ、正常にロールバックできることを示します.