精华内容
下载资源
问答
  • Babex能够让你在RabbitMQ的帮助下快速实现链式微服务
  • 第二篇描述了采用微服务架构应用客户端之间如何采用APIGateway方式进行通信。在这篇文章中,我们将讨论系统服务之间如何通信。在单体式应用中,各个模块之间的调用是通过编程语言级别的方法或者函数来实现的。但是一...
  • 微服务之间通信的选择之gRPC

    千次阅读 2019-09-28 21:04:39
    效率至关重要的轻量级微服务。 需要多种语言用于开发的 Polyglot 系统。 需要处理流式处理请求或响应的点对点实时服务。 以上摘自 Microsoft Document .NET中gRPC的简单使用 ASP.NET Core中 gRPC Server...

    介绍

    gRPC是一种与语言无关的高性能远程过程调用 (RPC) 框架。

    gRPC 的主要优点是:

    • 现代高性能轻量级 RPC 框架。
    • 协定优先 API 开发,默认使用协议缓冲区,允许与语言无关的实现。
    • 可用于多种语言的工具,以生成强类型服务器和客户端。
    • 支持客户端、服务器和双向流式处理调用。
    • 使用 Protobuf 二进制序列化减少对网络的使用。

    这些优点使 gRPC 适用于:

    • 效率至关重要的轻量级微服务。
    • 需要多种语言用于开发的 Polyglot 系统。
    • 需要处理流式处理请求或响应的点对点实时服务。

    以上摘自Microsoft Document

    .NET中gRPC的简单使用

    ASP.NET Core中 gRPC Server 配置:

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddGrpc();
    }
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        app.UseEndpoints(endpoints =>
        {
            endpoints.MapGrpcService<GreeterService>();
        });
    }
    

    ASP.NET Core中 gRPC Server 服务类:

    public class GreeterService : Greeter.GreeterBase
    {
        private readonly ILogger<GreeterService> _logger;
        public GreeterService(ILogger<GreeterService> logger)
        {
            _logger = logger;
        }
    
        public override Task<HelloReply> SayHello(HelloRequest request, ServerCallContext context)
        {
            return Task.FromResult(new HelloReply
            {
                Message = "Hello " + request.Name
            });
        }
    }
    

    greet.proto

    syntax = "proto3";
    
    option csharp_namespace = "GrpcServer";
    
    package Greet;
    
    // The greeting service definition.
    service Greeter {
      // Sends a greeting
      rpc SayHello (HelloRequest) returns (HelloReply);
    }
    
    // The request message containing the user's name.
    message HelloRequest {
      string name = 1;
    }
    
    // The response message containing the greetings.
    message HelloReply {
      string message = 1;
    }
    
    

    有关 protobuf 文件语法的详细信息,参考官方文档(protobuf)

    客户端:
    添加对应的包,复制服务端的proto文件并配置:

      <ItemGroup>
        <PackageReference Include="Google.Protobuf" Version="3.9.2" />
        <PackageReference Include="Grpc.Net.Client" Version="2.23.2" />
        <PackageReference Include="Grpc.Tools" Version="2.24.0">
          <PrivateAssets>all</PrivateAssets>
          <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
        </PackageReference>
        <Protobuf Include="Protos\greet.proto" GrpcServices="Client" />
      </ItemGroup>
    

    直接生成客户端项目即可根据proto生成对应的类文件。
    然后通过如下代码进行调用:

    static async Task Main(string[] args)
    {
        var channel = GrpcChannel.ForAddress("https://localhost:5001");
        var client = new Greeter.GreeterClient(channel);
        var reply = await client.SayHelloAsync(new HelloRequest { Name = "张三" });
        Console.WriteLine(reply.Message);
    }
    

    运行程序:
    在这里插入图片描述

    proto中标量值类型与C#对应关系

    .proto TypeC# TypeNotes
    doubledouble
    floatfloat
    int32intUses variable-length encoding. Inefficient for encoding negative numbers – if your field is likely to have negative values, use sint32 instead.
    int64longUses variable-length encoding. Inefficient for encoding negative numbers – if your field is likely to have negative values, use sint64 instead.
    uint32uintUses variable-length encoding.
    uint64ulongUses variable-length encoding.
    sint32intUses variable-length encoding. Signed int value. These more efficiently encode negative numbers than regular int32s.
    sint64longUses variable-length encoding. Signed int value. These more efficiently encode negative numbers than regular int64s.
    fixed32uintAlways four bytes. More efficient than uint32 if values are often greater than 2 28 2^{28} 228.
    fixed64ulongAlways eight bytes. More efficient than uint64 if values are often greater than 2 56 2^{56} 256 .
    sfixed32intAlways four bytes.
    sfixed64longAlways eight bytes.
    boolbool
    stringstringA string must always contain UTF-8 encoded or 7-bit ASCII text, and cannot be longer than 2 32 2^{32} 232.
    bytesByteStringMay contain any arbitrary sequence of bytes no longer than 2 32 2^{32} 232.
    展开全文
  • 微服务之间通信的方式

    万次阅读 2018-09-07 15:27:03
    SpringCloud中服务之间的两种调用RESTful接口通信的方式: RestTemplate Feign RestTemplate是一个Http客户端,类似于HTTPClient,org但比HTTPClient更简单。我们通过RestTemplate来简单演示一下服务之间的调用,...

    RestTemplate的三种使用方式

    SpringCloud中服务之间的两种调用RESTful接口通信的方式:

    1. RestTemplate
    2. Feign

    RestTemplate是一个Http客户端,类似于HTTPClient,org但比HTTPClient更简单。我们通过RestTemplate来简单演示一下服务之间的调用,我们使用两个服务来做演示。一个商品服务,一个订单服务。首先创建一个商品服务工程:
    微服务之间的通信的方式
    微服务之间的通信的方式

    选择相应的依赖:
    微服务之间的通信的方式

    项目创建完成后,编辑配置文件,需要配置服务的名称以及服务注册中心的地址:

    spring:
      application:
        name: product
    
    eureka:
      client:
        service-url:
          defaultZone: http://localhost:8761/eureka/
      instance:
        prefer-ip-address: true

    注:如果对eureka还不太清楚的话,可以参考我的另一篇关于eureka的文章:Spring Cloud Eureka-服务注册与发现

    不要忘了在启动类中,加上@EnableEurekaClient注解:

    package org.zero.example.product;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
    
    @SpringBootApplication
    @EnableEurekaClient
    public class ProductApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(ProductApplication.class, args);
        }
    }

    接着创建一个controller类,用于模拟商品列表接口,提供给订单服务调用。代码如下:

    package org.zero.example.product.controller;
    
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * @program: product
     * @description: product demo
     * @author: 01
     * @create: 2018-09-06 22:09
     **/
    @RestController
    @RequestMapping("/product")
    public class ProductController {
    
        /**
         * 模拟商品列表接口
         *
         * @return product list
         */
        @GetMapping("/list")
        public List<String> list() {
            List<String> productList = new ArrayList<>();
            productList.add("肥皂");
            productList.add("可乐");
    
            return productList;
        }
    }

    然后启动项目,启动完成后,此时,在eureka的信息面板上应该可以看到product注册上去了,如下:
    微服务之间的通信的方式


    商品服务准备好后,使用同样的步骤创建order项目,这里就不再赘述了。配置文件中除了服务名称需为order,其他的配置项和product一样。因为8080已经被product服务占用了,所以还需要手动设置一下项目的端口号:
    微服务之间的通信的方式

    新建一个ClientController类,我们来看看RestTemplate的第一种使用方式,代码如下:

    package org.zero.example.order.controller;
    
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    import org.springframework.web.client.RestTemplate;
    
    import java.util.List;
    
    /**
     * @program: order
     * @description: order demo
     * @author: 01
     * @create: 2018-09-06 22:24
     **/
    @RestController
    @RequestMapping("/order")
    public class OrderController {
    
        @GetMapping("/info")
        public List info() {
            // 1.第一种方式,直接使用。缺点:需要指定url地址,不灵活,也无法适应多个地址
            RestTemplate restTemplate = new RestTemplate();
            return restTemplate.getForObject("http://localhost:8080/product/list", List.class);
        }
    }

    写完后启动项目,可以看到order服务也注册到eureka上了:
    微服务之间的通信的方式

    接口测试结果如下,可以看到成功调用了商品服务的接口:
    微服务之间的通信的方式


    然后是RestTemplate的第二种使用方式,代码如下:

    ...
    
    import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
    
    @RestController
    @RequestMapping("/order")
    public class OrderController {
    
        @Autowired
        private LoadBalancerClient loadBalancerClient;
    
        @GetMapping("/info")
        public List info() {
            // 2.第二种方式,借助LoadBalancerClient获取服务实例,缺点:需要拼接url依旧不灵活
            RestTemplate restTemplate = new RestTemplate();
            // 参数传的是服务注册的id
            ServiceInstance serviceInstance = loadBalancerClient.choose("PRODUCT");
            String url = String.format("http://%s:%s", serviceInstance.getHost(), serviceInstance.getPort() + "/product/list");
    
            return restTemplate.getForObject(url, List.class);
        }
    }

    接着是RestTemplate的第三种使用方式,这种方式下我们需要先创建一个配置类,代码如下:

    package org.zero.example.order.config;
    
    import org.springframework.cloud.client.loadbalancer.LoadBalanced;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.client.RestTemplate;
    
    /**
     * @program: order
     * @description: RestTemplate Config
     * @author: 01
     * @create: 2018-09-06 22:47
     **/
    @Configuration
    public class RestTemplateConfig {
    
        @Bean
        @LoadBalanced
        public RestTemplate restTemplate(){
            return new RestTemplate();
        }
    }

    然后在controller中注入使用,这种方式虽然最简洁,其实本质上还是第二种方式:

    ...
    @RestController
    @RequestMapping("/order")
    public class OrderController {
    
        @Autowired
        private RestTemplate restTemplate;
    
        @GetMapping("/info")
        public List info() {
            // 3.第三种方式,利用@LoadBalanced注解,可在restTemplate里使用应用名称进行调用
            return restTemplate.getForObject("http://PRODUCT/product/list", List.class);
        }
    }

    负载均衡器:Ribbon

    eureka是客户端发现机制的,所以使用的是客户端负载均衡器,所谓客户端负载均衡,也就是说负载的策略在客户端完成,俗称软负载。如果我们的商品服务部署在多个节点上的话,当使用Feign进行服务调用的时候,默认会使用Ribbon来做负载均衡。当然使用RestTemplate的时候也是可以结合Ribbon做负载均衡的,例如上一小节中演示的第二、三种使用RestTemplate的方式就是结合了Ribbon。

    Ribbon是Netflix发布的负载均衡器,是一种客户端负载均衡器,运行在客户端上,它有助于控制HTTP和TCP的客户端的行为。为Ribbon配置服务提供者地址后,Ribbon就可基于某种负载均衡算法,自动地帮助服务消费者去请求。Ribbon默认为我们提供了很多负载均衡算法,例如轮询、随机等。当然,我们也可为Ribbon实现自定义的负载均衡算法。

    我们在配置文件中可以自定义负载均衡策略,如下:

    PRODUCT:  # 服务的名称
      ribbon:  # 负载均衡器
        NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule  # 规则完整的类名,这里使用的是随机

    注:如非必须,一般使用默认的轮询策略即可

    Ribbon特性:

    • 服务发现
    • 服务选择规则
    • 服务监听
    • ServerList,获取可用服务列表
    • IRule,选择最终调用,即负载策略
    • ServerListFilter,过滤不可用地址

    在Spring Cloud中,当Ribbon与Eureka配合使用时,Ribbon可自动从Eureka Server获取服务提供者地址列表,并基于负载均衡算法,请求其中一个服务提供者实例。下图展示了Ribbon与Eureka配合使用时的架构:
    微服务之间的通信的方式


    Feign的使用

    Feign是从Netflix中分离出来的轻量级项目,是一个声明式的REST客户端,它的出现使得我们在服务中编写REST客户端变得更加容易。利用 Feign 可以创建一个接口并对它进行注解,该接口就会具有可插拔的注解支持包括Feign注解与JAX-RS注解,Feign还支持可插拔的编码器与×××。Feign 灵感来源于Retrofit、JAXRS-2.0和WebSocket,Feign 最初是为了降低统一绑定 Denominator 到 HTTP API 的复杂度,不区分是否支持 Restful。

    Spring Cloud 增加了对 Spring MVC的注解,Spring Web 默认使用了HttpMessageConverters, Spring Cloud 集成 Ribbon 和 Eureka 提供的负载均衡的HTTP客户端 Feign。

    Feign特性:

    • 声明式REST客户端(伪RPC)
    • 采用了基于接口的注解
    • 同样使用ribbon做负载均衡器

    接下来我们尝试一下使用Feign编写REST客户端,实现订单服务调用商品服务接口,看看Feign到底有多方便。在商品和订单服务的项目中,都加入Feign的依赖,pom.xml文件配置的依赖如下:

    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-openfeign</artifactId>
    </dependency>

    注:若出现使用阿里云的仓库地址不能下载到该依赖的话,可以尝试使用maven中央仓库的地址进行下载

    首先到商品服务工程中,新建一个client包。本来应该是新建一个Client模块的,但是为了方便演示,我就直接用包了。在client包下新建一个 ProductClinet 接口,编写代码如下:

    package org.zero.example.product.client;
    
    import org.springframework.cloud.openfeign.FeignClient;
    import org.springframework.web.bind.annotation.GetMapping;
    
    import java.util.List;
    
    @Component
    // 此注解用于声明一个Feign客户端,name属性指定服务的名称
    @FeignClient(name = "PRODUCT")
    public interface ProductClinet {
    
        /**
         * 商品列表接口,注意这里的uri要写全
         *
         * @return Product List
         */
        @GetMapping("/product/list")
        List<String> list();
    }

    我们在使用RestTemplate的时候,都是在订单服务上编写接口调用相关代码的,但是为什么使用Feign就在商品服务上去写这个代码呢?这是因为使用Feign的时候,只需要通过注解就能在接口上声明客户端,当我们在订单服务里面使用的时候,注入这个ProductClinet接口调用相应的方法即可实现商品服务接口的调用。而这些接口属于商品服务对外暴露的接口,由于职责的关系,所以都应该由商品服务去维护,不应该写在订单服务里。

    编写好ProductClinet接口的代码后,使用如下命令将这个项目安装到本地的maven仓库中:

    mvn clean -Dmaven.test.skip=true install

    接着到订单服务的工程中,加入商品服务的依赖,如下:

    <dependency>
        <groupId>org.zero.example</groupId>
        <artifactId>product</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </dependency>

    然后在启动类中,加上@EnableFeignClients注解表示开启 Feign 客户端以及配置client包的路径,如下:

    package org.zero.example.order;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
    import org.springframework.cloud.openfeign.EnableFeignClients;
    
    @EnableEurekaClient
    @SpringBootApplication
    @EnableFeignClients(basePackages = "org.zero.example.product.client")
    public class OrderApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(OrderApplication.class, args);
        }
    }

    修改 OrderController 代码如下:

    ...
    
    import org.zero.example.product.client.ProductClinet;
    
    @RestController
    @RequestMapping("/order")
    public class OrderController {
    
        @Autowired
        private ProductClinet productClinet;
    
        @GetMapping("/info")
        public List info() {
            return productClinet.list();
        }
    }

    重启这两个项目,测试接口如下:
    微服务之间的通信的方式

    转载于:https://blog.51cto.com/zero01/2171663

    展开全文
  • 微服务之间是如何独立通信的?

    千次阅读 2019-08-12 15:58:37
    微服务通信机制  系统之间各个服务是可以独立部署,是松耦合的。每个服务仅关注于完成一个任务并很好的完成该任务。 围绕业务能力组织服务,自动化部署,智能端点,对语言和数据的去中心话控制。 将组建定义为可被...

    一、微服务通信机制
      系统之间各个服务是可以独立部署,是松耦合的。每个服务仅关注于完成一个任务并很好的完成该任务。
    围绕业务能力组织服务,自动化部署,智能端点,对语言和数据的去中心话控制。

    • 将组建定义为可被独立替换和升级的软件单元。
    • 以业务能力为出发点组织服务的策略。
    • 倡导谁开发谁运营的开发运维一体化方法。
    • RestFul Http协议是微服务架构中最常用的通讯机制。
    • 每个微服务可以考虑采用最佳微服务完成(如不同的编程语言)。
    • 允许不同的微服务采用不同的数据持久化技术。
    • 微服务非常注重建立架构和业务相关指标的实时监控和日志机制,必须考虑每个服务的失败容错机制。
    • 注重快速更新,因此系统会随着时间不断变化和演进。可替代性模块化设计。

    二、微服务通信方式

      同步:RPC ,REST等。
      异步:消息队列,要考虑消息的可靠传输、高性能,以及编程模型的变化等。
    

    RestTemplate通信的三种方式:

    第一种调用方式

      RestTemplate restTemplate = new RestTemplate();
      String data = restTemplate.getForObject("http://localhost:8773/hi?name=ceshi",String.class);
      ResposeResult responseFinishEntity = restTemplate.postForObject(urlNameString, inOrderVO, ResposeResult.class);
    

    第二种调用方式:

      @Autowired
      private LoadBalancerClient loadBalancerClient;
      //第二种调用方式
      RestTemplate restTemplate = new RestTemplate();
      ServiceInstance serviceInstance = loadBalancerClient.choose("provider");
      String url = String.format("http://%s:%s",serviceInstance.getHost(),serviceInstance.getPort());
      String data = restTemplate.getForObject(url,String.class);
    

    第三种调用方式(使用server_id):

      RestTemplate restTemplate = new RestTemplate();
      String data =  restTemplate.getForObject("http://service-provider/hi?name=" + name, String.class);
    

    负载均衡:在启动类中加入RestTemplate中bean和LoadBalanced注解

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

    再通过注解直接使用restTemplate

      @Autowired
      RestTemplate restTemplate;
    

    配置负载均衡规则。默认是轮询规则

    service-provider.ribbon.NFLoadBalancerRuleClassName=com.netflix.loadbalancer.RandomRule
    

    三、消息队列中间件如何选型?

    1.协议:AMQP、STOMP、MQTT、私有协议等。
    2.消息是否需要持久化。
    3.吞吐量。
    4.高可用支持,是否单点。
    5.分布式扩展能力。
    6.消息堆积能力和重放能力。
    7.开发便捷,易于维护。
    8.社区成熟度。
    

    RabbitMQ是一个实现了AMQP(高级消息队列协议)协议的消息队列中间件。RabbitMQ支持其中的最多一次和最少一次两种。网易蜂巢平台的服务架构,服务间通过RabbitMQ实现通信。

    文章来源:https://blog.csdn.net/qyj19920704/article/details/83927432
    https://blog.csdn.net/u012632466/article/details/90236984

    展开全文
  • 微服务之间通信

    千次阅读 2020-04-08 17:55:42
    在monolithic单体应用程序中,不同的组件之间通过编程语言级别的方法或函数调用相互调用。 相反,基于微服务的应用程序是在多台计算机上运行的分布式系统。 每个服务实例通常是一个进程。 因此,如下图所示,服务...

    在monolithic单体应用程序中,不同的组件之间通过编程语言级别的方法或函数调用相互调用。 相反,基于微服务的应用程序是在多台计算机上运行的分布式系统。 每个服务实例通常是一个进程。 因此,如下图所示,服务必须使用进程间通信(IPC)机制进行交互。

    In a microservices application, the services need an inter-process communication (IPC) mechanism (whereas modules in a monolith can call routines)

    交互方式

    为服务选择IPC机制时,首先考虑服务如何交互是必要的。 客户端⇔服务交互方式多种多样。 它们可以沿两个维度进行分类。 第一个维度是互动是一对一还是一对多:

    • 一对一–每个客户端请求仅由一个服务实例处理。
    • 一对多–每个请求由多个服务实例处理。

    第二个维度是交互是同步还是异步:

    • 同步–客户端期望服务及时响应,甚至在等待时可能会阻塞。
    • 异步-客户端在等待响应时不会阻塞,并且响应(如果有的话)不一定会立即发送。

    下表显示了各种交互样式。

    One-to-OneOne-to-Many
    SynchronousRequest/response — 
    AsynchronousNotificationPublish/subscribe
    Request/async responsePublish/async responses

    存在以下类型的一对一交互:

    • Request/response–客户端向服务发出请求并等待响应。客户希望响应能够及时到达。在基于线程的应用程序中,发出请求的线程甚至可能在等待时阻塞。
    • Notification (也称为单向one‑way 请求)–客户端向服务发送请求,但不希望或未发送答复。
    • Request/async response–客户端将请求发送到服务,该服务以异步方式答复。客户端在等待时不会阻塞,并假设响应可能不会在一段时间内到达。

    一对多互动有以下几种:

    • Publish/subscribe–客户端发布通知消息,该消息由零个或更多感兴趣的服务使用。
    • Publish/async responses –客户端发布请求消息,然后等待一定时间以等待感兴趣的服务的响应。

    每个服务通常使用这些交互样式的组合。对于某些服务,单个IPC机制就足够了。其他服务可能需要结合使用IPC机制。下图显示了当用户请求一个旅行时,出租车服务应用程序中的服务如何交互。

    A microservices-based taxi-hailing app can use a variety of communication methods: notification, request-response, publish-subscribe

    服务使用notifications, request/response, 和publish/subscribe的组合。 例如,乘客的智能手机向行程管理服务发送通知以请求接机。 行程管理服务通过使用请求/响应调用旅客服务来验证旅客的帐户是否处于活动状态。 然后,行程管理服务创建行程,并使用发布/订阅来通知其他服务,包括分派器,后者查找可用的驱动程序。

    现在我们已经研究了交互样式,让我们看一下如何定义API。

    定义 API

    服务的API是服务与其客户之间的contract。 无论选择哪种IPC机制,使用某种接口定义语言(IDL)精确定义服务的API都是很重要的。 使用API优先方法定义服务甚至有很好的论据。 您可以通过编写接口定义并与客户开发人员一起审查来开始开发服务。 只有在对API定义进行迭代之后,您才能实现服务。 预先进行此设计会增加您建立满足其客户需求的服务的机会。

    正如您将在本文后面看到的那样,API定义的性质取决于您所使用的IPC机制。 如果使用messaging消息服务,则API包含消息通道和消息类型。 如果使用的是HTTP,则API由URL以及请求和响应格式组成。

    调用API

    服务的API始终会随着时间而变化。在整体应用程序中,更改API和更新所有调用程序通常很简单。在基于微服务的应用程序中,即使API的所有使用者都是同一应用程序中的其他服务,也要困难得多。通常,您无法强制所有客户端与服务同步升级。另外,您可能会逐步部署服务的新版本,以便服务的旧版本和新版本将同时运行。制定处理这些问题的策略很重要。

    处理API更改的方式取决于更改的大小。某些更改是次要的,并且与以前的版本向后兼容。例如,您可以将属性添加到请求或响应。设计客户和服务以使其遵循健壮性原则是有意义的。使用较旧API的客户端应继续使用新版本的服务。该服务为缺少的请求属性提供默认值,客户端忽略任何额外的响应属性。重要的是要使用IPC机制和消息传递格式,使您能够轻松地开发API。

    但是,有时您必须对API进行重大的,不兼容的更改。由于您无法强制客户端立即升级,因此服务必须在一段时间内支持旧版API。如果使用的是基于HTTP的机制(例如REST),则一种方法是将版本号嵌入URL中。每个服务实例可能会同时处理多个版本。或者,您可以部署不同的实例,每个实例都处理特定的版本。

    处理部分失败

    如有关API gateway的文章中我们提到了,在分布式系统中,存在着永远存在的部分故障风险。 由于客户和服务是独立的流程,因此服务可能无法及时响应客户的请求。 服务可能由于故障或维护而关闭。 否则服务可能过载,并且对请求的响应非常缓慢。

    例如,考虑该文章中的“产品详细信息”方案。 假设推荐服务没有响应。 客户端的实现可能会无限期地阻塞等待响应。 这不仅会导致不良的用户体验,而且在许多应用程序中会消耗宝贵的资源,例如线程。 最终,运行时将耗尽线程并变得无响应,如下图所示。

    为避免此问题,必须设计服务以处理部分故障。

    Netflix所描述的是一种很好的遵循方法。处理部分故障的策略包括:

    • 网络超时–永远不会无限阻塞,并且在等待响应时始终使用超时。使用超时可确保资源不会无限期地被占用。
    • 限制未完成请求的数量–限制客户端可以使用特定服务的未完成请求的数量。如果已达到限制,则发出其他请求可能毫无意义,并且这些尝试必须立即失败。
    • 断路器模式–跟踪成功和失败请求的数量。如果错误率超过配置的阈值,请使断路器跳闸,以便进一步尝试立即失败。如果大量请求失败,则表明该服务不可用,并且发送请求毫无意义。超时后,客户端应重试,如果成功,则合上断路器。
    • 提供回退–当请求失败时执行回退逻辑。例如,返回缓存的数据或默认值,例如空的建议集。

    Netflix Hystrix是实现这些模式和其他模式的开源库。如果您使用的是JVM,则绝对应该考虑使用Hystrix。而且,如果您在非JVM环境中运行,则应使用等效的库。

    IPC Technologies

    有很多不同的IPC技术可供选择。服务可以使用基于请求/响应的同步通信机制,例如基于HTTP的REST或Thrift。或者,他们可以使用基于消息的异步通信机制,例如AMQP或STOMP。还有各种不同的消息格式。服务可以使用人类可读的,基于文本的格式,例如JSON或XML。或者,他们可以使用二进制格式(效率更高),例如Avro或Protocol Buffers。稍后,我们将讨论同步IPC机制,但首先让我们讨论异步IPC机制。

    基于消息的异步通信

    使用消息传递时,进程通过异步交换消息进行通信。客户端通过向其发送消息来向服务发出请求。如果期望该服务进行答复,则通过将单独的消息发送回客户端来进行答复。由于通信是异步的,因此客户端不会阻止等待答复。而是编写客户端,假定不会立即收到答复。

    一条消息由标头(例如发送方之类的元数据)和一条消息主体组成。消息通过通道交换。任何数量的生产者都可以将消息发送到一个频道。同样,任何数量的使用者都可以从频道接收消息。有两种渠道,点对点和发布-订阅。点对点通道将消息传递给正从该通道读取的消费者中的一个。服务使用点对点渠道进行前面所述的一对一交互样式。发布订阅通道将每个消息传递给所有附加的使用者。服务将发布-订阅通道用于上述一对多交互样式。

    下图显示了计程车应用程序如何使用发布-订阅通道。

    Microservices in taxi-hailing application use publish-subscribe channels for communication between dispatcher and other services

    行程管理服务通过将“行程创建”消息写入发布-订阅频道来通知感兴趣的服务(例如,调度程序)有关新行程。分派器通过将“驱动程序建议”消息写入发布-订阅通道来找到可用的驱动程序并通知其他服务。

    有许多消息传递系统可供选择。您应该选择一种支持多种编程语言的语言。一些消息传递系统支持标准协议,例如AMQP和STOMP。其他消息传递系统具有专有但已记录的协议。有很多开源消息传递系统可供选择,包括RabbitMQ,Apache Kafka,Apache ActiveMQ和NSQ。在较高级别上,它们都支持某种形式的消息和通道。他们都努力做到可靠,高性能和可扩展。但是,每个经纪人的消息传递模型的详细信息存在很大差异。

    使用消息传递有很多优点:

    • 使客户端与服务脱钩–客户端仅通过向适当的通道发送消息即可发出请求。客户端完全不知道服务实例。它不需要使用发现机制来确定服务实例的位置。
    • 消息缓冲–使用同步请求/响应协议(例如HTTP),客户端和服务在交换期间必须都可用。相反,消息代理将写入通道的消息排队,直到消费者可以处理它们为止。例如,这意味着即使订单履行系统很慢或不可用,在线商店也可以接受来自客户的订单。订单消息只是排队。
    • 灵活的客户端-服务交互–消息支持前面描述的所有交互样式。
    • 显式进程间通信–基于RPC的机制试图使调用远程服务看起来与调用本地服务相同。但是,由于物理定律和部分失效的可能性,它们实际上是完全不同的。消息传递使这些差异非常明显,因此开发人员不会陷入错误的安全感中。

    但是,使用消息传递有一些缺点:

    • 额外的操作复杂性–邮件系统是又一个必须安装,配置和操作的系统组件。邮件代理必须高度可用,否则会影响系统可靠性。
    • 实现基于请求/响应的交互的复杂性–请求/响应式的交互需要一些工作来实现。每个请求消息必须包含一个回复通道标识符和一个相关标识符。服务将包含相关ID的响应消息写入回复通道。客户端使用相关性ID将响应与请求进行匹配。使用直接支持请求/响应的IPC机制通常会更容易。

    现在,我们已经研究了使用基于消息的IPC,下面我们来研究基于请求/响应的IPC。

    Synchronous, Request/Response IPC 请求/响应的同步IPC

    当使用基于请求/响应的同步IPC机制时,客户端会将请求发送到服务。该服务处理请求并发送回响应。在许多客户端中,发出请求的线程在等待响应时会阻塞。其他客户端可能使用异步的,事件驱动的客户端代码,这些代码可能由Futures或Rx Observables封装。但是,与使用消息传递时不同,客户端假定响应将及时到达。有许多协议可供选择。两种流行的协议是REST和Thrift。首先让我们看一下REST。

    REST
    如今,以RESTful风格开发API已成为一种时尚。 REST是(几乎始终)使用HTTP的IPC机制。 REST中的一个关键概念是一种资源,通常代表一个业务对象,例如客户或产品,或业务对象的集合。 REST使用HTTP谓词来操纵资源,这些谓词是使用URL引用的。例如,GET请求返回资源的表示形式,该形式可以是XML文档或JSON对象的形式。 POST请求创建一个新资源,而PUT请求更新一个资源。

    下图显示了出租车服务应用程序可能使用REST的方式之一。

    In microservices-based taxi-hailing app, passenger smartphone sends POST request, which trip management microservice converts to GET request to passenger-verification microservice

    乘客的智能手机通过向旅行管理服务的/ trips资源发出POST请求来请求旅行。该服务通过向乘客管理服务发送有关乘客信息的GET请求来处理该请求。在确认乘客被授权创建行程后,行程管理服务将创建行程并将201响应返回至智能手机。

    许多开发人员声称他们基于HTTP的API是RESTful的。但是,正如Fielding在此博客文章中所描述的那样,实际上并非全部。 Leonard Richardson(无关系)为REST定义了一个非常有用的成熟度模型,该模型包含以下级别。

    • 级别0 –级别0 API的客户端通过向其唯一的URL端点发出HTTP POST请求来调用服务。每个请求都指定要执行的操作,操作的目标(例如业务对象)以及任何参数。
    • 1级– 1级API支持资源的概念。为了对资源执行操作,客户端发出POST请求,该请求指定要执行的操作以及任何参数。
    • 级别2 –级别2 API使用HTTP谓词执行操作:GET检索,POST创建和PUT更新。请求查询参数和主体(如果有)指定操作的参数。这使服务能够利用Web基础结构,例如为GET请求进行缓存。
    • 3级– 3级API的设计基于极为命名的HATEOAS(超文本作为应用程序状态引擎)原理。基本思想是,由GET请求返回的资源表示形式包含用于对该资源执行允许动作的链接。例如,客户可以使用响应于发送来检索订单的GET请求而返回的Order表示中的链接来取消订单。 HATEOAS的好处包括不再需要将URL硬编码到客户端代码中。另一个好处是,由于资源的表示形式包含允许操作的链接,因此客户端不必猜测在当前状态下可以对资源执行哪些操作。

    使用基于HTTP的协议有很多好处:

    • HTTP简单而熟悉。
    • 您可以使用扩展程序(例如Postman)从浏览器中测试HTTP API,也可以使用curl(例如,使用JSON或其他某种文本格式)从命令行测试HTTP API。
    • 它直接支持请求/响应样式的通信。
    • HTTP当然是防火墙友好的。
    • 它不需要中间代理,从而简化了系统的体系结构。

    使用HTTP有一些缺点:

    • 它仅直接支持交互的请求/响应样式。您可以使用HTTP进行通知,但是服务器必须始终发送HTTP响应。
    • 因为客户端和服务直接通信(没有中介来缓冲消息),所以它们必须在交换期间都处于运行状态。
    • 客户端必须知道每个服务实例的位置(即URL)。如上一篇有关API网关的文章所述,这是现代应用程序中的一个重要问题。客户端必须使用服务发现机制来定位服务实例。

    开发人员社区最近重新发现了RESTful API的接口定义语言的价值。有一些选项,包括RAML和Swagger。一些IDL(例如Swagger)允许您定义请求和响应消息的格式。其他(例如RAML)要求您使用单独的规范(例如JSON Schema)。除了描述API之外,IDL通常还具有从接口定义生成客户端存根和服务器框架的工具

    Message Formats消息格式

    现在,我们已经研究了HTTP和Thrift,现在让我们检查消息格式的问题。如果您使用的是消息传递系统或REST,则可以选择消息格式。其他IPC机制(例如Thrift)可能仅支持少量消息格式,也许仅支持一种。无论哪种情况,都必须使用跨语言消息格式。即使您今天用一种语言编写微服务,将来也可能会使用其他语言。

    消息格式主要有两种:文本和二进制。基于文本的格式的示例包括JSON和XML。这些格式的优点是它们不仅易于阅读,而且是自描述的。在JSON中,对象的属性由名称/值对的集合表示。同样,在XML中,属性由命名的元素和值表示。这使消息的使用者可以选择其感兴趣的值,而忽略其余值。因此,对消息格式的微小更改可以轻松地向后兼容。

    XML文档的结构由XML模式指定。随着时间的流逝,开发人员社区逐渐意识到JSON也需要类似的机制。一种选择是使用JSON Schema,它既可以独立使用,也可以作为IDL(例如Swagger)的一部分使用。

    使用基于文本的消息格式的缺点是消息往往很冗长,尤其是XML。因为消息是自描述的,所以每条消息除其值外还包含属性的名称。另一个缺点是解析文本的开销。因此,您可能要考虑使用二进制格式。

    总结

    微服务必须使用进程间通信机制进行通信。 在设计服务如何通信时,您需要考虑各种问题:服务如何交互,如何为每个服务指定API,如何扩展API以及如何处理部分故障。 微服务可以使用两种IPC机制:异步消息传递和同步请求/响应。 

     

     

     

     

    展开全文
  • 微服务通信--Feign

    2021-04-27 09:10:08
    关键在于加上注解:@RequestBody 3、使用feign客户端调用其他微服务时,报错超时:e=feign.RetryableException: Read timed out executing POST ribbon.ReadTimeout=60000 ribbon.ConnectTimeout=60000
  • 微服务通信 回想去年您在分布式系统中工作的时候,你可以考虑使用其他的东西比RESTful HTTP服务调用的组件之间通信的本系统中的方法? 在微服务的世界中,服务间通信的问题产生了两个主要的解决方案。 第一种...
  • 微服务通信协议:Restful,RPC(Dubbo、Motan、gRPC)

    万次阅读 多人点赞 2019-08-22 15:32:37
    简介 在单体式应用中,各个模块之间的调用是通过编程语言级别的方法或者函数来实现的。 但是一个基于微服务的分布式... 因此,微服务必须使用进程内通信协议(如 HTTP、AMQP)或二进制协议(如 TCP)进行交互,...
  • Feign是实现微服务架构下,不同服务之间通信很好的方式。在这里小编会给大家带来服务之间通信的几种方式。 1.LoadBalancerClient 2.RestTemplate 3 以及我们的主角 @FeignClient(name = “”) 前提知识 eureka ...
  • 微服务之间是如何独立通讯的 同步 REST HTTP 协议 REST 请求在微服务中是最为常用的一种通讯方式,它依赖于 HTTP\HTTPS 协议。RESTFUL 的特点是: 每一个 URI 代表 1 种资源 客户端使用 GET、POS
  • 微服务之间是如何通讯的

    千次阅读 2020-01-03 15:51:05
    REST 请求在微服务中是最为常用的一种通讯方式, 它依赖于 HTTP\HTTPS 协议。RESTFUL 的特点是: 每一个 URI 代表 1 种资源 客户端使用 GET、POST、PUT、DELETE 4 个表示操作方式的动词对服务端资源进行操作: GET ...
  • 服务间通信:API接口 服务间通信:API接口概述同步通信使用REST API使用gRPC API断路器模式(Circuit breaker pattern)... 被分解出来的服务之间需要协作 分布式环境下,协作会跨主机、跨进程 当
  • 微服务之间通信 1.返回Json字符串的方式 2.公共模块,添加依赖-------推荐 公共模块方式实现 1.准备domain ​ 1.新建模块 ​ 2.新建domain对象 ​ 3.需要用到的模块,依赖(先打jar包–install一下)注意:父模块...
  • 本场 Chat 主要讨论微服务之间的异步通信及其代码实践。 如何设计和实现基于 Spring 的微服务之间的异步通信。事件驱动的异步通信可以帮助您在(分别独立部署运行的)微服务之间进行异步交互。微服务架构加上事件...
  • 简介 在单体式应用中,各个模块... 因此,微服务必须使用进程内通信协议(如 HTTP、AMQP)或二进制协议(如 TCP)进行交互,具体取决于每个服务的性质。 交互模式 当为某一个服务选择IPC(Inter-Process Communi..
  • 微服务之间认证

    千次阅读 2020-04-01 15:37:01
    微服务之间认证: 如上图:由于微服务直接调用也需要传递token 进行认证,而因为微服务之间并没有传递头文件,所以我们可以定义一个拦截器,每次微服务调用之前都先检查下头文件,将请求的头文件中的令牌数据存储...
  • 34.微服务之间通信

    万次阅读 2018-03-11 20:00:29
    因此,如下图所示,服务之间的交互必须通过进程间通信(IPC)来实现。后面我们将会详细介绍 IPC 技术,现在我们先来看下设计相关的问题。交互模式当为某个服务选择 IPC 时,首先需要考虑服务之间的交互问题。客户端...
  • 作者在本文中介绍了一些常见的通信方法,并简要概述了其项目背景以及为何最终选择了RPC。 在决定微服务间连接方法前,我们需要搞清楚两个概念: 架构风格(Architectural Style) 传输协议(Transport Prot...
  • springCloud-微服务间的通信

    千次阅读 2018-04-30 19:07:48
    -第一种方式(loadBalancerClient实现) --通过loadBalancerClient获取其他微服务的名称(一般都是大写),在获取到地址和端口,并且拼接上对应的方法(如:“/msg”),最后生成response即可--缺点:每次需要写4行代码...
  • 微服务的世界中,服务间通信的问题产生了两个主要的解决方案。 第一种解决方案基于RESTful HTTP调用的使用,而另一种解决方案则围绕消息队列的使用。 通常,在做出此类设计决策时,正确的决策是基于对您的需求...
  • 微服务架构(五): 服务间通信方式

    万次阅读 2017-04-03 22:16:15
    工作中使用了微服务架构,接下来的一段时间里,我会写一系列的...这篇文章主要讲述了微服务架构中服务间的通信方式。 翻译和整理自: http://microservices.io/patterns/communication-style/rpi.html http://mi
  • 4.微服务互通,首先在本地测试,通过gateway进行转发,到customer服务,通过feign调用product的服务 4.1各服务Dockerfile文件,使用mvn package进行打包,并把jar包与Dockerfile同个目录存放 product FROM ...
  • 聊一聊微服务之间的通讯方式

    万次阅读 多人点赞 2021-08-11 23:18:04
    服务调用与事件驱动属于微服务调间用的两种方式,常规上可以看做是同步与异步。其两种方式会应用于不同的场景。 同步,属于直接调用,适用于处理并发不高,且需要另一个服务调用结果场景。 异步,属于事件驱动方式,...
  • 这是一个示例,展示了如何将Kafka用于微服务之间通信。 该项目将创建Docker容器。 它使用三种微服务: 订单创建订单。 该服务将消息发送到Kafka。 它使用KafkaTemplate 。 发货接收订单并提取发货所需的信息。...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 48,382
精华内容 19,352
关键字:

微服务之间如何通信