微服务架构- 网关(Ocelot)


微服务架构- 网关(Ocelot) 

一、Gateway

1. 为什么需要网关?
  有了Consul,使用服务名即可访问。但手机、web端等外部访问者仍然需要和N多服务器交互,需要记忆他们的服务器地址、端口号等。一旦内部发生修改,很麻烦,而且有时候内部服务 器是不希望外界直接访问的—需要路由功能!Ocelot就是一个提供了请求路由、安全验证等功能的API网关微服务,简单点就是对consul进行了一次封装。

2. 好处:

  1. 各个业务系统轻松独立维护服务器;
  2. 复用权限校验;
  3. 限流、熔断、降级、收费等。

二、差异

1. 之前版本的只使用consul时获取服务地址:

public IActionResult Info()
        {
            List userList = new List();
            string resultUrl = null;

            #region 直接调用
            {
                //string url = "http://localhost:5726/api/users/get";
                //string result = WebApiHelperExtend.InvokeApi(url);
                //userList = Newtonsoft.Json.JsonConvert.DeserializeObject>(result);
                //resultUrl = url;
            }
            #endregion

            #region 这么多地址你怎么管理?1 2 3 要累死--可以自行选择

            #endregion

            #region 通过consul去发现这些服务地址
            {
                //using (ConsulClient client = new ConsulClient(c =>
                //{
                //    c.Address = new Uri("http://localhost:8500/");
                //    c.Datacenter = "dc1";
                //}))
                //{
                //    var dictionary = client.Agent.Services().Result.Response;
                //    string message = "";
                //    foreach (var keyValuePair in dictionary)
                //    {
                //        AgentService agentService = keyValuePair.Value;
                //        this._logger.LogWarning($"{agentService.Address}:{agentService.Port} {agentService.ID} {agentService.Service}");//找的是全部服务 全部实例  其实可以通过ServiceName筛选
                //        message += $"{agentService.Address}:{agentService.Port};";
                //    }
                //    //获取当前consul的全部服务
                //    base.ViewBag.Message = message;
                //}
            }
            #endregion

            #region 调用---负载均衡
            {
                //string url = "http://localhost:5726/api/users/get";
                //string url = "http://localhost:5727/api/users/get";
                //string url = "http://localhost:5728/api/users/get";
                string url = "http://UserService/api/users/get";
                //consul解决使用服务名字 转换IP:Port----DNS

                Uri uri = new Uri(url);
                string groupName = uri.Host;
                using (ConsulClient client = new ConsulClient(c =>
                {
                    c.Address = new Uri("http://localhost:8500/");
                    c.Datacenter = "dc1";
                }))
                {
                    var dictionary = client.Agent.Services().Result.Response;
                    var list = dictionary.Where(k => k.Value.Service.Equals(groupName, StringComparison.OrdinalIgnoreCase));//获取consul上全部对应服务实例
                    KeyValuePair<string, AgentService> keyValuePair = new KeyValuePair<string, AgentService>();
                    //拿到3个地址,只需要从中选择---可以在这里做负载均衡--
                    //{
                    //    keyValuePair = list.First();//直接拿的第一个
                    //}
                    //{
                    //    var array = list.ToArray();
                    //    //随机策略---平均策略
                    //    keyValuePair = array[new Random(iSeed++).Next(0, array.Length)];
                    //}
                    //{
                    //    var array = list.ToArray();
                    //    //轮询策略---平均策略
                    //    keyValuePair = array[iSeed++ % array.Length];
                    //}
                    {
                        //权重---注册服务时指定权重,分配时获取权重并以此为依据
                        Liststring, AgentService>> pairsList = new Liststring, AgentService>>();
                        foreach (var pair in list)
                        {
                            int count = int.Parse(pair.Value.Tags?[0]);
                            for (int i = 0; i < count; i++)
                            {
                                pairsList.Add(pair);
                            }
                        }
                        keyValuePair = pairsList.ToArray()[new Random(iSeed++).Next(0, pairsList.Count())];
                    }
                    resultUrl = $"{uri.Scheme}://{keyValuePair.Value.Address}:{keyValuePair.Value.Port}{uri.PathAndQuery}";
                    string result = WebApiHelperExtend.InvokeApi(resultUrl);
                    userList = Newtonsoft.Json.JsonConvert.DeserializeObject>(result);
                }
            }
            #endregion
            base.ViewBag.Users = userList;
            base.ViewBag.Url = resultUrl;
            return View();
        }

2. 使用网关之后的调用:

2.1 安装如下几个包

 2.2 修改startup文件如下:

   public void ConfigureServices(IServiceCollection services)
        {
            services.AddOcelot().AddConsul().AddPolly();  //添加
            //services.AddControllers();
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            app.UseOcelot();  //添加
            //if (env.IsDevelopment())
            //{
            //    app.UseDeveloperExceptionPage();
            //}

            //app.UseHttpsRedirection();

            //app.UseRouting();

            //app.UseAuthorization();

            //app.UseEndpoints(endpoints =>
            //{
            //    endpoints.MapControllers();
            //});
        }

2.3  修改配置文件

     public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                 .ConfigureAppConfiguration(c =>   //修改添加如下配置文件
                 {
                     c.AddJsonFile("configuration.json", optional:  false,     reloadOnChange: true);
                 })   //添加代码结束
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup();
                });

2.4 添加一个configuration.json 文件

////*****************************单地址********************************
{
  "ReRoutes": [
    {
      "DownstreamPathTemplate": "/api/{url}", //服务地址--url变量
      "DownstreamScheme": "http",
      "DownstreamHostAndPorts": [
        {
          "Host": "localhost",
          "Port": 5000 //服务端口
        } //可以多个,自行负载均衡
      ],
      "UpstreamPathTemplate": "/T5726/{url}", //网关地址--url变量   //冲突的还可以加权重Priority
      "UpstreamHttpMethod": [ "Get", "Post" ]
    }
  ]
}

//*****************************多地址多实例********************************
//{
//  "ReRoutes": [
//    {
//      "DownstreamPathTemplate": "/api/{url}", //服务地址--url变量
//      "DownstreamScheme": "http",
//      "DownstreamHostAndPorts": [
//        {
//          "Host": "localhost",
//          "Port": 5726 //服务端口
//        } //可以多个,自行负载均衡
//      ],
//      "UpstreamPathTemplate": "/T5726/{url}", //网关地址--url变量   //冲突的还可以加权重Priority
//      "UpstreamHttpMethod": [ "Get", "Post" ]
//    },
//    {
//      "DownstreamPathTemplate": "/api/{url}", //服务地址--url变量
//      "DownstreamScheme": "http",
//      "DownstreamHostAndPorts": [
//        {
//          "Host": "localhost",
//          "Port": 5727 //服务端口
//        }
//      ],
//      "UpstreamPathTemplate": "/T5727/{url}", //网关地址--url变量
//      "UpstreamHttpMethod": [ "Get", "Post" ]
//    },
//        {
//      "DownstreamPathTemplate": "/api/{url}", //服务地址--url变量
//      "DownstreamScheme": "http",
//      "DownstreamHostAndPorts": [
//        {
//          "Host": "localhost",
//          "Port": 5728 //服务端口
//        }
//      ],
//      "UpstreamPathTemplate": "/T5728/{url}", //网关地址--url变量
//      "UpstreamHttpMethod": [ "Get", "Post" ]
//    }
//  ]
//}

////*****************************单地址多实例负载均衡********************************
//{
//  "ReRoutes": [
//    {
//      "DownstreamPathTemplate": "/api/{url}", //服务地址--url变量
//      "DownstreamScheme": "http",
//      "DownstreamHostAndPorts": [
//        {
//          "Host": "localhost",
//          "Port": 5726 //服务端口
//        } //可以多个,自行负载均衡
//        ,
//        {
//          "Host": "localhost",
//          "Port": 5727 //服务端口
//        },
//        {
//          "Host": "localhost",
//          "Port": 5728 //服务端口
//        }
//      ],
//      "UpstreamPathTemplate": "/T5/{url}", //网关地址--url变量   //冲突的还可以加权重Priority
//      "UpstreamHttpMethod": [ "Get", "Post" ],
//      "LoadBalancerOptions": {
//        "Type": "RoundRobin" //轮询      LeastConnection-最少连接数的服务器   NoLoadBalance不负载均衡
//      }
//    }
//  ]
//}


////*****************************单地址多实例负载均衡+Consul********************************
//{
//  "ReRoutes": [
//    {
//      "DownstreamPathTemplate": "/api/{url}", //服务地址--url变量
//      "DownstreamScheme": "http",
//      "UpstreamPathTemplate": "/TConsul/{url}", //网关地址--url变量
//      "UpstreamHttpMethod": [ "Get", "Post" ],
//      "ServiceName": "ZhaoxiUserService", //consul服务名称
//      "LoadBalancerOptions": {
//        "Type": "RoundRobin" //轮询      LeastConnection-最少连接数的服务器   NoLoadBalance不负载均衡
//      },
//      "UseServiceDiscovery": true
//    }
//  ],
//  "GlobalConfiguration": {
//    "BaseUrl": "http://127.0.0.1:6299", //网关对外地址
//    "ServiceDiscoveryProvider": {
//      "Host": "localhost",
//      "Port": 8500,
//      "Type": "Consul" //由Consul提供服务发现
//    }
//  }
//}

//*****************************单地址多实例负载均衡+Consul+Polly********************************
//{
//  "ReRoutes": [
//    {
//      "DownstreamPathTemplate": "/api/{url}", //服务地址--url变量
//      "DownstreamScheme": "http",
//      "UpstreamPathTemplate": "/consul/{url}", //网关地址--url变量
//      "UpstreamHttpMethod": [ "Get", "Post" ],
//      "ServiceName": "ZhaoxiUserService", //consul服务名称
//      "LoadBalancerOptions": {
//        "Type": "RoundRobin" //轮询      LeastConnection-最少连接数的服务器   NoLoadBalance不负载均衡
//      },
//      "UseServiceDiscovery": true,
//      "QoSOptions": {
//        "ExceptionsAllowedBeforeBreaking": 3, //允许多少个异常请求
//        "DurationOfBreak": 10000, // 熔断的时间,单位为ms
//        "TimeoutValue": 10000 //如果下游请求的处理时间超过多少则自如将请求设置为超时 默认90秒
//      }
//      //"RateLimitOptions": {
//      //  "ClientWhitelist": [], //白名单
//      //  "EnableRateLimiting": true,
//      //  "Period": "5m", //1s, 5m, 1h, 1d  jeffzhang
//      //  "PeriodTimespan": 5, //多少秒之后客户端可以重试
//      //  "Limit": 5 //统计时间段内允许的最大请求数量
//      //},
//      //"FileCacheOptions": {
//      //  "TtlSeconds": 10
//      //} //"缓存"
//    }
//  ],
//  "GlobalConfiguration": {
//    "BaseUrl": "http://127.0.0.1:6299", //网关对外地址
//    "ServiceDiscoveryProvider": {
//      "Host": "localhost",
//      "Port": 8500,
//      "Type": "Consul" //由Consul提供服务发现
//    },
//    //"RateLimitOptions": {
//    //  "QuotaExceededMessage": "Too many requests, maybe later? 11", // 当请求过载被截断时返回的消息
//    //  "HttpStatusCode": 666 // 当请求过载被截断时返回的http status
//    //}
//  }
//}

2.5 请求地址示例:

http://127.0.0.1:6299/T5726/WeatherForecast

以上就是网关相关的总结!!!谢谢学习,共同进步