zoukankan      html  css  js  c++  java
  • 《ASP.NET Core 微服务实战》-- 读书笔记(第8章)

    第 8 章 服务发现

    面对大量服务,为了简化配置和管理工作,我们需要了解”服务发现“概念

    回顾云原生特性

    配置外置

    将 URL 和登录凭证移到配置文件和 C# 代码之外,放到环境变量中

    这样能让代码运行所需的配置参数更明确,而把提供这些配置的责任交给运行环境

    后端服务

    不管程序需要的是二进制存储、数据库、另一个服务、队列服务,还是其他类型的依赖,这些设施都应该松耦合,并能从环境变量中配置

    把资源绑定为后端服务有两种方式:静态绑定和动态绑定

    静态绑定指的是,无论是由自动化工具还是由 DevOps 工程师来分配,服务与资源之间的绑定过程发生在应用启动期间,而且一经绑定,即不再变化

    动态绑定指资源的绑定过程发生在运行期间,具体来说,绑定关系并不固定,并能在应用收到的多个请求期间发生变化

    另外,为避免给应用开发人员增加额外的复杂性,它也要支持松耦合

    Netflix Eureka 简介

    GitHub链接:https://github.com/Netflix/eureka

    要实现运行时的服务发现,需要用到”服务注册表“设施--一种集中式的服务目录

    Netflix 基础设施主要运行在 Amazon 云服务上

    Netflix 自行开发了用于管理服务注册的产品 Eureka,它提供故障转移和负载均衡能力

    从一名开发人员的角度看,微服务与 Eureka 服务器的交互方式就是在启动时注册

    如果需要发现并消费其他后端服务,可从 Eureka 服务器查找服务目录

    微服务还会向 Eureka 服务以一定的时间间隔发送心跳

    如果服务在一定时间里没有发送心跳,就会从服务注册表中移除

    在服务注册和发现领域, Eureka 也不是唯一的选择

    从纯粹的服务注册工具到具有完整注册、发现和容错功能的产品,有很多其他公司和产品可供选用

    • etcd:一个底层的分布式键值存储,提供 HTTP 访问
    • Consul:一个功能完备的服务发现工具,也提供用于支持配置功能的键值存储
    • Marathon:Mesos 和 DC/OS 上一个相当成熟的容器编排系统
    • ZooKeeper:源自 Hadoop 项目,是这一体系中最悠久的产品

    如果想体验 Eureka,但不想从源代码编译,也不想把它完整地安装到服务器上,你可以直接使用 docker hub 镜像来运行它,命令行如下:

    $ docker run -p 8080:8080 --name eureka 
    -d netflixoss/eureka:1.3.1
    

    发现和广播 ASP.NET Core 服务

    现在分析一些与 Eureka 服务交互的示例代码

    在下面的虚构示例中,将开发一套用于支持电子商务的服务

    最终的服务将公开一个产品目录,这个目录提供标准的 API 端点,用于访问产品列表和详细信息

    此外,有一个库存服务,负责提供物理库存的实时状态

    当需要展示产品详细信息时,产品服务将需要调用库存服务获取数据,用于组装最终的完整数据

    服务注册

    我们示例项目的第一部分是库存服务,它需要在运行期间动态地被其他服务发现,以提供实时库存状态

    GitHub链接:https://github.com/microservices-aspnetcore/ecommerce-inventory

    使用 .NET Core 配置系统向 Steeltoe 类库提供一些配置信息

    appsettings.json

    {
        "spring": {
            "application": {
                "name": "inventory"
            }
        },
        "eureka": {
            "client": {
                "serviceUrl": "http://localhost:8080/eureka/",
                "shouldRegisterWithEureka": true,
                "shouldFetchRegistry": false,
                "validate_certificates": false
            },
            "instance": {
                "port": 5000
            }
        },
    }
    

    我们用惯常的方式装配好配置,确保加载了保存着服务发现客户端配置信息的 appsettings.json 文件

    var builder = new ConfigurationBuilder()
        .SetBasePath(System.IO.Directory.GetCurrentDirectory())
        .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true);
    
    Configuration = builder.Build();
    

    在 Startup 类的 ConfigureService 方法里调用 Steeltoe 的 AddDiscoveryClient 扩展方法

    services.AddDiscoveryClient(Configuration);
    

    最后,只需要在 Configure 方法中添加对 UseDiscoveryClient 方法的调用

    app.UseDiscoveryClient();
    
    发现并消费服务

    有一个可供发现的服务之后,我们把注意力转到要开发的下一个服务上:目录服务

    这个服务提供产品的目录,并通过查询库存服务来补充产品的详细信息

    这一服务与我们开发过的其他服务之间最重要的区别是,它会在运行期间动态地发现库存服务

    GitHub链接:https://github.com/microservices-aspnetcore/ecommerce-catalog

    用与配置库存服务时几乎一样的方式配置客户端

    appsettings.json

    {
     "spring": {
        "application": {
          "name": "catalog"
        }
      },    
      "eureka":{  
        "client":{  
          "serviceUrl":"http://localhost:8080/eureka/",
          "shouldRegisterWithEureka":false
        }
      }
    }
    

    区别在于目录服务不需要被注册(因为它不需要被其他服务发现),只有获取注册表才能发现库存服务

    请看 HttpInventoryClient 类的代码,它负责消费库存服务

    using StatlerWaldorfCorp.EcommerceCatalog.Models;
    using Steeltoe.Discovery.Client;
    using System.Threading.Tasks;
    using System.Net.Http;
    using Newtonsoft.Json;
    
    namespace StatlerWaldorfCorp.EcommerceCatalog.InventoryClient
    {
        public class HttpInventoryClient : IInventoryClient
        {
            private DiscoveryHttpClientHandler handler;
            private const string STOCKSERVICE_URL_BASE = "http://inventory/api/skustatus/";
    
            public HttpInventoryClient(IDiscoveryClient client)
            {
                this.handler = new DiscoveryHttpClientHandler(client);
            }
    
    
            private HttpClient CreateHttpClient()
            {
                return new HttpClient(this.handler, false);
            }
    
            public async Task<StockStatus> GetStockStatusAsync(int sku)
            {
                StockStatus stockStatus = null;
    
                using (HttpClient client = this.CreateHttpClient())
                {
                    var result = await client.GetStringAsync(STOCKSERVICE_URL_BASE + sku.ToString());
                    stockStatus = JsonConvert.DeserializeObject<StockStatus>(result);
                }
    
                return stockStatus;
            }
        }
    }
    

    .NET Core 的 HttpClient 类的构造函数有一个重载,允许传入一个自定义的 HttpHandler 实例

    由 Steeltoe 提供的 DiscoveryHttpClientHandler 负责把 URL 中的服务名称替换成在运行期间发现的 URL

    执行如下步骤,可在电脑上同时运行库存服务、目录服务和 Eureka

    首先,启动 Eureka 服务

    $ docker run -p 8080:8080 -d --name eureka 
    -d netflixoss/eureka:1.3.1
    

    然后在 5001 端口运行库存服务

    $ cd <inventory service>
    $ dotnet run --service.urls=http://0.0.0.0:5001
    

    要在 Docker 中运行服务,请使用下面的 docker run 命令:

    $ docker run -p 5001:5001 -e PORT=5001 
    -e EURKEA__CLIENT__SERVICEURL=http://192.168.0.33:8080/eureka/ 
    dotnetcoreservices/ecommerce-inventory
    

    如果要在这里覆盖配置的值,请确保使用本机的地址

    在 Docker 镜像中运行时,指向 localhost 就会有问题

    最后,在 5002 端口启动目录服务

    $ cd <目录服务>
    $ dotnet run --service.urls=http://0.0.0.0:5002
    

    现在,可以向产品目录服务 API 发送一些请求,获取产品的列表和详情

    GET http://localhost:5002/api/products
    GET http://localhost:5002/api/products/{id}
    

    获取产品详情信息,期间将调用库存服务,它的 URL 是通过 Eureka 动态发现的

    DNS 以及由平台支持的服务发现

    在我看来,服务发现、注册,以及失败检测都应该是非功能需求

    也就是说,应用代码的任何部分都不应该紧耦合特定服务发现的实现

    显然,还是要优先考虑现实状况,务实地做出决策,而且最终决定还要由你自己来做

    知识共享许可协议

    本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。

    欢迎转载、使用、重新发布,但务必保留文章署名 郑子铭 (包含链接: http://www.cnblogs.com/MingsonZheng/ ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。

    如有任何疑问,请与我联系 (MingsonZheng@outlook.com) 。

  • 相关阅读:
    Comet学习资料
    vue 组件使用中的细节点
    js基本数据类型 BigInt 和 Number 的区别
    vue v-model 简单使用
    promise总结
    axio post 请求后端接收不到参数的解决办法
    快速配置webpack多入口脚手架
    BETA 版冲刺前准备
    Alpha 事后诸葛亮(团队)
    Alpha 答辩总结
  • 原文地址:https://www.cnblogs.com/MingsonZheng/p/12285913.html
Copyright © 2011-2022 走看看