zoukankan      html  css  js  c++  java
  • Ocelot 发现服务总是失败的解决办法

    一、问题 

    今天用 Ocelot + Consul 项目,进行微服务实践,可是 Ocelot 的发现服务总是失败。

    二、分析问题

    2.1、分析方法:

          不得不下载了 Ocelot 源码进行追踪排查。

    2.2、源码分析

    源码对应文件为 Ocelot-developsrcOcelot.Provider.ConsulConsul.cs

    public async Task<List<Service>> Get()
            {
                var queryResult = await _consul.Health.Service(_config.KeyOfServiceInConsul, string.Empty, true);
    
                var services = new List<Service>();
    
                foreach (var serviceEntry in queryResult.Response)
                {
                    if (IsValid(serviceEntry))
                    {
                        var nodes = await _consul.Catalog.Nodes();
                        if (nodes.Response == null)
                        {
                            services.Add(BuildService(serviceEntry, null));
                        }
                        else
                        {
                            var serviceNode = nodes.Response.FirstOrDefault(n => n.Address == serviceEntry.Service.Address);
                            services.Add(BuildService(serviceEntry, serviceNode));
                        }
                    }
                    else
                    {
                        _logger.LogWarning($"Unable to use service Address: {serviceEntry.Service.Address} and Port: {serviceEntry.Service.Port} as it is invalid. Address must contain host only e.g. localhost and port must be greater than 0");
                    }
                }
    
                return services.ToList();
            }
    
            private Service BuildService(ServiceEntry serviceEntry, Node serviceNode)
            {
                return new Service(
                    serviceEntry.Service.Service,
                    new ServiceHostAndPort(serviceNode == null ? serviceEntry.Service.Address : serviceNode.Name, serviceEntry.Service.Port),
                    serviceEntry.Service.ID,
                    GetVersionFromStrings(serviceEntry.Service.Tags),
                    serviceEntry.Service.Tags ?? Enumerable.Empty<string>());
            }
    

      

    第3行,获得已注测的健康的服务;第11行,获得已注册 Consul 节点的电脑。

    第18行,如果当前服务与Consul节点是在同一台电脑上,则返回电脑节点 ServiceNode

    第31行中的 BuildSevrice 函数完成最后的 service信息创建, 

    第35行  如果找到了 ServiceNode,则返回对应的电脑名字 hostname,  如果没找到则返回对应的 ipAddress.

    就是说:服务和Consul 在同一台电脑上则返回hostname , 在不同电脑上则返回服务所在电脑的 ipAddress. 

     

    2.3 问题根源:

    是 Consul 注册时,hostname 参数由 -node参数指定。

    当服务和 Consul 在同一台电脑上时,Ocelot 最终变换成  http://hostname:port/url  的形式进行访问。

    三、解决问题

    3.1、Consul 的配置参数注意事项

    注意而 hostname 是由Consul 的 -node 参数指定的!

    所以,

    consul agent -server -datacenter=dc1 -bootstrap  -data-dir ./data  -ui  -node=n1 -bind 192.168.11.211 -client=0.0.0.0

      其中 -node=n1 是一个大坑。应该略去,系统会自己设置为自己的主机名字 hostname。

    所以我实际上用了配置文件 node1.json,也是去掉了该项。

    {
      "datacenter": "dc1",
      "data_dir": "c:/data/app/consul/node1",
      "log_level": "INFO",
      "server": true,
      "ui": true,
      "bind_addr": "192.168.11.211",
      "client_addr": "127.0.0.1",
      "advertise_addr": "192.168.11.211",
      "bootstrap_expect": 1,
      "ports":{
        "http": 8500,
        "dns": 8600,
        "server": 8300,
        "serf_lan": 8301,
        "serf_wan": 8302
        }
    }

    然后调用方式:

    consul agent -config-dir=e:/consul/node1.json

    然后用另一台服务器加入 

    consul agent -data-dir /tmp/consul  -bind=192.168.11.246 -join 192.168.11.248

    这时 Consul 的 web 管理界面为:

    它会自动带上主机名: HNSever 和 LGB-PC

    在这两台电脑上注册服务后,最终会变成  http://hostname:port/ + url 模板 的形式访问。

    3.2、hostname 不能访问问题修改

    如果 http://hostname:port/url,还是返回   错误代码 HTTP ERROR 500  访问失败。就是  hostname 不能转换为 ipaddress.

    所以需要修改 windows 的 hosts 文件

    打开系统目录:c:/windows/system32/drivers/etc找到hosts文件,打开hosts文件并在最后面添加一条记录

    例如:

    192.168.11.248  HNServer

    192.168.11.211  LGB-PC

    然后就能正常的发现服务了!

    3.3 附上 Ocelot 的配置文件  ocelot.json 

    {
      "ReRoutes": [
        {
          "DownstreamPathTemplate": "/api/{url}",
          "DownstreamScheme": "http",
          "ServiceName": "ProductService",
          "UseServiceDiscovery": true,
          "LoadBalancerOptions": {
            "Type": "LeastConnection"
          },
          "UpstreamPathTemplate": "/test/{url}",
          "UpstreamHttpMethod": [ "Post", "Get" ]
        }
      ],
    
      "GlobalConfiguration": {
        "ServiceDiscoveryProvider": {
          "Host": "localhost",
          "Port": 8500
        }
      }
    }

    四、参考

    Ocelot + Consul实践

    .net core Ocelot Consul 实现API网关 服务注册 服务发现 负载均衡

    netcore ocelot api网关结合consul服务发现

    Windows下主机名和IP映射设置

  • 相关阅读:
    Vue——data中的属性规范
    python的字符串用法
    python笔录第一周
    Mac下python版本的更新
    我的第一篇博客
    C语言-控制语句(循环)
    C语言-控制语句(分支与跳转)
    C语言-函数
    C语言-数组与指针
    C语言-堆和栈
  • 原文地址:https://www.cnblogs.com/citycomputing/p/12070909.html
Copyright © 2011-2022 走看看