【问题标题】:Hypermedia response in a microservice architecture微服务架构中的超媒体响应
【发布时间】:2017-07-14 15:50:37
【问题描述】:

我已经开始使用 Spring Cloud 和 Netflix 的项目了解更多有关此架构的旅程。

从一般的角度来看,我确实了解架构,但现在我实际上正在编写一个应用程序,对于一些可能对该架构的大方法产生重大影响的最小内容出现了怀疑。

首先,我的应用基于本教程,我认为它是有效的,因为它来自 Spring 本身:https://spring.io/blog/2015/07/14/microservices-with-spring

现在,问题是:(所有这些都使用 EUREKA)假设我有一个微服务“帐户”,它仅包含在 Spring Data REST 中用于持久性/HATEOAS,最重要的是我有一个客户端服务,它使用那些使用 RestTemplate 的端点(因为我使用的是 Ribbon 的负载均衡器)。在我看来,它是这样工作的:用户 -> 前端 -> 客户端服务 -> Spring Data REST 端点(微服务) -> 数据库。

这很好,但当我获得端点响应(来自 RestTemplate)时,它包含直接进入微服务的超媒体,并且就其本身而言,您现在可以在忽略负载均衡器的情况下自行通过微服务,这,对我来说,扼杀了它的目的。如果我喜欢 5 个微服务相互扩展,这意味着用户现在只关注应该由负载均衡器管理的 5 个微服务的广泛方式之一。

第一季度: 用户了解 API 是否可以(然后有点杀死结构的一部分)?

即使我将链接添加到 Eureka 检测到的服务并删除该微服务的当前端点,这些链接也不起作用,这意味着我正在切断超媒体链接。

第二季度: 还有另一种方法吗?通过某种代理、外部负载均衡器、dns 或类似的东西?

P.D:我不知道我说得够不够清楚。如果有什么模糊不清的地方请告诉我。

P.D.2:总结性问题:如何处理这些媒体链接?让他们成为或使用其他东西(请告诉)真正让他们“正确”?

编辑:根据以下建议,我添加了 Zuul,这似乎可以解决我的问题。现在,关于 Zuul,我应该在哪里过滤?

我的应用程序现在是这样的:account-microservice (Spring Data REST) 和 account-web-service(带有 RestTemplate 负载均衡器的客户端)。这些是 Eureka 注册的名称。

@EnabledZuulProxy 必须去哪里?在微服务内部还是在客户端内部?

我当前的配置是这个(目前,@EnabledZuulProxy 在客户端):

我的微服务:

@SpringBootApplication
@EnableEurekaClient
public class AccountServer {

    public static void main(String[] args) {
        System.setProperty("spring.config.name", "AccountServerClient");
        SpringApplication.run(AccountServer.class, args);
    }
 }

 //Config:
 spring.application.name=account-microservice
 spring.application.freemarker.enabled=false
 eureka.client.serviceUrl.defaultZone=http://localhost:1111/eureka/
 eureka.client.instance.leaseRenewalIntervalInSeconds=5

我的客户:

@SpringBootApplication
@EnableEurekaClient
@EnableZuulProxy
@EnableCircuitBreaker
public class AccountMicroService {

    public static void main(String[] args) {
        // Tell server to look for registration.properties or registration.yml
        System.setProperty("spring.config.name", "AccountMicroServiceClient");
        SpringApplication.run(AccountMicroService.class, args);
    }
 }

 //Config
 # Spring properties
 spring.application.name=account-web-service
 spring.freemarker.enabled=false
 eureka.instance.leaseRenewalIntervalInSeconds: 5
 eureka.client.serviceUrl.defaultZone=http://localhost:1111/eureka/
 zuul.routes.account-web-service.path=/accounts/**
 zuul.routes.account-web-service.serviceId=account-web-service
 zuul.routes.account-web-service.stripPrefix=false

使用 SDR 的客户端代码:

//@HystrixCommand(fallbackMethod="test")
public ResponseEntity<PagedResources<AccountResource>> findAll(Pageable pageable) throws RestClientException, URISyntaxException {

    return restTemplate.exchange(serviceUrl + "/accounts" + "?page={page}&size={size}&sort={sort}", HttpMethod.GET,
            null, new ParameterizedTypeReference<PagedResources<AccountResource>>() {
            }, pageable.getPageNumber(), pageable.getPageSize(), pageable.getSort());
}

像这样,它根本不起作用。也没有过滤。如果我更改它并在微服务中使用它,那么它会不断将指向微服务的所有内容发送到客户端,甚至是来自客户端的请求,最终会出现一个循环,然后是一个错误(超时、负载均衡器已满、电路损坏) ...) 这通常是这样的:com.netflix.zuul.exception.ZuulException: Forwarding error.

编辑 2: 我终于让 Zuul 工作并了解它的作用。现在,当我访问我的新网关应用程序时,它会将请求转发到我的微服务,生成的超媒体现在指向该网关,这正是我想要的。

这个问题最初是架构问题,然后变成了编码问题,但现在我认为这些技术已经很清楚了。

这杯茶是了解 Zuul 做什么、何时以及如何做的。 @Ryan Baxter 指南和这两篇文章:https://dzone.com/articles/microservice-architecture-with-spring-cloud-and-dohttps://spring.io/guides/gs/routing-and-filtering/ 完成这项工作的基础。我会用我所做的和我理解的来编辑这个答案。

【问题讨论】:

    标签: spring-cloud spring-data-rest microservices spring-cloud-netflix


    【解决方案1】:

    如果您使用 Spring Cloud Netflix 的 Zuul 作为负载均衡器,它将自动添加 Spring HATEOAS 将尊重的 X-Forwarded-Host 标头。当该标头存在时,HATEOAS 将使用标头中的主机值生成链接。如果您不使用 Zuul,则必须配置负载均衡器以添加该标头。

    【讨论】:

    • 我实际上开始使用 Zuul,但它似乎并没有做任何事情,超媒体和往常一样,并且就像它没有任何额外的 zuul 路由一样工作。介意指导一下吗?
    • 如果您使用RestTemplate 拨打电话,您必须添加正确的标头以便其他服务理解。
    • 介意告诉我怎么做吗?只需将标头 X-Forwarded-Host:serviceName 添加到每个 RestTemplate?
    • 好的,我有点设法让 Zuul 工作,但现在它完全被阻止了。无法直接访问微服务(一直循环到客户端服务,然后说负载均衡器已满),通过客户端服务访问时,以 Hybrix 运行时异常结束:超时和回退失败。
    • 我不确定您所说的 Zuul 是“被阻止”是什么意思。除非您提供更多详细信息,否则我们无法提供真正的帮助。重现问题的示例总是有帮助的。
    【解决方案2】:

    好的,我所做的只是使用 Zuul(正如@Ryan 建议的那样)。问题是,最初,我有点没有得到它的方法。这是一个很小的架构问题,在将@Ryan 的建议与我添加到问题底部的两篇文章进行内部化之后,最终解决了它们(希望如此)。

    首先:现在我的项目正在使用 Zuul(通过创建网关应用程序,正如我的两个链接所建议的那样)并且在其类路径中同时包含 Hybrix 和 Ribbon,Zuul 必须将它们全部连接在一起并变成带电路的多功能代理网关断路器和负载平衡特性。

    第二:我摆脱了那个 rest 模板负载均衡器,因为:a)获取微服务超媒体的响应,因为我没有发送端口转发标头,这几乎使 Zuul 的代理功能无效; b) 因为 Zuul 充当网关代理负载平衡器,所以我认为再次使用带有 rest 模板的功能区有点样板。

    现在,我的应用是这样的:user -> {[Zuul's gateway -> Spring Data REST microservice (forwarded by Zuul)]

    我将采用@Ryan 的答案作为答案,因为他准确地指出了正在发生的事情以及我最终为解决我的问题所做的事情。不过,我也在回答,因为我认为进一步解释我最终做了什么可能对另一个 SO 用户有所帮助。

    如果我的解决方案有问题,请发表评论。

    【讨论】:

      猜你喜欢
      • 2019-03-02
      • 2015-12-26
      • 2021-11-02
      • 2017-03-19
      • 2018-05-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多